summaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-02-17 00:59:28 -0300
committerGravatar ameerj2021-07-22 21:51:22 -0400
commit85cce78583bc2232428a8fb39e43182877c8d5ad (patch)
tree308f4ef2d145652e08dff1da31c72c2f00dad2e1 /src/video_core/renderer_vulkan
parentshader: Remove old shader management (diff)
downloadyuzu-85cce78583bc2232428a8fb39e43182877c8d5ad.tar.gz
yuzu-85cce78583bc2232428a8fb39e43182877c8d5ad.tar.xz
yuzu-85cce78583bc2232428a8fb39e43182877c8d5ad.zip
shader: Primitive Vulkan integration
Diffstat (limited to 'src/video_core/renderer_vulkan')
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp140
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.h43
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.h10
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline.h36
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp190
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h30
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp23
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h3
-rw-r--r--src/video_core/renderer_vulkan/vk_resource_pool.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_resource_pool.h12
11 files changed, 428 insertions, 77 deletions
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 7a3660496..588ce6139 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -4,6 +4,9 @@
4 4
5#include <vector> 5#include <vector>
6 6
7#include <boost/container/small_vector.hpp>
8
9#include "video_core/renderer_vulkan/vk_buffer_cache.h"
7#include "video_core/renderer_vulkan/vk_compute_pipeline.h" 10#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
8#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 11#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
9#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 12#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
@@ -13,9 +16,142 @@
13#include "video_core/vulkan_common/vulkan_wrapper.h" 16#include "video_core/vulkan_common/vulkan_wrapper.h"
14 17
15namespace Vulkan { 18namespace Vulkan {
19namespace {
20vk::DescriptorSetLayout CreateDescriptorSetLayout(const Device& device, const Shader::Info& info) {
21 boost::container::small_vector<VkDescriptorSetLayoutBinding, 24> bindings;
22 u32 binding{};
23 for ([[maybe_unused]] const auto& desc : info.constant_buffer_descriptors) {
24 bindings.push_back({
25 .binding = binding,
26 .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
27 .descriptorCount = 1,
28 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
29 .pImmutableSamplers = nullptr,
30 });
31 ++binding;
32 }
33 for ([[maybe_unused]] const auto& desc : info.storage_buffers_descriptors) {
34 bindings.push_back({
35 .binding = binding,
36 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
37 .descriptorCount = 1,
38 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
39 .pImmutableSamplers = nullptr,
40 });
41 ++binding;
42 }
43 return device.GetLogical().CreateDescriptorSetLayout({
44 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
45 .pNext = nullptr,
46 .flags = 0,
47 .bindingCount = static_cast<u32>(bindings.size()),
48 .pBindings = bindings.data(),
49 });
50}
51
52vk::DescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplate(
53 const Device& device, const Shader::Info& info, VkDescriptorSetLayout descriptor_set_layout,
54 VkPipelineLayout pipeline_layout) {
55 boost::container::small_vector<VkDescriptorUpdateTemplateEntry, 24> entries;
56 size_t offset{};
57 u32 binding{};
58 for ([[maybe_unused]] const auto& desc : info.constant_buffer_descriptors) {
59 entries.push_back({
60 .dstBinding = binding,
61 .dstArrayElement = 0,
62 .descriptorCount = 1,
63 .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
64 .offset = offset,
65 .stride = sizeof(DescriptorUpdateEntry),
66 });
67 ++binding;
68 offset += sizeof(DescriptorUpdateEntry);
69 }
70 for ([[maybe_unused]] const auto& desc : info.storage_buffers_descriptors) {
71 entries.push_back({
72 .dstBinding = binding,
73 .dstArrayElement = 0,
74 .descriptorCount = 1,
75 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
76 .offset = offset,
77 .stride = sizeof(DescriptorUpdateEntry),
78 });
79 ++binding;
80 offset += sizeof(DescriptorUpdateEntry);
81 }
82 return device.GetLogical().CreateDescriptorUpdateTemplateKHR({
83 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO,
84 .pNext = nullptr,
85 .flags = 0,
86 .descriptorUpdateEntryCount = static_cast<u32>(entries.size()),
87 .pDescriptorUpdateEntries = entries.data(),
88 .templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
89 .descriptorSetLayout = descriptor_set_layout,
90 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_COMPUTE,
91 .pipelineLayout = pipeline_layout,
92 .set = 0,
93 });
94}
95} // Anonymous namespace
96
97ComputePipeline::ComputePipeline(const Device& device, VKDescriptorPool& descriptor_pool,
98 VKUpdateDescriptorQueue& update_descriptor_queue_,
99 const Shader::Info& info_, vk::ShaderModule spv_module_)
100 : update_descriptor_queue{&update_descriptor_queue_}, info{info_},
101 spv_module(std::move(spv_module_)),
102 descriptor_set_layout(CreateDescriptorSetLayout(device, info)),
103 descriptor_allocator(descriptor_pool, *descriptor_set_layout),
104 pipeline_layout{device.GetLogical().CreatePipelineLayout({
105 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
106 .pNext = nullptr,
107 .flags = 0,
108 .setLayoutCount = 1,
109 .pSetLayouts = descriptor_set_layout.address(),
110 .pushConstantRangeCount = 0,
111 .pPushConstantRanges = nullptr,
112 })},
113 descriptor_update_template{
114 CreateDescriptorUpdateTemplate(device, info, *descriptor_set_layout, *pipeline_layout)},
115 pipeline{device.GetLogical().CreateComputePipeline({
116 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
117 .pNext = nullptr,
118 .flags = 0,
119 .stage{
120 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
121 .pNext = nullptr,
122 .flags = 0,
123 .stage = VK_SHADER_STAGE_COMPUTE_BIT,
124 .module = *spv_module,
125 .pName = "main",
126 .pSpecializationInfo = nullptr,
127 },
128 .layout = *pipeline_layout,
129 .basePipelineHandle = 0,
130 .basePipelineIndex = 0,
131 })} {}
132
133void ComputePipeline::ConfigureBufferCache(BufferCache& buffer_cache) {
134 u32 enabled_uniforms{};
135 for (const auto& desc : info.constant_buffer_descriptors) {
136 enabled_uniforms |= ((1ULL << desc.count) - 1) << desc.index;
137 }
138 buffer_cache.SetEnabledComputeUniformBuffers(enabled_uniforms);
16 139
17ComputePipeline::ComputePipeline() = default; 140 buffer_cache.UnbindComputeStorageBuffers();
141 size_t index{};
142 for (const auto& desc : info.storage_buffers_descriptors) {
143 ASSERT(desc.count == 1);
144 buffer_cache.BindComputeStorageBuffer(index, desc.cbuf_index, desc.cbuf_offset, true);
145 ++index;
146 }
147 buffer_cache.UpdateComputeBuffers();
148 buffer_cache.BindHostComputeBuffers();
149}
18 150
19ComputePipeline::~ComputePipeline() = default; 151VkDescriptorSet ComputePipeline::UpdateDescriptorSet() {
152 const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()};
153 update_descriptor_queue->Send(*descriptor_update_template, descriptor_set);
154 return descriptor_set;
155}
20 156
21} // namespace Vulkan 157} // 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 433d8bb3d..dc045d524 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
@@ -5,19 +5,52 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "shader_recompiler/shader_info.h"
9#include "video_core/renderer_vulkan/vk_buffer_cache.h"
8#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 10#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
11#include "video_core/renderer_vulkan/vk_pipeline.h"
12#include "video_core/renderer_vulkan/vk_update_descriptor.h"
9#include "video_core/vulkan_common/vulkan_wrapper.h" 13#include "video_core/vulkan_common/vulkan_wrapper.h"
10 14
11namespace Vulkan { 15namespace Vulkan {
12 16
13class Device; 17class Device;
14class VKScheduler;
15class VKUpdateDescriptorQueue;
16 18
17class ComputePipeline { 19class ComputePipeline : public Pipeline {
18public: 20public:
19 explicit ComputePipeline(); 21 explicit ComputePipeline() = default;
20 ~ComputePipeline(); 22 explicit ComputePipeline(const Device& device, VKDescriptorPool& descriptor_pool,
23 VKUpdateDescriptorQueue& update_descriptor_queue,
24 const Shader::Info& info, vk::ShaderModule spv_module);
25
26 ComputePipeline& operator=(ComputePipeline&&) noexcept = default;
27 ComputePipeline(ComputePipeline&&) noexcept = default;
28
29 ComputePipeline& operator=(const ComputePipeline&) = delete;
30 ComputePipeline(const ComputePipeline&) = delete;
31
32 void ConfigureBufferCache(BufferCache& buffer_cache);
33
34 [[nodiscard]] VkDescriptorSet UpdateDescriptorSet();
35
36 [[nodiscard]] VkPipeline Handle() const noexcept {
37 return *pipeline;
38 }
39
40 [[nodiscard]] VkPipelineLayout PipelineLayout() const noexcept {
41 return *pipeline_layout;
42 }
43
44private:
45 VKUpdateDescriptorQueue* update_descriptor_queue;
46 Shader::Info info;
47
48 vk::ShaderModule spv_module;
49 vk::DescriptorSetLayout descriptor_set_layout;
50 DescriptorAllocator descriptor_allocator;
51 vk::PipelineLayout pipeline_layout;
52 vk::DescriptorUpdateTemplateKHR descriptor_update_template;
53 vk::Pipeline pipeline;
21}; 54};
22 55
23} // namespace Vulkan 56} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
index ef9fb5910..3bea1ff44 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
@@ -19,9 +19,7 @@ constexpr std::size_t SETS_GROW_RATE = 0x20;
19DescriptorAllocator::DescriptorAllocator(VKDescriptorPool& descriptor_pool_, 19DescriptorAllocator::DescriptorAllocator(VKDescriptorPool& descriptor_pool_,
20 VkDescriptorSetLayout layout_) 20 VkDescriptorSetLayout layout_)
21 : ResourcePool(descriptor_pool_.master_semaphore, SETS_GROW_RATE), 21 : ResourcePool(descriptor_pool_.master_semaphore, SETS_GROW_RATE),
22 descriptor_pool{descriptor_pool_}, layout{layout_} {} 22 descriptor_pool{&descriptor_pool_}, layout{layout_} {}
23
24DescriptorAllocator::~DescriptorAllocator() = default;
25 23
26VkDescriptorSet DescriptorAllocator::Commit() { 24VkDescriptorSet DescriptorAllocator::Commit() {
27 const std::size_t index = CommitResource(); 25 const std::size_t index = CommitResource();
@@ -29,7 +27,7 @@ VkDescriptorSet DescriptorAllocator::Commit() {
29} 27}
30 28
31void DescriptorAllocator::Allocate(std::size_t begin, std::size_t end) { 29void DescriptorAllocator::Allocate(std::size_t begin, std::size_t end) {
32 descriptors_allocations.push_back(descriptor_pool.AllocateDescriptors(layout, end - begin)); 30 descriptors_allocations.push_back(descriptor_pool->AllocateDescriptors(layout, end - begin));
33} 31}
34 32
35VKDescriptorPool::VKDescriptorPool(const Device& device_, VKScheduler& scheduler) 33VKDescriptorPool::VKDescriptorPool(const Device& device_, VKScheduler& scheduler)
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
index f892be7be..2501f9967 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
@@ -17,8 +17,12 @@ class VKScheduler;
17 17
18class DescriptorAllocator final : public ResourcePool { 18class DescriptorAllocator final : public ResourcePool {
19public: 19public:
20 explicit DescriptorAllocator() = default;
20 explicit DescriptorAllocator(VKDescriptorPool& descriptor_pool, VkDescriptorSetLayout layout); 21 explicit DescriptorAllocator(VKDescriptorPool& descriptor_pool, VkDescriptorSetLayout layout);
21 ~DescriptorAllocator() override; 22 ~DescriptorAllocator() override = default;
23
24 DescriptorAllocator& operator=(DescriptorAllocator&&) noexcept = default;
25 DescriptorAllocator(DescriptorAllocator&&) noexcept = default;
22 26
23 DescriptorAllocator& operator=(const DescriptorAllocator&) = delete; 27 DescriptorAllocator& operator=(const DescriptorAllocator&) = delete;
24 DescriptorAllocator(const DescriptorAllocator&) = delete; 28 DescriptorAllocator(const DescriptorAllocator&) = delete;
@@ -29,8 +33,8 @@ protected:
29 void Allocate(std::size_t begin, std::size_t end) override; 33 void Allocate(std::size_t begin, std::size_t end) override;
30 34
31private: 35private:
32 VKDescriptorPool& descriptor_pool; 36 VKDescriptorPool* descriptor_pool{};
33 const VkDescriptorSetLayout layout; 37 VkDescriptorSetLayout layout{};
34 38
35 std::vector<vk::DescriptorSets> descriptors_allocations; 39 std::vector<vk::DescriptorSets> descriptors_allocations;
36}; 40};
diff --git a/src/video_core/renderer_vulkan/vk_pipeline.h b/src/video_core/renderer_vulkan/vk_pipeline.h
new file mode 100644
index 000000000..b06288403
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_pipeline.h
@@ -0,0 +1,36 @@
1// Copyright 2019 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 <cstddef>
8
9#include "video_core/vulkan_common/vulkan_wrapper.h"
10
11namespace Vulkan {
12
13class Pipeline {
14public:
15 /// Add a reference count to the pipeline
16 void AddRef() noexcept {
17 ++ref_count;
18 }
19
20 [[nodiscard]] bool RemoveRef() noexcept {
21 --ref_count;
22 return ref_count == 0;
23 }
24
25 [[nodiscard]] u64 UsageTick() const noexcept {
26 return usage_tick;
27 }
28
29protected:
30 u64 usage_tick{};
31
32private:
33 size_t ref_count{};
34};
35
36} // 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 7d0ba1180..4bf3e4819 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -12,6 +12,8 @@
12#include "common/microprofile.h" 12#include "common/microprofile.h"
13#include "core/core.h" 13#include "core/core.h"
14#include "core/memory.h" 14#include "core/memory.h"
15#include "shader_recompiler/environment.h"
16#include "shader_recompiler/recompiler.h"
15#include "video_core/engines/kepler_compute.h" 17#include "video_core/engines/kepler_compute.h"
16#include "video_core/engines/maxwell_3d.h" 18#include "video_core/engines/maxwell_3d.h"
17#include "video_core/memory_manager.h" 19#include "video_core/memory_manager.h"
@@ -22,43 +24,105 @@
22#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 24#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
23#include "video_core/renderer_vulkan/vk_rasterizer.h" 25#include "video_core/renderer_vulkan/vk_rasterizer.h"
24#include "video_core/renderer_vulkan/vk_scheduler.h" 26#include "video_core/renderer_vulkan/vk_scheduler.h"
27#include "video_core/renderer_vulkan/vk_shader_util.h"
25#include "video_core/renderer_vulkan/vk_update_descriptor.h" 28#include "video_core/renderer_vulkan/vk_update_descriptor.h"
26#include "video_core/shader_cache.h" 29#include "video_core/shader_cache.h"
27#include "video_core/shader_notify.h" 30#include "video_core/shader_notify.h"
28#include "video_core/vulkan_common/vulkan_device.h" 31#include "video_core/vulkan_common/vulkan_device.h"
29#include "video_core/vulkan_common/vulkan_wrapper.h" 32#include "video_core/vulkan_common/vulkan_wrapper.h"
30 33
34#pragma optimize("", off)
35
31namespace Vulkan { 36namespace Vulkan {
32MICROPROFILE_DECLARE(Vulkan_PipelineCache); 37MICROPROFILE_DECLARE(Vulkan_PipelineCache);
33 38
34using Tegra::Engines::ShaderType; 39using Tegra::Engines::ShaderType;
35 40
36namespace { 41namespace {
37size_t StageFromProgram(size_t program) { 42class Environment final : public Shader::Environment {
38 return program == 0 ? 0 : program - 1; 43public:
39} 44 explicit Environment(Tegra::Engines::KeplerCompute& kepler_compute_,
45 Tegra::MemoryManager& gpu_memory_, GPUVAddr program_base_)
46 : kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, program_base{program_base_} {}
47
48 ~Environment() override = default;
49
50 [[nodiscard]] std::optional<u128> Analyze(u32 start_address) {
51 const std::optional<u64> size{TryFindSize(start_address)};
52 if (!size) {
53 return std::nullopt;
54 }
55 cached_lowest = start_address;
56 cached_highest = start_address + static_cast<u32>(*size);
57 return Common::CityHash128(reinterpret_cast<const char*>(code.data()), code.size());
58 }
40 59
41ShaderType StageFromProgram(Maxwell::ShaderProgram program) { 60 [[nodiscard]] size_t ShaderSize() const noexcept {
42 return static_cast<ShaderType>(StageFromProgram(static_cast<size_t>(program))); 61 return read_highest - read_lowest + INST_SIZE;
43} 62 }
44 63
45ShaderType GetShaderType(Maxwell::ShaderProgram program) { 64 [[nodiscard]] u128 ComputeHash() const {
46 switch (program) { 65 const size_t size{ShaderSize()};
47 case Maxwell::ShaderProgram::VertexB: 66 auto data = std::make_unique<u64[]>(size);
48 return ShaderType::Vertex; 67 gpu_memory.ReadBlock(program_base + read_lowest, data.get(), size);
49 case Maxwell::ShaderProgram::TesselationControl: 68 return Common::CityHash128(reinterpret_cast<const char*>(data.get()), size);
50 return ShaderType::TesselationControl;
51 case Maxwell::ShaderProgram::TesselationEval:
52 return ShaderType::TesselationEval;
53 case Maxwell::ShaderProgram::Geometry:
54 return ShaderType::Geometry;
55 case Maxwell::ShaderProgram::Fragment:
56 return ShaderType::Fragment;
57 default:
58 UNIMPLEMENTED_MSG("program={}", program);
59 return ShaderType::Vertex;
60 } 69 }
61} 70
71 u64 ReadInstruction(u32 address) override {
72 read_lowest = std::min(read_lowest, address);
73 read_highest = std::max(read_highest, address);
74
75 if (address >= cached_lowest && address < cached_highest) {
76 return code[address / INST_SIZE];
77 }
78 return gpu_memory.Read<u64>(program_base + address);
79 }
80
81 std::array<u32, 3> WorkgroupSize() override {
82 const auto& qmd{kepler_compute.launch_description};
83 return {qmd.block_dim_x, qmd.block_dim_y, qmd.block_dim_z};
84 }
85
86private:
87 static constexpr size_t INST_SIZE = sizeof(u64);
88 static constexpr size_t BLOCK_SIZE = 0x1000;
89 static constexpr size_t MAXIMUM_SIZE = 0x100000;
90
91 static constexpr u64 SELF_BRANCH_A = 0xE2400FFFFF87000FULL;
92 static constexpr u64 SELF_BRANCH_B = 0xE2400FFFFF07000FULL;
93
94 std::optional<u64> TryFindSize(u32 start_address) {
95 GPUVAddr guest_addr = program_base + start_address;
96 size_t offset = 0;
97 size_t size = BLOCK_SIZE;
98 while (size <= MAXIMUM_SIZE) {
99 code.resize(size / INST_SIZE);
100 u64* const data = code.data() + offset / INST_SIZE;
101 gpu_memory.ReadBlock(guest_addr, data, BLOCK_SIZE);
102 for (size_t i = 0; i < BLOCK_SIZE; i += INST_SIZE) {
103 const u64 inst = data[i / INST_SIZE];
104 if (inst == SELF_BRANCH_A || inst == SELF_BRANCH_B) {
105 return offset + i;
106 }
107 }
108 guest_addr += BLOCK_SIZE;
109 size += BLOCK_SIZE;
110 offset += BLOCK_SIZE;
111 }
112 return std::nullopt;
113 }
114
115 Tegra::Engines::KeplerCompute& kepler_compute;
116 Tegra::MemoryManager& gpu_memory;
117 GPUVAddr program_base;
118
119 u32 read_lowest = 0;
120 u32 read_highest = 0;
121
122 std::vector<u64> code;
123 u32 cached_lowest = std::numeric_limits<u32>::max();
124 u32 cached_highest = 0;
125};
62} // Anonymous namespace 126} // Anonymous namespace
63 127
64size_t ComputePipelineCacheKey::Hash() const noexcept { 128size_t ComputePipelineCacheKey::Hash() const noexcept {
@@ -70,35 +134,91 @@ bool ComputePipelineCacheKey::operator==(const ComputePipelineCacheKey& rhs) con
70 return std::memcmp(&rhs, this, sizeof *this) == 0; 134 return std::memcmp(&rhs, this, sizeof *this) == 0;
71} 135}
72 136
73Shader::Shader() = default;
74
75Shader::~Shader() = default;
76
77PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_, 137PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_,
78 Tegra::Engines::Maxwell3D& maxwell3d_, 138 Tegra::Engines::Maxwell3D& maxwell3d_,
79 Tegra::Engines::KeplerCompute& kepler_compute_, 139 Tegra::Engines::KeplerCompute& kepler_compute_,
80 Tegra::MemoryManager& gpu_memory_, const Device& device_, 140 Tegra::MemoryManager& gpu_memory_, const Device& device_,
81 VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, 141 VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_,
82 VKUpdateDescriptorQueue& update_descriptor_queue_) 142 VKUpdateDescriptorQueue& update_descriptor_queue_)
83 : VideoCommon::ShaderCache<Shader>{rasterizer_}, gpu{gpu_}, maxwell3d{maxwell3d_}, 143 : VideoCommon::ShaderCache<ShaderInfo>{rasterizer_}, gpu{gpu_}, maxwell3d{maxwell3d_},
84 kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_}, 144 kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_},
85 scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, update_descriptor_queue{ 145 scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, update_descriptor_queue{
86 update_descriptor_queue_} {} 146 update_descriptor_queue_} {}
87 147
88PipelineCache::~PipelineCache() = default; 148PipelineCache::~PipelineCache() = default;
89 149
90ComputePipeline& PipelineCache::GetComputePipeline(const ComputePipelineCacheKey& key) { 150ComputePipeline* PipelineCache::CurrentComputePipeline() {
91 MICROPROFILE_SCOPE(Vulkan_PipelineCache); 151 MICROPROFILE_SCOPE(Vulkan_PipelineCache);
92 152
93 const auto [pair, is_cache_miss] = compute_cache.try_emplace(key); 153 const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()};
94 auto& entry = pair->second; 154 const auto& qmd{kepler_compute.launch_description};
95 if (!is_cache_miss) { 155 const GPUVAddr shader_addr{program_base + qmd.program_start};
96 return *entry; 156 const std::optional<VAddr> cpu_shader_addr{gpu_memory.GpuToCpuAddress(shader_addr)};
157 if (!cpu_shader_addr) {
158 return nullptr;
159 }
160 ShaderInfo* const shader{TryGet(*cpu_shader_addr)};
161 if (!shader) {
162 return CreateComputePipelineWithoutShader(*cpu_shader_addr);
163 }
164 const ComputePipelineCacheKey key{MakeComputePipelineKey(shader->unique_hash)};
165 const auto [pair, is_new]{compute_cache.try_emplace(key)};
166 auto& pipeline{pair->second};
167 if (!is_new) {
168 return &pipeline;
169 }
170 pipeline = CreateComputePipeline(shader);
171 shader->compute_users.push_back(key);
172 return &pipeline;
173}
174
175ComputePipeline PipelineCache::CreateComputePipeline(ShaderInfo* shader_info) {
176 const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()};
177 const auto& qmd{kepler_compute.launch_description};
178 Environment env{kepler_compute, gpu_memory, program_base};
179 if (const std::optional<u128> cached_hash{env.Analyze(qmd.program_start)}) {
180 // TODO: Load from cache
97 } 181 }
98 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); 182 const auto [info, code]{Shader::RecompileSPIRV(env, qmd.program_start)};
99 throw "Bad"; 183 shader_info->unique_hash = env.ComputeHash();
184 shader_info->size_bytes = env.ShaderSize();
185 return ComputePipeline{device, descriptor_pool, update_descriptor_queue, info,
186 BuildShader(device, code)};
100} 187}
101 188
102void PipelineCache::OnShaderRemoval(Shader*) {} 189ComputePipeline* PipelineCache::CreateComputePipelineWithoutShader(VAddr shader_cpu_addr) {
190 ShaderInfo shader;
191 ComputePipeline pipeline{CreateComputePipeline(&shader)};
192 const ComputePipelineCacheKey key{MakeComputePipelineKey(shader.unique_hash)};
193 shader.compute_users.push_back(key);
194 pipeline.AddRef();
195
196 const size_t size_bytes{shader.size_bytes};
197 Register(std::make_unique<ShaderInfo>(std::move(shader)), shader_cpu_addr, size_bytes);
198 return &compute_cache.emplace(key, std::move(pipeline)).first->second;
199}
200
201ComputePipelineCacheKey PipelineCache::MakeComputePipelineKey(u128 unique_hash) const {
202 const auto& qmd{kepler_compute.launch_description};
203 return {
204 .unique_hash = unique_hash,
205 .shared_memory_size = qmd.shared_alloc,
206 .workgroup_size{qmd.block_dim_x, qmd.block_dim_y, qmd.block_dim_z},
207 };
208}
209
210void PipelineCache::OnShaderRemoval(ShaderInfo* shader) {
211 for (const ComputePipelineCacheKey& key : shader->compute_users) {
212 const auto it = compute_cache.find(key);
213 ASSERT(it != compute_cache.end());
214
215 Pipeline& pipeline = it->second;
216 if (pipeline.RemoveRef()) {
217 // Wait for the pipeline to be free of GPU usage before destroying it
218 scheduler.Wait(pipeline.UsageTick());
219 compute_cache.erase(it);
220 }
221 }
222}
103 223
104} // namespace Vulkan 224} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index e3e63340d..eb35abc27 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -36,7 +36,7 @@ class VKUpdateDescriptorQueue;
36using Maxwell = Tegra::Engines::Maxwell3D::Regs; 36using Maxwell = Tegra::Engines::Maxwell3D::Regs;
37 37
38struct ComputePipelineCacheKey { 38struct ComputePipelineCacheKey {
39 GPUVAddr shader; 39 u128 unique_hash;
40 u32 shared_memory_size; 40 u32 shared_memory_size;
41 std::array<u32, 3> workgroup_size; 41 std::array<u32, 3> workgroup_size;
42 42
@@ -67,13 +67,13 @@ struct hash<Vulkan::ComputePipelineCacheKey> {
67 67
68namespace Vulkan { 68namespace Vulkan {
69 69
70class Shader { 70struct ShaderInfo {
71public: 71 u128 unique_hash{};
72 explicit Shader(); 72 size_t size_bytes{};
73 ~Shader(); 73 std::vector<ComputePipelineCacheKey> compute_users;
74}; 74};
75 75
76class PipelineCache final : public VideoCommon::ShaderCache<Shader> { 76class PipelineCache final : public VideoCommon::ShaderCache<ShaderInfo> {
77public: 77public:
78 explicit PipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu, 78 explicit PipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu,
79 Tegra::Engines::Maxwell3D& maxwell3d, 79 Tegra::Engines::Maxwell3D& maxwell3d,
@@ -83,12 +83,18 @@ public:
83 VKUpdateDescriptorQueue& update_descriptor_queue); 83 VKUpdateDescriptorQueue& update_descriptor_queue);
84 ~PipelineCache() override; 84 ~PipelineCache() override;
85 85
86 ComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key); 86 [[nodiscard]] ComputePipeline* CurrentComputePipeline();
87 87
88protected: 88protected:
89 void OnShaderRemoval(Shader* shader) final; 89 void OnShaderRemoval(ShaderInfo* shader) override;
90 90
91private: 91private:
92 ComputePipeline CreateComputePipeline(ShaderInfo* shader);
93
94 ComputePipeline* CreateComputePipelineWithoutShader(VAddr shader_cpu_addr);
95
96 ComputePipelineCacheKey MakeComputePipelineKey(u128 unique_hash) const;
97
92 Tegra::GPU& gpu; 98 Tegra::GPU& gpu;
93 Tegra::Engines::Maxwell3D& maxwell3d; 99 Tegra::Engines::Maxwell3D& maxwell3d;
94 Tegra::Engines::KeplerCompute& kepler_compute; 100 Tegra::Engines::KeplerCompute& kepler_compute;
@@ -99,13 +105,7 @@ private:
99 VKDescriptorPool& descriptor_pool; 105 VKDescriptorPool& descriptor_pool;
100 VKUpdateDescriptorQueue& update_descriptor_queue; 106 VKUpdateDescriptorQueue& update_descriptor_queue;
101 107
102 std::unique_ptr<Shader> null_shader; 108 std::unordered_map<ComputePipelineCacheKey, ComputePipeline> compute_cache;
103 std::unique_ptr<Shader> null_kernel;
104
105 std::array<Shader*, Maxwell::MaxShaderProgram> last_shaders{};
106
107 std::mutex pipeline_cache;
108 std::unordered_map<ComputePipelineCacheKey, std::unique_ptr<ComputePipeline>> compute_cache;
109}; 109};
110 110
111} // namespace Vulkan 111} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index f152297d9..b757454c4 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -36,6 +36,8 @@
36#include "video_core/vulkan_common/vulkan_device.h" 36#include "video_core/vulkan_common/vulkan_device.h"
37#include "video_core/vulkan_common/vulkan_wrapper.h" 37#include "video_core/vulkan_common/vulkan_wrapper.h"
38 38
39#pragma optimize("", off)
40
39namespace Vulkan { 41namespace Vulkan {
40 42
41using Maxwell = Tegra::Engines::Maxwell3D::Regs; 43using Maxwell = Tegra::Engines::Maxwell3D::Regs;
@@ -237,7 +239,26 @@ void RasterizerVulkan::Clear() {
237} 239}
238 240
239void RasterizerVulkan::DispatchCompute() { 241void RasterizerVulkan::DispatchCompute() {
240 UNREACHABLE_MSG("Not implemented"); 242 ComputePipeline* const pipeline{pipeline_cache.CurrentComputePipeline()};
243 if (!pipeline) {
244 return;
245 }
246 std::scoped_lock lock{buffer_cache.mutex};
247 update_descriptor_queue.Acquire();
248 pipeline->ConfigureBufferCache(buffer_cache);
249 const VkDescriptorSet descriptor_set{pipeline->UpdateDescriptorSet()};
250
251 const auto& qmd{kepler_compute.launch_description};
252 const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z};
253 const VkPipeline pipeline_handle{pipeline->Handle()};
254 const VkPipelineLayout pipeline_layout{pipeline->PipelineLayout()};
255 scheduler.Record(
256 [pipeline_handle, pipeline_layout, dim, descriptor_set](vk::CommandBuffer cmdbuf) {
257 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_handle);
258 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0,
259 descriptor_set, nullptr);
260 cmdbuf.Dispatch(dim[0], dim[1], dim[2]);
261 });
241} 262}
242 263
243void RasterizerVulkan::ResetCounter(VideoCore::QueryType type) { 264void RasterizerVulkan::ResetCounter(VideoCore::QueryType type) {
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 31017dc2b..3fd03b915 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -21,7 +21,6 @@
21#include "video_core/renderer_vulkan/vk_buffer_cache.h" 21#include "video_core/renderer_vulkan/vk_buffer_cache.h"
22#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 22#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
23#include "video_core/renderer_vulkan/vk_fence_manager.h" 23#include "video_core/renderer_vulkan/vk_fence_manager.h"
24#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
25#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 24#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
26#include "video_core/renderer_vulkan/vk_query_cache.h" 25#include "video_core/renderer_vulkan/vk_query_cache.h"
27#include "video_core/renderer_vulkan/vk_scheduler.h" 26#include "video_core/renderer_vulkan/vk_scheduler.h"
@@ -150,8 +149,6 @@ private:
150 BlitImageHelper blit_image; 149 BlitImageHelper blit_image;
151 ASTCDecoderPass astc_decoder_pass; 150 ASTCDecoderPass astc_decoder_pass;
152 151
153 GraphicsPipelineCacheKey graphics_key;
154
155 TextureCacheRuntime texture_cache_runtime; 152 TextureCacheRuntime texture_cache_runtime;
156 TextureCache texture_cache; 153 TextureCache texture_cache;
157 BufferCacheRuntime buffer_cache_runtime; 154 BufferCacheRuntime buffer_cache_runtime;
diff --git a/src/video_core/renderer_vulkan/vk_resource_pool.cpp b/src/video_core/renderer_vulkan/vk_resource_pool.cpp
index a8bf7bda8..2dd514968 100644
--- a/src/video_core/renderer_vulkan/vk_resource_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_resource_pool.cpp
@@ -10,18 +10,16 @@
10namespace Vulkan { 10namespace Vulkan {
11 11
12ResourcePool::ResourcePool(MasterSemaphore& master_semaphore_, size_t grow_step_) 12ResourcePool::ResourcePool(MasterSemaphore& master_semaphore_, size_t grow_step_)
13 : master_semaphore{master_semaphore_}, grow_step{grow_step_} {} 13 : master_semaphore{&master_semaphore_}, grow_step{grow_step_} {}
14
15ResourcePool::~ResourcePool() = default;
16 14
17size_t ResourcePool::CommitResource() { 15size_t ResourcePool::CommitResource() {
18 // Refresh semaphore to query updated results 16 // Refresh semaphore to query updated results
19 master_semaphore.Refresh(); 17 master_semaphore->Refresh();
20 const u64 gpu_tick = master_semaphore.KnownGpuTick(); 18 const u64 gpu_tick = master_semaphore->KnownGpuTick();
21 const auto search = [this, gpu_tick](size_t begin, size_t end) -> std::optional<size_t> { 19 const auto search = [this, gpu_tick](size_t begin, size_t end) -> std::optional<size_t> {
22 for (size_t iterator = begin; iterator < end; ++iterator) { 20 for (size_t iterator = begin; iterator < end; ++iterator) {
23 if (gpu_tick >= ticks[iterator]) { 21 if (gpu_tick >= ticks[iterator]) {
24 ticks[iterator] = master_semaphore.CurrentTick(); 22 ticks[iterator] = master_semaphore->CurrentTick();
25 return iterator; 23 return iterator;
26 } 24 }
27 } 25 }
@@ -36,7 +34,7 @@ size_t ResourcePool::CommitResource() {
36 // Both searches failed, the pool is full; handle it. 34 // Both searches failed, the pool is full; handle it.
37 const size_t free_resource = ManageOverflow(); 35 const size_t free_resource = ManageOverflow();
38 36
39 ticks[free_resource] = master_semaphore.CurrentTick(); 37 ticks[free_resource] = master_semaphore->CurrentTick();
40 found = free_resource; 38 found = free_resource;
41 } 39 }
42 } 40 }
diff --git a/src/video_core/renderer_vulkan/vk_resource_pool.h b/src/video_core/renderer_vulkan/vk_resource_pool.h
index 9d0bb3b4d..f0b80ad59 100644
--- a/src/video_core/renderer_vulkan/vk_resource_pool.h
+++ b/src/video_core/renderer_vulkan/vk_resource_pool.h
@@ -18,8 +18,16 @@ class MasterSemaphore;
18 */ 18 */
19class ResourcePool { 19class ResourcePool {
20public: 20public:
21 explicit ResourcePool() = default;
21 explicit ResourcePool(MasterSemaphore& master_semaphore, size_t grow_step); 22 explicit ResourcePool(MasterSemaphore& master_semaphore, size_t grow_step);
22 virtual ~ResourcePool(); 23
24 virtual ~ResourcePool() = default;
25
26 ResourcePool& operator=(ResourcePool&&) noexcept = default;
27 ResourcePool(ResourcePool&&) noexcept = default;
28
29 ResourcePool& operator=(const ResourcePool&) = default;
30 ResourcePool(const ResourcePool&) = default;
23 31
24protected: 32protected:
25 size_t CommitResource(); 33 size_t CommitResource();
@@ -34,7 +42,7 @@ private:
34 /// Allocates a new page of resources. 42 /// Allocates a new page of resources.
35 void Grow(); 43 void Grow();
36 44
37 MasterSemaphore& master_semaphore; 45 MasterSemaphore* master_semaphore{};
38 size_t grow_step = 0; ///< Number of new resources created after an overflow 46 size_t grow_step = 0; ///< Number of new resources created after an overflow
39 size_t hint_iterator = 0; ///< Hint to where the next free resources is likely to be found 47 size_t hint_iterator = 0; ///< Hint to where the next free resources is likely to be found
40 std::vector<u64> ticks; ///< Ticks for each resource 48 std::vector<u64> ticks; ///< Ticks for each resource