wgl: Fix window resizing in multithread applications.
authorJosé Fonseca <jfonseca@vmware.com>
Wed, 17 Jun 2009 20:28:18 +0000 (21:28 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Thu, 18 Jun 2009 13:54:07 +0000 (14:54 +0100)
In multithreading stw_call_window_proc can be called by a thread other
than the thread where the context is bound.

src/gallium/state_trackers/wgl/shared/stw_context.c
src/gallium/state_trackers/wgl/shared/stw_device.c
src/gallium/state_trackers/wgl/shared/stw_framebuffer.c
src/gallium/state_trackers/wgl/shared/stw_framebuffer.h

index 1c217699ab1e26e6bb0c8841be8f10f324b57cc2..9df1ab765262da231bb7a205f4f72e3009a738ab 100644 (file)
@@ -116,6 +116,18 @@ stw_share_lists(
    return ret;
 }
 
+static void
+stw_viewport(GLcontext * glctx, GLint x, GLint y,
+             GLsizei width, GLsizei height)
+{
+   struct stw_context *ctx = (struct stw_context *)glctx->DriverCtx;
+   struct stw_framebuffer *fb;
+   
+   fb = stw_framebuffer_from_hdc( ctx->hdc );
+   if(fb)
+      stw_framebuffer_update(fb);
+}
+
 UINT_PTR
 stw_create_layer_context(
    HDC hdc,
@@ -175,6 +187,7 @@ stw_create_layer_context(
       goto no_st_ctx;
 
    ctx->st->ctx->DriverCtx = ctx;
+   ctx->st->ctx->Driver.Viewport = stw_viewport;
 
    pipe_mutex_lock( stw_dev->mutex );
    ctx->hglrc = handle_table_add(stw_dev->ctx_table, ctx);
@@ -298,8 +311,11 @@ stw_make_current(
         st_flush(curctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
       
       /* Return if already current. */
-      if (curctx->hglrc == hglrc && curctx->hdc == hdc)
-         return TRUE;
+      if (curctx->hglrc == hglrc && curctx->hdc == hdc) {
+         ctx = curctx;
+         fb = stw_framebuffer_from_hdc( hdc );
+         goto success;
+      }
    }
 
    if (hdc == NULL || hglrc == 0) {
@@ -343,7 +359,10 @@ stw_make_current(
    if(!st_make_current( ctx->st, fb->stfb, fb->stfb ))
       goto fail;
 
-   stw_framebuffer_resize(fb);
+success:
+   assert(fb);
+   if(fb)
+      stw_framebuffer_update(fb);
    
    return TRUE;
 
index 070ffcb3ca10449e66ee0a0535f5a7100de2dd3c..1b4a2d5cdbdff49a6d8fbbc5ead2c4e3a6b32ed4 100644 (file)
@@ -30,6 +30,7 @@
 #include "glapi/glthread.h"
 #include "util/u_debug.h"
 #include "pipe/p_screen.h"
+#include "state_tracker/st_public.h"
 
 #ifdef DEBUG
 #include "trace/tr_screen.h"
@@ -63,7 +64,26 @@ stw_flush_frontbuffer(struct pipe_screen *screen,
 {
    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 );
+   assert(fb);
+   if (fb == NULL)
+      return;
+
+   pipe_mutex_lock( fb->mutex );
+
+#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
+
 #ifdef DEBUG
    if(stw_dev->trace_running) {
       screen = trace_screen(screen)->screen;
@@ -72,6 +92,10 @@ stw_flush_frontbuffer(struct pipe_screen *screen,
 #endif
    
    stw_winsys->flush_frontbuffer(screen, surface, hdc);
+   
+   stw_framebuffer_update(fb);
+   
+   pipe_mutex_unlock( fb->mutex );
 }
 
 
index 88043859ce4e7d8e7ec31b09a8b60b83fb2fce45..7d0e8f46482bae963e0e9247c572595560c49388 100644 (file)
@@ -111,15 +111,10 @@ stw_call_window_proc(
          unsigned width = LOWORD( pParams->lParam );
          unsigned height = HIWORD( pParams->lParam );
          
-         /* FIXME: The mesa statetracker makes the assumptions that only
-          * one context is using the framebuffer, and that that context is the 
-          * current one. However neither holds true, as WGL allows more than
-          * one context to be bound to the same drawable, and this function can 
-          * be called from any thread.
-          */
          pipe_mutex_lock( fb->mutex );
-         if (fb->stfb)
-            st_resize_framebuffer( fb->stfb, width, height );
+         fb->must_resize = TRUE;
+         fb->width = width;
+         fb->height = height;
          pipe_mutex_unlock( fb->mutex );
       }
    }
@@ -140,6 +135,31 @@ stw_call_window_proc(
 }
 
 
+static void
+stw_framebuffer_get_size( struct stw_framebuffer *fb )
+{
+   unsigned width, height;
+   RECT rect;
+
+   assert(fb->hWnd);
+   
+   GetClientRect( fb->hWnd, &rect );
+   width = rect.right - rect.left;
+   height = rect.bottom - rect.top;
+
+   if(width < 1)
+      width = 1;
+   if(height < 1)
+      height = 1;
+
+   if(width != fb->width || height != fb->height) {
+      fb->must_resize = TRUE;
+      fb->width = width; 
+      fb->height = height; 
+   }
+}
+
+
 /**
  * Create a new framebuffer object which will correspond to the given HDC.
  */
@@ -169,6 +189,8 @@ stw_framebuffer_create_locked(
 
    stw_pixelformat_visual(&fb->visual, pfi);
    
+   stw_framebuffer_get_size(fb);
+
    pipe_mutex_init( fb->mutex );
 
    fb->next = stw_dev->fb_head;
@@ -178,32 +200,6 @@ stw_framebuffer_create_locked(
 }
 
 
-static void
-stw_framebuffer_get_size( struct stw_framebuffer *fb, GLuint *pwidth, GLuint *pheight )
-{
-   GLuint width, height;
-
-   if (fb->hWnd) {
-      RECT rect;
-      GetClientRect( fb->hWnd, &rect );
-      width = rect.right - rect.left;
-      height = rect.bottom - rect.top;
-   }
-   else {
-      width = GetDeviceCaps( fb->hDC, HORZRES );
-      height = GetDeviceCaps( fb->hDC, VERTRES );
-   }
-
-   if(width < 1)
-      width = 1;
-   if(height < 1)
-      height = 1;
-
-   *pwidth = width; 
-   *pheight = height; 
-}
-
-
 BOOL
 stw_framebuffer_allocate(
    struct stw_framebuffer *fb)
@@ -213,7 +209,6 @@ stw_framebuffer_allocate(
    if(!fb->stfb) {
       const struct stw_pixelformat_info *pfi = fb->pfi;
       enum pipe_format colorFormat, depthFormat, stencilFormat;
-      GLuint width, height; 
 
       colorFormat = pfi->color_format;
       
@@ -229,16 +224,21 @@ stw_framebuffer_allocate(
       else
          stencilFormat = PIPE_FORMAT_NONE;
    
-      stw_framebuffer_get_size(fb, &width, &height);
-      
+      assert(fb->must_resize);
+      assert(fb->width);
+      assert(fb->height);
+
       fb->stfb = st_create_framebuffer(
          &fb->visual,
          colorFormat,
          depthFormat,
          stencilFormat,
-         width,
-         height,
+         fb->width,
+         fb->height,
          (void *) fb );
+      
+      // to notify the context
+      fb->must_resize = TRUE;
    }
    
    pipe_mutex_unlock( fb->mutex );
@@ -247,14 +247,29 @@ stw_framebuffer_allocate(
 }
 
 
+/**
+ * Update the framebuffer's size if necessary.
+ */
 void
-stw_framebuffer_resize(
+stw_framebuffer_update(
    struct stw_framebuffer *fb)
 {
-   GLuint width, height; 
    assert(fb->stfb);
-   stw_framebuffer_get_size(fb, &width, &height);
-   st_resize_framebuffer(fb->stfb, width, height);
+   assert(fb->height);
+   assert(fb->width);
+   
+   /* XXX: It would be nice to avoid checking the size again -- in theory  
+    * stw_call_window_proc would have cought the resize and stored the right 
+    * size already, but unfortunately threads created before the DllMain is 
+    * called don't get a DLL_THREAD_ATTACH notification, and there is no way
+    * to know of their existing without using the not very portable PSAPI.
+    */
+   stw_framebuffer_get_size(fb);
+   
+   if(fb->must_resize) {
+      st_resize_framebuffer(fb->stfb, fb->width, fb->height);
+      fb->must_resize = FALSE;
+   }
 }                      
 
 
@@ -407,6 +422,8 @@ stw_swap_buffers(
 
    stw_dev->stw_winsys->flush_frontbuffer( screen, surface, hdc );
    
+   stw_framebuffer_update(fb);
+   
    pipe_mutex_unlock( fb->mutex );
    
    return TRUE;
index d6f5950ac3e948d4661a45984c3070d456dfe68c..759e06b89147ed7c508b1d7ac644dff1522da83d 100644 (file)
@@ -51,6 +51,11 @@ struct stw_framebuffer
    pipe_mutex mutex;
    struct st_framebuffer *stfb;
    
+   /* FIXME: Make this work for multiple contexts bound to the same framebuffer */
+   boolean must_resize;
+   unsigned width;
+   unsigned height;
+   
    /** This is protected by stw_device::mutex, not the mutex above */
    struct stw_framebuffer *next;
 };
@@ -65,7 +70,7 @@ stw_framebuffer_allocate(
    struct stw_framebuffer *fb );
 
 void
-stw_framebuffer_resize(
+stw_framebuffer_update(
    struct stw_framebuffer *fb);
 
 void