[GPU] Fix scalar ALU swizzles with three-source vector ops

This commit is contained in:
Michael Oliver
2026-08-11 13:06:07 +01:00
committed by Radosław Gliński
parent ec5c875122
commit 92ada8ebc0
3 changed files with 25 additions and 12 deletions

View File

@@ -620,7 +620,8 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
bool scalar_src_absolute = false;
switch (scalar_opcode_info.operand_count) {
case 1: {
// r#/c#.w or r#/c#.wx.
// r#/c#.w, or r#/c#.wx unless the paired vector opcode has three
// operands, in which case r#/c#.wz.
const float* scalar_src_ptr;
uint32_t scalar_src_register = instr.src_reg(3);
std::array<float, 4> scalar_src_float_constant;
@@ -640,9 +641,11 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
scalar_operand_component_count =
scalar_opcode_info.single_operand_is_two_component ? 2 : 1;
for (uint32_t i = 0; i < scalar_operand_component_count; ++i) {
uint32_t source_component =
i == 0 ? 3 : (vector_opcode_info.GetOperandCount() == 3 ? 2 : 0);
scalar_operands[i] =
scalar_src_ptr[ucode::AluInstruction::GetSwizzledComponentIndex(
scalar_src_swizzle, (3 + i) & 3)];
scalar_src_swizzle, source_component)];
}
} break;
case 2: {

View File

@@ -1213,7 +1213,8 @@ uint32_t ParsedTextureFetchInstruction::GetNonZeroResultComponents() const {
static void ParseAluInstructionOperand(const AluInstruction& op, uint32_t i,
uint32_t swizzle_component_count,
InstructionOperand& out_op) {
InstructionOperand& out_op,
uint32_t scalar_second_component = 0) {
out_op.is_negated = op.src_negate(i);
uint32_t reg = op.src_reg(i);
if (op.src_is_temp(i)) {
@@ -1247,9 +1248,10 @@ static void ParseAluInstructionOperand(const AluInstruction& op, uint32_t i,
// Scalar `a` (W).
out_op.components[0] = GetSwizzledAluSourceComponent(swizzle, 3);
} else if (swizzle_component_count == 2) {
// Scalar left-hand `a` (W) and right-hand `b` (X).
// Scalar left-hand `a` (W) and right-hand `b` (X or Z).
out_op.components[0] = GetSwizzledAluSourceComponent(swizzle, 3);
out_op.components[1] = GetSwizzledAluSourceComponent(swizzle, 0);
out_op.components[1] =
GetSwizzledAluSourceComponent(swizzle, scalar_second_component);
} else if (swizzle_component_count == 3) {
assert_always();
} else if (swizzle_component_count == 4) {
@@ -1421,9 +1423,13 @@ void ParseAluInstruction(const AluInstruction& op,
instr.scalar_operand_count = scalar_opcode_info.operand_count;
if (instr.scalar_operand_count) {
if (instr.scalar_operand_count == 1) {
// The scalar operation shares source 3 with the vector operation. If the
// vector operation uses source 3, the scalar `b` component is Z;
// otherwise it is X.
ParseAluInstructionOperand(
op, 3, scalar_opcode_info.single_operand_is_two_component ? 2 : 1,
instr.scalar_operands[0]);
instr.scalar_operands[0],
vector_opcode_info.GetOperandCount() == 3 ? 2 : 0);
} else {
// Constant and temporary register.

View File

@@ -942,10 +942,13 @@ static_assert_size(FetchInstruction, sizeof(uint32_t) * 3);
// - All temporary registers are vec4s.
// - Most scalar ALU operations work with one or two components of the source
// register or the float constant passed as the third operand of the whole
// co-issued ALU operation, denoted by `a` (the left-hand operand) and `b`
// (the right-hand operand).
// ALU instruction, denoted by `a` (the left-hand operand) and `b` (the
// right-hand operand).
// `a` is the [(3 + src3_swizzle[6:7]) & 3] component (W - alpha).
// `b` is the [(0 + src3_swizzle[0:1]) & 3] component (X - red).
// For single-source two-component scalar operations, `b` is the
// [(0 + src3_swizzle[0:1]) & 3] component (X - red), or the
// [(2 + src3_swizzle[4:5]) & 3] component (Z - blue) if the vector operation
// uses source 3.
// - mulsc, addsc, subsc scalar ALU operations accept two operands - a float
// constant with the `a` (W) swizzle (addressed by the third operand index and
// addressing mode) being the left-hand operand, and a temporary register with
@@ -1330,11 +1333,12 @@ enum class AluScalarOpcode : uint32_t {
struct AluScalarOpcodeInfo {
const char* name;
// 0 - no operands.
// 1 - one single-component (W) or two-component (WX) r# or c#.
// 1 - one single-component (W) or two-component (WX, or WZ if the vector
// operation uses source 3) r# or c#.
// 2 - c#.w and r#.x.
uint32_t operand_count;
// If operand_count is 1, whether both W and X of the operand are used rather
// than only W.
// If operand_count is 1, whether two components of the operand are used
// rather than only W.
bool single_operand_is_two_component;
// Note that all scalar instructions except for retain_prev modify the
// previous scalar register, so they must be executed even if they don't write