VideoBackends: add support to allow rendering to multiple output textures

This commit is contained in:
iwubcode 2023-05-28 20:59:02 -05:00
parent 252d3f353a
commit 834f8f7b5c
43 changed files with 713 additions and 327 deletions

View File

@ -61,11 +61,13 @@ std::unique_ptr<AbstractStagingTexture> Gfx::CreateStagingTexture(StagingTexture
return DXStagingTexture::Create(type, config);
}
std::unique_ptr<AbstractFramebuffer> Gfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
std::unique_ptr<AbstractFramebuffer>
Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments)
{
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
static_cast<DXTexture*>(depth_attachment));
static_cast<DXTexture*>(depth_attachment),
std::move(additional_color_attachments));
}
std::unique_ptr<AbstractShader>
@ -202,15 +204,7 @@ void Gfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
// We can't leave the framebuffer bound as a texture and a render target.
DXFramebuffer* fb = static_cast<DXFramebuffer*>(framebuffer);
if ((fb->GetColorAttachment() &&
D3D::stateman->UnsetTexture(
static_cast<DXTexture*>(fb->GetColorAttachment())->GetD3DSRV()) != 0) ||
(fb->GetDepthAttachment() &&
D3D::stateman->UnsetTexture(
static_cast<DXTexture*>(fb->GetDepthAttachment())->GetD3DSRV()) != 0))
{
D3D::stateman->ApplyTextures();
}
fb->Unbind();
D3D::stateman->SetFramebuffer(fb);
m_current_framebuffer = fb;
@ -227,16 +221,8 @@ void Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearCo
SetFramebuffer(framebuffer);
D3D::stateman->Apply();
if (framebuffer->GetColorFormat() != AbstractTextureFormat::Undefined)
{
D3D::context->ClearRenderTargetView(
static_cast<const DXFramebuffer*>(framebuffer)->GetRTVArray()[0], color_value.data());
}
if (framebuffer->GetDepthFormat() != AbstractTextureFormat::Undefined)
{
D3D::context->ClearDepthStencilView(static_cast<const DXFramebuffer*>(framebuffer)->GetDSV(),
D3D11_CLEAR_DEPTH, depth_value, 0);
}
DXFramebuffer* fb = static_cast<DXFramebuffer*>(framebuffer);
fb->Clear(color_value, depth_value);
}
void Gfx::SetTexture(u32 index, const AbstractTexture* texture)

View File

@ -41,7 +41,8 @@ public:
const void* cache_data = nullptr,
size_t cache_data_length = 0) override;
std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments) override;
void SetPipeline(const AbstractPipeline* pipeline) override;
void SetFramebuffer(AbstractFramebuffer* framebuffer) override;

View File

@ -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
{

View File

@ -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;

View File

@ -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()
{
if (!ValidateConfig(color_attachment, depth_attachment))
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, additional_color_attachments))
return nullptr;
const AbstractTextureFormat color_format =
@ -382,6 +438,25 @@ std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(DXTexture* color_attachment
}
}
std::vector<ComPtr<ID3D11RenderTargetView>> additional_rtvs;
for (auto additional_color_attachment : additional_color_attachments)
{
ComPtr<ID3D11RenderTargetView> additional_rtv;
CD3D11_RENDER_TARGET_VIEW_DESC desc(
additional_color_attachment->IsMultisampled() ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY :
D3D11_RTV_DIMENSION_TEXTURE2DARRAY,
D3DCommon::GetRTVFormatForAbstractFormat(additional_color_attachment->GetFormat(), false),
0, 0, 1);
HRESULT hr = D3D::device->CreateRenderTargetView(
static_cast<DXTexture*>(additional_color_attachment)->GetD3DTexture(), &desc,
additional_rtv.GetAddressOf());
ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Create render target view for framebuffer: {}",
DX11HRWrap(hr));
if (FAILED(hr))
return nullptr;
additional_rtvs.push_back(std::move(additional_rtv));
}
ComPtr<ID3D11DepthStencilView> dsv;
if (depth_attachment)
{
@ -398,9 +473,10 @@ std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(DXTexture* color_attachment
return nullptr;
}
return std::make_unique<DXFramebuffer>(color_attachment, depth_attachment, color_format,
depth_format, width, height, layers, samples,
std::move(rtv), std::move(integer_rtv), std::move(dsv));
return std::make_unique<DXFramebuffer>(
color_attachment, depth_attachment, std::move(additional_color_attachments), color_format,
depth_format, width, height, layers, samples, std::move(rtv), std::move(integer_rtv),
std::move(dsv), std::move(additional_rtvs));
}
} // namespace DX11

View File

@ -7,13 +7,15 @@
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include "Common/CommonTypes.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/RenderBase.h"
namespace DX11
{
@ -81,20 +83,28 @@ class DXFramebuffer final : public AbstractFramebuffer
{
public:
DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
u32 height, u32 layers, u32 samples, ComPtr<ID3D11RenderTargetView> rtv,
ComPtr<ID3D11RenderTargetView> integer_rtv, ComPtr<ID3D11DepthStencilView> dsv);
ComPtr<ID3D11RenderTargetView> integer_rtv, ComPtr<ID3D11DepthStencilView> dsv,
std::vector<ComPtr<ID3D11RenderTargetView>> additional_rtvs);
~DXFramebuffer() override;
ID3D11RenderTargetView* const* GetRTVArray() const { return m_rtv.GetAddressOf(); }
ID3D11RenderTargetView* const* GetRTVArray() const { return m_render_targets_raw.data(); }
ID3D11RenderTargetView* const* GetIntegerRTVArray() const { return m_integer_rtv.GetAddressOf(); }
UINT GetNumRTVs() const { return m_rtv ? 1 : 0; }
UINT GetNumRTVs() const { return static_cast<UINT>(m_render_targets_raw.size()); }
ID3D11DepthStencilView* GetDSV() const { return m_dsv.Get(); }
static std::unique_ptr<DXFramebuffer> Create(DXTexture* color_attachment,
DXTexture* depth_attachment);
void Unbind();
void Clear(const ClearColor& color_value, float depth_value);
static std::unique_ptr<DXFramebuffer>
Create(DXTexture* color_attachment, DXTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments);
protected:
ComPtr<ID3D11RenderTargetView> m_rtv;
std::vector<ComPtr<ID3D11RenderTargetView>> m_render_targets;
std::vector<ID3D11RenderTargetView*> m_render_targets_raw;
ComPtr<ID3D11RenderTargetView> m_integer_rtv;
ComPtr<ID3D11DepthStencilView> m_dsv;
};

View File

@ -59,11 +59,13 @@ std::unique_ptr<AbstractStagingTexture> Gfx::CreateStagingTexture(StagingTexture
return DXStagingTexture::Create(type, config);
}
std::unique_ptr<AbstractFramebuffer> Gfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
std::unique_ptr<AbstractFramebuffer>
Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments)
{
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
static_cast<DXTexture*>(depth_attachment));
static_cast<DXTexture*>(depth_attachment),
std::move(additional_color_attachments));
}
std::unique_ptr<AbstractShader>
@ -109,20 +111,18 @@ void Gfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enab
if (fast_color_clear || z_enable)
{
const D3D12_RECT d3d_clear_rc{target_rc.left, target_rc.top, target_rc.right, target_rc.bottom};
auto* d3d_frame_buffer = static_cast<const DXFramebuffer*>(m_current_framebuffer);
if (fast_color_clear)
{
static_cast<DXTexture*>(m_current_framebuffer->GetColorAttachment())
->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
d3d_frame_buffer->TransitionRenderTargets();
const std::array<float, 4> clear_color = {
{static_cast<float>((color >> 16) & 0xFF) / 255.0f,
static_cast<float>((color >> 8) & 0xFF) / 255.0f,
static_cast<float>((color >> 0) & 0xFF) / 255.0f,
static_cast<float>((color >> 24) & 0xFF) / 255.0f}};
g_dx_context->GetCommandList()->ClearRenderTargetView(
static_cast<const DXFramebuffer*>(m_current_framebuffer)->GetRTVDescriptor().cpu_handle,
clear_color.data(), 1, &d3d_clear_rc);
d3d_frame_buffer->ClearRenderTargets(clear_color, &d3d_clear_rc);
color_enable = false;
alpha_enable = false;
}
@ -134,9 +134,7 @@ void Gfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enab
// D3D does not support reversed depth ranges.
const float clear_depth = 1.0f - static_cast<float>(z & 0xFFFFFF) / 16777216.0f;
g_dx_context->GetCommandList()->ClearDepthStencilView(
static_cast<const DXFramebuffer*>(m_current_framebuffer)->GetDSVDescriptor().cpu_handle,
D3D12_CLEAR_FLAG_DEPTH, clear_depth, 0, 1, &d3d_clear_rc);
d3d_frame_buffer->ClearDepth(clear_depth, &d3d_clear_rc);
z_enable = false;
}
}
@ -180,11 +178,7 @@ void Gfx::SetPipeline(const AbstractPipeline* pipeline)
void Gfx::BindFramebuffer(DXFramebuffer* fb)
{
if (fb->HasColorBuffer())
{
static_cast<DXTexture*>(fb->GetColorAttachment())
->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
}
fb->TransitionRenderTargets();
if (fb->HasDepthBuffer())
{
static_cast<DXTexture*>(fb->GetDepthAttachment())
@ -212,19 +206,14 @@ void Gfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
SetFramebuffer(framebuffer);
static const D3D12_DISCARD_REGION dr = {0, nullptr, 0, 1};
if (framebuffer->HasColorBuffer())
DXFramebuffer* d3d_frame_buffer = static_cast<DXFramebuffer*>(framebuffer);
d3d_frame_buffer->TransitionRenderTargets();
if (d3d_frame_buffer->HasDepthBuffer())
{
DXTexture* color_attachment = static_cast<DXTexture*>(framebuffer->GetColorAttachment());
color_attachment->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
g_dx_context->GetCommandList()->DiscardResource(color_attachment->GetResource(), &dr);
}
if (framebuffer->HasDepthBuffer())
{
DXTexture* depth_attachment = static_cast<DXTexture*>(framebuffer->GetDepthAttachment());
depth_attachment->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE);
g_dx_context->GetCommandList()->DiscardResource(depth_attachment->GetResource(), &dr);
static_cast<DXTexture*>(d3d_frame_buffer->GetDepthAttachment())
->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE);
}
d3d_frame_buffer->Unbind();
}
void Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value,
@ -233,17 +222,8 @@ void Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearCo
DXFramebuffer* dxfb = static_cast<DXFramebuffer*>(framebuffer);
BindFramebuffer(dxfb);
static const D3D12_DISCARD_REGION dr = {0, nullptr, 0, 1};
if (framebuffer->HasColorBuffer())
{
g_dx_context->GetCommandList()->ClearRenderTargetView(dxfb->GetRTVDescriptor().cpu_handle,
color_value.data(), 0, nullptr);
}
if (framebuffer->HasDepthBuffer())
{
g_dx_context->GetCommandList()->ClearDepthStencilView(
dxfb->GetDSVDescriptor().cpu_handle, D3D12_CLEAR_FLAG_DEPTH, depth_value, 0, 0, nullptr);
}
dxfb->ClearRenderTargets(color_value, nullptr);
dxfb->ClearDepth(depth_value, nullptr);
}
void Gfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)

View File

@ -32,7 +32,8 @@ public:
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments) override;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
std::string_view name) override;

View File

@ -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)

View File

@ -85,7 +85,8 @@ static void GetD3DDepthDesc(D3D12_DEPTH_STENCIL_DESC* desc, const DepthState& st
state.updateenable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
}
static void GetD3DBlendDesc(D3D12_BLEND_DESC* desc, const BlendingState& state)
static void GetD3DBlendDesc(D3D12_BLEND_DESC* desc, const BlendingState& state,
u8 render_target_count)
{
static constexpr std::array<D3D12_BLEND, 8> src_dual_src_factors = {
{D3D12_BLEND_ZERO, D3D12_BLEND_ONE, D3D12_BLEND_DEST_COLOR, D3D12_BLEND_INV_DEST_COLOR,
@ -115,45 +116,49 @@ static void GetD3DBlendDesc(D3D12_BLEND_DESC* desc, const BlendingState& state)
desc->AlphaToCoverageEnable = FALSE;
desc->IndependentBlendEnable = FALSE;
D3D12_RENDER_TARGET_BLEND_DESC* rtblend = &desc->RenderTarget[0];
if (state.colorupdate)
for (u8 i = 0; i < render_target_count; i++)
{
rtblend->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED |
D3D12_COLOR_WRITE_ENABLE_GREEN |
D3D12_COLOR_WRITE_ENABLE_BLUE;
}
if (state.alphaupdate)
{
rtblend->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
}
// 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> DXPipeline::Create(const AbstractPipelineConfig& config,
@ -183,7 +188,8 @@ std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& con
if (config.pixel_shader)
desc.PS = static_cast<const DXShader*>(config.pixel_shader)->GetD3DByteCode();
GetD3DBlendDesc(&desc.BlendState, config.blending_state);
GetD3DBlendDesc(&desc.BlendState, config.blending_state,
config.framebuffer_state.additional_color_attachment_count + 1);
desc.SampleMask = 0xFFFFFFFF;
GetD3DRasterizerDesc(&desc.RasterizerState, config.rasterization_state, config.framebuffer_state);
GetD3DDepthDesc(&desc.DepthStencilState, config.depth_state);
@ -195,9 +201,25 @@ std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& con
desc.PrimitiveTopologyType = GetD3DTopologyType(config.rasterization_state);
if (config.framebuffer_state.color_texture_format != AbstractTextureFormat::Undefined)
{
desc.NumRenderTargets = 1;
desc.NumRenderTargets =
static_cast<u8>(config.framebuffer_state.additional_color_attachment_count) + 1;
desc.RTVFormats[0] = D3DCommon::GetRTVFormatForAbstractFormat(
config.framebuffer_state.color_texture_format, config.blending_state.logicopenable);
config.framebuffer_state.color_texture_format, false);
for (u8 i = 0; i < static_cast<u8>(config.framebuffer_state.additional_color_attachment_count);
i++)
{
// For now set all formats to be the same
desc.RTVFormats[i + 1] = D3DCommon::GetRTVFormatForAbstractFormat(
config.framebuffer_state.color_texture_format, false);
}
if (config.blending_state.logicopenable)
{
desc.NumRenderTargets++;
desc.RTVFormats[static_cast<u8>(config.framebuffer_state.additional_color_attachment_count) +
1] =
D3DCommon::GetRTVFormatForAbstractFormat(config.framebuffer_state.color_texture_format,
true);
}
}
if (config.framebuffer_state.depth_texture_format != AbstractTextureFormat::Undefined)
desc.DSVFormat =

View File

@ -393,10 +393,12 @@ void DXTexture::DestroyResource()
}
DXFramebuffer::DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
u32 width, u32 height, u32 layers, u32 samples)
: AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
height, layers, samples)
: AbstractFramebuffer(color_attachment, depth_attachment,
std::move(additional_color_attachments), color_format, depth_format,
width, height, layers, samples)
{
}
@ -412,15 +414,73 @@ DXFramebuffer::~DXFramebuffer()
g_dx_context->DeferDescriptorDestruction(g_dx_context->GetRTVHeapManager(),
m_int_rtv_descriptor.index);
}
}
for (auto render_target : m_render_targets)
{
g_dx_context->DeferDescriptorDestruction(g_dx_context->GetRTVHeapManager(),
m_rtv_descriptor.index);
render_target.index);
}
}
std::unique_ptr<DXFramebuffer> 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<DXTexture*>(GetColorAttachment())->GetResource(), &dr);
}
for (auto additional_color_attachment : m_additional_color_attachments)
{
g_dx_context->GetCommandList()->DiscardResource(
static_cast<DXTexture*>(additional_color_attachment)->GetResource(), &dr);
}
if (HasDepthBuffer())
{
g_dx_context->GetCommandList()->DiscardResource(
static_cast<DXTexture*>(GetDepthAttachment())->GetResource(), &dr);
}
}
void DXFramebuffer::ClearRenderTargets(const ClearColor& color_value,
const D3D12_RECT* rectangle) const
{
for (auto render_target : m_render_targets_raw)
{
g_dx_context->GetCommandList()->ClearRenderTargetView(render_target, color_value.data(),
rectangle ? 1 : 0, rectangle);
}
}
void DXFramebuffer::ClearDepth(float depth_value, const D3D12_RECT* rectangle) const
{
if (HasDepthBuffer())
{
g_dx_context->GetCommandList()->ClearDepthStencilView(GetDSVDescriptor().cpu_handle,
D3D12_CLEAR_FLAG_DEPTH, depth_value, 0,
rectangle ? 1 : 0, rectangle);
}
}
void DXFramebuffer::TransitionRenderTargets() const
{
if (HasColorBuffer())
{
static_cast<DXTexture*>(GetColorAttachment())
->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
}
for (auto additional_color_attachment : m_additional_color_attachments)
{
static_cast<DXTexture*>(additional_color_attachment)
->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
}
}
std::unique_ptr<DXFramebuffer>
DXFramebuffer::Create(DXTexture* color_attachment, DXTexture* depth_attachment,
std::vector<AbstractTexture*> 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> DXFramebuffer::Create(DXTexture* color_attachment
const u32 layers = either_attachment->GetLayers();
const u32 samples = either_attachment->GetSamples();
std::unique_ptr<DXFramebuffer> fb(new DXFramebuffer(color_attachment, depth_attachment,
color_format, depth_format, width, height,
layers, samples));
if ((color_attachment && !fb->CreateRTVDescriptor()) ||
std::unique_ptr<DXFramebuffer> fb(
new DXFramebuffer(color_attachment, depth_attachment, std::move(additional_color_attachments),
color_format, depth_format, width, height, layers, samples));
if (!fb->CreateRTVDescriptors() || (color_attachment && !fb->CreateIRTVDescriptor()) ||
(depth_attachment && !fb->CreateDSVDescriptor()))
{
return nullptr;
@ -445,38 +505,73 @@ std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(DXTexture* color_attachment
return fb;
}
bool DXFramebuffer::CreateRTVDescriptor()
bool DXFramebuffer::CreateRTVDescriptors()
{
if (!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<DXTexture*>(m_color_attachment)->GetResource(), &rtv_desc,
m_rtv_descriptor.cpu_handle);
static_cast<DXTexture*>(attachment)->GetResource(), &rtv_desc, m_render_targets_raw.back());
return true;
}
bool DXFramebuffer::CreateIRTVDescriptor()
{
const bool multisampled = m_samples > 1;
DXGI_FORMAT non_int_format = D3DCommon::GetRTVFormatForAbstractFormat(m_color_format, false);
DXGI_FORMAT int_format = D3DCommon::GetRTVFormatForAbstractFormat(m_color_format, true);
if (int_format != rtv_desc.Format)
if (int_format != non_int_format)
{
if (!g_dx_context->GetRTVHeapManager().Allocate(&m_int_rtv_descriptor))
return false;
rtv_desc.Format = int_format;
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {int_format, multisampled ?
D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY :
D3D12_RTV_DIMENSION_TEXTURE2DARRAY};
if (multisampled)
rtv_desc.Texture2DMSArray.ArraySize = m_layers;
else
rtv_desc.Texture2DArray.ArraySize = m_layers;
g_dx_context->GetDevice()->CreateRenderTargetView(
static_cast<DXTexture*>(m_color_attachment)->GetResource(), &rtv_desc,
m_int_rtv_descriptor.cpu_handle);
}
return true;
}

View File

@ -10,8 +10,10 @@
#include "VideoBackends/D3D12/Common.h"
#include "VideoBackends/D3D12/DescriptorHeapManager.h"
#include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/RenderBase.h"
namespace DX12
{
@ -65,14 +67,13 @@ class DXFramebuffer final : public AbstractFramebuffer
public:
~DXFramebuffer() override;
const DescriptorHandle& GetRTVDescriptor() const { return m_rtv_descriptor; }
const DescriptorHandle& GetIntRTVDescriptor() const { return m_int_rtv_descriptor; }
const DescriptorHandle& GetDSVDescriptor() const { return m_dsv_descriptor; }
UINT GetRTVDescriptorCount() const { return m_color_attachment ? 1 : 0; }
UINT GetRTVDescriptorCount() const { return static_cast<UINT>(m_render_targets.size()); }
const D3D12_CPU_DESCRIPTOR_HANDLE* GetRTVDescriptorArray() const
{
return m_color_attachment ? &m_rtv_descriptor.cpu_handle : nullptr;
return m_render_targets_raw.data();
}
const D3D12_CPU_DESCRIPTOR_HANDLE* GetIntRTVDescriptorArray() const
{
@ -83,18 +84,28 @@ public:
return m_depth_attachment ? &m_dsv_descriptor.cpu_handle : nullptr;
}
static std::unique_ptr<DXFramebuffer> Create(DXTexture* color_attachment,
DXTexture* depth_attachment);
void Unbind();
void ClearRenderTargets(const ClearColor& color_value, const D3D12_RECT* rectangle) const;
void ClearDepth(float depth_value, const D3D12_RECT* rectangle) const;
void TransitionRenderTargets() const;
static std::unique_ptr<DXFramebuffer>
Create(DXTexture* color_attachment, DXTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments);
private:
DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
u32 height, u32 layers, u32 samples);
bool CreateRTVDescriptor();
bool CreateRTVDescriptors();
bool CreateRTVDescriptor(u32 layers, AbstractTexture* attachment);
bool CreateIRTVDescriptor();
bool CreateDSVDescriptor();
DescriptorHandle m_rtv_descriptor = {};
std::vector<DescriptorHandle> m_render_targets;
std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> m_render_targets_raw;
DescriptorHandle m_int_rtv_descriptor = {};
DescriptorHandle m_dsv_descriptor = {};
};

View File

@ -28,7 +28,8 @@ public:
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments) override;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
std::string_view name) override;

View File

@ -93,7 +93,8 @@ Metal::Gfx::CreateStagingTexture(StagingTextureType type, const TextureConfig& c
}
std::unique_ptr<AbstractFramebuffer>
Metal::Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment)
Metal::Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*>)
{
AbstractTexture* const either_attachment = color_attachment ? color_attachment : depth_attachment;
return std::make_unique<Framebuffer>(

View File

@ -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)

View File

@ -77,11 +77,13 @@ std::unique_ptr<AbstractPipeline> NullGfx::CreatePipeline(const AbstractPipeline
return std::make_unique<NullPipeline>();
}
std::unique_ptr<AbstractFramebuffer> NullGfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
std::unique_ptr<AbstractFramebuffer>
NullGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments)
{
return NullFramebuffer::Create(static_cast<NullTexture*>(color_attachment),
static_cast<NullTexture*>(depth_attachment));
static_cast<NullTexture*>(depth_attachment),
std::move(additional_color_attachments));
}
std::unique_ptr<NativeVertexFormat>

View File

@ -22,7 +22,8 @@ public:
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments) override;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
std::string_view name) override;

View File

@ -66,18 +66,21 @@ void NullStagingTexture::Flush()
NullFramebuffer::NullFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format,
AbstractTextureFormat depth_format, u32 width, u32 height,
u32 layers, u32 samples)
: AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
height, layers, samples)
: AbstractFramebuffer(color_attachment, depth_attachment,
std::move(additional_color_attachments), color_format, depth_format,
width, height, layers, samples)
{
}
std::unique_ptr<NullFramebuffer> NullFramebuffer::Create(NullTexture* color_attachment,
NullTexture* depth_attachment)
std::unique_ptr<NullFramebuffer>
NullFramebuffer::Create(NullTexture* color_attachment, NullTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments)
{
if (!ValidateConfig(color_attachment, depth_attachment))
if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments))
return nullptr;
const AbstractTextureFormat color_format =
@ -90,7 +93,8 @@ std::unique_ptr<NullFramebuffer> NullFramebuffer::Create(NullTexture* color_atta
const u32 layers = either_attachment->GetLayers();
const u32 samples = either_attachment->GetSamples();
return std::make_unique<NullFramebuffer>(color_attachment, depth_attachment, color_format,
return std::make_unique<NullFramebuffer>(color_attachment, depth_attachment,
std::move(additional_color_attachments), color_format,
depth_format, width, height, layers, samples);
}

View File

@ -54,11 +54,13 @@ class NullFramebuffer final : public AbstractFramebuffer
{
public:
explicit NullFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
u32 width, u32 height, u32 layers, u32 samples);
static std::unique_ptr<NullFramebuffer> Create(NullTexture* color_attachment,
NullTexture* depth_attachment);
static std::unique_ptr<NullFramebuffer>
Create(NullTexture* color_attachment, NullTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments);
};
} // namespace Null

View File

@ -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;

View File

@ -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;

View File

@ -128,8 +128,8 @@ OGLGfx::OGLGfx(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scal
if (!m_main_gl_context->IsHeadless())
{
m_system_framebuffer = std::make_unique<OGLFramebuffer>(
nullptr, nullptr, AbstractTextureFormat::RGBA8, AbstractTextureFormat::Undefined,
std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
nullptr, nullptr, std::vector<AbstractTexture*>{}, AbstractTextureFormat::RGBA8,
AbstractTextureFormat::Undefined, std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
std::max(m_main_gl_context->GetBackBufferHeight(), 1u), 1, 1, 0);
m_current_framebuffer = m_system_framebuffer.get();
}
@ -226,11 +226,13 @@ std::unique_ptr<AbstractStagingTexture> OGLGfx::CreateStagingTexture(StagingText
return OGLStagingTexture::Create(type, config);
}
std::unique_ptr<AbstractFramebuffer> OGLGfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
std::unique_ptr<AbstractFramebuffer>
OGLGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments)
{
return OGLFramebuffer::Create(static_cast<OGLTexture*>(color_attachment),
static_cast<OGLTexture*>(depth_attachment));
static_cast<OGLTexture*>(depth_attachment),
std::move(additional_color_attachments));
}
std::unique_ptr<AbstractShader>

View File

@ -36,7 +36,8 @@ public:
const void* cache_data = nullptr,
size_t cache_data_length = 0) override;
std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments) override;
void SetPipeline(const AbstractPipeline* pipeline) override;
void SetFramebuffer(AbstractFramebuffer* framebuffer) override;

View File

@ -543,11 +543,13 @@ void OGLStagingTexture::Unmap()
}
OGLFramebuffer::OGLFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format,
AbstractTextureFormat depth_format, u32 width, u32 height,
u32 layers, u32 samples, GLuint fbo)
: AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
height, layers, samples),
: AbstractFramebuffer(color_attachment, depth_attachment,
std::move(additional_color_attachments), color_format, depth_format,
width, height, layers, samples),
m_fbo(fbo)
{
}
@ -557,10 +559,11 @@ OGLFramebuffer::~OGLFramebuffer()
glDeleteFramebuffers(1, &m_fbo);
}
std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachment,
OGLTexture* depth_attachment)
std::unique_ptr<OGLFramebuffer>
OGLFramebuffer::Create(OGLTexture* color_attachment, OGLTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments)
{
if (!ValidateConfig(color_attachment, depth_attachment))
if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments))
return nullptr;
const AbstractTextureFormat color_format =
@ -577,6 +580,7 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachm
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
std::vector<GLenum> buffers;
if (color_attachment)
{
if (color_attachment->GetConfig().layers > 1)
@ -589,6 +593,7 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachm
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
color_attachment->GetGLTextureId(), 0, 0);
}
buffers.push_back(GL_COLOR_ATTACHMENT0);
}
if (depth_attachment)
@ -607,10 +612,29 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachm
}
}
for (std::size_t i = 0; i < additional_color_attachments.size(); i++)
{
const auto attachment_enum = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i + 1);
OGLTexture* attachment = static_cast<OGLTexture*>(additional_color_attachments[i]);
if (attachment->GetConfig().layers > 1)
{
glFramebufferTexture(GL_FRAMEBUFFER, attachment_enum, attachment->GetGLTextureId(), 0);
}
else
{
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment_enum, attachment->GetGLTextureId(), 0,
0);
}
buffers.push_back(attachment_enum);
}
glDrawBuffers(static_cast<GLsizei>(buffers.size()), buffers.data());
DEBUG_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
GetOGLGfx()->RestoreFramebufferBinding();
return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment, color_format,
return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment,
std::move(additional_color_attachments), color_format,
depth_format, width, height, layers, samples, fbo);
}

View File

@ -82,12 +82,14 @@ class OGLFramebuffer final : public AbstractFramebuffer
{
public:
OGLFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
u32 height, u32 layers, u32 samples, GLuint fbo);
~OGLFramebuffer() override;
static std::unique_ptr<OGLFramebuffer> Create(OGLTexture* color_attachment,
OGLTexture* depth_attachment);
static std::unique_ptr<OGLFramebuffer>
Create(OGLTexture* color_attachment, OGLTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments);
GLuint GetFBO() const { return m_fbo; }

View File

@ -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" :
"",

View File

@ -44,11 +44,13 @@ std::unique_ptr<AbstractStagingTexture> SWGfx::CreateStagingTexture(StagingTextu
return std::make_unique<SWStagingTexture>(type, config);
}
std::unique_ptr<AbstractFramebuffer> SWGfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
std::unique_ptr<AbstractFramebuffer>
SWGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments)
{
return SWFramebuffer::Create(static_cast<SWTexture*>(color_attachment),
static_cast<SWTexture*>(depth_attachment));
static_cast<SWTexture*>(depth_attachment),
std::move(additional_color_attachments));
}
void SWGfx::BindBackbuffer(const ClearColor& clear_color)

View File

@ -22,7 +22,8 @@ public:
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments) override;
void BindBackbuffer(const ClearColor& clear_color = {}) override;

View File

@ -159,17 +159,20 @@ void SWStagingTexture::Flush()
}
SWFramebuffer::SWFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
u32 width, u32 height, u32 layers, u32 samples)
: AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
height, layers, samples)
: AbstractFramebuffer(color_attachment, depth_attachment,
std::move(additional_color_attachments), color_format, depth_format,
width, height, layers, samples)
{
}
std::unique_ptr<SWFramebuffer> SWFramebuffer::Create(SWTexture* color_attachment,
SWTexture* depth_attachment)
std::unique_ptr<SWFramebuffer>
SWFramebuffer::Create(SWTexture* color_attachment, SWTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments)
{
if (!ValidateConfig(color_attachment, depth_attachment))
if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments))
return nullptr;
const AbstractTextureFormat color_format =
@ -182,7 +185,8 @@ std::unique_ptr<SWFramebuffer> SWFramebuffer::Create(SWTexture* color_attachment
const u32 layers = either_attachment->GetLayers();
const u32 samples = either_attachment->GetSamples();
return std::make_unique<SWFramebuffer>(color_attachment, depth_attachment, color_format,
return std::make_unique<SWFramebuffer>(color_attachment, depth_attachment,
std::move(additional_color_attachments), color_format,
depth_format, width, height, layers, samples);
}

View File

@ -63,12 +63,14 @@ class SWFramebuffer final : public AbstractFramebuffer
{
public:
explicit SWFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
u32 width, u32 height, u32 layers, u32 samples);
~SWFramebuffer() override = default;
static std::unique_ptr<SWFramebuffer> Create(SWTexture* color_attachment,
SWTexture* depth_attachment);
static std::unique_ptr<SWFramebuffer>
Create(SWTexture* color_attachment, SWTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments);
};
} // namespace SW

View File

@ -388,66 +388,71 @@ VkSampler ObjectCache::GetSampler(const SamplerState& info)
}
VkRenderPass ObjectCache::GetRenderPass(VkFormat color_format, VkFormat depth_format,
u32 multisamples, VkAttachmentLoadOp load_op)
u32 multisamples, VkAttachmentLoadOp load_op,
u8 additional_attachment_count)
{
auto key = std::tie(color_format, depth_format, multisamples, load_op);
auto key =
std::tie(color_format, depth_format, multisamples, load_op, additional_attachment_count);
auto it = m_render_pass_cache.find(key);
if (it != m_render_pass_cache.end())
return it->second;
VkAttachmentReference color_reference;
VkAttachmentReference* color_reference_ptr = nullptr;
VkAttachmentReference depth_reference;
VkAttachmentReference* depth_reference_ptr = nullptr;
std::array<VkAttachmentDescription, 2> attachments;
u32 num_attachments = 0;
std::vector<VkAttachmentDescription> attachments;
std::vector<VkAttachmentReference> color_attachment_references;
if (color_format != VK_FORMAT_UNDEFINED)
{
attachments[num_attachments] = {0,
color_format,
static_cast<VkSampleCountFlagBits>(multisamples),
load_op,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
color_reference.attachment = num_attachments;
VkAttachmentReference color_reference;
color_reference.attachment = static_cast<uint32_t>(attachments.size());
color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_reference_ptr = &color_reference;
num_attachments++;
color_attachment_references.push_back(std::move(color_reference));
attachments.push_back({0, color_format, static_cast<VkSampleCountFlagBits>(multisamples),
load_op, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
}
if (depth_format != VK_FORMAT_UNDEFINED)
{
attachments[num_attachments] = {0,
depth_format,
static_cast<VkSampleCountFlagBits>(multisamples),
load_op,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
depth_reference.attachment = num_attachments;
depth_reference.attachment = static_cast<uint32_t>(attachments.size());
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depth_reference_ptr = &depth_reference;
num_attachments++;
attachments.push_back({0, depth_format, static_cast<VkSampleCountFlagBits>(multisamples),
load_op, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL});
}
VkSubpassDescription subpass = {0,
VK_PIPELINE_BIND_POINT_GRAPHICS,
0,
nullptr,
color_reference_ptr ? 1u : 0u,
color_reference_ptr ? color_reference_ptr : nullptr,
nullptr,
depth_reference_ptr,
0,
nullptr};
for (u8 i = 0; i < additional_attachment_count; i++)
{
VkAttachmentReference color_reference;
color_reference.attachment = static_cast<uint32_t>(attachments.size());
color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachment_references.push_back(std::move(color_reference));
attachments.push_back({0, color_format, static_cast<VkSampleCountFlagBits>(multisamples),
load_op, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
}
VkSubpassDescription subpass = {
0,
VK_PIPELINE_BIND_POINT_GRAPHICS,
0,
nullptr,
static_cast<uint32_t>(color_attachment_references.size()),
color_attachment_references.empty() ? nullptr : color_attachment_references.data(),
nullptr,
depth_reference_ptr,
0,
nullptr};
VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr,
0,
num_attachments,
static_cast<uint32_t>(attachments.size()),
attachments.data(),
1,
&subpass,

View File

@ -60,7 +60,7 @@ public:
// Render pass cache.
VkRenderPass GetRenderPass(VkFormat color_format, VkFormat depth_format, u32 multisamples,
VkAttachmentLoadOp load_op);
VkAttachmentLoadOp load_op, u8 additional_attachment_count = 0);
// Pipeline cache. Used when creating pipelines for drivers to store compiled programs.
VkPipelineCache GetPipelineCache() const { return m_pipeline_cache; }
@ -102,7 +102,7 @@ private:
std::unique_ptr<VKTexture> m_dummy_texture;
// Render pass cache
using RenderPassCacheKey = std::tuple<VkFormat, VkFormat, u32, VkAttachmentLoadOp>;
using RenderPassCacheKey = std::tuple<VkFormat, VkFormat, u32, VkAttachmentLoadOp, std::size_t>;
std::map<RenderPassCacheKey, VkRenderPass> m_render_pass_cache;
// pipeline cache

View File

@ -88,11 +88,13 @@ std::unique_ptr<AbstractPipeline> VKGfx::CreatePipeline(const AbstractPipelineCo
return VKPipeline::Create(config);
}
std::unique_ptr<AbstractFramebuffer> VKGfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
std::unique_ptr<AbstractFramebuffer>
VKGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments)
{
return VKFramebuffer::Create(static_cast<VKTexture*>(color_attachment),
static_cast<VKTexture*>(depth_attachment));
static_cast<VKTexture*>(depth_attachment),
std::move(additional_color_attachments));
}
void VKGfx::SetPipeline(const AbstractPipeline* pipeline)
@ -138,12 +140,12 @@ void VKGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_en
if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_CLEAR_LOADOP_RENDERPASS))
use_clear_render_pass = false;
auto* vk_frame_buffer = static_cast<VKFramebuffer*>(m_current_framebuffer);
// Fastest path: Use a render pass to clear the buffers.
if (use_clear_render_pass)
{
const std::array<VkClearValue, 2> clear_values = {{clear_color_value, clear_depth_value}};
StateTracker::GetInstance()->BeginClearRenderPass(target_vk_rc, clear_values.data(),
static_cast<u32>(clear_values.size()));
vk_frame_buffer->SetAndClear(target_vk_rc, clear_color_value, clear_depth_value);
return;
}
@ -151,26 +153,40 @@ void VKGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_en
// We can't use this when preserving alpha but clearing color.
if (use_clear_attachments)
{
VkClearAttachment clear_attachments[2];
uint32_t num_clear_attachments = 0;
std::vector<VkClearAttachment> clear_attachments;
bool has_color = false;
if (color_enable && alpha_enable)
{
clear_attachments[num_clear_attachments].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clear_attachments[num_clear_attachments].colorAttachment = 0;
clear_attachments[num_clear_attachments].clearValue = clear_color_value;
num_clear_attachments++;
VkClearAttachment clear_attachment;
clear_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clear_attachment.colorAttachment = 0;
clear_attachment.clearValue = clear_color_value;
clear_attachments.push_back(std::move(clear_attachment));
color_enable = false;
alpha_enable = false;
has_color = true;
}
if (z_enable)
{
clear_attachments[num_clear_attachments].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
clear_attachments[num_clear_attachments].colorAttachment = 0;
clear_attachments[num_clear_attachments].clearValue = clear_depth_value;
num_clear_attachments++;
VkClearAttachment clear_attachment;
clear_attachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
clear_attachment.colorAttachment = 0;
clear_attachment.clearValue = clear_depth_value;
clear_attachments.push_back(std::move(clear_attachment));
z_enable = false;
}
if (num_clear_attachments > 0)
if (has_color)
{
for (std::size_t i = 0; i < vk_frame_buffer->GetNumberOfAdditonalAttachments(); i++)
{
VkClearAttachment clear_attachment;
clear_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clear_attachment.colorAttachment = 0;
clear_attachment.clearValue = clear_color_value;
clear_attachments.push_back(std::move(clear_attachment));
}
}
if (!clear_attachments.empty())
{
VkClearRect vk_rect = {target_vk_rc, 0, g_framebuffer_manager->GetEFBLayers()};
if (!StateTracker::GetInstance()->IsWithinRenderArea(
@ -181,8 +197,9 @@ void VKGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_en
}
StateTracker::GetInstance()->BeginRenderPass();
vkCmdClearAttachments(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_clear_attachments,
clear_attachments, 1, &vk_rect);
vkCmdClearAttachments(g_command_buffer_mgr->GetCurrentCommandBuffer(),
static_cast<uint32_t>(clear_attachments.size()),
clear_attachments.data(), 1, &vk_rect);
}
}
@ -405,16 +422,7 @@ void VKGfx::BindFramebuffer(VKFramebuffer* fb)
StateTracker::GetInstance()->EndRenderPass();
// Shouldn't be bound as a texture.
if (fb->GetColorAttachment())
{
StateTracker::GetInstance()->UnbindTexture(
static_cast<VKTexture*>(fb->GetColorAttachment())->GetView());
}
if (fb->GetDepthAttachment())
{
StateTracker::GetInstance()->UnbindTexture(
static_cast<VKTexture*>(fb->GetDepthAttachment())->GetView());
}
fb->Unbind();
fb->TransitionForRender();
StateTracker::GetInstance()->SetFramebuffer(fb);
@ -449,22 +457,13 @@ void VKGfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const Clear
VKFramebuffer* vkfb = static_cast<VKFramebuffer*>(framebuffer);
BindFramebuffer(vkfb);
std::array<VkClearValue, 2> clear_values;
u32 num_clear_values = 0;
if (vkfb->GetColorFormat() != AbstractTextureFormat::Undefined)
{
std::memcpy(clear_values[num_clear_values].color.float32, color_value.data(),
sizeof(clear_values[num_clear_values].color.float32));
num_clear_values++;
}
if (vkfb->GetDepthFormat() != AbstractTextureFormat::Undefined)
{
clear_values[num_clear_values].depthStencil.depth = depth_value;
clear_values[num_clear_values].depthStencil.stencil = 0;
num_clear_values++;
}
StateTracker::GetInstance()->BeginClearRenderPass(vkfb->GetRect(), clear_values.data(),
num_clear_values);
VkClearValue clear_color_value;
std::memcpy(clear_color_value.color.float32, color_value.data(),
sizeof(clear_color_value.color.float32));
VkClearValue clear_depth_value;
clear_depth_value.depthStencil.depth = depth_value;
clear_depth_value.depthStencil.stencil = 0;
vkfb->SetAndClear(vkfb->GetRect(), clear_color_value, clear_depth_value);
}
void VKGfx::SetTexture(u32 index, const AbstractTexture* texture)

View File

@ -35,7 +35,8 @@ public:
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments) override;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
std::string_view name) override;

View File

@ -72,11 +72,11 @@ static VkPipelineMultisampleStateCreateInfo GetVulkanMultisampleState(const Fram
0, // VkPipelineMultisampleStateCreateFlags flags
static_cast<VkSampleCountFlagBits>(
state.samples.Value()), // VkSampleCountFlagBits rasterizationSamples
state.per_sample_shading, // VkBool32 sampleShadingEnable
1.0f, // float minSampleShading
nullptr, // const VkSampleMask* pSampleMask;
VK_FALSE, // VkBool32 alphaToCoverageEnable
VK_FALSE // VkBool32 alphaToOneEnable
static_cast<bool>(state.per_sample_shading), // VkBool32 sampleShadingEnable
1.0f, // float minSampleShading
nullptr, // const VkSampleMask* pSampleMask;
VK_FALSE, // VkBool32 alphaToCoverageEnable
VK_FALSE // VkBool32 alphaToOneEnable
};
}
@ -243,7 +243,14 @@ std::unique_ptr<VKPipeline> VKPipeline::Create(const AbstractPipelineConfig& con
VkRenderPass render_pass = g_object_cache->GetRenderPass(
VKTexture::GetVkFormatForHostTextureFormat(config.framebuffer_state.color_texture_format),
VKTexture::GetVkFormatForHostTextureFormat(config.framebuffer_state.depth_texture_format),
config.framebuffer_state.samples, VK_ATTACHMENT_LOAD_OP_LOAD);
config.framebuffer_state.samples, VK_ATTACHMENT_LOAD_OP_LOAD,
config.framebuffer_state.additional_color_attachment_count);
if (render_pass == VK_NULL_HANDLE)
{
PanicAlertFmt("Failed to get render pass");
return nullptr;
}
// Get pipeline layout.
VkPipelineLayout pipeline_layout;
@ -343,8 +350,18 @@ std::unique_ptr<VKPipeline> VKPipeline::Create(const AbstractPipelineConfig& con
GetVulkanDepthStencilState(config.depth_state);
VkPipelineColorBlendAttachmentState blend_attachment_state =
GetVulkanAttachmentBlendState(config.blending_state, config.usage);
std::vector<VkPipelineColorBlendAttachmentState> blend_attachment_states;
blend_attachment_states.push_back(blend_attachment_state);
// Right now all our attachments have the same state
for (u8 i = 0; i < static_cast<u8>(config.framebuffer_state.additional_color_attachment_count);
i++)
{
blend_attachment_states.push_back(blend_attachment_state);
}
VkPipelineColorBlendStateCreateInfo blend_state =
GetVulkanColorBlendState(config.blending_state, &blend_attachment_state, 1);
GetVulkanColorBlendState(config.blending_state, blend_attachment_states.data(),
static_cast<uint32_t>(blend_attachment_states.size()));
// This viewport isn't used, but needs to be specified anyway.
static const VkViewport viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};

View File

@ -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();

View File

@ -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<AbstractTexture*> additional_color_attachments, u32 width,
u32 height, u32 layers, u32 samples, VkFramebuffer fb,
VkRenderPass load_render_pass, VkRenderPass discard_render_pass,
VkRenderPass clear_render_pass)
: AbstractFramebuffer(
color_attachment, depth_attachment,
color_attachment, depth_attachment, std::move(additional_color_attachments),
color_attachment ? color_attachment->GetFormat() : AbstractTextureFormat::Undefined,
depth_attachment ? depth_attachment->GetFormat() : AbstractTextureFormat::Undefined,
width, height, layers, samples),
@ -1001,10 +1002,11 @@ VKFramebuffer::~VKFramebuffer()
g_command_buffer_mgr->DeferFramebufferDestruction(m_fb);
}
std::unique_ptr<VKFramebuffer> VKFramebuffer::Create(VKTexture* color_attachment,
VKTexture* depth_attachment)
std::unique_ptr<VKFramebuffer>
VKFramebuffer::Create(VKTexture* color_attachment, VKTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments)
{
if (!ValidateConfig(color_attachment, depth_attachment))
if (!ValidateConfig(color_attachment, depth_attachment, additional_color_attachments))
return nullptr;
const VkFormat vk_color_format =
@ -1017,21 +1019,27 @@ std::unique_ptr<VKFramebuffer> VKFramebuffer::Create(VKTexture* color_attachment
const u32 layers = either_attachment->GetLayers();
const u32 samples = either_attachment->GetSamples();
std::array<VkImageView, 2> attachment_views{};
u32 num_attachments = 0;
std::vector<VkImageView> attachment_views;
if (color_attachment)
attachment_views[num_attachments++] = color_attachment->GetView();
attachment_views.push_back(color_attachment->GetView());
if (depth_attachment)
attachment_views[num_attachments++] = depth_attachment->GetView();
attachment_views.push_back(depth_attachment->GetView());
for (auto* attachment : additional_color_attachments)
{
attachment_views.push_back(static_cast<VKTexture*>(attachment)->GetView());
}
VkRenderPass load_render_pass = g_object_cache->GetRenderPass(
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_LOAD);
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_LOAD,
static_cast<u8>(additional_color_attachments.size()));
VkRenderPass discard_render_pass = g_object_cache->GetRenderPass(
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
static_cast<u8>(additional_color_attachments.size()));
VkRenderPass clear_render_pass = g_object_cache->GetRenderPass(
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_CLEAR);
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_CLEAR,
static_cast<u8>(additional_color_attachments.size()));
if (load_render_pass == VK_NULL_HANDLE || discard_render_pass == VK_NULL_HANDLE ||
clear_render_pass == VK_NULL_HANDLE)
{
@ -1042,7 +1050,7 @@ std::unique_ptr<VKFramebuffer> VKFramebuffer::Create(VKTexture* color_attachment
nullptr,
0,
load_render_pass,
num_attachments,
static_cast<uint32_t>(attachment_views.size()),
attachment_views.data(),
width,
height,
@ -1057,9 +1065,27 @@ std::unique_ptr<VKFramebuffer> VKFramebuffer::Create(VKTexture* color_attachment
return nullptr;
}
return std::make_unique<VKFramebuffer>(color_attachment, depth_attachment, width, height, layers,
samples, fb, load_render_pass, discard_render_pass,
clear_render_pass);
return std::make_unique<VKFramebuffer>(
color_attachment, depth_attachment, std::move(additional_color_attachments), width, height,
layers, samples, fb, load_render_pass, discard_render_pass, clear_render_pass);
}
void VKFramebuffer::Unbind()
{
if (m_color_attachment)
{
StateTracker::GetInstance()->UnbindTexture(
static_cast<VKTexture*>(m_color_attachment)->GetView());
}
for (auto* attachment : m_additional_color_attachments)
{
StateTracker::GetInstance()->UnbindTexture(static_cast<VKTexture*>(attachment)->GetView());
}
if (m_depth_attachment)
{
StateTracker::GetInstance()->UnbindTexture(
static_cast<VKTexture*>(m_depth_attachment)->GetView());
}
}
void VKFramebuffer::TransitionForRender()
@ -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<VKTexture*>(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<VkClearValue> clear_values;
if (GetColorFormat() != AbstractTextureFormat::Undefined)
{
clear_values.push_back(color_value);
}
if (GetDepthFormat() != AbstractTextureFormat::Undefined)
{
clear_values.push_back(depth_value);
}
for (std::size_t i = 0; i < m_additional_color_attachments.size(); i++)
{
clear_values.push_back(color_value);
}
StateTracker::GetInstance()->BeginClearRenderPass(rect, clear_values.data(),
static_cast<u32>(clear_values.size()));
}
} // namespace Vulkan

View File

@ -126,7 +126,8 @@ private:
class VKFramebuffer final : public AbstractFramebuffer
{
public:
VKFramebuffer(VKTexture* color_attachment, VKTexture* depth_attachment, u32 width, u32 height,
VKFramebuffer(VKTexture* color_attachment, VKTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments, u32 width, u32 height,
u32 layers, u32 samples, VkFramebuffer fb, VkRenderPass load_render_pass,
VkRenderPass discard_render_pass, VkRenderPass clear_render_pass);
~VKFramebuffer() override;
@ -137,10 +138,20 @@ public:
VkRenderPass GetLoadRenderPass() const { return m_load_render_pass; }
VkRenderPass GetDiscardRenderPass() const { return m_discard_render_pass; }
VkRenderPass GetClearRenderPass() const { return m_clear_render_pass; }
void Unbind();
void TransitionForRender();
static std::unique_ptr<VKFramebuffer> Create(VKTexture* color_attachments,
VKTexture* depth_attachment);
void SetAndClear(const VkRect2D& rect, const VkClearValue& color_value,
const VkClearValue& depth_value);
std::size_t GetNumberOfAdditonalAttachments() const
{
return m_additional_color_attachments.size();
}
static std::unique_ptr<VKFramebuffer>
Create(VKTexture* color_attachments, VKTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments);
protected:
VkFramebuffer m_fb;

View File

@ -6,10 +6,12 @@
AbstractFramebuffer::AbstractFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format,
AbstractTextureFormat depth_format, u32 width, u32 height,
u32 layers, u32 samples)
: m_color_attachment(color_attachment), m_depth_attachment(depth_attachment),
m_additional_color_attachments(std::move(additional_color_attachments)),
m_color_format(color_format), m_depth_format(depth_format), m_width(width), m_height(height),
m_layers(layers), m_samples(samples)
{
@ -17,13 +19,18 @@ AbstractFramebuffer::AbstractFramebuffer(AbstractTexture* color_attachment,
AbstractFramebuffer::~AbstractFramebuffer() = default;
bool AbstractFramebuffer::ValidateConfig(const AbstractTexture* color_attachment,
const AbstractTexture* depth_attachment)
bool AbstractFramebuffer::ValidateConfig(
const AbstractTexture* color_attachment, const AbstractTexture* depth_attachment,
const std::vector<AbstractTexture*>& additional_color_attachments)
{
// Must have at least a color or depth attachment.
if (!color_attachment && !depth_attachment)
return false;
// Must have a color attachment if additional color attachments are defined
if (!color_attachment && !additional_color_attachments.empty())
return false;
// Currently we only expose a single mip level for render target textures.
// MSAA textures are not supported with mip levels on most backends, and it simplifies our
// handling of framebuffers.
@ -36,6 +43,14 @@ bool AbstractFramebuffer::ValidateConfig(const AbstractTexture* color_attachment
return false;
}
for (auto* attachment : additional_color_attachments)
{
if (!CheckAttachment(attachment))
{
return false;
}
}
// If both color and depth are present, their attributes must match.
if (color_attachment && depth_attachment)
{
@ -48,6 +63,16 @@ bool AbstractFramebuffer::ValidateConfig(const AbstractTexture* color_attachment
}
}
for (auto* attachment : additional_color_attachments)
{
if (color_attachment->GetConfig().width != attachment->GetConfig().width ||
color_attachment->GetConfig().height != attachment->GetConfig().height ||
color_attachment->GetConfig().samples != attachment->GetConfig().samples)
{
return false;
}
}
return true;
}

View File

@ -3,6 +3,8 @@
#pragma once
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/MathUtil.h"
#include "VideoCommon/TextureConfig.h"
@ -18,12 +20,14 @@ class AbstractFramebuffer
{
public:
AbstractFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments,
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
u32 width, u32 height, u32 layers, u32 samples);
virtual ~AbstractFramebuffer();
static bool ValidateConfig(const AbstractTexture* color_attachment,
const AbstractTexture* depth_attachment);
const AbstractTexture* depth_attachment,
const std::vector<AbstractTexture*>& additional_color_attachments);
AbstractTexture* GetColorAttachment() const { return m_color_attachment; }
AbstractTexture* GetDepthAttachment() const { return m_depth_attachment; }
@ -42,6 +46,7 @@ protected:
AbstractTexture* m_depth_attachment;
AbstractTextureFormat m_color_format;
AbstractTextureFormat m_depth_format;
std::vector<AbstractTexture*> m_additional_color_attachments;
u32 m_width;
u32 m_height;
u32 m_layers;

View File

@ -10,6 +10,7 @@
#include <array>
#include <memory>
#include <vector>
class AbstractFramebuffer;
class AbstractPipeline;
@ -75,7 +76,8 @@ public:
virtual std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) = 0;
virtual std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) = 0;
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
std::vector<AbstractTexture*> additional_color_attachments = {}) = 0;
// Framebuffer operations.
virtual void SetFramebuffer(AbstractFramebuffer* framebuffer);

View File

@ -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;
}

View File

@ -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;
};