First pass ShaderTranslator base type, able to disasm in msft style.

This commit is contained in:
Ben Vanik
2015-11-28 16:19:04 -08:00
parent bea8870700
commit 65130edaa1
11 changed files with 2796 additions and 716 deletions

View File

@@ -83,4 +83,10 @@ std::string StringBuffer::to_string() {
char* StringBuffer::ToString() { return strdup(buffer_); }
std::vector<uint8_t> StringBuffer::ToBytes() const {
std::vector<uint8_t> bytes(buffer_offset_);
std::memcpy(bytes.data(), buffer_, buffer_offset_);
return bytes;
}
} // namespace xe

View File

@@ -12,6 +12,7 @@
#include <cstdint>
#include <string>
#include <vector>
namespace xe {
@@ -34,6 +35,7 @@ class StringBuffer {
const char* GetString() const;
std::string to_string();
char* ToString();
std::vector<uint8_t> ToBytes() const;
private:
void Grow(size_t additional_length);

View File

@@ -18,68 +18,83 @@
#include "xenia/base/string.h"
#include "xenia/gpu/shader_translator.h"
DEFINE_string(input_shader, "", "Input shader binary file path.");
DEFINE_string(
shader_type, "",
"'vert', 'frag', or unspecified to infer from the given filename.");
DEFINE_string(shader_input, "", "Input shader binary file path.");
DEFINE_string(shader_input_type, "",
"'vs', 'ps', or unspecified to infer from the given filename.");
DEFINE_string(shader_output, "", "Output shader file path.");
DEFINE_string(shader_output_type, "ucode",
"Translator to use: [ucode, spirvtext].");
namespace xe {
namespace gpu {
int shader_compiler_main(const std::vector<std::wstring>& args) {
ShaderType shader_type;
if (!FLAGS_shader_type.empty()) {
if (FLAGS_shader_type == "vert") {
if (!FLAGS_shader_input_type.empty()) {
if (FLAGS_shader_input_type == "vs") {
shader_type = ShaderType::kVertex;
} else if (FLAGS_shader_type == "frag") {
} else if (FLAGS_shader_input_type == "ps") {
shader_type = ShaderType::kPixel;
} else {
XELOGE("Invalid --shader_type; must be 'vert' or 'frag'.");
XELOGE("Invalid --shader_input_type; must be 'vs' or 'ps'.");
return 1;
}
} else {
auto last_dot = FLAGS_input_shader.find_last_of('.');
auto last_dot = FLAGS_shader_input.find_last_of('.');
bool valid_type = false;
if (last_dot != std::string::npos) {
if (FLAGS_input_shader.substr(last_dot) == ".vert") {
if (FLAGS_shader_input.substr(last_dot) == ".vs") {
shader_type = ShaderType::kVertex;
valid_type = true;
} else if (FLAGS_input_shader.substr(last_dot) == ".frag") {
} else if (FLAGS_shader_input.substr(last_dot) == ".ps") {
shader_type = ShaderType::kPixel;
valid_type = true;
}
}
if (!valid_type) {
XELOGE(
"File type not recognized (use .vert, .frag or "
"--shader_type=vert|frag).");
"File type not recognized (use .vs, .ps or "
"--shader_input_type=vs|ps).");
return 1;
}
}
auto input_file = fopen(FLAGS_input_shader.c_str(), "r");
auto input_file = fopen(FLAGS_shader_input.c_str(), "rb");
if (!input_file) {
XELOGE("Unable to open input file: %s", FLAGS_input_shader.c_str());
XELOGE("Unable to open input file: %s", FLAGS_shader_input.c_str());
return 1;
}
fseek(input_file, 0, SEEK_END);
size_t input_file_size = ftell(input_file);
fseek(input_file, 0, SEEK_SET);
std::vector<uint32_t> ucode_words(input_file_size / 4);
fread(ucode_words.data(), 4, ucode_words.size(), input_file);
std::vector<uint32_t> ucode_dwords(input_file_size / 4);
fread(ucode_dwords.data(), 4, ucode_dwords.size(), input_file);
fclose(input_file);
XELOGI("Opened %s as a %s shader, %" PRId64 " words (%" PRId64 " bytes).",
FLAGS_input_shader.c_str(),
shader_type == ShaderType::kVertex ? "vertex" : "fragment",
ucode_words.size(), ucode_words.size() * 4);
FLAGS_shader_input.c_str(),
shader_type == ShaderType::kVertex ? "vertex" : "pixel",
ucode_dwords.size(), ucode_dwords.size() * 4);
ShaderTranslator translator;
std::unique_ptr<ShaderTranslator> translator;
if (FLAGS_shader_output_type == "spirvtext") {
// TODO(benvanik): SPIRV translator.
translator = std::make_unique<UcodeShaderTranslator>();
} else {
translator = std::make_unique<UcodeShaderTranslator>();
}
// TODO(benvanik): hash? need to return the data to big-endian format first.
uint64_t ucode_data_hash = 0;
auto translated_shader = translator.Translate(
shader_type, ucode_data_hash, ucode_words.data(), ucode_words.size());
auto translated_shader = translator->Translate(
shader_type, ucode_data_hash, ucode_dwords.data(), ucode_dwords.size());
if (!FLAGS_shader_output.empty()) {
auto output_file = fopen(FLAGS_shader_output.c_str(), "w");
fwrite(translated_shader->binary().data(),
translated_shader->binary().size(), 1, output_file);
fclose(output_file);
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,44 +11,316 @@
#define XENIA_GPU_SHADER_TRANSLATOR_H_
#include <memory>
#include <string>
#include <vector>
#include "xenia/base/string_buffer.h"
#include "xenia/gpu/ucode.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/spirv/spirv_util.h"
namespace xe {
namespace gpu {
class TranslatedShader {
public:
TranslatedShader(ShaderType shader_type, uint64_t ucode_data_hash,
const uint32_t* ucode_words, size_t ucode_word_count);
struct Error {
bool is_fatal = false;
std::string message;
};
struct VertexBinding {
// Index within the vertex binding listing.
size_t binding_index;
// Fetch constant index [0-95].
uint32_t fetch_constant;
// Fetch instruction with all parameters.
ucode::VertexFetchInstruction op;
};
struct TextureBinding {
// Index within the texture binding listing.
size_t binding_index;
// Fetch constant index [0-31].
uint32_t fetch_constant;
// Fetch instruction with all parameters.
ucode::TextureFetchInstruction op;
};
~TranslatedShader();
ShaderType type() const { return shader_type_; }
const uint32_t* ucode_words() const { return ucode_data_.data(); }
size_t ucode_word_count() const { return ucode_data_.size(); }
const std::vector<uint32_t>& ucode_data() const { return ucode_data_; }
const uint32_t* ucode_dwords() const { return ucode_data_.data(); }
size_t ucode_dword_count() const { return ucode_data_.size(); }
const std::vector<VertexBinding>& vertex_bindings() const {
return vertex_bindings_;
}
const std::vector<TextureBinding>& texture_bindings() const {
return texture_bindings_;
}
bool is_valid() const { return is_valid_; }
const std::vector<Error> errors() const { return errors_; }
const std::vector<uint8_t> binary() const { return binary_; }
private:
friend class ShaderTranslator;
TranslatedShader(ShaderType shader_type, uint64_t ucode_data_hash,
const uint32_t* ucode_dwords, size_t ucode_dword_count,
std::vector<Error> errors);
ShaderType shader_type_;
std::vector<uint32_t> ucode_data_;
uint64_t ucode_data_hash_;
std::vector<VertexBinding> vertex_bindings_;
std::vector<TextureBinding> texture_bindings_;
bool is_valid_ = false;
std::vector<Error> errors_;
std::vector<uint8_t> binary_;
};
class ShaderTranslator {
public:
ShaderTranslator();
virtual ~ShaderTranslator();
std::unique_ptr<TranslatedShader> Translate(ShaderType shader_type,
uint64_t ucode_data_hash,
const uint32_t* ucode_words,
size_t ucode_word_count);
const uint32_t* ucode_dwords,
size_t ucode_dword_count);
protected:
ShaderTranslator();
size_t ucode_disasm_line_number() const { return ucode_disasm_line_number_; }
StringBuffer& ucode_disasm_buffer() { return ucode_disasm_buffer_; }
void EmitTranslationError(const char* message);
virtual std::vector<uint8_t> CompleteTranslation() {
return std::vector<uint8_t>();
}
virtual void ProcessControlFlowNop(const ucode::ControlFlowInstruction& cf) {}
virtual void ProcessControlFlowExec(
const ucode::ControlFlowExecInstruction& cf) {}
virtual void ProcessControlFlowCondExec(
const ucode::ControlFlowCondExecInstruction& cf) {}
virtual void ProcessControlFlowCondExecPred(
const ucode::ControlFlowCondExecPredInstruction& cf) {}
virtual void ProcessControlFlowLoopStart(
const ucode::ControlFlowLoopStartInstruction& cf) {}
virtual void ProcessControlFlowLoopEnd(
const ucode::ControlFlowLoopEndInstruction& cf) {}
virtual void ProcessControlFlowCondCall(
const ucode::ControlFlowCondCallInstruction& cf) {}
virtual void ProcessControlFlowReturn(
const ucode::ControlFlowReturnInstruction& cf) {}
virtual void ProcessControlFlowCondJmp(
const ucode::ControlFlowCondJmpInstruction& cf) {}
virtual void ProcessControlFlowAlloc(
const ucode::ControlFlowAllocInstruction& cf) {}
virtual void ProcessVertexFetchInstruction(
const ucode::VertexFetchInstruction& op) {}
virtual void ProcessTextureFetchTextureFetch(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchGetTextureBorderColorFrac(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchGetTextureComputedLod(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchGetTextureGradients(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchGetTextureWeights(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchSetTextureLod(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchSetTextureGradientsHorz(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchSetTextureGradientsVert(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessAluNop(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorAdd(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMul(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMax(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMin(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorSetEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorSetGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorSetGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorSetNE(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorFrac(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorTrunc(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorFloor(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMad(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorCndEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorCndGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorCndGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorDp4(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorDp3(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorDp2Add(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorCube(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMax4(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorPredSetEQPush(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorPredSetNEPush(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorPredSetGTPush(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorPredSetGEPush(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorKillEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorKillGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorKillLGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorKillNE(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorDst(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMaxA(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarAdd(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarAddPrev(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMul(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMulPrev(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMulPrev2(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMax(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMin(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSetEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSetGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSetGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSetNE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarFrac(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarTrunc(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarFloor(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarExp(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarLogClamp(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarLog(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarRecipClamp(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarRecipFixedFunc(const ucode::AluInstruction& op) {
}
virtual void ProcessAluScalarRecip(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarRSqrtClamp(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarRSqrtFixedFunc(const ucode::AluInstruction& op) {
}
virtual void ProcessAluScalarRSqrt(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMovA(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMovAFloor(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSub(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSubPrev(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetNE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetInv(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetPop(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetClear(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetRestore(const ucode::AluInstruction& op) {
}
virtual void ProcessAluScalarKillEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarKillGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarKillGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarKillNE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarKillOne(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSqrt(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMulConst0(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMulConst1(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarAddConst0(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarAddConst1(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSubConst0(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSubConst1(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSin(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarCos(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarRetainPrev(const ucode::AluInstruction& op) {}
private:
struct AluOpcodeInfo {
const char* name;
size_t argument_count;
int src_swizzle_component_count;
void (ShaderTranslator::*fn)(const ucode::AluInstruction& op);
};
void MarkUcodeInstruction(uint32_t dword_offset);
void AppendUcodeDisasm(char c);
void AppendUcodeDisasm(const char* value);
void AppendUcodeDisasmFormat(const char* format, ...);
bool TranslateBlocks();
void GatherBindingInformation(const ucode::ControlFlowInstruction& cf);
void GatherVertexBindingInformation(const ucode::VertexFetchInstruction& op);
void GatherTextureBindingInformation(
const ucode::TextureFetchInstruction& op);
void TranslateControlFlowInstruction(const ucode::ControlFlowInstruction& cf);
void TranslateControlFlowNop(const ucode::ControlFlowInstruction& cf);
void TranslateControlFlowExec(const ucode::ControlFlowExecInstruction& cf);
void TranslateControlFlowCondExec(
const ucode::ControlFlowCondExecInstruction& cf);
void TranslateControlFlowCondExecPred(
const ucode::ControlFlowCondExecPredInstruction& cf);
void TranslateControlFlowLoopStart(
const ucode::ControlFlowLoopStartInstruction& cf);
void TranslateControlFlowLoopEnd(
const ucode::ControlFlowLoopEndInstruction& cf);
void TranslateControlFlowCondCall(
const ucode::ControlFlowCondCallInstruction& cf);
void TranslateControlFlowReturn(
const ucode::ControlFlowReturnInstruction& cf);
void TranslateControlFlowCondJmp(
const ucode::ControlFlowCondJmpInstruction& cf);
void TranslateControlFlowAlloc(const ucode::ControlFlowAllocInstruction& cf);
void TranslateExecInstructions(uint32_t address, uint32_t count,
uint32_t sequence);
void DisasmFetchDestReg(uint32_t dest, uint32_t swizzle, bool is_relative);
void DisasmFetchSourceReg(uint32_t src, uint32_t swizzle, bool is_relative,
int component_count);
void TranslateVertexFetchInstruction(const ucode::VertexFetchInstruction& op);
void TranslateTextureFetchInstruction(
const ucode::TextureFetchInstruction& op);
void DisasmVertexFetchAttributes(const ucode::VertexFetchInstruction& op);
void DisasmTextureFetchAttributes(const ucode::TextureFetchInstruction& op);
void TranslateAluInstruction(const ucode::AluInstruction& op);
void DisasmAluVectorInstruction(const ucode::AluInstruction& op,
const AluOpcodeInfo& opcode_info);
void DisasmAluScalarInstruction(const ucode::AluInstruction& op,
const AluOpcodeInfo& opcode_info);
void DisasmAluSourceReg(const ucode::AluInstruction& op, int i,
int swizzle_component_count);
void DisasmAluSourceRegScalarSpecial(const ucode::AluInstruction& op,
uint32_t reg, bool is_temp, bool negate,
int const_slot, uint32_t swizzle);
// Input shader metadata and microcode.
ShaderType shader_type_;
const uint32_t* ucode_dwords_;
size_t ucode_dword_count_;
// Accumulated translation errors.
std::vector<TranslatedShader::Error> errors_;
// Microcode disassembly buffer, accumulated throughout the translation.
StringBuffer ucode_disasm_buffer_;
// Current line number in the disasm, which can be used for source annotation.
size_t ucode_disasm_line_number_ = 0;
// Last offset used when scanning for line numbers.
size_t previous_ucode_disasm_scan_offset_ = 0;
// Kept for supporting vfetch_mini.
ucode::VertexFetchInstruction previous_vfetch_full_;
// Detected binding information gathered before translation.
std::vector<TranslatedShader::VertexBinding> vertex_bindings_;
std::vector<TranslatedShader::TextureBinding> texture_bindings_;
static const AluOpcodeInfo alu_vector_opcode_infos_[0x20];
static const AluOpcodeInfo alu_scalar_opcode_infos_[0x40];
};
class UcodeShaderTranslator : public ShaderTranslator {
public:
UcodeShaderTranslator() = default;
protected:
std::vector<uint8_t> CompleteTranslation() override;
};
} // namespace gpu

File diff suppressed because it is too large Load Diff

View File

@@ -1151,6 +1151,17 @@ Id SpirvEmitter::CreateExtendedInstructionCall(spv::Decoration precision,
return instr->result_id();
}
Id SpirvEmitter::CreateGlslStd450InstructionCall(
spv::Decoration precision, Id result_type,
spv::GLSLstd450 instruction_ordinal, std::initializer_list<Id> args) {
if (!glsl_std_450_instruction_set_) {
glsl_std_450_instruction_set_ = ImportExtendedInstructions("GLSL.std.450");
}
return CreateExtendedInstructionCall(
precision, result_type, glsl_std_450_instruction_set_,
static_cast<int>(instruction_ordinal), args);
}
// Accept all parameters needed to create a texture instruction.
// Create the correct instruction based on the inputs, and make the call.
Id SpirvEmitter::CreateTextureCall(spv::Decoration precision, Id result_type,

View File

@@ -373,6 +373,10 @@ class SpirvEmitter {
Id CreateExtendedInstructionCall(spv::Decoration precision, Id result_type,
Id instruction_set, int instruction_ordinal,
std::initializer_list<Id> args);
// Executes an instruction from the extended GLSL set.
Id CreateGlslStd450InstructionCall(spv::Decoration precision, Id result_type,
spv::GLSLstd450 instruction_ordinal,
std::initializer_list<Id> args);
// List of parameters used to create a texture operation
struct TextureParameters {
@@ -655,6 +659,7 @@ class SpirvEmitter {
Id unique_id_ = 0;
Function* main_function_ = nullptr;
AccessChain access_chain_;
Id glsl_std_450_instruction_set_ = 0;
// special blocks of instructions for output
std::vector<Instruction*> imports_;