/*******************************************************************************
**
**  gckHEAP_Allocate
**
**  Allocate data from the heap.
**
**  INPUT:
**
**      gckHEAP Heap
**          Pointer to a gckHEAP object.
**
**      IN gctSIZE_T Bytes
**          Number of byte to allocate.
**
**  OUTPUT:
**
**      gctPOINTER * Memory
**          Pointer to a variable that will hold the address of the allocated
**          memory.
*/
gceSTATUS
gckHEAP_Allocate(
    IN gckHEAP Heap,
    IN gctSIZE_T Bytes,
    OUT gctPOINTER * Memory
    )
{
    gctBOOL acquired = gcvFALSE;
    gcskHEAP_PTR heap;
    gceSTATUS status;
    gctSIZE_T bytes;
    gcskNODE_PTR node, used, prevFree = gcvNULL;
    gctPOINTER memory = gcvNULL;

    gcmkHEADER_ARG("Heap=0x%x Bytes=%lu", Heap, Bytes);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
    gcmkVERIFY_ARGUMENT(Bytes > 0);
    gcmkVERIFY_ARGUMENT(Memory != gcvNULL);

    /* Determine number of bytes required for a node. */
    bytes = gcmALIGN(Bytes + gcmSIZEOF(gcskNODE), 8);

    /* Acquire the mutex. */
    gcmkONERROR(
        gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));

    acquired = gcvTRUE;

    /* Check if this allocation is bigger than the default allocation size. */
    if (bytes > Heap->allocationSize - gcmSIZEOF(gcskHEAP) - gcmSIZEOF(gcskNODE))
    {
        /* Adjust allocation size. */
        Heap->allocationSize = bytes * 2;
    }

    else if (Heap->heap != gcvNULL)
    {
        gctINT i;

        /* 2 retries, since we might need to compact. */
        for (i = 0; i < 2; ++i)
        {
            /* Walk all the heaps. */
            for (heap = Heap->heap; heap != gcvNULL; heap = heap->next)
            {
                /* Check if this heap has enough bytes to hold the request. */
                if (bytes <= heap->size - gcmSIZEOF(gcskNODE))
                {
                    prevFree = gcvNULL;

                    /* Walk the chain of free nodes. */
                    for (node = heap->freeList;
                         node != gcvNULL;
                         node = node->next
                    )
                    {
                        gcmkASSERT(node->next != gcdIN_USE);

                        /* Check if this free node has enough bytes. */
                        if (node->bytes >= bytes)
                        {
                            /* Use the node. */
                            goto UseNode;
                        }

                        /* Save current free node for linked list management. */
                        prevFree = node;
                    }
                }
            }

            if (i == 0)
            {
                /* Compact the heap. */
                gcmkVERIFY_OK(_CompactKernelHeap(Heap));

#if gcmIS_DEBUG(gcdDEBUG_CODE)
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "===== KERNEL HEAP =====");
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Number of allocations           : %12u",
                               Heap->allocCount);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Number of bytes allocated       : %12llu",
                               Heap->allocBytes);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Maximum allocation size         : %12llu",
                               Heap->allocBytesMax);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Total number of bytes allocated : %12llu",
                               Heap->allocBytesTotal);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Number of heaps                 : %12u",
                               Heap->heapCount);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Heap memory in bytes            : %12llu",
                               Heap->heapMemory);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Maximum number of heaps         : %12u",
                               Heap->heapCountMax);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Maximum heap memory in bytes    : %12llu",
                               Heap->heapMemoryMax);
#endif
            }
        }
    }

    /* Release the mutex. */
    gcmkONERROR(
        gckOS_ReleaseMutex(Heap->os, Heap->mutex));

    acquired = gcvFALSE;

    /* Allocate a new heap. */
    gcmkONERROR(
        gckOS_AllocateMemory(Heap->os,
                             Heap->allocationSize,
                             &memory));

    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP,
                   "Allocated heap 0x%x (%lu bytes)",
                   memory, Heap->allocationSize);

    /* Acquire the mutex. */
    gcmkONERROR(
        gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));

    acquired = gcvTRUE;

    /* Use the allocated memory as the heap. */
    heap = (gcskHEAP_PTR) memory;

    /* Insert this heap to the head of the chain. */
    heap->next = Heap->heap;
    heap->prev = gcvNULL;
    heap->size = Heap->allocationSize - gcmSIZEOF(gcskHEAP);

    if (heap->next != gcvNULL)
    {
        heap->next->prev = heap;
    }
    Heap->heap = heap;

    /* Mark the end of the heap. */
    node = (gcskNODE_PTR) ( (gctUINT8_PTR) heap
                          + Heap->allocationSize
                          - gcmSIZEOF(gcskNODE)
                          );
    node->bytes = 0;
    node->next  = gcvNULL;

    /* Create a free list. */
    node           = (gcskNODE_PTR) (heap + 1);
    heap->freeList = node;

    /* Initialize the free list. */
    node->bytes = heap->size - gcmSIZEOF(gcskNODE);
    node->next  = gcvNULL;

    /* No previous free. */
    prevFree = gcvNULL;

#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
    /* Update profiling. */
    Heap->heapCount  += 1;
    Heap->heapMemory += Heap->allocationSize;

    if (Heap->heapCount > Heap->heapCountMax)
    {
        Heap->heapCountMax = Heap->heapCount;
    }
    if (Heap->heapMemory > Heap->heapMemoryMax)
    {
        Heap->heapMemoryMax = Heap->heapMemory;
    }
#endif

UseNode:
    /* Verify some stuff. */
    gcmkASSERT(heap != gcvNULL);
    gcmkASSERT(node != gcvNULL);
    gcmkASSERT(node->bytes >= bytes);

    if (heap->prev != gcvNULL)
    {
        /* Unlink the heap from the linked list. */
        heap->prev->next = heap->next;
        if (heap->next != gcvNULL)
        {
            heap->next->prev = heap->prev;
        }

        /* Move the heap to the front of the list. */
        heap->next       = Heap->heap;
        heap->prev       = gcvNULL;
        Heap->heap       = heap;
        heap->next->prev = heap;
    }

    /* Check if there is enough free space left after usage for another free
    ** node. */
    if (node->bytes - bytes >= gcmSIZEOF(gcskNODE))
    {
        /* Allocated used space from the back of the free list. */
        used = (gcskNODE_PTR) ((gctUINT8_PTR) node + node->bytes - bytes);

        /* Adjust the number of free bytes. */
        node->bytes -= bytes;
        gcmkASSERT(node->bytes >= gcmSIZEOF(gcskNODE));
    }
    else
    {
        /* Remove this free list from the chain. */
        if (prevFree == gcvNULL)
        {
            heap->freeList = node->next;
        }
        else
        {
            prevFree->next = node->next;
        }

        /* Consume the entire free node. */
        used  = (gcskNODE_PTR) node;
        bytes = node->bytes;
    }

    /* Mark node as used. */
    used->bytes     = bytes;
    used->next      = gcdIN_USE;
#if gcmIS_DEBUG(gcdDEBUG_CODE)
    used->timeStamp = ++Heap->timeStamp;
#endif

#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
    /* Update profile counters. */
    Heap->allocCount      += 1;
    Heap->allocBytes      += bytes;
    Heap->allocBytesMax    = gcmMAX(Heap->allocBytes, Heap->allocBytesMax);
    Heap->allocBytesTotal += bytes;
#endif

    /* Release the mutex. */
    gcmkVERIFY_OK(
        gckOS_ReleaseMutex(Heap->os, Heap->mutex));

    /* Return pointer to memory. */
    *Memory = used + 1;

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

OnError:
    if (acquired)
    {
        /* Release the mutex. */
        gcmkVERIFY_OK(
            gckOS_ReleaseMutex(Heap->os, Heap->mutex));
    }

    if (memory != gcvNULL)
    {
        /* Free the heap memory. */
        gckOS_FreeMemory(Heap->os, memory);
    }

    /* Return the status. */
    gcmkFOOTER();
    return status;
}
gceSTATUS
_StretchBlitPE1x(
    IN gcsCOPYBIT_CONTEXT * Context,
    IN struct copybit_image_t const  * Dest,
    IN struct copybit_image_t const  * Source,
    IN struct copybit_rect_t const   * DestRect,
    IN struct copybit_rect_t const   * SourceRect,
    IN struct copybit_region_t const * Clip)
{
    gceSTATUS status = gcvSTATUS_OK;

    gceSURF_FORMAT siFormat;
    gceSURF_FORMAT diFormat;

    gctUINT32      diPhysical = ~0;
    gctUINT32      diAlignedWidth;
    gctUINT32      diAlignedHeight;
    gctINT         diStride;

    gcsRECT srcRect;
    gcsRECT dstRect;
    copybit_rect_t rect;

    gctUINT32      srcPhysical = ~0;
    gctINT         srcStride;
    gctUINT32      srcAlignedWidth;
    gctUINT32      srcAlignedHeight;
    gceSURF_FORMAT srcFormat;

    gctUINT32      dstPhysical = ~0;
    gctINT         dstStride;
    gctUINT32      dstAlignedWidth;
    gctUINT32      dstAlignedHeight;
    gceSURF_FORMAT dstFormat;

    gctBOOL stretch   = gcvFALSE;
    gctBOOL yuvFormat = gcvFALSE;
    gctBOOL perpixelAlpha;

    gc_private_handle_t* dsthnd = (gc_private_handle_t *) Dest->handle;
    gc_private_handle_t* srchnd = (gc_private_handle_t *) Source->handle;

    LOGV("Blit from Source hnd=%p, to Dest hnd=%p", srchnd, dsthnd);

    if (gc_private_handle_t::validate(dsthnd) < 0)
    {
        gcmTRACE(gcvLEVEL_ERROR,
                 "Invalid hnd in funciton %s",
                 __func__);

        return gcvSTATUS_INVALID_ARGUMENT;
    }

    siFormat = (gceSURF_FORMAT) srchnd->format;
    diFormat = (gceSURF_FORMAT) dsthnd->format;

    if ((siFormat == gcvSURF_UNKNOWN)
    ||  (diFormat == gcvSURF_UNKNOWN)
    )
    {
        gcmTRACE(gcvLEVEL_ERROR,
                 "Image format not support in copybit!");

        return gcvSTATUS_INVALID_ARGUMENT;
    }

    /* Convert to supported Source format. */
    siFormat = (siFormat == gcvSURF_A8B8G8R8) ? gcvSURF_A8R8G8B8 : siFormat;
    siFormat = (siFormat == gcvSURF_X8B8G8R8) ? gcvSURF_X8R8G8B8 : siFormat;

    /* Convert to supported Dest format. */
    diFormat = (diFormat == gcvSURF_A8B8G8R8) ? gcvSURF_A8R8G8B8 : diFormat;
    diFormat = (diFormat == gcvSURF_X8B8G8R8) ? gcvSURF_X8R8G8B8 : diFormat;

    do
    {
        srcPhysical = srchnd->phys;
        gcoSURF_GetAlignedSize((gcoSURF) srchnd->surface,
                               &srcAlignedWidth,
                               &srcAlignedHeight,
                               &srcStride);

        diPhysical = dsthnd->phys;
        gcoSURF_GetAlignedSize((gcoSURF) dsthnd->surface,
                               &diAlignedWidth,
                               &diAlignedHeight,
                               &diStride);

        if  ((((gcoSURF)srchnd->surface)->info.type == gcvSURF_BITMAP) &&
            !(srchnd->flags & gc_private_handle_t::PRIV_FLAGS_FRAMEBUFFER))
        {
            /* Clean the CPU cache. Source would've been rendered by the CPU. */
            gcmERR_BREAK(
                gcoSURF_CPUCacheOperation(
                            (gcoSURF) srchnd->surface,
                            gcvCACHE_CLEAN
                            )
            );
        }

        perpixelAlpha = _HasAlpha(siFormat) &&
                 (dsthnd->flags & gc_private_handle_t::PRIV_FLAGS_FRAMEBUFFER) &&
                 !(srchnd->flags & gc_private_handle_t::PRIV_FLAGS_FRAMEBUFFER);

        if (Context->perpixelAlpha != perpixelAlpha)
        {
            Context->perpixelAlpha = perpixelAlpha;

            if (Context->planeAlpha == 0xff)
            {
                Context->dirty.s.alphaKey = 1;
            }
        }

        /* Need temp surface if source has alpha channel, but dest not. */
        Context->needAlphaDest = Context->perpixelAlpha &&
                !_HasAlpha(diFormat);

        if (Context->needAlphaDest)
        {
            gcsRECT tempRect;

            tempRect.left   = gcmMAX(0, DestRect->l);
            tempRect.top    = gcmMAX(0, DestRect->t);
            tempRect.right  = gcmMIN((int32_t) Dest->w, DestRect->r);
            tempRect.bottom = gcmMIN((int32_t) Dest->h, DestRect->b);

            gcmERR_BREAK(
                _FitSurface(Context,
                            &Context->alphaDest,
                            Dest->w,
                            Dest->h));

            if (Context->alphaDest.surface == gcvNULL)
            {
                gcmTRACE(gcvLEVEL_ERROR,
                         "fail to construct tmp surface for per_pixel_alpha");

                break;
            }

            /* Copy dest surface to temp surface. */
            gcmERR_BREAK(
                _MonoBlit(Context,
                          diPhysical,
                          diStride,
                          diFormat,
                          Context->alphaDest.physical,
                          Context->alphaDest.stride,
                          Context->alphaDest.format,
                          &tempRect));
        }

        gcmERR_BREAK(
            _UploadStates(Context));

        if (Context->needAlphaDest)
        {
            dstPhysical      = Context->alphaDest.physical;
            dstStride        = Context->alphaDest.stride;
            dstAlignedWidth  = Context->alphaDest.alignedWidth;
            dstAlignedHeight = Context->alphaDest.alignedHeight;
            dstFormat        = Context->alphaDest.format;
        }
        else
        {
            dstPhysical      = diPhysical;
            dstStride        = diStride;
            dstAlignedWidth  = diAlignedWidth;
            dstAlignedHeight = diAlignedHeight;
            dstFormat        = diFormat;
        }

        srcFormat = siFormat;

        if (Context->transform == COPYBIT_TRANSFORM_ROT_270)
        {
            srcRect.left   = SourceRect->t;
            srcRect.top    = Source->w - SourceRect->r;
            srcRect.right  = SourceRect->b;
            srcRect.bottom = Source->w - SourceRect->l;
        }
        else
        {
            srcRect.left   = SourceRect->l;
            srcRect.top    = SourceRect->t;
            srcRect.right  = SourceRect->r;
            srcRect.bottom = SourceRect->b;
        }

        if (Context->transform ==  COPYBIT_TRANSFORM_ROT_90)
        {
            dstRect.left   = DestRect->t;
            dstRect.top    = Dest->w - DestRect->r;
            dstRect.right  = DestRect->b;
            dstRect.bottom = Dest->w - DestRect->l;
        }
        else
        {
            dstRect.left   = DestRect->l;
            dstRect.top    = DestRect->t;
            dstRect.right  = DestRect->r;
            dstRect.bottom = DestRect->b;
        }

        /* Check yuv format. */
        yuvFormat = (srcFormat == gcvSURF_YUY2 || srcFormat == gcvSURF_UYVY);

        stretch =
            (srcRect.right - srcRect.left) != (dstRect.right - dstRect.left) ||
            (srcRect.bottom - srcRect.top) != (dstRect.bottom - dstRect.top);

        /* Upload stretch factor. */
        if (stretch)
        {
            int hFactor;
            int vFactor;

            if ((dstRect.right-dstRect.left) > 1 && (dstRect.bottom-dstRect.top) > 1)
            {
                hFactor = ((srcRect.right - srcRect.left - 1) << 16) /
                        (dstRect.right - dstRect.left - 1);

                vFactor = ((srcRect.bottom - srcRect.top - 1) << 16) /
                        (dstRect.bottom - dstRect.top - 1);
            }
            else
            {
                hFactor = 0;
                vFactor = 0;
            }

            gcmERR_BREAK(
                gco2D_SetStretchFactors(Context->engine,
                                        hFactor,
                                        vFactor));
        }

        /* Prepare source and target for normal blit. */
        gcmERR_BREAK(
            gco2D_SetColorSource(Context->engine,
                                 srcPhysical,
                                 srcStride,
                                 srcFormat,
                                 Context->srcRotation,
                                 srcAlignedWidth,
                                 gcvFALSE,
                                 gcvSURF_OPAQUE,
                                 0));

        gcmERR_BREAK(
            gco2D_SetSource(Context->engine,
                            &srcRect));

        gcmERR_BREAK(
            gco2D_SetTarget(Context->engine,
                            dstPhysical,
                            dstStride,
                            Context->dstRotation,
                            dstAlignedWidth));

        gcsRECT srcRectBackup = srcRect;
        gcsRECT dstRectBackup = dstRect;

        /* Go though all clip rectangles. */
        while (Clip->next(Clip, &rect))
        {
            gcsRECT clipRect;

            srcRect = srcRectBackup;
            dstRect = dstRectBackup;

            if (Context->transform ==  COPYBIT_TRANSFORM_ROT_90)
            {
                clipRect.left   = rect.t;
                clipRect.top    = Dest->w - rect.r;
                clipRect.right  = rect.b;
                clipRect.bottom = Dest->w - rect.l;
            }
            else if (Context->transform == COPYBIT_TRANSFORM_ROT_180)
            {
                float hfactor = (float) (SourceRect->r - SourceRect->l)
                                 / (DestRect->r - DestRect->l);

                float vfactor = (float) (SourceRect->b - SourceRect->t)
                                 / (DestRect->b - DestRect->t);

                /* Intersect. */
                clipRect.left   = gcmMAX(dstRect.left, rect.l);
                clipRect.top    = gcmMAX(dstRect.top, rect.t);
                clipRect.right  = gcmMIN(dstRect.right, rect.r);
                clipRect.bottom = gcmMIN(dstRect.bottom, rect.b);

                /* Adjust src rectangle. */
                srcRect.left   += (int) ((dstRect.right - clipRect.right) * hfactor);
                srcRect.top    += (int) ((dstRect.bottom - clipRect.bottom) * vfactor);
                srcRect.right  -= (int) ((clipRect.left - dstRect.left) * hfactor);
                srcRect.bottom -= (int) ((clipRect.top - dstRect.top) * vfactor);

                /* Set dstRect to clip rectangle. */
                dstRect = clipRect;

                if ((srcRect.left   != srcRectBackup.left)
                ||  (srcRect.right  != srcRectBackup.right)
                ||  (srcRect.top    != srcRectBackup.top)
                ||  (srcRect.bottom != srcRectBackup.bottom)
                )
                {
                    gcmERR_BREAK(
                        gco2D_SetSource(Context->engine,
                                        &srcRect));
                }
            }
            else
            {
                clipRect.left   = rect.l;
                clipRect.top    = rect.t;
                clipRect.right  = rect.r;
                clipRect.bottom = rect.b;
            }

            /* Clamp clip rectangle. */
            if (clipRect.right > dstRect.right)
                clipRect.right = dstRect.right;

            if (clipRect.bottom > dstRect.bottom)
                clipRect.bottom = dstRect.bottom;

            if (clipRect.left < dstRect.left)
                clipRect.left = dstRect.left;

            if (clipRect.top < dstRect.top)
                clipRect.top = dstRect.top;

            gcmERR_BREAK(
                gco2D_SetClipping(Context->engine,
                                  &clipRect));

            if (yuvFormat)
            {
                /* TODO: FilterBlit does not support rotation before PE20. */
                /* Video filter blit */
                /* 1. SetClipping() has no effect for FilterBlit()
                 *    so we use dstSubRect to realize clipping effect
                 * 2. Only FilterBlit support yuv format covertion.
                 */
                gcsRECT dstSubRect;
                int dstWidth   = dstRect.right   - dstRect.left;
                int dstHeight  = dstRect.bottom  - dstRect.top;
                int clipWidth  = clipRect.right  - clipRect.left;
                int clipHeight = clipRect.bottom - clipRect.top;

                dstSubRect.left   = clipRect.left - dstRect.left;
                dstSubRect.top    = clipRect.top - dstRect.top;
                dstSubRect.right  = dstWidth < clipWidth ?
                        dstSubRect.left + dstWidth :
                        dstSubRect.left + clipWidth;
                dstSubRect.bottom = dstHeight < clipHeight ?
                        dstSubRect.top  + dstHeight :
                        dstSubRect.top  + clipHeight;

                gcmERR_BREAK(
                    gco2D_SetKernelSize(Context->engine,
                                        gcdFILTER_BLOCK_SIZE,
                                        gcdFILTER_BLOCK_SIZE));

                gcmERR_BREAK(
                    gco2D_SetFilterType(Context->engine,
                                        gcvFILTER_SYNC));

                gcmERR_BREAK(
                    gco2D_FilterBlit(Context->engine,
                                     srcPhysical,
                                     srcStride,
                                     0, 0, 0, 0,
                                     srcFormat,
                                     Context->srcRotation,
                                     srcAlignedWidth,
                                     &srcRect,
                                     dstPhysical,
                                     dstStride,
                                     dstFormat,
                                     Context->dstRotation,
                                     dstAlignedWidth,
                                     &dstRect,
                                     &dstSubRect));
            }
            else if (Context->blur)
            {
                /* TODO: FilterBlit does not support rotation before PE20. */
                gcsRECT dstSubRect;
                dstSubRect.left  = 0;
                dstSubRect.top   = 0;
                dstSubRect.right = dstRect.right - dstRect.left;
                dstSubRect.bottom = dstRect.bottom - dstRect.top;

                /* Blur blit. */
                gcmERR_BREAK(
                    gco2D_SetKernelSize(Context->engine,
                                        gcdFILTER_BLOCK_SIZE,
                                        gcdFILTER_BLOCK_SIZE));

                gcmERR_BREAK(
                    gco2D_SetFilterType(Context->engine,
                                        gcvFILTER_BLUR));

                gcmERR_BREAK(
                    gco2D_FilterBlit(Context->engine,
                                     srcPhysical,
                                     srcStride,
                                     0, 0, 0, 0,
                                     srcFormat,
                                     gcvSURF_0_DEGREE,
                                     srcAlignedWidth,
                                     &srcRect,
                                     dstPhysical,
                                     dstStride,
                                     dstFormat,
                                     gcvSURF_0_DEGREE,
                                     dstAlignedWidth,
                                     &dstRect,
                                     &dstSubRect));

                gcmERR_BREAK(
                    gco2D_FilterBlit(Context->engine,
                                     dstPhysical,
                                     dstStride,
                                     0, 0, 0, 0,
                                     dstFormat,
                                     gcvSURF_0_DEGREE,
                                     dstAlignedWidth,
                                     &dstRect,
                                     dstPhysical,
                                     dstStride,
                                     dstFormat,
                                     gcvSURF_0_DEGREE,
                                     dstAlignedWidth,
                                     &dstRect,
                                     &dstSubRect));

                /* TODO: surfaceflinger set blur issue. */
                Context->blur = COPYBIT_DISABLE;
            }
            else if (stretch == gcvFALSE)
            {
                /* BitBlit. */
                gcmERR_BREAK(
                    gco2D_Blit(Context->engine,
                               1,
                               &dstRect,
                               0xCC,
                               0xCC,
                               dstFormat));
            }
            else
            {
                /* Normal stretch blit. */
                gcmERR_BREAK(
                    gco2D_StretchBlit(Context->engine,
                                      1,
                                      &dstRect,
                                      0xCC,
                                      0xCC,
                                      dstFormat));
            }
        }

        if (gcmIS_ERROR(status))
        {
            break;
        }

        if (Context->needAlphaDest)
        {
            gcsRECT tempRect;

            tempRect.left   = gcmMAX(0, DestRect->l);
            tempRect.top    = gcmMAX(0, DestRect->t);
            tempRect.right  = gcmMIN((int32_t) Dest->w, DestRect->r);
            tempRect.bottom = gcmMIN((int32_t) Dest->h, DestRect->b);

            /* Blit back to actual dest. */
            gcmERR_BREAK(
                _MonoBlit(Context,
                          Context->alphaDest.physical,
                          Context->alphaDest.stride,
                          Context->alphaDest.format,
                          diPhysical,
                          diStride,
                          diFormat,
                          &tempRect));
        }

        /* Flush and commit. */
        gcmERR_BREAK(
            gco2D_Flush(Context->engine));

        gcmERR_BREAK(
            gcoHAL_Commit(gcvNULL, gcvFALSE));
    }
    while (gcvFALSE);

    return status;
}
static void
_Policy(
    IN gckDVFS Dvfs,
    IN gctUINT32 Load,
    OUT gctUINT8 *Scale
    )
{
    gctUINT8 load[4], nextLoad;
    gctUINT8 scale;

    /* Last 4 history. */
    load[0] = (Load & 0xFF);
    load[1] = (Load & 0xFF00) >> 8;
    load[2] = (Load & 0xFF0000) >> 16;
    load[3] = (Load & 0xFF000000) >> 24;

    /* Determine target scale. */
    if (load[0] > 54)
    {
        _IncreaseScale(Dvfs, Load, &scale);
    }
    else
    {
        nextLoad = (load[0] + load[1] + load[2] + load[3])/4;

        scale = Dvfs->currentScale * (nextLoad) / 54;

        scale = gcmMAX(1, scale);
        scale = gcmMIN(64, scale);
    }

    Dvfs->totalConfig++;

    Dvfs->loads[(load[0]-1)/8]++;

    *Scale = scale;


    if (Dvfs->totalConfig % 100 == 0)
    {
        gcmkPRINT("=======================================================");
        gcmkPRINT("GPU Load:       %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d",
                                   8, 16, 24, 32, 40, 48, 56, 64);
        gcmkPRINT("                %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d",
                  _GetLoadHistory(Dvfs,2, 0),
                  _GetLoadHistory(Dvfs,2, 1),
                  _GetLoadHistory(Dvfs,2, 2),
                  _GetLoadHistory(Dvfs,2, 3),
                  _GetLoadHistory(Dvfs,2, 4),
                  _GetLoadHistory(Dvfs,2, 5),
                  _GetLoadHistory(Dvfs,2, 6),
                  _GetLoadHistory(Dvfs,2, 7)
                  );

        gcmkPRINT("Frequency(MHz)  %-8d %-8d %-8d %-8d %-8d",
                  58, 120, 240, 360, 480);
        gcmkPRINT("                %-8d %-8d %-8d %-8d %-8d",
                  _GetFrequencyHistory(Dvfs, 58),
                  _GetFrequencyHistory(Dvfs,120),
                  _GetFrequencyHistory(Dvfs,240),
                  _GetFrequencyHistory(Dvfs,360),
                  _GetFrequencyHistory(Dvfs,480)
                  );
    }
}
Пример #4
0
VEGLThreadData
veglGetThreadData(
    void
    )
{
    gcsTLS_PTR tls = gcvNULL;
    gceSTATUS status;
#if gcdENABLE_VG
    gctINT32 i;
#endif
    gcmHEADER();

    gcmONERROR(gcoOS_GetTLS(&tls));

    if (tls->context == gcvNULL)
    {
        gctPOINTER pointer = gcvNULL;
        VEGLThreadData thread;

        gcmONERROR(gcoOS_Allocate(
            gcvNULL, gcmSIZEOF(struct eglThreadData), &pointer
            ));

        gcmONERROR(gcoOS_ZeroMemory(
            pointer, gcmSIZEOF(struct eglThreadData)
            ));

        /* Initialize TLS record. */
        tls->context    = pointer;
        tls->destructor = _DestroyThreadData;

        /* Cast the pointer. */
        thread = (VEGLThreadData) pointer;

        /* Initialize the thread data. */
        thread->error             = EGL_SUCCESS;
        thread->api               = EGL_OPENGL_ES_API;
        thread->lastClient        = 1;
		thread->worker = gcvNULL;

        tls->currentType           = gcvHARDWARE_3D;
#if veglUSE_HAL_DUMP
        /* Get the gcoDUMP object. */
        gcmONERROR(gcoHAL_GetDump(thread->hal, &thread->dump));
#endif

#if gcdENABLE_VG
        gcmONERROR(gcoHAL_QueryChipCount(gcvNULL, &thread->chipCount));

        for (i = 0; i < thread->chipCount; i++)
        {
            gcmONERROR(gcoHAL_QueryChipLimits(gcvNULL, i, &thread->chipLimits[i]));
        }

        for (i = 0; i < thread->chipCount; i++)
        {
            thread->maxWidth =
                gcmMAX(thread->maxWidth, (gctINT32)thread->chipLimits[i].maxWidth);

            thread->maxHeight =
                gcmMAX(thread->maxHeight, (gctINT32)thread->chipLimits[i].maxHeight);

            thread->maxSamples =
                gcmMAX(thread->maxSamples, (gctINT32)thread->chipLimits[i].maxSamples);
        }

        for (i = 0; i < thread->chipCount; i++)
        {
            /* Query VAA support. */
            if (gcoHAL_QueryChipFeature(gcvNULL, i, gcvFEATURE_VAA))
            {
                thread->vaa = gcvTRUE;
                break;
            }
        }

        for (i = 0; i < thread->chipCount; i++)
        {
            if (gcoHAL_QueryChipFeature(gcvNULL, i, gcvFEATURE_PIPE_VG))
            {
                thread->openVGpipe = _IsHWVGDriverAvailable(thread);
                break;
            }
        }
#else
        /* Query the hardware identity. */
        gcmONERROR(gcoHAL_QueryChipIdentity(
            gcvNULL,
            &thread->chipModel,
            gcvNULL, gcvNULL, gcvNULL
            ));

        /* Query the hardware capabilities. */
        gcmONERROR(gcoHAL_QueryTargetCaps(
            gcvNULL,
            (gctUINT32_PTR) &thread->maxWidth,
            (gctUINT32_PTR) &thread->maxHeight,
            gcvNULL,
            (gctUINT32_PTR) &thread->maxSamples
            ));

        /* Query VAA support. */
        thread->vaa
            =  gcoHAL_IsFeatureAvailable(gcvNULL, gcvFEATURE_VAA)
            == gcvSTATUS_TRUE;

        /* Query OpenVG pipe support. */
        thread->openVGpipe
            =  gcoHAL_IsFeatureAvailable(gcvNULL, gcvFEATURE_PIPE_VG)
            == gcvSTATUS_TRUE;
#endif

        gcmTRACE_ZONE(
            gcvLEVEL_VERBOSE, gcdZONE_EGL_API,
            "%s(%d): maxWidth=%d maxHeight=%d maxSamples=%d vaa=%d openVG=%d",
            __FUNCTION__, __LINE__,
            thread->maxWidth, thread->maxHeight, thread->maxSamples,
            thread->vaa, thread->openVGpipe
            );
    }