VideoBackends: add support to allow rendering to multiple output textures
This commit is contained in:
parent
252d3f353a
commit
834f8f7b5c
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = {};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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" :
|
||||
"",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue