diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp index f5f2151fe3..f4176266c5 100644 --- a/src/sksl/SkSLCompiler.cpp +++ b/src/sksl/SkSLCompiler.cpp @@ -396,14 +396,27 @@ bool try_replace_expression(BasicBlock* b, } /** - * Returns true if the expression is a constant numeric literal with the specified value. + * Returns true if the expression is a constant numeric literal with the specified value, or a + * constant vector with all elements equal to the specified value. */ -bool is_constant(Expression& expr, double value) { +bool is_constant(const Expression& expr, double value) { switch (expr.fKind) { case Expression::kIntLiteral_Kind: return ((IntLiteral&) expr).fValue == value; case Expression::kFloatLiteral_Kind: return ((FloatLiteral&) expr).fValue == value; + case Expression::kConstructor_Kind: { + Constructor& c = (Constructor&) expr; + if (c.fType.kind() == Type::kVector_Kind && c.isConstant()) { + for (int i = 0; i < c.fType.columns(); ++i) { + if (!is_constant(c.getVecComponent(i), value)) { + return false; + } + } + return true; + } + return false; + } default: return false; } @@ -417,6 +430,7 @@ void delete_left(BasicBlock* b, std::vector::iterator* iter, bool* outUpdated, bool* outNeedsRescan) { + ASSERT((*(*iter)->expression())->fKind == Expression::kBinary_Kind); *outUpdated = true; if (!try_replace_expression(b, iter, &((BinaryExpression&) **(*iter)->expression()).fRight)) { *outNeedsRescan = true; @@ -431,12 +445,95 @@ void delete_right(BasicBlock* b, std::vector::iterator* iter, bool* outUpdated, bool* outNeedsRescan) { + ASSERT((*(*iter)->expression())->fKind == Expression::kBinary_Kind); *outUpdated = true; if (!try_replace_expression(b, iter, &((BinaryExpression&) **(*iter)->expression()).fLeft)) { *outNeedsRescan = true; } } +/** + * Constructs the specified type using a single argument. + */ +static std::unique_ptr construct(const Type& type, std::unique_ptr v) { + std::vector> args; + args.push_back(std::move(v)); + auto result = std::unique_ptr(new Constructor(Position(), type, std::move(args))); + return result; +} + +/** + * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an + * expression x, deletes the expression pointed to by iter and replaces it with (x). + */ +static void vectorize(BasicBlock* b, + std::vector::iterator* iter, + const Type& type, + std::unique_ptr* otherExpression, + bool* outUpdated, + bool* outNeedsRescan) { + ASSERT((*(*iter)->expression())->fKind == Expression::kBinary_Kind); + ASSERT(type.kind() == Type::kVector_Kind); + ASSERT((*otherExpression)->fType.kind() == Type::kScalar_Kind); + *outUpdated = true; + std::unique_ptr* target = (*iter)->expression(); + if (!b->tryRemoveExpression(iter)) { + *target = construct(type, std::move(*otherExpression)); + *outNeedsRescan = true; + } else { + *target = construct(type, std::move(*otherExpression)); + if (!b->tryInsertExpression(iter, target)) { + *outNeedsRescan = true; + } + } +} + +/** + * Given a binary expression of the form x vec(y), deletes the right side and vectorizes the + * left to yield vec(x). + */ +static void vectorize_left(BasicBlock* b, + std::vector::iterator* iter, + bool* outUpdated, + bool* outNeedsRescan) { + BinaryExpression& bin = (BinaryExpression&) **(*iter)->expression(); + vectorize(b, iter, bin.fRight->fType, &bin.fLeft, outUpdated, outNeedsRescan); +} + +/** + * Given a binary expression of the form vec(x) y, deletes the left side and vectorizes the + * right to yield vec(y). + */ +static void vectorize_right(BasicBlock* b, + std::vector::iterator* iter, + bool* outUpdated, + bool* outNeedsRescan) { + BinaryExpression& bin = (BinaryExpression&) **(*iter)->expression(); + vectorize(b, iter, bin.fLeft->fType, &bin.fRight, outUpdated, outNeedsRescan); +} + +// Mark that an expression which we were writing to is no longer being written to +void clear_write(const Expression& expr) { + switch (expr.fKind) { + case Expression::kVariableReference_Kind: { + ((VariableReference&) expr).setRefKind(VariableReference::kRead_RefKind); + break; + } + case Expression::kFieldAccess_Kind: + clear_write(*((FieldAccess&) expr).fBase); + break; + case Expression::kSwizzle_Kind: + clear_write(*((Swizzle&) expr).fBase); + break; + case Expression::kIndex_Kind: + clear_write(*((IndexExpression&) expr).fBase); + break; + default: + ABORT("shouldn't be writing to this kind of expression\n"); + break; + } +} + void Compiler::simplifyExpression(DefinitionMap& definitions, BasicBlock& b, std::vector::iterator* iter, @@ -485,30 +582,148 @@ void Compiler::simplifyExpression(DefinitionMap& definitions, case Expression::kBinary_Kind: { // collapse useless expressions like x * 1 or x + 0 BinaryExpression* bin = (BinaryExpression*) expr; + if (((bin->fLeft->fType.kind() != Type::kScalar_Kind) && + (bin->fLeft->fType.kind() != Type::kVector_Kind)) || + ((bin->fRight->fType.kind() != Type::kScalar_Kind) && + (bin->fRight->fType.kind() != Type::kVector_Kind))) { + break; + } switch (bin->fOperator) { case Token::STAR: if (is_constant(*bin->fLeft, 1)) { - delete_left(&b, iter, outUpdated, outNeedsRescan); + if (bin->fLeft->fType.kind() == Type::kVector_Kind && + bin->fRight->fType.kind() == Type::kScalar_Kind) { + // vec4(1) * x -> vec4(x) + vectorize_right(&b, iter, outUpdated, outNeedsRescan); + } else { + // 1 * x -> x + // 1 * vec4(x) -> vec4(x) + // vec4(1) * vec4(x) -> vec4(x) + delete_left(&b, iter, outUpdated, outNeedsRescan); + } + } + else if (is_constant(*bin->fLeft, 0)) { + if (bin->fLeft->fType.kind() == Type::kScalar_Kind && + bin->fRight->fType.kind() == Type::kVector_Kind) { + // 0 * vec4(x) -> vec4(0) + vectorize_left(&b, iter, outUpdated, outNeedsRescan); + } else { + // 0 * x -> 0 + // vec4(0) * x -> vec4(0) + // vec4(0) * vec4(x) -> vec4(0) + delete_right(&b, iter, outUpdated, outNeedsRescan); + } } else if (is_constant(*bin->fRight, 1)) { - delete_right(&b, iter, outUpdated, outNeedsRescan); + if (bin->fLeft->fType.kind() == Type::kScalar_Kind && + bin->fRight->fType.kind() == Type::kVector_Kind) { + // x * vec4(1) -> vec4(x) + vectorize_left(&b, iter, outUpdated, outNeedsRescan); + } else { + // x * 1 -> x + // vec4(x) * 1 -> vec4(x) + // vec4(x) * vec4(1) -> vec4(x) + delete_right(&b, iter, outUpdated, outNeedsRescan); + } + } + else if (is_constant(*bin->fRight, 0)) { + if (bin->fLeft->fType.kind() == Type::kVector_Kind && + bin->fRight->fType.kind() == Type::kScalar_Kind) { + // vec4(x) * 0 -> vec4(0) + vectorize_right(&b, iter, outUpdated, outNeedsRescan); + } else { + // x * 0 -> 0 + // x * vec4(0) -> vec4(0) + // vec4(x) * vec4(0) -> vec4(0) + delete_left(&b, iter, outUpdated, outNeedsRescan); + } } break; case Token::PLUS: if (is_constant(*bin->fLeft, 0)) { - delete_left(&b, iter, outUpdated, outNeedsRescan); - } - if (is_constant(*bin->fRight, 0)) { - delete_right(&b, iter, outUpdated, outNeedsRescan); + if (bin->fLeft->fType.kind() == Type::kVector_Kind && + bin->fRight->fType.kind() == Type::kScalar_Kind) { + // vec4(0) + x -> vec4(x) + vectorize_right(&b, iter, outUpdated, outNeedsRescan); + } else { + // 0 + x -> x + // 0 + vec4(x) -> vec4(x) + // vec4(0) + vec4(x) -> vec4(x) + delete_left(&b, iter, outUpdated, outNeedsRescan); + } + } else if (is_constant(*bin->fRight, 0)) { + if (bin->fLeft->fType.kind() == Type::kScalar_Kind && + bin->fRight->fType.kind() == Type::kVector_Kind) { + // x + vec4(0) -> vec4(x) + vectorize_left(&b, iter, outUpdated, outNeedsRescan); + } else { + // x + 0 -> x + // vec4(x) + 0 -> vec4(x) + // vec4(x) + vec4(0) -> vec4(x) + delete_right(&b, iter, outUpdated, outNeedsRescan); + } } break; case Token::MINUS: if (is_constant(*bin->fRight, 0)) { - delete_right(&b, iter, outUpdated, outNeedsRescan); + if (bin->fLeft->fType.kind() == Type::kScalar_Kind && + bin->fRight->fType.kind() == Type::kVector_Kind) { + // x - vec4(0) -> vec4(x) + vectorize_left(&b, iter, outUpdated, outNeedsRescan); + } else { + // x - 0 -> x + // vec4(x) - 0 -> vec4(x) + // vec4(x) - vec4(0) -> vec4(x) + delete_right(&b, iter, outUpdated, outNeedsRescan); + } } break; case Token::SLASH: if (is_constant(*bin->fRight, 1)) { + if (bin->fLeft->fType.kind() == Type::kScalar_Kind && + bin->fRight->fType.kind() == Type::kVector_Kind) { + // x / vec4(1) -> vec4(x) + vectorize_left(&b, iter, outUpdated, outNeedsRescan); + } else { + // x / 1 -> x + // vec4(x) / 1 -> vec4(x) + // vec4(x) / vec4(1) -> vec4(x) + delete_right(&b, iter, outUpdated, outNeedsRescan); + } + } else if (is_constant(*bin->fLeft, 0)) { + if (bin->fLeft->fType.kind() == Type::kScalar_Kind && + bin->fRight->fType.kind() == Type::kVector_Kind) { + // 0 / vec4(x) -> vec4(0) + vectorize_left(&b, iter, outUpdated, outNeedsRescan); + } else { + // 0 / x -> 0 + // vec4(0) / x -> vec4(0) + // vec4(0) / vec4(x) -> vec4(0) + delete_right(&b, iter, outUpdated, outNeedsRescan); + } + } + break; + case Token::PLUSEQ: + if (is_constant(*bin->fRight, 0)) { + clear_write(*bin->fLeft); + delete_right(&b, iter, outUpdated, outNeedsRescan); + } + break; + case Token::MINUSEQ: + if (is_constant(*bin->fRight, 0)) { + clear_write(*bin->fLeft); + delete_right(&b, iter, outUpdated, outNeedsRescan); + } + break; + case Token::STAREQ: + if (is_constant(*bin->fRight, 1)) { + clear_write(*bin->fLeft); + delete_right(&b, iter, outUpdated, outNeedsRescan); + } + break; + case Token::SLASHEQ: + if (is_constant(*bin->fRight, 1)) { + clear_write(*bin->fLeft); delete_right(&b, iter, outUpdated, outNeedsRescan); } break; diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp index 6951cac827..b945211eca 100644 --- a/tests/SkSLGLSLTest.cpp +++ b/tests/SkSLGLSLTest.cpp @@ -173,8 +173,8 @@ DEF_TEST(SkSLMatrices, r) { "mat2x4 x = mat2x4(1);" "mat3x2 y = mat3x2(1, 0, 0, 1, vec2(2, 2));" "mat3x4 z = x * y;" - "vec3 v1 = mat3(1) * vec3(1);" - "vec3 v2 = vec3(1) * mat3(1);" + "vec3 v1 = mat3(1) * vec3(2);" + "vec3 v2 = vec3(2) * mat3(1);" "sk_FragColor = vec4(z[0].x, v1 + v2);" "}", *SkSL::ShaderCapsFactory::Default(), @@ -182,8 +182,8 @@ DEF_TEST(SkSLMatrices, r) { "out vec4 sk_FragColor;\n" "void main() {\n" " mat3x4 z = mat2x4(1.0) * mat3x2(1.0, 0.0, 0.0, 1.0, vec2(2.0, 2.0));\n" - " vec3 v1 = mat3(1.0) * vec3(1.0);\n" - " vec3 v2 = vec3(1.0) * mat3(1.0);\n" + " vec3 v1 = mat3(1.0) * vec3(2.0);\n" + " vec3 v2 = vec3(2.0) * mat3(1.0);\n" " sk_FragColor = vec4(z[0].x, v1 + v2);\n" "}\n"); } @@ -523,6 +523,25 @@ DEF_TEST(SkSLIntFolding, r) { "sk_FragColor.r = 6 >= 7 ? 10 : -10;" "sk_FragColor.r = 6 <= 6 ? 11 : -11;" "sk_FragColor.r = 6 <= 5 ? 12 : -12;" + "sk_FragColor.r = int(sqrt(1)) + 0;" + "sk_FragColor.r = 0 + int(sqrt(2));" + "sk_FragColor.r = int(sqrt(3)) - 0;" + "sk_FragColor.r = int(sqrt(4)) * 0;" + "sk_FragColor.r = int(sqrt(5)) * 1;" + "sk_FragColor.r = 1 * int(sqrt(6));" + "sk_FragColor.r = 0 * int(sqrt(7));" + "sk_FragColor.r = int(sqrt(8)) / 1;" + "sk_FragColor.r = 0 / int(sqrt(9));" + "int x = int(sqrt(2));" + "x += 1;" + "x += 0;" + "x -= 1;" + "x -= 0;" + "x *= 1;" + "x *= 2;" + "x /= 1;" + "x /= 2;" + "sk_FragColor.r = x;" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" @@ -549,6 +568,21 @@ DEF_TEST(SkSLIntFolding, r) { " sk_FragColor.x = -10.0;\n" " sk_FragColor.x = 11.0;\n" " sk_FragColor.x = -12.0;\n" + " sk_FragColor.x = float(int(sqrt(1.0)));\n" + " sk_FragColor.x = float(int(sqrt(2.0)));\n" + " sk_FragColor.x = float(int(sqrt(3.0)));\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = float(int(sqrt(5.0)));\n" + " sk_FragColor.x = float(int(sqrt(6.0)));\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = float(int(sqrt(8.0)));\n" + " sk_FragColor.x = 0.0;\n" + " int x = int(sqrt(2.0));\n" + " x += 1;\n" + " x -= 1;\n" + " x *= 2;\n" + " x /= 2;\n" + " sk_FragColor.x = float(x);\n" "}\n"); } @@ -572,6 +606,23 @@ DEF_TEST(SkSLFloatFolding, r) { "sk_FragColor.r = 6.0 < 6.0 ? 10 : -10;" "sk_FragColor.r = 6.0 <= 6.0 ? 11 : -11;" "sk_FragColor.r = 6.0 <= 5.0 ? 12 : -12;" + "sk_FragColor.r = sqrt(1) + 0;" + "sk_FragColor.r = 0 + sqrt(2);" + "sk_FragColor.r = sqrt(3) - 0;" + "sk_FragColor.r = sqrt(4) * 0;" + "sk_FragColor.r = sqrt(5) * 1;" + "sk_FragColor.r = 1 * sqrt(6);" + "sk_FragColor.r = 0 * sqrt(7);" + "sk_FragColor.r = sqrt(8) / 1;" + "sk_FragColor.r = 0 / sqrt(9);" + "sk_FragColor.r += 1;" + "sk_FragColor.r += 0;" + "sk_FragColor.r -= 1;" + "sk_FragColor.r -= 0;" + "sk_FragColor.r *= 1;" + "sk_FragColor.r *= 2;" + "sk_FragColor.r /= 1;" + "sk_FragColor.r /= 2;" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" @@ -594,6 +645,19 @@ DEF_TEST(SkSLFloatFolding, r) { " sk_FragColor.x = -10.0;\n" " sk_FragColor.x = 11.0;\n" " sk_FragColor.x = -12.0;\n" + " sk_FragColor.x = sqrt(1.0);\n" + " sk_FragColor.x = sqrt(2.0);\n" + " sk_FragColor.x = sqrt(3.0);\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = sqrt(5.0);\n" + " sk_FragColor.x = sqrt(6.0);\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x = sqrt(8.0);\n" + " sk_FragColor.x = 0.0;\n" + " sk_FragColor.x += 1.0;\n" + " sk_FragColor.x -= 1.0;\n" + " sk_FragColor.x *= 2.0;\n" + " sk_FragColor.x /= 2.0;\n" "}\n"); } @@ -639,6 +703,39 @@ DEF_TEST(SkSLVecFolding, r) { "sk_FragColor.x = vec4(vec3(1), 1) == vec4(vec2(1), 1, 0) ? 8.0 : -8.0;" "sk_FragColor.x = vec2(1) != vec2(1, 0) ? 9.0 : -9.0;" "sk_FragColor.x = vec4(1) != vec4(vec2(1), vec2(1)) ? 10.0 : -10.0;" + "sk_FragColor = vec4(sqrt(1)) * vec4(1);" + "sk_FragColor = vec4(1) * vec4(sqrt(2));" + "sk_FragColor = vec4(0) * vec4(sqrt(3));" + "sk_FragColor = vec4(sqrt(4)) * vec4(0);" + "sk_FragColor = vec4(0) / vec4(sqrt(5));" + "sk_FragColor = vec4(0) + vec4(sqrt(6));" + "sk_FragColor = vec4(sqrt(7)) + vec4(0);" + "sk_FragColor = vec4(sqrt(8)) - vec4(0);" + "sk_FragColor = vec4(0) + sqrt(9);" + "sk_FragColor = vec4(0) * sqrt(10);" + "sk_FragColor = vec4(0) / sqrt(11);" + "sk_FragColor = vec4(1) * sqrt(12);" + "sk_FragColor = 0 + vec4(sqrt(13));" + "sk_FragColor = 0 * vec4(sqrt(14));" + "sk_FragColor = 0 / vec4(sqrt(15));" + "sk_FragColor = 1 * vec4(sqrt(16));" + "sk_FragColor = vec4(sqrt(17)) + 0;" + "sk_FragColor = vec4(sqrt(18)) * 0;" + "sk_FragColor = vec4(sqrt(19)) * 1;" + "sk_FragColor = vec4(sqrt(19.5)) - 0;" + "sk_FragColor = sqrt(20) * vec4(1);" + "sk_FragColor = sqrt(21) + vec4(0);" + "sk_FragColor = sqrt(22) - vec4(0);" + "sk_FragColor = sqrt(23) / vec4(1);" + "sk_FragColor = vec4(sqrt(24)) / 1;" + "sk_FragColor += vec4(1);" + "sk_FragColor += vec4(0);" + "sk_FragColor -= vec4(1);" + "sk_FragColor -= vec4(0);" + "sk_FragColor *= vec4(1);" + "sk_FragColor *= vec4(2);" + "sk_FragColor /= vec4(1);" + "sk_FragColor /= vec4(2);" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" @@ -660,6 +757,35 @@ DEF_TEST(SkSLVecFolding, r) { " sk_FragColor.x = -8.0;\n" " sk_FragColor.x = 9.0;\n" " sk_FragColor.x = -10.0;\n" + " sk_FragColor = vec4(sqrt(1.0));\n" + " sk_FragColor = vec4(sqrt(2.0));\n" + " sk_FragColor = vec4(0.0);\n" + " sk_FragColor = vec4(0.0);\n" + " sk_FragColor = vec4(0.0);\n" + " sk_FragColor = vec4(sqrt(6.0));\n" + " sk_FragColor = vec4(sqrt(7.0));\n" + " sk_FragColor = vec4(sqrt(8.0));\n" + " sk_FragColor = vec4(sqrt(9.0));\n" + " sk_FragColor = vec4(0.0);\n" + " sk_FragColor = vec4(0.0);\n" + " sk_FragColor = vec4(sqrt(12.0));\n" + " sk_FragColor = vec4(sqrt(13.0));\n" + " sk_FragColor = vec4(0.0);\n" + " sk_FragColor = vec4(0.0);\n" + " sk_FragColor = vec4(sqrt(16.0));\n" + " sk_FragColor = vec4(sqrt(17.0));\n" + " sk_FragColor = vec4(0.0);\n" + " sk_FragColor = vec4(sqrt(19.0));\n" + " sk_FragColor = vec4(sqrt(19.5));\n" + " sk_FragColor = vec4(sqrt(20.0));\n" + " sk_FragColor = vec4(sqrt(21.0));\n" + " sk_FragColor = vec4(sqrt(22.0));\n" + " sk_FragColor = vec4(sqrt(23.0));\n" + " sk_FragColor = vec4(sqrt(24.0));\n" + " sk_FragColor += vec4(1.0);\n" + " sk_FragColor -= vec4(1.0);\n" + " sk_FragColor *= vec4(2.0);\n" + " sk_FragColor /= vec4(2.0);\n" "}\n"); } @@ -1030,38 +1156,38 @@ DEF_TEST(SkSLRectangleTexture, r) { test(r, "uniform sampler2D test;" "void main() {" - " sk_FragColor = texture(test, vec2(1));" + " sk_FragColor = texture(test, vec2(0.5));" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "uniform sampler2D test;\n" "void main() {\n" - " sk_FragColor = texture(test, vec2(1.0));\n" + " sk_FragColor = texture(test, vec2(0.5));\n" "}\n"); test(r, "uniform sampler2DRect test;" "void main() {" - " sk_FragColor = texture(test, vec2(1));" + " sk_FragColor = texture(test, vec2(0.5));" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "uniform sampler2DRect test;\n" "void main() {\n" - " sk_FragColor = texture(test, textureSize(test) * vec2(1.0));\n" + " sk_FragColor = texture(test, textureSize(test) * vec2(0.5));\n" "}\n"); test(r, "uniform sampler2DRect test;" "void main() {" - " sk_FragColor = texture(test, vec3(1));" + " sk_FragColor = texture(test, vec3(0.5));" "}", *SkSL::ShaderCapsFactory::Default(), "#version 400\n" "out vec4 sk_FragColor;\n" "uniform sampler2DRect test;\n" "void main() {\n" - " sk_FragColor = texture(test, vec3(textureSize(test), 1.0) * vec3(1.0));\n" + " sk_FragColor = texture(test, vec3(textureSize(test), 1.0) * vec3(0.5));\n" "}\n"); }