diff --git a/src/xenia/gpu/spirv_shader_translator_alu.cc b/src/xenia/gpu/spirv_shader_translator_alu.cc index 0aaf46473..819ca15ed 100644 --- a/src/xenia/gpu/spirv_shader_translator_alu.cc +++ b/src/xenia/gpu/spirv_shader_translator_alu.cc @@ -960,57 +960,57 @@ spv::Id SpirvShaderTranslator::ProcessScalarAluOperation( // Lookup table for variants of instructions with similar structure. static const unsigned int kOps[] = { - static_cast(spv::OpFAdd), // kAdds - static_cast(spv::OpFAdd), // kAddsPrev - static_cast(spv::OpNop), // kMuls - static_cast(spv::OpNop), // kMulsPrev - static_cast(spv::OpNop), // kMulsPrev2 - static_cast(spv::OpNop), // kMaxs - static_cast(spv::OpNop), // kMins - static_cast(spv::OpNop), // kSeqs - static_cast(spv::OpNop), // kSgts - static_cast(spv::OpNop), // kSges - static_cast(spv::OpNop), // kSnes - static_cast(spv::OpNop), // kFrcs - static_cast(spv::OpNop), // kTruncs - static_cast(spv::OpNop), // kFloors - static_cast(spv::OpNop), // kExp - static_cast(spv::OpNop), // kLogc - static_cast(spv::OpNop), // kLog - static_cast(spv::OpNop), // kRcpc - static_cast(spv::OpNop), // kRcpf - static_cast(spv::OpNop), // kRcp - static_cast(spv::OpNop), // kRsqc - static_cast(spv::OpNop), // kRsqf - static_cast(spv::OpNop), // kRsq - static_cast(spv::OpNop), // kMaxAs - static_cast(spv::OpNop), // kMaxAsf - static_cast(spv::OpFSub), // kSubs - static_cast(spv::OpFSub), // kSubsPrev - static_cast(spv::OpNop), // kSetpEq - static_cast(spv::OpNop), // kSetpNe - static_cast(spv::OpNop), // kSetpGt - static_cast(spv::OpNop), // kSetpGe - static_cast(spv::OpNop), // kSetpInv - 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::OpNop), // kSqrt - static_cast(spv::OpNop), // Invalid - static_cast(spv::OpNop), // kMulsc0 - static_cast(spv::OpNop), // kMulsc1 - static_cast(spv::OpNop), // kAddsc0 - static_cast(spv::OpNop), // kAddsc1 - static_cast(spv::OpNop), // kSubsc0 - static_cast(spv::OpNop), // kSubsc1 - static_cast(spv::OpNop), // kSin - static_cast(spv::OpNop), // kCos - static_cast(spv::OpNop), // kRetainPrev + static_cast(spv::OpFAdd), // kAdds + static_cast(spv::OpFAdd), // kAddsPrev + static_cast(spv::OpNop), // kMuls + static_cast(spv::OpNop), // kMulsPrev + static_cast(spv::OpNop), // kMulsPrev2 + static_cast(spv::OpFOrdGreaterThanEqual), // kMaxs + static_cast(spv::OpFOrdLessThan), // kMins + static_cast(spv::OpFOrdEqual), // kSeqs + static_cast(spv::OpFOrdGreaterThan), // kSgts + static_cast(spv::OpFOrdGreaterThanEqual), // kSges + static_cast(spv::OpFUnordNotEqual), // kSnes + static_cast(GLSLstd450Fract), // kFrcs + static_cast(GLSLstd450Trunc), // kTruncs + static_cast(GLSLstd450Floor), // kFloors + static_cast(GLSLstd450Exp2), // kExp + static_cast(spv::OpNop), // kLogc + static_cast(GLSLstd450Log2), // kLog + static_cast(spv::OpNop), // kRcpc + static_cast(spv::OpNop), // kRcpf + static_cast(spv::OpNop), // kRcp + static_cast(spv::OpNop), // kRsqc + static_cast(spv::OpNop), // kRsqf + static_cast(GLSLstd450InverseSqrt), // kRsq + static_cast(spv::OpNop), // kMaxAs + static_cast(spv::OpNop), // kMaxAsf + static_cast(spv::OpFSub), // kSubs + static_cast(spv::OpFSub), // kSubsPrev + static_cast(spv::OpNop), // kSetpEq + static_cast(spv::OpNop), // kSetpNe + static_cast(spv::OpNop), // kSetpGt + static_cast(spv::OpNop), // kSetpGe + static_cast(spv::OpNop), // kSetpInv + 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(GLSLstd450Sqrt), // kSqrt + static_cast(spv::OpNop), // Invalid + static_cast(spv::OpNop), // kMulsc0 + static_cast(spv::OpNop), // kMulsc1 + static_cast(spv::OpNop), // kAddsc0 + static_cast(spv::OpNop), // kAddsc1 + static_cast(spv::OpNop), // kSubsc0 + static_cast(spv::OpNop), // kSubsc1 + static_cast(GLSLstd450Sin), // kSin + static_cast(GLSLstd450Cos), // kCos + static_cast(spv::OpNop), // kRetainPrev }; switch (instr.scalar_opcode) { @@ -1164,10 +1164,57 @@ spv::Id SpirvShaderTranslator::ProcessScalarAluOperation( return phi_result; } } + + case ucode::AluScalarOpcode::kMaxs: + case ucode::AluScalarOpcode::kMins: { + spv::Id a, b; + GetOperandScalarXY(operand_storage[0], instr.scalar_operands[0], a, b); + if (a == b) { + // max is commonly used as mov. + return a; + } + // Shader Model 3 NaN behavior (a op b ? a : b, not SPIR-V FMax/FMin which + // are undefined for NaN or NMax/NMin which return the non-NaN operand). + return builder_->createTriOp( + spv::OpSelect, type_float_, + builder_->createBinOp(spv::Op(kOps[size_t(instr.scalar_opcode)]), + type_bool_, a, b), + a, b); + } + + case ucode::AluScalarOpcode::kSeqs: + case ucode::AluScalarOpcode::kSgts: + case ucode::AluScalarOpcode::kSges: + case ucode::AluScalarOpcode::kSnes: + return builder_->createTriOp( + spv::OpSelect, type_float_, + builder_->createBinOp( + spv::Op(kOps[size_t(instr.scalar_opcode)]), type_bool_, + GetOperandComponents(operand_storage[0], instr.scalar_operands[0], + 0b0001), + const_float_0_), + const_float_1_, const_float_0_); + + case ucode::AluScalarOpcode::kFrcs: + case ucode::AluScalarOpcode::kTruncs: + case ucode::AluScalarOpcode::kFloors: + case ucode::AluScalarOpcode::kExp: + case ucode::AluScalarOpcode::kLog: + case ucode::AluScalarOpcode::kRsq: + case ucode::AluScalarOpcode::kSqrt: + case ucode::AluScalarOpcode::kSin: + case ucode::AluScalarOpcode::kCos: + id_vector_temp_.clear(); + id_vector_temp_.push_back(GetOperandComponents( + operand_storage[0], instr.scalar_operands[0], 0b0001)); + return builder_->createBuiltinCall( + type_float_, ext_inst_glsl_std_450_, + GLSLstd450(kOps[size_t(instr.scalar_opcode)]), id_vector_temp_); + // TODO(Triang3l): Implement the rest of instructions. } - /* assert_unhandled_case(instr.vector_opcode); + /* assert_unhandled_case(instr.scalar_opcode); EmitTranslationError("Unknown ALU scalar operation"); */ return spv::NoResult; }