[PATCH 2/6] wined3d: Manage event queries in the context.

Henri Verbeet hverbeet at codeweavers.com
Fri Jul 24 03:44:14 CDT 2009


---
 dlls/wined3d/context.c         |   92 ++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/device.c          |   15 +------
 dlls/wined3d/query.c           |   92 ++++++++++++++++-----------------------
 dlls/wined3d/wined3d_private.h |   20 ++++++---
 4 files changed, 146 insertions(+), 73 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index ae153d9..0109254 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -2,6 +2,7 @@
  * Context and render target management in wined3d
  *
  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
+ * Copyright 2009 Henri Verbeet for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -508,6 +509,72 @@ void context_free_occlusion_query(struct wined3d_occlusion_query *query)
     context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
 }
 
+/* Context activation is done by the caller. */
+void context_alloc_event_query(struct WineD3DContext *context, struct wined3d_event_query *query)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+
+    if (context->free_event_query_count)
+    {
+        query->id = context->free_event_queries[--context->free_event_query_count];
+    }
+    else
+    {
+        if (GL_SUPPORT(APPLE_FENCE))
+        {
+            ENTER_GL();
+            GL_EXTCALL(glGenFencesAPPLE(1, &query->id));
+            checkGLcall("glGenFencesAPPLE");
+            LEAVE_GL();
+
+            TRACE("Allocated event query %u in context %p.\n", query->id, context);
+        }
+        else if(GL_SUPPORT(NV_FENCE))
+        {
+            ENTER_GL();
+            GL_EXTCALL(glGenFencesNV(1, &query->id));
+            checkGLcall("glGenFencesNV");
+            LEAVE_GL();
+
+            TRACE("Allocated event query %u in context %p.\n", query->id, context);
+        }
+        else
+        {
+            WARN("Event queries not supported, not allocating query id.\n");
+            query->id = 0;
+        }
+    }
+
+    query->context = context;
+    list_add_head(&context->event_queries, &query->entry);
+}
+
+void context_free_event_query(struct wined3d_event_query *query)
+{
+    struct WineD3DContext *context = query->context;
+
+    list_remove(&query->entry);
+    query->context = NULL;
+
+    if (context->free_event_query_count >= context->free_event_query_size - 1)
+    {
+        UINT new_size = context->free_event_query_size << 1;
+        GLuint *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_event_queries,
+                new_size * sizeof(*context->free_event_queries));
+
+        if (!new_data)
+        {
+            ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
+            return;
+        }
+
+        context->free_event_query_size = new_size;
+        context->free_event_queries = new_data;
+    }
+
+    context->free_event_queries[context->free_event_query_count++] = query->id;
+}
+
 void context_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource, WINED3DRESOURCETYPE type)
 {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
@@ -562,6 +629,7 @@ static void context_destroy_gl_resources(struct WineD3DContext *context)
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
     struct wined3d_occlusion_query *occlusion_query;
+    struct wined3d_event_query *event_query;
     struct fbo_entry *entry, *entry2;
     BOOL has_glctx;
 
@@ -576,6 +644,16 @@ static void context_destroy_gl_resources(struct WineD3DContext *context)
         occlusion_query->context = NULL;
     }
 
+    LIST_FOR_EACH_ENTRY(event_query, &context->event_queries, struct wined3d_event_query, entry)
+    {
+        if (has_glctx)
+        {
+            if (GL_SUPPORT(APPLE_FENCE)) GL_EXTCALL(glDeleteFencesAPPLE(1, &event_query->id));
+            else if (GL_SUPPORT(NV_FENCE)) GL_EXTCALL(glDeleteFencesNV(1, &event_query->id));
+        }
+        event_query->context = 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);
@@ -599,12 +677,18 @@ static void context_destroy_gl_resources(struct WineD3DContext *context)
 
         GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
 
+        if (GL_SUPPORT(APPLE_FENCE))
+            GL_EXTCALL(glDeleteFencesAPPLE(context->free_event_query_count, context->free_event_queries));
+        else if (GL_SUPPORT(NV_FENCE))
+            GL_EXTCALL(glDeleteFencesNV(context->free_event_query_count, context->free_event_queries));
+
         checkGLcall("context cleanup");
     }
 
     LEAVE_GL();
 
     HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries);
+    HeapFree(GetProcessHeap(), 0, context->free_event_queries);
 
     if (!pwglMakeCurrent(NULL, NULL))
     {
@@ -1169,6 +1253,13 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
 
     list_init(&ret->occlusion_queries);
 
+    ret->free_event_query_size = 4;
+    ret->free_event_queries = HeapAlloc(GetProcessHeap(), 0,
+            ret->free_event_query_size * sizeof(*ret->free_event_queries));
+    if (!ret->free_event_queries) goto out;
+
+    list_init(&ret->event_queries);
+
     TRACE("Successfully created new context %p\n", ret);
 
     list_init(&ret->fbo_list);
@@ -1266,6 +1357,7 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
 out:
     if (ret)
     {
+        HeapFree(GetProcessHeap(), 0, ret->free_event_queries);
         HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
         HeapFree(GetProcessHeap(), 0, ret->pshader_const_dirty);
         HeapFree(GetProcessHeap(), 0, ret->vshader_const_dirty);
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index e5fd2b2..6edb39e 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1196,19 +1196,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINE
         break;
 
     case WINED3DQUERYTYPE_EVENT:
-        object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
-        ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
-
-        ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
-        ENTER_GL();
-        if(GL_SUPPORT(APPLE_FENCE)) {
-            GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
-            checkGLcall("glGenFencesAPPLE");
-        } else if(GL_SUPPORT(NV_FENCE)) {
-            GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
-            checkGLcall("glGenFencesNV");
-        }
-        LEAVE_GL();
+        object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
+        ((struct wined3d_event_query *)object->extendedData)->context = NULL;
         break;
 
     case WINED3DQUERYTYPE_VCACHE:
diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c
index a3dfa87..0f395bc 100644
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -68,31 +68,9 @@ static ULONG  WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) {
          * context, and (still) leaking the actual query. */
         if (This->type == WINED3DQUERYTYPE_EVENT)
         {
-            WineQueryEventData *query_data = (WineQueryEventData *)This->extendedData;
+            struct wined3d_event_query *query = This->extendedData;
 
-            if (query_data->ctx->tid != GetCurrentThreadId())
-            {
-                FIXME("Query was created in a different thread, skipping deletion.\n");
-            }
-            else
-            {
-                ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD);
-
-                ENTER_GL();
-
-                if (GL_SUPPORT(APPLE_FENCE))
-                {
-                    GL_EXTCALL(glDeleteFencesAPPLE(1, &query_data->fenceId));
-                    checkGLcall("glDeleteFencesAPPLE");
-                }
-                else if (GL_SUPPORT(NV_FENCE))
-                {
-                    GL_EXTCALL(glDeleteFencesNV(1, &query_data->fenceId));
-                    checkGLcall("glDeleteFencesNV");
-                }
-
-                LEAVE_GL();
-            }
+            if (query->context) context_free_event_query(query);
         }
         else if (This->type == WINED3DQUERYTYPE_OCCLUSION)
         {
@@ -362,14 +340,14 @@ static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface,
 
 static HRESULT  WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
+    struct wined3d_event_query *query = This->extendedData;
     BOOL* data = pData;
-    WineQueryEventData *query_data = (WineQueryEventData *)This->extendedData;
 
     TRACE("(%p) : type D3DQUERY_EVENT, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
 
     if (!pData || !dwSize) return S_OK;
 
-    if (query_data->ctx->tid != GetCurrentThreadId())
+    if (query->context->tid != GetCurrentThreadId())
     {
         /* See comment in IWineD3DQuery::Issue, event query codeblock */
         FIXME("Wrong thread, reporting GPU idle.\n");
@@ -378,18 +356,18 @@ static HRESULT  WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void
         return S_OK;
     }
 
-    ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD);
+    ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
 
     ENTER_GL();
 
     if (GL_SUPPORT(APPLE_FENCE))
     {
-        *data = GL_EXTCALL(glTestFenceAPPLE(query_data->fenceId));
+        *data = GL_EXTCALL(glTestFenceAPPLE(query->id));
         checkGLcall("glTestFenceAPPLE");
     }
     else if (GL_SUPPORT(NV_FENCE))
     {
-        *data = GL_EXTCALL(glTestFenceNV(query_data->fenceId));
+        *data = GL_EXTCALL(glTestFenceNV(query->id));
         checkGLcall("glTestFenceNV");
     }
     else
@@ -478,39 +456,45 @@ static HRESULT  WINAPI IWineD3DEventQueryImpl_Issue(IWineD3DQuery* iface,  DWORD
     TRACE("(%p) : dwIssueFlags %#x, type D3DQUERY_EVENT\n", This, dwIssueFlags);
     if (dwIssueFlags & WINED3DISSUE_END)
     {
-        WineQueryEventData *query_data = (WineQueryEventData *)This->extendedData;
+        struct wined3d_event_query *query = This->extendedData;
+        struct WineD3DContext *context;
 
-        if (query_data->ctx->tid != GetCurrentThreadId())
-        {
-            /* GL fences can be used only from the context that created them,
-             * so if a different context is active, don't bother setting the query. The penalty
-             * of a context switch is most likely higher than the gain of a correct query result
-             *
-             * If the query is used from a different thread, don't bother creating a multithread
-             * context - there's no point in doing that as the query would be unusable anyway
-             */
-            WARN("Query context not active\n");
-        }
-        else
+        if (query->context)
         {
-            ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD);
-
-            ENTER_GL();
-
-            if (GL_SUPPORT(APPLE_FENCE))
+            if (query->context->tid != GetCurrentThreadId())
             {
-                GL_EXTCALL(glSetFenceAPPLE(query_data->fenceId));
-                checkGLcall("glSetFenceAPPLE");
+                context_free_event_query(query);
+                context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD);
+                context_alloc_event_query(context, query);
             }
-            else if (GL_SUPPORT(NV_FENCE))
+            else
             {
-                GL_EXTCALL(glSetFenceNV(query_data->fenceId, GL_ALL_COMPLETED_NV));
-                checkGLcall("glSetFenceNV");
+                ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
             }
+        }
+        else
+        {
+            context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD);
+            context_alloc_event_query(context, query);
+        }
 
-            LEAVE_GL();
+        ENTER_GL();
+
+        if (GL_SUPPORT(APPLE_FENCE))
+        {
+            GL_EXTCALL(glSetFenceAPPLE(query->id));
+            checkGLcall("glSetFenceAPPLE");
         }
-    } else if(dwIssueFlags & WINED3DISSUE_BEGIN) {
+        else if (GL_SUPPORT(NV_FENCE))
+        {
+            GL_EXTCALL(glSetFenceNV(query->id, GL_ALL_COMPLETED_NV));
+            checkGLcall("glSetFenceNV");
+        }
+
+        LEAVE_GL();
+    }
+    else if(dwIssueFlags & WINED3DISSUE_BEGIN)
+    {
         /* Started implicitly at device creation */
         ERR("Event query issued with START flag - what to do?\n");
     }
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 533befd..be2811b 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1195,6 +1195,13 @@ struct wined3d_occlusion_query
     struct WineD3DContext *context;
 };
 
+struct wined3d_event_query
+{
+    struct list entry;
+    GLuint id;
+    struct WineD3DContext *context;
+};
+
 /* The new context manager that should deal with onscreen and offscreen rendering */
 struct WineD3DContext
 {
@@ -1261,6 +1268,11 @@ struct WineD3DContext
     UINT free_occlusion_query_count;
     struct list occlusion_queries;
 
+    GLuint *free_event_queries;
+    UINT free_event_query_size;
+    UINT free_event_query_count;
+    struct list event_queries;
+
     /* Extension emulation */
     GLint                   gl_fog_source;
     GLfloat                 fog_coord_value;
@@ -1278,6 +1290,7 @@ typedef enum ContextUsage {
 struct WineD3DContext *ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, enum ContextUsage usage);
 WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, HWND win, BOOL create_pbuffer, const WINED3DPRESENT_PARAMETERS *pPresentParms);
 void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context);
+void context_alloc_event_query(struct WineD3DContext *context, struct wined3d_event_query *query);
 void context_alloc_occlusion_query(struct WineD3DContext *context, struct wined3d_occlusion_query *query);
 void context_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource, WINED3DRESOURCETYPE type);
 void context_bind_fbo(struct WineD3DContext *context, GLenum target, GLuint *fbo);
@@ -1285,6 +1298,7 @@ void context_attach_depth_stencil_fbo(struct WineD3DContext *context,
         GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer);
 void context_attach_surface_fbo(const struct WineD3DContext *context,
         GLenum fbo_target, DWORD idx, IWineD3DSurface *surface);
+void context_free_event_query(struct wined3d_event_query *query);
 void context_free_occlusion_query(struct wined3d_occlusion_query *query);
 struct WineD3DContext *context_get_current(void);
 DWORD context_get_tls_idx(void);
@@ -2364,12 +2378,6 @@ extern const IWineD3DQueryVtbl IWineD3DQuery_Vtbl;
 extern const IWineD3DQueryVtbl IWineD3DEventQuery_Vtbl;
 extern const IWineD3DQueryVtbl IWineD3DOcclusionQuery_Vtbl;
 
-/* Datastructures for IWineD3DQueryImpl.extendedData */
-typedef struct  WineQueryEventData {
-    GLuint  fenceId;
-    WineD3DContext *ctx;
-} WineQueryEventData;
-
 /* IWineD3DBuffer */
 
 /* TODO: Add tests and support for FLOAT16_4 POSITIONT, D3DCOLOR position, other
-- 
1.6.0.6




More information about the wine-patches mailing list