summaryrefslogtreecommitdiffstats
path: root/src/video_core/shader_environment.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/shader_environment.cpp')
-rw-r--r--src/video_core/shader_environment.cpp54
1 files changed, 54 insertions, 0 deletions
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp
index 05850afd0..7d3ae0de4 100644
--- a/src/video_core/shader_environment.cpp
+++ b/src/video_core/shader_environment.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <bit>
#include <filesystem>
#include <fstream>
#include <memory>
@@ -14,6 +15,7 @@
#include "common/common_types.h"
#include "common/div_ceil.h"
#include "common/fs/fs.h"
+#include "common/fs/path_util.h"
#include "common/logging/log.h"
#include "shader_recompiler/environment.h"
#include "video_core/engines/kepler_compute.h"
@@ -57,6 +59,47 @@ static Shader::TextureType ConvertType(const Tegra::Texture::TICEntry& entry) {
}
}
+static std::string_view StageToPrefix(Shader::Stage stage) {
+ switch (stage) {
+ case Shader::Stage::VertexB:
+ return "VB";
+ case Shader::Stage::TessellationControl:
+ return "TC";
+ case Shader::Stage::TessellationEval:
+ return "TE";
+ case Shader::Stage::Geometry:
+ return "GS";
+ case Shader::Stage::Fragment:
+ return "FS";
+ case Shader::Stage::Compute:
+ return "CS";
+ case Shader::Stage::VertexA:
+ return "VA";
+ default:
+ return "UK";
+ }
+}
+
+static void DumpImpl(u64 hash, const u64* code, u32 read_highest, u32 read_lowest,
+ u32 initial_offset, Shader::Stage stage) {
+ const auto shader_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)};
+ const auto base_dir{shader_dir / "shaders"};
+ if (!Common::FS::CreateDir(shader_dir) || !Common::FS::CreateDir(base_dir)) {
+ LOG_ERROR(Common_Filesystem, "Failed to create shader dump directories");
+ return;
+ }
+ const auto prefix = StageToPrefix(stage);
+ const auto name{base_dir / fmt::format("{}{:016x}.ash", prefix, hash)};
+ const size_t real_size = read_highest - read_lowest + initial_offset;
+ const size_t padding_needed = ((32 - (real_size % 32)) % 32);
+ std::fstream shader_file(name, std::ios::out | std::ios::binary);
+ const size_t jump_index = initial_offset / sizeof(u64);
+ shader_file.write(reinterpret_cast<const char*>(code + jump_index), real_size);
+ for (size_t i = 0; i < padding_needed; i++) {
+ shader_file.put(0);
+ }
+}
+
GenericEnvironment::GenericEnvironment(Tegra::MemoryManager& gpu_memory_, GPUVAddr program_base_,
u32 start_address_)
: gpu_memory{&gpu_memory_}, program_base{program_base_} {
@@ -128,6 +171,10 @@ u64 GenericEnvironment::CalculateHash() const {
return Common::CityHash64(data.get(), size);
}
+void GenericEnvironment::Dump(u64 hash) {
+ DumpImpl(hash, code.data(), read_highest, read_lowest, initial_offset, stage);
+}
+
void GenericEnvironment::Serialize(std::ofstream& file) const {
const u64 code_size{static_cast<u64>(CachedSize())};
const u64 num_texture_types{static_cast<u64>(texture_types.size())};
@@ -207,6 +254,7 @@ GraphicsEnvironment::GraphicsEnvironment(Tegra::Engines::Maxwell3D& maxwell3d_,
u32 start_address_)
: GenericEnvironment{gpu_memory_, program_base_, start_address_}, maxwell3d{&maxwell3d_} {
gpu_memory->ReadBlock(program_base + start_address, &sph, sizeof(sph));
+ initial_offset = sizeof(sph);
gp_passthrough_mask = maxwell3d->regs.gp_passthrough_mask;
switch (program) {
case Maxwell::ShaderProgram::VertexA:
@@ -323,14 +371,20 @@ void FileEnvironment::Deserialize(std::ifstream& file) {
if (stage == Shader::Stage::Compute) {
file.read(reinterpret_cast<char*>(&workgroup_size), sizeof(workgroup_size))
.read(reinterpret_cast<char*>(&shared_memory_size), sizeof(shared_memory_size));
+ initial_offset = 0;
} else {
file.read(reinterpret_cast<char*>(&sph), sizeof(sph));
+ initial_offset = sizeof(sph);
if (stage == Shader::Stage::Geometry) {
file.read(reinterpret_cast<char*>(&gp_passthrough_mask), sizeof(gp_passthrough_mask));
}
}
}
+void FileEnvironment::Dump(u64 [[maybe_unused]] hash) {
+ DumpImpl(hash, code.get(), read_highest, read_lowest, initial_offset, stage);
+}
+
u64 FileEnvironment::ReadInstruction(u32 address) {
if (address < read_lowest || address > read_highest) {
throw Shader::LogicError("Out of bounds address {}", address);