From 6a9dca267d122629bb600d4f79aa0bb46d27e12c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Mon, 25 Jan 2010 23:43:37 +0100 Subject: [PATCH 05/18] WineD3D: Implement manual fencing with GL_APPLE_flush_buffer_range --- dlls/wined3d/buffer.c | 48 ++++++++++++++++++++++++++++++++++++++++ dlls/wined3d/device.c | 10 +++++++- dlls/wined3d/drawprim.c | 18 +++++++++++++++ dlls/wined3d/wined3d_private.h | 4 +++ 4 files changed, 79 insertions(+), 1 deletions(-) diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c index 64d144a..8642130 100644 --- a/dlls/wined3d/buffer.c +++ b/dlls/wined3d/buffer.c @@ -101,6 +101,10 @@ static void delete_gl_buffer(struct wined3d_buffer *This) checkGLcall("glDeleteBuffersARB"); LEAVE_GL(); This->buffer_object = 0; + + if(This->query) IWineD3DQuery_Release(This->query); + This->query = NULL; + This->flags &= ~WINED3D_BUFFER_APPLESYNC; } /* Context activation is done by the caller. */ @@ -163,6 +167,19 @@ static void buffer_create_buffer_object(struct wined3d_buffer *This) GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE)); checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE)"); This->flags |= WINED3D_BUFFER_FLUSH; + + /* The d3d way to check for event query support would be to try to create a query with a NULL + * ppQuery pointer and check the return result. However, WineD3D fakes event queries if they're + * not supported by GL because some games depend on them and some drivers don't provide support + * for them. So check the GL extensions instead + */ + if(gl_info->supported[APPLE_FENCE] || gl_info->supported[NV_FENCE] || + gl_info->supported[ARB_SYNC]) + { + This->flags |= WINED3D_BUFFER_APPLESYNC; + GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE)); + checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE)"); + } } } else @@ -1040,6 +1057,35 @@ static WINED3DRESOURCETYPE STDMETHODCALLTYPE buffer_GetType(IWineD3DBuffer *ifac /* IWineD3DBuffer methods */ +/* The caller provides a context and GL locking and binds the buffer */ +static void buffer_sync_apple(struct wined3d_buffer *This, DWORD flags) +{ + HRESULT hr; + + /* No fencing needs to be done if the app promises not to overwrite + * existing data */ + if(flags & WINED3DLOCK_NOOVERWRITE) return; + + if(!This->query) return; /* No draw yet */ + LEAVE_GL(); + hr = wined3d_event_query_finish(This->query); + ENTER_GL(); + if(FAILED(hr)) + { + /* This happens when draws and maps happen in different threads and the query code cannot handle + * this. glFinish() does not help here because it doesn't wait for draws in different contexts. */ + ERR("Waiting for the buffer sync query failed. Dropping async buffer updates\n"); + LEAVE_GL(); + IWineD3DQuery_Release(This->query); + ENTER_GL(); + This->query = NULL; + This->flags &= ~WINED3D_BUFFER_APPLESYNC; + + GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE)); + checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE)"); + } +} + static HRESULT STDMETHODCALLTYPE buffer_Map(IWineD3DBuffer *iface, UINT offset, UINT size, BYTE **data, DWORD flags) { struct wined3d_buffer *This = (struct wined3d_buffer *)iface; @@ -1066,6 +1112,8 @@ static HRESULT STDMETHODCALLTYPE buffer_Map(IWineD3DBuffer *iface, UINT offset, context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD); ENTER_GL(); GL_EXTCALL(glBindBufferARB(This->buffer_type_hint, This->buffer_object)); + if(This->flags & WINED3D_BUFFER_APPLESYNC) buffer_sync_apple(This, flags); + This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(This->buffer_type_hint, GL_READ_WRITE_ARB)); LEAVE_GL(); context_release(context); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index d66b46e..739de5c 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -314,10 +314,18 @@ void device_stream_info_from_declaration(IWineD3DDeviceImpl *This, * * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only * once in there. */ + This->num_buffer_fences = 0; for (i = 0; i < stream_count; ++i) { IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]]; - if (vb) IWineD3DBuffer_PreLoad(vb); + if (vb) + { + IWineD3DBuffer_PreLoad(vb); + if(((struct wined3d_buffer *) vb)->flags & WINED3D_BUFFER_APPLESYNC) + { + This->buffer_fences[This->num_buffer_fences++] = vb; + } + } } } diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 8250e79..1bdae6d 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -692,6 +692,24 @@ void drawPrimitive(IWineD3DDevice *iface, UINT index_count, UINT StartIdx, UINT LEAVE_GL(); context_release(context); + for(i = 0; i < This->num_buffer_fences; i++) + { + struct wined3d_buffer *cur = (struct wined3d_buffer *) This->buffer_fences[i]; + + if(!cur->query) + { + HRESULT hr; + hr = IWineD3DDevice_CreateQuery(iface, WINED3DQUERYTYPE_EVENT, &cur->query, NULL); + if(FAILED(hr)) + { + ERR("Creating an event query for the buffer failed\n"); + continue; + } + } + + IWineD3DQuery_Issue(cur->query, WINED3DISSUE_END); + } + TRACE("Done all gl drawing\n"); /* Diagnostics */ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 0ea4bb9..26e3da4 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1597,6 +1597,8 @@ struct IWineD3DDeviceImpl /* Stream source management */ struct wined3d_stream_info strided_streams; const WineDirect3DVertexStridedData *up_strided; + IWineD3DBuffer *buffer_fences[MAX_ATTRIBS]; + unsigned int num_buffer_fences; /* Context management */ struct wined3d_context **contexts; @@ -2382,6 +2384,7 @@ struct wined3d_map_range #define WINED3D_BUFFER_CREATEBO 0x04 /* Attempt to create a buffer object next PreLoad */ #define WINED3D_BUFFER_DOUBLEBUFFER 0x08 /* Use a vbo and local allocated memory */ #define WINED3D_BUFFER_FLUSH 0x10 /* Manual unmap flushing */ +#define WINED3D_BUFFER_APPLESYNC 0x20 /* Using sync as in GL_APPLE_flush_buffer_range */ struct wined3d_buffer { @@ -2400,6 +2403,7 @@ struct wined3d_buffer LONG lock_count; struct wined3d_map_range *maps; ULONG maps_size, modified_areas; + IWineD3DQuery *query; /* conversion stuff */ UINT decl_change_count, full_conversion_count; -- 1.6.4.4