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;