Commit 4ab7af65 authored by Henri Verbeet's avatar Henri Verbeet Committed by Alexandre Julliard

wined3d: Manage occlusion queries in the context.

parent 6a1aa9b1
......@@ -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;
}
......
......@@ -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;
......
......@@ -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);
......
......@@ -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;
......
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