Compare commits

...

3 Commits

Author SHA1 Message Date
FernandoS27
26c4cb1fdc Implement dumping the decompiled shader as well 2018-10-19 22:21:40 -04:00
FernandoS27
f72b9e2c32 Implemented Shader Dumper 2018-10-19 19:12:41 -04:00
ReinUsesLisp
03feb29bce glsl_decompiler: Implement geometry shaders 2018-10-19 18:03:06 -04:00
6 changed files with 133 additions and 14 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

@@ -847,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();
}
@@ -1229,6 +1234,7 @@ private:
// Decoding failure
if (!opcode) {
faulty = true;
LOG_CRITICAL(HW_GPU, "Unhandled instruction: {0:x}", instr.value);
UNREACHABLE();
return offset + 1;
@@ -3206,6 +3212,7 @@ private:
const u32 main_offset;
Maxwell3D::Regs::ShaderStage stage;
const std::string& suffix;
bool faulty;
ShaderWriter shader;
ShaderWriter declarations;
@@ -3222,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,61 @@
#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() {
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() + ".bin";
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();
}
void ShaderDumper::dumpText(const std::string& s) {
FileUtil::IOFile sFile;
std::string name = prefix + hashName() + ".txt";
sFile.Open(name, "w");
sFile.WriteString(s);
sFile.Close();
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include <array>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "common/hash.h"
class ShaderDumper {
public:
ShaderDumper(const std::vector<u64>& prog, std::string prefix) : program(prog) {
this->hash = Common::ComputeHash64(program.data(), sizeof(u64) * program.size());
this->prefix = prefix;
}
void dump();
void dumpText(const std::string& s);
private:
std::string hashName();
u64 hash;
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,6 +15,8 @@ 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();
@@ -36,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() {
@@ -77,11 +72,29 @@ 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();
s.dumpText(out);
}
if (faultyB) {
ShaderDumper s(setup.program.code_b, "VS");
s.dump();
s.dumpText(out);
}
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();
@@ -89,7 +102,7 @@ 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 {
@@ -108,10 +121,16 @@ void main() {
)";
out += program.first;
if (faulty) {
ShaderDumper s(setup.program.code, "GS");
s.dump();
s.dumpText(out);
}
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();
@@ -119,7 +138,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;
@@ -143,6 +162,11 @@ void main() {
)";
out += program.first;
if (faulty) {
ShaderDumper s(setup.program.code, "FM");
s.dump();
s.dumpText(out);
}
return {out, program.second};
}
} // namespace OpenGL::GLShader
} // namespace OpenGL::GLShader