wined3d: Use query buffer objects for occlusion queries.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45723 Signed-off-by: Andrew Wesie <awesie@gmail.com> Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
dc0ec5502d
commit
580ea44bc6
|
@ -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 },
|
||||
|
@ -2061,6 +2063,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)
|
||||
|
@ -3301,7 +3305,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)},
|
||||
|
|
|
@ -1986,6 +1986,9 @@ static void wined3d_cs_exec_query_issue(struct wined3d_cs *cs, const void *data)
|
|||
|
||||
if (poll && list_empty(&query->poll_list_entry))
|
||||
{
|
||||
if (query->buffer_object)
|
||||
InterlockedIncrement(&query->counter_retrieved);
|
||||
else
|
||||
list_add_tail(&cs->query_poll_list, &query->poll_list_entry);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,88 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
|
||||
|
||||
static void wined3d_query_buffer_invalidate(struct wined3d_query *query)
|
||||
{
|
||||
/* map[0] != map[1]: exact values do not have any significance. */
|
||||
query->map_ptr[0] = 0;
|
||||
query->map_ptr[1] = ~(UINT64)0;
|
||||
}
|
||||
|
||||
static BOOL wined3d_query_buffer_is_valid(struct wined3d_query *query)
|
||||
{
|
||||
return query->map_ptr[0] == query->map_ptr[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;
|
||||
|
||||
GL_EXTCALL(glGenBuffers(1, &buffer_object));
|
||||
GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, buffer_object));
|
||||
GL_EXTCALL(glBufferStorage(GL_QUERY_BUFFER, sizeof(query->map_ptr[0]) * 2, NULL, map_flags));
|
||||
query->map_ptr = GL_EXTCALL(glMapBufferRange(GL_QUERY_BUFFER, 0, sizeof(query->map_ptr[0]) * 2, map_flags));
|
||||
GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
|
||||
checkGLcall("query buffer object creation");
|
||||
|
||||
wined3d_query_buffer_invalidate(query);
|
||||
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("query buffer object destruction");
|
||||
|
||||
query->buffer_object = 0;
|
||||
query->map_ptr = NULL;
|
||||
}
|
||||
|
||||
/* From ARB_occlusion_query: "Querying the state for a given occlusion query
|
||||
* forces that occlusion query to complete within a finite amount of time."
|
||||
* In practice, that means drivers flush when retrieving
|
||||
* GL_QUERY_RESULT_AVAILABLE, which can be undesirable when applications use a
|
||||
* significant number of queries. Using a persistently mapped query buffer
|
||||
* object allows us to avoid these implicit flushes. An additional benefit is
|
||||
* that it allows us to poll the query status from the application-thread
|
||||
* instead of from the csmt-thread. */
|
||||
static BOOL wined3d_query_buffer_queue_result(struct wined3d_context *context, struct wined3d_query *query, GLuint id)
|
||||
{
|
||||
const struct wined3d_gl_info *gl_info = context->gl_info;
|
||||
|
||||
if (!gl_info->supported[ARB_QUERY_BUFFER_OBJECT] || !gl_info->supported[ARB_BUFFER_STORAGE])
|
||||
return FALSE;
|
||||
/* Don't use query buffers without CSMT, mainly for simplicity. */
|
||||
if (!context->device->cs->thread)
|
||||
return FALSE;
|
||||
|
||||
if (query->buffer_object)
|
||||
{
|
||||
/* If there's still a query result in-flight for the existing buffer
|
||||
* object (i.e., the query was restarted before we received its
|
||||
* result), we can't reuse the existing buffer object. */
|
||||
if (wined3d_query_buffer_is_valid(query))
|
||||
wined3d_query_buffer_invalidate(query);
|
||||
else
|
||||
wined3d_query_destroy_buffer_object(context, query);
|
||||
}
|
||||
|
||||
if (!query->buffer_object)
|
||||
wined3d_query_create_buffer_object(context, query);
|
||||
|
||||
GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, query->buffer_object));
|
||||
/* Read the same value twice. We know we have the result if map_ptr[0] == map_ptr[1]. */
|
||||
GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)0));
|
||||
GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)sizeof(query->map_ptr[0])));
|
||||
GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
|
||||
checkGLcall("queue query result");
|
||||
|
||||
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 +421,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,17 +472,22 @@ HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
|
|||
return WINED3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
if (!query->device->cs->thread)
|
||||
if (query->device->cs->thread)
|
||||
{
|
||||
if (!query->query_ops->query_poll(query, flags))
|
||||
return S_FALSE;
|
||||
}
|
||||
else if (query->counter_main != query->counter_retrieved)
|
||||
if (query->counter_main != query->counter_retrieved
|
||||
|| (query->buffer_object && !wined3d_query_buffer_is_valid(query)))
|
||||
{
|
||||
if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed)
|
||||
wined3d_cs_emit_flush(query->device->cs);
|
||||
return S_FALSE;
|
||||
}
|
||||
if (query->buffer_object)
|
||||
query->data = query->map_ptr;
|
||||
}
|
||||
else if (!query->query_ops->query_poll(query, flags))
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (data)
|
||||
memcpy(data, query->data, min(data_size, query->data_size));
|
||||
|
@ -579,6 +674,7 @@ static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD
|
|||
gl_info = context->gl_info;
|
||||
GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
|
||||
checkGLcall("glEndQuery()");
|
||||
wined3d_query_buffer_queue_result(context, query, oq->id);
|
||||
|
||||
context_release(context);
|
||||
poll = TRUE;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1730,6 +1730,9 @@ struct wined3d_query
|
|||
|
||||
LONG counter_main, counter_retrieved;
|
||||
struct list poll_list_entry;
|
||||
|
||||
GLuint buffer_object;
|
||||
UINT64 *map_ptr;
|
||||
};
|
||||
|
||||
struct wined3d_event_query
|
||||
|
|
Loading…
Reference in New Issue