mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
D3D: Support logic op through integer render target view
This brings D3D to parity with OpenGL and Vulkan.
This commit is contained in:
parent
c9d649d27c
commit
90051536bf
@ -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<D3D11_LOGIC_OP, 16> 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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#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<unsigned int>(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();
|
||||
}
|
||||
|
||||
|
@ -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<XFBSourceBase> 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;
|
||||
|
@ -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)
|
||||
|
@ -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++)
|
||||
{
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user