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_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

View File

@@ -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());

View File

@@ -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

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 "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