Skeleton SPIRV translator.
This commit is contained in:
parent
d2f7cc1602
commit
cd50aac6d2
|
@ -94,17 +94,18 @@ int shader_compiler_main(const std::vector<std::wstring>& args) {
|
||||||
const void* source_data = translated_shader->binary().data();
|
const void* source_data = translated_shader->binary().data();
|
||||||
size_t source_data_size = translated_shader->binary().size();
|
size_t source_data_size = translated_shader->binary().size();
|
||||||
|
|
||||||
|
std::unique_ptr<xe::ui::spirv::SpirvDisassembler::Result> spirv_disasm_result;
|
||||||
if (FLAGS_shader_output_type == "spirvtext") {
|
if (FLAGS_shader_output_type == "spirvtext") {
|
||||||
// Disassemble SPIRV.
|
// Disassemble SPIRV.
|
||||||
auto disasm_result = xe::ui::spirv::SpirvDisassembler().Disassemble(
|
spirv_disasm_result = xe::ui::spirv::SpirvDisassembler().Disassemble(
|
||||||
reinterpret_cast<const uint32_t*>(source_data), source_data_size / 4);
|
reinterpret_cast<const uint32_t*>(source_data), source_data_size / 4);
|
||||||
source_data = disasm_result->text();
|
source_data = spirv_disasm_result->text();
|
||||||
source_data_size = std::strlen(disasm_result->text()) + 1;
|
source_data_size = std::strlen(spirv_disasm_result->text()) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FLAGS_shader_output.empty()) {
|
if (!FLAGS_shader_output.empty()) {
|
||||||
auto output_file = fopen(FLAGS_shader_output.c_str(), "w");
|
auto output_file = fopen(FLAGS_shader_output.c_str(), "wb");
|
||||||
fwrite(source_data, source_data_size, 1, output_file);
|
fwrite(source_data, 1, source_data_size, output_file);
|
||||||
fclose(output_file);
|
fclose(output_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,14 @@ void ShaderTranslator::EmitTranslationError(const char* message) {
|
||||||
errors_.push_back(std::move(error));
|
errors_.push_back(std::move(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShaderTranslator::EmitUnimplementedTranslationError() {
|
||||||
|
TranslatedShader::Error error;
|
||||||
|
error.is_fatal = true;
|
||||||
|
error.message = "Unimplemented translation";
|
||||||
|
// TODO(benvanik): location information.
|
||||||
|
errors_.push_back(std::move(error));
|
||||||
|
}
|
||||||
|
|
||||||
void ShaderTranslator::GatherBindingInformation(
|
void ShaderTranslator::GatherBindingInformation(
|
||||||
const ControlFlowInstruction& cf) {
|
const ControlFlowInstruction& cf) {
|
||||||
switch (cf.opcode()) {
|
switch (cf.opcode()) {
|
||||||
|
|
|
@ -538,6 +538,9 @@ class ShaderTranslator {
|
||||||
StringBuffer& ucode_disasm_buffer() { return ucode_disasm_buffer_; }
|
StringBuffer& ucode_disasm_buffer() { return ucode_disasm_buffer_; }
|
||||||
// Emits a translation error that will be passed back in the result.
|
// Emits a translation error that will be passed back in the result.
|
||||||
void EmitTranslationError(const char* message);
|
void EmitTranslationError(const char* message);
|
||||||
|
// Emits a translation error indicating that the current translation is not
|
||||||
|
// implemented or supported.
|
||||||
|
void EmitUnimplementedTranslationError();
|
||||||
|
|
||||||
// Handles the start of translation.
|
// Handles the start of translation.
|
||||||
// At this point the vertex and texture bindings have been gathered.
|
// At this point the vertex and texture bindings have been gathered.
|
||||||
|
|
|
@ -16,8 +16,248 @@ SpirvShaderTranslator::SpirvShaderTranslator() = default;
|
||||||
|
|
||||||
SpirvShaderTranslator::~SpirvShaderTranslator() = default;
|
SpirvShaderTranslator::~SpirvShaderTranslator() = default;
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::StartTranslation() {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
auto fn = e.MakeMainEntry();
|
||||||
|
auto float_1_0 = e.MakeFloatConstant(1.0f);
|
||||||
|
auto acos = e.CreateGlslStd450InstructionCall(
|
||||||
|
spv::Decoration::Invariant, e.MakeFloatType(32), spv::GLSLstd450::Acos,
|
||||||
|
{{float_1_0}});
|
||||||
|
e.MakeReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
|
std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
|
||||||
return std::vector<uint8_t>();
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
std::vector<uint32_t> spirv_words;
|
||||||
|
e.Serialize(spirv_words);
|
||||||
|
|
||||||
|
std::vector<uint8_t> spirv_bytes;
|
||||||
|
spirv_bytes.resize(spirv_words.size() * 4);
|
||||||
|
std::memcpy(spirv_bytes.data(), spirv_words.data(), spirv_bytes.size());
|
||||||
|
return spirv_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessLabel(uint32_t cf_index) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessControlFlowNopInstruction() {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessExecInstructionBegin(
|
||||||
|
const ParsedExecInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessExecInstructionEnd(
|
||||||
|
const ParsedExecInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessLoopStartInstruction(
|
||||||
|
const ParsedLoopStartInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessLoopEndInstruction(
|
||||||
|
const ParsedLoopEndInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessCallInstruction(
|
||||||
|
const ParsedCallInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessReturnInstruction(
|
||||||
|
const ParsedReturnInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessJumpInstruction(
|
||||||
|
const ParsedJumpInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessAllocInstruction(
|
||||||
|
const ParsedAllocInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessVertexFetchInstruction(
|
||||||
|
const ParsedVertexFetchInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||||
|
const ParsedTextureFetchInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessAluInstruction(
|
||||||
|
const ParsedAluInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
switch (instr.type) {
|
||||||
|
case ParsedAluInstruction::Type::kNop:
|
||||||
|
e.CreateNop();
|
||||||
|
break;
|
||||||
|
case ParsedAluInstruction::Type::kVector:
|
||||||
|
ProcessVectorAluInstruction(instr);
|
||||||
|
break;
|
||||||
|
case ParsedAluInstruction::Type::kScalar:
|
||||||
|
ProcessScalarAluInstruction(instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessVectorAluInstruction(
|
||||||
|
const ParsedAluInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessScalarAluInstruction(
|
||||||
|
const ParsedAluInstruction& instr) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
spv::Id value_id = LoadFromOperand(instr.operands[0]);
|
||||||
|
|
||||||
|
StoreToResult(value_id, instr.result);
|
||||||
|
|
||||||
|
EmitUnimplementedTranslationError();
|
||||||
|
}
|
||||||
|
|
||||||
|
spv::Id SpirvShaderTranslator::LoadFromOperand(const InstructionOperand& op) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
spv::Id current_type_id = e.MakeFloatType(32);
|
||||||
|
spv::Id current_value_id = e.CreateUndefined(current_type_id);
|
||||||
|
|
||||||
|
// storage_addressing_mode
|
||||||
|
switch (op.storage_source) {
|
||||||
|
case InstructionStorageSource::kRegister:
|
||||||
|
//
|
||||||
|
op.storage_index;
|
||||||
|
break;
|
||||||
|
case InstructionStorageSource::kConstantFloat:
|
||||||
|
//
|
||||||
|
op.storage_index;
|
||||||
|
break;
|
||||||
|
case InstructionStorageSource::kConstantInt:
|
||||||
|
//
|
||||||
|
op.storage_index;
|
||||||
|
break;
|
||||||
|
case InstructionStorageSource::kConstantBool:
|
||||||
|
//
|
||||||
|
op.storage_index;
|
||||||
|
break;
|
||||||
|
case InstructionStorageSource::kVertexFetchConstant:
|
||||||
|
//
|
||||||
|
op.storage_index;
|
||||||
|
break;
|
||||||
|
case InstructionStorageSource::kTextureFetchConstant:
|
||||||
|
//
|
||||||
|
op.storage_index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.is_absolute_value) {
|
||||||
|
current_value_id = e.CreateGlslStd450InstructionCall(
|
||||||
|
spv::Decoration::RelaxedPrecision, current_type_id,
|
||||||
|
spv::GLSLstd450::FAbs, {current_value_id});
|
||||||
|
}
|
||||||
|
if (op.is_negated) {
|
||||||
|
current_value_id =
|
||||||
|
e.CreateUnaryOp(spv::Op::OpFNegate, current_type_id, current_value_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// swizzle
|
||||||
|
|
||||||
|
return current_value_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::StoreToResult(spv::Id source_value_id,
|
||||||
|
const InstructionResult& result) {
|
||||||
|
auto& e = emitter_;
|
||||||
|
|
||||||
|
if (result.storage_target == InstructionStorageTarget::kNone) {
|
||||||
|
// No-op?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
spv::Id storage_pointer = 0;
|
||||||
|
// storage_addressing_mode
|
||||||
|
switch (result.storage_target) {
|
||||||
|
case InstructionStorageTarget::kRegister:
|
||||||
|
//
|
||||||
|
result.storage_index;
|
||||||
|
break;
|
||||||
|
case InstructionStorageTarget::kInterpolant:
|
||||||
|
//
|
||||||
|
result.storage_index;
|
||||||
|
break;
|
||||||
|
case InstructionStorageTarget::kPosition:
|
||||||
|
//
|
||||||
|
break;
|
||||||
|
case InstructionStorageTarget::kPointSize:
|
||||||
|
//
|
||||||
|
break;
|
||||||
|
case InstructionStorageTarget::kColorTarget:
|
||||||
|
//
|
||||||
|
result.storage_index;
|
||||||
|
break;
|
||||||
|
case InstructionStorageTarget::kDepth:
|
||||||
|
//
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
spv::Id current_value_id = source_value_id;
|
||||||
|
spv::Id current_type_id = e.GetTypeId(source_value_id);
|
||||||
|
|
||||||
|
// Clamp the input value.
|
||||||
|
if (result.is_clamped) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
// write mask
|
||||||
|
|
||||||
|
// swizzle
|
||||||
|
|
||||||
|
// Convert to the appropriate type, if needed.
|
||||||
|
spv::Id desired_type_id = e.MakeFloatType(32);
|
||||||
|
if (current_value_id != desired_type_id) {
|
||||||
|
EmitTranslationError("Type conversion on storage not yet implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform store into the pointer.
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "xenia/gpu/shader_translator.h"
|
#include "xenia/gpu/shader_translator.h"
|
||||||
|
#include "xenia/ui/spirv/spirv_emitter.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
@ -25,7 +26,41 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||||
~SpirvShaderTranslator() override;
|
~SpirvShaderTranslator() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void StartTranslation() override;
|
||||||
std::vector<uint8_t> CompleteTranslation() override;
|
std::vector<uint8_t> CompleteTranslation() override;
|
||||||
|
|
||||||
|
void ProcessLabel(uint32_t cf_index) override;
|
||||||
|
void ProcessControlFlowNopInstruction() override;
|
||||||
|
void ProcessExecInstructionBegin(const ParsedExecInstruction& instr) override;
|
||||||
|
void ProcessExecInstructionEnd(const ParsedExecInstruction& instr) override;
|
||||||
|
void ProcessLoopStartInstruction(
|
||||||
|
const ParsedLoopStartInstruction& instr) override;
|
||||||
|
void ProcessLoopEndInstruction(
|
||||||
|
const ParsedLoopEndInstruction& instr) override;
|
||||||
|
void ProcessCallInstruction(const ParsedCallInstruction& instr) override;
|
||||||
|
void ProcessReturnInstruction(const ParsedReturnInstruction& instr) override;
|
||||||
|
void ProcessJumpInstruction(const ParsedJumpInstruction& instr) override;
|
||||||
|
void ProcessAllocInstruction(const ParsedAllocInstruction& instr) override;
|
||||||
|
void ProcessVertexFetchInstruction(
|
||||||
|
const ParsedVertexFetchInstruction& instr) override;
|
||||||
|
void ProcessTextureFetchInstruction(
|
||||||
|
const ParsedTextureFetchInstruction& instr) override;
|
||||||
|
void ProcessAluInstruction(const ParsedAluInstruction& instr) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ProcessVectorAluInstruction(const ParsedAluInstruction& instr);
|
||||||
|
void ProcessScalarAluInstruction(const ParsedAluInstruction& instr);
|
||||||
|
|
||||||
|
// Loads an operand into a value.
|
||||||
|
// The value returned will be in the form described in the operand (number of
|
||||||
|
// components, etc).
|
||||||
|
spv::Id LoadFromOperand(const InstructionOperand& op);
|
||||||
|
// Stores a value based on the specified result information.
|
||||||
|
// The value will be transformed into the appropriate form for the result and
|
||||||
|
// the proper components will be selected.
|
||||||
|
void StoreToResult(spv::Id source_value_id, const InstructionResult& result);
|
||||||
|
|
||||||
|
xe::ui::spirv::SpirvEmitter emitter_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace shader_playground {
|
||||||
};
|
};
|
||||||
|
|
||||||
sourceCodeTextBox.Text = string.Join(
|
sourceCodeTextBox.Text = string.Join(
|
||||||
"\r\n", new string[] {
|
Environment.NewLine, new string[] {
|
||||||
"xps_3_0",
|
"xps_3_0",
|
||||||
"dcl_texcoord1 r0",
|
"dcl_texcoord1 r0",
|
||||||
"dcl_color r1.xy",
|
"dcl_color r1.xy",
|
||||||
|
@ -134,7 +134,7 @@ namespace shader_playground {
|
||||||
Microsoft.Xna.Framework.TargetPlatform.Xbox360);
|
Microsoft.Xna.Framework.TargetPlatform.Xbox360);
|
||||||
|
|
||||||
var disassembledSourceCode = compiledShader.ErrorsAndWarnings;
|
var disassembledSourceCode = compiledShader.ErrorsAndWarnings;
|
||||||
disassembledSourceCode = disassembledSourceCode.Replace("\n", "\r\n");
|
disassembledSourceCode = disassembledSourceCode.Replace("\n", Environment.NewLine);
|
||||||
if (disassembledSourceCode.IndexOf("// PDB hint 00000000-00000000-00000000") == -1) {
|
if (disassembledSourceCode.IndexOf("// PDB hint 00000000-00000000-00000000") == -1) {
|
||||||
outputTextBox.Text = disassembledSourceCode;
|
outputTextBox.Text = disassembledSourceCode;
|
||||||
compilerUcodeTextBox.Text = "";
|
compilerUcodeTextBox.Text = "";
|
||||||
|
@ -147,11 +147,11 @@ namespace shader_playground {
|
||||||
disassembledSourceCode =
|
disassembledSourceCode =
|
||||||
disassembledSourceCode.Replace(prefix + ": ", "");
|
disassembledSourceCode.Replace(prefix + ": ", "");
|
||||||
disassembledSourceCode = disassembledSourceCode.Replace(
|
disassembledSourceCode = disassembledSourceCode.Replace(
|
||||||
"// PDB hint 00000000-00000000-00000000\r\n", "");
|
"// PDB hint 00000000-00000000-00000000" + Environment.NewLine, "");
|
||||||
var firstLine = disassembledSourceCode.IndexOf("//");
|
var firstLine = disassembledSourceCode.IndexOf("//");
|
||||||
var warnings = "// " +
|
var warnings = "// " +
|
||||||
disassembledSourceCode.Substring(0, firstLine)
|
disassembledSourceCode.Substring(0, firstLine)
|
||||||
.Replace("\r\n", "\r\n// ");
|
.Replace(Environment.NewLine, Environment.NewLine + "// ");
|
||||||
disassembledSourceCode =
|
disassembledSourceCode =
|
||||||
warnings + disassembledSourceCode.Substring(firstLine + 3);
|
warnings + disassembledSourceCode.Substring(firstLine + 3);
|
||||||
disassembledSourceCode = disassembledSourceCode.Trim();
|
disassembledSourceCode = disassembledSourceCode.Trim();
|
||||||
|
@ -209,7 +209,7 @@ namespace shader_playground {
|
||||||
process.WaitForExit();
|
process.WaitForExit();
|
||||||
}
|
}
|
||||||
string disasmText = File.ReadAllText(ucodeDisasmPath);
|
string disasmText = File.ReadAllText(ucodeDisasmPath);
|
||||||
compilerUcodeTextBox.Text = disasmText;
|
compilerUcodeTextBox.Text = disasmText.Replace("\n", Environment.NewLine);
|
||||||
} catch {
|
} catch {
|
||||||
compilerUcodeTextBox.Text = "COMPILER FAILURE";
|
compilerUcodeTextBox.Text = "COMPILER FAILURE";
|
||||||
}
|
}
|
||||||
|
@ -236,7 +236,7 @@ namespace shader_playground {
|
||||||
process.WaitForExit();
|
process.WaitForExit();
|
||||||
}
|
}
|
||||||
string disasmText = File.ReadAllText(translatedDisasmPath);
|
string disasmText = File.ReadAllText(translatedDisasmPath);
|
||||||
compilerTranslatedTextBox.Text = disasmText;
|
compilerTranslatedTextBox.Text = disasmText.Replace("\n", Environment.NewLine);
|
||||||
} catch {
|
} catch {
|
||||||
compilerTranslatedTextBox.Text = "COMPILER FAILURE";
|
compilerTranslatedTextBox.Text = "COMPILER FAILURE";
|
||||||
}
|
}
|
||||||
|
@ -300,8 +300,8 @@ namespace shader_playground {
|
||||||
for (int i = 0; i < swappedCode.Length; ++i) {
|
for (int i = 0; i < swappedCode.Length; ++i) {
|
||||||
sb.AppendFormat("0x{0:X8}, ", swappedCode[i]);
|
sb.AppendFormat("0x{0:X8}, ", swappedCode[i]);
|
||||||
}
|
}
|
||||||
sb.Append("};\r\n");
|
sb.Append("};" + Environment.NewLine);
|
||||||
sb.Append("shader_type = ShaderType::" + (shaderType == "vs" ? "kVertex" : "kPixel") + ";\r\n");
|
sb.Append("shader_type = ShaderType::" + (shaderType == "vs" ? "kVertex" : "kPixel") + ";" + Environment.NewLine);
|
||||||
wordsTextBox.Text = sb.ToString();
|
wordsTextBox.Text = sb.ToString();
|
||||||
wordsTextBox.SelectAll();
|
wordsTextBox.SelectAll();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue