Skip to content

Commit

Permalink
Merge pull request #11859 from iwubcode/backend-multi-output
Browse files Browse the repository at this point in the history
VideoBackends: add support to allow rendering to multiple output targets
  • Loading branch information
AdmiralCurtiss authored Jun 9, 2023
2 parents e16791f + 8c3dc5b commit 092773a
Show file tree
Hide file tree
Showing 44 changed files with 713 additions and 327 deletions.
30 changes: 8 additions & 22 deletions Source/Core/VideoBackends/D3D/D3DGfx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/VideoBackends/D3D/D3DGfx.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class Gfx final : public ::AbstractGfx
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;
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/VideoBackends/D3D/D3DState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoBackends/D3D/D3DSwapChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
96 changes: 86 additions & 10 deletions Source/Core/VideoBackends/D3D/DXTexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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)
{
Expand All @@ -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
24 changes: 17 additions & 7 deletions Source/Core/VideoBackends/D3D/DXTexture.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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;
};
Expand Down
56 changes: 18 additions & 38 deletions Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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,
Expand All @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/VideoBackends/D3D12/D3D12Gfx.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class Gfx final : public ::AbstractGfx
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;
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoBackends/D3D12/D3D12SwapChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 092773a

Please sign in to comment.