Implemented Shader Dumper
This commit is contained in:
@@ -38,6 +38,8 @@ add_library(video_core STATIC
|
||||
renderer_opengl/gl_shader_cache.h
|
||||
renderer_opengl/gl_shader_decompiler.cpp
|
||||
renderer_opengl/gl_shader_decompiler.h
|
||||
renderer_opengl/gl_shader_dumper.cpp
|
||||
renderer_opengl/gl_shader_dumper.h
|
||||
renderer_opengl/gl_shader_gen.cpp
|
||||
renderer_opengl/gl_shader_gen.h
|
||||
renderer_opengl/gl_shader_manager.cpp
|
||||
|
||||
@@ -30,11 +30,7 @@ using Tegra::Shader::SubOp;
|
||||
constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH;
|
||||
constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header);
|
||||
|
||||
<<<<<<< HEAD
|
||||
enum : u32 { POSITION_VARYING_LOCATION = 0, GENERIC_VARYING_START_LOCATION = 1 };
|
||||
=======
|
||||
constexpr u32 POSITION_VARYING_LOCATION = 15;
|
||||
>>>>>>> glsl_decompiler: Implement geometry shaders
|
||||
|
||||
constexpr u32 MAX_GEOMETRY_BUFFERS = 6;
|
||||
constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested
|
||||
@@ -510,11 +506,7 @@ public:
|
||||
/// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
|
||||
/// necessary.
|
||||
std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
|
||||
<<<<<<< HEAD
|
||||
bool is_array, bool is_shadow) {
|
||||
=======
|
||||
bool is_array) {
|
||||
>>>>>>> glsl_decompiler: Implement geometry shaders
|
||||
const auto offset = static_cast<std::size_t>(sampler.index.Value());
|
||||
|
||||
// If this sampler has already been used, return the existing mapping.
|
||||
@@ -523,22 +515,14 @@ public:
|
||||
[&](const SamplerEntry& entry) { return entry.GetOffset() == offset; });
|
||||
|
||||
if (itr != used_samplers.end()) {
|
||||
<<<<<<< HEAD
|
||||
ASSERT(itr->GetType() == type && itr->IsArray() == is_array &&
|
||||
itr->IsShadow() == is_shadow);
|
||||
=======
|
||||
ASSERT(itr->GetType() == type && itr->IsArray() == is_array);
|
||||
>>>>>>> glsl_decompiler: Implement geometry shaders
|
||||
return itr->GetName();
|
||||
}
|
||||
|
||||
// Otherwise create a new mapping for this sampler
|
||||
const std::size_t next_index = used_samplers.size();
|
||||
<<<<<<< HEAD
|
||||
const SamplerEntry entry{stage, offset, next_index, type, is_array, is_shadow};
|
||||
=======
|
||||
const SamplerEntry entry{stage, offset, next_index, type, is_array};
|
||||
>>>>>>> glsl_decompiler: Implement geometry shaders
|
||||
used_samplers.emplace_back(entry);
|
||||
return entry.GetName();
|
||||
}
|
||||
@@ -575,14 +559,10 @@ private:
|
||||
// TODO(bunnei): Use proper number of elements for these
|
||||
u32 idx =
|
||||
static_cast<u32>(element.first) - static_cast<u32>(Attribute::Index::Attribute_0);
|
||||
<<<<<<< HEAD
|
||||
if (stage != Maxwell3D::Regs::ShaderStage::Vertex) {
|
||||
// If inputs are varyings, add an offset
|
||||
idx += GENERIC_VARYING_START_LOCATION;
|
||||
}
|
||||
=======
|
||||
ASSERT(idx != POSITION_VARYING_LOCATION);
|
||||
>>>>>>> glsl_decompiler: Implement geometry shaders
|
||||
|
||||
std::string attr{GetInputAttribute(element.first, element.second)};
|
||||
if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
|
||||
@@ -603,18 +583,11 @@ private:
|
||||
}
|
||||
for (const auto& index : declr_output_attribute) {
|
||||
// TODO(bunnei): Use proper number of elements for these
|
||||
<<<<<<< HEAD
|
||||
const u32 idx = static_cast<u32>(index) -
|
||||
static_cast<u32>(Attribute::Index::Attribute_0) +
|
||||
GENERIC_VARYING_START_LOCATION;
|
||||
declarations.AddLine("layout (location = " + std::to_string(idx) + ") out vec4 " +
|
||||
GetOutputAttribute(index) + ';');
|
||||
=======
|
||||
declarations.AddLine("layout (location = " +
|
||||
std::to_string(static_cast<u32>(index) -
|
||||
static_cast<u32>(Attribute::Index::Attribute_0)) +
|
||||
") out vec4 " + GetOutputAttribute(index) + ';');
|
||||
>>>>>>> glsl_decompiler: Implement geometry shaders
|
||||
}
|
||||
declarations.AddNewLine();
|
||||
}
|
||||
@@ -737,11 +710,7 @@ private:
|
||||
const Tegra::Shader::IpaMode& input_mode,
|
||||
boost::optional<Register> vertex = {}) {
|
||||
auto GeometryPass = [&](const std::string& name) {
|
||||
<<<<<<< HEAD
|
||||
if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) {
|
||||
=======
|
||||
if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex.has_value()) {
|
||||
>>>>>>> glsl_decompiler: Implement geometry shaders
|
||||
return "gs_" + name + '[' + GetRegisterAsInteger(vertex.value(), 0, false) + ']';
|
||||
}
|
||||
return name;
|
||||
@@ -878,9 +847,14 @@ public:
|
||||
: subroutines(subroutines), program_code(program_code), main_offset(main_offset),
|
||||
stage(stage), suffix(suffix) {
|
||||
std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
|
||||
faulty = false;
|
||||
Generate(suffix);
|
||||
}
|
||||
|
||||
bool IsFaulty() {
|
||||
return faulty;
|
||||
}
|
||||
|
||||
std::string GetShaderCode() {
|
||||
return declarations.GetResult() + shader.GetResult();
|
||||
}
|
||||
@@ -1260,6 +1234,7 @@ private:
|
||||
|
||||
// Decoding failure
|
||||
if (!opcode) {
|
||||
faulty = true;
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled instruction: {0:x}", instr.value);
|
||||
UNREACHABLE();
|
||||
return offset + 1;
|
||||
@@ -3237,6 +3212,7 @@ private:
|
||||
const u32 main_offset;
|
||||
Maxwell3D::Regs::ShaderStage stage;
|
||||
const std::string& suffix;
|
||||
bool faulty;
|
||||
|
||||
ShaderWriter shader;
|
||||
ShaderWriter declarations;
|
||||
@@ -3253,11 +3229,12 @@ std::string GetCommonDeclarations() {
|
||||
|
||||
boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
|
||||
Maxwell3D::Regs::ShaderStage stage,
|
||||
const std::string& suffix) {
|
||||
const std::string& suffix, bool& faulty_shader) {
|
||||
try {
|
||||
const auto subroutines =
|
||||
ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines();
|
||||
GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix);
|
||||
faulty_shader = generator.IsFaulty();
|
||||
return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
|
||||
} catch (const DecompileFail& exception) {
|
||||
LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
|
||||
|
||||
@@ -20,6 +20,6 @@ std::string GetCommonDeclarations();
|
||||
|
||||
boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
|
||||
Maxwell3D::Regs::ShaderStage stage,
|
||||
const std::string& suffix);
|
||||
const std::string& suffix, bool& faulty_shader);
|
||||
|
||||
} // namespace OpenGL::GLShader::Decompiler
|
||||
|
||||
54
src/video_core/renderer_opengl/gl_shader_dumper.cpp
Normal file
54
src/video_core/renderer_opengl/gl_shader_dumper.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
#include "common/file_util.h"
|
||||
#include "common/hash.h"
|
||||
#include "video_core/engines/shader_bytecode.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_dumper.h"
|
||||
|
||||
template <typename I>
|
||||
std::string n2hexstr(I w, size_t hex_len = sizeof(I) << 1) {
|
||||
static const char* digits = "0123456789ABCDEF";
|
||||
std::string rc(hex_len, '0');
|
||||
for (size_t i = 0, j = (hex_len - 1) * 4; i < hex_len; ++i, j -= 4)
|
||||
rc[i] = digits[(w >> j) & 0x0f];
|
||||
return rc;
|
||||
}
|
||||
|
||||
std::string ShaderDumper::hashName() {
|
||||
u64 hash = Common::ComputeHash64(program.data(), sizeof(u64) * program.size());
|
||||
return n2hexstr(hash);
|
||||
}
|
||||
|
||||
bool IsSchedInstruction(u32 offset, u32 main_offset) {
|
||||
// sched instructions appear once every 4 instructions.
|
||||
static constexpr size_t SchedPeriod = 4;
|
||||
u32 absolute_offset = offset - main_offset;
|
||||
|
||||
return (absolute_offset % SchedPeriod) == 0;
|
||||
}
|
||||
|
||||
void ShaderDumper::dump() {
|
||||
FileUtil::IOFile sFile;
|
||||
std::string name = prefix + hashName();
|
||||
sFile.Open(name, "wb");
|
||||
u32 start_offset = 10;
|
||||
u32 offset = start_offset;
|
||||
u64 size = 0;
|
||||
while (true) { // dump until hitting not finding a valid instruction
|
||||
u64 inst = program[offset];
|
||||
if (!IsSchedInstruction(offset, start_offset)) {
|
||||
if (inst == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
sFile.WriteArray<u64>(&inst, 1);
|
||||
size += 8;
|
||||
offset += 1;
|
||||
}
|
||||
u64 fill = 0;
|
||||
// Align to 32 bytes for nvdisasm
|
||||
while ((size % 0x20) != 0) {
|
||||
sFile.WriteArray<u64>(&fill, 1);
|
||||
size += 8;
|
||||
}
|
||||
sFile.Close();
|
||||
}
|
||||
21
src/video_core/renderer_opengl/gl_shader_dumper.h
Normal file
21
src/video_core/renderer_opengl/gl_shader_dumper.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
class ShaderDumper {
|
||||
public:
|
||||
ShaderDumper(const std::vector<u64>& prog, std::string prefix) : program(prog) {
|
||||
this->prefix = prefix;
|
||||
}
|
||||
void dump();
|
||||
|
||||
private:
|
||||
std::string hashName();
|
||||
|
||||
std::string prefix;
|
||||
const std::vector<u64>& program;
|
||||
};
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_dumper.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||
|
||||
namespace OpenGL::GLShader {
|
||||
@@ -14,11 +15,12 @@ using Tegra::Engines::Maxwell3D;
|
||||
static constexpr u32 PROGRAM_OFFSET{10};
|
||||
|
||||
ProgramResult GenerateVertexShader(const ShaderSetup& setup) {
|
||||
bool faultyA = false;
|
||||
bool faultyB = false;
|
||||
std::string out = "#version 430 core\n";
|
||||
out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
|
||||
out += Decompiler::GetCommonDeclarations();
|
||||
|
||||
<<<<<<< HEAD
|
||||
out += R"(
|
||||
out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
@@ -29,17 +31,6 @@ layout(std140) uniform vs_config {
|
||||
uvec4 instance_id;
|
||||
uvec4 flip_stage;
|
||||
};
|
||||
=======
|
||||
out += R"(out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
layout(std140) uniform vs_config {
|
||||
vec4 viewport_flip;
|
||||
uvec4 instance_id;
|
||||
uvec4 flip_stage;
|
||||
};
|
||||
>>>>>>> glsl_decompiler: Implement geometry shaders
|
||||
)";
|
||||
|
||||
if (setup.IsDualProgram()) {
|
||||
@@ -48,19 +39,11 @@ layout(std140) uniform vs_config {
|
||||
|
||||
ProgramResult program =
|
||||
Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
|
||||
Maxwell3D::Regs::ShaderStage::Vertex, "vertex")
|
||||
Maxwell3D::Regs::ShaderStage::Vertex, "vertex", faultyA)
|
||||
.get_value_or({});
|
||||
|
||||
out += program.first;
|
||||
|
||||
if (setup.IsDualProgram()) {
|
||||
ProgramResult program_b =
|
||||
Decompiler::DecompileProgram(setup.program.code_b, PROGRAM_OFFSET,
|
||||
Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b")
|
||||
.get_value_or({});
|
||||
out += program_b.first;
|
||||
}
|
||||
|
||||
out += R"(
|
||||
|
||||
void main() {
|
||||
@@ -89,11 +72,27 @@ void main() {
|
||||
}
|
||||
|
||||
)";
|
||||
if (setup.IsDualProgram()) {
|
||||
ProgramResult program_b =
|
||||
Decompiler::DecompileProgram(setup.program.code_b, PROGRAM_OFFSET,
|
||||
Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b", faultyB)
|
||||
.get_value_or({});
|
||||
out += program_b.first;
|
||||
}
|
||||
|
||||
if (faultyA) {
|
||||
ShaderDumper s(setup.program.code, "VS");
|
||||
s.dump();
|
||||
}
|
||||
if (faultyB) {
|
||||
ShaderDumper s(setup.program.code_b, "VS");
|
||||
s.dump();
|
||||
}
|
||||
return {out, program.second};
|
||||
}
|
||||
|
||||
ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
|
||||
bool faulty = false;
|
||||
std::string out = "#version 430 core\n";
|
||||
out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
|
||||
out += Decompiler::GetCommonDeclarations();
|
||||
@@ -101,13 +100,12 @@ ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
|
||||
|
||||
ProgramResult program =
|
||||
Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
|
||||
Maxwell3D::Regs::ShaderStage::Geometry, "geometry")
|
||||
Maxwell3D::Regs::ShaderStage::Geometry, "geometry", faulty)
|
||||
.get_value_or({});
|
||||
out += R"(
|
||||
out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
};
|
||||
<<<<<<< HEAD
|
||||
|
||||
layout (std140) uniform gs_config {
|
||||
vec4 viewport_flip;
|
||||
@@ -115,25 +113,21 @@ layout (std140) uniform gs_config {
|
||||
uvec4 flip_stage;
|
||||
};
|
||||
|
||||
=======
|
||||
|
||||
layout (std140) uniform gs_config {
|
||||
vec4 viewport_flip;
|
||||
uvec4 instance_id;
|
||||
uvec4 flip_stage;
|
||||
};
|
||||
|
||||
>>>>>>> glsl_decompiler: Implement geometry shaders
|
||||
void main() {
|
||||
exec_geometry();
|
||||
}
|
||||
|
||||
)";
|
||||
out += program.first;
|
||||
if (faulty) {
|
||||
ShaderDumper s(setup.program.code, "GS");
|
||||
s.dump();
|
||||
}
|
||||
return {out, program.second};
|
||||
}
|
||||
|
||||
ProgramResult GenerateFragmentShader(const ShaderSetup& setup) {
|
||||
bool faulty = false;
|
||||
std::string out = "#version 430 core\n";
|
||||
out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
|
||||
out += Decompiler::GetCommonDeclarations();
|
||||
@@ -141,7 +135,7 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup) {
|
||||
|
||||
ProgramResult program =
|
||||
Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
|
||||
Maxwell3D::Regs::ShaderStage::Fragment, "fragment")
|
||||
Maxwell3D::Regs::ShaderStage::Fragment, "fragment", faulty)
|
||||
.get_value_or({});
|
||||
out += R"(
|
||||
layout(location = 0) out vec4 FragColor0;
|
||||
@@ -165,6 +159,10 @@ void main() {
|
||||
|
||||
)";
|
||||
out += program.first;
|
||||
if (faulty) {
|
||||
ShaderDumper s(setup.program.code, "FM");
|
||||
s.dump();
|
||||
}
|
||||
return {out, program.second};
|
||||
}
|
||||
} // namespace OpenGL::GLShader
|
||||
} // namespace OpenGL::GLShader
|
||||
|
||||
Reference in New Issue
Block a user