From 1acc5eff0519e5dd53be251e400b30c7a72c9015 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Sat, 31 Oct 2020 17:56:46 +0300 Subject: [PATCH] [SPIR-V] Vector mul, mad --- src/xenia/gpu/spirv_shader_translator.cc | 23 ++-- src/xenia/gpu/spirv_shader_translator.h | 13 +- src/xenia/gpu/spirv_shader_translator_alu.cc | 129 ++++++++++++++++++- 3 files changed, 150 insertions(+), 15 deletions(-) diff --git a/src/xenia/gpu/spirv_shader_translator.cc b/src/xenia/gpu/spirv_shader_translator.cc index 3c5a1c71e..982d9a8d9 100644 --- a/src/xenia/gpu/spirv_shader_translator.cc +++ b/src/xenia/gpu/spirv_shader_translator.cc @@ -87,6 +87,9 @@ void SpirvShaderTranslator::StartTranslation() { type_void_ = builder_->makeVoidType(); type_bool_ = builder_->makeBoolType(); + type_bool2_ = builder_->makeVectorType(type_bool_, 2); + type_bool3_ = builder_->makeVectorType(type_bool_, 3); + type_bool4_ = builder_->makeVectorType(type_bool_, 4); type_int_ = builder_->makeIntType(32); type_int4_ = builder_->makeVectorType(type_int_, 4); type_uint_ = builder_->makeUintType(32); @@ -1312,10 +1315,9 @@ void SpirvShaderTranslator::StoreResult(const InstructionResult& result, assert_true(target_num_components > 1); if (value_num_components > 1) { // Mixed non-constants and constants - vector source. - value_to_store = builder_->getUniqueId(); std::unique_ptr shuffle_op = - std::make_unique(value_to_store, target_type, - spv::OpVectorShuffle); + std::make_unique( + builder_->getUniqueId(), target_type, spv::OpVectorShuffle); shuffle_op->addIdOperand(value); shuffle_op->addIdOperand(const_float2_0_1_); for (uint32_t i = 0; i < target_num_components; ++i) { @@ -1324,6 +1326,7 @@ void SpirvShaderTranslator::StoreResult(const InstructionResult& result, ? value_num_components + ((constant_values >> i) & 1) : result_swizzled_value_components[i]); } + value_to_store = shuffle_op->getResultId(); builder_->getBuildPoint()->addInstruction(std::move(shuffle_op)); } else { // Mixed non-constants and constants - scalar source. @@ -1353,10 +1356,9 @@ void SpirvShaderTranslator::StoreResult(const InstructionResult& result, // 2) Insert value components - via shuffling for vector source, via // composite inserts for scalar value. if (constant_components) { - spv::Id shuffle_result = builder_->getUniqueId(); std::unique_ptr shuffle_op = - std::make_unique(shuffle_result, target_type, - spv::OpVectorShuffle); + std::make_unique(builder_->getUniqueId(), + target_type, spv::OpVectorShuffle); shuffle_op->addIdOperand(value_to_store); shuffle_op->addIdOperand(const_float2_0_1_); for (uint32_t i = 0; i < target_num_components; ++i) { @@ -1365,15 +1367,14 @@ void SpirvShaderTranslator::StoreResult(const InstructionResult& result, ((constant_values >> i) & 1) : i); } + value_to_store = shuffle_op->getResultId(); builder_->getBuildPoint()->addInstruction(std::move(shuffle_op)); - value_to_store = shuffle_result; } if (non_constant_components) { if (value_num_components > 1) { - spv::Id shuffle_result = builder_->getUniqueId(); std::unique_ptr shuffle_op = - std::make_unique(shuffle_result, target_type, - spv::OpVectorShuffle); + std::make_unique( + builder_->getUniqueId(), target_type, spv::OpVectorShuffle); shuffle_op->addIdOperand(value_to_store); shuffle_op->addIdOperand(value); for (uint32_t i = 0; i < target_num_components; ++i) { @@ -1382,8 +1383,8 @@ void SpirvShaderTranslator::StoreResult(const InstructionResult& result, ? target_num_components + result_swizzled_value_components[i] : i); } + value_to_store = shuffle_op->getResultId(); builder_->getBuildPoint()->addInstruction(std::move(shuffle_op)); - value_to_store = shuffle_result; } else { for (uint32_t i = 0; i < target_num_components; ++i) { if (non_constant_components & (1 << i)) { diff --git a/src/xenia/gpu/spirv_shader_translator.h b/src/xenia/gpu/spirv_shader_translator.h index 07620f081..395733b62 100644 --- a/src/xenia/gpu/spirv_shader_translator.h +++ b/src/xenia/gpu/spirv_shader_translator.h @@ -170,7 +170,17 @@ class SpirvShaderTranslator : public ShaderTranslator { spv::Id ext_inst_glsl_std_450_; spv::Id type_void_; - spv::Id type_bool_; + + union { + struct { + spv::Id type_bool_; + spv::Id type_bool2_; + spv::Id type_bool3_; + spv::Id type_bool4_; + }; + // Index = component count - 1. + spv::Id type_bool_vectors_[4]; + }; spv::Id type_int_; spv::Id type_int4_; spv::Id type_uint_; @@ -183,7 +193,6 @@ class SpirvShaderTranslator : public ShaderTranslator { spv::Id type_float3_; spv::Id type_float4_; }; - // Index = component count - 1. spv::Id type_float_vectors_[4]; }; diff --git a/src/xenia/gpu/spirv_shader_translator_alu.cc b/src/xenia/gpu/spirv_shader_translator_alu.cc index 613d9d066..9c69e8e8a 100644 --- a/src/xenia/gpu/spirv_shader_translator_alu.cc +++ b/src/xenia/gpu/spirv_shader_translator_alu.cc @@ -9,6 +9,10 @@ #include "xenia/gpu/spirv_shader_translator.h" +#include + +#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 shuffle_op = + std::make_unique( + 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;