aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/Makefile19
-rw-r--r--test/shared.c594
-rw-r--r--test/shared.rc3
-rw-r--r--wglarb.c17
4 files changed, 626 insertions, 7 deletions
diff --git a/test/Makefile b/test/Makefile
index 52128ef..2b5a0b7 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -10,12 +10,12 @@ WINDRES32=$(TARGET32)-windres
.PHONY: all
-all: layered64.exe layered32.exe
+all: layered64.exe layered32.exe shared64.exe shared32.exe
-layered64.exe: layered.c layered64_rc.o
+layered64.exe: layered.c layered64_rc.o ../wglarb.c
$(CC64) $(CFLAGS) -o layered64.exe layered.c layered64_rc.o ../wglarb.c $(LIBS) -Wl,--subsystem,windows
-layered32.exe: layered.c layered32_rc.o
+layered32.exe: layered.c layered32_rc.o ../wglarb.c
$(CC32) -march=i686 $(CFLAGS) -o layered32.exe layered.c layered32_rc.o ../wglarb.c $(LIBS) -Wl,--subsystem,windows
@@ -25,5 +25,18 @@ layered64_rc.o: layered.rc manifest.xml
layered32_rc.o: layered.rc manifest.xml
$(WINDRES32) --input layered.rc --output layered32_rc.o
+shared64.exe: shared.c shared64_rc.o ../wglarb.c
+ $(CC64) $(CFLAGS) -o shared64.exe shared.c shared64_rc.o ../wglarb.c $(LIBS) -Wl,--subsystem,windows
+
+shared32.exe: shared.c shared32_rc.o ../wglarb.c
+ $(CC32) -march=i686 $(CFLAGS) -o shared32.exe shared.c shared32_rc.o ../wglarb.c $(LIBS) -Wl,--subsystem,windows
+
+
+shared64_rc.o: layered.rc manifest.xml
+ $(WINDRES64) --input shared.rc --output shared64_rc.o
+
+shared32_rc.o: layered.rc manifest.xml
+ $(WINDRES32) --input shared.rc --output shared32_rc.o
+
clean:
rm *.o *.exe
diff --git a/test/shared.c b/test/shared.c
new file mode 100644
index 0000000..a7f3c24
--- /dev/null
+++ b/test/shared.c
@@ -0,0 +1,594 @@
+#include <windows.h>
+#include <wingdi.h>
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <math.h>
+
+#include <GL/gl.h>
+#include <GL/glext.h>
+
+#include <wglarb.h>
+
+int const pf_attribs[] = {
+ WGL_DRAW_TO_WINDOW_ARB, TRUE,
+ WGL_DOUBLE_BUFFER_ARB, TRUE,
+ WGL_SUPPORT_OPENGL_ARB, TRUE,
+ WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
+ WGL_TRANSPARENT_ARB, TRUE,
+ WGL_COLOR_BITS_ARB, 32,
+ WGL_RED_BITS_ARB, 8,
+ WGL_GREEN_BITS_ARB, 8,
+ WGL_BLUE_BITS_ARB, 8,
+ WGL_ALPHA_BITS_ARB, 8,
+ WGL_DEPTH_BITS_ARB, 24,
+ WGL_STENCIL_BITS_ARB, 8,
+ 0, 0
+};
+
+int gl_attribs[] = {
+ WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
+ WGL_CONTEXT_MINOR_VERSION_ARB, 1,
+ 0, 0
+};
+
+typedef struct {
+ HANDLE mutex;
+ HGLRC hRC;
+ int refcount;
+} *RefCountGLRC;
+
+typedef struct {
+ void (*display)(HWND, void*);
+} OpenGLWndFuncs;
+
+typedef struct {
+ RefCountGLRC glrc;
+ struct {
+ HCURSOR handle;
+ BOOL set;
+ } cursor;
+
+ OpenGLWndFuncs wndfuncs;
+ void *userdata;
+} OpenGLWndData;
+
+LRESULT CALLBACK OpenGLWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
+
+BOOL WindowSetCursor(
+ HWND hWnd,
+ HCURSOR hCursor )
+{
+ OpenGLWndData *data = (void*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ if(!data) {
+ return FALSE;
+ }
+ data->cursor.handle = hCursor;
+ if( data->cursor.set ) {
+ SetCursor(hCursor);
+ }
+ return TRUE;
+}
+
+HWND CreateWindowForOpenGL(
+ HWND hWndParent,
+ LPCTSTR lpszWindowName,
+ int const *pPFAttribs,
+ HINSTANCE hInstance,
+ DWORD dwStyle,
+ DWORD dwExStyle,
+ OpenGLWndFuncs const *wndfuncs,
+ void *userdata)
+{
+ if(!hInstance) {
+ hInstance = GetModuleHandle(NULL);
+ }
+
+ WNDCLASS wc;
+ memset(&wc, 0, sizeof(wc));
+ wc.hInstance = hInstance;
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+
+ /* Register DefWindowProc as intermediary window proc in the
+ * window class. We're setting the proper window proc of the
+ * window later, when the userdata window long property has
+ * been initialized. */
+ wc.lpfnWndProc = DefWindowProc;
+ wc.lpszClassName = TEXT("OpenGL Window");
+ RegisterClass(&wc);
+
+ RECT rect;
+ if( hWndParent
+ && (dwStyle & WS_CHILD) ) {
+ GetClientRect(hWndParent, &rect);
+ }
+ else {
+ rect.left =
+ rect.top =
+ rect.right =
+ rect.bottom = CW_USEDEFAULT;
+ }
+
+ HWND hWnd =
+ CreateWindowEx(
+ dwExStyle,
+ wc.lpszClassName,
+ lpszWindowName,
+ dwStyle,
+ rect.left,
+ rect.top,
+ rect.right,
+ rect.bottom,
+ hWndParent,
+ NULL,
+ hInstance,
+ NULL);
+ if( !hWnd ) {
+ goto fail_create_wnd;
+ }
+
+ OpenGLWndData *wnddata = VirtualAlloc(
+ NULL,
+ sizeof(*wnddata),
+ MEM_COMMIT | MEM_RESERVE,
+ PAGE_READWRITE );
+
+ if( !wnddata ) {
+ goto fail_alloc_wnddata;
+ }
+ wnddata->userdata = userdata;
+ wnddata->wndfuncs = *wndfuncs;
+ SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)wnddata);
+ SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)OpenGLWndProc);
+
+ /* Must call SetWindowPos to reliably update window longs...
+ * Bad API design is bad. */
+ SetWindowPos(
+ hWnd, hWnd,
+ 0, 0, 0, 0,
+ SWP_NOACTIVATE
+ | SWP_NOCOPYBITS
+ | SWP_NOMOVE
+ | SWP_NOSIZE
+ | SWP_NOZORDER );
+
+ HDC hDC = GetDC(hWnd);
+ if( !hDC ) {
+ goto fail_get_dc;
+ }
+
+ INT iPF;
+ UINT num_formats_choosen;
+ if( !wglarb_ChoosePixelFormatARB(
+ hDC,
+ pPFAttribs,
+ NULL,
+ 1,
+ &iPF,
+ &num_formats_choosen)
+ || !num_formats_choosen ) {
+ goto fail_choose_pf;
+ }
+
+ PIXELFORMATDESCRIPTOR pfd;
+ memset(&pfd, 0, sizeof(pfd));
+ /* now this is a kludge; we need to pass something in the
+ * PIXELFORMATDESCRIPTOR to SetPixelFormat; it will be ignored,
+ * mostly. OTOH we want to send something sane, we're nice
+ * people after all - it doesn't hurt if this fails. */
+ DescribePixelFormat(hDC, iPF, sizeof(pfd), &pfd);
+
+ if( !SetPixelFormat(hDC, iPF, &pfd) ) {
+ goto fail_set_pf;
+ }
+ ReleaseDC(hWnd, hDC);
+
+ return hWnd;
+
+fail_set_pf:
+fail_choose_pf:
+ ReleaseDC(hWnd, hDC);
+
+fail_get_dc:
+ VirtualFree(
+ wnddata,
+ 0,
+ MEM_RELEASE );
+
+fail_alloc_wnddata:
+ DestroyWindow(hWnd);
+fail_create_wnd:
+
+ return NULL;
+}
+
+BOOL AssociateOpenGLContextWithWindow_L(
+ HWND hWnd,
+ RefCountGLRC glrc)
+{
+ if( 0 > glrc->refcount ) {
+ /* OpenGL context has been destroyed */
+ return FALSE;
+ }
+
+ if( INT_MAX == glrc->refcount ) {
+ /* refcount is at integer maximum.
+ * This is very unlikely to happen though. */
+ return FALSE;
+ }
+
+ OpenGLWndData *data = (void*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ if( !data ) {
+ return FALSE;
+ }
+
+ ++ glrc->refcount;
+ data->glrc = glrc;
+
+ return TRUE;
+}
+
+RefCountGLRC CreateOpenGLContextToWindow(
+ HWND hWnd,
+ int const *pGLAttribs )
+{
+ if( !hWnd ) {
+ return NULL;
+ }
+
+ int const default_attribs[] = {0, 0};
+ if( !pGLAttribs ) {
+ pGLAttribs = default_attribs;
+ }
+
+ RefCountGLRC glrc = VirtualAlloc(
+ NULL,
+ sizeof(*glrc),
+ MEM_COMMIT | MEM_RESERVE,
+ PAGE_READWRITE);
+ if( !glrc ) {
+ goto fail_alloc_glrc;
+ }
+
+ glrc->mutex = CreateMutex(NULL, TRUE, NULL);
+ if( !glrc->mutex ) {
+ goto fail_create_mutex;
+ }
+
+ HDC hDC = GetDC(hWnd);
+ if( !hDC ) {
+ goto fail_get_dc;
+ }
+
+ glrc->hRC = wglarb_CreateContextAttribsARB(hDC, NULL, pGLAttribs);
+ if( !glrc->hRC ) {
+ goto fail_create_glrc;
+ }
+
+ if( !AssociateOpenGLContextWithWindow_L(hWnd, glrc) ) {
+ goto fail_associate_rc_to_wnd;
+ }
+
+ ReleaseDC(hWnd, hDC);
+ ReleaseMutex(glrc->mutex);
+
+ return glrc;
+
+fail_associate_rc_to_wnd:
+ wglDeleteContext(glrc->hRC);
+
+fail_create_glrc:
+ ReleaseDC(hWnd, hDC);
+
+fail_get_dc:
+ ReleaseMutex(glrc->mutex);
+ CloseHandle(glrc->mutex);
+
+fail_create_mutex:
+ VirtualFree(
+ glrc,
+ 0,
+ MEM_RELEASE );
+
+fail_alloc_glrc:
+ return NULL;
+}
+
+BOOL AssociateOpenGLContextWithWindow(
+ HWND hWnd,
+ RefCountGLRC glrc)
+{
+ if( !hWnd
+ || !glrc ) {
+ return FALSE;
+ }
+
+ if( WAIT_OBJECT_0 != WaitForSingleObject(glrc->mutex, INFINITE) ) {
+ return FALSE;
+ }
+ BOOL const rv = AssociateOpenGLContextWithWindow_L(hWnd, glrc);
+ ReleaseMutex(glrc->mutex);
+
+ return rv;
+}
+
+void OnOpenGLWindowDestroy(HWND hWnd)
+{
+ /*
+ wglMakeCurrent(NULL,NULL);
+ wglDeleteContext(hRC);
+ */
+ PostQuitMessage(0);
+}
+
+BOOL cursor_needs_setting = TRUE;
+
+LRESULT CALLBACK OpenGLWndProc(
+ HWND hWnd,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ OpenGLWndData *data = (void*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ if(!data) {
+ return DefWindowProc(hWnd,uMsg,wParam,lParam);
+ }
+
+ switch(uMsg)
+ {
+ case WM_MOUSELEAVE:
+ data->cursor.set = FALSE;
+ break;
+
+ case WM_MOUSEMOVE:
+ if( !data->cursor.set ) {
+ SetCursor(data->cursor.handle);
+ }
+ break;
+
+ case WM_DESTROY:
+ OnOpenGLWindowDestroy(hWnd);
+ break;
+
+ case WM_PAINT: {
+ PAINTSTRUCT ps;
+ HDC hDC = BeginPaint(hWnd, &ps);
+ if( data->glrc ) {
+ wglMakeCurrent(hDC, data->glrc->hRC);
+
+ if(data->wndfuncs.display) {
+ data->wndfuncs.display(hWnd, data->userdata);
+ }
+ else {
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ /* SwapBuffers causes an implicit OpenGL command queue flush,
+ * but only on double buffered windows. On single buffered
+ * windows SwapBuffers has no effect at all. Also calling
+ * glFlush right before SwapBuffers has no ill effect other
+ * than that the OpenGL queue gets flushed a few CPU cycles
+ * earlier. */
+ glFlush();
+ SwapBuffers(hDC);
+
+ wglMakeCurrent(hDC, NULL);
+ }
+ EndPaint(hWnd, &ps);
+ } break;
+
+ default:
+ break;
+ }
+ return DefWindowProc(hWnd,uMsg,wParam,lParam);
+}
+
+
+typedef struct {
+ GLuint anaglyph_fbo;
+} PrimaryWindowData;
+
+void primary_display(HWND hWnd, void *userdata)
+{
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+
+ float const ratio = (float)rect.right/(float)rect.bottom;
+ glViewport(
+ 0,
+ 0,
+ rect.right,
+ rect.bottom);
+
+ glClearColor(0., 0., 0., 0.);
+ glClearDepth(1.);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-ratio, ratio, -1., 1., -1, 1);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ float const cos60 = cosf(M_PI*60./180.);
+ float const sin60 = sinf(M_PI*60./180.);
+
+ GLfloat const triangle[] = {
+ -1., -sin60, 1., 0., 0.,
+ 1., -sin60, 0., 1., 0.,
+ 0., sin60, 0., 0., 1.
+ };
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+
+ glVertexPointer(2, GL_FLOAT, sizeof(GLfloat)*5, &triangle[0]);
+ glColorPointer( 3, GL_FLOAT, sizeof(GLfloat)*5, &triangle[0]);
+
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+}
+
+OpenGLWndFuncs const primary_window_funcs = {
+ .display = primary_display,
+};
+
+typedef struct {
+ GLuint rendertexture_fbo;
+} SecondaryWindowData;
+
+void secondary_display(HWND hWnd, void *userdata)
+{
+ RECT rect;
+ GetClientRect(hWnd, &rect);
+
+ float const ratio = (float)rect.right/(float)rect.bottom;
+ glViewport(
+ 0,
+ 0,
+ rect.right,
+ rect.bottom);
+
+ glClearColor(0., 0., 0., 0.);
+ glClearDepth(1.);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-ratio, ratio, -1., 1., -1, 1);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ float const cos60 = cosf(M_PI*60./180.);
+ float const sin60 = sinf(M_PI*60./180.);
+
+ GLfloat const triangle[] = {
+ -1., -sin60, 1., 0., 0.,
+ 1., -sin60, 0., 1., 0.,
+ 0., sin60, 0., 0., 1.
+ };
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+
+ glVertexPointer(2, GL_FLOAT, sizeof(GLfloat)*5, &triangle[0]);
+ glColorPointer( 3, GL_FLOAT, sizeof(GLfloat)*5, &triangle[0]);
+
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+}
+
+OpenGLWndFuncs const secondary_window_funcs = {
+ .display = secondary_display,
+};
+
+int CALLBACK WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ MSG msg;
+ BOOL bRet;
+
+ PrimaryWindowData primary_data;
+ HWND hPrimaryWnd = CreateWindowForOpenGL(
+ NULL,
+ "Test Primary Window",
+ pf_attribs,
+ hInstance,
+ WS_OVERLAPPEDWINDOW,
+ WS_EX_APPWINDOW,
+ &primary_window_funcs,
+ &primary_data );
+ if( !hPrimaryWnd ) {
+ return -1;
+ }
+ WindowSetCursor(
+ hPrimaryWnd,
+ LoadCursor(NULL, IDC_CROSS) );
+ RefCountGLRC primary_glrc =
+ CreateOpenGLContextToWindow(hPrimaryWnd, NULL);
+ if( !primary_glrc ) {
+ return -1;
+ }
+
+ BOOL glcontext_reuse = TRUE;
+
+ SecondaryWindowData secondary_data;
+ HWND hSecondaryWnd = CreateWindowForOpenGL(
+ NULL,
+ "Test Secondary Window",
+ pf_attribs,
+ hInstance,
+ WS_OVERLAPPEDWINDOW,
+ WS_EX_APPWINDOW,
+ &secondary_window_funcs,
+ &secondary_data );
+ if( !hSecondaryWnd ) {
+ return -1;
+ }
+ WindowSetCursor(
+ hSecondaryWnd,
+ LoadCursor(NULL, IDC_HAND) );
+ RefCountGLRC secondary_glrc;
+ if( glcontext_reuse ) {
+ if( !AssociateOpenGLContextWithWindow(
+ hSecondaryWnd,
+ primary_glrc) ) {
+ goto window_owns_own_context_fallback;
+ }
+ secondary_glrc = primary_glrc;
+ }
+ else {
+window_owns_own_context_fallback:
+ secondary_glrc =
+ CreateOpenGLContextToWindow(hSecondaryWnd, NULL);
+ if( !secondary_glrc ) {
+ return -1;
+ }
+
+ /* The secondary OpenGL context is freshly created. This
+ * means nothing has been allocated from its namespaces
+ * so far. Hence we can safely create a namespace sharing
+ * association with the primary OpenGL context. All
+ * data holding objects (textures, buffer objects, display
+ * lists) will also appear in the secondary OpenGL context
+ * from now on. Also anything created in the secondary
+ * OpenGL context will appear in the primary one. */
+ if( !wglShareLists(primary_glrc->hRC, secondary_glrc->hRC) ) {
+ /* OpenGL context resource sharing failed. Most likely
+ * the OpenGL contexts are incompatible to each other;
+ * they may run on different drivers / GPUs but there
+ * are other possible reasons. Since the contexts
+ * and windows have been created using the very same
+ * this is very unlikely though. */
+ return -1;
+ }
+ }
+
+ UpdateWindow(hPrimaryWnd);
+ UpdateWindow(hSecondaryWnd);
+ ShowWindow(hPrimaryWnd, SW_SHOW);
+ ShowWindow(hSecondaryWnd, SW_SHOW);
+
+ while( (bRet = GetMessage(&msg, NULL, 0, 0)) ) {
+ if(bRet == -1) {
+ // Handle Error
+ }
+ else {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ return msg.wParam;
+}
diff --git a/test/shared.rc b/test/shared.rc
new file mode 100644
index 0000000..7c46d6e
--- /dev/null
+++ b/test/shared.rc
@@ -0,0 +1,3 @@
+#include "winuser.h"
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST manifest.xml
+
diff --git a/wglarb.c b/wglarb.c
index 3c76608..a8bc126 100644
--- a/wglarb.c
+++ b/wglarb.c
@@ -186,8 +186,9 @@ HGLRC WINAPI wglarb_CreateContextAttribsARB(
return NULL;
}
- PFNWGLCREATECONTEXTATTRIBSARBPROC impl;
- *(PROC*)(&impl) = wglGetProcAddress("wglCreateContextAttribsARB");
+ PFNWGLCREATECONTEXTATTRIBSARBPROC impl =
+ (PFNWGLCREATECONTEXTATTRIBSARBPROC)
+ wglGetProcAddress("wglCreateContextAttribsARB");
HGLRC ret = NULL;
if( impl ) {
@@ -218,8 +219,16 @@ BOOL WINAPI wglarb_ChoosePixelFormatARB(
return FALSE;
}
- PFNWGLCHOOSEPIXELFORMATARBPROC impl;
- *(PROC*)(&impl) = wglGetProcAddress("wglChoosePixelFormatARB");
+ PFNWGLCHOOSEPIXELFORMATARBPROC impl = NULL;
+
+ impl = (PFNWGLCHOOSEPIXELFORMATARBPROC)
+ wglGetProcAddress("wglChoosePixelFormatARB");
+ if( !impl ) {
+ /* WGL_EXT_pixel_format uses the same function prototypes
+ * as the WGL_ARB_pixel_format extension */
+ impl = (PFNWGLCHOOSEPIXELFORMATARBPROC)
+ wglGetProcAddress("wglChoosePixelFormatEXT");
+ }
BOOL ret = FALSE;
if( impl ) {