[PATCH 2/6] wined3d: Avoid destroying contexts that are current in another thread.
Henri Verbeet
hverbeet at codeweavers.com
Wed Jul 22 03:41:06 CDT 2009
---
dlls/wined3d/context.c | 130 ++++++++++++++++++++++++++--------------
dlls/wined3d/wined3d_private.h | 4 +-
2 files changed, 89 insertions(+), 45 deletions(-)
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index ba49ddb..bfcd3cf 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -558,6 +558,59 @@ void context_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource
}
}
+static void context_destroy_gl_resources(struct WineD3DContext *context)
+{
+ const struct wined3d_gl_info *gl_info = context->gl_info;
+ struct fbo_entry *entry, *entry2;
+ BOOL has_glctx;
+
+ has_glctx = pwglMakeCurrent(context->hdc, context->glCtx);
+ if (!has_glctx) WARN("Failed to activate context. Window already destroyed?\n");
+
+ ENTER_GL();
+
+ LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry) {
+ if (!has_glctx) entry->id = 0;
+ context_destroy_fbo_entry(context, entry);
+ }
+ if (has_glctx)
+ {
+ if (context->src_fbo)
+ {
+ TRACE("Destroy src FBO %d\n", context->src_fbo);
+ context_destroy_fbo(context, &context->src_fbo);
+ }
+ if (context->dst_fbo)
+ {
+ TRACE("Destroy dst FBO %d\n", context->dst_fbo);
+ context_destroy_fbo(context, &context->dst_fbo);
+ }
+ if (context->dummy_arbfp_prog)
+ {
+ GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
+ }
+ }
+
+ LEAVE_GL();
+
+ if (!pwglMakeCurrent(NULL, NULL))
+ {
+ ERR("Failed to disable GL context.\n");
+ }
+
+ if (context->isPBuffer)
+ {
+ GL_EXTCALL(wglReleasePbufferDCARB(context->pbuffer, context->hdc));
+ GL_EXTCALL(wglDestroyPbufferARB(context->pbuffer));
+ }
+ else
+ {
+ ReleaseDC(context->win_handle, context->hdc);
+ }
+
+ pwglDeleteContext(context->glCtx);
+}
+
DWORD context_get_tls_idx(void)
{
return wined3d_context_tls_idx;
@@ -583,6 +636,20 @@ BOOL context_set_current(struct WineD3DContext *ctx)
return TRUE;
}
+ if (old)
+ {
+ if (old->destroyed)
+ {
+ TRACE("Switching away from destroyed context %p.\n", old);
+ context_destroy_gl_resources(old);
+ HeapFree(GetProcessHeap(), 0, old);
+ }
+ else
+ {
+ old->current = 0;
+ }
+ }
+
if (ctx)
{
TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->hdc);
@@ -591,6 +658,7 @@ BOOL context_set_current(struct WineD3DContext *ctx)
ERR("Failed to make GL context %p current on device context %p.\n", ctx->glCtx, ctx->hdc);
return FALSE;
}
+ ctx->current = 1;
}
else
{
@@ -1211,7 +1279,6 @@ static void RemoveContextFromArray(IWineD3DDeviceImpl *This, WineD3DContext *con
{
if (This->contexts[i] == context)
{
- HeapFree(GetProcessHeap(), 0, context);
found = TRUE;
break;
}
@@ -1257,65 +1324,40 @@ static void RemoveContextFromArray(IWineD3DDeviceImpl *This, WineD3DContext *con
* context: Context to destroy
*
*****************************************************************************/
-void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context) {
- const struct wined3d_gl_info *gl_info = context->gl_info;
- struct fbo_entry *entry, *entry2;
- BOOL has_glctx;
+void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context)
+{
+ BOOL destroy;
TRACE("Destroying ctx %p\n", context);
- /* The correct GL context needs to be active to cleanup the GL resources below */
- has_glctx = pwglMakeCurrent(context->hdc, context->glCtx);
- context_set_last_device(NULL);
-
- if (!has_glctx) WARN("Failed to activate context. Window already destroyed?\n");
+ if (context->tid == GetCurrentThreadId() || !context->current)
+ {
+ context_destroy_gl_resources(context);
+ destroy = TRUE;
- ENTER_GL();
+ context_set_last_device(NULL);
- LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry) {
- if (!has_glctx) entry->id = 0;
- context_destroy_fbo_entry(context, entry);
- }
- if (has_glctx)
- {
- if (context->src_fbo)
- {
- TRACE("Destroy src FBO %d\n", context->src_fbo);
- context_destroy_fbo(context, &context->src_fbo);
- }
- if (context->dst_fbo)
+ if (This->activeContext == context)
{
- TRACE("Destroy dst FBO %d\n", context->dst_fbo);
- context_destroy_fbo(context, &context->dst_fbo);
+ This->activeContext = NULL;
+ TRACE("Destroying the active context.\n");
}
- if (context->dummy_arbfp_prog)
+
+ if (!context_set_current(NULL))
{
- GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
+ ERR("Failed to clear current D3D context.\n");
}
}
-
- LEAVE_GL();
-
- if (This->activeContext == context)
- {
- This->activeContext = NULL;
- TRACE("Destroying the active context.\n");
- }
-
- if (!context_set_current(NULL))
+ else
{
- ERR("Failed to clear current D3D context.\n");
+ context->destroyed = 1;
+ destroy = FALSE;
}
- if(context->isPBuffer) {
- GL_EXTCALL(wglReleasePbufferDCARB(context->pbuffer, context->hdc));
- GL_EXTCALL(wglDestroyPbufferARB(context->pbuffer));
- } else ReleaseDC(context->win_handle, context->hdc);
- pwglDeleteContext(context->glCtx);
-
HeapFree(GetProcessHeap(), 0, context->vshader_const_dirty);
HeapFree(GetProcessHeap(), 0, context->pshader_const_dirty);
RemoveContextFromArray(This, context);
+ if (destroy) HeapFree(GetProcessHeap(), 0, context);
}
/* GL locking is done by the caller */
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 25d18df..a21bec5 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1219,7 +1219,9 @@ struct WineD3DContext
WORD isPBuffer : 1;
WORD fog_enabled : 1;
WORD num_untracked_materials : 2; /* Max value 2 */
- WORD padding : 3;
+ WORD current : 1;
+ WORD destroyed : 1;
+ WORD padding : 1;
BYTE texShaderBumpMap; /* MAX_TEXTURES, 8 */
BYTE lastWasPow2Texture; /* MAX_TEXTURES, 8 */
DWORD numbered_array_mask;
--
1.6.0.6
More information about the wine-patches
mailing list