[PATCH 3/5] wined3d: Implement SO statistics queries.

Józef Kucia jkucia at codeweavers.com
Wed May 24 10:09:59 CDT 2017


Signed-off-by: Józef Kucia <jkucia at codeweavers.com>
---
 dlls/wined3d/context.c         |  64 ++++++++++++-
 dlls/wined3d/directx.c         |  16 ++++
 dlls/wined3d/query.c           | 200 +++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/wined3d_gl.h      |   3 +-
 dlls/wined3d/wined3d_private.h |  31 +++++++
 include/wine/wined3d.h         |  49 ++++++----
 6 files changed, 343 insertions(+), 20 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 6d09c22..e214e84 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -892,6 +892,47 @@ void context_free_timestamp_query(struct wined3d_timestamp_query *query)
     context->free_timestamp_queries[context->free_timestamp_query_count++] = query->id;
 }
 
+void context_alloc_so_statistics_query(struct wined3d_context *context,
+        struct wined3d_so_statistics_query *query)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+
+    if (context->free_so_statistics_query_count)
+    {
+        query->u = context->free_so_statistics_queries[--context->free_so_statistics_query_count];
+    }
+    else
+    {
+        GL_EXTCALL(glGenQueries(ARRAY_SIZE(query->u.id), query->u.id));
+        checkGLcall("glGenQueries");
+
+        TRACE("Allocated SO statistics queries %u, %u in context %p.\n",
+                query->u.id[0], query->u.id[1], context);
+    }
+
+    query->context = context;
+    list_add_head(&context->so_statistics_queries, &query->entry);
+}
+
+void context_free_so_statistics_query(struct wined3d_so_statistics_query *query)
+{
+    struct wined3d_context *context = query->context;
+
+    list_remove(&query->entry);
+    query->context = NULL;
+
+    if (!wined3d_array_reserve((void **)&context->free_so_statistics_queries,
+            &context->free_so_statistics_query_size, context->free_so_statistics_query_count + 1,
+            sizeof(*context->free_so_statistics_queries)))
+    {
+        ERR("Failed to grow free list, leaking GL queries %u, %u in context %p.\n",
+                query->u.id[0], query->u.id[1], context);
+        return;
+    }
+
+    context->free_so_statistics_queries[context->free_so_statistics_query_count++] = query->u;
+}
+
 typedef void (context_fbo_entry_func_t)(struct wined3d_context *context, struct fbo_entry *entry);
 
 static void context_enum_fbo_entries(const struct wined3d_device *device,
@@ -1183,6 +1224,7 @@ static void context_update_window(struct wined3d_context *context)
 static void context_destroy_gl_resources(struct wined3d_context *context)
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
+    struct wined3d_so_statistics_query *so_statistics_query;
     struct wined3d_timestamp_query *timestamp_query;
     struct wined3d_occlusion_query *occlusion_query;
     struct wined3d_event_query *event_query;
@@ -1199,6 +1241,14 @@ static void context_destroy_gl_resources(struct wined3d_context *context)
     else if (context->valid)
         context_set_gl_context(context);
 
+    LIST_FOR_EACH_ENTRY(so_statistics_query, &context->so_statistics_queries,
+            struct wined3d_so_statistics_query, entry)
+    {
+        if (context->valid)
+            GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(so_statistics_query->u.id), so_statistics_query->u.id));
+        so_statistics_query->context = NULL;
+    }
+
     LIST_FOR_EACH_ENTRY(timestamp_query, &context->timestamp_queries, struct wined3d_timestamp_query, entry)
     {
         if (context->valid)
@@ -1246,6 +1296,15 @@ static void context_destroy_gl_resources(struct wined3d_context *context)
             GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
         }
 
+        if (gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
+        {
+            for (i = 0; i < context->free_so_statistics_query_count; ++i)
+            {
+                union wined3d_gl_so_statistics_query *q = &context->free_so_statistics_queries[i];
+                GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(q->id), q->id));
+            }
+        }
+
         if (gl_info->supported[ARB_TIMER_QUERY])
             GL_EXTCALL(glDeleteQueries(context->free_timestamp_query_count, context->free_timestamp_queries));
 
@@ -1731,15 +1790,16 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
     if (!(ret->free_occlusion_queries = wined3d_calloc(ret->free_occlusion_query_size,
             sizeof(*ret->free_occlusion_queries))))
         goto out;
-
     list_init(&ret->occlusion_queries);
 
     ret->free_event_query_size = 4;
     if (!(ret->free_event_queries = wined3d_calloc(ret->free_event_query_size,
             sizeof(*ret->free_event_queries))))
         goto out;
-
     list_init(&ret->event_queries);
+
+    list_init(&ret->so_statistics_queries);
+
     list_init(&ret->fbo_list);
     list_init(&ret->fbo_destroy_list);
 
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 4115453..c118357 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -4140,6 +4140,22 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter,
         if (!counter_bits)
             gl_info->supported[ARB_TIMER_QUERY] = FALSE;
     }
+    if (gl_version >= MAKEDWORD_VERSION(3, 0))
+    {
+        GLint counter_bits;
+
+        gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY] = TRUE;
+
+        GL_EXTCALL(glGetQueryiv(GL_PRIMITIVES_GENERATED, GL_QUERY_COUNTER_BITS, &counter_bits));
+        TRACE("Primitives query counter has %d bits.\n", counter_bits);
+        if (!counter_bits)
+            gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY] = FALSE;
+
+        GL_EXTCALL(glGetQueryiv(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_QUERY_COUNTER_BITS, &counter_bits));
+        TRACE("Transform feedback primitives query counter has %d bits.\n", counter_bits);
+        if (!counter_bits)
+            gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY] = FALSE;
+    }
     if (gl_info->supported[ARB_VIEWPORT_ARRAY])
     {
         GLint subpixel_bits;
diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c
index 3cfbd84..28db6be 100644
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -56,6 +56,11 @@ static struct wined3d_timestamp_query *wined3d_timestamp_query_from_query(struct
     return CONTAINING_RECORD(query, struct wined3d_timestamp_query, query);
 }
 
+static struct wined3d_so_statistics_query *wined3d_so_statistics_query_from_query(struct wined3d_query *query)
+{
+    return CONTAINING_RECORD(query, struct wined3d_so_statistics_query, query);
+}
+
 BOOL wined3d_event_query_supported(const struct wined3d_gl_info *gl_info)
 {
     return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
@@ -294,6 +299,16 @@ static void wined3d_query_destroy_object(void *object)
     {
         HeapFree(GetProcessHeap(), 0, query);
     }
+    else if (query->type == WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
+            || query->type ==  WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
+            || query->type ==  WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
+            || query->type ==  WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
+    {
+        struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
+        if (pq->context)
+            context_free_so_statistics_query(pq);
+        HeapFree(GetProcessHeap(), 0, pq);
+    }
     else
     {
         ERR("Query %p has invalid type %#x.\n", query, query->type);
@@ -637,6 +652,127 @@ static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *que
     return FALSE;
 }
 
+static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags)
+{
+    struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
+    struct wined3d_device *device = query->device;
+    GLuint written_available, generated_available;
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_context *context;
+
+    TRACE("query %p, flags %#x.\n", query, flags);
+
+    if (!(context = context_reacquire(device, pq->context)))
+    {
+        FIXME("%p Wrong thread, returning 0 primitives.\n", query);
+        memset(&pq->statistics, 0, sizeof(pq->statistics));
+        return TRUE;
+    }
+    gl_info = context->gl_info;
+
+    GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written,
+            GL_QUERY_RESULT_AVAILABLE, &written_available));
+    GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated,
+            GL_QUERY_RESULT_AVAILABLE, &generated_available));
+    TRACE("Available %#x, %#x.\n", written_available, generated_available);
+
+    if (written_available && generated_available)
+    {
+        if (gl_info->supported[ARB_TIMER_QUERY])
+        {
+            GLuint64 result;
+            GL_EXTCALL(glGetQueryObjectui64v(pq->u.query.written, GL_QUERY_RESULT, &result));
+            pq->statistics.primitives_written = result;
+            GL_EXTCALL(glGetQueryObjectui64v(pq->u.query.generated, GL_QUERY_RESULT, &result));
+            pq->statistics.primitives_generated = result;
+        }
+        else
+        {
+            GLuint result;
+            GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written, GL_QUERY_RESULT, &result));
+            pq->statistics.primitives_written = result;
+            GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated, GL_QUERY_RESULT, &result));
+            pq->statistics.primitives_generated = result;
+        }
+        TRACE("Returning %s, %s primitives.\n",
+                wine_dbgstr_longlong(pq->statistics.primitives_written),
+                wine_dbgstr_longlong(pq->statistics.primitives_generated));
+    }
+
+    checkGLcall("poll SO statistics query");
+    context_release(context);
+
+    return written_available && generated_available;
+}
+
+static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags)
+{
+    struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
+    struct wined3d_device *device = query->device;
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+    struct wined3d_context *context;
+    BOOL poll = FALSE;
+
+    TRACE("query %p, flags %#x.\n", query, flags);
+
+    if (flags & WINED3DISSUE_BEGIN)
+    {
+        if (pq->started)
+        {
+            if ((context = context_reacquire(device, pq->context)))
+            {
+                GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, pq->stream_idx));
+                GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, pq->stream_idx));
+            }
+            else
+            {
+                FIXME("Wrong thread, can't restart query.\n");
+                context_free_so_statistics_query(pq);
+                context = context_acquire(device, NULL, 0);
+                context_alloc_so_statistics_query(context, pq);
+            }
+        }
+        else
+        {
+            if (pq->context)
+                context_free_so_statistics_query(pq);
+            context = context_acquire(device, NULL, 0);
+            context_alloc_so_statistics_query(context, pq);
+        }
+
+        GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
+                pq->stream_idx, pq->u.query.written));
+        GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED,
+                pq->stream_idx, pq->u.query.generated));
+        checkGLcall("begin query");
+
+        context_release(context);
+        pq->started = TRUE;
+    }
+    if (flags & WINED3DISSUE_END)
+    {
+        if (pq->started)
+        {
+            if ((context = context_reacquire(device, pq->context)))
+            {
+                GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, pq->stream_idx));
+                GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, pq->stream_idx));
+                checkGLcall("end query");
+
+                context_release(context);
+                poll = TRUE;
+            }
+            else
+            {
+                FIXME("Wrong thread, can't end query.\n");
+            }
+        }
+        pq->started = FALSE;
+    }
+
+    return poll;
+}
+
 static const struct wined3d_query_ops event_query_ops =
 {
     wined3d_event_query_ops_poll,
@@ -785,6 +921,64 @@ static HRESULT wined3d_timestamp_disjoint_query_create(struct wined3d_device *de
     return WINED3D_OK;
 }
 
+static const struct wined3d_query_ops so_statistics_query_ops =
+{
+    wined3d_so_statistics_query_ops_poll,
+    wined3d_so_statistics_query_ops_issue,
+};
+
+static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device,
+        enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
+        struct wined3d_query **query)
+{
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+    struct wined3d_so_statistics_query *object;
+
+    TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
+            device, type, parent, parent_ops, query);
+
+    if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
+    {
+        WARN("OpenGL implementation does not support primitive queries.\n");
+        return WINED3DERR_NOTAVAILABLE;
+    }
+    if (!gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
+    {
+        WARN("OpenGL implementation does not support indexed queries.\n");
+        return WINED3DERR_NOTAVAILABLE;
+    }
+
+    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    switch (type)
+    {
+        case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
+            object->stream_idx = 0;
+            break;
+        case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
+            object->stream_idx = 1;
+            break;
+        case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
+            object->stream_idx = 2;
+            break;
+        case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
+            object->stream_idx = 3;
+            break;
+        default:
+            HeapFree(GetProcessHeap(), 0, object);
+            return WINED3DERR_NOTAVAILABLE;
+    }
+
+    wined3d_query_init(&object->query, device, type, &object->statistics,
+            sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops);
+
+    TRACE("Created query %p.\n", object);
+    *query = &object->query;
+
+    return WINED3D_OK;
+}
+
 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
         void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
 {
@@ -806,6 +1000,12 @@ HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_q
         case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
             return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query);
 
+        case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
+        case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
+        case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
+        case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
+            return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query);
+
         default:
             FIXME("Unhandled query type %#x.\n", type);
             return WINED3DERR_NOTAVAILABLE;
diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h
index 52fb5fd..ca7be85 100644
--- a/dlls/wined3d/wined3d_gl.h
+++ b/dlls/wined3d/wined3d_gl.h
@@ -200,8 +200,9 @@ enum wined3d_gl_extension
     WGL_WINE_QUERY_RENDERER,
     /* Internally used */
     WINED3D_GL_BLEND_EQUATION,
-    WINED3D_GL_NORMALIZED_TEXRECT,
     WINED3D_GL_LEGACY_CONTEXT,
+    WINED3D_GL_NORMALIZED_TEXRECT,
+    WINED3D_GL_PRIMITIVE_QUERY,
     WINED3D_GL_VERSION_2_0,
     WINED3D_GL_VERSION_3_2,
     WINED3D_GL_VERSION_4_3,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 321f4d5..4a1c64c 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1694,6 +1694,32 @@ struct wined3d_timestamp_query
 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;
 
+union wined3d_gl_so_statistics_query
+{
+    GLuint id[2];
+    struct
+    {
+        GLuint written;
+        GLuint generated;
+    } query;
+};
+
+struct wined3d_so_statistics_query
+{
+    struct wined3d_query query;
+
+    struct list entry;
+    union wined3d_gl_so_statistics_query u;
+    struct wined3d_context *context;
+    unsigned int stream_idx;
+    struct wined3d_query_data_so_statistics statistics;
+    BOOL started;
+};
+
+void context_alloc_so_statistics_query(struct wined3d_context *context,
+        struct wined3d_so_statistics_query *query) DECLSPEC_HIDDEN;
+void context_free_so_statistics_query(struct wined3d_so_statistics_query *query) DECLSPEC_HIDDEN;
+
 struct wined3d_gl_view
 {
     GLenum target;
@@ -1825,6 +1851,11 @@ struct wined3d_context
     unsigned int free_timestamp_query_count;
     struct list timestamp_queries;
 
+    union wined3d_gl_so_statistics_query *free_so_statistics_queries;
+    SIZE_T free_so_statistics_query_size;
+    unsigned int free_so_statistics_query_count;
+    struct list so_statistics_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 97947e4..8697fbf 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -685,23 +685,32 @@ enum wined3d_pool
 
 enum wined3d_query_type
 {
-    WINED3D_QUERY_TYPE_PIPELINE_STATISTICS  = 1,
-    WINED3D_QUERY_TYPE_SO_STATISTICS        = 2,
-    WINED3D_QUERY_TYPE_SO_OVERFLOW          = 3,
-    WINED3D_QUERY_TYPE_VCACHE               = 4,
-    WINED3D_QUERY_TYPE_RESOURCE_MANAGER     = 5,
-    WINED3D_QUERY_TYPE_VERTEX_STATS         = 6,
-    WINED3D_QUERY_TYPE_EVENT                = 8,
-    WINED3D_QUERY_TYPE_OCCLUSION            = 9,
-    WINED3D_QUERY_TYPE_TIMESTAMP            = 10,
-    WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT   = 11,
-    WINED3D_QUERY_TYPE_TIMESTAMP_FREQ       = 12,
-    WINED3D_QUERY_TYPE_PIPELINE_TIMINGS     = 13,
-    WINED3D_QUERY_TYPE_INTERFACE_TIMINGS    = 14,
-    WINED3D_QUERY_TYPE_VERTEX_TIMINGS       = 15,
-    WINED3D_QUERY_TYPE_PIXEL_TIMINGS        = 16,
-    WINED3D_QUERY_TYPE_BANDWIDTH_TIMINGS    = 17,
-    WINED3D_QUERY_TYPE_CACHE_UTILIZATION    = 18
+    WINED3D_QUERY_TYPE_VCACHE                = 4,
+    WINED3D_QUERY_TYPE_RESOURCE_MANAGER      = 5,
+    WINED3D_QUERY_TYPE_VERTEX_STATS          = 6,
+    WINED3D_QUERY_TYPE_EVENT                 = 8,
+    WINED3D_QUERY_TYPE_OCCLUSION             = 9,
+    WINED3D_QUERY_TYPE_TIMESTAMP             = 10,
+    WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT    = 11,
+    WINED3D_QUERY_TYPE_TIMESTAMP_FREQ        = 12,
+    WINED3D_QUERY_TYPE_PIPELINE_TIMINGS      = 13,
+    WINED3D_QUERY_TYPE_INTERFACE_TIMINGS     = 14,
+    WINED3D_QUERY_TYPE_VERTEX_TIMINGS        = 15,
+    WINED3D_QUERY_TYPE_PIXEL_TIMINGS         = 16,
+    WINED3D_QUERY_TYPE_BANDWIDTH_TIMINGS     = 17,
+    WINED3D_QUERY_TYPE_CACHE_UTILIZATION     = 18,
+    WINED3D_QUERY_TYPE_MEMORY_PRESSURE       = 19,
+    WINED3D_QUERY_TYPE_PIPELINE_STATISTICS   = 20,
+    WINED3D_QUERY_TYPE_SO_STATISTICS         = 21,
+    WINED3D_QUERY_TYPE_SO_OVERFLOW           = 22,
+    WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 = 23,
+    WINED3D_QUERY_TYPE_SO_OVERFLOW_STREAM0   = 24,
+    WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1 = 25,
+    WINED3D_QUERY_TYPE_SO_OVERFLOW_STREAM1   = 26,
+    WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2 = 27,
+    WINED3D_QUERY_TYPE_SO_OVERFLOW_STREAM2   = 28,
+    WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3 = 29,
+    WINED3D_QUERY_TYPE_SO_OVERFLOW_STREAM3   = 30,
 };
 
 struct wined3d_query_data_timestamp_disjoint
@@ -710,6 +719,12 @@ struct wined3d_query_data_timestamp_disjoint
     BOOL disjoint;
 };
 
+struct wined3d_query_data_so_statistics
+{
+    UINT64 primitives_written;
+    UINT64 primitives_generated;
+};
+
 #define WINED3DISSUE_BEGIN                                      (1u << 1)
 #define WINED3DISSUE_END                                        (1u << 0)
 #define WINED3DGETDATA_FLUSH                                    (1u << 0)
-- 
2.10.2




More information about the wine-patches mailing list