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;