| /* |
| * Copyright 2020 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/sksl/DSLType.h" |
| |
| #include "include/core/SkTypes.h" |
| #include "include/private/SkSLDefines.h" |
| #include "include/private/SkSLProgramElement.h" |
| #include "include/private/SkSLString.h" |
| #include "include/private/SkSLSymbol.h" |
| #include "include/sksl/SkSLErrorReporter.h" |
| #include "src/sksl/SkSLBuiltinTypes.h" |
| #include "src/sksl/SkSLContext.h" |
| #include "src/sksl/SkSLProgramSettings.h" |
| #include "src/sksl/SkSLThreadContext.h" |
| #include "src/sksl/ir/SkSLConstructor.h" |
| #include "src/sksl/ir/SkSLStructDefinition.h" |
| #include "src/sksl/ir/SkSLSymbolTable.h" |
| #include "src/sksl/ir/SkSLType.h" |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| namespace SkSL { |
| |
| struct Modifiers; |
| |
| namespace dsl { |
| |
| static const SkSL::Type* verify_type(const Context& context, |
| const SkSL::Type* type, |
| bool allowGenericTypes, |
| Position pos) { |
| if (!context.fConfig->fIsBuiltinCode && type) { |
| if (!allowGenericTypes && (type->isGeneric() || type->isLiteral())) { |
| context.fErrors->error(pos, "type '" + std::string(type->name()) + "' is generic"); |
| return context.fTypes.fPoison.get(); |
| } |
| if (!type->isAllowedInES2(context)) { |
| context.fErrors->error(pos, "type '" + std::string(type->name()) +"' is not supported"); |
| return context.fTypes.fPoison.get(); |
| } |
| } |
| return type; |
| } |
| |
| static const SkSL::Type* find_type(const Context& context, |
| Position pos, |
| std::string_view name) { |
| const Symbol* symbol = ThreadContext::SymbolTable()->find(name); |
| if (!symbol) { |
| context.fErrors->error(pos, String::printf("no symbol named '%.*s'", |
| (int)name.length(), name.data())); |
| return context.fTypes.fPoison.get(); |
| } |
| if (!symbol->is<SkSL::Type>()) { |
| context.fErrors->error(pos, String::printf("symbol '%.*s' is not a type", |
| (int)name.length(), name.data())); |
| return context.fTypes.fPoison.get(); |
| } |
| const SkSL::Type* type = &symbol->as<SkSL::Type>(); |
| return verify_type(context, type, /*allowGenericTypes=*/false, pos); |
| } |
| |
| static const SkSL::Type* find_type(const Context& context, |
| Position overallPos, |
| std::string_view name, |
| Position modifiersPos, |
| Modifiers* modifiers) { |
| const Type* type = find_type(context, overallPos, name); |
| return type->applyQualifiers(context, modifiers, ThreadContext::SymbolTable().get(), |
| modifiersPos); |
| } |
| |
| static const SkSL::Type* get_type_from_type_constant(TypeConstant tc) { |
| const Context& context = ThreadContext::Context(); |
| switch (tc) { |
| case kBool_Type: |
| return context.fTypes.fBool.get(); |
| case kBool2_Type: |
| return context.fTypes.fBool2.get(); |
| case kBool3_Type: |
| return context.fTypes.fBool3.get(); |
| case kBool4_Type: |
| return context.fTypes.fBool4.get(); |
| case kHalf_Type: |
| return context.fTypes.fHalf.get(); |
| case kHalf2_Type: |
| return context.fTypes.fHalf2.get(); |
| case kHalf3_Type: |
| return context.fTypes.fHalf3.get(); |
| case kHalf4_Type: |
| return context.fTypes.fHalf4.get(); |
| case kHalf2x2_Type: |
| return context.fTypes.fHalf2x2.get(); |
| case kHalf3x2_Type: |
| return context.fTypes.fHalf3x2.get(); |
| case kHalf4x2_Type: |
| return context.fTypes.fHalf4x2.get(); |
| case kHalf2x3_Type: |
| return context.fTypes.fHalf2x3.get(); |
| case kHalf3x3_Type: |
| return context.fTypes.fHalf3x3.get(); |
| case kHalf4x3_Type: |
| return context.fTypes.fHalf4x3.get(); |
| case kHalf2x4_Type: |
| return context.fTypes.fHalf2x4.get(); |
| case kHalf3x4_Type: |
| return context.fTypes.fHalf3x4.get(); |
| case kHalf4x4_Type: |
| return context.fTypes.fHalf4x4.get(); |
| case kFloat_Type: |
| return context.fTypes.fFloat.get(); |
| case kFloat2_Type: |
| return context.fTypes.fFloat2.get(); |
| case kFloat3_Type: |
| return context.fTypes.fFloat3.get(); |
| case kFloat4_Type: |
| return context.fTypes.fFloat4.get(); |
| case kFloat2x2_Type: |
| return context.fTypes.fFloat2x2.get(); |
| case kFloat3x2_Type: |
| return context.fTypes.fFloat3x2.get(); |
| case kFloat4x2_Type: |
| return context.fTypes.fFloat4x2.get(); |
| case kFloat2x3_Type: |
| return context.fTypes.fFloat2x3.get(); |
| case kFloat3x3_Type: |
| return context.fTypes.fFloat3x3.get(); |
| case kFloat4x3_Type: |
| return context.fTypes.fFloat4x3.get(); |
| case kFloat2x4_Type: |
| return context.fTypes.fFloat2x4.get(); |
| case kFloat3x4_Type: |
| return context.fTypes.fFloat3x4.get(); |
| case kFloat4x4_Type: |
| return context.fTypes.fFloat4x4.get(); |
| case kInt_Type: |
| return context.fTypes.fInt.get(); |
| case kInt2_Type: |
| return context.fTypes.fInt2.get(); |
| case kInt3_Type: |
| return context.fTypes.fInt3.get(); |
| case kInt4_Type: |
| return context.fTypes.fInt4.get(); |
| case kShader_Type: |
| return context.fTypes.fShader.get(); |
| case kShort_Type: |
| return context.fTypes.fShort.get(); |
| case kShort2_Type: |
| return context.fTypes.fShort2.get(); |
| case kShort3_Type: |
| return context.fTypes.fShort3.get(); |
| case kShort4_Type: |
| return context.fTypes.fShort4.get(); |
| case kUInt_Type: |
| return context.fTypes.fUInt.get(); |
| case kUInt2_Type: |
| return context.fTypes.fUInt2.get(); |
| case kUInt3_Type: |
| return context.fTypes.fUInt3.get(); |
| case kUInt4_Type: |
| return context.fTypes.fUInt4.get(); |
| case kUShort_Type: |
| return context.fTypes.fUShort.get(); |
| case kUShort2_Type: |
| return context.fTypes.fUShort2.get(); |
| case kUShort3_Type: |
| return context.fTypes.fUShort3.get(); |
| case kUShort4_Type: |
| return context.fTypes.fUShort4.get(); |
| case kVoid_Type: |
| return context.fTypes.fVoid.get(); |
| case kPoison_Type: |
| return context.fTypes.fPoison.get(); |
| default: |
| SkUNREACHABLE; |
| } |
| } |
| |
| DSLType::DSLType(TypeConstant tc, Position pos) |
| : fSkSLType(verify_type(ThreadContext::Context(), |
| get_type_from_type_constant(tc), |
| /*allowGenericTypes=*/false, |
| pos)) {} |
| |
| DSLType::DSLType(std::string_view name, Position pos) |
| : fSkSLType(find_type(ThreadContext::Context(), pos, name)) {} |
| |
| DSLType::DSLType(std::string_view name, DSLModifiers* modifiers, Position pos) |
| : fSkSLType(find_type(ThreadContext::Context(), |
| pos, |
| name, |
| modifiers->fPosition, |
| &modifiers->fModifiers)) {} |
| |
| DSLType::DSLType(const SkSL::Type* type, Position pos) |
| : fSkSLType(verify_type(ThreadContext::Context(), type, /*allowGenericTypes=*/true, pos)) {} |
| |
| DSLType DSLType::Invalid() { |
| return DSLType(ThreadContext::Context().fTypes.fInvalid.get(), Position()); |
| } |
| |
| bool DSLType::isBoolean() const { |
| return this->skslType().isBoolean(); |
| } |
| |
| bool DSLType::isNumber() const { |
| return this->skslType().isNumber(); |
| } |
| |
| bool DSLType::isFloat() const { |
| return this->skslType().isFloat(); |
| } |
| |
| bool DSLType::isSigned() const { |
| return this->skslType().isSigned(); |
| } |
| |
| bool DSLType::isUnsigned() const { |
| return this->skslType().isUnsigned(); |
| } |
| |
| bool DSLType::isInteger() const { |
| return this->skslType().isInteger(); |
| } |
| |
| bool DSLType::isScalar() const { |
| return this->skslType().isScalar(); |
| } |
| |
| bool DSLType::isVector() const { |
| return this->skslType().isVector(); |
| } |
| |
| bool DSLType::isMatrix() const { |
| return this->skslType().isMatrix(); |
| } |
| |
| bool DSLType::isArray() const { |
| return this->skslType().isArray(); |
| } |
| |
| bool DSLType::isStruct() const { |
| return this->skslType().isStruct(); |
| } |
| |
| bool DSLType::isInterfaceBlock() const { |
| return this->skslType().isInterfaceBlock(); |
| } |
| |
| bool DSLType::isEffectChild() const { |
| return this->skslType().isEffectChild(); |
| } |
| |
| DSLExpression DSLType::Construct(DSLType type, SkSpan<DSLExpression> argArray) { |
| SkSL::ExpressionArray skslArgs; |
| skslArgs.reserve_back(argArray.size()); |
| |
| for (DSLExpression& arg : argArray) { |
| if (!arg.hasValue()) { |
| return DSLExpression(); |
| } |
| skslArgs.push_back(arg.release()); |
| } |
| return DSLExpression(SkSL::Constructor::Convert(ThreadContext::Context(), Position(), |
| type.skslType(), std::move(skslArgs))); |
| } |
| |
| DSLType Array(const DSLType& base, int count, Position pos) { |
| count = base.skslType().convertArraySize(ThreadContext::Context(), pos, |
| DSLExpression(count, pos).release()); |
| if (!count) { |
| return DSLType(kPoison_Type); |
| } |
| return DSLType(ThreadContext::SymbolTable()->addArrayDimension(&base.skslType(), count), pos); |
| } |
| |
| DSLType UnsizedArray(const DSLType& base, Position pos) { |
| if (!base.skslType().checkIfUsableInArray(ThreadContext::Context(), pos)) { |
| return DSLType(kPoison_Type); |
| } |
| return ThreadContext::SymbolTable()->addArrayDimension(&base.skslType(), |
| SkSL::Type::kUnsizedArray); |
| } |
| |
| DSLType StructType(std::string_view name, |
| SkSpan<DSLField> fields, |
| bool interfaceBlock, |
| Position pos) { |
| std::vector<SkSL::Type::Field> skslFields; |
| skslFields.reserve(fields.size()); |
| for (const DSLField& field : fields) { |
| skslFields.emplace_back(field.fPosition, field.fModifiers.fModifiers, field.fName, |
| &field.fType.skslType()); |
| } |
| std::unique_ptr<Type> newType = Type::MakeStructType(ThreadContext::Context(), pos, name, |
| std::move(skslFields), interfaceBlock); |
| return DSLType(ThreadContext::SymbolTable()->add(std::move(newType)), pos); |
| } |
| |
| DSLType Struct(std::string_view name, SkSpan<DSLField> fields, Position pos) { |
| DSLType result = StructType(name, fields, /*interfaceBlock=*/false, pos); |
| ThreadContext::ProgramElements().push_back( |
| std::make_unique<SkSL::StructDefinition>(pos, result.skslType())); |
| return result; |
| } |
| |
| } // namespace dsl |
| |
| } // namespace SkSL |