diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index 67536a4fa3..ab67fbf48a 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -358,6 +358,37 @@ ID3D11BlendState* StateCache::Get(BlendingState state) if (it != m_blend.end()) return it->second; + if (state.logicopenable && D3D::device1) + { + D3D11_BLEND_DESC1 desc = {}; + D3D11_RENDER_TARGET_BLEND_DESC1& tdesc = desc.RenderTarget[0]; + if (state.colorupdate) + tdesc.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | + D3D11_COLOR_WRITE_ENABLE_BLUE; + else + tdesc.RenderTargetWriteMask = 0; + if (state.alphaupdate) + tdesc.RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; + + static constexpr std::array logic_ops = { + {D3D11_LOGIC_OP_CLEAR, D3D11_LOGIC_OP_AND, D3D11_LOGIC_OP_AND_REVERSE, D3D11_LOGIC_OP_COPY, + D3D11_LOGIC_OP_AND_INVERTED, D3D11_LOGIC_OP_NOOP, D3D11_LOGIC_OP_XOR, D3D11_LOGIC_OP_OR, + D3D11_LOGIC_OP_NOR, D3D11_LOGIC_OP_EQUIV, D3D11_LOGIC_OP_INVERT, D3D11_LOGIC_OP_OR_REVERSE, + D3D11_LOGIC_OP_COPY_INVERTED, D3D11_LOGIC_OP_OR_INVERTED, D3D11_LOGIC_OP_NAND, + D3D11_LOGIC_OP_SET}}; + tdesc.LogicOpEnable = TRUE; + tdesc.LogicOp = logic_ops[state.logicmode]; + + ID3D11BlendState1* res; + HRESULT hr = D3D::device1->CreateBlendState1(&desc, &res); + if (SUCCEEDED(hr)) + { + D3D::SetDebugObjectName(res, "blend state used to emulate the GX pipeline"); + m_blend.emplace(state.hex, res); + return res; + } + } + D3D11_BLEND_DESC desc = {}; desc.AlphaToCoverageEnable = FALSE; desc.IndependentBlendEnable = FALSE; diff --git a/Source/Core/VideoBackends/D3D/DXTexture.cpp b/Source/Core/VideoBackends/D3D/DXTexture.cpp index 712af7fc9a..1ac52e76b2 100644 --- a/Source/Core/VideoBackends/D3D/DXTexture.cpp +++ b/Source/Core/VideoBackends/D3D/DXTexture.cpp @@ -181,9 +181,7 @@ void DXTexture::CopyRectangleFromTexture(const AbstractTexture* source, VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); - + FramebufferManager::BindEFBRenderTarget(); g_renderer->RestoreAPIState(); } diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp index 5618f99e41..5853b8e849 100644 --- a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp @@ -5,6 +5,7 @@ #include "VideoBackends/D3D/FramebufferManager.h" #include +#include #include "Common/CommonTypes.h" #include "Core/HW/Memmap.h" @@ -21,6 +22,7 @@ namespace DX11 { static XFBEncoder s_xfbEncoder; +static bool s_integer_efb_render_target = false; FramebufferManager::Efb FramebufferManager::m_efb; unsigned int FramebufferManager::m_target_width; @@ -30,6 +32,7 @@ D3DTexture2D*& FramebufferManager::GetEFBColorTexture() { return m_efb.color_tex; } + D3DTexture2D*& FramebufferManager::GetEFBColorReadTexture() { return m_efb.color_read_texture; @@ -86,8 +89,7 @@ D3DTexture2D*& FramebufferManager::GetResolvedEFBDepthTexture() PixelShaderCache::GetDepthResolveProgram(), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader()); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); + BindEFBRenderTarget(); g_renderer->RestoreAPIState(); return m_efb.resolved_depth_tex; @@ -98,6 +100,33 @@ D3DTexture2D*& FramebufferManager::GetResolvedEFBDepthTexture() } } +void FramebufferManager::SwapReinterpretTexture() +{ + std::swap(m_efb.color_tex, m_efb.color_temp_tex); + std::swap(m_efb.color_int_rtv, m_efb.color_temp_int_rtv); +} + +void FramebufferManager::SetIntegerEFBRenderTarget(bool enabled) +{ + if (s_integer_efb_render_target == enabled) + return; + + // We only use UINT render targets for logic ops, which is only supported with D3D11.1. + if (!D3D::device1) + return; + + s_integer_efb_render_target = enabled; + BindEFBRenderTarget(); +} + +void FramebufferManager::BindEFBRenderTarget(bool bind_depth) +{ + ID3D11RenderTargetView* rtv = + s_integer_efb_render_target ? m_efb.color_int_rtv : m_efb.color_tex->GetRTV(); + ID3D11DepthStencilView* dsv = bind_depth ? m_efb.depth_tex->GetDSV() : nullptr; + D3D::context->OMSetRenderTargets(1, &rtv, dsv); +} + FramebufferManager::FramebufferManager(int target_width, int target_height) { m_target_width = static_cast(std::max(target_width, 1)); @@ -114,7 +143,7 @@ FramebufferManager::FramebufferManager(int target_width, int target_height) // EFB color texture - primary render target texdesc = - CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, + CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_TYPELESS, m_target_width, m_target_height, m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); @@ -124,6 +153,7 @@ FramebufferManager::FramebufferManager(int target_width, int target_height) buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET), DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1)); + SAFE_RELEASE(buf); D3D::SetDebugObjectName(m_efb.color_tex->GetTex(), "EFB color texture"); D3D::SetDebugObjectName(m_efb.color_tex->GetSRV(), "EFB color texture shader resource view"); @@ -131,7 +161,7 @@ FramebufferManager::FramebufferManager(int target_width, int target_height) // Temporary EFB color texture - used in ReinterpretPixelData texdesc = - CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, + CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_TYPELESS, m_target_width, m_target_height, m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); @@ -148,6 +178,19 @@ FramebufferManager::FramebufferManager(int target_width, int target_height) D3D::SetDebugObjectName(m_efb.color_temp_tex->GetRTV(), "EFB color temp texture render target view"); + // Integer render targets for EFB, used for logic op + CD3D11_RENDER_TARGET_VIEW_DESC int_rtv_desc(m_efb.color_tex->GetTex(), + g_ActiveConfig.iMultisamples > 1 ? + D3D11_RTV_DIMENSION_TEXTURE2DMS : + D3D11_RTV_DIMENSION_TEXTURE2D, + DXGI_FORMAT_R8G8B8A8_UINT); + hr = D3D::device->CreateRenderTargetView(m_efb.color_tex->GetTex(), &int_rtv_desc, + &m_efb.color_int_rtv); + CHECK(hr == S_OK, "create EFB integer RTV(hr=%#x)", hr); + hr = D3D::device->CreateRenderTargetView(m_efb.color_temp_tex->GetTex(), &int_rtv_desc, + &m_efb.color_temp_int_rtv); + CHECK(hr == S_OK, "create EFB integer RTV(hr=%#x)", hr); + // Render buffer for AccessEFB (color data) texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET); hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); @@ -241,6 +284,7 @@ FramebufferManager::FramebufferManager(int target_width, int target_height) } s_xfbEncoder.Init(); + s_integer_efb_render_target = false; } FramebufferManager::~FramebufferManager() @@ -248,7 +292,9 @@ FramebufferManager::~FramebufferManager() s_xfbEncoder.Shutdown(); SAFE_RELEASE(m_efb.color_tex); + SAFE_RELEASE(m_efb.color_int_rtv); SAFE_RELEASE(m_efb.color_temp_tex); + SAFE_RELEASE(m_efb.color_temp_int_rtv); SAFE_RELEASE(m_efb.color_staging_buf); SAFE_RELEASE(m_efb.color_read_texture); SAFE_RELEASE(m_efb.resolved_color_tex); @@ -308,9 +354,7 @@ void XFBSource::CopyEFB(float Gamma) VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader(), Gamma); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); - + FramebufferManager::BindEFBRenderTarget(); g_renderer->RestoreAPIState(); } diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.h b/Source/Core/VideoBackends/D3D/FramebufferManager.h index bded95df47..f38a60edc0 100644 --- a/Source/Core/VideoBackends/D3D/FramebufferManager.h +++ b/Source/Core/VideoBackends/D3D/FramebufferManager.h @@ -75,12 +75,9 @@ public: static D3DTexture2D*& GetResolvedEFBDepthTexture(); static D3DTexture2D*& GetEFBColorTempTexture() { return m_efb.color_temp_tex; } - static void SwapReinterpretTexture() - { - D3DTexture2D* swaptex = GetEFBColorTempTexture(); - m_efb.color_temp_tex = GetEFBColorTexture(); - m_efb.color_tex = swaptex; - } + static void SwapReinterpretTexture(); + static void SetIntegerEFBRenderTarget(bool enabled); + static void BindEFBRenderTarget(bool bind_depth = true); private: std::unique_ptr CreateXFBSource(unsigned int target_width, @@ -94,6 +91,7 @@ private: static struct Efb { D3DTexture2D* color_tex; + ID3D11RenderTargetView* color_int_rtv; ID3D11Texture2D* color_staging_buf; D3DTexture2D* color_read_texture; @@ -102,6 +100,7 @@ private: D3DTexture2D* depth_read_texture; D3DTexture2D* color_temp_tex; + ID3D11RenderTargetView* color_temp_int_rtv; D3DTexture2D* resolved_color_tex; D3DTexture2D* resolved_depth_tex; diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp index b89e812879..9ac10e3a77 100644 --- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp @@ -163,9 +163,8 @@ void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_w } // Restore API + FramebufferManager::BindEFBRenderTarget(); g_renderer->RestoreAPIState(); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); } ID3D11PixelShader* PSTextureEncoder::GetEncodingPixelShader(const EFBCopyParams& params) diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 1bf929caa5..ae50045c26 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -266,8 +266,7 @@ Renderer::Renderer() : ::Renderer(D3D::GetBackBufferWidth(), D3D::GetBackBufferH D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)m_target_width, (float)m_target_height); D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); + FramebufferManager::BindEFBRenderTarget(); D3D::BeginFrame(); } @@ -402,8 +401,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) VertexShaderCache::GetSimpleInputLayout()); // Restore expected game state. - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); + FramebufferManager::BindEFBRenderTarget(); RestoreAPIState(); // Copy the pixel from the renderable to cpu-readable buffer. @@ -478,8 +476,7 @@ void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight()); D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - nullptr); + FramebufferManager::BindEFBRenderTarget(false); } else // if (type == EFBAccessType::PokeZ) { @@ -490,9 +487,7 @@ void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight()); D3D::context->RSSetViewports(1, &vp); - - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); + FramebufferManager::BindEFBRenderTarget(); } D3D::DrawEFBPokeQuads(type, points, num_points); @@ -590,6 +585,7 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(), (float)targetRc.GetHeight(), 0.f, 1.f); D3D::context->RSSetViewports(1, &vp); + FramebufferManager::SetIntegerEFBRenderTarget(false); // Color is passed in bgra mode so we need to convert it to rgba u32 rgbaColor = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000); @@ -636,8 +632,7 @@ void Renderer::ReinterpretPixelData(unsigned int convtype) RestoreAPIState(); FramebufferManager::SwapReinterpretTexture(); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); + FramebufferManager::BindEFBRenderTarget(); } void Renderer::SetBlendingState(const BlendingState& state) @@ -845,8 +840,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, // begin next frame RestoreAPIState(); D3D::BeginFrame(); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); + FramebufferManager::BindEFBRenderTarget(); SetViewport(); } @@ -873,6 +867,7 @@ void Renderer::ApplyState() D3D::stateman->PushBlendState(s_gx_state_cache.Get(s_gx_state.blend)); D3D::stateman->PushDepthState(s_gx_state_cache.Get(s_gx_state.zmode)); D3D::stateman->PushRasterizerState(s_gx_state_cache.Get(s_gx_state.raster)); + FramebufferManager::SetIntegerEFBRenderTarget(s_gx_state.blend.logicopenable); for (size_t stage = 0; stage < s_gx_state.samplers.size(); stage++) { diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp index 36ed5f96bb..578a488bde 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -167,9 +167,7 @@ void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source, VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader()); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); - + FramebufferManager::BindEFBRenderTarget(); g_renderer->RestoreAPIState(); } @@ -296,9 +294,7 @@ void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader()); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); - + FramebufferManager::BindEFBRenderTarget(); g_renderer->RestoreAPIState(); } } diff --git a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp b/Source/Core/VideoBackends/D3D/XFBEncoder.cpp index 7b10b02091..696c5c35e0 100644 --- a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/XFBEncoder.cpp @@ -362,7 +362,6 @@ void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcR // Restore API g_renderer->RestoreAPIState(); D3D::stateman->Apply(); // force unbind efb texture as shader resource - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); + FramebufferManager::BindEFBRenderTarget(); } }