From a433d5c895f807706dbed697604f3029be85d392 Mon Sep 17 00:00:00 2001
From: Roderick Colenbrander <thunderbird2k@gmail.com>
Date: Mon, 16 Nov 2009 23:24:24 +0100
Subject: [PATCH 2/2] Add initial WGL_ARB_create_context support. This is needed for full OpenGL 3.x support.

---
 dlls/gdi32/driver.c               |    1 +
 dlls/gdi32/gdi_private.h          |    1 +
 dlls/gdi32/opengl.c               |   23 ++++++-
 dlls/opengl32/tests/opengl.c      |    2 +-
 dlls/winex11.drv/opengl.c         |  133 ++++++++++++++++++++++++++++++++++++-
 dlls/winex11.drv/winex11.drv.spec |    1 +
 6 files changed, 158 insertions(+), 3 deletions(-)

diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c
index 73c594f..41c59c7 100644
--- a/dlls/gdi32/driver.c
+++ b/dlls/gdi32/driver.c
@@ -198,6 +198,7 @@ static struct graphics_driver *create_driver( HMODULE module )
 
         /* OpenGL32 */
         GET_FUNC(wglCreateContext);
+        GET_FUNC(wglCreateContextAttribsARB);
         GET_FUNC(wglDeleteContext);
         GET_FUNC(wglGetProcAddress);
         GET_FUNC(wglGetPbufferDCARB);
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index ab4cd03..0ee87b6 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -199,6 +199,7 @@ typedef struct tagDC_FUNCS
     /* OpenGL32 */
     BOOL     (CDECL *pwglCopyContext)(HGLRC, HGLRC, UINT);
     HGLRC    (CDECL *pwglCreateContext)(PHYSDEV);
+    HGLRC    (CDECL *pwglCreateContextAttribsARB)(PHYSDEV, HGLRC, const int*);
     BOOL     (CDECL *pwglDeleteContext)(HGLRC);
     PROC     (CDECL *pwglGetProcAddress)(LPCSTR);
     HDC      (CDECL *pwglGetPbufferDCARB)(PHYSDEV, void*);
diff --git a/dlls/gdi32/opengl.c b/dlls/gdi32/opengl.c
index 2317afa..0be4037 100644
--- a/dlls/gdi32/opengl.c
+++ b/dlls/gdi32/opengl.c
@@ -104,6 +104,25 @@ HGLRC WINAPI wglCreateContext(HDC hdc)
     return ret;
 }
 
+/***********************************************************************
+ *      wglCreateContextAttribsARB
+ */
+HGLRC WINAPI wglCreateContextAttribsARB(HDC hdc, HGLRC hShareContext, const int *attributeList)
+{
+    HGLRC ret = 0;
+    DC * dc = get_dc_ptr( hdc );
+
+    TRACE("(%p)\n",hdc);
+
+    if (!dc) return 0;
+
+    update_dc( dc );
+    if (!dc->funcs->pwglCreateContextAttribsARB) FIXME(" :stub\n");
+    else ret = dc->funcs->pwglCreateContextAttribsARB(dc->physDev, hShareContext, attributeList);
+
+    release_dc_ptr( dc );
+    return ret;
+}
 
 /***********************************************************************
  *		wglDeleteContext (OPENGL32.@)
@@ -358,7 +377,9 @@ PROC WINAPI wglGetProcAddress(LPCSTR func)
      * when a non-NULL value is returned by wglGetProcAddress), we return the address
      * of a wrapper function which will handle the HDC->PhysDev conversion.
      */
-    if(ret && strcmp(func, "wglMakeContextCurrentARB") == 0)
+    if(ret && strcmp(func, "wglCreateContextAttribsARB") == 0)
+        return (PROC)wglCreateContextAttribsARB;
+    else if(ret && strcmp(func, "wglMakeContextCurrentARB") == 0)
         return (PROC)wglMakeContextCurrentARB;
     else if(ret && strcmp(func, "wglGetPbufferDCARB") == 0)
         return (PROC)wglGetPbufferDCARB;
diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c
index 5c3de1f..c83f1a0 100644
--- a/dlls/opengl32/tests/opengl.c
+++ b/dlls/opengl32/tests/opengl.c
@@ -591,7 +591,7 @@ static void test_opengl3(HDC hdc)
         HGLRC gl3Ctx;
         DWORD error;
         gl3Ctx = pwglCreateContextAttribsARB(hdc, (HGLRC)0xdeadbeef, 0);
-        ok(gl3Ctx == 0, "pwglCreateContextAttribsARB using an invalid shareList passed\n");
+        todo_wine ok(gl3Ctx == 0, "pwglCreateContextAttribsARB using an invalid shareList passed\n");
         error = GetLastError();
         todo_wine ok(error == ERROR_INVALID_OPERATION, "Expected ERROR_INVALID_OPERATION, got error=%x\n", error);
         wglDeleteContext(gl3Ctx);
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c
index 6277e8a..6961414 100644
--- a/dlls/winex11.drv/opengl.c
+++ b/dlls/winex11.drv/opengl.c
@@ -105,8 +105,11 @@ typedef struct wine_glcontext {
     BOOL do_escape;
     BOOL has_been_current;
     BOOL sharing;
+    BOOL gl3_context;
     XVisualInfo *vis;
     WineGLPixelFormat *fmt;
+    int numAttribs; /* This is needed for delaying wglCreateContextAttribsARB */
+    int attribList[16]; /* This is needed for delaying wglCreateContextAttribsARB */
     GLXContext ctx;
     HDC read_hdc;
     Drawable drawables[2];
@@ -240,6 +243,7 @@ MAKE_FUNCPTR(glXQueryDrawable)
 MAKE_FUNCPTR(glXGetCurrentReadDrawable)
 
 /* GLX Extensions */
+static GLXContext (*pglXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
 static void* (*pglXGetProcAddressARB)(const GLubyte *);
 static int   (*pglXSwapIntervalSGI)(int);
 
@@ -274,6 +278,12 @@ MAKE_FUNCPTR(glFinish)
 MAKE_FUNCPTR(glFlush)
 #undef MAKE_FUNCPTR
 
+static int GLXErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
+{
+    /* In the future we might want to find the exact X or GLX error to report back to the app */
+    return 1;
+}
+
 static BOOL infoInitialized = FALSE;
 static BOOL X11DRV_WineGL_InitOpenglInfo(void)
 {
@@ -442,6 +452,8 @@ static BOOL has_opengl(void)
    the associated extension is available (and if a driver reports the extension
    is available but fails to provide the functions, it's quite broken) */
 #define LOAD_FUNCPTR(f) p##f = (void*)pglXGetProcAddressARB((const unsigned char*)#f)
+    /* ARB GLX Extension */
+    LOAD_FUNCPTR(glXCreateContextAttribsARB);
     /* NV GLX Extension */
     LOAD_FUNCPTR(glXAllocateMemoryNV);
     LOAD_FUNCPTR(glXFreeMemoryNV);
@@ -1066,7 +1078,14 @@ static GLXContext create_glxcontext(Display *display, Wine_GLContext *context, G
     /* We use indirect rendering for rendering to bitmaps. See get_formats for a comment about this. */
     BOOL indirect = (context->fmt->dwFlags & PFD_DRAW_TO_BITMAP) ? FALSE : TRUE;
 
-    if(context->vis)
+    if(context->gl3_context) 
+    { 
+        if(context->numAttribs) 
+            ctx = pglXCreateContextAttribsARB(gdi_display, context->fmt->fbconfig, shareList, indirect, context->attribList); 
+        else 
+            ctx = pglXCreateContextAttribsARB(gdi_display, context->fmt->fbconfig, shareList, indirect, NULL); 
+    }
+    else if(context->vis)
         ctx = pglXCreateContext(gdi_display, context->vis, shareList, indirect);
     else /* Create a GLX Context for a pbuffer */
         ctx = pglXCreateNewContext(gdi_display, context->fmt->fbconfig, context->fmt->render_type, shareList, TRUE);
@@ -2172,6 +2191,94 @@ static void WINAPI X11DRV_wglFlush(void)
 }
 
 /**
+ * X11DRV_wglCreateContextAttribsARB
+ *
+ * WGL_ARB_create_context: wglCreateContextAttribsARB
+ */
+HGLRC X11DRV_wglCreateContextAttribsARB(X11DRV_PDEVICE *physDev, HGLRC hShareContext, const int* attribList)
+{
+    Wine_GLContext *ret;
+    WineGLPixelFormat *fmt;
+    int hdcPF = physDev->current_pf;
+    int fmt_count = 0;
+
+    TRACE("(%p %p %p)\n", physDev, hShareContext, attribList);
+
+    if (!has_opengl()) return 0;
+
+    fmt = ConvertPixelFormatWGLtoGLX(gdi_display, hdcPF, TRUE /* Offscreen */, &fmt_count);
+    /* wglCreateContextAttribsARB supports ALL pixel formats, so also offscreen ones.
+     * If this fails something is very wrong on the system. */
+    if(!fmt)
+    {
+        ERR("Cannot get FB Config for iPixelFormat %d, expect problems!\n", hdcPF);
+        SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+        return NULL;
+    }
+
+    wine_tsx11_lock();
+    ret = alloc_context();
+    wine_tsx11_unlock();
+    ret->hdc = physDev->hdc;
+    ret->fmt = fmt;
+    ret->vis = NULL; /* glXCreateContextAttribsARB requires a fbconfig instead of a visual */
+    ret->gl3_context = TRUE;
+
+    ret->numAttribs = 0;
+    if(attribList)
+    {
+        int *pAttribList = (int*)attribList;
+        int *pContextAttribList = &ret->attribList[0];
+        /* attribList consists of pairs {token, value] terminated with 0 */
+        while(pAttribList[0] != 0)
+        {
+            TRACE("%#x %#x\n", pAttribList[0], pAttribList[1]);
+            switch(pAttribList[0])
+            {
+                case WGL_CONTEXT_MAJOR_VERSION_ARB:
+                    pContextAttribList[0] = GLX_CONTEXT_MAJOR_VERSION_ARB;
+                    pContextAttribList[1] = pAttribList[1];
+                    break;
+                case WGL_CONTEXT_MINOR_VERSION_ARB:
+                    pContextAttribList[0] = GLX_CONTEXT_MINOR_VERSION_ARB;
+                    pContextAttribList[1] = pAttribList[1];
+                    break;
+                case WGL_CONTEXT_LAYER_PLANE_ARB:
+                    break;
+                case WGL_CONTEXT_FLAGS_ARB:
+                    pContextAttribList[0] = GLX_CONTEXT_FLAGS_ARB;
+                    pContextAttribList[1] = pAttribList[1];
+                    break;
+                default:
+                    ERR("Unhandled attribList pair: %#x %#x\n", pAttribList[0], pAttribList[1]);
+            }
+
+            ret->numAttribs++;
+            pAttribList += 2;
+            pContextAttribList += 2;
+        }
+    }
+
+    wine_tsx11_lock();
+    X11DRV_expect_error(gdi_display, GLXErrorHandler, NULL);
+    ret->ctx = create_glxcontext(gdi_display, ret, NULL);
+
+    XSync(gdi_display, False);
+    if(X11DRV_check_error() || !ret->ctx)
+    {
+        /* In the future we should convert the GLX error to a win32 one here if needed */
+        ERR("Context creation failed\n");
+        free_context(ret);
+        wine_tsx11_unlock();
+        return NULL;
+    }
+
+    wine_tsx11_unlock();
+    TRACE(" creating context %p\n", ret);
+    return (HGLRC) ret;
+}
+
+/**
  * X11DRV_wglGetExtensionsStringARB
  *
  * WGL_ARB_extensions_string: wglGetExtensionsStringARB
@@ -3322,6 +3429,14 @@ static const WineGLExtension WGL_internal_functions =
 };
 
 
+static const WineGLExtension WGL_ARB_create_context =
+{
+  "WGL_ARB_create_context",
+  {
+    { "wglCreateContextAttribsARB", X11DRV_wglCreateContextAttribsARB },
+  }
+};
+
 static const WineGLExtension WGL_ARB_extensions_string =
 {
   "WGL_ARB_extensions_string",
@@ -3422,6 +3537,11 @@ static void X11DRV_WineGL_LoadExtensions(void)
 
     /* ARB Extensions */
 
+    if(glxRequireExtension("GLX_ARB_create_context"))
+    {
+        register_extension(&WGL_ARB_create_context);
+    }
+
     if(glxRequireExtension("GLX_ARB_fbconfig_float"))
     {
         register_extension_string("WGL_ARB_pixel_format_float");
@@ -3694,6 +3814,17 @@ HGLRC CDECL X11DRV_wglCreateContext(X11DRV_PDEVICE *physDev) {
 }
 
 /**
+ * X11DRV_wglCreateContextAttribsARB
+ *
+ * WGL_ARB_create_context: wglCreateContextAttribsARB
+ */
+HGLRC X11DRV_wglCreateContextAttribsARB(X11DRV_PDEVICE *physDev, HGLRC hShareContext, const int* attribList)
+{
+    opengl_error();
+    return NULL;
+}
+
+/**
  * X11DRV_wglDeleteContext
  *
  * For OpenGL32 wglDeleteContext.
diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec
index 4993d9a..27f2fb3 100644
--- a/dlls/winex11.drv/winex11.drv.spec
+++ b/dlls/winex11.drv/winex11.drv.spec
@@ -133,6 +133,7 @@
 # OpenGL
 @ cdecl wglCopyContext(long long long) X11DRV_wglCopyContext
 @ cdecl wglCreateContext(ptr) X11DRV_wglCreateContext
+@ cdecl wglCreateContextAttribsARB(ptr long ptr) X11DRV_wglCreateContextAttribsARB
 @ cdecl wglDeleteContext(long) X11DRV_wglDeleteContext
 @ cdecl wglGetProcAddress(str) X11DRV_wglGetProcAddress
 @ cdecl wglGetPbufferDCARB(ptr ptr) X11DRV_wglGetPbufferDCARB
-- 
1.6.3.3

