From 379ae701c04046661a092cacd7263ca97101f51b Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Thu, 22 Dec 2022 12:33:15 -0600 Subject: [PATCH] d3d8: Filter out redundant buffer discards. I was unable to write tests for this; it seems it doesn't consistently work on Windows. However, Rayman 3 seems to rely on it; it maps the same buffer twice immediately after creation, with DISCARD flags on both maps, and expects the same address to be returned. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53752 --- dlls/d3d8/buffer.c | 10 ++++++++++ dlls/d3d8/d3d8_private.h | 2 ++ dlls/d3d8/device.c | 28 ++++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/dlls/d3d8/buffer.c b/dlls/d3d8/buffer.c index 2b0f0a41888..23dcf05044c 100644 --- a/dlls/d3d8/buffer.c +++ b/dlls/d3d8/buffer.c @@ -192,6 +192,11 @@ static HRESULT WINAPI d3d8_vertexbuffer_Lock(IDirect3DVertexBuffer8 *iface, UINT TRACE("iface %p, offset %u, size %u, data %p, flags %#lx.\n", iface, offset, size, data, flags); + if (buffer->discarded) + flags &= ~D3DLOCK_DISCARD; + if (flags & D3DLOCK_DISCARD) + buffer->discarded = true; + wined3d_box.left = offset; wined3d_box.right = offset + size; wined3d_resource = wined3d_buffer_get_resource(buffer->wined3d_buffer); @@ -508,6 +513,11 @@ static HRESULT WINAPI d3d8_indexbuffer_Lock(IDirect3DIndexBuffer8 *iface, UINT o TRACE("iface %p, offset %u, size %u, data %p, flags %#lx.\n", iface, offset, size, data, flags); + if (buffer->discarded) + flags &= ~D3DLOCK_DISCARD; + if (flags & D3DLOCK_DISCARD) + buffer->discarded = true; + wined3d_box.left = offset; wined3d_box.right = offset + size; wined3d_resource = wined3d_buffer_get_resource(buffer->wined3d_buffer); diff --git a/dlls/d3d8/d3d8_private.h b/dlls/d3d8/d3d8_private.h index 340f4f2d07d..dda85062dea 100644 --- a/dlls/d3d8/d3d8_private.h +++ b/dlls/d3d8/d3d8_private.h @@ -217,6 +217,7 @@ struct d3d8_vertexbuffer IDirect3DDevice8 *parent_device; struct wined3d_buffer *draw_buffer; DWORD fvf, usage; + bool discarded; }; HRESULT vertexbuffer_init(struct d3d8_vertexbuffer *buffer, struct d3d8_device *device, @@ -232,6 +233,7 @@ struct d3d8_indexbuffer enum wined3d_format_id format; DWORD usage; bool sysmem; + bool discarded; }; HRESULT indexbuffer_init(struct d3d8_indexbuffer *buffer, struct d3d8_device *device, diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index fb7e25a6bc1..539dd7a89b9 100644 --- a/dlls/d3d8/device.c +++ b/dlls/d3d8/device.c @@ -2516,7 +2516,8 @@ static HRESULT WINAPI d3d8_device_DrawPrimitive(IDirect3DDevice8 *iface, D3DPRIMITIVETYPE primitive_type, UINT start_vertex, UINT primitive_count) { struct d3d8_device *device = impl_from_IDirect3DDevice8(iface); - unsigned int vertex_count; + struct d3d8_vertexbuffer *vb; + unsigned int vertex_count, i; TRACE("iface %p, primitive_type %#x, start_vertex %u, primitive_count %u.\n", iface, primitive_type, start_vertex, primitive_count); @@ -2529,6 +2530,16 @@ static HRESULT WINAPI d3d8_device_DrawPrimitive(IDirect3DDevice8 *iface, wined3d_primitive_type_from_d3d(primitive_type), 0); wined3d_device_apply_stateblock(device->wined3d_device, device->state); wined3d_device_context_draw(device->immediate_context, start_vertex, vertex_count, 0, 0); + + for (i = 0; i < ARRAY_SIZE(device->stateblock_state->streams); ++i) + { + if (device->stateblock_state->streams[i].buffer) + { + vb = wined3d_buffer_get_parent(device->stateblock_state->streams[i].buffer); + vb->discarded = false; + } + } + wined3d_mutex_unlock(); return D3D_OK; @@ -2539,7 +2550,9 @@ static HRESULT WINAPI d3d8_device_DrawIndexedPrimitive(IDirect3DDevice8 *iface, UINT start_idx, UINT primitive_count) { struct d3d8_device *device = impl_from_IDirect3DDevice8(iface); - unsigned int index_count; + struct d3d8_vertexbuffer *vb; + struct d3d8_indexbuffer *ib; + unsigned int index_count, i; int base_vertex_index; HRESULT hr; @@ -2567,6 +2580,17 @@ static HRESULT WINAPI d3d8_device_DrawIndexedPrimitive(IDirect3DDevice8 *iface, } wined3d_device_context_draw_indexed(device->immediate_context, base_vertex_index, start_idx, index_count, 0, 0); + ib = wined3d_buffer_get_parent(device->stateblock_state->index_buffer); + ib->discarded = false; + for (i = 0; i < ARRAY_SIZE(device->stateblock_state->streams); ++i) + { + if (device->stateblock_state->streams[i].buffer) + { + vb = wined3d_buffer_get_parent(device->stateblock_state->streams[i].buffer); + vb->discarded = false; + } + } + wined3d_mutex_unlock(); return D3D_OK;