Fixed problems with OpenGL ES window resizing.
authorMike Gorchak <lestat@i.com.ua>
Thu, 11 Jun 2009 05:57:32 +0000
changeset 3193 64e4442676a6
parent 3192 ec126b077b96
child 3194 c18c03927a77
Fixed problems with OpenGL ES window resizing.
src/video/photon/SDL_photon.c
src/video/photon/SDL_photon.h
--- a/src/video/photon/SDL_photon.c	Wed Jun 10 18:32:42 2009 +0000
+++ b/src/video/photon/SDL_photon.c	Thu Jun 11 05:57:32 2009 +0000
@@ -385,42 +385,42 @@
         status = PgGetGraphicsHWCaps(&hwcaps);
         if (status != 0) {
             PhRect_t extent;
-            PdOffscreenContext_t *curctx;
+            PdOffscreenContext_t* curctx;
 
             /* If error happens, this also could mean, that photon is working */
             /* under custom (not listed by photon) video mode                 */
-            status = PhWindowQueryVisible(Ph_QUERY_GRAPHICS, 0, 0, &extent);
+            status=PhWindowQueryVisible(Ph_QUERY_GRAPHICS, 0, 0, &extent);
             if (status != 0) {
                 SDL_SetError("Photon: Can't get graphics driver region");
                 SDL_free(didata->cursor);
                 SDL_free(didata);
                 return -1;
             }
-            modeinfo.width = extent.lr.x + 1;
-            modeinfo.height = extent.lr.y + 1;
+            modeinfo.width=extent.lr.x+1;
+            modeinfo.height=extent.lr.y+1;
             /* Hardcode 60Hz, as the base refresh rate frequency */
-            hwcaps.current_rrate = 60;
+            hwcaps.current_rrate=60;
             /* Clear current video driver name, no way to get it somehow */
-            hwcaps.chip_name[0] = 0x00;
+            hwcaps.chip_name[0]=0x00;
 
             /* Create offscreen context from video memory, which is currently */
             /* displayed on the screen                                        */
-            curctx = PdCreateOffscreenContext(0, 0, 0, Pg_OSC_MAIN_DISPLAY);
-            if (curctx == NULL) {
+            curctx=PdCreateOffscreenContext(0, 0, 0, Pg_OSC_MAIN_DISPLAY);
+            if (curctx==NULL)
+            {
                 SDL_SetError("Photon: Can't get display area capabilities");
                 SDL_free(didata->cursor);
                 SDL_free(didata);
                 return -1;
             }
             /* Retrieve current bpp */
-            modeinfo.type = curctx->format;
+            modeinfo.type=curctx->format;
             PhDCRelease(curctx);
         } else {
             /* Get current video mode details */
             status = PgGetVideoModeInfo(hwcaps.current_video_mode, &modeinfo);
             if (status != 0) {
-                SDL_SetError
-                    ("Photon: Can't get current video mode information");
+                SDL_SetError("Photon: Can't get current video mode information");
                 SDL_free(didata->cursor);
                 SDL_free(didata);
                 return -1;
@@ -1243,6 +1243,12 @@
 
 #if defined(SDL_VIDEO_OPENGL_ES)
         if (phdata->gfinitialized == SDL_TRUE) {
+            /* Destroy photon handle to GF surface */
+            if (wdata->phsurface != NULL) {
+                PhDCRelease(wdata->phsurface);
+                wdata->phsurface=NULL;
+            }
+
             /* Destroy OpenGL ES surface if it was created */
             if (wdata->gles_surface != EGL_NO_SURFACE) {
                 eglDestroySurface(phdata->egldisplay, wdata->gles_surface);
@@ -1670,13 +1676,22 @@
         return NULL;
     }
 
+    /* Store last used context and surface */
+    phdata->lgles_surface=wdata->gles_surface;
+    phdata->lgles_context=wdata->gles_context;
+
     /* Make just created context current */
     status =
         eglMakeCurrent(phdata->egldisplay, wdata->gles_surface,
                        wdata->gles_surface, wdata->gles_context);
     if (status != EGL_TRUE) {
+        /* Reset last used context and surface */
+        phdata->lgles_surface=EGL_NO_SURFACE;
+        phdata->lgles_context=EGL_NO_CONTEXT;
+
         /* Destroy OpenGL ES surface */
         eglDestroySurface(phdata->egldisplay, wdata->gles_surface);
+        wdata->gles_surface=EGL_NO_SURFACE;
         gf_surface_free(wdata->gfsurface);
         eglDestroyContext(phdata->egldisplay, wdata->gles_context);
         wdata->gles_context = EGL_NO_CONTEXT;
@@ -1739,6 +1754,7 @@
         if (status != 0) {
             /* Destroy OpenGL ES surface */
             eglDestroySurface(phdata->egldisplay, wdata->gles_surface);
+            wdata->gles_surface=EGL_NO_SURFACE;
             gf_surface_free(wdata->gfsurface);
             eglDestroyContext(phdata->egldisplay, wdata->gles_context);
             wdata->gles_context = EGL_NO_CONTEXT;
@@ -1752,6 +1768,7 @@
     if (wdata->phsurface == NULL) {
         /* Destroy OpenGL ES surface */
         eglDestroySurface(phdata->egldisplay, wdata->gles_surface);
+        wdata->gles_surface=EGL_NO_SURFACE;
         gf_surface_free(wdata->gfsurface);
         eglDestroyContext(phdata->egldisplay, wdata->gles_context);
         wdata->gles_context = EGL_NO_CONTEXT;
@@ -1782,12 +1799,17 @@
     }
 
     if ((window == NULL) && (context == NULL)) {
+        /* Reset last used context and surface */
+        phdata->lgles_surface=EGL_NO_SURFACE;
+        phdata->lgles_context=EGL_NO_CONTEXT;
+
+        /* Unset current context */
         status =
             eglMakeCurrent(phdata->egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
                            EGL_NO_CONTEXT);
         if (status != EGL_TRUE) {
             /* Failed to set current GL ES context */
-            SDL_SetError("Photon: Can't set OpenGL ES context");
+            SDL_SetError("Photon: Can't empty current OpenGL ES context");
             return -1;
         }
     } else {
@@ -1807,10 +1829,19 @@
                 ("Photon: OpenGL ES context is not belong to this window");
             return -1;
         }
+
+        /* Store last set surface and context */
+        phdata->lgles_surface=wdata->gles_surface;
+        phdata->lgles_context=wdata->gles_context;
+
+        /* Set new current context */
         status =
             eglMakeCurrent(phdata->egldisplay, wdata->gles_surface,
                            wdata->gles_surface, wdata->gles_context);
         if (status != EGL_TRUE) {
+            /* Reset last used context and surface */
+            phdata->lgles_surface=EGL_NO_SURFACE;
+            phdata->lgles_context=EGL_NO_CONTEXT;
             /* Failed to set current GL ES context */
             SDL_SetError("Photon: Can't set OpenGL ES context");
             return -1;
@@ -1894,6 +1925,12 @@
         return;
     }
 
+    if (wdata->phsurface==NULL) {
+        SDL_SetError
+            ("Photon: Photon OpenGL ES surface is not initialized");
+        return;
+    }
+
     /* Many applications do not uses glFinish(), so we call it for them */
     glFinish();
 
@@ -1945,6 +1982,13 @@
     /* Check if OpenGL ES connection has been initialized */
     if (phdata->egldisplay != EGL_NO_DISPLAY) {
         if (context != EGL_NO_CONTEXT) {
+            /* Check if we are destroying current active context */
+            if (phdata->lgles_context==context) {
+                /* Release current context */
+                eglMakeCurrent(phdata->egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+                phdata->lgles_context=EGL_NO_CONTEXT;
+                phdata->lgles_surface=EGL_NO_SURFACE;
+            }
             status = eglDestroyContext(phdata->egldisplay, context);
             if (status != EGL_TRUE) {
                 /* Error during OpenGL ES context destroying */
@@ -1961,6 +2005,104 @@
 #endif /* SDL_VIDEO_OPENGL_ES */
 }
 
+/* Helper function, which re-creates surface, not an API */
+int photon_gl_recreatesurface(_THIS, SDL_Window * window, uint32_t width, uint32_t height)
+{
+#if defined(SDL_VIDEO_OPENGL_ES)
+    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
+    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
+    SDL_DisplayData *didata =
+        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
+    SDL_bool makecurrent=SDL_FALSE;
+    int32_t gfstatus;
+
+    /* Check if context has been initialized */
+    if (wdata->gles_context == EGL_NO_CONTEXT) {
+        /* If no, abort surface re-creating */
+        return -1;
+    }
+
+    /* Check if last used surface the same as one which must be re-created */
+    if (phdata->lgles_surface == wdata->gles_surface) {
+        makecurrent=SDL_TRUE;
+        /* Flush all current drawings */
+        glFinish();
+        /* Wait until OpenGL ES rendering is completed */
+        eglWaitGL();
+        /* Release current context */
+        eglMakeCurrent(phdata->egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+        phdata->lgles_surface=EGL_NO_SURFACE;
+    }
+
+    /* Check if we need to destroy previous surface */
+    if (wdata->gles_surface != EGL_NO_SURFACE) {
+        /* Destroy photon handle to GF surface */
+        if (wdata->phsurface != NULL) {
+            PhDCRelease(wdata->phsurface);
+            wdata->phsurface=NULL;
+        }
+
+        /* Destroy previous surface */
+        eglDestroySurface(phdata->egldisplay, wdata->gles_surface);
+
+        /* Set surface to uninitialized */
+        wdata->gles_surface = EGL_NO_SURFACE;
+
+        if (wdata->gfsurface!=NULL) {
+           gf_surface_free(wdata->gfsurface);
+           wdata->gfsurface=NULL;
+        }
+    }
+
+    /* Create new GF surface */
+    gfstatus =
+        gf_surface_create(&wdata->gfsurface, phdata->gfdev, width,
+                          height,
+                          qnxgf_sdl_to_gf_pixelformat(didata->current_mode.
+                                                      format), NULL,
+                          GF_SURFACE_CREATE_2D_ACCESSIBLE |
+                          GF_SURFACE_CREATE_3D_ACCESSIBLE |
+                          GF_SURFACE_CREATE_SHAREABLE);
+    if (gfstatus != GF_ERR_OK) {
+        SDL_SetError("Photon: Can't create GF 3D surface (%08X)", gfstatus);
+        return -1;
+    }
+
+    /* Create new pixmap 3D target surface */
+    wdata->gles_surface =
+        eglCreatePixmapSurface(phdata->egldisplay,
+                               wdata->gles_configs[wdata->gles_config],
+                               wdata->gfsurface, NULL);
+    if (wdata->gles_surface == EGL_NO_SURFACE) {
+        gf_surface_free(wdata->gfsurface);
+        wdata->gfsurface=NULL;
+        SDL_SetError("Photon: Can't create EGL pixmap surface");
+        return -1;
+    }
+
+    wdata->phsurface = PdCreateOffscreenContextGF(wdata->gfsurface);
+    if (wdata->phsurface == NULL) {
+        /* Destroy OpenGL ES surface */
+        eglDestroySurface(phdata->egldisplay, wdata->gles_surface);
+        wdata->gles_surface=EGL_NO_SURFACE;
+        gf_surface_free(wdata->gfsurface);
+        wdata->gfsurface=NULL;
+        SDL_SetError("Photon: Can't bind GF surface to Photon\n");
+        return -1;
+    }
+
+    /* Check if we need to set this surface and context as current */
+    if (makecurrent == SDL_TRUE) {
+        return photon_gl_makecurrent(_this, window, wdata->gles_context);
+    } else {
+        return 0;
+    }
+#else
+    /* Do nothing, if OpenGL ES support is not compiled in */
+    return 0;
+#endif /* SDL_VIDEO_OPENGL_ES */
+}
+
 /*****************************************************************************/
 /* SDL Event handling function                                               */
 /*****************************************************************************/
@@ -2519,6 +2661,13 @@
                                                         SDL_WINDOWEVENT_MOVED,
                                                         wmevent->pos.x,
                                                         wmevent->pos.y);
+
+                                    /* Check if this window uses OpenGL ES */
+                                    if (wdata->uses_gles == SDL_TRUE) {
+                                        /* If so, recreate surface with new dimensions */
+                                        photon_gl_recreatesurface(_this, window, wmevent->size.w, wmevent->size.h);
+                                    }
+
                                     /* Set new window size after resize */
                                     SDL_SendWindowEvent(window->id,
                                                         SDL_WINDOWEVENT_RESIZED,
--- a/src/video/photon/SDL_photon.h	Wed Jun 10 18:32:42 2009 +0000
+++ b/src/video/photon/SDL_photon.h	Thu Jun 11 05:57:32 2009 +0000
@@ -55,7 +55,9 @@
     EGLDisplay egldisplay;      /* OpenGL ES display connection         */
     uint32_t egl_refcount;      /* OpenGL ES reference count            */
     uint32_t swapinterval;      /* OpenGL ES default swap interval      */
-#endif                          /* SDL_VIDEO_OPENGL_ES */
+    EGLContext lgles_context;   /* Last used OpenGL ES context          */
+    EGLSurface lgles_surface;   /* Last used OpenGL ES target surface   */
+#endif /* SDL_VIDEO_OPENGL_ES */
 } SDL_VideoData;
 
 /* This is hardcoded value in photon/Pg.h */
@@ -68,18 +70,18 @@
 typedef struct SDL_DisplayData
 {
     uint32_t device_id;
-    uint32_t custom_refresh;    /* Custom refresh rate for all modes  */
+    uint32_t custom_refresh;            /* Custom refresh rate for all modes  */
     SDL_DisplayMode current_mode;       /* Current video mode                 */
     uint8_t description[SDL_VIDEO_PHOTON_DEVICENAME_MAX];
-    /* Device description                 */
-    uint32_t caps;              /* Device capabilities                */
-    PhCursorDef_t *cursor;      /* Global cursor settings             */
-    SDL_bool cursor_visible;    /* SDL_TRUE if cursor visible         */
-    uint32_t cursor_size;       /* Cursor size in memory w/ structure */
+    /* Device description */
+    uint32_t caps;                      /* Device capabilities                */
+    PhCursorDef_t *cursor;              /* Global cursor settings             */
+    SDL_bool cursor_visible;            /* SDL_TRUE if cursor visible         */
+    uint32_t cursor_size;               /* Cursor size in memory w/ structure */
 #if defined(SDL_VIDEO_OPENGL_ES)
-    gf_display_t display;       /* GF display handle                  */
+    gf_display_t display;               /* GF display handle                  */
     gf_display_info_t display_info;     /* GF display information             */
-#endif                          /* SDL_VIDEO_OPENGL_ES */
+#endif /* SDL_VIDEO_OPENGL_ES */
 } SDL_DisplayData;
 
 /* Maximum amount of OpenGL ES framebuffer configurations */
@@ -88,17 +90,17 @@
 typedef struct SDL_WindowData
 {
     SDL_bool uses_gles;         /* if true window must support OpenGL ES */
-    PtWidget_t *window;         /* window handle                        */
+    PtWidget_t *window;         /* window handle                         */
 #if defined(SDL_VIDEO_OPENGL_ES)
     EGLConfig gles_configs[SDL_VIDEO_GF_OPENGLES_CONFS];
-    /* OpenGL ES framebuffer confs        */
-    EGLint gles_config;         /* OpenGL ES configuration index      */
-    EGLContext gles_context;    /* OpenGL ES context                  */
+    /* OpenGL ES framebuffer confs */
+    EGLint gles_config;                 /* OpenGL ES configuration index      */
+    EGLContext gles_context;            /* OpenGL ES context                  */
     EGLint gles_attributes[256];        /* OpenGL ES attributes for context   */
-    EGLSurface gles_surface;    /* OpenGL ES target rendering surface */
-    gf_surface_t gfsurface;     /* OpenGL ES GF's surface             */
+    EGLSurface gles_surface;            /* OpenGL ES target rendering surface */
+    gf_surface_t gfsurface;             /* OpenGL ES GF's surface             */
     PdOffscreenContext_t *phsurface;    /* OpenGL ES Photon's surface         */
-#endif                          /* SDL_VIDEO_OPENGL_ES */
+#endif /* SDL_VIDEO_OPENGL_ES */
 } SDL_WindowData;
 
 /****************************************************************************/
@@ -158,6 +160,9 @@
 void photon_gl_swapwindow(_THIS, SDL_Window * window);
 void photon_gl_deletecontext(_THIS, SDL_GLContext context);
 
+/* Helper function, which re-creates surface, not an API */
+int photon_gl_recreatesurface(_THIS, SDL_Window * window, uint32_t width, uint32_t height);
+
 /* Event handling function */
 void photon_pumpevents(_THIS);