[waffle] [PATCH 06/53] wgl: implement display management

Emil Velikov emil.l.velikov at gmail.com
Sun Nov 9 14:58:48 PST 2014


Unlike GLX and EGL, WGL(Windows) does not have the concept of a display
in the sense used in waffle.

The 'root primitive' for WGL is a window with it's device context
which encapsulates the properties and capabilities of the device
doing the actual rendering (CPU or GPU).

As such we first need to create a unique window class that will be
used for all waffle windows, and then create the 'root' window.

The windows itself is disabled (cannot grab the input) and of zero
width and height.

While we're here make sure that we create a context, which will be
needed in a variety of cases - when we query the WGL extensions,
choose the config ...

v2: Bail out if we're using the GDI renderer.
v3: Zero-initialise pfd and explicitly set its required parameters.
v4: No not mention waffle_get_proc_address in commit msg.

Signed-off-by: Emil Velikov <emil.l.velikov at gmail.com>
Reviewed-by: Chad Versace <chad.versace at linux.intel.com>
---
 src/waffle/wgl/wgl_display.c  | 112 +++++++++++++++++++++++++++++++++++++++++-
 src/waffle/wgl/wgl_display.h  |   5 ++
 src/waffle/wgl/wgl_platform.c |  41 ++++++++++++++++
 src/waffle/wgl/wgl_platform.h |   3 ++
 4 files changed, 159 insertions(+), 2 deletions(-)

diff --git a/src/waffle/wgl/wgl_display.c b/src/waffle/wgl/wgl_display.c
index a51e538..c2cab1c 100644
--- a/src/waffle/wgl/wgl_display.c
+++ b/src/waffle/wgl/wgl_display.c
@@ -25,25 +25,117 @@
 
 
 #include <stdlib.h>
+#include <strings.h>
+#include <windows.h>
 
 #include "wcore_error.h"
 
 #include "wgl_display.h"
+#include "wgl_dl.h"
+#include "wgl_platform.h"
 
 bool
 wgl_display_destroy(struct wcore_display *wc_self)
 {
     struct wgl_display *self = wgl_display(wc_self);
-    bool ok;
+    bool ok = true;
 
     if (!self)
         return true;
 
-    ok = wcore_display_teardown(wc_self);
+    if (self->hWnd) {
+        if (self->hglrc) {
+            ok &= wglDeleteContext(self->hglrc);
+        }
+
+        if (self->hDC)
+            ok &= ReleaseDC(self->hWnd, self->hDC);
+
+        ok &= DestroyWindow(self->hWnd);
+    }
+
+    ok &= wcore_display_teardown(wc_self);
     free(self);
     return ok;
 }
 
+static bool
+wgl_display_create_window(struct wgl_platform *plat, struct wgl_display *dpy)
+{
+    dpy->hWnd = CreateWindow(plat->class_name, NULL,
+                             WS_POPUPWINDOW|WS_DISABLED,
+                             0, 0, 0, 0, NULL, NULL, NULL, NULL);
+    if (!dpy->hWnd)
+        return false;
+
+    dpy->hDC = GetDC(dpy->hWnd);
+    if (!dpy->hDC)
+        return false;
+
+    return true;
+}
+
+static bool
+wgl_display_choose_config(struct wgl_display *dpy)
+{
+    // XXX: Is there a move common/appropriate pixelformat ?
+    PIXELFORMATDESCRIPTOR pfd = {0};
+    bool ok;
+
+    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+    pfd.nVersion = 1;
+
+    pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
+
+    pfd.iPixelType = PFD_TYPE_RGBA;
+    pfd.iLayerType = PFD_MAIN_PLANE;
+    pfd.cColorBits = 32;
+    pfd.cDepthBits = 16;
+
+    dpy->pixel_format = ChoosePixelFormat(dpy->hDC, &pfd);
+    if (!dpy->pixel_format)
+        return false;
+
+    ok = SetPixelFormat(dpy->hDC, dpy->pixel_format, &pfd);
+    if (!ok)
+        return false;
+
+    return true;
+}
+
+static bool
+wgl_display_hardware_render(struct wgl_display *dpy)
+{
+#ifndef GL_RENDERER
+#define GL_RENDERER 0x1F01
+#endif
+    typedef unsigned int GLenum;
+    typedef unsigned char GLubyte;
+    typedef const GLubyte * (__stdcall *PFNGLGETSTRINGPROC)(GLenum name);
+
+    PFNGLGETSTRINGPROC glGetString_func;
+    const GLubyte *gl_renderer;
+    bool ok;
+
+    glGetString_func = wgl_dl_sym(dpy->wcore.platform, WAFFLE_DL_OPENGL, "glGetString");
+    if (!glGetString_func)
+        return false;
+
+    ok = wglMakeCurrent(dpy->hDC, dpy->hglrc);
+    if (!ok)
+        return false;
+
+    gl_renderer = glGetString_func(GL_RENDERER);
+    ok = wglMakeCurrent(NULL, NULL);
+    if (!ok)
+        return false;
+
+    // Bail out if we cannot retrieve the renderer string or if we're using GDI
+    if (!gl_renderer || strcasecmp((const char *)gl_renderer, "GDI Generic") == 0)
+        return false;
+
+    return true;
+}
 
 struct wcore_display*
 wgl_display_connect(struct wcore_platform *wc_plat,
@@ -60,6 +152,22 @@ wgl_display_connect(struct wcore_platform *wc_plat,
     if (!ok)
         goto error;
 
+    ok = wgl_display_create_window(wgl_platform(wc_plat), self);
+    if (!ok)
+        goto error;
+
+    ok = wgl_display_choose_config(self);
+    if (!ok)
+        goto error;
+
+    self->hglrc = wglCreateContext(self->hDC);
+    if (!self->hglrc)
+        goto error;
+
+    ok = wgl_display_hardware_render(self);
+    if (!ok)
+        goto error;
+
     return &self->wcore;
 
 error:
diff --git a/src/waffle/wgl/wgl_display.h b/src/waffle/wgl/wgl_display.h
index 262ab18..6a2b6c7 100644
--- a/src/waffle/wgl/wgl_display.h
+++ b/src/waffle/wgl/wgl_display.h
@@ -35,6 +35,11 @@ struct wcore_platform;
 
 struct wgl_display {
     struct wcore_display wcore;
+
+    HWND hWnd;
+    HDC hDC;
+    int pixel_format;
+    HGLRC hglrc;
 };
 
 DEFINE_CONTAINER_CAST_FUNC(wgl_display,
diff --git a/src/waffle/wgl/wgl_platform.c b/src/waffle/wgl/wgl_platform.c
index 6c31c7e..2f88aff 100644
--- a/src/waffle/wgl/wgl_platform.c
+++ b/src/waffle/wgl/wgl_platform.c
@@ -36,6 +36,8 @@
 
 static const struct wcore_platform_vtbl wgl_platform_vtbl;
 
+const char* wfl_class_name = "waffle";
+
 static bool
 wgl_platform_destroy(struct wcore_platform *wc_self)
 {
@@ -48,11 +50,45 @@ wgl_platform_destroy(struct wcore_platform *wc_self)
     if (self->dl_gl)
         ok &= wgl_dl_close(wc_self);
 
+    if (self->class_name)
+        ok &= UnregisterClass(self->class_name, GetModuleHandle(NULL));
+
     ok &= wcore_platform_teardown(wc_self);
     free(self);
     return ok;
 }
 
+static bool
+wgl_platform_register_class(const char* class_name)
+{
+    WNDCLASS wc;
+    bool ok;
+
+    memset(&wc, 0, sizeof(wc));
+    wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
+    // XXX: Use a non-default window_proc ?
+    wc.lpfnWndProc = DefWindowProc;
+    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+    wc.hInstance = GetModuleHandle(NULL);
+    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);;
+    wc.lpszClassName = class_name;
+
+    ok = !!RegisterClass(&wc);
+
+    if (!ok) {
+        int error = GetLastError();
+
+        if (error) {
+            wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+                         "RegisterClass() failed: %d",
+                         error);
+        }
+    }
+
+    return ok;
+}
+
 struct wcore_platform*
 wgl_platform_create(void)
 {
@@ -67,6 +103,11 @@ wgl_platform_create(void)
     if (!ok)
         goto error;
 
+    ok = wgl_platform_register_class(wfl_class_name);
+    if (!ok)
+        goto error;
+    self->class_name = wfl_class_name;
+
     self->wcore.vtbl = &wgl_platform_vtbl;
     return &self->wcore;
 
diff --git a/src/waffle/wgl/wgl_platform.h b/src/waffle/wgl/wgl_platform.h
index 9aa3611..9223aea 100644
--- a/src/waffle/wgl/wgl_platform.h
+++ b/src/waffle/wgl/wgl_platform.h
@@ -38,6 +38,9 @@ struct wgl_platform {
 
     /// @brief The OpenGL library obtained with LoadLibraryA().
     void *dl_gl;
+
+    /// @brief The class name of the waffle windows.
+    const char *class_name;
 };
 
 DEFINE_CONTAINER_CAST_FUNC(wgl_platform,
-- 
2.1.3



More information about the waffle mailing list