[PATCH 1/6] wined3d: Manage occlusion queries in the context.
Henri Verbeet
hverbeet at codeweavers.com
Fri Jul 24 03:44:13 CDT 2009
---
dlls/wined3d/context.c | 84 +++++++++++++++++++++++++++++++++
dlls/wined3d/device.c | 14 +----
dlls/wined3d/query.c | 101 +++++++++++++++++++++++-----------------
dlls/wined3d/wined3d_private.h | 20 ++++++--
4 files changed, 160 insertions(+), 59 deletions(-)
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 5afbda7..ae153d9 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -451,6 +451,63 @@ static void context_apply_fbo_state(struct WineD3DContext *context)
context_check_fbo_status(context);
}
+/* Context activation is done by the caller. */
+void context_alloc_occlusion_query(struct WineD3DContext *context, struct wined3d_occlusion_query *query)
+{
+ const struct wined3d_gl_info *gl_info = context->gl_info;
+
+ if (context->free_occlusion_query_count)
+ {
+ query->id = context->free_occlusion_queries[--context->free_occlusion_query_count];
+ }
+ else
+ {
+ if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
+ {
+ ENTER_GL();
+ GL_EXTCALL(glGenQueriesARB(1, &query->id));
+ checkGLcall("glGenQueriesARB");
+ LEAVE_GL();
+
+ TRACE("Allocated occlusion query %u in context %p.\n", query->id, context);
+ }
+ else
+ {
+ WARN("Occlusion queries not supported, not allocating query id.\n");
+ query->id = 0;
+ }
+ }
+
+ query->context = context;
+ list_add_head(&context->occlusion_queries, &query->entry);
+}
+
+void context_free_occlusion_query(struct wined3d_occlusion_query *query)
+{
+ struct WineD3DContext *context = query->context;
+
+ list_remove(&query->entry);
+ query->context = NULL;
+
+ if (context->free_occlusion_query_count >= context->free_occlusion_query_size - 1)
+ {
+ UINT new_size = context->free_occlusion_query_size << 1;
+ GLuint *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_occlusion_queries,
+ new_size * sizeof(*context->free_occlusion_queries));
+
+ if (!new_data)
+ {
+ ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
+ return;
+ }
+
+ context->free_occlusion_query_size = new_size;
+ context->free_occlusion_queries = new_data;
+ }
+
+ context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
+}
+
void context_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource, WINED3DRESOURCETYPE type)
{
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
@@ -504,6 +561,7 @@ void context_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource
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 fbo_entry *entry, *entry2;
BOOL has_glctx;
@@ -512,6 +570,12 @@ static void context_destroy_gl_resources(struct WineD3DContext *context)
ENTER_GL();
+ LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry)
+ {
+ if (has_glctx && GL_SUPPORT(ARB_OCCLUSION_QUERY)) GL_EXTCALL(glDeleteQueriesARB(1, &occlusion_query->id));
+ occlusion_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);
@@ -532,10 +596,16 @@ static void context_destroy_gl_resources(struct WineD3DContext *context)
{
GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
}
+
+ GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
+
+ checkGLcall("context cleanup");
}
LEAVE_GL();
+ HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries);
+
if (!pwglMakeCurrent(NULL, NULL))
{
ERR("Failed to disable GL context.\n");
@@ -1092,6 +1162,13 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
sizeof(*ret->pshader_const_dirty) * GL_LIMITS(pshader_constantsF));
}
+ ret->free_occlusion_query_size = 4;
+ ret->free_occlusion_queries = HeapAlloc(GetProcessHeap(), 0,
+ ret->free_occlusion_query_size * sizeof(*ret->free_occlusion_queries));
+ if (!ret->free_occlusion_queries) goto out;
+
+ list_init(&ret->occlusion_queries);
+
TRACE("Successfully created new context %p\n", ret);
list_init(&ret->fbo_list);
@@ -1187,6 +1264,13 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
return ret;
out:
+ if (ret)
+ {
+ HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
+ HeapFree(GetProcessHeap(), 0, ret->pshader_const_dirty);
+ HeapFree(GetProcessHeap(), 0, ret->vshader_const_dirty);
+ HeapFree(GetProcessHeap(), 0, ret);
+ }
return NULL;
}
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 10b20fb..e5fd2b2 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1191,18 +1191,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINE
/* allocated the 'extended' data based on the type of query requested */
switch(Type){
case WINED3DQUERYTYPE_OCCLUSION:
- object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
- ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
-
- if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
- TRACE("(%p) Allocating data for an occlusion query\n", This);
+ object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
+ ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
+ break;
- ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
- ENTER_GL();
- GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
- LEAVE_GL();
- break;
- }
case WINED3DQUERYTYPE_EVENT:
object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c
index 6627223..a3dfa87 100644
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -94,25 +94,11 @@ static ULONG WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) {
LEAVE_GL();
}
}
- else if (This->type == WINED3DQUERYTYPE_OCCLUSION && GL_SUPPORT(ARB_OCCLUSION_QUERY))
+ else if (This->type == WINED3DQUERYTYPE_OCCLUSION)
{
- WineQueryOcclusionData *query_data = (WineQueryOcclusionData *)This->extendedData;
+ struct wined3d_occlusion_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();
-
- GL_EXTCALL(glDeleteQueriesARB(1, &query_data->queryId));
- checkGLcall("glDeleteQueriesARB");
-
- LEAVE_GL();
- }
+ if (query->context) context_free_occlusion_query(query);
}
HeapFree(GetProcessHeap(), 0, This->extendedData);
@@ -306,7 +292,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa
static HRESULT WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
- WineQueryOcclusionData *query_data = (WineQueryOcclusionData *)This->extendedData;
+ struct wined3d_occlusion_query *query = This->extendedData;
DWORD* data = pData;
GLuint available;
GLuint samples;
@@ -314,6 +300,8 @@ static HRESULT WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface,
TRACE("(%p) : type D3DQUERY_OCCLUSION, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
+ if (!query->context) This->state = QUERY_CREATED;
+
if (This->state == QUERY_CREATED)
{
/* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
@@ -336,18 +324,18 @@ static HRESULT WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface,
return S_OK;
}
- if (query_data->ctx->tid != GetCurrentThreadId())
+ if (query->context->tid != GetCurrentThreadId())
{
FIXME("%p Wrong thread, returning 1.\n", This);
*data = 1;
return S_OK;
}
- ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD);
+ ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
ENTER_GL();
- GL_EXTCALL(glGetQueryObjectuivARB(query_data->queryId, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
+ GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)");
TRACE("(%p) : available %d.\n", This, available);
@@ -355,7 +343,7 @@ static HRESULT WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface,
{
if (data)
{
- GL_EXTCALL(glGetQueryObjectuivARB(query_data->queryId, GL_QUERY_RESULT_ARB, &samples));
+ GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_ARB, &samples));
checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
TRACE("(%p) : Returning %d samples.\n", This, samples);
*data = samples;
@@ -541,38 +529,65 @@ static HRESULT WINAPI IWineD3DOcclusionQueryImpl_Issue(IWineD3DQuery* iface, D
if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
{
- WineQueryOcclusionData *query_data = (WineQueryOcclusionData *)This->extendedData;
+ struct wined3d_occlusion_query *query = This->extendedData;
+ struct WineD3DContext *context;
- if (query_data->ctx->tid != GetCurrentThreadId())
+ /* This is allowed according to msdn and our tests. Reset the query and restart */
+ if (dwIssueFlags & WINED3DISSUE_BEGIN)
{
- FIXME("Not the owning context, can't start query.\n");
- }
- else
- {
- ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD);
+ if (This->state == QUERY_BUILDING)
+ {
+ if (query->context->tid != GetCurrentThreadId())
+ {
+ FIXME("Wrong thread, can't restart query.\n");
- ENTER_GL();
- /* This is allowed according to msdn and our tests. Reset the query and restart */
- if (dwIssueFlags & WINED3DISSUE_BEGIN) {
- if(This->state == QUERY_BUILDING) {
+ context_free_occlusion_query(query);
+ context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD);
+ context_alloc_occlusion_query(context, query);
+ }
+ else
+ {
+ ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
+
+ ENTER_GL();
GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
checkGLcall("glEndQuery()");
+ LEAVE_GL();
}
-
- GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, query_data->queryId));
- checkGLcall("glBeginQuery()");
}
- if (dwIssueFlags & WINED3DISSUE_END) {
- /* Msdn says _END on a non-building occlusion query returns an error, but
- * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
- * generating an error
- */
- if(This->state == QUERY_BUILDING) {
+ else
+ {
+ if (query->context) context_free_occlusion_query(query);
+ context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD);
+ context_alloc_occlusion_query(context, query);
+ }
+
+ ENTER_GL();
+ GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, query->id));
+ checkGLcall("glBeginQuery()");
+ LEAVE_GL();
+ }
+ if (dwIssueFlags & WINED3DISSUE_END) {
+ /* Msdn says _END on a non-building occlusion query returns an error, but
+ * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
+ * generating an error
+ */
+ if (This->state == QUERY_BUILDING)
+ {
+ if (query->context->tid != GetCurrentThreadId())
+ {
+ FIXME("Wrong thread, can't end query.\n");
+ }
+ else
+ {
+ ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
+
+ ENTER_GL();
GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
checkGLcall("glEndQuery()");
+ LEAVE_GL();
}
}
- LEAVE_GL();
}
} else {
FIXME("(%p) : Occlusion queries not supported\n", This);
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index bb64875..533befd 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1188,6 +1188,13 @@ enum fogsource {
#define WINED3D_MAX_FBO_ENTRIES 64
+struct wined3d_occlusion_query
+{
+ struct list entry;
+ GLuint id;
+ struct WineD3DContext *context;
+};
+
/* The new context manager that should deal with onscreen and offscreen rendering */
struct WineD3DContext
{
@@ -1248,6 +1255,12 @@ struct WineD3DContext
GLuint fbo_read_binding;
GLuint fbo_draw_binding;
+ /* Queries */
+ GLuint *free_occlusion_queries;
+ UINT free_occlusion_query_size;
+ UINT free_occlusion_query_count;
+ struct list occlusion_queries;
+
/* Extension emulation */
GLint gl_fog_source;
GLfloat fog_coord_value;
@@ -1265,12 +1278,14 @@ 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_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);
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_occlusion_query(struct wined3d_occlusion_query *query);
struct WineD3DContext *context_get_current(void);
DWORD context_get_tls_idx(void);
BOOL context_set_current(struct WineD3DContext *ctx);
@@ -2350,11 +2365,6 @@ extern const IWineD3DQueryVtbl IWineD3DEventQuery_Vtbl;
extern const IWineD3DQueryVtbl IWineD3DOcclusionQuery_Vtbl;
/* Datastructures for IWineD3DQueryImpl.extendedData */
-typedef struct WineQueryOcclusionData {
- GLuint queryId;
- WineD3DContext *ctx;
-} WineQueryOcclusionData;
-
typedef struct WineQueryEventData {
GLuint fenceId;
WineD3DContext *ctx;
--
1.6.0.6
More information about the wine-patches
mailing list