LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/sksl - SkSLCompiler.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 329 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "SkSLCompiler.h"
       9             : 
      10             : #include "ast/SkSLASTPrecision.h"
      11             : #include "SkSLCFGGenerator.h"
      12             : #include "SkSLGLSLCodeGenerator.h"
      13             : #include "SkSLIRGenerator.h"
      14             : #include "SkSLParser.h"
      15             : #include "SkSLSPIRVCodeGenerator.h"
      16             : #include "ir/SkSLExpression.h"
      17             : #include "ir/SkSLIntLiteral.h"
      18             : #include "ir/SkSLModifiersDeclaration.h"
      19             : #include "ir/SkSLSymbolTable.h"
      20             : #include "ir/SkSLUnresolvedFunction.h"
      21             : #include "ir/SkSLVarDeclarations.h"
      22             : 
      23             : #ifdef SK_ENABLE_SPIRV_VALIDATION
      24             : #include "spirv-tools/libspirv.hpp"
      25             : #endif
      26             : 
      27             : #define STRINGIFY(x) #x
      28             : 
      29             : // include the built-in shader symbols as static strings
      30             : 
      31             : static const char* SKSL_INCLUDE =
      32             : #include "sksl.include"
      33             : ;
      34             : 
      35             : static const char* SKSL_VERT_INCLUDE =
      36             : #include "sksl_vert.include"
      37             : ;
      38             : 
      39             : static const char* SKSL_FRAG_INCLUDE =
      40             : #include "sksl_frag.include"
      41             : ;
      42             : 
      43             : static const char* SKSL_GEOM_INCLUDE =
      44             : #include "sksl_geom.include"
      45             : ;
      46             : 
      47             : namespace SkSL {
      48             : 
      49           0 : Compiler::Compiler()
      50           0 : : fErrorCount(0) {
      51           0 :     auto types = std::shared_ptr<SymbolTable>(new SymbolTable(this));
      52           0 :     auto symbols = std::shared_ptr<SymbolTable>(new SymbolTable(types, this));
      53           0 :     fIRGenerator = new IRGenerator(&fContext, symbols, *this);
      54           0 :     fTypes = types;
      55             :     #define ADD_TYPE(t) types->addWithoutOwnership(fContext.f ## t ## _Type->fName, \
      56             :                                                    fContext.f ## t ## _Type.get())
      57           0 :     ADD_TYPE(Void);
      58           0 :     ADD_TYPE(Float);
      59           0 :     ADD_TYPE(Vec2);
      60           0 :     ADD_TYPE(Vec3);
      61           0 :     ADD_TYPE(Vec4);
      62           0 :     ADD_TYPE(Double);
      63           0 :     ADD_TYPE(DVec2);
      64           0 :     ADD_TYPE(DVec3);
      65           0 :     ADD_TYPE(DVec4);
      66           0 :     ADD_TYPE(Int);
      67           0 :     ADD_TYPE(IVec2);
      68           0 :     ADD_TYPE(IVec3);
      69           0 :     ADD_TYPE(IVec4);
      70           0 :     ADD_TYPE(UInt);
      71           0 :     ADD_TYPE(UVec2);
      72           0 :     ADD_TYPE(UVec3);
      73           0 :     ADD_TYPE(UVec4);
      74           0 :     ADD_TYPE(Bool);
      75           0 :     ADD_TYPE(BVec2);
      76           0 :     ADD_TYPE(BVec3);
      77           0 :     ADD_TYPE(BVec4);
      78           0 :     ADD_TYPE(Mat2x2);
      79           0 :     types->addWithoutOwnership(String("mat2x2"), fContext.fMat2x2_Type.get());
      80           0 :     ADD_TYPE(Mat2x3);
      81           0 :     ADD_TYPE(Mat2x4);
      82           0 :     ADD_TYPE(Mat3x2);
      83           0 :     ADD_TYPE(Mat3x3);
      84           0 :     types->addWithoutOwnership(String("mat3x3"), fContext.fMat3x3_Type.get());
      85           0 :     ADD_TYPE(Mat3x4);
      86           0 :     ADD_TYPE(Mat4x2);
      87           0 :     ADD_TYPE(Mat4x3);
      88           0 :     ADD_TYPE(Mat4x4);
      89           0 :     types->addWithoutOwnership(String("mat4x4"), fContext.fMat4x4_Type.get());
      90           0 :     ADD_TYPE(GenType);
      91           0 :     ADD_TYPE(GenDType);
      92           0 :     ADD_TYPE(GenIType);
      93           0 :     ADD_TYPE(GenUType);
      94           0 :     ADD_TYPE(GenBType);
      95           0 :     ADD_TYPE(Mat);
      96           0 :     ADD_TYPE(Vec);
      97           0 :     ADD_TYPE(GVec);
      98           0 :     ADD_TYPE(GVec2);
      99           0 :     ADD_TYPE(GVec3);
     100           0 :     ADD_TYPE(GVec4);
     101           0 :     ADD_TYPE(DVec);
     102           0 :     ADD_TYPE(IVec);
     103           0 :     ADD_TYPE(UVec);
     104           0 :     ADD_TYPE(BVec);
     105             : 
     106           0 :     ADD_TYPE(Sampler1D);
     107           0 :     ADD_TYPE(Sampler2D);
     108           0 :     ADD_TYPE(Sampler3D);
     109           0 :     ADD_TYPE(SamplerExternalOES);
     110           0 :     ADD_TYPE(SamplerCube);
     111           0 :     ADD_TYPE(Sampler2DRect);
     112           0 :     ADD_TYPE(Sampler1DArray);
     113           0 :     ADD_TYPE(Sampler2DArray);
     114           0 :     ADD_TYPE(SamplerCubeArray);
     115           0 :     ADD_TYPE(SamplerBuffer);
     116           0 :     ADD_TYPE(Sampler2DMS);
     117           0 :     ADD_TYPE(Sampler2DMSArray);
     118             : 
     119           0 :     ADD_TYPE(ISampler2D);
     120             : 
     121           0 :     ADD_TYPE(Image2D);
     122           0 :     ADD_TYPE(IImage2D);
     123             : 
     124           0 :     ADD_TYPE(SubpassInput);
     125           0 :     ADD_TYPE(SubpassInputMS);
     126             : 
     127           0 :     ADD_TYPE(GSampler1D);
     128           0 :     ADD_TYPE(GSampler2D);
     129           0 :     ADD_TYPE(GSampler3D);
     130           0 :     ADD_TYPE(GSamplerCube);
     131           0 :     ADD_TYPE(GSampler2DRect);
     132           0 :     ADD_TYPE(GSampler1DArray);
     133           0 :     ADD_TYPE(GSampler2DArray);
     134           0 :     ADD_TYPE(GSamplerCubeArray);
     135           0 :     ADD_TYPE(GSamplerBuffer);
     136           0 :     ADD_TYPE(GSampler2DMS);
     137           0 :     ADD_TYPE(GSampler2DMSArray);
     138             : 
     139           0 :     ADD_TYPE(Sampler1DShadow);
     140           0 :     ADD_TYPE(Sampler2DShadow);
     141           0 :     ADD_TYPE(SamplerCubeShadow);
     142           0 :     ADD_TYPE(Sampler2DRectShadow);
     143           0 :     ADD_TYPE(Sampler1DArrayShadow);
     144           0 :     ADD_TYPE(Sampler2DArrayShadow);
     145           0 :     ADD_TYPE(SamplerCubeArrayShadow);
     146           0 :     ADD_TYPE(GSampler2DArrayShadow);
     147           0 :     ADD_TYPE(GSamplerCubeArrayShadow);
     148             : 
     149           0 :     String skCapsName("sk_Caps");
     150           0 :     Variable* skCaps = new Variable(Position(), Modifiers(), skCapsName,
     151           0 :                                     *fContext.fSkCaps_Type, Variable::kGlobal_Storage);
     152           0 :     fIRGenerator->fSymbolTable->add(skCapsName, std::unique_ptr<Symbol>(skCaps));
     153             : 
     154             :     Modifiers::Flag ignored1;
     155           0 :     std::vector<std::unique_ptr<ProgramElement>> ignored2;
     156           0 :     this->internalConvertProgram(String(SKSL_INCLUDE), &ignored1, &ignored2);
     157           0 :     fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
     158           0 :     ASSERT(!fErrorCount);
     159           0 : }
     160             : 
     161           0 : Compiler::~Compiler() {
     162           0 :     delete fIRGenerator;
     163           0 : }
     164             : 
     165             : // add the definition created by assigning to the lvalue to the definition set
     166           0 : void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
     167             :                              DefinitionMap* definitions) {
     168           0 :     switch (lvalue->fKind) {
     169             :         case Expression::kVariableReference_Kind: {
     170           0 :             const Variable& var = ((VariableReference*) lvalue)->fVariable;
     171           0 :             if (var.fStorage == Variable::kLocal_Storage) {
     172           0 :                 (*definitions)[&var] = expr;
     173             :             }
     174           0 :             break;
     175             :         }
     176             :         case Expression::kSwizzle_Kind:
     177             :             // We consider the variable written to as long as at least some of its components have
     178             :             // been written to. This will lead to some false negatives (we won't catch it if you
     179             :             // write to foo.x and then read foo.y), but being stricter could lead to false positives
     180             :             // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
     181             :             // but since we pass foo as a whole it is flagged as an error) unless we perform a much
     182             :             // more complicated whole-program analysis. This is probably good enough.
     183           0 :             this->addDefinition(((Swizzle*) lvalue)->fBase.get(),
     184           0 :                                 (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
     185           0 :                                 definitions);
     186           0 :             break;
     187             :         case Expression::kIndex_Kind:
     188             :             // see comments in Swizzle
     189           0 :             this->addDefinition(((IndexExpression*) lvalue)->fBase.get(),
     190           0 :                                 (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
     191           0 :                                 definitions);
     192           0 :             break;
     193             :         case Expression::kFieldAccess_Kind:
     194             :             // see comments in Swizzle
     195           0 :             this->addDefinition(((FieldAccess*) lvalue)->fBase.get(),
     196           0 :                                 (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
     197           0 :                                 definitions);
     198           0 :             break;
     199             :         default:
     200             :             // not an lvalue, can't happen
     201           0 :             ASSERT(false);
     202             :     }
     203           0 : }
     204             : 
     205             : // add local variables defined by this node to the set
     206           0 : void Compiler::addDefinitions(const BasicBlock::Node& node,
     207             :                               DefinitionMap* definitions) {
     208           0 :     switch (node.fKind) {
     209             :         case BasicBlock::Node::kExpression_Kind: {
     210           0 :             ASSERT(node.fExpression);
     211           0 :             const Expression* expr = (Expression*) node.fExpression->get();
     212           0 :             switch (expr->fKind) {
     213             :                 case Expression::kBinary_Kind: {
     214           0 :                     BinaryExpression* b = (BinaryExpression*) expr;
     215           0 :                     if (b->fOperator == Token::EQ) {
     216           0 :                         this->addDefinition(b->fLeft.get(), &b->fRight, definitions);
     217           0 :                     } else if (Token::IsAssignment(b->fOperator)) {
     218             :                         this->addDefinition(
     219           0 :                                        b->fLeft.get(),
     220           0 :                                        (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
     221           0 :                                        definitions);
     222             : 
     223             :                     }
     224           0 :                     break;
     225             :                 }
     226             :                 case Expression::kPrefix_Kind: {
     227           0 :                     const PrefixExpression* p = (PrefixExpression*) expr;
     228           0 :                     if (p->fOperator == Token::MINUSMINUS || p->fOperator == Token::PLUSPLUS) {
     229             :                         this->addDefinition(
     230           0 :                                        p->fOperand.get(),
     231           0 :                                        (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
     232           0 :                                        definitions);
     233             :                     }
     234           0 :                     break;
     235             :                 }
     236             :                 case Expression::kPostfix_Kind: {
     237           0 :                     const PostfixExpression* p = (PostfixExpression*) expr;
     238           0 :                     if (p->fOperator == Token::MINUSMINUS || p->fOperator == Token::PLUSPLUS) {
     239             :                         this->addDefinition(
     240           0 :                                        p->fOperand.get(),
     241           0 :                                        (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
     242           0 :                                        definitions);
     243             : 
     244             :                     }
     245           0 :                     break;
     246             :                 }
     247             :                 default:
     248           0 :                     break;
     249             :             }
     250           0 :             break;
     251             :         }
     252             :         case BasicBlock::Node::kStatement_Kind: {
     253           0 :             const Statement* stmt = (Statement*) node.fStatement;
     254           0 :             if (stmt->fKind == Statement::kVarDeclarations_Kind) {
     255           0 :                 VarDeclarationsStatement* vd = (VarDeclarationsStatement*) stmt;
     256           0 :                 for (VarDeclaration& decl : vd->fDeclaration->fVars) {
     257           0 :                     if (decl.fValue) {
     258           0 :                         (*definitions)[decl.fVar] = &decl.fValue;
     259             :                     }
     260             :                 }
     261             :             }
     262           0 :             break;
     263             :         }
     264             :     }
     265           0 : }
     266             : 
     267           0 : void Compiler::scanCFG(CFG* cfg, BlockId blockId, std::set<BlockId>* workList) {
     268           0 :     BasicBlock& block = cfg->fBlocks[blockId];
     269             : 
     270             :     // compute definitions after this block
     271           0 :     DefinitionMap after = block.fBefore;
     272           0 :     for (const BasicBlock::Node& n : block.fNodes) {
     273           0 :         this->addDefinitions(n, &after);
     274             :     }
     275             : 
     276             :     // propagate definitions to exits
     277           0 :     for (BlockId exitId : block.fExits) {
     278           0 :         BasicBlock& exit = cfg->fBlocks[exitId];
     279           0 :         for (const auto& pair : after) {
     280           0 :             std::unique_ptr<Expression>* e1 = pair.second;
     281           0 :             auto found = exit.fBefore.find(pair.first);
     282           0 :             if (found == exit.fBefore.end()) {
     283             :                 // exit has no definition for it, just copy it
     284           0 :                 workList->insert(exitId);
     285           0 :                 exit.fBefore[pair.first] = e1;
     286             :             } else {
     287             :                 // exit has a (possibly different) value already defined
     288           0 :                 std::unique_ptr<Expression>* e2 = exit.fBefore[pair.first];
     289           0 :                 if (e1 != e2) {
     290             :                     // definition has changed, merge and add exit block to worklist
     291           0 :                     workList->insert(exitId);
     292           0 :                     if (e1 && e2) {
     293           0 :                         exit.fBefore[pair.first] =
     294           0 :                                        (std::unique_ptr<Expression>*) &fContext.fDefined_Expression;
     295             :                     } else {
     296           0 :                         exit.fBefore[pair.first] = nullptr;
     297             :                     }
     298             :                 }
     299             :             }
     300             :         }
     301             :     }
     302           0 : }
     303             : 
     304             : // returns a map which maps all local variables in the function to null, indicating that their value
     305             : // is initially unknown
     306           0 : static DefinitionMap compute_start_state(const CFG& cfg) {
     307           0 :     DefinitionMap result;
     308           0 :     for (const auto& block : cfg.fBlocks) {
     309           0 :         for (const auto& node : block.fNodes) {
     310           0 :             if (node.fKind == BasicBlock::Node::kStatement_Kind) {
     311           0 :                 ASSERT(node.fStatement);
     312           0 :                 const Statement* s = node.fStatement;
     313           0 :                 if (s->fKind == Statement::kVarDeclarations_Kind) {
     314           0 :                     const VarDeclarationsStatement* vd = (const VarDeclarationsStatement*) s;
     315           0 :                     for (const VarDeclaration& decl : vd->fDeclaration->fVars) {
     316           0 :                         result[decl.fVar] = nullptr;
     317             :                     }
     318             :                 }
     319             :             }
     320             :         }
     321             :     }
     322           0 :     return result;
     323             : }
     324             : 
     325           0 : void Compiler::scanCFG(const FunctionDefinition& f) {
     326           0 :     CFG cfg = CFGGenerator().getCFG(f);
     327             : 
     328             :     // compute the data flow
     329           0 :     cfg.fBlocks[cfg.fStart].fBefore = compute_start_state(cfg);
     330           0 :     std::set<BlockId> workList;
     331           0 :     for (BlockId i = 0; i < cfg.fBlocks.size(); i++) {
     332           0 :         workList.insert(i);
     333             :     }
     334           0 :     while (workList.size()) {
     335           0 :         BlockId next = *workList.begin();
     336           0 :         workList.erase(workList.begin());
     337           0 :         this->scanCFG(&cfg, next, &workList);
     338             :     }
     339             : 
     340             :     // check for unreachable code
     341           0 :     for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
     342           0 :         if (i != cfg.fStart && !cfg.fBlocks[i].fEntrances.size() &&
     343           0 :             cfg.fBlocks[i].fNodes.size()) {
     344           0 :             Position p;
     345           0 :             switch (cfg.fBlocks[i].fNodes[0].fKind) {
     346             :                 case BasicBlock::Node::kStatement_Kind:
     347           0 :                     p = cfg.fBlocks[i].fNodes[0].fStatement->fPosition;
     348           0 :                     break;
     349             :                 case BasicBlock::Node::kExpression_Kind:
     350           0 :                     p = (*cfg.fBlocks[i].fNodes[0].fExpression)->fPosition;
     351           0 :                     break;
     352             :             }
     353           0 :             this->error(p, String("unreachable"));
     354             :         }
     355             :     }
     356           0 :     if (fErrorCount) {
     357           0 :         return;
     358             :     }
     359             : 
     360             :     // check for undefined variables, perform constant propagation
     361           0 :     for (BasicBlock& b : cfg.fBlocks) {
     362           0 :         DefinitionMap definitions = b.fBefore;
     363           0 :         for (BasicBlock::Node& n : b.fNodes) {
     364           0 :             if (n.fKind == BasicBlock::Node::kExpression_Kind) {
     365           0 :                 ASSERT(n.fExpression);
     366           0 :                 Expression* expr = n.fExpression->get();
     367           0 :                 if (n.fConstantPropagation) {
     368           0 :                     std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
     369           0 :                                                                                     definitions);
     370           0 :                     if (optimized) {
     371           0 :                         n.fExpression->reset(optimized.release());
     372           0 :                         expr = n.fExpression->get();
     373             :                     }
     374             :                 }
     375           0 :                 if (expr->fKind == Expression::kVariableReference_Kind) {
     376           0 :                     const Variable& var = ((VariableReference*) expr)->fVariable;
     377           0 :                     if (var.fStorage == Variable::kLocal_Storage &&
     378           0 :                         !definitions[&var]) {
     379             :                         this->error(expr->fPosition,
     380           0 :                                     "'" + var.fName + "' has not been assigned");
     381             :                     }
     382             :                 }
     383             :             }
     384           0 :             this->addDefinitions(n, &definitions);
     385             :         }
     386             :     }
     387             : 
     388             :     // check for missing return
     389           0 :     if (f.fDeclaration.fReturnType != *fContext.fVoid_Type) {
     390           0 :         if (cfg.fBlocks[cfg.fExit].fEntrances.size()) {
     391           0 :             this->error(f.fPosition, String("function can exit without returning a value"));
     392             :         }
     393             :     }
     394             : }
     395             : 
     396           0 : void Compiler::internalConvertProgram(String text,
     397             :                                       Modifiers::Flag* defaultPrecision,
     398             :                                       std::vector<std::unique_ptr<ProgramElement>>* result) {
     399           0 :     Parser parser(text, *fTypes, *this);
     400           0 :     std::vector<std::unique_ptr<ASTDeclaration>> parsed = parser.file();
     401           0 :     if (fErrorCount) {
     402           0 :         return;
     403             :     }
     404           0 :     *defaultPrecision = Modifiers::kHighp_Flag;
     405           0 :     for (size_t i = 0; i < parsed.size(); i++) {
     406           0 :         ASTDeclaration& decl = *parsed[i];
     407           0 :         switch (decl.fKind) {
     408             :             case ASTDeclaration::kVar_Kind: {
     409           0 :                 std::unique_ptr<VarDeclarations> s = fIRGenerator->convertVarDeclarations(
     410             :                                                                          (ASTVarDeclarations&) decl,
     411           0 :                                                                          Variable::kGlobal_Storage);
     412           0 :                 if (s) {
     413           0 :                     result->push_back(std::move(s));
     414             :                 }
     415           0 :                 break;
     416             :             }
     417             :             case ASTDeclaration::kFunction_Kind: {
     418           0 :                 std::unique_ptr<FunctionDefinition> f = fIRGenerator->convertFunction(
     419           0 :                                                                                (ASTFunction&) decl);
     420           0 :                 if (!fErrorCount && f) {
     421           0 :                     this->scanCFG(*f);
     422           0 :                     result->push_back(std::move(f));
     423             :                 }
     424           0 :                 break;
     425             :             }
     426             :             case ASTDeclaration::kModifiers_Kind: {
     427           0 :                 std::unique_ptr<ModifiersDeclaration> f = fIRGenerator->convertModifiersDeclaration(
     428           0 :                                                                    (ASTModifiersDeclaration&) decl);
     429           0 :                 if (f) {
     430           0 :                     result->push_back(std::move(f));
     431             :                 }
     432           0 :                 break;
     433             :             }
     434             :             case ASTDeclaration::kInterfaceBlock_Kind: {
     435           0 :                 std::unique_ptr<InterfaceBlock> i = fIRGenerator->convertInterfaceBlock(
     436           0 :                                                                          (ASTInterfaceBlock&) decl);
     437           0 :                 if (i) {
     438           0 :                     result->push_back(std::move(i));
     439             :                 }
     440           0 :                 break;
     441             :             }
     442             :             case ASTDeclaration::kExtension_Kind: {
     443           0 :                 std::unique_ptr<Extension> e = fIRGenerator->convertExtension((ASTExtension&) decl);
     444           0 :                 if (e) {
     445           0 :                     result->push_back(std::move(e));
     446             :                 }
     447           0 :                 break;
     448             :             }
     449             :             case ASTDeclaration::kPrecision_Kind: {
     450           0 :                 *defaultPrecision = ((ASTPrecision&) decl).fPrecision;
     451           0 :                 break;
     452             :             }
     453             :             default:
     454           0 :                 ABORT("unsupported declaration: %s\n", decl.description().c_str());
     455             :         }
     456             :     }
     457             : }
     458             : 
     459           0 : std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, String text,
     460             :                                                   const Program::Settings& settings) {
     461           0 :     fErrorText = "";
     462           0 :     fErrorCount = 0;
     463           0 :     fIRGenerator->start(&settings);
     464           0 :     std::vector<std::unique_ptr<ProgramElement>> elements;
     465             :     Modifiers::Flag ignored;
     466           0 :     switch (kind) {
     467             :         case Program::kVertex_Kind:
     468           0 :             this->internalConvertProgram(String(SKSL_VERT_INCLUDE), &ignored, &elements);
     469           0 :             break;
     470             :         case Program::kFragment_Kind:
     471           0 :             this->internalConvertProgram(String(SKSL_FRAG_INCLUDE), &ignored, &elements);
     472           0 :             break;
     473             :         case Program::kGeometry_Kind:
     474           0 :             this->internalConvertProgram(String(SKSL_GEOM_INCLUDE), &ignored, &elements);
     475           0 :             break;
     476             :     }
     477           0 :     fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
     478             :     Modifiers::Flag defaultPrecision;
     479           0 :     this->internalConvertProgram(text, &defaultPrecision, &elements);
     480             :     auto result = std::unique_ptr<Program>(new Program(kind, settings, defaultPrecision, &fContext,
     481           0 :                                                        std::move(elements),
     482           0 :                                                        fIRGenerator->fSymbolTable,
     483           0 :                                                        fIRGenerator->fInputs));
     484           0 :     fIRGenerator->finish();
     485           0 :     this->writeErrorCount();
     486           0 :     if (fErrorCount) {
     487           0 :         return nullptr;
     488             :     }
     489           0 :     return result;
     490             : }
     491             : 
     492           0 : bool Compiler::toSPIRV(const Program& program, OutputStream& out) {
     493             : #ifdef SK_ENABLE_SPIRV_VALIDATION
     494             :     StringStream buffer;
     495             :     SPIRVCodeGenerator cg(&fContext, &program, this, &buffer);
     496             :     bool result = cg.generateCode();
     497             :     if (result) {
     498             :         spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
     499             :         ASSERT(0 == buffer.size() % 4);
     500             :         auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
     501             :             SkDebugf("SPIR-V validation error: %s\n", m);
     502             :         };
     503             :         tools.SetMessageConsumer(dumpmsg);
     504             :         // Verify that the SPIR-V we produced is valid. If this assert fails, check the logs prior
     505             :         // to the failure to see the validation errors.
     506             :         ASSERT_RESULT(tools.Validate((const uint32_t*) buffer.data(), buffer.size() / 4));
     507             :         out.write(buffer.data(), buffer.size());
     508             :     }
     509             : #else
     510           0 :     SPIRVCodeGenerator cg(&fContext, &program, this, &out);
     511           0 :     bool result = cg.generateCode();
     512             : #endif
     513           0 :     this->writeErrorCount();
     514           0 :     return result;
     515             : }
     516             : 
     517           0 : bool Compiler::toSPIRV(const Program& program, String* out) {
     518           0 :     StringStream buffer;
     519           0 :     bool result = this->toSPIRV(program, buffer);
     520           0 :     if (result) {
     521           0 :         *out = String(buffer.data(), buffer.size());
     522             :     }
     523           0 :     return result;
     524             : }
     525             : 
     526           0 : bool Compiler::toGLSL(const Program& program, OutputStream& out) {
     527           0 :     GLSLCodeGenerator cg(&fContext, &program, this, &out);
     528           0 :     bool result = cg.generateCode();
     529           0 :     this->writeErrorCount();
     530           0 :     return result;
     531             : }
     532             : 
     533           0 : bool Compiler::toGLSL(const Program& program, String* out) {
     534           0 :     StringStream buffer;
     535           0 :     bool result = this->toGLSL(program, buffer);
     536           0 :     if (result) {
     537           0 :         *out = String(buffer.data(), buffer.size());
     538             :     }
     539           0 :     return result;
     540             : }
     541             : 
     542             : 
     543           0 : void Compiler::error(Position position, String msg) {
     544           0 :     fErrorCount++;
     545           0 :     fErrorText += "error: " + position.description() + ": " + msg.c_str() + "\n";
     546           0 : }
     547             : 
     548           0 : String Compiler::errorText() {
     549           0 :     String result = fErrorText;
     550           0 :     return result;
     551             : }
     552             : 
     553           0 : void Compiler::writeErrorCount() {
     554           0 :     if (fErrorCount) {
     555           0 :         fErrorText += to_string(fErrorCount) + " error";
     556           0 :         if (fErrorCount > 1) {
     557           0 :             fErrorText += "s";
     558             :         }
     559           0 :         fErrorText += "\n";
     560             :     }
     561           0 : }
     562             : 
     563             : } // namespace

Generated by: LCOV version 1.13