summaryrefslogtreecommitdiff
path: root/src/vg/EGLAddOn.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vg/EGLAddOn.cpp')
-rw-r--r--src/vg/EGLAddOn.cpp868
1 files changed, 868 insertions, 0 deletions
diff --git a/src/vg/EGLAddOn.cpp b/src/vg/EGLAddOn.cpp
new file mode 100644
index 0000000..e8da666
--- /dev/null
+++ b/src/vg/EGLAddOn.cpp
@@ -0,0 +1,868 @@
+/*------------------------------------------------------------------------
+ *
+ * EGL 1.3
+ * -------
+ *
+ * Copyright (c) 2007 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.
+ *
+ *//**
+ * \file
+ * \brief Simple implementation of EGL 1.3
+ * \note caveats:
+ - always renders into the backbuffer and blits it to window (no single buffered rendering)
+ - no native Windows or Mac OS X pixmap support
+ - no power management events
+ - no support for swap interval
+ * \todo what happens in egl functions when eglTerminate has been called but the context and surface are still in use?
+ * \todo OSDeinitMutex should be called in case getEGL fails.
+ *//*-------------------------------------------------------------------*/
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <EGL/egl.h>
+#include "VG/openvg.h"
+#include "Array.h"
+#include "Math.h"
+#include "Context.h"
+#include "Image.h"
+#include "esUtil.h"
+//==============================================================================================
+
+namespace tgOpenVG
+{
+
+void* OSGetCurrentThreadID(void);
+void OSAcquireMutex(void);
+void OSReleaseMutex(void);
+void OSDeinitMutex(void);
+
+EGLDisplay OSGetDisplay(EGLNativeDisplayType display_id);
+void* OSCreateWindowContext(EGLNativeWindowType window);
+void OSDestroyWindowContext(void* context);
+bool OSIsWindow(const void* context);
+void OSGetWindowSize(const void* context, int& width, int& height);
+void OSBlitToWindow(void* context, const Drawable* drawable);
+
+static pthread_mutex_t mutex;
+static int mutexRefCount = 0;
+static bool mutexInitialized = false;
+
+class RIEGLThread;
+
+void* OSGetCurrentThreadID(void)
+{
+ return (void*)pthread_self(); //TODO this is not safe
+}
+
+void OSAcquireMutex(void)
+{
+ if(!mutexInitialized)
+ {
+ int ret;
+ pthread_mutexattr_t attr;
+ ret = pthread_mutexattr_init(&attr); //initially not locked
+ RI_ASSERT(!ret); //check that there aren't any errors
+ ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); //count the number of recursive locks
+ RI_ASSERT(!ret); //check that there aren't any errors
+ ret = pthread_mutex_init(&mutex, &attr);
+ pthread_mutexattr_destroy(&attr);
+ RI_ASSERT(!ret); //check that there aren't more errors
+ RI_UNREF(ret);
+ mutexInitialized = true;
+ }
+ int ret = pthread_mutex_lock(&mutex);
+ RI_ASSERT(ret != EINVAL); //assert that the mutex has been initialized
+ RI_ASSERT(ret != EAGAIN); //assert that the maximum number of recursive locks hasn't been exceeded
+ RI_ASSERT(ret != EDEADLK); //recursive mutexes shouldn't return this
+ RI_ASSERT(!ret); //check that there aren't other errors
+ RI_UNREF(ret);
+ mutexRefCount++;
+}
+
+void OSReleaseMutex(void)
+{
+ RI_ASSERT(mutexInitialized);
+ mutexRefCount--;
+ RI_ASSERT(mutexRefCount >= 0);
+ int ret = pthread_mutex_unlock(&mutex);
+ RI_ASSERT(ret != EPERM); //assert that the current thread owns the mutex
+ RI_ASSERT(!ret); //check that there aren't more errors
+ RI_UNREF(ret);
+}
+
+
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+class RIEGLConfig
+{
+public:
+ RIEGLConfig() : m_desc(Color::formatToDescriptor(VG_sRGBA_8888)), m_configID(0) {}
+ ~RIEGLConfig() {}
+ void set(int r, int g, int b, int a, int l, int bpp, int samples, int maskBits, int ID)
+ {
+ m_desc.redBits = r;
+ m_desc.greenBits = g;
+ m_desc.blueBits = b;
+ m_desc.alphaBits = a;
+ m_desc.luminanceBits = l;
+ m_desc.alphaShift = 0;
+ m_desc.luminanceShift = 0;
+ m_desc.blueShift = b ? a : 0;
+ m_desc.greenShift = g ? a + b : 0;
+ m_desc.redShift = r ? a + b + g : 0;
+ m_desc.format = (VGImageFormat)-1;
+ m_desc.internalFormat = l ? Color::sLA : Color::sRGBA;
+ m_desc.bitsPerPixel = bpp;
+ RI_ASSERT(Color::isValidDescriptor(m_desc));
+ m_samples = samples;
+ m_maskBits = maskBits;
+ m_configID = ID;
+ m_config = (EGLConfig)ID;
+ }
+
+ Color::Descriptor configToDescriptor(bool sRGB, bool premultiplied) const
+ {
+ Color::Descriptor desc = m_desc;
+ unsigned int f = m_desc.luminanceBits ? Color::LUMINANCE : 0;
+ f |= sRGB ? Color::NONLINEAR : 0;
+ f |= premultiplied ? Color::PREMULTIPLIED : 0;
+ desc.internalFormat = (Color::InternalFormat)f;
+ return desc;
+ }
+
+ //EGL RED SIZE bits of Red in the color buffer
+ //EGL GREEN SIZE bits of Green in the color buffer
+ //EGL BLUE SIZE bits of Blue in the color buffer
+ //EGL ALPHA SIZE bits of Alpha in the color buffer
+ //EGL LUMINANCE SIZE bits of Luminance in the color buffer
+ Color::Descriptor m_desc;
+ int m_samples;
+ int m_maskBits;
+ EGLint m_configID; //EGL CONFIG ID unique EGLConfig identifier
+ EGLConfig m_config;
+ //EGL BUFFER SIZE depth of the color buffer (sum of channel bits)
+ //EGL ALPHA MASK SIZE number alpha mask bits (always 8)
+ //EGL BIND TO TEXTURE RGB boolean True if bindable to RGB textures. (always EGL_FALSE)
+ //EGL BIND TO TEXTURE RGBA boolean True if bindable to RGBA textures. (always EGL_FALSE)
+ //EGL COLOR BUFFER TYPE enum color buffer type (EGL_RGB_BUFFER, EGL_LUMINANCE_BUFFER)
+ //EGL CONFIG CAVEAT enum any caveats for the configuration (always EGL_NONE)
+ //EGL DEPTH SIZE integer bits of Z in the depth buffer (always 0)
+ //EGL LEVEL integer frame buffer level (always 0)
+ //EGL MAX PBUFFER WIDTH integer maximum width of pbuffer (always INT_MAX)
+ //EGL MAX PBUFFER HEIGHT integer maximum height of pbuffer (always INT_MAX)
+ //EGL MAX PBUFFER PIXELS integer maximum size of pbuffer (always INT_MAX)
+ //EGL MAX SWAP INTERVAL integer maximum swap interval (always 1)
+ //EGL MIN SWAP INTERVAL integer minimum swap interval (always 1)
+ //EGL NATIVE RENDERABLE boolean EGL TRUE if native rendering APIs can render to surface (always EGL_FALSE)
+ //EGL NATIVE VISUAL ID integer handle of corresponding native visual (always 0)
+ //EGL NATIVE VISUAL TYPE integer native visual type of the associated visual (always EGL_NONE)
+ //EGL RENDERABLE TYPE bitmask which client rendering APIs are supported. (always EGL_OPENVG_BIT)
+ //EGL SAMPLE BUFFERS integer number of multisample buffers (always 0)
+ //EGL SAMPLES integer number of samples per pixel (always 0)
+ //EGL STENCIL SIZE integer bits of Stencil in the stencil buffer (always 0)
+ //EGL SURFACE TYPE bitmask which types of EGL surfaces are supported. (always EGL WINDOW BIT | EGL PIXMAP BIT | EGL PBUFFER BIT)
+ //EGL TRANSPARENT TYPE enum type of transparency supported (always EGL_NONE)
+ //EGL TRANSPARENT RED VALUE integer transparent red value (undefined)
+ //EGL TRANSPARENT GREEN VALUE integer transparent green value (undefined)
+ //EGL TRANSPARENT BLUE VALUE integer transparent blue value (undefined)
+};
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+class RIEGLContext
+{
+public:
+ RIEGLContext(VGContext* vgctx, const EGLConfig config);
+ ~RIEGLContext();
+ void addReference() { m_referenceCount++; }
+ int removeReference() { m_referenceCount--; RI_ASSERT(m_referenceCount >= 0); return m_referenceCount; }
+
+ VGContext* getVGContext() const { return m_vgContext; }
+ const EGLConfig getConfig() const { return m_config; }
+private:
+ RIEGLContext(const RIEGLContext&);
+ RIEGLContext& operator=(const RIEGLContext&);
+ VGContext* m_vgContext;
+ const EGLConfig m_config;
+ int m_referenceCount;
+};
+
+RIEGLContext::RIEGLContext(VGContext* vgctx, const EGLConfig config) :
+ m_vgContext(vgctx),
+ m_config(config),
+ m_referenceCount(0)
+{
+}
+RIEGLContext::~RIEGLContext()
+{
+ RI_ASSERT(m_referenceCount == 0);
+ RI_DELETE(m_vgContext);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+class RIEGLSurface
+{
+public:
+ RIEGLSurface(void* OSWindowContext, const EGLConfig config, Drawable* drawable, bool largestPbuffer, int renderBuffer);
+ ~RIEGLSurface();
+ void addReference() { m_referenceCount++; }
+ int removeReference() { m_referenceCount--; RI_ASSERT(m_referenceCount >= 0); return m_referenceCount; }
+
+ void* getOSWindowContext() const { return m_OSWindowContext; }
+ const EGLConfig getConfig() const { return m_config; }
+ Drawable* getDrawable() const { return m_drawable; }
+ bool isLargestPbuffer() const { return m_largestPbuffer; }
+ int getRenderBuffer() const { return m_renderBuffer; }
+
+private:
+ RIEGLSurface(const RIEGLSurface&);
+ RIEGLSurface& operator=(const RIEGLSurface&);
+ void* m_OSWindowContext;
+ const EGLConfig m_config;
+ Drawable* m_drawable;
+ bool m_largestPbuffer;
+ int m_renderBuffer; //EGL_BACK_BUFFER or EGL_SINGLE_BUFFER
+ int m_referenceCount;
+};
+
+RIEGLSurface::RIEGLSurface(void* OSWindowContext, const EGLConfig config, Drawable* drawable, bool largestPbuffer, int renderBuffer) :
+ m_OSWindowContext(OSWindowContext),
+ m_config(config),
+ m_drawable(drawable),
+ m_largestPbuffer(largestPbuffer),
+ m_renderBuffer(renderBuffer),
+ m_referenceCount(0)
+{
+ RI_ASSERT(m_renderBuffer == EGL_BACK_BUFFER); //only back buffer rendering is supported
+ m_drawable->addReference();
+}
+
+RIEGLSurface::~RIEGLSurface()
+{
+ RI_ASSERT(m_referenceCount == 0);
+ // TAG FIX ME OSDestroyWindowContext(m_OSWindowContext);
+ if(m_drawable)
+ {
+ if(!m_drawable->removeReference())
+ RI_DELETE(m_drawable);
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+#define EGL_NUMCONFIGS 60
+
+class RIEGLDisplay
+{
+public:
+ RIEGLDisplay(EGLDisplay id);
+ ~RIEGLDisplay();
+
+ int getNumConfigs() const { return EGL_NUMCONFIGS; }
+ const RIEGLConfig& getConfig(int i) const { RI_ASSERT(i >= 0 && i < EGL_NUMCONFIGS); return m_configs[i]; }
+ const RIEGLConfig& getConfig(const EGLConfig config) const { for(int i=0;i<EGL_NUMCONFIGS;i++) { if(m_configs[i].m_config == config) return m_configs[i]; } RI_ASSERT(0); return m_configs[0]; }
+
+ const EGLDisplay getID() const { return m_id; }
+
+ void addContext(RIEGLContext* ctx) { RI_ASSERT(ctx); m_contexts.push_back(ctx); } //throws bad_alloc
+ void removeContext(RIEGLContext* ctx) { RI_ASSERT(ctx); bool res = m_contexts.remove(ctx); RI_ASSERT(res); RI_UNREF(res); }
+
+ void addSurface(RIEGLSurface* srf) { RI_ASSERT(srf); m_surfaces.push_back(srf); } //throws bad_alloc
+ void removeSurface(RIEGLSurface* srf) { RI_ASSERT(srf); bool res = m_surfaces.remove(srf); RI_ASSERT(res); RI_UNREF(res); }
+
+ EGLBoolean contextExists(const EGLContext ctx) const;
+ EGLBoolean surfaceExists(const EGLSurface srf) const;
+ EGLBoolean configExists(const EGLConfig cfg) const;
+
+private:
+ RIEGLDisplay(const RIEGLDisplay& t);
+ RIEGLDisplay& operator=(const RIEGLDisplay&t);
+
+ EGLDisplay m_id;
+
+ Array<RIEGLContext*> m_contexts;
+ Array<RIEGLSurface*> m_surfaces;
+
+ RIEGLConfig m_configs[EGL_NUMCONFIGS];
+};
+
+RIEGLDisplay::RIEGLDisplay(EGLDisplay id) :
+ m_id(id),
+ m_contexts(),
+ m_surfaces()
+{
+ RI_ASSERT(EGL_NUMCONFIGS == 60);
+
+ //sorted by RGB/LUMINANCE (exact), larger total number of color bits (at least), buffer size (at least), config ID (exact)
+ //NOTE: 16 bit configs need to be sorted on the fly if the request ignores some channels
+ //NOTE: config IDs start from 1
+ // R B G A L bpp samples maskBits ID
+ m_configs[0].set(8, 8, 8, 8, 0, 32, 1, 8, 1); //EGL_RGB_BUFFER, buffer size = 32
+ m_configs[1].set(8, 8, 8, 0, 0, 32, 1, 8, 2); //EGL_RGB_BUFFER, buffer size = 24
+ m_configs[2].set(5, 5, 5, 1, 0, 16, 1, 4, 3); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[3].set(5, 6, 5, 0, 0, 16, 1, 4, 4); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[4].set(4, 4, 4, 4, 0, 16, 1, 4, 5); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[5].set(0, 0, 0, 8, 0, 8, 1, 8, 6); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[6].set(0, 0, 0, 4, 0, 4, 1, 4, 7); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[7].set(0, 0, 0, 1, 0, 1, 1, 1, 8); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[8].set(0, 0, 0, 0, 8, 8, 1, 8, 9); //EGL_LUMINANCE_BUFFER, buffer size = 8
+ m_configs[9].set(0, 0, 0, 0, 1, 1, 1, 1, 10); //EGL_LUMINANCE_BUFFER, buffer size = 1
+
+ m_configs[10].set(8, 8, 8, 8, 0, 32, 4, 1, 11); //EGL_RGB_BUFFER, buffer size = 32
+ m_configs[11].set(8, 8, 8, 0, 0, 32, 4, 1, 12); //EGL_RGB_BUFFER, buffer size = 24
+ m_configs[12].set(5, 5, 5, 1, 0, 16, 4, 1, 13); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[13].set(5, 6, 5, 0, 0, 16, 4, 1, 14); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[14].set(4, 4, 4, 4, 0, 16, 4, 1, 15); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[15].set(0, 0, 0, 8, 0, 8, 4, 1, 16); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[16].set(0, 0, 0, 4, 0, 4, 4, 1, 17); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[17].set(0, 0, 0, 1, 0, 1, 4, 1, 18); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[18].set(0, 0, 0, 0, 8, 8, 4, 1, 19); //EGL_LUMINANCE_BUFFER, buffer size = 8
+ m_configs[19].set(0, 0, 0, 0, 1, 1, 4, 1, 20); //EGL_LUMINANCE_BUFFER, buffer size = 1
+
+ m_configs[20].set(8, 8, 8, 8, 0, 32, 32, 1, 21); //EGL_RGB_BUFFER, buffer size = 32
+ m_configs[21].set(8, 8, 8, 0, 0, 32, 32, 1, 22); //EGL_RGB_BUFFER, buffer size = 24
+ m_configs[22].set(5, 5, 5, 1, 0, 16, 32, 1, 23); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[23].set(5, 6, 5, 0, 0, 16, 32, 1, 24); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[24].set(4, 4, 4, 4, 0, 16, 32, 1, 25); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[25].set(0, 0, 0, 8, 0, 8, 32, 1, 26); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[26].set(0, 0, 0, 4, 0, 4, 32, 1, 27); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[27].set(0, 0, 0, 1, 0, 1, 32, 1, 28); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[28].set(0, 0, 0, 0, 8, 8, 32, 1, 29); //EGL_LUMINANCE_BUFFER, buffer size = 8
+ m_configs[29].set(0, 0, 0, 0, 1, 1, 32, 1, 30); //EGL_LUMINANCE_BUFFER, buffer size = 1
+
+ //configs without mask
+ m_configs[30].set(8, 8, 8, 8, 0, 32, 1, 0, 31); //EGL_RGB_BUFFER, buffer size = 32
+ m_configs[31].set(8, 8, 8, 0, 0, 32, 1, 0, 32); //EGL_RGB_BUFFER, buffer size = 24
+ m_configs[32].set(5, 5, 5, 1, 0, 16, 1, 0, 33); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[33].set(5, 6, 5, 0, 0, 16, 1, 0, 34); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[34].set(4, 4, 4, 4, 0, 16, 1, 0, 35); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[35].set(0, 0, 0, 8, 0, 8, 1, 0, 36); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[36].set(0, 0, 0, 4, 0, 4, 1, 0, 37); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[37].set(0, 0, 0, 1, 0, 1, 1, 0, 38); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[38].set(0, 0, 0, 0, 8, 8, 1, 0, 39); //EGL_LUMINANCE_BUFFER, buffer size = 8
+ m_configs[39].set(0, 0, 0, 0, 1, 1, 1, 0, 40); //EGL_LUMINANCE_BUFFER, buffer size = 1
+
+ m_configs[40].set(8, 8, 8, 8, 0, 32, 4, 0, 41); //EGL_RGB_BUFFER, buffer size = 32
+ m_configs[41].set(8, 8, 8, 0, 0, 32, 4, 0, 42); //EGL_RGB_BUFFER, buffer size = 24
+ m_configs[42].set(5, 5, 5, 1, 0, 16, 4, 0, 43); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[43].set(5, 6, 5, 0, 0, 16, 4, 0, 44); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[44].set(4, 4, 4, 4, 0, 16, 4, 0, 45); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[45].set(0, 0, 0, 8, 0, 8, 4, 0, 46); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[46].set(0, 0, 0, 4, 0, 4, 4, 0, 47); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[47].set(0, 0, 0, 1, 0, 1, 4, 0, 48); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[48].set(0, 0, 0, 0, 8, 8, 4, 0, 49); //EGL_LUMINANCE_BUFFER, buffer size = 8
+ m_configs[49].set(0, 0, 0, 0, 1, 1, 4, 0, 50); //EGL_LUMINANCE_BUFFER, buffer size = 1
+
+ m_configs[50].set(8, 8, 8, 8, 0, 32, 32, 0, 51); //EGL_RGB_BUFFER, buffer size = 32
+ m_configs[51].set(8, 8, 8, 0, 0, 32, 32, 0, 52); //EGL_RGB_BUFFER, buffer size = 24
+ m_configs[52].set(5, 5, 5, 1, 0, 16, 32, 0, 53); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[53].set(5, 6, 5, 0, 0, 16, 32, 0, 54); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[54].set(4, 4, 4, 4, 0, 16, 32, 0, 55); //EGL_RGB_BUFFER, buffer size = 16
+ m_configs[55].set(0, 0, 0, 8, 0, 8, 32, 0, 56); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[56].set(0, 0, 0, 4, 0, 4, 32, 0, 57); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[57].set(0, 0, 0, 1, 0, 1, 32, 0, 58); //EGL_RGB_BUFFER, buffer size = 8
+ m_configs[58].set(0, 0, 0, 0, 8, 8, 32, 0, 59); //EGL_LUMINANCE_BUFFER, buffer size = 8
+ m_configs[59].set(0, 0, 0, 0, 1, 1, 32, 0, 60); //EGL_LUMINANCE_BUFFER, buffer size = 1
+/*
+attrib default criteria order priority
+--------------------------------------------------------------
+EGL_COLOR_BUFFER_TYPE EGL_RGB_BUFFER Exact None 2
+EGL_RED_SIZE 0 AtLeast Special 3
+EGL_GREEN_SIZE 0 AtLeast Special 3
+EGL_BLUE_SIZE 0 AtLeast Special 3
+EGL_LUMINANCE_SIZE 0 AtLeast Special 3
+EGL_ALPHA_SIZE 0 AtLeast Special 3
+EGL_BUFFER_SIZE 0 AtLeast Smaller 4
+EGL_CONFIG_ID EGL_DONT_CARE Exact Smaller 11
+*/
+}
+
+RIEGLDisplay::~RIEGLDisplay()
+{
+ //mark everything for deletion, but don't delete the current context and surface
+ for(int i=0;i<m_contexts.size();i++)
+ {
+ if(!m_contexts[i]->removeReference())
+ RI_DELETE(m_contexts[i]);
+ }
+ m_contexts.clear(); //remove all contexts from the list (makes further references to the current contexts invalid)
+
+ for(int i=0;i<m_surfaces.size();i++)
+ {
+ if(!m_surfaces[i]->removeReference())
+ RI_DELETE(m_surfaces[i]);
+ }
+ m_surfaces.clear(); //remove all surfaces from the list (makes further references to the current surfaces invalid)
+}
+
+EGLBoolean RIEGLDisplay::contextExists(const EGLContext ctx) const
+{
+ for(int i=0;i<m_contexts.size();i++)
+ {
+ if(m_contexts[i] == ctx)
+ return EGL_TRUE;
+ }
+ return EGL_FALSE;
+}
+
+EGLBoolean RIEGLDisplay::surfaceExists(const EGLSurface surf) const
+{
+ for(int i=0;i<m_surfaces.size();i++)
+ {
+ if(m_surfaces[i] == surf)
+ return EGL_TRUE;
+ }
+ return EGL_FALSE;
+}
+
+EGLBoolean RIEGLDisplay::configExists(const EGLConfig config) const
+{
+ for(int i=0;i<EGL_NUMCONFIGS;i++)
+ {
+ if(m_configs[i].m_config == config)
+ return EGL_TRUE;
+ }
+ return EGL_FALSE;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+class RIEGLThread
+{
+public:
+ RIEGLThread(void* currentThreadID);
+ ~RIEGLThread();
+
+ void* getThreadID() const { return m_threadID; }
+
+ void makeCurrent(RIEGLContext* c, RIEGLSurface* s) { m_context = c; m_surface = s; }
+ RIEGLContext* getCurrentContext() const { return m_context; }
+ RIEGLSurface* getCurrentSurface() const { return m_surface; }
+
+ void setError(EGLint error) { m_error = error; }
+ EGLint getError() const { return m_error; }
+
+ void bindAPI(EGLint api) { m_boundAPI = api; }
+ EGLint getBoundAPI() const { return m_boundAPI; }
+
+private:
+ RIEGLThread(const RIEGLThread&);
+ RIEGLThread operator=(const RIEGLThread&);
+
+ RIEGLContext* m_context;
+ RIEGLSurface* m_surface;
+ EGLint m_error;
+ void* m_threadID;
+ EGLint m_boundAPI;
+};
+
+RIEGLThread::RIEGLThread(void* currentThreadID) :
+ m_context(NULL),
+ m_surface(NULL),
+ m_error(EGL_SUCCESS),
+ m_threadID(currentThreadID),
+ m_boundAPI(EGL_NONE)
+{
+}
+
+RIEGLThread::~RIEGLThread()
+{
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+class EGL
+{
+public:
+ EGL();
+ ~EGL();
+
+ void addReference() { m_referenceCount++; }
+ int removeReference() { m_referenceCount--; RI_ASSERT(m_referenceCount >= 0); return m_referenceCount; }
+
+ void addDisplay(RIEGLDisplay* display) { RI_ASSERT(display); m_displays.push_back(display); } //throws bad alloc
+ void removeDisplay(RIEGLDisplay* display) { RI_ASSERT(display); bool res = m_displays.remove(display); RI_ASSERT(res); RI_UNREF(res); }
+ RIEGLDisplay* getDisplay(const EGLDisplay displayID) const;
+ const EGLDisplay findDisplay(const EGLContext ctx) const;
+
+ void addCurrentThread(RIEGLThread* thread) { RI_ASSERT(thread); m_currentThreads.push_back(thread); } //throws bad alloc
+ void removeCurrentThread(RIEGLThread* thread) { RI_ASSERT(thread); bool res = m_currentThreads.remove(thread); RI_ASSERT(res); RI_UNREF(res); }
+ RIEGLThread* getCurrentThread() const;
+
+ RIEGLThread* getThread();
+ void destroyThread();
+
+ bool isInUse(const void* image) const;
+
+private:
+ EGL(const EGL&); // Not allowed.
+ const EGL& operator=(const EGL&); // Not allowed.
+
+ Array<RIEGLThread*> m_threads; //threads that have called EGL
+ Array<RIEGLThread*> m_currentThreads; //threads that have a bound context
+ Array<RIEGLDisplay*> m_displays;
+
+ int m_referenceCount;
+};
+
+EGL::EGL() :
+ m_displays(),
+ m_threads(),
+ m_currentThreads(),
+ m_referenceCount(0)
+{
+}
+EGL::~EGL()
+{
+ for(int i=0;i<m_displays.size();i++)
+ {
+ RI_DELETE(m_displays[i]);
+ }
+ for(int i=0;i<m_threads.size();i++)
+ {
+ RI_DELETE(m_threads[i]);
+ }
+ //currentThreads contain just pointers to threads we just deleted
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static EGL* g_egl = NULL; //never use this directly
+static EGL* getEGL()
+{
+ if(!g_egl)
+ {
+ try
+ {
+ g_egl = RI_NEW(EGL, ()); //throws bad_alloc
+ g_egl->addReference();
+ }
+ catch(std::bad_alloc)
+ {
+ g_egl = NULL;
+ }
+ }
+ return g_egl;
+}
+static void releaseEGL()
+{
+ if(g_egl)
+ {
+ if(!g_egl->removeReference())
+ {
+ RI_DELETE(g_egl);
+ g_egl = NULL;
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Given a display ID, return the corresponding object, or NULL
+* if the ID hasn't been initialized.
+* \param
+* \return
+* \note if egl has been initialized for this display, the display ID can
+* be found from egl->m_displays
+*//*-------------------------------------------------------------------*/
+
+RIEGLDisplay* EGL::getDisplay(EGLDisplay displayID) const
+{
+ for(int i=0;i<m_displays.size();i++)
+ {
+ if(displayID == m_displays[i]->getID())
+ return m_displays[i];
+ }
+ return NULL; //error: the display hasn't been eglInitialized
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief return EGLDisplay for the current context
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+const EGLDisplay EGL::findDisplay(EGLContext ctx) const
+{
+ for(int i=0;i<m_displays.size();i++)
+ {
+ if(m_displays[i]->contextExists(ctx))
+ return m_displays[i]->getID();
+ }
+ return EGL_NO_DISPLAY;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief return an EGL thread struct for the thread made current, or
+* NULL if there's no current context.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+RIEGLThread* EGL::getCurrentThread() const
+{
+ void* currentThreadID = OSGetCurrentThreadID();
+ for(int i=0;i<m_currentThreads.size();i++)
+ {
+ if(currentThreadID == m_currentThreads[i]->getThreadID())
+ return m_currentThreads[i];
+ }
+ return NULL; //thread is not current
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief return an EGL thread struct corresponding to current OS thread.
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+RIEGLThread* EGL::getThread()
+{
+ void* currentThreadID = OSGetCurrentThreadID();
+ for(int i=0;i<m_threads.size();i++)
+ {
+ if(currentThreadID == m_threads[i]->getThreadID())
+ return m_threads[i];
+ }
+
+ //EGL doesn't have a struct for the thread yet, add it to EGL's list
+ RIEGLThread* newThread = NULL;
+ try
+ {
+ newThread = RI_NEW(RIEGLThread, (OSGetCurrentThreadID())); //throws bad_alloc
+ m_threads.push_back(newThread); //throws bad_alloc
+ return newThread;
+ }
+ catch(std::bad_alloc)
+ {
+ RI_DELETE(newThread);
+ return NULL;
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief destroy an EGL thread struct
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+void EGL::destroyThread()
+{
+ void* currentThreadID = OSGetCurrentThreadID();
+ for(int i=0;i<m_threads.size();i++)
+ {
+ if(currentThreadID == m_threads[i]->getThreadID())
+ {
+ RIEGLThread* thread = m_threads[i];
+ bool res = m_threads.remove(thread);
+ RI_ASSERT(res);
+ RI_UNREF(res);
+ RI_DELETE(thread);
+ break;
+ }
+ }
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+bool EGL::isInUse(const void* image) const
+{
+ for(int i=0;i<m_currentThreads.size();i++)
+ {
+ RIEGLSurface* s = m_currentThreads[i]->getCurrentSurface();
+ if(s && s->getDrawable() && s->getDrawable()->isInUse((Image*)image))
+ return true;
+ }
+ return false;
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+#define EGL_GET_DISPLAY(DISPLAY, RETVAL) \
+ OSAcquireMutex(); \
+ EGL* egl = getEGL(); \
+ if(!egl) \
+ { \
+ OSReleaseMutex(); \
+ return RETVAL; \
+ } \
+ RIEGLDisplay* display = egl->getDisplay(DISPLAY); \
+
+#define EGL_GET_EGL(RETVAL) \
+ OSAcquireMutex(); \
+ EGL* egl = getEGL(); \
+ if(!egl) \
+ { \
+ OSReleaseMutex(); \
+ return RETVAL; \
+ } \
+
+#define EGL_IF_ERROR(COND, ERRORCODE, RETVAL) \
+ if(COND) { eglSetError(egl, ERRORCODE); OSReleaseMutex(); return RETVAL; } \
+
+#define EGL_RETURN(ERRORCODE, RETVAL) \
+ { \
+ eglSetError(egl, ERRORCODE); \
+ OSReleaseMutex(); \
+ return RETVAL; \
+ }
+
+// Note: egl error handling model differs from OpenVG. The latest error is stored instead of the oldest one.
+static void eglSetError(EGL* egl, EGLint error)
+{
+ RIEGLThread* thread = egl->getThread();
+ if(thread)
+ thread->setError(error);
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Returns the OpenVG context current to the calling thread.
+* \param
+* \return
+* \note This function is always called from a mutexed API function
+*//*-------------------------------------------------------------------*/
+
+void* eglvgGetCurrentVGContext(void)
+{
+ EGL* egl = getEGL();
+ if(egl)
+ {
+ RIEGLThread* thread = egl->getCurrentThread();
+ if(thread)
+ {
+ RI_ASSERT(thread->getCurrentContext() && thread->getCurrentSurface());
+ return thread->getCurrentContext()->getVGContext();
+ }
+ }
+ return NULL; //not initialized or made current
+}
+
+/*-------------------------------------------------------------------*//*!
+* \brief Check if the image is current in any of the displays
+* \param
+* \return
+* \note This function is always called from a mutexed API function
+*//*-------------------------------------------------------------------*/
+
+bool eglvgIsInUse(void* image)
+{
+ EGL* egl = getEGL();
+ if(egl)
+ {
+ return egl->isInUse(image);
+ }
+ return false;
+}
+
+//==============================================================================================
+
+} //namespace tgOpenVG
+
+using namespace tgOpenVG;
+
+extern "C"
+void tgOpenVGCreateContext(ESContext *esContext) {
+
+ EGL* egl = getEGL();
+
+ RIEGLThread* thread = egl->getThread();
+ tgOpenVG::VGContext* vgctx = NULL;
+ RIEGLContext* c = NULL;
+
+ try {
+ vgctx = RI_NEW(tgOpenVG::VGContext, (NULL)); //throws bad_alloc
+ c = RI_NEW(RIEGLContext, (vgctx, esContext->eglConfig)); //throws bad_alloc
+ esContext->vgContext = vgctx;
+
+ }
+ catch (std::bad_alloc) {
+ }
+}
+
+
+/*-------------------------------------------------------------------*//*!
+* \brief
+* \param
+* \return
+* \note
+*//*-------------------------------------------------------------------*/
+
+static bool smaller(EGLint c, EGLint filter)
+{
+ return (filter != EGL_DONT_CARE) && (c < filter);
+}
+