sl@0: /* Copyright (c) 2009 The Khronos Group Inc. sl@0: * Portions copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies) sl@0: * sl@0: * Permission is hereby granted, free of charge, to any person obtaining a sl@0: * copy of this software and/or associated documentation files (the sl@0: * "Materials"), to deal in the Materials without restriction, including sl@0: * without limitation the rights to use, copy, modify, merge, publish, sl@0: * distribute, sublicense, and/or sell copies of the Materials, and to sl@0: * permit persons to whom the Materials are furnished to do so, subject to sl@0: * the following conditions: sl@0: * sl@0: * The above copyright notice and this permission notice shall be included sl@0: * in all copies or substantial portions of the Materials. sl@0: * sl@0: * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, sl@0: * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF sl@0: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. sl@0: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY sl@0: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, sl@0: * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE sl@0: * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. sl@0: */ sl@0: sl@0: /*! sl@0: * Ring buffer based Image Stream implementation for Linux. sl@0: */ sl@0: sl@0: sl@0: sl@0: #ifdef __cplusplus sl@0: extern "C" { sl@0: #endif sl@0: sl@0: #define OWF_NATIVESTREAM_HANDLE 0xAB sl@0: sl@0: #include sl@0: #include sl@0: sl@0: #include "owfnativestream.h" sl@0: #include "owfscreen.h" sl@0: #include "owfmemory.h" sl@0: #include "owfdebug.h" sl@0: #include "owftypes.h" sl@0: #include "owfmutex.h" sl@0: #include "owfhstore.h" sl@0: sl@0: /*needed for owfNativeStreamFromWFC function */ sl@0: #include "WF/wfcplatform.h" sl@0: sl@0: /* macro for fetching stream object by handle */ sl@0: #define GET_STREAM(ns, s) ns = owfNativeStreamGet(s) sl@0: sl@0: /* stream null checks */ sl@0: #define CHECK_STREAM(v) if (NULL == ns) { return v;} sl@0: #define CHECK_STREAM_NR() if (NULL == ns) { return; } sl@0: sl@0: #define BUFFER_HANDLE_BASE 0x100 sl@0: #define STREAM_HANDLE_BASE 10000 sl@0: #define STREAM_HASHTABLE_SIZE 0x100 sl@0: sl@0: /* buffer handle sanity checks */ sl@0: #define CHECK_BUFFER_NR(x) if ((x) < BUFFER_HANDLE_BASE || \ sl@0: (x) >= BUFFER_HANDLE_BASE + ns->bufferCount) \ sl@0: { \ sl@0: return; \ sl@0: } sl@0: sl@0: #define CHECK_BUFFER(x,v) if ((x) < BUFFER_HANDLE_BASE || \ sl@0: (x) >= BUFFER_HANDLE_BASE + ns->bufferCount) \ sl@0: { \ sl@0: return v; \ sl@0: } sl@0: sl@0: #define BUFFER(x) ns->bufferList[(x)-BUFFER_HANDLE_BASE] sl@0: sl@0: #define INDEX_TO_HANDLE(x) ((OWFNativeStreamBuffer) ((x)+BUFFER_HANDLE_BASE)) sl@0: #define HANDLE_TO_INDEX(x) ((int) ((x)-BUFFER_HANDLE_BASE)) sl@0: sl@0: typedef struct { sl@0: EGLDisplay dpy; sl@0: EGLSyncKHR* sync; sl@0: } OWF_SYNC_DESC; sl@0: sl@0: sl@0: /*! sl@0: * Structure for image stream. sl@0: */ sl@0: typedef struct { sl@0: OWFNativeStreamType handle; /* stream handle */ sl@0: void** bufferList; sl@0: OWFint* bufferRefs; sl@0: OWFint bufferCount; sl@0: OWFint lockCount; sl@0: OWFint screenNumber; sl@0: OWFint width, /* frame width (pixels) */ sl@0: height, /* frame height (pixels) */ sl@0: stride; /* size of single row (bytes) */ sl@0: OWF_IMAGE_FORMAT colorFormat; sl@0: OWFint referenceCount; sl@0: OWF_MUTEX mutex; sl@0: OWF_SEMAPHORE writer; sl@0: OWFint idxFront; sl@0: OWFint idxNextFree; sl@0: OWF_NODE* observers; sl@0: OWFboolean sendNotifications; sl@0: OWFboolean protected; /* protection flag to prevent the sl@0: user from destroying the stream sl@0: (for onscreen-context use) */ sl@0: sl@0: OWF_SYNC_DESC* bufferSyncs; /* sync object to be signalled when sl@0: buffer is 'consumed' */ sl@0: } OWF_NATIVE_STREAM; sl@0: sl@0: sl@0: static const OWF_IMAGE_FORMAT owfOnScreenColorFormat = sl@0: { sl@0: OWF_IMAGE_ARGB8888, sl@0: OWF_FALSE, sl@0: OWF_TRUE, sl@0: 4 sl@0: }; sl@0: sl@0: /*============================================================================ sl@0: * PRIVATE PARTS sl@0: *============================================================================*/ sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Internal. sl@0: *----------------------------------------------------------------------------*/ sl@0: /* sl@0: sl@0: */ sl@0: /*!--------------------------------------------------------------------------- sl@0: * Add stream to internal stream dictionary sl@0: * sl@0: * \param handle Stream handle sl@0: * \param stream Stream object associated with the handle sl@0: * sl@0: * \return Boolean value indicating whether the addition was succesful sl@0: *----------------------------------------------------------------------------*/ sl@0: static OWFHandle sl@0: owfNativeStreamAddStream(OWF_NATIVE_STREAM* stream) sl@0: { sl@0: OWFHandle handle = OWF_INVALID_HANDLE; sl@0: sl@0: handle = OWF_HStore_HandleCreate(OWF_NATIVESTREAM_HANDLE, stream); sl@0: sl@0: return handle; sl@0: } sl@0: sl@0: /*---------------------------------------------------------------------------- sl@0: * Returns the stream object associated to given handle sl@0: * sl@0: * \param handle Stream handle sl@0: * sl@0: * \return Stream object or NULL if the handle is invalid sl@0: *----------------------------------------------------------------------------*/ sl@0: static OWF_NATIVE_STREAM* sl@0: owfNativeStreamGet(OWFNativeStreamType handle) sl@0: { sl@0: return (OWF_NATIVE_STREAM*) OWF_HStore_GetObj(handle, OWF_NATIVESTREAM_HANDLE); sl@0: } sl@0: sl@0: /*---------------------------------------------------------------------------- sl@0: * Remove stream from internal stream dictionary sl@0: * sl@0: * \param handle Stream handle sl@0: * sl@0: * \return Boolean value indicating success of the deletion sl@0: *----------------------------------------------------------------------------*/ sl@0: static OWFboolean sl@0: owfNativeStreamRemove(OWFNativeStreamType handle) sl@0: { sl@0: OWF_HStore_HandleDelete(handle); sl@0: return OWF_TRUE; sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Notify stream's observers about an event sl@0: * sl@0: * \param stream Stream sl@0: * \param event Event to notify about sl@0: *----------------------------------------------------------------------------*/ sl@0: static void owfNativeStreamNotifyObservers(OWFNativeStreamType stream, sl@0: OWFNativeStreamEvent event) sl@0: { sl@0: OWF_NODE* iter = NULL; sl@0: sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: DPRINT(("owfNativeStreamNotifyObservers(%p, %x)", sl@0: stream, event)); sl@0: sl@0: GET_STREAM(ns, stream); sl@0: CHECK_STREAM_NR(); sl@0: sl@0: if (ns->sendNotifications) sl@0: { sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: sl@0: iter = ns->observers; sl@0: while (iter) sl@0: { sl@0: OWFStreamCallbackData* cbdata = (OWFStreamCallbackData*) iter->data; sl@0: sl@0: DPRINT(("Stream callback: (%p)(%p, %x, %p)", sl@0: cbdata->callback, stream, event, cbdata->data)); sl@0: sl@0: if (cbdata->callback) sl@0: { sl@0: (cbdata->callback)(stream, event, cbdata->data); sl@0: } sl@0: iter = iter->next; sl@0: } sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: } sl@0: } sl@0: sl@0: /*---------------------------------------------------------------------------- sl@0: * Observer equality comparison sl@0: *----------------------------------------------------------------------------*/ sl@0: static OWFint sl@0: ObserversEqual(void* arg1, void* arg2) sl@0: { sl@0: #define _CALLBACK(x) ((OWFStreamCallbackData*)(x)) sl@0: sl@0: sl@0: return (OWFint)( _CALLBACK(arg1)->callback ==_CALLBACK(arg2)->callback sl@0: && _CALLBACK(arg1)->data ==_CALLBACK(arg2)->data sl@0: ); sl@0: sl@0: #undef _CALLBACK sl@0: } sl@0: sl@0: static OWFint sl@0: ObserverFuncsEqual(void* arg1, void* arg2) sl@0: { sl@0: #define _CALLBACK(x) ((OWFStreamCallbackData*)(x)) sl@0: sl@0: sl@0: return (OWFint)(_CALLBACK(arg1)->callback ==_CALLBACK(arg2)->callback sl@0: ); sl@0: sl@0: #undef _CALLBACK sl@0: } sl@0: sl@0: static OWFint sl@0: ObserverDatasEqual(void* arg1, void* arg2) sl@0: { sl@0: #define _CALLBACK(x) ((OWFStreamCallbackData*)(x)) sl@0: sl@0: sl@0: return (OWFint)(_CALLBACK(arg1)->data ==_CALLBACK(arg2)->data sl@0: ); sl@0: sl@0: #undef _CALLBACK sl@0: } sl@0: sl@0: /*---------------------------------------------------------------------------- sl@0: * Destroy native stream (implementation) sl@0: * sl@0: * \param ns Native stream object sl@0: *----------------------------------------------------------------------------*/ sl@0: static void sl@0: owfNativeStreamDoDestroy(OWF_NATIVE_STREAM* ns) sl@0: { sl@0: OWFint ii = 0; sl@0: sl@0: OWF_ASSERT(ns); sl@0: sl@0: /* bail out if the stream is protected (e.g. the user tries to sl@0: * free on-screen context's stream) */ sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: if (ns->protected) sl@0: { sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: return; sl@0: } sl@0: sl@0: /* decrease reference count and check whether it is safe to sl@0: * actually destroy the stream */ sl@0: ns->referenceCount--; sl@0: sl@0: if (ns->referenceCount > 0) { sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: return; sl@0: } sl@0: sl@0: /* remove from internal dictionary */ sl@0: if (ns->handle != OWF_INVALID_HANDLE) sl@0: { sl@0: owfNativeStreamRemove(ns->handle); sl@0: } sl@0: sl@0: OWF_ASSERT(0 == ns->lockCount); sl@0: sl@0: /* release resources allocated by the stream. */ sl@0: for (ii = 0; ii < ns->bufferCount; ii++) sl@0: { sl@0: OWF_Image_FreeData(&ns->bufferList[ii]); sl@0: } sl@0: xfree(ns->bufferList); sl@0: sl@0: OWF_Semaphore_Destroy(&ns->writer); sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: OWF_Mutex_Destroy(&ns->mutex); sl@0: sl@0: ns->mutex = NULL; sl@0: sl@0: while (ns->observers) sl@0: { sl@0: OWF_NODE* next = ns->observers->next; sl@0: xfree(ns->observers); sl@0: ns->observers = next; sl@0: } sl@0: sl@0: xfree(ns->bufferSyncs); sl@0: xfree(ns->bufferRefs); sl@0: xfree(ns); sl@0: } sl@0: sl@0: /*============================================================================ sl@0: * PUBLIC API STARTS HERE sl@0: *============================================================================*/ sl@0: sl@0: /*!---------------------------------------------------------------------------- sl@0: * Create new native stream. sl@0: * sl@0: * \param width Stream image buffer width sl@0: * \param height Stream image buffer height sl@0: * \param imageFormat Stream image buffer format sl@0: * \param nbufs Number of image buffers to allocate sl@0: * sl@0: * \param Handle to newly created stream or OWF_INVALID_HANDLe if no sl@0: * stream could be created. sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_PUBLIC OWFNativeStreamType sl@0: owfNativeStreamCreateImageStream(OWFint width, sl@0: OWFint height, sl@0: const OWF_IMAGE_FORMAT* imageFormat, sl@0: OWFint nbufs) sl@0: { sl@0: OWF_NATIVE_STREAM* ns = NULL; sl@0: OWFint multiFail = 0; sl@0: void** bufferList = NULL; sl@0: OWFint* bufferRefs = NULL; sl@0: OWF_SYNC_DESC* bufferSyncs = NULL; sl@0: OWFint ii = 0, sl@0: j = 0; sl@0: OWFint ok = 0; sl@0: sl@0: OWF_ASSERT(nbufs >= 1); sl@0: sl@0: /* stream must have at least 2 buffers (front & back) */ sl@0: ns = NEW0(OWF_NATIVE_STREAM); sl@0: bufferList = xalloc(sizeof(void*), nbufs); sl@0: bufferRefs = xalloc(sizeof(int*), nbufs); sl@0: sl@0: bufferSyncs = xalloc(sizeof(OWF_SYNC_DESC), nbufs); sl@0: sl@0: sl@0: /* initialize surface/buffer list */ sl@0: if (bufferList) sl@0: { sl@0: for (ii = 0; ii < nbufs; ii++) sl@0: { sl@0: bufferList[ii] = OWF_Image_AllocData(width, height, sl@0: imageFormat->pixelFormat); sl@0: if (!bufferList[ii]) sl@0: { sl@0: multiFail++; sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: if (!ns || !bufferList || multiFail || !bufferRefs || !bufferSyncs) sl@0: { sl@0: xfree(ns); sl@0: if (bufferList) sl@0: { sl@0: for (j = 0; j < ii; j++) sl@0: { sl@0: OWF_Image_FreeData(&bufferList[j]); sl@0: } sl@0: } sl@0: xfree(bufferList); sl@0: xfree(bufferRefs); sl@0: xfree(bufferSyncs); sl@0: sl@0: return OWF_INVALID_HANDLE; sl@0: } sl@0: sl@0: ns->bufferList = bufferList; sl@0: ns->bufferRefs = bufferRefs; sl@0: ns->bufferCount = nbufs; sl@0: sl@0: ns->width = width; sl@0: ns->height = height; sl@0: sl@0: ns->idxFront = 0; sl@0: ns->idxNextFree = 1; sl@0: memcpy(&ns->colorFormat, imageFormat, sizeof(ns->colorFormat)); sl@0: ns->stride = OWF_Image_GetStride(width, imageFormat); sl@0: ns->referenceCount = 1; sl@0: ns->sendNotifications = OWF_TRUE; sl@0: ns->protected = OWF_FALSE; sl@0: sl@0: ok = OWF_Semaphore_Init(&ns->writer, nbufs); sl@0: if (ok == 0) sl@0: { sl@0: ok = OWF_Mutex_Init(&ns->mutex); sl@0: } sl@0: sl@0: ns->bufferSyncs = bufferSyncs; sl@0: sl@0: ns->handle = owfNativeStreamAddStream(ns); sl@0: if (ns->handle == OWF_INVALID_HANDLE || ok != 0) sl@0: { sl@0: owfNativeStreamDoDestroy(ns); sl@0: ns = NULL; sl@0: return OWF_INVALID_HANDLE; sl@0: } sl@0: sl@0: return ns->handle; sl@0: } sl@0: /*!--------------------------------------------------------------------------- sl@0: * Converts from external WFC native stream handle type to internal OWF native stream handle type. sl@0: * The internal handle MUST be persistant. The external handle nmay already be persistant. sl@0: * This method may fail, either due to memory, or due to the stream object not being supported by the compositor sl@0: * @param publicStream The publicly defined stream handle sl@0: * @param error Pointer to store error code - optionally can be NULL sl@0: * @return OWFNativeStreamType an equivalent internal stream handle sl@0: *----------------------------------------------------------------------------**/ sl@0: OWF_PUBLIC OWFNativeStreamType owfNativeStreamFromWFC(WFCNativeStreamType publicStream,OWF_STREAM_ERROR* errorReturn) sl@0: { sl@0: OWFNativeStreamType rv=(OWFNativeStreamType)publicStream; sl@0: OWF_IMAGE_FORMAT format; sl@0: owfNativeStreamGetHeader(rv,NULL,NULL,NULL,&format,NULL); sl@0: if (format.pixelFormat==OWF_IMAGE_NOT_SUPPORTED) sl@0: { sl@0: if (errorReturn) sl@0: { sl@0: *errorReturn=OWF_STREAM_ERROR_INVALID_STREAM; sl@0: } sl@0: return OWF_INVALID_HANDLE; sl@0: } sl@0: owfNativeStreamAddReference(rv); sl@0: if (errorReturn) sl@0: { sl@0: *errorReturn=OWF_STREAM_ERROR_NONE; sl@0: } sl@0: return rv; sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Increase stream's reference count sl@0: * sl@0: * \param stream Stream handle sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL void sl@0: owfNativeStreamAddReference(OWFNativeStreamType stream) sl@0: { sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: sl@0: CHECK_STREAM_NR(); sl@0: sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: ++(ns->referenceCount); sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Decrease stream's reference count sl@0: * sl@0: * \param stream Stream handle sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL void sl@0: owfNativeStreamRemoveReference(OWFNativeStreamType stream) sl@0: { sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: sl@0: CHECK_STREAM_NR(); sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: --(ns->referenceCount); sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Destroy stream. The stream isn't necessarily immediately destroyed, but sl@0: * only when it's reference count reaches zero. sl@0: * sl@0: * \param stream Stream handle sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_PUBLIC void sl@0: owfNativeStreamDestroy(OWFNativeStreamType stream) sl@0: { sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: CHECK_STREAM_NR(); sl@0: sl@0: owfNativeStreamDoDestroy(ns); sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Acquire read buffer from stream sl@0: * sl@0: * \param stream Stream handle sl@0: * sl@0: * \return Handle to next readable (unread since last write) sl@0: * buffer from the stream or OWF_INVALID_HANDLE if no unread buffers sl@0: * are available. sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_PUBLIC OWFNativeStreamBuffer sl@0: owfNativeStreamAcquireReadBuffer(OWFNativeStreamType stream) sl@0: { sl@0: OWF_NATIVE_STREAM* ns; sl@0: OWFNativeStreamBuffer buffer = OWF_INVALID_HANDLE; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: CHECK_STREAM(OWF_INVALID_HANDLE); sl@0: sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: sl@0: if (ns->bufferCount == 1) sl@0: { sl@0: /* Single buffered stream. sl@0: * A "Write lock" must not block reading */ sl@0: buffer = INDEX_TO_HANDLE(0); sl@0: ++(ns->bufferRefs[0]); /* Increase buffer's reference count */ sl@0: } sl@0: else sl@0: { sl@0: buffer = INDEX_TO_HANDLE(ns->idxFront); sl@0: /* Increase reference count of front buffer */ sl@0: ++(ns->bufferRefs[ns->idxFront]); sl@0: } sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: sl@0: return buffer; sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Release read buffer. sl@0: * sl@0: * \param stream Stream handle sl@0: * \param buf Buffer handle sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_PUBLIC void sl@0: owfNativeStreamReleaseReadBuffer(OWFNativeStreamType stream, sl@0: OWFNativeStreamBuffer buf) sl@0: { sl@0: OWFint i = 0; sl@0: OWF_SYNC_DESC* syncDesc = NULL; sl@0: sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: CHECK_STREAM_NR(); sl@0: CHECK_BUFFER_NR(buf); sl@0: sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: sl@0: i = HANDLE_TO_INDEX(buf); sl@0: sl@0: OWF_ASSERT(ns->bufferRefs[i] > 0); sl@0: sl@0: --(ns->bufferRefs[i]); sl@0: sl@0: syncDesc = &ns->bufferSyncs[i]; sl@0: if (syncDesc->sync != NULL) sl@0: { sl@0: DPRINT(("signalling synched buffer(%p, %x)", sl@0: stream, syncDesc->sync)); sl@0: sl@0: eglSignalSyncKHR(syncDesc->dpy, syncDesc->sync, EGL_SIGNALED_KHR); sl@0: syncDesc->dpy = EGL_NO_DISPLAY; sl@0: syncDesc->sync = NULL; sl@0: } sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Acquires writable buffer from a stream. The caller has exclusive access sl@0: * to returned buffer until the buffer is commited to stream by sl@0: * calling ReleaseWriteBuffer. sl@0: * sl@0: * \param stream Stream handle sl@0: * sl@0: * \return Handle to next writable buffer or OWF_INVALID_HANDLE if no such sl@0: * buffer is available. sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_PUBLIC OWFNativeStreamBuffer sl@0: owfNativeStreamAcquireWriteBuffer(OWFNativeStreamType stream) sl@0: { sl@0: OWFNativeStreamBuffer buffer = OWF_INVALID_HANDLE; sl@0: sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: CHECK_STREAM(OWF_INVALID_HANDLE); sl@0: sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: sl@0: /* write always blocks */ sl@0: OWF_Semaphore_Wait(&ns->writer); sl@0: sl@0: if (ns->bufferCount == 1) sl@0: { sl@0: /* Single buffered stream */ sl@0: buffer = INDEX_TO_HANDLE(0); sl@0: ++(ns->bufferRefs[0]); /* Increase buffer's reference count */ sl@0: } sl@0: else sl@0: { sl@0: if (ns->idxFront == ns->idxNextFree) sl@0: { sl@0: buffer = OWF_INVALID_HANDLE; sl@0: } sl@0: else sl@0: { sl@0: buffer = INDEX_TO_HANDLE(ns->idxNextFree); sl@0: sl@0: ++(ns->bufferRefs[ns->idxNextFree]); /* Increase buffer's sl@0: reference count */ sl@0: ++(ns->idxNextFree); /* Move pointer to next buffer */ sl@0: if (ns->idxNextFree == ns->bufferCount) sl@0: { sl@0: ns->idxNextFree = 0; sl@0: } sl@0: } sl@0: } sl@0: sl@0: if (buffer != OWF_INVALID_HANDLE) sl@0: { sl@0: /* Signal associated 'old' sync because sl@0: * buffer gets 'dropped', never consumed sl@0: */ sl@0: sl@0: OWFint bufferIndex; sl@0: OWF_SYNC_DESC* syncDesc; sl@0: sl@0: bufferIndex = HANDLE_TO_INDEX(buffer); sl@0: syncDesc = &ns->bufferSyncs[bufferIndex]; sl@0: sl@0: if (syncDesc->sync != NULL) sl@0: { sl@0: DPRINT(("dropping synched buffer(%p, %x)", sl@0: stream, syncDesc->sync)); sl@0: sl@0: eglSignalSyncKHR(syncDesc->dpy, syncDesc->sync, EGL_SIGNALED_KHR); sl@0: syncDesc->dpy = EGL_NO_DISPLAY; sl@0: syncDesc->sync = NULL; sl@0: } sl@0: } sl@0: sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: sl@0: return buffer; sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Commit write buffer to stream. sl@0: * sl@0: * \param stream Stream handle sl@0: * \param buf Buffer handle sl@0: * \param sync EGLSync object which is signalled when sl@0: * release buffer gets consumed or dropped sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_PUBLIC void sl@0: owfNativeStreamReleaseWriteBuffer(OWFNativeStreamType stream, sl@0: OWFNativeStreamBuffer buf, sl@0: EGLDisplay dpy, sl@0: EGLSyncKHR sync) sl@0: { sl@0: OWFint bufferIndex = 0; sl@0: sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: CHECK_STREAM_NR(); sl@0: sl@0: CHECK_BUFFER_NR(buf); sl@0: sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: sl@0: bufferIndex = HANDLE_TO_INDEX(buf); sl@0: OWF_ASSERT(ns->bufferRefs[bufferIndex] > 0); sl@0: sl@0: /* Look up correct buffer (naive search) */ sl@0: --(ns->bufferRefs[bufferIndex]); /* Decrease buffer's reference count */ sl@0: ns->idxFront = bufferIndex; /* Update front buffer to point to new sl@0: front buffer */ sl@0: sl@0: OWF_Semaphore_Post(&ns->writer); sl@0: sl@0: /* sync object bookkeeping */ sl@0: ns->bufferSyncs[bufferIndex].dpy = dpy; sl@0: ns->bufferSyncs[bufferIndex].sync = sync; sl@0: sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: sl@0: DPRINT(("Stream updated %p", stream )); sl@0: sl@0: owfNativeStreamNotifyObservers(stream, OWF_STREAM_UPDATED); sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Register stream content observer. The observer will receive buffer sl@0: * modification event from the stream whenever a buffer is committed. sl@0: * sl@0: * \param stream Stream handle sl@0: * \param observer Stream observer sl@0: * \param data Optional data to pass to observer callback sl@0: * function when event is dispatched. sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_PUBLIC OWF_STREAM_ERROR sl@0: owfNativeStreamAddObserver(OWFNativeStreamType stream, sl@0: OWFStreamCallback observer, sl@0: void* data) sl@0: { sl@0: OWF_NODE* node = NULL; sl@0: OWFStreamCallbackData* cbdata = NULL; sl@0: sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: CHECK_STREAM(OWF_STREAM_ERROR_INVALID_STREAM); sl@0: sl@0: /* exclusive access only for you my friend. */ sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: sl@0: sl@0: sl@0: /* new observer. allocate a slot with extra space needed sl@0: * to store the callback data. */ sl@0: node = xalloc(sizeof(OWF_NODE) + sizeof(OWFStreamCallbackData), 1); sl@0: if (!node) sl@0: { sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: return OWF_STREAM_ERROR_OUT_OF_MEMORY; sl@0: } sl@0: sl@0: /* callback data is directly after node in the memory*/ sl@0: cbdata = (OWFStreamCallbackData*) &node[1]; sl@0: cbdata->callback = observer; sl@0: cbdata->data = data; sl@0: /* for convenience. */ sl@0: node->data = (void*) cbdata; sl@0: sl@0: sl@0: if (node) sl@0: { sl@0: /* append to callback-chain */ sl@0: ns->observers = OWF_List_Append(ns->observers, node); sl@0: } sl@0: sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: sl@0: return OWF_STREAM_ERROR_NONE; sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Remove stream content observer. sl@0: * Observer or Data can be NULL indicating search only checks for other member. sl@0: * Both must not be NULL. sl@0: * \param stream Stream handle sl@0: * \param observer Observer to remove sl@0: * \param data Identifying client data sl@0: * sl@0: * \return Zero if the observer was removed successfully, otherwise non-zero sl@0: * (OWF_STREAM_ERROR_INVALID_STREAM if the stream is invalid; sl@0: * OWF_STREAM_ERROR_INVALID_OBSERVER if the observer is invalid.) sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_PUBLIC OWFint sl@0: owfNativeStreamRemoveObserver(OWFNativeStreamType stream, sl@0: OWFStreamCallback observer, sl@0: void* data) sl@0: { sl@0: OWF_NODE* node = NULL; sl@0: OWFStreamCallbackData tmp; sl@0: sl@0: NODECMPFUNC search=ObserversEqual; sl@0: sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: CHECK_STREAM(OWF_STREAM_ERROR_INVALID_STREAM); sl@0: sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: sl@0: tmp.callback = observer; sl@0: tmp.data = data; sl@0: if (!observer) sl@0: { sl@0: if (!data) sl@0: { sl@0: return OWF_STREAM_ERROR_INVALID_OBSERVER; sl@0: } sl@0: else sl@0: { sl@0: search=ObserverDatasEqual; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if (!data) sl@0: { sl@0: search=ObserverFuncsEqual; sl@0: } sl@0: } sl@0: sl@0: node = OWF_List_Find(ns->observers, search, &tmp); sl@0: sl@0: if (node) sl@0: { sl@0: /* taketh the observer away */ sl@0: ns->observers = OWF_List_Remove(ns->observers, node); sl@0: /* to death */ sl@0: xfree(node); sl@0: } sl@0: sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: sl@0: return node ? OWF_STREAM_ERROR_NONE : sl@0: OWF_STREAM_ERROR_INVALID_OBSERVER; sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Enable/disable stream content notifications. sl@0: * sl@0: * \param stream Stream handle sl@0: * \param send Boolean value indicating whether the stream should sl@0: * send content notifications to its observers. sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL void sl@0: owfNativeStreamEnableUpdateNotifications(OWFNativeStreamType stream, sl@0: OWFboolean send) sl@0: { sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: CHECK_STREAM_NR(); sl@0: sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: sl@0: ns->sendNotifications = send; sl@0: sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Return pointer to stream buffer's pixel data. The buffer must be sl@0: * a valid read/write buffer. sl@0: * sl@0: * \param stream Stream handle sl@0: * \param buffer Buffer handle sl@0: * sl@0: * \return Pointer to buffers pixel data. sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_PUBLIC void* sl@0: owfNativeStreamGetBufferPtr(OWFNativeStreamType stream, sl@0: OWFNativeStreamBuffer buffer) sl@0: { sl@0: void* bufferPtr = NULL; sl@0: sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: CHECK_STREAM(NULL); sl@0: sl@0: /* Check that buffer has been locked */ sl@0: OWF_ASSERT(ns->bufferRefs[HANDLE_TO_INDEX(buffer)] > 0); sl@0: sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: sl@0: bufferPtr = ns->bufferList[HANDLE_TO_INDEX(buffer)]; sl@0: sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: sl@0: return bufferPtr; sl@0: } sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Set/reset stream's protection flag. This flag is used for preventing the sl@0: * user from deleting a stream that s/he doesn't really own or should sl@0: * not twiddle with too much (on-screen context's target stream, for example) sl@0: * sl@0: * \param stream Stream handle sl@0: * \param flag Protection status sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL void sl@0: owfNativeStreamSetProtectionFlag(OWFNativeStreamType stream, OWFboolean flag) sl@0: { sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: CHECK_STREAM_NR(); sl@0: sl@0: OWF_Mutex_Lock(&ns->mutex); sl@0: ns->protected = flag; sl@0: OWF_Mutex_Unlock(&ns->mutex); sl@0: } sl@0: sl@0: sl@0: /*!--------------------------------------------------------------------------- sl@0: * Get stream's image header sl@0: * sl@0: * \param stream Stream handle sl@0: * \param width Stream width sl@0: * \param height Stream height sl@0: * \param stride Stream stride sl@0: * \param format Stream format sl@0: * \param pixelSize Stream pixelSize sl@0: * sl@0: * All the parameters above, except stream handle, are pointers to locations sl@0: * where the particular value should be written to. Passing in a NULL sl@0: * pointer means that the particular values is of no interest to the caller. sl@0: * sl@0: * E.g. to query only width & height one would call this function with sl@0: * parameters (stream_handle, &width, &height, NULL, NULL, NULL); sl@0: * sl@0: *----------------------------------------------------------------------------*/ sl@0: OWF_PUBLIC void sl@0: owfNativeStreamGetHeader(OWFNativeStreamType stream, sl@0: OWFint* width, sl@0: OWFint* height, sl@0: OWFint* stride, sl@0: OWF_IMAGE_FORMAT* format, sl@0: OWFint* pixelSize) sl@0: { sl@0: OWF_NATIVE_STREAM* ns; sl@0: sl@0: GET_STREAM(ns, stream); sl@0: sl@0: CHECK_STREAM_NR(); sl@0: sl@0: if (width) sl@0: { sl@0: *width = ns->width; sl@0: } sl@0: if (height) sl@0: { sl@0: *height = ns->height; sl@0: } sl@0: if (stride) sl@0: { sl@0: *stride = ns->stride; sl@0: } sl@0: if (format) sl@0: { sl@0: memcpy(format, &ns->colorFormat, sizeof(*format)); sl@0: } sl@0: sl@0: if (pixelSize) sl@0: { sl@0: *pixelSize = OWF_Image_GetFormatPixelSize(ns->colorFormat.pixelFormat); sl@0: } sl@0: } sl@0: sl@0: #ifdef __cplusplus sl@0: } sl@0: sl@0: #endif