summaryrefslogtreecommitdiff
path: root/src/vg/EGLAddOn.cpp
diff options
context:
space:
mode:
authorTom Gall <tom.gall@linaro.org>2014-10-05 23:02:12 -0500
committerTom Gall <tom.gall@linaro.org>2014-10-05 23:02:12 -0500
commitffbf61c267a162c3e5d41c9ff310e2c8dae1c3bd (patch)
treeb966b6d1b2c0a6bcb8787e234defcd47ac2a1f0b /src/vg/EGLAddOn.cpp
Initial commit
This is the reference implementation with the miniEGL code stripped out Tests are simplistic at this point. Windowing uses traditional egl (mesa test) but should work with mali egl too.
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);
+}
+