Moved swizzle error checking into Swizzle::Convert
Change-Id: Id2676ffaba1dafc4a0485d99e1c5b87b990e0861 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/426976 Reviewed-by: John Stiles <johnstiles@google.com> Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com>
This commit is contained in:
parent
df3edc570f
commit
59ff4e2b78
@ -14,7 +14,6 @@
|
||||
|
||||
#include "include/private/SkSLLayout.h"
|
||||
#include "include/private/SkTArray.h"
|
||||
#include "include/private/SkTOptional.h"
|
||||
#include "include/sksl/DSLCore.h"
|
||||
#include "src/core/SkScopeExit.h"
|
||||
#include "src/sksl/SkSLAnalysis.h"
|
||||
@ -1410,147 +1409,9 @@ std::unique_ptr<Expression> IRGenerator::convertPrefixExpression(const ASTNode&
|
||||
return PrefixExpression::Convert(fContext, expression.getOperator(), std::move(base));
|
||||
}
|
||||
|
||||
static bool validate_swizzle_domain(skstd::string_view fields) {
|
||||
enum SwizzleDomain {
|
||||
kCoordinate,
|
||||
kColor,
|
||||
kUV,
|
||||
kRectangle,
|
||||
};
|
||||
|
||||
skstd::optional<SwizzleDomain> domain;
|
||||
|
||||
for (char field : fields) {
|
||||
SwizzleDomain fieldDomain;
|
||||
switch (field) {
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
case 'w':
|
||||
fieldDomain = kCoordinate;
|
||||
break;
|
||||
case 'r':
|
||||
case 'g':
|
||||
case 'b':
|
||||
case 'a':
|
||||
fieldDomain = kColor;
|
||||
break;
|
||||
case 's':
|
||||
case 't':
|
||||
case 'p':
|
||||
case 'q':
|
||||
fieldDomain = kUV;
|
||||
break;
|
||||
case 'L':
|
||||
case 'T':
|
||||
case 'R':
|
||||
case 'B':
|
||||
fieldDomain = kRectangle;
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
continue;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!domain.has_value()) {
|
||||
domain = fieldDomain;
|
||||
} else if (domain != fieldDomain) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Swizzles are complicated due to constant components. The most difficult case is a mask like
|
||||
// '.x1w0'. A naive approach might turn that into 'float4(base.x, 1, base.w, 0)', but that evaluates
|
||||
// 'base' twice. We instead group the swizzle mask ('xw') and constants ('1, 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, 1, 0).xzyw'.
|
||||
std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expression> base,
|
||||
skstd::string_view fields) {
|
||||
const int offset = base->fOffset;
|
||||
const Type& baseType = base->type();
|
||||
if (!baseType.isVector() && !baseType.isNumber()) {
|
||||
this->errorReporter().error(
|
||||
offset, "cannot swizzle value of type '" + baseType.displayName() + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (fields.length() > 4) {
|
||||
this->errorReporter().error(offset, "too many components in swizzle mask '" + fields + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!validate_swizzle_domain(fields)) {
|
||||
this->errorReporter().error(offset, "invalid swizzle mask '" + fields + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ComponentArray components;
|
||||
bool foundXYZW = false;
|
||||
for (char field : fields) {
|
||||
switch (field) {
|
||||
case '0':
|
||||
components.push_back(SwizzleComponent::ZERO);
|
||||
break;
|
||||
case '1':
|
||||
components.push_back(SwizzleComponent::ONE);
|
||||
break;
|
||||
case 'x':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 'L':
|
||||
components.push_back(SwizzleComponent::X);
|
||||
foundXYZW = true;
|
||||
break;
|
||||
case 'y':
|
||||
case 'g':
|
||||
case 't':
|
||||
case 'T':
|
||||
if (baseType.columns() >= 2) {
|
||||
components.push_back(SwizzleComponent::Y);
|
||||
foundXYZW = true;
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case 'z':
|
||||
case 'b':
|
||||
case 'p':
|
||||
case 'R':
|
||||
if (baseType.columns() >= 3) {
|
||||
components.push_back(SwizzleComponent::Z);
|
||||
foundXYZW = true;
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case 'w':
|
||||
case 'a':
|
||||
case 'q':
|
||||
case 'B':
|
||||
if (baseType.columns() >= 4) {
|
||||
components.push_back(SwizzleComponent::W);
|
||||
foundXYZW = true;
|
||||
break;
|
||||
}
|
||||
// The swizzle component references a field that doesn't exist in the base type.
|
||||
this->errorReporter().error(
|
||||
offset, String::printf("invalid swizzle component '%c'", field));
|
||||
return nullptr;
|
||||
default:
|
||||
SkDEBUGFAIL("unexpected swizzle component");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundXYZW) {
|
||||
this->errorReporter().error(offset, "swizzle must refer to base expression");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Swizzle::Convert(fContext, std::move(base), components);
|
||||
return Swizzle::Convert(fContext, std::move(base), fields);
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> IRGenerator::convertIndexExpression(const ASTNode& index) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "include/private/SkTOptional.h"
|
||||
#include "src/sksl/SkSLConstantFolder.h"
|
||||
#include "src/sksl/ir/SkSLConstructor.h"
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
@ -13,51 +14,193 @@
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
static bool validate_swizzle_domain(skstd::string_view fields) {
|
||||
enum SwizzleDomain {
|
||||
kCoordinate,
|
||||
kColor,
|
||||
kUV,
|
||||
kRectangle,
|
||||
};
|
||||
|
||||
skstd::optional<SwizzleDomain> domain;
|
||||
|
||||
for (char field : fields) {
|
||||
SwizzleDomain fieldDomain;
|
||||
switch (field) {
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
case 'w':
|
||||
fieldDomain = kCoordinate;
|
||||
break;
|
||||
case 'r':
|
||||
case 'g':
|
||||
case 'b':
|
||||
case 'a':
|
||||
fieldDomain = kColor;
|
||||
break;
|
||||
case 's':
|
||||
case 't':
|
||||
case 'p':
|
||||
case 'q':
|
||||
fieldDomain = kUV;
|
||||
break;
|
||||
case 'L':
|
||||
case 'T':
|
||||
case 'R':
|
||||
case 'B':
|
||||
fieldDomain = kRectangle;
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
continue;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!domain.has_value()) {
|
||||
domain = fieldDomain;
|
||||
} else if (domain != fieldDomain) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> Swizzle::Convert(const Context& context,
|
||||
std::unique_ptr<Expression> base,
|
||||
skstd::string_view maskString) {
|
||||
if (!validate_swizzle_domain(maskString)) {
|
||||
context.fErrors.error(base->fOffset, "invalid swizzle mask '" + maskString + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ComponentArray components;
|
||||
for (char field : maskString) {
|
||||
switch (field) {
|
||||
case '0':
|
||||
components.push_back(SwizzleComponent::ZERO);
|
||||
break;
|
||||
case '1':
|
||||
components.push_back(SwizzleComponent::ONE);
|
||||
break;
|
||||
case 'x':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 'L':
|
||||
components.push_back(SwizzleComponent::X);
|
||||
break;
|
||||
case 'y':
|
||||
case 'g':
|
||||
case 't':
|
||||
case 'T':
|
||||
components.push_back(SwizzleComponent::Y);
|
||||
break;
|
||||
case 'z':
|
||||
case 'b':
|
||||
case 'p':
|
||||
case 'R':
|
||||
components.push_back(SwizzleComponent::Z);
|
||||
break;
|
||||
case 'w':
|
||||
case 'a':
|
||||
case 'q':
|
||||
case 'B':
|
||||
components.push_back(SwizzleComponent::W);
|
||||
break;
|
||||
default:
|
||||
SkDEBUGFAIL("unexpected swizzle component");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return Convert(context, std::move(base), std::move(components), maskString);
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> Swizzle::Convert(const Context& context,
|
||||
std::unique_ptr<Expression> base,
|
||||
ComponentArray inComponents) {
|
||||
return Convert(context, std::move(base), std::move(inComponents), "");
|
||||
}
|
||||
|
||||
|
||||
// Swizzles are complicated due to constant components. The most difficult case is a mask like
|
||||
// '.x1w0'. A naive approach might turn that into 'float4(base.x, 1, base.w, 0)', but that evaluates
|
||||
// 'base' twice. We instead group the swizzle mask ('xw') and constants ('1, 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, 1, 0).xzyw'.
|
||||
std::unique_ptr<Expression> Swizzle::Convert(const Context& context,
|
||||
std::unique_ptr<Expression> base,
|
||||
ComponentArray inComponents,
|
||||
skstd::string_view maskString) {
|
||||
SkASSERT(maskString.empty() || (int) maskString.length() == inComponents.count());
|
||||
|
||||
const int offset = base->fOffset;
|
||||
const Type& baseType = base->type();
|
||||
|
||||
// The IRGenerator is responsible for enforcing these invariants.
|
||||
SkASSERTF(baseType.isVector() || baseType.isScalar(),
|
||||
"cannot swizzle type '%s'", baseType.description().c_str());
|
||||
SkASSERT(inComponents.count() >= 1 && inComponents.count() <= 4);
|
||||
if (!baseType.isVector() && !baseType.isNumber()) {
|
||||
context.fErrors.error(
|
||||
offset, "cannot swizzle value of type '" + baseType.displayName() + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (inComponents.count() > 4) {
|
||||
String error = "too many components in swizzle mask";
|
||||
if (!maskString.empty()) {
|
||||
error += " '" + maskString + "'";
|
||||
}
|
||||
context.fErrors.error(offset, error.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ComponentArray maskComponents;
|
||||
for (int8_t component : inComponents) {
|
||||
switch (component) {
|
||||
bool foundXYZW = false;
|
||||
for (int i = 0; i < inComponents.count(); ++i) {
|
||||
switch (inComponents[i]) {
|
||||
case SwizzleComponent::ZERO:
|
||||
case SwizzleComponent::ONE:
|
||||
// Skip over constant fields for now.
|
||||
break;
|
||||
case SwizzleComponent::X:
|
||||
foundXYZW = true;
|
||||
maskComponents.push_back(SwizzleComponent::X);
|
||||
break;
|
||||
case SwizzleComponent::Y:
|
||||
foundXYZW = true;
|
||||
if (baseType.columns() >= 2) {
|
||||
maskComponents.push_back(SwizzleComponent::Y);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case SwizzleComponent::Z:
|
||||
foundXYZW = true;
|
||||
if (baseType.columns() >= 3) {
|
||||
maskComponents.push_back(SwizzleComponent::Z);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case SwizzleComponent::W:
|
||||
foundXYZW = true;
|
||||
if (baseType.columns() >= 4) {
|
||||
maskComponents.push_back(SwizzleComponent::W);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
SkDEBUGFAILF("invalid swizzle component %d", component);
|
||||
// The swizzle component references a field that doesn't exist in the base type.
|
||||
context.fErrors.error(offset,
|
||||
maskString.empty() ? "invalid swizzle component"
|
||||
: String::printf("invalid swizzle component '%c'",
|
||||
maskString[i]));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundXYZW) {
|
||||
context.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)
|
||||
|
@ -39,6 +39,10 @@ struct Swizzle final : public Expression {
|
||||
std::unique_ptr<Expression> base,
|
||||
ComponentArray inComponents);
|
||||
|
||||
static std::unique_ptr<Expression> Convert(const Context& context,
|
||||
std::unique_ptr<Expression> base,
|
||||
skstd::string_view maskString);
|
||||
|
||||
// Swizzle::Make does not permit ZERO or ONE in the component array, just X/Y/Z/W; errors are
|
||||
// reported via ASSERT.
|
||||
static std::unique_ptr<Expression> Make(const Context& context,
|
||||
@ -75,6 +79,11 @@ struct Swizzle final : public Expression {
|
||||
}
|
||||
|
||||
private:
|
||||
static std::unique_ptr<Expression> Convert(const Context& context,
|
||||
std::unique_ptr<Expression> base,
|
||||
ComponentArray inComponents,
|
||||
skstd::string_view maskString);
|
||||
|
||||
Swizzle(const Type* type, std::unique_ptr<Expression> base, const ComponentArray& components)
|
||||
: INHERITED(base->fOffset, kExpressionKind, type)
|
||||
, fBase(std::move(base))
|
||||
|
@ -3,6 +3,6 @@
|
||||
error: 3: type 'S' does not have a field named 'missing'
|
||||
error: 4: not a function
|
||||
error: 5: type mismatch: '=' cannot operate on 'float', 'bool3'
|
||||
error: 6: too many components in swizzle mask 'missing'
|
||||
error: 6: invalid swizzle mask 'missing'
|
||||
error: 7: expected array, but found 'float'
|
||||
5 errors
|
||||
|
Loading…
Reference in New Issue
Block a user