| /* |
| * Copyright 2021 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "src/sksl/ir/SkSLConstructorCompoundCast.h" |
| |
| #include "src/sksl/SkSLConstantFolder.h" |
| #include "src/sksl/SkSLProgramSettings.h" |
| #include "src/sksl/ir/SkSLConstructor.h" |
| #include "src/sksl/ir/SkSLConstructorCompound.h" |
| #include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h" |
| #include "src/sksl/ir/SkSLConstructorScalarCast.h" |
| #include "src/sksl/ir/SkSLConstructorSplat.h" |
| |
| namespace SkSL { |
| |
| static std::unique_ptr<Expression> cast_constant_composite(const Context& context, |
| const Type& destType, |
| std::unique_ptr<Expression> constCtor) { |
| const Type& scalarType = destType.componentType(); |
| |
| // We generate nicer code for splats and diagonal matrices by handling them separately instead |
| // of relying on the constant-subexpression code below. This is not truly necessary but it makes |
| // our output look a little better; human beings prefer `half4(0)` to `half4(0, 0, 0, 0)`. |
| if (constCtor->is<ConstructorSplat>()) { |
| // This is a typecast of a splat containing a constant value, e.g. `half4(7)`. We can |
| // replace it with a splat of a different type, e.g. `int4(7)`. |
| ConstructorSplat& splat = constCtor->as<ConstructorSplat>(); |
| return ConstructorSplat::Make( |
| context, constCtor->fLine, destType, |
| ConstructorScalarCast::Make(context, constCtor->fLine, scalarType, |
| std::move(splat.argument()))); |
| } |
| |
| if (constCtor->is<ConstructorDiagonalMatrix>() && destType.isMatrix()) { |
| // This is a typecast of a constant diagonal matrix, e.g. `float3x3(2)`. We can replace it |
| // with a diagonal matrix of a different type, e.g. `half3x3(2)`. |
| ConstructorDiagonalMatrix& matrixCtor = constCtor->as<ConstructorDiagonalMatrix>(); |
| return ConstructorDiagonalMatrix::Make( |
| context, constCtor->fLine, destType, |
| ConstructorScalarCast::Make(context, constCtor->fLine, scalarType, |
| std::move(matrixCtor.argument()))); |
| } |
| |
| // Create a compound Constructor(literal, ...) which typecasts each scalar value inside. |
| size_t numSlots = destType.slotCount(); |
| SkASSERT(numSlots == constCtor->type().slotCount()); |
| |
| ExpressionArray typecastArgs; |
| typecastArgs.reserve_back(numSlots); |
| for (size_t index = 0; index < numSlots; ++index) { |
| std::optional<double> slotVal = constCtor->getConstantValue(index); |
| if (scalarType.checkForOutOfRangeLiteral(context, *slotVal, constCtor->fLine)) { |
| // We've reported an error because the literal is out of range for this type. Zero out |
| // the value to avoid a cascade of errors. |
| *slotVal = 0.0; |
| } |
| typecastArgs.push_back(Literal::Make(constCtor->fLine, *slotVal, &scalarType)); |
| } |
| |
| return ConstructorCompound::Make(context, constCtor->fLine, destType, |
| std::move(typecastArgs)); |
| } |
| |
| std::unique_ptr<Expression> ConstructorCompoundCast::Make(const Context& context, |
| int line, |
| const Type& type, |
| std::unique_ptr<Expression> arg) { |
| // Only vectors or matrices of the same dimensions are allowed. |
| SkASSERT(type.isVector() || type.isMatrix()); |
| SkASSERT(type.isAllowedInES2(context)); |
| SkASSERT(arg->type().isVector() == type.isVector()); |
| SkASSERT(arg->type().isMatrix() == type.isMatrix()); |
| SkASSERT(type.columns() == arg->type().columns()); |
| SkASSERT(type.rows() == arg->type().rows()); |
| |
| // If this is a no-op cast, return the expression as-is. |
| if (type.matches(arg->type())) { |
| return arg; |
| } |
| // Look up the value of constant variables. This allows constant-expressions like |
| // `int4(colorGreen)` to be replaced with the compile-time constant `int4(0, 1, 0, 1)`. |
| arg = ConstantFolder::MakeConstantValueForVariable(std::move(arg)); |
| |
| // We can cast a vector of compile-time constants at compile-time. |
| if (arg->isCompileTimeConstant()) { |
| return cast_constant_composite(context, type, std::move(arg)); |
| } |
| return std::make_unique<ConstructorCompoundCast>(line, type, std::move(arg)); |
| } |
| |
| } // namespace SkSL |