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 Gfx::CreateStagingTexture(StagingTexture return DXStagingTexture::Create(type, config); } -std::unique_ptr Gfx::CreateFramebuffer(AbstractTexture* color_attachment, - AbstractTexture* depth_attachment) +std::unique_ptr +Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector additional_color_attachments) { return DXFramebuffer::Create(static_cast(color_attachment), - static_cast(depth_attachment)); + static_cast(depth_attachment), + std::move(additional_color_attachments)); } std::unique_ptr @@ -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(framebuffer); - if ((fb->GetColorAttachment() && - D3D::stateman->UnsetTexture( - static_cast(fb->GetColorAttachment())->GetD3DSRV()) != 0) || - (fb->GetDepthAttachment() && - D3D::stateman->UnsetTexture( - static_cast(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(framebuffer)->GetRTVArray()[0], color_value.data()); - } - if (framebuffer->GetDepthFormat() != AbstractTextureFormat::Undefined) - { - D3D::context->ClearDepthStencilView(static_cast(framebuffer)->GetDSV(), - D3D11_CLEAR_DEPTH, depth_value, 0); - } + DXFramebuffer* fb = static_cast(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 - CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override; + CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector 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 additional_color_attachments, AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width, u32 height, u32 layers, u32 samples, ComPtr rtv, ComPtr integer_rtv, - ComPtr 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 dsv, + std::vector> 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::Create(DXTexture* color_attachment, - DXTexture* depth_attachment) +void DXFramebuffer::Unbind() { - if (!ValidateConfig(color_attachment, depth_attachment)) + bool should_apply = false; + if (GetColorAttachment() && + D3D::stateman->UnsetTexture(static_cast(GetColorAttachment())->GetD3DSRV()) != 0) + { + should_apply = true; + } + + if (GetDepthAttachment() && + D3D::stateman->UnsetTexture(static_cast(GetDepthAttachment())->GetD3DSRV()) != 0) + { + should_apply = true; + } + + for (auto additional_color_attachment : m_additional_color_attachments) + { + if (D3D::stateman->UnsetTexture( + static_cast(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::Create(DXTexture* color_attachment, DXTexture* depth_attachment, + std::vector additional_color_attachments) +{ + if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments)) return nullptr; const AbstractTextureFormat color_format = @@ -382,6 +438,25 @@ std::unique_ptr DXFramebuffer::Create(DXTexture* color_attachment } } + std::vector> additional_rtvs; + for (auto additional_color_attachment : additional_color_attachments) + { + ComPtr 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(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 dsv; if (depth_attachment) { @@ -398,9 +473,10 @@ std::unique_ptr DXFramebuffer::Create(DXTexture* color_attachment return nullptr; } - return std::make_unique(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( + 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 #include #include - +#include #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 additional_color_attachments, AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width, u32 height, u32 layers, u32 samples, ComPtr rtv, - ComPtr integer_rtv, ComPtr dsv); + ComPtr integer_rtv, ComPtr dsv, + std::vector> 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(m_render_targets_raw.size()); } ID3D11DepthStencilView* GetDSV() const { return m_dsv.Get(); } - static std::unique_ptr Create(DXTexture* color_attachment, - DXTexture* depth_attachment); + + void Unbind(); + void Clear(const ClearColor& color_value, float depth_value); + + static std::unique_ptr + Create(DXTexture* color_attachment, DXTexture* depth_attachment, + std::vector additional_color_attachments); protected: - ComPtr m_rtv; + std::vector> m_render_targets; + std::vector m_render_targets_raw; ComPtr m_integer_rtv; ComPtr 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 Gfx::CreateStagingTexture(StagingTexture return DXStagingTexture::Create(type, config); } -std::unique_ptr Gfx::CreateFramebuffer(AbstractTexture* color_attachment, - AbstractTexture* depth_attachment) +std::unique_ptr +Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector additional_color_attachments) { return DXFramebuffer::Create(static_cast(color_attachment), - static_cast(depth_attachment)); + static_cast(depth_attachment), + std::move(additional_color_attachments)); } std::unique_ptr @@ -109,20 +111,18 @@ void Gfx::ClearRegion(const MathUtil::Rectangle& 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(m_current_framebuffer); if (fast_color_clear) { - static_cast(m_current_framebuffer->GetColorAttachment()) - ->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); + d3d_frame_buffer->TransitionRenderTargets(); const std::array clear_color = { {static_cast((color >> 16) & 0xFF) / 255.0f, static_cast((color >> 8) & 0xFF) / 255.0f, static_cast((color >> 0) & 0xFF) / 255.0f, static_cast((color >> 24) & 0xFF) / 255.0f}}; - g_dx_context->GetCommandList()->ClearRenderTargetView( - static_cast(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& target_rc, bool color_enab // D3D does not support reversed depth ranges. const float clear_depth = 1.0f - static_cast(z & 0xFFFFFF) / 16777216.0f; - g_dx_context->GetCommandList()->ClearDepthStencilView( - static_cast(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(fb->GetColorAttachment()) - ->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); - } + fb->TransitionRenderTargets(); if (fb->HasDepthBuffer()) { static_cast(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(framebuffer); + d3d_frame_buffer->TransitionRenderTargets(); + if (d3d_frame_buffer->HasDepthBuffer()) { - DXTexture* color_attachment = static_cast(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(framebuffer->GetDepthAttachment()); - depth_attachment->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE); - g_dx_context->GetCommandList()->DiscardResource(depth_attachment->GetResource(), &dr); + static_cast(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(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& 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 CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override; std::unique_ptr - CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override; + CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector additional_color_attachments) override; std::unique_ptr 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 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; - } - - // 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) + D3D12_RENDER_TARGET_BLEND_DESC* rtblend = &desc->RenderTarget[i]; + if (state.colorupdate) { - 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->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) + { + 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::Create(const AbstractPipelineConfig& config, @@ -183,7 +188,8 @@ std::unique_ptr DXPipeline::Create(const AbstractPipelineConfig& con if (config.pixel_shader) desc.PS = static_cast(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::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(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(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(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 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); } } -std::unique_ptr DXFramebuffer::Create(DXTexture* color_attachment, - DXTexture* depth_attachment) +void DXFramebuffer::Unbind() { - if (!ValidateConfig(color_attachment, depth_attachment)) + static const D3D12_DISCARD_REGION dr = {0, nullptr, 0, 1}; + if (HasColorBuffer()) + { + g_dx_context->GetCommandList()->DiscardResource( + static_cast(GetColorAttachment())->GetResource(), &dr); + } + for (auto additional_color_attachment : m_additional_color_attachments) + { + g_dx_context->GetCommandList()->DiscardResource( + static_cast(additional_color_attachment)->GetResource(), &dr); + } + if (HasDepthBuffer()) + { + g_dx_context->GetCommandList()->DiscardResource( + static_cast(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(GetColorAttachment()) + ->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); + } + for (auto additional_color_attachment : m_additional_color_attachments) + { + static_cast(additional_color_attachment) + ->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); + } +} + +std::unique_ptr +DXFramebuffer::Create(DXTexture* color_attachment, DXTexture* depth_attachment, + std::vector additional_color_attachments) +{ + if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments)) return nullptr; const AbstractTextureFormat color_format = @@ -433,10 +493,10 @@ std::unique_ptr DXFramebuffer::Create(DXTexture* color_attachment const u32 layers = either_attachment->GetLayers(); const u32 samples = either_attachment->GetSamples(); - std::unique_ptr fb(new DXFramebuffer(color_attachment, depth_attachment, - color_format, depth_format, width, height, - layers, samples)); - if ((color_attachment && !fb->CreateRTVDescriptor()) || + std::unique_ptr 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::Create(DXTexture* color_attachment return fb; } -bool DXFramebuffer::CreateRTVDescriptor() +bool DXFramebuffer::CreateRTVDescriptors() { - if (!g_dx_context->GetRTVHeapManager().Allocate(&m_rtv_descriptor)) + 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) +{ + 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(m_color_attachment)->GetResource(), &rtv_desc, - m_rtv_descriptor.cpu_handle); + static_cast(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(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(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 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 + Create(DXTexture* color_attachment, DXTexture* depth_attachment, + std::vector additional_color_attachments); private: DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector 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 m_render_targets; + std::vector 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 CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override; std::unique_ptr - CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override; + CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector additional_color_attachments) override; std::unique_ptr 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 -Metal::Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) +Metal::Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector) { AbstractTexture* const either_attachment = color_attachment ? color_attachment : depth_attachment; return std::make_unique( 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 NullGfx::CreatePipeline(const AbstractPipeline return std::make_unique(); } -std::unique_ptr NullGfx::CreateFramebuffer(AbstractTexture* color_attachment, - AbstractTexture* depth_attachment) +std::unique_ptr +NullGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector additional_color_attachments) { return NullFramebuffer::Create(static_cast(color_attachment), - static_cast(depth_attachment)); + static_cast(depth_attachment), + std::move(additional_color_attachments)); } std::unique_ptr 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 CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override; std::unique_ptr - CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override; + CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector additional_color_attachments) override; std::unique_ptr 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 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::Create(NullTexture* color_attachment, - NullTexture* depth_attachment) +std::unique_ptr +NullFramebuffer::Create(NullTexture* color_attachment, NullTexture* depth_attachment, + std::vector 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::Create(NullTexture* color_atta const u32 layers = either_attachment->GetLayers(); const u32 samples = either_attachment->GetSamples(); - return std::make_unique(color_attachment, depth_attachment, color_format, + return std::make_unique(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 additional_color_attachments, AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width, u32 height, u32 layers, u32 samples); - static std::unique_ptr Create(NullTexture* color_attachment, - NullTexture* depth_attachment); + static std::unique_ptr + Create(NullTexture* color_attachment, NullTexture* depth_attachment, + std::vector 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 main_gl_context, float backbuffer_scal if (!m_main_gl_context->IsHeadless()) { m_system_framebuffer = std::make_unique( - nullptr, nullptr, AbstractTextureFormat::RGBA8, AbstractTextureFormat::Undefined, - std::max(m_main_gl_context->GetBackBufferWidth(), 1u), + nullptr, nullptr, std::vector{}, 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 OGLGfx::CreateStagingTexture(StagingText return OGLStagingTexture::Create(type, config); } -std::unique_ptr OGLGfx::CreateFramebuffer(AbstractTexture* color_attachment, - AbstractTexture* depth_attachment) +std::unique_ptr +OGLGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector additional_color_attachments) { return OGLFramebuffer::Create(static_cast(color_attachment), - static_cast(depth_attachment)); + static_cast(depth_attachment), + std::move(additional_color_attachments)); } std::unique_ptr 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 - CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override; + CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector 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 d3274a3528..12c1eb21c0 100644 --- a/Source/Core/VideoBackends/OGL/OGLTexture.cpp +++ b/Source/Core/VideoBackends/OGL/OGLTexture.cpp @@ -543,11 +543,13 @@ void OGLStagingTexture::Unmap() } OGLFramebuffer::OGLFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector 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) { } @@ -557,10 +559,11 @@ OGLFramebuffer::~OGLFramebuffer() glDeleteFramebuffers(1, &m_fbo); } -std::unique_ptr OGLFramebuffer::Create(OGLTexture* color_attachment, - OGLTexture* depth_attachment) +std::unique_ptr +OGLFramebuffer::Create(OGLTexture* color_attachment, OGLTexture* depth_attachment, + std::vector additional_color_attachments) { - if (!ValidateConfig(color_attachment, depth_attachment)) + if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments)) return nullptr; const AbstractTextureFormat color_format = @@ -577,6 +580,7 @@ std::unique_ptr OGLFramebuffer::Create(OGLTexture* color_attachm glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); + std::vector buffers; if (color_attachment) { if (color_attachment->GetConfig().layers > 1) @@ -589,6 +593,7 @@ std::unique_ptr 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) @@ -607,10 +612,29 @@ std::unique_ptr OGLFramebuffer::Create(OGLTexture* color_attachm } } + for (std::size_t i = 0; i < additional_color_attachments.size(); i++) + { + const auto attachment_enum = static_cast(GL_COLOR_ATTACHMENT0 + i + 1); + OGLTexture* attachment = static_cast(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(buffers.size()), buffers.data()); + DEBUG_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); GetOGLGfx()->RestoreFramebufferBinding(); - return std::make_unique(color_attachment, depth_attachment, color_format, + return std::make_unique(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 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 Create(OGLTexture* color_attachment, - OGLTexture* depth_attachment); + static std::unique_ptr + Create(OGLTexture* color_attachment, OGLTexture* depth_attachment, + std::vector 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 SWGfx::CreateStagingTexture(StagingTextu return std::make_unique(type, config); } -std::unique_ptr SWGfx::CreateFramebuffer(AbstractTexture* color_attachment, - AbstractTexture* depth_attachment) +std::unique_ptr +SWGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector additional_color_attachments) { return SWFramebuffer::Create(static_cast(color_attachment), - static_cast(depth_attachment)); + static_cast(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 CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override; std::unique_ptr - CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override; + CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector 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 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::Create(SWTexture* color_attachment, - SWTexture* depth_attachment) +std::unique_ptr +SWFramebuffer::Create(SWTexture* color_attachment, SWTexture* depth_attachment, + std::vector 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::Create(SWTexture* color_attachment const u32 layers = either_attachment->GetLayers(); const u32 samples = either_attachment->GetSamples(); - return std::make_unique(color_attachment, depth_attachment, color_format, + return std::make_unique(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 additional_color_attachments, AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width, u32 height, u32 layers, u32 samples); ~SWFramebuffer() override = default; - static std::unique_ptr Create(SWTexture* color_attachment, - SWTexture* depth_attachment); + static std::unique_ptr + Create(SWTexture* color_attachment, SWTexture* depth_attachment, + std::vector 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 attachments; - u32 num_attachments = 0; + std::vector attachments; + std::vector color_attachment_references; if (color_format != VK_FORMAT_UNDEFINED) { - attachments[num_attachments] = {0, - color_format, - static_cast(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(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(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(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(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(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(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(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(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(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 m_dummy_texture; // Render pass cache - using RenderPassCacheKey = std::tuple; + using RenderPassCacheKey = std::tuple; std::map 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 VKGfx::CreatePipeline(const AbstractPipelineCo return VKPipeline::Create(config); } -std::unique_ptr VKGfx::CreateFramebuffer(AbstractTexture* color_attachment, - AbstractTexture* depth_attachment) +std::unique_ptr +VKGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector additional_color_attachments) { return VKFramebuffer::Create(static_cast(color_attachment), - static_cast(depth_attachment)); + static_cast(depth_attachment), + std::move(additional_color_attachments)); } void VKGfx::SetPipeline(const AbstractPipeline* pipeline) @@ -138,12 +140,12 @@ void VKGfx::ClearRegion(const MathUtil::Rectangle& 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(m_current_framebuffer); + // Fastest path: Use a render pass to clear the buffers. if (use_clear_render_pass) { - const std::array clear_values = {{clear_color_value, clear_depth_value}}; - StateTracker::GetInstance()->BeginClearRenderPass(target_vk_rc, clear_values.data(), - static_cast(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& 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 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& 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(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(fb->GetColorAttachment())->GetView()); - } - if (fb->GetDepthAttachment()) - { - StateTracker::GetInstance()->UnbindTexture( - static_cast(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(framebuffer); BindFramebuffer(vkfb); - std::array 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 CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override; std::unique_ptr - CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override; + CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector additional_color_attachments) override; std::unique_ptr 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( 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(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::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::Create(const AbstractPipelineConfig& con GetVulkanDepthStencilState(config.depth_state); VkPipelineColorBlendAttachmentState blend_attachment_state = GetVulkanAttachmentBlendState(config.blending_state, config.usage); + + std::vector 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(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(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 14b33d2376..580c193aef 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp @@ -982,12 +982,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 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), @@ -1001,10 +1002,11 @@ VKFramebuffer::~VKFramebuffer() g_command_buffer_mgr->DeferFramebufferDestruction(m_fb); } -std::unique_ptr VKFramebuffer::Create(VKTexture* color_attachment, - VKTexture* depth_attachment) +std::unique_ptr +VKFramebuffer::Create(VKTexture* color_attachment, VKTexture* depth_attachment, + std::vector 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 = @@ -1017,21 +1019,27 @@ std::unique_ptr VKFramebuffer::Create(VKTexture* color_attachment const u32 layers = either_attachment->GetLayers(); const u32 samples = either_attachment->GetSamples(); - std::array attachment_views{}; - u32 num_attachments = 0; - + std::vector 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(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(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(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(additional_color_attachments.size())); if (load_render_pass == VK_NULL_HANDLE || discard_render_pass == VK_NULL_HANDLE || clear_render_pass == VK_NULL_HANDLE) { @@ -1042,7 +1050,7 @@ std::unique_ptr VKFramebuffer::Create(VKTexture* color_attachment nullptr, 0, load_render_pass, - num_attachments, + static_cast(attachment_views.size()), attachment_views.data(), width, height, @@ -1057,9 +1065,27 @@ std::unique_ptr VKFramebuffer::Create(VKTexture* color_attachment return nullptr; } - return std::make_unique(color_attachment, depth_attachment, width, height, layers, - samples, fb, load_render_pass, discard_render_pass, - clear_render_pass); + return std::make_unique( + 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(m_color_attachment)->GetView()); + } + for (auto* attachment : m_additional_color_attachments) + { + StateTracker::GetInstance()->UnbindTexture(static_cast(attachment)->GetView()); + } + if (m_depth_attachment) + { + StateTracker::GetInstance()->UnbindTexture( + static_cast(m_depth_attachment)->GetView()); + } } void VKFramebuffer::TransitionForRender() @@ -1070,6 +1096,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(attachment) + ->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + } if (m_depth_attachment) { @@ -1078,4 +1110,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 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(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 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 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 + Create(VKTexture* color_attachments, VKTexture* depth_attachment, + std::vector 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 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& 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 + #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 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& 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 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 #include +#include class AbstractFramebuffer; class AbstractPipeline; @@ -75,7 +76,8 @@ public: virtual std::unique_ptr CreateStagingTexture(StagingTextureType type, const TextureConfig& config) = 0; virtual std::unique_ptr - CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) = 0; + CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment, + std::vector additional_color_attachments = {}) = 0; // Framebuffer operations. virtual void SetFramebuffer(AbstractFramebuffer* framebuffer); 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; };