summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorAnthony <Helios747@users.noreply.github.com>2017-09-03 19:26:50 -0700
committerGitHub <noreply@github.com>2017-09-03 19:26:50 -0700
commitee6930a231a7ff1b25750deb84f613bddee90379 (patch)
tree5cfee129760ba3d4747f029cd47872c0b92a7aa6 /Source
parent26e777d80bb125e12a4a93e0e727c804a0facd34 (diff)
parent90051536bf53f66ca0e4c46105e481e08f1642f3 (diff)
Merge pull request #6013 from stenzek/d3d-logic-op
D3D: Implement logic op support
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/VideoBackends/D3D/D3DBase.cpp6
-rw-r--r--Source/Core/VideoBackends/D3D/D3DBase.h2
-rw-r--r--Source/Core/VideoBackends/D3D/D3DState.cpp31
-rw-r--r--Source/Core/VideoBackends/D3D/DXTexture.cpp4
-rw-r--r--Source/Core/VideoBackends/D3D/FramebufferManager.cpp58
-rw-r--r--Source/Core/VideoBackends/D3D/FramebufferManager.h11
-rw-r--r--Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp3
-rw-r--r--Source/Core/VideoBackends/D3D/Render.cpp21
-rw-r--r--Source/Core/VideoBackends/D3D/TextureCache.cpp8
-rw-r--r--Source/Core/VideoBackends/D3D/XFBEncoder.cpp3
-rw-r--r--Source/Core/VideoCommon/BPMemory.cpp13
-rw-r--r--Source/Core/VideoCommon/BPMemory.h2
-rw-r--r--Source/Core/VideoCommon/PixelShaderGen.cpp26
-rw-r--r--Source/Core/VideoCommon/PixelShaderGen.h3
-rw-r--r--Source/Core/VideoCommon/UberShaderPixel.cpp42
-rw-r--r--Source/Core/VideoCommon/UberShaderPixel.h1
16 files changed, 176 insertions, 58 deletions
diff --git a/Source/Core/VideoBackends/D3D/D3DBase.cpp b/Source/Core/VideoBackends/D3D/D3DBase.cpp
index 0434395575..dc0db95442 100644
--- a/Source/Core/VideoBackends/D3D/D3DBase.cpp
+++ b/Source/Core/VideoBackends/D3D/D3DBase.cpp
@@ -33,6 +33,7 @@ int d3d_dll_ref = 0;
namespace D3D
{
ID3D11Device* device = nullptr;
+ID3D11Device1* device1 = nullptr;
ID3D11DeviceContext* context = nullptr;
static IDXGISwapChain1* swapchain = nullptr;
static ID3D11Debug* debug = nullptr;
@@ -376,6 +377,10 @@ HRESULT Create(HWND wnd)
return E_FAIL;
}
+ hr = device->QueryInterface<ID3D11Device1>(&device1);
+ if (FAILED(hr))
+ WARN_LOG(VIDEO, "Missing Direct3D 11.1 support. Logical operations will not be supported.");
+
// prevent DXGI from responding to Alt+Enter, unfortunately DXGI_MWA_NO_ALT_ENTER
// does not work so we disable all monitoring of window messages. However this
// may make it more difficult for DXGI to handle display mode changes.
@@ -438,6 +443,7 @@ void Close()
context->Flush(); // immediately destroy device objects
SAFE_RELEASE(context);
+ SAFE_RELEASE(device1);
ULONG references = device->Release();
#if defined(_DEBUG) || defined(DEBUGFAST)
diff --git a/Source/Core/VideoBackends/D3D/D3DBase.h b/Source/Core/VideoBackends/D3D/D3DBase.h
index 224395a016..e1328494df 100644
--- a/Source/Core/VideoBackends/D3D/D3DBase.h
+++ b/Source/Core/VideoBackends/D3D/D3DBase.h
@@ -5,6 +5,7 @@
#pragma once
#include <d3d11.h>
+#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <dxgi1_2.h>
#include <vector>
@@ -56,6 +57,7 @@ HRESULT Create(HWND wnd);
void Close();
extern ID3D11Device* device;
+extern ID3D11Device1* device1;
extern ID3D11DeviceContext* context;
extern HWND hWnd;
extern bool bFrameInProgress;
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<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;
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 <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();
}
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<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;
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();
}
}
diff --git a/Source/Core/VideoCommon/BPMemory.cpp b/Source/Core/VideoCommon/BPMemory.cpp
index 26891ba941..8c0a2ec43a 100644
--- a/Source/Core/VideoCommon/BPMemory.cpp
+++ b/Source/Core/VideoCommon/BPMemory.cpp
@@ -10,6 +10,19 @@
// STATE_TO_SAVE
BPMemory bpmem;
+bool BlendMode::UseLogicOp() const
+{
+ // Logicop bit has lowest priority.
+ if (subtract || blendenable || !logicopenable)
+ return false;
+
+ // Fast path for Kirby's Return to Dreamland, they use it with dstAlpha.
+ if (logicmode == BlendMode::NOOP)
+ return false;
+
+ return true;
+}
+
float FogParam0::GetA() const
{
// scale mantissa from 11 to 23 bits
diff --git a/Source/Core/VideoCommon/BPMemory.h b/Source/Core/VideoCommon/BPMemory.h
index e2730c1472..fce322c4fd 100644
--- a/Source/Core/VideoCommon/BPMemory.h
+++ b/Source/Core/VideoCommon/BPMemory.h
@@ -648,6 +648,8 @@ union BlendMode
BitField<12, 4, LogicOp> logicmode;
u32 hex;
+
+ bool UseLogicOp() const;
};
union FogParam0
diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp
index d503b21176..5e561456ab 100644
--- a/Source/Core/VideoCommon/PixelShaderGen.cpp
+++ b/Source/Core/VideoCommon/PixelShaderGen.cpp
@@ -175,6 +175,7 @@ PixelShaderUid GetPixelShaderUid()
uid_data->rgba6_format =
bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor;
uid_data->dither = bpmem.blendmode.dither && uid_data->rgba6_format;
+ uid_data->uint_output = bpmem.blendmode.UseLogicOp();
u32 numStages = uid_data->genMode_numtevstages + 1;
@@ -434,7 +435,7 @@ static void SampleTexture(ShaderCode& out, const char* texcoords, const char* te
static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_data, APIType ApiType,
bool per_pixel_depth, bool use_dual_source);
static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data);
-static void WriteColor(ShaderCode& out, const pixel_shader_uid_data* uid_data,
+static void WriteColor(ShaderCode& out, APIType api_type, const pixel_shader_uid_data* uid_data,
bool use_dual_source);
ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host_config,
@@ -568,8 +569,12 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host
else // D3D
{
out.Write("void main(\n");
- out.Write(" out float4 ocol0 : SV_Target0,\n"
- " out float4 ocol1 : SV_Target1,\n%s"
+ if (uid_data->uint_output)
+ out.Write(" out uint4 ocol0 : SV_Target,\n");
+ else
+ out.Write(" out float4 ocol0 : SV_Target0,\n"
+ " out float4 ocol1 : SV_Target1,\n");
+ out.Write("%s"
" in float4 rawpos : SV_Position,\n",
uid_data->per_pixel_depth ? " out float depth : SV_Depth,\n" : "");
@@ -778,7 +783,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host
WriteFog(out, uid_data);
// Write the color and alpha values to the framebuffer
- WriteColor(out, uid_data, use_dual_source);
+ WriteColor(out, ApiType, uid_data, use_dual_source);
if (uid_data->bounding_box)
{
@@ -1302,8 +1307,19 @@ static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data)
out.Write("\tprev.rgb = (prev.rgb * (256 - ifog) + " I_FOGCOLOR ".rgb * ifog) >> 8;\n");
}
-static void WriteColor(ShaderCode& out, const pixel_shader_uid_data* uid_data, bool use_dual_source)
+static void WriteColor(ShaderCode& out, APIType api_type, const pixel_shader_uid_data* uid_data,
+ bool use_dual_source)
{
+ // D3D requires that the shader outputs be uint when writing to a uint render target for logic op.
+ if (api_type == APIType::D3D && uid_data->uint_output)
+ {
+ if (uid_data->rgba6_format)
+ out.Write("\tocol0 = uint4(prev & 0xFC);\n");
+ else
+ out.Write("\tocol0 = uint4(prev);\n");
+ return;
+ }
+
if (uid_data->rgba6_format)
out.Write("\tocol0.rgb = float3(prev.rgb >> 2) / 63.0;\n");
else
diff --git a/Source/Core/VideoCommon/PixelShaderGen.h b/Source/Core/VideoCommon/PixelShaderGen.h
index ee422bee8d..253dc59e22 100644
--- a/Source/Core/VideoCommon/PixelShaderGen.h
+++ b/Source/Core/VideoCommon/PixelShaderGen.h
@@ -43,7 +43,8 @@ struct pixel_shader_uid_data
u32 numColorChans : 2;
u32 rgba6_format : 1;
u32 dither : 1;
- u32 pad : 16;
+ u32 uint_output : 1;
+ u32 pad : 15;
u32 texMtxInfo_n_projection : 8; // 8x1 bit
u32 tevindref_bi0 : 3;
diff --git a/Source/Core/VideoCommon/UberShaderPixel.cpp b/Source/Core/VideoCommon/UberShaderPixel.cpp
index 01cca466cd..4e760408c5 100644
--- a/Source/Core/VideoCommon/UberShaderPixel.cpp
+++ b/Source/Core/VideoCommon/UberShaderPixel.cpp
@@ -25,6 +25,7 @@ PixelShaderUid GetPixelShaderUid()
(bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) ||
(!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !uid_data->early_depth) ||
(bpmem.zmode.testenable && bpmem.genMode.zfreeze);
+ uid_data->uint_output = bpmem.blendmode.UseLogicOp();
return out;
}
@@ -1163,18 +1164,29 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
" }\n"
"\n");
- // TODO: Do we still want to support two pass alpha blending?
- out.Write(" if (bpmem_rgba6_format)\n"
- " ocol0.rgb = float3(TevResult.rgb >> 2) / 63.0;\n"
- " else\n"
- " ocol0.rgb = float3(TevResult.rgb) / 255.0;\n"
- "\n"
- " if (bpmem_dstalpha != 0u)\n");
- out.Write(" ocol0.a = float(%s >> 2) / 63.0;\n",
- BitfieldExtract("bpmem_dstalpha", ConstantAlpha().alpha).c_str());
- out.Write(" else\n"
- " ocol0.a = float(TevResult.a >> 2) / 63.0;\n"
- " \n");
+ // D3D requires that the shader outputs be uint when writing to a uint render target for logic op.
+ if (ApiType == APIType::D3D && uid_data->uint_output)
+ {
+ out.Write(" if (bpmem_rgba6_format)\n"
+ " ocol0 = uint4(TevResult & 0xFC);\n"
+ " else\n"
+ " ocol0 = uint4(TevResult);\n"
+ "\n");
+ }
+ else
+ {
+ out.Write(" if (bpmem_rgba6_format)\n"
+ " ocol0.rgb = float3(TevResult.rgb >> 2) / 63.0;\n"
+ " else\n"
+ " ocol0.rgb = float3(TevResult.rgb) / 255.0;\n"
+ "\n"
+ " if (bpmem_dstalpha != 0u)\n");
+ out.Write(" ocol0.a = float(%s >> 2) / 63.0;\n",
+ BitfieldExtract("bpmem_dstalpha", ConstantAlpha().alpha).c_str());
+ out.Write(" else\n"
+ " ocol0.a = float(TevResult.a >> 2) / 63.0;\n"
+ " \n");
+ }
if (use_dual_source)
{
@@ -1259,7 +1271,11 @@ void EnumeratePixelShaderUids(const std::function<void(const PixelShaderUid&)>&
continue;
puid->per_pixel_depth = per_pixel_depth != 0;
- callback(uid);
+ for (u32 uint_output = 0; uint_output < 2; uint_output++)
+ {
+ puid->uint_output = uint_output;
+ callback(uid);
+ }
}
}
}
diff --git a/Source/Core/VideoCommon/UberShaderPixel.h b/Source/Core/VideoCommon/UberShaderPixel.h
index d7dc8109e8..3a5a8f8435 100644
--- a/Source/Core/VideoCommon/UberShaderPixel.h
+++ b/Source/Core/VideoCommon/UberShaderPixel.h
@@ -15,6 +15,7 @@ struct pixel_ubershader_uid_data
u32 num_texgens : 4;
u32 early_depth : 1;
u32 per_pixel_depth : 1;
+ u32 uint_output : 1;
u32 NumValues() const { return sizeof(pixel_ubershader_uid_data); }
};