From d6805cde0e8f01e672f17fb03af947e7d2f83dde Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sun, 1 Oct 2017 04:43:22 +0200
Subject: [PATCH] d3d11: Implement restoring of state after executing a command
 list.

---
 dlls/d3d11/device.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 229 insertions(+), 4 deletions(-)

diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c
index 4f3700d..e214202 100644
--- a/dlls/d3d11/device.c
+++ b/dlls/d3d11/device.c
@@ -367,6 +367,62 @@ struct deferred_call
     };
 };
 
+/* Replace with D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT as soon as wined3d supports >= 32 streams */
+#define MAX_WINED3D_STREAMS 16
+
+struct d3d11_state
+{
+    ID3D11ShaderResourceView *vs_resources[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
+    ID3D11SamplerState *vs_samplers[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT];
+    ID3D11Buffer *vs_cbs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
+    ID3D11VertexShader *vs;
+
+    ID3D11ShaderResourceView *gs_resources[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
+    ID3D11SamplerState *gs_samplers[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT];
+    ID3D11Buffer *gs_cbs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
+    ID3D11GeometryShader *gs;
+
+    ID3D11ShaderResourceView *ps_resources[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
+    ID3D11SamplerState *ps_samplers[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT];
+    ID3D11Buffer *ps_cbs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
+    ID3D11PixelShader *ps;
+
+    ID3D11ShaderResourceView *hs_resources[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
+    ID3D11SamplerState *hs_samplers[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT];
+    ID3D11Buffer *hs_cbs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
+    ID3D11HullShader *hs;
+
+    ID3D11ShaderResourceView *ds_resources[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
+    ID3D11SamplerState *ds_samplers[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT];
+    ID3D11Buffer *ds_cbs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
+    ID3D11DomainShader *ds;
+
+    ID3D11Buffer *vbs[MAX_WINED3D_STREAMS];
+    UINT vb_strides[MAX_WINED3D_STREAMS];
+    UINT vb_offsets[MAX_WINED3D_STREAMS];
+    D3D11_PRIMITIVE_TOPOLOGY topology;
+    ID3D11InputLayout *il;
+    DXGI_FORMAT ib_format;
+    ID3D11Buffer *ib;
+    UINT ib_offset;
+
+    ID3D11RenderTargetView *rtvs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
+    ID3D11DepthStencilView *dsv;
+    ID3D11DepthStencilState *dss;
+    float blend_factor[4];
+    ID3D11BlendState *bs;
+    UINT stencil_ref;
+    UINT sample_mask;
+
+    D3D11_RECT scissor_rects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+    D3D11_VIEWPORT vps[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+    ID3D11Buffer *so_buffers[D3D11_SO_BUFFER_SLOT_COUNT];
+    UINT so_offsets[D3D11_SO_BUFFER_SLOT_COUNT];
+    ID3D11Predicate *predicate;
+    ID3D11RasterizerState *rs;
+    BOOL predicate_value;
+};
+
 /* ID3D11CommandList - command list */
 struct d3d11_command_list
 {
@@ -2513,22 +2569,191 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_ResolveSubresource(ID3D11D
     wined3d_mutex_unlock();
 }
 
+static struct d3d11_state *state_capture(ID3D11DeviceContext1 *context)
+{
+    struct d3d_device *device = device_from_immediate_ID3D11DeviceContext1(context);
+    unsigned int vp_count = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+    struct d3d11_state *stateblock;
+    int i;
+
+    if (!(stateblock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*stateblock))))
+        return NULL;
+
+    ID3D11DeviceContext1_VSGetShader(context, &stateblock->vs, NULL, 0);
+    ID3D11DeviceContext1_VSGetSamplers(context, 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, stateblock->vs_samplers);
+    ID3D11DeviceContext1_VSGetShaderResources(context, 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, stateblock->vs_resources);
+    ID3D11DeviceContext1_VSGetConstantBuffers(context, 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, stateblock->vs_cbs);
+
+    ID3D11DeviceContext1_GSGetShader(context, &stateblock->gs, NULL, 0);
+    ID3D11DeviceContext1_GSGetSamplers(context, 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, stateblock->gs_samplers);
+    ID3D11DeviceContext1_GSGetShaderResources(context, 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, stateblock->gs_resources);
+    ID3D11DeviceContext1_GSGetConstantBuffers(context, 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, stateblock->gs_cbs);
+
+    ID3D11DeviceContext1_PSGetShader(context, &stateblock->ps, NULL, 0);
+    ID3D11DeviceContext1_PSGetSamplers(context, 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, stateblock->ps_samplers);
+    ID3D11DeviceContext1_PSGetShaderResources(context, 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, stateblock->ps_resources);
+    ID3D11DeviceContext1_PSGetConstantBuffers(context, 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, stateblock->ps_cbs);
+
+    ID3D11DeviceContext1_HSGetShader(context, &stateblock->hs, NULL, 0);
+    ID3D11DeviceContext1_HSGetSamplers(context, 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, stateblock->hs_samplers);
+    ID3D11DeviceContext1_HSGetShaderResources(context, 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, stateblock->hs_resources);
+    ID3D11DeviceContext1_HSGetConstantBuffers(context, 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, stateblock->hs_cbs);
+
+    ID3D11DeviceContext1_DSGetShader(context, &stateblock->ds, NULL, 0);
+    ID3D11DeviceContext1_DSGetSamplers(context, 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, stateblock->ds_samplers);
+    ID3D11DeviceContext1_DSGetShaderResources(context, 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, stateblock->ds_resources);
+    ID3D11DeviceContext1_DSGetConstantBuffers(context, 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, stateblock->ds_cbs);
+
+    ID3D11DeviceContext1_IAGetVertexBuffers(context, 0, MAX_WINED3D_STREAMS, stateblock->vbs, stateblock->vb_strides, stateblock->vb_offsets);
+    ID3D11DeviceContext1_IAGetIndexBuffer(context, &stateblock->ib, &stateblock->ib_format, &stateblock->ib_offset);
+    ID3D11DeviceContext1_IAGetInputLayout(context, &stateblock->il);
+    ID3D11DeviceContext1_IAGetPrimitiveTopology(context, &stateblock->topology);
+
+    ID3D11DeviceContext1_OMGetRenderTargets(context, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, stateblock->rtvs, &stateblock->dsv);
+    ID3D11DeviceContext1_OMGetDepthStencilState(context, &stateblock->dss, &stateblock->stencil_ref);
+    ID3D11DeviceContext1_OMGetBlendState(context, &stateblock->bs, stateblock->blend_factor, &stateblock->sample_mask);
+
+    ID3D11DeviceContext1_RSGetViewports(context, &vp_count, stateblock->vps);
+    ID3D11DeviceContext1_RSGetScissorRects(context, &vp_count, stateblock->scissor_rects);
+    ID3D11DeviceContext1_RSGetState(context, &stateblock->rs);
+
+    ID3D11DeviceContext1_SOGetTargets(context, D3D11_SO_BUFFER_SLOT_COUNT, stateblock->so_buffers);
+    /* For some reason the d3d11 get function is missing the offset parameter */
+    for (i = 0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++)
+        wined3d_device_get_stream_output(device->wined3d_device, i, &stateblock->so_offsets[i]);
+
+    ID3D11DeviceContext1_GetPredication(context, &stateblock->predicate, &stateblock->predicate_value);
+
+    return stateblock;
+}
+
+static void state_apply(ID3D11DeviceContext1 *context, struct d3d11_state *stateblock)
+{
+    static DWORD warn_once;
+    int i;
+
+    if (!stateblock)
+        return;
+
+    if (!warn_once++) FIXME("restoring state is potentially slow and incomplete!\n");
+
+    ID3D11DeviceContext1_VSSetShader(context, stateblock->vs, NULL, 0);
+    ID3D11DeviceContext1_VSSetSamplers(context, 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, stateblock->vs_samplers);
+    ID3D11DeviceContext1_VSSetShaderResources(context, 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, stateblock->vs_resources);
+    ID3D11DeviceContext1_VSSetConstantBuffers(context, 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, stateblock->vs_cbs);
+
+    if (stateblock->vs) ID3D11VertexShader_Release(stateblock->vs);
+    for (i = 0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; i++)
+        if (stateblock->vs_samplers[i]) ID3D11SamplerState_Release(stateblock->vs_samplers[i]);
+    for (i = 0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++)
+        if (stateblock->vs_resources[i]) ID3D11ShaderResourceView_Release(stateblock->vs_resources[i]);
+    for (i = 0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++)
+        if (stateblock->vs_cbs[i]) ID3D11Buffer_Release(stateblock->vs_cbs[i]);
+
+    ID3D11DeviceContext1_GSSetShader(context, stateblock->gs, NULL, 0);
+    ID3D11DeviceContext1_GSSetSamplers(context, 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, stateblock->gs_samplers);
+    ID3D11DeviceContext1_GSSetShaderResources(context, 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, stateblock->gs_resources);
+    ID3D11DeviceContext1_GSSetConstantBuffers(context, 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, stateblock->gs_cbs);
+
+    if (stateblock->gs) ID3D11GeometryShader_Release(stateblock->gs);
+    for (i = 0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; i++)
+        if (stateblock->gs_samplers[i]) ID3D11SamplerState_Release(stateblock->gs_samplers[i]);
+    for (i = 0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++)
+        if (stateblock->gs_resources[i]) ID3D11ShaderResourceView_Release(stateblock->gs_resources[i]);
+    for (i = 0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++)
+        if (stateblock->gs_cbs[i]) ID3D11Buffer_Release(stateblock->gs_cbs[i]);
+
+    ID3D11DeviceContext1_PSSetShader(context, stateblock->ps, NULL, 0);
+    ID3D11DeviceContext1_PSSetSamplers(context, 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, stateblock->ps_samplers);
+    ID3D11DeviceContext1_PSSetShaderResources(context, 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, stateblock->ps_resources);
+    ID3D11DeviceContext1_PSSetConstantBuffers(context, 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, stateblock->ps_cbs);
+
+    if (stateblock->ps) ID3D11PixelShader_Release(stateblock->ps);
+    for (i = 0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; i++)
+        if (stateblock->ps_samplers[i]) ID3D11SamplerState_Release(stateblock->ps_samplers[i]);
+    for (i = 0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++)
+        if (stateblock->ps_resources[i]) ID3D11ShaderResourceView_Release(stateblock->ps_resources[i]);
+    for (i = 0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++)
+        if (stateblock->ps_cbs[i]) ID3D11Buffer_Release(stateblock->ps_cbs[i]);
+
+    ID3D11DeviceContext1_HSSetShader(context, stateblock->hs, NULL, 0);
+    ID3D11DeviceContext1_HSSetSamplers(context, 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, stateblock->hs_samplers);
+    ID3D11DeviceContext1_HSSetShaderResources(context, 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, stateblock->hs_resources);
+    ID3D11DeviceContext1_HSSetConstantBuffers(context, 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, stateblock->hs_cbs);
+
+    if (stateblock->hs) ID3D11HullShader_Release(stateblock->hs);
+    for (i = 0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; i++)
+        if (stateblock->hs_samplers[i]) ID3D11SamplerState_Release(stateblock->hs_samplers[i]);
+    for (i = 0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++)
+        if (stateblock->hs_resources[i]) ID3D11ShaderResourceView_Release(stateblock->hs_resources[i]);
+    for (i = 0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++)
+        if (stateblock->hs_cbs[i]) ID3D11Buffer_Release(stateblock->hs_cbs[i]);
+
+    ID3D11DeviceContext1_DSSetShader(context, stateblock->ds, NULL, 0);
+    ID3D11DeviceContext1_DSSetSamplers(context, 0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, stateblock->ds_samplers);
+    ID3D11DeviceContext1_DSSetShaderResources(context, 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, stateblock->ds_resources);
+    ID3D11DeviceContext1_DSSetConstantBuffers(context, 0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, stateblock->ds_cbs);
+
+    if (stateblock->ds) ID3D11DomainShader_Release(stateblock->ds);
+    for (i = 0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; i++)
+        if (stateblock->ds_samplers[i]) ID3D11SamplerState_Release(stateblock->ds_samplers[i]);
+    for (i = 0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++)
+        if (stateblock->ds_resources[i]) ID3D11ShaderResourceView_Release(stateblock->ds_resources[i]);
+    for (i = 0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++)
+        if (stateblock->ds_cbs[i]) ID3D11Buffer_Release(stateblock->ds_cbs[i]);
+
+    ID3D11DeviceContext1_IASetVertexBuffers(context, 0, MAX_WINED3D_STREAMS, stateblock->vbs, stateblock->vb_strides, stateblock->vb_offsets);
+    ID3D11DeviceContext1_IASetIndexBuffer(context, stateblock->ib, stateblock->ib_format, stateblock->ib_offset);
+    ID3D11DeviceContext1_IASetInputLayout(context, stateblock->il);
+    ID3D11DeviceContext1_IASetPrimitiveTopology(context, stateblock->topology);
+
+    for (i = 0; i < MAX_WINED3D_STREAMS; i++)
+        if (stateblock->vbs[i]) ID3D11Buffer_Release(stateblock->vbs[i]);
+    if (stateblock->ib) ID3D11Buffer_Release(stateblock->ib);
+    if (stateblock->il) ID3D11InputLayout_Release(stateblock->il);
+
+    ID3D11DeviceContext1_OMSetRenderTargets(context, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, stateblock->rtvs, stateblock->dsv);
+    ID3D11DeviceContext1_OMSetDepthStencilState(context, stateblock->dss, stateblock->stencil_ref);
+    ID3D11DeviceContext1_OMSetBlendState(context, stateblock->bs, stateblock->blend_factor, stateblock->sample_mask);
+
+    for (i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
+        if (stateblock->rtvs[i]) ID3D11RenderTargetView_Release(stateblock->rtvs[i]);
+    if (stateblock->dsv) ID3D11DepthStencilView_Release(stateblock->dsv);
+    if (stateblock->dss) ID3D11DepthStencilState_Release(stateblock->dss);
+    if (stateblock->bs)  ID3D11BlendState_Release(stateblock->bs);
+
+    ID3D11DeviceContext1_RSSetViewports(context, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE, stateblock->vps);
+    ID3D11DeviceContext1_RSSetScissorRects(context, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE, stateblock->scissor_rects);
+    ID3D11DeviceContext1_RSSetState(context, stateblock->rs);
+
+    if (stateblock->rs) ID3D11RasterizerState_Release(stateblock->rs);
+
+    ID3D11DeviceContext1_SOSetTargets(context, D3D11_SO_BUFFER_SLOT_COUNT, stateblock->so_buffers, stateblock->so_offsets);
+    ID3D11DeviceContext1_SetPredication(context, stateblock->predicate, stateblock->predicate_value);
+
+    for (i = 0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++)
+        if (stateblock->so_buffers[i]) ID3D11Buffer_Release(stateblock->so_buffers[i]);
+    if (stateblock->predicate) ID3D11Predicate_Release(stateblock->predicate);
+
+    HeapFree(GetProcessHeap(), 0, stateblock);
+}
+
 static void STDMETHODCALLTYPE d3d11_immediate_context_ExecuteCommandList(ID3D11DeviceContext1 *iface,
         ID3D11CommandList *command_list, BOOL restore_state)
 {
     struct d3d11_command_list *cmdlist = unsafe_impl_from_ID3D11CommandList(command_list);
+    struct d3d11_state *stateblock = NULL;
 
     TRACE("iface %p, command_list %p, restore_state %#x.\n", iface, command_list, restore_state);
 
     if (!cmdlist)
         return;
 
-    if (restore_state)
-        FIXME("restoring state not supported!\n");
-
     wined3d_mutex_lock();
+    if (restore_state) stateblock = state_capture(iface);
     exec_deferred_calls(iface, &cmdlist->commands);
-    ID3D11DeviceContext1_ClearState(iface);
+    if (restore_state) state_apply(iface, stateblock);
+    else ID3D11DeviceContext1_ClearState(iface);
     wined3d_mutex_unlock();
 }
 
-- 
1.9.1

