From ae3b68c7b602b34412db5de16e20bd933e0ab1bd Mon Sep 17 00:00:00 2001 From: Triang3l Date: Fri, 30 Oct 2020 22:31:30 +0300 Subject: [PATCH] [DXBC] Fast mul path only for fully identical components because neg is post-abs --- src/xenia/gpu/dxbc_shader_translator_alu.cc | 15 ++++++----- src/xenia/gpu/shader.h | 28 +++++++-------------- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/src/xenia/gpu/dxbc_shader_translator_alu.cc b/src/xenia/gpu/dxbc_shader_translator_alu.cc index 5fef220b0..b2d24f89b 100644 --- a/src/xenia/gpu/dxbc_shader_translator_alu.cc +++ b/src/xenia/gpu/dxbc_shader_translator_alu.cc @@ -74,7 +74,7 @@ void DxbcShaderTranslator::ProcessVectorAluOperation( DxbcOpMul(per_component_dest, operands[0], operands[1]); uint32_t multiplicands_different = used_result_components & - ~instr.vector_operands[0].GetIdenticalMultiplicandComponents( + ~instr.vector_operands[0].GetIdenticalComponents( instr.vector_operands[1]); if (multiplicands_different) { // Shader Model 3: +-0 or denormal * anything = +0. @@ -181,15 +181,14 @@ void DxbcShaderTranslator::ProcessVectorAluOperation( component_count = 4; } result_swizzle = DxbcSrc::kXXXX; - uint32_t multiplicands_different = - uint32_t((1 << component_count) - 1) & - ~instr.vector_operands[0].GetIdenticalMultiplicandComponents( - instr.vector_operands[1]); + uint32_t different = uint32_t((1 << component_count) - 1) & + ~instr.vector_operands[0].GetIdenticalComponents( + instr.vector_operands[1]); for (uint32_t i = 0; i < component_count; ++i) { DxbcOpMul(DxbcDest::R(system_temp_result_, i ? 0b0010 : 0b0001), operands[0].SelectFromSwizzled(i), operands[1].SelectFromSwizzled(i)); - if ((multiplicands_different & (1 << i)) != 0) { + if ((different & (1 << i)) != 0) { // Shader Model 3: +-0 or denormal * anything = +0 (also not replacing // true `0 + term` with movc of the term because +0 + -0 should result // in +0, not -0). @@ -569,7 +568,7 @@ void DxbcShaderTranslator::ProcessVectorAluOperation( DxbcOpMul(DxbcDest::R(system_temp_result_, 0b0010), operands[0].SelectFromSwizzled(1), operands[1].SelectFromSwizzled(1)); - if (!(instr.vector_operands[0].GetIdenticalMultiplicandComponents( + if (!(instr.vector_operands[0].GetIdenticalComponents( instr.vector_operands[1]) & 0b0010)) { // Shader Model 3: +-0 or denormal * anything = +0. @@ -987,7 +986,7 @@ void DxbcShaderTranslator::ProcessScalarAluOperation( case AluScalarOpcode::kMulsc0: case AluScalarOpcode::kMulsc1: DxbcOpMul(ps_dest, operand_0_a, operand_1); - if (!(instr.scalar_operands[0].GetIdenticalMultiplicandComponents( + if (!(instr.scalar_operands[0].GetIdenticalComponents( instr.scalar_operands[1]) & 0b0001)) { // Shader Model 3: +-0 or denormal * anything = +0. diff --git a/src/xenia/gpu/shader.h b/src/xenia/gpu/shader.h index 0f3220601..d253bdad0 100644 --- a/src/xenia/gpu/shader.h +++ b/src/xenia/gpu/shader.h @@ -212,19 +212,18 @@ struct InstructionOperand { return false; } - // Returns which components of two operands are identical, so that - // multiplication of them would result in pow2 with + sign, including in case - // they're zero (because -0 * |-0|, or -0 * +0, is -0), for providing a fast - // path in emulation of the Shader Model 3 +-0 * x = +0 multiplication - // behavior (disregarding component_count for simplicity of usage with - // GetComponent, treating the rightmost component as replicated). - uint32_t GetIdenticalMultiplicandComponents( - const InstructionOperand& other) const { + // Returns which components of two operands will always be bitwise equal + // (disregarding component_count for simplicity of usage with GetComponent, + // treating the rightmost component as replicated). This, strictly with all + // conditions, must be used when emulating Shader Model 3 +-0 * x = +0 + // multiplication behavior with IEEE-compliant multiplication (because + // -0 * |-0|, or -0 * +0, is -0, while the result must be +0). + uint32_t GetIdenticalComponents(const InstructionOperand& other) const { if (storage_source != other.storage_source || storage_index != other.storage_index || storage_addressing_mode != other.storage_addressing_mode || - is_absolute_value != other.is_absolute_value || - (!is_absolute_value && is_negated != other.is_negated)) { + is_negated != other.is_negated || + is_absolute_value != other.is_absolute_value) { return 0; } uint32_t identical_components = 0; @@ -234,15 +233,6 @@ struct InstructionOperand { } return identical_components; } - // Returns which components of two operands will always be bitwise equal - // (disregarding component_count for simplicity of usage with GetComponent, - // treating the rightmost component as replicated). - uint32_t GetIdenticalComponents(const InstructionOperand& other) const { - if (is_negated != other.is_negated) { - return 0; - } - return GetIdenticalMultiplicandComponents(other); - } }; struct ParsedExecInstruction {