summaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp153
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.h11
-rw-r--r--src/video_core/vulkan_common/nsight_aftermath_tracker.cpp47
-rw-r--r--src/video_core/vulkan_common/nsight_aftermath_tracker.h3
-rw-r--r--src/video_core/vulkan_common/vulkan_library.cpp8
5 files changed, 116 insertions, 106 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index dbcb751cb..0deb86517 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -7,9 +7,10 @@
7#include <fmt/format.h> 7#include <fmt/format.h>
8 8
9#include "common/assert.h" 9#include "common/assert.h"
10#include "common/common_paths.h"
11#include "common/common_types.h" 10#include "common/common_types.h"
12#include "common/file_util.h" 11#include "common/fs/file.h"
12#include "common/fs/fs.h"
13#include "common/fs/path_util.h"
13#include "common/logging/log.h" 14#include "common/logging/log.h"
14#include "common/scm_rev.h" 15#include "common/scm_rev.h"
15#include "common/settings.h" 16#include "common/settings.h"
@@ -26,11 +27,7 @@ using Tegra::Engines::ShaderType;
26using VideoCommon::Shader::BindlessSamplerMap; 27using VideoCommon::Shader::BindlessSamplerMap;
27using VideoCommon::Shader::BoundSamplerMap; 28using VideoCommon::Shader::BoundSamplerMap;
28using VideoCommon::Shader::KeyMap; 29using VideoCommon::Shader::KeyMap;
29
30namespace {
31
32using VideoCommon::Shader::SeparateSamplerKey; 30using VideoCommon::Shader::SeparateSamplerKey;
33
34using ShaderCacheVersionHash = std::array<u8, 64>; 31using ShaderCacheVersionHash = std::array<u8, 64>;
35 32
36struct ConstBufferKey { 33struct ConstBufferKey {
@@ -58,6 +55,8 @@ struct BindlessSamplerEntry {
58 Tegra::Engines::SamplerDescriptor sampler; 55 Tegra::Engines::SamplerDescriptor sampler;
59}; 56};
60 57
58namespace {
59
61constexpr u32 NativeVersion = 21; 60constexpr u32 NativeVersion = 21;
62 61
63ShaderCacheVersionHash GetShaderCacheVersionHash() { 62ShaderCacheVersionHash GetShaderCacheVersionHash() {
@@ -74,22 +73,20 @@ ShaderDiskCacheEntry::ShaderDiskCacheEntry() = default;
74ShaderDiskCacheEntry::~ShaderDiskCacheEntry() = default; 73ShaderDiskCacheEntry::~ShaderDiskCacheEntry() = default;
75 74
76bool ShaderDiskCacheEntry::Load(Common::FS::IOFile& file) { 75bool ShaderDiskCacheEntry::Load(Common::FS::IOFile& file) {
77 if (file.ReadBytes(&type, sizeof(u32)) != sizeof(u32)) { 76 if (!file.ReadObject(type)) {
78 return false; 77 return false;
79 } 78 }
80 u32 code_size; 79 u32 code_size;
81 u32 code_size_b; 80 u32 code_size_b;
82 if (file.ReadBytes(&code_size, sizeof(u32)) != sizeof(u32) || 81 if (!file.ReadObject(code_size) || !file.ReadObject(code_size_b)) {
83 file.ReadBytes(&code_size_b, sizeof(u32)) != sizeof(u32)) {
84 return false; 82 return false;
85 } 83 }
86 code.resize(code_size); 84 code.resize(code_size);
87 code_b.resize(code_size_b); 85 code_b.resize(code_size_b);
88 86 if (file.Read(code) != code_size) {
89 if (file.ReadArray(code.data(), code_size) != code_size) {
90 return false; 87 return false;
91 } 88 }
92 if (HasProgramA() && file.ReadArray(code_b.data(), code_size_b) != code_size_b) { 89 if (HasProgramA() && file.Read(code_b) != code_size_b) {
93 return false; 90 return false;
94 } 91 }
95 92
@@ -99,13 +96,12 @@ bool ShaderDiskCacheEntry::Load(Common::FS::IOFile& file) {
99 u32 num_bound_samplers; 96 u32 num_bound_samplers;
100 u32 num_separate_samplers; 97 u32 num_separate_samplers;
101 u32 num_bindless_samplers; 98 u32 num_bindless_samplers;
102 if (file.ReadArray(&unique_identifier, 1) != 1 || file.ReadArray(&bound_buffer, 1) != 1 || 99 if (!file.ReadObject(unique_identifier) || !file.ReadObject(bound_buffer) ||
103 file.ReadArray(&is_texture_handler_size_known, 1) != 1 || 100 !file.ReadObject(is_texture_handler_size_known) ||
104 file.ReadArray(&texture_handler_size_value, 1) != 1 || 101 !file.ReadObject(texture_handler_size_value) || !file.ReadObject(graphics_info) ||
105 file.ReadArray(&graphics_info, 1) != 1 || file.ReadArray(&compute_info, 1) != 1 || 102 !file.ReadObject(compute_info) || !file.ReadObject(num_keys) ||
106 file.ReadArray(&num_keys, 1) != 1 || file.ReadArray(&num_bound_samplers, 1) != 1 || 103 !file.ReadObject(num_bound_samplers) || !file.ReadObject(num_separate_samplers) ||
107 file.ReadArray(&num_separate_samplers, 1) != 1 || 104 !file.ReadObject(num_bindless_samplers)) {
108 file.ReadArray(&num_bindless_samplers, 1) != 1) {
109 return false; 105 return false;
110 } 106 }
111 if (is_texture_handler_size_known) { 107 if (is_texture_handler_size_known) {
@@ -116,13 +112,10 @@ bool ShaderDiskCacheEntry::Load(Common::FS::IOFile& file) {
116 std::vector<BoundSamplerEntry> flat_bound_samplers(num_bound_samplers); 112 std::vector<BoundSamplerEntry> flat_bound_samplers(num_bound_samplers);
117 std::vector<SeparateSamplerEntry> flat_separate_samplers(num_separate_samplers); 113 std::vector<SeparateSamplerEntry> flat_separate_samplers(num_separate_samplers);
118 std::vector<BindlessSamplerEntry> flat_bindless_samplers(num_bindless_samplers); 114 std::vector<BindlessSamplerEntry> flat_bindless_samplers(num_bindless_samplers);
119 if (file.ReadArray(flat_keys.data(), flat_keys.size()) != flat_keys.size() || 115 if (file.Read(flat_keys) != flat_keys.size() ||
120 file.ReadArray(flat_bound_samplers.data(), flat_bound_samplers.size()) != 116 file.Read(flat_bound_samplers) != flat_bound_samplers.size() ||
121 flat_bound_samplers.size() || 117 file.Read(flat_separate_samplers) != flat_separate_samplers.size() ||
122 file.ReadArray(flat_separate_samplers.data(), flat_separate_samplers.size()) != 118 file.Read(flat_bindless_samplers) != flat_bindless_samplers.size()) {
123 flat_separate_samplers.size() ||
124 file.ReadArray(flat_bindless_samplers.data(), flat_bindless_samplers.size()) !=
125 flat_bindless_samplers.size()) {
126 return false; 119 return false;
127 } 120 }
128 for (const auto& entry : flat_keys) { 121 for (const auto& entry : flat_keys) {
@@ -145,26 +138,25 @@ bool ShaderDiskCacheEntry::Load(Common::FS::IOFile& file) {
145} 138}
146 139
147bool ShaderDiskCacheEntry::Save(Common::FS::IOFile& file) const { 140bool ShaderDiskCacheEntry::Save(Common::FS::IOFile& file) const {
148 if (file.WriteObject(static_cast<u32>(type)) != 1 || 141 if (!file.WriteObject(static_cast<u32>(type)) ||
149 file.WriteObject(static_cast<u32>(code.size())) != 1 || 142 !file.WriteObject(static_cast<u32>(code.size())) ||
150 file.WriteObject(static_cast<u32>(code_b.size())) != 1) { 143 !file.WriteObject(static_cast<u32>(code_b.size()))) {
151 return false; 144 return false;
152 } 145 }
153 if (file.WriteArray(code.data(), code.size()) != code.size()) { 146 if (file.Write(code) != code.size()) {
154 return false; 147 return false;
155 } 148 }
156 if (HasProgramA() && file.WriteArray(code_b.data(), code_b.size()) != code_b.size()) { 149 if (HasProgramA() && file.Write(code_b) != code_b.size()) {
157 return false; 150 return false;
158 } 151 }
159 152
160 if (file.WriteObject(unique_identifier) != 1 || file.WriteObject(bound_buffer) != 1 || 153 if (!file.WriteObject(unique_identifier) || !file.WriteObject(bound_buffer) ||
161 file.WriteObject(static_cast<u8>(texture_handler_size.has_value())) != 1 || 154 !file.WriteObject(static_cast<u8>(texture_handler_size.has_value())) ||
162 file.WriteObject(texture_handler_size.value_or(0)) != 1 || 155 !file.WriteObject(texture_handler_size.value_or(0)) || !file.WriteObject(graphics_info) ||
163 file.WriteObject(graphics_info) != 1 || file.WriteObject(compute_info) != 1 || 156 !file.WriteObject(compute_info) || !file.WriteObject(static_cast<u32>(keys.size())) ||
164 file.WriteObject(static_cast<u32>(keys.size())) != 1 || 157 !file.WriteObject(static_cast<u32>(bound_samplers.size())) ||
165 file.WriteObject(static_cast<u32>(bound_samplers.size())) != 1 || 158 !file.WriteObject(static_cast<u32>(separate_samplers.size())) ||
166 file.WriteObject(static_cast<u32>(separate_samplers.size())) != 1 || 159 !file.WriteObject(static_cast<u32>(bindless_samplers.size()))) {
167 file.WriteObject(static_cast<u32>(bindless_samplers.size())) != 1) {
168 return false; 160 return false;
169 } 161 }
170 162
@@ -197,13 +189,10 @@ bool ShaderDiskCacheEntry::Save(Common::FS::IOFile& file) const {
197 BindlessSamplerEntry{address.first, address.second, sampler}); 189 BindlessSamplerEntry{address.first, address.second, sampler});
198 } 190 }
199 191
200 return file.WriteArray(flat_keys.data(), flat_keys.size()) == flat_keys.size() && 192 return file.Write(flat_keys) == flat_keys.size() &&
201 file.WriteArray(flat_bound_samplers.data(), flat_bound_samplers.size()) == 193 file.Write(flat_bound_samplers) == flat_bound_samplers.size() &&
202 flat_bound_samplers.size() && 194 file.Write(flat_separate_samplers) == flat_separate_samplers.size() &&
203 file.WriteArray(flat_separate_samplers.data(), flat_separate_samplers.size()) == 195 file.Write(flat_bindless_samplers) == flat_bindless_samplers.size();
204 flat_separate_samplers.size() &&
205 file.WriteArray(flat_bindless_samplers.data(), flat_bindless_samplers.size()) ==
206 flat_bindless_samplers.size();
207} 196}
208 197
209ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL() = default; 198ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL() = default;
@@ -221,7 +210,8 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran
221 return std::nullopt; 210 return std::nullopt;
222 } 211 }
223 212
224 Common::FS::IOFile file(GetTransferablePath(), "rb"); 213 Common::FS::IOFile file{GetTransferablePath(), Common::FS::FileAccessMode::Read,
214 Common::FS::FileType::BinaryFile};
225 if (!file.IsOpen()) { 215 if (!file.IsOpen()) {
226 LOG_INFO(Render_OpenGL, "No transferable shader cache found"); 216 LOG_INFO(Render_OpenGL, "No transferable shader cache found");
227 is_usable = true; 217 is_usable = true;
@@ -229,7 +219,7 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran
229 } 219 }
230 220
231 u32 version{}; 221 u32 version{};
232 if (file.ReadBytes(&version, sizeof(version)) != sizeof(version)) { 222 if (!file.ReadObject(version)) {
233 LOG_ERROR(Render_OpenGL, "Failed to get transferable cache version, skipping it"); 223 LOG_ERROR(Render_OpenGL, "Failed to get transferable cache version, skipping it");
234 return std::nullopt; 224 return std::nullopt;
235 } 225 }
@@ -249,7 +239,7 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran
249 239
250 // Version is valid, load the shaders 240 // Version is valid, load the shaders
251 std::vector<ShaderDiskCacheEntry> entries; 241 std::vector<ShaderDiskCacheEntry> entries;
252 while (file.Tell() < file.GetSize()) { 242 while (static_cast<u64>(file.Tell()) < file.GetSize()) {
253 ShaderDiskCacheEntry& entry = entries.emplace_back(); 243 ShaderDiskCacheEntry& entry = entries.emplace_back();
254 if (!entry.Load(file)) { 244 if (!entry.Load(file)) {
255 LOG_ERROR(Render_OpenGL, "Failed to load transferable raw entry, skipping"); 245 LOG_ERROR(Render_OpenGL, "Failed to load transferable raw entry, skipping");
@@ -266,7 +256,8 @@ std::vector<ShaderDiskCachePrecompiled> ShaderDiskCacheOpenGL::LoadPrecompiled()
266 return {}; 256 return {};
267 } 257 }
268 258
269 Common::FS::IOFile file(GetPrecompiledPath(), "rb"); 259 Common::FS::IOFile file{GetPrecompiledPath(), Common::FS::FileAccessMode::Read,
260 Common::FS::FileType::BinaryFile};
270 if (!file.IsOpen()) { 261 if (!file.IsOpen()) {
271 LOG_INFO(Render_OpenGL, "No precompiled shader cache found"); 262 LOG_INFO(Render_OpenGL, "No precompiled shader cache found");
272 return {}; 263 return {};
@@ -286,7 +277,9 @@ std::optional<std::vector<ShaderDiskCachePrecompiled>> ShaderDiskCacheOpenGL::Lo
286 Common::FS::IOFile& file) { 277 Common::FS::IOFile& file) {
287 // Read compressed file from disk and decompress to virtual precompiled cache file 278 // Read compressed file from disk and decompress to virtual precompiled cache file
288 std::vector<u8> compressed(file.GetSize()); 279 std::vector<u8> compressed(file.GetSize());
289 file.ReadBytes(compressed.data(), compressed.size()); 280 if (file.Read(compressed) != file.GetSize()) {
281 return std::nullopt;
282 }
290 const std::vector<u8> decompressed = Common::Compression::DecompressDataZSTD(compressed); 283 const std::vector<u8> decompressed = Common::Compression::DecompressDataZSTD(compressed);
291 SaveArrayToPrecompiled(decompressed.data(), decompressed.size()); 284 SaveArrayToPrecompiled(decompressed.data(), decompressed.size());
292 precompiled_cache_virtual_file_offset = 0; 285 precompiled_cache_virtual_file_offset = 0;
@@ -321,9 +314,9 @@ std::optional<std::vector<ShaderDiskCachePrecompiled>> ShaderDiskCacheOpenGL::Lo
321} 314}
322 315
323void ShaderDiskCacheOpenGL::InvalidateTransferable() { 316void ShaderDiskCacheOpenGL::InvalidateTransferable() {
324 if (!Common::FS::Delete(GetTransferablePath())) { 317 if (!Common::FS::RemoveFile(GetTransferablePath())) {
325 LOG_ERROR(Render_OpenGL, "Failed to invalidate transferable file={}", 318 LOG_ERROR(Render_OpenGL, "Failed to invalidate transferable file={}",
326 GetTransferablePath()); 319 Common::FS::PathToUTF8String(GetTransferablePath()));
327 } 320 }
328 InvalidatePrecompiled(); 321 InvalidatePrecompiled();
329} 322}
@@ -332,8 +325,9 @@ void ShaderDiskCacheOpenGL::InvalidatePrecompiled() {
332 // Clear virtaul precompiled cache file 325 // Clear virtaul precompiled cache file
333 precompiled_cache_virtual_file.Resize(0); 326 precompiled_cache_virtual_file.Resize(0);
334 327
335 if (!Common::FS::Delete(GetPrecompiledPath())) { 328 if (!Common::FS::RemoveFile(GetPrecompiledPath())) {
336 LOG_ERROR(Render_OpenGL, "Failed to invalidate precompiled file={}", GetPrecompiledPath()); 329 LOG_ERROR(Render_OpenGL, "Failed to invalidate precompiled file={}",
330 Common::FS::PathToUTF8String(GetPrecompiledPath()));
337 } 331 }
338} 332}
339 333
@@ -398,16 +392,18 @@ Common::FS::IOFile ShaderDiskCacheOpenGL::AppendTransferableFile() const {
398 const auto transferable_path{GetTransferablePath()}; 392 const auto transferable_path{GetTransferablePath()};
399 const bool existed = Common::FS::Exists(transferable_path); 393 const bool existed = Common::FS::Exists(transferable_path);
400 394
401 Common::FS::IOFile file(transferable_path, "ab"); 395 Common::FS::IOFile file{transferable_path, Common::FS::FileAccessMode::Append,
396 Common::FS::FileType::BinaryFile};
402 if (!file.IsOpen()) { 397 if (!file.IsOpen()) {
403 LOG_ERROR(Render_OpenGL, "Failed to open transferable cache in path={}", transferable_path); 398 LOG_ERROR(Render_OpenGL, "Failed to open transferable cache in path={}",
399 Common::FS::PathToUTF8String(transferable_path));
404 return {}; 400 return {};
405 } 401 }
406 if (!existed || file.GetSize() == 0) { 402 if (!existed || file.GetSize() == 0) {
407 // If the file didn't exist, write its version 403 // If the file didn't exist, write its version
408 if (file.WriteObject(NativeVersion) != 1) { 404 if (!file.WriteObject(NativeVersion)) {
409 LOG_ERROR(Render_OpenGL, "Failed to write transferable cache version in path={}", 405 LOG_ERROR(Render_OpenGL, "Failed to write transferable cache version in path={}",
410 transferable_path); 406 Common::FS::PathToUTF8String(transferable_path));
411 return {}; 407 return {};
412 } 408 }
413 } 409 }
@@ -429,51 +425,54 @@ void ShaderDiskCacheOpenGL::SaveVirtualPrecompiledFile() {
429 const std::vector<u8> compressed = 425 const std::vector<u8> compressed =
430 Common::Compression::CompressDataZSTDDefault(uncompressed.data(), uncompressed.size()); 426 Common::Compression::CompressDataZSTDDefault(uncompressed.data(), uncompressed.size());
431 427
432 const auto precompiled_path{GetPrecompiledPath()}; 428 const auto precompiled_path = GetPrecompiledPath();
433 Common::FS::IOFile file(precompiled_path, "wb"); 429 Common::FS::IOFile file{precompiled_path, Common::FS::FileAccessMode::Write,
430 Common::FS::FileType::BinaryFile};
434 431
435 if (!file.IsOpen()) { 432 if (!file.IsOpen()) {
436 LOG_ERROR(Render_OpenGL, "Failed to open precompiled cache in path={}", precompiled_path); 433 LOG_ERROR(Render_OpenGL, "Failed to open precompiled cache in path={}",
434 Common::FS::PathToUTF8String(precompiled_path));
437 return; 435 return;
438 } 436 }
439 if (file.WriteBytes(compressed.data(), compressed.size()) != compressed.size()) { 437 if (file.Write(compressed) != compressed.size()) {
440 LOG_ERROR(Render_OpenGL, "Failed to write precompiled cache version in path={}", 438 LOG_ERROR(Render_OpenGL, "Failed to write precompiled cache version in path={}",
441 precompiled_path); 439 Common::FS::PathToUTF8String(precompiled_path));
442 } 440 }
443} 441}
444 442
445bool ShaderDiskCacheOpenGL::EnsureDirectories() const { 443bool ShaderDiskCacheOpenGL::EnsureDirectories() const {
446 const auto CreateDir = [](const std::string& dir) { 444 const auto CreateDir = [](const std::filesystem::path& dir) {
447 if (!Common::FS::CreateDir(dir)) { 445 if (!Common::FS::CreateDir(dir)) {
448 LOG_ERROR(Render_OpenGL, "Failed to create directory={}", dir); 446 LOG_ERROR(Render_OpenGL, "Failed to create directory={}",
447 Common::FS::PathToUTF8String(dir));
449 return false; 448 return false;
450 } 449 }
451 return true; 450 return true;
452 }; 451 };
453 452
454 return CreateDir(Common::FS::GetUserPath(Common::FS::UserPath::ShaderDir)) && 453 return CreateDir(Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir)) &&
455 CreateDir(GetBaseDir()) && CreateDir(GetTransferableDir()) && 454 CreateDir(GetBaseDir()) && CreateDir(GetTransferableDir()) &&
456 CreateDir(GetPrecompiledDir()); 455 CreateDir(GetPrecompiledDir());
457} 456}
458 457
459std::string ShaderDiskCacheOpenGL::GetTransferablePath() const { 458std::filesystem::path ShaderDiskCacheOpenGL::GetTransferablePath() const {
460 return Common::FS::SanitizePath(GetTransferableDir() + DIR_SEP_CHR + GetTitleID() + ".bin"); 459 return GetTransferableDir() / fmt::format("{}.bin", GetTitleID());
461} 460}
462 461
463std::string ShaderDiskCacheOpenGL::GetPrecompiledPath() const { 462std::filesystem::path ShaderDiskCacheOpenGL::GetPrecompiledPath() const {
464 return Common::FS::SanitizePath(GetPrecompiledDir() + DIR_SEP_CHR + GetTitleID() + ".bin"); 463 return GetPrecompiledDir() / fmt::format("{}.bin", GetTitleID());
465} 464}
466 465
467std::string ShaderDiskCacheOpenGL::GetTransferableDir() const { 466std::filesystem::path ShaderDiskCacheOpenGL::GetTransferableDir() const {
468 return GetBaseDir() + DIR_SEP "transferable"; 467 return GetBaseDir() / "transferable";
469} 468}
470 469
471std::string ShaderDiskCacheOpenGL::GetPrecompiledDir() const { 470std::filesystem::path ShaderDiskCacheOpenGL::GetPrecompiledDir() const {
472 return GetBaseDir() + DIR_SEP "precompiled"; 471 return GetBaseDir() / "precompiled";
473} 472}
474 473
475std::string ShaderDiskCacheOpenGL::GetBaseDir() const { 474std::filesystem::path ShaderDiskCacheOpenGL::GetBaseDir() const {
476 return Common::FS::GetUserPath(Common::FS::UserPath::ShaderDir) + DIR_SEP "opengl"; 475 return Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir) / "opengl";
477} 476}
478 477
479std::string ShaderDiskCacheOpenGL::GetTitleID() const { 478std::string ShaderDiskCacheOpenGL::GetTitleID() const {
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.h b/src/video_core/renderer_opengl/gl_shader_disk_cache.h
index aef841c1d..f8bc23868 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <filesystem>
7#include <optional> 8#include <optional>
8#include <string> 9#include <string>
9#include <tuple> 10#include <tuple>
@@ -108,19 +109,19 @@ private:
108 bool EnsureDirectories() const; 109 bool EnsureDirectories() const;
109 110
110 /// Gets current game's transferable file path 111 /// Gets current game's transferable file path
111 std::string GetTransferablePath() const; 112 std::filesystem::path GetTransferablePath() const;
112 113
113 /// Gets current game's precompiled file path 114 /// Gets current game's precompiled file path
114 std::string GetPrecompiledPath() const; 115 std::filesystem::path GetPrecompiledPath() const;
115 116
116 /// Get user's transferable directory path 117 /// Get user's transferable directory path
117 std::string GetTransferableDir() const; 118 std::filesystem::path GetTransferableDir() const;
118 119
119 /// Get user's precompiled directory path 120 /// Get user's precompiled directory path
120 std::string GetPrecompiledDir() const; 121 std::filesystem::path GetPrecompiledDir() const;
121 122
122 /// Get user's shader directory path 123 /// Get user's shader directory path
123 std::string GetBaseDir() const; 124 std::filesystem::path GetBaseDir() const;
124 125
125 /// Get current game's title id 126 /// Get current game's title id
126 std::string GetTitleID() const; 127 std::string GetTitleID() const;
diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
index 7a9d00d4f..f0ee76519 100644
--- a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
+++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
@@ -5,6 +5,7 @@
5#ifdef HAS_NSIGHT_AFTERMATH 5#ifdef HAS_NSIGHT_AFTERMATH
6 6
7#include <mutex> 7#include <mutex>
8#include <span>
8#include <string> 9#include <string>
9#include <string_view> 10#include <string_view>
10#include <utility> 11#include <utility>
@@ -12,9 +13,10 @@
12 13
13#include <fmt/format.h> 14#include <fmt/format.h>
14 15
15#include "common/common_paths.h"
16#include "common/common_types.h" 16#include "common/common_types.h"
17#include "common/file_util.h" 17#include "common/fs/file.h"
18#include "common/fs/fs.h"
19#include "common/fs/path_util.h"
18#include "common/logging/log.h" 20#include "common/logging/log.h"
19#include "common/scope_exit.h" 21#include "common/scope_exit.h"
20#include "video_core/vulkan_common/nsight_aftermath_tracker.h" 22#include "video_core/vulkan_common/nsight_aftermath_tracker.h"
@@ -46,9 +48,9 @@ NsightAftermathTracker::NsightAftermathTracker() {
46 LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers"); 48 LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers");
47 return; 49 return;
48 } 50 }
49 dump_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir) + "gpucrash"; 51 dump_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::LogDir) / "gpucrash";
50 52
51 void(Common::FS::DeleteDirRecursively(dump_dir)); 53 void(Common::FS::RemoveDirRecursively(dump_dir));
52 if (!Common::FS::CreateDir(dump_dir)) { 54 if (!Common::FS::CreateDir(dump_dir)) {
53 LOG_ERROR(Render_Vulkan, "Failed to create Nsight Aftermath dump directory"); 55 LOG_ERROR(Render_Vulkan, "Failed to create Nsight Aftermath dump directory");
54 return; 56 return;
@@ -60,7 +62,8 @@ NsightAftermathTracker::NsightAftermathTracker() {
60 LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_EnableGpuCrashDumps failed"); 62 LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_EnableGpuCrashDumps failed");
61 return; 63 return;
62 } 64 }
63 LOG_INFO(Render_Vulkan, "Nsight Aftermath dump directory is \"{}\"", dump_dir); 65 LOG_INFO(Render_Vulkan, "Nsight Aftermath dump directory is \"{}\"",
66 Common::FS::PathToUTF8String(dump_dir));
64 initialized = true; 67 initialized = true;
65} 68}
66 69
@@ -89,12 +92,15 @@ void NsightAftermathTracker::SaveShader(const std::vector<u32>& spirv) const {
89 return; 92 return;
90 } 93 }
91 94
92 Common::FS::IOFile file(fmt::format("{}/source_{:016x}.spv", dump_dir, hash.hash), "wb"); 95 const auto shader_file = dump_dir / fmt::format("source_{:016x}.spv", hash.hash);
96
97 Common::FS::IOFile file{shader_file, Common::FS::FileAccessMode::Write,
98 Common::FS::FileType::BinaryFile};
93 if (!file.IsOpen()) { 99 if (!file.IsOpen()) {
94 LOG_ERROR(Render_Vulkan, "Failed to dump SPIR-V module with hash={:016x}", hash.hash); 100 LOG_ERROR(Render_Vulkan, "Failed to dump SPIR-V module with hash={:016x}", hash.hash);
95 return; 101 return;
96 } 102 }
97 if (file.WriteArray(spirv.data(), spirv.size()) != spirv.size()) { 103 if (file.Write(spirv) != spirv.size()) {
98 LOG_ERROR(Render_Vulkan, "Failed to write SPIR-V module with hash={:016x}", hash.hash); 104 LOG_ERROR(Render_Vulkan, "Failed to write SPIR-V module with hash={:016x}", hash.hash);
99 return; 105 return;
100 } 106 }
@@ -129,22 +135,24 @@ void NsightAftermathTracker::OnGpuCrashDumpCallback(const void* gpu_crash_dump,
129 return; 135 return;
130 } 136 }
131 137
132 const std::string base_name = [this] { 138 std::filesystem::path base_name = [this] {
133 const int id = dump_id++; 139 const int id = dump_id++;
134 if (id == 0) { 140 if (id == 0) {
135 return fmt::format("{}/crash.nv-gpudmp", dump_dir); 141 return dump_dir / "crash.nv-gpudmp";
136 } else { 142 } else {
137 return fmt::format("{}/crash_{}.nv-gpudmp", dump_dir, id); 143 return dump_dir / fmt::format("crash_{}.nv-gpudmp", id);
138 } 144 }
139 }(); 145 }();
140 146
141 std::string_view dump_view(static_cast<const char*>(gpu_crash_dump), gpu_crash_dump_size); 147 std::string_view dump_view(static_cast<const char*>(gpu_crash_dump), gpu_crash_dump_size);
142 if (Common::FS::WriteStringToFile(false, base_name, dump_view) != gpu_crash_dump_size) { 148 if (Common::FS::WriteStringToFile(base_name, Common::FS::FileType::BinaryFile, dump_view) !=
149 gpu_crash_dump_size) {
143 LOG_ERROR(Render_Vulkan, "Failed to write dump file"); 150 LOG_ERROR(Render_Vulkan, "Failed to write dump file");
144 return; 151 return;
145 } 152 }
146 const std::string_view json_view(json.data(), json.size()); 153 const std::string_view json_view(json.data(), json.size());
147 if (Common::FS::WriteStringToFile(true, base_name + ".json", json_view) != json.size()) { 154 if (Common::FS::WriteStringToFile(base_name.concat(".json"), Common::FS::FileType::TextFile,
155 json_view) != json.size()) {
148 LOG_ERROR(Render_Vulkan, "Failed to write JSON"); 156 LOG_ERROR(Render_Vulkan, "Failed to write JSON");
149 return; 157 return;
150 } 158 }
@@ -161,16 +169,17 @@ void NsightAftermathTracker::OnShaderDebugInfoCallback(const void* shader_debug_
161 return; 169 return;
162 } 170 }
163 171
164 const std::string path = 172 const auto path =
165 fmt::format("{}/shader_{:016x}{:016x}.nvdbg", dump_dir, identifier.id[0], identifier.id[1]); 173 dump_dir / fmt::format("shader_{:016x}{:016x}.nvdbg", identifier.id[0], identifier.id[1]);
166 Common::FS::IOFile file(path, "wb"); 174 Common::FS::IOFile file{path, Common::FS::FileAccessMode::Write,
175 Common::FS::FileType::BinaryFile};
167 if (!file.IsOpen()) { 176 if (!file.IsOpen()) {
168 LOG_ERROR(Render_Vulkan, "Failed to create file {}", path); 177 LOG_ERROR(Render_Vulkan, "Failed to create file {}", Common::FS::PathToUTF8String(path));
169 return; 178 return;
170 } 179 }
171 if (file.WriteBytes(static_cast<const u8*>(shader_debug_info), shader_debug_info_size) != 180 if (file.WriteSpan(std::span(static_cast<const u8*>(shader_debug_info),
172 shader_debug_info_size) { 181 shader_debug_info_size)) != shader_debug_info_size) {
173 LOG_ERROR(Render_Vulkan, "Failed to write file {}", path); 182 LOG_ERROR(Render_Vulkan, "Failed to write file {}", Common::FS::PathToUTF8String(path));
174 return; 183 return;
175 } 184 }
176} 185}
diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.h b/src/video_core/vulkan_common/nsight_aftermath_tracker.h
index 1ce8d4e8e..4fe2b14d9 100644
--- a/src/video_core/vulkan_common/nsight_aftermath_tracker.h
+++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <filesystem>
7#include <mutex> 8#include <mutex>
8#include <string> 9#include <string>
9#include <vector> 10#include <vector>
@@ -54,7 +55,7 @@ private:
54 55
55 mutable std::mutex mutex; 56 mutable std::mutex mutex;
56 57
57 std::string dump_dir; 58 std::filesystem::path dump_dir;
58 int dump_id = 0; 59 int dump_id = 0;
59 60
60 bool initialized = false; 61 bool initialized = false;
diff --git a/src/video_core/vulkan_common/vulkan_library.cpp b/src/video_core/vulkan_common/vulkan_library.cpp
index 557871d81..22833fa56 100644
--- a/src/video_core/vulkan_common/vulkan_library.cpp
+++ b/src/video_core/vulkan_common/vulkan_library.cpp
@@ -6,7 +6,7 @@
6#include <string> 6#include <string>
7 7
8#include "common/dynamic_library.h" 8#include "common/dynamic_library.h"
9#include "common/file_util.h" 9#include "common/fs/path_util.h"
10#include "video_core/vulkan_common/vulkan_library.h" 10#include "video_core/vulkan_common/vulkan_library.h"
11 11
12namespace Vulkan { 12namespace Vulkan {
@@ -18,9 +18,9 @@ Common::DynamicLibrary OpenLibrary() {
18 char* const libvulkan_env = std::getenv("LIBVULKAN_PATH"); 18 char* const libvulkan_env = std::getenv("LIBVULKAN_PATH");
19 if (!libvulkan_env || !library.Open(libvulkan_env)) { 19 if (!libvulkan_env || !library.Open(libvulkan_env)) {
20 // Use the libvulkan.dylib from the application bundle. 20 // Use the libvulkan.dylib from the application bundle.
21 const std::string filename = 21 const auto filename =
22 Common::FS::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib"; 22 Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.dylib";
23 void(library.Open(filename.c_str())); 23 void(library.Open(Common::FS::PathToUTF8String(filename).c_str()));
24 } 24 }
25#else 25#else
26 std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); 26 std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);