From: Józef Kucia Subject: [PATCH 5/6] wined3d: Explicitly track locations for buffers. Message-Id: <1476647209-11162-5-git-send-email-jkucia@codeweavers.com> Date: Sun, 16 Oct 2016 21:46:48 +0200 In-Reply-To: <1476647209-11162-1-git-send-email-jkucia@codeweavers.com> References: <1476647209-11162-1-git-send-email-jkucia@codeweavers.com> Signed-off-by: Józef Kucia --- This is a first step to implement the location tracking for buffers and introduce invalidate/load/prepare location functions for buffers. Such API is required if we want to allow using double buffered buffers as stream output buffers or UAV buffers. The idea is to still track, internally, dirty areas of a buffer object. The buffers should work in the same way as before when there are no external calls to wined3d_buffer_invalidate(). Note: This patch depends on the fact that WINED3D_MAP_DISCARD and WINED3D_MAP_READONLY are never set simultaneously (see wined3d_resource_sanitise_map_flags()). --- dlls/wined3d/buffer.c | 79 ++++++++++++++++++++++++++++++++++++++---- dlls/wined3d/device.c | 1 + dlls/wined3d/wined3d_private.h | 3 ++ 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c index b6338d1..c7f0d81 100644 --- a/dlls/wined3d/buffer.c +++ b/dlls/wined3d/buffer.c @@ -93,6 +93,46 @@ static BOOL buffer_is_fully_dirty(const struct wined3d_buffer *buffer) && !buffer->maps->offset && buffer->maps->size == buffer->resource.size; } +void wined3d_buffer_validate_location(struct wined3d_buffer *buffer, DWORD location) +{ + TRACE("buffer %p, location %s.\n", buffer, wined3d_debug_location(location)); + + if (location & WINED3D_LOCATION_BUFFER) + buffer_clear_dirty_areas(buffer); + + buffer->locations |= location; + + TRACE("New locations flags are %s.\n", wined3d_debug_location(buffer->locations)); +} + +static void wined3d_buffer_invalidate_range(struct wined3d_buffer *buffer, DWORD location, + unsigned int offset, unsigned int size) +{ + TRACE("buffer %p, location %s, offset %u, size %u.\n", + buffer, wined3d_debug_location(location), offset, size); + + if ((offset || size) && (location & ~WINED3D_LOCATION_BUFFER)) + { + ERR("Range can be invalidated only for WINED3D_LOCATION_BUFFER.\n"); + return; + } + + if (location & WINED3D_LOCATION_BUFFER) + buffer_invalidate_bo_range(buffer, offset, size); + + buffer->locations &= ~location; + + TRACE("New locations flags are %s.\n", wined3d_debug_location(buffer->locations)); + + if (!buffer->locations) + ERR("Buffer %p does not have any up to date location.\n", buffer); +} + +void wined3d_buffer_invalidate_location(struct wined3d_buffer *buffer, DWORD location) +{ + wined3d_buffer_invalidate_range(buffer, location, 0, 0); +} + /* Context activation is done by the caller. */ static void buffer_bind(struct wined3d_buffer *buffer, struct wined3d_context *context) { @@ -192,15 +232,21 @@ static void buffer_create_buffer_object(struct wined3d_buffer *This, struct wine This->buffer_object_usage = gl_usage; if (This->flags & WINED3D_BUFFER_DOUBLEBUFFER) + { buffer_invalidate_bo_range(This, 0, 0); + } else + { wined3d_resource_free_sysmem(&This->resource); + wined3d_buffer_validate_location(This, WINED3D_LOCATION_BUFFER); + wined3d_buffer_invalidate_location(This, WINED3D_LOCATION_SYSMEM); + } return; 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"); + ERR("Failed to create a vertex buffer object. Continuing, but performance issues may occur.\n"); This->flags &= ~WINED3D_BUFFER_USE_BO; delete_gl_buffer(This, gl_info); buffer_clear_dirty_areas(This); @@ -509,6 +555,8 @@ BYTE *wined3d_buffer_load_sysmem(struct wined3d_buffer *buffer, struct wined3d_c checkGLcall("buffer download"); buffer->flags |= WINED3D_BUFFER_DOUBLEBUFFER; + wined3d_buffer_validate_location(buffer, WINED3D_LOCATION_SYSMEM); + return buffer->resource.heap_memory; } @@ -532,6 +580,7 @@ static void buffer_unload(struct wined3d_resource *resource) buffer->flags &= ~WINED3D_BUFFER_DOUBLEBUFFER; } + wined3d_buffer_invalidate_location(buffer, WINED3D_LOCATION_BUFFER); delete_gl_buffer(buffer, context->gl_info); buffer_clear_dirty_areas(buffer); @@ -707,7 +756,7 @@ static void buffer_direct_upload(struct wined3d_buffer *This, struct wined3d_con } if (!map) { - ERR("Failed to map opengl buffer\n"); + ERR("Failed to map OpenGL buffer.\n"); return; } @@ -732,6 +781,8 @@ static void buffer_direct_upload(struct wined3d_buffer *This, struct wined3d_con } GL_EXTCALL(glUnmapBuffer(This->buffer_type_hint)); checkGLcall("glUnmapBuffer"); + + wined3d_buffer_validate_location(This, WINED3D_LOCATION_BUFFER); } void buffer_mark_used(struct wined3d_buffer *buffer) @@ -924,6 +975,8 @@ void wined3d_buffer_load(struct wined3d_buffer *buffer, struct wined3d_context * } HeapFree(GetProcessHeap(), 0, data); + + wined3d_buffer_validate_location(buffer, WINED3D_LOCATION_BUFFER); } struct wined3d_resource * CDECL wined3d_buffer_get_resource(struct wined3d_buffer *buffer) @@ -952,17 +1005,28 @@ static HRESULT wined3d_buffer_map(struct wined3d_buffer *buffer, UINT offset, UI if (buffer->buffer_object) { + unsigned int dirty_offset = offset, dirty_size = size; + /* DISCARD invalidates the entire buffer, regardless of the specified * offset and size. Some applications also depend on the entire buffer * being uploaded in that case. Two such applications are Port Royale * and Darkstar One. */ if (flags & WINED3D_MAP_DISCARD) - buffer_invalidate_bo_range(buffer, 0, 0); - else if (!(flags & WINED3D_MAP_READONLY)) - buffer_invalidate_bo_range(buffer, offset, size); + { + dirty_offset = 0; + dirty_size = 0; + } - if (!(buffer->flags & WINED3D_BUFFER_DOUBLEBUFFER)) + if (buffer->flags & WINED3D_BUFFER_DOUBLEBUFFER) { + if (!(flags & WINED3D_MAP_READONLY)) + wined3d_buffer_invalidate_range(buffer, WINED3D_LOCATION_BUFFER, dirty_offset, dirty_size); + } + else + { + if (!(flags & WINED3D_MAP_READONLY)) + buffer_invalidate_bo_range(buffer, dirty_offset, dirty_size); + if (count == 1) { struct wined3d_device *device = buffer->resource.device; @@ -1171,7 +1235,7 @@ HRESULT wined3d_buffer_copy(struct wined3d_buffer *dst_buffer, unsigned int dst_ } if (dst_buffer_mem) - buffer_invalidate_bo_range(dst_buffer, dst_offset, size); + wined3d_buffer_invalidate_range(dst_buffer, WINED3D_LOCATION_BUFFER, dst_offset, size); context_release(context); return WINED3D_OK; @@ -1300,6 +1364,7 @@ static HRESULT buffer_init(struct wined3d_buffer *buffer, struct wined3d_device return hr; } buffer->buffer_type_hint = bind_hint; + buffer->locations = WINED3D_LOCATION_SYSMEM; TRACE("size %#x, usage %#x, format %s, memory @ %p, iface @ %p.\n", buffer->resource.size, buffer->resource.usage, debug_d3dformat(buffer->resource.format->id), buffer->resource.heap_memory, buffer); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 89b781c..a611531 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -3179,6 +3179,7 @@ HRESULT CDECL wined3d_device_process_vertices(struct wined3d_device *device, { GL_EXTCALL(glDeleteBuffers(1, &buffer->buffer_object)); buffer->buffer_object = 0; + wined3d_buffer_invalidate_location(buffer, WINED3D_LOCATION_BUFFER); } if (e->data.addr) e->data.addr += e->stride * src_start_idx; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index c3152a2..45a24f1 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3163,6 +3163,7 @@ struct wined3d_buffer struct wined3d_map_range *maps; ULONG maps_size, modified_areas; + DWORD locations; struct wined3d_event_query *query; /* conversion stuff */ @@ -3181,6 +3182,7 @@ static inline struct wined3d_buffer *buffer_from_resource(struct wined3d_resourc void buffer_get_memory(struct wined3d_buffer *buffer, struct wined3d_context *context, struct wined3d_bo_address *data) DECLSPEC_HIDDEN; void buffer_mark_used(struct wined3d_buffer *buffer) DECLSPEC_HIDDEN; +void wined3d_buffer_invalidate_location(struct wined3d_buffer *buffer, DWORD location) DECLSPEC_HIDDEN; void wined3d_buffer_load(struct wined3d_buffer *buffer, struct wined3d_context *context, const struct wined3d_state *state) DECLSPEC_HIDDEN; BYTE *wined3d_buffer_load_sysmem(struct wined3d_buffer *buffer, struct wined3d_context *context) DECLSPEC_HIDDEN; @@ -3188,6 +3190,7 @@ HRESULT wined3d_buffer_copy(struct wined3d_buffer *dst_buffer, unsigned int dst_ struct wined3d_buffer *src_buffer, unsigned int src_offset, unsigned int size) DECLSPEC_HIDDEN; HRESULT wined3d_buffer_upload_data(struct wined3d_buffer *buffer, const struct wined3d_box *box, const void *data) DECLSPEC_HIDDEN; +void wined3d_buffer_validate_location(struct wined3d_buffer *buffer, DWORD location) DECLSPEC_HIDDEN; struct wined3d_rendertarget_view { -- 2.7.3