From: Andrew Wesie Subject: [PATCH] wined3d: Use query buffer objects for occlusion queries. Message-Id: <1535933403-23092-1-git-send-email-awesie@gmail.com> Date: Sun, 2 Sep 2018 19:10:03 -0500 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45723 Signed-off-by: Andrew Wesie --- 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