wgl: DWM integration.
authorJosé Fonseca <jfonseca@vmware.com>
Thu, 24 Sep 2009 12:08:34 +0000 (13:08 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Thu, 24 Sep 2009 12:12:51 +0000 (13:12 +0100)
src/gallium/state_trackers/wgl/opengl32.def
src/gallium/state_trackers/wgl/opengl32.mingw.def
src/gallium/state_trackers/wgl/stw_device.c
src/gallium/state_trackers/wgl/stw_device.h
src/gallium/state_trackers/wgl/stw_framebuffer.c
src/gallium/state_trackers/wgl/stw_framebuffer.h
src/gallium/state_trackers/wgl/stw_icd.h
src/gallium/state_trackers/wgl/stw_pixelformat.c
src/gallium/state_trackers/wgl/stw_pixelformat.h
src/gallium/state_trackers/wgl/stw_winsys.h

index 596417ed8443255a94cbb765d12ff550166f64b0..5daa6ddd413b1c9ed9586755fb81365d2f18d34b 100644 (file)
@@ -376,6 +376,7 @@ EXPORTS
        DrvDescribePixelFormat
        DrvGetLayerPaletteEntries
        DrvGetProcAddress
+       DrvPresentBuffers
        DrvRealizeLayerPalette
        DrvReleaseContext
        DrvSetCallbackProcs
index 1f03ea3b375952078d69d2f2e9247f9236ef83d0..6ebb31a6f1bba61b4ab6af28f2a8ad6f55abe086 100644 (file)
@@ -375,6 +375,7 @@ EXPORTS
        DrvDescribePixelFormat = DrvDescribePixelFormat@16
        DrvGetLayerPaletteEntries = DrvGetLayerPaletteEntries@20
        DrvGetProcAddress = DrvGetProcAddress@4
+       DrvPresentBuffers = DrvPresentBuffers@8
        DrvRealizeLayerPalette = DrvRealizeLayerPalette@12
        DrvReleaseContext = DrvReleaseContext@4
        DrvSetCallbackProcs = DrvSetCallbackProcs@8
index a1a5b892ef53200f395af2b827587f6432be798b..985b8f0456a9f6f36cd631d72c3e46d665836b31 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "glapi/glthread.h"
 #include "util/u_debug.h"
+#include "util/u_math.h"
 #include "pipe/p_screen.h"
 #include "state_tracker/st_public.h"
 
@@ -62,38 +63,28 @@ stw_flush_frontbuffer(struct pipe_screen *screen,
                      struct pipe_surface *surface,
                      void *context_private )
 {
-   const struct stw_winsys *stw_winsys = stw_dev->stw_winsys;
    HDC hdc = (HDC)context_private;
    struct stw_framebuffer *fb;
    
    fb = stw_framebuffer_from_hdc( hdc );
-   /* fb can be NULL if window was destroyed already */
-   if (fb) {
+   if (!fb) {
+      /* fb can be NULL if window was destroyed already */
+      return;
+   }
+
 #if DEBUG
-      {
-         struct pipe_surface *surface2;
-   
-         if(!st_get_framebuffer_surface( fb->stfb, ST_SURFACE_FRONT_LEFT, &surface2 ))
-            assert(0);
-         else
-            assert(surface2 == surface);
-      }
-#endif
+   {
+      /* ensure that a random surface was not passed to us */
+      struct pipe_surface *surface2;
 
-#ifdef DEBUG
-      if(stw_dev->trace_running) {
-         screen = trace_screen(screen)->screen;
-         surface = trace_surface(surface)->surface;
-      }
-#endif
-   }
-   
-   stw_winsys->flush_frontbuffer(screen, surface, hdc);
-   
-   if(fb) {
-      stw_framebuffer_update(fb);
-      stw_framebuffer_release(fb);
+      if(!st_get_framebuffer_surface( fb->stfb, ST_SURFACE_FRONT_LEFT, &surface2 ))
+         assert(0);
+      else
+         assert(surface2 == surface);
    }
+#endif
+
+   stw_framebuffer_present_locked(hdc, fb, ST_SURFACE_FRONT_LEFT);
 }
 
 
@@ -126,6 +117,9 @@ stw_init(const struct stw_winsys *stw_winsys)
    if(!screen)
       goto error1;
 
+   if(stw_winsys->get_adapter_luid)
+      stw_winsys->get_adapter_luid(screen, &stw_dev->AdapterLuid);
+
 #ifdef DEBUG
    stw_dev->screen = trace_screen_create(screen);
    stw_dev->trace_running = stw_dev->screen != screen ? TRUE : FALSE;
@@ -229,6 +223,14 @@ DrvSetCallbackProcs(
    INT nProcs,
    PROC *pProcs )
 {
+   size_t size;
+
+   if (stw_dev == NULL)
+      return;
+
+   size = MIN2(nProcs * sizeof *pProcs, sizeof stw_dev->callbacks);
+   memcpy(&stw_dev->callbacks, pProcs, size);
+
    return;
 }
 
index 5e4e3d618021198633f0edd15332b400b60759c5..0bf3b0da82502c424ec94cf0d1bc06dd5d38bdc1 100644 (file)
@@ -52,10 +52,14 @@ struct stw_device
    boolean trace_running;
 #endif
 
+   LUID AdapterLuid;
+
    struct stw_pixelformat_info pixelformats[STW_MAX_PIXELFORMATS];
    unsigned pixelformat_count;
    unsigned pixelformat_extended_count;
 
+   GLCALLBACKTABLE callbacks;
+
    pipe_mutex ctx_mutex;
    struct handle_table *ctx_table;
    
index 123b841c8f3eda25d77676be469ab7b3825b61c1..8a3e11b6b4075cd71b0765c537a81c0164e41902 100644 (file)
@@ -1,8 +1,8 @@
 /**************************************************************************
- * 
- * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ *
+ * Copyright 2008-2009 Vmware, Inc.
  * All Rights Reserved.
- * 
+ *
  * 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
  * distribute, sub license, 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 NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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 <windows.h>
@@ -83,6 +83,9 @@ stw_framebuffer_destroy_locked(
    *link = fb->next;
    fb->next = NULL;
 
+   if(fb->shared_surface)
+      stw_dev->stw_winsys->shared_surface_close(stw_dev->screen, fb->shared_surface);
+
    st_unreference_framebuffer(fb->stfb);
    
    pipe_mutex_unlock( fb->mutex );
@@ -106,13 +109,18 @@ static INLINE void
 stw_framebuffer_get_size( struct stw_framebuffer *fb )
 {
    unsigned width, height;
-   RECT rect;
+   RECT client_rect;
+   RECT window_rect;
+   POINT client_pos;
 
    assert(fb->hWnd);
    
-   GetClientRect( fb->hWnd, &rect );
-   width = rect.right - rect.left;
-   height = rect.bottom - rect.top;
+   /* Get the client area size. */
+   GetClientRect( fb->hWnd, &client_rect );
+   assert(client_rect.left == 0);
+   assert(client_rect.top == 0);
+   width = client_rect.right - client_rect.left;
+   height = client_rect.bottom - client_rect.top;
 
    if(width < 1)
       width = 1;
@@ -124,6 +132,31 @@ stw_framebuffer_get_size( struct stw_framebuffer *fb )
       fb->width = width; 
       fb->height = height; 
    }
+
+   client_pos.x = 0;
+   client_pos.y = 0;
+   ClientToScreen(fb->hWnd, &client_pos);
+
+   GetWindowRect(fb->hWnd, &window_rect);
+
+   fb->client_rect.left = client_pos.x - window_rect.left;
+   fb->client_rect.top =  client_pos.y - window_rect.top;
+   fb->client_rect.right = fb->client_rect.left + fb->width;
+   fb->client_rect.bottom = fb->client_rect.top + fb->height;
+
+#if 0
+   debug_printf("\n");
+   debug_printf("%s: client_position = (%i, %i)\n",
+                __FUNCTION__, client_pos.x, client_pos.y);
+   debug_printf("%s: window_rect = (%i, %i) - (%i, %i)\n",
+                __FUNCTION__,
+                window_rect.left, window_rect.top,
+                window_rect.right, window_rect.bottom);
+   debug_printf("%s: client_rect = (%i, %i) - (%i, %i)\n",
+                __FUNCTION__,
+                fb->client_rect.left, fb->client_rect.top,
+                fb->client_rect.right, fb->client_rect.bottom);
+#endif
 }
 
 
@@ -155,6 +188,7 @@ stw_call_window_proc(
        * can be masked out by the application. */
       LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam;
       if((lpWindowPos->flags & SWP_SHOWWINDOW) || 
+         !(lpWindowPos->flags & SWP_NOMOVE) ||
          !(lpWindowPos->flags & SWP_NOSIZE)) {
          fb = stw_framebuffer_from_hwnd( pParams->hwnd );
          if(fb) {
@@ -436,34 +470,23 @@ stw_pixelformat_get(
 
 
 BOOL APIENTRY
-DrvSwapBuffers(
-   HDC hdc )
+DrvPresentBuffers(HDC hdc, PGLPRESENTBUFFERSDATA data)
 {
    struct stw_framebuffer *fb;
    struct pipe_screen *screen;
    struct pipe_surface *surface;
+   unsigned surface_index;
+   BOOL ret = FALSE;
 
    fb = stw_framebuffer_from_hdc( hdc );
    if (fb == NULL)
       return FALSE;
 
-   if (!(fb->pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) {
-      stw_framebuffer_release(fb);
-      return TRUE;
-   }
-
-   /* If we're swapping the buffer associated with the current context
-    * we have to flush any pending rendering commands first.
-    */
-   st_notify_swapbuffers( fb->stfb );
-
    screen = stw_dev->screen;
-   
-   if(!st_get_framebuffer_surface( fb->stfb, ST_SURFACE_BACK_LEFT, &surface )) {
-      /* FIXME: this shouldn't happen, but does on glean */
-      stw_framebuffer_release(fb);
-      return FALSE;
-   }
+
+   surface_index = (unsigned)(uintptr_t)data->pPrivateData;
+   if(!st_get_framebuffer_surface( fb->stfb, surface_index, &surface ))
+      goto fail;
 
 #ifdef DEBUG
    if(stw_dev->trace_running) {
@@ -472,12 +495,117 @@ DrvSwapBuffers(
    }
 #endif
 
-   stw_dev->stw_winsys->flush_frontbuffer( screen, surface, hdc );
-   
+   if(data->hSharedSurface != fb->hSharedSurface) {
+      if(fb->shared_surface) {
+         stw_dev->stw_winsys->shared_surface_close(screen, fb->shared_surface);
+         fb->shared_surface = NULL;
+      }
+
+      fb->hSharedSurface = data->hSharedSurface;
+
+      if(data->hSharedSurface &&
+         stw_dev->stw_winsys->shared_surface_open) {
+         fb->shared_surface = stw_dev->stw_winsys->shared_surface_open(screen, fb->hSharedSurface);
+      }
+   }
+
+   if(fb->shared_surface) {
+      stw_dev->stw_winsys->compose(screen,
+                                   surface,
+                                   fb->shared_surface,
+                                   &fb->client_rect,
+                                   data->PresentHistoryToken);
+   }
+   else {
+      stw_dev->stw_winsys->present( screen, surface, hdc );
+   }
+
+   ret = TRUE;
+
+fail:
+
    stw_framebuffer_update(fb);
+
    stw_framebuffer_release(fb);
-   
-   return TRUE;
+
+   return ret;
+}
+
+
+/**
+ * Queue a composition.
+ *
+ * It will drop the lock on success.
+ */
+BOOL
+stw_framebuffer_present_locked(HDC hdc,
+                               struct stw_framebuffer *fb,
+                               unsigned surface_index)
+{
+   if(stw_dev->callbacks.wglCbPresentBuffers &&
+      stw_dev->stw_winsys->compose) {
+      GLCBPRESENTBUFFERSDATA data;
+
+      memset(&data, 0, sizeof data);
+      data.magic1 = 2;
+      data.magic2 = 0;
+      data.AdapterLuid = stw_dev->AdapterLuid;
+      data.rect = fb->client_rect;
+      data.pPrivateData = (void *)(uintptr_t)surface_index;
+
+      stw_framebuffer_release(fb);
+
+      return stw_dev->callbacks.wglCbPresentBuffers(hdc, &data);
+   }
+   else {
+      struct pipe_screen *screen = stw_dev->screen;
+      struct pipe_surface *surface;
+
+      if(!st_get_framebuffer_surface( fb->stfb, surface_index, &surface )) {
+         /* FIXME: this shouldn't happen, but does on glean */
+         stw_framebuffer_release(fb);
+         return FALSE;
+      }
+
+#ifdef DEBUG
+      if(stw_dev->trace_running) {
+         screen = trace_screen(screen)->screen;
+         surface = trace_surface(surface)->surface;
+      }
+#endif
+
+      stw_dev->stw_winsys->present( screen, surface, hdc );
+
+      stw_framebuffer_update(fb);
+
+      stw_framebuffer_release(fb);
+
+      return TRUE;
+   }
+}
+
+
+BOOL APIENTRY
+DrvSwapBuffers(
+   HDC hdc )
+{
+   struct stw_framebuffer *fb;
+
+   fb = stw_framebuffer_from_hdc( hdc );
+   if (fb == NULL)
+      return FALSE;
+
+   if (!(fb->pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) {
+      stw_framebuffer_release(fb);
+      return TRUE;
+   }
+
+   /* If we're swapping the buffer associated with the current context
+    * we have to flush any pending rendering commands first.
+    */
+   st_notify_swapbuffers( fb->stfb );
+
+   return stw_framebuffer_present_locked(hdc, fb, ST_SURFACE_BACK_LEFT);
 }
 
 
index 13d29f37e485b100dedf981fc12ca0649973b753..5afbe749086c82ce6f39ab75aa21b33f9e5c6df9 100644 (file)
@@ -73,9 +73,20 @@ struct stw_framebuffer
    
    /* FIXME: Make this work for multiple contexts bound to the same framebuffer */
    boolean must_resize;
+
    unsigned width;
    unsigned height;
    
+   /**
+    * Client area rectangle, relative to the window upper-left corner.
+    *
+    * @sa GLCBPRESENTBUFFERSDATA::rect.
+    */
+   RECT client_rect;
+
+   HANDLE hSharedSurface;
+   struct stw_shared_surface *shared_surface;
+
    /** 
     * This is protected by stw_device::fb_mutex, not the mutex above.
     * 
@@ -126,6 +137,11 @@ BOOL
 stw_framebuffer_allocate(
    struct stw_framebuffer *fb );
 
+BOOL
+stw_framebuffer_present_locked(HDC hdc,
+                               struct stw_framebuffer *fb,
+                               unsigned surface_index);
+
 void
 stw_framebuffer_update(
    struct stw_framebuffer *fb);
index cbc1a665481c94dfdce1deb336a2841a165bb001..02eb543fef020ab0dc2bee6c4de0878d3490c6c5 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2008-2009 Vmware, Inc.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -18,7 +18,7 @@
  * 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 NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
@@ -388,6 +388,113 @@ typedef struct _GLCLTPROCTABLE
 
 typedef VOID (APIENTRY * PFN_SETPROCTABLE)(PGLCLTPROCTABLE);
 
+/**
+ * Presentation data passed to opengl32!wglCbPresentBuffers.
+ *
+ * Pure software drivers don't need to worry about this -- if they stick to the
+ * GDI API then will integrate with the Desktop Window Manager (DWM) without
+ * problems. Hardware drivers, however, cannot present directly to the primary
+ * surface while the DWM is active, as DWM gets exclusive access to the primary
+ * surface.
+ *
+ * Proper DWM integration requires:
+ * - advertise the PFD_SUPPORT_COMPOSITION flag
+ * - redirect glFlush/glfinish/wglSwapBuffers into a surface shared with the
+ * DWM process.
+ *
+ * @sa http://www.opengl.org/pipeline/article/vol003_7/
+ * @sa http://blogs.msdn.com/greg_schechter/archive/2006/05/02/588934.aspx
+ */
+typedef struct _GLCBPRESENTBUFFERSDATA
+{
+   /**
+    * wglCbPresentBuffers enforces this to be 2.
+    */
+   DWORD magic1;
+
+   /**
+    * wglCbPresentBuffers enforces to be 0 or 1, but it is most commonly
+    * set to 0.
+    */
+   DWORD magic2;
+
+   /**
+    * Locally unique identifier (LUID) of the graphics adapter.
+    *
+    * This should contain the value returned by D3DKMTOpenAdapterFromHdc. It
+    * is passed to dwmapi!DwmpDxGetWindowSharedSurface in order to obtain
+    * the shared surface handle for the bound drawable (window).
+    *
+    * @sa http://msdn.microsoft.com/en-us/library/ms799177.aspx
+    */
+   LUID AdapterLuid;
+
+   /**
+    * This is passed unmodified to DrvPresentBuffers
+    */
+   LPVOID pPrivateData;
+
+   /**
+    * Client area rectangle to update, relative to the window upper-left corner.
+    */
+   RECT rect;
+} GLCBPRESENTBUFFERSDATA, *PGLCBPRESENTBUFFERSDATA;
+
+/**
+ * Callbacks supplied to DrvSetCallbackProcs by the OpenGL runtime.
+ *
+ * Pointers to several callback functions in opengl32.dll.
+ */
+typedef struct _GLCALLBACKTABLE
+{
+   /** Unused */
+   PROC wglCbSetCurrentValue;
+
+   /** Unused */
+   PROC wglCbGetCurrentValue;
+
+   /** Unused */
+   PROC wglCbGetDhglrc;
+
+   /** Unused */
+   PROC wglCbGetDdHandle;
+
+   /**
+    * Queue a present composition.
+    *
+    * Makes the runtime call DrvPresentBuffers with the composition information.
+    */
+   BOOL (APIENTRY *wglCbPresentBuffers)(HDC hdc, PGLCBPRESENTBUFFERSDATA data);
+
+} GLCALLBACKTABLE;
+
+typedef struct _GLPRESENTBUFFERSDATA
+{
+   /**
+    * The shared surface handle.
+    *
+    * Return by dwmapi!DwmpDxGetWindowSharedSurface.
+    *
+    * @sa http://channel9.msdn.com/forums/TechOff/251261-Help-Getting-the-shared-window-texture-out-of-DWM-/
+    */
+   HANDLE hSharedSurface;
+
+   LUID AdapterLuid;
+
+   /**
+    * Present history token.
+    *
+    * This is returned by dwmapi!DwmpDxGetWindowSharedSurface and
+    * should be passed to D3DKMTRender in D3DKMT_RENDER::PresentHistoryToken.
+    *
+    * @sa http://msdn.microsoft.com/en-us/library/ms799176.aspx
+    */
+   ULONGLONG PresentHistoryToken;
+
+   /** Same as GLCBPRESENTBUFFERSDATA::pPrivateData */
+   LPVOID pPrivateData;
+} GLPRESENTBUFFERSDATA, *PGLPRESENTBUFFERSDATA;
+
 BOOL APIENTRY
 DrvCopyContext(
    DHGLRC dhrcSource,
@@ -434,6 +541,9 @@ PROC APIENTRY
 DrvGetProcAddress(
    LPCSTR lpszProc );
 
+BOOL APIENTRY
+DrvPresentBuffers(HDC hdc, PGLPRESENTBUFFERSDATA data);
+
 BOOL APIENTRY
 DrvRealizeLayerPalette(
    HDC hdc,
index 9b591d5751d1b3571c36b8b535dedfbb1d0ef289..7abe5d9f7fa19a9cadaefc1dcccc31f6d295198b 100644 (file)
@@ -154,8 +154,11 @@ stw_pixelformat_add(
    pfi->pfd.dwFlags = PFD_SUPPORT_OPENGL;
    
    /* TODO: also support non-native pixel formats */
-   pfi->pfd.dwFlags |= PFD_DRAW_TO_WINDOW ;
-   
+   pfi->pfd.dwFlags |= PFD_DRAW_TO_WINDOW;
+
+   /* See http://www.opengl.org/pipeline/article/vol003_7/ */
+   pfi->pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;
+
    if (doublebuffer)
       pfi->pfd.dwFlags |= PFD_DOUBLEBUFFER | PFD_SWAP_COPY;
    
index 2fa7e22c4360c38bd03c25737d7aa3b834e27a2a..3a690b35badf09feddba7e014c241329800b9de2 100644 (file)
 
 #include <windows.h>
 
+#ifndef PFD_SUPPORT_COMPOSITION
+#define PFD_SUPPORT_COMPOSITION 0x00008000
+#endif
+
 #include "main/mtypes.h"
 
 #include "pipe/p_compiler.h"
index c0bf82c9ed7a7e488717622fa50e6ca8f62221c5..1ead47d6e637c35c5fe50c23cfa63afc14ca94ce 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2008-2009 Vmware, Inc.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -18,7 +18,7 @@
  * 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 NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
@@ -36,6 +36,8 @@ struct pipe_screen;
 struct pipe_context;
 struct pipe_surface;
 
+struct stw_shared_surface;
+
 struct stw_winsys
 {
    struct pipe_screen *
@@ -44,10 +46,52 @@ struct stw_winsys
    struct pipe_context *
    (*create_context)( struct pipe_screen *screen );
 
+   /**
+    * Present the color buffer to the window associated with the device context.
+    */
+   void
+   (*present)( struct pipe_screen *screen,
+               struct pipe_surface *surf,
+               HDC hDC );
+
+   /**
+    * Locally unique identifier (LUID) of the graphics adapter.
+    *
+    * @sa GLCBPRESENTBUFFERSDATA::AdapterLuid;
+    */
+   boolean
+   (*get_adapter_luid)( struct pipe_screen *screen,
+                        LUID *pAdapterLuid );
+
+   /**
+    * Open a shared surface (optional).
+    *
+    * @sa GLCBPRESENTBUFFERSDATA::hSharedSurface;
+    */
+   struct stw_shared_surface *
+   (*shared_surface_open)(struct pipe_screen *screen,
+                          HANDLE hSharedSurface);
+
+   /**
+    * Open a shared surface (optional).
+    */
+   void
+   (*shared_surface_close)(struct pipe_screen *screen,
+                           struct stw_shared_surface *surface);
+
+   /**
+    * Compose into a shared (optional).
+    *
+    * Blit the color buffer into a shared surface.
+    *
+    * @sa GLPRESENTBUFFERSDATA::PresentHistoryToken.
+    */
    void
-   (*flush_frontbuffer)( struct pipe_screen *screen,
-                         struct pipe_surface *surf,
-                         HDC hDC );
+   (*compose)( struct pipe_screen *screen,
+               struct pipe_surface *src,
+               struct stw_shared_surface *dest,
+               LPCRECT pRect,
+               ULONGLONG PresentHistoryToken );
 };
 
 boolean