Move constant swizzle handling into the IR generator
SkSL::Swizzle objects never represent constant swizzles - they are directly converted to IR that represents a small sub-tree, up to the most complex case of: Swizzle(Constructor(Swizzle(BaseVector), Literals, ...)) GLSL was the only backend that handled arbitrary complex swizzles correctly in all cases - this change basically moves that logic into the IR generator, subsumes the (similar) handling of scalar swizzles that was there, and simplifies the algorithm so that it's all procedural (not hard-coded based on bit-patterns). Bug: skia:10721 Change-Id: Iac96a26da517a7b1bdc9905cc38ad727fb68af12 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/317238 Reviewed-by: John Stiles <johnstiles@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
db42bf2140
commit
2564767d24
@ -108,7 +108,7 @@ color = clamp(color, 0.0, 1.0);
|
||||
@if (%s) {
|
||||
color.xyz = sqrt(color.xyz);
|
||||
}
|
||||
%s = half4(color.xyz, 1) * inColor.w;
|
||||
%s = half4(color.xyz, 1.0) * inColor.w;
|
||||
)SkSL",
|
||||
_sample896.c_str(), (_outer.linearize ? "true" : "false"),
|
||||
(_outer.grayscale ? "true" : "false"), (_outer.invertBrightness ? "true" : "false"),
|
||||
|
@ -51,7 +51,7 @@ if (!%s && t.y < 0.0) {
|
||||
args.fOutputColor, args.fOutputColor,
|
||||
args.fUniformHandler->getUniformCStr(leftBorderColorVar), args.fOutputColor,
|
||||
args.fUniformHandler->getUniformCStr(rightBorderColorVar));
|
||||
SkString _coords1871("float2(half2(t.x, 0))");
|
||||
SkString _coords1871("float2(half2(t.x, 0.0))");
|
||||
SkString _sample1871 = this->invokeChild(0, args, _coords1871.c_str());
|
||||
fragBuilder->codeAppendf(
|
||||
R"SkSL(
|
||||
|
@ -49,7 +49,7 @@ if (!%s && t.y < 0.0) {
|
||||
_sample453.c_str(),
|
||||
(_outer.childProcessor(1)->preservesOpaqueInput() ? "true" : "false"),
|
||||
args.fOutputColor, (_outer.mirror ? "true" : "false"));
|
||||
SkString _coords1451("float2(half2(t.x, 0))");
|
||||
SkString _coords1451("float2(half2(t.x, 0.0))");
|
||||
SkString _sample1451 = this->invokeChild(0, args, _coords1451.c_str());
|
||||
fragBuilder->codeAppendf(
|
||||
R"SkSL(
|
||||
|
@ -1090,11 +1090,7 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
|
||||
Swizzle& base = s.fBase->as<Swizzle>();
|
||||
std::vector<int> final;
|
||||
for (int c : s.fComponents) {
|
||||
if (c == SKSL_SWIZZLE_0 || c == SKSL_SWIZZLE_1) {
|
||||
final.push_back(c);
|
||||
} else {
|
||||
final.push_back(base.fComponents[c]);
|
||||
}
|
||||
final.push_back(base.fComponents[c]);
|
||||
}
|
||||
*outUpdated = true;
|
||||
std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.fBase->clone(),
|
||||
|
@ -862,189 +862,12 @@ void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
|
||||
}
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeConstantSwizzle(const Swizzle& swizzle, const String& constants) {
|
||||
this->writeType(swizzle.type());
|
||||
this->write("(");
|
||||
this->write(constants);
|
||||
this->write(")");
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeSwizzleMask(const Swizzle& swizzle, const String& mask) {
|
||||
void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
|
||||
this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
|
||||
this->write(".");
|
||||
this->write(mask);
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeSwizzleConstructor(const Swizzle& swizzle, const String& constants,
|
||||
const String& mask,
|
||||
GLSLCodeGenerator::SwizzleOrder order) {
|
||||
this->writeType(swizzle.type());
|
||||
this->write("(");
|
||||
if (order == SwizzleOrder::CONSTANTS_FIRST) {
|
||||
this->write(constants);
|
||||
this->write(", ");
|
||||
this->writeSwizzleMask(swizzle, mask);
|
||||
} else {
|
||||
this->writeSwizzleMask(swizzle, mask);
|
||||
this->write(", ");
|
||||
this->write(constants);
|
||||
}
|
||||
this->write(")");
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeSwizzleConstructor(const Swizzle& swizzle, const String& constants,
|
||||
const String& mask, const String& reswizzle) {
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask, SwizzleOrder::MASK_FIRST);
|
||||
this->write(".");
|
||||
this->write(reswizzle);
|
||||
}
|
||||
|
||||
// Writing a swizzle is complicated due to the handling of constant swizzle components. The most
|
||||
// problematic case is a mask like '.r00a'. A naive approach might turn that into
|
||||
// 'vec4(base.r, 0, 0, base.a)', but that would cause 'base' to be evaluated twice. We instead
|
||||
// group the swizzle mask ('ra') and constants ('0, 0') together and use a secondary swizzle to put
|
||||
// them back into the right order, so in this case we end up with something like
|
||||
// 'vec4(base4.ra, 0, 0).rbag'.
|
||||
void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
|
||||
// has a 1 bit in every position for which the swizzle mask is a constant, so 'r0b1' would
|
||||
// yield binary 0101.
|
||||
int constantBits = 0;
|
||||
String mask;
|
||||
String constants;
|
||||
// compute mask ("ra") and constant ("0, 0") strings, and fill in constantBits
|
||||
for (int c : swizzle.fComponents) {
|
||||
constantBits <<= 1;
|
||||
switch (c) {
|
||||
case SKSL_SWIZZLE_0:
|
||||
constantBits |= 1;
|
||||
if (constants.length() > 0) {
|
||||
constants += ", ";
|
||||
}
|
||||
constants += "0";
|
||||
break;
|
||||
case SKSL_SWIZZLE_1:
|
||||
constantBits |= 1;
|
||||
if (constants.length() > 0) {
|
||||
constants += ", ";
|
||||
}
|
||||
constants += "1";
|
||||
break;
|
||||
case 0:
|
||||
mask += "x";
|
||||
break;
|
||||
case 1:
|
||||
mask += "y";
|
||||
break;
|
||||
case 2:
|
||||
mask += "z";
|
||||
break;
|
||||
case 3:
|
||||
mask += "w";
|
||||
break;
|
||||
default:
|
||||
SkASSERT(false);
|
||||
}
|
||||
}
|
||||
switch (swizzle.fComponents.size()) {
|
||||
case 1:
|
||||
if (constantBits == 1) {
|
||||
this->write(constants);
|
||||
}
|
||||
else {
|
||||
this->writeSwizzleMask(swizzle, mask);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (constantBits) {
|
||||
case 0: // 00
|
||||
this->writeSwizzleMask(swizzle, mask);
|
||||
break;
|
||||
case 1: // 01
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask,
|
||||
SwizzleOrder::MASK_FIRST);
|
||||
break;
|
||||
case 2: // 10
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask,
|
||||
SwizzleOrder::CONSTANTS_FIRST);
|
||||
break;
|
||||
case 3: // 11
|
||||
this->writeConstantSwizzle(swizzle, constants);
|
||||
break;
|
||||
default:
|
||||
SkASSERT(false);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (constantBits) {
|
||||
case 0: // 000
|
||||
this->writeSwizzleMask(swizzle, mask);
|
||||
break;
|
||||
case 1: // 001
|
||||
case 3: // 011
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask,
|
||||
SwizzleOrder::MASK_FIRST);
|
||||
break;
|
||||
case 4: // 100
|
||||
case 6: // 110
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask,
|
||||
SwizzleOrder::CONSTANTS_FIRST);
|
||||
break;
|
||||
case 2: // 010
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask, "xzy");
|
||||
break;
|
||||
case 5: // 101
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask, "yxz");
|
||||
break;
|
||||
case 7: // 111
|
||||
this->writeConstantSwizzle(swizzle, constants);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (constantBits) {
|
||||
case 0: // 0000
|
||||
this->writeSwizzleMask(swizzle, mask);
|
||||
break;
|
||||
case 1: // 0001
|
||||
case 3: // 0011
|
||||
case 7: // 0111
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask,
|
||||
SwizzleOrder::MASK_FIRST);
|
||||
break;
|
||||
case 8: // 1000
|
||||
case 12: // 1100
|
||||
case 14: // 1110
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask,
|
||||
SwizzleOrder::CONSTANTS_FIRST);
|
||||
break;
|
||||
case 2: // 0010
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask, "xywz");
|
||||
break;
|
||||
case 4: // 0100
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask, "xwyz");
|
||||
break;
|
||||
case 5: // 0101
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask, "xzyw");
|
||||
break;
|
||||
case 6: // 0110
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask, "xzwy");
|
||||
break;
|
||||
case 9: // 1001
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask, "zxyw");
|
||||
break;
|
||||
case 10: // 1010
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask, "zxwy");
|
||||
break;
|
||||
case 11: // 1011
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask, "yxzw");
|
||||
break;
|
||||
case 13: // 1101
|
||||
this->writeSwizzleConstructor(swizzle, constants, mask, "yzxw");
|
||||
break;
|
||||
case 15: // 1111
|
||||
this->writeConstantSwizzle(swizzle, constants);
|
||||
break;
|
||||
}
|
||||
SkASSERT(c >= 0 && c <= 3);
|
||||
this->write(&("x\0y\0z\0w\0"[c * 2]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,11 +83,6 @@ public:
|
||||
bool generateCode() override;
|
||||
|
||||
protected:
|
||||
enum class SwizzleOrder {
|
||||
MASK_FIRST,
|
||||
CONSTANTS_FIRST
|
||||
};
|
||||
|
||||
void write(const char* s);
|
||||
|
||||
void writeLine();
|
||||
@ -158,15 +153,6 @@ protected:
|
||||
|
||||
virtual void writeFieldAccess(const FieldAccess& f);
|
||||
|
||||
void writeConstantSwizzle(const Swizzle& swizzle, const String& constants);
|
||||
|
||||
void writeSwizzleMask(const Swizzle& swizzle, const String& mask);
|
||||
|
||||
void writeSwizzleConstructor(const Swizzle& swizzle, const String& constants,
|
||||
const String& mask, SwizzleOrder order);
|
||||
|
||||
void writeSwizzleConstructor(const Swizzle& swizzle, const String& constants,
|
||||
const String& mask, const String& reswizzle);
|
||||
virtual void writeSwizzle(const Swizzle& swizzle);
|
||||
|
||||
static Precedence GetBinaryPrecedence(Token::Kind op);
|
||||
|
@ -2483,53 +2483,45 @@ std::unique_ptr<Expression> IRGenerator::convertField(std::unique_ptr<Expression
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// counts the number of chunks of contiguous 'x's in a swizzle, e.g. xxx1 has one and x0xx has two
|
||||
static int count_contiguous_swizzle_chunks(const std::vector<int>& components) {
|
||||
int chunkCount = 0;
|
||||
for (size_t i = 0; i < components.size(); ++i) {
|
||||
SkASSERT(components[i] <= 0);
|
||||
if (components[i] == 0) {
|
||||
++chunkCount;
|
||||
while (i + 1 < components.size() && components[i + 1] == 0) {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunkCount;
|
||||
}
|
||||
|
||||
// Swizzles are complicated due to constant components. The most difficult case is a mask like
|
||||
// '.x00w'. A naive approach might turn that into 'float4(base.x, 0, 0, base.w)', but that evaluates
|
||||
// 'base' twice. We instead group the swizzle mask ('xw') and constants ('0, 0') together and use a
|
||||
// secondary swizzle to put them back into the right order, so in this case we end up with
|
||||
// 'float4(base.xw, 0, 0).xzwy'.
|
||||
std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expression> base,
|
||||
StringFragment fields) {
|
||||
const int offset = base->fOffset;
|
||||
const Type& baseType = base->type();
|
||||
if (baseType.typeKind() != Type::TypeKind::kVector && !baseType.isNumber()) {
|
||||
fErrors.error(base->fOffset, "cannot swizzle value of type '" + baseType.displayName() +
|
||||
"'");
|
||||
fErrors.error(offset, "cannot swizzle value of type '" + baseType.displayName() + "'");
|
||||
return nullptr;
|
||||
}
|
||||
std::vector<int> swizzleComponents;
|
||||
size_t numLiteralFields = 0;
|
||||
|
||||
if (fields.fLength > 4) {
|
||||
fErrors.error(offset, "too many components in swizzle mask '" + fields + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<int> maskComponents;
|
||||
std::vector<int> constants;
|
||||
for (size_t i = 0; i < fields.fLength; i++) {
|
||||
switch (fields[i]) {
|
||||
case '0':
|
||||
swizzleComponents.push_back(SKSL_SWIZZLE_0);
|
||||
numLiteralFields++;
|
||||
break;
|
||||
case '1':
|
||||
swizzleComponents.push_back(SKSL_SWIZZLE_1);
|
||||
numLiteralFields++;
|
||||
constants.push_back(fields[i] - '0');
|
||||
break;
|
||||
case 'x':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 'L':
|
||||
swizzleComponents.push_back(0);
|
||||
maskComponents.push_back(0);
|
||||
break;
|
||||
case 'y':
|
||||
case 'g':
|
||||
case 't':
|
||||
case 'T':
|
||||
if (baseType.columns() >= 2) {
|
||||
swizzleComponents.push_back(1);
|
||||
maskComponents.push_back(1);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
@ -2538,7 +2530,7 @@ std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expressi
|
||||
case 'p':
|
||||
case 'R':
|
||||
if (baseType.columns() >= 3) {
|
||||
swizzleComponents.push_back(2);
|
||||
maskComponents.push_back(2);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
@ -2547,104 +2539,74 @@ std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expressi
|
||||
case 'q':
|
||||
case 'B':
|
||||
if (baseType.columns() >= 4) {
|
||||
swizzleComponents.push_back(3);
|
||||
maskComponents.push_back(3);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
fErrors.error(base->fOffset, String::printf("invalid swizzle component '%c'",
|
||||
fields[i]));
|
||||
fErrors.error(offset, String::printf("invalid swizzle component '%c'", fields[i]));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
SkASSERT(swizzleComponents.size() > 0);
|
||||
if (swizzleComponents.size() > 4) {
|
||||
fErrors.error(base->fOffset, "too many components in swizzle mask '" + fields + "'");
|
||||
return nullptr;
|
||||
}
|
||||
if (numLiteralFields == swizzleComponents.size()) {
|
||||
fErrors.error(base->fOffset, "swizzle must refer to base expression");
|
||||
if (maskComponents.empty()) {
|
||||
fErrors.error(offset, "swizzle must refer to base expression");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// First, we need a vector expression that is the non-constant portion of the swizzle, packed:
|
||||
// scalar.xxx -> type3(scalar)
|
||||
// scalar.x0x0 -> type2(scalar)
|
||||
// vector.zyx -> vector.zyx
|
||||
// vector.x0y0 -> vector.xy
|
||||
std::unique_ptr<Expression> expr;
|
||||
if (baseType.isNumber()) {
|
||||
// Swizzling a single scalar. Something like foo.x0x1 is equivalent to float4(foo, 0, foo,
|
||||
// 1)
|
||||
int offset = base->fOffset;
|
||||
std::unique_ptr<Expression> expr;
|
||||
switch (base->kind()) {
|
||||
case Expression::Kind::kVariableReference:
|
||||
case Expression::Kind::kFloatLiteral:
|
||||
case Expression::Kind::kIntLiteral:
|
||||
// the value being swizzled is just a constant or variable reference, so we can
|
||||
// safely re-use copies of it without reevaluation concerns
|
||||
expr = std::move(base);
|
||||
break;
|
||||
default:
|
||||
// It's a value we can't safely re-use multiple times. If it's all in one contiguous
|
||||
// chunk it's easy (e.g. foo.xxx0 can be turned into half4(half3(x), 0)), but
|
||||
// for multiple discontiguous chunks we'll need to copy it into a temporary value.
|
||||
int chunkCount = count_contiguous_swizzle_chunks(swizzleComponents);
|
||||
if (chunkCount <= 1) {
|
||||
// no copying needed, so we can just use the value directly
|
||||
expr = std::move(base);
|
||||
} else {
|
||||
// store the value in a temporary variable so we can re-use it
|
||||
int varIndex = fTmpSwizzleCounter++;
|
||||
auto name = std::make_unique<String>();
|
||||
name->appendf("_tmpSwizzle%d", varIndex);
|
||||
const String* namePtr = fSymbolTable->takeOwnershipOfString(std::move(name));
|
||||
const Variable* var = fSymbolTable->takeOwnershipOfSymbol(
|
||||
std::make_unique<Variable>(offset,
|
||||
Modifiers(),
|
||||
namePtr->c_str(),
|
||||
&baseType,
|
||||
Variable::kLocal_Storage,
|
||||
base.get()));
|
||||
expr = std::make_unique<VariableReference>(offset, *var);
|
||||
std::vector<std::unique_ptr<VarDeclaration>> variables;
|
||||
variables.emplace_back(new VarDeclaration(var, {}, std::move(base)));
|
||||
fExtraStatements.emplace_back(new VarDeclarationsStatement(
|
||||
std::make_unique<VarDeclarations>(offset, &expr->type(),
|
||||
std::move(variables))));
|
||||
}
|
||||
}
|
||||
std::vector<std::unique_ptr<Expression>> args;
|
||||
for (size_t i = 0; i < swizzleComponents.size(); ++i) {
|
||||
switch (swizzleComponents[i]) {
|
||||
case 0: {
|
||||
args.push_back(expr->clone());
|
||||
int count = 1;
|
||||
while (i + 1 < swizzleComponents.size() && swizzleComponents[i + 1] == 0) {
|
||||
++i;
|
||||
++count;
|
||||
}
|
||||
if (count > 1) {
|
||||
std::vector<std::unique_ptr<Expression>> constructorArgs;
|
||||
constructorArgs.push_back(std::move(args.back()));
|
||||
args.pop_back();
|
||||
args.emplace_back(new Constructor(offset, &expr->type().toCompound(fContext,
|
||||
count,
|
||||
1),
|
||||
std::move(constructorArgs)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SKSL_SWIZZLE_0:
|
||||
args.emplace_back(new IntLiteral(fContext, offset, 0));
|
||||
break;
|
||||
case SKSL_SWIZZLE_1:
|
||||
args.emplace_back(new IntLiteral(fContext, offset, 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return std::unique_ptr<Expression>(new Constructor(offset,
|
||||
&expr->type().toCompound(
|
||||
fContext,
|
||||
swizzleComponents.size(),
|
||||
1),
|
||||
std::move(args)));
|
||||
std::vector<std::unique_ptr<Expression>> scalarConstructorArgs;
|
||||
scalarConstructorArgs.push_back(std::move(base));
|
||||
expr = std::make_unique<Constructor>(
|
||||
offset, &baseType.toCompound(fContext, maskComponents.size(), 1),
|
||||
std::move(scalarConstructorArgs));
|
||||
} else {
|
||||
expr = std::make_unique<Swizzle>(fContext, std::move(base), maskComponents);
|
||||
}
|
||||
return std::unique_ptr<Expression>(new Swizzle(fContext, std::move(base), swizzleComponents));
|
||||
|
||||
// If there are no constants, we're done
|
||||
if (constants.empty()) {
|
||||
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)
|
||||
//
|
||||
// NOTE: 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.
|
||||
std::vector<std::unique_ptr<Expression>> constructorArgs;
|
||||
constructorArgs.push_back(std::move(expr));
|
||||
const Type* numberType = baseType.isNumber() ? &baseType : &baseType.componentType();
|
||||
for (int constant : constants) {
|
||||
constructorArgs.push_back(this->coerce(
|
||||
std::make_unique<IntLiteral>(fContext, offset, constant), *numberType));
|
||||
}
|
||||
|
||||
expr = std::make_unique<Constructor>(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<int> 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++);
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<Swizzle>(fContext, std::move(expr), std::move(shuffleComponents));
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> IRGenerator::getCap(int offset, String name) {
|
||||
@ -2813,10 +2775,6 @@ void IRGenerator::checkValid(const Expression& expr) {
|
||||
bool IRGenerator::checkSwizzleWrite(const Swizzle& swizzle) {
|
||||
int bits = 0;
|
||||
for (int idx : swizzle.fComponents) {
|
||||
if (idx < 0) {
|
||||
fErrors.error(swizzle.fOffset, "cannot write to a swizzle mask containing a constant");
|
||||
return false;
|
||||
}
|
||||
SkASSERT(idx <= 3);
|
||||
int bit = 1 << idx;
|
||||
if (bits & bit) {
|
||||
|
@ -746,23 +746,11 @@ void MetalCodeGenerator::writeFieldAccess(const FieldAccess& f) {
|
||||
}
|
||||
|
||||
void MetalCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
|
||||
int last = swizzle.fComponents.back();
|
||||
if (last == SKSL_SWIZZLE_0 || last == SKSL_SWIZZLE_1) {
|
||||
this->writeType(swizzle.type());
|
||||
this->write("(");
|
||||
}
|
||||
this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
|
||||
this->write(".");
|
||||
for (int c : swizzle.fComponents) {
|
||||
if (c >= 0) {
|
||||
this->write(&("x\0y\0z\0w\0"[c * 2]));
|
||||
}
|
||||
}
|
||||
if (last == SKSL_SWIZZLE_0) {
|
||||
this->write(", 0)");
|
||||
}
|
||||
else if (last == SKSL_SWIZZLE_1) {
|
||||
this->write(", 1)");
|
||||
SkASSERT(c >= 0 && c <= 3);
|
||||
this->write(&("x\0y\0z\0w\0"[c * 2]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1980,36 +1980,9 @@ SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out
|
||||
this->writeWord(this->getType(swizzle.type()), out);
|
||||
this->writeWord(result, out);
|
||||
this->writeWord(base, out);
|
||||
SpvId other = base;
|
||||
for (int c : swizzle.fComponents) {
|
||||
if (c < 0) {
|
||||
if (!fConstantZeroOneVector) {
|
||||
FloatLiteral zero(fContext, -1, 0);
|
||||
SpvId zeroId = this->writeFloatLiteral(zero);
|
||||
FloatLiteral one(fContext, -1, 1);
|
||||
SpvId oneId = this->writeFloatLiteral(one);
|
||||
SpvId type = this->getType(*fContext.fFloat2_Type);
|
||||
fConstantZeroOneVector = this->nextId();
|
||||
this->writeOpCode(SpvOpConstantComposite, 5, fConstantBuffer);
|
||||
this->writeWord(type, fConstantBuffer);
|
||||
this->writeWord(fConstantZeroOneVector, fConstantBuffer);
|
||||
this->writeWord(zeroId, fConstantBuffer);
|
||||
this->writeWord(oneId, fConstantBuffer);
|
||||
}
|
||||
other = fConstantZeroOneVector;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this->writeWord(other, out);
|
||||
int baseColumns = swizzle.fBase->type().columns();
|
||||
this->writeWord(base, out);
|
||||
for (int component : swizzle.fComponents) {
|
||||
if (component == SKSL_SWIZZLE_0) {
|
||||
this->writeWord(baseColumns, out);
|
||||
} else if (component == SKSL_SWIZZLE_1) {
|
||||
this->writeWord(baseColumns + 1, out);
|
||||
} else {
|
||||
this->writeWord(component, out);
|
||||
}
|
||||
this->writeWord(component, out);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -387,8 +387,6 @@ private:
|
||||
SpvId fBoolTrue;
|
||||
SpvId fBoolFalse;
|
||||
std::unordered_map<std::pair<ConstantValue, ConstantType>, SpvId> fNumberConstants;
|
||||
// The constant float2(0, 1), used in swizzling
|
||||
SpvId fConstantZeroOneVector = 0;
|
||||
bool fSetupFragPosition;
|
||||
// label of the current block, or 0 if we are not in a block
|
||||
SpvId fCurrentBlock;
|
||||
|
@ -16,12 +16,6 @@
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
// represents a swizzle component of constant 0, as in x.rgb0
|
||||
const int SKSL_SWIZZLE_0 = -2;
|
||||
|
||||
// represents a swizzle component of constant 1, as in x.rgb1
|
||||
const int SKSL_SWIZZLE_1 = -1;
|
||||
|
||||
/**
|
||||
* Given a type and a swizzle component count, returns the type that will result from swizzling. For
|
||||
* instance, swizzling a float3 with two components will result in a float2. It is possible to
|
||||
@ -140,7 +134,7 @@ struct Swizzle : public Expression {
|
||||
String description() const override {
|
||||
String result = fBase->description() + ".";
|
||||
for (int x : fComponents) {
|
||||
result += "01xyzw"[x + 2];
|
||||
result += "xyzw"[x];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ DEF_TEST(SkSLSwizzleDuplicateOutput, r) {
|
||||
DEF_TEST(SkSLSwizzleConstantOutput, r) {
|
||||
test_failure(r,
|
||||
"void main() { float4 test = float4(1); test.xyz0 = float4(1); }",
|
||||
"error: 1: cannot write to a swizzle mask containing a constant\n1 error\n");
|
||||
"error: 1: cannot assign to this expression\n1 error\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLSwizzleOnlyLiterals, r) {
|
||||
|
@ -1210,30 +1210,30 @@ DEF_TEST(SkSLSwizzleConstants, r) {
|
||||
" vec4 v = vec4(sqrt(1.0));\n"
|
||||
" sk_FragColor = vec4(v.x, 1.0, 1.0, 1.0);\n"
|
||||
" sk_FragColor = vec4(v.xy, 1.0, 1.0);\n"
|
||||
" sk_FragColor = vec4(vec2(v.x, 1), 1.0, 1.0);\n"
|
||||
" sk_FragColor = vec4(vec2(0, v.y), 1.0, 1.0);\n"
|
||||
" sk_FragColor = vec4(vec2(v.x, 1.0), 1.0, 1.0);\n"
|
||||
" sk_FragColor = vec4(vec2(v.y, 0.0).yx, 1.0, 1.0);\n"
|
||||
" sk_FragColor = vec4(v.xyz, 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(v.xy, 1), 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(v.xz, 0).xzy, 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(v.x, 1, 0), 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(1, v.yz), 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(v.y, 0, 1).yxz, 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(1, 1, v.z), 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(v.xy, 1.0), 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(v.xz, 0.0).xzy, 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(v.x, 1.0, 0.0), 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(v.yz, 1.0).zxy, 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(v.y, 0.0, 1.0).yxz, 1.0);\n"
|
||||
" sk_FragColor = vec4(vec3(v.z, 1.0, 1.0).yzx, 1.0);\n"
|
||||
" sk_FragColor = v;\n"
|
||||
" sk_FragColor = vec4(v.xyz, 1);\n"
|
||||
" sk_FragColor = vec4(v.xyw, 0).xywz;\n"
|
||||
" sk_FragColor = vec4(v.xy, 1, 0);\n"
|
||||
" sk_FragColor = vec4(v.xzw, 1).xwyz;\n"
|
||||
" sk_FragColor = vec4(v.xz, 0, 1).xzyw;\n"
|
||||
" sk_FragColor = vec4(v.xw, 1, 1).xzwy;\n"
|
||||
" sk_FragColor = vec4(v.x, 1, 0, 1);\n"
|
||||
" sk_FragColor = vec4(1, v.yzw);\n"
|
||||
" sk_FragColor = vec4(v.yz, 0, 1).zxyw;\n"
|
||||
" sk_FragColor = vec4(v.yw, 0, 1).zxwy;\n"
|
||||
" sk_FragColor = vec4(v.y, 1, 1, 1).yxzw;\n"
|
||||
" sk_FragColor = vec4(0, 0, v.zw);\n"
|
||||
" sk_FragColor = vec4(v.z, 0, 0, 1).yzxw;\n"
|
||||
" sk_FragColor = vec4(0, 1, 1, v.w);\n"
|
||||
" sk_FragColor = vec4(v.xyz, 1.0);\n"
|
||||
" sk_FragColor = vec4(v.xyw, 0.0).xywz;\n"
|
||||
" sk_FragColor = vec4(v.xy, 1.0, 0.0);\n"
|
||||
" sk_FragColor = vec4(v.xzw, 1.0).xwyz;\n"
|
||||
" sk_FragColor = vec4(v.xz, 0.0, 1.0).xzyw;\n"
|
||||
" sk_FragColor = vec4(v.xw, 1.0, 1.0).xzwy;\n"
|
||||
" sk_FragColor = vec4(v.x, 1.0, 0.0, 1.0);\n"
|
||||
" sk_FragColor = vec4(v.yzw, 1.0).wxyz;\n"
|
||||
" sk_FragColor = vec4(v.yz, 0.0, 1.0).zxyw;\n"
|
||||
" sk_FragColor = vec4(v.yw, 0.0, 1.0).zxwy;\n"
|
||||
" sk_FragColor = vec4(v.y, 1.0, 1.0, 1.0).yxzw;\n"
|
||||
" sk_FragColor = vec4(v.zw, 0.0, 0.0).zwxy;\n"
|
||||
" sk_FragColor = vec4(v.z, 0.0, 0.0, 1.0).yzxw;\n"
|
||||
" sk_FragColor = vec4(v.w, 0.0, 1.0, 1.0).yzwx;\n"
|
||||
"}\n",
|
||||
SkSL::Program::kFragment_Kind
|
||||
);
|
||||
@ -1258,10 +1258,10 @@ DEF_TEST(SkSLSwizzleOpt, r) {
|
||||
"void main() {\n"
|
||||
" float v = sqrt(1.0);\n"
|
||||
" sk_FragColor = vec4(v);\n"
|
||||
" sk_FragColor = vec4(0, vec4(v).zyx);\n"
|
||||
" sk_FragColor = vec4(0, 0, vec4(v).xw);\n"
|
||||
" sk_FragColor = vec4(1, 1, vec4(v).wx);\n"
|
||||
" sk_FragColor = vec4(vec4(v).zy, 1, 1);\n"
|
||||
" sk_FragColor = vec4(vec4(v).xyz, 0.0).wzyx;\n"
|
||||
" sk_FragColor = vec4(vec4(v).xw, 0.0, 0.0).zwxy;\n"
|
||||
" sk_FragColor = vec4(vec4(vec4(v).xw, 0.0, 0.0).yx, 1.0, 1.0).zwxy;\n"
|
||||
" sk_FragColor = vec4(vec4(v).zy, 1.0, 1.0);\n"
|
||||
" sk_FragColor = vec4(v);\n"
|
||||
" sk_FragColor = vec4(vec4(v).xx, 1.0, 1.0);\n"
|
||||
" sk_FragColor = vec4(v).wzwz;\n"
|
||||
@ -1281,7 +1281,7 @@ DEF_TEST(SkSLSwizzleScalar, r) {
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" float x = sqrt(4.0);\n"
|
||||
" sk_FragColor = vec4(vec2(x), 0, 1);\n"
|
||||
" sk_FragColor = vec4(vec2(x), 0.0, 1.0);\n"
|
||||
"}\n");
|
||||
test(r,
|
||||
"void main() {"
|
||||
@ -1291,7 +1291,7 @@ DEF_TEST(SkSLSwizzleScalar, r) {
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" sk_FragColor = vec4(vec2(sqrt(4.0)), 0, 1);\n"
|
||||
" sk_FragColor = vec4(vec2(sqrt(4.0)), 0.0, 1.0);\n"
|
||||
"}\n");
|
||||
test(r,
|
||||
"void main() {"
|
||||
@ -1301,7 +1301,7 @@ DEF_TEST(SkSLSwizzleScalar, r) {
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" sk_FragColor = vec4(0, sqrt(4.0), 0, 1);\n"
|
||||
" sk_FragColor = vec4(sqrt(4.0), 0.0, 0.0, 1.0).yxzw;\n"
|
||||
"}\n");
|
||||
test(r,
|
||||
"void main() {"
|
||||
@ -1311,9 +1311,7 @@ DEF_TEST(SkSLSwizzleScalar, r) {
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" float _tmpSwizzle0 = sqrt(4.0);\n"
|
||||
" sk_FragColor = vec4(0, _tmpSwizzle0, 0, _tmpSwizzle0);\n"
|
||||
"\n"
|
||||
" sk_FragColor = vec4(vec2(sqrt(4.0)), 0.0, 0.0).zxwy;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
|
@ -291,7 +291,7 @@ DEF_TEST(SkSLMetalConstantSwizzle, r) {
|
||||
"fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {\n"
|
||||
" Outputs _outputStruct;\n"
|
||||
" thread Outputs* _out = &_outputStruct;\n"
|
||||
" _out->sk_FragColor = float4(float4(0.5).xyz, 1);\n"
|
||||
" _out->sk_FragColor = float4(float4(0.5).xyz, 1.0);\n"
|
||||
" return *_out;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user