From: Matteo Bruni Subject: [PATCH 3/5] wined3d: Add support for timestamp queries. (try 3) Message-Id: <1397664890-8193-3-git-send-email-mbruni@codeweavers.com> Date: Wed, 16 Apr 2014 18:14:48 +0200 --- Try 3: hopefully fixed the issues found by Henri. dlls/d3d9/query.c | 21 ++++- dlls/wined3d/context.c | 67 ++++++++++++++ dlls/wined3d/query.c | 197 ++++++++++++++++++++++++++++++++++++++++- dlls/wined3d/wined3d_private.h | 15 ++++ include/wine/wined3d.h | 6 ++ 5 files changed, 301 insertions(+), 5 deletions(-) diff --git a/dlls/d3d9/query.c b/dlls/d3d9/query.c index d363413..bb78d7f 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); + enum wined3d_query_type 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 == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT) + 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); + enum wined3d_query_type 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 == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT && data) + { + 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..bd707eb 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -614,6 +614,53 @@ 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 + { + GL_EXTCALL(glGenQueriesARB(1, &query->id)); + checkGLcall("glGenQueriesARB"); + + TRACE("Allocated timestamp query %u in context %p.\n", query->id, context); + } + + 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, @@ -914,6 +961,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_timestamp_query *timestamp_query; struct wined3d_occlusion_query *occlusion_query; struct wined3d_event_query *event_query; struct fbo_entry *entry, *entry2; @@ -929,6 +977,13 @@ static void context_destroy_gl_resources(struct wined3d_context *context) else if (context->valid) context_set_gl_context(context); + LIST_FOR_EACH_ENTRY(timestamp_query, &context->timestamp_queries, struct wined3d_timestamp_query, entry) + { + if (context->valid) + GL_EXTCALL(glDeleteQueriesARB(1, ×tamp_query->id)); + timestamp_query->context = NULL; + } + LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry) { if (context->valid && gl_info->supported[ARB_OCCLUSION_QUERY]) @@ -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..ef1ab17 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,148 @@ 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 (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, ×tamp)); + 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 + { + ERR("Timestamp queries not supported.\n"); + } + + 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 +681,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 +737,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 = ×tamp_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 = ×tamp_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