mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-31 01:59:52 -06:00
VideoCommon: Add support for Abstract Framebuffers
This commit is contained in:
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user