diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index ae153d99692..010925427e5 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -2,6 +2,7 @@ * Context and render target management in wined3d * * 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 * 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) 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) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; @@ -562,6 +629,7 @@ static void context_destroy_gl_resources(struct WineD3DContext *context) { const struct wined3d_gl_info *gl_info = context->gl_info; struct wined3d_occlusion_query *occlusion_query; + struct wined3d_event_query *event_query; struct fbo_entry *entry, *entry2; BOOL has_glctx; @@ -576,6 +644,16 @@ static void context_destroy_gl_resources(struct WineD3DContext *context) 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) { if (!has_glctx) entry->id = 0; context_destroy_fbo_entry(context, entry); @@ -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)); + 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"); } LEAVE_GL(); HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries); + HeapFree(GetProcessHeap(), 0, context->free_event_queries); if (!pwglMakeCurrent(NULL, NULL)) { @@ -1169,6 +1253,13 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar 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); list_init(&ret->fbo_list); @@ -1266,6 +1357,7 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar out: if (ret) { + HeapFree(GetProcessHeap(), 0, ret->free_event_queries); HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries); HeapFree(GetProcessHeap(), 0, ret->pshader_const_dirty); HeapFree(GetProcessHeap(), 0, ret->vshader_const_dirty); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index e5fd2b25e59..6edb39e7a09 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -1196,19 +1196,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINE break; case WINED3DQUERYTYPE_EVENT: - object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData)); - ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext; - - 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(); + object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query)); + ((struct wined3d_event_query *)object->extendedData)->context = NULL; break; case WINED3DQUERYTYPE_VCACHE: diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c index a3dfa875798..0f395bca458 100644 --- a/dlls/wined3d/query.c +++ b/dlls/wined3d/query.c @@ -68,31 +68,9 @@ static ULONG WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) { * context, and (still) leaking the actual query. */ if (This->type == WINED3DQUERYTYPE_EVENT) { - WineQueryEventData *query_data = (WineQueryEventData *)This->extendedData; + struct wined3d_event_query *query = This->extendedData; - if (query_data->ctx->tid != GetCurrentThreadId()) - { - 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(); - } + if (query->context) context_free_event_query(query); } else if (This->type == WINED3DQUERYTYPE_OCCLUSION) { @@ -362,14 +340,14 @@ static HRESULT WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface, static HRESULT WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) { IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface; + struct wined3d_event_query *query = This->extendedData; 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); 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 */ FIXME("Wrong thread, reporting GPU idle.\n"); @@ -378,18 +356,18 @@ static HRESULT WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void return S_OK; } - ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD); + ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD); ENTER_GL(); if (GL_SUPPORT(APPLE_FENCE)) { - *data = GL_EXTCALL(glTestFenceAPPLE(query_data->fenceId)); + *data = GL_EXTCALL(glTestFenceAPPLE(query->id)); checkGLcall("glTestFenceAPPLE"); } else if (GL_SUPPORT(NV_FENCE)) { - *data = GL_EXTCALL(glTestFenceNV(query_data->fenceId)); + *data = GL_EXTCALL(glTestFenceNV(query->id)); checkGLcall("glTestFenceNV"); } else @@ -478,39 +456,45 @@ static HRESULT WINAPI IWineD3DEventQueryImpl_Issue(IWineD3DQuery* iface, DWORD TRACE("(%p) : dwIssueFlags %#x, type D3DQUERY_EVENT\n", This, dwIssueFlags); 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"); + if (query->context->tid != GetCurrentThreadId()) + { + context_free_event_query(query); + context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD); + context_alloc_event_query(context, query); + } + else + { + ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD); + } } else { - ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD); - - ENTER_GL(); - - if (GL_SUPPORT(APPLE_FENCE)) - { - GL_EXTCALL(glSetFenceAPPLE(query_data->fenceId)); - checkGLcall("glSetFenceAPPLE"); - } - else if (GL_SUPPORT(NV_FENCE)) - { - GL_EXTCALL(glSetFenceNV(query_data->fenceId, GL_ALL_COMPLETED_NV)); - checkGLcall("glSetFenceNV"); - } - - LEAVE_GL(); + context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD); + context_alloc_event_query(context, query); } - } else if(dwIssueFlags & WINED3DISSUE_BEGIN) { + + ENTER_GL(); + + if (GL_SUPPORT(APPLE_FENCE)) + { + GL_EXTCALL(glSetFenceAPPLE(query->id)); + checkGLcall("glSetFenceAPPLE"); + } + 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 */ ERR("Event query issued with START flag - what to do?\n"); } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 533befd2fca..be2811b1abf 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1195,6 +1195,13 @@ struct wined3d_occlusion_query 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 */ struct WineD3DContext { @@ -1261,6 +1268,11 @@ struct WineD3DContext UINT free_occlusion_query_count; struct list occlusion_queries; + GLuint *free_event_queries; + UINT free_event_query_size; + UINT free_event_query_count; + struct list event_queries; + /* Extension emulation */ GLint gl_fog_source; GLfloat fog_coord_value; @@ -1278,6 +1290,7 @@ typedef enum ContextUsage { 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); 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_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource, WINED3DRESOURCETYPE type); void context_bind_fbo(struct WineD3DContext *context, GLenum target, GLuint *fbo); @@ -1285,6 +1298,7 @@ void context_attach_depth_stencil_fbo(struct WineD3DContext *context, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer); void context_attach_surface_fbo(const struct WineD3DContext *context, 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); struct WineD3DContext *context_get_current(void); DWORD context_get_tls_idx(void); @@ -2364,12 +2378,6 @@ extern const IWineD3DQueryVtbl IWineD3DQuery_Vtbl; extern const IWineD3DQueryVtbl IWineD3DEventQuery_Vtbl; extern const IWineD3DQueryVtbl IWineD3DOcclusionQuery_Vtbl; -/* Datastructures for IWineD3DQueryImpl.extendedData */ -typedef struct WineQueryEventData { - GLuint fenceId; - WineD3DContext *ctx; -} WineQueryEventData; - /* IWineD3DBuffer */ /* TODO: Add tests and support for FLOAT16_4 POSITIONT, D3DCOLOR position, other