[PATCH 1/6] wined3d: Manage occlusion queries in the context.

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


---
 dlls/wined3d/context.c         |   84 +++++++++++++++++++++++++++++++++
 dlls/wined3d/device.c          |   14 +----
 dlls/wined3d/query.c           |  101 +++++++++++++++++++++++-----------------
 dlls/wined3d/wined3d_private.h |   20 ++++++--
 4 files changed, 160 insertions(+), 59 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 5afbda7..ae153d9 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -451,6 +451,63 @@ static void context_apply_fbo_state(struct WineD3DContext *context)
     context_check_fbo_status(context);
 }
 
+/* Context activation is done by the caller. */
+void context_alloc_occlusion_query(struct WineD3DContext *context, struct wined3d_occlusion_query *query)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+
+    if (context->free_occlusion_query_count)
+    {
+        query->id = context->free_occlusion_queries[--context->free_occlusion_query_count];
+    }
+    else
+    {
+        if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
+        {
+            ENTER_GL();
+            GL_EXTCALL(glGenQueriesARB(1, &query->id));
+            checkGLcall("glGenQueriesARB");
+            LEAVE_GL();
+
+            TRACE("Allocated occlusion query %u in context %p.\n", query->id, context);
+        }
+        else
+        {
+            WARN("Occlusion queries not supported, not allocating query id.\n");
+            query->id = 0;
+        }
+    }
+
+    query->context = context;
+    list_add_head(&context->occlusion_queries, &query->entry);
+}
+
+void context_free_occlusion_query(struct wined3d_occlusion_query *query)
+{
+    struct WineD3DContext *context = query->context;
+
+    list_remove(&query->entry);
+    query->context = NULL;
+
+    if (context->free_occlusion_query_count >= context->free_occlusion_query_size - 1)
+    {
+        UINT new_size = context->free_occlusion_query_size << 1;
+        GLuint *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_occlusion_queries,
+                new_size * sizeof(*context->free_occlusion_queries));
+
+        if (!new_data)
+        {
+            ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
+            return;
+        }
+
+        context->free_occlusion_query_size = new_size;
+        context->free_occlusion_queries = new_data;
+    }
+
+    context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
+}
+
 void context_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource, WINED3DRESOURCETYPE type)
 {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
@@ -504,6 +561,7 @@ 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 wined3d_occlusion_query *occlusion_query;
     struct fbo_entry *entry, *entry2;
     BOOL has_glctx;
 
@@ -512,6 +570,12 @@ static void context_destroy_gl_resources(struct WineD3DContext *context)
 
     ENTER_GL();
 
+    LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry)
+    {
+        if (has_glctx && GL_SUPPORT(ARB_OCCLUSION_QUERY)) GL_EXTCALL(glDeleteQueriesARB(1, &occlusion_query->id));
+        occlusion_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);
@@ -532,10 +596,16 @@ static void context_destroy_gl_resources(struct WineD3DContext *context)
         {
             GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
         }
+
+        GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
+
+        checkGLcall("context cleanup");
     }
 
     LEAVE_GL();
 
+    HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries);
+
     if (!pwglMakeCurrent(NULL, NULL))
     {
         ERR("Failed to disable GL context.\n");
@@ -1092,6 +1162,13 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
                 sizeof(*ret->pshader_const_dirty) * GL_LIMITS(pshader_constantsF));
     }
 
+    ret->free_occlusion_query_size = 4;
+    ret->free_occlusion_queries = HeapAlloc(GetProcessHeap(), 0,
+            ret->free_occlusion_query_size * sizeof(*ret->free_occlusion_queries));
+    if (!ret->free_occlusion_queries) goto out;
+
+    list_init(&ret->occlusion_queries);
+
     TRACE("Successfully created new context %p\n", ret);
 
     list_init(&ret->fbo_list);
@@ -1187,6 +1264,13 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
     return ret;
 
 out:
+    if (ret)
+    {
+        HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
+        HeapFree(GetProcessHeap(), 0, ret->pshader_const_dirty);
+        HeapFree(GetProcessHeap(), 0, ret->vshader_const_dirty);
+        HeapFree(GetProcessHeap(), 0, ret);
+    }
     return NULL;
 }
 
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 10b20fb..e5fd2b2 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1191,18 +1191,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINE
     /* allocated the 'extended' data based on the type of query requested */
     switch(Type){
     case WINED3DQUERYTYPE_OCCLUSION:
-        object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
-        ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
-
-        if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
-            TRACE("(%p) Allocating data for an occlusion query\n", This);
+        object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
+        ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
+        break;
 
-            ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
-            ENTER_GL();
-            GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
-            LEAVE_GL();
-            break;
-        }
     case WINED3DQUERYTYPE_EVENT:
         object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
         ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c
index 6627223..a3dfa87 100644
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -94,25 +94,11 @@ static ULONG  WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) {
                 LEAVE_GL();
             }
         }
-        else if (This->type == WINED3DQUERYTYPE_OCCLUSION && GL_SUPPORT(ARB_OCCLUSION_QUERY))
+        else if (This->type == WINED3DQUERYTYPE_OCCLUSION)
         {
-            WineQueryOcclusionData *query_data = (WineQueryOcclusionData *)This->extendedData;
+            struct wined3d_occlusion_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();
-
-                GL_EXTCALL(glDeleteQueriesARB(1, &query_data->queryId));
-                checkGLcall("glDeleteQueriesARB");
-
-                LEAVE_GL();
-            }
+            if (query->context) context_free_occlusion_query(query);
         }
 
         HeapFree(GetProcessHeap(), 0, This->extendedData);
@@ -306,7 +292,7 @@ static HRESULT  WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
 
 static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
-    WineQueryOcclusionData *query_data = (WineQueryOcclusionData *)This->extendedData;
+    struct wined3d_occlusion_query *query = This->extendedData;
     DWORD* data = pData;
     GLuint available;
     GLuint samples;
@@ -314,6 +300,8 @@ static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface,
 
     TRACE("(%p) : type D3DQUERY_OCCLUSION, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
 
+    if (!query->context) This->state = QUERY_CREATED;
+
     if (This->state == QUERY_CREATED)
     {
         /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
@@ -336,18 +324,18 @@ static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface,
         return S_OK;
     }
 
-    if (query_data->ctx->tid != GetCurrentThreadId())
+    if (query->context->tid != GetCurrentThreadId())
     {
         FIXME("%p Wrong thread, returning 1.\n", This);
         *data = 1;
         return S_OK;
     }
 
-    ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD);
+    ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
 
     ENTER_GL();
 
-    GL_EXTCALL(glGetQueryObjectuivARB(query_data->queryId, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
+    GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
     checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)");
     TRACE("(%p) : available %d.\n", This, available);
 
@@ -355,7 +343,7 @@ static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface,
     {
         if (data)
         {
-            GL_EXTCALL(glGetQueryObjectuivARB(query_data->queryId, GL_QUERY_RESULT_ARB, &samples));
+            GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_ARB, &samples));
             checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
             TRACE("(%p) : Returning %d samples.\n", This, samples);
             *data = samples;
@@ -541,38 +529,65 @@ static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_Issue(IWineD3DQuery* iface,  D
 
     if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
     {
-        WineQueryOcclusionData *query_data = (WineQueryOcclusionData *)This->extendedData;
+        struct wined3d_occlusion_query *query = This->extendedData;
+        struct WineD3DContext *context;
 
-        if (query_data->ctx->tid != GetCurrentThreadId())
+        /* This is allowed according to msdn and our tests. Reset the query and restart */
+        if (dwIssueFlags & WINED3DISSUE_BEGIN)
         {
-            FIXME("Not the owning context, can't start query.\n");
-        }
-        else
-        {
-            ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD);
+            if (This->state == QUERY_BUILDING)
+            {
+                if (query->context->tid != GetCurrentThreadId())
+                {
+                    FIXME("Wrong thread, can't restart query.\n");
 
-            ENTER_GL();
-            /* This is allowed according to msdn and our tests. Reset the query and restart */
-            if (dwIssueFlags & WINED3DISSUE_BEGIN) {
-                if(This->state == QUERY_BUILDING) {
+                    context_free_occlusion_query(query);
+                    context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD);
+                    context_alloc_occlusion_query(context, query);
+                }
+                else
+                {
+                    ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
+
+                    ENTER_GL();
                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
                     checkGLcall("glEndQuery()");
+                    LEAVE_GL();
                 }
-
-                GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, query_data->queryId));
-                checkGLcall("glBeginQuery()");
             }
-            if (dwIssueFlags & WINED3DISSUE_END) {
-                /* Msdn says _END on a non-building occlusion query returns an error, but
-                 * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
-                 * generating an error
-                 */
-                if(This->state == QUERY_BUILDING) {
+            else
+            {
+                if (query->context) context_free_occlusion_query(query);
+                context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD);
+                context_alloc_occlusion_query(context, query);
+            }
+
+            ENTER_GL();
+            GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, query->id));
+            checkGLcall("glBeginQuery()");
+            LEAVE_GL();
+        }
+        if (dwIssueFlags & WINED3DISSUE_END) {
+            /* Msdn says _END on a non-building occlusion query returns an error, but
+             * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
+             * generating an error
+             */
+            if (This->state == QUERY_BUILDING)
+            {
+                if (query->context->tid != GetCurrentThreadId())
+                {
+                    FIXME("Wrong thread, can't end query.\n");
+                }
+                else
+                {
+                    ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
+
+                    ENTER_GL();
                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
                     checkGLcall("glEndQuery()");
+                    LEAVE_GL();
                 }
             }
-            LEAVE_GL();
         }
     } else {
         FIXME("(%p) : Occlusion queries not supported\n", This);
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index bb64875..533befd 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1188,6 +1188,13 @@ enum fogsource {
 
 #define WINED3D_MAX_FBO_ENTRIES 64
 
+struct wined3d_occlusion_query
+{
+    struct list entry;
+    GLuint id;
+    struct WineD3DContext *context;
+};
+
 /* The new context manager that should deal with onscreen and offscreen rendering */
 struct WineD3DContext
 {
@@ -1248,6 +1255,12 @@ struct WineD3DContext
     GLuint                  fbo_read_binding;
     GLuint                  fbo_draw_binding;
 
+    /* Queries */
+    GLuint *free_occlusion_queries;
+    UINT free_occlusion_query_size;
+    UINT free_occlusion_query_count;
+    struct list occlusion_queries;
+
     /* Extension emulation */
     GLint                   gl_fog_source;
     GLfloat                 fog_coord_value;
@@ -1265,12 +1278,14 @@ 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_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);
 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_occlusion_query(struct wined3d_occlusion_query *query);
 struct WineD3DContext *context_get_current(void);
 DWORD context_get_tls_idx(void);
 BOOL context_set_current(struct WineD3DContext *ctx);
@@ -2350,11 +2365,6 @@ extern const IWineD3DQueryVtbl IWineD3DEventQuery_Vtbl;
 extern const IWineD3DQueryVtbl IWineD3DOcclusionQuery_Vtbl;
 
 /* Datastructures for IWineD3DQueryImpl.extendedData */
-typedef struct  WineQueryOcclusionData {
-    GLuint  queryId;
-    WineD3DContext *ctx;
-} WineQueryOcclusionData;
-
 typedef struct  WineQueryEventData {
     GLuint  fenceId;
     WineD3DContext *ctx;
-- 
1.6.0.6




More information about the wine-patches mailing list