Commit fb77678e authored by Henri Verbeet's avatar Henri Verbeet Committed by Alexandre Julliard

wined3d: Manage event queries in the context.

parent 4ab7af65
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Context and render target management in wined3d * Context and render target management in wined3d
* *
* Copyright 2007-2008 Stefan Dösinger for CodeWeavers * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
* Copyright 2009 Henri Verbeet for CodeWeavers
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
...@@ -508,6 +509,72 @@ void context_free_occlusion_query(struct wined3d_occlusion_query *query) ...@@ -508,6 +509,72 @@ void context_free_occlusion_query(struct wined3d_occlusion_query *query)
context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id; context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
} }
/* Context activation is done by the caller. */
void context_alloc_event_query(struct WineD3DContext *context, struct wined3d_event_query *query)
{
const struct wined3d_gl_info *gl_info = context->gl_info;
if (context->free_event_query_count)
{
query->id = context->free_event_queries[--context->free_event_query_count];
}
else
{
if (GL_SUPPORT(APPLE_FENCE))
{
ENTER_GL();
GL_EXTCALL(glGenFencesAPPLE(1, &query->id));
checkGLcall("glGenFencesAPPLE");
LEAVE_GL();
TRACE("Allocated event query %u in context %p.\n", query->id, context);
}
else if(GL_SUPPORT(NV_FENCE))
{
ENTER_GL();
GL_EXTCALL(glGenFencesNV(1, &query->id));
checkGLcall("glGenFencesNV");
LEAVE_GL();
TRACE("Allocated event query %u in context %p.\n", query->id, context);
}
else
{
WARN("Event queries not supported, not allocating query id.\n");
query->id = 0;
}
}
query->context = context;
list_add_head(&context->event_queries, &query->entry);
}
void context_free_event_query(struct wined3d_event_query *query)
{
struct WineD3DContext *context = query->context;
list_remove(&query->entry);
query->context = NULL;
if (context->free_event_query_count >= context->free_event_query_size - 1)
{
UINT new_size = context->free_event_query_size << 1;
GLuint *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_event_queries,
new_size * sizeof(*context->free_event_queries));
if (!new_data)
{
ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
return;
}
context->free_event_query_size = new_size;
context->free_event_queries = new_data;
}
context->free_event_queries[context->free_event_query_count++] = query->id;
}
void context_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource, WINED3DRESOURCETYPE type) void context_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource, WINED3DRESOURCETYPE type)
{ {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
...@@ -562,6 +629,7 @@ static void context_destroy_gl_resources(struct WineD3DContext *context) ...@@ -562,6 +629,7 @@ static void context_destroy_gl_resources(struct WineD3DContext *context)
{ {
const struct wined3d_gl_info *gl_info = context->gl_info; const struct wined3d_gl_info *gl_info = context->gl_info;
struct wined3d_occlusion_query *occlusion_query; struct wined3d_occlusion_query *occlusion_query;
struct wined3d_event_query *event_query;
struct fbo_entry *entry, *entry2; struct fbo_entry *entry, *entry2;
BOOL has_glctx; BOOL has_glctx;
...@@ -576,6 +644,16 @@ static void context_destroy_gl_resources(struct WineD3DContext *context) ...@@ -576,6 +644,16 @@ static void context_destroy_gl_resources(struct WineD3DContext *context)
occlusion_query->context = NULL; occlusion_query->context = NULL;
} }
LIST_FOR_EACH_ENTRY(event_query, &context->event_queries, struct wined3d_event_query, entry)
{
if (has_glctx)
{
if (GL_SUPPORT(APPLE_FENCE)) GL_EXTCALL(glDeleteFencesAPPLE(1, &event_query->id));
else if (GL_SUPPORT(NV_FENCE)) GL_EXTCALL(glDeleteFencesNV(1, &event_query->id));
}
event_query->context = NULL;
}
LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry) { LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry) {
if (!has_glctx) entry->id = 0; if (!has_glctx) entry->id = 0;
context_destroy_fbo_entry(context, entry); context_destroy_fbo_entry(context, entry);
...@@ -599,12 +677,18 @@ static void context_destroy_gl_resources(struct WineD3DContext *context) ...@@ -599,12 +677,18 @@ static void context_destroy_gl_resources(struct WineD3DContext *context)
GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries)); GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
if (GL_SUPPORT(APPLE_FENCE))
GL_EXTCALL(glDeleteFencesAPPLE(context->free_event_query_count, context->free_event_queries));
else if (GL_SUPPORT(NV_FENCE))
GL_EXTCALL(glDeleteFencesNV(context->free_event_query_count, context->free_event_queries));
checkGLcall("context cleanup"); checkGLcall("context cleanup");
} }
LEAVE_GL(); LEAVE_GL();
HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries); HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries);
HeapFree(GetProcessHeap(), 0, context->free_event_queries);
if (!pwglMakeCurrent(NULL, NULL)) if (!pwglMakeCurrent(NULL, NULL))
{ {
...@@ -1169,6 +1253,13 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar ...@@ -1169,6 +1253,13 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
list_init(&ret->occlusion_queries); list_init(&ret->occlusion_queries);
ret->free_event_query_size = 4;
ret->free_event_queries = HeapAlloc(GetProcessHeap(), 0,
ret->free_event_query_size * sizeof(*ret->free_event_queries));
if (!ret->free_event_queries) goto out;
list_init(&ret->event_queries);
TRACE("Successfully created new context %p\n", ret); TRACE("Successfully created new context %p\n", ret);
list_init(&ret->fbo_list); list_init(&ret->fbo_list);
...@@ -1266,6 +1357,7 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar ...@@ -1266,6 +1357,7 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
out: out:
if (ret) if (ret)
{ {
HeapFree(GetProcessHeap(), 0, ret->free_event_queries);
HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries); HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
HeapFree(GetProcessHeap(), 0, ret->pshader_const_dirty); HeapFree(GetProcessHeap(), 0, ret->pshader_const_dirty);
HeapFree(GetProcessHeap(), 0, ret->vshader_const_dirty); HeapFree(GetProcessHeap(), 0, ret->vshader_const_dirty);
......
...@@ -1196,19 +1196,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINE ...@@ -1196,19 +1196,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINE
break; break;
case WINED3DQUERYTYPE_EVENT: case WINED3DQUERYTYPE_EVENT:
object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData)); object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext; ((struct wined3d_event_query *)object->extendedData)->context = NULL;
ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
ENTER_GL();
if(GL_SUPPORT(APPLE_FENCE)) {
GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
checkGLcall("glGenFencesAPPLE");
} else if(GL_SUPPORT(NV_FENCE)) {
GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
checkGLcall("glGenFencesNV");
}
LEAVE_GL();
break; break;
case WINED3DQUERYTYPE_VCACHE: case WINED3DQUERYTYPE_VCACHE:
......
...@@ -68,31 +68,9 @@ static ULONG WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) { ...@@ -68,31 +68,9 @@ static ULONG WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) {
* context, and (still) leaking the actual query. */ * context, and (still) leaking the actual query. */
if (This->type == WINED3DQUERYTYPE_EVENT) if (This->type == WINED3DQUERYTYPE_EVENT)
{ {
WineQueryEventData *query_data = (WineQueryEventData *)This->extendedData; struct wined3d_event_query *query = This->extendedData;
if (query_data->ctx->tid != GetCurrentThreadId()) if (query->context) context_free_event_query(query);
{
FIXME("Query was created in a different thread, skipping deletion.\n");
}
else
{
ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD);
ENTER_GL();
if (GL_SUPPORT(APPLE_FENCE))
{
GL_EXTCALL(glDeleteFencesAPPLE(1, &query_data->fenceId));
checkGLcall("glDeleteFencesAPPLE");
}
else if (GL_SUPPORT(NV_FENCE))
{
GL_EXTCALL(glDeleteFencesNV(1, &query_data->fenceId));
checkGLcall("glDeleteFencesNV");
}
LEAVE_GL();
}
} }
else if (This->type == WINED3DQUERYTYPE_OCCLUSION) else if (This->type == WINED3DQUERYTYPE_OCCLUSION)
{ {
...@@ -362,14 +340,14 @@ static HRESULT WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface, ...@@ -362,14 +340,14 @@ static HRESULT WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface,
static HRESULT WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) { static HRESULT WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface; IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
struct wined3d_event_query *query = This->extendedData;
BOOL* data = pData; BOOL* data = pData;
WineQueryEventData *query_data = (WineQueryEventData *)This->extendedData;
TRACE("(%p) : type D3DQUERY_EVENT, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags); TRACE("(%p) : type D3DQUERY_EVENT, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
if (!pData || !dwSize) return S_OK; if (!pData || !dwSize) return S_OK;
if (query_data->ctx->tid != GetCurrentThreadId()) if (query->context->tid != GetCurrentThreadId())
{ {
/* See comment in IWineD3DQuery::Issue, event query codeblock */ /* See comment in IWineD3DQuery::Issue, event query codeblock */
FIXME("Wrong thread, reporting GPU idle.\n"); FIXME("Wrong thread, reporting GPU idle.\n");
...@@ -378,18 +356,18 @@ static HRESULT WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void ...@@ -378,18 +356,18 @@ static HRESULT WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void
return S_OK; return S_OK;
} }
ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD); ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
ENTER_GL(); ENTER_GL();
if (GL_SUPPORT(APPLE_FENCE)) if (GL_SUPPORT(APPLE_FENCE))
{ {
*data = GL_EXTCALL(glTestFenceAPPLE(query_data->fenceId)); *data = GL_EXTCALL(glTestFenceAPPLE(query->id));
checkGLcall("glTestFenceAPPLE"); checkGLcall("glTestFenceAPPLE");
} }
else if (GL_SUPPORT(NV_FENCE)) else if (GL_SUPPORT(NV_FENCE))
{ {
*data = GL_EXTCALL(glTestFenceNV(query_data->fenceId)); *data = GL_EXTCALL(glTestFenceNV(query->id));
checkGLcall("glTestFenceNV"); checkGLcall("glTestFenceNV");
} }
else else
...@@ -478,39 +456,45 @@ static HRESULT WINAPI IWineD3DEventQueryImpl_Issue(IWineD3DQuery* iface, DWORD ...@@ -478,39 +456,45 @@ static HRESULT WINAPI IWineD3DEventQueryImpl_Issue(IWineD3DQuery* iface, DWORD
TRACE("(%p) : dwIssueFlags %#x, type D3DQUERY_EVENT\n", This, dwIssueFlags); TRACE("(%p) : dwIssueFlags %#x, type D3DQUERY_EVENT\n", This, dwIssueFlags);
if (dwIssueFlags & WINED3DISSUE_END) if (dwIssueFlags & WINED3DISSUE_END)
{ {
WineQueryEventData *query_data = (WineQueryEventData *)This->extendedData; struct wined3d_event_query *query = This->extendedData;
struct WineD3DContext *context;
if (query_data->ctx->tid != GetCurrentThreadId()) if (query->context)
{
/* GL fences can be used only from the context that created them,
* so if a different context is active, don't bother setting the query. The penalty
* of a context switch is most likely higher than the gain of a correct query result
*
* If the query is used from a different thread, don't bother creating a multithread
* context - there's no point in doing that as the query would be unusable anyway
*/
WARN("Query context not active\n");
}
else
{ {
ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD); if (query->context->tid != GetCurrentThreadId())
ENTER_GL();
if (GL_SUPPORT(APPLE_FENCE))
{ {
GL_EXTCALL(glSetFenceAPPLE(query_data->fenceId)); context_free_event_query(query);
checkGLcall("glSetFenceAPPLE"); context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD);
context_alloc_event_query(context, query);
} }
else if (GL_SUPPORT(NV_FENCE)) else
{ {
GL_EXTCALL(glSetFenceNV(query_data->fenceId, GL_ALL_COMPLETED_NV)); ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
checkGLcall("glSetFenceNV");
} }
}
else
{
context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD);
context_alloc_event_query(context, query);
}
LEAVE_GL(); ENTER_GL();
if (GL_SUPPORT(APPLE_FENCE))
{
GL_EXTCALL(glSetFenceAPPLE(query->id));
checkGLcall("glSetFenceAPPLE");
} }
} else if(dwIssueFlags & WINED3DISSUE_BEGIN) { else if (GL_SUPPORT(NV_FENCE))
{
GL_EXTCALL(glSetFenceNV(query->id, GL_ALL_COMPLETED_NV));
checkGLcall("glSetFenceNV");
}
LEAVE_GL();
}
else if(dwIssueFlags & WINED3DISSUE_BEGIN)
{
/* Started implicitly at device creation */ /* Started implicitly at device creation */
ERR("Event query issued with START flag - what to do?\n"); ERR("Event query issued with START flag - what to do?\n");
} }
......
...@@ -1195,6 +1195,13 @@ struct wined3d_occlusion_query ...@@ -1195,6 +1195,13 @@ struct wined3d_occlusion_query
struct WineD3DContext *context; struct WineD3DContext *context;
}; };
struct wined3d_event_query
{
struct list entry;
GLuint id;
struct WineD3DContext *context;
};
/* The new context manager that should deal with onscreen and offscreen rendering */ /* The new context manager that should deal with onscreen and offscreen rendering */
struct WineD3DContext struct WineD3DContext
{ {
...@@ -1261,6 +1268,11 @@ struct WineD3DContext ...@@ -1261,6 +1268,11 @@ struct WineD3DContext
UINT free_occlusion_query_count; UINT free_occlusion_query_count;
struct list occlusion_queries; struct list occlusion_queries;
GLuint *free_event_queries;
UINT free_event_query_size;
UINT free_event_query_count;
struct list event_queries;
/* Extension emulation */ /* Extension emulation */
GLint gl_fog_source; GLint gl_fog_source;
GLfloat fog_coord_value; GLfloat fog_coord_value;
...@@ -1278,6 +1290,7 @@ typedef enum ContextUsage { ...@@ -1278,6 +1290,7 @@ typedef enum ContextUsage {
struct WineD3DContext *ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, enum ContextUsage usage); struct WineD3DContext *ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, enum ContextUsage usage);
WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, HWND win, BOOL create_pbuffer, const WINED3DPRESENT_PARAMETERS *pPresentParms); WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, HWND win, BOOL create_pbuffer, const WINED3DPRESENT_PARAMETERS *pPresentParms);
void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context); void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context);
void context_alloc_event_query(struct WineD3DContext *context, struct wined3d_event_query *query);
void context_alloc_occlusion_query(struct WineD3DContext *context, struct wined3d_occlusion_query *query); void context_alloc_occlusion_query(struct WineD3DContext *context, struct wined3d_occlusion_query *query);
void context_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource, WINED3DRESOURCETYPE type); void context_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource, WINED3DRESOURCETYPE type);
void context_bind_fbo(struct WineD3DContext *context, GLenum target, GLuint *fbo); void context_bind_fbo(struct WineD3DContext *context, GLenum target, GLuint *fbo);
...@@ -1285,6 +1298,7 @@ void context_attach_depth_stencil_fbo(struct WineD3DContext *context, ...@@ -1285,6 +1298,7 @@ void context_attach_depth_stencil_fbo(struct WineD3DContext *context,
GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer); GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer);
void context_attach_surface_fbo(const struct WineD3DContext *context, void context_attach_surface_fbo(const struct WineD3DContext *context,
GLenum fbo_target, DWORD idx, IWineD3DSurface *surface); GLenum fbo_target, DWORD idx, IWineD3DSurface *surface);
void context_free_event_query(struct wined3d_event_query *query);
void context_free_occlusion_query(struct wined3d_occlusion_query *query); void context_free_occlusion_query(struct wined3d_occlusion_query *query);
struct WineD3DContext *context_get_current(void); struct WineD3DContext *context_get_current(void);
DWORD context_get_tls_idx(void); DWORD context_get_tls_idx(void);
...@@ -2364,12 +2378,6 @@ extern const IWineD3DQueryVtbl IWineD3DQuery_Vtbl; ...@@ -2364,12 +2378,6 @@ extern const IWineD3DQueryVtbl IWineD3DQuery_Vtbl;
extern const IWineD3DQueryVtbl IWineD3DEventQuery_Vtbl; extern const IWineD3DQueryVtbl IWineD3DEventQuery_Vtbl;
extern const IWineD3DQueryVtbl IWineD3DOcclusionQuery_Vtbl; extern const IWineD3DQueryVtbl IWineD3DOcclusionQuery_Vtbl;
/* Datastructures for IWineD3DQueryImpl.extendedData */
typedef struct WineQueryEventData {
GLuint fenceId;
WineD3DContext *ctx;
} WineQueryEventData;
/* IWineD3DBuffer */ /* IWineD3DBuffer */
/* TODO: Add tests and support for FLOAT16_4 POSITIONT, D3DCOLOR position, other /* TODO: Add tests and support for FLOAT16_4 POSITIONT, D3DCOLOR position, other
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment