From 287db6691491d1960616fe2238c4755b652d33f4 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Sun, 19 Nov 2023 20:39:19 +0200 Subject: [PATCH] temp --- src/video_core/regs_texturing.h | 26 ++- .../renderer_vulkan/renderer_vulkan.cpp | 30 +-- .../renderer_vulkan/renderer_vulkan.h | 7 +- .../renderer_vulkan/vk_blit_helper.cpp | 9 +- .../renderer_vulkan/vk_blit_helper.h | 12 +- .../renderer_vulkan/vk_descriptor_update.cpp | 36 ++++ .../renderer_vulkan/vk_descriptor_update.h | 29 +++ .../renderer_vulkan/vk_graphics_pipeline.cpp | 8 +- .../renderer_vulkan/vk_graphics_pipeline.h | 41 ++-- .../renderer_vulkan/vk_pipeline_cache.cpp | 184 ++++++++---------- .../renderer_vulkan/vk_pipeline_cache.h | 40 ++-- .../renderer_vulkan/vk_present_window.cpp | 12 +- .../renderer_vulkan/vk_present_window.h | 3 +- .../renderer_vulkan/vk_rasterizer.cpp | 101 +++++----- .../renderer_vulkan/vk_rasterizer.h | 9 +- .../renderer_vulkan/vk_texture_runtime.cpp | 19 +- .../renderer_vulkan/vk_texture_runtime.h | 10 +- 17 files changed, 282 insertions(+), 294 deletions(-) diff --git a/src/video_core/regs_texturing.h b/src/video_core/regs_texturing.h index a92d118a5..7272ff05d 100644 --- a/src/video_core/regs_texturing.h +++ b/src/video_core/regs_texturing.h @@ -176,15 +176,23 @@ struct TexturingRegs { INSERT_PADDING_WORDS(0x9); struct FullTextureConfig { - const bool enabled; - const TextureConfig config; - const TextureFormat format; + u32 enabled; + TextureConfig config; + TextureFormat format; + + bool operator==(const FullTextureConfig& other) const noexcept { + return std::memcmp(this, &other, sizeof(other)) == 0; + } }; - const std::array GetTextures() const { + static_assert(std::has_unique_object_representations_v); + + using Textures = std::array; + + const Textures GetTextures() const { return {{ - {static_cast(main_config.texture0_enable), texture0, texture0_format}, - {static_cast(main_config.texture1_enable), texture1, texture1_format}, - {static_cast(main_config.texture2_enable), texture2, texture2_format}, + {main_config.texture0_enable, texture0, texture0_format}, + {main_config.texture1_enable, texture1, texture1_format}, + {main_config.texture2_enable, texture2, texture2_format}, }}; } @@ -381,11 +389,11 @@ struct TexturingRegs { BitField<16, 2, u32> alpha_scale; }; - inline unsigned GetColorMultiplier() const { + inline u32 GetColorMultiplier() const { return (color_scale < 3) ? (1 << color_scale) : 1; } - inline unsigned GetAlphaMultiplier() const { + inline u32 GetAlphaMultiplier() const { return (alpha_scale < 3) ? (1 << alpha_scale) : 1; } }; diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 30b5abcb8..193fee793 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -35,6 +35,7 @@ struct ScreenRectVertex { Common::Vec2f tex_coord; }; +constexpr u32 MAX_IN_FLIGHT_FRAMES = 10; constexpr u32 VERTEX_BUFFER_SIZE = sizeof(ScreenRectVertex) * 8192; constexpr std::array MakeOrthographicMatrix(u32 width, u32 height) { @@ -50,8 +51,8 @@ RendererVulkan::RendererVulkan(Core::System& system, Frontend::EmuWindow& window Frontend::EmuWindow* secondary_window) : RendererBase{system, window, secondary_window}, memory{system.Memory()}, instance{system.TelemetrySession(), window, Settings::values.physical_device.GetValue()}, - scheduler{instance, renderpass_cache}, renderpass_cache{instance, scheduler}, pool{instance}, - main_window{window, instance, scheduler}, + scheduler{instance, renderpass_cache}, renderpass_cache{instance, scheduler}, + pool{instance, scheduler.GetMasterSemaphore()}, main_window{window, instance, scheduler}, vertex_buffer{instance, scheduler, vk::BufferUsageFlagBits::eVertexBuffer, VERTEX_BUFFER_SIZE}, rasterizer{memory, @@ -77,7 +78,6 @@ RendererVulkan::~RendererVulkan() { device.waitIdle(); device.destroyPipelineLayout(pipeline_layout); - device.destroyDescriptorPool(descriptor_pool); device.destroyDescriptorSetLayout(descriptor_set_layout); device.destroyDescriptorUpdateTemplate(update_template); device.destroyShaderModule(vert_shader); @@ -305,29 +305,7 @@ void RendererVulkan::BuildLayoutsAndDescriptors() { pipeline_layout = device.createPipelineLayout(pipeline_layout_info); const u32 image_count = main_window.ImageCount(); - const vk::DescriptorPoolSize pool_size = { - .type = vk::DescriptorType::eCombinedImageSampler, - .descriptorCount = binding.descriptorCount * image_count, - }; - - const vk::DescriptorPoolCreateInfo descriptor_pool_info = { - .maxSets = image_count, - .poolSizeCount = 1, - .pPoolSizes = &pool_size, - }; - - descriptor_pool = device.createDescriptorPool(descriptor_pool_info); - - std::array layouts; - layouts.fill(descriptor_set_layout); - - const vk::DescriptorSetAllocateInfo alloc_info = { - .descriptorPool = descriptor_pool, - .descriptorSetCount = image_count, - .pSetLayouts = layouts.data(), - }; - - present_sets = device.allocateDescriptorSets(alloc_info); + present_sets = pool.Commit(descriptor_set_layout, image_count); } void RendererVulkan::BuildPipelines() { diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index fe0636323..f1a0603f6 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -4,18 +4,14 @@ #pragma once -#include -#include -#include -#include "common/common_types.h" #include "common/math_util.h" #include "core/hw/gpu.h" #include "video_core/renderer_base.h" -#include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_present_window.h" #include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_renderpass_cache.h" +#include "video_core/renderer_vulkan/vk_resource_pool.h" #include "video_core/renderer_vulkan/vk_scheduler.h" namespace Core { @@ -122,7 +118,6 @@ private: std::unique_ptr second_window; vk::PipelineLayout pipeline_layout; - vk::DescriptorPool descriptor_pool; vk::DescriptorSetLayout descriptor_set_layout; vk::DescriptorUpdateTemplate update_template; std::vector present_sets; diff --git a/src/video_core/renderer_vulkan/vk_blit_helper.cpp b/src/video_core/renderer_vulkan/vk_blit_helper.cpp index 9c7fbcbae..4242007f1 100644 --- a/src/video_core/renderer_vulkan/vk_blit_helper.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_helper.cpp @@ -177,10 +177,9 @@ constexpr vk::PipelineShaderStageCreateInfo MakeStages(vk::ShaderModule compute_ } // Anonymous namespace -BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_, DescriptorPool& pool, - RenderpassCache& renderpass_cache_) - : instance{instance_}, scheduler{scheduler_}, renderpass_cache{renderpass_cache_}, - device{instance.GetDevice()}, compute_provider{instance, pool, COMPUTE_BINDINGS}, +BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_) + : instance{instance_}, scheduler{scheduler_}, device{instance.GetDevice()}, + compute_provider{instance, pool, COMPUTE_BINDINGS}, compute_buffer_provider{instance, pool, COMPUTE_BUFFER_BINDINGS}, two_textures_provider{instance, pool, TWO_TEXTURES_BINDINGS}, compute_pipeline_layout{ @@ -314,7 +313,6 @@ bool BlitHelper::ConvertDS24S8ToRGBA8(Surface& source, Surface& dest, const auto descriptor_set = compute_provider.Acquire(textures); - renderpass_cache.EndRendering(); scheduler.Record([this, descriptor_set, copy, src_image = source.Image(), dst_image = dest.Image()](vk::CommandBuffer cmdbuf) { const std::array pre_barriers = { @@ -437,7 +435,6 @@ bool BlitHelper::DepthToBuffer(Surface& source, vk::Buffer buffer, const auto descriptor_set = compute_buffer_provider.Acquire(textures); - renderpass_cache.EndRendering(); scheduler.Record([this, descriptor_set, copy, src_image = source.Image(), extent = source.RealExtent(false)](vk::CommandBuffer cmdbuf) { const vk::ImageMemoryBarrier pre_barrier = { diff --git a/src/video_core/renderer_vulkan/vk_blit_helper.h b/src/video_core/renderer_vulkan/vk_blit_helper.h index b7735fcc9..afe66f1c7 100644 --- a/src/video_core/renderer_vulkan/vk_blit_helper.h +++ b/src/video_core/renderer_vulkan/vk_blit_helper.h @@ -4,7 +4,7 @@ #pragma once -#include "video_core/renderer_vulkan/vk_descriptor_pool.h" +#include "video_core/renderer_vulkan/vk_common.h" namespace VideoCore { struct TextureBlit; @@ -23,8 +23,7 @@ class BlitHelper { friend class TextureRuntime; public: - BlitHelper(const Instance& instance, Scheduler& scheduler, DescriptorPool& pool, - RenderpassCache& renderpass_cache); + explicit BlitHelper(const Instance& instance, Scheduler& scheduler); ~BlitHelper(); bool BlitDepthStencil(Surface& source, Surface& dest, const VideoCore::TextureBlit& blit); @@ -35,23 +34,16 @@ public: const VideoCore::BufferTextureCopy& copy); private: - /// Creates compute pipelines used for blit vk::Pipeline MakeComputePipeline(vk::ShaderModule shader, vk::PipelineLayout layout); - - /// Creates graphics pipelines used for blit vk::Pipeline MakeDepthStencilBlitPipeline(); private: const Instance& instance; Scheduler& scheduler; - RenderpassCache& renderpass_cache; vk::Device device; vk::RenderPass r32_renderpass; - DescriptorSetProvider compute_provider; - DescriptorSetProvider compute_buffer_provider; - DescriptorSetProvider two_textures_provider; vk::PipelineLayout compute_pipeline_layout; vk::PipelineLayout compute_buffer_pipeline_layout; vk::PipelineLayout two_textures_pipeline_layout; diff --git a/src/video_core/renderer_vulkan/vk_descriptor_update.cpp b/src/video_core/renderer_vulkan/vk_descriptor_update.cpp index a4db08887..83ba32245 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_update.cpp +++ b/src/video_core/renderer_vulkan/vk_descriptor_update.cpp @@ -3,10 +3,46 @@ // Refer to the license.txt file included. #include "video_core/renderer_vulkan/vk_descriptor_update.h" +#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_scheduler.h" namespace Vulkan { +constexpr size_t NUM_MAX_DESCRIPTORS = 5; + +DescriptorSetSpec::DescriptorSetSpec(const Instance& instance, + std::span bindings) { + const vk::Device device = instance.GetDevice(); + std::array update_entries; + + for (u32 i = 0; i < bindings.size(); i++) { + update_entries[i] = vk::DescriptorUpdateTemplateEntry{ + .dstBinding = bindings[i].binding, + .dstArrayElement = 0, + .descriptorCount = bindings[i].descriptorCount, + .descriptorType = bindings[i].descriptorType, + .offset = i * sizeof(DescriptorUpdateEntry), + .stride = sizeof(DescriptorUpdateEntry), + }; + } + + const vk::DescriptorSetLayoutCreateInfo layout_info = { + .bindingCount = static_cast(bindings.size()), + .pBindings = bindings.data(), + }; + descriptor_set_layout = device.createDescriptorSetLayoutUnique(layout_info); + + const vk::DescriptorUpdateTemplateCreateInfo template_info = { + .descriptorUpdateEntryCount = static_cast(bindings.size()), + .pDescriptorUpdateEntries = update_entries.data(), + .templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet, + .descriptorSetLayout = descriptor_set_layout.get(), + }; + update_template = device.createDescriptorUpdateTemplateUnique(template_info); +} + +DescriptorSetSpec::~DescriptorSetSpec() = default; + DescriptorUpdateQueue::DescriptorUpdateQueue(Scheduler& scheduler_, size_t num_frames_) : scheduler{scheduler_}, num_frames{num_frames_} { frame_payload_size = PAYLOAD_SIZE / num_frames; diff --git a/src/video_core/renderer_vulkan/vk_descriptor_update.h b/src/video_core/renderer_vulkan/vk_descriptor_update.h index e3b016919..857e99b33 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_update.h +++ b/src/video_core/renderer_vulkan/vk_descriptor_update.h @@ -9,6 +9,7 @@ namespace Vulkan { +class Instance; class Scheduler; union DescriptorUpdateEntry { @@ -17,10 +18,30 @@ union DescriptorUpdateEntry { vk::BufferView texel_buffer; }; +class DescriptorSetSpec { +public: + explicit DescriptorSetSpec(const Instance& instance, + std::span bindings); + ~DescriptorSetSpec(); + + vk::DescriptorSetLayout Layout() const noexcept { + return descriptor_set_layout.get(); + } + + vk::DescriptorUpdateTemplate Template() const noexcept { + return update_template.get(); + } + +private: + vk::UniqueDescriptorSetLayout descriptor_set_layout; + vk::UniqueDescriptorUpdateTemplate update_template; +}; + using namespace Common::Literals; class DescriptorUpdateQueue final { static constexpr size_t PAYLOAD_SIZE = 1_MiB; + public: explicit DescriptorUpdateQueue(Scheduler& scheduler, size_t num_frames); ~DescriptorUpdateQueue(); @@ -33,6 +54,14 @@ public: return upload_start; } + void AddImage(vk::ImageView image_view) { + (payload_cursor++)->image = vk::DescriptorImageInfo{ + .sampler = VK_NULL_HANDLE, + .imageView = image_view, + .imageLayout = vk::ImageLayout::eGeneral, + }; + } + void AddSampledImage(vk::ImageView image_view, vk::Sampler sampler) { (payload_cursor++)->image = vk::DescriptorImageInfo{ .sampler = sampler, diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 5ef3eb513..cf64b0d1b 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -272,10 +272,10 @@ bool GraphicsPipeline::Build(bool fail_on_compile_required) { pipeline_info.flags |= vk::PipelineCreateFlagBits::eFailOnPipelineCompileRequiredEXT; } - auto result = device.createGraphicsPipelineUnique(pipeline_cache, pipeline_info); - if (result.result == vk::Result::eSuccess) { - pipeline = std::move(result.value); - } else if (result.result == vk::Result::eErrorPipelineCompileRequiredEXT) { + auto [result, handle] = device.createGraphicsPipelineUnique(pipeline_cache, pipeline_info); + if (result == vk::Result::eSuccess) { + pipeline = std::move(handle); + } else if (result == vk::Result::eErrorPipelineCompileRequiredEXT) { return false; } else { UNREACHABLE_MSG("Graphics pipeline creation failed!"); diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 5d20f0b13..0859caee7 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -42,22 +42,18 @@ namespace Vulkan { class Instance; class RenderpassCache; -constexpr u32 MAX_SHADER_STAGES = 3; -constexpr u32 MAX_VERTEX_ATTRIBUTES = 16; -constexpr u32 MAX_VERTEX_BINDINGS = 13; +constexpr size_t MAX_SHADER_STAGES = 3; +constexpr size_t MAX_VERTEX_ATTRIBUTES = 16; +constexpr size_t MAX_VERTEX_BINDINGS = 13; -/** - * The pipeline state is tightly packed with bitfields to reduce - * the overhead of hashing as much as possible - */ union RasterizationState { - u8 value = 0; + u32 raw; BitField<0, 2, Pica::PipelineRegs::TriangleTopology> topology; BitField<4, 2, Pica::RasterizerRegs::CullMode> cull_mode; }; union DepthStencilState { - u32 value = 0; + u32 raw; BitField<0, 1, u32> depth_test_enable; BitField<1, 1, u32> depth_write_enable; BitField<2, 1, u32> stencil_test_enable; @@ -73,7 +69,7 @@ struct BlendingState { u16 color_write_mask; Pica::FramebufferRegs::LogicOp logic_op; union { - u32 value = 0; + u32 raw; BitField<0, 4, Pica::FramebufferRegs::BlendFactor> src_color_blend_factor; BitField<4, 4, Pica::FramebufferRegs::BlendFactor> dst_color_blend_factor; BitField<8, 3, Pica::FramebufferRegs::BlendEquation> color_blend_eq; @@ -84,10 +80,11 @@ struct BlendingState { }; struct DynamicState { - u32 blend_color = 0; + u32 blend_color; u8 stencil_reference; u8 stencil_compare_mask; u8 stencil_write_mask; + INSERT_PADDING_BYTES(1); Common::Rectangle scissor; Common::Rectangle viewport; @@ -129,12 +126,19 @@ struct AttachmentInfo { * Information about a graphics/compute pipeline */ struct PipelineInfo { - BlendingState blending; - AttachmentInfo attachments; - RasterizationState rasterization; - DepthStencilState depth_stencil; - DynamicState dynamic; - VertexLayout vertex_layout; + BlendingState blending{}; + AttachmentInfo attachments{}; + RasterizationState rasterization{}; + DepthStencilState depth_stencil{}; + DynamicState dynamic{}; + VertexLayout vertex_layout{}; + + enum Type : u32 { + Normal, + ShadowPlane, + ShadowCube, + }; + Type type{Type::Normal}; [[nodiscard]] u64 Hash(const Instance& instance) const; @@ -148,6 +152,7 @@ struct PipelineInfo { return depth_write || stencil_write; } }; +static_assert(std::has_unique_object_representations_v); struct Shader : public Common::AsyncHandle { explicit Shader(const Instance& instance); @@ -176,7 +181,7 @@ public: bool Build(bool fail_on_compile_required = false); [[nodiscard]] vk::Pipeline Handle() const noexcept { - return *pipeline; + return pipeline.get(); } private: diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 5f15620aa..5a9e855a7 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -8,6 +8,7 @@ #include "common/file_util.h" #include "common/logging/log.h" #include "common/microprofile.h" +#include "common/scope_exit.h" #include "common/settings.h" #include "video_core/renderer_vulkan/pica_to_vk.h" #include "video_core/renderer_vulkan/vk_instance.h" @@ -26,6 +27,12 @@ MICROPROFILE_DEFINE(Vulkan_Bind, "Vulkan", "Pipeline Bind", MP_RGB(192, 32, 32)) namespace Vulkan { +enum DescriptorSet { + Buffer, + Texture, + Utility, +}; + u32 AttribBytes(Pica::PipelineRegs::VertexAttributeFormat format, u32 size) { switch (format) { case Pica::PipelineRegs::VertexAttributeFormat::FLOAT: @@ -61,31 +68,33 @@ constexpr std::array BUFFER_BINDINGS = {{ {5, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, }}; +template constexpr std::array TEXTURE_BINDINGS = {{ - {0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}, + {0, tex0_type, num_faces, vk::ShaderStageFlagBits::eFragment}, {1, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}, {2, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}, }}; -// TODO: Use descriptor array for shadow cube -constexpr std::array SHADOW_BINDINGS = {{ +constexpr std::array UTILITY_BINDINGS = {{ {0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eFragment}, - {1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eFragment}, - {2, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eFragment}, - {3, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eFragment}, - {4, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eFragment}, - {5, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eFragment}, - {6, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eFragment}, }}; PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_, - RenderpassCache& renderpass_cache_, DescriptorPool& pool_) - : instance{instance_}, scheduler{scheduler_}, renderpass_cache{renderpass_cache_}, pool{pool_}, + RenderpassCache& renderpass_cache_, DescriptorPool& persistent_pool) + : instance{instance_}, scheduler{scheduler_}, + renderpass_cache{renderpass_cache_}, pool{instance, scheduler.GetMasterSemaphore()}, num_worker_threads{std::max(std::thread::hardware_concurrency(), 2U)}, - workers{num_worker_threads, "Pipeline workers"}, + workers{num_worker_threads, "Pipeline workers"}, buffer_set_spec{instance, BUFFER_BINDINGS}, + utility_set_spec{instance, UTILITY_BINDINGS}, + texture_set_specs{ + DescriptorSetSpec{instance, + TEXTURE_BINDINGS}, + DescriptorSetSpec{instance, TEXTURE_BINDINGS}, + DescriptorSetSpec{instance, TEXTURE_BINDINGS}}, trivial_vertex_shader{ instance, vk::ShaderStageFlagBits::eVertex, GLSL::GenerateTrivialVertexShader(instance.IsShaderClipDistanceSupported(), true)} { + // Create profile for driver assisted shader features. profile = Pica::Shader::Profile{ .has_separable_shaders = true, .has_clip_planes = instance.IsShaderClipDistanceSupported(), @@ -98,14 +107,10 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_, .has_logic_op = !instance.NeedsLogicOpEmulation(), .is_vulkan = true, }; - BuildLayout(); -} -void PipelineCache::BuildLayout() { std::array descriptor_set_layouts; - std::transform(descriptor_set_providers.begin(), descriptor_set_providers.end(), - descriptor_set_layouts.begin(), - [](const auto& provider) { return provider.Layout(); }); + descriptor_set_layouts[DescriptorSet::Buffer] = buffer_set_spec.Layout(); + descriptor_set_layouts[DescriptorSet::Utility] = utility_set_spec.Layout(); const vk::PipelineLayoutCreateInfo layout_info = { .setLayoutCount = NUM_RASTERIZER_SETS, @@ -113,7 +118,15 @@ void PipelineCache::BuildLayout() { .pushConstantRangeCount = 0, .pPushConstantRanges = nullptr, }; - pipeline_layout = instance.GetDevice().createPipelineLayoutUnique(layout_info); + + // Create rasterizer pipeline layouts. + for (size_t i = 0; i < NUM_PIPELINE_CONFIGS; i++) { + descriptor_set_layouts[DescriptorSet::Texture] = texture_set_specs[i].Layout(); + pipeline_layouts[i] = instance.GetDevice().createPipelineLayoutUnique(layout_info); + } + + // Allocate buffer descriptor set from the persistent pool + bound_descriptor_sets[DescriptorSet::Buffer] = persistent_pool.Commit(buffer_set_spec.Layout()); } PipelineCache::~PipelineCache() { @@ -125,34 +138,40 @@ void PipelineCache::LoadDiskCache() { return; } - const std::string cache_file_path = fmt::format("{}{:x}{:x}.bin", GetPipelineCacheDir(), - instance.GetVendorID(), instance.GetDeviceID()); - vk::PipelineCacheCreateInfo cache_info = { - .initialDataSize = 0, - .pInitialData = nullptr, - }; + const auto cache_dir = GetPipelineCacheDir(); + const u32 vendor_id = instance.GetVendorID(); + const u32 device_id = instance.GetDeviceID(); + const auto cache_file_path = fmt::format("{}{:x}{:x}.bin", cache_dir, vendor_id, device_id); + vk::PipelineCacheCreateInfo cache_info{}; std::vector cache_data; - FileUtil::IOFile cache_file{cache_file_path, "r"}; - if (cache_file.IsOpen()) { - LOG_INFO(Render_Vulkan, "Loading pipeline cache"); - const u64 cache_file_size = cache_file.GetSize(); - cache_data.resize(cache_file_size); - if (cache_file.ReadBytes(cache_data.data(), cache_file_size)) { - if (!IsCacheValid(cache_data)) { - LOG_WARNING(Render_Vulkan, "Pipeline cache provided invalid, ignoring"); - } else { - cache_info.initialDataSize = cache_file_size; - cache_info.pInitialData = cache_data.data(); - } - } + SCOPE_EXIT({ + const vk::Device device = instance.GetDevice(); + pipeline_cache = device.createPipelineCacheUnique(cache_info); + }); - cache_file.Close(); + FileUtil::IOFile cache_file{cache_file_path, "rb"}; + if (!cache_file.IsOpen()) { + LOG_INFO(Render_Vulkan, "No pipeline cache found for device"); + return; } - vk::Device device = instance.GetDevice(); - pipeline_cache = device.createPipelineCacheUnique(cache_info); + const u64 cache_file_size = cache_file.GetSize(); + cache_data.resize(cache_file_size); + if (cache_file.ReadBytes(cache_data.data(), cache_file_size) != cache_file_size) { + LOG_ERROR(Render_Vulkan, "Error during pipeline cache read, removing"); + FileUtil::Delete(cache_file_path); + return; + } + + if (!IsCacheValid(cache_data)) { + LOG_WARNING(Render_Vulkan, "Pipeline cache provided invalid, ignoring"); + } + + LOG_INFO(Render_Vulkan, "Loading pipeline cache with size {} KB", cache_file_size / 1024); + cache_info.initialDataSize = cache_file_size; + cache_info.pInitialData = cache_data.data(); } void PipelineCache::SaveDiskCache() { @@ -160,22 +179,23 @@ void PipelineCache::SaveDiskCache() { return; } - const std::string cache_file_path = fmt::format("{}{:x}{:x}.bin", GetPipelineCacheDir(), - instance.GetVendorID(), instance.GetDeviceID()); + const auto cache_dir = GetPipelineCacheDir(); + const u32 vendor_id = instance.GetVendorID(); + const u32 device_id = instance.GetDeviceID(); + const auto cache_file_path = fmt::format("{}{:x}{:x}.bin", cache_dir, vendor_id, device_id); + FileUtil::IOFile cache_file{cache_file_path, "wb"}; if (!cache_file.IsOpen()) { LOG_ERROR(Render_Vulkan, "Unable to open pipeline cache for writing"); return; } - vk::Device device = instance.GetDevice(); - auto cache_data = device.getPipelineCacheData(*pipeline_cache); - if (!cache_file.WriteBytes(cache_data.data(), cache_data.size())) { - LOG_ERROR(Render_Vulkan, "Error during pipeline cache write"); - return; + const vk::Device device = instance.GetDevice(); + const auto cache_data = device.getPipelineCacheData(*pipeline_cache); + if (cache_file.WriteBytes(cache_data.data(), cache_data.size()) != cache_data.size()) { + LOG_ERROR(Render_Vulkan, "Error during pipeline cache write, removing"); + FileUtil::Delete(cache_file_path); } - - cache_file.Close(); } bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) { @@ -191,12 +211,14 @@ bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) { auto [it, new_pipeline] = graphics_pipelines.try_emplace(pipeline_hash); if (new_pipeline) { - it.value() = - std::make_unique(instance, renderpass_cache, info, *pipeline_cache, - *pipeline_layout, current_shaders, &workers); + const auto pipeline_layout = pipeline_layouts[info.type].get(); + auto pipeline = std::make_unique(instance, renderpass_cache, info, + pipeline_cache.get(), pipeline_layout, + current_shaders, &workers); + it.value() = std::move(pipeline); } - GraphicsPipeline* const pipeline{it->second.get()}; + GraphicsPipeline* const pipeline = it->second.get(); if (!pipeline->IsDone() && !pipeline->TryBuild(wait_built)) { return false; } @@ -399,7 +421,7 @@ bool PipelineCache::UseProgrammableVertexShader(const Pica::Regs& regs, } auto [iter, new_program] = programmable_vertex_cache.try_emplace(program, instance); - auto& shader = iter->second; + auto& shader = iter.value(); if (new_program) { shader.program = std::move(program); @@ -410,7 +432,7 @@ bool PipelineCache::UseProgrammableVertexShader(const Pica::Regs& regs, }); } - it->second = &shader; + it.value() = &shader; } Shader* const shader{it->second}; @@ -438,7 +460,7 @@ bool PipelineCache::UseFixedGeometryShader(const Pica::Regs& regs) { const PicaFixedGSConfig gs_config{regs, instance.IsShaderClipDistanceSupported()}; auto [it, new_shader] = fixed_geometry_shaders.try_emplace(gs_config, instance); - auto& shader = it->second; + auto& shader = it.value(); if (new_shader) { workers.QueueWork([gs_config, device = instance.GetDevice(), &shader]() { @@ -463,7 +485,7 @@ void PipelineCache::UseFragmentShader(const Pica::Regs& regs, const Pica::Shader::UserConfig& user) { const FSConfig fs_config{regs, user, profile}; const auto [it, new_shader] = fragment_shaders.try_emplace(fs_config, instance); - auto& shader = it->second; + auto& shader = it.value(); if (new_shader) { const bool use_spirv = Settings::values.spirv_shader_gen.GetValue(); @@ -485,52 +507,6 @@ void PipelineCache::UseFragmentShader(const Pica::Regs& regs, shader_hashes[ProgramType::FS] = fs_config.Hash(); } -void PipelineCache::BindTexture(u32 binding, vk::ImageView image_view, vk::Sampler sampler) { - auto& info = update_data[1][binding].image_info; - if (info.imageView == image_view && info.sampler == sampler) { - return; - } - set_dirty[1] = true; - info = vk::DescriptorImageInfo{ - .sampler = sampler, - .imageView = image_view, - .imageLayout = vk::ImageLayout::eGeneral, - }; -} - -void PipelineCache::BindStorageImage(u32 binding, vk::ImageView image_view) { - auto& info = update_data[2][binding].image_info; - if (info.imageView == image_view) { - return; - } - set_dirty[2] = true; - info = vk::DescriptorImageInfo{ - .imageView = image_view, - .imageLayout = vk::ImageLayout::eGeneral, - }; -} - -void PipelineCache::BindBuffer(u32 binding, vk::Buffer buffer, u32 offset, u32 size) { - auto& info = update_data[0][binding].buffer_info; - if (info.buffer == buffer && info.offset == offset && info.range == size) { - return; - } - set_dirty[0] = true; - info = vk::DescriptorBufferInfo{ - .buffer = buffer, - .offset = offset, - .range = size, - }; -} - -void PipelineCache::BindTexelBuffer(u32 binding, vk::BufferView buffer_view) { - auto& view = update_data[0][binding].buffer_view; - if (view != buffer_view) { - set_dirty[0] = true; - view = buffer_view; - } -} - void PipelineCache::SetBufferOffset(u32 binding, size_t offset) { if (offsets[binding] != static_cast(offset)) { offsets[binding] = static_cast(offset); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 29c724189..586a73025 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -8,7 +8,9 @@ #include #include "common/thread_worker.h" +#include "video_core/renderer_vulkan/vk_descriptor_update.h" #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" +#include "video_core/renderer_vulkan/vk_resource_pool.h" #include "video_core/shader/generator/pica_fs_config.h" #include "video_core/shader/generator/profile.h" #include "video_core/shader/generator/shader_gen.h" @@ -28,13 +30,20 @@ class Scheduler; class RenderpassCache; class DescriptorPool; -constexpr u32 NUM_RASTERIZER_SETS = 3; -constexpr u32 NUM_DYNAMIC_OFFSETS = 3; +enum class PipelineConfig { + Normal, + ShadowPlane, + ShadowCube, +}; /** * Stores a collection of rasterizer pipelines used during rendering. */ class PipelineCache { + static constexpr size_t NUM_RASTERIZER_SETS = 3; + static constexpr size_t NUM_PIPELINE_CONFIGS = 3; + static constexpr size_t NUM_DYNAMIC_OFFSETS = 3; + public: explicit PipelineCache(const Instance& instance, Scheduler& scheduler, RenderpassCache& renderpass_cache, DescriptorPool& pool); @@ -65,25 +74,10 @@ public: /// Binds a fragment shader generated from PICA state void UseFragmentShader(const Pica::Regs& regs, const Pica::Shader::UserConfig& user); - /// Binds a texture to the specified binding - void BindTexture(u32 binding, vk::ImageView image_view, vk::Sampler sampler); - - /// Binds a storage image to the specified binding - void BindStorageImage(u32 binding, vk::ImageView image_view); - - /// Binds a buffer to the specified binding - void BindBuffer(u32 binding, vk::Buffer buffer, u32 offset, u32 size); - - /// Binds a buffer to the specified binding - void BindTexelBuffer(u32 binding, vk::BufferView buffer_view); - /// Sets the dynamic offset for the uniform buffer at binding - void SetBufferOffset(u32 binding, size_t offset); + void BindBufferRange(u32 binding, size_t offset); private: - /// Builds the rasterizer pipeline layout - void BuildLayout(); - /// Returns true when the disk data can be used by the current driver bool IsCacheValid(std::span cache_data) const; @@ -97,11 +91,10 @@ private: const Instance& instance; Scheduler& scheduler; RenderpassCache& renderpass_cache; - DescriptorPool& pool; + DescriptorPool pool; Pica::Shader::Profile profile{}; vk::UniquePipelineCache pipeline_cache; - vk::UniquePipelineLayout pipeline_layout; std::size_t num_worker_threads; Common::ThreadWorker workers; PipelineInfo current_info{}; @@ -109,8 +102,13 @@ private: tsl::robin_map, Common::IdentityHash> graphics_pipelines; + DescriptorSetSpec buffer_set_spec; + DescriptorSetSpec utility_set_spec; + std::array texture_set_specs; + std::array pipeline_layouts; + + std::array bound_descriptor_sets; std::array offsets{}; - std::array bound_descriptor_sets{}; std::bitset set_dirty{}; std::array shader_hashes; diff --git a/src/video_core/renderer_vulkan/vk_present_window.cpp b/src/video_core/renderer_vulkan/vk_present_window.cpp index 6b17ee88a..9788e0d6b 100644 --- a/src/video_core/renderer_vulkan/vk_present_window.cpp +++ b/src/video_core/renderer_vulkan/vk_present_window.cpp @@ -106,8 +106,7 @@ PresentWindow::PresentWindow(Frontend::EmuWindow& emu_window_, const Instance& i vsync_enabled{Settings::values.use_vsync_new.GetValue()}, blit_supported{ CanBlitToSwapchain(instance.GetPhysicalDevice(), swapchain.GetSurfaceFormat().format)}, - use_present_thread{Settings::values.async_presentation.GetValue()}, - last_render_surface{emu_window.GetWindowInfo().render_surface} { + use_present_thread{Settings::values.async_presentation.GetValue()} { const u32 num_images = swapchain.GetImageCount(); const vk::Device device = instance.GetDevice(); @@ -156,7 +155,7 @@ PresentWindow::~PresentWindow() { } void PresentWindow::RecreateFrame(Frame* frame, u32 width, u32 height) { - vk::Device device = instance.GetDevice(); + const vk::Device device = instance.GetDevice(); if (frame->framebuffer) { device.destroyFramebuffer(frame->framebuffer); } @@ -237,7 +236,7 @@ Frame* PresentWindow::GetRenderFrame() { Frame* frame = free_queue.front(); free_queue.pop(); - vk::Device device = instance.GetDevice(); + const vk::Device device = instance.GetDevice(); vk::Result result{}; const auto wait = [&]() { @@ -453,7 +452,7 @@ void PresentWindow::CopyToSwapchain(Frame* frame) { const vk::Semaphore image_acquired = swapchain.GetImageAcquiredSemaphore(); const std::array wait_semaphores = {image_acquired, frame->render_ready}; - vk::SubmitInfo submit_info = { + const vk::SubmitInfo submit_info = { .waitSemaphoreCount = static_cast(wait_semaphores.size()), .pWaitSemaphores = wait_semaphores.data(), .pWaitDstStageMask = wait_stage_masks.data(), @@ -468,8 +467,7 @@ void PresentWindow::CopyToSwapchain(Frame* frame) { try { graphics_queue.submit(submit_info, frame->present_done); } catch (vk::DeviceLostError& err) { - LOG_CRITICAL(Render_Vulkan, "Device lost during present submit: {}", err.what()); - UNREACHABLE(); + UNREACHABLE_MSG("Device lost during present submit: {}", err.what()); } swapchain.Present(); diff --git a/src/video_core/renderer_vulkan/vk_present_window.h b/src/video_core/renderer_vulkan/vk_present_window.h index 71da72003..fffacb200 100644 --- a/src/video_core/renderer_vulkan/vk_present_window.h +++ b/src/video_core/renderer_vulkan/vk_present_window.h @@ -65,7 +65,9 @@ public: private: void PresentThread(std::stop_token token); + void CopyToSwapchain(Frame* frame); + vk::RenderPass CreateRenderpass(); private: @@ -92,7 +94,6 @@ private: bool vsync_enabled{}; bool blit_supported; bool use_present_thread{true}; - void* last_render_surface{}; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 401c8010d..4f7d0b08c 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -89,6 +89,7 @@ RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory, MakeSoftwareVertexLayout(); pipeline_info.vertex_layout = software_layout; + // Create texture buffer views for the lighting LUTs. const vk::Device device = instance.GetDevice(); texture_lf_view = device.createBufferViewUnique({ .buffer = texture_lf_buffer.Handle(), @@ -109,24 +110,14 @@ RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory, .range = VK_WHOLE_SIZE, }); - // Since we don't have access to VK_EXT_descriptor_indexing we need to intiallize - // all descriptor sets even the ones we don't use. - pipeline_cache.BindBuffer(0, uniform_buffer.Handle(), 0, sizeof(VSPicaUniformData)); - pipeline_cache.BindBuffer(1, uniform_buffer.Handle(), 0, sizeof(VSUniformData)); - pipeline_cache.BindBuffer(2, uniform_buffer.Handle(), 0, sizeof(FSUniformData)); - pipeline_cache.BindTexelBuffer(3, *texture_lf_view); - pipeline_cache.BindTexelBuffer(4, *texture_rg_view); - pipeline_cache.BindTexelBuffer(5, *texture_rgba_view); - - Surface& null_surface = res_cache.GetSurface(VideoCore::NULL_SURFACE_ID); - Sampler& null_sampler = res_cache.GetSampler(VideoCore::NULL_SAMPLER_ID); - for (u32 i = 0; i < 3; i++) { - pipeline_cache.BindTexture(i, null_surface.ImageView(), null_sampler.Handle()); - } - - for (u32 i = 0; i < 7; i++) { - pipeline_cache.BindStorageImage(i, null_surface.StorageView()); - } + // Update persistent buffer descriptor set with our rasterizer buffers. + update_queue.Acquire(); + update_queue.AddBuffer(uniform_buffer.Handle(), 0, sizeof(VSPicaUniformData)); + update_queue.AddBuffer(uniform_buffer.Handle(), 0, sizeof(VSPicaUniformData)); + update_queue.AddBuffer(uniform_buffer.Handle(), 0, sizeof(VSUniformData)); + update_queue.AddTexelBuffer(texture_lf_view.get()); + update_queue.AddTexelBuffer(texture_rg_view.get()); + update_queue.AddTexelBuffer(texture_rgba_view.get()); SyncEntireState(); } @@ -476,16 +467,10 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { return true; } + // Update attachment formats pipeline_info.attachments.color = framebuffer->Format(SurfaceType::Color); pipeline_info.attachments.depth = framebuffer->Format(SurfaceType::Depth); - if (shadow_rendering) { - pipeline_cache.BindStorageImage(6, framebuffer->ImageView(SurfaceType::Color)); - } else { - Surface& null_surface = res_cache.GetSurface(VideoCore::NULL_SURFACE_ID); - pipeline_cache.BindStorageImage(6, null_surface.StorageView()); - } - // Update scissor uniforms const auto [scissor_x1, scissor_y2, scissor_x2, scissor_y1] = fb_helper.Scissor(); if (fs_uniform_block_data.data.scissor_x1 != scissor_x1 || @@ -503,6 +488,11 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { // Sync and bind the texture surfaces SyncTextureUnits(framebuffer); + // Attach the framebuffer as storage image during shadow rendering. + if (shadow_rendering) { + update_queue.AddImage(framebuffer->ImageView(SurfaceType::Color)); + } + // Sync and bind the shader if (shader_dirty) { pipeline_cache.UseFragmentShader(regs, user_config); @@ -555,7 +545,17 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { void RasterizerVulkan::SyncTextureUnits(const Framebuffer* framebuffer) { using TextureType = Pica::TexturingRegs::TextureConfig::TextureType; + // Check if the PICA texture configuration changed. const auto pica_textures = regs.texturing.GetTextures(); + if (pica_textures == textures && textures[0].config.type != TextureType::TextureCube) { + return; + } + + // Reserve space in the queue for incoming texture data. + // We will write the image data in the same order as defined + // in the rasterizer descriptor texture sets. + update_queue.Acquire(); + for (u32 texture_index = 0; texture_index < pica_textures.size(); ++texture_index) { const auto& texture = pica_textures[texture_index]; @@ -563,8 +563,7 @@ void RasterizerVulkan::SyncTextureUnits(const Framebuffer* framebuffer) { if (!texture.enabled) { const Surface& null_surface = res_cache.GetSurface(VideoCore::NULL_SURFACE_ID); const Sampler& null_sampler = res_cache.GetSampler(VideoCore::NULL_SAMPLER_ID); - pipeline_cache.BindTexture(texture_index, null_surface.ImageView(), - null_sampler.Handle()); + update_queue.AddSampledImage(null_surface.ImageView(), null_sampler.Handle()); continue; } @@ -574,7 +573,7 @@ void RasterizerVulkan::SyncTextureUnits(const Framebuffer* framebuffer) { case TextureType::Shadow2D: { Surface& surface = res_cache.GetTextureSurface(texture); surface.flags |= VideoCore::SurfaceFlagBits::ShadowMap; - pipeline_cache.BindStorageImage(0, surface.StorageView()); + update_queue.AddImage(surface.StorageView()); continue; } case TextureType::ShadowCube: { @@ -586,7 +585,6 @@ void RasterizerVulkan::SyncTextureUnits(const Framebuffer* framebuffer) { continue; } default: - UnbindSpecial(); break; } } @@ -594,10 +592,12 @@ void RasterizerVulkan::SyncTextureUnits(const Framebuffer* framebuffer) { // Bind the texture provided by the rasterizer cache Surface& surface = res_cache.GetTextureSurface(texture); Sampler& sampler = res_cache.GetSampler(texture.config); - if (!IsFeedbackLoop(texture_index, framebuffer, surface, sampler)) { - pipeline_cache.BindTexture(texture_index, surface.ImageView(), sampler.Handle()); + if (!IsFeedbackLoop(framebuffer, surface, sampler)) { + update_queue.AddSampledImage(surface.ImageView(), sampler.Handle()); } } + + textures = pica_textures; } void RasterizerVulkan::BindShadowCube(const Pica::TexturingRegs::FullTextureConfig& texture) { @@ -609,13 +609,11 @@ void RasterizerVulkan::BindShadowCube(const Pica::TexturingRegs::FullTextureConf }; for (CubeFace face : faces) { - const u32 binding = static_cast(face); info.physical_address = regs.texturing.GetCubePhysicalAddress(face); - - const VideoCore::SurfaceId surface_id = res_cache.GetTextureSurface(info); + const auto surface_id = res_cache.GetTextureSurface(info); Surface& surface = res_cache.GetSurface(surface_id); surface.flags |= VideoCore::SurfaceFlagBits::ShadowMap; - pipeline_cache.BindStorageImage(binding, surface.StorageView()); + update_queue.AddImage(surface.StorageView()); } } @@ -633,13 +631,13 @@ void RasterizerVulkan::BindTextureCube(const Pica::TexturingRegs::FullTextureCon .format = texture.format, }; - Surface& surface = res_cache.GetTextureCube(config); - Sampler& sampler = res_cache.GetSampler(texture.config); - pipeline_cache.BindTexture(0, surface.ImageView(), sampler.Handle()); + const Surface& surface = res_cache.GetTextureCube(config); + const Sampler& sampler = res_cache.GetSampler(texture.config); + update_queue.AddSampledImage(surface.ImageView(), sampler.Handle()); } -bool RasterizerVulkan::IsFeedbackLoop(u32 texture_index, const Framebuffer* framebuffer, - Surface& surface, Sampler& sampler) { +bool RasterizerVulkan::IsFeedbackLoop(const Framebuffer* framebuffer, Surface& surface, + Sampler& sampler) { const vk::ImageView color_view = framebuffer->ImageView(SurfaceType::Color); const bool is_feedback_loop = color_view == surface.ImageView(); if (!is_feedback_loop) { @@ -647,17 +645,10 @@ bool RasterizerVulkan::IsFeedbackLoop(u32 texture_index, const Framebuffer* fram } // Make a temporary copy of the framebuffer to sample from - pipeline_cache.BindTexture(texture_index, surface.CopyImageView(), sampler.Handle()); + update_queue.AddSampledImage(surface.CopyImageView(), sampler.Handle()); return true; } -void RasterizerVulkan::UnbindSpecial() { - Surface& null_surface = res_cache.GetSurface(VideoCore::NULL_SURFACE_ID); - for (u32 i = 0; i < 6; i++) { - pipeline_cache.BindStorageImage(i, null_surface.StorageView()); - } -} - void RasterizerVulkan::NotifyFixedFunctionPicaRegisterChanged(u32 id) { switch (id) { // Culling @@ -1098,24 +1089,24 @@ void RasterizerVulkan::UploadUniforms(bool accelerate_draw) { auto [uniforms, offset, invalidate] = uniform_buffer.Map(uniform_size, uniform_buffer_alignment); - u32 used_bytes = 0; + size_t used_bytes = 0; if (sync_vs || invalidate) { std::memcpy(uniforms + used_bytes, &vs_uniform_block_data.data, sizeof(vs_uniform_block_data.data)); - pipeline_cache.SetBufferOffset(1, offset + used_bytes); + pipeline_cache.BindBufferRange(1, offset + used_bytes); vs_uniform_block_data.dirty = false; - used_bytes += static_cast(uniform_size_aligned_vs); + used_bytes += uniform_size_aligned_vs; } if (sync_fs || invalidate) { std::memcpy(uniforms + used_bytes, &fs_uniform_block_data.data, sizeof(fs_uniform_block_data.data)); - pipeline_cache.SetBufferOffset(2, offset + used_bytes); + pipeline_cache.BindBufferRange(2, offset + used_bytes); fs_uniform_block_data.dirty = false; - used_bytes += static_cast(uniform_size_aligned_fs); + used_bytes += uniform_size_aligned_fs; } if (sync_vs_pica) { @@ -1123,8 +1114,8 @@ void RasterizerVulkan::UploadUniforms(bool accelerate_draw) { vs_uniforms.uniforms.SetFromRegs(regs.vs, Pica::g_state.vs); std::memcpy(uniforms + used_bytes, &vs_uniforms, sizeof(vs_uniforms)); - pipeline_cache.SetBufferOffset(0, offset + used_bytes); - used_bytes += static_cast(uniform_size_aligned_vs_pica); + pipeline_cache.BindBufferRange(0, offset + used_bytes); + used_bytes += uniform_size_aligned_vs_pica; } uniform_buffer.Commit(used_bytes); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index cd7620c49..db62500ab 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -6,6 +6,7 @@ #include "core/hw/gpu.h" #include "video_core/rasterizer_accelerated.h" +#include "video_core/renderer_vulkan/vk_descriptor_update.h" #include "video_core/renderer_vulkan/vk_pipeline_cache.h" #include "video_core/renderer_vulkan/vk_renderpass_cache.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h" @@ -104,11 +105,7 @@ private: void BindTextureCube(const Pica::TexturingRegs::FullTextureConfig& texture); /// Makes a temporary copy of the framebuffer if a feedback loop is detected - bool IsFeedbackLoop(u32 texture_index, const Framebuffer* framebuffer, Surface& surface, - Sampler& sampler); - - /// Unbinds all special texture unit 0 texture configurations - void UnbindSpecial(); + bool IsFeedbackLoop(const Framebuffer* framebuffer, Surface& surface, Sampler& sampler); /// Upload the uniform blocks to the uniform buffer object void UploadUniforms(bool accelerate_draw); @@ -144,6 +141,7 @@ private: PipelineCache pipeline_cache; TextureRuntime runtime; RasterizerCache res_cache; + DescriptorUpdateQueue update_queue; VertexLayout software_layout; std::array binding_offsets{}; @@ -159,6 +157,7 @@ private: vk::UniqueBufferView texture_lf_view; vk::UniqueBufferView texture_rg_view; vk::UniqueBufferView texture_rgba_view; + Pica::TexturingRegs::Textures textures{}; u64 uniform_buffer_alignment; u64 uniform_size_aligned_vs_pica; u64 uniform_size_aligned_vs; diff --git a/src/video_core/renderer_vulkan/vk_texture_runtime.cpp b/src/video_core/renderer_vulkan/vk_texture_runtime.cpp index 79458a70c..bd4f49fa9 100644 --- a/src/video_core/renderer_vulkan/vk_texture_runtime.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_runtime.cpp @@ -11,7 +11,6 @@ #include "video_core/rasterizer_cache/texture_codec.h" #include "video_core/rasterizer_cache/utils.h" #include "video_core/renderer_vulkan/pica_to_vk.h" -#include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_renderpass_cache.h" #include "video_core/renderer_vulkan/vk_scheduler.h" @@ -253,9 +252,9 @@ constexpr u64 DOWNLOAD_BUFFER_SIZE = 16_MiB; TextureRuntime::TextureRuntime(const Instance& instance, Scheduler& scheduler, RenderpassCache& renderpass_cache, DescriptorPool& pool, - DescriptorSetProvider& texture_provider_, u32 num_swapchain_images_) + u32 num_swapchain_images_) : instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache}, - texture_provider{texture_provider_}, blit_helper{instance, scheduler, pool, renderpass_cache}, + blit_helper{instance, scheduler, pool, renderpass_cache}, upload_buffer{instance, scheduler, vk::BufferUsageFlagBits::eTransferSrc, UPLOAD_BUFFER_SIZE, BufferType::Upload}, download_buffer{instance, scheduler, @@ -697,13 +696,6 @@ bool TextureRuntime::NeedsConversion(VideoCore::PixelFormat format) const { traits.aspect != (vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil); } -void TextureRuntime::FreeDescriptorSetsWithImage(vk::ImageView image_view) { - texture_provider.FreeWithImage(image_view); - blit_helper.compute_provider.FreeWithImage(image_view); - blit_helper.compute_buffer_provider.FreeWithImage(image_view); - blit_helper.two_textures_provider.FreeWithImage(image_view); -} - Surface::Surface(TextureRuntime& runtime_, const VideoCore::SurfaceParams& params) : SurfaceBase{params}, runtime{&runtime_}, instance{&runtime_.GetInstance()}, scheduler{&runtime_.GetScheduler()}, traits{instance->GetTraits(pixel_format)} { @@ -803,9 +795,6 @@ Surface::~Surface() { return; } for (const auto& [alloc, image, image_view] : handles) { - if (image_view) { - runtime->FreeDescriptorSetsWithImage(*image_view); - } if (image) { vmaDestroyImage(instance->GetAllocator(), image, alloc); } @@ -1558,13 +1547,13 @@ Sampler::Sampler(TextureRuntime& runtime, const VideoCore::SamplerParams& params Sampler::~Sampler() = default; -DebugScope::DebugScope(TextureRuntime& runtime, Common::Vec4f color, std::string_view label) +DebugScope::DebugScope(TextureRuntime& runtime, Common::Vec4f color, std::string&& label) : scheduler{runtime.GetScheduler()}, has_debug_tool{ runtime.GetInstance().HasDebuggingToolAttached()} { if (!has_debug_tool) { return; } - scheduler.Record([color, label = std::string(label)](vk::CommandBuffer cmdbuf) { + scheduler.Record([color, label = std::move(label)](vk::CommandBuffer cmdbuf) { const vk::DebugUtilsLabelEXT debug_label = { .pLabelName = label.data(), .color = std::array{color[0], color[1], color[2], color[3]}, diff --git a/src/video_core/renderer_vulkan/vk_texture_runtime.h b/src/video_core/renderer_vulkan/vk_texture_runtime.h index 2bef63dab..319ffdd6d 100644 --- a/src/video_core/renderer_vulkan/vk_texture_runtime.h +++ b/src/video_core/renderer_vulkan/vk_texture_runtime.h @@ -42,8 +42,8 @@ class TextureRuntime { public: explicit TextureRuntime(const Instance& instance, Scheduler& scheduler, - RenderpassCache& renderpass_cache, DescriptorPool& pool, - DescriptorSetProvider& texture_provider, u32 num_swapchain_images); + RenderpassCache& renderpass_cache, + u32 num_swapchain_images); ~TextureRuntime(); const Instance& GetInstance() const { @@ -85,9 +85,6 @@ public: /// Returns true if the provided pixel format needs convertion bool NeedsConversion(VideoCore::PixelFormat format) const; - /// Removes any descriptor sets that contain the provided image view. - void FreeDescriptorSetsWithImage(vk::ImageView image_view); - private: /// Clears a partial texture rect using a clear rectangle void ClearTextureWithRenderpass(Surface& surface, const VideoCore::TextureClear& clear); @@ -96,7 +93,6 @@ private: const Instance& instance; Scheduler& scheduler; RenderpassCache& renderpass_cache; - DescriptorSetProvider& texture_provider; BlitHelper blit_helper; StreamBuffer upload_buffer; StreamBuffer download_buffer; @@ -277,7 +273,7 @@ public: explicit DebugScope(TextureRuntime& runtime, Common::Vec4f color, fmt::format_string format, T... args) : DebugScope{runtime, color, fmt::format(format, std::forward(args)...)} {} - explicit DebugScope(TextureRuntime& runtime, Common::Vec4f color, std::string_view label); + explicit DebugScope(TextureRuntime& runtime, Common::Vec4f color, std::string&& label); ~DebugScope(); private: