VideoCommon: Add support for Abstract Framebuffers

This commit is contained in:
Stenzek
2018-01-21 20:22:45 +10:00
parent 2a6d9e4713
commit 4c24a69710
31 changed files with 792 additions and 9 deletions

View File

@ -192,6 +192,14 @@ std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelin
return VKPipeline::Create(config);
}
std::unique_ptr<AbstractFramebuffer>
Renderer::CreateFramebuffer(const AbstractTexture* color_attachment,
const AbstractTexture* depth_attachment)
{
return VKFramebuffer::Create(static_cast<const VKTexture*>(color_attachment),
static_cast<const VKTexture*>(depth_attachment));
}
std::tuple<VkBuffer, u32> Renderer::UpdateUtilityUniformBuffer(const void* uniforms,
u32 uniforms_size)
{
@ -593,8 +601,9 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha
// Fastest path: Use a render pass to clear the buffers.
if (use_clear_render_pass)
{
VkClearValue clear_values[2] = {clear_color_value, clear_depth_value};
StateTracker::GetInstance()->BeginClearRenderPass(target_vk_rc, clear_values);
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()));
return;
}
@ -743,6 +752,7 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
// Restore the EFB color texture to color attachment ready for rendering the next frame.
FramebufferManager::GetInstance()->GetEFBColorTexture()->TransitionToLayout(
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
RestoreAPIState();
// Determine what (if anything) has changed in the config.
CheckForConfigChanges();
@ -792,6 +802,9 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region
backbuffer->OverrideImageLayout(VK_IMAGE_LAYOUT_UNDEFINED);
backbuffer->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
m_current_framebuffer = nullptr;
m_current_framebuffer_width = backbuffer->GetWidth();
m_current_framebuffer_height = backbuffer->GetHeight();
// Begin render pass for rendering to the swap chain.
VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
@ -1010,6 +1023,9 @@ void Renderer::BindEFBToStateTracker()
FramebufferManager::GetInstance()->GetEFBFramebuffer(), framebuffer_size);
StateTracker::GetInstance()->SetMultisamplingstate(
FramebufferManager::GetInstance()->GetEFBMultisamplingState());
m_current_framebuffer = nullptr;
m_current_framebuffer_width = FramebufferManager::GetInstance()->GetEFBWidth();
m_current_framebuffer_height = FramebufferManager::GetInstance()->GetEFBHeight();
}
void Renderer::RecreateEFBFramebuffer()
@ -1037,12 +1053,78 @@ void Renderer::ResetAPIState()
void Renderer::RestoreAPIState()
{
StateTracker::GetInstance()->EndRenderPass();
if (m_current_framebuffer)
static_cast<const VKFramebuffer*>(m_current_framebuffer)->TransitionForSample();
BindEFBToStateTracker();
// Instruct the state tracker to re-bind everything before the next draw
StateTracker::GetInstance()->SetPendingRebind();
}
void Renderer::BindFramebuffer(const VKFramebuffer* fb)
{
const VkRect2D render_area = {static_cast<int>(fb->GetWidth()),
static_cast<int>(fb->GetHeight())};
StateTracker::GetInstance()->EndRenderPass();
if (m_current_framebuffer)
static_cast<const VKFramebuffer*>(m_current_framebuffer)->TransitionForSample();
fb->TransitionForRender();
StateTracker::GetInstance()->SetFramebuffer(fb->GetFB(), render_area);
StateTracker::GetInstance()->SetRenderPass(fb->GetLoadRenderPass(), fb->GetClearRenderPass());
m_current_framebuffer = fb;
m_current_framebuffer_width = fb->GetWidth();
m_current_framebuffer_height = fb->GetHeight();
}
void Renderer::SetFramebuffer(const AbstractFramebuffer* framebuffer)
{
const VKFramebuffer* vkfb = static_cast<const VKFramebuffer*>(framebuffer);
BindFramebuffer(vkfb);
StateTracker::GetInstance()->BeginRenderPass();
}
void Renderer::SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer)
{
const VKFramebuffer* vkfb = static_cast<const VKFramebuffer*>(framebuffer);
BindFramebuffer(vkfb);
// If we're discarding, begin the discard pass, then switch to a load pass.
// This way if the command buffer is flushed, we don't start another discard pass.
StateTracker::GetInstance()->SetRenderPass(vkfb->GetDiscardRenderPass(),
vkfb->GetClearRenderPass());
StateTracker::GetInstance()->BeginRenderPass();
StateTracker::GetInstance()->SetRenderPass(vkfb->GetLoadRenderPass(), vkfb->GetClearRenderPass());
}
void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value)
{
const VKFramebuffer* vkfb = static_cast<const VKFramebuffer*>(framebuffer);
BindFramebuffer(vkfb);
const VkRect2D render_area = {static_cast<int>(vkfb->GetWidth()),
static_cast<int>(vkfb->GetHeight())};
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(render_area, clear_values.data(),
num_clear_values);
}
void Renderer::SetRasterizationState(const RasterizationState& state)
{
StateTracker::GetInstance()->SetRasterizationState(state);

View File

@ -23,6 +23,7 @@ class SwapChain;
class StagingTexture2D;
class Texture2D;
class RasterFont;
class VKFramebuffer;
class VKPipeline;
class VKTexture;
@ -37,6 +38,9 @@ public:
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(const AbstractTexture* color_attachment,
const AbstractTexture* depth_attachment) override;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
size_t length) override;
@ -68,6 +72,11 @@ public:
void RestoreAPIState() override;
void SetPipeline(const AbstractPipeline* pipeline) override;
void SetFramebuffer(const AbstractFramebuffer* framebuffer) override;
void SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer) override;
void SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
const ClearColor& color_value = {},
float depth_value = 0.0f) override;
void SetBlendingState(const BlendingState& state) override;
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
void SetRasterizationState(const RasterizationState& state) override;
@ -99,6 +108,7 @@ private:
void OnSwapChainResized();
void BindEFBToStateTracker();
void RecreateEFBFramebuffer();
void BindFramebuffer(const VKFramebuffer* fb);
void RecompileShaders();
bool CompileShaders();

View File

@ -703,7 +703,8 @@ void StateTracker::EndRenderPass()
m_current_render_pass = VK_NULL_HANDLE;
}
void StateTracker::BeginClearRenderPass(const VkRect2D& area, const VkClearValue clear_values[2])
void StateTracker::BeginClearRenderPass(const VkRect2D& area, const VkClearValue* clear_values,
u32 num_clear_values)
{
_assert_(!InRenderPass());
@ -715,7 +716,7 @@ void StateTracker::BeginClearRenderPass(const VkRect2D& area, const VkClearValue
m_current_render_pass,
m_framebuffer,
m_framebuffer_render_area,
2,
num_clear_values,
clear_values};
vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &begin_info,

View File

@ -45,6 +45,7 @@ public:
{
return m_bindings.ps_samplers;
}
VkFramebuffer GetFramebuffer() const { return m_framebuffer; }
void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset);
void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type);
@ -90,7 +91,8 @@ public:
void EndRenderPass();
// Ends the current render pass if it was a clear render pass.
void BeginClearRenderPass(const VkRect2D& area, const VkClearValue clear_values[2]);
void BeginClearRenderPass(const VkRect2D& area, const VkClearValue* clear_values,
u32 num_clear_values);
void EndClearRenderPass();
void SetViewport(const VkViewport& viewport);

View File

@ -566,4 +566,118 @@ void VKStagingTexture::Flush()
m_staging_buffer->InvalidateCPUCache();
}
VKFramebuffer::VKFramebuffer(const VKTexture* color_attachment, const VKTexture* depth_attachment,
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 ? color_attachment->GetFormat() : AbstractTextureFormat::Undefined,
depth_attachment ? depth_attachment->GetFormat() : AbstractTextureFormat::Undefined,
width, height, layers, samples),
m_color_attachment(color_attachment), m_depth_attachment(depth_attachment), m_fb(fb),
m_load_render_pass(load_render_pass), m_discard_render_pass(discard_render_pass),
m_clear_render_pass(clear_render_pass)
{
}
VKFramebuffer::~VKFramebuffer()
{
g_command_buffer_mgr->DeferFramebufferDestruction(m_fb);
}
std::unique_ptr<VKFramebuffer> VKFramebuffer::Create(const VKTexture* color_attachment,
const VKTexture* depth_attachment)
{
if (!ValidateConfig(color_attachment, depth_attachment))
return nullptr;
const VkFormat vk_color_format =
color_attachment ? color_attachment->GetRawTexIdentifier()->GetFormat() : VK_FORMAT_UNDEFINED;
const VkFormat vk_depth_format =
depth_attachment ? depth_attachment->GetRawTexIdentifier()->GetFormat() : VK_FORMAT_UNDEFINED;
const VKTexture* either_attachment = color_attachment ? color_attachment : depth_attachment;
const u32 width = either_attachment->GetWidth();
const u32 height = either_attachment->GetHeight();
const u32 layers = either_attachment->GetLayers();
const u32 samples = either_attachment->GetSamples();
std::array<VkImageView, 2> attachment_views{};
u32 num_attachments = 0;
if (color_attachment)
attachment_views[num_attachments++] = color_attachment->GetRawTexIdentifier()->GetView();
if (depth_attachment)
attachment_views[num_attachments++] = depth_attachment->GetRawTexIdentifier()->GetView();
VkRenderPass load_render_pass = g_object_cache->GetRenderPass(
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_LOAD);
VkRenderPass discard_render_pass = g_object_cache->GetRenderPass(
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
VkRenderPass clear_render_pass = g_object_cache->GetRenderPass(
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_CLEAR);
if (load_render_pass == VK_NULL_HANDLE || discard_render_pass == VK_NULL_HANDLE ||
clear_render_pass == VK_NULL_HANDLE)
{
return nullptr;
}
VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
nullptr,
0,
load_render_pass,
num_attachments,
attachment_views.data(),
width,
height,
layers};
VkFramebuffer fb;
VkResult res =
vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, &fb);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: ");
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);
}
void VKFramebuffer::TransitionForRender() const
{
if (m_color_attachment)
{
m_color_attachment->GetRawTexIdentifier()->TransitionToLayout(
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
if (m_depth_attachment)
{
m_depth_attachment->GetRawTexIdentifier()->TransitionToLayout(
g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
}
void VKFramebuffer::TransitionForSample() const
{
if (StateTracker::GetInstance()->GetFramebuffer() == m_fb)
StateTracker::GetInstance()->EndRenderPass();
if (m_color_attachment)
{
m_color_attachment->GetRawTexIdentifier()->TransitionToLayout(
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
if (m_depth_attachment)
{
m_depth_attachment->GetRawTexIdentifier()->TransitionToLayout(
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
}
} // namespace Vulkan

View File

@ -7,6 +7,7 @@
#include <memory>
#include <vulkan/vulkan.h>
#include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"
@ -80,4 +81,32 @@ private:
VkFence m_flush_fence = VK_NULL_HANDLE;
};
class VKFramebuffer final : public AbstractFramebuffer
{
public:
VKFramebuffer(const VKTexture* color_attachment, const VKTexture* depth_attachment, u32 width,
u32 height, u32 layers, u32 samples, VkFramebuffer fb,
VkRenderPass load_render_pass, VkRenderPass discard_render_pass,
VkRenderPass clear_render_pass);
~VKFramebuffer() override;
VkFramebuffer GetFB() const { return m_fb; }
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 TransitionForRender() const;
void TransitionForSample() const;
static std::unique_ptr<VKFramebuffer> Create(const VKTexture* color_attachments,
const VKTexture* depth_attachment);
protected:
const VKTexture* m_color_attachment;
const VKTexture* m_depth_attachment;
VkFramebuffer m_fb;
VkRenderPass m_load_render_pass;
VkRenderPass m_discard_render_pass;
VkRenderPass m_clear_render_pass;
};
} // namespace Vulkan