aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/sksl
diff options
context:
space:
mode:
authorGravatar Ethan Nicholas <ethannicholas@google.com>2018-02-27 15:25:47 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-02-28 19:02:26 +0000
commit0fc07f95bb2cf6c3e5da1c088694eb1b495cbf01 (patch)
tree03e04c29a4726f4ec0ea5701aa187a435cd1fe8c /src/sksl
parent874c93b2e7dadb2635db229b487105e371d6bf0c (diff)
Update certain instrinsic calls in SkSL SPIR-V gen to not mix vectors and scalars.
Functions like min, max, clamp, and mix cannot intermix vectors and scalars as operands and return value. This updates SkSL to promote scalars to vectors if need be before calling these functions. Bug: skia:7653 Change-Id: I13f98d452978e3f15bafddea638b7bbe313d98ce Reviewed-on: https://skia-review.googlesource.com/110660 Commit-Queue: Greg Daniel <egdaniel@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com>
Diffstat (limited to 'src/sksl')
-rw-r--r--src/sksl/SkSLSPIRVCodeGenerator.cpp115
-rw-r--r--src/sksl/SkSLSPIRVCodeGenerator.h18
2 files changed, 111 insertions, 22 deletions
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp
index d01a82dae2..fbe8bf02a0 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp
@@ -66,12 +66,12 @@ void SPIRVCodeGenerator::setupIntrinsics() {
fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
fIntrinsicMap[String("mod")] = SPECIAL(Mod);
- fIntrinsicMap[String("min")] = BY_TYPE_GLSL(FMin, SMin, UMin);
- fIntrinsicMap[String("max")] = BY_TYPE_GLSL(FMax, SMax, UMax);
- fIntrinsicMap[String("clamp")] = BY_TYPE_GLSL(FClamp, SClamp, UClamp);
+ fIntrinsicMap[String("min")] = SPECIAL(Min);
+ fIntrinsicMap[String("max")] = SPECIAL(Max);
+ fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
SpvOpUndef, SpvOpUndef, SpvOpUndef);
- fIntrinsicMap[String("mix")] = ALL_GLSL(FMix);
+ fIntrinsicMap[String("mix")] = SPECIAL(Mix);
fIntrinsicMap[String("step")] = ALL_GLSL(Step);
fIntrinsicMap[String("smoothstep")] = ALL_GLSL(SmoothStep);
fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
@@ -721,6 +721,62 @@ SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream
}
}
+std::vector<SpvId> SPIRVCodeGenerator::vectorize(
+ const std::vector<std::unique_ptr<Expression>>& args,
+ OutputStream& out) {
+ int vectorSize = 0;
+ for (const auto& a : args) {
+ if (a->fType.kind() == Type::kVector_Kind) {
+ if (vectorSize) {
+ ASSERT(a->fType.columns() == vectorSize);
+ }
+ else {
+ vectorSize = a->fType.columns();
+ }
+ }
+ }
+ std::vector<SpvId> result;
+ for (const auto& a : args) {
+ SpvId raw = this->writeExpression(*a, out);
+ if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
+ SpvId vector = this->nextId();
+ this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
+ this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
+ this->writeWord(vector, out);
+ for (int i = 0; i < vectorSize; i++) {
+ this->writeWord(raw, out);
+ }
+ result.push_back(vector);
+ } else {
+ result.push_back(raw);
+ }
+ }
+ return result;
+}
+
+void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
+ SpvId signedInst, SpvId unsignedInst,
+ const std::vector<SpvId>& args,
+ OutputStream& out) {
+ this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
+ this->writeWord(this->getType(type), out);
+ this->writeWord(id, out);
+ this->writeWord(fGLSLExtendedInstructions, out);
+
+ if (is_float(fContext, type)) {
+ this->writeWord(floatInst, out);
+ } else if (is_signed(fContext, type)) {
+ this->writeWord(signedInst, out);
+ } else if (is_unsigned(fContext, type)) {
+ this->writeWord(unsignedInst, out);
+ } else {
+ ASSERT(false);
+ }
+ for (SpvId a : args) {
+ this->writeWord(a, out);
+ }
+}
+
SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
OutputStream& out) {
SpvId result = this->nextId();
@@ -838,22 +894,8 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
break;
}
case kMod_SpecialIntrinsic: {
- ASSERT(c.fArguments.size() == 2);
- SpvId arg1 = this->writeExpression(*c.fArguments[0], out);
- SpvId arg2 = this->writeExpression(*c.fArguments[1], out);
- if (c.fArguments[0]->fType != c.fArguments[1]->fType) {
- // we have mod(vector, scalar), but SPIR-V wants mod(vector, vector)
- ASSERT(c.fArguments[0]->fType.componentType() == c.fArguments[1]->fType);
- SpvId scalar = arg2;
- const Type& type = c.fArguments[0]->fType;
- arg2 = this->nextId();
- this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), out);
- this->writeWord(this->getType(type), out);
- this->writeWord(arg2, out);
- for (int i = 0; i < type.columns(); i++) {
- this->writeWord(scalar, out);
- }
- }
+ std::vector<SpvId> args = this->vectorize(c.fArguments, out);
+ ASSERT(args.size() == 2);
const Type& operandType = c.fArguments[0]->fType;
SpvOp_ op;
if (is_float(fContext, operandType)) {
@@ -869,8 +911,37 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
this->writeOpCode(op, 5, out);
this->writeWord(this->getType(operandType), out);
this->writeWord(result, out);
- this->writeWord(arg1, out);
- this->writeWord(arg2, out);
+ this->writeWord(args[0], out);
+ this->writeWord(args[1], out);
+ break;
+ }
+ case kClamp_SpecialIntrinsic: {
+ std::vector<SpvId> args = this->vectorize(c.fArguments, out);
+ ASSERT(args.size() == 3);
+ this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
+ GLSLstd450UClamp, args, out);
+ break;
+ }
+ case kMax_SpecialIntrinsic: {
+ std::vector<SpvId> args = this->vectorize(c.fArguments, out);
+ ASSERT(args.size() == 2);
+ this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
+ GLSLstd450UMax, args, out);
+ break;
+ }
+ case kMin_SpecialIntrinsic: {
+ std::vector<SpvId> args = this->vectorize(c.fArguments, out);
+ ASSERT(args.size() == 2);
+ this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
+ GLSLstd450UMin, args, out);
+ break;
+ }
+ case kMix_SpecialIntrinsic: {
+ std::vector<SpvId> args = this->vectorize(c.fArguments, out);
+ ASSERT(args.size() == 3);
+ this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
+ SpvOpUndef, args, out);
+ break;
}
}
return result;
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.h b/src/sksl/SkSLSPIRVCodeGenerator.h
index 0d51af5d71..4bd8d86dd8 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.h
+++ b/src/sksl/SkSLSPIRVCodeGenerator.h
@@ -90,6 +90,10 @@ private:
enum SpecialIntrinsic {
kAtan_SpecialIntrinsic,
+ kClamp_SpecialIntrinsic,
+ kMax_SpecialIntrinsic,
+ kMin_SpecialIntrinsic,
+ kMix_SpecialIntrinsic,
kMod_SpecialIntrinsic,
kSubpassLoad_SpecialIntrinsic,
kTexelFetch_SpecialIntrinsic,
@@ -149,6 +153,20 @@ private:
SpvId writeFunctionCall(const FunctionCall& c, OutputStream& out);
+
+ void writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
+ SpvId signedInst, SpvId unsignedInst,
+ const std::vector<SpvId>& args, OutputStream& out);
+
+ /**
+ * Given a list of potentially mixed scalars and vectors, promotes the scalars to match the
+ * size of the vectors and returns the ids of the written expressions. e.g. given (float, vec2),
+ * returns (vec2(float), vec2). It is an error to use mismatched vector sizes, e.g. (float,
+ * vec2, vec3).
+ */
+ std::vector<SpvId> vectorize(const std::vector<std::unique_ptr<Expression>>& args,
+ OutputStream& out);
+
SpvId writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, OutputStream& out);
SpvId writeConstantVector(const Constructor& c);