/****************************************************************************
*
*    Copyright (c) 2005 - 2015 by Vivante Corp.  All rights reserved.
*
*    The material in this file is confidential and contains trade secrets
*    of Vivante Corporation. This is proprietary information owned by
*    Vivante Corporation. No part of this work may be disclosed,
*    reproduced, copied, transmitted, or used in any way for any purpose,
*    without the express written permission of Vivante Corporation.
*
*****************************************************************************/

 
#include <galUtil.h>
#include "gutsystem.h"

/* drm headers */
#include <omap/omap_drm.h>
#include <libdrm/omap_drmif.h>
#include <xf86drm.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

/* leejoonho :  */
#define OMK_CMEM_SUPPORT

#ifdef OMK_CMEM_SUPPORT
#include <ti/cmem.h>
#endif

//#define TIMEDEBUG

#ifdef TIMEDEBUG
#include <sys/time.h>
#endif

#ifdef TIMEDEBUG
static struct timeval timeStart;
static char g_timeBuf[20];

#define DPRINTF(fmt, args...) printf("[%s] :" fmt, GetStartedTime(), ## args)
char* GetStartedTime(void)
{
 	struct timeval currentTime;
    int hours, minutes, seconds;
    int milliseconds;

    gettimeofday(&currentTime, NULL);

    if (currentTime.tv_usec < timeStart.tv_usec)
    {
        milliseconds = (currentTime.tv_usec - timeStart.tv_usec + 1000000)/1000;
        currentTime.tv_sec--;
    }
    else    
    {
        milliseconds = (currentTime.tv_usec - timeStart.tv_usec)/1000;
    }

    /* Calculate the time   */
    hours = (currentTime.tv_sec - timeStart.tv_sec)/3600;
    minutes = (((currentTime.tv_sec - timeStart.tv_sec)/60))%60;
    seconds = (currentTime.tv_sec - timeStart.tv_sec)%60;
	
	memset(g_timeBuf, 0, sizeof(g_timeBuf));    
	sprintf(g_timeBuf, "%02u:%02u:%02u.%03u", hours, minutes, seconds, milliseconds);
 	return g_timeBuf; 	 	 	
}
#else
#define DPRINTF(fmt, args...)
#endif /* TIMEDEBUG */


//#define VIVANTE_DEBUG

#define GOOD_RECT(rect) (rect.left < rect.right && rect.top < rect.bottom)
/* Version info. */
static const char c_szFrameworkInfo[] = "\tGAL Test Framework Version 3.1 \n";

/* Base objects */
static GalRuntime g_Runtime;

#if defined(LINUX) || defined(ANDROID)
/* Video memory mapping. */
static gctPHYS_ADDR g_InternalPhysical, g_ExternalPhysical, g_ContiguousPhysical;
static gctSIZE_T    g_InternalSize,     g_ExternalSize,     g_ContiguousSize;
static gctPOINTER   g_Internal,         g_External,         g_Contiguous;
#endif

static gctSTRING        g_Argv2Test[MAX_ARG_COUNT] = {"",};

int g_alloc_fd = -1;

typedef struct Test2D {
        GalTest     base;
	GalRuntime  *runtime;

	// destination surface
	gcoSURF			dstSurf;
	gceSURF_FORMAT		dstFormat;
	gctUINT			dstWidth;
	gctUINT			dstHeight;
	gctINT			dstStride;
	gctUINT32		dstPhyAddr;
	gctPOINTER		dstLgcAddr;

	//source surface
	gcoSURF			src1Surf;
	gceSURF_FORMAT		src1Format;
	gctUINT			src1Width;
	gctUINT			src1Height;
	gctINT			src1Stride[3];
	gctUINT32		src1PhyAddr[3];
	gctPOINTER		src1LgcAddr[3];

	gcoSURF			src2Surf;
	gceSURF_FORMAT		src2Format;
	gctUINT			src2Width;
	gctUINT			src2Height;
	gctINT			src2Stride[3];
	gctUINT32		src2PhyAddr[3];
	gctPOINTER		src2LgcAddr[3];

	gctUINT			alpha;

} Test2D;

typedef struct SurfaceGeom {
	gctINT width;
	gctINT height;
	gceSURF_FORMAT format;

}SurfaceGeom;

Test2D* GalTest2D;
static SurfaceGeom dstGeom ={0,}, src1Geom= {0,}, src2Geom= {0,};
static 	gcsRECT dstrect={0,}, src1rect={0,}, src2rect={0,}, cliprect={0,}, src2auxdstrect={0,};
static gctUINT32 src2Angle = 0;
const char *dstFile = NULL, *src1File = NULL, *src2File = NULL;


gctBOOL IsFileVimg(const char* szFilename)
{
  gctINT len = strlen(szFilename);
  return(strcmp(&(szFilename[len-4]), "vimg") == 0);
}

gctBOOL IsFileRaw(const char* szFilename)
{
  gctINT len = strlen(szFilename);
  return((strcmp(&(szFilename[len-3]), "raw") == 0)
   || (strcmp(&(szFilename[len-3]), "yuv") == 0));
}

gctBOOL IsFileBmp(const char* szFilename)
{
  gctINT len = strlen(szFilename);
  return(strcmp(&(szFilename[len-3]), "bmp") == 0);
}

gctINT GetStride(gctINT width, gceSURF_FORMAT format)
{
	size_t stride;
	gcsSURF_FORMAT_INFO_PTR info[2]; 
	gcmVERIFY_OK(gcoSURF_QueryFormat(format, info));
	stride = ((width + 15) & ~15);
	switch(format)
	{
		case gcvSURF_YUY2:
		case gcvSURF_UYVY:
		case gcvSURF_YVYU:
		case gcvSURF_VYUY:
			stride *= 2;
			break;

		case gcvSURF_YV12:
		case gcvSURF_I420:
		case gcvSURF_NV12:
		case gcvSURF_NV21:
		case gcvSURF_NV16:
		case gcvSURF_NV61:
			break;

		default:
			stride *= info[0]->bitsPerPixel / 8;
			break;
	}
	return(stride);
}

gctUINT GetAddressStrideNum(gceSURF_FORMAT format)
 {
    gctUINT numPlanes;
    switch (format)
    {
    case gcvSURF_YUY2:
    case gcvSURF_UYVY:
        numPlanes = 1;
        break;

    case gcvSURF_I420:
    case gcvSURF_YV12:
        numPlanes = 3;
        break;

    case gcvSURF_NV16:
    case gcvSURF_NV12:
    case gcvSURF_NV61:
    case gcvSURF_NV21:
        numPlanes = 2;
        break;

    default:
        numPlanes = 1;
    }
	
	return numPlanes;
 }	
gceSTATUS LoadFileToSurface(const char* source, Test2D *t2d)
{
	gcoSURF *surf;
	const char* file;
	SurfaceGeom src;
	gceSTATUS status = gcvSTATUS_OK  ;
	
	printf("DBG111 : at %s\n", __FUNCTION__);
	
	if(!strcmp(source, "src1")) {
		surf = &t2d->src1Surf;
		file = src1File;
		memcpy((void*)&src, (void*)&src1Geom, sizeof(SurfaceGeom));
	}
	else {
		surf = &t2d->src2Surf;
		file = src2File;
		memcpy((void*)&src, (void*)&src2Geom, sizeof(SurfaceGeom));
	}
	
	printf("DBG222 : file(%s) at %s\n", file, __FUNCTION__);
	if ( !file ) 
	{
			status = -1;
	}		
	else
	{		
		if(IsFileVimg(file))
			status = GalLoadVimgToSurface(file, surf);
		else if(IsFileBmp(file)){	
			printf("DBG : after IsFileBmp. at %s\n", __FUNCTION__);
			*surf = GalLoadDIB2Surface(t2d->runtime->hal, file);
			if(*surf == NULL)
			  status = -1;
		}	
		else if(IsFileRaw(file)) {
			gctUINT stride;
			if(src.width <=0 || src.height <= 0) {
				sysOutput("For raw source files Geometry needs to be set. example: -src1 NV12 720x480\n");
				return -1;  
			}
			stride = GetStride(src.width, src.format);
			status = GalLoadRawToSurface(file, src.width, src.height, stride, src.format, surf);		
		}
		else {	 
			sysOutput("Not a valid type file. Only bmp, raw/yuv or vimg supported\n");
			status = -1;;
		}
	}
	
	printf("DBG33 : at %s\n", __FUNCTION__);
	return status;

}

gctBOOL TextToInt(gctINT*  val,
               const char** p,
               const char end)
{
  gctBOOL success = gcvTRUE;
  gctINT v = 0;
  gctBOOL vneg = gcvFALSE;
  if(**p == '-')
  {
    vneg = gcvTRUE;
    (*p)++;
  }

  do
  {
    if((**p <'0') || (**p >'9'))
    {
      success = gcvFALSE;
      goto Error;
    }

    v = (v * 10) + (**p - '0');
    (*p)++;
  }while(**p != end);

  *val = vneg ? -v : v;
Error:
  return(success);
}

gctBOOL TextToValPair(gctINT *val1,
                         gctINT *val2,
                         const char **p,
                         const char   sep,
                         const char   end)
{
  gctBOOL success;
  const char* szVals = *p;

  if(!(success = TextToInt(val1, p, sep)))
  {
    sysOutput("Invalid first value of value pair: %s\n", szVals);
  }
  else
  {
    (*p)++;
    if(!(success = TextToInt(val2, p, end)))
    {
      sysOutput("Invalid second value of value pair: %s\n", szVals);
    }
  }

  return(success);
}
const char* GetRect(gcsRECT* rect, const char* p)
{
  const char* szErr = 0;

  if(!TextToValPair(&rect->left, &rect->top, &p, ',', '-'))
  {
    szErr = "Invalid upper left coordinate";
    goto Error;
  }
  if(*p)
    p++;

  if(!TextToValPair(&rect->right, &rect->bottom, &p, 'x', '\0'))
  {
    szErr = "Invalid size";
    goto Error;
  }

Error:
  return(szErr);
}
const char* HexToUL(unsigned long *val,
                    const char*    p)
{
  const char* szErr = 0;

  *val = 0;

  char c = *p;
  while(c)
  {
    if((c >= '0') && (c <= '9'))
      *val = (*val * 16) + (c - '0');
    else if((c >= 'A') && (c <= 'F'))
      *val = (*val * 16) + (10 + c - 'A');
    else if((c >= 'a') && (c <= 'f'))
      *val = (*val * 16) + (10 + c - 'a');
    else
    {
      szErr = "Invalid hex value";
      break;
    }
    p++;
    c = *p;
  }

  return(szErr);
}

gctBOOL ParseFile(const char** szFile,
               gctINT          argc,
               const char*  argv[],
               gctINT*         arg)
{
  gctBOOL success = gcvFALSE;
  if((*arg + 1) >= argc)
  {
    sysOutput("No filename provided with %s option (ex. %s image.bmp).\n", argv[*arg], argv[*arg]);
    goto Error;
  }

  *szFile = argv[*arg + 1];
  sysOutput("%s %s\n", argv[*arg], *szFile);
  *arg += 2;

  success = gcvTRUE;
Error:
  return(success);
}

gctBOOL ParseAlpha(gctINT         argc,
                const char* argv[],
                gctINT       *arg)
{
  gctBOOL success = gcvFALSE;
  const char* szErr;
  unsigned long alpha;

  szErr = HexToUL(&alpha, argv[*arg + 1]);
  if(szErr)
  {
    sysOutput("%s with -alpha option.\n", szErr);
    goto Error;
  }

  if(alpha > 0xFF)
  {
    sysOutput("Invalid alpha value provided for -alpha option: %s (ex. -rop 80).\n", argv[*arg + 1]);
    goto Error;
  }

//  GalTest2D->alpha = (unsigned char)alpha;
  sysOutput("-alpha %02X\n", alpha);
  *arg += 2;
  
  success = gcvTRUE;
Error:
  return(success);
}

gctBOOL ParseRect(gcsRECT*  rect,
               gctINT         argc,
               const char* argv[],
               gctINT*        arg)
{
  const char* szErr = 0;

  if((*arg + 1) >= argc)
  {
    sysOutput("No rectangle provided with %s option (ex. %s 0,0-640x480)\n", argv[*arg], argv[*arg]);
    goto Error;
  }

  szErr = GetRect(rect, argv[*arg + 1]);
  if(szErr)
  {
    sysOutput("%s with option %s (ex. %s 0,0-640x480)\n", szErr, argv[*arg], argv[*arg]);
    goto Error;
  }
  sysOutput("%s %d,%d-%dx%d\n", argv[*arg], rect->left, rect->top, rect->right, rect->bottom);
  rect->right += rect->left;
  rect->bottom += rect->top;
  *arg += 2;

Error:
  return(szErr == 0);
}
const char* GetDimensions(gctINT *w,
                          gctINT *h,
                          const char*   p)
{
  const char* szErr = 0;
  gctINT width = 0, height = 0;

  if(!TextToValPair(&width, &height, &p, 'x', '\0'))
  {
    szErr = "Invalid size specified";
    goto Error;
  }

  
  if((width <= 0) || (height <= 0))
  {
    szErr = "Invalid surface size";
    goto Error;
  }

  *w = width;
  *h = height;

Error:
  return(szErr);
}

gctBOOL ParseSurf(SurfaceGeom *geom,
               gctINT         argc,
               const char* argv[],
               gctINT        *arg)
{
  gctBOOL success = gcvFALSE;
  const char* szErr = NULL;

  if((*arg + 2) >= argc)
  {
    sysOutput("Details not provided with %s option.\n", argv[*arg]);
    goto Error;
  }

  geom->format = GalQueryFormat(argv[*arg + 1]);
  if(geom->format == gcvSURF_UNKNOWN)
  {
    sysOutput("unknown format %s.\n", argv[*arg]);
    goto Error;
  }
  // Next param is dimension
  // Only calculate dimensions if the next char is a digit.
  if ( (argv[*arg + 2][0] >= '0') && (argv[*arg + 2][0] <= '9') )
  {
    szErr = GetDimensions(&geom->width, &geom->height, argv[*arg + 2]);
    if (szErr)
    {
      sysOutput("Error '%s' while getting surface dimensions\n",szErr);
      *arg += 3;
      success = gcvFALSE;
      goto Error;
    }
    sysOutput("%s %s %dx%d\n", argv[*arg], argv[*arg + 1], geom->width, geom->height);
  }
  else
  {
      sysOutput("invalid parameter '%s' with option %s.\n", argv[*arg + 2], argv[*arg]);
      goto Error;
   }
 

  *arg += 3;

  success = gcvTRUE;

Error:
  return(success);
}

void Usage(const char* szapp)
{
  
  sysOutput("USAGE:  %s\n", szapp);
  sysOutput("-dst <format> ###x### \n"
      "  Specify a destination surface format and size.\n"
      "  Destination format is always forced to A8R8G8B8\n"
      "  If not specified 800x480 will be considered\n");
  sysOutput("-dstrect ###,###-###x###\n"
      "  Specify a rectangle within the destination surface which receives the BLT.\n"
      "  If not specified dst surface width and height will be considered\n");
  sysOutput("-dstfile <file.>bmp\n"
      "  Specify a file into which to save the results.  Must be a BMP \n");
  sysOutput("-src1 <format> ###x### \n"
      "  Specify a source surface format and size.\n"
      "  Not needed for bmp and vimg files. Required only for raw files\n");
  sysOutput("-src1rect ###,###-###x###\n"
      "  Specify a rectangle within the source surface used as the source for the BLT.\n"
      "  If not specified, src1 actual image width and height will be considered\n");
  sysOutput("-src1file <file.>bmp|vimg|raw\n"
      "  Specify a file from which the source surface is initialized.  The image is\n"
      "  placed in the upper left corner of the source surface and clipped if\n"
      "  necessary.\n");
  sysOutput("-alpha <AA>\n"
      "  Specify the global alpha value as a hexadecimal value between 00\n"
      "  (transparent) to FF (opaque).\n");
  sysOutput("-src2 <format> ###x### \n"
      "  Specify a source2 surface format and size.\n"
      "  Not needed for bmp and vimg files. Required only for raw files\n");
  sysOutput("-src2rect ###,###-###x###\n"
      "  Specify a rectangle within the source2 surface used as the\n"
      "  source2 for the BLT.\n"
      "  If not specified, src2 actual image width and height will be considered\n");
  sysOutput("-src2file <file.>|bmp|raw|vimg"
      "  Specify a file from which the source2 surface is initialized.  The\n"
      "  image is placed in the upper left corner of the source2 surface and\n"
      "  clipped if necessary.\n");
  sysOutput("-src2auxdstrect ###,###-###x###\n"
      "  Specify a destination source2 surface used as the\n"
      "  source2 for the Strectching on src1 background.\n"
      "  If not specified, 0,0-256x256 will be considered\n");
  sysOutput("-src2angle ###\n"
      "  Specify orientation of source2 in degrees supported values are 0, 90, 180 and 270.\n");
  sysOutput("-blend clear|src1|src2|src1over|src2over|src1in|src2in|src1out|src2out|src1atop|src2atop|xor|plus|remote|global\n"
      "  Specify the type of blend to use. Multiple -blend parameters can be specified.\n");
  sysOutput("-cliprect ###,###-###x###\n"
      "  Specify a rectangle which is used to indicate the area in the destination\n"
      "  which is written, and outside of which the destination is not modified.\n");
    
}

gctBOOL ParseCmdLine(gctINT         argc,
                   const char* argv[])
{
  gctBOOL success = gcvFALSE;

  for(gctINT arg = 1; arg < argc;)
  {
    if(!strcmp(argv[arg], "-dst"))
    {
      if(!ParseSurf(&dstGeom, argc, argv, &arg))
        goto Error;
    }
    else if(!strcmp(argv[arg], "-dstfile"))
    {
      if(!ParseFile(&dstFile, argc, argv, &arg))
        goto Error;
    }
    else if(!strcmp(argv[arg], "-dstrect"))
    {
      if(!ParseRect(&dstrect, argc, argv, &arg))
        goto Error;
    }
    else if(!strcmp(argv[arg], "-src1"))
    {
      if(!ParseSurf(&src1Geom, argc, argv, &arg))
        goto Error;
    }
    else if(!strcmp(argv[arg], "-src1rect"))
    {
      if(!ParseRect(&src1rect, argc, argv, &arg))
        goto Error;
    }
    else if(!strcmp(argv[arg], "-src1file"))
    {
      if(!ParseFile(&src1File, argc, argv, &arg))
        goto Error;
    }
    else if(!strcmp(argv[arg], "-src2"))
    {
      if(!ParseSurf(&src2Geom, argc, argv, &arg))
        goto Error;
    }
    else if(!strcmp(argv[arg], "-src2file"))
    {
      if(!ParseFile(&src2File, argc, argv, &arg))
        goto Error;
    }
    else if(!strcmp(argv[arg], "-src2rect"))
    {
      if(!ParseRect(&src2rect, argc, argv, &arg))
        goto Error;
    }
    else if(!strcmp(argv[arg], "-src2angle"))
    {
      if(arg + 1 >= argc)
      {
        sysOutput("No angle provided with -src2angle option.\n");
        goto Error;
      }
      src2Angle = atoi(argv[arg + 1]);
      sysOutput("src2 orientation %d\n", src2Angle);
      arg += 2;
    }
    else if(!strcmp(argv[arg], "-src2auxdstrect"))
    {
      if(!ParseRect(&src2auxdstrect, argc, argv, &arg))
        goto Error;
    }
    else if(!strcmp(argv[arg], "-cliprect"))
    {
      if(!ParseRect(&cliprect, argc, argv, &arg))
        goto Error;
    }
    ///////////////////////////////
    else if(!strcmp(argv[arg], "-alpha"))
    {
      if(!ParseAlpha(argc, argv, &arg))
        goto Error;
    }
    
    else
    {
      sysOutput("Unrecognized option %s\n", argv[arg]);
      goto Error;
    }
    ///////////////////////////////
  }
  success = gcvTRUE;
Error:
  return(success);
}


static const struct PoolInfo
{
    gctCONST_STRING name;
    gcePOOL         type;
} c_PoolInfos[] =
{
    {"DEFAULT", gcvPOOL_DEFAULT},
    {"VIRTUAL", gcvPOOL_VIRTUAL},
    {"SYSTEM",  gcvPOOL_SYSTEM},
};


static void close_fd()
{
    close(g_alloc_fd);
    g_alloc_fd = -1;
}

#ifdef OMK_CMEM_SUPPORT

#define CMEM_BLOCKID 2
CMEM_AllocParams cmem_alloc_params = {
    CMEM_HEAP,      /* type */
    CMEM_CACHED,    /* flags */
    1               /* alignment */
};

static void* create_cmem_buffer(gctUINT width, gctUINT height, gceSURF_FORMAT format, size_t *stride)
{
	uint32_t size;
	size_t stride1;
	int bpr;
	void *vaddr = gcvNULL;
	/* Vivante DDK vars */
    gcsSURF_FORMAT_INFO_PTR info[2];    /* format parameters */
    
    assert ( format == gcvSURF_A8R8G8B8 );
    
    CMEM_init();
    
	gcmVERIFY_OK(gcoSURF_QueryFormat(format, info));	
	
	stride1 = ((width + 15) & ~15);
	bpr = ((width + 15) & ~15) *(double) ((double)info[0]->bitsPerPixel / 8);
	size = bpr * ((height + 3) & ~3);

#if 1
	*stride = bpr;
#else	
	*stride = stride1;
#endif
		 	
	printf("DBG : width(%d) stride1(%d) height(%d) size(%d) at %s\n", width, stride1, height, size, __PRETTY_FUNCTION__);
	 
	cmem_alloc_params.alignment = 0x80; 
	vaddr = CMEM_alloc2(CMEM_BLOCKID, size, &cmem_alloc_params);
    printf("DBG : vaddr(%#x) at %s\n", vaddr, __PRETTY_FUNCTION__);
    return vaddr;    
}	
#endif

static void* create_drm_buffer(gctUINT width, gctUINT height, gceSURF_FORMAT format, size_t *stride)
{
    /* omapdrm vars */
    struct omap_device *dev;
    struct omap_bo *bo;

    uint32_t size, flags = 0;
    void *vaddr = gcvNULL;
    size_t stride1;

    /* Vivante DDK vars */
    gcsSURF_FORMAT_INFO_PTR info[2];    /* format parameters */
    int bpr;

    //g_alloc_fd = drmOpen("omapdrm", NULL);
    if(g_alloc_fd == -1) {
    	g_alloc_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
    	if (g_alloc_fd <= 0) {
        	sysOutput("*ERROR* Failed to open omapdrm device\n");
        	return gcvNULL;
    	}
        sysOutput("\tINFO: opened omapdrm device %d\n", g_alloc_fd);
   }	
    dev = omap_device_new(g_alloc_fd);
    if (dev == gcvNULL) {
        sysOutput("*ERROR* Failed to get omap device\n");
        return gcvNULL;
    }
    //sysOutput("\tINFO: got omap_device\n");

    /* calculate the size of the buffer needed. Use gcoSURF_QueryFormat API to
     * format parameters descriptor - this contains information on format as
     * needed by the Vivante driver
     */
    gcmVERIFY_OK(gcoSURF_QueryFormat(format, info));
    //sysOutput("\tINFO: bits per pixel: %d\n", info[0]->bitsPerPixel);

    /* Vivante HAL needs 16 pixel alignment in width and 4 pixel alignment in
     * height.
     */
    stride1 = ((width + 15) & ~15);
    bpr = ((width + 15) & ~15) *(double) ((double)info[0]->bitsPerPixel / 8);
 //   sysOutput("\tINFO: bytes per row: %d bpp %d\n", bpr, info[0]->bitsPerPixel);
    size = bpr * ((height + 3) & ~3);
    switch(format)
    {
	    case gcvSURF_YUY2:
	    case gcvSURF_UYVY:
	    case gcvSURF_YVYU:
	    case gcvSURF_VYUY:
		    stride1 *= 2;
		    break;

	    case gcvSURF_YV12:
	    case gcvSURF_I420:
	    case gcvSURF_NV12:
	    case gcvSURF_NV21:
	    case gcvSURF_NV16:
	    case gcvSURF_NV61:
		    break;

	    default:
		    stride1 *= info[0]->bitsPerPixel / 8;
		    break;
    }
    *stride = stride1;
       
    /* TODO: need to get the flags right here */
    /* MEM_CACHED, MEM_WRITE, */
    //flags &= ~OMAP_BO_CACHE_MASK;   /* MEM_CACHED */
    flags = OMAP_BO_WC;            /* write combine */
    //flags &= ~OMAP_BO_TILED_MASK;   /* non-Tiler */
    sysOutput("size = %d stride %d\n", size, stride1);
    bo = omap_bo_new(dev, size, flags);
    if (!bo) {
        sysOutput("*ERROR* Failed to create omap bo\n");
        return gcvNULL;
    }
   
    vaddr = omap_bo_map(bo);
    if (!vaddr) {
        sysOutput("*ERROR* could not mmap dmabuf - %s\n", strerror(errno));
        return gcvNULL;
    }
    /*
     * `omap_bo` might not have backing pages at this point, make sure you got
     * them by writing into it.
     */
    memset(vaddr, 0, size);
  
    return vaddr;

}

/*
 *  Name:       Initialize()
 *  Parameters: case_name, the name of the dll of the test case.
*/

static gctBOOL Initialize()
{
//    PGalCreateTestObject createTestObject;
    gceSTATUS status;

    /* Construct the gcoOS object. */
    status = gcoOS_Construct(gcvNULL, &g_Runtime.os);
    if (status < 0)
    {
        sysOutput("*ERROR* Failed to construct OS object (status = %d)\n", status);
        return gcvFALSE;
    }

    /* Construct the gcoHAL object. */
    status = gcoHAL_Construct(gcvNULL, g_Runtime.os, &g_Runtime.hal);
    if (status < 0)
    {
        sysOutput("*ERROR* Failed to construct GAL object (status = %d)\n", status);
        return gcvFALSE;
    }

    if (!gcoHAL_IsFeatureAvailable(g_Runtime.hal, gcvFEATURE_2DPE20))
    {
        switch (g_Runtime.format)
        {
        /* PE1.0 support. */
        case gcvSURF_X4R4G4B4:
        case gcvSURF_A4R4G4B4:
        case gcvSURF_X1R5G5B5:
        case gcvSURF_A1R5G5B5:
        case gcvSURF_X8R8G8B8:
        case gcvSURF_A8R8G8B8:
        case gcvSURF_R5G6B5:
            break;

        default:
            sysOutput("*ERROR* the target format %d is not supported by the hardware.\n",
                g_Runtime.format);
            return gcvFALSE;
        }
    }

#if defined(LINUX) || defined(ANDROID)
    /* Query the amount of video memory. */
    status = gcoHAL_QueryVideoMemory(g_Runtime.hal,
                                     &g_InternalPhysical, &g_InternalSize,
                                     &g_ExternalPhysical, &g_ExternalSize,
                                     &g_ContiguousPhysical, &g_ContiguousSize);
    if (gcmIS_ERROR(status))
    {
        sysOutput("gcoHAL_QueryVideoMemory failed %d.", status);
        return gcvFALSE;
    }
    /* Map the local internal memory. */
    if (g_InternalSize > 0)
    {
        status = gcoHAL_MapMemory(g_Runtime.hal,
                                  g_InternalPhysical, g_InternalSize,
                                  &g_Internal);
        if (gcmIS_ERROR(status))
        {
            sysOutput("gcoHAL_MapMemory failed %d.", status);
            return gcvFALSE;
        }
    }

    /* Map the local external memory. */
    if (g_ExternalSize > 0)
    {
        status = gcoHAL_MapMemory(g_Runtime.hal,
                                  g_ExternalPhysical, g_ExternalSize,
                                  &g_External);
        if (gcmIS_ERROR(status))
        {
            sysOutput("gcoHAL_MapMemory failed %d.", status);
            return gcvFALSE;
        }
    }

    /* Map the contiguous memory. */
    if (g_ContiguousSize > 0)
    {
        status = gcoHAL_MapMemory(g_Runtime.hal,
                                  g_ContiguousPhysical, g_ContiguousSize,
                                  &g_Contiguous);
        if (gcmIS_ERROR(status))
        {
            sysOutput("gcoHAL_MapMemory failed %d.", status);
            return gcvFALSE;
        }
    }
#endif
	
	printf("DBG : g_ContiguousSize(%d) at %s\n", g_ContiguousSize, __PRETTY_FUNCTION__);
	
    status = gcoHAL_Get2DEngine(g_Runtime.hal, &g_Runtime.engine2d);
    if (status < 0)
    {
        sysOutput("*ERROR* Failed to get 2D engine object (status = %d)\n", status);
        return gcvFALSE;
    }


    if (g_Runtime.createTarget)
    {
        void *vaddr = gcvNULL;
        size_t stride;
        gceHARDWARE_TYPE type;
        unsigned long phys = ~0U;

#ifdef OMK_CMEM_SUPPORT		
		vaddr = create_cmem_buffer(g_Runtime.width, g_Runtime.height, g_Runtime.format, &stride);
#else		
        vaddr = create_drm_buffer(g_Runtime.width, g_Runtime.height, g_Runtime.format, &stride);
#endif        
        if (!vaddr) {
            sysOutput("*ERROR*: Failed to create drm target surface ");
            return gcvFALSE;
        }

        gcoHAL_GetHardwareType(gcvNULL, &type);

        /* now that we created gem buffer and mapped it to this process, we need to
         * map this to GC320 MMU. First we get the hardware type, to figure which
         * version of MMU is the HAL using. Then set this buffer as an underlying
         * buffer to the gcoSURF object.
         */
        //set_default_hardware_type();

        /* create a wrapper gcoSURF surface object, because we are mapping the user
         * allocated buffer pool should be gcvPOOL_USER */
        status = gcoSURF_Construct(
                gcvNULL,
                g_Runtime.width,
                g_Runtime.height,
                1,
                gcvSURF_BITMAP,
                g_Runtime.format,
                gcvPOOL_USER,
                &g_Runtime.target);
        if (status < 0) {
            sysOutput("*ERROR* Failed to create gcoSURF object");
            return gcvFALSE;
        }
		
#ifdef OMK_CMEM_SUPPORT			
		{
			uint32_t  p_adr_al;
			uint32_t tmpwidth, tmpheight;
        	int tmpstride;
        	gcmONERROR(gcoSURF_GetAlignedSize(g_Runtime.target, &tmpwidth, &tmpheight, &tmpstride));	
			
			if ( (tmpwidth != g_Runtime.width) || (tmpheight != g_Runtime.height) || ((uint32_t) tmpstride != stride) )
			{
            	printf("Allocated Surf buffer width %d, height %d and stride %d doesn't meet GC320 aligned requirement on width %d, height %d and stride %d\n", 
            		g_Runtime.width, g_Runtime.height, stride, tmpwidth, tmpheight, tmpstride);
        	}
        	
        	gcmONERROR(gcoSURF_GetAlignment(gcvSURF_BITMAP, g_Runtime.format, &p_adr_al, NULL, NULL ));

			if ( (uint32_t)vaddr % p_adr_al )
			{
				printf("Buffer passed to GC320 doesn't meet the alignment requirement, GC320 alignment need is %x, received buffer with %x aligned address\n", 
					p_adr_al, ((uint32_t)vaddr%p_adr_al));
			}
        	
		}	
#endif		
	
        /* set the underlying buffer */
        status = gcoSURF_SetBuffer(
                    g_Runtime.target,
                    gcvSURF_BITMAP,
                    g_Runtime.format,
                    stride,
                    vaddr,
                    phys);
        if (status < 0) {
            sysOutput("*ERROR* Failed to set buffer for gcoSURF object");
            return gcvFALSE;
        }
        
        printf("DBG111 : g_Runtime.target(%#x) sleep(5) at %s\n", g_Runtime.target, __FUNCTION__);
        sleep(5);
        
        /* set window size */
        status = gcoSURF_SetWindow(
                    g_Runtime.target, 0, 0, g_Runtime.width, g_Runtime.height);
        if (status < 0) {
            sysOutput("*ERROR* Failed to set window for gcoSURF object");
            return gcvFALSE;
        }
		
		printf("DBG : sleep(30).. at %s\n", __FUNCTION__);
		sleep(30);
		
        gcoHAL_SetHardwareType(gcvNULL, type);

    }
    else
        g_Runtime.target = gcvNULL;


    g_Runtime.pe20      = gcoHAL_IsFeatureAvailable(g_Runtime.hal, gcvFEATURE_2DPE20);
#if gcvVERSION_MAJOR >= 4
    g_Runtime.fullDFB     = gcoHAL_IsFeatureAvailable(g_Runtime.hal, gcvFEATURE_FULL_DIRECTFB);
#else
    g_Runtime.fullDFB     = gcvFALSE;
#endif

    // log chip info
   
    GalTest2D = (Test2D*)malloc(sizeof(Test2D));
    if(!GalTest2D){
	sysOutput("Error: Failed to allocate Test2D\n");
	return gcvFALSE;
    }

    GalTest2D->runtime    = &g_Runtime;
    GalTest2D->dstSurf    = g_Runtime.target;
    GalTest2D->dstFormat = g_Runtime.format;
    GalTest2D->dstWidth = 0;
    GalTest2D->dstHeight = 0;
    GalTest2D->dstStride = 0;
    GalTest2D->dstPhyAddr = 0;
    GalTest2D->dstLgcAddr = 0;

    GalTest2D->src1Surf    = gcvNULL;
    GalTest2D->src1Width = 0;
    GalTest2D->src1Height = 0;
    GalTest2D->src1Stride[0] = 0;
    GalTest2D->src1Stride[1] = 0;
    GalTest2D->src1Stride[2] = 0;
    GalTest2D->src1PhyAddr[0] = 0;
    GalTest2D->src1LgcAddr[0] = 0;
    GalTest2D->src1PhyAddr[1] = 0;
    GalTest2D->src1LgcAddr[1] = 0;
    GalTest2D->src1PhyAddr[2] = 0;
    GalTest2D->src1LgcAddr[2] = 0;
    GalTest2D->src1Format = gcvSURF_UNKNOWN;

    GalTest2D->src2Surf    = gcvNULL;
    GalTest2D->src2Width = 0;
    GalTest2D->src2Height = 0;
    GalTest2D->src2Stride[0] = 0;
    GalTest2D->src2Stride[1] = 0;
    GalTest2D->src2Stride[2] = 0;
    GalTest2D->src2PhyAddr[0] = 0;
    GalTest2D->src2LgcAddr[0] = 0;
    GalTest2D->src2PhyAddr[1] = 0;
    GalTest2D->src2LgcAddr[1] = 0;
    GalTest2D->src2PhyAddr[2] = 0;
    GalTest2D->src2LgcAddr[2] = 0;
    GalTest2D->src2Format = gcvSURF_UNKNOWN;

    gcoSURF_GetAlignedSize(GalTest2D->dstSurf,
			&GalTest2D->dstWidth,
			&GalTest2D->dstHeight,
			&GalTest2D->dstStride);

    gcoSURF_Lock(GalTest2D->dstSurf, &GalTest2D->dstPhyAddr, &GalTest2D->dstLgcAddr);


    return gcvTRUE;

OnError:	
	assert(0);
	return gcvFALSE;    
}

/*
 *  Name:       Finalize()
 *  Returns:    None.
 *  Parameters: None.
 *  Description:Free all resource that the framework has used. These may include the memory resource it used, and the egl system resource and so on.
 *              Here it includes "finalize the test object(case)", "free egl resource", "free library resource", "finalize output file resource" and
 *              "destroy win32 resource".
*/
static void Finalize()
{

    if (g_Runtime.hal != gcvNULL)
    {
        gcoHAL_Commit(g_Runtime.hal, gcvTRUE);
    }

    if(GalTest2D->src1Surf != NULL)
    {
	if(GalTest2D->src1LgcAddr)
	  gcoSURF_Unlock(GalTest2D->src1Surf, GalTest2D->src1LgcAddr);

	GalTest2D->src1LgcAddr[0] = NULL;	
	GalTest2D->src1LgcAddr[1] = NULL;	
	GalTest2D->src1LgcAddr[2] = NULL;	

	gcoSURF_Destroy(GalTest2D->src1Surf);

    }
    if(GalTest2D->src2Surf != NULL)
    {
	if(GalTest2D->src2LgcAddr)
	  gcoSURF_Unlock(GalTest2D->src2Surf, GalTest2D->src2LgcAddr);

	GalTest2D->src2LgcAddr[0] = NULL;	
	GalTest2D->src2LgcAddr[1] = NULL;	
	GalTest2D->src2LgcAddr[2] = NULL;	

	gcoSURF_Destroy(GalTest2D->src2Surf);

    }
    if (g_Runtime.target != gcvNULL)
    {
        gceHARDWARE_TYPE type;

        gcoHAL_GetHardwareType(gcvNULL, &type);
        //set_default_hardware_type();

        gcmVERIFY_OK(gcoSURF_Unlock(g_Runtime.target, gcvNULL));
        gcmVERIFY_OK(gcoSURF_Destroy(g_Runtime.target));
        gcmVERIFY_OK(gcoHAL_Commit(gcvNULL, gcvTRUE));

        gcoHAL_SetHardwareType(gcvNULL, type);

    }

    
    close_fd();

#if defined(LINUX) || defined(ANDROID)
    if (g_Internal != gcvNULL)
    {
        /* Unmap the local internal memory. */
        gcmVERIFY_OK(gcoHAL_UnmapMemory(g_Runtime.hal,
                                        g_InternalPhysical, g_InternalSize,
                                        g_Internal));
    }

    if (g_External != gcvNULL)
    {
        /* Unmap the local external memory. */
        gcmVERIFY_OK(gcoHAL_UnmapMemory(g_Runtime.hal,
                                        g_ExternalPhysical, g_ExternalSize,
                                        g_External));
    }

    if (g_Contiguous != gcvNULL)
    {
        /* Unmap the contiguous memory. */
        gcmVERIFY_OK(gcoHAL_UnmapMemory(g_Runtime.hal,
                                        g_ContiguousPhysical, g_ContiguousSize,
                                        g_Contiguous));
    }
#endif

    if (g_Runtime.hal != gcvNULL)
    {
        gcoHAL_Commit(g_Runtime.hal, gcvTRUE);
        gcoHAL_Destroy(g_Runtime.hal);
    }

    if (g_Runtime.os != gcvNULL)
    {
        gcoOS_Destroy(g_Runtime.os);
    }

    GalFinalizeOutput();

    free(GalTest2D);
}


static gctBOOL Render(Test2D *t2d)
{
	gctUINT8 horKernel = 1, verKernel = 1;
	gcsRECT srcRect;
	gco2D egn2D = t2d->runtime->engine2d;
	gceSTATUS status;
	//size_t stride;
	//void* VirtAddr;
        //gceHARDWARE_TYPE type;
        //unsigned long phys = ~0U;
	gcsRECT srcRect2 ;
        gctUINT numPlanes;
        gctINT temp;
	gceSURF_ROTATION srcRotation = gcvSURF_0_DEGREE, dstRotation = gcvSURF_0_DEGREE;
	gcsRECT dstRect = {0, 0, t2d->dstWidth, t2d->dstHeight};
	gcsRECT clipRect = {0, 0, t2d->dstWidth , t2d->dstHeight };
	Gal2DCleanSurface(g_Runtime.hal, g_Runtime.target, COLOR_ARGB8(0x00, 0x00, 0x00, 0x00));

	if ( LoadFileToSurface("src1", t2d) == 0 ) 
	{	
        
        printf("DBG : src1 processing. at %s\n", __FUNCTION__);
        
        gcmONERROR(gcoSURF_GetAlignedSize(t2d->src1Surf,
	  				gcvNULL,
					gcvNULL,
					t2d->src1Stride));

		gcmONERROR(gcoSURF_GetSize(t2d->src1Surf,
					&t2d->src1Width,
					&t2d->src1Height,
					gcvNULL));

		gcmONERROR(gcoSURF_GetFormat(t2d->src1Surf, gcvNULL, &t2d->src1Format));

		gcmONERROR(gcoSURF_Lock(t2d->src1Surf, t2d->src1PhyAddr, t2d->src1LgcAddr));

		if(GOOD_RECT(src1rect))
		{

		srcRect.left = src1rect.left;
		srcRect.top = src1rect.top;
		srcRect.right = src1rect.right;
		srcRect.bottom = src1rect.bottom;

		}
		else 
		{
			srcRect.left = 0;
			srcRect.top = 0;
			srcRect.right = t2d->src1Width;
			srcRect.bottom = t2d->src1Height;
		}

		if(GOOD_RECT(dstrect)){
	
			dstRect.left = dstrect.left;
			dstRect.top = dstrect.top;
			dstRect.right = dstrect.right;
			dstRect.bottom = dstrect.bottom;
		}
		// set clippint rect
		gcmONERROR(gco2D_SetClipping(egn2D, &dstRect));
	
		// set kernel size
		gcmONERROR(gco2D_SetKernelSize(egn2D, horKernel, verKernel));
		
		//printf("DBG : before gcoSURF_FilterBlit. at %s\n", __FUNCTION__);
		gcmONERROR(gcoSURF_FilterBlit(t2d->src1Surf, t2d->dstSurf, &srcRect, &dstRect, &dstRect));
		//printf("DBG : after gcoSURF_FilterBlit. at %s\n", __FUNCTION__);
		
		//DPRINTF("after gcoSURF_FilterBlit.\n"); 	
	}	
	
	if(src2File) {

		printf("src2 load.\n");
		LoadFileToSurface("src2", t2d);
		
		
#ifdef TIMEDEBUG
		gettimeofday(&timeStart, NULL);
#endif		
		DPRINTF("before alphablending.\n");
		
		gcmONERROR(gcoSURF_GetAlignedSize(t2d->src2Surf,
					gcvNULL,
					gcvNULL,
					t2d->src2Stride));

		gcmONERROR(gcoSURF_GetSize(t2d->src2Surf,
					&t2d->src2Width,
					&t2d->src2Height,
					gcvNULL));
		
		printf("DBG : src2Width(%d) src2Height(%d) at %s\n", t2d->src2Width, t2d->src2Height, __FUNCTION__);
		
		gcmONERROR(gcoSURF_GetFormat(t2d->src2Surf, gcvNULL, &t2d->src2Format));
		gcmONERROR(gcoSURF_Lock(t2d->src2Surf, t2d->src2PhyAddr, t2d->src2LgcAddr));

		if(src2Angle != 0 && src2Angle != 90 && src2Angle != 180 && src2Angle != 270)
			src2Angle = 0;
		if(GOOD_RECT(src2rect)){

			srcRect2.left = src2rect.left;
			srcRect2.top = src2rect.top;
			srcRect2.right = src2rect.right;
			srcRect2.bottom = src2rect.bottom;

		}
		else {
			srcRect2.left = 0;
			srcRect2.top = 0;
			srcRect2.right = t2d->src2Width;
			srcRect2.bottom = t2d->src2Height;
		}

		if(GOOD_RECT(src2auxdstrect)){

			dstRect.left = src2auxdstrect.left;
			dstRect.top = src2auxdstrect.top;
			dstRect.right = src2auxdstrect.right;
			dstRect.bottom = src2auxdstrect.bottom;

		}
		else {
			dstRect.left= 0;
			dstRect.top = 0;
#if 1	
			dstRect.right = g_Runtime.width;
			dstRect.bottom = g_Runtime.height;
#else	 /* 알파블렌딩영역을 작게 하고 있음 */		
			dstRect.right = 256;
			dstRect.bottom = 256;
#endif			
		}
		if(src2Angle == 180) {
			gcmONERROR(gco2D_SetBitBlitMirror(egn2D, gcvTRUE, gcvTRUE));
		}
		else if(src2Angle == 90) {
		     dstRotation = gcvSURF_90_DEGREE;
		     temp = clipRect.right;
		     clipRect.right = clipRect.bottom;
		     clipRect.bottom = temp;
		}
		else if(src2Angle == 270) {
		     srcRotation = gcvSURF_90_DEGREE;
		     temp = srcRect2.right;
		     srcRect2.right = srcRect2.bottom;
		     srcRect2.bottom = temp;

		}
		numPlanes = GetAddressStrideNum(t2d->src2Format);
		gcmONERROR(gco2D_SetGenericSource(egn2D,
        			t2d->src2PhyAddr, numPlanes,
        			(gctUINT*)t2d->src2Stride, numPlanes,
        			gcvLINEAR,
        			t2d->src2Format,
        			srcRotation,
        			t2d->src2Width,
        			t2d->src2Height));
		gcmONERROR(gco2D_SetSource(egn2D, &srcRect2));

		gcmONERROR(gco2D_SetTarget(egn2D, t2d->dstPhyAddr, t2d->dstStride, dstRotation, t2d->dstWidth));

		gcmONERROR(gco2D_SetClipping(egn2D, &clipRect));
#if 1
		gcmONERROR(gco2D_SetSourceGlobalColorAdvanced(egn2D, 0x80 << 24));

		gcmONERROR(gco2D_SetTargetGlobalColorAdvanced(egn2D, 0x80 << 24));

		gcmONERROR(gco2D_EnableAlphaBlendAdvanced(egn2D,
					gcvSURF_PIXEL_ALPHA_STRAIGHT, gcvSURF_PIXEL_ALPHA_STRAIGHT,
					gcvSURF_GLOBAL_ALPHA_ON, gcvSURF_GLOBAL_ALPHA_ON,
					gcvSURF_BLEND_STRAIGHT, gcvSURF_BLEND_STRAIGHT));
#endif
		// gcmONERROR(gco2D_Blit(egn2D, 1, &dstRect, 0xCC, 0xCC, t2d->dstFormat));
		 //stretch and blit 
		gcmONERROR(gco2D_SetStretchRectFactors(
					egn2D,
					&srcRect2,
					&dstRect
					));

		gcmONERROR(gco2D_StretchBlit(
					egn2D,
					1,
					&dstRect,
					0xCC, 0xCC,
					t2d->dstFormat
					));
		gcmONERROR(gco2D_SetBitBlitMirror(egn2D, gcvFALSE, gcvFALSE));
		gcmONERROR(gco2D_DisableAlphaBlend(egn2D));
	}

#if 0
	gcmONERROR(gco2D_Flush(egn2D));
#else
	printf("DBG : skip flush.. at %s\n", __FUNCTION__);
#endif

	gcmONERROR(gcoHAL_Commit(t2d->runtime->hal, gcvTRUE));
	DPRINTF("after gcoHAL_Commit.\n"); 	
	
	printf("DBG : width(%d) height(%d) stride(%d) at %s\n", GalTest2D->dstWidth, GalTest2D->dstHeight, GalTest2D->dstStride, __FUNCTION__);
	GalSaveDIB(GalTest2D->dstLgcAddr, gcvSURF_A8R8G8B8, GalTest2D->dstStride, GalTest2D->dstWidth, GalTest2D->dstHeight, "/tmp/test.bmp");
    return gcvTRUE;

OnError:

    GalOutput(GalOutputType_Error | GalOutputType_Console,
        "%s(%d) failed:%s\n",__FUNCTION__, __LINE__, gcoOS_DebugStatus2Name(status));

    return gcvFALSE;
}
/*
 *  Name:       Run()
 *  Returns:    None.
 *  Parameters: None.
*/

/*******************************************************************************
**
**  main
**
**  Test entry point.
**
**  INPUT:
**
**      Command lines.
**
**  OUTPUT:
**
**      Nothing.
**
**  RETURN:
**
**      int
**          Exit value.
*/
int main(int argc, const char *argv[])
{
    /* Assume failure. */
    int result = -1;
    const char* bmpFileName ;

    if(argc < 2){
        Usage(argv[0]);
	return 1;
    }

    if(!ParseCmdLine(argc, argv))
	return 1;

    bmpFileName = dstFile;
    /* default arguements */
    memset(&g_Runtime, 0, sizeof(g_Runtime));

    /* target surface. */
    g_Runtime.target    = gcvNULL;
    if(dstGeom.width != 0 && dstGeom.height != 0){
    	g_Runtime.width   = dstGeom.width;
    	g_Runtime.height  = dstGeom.height;
    }
    else {
    	g_Runtime.width   = 800;
    	g_Runtime.height  = 480;
    }
    
    printf("DBG : width(%d) height(%d)  at %s\n", g_Runtime.width, g_Runtime.height, __FUNCTION__);
    
    g_Runtime.format  = gcvSURF_A8R8G8B8;
    //g_Runtime.format  = gcvSURF_NV12;    
    //printf("DBG : force gcvSURF_NV12. at %s\n", __FUNCTION__);
    
    g_Runtime.pool  = gcvPOOL_DEFAULT;

    g_Runtime.argc      = 0;
    g_Runtime.argv      = g_Argv2Test;
    g_Runtime.saveTarget    = gcvTRUE;
    g_Runtime.noSaveTargetNew = gcvFALSE;
    // error
    //g_Runtime.cleanTarget = gcvTRUE;
    g_Runtime.createTarget = gcvTRUE;
    // error
    //g_Runtime.notSupport = gcvFALSE;
	


    do
    {
        /* Initialize the test. */
        if (!Initialize())
        {
            /*
            if (!g_Runtime.notSupport)
                sysOutput("Initialize test failed\n");
            else
                sysOutput("Cannot initialize test because hw feature is not supported.\n");
            */
                
            result = 0;
            break;
        }
	
	//sleep(1);
	//DPRINTF("before Render.\n"); 	
	Render(GalTest2D);
	//DPRINTF("after Render.\n"); 	
	
	if(bmpFileName)
        	GalSaveSurface2DIB(g_Runtime.target, bmpFileName);

        result = 0;
    }
    while (gcvFALSE);

    /* Cleanup the test environment. */
    Finalize();
    sysOutput("Successfully completed\n");	
    return result;
}

