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

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