Implemented Shader Dumper

This commit is contained in:
FernandoS27
2018-09-04 19:19:31 -04:00
parent 03feb29bce
commit f72b9e2c32
6 changed files with 119 additions and 67 deletions

View File

@@ -38,6 +38,8 @@ add_library(video_core STATIC
renderer_opengl/gl_shader_cache.h renderer_opengl/gl_shader_cache.h
renderer_opengl/gl_shader_decompiler.cpp renderer_opengl/gl_shader_decompiler.cpp
renderer_opengl/gl_shader_decompiler.h 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.cpp
renderer_opengl/gl_shader_gen.h renderer_opengl/gl_shader_gen.h
renderer_opengl/gl_shader_manager.cpp renderer_opengl/gl_shader_manager.cpp

View File

@@ -30,11 +30,7 @@ using Tegra::Shader::SubOp;
constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH; constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH;
constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header); constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header);
<<<<<<< HEAD
enum : u32 { POSITION_VARYING_LOCATION = 0, GENERIC_VARYING_START_LOCATION = 1 }; 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_GEOMETRY_BUFFERS = 6;
constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested 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 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
/// necessary. /// necessary.
std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
<<<<<<< HEAD
bool is_array, bool is_shadow) { 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()); const auto offset = static_cast<std::size_t>(sampler.index.Value());
// If this sampler has already been used, return the existing mapping. // If this sampler has already been used, return the existing mapping.
@@ -523,22 +515,14 @@ public:
[&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; });
if (itr != used_samplers.end()) { if (itr != used_samplers.end()) {
<<<<<<< HEAD
ASSERT(itr->GetType() == type && itr->IsArray() == is_array && ASSERT(itr->GetType() == type && itr->IsArray() == is_array &&
itr->IsShadow() == is_shadow); itr->IsShadow() == is_shadow);
=======
ASSERT(itr->GetType() == type && itr->IsArray() == is_array);
>>>>>>> glsl_decompiler: Implement geometry shaders
return itr->GetName(); return itr->GetName();
} }
// Otherwise create a new mapping for this sampler // Otherwise create a new mapping for this sampler
const std::size_t next_index = used_samplers.size(); 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, is_shadow};
=======
const SamplerEntry entry{stage, offset, next_index, type, is_array};
>>>>>>> glsl_decompiler: Implement geometry shaders
used_samplers.emplace_back(entry); used_samplers.emplace_back(entry);
return entry.GetName(); return entry.GetName();
} }
@@ -575,14 +559,10 @@ private:
// TODO(bunnei): Use proper number of elements for these // TODO(bunnei): Use proper number of elements for these
u32 idx = u32 idx =
static_cast<u32>(element.first) - static_cast<u32>(Attribute::Index::Attribute_0); static_cast<u32>(element.first) - static_cast<u32>(Attribute::Index::Attribute_0);
<<<<<<< HEAD
if (stage != Maxwell3D::Regs::ShaderStage::Vertex) { if (stage != Maxwell3D::Regs::ShaderStage::Vertex) {
// If inputs are varyings, add an offset // If inputs are varyings, add an offset
idx += GENERIC_VARYING_START_LOCATION; idx += GENERIC_VARYING_START_LOCATION;
} }
=======
ASSERT(idx != POSITION_VARYING_LOCATION);
>>>>>>> glsl_decompiler: Implement geometry shaders
std::string attr{GetInputAttribute(element.first, element.second)}; std::string attr{GetInputAttribute(element.first, element.second)};
if (stage == Maxwell3D::Regs::ShaderStage::Geometry) { if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
@@ -603,18 +583,11 @@ private:
} }
for (const auto& index : declr_output_attribute) { for (const auto& index : declr_output_attribute) {
// TODO(bunnei): Use proper number of elements for these // TODO(bunnei): Use proper number of elements for these
<<<<<<< HEAD
const u32 idx = static_cast<u32>(index) - const u32 idx = static_cast<u32>(index) -
static_cast<u32>(Attribute::Index::Attribute_0) + static_cast<u32>(Attribute::Index::Attribute_0) +
GENERIC_VARYING_START_LOCATION; GENERIC_VARYING_START_LOCATION;
declarations.AddLine("layout (location = " + std::to_string(idx) + ") out vec4 " + declarations.AddLine("layout (location = " + std::to_string(idx) + ") out vec4 " +
GetOutputAttribute(index) + ';'); 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(); declarations.AddNewLine();
} }
@@ -737,11 +710,7 @@ private:
const Tegra::Shader::IpaMode& input_mode, const Tegra::Shader::IpaMode& input_mode,
boost::optional<Register> vertex = {}) { boost::optional<Register> vertex = {}) {
auto GeometryPass = [&](const std::string& name) { auto GeometryPass = [&](const std::string& name) {
<<<<<<< HEAD
if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) { 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 "gs_" + name + '[' + GetRegisterAsInteger(vertex.value(), 0, false) + ']';
} }
return name; return name;
@@ -878,9 +847,14 @@ public:
: subroutines(subroutines), program_code(program_code), main_offset(main_offset), : subroutines(subroutines), program_code(program_code), main_offset(main_offset),
stage(stage), suffix(suffix) { stage(stage), suffix(suffix) {
std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
faulty = false;
Generate(suffix); Generate(suffix);
} }
bool IsFaulty() {
return faulty;
}
std::string GetShaderCode() { std::string GetShaderCode() {
return declarations.GetResult() + shader.GetResult(); return declarations.GetResult() + shader.GetResult();
} }
@@ -1260,6 +1234,7 @@ private:
// Decoding failure // Decoding failure
if (!opcode) { if (!opcode) {
faulty = true;
LOG_CRITICAL(HW_GPU, "Unhandled instruction: {0:x}", instr.value); LOG_CRITICAL(HW_GPU, "Unhandled instruction: {0:x}", instr.value);
UNREACHABLE(); UNREACHABLE();
return offset + 1; return offset + 1;
@@ -3237,6 +3212,7 @@ private:
const u32 main_offset; const u32 main_offset;
Maxwell3D::Regs::ShaderStage stage; Maxwell3D::Regs::ShaderStage stage;
const std::string& suffix; const std::string& suffix;
bool faulty;
ShaderWriter shader; ShaderWriter shader;
ShaderWriter declarations; ShaderWriter declarations;
@@ -3253,11 +3229,12 @@ std::string GetCommonDeclarations() {
boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
Maxwell3D::Regs::ShaderStage stage, Maxwell3D::Regs::ShaderStage stage,
const std::string& suffix) { const std::string& suffix, bool& faulty_shader) {
try { try {
const auto subroutines = const auto subroutines =
ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines(); ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines();
GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix); GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix);
faulty_shader = generator.IsFaulty();
return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
} catch (const DecompileFail& exception) { } catch (const DecompileFail& exception) {
LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what()); LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());

View File

@@ -20,6 +20,6 @@ std::string GetCommonDeclarations();
boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
Maxwell3D::Regs::ShaderStage stage, Maxwell3D::Regs::ShaderStage stage,
const std::string& suffix); const std::string& suffix, bool& faulty_shader);
} // namespace OpenGL::GLShader::Decompiler } // namespace OpenGL::GLShader::Decompiler

View 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();
}

View 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;
};

View File

@@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_opengl/gl_shader_decompiler.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" #include "video_core/renderer_opengl/gl_shader_gen.h"
namespace OpenGL::GLShader { namespace OpenGL::GLShader {
@@ -14,11 +15,12 @@ using Tegra::Engines::Maxwell3D;
static constexpr u32 PROGRAM_OFFSET{10}; static constexpr u32 PROGRAM_OFFSET{10};
ProgramResult GenerateVertexShader(const ShaderSetup& setup) { ProgramResult GenerateVertexShader(const ShaderSetup& setup) {
bool faultyA = false;
bool faultyB = false;
std::string out = "#version 430 core\n"; std::string out = "#version 430 core\n";
out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
out += Decompiler::GetCommonDeclarations(); out += Decompiler::GetCommonDeclarations();
<<<<<<< HEAD
out += R"( out += R"(
out gl_PerVertex { out gl_PerVertex {
vec4 gl_Position; vec4 gl_Position;
@@ -29,17 +31,6 @@ layout(std140) uniform vs_config {
uvec4 instance_id; uvec4 instance_id;
uvec4 flip_stage; 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()) { if (setup.IsDualProgram()) {
@@ -48,19 +39,11 @@ layout(std140) uniform vs_config {
ProgramResult program = ProgramResult program =
Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET, Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
Maxwell3D::Regs::ShaderStage::Vertex, "vertex") Maxwell3D::Regs::ShaderStage::Vertex, "vertex", faultyA)
.get_value_or({}); .get_value_or({});
out += program.first; 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"( out += R"(
void main() { 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}; return {out, program.second};
} }
ProgramResult GenerateGeometryShader(const ShaderSetup& setup) { ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
bool faulty = false;
std::string out = "#version 430 core\n"; std::string out = "#version 430 core\n";
out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
out += Decompiler::GetCommonDeclarations(); out += Decompiler::GetCommonDeclarations();
@@ -101,13 +100,12 @@ ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
ProgramResult program = ProgramResult program =
Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET, Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
Maxwell3D::Regs::ShaderStage::Geometry, "geometry") Maxwell3D::Regs::ShaderStage::Geometry, "geometry", faulty)
.get_value_or({}); .get_value_or({});
out += R"( out += R"(
out gl_PerVertex { out gl_PerVertex {
vec4 gl_Position; vec4 gl_Position;
}; };
<<<<<<< HEAD
layout (std140) uniform gs_config { layout (std140) uniform gs_config {
vec4 viewport_flip; vec4 viewport_flip;
@@ -115,25 +113,21 @@ layout (std140) uniform gs_config {
uvec4 flip_stage; uvec4 flip_stage;
}; };
=======
layout (std140) uniform gs_config {
vec4 viewport_flip;
uvec4 instance_id;
uvec4 flip_stage;
};
>>>>>>> glsl_decompiler: Implement geometry shaders
void main() { void main() {
exec_geometry(); exec_geometry();
} }
)"; )";
out += program.first; out += program.first;
if (faulty) {
ShaderDumper s(setup.program.code, "GS");
s.dump();
}
return {out, program.second}; return {out, program.second};
} }
ProgramResult GenerateFragmentShader(const ShaderSetup& setup) { ProgramResult GenerateFragmentShader(const ShaderSetup& setup) {
bool faulty = false;
std::string out = "#version 430 core\n"; std::string out = "#version 430 core\n";
out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
out += Decompiler::GetCommonDeclarations(); out += Decompiler::GetCommonDeclarations();
@@ -141,7 +135,7 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup) {
ProgramResult program = ProgramResult program =
Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET, Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
Maxwell3D::Regs::ShaderStage::Fragment, "fragment") Maxwell3D::Regs::ShaderStage::Fragment, "fragment", faulty)
.get_value_or({}); .get_value_or({});
out += R"( out += R"(
layout(location = 0) out vec4 FragColor0; layout(location = 0) out vec4 FragColor0;
@@ -165,6 +159,10 @@ void main() {
)"; )";
out += program.first; out += program.first;
if (faulty) {
ShaderDumper s(setup.program.code, "FM");
s.dump();
}
return {out, program.second}; return {out, program.second};
} }
} // namespace OpenGL::GLShader } // namespace OpenGL::GLShader