wgl: Improve wglDeleteContext threading behavior.
This commit is contained in:
parent
bfc4c71049
commit
b86787e57c
|
@ -499,6 +499,61 @@ static void test_acceleration(HDC hdc)
|
|||
}
|
||||
}
|
||||
|
||||
struct wgl_thread_param
|
||||
{
|
||||
HANDLE test_finished;
|
||||
HGLRC hglrc;
|
||||
BOOL hglrc_deleted;
|
||||
};
|
||||
|
||||
static DWORD WINAPI wgl_thread(void *param)
|
||||
{
|
||||
struct wgl_thread_param *p = param;
|
||||
|
||||
p->hglrc_deleted = wglDeleteContext(p->hglrc);
|
||||
SetEvent(p->test_finished);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_deletecontext(HDC hdc)
|
||||
{
|
||||
struct wgl_thread_param thread_params;
|
||||
HGLRC hglrc = wglCreateContext(hdc);
|
||||
HANDLE thread_handle;
|
||||
DWORD res, tid;
|
||||
|
||||
if(!hglrc)
|
||||
{
|
||||
skip("wglCreateContext failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
res = wglMakeCurrent(hdc, hglrc);
|
||||
if(!res)
|
||||
{
|
||||
skip("wglMakeCurrent failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* WGL doesn't allow you to delete a context from a different thread than the one in which it is current.
|
||||
* This differs from GLX which does allow it but it delays actual deletion until the context becomes not current.
|
||||
*/
|
||||
thread_params.hglrc = hglrc;
|
||||
thread_params.test_finished = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
thread_handle = CreateThread(NULL, 0, wgl_thread, &thread_params, 0, &tid);
|
||||
ok(!!thread_handle, "Failed to create thread, last error %#x.\n", GetLastError());
|
||||
if(thread_handle)
|
||||
{
|
||||
WaitForSingleObject(thread_handle, INFINITE);
|
||||
ok(thread_params.hglrc_deleted == FALSE, "Attempt to delete WGL context from another thread passed but should fail!\n");
|
||||
}
|
||||
CloseHandle(thread_params.test_finished);
|
||||
|
||||
res = wglDeleteContext(hglrc);
|
||||
ok(res == TRUE, "wglDeleteContext failed\n");
|
||||
}
|
||||
|
||||
static void test_make_current_read(HDC hdc)
|
||||
{
|
||||
int res;
|
||||
|
@ -802,6 +857,7 @@ START_TEST(opengl)
|
|||
return;
|
||||
}
|
||||
|
||||
test_deletecontext(hdc);
|
||||
test_makecurrent(hdc);
|
||||
test_setpixelformat(hdc);
|
||||
test_sharelists(hdc);
|
||||
|
|
|
@ -113,6 +113,7 @@ typedef struct wine_glcontext {
|
|||
BOOL do_escape;
|
||||
BOOL has_been_current;
|
||||
BOOL sharing;
|
||||
DWORD tid;
|
||||
BOOL gl3_context;
|
||||
XVisualInfo *vis;
|
||||
WineGLPixelFormat *fmt;
|
||||
|
@ -1763,29 +1764,33 @@ HGLRC CDECL X11DRV_wglCreateContext(X11DRV_PDEVICE *physDev)
|
|||
BOOL CDECL X11DRV_wglDeleteContext(HGLRC hglrc)
|
||||
{
|
||||
Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
TRACE("(%p)\n", hglrc);
|
||||
|
||||
if (!has_opengl()) return 0;
|
||||
|
||||
wine_tsx11_lock();
|
||||
/* A game (Half Life not to name it) deletes twice the same context,
|
||||
* so make sure it is valid first */
|
||||
if (is_valid_context( ctx ))
|
||||
{
|
||||
if (ctx->ctx) pglXDestroyContext(gdi_display, ctx->ctx);
|
||||
free_context(ctx);
|
||||
}
|
||||
else
|
||||
if (!is_valid_context(ctx))
|
||||
{
|
||||
WARN("Error deleting context !\n");
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
ret = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
wine_tsx11_unlock();
|
||||
|
||||
return ret;
|
||||
/* WGL doesn't allow deletion of a context which is current in another thread */
|
||||
if (ctx->tid != 0 && ctx->tid != GetCurrentThreadId())
|
||||
{
|
||||
TRACE("Cannot delete context=%p because it is current in another thread.\n", ctx);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ctx->ctx)
|
||||
{
|
||||
wine_tsx11_lock();
|
||||
pglXDestroyContext(gdi_display, ctx->ctx);
|
||||
wine_tsx11_unlock();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1857,16 +1862,26 @@ BOOL CDECL X11DRV_wglMakeCurrent(X11DRV_PDEVICE *physDev, HGLRC hglrc) {
|
|||
if (!has_opengl()) return FALSE;
|
||||
|
||||
wine_tsx11_lock();
|
||||
if (hglrc == NULL) {
|
||||
if (hglrc == NULL)
|
||||
{
|
||||
Wine_GLContext *prev_ctx = NtCurrentTeb()->glContext;
|
||||
if (prev_ctx) prev_ctx->tid = 0;
|
||||
|
||||
ret = pglXMakeCurrent(gdi_display, None, NULL);
|
||||
NtCurrentTeb()->glContext = NULL;
|
||||
} else if (ctx->fmt->iPixelFormat != physDev->current_pf) {
|
||||
}
|
||||
else if (ctx->fmt->iPixelFormat != physDev->current_pf)
|
||||
{
|
||||
WARN( "mismatched pixel format hdc %p %u ctx %p %u\n",
|
||||
hdc, physDev->current_pf, ctx, ctx->fmt->iPixelFormat );
|
||||
SetLastError( ERROR_INVALID_PIXEL_FORMAT );
|
||||
ret = FALSE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Drawable drawable = get_glxdrawable(physDev);
|
||||
Wine_GLContext *prev_ctx = NtCurrentTeb()->glContext;
|
||||
if (prev_ctx) prev_ctx->tid = 0;
|
||||
|
||||
/* The describe lines below are for debugging purposes only */
|
||||
if (TRACE_ON(wgl)) {
|
||||
|
@ -1881,6 +1896,7 @@ BOOL CDECL X11DRV_wglMakeCurrent(X11DRV_PDEVICE *physDev, HGLRC hglrc) {
|
|||
if(ret)
|
||||
{
|
||||
ctx->has_been_current = TRUE;
|
||||
ctx->tid = GetCurrentThreadId();
|
||||
ctx->hdc = hdc;
|
||||
ctx->read_hdc = hdc;
|
||||
ctx->drawables[0] = drawable;
|
||||
|
@ -1913,18 +1929,28 @@ BOOL CDECL X11DRV_wglMakeContextCurrentARB(X11DRV_PDEVICE* pDrawDev, X11DRV_PDEV
|
|||
if (!has_opengl()) return 0;
|
||||
|
||||
wine_tsx11_lock();
|
||||
if (hglrc == NULL) {
|
||||
if (hglrc == NULL)
|
||||
{
|
||||
Wine_GLContext *prev_ctx = NtCurrentTeb()->glContext;
|
||||
if (prev_ctx) prev_ctx->tid = 0;
|
||||
|
||||
ret = pglXMakeCurrent(gdi_display, None, NULL);
|
||||
NtCurrentTeb()->glContext = NULL;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NULL == pglXMakeContextCurrent) {
|
||||
ret = FALSE;
|
||||
} else {
|
||||
Wine_GLContext *prev_ctx = NtCurrentTeb()->glContext;
|
||||
Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
|
||||
Drawable d_draw = get_glxdrawable(pDrawDev);
|
||||
Drawable d_read = get_glxdrawable(pReadDev);
|
||||
|
||||
if (prev_ctx) prev_ctx->tid = 0;
|
||||
|
||||
ctx->has_been_current = TRUE;
|
||||
ctx->tid = GetCurrentThreadId();
|
||||
ctx->hdc = pDrawDev->hdc;
|
||||
ctx->read_hdc = pReadDev->hdc;
|
||||
ctx->drawables[0] = d_draw;
|
||||
|
|
Loading…
Reference in New Issue