diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | 95 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_compute_pipeline.h | 30 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | 72 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_graphics_pipeline.h | 31 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 78 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.h | 24 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_rasterizer.cpp | 15 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_scheduler.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_scheduler.h | 7 |
9 files changed, 197 insertions, 165 deletions
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 8e544d745..1c3249e3c 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | |||
| @@ -27,8 +27,9 @@ DescriptorLayoutTuple CreateLayout(const Device& device, const Shader::Info& inf | |||
| 27 | 27 | ||
| 28 | ComputePipeline::ComputePipeline(const Device& device, VKDescriptorPool& descriptor_pool, | 28 | ComputePipeline::ComputePipeline(const Device& device, VKDescriptorPool& descriptor_pool, |
| 29 | VKUpdateDescriptorQueue& update_descriptor_queue_, | 29 | VKUpdateDescriptorQueue& update_descriptor_queue_, |
| 30 | const Shader::Info& info_, vk::ShaderModule spv_module_) | 30 | Common::ThreadWorker* thread_worker, const Shader::Info& info_, |
| 31 | : update_descriptor_queue{&update_descriptor_queue_}, info{info_}, | 31 | vk::ShaderModule spv_module_) |
| 32 | : update_descriptor_queue{update_descriptor_queue_}, info{info_}, | ||
| 32 | spv_module(std::move(spv_module_)) { | 33 | spv_module(std::move(spv_module_)) { |
| 33 | DescriptorLayoutTuple tuple{CreateLayout(device, info)}; | 34 | DescriptorLayoutTuple tuple{CreateLayout(device, info)}; |
| 34 | descriptor_set_layout = std::move(tuple.descriptor_set_layout); | 35 | descriptor_set_layout = std::move(tuple.descriptor_set_layout); |
| @@ -36,46 +37,55 @@ ComputePipeline::ComputePipeline(const Device& device, VKDescriptorPool& descrip | |||
| 36 | descriptor_update_template = std::move(tuple.descriptor_update_template); | 37 | descriptor_update_template = std::move(tuple.descriptor_update_template); |
| 37 | descriptor_allocator = DescriptorAllocator(descriptor_pool, *descriptor_set_layout); | 38 | descriptor_allocator = DescriptorAllocator(descriptor_pool, *descriptor_set_layout); |
| 38 | 39 | ||
| 39 | const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci{ | 40 | auto func{[this, &device] { |
| 40 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT, | 41 | const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci{ |
| 41 | .pNext = nullptr, | 42 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT, |
| 42 | .requiredSubgroupSize = GuestWarpSize, | 43 | .pNext = nullptr, |
| 43 | }; | 44 | .requiredSubgroupSize = GuestWarpSize, |
| 44 | pipeline = device.GetLogical().CreateComputePipeline({ | 45 | }; |
| 45 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, | 46 | pipeline = device.GetLogical().CreateComputePipeline({ |
| 46 | .pNext = nullptr, | 47 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, |
| 47 | .flags = 0, | 48 | .pNext = nullptr, |
| 48 | .stage{ | ||
| 49 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 50 | .pNext = device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr, | ||
| 51 | .flags = 0, | 49 | .flags = 0, |
| 52 | .stage = VK_SHADER_STAGE_COMPUTE_BIT, | 50 | .stage{ |
| 53 | .module = *spv_module, | 51 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, |
| 54 | .pName = "main", | 52 | .pNext = device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr, |
| 55 | .pSpecializationInfo = nullptr, | 53 | .flags = 0, |
| 56 | }, | 54 | .stage = VK_SHADER_STAGE_COMPUTE_BIT, |
| 57 | .layout = *pipeline_layout, | 55 | .module = *spv_module, |
| 58 | .basePipelineHandle = 0, | 56 | .pName = "main", |
| 59 | .basePipelineIndex = 0, | 57 | .pSpecializationInfo = nullptr, |
| 60 | }); | 58 | }, |
| 59 | .layout = *pipeline_layout, | ||
| 60 | .basePipelineHandle = 0, | ||
| 61 | .basePipelineIndex = 0, | ||
| 62 | }); | ||
| 63 | building_flag.test_and_set(); | ||
| 64 | building_flag.notify_all(); | ||
| 65 | }}; | ||
| 66 | if (thread_worker) { | ||
| 67 | thread_worker->QueueWork(std::move(func)); | ||
| 68 | } else { | ||
| 69 | func(); | ||
| 70 | } | ||
| 61 | } | 71 | } |
| 62 | 72 | ||
| 63 | void ComputePipeline::ConfigureBufferCache(BufferCache& buffer_cache) { | 73 | void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, |
| 74 | Tegra::MemoryManager& gpu_memory, VKScheduler& scheduler, | ||
| 75 | BufferCache& buffer_cache, TextureCache& texture_cache) { | ||
| 76 | update_descriptor_queue.Acquire(); | ||
| 77 | |||
| 64 | buffer_cache.SetEnabledComputeUniformBuffers(info.constant_buffer_mask); | 78 | buffer_cache.SetEnabledComputeUniformBuffers(info.constant_buffer_mask); |
| 65 | buffer_cache.UnbindComputeStorageBuffers(); | 79 | buffer_cache.UnbindComputeStorageBuffers(); |
| 66 | size_t index{}; | 80 | size_t ssbo_index{}; |
| 67 | for (const auto& desc : info.storage_buffers_descriptors) { | 81 | for (const auto& desc : info.storage_buffers_descriptors) { |
| 68 | ASSERT(desc.count == 1); | 82 | ASSERT(desc.count == 1); |
| 69 | buffer_cache.BindComputeStorageBuffer(index, desc.cbuf_index, desc.cbuf_offset, true); | 83 | buffer_cache.BindComputeStorageBuffer(ssbo_index, desc.cbuf_index, desc.cbuf_offset, true); |
| 70 | ++index; | 84 | ++ssbo_index; |
| 71 | } | 85 | } |
| 72 | buffer_cache.UpdateComputeBuffers(); | 86 | buffer_cache.UpdateComputeBuffers(); |
| 73 | buffer_cache.BindHostComputeBuffers(); | 87 | buffer_cache.BindHostComputeBuffers(); |
| 74 | } | ||
| 75 | 88 | ||
| 76 | void ComputePipeline::ConfigureTextureCache(Tegra::Engines::KeplerCompute& kepler_compute, | ||
| 77 | Tegra::MemoryManager& gpu_memory, | ||
| 78 | TextureCache& texture_cache) { | ||
| 79 | texture_cache.SynchronizeComputeDescriptors(); | 89 | texture_cache.SynchronizeComputeDescriptors(); |
| 80 | 90 | ||
| 81 | static constexpr size_t max_elements = 64; | 91 | static constexpr size_t max_elements = 64; |
| @@ -103,15 +113,26 @@ void ComputePipeline::ConfigureTextureCache(Tegra::Engines::KeplerCompute& keple | |||
| 103 | const std::span indices_span(image_view_indices.data(), image_view_indices.size()); | 113 | const std::span indices_span(image_view_indices.data(), image_view_indices.size()); |
| 104 | texture_cache.FillComputeImageViews(indices_span, image_view_ids); | 114 | texture_cache.FillComputeImageViews(indices_span, image_view_ids); |
| 105 | 115 | ||
| 106 | size_t index{}; | 116 | size_t image_index{}; |
| 107 | PushImageDescriptors(info, samplers.data(), image_view_ids.data(), texture_cache, | 117 | PushImageDescriptors(info, samplers.data(), image_view_ids.data(), texture_cache, |
| 108 | *update_descriptor_queue, index); | 118 | update_descriptor_queue, image_index); |
| 109 | } | ||
| 110 | 119 | ||
| 111 | VkDescriptorSet ComputePipeline::UpdateDescriptorSet() { | 120 | if (!building_flag.test()) { |
| 121 | // Wait for the pipeline to be built | ||
| 122 | scheduler.Record([this](vk::CommandBuffer) { building_flag.wait(false); }); | ||
| 123 | } | ||
| 124 | scheduler.Record([this](vk::CommandBuffer cmdbuf) { | ||
| 125 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); | ||
| 126 | }); | ||
| 127 | if (!descriptor_set_layout) { | ||
| 128 | return; | ||
| 129 | } | ||
| 112 | const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()}; | 130 | const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()}; |
| 113 | update_descriptor_queue->Send(*descriptor_update_template, descriptor_set); | 131 | update_descriptor_queue.Send(*descriptor_update_template, descriptor_set); |
| 114 | return descriptor_set; | 132 | scheduler.Record([this, descriptor_set](vk::CommandBuffer cmdbuf) { |
| 133 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline_layout, 0, | ||
| 134 | descriptor_set, nullptr); | ||
| 135 | }); | ||
| 115 | } | 136 | } |
| 116 | 137 | ||
| 117 | } // namespace Vulkan | 138 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index e82e5816b..02da504f7 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h | |||
| @@ -4,7 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <atomic> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/thread_worker.h" | ||
| 8 | #include "shader_recompiler/shader_info.h" | 11 | #include "shader_recompiler/shader_info.h" |
| 9 | #include "video_core/memory_manager.h" | 12 | #include "video_core/memory_manager.h" |
| 10 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | 13 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" |
| @@ -16,36 +19,26 @@ | |||
| 16 | namespace Vulkan { | 19 | namespace Vulkan { |
| 17 | 20 | ||
| 18 | class Device; | 21 | class Device; |
| 22 | class VKScheduler; | ||
| 19 | 23 | ||
| 20 | class ComputePipeline { | 24 | class ComputePipeline { |
| 21 | public: | 25 | public: |
| 22 | explicit ComputePipeline() = default; | ||
| 23 | explicit ComputePipeline(const Device& device, VKDescriptorPool& descriptor_pool, | 26 | explicit ComputePipeline(const Device& device, VKDescriptorPool& descriptor_pool, |
| 24 | VKUpdateDescriptorQueue& update_descriptor_queue, | 27 | VKUpdateDescriptorQueue& update_descriptor_queue, |
| 25 | const Shader::Info& info, vk::ShaderModule spv_module); | 28 | Common::ThreadWorker* thread_worker, const Shader::Info& info, |
| 29 | vk::ShaderModule spv_module); | ||
| 26 | 30 | ||
| 27 | ComputePipeline& operator=(ComputePipeline&&) noexcept = default; | 31 | ComputePipeline& operator=(ComputePipeline&&) noexcept = delete; |
| 28 | ComputePipeline(ComputePipeline&&) noexcept = default; | 32 | ComputePipeline(ComputePipeline&&) noexcept = delete; |
| 29 | 33 | ||
| 30 | ComputePipeline& operator=(const ComputePipeline&) = delete; | 34 | ComputePipeline& operator=(const ComputePipeline&) = delete; |
| 31 | ComputePipeline(const ComputePipeline&) = delete; | 35 | ComputePipeline(const ComputePipeline&) = delete; |
| 32 | 36 | ||
| 33 | void ConfigureBufferCache(BufferCache& buffer_cache); | 37 | void Configure(Tegra::Engines::KeplerCompute& kepler_compute, Tegra::MemoryManager& gpu_memory, |
| 34 | void ConfigureTextureCache(Tegra::Engines::KeplerCompute& kepler_compute, | 38 | VKScheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache); |
| 35 | Tegra::MemoryManager& gpu_memory, TextureCache& texture_cache); | ||
| 36 | |||
| 37 | [[nodiscard]] VkDescriptorSet UpdateDescriptorSet(); | ||
| 38 | |||
| 39 | [[nodiscard]] VkPipeline Handle() const noexcept { | ||
| 40 | return *pipeline; | ||
| 41 | } | ||
| 42 | |||
| 43 | [[nodiscard]] VkPipelineLayout PipelineLayout() const noexcept { | ||
| 44 | return *pipeline_layout; | ||
| 45 | } | ||
| 46 | 39 | ||
| 47 | private: | 40 | private: |
| 48 | VKUpdateDescriptorQueue* update_descriptor_queue; | 41 | VKUpdateDescriptorQueue& update_descriptor_queue; |
| 49 | Shader::Info info; | 42 | Shader::Info info; |
| 50 | 43 | ||
| 51 | vk::ShaderModule spv_module; | 44 | vk::ShaderModule spv_module; |
| @@ -54,6 +47,7 @@ private: | |||
| 54 | vk::PipelineLayout pipeline_layout; | 47 | vk::PipelineLayout pipeline_layout; |
| 55 | vk::DescriptorUpdateTemplateKHR descriptor_update_template; | 48 | vk::DescriptorUpdateTemplateKHR descriptor_update_template; |
| 56 | vk::Pipeline pipeline; | 49 | vk::Pipeline pipeline; |
| 50 | std::atomic_flag building_flag{}; | ||
| 57 | }; | 51 | }; |
| 58 | 52 | ||
| 59 | } // namespace Vulkan | 53 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 278509bf0..ddc08b8c4 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -112,13 +112,15 @@ GraphicsPipeline::GraphicsPipeline(Tegra::Engines::Maxwell3D& maxwell3d_, | |||
| 112 | BufferCache& buffer_cache_, TextureCache& texture_cache_, | 112 | BufferCache& buffer_cache_, TextureCache& texture_cache_, |
| 113 | const Device& device, VKDescriptorPool& descriptor_pool, | 113 | const Device& device, VKDescriptorPool& descriptor_pool, |
| 114 | VKUpdateDescriptorQueue& update_descriptor_queue_, | 114 | VKUpdateDescriptorQueue& update_descriptor_queue_, |
| 115 | Common::ThreadWorker* worker_thread, | ||
| 115 | RenderPassCache& render_pass_cache, | 116 | RenderPassCache& render_pass_cache, |
| 116 | const FixedPipelineState& state, | 117 | const FixedPipelineState& state_, |
| 117 | std::array<vk::ShaderModule, NUM_STAGES> stages, | 118 | std::array<vk::ShaderModule, NUM_STAGES> stages, |
| 118 | const std::array<const Shader::Info*, NUM_STAGES>& infos) | 119 | const std::array<const Shader::Info*, NUM_STAGES>& infos) |
| 119 | : maxwell3d{&maxwell3d_}, gpu_memory{&gpu_memory_}, texture_cache{&texture_cache_}, | 120 | : maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, texture_cache{texture_cache_}, |
| 120 | buffer_cache{&buffer_cache_}, scheduler{&scheduler_}, | 121 | buffer_cache{buffer_cache_}, scheduler{scheduler_}, |
| 121 | update_descriptor_queue{&update_descriptor_queue_}, spv_modules{std::move(stages)} { | 122 | update_descriptor_queue{update_descriptor_queue_}, state{state_}, spv_modules{ |
| 123 | std::move(stages)} { | ||
| 122 | std::ranges::transform(infos, stage_infos.begin(), | 124 | std::ranges::transform(infos, stage_infos.begin(), |
| 123 | [](const Shader::Info* info) { return info ? *info : Shader::Info{}; }); | 125 | [](const Shader::Info* info) { return info ? *info : Shader::Info{}; }); |
| 124 | 126 | ||
| @@ -128,8 +130,17 @@ GraphicsPipeline::GraphicsPipeline(Tegra::Engines::Maxwell3D& maxwell3d_, | |||
| 128 | descriptor_update_template = std::move(tuple.descriptor_update_template); | 130 | descriptor_update_template = std::move(tuple.descriptor_update_template); |
| 129 | descriptor_allocator = DescriptorAllocator(descriptor_pool, *descriptor_set_layout); | 131 | descriptor_allocator = DescriptorAllocator(descriptor_pool, *descriptor_set_layout); |
| 130 | 132 | ||
| 131 | const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(state))}; | 133 | auto func{[this, &device, &render_pass_cache] { |
| 132 | MakePipeline(device, state, render_pass); | 134 | const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(state))}; |
| 135 | MakePipeline(device, render_pass); | ||
| 136 | building_flag.test_and_set(); | ||
| 137 | building_flag.notify_all(); | ||
| 138 | }}; | ||
| 139 | if (worker_thread) { | ||
| 140 | worker_thread->QueueWork(std::move(func)); | ||
| 141 | } else { | ||
| 142 | func(); | ||
| 143 | } | ||
| 133 | } | 144 | } |
| 134 | 145 | ||
| 135 | void GraphicsPipeline::Configure(bool is_indexed) { | 146 | void GraphicsPipeline::Configure(bool is_indexed) { |
| @@ -138,67 +149,72 @@ void GraphicsPipeline::Configure(bool is_indexed) { | |||
| 138 | static_vector<u32, max_images_elements> image_view_indices; | 149 | static_vector<u32, max_images_elements> image_view_indices; |
| 139 | static_vector<VkSampler, max_images_elements> samplers; | 150 | static_vector<VkSampler, max_images_elements> samplers; |
| 140 | 151 | ||
| 141 | texture_cache->SynchronizeGraphicsDescriptors(); | 152 | texture_cache.SynchronizeGraphicsDescriptors(); |
| 142 | 153 | ||
| 143 | const auto& regs{maxwell3d->regs}; | 154 | const auto& regs{maxwell3d.regs}; |
| 144 | const bool via_header_index{regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex}; | 155 | const bool via_header_index{regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex}; |
| 145 | for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { | 156 | for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { |
| 146 | const Shader::Info& info{stage_infos[stage]}; | 157 | const Shader::Info& info{stage_infos[stage]}; |
| 147 | buffer_cache->SetEnabledUniformBuffers(stage, info.constant_buffer_mask); | 158 | buffer_cache.SetEnabledUniformBuffers(stage, info.constant_buffer_mask); |
| 148 | buffer_cache->UnbindGraphicsStorageBuffers(stage); | 159 | buffer_cache.UnbindGraphicsStorageBuffers(stage); |
| 149 | size_t index{}; | 160 | size_t index{}; |
| 150 | for (const auto& desc : info.storage_buffers_descriptors) { | 161 | for (const auto& desc : info.storage_buffers_descriptors) { |
| 151 | ASSERT(desc.count == 1); | 162 | ASSERT(desc.count == 1); |
| 152 | buffer_cache->BindGraphicsStorageBuffer(stage, index, desc.cbuf_index, desc.cbuf_offset, | 163 | buffer_cache.BindGraphicsStorageBuffer(stage, index, desc.cbuf_index, desc.cbuf_offset, |
| 153 | true); | 164 | true); |
| 154 | ++index; | 165 | ++index; |
| 155 | } | 166 | } |
| 156 | const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers}; | 167 | const auto& cbufs{maxwell3d.state.shader_stages[stage].const_buffers}; |
| 157 | for (const auto& desc : info.texture_descriptors) { | 168 | for (const auto& desc : info.texture_descriptors) { |
| 158 | const u32 cbuf_index{desc.cbuf_index}; | 169 | const u32 cbuf_index{desc.cbuf_index}; |
| 159 | const u32 cbuf_offset{desc.cbuf_offset}; | 170 | const u32 cbuf_offset{desc.cbuf_offset}; |
| 160 | ASSERT(cbufs[cbuf_index].enabled); | 171 | ASSERT(cbufs[cbuf_index].enabled); |
| 161 | const GPUVAddr addr{cbufs[cbuf_index].address + cbuf_offset}; | 172 | const GPUVAddr addr{cbufs[cbuf_index].address + cbuf_offset}; |
| 162 | const u32 raw_handle{gpu_memory->Read<u32>(addr)}; | 173 | const u32 raw_handle{gpu_memory.Read<u32>(addr)}; |
| 163 | 174 | ||
| 164 | const TextureHandle handle(raw_handle, via_header_index); | 175 | const TextureHandle handle(raw_handle, via_header_index); |
| 165 | image_view_indices.push_back(handle.image); | 176 | image_view_indices.push_back(handle.image); |
| 166 | 177 | ||
| 167 | Sampler* const sampler{texture_cache->GetGraphicsSampler(handle.sampler)}; | 178 | Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.sampler)}; |
| 168 | samplers.push_back(sampler->Handle()); | 179 | samplers.push_back(sampler->Handle()); |
| 169 | } | 180 | } |
| 170 | } | 181 | } |
| 171 | const std::span indices_span(image_view_indices.data(), image_view_indices.size()); | 182 | const std::span indices_span(image_view_indices.data(), image_view_indices.size()); |
| 172 | buffer_cache->UpdateGraphicsBuffers(is_indexed); | 183 | buffer_cache.UpdateGraphicsBuffers(is_indexed); |
| 173 | texture_cache->FillGraphicsImageViews(indices_span, image_view_ids); | 184 | texture_cache.FillGraphicsImageViews(indices_span, image_view_ids); |
| 174 | 185 | ||
| 175 | buffer_cache->BindHostGeometryBuffers(is_indexed); | 186 | buffer_cache.BindHostGeometryBuffers(is_indexed); |
| 176 | 187 | ||
| 177 | size_t index{}; | 188 | size_t index{}; |
| 178 | for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { | 189 | for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { |
| 179 | buffer_cache->BindHostStageBuffers(stage); | 190 | buffer_cache.BindHostStageBuffers(stage); |
| 180 | PushImageDescriptors(stage_infos[stage], samplers.data(), image_view_ids.data(), | 191 | PushImageDescriptors(stage_infos[stage], samplers.data(), image_view_ids.data(), |
| 181 | *texture_cache, *update_descriptor_queue, index); | 192 | texture_cache, update_descriptor_queue, index); |
| 182 | } | 193 | } |
| 183 | texture_cache->UpdateRenderTargets(false); | 194 | texture_cache.UpdateRenderTargets(false); |
| 184 | scheduler->RequestRenderpass(texture_cache->GetFramebuffer()); | 195 | scheduler.RequestRenderpass(texture_cache.GetFramebuffer()); |
| 185 | |||
| 186 | scheduler->BindGraphicsPipeline(*pipeline); | ||
| 187 | 196 | ||
| 197 | if (!building_flag.test()) { | ||
| 198 | scheduler.Record([this](vk::CommandBuffer) { building_flag.wait(false); }); | ||
| 199 | } | ||
| 200 | if (scheduler.UpdateGraphicsPipeline(this)) { | ||
| 201 | scheduler.Record([this](vk::CommandBuffer cmdbuf) { | ||
| 202 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); | ||
| 203 | }); | ||
| 204 | } | ||
| 188 | if (!descriptor_set_layout) { | 205 | if (!descriptor_set_layout) { |
| 189 | return; | 206 | return; |
| 190 | } | 207 | } |
| 191 | const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()}; | 208 | const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()}; |
| 192 | update_descriptor_queue->Send(*descriptor_update_template, descriptor_set); | 209 | update_descriptor_queue.Send(*descriptor_update_template, descriptor_set); |
| 193 | 210 | ||
| 194 | scheduler->Record([descriptor_set, layout = *pipeline_layout](vk::CommandBuffer cmdbuf) { | 211 | scheduler.Record([descriptor_set, layout = *pipeline_layout](vk::CommandBuffer cmdbuf) { |
| 195 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, | 212 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, |
| 196 | nullptr); | 213 | nullptr); |
| 197 | }); | 214 | }); |
| 198 | } | 215 | } |
| 199 | 216 | ||
| 200 | void GraphicsPipeline::MakePipeline(const Device& device, const FixedPipelineState& state, | 217 | void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pass) { |
| 201 | VkRenderPass render_pass) { | ||
| 202 | FixedPipelineState::DynamicState dynamic{}; | 218 | FixedPipelineState::DynamicState dynamic{}; |
| 203 | if (!device.IsExtExtendedDynamicStateSupported()) { | 219 | if (!device.IsExtExtendedDynamicStateSupported()) { |
| 204 | dynamic = state.dynamic_state; | 220 | dynamic = state.dynamic_state; |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index ba1d34a83..4e0583157 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h | |||
| @@ -5,13 +5,15 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <atomic> | ||
| 8 | 9 | ||
| 10 | #include "common/thread_worker.h" | ||
| 9 | #include "shader_recompiler/shader_info.h" | 11 | #include "shader_recompiler/shader_info.h" |
| 10 | #include "video_core/engines/maxwell_3d.h" | 12 | #include "video_core/engines/maxwell_3d.h" |
| 11 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 13 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| 14 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | ||
| 12 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 15 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 13 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | 16 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 14 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | ||
| 15 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 17 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 16 | 18 | ||
| 17 | namespace Vulkan { | 19 | namespace Vulkan { |
| @@ -25,34 +27,34 @@ class GraphicsPipeline { | |||
| 25 | static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; | 27 | static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; |
| 26 | 28 | ||
| 27 | public: | 29 | public: |
| 28 | explicit GraphicsPipeline() = default; | ||
| 29 | explicit GraphicsPipeline(Tegra::Engines::Maxwell3D& maxwell3d, | 30 | explicit GraphicsPipeline(Tegra::Engines::Maxwell3D& maxwell3d, |
| 30 | Tegra::MemoryManager& gpu_memory, VKScheduler& scheduler, | 31 | Tegra::MemoryManager& gpu_memory, VKScheduler& scheduler, |
| 31 | BufferCache& buffer_cache, | 32 | BufferCache& buffer_cache, TextureCache& texture_cache, |
| 32 | TextureCache& texture_cache, const Device& device, VKDescriptorPool& descriptor_pool, | 33 | const Device& device, VKDescriptorPool& descriptor_pool, |
| 33 | VKUpdateDescriptorQueue& update_descriptor_queue, | 34 | VKUpdateDescriptorQueue& update_descriptor_queue, |
| 35 | Common::ThreadWorker* worker_thread, | ||
| 34 | RenderPassCache& render_pass_cache, const FixedPipelineState& state, | 36 | RenderPassCache& render_pass_cache, const FixedPipelineState& state, |
| 35 | std::array<vk::ShaderModule, NUM_STAGES> stages, | 37 | std::array<vk::ShaderModule, NUM_STAGES> stages, |
| 36 | const std::array<const Shader::Info*, NUM_STAGES>& infos); | 38 | const std::array<const Shader::Info*, NUM_STAGES>& infos); |
| 37 | 39 | ||
| 38 | void Configure(bool is_indexed); | 40 | void Configure(bool is_indexed); |
| 39 | 41 | ||
| 40 | GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = default; | 42 | GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete; |
| 41 | GraphicsPipeline(GraphicsPipeline&&) noexcept = default; | 43 | GraphicsPipeline(GraphicsPipeline&&) noexcept = delete; |
| 42 | 44 | ||
| 43 | GraphicsPipeline& operator=(const GraphicsPipeline&) = delete; | 45 | GraphicsPipeline& operator=(const GraphicsPipeline&) = delete; |
| 44 | GraphicsPipeline(const GraphicsPipeline&) = delete; | 46 | GraphicsPipeline(const GraphicsPipeline&) = delete; |
| 45 | 47 | ||
| 46 | private: | 48 | private: |
| 47 | void MakePipeline(const Device& device, const FixedPipelineState& state, | 49 | void MakePipeline(const Device& device, VkRenderPass render_pass); |
| 48 | VkRenderPass render_pass); | ||
| 49 | 50 | ||
| 50 | Tegra::Engines::Maxwell3D* maxwell3d{}; | 51 | Tegra::Engines::Maxwell3D& maxwell3d; |
| 51 | Tegra::MemoryManager* gpu_memory{}; | 52 | Tegra::MemoryManager& gpu_memory; |
| 52 | TextureCache* texture_cache{}; | 53 | TextureCache& texture_cache; |
| 53 | BufferCache* buffer_cache{}; | 54 | BufferCache& buffer_cache; |
| 54 | VKScheduler* scheduler{}; | 55 | VKScheduler& scheduler; |
| 55 | VKUpdateDescriptorQueue* update_descriptor_queue{}; | 56 | VKUpdateDescriptorQueue& update_descriptor_queue; |
| 57 | const FixedPipelineState state; | ||
| 56 | 58 | ||
| 57 | std::array<vk::ShaderModule, NUM_STAGES> spv_modules; | 59 | std::array<vk::ShaderModule, NUM_STAGES> spv_modules; |
| 58 | std::array<Shader::Info, NUM_STAGES> stage_infos; | 60 | std::array<Shader::Info, NUM_STAGES> stage_infos; |
| @@ -61,6 +63,7 @@ private: | |||
| 61 | vk::PipelineLayout pipeline_layout; | 63 | vk::PipelineLayout pipeline_layout; |
| 62 | vk::DescriptorUpdateTemplateKHR descriptor_update_template; | 64 | vk::DescriptorUpdateTemplateKHR descriptor_update_template; |
| 63 | vk::Pipeline pipeline; | 65 | vk::Pipeline pipeline; |
| 66 | std::atomic_flag building_flag{}; | ||
| 64 | }; | 67 | }; |
| 65 | 68 | ||
| 66 | } // namespace Vulkan | 69 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 30a707599..e3d9debf4 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -518,9 +518,8 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading | |||
| 518 | } | 518 | } |
| 519 | pipeline_cache_filename = fmt::format("{}/{:016x}.bin", transferable_dir, title_id); | 519 | pipeline_cache_filename = fmt::format("{}/{:016x}.bin", transferable_dir, title_id); |
| 520 | 520 | ||
| 521 | Common::ThreadWorker worker(11, "PipelineBuilder"); | ||
| 522 | std::mutex cache_mutex; | ||
| 523 | struct { | 521 | struct { |
| 522 | std::mutex mutex; | ||
| 524 | size_t total{0}; | 523 | size_t total{0}; |
| 525 | size_t built{0}; | 524 | size_t built{0}; |
| 526 | bool has_loaded{false}; | 525 | bool has_loaded{false}; |
| @@ -542,51 +541,53 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading | |||
| 542 | } | 541 | } |
| 543 | u32 num_envs{}; | 542 | u32 num_envs{}; |
| 544 | file.read(reinterpret_cast<char*>(&num_envs), sizeof(num_envs)); | 543 | file.read(reinterpret_cast<char*>(&num_envs), sizeof(num_envs)); |
| 545 | auto envs{std::make_shared<std::vector<FileEnvironment>>(num_envs)}; | 544 | std::vector<FileEnvironment> envs(num_envs); |
| 546 | for (FileEnvironment& env : *envs) { | 545 | for (FileEnvironment& env : envs) { |
| 547 | env.Deserialize(file); | 546 | env.Deserialize(file); |
| 548 | } | 547 | } |
| 549 | if (envs->front().ShaderStage() == Shader::Stage::Compute) { | 548 | if (envs.front().ShaderStage() == Shader::Stage::Compute) { |
| 550 | ComputePipelineCacheKey key; | 549 | ComputePipelineCacheKey key; |
| 551 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); | 550 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); |
| 552 | 551 | ||
| 553 | worker.QueueWork([this, key, envs, &cache_mutex, &state, &callback] { | 552 | workers.QueueWork([this, key, envs = std::move(envs), &state, &callback]() mutable { |
| 554 | ShaderPools pools; | 553 | ShaderPools pools; |
| 555 | ComputePipeline pipeline{CreateComputePipeline(pools, key, envs->front())}; | 554 | auto pipeline{CreateComputePipeline(pools, key, envs.front(), false)}; |
| 556 | 555 | ||
| 557 | std::lock_guard lock{cache_mutex}; | 556 | std::lock_guard lock{state.mutex}; |
| 558 | compute_cache.emplace(key, std::move(pipeline)); | 557 | compute_cache.emplace(key, std::move(pipeline)); |
| 558 | ++state.built; | ||
| 559 | if (state.has_loaded) { | 559 | if (state.has_loaded) { |
| 560 | callback(VideoCore::LoadCallbackStage::Build, ++state.built, state.total); | 560 | callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); |
| 561 | } | 561 | } |
| 562 | }); | 562 | }); |
| 563 | } else { | 563 | } else { |
| 564 | GraphicsPipelineCacheKey key; | 564 | GraphicsPipelineCacheKey key; |
| 565 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); | 565 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); |
| 566 | 566 | ||
| 567 | worker.QueueWork([this, key, envs, &cache_mutex, &state, &callback] { | 567 | workers.QueueWork([this, key, envs = std::move(envs), &state, &callback]() mutable { |
| 568 | ShaderPools pools; | 568 | ShaderPools pools; |
| 569 | boost::container::static_vector<Shader::Environment*, 5> env_ptrs; | 569 | boost::container::static_vector<Shader::Environment*, 5> env_ptrs; |
| 570 | for (auto& env : *envs) { | 570 | for (auto& env : envs) { |
| 571 | env_ptrs.push_back(&env); | 571 | env_ptrs.push_back(&env); |
| 572 | } | 572 | } |
| 573 | GraphicsPipeline pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs))}; | 573 | auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs), false)}; |
| 574 | 574 | ||
| 575 | std::lock_guard lock{cache_mutex}; | 575 | std::lock_guard lock{state.mutex}; |
| 576 | graphics_cache.emplace(key, std::move(pipeline)); | 576 | graphics_cache.emplace(key, std::move(pipeline)); |
| 577 | ++state.built; | ||
| 577 | if (state.has_loaded) { | 578 | if (state.has_loaded) { |
| 578 | callback(VideoCore::LoadCallbackStage::Build, ++state.built, state.total); | 579 | callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); |
| 579 | } | 580 | } |
| 580 | }); | 581 | }); |
| 581 | } | 582 | } |
| 582 | ++state.total; | 583 | ++state.total; |
| 583 | } | 584 | } |
| 584 | { | 585 | { |
| 585 | std::lock_guard lock{cache_mutex}; | 586 | std::lock_guard lock{state.mutex}; |
| 586 | callback(VideoCore::LoadCallbackStage::Build, 0, state.total); | 587 | callback(VideoCore::LoadCallbackStage::Build, 0, state.total); |
| 587 | state.has_loaded = true; | 588 | state.has_loaded = true; |
| 588 | } | 589 | } |
| 589 | worker.WaitForRequests(); | 590 | workers.WaitForRequests(); |
| 590 | } | 591 | } |
| 591 | 592 | ||
| 592 | size_t ComputePipelineCacheKey::Hash() const noexcept { | 593 | size_t ComputePipelineCacheKey::Hash() const noexcept { |
| @@ -619,7 +620,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_, | |||
| 619 | kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_}, | 620 | kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_}, |
| 620 | scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, | 621 | scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, |
| 621 | update_descriptor_queue{update_descriptor_queue_}, render_pass_cache{render_pass_cache_}, | 622 | update_descriptor_queue{update_descriptor_queue_}, render_pass_cache{render_pass_cache_}, |
| 622 | buffer_cache{buffer_cache_}, texture_cache{texture_cache_} { | 623 | buffer_cache{buffer_cache_}, texture_cache{texture_cache_}, workers(11, "PipelineBuilder") { |
| 623 | const auto& float_control{device.FloatControlProperties()}; | 624 | const auto& float_control{device.FloatControlProperties()}; |
| 624 | const VkDriverIdKHR driver_id{device.GetDriverID()}; | 625 | const VkDriverIdKHR driver_id{device.GetDriverID()}; |
| 625 | base_profile = Shader::Profile{ | 626 | base_profile = Shader::Profile{ |
| @@ -662,10 +663,10 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() { | |||
| 662 | const auto [pair, is_new]{graphics_cache.try_emplace(graphics_key)}; | 663 | const auto [pair, is_new]{graphics_cache.try_emplace(graphics_key)}; |
| 663 | auto& pipeline{pair->second}; | 664 | auto& pipeline{pair->second}; |
| 664 | if (!is_new) { | 665 | if (!is_new) { |
| 665 | return &pipeline; | 666 | return pipeline.get(); |
| 666 | } | 667 | } |
| 667 | pipeline = CreateGraphicsPipeline(); | 668 | pipeline = CreateGraphicsPipeline(); |
| 668 | return &pipeline; | 669 | return pipeline.get(); |
| 669 | } | 670 | } |
| 670 | 671 | ||
| 671 | ComputePipeline* PipelineCache::CurrentComputePipeline() { | 672 | ComputePipeline* PipelineCache::CurrentComputePipeline() { |
| @@ -691,10 +692,10 @@ ComputePipeline* PipelineCache::CurrentComputePipeline() { | |||
| 691 | const auto [pair, is_new]{compute_cache.try_emplace(key)}; | 692 | const auto [pair, is_new]{compute_cache.try_emplace(key)}; |
| 692 | auto& pipeline{pair->second}; | 693 | auto& pipeline{pair->second}; |
| 693 | if (!is_new) { | 694 | if (!is_new) { |
| 694 | return &pipeline; | 695 | return pipeline.get(); |
| 695 | } | 696 | } |
| 696 | pipeline = CreateComputePipeline(key, shader); | 697 | pipeline = CreateComputePipeline(key, shader); |
| 697 | return &pipeline; | 698 | return pipeline.get(); |
| 698 | } | 699 | } |
| 699 | 700 | ||
| 700 | bool PipelineCache::RefreshStages() { | 701 | bool PipelineCache::RefreshStages() { |
| @@ -743,9 +744,9 @@ const ShaderInfo* PipelineCache::MakeShaderInfo(GenericEnvironment& env, VAddr c | |||
| 743 | return result; | 744 | return result; |
| 744 | } | 745 | } |
| 745 | 746 | ||
| 746 | GraphicsPipeline PipelineCache::CreateGraphicsPipeline(ShaderPools& pools, | 747 | std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( |
| 747 | const GraphicsPipelineCacheKey& key, | 748 | ShaderPools& pools, const GraphicsPipelineCacheKey& key, |
| 748 | std::span<Shader::Environment* const> envs) { | 749 | std::span<Shader::Environment* const> envs, bool build_in_parallel) { |
| 749 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); | 750 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); |
| 750 | size_t env_index{0}; | 751 | size_t env_index{0}; |
| 751 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; | 752 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; |
| @@ -783,12 +784,14 @@ GraphicsPipeline PipelineCache::CreateGraphicsPipeline(ShaderPools& pools, | |||
| 783 | modules[stage_index].SetObjectNameEXT(name.c_str()); | 784 | modules[stage_index].SetObjectNameEXT(name.c_str()); |
| 784 | } | 785 | } |
| 785 | } | 786 | } |
| 786 | return GraphicsPipeline(maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, device, | 787 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; |
| 787 | descriptor_pool, update_descriptor_queue, render_pass_cache, key.state, | 788 | return std::make_unique<GraphicsPipeline>( |
| 788 | std::move(modules), infos); | 789 | maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, device, descriptor_pool, |
| 790 | update_descriptor_queue, thread_worker, render_pass_cache, key.state, std::move(modules), | ||
| 791 | infos); | ||
| 789 | } | 792 | } |
| 790 | 793 | ||
| 791 | GraphicsPipeline PipelineCache::CreateGraphicsPipeline() { | 794 | std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() { |
| 792 | main_pools.ReleaseContents(); | 795 | main_pools.ReleaseContents(); |
| 793 | 796 | ||
| 794 | std::array<GraphicsEnvironment, Maxwell::MaxShaderProgram> graphics_envs; | 797 | std::array<GraphicsEnvironment, Maxwell::MaxShaderProgram> graphics_envs; |
| @@ -809,22 +812,22 @@ GraphicsPipeline PipelineCache::CreateGraphicsPipeline() { | |||
| 809 | generic_envs.push_back(&env); | 812 | generic_envs.push_back(&env); |
| 810 | envs.push_back(&env); | 813 | envs.push_back(&env); |
| 811 | } | 814 | } |
| 812 | GraphicsPipeline pipeline{CreateGraphicsPipeline(main_pools, graphics_key, MakeSpan(envs))}; | 815 | auto pipeline{CreateGraphicsPipeline(main_pools, graphics_key, MakeSpan(envs), true)}; |
| 813 | if (!pipeline_cache_filename.empty()) { | 816 | if (!pipeline_cache_filename.empty()) { |
| 814 | SerializePipeline(graphics_key, generic_envs, pipeline_cache_filename); | 817 | SerializePipeline(graphics_key, generic_envs, pipeline_cache_filename); |
| 815 | } | 818 | } |
| 816 | return pipeline; | 819 | return pipeline; |
| 817 | } | 820 | } |
| 818 | 821 | ||
| 819 | ComputePipeline PipelineCache::CreateComputePipeline(const ComputePipelineCacheKey& key, | 822 | std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( |
| 820 | const ShaderInfo* shader) { | 823 | const ComputePipelineCacheKey& key, const ShaderInfo* shader) { |
| 821 | const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()}; | 824 | const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()}; |
| 822 | const auto& qmd{kepler_compute.launch_description}; | 825 | const auto& qmd{kepler_compute.launch_description}; |
| 823 | ComputeEnvironment env{kepler_compute, gpu_memory, program_base, qmd.program_start}; | 826 | ComputeEnvironment env{kepler_compute, gpu_memory, program_base, qmd.program_start}; |
| 824 | env.SetCachedSize(shader->size_bytes); | 827 | env.SetCachedSize(shader->size_bytes); |
| 825 | 828 | ||
| 826 | main_pools.ReleaseContents(); | 829 | main_pools.ReleaseContents(); |
| 827 | ComputePipeline pipeline{CreateComputePipeline(main_pools, key, env)}; | 830 | auto pipeline{CreateComputePipeline(main_pools, key, env, true)}; |
| 828 | if (!pipeline_cache_filename.empty()) { | 831 | if (!pipeline_cache_filename.empty()) { |
| 829 | SerializePipeline(key, std::array<const GenericEnvironment*, 1>{&env}, | 832 | SerializePipeline(key, std::array<const GenericEnvironment*, 1>{&env}, |
| 830 | pipeline_cache_filename); | 833 | pipeline_cache_filename); |
| @@ -832,9 +835,9 @@ ComputePipeline PipelineCache::CreateComputePipeline(const ComputePipelineCacheK | |||
| 832 | return pipeline; | 835 | return pipeline; |
| 833 | } | 836 | } |
| 834 | 837 | ||
| 835 | ComputePipeline PipelineCache::CreateComputePipeline(ShaderPools& pools, | 838 | std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( |
| 836 | const ComputePipelineCacheKey& key, | 839 | ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env, |
| 837 | Shader::Environment& env) const { | 840 | bool build_in_parallel) { |
| 838 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); | 841 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); |
| 839 | 842 | ||
| 840 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; | 843 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; |
| @@ -846,8 +849,9 @@ ComputePipeline PipelineCache::CreateComputePipeline(ShaderPools& pools, | |||
| 846 | const auto name{fmt::format("{:016x}{:016x}", key.unique_hash[0], key.unique_hash[1])}; | 849 | const auto name{fmt::format("{:016x}{:016x}", key.unique_hash[0], key.unique_hash[1])}; |
| 847 | spv_module.SetObjectNameEXT(name.c_str()); | 850 | spv_module.SetObjectNameEXT(name.c_str()); |
| 848 | } | 851 | } |
| 849 | return ComputePipeline{device, descriptor_pool, update_descriptor_queue, program.info, | 852 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; |
| 850 | std::move(spv_module)}; | 853 | return std::make_unique<ComputePipeline>(device, descriptor_pool, update_descriptor_queue, |
| 854 | thread_worker, program.info, std::move(spv_module)); | ||
| 851 | } | 855 | } |
| 852 | 856 | ||
| 853 | static Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribute& attr) { | 857 | static Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribute& attr) { |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index b55e14189..609f00898 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <vector> | 14 | #include <vector> |
| 15 | 15 | ||
| 16 | #include "common/common_types.h" | 16 | #include "common/common_types.h" |
| 17 | #include "common/thread_worker.h" | ||
| 17 | #include "shader_recompiler/frontend/ir/basic_block.h" | 18 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 18 | #include "shader_recompiler/frontend/ir/microinstruction.h" | 19 | #include "shader_recompiler/frontend/ir/microinstruction.h" |
| 19 | #include "shader_recompiler/frontend/maxwell/control_flow.h" | 20 | #include "shader_recompiler/frontend/maxwell/control_flow.h" |
| @@ -145,16 +146,19 @@ private: | |||
| 145 | 146 | ||
| 146 | const ShaderInfo* MakeShaderInfo(GenericEnvironment& env, VAddr cpu_addr); | 147 | const ShaderInfo* MakeShaderInfo(GenericEnvironment& env, VAddr cpu_addr); |
| 147 | 148 | ||
| 148 | GraphicsPipeline CreateGraphicsPipeline(); | 149 | std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline(); |
| 149 | 150 | ||
| 150 | GraphicsPipeline CreateGraphicsPipeline(ShaderPools& pools, const GraphicsPipelineCacheKey& key, | 151 | std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline( |
| 151 | std::span<Shader::Environment* const> envs); | 152 | ShaderPools& pools, const GraphicsPipelineCacheKey& key, |
| 153 | std::span<Shader::Environment* const> envs, bool build_in_parallel); | ||
| 152 | 154 | ||
| 153 | ComputePipeline CreateComputePipeline(const ComputePipelineCacheKey& key, | 155 | std::unique_ptr<ComputePipeline> CreateComputePipeline(const ComputePipelineCacheKey& key, |
| 154 | const ShaderInfo* shader); | 156 | const ShaderInfo* shader); |
| 155 | 157 | ||
| 156 | ComputePipeline CreateComputePipeline(ShaderPools& pools, const ComputePipelineCacheKey& key, | 158 | std::unique_ptr<ComputePipeline> CreateComputePipeline(ShaderPools& pools, |
| 157 | Shader::Environment& env) const; | 159 | const ComputePipelineCacheKey& key, |
| 160 | Shader::Environment& env, | ||
| 161 | bool build_in_parallel); | ||
| 158 | 162 | ||
| 159 | Shader::Profile MakeProfile(const GraphicsPipelineCacheKey& key, Shader::Stage stage); | 163 | Shader::Profile MakeProfile(const GraphicsPipelineCacheKey& key, Shader::Stage stage); |
| 160 | 164 | ||
| @@ -174,13 +178,15 @@ private: | |||
| 174 | GraphicsPipelineCacheKey graphics_key{}; | 178 | GraphicsPipelineCacheKey graphics_key{}; |
| 175 | std::array<const ShaderInfo*, 6> shader_infos{}; | 179 | std::array<const ShaderInfo*, 6> shader_infos{}; |
| 176 | 180 | ||
| 177 | std::unordered_map<ComputePipelineCacheKey, ComputePipeline> compute_cache; | 181 | std::unordered_map<ComputePipelineCacheKey, std::unique_ptr<ComputePipeline>> compute_cache; |
| 178 | std::unordered_map<GraphicsPipelineCacheKey, GraphicsPipeline> graphics_cache; | 182 | std::unordered_map<GraphicsPipelineCacheKey, std::unique_ptr<GraphicsPipeline>> graphics_cache; |
| 179 | 183 | ||
| 180 | ShaderPools main_pools; | 184 | ShaderPools main_pools; |
| 181 | 185 | ||
| 182 | Shader::Profile base_profile; | 186 | Shader::Profile base_profile; |
| 183 | std::string pipeline_cache_filename; | 187 | std::string pipeline_cache_filename; |
| 188 | |||
| 189 | Common::ThreadWorker workers; | ||
| 184 | }; | 190 | }; |
| 185 | 191 | ||
| 186 | } // namespace Vulkan | 192 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index d7d9927dd..f0bd4b8af 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -276,22 +276,11 @@ void RasterizerVulkan::DispatchCompute() { | |||
| 276 | return; | 276 | return; |
| 277 | } | 277 | } |
| 278 | std::scoped_lock lock{texture_cache.mutex, buffer_cache.mutex}; | 278 | std::scoped_lock lock{texture_cache.mutex, buffer_cache.mutex}; |
| 279 | update_descriptor_queue.Acquire(); | 279 | pipeline->Configure(kepler_compute, gpu_memory, scheduler, buffer_cache, texture_cache); |
| 280 | pipeline->ConfigureBufferCache(buffer_cache); | ||
| 281 | pipeline->ConfigureTextureCache(kepler_compute, gpu_memory, texture_cache); | ||
| 282 | const VkDescriptorSet descriptor_set{pipeline->UpdateDescriptorSet()}; | ||
| 283 | 280 | ||
| 284 | const auto& qmd{kepler_compute.launch_description}; | 281 | const auto& qmd{kepler_compute.launch_description}; |
| 285 | const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z}; | 282 | const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z}; |
| 286 | const VkPipeline pipeline_handle{pipeline->Handle()}; | 283 | scheduler.Record([dim](vk::CommandBuffer cmdbuf) { cmdbuf.Dispatch(dim[0], dim[1], dim[2]); }); |
| 287 | const VkPipelineLayout pipeline_layout{pipeline->PipelineLayout()}; | ||
| 288 | scheduler.Record( | ||
| 289 | [pipeline_handle, pipeline_layout, dim, descriptor_set](vk::CommandBuffer cmdbuf) { | ||
| 290 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_handle); | ||
| 291 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, | ||
| 292 | descriptor_set, nullptr); | ||
| 293 | cmdbuf.Dispatch(dim[0], dim[1], dim[2]); | ||
| 294 | }); | ||
| 295 | } | 284 | } |
| 296 | 285 | ||
| 297 | void RasterizerVulkan::ResetCounter(VideoCore::QueryType type) { | 286 | void RasterizerVulkan::ResetCounter(VideoCore::QueryType type) { |
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index f35c120b0..25a4933e5 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp | |||
| @@ -124,18 +124,16 @@ void VKScheduler::RequestOutsideRenderPassOperationContext() { | |||
| 124 | EndRenderPass(); | 124 | EndRenderPass(); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | void VKScheduler::BindGraphicsPipeline(VkPipeline pipeline) { | 127 | bool VKScheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) { |
| 128 | if (state.graphics_pipeline == pipeline) { | 128 | if (state.graphics_pipeline == pipeline) { |
| 129 | return; | 129 | return false; |
| 130 | } | 130 | } |
| 131 | state.graphics_pipeline = pipeline; | 131 | state.graphics_pipeline = pipeline; |
| 132 | Record([pipeline](vk::CommandBuffer cmdbuf) { | 132 | return true; |
| 133 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||
| 134 | }); | ||
| 135 | } | 133 | } |
| 136 | 134 | ||
| 137 | void VKScheduler::WorkerThread() { | 135 | void VKScheduler::WorkerThread() { |
| 138 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); | 136 | Common::SetCurrentThreadName("yuzu:VulkanWorker"); |
| 139 | std::unique_lock lock{mutex}; | 137 | std::unique_lock lock{mutex}; |
| 140 | do { | 138 | do { |
| 141 | cv.wait(lock, [this] { return !chunk_queue.Empty() || quit; }); | 139 | cv.wait(lock, [this] { return !chunk_queue.Empty() || quit; }); |
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 3ce48e9d2..a40bb8bcd 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h | |||
| @@ -22,6 +22,7 @@ namespace Vulkan { | |||
| 22 | class CommandPool; | 22 | class CommandPool; |
| 23 | class Device; | 23 | class Device; |
| 24 | class Framebuffer; | 24 | class Framebuffer; |
| 25 | class GraphicsPipeline; | ||
| 25 | class StateTracker; | 26 | class StateTracker; |
| 26 | class VKQueryCache; | 27 | class VKQueryCache; |
| 27 | 28 | ||
| @@ -52,8 +53,8 @@ public: | |||
| 52 | /// of a renderpass. | 53 | /// of a renderpass. |
| 53 | void RequestOutsideRenderPassOperationContext(); | 54 | void RequestOutsideRenderPassOperationContext(); |
| 54 | 55 | ||
| 55 | /// Binds a pipeline to the current execution context. | 56 | /// Update the pipeline to the current execution context. |
| 56 | void BindGraphicsPipeline(VkPipeline pipeline); | 57 | bool UpdateGraphicsPipeline(GraphicsPipeline* pipeline); |
| 57 | 58 | ||
| 58 | /// Invalidates current command buffer state except for render passes | 59 | /// Invalidates current command buffer state except for render passes |
| 59 | void InvalidateState(); | 60 | void InvalidateState(); |
| @@ -170,7 +171,7 @@ private: | |||
| 170 | VkRenderPass renderpass = nullptr; | 171 | VkRenderPass renderpass = nullptr; |
| 171 | VkFramebuffer framebuffer = nullptr; | 172 | VkFramebuffer framebuffer = nullptr; |
| 172 | VkExtent2D render_area = {0, 0}; | 173 | VkExtent2D render_area = {0, 0}; |
| 173 | VkPipeline graphics_pipeline = nullptr; | 174 | GraphicsPipeline* graphics_pipeline = nullptr; |
| 174 | }; | 175 | }; |
| 175 | 176 | ||
| 176 | void WorkerThread(); | 177 | void WorkerThread(); |