diff --git a/src/xenia/gpu/spirv_shader_translator.cc b/src/xenia/gpu/spirv_shader_translator.cc index bf64a4599..dee001b99 100644 --- a/src/xenia/gpu/spirv_shader_translator.cc +++ b/src/xenia/gpu/spirv_shader_translator.cc @@ -827,6 +827,51 @@ void SpirvShaderTranslator::UpdateExecConditionals( builder_->setBuildPoint(&inner_block); } +void SpirvShaderTranslator::UpdateInstructionPredication(bool predicated, + bool condition) { + if (!predicated) { + CloseInstructionPredication(); + return; + } + + if (cf_instruction_predicate_merge_) { + if (cf_instruction_predicate_condition_ == condition) { + // Already in the needed instruction-level conditional. + return; + } + CloseInstructionPredication(); + } + + // If the instruction predicate condition is the same as the exec predicate + // condition, no need to open a check. However, if there was a `setp` prior + // to this instruction, the predicate value now may be different than it was + // in the beginning of the exec. + if (!cf_exec_predicate_written_ && cf_exec_conditional_merge_ && + cf_exec_bool_constant_or_predicate_ == kCfExecBoolConstantPredicate && + cf_exec_condition_ == condition) { + return; + } + + cf_instruction_predicate_condition_ = condition; + EnsureBuildPointAvailable(); + spv::Id predicate_id = + builder_->createLoad(var_main_predicate_, spv::NoPrecision); + spv::Block& predicated_block = builder_->makeNewBlock(); + cf_instruction_predicate_merge_ = &builder_->makeNewBlock(); + { + std::unique_ptr selection_merge_op = + std::make_unique(spv::OpSelectionMerge); + selection_merge_op->addIdOperand(cf_instruction_predicate_merge_->getId()); + selection_merge_op->addImmediateOperand(spv::SelectionControlMaskNone); + builder_->getBuildPoint()->addInstruction(std::move(selection_merge_op)); + } + builder_->createConditionalBranch( + predicate_id, + condition ? &predicated_block : cf_instruction_predicate_merge_, + condition ? cf_instruction_predicate_merge_ : &predicated_block); + builder_->setBuildPoint(&predicated_block); +} + void SpirvShaderTranslator::CloseInstructionPredication() { if (!cf_instruction_predicate_merge_) { return; diff --git a/src/xenia/gpu/spirv_shader_translator.h b/src/xenia/gpu/spirv_shader_translator.h index 6cd94e415..473afb65c 100644 --- a/src/xenia/gpu/spirv_shader_translator.h +++ b/src/xenia/gpu/spirv_shader_translator.h @@ -66,6 +66,8 @@ class SpirvShaderTranslator : public ShaderTranslator { const ParsedLoopEndInstruction& instr) override; void ProcessJumpInstruction(const ParsedJumpInstruction& instr) override; + void ProcessAluInstruction(const ParsedAluInstruction& instr) override; + private: // TODO(Triang3l): Depth-only pixel shader. bool IsSpirvVertexOrTessEvalShader() const { return is_vertex_shader(); } @@ -96,6 +98,9 @@ class SpirvShaderTranslator : public ShaderTranslator { // needed (for example, in jumps). void UpdateExecConditionals(ParsedExecInstruction::Type type, uint32_t bool_constant_index, bool condition); + // Opens or reopens the predicate check conditional for the instruction. + // Should be called before processing a non-control-flow instruction. + void UpdateInstructionPredication(bool predicated, bool condition); // Closes the instruction-level predicate conditional if it's open, useful if // a control flow instruction needs to do some code which needs to respect the // current exec conditional, but can't itself be predicated. diff --git a/src/xenia/gpu/spirv_shader_translator_alu.cc b/src/xenia/gpu/spirv_shader_translator_alu.cc new file mode 100644 index 000000000..4a051012a --- /dev/null +++ b/src/xenia/gpu/spirv_shader_translator_alu.cc @@ -0,0 +1,28 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/gpu/spirv_shader_translator.h" + +namespace xe { +namespace gpu { + +void SpirvShaderTranslator::ProcessAluInstruction( + const ParsedAluInstruction& instr) { + if (instr.IsNop()) { + // Don't even disassemble or update predication. + return; + } + + UpdateInstructionPredication(instr.is_predicated, instr.predicate_condition); + + // TODO(Triang3l): Translate the ALU instruction. +} + +} // namespace gpu +} // namespace xe