diff --git a/src/xenia/gpu/spirv_shader_translator_alu.cc b/src/xenia/gpu/spirv_shader_translator_alu.cc index 87b132853..83681a621 100644 --- a/src/xenia/gpu/spirv_shader_translator_alu.cc +++ b/src/xenia/gpu/spirv_shader_translator_alu.cc @@ -997,11 +997,11 @@ spv::Id SpirvShaderTranslator::ProcessScalarAluOperation( static_cast(spv::OpNop), // kSetpPop static_cast(spv::OpNop), // kSetpClr static_cast(spv::OpNop), // kSetpRstr - static_cast(spv::OpNop), // kKillsEq - static_cast(spv::OpNop), // kKillsGt - static_cast(spv::OpNop), // kKillsGe - static_cast(spv::OpNop), // kKillsNe - static_cast(spv::OpNop), // kKillsOne + static_cast(spv::OpFOrdEqual), // kKillsEq + static_cast(spv::OpFOrdGreaterThan), // kKillsGt + static_cast(spv::OpFOrdGreaterThanEqual), // kKillsGe + static_cast(spv::OpFUnordNotEqual), // kKillsNe + static_cast(spv::OpFOrdEqual), // kKillsOne static_cast(GLSLstd450Sqrt), // kSqrt static_cast(spv::OpNop), // Invalid static_cast(spv::OpNop), // kMulsc0 @@ -1043,8 +1043,8 @@ spv::Id SpirvShaderTranslator::ProcessScalarAluOperation( if (a != b) { // Shader Model 3: +0 or denormal * anything = +-0. result = ZeroIfAnyOperandIsZero( - result, GetAbsoluteOperand(a, instr.vector_operands[0]), - GetAbsoluteOperand(b, instr.vector_operands[0])); + result, GetAbsoluteOperand(a, instr.scalar_operands[0]), + GetAbsoluteOperand(b, instr.scalar_operands[0])); } return result; } @@ -1400,6 +1400,39 @@ spv::Id SpirvShaderTranslator::ProcessScalarAluOperation( const_float_0_, a); } + case ucode::AluScalarOpcode::kKillsEq: + case ucode::AluScalarOpcode::kKillsGt: + case ucode::AluScalarOpcode::kKillsGe: + case ucode::AluScalarOpcode::kKillsNe: + case ucode::AluScalarOpcode::kKillsOne: { + // Selection merge must be the penultimate instruction in the block, check + // the condition before it. + spv::Id condition = builder_->createBinOp( + spv::Op(kOps[size_t(instr.scalar_opcode)]), type_bool_, + GetOperandComponents(operand_storage[0], instr.scalar_operands[0], + 0b0001), + instr.scalar_opcode == ucode::AluScalarOpcode::kKillsOne + ? const_float_1_ + : const_float_0_); + spv::Block& kill_block = builder_->makeNewBlock(); + spv::Block& merge_block = builder_->makeNewBlock(); + { + std::unique_ptr selection_merge_op = + std::make_unique(spv::OpSelectionMerge); + selection_merge_op->addIdOperand(merge_block.getId()); + selection_merge_op->addImmediateOperand(spv::SelectionControlMaskNone); + builder_->getBuildPoint()->addInstruction( + std::move(selection_merge_op)); + } + builder_->createConditionalBranch(condition, &kill_block, &merge_block); + builder_->setBuildPoint(&kill_block); + // TODO(Triang3l): Demote to helper invocation to keep derivatives if + // needed (and return 1 if killed in this case). + builder_->createNoResultOp(spv::OpKill); + builder_->setBuildPoint(&merge_block); + return const_float_0_; + } + // TODO(Triang3l): Implement the rest of instructions. }