summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2023-06-09 13:40:21 +0200
committerGitHub <noreply@github.com>2023-06-09 13:40:21 +0200
commit092773ad0cd31cb0f3d111254e4e0bdb24f2c795 (patch)
tree817b91a21f01b8fdeacfdbc084f5aa6b9bad312b /Source/Core
parente16791f2ca5b6db29a54bc3b189d168632e4974b (diff)
parent8c3dc5b0d69bbe8a11b9cb0499f25f1164176f7c (diff)
Merge pull request #11859 from iwubcode/backend-multi-output
VideoBackends: add support to allow rendering to multiple output targets
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/VideoBackends/D3D/D3DGfx.cpp30
-rw-r--r--Source/Core/VideoBackends/D3D/D3DGfx.h3
-rw-r--r--Source/Core/VideoBackends/D3D/D3DState.cpp3
-rw-r--r--Source/Core/VideoBackends/D3D/D3DSwapChain.cpp2
-rw-r--r--Source/Core/VideoBackends/D3D/DXTexture.cpp96
-rw-r--r--Source/Core/VideoBackends/D3D/DXTexture.h24
-rw-r--r--Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp56
-rw-r--r--Source/Core/VideoBackends/D3D12/D3D12Gfx.h3
-rw-r--r--Source/Core/VideoBackends/D3D12/D3D12SwapChain.cpp2
-rw-r--r--Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp92
-rw-r--r--Source/Core/VideoBackends/D3D12/DX12Texture.cpp133
-rw-r--r--Source/Core/VideoBackends/D3D12/DX12Texture.h25
-rw-r--r--Source/Core/VideoBackends/Metal/MTLGfx.h3
-rw-r--r--Source/Core/VideoBackends/Metal/MTLGfx.mm3
-rw-r--r--Source/Core/VideoBackends/Metal/MTLTexture.mm2
-rw-r--r--Source/Core/VideoBackends/Null/NullGfx.cpp8
-rw-r--r--Source/Core/VideoBackends/Null/NullGfx.h3
-rw-r--r--Source/Core/VideoBackends/Null/NullTexture.cpp16
-rw-r--r--Source/Core/VideoBackends/Null/NullTexture.h6
-rw-r--r--Source/Core/VideoBackends/OGL/OGLConfig.cpp3
-rw-r--r--Source/Core/VideoBackends/OGL/OGLConfig.h1
-rw-r--r--Source/Core/VideoBackends/OGL/OGLGfx.cpp12
-rw-r--r--Source/Core/VideoBackends/OGL/OGLGfx.h3
-rw-r--r--Source/Core/VideoBackends/OGL/OGLTexture.cpp36
-rw-r--r--Source/Core/VideoBackends/OGL/OGLTexture.h6
-rw-r--r--Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp70
-rw-r--r--Source/Core/VideoBackends/Software/SWGfx.cpp8
-rw-r--r--Source/Core/VideoBackends/Software/SWGfx.h3
-rw-r--r--Source/Core/VideoBackends/Software/SWTexture.cpp16
-rw-r--r--Source/Core/VideoBackends/Software/SWTexture.h6
-rw-r--r--Source/Core/VideoBackends/Vulkan/ObjectCache.cpp85
-rw-r--r--Source/Core/VideoBackends/Vulkan/ObjectCache.h4
-rw-r--r--Source/Core/VideoBackends/Vulkan/VKGfx.cpp89
-rw-r--r--Source/Core/VideoBackends/Vulkan/VKGfx.h3
-rw-r--r--Source/Core/VideoBackends/Vulkan/VKPipeline.cpp31
-rw-r--r--Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp2
-rw-r--r--Source/Core/VideoBackends/Vulkan/VKTexture.cpp86
-rw-r--r--Source/Core/VideoBackends/Vulkan/VKTexture.h17
-rw-r--r--Source/Core/VideoCommon/AbstractFramebuffer.cpp29
-rw-r--r--Source/Core/VideoCommon/AbstractFramebuffer.h7
-rw-r--r--Source/Core/VideoCommon/AbstractGfx.h4
-rw-r--r--Source/Core/VideoCommon/GXPipelineTypes.h2
-rw-r--r--Source/Core/VideoCommon/RenderState.cpp1
-rw-r--r--Source/Core/VideoCommon/RenderState.h6
44 files changed, 713 insertions, 327 deletions
diff --git a/Source/Core/VideoBackends/D3D/D3DGfx.cpp b/Source/Core/VideoBackends/D3D/D3DGfx.cpp
index 35be881e01..5bae0477c7 100644
--- a/Source/Core/VideoBackends/D3D/D3DGfx.cpp
+++ b/Source/Core/VideoBackends/D3D/D3DGfx.cpp
@@ -61,11 +61,13 @@ std::unique_ptr<AbstractStagingTexture> Gfx::CreateStagingTexture(StagingTexture
return DXStagingTexture::Create(type, config);
}
-std::unique_ptr<AbstractFramebuffer> Gfx::CreateFramebuffer(AbstractTexture* color_attachment,
- AbstractTexture* depth_attachment)
+std::unique_ptr<AbstractFramebuffer>
+Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
- static_cast<DXTexture*>(depth_attachment));
+ static_cast<DXTexture*>(depth_attachment),
+ std::move(additional_color_attachments));
}
std::unique_ptr<AbstractShader>
@@ -202,15 +204,7 @@ void Gfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
// We can't leave the framebuffer bound as a texture and a render target.
DXFramebuffer* fb = static_cast<DXFramebuffer*>(framebuffer);
- if ((fb->GetColorAttachment() &&
- D3D::stateman->UnsetTexture(
- static_cast<DXTexture*>(fb->GetColorAttachment())->GetD3DSRV()) != 0) ||
- (fb->GetDepthAttachment() &&
- D3D::stateman->UnsetTexture(
- static_cast<DXTexture*>(fb->GetDepthAttachment())->GetD3DSRV()) != 0))
- {
- D3D::stateman->ApplyTextures();
- }
+ fb->Unbind();
D3D::stateman->SetFramebuffer(fb);
m_current_framebuffer = fb;
@@ -227,16 +221,8 @@ void Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearCo
SetFramebuffer(framebuffer);
D3D::stateman->Apply();
- if (framebuffer->GetColorFormat() != AbstractTextureFormat::Undefined)
- {
- D3D::context->ClearRenderTargetView(
- static_cast<const DXFramebuffer*>(framebuffer)->GetRTVArray()[0], color_value.data());
- }
- if (framebuffer->GetDepthFormat() != AbstractTextureFormat::Undefined)
- {
- D3D::context->ClearDepthStencilView(static_cast<const DXFramebuffer*>(framebuffer)->GetDSV(),
- D3D11_CLEAR_DEPTH, depth_value, 0);
- }
+ DXFramebuffer* fb = static_cast<DXFramebuffer*>(framebuffer);
+ fb->Clear(color_value, depth_value);
}
void Gfx::SetTexture(u32 index, const AbstractTexture* texture)
diff --git a/Source/Core/VideoBackends/D3D/D3DGfx.h b/Source/Core/VideoBackends/D3D/D3DGfx.h
index 853599224c..e23867e73b 100644
--- a/Source/Core/VideoBackends/D3D/D3DGfx.h
+++ b/Source/Core/VideoBackends/D3D/D3DGfx.h
@@ -41,7 +41,8 @@ public:
const void* cache_data = nullptr,
size_t cache_data_length = 0) override;
std::unique_ptr<AbstractFramebuffer>
- CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
+ CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments) override;
void SetPipeline(const AbstractPipeline* pipeline) override;
void SetFramebuffer(AbstractFramebuffer* framebuffer) override;
diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp
index 7beec54611..06f01792f5 100644
--- a/Source/Core/VideoBackends/D3D/D3DState.cpp
+++ b/Source/Core/VideoBackends/D3D/D3DState.cpp
@@ -41,7 +41,8 @@ void StateManager::Apply()
m_pending.framebuffer->GetNumRTVs(),
m_pending.use_integer_rtv ? m_pending.framebuffer->GetIntegerRTVArray() :
m_pending.framebuffer->GetRTVArray(),
- m_pending.framebuffer->GetDSV(), 2, 1, &m_pending.uav, nullptr);
+ m_pending.framebuffer->GetDSV(), m_pending.framebuffer->GetNumRTVs() + 1, 1,
+ &m_pending.uav, nullptr);
}
else
{
diff --git a/Source/Core/VideoBackends/D3D/D3DSwapChain.cpp b/Source/Core/VideoBackends/D3D/D3DSwapChain.cpp
index c3f2a9094a..83c366bc8e 100644
--- a/Source/Core/VideoBackends/D3D/D3DSwapChain.cpp
+++ b/Source/Core/VideoBackends/D3D/D3DSwapChain.cpp
@@ -39,7 +39,7 @@ bool SwapChain::CreateSwapChainBuffers()
if (!m_texture)
return false;
- m_framebuffer = DXFramebuffer::Create(m_texture.get(), nullptr);
+ m_framebuffer = DXFramebuffer::Create(m_texture.get(), nullptr, {});
if (!m_framebuffer)
return false;
diff --git a/Source/Core/VideoBackends/D3D/DXTexture.cpp b/Source/Core/VideoBackends/D3D/DXTexture.cpp
index c78b7cabbc..c20a8d9204 100644
--- a/Source/Core/VideoBackends/D3D/DXTexture.cpp
+++ b/Source/Core/VideoBackends/D3D/DXTexture.cpp
@@ -324,23 +324,79 @@ void DXStagingTexture::Flush()
}
DXFramebuffer::DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
u32 width, u32 height, u32 layers, u32 samples,
ComPtr<ID3D11RenderTargetView> rtv,
ComPtr<ID3D11RenderTargetView> integer_rtv,
- ComPtr<ID3D11DepthStencilView> dsv)
- : AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
- height, layers, samples),
- m_rtv(std::move(rtv)), m_integer_rtv(std::move(integer_rtv)), m_dsv(std::move(dsv))
+ ComPtr<ID3D11DepthStencilView> dsv,
+ std::vector<ComPtr<ID3D11RenderTargetView>> additional_rtvs)
+ : AbstractFramebuffer(color_attachment, depth_attachment,
+ std::move(additional_color_attachments), color_format, depth_format,
+ width, height, layers, samples),
+ m_integer_rtv(std::move(integer_rtv)), m_dsv(std::move(dsv))
{
+ m_render_targets.push_back(std::move(rtv));
+ for (auto additional_rtv : additional_rtvs)
+ {
+ m_render_targets.push_back(std::move(additional_rtv));
+ }
+ for (auto& render_target : m_render_targets)
+ {
+ m_render_targets_raw.push_back(render_target.Get());
+ }
}
DXFramebuffer::~DXFramebuffer() = default;
-std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(DXTexture* color_attachment,
- DXTexture* depth_attachment)
+void DXFramebuffer::Unbind()
+{
+ bool should_apply = false;
+ if (GetColorAttachment() &&
+ D3D::stateman->UnsetTexture(static_cast<DXTexture*>(GetColorAttachment())->GetD3DSRV()) != 0)
+ {
+ should_apply = true;
+ }
+
+ if (GetDepthAttachment() &&
+ D3D::stateman->UnsetTexture(static_cast<DXTexture*>(GetDepthAttachment())->GetD3DSRV()) != 0)
+ {
+ should_apply = true;
+ }
+
+ for (auto additional_color_attachment : m_additional_color_attachments)
+ {
+ if (D3D::stateman->UnsetTexture(
+ static_cast<DXTexture*>(additional_color_attachment)->GetD3DSRV()) != 0)
+ {
+ should_apply = true;
+ }
+ }
+
+ if (should_apply)
+ {
+ D3D::stateman->ApplyTextures();
+ }
+}
+
+void DXFramebuffer::Clear(const ClearColor& color_value, float depth_value)
+{
+ if (GetDepthFormat() != AbstractTextureFormat::Undefined)
+ {
+ D3D::context->ClearDepthStencilView(GetDSV(), D3D11_CLEAR_DEPTH, depth_value, 0);
+ }
+
+ for (auto render_target : m_render_targets_raw)
+ {
+ D3D::context->ClearRenderTargetView(render_target, color_value.data());
+ }
+}
+
+std::unique_ptr<DXFramebuffer>
+DXFramebuffer::Create(DXTexture* color_attachment, DXTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
- if (!ValidateConfig(color_attachment, depth_attachment))
+ if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments))
return nullptr;
const AbstractTextureFormat color_format =
@@ -382,6 +438,25 @@ std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(DXTexture* color_attachment
}
}
+ std::vector<ComPtr<ID3D11RenderTargetView>> additional_rtvs;
+ for (auto additional_color_attachment : additional_color_attachments)
+ {
+ ComPtr<ID3D11RenderTargetView> additional_rtv;
+ CD3D11_RENDER_TARGET_VIEW_DESC desc(
+ additional_color_attachment->IsMultisampled() ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY :
+ D3D11_RTV_DIMENSION_TEXTURE2DARRAY,
+ D3DCommon::GetRTVFormatForAbstractFormat(additional_color_attachment->GetFormat(), false),
+ 0, 0, 1);
+ HRESULT hr = D3D::device->CreateRenderTargetView(
+ static_cast<DXTexture*>(additional_color_attachment)->GetD3DTexture(), &desc,
+ additional_rtv.GetAddressOf());
+ ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Create render target view for framebuffer: {}",
+ DX11HRWrap(hr));
+ if (FAILED(hr))
+ return nullptr;
+ additional_rtvs.push_back(std::move(additional_rtv));
+ }
+
ComPtr<ID3D11DepthStencilView> dsv;
if (depth_attachment)
{
@@ -398,9 +473,10 @@ std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(DXTexture* color_attachment
return nullptr;
}
- return std::make_unique<DXFramebuffer>(color_attachment, depth_attachment, color_format,
- depth_format, width, height, layers, samples,
- std::move(rtv), std::move(integer_rtv), std::move(dsv));
+ return std::make_unique<DXFramebuffer>(
+ color_attachment, depth_attachment, std::move(additional_color_attachments), color_format,
+ depth_format, width, height, layers, samples, std::move(rtv), std::move(integer_rtv),
+ std::move(dsv), std::move(additional_rtvs));
}
} // namespace DX11
diff --git a/Source/Core/VideoBackends/D3D/DXTexture.h b/Source/Core/VideoBackends/D3D/DXTexture.h
index 2694903107..7997ca6f18 100644
--- a/Source/Core/VideoBackends/D3D/DXTexture.h
+++ b/Source/Core/VideoBackends/D3D/DXTexture.h
@@ -7,13 +7,15 @@
#include <memory>
#include <string>
#include <string_view>
-
+#include <vector>
#include "Common/CommonTypes.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoCommon/AbstractFramebuffer.h"
+#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"
+#include "VideoCommon/RenderBase.h"
namespace DX11
{
@@ -81,20 +83,28 @@ class DXFramebuffer final : public AbstractFramebuffer
{
public:
DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
u32 height, u32 layers, u32 samples, ComPtr<ID3D11RenderTargetView> rtv,
- ComPtr<ID3D11RenderTargetView> integer_rtv, ComPtr<ID3D11DepthStencilView> dsv);
+ ComPtr<ID3D11RenderTargetView> integer_rtv, ComPtr<ID3D11DepthStencilView> dsv,
+ std::vector<ComPtr<ID3D11RenderTargetView>> additional_rtvs);
~DXFramebuffer() override;
- ID3D11RenderTargetView* const* GetRTVArray() const { return m_rtv.GetAddressOf(); }
+ ID3D11RenderTargetView* const* GetRTVArray() const { return m_render_targets_raw.data(); }
ID3D11RenderTargetView* const* GetIntegerRTVArray() const { return m_integer_rtv.GetAddressOf(); }
- UINT GetNumRTVs() const { return m_rtv ? 1 : 0; }
+ UINT GetNumRTVs() const { return static_cast<UINT>(m_render_targets_raw.size()); }
ID3D11DepthStencilView* GetDSV() const { return m_dsv.Get(); }
- static std::unique_ptr<DXFramebuffer> Create(DXTexture* color_attachment,
- DXTexture* depth_attachment);
+
+ void Unbind();
+ void Clear(const ClearColor& color_value, float depth_value);
+
+ static std::unique_ptr<DXFramebuffer>
+ Create(DXTexture* color_attachment, DXTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments);
protected:
- ComPtr<ID3D11RenderTargetView> m_rtv;
+ std::vector<ComPtr<ID3D11RenderTargetView>> m_render_targets;
+ std::vector<ID3D11RenderTargetView*> m_render_targets_raw;
ComPtr<ID3D11RenderTargetView> m_integer_rtv;
ComPtr<ID3D11DepthStencilView> m_dsv;
};
diff --git a/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp b/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp
index e86579b87f..c6f257c735 100644
--- a/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp
+++ b/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp
@@ -59,11 +59,13 @@ std::unique_ptr<AbstractStagingTexture> Gfx::CreateStagingTexture(StagingTexture
return DXStagingTexture::Create(type, config);
}
-std::unique_ptr<AbstractFramebuffer> Gfx::CreateFramebuffer(AbstractTexture* color_attachment,
- AbstractTexture* depth_attachment)
+std::unique_ptr<AbstractFramebuffer>
+Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
- static_cast<DXTexture*>(depth_attachment));
+ static_cast<DXTexture*>(depth_attachment),
+ std::move(additional_color_attachments));
}
std::unique_ptr<AbstractShader>
@@ -109,20 +111,18 @@ void Gfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enab
if (fast_color_clear || z_enable)
{
const D3D12_RECT d3d_clear_rc{target_rc.left, target_rc.top, target_rc.right, target_rc.bottom};
+ auto* d3d_frame_buffer = static_cast<const DXFramebuffer*>(m_current_framebuffer);
if (fast_color_clear)
{
- static_cast<DXTexture*>(m_current_framebuffer->GetColorAttachment())
- ->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
+ d3d_frame_buffer->TransitionRenderTargets();
const std::array<float, 4> clear_color = {
{static_cast<float>((color >> 16) & 0xFF) / 255.0f,
static_cast<float>((color >> 8) & 0xFF) / 255.0f,
static_cast<float>((color >> 0) & 0xFF) / 255.0f,
static_cast<float>((color >> 24) & 0xFF) / 255.0f}};
- g_dx_context->GetCommandList()->ClearRenderTargetView(
- static_cast<const DXFramebuffer*>(m_current_framebuffer)->GetRTVDescriptor().cpu_handle,
- clear_color.data(), 1, &d3d_clear_rc);
+ d3d_frame_buffer->ClearRenderTargets(clear_color, &d3d_clear_rc);
color_enable = false;
alpha_enable = false;
}
@@ -134,9 +134,7 @@ void Gfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enab
// D3D does not support reversed depth ranges.
const float clear_depth = 1.0f - static_cast<float>(z & 0xFFFFFF) / 16777216.0f;
- g_dx_context->GetCommandList()->ClearDepthStencilView(
- static_cast<const DXFramebuffer*>(m_current_framebuffer)->GetDSVDescriptor().cpu_handle,
- D3D12_CLEAR_FLAG_DEPTH, clear_depth, 0, 1, &d3d_clear_rc);
+ d3d_frame_buffer->ClearDepth(clear_depth, &d3d_clear_rc);
z_enable = false;
}
}
@@ -180,11 +178,7 @@ void Gfx::SetPipeline(const AbstractPipeline* pipeline)
void Gfx::BindFramebuffer(DXFramebuffer* fb)
{
- if (fb->HasColorBuffer())
- {
- static_cast<DXTexture*>(fb->GetColorAttachment())
- ->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
- }
+ fb->TransitionRenderTargets();
if (fb->HasDepthBuffer())
{
static_cast<DXTexture*>(fb->GetDepthAttachment())
@@ -212,19 +206,14 @@ void Gfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
SetFramebuffer(framebuffer);
- static const D3D12_DISCARD_REGION dr = {0, nullptr, 0, 1};
- if (framebuffer->HasColorBuffer())
+ DXFramebuffer* d3d_frame_buffer = static_cast<DXFramebuffer*>(framebuffer);
+ d3d_frame_buffer->TransitionRenderTargets();
+ if (d3d_frame_buffer->HasDepthBuffer())
{
- DXTexture* color_attachment = static_cast<DXTexture*>(framebuffer->GetColorAttachment());
- color_attachment->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
- g_dx_context->GetCommandList()->DiscardResource(color_attachment->GetResource(), &dr);
- }
- if (framebuffer->HasDepthBuffer())
- {
- DXTexture* depth_attachment = static_cast<DXTexture*>(framebuffer->GetDepthAttachment());
- depth_attachment->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE);
- g_dx_context->GetCommandList()->DiscardResource(depth_attachment->GetResource(), &dr);
+ static_cast<DXTexture*>(d3d_frame_buffer->GetDepthAttachment())
+ ->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE);
}
+ d3d_frame_buffer->Unbind();
}
void Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value,
@@ -233,17 +222,8 @@ void Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearCo
DXFramebuffer* dxfb = static_cast<DXFramebuffer*>(framebuffer);
BindFramebuffer(dxfb);
- static const D3D12_DISCARD_REGION dr = {0, nullptr, 0, 1};
- if (framebuffer->HasColorBuffer())
- {
- g_dx_context->GetCommandList()->ClearRenderTargetView(dxfb->GetRTVDescriptor().cpu_handle,
- color_value.data(), 0, nullptr);
- }
- if (framebuffer->HasDepthBuffer())
- {
- g_dx_context->GetCommandList()->ClearDepthStencilView(
- dxfb->GetDSVDescriptor().cpu_handle, D3D12_CLEAR_FLAG_DEPTH, depth_value, 0, 0, nullptr);
- }
+ dxfb->ClearRenderTargets(color_value, nullptr);
+ dxfb->ClearDepth(depth_value, nullptr);
}
void Gfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)
diff --git a/Source/Core/VideoBackends/D3D12/D3D12Gfx.h b/Source/Core/VideoBackends/D3D12/D3D12Gfx.h
index 9855ae7ca6..77ce4da899 100644
--- a/Source/Core/VideoBackends/D3D12/D3D12Gfx.h
+++ b/Source/Core/VideoBackends/D3D12/D3D12Gfx.h
@@ -32,7 +32,8 @@ public:
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
- CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
+ CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments) override;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
std::string_view name) override;
diff --git a/Source/Core/VideoBackends/D3D12/D3D12SwapChain.cpp b/Source/Core/VideoBackends/D3D12/D3D12SwapChain.cpp
index 5ebc8c7d74..1cb4a3668b 100644
--- a/Source/Core/VideoBackends/D3D12/D3D12SwapChain.cpp
+++ b/Source/Core/VideoBackends/D3D12/D3D12SwapChain.cpp
@@ -42,7 +42,7 @@ bool SwapChain::CreateSwapChainBuffers()
if (!buffer.texture)
return false;
- buffer.framebuffer = DXFramebuffer::Create(buffer.texture.get(), nullptr);
+ buffer.framebuffer = DXFramebuffer::Create(buffer.texture.get(), nullptr, {});
ASSERT_MSG(VIDEO, buffer.framebuffer != nullptr,
"Failed to create swap chain buffer framebuffer");
if (!buffer.framebuffer)
diff --git a/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp b/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp
index 9d908e0516..c9ab423ee5 100644
--- a/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp
+++ b/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp
@@ -85,7 +85,8 @@ static void GetD3DDepthDesc(D3D12_DEPTH_STENCIL_DESC* desc, const DepthState& st
state.updateenable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
}
-static void GetD3DBlendDesc(D3D12_BLEND_DESC* desc, const BlendingState& state)
+static void GetD3DBlendDesc(D3D12_BLEND_DESC* desc, const BlendingState& state,
+ u8 render_target_count)
{
static constexpr std::array<D3D12_BLEND, 8> src_dual_src_factors = {
{D3D12_BLEND_ZERO, D3D12_BLEND_ONE, D3D12_BLEND_DEST_COLOR, D3D12_BLEND_INV_DEST_COLOR,
@@ -115,45 +116,49 @@ static void GetD3DBlendDesc(D3D12_BLEND_DESC* desc, const BlendingState& state)
desc->AlphaToCoverageEnable = FALSE;
desc->IndependentBlendEnable = FALSE;
- D3D12_RENDER_TARGET_BLEND_DESC* rtblend = &desc->RenderTarget[0];
- if (state.colorupdate)
+ for (u8 i = 0; i < render_target_count; i++)
{
- rtblend->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED |
- D3D12_COLOR_WRITE_ENABLE_GREEN |
- D3D12_COLOR_WRITE_ENABLE_BLUE;
- }
- if (state.alphaupdate)
- {
- rtblend->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
- }
+ D3D12_RENDER_TARGET_BLEND_DESC* rtblend = &desc->RenderTarget[i];
+ if (state.colorupdate)
+ {
+ rtblend->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED |
+ D3D12_COLOR_WRITE_ENABLE_GREEN |
+ D3D12_COLOR_WRITE_ENABLE_BLUE;
+ }
+ if (state.alphaupdate)
+ {
+ rtblend->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
+ }
- // blend takes precedence over logic op
- rtblend->BlendEnable = state.blendenable;
- if (state.blendenable)
- {
- rtblend->BlendOp = state.subtract ? D3D12_BLEND_OP_REV_SUBTRACT : D3D12_BLEND_OP_ADD;
- rtblend->BlendOpAlpha = state.subtractAlpha ? D3D12_BLEND_OP_REV_SUBTRACT : D3D12_BLEND_OP_ADD;
- if (state.usedualsrc)
+ // blend takes precedence over logic op
+ rtblend->BlendEnable = state.blendenable;
+ if (state.blendenable)
{
- rtblend->SrcBlend = src_dual_src_factors[u32(state.srcfactor.Value())];
- rtblend->SrcBlendAlpha = src_dual_src_factors[u32(state.srcfactoralpha.Value())];
- rtblend->DestBlend = dst_dual_src_factors[u32(state.dstfactor.Value())];
- rtblend->DestBlendAlpha = dst_dual_src_factors[u32(state.dstfactoralpha.Value())];
+ rtblend->BlendOp = state.subtract ? D3D12_BLEND_OP_REV_SUBTRACT : D3D12_BLEND_OP_ADD;
+ rtblend->BlendOpAlpha =
+ state.subtractAlpha ? D3D12_BLEND_OP_REV_SUBTRACT : D3D12_BLEND_OP_ADD;
+ if (state.usedualsrc)
+ {
+ rtblend->SrcBlend = src_dual_src_factors[u32(state.srcfactor.Value())];
+ rtblend->SrcBlendAlpha = src_dual_src_factors[u32(state.srcfactoralpha.Value())];
+ rtblend->DestBlend = dst_dual_src_factors[u32(state.dstfactor.Value())];
+ rtblend->DestBlendAlpha = dst_dual_src_factors[u32(state.dstfactoralpha.Value())];
+ }
+ else
+ {
+ rtblend->SrcBlend = src_factors[u32(state.srcfactor.Value())];
+ rtblend->SrcBlendAlpha = src_factors[u32(state.srcfactoralpha.Value())];
+ rtblend->DestBlend = dst_factors[u32(state.dstfactor.Value())];
+ rtblend->DestBlendAlpha = dst_factors[u32(state.dstfactoralpha.Value())];
+ }
}
else
{
- rtblend->SrcBlend = src_factors[u32(state.srcfactor.Value())];
- rtblend->SrcBlendAlpha = src_factors[u32(state.srcfactoralpha.Value())];
- rtblend->DestBlend = dst_factors[u32(state.dstfactor.Value())];
- rtblend->DestBlendAlpha = dst_factors[u32(state.dstfactoralpha.Value())];
+ rtblend->LogicOpEnable = state.logicopenable;
+ if (state.logicopenable)
+ rtblend->LogicOp = logic_ops[u32(state.logicmode.Value())];
}
}
- else
- {
- rtblend->LogicOpEnable = state.logicopenable;
- if (state.logicopenable)
- rtblend->LogicOp = logic_ops[u32(state.logicmode.Value())];
- }
}
std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& config,
@@ -183,7 +188,8 @@ std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& con
if (config.pixel_shader)
desc.PS = static_cast<const DXShader*>(config.pixel_shader)->GetD3DByteCode();
- GetD3DBlendDesc(&desc.BlendState, config.blending_state);
+ GetD3DBlendDesc(&desc.BlendState, config.blending_state,
+ config.framebuffer_state.additional_color_attachment_count + 1);
desc.SampleMask = 0xFFFFFFFF;
GetD3DRasterizerDesc(&desc.RasterizerState, config.rasterization_state, config.framebuffer_state);
GetD3DDepthDesc(&desc.DepthStencilState, config.depth_state);
@@ -195,9 +201,25 @@ std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& con
desc.PrimitiveTopologyType = GetD3DTopologyType(config.rasterization_state);
if (config.framebuffer_state.color_texture_format != AbstractTextureFormat::Undefined)
{
- desc.NumRenderTargets = 1;
+ desc.NumRenderTargets =
+ static_cast<u8>(config.framebuffer_state.additional_color_attachment_count) + 1;
desc.RTVFormats[0] = D3DCommon::GetRTVFormatForAbstractFormat(
- config.framebuffer_state.color_texture_format, config.blending_state.logicopenable);
+ config.framebuffer_state.color_texture_format, false);
+ for (u8 i = 0; i < static_cast<u8>(config.framebuffer_state.additional_color_attachment_count);
+ i++)
+ {
+ // For now set all formats to be the same
+ desc.RTVFormats[i + 1] = D3DCommon::GetRTVFormatForAbstractFormat(
+ config.framebuffer_state.color_texture_format, false);
+ }
+ if (config.blending_state.logicopenable)
+ {
+ desc.NumRenderTargets++;
+ desc.RTVFormats[static_cast<u8>(config.framebuffer_state.additional_color_attachment_count) +
+ 1] =
+ D3DCommon::GetRTVFormatForAbstractFormat(config.framebuffer_state.color_texture_format,
+ true);
+ }
}
if (config.framebuffer_state.depth_texture_format != AbstractTextureFormat::Undefined)
desc.DSVFormat =
diff --git a/Source/Core/VideoBackends/D3D12/DX12Texture.cpp b/Source/Core/VideoBackends/D3D12/DX12Texture.cpp
index 49c5bd08a5..f20c37354b 100644
--- a/Source/Core/VideoBackends/D3D12/DX12Texture.cpp
+++ b/Source/Core/VideoBackends/D3D12/DX12Texture.cpp
@@ -393,10 +393,12 @@ void DXTexture::DestroyResource()
}
DXFramebuffer::DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
u32 width, u32 height, u32 layers, u32 samples)
- : AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
- height, layers, samples)
+ : AbstractFramebuffer(color_attachment, depth_attachment,
+ std::move(additional_color_attachments), color_format, depth_format,
+ width, height, layers, samples)
{
}
@@ -412,15 +414,73 @@ DXFramebuffer::~DXFramebuffer()
g_dx_context->DeferDescriptorDestruction(g_dx_context->GetRTVHeapManager(),
m_int_rtv_descriptor.index);
}
+ }
+ for (auto render_target : m_render_targets)
+ {
g_dx_context->DeferDescriptorDestruction(g_dx_context->GetRTVHeapManager(),
- m_rtv_descriptor.index);
+ render_target.index);
+ }
+}
+
+void DXFramebuffer::Unbind()
+{
+ static const D3D12_DISCARD_REGION dr = {0, nullptr, 0, 1};
+ if (HasColorBuffer())
+ {
+ g_dx_context->GetCommandList()->DiscardResource(
+ static_cast<DXTexture*>(GetColorAttachment())->GetResource(), &dr);
+ }
+ for (auto additional_color_attachment : m_additional_color_attachments)
+ {
+ g_dx_context->GetCommandList()->DiscardResource(
+ static_cast<DXTexture*>(additional_color_attachment)->GetResource(), &dr);
+ }
+ if (HasDepthBuffer())
+ {
+ g_dx_context->GetCommandList()->DiscardResource(
+ static_cast<DXTexture*>(GetDepthAttachment())->GetResource(), &dr);
+ }
+}
+
+void DXFramebuffer::ClearRenderTargets(const ClearColor& color_value,
+ const D3D12_RECT* rectangle) const
+{
+ for (auto render_target : m_render_targets_raw)
+ {
+ g_dx_context->GetCommandList()->ClearRenderTargetView(render_target, color_value.data(),
+ rectangle ? 1 : 0, rectangle);
+ }
+}
+
+void DXFramebuffer::ClearDepth(float depth_value, const D3D12_RECT* rectangle) const
+{
+ if (HasDepthBuffer())
+ {
+ g_dx_context->GetCommandList()->ClearDepthStencilView(GetDSVDescriptor().cpu_handle,
+ D3D12_CLEAR_FLAG_DEPTH, depth_value, 0,
+ rectangle ? 1 : 0, rectangle);
+ }
+}
+
+void DXFramebuffer::TransitionRenderTargets() const
+{
+ if (HasColorBuffer())
+ {
+ static_cast<DXTexture*>(GetColorAttachment())
+ ->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
+ }
+ for (auto additional_color_attachment : m_additional_color_attachments)
+ {
+ static_cast<DXTexture*>(additional_color_attachment)
+ ->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
}
}
-std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(DXTexture* color_attachment,
- DXTexture* depth_attachment)
+std::unique_ptr<DXFramebuffer>
+DXFramebuffer::Create(DXTexture* color_attachment, DXTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
- if (!ValidateConfig(color_attachment, depth_attachment))
+ if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments))
return nullptr;
const AbstractTextureFormat color_format =
@@ -433,10 +493,10 @@ std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(DXTexture* color_attachment
const u32 layers = either_attachment->GetLayers();
const u32 samples = either_attachment->GetSamples();
- std::unique_ptr<DXFramebuffer> fb(new DXFramebuffer(color_attachment, depth_attachment,
- color_format, depth_format, width, height,
- layers, samples));
- if ((color_attachment && !fb->CreateRTVDescriptor()) ||
+ std::unique_ptr<DXFramebuffer> fb(
+ new DXFramebuffer(color_attachment, depth_attachment, std::move(additional_color_attachments),
+ color_format, depth_format, width, height, layers, samples));
+ if (!fb->CreateRTVDescriptors() || (color_attachment && !fb->CreateIRTVDescriptor()) ||
(depth_attachment && !fb->CreateDSVDescriptor()))
{
return nullptr;
@@ -445,38 +505,73 @@ std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(DXTexture* color_attachment
return fb;
}
-bool DXFramebuffer::CreateRTVDescriptor()
+bool DXFramebuffer::CreateRTVDescriptors()
+{
+ if (m_color_attachment)
+ {
+ if (!CreateRTVDescriptor(m_layers, m_color_attachment))
+ {
+ return false;
+ }
+ }
+
+ for (auto* attachment : m_additional_color_attachments)
+ {
+ if (!CreateRTVDescriptor(1, attachment))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool DXFramebuffer::CreateRTVDescriptor(u32 layers, AbstractTexture* attachment)
{
- if (!g_dx_context->GetRTVHeapManager().Allocate(&m_rtv_descriptor))
+ DescriptorHandle rtv;
+ if (!g_dx_context->GetRTVHeapManager().Allocate(&rtv))
{
PanicAlertFmt("Failed to allocate RTV descriptor");
return false;
}
+ m_render_targets.push_back(std::move(rtv));
+ m_render_targets_raw.push_back(m_render_targets.back().cpu_handle);
const bool multisampled = m_samples > 1;
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {
D3DCommon::GetRTVFormatForAbstractFormat(m_color_format, false),
multisampled ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D12_RTV_DIMENSION_TEXTURE2DARRAY};
if (multisampled)
- rtv_desc.Texture2DMSArray.ArraySize = m_layers;
+ rtv_desc.Texture2DMSArray.ArraySize = layers;
else
- rtv_desc.Texture2DArray.ArraySize = m_layers;
+ rtv_desc.Texture2DArray.ArraySize = layers;
g_dx_context->GetDevice()->CreateRenderTargetView(
- static_cast<DXTexture*>(m_color_attachment)->GetResource(), &rtv_desc,
- m_rtv_descriptor.cpu_handle);
+ static_cast<DXTexture*>(attachment)->GetResource(), &rtv_desc, m_render_targets_raw.back());
+ return true;
+}
+
+bool DXFramebuffer::CreateIRTVDescriptor()
+{
+ const bool multisampled = m_samples > 1;
+ DXGI_FORMAT non_int_format = D3DCommon::GetRTVFormatForAbstractFormat(m_color_format, false);
DXGI_FORMAT int_format = D3DCommon::GetRTVFormatForAbstractFormat(m_color_format, true);
- if (int_format != rtv_desc.Format)
+ if (int_format != non_int_format)
{
if (!g_dx_context->GetRTVHeapManager().Allocate(&m_int_rtv_descriptor))
return false;
- rtv_desc.Format = int_format;
+ D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {int_format, multisampled ?
+ D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY :
+ D3D12_RTV_DIMENSION_TEXTURE2DARRAY};
+ if (multisampled)
+ rtv_desc.Texture2DMSArray.ArraySize = m_layers;
+ else
+ rtv_desc.Texture2DArray.ArraySize = m_layers;
g_dx_context->GetDevice()->CreateRenderTargetView(
static_cast<DXTexture*>(m_color_attachment)->GetResource(), &rtv_desc,
m_int_rtv_descriptor.cpu_handle);
}
-
return true;
}
diff --git a/Source/Core/VideoBackends/D3D12/DX12Texture.h b/Source/Core/VideoBackends/D3D12/DX12Texture.h
index b7be428020..ea781fd899 100644
--- a/Source/Core/VideoBackends/D3D12/DX12Texture.h
+++ b/Source/Core/VideoBackends/D3D12/DX12Texture.h
@@ -10,8 +10,10 @@
#include "VideoBackends/D3D12/Common.h"
#include "VideoBackends/D3D12/DescriptorHeapManager.h"
#include "VideoCommon/AbstractFramebuffer.h"
+#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"
+#include "VideoCommon/RenderBase.h"
namespace DX12
{
@@ -65,14 +67,13 @@ class DXFramebuffer final : public AbstractFramebuffer
public:
~DXFramebuffer() override;
- const DescriptorHandle& GetRTVDescriptor() const { return m_rtv_descriptor; }
const DescriptorHandle& GetIntRTVDescriptor() const { return m_int_rtv_descriptor; }
const DescriptorHandle& GetDSVDescriptor() const { return m_dsv_descriptor; }
- UINT GetRTVDescriptorCount() const { return m_color_attachment ? 1 : 0; }
+ UINT GetRTVDescriptorCount() const { return static_cast<UINT>(m_render_targets.size()); }
const D3D12_CPU_DESCRIPTOR_HANDLE* GetRTVDescriptorArray() const
{
- return m_color_attachment ? &m_rtv_descriptor.cpu_handle : nullptr;
+ return m_render_targets_raw.data();
}
const D3D12_CPU_DESCRIPTOR_HANDLE* GetIntRTVDescriptorArray() const
{
@@ -83,18 +84,28 @@ public:
return m_depth_attachment ? &m_dsv_descriptor.cpu_handle : nullptr;
}
- static std::unique_ptr<DXFramebuffer> Create(DXTexture* color_attachment,
- DXTexture* depth_attachment);
+ void Unbind();
+ void ClearRenderTargets(const ClearColor& color_value, const D3D12_RECT* rectangle) const;
+ void ClearDepth(float depth_value, const D3D12_RECT* rectangle) const;
+ void TransitionRenderTargets() const;
+
+ static std::unique_ptr<DXFramebuffer>
+ Create(DXTexture* color_attachment, DXTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments);
private:
DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
u32 height, u32 layers, u32 samples);
- bool CreateRTVDescriptor();
+ bool CreateRTVDescriptors();
+ bool CreateRTVDescriptor(u32 layers, AbstractTexture* attachment);
+ bool CreateIRTVDescriptor();
bool CreateDSVDescriptor();
- DescriptorHandle m_rtv_descriptor = {};
+ std::vector<DescriptorHandle> m_render_targets;
+ std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> m_render_targets_raw;
DescriptorHandle m_int_rtv_descriptor = {};
DescriptorHandle m_dsv_descriptor = {};
};
diff --git a/Source/Core/VideoBackends/Metal/MTLGfx.h b/Source/Core/VideoBackends/Metal/MTLGfx.h
index 22795a0183..c1a698711a 100644
--- a/Source/Core/VideoBackends/Metal/MTLGfx.h
+++ b/Source/Core/VideoBackends/Metal/MTLGfx.h
@@ -28,7 +28,8 @@ public:
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
- CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
+ CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments) override;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
std::string_view name) override;
diff --git a/Source/Core/VideoBackends/Metal/MTLGfx.mm b/Source/Core/VideoBackends/Metal/MTLGfx.mm
index d6621396ec..1137c45e5f 100644
--- a/Source/Core/VideoBackends/Metal/MTLGfx.mm
+++ b/Source/Core/VideoBackends/Metal/MTLGfx.mm
@@ -93,7 +93,8 @@ Metal::Gfx::CreateStagingTexture(StagingTextureType type, const TextureConfig& c
}
std::unique_ptr<AbstractFramebuffer>
-Metal::Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment)
+Metal::Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*>)
{
AbstractTexture* const either_attachment = color_attachment ? color_attachment : depth_attachment;
return std::make_unique<Framebuffer>(
diff --git a/Source/Core/VideoBackends/Metal/MTLTexture.mm b/Source/Core/VideoBackends/Metal/MTLTexture.mm
index 17079b0c6e..c9750eb1a5 100644
--- a/Source/Core/VideoBackends/Metal/MTLTexture.mm
+++ b/Source/Core/VideoBackends/Metal/MTLTexture.mm
@@ -191,7 +191,7 @@ void Metal::StagingTexture::Flush()
Metal::Framebuffer::Framebuffer(AbstractTexture* color, AbstractTexture* depth, //
u32 width, u32 height, u32 layers, u32 samples)
- : AbstractFramebuffer(color, depth,
+ : AbstractFramebuffer(color, depth, {},
color ? color->GetFormat() : AbstractTextureFormat::Undefined, //
depth ? depth->GetFormat() : AbstractTextureFormat::Undefined, //
width, height, layers, samples)
diff --git a/Source/Core/VideoBackends/Null/NullGfx.cpp b/Source/Core/VideoBackends/Null/NullGfx.cpp
index 7449aae09c..72aea0ce50 100644
--- a/Source/Core/VideoBackends/Null/NullGfx.cpp
+++ b/Source/Core/VideoBackends/Null/NullGfx.cpp
@@ -77,11 +77,13 @@ std::unique_ptr<AbstractPipeline> NullGfx::CreatePipeline(const AbstractPipeline
return std::make_unique<NullPipeline>();
}
-std::unique_ptr<AbstractFramebuffer> NullGfx::CreateFramebuffer(AbstractTexture* color_attachment,
- AbstractTexture* depth_attachment)
+std::unique_ptr<AbstractFramebuffer>
+NullGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
return NullFramebuffer::Create(static_cast<NullTexture*>(color_attachment),
- static_cast<NullTexture*>(depth_attachment));
+ static_cast<NullTexture*>(depth_attachment),
+ std::move(additional_color_attachments));
}
std::unique_ptr<NativeVertexFormat>
diff --git a/Source/Core/VideoBackends/Null/NullGfx.h b/Source/Core/VideoBackends/Null/NullGfx.h
index 63b999b859..534109a09c 100644
--- a/Source/Core/VideoBackends/Null/NullGfx.h
+++ b/Source/Core/VideoBackends/Null/NullGfx.h
@@ -22,7 +22,8 @@ public:
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
- CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
+ CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments) override;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
std::string_view name) override;
diff --git a/Source/Core/VideoBackends/Null/NullTexture.cpp b/Source/Core/VideoBackends/Null/NullTexture.cpp
index 1b238ef674..89da5ae735 100644
--- a/Source/Core/VideoBackends/Null/NullTexture.cpp
+++ b/Source/Core/VideoBackends/Null/NullTexture.cpp
@@ -66,18 +66,21 @@ void NullStagingTexture::Flush()
NullFramebuffer::NullFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format,
AbstractTextureFormat depth_format, u32 width, u32 height,
u32 layers, u32 samples)
- : AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
- height, layers, samples)
+ : AbstractFramebuffer(color_attachment, depth_attachment,
+ std::move(additional_color_attachments), color_format, depth_format,
+ width, height, layers, samples)
{
}
-std::unique_ptr<NullFramebuffer> NullFramebuffer::Create(NullTexture* color_attachment,
- NullTexture* depth_attachment)
+std::unique_ptr<NullFramebuffer>
+NullFramebuffer::Create(NullTexture* color_attachment, NullTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
- if (!ValidateConfig(color_attachment, depth_attachment))
+ if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments))
return nullptr;
const AbstractTextureFormat color_format =
@@ -90,7 +93,8 @@ std::unique_ptr<NullFramebuffer> NullFramebuffer::Create(NullTexture* color_atta
const u32 layers = either_attachment->GetLayers();
const u32 samples = either_attachment->GetSamples();
- return std::make_unique<NullFramebuffer>(color_attachment, depth_attachment, color_format,
+ return std::make_unique<NullFramebuffer>(color_attachment, depth_attachment,
+ std::move(additional_color_attachments), color_format,
depth_format, width, height, layers, samples);
}
diff --git a/Source/Core/VideoBackends/Null/NullTexture.h b/Source/Core/VideoBackends/Null/NullTexture.h
index 8960114685..505f843cd0 100644
--- a/Source/Core/VideoBackends/Null/NullTexture.h
+++ b/Source/Core/VideoBackends/Null/NullTexture.h
@@ -54,11 +54,13 @@ class NullFramebuffer final : public AbstractFramebuffer
{
public:
explicit NullFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
u32 width, u32 height, u32 layers, u32 samples);
- static std::unique_ptr<NullFramebuffer> Create(NullTexture* color_attachment,
- NullTexture* depth_attachment);
+ static std::unique_ptr<NullFramebuffer>
+ Create(NullTexture* color_attachment, NullTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments);
};
} // namespace Null
diff --git a/Source/Core/VideoBackends/OGL/OGLConfig.cpp b/Source/Core/VideoBackends/OGL/OGLConfig.cpp
index e5e1bff83f..95998b836b 100644
--- a/Source/Core/VideoBackends/OGL/OGLConfig.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLConfig.cpp
@@ -480,6 +480,8 @@ bool PopulateConfig(GLContext* m_main_gl_context)
else if (GLExtensions::Version() == 330)
{
g_ogl_config.eSupportedGLSLVersion = Glsl330;
+ g_ogl_config.bSupportsExplicitLayoutInShader =
+ GLExtensions::Supports("GL_ARB_explicit_attrib_location");
}
else if (GLExtensions::Version() >= 430)
{
@@ -495,6 +497,7 @@ bool PopulateConfig(GLContext* m_main_gl_context)
g_ogl_config.bSupportsTextureStorage = true;
g_ogl_config.SupportedMultisampleTexStorage = MultisampleTexStorageType::TexStorageCore;
g_ogl_config.bSupportsImageLoadStore = true;
+ g_ogl_config.bSupportsExplicitLayoutInShader = true;
g_Config.backend_info.bSupportsSSAA = true;
g_Config.backend_info.bSupportsSettingObjectNames = true;
diff --git a/Source/Core/VideoBackends/OGL/OGLConfig.h b/Source/Core/VideoBackends/OGL/OGLConfig.h
index 4929901b09..6a50269222 100644
--- a/Source/Core/VideoBackends/OGL/OGLConfig.h
+++ b/Source/Core/VideoBackends/OGL/OGLConfig.h
@@ -77,6 +77,7 @@ struct VideoConfig
bool bSupportsTextureSubImage;
EsFbFetchType SupportedFramebufferFetch;
bool bSupportsKHRShaderSubgroup; // basic + arithmetic + ballot
+ bool bSupportsExplicitLayoutInShader;
const char* gl_vendor;
const char* gl_renderer;
diff --git a/Source/Core/VideoBackends/OGL/OGLGfx.cpp b/Source/Core/VideoBackends/OGL/OGLGfx.cpp
index a89f05626b..e83ff209ea 100644
--- a/Source/Core/VideoBackends/OGL/OGLGfx.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLGfx.cpp
@@ -128,8 +128,8 @@ OGLGfx::OGLGfx(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scal
if (!m_main_gl_context->IsHeadless())
{
m_system_framebuffer = std::make_unique<OGLFramebuffer>(
- nullptr, nullptr, AbstractTextureFormat::RGBA8, AbstractTextureFormat::Undefined,
- std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
+ nullptr, nullptr, std::vector<AbstractTexture*>{}, AbstractTextureFormat::RGBA8,
+ AbstractTextureFormat::Undefined, std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
std::max(m_main_gl_context->GetBackBufferHeight(), 1u), 1, 1, 0);
m_current_framebuffer = m_system_framebuffer.get();
}
@@ -226,11 +226,13 @@ std::unique_ptr<AbstractStagingTexture> OGLGfx::CreateStagingTexture(StagingText
return OGLStagingTexture::Create(type, config);
}
-std::unique_ptr<AbstractFramebuffer> OGLGfx::CreateFramebuffer(AbstractTexture* color_attachment,
- AbstractTexture* depth_attachment)
+std::unique_ptr<AbstractFramebuffer>
+OGLGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
return OGLFramebuffer::Create(static_cast<OGLTexture*>(color_attachment),
- static_cast<OGLTexture*>(depth_attachment));
+ static_cast<OGLTexture*>(depth_attachment),
+ std::move(additional_color_attachments));
}
std::unique_ptr<AbstractShader>
diff --git a/Source/Core/VideoBackends/OGL/OGLGfx.h b/Source/Core/VideoBackends/OGL/OGLGfx.h
index 51784c2ec8..8d552a661b 100644
--- a/Source/Core/VideoBackends/OGL/OGLGfx.h
+++ b/Source/Core/VideoBackends/OGL/OGLGfx.h
@@ -36,7 +36,8 @@ public:
const void* cache_data = nullptr,
size_t cache_data_length = 0) override;
std::unique_ptr<AbstractFramebuffer>
- CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
+ CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments) override;
void SetPipeline(const AbstractPipeline* pipeline) override;
void SetFramebuffer(AbstractFramebuffer* framebuffer) override;
diff --git a/Source/Core/VideoBackends/OGL/OGLTexture.cpp b/Source/Core/VideoBackends/OGL/OGLTexture.cpp
index f356e52d32..0e4e99f59b 100644
--- a/Source/Core/VideoBackends/OGL/OGLTexture.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLTexture.cpp
@@ -555,11 +555,13 @@ void OGLStagingTexture::Unmap()
}
OGLFramebuffer::OGLFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format,
AbstractTextureFormat depth_format, u32 width, u32 height,
u32 layers, u32 samples, GLuint fbo)
- : AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
- height, layers, samples),
+ : AbstractFramebuffer(color_attachment, depth_attachment,
+ std::move(additional_color_attachments), color_format, depth_format,
+ width, height, layers, samples),
m_fbo(fbo)
{
}
@@ -569,10 +571,11 @@ OGLFramebuffer::~OGLFramebuffer()
glDeleteFramebuffers(1, &m_fbo);
}
-std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachment,
- OGLTexture* depth_attachment)
+std::unique_ptr<OGLFramebuffer>
+OGLFramebuffer::Create(OGLTexture* color_attachment, OGLTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
- if (!ValidateConfig(color_attachment, depth_attachment))
+ if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments))
return nullptr;
const AbstractTextureFormat color_format =
@@ -589,6 +592,7 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachm
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ std::vector<GLenum> buffers;
if (color_attachment)
{
if (color_attachment->GetConfig().layers > 1)
@@ -601,6 +605,7 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachm
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
color_attachment->GetGLTextureId(), 0, 0);
}
+ buffers.push_back(GL_COLOR_ATTACHMENT0);
}
if (depth_attachment)
@@ -619,10 +624,29 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachm
}
}
+ for (std::size_t i = 0; i < additional_color_attachments.size(); i++)
+ {
+ const auto attachment_enum = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i + 1);
+ OGLTexture* attachment = static_cast<OGLTexture*>(additional_color_attachments[i]);
+ if (attachment->GetConfig().layers > 1)
+ {
+ glFramebufferTexture(GL_FRAMEBUFFER, attachment_enum, attachment->GetGLTextureId(), 0);
+ }
+ else
+ {
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment_enum, attachment->GetGLTextureId(), 0,
+ 0);
+ }
+ buffers.push_back(attachment_enum);
+ }
+
+ glDrawBuffers(static_cast<GLsizei>(buffers.size()), buffers.data());
+
DEBUG_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
GetOGLGfx()->RestoreFramebufferBinding();
- return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment, color_format,
+ return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment,
+ std::move(additional_color_attachments), color_format,
depth_format, width, height, layers, samples, fbo);
}
diff --git a/Source/Core/VideoBackends/OGL/OGLTexture.h b/Source/Core/VideoBackends/OGL/OGLTexture.h
index f80aa98725..ca08910eae 100644
--- a/Source/Core/VideoBackends/OGL/OGLTexture.h
+++ b/Source/Core/VideoBackends/OGL/OGLTexture.h
@@ -82,12 +82,14 @@ class OGLFramebuffer final : public AbstractFramebuffer
{
public:
OGLFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
u32 height, u32 layers, u32 samples, GLuint fbo);
~OGLFramebuffer() override;
- static std::unique_ptr<OGLFramebuffer> Create(OGLTexture* color_attachment,
- OGLTexture* depth_attachment);
+ static std::unique_ptr<OGLFramebuffer>
+ Create(OGLTexture* color_attachment, OGLTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments);
GLuint GetFBO() const { return m_fbo; }
diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
index a149c9fad0..8c56a40e8c 100644
--- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
+++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
@@ -126,6 +126,10 @@ void SHADER::SetProgramVariables()
void SHADER::SetProgramBindings(bool is_compute)
{
+ if (g_ogl_config.bSupportsExplicitLayoutInShader)
+ {
+ return;
+ }
if (!is_compute)
{
if (g_ActiveConfig.backend_info.bSupportsDualSourceBlend)
@@ -729,6 +733,49 @@ void ProgramShaderCache::CreateHeader()
v >= GlslEs320 ||
g_ogl_config.SupportedMultisampleTexStorage != MultisampleTexStorageType::TexStorageNone;
+ std::string binding_layout;
+ if (g_ActiveConfig.backend_info.bSupportsBindingLayout)
+ {
+ if (g_ogl_config.bSupportsExplicitLayoutInShader)
+ {
+ binding_layout =
+ "#extension GL_ARB_explicit_attrib_location : enable\n"
+ "#define ATTRIBUTE_LOCATION(x) layout(location = x)\n"
+ "#define FRAGMENT_OUTPUT_LOCATION(x) layout(location = x)\n"
+ "#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y) layout(location = x, index = y)\n"
+ "#define UBO_BINDING(packing, x) layout(packing, binding = x)\n"
+ "#define SAMPLER_BINDING(x) layout(binding = x)\n"
+ "#define TEXEL_BUFFER_BINDING(x) layout(binding = x)\n"
+ "#define SSBO_BINDING(x) layout(std430, binding = x)\n"
+ "#define IMAGE_BINDING(format, x) layout(format, binding = x)\n";
+ }
+ else
+ {
+ binding_layout = "#define ATTRIBUTE_LOCATION(x)\n"
+ "#define FRAGMENT_OUTPUT_LOCATION(x)\n"
+ "#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y)\n"
+ "#define UBO_BINDING(packing, x) layout(packing, binding = x)\n"
+ "#define SAMPLER_BINDING(x) layout(binding = x)\n"
+ "#define TEXEL_BUFFER_BINDING(x) layout(binding = x)\n"
+ "#define SSBO_BINDING(x) layout(std430, binding = x)\n"
+ "#define IMAGE_BINDING(format, x) layout(format, binding = x)\n";
+ }
+ }
+ else
+ {
+ binding_layout = "#define ATTRIBUTE_LOCATION(x)\n"
+ "#define FRAGMENT_OUTPUT_LOCATION(x)\n"
+ "#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y)\n"
+ "#define UBO_BINDING(packing, x) layout(packing)\n"
+ "#define SAMPLER_BINDING(x)\n"
+ "#define TEXEL_BUFFER_BINDING(x)\n"
+ "#define SSBO_BINDING(x) layout(std430)\n"
+ "#define IMAGE_BINDING(format, x) layout(format)\n";
+ }
+
+ // TODO: actually define this if using 'bSupportsExplicitLayoutInShader'
+ const std::string varying_location = "#define VARYING_LOCATION(x)\n";
+
std::string shader_shuffle_string;
if (g_ogl_config.bSupportsKHRShaderSubgroup)
{
@@ -799,28 +846,7 @@ void ProgramShaderCache::CreateHeader()
(g_ogl_config.bSupportsMSAA && v < Glsl150) ?
"#extension GL_ARB_texture_multisample : enable" :
"",
- // Attribute and fragment output bindings are still done via glBindAttribLocation and
- // glBindFragDataLocation. In the future this could be moved to the layout qualifier
- // in GLSL, but requires verification of GL_ARB_explicit_attrib_location.
- g_ActiveConfig.backend_info.bSupportsBindingLayout ?
- "#define ATTRIBUTE_LOCATION(x)\n"
- "#define FRAGMENT_OUTPUT_LOCATION(x)\n"
- "#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y)\n"
- "#define UBO_BINDING(packing, x) layout(packing, binding = x)\n"
- "#define SAMPLER_BINDING(x) layout(binding = x)\n"
- "#define TEXEL_BUFFER_BINDING(x) layout(binding = x)\n"
- "#define SSBO_BINDING(x) layout(std430, binding = x)\n"
- "#define IMAGE_BINDING(format, x) layout(format, binding = x)\n" :
- "#define ATTRIBUTE_LOCATION(x)\n"
- "#define FRAGMENT_OUTPUT_LOCATION(x)\n"
- "#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y)\n"
- "#define UBO_BINDING(packing, x) layout(packing)\n"
- "#define SAMPLER_BINDING(x)\n"
- "#define TEXEL_BUFFER_BINDING(x)\n"
- "#define SSBO_BINDING(x) layout(std430)\n"
- "#define IMAGE_BINDING(format, x) layout(format)\n",
- // Input/output blocks are matched by name during program linking
- "#define VARYING_LOCATION(x)\n",
+ binding_layout.c_str(), varying_location.c_str(),
!is_glsles && g_ActiveConfig.backend_info.bSupportsFragmentStoresAndAtomics ?
"#extension GL_ARB_shader_storage_buffer_object : enable" :
"",
diff --git a/Source/Core/VideoBackends/Software/SWGfx.cpp b/Source/Core/VideoBackends/Software/SWGfx.cpp
index 5837e19bf8..78d2d14d63 100644
--- a/Source/Core/VideoBackends/Software/SWGfx.cpp
+++ b/Source/Core/VideoBackends/Software/SWGfx.cpp
@@ -44,11 +44,13 @@ std::unique_ptr<AbstractStagingTexture> SWGfx::CreateStagingTexture(StagingTextu
return std::make_unique<SWStagingTexture>(type, config);
}
-std::unique_ptr<AbstractFramebuffer> SWGfx::CreateFramebuffer(AbstractTexture* color_attachment,
- AbstractTexture* depth_attachment)
+std::unique_ptr<AbstractFramebuffer>
+SWGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
return SWFramebuffer::Create(static_cast<SWTexture*>(color_attachment),
- static_cast<SWTexture*>(depth_attachment));
+ static_cast<SWTexture*>(depth_attachment),
+ std::move(additional_color_attachments));
}
void SWGfx::BindBackbuffer(const ClearColor& clear_color)
diff --git a/Source/Core/VideoBackends/Software/SWGfx.h b/Source/Core/VideoBackends/Software/SWGfx.h
index 6993c40882..bd9604fe3c 100644
--- a/Source/Core/VideoBackends/Software/SWGfx.h
+++ b/Source/Core/VideoBackends/Software/SWGfx.h
@@ -22,7 +22,8 @@ public:
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
- CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
+ CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments) override;
void BindBackbuffer(const ClearColor& clear_color = {}) override;
diff --git a/Source/Core/VideoBackends/Software/SWTexture.cpp b/Source/Core/VideoBackends/Software/SWTexture.cpp
index 0e3ebbde55..0ada0502f0 100644
--- a/Source/Core/VideoBackends/Software/SWTexture.cpp
+++ b/Source/Core/VideoBackends/Software/SWTexture.cpp
@@ -159,17 +159,20 @@ void SWStagingTexture::Flush()
}
SWFramebuffer::SWFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
u32 width, u32 height, u32 layers, u32 samples)
- : AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
- height, layers, samples)
+ : AbstractFramebuffer(color_attachment, depth_attachment,
+ std::move(additional_color_attachments), color_format, depth_format,
+ width, height, layers, samples)
{
}
-std::unique_ptr<SWFramebuffer> SWFramebuffer::Create(SWTexture* color_attachment,
- SWTexture* depth_attachment)
+std::unique_ptr<SWFramebuffer>
+SWFramebuffer::Create(SWTexture* color_attachment, SWTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
- if (!ValidateConfig(color_attachment, depth_attachment))
+ if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments))
return nullptr;
const AbstractTextureFormat color_format =
@@ -182,7 +185,8 @@ std::unique_ptr<SWFramebuffer> SWFramebuffer::Create(SWTexture* color_attachment
const u32 layers = either_attachment->GetLayers();
const u32 samples = either_attachment->GetSamples();
- return std::make_unique<SWFramebuffer>(color_attachment, depth_attachment, color_format,
+ return std::make_unique<SWFramebuffer>(color_attachment, depth_attachment,
+ std::move(additional_color_attachments), color_format,
depth_format, width, height, layers, samples);
}
diff --git a/Source/Core/VideoBackends/Software/SWTexture.h b/Source/Core/VideoBackends/Software/SWTexture.h
index 899c8e90b9..9332dccb98 100644
--- a/Source/Core/VideoBackends/Software/SWTexture.h
+++ b/Source/Core/VideoBackends/Software/SWTexture.h
@@ -63,12 +63,14 @@ class SWFramebuffer final : public AbstractFramebuffer
{
public:
explicit SWFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
u32 width, u32 height, u32 layers, u32 samples);
~SWFramebuffer() override = default;
- static std::unique_ptr<SWFramebuffer> Create(SWTexture* color_attachment,
- SWTexture* depth_attachment);
+ static std::unique_ptr<SWFramebuffer>
+ Create(SWTexture* color_attachment, SWTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments);
};
} // namespace SW
diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp
index b603ad36d4..6b8f66ae80 100644
--- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp
+++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp
@@ -388,66 +388,71 @@ VkSampler ObjectCache::GetSampler(const SamplerState& info)
}
VkRenderPass ObjectCache::GetRenderPass(VkFormat color_format, VkFormat depth_format,
- u32 multisamples, VkAttachmentLoadOp load_op)
+ u32 multisamples, VkAttachmentLoadOp load_op,
+ u8 additional_attachment_count)
{
- auto key = std::tie(color_format, depth_format, multisamples, load_op);
+ auto key =
+ std::tie(color_format, depth_format, multisamples, load_op, additional_attachment_count);
auto it = m_render_pass_cache.find(key);
if (it != m_render_pass_cache.end())
return it->second;
- VkAttachmentReference color_reference;
- VkAttachmentReference* color_reference_ptr = nullptr;
VkAttachmentReference depth_reference;
VkAttachmentReference* depth_reference_ptr = nullptr;
- std::array<VkAttachmentDescription, 2> attachments;
- u32 num_attachments = 0;
+ std::vector<VkAttachmentDescription> attachments;
+ std::vector<VkAttachmentReference> color_attachment_references;
if (color_format != VK_FORMAT_UNDEFINED)
{
- attachments[num_attachments] = {0,
- color_format,
- static_cast<VkSampleCountFlagBits>(multisamples),
- load_op,
- VK_ATTACHMENT_STORE_OP_STORE,
- VK_ATTACHMENT_LOAD_OP_DONT_CARE,
- VK_ATTACHMENT_STORE_OP_DONT_CARE,
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
- color_reference.attachment = num_attachments;
+ VkAttachmentReference color_reference;
+ color_reference.attachment = static_cast<uint32_t>(attachments.size());
color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- color_reference_ptr = &color_reference;
- num_attachments++;
+ color_attachment_references.push_back(std::move(color_reference));
+ attachments.push_back({0, color_format, static_cast<VkSampleCountFlagBits>(multisamples),
+ load_op, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+ VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
}
if (depth_format != VK_FORMAT_UNDEFINED)
{
- attachments[num_attachments] = {0,
- depth_format,
- static_cast<VkSampleCountFlagBits>(multisamples),
- load_op,
- VK_ATTACHMENT_STORE_OP_STORE,
- VK_ATTACHMENT_LOAD_OP_DONT_CARE,
- VK_ATTACHMENT_STORE_OP_DONT_CARE,
- VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
- VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
- depth_reference.attachment = num_attachments;
+ depth_reference.attachment = static_cast<uint32_t>(attachments.size());
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depth_reference_ptr = &depth_reference;
- num_attachments++;
+ attachments.push_back({0, depth_format, static_cast<VkSampleCountFlagBits>(multisamples),
+ load_op, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+ VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL});
}
- VkSubpassDescription subpass = {0,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- 0,
- nullptr,
- color_reference_ptr ? 1u : 0u,
- color_reference_ptr ? color_reference_ptr : nullptr,
- nullptr,
- depth_reference_ptr,
- 0,
- nullptr};
+ for (u8 i = 0; i < additional_attachment_count; i++)
+ {
+ VkAttachmentReference color_reference;
+ color_reference.attachment = static_cast<uint32_t>(attachments.size());
+ color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ color_attachment_references.push_back(std::move(color_reference));
+ attachments.push_back({0, color_format, static_cast<VkSampleCountFlagBits>(multisamples),
+ load_op, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+ VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
+ }
+
+ VkSubpassDescription subpass = {
+ 0,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ 0,
+ nullptr,
+ static_cast<uint32_t>(color_attachment_references.size()),
+ color_attachment_references.empty() ? nullptr : color_attachment_references.data(),
+ nullptr,
+ depth_reference_ptr,
+ 0,
+ nullptr};
VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr,
0,
- num_attachments,
+ static_cast<uint32_t>(attachments.size()),
attachments.data(),
1,
&subpass,
diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.h b/Source/Core/VideoBackends/Vulkan/ObjectCache.h
index 64ba4ace32..c3346ba783 100644
--- a/Source/Core/VideoBackends/Vulkan/ObjectCache.h
+++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.h
@@ -60,7 +60,7 @@ public:
// Render pass cache.
VkRenderPass GetRenderPass(VkFormat color_format, VkFormat depth_format, u32 multisamples,
- VkAttachmentLoadOp load_op);
+ VkAttachmentLoadOp load_op, u8 additional_attachment_count = 0);
// Pipeline cache. Used when creating pipelines for drivers to store compiled programs.
VkPipelineCache GetPipelineCache() const { return m_pipeline_cache; }
@@ -102,7 +102,7 @@ private:
std::unique_ptr<VKTexture> m_dummy_texture;
// Render pass cache
- using RenderPassCacheKey = std::tuple<VkFormat, VkFormat, u32, VkAttachmentLoadOp>;
+ using RenderPassCacheKey = std::tuple<VkFormat, VkFormat, u32, VkAttachmentLoadOp, std::size_t>;
std::map<RenderPassCacheKey, VkRenderPass> m_render_pass_cache;
// pipeline cache
diff --git a/Source/Core/VideoBackends/Vulkan/VKGfx.cpp b/Source/Core/VideoBackends/Vulkan/VKGfx.cpp
index 569fbaa32b..79b84d574b 100644
--- a/Source/Core/VideoBackends/Vulkan/VKGfx.cpp
+++ b/Source/Core/VideoBackends/Vulkan/VKGfx.cpp
@@ -88,11 +88,13 @@ std::unique_ptr<AbstractPipeline> VKGfx::CreatePipeline(const AbstractPipelineCo
return VKPipeline::Create(config);
}
-std::unique_ptr<AbstractFramebuffer> VKGfx::CreateFramebuffer(AbstractTexture* color_attachment,
- AbstractTexture* depth_attachment)
+std::unique_ptr<AbstractFramebuffer>
+VKGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
return VKFramebuffer::Create(static_cast<VKTexture*>(color_attachment),
- static_cast<VKTexture*>(depth_attachment));
+ static_cast<VKTexture*>(depth_attachment),
+ std::move(additional_color_attachments));
}
void VKGfx::SetPipeline(const AbstractPipeline* pipeline)
@@ -138,12 +140,12 @@ void VKGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_en
if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_CLEAR_LOADOP_RENDERPASS))
use_clear_render_pass = false;
+ auto* vk_frame_buffer = static_cast<VKFramebuffer*>(m_current_framebuffer);
+
// Fastest path: Use a render pass to clear the buffers.
if (use_clear_render_pass)
{
- const std::array<VkClearValue, 2> clear_values = {{clear_color_value, clear_depth_value}};
- StateTracker::GetInstance()->BeginClearRenderPass(target_vk_rc, clear_values.data(),
- static_cast<u32>(clear_values.size()));
+ vk_frame_buffer->SetAndClear(target_vk_rc, clear_color_value, clear_depth_value);
return;
}
@@ -151,26 +153,40 @@ void VKGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_en
// We can't use this when preserving alpha but clearing color.
if (use_clear_attachments)
{
- VkClearAttachment clear_attachments[2];
- uint32_t num_clear_attachments = 0;
+ std::vector<VkClearAttachment> clear_attachments;
+ bool has_color = false;
if (color_enable && alpha_enable)
{
- clear_attachments[num_clear_attachments].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- clear_attachments[num_clear_attachments].colorAttachment = 0;
- clear_attachments[num_clear_attachments].clearValue = clear_color_value;
- num_clear_attachments++;
+ VkClearAttachment clear_attachment;
+ clear_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ clear_attachment.colorAttachment = 0;
+ clear_attachment.clearValue = clear_color_value;
+ clear_attachments.push_back(std::move(clear_attachment));
color_enable = false;
alpha_enable = false;
+ has_color = true;
}
if (z_enable)
{
- clear_attachments[num_clear_attachments].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
- clear_attachments[num_clear_attachments].colorAttachment = 0;
- clear_attachments[num_clear_attachments].clearValue = clear_depth_value;
- num_clear_attachments++;
+ VkClearAttachment clear_attachment;
+ clear_attachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
+ clear_attachment.colorAttachment = 0;
+ clear_attachment.clearValue = clear_depth_value;
+ clear_attachments.push_back(std::move(clear_attachment));
z_enable = false;
}
- if (num_clear_attachments > 0)
+ if (has_color)
+ {
+ for (std::size_t i = 0; i < vk_frame_buffer->GetNumberOfAdditonalAttachments(); i++)
+ {
+ VkClearAttachment clear_attachment;
+ clear_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ clear_attachment.colorAttachment = 0;
+ clear_attachment.clearValue = clear_color_value;
+ clear_attachments.push_back(std::move(clear_attachment));
+ }
+ }
+ if (!clear_attachments.empty())
{
VkClearRect vk_rect = {target_vk_rc, 0, g_framebuffer_manager->GetEFBLayers()};
if (!StateTracker::GetInstance()->IsWithinRenderArea(
@@ -181,8 +197,9 @@ void VKGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_en
}
StateTracker::GetInstance()->BeginRenderPass();
- vkCmdClearAttachments(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_clear_attachments,
- clear_attachments, 1, &vk_rect);
+ vkCmdClearAttachments(g_command_buffer_mgr->GetCurrentCommandBuffer(),
+ static_cast<uint32_t>(clear_attachments.size()),
+ clear_attachments.data(), 1, &vk_rect);
}
}
@@ -405,16 +422,7 @@ void VKGfx::BindFramebuffer(VKFramebuffer* fb)
StateTracker::GetInstance()->EndRenderPass();
// Shouldn't be bound as a texture.
- if (fb->GetColorAttachment())
- {
- StateTracker::GetInstance()->UnbindTexture(
- static_cast<VKTexture*>(fb->GetColorAttachment())->GetView());
- }
- if (fb->GetDepthAttachment())
- {
- StateTracker::GetInstance()->UnbindTexture(
- static_cast<VKTexture*>(fb->GetDepthAttachment())->GetView());
- }
+ fb->Unbind();
fb->TransitionForRender();
StateTracker::GetInstance()->SetFramebuffer(fb);
@@ -449,22 +457,13 @@ void VKGfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const Clear
VKFramebuffer* vkfb = static_cast<VKFramebuffer*>(framebuffer);
BindFramebuffer(vkfb);
- std::array<VkClearValue, 2> clear_values;
- u32 num_clear_values = 0;
- if (vkfb->GetColorFormat() != AbstractTextureFormat::Undefined)
- {
- std::memcpy(clear_values[num_clear_values].color.float32, color_value.data(),
- sizeof(clear_values[num_clear_values].color.float32));
- num_clear_values++;
- }
- if (vkfb->GetDepthFormat() != AbstractTextureFormat::Undefined)
- {
- clear_values[num_clear_values].depthStencil.depth = depth_value;
- clear_values[num_clear_values].depthStencil.stencil = 0;
- num_clear_values++;
- }
- StateTracker::GetInstance()->BeginClearRenderPass(vkfb->GetRect(), clear_values.data(),
- num_clear_values);
+ VkClearValue clear_color_value;
+ std::memcpy(clear_color_value.color.float32, color_value.data(),
+ sizeof(clear_color_value.color.float32));
+ VkClearValue clear_depth_value;
+ clear_depth_value.depthStencil.depth = depth_value;
+ clear_depth_value.depthStencil.stencil = 0;
+ vkfb->SetAndClear(vkfb->GetRect(), clear_color_value, clear_depth_value);
}
void VKGfx::SetTexture(u32 index, const AbstractTexture* texture)
diff --git a/Source/Core/VideoBackends/Vulkan/VKGfx.h b/Source/Core/VideoBackends/Vulkan/VKGfx.h
index 97ddcbf585..c6d6201714 100644
--- a/Source/Core/VideoBackends/Vulkan/VKGfx.h
+++ b/Source/Core/VideoBackends/Vulkan/VKGfx.h
@@ -35,7 +35,8 @@ public:
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
- CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
+ CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments) override;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
std::string_view name) override;
diff --git a/Source/Core/VideoBackends/Vulkan/VKPipeline.cpp b/Source/Core/VideoBackends/Vulkan/VKPipeline.cpp
index ad59ee89a7..7e5643df83 100644
--- a/Source/Core/VideoBackends/Vulkan/VKPipeline.cpp
+++ b/Source/Core/VideoBackends/Vulkan/VKPipeline.cpp
@@ -72,11 +72,11 @@ static VkPipelineMultisampleStateCreateInfo GetVulkanMultisampleState(const Fram
0, // VkPipelineMultisampleStateCreateFlags flags
static_cast<VkSampleCountFlagBits>(
state.samples.Value()), // VkSampleCountFlagBits rasterizationSamples
- state.per_sample_shading, // VkBool32 sampleShadingEnable
- 1.0f, // float minSampleShading
- nullptr, // const VkSampleMask* pSampleMask;
- VK_FALSE, // VkBool32 alphaToCoverageEnable
- VK_FALSE // VkBool32 alphaToOneEnable
+ static_cast<bool>(state.per_sample_shading), // VkBool32 sampleShadingEnable
+ 1.0f, // float minSampleShading
+ nullptr, // const VkSampleMask* pSampleMask;
+ VK_FALSE, // VkBool32 alphaToCoverageEnable
+ VK_FALSE // VkBool32 alphaToOneEnable
};
}
@@ -243,7 +243,14 @@ std::unique_ptr<VKPipeline> VKPipeline::Create(const AbstractPipelineConfig& con
VkRenderPass render_pass = g_object_cache->GetRenderPass(
VKTexture::GetVkFormatForHostTextureFormat(config.framebuffer_state.color_texture_format),
VKTexture::GetVkFormatForHostTextureFormat(config.framebuffer_state.depth_texture_format),
- config.framebuffer_state.samples, VK_ATTACHMENT_LOAD_OP_LOAD);
+ config.framebuffer_state.samples, VK_ATTACHMENT_LOAD_OP_LOAD,
+ config.framebuffer_state.additional_color_attachment_count);
+
+ if (render_pass == VK_NULL_HANDLE)
+ {
+ PanicAlertFmt("Failed to get render pass");
+ return nullptr;
+ }
// Get pipeline layout.
VkPipelineLayout pipeline_layout;
@@ -343,8 +350,18 @@ std::unique_ptr<VKPipeline> VKPipeline::Create(const AbstractPipelineConfig& con
GetVulkanDepthStencilState(config.depth_state);
VkPipelineColorBlendAttachmentState blend_attachment_state =
GetVulkanAttachmentBlendState(config.blending_state, config.usage);
+
+ std::vector<VkPipelineColorBlendAttachmentState> blend_attachment_states;
+ blend_attachment_states.push_back(blend_attachment_state);
+ // Right now all our attachments have the same state
+ for (u8 i = 0; i < static_cast<u8>(config.framebuffer_state.additional_color_attachment_count);
+ i++)
+ {
+ blend_attachment_states.push_back(blend_attachment_state);
+ }
VkPipelineColorBlendStateCreateInfo blend_state =
- GetVulkanColorBlendState(config.blending_state, &blend_attachment_state, 1);
+ GetVulkanColorBlendState(config.blending_state, blend_attachment_states.data(),
+ static_cast<uint32_t>(blend_attachment_states.size()));
// This viewport isn't used, but needs to be specified anyway.
static const VkViewport viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
diff --git a/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp b/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp
index 71fb6bf9ba..5e76adf788 100644
--- a/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp
+++ b/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp
@@ -415,7 +415,7 @@ bool SwapChain::SetupSwapChainImages()
if (!image.texture)
return false;
- image.framebuffer = VKFramebuffer::Create(image.texture.get(), nullptr);
+ image.framebuffer = VKFramebuffer::Create(image.texture.get(), nullptr, {});
if (!image.framebuffer)
{
image.texture.reset();
diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp
index 201ee5f84f..1f0b1ff0d2 100644
--- a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp
+++ b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp
@@ -988,12 +988,13 @@ void VKStagingTexture::Flush()
m_needs_flush = false;
}
-VKFramebuffer::VKFramebuffer(VKTexture* color_attachment, VKTexture* depth_attachment, u32 width,
+VKFramebuffer::VKFramebuffer(VKTexture* color_attachment, VKTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments, u32 width,
u32 height, u32 layers, u32 samples, VkFramebuffer fb,
VkRenderPass load_render_pass, VkRenderPass discard_render_pass,
VkRenderPass clear_render_pass)
: AbstractFramebuffer(
- color_attachment, depth_attachment,
+ color_attachment, depth_attachment, std::move(additional_color_attachments),
color_attachment ? color_attachment->GetFormat() : AbstractTextureFormat::Undefined,
depth_attachment ? depth_attachment->GetFormat() : AbstractTextureFormat::Undefined,
width, height, layers, samples),
@@ -1007,10 +1008,11 @@ VKFramebuffer::~VKFramebuffer()
g_command_buffer_mgr->DeferFramebufferDestruction(m_fb);
}
-std::unique_ptr<VKFramebuffer> VKFramebuffer::Create(VKTexture* color_attachment,
- VKTexture* depth_attachment)
+std::unique_ptr<VKFramebuffer>
+VKFramebuffer::Create(VKTexture* color_attachment, VKTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments)
{
- if (!ValidateConfig(color_attachment, depth_attachment))
+ if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments))
return nullptr;
const VkFormat vk_color_format =
@@ -1023,21 +1025,27 @@ std::unique_ptr<VKFramebuffer> VKFramebuffer::Create(VKTexture* color_attachment
const u32 layers = either_attachment->GetLayers();
const u32 samples = either_attachment->GetSamples();
- std::array<VkImageView, 2> attachment_views{};
- u32 num_attachments = 0;
-
+ std::vector<VkImageView> attachment_views;
if (color_attachment)
- attachment_views[num_attachments++] = color_attachment->GetView();
+ attachment_views.push_back(color_attachment->GetView());
if (depth_attachment)
- attachment_views[num_attachments++] = depth_attachment->GetView();
+ attachment_views.push_back(depth_attachment->GetView());
+
+ for (auto* attachment : additional_color_attachments)
+ {
+ attachment_views.push_back(static_cast<VKTexture*>(attachment)->GetView());
+ }
VkRenderPass load_render_pass = g_object_cache->GetRenderPass(
- vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_LOAD);
+ vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_LOAD,
+ static_cast<u8>(additional_color_attachments.size()));
VkRenderPass discard_render_pass = g_object_cache->GetRenderPass(
- vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
+ vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+ static_cast<u8>(additional_color_attachments.size()));
VkRenderPass clear_render_pass = g_object_cache->GetRenderPass(
- vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_CLEAR);
+ vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_CLEAR,
+ static_cast<u8>(additional_color_attachments.size()));
if (load_render_pass == VK_NULL_HANDLE || discard_render_pass == VK_NULL_HANDLE ||
clear_render_pass == VK_NULL_HANDLE)
{
@@ -1048,7 +1056,7 @@ std::unique_ptr<VKFramebuffer> VKFramebuffer::Create(VKTexture* color_attachment
nullptr,
0,
load_render_pass,
- num_attachments,
+ static_cast<uint32_t>(attachment_views.size()),
attachment_views.data(),
width,
height,
@@ -1063,9 +1071,27 @@ std::unique_ptr<VKFramebuffer> VKFramebuffer::Create(VKTexture* color_attachment
return nullptr;
}
- return std::make_unique<VKFramebuffer>(color_attachment, depth_attachment, width, height, layers,
- samples, fb, load_render_pass, discard_render_pass,
- clear_render_pass);
+ return std::make_unique<VKFramebuffer>(
+ color_attachment, depth_attachment, std::move(additional_color_attachments), width, height,
+ layers, samples, fb, load_render_pass, discard_render_pass, clear_render_pass);
+}
+
+void VKFramebuffer::Unbind()
+{
+ if (m_color_attachment)
+ {
+ StateTracker::GetInstance()->UnbindTexture(
+ static_cast<VKTexture*>(m_color_attachment)->GetView());
+ }
+ for (auto* attachment : m_additional_color_attachments)
+ {
+ StateTracker::GetInstance()->UnbindTexture(static_cast<VKTexture*>(attachment)->GetView());
+ }
+ if (m_depth_attachment)
+ {
+ StateTracker::GetInstance()->UnbindTexture(
+ static_cast<VKTexture*>(m_depth_attachment)->GetView());
+ }
}
void VKFramebuffer::TransitionForRender()
@@ -1076,6 +1102,12 @@ void VKFramebuffer::TransitionForRender()
->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
+ for (auto* attachment : m_additional_color_attachments)
+ {
+ static_cast<VKTexture*>(attachment)
+ ->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ }
if (m_depth_attachment)
{
@@ -1084,4 +1116,24 @@ void VKFramebuffer::TransitionForRender()
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
}
+
+void VKFramebuffer::SetAndClear(const VkRect2D& rect, const VkClearValue& color_value,
+ const VkClearValue& depth_value)
+{
+ std::vector<VkClearValue> clear_values;
+ if (GetColorFormat() != AbstractTextureFormat::Undefined)
+ {
+ clear_values.push_back(color_value);
+ }
+ if (GetDepthFormat() != AbstractTextureFormat::Undefined)
+ {
+ clear_values.push_back(depth_value);
+ }
+ for (std::size_t i = 0; i < m_additional_color_attachments.size(); i++)
+ {
+ clear_values.push_back(color_value);
+ }
+ StateTracker::GetInstance()->BeginClearRenderPass(rect, clear_values.data(),
+ static_cast<u32>(clear_values.size()));
+}
} // namespace Vulkan
diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.h b/Source/Core/VideoBackends/Vulkan/VKTexture.h
index 1862da3825..b675e593fe 100644
--- a/Source/Core/VideoBackends/Vulkan/VKTexture.h
+++ b/Source/Core/VideoBackends/Vulkan/VKTexture.h
@@ -126,7 +126,8 @@ private:
class VKFramebuffer final : public AbstractFramebuffer
{
public:
- VKFramebuffer(VKTexture* color_attachment, VKTexture* depth_attachment, u32 width, u32 height,
+ VKFramebuffer(VKTexture* color_attachment, VKTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments, u32 width, u32 height,
u32 layers, u32 samples, VkFramebuffer fb, VkRenderPass load_render_pass,
VkRenderPass discard_render_pass, VkRenderPass clear_render_pass);
~VKFramebuffer() override;
@@ -137,10 +138,20 @@ public:
VkRenderPass GetLoadRenderPass() const { return m_load_render_pass; }
VkRenderPass GetDiscardRenderPass() const { return m_discard_render_pass; }
VkRenderPass GetClearRenderPass() const { return m_clear_render_pass; }
+
+ void Unbind();
void TransitionForRender();
- static std::unique_ptr<VKFramebuffer> Create(VKTexture* color_attachments,
- VKTexture* depth_attachment);
+ void SetAndClear(const VkRect2D& rect, const VkClearValue& color_value,
+ const VkClearValue& depth_value);
+ std::size_t GetNumberOfAdditonalAttachments() const
+ {
+ return m_additional_color_attachments.size();
+ }
+
+ static std::unique_ptr<VKFramebuffer>
+ Create(VKTexture* color_attachments, VKTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments);
protected:
VkFramebuffer m_fb;
diff --git a/Source/Core/VideoCommon/AbstractFramebuffer.cpp b/Source/Core/VideoCommon/AbstractFramebuffer.cpp
index 982357e691..beb6c6752b 100644
--- a/Source/Core/VideoCommon/AbstractFramebuffer.cpp
+++ b/Source/Core/VideoCommon/AbstractFramebuffer.cpp
@@ -6,10 +6,12 @@
AbstractFramebuffer::AbstractFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format,
AbstractTextureFormat depth_format, u32 width, u32 height,
u32 layers, u32 samples)
: m_color_attachment(color_attachment), m_depth_attachment(depth_attachment),
+ m_additional_color_attachments(std::move(additional_color_attachments)),
m_color_format(color_format), m_depth_format(depth_format), m_width(width), m_height(height),
m_layers(layers), m_samples(samples)
{
@@ -17,13 +19,18 @@ AbstractFramebuffer::AbstractFramebuffer(AbstractTexture* color_attachment,
AbstractFramebuffer::~AbstractFramebuffer() = default;
-bool AbstractFramebuffer::ValidateConfig(const AbstractTexture* color_attachment,
- const AbstractTexture* depth_attachment)
+bool AbstractFramebuffer::ValidateConfig(
+ const AbstractTexture* color_attachment, const AbstractTexture* depth_attachment,
+ const std::vector<AbstractTexture*>& additional_color_attachments)
{
// Must have at least a color or depth attachment.
if (!color_attachment && !depth_attachment)
return false;
+ // Must have a color attachment if additional color attachments are defined
+ if (!color_attachment && !additional_color_attachments.empty())
+ return false;
+
// Currently we only expose a single mip level for render target textures.
// MSAA textures are not supported with mip levels on most backends, and it simplifies our
// handling of framebuffers.
@@ -36,6 +43,14 @@ bool AbstractFramebuffer::ValidateConfig(const AbstractTexture* color_attachment
return false;
}
+ for (auto* attachment : additional_color_attachments)
+ {
+ if (!CheckAttachment(attachment))
+ {
+ return false;
+ }
+ }
+
// If both color and depth are present, their attributes must match.
if (color_attachment && depth_attachment)
{
@@ -48,6 +63,16 @@ bool AbstractFramebuffer::ValidateConfig(const AbstractTexture* color_attachment
}
}
+ for (auto* attachment : additional_color_attachments)
+ {
+ if (color_attachment->GetConfig().width != attachment->GetConfig().width ||
+ color_attachment->GetConfig().height != attachment->GetConfig().height ||
+ color_attachment->GetConfig().samples != attachment->GetConfig().samples)
+ {
+ return false;
+ }
+ }
+
return true;
}
diff --git a/Source/Core/VideoCommon/AbstractFramebuffer.h b/Source/Core/VideoCommon/AbstractFramebuffer.h
index 25b7aeebda..e4c3b0451c 100644
--- a/Source/Core/VideoCommon/AbstractFramebuffer.h
+++ b/Source/Core/VideoCommon/AbstractFramebuffer.h
@@ -3,6 +3,8 @@
#pragma once
+#include <vector>
+
#include "Common/CommonTypes.h"
#include "Common/MathUtil.h"
#include "VideoCommon/TextureConfig.h"
@@ -18,12 +20,14 @@ class AbstractFramebuffer
{
public:
AbstractFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
u32 width, u32 height, u32 layers, u32 samples);
virtual ~AbstractFramebuffer();
static bool ValidateConfig(const AbstractTexture* color_attachment,
- const AbstractTexture* depth_attachment);
+ const AbstractTexture* depth_attachment,
+ const std::vector<AbstractTexture*>& additional_color_attachments);
AbstractTexture* GetColorAttachment() const { return m_color_attachment; }
AbstractTexture* GetDepthAttachment() const { return m_depth_attachment; }
@@ -42,6 +46,7 @@ protected:
AbstractTexture* m_depth_attachment;
AbstractTextureFormat m_color_format;
AbstractTextureFormat m_depth_format;
+ std::vector<AbstractTexture*> m_additional_color_attachments;
u32 m_width;
u32 m_height;
u32 m_layers;
diff --git a/Source/Core/VideoCommon/AbstractGfx.h b/Source/Core/VideoCommon/AbstractGfx.h
index fff8bbf3f6..fb8351ff88 100644
--- a/Source/Core/VideoCommon/AbstractGfx.h
+++ b/Source/Core/VideoCommon/AbstractGfx.h
@@ -10,6 +10,7 @@
#include <array>
#include <memory>
+#include <vector>
class AbstractFramebuffer;
class AbstractPipeline;
@@ -75,7 +76,8 @@ public:
virtual std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) = 0;
virtual std::unique_ptr<AbstractFramebuffer>
- CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) = 0;
+ CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ std::vector<AbstractTexture*> additional_color_attachments = {}) = 0;
// Framebuffer operations.
virtual void SetFramebuffer(AbstractFramebuffer* framebuffer);
diff --git a/Source/Core/VideoCommon/GXPipelineTypes.h b/Source/Core/VideoCommon/GXPipelineTypes.h
index fdb76a6646..4089fac40e 100644
--- a/Source/Core/VideoCommon/GXPipelineTypes.h
+++ b/Source/Core/VideoCommon/GXPipelineTypes.h
@@ -19,7 +19,7 @@ namespace VideoCommon
// As pipelines encompass both shader UIDs and render states, changes to either of these should
// also increment the pipeline UID version. Incrementing the UID version will cause all UID
// caches to be invalidated.
-constexpr u32 GX_PIPELINE_UID_VERSION = 6; // Last changed in PR 10890
+constexpr u32 GX_PIPELINE_UID_VERSION = 7; // Last changed in PR 11859
struct GXPipelineUid
{
diff --git a/Source/Core/VideoCommon/RenderState.cpp b/Source/Core/VideoCommon/RenderState.cpp
index 0860488b8a..ec010756ba 100644
--- a/Source/Core/VideoCommon/RenderState.cpp
+++ b/Source/Core/VideoCommon/RenderState.cpp
@@ -453,6 +453,7 @@ FramebufferState GetColorFramebufferState(AbstractTextureFormat format)
state.depth_texture_format = AbstractTextureFormat::Undefined;
state.per_sample_shading = false;
state.samples = 1;
+ state.additional_color_attachment_count = 0;
return state;
}
diff --git a/Source/Core/VideoCommon/RenderState.h b/Source/Core/VideoCommon/RenderState.h
index b52a6d2851..8e0902b88e 100644
--- a/Source/Core/VideoCommon/RenderState.h
+++ b/Source/Core/VideoCommon/RenderState.h
@@ -80,6 +80,12 @@ union FramebufferState
BitField<16, 8, u32> samples;
BitField<24, 1, u32> per_sample_shading;
+ // Note: all additional color attachments
+ // have the same format as `color_texture_format`
+ // TODO: in the future improve this so every attachment
+ // can specify its own format
+ BitField<25, 3, u32> additional_color_attachment_count;
+
u32 hex = 0;
};