GPUDevice: Add support for feedback loops

This commit is contained in:
Stenzek
2024-03-08 17:55:02 +10:00
parent cc5f9a12b1
commit 72ab669e70
23 changed files with 426 additions and 191 deletions

View File

@ -44,7 +44,6 @@ public:
{
bool vk_ext_memory_budget : 1;
bool vk_ext_rasterization_order_attachment_access : 1;
bool vk_ext_attachment_feedback_loop_layout : 1;
bool vk_ext_full_screen_exclusive : 1;
bool vk_khr_get_memory_requirements2 : 1;
bool vk_khr_bind_memory2 : 1;
@ -52,6 +51,7 @@ public:
bool vk_khr_dedicated_allocation : 1;
bool vk_khr_driver_properties : 1;
bool vk_khr_dynamic_rendering : 1;
bool vk_khr_dynamic_rendering_local_read : 1;
bool vk_khr_push_descriptor : 1;
bool vk_ext_external_memory_host : 1;
};
@ -114,7 +114,8 @@ public:
void PushUniformBuffer(const void* data, u32 data_size) override;
void* MapUniformBuffer(u32 size) override;
void UnmapUniformBuffer(u32 size) override;
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds) override;
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
GPUPipeline::RenderPassFlag feedback_loop = GPUPipeline::NoRenderPassFlags) override;
void SetPipeline(GPUPipeline* pipeline) override;
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
@ -122,6 +123,7 @@ public:
void SetScissor(s32 x, s32 y, s32 width, s32 height) override;
void Draw(u32 vertex_count, u32 base_vertex) override;
void DrawIndexed(u32 index_count, u32 base_index, u32 base_vertex) override;
void DrawIndexedWithBarrier(u32 index_count, u32 base_index, u32 base_vertex, DrawBarrier type) override;
bool SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override;
@ -144,13 +146,6 @@ public:
/// Returns true if Vulkan is suitable as a default for the devices in the system.
static bool IsSuitableDefaultRenderer();
// The interaction between raster order attachment access and fbfetch is unclear.
ALWAYS_INLINE bool UseFeedbackLoopLayout() const
{
return (m_optional_extensions.vk_ext_attachment_feedback_loop_layout &&
!m_optional_extensions.vk_ext_rasterization_order_attachment_access);
}
// Helpers for getting constants
ALWAYS_INLINE u32 GetBufferCopyOffsetAlignment() const
{
@ -165,8 +160,8 @@ public:
// Creates a simple render pass.
VkRenderPass GetRenderPass(const GPUPipeline::GraphicsConfig& config);
VkRenderPass GetRenderPass(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, bool color_feedback_loop = false,
bool depth_sampling = false);
VkRenderPass GetRenderPass(VulkanTexture* const* rts, u32 num_rts, VulkanTexture* ds,
GPUPipeline::RenderPassFlag render_pass_flags);
VkRenderPass GetSwapChainRenderPass(GPUTexture::Format format, VkAttachmentLoadOp load_op);
// Gets a non-clearing version of the specified render pass. Slow, don't call in hot path.
@ -239,9 +234,10 @@ private:
DIRTY_FLAG_PIPELINE_LAYOUT = (1 << 1),
DIRTY_FLAG_DYNAMIC_OFFSETS = (1 << 2),
DIRTY_FLAG_TEXTURES_OR_SAMPLERS = (1 << 3),
DIRTY_FLAG_INPUT_ATTACHMENT = (1 << 4),
ALL_DIRTY_STATE =
DIRTY_FLAG_INITIAL | DIRTY_FLAG_PIPELINE_LAYOUT | DIRTY_FLAG_DYNAMIC_OFFSETS | DIRTY_FLAG_TEXTURES_OR_SAMPLERS,
ALL_DIRTY_STATE = DIRTY_FLAG_INITIAL | DIRTY_FLAG_PIPELINE_LAYOUT | DIRTY_FLAG_DYNAMIC_OFFSETS |
DIRTY_FLAG_TEXTURES_OR_SAMPLERS | DIRTY_FLAG_INPUT_ATTACHMENT,
};
struct RenderPassCacheKey
@ -259,8 +255,7 @@ private:
u8 depth_store_op : 1;
u8 stencil_load_op : 2;
u8 stencil_store_op : 1;
u8 depth_sampling : 1;
u8 color_feedback_loop : 1;
u8 feedback_loop : 2;
u8 samples;
bool operator==(const RenderPassCacheKey& rhs) const;
@ -361,7 +356,7 @@ private:
void PreDrawCheck();
template<GPUPipeline::Layout layout>
bool UpdateDescriptorSetsForLayout(bool new_layout, bool new_dynamic_offsets);
bool UpdateDescriptorSetsForLayout(u32 dirty);
bool UpdateDescriptorSets(u32 dirty);
// Ends a render pass if we're currently in one.
@ -375,6 +370,8 @@ private:
static VkFramebuffer CreateFramebuffer(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags);
static void DestroyFramebuffer(VkFramebuffer fbo);
VkImageMemoryBarrier GetColorBufferBarrier(const VulkanTexture* rt) const;
void BeginCommandBuffer(u32 index);
void WaitForCommandBufferCompletion(u32 index);
@ -445,6 +442,7 @@ private:
VkDescriptorSetLayout m_single_texture_ds_layout = VK_NULL_HANDLE;
VkDescriptorSetLayout m_single_texture_buffer_ds_layout = VK_NULL_HANDLE;
VkDescriptorSetLayout m_multi_texture_ds_layout = VK_NULL_HANDLE;
VkDescriptorSetLayout m_feedback_loop_ds_layout = VK_NULL_HANDLE;
std::array<VkPipelineLayout, static_cast<u8>(GPUPipeline::Layout::MaxCount)> m_pipeline_layouts = {};
VulkanStreamBuffer m_vertex_buffer;
@ -460,9 +458,10 @@ private:
// Which bindings/state has to be updated before the next draw.
u32 m_dirty_flags = ALL_DIRTY_STATE;
u32 m_num_current_render_targets = 0;
std::array<GPUTexture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
GPUTexture* m_current_depth_target = nullptr;
u8 m_num_current_render_targets = 0;
GPUPipeline::RenderPassFlag m_current_feedback_loop = GPUPipeline::NoRenderPassFlags;
std::array<VulkanTexture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
VulkanTexture* m_current_depth_target = nullptr;
VkFramebuffer m_current_framebuffer = VK_NULL_HANDLE;
VkRenderPass m_current_render_pass = VK_NULL_HANDLE;