Implement AbstractGfx for Dx11

This commit is contained in:
Scott Mansell 2023-01-29 23:58:32 +13:00
parent 8bc8e43dd6
commit 5a2d119bda
8 changed files with 67 additions and 74 deletions

View File

@ -534,7 +534,7 @@
<ClInclude Include="VideoBackends\D3D\D3DBase.h" /> <ClInclude Include="VideoBackends\D3D\D3DBase.h" />
<ClInclude Include="VideoBackends\D3D\D3DBoundingBox.h" /> <ClInclude Include="VideoBackends\D3D\D3DBoundingBox.h" />
<ClInclude Include="VideoBackends\D3D\D3DPerfQuery.h" /> <ClInclude Include="VideoBackends\D3D\D3DPerfQuery.h" />
<ClInclude Include="VideoBackends\D3D\D3DRender.h" /> <ClInclude Include="VideoBackends\D3D\D3DGfx.h" />
<ClInclude Include="VideoBackends\D3D\D3DState.h" /> <ClInclude Include="VideoBackends\D3D\D3DState.h" />
<ClInclude Include="VideoBackends\D3D\D3DSwapChain.h" /> <ClInclude Include="VideoBackends\D3D\D3DSwapChain.h" />
<ClInclude Include="VideoBackends\D3D\D3DVertexManager.h" /> <ClInclude Include="VideoBackends\D3D\D3DVertexManager.h" />
@ -1148,7 +1148,7 @@
<ClCompile Include="VideoBackends\D3D\D3DMain.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DMain.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DNativeVertexFormat.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DNativeVertexFormat.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DPerfQuery.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DPerfQuery.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DRender.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DGfx.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DState.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DState.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DSwapChain.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DSwapChain.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DVertexManager.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DVertexManager.cpp" />

View File

@ -7,8 +7,8 @@ add_library(videod3d
D3DNativeVertexFormat.cpp D3DNativeVertexFormat.cpp
D3DPerfQuery.cpp D3DPerfQuery.cpp
D3DPerfQuery.h D3DPerfQuery.h
D3DRender.cpp D3DGfx.cpp
D3DRender.h D3DGfx.h
D3DState.cpp D3DState.cpp
D3DState.h D3DState.h
D3DSwapChain.cpp D3DSwapChain.cpp

View File

@ -1,7 +1,7 @@
// Copyright 2010 Dolphin Emulator Project // Copyright 2010 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/D3D/D3DRender.h" #include "VideoBackends/D3D/D3DGfx.h"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
@ -37,34 +37,31 @@
namespace DX11 namespace DX11
{ {
Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale) Gfx::Gfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
: ::Renderer(swap_chain ? swap_chain->GetWidth() : 0, swap_chain ? swap_chain->GetHeight() : 0, : m_backbuffer_scale(backbuffer_scale), m_swap_chain(std::move(swap_chain))
backbuffer_scale,
swap_chain ? swap_chain->GetFormat() : AbstractTextureFormat::Undefined),
m_swap_chain(std::move(swap_chain))
{ {
} }
Renderer::~Renderer() = default; Gfx::~Gfx() = default;
bool Renderer::IsHeadless() const bool Gfx::IsHeadless() const
{ {
return !m_swap_chain; return !m_swap_chain;
} }
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config, std::unique_ptr<AbstractTexture> Gfx::CreateTexture(const TextureConfig& config,
std::string_view name) std::string_view name)
{ {
return DXTexture::Create(config, name); return DXTexture::Create(config, name);
} }
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type, std::unique_ptr<AbstractStagingTexture> Gfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config) const TextureConfig& config)
{ {
return DXStagingTexture::Create(type, config); return DXStagingTexture::Create(type, config);
} }
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment, std::unique_ptr<AbstractFramebuffer> Gfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment) AbstractTexture* depth_attachment)
{ {
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment), return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
@ -72,7 +69,7 @@ std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture
} }
std::unique_ptr<AbstractShader> std::unique_ptr<AbstractShader>
Renderer::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name) Gfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
{ {
auto bytecode = DXShader::CompileShader(D3D::feature_level, stage, source); auto bytecode = DXShader::CompileShader(D3D::feature_level, stage, source);
if (!bytecode) if (!bytecode)
@ -81,21 +78,21 @@ Renderer::CreateShaderFromSource(ShaderStage stage, std::string_view source, std
return DXShader::CreateFromBytecode(stage, std::move(*bytecode), name); return DXShader::CreateFromBytecode(stage, std::move(*bytecode), name);
} }
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage, std::unique_ptr<AbstractShader> Gfx::CreateShaderFromBinary(ShaderStage stage,
const void* data, size_t length, const void* data, size_t length,
std::string_view name) std::string_view name)
{ {
return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length), name); return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length), name);
} }
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config, std::unique_ptr<AbstractPipeline> Gfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data, const void* cache_data,
size_t cache_data_length) size_t cache_data_length)
{ {
return DXPipeline::Create(config); return DXPipeline::Create(config);
} }
void Renderer::SetPipeline(const AbstractPipeline* pipeline) void Gfx::SetPipeline(const AbstractPipeline* pipeline)
{ {
const DXPipeline* dx_pipeline = static_cast<const DXPipeline*>(pipeline); const DXPipeline* dx_pipeline = static_cast<const DXPipeline*>(pipeline);
if (m_current_pipeline == dx_pipeline) if (m_current_pipeline == dx_pipeline)
@ -123,7 +120,7 @@ void Renderer::SetPipeline(const AbstractPipeline* pipeline)
} }
} }
void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc) void Gfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{ {
// TODO: Move to stateman // TODO: Move to stateman
const CD3D11_RECT rect(rc.left, rc.top, std::max(rc.right, rc.left + 1), const CD3D11_RECT rect(rc.left, rc.top, std::max(rc.right, rc.left + 1),
@ -131,7 +128,7 @@ void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
D3D::context->RSSetScissorRects(1, &rect); D3D::context->RSSetScissorRects(1, &rect);
} }
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth, void Gfx::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) float far_depth)
{ {
// TODO: Move to stateman // TODO: Move to stateman
@ -139,19 +136,19 @@ void Renderer::SetViewport(float x, float y, float width, float height, float ne
D3D::context->RSSetViewports(1, &vp); D3D::context->RSSetViewports(1, &vp);
} }
void Renderer::Draw(u32 base_vertex, u32 num_vertices) void Gfx::Draw(u32 base_vertex, u32 num_vertices)
{ {
D3D::stateman->Apply(); D3D::stateman->Apply();
D3D::context->Draw(num_vertices, base_vertex); D3D::context->Draw(num_vertices, base_vertex);
} }
void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) void Gfx::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
{ {
D3D::stateman->Apply(); D3D::stateman->Apply();
D3D::context->DrawIndexed(num_indices, base_index, base_vertex); D3D::context->DrawIndexed(num_indices, base_index, base_vertex);
} }
void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y, void Gfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
{ {
D3D::stateman->SetComputeShader(static_cast<const DXShader*>(shader)->GetD3DComputeShader()); D3D::stateman->SetComputeShader(static_cast<const DXShader*>(shader)->GetD3DComputeShader());
@ -159,25 +156,25 @@ void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize
D3D::context->Dispatch(groups_x, groups_y, groups_z); D3D::context->Dispatch(groups_x, groups_y, groups_z);
} }
void Renderer::BindBackbuffer(const ClearColor& clear_color) void Gfx::BindBackbuffer(const ClearColor& clear_color)
{ {
CheckForSwapChainChanges(); CheckForSwapChainChanges();
SetAndClearFramebuffer(m_swap_chain->GetFramebuffer(), clear_color); SetAndClearFramebuffer(m_swap_chain->GetFramebuffer(), clear_color);
} }
void Renderer::PresentBackbuffer() void Gfx::PresentBackbuffer()
{ {
m_swap_chain->Present(); m_swap_chain->Present();
} }
void Renderer::OnConfigChanged(u32 bits) void Gfx::OnConfigChanged(u32 bits)
{ {
// Quad-buffer changes require swap chain recreation. // Quad-buffer changes require swap chain recreation.
if (bits & CONFIG_CHANGE_BIT_STEREO_MODE && m_swap_chain) if (bits & CONFIG_CHANGE_BIT_STEREO_MODE && m_swap_chain)
m_swap_chain->SetStereo(SwapChain::WantsStereo()); m_swap_chain->SetStereo(SwapChain::WantsStereo());
} }
void Renderer::CheckForSwapChainChanges() void Gfx::CheckForSwapChainChanges()
{ {
const bool surface_changed = g_presenter->SurfaceChangedTestAndClear(); const bool surface_changed = g_presenter->SurfaceChangedTestAndClear();
const bool surface_resized = const bool surface_resized =
@ -194,11 +191,10 @@ void Renderer::CheckForSwapChainChanges()
m_swap_chain->ResizeSwapChain(); m_swap_chain->ResizeSwapChain();
} }
m_backbuffer_width = m_swap_chain->GetWidth(); g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
m_backbuffer_height = m_swap_chain->GetHeight();
} }
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer) void Gfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{ {
if (m_current_framebuffer == framebuffer) if (m_current_framebuffer == framebuffer)
return; return;
@ -219,12 +215,12 @@ void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
m_current_framebuffer = fb; m_current_framebuffer = fb;
} }
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) void Gfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{ {
SetFramebuffer(framebuffer); SetFramebuffer(framebuffer);
} }
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, void Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value) const ClearColor& color_value, float depth_value)
{ {
SetFramebuffer(framebuffer); SetFramebuffer(framebuffer);
@ -242,53 +238,58 @@ void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
} }
} }
void Renderer::SetTexture(u32 index, const AbstractTexture* texture) void Gfx::SetTexture(u32 index, const AbstractTexture* texture)
{ {
D3D::stateman->SetTexture(index, texture ? static_cast<const DXTexture*>(texture)->GetD3DSRV() : D3D::stateman->SetTexture(index, texture ? static_cast<const DXTexture*>(texture)->GetD3DSRV() :
nullptr); nullptr);
} }
void Renderer::SetSamplerState(u32 index, const SamplerState& state) void Gfx::SetSamplerState(u32 index, const SamplerState& state)
{ {
D3D::stateman->SetSampler(index, m_state_cache.Get(state)); D3D::stateman->SetSampler(index, m_state_cache.Get(state));
} }
void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) void Gfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
{ {
D3D::stateman->SetComputeUAV(texture ? static_cast<DXTexture*>(texture)->GetD3DUAV() : nullptr); D3D::stateman->SetComputeUAV(texture ? static_cast<DXTexture*>(texture)->GetD3DUAV() : nullptr);
} }
void Renderer::UnbindTexture(const AbstractTexture* texture) void Gfx::UnbindTexture(const AbstractTexture* texture)
{ {
if (D3D::stateman->UnsetTexture(static_cast<const DXTexture*>(texture)->GetD3DSRV()) != 0) if (D3D::stateman->UnsetTexture(static_cast<const DXTexture*>(texture)->GetD3DSRV()) != 0)
D3D::stateman->ApplyTextures(); D3D::stateman->ApplyTextures();
} }
std::unique_ptr<BoundingBox> Renderer::CreateBoundingBox() const void Gfx::Flush()
{
return std::make_unique<D3DBoundingBox>();
}
void Renderer::Flush()
{ {
D3D::context->Flush(); D3D::context->Flush();
} }
void Renderer::WaitForGPUIdle() void Gfx::WaitForGPUIdle()
{ {
// There is no glFinish() equivalent in D3D. // There is no glFinish() equivalent in D3D.
D3D::context->Flush(); D3D::context->Flush();
} }
void Renderer::SetFullscreen(bool enable_fullscreen) void Gfx::SetFullscreen(bool enable_fullscreen)
{ {
if (m_swap_chain) if (m_swap_chain)
m_swap_chain->SetFullscreen(enable_fullscreen); m_swap_chain->SetFullscreen(enable_fullscreen);
} }
bool Renderer::IsFullscreen() const bool Gfx::IsFullscreen() const
{ {
return m_swap_chain && m_swap_chain->GetFullscreen(); return m_swap_chain && m_swap_chain->GetFullscreen();
} }
SurfaceInfo Gfx::GetSurfaceInfo() const
{
return {
m_swap_chain ? static_cast<u32>(m_swap_chain->GetWidth()) : 0,
m_swap_chain ? static_cast<u32>(m_swap_chain->GetHeight()) : 0,
m_backbuffer_scale,
m_swap_chain ? m_swap_chain->GetFormat() : AbstractTextureFormat::Undefined
};
}
} // namespace DX11 } // namespace DX11

View File

@ -6,7 +6,7 @@
#include <d3d11.h> #include <d3d11.h>
#include <string_view> #include <string_view>
#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DState.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/AbstractGfx.h"
class BoundingBox; class BoundingBox;
@ -16,11 +16,11 @@ class SwapChain;
class DXTexture; class DXTexture;
class DXFramebuffer; class DXFramebuffer;
class Renderer : public ::Renderer class Gfx : public ::AbstractGfx
{ {
public: public:
Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale); Gfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale);
~Renderer() override; ~Gfx() override;
StateCache& GetStateCache() { return m_state_cache; } StateCache& GetStateCache() { return m_state_cache; }
@ -69,14 +69,14 @@ public:
void OnConfigChanged(u32 bits) override; void OnConfigChanged(u32 bits) override;
protected: SurfaceInfo GetSurfaceInfo() const override;
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
private: private:
void CheckForSwapChainChanges(); void CheckForSwapChainChanges();
StateCache m_state_cache; StateCache m_state_cache;
float m_backbuffer_scale;
std::unique_ptr<SwapChain> m_swap_chain; std::unique_ptr<SwapChain> m_swap_chain;
}; };
} // namespace DX11 } // namespace DX11

View File

@ -14,11 +14,12 @@
#include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DBoundingBox.h" #include "VideoBackends/D3D/D3DBoundingBox.h"
#include "VideoBackends/D3D/D3DPerfQuery.h" #include "VideoBackends/D3D/D3DPerfQuery.h"
#include "VideoBackends/D3D/D3DRender.h" #include "VideoBackends/D3D/D3DGfx.h"
#include "VideoBackends/D3D/D3DSwapChain.h" #include "VideoBackends/D3D/D3DSwapChain.h"
#include "VideoBackends/D3D/D3DVertexManager.h" #include "VideoBackends/D3D/D3DVertexManager.h"
#include "VideoBackends/D3DCommon/D3DCommon.h" #include "VideoBackends/D3DCommon/D3DCommon.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/ShaderCache.h" #include "VideoCommon/ShaderCache.h"
#include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/TextureCacheBase.h"
@ -143,7 +144,7 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
return false; return false;
FillBackendInfo(); FillBackendInfo();
InitializeShared(); UpdateActiveConfig();
std::unique_ptr<SwapChain> swap_chain; std::unique_ptr<SwapChain> swap_chain;
if (wsi.render_surface && !(swap_chain = SwapChain::Create(wsi))) if (wsi.render_surface && !(swap_chain = SwapChain::Create(wsi)))
@ -154,22 +155,13 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
return false; return false;
} }
g_renderer = std::make_unique<Renderer>(std::move(swap_chain), wsi.render_surface_scale); auto gfx = std::make_unique<DX11::Gfx>(std::move(swap_chain), wsi.render_surface_scale);
g_vertex_manager = std::make_unique<VertexManager>(); auto vertex_manager = std::make_unique<VertexManager>();
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>(); auto perf_query = std::make_unique<PerfQuery>();
g_framebuffer_manager = std::make_unique<FramebufferManager>(); auto bounding_box = std::make_unique<D3DBoundingBox>();
g_texture_cache = std::make_unique<TextureCacheBase>();
g_perf_query = std::make_unique<PerfQuery>();
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
!g_texture_cache->Initialize())
{
Shutdown();
return false;
}
g_shader_cache->InitializeShaderCache(); return InitializeShared(std::move(gfx), std::move(vertex_manager), std::move(perf_query),
return true; std::move(bounding_box));
} }
void VideoBackend::Shutdown() void VideoBackend::Shutdown()

View File

@ -7,7 +7,7 @@
#include "Common/EnumMap.h" #include "Common/EnumMap.h"
#include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DRender.h" #include "VideoBackends/D3D/D3DGfx.h"
#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DVertexManager.h" #include "VideoBackends/D3D/D3DVertexManager.h"
#include "VideoBackends/D3D/DXShader.h" #include "VideoBackends/D3D/DXShader.h"
@ -18,7 +18,7 @@ namespace DX11
std::mutex s_input_layout_lock; std::mutex s_input_layout_lock;
std::unique_ptr<NativeVertexFormat> std::unique_ptr<NativeVertexFormat>
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) Gfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{ {
return std::make_unique<D3DVertexFormat>(vtx_decl); return std::make_unique<D3DVertexFormat>(vtx_decl);
} }

View File

@ -13,7 +13,7 @@
#include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DBoundingBox.h" #include "VideoBackends/D3D/D3DBoundingBox.h"
#include "VideoBackends/D3D/D3DRender.h" #include "VideoBackends/D3D/D3DGfx.h"
#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3DCommon/D3DCommon.h" #include "VideoBackends/D3DCommon/D3DCommon.h"

View File

@ -7,7 +7,7 @@
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DRender.h" #include "VideoBackends/D3D/D3DGfx.h"
#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DVertexManager.h" #include "VideoBackends/D3D/D3DVertexManager.h"
#include "VideoBackends/D3D/DXShader.h" #include "VideoBackends/D3D/DXShader.h"
@ -32,7 +32,7 @@ DXPipeline::~DXPipeline() = default;
std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& config) std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& config)
{ {
StateCache& state_cache = static_cast<Renderer*>(g_renderer.get())->GetStateCache(); StateCache& state_cache = static_cast<Gfx*>(g_gfx.get())->GetStateCache();
ID3D11RasterizerState* rasterizer_state = state_cache.Get(config.rasterization_state); ID3D11RasterizerState* rasterizer_state = state_cache.Get(config.rasterization_state);
ID3D11DepthStencilState* depth_state = state_cache.Get(config.depth_state); ID3D11DepthStencilState* depth_state = state_cache.Get(config.depth_state);
ID3D11BlendState* blend_state = state_cache.Get(config.blending_state); ID3D11BlendState* blend_state = state_cache.Get(config.blending_state);