os/graphics/graphicscomposition/openwfcompositionengine/adaptation/src/Platform/Graphics/owfnativestream.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /* Copyright (c) 2009 The Khronos Group Inc.
     2  * Portions copyright (c) 2009-2010  Nokia Corporation and/or its subsidiary(-ies)
     3  *
     4  * Permission is hereby granted, free of charge, to any person obtaining a
     5  * copy of this software and/or associated documentation files (the
     6  * "Materials"), to deal in the Materials without restriction, including
     7  * without limitation the rights to use, copy, modify, merge, publish,
     8  * distribute, sublicense, and/or sell copies of the Materials, and to
     9  * permit persons to whom the Materials are furnished to do so, subject to
    10  * the following conditions:
    11  *
    12  * The above copyright notice and this permission notice shall be included
    13  * in all copies or substantial portions of the Materials.
    14  *
    15  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    21  * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
    22  */
    23 
    24 /*!
    25  * Ring buffer based Image Stream implementation for Linux.
    26  */
    27 
    28 
    29 
    30 #ifdef __cplusplus
    31 extern "C" {
    32 #endif
    33 
    34 #define OWF_NATIVESTREAM_HANDLE 0xAB
    35 
    36 #include <stdlib.h>
    37 #include <string.h>
    38 
    39 #include "owfnativestream.h"
    40 #include "owfscreen.h"
    41 #include "owfmemory.h"
    42 #include "owfdebug.h"
    43 #include "owftypes.h"
    44 #include "owfmutex.h"
    45 #include "owfhstore.h"
    46 
    47 /*needed for owfNativeStreamFromWFC function */
    48 #include "WF/wfcplatform.h"
    49 
    50 /* macro for fetching stream object by handle */
    51 #define GET_STREAM(ns, s)       ns = owfNativeStreamGet(s)
    52 
    53 /* stream null checks */
    54 #define CHECK_STREAM(v)     if (NULL == ns) { return v;}
    55 #define CHECK_STREAM_NR()   if (NULL == ns) { return; }
    56 
    57 #define BUFFER_HANDLE_BASE  0x100
    58 #define STREAM_HANDLE_BASE  10000
    59 #define STREAM_HASHTABLE_SIZE   0x100
    60 
    61 /* buffer handle sanity checks */
    62 #define CHECK_BUFFER_NR(x)  if ((x) < BUFFER_HANDLE_BASE || \
    63                                 (x) >= BUFFER_HANDLE_BASE + ns->bufferCount) \
    64                             { \
    65                                 return; \
    66                             }
    67 
    68 #define CHECK_BUFFER(x,v)   if ((x) < BUFFER_HANDLE_BASE || \
    69                                 (x) >= BUFFER_HANDLE_BASE + ns->bufferCount) \
    70                             { \
    71                             return v; \
    72                             }
    73 
    74 #define BUFFER(x)           ns->bufferList[(x)-BUFFER_HANDLE_BASE]
    75 
    76 #define INDEX_TO_HANDLE(x)  ((OWFNativeStreamBuffer) ((x)+BUFFER_HANDLE_BASE))
    77 #define HANDLE_TO_INDEX(x)  ((int) ((x)-BUFFER_HANDLE_BASE))
    78 
    79 typedef struct {
    80     EGLDisplay     dpy;
    81     EGLSyncKHR*    sync;
    82 } OWF_SYNC_DESC;
    83 
    84 
    85 /*!
    86  * Structure for image stream.
    87  */
    88 typedef struct {
    89     OWFNativeStreamType     handle;     /* stream handle */
    90     void**                  bufferList;
    91     OWFint*                 bufferRefs;
    92     OWFint                  bufferCount;
    93     OWFint                  lockCount;
    94     OWFint                  screenNumber;
    95     OWFint                  width,      /* frame width (pixels) */
    96                             height,     /* frame height (pixels) */
    97                             stride;     /* size of single row (bytes) */
    98     OWF_IMAGE_FORMAT        colorFormat;
    99     OWFint                  referenceCount;
   100     OWF_MUTEX               mutex;
   101     OWF_SEMAPHORE           writer;
   102     OWFint                  idxFront;
   103     OWFint                  idxNextFree;
   104     OWF_NODE*               observers;
   105     OWFboolean              sendNotifications;
   106     OWFboolean              protected;  /* protection flag to prevent the
   107                                            user from destroying the stream
   108                                            (for onscreen-context use) */
   109 
   110     OWF_SYNC_DESC*          bufferSyncs; /* sync object to be signalled when
   111                                             buffer is 'consumed' */
   112 } OWF_NATIVE_STREAM;
   113 
   114 
   115 static const OWF_IMAGE_FORMAT   owfOnScreenColorFormat =
   116                                 {
   117                                     OWF_IMAGE_ARGB8888,
   118                                     OWF_FALSE,
   119                                     OWF_TRUE,
   120                                     4
   121                                 };
   122 
   123 /*============================================================================
   124  * PRIVATE PARTS
   125  *============================================================================*/
   126 
   127 /*!---------------------------------------------------------------------------
   128  * Internal.
   129  *----------------------------------------------------------------------------*/
   130 /*
   131 
   132 */
   133 /*!---------------------------------------------------------------------------
   134  *  Add stream to internal stream dictionary
   135  *
   136  *  \param handle           Stream handle
   137  *  \param stream           Stream object associated with the handle
   138  *
   139  *  \return Boolean value indicating whether the addition was succesful
   140  *----------------------------------------------------------------------------*/
   141 static OWFHandle
   142 owfNativeStreamAddStream(OWF_NATIVE_STREAM* stream)
   143 {
   144     OWFHandle handle = OWF_INVALID_HANDLE;
   145 
   146     handle = OWF_HStore_HandleCreate(OWF_NATIVESTREAM_HANDLE, stream);
   147 
   148     return handle;
   149 }
   150 
   151 /*----------------------------------------------------------------------------
   152  *  Returns the stream object associated to given handle
   153  *
   154  *  \param handle           Stream handle
   155  *
   156  *  \return Stream object or NULL if the handle is invalid
   157  *----------------------------------------------------------------------------*/
   158 static OWF_NATIVE_STREAM*
   159 owfNativeStreamGet(OWFNativeStreamType handle)
   160 {
   161     return (OWF_NATIVE_STREAM*) OWF_HStore_GetObj(handle, OWF_NATIVESTREAM_HANDLE);
   162 }
   163 
   164 /*----------------------------------------------------------------------------
   165  *  Remove stream from internal stream dictionary
   166  *
   167  *  \param handle           Stream handle
   168  *
   169  *  \return Boolean value indicating success of the deletion
   170  *----------------------------------------------------------------------------*/
   171 static OWFboolean
   172 owfNativeStreamRemove(OWFNativeStreamType handle)
   173 {
   174     OWF_HStore_HandleDelete(handle);
   175     return OWF_TRUE;
   176 }
   177 
   178 /*!---------------------------------------------------------------------------
   179  *  Notify stream's observers about an event
   180  *
   181  *  \param stream           Stream
   182  *  \param event            Event to notify about
   183  *----------------------------------------------------------------------------*/
   184 static void owfNativeStreamNotifyObservers(OWFNativeStreamType stream,
   185                                            OWFNativeStreamEvent event)
   186 {
   187     OWF_NODE*               iter = NULL;
   188 
   189     OWF_NATIVE_STREAM* ns;
   190 
   191     DPRINT(("owfNativeStreamNotifyObservers(%p, %x)",
   192              stream, event));
   193 
   194     GET_STREAM(ns, stream);
   195     CHECK_STREAM_NR();
   196 
   197     if (ns->sendNotifications)
   198     {
   199         OWF_Mutex_Lock(&ns->mutex);
   200 
   201         iter = ns->observers;
   202         while (iter)
   203         {
   204             OWFStreamCallbackData* cbdata = (OWFStreamCallbackData*) iter->data;
   205 
   206             DPRINT(("Stream callback: (%p)(%p, %x, %p)",
   207                     cbdata->callback, stream, event, cbdata->data));
   208 
   209             if (cbdata->callback)
   210             {
   211                 (cbdata->callback)(stream, event, cbdata->data);
   212             }
   213             iter = iter->next;
   214         }
   215         OWF_Mutex_Unlock(&ns->mutex);
   216     }
   217 }
   218 
   219 /*----------------------------------------------------------------------------
   220  *  Observer equality comparison
   221  *----------------------------------------------------------------------------*/
   222 static OWFint
   223 ObserversEqual(void* arg1, void* arg2)
   224 {
   225 #define _CALLBACK(x)        ((OWFStreamCallbackData*)(x))
   226 
   227 
   228     return (OWFint)(    _CALLBACK(arg1)->callback ==_CALLBACK(arg2)->callback
   229                     &&  _CALLBACK(arg1)->data ==_CALLBACK(arg2)->data
   230                     );
   231 
   232 #undef _CALLBACK
   233 }
   234 
   235 static OWFint
   236 ObserverFuncsEqual(void* arg1, void* arg2)
   237 {
   238 #define _CALLBACK(x)        ((OWFStreamCallbackData*)(x))
   239 
   240 
   241     return (OWFint)(_CALLBACK(arg1)->callback ==_CALLBACK(arg2)->callback
   242                     );
   243 
   244 #undef _CALLBACK
   245 }
   246 
   247 static OWFint
   248 ObserverDatasEqual(void* arg1, void* arg2)
   249 {
   250 #define _CALLBACK(x)        ((OWFStreamCallbackData*)(x))
   251 
   252 
   253     return (OWFint)(_CALLBACK(arg1)->data ==_CALLBACK(arg2)->data
   254                     );
   255 
   256 #undef _CALLBACK
   257 }
   258 
   259 /*----------------------------------------------------------------------------
   260  *  Destroy native stream (implementation)
   261  *
   262  *  \param ns               Native stream object
   263  *----------------------------------------------------------------------------*/
   264 static void
   265 owfNativeStreamDoDestroy(OWF_NATIVE_STREAM* ns)
   266 {
   267     OWFint                  ii = 0;
   268 
   269     OWF_ASSERT(ns);
   270 
   271     /* bail out if the stream is protected (e.g. the user tries to
   272      * free on-screen context's stream) */
   273     OWF_Mutex_Lock(&ns->mutex);
   274     if (ns->protected)
   275     {
   276         OWF_Mutex_Unlock(&ns->mutex);
   277         return;
   278     }
   279 
   280     /* decrease reference count and check whether it is safe to
   281      * actually destroy the stream */
   282     ns->referenceCount--;
   283 
   284     if (ns->referenceCount > 0) {
   285         OWF_Mutex_Unlock(&ns->mutex);
   286         return;
   287     }
   288 
   289     /* remove from internal dictionary */
   290     if (ns->handle != OWF_INVALID_HANDLE)
   291     {
   292         owfNativeStreamRemove(ns->handle);
   293     }
   294 
   295     OWF_ASSERT(0 == ns->lockCount);
   296 
   297     /* release resources allocated by the stream. */
   298     for (ii = 0; ii < ns->bufferCount; ii++)
   299     {
   300         OWF_Image_FreeData(&ns->bufferList[ii]);
   301     }
   302     xfree(ns->bufferList);
   303 
   304     OWF_Semaphore_Destroy(&ns->writer);
   305     OWF_Mutex_Unlock(&ns->mutex);
   306     OWF_Mutex_Destroy(&ns->mutex);
   307 
   308     ns->mutex = NULL;
   309 
   310     while (ns->observers)
   311     {
   312         OWF_NODE* next = ns->observers->next;
   313         xfree(ns->observers);
   314         ns->observers = next;
   315     }
   316 
   317     xfree(ns->bufferSyncs);
   318     xfree(ns->bufferRefs);
   319     xfree(ns);
   320 }
   321 
   322 /*============================================================================
   323  * PUBLIC API STARTS HERE
   324  *============================================================================*/
   325 
   326 /*!----------------------------------------------------------------------------
   327  *  Create new native stream.
   328  *
   329  *  \param width            Stream image buffer width
   330  *  \param height           Stream image buffer height
   331  *  \param imageFormat      Stream image buffer format
   332  *  \param nbufs            Number of image buffers to allocate
   333  *
   334  *  \param Handle to newly created stream or OWF_INVALID_HANDLe if no
   335  *  stream could be created.
   336  *----------------------------------------------------------------------------*/
   337 OWF_PUBLIC OWFNativeStreamType
   338 owfNativeStreamCreateImageStream(OWFint width,
   339                                  OWFint height,
   340                                  const OWF_IMAGE_FORMAT* imageFormat,
   341                                  OWFint nbufs)
   342 {
   343     OWF_NATIVE_STREAM*      ns          = NULL;
   344     OWFint                  multiFail   = 0;
   345     void**                  bufferList  = NULL;
   346     OWFint*                 bufferRefs  = NULL;
   347     OWF_SYNC_DESC*          bufferSyncs = NULL;
   348     OWFint                  ii          = 0,
   349                             j           = 0;
   350     OWFint                  ok          = 0;
   351 
   352     OWF_ASSERT(nbufs >= 1);
   353 
   354     /* stream must have at least 2 buffers (front & back) */
   355     ns          = NEW0(OWF_NATIVE_STREAM);
   356     bufferList  = xalloc(sizeof(void*), nbufs);
   357     bufferRefs  = xalloc(sizeof(int*), nbufs);
   358 
   359     bufferSyncs  = xalloc(sizeof(OWF_SYNC_DESC), nbufs);
   360 
   361 
   362     /* initialize surface/buffer list */
   363     if (bufferList)
   364     {
   365         for (ii = 0; ii < nbufs; ii++)
   366         {
   367             bufferList[ii] = OWF_Image_AllocData(width, height,
   368                                                  imageFormat->pixelFormat);
   369             if (!bufferList[ii])
   370             {
   371                 multiFail++;
   372                 break;
   373             }
   374         }
   375     }
   376 
   377     if (!ns || !bufferList || multiFail || !bufferRefs || !bufferSyncs)
   378     {
   379         xfree(ns);
   380         if (bufferList)
   381         {
   382             for (j = 0; j < ii; j++)
   383             {
   384                 OWF_Image_FreeData(&bufferList[j]);
   385             }
   386         }
   387         xfree(bufferList);
   388         xfree(bufferRefs);
   389         xfree(bufferSyncs);
   390 
   391         return OWF_INVALID_HANDLE;
   392     }
   393 
   394     ns->bufferList      = bufferList;
   395     ns->bufferRefs      = bufferRefs;
   396     ns->bufferCount     = nbufs;
   397 
   398     ns->width           = width;
   399     ns->height          = height;
   400 
   401     ns->idxFront        = 0;
   402     ns->idxNextFree     = 1;
   403     memcpy(&ns->colorFormat, imageFormat, sizeof(ns->colorFormat));
   404     ns->stride          = OWF_Image_GetStride(width, imageFormat);
   405     ns->referenceCount  = 1;
   406     ns->sendNotifications = OWF_TRUE;
   407     ns->protected       = OWF_FALSE;
   408 
   409     ok = OWF_Semaphore_Init(&ns->writer, nbufs);
   410     if (ok == 0)
   411     {
   412         ok = OWF_Mutex_Init(&ns->mutex);
   413     }
   414 
   415     ns->bufferSyncs = bufferSyncs;
   416 
   417     ns->handle = owfNativeStreamAddStream(ns);
   418     if (ns->handle == OWF_INVALID_HANDLE || ok != 0)
   419     {
   420         owfNativeStreamDoDestroy(ns);
   421         ns = NULL;
   422         return OWF_INVALID_HANDLE;
   423     }
   424 
   425     return ns->handle;
   426 }
   427 /*!---------------------------------------------------------------------------
   428  * Converts from external WFC native stream handle type to internal OWF native stream handle type.
   429  * The internal handle MUST be persistant. The external handle nmay already be persistant.
   430  * This method may fail, either due to memory, or due to the stream object not being supported by the compositor
   431  * @param publicStream The publicly defined stream handle
   432  * @param error			Pointer to store error code - optionally can be NULL
   433  * @return OWFNativeStreamType an equivalent internal stream handle
   434  *----------------------------------------------------------------------------**/
   435 OWF_PUBLIC OWFNativeStreamType owfNativeStreamFromWFC(WFCNativeStreamType publicStream,OWF_STREAM_ERROR* errorReturn)
   436 	{
   437 	OWFNativeStreamType rv=(OWFNativeStreamType)publicStream;
   438 	OWF_IMAGE_FORMAT format;
   439 	owfNativeStreamGetHeader(rv,NULL,NULL,NULL,&format,NULL);
   440 	if (format.pixelFormat==OWF_IMAGE_NOT_SUPPORTED)
   441 		{
   442 		if (errorReturn)
   443 			{
   444 			*errorReturn=OWF_STREAM_ERROR_INVALID_STREAM;
   445 			}
   446 		return OWF_INVALID_HANDLE; 
   447 		}
   448 	owfNativeStreamAddReference(rv);
   449 	if (errorReturn)
   450 		{
   451 		*errorReturn=OWF_STREAM_ERROR_NONE;
   452 		}
   453 	return rv;
   454 	}
   455 
   456 /*!---------------------------------------------------------------------------
   457  *  Increase stream's reference count
   458  *
   459  *  \param stream           Stream handle
   460  *----------------------------------------------------------------------------*/
   461 OWF_API_CALL void
   462 owfNativeStreamAddReference(OWFNativeStreamType stream)
   463 {
   464     OWF_NATIVE_STREAM* ns;
   465 
   466     GET_STREAM(ns, stream);
   467 
   468     CHECK_STREAM_NR();
   469 
   470     OWF_Mutex_Lock(&ns->mutex);
   471     ++(ns->referenceCount);
   472     OWF_Mutex_Unlock(&ns->mutex);
   473 }
   474 
   475 /*!---------------------------------------------------------------------------
   476  *  Decrease stream's reference count
   477  *
   478  *  \param stream           Stream handle
   479  *----------------------------------------------------------------------------*/
   480 OWF_API_CALL void
   481 owfNativeStreamRemoveReference(OWFNativeStreamType stream)
   482 {
   483     OWF_NATIVE_STREAM* ns;
   484 
   485     GET_STREAM(ns, stream);
   486 
   487     CHECK_STREAM_NR();
   488     OWF_Mutex_Lock(&ns->mutex);
   489     --(ns->referenceCount);
   490     OWF_Mutex_Unlock(&ns->mutex);
   491 }
   492 
   493 /*!---------------------------------------------------------------------------
   494  *  Destroy stream. The stream isn't necessarily immediately destroyed, but
   495  *  only when it's reference count reaches zero.
   496  *
   497  *  \param stream           Stream handle
   498  *----------------------------------------------------------------------------*/
   499 OWF_PUBLIC void
   500 owfNativeStreamDestroy(OWFNativeStreamType stream)
   501 {
   502     OWF_NATIVE_STREAM* ns;
   503 
   504     GET_STREAM(ns, stream);
   505     CHECK_STREAM_NR();
   506 
   507     owfNativeStreamDoDestroy(ns);
   508 }
   509 
   510 /*!---------------------------------------------------------------------------
   511  *  Acquire read buffer from stream
   512  *
   513  *  \param stream           Stream handle
   514  *
   515  *  \return Handle to next readable (unread since last write)
   516  *  buffer from the stream or OWF_INVALID_HANDLE if no unread buffers
   517  *  are available.
   518  *----------------------------------------------------------------------------*/
   519 OWF_PUBLIC OWFNativeStreamBuffer
   520 owfNativeStreamAcquireReadBuffer(OWFNativeStreamType stream)
   521 {
   522     OWF_NATIVE_STREAM* ns;
   523     OWFNativeStreamBuffer buffer = OWF_INVALID_HANDLE;
   524 
   525     GET_STREAM(ns, stream);
   526     CHECK_STREAM(OWF_INVALID_HANDLE);
   527 
   528     OWF_Mutex_Lock(&ns->mutex);
   529 
   530     if (ns->bufferCount == 1)
   531     {
   532         /* Single buffered stream.
   533          * A "Write lock" must not block reading */
   534         buffer = INDEX_TO_HANDLE(0);
   535         ++(ns->bufferRefs[0]); /* Increase buffer's reference count */
   536     }
   537     else
   538     {
   539         buffer = INDEX_TO_HANDLE(ns->idxFront);
   540         /* Increase reference count of front buffer */
   541         ++(ns->bufferRefs[ns->idxFront]);
   542     }
   543     OWF_Mutex_Unlock(&ns->mutex);
   544 
   545     return buffer;
   546 }
   547 
   548 /*!---------------------------------------------------------------------------
   549  *  Release read buffer.
   550  *
   551  *  \param stream           Stream handle
   552  *  \param buf              Buffer handle
   553  *----------------------------------------------------------------------------*/
   554 OWF_PUBLIC void
   555 owfNativeStreamReleaseReadBuffer(OWFNativeStreamType stream,
   556                                  OWFNativeStreamBuffer buf)
   557 {
   558     OWFint           i = 0;
   559     OWF_SYNC_DESC*   syncDesc = NULL;
   560 
   561     OWF_NATIVE_STREAM* ns;
   562 
   563     GET_STREAM(ns, stream);
   564     CHECK_STREAM_NR();
   565     CHECK_BUFFER_NR(buf);
   566 
   567     OWF_Mutex_Lock(&ns->mutex);
   568 
   569     i = HANDLE_TO_INDEX(buf);
   570 
   571     OWF_ASSERT(ns->bufferRefs[i] > 0);
   572 
   573     --(ns->bufferRefs[i]);
   574 
   575     syncDesc = &ns->bufferSyncs[i];
   576     if (syncDesc->sync != NULL)
   577     {
   578         DPRINT(("signalling synched buffer(%p, %x)",
   579                 stream, syncDesc->sync));
   580 
   581         eglSignalSyncKHR(syncDesc->dpy, syncDesc->sync, EGL_SIGNALED_KHR);
   582         syncDesc->dpy = EGL_NO_DISPLAY;
   583         syncDesc->sync = NULL;
   584     }
   585     OWF_Mutex_Unlock(&ns->mutex);
   586 }
   587 
   588 /*!---------------------------------------------------------------------------
   589  *  Acquires writable buffer from a stream. The caller has exclusive access
   590  *  to returned buffer until the buffer is commited to stream by
   591  *  calling ReleaseWriteBuffer.
   592  *
   593  *  \param stream           Stream handle
   594  *
   595  *  \return Handle to next writable buffer or OWF_INVALID_HANDLE if no such
   596  *  buffer is available.
   597  *----------------------------------------------------------------------------*/
   598 OWF_PUBLIC OWFNativeStreamBuffer
   599 owfNativeStreamAcquireWriteBuffer(OWFNativeStreamType stream)
   600 {
   601     OWFNativeStreamBuffer   buffer = OWF_INVALID_HANDLE;
   602 
   603     OWF_NATIVE_STREAM* ns;
   604 
   605     GET_STREAM(ns, stream);
   606     CHECK_STREAM(OWF_INVALID_HANDLE);
   607 
   608     OWF_Mutex_Lock(&ns->mutex);
   609 
   610     /* write always blocks */
   611     OWF_Semaphore_Wait(&ns->writer);
   612 
   613     if (ns->bufferCount == 1)
   614     {
   615         /* Single buffered stream */
   616         buffer = INDEX_TO_HANDLE(0);
   617         ++(ns->bufferRefs[0]); /* Increase buffer's reference count */
   618     }
   619     else
   620     {
   621         if (ns->idxFront == ns->idxNextFree)
   622         {
   623             buffer = OWF_INVALID_HANDLE;
   624         }
   625         else
   626         {
   627             buffer = INDEX_TO_HANDLE(ns->idxNextFree);
   628 
   629             ++(ns->bufferRefs[ns->idxNextFree]); /* Increase buffer's
   630                                                     reference count */
   631             ++(ns->idxNextFree); /* Move pointer to next buffer */
   632             if (ns->idxNextFree == ns->bufferCount)
   633             {
   634                 ns->idxNextFree = 0;
   635             }
   636         }
   637     }
   638 
   639     if (buffer != OWF_INVALID_HANDLE)
   640     {
   641         /* Signal associated 'old' sync because
   642          * buffer gets 'dropped', never consumed
   643          */
   644 
   645         OWFint           bufferIndex;
   646         OWF_SYNC_DESC*   syncDesc;
   647 
   648         bufferIndex = HANDLE_TO_INDEX(buffer);
   649         syncDesc = &ns->bufferSyncs[bufferIndex];
   650 
   651         if (syncDesc->sync != NULL)
   652         {
   653             DPRINT(("dropping synched buffer(%p, %x)",
   654                     stream, syncDesc->sync));
   655 
   656             eglSignalSyncKHR(syncDesc->dpy, syncDesc->sync, EGL_SIGNALED_KHR);
   657             syncDesc->dpy = EGL_NO_DISPLAY;
   658             syncDesc->sync = NULL;
   659         }
   660     }
   661 
   662     OWF_Mutex_Unlock(&ns->mutex);
   663 
   664     return buffer;
   665 }
   666 
   667 /*!---------------------------------------------------------------------------
   668  *  Commit write buffer to stream.
   669  *
   670  *  \param stream           Stream handle
   671  *  \param buf              Buffer handle
   672  *  \param sync             EGLSync object which is signalled when
   673  *                          release buffer gets consumed or dropped
   674  *----------------------------------------------------------------------------*/
   675 OWF_PUBLIC void
   676 owfNativeStreamReleaseWriteBuffer(OWFNativeStreamType stream,
   677                                  OWFNativeStreamBuffer buf,
   678                                  EGLDisplay dpy,
   679                                  EGLSyncKHR sync)
   680 {
   681     OWFint                  bufferIndex = 0;
   682 
   683     OWF_NATIVE_STREAM* ns;
   684 
   685     GET_STREAM(ns, stream);
   686     CHECK_STREAM_NR();
   687 
   688     CHECK_BUFFER_NR(buf);
   689 
   690     OWF_Mutex_Lock(&ns->mutex);
   691 
   692     bufferIndex = HANDLE_TO_INDEX(buf);
   693     OWF_ASSERT(ns->bufferRefs[bufferIndex] > 0);
   694 
   695     /* Look up correct buffer (naive search) */
   696     --(ns->bufferRefs[bufferIndex]); /* Decrease buffer's reference count */
   697     ns->idxFront = bufferIndex; /* Update front buffer to point to new
   698                                    front buffer */
   699 
   700     OWF_Semaphore_Post(&ns->writer);
   701 
   702     /* sync object bookkeeping */
   703     ns->bufferSyncs[bufferIndex].dpy = dpy;
   704     ns->bufferSyncs[bufferIndex].sync = sync;
   705 
   706     OWF_Mutex_Unlock(&ns->mutex);
   707 
   708     DPRINT(("Stream updated %p", stream ));
   709 
   710     owfNativeStreamNotifyObservers(stream, OWF_STREAM_UPDATED);
   711 }
   712 
   713 /*!---------------------------------------------------------------------------
   714  *  Register stream content observer. The observer will receive buffer
   715  *  modification event from the stream whenever a buffer is committed.
   716  *
   717  *  \param stream           Stream handle
   718  *  \param observer         Stream observer
   719  *  \param data             Optional data to pass to observer callback
   720  *                          function when event is dispatched.
   721  *----------------------------------------------------------------------------*/
   722 OWF_PUBLIC OWF_STREAM_ERROR
   723 owfNativeStreamAddObserver(OWFNativeStreamType stream,
   724                            OWFStreamCallback observer,
   725                            void* data)
   726 {
   727     OWF_NODE*               node = NULL;
   728     OWFStreamCallbackData* cbdata = NULL;
   729 
   730     OWF_NATIVE_STREAM* ns;
   731 
   732     GET_STREAM(ns, stream);
   733     CHECK_STREAM(OWF_STREAM_ERROR_INVALID_STREAM);
   734 
   735     /* exclusive access only for you my friend. */
   736     OWF_Mutex_Lock(&ns->mutex);
   737 
   738 
   739 
   740     /* new observer. allocate a slot with extra space needed
   741      * to store the callback data. */
   742     node = xalloc(sizeof(OWF_NODE) + sizeof(OWFStreamCallbackData), 1);
   743     if (!node)
   744     {
   745         OWF_Mutex_Unlock(&ns->mutex);
   746         return OWF_STREAM_ERROR_OUT_OF_MEMORY;
   747     }
   748     
   749     /* callback data is directly after node in the memory*/
   750     cbdata = (OWFStreamCallbackData*) &node[1];
   751     cbdata->callback = observer;
   752     cbdata->data = data;
   753     /* for convenience. */
   754     node->data = (void*) cbdata;
   755 
   756 
   757     if (node)
   758     {
   759         /* append to callback-chain */
   760         ns->observers = OWF_List_Append(ns->observers, node);
   761     }
   762 
   763     OWF_Mutex_Unlock(&ns->mutex);
   764 
   765     return OWF_STREAM_ERROR_NONE;
   766 }
   767 
   768 /*!---------------------------------------------------------------------------
   769  *  Remove stream content observer.
   770  *  Observer or Data can be NULL indicating search only checks for other member.
   771  *  Both must not be NULL.
   772  *  \param stream           Stream handle
   773  *  \param observer         Observer to remove
   774  *  \param data             Identifying client data
   775  *
   776  *  \return Zero if the observer was removed successfully, otherwise non-zero
   777  *  (OWF_STREAM_ERROR_INVALID_STREAM if the stream is invalid;
   778  *   OWF_STREAM_ERROR_INVALID_OBSERVER if the observer is invalid.)
   779  *----------------------------------------------------------------------------*/
   780 OWF_PUBLIC OWFint
   781 owfNativeStreamRemoveObserver(OWFNativeStreamType stream,
   782                               OWFStreamCallback observer,
   783                               void* data)
   784 {
   785     OWF_NODE*               node = NULL;
   786     OWFStreamCallbackData   tmp;
   787 
   788     NODECMPFUNC search=ObserversEqual;
   789 
   790     OWF_NATIVE_STREAM* ns;
   791 
   792     GET_STREAM(ns, stream);
   793     CHECK_STREAM(OWF_STREAM_ERROR_INVALID_STREAM);
   794 
   795     OWF_Mutex_Lock(&ns->mutex);
   796 
   797     tmp.callback = observer;
   798     tmp.data = data;
   799     if (!observer)
   800     {
   801         if (!data)
   802         {
   803             return OWF_STREAM_ERROR_INVALID_OBSERVER;
   804         }
   805         else
   806         {
   807             search=ObserverDatasEqual;
   808         }
   809     }
   810     else
   811     {
   812         if (!data)
   813         {
   814             search=ObserverFuncsEqual;
   815         }
   816     }
   817     
   818     node = OWF_List_Find(ns->observers, search, &tmp);
   819 
   820     if (node)
   821     {
   822         /* taketh the observer away */
   823         ns->observers = OWF_List_Remove(ns->observers, node);
   824         /*  to death */
   825         xfree(node);
   826     }
   827 
   828     OWF_Mutex_Unlock(&ns->mutex);
   829 
   830     return node ? OWF_STREAM_ERROR_NONE :
   831                   OWF_STREAM_ERROR_INVALID_OBSERVER;
   832 }
   833 
   834 /*!---------------------------------------------------------------------------
   835  *  Enable/disable stream content notifications.
   836  *
   837  *  \param stream           Stream handle
   838  *  \param send             Boolean value indicating whether the stream should
   839  *                          send content notifications to its observers.
   840  *----------------------------------------------------------------------------*/
   841 OWF_API_CALL void
   842 owfNativeStreamEnableUpdateNotifications(OWFNativeStreamType stream,
   843                                          OWFboolean send)
   844 {
   845     OWF_NATIVE_STREAM* ns;
   846 
   847     GET_STREAM(ns, stream);
   848     CHECK_STREAM_NR();
   849 
   850     OWF_Mutex_Lock(&ns->mutex);
   851 
   852     ns->sendNotifications = send;
   853 
   854     OWF_Mutex_Unlock(&ns->mutex);
   855 }
   856 
   857 /*!---------------------------------------------------------------------------
   858  *  Return pointer to stream buffer's pixel data. The buffer must be
   859  *  a valid read/write buffer.
   860  *
   861  *  \param stream           Stream handle
   862  *  \param buffer           Buffer handle
   863  *
   864  *  \return Pointer to buffers pixel data.
   865  *----------------------------------------------------------------------------*/
   866 OWF_PUBLIC void*
   867 owfNativeStreamGetBufferPtr(OWFNativeStreamType stream,
   868                             OWFNativeStreamBuffer buffer)
   869 {
   870     void*                   bufferPtr = NULL;
   871 
   872     OWF_NATIVE_STREAM* ns;
   873 
   874     GET_STREAM(ns, stream);
   875     CHECK_STREAM(NULL);
   876 
   877     /* Check that buffer has been locked */
   878     OWF_ASSERT(ns->bufferRefs[HANDLE_TO_INDEX(buffer)] > 0);
   879 
   880     OWF_Mutex_Lock(&ns->mutex);
   881 
   882     bufferPtr = ns->bufferList[HANDLE_TO_INDEX(buffer)];
   883 
   884     OWF_Mutex_Unlock(&ns->mutex);
   885 
   886     return bufferPtr;
   887 }
   888 
   889 /*!---------------------------------------------------------------------------
   890  *  Set/reset stream's protection flag. This flag is used for preventing the
   891  *  user from deleting a stream that s/he doesn't really own or should
   892  *  not twiddle with too much (on-screen context's target stream, for example)
   893  *
   894  *  \param stream           Stream handle
   895  *  \param flag             Protection status
   896  *----------------------------------------------------------------------------*/
   897 OWF_API_CALL void
   898 owfNativeStreamSetProtectionFlag(OWFNativeStreamType stream, OWFboolean flag)
   899 {
   900     OWF_NATIVE_STREAM* ns;
   901 
   902     GET_STREAM(ns, stream);
   903     CHECK_STREAM_NR();
   904 
   905     OWF_Mutex_Lock(&ns->mutex);
   906     ns->protected = flag;
   907     OWF_Mutex_Unlock(&ns->mutex);
   908 }
   909 
   910 
   911 /*!---------------------------------------------------------------------------
   912  * Get stream's image header
   913  *
   914  * \param stream            Stream handle
   915  * \param width             Stream width
   916  * \param height            Stream height
   917  * \param stride            Stream stride
   918  * \param format            Stream format
   919  * \param pixelSize         Stream pixelSize
   920  *
   921  * All the parameters above, except stream handle, are pointers to locations
   922  * where the particular value should be written to. Passing in a NULL
   923  * pointer means that the particular values is of no interest to the caller.
   924  *
   925  * E.g. to query only width & height one would call this function with
   926  * parameters (stream_handle, &width, &height, NULL, NULL, NULL);
   927  *
   928  *----------------------------------------------------------------------------*/
   929 OWF_PUBLIC void
   930 owfNativeStreamGetHeader(OWFNativeStreamType stream,
   931                            OWFint* width,
   932                            OWFint* height,
   933                            OWFint* stride,
   934                            OWF_IMAGE_FORMAT* format,
   935                            OWFint* pixelSize)
   936 {
   937     OWF_NATIVE_STREAM* ns;
   938 
   939     GET_STREAM(ns, stream);
   940 
   941     CHECK_STREAM_NR();
   942 
   943     if (width)
   944     {
   945         *width  = ns->width;
   946     }
   947     if (height)
   948     {
   949         *height = ns->height;
   950     }
   951     if (stride)
   952     {
   953         *stride = ns->stride;
   954     }
   955     if (format)
   956     {
   957         memcpy(format, &ns->colorFormat, sizeof(*format));
   958     }
   959 
   960     if (pixelSize)
   961     {
   962         *pixelSize = OWF_Image_GetFormatPixelSize(ns->colorFormat.pixelFormat);
   963     }
   964 }
   965 
   966 #ifdef __cplusplus
   967 }
   968 
   969 #endif