[SPIR-V] Operand loading

This commit is contained in:
Triang3l
2020-10-27 22:48:47 +03:00
parent de059f3d57
commit 4dba2d8d89
3 changed files with 294 additions and 12 deletions

View File

@@ -9,6 +9,8 @@
#include "xenia/gpu/spirv_shader_translator.h"
#include "xenia/base/math.h"
namespace xe {
namespace gpu {
@@ -21,7 +23,77 @@ void SpirvShaderTranslator::ProcessAluInstruction(
UpdateInstructionPredication(instr.is_predicated, instr.predicate_condition);
// TODO(Triang3l): Translate the ALU instruction.
// Floating-point arithmetic operations (addition, subtraction, negation,
// multiplication, dot product, division, modulo - see isArithmeticOperation
// in propagateNoContraction of glslang) must have the NoContraction
// decoration to prevent reordering to make sure floating-point calculations
// are optimized predictably and exactly the same in different shaders to
// allow for multipass rendering (in addition to the Invariant decoration on
// outputs).
// Whether the instruction has changed the predicate, and it needs to be
// checked again later.
bool predicate_written_vector = false;
ProcessVectorAluOperation(instr, predicate_written_vector);
// TODO(Triang3l): Process the ALU scalar operation.
if (predicate_written_vector) {
cf_exec_predicate_written_ = true;
CloseInstructionPredication();
}
}
spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
const ParsedAluInstruction& instr, bool& predicate_written) {
predicate_written = false;
uint32_t used_result_components =
instr.vector_and_constant_result.GetUsedResultComponents();
if (!used_result_components &&
!AluVectorOpHasSideEffects(instr.vector_opcode)) {
return spv::NoResult;
}
uint32_t used_result_component_count = xe::bit_count(used_result_components);
// Load operand storage without swizzle and sign modifiers.
// A small shortcut, operands of cube are the same, but swizzled.
uint32_t operand_count;
if (instr.vector_opcode == ucode::AluVectorOpcode::kCube) {
operand_count = 1;
} else {
operand_count = instr.vector_operand_count;
}
spv::Id operand_storage[3] = {};
for (uint32_t i = 0; i < operand_count; ++i) {
operand_storage[i] = LoadOperandStorage(instr.vector_operands[i]);
}
spv::Id result_vector_type =
used_result_component_count
? type_float_vectors_[used_result_component_count - 1]
: spv::NoType;
// In case the paired scalar instruction (if processed first) terminates the
// block (like via OpKill).
EnsureBuildPointAvailable();
switch (instr.vector_opcode) {
case ucode::AluVectorOpcode::kAdd: {
spv::Id result = builder_->createBinOp(
spv::OpFAdd, result_vector_type,
GetOperandComponents(operand_storage[0], instr.vector_operands[0],
used_result_components),
GetOperandComponents(operand_storage[1], instr.vector_operands[1],
used_result_components));
builder_->addDecoration(result, spv::DecorationNoContraction);
return result;
} break;
// TODO(Triang3l): Handle all instructions.
default:
break;
}
// Invalid instruction.
return spv::NoResult;
}
} // namespace gpu