m3g/m3gcore11/src/m3g_rendercontext.inl
changeset 36 01a6848ebfd7
parent 0 5d03bc08d59c
child 45 36b2e23a8629
--- a/m3g/m3gcore11/src/m3g_rendercontext.inl	Tue Feb 02 01:47:50 2010 +0200
+++ b/m3g/m3gcore11/src/m3g_rendercontext.inl	Fri Apr 16 16:21:04 2010 +0300
@@ -26,7 +26,7 @@
 #   error This file is for the OES API only
 #endif
 
-#include <GLES/egl.h>
+#include <EGL/egl.h>
 #include "m3g_image.h"
 
 /*----------------------------------------------------------------------
@@ -40,9 +40,10 @@
  */
 static EGLConfig m3gQueryEGLConfig(M3Genum format,
                                    M3Gbitmask bufferBits,
-                                   EGLint surfaceBits)
+                                   EGLint surfaceBits,
+                                   M3GNativeBitmap bitmapHandle)
 {
-    struct { int attrib, value; } attribs[9];
+    struct { int attrib, value; } attribs[10];
     int samples;
 
     /* Determine color depth */
@@ -93,37 +94,72 @@
     attribs[5].attrib = EGL_SURFACE_TYPE;
     attribs[5].value = surfaceBits;
 
-    /* Try to get multisampling if requested */
+
+    if (bitmapHandle) {
+        /* This attribute is matched only for pixmap targets */
+        attribs[6].attrib = EGL_MATCH_NATIVE_PIXMAP;
+        attribs[6].value = bitmapHandle;
+
+        /* Try to get multisampling if requested */
+
+        attribs[7].attrib = EGL_SAMPLE_BUFFERS;
+        attribs[8].attrib = EGL_SAMPLES;
 
-    attribs[6].attrib = EGL_SAMPLE_BUFFERS;
-    attribs[7].attrib = EGL_SAMPLES;
-    attribs[8].attrib = EGL_NONE;
+        attribs[9].attrib = EGL_NONE;
+    } else {
+        /* Try to get multisampling if requested */
 
+        attribs[6].attrib = EGL_SAMPLE_BUFFERS;
+        attribs[7].attrib = EGL_SAMPLES;
+
+        attribs[8].attrib = EGL_NONE;
+    }
+    
+    
     /* Try 4 samples if multisampling enabled, then 2, then 1 */
     
     samples = (bufferBits & M3G_MULTISAMPLE_BUFFER_BIT) ? 4 : 1;
     for ( ; samples > 0; samples >>= 1) {
         
-        if (samples > 1) {
-            attribs[6].value = 1;
-            attribs[7].value = samples;
-        }
-        else {
-            attribs[6].value = EGL_FALSE;
-            attribs[7].value = 0;
+        if (bitmapHandle) {
+            if (samples > 1) {
+                attribs[7].value = 1;
+                attribs[8].value = samples;
+            }
+            else {
+                attribs[7].value = EGL_FALSE;
+                attribs[8].value = 0;
+            }
+        } else {
+            if (samples > 1) {
+                attribs[6].value = 1;
+                attribs[7].value = samples;
+            }
+            else {
+                attribs[6].value = EGL_FALSE;
+                attribs[7].value = 0;
+            }
         }
 
         /* Get the first matching config; according to EGL sorting
          * rules, this should be an accelerated one if possible */
         {
             EGLConfig config;
-            int numConfigs;
+            int numConfigs;  
+            EGLint error;            
+        
             eglChooseConfig(eglGetDisplay(EGL_DEFAULT_DISPLAY),
                             (const int *) attribs,
                             &config, 1,
                             &numConfigs);
             
-            M3G_ASSERT(eglGetError() == EGL_SUCCESS);
+            error = eglGetError();
+            if (error != EGL_SUCCESS) {
+                M3G_LOG1(M3G_LOG_FATAL_ERRORS, "eglChooseConfig  failed: %d\n", error);
+            }
+            
+            
+            M3G_ASSERT(error == EGL_SUCCESS);
 
             /* If we got a config, return that; otherwise, drop the
              * number of multisampling samples and try again, or
@@ -154,6 +190,7 @@
 {
     M3G_LOG(M3G_LOG_INTERFACE, "Initializing EGL\n");
     eglInitialize(eglGetDisplay(EGL_DEFAULT_DISPLAY), NULL, NULL);
+    eglBindAPI(EGL_OPENGL_ES_API);
 }
 
 /*!
@@ -170,7 +207,7 @@
  * \internal
  * \brief Creates a new EGL context
  */
-static EGLContext m3gCreateGLContext(M3Genum format,
+/*static EGLContext m3gCreateGLContext(M3Genum format,
                                      M3Gbitmask bufferBits,
                                      M3Gbitmask reqSurfaceBits,
                                      EGLContext share,
@@ -181,7 +218,7 @@
 
     M3G_ASSERT((reqSurfaceBits & ~(EGL_PIXMAP_BIT|EGL_PBUFFER_BIT|EGL_WINDOW_BIT)) == 0);
     
-    config = m3gQueryEGLConfig(format, bufferBits, reqSurfaceBits);
+    config = m3gQueryEGLConfig(format, bufferBits, reqSurfaceBits, NULL);
     
     if (!config || !eglGetConfigAttrib(eglGetDisplay(EGL_DEFAULT_DISPLAY),
                                        config,
@@ -205,7 +242,7 @@
     M3G_LOG1(M3G_LOG_OBJECTS, "New GL context 0x%08X\n", (unsigned) ctx);
     return ctx;
 }
-
+*/
 /*!
  * \internal
  * \brief Deletes an EGL context
@@ -236,7 +273,7 @@
                                          M3GNativeWindow wnd)
 {
     EGLSurface surf;
-    EGLConfig config = m3gQueryEGLConfig(format, bufferBits, EGL_WINDOW_BIT);
+    EGLConfig config = m3gQueryEGLConfig(format, bufferBits, EGL_WINDOW_BIT, NULL);
     
     if (!config) {
         return NULL;
@@ -272,7 +309,7 @@
                                          M3GNativeBitmap bmp)
 {
     EGLSurface surf;
-    EGLConfig config = m3gQueryEGLConfig(format, bufferBits, EGL_PIXMAP_BIT);
+    EGLConfig config = m3gQueryEGLConfig(format, bufferBits, EGL_PIXMAP_BIT, bmp);
     
     if (!config) {
         return NULL;
@@ -317,7 +354,7 @@
     attrib[3] = height;
     attrib[4] = EGL_NONE;
     
-    config = m3gQueryEGLConfig(format, bufferBits, EGL_PBUFFER_BIT);
+    config = m3gQueryEGLConfig(format, bufferBits, EGL_PBUFFER_BIT, NULL);
     if (!config) {
         return NULL;
     }
@@ -410,7 +447,7 @@
     if (internalFormat == M3G_RGB8_32) {
         glFormat = GL_RGBA;
     }
-    if (internalFormat == M3G_BGR8_32) {
+    if (internalFormat == M3G_BGR8_32 || internalFormat == M3G_ARGB8) {
         glFormat = GL_RGBA;
         mustConvert = M3G_TRUE;
     }
@@ -714,6 +751,7 @@
     M3GPixelFormat format = ctx->target.format;
     M3Gbitmask bufferBits = ctx->bufferBits;
     M3Gbitmask surfaceType = ctx->target.type;
+    M3GNativeBitmap bitmapHandle = ctx->target.handle;
     int i;
 
     /* Images always go via pbuffers; EGL surfaces can always be
@@ -742,7 +780,7 @@
 
     /* No dice; must resort to querying from EGL */
 
-    return (m3gQueryEGLConfig(format, bufferBits, (EGLint) surfaceType) != NULL);
+    return (m3gQueryEGLConfig(format, bufferBits, (EGLint) surfaceType, bitmapHandle) != NULL);
 }
 
 /*!
@@ -918,38 +956,45 @@
     if (ctx->target.type == SURFACE_IMAGE) {
         m3gDrawFrameBufferImage(ctx, (Image *) ctx->target.handle);
     }
-    else if (ctx->target.type == SURFACE_BITMAP) {
+    else if (ctx->target.type == SURFACE_BITMAP || ctx->target.type == SURFACE_MEMORY) {
 
         M3Gubyte *src;
         M3Gsizei stride;
 
-        /* Obtain a pointer to the native bitmap and copy the data to
-         * the backbuffer from there */
-        
-        if (m3gglLockNativeBitmap((M3GNativeBitmap) ctx->target.handle,
-                                  &src, &stride)) {
+        M3Gint clipWidth = ctx->clip.x1 - ctx->clip.x0;
+        M3Gint clipHeight = ctx->clip.y1 - ctx->clip.y0;
+        M3Gint srcOffset;
 
-            M3Gint clipWidth = ctx->clip.x1 - ctx->clip.x0;
-            M3Gint clipHeight = ctx->clip.y1 - ctx->clip.y0;
-            M3Gint srcOffset =
-                (ctx->target.height - ctx->clip.y1) * stride
-                + ctx->clip.x0 * m3gBytesPerPixel(ctx->target.format);
-            
-            m3gBlitFrameBufferPixels(
-                ctx,
-                ctx->clip.x0, ctx->clip.y0,
-                clipWidth, clipHeight,
-                ctx->target.format,
-                stride,
-                src + srcOffset);
-                
+        if (ctx->target.type == SURFACE_BITMAP) {
+            /* Obtain a pointer to the native bitmap and copy the data to
+             * the backbuffer from there */
+            if (!m3gglLockNativeBitmap((M3GNativeBitmap) ctx->target.handle,
+                                      &src, &stride)) {
+                /* No dice! There's no way that we know of to copy the
+                 * data between the buffers */
+                M3G_ASSERT(M3G_FALSE);
+            }
+        } else {
+            /* Memory target */
+            src = ctx->target.pixels;
+            stride = ctx->target.stride;
+        }
+
+        srcOffset =
+            (ctx->target.height - ctx->clip.y1) * stride
+            + ctx->clip.x0 * m3gBytesPerPixel(ctx->target.format);
+        
+        m3gBlitFrameBufferPixels(
+            ctx,
+            ctx->clip.x0, ctx->clip.y0,
+            clipWidth, clipHeight,
+            ctx->target.format,
+            stride,
+            src + srcOffset);
+
+        if (ctx->target.type == SURFACE_BITMAP) {
             m3gglReleaseNativeBitmap((M3GNativeBitmap) ctx->target.handle);
         }
-        else {
-            /* No dice! There's no way that we know of to copy the
-             * data between the buffers */
-            M3G_ASSERT(M3G_FALSE);
-        }
     }
     else {
         /* Buffered rendering is not supported for window and pbuffer
@@ -969,67 +1014,75 @@
     if (ctx->target.type == SURFACE_IMAGE) {
         m3gCopyFrameBufferImage((Image *) ctx->target.handle);
     }
-    else if (ctx->target.type == SURFACE_BITMAP) {
+    else if (ctx->target.type == SURFACE_BITMAP || ctx->target.type == SURFACE_MEMORY) {
         
-        /* We must copy the back buffer to a native bitmap: first
-         * attempt a fast buffer-to-buffer copy using EGL, but if that
-         * fails, obtain a pointer and do the copy ourselves */
+        M3GPixelFormat format = ctx->target.format;
+        M3Gint width = ctx->clip.x1 - ctx->clip.x0;
+        M3Gint height = ctx->clip.y1 - ctx->clip.y0;
+        M3Gint xOffset = ctx->clip.x0;
+        M3Gint yOffset = ctx->clip.y0;
+        M3Gint row;
 
-        /* We can only do the fast copy for the full buffer */
+        M3Gubyte *dst;
+        M3Gsizei stride;
+        M3Gubyte *temp;
 
-        M3Gbool fullClip = (ctx->clip.x0 == 0)
-            && (ctx->clip.y0 <= ctx->target.height - ctx->display.height)
-            && (ctx->clip.x1 >= ctx->display.width)
-            && (ctx->clip.y1 >= ctx->clip.y0 + ctx->display.height);
-        
-        if (!fullClip || !eglCopyBuffers(eglGetDisplay(EGL_DEFAULT_DISPLAY),
-                                         ctx->backBuffer.glSurface,
-                                         (NativePixmapType) ctx->target.handle)) {
+        if (ctx->target.type == SURFACE_BITMAP) {
+            /* We must copy the back buffer to a native bitmap: first
+             * attempt a fast buffer-to-buffer copy using EGL, but if that
+             * fails, obtain a pointer and do the copy ourselves */
+
+            /* We can only do the fast copy for the full buffer */
+
+            M3Gbool fullClip = (ctx->clip.x0 == 0)
+                && (ctx->clip.y0 <= ctx->target.height - ctx->display.height)
+                && (ctx->clip.x1 >= ctx->display.width)
+                && (ctx->clip.y1 >= ctx->clip.y0 + ctx->display.height);
+            
+            if (fullClip && eglCopyBuffers(eglGetDisplay(EGL_DEFAULT_DISPLAY),
+                                             ctx->backBuffer.glSurface,
+                                             (NativePixmapType) ctx->target.handle)) 
+            {
+                return;
+            }
             
             /* Fast copy failed, try the generic approach */
-
-            M3Gubyte *dst;
-            M3Gsizei stride;
-            
-            if (m3gglLockNativeBitmap((M3GNativeBitmap) ctx->target.handle,
+            if (!m3gglLockNativeBitmap((M3GNativeBitmap) ctx->target.handle,
                                       &dst, &stride)) {
-                
-                /* OK, got the pointer; now, copy a scanline at a
-                 * time, and we can pretty much assume conversion
-                 * since the fast method didn't work */
-
-                M3GPixelFormat format = ctx->target.format;
-                M3Gint width = ctx->clip.x1 - ctx->clip.x0;
-                M3Gint height = ctx->clip.y1 - ctx->clip.y0;
-                M3Gint xOffset = ctx->clip.x0;
-                M3Gint yOffset = ctx->clip.y0;
-                M3Gint row;
-
-                M3Gubyte *temp = m3gAllocTemp(M3G_INTERFACE(ctx), width * 4);
-                if (!temp) {
-                    return; /* out of memory */
-                }
-
-                dst += (ctx->target.height - (yOffset + height)) * stride
-                    + xOffset * m3gBytesPerPixel(format);
-                
-                for (row = 0; row < height; ++row) {
-                    glReadPixels(xOffset, yOffset + height - row - 1,
-                                 width, 1,
-                                 GL_RGBA, GL_UNSIGNED_BYTE,
-                                 temp);
-                    m3gConvertPixels(M3G_RGBA8, temp, format, dst, width);
-                    dst += stride;
-                }
-                m3gFreeTemp(M3G_INTERFACE(ctx));
-                
-                m3gglReleaseNativeBitmap((M3GNativeBitmap) ctx->target.handle);
-            }
-            else {
                 /* No dice! There's no way that we know of to copy the
                  * data between the buffers */
                 M3G_ASSERT(M3G_FALSE);
             }
+        } else {
+            /* Memory target */
+            dst = ctx->target.pixels;
+            stride = ctx->target.stride;
+        }
+                
+        /* OK, got the pointer; now, copy a scanline at a
+         * time, and we can pretty much assume conversion
+         * since the fast method didn't work */
+
+        temp = m3gAllocTemp(M3G_INTERFACE(ctx), width * 4);
+        if (!temp) {
+            return; /* out of memory */
+        }
+
+        dst += (ctx->target.height - (yOffset + height)) * stride
+            + xOffset * m3gBytesPerPixel(format);
+        
+        for (row = 0; row < height; ++row) {
+            glReadPixels(xOffset, yOffset + height - row - 1,
+                         width, 1,
+                         GL_RGBA, GL_UNSIGNED_BYTE,
+                         temp);
+            m3gConvertPixels(M3G_RGBA8, temp, format, dst, width);
+            dst += stride;
+        }
+        m3gFreeTemp(M3G_INTERFACE(ctx));
+
+        if (ctx->target.type == SURFACE_BITMAP) {
+            m3gglReleaseNativeBitmap((M3GNativeBitmap) ctx->target.handle);
         }
     }
     else {
@@ -1102,24 +1155,25 @@
          * done in this order so that we don't lose any shared texture
          * objects when deleting a context. */
 
-        if (surfaceTypeBits == SURFACE_EGL) {
+        //if (surfaceTypeBits == SURFACE_EGL) 
+        {
             EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
             EGLint configID;
             eglQuerySurface(dpy,
-                            (EGLSurface) ctx->target.handle,
+                            surface,//(EGLSurface) ctx->target.handle,
                             EGL_CONFIG_ID,
                             &configID);
             glrc = eglCreateContext(dpy, (EGLConfig) configID, shareRc, NULL);
-            M3G_ASSERT(glrc);
+            //M3G_ASSERT(glrc);
         }
-        else {
+        /*else {
             glrc = m3gCreateGLContext(format,
                                       bufferBits,
                                       surfaceTypeBits,
                                       shareRc,
                                       &lru->surfaceTypeBits);
         }
-        
+        */
         if (!glrc) {
             m3gRaiseError(M3G_INTERFACE(ctx), M3G_OUT_OF_MEMORY);
             return NULL;
@@ -1181,9 +1235,13 @@
     for (i = 0; i < M3G_MAX_GL_SURFACES; ++i) {
         GLSurfaceRecord *surf = &ctx->glSurface[i];
         
-        if (surf->type == ctx->target.type
-            && surf->targetHandle == ctx->target.handle
-            && (ctx->bufferBits & surf->bufferBits) == ctx->bufferBits) {
+        if ((surf->type == ctx->target.type)
+            && (surf->targetHandle == ctx->target.handle)
+            && ((ctx->bufferBits & surf->bufferBits) == ctx->bufferBits)
+            && (surf->width == ctx->target.width)
+            && (surf->height == ctx->target.height)
+            && (surf->format == ctx->target.format)
+            && (surf->pixels == ctx->target.pixels)) {
             
             surf->lastUseTime = ctx->cacheTimeStamp;
             return surf->handle;
@@ -1241,6 +1299,10 @@
             lru->type         = ctx->target.type;
             lru->targetHandle = ctx->target.handle;
             lru->bufferBits   = ctx->bufferBits;
+            lru->width        = ctx->target.width;
+            lru->height       = ctx->target.height;
+            lru->format       = ctx->target.format;
+            lru->pixels       = ctx->target.pixels;
             lru->lastUseTime  = ctx->cacheTimeStamp;
             return lru->handle;
         }
@@ -1302,6 +1364,8 @@
  */
 static void m3gMakeGLCurrent(RenderContext *ctx)
 {
+    eglBindAPI(EGL_OPENGL_ES_API);
+
     if (ctx != NULL) {
         EGLContext eglCtx = NULL;
         if (ctx->target.buffered) {
@@ -1357,13 +1421,13 @@
                          M3GNativeBitmap hBitmap)
 {
     M3GPixelFormat format;
-    M3Gint width, height;
+    M3Gint width, height, pixels;
     RenderContext *ctx = (RenderContext *) hCtx;
     M3G_VALIDATE_OBJECT(ctx);
     
     M3G_LOG1(M3G_LOG_RENDERING, "Binding bitmap 0x%08X\n", (unsigned) hBitmap);
     
-    if (!m3gglGetNativeBitmapParams(hBitmap, &format, &width, &height)) {
+    if (!m3gglGetNativeBitmapParams(hBitmap, &format, &width, &height, &pixels)) {
         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_OBJECT);
         return;
     }
@@ -1376,7 +1440,10 @@
         return; /* appropriate error raised automatically */
     }
 
-    /* placeholder for bitmap target specific setup */
+    /* Set the bitmap target specific parameters */
+    
+    ctx->target.pixels = (void*)pixels;
+
 }
 
 /*!
@@ -1417,28 +1484,57 @@
 }
 
 /*!
- * \brief Unsupported with OpenGL ES
+ * \brief Binds a new memory rendering target to this rendering
+ * context
+ *
+ * Upon first binding of a specific target, binding the buffer may
+ * require auxiliary data to be allocated, depending on the rendering
+ * modes set for this context. In that case, the binding will be
+ * canceled, and the function will return a non-zero value giving the
+ * number of bytes of additional memory that needs to be supplied for
+ * binding of that target to succeed. The function must then be called
+ * again and a pointer to a sufficient memory block supplied as the \c
+ * mem parameter.
+ *
+ * \param pixels NULL to signal that the frame buffer is accessed
+ * using a callback upon rendering time
  */
-/*@access EGLContext@*/
-M3G_API void m3gBindMemoryTarget(M3GRenderContext context,
-                                 /*@shared@*/ void *pixels,
-                                 M3Guint width, M3Guint height,
-                                 M3GPixelFormat format,
-                                 M3Guint stride,
-                                 M3Guint userHandle)
+/*@access M3GGLContext@*/
+void m3gBindMemoryTarget(M3GRenderContext context,
+                         /*@shared@*/ void *pixels,
+                         M3Guint width, M3Guint height,
+                         M3GPixelFormat format,
+                         M3Guint stride,
+                         M3Guint userHandle)
 {
     RenderContext *ctx = (RenderContext*) context;
     Interface *m3g = M3G_INTERFACE(ctx);
     M3G_VALIDATE_OBJECT(ctx);
 
-    M3G_UNREF(pixels);
-    M3G_UNREF(width);
-    M3G_UNREF(height);
-    M3G_UNREF(format);
-    M3G_UNREF(stride);
-    M3G_UNREF(userHandle);
+    M3G_LOG1(M3G_LOG_RENDERING, "Binding memory buffer 0x%08X\n",
+             (unsigned) pixels);
+    
+    /* Check for bitmap specific errors */
+    
+    if (width == 0 || height == 0 || stride < width) {
+        m3gRaiseError(m3g, M3G_INVALID_VALUE);
+        return; 
+    }
+
+    /* Effect the generic target binding */
     
-    m3gRaiseError(m3g, M3G_INVALID_OPERATION);
+    if (!m3gBindRenderTarget(ctx,
+                             SURFACE_MEMORY,
+                             width, height,
+                             format,
+                             userHandle)) {
+        return; /* appropriate error raised automatically */
+    }
+
+    /* Set the memory target specific parameters */
+    
+    ctx->target.pixels = pixels;
+    ctx->target.stride = stride;
 }
 
 /*!
@@ -1515,3 +1611,24 @@
     
     m3gDeleteGLSurfaces(ctx, (M3Gbitmask) SURFACE_WINDOW, (M3Guint) hWindow);
 }
+
+/*!
+ * \brief Invalidate a previously bound memorytarget
+ *
+ * This should be called prior to deleting a memory buffer that has
+ * been used as an M3G rendering target in the past. 
+ *
+ * \param hCtx    M3G rendering context
+ * \param pixels  pointer to the memory buffer
+ */
+M3G_API void m3gInvalidateMemoryTarget(M3GRenderContext hCtx,
+                                       void *pixels)
+{
+    RenderContext *ctx = (RenderContext *) hCtx;
+    M3G_VALIDATE_OBJECT(ctx);
+
+    M3G_LOG1(M3G_LOG_RENDERING, "Invalidating memory target 0x%08X\n",
+             (unsigned) pixels);
+    
+    m3gDeleteGLSurfaces(ctx, (M3Gbitmask) SURFACE_MEMORY, (M3Guint) pixels);
+}