[SPIR-V] Vector mul, mad
This commit is contained in:
@@ -9,6 +9,10 @@
|
||||
|
||||
#include "xenia/gpu/spirv_shader_translator.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "third_party/glslang/SPIRV/GLSL.std.450.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/math.h"
|
||||
|
||||
namespace xe {
|
||||
@@ -70,7 +74,7 @@ spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
|
||||
for (uint32_t i = 0; i < operand_count; ++i) {
|
||||
operand_storage[i] = LoadOperandStorage(instr.vector_operands[i]);
|
||||
}
|
||||
spv::Id result_vector_type =
|
||||
spv::Id result_type =
|
||||
used_result_component_count
|
||||
? type_float_vectors_[used_result_component_count - 1]
|
||||
: spv::NoType;
|
||||
@@ -82,7 +86,7 @@ spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
|
||||
switch (instr.vector_opcode) {
|
||||
case ucode::AluVectorOpcode::kAdd: {
|
||||
spv::Id result = builder_->createBinOp(
|
||||
spv::OpFAdd, result_vector_type,
|
||||
spv::OpFAdd, result_type,
|
||||
GetOperandComponents(operand_storage[0], instr.vector_operands[0],
|
||||
used_result_components),
|
||||
GetOperandComponents(operand_storage[1], instr.vector_operands[1],
|
||||
@@ -90,6 +94,127 @@ spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
|
||||
builder_->addDecoration(result, spv::DecorationNoContraction);
|
||||
return result;
|
||||
} break;
|
||||
case ucode::AluVectorOpcode::kMul:
|
||||
case ucode::AluVectorOpcode::kMad: {
|
||||
spv::Id multiplicands[2];
|
||||
for (uint32_t i = 0; i < 2; ++i) {
|
||||
multiplicands[i] =
|
||||
GetOperandComponents(operand_storage[i], instr.vector_operands[i],
|
||||
used_result_components);
|
||||
}
|
||||
spv::Id result = builder_->createBinOp(
|
||||
spv::OpFMul, result_type, multiplicands[0], multiplicands[1]);
|
||||
builder_->addDecoration(result, spv::DecorationNoContraction);
|
||||
uint32_t multiplicands_different =
|
||||
used_result_components &
|
||||
~instr.vector_operands[0].GetIdenticalComponents(
|
||||
instr.vector_operands[1]);
|
||||
if (multiplicands_different) {
|
||||
// Shader Model 3: +0 or denormal * anything = +-0.
|
||||
spv::Id different_operands[2] = {multiplicands[0], multiplicands[1]};
|
||||
spv::Id different_result = result;
|
||||
uint32_t different_count = xe::bit_count(multiplicands_different);
|
||||
spv::Id different_type = type_float_vectors_[different_count - 1];
|
||||
// Extract the different components, if not all are different.
|
||||
if (multiplicands_different != used_result_components) {
|
||||
uint_vector_temp_.clear();
|
||||
uint_vector_temp_.reserve(different_count);
|
||||
uint32_t components_remaining = used_result_components;
|
||||
for (uint32_t i = 0; i < used_result_component_count; ++i) {
|
||||
uint32_t component;
|
||||
xe::bit_scan_forward(components_remaining, &component);
|
||||
components_remaining &= ~(1 << component);
|
||||
if (multiplicands_different & (1 << component)) {
|
||||
uint_vector_temp_.push_back(i);
|
||||
}
|
||||
}
|
||||
assert_true(uint_vector_temp_.size() == different_count);
|
||||
if (different_count > 1) {
|
||||
for (uint32_t i = 0; i < 2; ++i) {
|
||||
different_operands[i] = builder_->createRvalueSwizzle(
|
||||
spv::NoPrecision, different_type, different_operands[i],
|
||||
uint_vector_temp_);
|
||||
}
|
||||
different_result = builder_->createRvalueSwizzle(
|
||||
spv::NoPrecision, different_type, different_result,
|
||||
uint_vector_temp_);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < 2; ++i) {
|
||||
different_operands[i] = builder_->createCompositeExtract(
|
||||
different_operands[i], different_type, uint_vector_temp_[0]);
|
||||
}
|
||||
different_result = builder_->createCompositeExtract(
|
||||
different_result, different_type, uint_vector_temp_[0]);
|
||||
}
|
||||
}
|
||||
// Check if the different components in any of the operands are zero,
|
||||
// even if the other is NaN - if min(|a|, |b|) is 0.
|
||||
for (uint32_t i = 0; i < 2; ++i) {
|
||||
if (instr.vector_operands[i].is_absolute_value &&
|
||||
!instr.vector_operands[i].is_negated) {
|
||||
continue;
|
||||
}
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(different_operands[i]);
|
||||
different_operands[i] = builder_->createBuiltinCall(
|
||||
different_type, ext_inst_glsl_std_450_, GLSLstd450FAbs,
|
||||
id_vector_temp_);
|
||||
}
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.reserve(2);
|
||||
id_vector_temp_.push_back(different_operands[0]);
|
||||
id_vector_temp_.push_back(different_operands[1]);
|
||||
spv::Id different_abs_min =
|
||||
builder_->createBuiltinCall(different_type, ext_inst_glsl_std_450_,
|
||||
GLSLstd450NMin, id_vector_temp_);
|
||||
spv::Id different_zero = builder_->createBinOp(
|
||||
spv::OpFOrdEqual, type_bool_vectors_[different_count - 1],
|
||||
different_abs_min, const_float_vectors_0_[different_count - 1]);
|
||||
// Replace with +0.
|
||||
different_result = builder_->createTriOp(
|
||||
spv::OpSelect, different_type, different_zero,
|
||||
const_float_vectors_0_[different_count - 1], different_result);
|
||||
// Insert the different components back to the result.
|
||||
if (multiplicands_different != used_result_components) {
|
||||
if (different_count > 1) {
|
||||
std::unique_ptr<spv::Instruction> shuffle_op =
|
||||
std::make_unique<spv::Instruction>(
|
||||
builder_->getUniqueId(), result_type, spv::OpVectorShuffle);
|
||||
shuffle_op->addIdOperand(result);
|
||||
shuffle_op->addIdOperand(different_result);
|
||||
uint32_t components_remaining = used_result_components;
|
||||
unsigned int different_shuffle_index = used_result_component_count;
|
||||
for (uint32_t i = 0; i < used_result_component_count; ++i) {
|
||||
uint32_t component;
|
||||
xe::bit_scan_forward(components_remaining, &component);
|
||||
components_remaining &= ~(1 << component);
|
||||
shuffle_op->addImmediateOperand(
|
||||
(multiplicands_different & (1 << component))
|
||||
? different_shuffle_index++
|
||||
: i);
|
||||
}
|
||||
result = shuffle_op->getResultId();
|
||||
builder_->getBuildPoint()->addInstruction(std::move(shuffle_op));
|
||||
} else {
|
||||
result = builder_->createCompositeInsert(
|
||||
different_result, result, result_type,
|
||||
xe::bit_count(used_result_components &
|
||||
(multiplicands_different - 1)));
|
||||
}
|
||||
} else {
|
||||
result = different_result;
|
||||
}
|
||||
}
|
||||
if (instr.vector_opcode == ucode::AluVectorOpcode::kMad) {
|
||||
// Not replacing true `0 + term` with conditional selection of the term
|
||||
// because +0 + -0 should result in +0, not -0.
|
||||
result = builder_->createBinOp(
|
||||
spv::OpFAdd, result_type, result,
|
||||
GetOperandComponents(operand_storage[2], instr.vector_operands[2],
|
||||
used_result_components));
|
||||
builder_->addDecoration(result, spv::DecorationNoContraction);
|
||||
}
|
||||
} break;
|
||||
// TODO(Triang3l): Handle all instructions.
|
||||
default:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user