[PATCH 3/5] wined3d: Add support for timestamp queries. (try 2)

Matteo Bruni mbruni at codeweavers.com
Mon Apr 14 15:52:00 CDT 2014


---
 dlls/d3d9/query.c              |  21 ++++-
 dlls/wined3d/context.c         |  67 ++++++++++++++
 dlls/wined3d/query.c           | 205 ++++++++++++++++++++++++++++++++++++++++-
 dlls/wined3d/wined3d_private.h |  15 +++
 include/wine/wined3d.h         |   6 ++
 5 files changed, 309 insertions(+), 5 deletions(-)

diff --git a/dlls/d3d9/query.c b/dlls/d3d9/query.c
index d363413..f738cf0 100644
--- a/dlls/d3d9/query.c
+++ b/dlls/d3d9/query.c
@@ -108,12 +108,17 @@ static D3DQUERYTYPE WINAPI d3d9_query_GetType(IDirect3DQuery9 *iface)
 static DWORD WINAPI d3d9_query_GetDataSize(IDirect3DQuery9 *iface)
 {
     struct d3d9_query *query = impl_from_IDirect3DQuery9(iface);
+    D3DQUERYTYPE type;
     DWORD ret;
 
     TRACE("iface %p.\n", iface);
 
     wined3d_mutex_lock();
-    ret = wined3d_query_get_data_size(query->wined3d_query);
+    type = wined3d_query_get_type(query->wined3d_query);
+    if (type == D3DQUERYTYPE_TIMESTAMPDISJOINT)
+        ret = sizeof(BOOL);
+    else
+        ret = wined3d_query_get_data_size(query->wined3d_query);
     wined3d_mutex_unlock();
 
     return ret;
@@ -136,13 +141,25 @@ static HRESULT WINAPI d3d9_query_Issue(IDirect3DQuery9 *iface, DWORD flags)
 static HRESULT WINAPI d3d9_query_GetData(IDirect3DQuery9 *iface, void *data, DWORD size, DWORD flags)
 {
     struct d3d9_query *query = impl_from_IDirect3DQuery9(iface);
+    D3DQUERYTYPE type;
     HRESULT hr;
 
     TRACE("iface %p, data %p, size %u, flags %#x.\n",
             iface, data, size, flags);
 
     wined3d_mutex_lock();
-    hr = wined3d_query_get_data(query->wined3d_query, data, size, flags);
+    type = wined3d_query_get_type(query->wined3d_query);
+    if (type == D3DQUERYTYPE_TIMESTAMPDISJOINT && data && size == sizeof(BOOL))
+    {
+        struct wined3d_query_data_timestamp_disjoint data_disjoint;
+
+        hr = wined3d_query_get_data(query->wined3d_query, &data_disjoint, sizeof(data_disjoint), flags);
+        *(BOOL *)data = data_disjoint.disjoint;
+    }
+    else
+    {
+        hr = wined3d_query_get_data(query->wined3d_query, data, size, flags);
+    }
     wined3d_mutex_unlock();
 
     return hr;
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 00ab25f..d9f6505 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -614,6 +614,61 @@ void context_free_event_query(struct wined3d_event_query *query)
     context->free_event_queries[context->free_event_query_count++] = query->object;
 }
 
+/* Context activation is done by the caller. */
+void context_alloc_timestamp_query(struct wined3d_context *context, struct wined3d_timestamp_query *query)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+
+    if (context->free_timestamp_query_count)
+    {
+        query->id = context->free_timestamp_queries[--context->free_timestamp_query_count];
+    }
+    else
+    {
+        if (gl_info->supported[ARB_TIMER_QUERY])
+        {
+            GL_EXTCALL(glGenQueriesARB(1, &query->id));
+            checkGLcall("glGenQueriesARB");
+
+            TRACE("Allocated timestamp query %u in context %p.\n", query->id, context);
+        }
+        else
+        {
+            WARN("Timestamp queries not supported, not allocating query id.\n");
+            query->id = 0;
+        }
+    }
+
+    query->context = context;
+    list_add_head(&context->timestamp_queries, &query->entry);
+}
+
+void context_free_timestamp_query(struct wined3d_timestamp_query *query)
+{
+    struct wined3d_context *context = query->context;
+
+    list_remove(&query->entry);
+    query->context = NULL;
+
+    if (context->free_timestamp_query_count >= context->free_timestamp_query_size - 1)
+    {
+        UINT new_size = context->free_timestamp_query_size << 1;
+        GLuint *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_timestamp_queries,
+                new_size * sizeof(*context->free_timestamp_queries));
+
+        if (!new_data)
+        {
+            ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
+            return;
+        }
+
+        context->free_timestamp_query_size = new_size;
+        context->free_timestamp_queries = new_data;
+    }
+
+    context->free_timestamp_queries[context->free_timestamp_query_count++] = query->id;
+}
+
 typedef void (context_fbo_entry_func_t)(struct wined3d_context *context, struct fbo_entry *entry);
 
 static void context_enum_surface_fbo_entries(const struct wined3d_device *device,
@@ -969,6 +1024,9 @@ static void context_destroy_gl_resources(struct wined3d_context *context)
             GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
         }
 
+        if (gl_info->supported[ARB_TIMER_QUERY])
+            GL_EXTCALL(glDeleteQueriesARB(context->free_timestamp_query_count, context->free_timestamp_queries));
+
         if (gl_info->supported[ARB_OCCLUSION_QUERY])
             GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
 
@@ -997,6 +1055,7 @@ static void context_destroy_gl_resources(struct wined3d_context *context)
         checkGLcall("context cleanup");
     }
 
+    HeapFree(GetProcessHeap(), 0, context->free_timestamp_queries);
     HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries);
     HeapFree(GetProcessHeap(), 0, context->free_event_queries);
 
@@ -1358,6 +1417,13 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
     if (!ret->draw_buffers)
         goto out;
 
+    ret->free_timestamp_query_size = 4;
+    ret->free_timestamp_queries = HeapAlloc(GetProcessHeap(), 0,
+            ret->free_timestamp_query_size * sizeof(*ret->free_timestamp_queries));
+    if (!ret->free_timestamp_queries)
+        goto out;
+    list_init(&ret->timestamp_queries);
+
     ret->free_occlusion_query_size = 4;
     ret->free_occlusion_queries = HeapAlloc(GetProcessHeap(), 0,
             ret->free_occlusion_query_size * sizeof(*ret->free_occlusion_queries));
@@ -1700,6 +1766,7 @@ out:
     device->shader_backend->shader_free_context_data(ret);
     HeapFree(GetProcessHeap(), 0, ret->free_event_queries);
     HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
+    HeapFree(GetProcessHeap(), 0, ret->free_timestamp_queries);
     HeapFree(GetProcessHeap(), 0, ret->draw_buffers);
     HeapFree(GetProcessHeap(), 0, ret->blit_targets);
     HeapFree(GetProcessHeap(), 0, ret);
diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c
index a3a9246..0a3f61d 100644
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -257,6 +257,14 @@ ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
             if (oq->context) context_free_occlusion_query(oq);
             HeapFree(GetProcessHeap(), 0, query->extendedData);
         }
+        else if (query->type == WINED3D_QUERY_TYPE_TIMESTAMP)
+        {
+            struct wined3d_timestamp_query *tq = query->extendedData;
+
+            if (tq->context)
+                context_free_timestamp_query(tq);
+            HeapFree(GetProcessHeap(), 0, query->extendedData);
+        }
 
         HeapFree(GetProcessHeap(), 0, query);
     }
@@ -519,6 +527,156 @@ static HRESULT wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DW
     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
 }
 
+static HRESULT wined3d_timestamp_query_ops_get_data(struct wined3d_query *query,
+        void *data, DWORD size, DWORD flags)
+{
+    struct wined3d_timestamp_query *tq = query->extendedData;
+    struct wined3d_device *device = query->device;
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+    struct wined3d_context *context;
+    UINT64 *u64data = data;
+    GLuint available;
+    GLuint64 timestamp;
+    HRESULT res;
+
+    TRACE("(%p) : type D3DQUERY_TIMESTAMP, data %p, size %#x, flags %#x.\n", query, data, size, flags);
+
+    if (!tq->context)
+        query->state = QUERY_CREATED;
+
+    if (query->state == QUERY_CREATED)
+    {
+        /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves. */
+        TRACE("Query wasn't yet started, returning S_OK.\n");
+        if (u64data)
+            *u64data = 0;
+        return S_OK;
+    }
+
+    if (!gl_info->supported[ARB_TIMER_QUERY])
+    {
+        WARN("%p timestamp queries not supported. Returning 0.\n", query);
+        if (u64data)
+            *u64data = 0;
+        return S_OK;
+    }
+
+    if (tq->context->tid != GetCurrentThreadId())
+    {
+        FIXME("%p Wrong thread, returning 1.\n", query);
+        if (u64data)
+            *u64data = 1;
+        return S_OK;
+    }
+
+    context = context_acquire(query->device, tq->context->current_rt);
+
+    GL_EXTCALL(glGetQueryObjectuivARB(tq->id, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
+    checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)");
+    TRACE("available %#x.\n", available);
+
+    if (available)
+    {
+        if (u64data)
+        {
+            GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT_ARB, &timestamp));
+            checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
+            TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
+            *u64data = timestamp;
+        }
+        res = S_OK;
+    }
+    else
+    {
+        res = S_FALSE;
+    }
+
+    context_release(context);
+
+    return res;
+}
+
+static HRESULT wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
+{
+    struct wined3d_device *device = query->device;
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+
+    TRACE("query %p, flags %#x.\n", query, flags);
+
+    if (gl_info->supported[ARB_TIMER_QUERY])
+    {
+        struct wined3d_timestamp_query *tq = query->extendedData;
+        struct wined3d_context *context;
+
+        if (flags & WINED3DISSUE_BEGIN)
+        {
+            WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
+        }
+        if (flags & WINED3DISSUE_END)
+        {
+            if (tq->context)
+                context_free_timestamp_query(tq);
+            context = context_acquire(query->device, NULL);
+            context_alloc_timestamp_query(context, tq);
+            GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP));
+            checkGLcall("glQueryCounter()");
+            context_release(context);
+        }
+    }
+    else
+    {
+        FIXME("%p timestamp queries not supported.\n", query);
+    }
+
+    if (flags & WINED3DISSUE_END)
+        query->state = QUERY_SIGNALLED;
+
+    return WINED3D_OK;
+}
+
+static HRESULT wined3d_timestamp_disjoint_query_ops_get_data(struct wined3d_query *query,
+        void *data, DWORD size, DWORD flags)
+{
+    TRACE("(%p) : type D3DQUERY_TIMESTAMP_DISJOINT, data %p, size %#x, flags %#x.\n", query, data, size, flags);
+
+    if (query->type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
+    {
+        struct wined3d_query_data_timestamp_disjoint *disjoint_data = data;
+
+        if (query->state == QUERY_BUILDING)
+        {
+            TRACE("Query is building, returning S_FALSE.\n");
+            return S_FALSE;
+        }
+
+        if (disjoint_data)
+        {
+            disjoint_data->disjoint = FALSE;
+            disjoint_data->frequency = 1000 * 1000 * 1000;
+        }
+    }
+    else
+    {
+        UINT64 *u64data = data;
+
+        if (u64data)
+            *u64data = 1000 * 1000 * 1000;
+    }
+    return S_OK;
+}
+
+static HRESULT wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
+{
+    TRACE("query %p, flags %#x.\n", query, flags);
+
+    if (flags & WINED3DISSUE_BEGIN)
+        query->state = QUERY_BUILDING;
+    if (flags & WINED3DISSUE_END)
+        query->state = QUERY_SIGNALLED;
+
+    return WINED3D_OK;
+}
+
 static const struct wined3d_query_ops event_query_ops =
 {
     wined3d_event_query_ops_get_data,
@@ -531,6 +689,18 @@ static const struct wined3d_query_ops occlusion_query_ops =
     wined3d_occlusion_query_ops_issue,
 };
 
+static const struct wined3d_query_ops timestamp_query_ops =
+{
+    wined3d_timestamp_query_ops_get_data,
+    wined3d_timestamp_query_ops_issue,
+};
+
+static const struct wined3d_query_ops timestamp_disjoint_query_ops =
+{
+    wined3d_timestamp_disjoint_query_ops_get_data,
+    wined3d_timestamp_disjoint_query_ops_issue,
+};
+
 static HRESULT query_init(struct wined3d_query *query, struct wined3d_device *device, enum wined3d_query_type type)
 {
     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
@@ -575,12 +745,41 @@ static HRESULT query_init(struct wined3d_query *query, struct wined3d_device *de
             }
             break;
 
-        case WINED3D_QUERY_TYPE_VCACHE:
-        case WINED3D_QUERY_TYPE_RESOURCE_MANAGER:
-        case WINED3D_QUERY_TYPE_VERTEX_STATS:
         case WINED3D_QUERY_TYPE_TIMESTAMP:
+            TRACE("Timestamp query.\n");
+            if (!gl_info->supported[ARB_TIMER_QUERY])
+            {
+                WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
+                return WINED3DERR_NOTAVAILABLE;
+            }
+            query->query_ops = &timestamp_query_ops;
+            query->data_size = sizeof(UINT64);
+            query->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_timestamp_query));
+            if (!query->extendedData)
+            {
+                ERR("Failed to allocate timestamp query extended data.\n");
+                return E_OUTOFMEMORY;
+            }
+            ((struct wined3d_timestamp_query *)query->extendedData)->context = NULL;
+            break;
+
         case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
         case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
+            TRACE("TIMESTAMP_DISJOINT query.\n");
+            if (!gl_info->supported[ARB_TIMER_QUERY])
+            {
+                WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
+                return WINED3DERR_NOTAVAILABLE;
+            }
+            query->query_ops = &timestamp_disjoint_query_ops;
+            query->data_size = type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
+                    ? sizeof(struct wined3d_query_data_timestamp_disjoint) : sizeof(UINT64);
+            query->extendedData = NULL;
+            break;
+
+        case WINED3D_QUERY_TYPE_VCACHE:
+        case WINED3D_QUERY_TYPE_RESOURCE_MANAGER:
+        case WINED3D_QUERY_TYPE_VERTEX_STATS:
         case WINED3D_QUERY_TYPE_PIPELINE_TIMINGS:
         case WINED3D_QUERY_TYPE_INTERFACE_TIMINGS:
         case WINED3D_QUERY_TYPE_VERTEX_TIMINGS:
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index dd49f43..4e5d315 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1045,6 +1045,16 @@ enum wined3d_event_query_result wined3d_event_query_finish(const struct wined3d_
 void wined3d_event_query_issue(struct wined3d_event_query *query, const struct wined3d_device *device) DECLSPEC_HIDDEN;
 BOOL wined3d_event_query_supported(const struct wined3d_gl_info *gl_info) DECLSPEC_HIDDEN;
 
+struct wined3d_timestamp_query
+{
+    struct list entry;
+    GLuint id;
+    struct wined3d_context *context;
+};
+
+void context_alloc_timestamp_query(struct wined3d_context *context, struct wined3d_timestamp_query *query) DECLSPEC_HIDDEN;
+void context_free_timestamp_query(struct wined3d_timestamp_query *query) DECLSPEC_HIDDEN;
+
 struct wined3d_context
 {
     const struct wined3d_gl_info *gl_info;
@@ -1137,6 +1147,11 @@ struct wined3d_context
     UINT free_event_query_count;
     struct list event_queries;
 
+    GLuint *free_timestamp_queries;
+    UINT free_timestamp_query_size;
+    UINT free_timestamp_query_count;
+    struct list timestamp_queries;
+
     struct wined3d_stream_info stream_info;
 
     /* Fences for GL_APPLE_flush_buffer_range */
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index c958872..a4b32f9 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -710,6 +710,12 @@ enum wined3d_query_type
     WINED3D_QUERY_TYPE_CACHE_UTILIZATION    = 18
 };
 
+struct wined3d_query_data_timestamp_disjoint
+{
+    UINT64 frequency;
+    BOOL disjoint;
+};
+
 #define WINED3DISSUE_BEGIN                                      (1 << 1)
 #define WINED3DISSUE_END                                        (1 << 0)
 #define WINED3DGETDATA_FLUSH                                    (1 << 0)
-- 
1.8.3.2




More information about the wine-patches mailing list