From 7987c82d7cfd9ffbc5cacf9335303a8710ecd432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Thu, 10 Dec 2009 21:50:11 +0100 Subject: [PATCH 05/17] WineD3D: Implement buffer subrange mapping with GL_APPLE_flush_buffer_range --- dlls/wined3d/buffer.c | 83 +++++++++++++++++++++++++++++++++++++--- dlls/wined3d/device.c | 4 +- dlls/wined3d/wined3d_private.h | 9 ++++ 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c index 17ce8cb..97138a1 100644 --- a/dlls/wined3d/buffer.c +++ b/dlls/wined3d/buffer.c @@ -85,6 +85,21 @@ static void buffer_create_buffer_object(struct wined3d_buffer *This) { TRACE("Gl usage = GL_DYNAMIC_DRAW\n"); gl_usage = GL_DYNAMIC_DRAW_ARB; + if(This->resource.device->adapter->gl_info.supported[APPLE_FLUSH_BUFFER_RANGE]) + { + This->maps = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->maps)); + if(!This->maps) + { + /* Continuing would work, but the performance of plain vbos for dynamic + * buffers is usually worse than no vbo at all. + */ + ERR("Out of memory\n"); + goto fail; + } + This->maps_size = 1; + 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)"); + } } else { @@ -130,6 +145,9 @@ fail: /* Clean up all vbo init, but continue because we can work without a vbo :-) */ ERR("Failed to create a vertex buffer object. Continuing, but performance issues may occur\n"); if (This->buffer_object) GL_EXTCALL(glDeleteBuffersARB(1, &This->buffer_object)); + HeapFree(GetProcessHeap(), 0, This->maps); + This->maps = NULL; + This->maps_size = 0; This->buffer_object = 0; LEAVE_GL(); @@ -619,6 +637,9 @@ static void STDMETHODCALLTYPE buffer_UnLoad(IWineD3DBuffer *iface) checkGLcall("glDeleteBuffersARB"); LEAVE_GL(); This->buffer_object = 0; + HeapFree(GetProcessHeap(), 0, This->maps); + This->maps = NULL; + This->maps_size = 0; This->flags |= WINED3D_BUFFER_CREATEBO; /* Recreate the buffer object next load */ context_release(context); @@ -746,6 +767,9 @@ static void STDMETHODCALLTYPE buffer_PreLoad(IWineD3DBuffer *iface) This->buffer_object = 0; } HeapFree(GetProcessHeap(), 0, This->conversion_shift); + HeapFree(GetProcessHeap(), 0, This->maps); + This->maps = NULL; + This->maps_size = 0; /* The stream source state handler might have read the memory of the vertex buffer already * and got the memory in the vbo which is not valid any longer. Dirtify the stream source @@ -934,6 +958,38 @@ static HRESULT STDMETHODCALLTYPE buffer_Map(IWineD3DBuffer *iface, UINT offset, count = InterlockedIncrement(&This->lock_count); + if(This->maps) + { + if(This->maps_size < count) + { + void *new = HeapReAlloc(GetProcessHeap(), 0, This->maps, + This->maps_size * 2 * sizeof(*This->maps)); + if(!new) + { + ERR("Out of memory\n"); + InterlockedDecrement(&This->lock_count); + return E_OUTOFMEMORY; + } + else + { + This->maps = new; + This->maps_size *= 2; + } + } + + if(size) + { + This->maps[count - 1].start = offset; + This->maps[count - 1].len = size; + } + else + { + This->maps[count - 1].start = 0; + This->maps[count - 1].len = This->resource.size; + } + + } + if (This->flags & WINED3D_BUFFER_DIRTY) { if (This->dirty_start > offset) This->dirty_start = offset; @@ -990,6 +1046,9 @@ static HRESULT STDMETHODCALLTYPE buffer_Map(IWineD3DBuffer *iface, UINT offset, static HRESULT STDMETHODCALLTYPE buffer_Unmap(IWineD3DBuffer *iface) { struct wined3d_buffer *This = (struct wined3d_buffer *)iface; + ULONG count; + struct wined3d_context *context = NULL; + IWineD3DDeviceImpl *device = This->resource.device; TRACE("(%p)\n", This); @@ -1003,29 +1062,39 @@ static HRESULT STDMETHODCALLTYPE buffer_Unmap(IWineD3DBuffer *iface) return WINED3D_OK; } - if (InterlockedDecrement(&This->lock_count)) + count = InterlockedDecrement(&This->lock_count); + if(This->maps) + { + context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + GL_EXTCALL(glFlushMappedBufferRangeAPPLE(This->buffer_type_hint, + This->maps[count].start, + This->maps[count].len)); + checkGLcall("glFlushMappedBufferRangeAPPLE"); + LEAVE_GL(); + } + + if (count) { /* Delay loading the buffer until everything is unlocked */ TRACE("Ignoring unlock\n"); - return WINED3D_OK; + goto done; } if(!(This->flags & WINED3D_BUFFER_DOUBLEBUFFER) && This->buffer_object) { IWineD3DDeviceImpl *device = This->resource.device; - struct wined3d_context *context; if(This->buffer_type_hint == GL_ELEMENT_ARRAY_BUFFER_ARB) { - IWineD3DDeviceImpl_MarkStateDirty(This->resource.device, STATE_INDEXBUFFER); + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_INDEXBUFFER); } - context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD); + if(!context) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD); ENTER_GL(); GL_EXTCALL(glBindBufferARB(This->buffer_type_hint, This->buffer_object)); GL_EXTCALL(glUnmapBufferARB(This->buffer_type_hint)); LEAVE_GL(); - context_release(context); This->resource.allocatedMemory = NULL; } @@ -1034,6 +1103,8 @@ static HRESULT STDMETHODCALLTYPE buffer_Unmap(IWineD3DBuffer *iface) buffer_PreLoad(iface); } +done: + if(context) context_release(context); return WINED3D_OK; } diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index c2cd64a..295caa4 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -446,8 +446,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnkno static BOOL gl_support_dynamic_buffer(const struct wined3d_gl_info *gl_info) { - /* TODO: GL_APPLE_flush_buffer_range and GL_ARB_map_buffer_range */ - return FALSE; + /* TODO: GL_ARB_map_buffer_range */ + return gl_info->supported[APPLE_FLUSH_BUFFER_RANGE]; } static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc, diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 1834c77..2f9825a 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2350,6 +2350,12 @@ enum wined3d_buffer_conversion_type #define WINED3D_BUFFER_CREATEBO 0x08 /* Attempt to create a buffer object next PreLoad */ #define WINED3D_BUFFER_DOUBLEBUFFER 0x10 /* Use a vbo and local allocated memory */ +struct map_range +{ + UINT start; + UINT len; +}; + struct wined3d_buffer { const struct IWineD3DBufferVtbl *vtbl; @@ -2368,6 +2374,9 @@ struct wined3d_buffer UINT dirty_end; LONG lock_count; + struct map_range *maps; + LONG maps_size; + /* conversion stuff */ UINT conversion_count; UINT draw_count; -- 1.6.4.4