st/wgl: fix implementation of wglCreateContextAttribsARB()
authorBrian Paul <brianp@vmware.com>
Tue, 20 May 2014 20:56:41 +0000 (14:56 -0600)
committerJosé Fonseca <jfonseca@vmware.com>
Fri, 30 May 2014 17:52:39 +0000 (18:52 +0100)
wglCreateContextAttribsARB() didn't work previously since it returned
a context ID that wasn't allocated by OPENGL32.DLL.  So if that context
ID was later passed to wglMakeCurrent(), etc. it was rejected.

Now when wglCreateContextAttribsARB() is called we actually call
wglCreateContext() in order to get a valid context ID.  Then we
replace the context data which was created with new context data
which reflects the arguments passed to wglCreateContextAttribsARB().

If there were a DrvCreateContextAttribs() function in the ICD this
work-around wouldn't be necessary.

Reviewed-by: Charmaine Lee <charmainel@vmware.com>
Conflicts:
src/gallium/state_trackers/wgl/stw_ext_extensionsstring.c
src/gallium/state_trackers/wgl/stw_getprocaddress.c

src/gallium/state_trackers/wgl/stw_context.c
src/gallium/state_trackers/wgl/stw_context.h
src/gallium/state_trackers/wgl/stw_ext_context.c

index 43186fa2690e230f4c6a7f1eba9cb7a68325cb7f..99debfddadc7380e049dd6d1563eeadd491e98fb 100644 (file)
@@ -128,16 +128,23 @@ DrvCreateLayerContext(
    INT iLayerPlane )
 {
    return stw_create_context_attribs(hdc, iLayerPlane, 0, 1, 0, 0,
-                                     WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
+                                     WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
+                                     0);
 }
 
+
+/**
+ * Called via DrvCreateContext(), DrvCreateLayerContext() and
+ * wglCreateContextAttribsARB() to actually create a rendering context.
+ * \param handle  the desired DHGLRC handle to use for the context, or zero
+ *                if a new handle should be allocated.
+ * \return the handle for the new context or zero if there was a problem.
+ */
 DHGLRC
-stw_create_context_attribs(
-   HDC hdc,
-   INT iLayerPlane,
-   DHGLRC hShareContext,
-   int majorVersion, int minorVersion,
-   int contextFlags, int profileMask)
+stw_create_context_attribs(HDC hdc, INT iLayerPlane, DHGLRC hShareContext,
+                           int majorVersion, int minorVersion,
+                           int contextFlags, int profileMask,
+                           DHGLRC handle)
 {
    int iPixelFormat;
    struct stw_framebuffer *fb;
@@ -236,7 +243,31 @@ stw_create_context_attribs(
    }
 
    pipe_mutex_lock( stw_dev->ctx_mutex );
-   ctx->dhglrc = handle_table_add(stw_dev->ctx_table, ctx);
+   if (handle) {
+      /* We're replacing the context data for this handle. See the
+       * wglCreateContextAttribsARB() function.
+       */
+      struct stw_context *old_ctx =
+         stw_lookup_context_locked((unsigned) handle);
+      if (old_ctx) {
+         /* free the old context data associated with this handle */
+         if (old_ctx->hud) {
+            hud_destroy(old_ctx->hud);
+         }
+         ctx->st->destroy(old_ctx->st);
+         FREE(old_ctx);
+      }
+
+      /* replace table entry */
+      handle_table_set(stw_dev->ctx_table, (unsigned) handle, ctx);
+   }
+   else {
+      /* create new table entry */
+      handle = (DHGLRC) handle_table_add(stw_dev->ctx_table, ctx);
+   }
+
+   ctx->dhglrc = handle;
+
    pipe_mutex_unlock( stw_dev->ctx_mutex );
    if (!ctx->dhglrc)
       goto no_hglrc;
index e03ceb806e678560fbbffa79a867a18f25edf65a..c66c166de2e767fcb0b629e8d9476c7ea51169c4 100644 (file)
@@ -46,8 +46,11 @@ struct stw_context
    struct hud_context *hud;
 };
 
-DHGLRC stw_create_context_attribs( HDC hdc, INT iLayerPlane, DHGLRC hShareContext,
-                                   int majorVersion, int minorVersion, int contextFlags, int profileMask );
+DHGLRC stw_create_context_attribs(HDC hdc, INT iLayerPlane,
+                                  DHGLRC hShareContext,
+                                  int majorVersion, int minorVersion,
+                                  int contextFlags, int profileMask,
+                                  DHGLRC handle);
 
 DHGLRC stw_get_current_context( void );
 
index 4dd00bb4f94d1c734a9f07994e4b1e6085265241..0049896b8df351647a4bb70bdf556269c1954772 100644 (file)
@@ -22,6 +22,8 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <stdio.h>
+#include <assert.h>
 #include <windows.h>
 
 #define WGL_WGLEXT_PROTOTYPES
 
 #include "stw_icd.h"
 #include "stw_context.h"
+#include "stw_device.h"
 
+
+/**
+ * The implementation of this function is tricky.  The OPENGL32.DLL library
+ * remaps the context IDs returned by our stw_create_context_attribs()
+ * function to different values returned to the caller of wglCreateContext().
+ * That is, DHGLRC (driver) handles are not equivalent to HGLRC (public)
+ * handles.
+ *
+ * So we need to generate a new HGLRC ID here.  We do that by calling
+ * the regular wglCreateContext() function.  Then, we replace the newly-
+ * created stw_context with a new stw_context that reflects the arguments
+ * to this function.
+ */
 HGLRC WINAPI
 wglCreateContextAttribsARB(HDC hDC, HGLRC hShareContext, const int *attribList)
 {
+   typedef HGLRC (*wglCreateContext_t)(HDC hdc);
+   typedef BOOL (*wglDeleteContext_t)(HGLRC hglrc);
+   HGLRC context;
+   static HMODULE opengl_lib = 0;
+   static wglCreateContext_t wglCreateContext_func = 0;
+   static wglDeleteContext_t wglDeleteContext_func = 0;
+
    int majorVersion = 1, minorVersion = 0, layerPlane = 0;
    int contextFlags = 0x0;
    int profileMask = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
@@ -67,7 +90,7 @@ wglCreateContextAttribsARB(HDC hDC, HGLRC hShareContext, const int *attribList)
          default:
             /* bad attribute */
             SetLastError(ERROR_INVALID_PARAMETER);
-            return NULL;
+            return 0;
          }
       }
    }
@@ -77,46 +100,103 @@ wglCreateContextAttribsARB(HDC hDC, HGLRC hShareContext, const int *attribList)
    case 1:
       if (minorVersion < 0 || minorVersion > 5) {
          SetLastError(ERROR_INVALID_VERSION_ARB);
-         return NULL;
+         return 0;
       }
       break;
    case 2:
       if (minorVersion < 0 || minorVersion > 1) {
          SetLastError(ERROR_INVALID_VERSION_ARB);
-         return NULL;
+         return 0;
       }
       break;
    case 3:
       if (minorVersion < 0 || minorVersion > 3) {
          SetLastError(ERROR_INVALID_VERSION_ARB);
-         return NULL;
+         return 0;
       }
       break;
    case 4:
       if (minorVersion < 0 || minorVersion > 2) {
          SetLastError(ERROR_INVALID_VERSION_ARB);
-         return NULL;
+         return 0;
       }
       break;
    default:
-      return NULL;
+      return 0;
    }
 
    if ((contextFlags & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB) &&
        majorVersion < 3) {
       SetLastError(ERROR_INVALID_VERSION_ARB);
-      return NULL;
+      return 0;
    }
 
    /* check profileMask */
    if (profileMask != WGL_CONTEXT_CORE_PROFILE_BIT_ARB &&
        profileMask != WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB) {
       SetLastError(ERROR_INVALID_PROFILE_ARB);
-      return NULL;
+      return 0;
+   }
+
+   /* Get pointer to OPENGL32.DLL's wglCreate/DeleteContext() functions */
+   if (opengl_lib == 0) {
+      /* Open the OPENGL32.DLL library */
+      opengl_lib = LoadLibraryA("OPENGL32.DLL");
+      if (!opengl_lib) {
+         fprintf(stderr, "wgl: LoadLibrary(OPENGL32.DLL) failed\n");
+         fflush(stderr);
+         return 0;
+      }
+
+      /* Get pointer to wglCreateContext() function */
+      wglCreateContext_func = (wglCreateContext_t)
+         GetProcAddress(opengl_lib, "wglCreateContext");
+      if (!wglCreateContext_func) {
+         fprintf(stderr, "wgl: failed to get wglCreateContext()\n");
+         fflush(stderr);
+         return 0;
+      }
+
+      /* Get pointer to wglDeleteContext() function */
+      wglDeleteContext_func = (wglDeleteContext_t)
+         GetProcAddress(opengl_lib, "wglDeleteContext");
+      if (!wglDeleteContext_func) {
+         fprintf(stderr, "wgl: failed to get wglDeleteContext()\n");
+         fflush(stderr);
+         return 0;
+      }
+   }
+
+   /* Call wglCreateContext to get a valid context ID */
+   context = wglCreateContext_func(hDC);
+
+   if (context) {
+      /* Now replace the context we just created with a new one that reflects
+       * the attributes passed to this function.
+       */
+      DHGLRC dhglrc, c, share_dhglrc = 0;
+
+      /* Convert public HGLRC to driver DHGLRC */
+      if (stw_dev && stw_dev->callbacks.wglCbGetDhglrc) {
+         dhglrc = stw_dev->callbacks.wglCbGetDhglrc(context);
+         if (hShareContext)
+            share_dhglrc = stw_dev->callbacks.wglCbGetDhglrc(hShareContext);
+      }
+      else {
+         /* not using ICD */
+         dhglrc = (DHGLRC) context;
+         share_dhglrc = (DHGLRC) hShareContext;
+      }
+
+      c = stw_create_context_attribs(hDC, layerPlane, share_dhglrc,
+                                     majorVersion, minorVersion,
+                                     contextFlags, profileMask,
+                                     dhglrc);
+      if (!c) {
+         wglDeleteContext_func(context);
+         context = 0;
+      }
    }
 
-   return (HGLRC) stw_create_context_attribs(hDC, layerPlane,
-                                             (DHGLRC) (UINT_PTR) hShareContext,
-                                             majorVersion, minorVersion,
-                                             contextFlags, profileMask);
+   return context;
 }