diff options
| author | 2021-07-27 19:15:32 -0300 | |
|---|---|---|
| committer | 2021-07-27 21:29:24 -0300 | |
| commit | 3b006f4fe28006d320c60fd2b4393fd3f27eacd7 (patch) | |
| tree | e8704a3796e766a764e2643a2621451a8fe4ea49 /src/video_core/renderer_vulkan | |
| parent | Merge pull request #6748 from lioncash/engine-init (diff) | |
| download | yuzu-3b006f4fe28006d320c60fd2b4393fd3f27eacd7.tar.gz yuzu-3b006f4fe28006d320c60fd2b4393fd3f27eacd7.tar.xz yuzu-3b006f4fe28006d320c60fd2b4393fd3f27eacd7.zip | |
renderer_vulkan: Add setting to log pipeline statistics
Use VK_KHR_pipeline_executable_properties when enabled and available to
log statistics about the pipeline cache in a game.
For example, this is on Turing GPUs when generating a pipeline cache
from Super Smash Bros. Ultimate:
Average pipeline statistics
==========================================
Code size: 6433.167
Register count: 32.939
More advanced results could be presented, at the moment it's just an
average of all 3D and compute pipelines.
Diffstat (limited to 'src/video_core/renderer_vulkan')
8 files changed, 195 insertions, 19 deletions
diff --git a/src/video_core/renderer_vulkan/pipeline_statistics.cpp b/src/video_core/renderer_vulkan/pipeline_statistics.cpp new file mode 100644 index 000000000..bfec931a6 --- /dev/null +++ b/src/video_core/renderer_vulkan/pipeline_statistics.cpp | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <string_view> | ||
| 6 | |||
| 7 | #include <fmt/format.h> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "video_core/renderer_vulkan/pipeline_statistics.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 14 | |||
| 15 | namespace Vulkan { | ||
| 16 | |||
| 17 | using namespace std::string_view_literals; | ||
| 18 | |||
| 19 | static u64 GetUint64(const VkPipelineExecutableStatisticKHR& statistic) { | ||
| 20 | switch (statistic.format) { | ||
| 21 | case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR: | ||
| 22 | return static_cast<u64>(statistic.value.i64); | ||
| 23 | case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR: | ||
| 24 | return statistic.value.u64; | ||
| 25 | case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR: | ||
| 26 | return static_cast<u64>(statistic.value.f64); | ||
| 27 | default: | ||
| 28 | return 0; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | PipelineStatistics::PipelineStatistics(const Device& device_) : device{device_} {} | ||
| 33 | |||
| 34 | void PipelineStatistics::Collect(VkPipeline pipeline) { | ||
| 35 | const auto& dev{device.GetLogical()}; | ||
| 36 | const std::vector properties{dev.GetPipelineExecutablePropertiesKHR(pipeline)}; | ||
| 37 | const u32 num_executables{static_cast<u32>(properties.size())}; | ||
| 38 | for (u32 executable = 0; executable < num_executables; ++executable) { | ||
| 39 | const auto statistics{dev.GetPipelineExecutableStatisticsKHR(pipeline, executable)}; | ||
| 40 | if (statistics.empty()) { | ||
| 41 | continue; | ||
| 42 | } | ||
| 43 | Stats stage_stats; | ||
| 44 | for (const auto& statistic : statistics) { | ||
| 45 | const char* const name{statistic.name}; | ||
| 46 | if (name == "Binary Size"sv || name == "Code size"sv || name == "Instruction Count"sv) { | ||
| 47 | stage_stats.code_size = GetUint64(statistic); | ||
| 48 | } else if (name == "Register Count"sv) { | ||
| 49 | stage_stats.register_count = GetUint64(statistic); | ||
| 50 | } else if (name == "SGPRs"sv || name == "numUsedSgprs"sv) { | ||
| 51 | stage_stats.sgpr_count = GetUint64(statistic); | ||
| 52 | } else if (name == "VGPRs"sv || name == "numUsedVgprs"sv) { | ||
| 53 | stage_stats.vgpr_count = GetUint64(statistic); | ||
| 54 | } else if (name == "Branches"sv) { | ||
| 55 | stage_stats.branches_count = GetUint64(statistic); | ||
| 56 | } else if (name == "Basic Block Count"sv) { | ||
| 57 | stage_stats.basic_block_count = GetUint64(statistic); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | std::lock_guard lock{mutex}; | ||
| 61 | collected_stats.push_back(stage_stats); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | void PipelineStatistics::Report() const { | ||
| 66 | double num{}; | ||
| 67 | Stats total; | ||
| 68 | { | ||
| 69 | std::lock_guard lock{mutex}; | ||
| 70 | for (const Stats& stats : collected_stats) { | ||
| 71 | total.code_size += stats.code_size; | ||
| 72 | total.register_count += stats.register_count; | ||
| 73 | total.sgpr_count += stats.sgpr_count; | ||
| 74 | total.vgpr_count += stats.vgpr_count; | ||
| 75 | total.branches_count += stats.branches_count; | ||
| 76 | total.basic_block_count += stats.basic_block_count; | ||
| 77 | } | ||
| 78 | num = static_cast<double>(collected_stats.size()); | ||
| 79 | } | ||
| 80 | std::string report; | ||
| 81 | const auto add = [&](const char* fmt, u64 value) { | ||
| 82 | if (value > 0) { | ||
| 83 | report += fmt::format(fmt::runtime(fmt), static_cast<double>(value) / num); | ||
| 84 | } | ||
| 85 | }; | ||
| 86 | add("Code size: {:9.03f}\n", total.code_size); | ||
| 87 | add("Register count: {:9.03f}\n", total.register_count); | ||
| 88 | add("SGPRs: {:9.03f}\n", total.sgpr_count); | ||
| 89 | add("VGPRs: {:9.03f}\n", total.vgpr_count); | ||
| 90 | add("Branches count: {:9.03f}\n", total.branches_count); | ||
| 91 | add("Basic blocks: {:9.03f}\n", total.basic_block_count); | ||
| 92 | |||
| 93 | LOG_INFO(Render_Vulkan, | ||
| 94 | "\nAverage pipeline statistics\n" | ||
| 95 | "==========================================\n" | ||
| 96 | "{}\n", | ||
| 97 | report); | ||
| 98 | } | ||
| 99 | |||
| 100 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/pipeline_statistics.h b/src/video_core/renderer_vulkan/pipeline_statistics.h new file mode 100644 index 000000000..b61840107 --- /dev/null +++ b/src/video_core/renderer_vulkan/pipeline_statistics.h | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <mutex> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 12 | |||
| 13 | namespace Vulkan { | ||
| 14 | |||
| 15 | class Device; | ||
| 16 | |||
| 17 | class PipelineStatistics { | ||
| 18 | public: | ||
| 19 | explicit PipelineStatistics(const Device& device_); | ||
| 20 | |||
| 21 | void Collect(VkPipeline pipeline); | ||
| 22 | |||
| 23 | void Report() const; | ||
| 24 | |||
| 25 | private: | ||
| 26 | struct Stats { | ||
| 27 | u64 code_size{}; | ||
| 28 | u64 register_count{}; | ||
| 29 | u64 sgpr_count{}; | ||
| 30 | u64 vgpr_count{}; | ||
| 31 | u64 branches_count{}; | ||
| 32 | u64 basic_block_count{}; | ||
| 33 | }; | ||
| 34 | |||
| 35 | const Device& device; | ||
| 36 | mutable std::mutex mutex; | ||
| 37 | std::vector<Stats> collected_stats; | ||
| 38 | }; | ||
| 39 | |||
| 40 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 70b84c7a6..44faf626a 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <boost/container/small_vector.hpp> | 8 | #include <boost/container/small_vector.hpp> |
| 9 | 9 | ||
| 10 | #include "video_core/renderer_vulkan/pipeline_helper.h" | 10 | #include "video_core/renderer_vulkan/pipeline_helper.h" |
| 11 | #include "video_core/renderer_vulkan/pipeline_statistics.h" | ||
| 11 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | 12 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" |
| 12 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" | 13 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" |
| 13 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 14 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| @@ -26,6 +27,7 @@ using Tegra::Texture::TexturePair; | |||
| 26 | ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descriptor_pool, | 27 | ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descriptor_pool, |
| 27 | VKUpdateDescriptorQueue& update_descriptor_queue_, | 28 | VKUpdateDescriptorQueue& update_descriptor_queue_, |
| 28 | Common::ThreadWorker* thread_worker, | 29 | Common::ThreadWorker* thread_worker, |
| 30 | PipelineStatistics* pipeline_statistics, | ||
| 29 | VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_, | 31 | VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_, |
| 30 | vk::ShaderModule spv_module_) | 32 | vk::ShaderModule spv_module_) |
| 31 | : device{device_}, update_descriptor_queue{update_descriptor_queue_}, info{info_}, | 33 | : device{device_}, update_descriptor_queue{update_descriptor_queue_}, info{info_}, |
| @@ -36,7 +38,7 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript | |||
| 36 | std::copy_n(info.constant_buffer_used_sizes.begin(), uniform_buffer_sizes.size(), | 38 | std::copy_n(info.constant_buffer_used_sizes.begin(), uniform_buffer_sizes.size(), |
| 37 | uniform_buffer_sizes.begin()); | 39 | uniform_buffer_sizes.begin()); |
| 38 | 40 | ||
| 39 | auto func{[this, &descriptor_pool, shader_notify] { | 41 | auto func{[this, &descriptor_pool, shader_notify, pipeline_statistics] { |
| 40 | DescriptorLayoutBuilder builder{device}; | 42 | DescriptorLayoutBuilder builder{device}; |
| 41 | builder.Add(info, VK_SHADER_STAGE_COMPUTE_BIT); | 43 | builder.Add(info, VK_SHADER_STAGE_COMPUTE_BIT); |
| 42 | 44 | ||
| @@ -50,10 +52,14 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript | |||
| 50 | .pNext = nullptr, | 52 | .pNext = nullptr, |
| 51 | .requiredSubgroupSize = GuestWarpSize, | 53 | .requiredSubgroupSize = GuestWarpSize, |
| 52 | }; | 54 | }; |
| 55 | VkPipelineCreateFlags flags{}; | ||
| 56 | if (device.IsKhrPipelineEexecutablePropertiesEnabled()) { | ||
| 57 | flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR; | ||
| 58 | } | ||
| 53 | pipeline = device.GetLogical().CreateComputePipeline({ | 59 | pipeline = device.GetLogical().CreateComputePipeline({ |
| 54 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, | 60 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, |
| 55 | .pNext = nullptr, | 61 | .pNext = nullptr, |
| 56 | .flags = 0, | 62 | .flags = flags, |
| 57 | .stage{ | 63 | .stage{ |
| 58 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | 64 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, |
| 59 | .pNext = device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr, | 65 | .pNext = device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr, |
| @@ -67,6 +73,9 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript | |||
| 67 | .basePipelineHandle = 0, | 73 | .basePipelineHandle = 0, |
| 68 | .basePipelineIndex = 0, | 74 | .basePipelineIndex = 0, |
| 69 | }); | 75 | }); |
| 76 | if (pipeline_statistics) { | ||
| 77 | pipeline_statistics->Collect(*pipeline); | ||
| 78 | } | ||
| 70 | std::lock_guard lock{build_mutex}; | 79 | std::lock_guard lock{build_mutex}; |
| 71 | is_built = true; | 80 | is_built = true; |
| 72 | build_condvar.notify_one(); | 81 | build_condvar.notify_one(); |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index 52fec04d3..8c4b0a301 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h | |||
| @@ -25,6 +25,7 @@ class ShaderNotify; | |||
| 25 | namespace Vulkan { | 25 | namespace Vulkan { |
| 26 | 26 | ||
| 27 | class Device; | 27 | class Device; |
| 28 | class PipelineStatistics; | ||
| 28 | class VKScheduler; | 29 | class VKScheduler; |
| 29 | 30 | ||
| 30 | class ComputePipeline { | 31 | class ComputePipeline { |
| @@ -32,6 +33,7 @@ public: | |||
| 32 | explicit ComputePipeline(const Device& device, DescriptorPool& descriptor_pool, | 33 | explicit ComputePipeline(const Device& device, DescriptorPool& descriptor_pool, |
| 33 | VKUpdateDescriptorQueue& update_descriptor_queue, | 34 | VKUpdateDescriptorQueue& update_descriptor_queue, |
| 34 | Common::ThreadWorker* thread_worker, | 35 | Common::ThreadWorker* thread_worker, |
| 36 | PipelineStatistics* pipeline_statistics, | ||
| 35 | VideoCore::ShaderNotify* shader_notify, const Shader::Info& info, | 37 | VideoCore::ShaderNotify* shader_notify, const Shader::Info& info, |
| 36 | vk::ShaderModule spv_module); | 38 | vk::ShaderModule spv_module); |
| 37 | 39 | ||
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 18482e1d0..7c0f91007 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "common/bit_field.h" | 11 | #include "common/bit_field.h" |
| 12 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 12 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 13 | #include "video_core/renderer_vulkan/pipeline_helper.h" | 13 | #include "video_core/renderer_vulkan/pipeline_helper.h" |
| 14 | #include "video_core/renderer_vulkan/pipeline_statistics.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | 15 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" |
| 15 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" | 16 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" |
| 16 | #include "video_core/renderer_vulkan/vk_render_pass_cache.h" | 17 | #include "video_core/renderer_vulkan/vk_render_pass_cache.h" |
| @@ -217,8 +218,8 @@ GraphicsPipeline::GraphicsPipeline( | |||
| 217 | VKScheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_, | 218 | VKScheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_, |
| 218 | VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool, | 219 | VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool, |
| 219 | VKUpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread, | 220 | VKUpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread, |
| 220 | RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key_, | 221 | PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache, |
| 221 | std::array<vk::ShaderModule, NUM_STAGES> stages, | 222 | const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages, |
| 222 | const std::array<const Shader::Info*, NUM_STAGES>& infos) | 223 | const std::array<const Shader::Info*, NUM_STAGES>& infos) |
| 223 | : key{key_}, maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, device{device_}, | 224 | : key{key_}, maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, device{device_}, |
| 224 | texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, scheduler{scheduler_}, | 225 | texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, scheduler{scheduler_}, |
| @@ -235,7 +236,7 @@ GraphicsPipeline::GraphicsPipeline( | |||
| 235 | enabled_uniform_buffer_masks[stage] = info->constant_buffer_mask; | 236 | enabled_uniform_buffer_masks[stage] = info->constant_buffer_mask; |
| 236 | std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin()); | 237 | std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin()); |
| 237 | } | 238 | } |
| 238 | auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool] { | 239 | auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool, pipeline_statistics] { |
| 239 | DescriptorLayoutBuilder builder{MakeBuilder(device, stage_infos)}; | 240 | DescriptorLayoutBuilder builder{MakeBuilder(device, stage_infos)}; |
| 240 | uses_push_descriptor = builder.CanUsePushDescriptor(); | 241 | uses_push_descriptor = builder.CanUsePushDescriptor(); |
| 241 | descriptor_set_layout = builder.CreateDescriptorSetLayout(uses_push_descriptor); | 242 | descriptor_set_layout = builder.CreateDescriptorSetLayout(uses_push_descriptor); |
| @@ -250,6 +251,9 @@ GraphicsPipeline::GraphicsPipeline( | |||
| 250 | const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(key.state))}; | 251 | const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(key.state))}; |
| 251 | Validate(); | 252 | Validate(); |
| 252 | MakePipeline(render_pass); | 253 | MakePipeline(render_pass); |
| 254 | if (pipeline_statistics) { | ||
| 255 | pipeline_statistics->Collect(*pipeline); | ||
| 256 | } | ||
| 253 | 257 | ||
| 254 | std::lock_guard lock{build_mutex}; | 258 | std::lock_guard lock{build_mutex}; |
| 255 | is_built = true; | 259 | is_built = true; |
| @@ -782,10 +786,14 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | |||
| 782 | } | 786 | } |
| 783 | */ | 787 | */ |
| 784 | } | 788 | } |
| 789 | VkPipelineCreateFlags flags{}; | ||
| 790 | if (device.IsKhrPipelineEexecutablePropertiesEnabled()) { | ||
| 791 | flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR; | ||
| 792 | } | ||
| 785 | pipeline = device.GetLogical().CreateGraphicsPipeline({ | 793 | pipeline = device.GetLogical().CreateGraphicsPipeline({ |
| 786 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | 794 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, |
| 787 | .pNext = nullptr, | 795 | .pNext = nullptr, |
| 788 | .flags = 0, | 796 | .flags = flags, |
| 789 | .stageCount = static_cast<u32>(shader_stages.size()), | 797 | .stageCount = static_cast<u32>(shader_stages.size()), |
| 790 | .pStages = shader_stages.data(), | 798 | .pStages = shader_stages.data(), |
| 791 | .pVertexInputState = &vertex_input_ci, | 799 | .pVertexInputState = &vertex_input_ci, |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 2bd48d697..1c780e944 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h | |||
| @@ -60,6 +60,7 @@ struct hash<Vulkan::GraphicsPipelineCacheKey> { | |||
| 60 | namespace Vulkan { | 60 | namespace Vulkan { |
| 61 | 61 | ||
| 62 | class Device; | 62 | class Device; |
| 63 | class PipelineStatistics; | ||
| 63 | class RenderPassCache; | 64 | class RenderPassCache; |
| 64 | class VKScheduler; | 65 | class VKScheduler; |
| 65 | class VKUpdateDescriptorQueue; | 66 | class VKUpdateDescriptorQueue; |
| @@ -73,8 +74,9 @@ public: | |||
| 73 | VKScheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache, | 74 | VKScheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache, |
| 74 | VideoCore::ShaderNotify* shader_notify, const Device& device, | 75 | VideoCore::ShaderNotify* shader_notify, const Device& device, |
| 75 | DescriptorPool& descriptor_pool, VKUpdateDescriptorQueue& update_descriptor_queue, | 76 | DescriptorPool& descriptor_pool, VKUpdateDescriptorQueue& update_descriptor_queue, |
| 76 | Common::ThreadWorker* worker_thread, RenderPassCache& render_pass_cache, | 77 | Common::ThreadWorker* worker_thread, PipelineStatistics* pipeline_statistics, |
| 77 | const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages, | 78 | RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key, |
| 79 | std::array<vk::ShaderModule, NUM_STAGES> stages, | ||
| 78 | const std::array<const Shader::Info*, NUM_STAGES>& infos); | 80 | const std::array<const Shader::Info*, NUM_STAGES>& infos); |
| 79 | 81 | ||
| 80 | GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete; | 82 | GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete; |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 57b163247..a37ca1fdf 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 29 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| 30 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 30 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 31 | #include "video_core/renderer_vulkan/pipeline_helper.h" | 31 | #include "video_core/renderer_vulkan/pipeline_helper.h" |
| 32 | #include "video_core/renderer_vulkan/pipeline_statistics.h" | ||
| 32 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" | 33 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" |
| 33 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 34 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 34 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 35 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| @@ -389,15 +390,19 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading | |||
| 389 | size_t total{}; | 390 | size_t total{}; |
| 390 | size_t built{}; | 391 | size_t built{}; |
| 391 | bool has_loaded{}; | 392 | bool has_loaded{}; |
| 393 | std::unique_ptr<PipelineStatistics> statistics; | ||
| 392 | } state; | 394 | } state; |
| 393 | 395 | ||
| 396 | if (device.IsKhrPipelineEexecutablePropertiesEnabled()) { | ||
| 397 | state.statistics = std::make_unique<PipelineStatistics>(device); | ||
| 398 | } | ||
| 394 | const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { | 399 | const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { |
| 395 | ComputePipelineCacheKey key; | 400 | ComputePipelineCacheKey key; |
| 396 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); | 401 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); |
| 397 | 402 | ||
| 398 | workers.QueueWork([this, key, env = std::move(env), &state, &callback]() mutable { | 403 | workers.QueueWork([this, key, env = std::move(env), &state, &callback]() mutable { |
| 399 | ShaderPools pools; | 404 | ShaderPools pools; |
| 400 | auto pipeline{CreateComputePipeline(pools, key, env, false)}; | 405 | auto pipeline{CreateComputePipeline(pools, key, env, state.statistics.get(), false)}; |
| 401 | std::lock_guard lock{state.mutex}; | 406 | std::lock_guard lock{state.mutex}; |
| 402 | if (pipeline) { | 407 | if (pipeline) { |
| 403 | compute_cache.emplace(key, std::move(pipeline)); | 408 | compute_cache.emplace(key, std::move(pipeline)); |
| @@ -425,7 +430,8 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading | |||
| 425 | for (auto& env : envs) { | 430 | for (auto& env : envs) { |
| 426 | env_ptrs.push_back(&env); | 431 | env_ptrs.push_back(&env); |
| 427 | } | 432 | } |
| 428 | auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs), false)}; | 433 | auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs), |
| 434 | state.statistics.get(), false)}; | ||
| 429 | 435 | ||
| 430 | std::lock_guard lock{state.mutex}; | 436 | std::lock_guard lock{state.mutex}; |
| 431 | graphics_cache.emplace(key, std::move(pipeline)); | 437 | graphics_cache.emplace(key, std::move(pipeline)); |
| @@ -445,6 +451,10 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading | |||
| 445 | lock.unlock(); | 451 | lock.unlock(); |
| 446 | 452 | ||
| 447 | workers.WaitForRequests(); | 453 | workers.WaitForRequests(); |
| 454 | |||
| 455 | if (state.statistics) { | ||
| 456 | state.statistics->Report(); | ||
| 457 | } | ||
| 448 | } | 458 | } |
| 449 | 459 | ||
| 450 | GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() { | 460 | GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() { |
| @@ -486,7 +496,8 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const | |||
| 486 | 496 | ||
| 487 | std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( | 497 | std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( |
| 488 | ShaderPools& pools, const GraphicsPipelineCacheKey& key, | 498 | ShaderPools& pools, const GraphicsPipelineCacheKey& key, |
| 489 | std::span<Shader::Environment* const> envs, bool build_in_parallel) try { | 499 | std::span<Shader::Environment* const> envs, PipelineStatistics* statistics, |
| 500 | bool build_in_parallel) try { | ||
| 490 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); | 501 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); |
| 491 | size_t env_index{0}; | 502 | size_t env_index{0}; |
| 492 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; | 503 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; |
| @@ -540,7 +551,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( | |||
| 540 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; | 551 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; |
| 541 | return std::make_unique<GraphicsPipeline>( | 552 | return std::make_unique<GraphicsPipeline>( |
| 542 | maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, &shader_notify, device, | 553 | maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, &shader_notify, device, |
| 543 | descriptor_pool, update_descriptor_queue, thread_worker, render_pass_cache, key, | 554 | descriptor_pool, update_descriptor_queue, thread_worker, statistics, render_pass_cache, key, |
| 544 | std::move(modules), infos); | 555 | std::move(modules), infos); |
| 545 | 556 | ||
| 546 | } catch (const Shader::Exception& exception) { | 557 | } catch (const Shader::Exception& exception) { |
| @@ -553,7 +564,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() { | |||
| 553 | GetGraphicsEnvironments(environments, graphics_key.unique_hashes); | 564 | GetGraphicsEnvironments(environments, graphics_key.unique_hashes); |
| 554 | 565 | ||
| 555 | main_pools.ReleaseContents(); | 566 | main_pools.ReleaseContents(); |
| 556 | auto pipeline{CreateGraphicsPipeline(main_pools, graphics_key, environments.Span(), true)}; | 567 | auto pipeline{ |
| 568 | CreateGraphicsPipeline(main_pools, graphics_key, environments.Span(), nullptr, true)}; | ||
| 557 | if (!pipeline || pipeline_cache_filename.empty()) { | 569 | if (!pipeline || pipeline_cache_filename.empty()) { |
| 558 | return pipeline; | 570 | return pipeline; |
| 559 | } | 571 | } |
| @@ -578,7 +590,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( | |||
| 578 | env.SetCachedSize(shader->size_bytes); | 590 | env.SetCachedSize(shader->size_bytes); |
| 579 | 591 | ||
| 580 | main_pools.ReleaseContents(); | 592 | main_pools.ReleaseContents(); |
| 581 | auto pipeline{CreateComputePipeline(main_pools, key, env, true)}; | 593 | auto pipeline{CreateComputePipeline(main_pools, key, env, nullptr, true)}; |
| 582 | if (!pipeline || pipeline_cache_filename.empty()) { | 594 | if (!pipeline || pipeline_cache_filename.empty()) { |
| 583 | return pipeline; | 595 | return pipeline; |
| 584 | } | 596 | } |
| @@ -591,7 +603,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( | |||
| 591 | 603 | ||
| 592 | std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( | 604 | std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( |
| 593 | ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env, | 605 | ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env, |
| 594 | bool build_in_parallel) try { | 606 | PipelineStatistics* statistics, bool build_in_parallel) try { |
| 595 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); | 607 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); |
| 596 | 608 | ||
| 597 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; | 609 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; |
| @@ -605,8 +617,8 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( | |||
| 605 | } | 617 | } |
| 606 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; | 618 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; |
| 607 | return std::make_unique<ComputePipeline>(device, descriptor_pool, update_descriptor_queue, | 619 | return std::make_unique<ComputePipeline>(device, descriptor_pool, update_descriptor_queue, |
| 608 | thread_worker, &shader_notify, program.info, | 620 | thread_worker, statistics, &shader_notify, |
| 609 | std::move(spv_module)); | 621 | program.info, std::move(spv_module)); |
| 610 | 622 | ||
| 611 | } catch (const Shader::Exception& exception) { | 623 | } catch (const Shader::Exception& exception) { |
| 612 | LOG_ERROR(Render_Vulkan, "{}", exception.what()); | 624 | LOG_ERROR(Render_Vulkan, "{}", exception.what()); |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index efe5a7ed8..4c135b5dd 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h | |||
| @@ -80,8 +80,9 @@ struct hash<Vulkan::ComputePipelineCacheKey> { | |||
| 80 | namespace Vulkan { | 80 | namespace Vulkan { |
| 81 | 81 | ||
| 82 | class ComputePipeline; | 82 | class ComputePipeline; |
| 83 | class Device; | ||
| 84 | class DescriptorPool; | 83 | class DescriptorPool; |
| 84 | class Device; | ||
| 85 | class PipelineStatistics; | ||
| 85 | class RasterizerVulkan; | 86 | class RasterizerVulkan; |
| 86 | class RenderPassCache; | 87 | class RenderPassCache; |
| 87 | class VKScheduler; | 88 | class VKScheduler; |
| @@ -128,7 +129,8 @@ private: | |||
| 128 | 129 | ||
| 129 | std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline( | 130 | std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline( |
| 130 | ShaderPools& pools, const GraphicsPipelineCacheKey& key, | 131 | ShaderPools& pools, const GraphicsPipelineCacheKey& key, |
| 131 | std::span<Shader::Environment* const> envs, bool build_in_parallel); | 132 | std::span<Shader::Environment* const> envs, PipelineStatistics* statistics, |
| 133 | bool build_in_parallel); | ||
| 132 | 134 | ||
| 133 | std::unique_ptr<ComputePipeline> CreateComputePipeline(const ComputePipelineCacheKey& key, | 135 | std::unique_ptr<ComputePipeline> CreateComputePipeline(const ComputePipelineCacheKey& key, |
| 134 | const ShaderInfo* shader); | 136 | const ShaderInfo* shader); |
| @@ -136,6 +138,7 @@ private: | |||
| 136 | std::unique_ptr<ComputePipeline> CreateComputePipeline(ShaderPools& pools, | 138 | std::unique_ptr<ComputePipeline> CreateComputePipeline(ShaderPools& pools, |
| 137 | const ComputePipelineCacheKey& key, | 139 | const ComputePipelineCacheKey& key, |
| 138 | Shader::Environment& env, | 140 | Shader::Environment& env, |
| 141 | PipelineStatistics* statistics, | ||
| 139 | bool build_in_parallel); | 142 | bool build_in_parallel); |
| 140 | 143 | ||
| 141 | const Device& device; | 144 | const Device& device; |