Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wined3d/buffer.c | 13 ++++++------- dlls/wined3d/texture.c | 18 +++++++++++------- dlls/wined3d/wined3d_private.h | 3 ++- 3 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c index 7c3537e466e..3ecaa9017d0 100644 --- a/dlls/wined3d/buffer.c +++ b/dlls/wined3d/buffer.c @@ -30,7 +30,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d);
#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 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 */ @@ -47,7 +46,7 @@ struct wined3d_buffer_ops
static void wined3d_buffer_evict_sysmem(struct wined3d_buffer *buffer) { - if (buffer->flags & WINED3D_BUFFER_PIN_SYSMEM) + if (buffer->resource.pin_sysmem) { TRACE("Not evicting system memory for buffer %p.\n", buffer); return; @@ -513,7 +512,7 @@ static void buffer_conversion_upload(struct wined3d_buffer *buffer, struct wined ERR("Failed to load system memory.\n"); return; } - buffer->flags |= WINED3D_BUFFER_PIN_SYSMEM; + buffer->resource.pin_sysmem = 1;
/* Now for each vertex in the buffer that needs conversion. */ vertex_count = buffer->resource.size / buffer->stride; @@ -666,7 +665,7 @@ BOOL wined3d_buffer_load_location(struct wined3d_buffer *buffer, BYTE *wined3d_buffer_load_sysmem(struct wined3d_buffer *buffer, struct wined3d_context *context) { if (wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_SYSMEM)) - buffer->flags |= WINED3D_BUFFER_PIN_SYSMEM; + buffer->resource.pin_sysmem = 1; return buffer->resource.heap_memory; }
@@ -966,7 +965,7 @@ static HRESULT buffer_resource_sub_resource_map(struct wined3d_resource *resourc
if (((flags & WINED3D_MAP_WRITE) && !(flags & (WINED3D_MAP_NOOVERWRITE | WINED3D_MAP_DISCARD))) || (!(flags & WINED3D_MAP_WRITE) && (buffer->locations & WINED3D_LOCATION_SYSMEM)) - || buffer->flags & WINED3D_BUFFER_PIN_SYSMEM + || buffer->resource.pin_sysmem || !(buffer->flags & WINED3D_BUFFER_USE_BO)) { if (!(buffer->locations & WINED3D_LOCATION_SYSMEM)) @@ -1036,7 +1035,7 @@ static HRESULT buffer_resource_sub_resource_map(struct wined3d_resource *resourc { TRACE("Falling back to doublebuffered operation.\n"); wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_SYSMEM); - buffer->flags |= WINED3D_BUFFER_PIN_SYSMEM; + buffer->resource.pin_sysmem = 1; } TRACE("New pointer is %p.\n", resource->heap_memory); } @@ -1302,7 +1301,7 @@ static HRESULT wined3d_buffer_init(struct wined3d_buffer *buffer, struct wined3d * maps and retain data in DISCARD maps. Keep a system memory copy of * the buffer to provide the same behavior to the application. */ TRACE("Pinning system memory.\n"); - buffer->flags |= WINED3D_BUFFER_PIN_SYSMEM; + buffer->resource.pin_sysmem = 1; buffer->locations = WINED3D_LOCATION_SYSMEM; }
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index b1fd1e7bde2..1323d533eff 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -48,8 +48,8 @@ struct wined3d_rect_f
BOOL wined3d_texture_can_use_pbo(const struct wined3d_texture *texture, const struct wined3d_d3d_info *d3d_info) { - if (!d3d_info->pbo || texture->resource.format->conv_byte_count - || (texture->flags & (WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_COND_NP2_EMULATED))) + if (!d3d_info->pbo || texture->resource.format->conv_byte_count || texture->resource.pin_sysmem + || (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)) return FALSE;
return TRUE; @@ -666,7 +666,8 @@ static void wined3d_texture_evict_sysmem(struct wined3d_texture *texture) struct wined3d_texture_sub_resource *sub_resource; unsigned int i, sub_count;
- if (texture->flags & (WINED3D_TEXTURE_CONVERTED | WINED3D_TEXTURE_PIN_SYSMEM) + if ((texture->flags & WINED3D_TEXTURE_CONVERTED) + || texture->resource.pin_sysmem || texture->download_count > WINED3D_TEXTURE_DYNAMIC_MAP_THRESHOLD) { TRACE("Not evicting system memory for texture %p.\n", texture); @@ -2462,8 +2463,8 @@ static void wined3d_texture_gl_upload_data(struct wined3d_context *context,
if (dst_texture->sub_resources[dst_sub_resource_idx].map_count) { - WARN("Uploading a texture that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n"); - dst_texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM; + WARN("Uploading a texture that is currently mapped, pinning sysmem.\n"); + dst_texture->resource.pin_sysmem = 1; }
if (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_HEIGHT_SCALE) @@ -3825,7 +3826,10 @@ static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struc texture->flags |= WINED3D_TEXTURE_POW2_MAT_IDENT | WINED3D_TEXTURE_NORMALIZED_COORDS | WINED3D_TEXTURE_DOWNLOADABLE; if (flags & WINED3D_TEXTURE_CREATE_GET_DC_LENIENT) - texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_GET_DC_LENIENT; + { + texture->flags |= WINED3D_TEXTURE_GET_DC_LENIENT; + texture->resource.pin_sysmem = 1; + } if (flags & (WINED3D_TEXTURE_CREATE_GET_DC | WINED3D_TEXTURE_CREATE_GET_DC_LENIENT)) texture->flags |= WINED3D_TEXTURE_GET_DC; if (flags & WINED3D_TEXTURE_CREATE_DISCARD) @@ -5744,7 +5748,7 @@ static bool blitter_use_cpu_clear(struct wined3d_rendertarget_view *view) locations = texture->sub_resources[view->sub_resource_idx].locations; if (locations & (resource->map_binding | WINED3D_LOCATION_DISCARDED)) return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU) - || (texture->flags & WINED3D_TEXTURE_PIN_SYSMEM); + || texture->resource.pin_sysmem;
return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU) && !(texture->flags & WINED3D_TEXTURE_CONVERTED); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index c8c9bb7c8c6..e190fc4285e 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -4332,6 +4332,8 @@ struct wined3d_resource DWORD priority; void *heap_memory;
+ uint32_t pin_sysmem : 1; + struct wined3d_client_resource client;
void *parent; @@ -4450,7 +4452,6 @@ struct wined3d_texture_ops #define WINED3D_TEXTURE_SRGB_ALLOCATED 0x00000040 #define WINED3D_TEXTURE_SRGB_VALID 0x00000080 #define WINED3D_TEXTURE_CONVERTED 0x00000100 -#define WINED3D_TEXTURE_PIN_SYSMEM 0x00000200 #define WINED3D_TEXTURE_NORMALIZED_COORDS 0x00000400 #define WINED3D_TEXTURE_GET_DC_LENIENT 0x00000800 #define WINED3D_TEXTURE_DC_IN_USE 0x00001000
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wined3d/cs.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 56abc146733..4a20f2ffe23 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -3094,6 +3094,12 @@ static bool wined3d_cs_map_upload_bo(struct wined3d_device_context *context, str return NULL; }
+ if (resource->pin_sysmem) + { + TRACE("Not allocating an upload buffer because system memory is pinned for this resource.\n"); + return NULL; + } + if (flags & WINED3D_MAP_DISCARD) { if (!device->adapter->adapter_ops->adapter_alloc_bo(device, resource, sub_resource_idx, &addr))
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wined3d/adapter_gl.c | 43 ++++++++++++++++++++++++++++++++++ dlls/wined3d/buffer.c | 2 +- dlls/wined3d/cs.c | 36 ++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 4 ++++ 4 files changed, 84 insertions(+), 1 deletion(-)
diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c index bc54f46222f..cb0c34823aa 100644 --- a/dlls/wined3d/adapter_gl.c +++ b/dlls/wined3d/adapter_gl.c @@ -4616,6 +4616,49 @@ static void adapter_gl_flush_bo_address(struct wined3d_context *context, static bool adapter_gl_alloc_bo(struct wined3d_device *device, struct wined3d_resource *resource, unsigned int sub_resource_idx, struct wined3d_bo_address *addr) { + const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; + struct wined3d_device_gl *device_gl = wined3d_device_gl(device); + + wined3d_not_from_cs(device->cs); + assert(device->context_count); + + if (resource->type == WINED3D_RTYPE_BUFFER) + { + GLenum usage = GL_STATIC_DRAW; + struct wined3d_bo_gl *bo_gl; + bool coherent = true; + + if (resource->usage & WINED3DUSAGE_DYNAMIC) + { + usage = GL_STREAM_DRAW_ARB; + coherent = false; + } + + if (!(bo_gl = heap_alloc(sizeof(*bo_gl)))) + return false; + + if (!(wined3d_device_gl_create_bo(device_gl, NULL, resource->size, + wined3d_buffer_gl_binding_from_bind_flags(gl_info, resource->bind_flags), + usage, coherent, wined3d_resource_gl_storage_flags(resource), bo_gl))) + { + WARN("Failed to create OpenGL buffer.\n"); + heap_free(bo_gl); + return false; + } + + addr->buffer_object = &bo_gl->b; + addr->addr = NULL; + + if (!bo_gl->b.map_ptr) + { + WARN_(d3d_perf)("BO %p (chunk %p) is not persistently mapped.\n", + bo_gl, bo_gl->memory ? bo_gl->memory->chunk : NULL); + wined3d_cs_map_bo_address(device->cs, addr, resource->size, WINED3D_MAP_WRITE | WINED3D_MAP_DISCARD); + } + + return true; + } + return false; }
diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c index 3ecaa9017d0..16308a098e3 100644 --- a/dlls/wined3d/buffer.c +++ b/dlls/wined3d/buffer.c @@ -136,7 +136,7 @@ void wined3d_buffer_invalidate_location(struct wined3d_buffer *buffer, DWORD loc wined3d_buffer_invalidate_range(buffer, location, 0, 0); }
-static GLenum wined3d_buffer_gl_binding_from_bind_flags(const struct wined3d_gl_info *gl_info, uint32_t bind_flags) +GLenum wined3d_buffer_gl_binding_from_bind_flags(const struct wined3d_gl_info *gl_info, uint32_t bind_flags) { if (!bind_flags) return GL_PIXEL_UNPACK_BUFFER; diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 4a20f2ffe23..af3ee9e7624 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -120,6 +120,7 @@ enum wined3d_cs_op WINED3D_CS_OP_UNLOAD_RESOURCE, WINED3D_CS_OP_MAP, WINED3D_CS_OP_UNMAP, + WINED3D_CS_OP_MAP_BO_ADDRESS, WINED3D_CS_OP_BLT_SUB_RESOURCE, WINED3D_CS_OP_UPDATE_SUB_RESOURCE, WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION, @@ -454,6 +455,14 @@ struct wined3d_cs_unmap HRESULT *hr; };
+struct wined3d_cs_map_bo_address +{ + enum wined3d_cs_op opcode; + struct wined3d_bo_address addr; + size_t size; + uint32_t flags; +}; + struct wined3d_cs_blt_sub_resource { enum wined3d_cs_op opcode; @@ -594,6 +603,7 @@ static const char *debug_cs_op(enum wined3d_cs_op op) WINED3D_TO_STR(WINED3D_CS_OP_UNLOAD_RESOURCE); WINED3D_TO_STR(WINED3D_CS_OP_MAP); WINED3D_TO_STR(WINED3D_CS_OP_UNMAP); + WINED3D_TO_STR(WINED3D_CS_OP_MAP_BO_ADDRESS); WINED3D_TO_STR(WINED3D_CS_OP_BLT_SUB_RESOURCE); WINED3D_TO_STR(WINED3D_CS_OP_UPDATE_SUB_RESOURCE); WINED3D_TO_STR(WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION); @@ -2550,6 +2560,31 @@ HRESULT wined3d_device_context_emit_unmap(struct wined3d_device_context *context return hr; }
+static void wined3d_cs_exec_map_bo_address(struct wined3d_cs *cs, const void *data) +{ + const struct wined3d_cs_map_bo_address *op = data; + struct wined3d_context *context; + + context = context_acquire(cs->c.device, NULL, 0); + wined3d_context_map_bo_address(context, &op->addr, op->size, op->flags); + context_release(context); +} + +void wined3d_cs_map_bo_address(struct wined3d_cs *cs, + struct wined3d_bo_address *addr, size_t size, unsigned int flags) +{ + struct wined3d_device_context *context = &cs->c; + struct wined3d_cs_map_bo_address *op; + + op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_MAP); + op->opcode = WINED3D_CS_OP_MAP_BO_ADDRESS; + op->addr = *addr; + op->size = size; + op->flags = flags; + wined3d_device_context_submit(context, WINED3D_CS_QUEUE_MAP); + wined3d_device_context_finish(context, WINED3D_CS_QUEUE_MAP); +} + static void wined3d_cs_exec_blt_sub_resource(struct wined3d_cs *cs, const void *data) { const struct wined3d_cs_blt_sub_resource *op = data; @@ -2968,6 +3003,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void /* WINED3D_CS_OP_UNLOAD_RESOURCE */ wined3d_cs_exec_unload_resource, /* WINED3D_CS_OP_MAP */ wined3d_cs_exec_map, /* WINED3D_CS_OP_UNMAP */ wined3d_cs_exec_unmap, + /* WINED3D_CS_OP_MAP_BO_ADDRESS */ wined3d_cs_exec_map_bo_address, /* WINED3D_CS_OP_BLT_SUB_RESOURCE */ wined3d_cs_exec_blt_sub_resource, /* WINED3D_CS_OP_UPDATE_SUB_RESOURCE */ wined3d_cs_exec_update_sub_resource, /* WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION */ wined3d_cs_exec_add_dirty_texture_region, diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index e190fc4285e..eff42be3aa6 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -5034,6 +5034,8 @@ void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource) DECLSPEC_HIDDEN; void wined3d_cs_init_object(struct wined3d_cs *cs, void (*callback)(void *object), void *object) DECLSPEC_HIDDEN; +void wined3d_cs_map_bo_address(struct wined3d_cs *cs, + struct wined3d_bo_address *addr, size_t size, unsigned int flags) DECLSPEC_HIDDEN;
static inline void wined3d_cs_finish(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id) { @@ -5217,6 +5219,8 @@ static inline const struct wined3d_buffer_gl *wined3d_buffer_gl_const(const stru return CONTAINING_RECORD(buffer, struct wined3d_buffer_gl, b); }
+GLenum wined3d_buffer_gl_binding_from_bind_flags(const struct wined3d_gl_info *gl_info, + uint32_t bind_flags) DECLSPEC_HIDDEN; HRESULT wined3d_buffer_gl_init(struct wined3d_buffer_gl *buffer_gl, struct wined3d_device *device, const struct wined3d_buffer_desc *desc, const struct wined3d_sub_resource_data *data, void *parent, const struct wined3d_parent_ops *parent_ops) DECLSPEC_HIDDEN;
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wined3d/adapter_gl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c index cb0c34823aa..4e93e25452d 100644 --- a/dlls/wined3d/adapter_gl.c +++ b/dlls/wined3d/adapter_gl.c @@ -4646,6 +4646,18 @@ static bool adapter_gl_alloc_bo(struct wined3d_device *device, struct wined3d_re return false; }
+ if (bo_gl->memory) + { + struct wined3d_allocator_chunk_gl *chunk = wined3d_allocator_chunk_gl(bo_gl->memory->chunk); + + wined3d_allocator_chunk_gl_lock(chunk); + + if ((bo_gl->b.map_ptr = chunk->c.map_ptr)) + ++chunk->c.map_count; + + wined3d_allocator_chunk_gl_unlock(chunk); + } + addr->buffer_object = &bo_gl->b; addr->addr = NULL;
For the purposes of wined3d_cs_map_upload_bo().
That is, if a buffer was just created or just discarded [e.g. with wined3d_device_evict_managed_resources()], and then subsequently mapped with WINED3D_MAP_NOOVERWRITE, treat it as if it had been mapped with WINED3D_MAP_DISCARD instead, thus allowing the adapter_alloc_upload_bo callback to allocate a new buffer from the client thread.
This was the source of a bunch of stalls in Grand Theft Auto V, although it's hard to measure a difference in performance.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wined3d/buffer.c | 3 +++ dlls/wined3d/cs.c | 13 ++++++++++++- dlls/wined3d/wined3d_private.h | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c index 16308a098e3..63afa01bb2e 100644 --- a/dlls/wined3d/buffer.c +++ b/dlls/wined3d/buffer.c @@ -1321,6 +1321,9 @@ static HRESULT wined3d_buffer_init(struct wined3d_buffer *buffer, struct wined3d } buffer->maps_size = 1;
+ if (buffer->locations & WINED3D_LOCATION_DISCARDED) + buffer->resource.client.addr.buffer_object = CLIENT_BO_DISCARDED; + if (data) wined3d_buffer_init_data(buffer, device, data);
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index af3ee9e7624..ae1f4ad18e0 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -69,6 +69,14 @@ struct wined3d_command_list struct wined3d_deferred_query_issue *queries; };
+static void discard_client_address(struct wined3d_resource *resource) +{ + struct wined3d_client_resource *client = &resource->client; + + client->addr.buffer_object = CLIENT_BO_DISCARDED; + client->addr.addr = NULL; +} + static void invalidate_client_address(struct wined3d_resource *resource) { struct wined3d_client_resource *client = &resource->client; @@ -2432,7 +2440,7 @@ void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resou { struct wined3d_cs_unload_resource *op;
- invalidate_client_address(resource); + discard_client_address(resource);
op = wined3d_device_context_require_space(&cs->c, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT); op->opcode = WINED3D_CS_OP_UNLOAD_RESOURCE; @@ -3136,6 +3144,9 @@ static bool wined3d_cs_map_upload_bo(struct wined3d_device_context *context, str return NULL; }
+ if ((flags & WINED3D_MAP_NOOVERWRITE) && client->addr.buffer_object == CLIENT_BO_DISCARDED) + flags = (flags & ~WINED3D_MAP_NOOVERWRITE) | WINED3D_MAP_DISCARD; + if (flags & WINED3D_MAP_DISCARD) { if (!device->adapter->adapter_ops->adapter_alloc_bo(device, resource, sub_resource_idx, &addr)) diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index eff42be3aa6..989fd33d2bf 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -4276,6 +4276,8 @@ static inline ULONG wined3d_atomic_decrement_mutex_lock(volatile LONG *refcount) return count - 1; }
+#define CLIENT_BO_DISCARDED ((struct wined3d_bo *)~(UINT_PTR)0) + struct wined3d_client_resource { /* The resource's persistently mapped address, which we may use to perform
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com