[PATCH] wined3d: Use query buffer objects for occlusion queries.

Andrew Wesie awesie at gmail.com
Sun Sep 2 19:10:03 CDT 2018


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45723
Signed-off-by: Andrew Wesie <awesie at gmail.com>
---
 dlls/wined3d/adapter_gl.c      |   6 ++
 dlls/wined3d/query.c           | 159 ++++++++++++++++++++++++++++++++++++-----
 dlls/wined3d/wined3d_gl.h      |   2 +
 dlls/wined3d/wined3d_private.h |   3 +
 4 files changed, 151 insertions(+), 19 deletions(-)

diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c
index af17df8..0ac72ba 100644
--- a/dlls/wined3d/adapter_gl.c
+++ b/dlls/wined3d/adapter_gl.c
@@ -58,6 +58,7 @@ static const struct wined3d_extension_map gl_extension_map[] =
     /* ARB */
     {"GL_ARB_base_instance",                ARB_BASE_INSTANCE             },
     {"GL_ARB_blend_func_extended",          ARB_BLEND_FUNC_EXTENDED       },
+    {"GL_ARB_buffer_storage",               ARB_BUFFER_STORAGE            },
     {"GL_ARB_clear_buffer_object",          ARB_CLEAR_BUFFER_OBJECT       },
     {"GL_ARB_clear_texture",                ARB_CLEAR_TEXTURE             },
     {"GL_ARB_clip_control",                 ARB_CLIP_CONTROL              },
@@ -103,6 +104,7 @@ static const struct wined3d_extension_map gl_extension_map[] =
     {"GL_ARB_point_parameters",             ARB_POINT_PARAMETERS          },
     {"GL_ARB_point_sprite",                 ARB_POINT_SPRITE              },
     {"GL_ARB_provoking_vertex",             ARB_PROVOKING_VERTEX          },
+    {"GL_ARB_query_buffer_object",          ARB_QUERY_BUFFER_OBJECT       },
     {"GL_ARB_sample_shading",               ARB_SAMPLE_SHADING            },
     {"GL_ARB_sampler_objects",              ARB_SAMPLER_OBJECTS           },
     {"GL_ARB_seamless_cube_map",            ARB_SEAMLESS_CUBE_MAP         },
@@ -2063,6 +2065,8 @@ static void load_gl_funcs(struct wined3d_gl_info *gl_info)
     /* GL_ARB_blend_func_extended */
     USE_GL_FUNC(glBindFragDataLocationIndexed)
     USE_GL_FUNC(glGetFragDataIndex)
+    /* GL_ARB_buffer_storage */
+    USE_GL_FUNC(glBufferStorage)
     /* GL_ARB_clear_buffer_object */
     USE_GL_FUNC(glClearBufferData)
     USE_GL_FUNC(glClearBufferSubData)
@@ -3304,7 +3308,9 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter,
         {ARB_TEXTURE_STORAGE_MULTISAMPLE,  MAKEDWORD_VERSION(4, 2)},
         {ARB_TEXTURE_VIEW,                 MAKEDWORD_VERSION(4, 3)},
 
+        {ARB_BUFFER_STORAGE,               MAKEDWORD_VERSION(4, 4)},
         {ARB_CLEAR_TEXTURE,                MAKEDWORD_VERSION(4, 4)},
+        {ARB_QUERY_BUFFER_OBJECT,          MAKEDWORD_VERSION(4, 4)},
 
         {ARB_CLIP_CONTROL,                 MAKEDWORD_VERSION(4, 5)},
         {ARB_CULL_DISTANCE,                MAKEDWORD_VERSION(4, 5)},
diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c
index 01e6bcb..d364216 100644
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -25,6 +25,108 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
 
+#define INVALID_QUERY_RESULT ((UINT64)-1)
+
+static void wined3d_query_create_buffer_object(struct wined3d_context *context, struct wined3d_query *query)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+    const GLuint map_flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
+    GLuint buffer_object;
+
+    if (!gl_info->supported[ARB_BUFFER_STORAGE])
+        return;
+
+    GL_EXTCALL(glGenBuffers(1, &buffer_object));
+    checkGLcall("glGenBuffers");
+
+    GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, buffer_object));
+    checkGLcall("glBindBuffer");
+
+    GL_EXTCALL(glBufferStorage(GL_QUERY_BUFFER, 16, NULL, map_flags));
+    checkGLcall("glBufferStorage");
+
+    query->map_ptr = GL_EXTCALL(glMapBufferRange(GL_QUERY_BUFFER, 0, 16, map_flags));
+    checkGLcall("glMapBufferRange");
+
+    GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
+
+    *query->map_ptr = INVALID_QUERY_RESULT;
+    query->buffer_object = buffer_object;
+}
+
+static void wined3d_query_destroy_buffer_object(struct wined3d_context *context, struct wined3d_query *query)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+
+    GL_EXTCALL(glDeleteBuffers(1, &query->buffer_object));
+    checkGLcall("glDeleteBuffers");
+
+    query->buffer_object = 0;
+    query->map_ptr = NULL;
+}
+
+static void wined3d_query_buffer_begin(struct wined3d_query *query)
+{
+    if (query->buffer_object)
+        *query->map_ptr = INVALID_QUERY_RESULT;
+}
+
+static void wined3d_query_buffer_begin_cs(struct wined3d_context *context, struct wined3d_query *query)
+{
+    if (!context->gl_info->supported[ARB_QUERY_BUFFER_OBJECT])
+        return;
+
+    if (!query->buffer_object)
+        wined3d_query_create_buffer_object(context, query);
+}
+
+static BOOL wined3d_query_buffer_end_cs(struct wined3d_context *context, struct wined3d_query *query, GLuint id)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+
+    if (!query->buffer_object)
+        return FALSE;
+
+    GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, query->buffer_object));
+    checkGLcall("glBindBuffer");
+
+    GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, NULL));
+    checkGLcall("glGetQueryObjectui64v");
+
+    GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
+    return TRUE;
+}
+
+static BOOL wined3d_query_buffer_poll(struct wined3d_query *query, GLuint *available, UINT64 *result)
+{
+    if (!query->buffer_object)
+        return FALSE;
+
+    if (query->map_ptr && *query->map_ptr != INVALID_QUERY_RESULT)
+    {
+        if (available)
+            *available = GL_TRUE;
+        if (result)
+            *result = *query->map_ptr;
+    }
+    else
+    {
+        if (available)
+            *available = GL_FALSE;
+    }
+    return TRUE;
+}
+
+static BOOL wined3d_query_buffer_get_data(struct wined3d_query *query, DWORD flags)
+{
+    if (!query->buffer_object)
+        return FALSE;
+
+    if (flags & WINED3DGETDATA_FLUSH && query->device->cs->thread && !query->device->cs->queries_flushed)
+        wined3d_cs_emit_flush(query->device->cs);
+    return TRUE;
+}
+
 static UINT64 get_query_result64(GLuint id, const struct wined3d_gl_info *gl_info)
 {
     if (gl_info->supported[ARB_TIMER_QUERY])
@@ -339,6 +441,14 @@ static void wined3d_query_destroy_object(void *object)
     if (!list_empty(&query->poll_list_entry))
         list_remove(&query->poll_list_entry);
 
+    if (query->buffer_object)
+    {
+        struct wined3d_context *context;
+        context = context_acquire(query->device, NULL, 0);
+        wined3d_query_destroy_buffer_object(context, query);
+        context_release(context);
+    }
+
     /* Queries are specific to the GL context that created them. Not
      * deleting the query will obviously leak it, but that's still better
      * than potentially deleting a different query with the same id in this
@@ -382,7 +492,7 @@ HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
         return WINED3DERR_INVALIDCALL;
     }
 
-    if (!query->device->cs->thread)
+    if (!query->device->cs->thread || wined3d_query_buffer_get_data(query, flags))
     {
         if (!query->query_ops->query_poll(query, flags))
             return S_FALSE;
@@ -411,6 +521,9 @@ HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, DWORD flags)
 {
     TRACE("query %p, flags %#x.\n", query, flags);
 
+    if (flags & WINED3DISSUE_BEGIN)
+        wined3d_query_buffer_begin(query);
+
     if (flags & WINED3DISSUE_END)
         ++query->counter_main;
 
@@ -428,31 +541,35 @@ static BOOL wined3d_occlusion_query_ops_poll(struct wined3d_query *query, DWORD
 {
     struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
     struct wined3d_device *device = query->device;
-    const struct wined3d_gl_info *gl_info;
-    struct wined3d_context *context;
-    GLuint available;
+    GLuint available = FALSE;
 
     TRACE("query %p, flags %#x.\n", query, flags);
 
-    if (!(context = context_reacquire(device, oq->context)))
+    if (!wined3d_query_buffer_poll(query, &available, &oq->samples))
     {
-        FIXME("%p Wrong thread, returning 1.\n", query);
-        oq->samples = 1;
-        return TRUE;
-    }
-    gl_info = context->gl_info;
+        const struct wined3d_gl_info *gl_info;
+        struct wined3d_context *context;
 
-    GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
-    TRACE("Available %#x.\n", available);
+        if (!(context = context_reacquire(device, oq->context)))
+        {
+            FIXME("%p Wrong thread, returning 1.\n", query);
+            oq->samples = 1;
+            return TRUE;
+        }
+        gl_info = context->gl_info;
 
-    if (available)
-    {
-        oq->samples = get_query_result64(oq->id, gl_info);
-        TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples));
+        GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
+        TRACE("Available %#x.\n", available);
+
+        if (available)
+            oq->samples = get_query_result64(oq->id, gl_info);
+
+        checkGLcall("poll occlusion query");
+        context_release(context);
     }
 
-    checkGLcall("poll occlusion query");
-    context_release(context);
+    if (available)
+        TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples));
 
     return available;
 }
@@ -564,6 +681,8 @@ static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD
         GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
         checkGLcall("glBeginQuery()");
 
+        wined3d_query_buffer_begin_cs(context, query);
+
         context_release(context);
         oq->started = TRUE;
     }
@@ -580,8 +699,10 @@ static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD
                 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
                 checkGLcall("glEndQuery()");
 
+                /* If we cannot use query buffers, poll instead. */
+                poll = !wined3d_query_buffer_end_cs(context, query, oq->id);
+
                 context_release(context);
-                poll = TRUE;
             }
             else
             {
diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h
index 525c298..0bc9309 100644
--- a/dlls/wined3d/wined3d_gl.h
+++ b/dlls/wined3d/wined3d_gl.h
@@ -44,6 +44,7 @@ enum wined3d_gl_extension
     /* ARB */
     ARB_BASE_INSTANCE,
     ARB_BLEND_FUNC_EXTENDED,
+    ARB_BUFFER_STORAGE,
     ARB_CLEAR_BUFFER_OBJECT,
     ARB_CLEAR_TEXTURE,
     ARB_CLIP_CONTROL,
@@ -89,6 +90,7 @@ enum wined3d_gl_extension
     ARB_POINT_PARAMETERS,
     ARB_POINT_SPRITE,
     ARB_PROVOKING_VERTEX,
+    ARB_QUERY_BUFFER_OBJECT,
     ARB_SAMPLE_SHADING,
     ARB_SAMPLER_OBJECTS,
     ARB_SEAMLESS_CUBE_MAP,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 7084168..db7c772 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1741,6 +1741,9 @@ struct wined3d_query
 
     LONG counter_main, counter_retrieved;
     struct list poll_list_entry;
+
+    GLuint buffer_object;
+    UINT64 *map_ptr;
 };
 
 struct wined3d_event_query
-- 
2.7.4




More information about the wine-devel mailing list