From: Rémi Bernon rbernon@codeweavers.com
--- dlls/opengl32/tests/opengl.c | 3 +- dlls/opengl32/unix_wgl.c | 61 ++++++++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 15 deletions(-)
diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index 899b695e518..63e05a397f5 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -1145,12 +1145,11 @@ static void test_sharelists(HDC winhdc) if (dest_sharing) { res = wglShareLists(other, dest); - todo_wine_if(source_sharing && dest_current) ok(res, "Sharing of display lists from other to dest failed\n"); }
res = wglShareLists(source, dest); - todo_wine_if((source_current || source_sharing) && (dest_current || dest_sharing)) + todo_wine_if(source_current && dest_current) ok(res || broken(nvidia && !source_sharing && dest_sharing), "Sharing of display lists from source to dest failed\n");
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index f2cc34006e1..c80144c6a27 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -696,29 +696,52 @@ static HGLRC wrap_wglCreateContext( HDC hdc ) if (!funcs) return 0; if (!(context = funcs->p_wglCreateContext( hdc ))) return 0; context->hdc = hdc; + context->share = (HGLRC)-1; /* initial shared context */
ret = alloc_handle( HANDLE_CONTEXT, funcs, context ); if (!ret) funcs->p_wglDeleteContext( context ); return ret; }
+static struct wgl_context *wgl_handle_update_context( struct wgl_handle *ptr, DWORD tid ) +{ + struct wgl_context *context, *prev = ptr->u.context, *shared; + const struct opengl_funcs *funcs = ptr->funcs, *share_funcs; + + if (!funcs->p_wglCreateContextAttribsARB) return prev; /* not supported */ + if (prev->share == (HGLRC)-1) return prev; /* hasn't been re-shared */ + + shared = prev->share ? wgl_context_from_handle( prev->share, &share_funcs ) : NULL; + if (!(context = funcs->p_wglCreateContextAttribsARB( prev->hdc, shared, prev->attribs ))) return prev; + *context = *prev; + funcs->p_wglDeleteContext( prev ); + + return context; +} + static BOOL wrap_wglMakeCurrent( TEB *teb, HDC hdc, HGLRC hglrc ) { DWORD tid = HandleToULong(teb->ClientId.UniqueThread); struct wgl_context *ctx, *prev = get_current_context( teb ); const struct opengl_funcs *funcs = teb->glTable; + struct wgl_handle *ptr;
if (hglrc) { - if (!(ctx = wgl_context_from_handle( hglrc, &funcs ))) return FALSE; - if (ctx->tid && ctx->tid != tid) + if (!(ptr = get_handle_ptr( hglrc ))) return FALSE; + ctx = ptr->u.context; + funcs = ptr->funcs; + + if (ctx->tid && ctx->tid != -1 && ctx->tid != tid) { RtlSetLastWin32Error( ERROR_BUSY ); return FALSE; } + /* update the context now with new shared context if it hasn't been current yet */ + if (!ctx->tid) ctx = wgl_handle_update_context( ptr, tid );
if (!funcs->p_wglMakeCurrent( hdc, ctx )) return FALSE; - if (prev) prev->tid = 0; + if (prev) prev->tid = -1; /* has been current */ ctx->tid = tid; teb->glReserved1[0] = hdc; teb->glReserved1[1] = hdc; @@ -729,7 +752,7 @@ static BOOL wrap_wglMakeCurrent( TEB *teb, HDC hdc, HGLRC hglrc ) if (prev) { if (!funcs->p_wglMakeCurrent( 0, NULL )) return FALSE; - prev->tid = 0; + prev->tid = -1; /* has been current */ teb->glCurrentRC = 0; teb->glTable = &null_opengl_funcs; return TRUE; @@ -750,7 +773,7 @@ static BOOL wrap_wglDeleteContext( TEB *teb, HGLRC hglrc )
if (!(ptr = get_handle_ptr( hglrc ))) return FALSE; ctx = ptr->u.context; - if (ctx->tid && ctx->tid != tid) + if (ctx->tid && ctx->tid != -1 && ctx->tid != tid) { RtlSetLastWin32Error( ERROR_BUSY ); return FALSE; @@ -833,9 +856,15 @@ static BOOL wrap_wglShareLists( HGLRC hglrcSrc, HGLRC hglrcDst ) else { struct wgl_context *src = src_ptr->u.context, *dst = dst_ptr->u.context; - if (!src->share) src->share = hglrcDst; - if (!dst->share) dst->share = hglrcSrc; - ret = src_funcs->p_wglShareLists( src, dst ); + if (!src->tid) src->share = hglrcDst; + if (!dst->tid) dst->share = hglrcSrc; + if (src->share != hglrcDst && dst->share != hglrcSrc) + { + ERR( "Could not share display lists because both of the contexts have already been current\n" ); + RtlSetLastWin32Error( ERROR_BUSY ); + return FALSE; + } + ret = TRUE; }
return ret; @@ -870,7 +899,7 @@ static HGLRC wrap_wglCreateContextAttribsARB( HDC hdc, HGLRC share, const int *a if ((context = funcs->p_wglCreateContextAttribsARB( hdc, share_ctx, attribs ))) { context->hdc = hdc; - context->share = share; + context->share = (HGLRC)-1; /* initial shared context */ context->attribs = memdup_attribs( attribs );
ret = alloc_handle( HANDLE_CONTEXT, funcs, context ); @@ -918,19 +947,25 @@ static BOOL wrap_wglMakeContextCurrentARB( TEB *teb, HDC draw_hdc, HDC read_hdc, DWORD tid = HandleToULong(teb->ClientId.UniqueThread); struct wgl_context *ctx, *prev = get_current_context( teb ); const struct opengl_funcs *funcs = teb->glTable; + struct wgl_handle *ptr;
if (hglrc) { - if (!(ctx = wgl_context_from_handle( hglrc, &funcs ))) return FALSE; - if (ctx->tid && ctx->tid != tid) + if (!(ptr = get_handle_ptr( hglrc ))) return FALSE; + ctx = ptr->u.context; + funcs = ptr->funcs; + + if (ctx->tid && ctx->tid != -1 && ctx->tid != tid) { RtlSetLastWin32Error( ERROR_BUSY ); return FALSE; } + /* update the context now with new shared context if it hasn't been current yet */ + if (!ctx->tid) ctx = wgl_handle_update_context( ptr, tid );
if (!funcs->p_wglMakeContextCurrentARB) return FALSE; if (!funcs->p_wglMakeContextCurrentARB( draw_hdc, read_hdc, ctx )) return FALSE; - if (prev) prev->tid = 0; + if (prev) prev->tid = -1; /* has been current */ ctx->tid = tid; teb->glReserved1[0] = draw_hdc; teb->glReserved1[1] = read_hdc; @@ -941,7 +976,7 @@ static BOOL wrap_wglMakeContextCurrentARB( TEB *teb, HDC draw_hdc, HDC read_hdc, if (prev) { if (!funcs->p_wglMakeCurrent( 0, NULL )) return FALSE; - prev->tid = 0; + prev->tid = -1; /* has been current */ teb->glCurrentRC = 0; teb->glTable = &null_opengl_funcs; }