diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/shader_recompiler/environment.h | 11 | ||||
| -rw-r--r-- | src/shader_recompiler/file_environment.cpp | 4 | ||||
| -rw-r--r-- | src/shader_recompiler/file_environment.h | 4 | ||||
| -rw-r--r-- | src/shader_recompiler/stage.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 391 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.h | 34 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_render_pass_cache.cpp | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_render_pass_cache.h | 4 |
8 files changed, 347 insertions, 106 deletions
diff --git a/src/shader_recompiler/environment.h b/src/shader_recompiler/environment.h index 1fcaa56dd..6dec4b255 100644 --- a/src/shader_recompiler/environment.h +++ b/src/shader_recompiler/environment.h | |||
| @@ -3,8 +3,8 @@ | |||
| 3 | #include <array> | 3 | #include <array> |
| 4 | 4 | ||
| 5 | #include "common/common_types.h" | 5 | #include "common/common_types.h" |
| 6 | #include "shader_recompiler/stage.h" | ||
| 7 | #include "shader_recompiler/program_header.h" | 6 | #include "shader_recompiler/program_header.h" |
| 7 | #include "shader_recompiler/stage.h" | ||
| 8 | 8 | ||
| 9 | namespace Shader { | 9 | namespace Shader { |
| 10 | 10 | ||
| @@ -14,9 +14,9 @@ public: | |||
| 14 | 14 | ||
| 15 | [[nodiscard]] virtual u64 ReadInstruction(u32 address) = 0; | 15 | [[nodiscard]] virtual u64 ReadInstruction(u32 address) = 0; |
| 16 | 16 | ||
| 17 | [[nodiscard]] virtual u32 TextureBoundBuffer() = 0; | 17 | [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; |
| 18 | 18 | ||
| 19 | [[nodiscard]] virtual std::array<u32, 3> WorkgroupSize() = 0; | 19 | [[nodiscard]] virtual std::array<u32, 3> WorkgroupSize() const = 0; |
| 20 | 20 | ||
| 21 | [[nodiscard]] const ProgramHeader& SPH() const noexcept { | 21 | [[nodiscard]] const ProgramHeader& SPH() const noexcept { |
| 22 | return sph; | 22 | return sph; |
| @@ -26,9 +26,14 @@ public: | |||
| 26 | return stage; | 26 | return stage; |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | [[nodiscard]] u32 StartAddress() const noexcept { | ||
| 30 | return start_address; | ||
| 31 | } | ||
| 32 | |||
| 29 | protected: | 33 | protected: |
| 30 | ProgramHeader sph{}; | 34 | ProgramHeader sph{}; |
| 31 | Stage stage{}; | 35 | Stage stage{}; |
| 36 | u32 start_address{}; | ||
| 32 | }; | 37 | }; |
| 33 | 38 | ||
| 34 | } // namespace Shader | 39 | } // namespace Shader |
diff --git a/src/shader_recompiler/file_environment.cpp b/src/shader_recompiler/file_environment.cpp index 21700c72b..f2104f444 100644 --- a/src/shader_recompiler/file_environment.cpp +++ b/src/shader_recompiler/file_environment.cpp | |||
| @@ -39,11 +39,11 @@ u64 FileEnvironment::ReadInstruction(u32 offset) { | |||
| 39 | return data[offset / 8]; | 39 | return data[offset / 8]; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | u32 FileEnvironment::TextureBoundBuffer() { | 42 | u32 FileEnvironment::TextureBoundBuffer() const { |
| 43 | throw NotImplementedException("Texture bound buffer serialization"); | 43 | throw NotImplementedException("Texture bound buffer serialization"); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | std::array<u32, 3> FileEnvironment::WorkgroupSize() { | 46 | std::array<u32, 3> FileEnvironment::WorkgroupSize() const { |
| 47 | return {1, 1, 1}; | 47 | return {1, 1, 1}; |
| 48 | } | 48 | } |
| 49 | 49 | ||
diff --git a/src/shader_recompiler/file_environment.h b/src/shader_recompiler/file_environment.h index 62302bc8e..17640a622 100644 --- a/src/shader_recompiler/file_environment.h +++ b/src/shader_recompiler/file_environment.h | |||
| @@ -14,9 +14,9 @@ public: | |||
| 14 | 14 | ||
| 15 | u64 ReadInstruction(u32 offset) override; | 15 | u64 ReadInstruction(u32 offset) override; |
| 16 | 16 | ||
| 17 | u32 TextureBoundBuffer() override; | 17 | u32 TextureBoundBuffer() const override; |
| 18 | 18 | ||
| 19 | std::array<u32, 3> WorkgroupSize() override; | 19 | std::array<u32, 3> WorkgroupSize() const override; |
| 20 | 20 | ||
| 21 | private: | 21 | private: |
| 22 | std::vector<u64> data; | 22 | std::vector<u64> data; |
diff --git a/src/shader_recompiler/stage.h b/src/shader_recompiler/stage.h index fc6ce6043..7d4f2c0bb 100644 --- a/src/shader_recompiler/stage.h +++ b/src/shader_recompiler/stage.h | |||
| @@ -4,9 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 7 | namespace Shader { | 9 | namespace Shader { |
| 8 | 10 | ||
| 9 | enum class Stage { | 11 | enum class Stage : u32 { |
| 10 | Compute, | 12 | Compute, |
| 11 | VertexA, | 13 | VertexA, |
| 12 | VertexB, | 14 | VertexB, |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 75f7c1e61..41fc9588f 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -4,12 +4,15 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <cstddef> | 6 | #include <cstddef> |
| 7 | #include <fstream> | ||
| 7 | #include <memory> | 8 | #include <memory> |
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | 10 | ||
| 10 | #include "common/bit_cast.h" | 11 | #include "common/bit_cast.h" |
| 11 | #include "common/cityhash.h" | 12 | #include "common/cityhash.h" |
| 13 | #include "common/file_util.h" | ||
| 12 | #include "common/microprofile.h" | 14 | #include "common/microprofile.h" |
| 15 | #include "common/thread_worker.h" | ||
| 13 | #include "core/core.h" | 16 | #include "core/core.h" |
| 14 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 15 | #include "shader_recompiler/backend/spirv/emit_spirv.h" | 18 | #include "shader_recompiler/backend/spirv/emit_spirv.h" |
| @@ -37,18 +40,23 @@ | |||
| 37 | namespace Vulkan { | 40 | namespace Vulkan { |
| 38 | MICROPROFILE_DECLARE(Vulkan_PipelineCache); | 41 | MICROPROFILE_DECLARE(Vulkan_PipelineCache); |
| 39 | 42 | ||
| 40 | namespace { | 43 | template <typename Container> |
| 41 | using Shader::Backend::SPIRV::EmitSPIRV; | 44 | auto MakeSpan(Container& container) { |
| 45 | return std::span(container.data(), container.size()); | ||
| 46 | } | ||
| 42 | 47 | ||
| 43 | class GenericEnvironment : public Shader::Environment { | 48 | class GenericEnvironment : public Shader::Environment { |
| 44 | public: | 49 | public: |
| 45 | explicit GenericEnvironment() = default; | 50 | explicit GenericEnvironment() = default; |
| 46 | explicit GenericEnvironment(Tegra::MemoryManager& gpu_memory_, GPUVAddr program_base_) | 51 | explicit GenericEnvironment(Tegra::MemoryManager& gpu_memory_, GPUVAddr program_base_, |
| 47 | : gpu_memory{&gpu_memory_}, program_base{program_base_} {} | 52 | u32 start_address_) |
| 53 | : gpu_memory{&gpu_memory_}, program_base{program_base_} { | ||
| 54 | start_address = start_address_; | ||
| 55 | } | ||
| 48 | 56 | ||
| 49 | ~GenericEnvironment() override = default; | 57 | ~GenericEnvironment() override = default; |
| 50 | 58 | ||
| 51 | std::optional<u128> Analyze(u32 start_address) { | 59 | std::optional<u128> Analyze() { |
| 52 | const std::optional<u64> size{TryFindSize(start_address)}; | 60 | const std::optional<u64> size{TryFindSize(start_address)}; |
| 53 | if (!size) { | 61 | if (!size) { |
| 54 | return std::nullopt; | 62 | return std::nullopt; |
| @@ -66,11 +74,15 @@ public: | |||
| 66 | return read_highest - read_lowest + INST_SIZE; | 74 | return read_highest - read_lowest + INST_SIZE; |
| 67 | } | 75 | } |
| 68 | 76 | ||
| 77 | [[nodiscard]] bool CanBeSerialized() const noexcept { | ||
| 78 | return has_unbound_instructions; | ||
| 79 | } | ||
| 80 | |||
| 69 | [[nodiscard]] u128 CalculateHash() const { | 81 | [[nodiscard]] u128 CalculateHash() const { |
| 70 | const size_t size{ReadSize()}; | 82 | const size_t size{ReadSize()}; |
| 71 | auto data = std::make_unique<u64[]>(size); | 83 | const auto data{std::make_unique<char[]>(size)}; |
| 72 | gpu_memory->ReadBlock(program_base + read_lowest, data.get(), size); | 84 | gpu_memory->ReadBlock(program_base + read_lowest, data.get(), size); |
| 73 | return Common::CityHash128(reinterpret_cast<const char*>(data.get()), size); | 85 | return Common::CityHash128(data.get(), size); |
| 74 | } | 86 | } |
| 75 | 87 | ||
| 76 | u64 ReadInstruction(u32 address) final { | 88 | u64 ReadInstruction(u32 address) final { |
| @@ -80,9 +92,32 @@ public: | |||
| 80 | if (address >= cached_lowest && address < cached_highest) { | 92 | if (address >= cached_lowest && address < cached_highest) { |
| 81 | return code[address / INST_SIZE]; | 93 | return code[address / INST_SIZE]; |
| 82 | } | 94 | } |
| 95 | has_unbound_instructions = true; | ||
| 83 | return gpu_memory->Read<u64>(program_base + address); | 96 | return gpu_memory->Read<u64>(program_base + address); |
| 84 | } | 97 | } |
| 85 | 98 | ||
| 99 | void Serialize(std::ofstream& file) const { | ||
| 100 | const u64 code_size{static_cast<u64>(ReadSize())}; | ||
| 101 | const auto data{std::make_unique<char[]>(code_size)}; | ||
| 102 | gpu_memory->ReadBlock(program_base + read_lowest, data.get(), code_size); | ||
| 103 | |||
| 104 | const u32 texture_bound{TextureBoundBuffer()}; | ||
| 105 | |||
| 106 | file.write(reinterpret_cast<const char*>(&code_size), sizeof(code_size)) | ||
| 107 | .write(reinterpret_cast<const char*>(&texture_bound), sizeof(texture_bound)) | ||
| 108 | .write(reinterpret_cast<const char*>(&start_address), sizeof(start_address)) | ||
| 109 | .write(reinterpret_cast<const char*>(&read_lowest), sizeof(read_lowest)) | ||
| 110 | .write(reinterpret_cast<const char*>(&read_highest), sizeof(read_highest)) | ||
| 111 | .write(reinterpret_cast<const char*>(&stage), sizeof(stage)) | ||
| 112 | .write(data.get(), code_size); | ||
| 113 | if (stage == Shader::Stage::Compute) { | ||
| 114 | const std::array<u32, 3> workgroup_size{WorkgroupSize()}; | ||
| 115 | file.write(reinterpret_cast<const char*>(&workgroup_size), sizeof(workgroup_size)); | ||
| 116 | } else { | ||
| 117 | file.write(reinterpret_cast<const char*>(&sph), sizeof(sph)); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 86 | protected: | 121 | protected: |
| 87 | static constexpr size_t INST_SIZE = sizeof(u64); | 122 | static constexpr size_t INST_SIZE = sizeof(u64); |
| 88 | 123 | ||
| @@ -122,16 +157,22 @@ protected: | |||
| 122 | 157 | ||
| 123 | u32 cached_lowest = std::numeric_limits<u32>::max(); | 158 | u32 cached_lowest = std::numeric_limits<u32>::max(); |
| 124 | u32 cached_highest = 0; | 159 | u32 cached_highest = 0; |
| 160 | |||
| 161 | bool has_unbound_instructions = false; | ||
| 125 | }; | 162 | }; |
| 126 | 163 | ||
| 164 | namespace { | ||
| 165 | using Shader::Backend::SPIRV::EmitSPIRV; | ||
| 166 | using Shader::Maxwell::TranslateProgram; | ||
| 167 | |||
| 127 | class GraphicsEnvironment final : public GenericEnvironment { | 168 | class GraphicsEnvironment final : public GenericEnvironment { |
| 128 | public: | 169 | public: |
| 129 | explicit GraphicsEnvironment() = default; | 170 | explicit GraphicsEnvironment() = default; |
| 130 | explicit GraphicsEnvironment(Tegra::Engines::Maxwell3D& maxwell3d_, | 171 | explicit GraphicsEnvironment(Tegra::Engines::Maxwell3D& maxwell3d_, |
| 131 | Tegra::MemoryManager& gpu_memory_, Maxwell::ShaderProgram program, | 172 | Tegra::MemoryManager& gpu_memory_, Maxwell::ShaderProgram program, |
| 132 | GPUVAddr program_base_, u32 start_offset) | 173 | GPUVAddr program_base_, u32 start_address_) |
| 133 | : GenericEnvironment{gpu_memory_, program_base_}, maxwell3d{&maxwell3d_} { | 174 | : GenericEnvironment{gpu_memory_, program_base_, start_address_}, maxwell3d{&maxwell3d_} { |
| 134 | gpu_memory->ReadBlock(program_base + start_offset, &sph, sizeof(sph)); | 175 | gpu_memory->ReadBlock(program_base + start_address, &sph, sizeof(sph)); |
| 135 | switch (program) { | 176 | switch (program) { |
| 136 | case Maxwell::ShaderProgram::VertexA: | 177 | case Maxwell::ShaderProgram::VertexA: |
| 137 | stage = Shader::Stage::VertexA; | 178 | stage = Shader::Stage::VertexA; |
| @@ -158,11 +199,11 @@ public: | |||
| 158 | 199 | ||
| 159 | ~GraphicsEnvironment() override = default; | 200 | ~GraphicsEnvironment() override = default; |
| 160 | 201 | ||
| 161 | u32 TextureBoundBuffer() override { | 202 | u32 TextureBoundBuffer() const override { |
| 162 | return maxwell3d->regs.tex_cb_index; | 203 | return maxwell3d->regs.tex_cb_index; |
| 163 | } | 204 | } |
| 164 | 205 | ||
| 165 | std::array<u32, 3> WorkgroupSize() override { | 206 | std::array<u32, 3> WorkgroupSize() const override { |
| 166 | throw Shader::LogicError("Requesting workgroup size in a graphics stage"); | 207 | throw Shader::LogicError("Requesting workgroup size in a graphics stage"); |
| 167 | } | 208 | } |
| 168 | 209 | ||
| @@ -174,18 +215,20 @@ class ComputeEnvironment final : public GenericEnvironment { | |||
| 174 | public: | 215 | public: |
| 175 | explicit ComputeEnvironment() = default; | 216 | explicit ComputeEnvironment() = default; |
| 176 | explicit ComputeEnvironment(Tegra::Engines::KeplerCompute& kepler_compute_, | 217 | explicit ComputeEnvironment(Tegra::Engines::KeplerCompute& kepler_compute_, |
| 177 | Tegra::MemoryManager& gpu_memory_, GPUVAddr program_base_) | 218 | Tegra::MemoryManager& gpu_memory_, GPUVAddr program_base_, |
| 178 | : GenericEnvironment{gpu_memory_, program_base_}, kepler_compute{&kepler_compute_} { | 219 | u32 start_address_) |
| 220 | : GenericEnvironment{gpu_memory_, program_base_, start_address_}, kepler_compute{ | ||
| 221 | &kepler_compute_} { | ||
| 179 | stage = Shader::Stage::Compute; | 222 | stage = Shader::Stage::Compute; |
| 180 | } | 223 | } |
| 181 | 224 | ||
| 182 | ~ComputeEnvironment() override = default; | 225 | ~ComputeEnvironment() override = default; |
| 183 | 226 | ||
| 184 | u32 TextureBoundBuffer() override { | 227 | u32 TextureBoundBuffer() const override { |
| 185 | return kepler_compute->regs.tex_cb_index; | 228 | return kepler_compute->regs.tex_cb_index; |
| 186 | } | 229 | } |
| 187 | 230 | ||
| 188 | std::array<u32, 3> WorkgroupSize() override { | 231 | std::array<u32, 3> WorkgroupSize() const override { |
| 189 | const auto& qmd{kepler_compute->launch_description}; | 232 | const auto& qmd{kepler_compute->launch_description}; |
| 190 | return {qmd.block_dim_x, qmd.block_dim_y, qmd.block_dim_z}; | 233 | return {qmd.block_dim_x, qmd.block_dim_y, qmd.block_dim_z}; |
| 191 | } | 234 | } |
| @@ -193,8 +236,174 @@ public: | |||
| 193 | private: | 236 | private: |
| 194 | Tegra::Engines::KeplerCompute* kepler_compute{}; | 237 | Tegra::Engines::KeplerCompute* kepler_compute{}; |
| 195 | }; | 238 | }; |
| 239 | |||
| 240 | void SerializePipeline(std::span<const char> key, std::span<const GenericEnvironment* const> envs, | ||
| 241 | std::ofstream& file) { | ||
| 242 | if (!std::ranges::all_of(envs, &GenericEnvironment::CanBeSerialized)) { | ||
| 243 | return; | ||
| 244 | } | ||
| 245 | const u32 num_envs{static_cast<u32>(envs.size())}; | ||
| 246 | file.write(reinterpret_cast<const char*>(&num_envs), sizeof(num_envs)); | ||
| 247 | for (const GenericEnvironment* const env : envs) { | ||
| 248 | env->Serialize(file); | ||
| 249 | } | ||
| 250 | file.write(key.data(), key.size_bytes()); | ||
| 251 | } | ||
| 252 | |||
| 253 | template <typename Key, typename Envs> | ||
| 254 | void SerializePipeline(const Key& key, const Envs& envs, const std::string& filename) { | ||
| 255 | try { | ||
| 256 | std::ofstream file; | ||
| 257 | file.exceptions(std::ifstream::failbit); | ||
| 258 | Common::FS::OpenFStream(file, filename, std::ios::binary | std::ios::app); | ||
| 259 | if (!file.is_open()) { | ||
| 260 | LOG_ERROR(Common_Filesystem, "Failed to open pipeline cache file {}", filename); | ||
| 261 | return; | ||
| 262 | } | ||
| 263 | if (file.tellp() == 0) { | ||
| 264 | // Write header... | ||
| 265 | } | ||
| 266 | const std::span key_span(reinterpret_cast<const char*>(&key), sizeof(key)); | ||
| 267 | SerializePipeline(key_span, MakeSpan(envs), file); | ||
| 268 | |||
| 269 | } catch (const std::ios_base::failure& e) { | ||
| 270 | LOG_ERROR(Common_Filesystem, "{}", e.what()); | ||
| 271 | if (!Common::FS::Delete(filename)) { | ||
| 272 | LOG_ERROR(Common_Filesystem, "Failed to delete pipeline cache file {}", filename); | ||
| 273 | } | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | class FileEnvironment final : public Shader::Environment { | ||
| 278 | public: | ||
| 279 | void Deserialize(std::ifstream& file) { | ||
| 280 | u64 code_size{}; | ||
| 281 | file.read(reinterpret_cast<char*>(&code_size), sizeof(code_size)) | ||
| 282 | .read(reinterpret_cast<char*>(&texture_bound), sizeof(texture_bound)) | ||
| 283 | .read(reinterpret_cast<char*>(&start_address), sizeof(start_address)) | ||
| 284 | .read(reinterpret_cast<char*>(&read_lowest), sizeof(read_lowest)) | ||
| 285 | .read(reinterpret_cast<char*>(&read_highest), sizeof(read_highest)) | ||
| 286 | .read(reinterpret_cast<char*>(&stage), sizeof(stage)); | ||
| 287 | code = std::make_unique<u64[]>(Common::DivCeil(code_size, sizeof(u64))); | ||
| 288 | file.read(reinterpret_cast<char*>(code.get()), code_size); | ||
| 289 | if (stage == Shader::Stage::Compute) { | ||
| 290 | file.read(reinterpret_cast<char*>(&workgroup_size), sizeof(workgroup_size)); | ||
| 291 | } else { | ||
| 292 | file.read(reinterpret_cast<char*>(&sph), sizeof(sph)); | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | u64 ReadInstruction(u32 address) override { | ||
| 297 | if (address < read_lowest || address > read_highest) { | ||
| 298 | throw Shader::LogicError("Out of bounds address {}", address); | ||
| 299 | } | ||
| 300 | return code[(address - read_lowest) / sizeof(u64)]; | ||
| 301 | } | ||
| 302 | |||
| 303 | u32 TextureBoundBuffer() const override { | ||
| 304 | return texture_bound; | ||
| 305 | } | ||
| 306 | |||
| 307 | std::array<u32, 3> WorkgroupSize() const override { | ||
| 308 | return workgroup_size; | ||
| 309 | } | ||
| 310 | |||
| 311 | private: | ||
| 312 | std::unique_ptr<u64[]> code; | ||
| 313 | std::array<u32, 3> workgroup_size{}; | ||
| 314 | u32 texture_bound{}; | ||
| 315 | u32 read_lowest{}; | ||
| 316 | u32 read_highest{}; | ||
| 317 | }; | ||
| 196 | } // Anonymous namespace | 318 | } // Anonymous namespace |
| 197 | 319 | ||
| 320 | void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||
| 321 | const VideoCore::DiskResourceLoadCallback& callback) { | ||
| 322 | if (title_id == 0) { | ||
| 323 | return; | ||
| 324 | } | ||
| 325 | std::string shader_dir{Common::FS::GetUserPath(Common::FS::UserPath::ShaderDir)}; | ||
| 326 | std::string base_dir{shader_dir + "/vulkan"}; | ||
| 327 | std::string transferable_dir{base_dir + "/transferable"}; | ||
| 328 | std::string precompiled_dir{base_dir + "/precompiled"}; | ||
| 329 | if (!Common::FS::CreateDir(shader_dir) || !Common::FS::CreateDir(base_dir) || | ||
| 330 | !Common::FS::CreateDir(transferable_dir) || !Common::FS::CreateDir(precompiled_dir)) { | ||
| 331 | LOG_ERROR(Common_Filesystem, "Failed to create pipeline cache directories"); | ||
| 332 | return; | ||
| 333 | } | ||
| 334 | pipeline_cache_filename = fmt::format("{}/{:016x}.bin", transferable_dir, title_id); | ||
| 335 | |||
| 336 | Common::ThreadWorker worker(11, "PipelineBuilder"); | ||
| 337 | std::mutex cache_mutex; | ||
| 338 | struct { | ||
| 339 | size_t total{0}; | ||
| 340 | size_t built{0}; | ||
| 341 | bool has_loaded{false}; | ||
| 342 | } state; | ||
| 343 | |||
| 344 | std::ifstream file; | ||
| 345 | Common::FS::OpenFStream(file, pipeline_cache_filename, std::ios::binary | std::ios::ate); | ||
| 346 | if (!file.is_open()) { | ||
| 347 | return; | ||
| 348 | } | ||
| 349 | file.exceptions(std::ifstream::failbit); | ||
| 350 | const auto end{file.tellg()}; | ||
| 351 | file.seekg(0, std::ios::beg); | ||
| 352 | // Read header... | ||
| 353 | |||
| 354 | while (file.tellg() != end) { | ||
| 355 | if (stop_loading) { | ||
| 356 | return; | ||
| 357 | } | ||
| 358 | u32 num_envs{}; | ||
| 359 | file.read(reinterpret_cast<char*>(&num_envs), sizeof(num_envs)); | ||
| 360 | auto envs{std::make_shared<std::vector<FileEnvironment>>(num_envs)}; | ||
| 361 | for (FileEnvironment& env : *envs) { | ||
| 362 | env.Deserialize(file); | ||
| 363 | } | ||
| 364 | if (envs->front().ShaderStage() == Shader::Stage::Compute) { | ||
| 365 | ComputePipelineCacheKey key; | ||
| 366 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); | ||
| 367 | |||
| 368 | worker.QueueWork([this, key, envs, &cache_mutex, &state, &callback] { | ||
| 369 | ShaderPools pools; | ||
| 370 | ComputePipeline pipeline{CreateComputePipeline(pools, key, envs->front())}; | ||
| 371 | |||
| 372 | std::lock_guard lock{cache_mutex}; | ||
| 373 | compute_cache.emplace(key, std::move(pipeline)); | ||
| 374 | if (state.has_loaded) { | ||
| 375 | callback(VideoCore::LoadCallbackStage::Build, ++state.built, state.total); | ||
| 376 | } | ||
| 377 | }); | ||
| 378 | } else { | ||
| 379 | GraphicsPipelineCacheKey key; | ||
| 380 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); | ||
| 381 | |||
| 382 | worker.QueueWork([this, key, envs, &cache_mutex, &state, &callback] { | ||
| 383 | ShaderPools pools; | ||
| 384 | boost::container::static_vector<Shader::Environment*, 5> env_ptrs; | ||
| 385 | for (auto& env : *envs) { | ||
| 386 | env_ptrs.push_back(&env); | ||
| 387 | } | ||
| 388 | GraphicsPipeline pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs))}; | ||
| 389 | |||
| 390 | std::lock_guard lock{cache_mutex}; | ||
| 391 | graphics_cache.emplace(key, std::move(pipeline)); | ||
| 392 | if (state.has_loaded) { | ||
| 393 | callback(VideoCore::LoadCallbackStage::Build, ++state.built, state.total); | ||
| 394 | } | ||
| 395 | }); | ||
| 396 | } | ||
| 397 | ++state.total; | ||
| 398 | } | ||
| 399 | { | ||
| 400 | std::lock_guard lock{cache_mutex}; | ||
| 401 | callback(VideoCore::LoadCallbackStage::Build, 0, state.total); | ||
| 402 | state.has_loaded = true; | ||
| 403 | } | ||
| 404 | worker.WaitForRequests(); | ||
| 405 | } | ||
| 406 | |||
| 198 | size_t ComputePipelineCacheKey::Hash() const noexcept { | 407 | size_t ComputePipelineCacheKey::Hash() const noexcept { |
| 199 | const u64 hash = Common::CityHash64(reinterpret_cast<const char*>(this), sizeof *this); | 408 | const u64 hash = Common::CityHash64(reinterpret_cast<const char*>(this), sizeof *this); |
| 200 | return static_cast<size_t>(hash); | 409 | return static_cast<size_t>(hash); |
| @@ -279,17 +488,22 @@ ComputePipeline* PipelineCache::CurrentComputePipeline() { | |||
| 279 | if (!cpu_shader_addr) { | 488 | if (!cpu_shader_addr) { |
| 280 | return nullptr; | 489 | return nullptr; |
| 281 | } | 490 | } |
| 282 | ShaderInfo* const shader{TryGet(*cpu_shader_addr)}; | 491 | const ShaderInfo* shader{TryGet(*cpu_shader_addr)}; |
| 283 | if (!shader) { | 492 | if (!shader) { |
| 284 | return CreateComputePipelineWithoutShader(*cpu_shader_addr); | 493 | ComputeEnvironment env{kepler_compute, gpu_memory, program_base, qmd.program_start}; |
| 494 | shader = MakeShaderInfo(env, *cpu_shader_addr); | ||
| 285 | } | 495 | } |
| 286 | const ComputePipelineCacheKey key{MakeComputePipelineKey(shader->unique_hash)}; | 496 | const ComputePipelineCacheKey key{ |
| 497 | .unique_hash = shader->unique_hash, | ||
| 498 | .shared_memory_size = qmd.shared_alloc, | ||
| 499 | .workgroup_size{qmd.block_dim_x, qmd.block_dim_y, qmd.block_dim_z}, | ||
| 500 | }; | ||
| 287 | const auto [pair, is_new]{compute_cache.try_emplace(key)}; | 501 | const auto [pair, is_new]{compute_cache.try_emplace(key)}; |
| 288 | auto& pipeline{pair->second}; | 502 | auto& pipeline{pair->second}; |
| 289 | if (!is_new) { | 503 | if (!is_new) { |
| 290 | return &pipeline; | 504 | return &pipeline; |
| 291 | } | 505 | } |
| 292 | pipeline = CreateComputePipeline(shader); | 506 | pipeline = CreateComputePipeline(key, shader); |
| 293 | return &pipeline; | 507 | return &pipeline; |
| 294 | } | 508 | } |
| 295 | 509 | ||
| @@ -310,26 +524,25 @@ bool PipelineCache::RefreshStages() { | |||
| 310 | } | 524 | } |
| 311 | const ShaderInfo* shader_info{TryGet(*cpu_shader_addr)}; | 525 | const ShaderInfo* shader_info{TryGet(*cpu_shader_addr)}; |
| 312 | if (!shader_info) { | 526 | if (!shader_info) { |
| 313 | const u32 offset{shader_config.offset}; | 527 | const u32 start_address{shader_config.offset}; |
| 314 | shader_info = MakeShaderInfo(program, base_addr, offset, *cpu_shader_addr); | 528 | GraphicsEnvironment env{maxwell3d, gpu_memory, program, base_addr, start_address}; |
| 529 | shader_info = MakeShaderInfo(env, *cpu_shader_addr); | ||
| 315 | } | 530 | } |
| 316 | graphics_key.unique_hashes[index] = shader_info->unique_hash; | 531 | graphics_key.unique_hashes[index] = shader_info->unique_hash; |
| 317 | } | 532 | } |
| 318 | return true; | 533 | return true; |
| 319 | } | 534 | } |
| 320 | 535 | ||
| 321 | const ShaderInfo* PipelineCache::MakeShaderInfo(Maxwell::ShaderProgram program, GPUVAddr base_addr, | 536 | const ShaderInfo* PipelineCache::MakeShaderInfo(GenericEnvironment& env, VAddr cpu_addr) { |
| 322 | u32 start_address, VAddr cpu_addr) { | ||
| 323 | GraphicsEnvironment env{maxwell3d, gpu_memory, program, base_addr, start_address}; | ||
| 324 | auto info = std::make_unique<ShaderInfo>(); | 537 | auto info = std::make_unique<ShaderInfo>(); |
| 325 | if (const std::optional<u128> cached_hash{env.Analyze(start_address)}) { | 538 | if (const std::optional<u128> cached_hash{env.Analyze()}) { |
| 326 | info->unique_hash = *cached_hash; | 539 | info->unique_hash = *cached_hash; |
| 327 | info->size_bytes = env.CachedSize(); | 540 | info->size_bytes = env.CachedSize(); |
| 328 | } else { | 541 | } else { |
| 329 | // Slow path, not really hit on commercial games | 542 | // Slow path, not really hit on commercial games |
| 330 | // Build a control flow graph to get the real shader size | 543 | // Build a control flow graph to get the real shader size |
| 331 | flow_block_pool.ReleaseContents(); | 544 | main_pools.flow_block.ReleaseContents(); |
| 332 | Shader::Maxwell::Flow::CFG cfg{env, flow_block_pool, start_address}; | 545 | Shader::Maxwell::Flow::CFG cfg{env, main_pools.flow_block, env.StartAddress()}; |
| 333 | info->unique_hash = env.CalculateHash(); | 546 | info->unique_hash = env.CalculateHash(); |
| 334 | info->size_bytes = env.ReadSize(); | 547 | info->size_bytes = env.ReadSize(); |
| 335 | } | 548 | } |
| @@ -339,100 +552,100 @@ const ShaderInfo* PipelineCache::MakeShaderInfo(Maxwell::ShaderProgram program, | |||
| 339 | return result; | 552 | return result; |
| 340 | } | 553 | } |
| 341 | 554 | ||
| 342 | GraphicsPipeline PipelineCache::CreateGraphicsPipeline() { | 555 | GraphicsPipeline PipelineCache::CreateGraphicsPipeline(ShaderPools& pools, |
| 343 | flow_block_pool.ReleaseContents(); | 556 | const GraphicsPipelineCacheKey& key, |
| 344 | inst_pool.ReleaseContents(); | 557 | std::span<Shader::Environment* const> envs) { |
| 345 | block_pool.ReleaseContents(); | 558 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); |
| 346 | 559 | size_t env_index{0}; | |
| 347 | std::array<GraphicsEnvironment, Maxwell::MaxShaderProgram> envs; | ||
| 348 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; | 560 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; |
| 349 | |||
| 350 | const GPUVAddr base_addr{maxwell3d.regs.code_address.CodeAddress()}; | ||
| 351 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { | 561 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { |
| 352 | if (graphics_key.unique_hashes[index] == u128{}) { | 562 | if (key.unique_hashes[index] == u128{}) { |
| 353 | continue; | 563 | continue; |
| 354 | } | 564 | } |
| 355 | const auto program{static_cast<Maxwell::ShaderProgram>(index)}; | 565 | Shader::Environment& env{*envs[env_index]}; |
| 356 | GraphicsEnvironment& env{envs[index]}; | 566 | ++env_index; |
| 357 | const u32 start_address{maxwell3d.regs.shader_config[index].offset}; | ||
| 358 | env = GraphicsEnvironment{maxwell3d, gpu_memory, program, base_addr, start_address}; | ||
| 359 | 567 | ||
| 360 | const u32 cfg_offset = start_address + sizeof(Shader::ProgramHeader); | 568 | const u32 cfg_offset{env.StartAddress() + sizeof(Shader::ProgramHeader)}; |
| 361 | Shader::Maxwell::Flow::CFG cfg(env, flow_block_pool, cfg_offset); | 569 | Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset); |
| 362 | programs[index] = Shader::Maxwell::TranslateProgram(inst_pool, block_pool, env, cfg); | 570 | programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg); |
| 363 | } | 571 | } |
| 364 | std::array<const Shader::Info*, Maxwell::MaxShaderStage> infos{}; | 572 | std::array<const Shader::Info*, Maxwell::MaxShaderStage> infos{}; |
| 365 | std::array<vk::ShaderModule, Maxwell::MaxShaderStage> modules; | 573 | std::array<vk::ShaderModule, Maxwell::MaxShaderStage> modules; |
| 366 | 574 | ||
| 367 | u32 binding{0}; | 575 | u32 binding{0}; |
| 576 | env_index = 0; | ||
| 368 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { | 577 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { |
| 369 | if (graphics_key.unique_hashes[index] == u128{}) { | 578 | if (key.unique_hashes[index] == u128{}) { |
| 370 | continue; | 579 | continue; |
| 371 | } | 580 | } |
| 372 | UNIMPLEMENTED_IF(index == 0); | 581 | UNIMPLEMENTED_IF(index == 0); |
| 373 | 582 | ||
| 374 | GraphicsEnvironment& env{envs[index]}; | ||
| 375 | Shader::IR::Program& program{programs[index]}; | 583 | Shader::IR::Program& program{programs[index]}; |
| 376 | |||
| 377 | const size_t stage_index{index - 1}; | 584 | const size_t stage_index{index - 1}; |
| 378 | infos[stage_index] = &program.info; | 585 | infos[stage_index] = &program.info; |
| 379 | std::vector<u32> code{EmitSPIRV(profile, env, program, binding)}; | ||
| 380 | 586 | ||
| 381 | FILE* file = fopen("D:\\shader.spv", "wb"); | 587 | Shader::Environment& env{*envs[env_index]}; |
| 382 | fwrite(code.data(), 4, code.size(), file); | 588 | ++env_index; |
| 383 | fclose(file); | ||
| 384 | std::system("spirv-cross --vulkan-semantics D:\\shader.spv"); | ||
| 385 | 589 | ||
| 590 | const std::vector<u32> code{EmitSPIRV(profile, env, program, binding)}; | ||
| 386 | modules[stage_index] = BuildShader(device, code); | 591 | modules[stage_index] = BuildShader(device, code); |
| 387 | } | 592 | } |
| 388 | return GraphicsPipeline(maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, device, | 593 | return GraphicsPipeline(maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, device, |
| 389 | descriptor_pool, update_descriptor_queue, render_pass_cache, | 594 | descriptor_pool, update_descriptor_queue, render_pass_cache, key.state, |
| 390 | graphics_key.state, std::move(modules), infos); | 595 | std::move(modules), infos); |
| 391 | } | 596 | } |
| 392 | 597 | ||
| 393 | ComputePipeline PipelineCache::CreateComputePipeline(ShaderInfo* shader_info) { | 598 | GraphicsPipeline PipelineCache::CreateGraphicsPipeline() { |
| 599 | main_pools.ReleaseContents(); | ||
| 600 | |||
| 601 | std::array<GraphicsEnvironment, Maxwell::MaxShaderProgram> graphics_envs; | ||
| 602 | boost::container::static_vector<GenericEnvironment*, Maxwell::MaxShaderProgram> generic_envs; | ||
| 603 | boost::container::static_vector<Shader::Environment*, Maxwell::MaxShaderProgram> envs; | ||
| 604 | |||
| 605 | const GPUVAddr base_addr{maxwell3d.regs.code_address.CodeAddress()}; | ||
| 606 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { | ||
| 607 | if (graphics_key.unique_hashes[index] == u128{}) { | ||
| 608 | continue; | ||
| 609 | } | ||
| 610 | const auto program{static_cast<Maxwell::ShaderProgram>(index)}; | ||
| 611 | GraphicsEnvironment& env{graphics_envs[index]}; | ||
| 612 | const u32 start_address{maxwell3d.regs.shader_config[index].offset}; | ||
| 613 | env = GraphicsEnvironment{maxwell3d, gpu_memory, program, base_addr, start_address}; | ||
| 614 | generic_envs.push_back(&env); | ||
| 615 | envs.push_back(&env); | ||
| 616 | } | ||
| 617 | GraphicsPipeline pipeline{CreateGraphicsPipeline(main_pools, graphics_key, MakeSpan(envs))}; | ||
| 618 | if (!pipeline_cache_filename.empty()) { | ||
| 619 | SerializePipeline(graphics_key, generic_envs, pipeline_cache_filename); | ||
| 620 | } | ||
| 621 | return pipeline; | ||
| 622 | } | ||
| 623 | |||
| 624 | ComputePipeline PipelineCache::CreateComputePipeline(const ComputePipelineCacheKey& key, | ||
| 625 | const ShaderInfo* shader) { | ||
| 394 | const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()}; | 626 | const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()}; |
| 395 | const auto& qmd{kepler_compute.launch_description}; | 627 | const auto& qmd{kepler_compute.launch_description}; |
| 396 | ComputeEnvironment env{kepler_compute, gpu_memory, program_base}; | 628 | ComputeEnvironment env{kepler_compute, gpu_memory, program_base, qmd.program_start}; |
| 397 | if (const std::optional<u128> cached_hash{env.Analyze(qmd.program_start)}) { | 629 | main_pools.ReleaseContents(); |
| 398 | // TODO: Load from cache | 630 | ComputePipeline pipeline{CreateComputePipeline(main_pools, key, env)}; |
| 631 | if (!pipeline_cache_filename.empty()) { | ||
| 632 | SerializePipeline(key, std::array<const GenericEnvironment*, 1>{&env}, | ||
| 633 | pipeline_cache_filename); | ||
| 399 | } | 634 | } |
| 400 | flow_block_pool.ReleaseContents(); | 635 | return pipeline; |
| 401 | inst_pool.ReleaseContents(); | 636 | } |
| 402 | block_pool.ReleaseContents(); | 637 | |
| 638 | ComputePipeline PipelineCache::CreateComputePipeline(ShaderPools& pools, | ||
| 639 | const ComputePipelineCacheKey& key, | ||
| 640 | Shader::Environment& env) const { | ||
| 641 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); | ||
| 403 | 642 | ||
| 404 | Shader::Maxwell::Flow::CFG cfg{env, flow_block_pool, qmd.program_start}; | 643 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; |
| 405 | Shader::IR::Program program{Shader::Maxwell::TranslateProgram(inst_pool, block_pool, env, cfg)}; | 644 | Shader::IR::Program program{TranslateProgram(pools.inst, pools.block, env, cfg)}; |
| 406 | u32 binding{0}; | 645 | u32 binding{0}; |
| 407 | std::vector<u32> code{EmitSPIRV(profile, env, program, binding)}; | 646 | std::vector<u32> code{EmitSPIRV(profile, env, program, binding)}; |
| 408 | /* | ||
| 409 | FILE* file = fopen("D:\\shader.spv", "wb"); | ||
| 410 | fwrite(code.data(), 4, code.size(), file); | ||
| 411 | fclose(file); | ||
| 412 | std::system("spirv-dis D:\\shader.spv"); | ||
| 413 | */ | ||
| 414 | shader_info->unique_hash = env.CalculateHash(); | ||
| 415 | shader_info->size_bytes = env.ReadSize(); | ||
| 416 | return ComputePipeline{device, descriptor_pool, update_descriptor_queue, program.info, | 647 | return ComputePipeline{device, descriptor_pool, update_descriptor_queue, program.info, |
| 417 | BuildShader(device, code)}; | 648 | BuildShader(device, code)}; |
| 418 | } | 649 | } |
| 419 | 650 | ||
| 420 | ComputePipeline* PipelineCache::CreateComputePipelineWithoutShader(VAddr shader_cpu_addr) { | ||
| 421 | ShaderInfo shader; | ||
| 422 | ComputePipeline pipeline{CreateComputePipeline(&shader)}; | ||
| 423 | const ComputePipelineCacheKey key{MakeComputePipelineKey(shader.unique_hash)}; | ||
| 424 | const size_t size_bytes{shader.size_bytes}; | ||
| 425 | Register(std::make_unique<ShaderInfo>(std::move(shader)), shader_cpu_addr, size_bytes); | ||
| 426 | return &compute_cache.emplace(key, std::move(pipeline)).first->second; | ||
| 427 | } | ||
| 428 | |||
| 429 | ComputePipelineCacheKey PipelineCache::MakeComputePipelineKey(u128 unique_hash) const { | ||
| 430 | const auto& qmd{kepler_compute.launch_description}; | ||
| 431 | return { | ||
| 432 | .unique_hash = unique_hash, | ||
| 433 | .shared_memory_size = qmd.shared_alloc, | ||
| 434 | .workgroup_size{qmd.block_dim_x, qmd.block_dim_y, qmd.block_dim_z}, | ||
| 435 | }; | ||
| 436 | } | ||
| 437 | |||
| 438 | } // namespace Vulkan | 651 | } // 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 60fb976df..2ecb68bdc 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <iosfwd> | ||
| 9 | #include <memory> | 10 | #include <memory> |
| 10 | #include <type_traits> | 11 | #include <type_traits> |
| 11 | #include <unordered_map> | 12 | #include <unordered_map> |
| @@ -96,6 +97,7 @@ namespace Vulkan { | |||
| 96 | 97 | ||
| 97 | class ComputePipeline; | 98 | class ComputePipeline; |
| 98 | class Device; | 99 | class Device; |
| 100 | class GenericEnvironment; | ||
| 99 | class RasterizerVulkan; | 101 | class RasterizerVulkan; |
| 100 | class RenderPassCache; | 102 | class RenderPassCache; |
| 101 | class VKDescriptorPool; | 103 | class VKDescriptorPool; |
| @@ -107,6 +109,18 @@ struct ShaderInfo { | |||
| 107 | size_t size_bytes{}; | 109 | size_t size_bytes{}; |
| 108 | }; | 110 | }; |
| 109 | 111 | ||
| 112 | struct ShaderPools { | ||
| 113 | void ReleaseContents() { | ||
| 114 | inst.ReleaseContents(); | ||
| 115 | block.ReleaseContents(); | ||
| 116 | flow_block.ReleaseContents(); | ||
| 117 | } | ||
| 118 | |||
| 119 | Shader::ObjectPool<Shader::IR::Inst> inst; | ||
| 120 | Shader::ObjectPool<Shader::IR::Block> block; | ||
| 121 | Shader::ObjectPool<Shader::Maxwell::Flow::Block> flow_block; | ||
| 122 | }; | ||
| 123 | |||
| 110 | class PipelineCache final : public VideoCommon::ShaderCache<ShaderInfo> { | 124 | class PipelineCache final : public VideoCommon::ShaderCache<ShaderInfo> { |
| 111 | public: | 125 | public: |
| 112 | explicit PipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu, | 126 | explicit PipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu, |
| @@ -123,19 +137,24 @@ public: | |||
| 123 | 137 | ||
| 124 | [[nodiscard]] ComputePipeline* CurrentComputePipeline(); | 138 | [[nodiscard]] ComputePipeline* CurrentComputePipeline(); |
| 125 | 139 | ||
| 140 | void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||
| 141 | const VideoCore::DiskResourceLoadCallback& callback); | ||
| 142 | |||
| 126 | private: | 143 | private: |
| 127 | bool RefreshStages(); | 144 | bool RefreshStages(); |
| 128 | 145 | ||
| 129 | const ShaderInfo* MakeShaderInfo(Maxwell::ShaderProgram program, GPUVAddr base_addr, | 146 | const ShaderInfo* MakeShaderInfo(GenericEnvironment& env, VAddr cpu_addr); |
| 130 | u32 start_address, VAddr cpu_addr); | ||
| 131 | 147 | ||
| 132 | GraphicsPipeline CreateGraphicsPipeline(); | 148 | GraphicsPipeline CreateGraphicsPipeline(); |
| 133 | 149 | ||
| 134 | ComputePipeline CreateComputePipeline(ShaderInfo* shader); | 150 | GraphicsPipeline CreateGraphicsPipeline(ShaderPools& pools, const GraphicsPipelineCacheKey& key, |
| 151 | std::span<Shader::Environment* const> envs); | ||
| 135 | 152 | ||
| 136 | ComputePipeline* CreateComputePipelineWithoutShader(VAddr shader_cpu_addr); | 153 | ComputePipeline CreateComputePipeline(const ComputePipelineCacheKey& key, |
| 154 | const ShaderInfo* shader); | ||
| 137 | 155 | ||
| 138 | ComputePipelineCacheKey MakeComputePipelineKey(u128 unique_hash) const; | 156 | ComputePipeline CreateComputePipeline(ShaderPools& pools, const ComputePipelineCacheKey& key, |
| 157 | Shader::Environment& env) const; | ||
| 139 | 158 | ||
| 140 | Tegra::GPU& gpu; | 159 | Tegra::GPU& gpu; |
| 141 | Tegra::Engines::Maxwell3D& maxwell3d; | 160 | Tegra::Engines::Maxwell3D& maxwell3d; |
| @@ -155,11 +174,10 @@ private: | |||
| 155 | std::unordered_map<ComputePipelineCacheKey, ComputePipeline> compute_cache; | 174 | std::unordered_map<ComputePipelineCacheKey, ComputePipeline> compute_cache; |
| 156 | std::unordered_map<GraphicsPipelineCacheKey, GraphicsPipeline> graphics_cache; | 175 | std::unordered_map<GraphicsPipelineCacheKey, GraphicsPipeline> graphics_cache; |
| 157 | 176 | ||
| 158 | Shader::ObjectPool<Shader::IR::Inst> inst_pool; | 177 | ShaderPools main_pools; |
| 159 | Shader::ObjectPool<Shader::IR::Block> block_pool; | ||
| 160 | Shader::ObjectPool<Shader::Maxwell::Flow::Block> flow_block_pool; | ||
| 161 | 178 | ||
| 162 | Shader::Profile profile; | 179 | Shader::Profile profile; |
| 180 | std::string pipeline_cache_filename; | ||
| 163 | }; | 181 | }; |
| 164 | 182 | ||
| 165 | } // namespace Vulkan | 183 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp b/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp index 7e5ae43ea..1c6ba7289 100644 --- a/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp | |||
| @@ -50,6 +50,7 @@ VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat | |||
| 50 | RenderPassCache::RenderPassCache(const Device& device_) : device{&device_} {} | 50 | RenderPassCache::RenderPassCache(const Device& device_) : device{&device_} {} |
| 51 | 51 | ||
| 52 | VkRenderPass RenderPassCache::Get(const RenderPassKey& key) { | 52 | VkRenderPass RenderPassCache::Get(const RenderPassKey& key) { |
| 53 | std::lock_guard lock{mutex}; | ||
| 53 | const auto [pair, is_new] = cache.try_emplace(key); | 54 | const auto [pair, is_new] = cache.try_emplace(key); |
| 54 | if (!is_new) { | 55 | if (!is_new) { |
| 55 | return *pair->second; | 56 | return *pair->second; |
diff --git a/src/video_core/renderer_vulkan/vk_render_pass_cache.h b/src/video_core/renderer_vulkan/vk_render_pass_cache.h index db8e83f1a..eaa0ed775 100644 --- a/src/video_core/renderer_vulkan/vk_render_pass_cache.h +++ b/src/video_core/renderer_vulkan/vk_render_pass_cache.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <mutex> | ||
| 7 | #include <unordered_map> | 8 | #include <unordered_map> |
| 8 | 9 | ||
| 9 | #include "video_core/surface.h" | 10 | #include "video_core/surface.h" |
| @@ -37,7 +38,7 @@ struct hash<Vulkan::RenderPassKey> { | |||
| 37 | 38 | ||
| 38 | namespace Vulkan { | 39 | namespace Vulkan { |
| 39 | 40 | ||
| 40 | class Device; | 41 | class Device; |
| 41 | 42 | ||
| 42 | class RenderPassCache { | 43 | class RenderPassCache { |
| 43 | public: | 44 | public: |
| @@ -48,6 +49,7 @@ public: | |||
| 48 | private: | 49 | private: |
| 49 | const Device* device{}; | 50 | const Device* device{}; |
| 50 | std::unordered_map<RenderPassKey, vk::RenderPass> cache; | 51 | std::unordered_map<RenderPassKey, vk::RenderPass> cache; |
| 52 | std::mutex mutex; | ||
| 51 | }; | 53 | }; |
| 52 | 54 | ||
| 53 | } // namespace Vulkan | 55 | } // namespace Vulkan |