Flutter Engine
The Flutter Engine
Classes | Public Types | Public Member Functions | Static Public Member Functions | Static Public Attributes | Friends | List of all members
SkSL::Compiler Class Reference

#include <SkSLCompiler.h>

Public Types

enum class  OverrideFlag { kDefault , kOff , kOn }
 

Public Member Functions

 Compiler ()
 
 ~Compiler ()
 
 Compiler (const Compiler &)=delete
 
Compileroperator= (const Compiler &)=delete
 
std::unique_ptr< ProgramconvertProgram (ProgramKind kind, std::string programSource, const ProgramSettings &settings)
 
void handleError (std::string_view msg, Position pos)
 
std::string errorText (bool showCount=true)
 
ErrorReportererrorReporter ()
 
int errorCount () const
 
void writeErrorCount ()
 
void resetErrors ()
 
Contextcontext () const
 
SymbolTableglobalSymbols ()
 
SymbolTablesymbolTable ()
 
std::unique_ptr< ModulecompileModule (ProgramKind kind, const char *moduleName, std::string moduleSource, const Module *parentModule, bool shouldInline)
 
bool optimizeModuleBeforeMinifying (ProgramKind kind, Module &module, bool shrinkSymbols)
 
const ModulemoduleForProgramKind (ProgramKind kind)
 
void runInliner (Program &program)
 

Static Public Member Functions

static std::array< float, 4 > GetRTAdjustVector (SkISize rtDims, bool flipY)
 
static std::array< float, 2 > GetRTFlipVector (int rtHeight, bool flipY)
 
static void EnableOptimizer (OverrideFlag flag)
 
static void EnableInliner (OverrideFlag flag)
 

Static Public Attributes

static constexpr const char FRAGCOLOR_NAME [] = "sk_FragColor"
 
static constexpr const char RTADJUST_NAME [] = "sk_RTAdjust"
 
static constexpr const char POSITION_NAME [] = "sk_Position"
 
static constexpr const char POISON_TAG [] = "<POISON>"
 

Friends

class Parser
 
class ThreadContext
 

Detailed Description

Main compiler entry point. The compiler parses the SkSL text directly into a tree of IRNodes, while performing basic optimizations such as constant-folding and dead-code elimination. Then the Program is passed into a CodeGenerator to produce compiled output.

See the README for information about SkSL.

Definition at line 69 of file SkSLCompiler.h.

Member Enumeration Documentation

◆ OverrideFlag

enum class SkSL::Compiler::OverrideFlag
strong

Allows optimization settings to be unilaterally overridden. This is meant to allow tools like Viewer or Nanobench to override the compiler's ProgramSettings and ShaderCaps for debugging.

Enumerator
kDefault 
kOff 
kOn 

Definition at line 116 of file SkSLCompiler.h.

116 {
117 kDefault,
118 kOff,
119 kOn,
120 };
@ kDefault

Constructor & Destructor Documentation

◆ Compiler() [1/2]

SkSL::Compiler::Compiler ( )

Definition at line 56 of file SkSLCompiler.cpp.

56 : fErrorReporter(this) {
57 auto moduleLoader = ModuleLoader::Get();
58 fContext = std::make_shared<Context>(moduleLoader.builtinTypes(), fErrorReporter);
59}
static ModuleLoader Get()

◆ ~Compiler()

SkSL::Compiler::~Compiler ( )

Definition at line 61 of file SkSLCompiler.cpp.

61{}

◆ Compiler() [2/2]

SkSL::Compiler::Compiler ( const Compiler )
delete

Member Function Documentation

◆ compileModule()

std::unique_ptr< Module > SkSL::Compiler::compileModule ( ProgramKind  kind,
const char *  moduleName,
std::string  moduleSource,
const Module parentModule,
bool  shouldInline 
)

Definition at line 175 of file SkSLCompiler.cpp.

179 {
180 SkASSERT(parentModule);
181 SkASSERT(!moduleSource.empty());
182 SkASSERT(this->errorCount() == 0);
183
184 // Wrap the program source in a pointer so it is guaranteed to be stable across moves.
185 auto sourcePtr = std::make_unique<std::string>(std::move(moduleSource));
186
187 // Compile the module from source, using default program settings (but no memory pooling).
188 ProgramSettings settings;
189 settings.fUseMemoryPool = false;
190 this->initializeContext(parentModule, kind, settings, *sourcePtr, /*isModule=*/true);
191
192 std::unique_ptr<Module> module = SkSL::Parser(this, settings, kind, std::move(sourcePtr))
193 .moduleInheritingFrom(parentModule);
194
195 this->cleanupContext();
196
197 if (this->errorCount() != 0) {
198 SkDebugf("Unexpected errors compiling %s:\n\n%s\n", moduleName, this->errorText().c_str());
199 return nullptr;
200 }
201 if (shouldInline) {
202 this->optimizeModuleAfterLoading(kind, *module);
203 }
204 return module;
205}
#define SkASSERT(cond)
Definition: SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
std::string errorText(bool showCount=true)
int errorCount() const
Definition: SkSLCompiler.h:134
std::unique_ptr< Module > moduleInheritingFrom(const Module *parentModule)
Definition: SkSLParser.cpp:418

◆ context()

Context & SkSL::Compiler::context ( ) const
inline

Definition at line 143 of file SkSLCompiler.h.

143 {
144 return *fContext;
145 }

◆ convertProgram()

std::unique_ptr< Program > SkSL::Compiler::convertProgram ( ProgramKind  kind,
std::string  programSource,
const ProgramSettings settings 
)

Definition at line 207 of file SkSLCompiler.cpp.

209 {
210 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::convertProgram");
211
212 // Wrap the program source in a pointer so it is guaranteed to be stable across moves.
213 auto sourcePtr = std::make_unique<std::string>(std::move(programSource));
214
215 // Load the module used by this ProgramKind.
216 const SkSL::Module* module = this->moduleForProgramKind(kind);
217
218 this->initializeContext(module, kind, settings, *sourcePtr, /*isModule=*/false);
219
220 std::unique_ptr<Program> program = SkSL::Parser(this, settings, kind, std::move(sourcePtr))
221 .programInheritingFrom(module);
222
223 this->cleanupContext();
224 return program;
225}
const Module * moduleForProgramKind(ProgramKind kind)
std::unique_ptr< Program > programInheritingFrom(const Module *module)
Definition: SkSLParser.cpp:407
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131

◆ EnableInliner()

static void SkSL::Compiler::EnableInliner ( OverrideFlag  flag)
inlinestatic

Definition at line 122 of file SkSLCompiler.h.

122{ sInliner = flag; }
FlutterSemanticsFlag flag

◆ EnableOptimizer()

static void SkSL::Compiler::EnableOptimizer ( OverrideFlag  flag)
inlinestatic

Definition at line 121 of file SkSLCompiler.h.

121{ sOptimizer = flag; }

◆ errorCount()

int SkSL::Compiler::errorCount ( ) const
inline

Definition at line 134 of file SkSLCompiler.h.

134{ return fContext->fErrors->errorCount(); }

◆ errorReporter()

ErrorReporter & SkSL::Compiler::errorReporter ( )
inline

Definition at line 132 of file SkSLCompiler.h.

132{ return *fContext->fErrors; }

◆ errorText()

std::string SkSL::Compiler::errorText ( bool  showCount = true)

Definition at line 512 of file SkSLCompiler.cpp.

512 {
513 if (showCount) {
514 this->writeErrorCount();
515 }
516 std::string result = fErrorText;
517 this->resetErrors();
518 return result;
519}
void writeErrorCount()
void resetErrors()
Definition: SkSLCompiler.h:138
GAsyncResult * result

◆ GetRTAdjustVector()

static std::array< float, 4 > SkSL::Compiler::GetRTAdjustVector ( SkISize  rtDims,
bool  flipY 
)
inlinestatic

Gets a float4 that adjusts the position from Skia device coords to normalized device coords, used to populate sk_RTAdjust. Assuming the transformed position, pos, is a homogeneous float4, the vec, v, is applied as such: float4((pos.xy * v.xz) + sk_Position.ww * v.yw, 0, pos.w);

Definition at line 82 of file SkSLCompiler.h.

82 {
83 std::array<float, 4> result;
84 result[0] = 2.f/rtDims.width();
85 result[2] = 2.f/rtDims.height();
86 result[1] = -1.f;
87 result[3] = -1.f;
88 if (flipY) {
89 result[2] = -result[2];
90 result[3] = -result[3];
91 }
92 return result;
93 }
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37

◆ GetRTFlipVector()

static std::array< float, 2 > SkSL::Compiler::GetRTFlipVector ( int  rtHeight,
bool  flipY 
)
inlinestatic

Uniform values used by the compiler to implement origin-neutral dFdy, sk_Clockwise, and sk_FragCoord.

Definition at line 99 of file SkSLCompiler.h.

99 {
100 std::array<float, 2> result;
101 result[0] = flipY ? rtHeight : 0.f;
102 result[1] = flipY ? -1.f : 1.f;
103 return result;
104 }

◆ globalSymbols()

SymbolTable * SkSL::Compiler::globalSymbols ( )
inline

Definition at line 147 of file SkSLCompiler.h.

147 {
148 return fGlobalSymbols.get();
149 }

◆ handleError()

void SkSL::Compiler::handleError ( std::string_view  msg,
Position  pos 
)

Definition at line 433 of file SkSLCompiler.cpp.

433 {
434 fErrorText += "error: ";
435 bool printLocation = false;
436 std::string_view src = this->errorReporter().source();
437 int line = -1;
438 if (pos.valid()) {
439 line = pos.line(src);
440 printLocation = pos.startOffset() < (int)src.length();
441 fErrorText += std::to_string(line) + ": ";
442 }
443 fErrorText += std::string(msg) + "\n";
444 if (printLocation) {
445 const int kMaxSurroundingChars = 100;
446
447 // Find the beginning of the line.
448 int lineStart = pos.startOffset();
449 while (lineStart > 0) {
450 if (src[lineStart - 1] == '\n') {
451 break;
452 }
453 --lineStart;
454 }
455
456 // We don't want to show more than 100 characters surrounding the error, so push the line
457 // start forward and add a leading ellipsis if there would be more than this.
458 std::string lineText;
459 std::string caretText;
460 if ((pos.startOffset() - lineStart) > kMaxSurroundingChars) {
461 lineStart = pos.startOffset() - kMaxSurroundingChars;
462 lineText = "...";
463 caretText = " ";
464 }
465
466 // Echo the line. Again, we don't want to show more than 100 characters after the end of the
467 // error, so truncate with a trailing ellipsis if needed.
468 const char* lineSuffix = "...\n";
469 int lineStop = pos.endOffset() + kMaxSurroundingChars;
470 if (lineStop >= (int)src.length()) {
471 lineStop = src.length() - 1;
472 lineSuffix = "\n"; // no ellipsis if we reach end-of-file
473 }
474 for (int i = lineStart; i < lineStop; ++i) {
475 char c = src[i];
476 if (c == '\n') {
477 lineSuffix = "\n"; // no ellipsis if we reach end-of-line
478 break;
479 }
480 switch (c) {
481 case '\t': lineText += " "; break;
482 case '\0': lineText += " "; break;
483 default: lineText += src[i]; break;
484 }
485 }
486 fErrorText += lineText + lineSuffix;
487
488 // print the carets underneath it, pointing to the range in question
489 for (int i = lineStart; i < (int)src.length(); i++) {
490 if (i >= pos.endOffset()) {
491 break;
492 }
493 switch (src[i]) {
494 case '\t':
495 caretText += (i >= pos.startOffset()) ? "^^^^" : " ";
496 break;
497 case '\n':
498 SkASSERT(i >= pos.startOffset());
499 // use an ellipsis if the error continues past the end of the line
500 caretText += (pos.endOffset() > i + 1) ? "..." : "^";
501 i = src.length();
502 break;
503 default:
504 caretText += (i >= pos.startOffset()) ? '^' : ' ';
505 break;
506 }
507 }
508 fErrorText += caretText + '\n';
509 }
510}
SkPoint pos
ErrorReporter & errorReporter()
Definition: SkSLCompiler.h:132
std::string_view source() const
static SkString to_string(int n)
Definition: nanobench.cpp:119

◆ moduleForProgramKind()

const Module * SkSL::Compiler::moduleForProgramKind ( ProgramKind  kind)

Definition at line 63 of file SkSLCompiler.cpp.

63 {
64 auto m = ModuleLoader::Get();
65 switch (kind) {
66 case ProgramKind::kFragment: return m.loadFragmentModule(this);
67 case ProgramKind::kVertex: return m.loadVertexModule(this);
68 case ProgramKind::kCompute: return m.loadComputeModule(this);
69 case ProgramKind::kGraphiteFragment: return m.loadGraphiteFragmentModule(this);
70 case ProgramKind::kGraphiteVertex: return m.loadGraphiteVertexModule(this);
71 case ProgramKind::kGraphiteFragmentES2: return m.loadGraphiteFragmentES2Module(this);
72 case ProgramKind::kGraphiteVertexES2: return m.loadGraphiteVertexES2Module(this);
73 case ProgramKind::kPrivateRuntimeShader: return m.loadPrivateRTShaderModule(this);
80 case ProgramKind::kMeshFragment: return m.loadPublicModule(this);
81 }
83}
#define SkUNREACHABLE
Definition: SkAssert.h:135

◆ operator=()

Compiler & SkSL::Compiler::operator= ( const Compiler )
delete

◆ optimizeModuleBeforeMinifying()

bool SkSL::Compiler::optimizeModuleBeforeMinifying ( ProgramKind  kind,
Module module,
bool  shrinkSymbols 
)

Optimize a module at minification time, before writing it out.

Definition at line 247 of file SkSLCompiler.cpp.

247 {
248 SkASSERT(this->errorCount() == 0);
249
250 auto m = SkSL::ModuleLoader::Get();
251
252 // Create a temporary program configuration with default settings.
253 ProgramConfig config;
254 config.fIsBuiltinCode = true;
255 config.fKind = kind;
256 AutoProgramConfig autoConfig(this->context(), &config);
257
258 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
259
260 if (shrinkSymbols) {
261 // Assign shorter names to symbols as long as it won't change the external meaning of the
262 // code.
263 Transform::RenamePrivateSymbols(this->context(), module, usage.get(), kind);
264
265 // Replace constant variables with their literal values to save space.
267 }
268
269 // Remove any unreachable code.
271
272 // We can only remove dead functions from runtime shaders, since runtime-effect helper functions
273 // are isolated from other parts of the program. In a module, an unreferenced function is
274 // intended to be called by the code that includes the module.
275 if (kind == ProgramKind::kRuntimeShader) {
276 while (Transform::EliminateDeadFunctions(this->context(), module, usage.get())) {
277 // Removing dead functions may cause more functions to become unreferenced. Try again.
278 }
279 }
280
281 while (Transform::EliminateDeadLocalVariables(this->context(), module, usage.get())) {
282 // Removing dead variables may cause more variables to become unreferenced. Try again.
283 }
284
285 // Runtime shaders are isolated from other parts of the program via name mangling, so we can
286 // eliminate public globals if they aren't referenced. Otherwise, we only eliminate private
287 // globals (prefixed with `$`) to avoid changing the meaning of the module code.
288 bool onlyPrivateGlobals = !ProgramConfig::IsRuntimeEffect(kind);
289 while (Transform::EliminateDeadGlobalVariables(this->context(), module, usage.get(),
290 onlyPrivateGlobals)) {
291 // Repeat until no changes occur.
292 }
293
294 // We eliminate empty statements to avoid runs of `;;;;;;` caused by the previous passes.
296
297 // We can eliminate `{}` around single-statement blocks.
299
300 // Make sure that program usage is still correct after the optimization pass is complete.
301 SkASSERT(*usage == *Analysis::GetUsage(module));
302
303 return this->errorCount() == 0;
304}
Context & context() const
Definition: SkSLCompiler.h:143
std::unique_ptr< ProgramUsage > GetUsage(const Program &program)
void ReplaceConstVarsWithLiterals(Module &module, ProgramUsage *usage)
bool EliminateDeadLocalVariables(const Context &context, Module &module, ProgramUsage *usage)
void EliminateUnreachableCode(Module &module, ProgramUsage *usage)
bool EliminateDeadFunctions(const Context &context, Module &module, ProgramUsage *usage)
void EliminateEmptyStatements(Module &module)
void EliminateUnnecessaryBraces(Module &module)
bool EliminateDeadGlobalVariables(const Context &context, Module &module, ProgramUsage *usage, bool onlyPrivateGlobals)
void RenamePrivateSymbols(Context &context, Module &module, ProgramUsage *usage, ProgramKind kind)
static void usage(char *argv0)
static bool IsRuntimeEffect(ProgramKind kind)

◆ resetErrors()

void SkSL::Compiler::resetErrors ( )
inline

Definition at line 138 of file SkSLCompiler.h.

138 {
139 fErrorText.clear();
141 }

◆ runInliner()

void SkSL::Compiler::runInliner ( Program program)

Run the inliner on a program which was compiled earlier (with inlining turned off).

Definition at line 370 of file SkSLCompiler.cpp.

370 {
371#ifndef SK_ENABLE_OPTIMIZE_SIZE
372 AutoProgramConfig autoConfig(this->context(), program.fConfig.get());
373 Inliner inliner(fContext.get());
374 this->runInliner(&inliner, program.fOwnedElements, program.fSymbols.get(),
375 program.fUsage.get());
376#endif
377}
void runInliner(Program &program)
ProgramConfig * fConfig
Definition: SkSLContext.h:33

◆ symbolTable()

SymbolTable * SkSL::Compiler::symbolTable ( )
inline

Definition at line 151 of file SkSLCompiler.h.

151 {
152 return fContext->fSymbolTable;
153 }

◆ writeErrorCount()

void SkSL::Compiler::writeErrorCount ( )

Definition at line 521 of file SkSLCompiler.cpp.

521 {
522 int count = this->errorCount();
523 if (count) {
524 fErrorText += std::to_string(count) +
525 ((count == 1) ? " error\n" : " errors\n");
526 }
527}
int count
Definition: FontMgrTest.cpp:50

Friends And Related Function Documentation

◆ Parser

friend class Parser
friend

Definition at line 230 of file SkSLCompiler.h.

◆ ThreadContext

friend class ThreadContext
friend

Definition at line 231 of file SkSLCompiler.h.

Member Data Documentation

◆ FRAGCOLOR_NAME

constexpr const char SkSL::Compiler::FRAGCOLOR_NAME[] = "sk_FragColor"
inlinestaticconstexpr

Definition at line 71 of file SkSLCompiler.h.

◆ POISON_TAG

constexpr const char SkSL::Compiler::POISON_TAG[] = "<POISON>"
inlinestaticconstexpr

Definition at line 74 of file SkSLCompiler.h.

◆ POSITION_NAME

constexpr const char SkSL::Compiler::POSITION_NAME[] = "sk_Position"
inlinestaticconstexpr

Definition at line 73 of file SkSLCompiler.h.

◆ RTADJUST_NAME

constexpr const char SkSL::Compiler::RTADJUST_NAME[] = "sk_RTAdjust"
inlinestaticconstexpr

Definition at line 72 of file SkSLCompiler.h.


The documentation for this class was generated from the following files: