summaryrefslogtreecommitdiffstats
path: root/src/glx/windows/windowsgl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glx/windows/windowsgl.c')
-rw-r--r--src/glx/windows/windowsgl.c403
1 files changed, 403 insertions, 0 deletions
diff --git a/src/glx/windows/windowsgl.c b/src/glx/windows/windowsgl.c
new file mode 100644
index 00000000000..56849da8371
--- /dev/null
+++ b/src/glx/windows/windowsgl.c
@@ -0,0 +1,403 @@
+/*
+ * Copyright © 2014 Jon Turney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "windowsgl.h"
+#include "windowsgl_internal.h"
+
+#include "glapi.h"
+#include "wgl.h"
+
+#include <dlfcn.h>
+#include <assert.h>
+#include <stdio.h>
+#include <strings.h>
+
+static struct _glapi_table *windows_api = NULL;
+
+static void *
+windows_get_dl_handle(void)
+{
+ static void *dl_handle = NULL;
+
+ if (!dl_handle)
+ dl_handle = dlopen("cygnativeGLthunk.dll", RTLD_NOW);
+
+ return dl_handle;
+}
+
+static void
+windows_glapi_create_table(void)
+{
+ if (windows_api)
+ return;
+
+ windows_api = _glapi_create_table_from_handle(windows_get_dl_handle(), "gl");
+ assert(windows_api);
+}
+
+static void windows_glapi_set_dispatch(void)
+{
+ windows_glapi_create_table();
+ _glapi_set_dispatch(windows_api);
+}
+
+windowsContext *
+windows_create_context(int pxfi, windowsContext *shared)
+{
+ windowsContext *gc;
+
+ gc = calloc(1, sizeof *gc);
+ if (gc == NULL)
+ return NULL;
+
+ // create a temporary, invisible window
+#define GL_TEMP_WINDOW_CLASS "glTempWndClass"
+ {
+ static wATOM glTempWndClass = 0;
+
+ if (glTempWndClass == 0) {
+ WNDCLASSEX wc;
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = DefWindowProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = 0;
+ wc.hCursor = 0;
+ wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = GL_TEMP_WINDOW_CLASS;
+ wc.hIconSm = 0;
+ RegisterClassEx(&wc);
+ }
+ }
+
+ HWND hwnd = CreateWindowExA(0,
+ GL_TEMP_WINDOW_CLASS,
+ "glWindow",
+ 0,
+ 0, 0, 0, 0,
+ NULL, NULL, GetModuleHandle(NULL), NULL);
+ HDC hdc = GetDC(hwnd);
+
+ // We must set the windows pixel format before we can create a WGL context
+ gc->pxfi = pxfi;
+ SetPixelFormat(hdc, gc->pxfi, NULL);
+
+ gc->ctx = wglCreateContext(hdc);
+
+ if (shared && gc->ctx)
+ wglShareLists(shared->ctx, gc->ctx);
+
+ ReleaseDC(hwnd, hdc);
+ DestroyWindow(hwnd);
+
+ if (!gc->ctx)
+ {
+ free(gc);
+ return NULL;
+ }
+
+ return gc;
+}
+
+windowsContext *
+windows_create_context_attribs(int pxfi, windowsContext *shared, const int *attribList)
+{
+ windowsContext *gc;
+
+ gc = calloc(1, sizeof *gc);
+ if (gc == NULL)
+ return NULL;
+
+ // create a temporary, invisible window
+#define GL_TEMP_WINDOW_CLASS "glTempWndClass"
+ {
+ static wATOM glTempWndClass = 0;
+
+ if (glTempWndClass == 0) {
+ WNDCLASSEX wc;
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = DefWindowProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = 0;
+ wc.hCursor = 0;
+ wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = GL_TEMP_WINDOW_CLASS;
+ wc.hIconSm = 0;
+ RegisterClassEx(&wc);
+ }
+ }
+
+ HWND hwnd = CreateWindowExA(0,
+ GL_TEMP_WINDOW_CLASS,
+ "glWindow",
+ 0,
+ 0, 0, 0, 0,
+ NULL, NULL, GetModuleHandle(NULL), NULL);
+ HDC hdc = GetDC(hwnd);
+ HGLRC shareContext = NULL;
+ if (shared)
+ shareContext = shared->ctx;
+
+ // We must set the windows pixel format before we can create a WGL context
+ gc->pxfi = pxfi;
+ SetPixelFormat(hdc, gc->pxfi, NULL);
+
+ gc->ctx = wglCreateContextAttribsARB(hdc, shareContext, attribList);
+
+ ReleaseDC(hwnd, hdc);
+ DestroyWindow(hwnd);
+
+ if (!gc->ctx)
+ {
+ free(gc);
+ return NULL;
+ }
+
+ return gc;
+}
+
+void
+windows_destroy_context(windowsContext *context)
+{
+ wglDeleteContext(context->ctx);
+ context->ctx = NULL;
+ free(context);
+}
+
+int windows_bind_context(windowsContext *context, windowsDrawable *draw, windowsDrawable *read)
+{
+ HDC drawDc = draw->callbacks->getdc(draw);
+
+ if (!draw->pxfi)
+ {
+ SetPixelFormat(drawDc, context->pxfi, NULL);
+ draw->pxfi = context->pxfi;
+ }
+
+ if ((read != NULL) && (read != draw))
+ {
+ /*
+ If there is a separate read drawable, create a separate read DC, and
+ use the wglMakeContextCurrent extension to make the context current
+ drawing to one DC and reading from the other
+
+ Should only occur when WGL_ARB_make_current_read extension is present
+ */
+ HDC readDc = read->callbacks->getdc(read);
+
+ BOOL ret = wglMakeContextCurrentARB(drawDc, readDc, context->ctx);
+
+ read->callbacks->releasedc(read, readDc);
+
+ if (!ret) {
+ printf("wglMakeContextCurrentARB error: %08x\n", GetLastError());
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* Otherwise, just use wglMakeCurrent */
+ BOOL ret = wglMakeCurrent(drawDc, context->ctx);
+ if (!ret) {
+ printf("wglMakeCurrent error: %08x\n", GetLastError());
+ return FALSE;
+ }
+ }
+
+ draw->callbacks->releasedc(draw, drawDc);
+
+ windows_glapi_set_dispatch();
+
+ return TRUE;
+}
+
+void windows_unbind_context(windowsContext * context)
+{
+ wglMakeCurrent(NULL, NULL);
+}
+
+/*
+ *
+ */
+
+void
+windows_swap_buffers(windowsDrawable *draw)
+{
+ HDC drawDc = GetDC(draw->hWnd);
+ SwapBuffers(drawDc);
+ ReleaseDC(draw->hWnd, drawDc);
+}
+
+
+typedef void (__stdcall * PFNGLADDSWAPHINTRECTWIN) (GLint x, GLint y,
+ GLsizei width,
+ GLsizei height);
+
+static void
+glAddSwapHintRectWIN(GLint x, GLint y, GLsizei width,
+ GLsizei height)
+{
+ PFNGLADDSWAPHINTRECTWIN proc = (PFNGLADDSWAPHINTRECTWIN)wglGetProcAddress("glAddSwapHintRectWIN");
+ if (proc)
+ proc(x, y, width, height);
+}
+
+void
+windows_copy_subbuffer(windowsDrawable *draw,
+ int x, int y, int width, int height)
+{
+ glAddSwapHintRectWIN(x, y, width, height);
+ windows_swap_buffers(draw);
+}
+
+/*
+ * Helper function for calling a test function on an initial context
+ */
+static void
+windows_call_with_context(void (*proc)(HDC, void *), void *args)
+{
+ // create window class
+#define WIN_GL_TEST_WINDOW_CLASS "GLTest"
+ {
+ static wATOM glTestWndClass = 0;
+
+ if (glTestWndClass == 0) {
+ WNDCLASSEX wc;
+
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = DefWindowProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = 0;
+ wc.hCursor = 0;
+ wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = WIN_GL_TEST_WINDOW_CLASS;
+ wc.hIconSm = 0;
+ glTestWndClass = RegisterClassEx(&wc);
+ }
+ }
+
+ // create an invisible window for a scratch DC
+ HWND hwnd = CreateWindowExA(0,
+ WIN_GL_TEST_WINDOW_CLASS,
+ "GL Renderer Capabilities Test Window",
+ 0, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL),
+ NULL);
+ if (hwnd) {
+ HDC hdc = GetDC(hwnd);
+
+ // we must set a pixel format before we can create a context, just use the first one...
+ SetPixelFormat(hdc, 1, NULL);
+ HGLRC hglrc = wglCreateContext(hdc);
+ wglMakeCurrent(hdc, hglrc);
+
+ // call the test function
+ proc(hdc, args);
+
+ // clean up
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(hglrc);
+ ReleaseDC(hwnd, hdc);
+ DestroyWindow(hwnd);
+ }
+}
+
+static void
+windows_check_render_test(HDC hdc, void *args)
+{
+ int *result = (int *)args;
+
+ /* Rather than play linkage games using stdcall to ensure we get
+ glGetString from opengl32.dll here, use dlsym */
+ void *dlhandle = windows_get_dl_handle();
+ const char *(*proc)(int) = dlsym(dlhandle, "glGetString");
+ const char *gl_renderer = (const char *)proc(GL_RENDERER);
+
+ if ((!gl_renderer) || (strcasecmp(gl_renderer, "GDI Generic") == 0))
+ *result = FALSE;
+ else
+ *result = TRUE;
+}
+
+int
+windows_check_renderer(void)
+{
+ int result;
+ windows_call_with_context(windows_check_render_test, &result);
+ return result;
+}
+
+typedef struct {
+ char *gl_extensions;
+ char *wgl_extensions;
+} windows_extensions_result;
+
+static void
+windows_extensions_test(HDC hdc, void *args)
+{
+ windows_extensions_result *r = (windows_extensions_result *)args;
+
+ void *dlhandle = windows_get_dl_handle();
+ const char *(*proc)(int) = dlsym(dlhandle, "glGetString");
+
+ r->gl_extensions = strdup(proc(GL_EXTENSIONS));
+
+ wglResolveExtensionProcs();
+ r->wgl_extensions = strdup(wglGetExtensionsStringARB(hdc));
+}
+
+void
+windows_extensions(char **gl_extensions, char **wgl_extensions)
+{
+ windows_extensions_result result;
+
+ *gl_extensions = "";
+ *wgl_extensions = "";
+
+ windows_call_with_context(windows_extensions_test, &result);
+
+ *gl_extensions = result.gl_extensions;
+ *wgl_extensions = result.wgl_extensions;
+}
+
+void windows_setTexBuffer(windowsContext *context, int textureTarget,
+ int textureFormat, windowsDrawable *drawable)
+{
+ // not yet implemented
+}
+
+void windows_releaseTexBuffer(windowsContext *context, int textureTarget,
+ windowsDrawable *drawable)
+{
+ // not yet implemented
+}