/*******************************************************************************
**
**  gckVIDMEM_Allocate
**
**  Allocate rectangular memory from the gckVIDMEM object.
**
**  INPUT:
**
**      gckVIDMEM Memory
**          Pointer to an gckVIDMEM object.
**
**      gctUINT Width
**          Width of rectangle to allocate.  Make sure the width is properly
**          aligned.
**
**      gctUINT Height
**          Height of rectangle to allocate.  Make sure the height is properly
**          aligned.
**
**      gctUINT Depth
**          Depth of rectangle to allocate.  This equals to the number of
**          rectangles to allocate contiguously (i.e., for cubic maps and volume
**          textures).
**
**      gctUINT BytesPerPixel
**          Number of bytes per pixel.
**
**      gctUINT32 Alignment
**          Byte alignment for allocation.
**
**      gceSURF_TYPE Type
**          Type of surface to allocate (use by bank optimization).
**
**  OUTPUT:
**
**      gcuVIDMEM_NODE_PTR * Node
**          Pointer to a variable that will hold the allocated memory node.
*/
gceSTATUS
gckVIDMEM_Allocate(
    IN gckVIDMEM Memory,
    IN gctUINT Width,
    IN gctUINT Height,
    IN gctUINT Depth,
    IN gctUINT BytesPerPixel,
    IN gctUINT32 Alignment,
    IN gceSURF_TYPE Type,
#ifdef __QNXNTO__
    IN gctHANDLE Handle,
#endif
    OUT gcuVIDMEM_NODE_PTR * Node
    )
{
    gctSIZE_T bytes;
    gceSTATUS status;

    gcmkHEADER_ARG("Memory=0x%x Width=%u Height=%u Depth=%u BytesPerPixel=%u "
                   "Alignment=%u Type=%d",
                   Memory, Width, Height, Depth, BytesPerPixel, Alignment,
                   Type);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
    gcmkVERIFY_ARGUMENT(Width > 0);
    gcmkVERIFY_ARGUMENT(Height > 0);
    gcmkVERIFY_ARGUMENT(Depth > 0);
    gcmkVERIFY_ARGUMENT(BytesPerPixel > 0);
    gcmkVERIFY_ARGUMENT(Node != gcvNULL);
#ifdef __QNXNTO__
    gcmkVERIFY_ARGUMENT(Handle != gcvNULL);
#endif

    /* Compute linear size. */
    bytes = Width * Height * Depth * BytesPerPixel;

    /* Allocate through linear function. */
#ifdef __QNXNTO__
    gcmkONERROR(
        gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Handle, Node));
#else
    gcmkONERROR(
        gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Node));
#endif

    /* Success. */
    gcmkFOOTER_ARG("*Node=0x%x", *Node);
    return gcvSTATUS_OK;

OnError:
    /* Return the status. */
    gcmkFOOTER();
    return status;
}
/*******************************************************************************
**
**  gckKERNEL_AllocateLinearMemory
**
**  Function walks all required memory pools and allocates the requested
**  amount of video memory.
**
**  INPUT:
**
**      gckKERNEL Kernel
**          Pointer to an gckKERNEL object.
**
**      gcePOOL * Pool
**          Pointer the desired memory pool.
**
**      gctSIZE_T Bytes
**          Number of bytes to allocate.
**
**      gctSIZE_T Alignment
**          Required buffer alignment.
**
**      gceSURF_TYPE Type
**          Surface type.
**
**  OUTPUT:
**
**      gcePOOL * Pool
**          Pointer to the actual pool where the memory was allocated.
**
**      gcuVIDMEM_NODE_PTR * Node
**          Allocated node.
*/
gceSTATUS
gckKERNEL_AllocateLinearMemory(
    IN gckKERNEL Kernel,
    IN OUT gcePOOL * Pool,
    IN gctSIZE_T Bytes,
    IN gctSIZE_T Alignment,
    IN gceSURF_TYPE Type,
    OUT gcuVIDMEM_NODE_PTR * Node
    )
{
    gcePOOL pool;
    gceSTATUS status;
    gckVIDMEM videoMemory;

    /* Get initial pool. */
    switch (pool = *Pool)
    {
    case gcvPOOL_DEFAULT:
    case gcvPOOL_LOCAL:
        pool = gcvPOOL_LOCAL_INTERNAL;
        break;

    case gcvPOOL_UNIFIED:
        pool = gcvPOOL_SYSTEM;
        break;

    default:
        break;
    }

    do
    {
        /* Verify the number of bytes to allocate. */
        if (Bytes == 0)
        {
            status = gcvSTATUS_INVALID_ARGUMENT;
            break;
        }

        if (pool == gcvPOOL_VIRTUAL)
        {
            /* Create a gcuVIDMEM_NODE for virtual memory. */
            gcmkERR_BREAK(gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Node));

            /* Success. */
            break;
        }

        else
        {
            /* Get pointer to gckVIDMEM object for pool. */
            status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory);

            if (status == gcvSTATUS_OK)
            {
                /* Allocate memory. */
                status = gckVIDMEM_AllocateLinear(Kernel,
                                                  videoMemory,
                                                  Bytes,
                                                  Alignment,
                                                  Type,
                                                  Node);

                if (status == gcvSTATUS_OK)
                {
                    /* Memory allocated. */
                    break;
                }
            }
        }

        if (pool == gcvPOOL_LOCAL_INTERNAL)
        {
            /* Advance to external memory. */
            pool = gcvPOOL_LOCAL_EXTERNAL;
        }
        else if (pool == gcvPOOL_LOCAL_EXTERNAL)
        {
            /* Advance to contiguous system memory. */
            pool = gcvPOOL_SYSTEM;
        }
        else if (pool == gcvPOOL_SYSTEM)
        {
            /* Advance to virtual memory. */
            pool = gcvPOOL_VIRTUAL;
        }
        else
        {
            /* Out of pools. */
            break;
        }
    }
    /* Loop only for multiple selection pools. */
    while ((*Pool == gcvPOOL_DEFAULT)
    ||     (*Pool == gcvPOOL_LOCAL)
    ||     (*Pool == gcvPOOL_UNIFIED)
    );

    if (gcmIS_SUCCESS(status))
    {
        /* Return pool used for allocation. */
        *Pool = pool;
    }

    /* Return status. */
    return status;
}
/*******************************************************************************
**
**	_AllocateMemory
**
**	Private function to walk all required memory pools to allocate the requested
**	amount of video memory.
**
**	INPUT:
**
**		gckKERNEL Kernel
**			Pointer to an gckKERNEL object.
**
**		gcsHAL_INTERFACE * Interface
**			Pointer to a gcsHAL_INTERFACE structure that defines the command to
**			be dispatched.
**
**	OUTPUT:
**
**		gcsHAL_INTERFACE * Interface
**			Pointer to a gcsHAL_INTERFACE structure that receives any data to be
**			returned.
*/
static gceSTATUS
_AllocateMemory(
	IN gckKERNEL Kernel,
	IN OUT gcePOOL * Pool,
	IN gctSIZE_T Bytes,
	IN gctSIZE_T Alignment,
	IN gceSURF_TYPE Type,
#ifdef __QNXNTO__
	IN gctHANDLE Handle,
#endif
	OUT gcuVIDMEM_NODE_PTR * Node
	)
{
	gcePOOL pool;
	gceSTATUS status;
	gckVIDMEM videoMemory;

	gcmkVERIFY_ARGUMENT(Pool != gcvNULL);

	/* Get initial pool. */
	switch (pool = *Pool)
	{
	case gcvPOOL_DEFAULT:
	case gcvPOOL_LOCAL:
		pool = gcvPOOL_LOCAL_INTERNAL;
		break;

	case gcvPOOL_UNIFIED:
		pool = gcvPOOL_SYSTEM;
		break;

	default:
		break;
	}

	do
	{
		/* Verify the number of bytes to allocate. */
		if (Bytes == 0)
		{
			gcmkERR_BREAK(gcvSTATUS_INVALID_ARGUMENT);
		}

		if (pool == gcvPOOL_VIRTUAL)
		{
			/* Create a gcuVIDMEM_NODE for virtual memory. */
#ifdef __QNXNTO__
			gcmkERR_BREAK(
				gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Handle, Node));
#else
			gcmkERR_BREAK(
				gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Node));
#endif

			/* Success. */
			break;
		}
		else if (pool == gcvPOOL_CONTIGUOUS)
		{
			/* Create a gcuVIDMEM_NODE for contiguous memory. */
#ifdef __QNXNTO__
			status = gckVIDMEM_ConstructVirtual(Kernel, gcvTRUE, Bytes, Handle, Node);
#else
			status = gckVIDMEM_ConstructVirtual(Kernel, gcvTRUE, Bytes, Node);
#endif
			if (gcmIS_SUCCESS(status))
			{
				/* Memory allocated. */
				break;
			}
		}
		else
		{
			/* Get pointer to gckVIDMEM object for pool. */
			status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory);

			if (gcmIS_SUCCESS(status))
			{
				/* Allocate memory. */
				status = gckVIDMEM_AllocateLinear(videoMemory,
												  Bytes,
												  Alignment,
												  Type,
#ifdef __QNXNTO__
												  Handle,
#endif
												  Node);

				if (gcmIS_SUCCESS(status))
				{
					/* Memory allocated. */
					(*Node)->VidMem.pool = pool;
					break;
				}
			}
		}

		if (pool == gcvPOOL_LOCAL_INTERNAL)
		{
			/* Advance to external memory. */
			pool = gcvPOOL_LOCAL_EXTERNAL;
		}
		else
		if (pool == gcvPOOL_LOCAL_EXTERNAL)
		{
			/* Advance to contiguous system memory. */
			pool = gcvPOOL_SYSTEM;
		}
		else
		if (pool == gcvPOOL_SYSTEM)
		{
			/* Advance to contiguous memory. */
			pool = gcvPOOL_CONTIGUOUS;
		}
		else
		if ((pool == gcvPOOL_CONTIGUOUS)
		&&  (Type != gcvSURF_TILE_STATUS)
		)
		{
            static int count= 1;
			/* Advance to virtual memory. */
            if (count == 1)
            {
				gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
					"Try to allocate virtual memory!\n");
                count = 0;
            }
			pool = gcvPOOL_VIRTUAL;
		}
		else
		{
			/* Out of pools. */
			break;
		}
	}
	/* Loop only for multiple selection pools. */
	while ((*Pool == gcvPOOL_DEFAULT)
	||     (*Pool == gcvPOOL_LOCAL)
	||     (*Pool == gcvPOOL_UNIFIED)
	);

	if (gcmIS_SUCCESS(status))
	{
		/* Return pool used for allocation. */
		*Pool = pool;
	}

	/* Return status. */
	return status;
}