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)
|
static void test_make_current_read(HDC hdc)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
@ -802,6 +857,7 @@ START_TEST(opengl)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_deletecontext(hdc);
|
||||||
test_makecurrent(hdc);
|
test_makecurrent(hdc);
|
||||||
test_setpixelformat(hdc);
|
test_setpixelformat(hdc);
|
||||||
test_sharelists(hdc);
|
test_sharelists(hdc);
|
||||||
|
|
|
@ -113,6 +113,7 @@ typedef struct wine_glcontext {
|
||||||
BOOL do_escape;
|
BOOL do_escape;
|
||||||
BOOL has_been_current;
|
BOOL has_been_current;
|
||||||
BOOL sharing;
|
BOOL sharing;
|
||||||
|
DWORD tid;
|
||||||
BOOL gl3_context;
|
BOOL gl3_context;
|
||||||
XVisualInfo *vis;
|
XVisualInfo *vis;
|
||||||
WineGLPixelFormat *fmt;
|
WineGLPixelFormat *fmt;
|
||||||
|
@ -1763,29 +1764,33 @@ HGLRC CDECL X11DRV_wglCreateContext(X11DRV_PDEVICE *physDev)
|
||||||
BOOL CDECL X11DRV_wglDeleteContext(HGLRC hglrc)
|
BOOL CDECL X11DRV_wglDeleteContext(HGLRC hglrc)
|
||||||
{
|
{
|
||||||
Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
|
Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
|
||||||
BOOL ret = TRUE;
|
|
||||||
|
|
||||||
TRACE("(%p)\n", hglrc);
|
TRACE("(%p)\n", hglrc);
|
||||||
|
|
||||||
if (!has_opengl()) return 0;
|
if (!has_opengl()) return 0;
|
||||||
|
|
||||||
wine_tsx11_lock();
|
if (!is_valid_context(ctx))
|
||||||
/* 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
|
|
||||||
{
|
{
|
||||||
WARN("Error deleting context !\n");
|
WARN("Error deleting context !\n");
|
||||||
SetLastError(ERROR_INVALID_HANDLE);
|
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;
|
if (!has_opengl()) return FALSE;
|
||||||
|
|
||||||
wine_tsx11_lock();
|
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);
|
ret = pglXMakeCurrent(gdi_display, None, NULL);
|
||||||
NtCurrentTeb()->glContext = 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",
|
WARN( "mismatched pixel format hdc %p %u ctx %p %u\n",
|
||||||
hdc, physDev->current_pf, ctx, ctx->fmt->iPixelFormat );
|
hdc, physDev->current_pf, ctx, ctx->fmt->iPixelFormat );
|
||||||
SetLastError( ERROR_INVALID_PIXEL_FORMAT );
|
SetLastError( ERROR_INVALID_PIXEL_FORMAT );
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Drawable drawable = get_glxdrawable(physDev);
|
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 */
|
/* The describe lines below are for debugging purposes only */
|
||||||
if (TRACE_ON(wgl)) {
|
if (TRACE_ON(wgl)) {
|
||||||
|
@ -1881,6 +1896,7 @@ BOOL CDECL X11DRV_wglMakeCurrent(X11DRV_PDEVICE *physDev, HGLRC hglrc) {
|
||||||
if(ret)
|
if(ret)
|
||||||
{
|
{
|
||||||
ctx->has_been_current = TRUE;
|
ctx->has_been_current = TRUE;
|
||||||
|
ctx->tid = GetCurrentThreadId();
|
||||||
ctx->hdc = hdc;
|
ctx->hdc = hdc;
|
||||||
ctx->read_hdc = hdc;
|
ctx->read_hdc = hdc;
|
||||||
ctx->drawables[0] = drawable;
|
ctx->drawables[0] = drawable;
|
||||||
|
@ -1913,18 +1929,28 @@ BOOL CDECL X11DRV_wglMakeContextCurrentARB(X11DRV_PDEVICE* pDrawDev, X11DRV_PDEV
|
||||||
if (!has_opengl()) return 0;
|
if (!has_opengl()) return 0;
|
||||||
|
|
||||||
wine_tsx11_lock();
|
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);
|
ret = pglXMakeCurrent(gdi_display, None, NULL);
|
||||||
NtCurrentTeb()->glContext = NULL;
|
NtCurrentTeb()->glContext = NULL;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (NULL == pglXMakeContextCurrent) {
|
if (NULL == pglXMakeContextCurrent) {
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
} else {
|
} else {
|
||||||
|
Wine_GLContext *prev_ctx = NtCurrentTeb()->glContext;
|
||||||
Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
|
Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
|
||||||
Drawable d_draw = get_glxdrawable(pDrawDev);
|
Drawable d_draw = get_glxdrawable(pDrawDev);
|
||||||
Drawable d_read = get_glxdrawable(pReadDev);
|
Drawable d_read = get_glxdrawable(pReadDev);
|
||||||
|
|
||||||
|
if (prev_ctx) prev_ctx->tid = 0;
|
||||||
|
|
||||||
ctx->has_been_current = TRUE;
|
ctx->has_been_current = TRUE;
|
||||||
|
ctx->tid = GetCurrentThreadId();
|
||||||
ctx->hdc = pDrawDev->hdc;
|
ctx->hdc = pDrawDev->hdc;
|
||||||
ctx->read_hdc = pReadDev->hdc;
|
ctx->read_hdc = pReadDev->hdc;
|
||||||
ctx->drawables[0] = d_draw;
|
ctx->drawables[0] = d_draw;
|
||||||
|
|
Loading…
Reference in New Issue