/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SKSL_PROGRAM #define SKSL_PROGRAM #include #include #include "include/private/SkSLDefines.h" #include "include/private/SkSLModifiers.h" #include "include/private/SkSLProgramElement.h" #include "include/private/SkTHash.h" #include "src/sksl/SkSLAnalysis.h" #include "src/sksl/SkSLProgramSettings.h" #include "src/sksl/ir/SkSLBoolLiteral.h" #include "src/sksl/ir/SkSLExpression.h" #include "src/sksl/ir/SkSLFloatLiteral.h" #include "src/sksl/ir/SkSLIntLiteral.h" #include "src/sksl/ir/SkSLSymbolTable.h" #ifdef SK_VULKAN #include "src/gpu/vk/GrVkCaps.h" #endif // name of the render target height uniform #define SKSL_RTHEIGHT_NAME "u_skRTHeight" namespace SkSL { class Context; class Pool; /** * Side-car class holding mutable information about a Program's IR */ class ProgramUsage { public: struct VariableCounts { int fDeclared = 0; int fRead = 0; int fWrite = 0; }; VariableCounts get(const Variable&) const; bool isDead(const Variable&) const; int get(const FunctionDeclaration&) const; void replace(const Expression* oldExpr, const Expression* newExpr); void add(const Statement* stmt); void remove(const Expression* expr); void remove(const Statement* stmt); void remove(const ProgramElement& element); SkTHashMap fVariableCounts; SkTHashMap fCallCounts; }; /** * Represents a fully-digested program, ready for code generation. */ struct Program { using Settings = ProgramSettings; struct Inputs { // if true, this program requires the render target height uniform to be defined bool fRTHeight; // if true, this program must be recompiled if the flipY setting changes. If false, the // program will compile to the same code regardless of the flipY setting. bool fFlipY; void reset() { fRTHeight = false; fFlipY = false; } bool isEmpty() { return !fRTHeight && !fFlipY; } }; Program(std::unique_ptr source, std::unique_ptr config, std::shared_ptr context, std::vector> elements, std::vector sharedElements, std::unique_ptr modifiers, std::shared_ptr symbols, std::unique_ptr pool, Inputs inputs) : fSource(std::move(source)) , fConfig(std::move(config)) , fContext(context) , fSymbols(symbols) , fPool(std::move(pool)) , fInputs(inputs) , fElements(std::move(elements)) , fSharedElements(std::move(sharedElements)) , fModifiers(std::move(modifiers)) { fUsage = Analysis::GetUsage(*this); } ~Program() { // Some or all of the program elements are in the pool. To free them safely, we must attach // the pool before destroying any program elements. (Otherwise, we may accidentally call // delete on a pooled node.) if (fPool) { fPool->attachToThread(); } fElements.clear(); fContext.reset(); fSymbols.reset(); fModifiers.reset(); if (fPool) { fPool->detachFromThread(); } } class ElementsCollection { public: class iterator { public: const ProgramElement* operator*() { if (fShared != fSharedEnd) { return *fShared; } else { return fOwned->get(); } } iterator& operator++() { if (fShared != fSharedEnd) { ++fShared; } else { ++fOwned; } return *this; } bool operator==(const iterator& other) const { return fOwned == other.fOwned && fShared == other.fShared; } bool operator!=(const iterator& other) const { return !(*this == other); } private: using Owned = std::vector>::const_iterator; using Shared = std::vector::const_iterator; friend class ElementsCollection; iterator(Owned owned, Owned ownedEnd, Shared shared, Shared sharedEnd) : fOwned(owned), fOwnedEnd(ownedEnd), fShared(shared), fSharedEnd(sharedEnd) {} Owned fOwned; Owned fOwnedEnd; Shared fShared; Shared fSharedEnd; }; iterator begin() const { return iterator(fProgram.fElements.begin(), fProgram.fElements.end(), fProgram.fSharedElements.begin(), fProgram.fSharedElements.end()); } iterator end() const { return iterator(fProgram.fElements.end(), fProgram.fElements.end(), fProgram.fSharedElements.end(), fProgram.fSharedElements.end()); } private: friend struct Program; ElementsCollection(const Program& program) : fProgram(program) {} const Program& fProgram; }; // Can be used to iterate over *all* elements in this Program, both owned and shared (builtin). // The iterator's value type is 'const ProgramElement*', so it's clear that you *must not* // modify anything (as you might be mutating shared data). ElementsCollection elements() const { return ElementsCollection(*this); } // Can be used to iterate over *just* the elements owned by the Program, not shared builtins. // The iterator's value type is 'std::unique_ptr', and mutation is allowed. std::vector>& ownedElements() { return fElements; } const std::vector>& ownedElements() const { return fElements; } String description() const { String result; for (const auto& e : this->elements()) { result += e->description(); } return result; } const ProgramUsage* usage() const { return fUsage.get(); } std::unique_ptr fSource; std::unique_ptr fConfig; std::shared_ptr fContext; // it's important to keep fElements defined after (and thus destroyed before) fSymbols, // because destroying elements can modify reference counts in symbols std::shared_ptr fSymbols; std::unique_ptr fPool; Inputs fInputs; private: std::vector> fElements; std::vector fSharedElements; std::unique_ptr fModifiers; std::unique_ptr fUsage; friend class Compiler; friend class Inliner; // fUsage friend class SPIRVCodeGenerator; // fModifiers }; } // namespace SkSL #endif