[gtk+/master.fcw: 59/648] Add GL Area Support for Windows (WIP)



commit 3441760a917ee2aee1f464d8523d4b0b8358fab3
Author: Chun-wei Fan <fanchunwei src gnome org>
Date:   Fri Nov 28 19:24:37 2014 +0800

    Add GL Area Support for Windows (WIP)
    
    This is obviously not ready to go into master, but shows the progress of
    the work of adding GL Area support into the Windows GDK backend.
    
    Current State:
    -Is able to create GL 3.2+ contexts, as well as legacy GL contexts.
    -Is able to switch GL contexts
    -Still has problems doing updates to the screen: Currently the GL Area demo
     could draw the yellow triangle but:
    --The GTK+ GUI widgets do not appear.
    --The Triangle disappears when the mouse pointer is on the portion of the
      window where the GTK+ GUI widgets is supposed to be.
    --Software fallback does draw the triangle and GTK+ GUI widgets, but the GL
      Area portion and the GUI portions are initially not that correctly
      displayed.  The image and GUI widgets do display somewhat correctly after
      a little bit of time after moving mouse pointer onto GUI widgets, but
      triangle turns black upon so, and the GUI control sliders do not
      function.
      moving the mouse onto the GTK+ GUI widgets.
    
    -gtkgears test/demo program compiles after changing M_PI into G_PI, but
     only a black window appears, likely due to the updating issue mentioned
     above.

 gdk/win32/Makefile.am          |    4 +
 gdk/win32/gdkdisplay-win32.c   |   30 ++-
 gdk/win32/gdkdisplay-win32.h   |   55 +++
 gdk/win32/gdkglcontext-win32.c |  710 ++++++++++++++++++++++++++++++++++++++++
 gdk/win32/gdkglcontext-win32.h |   84 +++++
 gdk/win32/gdkglobals-win32.c   |    8 +
 gdk/win32/gdkmain-win32.c      |    2 +-
 gdk/win32/gdkwin32.h           |    1 +
 gdk/win32/gdkwin32glcontext.h  |   49 +++
 gdk/win32/gdkwindow-win32.c    |   24 +-
 10 files changed, 955 insertions(+), 12 deletions(-)
---
diff --git a/gdk/win32/Makefile.am b/gdk/win32/Makefile.am
index 640a215..aa31d04 100644
--- a/gdk/win32/Makefile.am
+++ b/gdk/win32/Makefile.am
@@ -41,6 +41,8 @@ libgdk_win32_la_SOURCES = \
        gdkdnd-win32.c \
        gdkevents-win32.c \
        gdkgeometry-win32.c \
+       gdkglcontext-win32.c \
+       gdkglcontext-win32.h \
        gdkglobals-win32.c \
        gdkinput.c \
        gdkkeys-win32.c \
@@ -55,6 +57,7 @@ libgdk_win32_la_SOURCES = \
        gdkwin32display.h \
        gdkwin32displaymanager.h \
        gdkwin32dnd.h \
+       gdkwin32glcontext.h             \
        gdkwin32.h \
        gdkwin32id.c \
        gdkwin32keys.h \
@@ -74,6 +77,7 @@ libgdkwin32include_HEADERS =  \
        gdkwin32display.h       \
        gdkwin32displaymanager.h\
        gdkwin32dnd.h           \
+       gdkwin32glcontext.h             \
        gdkwin32keys.h          \
        gdkwin32misc.h          \
        gdkwin32screen.h        \
diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c
index 97d0e3e..476f930 100644
--- a/gdk/win32/gdkdisplay-win32.c
+++ b/gdk/win32/gdkdisplay-win32.c
@@ -19,7 +19,8 @@
 #include "config.h"
 #include "gdk.h"
 #include "gdkprivate-win32.h"
-#include "gdkdisplayprivate.h"
+#include "gdkdisplay-win32.h"
+#include "gdkglcontext-win32.h"
 #include "gdkwin32display.h"
 #include "gdkwin32screen.h"
 #include "gdkwin32window.h"
@@ -216,6 +217,7 @@ _gdk_win32_display_open (const gchar *display_name)
   return _gdk_display;
 }
 
+/*
 struct _GdkWin32Display
 {
   GdkDisplay display;
@@ -224,7 +226,7 @@ struct _GdkWin32Display
 struct _GdkWin32DisplayClass
 {
   GdkDisplayClass display_class;
-};
+};*/
 
 G_DEFINE_TYPE (GdkWin32Display, gdk_win32_display, GDK_TYPE_DISPLAY)
 
@@ -571,6 +573,28 @@ gdk_win32_display_sync (GdkDisplay * display)
 static void
 gdk_win32_display_dispose (GObject *object)
 {
+  GdkDisplay *display = GDK_DISPLAY (object);
+  GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
+
+  if (display_win32->dummy_hglrc != NULL)
+    {
+      wglDeleteContext (display_win32->dummy_hglrc);
+      display_win32->dummy_hglrc = NULL;
+    }
+  if (display_win32->dummy_hdc != NULL)
+    {
+      ReleaseDC (display_win32->dummy_hwnd, display_win32->dummy_hdc);
+      display_win32->dummy_hdc = NULL;
+    }
+  if (display_win32->is_foreign_window && display_win32->dummy_hwnd != NULL)
+    {
+      DestroyWindow (display_win32->dummy_hwnd);
+      display_win32->dummy_hwnd = NULL;
+    }
+  if (display_win32->dummy_atom_wc != 0)
+    UnregisterClass (MAKEINTATOM (display_win32->dummy_atom_wc), GetModuleHandle (NULL));
+
+  G_OBJECT_CLASS (gdk_win32_display_parent_class)->dispose (object);
 }
 
 static void
@@ -581,6 +605,7 @@ gdk_win32_display_finalize (GObject *object)
 static void
 gdk_win32_display_init(GdkWin32Display *display)
 {
+  display->pixel_format = 0;
 }
 
 static void
@@ -664,6 +689,7 @@ gdk_win32_display_class_init (GdkWin32DisplayClass *klass)
   display_class->convert_selection = _gdk_win32_display_convert_selection;
   display_class->text_property_to_utf8_list = _gdk_win32_display_text_property_to_utf8_list;
   display_class->utf8_to_string_target = _gdk_win32_display_utf8_to_string_target;
+  display_class->make_gl_context_current = _gdk_win32_display_make_gl_context_current;
   
   _gdk_win32_windowing_init ();
 }
diff --git a/gdk/win32/gdkdisplay-win32.h b/gdk/win32/gdkdisplay-win32.h
new file mode 100644
index 0000000..766c23d
--- /dev/null
+++ b/gdk/win32/gdkdisplay-win32.h
@@ -0,0 +1,55 @@
+/*
+ * gdkdisplay-win32.h
+ *
+ * Copyright 2014 Chun-wei Fan <fanc999 yahoo com tw>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gdkdisplayprivate.h"
+
+#ifndef __GDK_DISPLAY__WIN32_H__
+#define __GDK_DISPLAY__WIN32_H__
+
+struct _GdkWin32Display
+{
+  GdkDisplay display;
+
+  /* WGL/OpenGL Items */
+  guint have_wgl : 1;
+  gint gl_version;
+  HDC gl_hdc;
+  HWND gl_hwnd;
+  guint pixel_format;
+
+  /* dummy items for use */
+  HWND dummy_hwnd;
+  HDC dummy_hdc;
+  HGLRC dummy_hglrc;
+  ATOM dummy_atom_wc;
+  gboolean is_foreign_window;
+
+  gint hasWglARBCreateContext : 1;
+  gint hasWglARBPbuffer : 1;
+  gint hasWglARBRenderTexture : 1;
+  gint hasWglEXTSwapControl : 1;
+  gint hasWglOMLSyncControl : 1;
+};
+
+struct _GdkWin32DisplayClass
+{
+  GdkDisplayClass display_class;
+};
+
+#endif /* __GDK_DISPLAY__WIN32_H__ */
\ No newline at end of file
diff --git a/gdk/win32/gdkglcontext-win32.c b/gdk/win32/gdkglcontext-win32.c
new file mode 100644
index 0000000..4aaaae0
--- /dev/null
+++ b/gdk/win32/gdkglcontext-win32.c
@@ -0,0 +1,710 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontext-win32.c: Win32 specific OpenGL wrappers
+ *
+ * Copyright © 2014 Emmanuele Bassi
+ * Copyright © 2014 Alexander Larsson
+ * Copyright © 2014 Chun-wei Fan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gdkprivate-win32.h"
+#include "gdkwindow-win32.h"
+#include "gdkglcontext-win32.h"
+#include "gdkdisplay-win32.h"
+
+#include "gdkwin32display.h"
+#include "gdkwin32glcontext.h"
+#include "gdkwin32misc.h"
+#include "gdkwin32screen.h"
+#include "gdkwin32window.h"
+
+#include "gdkglcontext.h"
+#include "gdkinternals.h"
+#include "gdkintl.h"
+
+#include <epoxy/wgl.h>
+
+G_DEFINE_TYPE (GdkWin32GLContext, gdk_win32_gl_context, GDK_TYPE_GL_CONTEXT)
+
+static void
+gdk_win32_gl_context_dispose (GObject *gobject)
+{
+  GdkGLContext *context = GDK_GL_CONTEXT (gobject);
+  GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (gobject);
+  GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context));
+
+  if (context_win32->hglrc != NULL)
+    {
+
+      if (wglGetCurrentContext () == context_win32->hglrc)
+        wglMakeCurrent (NULL, NULL);
+
+      GDK_NOTE (OPENGL, g_print ("Destroying WGL context\n"));
+
+      wglDeleteContext (context_win32->hglrc);
+      context_win32->hglrc = NULL;
+
+      ReleaseDC (display_win32->gl_hwnd, display_win32->gl_hdc);
+    }
+
+  G_OBJECT_CLASS (gdk_win32_gl_context_parent_class)->dispose (gobject);
+}
+
+static void
+gdk_win32_gl_context_class_init (GdkWin32GLContextClass *klass)
+{
+  GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  context_class->end_frame = _gdk_win32_gl_context_end_frame;
+  context_class->texture_from_surface = _gdk_win32_gl_context_texture_from_surface;
+
+  gobject_class->dispose = gdk_win32_gl_context_dispose;
+}
+
+void
+_gdk_win32_gl_context_end_frame (GdkGLContext *context,
+                                 cairo_region_t *painted,
+                                 cairo_region_t *damage)
+{
+  GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
+  GdkWindow *window = gdk_gl_context_get_window (context);
+  GdkWin32Display *display = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)));
+  gboolean can_wait = display->hasWglOMLSyncControl;
+
+  gdk_gl_context_make_current (context);
+
+  if (can_wait)
+    {
+      gint64 ust, msc, sbc;
+
+      wglGetSyncValuesOML (context_win32->gl_hdc, &ust, &msc, &sbc);
+      wglWaitForMscOML (context_win32->gl_hdc,
+                        0, 2, (msc + 1) % 2,
+                        &ust, &msc, &sbc);
+    }
+
+  SwapBuffers (context_win32->gl_hdc);
+}
+
+void
+_gdk_win32_window_invalidate_for_new_frame (GdkWindow *window,
+                                            cairo_region_t *update_area)
+{
+  cairo_rectangle_int_t window_rect;
+  unsigned int buffer_age;
+  gboolean invalidate_all;
+  GdkWin32GLContext *context_win32;
+
+  /* Minimal update is ok if we're not drawing with gl */
+  if (window->gl_paint_context == NULL)
+    return;
+
+  context_win32 = GDK_WIN32_GL_CONTEXT (window->gl_paint_context);
+
+  window_rect.x = 0;
+  window_rect.y = 0;
+  window_rect.width = gdk_window_get_width (window);
+  window_rect.height = gdk_window_get_height (window);
+
+  /* If nothing else is known, repaint everything so that the back
+     buffer is fully up-to-date for the swapbuffer */
+  cairo_region_union_rectangle (update_area, &window_rect);
+}
+
+static void _get_dummy_window_hwnd (GdkWin32Display *display)
+{
+  WNDCLASSEX dummy_wc;
+  HWND dummy_hwnd;
+       /* create dummy GL window and get GL function pointers */
+  memset (&dummy_wc, 0, sizeof (WNDCLASSEX));
+
+       dummy_wc.cbSize = sizeof( WNDCLASSEX );
+       dummy_wc.style = CS_OWNDC;
+       dummy_wc.lpfnWndProc = (WNDPROC) DefWindowProc;
+       dummy_wc.cbClsExtra = 0;
+       dummy_wc.cbWndExtra = 0;
+       dummy_wc.hInstance = GetModuleHandle( NULL );
+       dummy_wc.hIcon = 0;
+       dummy_wc.hCursor = NULL;
+       dummy_wc.hbrBackground = 0;
+       dummy_wc.lpszMenuName = 0;
+       dummy_wc.lpszClassName = "dummy";
+       dummy_wc.hIconSm = 0;
+
+  display->dummy_atom_wc = RegisterClassEx (&dummy_wc);
+       
+       display->dummy_hwnd =
+    CreateWindowEx (WS_EX_APPWINDOW,
+                    MAKEINTATOM (display->dummy_atom_wc),
+                    "",
+                    WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+                    0,
+                    0,
+                    0,
+                    0,
+                    NULL,
+                    NULL,
+                    GetModuleHandle (NULL),
+                    NULL);
+}
+
+gboolean
+_gdk_win32_gl_context_texture_from_surface (GdkGLContext *paint_context,
+                                            cairo_surface_t *surface,
+                                            cairo_region_t *region)
+{
+  GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (paint_context);
+  GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_gl_context_get_display (paint_context));
+  GdkWindow *window_bitmap = gdk_gl_context_get_window (paint_context);
+  
+  if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_WIN32)
+    return FALSE;
+
+  if (display_win32->hasWglARBPbuffer && display_win32->hasWglARBRenderTexture)
+    {
+#define MAX_ATTRIBS 10
+      double device_x_offset, device_y_offset;
+      cairo_rectangle_int_t rect;
+      int n_rects, i;
+      GdkWindow *window;
+      int window_height;
+      int window_width;
+      int window_scale;
+      unsigned int texture_id;
+      gboolean use_texture_rectangle;
+      guint target;
+      double sx, sy;
+      float uscale, vscale;
+      GdkTexturedQuad *quads;
+
+      /* Windows-Specific */
+      PIXELFORMATDESCRIPTOR current_pfd, bitmap_pfd;
+      gint curr_pixel_format;
+
+      HDC hdc_pbuf;
+      HGLRC hglrc_pbuf;
+      PIXELFORMATDESCRIPTOR pfd;
+      const gint pattribs[] = {WGL_PBUFFER_LARGEST_EXT, 0, 0};
+      HPBUFFERARB pbuf;
+      gint surface_width = cairo_image_surface_get_width (surface);
+      gint surface_height = cairo_image_surface_get_height (surface);
+      gint pixformat_attribs [2 * MAX_ATTRIBS];
+      gint formats[MAX_ATTRIBS];
+      gint num_formats;
+      gint pbuffer_pixel_format;
+
+      use_texture_rectangle = gdk_gl_context_use_texture_rectangle (paint_context);
+      if (use_texture_rectangle)
+        target = GL_TEXTURE_RECTANGLE_ARB;
+      else
+        target = GL_TEXTURE_2D;
+      
+      window = gdk_gl_context_get_window (paint_context)/*->impl_window*/;
+      window_scale = gdk_window_get_scale_factor (window);
+      window_height = gdk_window_get_height (window);
+      window_width = gdk_window_get_width (window);
+
+      sx = sy = 1;
+      cairo_surface_get_device_scale (window->current_paint.surface, &sx, &sy);
+
+      cairo_surface_get_device_offset (surface, &device_x_offset, &device_y_offset);
+
+      i = 0;
+
+      pixformat_attribs[i ++] = WGL_DRAW_TO_PBUFFER_ARB;
+      pixformat_attribs[i ++] = GL_TRUE;
+      pixformat_attribs[i ++] = WGL_DEPTH_BITS_ARB;
+      pixformat_attribs[i ++] = current_pfd.cDepthBits;
+      pixformat_attribs[i ++] = WGL_COLOR_BITS_ARB;
+      pixformat_attribs[i ++] = current_pfd.cColorBits;
+      pixformat_attribs[i ++] = WGL_STENCIL_BITS_ARB;
+      pixformat_attribs[i ++] = current_pfd.cStencilBits;
+      pixformat_attribs[i ++] = WGL_DOUBLE_BUFFER_ARB;
+      pixformat_attribs[i ++] = GL_TRUE;
+      pixformat_attribs[i ++] = WGL_SUPPORT_OPENGL_ARB;
+      pixformat_attribs[i ++] = GL_TRUE;
+      pixformat_attribs[i ++] = WGL_PIXEL_TYPE_ARB;
+      pixformat_attribs[i ++] = WGL_TYPE_RGBA_ARB;
+      if (target == GL_TEXTURE_2D)
+        {
+          pixformat_attribs[i ++] = WGL_TEXTURE_TARGET_ARB;
+          pixformat_attribs[i ++] = WGL_TEXTURE_2D_ARB;
+        }
+      pixformat_attribs[i ++] = 0;
+
+      wglMakeCurrent (display_win32->dummy_hdc, display_win32->dummy_hglrc);
+
+      pbuffer_pixel_format = 
+        wglChoosePixelFormatARB (context_win32->gl_hdc,
+                                 pixformat_attribs,
+                                 NULL,
+                                 1,
+                                 formats,
+                                 &num_formats);
+
+      if (pbuffer_pixel_format == 0)
+        return FALSE;      
+
+      pbuf = wglCreatePbufferARB (display_win32->dummy_hdc,
+                                  pbuffer_pixel_format,
+                                  window_width,
+                                  window_height,
+                                  pattribs);
+
+      if (pbuf == NULL)
+        return FALSE;
+
+      hdc_pbuf = wglGetPbufferDCARB (pbuf);
+      hglrc_pbuf = wglCreateContext (hdc_pbuf);
+
+      wglMakeCurrent (hdc_pbuf, hglrc_pbuf);
+
+      GdiFlush ();
+      glFinish ();
+      glGenTextures (1, &texture_id);
+      glBindTexture (target, texture_id);
+
+      wglBindTexImageARB (pbuf, WGL_FRONT_LEFT_ARB);
+
+      glEnable (target);
+      glEnable (GL_SCISSOR_TEST);
+
+      glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+      glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+      glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+      glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+
+      n_rects = cairo_region_num_rectangles (region);
+      quads = g_new (GdkTexturedQuad, n_rects);
+
+#define FLIP_Y(_y) (window_height - (_y))
+
+      cairo_region_get_extents (region, &rect);
+      glScissor (rect.x * window_scale, FLIP_Y(rect.y) * window_scale,
+             (rect.x + rect.width) * window_scale, FLIP_Y (rect.y + rect.height) * window_scale);
+
+      for (i = 0; i < n_rects; i++)
+        {
+          int src_x, src_y, src_height, src_width;
+
+          cairo_region_get_rectangle (region, i, &rect);
+
+          src_x = rect.x * sx + device_x_offset;
+          src_y = rect.y * sy + device_y_offset;
+          src_width = rect.width * sx;
+          src_height = rect.height * sy;
+
+          if (use_texture_rectangle)
+            {
+              uscale = src_width;
+              vscale = src_height;
+            }
+          else
+            {
+              uscale = 1.0;
+              vscale = 1.0;
+            }
+
+          {
+            GdkTexturedQuad quad =
+              {
+                rect.x * window_scale, FLIP_Y(rect.y) * window_scale,
+                (rect.x + rect.width) * window_scale, FLIP_Y(rect.y + rect.height) * window_scale,
+                uscale * src_x, vscale * src_y,
+                uscale * (src_x + src_width), vscale * (src_y + src_height),
+              };
+            quads[i] = quad;
+          }
+        }
+
+#undef FLIP_Y
+
+      gdk_gl_texture_quads (paint_context, target, n_rects, quads);
+      g_free (quads);
+
+      wglReleaseTexImageARB (pbuf, WGL_FRONT_LEFT_ARB);
+
+      glDisable (GL_SCISSOR_TEST);
+      glDisable (target);
+
+      glDeleteTextures (1, &texture_id);
+
+      wglReleasePbufferDCARB (pbuf, hdc_pbuf);
+      wglDestroyPbufferARB (pbuf);
+      wglMakeCurrent (NULL, NULL);
+      wglDeleteContext (hglrc_pbuf);
+
+      wglMakeCurrent (context_win32->gl_hdc, context_win32->hglrc);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static void
+gdk_win32_gl_context_init (GdkWin32GLContext *self)
+{
+}
+
+static gboolean
+pixel_format_is_better (const PIXELFORMATDESCRIPTOR *pfa,
+                        const PIXELFORMATDESCRIPTOR *pfb)
+{
+  /* Always prefer a format with a stencil buffer */
+  if (pfa->cStencilBits == 0)
+    {
+      if (pfb->cStencilBits > 0)
+        return TRUE;
+    }
+  else if (pfb->cStencilBits == 0)
+    return FALSE;
+
+  /* Prefer a bigger color buffer */
+  if (pfb->cColorBits > pfa->cColorBits)
+    return TRUE;
+  else if (pfb->cColorBits < pfa->cColorBits)
+    return FALSE;
+
+  /* Prefer a bigger depth buffer */
+  return pfb->cDepthBits > pfa->cDepthBits;
+}
+
+static gint
+get_wgl_pfd (HDC hdc, PIXELFORMATDESCRIPTOR *pfd)
+{
+  PIXELFORMATDESCRIPTOR best_pfd;
+  gint configs;
+  gint i;
+  gint best_pf = 0;
+
+  configs = DescribePixelFormat (hdc, 0, sizeof (best_pfd), NULL);
+  for (i = 1; i <= configs; i++)
+    {
+      gint config;
+
+      memset (pfd, 0, sizeof (best_pfd));
+      config = DescribePixelFormat (hdc, i, sizeof (best_pfd), pfd);
+
+      if (config != 0)
+        {
+          if (((pfd->dwFlags &(PFD_SUPPORT_OPENGL |
+                            PFD_DRAW_TO_WINDOW |
+                            PFD_DOUBLEBUFFER |
+                            PFD_GENERIC_FORMAT)) ==
+          (PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW)) &&
+
+          pfd->iPixelType == PFD_TYPE_RGBA &&
+          pfd->cColorBits >= 16 && pfd->cColorBits <= 32 &&
+          pfd->cDepthBits >= 16 && pfd->cDepthBits <= 32 &&
+          /* Check whether this is a better format than one we've
+             already found */
+          (best_pf == 0 || pixel_format_is_better (&best_pfd, pfd)))
+            {
+              best_pf = i;
+              best_pfd = *pfd;
+            }
+        }
+    }
+
+  return best_pf;
+}
+
+gboolean
+gdk_win32_display_init_gl (GdkDisplay *display)
+{
+  GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
+  gint glMajMinVersion;
+  GdkWindowImplWin32 *impl;
+
+  gboolean set_pixel_format_result = FALSE;
+  gint best_idx = 0;
+
+  PIXELFORMATDESCRIPTOR pfd;
+
+  if (display_win32->have_wgl)
+    return TRUE;
+
+  /* acquire and later cache dummy Window (HWND & HDC) and
+     dummy GL Context, it is used to query functions
+     and used for many other stuff as well */
+       _get_dummy_window_hwnd (display_win32);
+
+  display_win32->dummy_hdc = GetDC (display_win32->dummy_hwnd);
+
+  best_idx = get_wgl_pfd (display_win32->dummy_hdc, &pfd);
+
+  if (best_idx != 0)
+    set_pixel_format_result = SetPixelFormat (display_win32->dummy_hdc,
+                                              best_idx,
+                                              &pfd);
+
+  if (best_idx == 0 || !set_pixel_format_result)
+    return FALSE;
+
+  display_win32->dummy_hglrc = wglCreateContext (display_win32->dummy_hdc);
+
+  if (display_win32->dummy_hglrc == NULL)
+    return FALSE;
+
+  if (!wglMakeCurrent (display_win32->dummy_hdc, display_win32->dummy_hglrc))
+    return FALSE;
+
+  display_win32->pixel_format = best_idx;
+  display_win32->have_wgl = TRUE;
+  display_win32->gl_version = epoxy_gl_version ();
+
+  display_win32->hasWglARBCreateContext =
+    epoxy_has_wgl_extension (display_win32->dummy_hdc, "WGL_ARB_create_context");
+  display_win32->hasWglARBPbuffer =
+    epoxy_has_wgl_extension (display_win32->dummy_hdc, "WGL_ARB_pbuffer");
+  display_win32->hasWglARBRenderTexture =
+    epoxy_has_wgl_extension (display_win32->dummy_hdc, "WGL_ARB_render_texture");
+  display_win32->hasWglEXTSwapControl =
+    epoxy_has_wgl_extension (display_win32->dummy_hdc, "WGL_EXT_swap_control");
+  display_win32->hasWglOMLSyncControl =
+    epoxy_has_wgl_extension (display_win32->dummy_hdc, "WGL_OML_sync_control");
+
+  GDK_NOTE (OPENGL,
+            g_print ("WGL API version %d.%d found\n"
+                     " - Vendor: %s\n"
+                     " - Checked extensions:\n"
+                     "\t* WGL_ARB_create_context: %s\n"
+                     "\t* WGL_ARB_pbuffer: %s\n"
+                     "\t* WGL_ARB_render_texture: %s\n"
+                     "\t* WGL_EXT_swap_control: %s\n"
+                     "\t* WGL_OML_sync_control: %s\n",
+                     display_win32->gl_version / 10,
+                     display_win32->gl_version % 10,
+                     glGetString (GL_VENDOR),
+                     display_win32->hasWglARBCreateContext ? "yes" : "no",
+                     display_win32->hasWglARBPbuffer ? "yes" : "no",
+                     display_win32->hasWglARBRenderTexture ? "yes" : "no",
+                     display_win32->hasWglEXTSwapControl ? "yes" : "no",
+                     display_win32->hasWglOMLSyncControl ? "yes" : "no"));
+
+  return TRUE;
+}
+
+static HGLRC
+_create_legacy_gl_context (HDC hdc, GdkGLContext *share)
+{
+  HGLRC hglrc, hglrc2;
+
+  hglrc = wglCreateContext (hdc);
+
+  if (share != NULL)
+    {
+      hglrc2 = GDK_WIN32_GL_CONTEXT (share)->hglrc;
+      wglShareLists (hglrc2, hglrc);
+    }
+  
+  return hglrc;
+}
+
+static HGLRC
+_create_gl3_context (HDC hdc,
+                     GdkGLContext *share,
+                     GdkWin32Display *display)
+{
+  HGLRC hglrc;
+  GdkWin32GLContext *context_win32;
+
+  gint attribs[] = {
+    WGL_CONTEXT_PROFILE_MASK_ARB,  WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
+    WGL_CONTEXT_FLAGS_ARB,         WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
+    WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
+    WGL_CONTEXT_MINOR_VERSION_ARB, 2,
+    0
+  };
+
+  /* Use the dummy GL Context We had earlier... */
+  if (!wglMakeCurrent (hdc, display->dummy_hglrc))
+    return NULL;
+
+  if (share != NULL)
+    context_win32 = GDK_WIN32_GL_CONTEXT (share);
+
+
+  hglrc = wglCreateContextAttribsARB (hdc,
+                                      share != NULL ? context_win32->hglrc : NULL,
+                                      attribs);
+
+  wglMakeCurrent (NULL, NULL);
+
+  return hglrc;
+}
+
+static gboolean
+set_pixformat_for_hdc (HDC hdc, gint *best_idx, GError **error)
+{
+  PIXELFORMATDESCRIPTOR pfd;
+  gboolean set_pixel_format_result = FALSE;
+
+  /* one is only allowed to call SetPixelFormat(), and so ChoosePixelFormat()
+     one single time per window HDC */
+  *best_idx = get_wgl_pfd (hdc, &pfd);
+  if (*best_idx != 0)
+    set_pixel_format_result = SetPixelFormat (hdc, *best_idx, &pfd);
+
+  /* ChoosePixelFormat() or SetPixelFormat() failed, bail out */
+  if (*best_idx == 0 || !set_pixel_format_result)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+                           _("No available configurations for the given pixel format"));
+    }
+  return set_pixel_format_result;
+}
+
+GdkGLContext *
+_gdk_win32_window_create_gl_context (GdkWindow *window,
+                                     gboolean attached,
+                                     GdkGLProfile profile,
+                                     GdkGLContext *share,
+                                     GError **error)
+{
+  GdkDisplay *display = gdk_window_get_display (window);
+  GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_window_get_display (window));
+  GdkWin32GLContext *context = NULL;
+  GdkVisual *visual = NULL;
+
+  /* Real GL Context and Window items */
+  HWND hwnd = GDK_WINDOW_HWND (window);
+  HDC hdc = GetDC (hwnd);
+  HGLRC hglrc;
+  gint pixel_format;
+
+  if (!gdk_win32_display_init_gl (display))
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_NOT_AVAILABLE,
+                           _("No GL implementation is available"));
+      return NULL;
+    }
+
+  if (profile == GDK_GL_PROFILE_3_2_CORE &&
+      !display_win32->hasWglARBCreateContext)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_UNSUPPORTED_PROFILE,
+                           _("The WGL_ARB_create_context extension "
+                             "needed to create 3.2 core profiles is not "
+                             "available"));
+      return NULL;
+    }
+
+  if (!set_pixformat_for_hdc (hdc, &pixel_format, error))
+    return NULL;
+
+  if (profile == GDK_GL_PROFILE_3_2_CORE)
+    hglrc = _create_gl3_context (hdc, share, display_win32);
+  else
+    {
+      profile = GDK_GL_PROFILE_LEGACY;
+      hglrc = _create_legacy_gl_context (hdc, share);
+    }
+
+  if (hglrc == NULL)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_NOT_AVAILABLE,
+                           _("Unable to create a GL context"));
+      return NULL;
+    }
+
+  display_win32->gl_hdc = hdc;
+  display_win32->gl_hwnd = hwnd;
+
+  GDK_NOTE (OPENGL,
+            g_print ("Created WGL context[%p], pixel_format=%d\n",
+                     hglrc,
+                     pixel_format));
+
+  context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT,
+                          "display", display,
+                          "window", window,
+                          "profile", profile,
+                          "shared-context", share,
+                          NULL);
+
+  context->hglrc = hglrc;
+  context->is_attached = attached;
+
+  return GDK_GL_CONTEXT (context);
+}
+
+gboolean
+_gdk_win32_display_make_gl_context_current (GdkDisplay *display,
+                                            GdkGLContext *context)
+{
+  GdkWin32GLContext *context_win32;
+  GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
+
+  if (context == NULL)
+    {
+      wglMakeCurrent(NULL, NULL);
+      return TRUE;
+    }
+
+  context_win32 = GDK_WIN32_GL_CONTEXT (context);
+
+  /* if we are on the same GL HDC, don't bother further, just return TRUE */
+  if (display_win32->gl_hdc == context_win32->gl_hdc)
+    return TRUE;
+
+  if (!wglMakeCurrent (display_win32->gl_hdc, context_win32->hglrc))
+    {
+      GDK_NOTE (OPENGL,
+                g_print ("Making WGL context current failed\n"));
+      return FALSE;
+    }
+
+  context_win32->gl_hdc = display_win32->gl_hdc;
+
+
+  if (display_win32->hasWglEXTSwapControl)
+    if (context_win32->is_attached)
+      wglSwapIntervalEXT (1);
+    else
+      wglSwapIntervalEXT (0);
+
+  return TRUE;
+}
+
+gboolean
+gdk_win32_display_get_wgl_version (GdkDisplay *display,
+                                   gint *major,
+                                   gint *minor)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  if (!GDK_IS_WIN32_DISPLAY (display))
+    return FALSE;
+
+  if (!gdk_win32_display_init_gl (display))
+    return FALSE;
+
+  if (major != NULL)
+    *major = GDK_WIN32_DISPLAY (display)->gl_version / 10;
+  if (minor != NULL)
+    *minor = GDK_WIN32_DISPLAY (display)->gl_version % 10;
+
+  return TRUE;
+}
\ No newline at end of file
diff --git a/gdk/win32/gdkglcontext-win32.h b/gdk/win32/gdkglcontext-win32.h
new file mode 100644
index 0000000..d6b3d38
--- /dev/null
+++ b/gdk/win32/gdkglcontext-win32.h
@@ -0,0 +1,84 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontext-win32.h: Private Win32 specific OpenGL wrappers
+ *
+ * Copyright © 2014 Chun-wei Fan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_WIN32_GL_CONTEXT__
+#define __GDK_WIN32_GL_CONTEXT__
+
+#include <epoxy/gl.h>
+#include <epoxy/wgl.h>
+
+#include "gdkglcontextprivate.h"
+#include "gdkdisplayprivate.h"
+#include "gdkvisual.h"
+#include "gdkwindow.h"
+#include "gdkinternals.h"
+#include "gdkmain.h"
+
+G_BEGIN_DECLS
+
+struct _GdkWin32GLContext
+{
+  GdkGLContext parent_instance;
+
+  /* Real items */
+  HGLRC hglrc;
+  HDC gl_hdc;
+
+  /* other items */
+  gboolean is_attached;
+  gboolean do_blit_swap;
+};
+
+struct _GdkWin32GLContextClass
+{
+  GdkGLContextClass parent_class;
+};
+
+gboolean
+gdk_win32_display_init_gl (GdkDisplay *display);
+
+GdkGLContext *
+_gdk_win32_window_create_gl_context (GdkWindow *window,
+                                     gboolean attached,
+                                     GdkGLProfile profile,
+                                     GdkGLContext *share,
+                                     GError **error);
+
+void
+_gdk_win32_window_invalidate_for_new_frame (GdkWindow *window,
+                                            cairo_region_t *update_area);
+
+void
+_gdk_win32_gl_context_end_frame (GdkGLContext *context,
+                                 cairo_region_t *painted,
+                                 cairo_region_t *damage);
+
+gboolean
+_gdk_win32_gl_context_texture_from_surface (GdkGLContext *paint_context,
+                                            cairo_surface_t *surface,
+                                            cairo_region_t *region);
+
+gboolean
+_gdk_win32_display_make_gl_context_current (GdkDisplay *display,
+                                            GdkGLContext *context);
+
+G_END_DECLS
+
+#endif /* __GDK_WIN32_GL_CONTEXT__ */
diff --git a/gdk/win32/gdkglobals-win32.c b/gdk/win32/gdkglobals-win32.c
index 5248a00..3752f3f 100644
--- a/gdk/win32/gdkglobals-win32.c
+++ b/gdk/win32/gdkglobals-win32.c
@@ -82,3 +82,11 @@ gboolean       _ignore_destroy_clipboard = FALSE;
 
 HGLOBAL           _delayed_rendering_data = NULL;
 GHashTable       *_format_atom_table = NULL;
+
+gboolean         _have_wgl;
+gint             _gl_version;
+HDC              _gl_hdc;
+
+gboolean    _hasWglARBCreateContext;
+gboolean    _hasWglEXTSwapControl;
+gboolean    _hasWglOMLSyncControl;
\ No newline at end of file
diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c
index 905c729..10488dd 100644
--- a/gdk/win32/gdkmain-win32.c
+++ b/gdk/win32/gdkmain-win32.c
@@ -129,7 +129,7 @@ _gdk_win32_windowing_init (void)
 
   _cf_url = RegisterClipboardFormat ("UniformResourceLocatorW");
   _cf_html_format = RegisterClipboardFormat ("HTML Format");
-  _cf_text_html = RegisterClipboardFormat ("text/html");
+  _cf_text_html = RegisterClipboardFormat ("text/html");
 
   _gdk_win32_selection_init ();
 }
diff --git a/gdk/win32/gdkwin32.h b/gdk/win32/gdkwin32.h
index 5256392..4550dc7 100644
--- a/gdk/win32/gdkwin32.h
+++ b/gdk/win32/gdkwin32.h
@@ -35,6 +35,7 @@
 #include <gdk/win32/gdkwin32screen.h>
 #include <gdk/win32/gdkwin32window.h>
 #include <gdk/win32/gdkwin32misc.h>
+#include <gdk/win32/gdkwin32glcontext.h>
 
 #undef __GDKWIN32_H_INSIDE__
 
diff --git a/gdk/win32/gdkwin32glcontext.h b/gdk/win32/gdkwin32glcontext.h
new file mode 100644
index 0000000..cd5ffda
--- /dev/null
+++ b/gdk/win32/gdkwin32glcontext.h
@@ -0,0 +1,49 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontext-win32.c: Win32 specific OpenGL wrappers
+ * 
+ * Copyright © 2014  Chun-wei Fan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_WIN32_GL_CONTEXT_H__
+#define __GDK_WIN32_GL_CONTEXT_H__
+
+#if !defined (__GDKWIN32_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdkwin32.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_WIN32_GL_CONTEXT              (gdk_win32_gl_context_get_type ())
+#define GDK_WIN32_GL_CONTEXT(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GDK_TYPE_WIN32_GL_CONTEXT, GdkWin32GLContext))
+#define GDK_WIN32_IS_GL_CONTEXT(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_WIN32_GL_CONTEXT))
+
+typedef struct _GdkWin32GLContext              GdkWin32GLContext;
+typedef struct _GdkWin32GLContextClass GdkWin32GLContextClass;
+
+GDK_AVAILABLE_IN_3_16
+GType gdk_win32_gl_context_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_3_16
+gboolean        gdk_win32_display_get_wgl_version (GdkDisplay *display,
+                                                   gint       *major,
+                                                   gint       *minor);
+
+G_END_DECLS
+
+#endif /* __GDK_WIN32_GL_CONTEXT_H__ */
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index 7b4bd79..c83d29e 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -38,6 +38,7 @@
 #include "gdkdisplayprivate.h"
 #include "gdkvisualprivate.h"
 #include "gdkwin32window.h"
+#include "gdkglcontext-win32.h"
 
 #include <cairo-win32.h>
 
@@ -337,12 +338,13 @@ RegisterGdkClass (GdkWindowType wtype, GdkWindowTypeHint wtype_hint)
     {
     case GDK_WINDOW_TOPLEVEL:
       if (0 == klassTOPLEVEL)
-       {
-         wcl.lpszClassName = L"gdkWindowToplevel";
-         
-         ONCE_PER_CLASS ();
-         klassTOPLEVEL = RegisterClassExW (&wcl);
-       }
+        {
+          wcl.lpszClassName = L"gdkWindowToplevel";
+
+          ONCE_PER_CLASS ();
+          klassTOPLEVEL = RegisterClassExW (&wcl);
+        }
+      wcl.style |= CS_OWNDC;
       klass = klassTOPLEVEL;
       break;
       
@@ -523,11 +525,11 @@ _gdk_win32_display_create_window_impl (GdkDisplay    *display,
          dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN;
        }
       else
-       {
+       { 
          if (window->window_type == GDK_WINDOW_TOPLEVEL)
-           dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
+      dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
          else
-           dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | 
WS_CLIPCHILDREN;
+      dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN;
 
          offset_x = _gdk_offset_x;
          offset_y = _gdk_offset_y;
@@ -3440,6 +3442,10 @@ gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
   impl_class->get_property = _gdk_win32_window_get_property;
   impl_class->change_property = _gdk_win32_window_change_property;
   impl_class->delete_property = _gdk_win32_window_delete_property;
+
+  impl_class->create_gl_context = _gdk_win32_window_create_gl_context;
+  impl_class->invalidate_for_new_frame = _gdk_win32_window_invalidate_for_new_frame;
+
 }
 
 HGDIOBJ



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]