diff options
Diffstat (limited to 'src/gallium/state_trackers/wgl')
5 files changed, 234 insertions, 123 deletions
diff --git a/src/gallium/state_trackers/wgl/shared/stw_context.c b/src/gallium/state_trackers/wgl/shared/stw_context.c index 9df1ab7652..4968ecc692 100644 --- a/src/gallium/state_trackers/wgl/shared/stw_context.c +++ b/src/gallium/state_trackers/wgl/shared/stw_context.c @@ -60,8 +60,14 @@ stw_context(GLcontext *glctx) static INLINE struct stw_context * stw_current_context(void) { - GET_CURRENT_CONTEXT( glctx ); - return stw_context(glctx); + /* We must check if multiple threads are being used or GET_CURRENT_CONTEXT + * might return the current context of the thread first seen. */ + _glapi_check_multithread(); + + { + GET_CURRENT_CONTEXT( glctx ); + return stw_context(glctx); + } } BOOL @@ -74,7 +80,7 @@ stw_copy_context( struct stw_context *dst; BOOL ret = FALSE; - pipe_mutex_lock( stw_dev->mutex ); + pipe_mutex_lock( stw_dev->ctx_mutex ); src = stw_lookup_context_locked( hglrcSrc ); dst = stw_lookup_context_locked( hglrcDst ); @@ -87,7 +93,7 @@ stw_copy_context( (void) mask; } - pipe_mutex_unlock( stw_dev->mutex ); + pipe_mutex_unlock( stw_dev->ctx_mutex ); return ret; } @@ -101,7 +107,7 @@ stw_share_lists( struct stw_context *ctx2; BOOL ret = FALSE; - pipe_mutex_lock( stw_dev->mutex ); + pipe_mutex_lock( stw_dev->ctx_mutex ); ctx1 = stw_lookup_context_locked( hglrc1 ); ctx2 = stw_lookup_context_locked( hglrc2 ); @@ -111,7 +117,7 @@ stw_share_lists( ret = _mesa_share_state(ctx2->st->ctx, ctx1->st->ctx); } - pipe_mutex_unlock( stw_dev->mutex ); + pipe_mutex_unlock( stw_dev->ctx_mutex ); return ret; } @@ -124,8 +130,10 @@ stw_viewport(GLcontext * glctx, GLint x, GLint y, struct stw_framebuffer *fb; fb = stw_framebuffer_from_hdc( ctx->hdc ); - if(fb) + if(fb) { stw_framebuffer_update(fb); + stw_framebuffer_release(fb); + } } UINT_PTR @@ -189,9 +197,9 @@ stw_create_layer_context( ctx->st->ctx->DriverCtx = ctx; ctx->st->ctx->Driver.Viewport = stw_viewport; - pipe_mutex_lock( stw_dev->mutex ); + pipe_mutex_lock( stw_dev->ctx_mutex ); ctx->hglrc = handle_table_add(stw_dev->ctx_table, ctx); - pipe_mutex_unlock( stw_dev->mutex ); + pipe_mutex_unlock( stw_dev->ctx_mutex ); if (!ctx->hglrc) goto no_hglrc; @@ -218,10 +226,10 @@ stw_delete_context( if (!stw_dev) return FALSE; - pipe_mutex_lock( stw_dev->mutex ); + pipe_mutex_lock( stw_dev->ctx_mutex ); ctx = stw_lookup_context_locked(hglrc); handle_table_remove(stw_dev->ctx_table, hglrc); - pipe_mutex_unlock( stw_dev->mutex ); + pipe_mutex_unlock( stw_dev->ctx_mutex ); if (ctx) { struct stw_context *curctx = stw_current_context(); @@ -248,9 +256,9 @@ stw_release_context( if (!stw_dev) return FALSE; - pipe_mutex_lock( stw_dev->mutex ); + pipe_mutex_lock( stw_dev->ctx_mutex ); ctx = stw_lookup_context_locked( hglrc ); - pipe_mutex_unlock( stw_dev->mutex ); + pipe_mutex_unlock( stw_dev->ctx_mutex ); if (!ctx) return FALSE; @@ -298,9 +306,9 @@ stw_make_current( HDC hdc, UINT_PTR hglrc ) { - struct stw_context *curctx; - struct stw_context *ctx; - struct stw_framebuffer *fb; + struct stw_context *curctx = NULL; + struct stw_context *ctx = NULL; + struct stw_framebuffer *fb = NULL; if (!stw_dev) goto fail; @@ -322,13 +330,13 @@ stw_make_current( return st_make_current( NULL, NULL, NULL ); } - pipe_mutex_lock( stw_dev->mutex ); - + pipe_mutex_lock( stw_dev->ctx_mutex ); ctx = stw_lookup_context_locked( hglrc ); + pipe_mutex_unlock( stw_dev->ctx_mutex ); if(!ctx) goto fail; - fb = stw_framebuffer_from_hdc_locked( hdc ); + fb = stw_framebuffer_from_hdc( hdc ); if(!fb) { /* Applications should call SetPixelFormat before creating a context, * but not all do, and the opengl32 runtime seems to use a default pixel @@ -336,13 +344,11 @@ stw_make_current( */ int iPixelFormat = GetPixelFormat(hdc); if(iPixelFormat) - fb = stw_framebuffer_create_locked( hdc, iPixelFormat ); + fb = stw_framebuffer_create( hdc, iPixelFormat ); if(!fb) goto fail; } - pipe_mutex_unlock( stw_dev->mutex ); - if(fb->iPixelFormat != ctx->iPixelFormat) goto fail; @@ -361,12 +367,16 @@ stw_make_current( success: assert(fb); - if(fb) + if(fb) { stw_framebuffer_update(fb); + stw_framebuffer_release(fb); + } return TRUE; fail: + if(fb) + stw_framebuffer_release(fb); st_make_current( NULL, NULL, NULL ); return FALSE; } diff --git a/src/gallium/state_trackers/wgl/shared/stw_device.c b/src/gallium/state_trackers/wgl/shared/stw_device.c index ce46624146..0b6954915a 100644 --- a/src/gallium/state_trackers/wgl/shared/stw_device.c +++ b/src/gallium/state_trackers/wgl/shared/stw_device.c @@ -69,8 +69,6 @@ stw_flush_frontbuffer(struct pipe_screen *screen, fb = stw_framebuffer_from_hdc( hdc ); /* fb can be NULL if window was destroyed already */ if (fb) { - pipe_mutex_lock( fb->mutex ); - #if DEBUG { struct pipe_surface *surface2; @@ -94,8 +92,7 @@ stw_flush_frontbuffer(struct pipe_screen *screen, if(fb) { stw_framebuffer_update(fb); - - pipe_mutex_unlock( fb->mutex ); + stw_framebuffer_release(fb); } } @@ -138,7 +135,8 @@ stw_init(const struct stw_winsys *stw_winsys) stw_dev->screen->flush_frontbuffer = &stw_flush_frontbuffer; - pipe_mutex_init( stw_dev->mutex ); + pipe_mutex_init( stw_dev->ctx_mutex ); + pipe_mutex_init( stw_dev->fb_mutex ); stw_dev->ctx_table = handle_table_create(); if (!stw_dev->ctx_table) { @@ -179,7 +177,7 @@ stw_cleanup(void) if (!stw_dev) return; - pipe_mutex_lock( stw_dev->mutex ); + pipe_mutex_lock( stw_dev->ctx_mutex ); { /* Ensure all contexts are destroyed */ i = handle_table_get_first_handle(stw_dev->ctx_table); @@ -189,11 +187,12 @@ stw_cleanup(void) } handle_table_destroy(stw_dev->ctx_table); } - pipe_mutex_unlock( stw_dev->mutex ); + pipe_mutex_unlock( stw_dev->ctx_mutex ); stw_framebuffer_cleanup(); - pipe_mutex_destroy( stw_dev->mutex ); + pipe_mutex_destroy( stw_dev->fb_mutex ); + pipe_mutex_destroy( stw_dev->ctx_mutex ); stw_dev->screen->destroy(stw_dev->screen); diff --git a/src/gallium/state_trackers/wgl/shared/stw_device.h b/src/gallium/state_trackers/wgl/shared/stw_device.h index e097f1f71e..e1bb9518dd 100644 --- a/src/gallium/state_trackers/wgl/shared/stw_device.h +++ b/src/gallium/state_trackers/wgl/shared/stw_device.h @@ -57,10 +57,10 @@ struct stw_device unsigned pixelformat_count; unsigned pixelformat_extended_count; - pipe_mutex mutex; - + pipe_mutex ctx_mutex; struct handle_table *ctx_table; + pipe_mutex fb_mutex; struct stw_framebuffer *fb_head; #ifdef DEBUG diff --git a/src/gallium/state_trackers/wgl/shared/stw_framebuffer.c b/src/gallium/state_trackers/wgl/shared/stw_framebuffer.c index 78a2dbc4d7..b8956bb550 100644 --- a/src/gallium/state_trackers/wgl/shared/stw_framebuffer.c +++ b/src/gallium/state_trackers/wgl/shared/stw_framebuffer.c @@ -45,6 +45,10 @@ #include "stw_tls.h" +/** + * Search the framebuffer with the matching HWND while holding the + * stw_dev::fb_mutex global lock. + */ static INLINE struct stw_framebuffer * stw_framebuffer_from_hwnd_locked( HWND hwnd ) @@ -52,13 +56,20 @@ stw_framebuffer_from_hwnd_locked( struct stw_framebuffer *fb; for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next) - if (fb->hWnd == hwnd) + if (fb->hWnd == hwnd) { + pipe_mutex_lock(fb->mutex); break; + } return fb; } +/** + * Destroy this framebuffer. Both stw_dev::fb_mutex and stw_framebuffer::mutex + * must be held, by this order. Obviously no further access to fb can be done + * after this. + */ static INLINE void stw_framebuffer_destroy_locked( struct stw_framebuffer *fb ) @@ -74,12 +85,48 @@ stw_framebuffer_destroy_locked( st_unreference_framebuffer(fb->stfb); + pipe_mutex_unlock( fb->mutex ); + pipe_mutex_destroy( fb->mutex ); FREE( fb ); } +void +stw_framebuffer_release( + struct stw_framebuffer *fb) +{ + assert(fb); + pipe_mutex_unlock( fb->mutex ); +} + + +static INLINE 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; + } +} + + /** * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx @@ -92,6 +139,7 @@ stw_call_window_proc( { struct stw_tls_data *tls_data; PCWPSTRUCT pParams = (PCWPSTRUCT)lParam; + struct stw_framebuffer *fb; tls_data = stw_tls_get_data(); if(!tls_data) @@ -100,71 +148,37 @@ stw_call_window_proc( if (nCode < 0) return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam); - if (pParams->message == WM_SIZE && pParams->wParam != SIZE_MINIMIZED) { - struct stw_framebuffer *fb; - - pipe_mutex_lock( stw_dev->mutex ); - fb = stw_framebuffer_from_hwnd_locked( pParams->hwnd ); - pipe_mutex_unlock( stw_dev->mutex ); - - if(fb) { - unsigned width = LOWORD( pParams->lParam ); - unsigned height = HIWORD( pParams->lParam ); - - pipe_mutex_lock( fb->mutex ); - fb->must_resize = TRUE; - fb->width = width; - fb->height = height; - pipe_mutex_unlock( fb->mutex ); + if (pParams->message == WM_WINDOWPOSCHANGED) { + /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to + * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx + * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it + * can be masked out by the application. */ + LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam; + if((lpWindowPos->flags & SWP_SHOWWINDOW) || + !(lpWindowPos->flags & SWP_NOSIZE)) { + fb = stw_framebuffer_from_hwnd( pParams->hwnd ); + if(fb) { + /* Size in WINDOWPOS includes the window frame, so get the size + * of the client area via GetClientRect. */ + stw_framebuffer_get_size(fb); + stw_framebuffer_release(fb); + } } } - - if (pParams->message == WM_DESTROY) { - struct stw_framebuffer *fb; - - pipe_mutex_lock( stw_dev->mutex ); - + else if (pParams->message == WM_DESTROY) { + pipe_mutex_lock( stw_dev->fb_mutex ); fb = stw_framebuffer_from_hwnd_locked( pParams->hwnd ); if(fb) stw_framebuffer_destroy_locked(fb); - - pipe_mutex_unlock( stw_dev->mutex ); + pipe_mutex_unlock( stw_dev->fb_mutex ); } return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam); } -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. - */ struct stw_framebuffer * -stw_framebuffer_create_locked( +stw_framebuffer_create( HDC hdc, int iPixelFormat ) { @@ -193,8 +207,16 @@ stw_framebuffer_create_locked( pipe_mutex_init( fb->mutex ); + /* This is the only case where we lock the stw_framebuffer::mutex before + * stw_dev::fb_mutex, since no other thread can know about this framebuffer + * and we must prevent any other thread from destroying it before we return. + */ + pipe_mutex_lock( fb->mutex ); + + pipe_mutex_lock( stw_dev->fb_mutex ); fb->next = stw_dev->fb_head; stw_dev->fb_head = fb; + pipe_mutex_unlock( stw_dev->fb_mutex ); return fb; } @@ -204,8 +226,8 @@ BOOL stw_framebuffer_allocate( struct stw_framebuffer *fb) { - pipe_mutex_lock( fb->mutex ); - + assert(fb); + if(!fb->stfb) { const struct stw_pixelformat_info *pfi = fb->pfi; enum pipe_format colorFormat, depthFormat, stencilFormat; @@ -241,8 +263,6 @@ stw_framebuffer_allocate( fb->must_resize = TRUE; } - pipe_mutex_unlock( fb->mutex ); - return fb->stfb ? TRUE : FALSE; } @@ -279,24 +299,27 @@ stw_framebuffer_cleanup( void ) struct stw_framebuffer *fb; struct stw_framebuffer *next; - pipe_mutex_lock( stw_dev->mutex ); + pipe_mutex_lock( stw_dev->fb_mutex ); fb = stw_dev->fb_head; while (fb) { next = fb->next; + + pipe_mutex_lock(fb->mutex); stw_framebuffer_destroy_locked(fb); + fb = next; } stw_dev->fb_head = NULL; - pipe_mutex_unlock( stw_dev->mutex ); + pipe_mutex_unlock( stw_dev->fb_mutex ); } /** * Given an hdc, return the corresponding stw_framebuffer. */ -struct stw_framebuffer * +static INLINE struct stw_framebuffer * stw_framebuffer_from_hdc_locked( HDC hdc ) { @@ -313,8 +336,10 @@ stw_framebuffer_from_hdc_locked( return stw_framebuffer_from_hwnd_locked(hwnd); for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next) - if (fb->hDC == hdc) + if (fb->hDC == hdc) { + pipe_mutex_lock(fb->mutex); break; + } return fb; } @@ -329,9 +354,26 @@ stw_framebuffer_from_hdc( { struct stw_framebuffer *fb; - pipe_mutex_lock( stw_dev->mutex ); + pipe_mutex_lock( stw_dev->fb_mutex ); fb = stw_framebuffer_from_hdc_locked(hdc); - pipe_mutex_unlock( stw_dev->mutex ); + pipe_mutex_unlock( stw_dev->fb_mutex ); + + return fb; +} + + +/** + * Given an hdc, return the corresponding stw_framebuffer. + */ +struct stw_framebuffer * +stw_framebuffer_from_hwnd( + HWND hwnd ) +{ + struct stw_framebuffer *fb; + + pipe_mutex_lock( stw_dev->fb_mutex ); + fb = stw_framebuffer_from_hwnd_locked(hwnd); + pipe_mutex_unlock( stw_dev->fb_mutex ); return fb; } @@ -351,22 +393,19 @@ stw_pixelformat_set( if (index >= count) return FALSE; - pipe_mutex_lock( stw_dev->mutex ); - fb = stw_framebuffer_from_hdc_locked(hdc); if(fb) { /* SetPixelFormat must be called only once */ - pipe_mutex_unlock( stw_dev->mutex ); + stw_framebuffer_release( fb ); return FALSE; } - fb = stw_framebuffer_create_locked(hdc, iPixelFormat); + fb = stw_framebuffer_create(hdc, iPixelFormat); if(!fb) { - pipe_mutex_unlock( stw_dev->mutex ); return FALSE; } - pipe_mutex_unlock( stw_dev->mutex ); + stw_framebuffer_release( fb ); /* Some applications mistakenly use the undocumented wglSetPixelFormat * function instead of SetPixelFormat, so we call SetPixelFormat here to @@ -383,13 +422,16 @@ int stw_pixelformat_get( HDC hdc ) { + int iPixelFormat = 0; struct stw_framebuffer *fb; fb = stw_framebuffer_from_hdc(hdc); - if(!fb) - return 0; + if(fb) { + iPixelFormat = fb->iPixelFormat; + stw_framebuffer_release(fb); + } - return fb->iPixelFormat; + return iPixelFormat; } @@ -405,10 +447,10 @@ stw_swap_buffers( if (fb == NULL) return FALSE; - if (!(fb->pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) + if (!(fb->pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) { + stw_framebuffer_release(fb); return TRUE; - - pipe_mutex_lock( fb->mutex ); + } /* If we're swapping the buffer associated with the current context * we have to flush any pending rendering commands first. @@ -419,7 +461,7 @@ stw_swap_buffers( if(!st_get_framebuffer_surface( fb->stfb, ST_SURFACE_BACK_LEFT, &surface )) { /* FIXME: this shouldn't happen, but does on glean */ - pipe_mutex_unlock( fb->mutex ); + stw_framebuffer_release(fb); return FALSE; } @@ -433,8 +475,7 @@ stw_swap_buffers( stw_dev->stw_winsys->flush_frontbuffer( screen, surface, hdc ); stw_framebuffer_update(fb); - - pipe_mutex_unlock( fb->mutex ); + stw_framebuffer_release(fb); return TRUE; } diff --git a/src/gallium/state_trackers/wgl/shared/stw_framebuffer.h b/src/gallium/state_trackers/wgl/shared/stw_framebuffer.h index 759e06b891..13d29f37e4 100644 --- a/src/gallium/state_trackers/wgl/shared/stw_framebuffer.h +++ b/src/gallium/state_trackers/wgl/shared/stw_framebuffer.h @@ -41,6 +41,23 @@ struct stw_pixelformat_info; */ struct stw_framebuffer { + /** + * This mutex has two purposes: + * - protect the access to the mutable data members below + * - prevent the the framebuffer from being deleted while being accessed. + * + * It is OK to lock this mutex while holding the stw_device::fb_mutex lock, + * but the opposite must never happen. + */ + pipe_mutex mutex; + + /* + * Immutable members. + * + * Note that even access to immutable members implies acquiring the mutex + * above, to prevent the framebuffer from being destroyed. + */ + HDC hDC; HWND hWnd; @@ -48,7 +65,10 @@ struct stw_framebuffer const struct stw_pixelformat_info *pfi; GLvisual visual; - pipe_mutex mutex; + /* + * Mutable members. + */ + struct st_framebuffer *stfb; /* FIXME: Make this work for multiple contexts bound to the same framebuffer */ @@ -56,15 +76,52 @@ struct stw_framebuffer unsigned width; unsigned height; - /** This is protected by stw_device::mutex, not the mutex above */ + /** + * This is protected by stw_device::fb_mutex, not the mutex above. + * + * Deletions must be done by first acquiring stw_device::fb_mutex, and then + * acquiring the stw_framebuffer::mutex of the framebuffer to be deleted. + * This ensures that nobody else is reading/writing to the. + * + * It is not necessary to aquire the mutex above to navigate the linked list + * given that deletions are done with stw_device::fb_mutex held, so no other + * thread can delete. + */ struct stw_framebuffer *next; }; + +/** + * Create a new framebuffer object which will correspond to the given HDC. + * + * This function will acquire stw_framebuffer::mutex. stw_framebuffer_release + * must be called when done + */ struct stw_framebuffer * -stw_framebuffer_create_locked( +stw_framebuffer_create( HDC hdc, int iPixelFormat ); +/** + * Search a framebuffer with a matching HWND. + * + * This function will acquire stw_framebuffer::mutex. stw_framebuffer_release + * must be called when done + */ +struct stw_framebuffer * +stw_framebuffer_from_hwnd( + HWND hwnd ); + +/** + * Search a framebuffer with a matching HDC. + * + * This function will acquire stw_framebuffer::mutex. stw_framebuffer_release + * must be called when done + */ +struct stw_framebuffer * +stw_framebuffer_from_hdc( + HDC hdc ); + BOOL stw_framebuffer_allocate( struct stw_framebuffer *fb ); @@ -73,15 +130,19 @@ void stw_framebuffer_update( struct stw_framebuffer *fb); +/** + * Release stw_framebuffer::mutex lock. This framebuffer must not be accessed + * after calling this function, as it may have been deleted by another thread + * in the meanwhile. + */ void -stw_framebuffer_cleanup(void); - -struct stw_framebuffer * -stw_framebuffer_from_hdc_locked( - HDC hdc ); +stw_framebuffer_release( + struct stw_framebuffer *fb); -struct stw_framebuffer * -stw_framebuffer_from_hdc( - HDC hdc ); +/** + * Cleanup any existing framebuffers when exiting application. + */ +void +stw_framebuffer_cleanup(void); #endif /* STW_FRAMEBUFFER_H */ |