diff options
author | Lars Norberg | 2018-03-26 22:40:54 +0200 |
---|---|---|
committer | Lars Norberg | 2018-03-26 22:40:54 +0200 |
commit | 60a34983d19f8aabe667b20cf951ab4dda41d293 (patch) | |
tree | fba2b8424435d5853781e875fa78e86c7aac32a8 /0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch | |
parent | b9ee62f46a35e7eb1a40f0c7872e48f5ec776e82 (diff) | |
download | aur-60a34983d19f8aabe667b20cf951ab4dda41d293.tar.gz |
rebased wine-pba
Diffstat (limited to '0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch')
-rw-r--r-- | 0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch | 679 |
1 files changed, 679 insertions, 0 deletions
diff --git a/0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch b/0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch new file mode 100644 index 000000000000..d4b2299641b0 --- /dev/null +++ b/0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch @@ -0,0 +1,679 @@ +From af82b8e867af940f7ec68998a797aa5d7dfc540a Mon Sep 17 00:00:00 2001 +From: Andrew Comminos <andrew@comminos.com> +Date: Mon, 5 Mar 2018 15:39:11 -0800 +Subject: [PATCH 2/9] wined3d: Add support for backing dynamic wined3d_buffer + objects by a persistent map. + +--- + dlls/wined3d/buffer.c | 220 ++++++++++++++++++++++++++++++++++++++++- + dlls/wined3d/context.c | 6 +- + dlls/wined3d/cs.c | 60 ++++++++++- + dlls/wined3d/resource.c | 18 +++- + dlls/wined3d/state.c | 17 +++- + dlls/wined3d/texture.c | 13 +++ + dlls/wined3d/utils.c | 1 + + dlls/wined3d/wined3d_private.h | 11 +++ + 8 files changed, 336 insertions(+), 10 deletions(-) + +diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c +index cae7ef8788..e7a0f59a67 100644 +--- a/dlls/wined3d/buffer.c ++++ b/dlls/wined3d/buffer.c +@@ -28,12 +28,14 @@ + #include "wined3d_private.h" + + WINE_DEFAULT_DEBUG_CHANNEL(d3d); ++WINE_DECLARE_DEBUG_CHANNEL(d3d_perf); + + #define WINED3D_BUFFER_HASDESC 0x01 /* A vertex description has been found. */ + #define WINED3D_BUFFER_USE_BO 0x02 /* Use a buffer object for this buffer. */ + #define WINED3D_BUFFER_PIN_SYSMEM 0x04 /* Keep a system memory copy for this buffer. */ + #define WINED3D_BUFFER_DISCARD 0x08 /* A DISCARD lock has occurred since the last preload. */ + #define WINED3D_BUFFER_APPLESYNC 0x10 /* Using sync as in GL_APPLE_flush_buffer_range. */ ++#define WINED3D_BUFFER_PERSISTENT 0x20 /* Uses a persistent-mapped buffer via ARB_buffer_storage. */ + + #define VB_MAXDECLCHANGES 100 /* After that number of decl changes we stop converting */ + #define VB_RESETDECLCHANGE 1000 /* Reset the decl changecount after that number of draws */ +@@ -269,6 +271,52 @@ fail: + return FALSE; + } + ++/* Context activation is done by the caller. */ ++static BOOL buffer_alloc_persistent_map(struct wined3d_buffer *buffer, struct wined3d_context *context) ++{ ++ struct wined3d_device *device = buffer->resource.device; ++ struct wined3d_buffer_heap *heap; ++ struct wined3d_map_range map_range; ++ HRESULT hr; ++ ++ if (buffer->bind_flags & WINED3D_BIND_CONSTANT_BUFFER) ++ { ++ // Use a heap aligned to constant buffer offset requirements. ++ heap = device->cb_buffer_heap; ++ } ++ else ++ { ++ if (!(buffer->resource.usage & WINED3DUSAGE_WRITEONLY)) ++ FIXME("Using a write-only persistent buffer for %p without WINED3DUSAGE_WRITEONLY.\n", buffer); ++ heap = device->wo_buffer_heap; ++ } ++ ++ buffer->buffer_heap = heap; ++ if (FAILED(hr = wined3d_buffer_heap_alloc(heap, buffer->resource.size, &map_range))) ++ { ++ goto fail; ++ } ++ buffer->cs_persistent_map = map_range; ++ buffer->mt_persistent_map = map_range; ++ return TRUE; ++ ++fail: ++ // FIXME(acomminos): fall back to standalone BO here? ++ ERR("Failed to create persistent map for buffer %p, hr=%x\n", buffer, hr); ++ buffer->buffer_heap = NULL; ++ return FALSE; ++} ++ ++static void buffer_free_persistent_map(struct wined3d_buffer *buffer) ++{ ++ if (!buffer->buffer_heap) ++ return; ++ ++ // TODO(acomminos): get the CS thread to free pending main thread buffers. ++ wined3d_buffer_heap_free(buffer->buffer_heap, buffer->cs_persistent_map); ++ buffer->buffer_heap = NULL; ++} ++ + static BOOL buffer_process_converted_attribute(struct wined3d_buffer *buffer, + const enum wined3d_buffer_conversion_type conversion_type, + const struct wined3d_stream_info_element *attrib, DWORD *stride_this_run) +@@ -631,6 +679,16 @@ static BOOL wined3d_buffer_prepare_location(struct wined3d_buffer *buffer, + return FALSE; + } + return buffer_create_buffer_object(buffer, context); ++ case WINED3D_LOCATION_PERSISTENT_MAP: ++ if (buffer->buffer_heap) ++ return TRUE; ++ ++ if (!(buffer->flags & WINED3D_BUFFER_PERSISTENT)) ++ { ++ WARN("Trying to map a persistent region for buffer %p without WINED3D_BUFFER_PERSISTENT.\n", buffer); ++ return FALSE; ++ } ++ return buffer_alloc_persistent_map(buffer, context); + + default: + ERR("Invalid location %s.\n", wined3d_debug_location(location)); +@@ -689,16 +747,32 @@ BOOL wined3d_buffer_load_location(struct wined3d_buffer *buffer, + buffer_conversion_upload(buffer, context); + break; + ++ case WINED3D_LOCATION_PERSISTENT_MAP: ++ // TODO(acomminos): are we guaranteed location_sysmem to be kept? ++ // no. ++ if (buffer->conversion_map) ++ FIXME("Attempting to use conversion map with persistent mapping.\n"); ++ memcpy(buffer->buffer_heap->map_ptr + ++ buffer->cs_persistent_map.offset, ++ buffer->resource.heap_memory, buffer->resource.size); ++ break; ++ + default: + ERR("Invalid location %s.\n", wined3d_debug_location(location)); + return FALSE; + } + + wined3d_buffer_validate_location(buffer, location); +- if (buffer->resource.heap_memory && location == WINED3D_LOCATION_BUFFER ++ if (buffer->resource.heap_memory ++ && location & WINED3D_LOCATION_BUFFER + && !(buffer->resource.usage & WINED3DUSAGE_DYNAMIC)) + wined3d_buffer_evict_sysmem(buffer); + ++ // FIXME(acomminos) ++ if (buffer->resource.heap_memory ++ && location & WINED3D_LOCATION_PERSISTENT_MAP) ++ wined3d_buffer_evict_sysmem(buffer); ++ + return TRUE; + } + +@@ -720,12 +794,25 @@ DWORD wined3d_buffer_get_memory(struct wined3d_buffer *buffer, + { + data->buffer_object = buffer->buffer_object; + data->addr = NULL; ++ data->length = buffer->resource.size; + return WINED3D_LOCATION_BUFFER; + } ++ if (locations & WINED3D_LOCATION_PERSISTENT_MAP) ++ { ++ // FIXME(acomminos): should we expose a buffer object we don't wholly own here? ++ data->buffer_object = buffer->buffer_heap->buffer_object; ++ data->addr = buffer->cs_persistent_map.offset; ++ // Note that the size of the underlying buffer allocation may be larger ++ // than the buffer knows about. In this case, we've rounded it up to be ++ // aligned (e.g. for uniform buffer offsets). ++ data->length = buffer->cs_persistent_map.size; ++ return WINED3D_LOCATION_PERSISTENT_MAP; ++ } + if (locations & WINED3D_LOCATION_SYSMEM) + { + data->buffer_object = 0; + data->addr = buffer->resource.heap_memory; ++ data->length = buffer->resource.size; + return WINED3D_LOCATION_SYSMEM; + } + +@@ -761,6 +848,8 @@ static void buffer_unload(struct wined3d_resource *resource) + buffer->flags &= ~WINED3D_BUFFER_HASDESC; + } + ++ buffer_free_persistent_map(buffer); ++ + resource_unload(resource); + } + +@@ -784,6 +873,8 @@ static void wined3d_buffer_destroy_object(void *object) + heap_free(buffer->conversion_map); + } + ++ buffer_free_persistent_map(buffer); ++ + heap_free(buffer->maps); + heap_free(buffer); + } +@@ -900,6 +991,16 @@ void wined3d_buffer_load(struct wined3d_buffer *buffer, struct wined3d_context * + + buffer_mark_used(buffer); + ++ if (buffer->flags & WINED3D_BUFFER_PERSISTENT) ++ { ++ if (wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_PERSISTENT_MAP)) ++ return; ++ ++ ERR("Failed to preload persistent mapping for %p, falling back to BO.\n", buffer); ++ buffer->flags |= WINED3D_BUFFER_USE_BO; ++ buffer->flags &= ~WINED3D_BUFFER_PERSISTENT; ++ } ++ + /* TODO: Make converting independent from VBOs */ + if (!(buffer->flags & WINED3D_BUFFER_USE_BO)) + { +@@ -1010,6 +1111,25 @@ static HRESULT wined3d_buffer_map(struct wined3d_buffer *buffer, UINT offset, UI + + count = ++buffer->resource.map_count; + ++ if (buffer->locations & WINED3D_LOCATION_PERSISTENT_MAP) ++ { ++ const struct wined3d_gl_info *gl_info; ++ context = context_acquire(device, NULL, 0); ++ ++ FIXME_(d3d_perf)("Fences not used for persistent buffer maps on CS thread, using glFinish.\n"); ++ ++ gl_info = context->gl_info; ++ gl_info->gl_ops.gl.p_glFinish(); ++ ++ base = buffer->buffer_heap->map_ptr ++ + buffer->cs_persistent_map.offset; ++ *data = base + offset; ++ ++ context_release(context); ++ ++ return WINED3D_OK; ++ } ++ + if (buffer->buffer_object) + { + unsigned int dirty_offset = offset, dirty_size = size; +@@ -1152,6 +1272,12 @@ static void wined3d_buffer_unmap(struct wined3d_buffer *buffer) + return; + } + ++ if (buffer->flags & WINED3D_BUFFER_PERSISTENT) ++ { ++ TRACE("Persistent buffer, ignore unmap.\n"); ++ return; ++ } ++ + if (buffer->map_ptr) + { + struct wined3d_device *device = buffer->resource.device; +@@ -1256,6 +1382,64 @@ static void buffer_resource_preload(struct wined3d_resource *resource) + + static HRESULT buffer_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx, + struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) ++{ ++ struct wined3d_buffer *buffer = buffer_from_resource(resource); ++ UINT offset = box ? box->left : 0; ++ ++ if (sub_resource_idx) ++ { ++ WARN("Invalid sub_resource_idx %u.\n", sub_resource_idx); ++ return E_INVALIDARG; ++ } ++ ++ // Support immediate mapping of persistent buffers off the command thread, ++ // which require no GL calls to interface with. ++ if (buffer->locations & WINED3D_LOCATION_PERSISTENT_MAP) ++ { ++ map_desc->row_pitch = map_desc->slice_pitch = buffer->desc.byte_width; ++ if (flags & WINED3D_MAP_DISCARD) ++ { ++ HRESULT hr; ++ struct wined3d_map_range map_range; ++ if (FAILED(hr = wined3d_buffer_heap_alloc(buffer->buffer_heap, resource->size, &map_range))) ++ { ++ FIXME_(d3d_perf)("Failed to allocate new buffer, falling back to sync path.\n"); ++ return hr; ++ } ++ map_desc->data = buffer->buffer_heap->map_ptr + map_range.offset + offset; ++ resource->map_count++; ++ ++ buffer->mt_persistent_map = map_range; ++ ++ // Discard handler on CSMT thread is responsible for returning the ++ // currently used buffer to the free pool, along with the fence that ++ // must be called before the buffer can be reused. ++ wined3d_cs_emit_discard_buffer(resource->device->cs, buffer, map_range); ++ return WINED3D_OK; ++ } ++ else if (flags & WINED3D_MAP_NOOVERWRITE) ++ { ++ // Allow immediate access for persistent buffers without a fence. ++ // Always use the latest buffer in this case in case the latest ++ // DISCARDed one hasn't reached the command stream yet. ++ struct wined3d_map_range map_range = buffer->mt_persistent_map; ++ map_desc->data = buffer->buffer_heap->map_ptr + map_range.offset + offset; ++ resource->map_count++; ++ return WINED3D_OK; ++ } ++ else ++ { ++ // TODO(acomminos): Should check mapped ranges to see if the region is writeable even though NOOVERWRITE is specified. ++ WARN_(d3d_perf)("Mapping persistent buffer %p in sync with CS thread.\n", buffer); ++ // XXX(acomminos): kill this early return. they're the worst. ++ } ++ } ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT buffer_resource_sub_resource_map_cs(struct wined3d_resource *resource, unsigned int sub_resource_idx, ++ struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) + { + struct wined3d_buffer *buffer = buffer_from_resource(resource); + UINT offset, size; +@@ -1299,6 +1483,18 @@ static HRESULT buffer_resource_sub_resource_map_info(struct wined3d_resource *re + } + + static HRESULT buffer_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx) ++{ ++ struct wined3d_buffer *buffer = buffer_from_resource(resource); ++ if (buffer->locations & WINED3D_LOCATION_PERSISTENT_MAP) ++ { ++ // Nothing to be done to unmap a region of a persistent buffer. ++ resource->map_count--; ++ return WINED3D_OK; ++ } ++ return E_NOTIMPL; ++} ++ ++static HRESULT buffer_resource_sub_resource_unmap_cs(struct wined3d_resource *resource, unsigned int sub_resource_idx) + { + if (sub_resource_idx) + { +@@ -1319,6 +1515,8 @@ static const struct wined3d_resource_ops buffer_resource_ops = + buffer_resource_sub_resource_map, + buffer_resource_sub_resource_map_info, + buffer_resource_sub_resource_unmap, ++ buffer_resource_sub_resource_map_cs, ++ buffer_resource_sub_resource_unmap_cs, + }; + + static GLenum buffer_type_hint_from_bind_flags(const struct wined3d_gl_info *gl_info, +@@ -1394,12 +1592,30 @@ static HRESULT buffer_init(struct wined3d_buffer *buffer, struct wined3d_device + buffer->flags |= WINED3D_BUFFER_PIN_SYSMEM; + } + ++ if (buffer->resource.usage & WINED3DUSAGE_DYNAMIC) ++ { ++ if (!gl_info->supported[ARB_BUFFER_STORAGE]) ++ { ++ WARN_(d3d_perf)("Not creating a persistent mapping for a dynamic buffer because ARB_buffer_storage is unsupported.\n"); ++ } ++ else ++ { ++ // If supported, use persistent mapped buffers instead of a ++ // standalone BO for dynamic buffers. ++ buffer->flags |= WINED3D_BUFFER_PERSISTENT; ++ } ++ } ++ + /* Observations show that draw_primitive_immediate_mode() is faster on + * dynamic vertex buffers than converting + draw_primitive_arrays(). + * (Half-Life 2 and others.) */ + dynamic_buffer_ok = gl_info->supported[APPLE_FLUSH_BUFFER_RANGE] || gl_info->supported[ARB_MAP_BUFFER_RANGE]; + +- if (!gl_info->supported[ARB_VERTEX_BUFFER_OBJECT]) ++ if (buffer->flags & WINED3D_BUFFER_PERSISTENT) ++ { ++ TRACE("Not creating a BO because a persistent mapped buffer will be used.\n"); ++ } ++ else if (!gl_info->supported[ARB_VERTEX_BUFFER_OBJECT]) + { + TRACE("Not creating a BO because GL_ARB_vertex_buffer is not supported.\n"); + } +diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c +index 0e2e68b4b0..eae2c3a79d 100644 +--- a/dlls/wined3d/context.c ++++ b/dlls/wined3d/context.c +@@ -5005,7 +5005,11 @@ void draw_primitive(struct wined3d_device *device, const struct wined3d_state *s + if (parameters->indexed) + { + struct wined3d_buffer *index_buffer = state->index_buffer; +- if (!index_buffer->buffer_object || !stream_info->all_vbo) ++ if (index_buffer->locations & WINED3D_LOCATION_PERSISTENT_MAP) ++ { ++ idx_data = index_buffer->cs_persistent_map.offset; ++ } ++ else if (!index_buffer->buffer_object || !stream_info->all_vbo) + { + idx_data = index_buffer->resource.heap_memory; + } +diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c +index 50a4d041cd..e61b8dedbb 100644 +--- a/dlls/wined3d/cs.c ++++ b/dlls/wined3d/cs.c +@@ -73,6 +73,7 @@ enum wined3d_cs_op + WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW, + WINED3D_CS_OP_COPY_UAV_COUNTER, + WINED3D_CS_OP_GENERATE_MIPMAPS, ++ WINED3D_CS_OP_DISCARD_BUFFER, + WINED3D_CS_OP_STOP, + }; + +@@ -439,6 +440,13 @@ struct wined3d_cs_generate_mipmaps + struct wined3d_shader_resource_view *view; + }; + ++struct wined3d_cs_discard_buffer ++{ ++ enum wined3d_cs_op opcode; ++ struct wined3d_buffer *buffer; ++ struct wined3d_map_range map_range; ++}; ++ + struct wined3d_cs_stop + { + enum wined3d_cs_op opcode; +@@ -2002,7 +2010,7 @@ static void wined3d_cs_exec_map(struct wined3d_cs *cs, const void *data) + const struct wined3d_cs_map *op = data; + struct wined3d_resource *resource = op->resource; + +- *op->hr = resource->resource_ops->resource_sub_resource_map(resource, ++ *op->hr = resource->resource_ops->resource_sub_resource_map_cs(resource, + op->sub_resource_idx, op->map_desc, op->box, op->flags); + } + +@@ -2036,7 +2044,7 @@ static void wined3d_cs_exec_unmap(struct wined3d_cs *cs, const void *data) + const struct wined3d_cs_unmap *op = data; + struct wined3d_resource *resource = op->resource; + +- *op->hr = resource->resource_ops->resource_sub_resource_unmap(resource, op->sub_resource_idx); ++ *op->hr = resource->resource_ops->resource_sub_resource_unmap_cs(resource, op->sub_resource_idx); + } + + HRESULT wined3d_cs_unmap(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx) +@@ -2455,6 +2463,53 @@ void wined3d_cs_emit_generate_mipmaps(struct wined3d_cs *cs, struct wined3d_shad + cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); + } + ++static void wined3d_cs_exec_discard_buffer(struct wined3d_cs *cs, const void *data) ++{ ++ const struct wined3d_cs_discard_buffer *op = data; ++ struct wined3d_buffer *buffer = op->buffer; ++ HRESULT hr; ++ ++ // TODO(acomminos): should call into buffer.c here instead. ++ if (FAILED(hr = wined3d_buffer_heap_free_fenced(buffer->buffer_heap, cs->device, buffer->cs_persistent_map))) ++ { ++ ERR("Failed to do a fenced free on discarded buffer %p, hr %x\n. Freeing anyway.", buffer, hr); ++ wined3d_buffer_heap_free(buffer->buffer_heap, buffer->cs_persistent_map); ++ } ++ ++ buffer->cs_persistent_map = op->map_range; ++ ++ // TODO(acomminos): merge this logic with buffer.c functions for standalone BOs ++ if (buffer->bind_flags & WINED3D_BIND_VERTEX_BUFFER) ++ device_invalidate_state(cs->device, STATE_STREAMSRC); ++ if (buffer->bind_flags & WINED3D_BIND_INDEX_BUFFER) ++ device_invalidate_state(cs->device, STATE_INDEXBUFFER); ++ if (buffer->bind_flags & WINED3D_BIND_CONSTANT_BUFFER) ++ { ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX)); ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_HULL)); ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_DOMAIN)); ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY)); ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL)); ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COMPUTE)); ++ } ++ ++ wined3d_resource_release(&op->buffer->resource); ++} ++ ++void wined3d_cs_emit_discard_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer, struct wined3d_map_range map_range) ++{ ++ struct wined3d_cs_discard_buffer *op; ++ ++ op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT); ++ op->opcode = WINED3D_CS_OP_DISCARD_BUFFER; ++ op->buffer = buffer; ++ op->map_range = map_range; ++ ++ wined3d_resource_acquire(&buffer->resource); ++ ++ cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); ++} ++ + static void wined3d_cs_emit_stop(struct wined3d_cs *cs) + { + struct wined3d_cs_stop *op; +@@ -2515,6 +2570,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void + /* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view, + /* WINED3D_CS_OP_COPY_UAV_COUNTER */ wined3d_cs_exec_copy_uav_counter, + /* WINED3D_CS_OP_GENERATE_MIPMAPS */ wined3d_cs_exec_generate_mipmaps, ++ /* WINED3D_CS_OP_DISCARD_BUFFER */ wined3d_cs_exec_discard_buffer, + }; + + #if defined(STAGING_CSMT) +diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c +index 8b7f17bb6b..02d469bc20 100644 +--- a/dlls/wined3d/resource.c ++++ b/dlls/wined3d/resource.c +@@ -344,6 +344,7 @@ static DWORD wined3d_resource_sanitise_map_flags(const struct wined3d_resource * + HRESULT CDECL wined3d_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx, + struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) + { ++ HRESULT hr; + TRACE("resource %p, sub_resource_idx %u, map_desc %p, box %s, flags %#x.\n", + resource, sub_resource_idx, map_desc, debug_box(box), flags); + +@@ -366,9 +367,14 @@ HRESULT CDECL wined3d_resource_map(struct wined3d_resource *resource, unsigned i + } + + flags = wined3d_resource_sanitise_map_flags(resource, flags); +- wined3d_resource_wait_idle(resource); ++ if (FAILED(hr = resource->resource_ops->resource_sub_resource_map(resource, sub_resource_idx, map_desc, box, flags))) ++ { ++ TRACE_(d3d_perf)("Mapping resource %p on the command stream.\n", resource); ++ wined3d_resource_wait_idle(resource); ++ hr = wined3d_cs_map(resource->device->cs, resource, sub_resource_idx, map_desc, box, flags); ++ } + +- return wined3d_cs_map(resource->device->cs, resource, sub_resource_idx, map_desc, box, flags); ++ return hr; + } + + HRESULT CDECL wined3d_resource_map_info(struct wined3d_resource *resource, unsigned int sub_resource_idx, +@@ -381,9 +387,15 @@ HRESULT CDECL wined3d_resource_map_info(struct wined3d_resource *resource, unsig + + HRESULT CDECL wined3d_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx) + { ++ HRESULT hr; + TRACE("resource %p, sub_resource_idx %u.\n", resource, sub_resource_idx); + +- return wined3d_cs_unmap(resource->device->cs, resource, sub_resource_idx); ++ if (FAILED(hr = resource->resource_ops->resource_sub_resource_unmap(resource, sub_resource_idx))) ++ { ++ TRACE_(d3d_perf)("Unmapping resource %p on the command stream.\n", resource); ++ hr = wined3d_cs_unmap(resource->device->cs, resource, sub_resource_idx); ++ } ++ return hr; + } + + UINT CDECL wined3d_resource_update_info(struct wined3d_resource *resource, unsigned int sub_resource_idx, +diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c +index 2f506c36d1..6f7805b8bd 100644 +--- a/dlls/wined3d/state.c ++++ b/dlls/wined3d/state.c +@@ -4934,7 +4934,11 @@ static void indexbuffer(struct wined3d_context *context, const struct wined3d_st + else + { + struct wined3d_buffer *ib = state->index_buffer; +- GL_EXTCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->buffer_object)); ++ // FIXME(acomminos): disasterous. ++ if (ib->locations & WINED3D_LOCATION_PERSISTENT_MAP) ++ GL_EXTCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->buffer_heap->buffer_object)); ++ else ++ GL_EXTCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->buffer_object)); + } + } + +@@ -5000,6 +5004,7 @@ static void state_cb(struct wined3d_context *context, const struct wined3d_state + enum wined3d_shader_type shader_type; + struct wined3d_buffer *buffer; + unsigned int i, base, count; ++ struct wined3d_bo_address bo_addr; + + TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); + +@@ -5012,7 +5017,15 @@ static void state_cb(struct wined3d_context *context, const struct wined3d_state + for (i = 0; i < count; ++i) + { + buffer = state->cb[shader_type][i]; +- GL_EXTCALL(glBindBufferBase(GL_UNIFORM_BUFFER, base + i, buffer ? buffer->buffer_object : 0)); ++ if (buffer) ++ { ++ wined3d_buffer_get_memory(buffer, &bo_addr, buffer->locations); ++ GL_EXTCALL(glBindBufferRange(GL_UNIFORM_BUFFER, base + i, bo_addr.buffer_object, bo_addr.addr, bo_addr.length)); ++ } ++ else ++ { ++ GL_EXTCALL(glBindBufferBase(GL_UNIFORM_BUFFER, base + i, 0)); ++ } + } + checkGLcall("bind constant buffers"); + } +diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c +index e6af0c7508..7260f902cf 100644 +--- a/dlls/wined3d/texture.c ++++ b/dlls/wined3d/texture.c +@@ -2301,6 +2301,12 @@ static void wined3d_texture_unload(struct wined3d_resource *resource) + + static HRESULT texture_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx, + struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) ++{ ++ return E_NOTIMPL; ++} ++ ++static HRESULT texture_resource_sub_resource_map_cs(struct wined3d_resource *resource, unsigned int sub_resource_idx, ++ struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) + { + const struct wined3d_format *format = resource->format; + struct wined3d_texture_sub_resource *sub_resource; +@@ -2461,6 +2467,11 @@ static HRESULT texture_resource_sub_resource_map_info(struct wined3d_resource *r + } + + static HRESULT texture_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx) ++{ ++ return E_NOTIMPL; ++} ++ ++static HRESULT texture_resource_sub_resource_unmap_cs(struct wined3d_resource *resource, unsigned int sub_resource_idx) + { + struct wined3d_texture_sub_resource *sub_resource; + struct wined3d_device *device = resource->device; +@@ -2513,6 +2524,8 @@ static const struct wined3d_resource_ops texture_resource_ops = + texture_resource_sub_resource_map, + texture_resource_sub_resource_map_info, + texture_resource_sub_resource_unmap, ++ texture_resource_sub_resource_map_cs, ++ texture_resource_sub_resource_unmap_cs, + }; + + static HRESULT texture1d_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc, +diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c +index b8b7880501..62758ae056 100644 +--- a/dlls/wined3d/utils.c ++++ b/dlls/wined3d/utils.c +@@ -6404,6 +6404,7 @@ const char *wined3d_debug_location(DWORD location) + LOCATION_TO_STR(WINED3D_LOCATION_DRAWABLE); + LOCATION_TO_STR(WINED3D_LOCATION_RB_MULTISAMPLE); + LOCATION_TO_STR(WINED3D_LOCATION_RB_RESOLVED); ++ LOCATION_TO_STR(WINED3D_LOCATION_PERSISTENT_MAP); + #undef LOCATION_TO_STR + if (location) + FIXME("Unrecognized location flag(s) %#x.\n", location); +diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h +index 3d535f4e17..b3fd0136ff 100644 +--- a/dlls/wined3d/wined3d_private.h ++++ b/dlls/wined3d/wined3d_private.h +@@ -1470,6 +1470,7 @@ struct wined3d_bo_address + { + GLuint buffer_object; + BYTE *addr; ++ GLsizeiptr length; + }; + + struct wined3d_const_bo_address +@@ -3047,6 +3048,9 @@ struct wined3d_resource_ops + HRESULT (*resource_map_info)(struct wined3d_resource *resource, unsigned int sub_resource_idx, + struct wined3d_map_info *info, DWORD flags); + HRESULT (*resource_sub_resource_unmap)(struct wined3d_resource *resource, unsigned int sub_resource_idx); ++ HRESULT (*resource_sub_resource_map_cs)(struct wined3d_resource *resource, unsigned int sub_resource_idx, ++ struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags); ++ HRESULT (*resource_sub_resource_unmap_cs)(struct wined3d_resource *resource, unsigned int sub_resource_idx); + }; + + struct wined3d_resource +@@ -3325,6 +3329,7 @@ void wined3d_texture_validate_location(struct wined3d_texture *texture, + #define WINED3D_LOCATION_DRAWABLE 0x00000040 + #define WINED3D_LOCATION_RB_MULTISAMPLE 0x00000080 + #define WINED3D_LOCATION_RB_RESOLVED 0x00000100 ++#define WINED3D_LOCATION_PERSISTENT_MAP 0x00000200 + + const char *wined3d_debug_location(DWORD location) DECLSPEC_HIDDEN; + +@@ -3672,6 +3677,7 @@ void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resou + void wined3d_cs_emit_update_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *resource, + unsigned int sub_resource_idx, const struct wined3d_box *box, const void *data, unsigned int row_pitch, + unsigned int slice_pitch) DECLSPEC_HIDDEN; ++void wined3d_cs_emit_discard_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer, struct wined3d_map_range map_range) DECLSPEC_HIDDEN; + void wined3d_cs_init_object(struct wined3d_cs *cs, + void (*callback)(void *object), void *object) DECLSPEC_HIDDEN; + HRESULT wined3d_cs_map(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx, +@@ -3784,6 +3790,11 @@ struct wined3d_buffer + UINT stride; /* 0 if no conversion */ + enum wined3d_buffer_conversion_type *conversion_map; /* NULL if no conversion */ + UINT conversion_stride; /* 0 if no shifted conversion */ ++ ++ /* persistent mapped buffer */ ++ struct wined3d_buffer_heap *buffer_heap; ++ struct wined3d_map_range cs_persistent_map; ++ struct wined3d_map_range mt_persistent_map; // TODO: make struct list? + }; + + static inline struct wined3d_buffer *buffer_from_resource(struct wined3d_resource *resource) +-- +2.16.2 + |