d3d9 does not do instancing for not-indexed draw calls on Windows
Original issue in DXVK repo: https://github.com/doitsujin/dxvk/issues/3157
From: Illia Polishchuk illia.a.polishchuk@globallogic.com
d3d9 does not do instancing for not-indexed draw calls on Windows --- dlls/d3d9/tests/visual.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index 230f7deabb2..8132007a3d0 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -13090,6 +13090,35 @@ static void stream_test(void) hr = IDirect3DDevice9_SetStreamSource(device, act.strInstance, vb3, 0, sizeof(instancepos[0])); ok(SUCCEEDED(hr), "Failed to set stream source, hr %#lx.\n", hr);
+ /* Not indexed draw test. Instancing should not happen */ + hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLELIST, 0, 1); + ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr); + + hr = IDirect3DDevice9_EndScene(device); + ok(SUCCEEDED(hr), "Failed to end scene, hr %#lx.\n", hr); + + /* Check that only single triangle without instansing has beed drawed with not-indexed draw + * Instancing should happens only with indexed draws for d3d9 */ + color = getPixelColor(device, 200, 340); + ok(color == act.color1, "has color 0x%08x, expected 0x%08x (case %i)\n", color, act.color1, i); + color = getPixelColor(device, 400, 340); + ok(color == 0x00ffffff, "has color 0x%08x, expected 0x%08x (case %i)\n", color, 0x00ffffff, i); + color = getPixelColor(device, 400, 180); + ok(color == 0x00ffffff, "has color 0x%08x, expected 0x%08x (case %i)\n", color, 0x00ffffff, i); + color = getPixelColor(device, 200, 180); + ok(color == 0x00ffffff, "has color 0x%08x, expected 0x%08x (case %i)\n", color, 0x00ffffff, i); + + + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IDirect3DDevice9_BeginScene(device); + ok(SUCCEEDED(hr), "Failed to begin scene, hr %#lx.\n", hr); + + /* Indexed draw test. Instancing should happen */ hr = IDirect3DDevice9_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, 0, 0, 4, 0, 2); ok(SUCCEEDED(hr), "Failed to draw, hr %#lx.\n", hr); hr = IDirect3DDevice9_EndScene(device); @@ -13120,7 +13149,7 @@ static void stream_test(void) ok(color == act.color3, "has color 0x%08x, expected 0x%08x (case %i)\n", color, act.color3, i); color = getPixelColor(device, 160, 120); ok(color == act.color4, "has color 0x%08x, expected 0x%08x (case %i)\n", color, act.color4, i); - + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); ok(hr == S_OK, "Got hr %#lx.\n", hr); }
From: Illia Polishchuk illia.a.polishchuk@globallogic.com
d3d9 does not do instancing for not-indexed draw calls
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54570 --- dlls/d3d9/device.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index eddb2a0ebdd..8aba3288513 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -3033,7 +3033,9 @@ static HRESULT WINAPI d3d9_device_DrawPrimitive(IDirect3DDevice9Ex *iface, D3DPRIMITIVETYPE primitive_type, UINT start_vertex, UINT primitive_count) { struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface); + const struct wined3d_stateblock_state *state; unsigned int vertex_count; + UINT saved_flags, saved_freq;
TRACE("iface %p, primitive_type %#x, start_vertex %u, primitive_count %u.\n", iface, primitive_type, start_vertex, primitive_count); @@ -3045,6 +3047,17 @@ static HRESULT WINAPI d3d9_device_DrawPrimitive(IDirect3DDevice9Ex *iface, WARN("Called without a valid vertex declaration set.\n"); return D3DERR_INVALIDCALL; } + + /* Windows D3D9 does not do non-indexed instanced draws. + * Set instance count to 1 for the not indexed draw */ + state = wined3d_stateblock_get_state(device->state); + saved_freq = state->streams[0].frequency; + if(saved_freq > 1) + { + saved_flags = state->streams[0].flags; + wined3d_stateblock_set_stream_source_freq(device->update_state, 0, saved_flags | 1); + } + wined3d_device_apply_stateblock(device->wined3d_device, device->state); vertex_count = vertex_count_from_primitive_count(primitive_type, primitive_count); d3d9_device_upload_managed_textures(device); @@ -3053,6 +3066,11 @@ static HRESULT WINAPI d3d9_device_DrawPrimitive(IDirect3DDevice9Ex *iface, wined3d_device_context_set_primitive_type(device->immediate_context, wined3d_primitive_type_from_d3d(primitive_type), 0); wined3d_device_context_draw(device->immediate_context, start_vertex, vertex_count, 0, 0); + + /* Restore instance count to previous value */ + if(saved_freq > 1) + wined3d_stateblock_set_stream_source_freq(device->update_state, 0, saved_flags | saved_freq); + d3d9_rts_flag_auto_gen_mipmap(device); wined3d_mutex_unlock();
@@ -3103,8 +3121,10 @@ static HRESULT WINAPI d3d9_device_DrawPrimitiveUP(IDirect3DDevice9Ex *iface, D3DPRIMITIVETYPE primitive_type, UINT primitive_count, const void *data, UINT stride) { struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface); + const struct wined3d_stateblock_state *state; UINT vtx_count = vertex_count_from_primitive_count(primitive_type, primitive_count); UINT size = vtx_count * stride; + UINT saved_flags, saved_freq; unsigned int vb_pos; HRESULT hr;
@@ -3143,8 +3163,24 @@ static HRESULT WINAPI d3d9_device_DrawPrimitiveUP(IDirect3DDevice9Ex *iface, d3d9_device_upload_managed_textures(device); wined3d_device_context_set_primitive_type(device->immediate_context, wined3d_primitive_type_from_d3d(primitive_type), 0); + + /* Windows D3D9 does not do non-indexed instanced draws. + * Set instance count to 1 for the not indexed draw */ + state = wined3d_stateblock_get_state(device->state); + saved_freq = state->streams[0].frequency; + if(saved_freq > 1) + { + saved_flags = state->streams[0].flags; + wined3d_stateblock_set_stream_source_freq(device->update_state, 0, saved_flags | 1); + } + wined3d_device_apply_stateblock(device->wined3d_device, device->state); wined3d_device_context_draw(device->immediate_context, vb_pos / stride, vtx_count, 0, 0); + + /* Restore instance count to previous value */ + if(saved_freq > 1) + wined3d_stateblock_set_stream_source_freq(device->update_state, 0, saved_flags | saved_freq); + wined3d_stateblock_set_stream_source(device->state, 0, NULL, 0, 0); d3d9_rts_flag_auto_gen_mipmap(device);
Also updated d3d9 unit test with this case and verified that it works on both Linux and Windows