From f434bd7d3f12b51ce79bff02a032b7774c7279a9 Mon Sep 17 00:00:00 2001 From: Yuriy O'Donnell Date: Thu, 5 Jun 2014 13:58:36 +0200 Subject: [PATCH 1/7] D3D: Implemented cache for dynamic render states --- Source/Core/VideoBackends/D3D/Render.cpp | 584 +++++++++++++++-------- 1 file changed, 383 insertions(+), 201 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 56a47310c7..eeca80e3a2 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "Common/Timer.h" @@ -53,16 +54,355 @@ ID3D11RasterizerState* resetraststate = nullptr; static ID3D11Texture2D* s_screenshot_texture = nullptr; +union RasterizerState +{ + struct + { + u32 cull_mode : 2; + u32 wireframe : 1; + }; + + u32 packed; +}; + +union BlendState +{ + struct + { + u32 blend_enable : 1; + u32 blend_op : 3; + u32 write_mask : 4; + u32 src_blend : 5; + u32 dst_blend : 5; + u32 use_dst_alpha : 1; + }; + + u32 packed; +}; + +union SamplerState +{ + struct + { + u64 min_filter : 3; + u64 mag_filter : 1; + u64 min_lod : 8; + u64 max_lod : 8; + s64 lod_bias : 8; + u64 wrap_s : 2; + u64 wrap_t : 2; + u64 max_anisotropy : 5; + }; + + u64 packed; +}; // GX pipeline state struct { - D3D11_SAMPLER_DESC sampdc[8]; - D3D11_BLEND_DESC blenddc; - D3D11_DEPTH_STENCIL_DESC depthdc; - D3D11_RASTERIZER_DESC rastdc; + SamplerState sampler[8]; + BlendState blend; + ZMode zmode; + RasterizerState raster; + } gx_state; +class GXStateCache +{ +public: + + ID3D11SamplerState* Get(SamplerState state) + { + ID3D11SamplerState* res = nullptr; + + auto it = m_sampler.find(state.packed); + + if (it != m_sampler.end()) + { + res = it->second; + } + else + { + enum + { + TEXF_NONE = 0, + TEXF_POINT = 1, + TEXF_LINEAR = 2 + }; + + const unsigned int d3dMipFilters[4] = + { + TEXF_NONE, + TEXF_POINT, + TEXF_LINEAR, + TEXF_NONE, //reserved + }; + const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] = + { + D3D11_TEXTURE_ADDRESS_CLAMP, + D3D11_TEXTURE_ADDRESS_WRAP, + D3D11_TEXTURE_ADDRESS_MIRROR, + D3D11_TEXTURE_ADDRESS_WRAP //reserved + }; + + D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); + + unsigned int mip = d3dMipFilters[state.min_filter & 3]; + + if (state.max_anisotropy) + { + sampdc.Filter = D3D11_FILTER_ANISOTROPIC; + sampdc.MaxAnisotropy = state.max_anisotropy; + } + else if (state.min_filter & 4) // linear min filter + { + if (state.mag_filter) // linear mag filter + { + if (mip == TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + else if (mip == TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + else if (mip == TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + } + else // point mag filter + { + if (mip == TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; + else if (mip == TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; + else if (mip == TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; + } + } + else // point min filter + { + if (state.mag_filter) // linear mag filter + { + if (mip == TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; + else if (mip == TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; + else if (mip == TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR; + } + else // point mag filter + { + if (mip == TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + else if (mip == TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + else if (mip == TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; + } + } + + sampdc.AddressU = d3dClamps[state.wrap_s]; + sampdc.AddressV = d3dClamps[state.wrap_t]; + + sampdc.MaxLOD = (mip == TEXF_NONE) ? 0.0f : (float)state.max_lod / 16.f; + sampdc.MinLOD = (float)state.min_lod / 16.f; + sampdc.MipLODBias = (s32)state.lod_bias / 32.0f; + + HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res); + if (FAILED(hr)) PanicAlert("Fail %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "sampler state used to emulate the GX pipeline"); + m_sampler.insert(std::make_pair(state.packed, res)); + } + + return res; + } + + ID3D11BlendState* Get(BlendState state) + { + ID3D11BlendState* res = nullptr; + + auto it = m_blend.find(state.packed); + + if (it != m_blend.end()) + { + res = it->second; + } + else + { + D3D11_BLEND_DESC blenddc = CD3D11_BLEND_DESC(CD3D11_DEFAULT()); + + blenddc.AlphaToCoverageEnable = FALSE; + blenddc.IndependentBlendEnable = FALSE; + blenddc.RenderTarget[0].BlendEnable = state.blend_enable; + blenddc.RenderTarget[0].RenderTargetWriteMask = (D3D11_COLOR_WRITE_ENABLE)state.write_mask; + blenddc.RenderTarget[0].SrcBlend = (D3D11_BLEND)state.src_blend; + blenddc.RenderTarget[0].DestBlend = (D3D11_BLEND)state.dst_blend; + blenddc.RenderTarget[0].BlendOp = (D3D11_BLEND_OP)state.blend_op; + blenddc.RenderTarget[0].SrcBlendAlpha = (D3D11_BLEND)state.src_blend; + blenddc.RenderTarget[0].DestBlendAlpha = (D3D11_BLEND)state.dst_blend; + blenddc.RenderTarget[0].BlendOpAlpha = (D3D11_BLEND_OP)state.blend_op; + + if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_DEST_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_DEST_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; + else + blenddc.RenderTarget[0].SrcBlendAlpha = blenddc.RenderTarget[0].SrcBlend; + + if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_DEST_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_DEST_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; + else + blenddc.RenderTarget[0].DestBlendAlpha = blenddc.RenderTarget[0].DestBlend; + + if (state.use_dst_alpha) + { + // Colors should blend against SRC1_ALPHA + if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_ALPHA) + blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC1_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_ALPHA) + blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_SRC1_ALPHA; + + // Colors should blend against SRC1_ALPHA + if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_ALPHA) + blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_ALPHA) + blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC1_ALPHA; + + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blenddc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + } + + HRESULT hr = D3D::device->CreateBlendState(&blenddc, &res); + if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "blend state used to emulate the GX pipeline"); + m_blend.insert(std::make_pair(state.packed, res)); + } + + return res; + } + + ID3D11RasterizerState* Get(RasterizerState state) + { + ID3D11RasterizerState* res = nullptr; + + auto it = m_raster.find(state.packed); + + if (it != m_raster.end()) + { + res = it->second; + } + else + { + D3D11_RASTERIZER_DESC rastdc = CD3D11_RASTERIZER_DESC(state.wireframe ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID, + (D3D11_CULL_MODE)state.cull_mode, + false, 0, 0.f, 0, false, true, false, false); + + HRESULT hr = D3D::device->CreateRasterizerState(&rastdc, &res); + if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "rasterizer state used to emulate the GX pipeline"); + m_raster.insert(std::make_pair(state.packed, res)); + } + + return res; + } + + ID3D11DepthStencilState* Get(ZMode state) + { + ID3D11DepthStencilState* res = nullptr; + + auto it = m_depth.find(state.hex); + if (it != m_depth.end()) + { + res = it->second; + } + else + { + D3D11_DEPTH_STENCIL_DESC depthdc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); + + depthdc.DepthEnable = TRUE; + depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthdc.DepthFunc = D3D11_COMPARISON_LESS; + depthdc.StencilEnable = FALSE; + depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + + const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] = + { + D3D11_COMPARISON_NEVER, + D3D11_COMPARISON_LESS, + D3D11_COMPARISON_EQUAL, + D3D11_COMPARISON_LESS_EQUAL, + D3D11_COMPARISON_GREATER, + D3D11_COMPARISON_NOT_EQUAL, + D3D11_COMPARISON_GREATER_EQUAL, + D3D11_COMPARISON_ALWAYS + }; + + if (state.testenable) + { + depthdc.DepthEnable = TRUE; + depthdc.DepthWriteMask = state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + depthdc.DepthFunc = d3dCmpFuncs[state.func]; + } + else + { + // if the test is disabled write is disabled too + depthdc.DepthEnable = FALSE; + depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + } + + HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res); + if (SUCCEEDED(hr)) D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "depth-stencil state used to emulate the GX pipeline"); + else PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); + + m_depth.insert(std::make_pair(state.hex, res)); + } + + return res; + } + + void Clear() + { + for (auto it : m_depth) + { + SAFE_RELEASE(it.second); + } + m_depth.clear(); + + for (auto it : m_raster) + { + SAFE_RELEASE(it.second); + } + m_raster.clear(); + + for (auto it : m_blend) + { + SAFE_RELEASE(it.second); + } + m_blend.clear(); + + for (auto it : m_sampler) + { + SAFE_RELEASE(it.second); + } + m_sampler.clear(); + } + +private: + + std::unordered_map m_depth; + std::unordered_map m_raster; + std::unordered_map m_blend; + std::unordered_map m_sampler; + +} gx_state_cache; void SetupDeviceObjects() { @@ -167,6 +507,8 @@ void TeardownDeviceObjects() SAFE_RELEASE(s_screenshot_texture); s_television.Shutdown(); + + gx_state_cache.Clear(); } void CreateScreenshotTexture(const TargetRectangle& rc) @@ -198,37 +540,17 @@ Renderer::Renderer(void *&window_handle) // Setup GX pipeline state - memset(&gx_state.blenddc, 0, sizeof(gx_state.blenddc)); - gx_state.blenddc.AlphaToCoverageEnable = FALSE; - gx_state.blenddc.IndependentBlendEnable = FALSE; - gx_state.blenddc.RenderTarget[0].BlendEnable = FALSE; - gx_state.blenddc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - gx_state.blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; - gx_state.blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; - gx_state.blenddc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - gx_state.blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - gx_state.blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - gx_state.blenddc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - - memset(&gx_state.depthdc, 0, sizeof(gx_state.depthdc)); - gx_state.depthdc.DepthEnable = TRUE; - gx_state.depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - gx_state.depthdc.DepthFunc = D3D11_COMPARISON_LESS; - gx_state.depthdc.StencilEnable = FALSE; - gx_state.depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - gx_state.depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - - // TODO: Do we need to enable multisampling here? - gx_state.rastdc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0, false, true, false, false); + gx_state.blend.blend_enable = false; + gx_state.blend.write_mask = D3D11_COLOR_WRITE_ENABLE_ALL; + gx_state.blend.src_blend = D3D11_BLEND_ONE; + gx_state.blend.dst_blend = D3D11_BLEND_ZERO; + gx_state.blend.blend_op = D3D11_BLEND_OP_ADD; + gx_state.blend.use_dst_alpha = false; for (unsigned int k = 0;k < 8;k++) { float border[4] = {0.f, 0.f, 0.f, 0.f}; - gx_state.sampdc[k] = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_CLAMP, - 0.f, 1 << g_ActiveConfig.iMaxAnisotropy, - D3D11_COMPARISON_ALWAYS, border, - -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX); - if (g_ActiveConfig.iMaxAnisotropy != 0) gx_state.sampdc[k].Filter = D3D11_FILTER_ANISOTROPIC; + gx_state.sampler[k].packed = 0; } // Clear EFB textures @@ -302,7 +624,7 @@ void Renderer::SetColorMask() if (bpmem.blendmode.colorupdate) color_mask |= D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE; } - gx_state.blenddc.RenderTarget[0].RenderTargetWriteMask = color_mask; + gx_state.blend.write_mask = color_mask; } // This function allows the CPU to directly access the EFB. @@ -570,18 +892,7 @@ void SetSrcBlend(D3D11_BLEND val) else if (val == D3D11_BLEND_INV_SRC1_ALPHA) val = D3D11_BLEND_INV_SRC_ALPHA; - if (val == D3D11_BLEND_SRC_COLOR) - gx_state.blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; - else if (val == D3D11_BLEND_INV_SRC_COLOR) - gx_state.blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - else if (val == D3D11_BLEND_DEST_COLOR) - gx_state.blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA; - else if (val == D3D11_BLEND_INV_DEST_COLOR) - gx_state.blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; - else - gx_state.blenddc.RenderTarget[0].SrcBlendAlpha = val; - - gx_state.blenddc.RenderTarget[0].SrcBlend = val; + gx_state.blend.src_blend = val; } void SetDestBlend(D3D11_BLEND val) @@ -592,24 +903,12 @@ void SetDestBlend(D3D11_BLEND val) else if (val == D3D11_BLEND_INV_SRC1_ALPHA) val = D3D11_BLEND_INV_SRC_ALPHA; - if (val == D3D11_BLEND_SRC_COLOR) - gx_state.blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA; - else if (val == D3D11_BLEND_INV_SRC_COLOR) - gx_state.blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - else if (val == D3D11_BLEND_DEST_COLOR) - gx_state.blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA; - else if (val == D3D11_BLEND_INV_DEST_COLOR) - gx_state.blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; - else - gx_state.blenddc.RenderTarget[0].DestBlendAlpha = val; - - gx_state.blenddc.RenderTarget[0].DestBlend = val; + gx_state.blend.dst_blend = val; } void SetBlendOp(D3D11_BLEND_OP val) { - gx_state.blenddc.RenderTarget[0].BlendOp = val; - gx_state.blenddc.RenderTarget[0].BlendOpAlpha = val; + gx_state.blend.blend_op = val; } void Renderer::SetBlendMode(bool forceUpdate) @@ -645,14 +944,14 @@ void Renderer::SetBlendMode(bool forceUpdate) if (bpmem.blendmode.subtract) { - gx_state.blenddc.RenderTarget[0].BlendEnable = true; + gx_state.blend.blend_enable = true; SetBlendOp(D3D11_BLEND_OP_REV_SUBTRACT); SetSrcBlend(D3D11_BLEND_ONE); SetDestBlend(D3D11_BLEND_ONE); } else { - gx_state.blenddc.RenderTarget[0].BlendEnable = bpmem.blendmode.blendenable; + gx_state.blend.blend_enable = bpmem.blendmode.blendenable; if (bpmem.blendmode.blendenable) { SetBlendOp(D3D11_BLEND_OP_ADD); @@ -1053,65 +1352,22 @@ void Renderer::RestoreAPIState() void Renderer::ApplyState(bool bUseDstAlpha) { - HRESULT hr; + gx_state.blend.use_dst_alpha = bUseDstAlpha; + D3D::stateman->PushBlendState(gx_state_cache.Get(gx_state.blend)); - if (bUseDstAlpha) - { - // Colors should blend against SRC1_ALPHA - if (gx_state.blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_ALPHA) - gx_state.blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC1_ALPHA; - else if (gx_state.blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_ALPHA) - gx_state.blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_SRC1_ALPHA; + D3D::stateman->PushDepthState(gx_state_cache.Get(gx_state.zmode)); - // Colors should blend against SRC1_ALPHA - if (gx_state.blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_ALPHA) - gx_state.blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_ALPHA; - else if (gx_state.blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_ALPHA) - gx_state.blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC1_ALPHA; - - gx_state.blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - gx_state.blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - gx_state.blenddc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - } - - ID3D11BlendState* blstate; - hr = D3D::device->CreateBlendState(&gx_state.blenddc, &blstate); - if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); - D3D::stateman->PushBlendState(blstate); - D3D::SetDebugObjectName((ID3D11DeviceChild*)blstate, "blend state used to emulate the GX pipeline"); - SAFE_RELEASE(blstate); - - ID3D11DepthStencilState* depth_state; - hr = D3D::device->CreateDepthStencilState(&gx_state.depthdc, &depth_state); - if (SUCCEEDED(hr)) D3D::SetDebugObjectName((ID3D11DeviceChild*)depth_state, "depth-stencil state used to emulate the GX pipeline"); - else PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); - D3D::stateman->PushDepthState(depth_state); - SAFE_RELEASE(depth_state); - - gx_state.rastdc.FillMode = (g_ActiveConfig.bWireFrame) ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID; - ID3D11RasterizerState* raststate; - hr = D3D::device->CreateRasterizerState(&gx_state.rastdc, &raststate); - if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)raststate, "rasterizer state used to emulate the GX pipeline"); - D3D::stateman->PushRasterizerState(raststate); - SAFE_RELEASE(raststate); + gx_state.raster.wireframe = g_ActiveConfig.bWireFrame; + D3D::stateman->PushRasterizerState(gx_state_cache.Get(gx_state.raster)); ID3D11SamplerState* samplerstate[8]; for (unsigned int stage = 0; stage < 8; stage++) { - // TODO: unnecessary state changes, we should store a list of shader resources - //if (shader_resources[stage]) - { - if (g_ActiveConfig.iMaxAnisotropy > 0) gx_state.sampdc[stage].Filter = D3D11_FILTER_ANISOTROPIC; - hr = D3D::device->CreateSamplerState(&gx_state.sampdc[stage], &samplerstate[stage]); - if (FAILED(hr)) PanicAlert("Fail %s %d, stage=%d\n", __FILE__, __LINE__, stage); - else D3D::SetDebugObjectName((ID3D11DeviceChild*)samplerstate[stage], "sampler state used to emulate the GX pipeline"); - } - // else samplerstate[stage] = nullptr; + SamplerState state = gx_state.sampler[stage]; + state.max_anisotropy = g_ActiveConfig.iMaxAnisotropy; + samplerstate[stage] = gx_state_cache.Get(gx_state.sampler[stage]); } D3D::context->PSSetSamplers(0, 8, samplerstate); - for (unsigned int stage = 0; stage < 8; stage++) - SAFE_RELEASE(samplerstate[stage]); D3D::stateman->Apply(); @@ -1142,16 +1398,11 @@ void Renderer::RestoreState() void Renderer::ApplyCullDisable() { - D3D11_RASTERIZER_DESC rastDesc = gx_state.rastdc; - rastDesc.CullMode = D3D11_CULL_NONE; - - ID3D11RasterizerState* raststate; - HRESULT hr = D3D::device->CreateRasterizerState(&rastDesc, &raststate); - if (FAILED(hr)) PanicAlert("Failed to create culling-disabled rasterizer state at %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)raststate, "rasterizer state (culling disabled) used to emulate the GX pipeline"); + RasterizerState rast = gx_state.raster; + rast.cull_mode = D3D11_CULL_NONE; + ID3D11RasterizerState* raststate = gx_state_cache.Get(rast); D3D::stateman->PushRasterizerState(raststate); - SAFE_RELEASE(raststate); D3D::stateman->Apply(); } @@ -1173,35 +1424,12 @@ void Renderer::SetGenerationMode() // rastdc.FrontCounterClockwise must be false for this to work // TODO: GX_CULL_ALL not supported, yet! - gx_state.rastdc.CullMode = d3dCullModes[bpmem.genMode.cullmode]; + gx_state.raster.cull_mode = d3dCullModes[bpmem.genMode.cullmode]; } void Renderer::SetDepthMode() { - const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] = - { - D3D11_COMPARISON_NEVER, - D3D11_COMPARISON_LESS, - D3D11_COMPARISON_EQUAL, - D3D11_COMPARISON_LESS_EQUAL, - D3D11_COMPARISON_GREATER, - D3D11_COMPARISON_NOT_EQUAL, - D3D11_COMPARISON_GREATER_EQUAL, - D3D11_COMPARISON_ALWAYS - }; - - if (bpmem.zmode.testenable) - { - gx_state.depthdc.DepthEnable = TRUE; - gx_state.depthdc.DepthWriteMask = bpmem.zmode.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - gx_state.depthdc.DepthFunc = d3dCmpFuncs[bpmem.zmode.func]; - } - else - { - // if the test is disabled write is disabled too - gx_state.depthdc.DepthEnable = FALSE; - gx_state.depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - } + gx_state.zmode = bpmem.zmode; } void Renderer::SetLogicOpMode() @@ -1285,7 +1513,7 @@ void Renderer::SetLogicOpMode() if (bpmem.blendmode.logicopenable) { - gx_state.blenddc.RenderTarget[0].BlendEnable = true; + gx_state.blend.blend_enable = true; SetBlendOp(d3dLogicOps[bpmem.blendmode.logicmode]); SetSrcBlend(d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]); SetDestBlend(d3dLogicOpDestFactors[bpmem.blendmode.logicmode]); @@ -1308,75 +1536,29 @@ void Renderer::SetLineWidth() void Renderer::SetSamplerState(int stage, int texindex) { -#define TEXF_NONE 0 -#define TEXF_POINT 1 -#define TEXF_LINEAR 2 - const unsigned int d3dMipFilters[4] = - { - TEXF_NONE, - TEXF_POINT, - TEXF_LINEAR, - TEXF_NONE, //reserved - }; - const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] = - { - D3D11_TEXTURE_ADDRESS_CLAMP, - D3D11_TEXTURE_ADDRESS_WRAP, - D3D11_TEXTURE_ADDRESS_MIRROR, - D3D11_TEXTURE_ADDRESS_WRAP //reserved - }; - const FourTexUnits &tex = bpmem.tex[texindex]; const TexMode0 &tm0 = tex.texMode0[stage]; const TexMode1 &tm1 = tex.texMode1[stage]; - unsigned int mip = d3dMipFilters[tm0.min_filter & 3]; - if (texindex) stage += 4; if (g_ActiveConfig.bForceFiltering) { - gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + gx_state.sampler[stage].min_filter = 6; // 4 (linear mip) | 2 (linear min) + gx_state.sampler[stage].mag_filter = 1; // linear mag } - else if (tm0.min_filter & 4) // linear min filter + else { - if (tm0.mag_filter) // linear mag filter - { - if (mip == TEXF_NONE) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - else if (mip == TEXF_POINT) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - else if (mip == TEXF_LINEAR) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - } - else // point mag filter - { - if (mip == TEXF_NONE) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; - else if (mip == TEXF_POINT) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; - else if (mip == TEXF_LINEAR) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; - } - } - else // point min filter - { - if (tm0.mag_filter) // linear mag filter - { - if (mip == TEXF_NONE) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; - else if (mip == TEXF_POINT) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; - else if (mip == TEXF_LINEAR) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR; - } - else // point mag filter - { - if (mip == TEXF_NONE) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; - else if (mip == TEXF_POINT) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; - else if (mip == TEXF_LINEAR) gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; - } + gx_state.sampler[stage].min_filter = tm0.min_filter; + gx_state.sampler[stage].mag_filter = tm0.mag_filter; } - gx_state.sampdc[stage].AddressU = d3dClamps[tm0.wrap_s]; - gx_state.sampdc[stage].AddressV = d3dClamps[tm0.wrap_t]; - - // When mipfilter is set to "none", just disable mipmapping altogether - gx_state.sampdc[stage].MaxLOD = (mip == TEXF_NONE) ? 0.0f : (float)tm1.max_lod/16.f; - gx_state.sampdc[stage].MinLOD = (float)tm1.min_lod/16.f; - gx_state.sampdc[stage].MipLODBias = (s32)tm0.lod_bias/32.0f; + gx_state.sampler[stage].wrap_s = tm0.wrap_s; + gx_state.sampler[stage].wrap_t = tm0.wrap_t; + gx_state.sampler[stage].max_lod = tm1.max_lod; + gx_state.sampler[stage].min_lod = tm1.min_lod; + gx_state.sampler[stage].lod_bias = tm0.lod_bias; } void Renderer::SetInterlacingMode() From 2e4667caaa517392e8fbce00af5cf189d8960f2c Mon Sep 17 00:00:00 2001 From: Yuriy O'Donnell Date: Mon, 9 Jun 2014 00:36:26 +0200 Subject: [PATCH 2/7] D3D: Moved render state cache into separate source files. Refactored StateCache::Get() to early out for narrower indentation. Added comments to clarify ownership of objects returned by StateCache::Get(). --- Source/Core/VideoBackends/D3D/D3D.vcxproj | 4 +- .../VideoBackends/D3D/D3D.vcxproj.filters | 8 +- Source/Core/VideoBackends/D3D/Render.cpp | 341 +----------------- Source/Core/VideoBackends/D3D/StateCache.cpp | 280 ++++++++++++++ Source/Core/VideoBackends/D3D/StateCache.h | 82 +++++ Source/Core/VideoCommon/BPMemory.h | 7 + 6 files changed, 381 insertions(+), 341 deletions(-) create mode 100644 Source/Core/VideoBackends/D3D/StateCache.cpp create mode 100644 Source/Core/VideoBackends/D3D/StateCache.h diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj b/Source/Core/VideoBackends/D3D/D3D.vcxproj index fd95e42b6d..ee77521420 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj @@ -50,6 +50,7 @@ + @@ -72,6 +73,7 @@ + @@ -91,4 +93,4 @@ - \ No newline at end of file + diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters index 3682937f5d..58b26f0ea9 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -67,6 +67,9 @@ Render + + Render + @@ -129,5 +132,8 @@ + + Render + \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index eeca80e3a2..655000f72b 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -21,6 +21,7 @@ #include "VideoBackends/D3D/GfxState.h" #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/Render.h" +#include "VideoBackends/D3D/StateCache.h" #include "VideoBackends/D3D/Television.h" #include "VideoBackends/D3D/TextureCache.h" #include "VideoBackends/D3D/VertexShaderCache.h" @@ -54,49 +55,6 @@ ID3D11RasterizerState* resetraststate = nullptr; static ID3D11Texture2D* s_screenshot_texture = nullptr; -union RasterizerState -{ - struct - { - u32 cull_mode : 2; - u32 wireframe : 1; - }; - - u32 packed; -}; - -union BlendState -{ - struct - { - u32 blend_enable : 1; - u32 blend_op : 3; - u32 write_mask : 4; - u32 src_blend : 5; - u32 dst_blend : 5; - u32 use_dst_alpha : 1; - }; - - u32 packed; -}; - -union SamplerState -{ - struct - { - u64 min_filter : 3; - u64 mag_filter : 1; - u64 min_lod : 8; - u64 max_lod : 8; - s64 lod_bias : 8; - u64 wrap_s : 2; - u64 wrap_t : 2; - u64 max_anisotropy : 5; - }; - - u64 packed; -}; - // GX pipeline state struct { @@ -107,302 +65,7 @@ struct } gx_state; -class GXStateCache -{ -public: - - ID3D11SamplerState* Get(SamplerState state) - { - ID3D11SamplerState* res = nullptr; - - auto it = m_sampler.find(state.packed); - - if (it != m_sampler.end()) - { - res = it->second; - } - else - { - enum - { - TEXF_NONE = 0, - TEXF_POINT = 1, - TEXF_LINEAR = 2 - }; - - const unsigned int d3dMipFilters[4] = - { - TEXF_NONE, - TEXF_POINT, - TEXF_LINEAR, - TEXF_NONE, //reserved - }; - const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] = - { - D3D11_TEXTURE_ADDRESS_CLAMP, - D3D11_TEXTURE_ADDRESS_WRAP, - D3D11_TEXTURE_ADDRESS_MIRROR, - D3D11_TEXTURE_ADDRESS_WRAP //reserved - }; - - D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); - - unsigned int mip = d3dMipFilters[state.min_filter & 3]; - - if (state.max_anisotropy) - { - sampdc.Filter = D3D11_FILTER_ANISOTROPIC; - sampdc.MaxAnisotropy = state.max_anisotropy; - } - else if (state.min_filter & 4) // linear min filter - { - if (state.mag_filter) // linear mag filter - { - if (mip == TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - else if (mip == TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - else if (mip == TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - } - else // point mag filter - { - if (mip == TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; - else if (mip == TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; - else if (mip == TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; - } - } - else // point min filter - { - if (state.mag_filter) // linear mag filter - { - if (mip == TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; - else if (mip == TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; - else if (mip == TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR; - } - else // point mag filter - { - if (mip == TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; - else if (mip == TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; - else if (mip == TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; - } - } - - sampdc.AddressU = d3dClamps[state.wrap_s]; - sampdc.AddressV = d3dClamps[state.wrap_t]; - - sampdc.MaxLOD = (mip == TEXF_NONE) ? 0.0f : (float)state.max_lod / 16.f; - sampdc.MinLOD = (float)state.min_lod / 16.f; - sampdc.MipLODBias = (s32)state.lod_bias / 32.0f; - - HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res); - if (FAILED(hr)) PanicAlert("Fail %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "sampler state used to emulate the GX pipeline"); - m_sampler.insert(std::make_pair(state.packed, res)); - } - - return res; - } - - ID3D11BlendState* Get(BlendState state) - { - ID3D11BlendState* res = nullptr; - - auto it = m_blend.find(state.packed); - - if (it != m_blend.end()) - { - res = it->second; - } - else - { - D3D11_BLEND_DESC blenddc = CD3D11_BLEND_DESC(CD3D11_DEFAULT()); - - blenddc.AlphaToCoverageEnable = FALSE; - blenddc.IndependentBlendEnable = FALSE; - blenddc.RenderTarget[0].BlendEnable = state.blend_enable; - blenddc.RenderTarget[0].RenderTargetWriteMask = (D3D11_COLOR_WRITE_ENABLE)state.write_mask; - blenddc.RenderTarget[0].SrcBlend = (D3D11_BLEND)state.src_blend; - blenddc.RenderTarget[0].DestBlend = (D3D11_BLEND)state.dst_blend; - blenddc.RenderTarget[0].BlendOp = (D3D11_BLEND_OP)state.blend_op; - blenddc.RenderTarget[0].SrcBlendAlpha = (D3D11_BLEND)state.src_blend; - blenddc.RenderTarget[0].DestBlendAlpha = (D3D11_BLEND)state.dst_blend; - blenddc.RenderTarget[0].BlendOpAlpha = (D3D11_BLEND_OP)state.blend_op; - - if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_COLOR) - blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; - else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_COLOR) - blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_DEST_COLOR) - blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA; - else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_DEST_COLOR) - blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; - else - blenddc.RenderTarget[0].SrcBlendAlpha = blenddc.RenderTarget[0].SrcBlend; - - if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_COLOR) - blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA; - else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_COLOR) - blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_DEST_COLOR) - blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA; - else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_DEST_COLOR) - blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; - else - blenddc.RenderTarget[0].DestBlendAlpha = blenddc.RenderTarget[0].DestBlend; - - if (state.use_dst_alpha) - { - // Colors should blend against SRC1_ALPHA - if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_ALPHA) - blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC1_ALPHA; - else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_ALPHA) - blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_SRC1_ALPHA; - - // Colors should blend against SRC1_ALPHA - if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_ALPHA) - blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_ALPHA; - else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_ALPHA) - blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC1_ALPHA; - - blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - blenddc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - } - - HRESULT hr = D3D::device->CreateBlendState(&blenddc, &res); - if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "blend state used to emulate the GX pipeline"); - m_blend.insert(std::make_pair(state.packed, res)); - } - - return res; - } - - ID3D11RasterizerState* Get(RasterizerState state) - { - ID3D11RasterizerState* res = nullptr; - - auto it = m_raster.find(state.packed); - - if (it != m_raster.end()) - { - res = it->second; - } - else - { - D3D11_RASTERIZER_DESC rastdc = CD3D11_RASTERIZER_DESC(state.wireframe ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID, - (D3D11_CULL_MODE)state.cull_mode, - false, 0, 0.f, 0, false, true, false, false); - - HRESULT hr = D3D::device->CreateRasterizerState(&rastdc, &res); - if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "rasterizer state used to emulate the GX pipeline"); - m_raster.insert(std::make_pair(state.packed, res)); - } - - return res; - } - - ID3D11DepthStencilState* Get(ZMode state) - { - ID3D11DepthStencilState* res = nullptr; - - auto it = m_depth.find(state.hex); - if (it != m_depth.end()) - { - res = it->second; - } - else - { - D3D11_DEPTH_STENCIL_DESC depthdc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); - - depthdc.DepthEnable = TRUE; - depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - depthdc.DepthFunc = D3D11_COMPARISON_LESS; - depthdc.StencilEnable = FALSE; - depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - - const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] = - { - D3D11_COMPARISON_NEVER, - D3D11_COMPARISON_LESS, - D3D11_COMPARISON_EQUAL, - D3D11_COMPARISON_LESS_EQUAL, - D3D11_COMPARISON_GREATER, - D3D11_COMPARISON_NOT_EQUAL, - D3D11_COMPARISON_GREATER_EQUAL, - D3D11_COMPARISON_ALWAYS - }; - - if (state.testenable) - { - depthdc.DepthEnable = TRUE; - depthdc.DepthWriteMask = state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - depthdc.DepthFunc = d3dCmpFuncs[state.func]; - } - else - { - // if the test is disabled write is disabled too - depthdc.DepthEnable = FALSE; - depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - } - - HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res); - if (SUCCEEDED(hr)) D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "depth-stencil state used to emulate the GX pipeline"); - else PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); - - m_depth.insert(std::make_pair(state.hex, res)); - } - - return res; - } - - void Clear() - { - for (auto it : m_depth) - { - SAFE_RELEASE(it.second); - } - m_depth.clear(); - - for (auto it : m_raster) - { - SAFE_RELEASE(it.second); - } - m_raster.clear(); - - for (auto it : m_blend) - { - SAFE_RELEASE(it.second); - } - m_blend.clear(); - - for (auto it : m_sampler) - { - SAFE_RELEASE(it.second); - } - m_sampler.clear(); - } - -private: - - std::unordered_map m_depth; - std::unordered_map m_raster; - std::unordered_map m_blend; - std::unordered_map m_sampler; - -} gx_state_cache; +StateCache gx_state_cache; void SetupDeviceObjects() { diff --git a/Source/Core/VideoBackends/D3D/StateCache.cpp b/Source/Core/VideoBackends/D3D/StateCache.cpp new file mode 100644 index 0000000000..c1b351cd56 --- /dev/null +++ b/Source/Core/VideoBackends/D3D/StateCache.cpp @@ -0,0 +1,280 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "VideoBackends/D3D/StateCache.h" + +namespace DX11 +{ + +ID3D11SamplerState* StateCache::Get(SamplerState state) +{ + auto it = m_sampler.find(state.packed); + + if (it != m_sampler.end()) + { + return it->second; + } + + const unsigned int d3dMipFilters[4] = + { + TexMode0::TEXF_NONE, + TexMode0::TEXF_POINT, + TexMode0::TEXF_LINEAR, + TexMode0::TEXF_NONE, //reserved + }; + const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] = + { + D3D11_TEXTURE_ADDRESS_CLAMP, + D3D11_TEXTURE_ADDRESS_WRAP, + D3D11_TEXTURE_ADDRESS_MIRROR, + D3D11_TEXTURE_ADDRESS_WRAP //reserved + }; + + D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); + + unsigned int mip = d3dMipFilters[state.min_filter & 3]; + + if (state.max_anisotropy) + { + sampdc.Filter = D3D11_FILTER_ANISOTROPIC; + sampdc.MaxAnisotropy = state.max_anisotropy; + } + else if (state.min_filter & 4) // linear min filter + { + if (state.mag_filter) // linear mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + } + else // point mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; + } + } + else // point min filter + { + if (state.mag_filter) // linear mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR; + } + else // point mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; + } + } + + sampdc.AddressU = d3dClamps[state.wrap_s]; + sampdc.AddressV = d3dClamps[state.wrap_t]; + + sampdc.MaxLOD = (mip == TexMode0::TEXF_NONE) ? 0.0f : (float)state.max_lod / 16.f; + sampdc.MinLOD = (float)state.min_lod / 16.f; + sampdc.MipLODBias = (s32)state.lod_bias / 32.0f; + + ID3D11SamplerState* res = nullptr; + + HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res); + if (FAILED(hr)) PanicAlert("Fail %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "sampler state used to emulate the GX pipeline"); + m_sampler.insert(std::make_pair(state.packed, res)); + + return res; +} + +ID3D11BlendState* StateCache::Get(BlendState state) +{ + auto it = m_blend.find(state.packed); + + if (it != m_blend.end()) + { + return it->second; + } + + D3D11_BLEND_DESC blenddc = CD3D11_BLEND_DESC(CD3D11_DEFAULT()); + + blenddc.AlphaToCoverageEnable = FALSE; + blenddc.IndependentBlendEnable = FALSE; + blenddc.RenderTarget[0].BlendEnable = state.blend_enable; + blenddc.RenderTarget[0].RenderTargetWriteMask = (D3D11_COLOR_WRITE_ENABLE)state.write_mask; + blenddc.RenderTarget[0].SrcBlend = (D3D11_BLEND)state.src_blend; + blenddc.RenderTarget[0].DestBlend = (D3D11_BLEND)state.dst_blend; + blenddc.RenderTarget[0].BlendOp = (D3D11_BLEND_OP)state.blend_op; + blenddc.RenderTarget[0].SrcBlendAlpha = (D3D11_BLEND)state.src_blend; + blenddc.RenderTarget[0].DestBlendAlpha = (D3D11_BLEND)state.dst_blend; + blenddc.RenderTarget[0].BlendOpAlpha = (D3D11_BLEND_OP)state.blend_op; + + if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_DEST_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_DEST_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; + else + blenddc.RenderTarget[0].SrcBlendAlpha = blenddc.RenderTarget[0].SrcBlend; + + if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_DEST_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_DEST_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; + else + blenddc.RenderTarget[0].DestBlendAlpha = blenddc.RenderTarget[0].DestBlend; + + if (state.use_dst_alpha) + { + // Colors should blend against SRC1_ALPHA + if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_ALPHA) + blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC1_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_ALPHA) + blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_SRC1_ALPHA; + + // Colors should blend against SRC1_ALPHA + if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_ALPHA) + blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_ALPHA) + blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC1_ALPHA; + + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blenddc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + } + + ID3D11BlendState* res = nullptr; + + HRESULT hr = D3D::device->CreateBlendState(&blenddc, &res); + if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "blend state used to emulate the GX pipeline"); + m_blend.insert(std::make_pair(state.packed, res)); + + return res; +} + +ID3D11RasterizerState* StateCache::Get(RasterizerState state) +{ + auto it = m_raster.find(state.packed); + + if (it != m_raster.end()) + { + return it->second; + } + + D3D11_RASTERIZER_DESC rastdc = CD3D11_RASTERIZER_DESC(state.wireframe ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID, + (D3D11_CULL_MODE)state.cull_mode, + false, 0, 0.f, 0, false, true, false, false); + + ID3D11RasterizerState* res = nullptr; + + HRESULT hr = D3D::device->CreateRasterizerState(&rastdc, &res); + if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "rasterizer state used to emulate the GX pipeline"); + m_raster.insert(std::make_pair(state.packed, res)); + + return res; +} + +ID3D11DepthStencilState* StateCache::Get(ZMode state) +{ + auto it = m_depth.find(state.hex); + + if (it != m_depth.end()) + { + return it->second; + } + + D3D11_DEPTH_STENCIL_DESC depthdc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); + + depthdc.DepthEnable = TRUE; + depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthdc.DepthFunc = D3D11_COMPARISON_LESS; + depthdc.StencilEnable = FALSE; + depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + + const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] = + { + D3D11_COMPARISON_NEVER, + D3D11_COMPARISON_LESS, + D3D11_COMPARISON_EQUAL, + D3D11_COMPARISON_LESS_EQUAL, + D3D11_COMPARISON_GREATER, + D3D11_COMPARISON_NOT_EQUAL, + D3D11_COMPARISON_GREATER_EQUAL, + D3D11_COMPARISON_ALWAYS + }; + + if (state.testenable) + { + depthdc.DepthEnable = TRUE; + depthdc.DepthWriteMask = state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + depthdc.DepthFunc = d3dCmpFuncs[state.func]; + } + else + { + // if the test is disabled write is disabled too + depthdc.DepthEnable = FALSE; + depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + } + + ID3D11DepthStencilState* res = nullptr; + + HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res); + if (SUCCEEDED(hr)) D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "depth-stencil state used to emulate the GX pipeline"); + else PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); + + m_depth.insert(std::make_pair(state.hex, res)); + + return res; +} + +void StateCache::Clear() +{ + for (auto it : m_depth) + { + SAFE_RELEASE(it.second); + } + m_depth.clear(); + + for (auto it : m_raster) + { + SAFE_RELEASE(it.second); + } + m_raster.clear(); + + for (auto it : m_blend) + { + SAFE_RELEASE(it.second); + } + m_blend.clear(); + + for (auto it : m_sampler) + { + SAFE_RELEASE(it.second); + } + m_sampler.clear(); +} + +} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/StateCache.h b/Source/Core/VideoBackends/D3D/StateCache.h new file mode 100644 index 0000000000..6d2b242558 --- /dev/null +++ b/Source/Core/VideoBackends/D3D/StateCache.h @@ -0,0 +1,82 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "Common/CommonTypes.h" +#include "VideoBackends/D3D/D3DBase.h" +#include "VideoCommon/BPMemory.h" + +namespace DX11 +{ + +union RasterizerState +{ + struct + { + u32 cull_mode : 2; + u32 wireframe : 1; + }; + + u32 packed; +}; + +union BlendState +{ + struct + { + u32 blend_enable : 1; + u32 blend_op : 3; + u32 write_mask : 4; + u32 src_blend : 5; + u32 dst_blend : 5; + u32 use_dst_alpha : 1; + }; + + u32 packed; +}; + +union SamplerState +{ + struct + { + u64 min_filter : 3; + u64 mag_filter : 1; + u64 min_lod : 8; + u64 max_lod : 8; + s64 lod_bias : 8; + u64 wrap_s : 2; + u64 wrap_t : 2; + u64 max_anisotropy : 5; + }; + + u64 packed; +}; + +class StateCache +{ +public: + + // Get existing or create new render state. + // Returned objects is owned by the cache and does not need to be released. + ID3D11SamplerState* Get(SamplerState state); + ID3D11BlendState* Get(BlendState state); + ID3D11RasterizerState* Get(RasterizerState state); + ID3D11DepthStencilState* Get(ZMode state); + + // Release all cached states and clear hash tables. + void Clear(); + +private: + + std::unordered_map m_depth; + std::unordered_map m_raster; + std::unordered_map m_blend; + std::unordered_map m_sampler; + +}; + +} diff --git a/Source/Core/VideoCommon/BPMemory.h b/Source/Core/VideoCommon/BPMemory.h index 346af479f2..d46a927370 100644 --- a/Source/Core/VideoCommon/BPMemory.h +++ b/Source/Core/VideoCommon/BPMemory.h @@ -413,6 +413,13 @@ union RAS1_IREF union TexMode0 { + enum TextureFilter : u32 + { + TEXF_NONE = 0, + TEXF_POINT = 1, + TEXF_LINEAR = 2 + }; + struct { u32 wrap_s : 2; From e7f8032d7dba8077217d2f42a6ecc2a765a49a73 Mon Sep 17 00:00:00 2001 From: Yuriy O'Donnell Date: Mon, 9 Jun 2014 11:55:25 +0200 Subject: [PATCH 3/7] D3D: State cache now uses BitField to define packed render states --- Source/Core/VideoBackends/D3D/Render.cpp | 16 ++++---- Source/Core/VideoBackends/D3D/StateCache.cpp | 18 ++++----- Source/Core/VideoBackends/D3D/StateCache.h | 42 ++++++++------------ 3 files changed, 34 insertions(+), 42 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 655000f72b..d3bd091017 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -614,7 +614,7 @@ void Renderer::SetBlendMode(bool forceUpdate) } else { - gx_state.blend.blend_enable = bpmem.blendmode.blendenable; + gx_state.blend.blend_enable = (u32)bpmem.blendmode.blendenable; if (bpmem.blendmode.blendenable) { SetBlendOp(D3D11_BLEND_OP_ADD); @@ -1213,15 +1213,15 @@ void Renderer::SetSamplerState(int stage, int texindex) } else { - gx_state.sampler[stage].min_filter = tm0.min_filter; - gx_state.sampler[stage].mag_filter = tm0.mag_filter; + gx_state.sampler[stage].min_filter = (u32)tm0.min_filter; + gx_state.sampler[stage].mag_filter = (u32)tm0.mag_filter; } - gx_state.sampler[stage].wrap_s = tm0.wrap_s; - gx_state.sampler[stage].wrap_t = tm0.wrap_t; - gx_state.sampler[stage].max_lod = tm1.max_lod; - gx_state.sampler[stage].min_lod = tm1.min_lod; - gx_state.sampler[stage].lod_bias = tm0.lod_bias; + gx_state.sampler[stage].wrap_s = (u32)tm0.wrap_s; + gx_state.sampler[stage].wrap_t = (u32)tm0.wrap_t; + gx_state.sampler[stage].max_lod = (u32)tm1.max_lod; + gx_state.sampler[stage].min_lod = (u32)tm1.min_lod; + gx_state.sampler[stage].lod_bias = (s32)tm0.lod_bias; } void Renderer::SetInterlacingMode() diff --git a/Source/Core/VideoBackends/D3D/StateCache.cpp b/Source/Core/VideoBackends/D3D/StateCache.cpp index c1b351cd56..ace05f0709 100644 --- a/Source/Core/VideoBackends/D3D/StateCache.cpp +++ b/Source/Core/VideoBackends/D3D/StateCache.cpp @@ -38,7 +38,7 @@ ID3D11SamplerState* StateCache::Get(SamplerState state) if (state.max_anisotropy) { sampdc.Filter = D3D11_FILTER_ANISOTROPIC; - sampdc.MaxAnisotropy = state.max_anisotropy; + sampdc.MaxAnisotropy = (u32)state.max_anisotropy; } else if (state.min_filter & 4) // linear min filter { @@ -114,13 +114,13 @@ ID3D11BlendState* StateCache::Get(BlendState state) blenddc.AlphaToCoverageEnable = FALSE; blenddc.IndependentBlendEnable = FALSE; blenddc.RenderTarget[0].BlendEnable = state.blend_enable; - blenddc.RenderTarget[0].RenderTargetWriteMask = (D3D11_COLOR_WRITE_ENABLE)state.write_mask; - blenddc.RenderTarget[0].SrcBlend = (D3D11_BLEND)state.src_blend; - blenddc.RenderTarget[0].DestBlend = (D3D11_BLEND)state.dst_blend; - blenddc.RenderTarget[0].BlendOp = (D3D11_BLEND_OP)state.blend_op; - blenddc.RenderTarget[0].SrcBlendAlpha = (D3D11_BLEND)state.src_blend; - blenddc.RenderTarget[0].DestBlendAlpha = (D3D11_BLEND)state.dst_blend; - blenddc.RenderTarget[0].BlendOpAlpha = (D3D11_BLEND_OP)state.blend_op; + blenddc.RenderTarget[0].RenderTargetWriteMask = (u32)state.write_mask; + blenddc.RenderTarget[0].SrcBlend = state.src_blend; + blenddc.RenderTarget[0].DestBlend = state.dst_blend; + blenddc.RenderTarget[0].BlendOp = state.blend_op; + blenddc.RenderTarget[0].SrcBlendAlpha = state.src_blend; + blenddc.RenderTarget[0].DestBlendAlpha = state.dst_blend; + blenddc.RenderTarget[0].BlendOpAlpha = state.blend_op; if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_COLOR) blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; @@ -183,7 +183,7 @@ ID3D11RasterizerState* StateCache::Get(RasterizerState state) } D3D11_RASTERIZER_DESC rastdc = CD3D11_RASTERIZER_DESC(state.wireframe ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID, - (D3D11_CULL_MODE)state.cull_mode, + state.cull_mode, false, 0, 0.f, 0, false, true, false, false); ID3D11RasterizerState* res = nullptr; diff --git a/Source/Core/VideoBackends/D3D/StateCache.h b/Source/Core/VideoBackends/D3D/StateCache.h index 6d2b242558..53745899bb 100644 --- a/Source/Core/VideoBackends/D3D/StateCache.h +++ b/Source/Core/VideoBackends/D3D/StateCache.h @@ -6,6 +6,7 @@ #include +#include "Common/BitField.h" #include "Common/CommonTypes.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoCommon/BPMemory.h" @@ -15,43 +16,34 @@ namespace DX11 union RasterizerState { - struct - { - u32 cull_mode : 2; - u32 wireframe : 1; - }; + BitField<0, 2, D3D11_CULL_MODE> cull_mode; + BitField<2, 1, u32> wireframe; u32 packed; }; union BlendState { - struct - { - u32 blend_enable : 1; - u32 blend_op : 3; - u32 write_mask : 4; - u32 src_blend : 5; - u32 dst_blend : 5; - u32 use_dst_alpha : 1; - }; + BitField<0, 1, u32> blend_enable; + BitField<1, 3, D3D11_BLEND_OP> blend_op; + BitField<4, 4, u32> write_mask; + BitField<8, 5, D3D11_BLEND> src_blend; + BitField<13, 5, D3D11_BLEND> dst_blend; + BitField<18, 1, u32> use_dst_alpha; u32 packed; }; union SamplerState { - struct - { - u64 min_filter : 3; - u64 mag_filter : 1; - u64 min_lod : 8; - u64 max_lod : 8; - s64 lod_bias : 8; - u64 wrap_s : 2; - u64 wrap_t : 2; - u64 max_anisotropy : 5; - }; + BitField<0, 3, u64> min_filter; + BitField<3, 1, u64> mag_filter; + BitField<4, 8, u64> min_lod; + BitField<12, 8, u64> max_lod; + BitField<20, 8, s64> lod_bias; + BitField<28, 2, u64> wrap_s; + BitField<30, 2, u64> wrap_t; + BitField<32, 5, u64> max_anisotropy; u64 packed; }; From 21655dc61a81845c88ebc20934c76a2ad93f1f3a Mon Sep 17 00:00:00 2001 From: Yuriy O'Donnell Date: Mon, 23 Jun 2014 08:11:07 +0200 Subject: [PATCH 4/7] D3D: moved render state cache implementation to D3DState.h/cpp --- Source/Core/VideoBackends/D3D/D3D.vcxproj | 8 +- .../VideoBackends/D3D/D3D.vcxproj.filters | 12 +-- Source/Core/VideoBackends/D3D/D3DBase.cpp | 2 +- .../D3D/{StateCache.cpp => D3DState.cpp} | 72 ++++++++++++++++- .../D3D/{StateCache.h => D3DState.h} | 58 +++++++++++++- Source/Core/VideoBackends/D3D/D3DUtil.cpp | 2 +- Source/Core/VideoBackends/D3D/GfxState.cpp | 80 ------------------- Source/Core/VideoBackends/D3D/GfxState.h | 67 ---------------- .../VideoBackends/D3D/PSTextureEncoder.cpp | 2 +- Source/Core/VideoBackends/D3D/Render.cpp | 3 +- Source/Core/VideoBackends/D3D/XFBEncoder.cpp | 2 +- 11 files changed, 139 insertions(+), 169 deletions(-) rename Source/Core/VideoBackends/D3D/{StateCache.cpp => D3DState.cpp} (81%) rename Source/Core/VideoBackends/D3D/{StateCache.h => D3DState.h} (55%) delete mode 100644 Source/Core/VideoBackends/D3D/GfxState.cpp delete mode 100644 Source/Core/VideoBackends/D3D/GfxState.h diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj b/Source/Core/VideoBackends/D3D/D3D.vcxproj index ee77521420..41e1c18529 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj @@ -38,10 +38,10 @@ + - @@ -50,7 +50,6 @@ - @@ -61,10 +60,10 @@ + - @@ -73,7 +72,6 @@ - @@ -93,4 +91,4 @@ - + \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters index 58b26f0ea9..a552f47216 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -24,7 +24,7 @@ D3D - + D3D @@ -67,9 +67,6 @@ Render - - Render - @@ -87,7 +84,7 @@ D3D - + D3D @@ -132,8 +129,5 @@ - - Render - \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D/D3DBase.cpp b/Source/Core/VideoBackends/D3D/D3DBase.cpp index cde40490a4..f7426da03a 100644 --- a/Source/Core/VideoBackends/D3D/D3DBase.cpp +++ b/Source/Core/VideoBackends/D3D/D3DBase.cpp @@ -4,8 +4,8 @@ #include "Common/StringUtil.h" #include "VideoBackends/D3D/D3DBase.h" +#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DTexture.h" -#include "VideoBackends/D3D/GfxState.h" #include "VideoCommon/VideoConfig.h" namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/StateCache.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp similarity index 81% rename from Source/Core/VideoBackends/D3D/StateCache.cpp rename to Source/Core/VideoBackends/D3D/D3DState.cpp index ace05f0709..67436df56f 100644 --- a/Source/Core/VideoBackends/D3D/StateCache.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -2,11 +2,81 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include "VideoBackends/D3D/StateCache.h" +#include "Common/Logging/Log.h" + +#include "VideoBackends/D3D/D3DBase.h" +#include "VideoBackends/D3D/D3DState.h" namespace DX11 { +namespace D3D +{ + +StateManager* stateman; + + +template AutoState::AutoState(const T* object) : state(object) +{ + ((IUnknown*)state)->AddRef(); +} + +template AutoState::AutoState(const AutoState &source) +{ + state = source.GetPtr(); + ((T*)state)->AddRef(); +} + +template AutoState::~AutoState() +{ + if (state) ((T*)state)->Release(); + state = nullptr; +} + +StateManager::StateManager() : cur_blendstate(nullptr), cur_depthstate(nullptr), cur_raststate(nullptr) {} + +void StateManager::PushBlendState(const ID3D11BlendState* state) { blendstates.push(AutoBlendState(state)); } +void StateManager::PushDepthState(const ID3D11DepthStencilState* state) { depthstates.push(AutoDepthStencilState(state)); } +void StateManager::PushRasterizerState(const ID3D11RasterizerState* state) { raststates.push(AutoRasterizerState(state)); } +void StateManager::PopBlendState() { blendstates.pop(); } +void StateManager::PopDepthState() { depthstates.pop(); } +void StateManager::PopRasterizerState() { raststates.pop(); } + +void StateManager::Apply() +{ + if (!blendstates.empty()) + { + if (cur_blendstate != blendstates.top().GetPtr()) + { + cur_blendstate = (ID3D11BlendState*)blendstates.top().GetPtr(); + D3D::context->OMSetBlendState(cur_blendstate, nullptr, 0xFFFFFFFF); + } + } + else ERROR_LOG(VIDEO, "Tried to apply without blend state!"); + + if (!depthstates.empty()) + { + if (cur_depthstate != depthstates.top().GetPtr()) + { + cur_depthstate = (ID3D11DepthStencilState*)depthstates.top().GetPtr(); + D3D::context->OMSetDepthStencilState(cur_depthstate, 0); + } + } + else ERROR_LOG(VIDEO, "Tried to apply without depth state!"); + + if (!raststates.empty()) + { + if (cur_raststate != raststates.top().GetPtr()) + { + cur_raststate = (ID3D11RasterizerState*)raststates.top().GetPtr(); + D3D::context->RSSetState(cur_raststate); + } + } + else ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!"); +} + +} // namespace D3D + ID3D11SamplerState* StateCache::Get(SamplerState state) { auto it = m_sampler.find(state.packed); diff --git a/Source/Core/VideoBackends/D3D/StateCache.h b/Source/Core/VideoBackends/D3D/D3DState.h similarity index 55% rename from Source/Core/VideoBackends/D3D/StateCache.h rename to Source/Core/VideoBackends/D3D/D3DState.h index 53745899bb..8c7ee75776 100644 --- a/Source/Core/VideoBackends/D3D/StateCache.h +++ b/Source/Core/VideoBackends/D3D/D3DState.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include "Common/BitField.h" @@ -11,6 +12,10 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoCommon/BPMemory.h" +struct ID3D11BlendState; +struct ID3D11DepthStencilState; +struct ID3D11RasterizerState; + namespace DX11 { @@ -71,4 +76,55 @@ private: }; -} +namespace D3D +{ + +template class AutoState +{ +public: + AutoState(const T* object); + AutoState(const AutoState &source); + ~AutoState(); + + const inline T* GetPtr() const { return state; } + +private: + const T* state; +}; + +typedef AutoState AutoBlendState; +typedef AutoState AutoDepthStencilState; +typedef AutoState AutoRasterizerState; + +class StateManager +{ +public: + StateManager(); + + // call any of these to change the affected states + void PushBlendState(const ID3D11BlendState* state); + void PushDepthState(const ID3D11DepthStencilState* state); + void PushRasterizerState(const ID3D11RasterizerState* state); + + // call these after drawing + void PopBlendState(); + void PopDepthState(); + void PopRasterizerState(); + + // call this before any drawing operation if states could have changed meanwhile + void Apply(); + +private: + std::stack blendstates; + std::stack depthstates; + std::stack raststates; + ID3D11BlendState* cur_blendstate; + ID3D11DepthStencilState* cur_depthstate; + ID3D11RasterizerState* cur_raststate; +}; + +extern StateManager* stateman; + +} // namespace + +} // namespace DX11 \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D/D3DUtil.cpp b/Source/Core/VideoBackends/D3D/D3DUtil.cpp index f8d91df952..ad37d4f419 100644 --- a/Source/Core/VideoBackends/D3D/D3DUtil.cpp +++ b/Source/Core/VideoBackends/D3D/D3DUtil.cpp @@ -8,8 +8,8 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DShader.h" +#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DUtil.h" -#include "VideoBackends/D3D/GfxState.h" #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/VertexShaderCache.h" diff --git a/Source/Core/VideoBackends/D3D/GfxState.cpp b/Source/Core/VideoBackends/D3D/GfxState.cpp deleted file mode 100644 index b14ecec8fc..0000000000 --- a/Source/Core/VideoBackends/D3D/GfxState.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "Common/Logging/Log.h" - -#include "VideoBackends/D3D/D3DBase.h" -#include "VideoBackends/D3D/GfxState.h" - -namespace DX11 -{ - -namespace D3D -{ - -StateManager* stateman; - - -template AutoState::AutoState(const T* object) : state(object) -{ - ((IUnknown*)state)->AddRef(); -} - -template AutoState::AutoState(const AutoState &source) -{ - state = source.GetPtr(); - ((T*)state)->AddRef(); -} - -template AutoState::~AutoState() -{ - if (state) ((T*)state)->Release(); - state = nullptr; -} - -StateManager::StateManager() : cur_blendstate(nullptr), cur_depthstate(nullptr), cur_raststate(nullptr) {} - -void StateManager::PushBlendState(const ID3D11BlendState* state) { blendstates.push(AutoBlendState(state)); } -void StateManager::PushDepthState(const ID3D11DepthStencilState* state) { depthstates.push(AutoDepthStencilState(state)); } -void StateManager::PushRasterizerState(const ID3D11RasterizerState* state) { raststates.push(AutoRasterizerState(state)); } -void StateManager::PopBlendState() { blendstates.pop(); } -void StateManager::PopDepthState() { depthstates.pop(); } -void StateManager::PopRasterizerState() { raststates.pop(); } - -void StateManager::Apply() -{ - if (!blendstates.empty()) - { - if (cur_blendstate != blendstates.top().GetPtr()) - { - cur_blendstate = (ID3D11BlendState*)blendstates.top().GetPtr(); - D3D::context->OMSetBlendState(cur_blendstate, nullptr, 0xFFFFFFFF); - } - } - else ERROR_LOG(VIDEO, "Tried to apply without blend state!"); - - if (!depthstates.empty()) - { - if (cur_depthstate != depthstates.top().GetPtr()) - { - cur_depthstate = (ID3D11DepthStencilState*)depthstates.top().GetPtr(); - D3D::context->OMSetDepthStencilState(cur_depthstate, 0); - } - } - else ERROR_LOG(VIDEO, "Tried to apply without depth state!"); - - if (!raststates.empty()) - { - if (cur_raststate != raststates.top().GetPtr()) - { - cur_raststate = (ID3D11RasterizerState*)raststates.top().GetPtr(); - D3D::context->RSSetState(cur_raststate); - } - } - else ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!"); -} - -} // namespace - -} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/GfxState.h b/Source/Core/VideoBackends/D3D/GfxState.h deleted file mode 100644 index 977b53dab6..0000000000 --- a/Source/Core/VideoBackends/D3D/GfxState.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include - -struct ID3D11BlendState; -struct ID3D11DepthStencilState; -struct ID3D11RasterizerState; - -namespace DX11 -{ - -namespace D3D -{ - -template class AutoState -{ -public: - AutoState(const T* object); - AutoState(const AutoState &source); - ~AutoState(); - - const inline T* GetPtr() const { return state; } - -private: - const T* state; -}; - -typedef AutoState AutoBlendState; -typedef AutoState AutoDepthStencilState; -typedef AutoState AutoRasterizerState; - -class StateManager -{ -public: - StateManager(); - - // call any of these to change the affected states - void PushBlendState(const ID3D11BlendState* state); - void PushDepthState(const ID3D11DepthStencilState* state); - void PushRasterizerState(const ID3D11RasterizerState* state); - - // call these after drawing - void PopBlendState(); - void PopDepthState(); - void PopRasterizerState(); - - // call this before any drawing operation if states could have changed meanwhile - void Apply(); - -private: - std::stack blendstates; - std::stack depthstates; - std::stack raststates; - ID3D11BlendState* cur_blendstate; - ID3D11DepthStencilState* cur_depthstate; - ID3D11RasterizerState* cur_raststate; -}; - -extern StateManager* stateman; - -} // namespace - -} // namespace DX11 \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp index fd1bd8a76d..fe1f134635 100644 --- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp @@ -5,8 +5,8 @@ #include "Core/HW/Memmap.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DShader.h" +#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/FramebufferManager.h" -#include "VideoBackends/D3D/GfxState.h" #include "VideoBackends/D3D/PSTextureEncoder.h" #include "VideoBackends/D3D/Render.h" #include "VideoBackends/D3D/TextureCache.h" diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index d3bd091017..a947a8c99e 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -16,12 +16,11 @@ #include "Core/Movie.h" #include "VideoBackends/D3D/D3DBase.h" +#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DUtil.h" #include "VideoBackends/D3D/FramebufferManager.h" -#include "VideoBackends/D3D/GfxState.h" #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/Render.h" -#include "VideoBackends/D3D/StateCache.h" #include "VideoBackends/D3D/Television.h" #include "VideoBackends/D3D/TextureCache.h" #include "VideoBackends/D3D/VertexShaderCache.h" diff --git a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp b/Source/Core/VideoBackends/D3D/XFBEncoder.cpp index 215a7e911f..50524d8a3d 100644 --- a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/XFBEncoder.cpp @@ -5,8 +5,8 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DBlob.h" #include "VideoBackends/D3D/D3DShader.h" +#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/FramebufferManager.h" -#include "VideoBackends/D3D/GfxState.h" #include "VideoBackends/D3D/Render.h" #include "VideoBackends/D3D/XFBEncoder.h" From bea68c95a45a02ae616a817a248b28eb3f270e6e Mon Sep 17 00:00:00 2001 From: Yuriy O'Donnell Date: Wed, 15 Oct 2014 20:17:34 +0200 Subject: [PATCH 5/7] D3D: Fixed uninitialized members of gx_state --- Source/Core/VideoBackends/D3D/Render.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index a947a8c99e..a036e67b4c 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -200,7 +200,6 @@ Renderer::Renderer(void *&window_handle) SetupDeviceObjects(); - // Setup GX pipeline state gx_state.blend.blend_enable = false; gx_state.blend.write_mask = D3D11_COLOR_WRITE_ENABLE_ALL; @@ -211,10 +210,16 @@ Renderer::Renderer(void *&window_handle) for (unsigned int k = 0;k < 8;k++) { - float border[4] = {0.f, 0.f, 0.f, 0.f}; gx_state.sampler[k].packed = 0; } + gx_state.zmode.testenable = false; + gx_state.zmode.updateenable = false; + gx_state.zmode.func = ZMode::NEVER; + + gx_state.raster.cull_mode = D3D11_CULL_NONE; + gx_state.raster.wireframe = false; + // Clear EFB textures float ClearColor[4] = { 0.f, 0.f, 0.f, 1.f }; D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), ClearColor); From 9bdfd4a833ffbd95f7636fb42db0004a896621b1 Mon Sep 17 00:00:00 2001 From: Yuriy O'Donnell Date: Thu, 16 Oct 2014 18:27:43 +0200 Subject: [PATCH 6/7] D3D: State cache now reduces number of blend state permutations by collapsing some states that have blending disabled --- Source/Core/VideoBackends/D3D/D3DState.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index 67436df56f..f24532b385 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -172,6 +172,14 @@ ID3D11SamplerState* StateCache::Get(SamplerState state) ID3D11BlendState* StateCache::Get(BlendState state) { + if (!state.blend_enable) + { + state.src_blend = D3D11_BLEND_ONE; + state.dst_blend = D3D11_BLEND_ZERO; + state.blend_op = D3D11_BLEND_OP_ADD; + state.use_dst_alpha = false; + } + auto it = m_blend.find(state.packed); if (it != m_blend.end()) From b78396847fe5e2244fab613ab527b3fd89f3da3a Mon Sep 17 00:00:00 2001 From: Yuriy O'Donnell Date: Fri, 17 Oct 2014 22:24:44 +0200 Subject: [PATCH 7/7] D3D: Removed SetBlendOp, SetSrcBlend and SetDestBlend as they are now trivial --- Source/Core/VideoBackends/D3D/Render.cpp | 45 +++++------------------- 1 file changed, 9 insertions(+), 36 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index a036e67b4c..dd4e5e62c5 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -551,33 +551,6 @@ void Renderer::ReinterpretPixelData(unsigned int convtype) D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); } -void SetSrcBlend(D3D11_BLEND val) -{ - // Colors should blend against SRC_ALPHA - if (val == D3D11_BLEND_SRC1_ALPHA) - val = D3D11_BLEND_SRC_ALPHA; - else if (val == D3D11_BLEND_INV_SRC1_ALPHA) - val = D3D11_BLEND_INV_SRC_ALPHA; - - gx_state.blend.src_blend = val; -} - -void SetDestBlend(D3D11_BLEND val) -{ - // Colors should blend against SRC_ALPHA - if (val == D3D11_BLEND_SRC1_ALPHA) - val = D3D11_BLEND_SRC_ALPHA; - else if (val == D3D11_BLEND_INV_SRC1_ALPHA) - val = D3D11_BLEND_INV_SRC_ALPHA; - - gx_state.blend.dst_blend = val; -} - -void SetBlendOp(D3D11_BLEND_OP val) -{ - gx_state.blend.blend_op = val; -} - void Renderer::SetBlendMode(bool forceUpdate) { // Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel @@ -612,18 +585,18 @@ void Renderer::SetBlendMode(bool forceUpdate) if (bpmem.blendmode.subtract) { gx_state.blend.blend_enable = true; - SetBlendOp(D3D11_BLEND_OP_REV_SUBTRACT); - SetSrcBlend(D3D11_BLEND_ONE); - SetDestBlend(D3D11_BLEND_ONE); + gx_state.blend.blend_op = D3D11_BLEND_OP_REV_SUBTRACT; + gx_state.blend.src_blend = D3D11_BLEND_ONE; + gx_state.blend.dst_blend = D3D11_BLEND_ONE; } else { gx_state.blend.blend_enable = (u32)bpmem.blendmode.blendenable; if (bpmem.blendmode.blendenable) { - SetBlendOp(D3D11_BLEND_OP_ADD); - SetSrcBlend(d3dSrcFactors[bpmem.blendmode.srcfactor]); - SetDestBlend(d3dDestFactors[bpmem.blendmode.dstfactor]); + gx_state.blend.blend_op = D3D11_BLEND_OP_ADD; + gx_state.blend.src_blend = d3dSrcFactors[bpmem.blendmode.srcfactor]; + gx_state.blend.dst_blend = d3dDestFactors[bpmem.blendmode.dstfactor]; } } } @@ -1181,9 +1154,9 @@ void Renderer::SetLogicOpMode() if (bpmem.blendmode.logicopenable) { gx_state.blend.blend_enable = true; - SetBlendOp(d3dLogicOps[bpmem.blendmode.logicmode]); - SetSrcBlend(d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]); - SetDestBlend(d3dLogicOpDestFactors[bpmem.blendmode.logicmode]); + gx_state.blend.blend_op = d3dLogicOps[bpmem.blendmode.logicmode]; + gx_state.blend.src_blend = d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]; + gx_state.blend.dst_blend = d3dLogicOpDestFactors[bpmem.blendmode.logicmode]; } else {