diff -r 000000000000 -r 5d03bc08d59c graphicscomposition/openwfcompositionengine/composition/src/wfccontext.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graphicscomposition/openwfcompositionengine/composition/src/wfccontext.c Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,1763 @@ +/* Copyright (c) 2009 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + */ + +/*! \ingroup wfc + * \file wfccontext.c + * + * \brief SI Context handling + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "wfccontext.h" +#include "wfcpipeline.h" + +#include "owfscreen.h" +#include "owfdisplaycontextgeneral.h" +#include "owfnotifications.h" + + +/*! maximum number of elements per scene */ +#define MAX_ELEMENTS 512 +/*! maximum number of scenes per context */ +#define MAX_SCENES 3 + + +#define CONTEXT_SCENE_POOL_SIZE MAX_SCENES +#define CONTEXT_ELEMENT_POOL_SIZE MAX_SCENES * MAX_ELEMENTS +#define CONTEXT_NODE_POOL_SIZE 2 * CONTEXT_ELEMENT_POOL_SIZE + +/*! almost 2^31 */ +#define MAX_DELAY 2100000000 + +/*! 15ms */ +#define AUTO_COMPOSE_DELAY 15000 +#define FIRST_CONTEXT_HANDLE 2000 + +#define WAIT_FOREVER -1 + +#ifdef __cplusplus +extern "C" { +#endif + +static WFCHandle nextContextHandle = FIRST_CONTEXT_HANDLE; + +typedef enum +{ + WFC_MESSAGE_NONE, + WFC_MESSAGE_QUIT, + WFC_MESSAGE_COMPOSE, + WFC_MESSAGE_COMMIT, + WFC_MESSAGE_FENCE_1_DISPLAY, + WFC_MESSAGE_FENCE_2_SYNCOBJECT, + WFC_MESSAGE_ACTIVATE, + WFC_MESSAGE_DEACTIVATE, + WFC_MESSAGE_START_COUNTDOWN, + WFC_MESSAGE_CANCEL +} WFC_MESSAGES; + +static void* +WFC_Context_ComposerThread(void* data); + + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +void WFC_CONTEXT_Ctor(void* self) +{ + self = self; +} + +/*---------------------------------------------------------------------------*/ +static WFCboolean +WFC_Context_CreateState(WFC_CONTEXT* context) + { /* Must be called late enough that scratch buffers can be mapped and hardware rotation capability queried */ + OWF_IMAGE_FORMAT fInt, + fExt; + WFCint stride = 0; + OWF_ASSERT(context); + + DPRINT(("WFC_Context_CreateContextState")); + + owfNativeStreamGetHeader(context->stream, + NULL, NULL, &stride, &fExt, NULL); + /* internal image used as intermediate target */ + fInt.pixelFormat = OWF_IMAGE_ARGB_INTERNAL; + fInt.linear = fExt.linear; + fInt.premultiplied = fExt.premultiplied; + fInt.rowPadding = 1; + + + if (context->type == WFC_CONTEXT_TYPE_ON_SCREEN) + { + /* The unrotated target buffer: Can't get real address without locking for writing! NO STRIDE */ + context->state.unrotatedTargetImage=OWF_Image_Create(context->targetWidth,context->targetHeight,&fExt,context->scratchBuffer[2],0); + /* The rotated version of the target buffer for hardware rotation + * or a de-rotated version of the internal buffer into another scratch buffer for software rotation + */ + if (OWF_Screen_Rotation_Supported(context->screenNumber)) + { /* The rotated version of the target buffer for hardware rotation */ + context->state.rotatedTargetImage=OWF_Image_Create(context->targetHeight,context->targetWidth,&fExt,context->scratchBuffer[2],0); + } + else + { /* a de-rotated version of the internal buffer into another scratch buffer for software rotation */ + context->state.rotatedTargetImage=OWF_Image_Create(context->targetWidth,context->targetHeight,&fInt,context->scratchBuffer[1],0); + } + } + else + { + /* The unrotated target buffer: Can't get real address without locking for writing! STRIDE HONOURED */ + context->state.unrotatedTargetImage=OWF_Image_Create(context->targetWidth,context->targetHeight,&fExt,context->scratchBuffer[2],stride); + /* a de-rotated version of the internal buffer into another scratch buffer for software rotation */ + context->state.rotatedTargetImage=OWF_Image_Create(context->targetWidth,context->targetHeight,&fInt,context->scratchBuffer[1],0); + } + /* The internal target buffer composed to for 0 and 180 degree rotation */ + context->state.unrotatedInternalTargetImage=OWF_Image_Create(context->targetWidth,context->targetHeight,&fInt,context->scratchBuffer[0],stride); + /* The internal target buffer composed to for 90 and 270 degree rotation */ + context->state.rotatedInternalTargetImage=OWF_Image_Create(context->targetHeight,context->targetWidth,&fInt,context->scratchBuffer[0],stride); + + if (context->state.unrotatedTargetImage && context->state.rotatedTargetImage && context->state.unrotatedInternalTargetImage && context->state.rotatedInternalTargetImage) + { + return WFC_TRUE; + } + else + { + return WFC_FALSE; + } + } +/*---------------------------------------------------------------------------*/ +static void +WFC_Context_DestroyState(WFC_CONTEXT* context) + { + /* The unrotated target buffer */ + OWF_Image_Destroy(context->state.unrotatedTargetImage); + /* The rotated version of the target buffer for hardware rotation, + * or a de-rotated version of the internal buffer into another scratch buffer for software rotation + */ + OWF_Image_Destroy(context->state.rotatedTargetImage); + /* The internal target buffer composed to for 0 and 180 degree rotation */ + OWF_Image_Destroy(context->state.unrotatedInternalTargetImage); + /* The internal target buffer composed to for 90 and 270 degree rotation */ + OWF_Image_Destroy(context->state.rotatedInternalTargetImage); + + } +/*--------------------------------------------------------------------------- + * Should only be accessed indirectly by calls to WFC_Device_DestroyContext or + * WFC_Device_DestroyContexts + *----------------------------------------------------------------------------*/ +void WFC_CONTEXT_Dtor(void* self) +{ + OWFint ii = 0; + WFC_CONTEXT* context = NULL; + + OWF_ASSERT(self); + DPRINT(("WFC_CONTEXT_Dtor(%p)", self)); + + context = CONTEXT(self); + + OWF_ASSERT(context); + + WFC_Pipeline_DestroyState(context); + WFC_Context_DestroyState(context); + + OWF_MessageQueue_Destroy(&context->composerQueue); + + /* make the stream destroyable */ + if (context->stream != OWF_INVALID_HANDLE) + { + owfNativeStreamSetProtectionFlag(context->stream, OWF_FALSE); + owfNativeStreamDestroy(context->stream); + } + context->stream = OWF_INVALID_HANDLE; + + OWF_AttributeList_Destroy(&context->attributes); + + for (ii = 0; ii < SCRATCH_BUFFER_COUNT; ii++) + { + OWF_Image_FreeData(context->displayContext, &context->scratchBuffer[ii]); + context->scratchBuffer[ii] = 0; + } + + OWF_DisplayContext_Destroy(context->screenNumber, context->displayContext); + context->displayContext = NULL; + + OWF_Pool_Destroy(context->scenePool); + OWF_Pool_Destroy(context->elementPool); + OWF_Pool_Destroy(context->nodePool); + + OWF_Semaphore_Destroy(&context->compositionSemaphore); + OWF_Semaphore_Destroy(&context->commitSemaphore); + OWF_Mutex_Destroy(&context->updateFlagMutex); + OWF_Mutex_Destroy(&context->sceneMutex); +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +OWF_API_CALL void +WFC_Context_Shutdown(WFC_CONTEXT* context) +{ + OWF_ASSERT(context); + DPRINT(("WFC_Context_Shutdown(context = %d)", context->handle)); + + DPRINT(("Waiting for composer thread termination")); + OWF_Message_Send(&context->composerQueue, WFC_MESSAGE_QUIT, 0); + OWF_Thread_Join(context->composerThread, NULL); + OWF_Thread_Destroy(context->composerThread); + context->composerThread = NULL; + + if (context->device) + { + /* #4604: added guard condition */ + WFC_Device_DestroyContextElements(context->device, context); + WFC_Device_DestroyContextImageProviders(context->device, context); + } + + WFC_Scene_Destroy(context->workScene); + WFC_Scene_Destroy(context->snapshotScene); + WFC_Scene_Destroy(context->committedScene); + context->workScene = NULL; + context->snapshotScene = NULL; + context->committedScene = NULL; +} + +/*--------------------------------------------------------------------------- + * Initialize context attributes + *----------------------------------------------------------------------------*/ +OWF_API_CALL OWF_ATTRIBUTE_LIST_STATUS +WFC_Context_InitializeAttributes(WFC_CONTEXT* context, + WFCContextType type) +{ + OWF_ATTRIBUTE_LIST_STATUS attribError=ATTR_ERROR_NONE; + OWF_ASSERT(context); + /* initialize attributes/properties */ + if (context->stream) + { + owfNativeStreamGetHeader(context->stream, + &context->targetWidth, + &context->targetHeight, + NULL, NULL, NULL); + } + context->type = type; + context->rotation = WFC_ROTATION_0; + context->backgroundColor = 0x000000FF; + context->lowestElement = WFC_INVALID_HANDLE; + + + OWF_AttributeList_Create(&context->attributes, + WFC_CONTEXT_TYPE, + WFC_CONTEXT_BG_COLOR); + attribError=OWF_AttributeList_GetError(&context->attributes); + if (attribError!=ATTR_ERROR_NONE) + { + OWF_ASSERT(attribError==ATTR_ERROR_NO_MEMORY); + return attribError; + } + + /* The composition code uses the member variables directly, + * not via the attribute engine. + */ + OWF_Attribute_Initi(&context->attributes, + WFC_CONTEXT_TYPE, + (WFCint*) &context->type, + OWF_TRUE); + + OWF_Attribute_Initi(&context->attributes, + WFC_CONTEXT_TARGET_WIDTH, + &context->targetWidth, + OWF_TRUE); + + OWF_Attribute_Initi(&context->attributes, + WFC_CONTEXT_TARGET_HEIGHT, + &context->targetHeight, + OWF_TRUE); + + OWF_Attribute_Initi(&context->attributes, + WFC_CONTEXT_ROTATION, + (WFCint*) &context->rotation, + OWF_FALSE); + + OWF_Attribute_Initi(&context->attributes, + WFC_CONTEXT_BG_COLOR, + (WFCint*) &context->backgroundColor, + OWF_FALSE); + + OWF_Attribute_Initi(&context->attributes, + WFC_CONTEXT_LOWEST_ELEMENT, + (OWFint*) &context->lowestElement, + OWF_TRUE); + attribError=OWF_AttributeList_GetError(&context->attributes); + return attribError; +} + + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +static WFC_CONTEXT* +WFC_Context_Initialize(WFC_CONTEXT* context, + WFC_DEVICE* device, + WFCNativeStreamType stream, + WFCContextType type, + WFCint screenNum) +{ + void* scratch[SCRATCH_BUFFER_COUNT]; + OWFint err2 = 0; + OWFint ii = 0, + nbufs = 0; + OWFint fail = 0; + OWF_ATTRIBUTE_LIST_STATUS attribStatus = ATTR_ERROR_NONE; + OWF_ASSERT(context); + OWF_ASSERT(device); + + DPRINT(("WFC_Context_Initialize(%p,%p,%d,%d)", context, device, type, screenNum)); + + context->type = type; + context->device = device; + context->handle = nextContextHandle; + context->screenNumber = screenNum; + context->activationState = WFC_CONTEXT_STATE_PASSIVE; + context->sourceUpdateCount = 0; + context->clientElementCount = 0; + ++nextContextHandle; + + context->displayContext = OWF_DisplayContext_Create(screenNum); + if (context->displayContext == NULL) + { + DPRINT(("WFC_Context_Initialize(): Could not create display Context")); + return NULL; + } + + context->eglPrivateSignalSync = (TFPtrEglPrivateSignalSyncNok) eglGetProcAddress("egl_Private_SignalSyncNOK"); + if (! context->eglPrivateSignalSync) + { + DPRINT(("WFC_Context_Initialize(): Missing EGL extension - egl_Private_SignalSyncNOK extension")); + return NULL; + } + + /*the following section of the code could be pushed to adaptation in future*/ + if (type == WFC_CONTEXT_TYPE_ON_SCREEN) + { + OWF_IMAGE_FORMAT imageFormat; + OWF_SCREEN screen; + WFCint width = 0; + WFCint height = 0; + WFCint normalSize = 0; + WFCint flippedSize = 0; + WFCNativeStreamType stream; + + /* Set up stream for sending data to screen */ + + if (!OWF_Screen_GetHeader(screenNum, &screen)) + { + DPRINT(("WFC_Context_Initialize(): Could not retrieve the screen parameters")); + return NULL; + } + + /* Set on-screen pixel format */ + imageFormat.pixelFormat = OWF_SURFACE_PIXEL_FORMAT; + imageFormat.premultiplied = OWF_SURFACE_PREMULTIPLIED; + imageFormat.linear = OWF_SURFACE_LINEAR; + imageFormat.rowPadding = OWF_SURFACE_ROWPADDING; + + width = screen.normal.width; + height = screen.normal.height; + + normalSize = screen.normal.height * screen.normal.stride; + flippedSize = screen.flipped.height * screen.flipped.stride; + + if (flippedSize > normalSize) + { + width = screen.flipped.width; + height = screen.flipped.height; + } + + stream = owfNativeStreamCreateImageStream(width, + height, + &imageFormat, + 1); + + if (stream) + { + WFC_Context_SetTargetStream(context, stream); + + /* At this point the stream's refcount is 2 - we must decrement + * it by one to ensure that the stream is destroyed when the + * context (that "owns" it) is destroyed. + */ + owfNativeStreamRemoveReference(stream); + } + else + { + DPRINT(("WFC_Context_Initialize(): cannot create internal target stream")); + return NULL; + } + } + else + { + WFC_Context_SetTargetStream(context, stream); + } + + nbufs = SCRATCH_BUFFER_COUNT-1; + for (ii = 0; ii < nbufs; ii++) + { + scratch[ii] = OWF_Image_AllocData(context->displayContext, MAX_SOURCE_WIDTH, + MAX_SOURCE_HEIGHT, + OWF_IMAGE_ARGB_INTERNAL); + fail = fail || (scratch[ii] == NULL); + } + + /* + * allocate one-channel buffer for alpha + * obs! this assumes sizeof(OWFsubpixel) is 4. + */ + scratch[nbufs] = OWF_Image_AllocData(context->displayContext, MAX_SOURCE_WIDTH, + MAX_SOURCE_HEIGHT, + OWF_IMAGE_L32); + fail = fail || (scratch[nbufs] == NULL); + + err2 = OWF_MessageQueue_Init(&context->composerQueue); + fail = fail || (err2 != 0); + + if (fail) + { + OWF_MessageQueue_Destroy(&context->composerQueue); + + for (ii = 0; ii < SCRATCH_BUFFER_COUNT; ii++) + { + OWF_Image_FreeData(context->displayContext, &scratch[ii]); + } + return NULL; + } + + for (ii = 0; ii < SCRATCH_BUFFER_COUNT; ii++) + { + context->scratchBuffer[ii] = scratch[ii]; + } + + if (!WFC_Pipeline_CreateState(context) || !WFC_Context_CreateState(context)) + { + DPRINT(("WFC_Context_Initialize(): Could not create pipeline state object")); + return NULL; + } + if ( OWF_Semaphore_Init(&context->compositionSemaphore, 1) + || OWF_Semaphore_Init(&context->commitSemaphore, 1) + || OWF_Mutex_Init(&context->updateFlagMutex) + || OWF_Mutex_Init(&context->sceneMutex) + + ) + { + DPRINT(("WFC_Context_Initialize(): Could not create mutexes and semaphores!")); + return NULL; + } + + attribStatus= WFC_Context_InitializeAttributes(context, type); + + if (attribStatus!=ATTR_ERROR_NONE) + { + return NULL; + } + + + context->scenePool = OWF_Pool_Create(sizeof(WFC_SCENE), + CONTEXT_SCENE_POOL_SIZE); + context->elementPool = OWF_Pool_Create(sizeof(WFC_ELEMENT), + CONTEXT_ELEMENT_POOL_SIZE); + context->nodePool = OWF_Pool_Create(sizeof(OWF_NODE), + CONTEXT_NODE_POOL_SIZE); + if (!( context->scenePool && + context->nodePool && context->elementPool)) + { + /* must call these to remove references to context */ + context->workScene = NULL; + context->committedScene = NULL; + return NULL; + } + + DPRINT((" Creating scenes")); + context->workScene = WFC_Scene_Create(context); + context->committedScene = WFC_Scene_Create(context); + context->snapshotScene = NULL; + + /* snapshotScene is initialized in InvokeCommit */ + + /* context's refcount is now 3 */ + + if (!(context->workScene && context->committedScene && + context->nodePool && context->elementPool)) + { + /* must call these to remove references to context */ + WFC_Scene_Destroy(context->workScene); + WFC_Scene_Destroy(context->committedScene); + context->workScene = NULL; + context->committedScene = NULL; + return NULL; + } + + + context->composerThread = OWF_Thread_Create(WFC_Context_ComposerThread, + context); + if (!(context->composerThread)) + { + /* must call these to remove references to context */ + WFC_Scene_Destroy(context->workScene); + WFC_Scene_Destroy(context->committedScene); + context->workScene = NULL; + context->committedScene = NULL; + return NULL; + } + + return context; +} + +/*--------------------------------------------------------------------------- + * Create new context on device + * + * \param device Device on which the context should be created + * \param type Context type (on- or off-screen) + * + * \return New context object or NULL in case of failure + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFC_CONTEXT* +WFC_Context_Create(WFC_DEVICE* device, + WFCNativeStreamType stream, + WFCContextType type, + WFCint screenNum) +{ + WFC_CONTEXT* context = NULL; + + OWF_ASSERT(device); + context = CREATE(WFC_CONTEXT); + + if (context) + { + if (!WFC_Context_Initialize(context, device, stream, type, screenNum)) + { + DESTROY(context); + } + } + return context; +} + +/*--------------------------------------------------------------------------- + * Setup context rendering target + * + * \param context Context + * \param stream Target stream to use for rendering + *----------------------------------------------------------------------------*/ +OWF_API_CALL void +WFC_Context_SetTargetStream(WFC_CONTEXT* context, + OWFNativeStreamType stream) +{ + OWF_ASSERT(context); + context->stream = stream; + + owfNativeStreamAddReference(stream); + + owfNativeStreamGetHeader(stream, + &context->targetWidth, &context->targetHeight, + NULL, NULL, NULL); +} +/*--------------------------------------------------------------------------- + * Checks if the given stream would be valid as an off-screen context target. + * + * Checks that the format can be rendered TO. + * Also checks that the image size is acceptable (within the scratch buffers). + * This is called before the context is created so is effectively a "static" context method. + * + * \param stream Target stream to use for rendering + ---------------------------------------------------------------------------*/ + +OWF_API_CALL WFCboolean +WFC_Context_IsValidTargetStream(OWFNativeStreamType stream) +{ + OWFint width,height; + OWF_IMAGE_FORMAT format; + owfNativeStreamGetHeader(stream, + &width, &height, + NULL, &format, NULL); + if (width>MAX_SOURCE_WIDTH) + { + return WFC_FALSE; + } + if (height>MAX_SOURCE_HEIGHT) + { + return WFC_FALSE; + } + return (WFCboolean)OWF_Image_IsValidDestinationFormat(&format); +} + +/*--------------------------------------------------------------------------- + * Checks that the image size is acceptable (within the scratch buffers). + * This is called before the source is created. + * + * \param stream source stream to use for rendering. + ---------------------------------------------------------------------------*/ + +OWF_API_CALL WFCboolean +WFC_Context_IsValidSourceStream(OWFNativeStreamType stream) +{ + OWFint width,height; + owfNativeStreamGetHeader(stream, + &width, &height, + NULL, NULL, NULL); + if ((width+2) * (height+2) > MAX_SOURCE_WIDTH * MAX_SOURCE_HEIGHT) + { + return WFC_FALSE; + } + return WFC_TRUE; +} + +/*--------------------------------------------------------------------------- + * Find element from current scene + * + * \param context Context object + * \param element Element to find + * + * \return Element object or NULL if element hasn't been inserted + * into current scene. + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFC_ELEMENT* +WFC_Context_FindElement(WFC_CONTEXT* context, + WFCElement element) +{ + OWF_ASSERT(context); + return WFC_Scene_FindElement(context->workScene, element); +} + +/*--------------------------------------------------------------------------- + * Commit context scene graph changes + * + * \param context Context to commit + *----------------------------------------------------------------------------*/ +static void +WFC_Context_DoCommit(WFC_CONTEXT* context) +{ + OWF_ASSERT(context); + DPRINT(("WFC_Context_DoCommit(context = %p)", context)); + + OWF_ASSERT(context->snapshotScene); + + + DPRINT(("COMMIT: Committing attribute list changes")); + + DPRINT(("COMMIT: Acquiring mutex")); + OWF_Mutex_Lock(&context->sceneMutex); + + /* comitting scene attribute changes */ + DPRINT(("COMMIT: Committing scene attribute changes")); + OWF_AttributeList_Commit(&context->attributes, + WFC_CONTEXT_TYPE, + WFC_CONTEXT_BG_COLOR,COMMITTED_ATTR_VALUE_INDEX); + + + /* resolve sources and masks */ + DPRINT(("COMMIT: Committing scene changes")); + WFC_Scene_Commit(context->snapshotScene); + DPRINT(("COMMIT: Destroying old committed scene")); + WFC_Scene_Destroy(context->committedScene); + DPRINT(("COMMIT: Setting new snapshot scene as committed one.")); + context->committedScene = context->snapshotScene; + context->snapshotScene = NULL; + + // reset the visibility flags + owfSymDeviceResetVisibilityState(context); + + DPRINT(("COMMIT: Unlocking mutex")); + OWF_Mutex_Unlock(&context->sceneMutex); + + DPRINT(("COMMIT: Signaling commit semaphore")); + /* signal we're ready */ + OWF_Semaphore_Post(&context->commitSemaphore); +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +static void +WFC_Context_LockTargetForWriting(WFC_CONTEXT* context) +{ + OWF_ASSERT(context); + + DPRINT(("WFC_Context_LockTargetForWriting")); + + context->state.targetBuffer = + owfNativeStreamAcquireWriteBuffer(context->stream); + context->state.targetPixels = + owfNativeStreamGetBufferPtr(context->stream, + context->state.targetBuffer); + + if ((WFC_ROTATION_0 == context->rotation || WFC_ROTATION_180 == context->rotation) || + !OWF_Screen_Rotation_Supported(context->screenNumber)) + { + /* final target, in target format */ + context->state.targetImage =context->state.unrotatedTargetImage; + } + else + { + /* final target, in target format */ + /* fExt stride/padding value is the rotated value */ + context->state.targetImage = context->state.rotatedTargetImage; + } + OWF_Image_SetPixelBuffer(context->state.targetImage,context->state.targetPixels); + + if (context->state.targetImage==NULL) + { + OWF_ASSERT(WFC_FALSE); + } + + /* take context rotation into account. */ + if (WFC_ROTATION_0 == context->rotation || + WFC_ROTATION_180 == context->rotation) + { + context->state.internalTargetImage = context->state.unrotatedInternalTargetImage; + } + else + { + context->state.internalTargetImage = context->state.rotatedInternalTargetImage; + } + + if (context->state.internalTargetImage==NULL) + { + OWF_ASSERT(WFC_FALSE); + } +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +static void +WFC_Context_UnlockTarget(WFC_CONTEXT* context) +{ + OWFNativeStreamBuffer frontBuffer = OWF_INVALID_HANDLE; + void* pixelDataPtr = NULL; + OWF_ROTATION rotation = OWF_ROTATION_0; + + OWF_ASSERT(context); + DPRINT(("WFC_Context_UnlockTarget")); + DPRINT((" Unlocking target stream=%d, buffer=%d", + context->stream, context->state.targetBuffer)); + + owfNativeStreamReleaseWriteBuffer(context->stream, + context->state.targetBuffer, + EGL_NO_DISPLAY, + NULL); + + + /* Refactor the code that follows so that it is triggered by the above releasewrite */ + + /* Acquire target stream front buffer and blit to SDL screen */ + frontBuffer = owfNativeStreamAcquireReadBuffer(context->stream); + DPRINT((" Locking target stream=%d, buffer=%d", + context->stream, frontBuffer)); + + pixelDataPtr = owfNativeStreamGetBufferPtr(context->stream, frontBuffer); + + switch (context->rotation) + { + case WFC_ROTATION_0: + { + rotation = OWF_ROTATION_0; + break; + } + case WFC_ROTATION_90: + { + rotation = OWF_ROTATION_90; + break; + } + case WFC_ROTATION_180: + { + rotation = OWF_ROTATION_180; + break; + } + case WFC_ROTATION_270: + { + rotation = OWF_ROTATION_270; + break; + } + default: + { + OWF_ASSERT(0); + } + } + + OWF_Screen_Blit(context->screenNumber, pixelDataPtr, rotation); + + owfNativeStreamReleaseReadBuffer(context->stream, frontBuffer); + DPRINT((" Releasing target stream=%d, buffer=%d", + context->stream, frontBuffer)); + +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +static void +WFC_Context_PrepareComposition(WFC_CONTEXT* context) +{ + OWFsubpixel r, g, b, a; + + OWF_ASSERT(context); + + /* the first thing to do is to lock target stream and fetch + write buffer to it. fetching blocks until one is available, + but since only one stream can be target to only one context + at the time, no stalls should occur */ + WFC_Context_LockTargetForWriting(context); + + /* prepare for composition by "clearing the table" with + background color. */ + + r = (OWFsubpixel) OWF_RED_MAX_VALUE * ((context->backgroundColor >> 24) & + 0xFF) / OWF_BYTE_MAX_VALUE; + g = (OWFsubpixel) OWF_GREEN_MAX_VALUE * ((context->backgroundColor >> 16) & + 0xFF) / OWF_BYTE_MAX_VALUE; + b = (OWFsubpixel) OWF_BLUE_MAX_VALUE * ((context->backgroundColor >> 8) & + 0xFF) / OWF_BYTE_MAX_VALUE; + a = (OWFsubpixel) OWF_ALPHA_MAX_VALUE * (context->backgroundColor & 0xFF) / + OWF_BYTE_MAX_VALUE; + + r = r * a / OWF_ALPHA_MAX_VALUE; + g = g * a / OWF_ALPHA_MAX_VALUE; + b = b * a / OWF_ALPHA_MAX_VALUE; + + OWF_Image_Clear(context->state.internalTargetImage, r, g, b, a); + + WFC_Scene_LockSourcesAndMasks(context->committedScene); +} + + + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +static void +WFC_Context_FinishComposition(WFC_CONTEXT* context) +{ + OWF_ROTATION rotation = OWF_ROTATION_0; + OWFint screenNumber; + OWFboolean screenRotation; + + OWF_ASSERT(context); + + screenNumber = context->screenNumber; + screenRotation = OWF_Screen_Rotation_Supported(screenNumber); + /* re-use scratch buffer 1 for context rotation */ + if (WFC_ROTATION_0 == context->rotation || screenRotation) + { + + if (screenRotation) + { + if (WFC_ROTATION_90 == context->rotation || WFC_ROTATION_270 == context->rotation) + { + owfSetStreamFlipState(context->stream, OWF_TRUE); + } + else + { + owfSetStreamFlipState(context->stream, OWF_FALSE); + } + } + OWF_Image_DestinationFormatConversion(context->state.targetImage, context->state.internalTargetImage); + } + else + { + switch (context->rotation) + { + case WFC_ROTATION_0: + { + rotation = OWF_ROTATION_0; + break; + } + case WFC_ROTATION_90: + { + rotation = OWF_ROTATION_90; + break; + } + case WFC_ROTATION_180: + { + rotation = OWF_ROTATION_180; + break; + } + case WFC_ROTATION_270: + { + rotation = OWF_ROTATION_270; + break; + } + default: + { + OWF_ASSERT(0); + } + } + + /* rotate */ + OWF_Image_Rotate(context->state.rotatedTargetImage, + context->state.internalTargetImage, + rotation); + + /* Note: support of different target formats can be put here */ + + OWF_Image_DestinationFormatConversion(context->state.targetImage, context->state.rotatedTargetImage); + } + WFC_Context_UnlockTarget(context); + WFC_Scene_UnlockSourcesAndMasks(context->committedScene); +} + +/*!--------------------------------------------------------------------------- + * \brief Actual composition routine. + * Mainly just calls other functions that executes different stages of + * the composition pipeline. + * \param context Context to compose. + *----------------------------------------------------------------------------*/ +static void +WFC_Context_DoCompose(WFC_CONTEXT* context) +{ + WFC_SCENE* scene = NULL; + OWF_NODE* node = NULL; + + OWF_ASSERT(context); + + OWF_Mutex_Lock(&context->updateFlagMutex); + + OWF_DisplayContext_IncrementSerialNumber(context->displayContext); + + OWF_DisplayContext_SetCompositionOngoing(context->displayContext, WFC_TRUE); + context->sourceUpdateCount = 0; + OWF_Mutex_Unlock(&context->updateFlagMutex); + + WFC_Context_PrepareComposition(context); + + DPRINT(("WFC_Context_Compose")); + /* Composition always uses the committed version + * of the scene. + */ + + OWF_Mutex_Lock(&context->sceneMutex); + + scene = context->committedScene; + OWF_ASSERT(scene); + + for (node = scene->elements; NULL != node; node = node->next) + { + + WFC_ELEMENT* element = NULL; + WFC_ELEMENT_STATE* elementState = NULL; + element = ELEMENT(node->data); + + if (element->skipCompose) + { + /* this element is somehow degraded, its source is missing or + * something else; skip to next element */ + DPRINT((" *** Skipping element %d", element->handle)); + continue; + } + + DPRINT((" Composing element %d", element->handle)); + + /* BeginComposition may fail e.g. if the element's destination + * rectangle is something bizarre, i.e. causes overflows or + * something. + */ + if ((elementState=WFC_Pipeline_BeginComposition(context, element))!=NULL) + { + owfSymElementNotifications(context, element); + + WFC_Pipeline_ExecuteSourceConversionStage(context, elementState); + WFC_Pipeline_ExecuteCropStage(context, elementState); + WFC_Pipeline_ExecuteFlipStage(context, elementState); + WFC_Pipeline_ExecuteRotationStage(context, elementState); + WFC_Pipeline_ExecuteScalingStage(context, elementState); + WFC_Pipeline_ExecuteBlendingStage(context, elementState); + + WFC_Pipeline_EndComposition(context, element,elementState); + } + } + + WFC_Context_FinishComposition(context); + + owfSymProcessAllNotifications(context); + OWF_Mutex_Unlock(&context->sceneMutex); + + OWF_Semaphore_Post(&context->compositionSemaphore); +} + +/*--------------------------------------------------------------------------- + * Activate/deactivate auto-composition on context + * + * \param context Context + * \param act Auto-composition enable/disable + *----------------------------------------------------------------------------*/ +OWF_API_CALL void +WFC_Context_Activate(WFC_CONTEXT* context, + WFCboolean act) +{ + OWF_ASSERT(context); + + DPRINT(("WFC_Context_Activate: %s", (act) ? "activate" : "deactivate")); + + if (act && !WFC_Context_Active(context)) + { + DPRINT(("WFC_Context_Activate: WFC_CONTEXT_STATE_PASSIVE: activating")); + context->activationState = WFC_CONTEXT_STATE_ACTIVATING; + + /* moved from composer loop - updates must be allowed + * immediately after activation + */ + WFC_Device_EnableContentNotifications(context->device, + context, + WFC_TRUE); + + OWF_Message_Send(&context->composerQueue, + WFC_MESSAGE_ACTIVATE, + 0); + } + else if (!act && WFC_Context_Active(context)) + { + DPRINT(("WFC_Context_Activate: WFC_CONTEXT_STATE_ACTIVE: deactivating")); + context->activationState = WFC_CONTEXT_STATE_DEACTIVATING; + OWF_Message_Send(&context->composerQueue, + WFC_MESSAGE_DEACTIVATE, + 0); + } +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFCboolean +WFC_Context_InvokeComposition(WFC_DEVICE* device, + WFC_CONTEXT* context, + WFCboolean wait) +{ + WFCint status = 0; + + OWF_ASSERT(context); + OWF_ASSERT(device); + + device = device; /* suppress the compiler warning */ + + status = OWF_Semaphore_TryWait(&context->compositionSemaphore); + if (status) + { + if (!wait) + { + /* busy; processing last request */ + return WFC_FALSE; + } + /* wait previous frame composition to finish */ + OWF_Semaphore_Wait(&context->compositionSemaphore); + } + + /* compositionSemaphore is posted/signaled in WFC_Context_Compose() + after frame has been successfully composed */ + OWF_Message_Send(&context->composerQueue, WFC_MESSAGE_COMPOSE, 0); + + return WFC_TRUE; +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFCErrorCode +WFC_Context_InvokeCommit(WFC_DEVICE* device, + WFC_CONTEXT* context, + WFCboolean wait) +{ + WFCint status = 0; + + OWF_ASSERT(context); + OWF_ASSERT(device); + + device = device; /* suppress the compiler warning */ + + /* first check if there're inconsistensies in the scene */ + if (WFC_Scene_HasConflicts(context->workScene)) + { + DPRINT(("WFC_Context_InvokeCommit: scene has inconsistensies")); + return WFC_ERROR_INCONSISTENCY; + } + + /* then commit - always asynchronously */ + status = OWF_Semaphore_TryWait(&context->commitSemaphore); + DPRINT(("COMMIT: Commit semaphore status = %d", status)); + if (status) + { + if (!wait) + { + DPRINT(("COMMIT: Busy; exiting.")); + /* busy; processing last commit */ + return WFC_ERROR_BUSY; + } + + DPRINT(("COMMIT: Waiting for previous commit to finish.")); + /* wait previous commit to finish */ + OWF_Semaphore_Wait(&context->commitSemaphore); + } + + /* comitting scene attribute changes */ + DPRINT(("COMMIT: Cloning scene attribute changes")); + OWF_AttributeList_Commit(&context->attributes, + WFC_CONTEXT_TYPE, + WFC_CONTEXT_BG_COLOR,SNAPSHOT_ATTR_VALUE_INDEX); + + DPRINT(("COMMIT: Cloning scene")); + /* take snapshot of the current working copy - it will + * be the new committed scene */ + context->snapshotScene = WFC_Scene_Clone(context->workScene); + + DPRINT(("COMMIT: Sending commit request")); + /* invoke async commit */ + OWF_Message_Send(&context->composerQueue, WFC_MESSAGE_COMMIT, 0); + return WFC_ERROR_NONE; +} + +/*--------------------------------------------------------------------------- + * \param context + * \param dpy + * \param sync + *----------------------------------------------------------------------------*/ +OWF_API_CALL void +WFC_Context_InsertFence(WFC_CONTEXT* context, + WFCEGLDisplay dpy, + WFCEGLSync sync) +{ + OWF_ASSERT(context); + OWF_ASSERT(sync); + + DPRINT(("WFC_Context_InsertFence: Sending fence sync: 0x%08x", sync)); + + OWF_Message_Send(&context->composerQueue, WFC_MESSAGE_FENCE_1_DISPLAY, (void*) dpy); + OWF_Message_Send(&context->composerQueue, WFC_MESSAGE_FENCE_2_SYNCOBJECT, sync); +} + +/*--------------------------------------------------------------------------- + * Insert element into context's scene + * + * \param context + * \param element + * \param subordinate + * + * \return WFCErrorCode + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFCErrorCode +WFC_Context_InsertElement(WFC_CONTEXT* context, + WFCElement element, + WFCElement subordinate) +{ + WFC_ELEMENT* object = NULL; + WFCErrorCode result = WFC_ERROR_BAD_HANDLE; + + OWF_ASSERT(context); + + object = WFC_Device_FindElement(context->device, element); + + if (NULL != object && CONTEXT(object->context) == context) + { + /* set the sharing flag as the element will be + * shared between the device and working copy scene. + * this is to tell the scene that it must not destroy + * this element. + */ + object->shared = WFC_TRUE; + result = WFC_Scene_InsertElement(context->workScene, + object, + subordinate); + + context->lowestElement = WFC_Scene_LowestElement(context->workScene); + } + return result; +} + +/*--------------------------------------------------------------------------- + * Remove element from context's scene + * + * \param context + * \param element + * + * \return WFCErrorCode + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFCErrorCode +WFC_Context_RemoveElement(WFC_CONTEXT* context, + WFCElement element) +{ + WFCErrorCode err = WFC_ERROR_BAD_HANDLE; + WFC_ELEMENT* elemento = NULL; + + OWF_ASSERT(context); + + elemento = WFC_Context_FindElement(context, element); + + if (elemento) + { + WFC_Scene_RemoveElement(context->workScene, element); + /* the element is no longer shared, as it only resides + * in device from this point on + */ + elemento->shared = WFC_FALSE; + context->lowestElement = WFC_Scene_LowestElement(context->workScene); + + err = WFC_ERROR_NONE; + } + + return err; +} + +/*! + * \brief IncreaseClientElementCount + * + * \param context + * \return positive increased current element count; negative or zero indicating the count can't be increased + */ +OWF_API_CALL WFCint +WFC_Context_IncreaseClientElementCount(WFC_CONTEXT* context) + { + /* This implementation simply caps the number of elements allocated to the client + * to 1/3 of the total elements. + * A cleverer strategy would allow the client to create more elements + * so long as the number added to the scene *2 did not exceed the spare pool size. + * These failure points are also a good place to consider increasing the pool size + */ + if (context->clientElementCount>=MAX_ELEMENTS) + { + return -context->clientElementCount; + } + else + { + return ++context->clientElementCount; + } + } + +/*! + * \brief DecreaseClientElementCount + * + * \param context + * \return positive or zero decreased current element count; negative indicating the count can't be decreased - p0robably already zero + */ +OWF_API_CALL WFCint +WFC_Context_DecreaseClientElementCount(WFC_CONTEXT* context) + { + /* note that a negative return indicates that decrements are not matched with increments */ + return --context->clientElementCount; + } + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFCErrorCode +WFC_Context_GetElementAbove(WFC_CONTEXT* context, + WFCElement element, + WFCElement* result) +{ + WFC_ELEMENT* object = NULL; + WFCErrorCode error = WFC_ERROR_ILLEGAL_ARGUMENT; + + OWF_ASSERT(context); + OWF_ASSERT(result); + + object = WFC_Context_FindElement(context, element); + + if (object) + { + WFCElement temp; + + temp = WFC_Scene_GetNeighbourElement(context->workScene, element, 1); + *result = temp; + error = WFC_ERROR_NONE; + } + return error; +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFCErrorCode +WFC_Context_GetElementBelow(WFC_CONTEXT* context, + WFCElement element, + WFCElement* result) +{ + WFC_ELEMENT* object = NULL; + WFCErrorCode error = WFC_ERROR_ILLEGAL_ARGUMENT; + + OWF_ASSERT(context); + OWF_ASSERT(result); + + object = WFC_Context_FindElement(context, element); + if (object) + { + WFCElement temp; + + temp = WFC_Scene_GetNeighbourElement(context->workScene, element, -1); + *result = temp; + error = WFC_ERROR_NONE; + } + return error; +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFCErrorCode +WFC_Context_GetAttribi(WFC_CONTEXT* context, + WFCContextAttrib attrib, + WFCint* value) +{ + WFCint temp = 0; + OWF_ATTRIBUTE_LIST_STATUS err; + WFCErrorCode result = WFC_ERROR_NONE; + + OWF_ASSERT(context); + OWF_ASSERT(value); + + temp = OWF_Attribute_GetValuei(&context->attributes, attrib); + err = OWF_AttributeList_GetError(&context->attributes); + + if (err != ATTR_ERROR_NONE) + { + result = WFC_ERROR_BAD_ATTRIBUTE; + } + else + { + *value = temp; + } + return result; +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFCErrorCode +WFC_Context_SetAttribi(WFC_CONTEXT* context, + WFCContextAttrib attrib, + WFCint value) +{ + WFCErrorCode result = WFC_ERROR_NONE; + + OWF_ASSERT(context); + + /* check value */ + switch (attrib) + { + case WFC_CONTEXT_BG_COLOR: + { + OWFint alpha; + + /* + * Color format is RGBA NOT RGBA. + */ + alpha = value & 0xFF; + + if (WFC_CONTEXT_TYPE_ON_SCREEN == context->type) + { + /* the only allowed value for on-screen context + * background alpha is 255 */ + if (alpha != 255) + { + result = WFC_ERROR_ILLEGAL_ARGUMENT; + } + } + break; + } + + case WFC_CONTEXT_ROTATION: + { + if (!(WFC_ROTATION_0 == value || + WFC_ROTATION_90 == value || + WFC_ROTATION_180 == value || + WFC_ROTATION_270 == value)) + { + result = WFC_ERROR_ILLEGAL_ARGUMENT; + } + break; + } + + case WFC_CONTEXT_TYPE: + case WFC_CONTEXT_TARGET_HEIGHT: + case WFC_CONTEXT_TARGET_WIDTH: + case WFC_CONTEXT_LOWEST_ELEMENT: + { + result = WFC_ERROR_BAD_ATTRIBUTE; + break; + } + + case WFC_CONTEXT_FORCE_32BIT: + default: + { + result = WFC_ERROR_BAD_ATTRIBUTE; + break; + } + } + + if (WFC_ERROR_NONE == result) + { + OWF_ATTRIBUTE_LIST_STATUS error; + + /* try changing the value */ + OWF_Attribute_SetValuei(&context->attributes, attrib, value); + error = OWF_AttributeList_GetError(&context->attributes); + + /* transform errors */ + switch (error) { + case ATTR_ERROR_ACCESS_DENIED: + case ATTR_ERROR_INVALID_ATTRIBUTE: + { + result = WFC_ERROR_BAD_ATTRIBUTE; + break; + } + default: + { + break; + } + } + } + + return result; +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFCErrorCode +WFC_Context_GetAttribfv(WFC_CONTEXT* context, + WFCContextAttrib attrib, + WFCint count, + WFCfloat* values) +{ + WFCErrorCode result = WFC_ERROR_NONE; + + OWF_ASSERT(context); + OWF_ASSERT(values); + + switch (attrib) + { + case WFC_CONTEXT_BG_COLOR: + { + if (4 != count) + { + result = WFC_ERROR_ILLEGAL_ARGUMENT; + } + else + { + OWFuint32 color; + OWF_ATTRIBUTE_LIST_STATUS err; + + color = OWF_Attribute_GetValuei(&context->attributes, attrib); + err = OWF_AttributeList_GetError(&context->attributes); + + if (err != ATTR_ERROR_NONE) + { + result = WFC_ERROR_BAD_ATTRIBUTE; + break; + } + + /* extract color channels and convert to float */ + values[0] = (WFCfloat) (color >> 24) / + (WFCfloat) OWF_BYTE_MAX_VALUE; + values[1] = (WFCfloat) ((color >> 16) & 0xFF) / + (WFCfloat) OWF_BYTE_MAX_VALUE; + values[2] = (WFCfloat) ((color >> 8) & 0xFF) / + (WFCfloat) OWF_BYTE_MAX_VALUE; + values[3] = (WFCfloat) (color & 0xFF) / + (WFCfloat) OWF_BYTE_MAX_VALUE; + } + break; + } + + default: + { + result = WFC_ERROR_BAD_ATTRIBUTE; + break; + } + } + + return result; +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFCErrorCode +WFC_Context_SetAttribfv(WFC_CONTEXT* context, + WFCContextAttrib attrib, + WFCint count, + const WFCfloat* values) +{ + WFCErrorCode result = WFC_ERROR_NONE; + + OWF_ASSERT(context); + OWF_ASSERT(values); + + switch (attrib) + { + case WFC_CONTEXT_BG_COLOR: + { + if (4 != count) + { + result = WFC_ERROR_ILLEGAL_ARGUMENT; + } + else + { + OWFuint32 color; + + /* Every color component value must fall within range [0, 1] */ + if (INRANGE(values[0], 0.0f, 1.0f) && + INRANGE(values[1], 0.0f, 1.0f) && + INRANGE(values[2], 0.0f, 1.0f) && + INRANGE(values[3], 0.0f, 1.0f)) + { + color = (((OWFuint32) floor(values[0] * 255)) << 24) | + (((OWFuint32) floor(values[1] * 255)) << 16) | + (((OWFuint32) floor(values[2] * 255)) << 8) | + ((OWFuint32) floor(values[3] * 255)); + + /* delegate to integer accessor - it'll check the + * the rest of the value and update it eventually */ + result = WFC_Context_SetAttribi(context, attrib, color); + } + else + { + result = WFC_ERROR_ILLEGAL_ARGUMENT; + } + } + break; + } + + default: + { + result = WFC_ERROR_BAD_ATTRIBUTE; + break; + } + } + + return result; +} + + +static void +WFC_Context_AutoComposer(WFC_CONTEXT* context) +{ + OWF_Mutex_Lock(&context->updateFlagMutex); + if (context->sourceUpdateCount > 0) + { + DPRINT(("WFC_Context_ComposerThread: %d sources were updated, " + "invoking composition\n", + context->sourceUpdateCount)); + + /* reset update counter */ + + OWF_Mutex_Unlock(&context->updateFlagMutex); + WFC_Context_DoCompose(context); + } + else + { + OWF_Mutex_Unlock(&context->updateFlagMutex); + } +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +static void* +WFC_Context_ComposerThread(void* data) +{ + WFC_CONTEXT* context = (WFC_CONTEXT*) data; + OWF_MESSAGE msg; + + + OWF_ASSERT(context); + DPRINT(("WFC_Context_ComposerThread starting")); + + memset(&msg, 0, sizeof(OWF_MESSAGE)); + + while (context->device && msg.id != WFC_MESSAGE_QUIT) + { + OWFint err = -1; + + if (WFC_CONTEXT_STATE_ACTIVE == context->activationState) + { + err = OWF_Message_Wait(&context->composerQueue, + &msg, + AUTO_COMPOSE_DELAY); + + WFC_Context_AutoComposer(context); + } + else + { + DPRINT((" ComposerThread waiting for message")); + err = OWF_Message_Wait(&context->composerQueue, &msg, WAIT_FOREVER); + } + + if (0 == err) + { + switch (msg.id) + { + case WFC_MESSAGE_ACTIVATE: + { + DPRINT(("****** ENABLING AUTO-COMPOSITION ******")); + context->activationState = WFC_CONTEXT_STATE_ACTIVE; + break; + } + + case WFC_MESSAGE_DEACTIVATE: + { + /* cancel possible countdown so that update won't occur + * after deactivation */ + DPRINT(("****** DISABLING AUTO-COMPOSITION ******")); + WFC_Device_EnableContentNotifications(context->device, + context, + WFC_FALSE); + context->activationState = WFC_CONTEXT_STATE_PASSIVE; + break; + } + + case WFC_MESSAGE_COMMIT: + { + DPRINT(("****** COMMITTING SCENE CHANGES ******")); + + DPRINT(("COMMIT: Invoking DoCommit")); + WFC_Context_DoCommit(context); + + if (!WFC_Context_Active(context)) + { + DPRINT(("COMMIT: Context is inactive, composition " + "not needed.", context->handle)); + break; + } + else + { + /* context is active; compose immediately after + * commit has completed */ + + DPRINT(("COMMIT: Invoking composition after commit")); + } + /* FLOW THROUGH */ + } + + case WFC_MESSAGE_COMPOSE: + { + DPRINT(("****** COMPOSING SCENE ******")); + + WFC_Context_DoCompose(context); + + break; + } + + case WFC_MESSAGE_FENCE_1_DISPLAY: + { + DPRINT(("****** STORING EGLDISPLAY (%p) ******", msg.data)); + + context->nextSyncObjectDisplay = (WFCEGLDisplay)msg.data; + break; + } + + case WFC_MESSAGE_FENCE_2_SYNCOBJECT: + { + DPRINT(("****** BREAKING FENCE (%p) ******", msg.data)); + OWF_ASSERT(context->eglPrivateSignalSync); + + context->eglPrivateSignalSync(context->nextSyncObjectDisplay, + (WFCEGLSync) msg.data, + EGL_SIGNALED_KHR); + break; + } + } + } + } + + /* Release any use of EGL by this thread. */ + eglReleaseThread(); + + DPRINT(("WFC_Context_ComposerThread terminating")); + OWF_Thread_Exit(NULL); + return NULL; +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ + +OWF_API_CALL void +WFC_Context_SourceStreamUpdated(OWFNativeStreamType stream, + OWFint event, + void* data, + void* returnParam) +{ + (void)returnParam; + OWF_ASSERT(data); + + DPRINT(("WFC_Context_SourceStreamUpdated(%p, %x, %p)", + stream, event, data)); + stream = stream; /* suppress compiler warning */ + + switch (event) + { + case OWF_OBSERVER_RETURN_DEFAULT_EVENT: + if (returnParam) + { + OWF_DEFAULT_EVENT_PARAM* parameter = (OWF_DEFAULT_EVENT_PARAM*) returnParam; + if ((parameter->length) == sizeof(OWF_DEFAULT_EVENT_PARAM)) + { + parameter->event = OWF_STREAM_UPDATED; + } + } + break; + + case OWF_STREAM_UPDATED: + { + WFC_CONTEXT* context = NULL; + context = CONTEXT(data); + OWF_ASSERT(context); + OWF_Mutex_Lock(&context->updateFlagMutex); + + if (WFC_Context_Active(context)) + { + ++context->sourceUpdateCount; + } + OWF_Mutex_Unlock(&context->updateFlagMutex); + } + break; + default: + break; + } +} + +/*--------------------------------------------------------------------------- + * + *----------------------------------------------------------------------------*/ +OWF_API_CALL WFCboolean +WFC_Context_Active(WFC_CONTEXT* context) +{ + OWF_ASSERT(context); + + return (WFC_CONTEXT_STATE_ACTIVE == context->activationState || + WFC_CONTEXT_STATE_ACTIVATING == context->activationState) ? WFC_TRUE : WFC_FALSE; +} + +#ifdef __cplusplus +} +#endif +