From cd50aac6d254e478eb7960d3947350f1be34e70b Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sun, 29 Nov 2015 19:45:55 -0800 Subject: [PATCH] Skeleton SPIRV translator. --- src/xenia/gpu/shader_compiler_main.cc | 11 +- src/xenia/gpu/shader_translator.cc | 8 + src/xenia/gpu/shader_translator.h | 3 + src/xenia/gpu/spirv_shader_translator.cc | 242 ++++++++++++++++++++++- src/xenia/gpu/spirv_shader_translator.h | 35 ++++ tools/shader-playground/Editor.cs | 16 +- 6 files changed, 301 insertions(+), 14 deletions(-) diff --git a/src/xenia/gpu/shader_compiler_main.cc b/src/xenia/gpu/shader_compiler_main.cc index cc7886b72..7d845d78e 100644 --- a/src/xenia/gpu/shader_compiler_main.cc +++ b/src/xenia/gpu/shader_compiler_main.cc @@ -94,17 +94,18 @@ int shader_compiler_main(const std::vector& args) { const void* source_data = translated_shader->binary().data(); size_t source_data_size = translated_shader->binary().size(); + std::unique_ptr spirv_disasm_result; if (FLAGS_shader_output_type == "spirvtext") { // Disassemble SPIRV. - auto disasm_result = xe::ui::spirv::SpirvDisassembler().Disassemble( + spirv_disasm_result = xe::ui::spirv::SpirvDisassembler().Disassemble( reinterpret_cast(source_data), source_data_size / 4); - source_data = disasm_result->text(); - source_data_size = std::strlen(disasm_result->text()) + 1; + source_data = spirv_disasm_result->text(); + source_data_size = std::strlen(spirv_disasm_result->text()) + 1; } if (!FLAGS_shader_output.empty()) { - auto output_file = fopen(FLAGS_shader_output.c_str(), "w"); - fwrite(source_data, source_data_size, 1, output_file); + auto output_file = fopen(FLAGS_shader_output.c_str(), "wb"); + fwrite(source_data, 1, source_data_size, output_file); fclose(output_file); } diff --git a/src/xenia/gpu/shader_translator.cc b/src/xenia/gpu/shader_translator.cc index 0fb16221b..d36673783 100644 --- a/src/xenia/gpu/shader_translator.cc +++ b/src/xenia/gpu/shader_translator.cc @@ -140,6 +140,14 @@ void ShaderTranslator::EmitTranslationError(const char* message) { 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( const ControlFlowInstruction& cf) { switch (cf.opcode()) { diff --git a/src/xenia/gpu/shader_translator.h b/src/xenia/gpu/shader_translator.h index fb8305bbe..f77e18971 100644 --- a/src/xenia/gpu/shader_translator.h +++ b/src/xenia/gpu/shader_translator.h @@ -538,6 +538,9 @@ class ShaderTranslator { StringBuffer& ucode_disasm_buffer() { return ucode_disasm_buffer_; } // Emits a translation error that will be passed back in the result. 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. // At this point the vertex and texture bindings have been gathered. diff --git a/src/xenia/gpu/spirv_shader_translator.cc b/src/xenia/gpu/spirv_shader_translator.cc index 5f89b3882..0c461ea62 100644 --- a/src/xenia/gpu/spirv_shader_translator.cc +++ b/src/xenia/gpu/spirv_shader_translator.cc @@ -16,8 +16,248 @@ 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 SpirvShaderTranslator::CompleteTranslation() { - return std::vector(); + auto& e = emitter_; + + std::vector spirv_words; + e.Serialize(spirv_words); + + std::vector 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 diff --git a/src/xenia/gpu/spirv_shader_translator.h b/src/xenia/gpu/spirv_shader_translator.h index 2548c80d1..fc068a33d 100644 --- a/src/xenia/gpu/spirv_shader_translator.h +++ b/src/xenia/gpu/spirv_shader_translator.h @@ -15,6 +15,7 @@ #include #include "xenia/gpu/shader_translator.h" +#include "xenia/ui/spirv/spirv_emitter.h" namespace xe { namespace gpu { @@ -25,7 +26,41 @@ class SpirvShaderTranslator : public ShaderTranslator { ~SpirvShaderTranslator() override; protected: + void StartTranslation() override; std::vector 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 diff --git a/tools/shader-playground/Editor.cs b/tools/shader-playground/Editor.cs index 1161cf83d..785f24cd1 100644 --- a/tools/shader-playground/Editor.cs +++ b/tools/shader-playground/Editor.cs @@ -60,7 +60,7 @@ namespace shader_playground { }; sourceCodeTextBox.Text = string.Join( - "\r\n", new string[] { + Environment.NewLine, new string[] { "xps_3_0", "dcl_texcoord1 r0", "dcl_color r1.xy", @@ -134,7 +134,7 @@ namespace shader_playground { Microsoft.Xna.Framework.TargetPlatform.Xbox360); 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) { outputTextBox.Text = disassembledSourceCode; compilerUcodeTextBox.Text = ""; @@ -147,11 +147,11 @@ namespace shader_playground { disassembledSourceCode = disassembledSourceCode.Replace(prefix + ": ", ""); disassembledSourceCode = disassembledSourceCode.Replace( - "// PDB hint 00000000-00000000-00000000\r\n", ""); + "// PDB hint 00000000-00000000-00000000" + Environment.NewLine, ""); var firstLine = disassembledSourceCode.IndexOf("//"); var warnings = "// " + disassembledSourceCode.Substring(0, firstLine) - .Replace("\r\n", "\r\n// "); + .Replace(Environment.NewLine, Environment.NewLine + "// "); disassembledSourceCode = warnings + disassembledSourceCode.Substring(firstLine + 3); disassembledSourceCode = disassembledSourceCode.Trim(); @@ -209,7 +209,7 @@ namespace shader_playground { process.WaitForExit(); } string disasmText = File.ReadAllText(ucodeDisasmPath); - compilerUcodeTextBox.Text = disasmText; + compilerUcodeTextBox.Text = disasmText.Replace("\n", Environment.NewLine); } catch { compilerUcodeTextBox.Text = "COMPILER FAILURE"; } @@ -236,7 +236,7 @@ namespace shader_playground { process.WaitForExit(); } string disasmText = File.ReadAllText(translatedDisasmPath); - compilerTranslatedTextBox.Text = disasmText; + compilerTranslatedTextBox.Text = disasmText.Replace("\n", Environment.NewLine); } catch { compilerTranslatedTextBox.Text = "COMPILER FAILURE"; } @@ -300,8 +300,8 @@ namespace shader_playground { for (int i = 0; i < swappedCode.Length; ++i) { sb.AppendFormat("0x{0:X8}, ", swappedCode[i]); } - sb.Append("};\r\n"); - sb.Append("shader_type = ShaderType::" + (shaderType == "vs" ? "kVertex" : "kPixel") + ";\r\n"); + sb.Append("};" + Environment.NewLine); + sb.Append("shader_type = ShaderType::" + (shaderType == "vs" ? "kVertex" : "kPixel") + ";" + Environment.NewLine); wordsTextBox.Text = sb.ToString(); wordsTextBox.SelectAll();