graphicscomposition/openwfcompositionengine/composition/src/wfccontext.c
changeset 0 5d03bc08d59c
child 36 01a6848ebfd7
child 143 3db46cb3f779
child 163 bbf46f59e123
--- /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 <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <WF/wfc.h>
+#include <EGL/egl.h>
+
+#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
+