SkSL include files are now stored in a binary format
This speeds up compiler construction, because we no longer have to parse
and process a bunch of SkSL source code during startup.
Change-Id: I6d6bd9b5ce78b1661be691708ab84bf399c6df8b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/305717
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 6adc803..5342d69 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -15,6 +15,7 @@
#include "src/sksl/SkSLIRGenerator.h"
#include "src/sksl/SkSLMetalCodeGenerator.h"
#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
+#include "src/sksl/SkSLRehydrator.h"
#include "src/sksl/SkSLSPIRVCodeGenerator.h"
#include "src/sksl/SkSLSPIRVtoHLSL.h"
#include "src/sksl/ir/SkSLEnum.h"
@@ -38,42 +39,43 @@
#include "spirv-tools/libspirv.hpp"
#endif
-// include the built-in shader symbols as static strings
+// If true, we use a compact binary IR representation of the core include files; otherwise we parse
+// the actual source code for the include files at runtime. The main reason you would need to change
+// this is to make format changes easier: set it to 0, change the encoder and decoder as needed,
+// build Skia to regenerate the encoded files, then set this back to 1 to actually use the
+// newly-generated files.
+#define REHYDRATE 1
-#define STRINGIFY(x) #x
+#if REHYDRATE
+
+#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
+#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
+#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
+#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
+#include "src/sksl/generated/sksl_interp.dehydrated.sksl"
+#include "src/sksl/generated/sksl_pipeline.dehydrated.sksl"
+#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
+
+#else
+
+#warning SkSL rehydrator is disabled
static const char* SKSL_GPU_INCLUDE =
-#include "sksl_gpu.inc"
-;
-
-static const char* SKSL_BLEND_INCLUDE =
-#include "sksl_blend.inc"
-;
-
+#include "src/sksl/generated/sksl_gpu.c.inc"
static const char* SKSL_INTERP_INCLUDE =
-#include "sksl_interp.inc"
-;
-
+#include "src/sksl/generated/sksl_interp.c.inc"
static const char* SKSL_VERT_INCLUDE =
-#include "sksl_vert.inc"
-;
-
+#include "src/sksl/generated/sksl_vert.c.inc"
static const char* SKSL_FRAG_INCLUDE =
-#include "sksl_frag.inc"
-;
-
+#include "src/sksl/generated/sksl_frag.c.inc"
static const char* SKSL_GEOM_INCLUDE =
-#include "sksl_geom.inc"
-;
-
+#include "src/sksl/generated/sksl_geom.c.inc"
static const char* SKSL_FP_INCLUDE =
-#include "sksl_enums.inc"
-#include "sksl_fp.inc"
-;
-
+#include "src/sksl/generated/sksl_fp.c.inc"
static const char* SKSL_PIPELINE_INCLUDE =
-#include "sksl_pipeline.inc"
-;
+#include "src/sksl/generated/sksl_pipeline.c.inc"
+
+#endif
namespace SkSL {
@@ -85,7 +87,7 @@
case ProgramElement::kFunction_Kind: {
FunctionDefinition& f = (FunctionDefinition&) *element;
SkASSERT(f.fDeclaration.fBuiltin);
- String key = f.fDeclaration.declaration();
+ String key = f.fDeclaration.description();
SkASSERT(target->find(key) == target->end());
(*target)[key] = std::make_pair(std::move(element), false);
iter = src->erase(iter);
@@ -106,17 +108,14 @@
}
}
-
Compiler::Compiler(Flags flags)
: fFlags(flags)
, fContext(new Context())
, fErrorCount(0) {
- auto types = std::shared_ptr<SymbolTable>(new SymbolTable(this));
- auto symbols = std::shared_ptr<SymbolTable>(new SymbolTable(types, this));
+ auto symbols = std::shared_ptr<SymbolTable>(new SymbolTable(this));
fIRGenerator = new IRGenerator(fContext.get(), symbols, *this);
- fTypes = types;
- #define ADD_TYPE(t) types->addWithoutOwnership(fContext->f ## t ## _Type->fName, \
- fContext->f ## t ## _Type.get())
+ #define ADD_TYPE(t) symbols->addWithoutOwnership(fContext->f ## t ## _Type->fName, \
+ fContext->f ## t ## _Type.get())
ADD_TYPE(Void);
ADD_TYPE(Float);
ADD_TYPE(Float2);
@@ -239,7 +238,7 @@
ADD_TYPE(Texture2D);
StringFragment fpAliasName("shader");
- fTypes->addWithoutOwnership(fpAliasName, fContext->fFragmentProcessor_Type.get());
+ symbols->addWithoutOwnership(fpAliasName, fContext->fFragmentProcessor_Type.get());
StringFragment skCapsName("sk_Caps");
Variable* skCaps = new Variable(-1, Modifiers(), skCapsName,
@@ -253,12 +252,10 @@
fIRGenerator->fIntrinsics = &fGPUIntrinsics;
std::vector<std::unique_ptr<ProgramElement>> gpuIntrinsics;
+ std::vector<std::unique_ptr<ProgramElement>> interpIntrinsics;
+#if !REHYDRATE
this->processIncludeFile(Program::kFragment_Kind, SKSL_GPU_INCLUDE, strlen(SKSL_GPU_INCLUDE),
symbols, &gpuIntrinsics, &fGpuSymbolTable);
- this->processIncludeFile(Program::kFragment_Kind, SKSL_BLEND_INCLUDE,
- strlen(SKSL_BLEND_INCLUDE), std::move(fGpuSymbolTable), &gpuIntrinsics,
- &fGpuSymbolTable);
- grab_intrinsics(&gpuIntrinsics, &fGPUIntrinsics);
// need to hang on to the source so that FunctionDefinition.fSource pointers in this file
// remain valid
fGpuIncludeSource = std::move(fIRGenerator->fFile);
@@ -266,15 +263,27 @@
fGpuSymbolTable, &fVertexInclude, &fVertexSymbolTable);
this->processIncludeFile(Program::kFragment_Kind, SKSL_FRAG_INCLUDE, strlen(SKSL_FRAG_INCLUDE),
fGpuSymbolTable, &fFragmentInclude, &fFragmentSymbolTable);
- this->processIncludeFile(Program::kGeometry_Kind, SKSL_GEOM_INCLUDE, strlen(SKSL_GEOM_INCLUDE),
- fGpuSymbolTable, &fGeometryInclude, &fGeometrySymbolTable);
- this->processIncludeFile(Program::kPipelineStage_Kind, SKSL_PIPELINE_INCLUDE,
- strlen(SKSL_PIPELINE_INCLUDE), fGpuSymbolTable, &fPipelineInclude,
- &fPipelineSymbolTable);
- std::vector<std::unique_ptr<ProgramElement>> interpIntrinsics;
- this->processIncludeFile(Program::kGeneric_Kind, SKSL_INTERP_INCLUDE,
- strlen(SKSL_INTERP_INCLUDE), symbols, &fInterpreterInclude,
- &fInterpreterSymbolTable);
+#else
+ {
+ Rehydrator rehydrator(fContext.get(), symbols, this, SKSL_INCLUDE_sksl_gpu,
+ SKSL_INCLUDE_sksl_gpu_LENGTH);
+ fGpuSymbolTable = rehydrator.symbolTable();
+ gpuIntrinsics = rehydrator.elements();
+ }
+ {
+ Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_vert,
+ SKSL_INCLUDE_sksl_vert_LENGTH);
+ fVertexSymbolTable = rehydrator.symbolTable();
+ fVertexInclude = rehydrator.elements();
+ }
+ {
+ Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_frag,
+ SKSL_INCLUDE_sksl_frag_LENGTH);
+ fFragmentSymbolTable = rehydrator.symbolTable();
+ fFragmentInclude = rehydrator.elements();
+ }
+#endif
+ grab_intrinsics(&gpuIntrinsics, &fGPUIntrinsics);
grab_intrinsics(&interpIntrinsics, &fInterpreterIntrinsics);
}
@@ -282,6 +291,63 @@
delete fIRGenerator;
}
+void Compiler::loadGeometryIntrinsics() {
+ if (fGeometrySymbolTable) {
+ return;
+ }
+ #if REHYDRATE
+ {
+ Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_geom,
+ SKSL_INCLUDE_sksl_geom_LENGTH);
+ fGeometrySymbolTable = rehydrator.symbolTable();
+ fGeometryInclude = rehydrator.elements();
+ }
+ #else
+ this->processIncludeFile(Program::kGeometry_Kind, SKSL_GEOM_INCLUDE,
+ strlen(SKSL_GEOM_INCLUDE), fGpuSymbolTable, &fGeometryInclude,
+ &fGeometrySymbolTable);
+ #endif
+}
+
+void Compiler::loadPipelineIntrinsics() {
+ if (fPipelineSymbolTable) {
+ return;
+ }
+ #if REHYDRATE
+ {
+ Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this,
+ SKSL_INCLUDE_sksl_pipeline,
+ SKSL_INCLUDE_sksl_pipeline_LENGTH);
+ fPipelineSymbolTable = rehydrator.symbolTable();
+ fPipelineInclude = rehydrator.elements();
+ }
+ #else
+ this->processIncludeFile(Program::kPipelineStage_Kind, SKSL_PIPELINE_INCLUDE,
+ strlen(SKSL_PIPELINE_INCLUDE), fGpuSymbolTable, &fPipelineInclude,
+ &fPipelineSymbolTable);
+ #endif
+}
+
+void Compiler::loadInterpreterIntrinsics() {
+ if (fInterpreterSymbolTable) {
+ return;
+ }
+ this->loadPipelineIntrinsics();
+ #if REHYDRATE
+ {
+ Rehydrator rehydrator(fContext.get(), fPipelineSymbolTable, this,
+ SKSL_INCLUDE_sksl_interp,
+ SKSL_INCLUDE_sksl_interp_LENGTH);
+ fInterpreterSymbolTable = rehydrator.symbolTable();
+ fInterpreterInclude = rehydrator.elements();
+ }
+ #else
+ this->processIncludeFile(Program::kGeneric_Kind, SKSL_INTERP_INCLUDE,
+ strlen(SKSL_INTERP_INCLUDE), fIRGenerator->fSymbolTable,
+ &fInterpreterInclude, &fInterpreterSymbolTable);
+ #endif
+}
+
void Compiler::processIncludeFile(Program::Kind kind, const char* src, size_t length,
std::shared_ptr<SymbolTable> base,
std::vector<std::unique_ptr<ProgramElement>>* outElements,
@@ -290,24 +356,30 @@
String source(src, length);
fSource = &source;
#endif
- fIRGenerator->fSymbolTable = std::move(base);
+ std::shared_ptr<SymbolTable> old = fIRGenerator->fSymbolTable;
+ if (base) {
+ fIRGenerator->fSymbolTable = std::move(base);
+ }
Program::Settings settings;
#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
GrContextOptions opts;
GrShaderCaps caps(opts);
settings.fCaps = ∩︀
#endif
- fIRGenerator->start(&settings, nullptr);
- fIRGenerator->convertProgram(kind, src, length, *fTypes, outElements);
+ SkASSERT(fIRGenerator->fCanInline);
+ fIRGenerator->fCanInline = false;
+ fIRGenerator->start(&settings, nullptr, true);
+ fIRGenerator->convertProgram(kind, src, length, outElements);
+ fIRGenerator->fCanInline = true;
if (this->fErrorCount) {
printf("Unexpected errors: %s\n", this->fErrorText.c_str());
}
SkASSERT(!fErrorCount);
- fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
*outSymbolTable = fIRGenerator->fSymbolTable;
#ifdef SK_DEBUG
fSource = nullptr;
#endif
+ fIRGenerator->fSymbolTable = std::move(old);
}
// add the definition created by assigning to the lvalue to the definition set
@@ -1459,7 +1531,7 @@
fIRGenerator->fRootSymbolTable->addWithoutOwnership(value->fName, value);
}
-Symbol* Compiler::takeOwnership(std::unique_ptr<Symbol> symbol) {
+const Symbol* Compiler::takeOwnership(std::unique_ptr<const Symbol> symbol) {
return fIRGenerator->fRootSymbolTable->takeOwnership(std::move(symbol));
}
@@ -1483,41 +1555,53 @@
fIRGenerator->start(&settings, inherited);
break;
case Program::kGeometry_Kind:
+ this->loadGeometryIntrinsics();
inherited = &fGeometryInclude;
fIRGenerator->fSymbolTable = fGeometrySymbolTable;
fIRGenerator->fIntrinsics = &fGPUIntrinsics;
fIRGenerator->start(&settings, inherited);
break;
case Program::kFragmentProcessor_Kind:
+#if REHYDRATE
+ {
+ Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this,
+ SKSL_INCLUDE_sksl_fp,
+ SKSL_INCLUDE_sksl_fp_LENGTH);
+ fFPSymbolTable = rehydrator.symbolTable();
+ fFPInclude = rehydrator.elements();
+ }
+ inherited = &fFPInclude;
+ fIRGenerator->fSymbolTable = fFPSymbolTable;
+ fIRGenerator->fIntrinsics = &fGPUIntrinsics;
+ fIRGenerator->start(&settings, inherited);
+ break;
+#else
inherited = nullptr;
fIRGenerator->fSymbolTable = fGpuSymbolTable;
- fIRGenerator->start(&settings, nullptr);
+ fIRGenerator->start(&settings, nullptr, true);
fIRGenerator->fIntrinsics = &fGPUIntrinsics;
- fIRGenerator->convertProgram(kind, SKSL_FP_INCLUDE, strlen(SKSL_FP_INCLUDE), *fTypes,
- &elements);
- fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
+ fIRGenerator->convertProgram(kind, SKSL_FP_INCLUDE, strlen(SKSL_FP_INCLUDE), &elements);
+ fIRGenerator->fIsBuiltinCode = false;
break;
+#endif
case Program::kPipelineStage_Kind:
+ this->loadPipelineIntrinsics();
inherited = &fPipelineInclude;
fIRGenerator->fSymbolTable = fPipelineSymbolTable;
fIRGenerator->fIntrinsics = &fGPUIntrinsics;
fIRGenerator->start(&settings, inherited);
break;
case Program::kGeneric_Kind:
+ this->loadInterpreterIntrinsics();
inherited = &fInterpreterInclude;
fIRGenerator->fSymbolTable = fInterpreterSymbolTable;
fIRGenerator->fIntrinsics = &fInterpreterIntrinsics;
fIRGenerator->start(&settings, inherited);
break;
}
- for (auto& element : elements) {
- if (element->fKind == ProgramElement::kEnum_Kind) {
- ((Enum&) *element).fBuiltin = true;
- }
- }
std::unique_ptr<String> textPtr(new String(std::move(text)));
fSource = textPtr.get();
- fIRGenerator->convertProgram(kind, textPtr->c_str(), textPtr->size(), *fTypes, &elements);
+ fIRGenerator->convertProgram(kind, textPtr->c_str(), textPtr->size(), &elements);
auto result = std::unique_ptr<Program>(new Program(kind,
std::move(textPtr),
settings,