X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fstate_trackers%2Fwgl%2Fstw_context.c;h=a9e4024c236d01232fc2e656083fce1ff0f67e55;hb=e92caad74476b915bb73baedbddce8af89bd62b0;hp=86c0a28e8da75122cfa59aa62d279872e8f02ce6;hpb=e6b71530daea3059ee362d4df51575e27e026b22;p=mesa.git diff --git a/src/gallium/state_trackers/wgl/stw_context.c b/src/gallium/state_trackers/wgl/stw_context.c index 86c0a28e8da..a9e4024c236 100644 --- a/src/gallium/state_trackers/wgl/stw_context.c +++ b/src/gallium/state_trackers/wgl/stw_context.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2008 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. @@ -27,11 +27,18 @@ #include +#define WGL_WGLEXT_PROTOTYPES + +#include +#include + #include "pipe/p_compiler.h" #include "pipe/p_context.h" #include "pipe/p_state.h" #include "util/u_memory.h" +#include "util/u_atomic.h" #include "state_tracker/st_api.h" +#include "hud/hud_context.h" #include "stw_icd.h" #include "stw_device.h" @@ -42,7 +49,7 @@ #include "stw_tls.h" -static INLINE struct stw_context * +struct stw_context * stw_current_context(void) { struct st_context_iface *st; @@ -52,11 +59,9 @@ stw_current_context(void) return (struct stw_context *) ((st) ? st->st_manager_private : NULL); } + BOOL APIENTRY -DrvCopyContext( - DHGLRC dhrcSource, - DHGLRC dhrcDest, - UINT fuMask ) +DrvCopyContext(DHGLRC dhrcSource, DHGLRC dhrcDest, UINT fuMask) { struct stw_context *src; struct stw_context *dst; @@ -65,12 +70,12 @@ DrvCopyContext( if (!stw_dev) return FALSE; - pipe_mutex_lock( stw_dev->ctx_mutex ); - + stw_lock_contexts(stw_dev); + src = stw_lookup_context_locked( dhrcSource ); dst = stw_lookup_context_locked( dhrcDest ); - if (src && dst) { + if (src && dst) { /* FIXME */ assert(0); (void) src; @@ -78,15 +83,14 @@ DrvCopyContext( (void) fuMask; } - pipe_mutex_unlock( stw_dev->ctx_mutex ); - + stw_unlock_contexts(stw_dev); + return ret; } + BOOL APIENTRY -DrvShareLists( - DHGLRC dhglrc1, - DHGLRC dhglrc2 ) +DrvShareLists(DHGLRC dhglrc1, DHGLRC dhglrc2) { struct stw_context *ctx1; struct stw_context *ctx2; @@ -95,75 +99,225 @@ DrvShareLists( if (!stw_dev) return FALSE; - pipe_mutex_lock( stw_dev->ctx_mutex ); - + stw_lock_contexts(stw_dev); + ctx1 = stw_lookup_context_locked( dhglrc1 ); ctx2 = stw_lookup_context_locked( dhglrc2 ); - if (ctx1 && ctx2 && ctx2->st->share) + if (ctx1 && ctx2 && ctx2->st->share) { ret = ctx2->st->share(ctx2->st, ctx1->st); + ctx1->shared = TRUE; + ctx2->shared = TRUE; + } + + stw_unlock_contexts(stw_dev); - pipe_mutex_unlock( stw_dev->ctx_mutex ); - return ret; } + DHGLRC APIENTRY -DrvCreateContext( - HDC hdc ) +DrvCreateContext(HDC hdc) { return DrvCreateLayerContext( hdc, 0 ); } + DHGLRC APIENTRY -DrvCreateLayerContext( - HDC hdc, - INT iLayerPlane ) +DrvCreateLayerContext(HDC hdc, INT iLayerPlane) +{ + return stw_create_context_attribs(hdc, iLayerPlane, 0, 1, 0, 0, + WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + 0); +} + + +/** + * Return the stw pixel format that most closely matches the pixel format + * on HDC. + * Used to get a pixel format when SetPixelFormat() hasn't been called before. + */ +static int +get_matching_pixel_format(HDC hdc) +{ + int iPixelFormat = GetPixelFormat(hdc); + PIXELFORMATDESCRIPTOR pfd; + + if (!iPixelFormat) + return 0; + if (!DescribePixelFormat(hdc, iPixelFormat, sizeof(pfd), &pfd)) + return 0; + return stw_pixelformat_choose(hdc, &pfd); +} + + +/** + * Called via DrvCreateContext(), DrvCreateLayerContext() and + * wglCreateContextAttribsARB() to actually create a rendering context. + * \param handle the desired DHGLRC handle to use for the context, or zero + * if a new handle should be allocated. + * \return the handle for the new context or zero if there was a problem. + */ +DHGLRC +stw_create_context_attribs(HDC hdc, INT iLayerPlane, DHGLRC hShareContext, + int majorVersion, int minorVersion, + int contextFlags, int profileMask, + DHGLRC handle) { int iPixelFormat; + struct stw_framebuffer *fb; const struct stw_pixelformat_info *pfi; struct st_context_attribs attribs; struct stw_context *ctx = NULL; - - if(!stw_dev) + struct stw_context *shareCtx = NULL; + enum st_context_error ctx_err = 0; + + if (!stw_dev) return 0; - + if (iLayerPlane != 0) return 0; - iPixelFormat = GetPixelFormat(hdc); - if(!iPixelFormat) - return 0; - - pfi = stw_pixelformat_get_info( iPixelFormat - 1 ); - + /* + * GDI only knows about displayable pixel formats, so determine the pixel + * format from the framebuffer. + * + * This also allows to use a OpenGL DLL / ICD without installing. + */ + fb = stw_framebuffer_from_hdc( hdc ); + if (fb) { + iPixelFormat = fb->iPixelFormat; + stw_framebuffer_unlock(fb); + } else { + /* Applications should call SetPixelFormat before creating a context, + * but not all do, and the opengl32 runtime seems to use a default + * pixel format in some cases, so use that. + */ + iPixelFormat = get_matching_pixel_format(hdc); + if (!iPixelFormat) + return 0; + } + + pfi = stw_pixelformat_get_info( iPixelFormat ); + + if (hShareContext != 0) { + stw_lock_contexts(stw_dev); + shareCtx = stw_lookup_context_locked( hShareContext ); + shareCtx->shared = TRUE; + stw_unlock_contexts(stw_dev); + } + ctx = CALLOC_STRUCT( stw_context ); if (ctx == NULL) goto no_ctx; - ctx->hdc = hdc; + ctx->hDrawDC = hdc; + ctx->hReadDC = hdc; ctx->iPixelFormat = iPixelFormat; + ctx->shared = shareCtx != NULL; memset(&attribs, 0, sizeof(attribs)); - attribs.profile = ST_PROFILE_DEFAULT; attribs.visual = pfi->stvis; + attribs.major = majorVersion; + attribs.minor = minorVersion; + if (contextFlags & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB) + attribs.flags |= ST_CONTEXT_FLAG_FORWARD_COMPATIBLE; + if (contextFlags & WGL_CONTEXT_DEBUG_BIT_ARB) + attribs.flags |= ST_CONTEXT_FLAG_DEBUG; + + switch (profileMask) { + case WGL_CONTEXT_CORE_PROFILE_BIT_ARB: + /* There are no profiles before OpenGL 3.2. The + * WGL_ARB_create_context_profile spec says: + * + * "If the requested OpenGL version is less than 3.2, + * WGL_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality + * of the context is determined solely by the requested version." + */ + if (majorVersion > 3 || (majorVersion == 3 && minorVersion >= 2)) { + attribs.profile = ST_PROFILE_OPENGL_CORE; + break; + } + /* fall-through */ + case WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: + /* + * The spec also says: + * + * "If version 3.1 is requested, the context returned may implement + * any of the following versions: + * + * * Version 3.1. The GL_ARB_compatibility extension may or may not + * be implemented, as determined by the implementation. + * * The core profile of version 3.2 or greater." + * + * But Mesa doesn't support GL_ARB_compatibility, while most prevalent + * Windows OpenGL implementations do, and unfortunately many Windows + * applications don't check whether they receive or not a context with + * GL_ARB_compatibility, so returning a core profile here does more harm + * than good. + */ + attribs.profile = ST_PROFILE_DEFAULT; + break; + case WGL_CONTEXT_ES_PROFILE_BIT_EXT: + if (majorVersion >= 2) { + attribs.profile = ST_PROFILE_OPENGL_ES2; + } else { + attribs.profile = ST_PROFILE_OPENGL_ES1; + } + break; + default: + assert(0); + goto no_st_ctx; + } ctx->st = stw_dev->stapi->create_context(stw_dev->stapi, - stw_dev->smapi, &attribs, NULL); - if (ctx->st == NULL) + stw_dev->smapi, &attribs, &ctx_err, shareCtx ? shareCtx->st : NULL); + if (ctx->st == NULL) goto no_st_ctx; ctx->st->st_manager_private = (void *) ctx; - pipe_mutex_lock( stw_dev->ctx_mutex ); - ctx->dhglrc = handle_table_add(stw_dev->ctx_table, ctx); - pipe_mutex_unlock( stw_dev->ctx_mutex ); + if (ctx->st->cso_context) { + ctx->hud = hud_create(ctx->st->cso_context, NULL); + } + + stw_lock_contexts(stw_dev); + if (handle) { + /* We're replacing the context data for this handle. See the + * wglCreateContextAttribsARB() function. + */ + struct stw_context *old_ctx = + stw_lookup_context_locked((unsigned) handle); + if (old_ctx) { + /* free the old context data associated with this handle */ + if (old_ctx->hud) { + hud_destroy(old_ctx->hud, NULL); + } + ctx->st->destroy(old_ctx->st); + FREE(old_ctx); + } + + /* replace table entry */ + handle_table_set(stw_dev->ctx_table, (unsigned) handle, ctx); + } + else { + /* create new table entry */ + handle = (DHGLRC) handle_table_add(stw_dev->ctx_table, ctx); + } + + ctx->dhglrc = handle; + + stw_unlock_contexts(stw_dev); + if (!ctx->dhglrc) goto no_hglrc; return ctx->dhglrc; no_hglrc: + if (ctx->hud) { + hud_destroy(ctx->hud, NULL); + } ctx->st->destroy(ctx->st); no_st_ctx: FREE(ctx); @@ -171,28 +325,32 @@ no_ctx: return 0; } + BOOL APIENTRY -DrvDeleteContext( - DHGLRC dhglrc ) +DrvDeleteContext(DHGLRC dhglrc) { struct stw_context *ctx ; BOOL ret = FALSE; - + if (!stw_dev) return FALSE; - pipe_mutex_lock( stw_dev->ctx_mutex ); + stw_lock_contexts(stw_dev); ctx = stw_lookup_context_locked(dhglrc); handle_table_remove(stw_dev->ctx_table, dhglrc); - pipe_mutex_unlock( stw_dev->ctx_mutex ); + stw_unlock_contexts(stw_dev); if (ctx) { struct stw_context *curctx = stw_current_context(); - + /* Unbind current if deleting current context. */ if (curctx == ctx) stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL); + if (ctx->hud) { + hud_destroy(ctx->hud, NULL); + } + ctx->st->destroy(ctx->st); FREE(ctx); @@ -202,22 +360,22 @@ DrvDeleteContext( return ret; } + BOOL APIENTRY -DrvReleaseContext( - DHGLRC dhglrc ) +DrvReleaseContext(DHGLRC dhglrc) { struct stw_context *ctx; if (!stw_dev) return FALSE; - pipe_mutex_lock( stw_dev->ctx_mutex ); + stw_lock_contexts(stw_dev); ctx = stw_lookup_context_locked( dhglrc ); - pipe_mutex_unlock( stw_dev->ctx_mutex ); + stw_unlock_contexts(stw_dev); if (!ctx) return FALSE; - + /* The expectation is that ctx is the same context which is * current for this thread. We should check that and return False * if not the case. @@ -225,7 +383,7 @@ DrvReleaseContext( if (ctx != stw_current_context()) return FALSE; - if (stw_make_current( NULL, 0 ) == FALSE) + if (stw_make_current( NULL, NULL, 0 ) == FALSE) return FALSE; return TRUE; @@ -238,132 +396,204 @@ stw_get_current_context( void ) struct stw_context *ctx; ctx = stw_current_context(); - if(!ctx) + if (!ctx) return 0; - + return ctx->dhglrc; } + HDC stw_get_current_dc( void ) { struct stw_context *ctx; ctx = stw_current_context(); - if(!ctx) + if (!ctx) + return NULL; + + return ctx->hDrawDC; +} + +HDC +stw_get_current_read_dc( void ) +{ + struct stw_context *ctx; + + ctx = stw_current_context(); + if (!ctx) return NULL; - - return ctx->hdc; + + return ctx->hReadDC; } BOOL -stw_make_current( - HDC hdc, - DHGLRC dhglrc ) +stw_make_current(HDC hDrawDC, HDC hReadDC, DHGLRC dhglrc) { - struct stw_context *curctx = NULL; + struct stw_context *old_ctx = NULL; struct stw_context *ctx = NULL; - struct stw_framebuffer *fb = NULL; + BOOL ret = FALSE; if (!stw_dev) - goto fail; - - curctx = stw_current_context(); - if (curctx != NULL) { - if (curctx->dhglrc != dhglrc) - curctx->st->flush(curctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); - - /* Return if already current. */ - if (curctx->dhglrc == dhglrc && curctx->hdc == hdc) { - ctx = curctx; - fb = stw_framebuffer_from_hdc( hdc ); - goto success; - } + return FALSE; - stw_framebuffer_reference(&curctx->current_framebuffer, NULL); + old_ctx = stw_current_context(); + if (old_ctx != NULL) { + if (old_ctx->dhglrc == dhglrc) { + if (old_ctx->hDrawDC == hDrawDC && old_ctx->hReadDC == hReadDC) { + /* Return if already current. */ + return TRUE; + } + } else { + if (old_ctx->shared) { + struct pipe_fence_handle *fence = NULL; + old_ctx->st->flush(old_ctx->st, + ST_FLUSH_FRONT | ST_FLUSH_WAIT, &fence); + } + else { + old_ctx->st->flush(old_ctx->st, ST_FLUSH_FRONT, NULL); + } + } } - if (hdc == NULL || dhglrc == 0) { - return stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL); - } + if (dhglrc) { + struct stw_framebuffer *fb = NULL; + struct stw_framebuffer *fbRead = NULL; + stw_lock_contexts(stw_dev); + ctx = stw_lookup_context_locked( dhglrc ); + stw_unlock_contexts(stw_dev); + if (!ctx) { + goto fail; + } - pipe_mutex_lock( stw_dev->ctx_mutex ); - ctx = stw_lookup_context_locked( dhglrc ); - pipe_mutex_unlock( stw_dev->ctx_mutex ); - if(!ctx) - goto fail; + /* This call locks fb's mutex */ + fb = stw_framebuffer_from_hdc( hDrawDC ); + if (fb) { + stw_framebuffer_update(fb); + } + else { + /* Applications should call SetPixelFormat before creating a context, + * but not all do, and the opengl32 runtime seems to use a default + * pixel format in some cases, so we must create a framebuffer for + * those here. + */ + int iPixelFormat = get_matching_pixel_format(hDrawDC); + if (iPixelFormat) + fb = stw_framebuffer_create( hDrawDC, iPixelFormat ); + if (!fb) + goto fail; + } - fb = stw_framebuffer_from_hdc( hdc ); - if (fb) { - stw_framebuffer_update(fb); - } - else { - /* Applications should call SetPixelFormat before creating a context, - * but not all do, and the opengl32 runtime seems to use a default pixel - * format in some cases, so we must create a framebuffer for those here - */ - int iPixelFormat = GetPixelFormat(hdc); - if(iPixelFormat) - fb = stw_framebuffer_create( hdc, iPixelFormat ); - if(!fb) + if (fb->iPixelFormat != ctx->iPixelFormat) { + stw_framebuffer_unlock(fb); + SetLastError(ERROR_INVALID_PIXEL_FORMAT); goto fail; - } - - if(fb->iPixelFormat != ctx->iPixelFormat) - goto fail; - - /* Bind the new framebuffer */ - ctx->hdc = hdc; - - if (!stw_dev->stapi->make_current(stw_dev->stapi, ctx->st, fb->stfb, fb->stfb)) - goto fail; - - stw_framebuffer_reference(&ctx->current_framebuffer, fb); - -success: - assert(fb); - if(fb) { - stw_framebuffer_release(fb); - } - - return TRUE; + } + + /* Bind the new framebuffer */ + ctx->hDrawDC = hDrawDC; + ctx->hReadDC = hReadDC; + + struct stw_framebuffer *old_fb = ctx->current_framebuffer; + if (old_fb != fb) { + stw_framebuffer_reference_locked(fb); + ctx->current_framebuffer = fb; + } + stw_framebuffer_unlock(fb); + + if (hReadDC) { + if (hReadDC == hDrawDC) { + fbRead = fb; + } + else { + fbRead = stw_framebuffer_from_hdc( hReadDC ); + + if (fbRead) { + stw_framebuffer_update(fbRead); + } + else { + /* Applications should call SetPixelFormat before creating a + * context, but not all do, and the opengl32 runtime seems to + * use a default pixel format in some cases, so we must create + * a framebuffer for those here. + */ + int iPixelFormat = GetPixelFormat(hReadDC); + if (iPixelFormat) + fbRead = stw_framebuffer_create( hReadDC, iPixelFormat ); + if (!fbRead) + goto fail; + } + + if (fbRead->iPixelFormat != ctx->iPixelFormat) { + stw_framebuffer_unlock(fbRead); + SetLastError(ERROR_INVALID_PIXEL_FORMAT); + goto fail; + } + stw_framebuffer_unlock(fbRead); + } + ret = stw_dev->stapi->make_current(stw_dev->stapi, ctx->st, + fb->stfb, fbRead->stfb); + } + else { + /* Note: when we call this function we will wind up in the + * stw_st_framebuffer_validate_locked() function which will incur + * a recursive fb->mutex lock. + */ + ret = stw_dev->stapi->make_current(stw_dev->stapi, ctx->st, + fb->stfb, fb->stfb); + } + + if (old_fb && old_fb != fb) { + stw_lock_framebuffers(stw_dev); + stw_framebuffer_lock(old_fb); + stw_framebuffer_release_locked(old_fb); + stw_unlock_framebuffers(stw_dev); + } fail: - if(fb) - stw_framebuffer_release(fb); - stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL); - return FALSE; -} + if (fb) { + /* fb must be unlocked at this point. */ + assert(!stw_own_mutex(&fb->mutex)); + } -/** - * Flush the current context if it is bound to the framebuffer. - */ -void -stw_flush_current_locked( struct stw_framebuffer *fb ) -{ - struct stw_context *ctx = stw_current_context(); - - if (ctx && ctx->current_framebuffer == fb) { - ctx->st->flush(ctx->st, - PIPE_FLUSH_RENDER_CACHE | - PIPE_FLUSH_SWAPBUFFERS | - PIPE_FLUSH_FRAME, - NULL); + /* On failure, make the thread's current rendering context not current + * before returning. + */ + if (!ret) { + stw_make_current(NULL, NULL, 0); + } + } else { + ret = stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL); } + + /* Unreference the previous framebuffer if any. It must be done after + * make_current, as it can be referenced inside. + */ + if (old_ctx && old_ctx != ctx) { + struct stw_framebuffer *old_fb = old_ctx->current_framebuffer; + if (old_fb) { + old_ctx->current_framebuffer = NULL; + stw_lock_framebuffers(stw_dev); + stw_framebuffer_lock(old_fb); + stw_framebuffer_release_locked(old_fb); + stw_unlock_framebuffers(stw_dev); + } + } + + return ret; } + /** * Notify the current context that the framebuffer has become invalid. */ void stw_notify_current_locked( struct stw_framebuffer *fb ) { - struct stw_context *ctx = stw_current_context(); - - if (ctx && ctx->current_framebuffer == fb) - ctx->st->notify_invalid_framebuffer(ctx->st, fb->stfb); + p_atomic_inc(&fb->stfb->stamp); } + /** * Although WGL allows different dispatch entrypoints per context */ @@ -710,15 +940,13 @@ static const GLCLTPROCTABLE cpt = } }; + PGLCLTPROCTABLE APIENTRY -DrvSetContext( - HDC hdc, - DHGLRC dhglrc, - PFN_SETPROCTABLE pfnSetProcTable ) +DrvSetContext(HDC hdc, DHGLRC dhglrc, PFN_SETPROCTABLE pfnSetProcTable) { PGLCLTPROCTABLE r = (PGLCLTPROCTABLE)&cpt; - if (!stw_make_current( hdc, dhglrc )) + if (!stw_make_current(hdc, hdc, dhglrc)) r = NULL; return r;