diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp index 9a5ac71153..e576705f47 100644 --- a/src/sksl/SkSLIRGenerator.cpp +++ b/src/sksl/SkSLIRGenerator.cpp @@ -2484,10 +2484,10 @@ std::unique_ptr IRGenerator::convertField(std::unique_ptr IRGenerator::convertSwizzle(std::unique_ptr base, StringFragment fields) { const int offset = base->fOffset; @@ -2503,12 +2503,12 @@ std::unique_ptr IRGenerator::convertSwizzle(std::unique_ptr maskComponents; - std::vector constants; + maskComponents.reserve(fields.fLength); for (size_t i = 0; i < fields.fLength; i++) { switch (fields[i]) { case '0': case '1': - constants.push_back(fields[i] - '0'); + // Skip over constant fields for now. break; case 'x': case 'r': @@ -2569,44 +2569,71 @@ std::unique_ptr IRGenerator::convertSwizzle(std::unique_ptr(fContext, std::move(base), maskComponents); } - // If there are no constants, we're done - if (constants.empty()) { + // If we have processed the entire swizzle, we're done. + if (maskComponents.size() == fields.fLength) { return expr; } // Now we create a constructor that has the correct number of elements for the final swizzle, - // with all fields at the start, and all constants at the end: - // scalar.x0x0 -> type4(type2(x), 0, 0) - // vector.z10x -> type4(vector.zx, 1, 0) + // with all fields at the start. It's not finished yet; constants we need will be added below. + // scalar.x0x0 -> type4(type2(x), ...) + // vector.y111 -> type4(vector.y, ...) + // vector.z10x -> type4(vector.zx, ...) // - // NOTE: We could create simpler IR in some cases by reordering here, if all fields are packed + // We could create simpler IR in some cases by reordering here, if all fields are packed // contiguously. The benefits are minor, so skip the optimization to keep the algorithm simple. + // The constructor will have at most three arguments: { base value, constant 0, constant 1 } std::vector> constructorArgs; + constructorArgs.reserve(3); constructorArgs.push_back(std::move(expr)); + + // Apply another swizzle to shuffle the constants into the correct place. Any constant values we + // need are also tacked on to the end of the constructor. + // scalar.x0x0 -> type4(type2(x), 0).xyxy + // vector.y111 -> type4(vector.y, 1).xyyy + // vector.z10x -> type4(vector.zx, 1, 0).xzwy + // + // For our most common use cases ('.xyz0', '.xyz1'), this can produce an identity swizzle, which + // will be optimized away later. const Type* numberType = baseType.isNumber() ? &baseType : &baseType.componentType(); - for (int constant : constants) { - constructorArgs.push_back(this->coerce( - std::make_unique(fContext, offset, constant), *numberType)); - } + std::vector swizzleComponents; + swizzleComponents.reserve(fields.fLength); + int maskFieldIdx = 0; + int constantFieldIdx = maskComponents.size(); + int constantZeroIdx = -1, constantOneIdx = -1; - expr = std::make_unique(offset, - &numberType->toCompound(fContext, fields.fLength, 1), - std::move(constructorArgs)); - - // Now, we apply another swizzle to shuffle the constants into the correct place. For common - // uses ('.xyz0', '.xyz1'), this produces an identity swizzle, which is optimized away later. - std::vector shuffleComponents; - int curFieldIdx = 0, - curConstIdx = maskComponents.size(); for (size_t i = 0; i < fields.fLength; i++) { - if (fields[i] == '0' || fields[i] == '1') { - shuffleComponents.push_back(curConstIdx++); - } else { - shuffleComponents.push_back(curFieldIdx++); + switch (fields[i]) { + case '0': + if (constantZeroIdx == -1) { + // Synthesize a 'zero' argument at the end of the constructor. + auto literal = std::make_unique(fContext, offset, /*value=*/0); + constructorArgs.push_back(this->coerce(std::move(literal), *numberType)); + constantZeroIdx = constantFieldIdx++; + } + swizzleComponents.push_back(constantZeroIdx); + break; + case '1': + if (constantOneIdx == -1) { + // Synthesize a 'one' argument at the end of the constructor. + auto literal = std::make_unique(fContext, offset, /*value=*/1); + constructorArgs.push_back(this->coerce(std::move(literal), *numberType)); + constantOneIdx = constantFieldIdx++; + } + swizzleComponents.push_back(constantOneIdx); + break; + default: + // The non-constant fields are already in the expected order. + swizzleComponents.push_back(maskFieldIdx++); + break; } } - return std::make_unique(fContext, std::move(expr), std::move(shuffleComponents)); + expr = std::make_unique(offset, + &numberType->toCompound(fContext, constantFieldIdx, 1), + std::move(constructorArgs)); + + return std::make_unique(fContext, std::move(expr), std::move(swizzleComponents)); } std::unique_ptr IRGenerator::getCap(int offset, String name) { diff --git a/tests/sksl/glsl/golden/SwizzleConstants.glsl b/tests/sksl/glsl/golden/SwizzleConstants.glsl index 922540270f..e497cb4b5c 100644 --- a/tests/sksl/glsl/golden/SwizzleConstants.glsl +++ b/tests/sksl/glsl/golden/SwizzleConstants.glsl @@ -12,20 +12,20 @@ void main() { sk_FragColor = vec4(vec3(v.x, 1.0, 0.0), 1.0); sk_FragColor = vec4(vec3(v.yz, 1.0).zxy, 1.0); sk_FragColor = vec4(vec3(v.y, 0.0, 1.0).yxz, 1.0); - sk_FragColor = vec4(vec3(v.z, 1.0, 1.0).yzx, 1.0); + sk_FragColor = vec4(vec2(v.z, 1.0).yyx, 1.0); sk_FragColor = v; sk_FragColor = vec4(v.xyz, 1.0); sk_FragColor = vec4(v.xyw, 0.0).xywz; sk_FragColor = vec4(v.xy, 1.0, 0.0); sk_FragColor = vec4(v.xzw, 1.0).xwyz; sk_FragColor = vec4(v.xz, 0.0, 1.0).xzyw; - sk_FragColor = vec4(v.xw, 1.0, 1.0).xzwy; - sk_FragColor = vec4(v.x, 1.0, 0.0, 1.0); + sk_FragColor = vec3(v.xw, 1.0).xzzy; + sk_FragColor = vec3(v.x, 1.0, 0.0).xyzy; sk_FragColor = vec4(v.yzw, 1.0).wxyz; sk_FragColor = vec4(v.yz, 0.0, 1.0).zxyw; sk_FragColor = vec4(v.yw, 0.0, 1.0).zxwy; - sk_FragColor = vec4(v.y, 1.0, 1.0, 1.0).yxzw; - sk_FragColor = vec4(v.zw, 0.0, 0.0).zwxy; - sk_FragColor = vec4(v.z, 0.0, 0.0, 1.0).yzxw; - sk_FragColor = vec4(v.w, 0.0, 1.0, 1.0).yzwx; + sk_FragColor = vec2(v.y, 1.0).yxyy; + sk_FragColor = vec3(v.zw, 0.0).zzxy; + sk_FragColor = vec3(v.z, 0.0, 1.0).yyxz; + sk_FragColor = vec3(v.w, 0.0, 1.0).yzzx; } diff --git a/tests/sksl/glsl/golden/SwizzleOpt.glsl b/tests/sksl/glsl/golden/SwizzleOpt.glsl index d89c1fb285..418eb9e130 100644 --- a/tests/sksl/glsl/golden/SwizzleOpt.glsl +++ b/tests/sksl/glsl/golden/SwizzleOpt.glsl @@ -4,9 +4,9 @@ void main() { float v = sqrt(1.0); sk_FragColor = vec4(v); sk_FragColor = vec4(vec4(v).xyz, 0.0).wzyx; - sk_FragColor = vec4(vec4(v).xw, 0.0, 0.0).zwxy; - sk_FragColor = vec4(vec4(vec4(v).xw, 0.0, 0.0).yx, 1.0, 1.0).zwxy; - sk_FragColor = vec4(vec4(v).zy, 1.0, 1.0); + sk_FragColor = vec3(vec4(v).xw, 0.0).zzxy; + sk_FragColor = vec3(vec3(vec4(v).xw, 0.0).yx, 1.0).zzxy; + sk_FragColor = vec3(vec4(v).zy, 1.0).xyzz; sk_FragColor = vec4(v); sk_FragColor = vec4(vec4(v).xx, 1.0, 1.0); sk_FragColor = vec4(v).wzwz; diff --git a/tests/sksl/glsl/golden/SwizzleScalar.glsl b/tests/sksl/glsl/golden/SwizzleScalar.glsl index 73225f839c..afbf62499f 100644 --- a/tests/sksl/glsl/golden/SwizzleScalar.glsl +++ b/tests/sksl/glsl/golden/SwizzleScalar.glsl @@ -4,6 +4,6 @@ void main() { float x = sqrt(4.0); sk_FragColor = vec4(vec2(x), 0.0, 1.0); sk_FragColor = vec4(vec2(sqrt(4.0)), 0.0, 1.0); - sk_FragColor = vec4(sqrt(4.0), 0.0, 0.0, 1.0).yxzw; - sk_FragColor = vec4(vec2(sqrt(4.0)), 0.0, 0.0).zxwy; + sk_FragColor = vec3(sqrt(4.0), 0.0, 1.0).yxyz; + sk_FragColor = vec3(vec2(sqrt(4.0)), 0.0).zxzy; }