blob: a61b416beb3d3c092a3a4e407a0256e9195b4a51 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
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 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stiles270cec22021-02-17 12:59:36 -050013#include "src/core/SkScopeExit.h"
Leon Scrogginsb66214e2021-02-11 17:14:18 -050014#include "src/core/SkTraceEvent.h"
John Stilesb92641c2020-08-31 18:09:01 -040015#include "src/sksl/SkSLAnalysis.h"
John Stilesf3a28db2021-03-10 23:00:47 -050016#include "src/sksl/SkSLConstantFolder.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/sksl/SkSLIRGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050018#include "src/sksl/SkSLOperators.h"
John Stiles270cec22021-02-17 12:59:36 -050019#include "src/sksl/SkSLProgramSettings.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040020#include "src/sksl/SkSLRehydrator.h"
John Stiles3738ef52021-04-13 10:41:57 -040021#include "src/sksl/codegen/SkSLCPPCodeGenerator.h"
John Stiles82ab3402021-04-13 17:13:03 -040022#include "src/sksl/codegen/SkSLDSLCPPCodeGenerator.h"
John Stiles3738ef52021-04-13 10:41:57 -040023#include "src/sksl/codegen/SkSLGLSLCodeGenerator.h"
24#include "src/sksl/codegen/SkSLHCodeGenerator.h"
25#include "src/sksl/codegen/SkSLMetalCodeGenerator.h"
26#include "src/sksl/codegen/SkSLSPIRVCodeGenerator.h"
27#include "src/sksl/codegen/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050028#include "src/sksl/ir/SkSLEnum.h"
29#include "src/sksl/ir/SkSLExpression.h"
30#include "src/sksl/ir/SkSLExpressionStatement.h"
31#include "src/sksl/ir/SkSLFunctionCall.h"
32#include "src/sksl/ir/SkSLIntLiteral.h"
33#include "src/sksl/ir/SkSLModifiersDeclaration.h"
34#include "src/sksl/ir/SkSLNop.h"
35#include "src/sksl/ir/SkSLSymbolTable.h"
36#include "src/sksl/ir/SkSLTernaryExpression.h"
37#include "src/sksl/ir/SkSLUnresolvedFunction.h"
38#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040039#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070040
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040041#include <fstream>
42
Ethan Nicholasa11035b2019-11-26 16:27:47 -050043#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
44#include "include/gpu/GrContextOptions.h"
45#include "src/gpu/GrShaderCaps.h"
46#endif
47
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040048#ifdef SK_ENABLE_SPIRV_VALIDATION
49#include "spirv-tools/libspirv.hpp"
50#endif
51
Brian Osman3d87e9f2020-10-08 11:50:22 -040052#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040053
Brian Osman3d87e9f2020-10-08 11:50:22 -040054// In standalone mode, we load the textual sksl source files. GN generates or copies these files
55// to the skslc executable directory. The "data" in this mode is just the filename.
56#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
57
58#else
59
60// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040061#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
62#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
63#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
64#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050065#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osmancbb60bd2021-04-12 09:49:20 -040066#include "src/sksl/generated/sksl_rt_colorfilter.dehydrated.sksl"
67#include "src/sksl/generated/sksl_rt_shader.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040068#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
69
Brian Osman3d87e9f2020-10-08 11:50:22 -040070#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
71 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040072
73#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040074
ethannicholasb3058bd2016-07-01 08:22:01 -070075namespace SkSL {
76
John Stiles7247b482021-03-08 10:40:35 -050077// These flags allow tools like Viewer or Nanobench to override the compiler's ProgramSettings.
John Stiles2ee4d7a2021-03-30 10:30:47 -040078Compiler::OverrideFlag Compiler::sOptimizer = OverrideFlag::kDefault;
79Compiler::OverrideFlag Compiler::sInliner = OverrideFlag::kDefault;
John Stiles8ef4d6c2021-03-05 16:01:45 -050080
John Stiles47c0a742021-02-09 09:30:35 -050081using RefKind = VariableReference::RefKind;
82
Brian Osman88cda172020-10-09 12:05:16 -040083class AutoSource {
84public:
85 AutoSource(Compiler* compiler, const String* source)
86 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
87 fCompiler->fSource = source;
88 }
89
90 ~AutoSource() { fCompiler->fSource = fOldSource; }
91
92 Compiler* fCompiler;
93 const String* fOldSource;
94};
95
John Stilesa935c3f2021-02-25 10:35:49 -050096class AutoProgramConfig {
97public:
98 AutoProgramConfig(std::shared_ptr<Context>& context, ProgramConfig* config)
99 : fContext(context.get()) {
100 SkASSERT(!fContext->fConfig);
101 fContext->fConfig = config;
102 }
103
104 ~AutoProgramConfig() {
105 fContext->fConfig = nullptr;
106 }
107
108 Context* fContext;
109};
110
John Stilesd6a5f4492021-02-11 15:46:11 -0500111Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesc1a98b82021-02-24 13:35:02 -0500112 : fContext(std::make_shared<Context>(/*errors=*/*this, *caps))
John Stiles7b920442020-12-17 10:43:41 -0500113 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -0500114 , fErrorCount(0) {
John Stilesc1a98b82021-02-24 13:35:02 -0500115 SkASSERT(caps);
John Stiles7c3515b2020-10-16 18:38:39 -0400116 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -0500117 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesc1a98b82021-02-24 13:35:02 -0500118 fIRGenerator = std::make_unique<IRGenerator>(fContext.get());
ethannicholasb3058bd2016-07-01 08:22:01 -0700119
John Stiles54e7c052021-01-11 14:22:36 -0500120#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700121
Brian Osmanb06301e2020-11-06 11:45:36 -0500122 const SkSL::Symbol* rootTypes[] = {
123 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500124
Brian Osmanb06301e2020-11-06 11:45:36 -0500125 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
126 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
127 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500128 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500129
Brian Osmanc0f2b642020-12-22 13:35:55 -0500130 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500131 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500132
Brian Osmanc63f4312020-12-23 11:44:14 -0500133 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700134
Brian Osman20fad322020-12-23 12:42:33 -0500135 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
136 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500137
Brian Osman14d00962021-04-02 17:04:35 -0400138 TYPE(ColorFilter),
139 TYPE(Shader),
Brian Osmanb06301e2020-11-06 11:45:36 -0500140 };
141
142 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500143 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
144 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
145 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
146 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
147 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
148
149 TYPE(GenUType), TYPE(UVec),
150 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
151
Brian Osmanc0f2b642020-12-22 13:35:55 -0500152 TYPE(Float2x3), TYPE(Float2x4),
153 TYPE(Float3x2), TYPE(Float3x4),
154 TYPE(Float4x2), TYPE(Float4x3),
155
Brian Osmanc63f4312020-12-23 11:44:14 -0500156 TYPE(Half2x3), TYPE(Half2x4),
157 TYPE(Half3x2), TYPE(Half3x4),
158 TYPE(Half4x2), TYPE(Half4x3),
159
Brian Osmanc0f2b642020-12-22 13:35:55 -0500160 TYPE(Mat), TYPE(HMat),
161
Brian Osmanb06301e2020-11-06 11:45:36 -0500162 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
163 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500164 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500165
166 TYPE(ISampler2D),
Brian Osmanb06301e2020-11-06 11:45:36 -0500167 TYPE(SubpassInput), TYPE(SubpassInputMS),
168
Brian Osmanb06301e2020-11-06 11:45:36 -0500169 TYPE(Sampler),
170 TYPE(Texture2D),
Brian Osman14d00962021-04-02 17:04:35 -0400171
172 TYPE(FragmentProcessor),
Brian Osmanb06301e2020-11-06 11:45:36 -0500173 };
174
175 for (const SkSL::Symbol* type : rootTypes) {
176 fRootSymbolTable->addWithoutOwnership(type);
177 }
178 for (const SkSL::Symbol* type : privateTypes) {
179 fPrivateSymbolTable->addWithoutOwnership(type);
180 }
181
182#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700183
Brian Osman3887a012020-09-30 13:22:27 -0400184 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
185 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500186 fPrivateSymbolTable->add(
187 std::make_unique<Variable>(/*offset=*/-1,
John Stilesf2872e62021-05-04 11:38:43 -0400188 fIRGenerator->modifiersPool().add(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500189 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500190 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500191 /*builtin=*/false,
192 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500193
Brian Osman3d87e9f2020-10-08 11:50:22 -0400194 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500195 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700196}
197
John Stilesdd13dba2020-10-29 10:45:34 -0400198Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700199
Brian Osman56269982020-11-20 12:38:07 -0500200const ParsedModule& Compiler::loadGPUModule() {
201 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500202 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500203 }
204 return fGPUModule;
205}
206
207const ParsedModule& Compiler::loadFragmentModule() {
208 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500209 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500210 this->loadGPUModule());
211 }
212 return fFragmentModule;
213}
214
215const ParsedModule& Compiler::loadVertexModule() {
216 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500217 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500218 this->loadGPUModule());
219 }
220 return fVertexModule;
221}
222
Brian Osman88cda172020-10-09 12:05:16 -0400223const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400224 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500225 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500226 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400227 }
Brian Osman88cda172020-10-09 12:05:16 -0400228 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400229}
230
Brian Osman88cda172020-10-09 12:05:16 -0400231const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400232 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500233 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500234 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400235 }
Brian Osman88cda172020-10-09 12:05:16 -0400236 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400237}
238
Brian Osmanb06301e2020-11-06 11:45:36 -0500239const ParsedModule& Compiler::loadPublicModule() {
240 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500241 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500242 }
243 return fPublicModule;
244}
245
Brian Osmancbb60bd2021-04-12 09:49:20 -0400246static void add_glsl_type_aliases(SkSL::SymbolTable* symbols, const SkSL::BuiltinTypes& types) {
247 // Add some aliases to the runtime effect modules so that it's friendlier, and more like GLSL
248 symbols->addAlias("vec2", types.fFloat2.get());
249 symbols->addAlias("vec3", types.fFloat3.get());
250 symbols->addAlias("vec4", types.fFloat4.get());
251
252 symbols->addAlias("ivec2", types.fInt2.get());
253 symbols->addAlias("ivec3", types.fInt3.get());
254 symbols->addAlias("ivec4", types.fInt4.get());
255
256 symbols->addAlias("bvec2", types.fBool2.get());
257 symbols->addAlias("bvec3", types.fBool3.get());
258 symbols->addAlias("bvec4", types.fBool4.get());
259
260 symbols->addAlias("mat2", types.fFloat2x2.get());
261 symbols->addAlias("mat3", types.fFloat3x3.get());
262 symbols->addAlias("mat4", types.fFloat4x4.get());
263}
264
Brian Osmancbb60bd2021-04-12 09:49:20 -0400265const ParsedModule& Compiler::loadRuntimeColorFilterModule() {
266 if (!fRuntimeColorFilterModule.fSymbols) {
267 fRuntimeColorFilterModule = this->parseModule(ProgramKind::kRuntimeColorFilter,
268 MODULE_DATA(rt_colorfilter),
269 this->loadPublicModule());
270 add_glsl_type_aliases(fRuntimeColorFilterModule.fSymbols.get(), fContext->fTypes);
271 }
272 return fRuntimeColorFilterModule;
273}
274
275const ParsedModule& Compiler::loadRuntimeShaderModule() {
276 if (!fRuntimeShaderModule.fSymbols) {
277 fRuntimeShaderModule = this->parseModule(
278 ProgramKind::kRuntimeShader, MODULE_DATA(rt_shader), this->loadPublicModule());
279 add_glsl_type_aliases(fRuntimeShaderModule.fSymbols.get(), fContext->fTypes);
280 }
281 return fRuntimeShaderModule;
282}
283
John Stilesdbd4e6f2021-02-16 13:29:15 -0500284const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400285 switch (kind) {
Brian Osmancbb60bd2021-04-12 09:49:20 -0400286 case ProgramKind::kVertex: return this->loadVertexModule(); break;
287 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
288 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
289 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
Brian Osmancbb60bd2021-04-12 09:49:20 -0400290 case ProgramKind::kRuntimeColorFilter: return this->loadRuntimeColorFilterModule(); break;
291 case ProgramKind::kRuntimeShader: return this->loadRuntimeShaderModule(); break;
292 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400293 }
294 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400295}
296
John Stilesdbd4e6f2021-02-16 13:29:15 -0500297LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400298 ModuleData data,
John Stilesa935c3f2021-02-25 10:35:49 -0500299 std::shared_ptr<SymbolTable> base,
300 bool dehydrate) {
301 if (dehydrate) {
302 // NOTE: This is a workaround. When dehydrating includes, skslc doesn't know which module
303 // it's preparing, nor what the correct base module is. We can't use 'Root', because many
304 // GPU intrinsics reference private types, like samplers or textures. Today, 'Private' does
305 // contain the union of all known types, so this is safe. If we ever have types that only
306 // exist in 'Public' (for example), this logic needs to be smarter (by choosing the correct
307 // base for the module we're compiling).
Brian Osmanb06301e2020-11-06 11:45:36 -0500308 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400309 }
John Stilesa935c3f2021-02-25 10:35:49 -0500310 SkASSERT(base);
311
312 // Built-in modules always use default program settings.
313 ProgramConfig config;
314 config.fKind = kind;
315 config.fSettings.fReplaceSettings = !dehydrate;
316 AutoProgramConfig autoConfig(fContext, &config);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400317
318#if defined(SKSL_STANDALONE)
319 SkASSERT(data.fPath);
320 std::ifstream in(data.fPath);
John Stilesd51c9792021-03-18 11:40:14 -0400321 String text{std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()};
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400322 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400323 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400324 abort();
325 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400326 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400327 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500328
Brian Osman88cda172020-10-09 12:05:16 -0400329 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500330 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
331 source->c_str(), source->length(),
332 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400333 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500334 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400335 if (this->fErrorCount) {
336 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400337 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400338 }
Brian Osman88cda172020-10-09 12:05:16 -0400339 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400340#else
341 SkASSERT(data.fData && (data.fSize != 0));
John Stilesf2872e62021-05-04 11:38:43 -0400342 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400343 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500344 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400345 fModifiers.push_back(fIRGenerator->releaseModifiers());
346#endif
347
348 return module;
349}
350
John Stilesdbd4e6f2021-02-16 13:29:15 -0500351ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500352 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500353 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400354
355 // For modules that just declare (but don't define) intrinsic functions, there will be no new
356 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500357 if (module.fElements.empty()) {
358 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400359 }
360
361 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
362
363 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
364 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500365 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400366 switch (element->kind()) {
367 case ProgramElement::Kind::kFunction: {
368 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400369 SkASSERT(f.declaration().isBuiltin());
370 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400371 break;
372 }
John Stiles569249b2020-11-03 12:18:22 -0500373 case ProgramElement::Kind::kFunctionPrototype: {
374 // These are already in the symbol table.
375 break;
376 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400377 case ProgramElement::Kind::kEnum: {
378 const Enum& e = element->as<Enum>();
379 SkASSERT(e.isBuiltin());
380 intrinsics->insertOrDie(e.typeName(), std::move(element));
381 break;
382 }
383 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400384 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
385 const Variable& var = global.declaration()->as<VarDeclaration>().var();
386 SkASSERT(var.isBuiltin());
387 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400388 break;
389 }
390 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400391 const Variable& var = element->as<InterfaceBlock>().variable();
392 SkASSERT(var.isBuiltin());
393 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400394 break;
395 }
396 default:
397 printf("Unsupported element: %s\n", element->description().c_str());
398 SkASSERT(false);
399 break;
400 }
401 }
402
Brian Osman0006ad02020-11-18 15:38:39 -0500403 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400404}
405
Brian Osman32d53552020-09-23 13:55:20 -0400406std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -0500407 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -0400408 String text,
409 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500410 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400411 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -0500412
John Stilesdbd4e6f2021-02-16 13:29:15 -0500413 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400414
Brian Osman0006ad02020-11-18 15:38:39 -0500415 // Loading and optimizing our base module might reset the inliner, so do that first,
416 // *then* configure the inliner with the settings for this program.
417 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
418
John Stiles270cec22021-02-17 12:59:36 -0500419 // Update our context to point to the program configuration for the duration of compilation.
420 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -0500421 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -0500422
John Stiles2ee4d7a2021-03-30 10:30:47 -0400423 // Honor our optimization-override flags.
424 switch (sOptimizer) {
425 case OverrideFlag::kDefault:
426 break;
427 case OverrideFlag::kOff:
428 config->fSettings.fOptimize = false;
429 break;
430 case OverrideFlag::kOn:
431 config->fSettings.fOptimize = true;
432 break;
433 }
434
435 switch (sInliner) {
436 case OverrideFlag::kDefault:
437 break;
438 case OverrideFlag::kOff:
439 config->fSettings.fInlineThreshold = 0;
440 break;
441 case OverrideFlag::kOn:
442 if (config->fSettings.fInlineThreshold == 0) {
443 config->fSettings.fInlineThreshold = kDefaultInlineThreshold;
444 }
445 break;
446 }
John Stiles7247b482021-03-08 10:40:35 -0500447
448 // Disable optimization settings that depend on a parent setting which has been disabled.
John Stiles7247b482021-03-08 10:40:35 -0500449 config->fSettings.fInlineThreshold *= (int)config->fSettings.fOptimize;
John Stiles0bfeae62021-03-11 09:09:42 -0500450 config->fSettings.fRemoveDeadFunctions &= config->fSettings.fOptimize;
451 config->fSettings.fRemoveDeadVariables &= config->fSettings.fOptimize;
John Stiles7247b482021-03-08 10:40:35 -0500452
ethannicholasb3058bd2016-07-01 08:22:01 -0700453 fErrorText = "";
454 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -0500455 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -0400456
457 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700458 std::unique_ptr<String> textPtr(new String(std::move(text)));
459 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -0400460
John Stiles5c7bb322020-10-22 11:09:15 -0400461 // Enable node pooling while converting and optimizing the program for a performance boost.
462 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -0500463 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -0500464 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -0500465 pool = Pool::Create();
466 pool->attachToThread();
467 }
John Stilesd1204642021-02-17 16:30:02 -0500468 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
469 textPtr->c_str(), textPtr->size(),
470 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -0500471 auto program = std::make_unique<Program>(std::move(textPtr),
472 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -0400473 fContext,
474 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -0400475 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -0400476 std::move(ir.fModifiers),
477 std::move(ir.fSymbolTable),
478 std::move(pool),
479 ir.fInputs);
480 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500481 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -0400482 // Do not return programs that failed to compile.
John Stiles7247b482021-03-08 10:40:35 -0500483 } else if (!this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -0400484 // Do not return programs that failed to optimize.
485 } else {
486 // We have a successful program!
487 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500488 }
John Stiles5c7bb322020-10-22 11:09:15 -0400489
Brian Osman28f702c2021-02-02 11:52:07 -0500490 if (program->fPool) {
491 program->fPool->detachFromThread();
492 }
John Stiles5c7bb322020-10-22 11:09:15 -0400493 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500494}
495
John Stilesbb1505f2021-02-12 09:17:53 -0500496void Compiler::verifyStaticTests(const Program& program) {
497 class StaticTestVerifier : public ProgramVisitor {
498 public:
499 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
500
501 using ProgramVisitor::visitProgramElement;
502
503 bool visitStatement(const Statement& stmt) override {
504 switch (stmt.kind()) {
505 case Statement::Kind::kIf:
506 if (stmt.as<IfStatement>().isStatic()) {
507 fReporter->error(stmt.fOffset, "static if has non-static test");
508 }
509 break;
510
511 case Statement::Kind::kSwitch:
512 if (stmt.as<SwitchStatement>().isStatic()) {
513 fReporter->error(stmt.fOffset, "static switch has non-static test");
514 }
515 break;
516
517 default:
518 break;
519 }
520 return INHERITED::visitStatement(stmt);
521 }
522
John Stiles59e34562021-02-12 16:56:39 -0500523 bool visitExpression(const Expression&) override {
524 // We aren't looking for anything inside an Expression, so skip them entirely.
525 return false;
526 }
527
John Stilesbb1505f2021-02-12 09:17:53 -0500528 private:
529 using INHERITED = ProgramVisitor;
530 ErrorReporter* fReporter;
531 };
532
533 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -0500534 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -0500535 return;
536 }
537
538 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
539 StaticTestVerifier visitor{this};
540 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
541 if (element->is<FunctionDefinition>()) {
542 visitor.visitProgramElement(*element);
543 }
544 }
545}
546
Brian Osman0006ad02020-11-18 15:38:39 -0500547bool Compiler::optimize(LoadedModule& module) {
548 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -0500549
John Stiles270cec22021-02-17 12:59:36 -0500550 // Create a temporary program configuration with default settings.
551 ProgramConfig config;
552 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -0500553 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -0500554
John Stilesd1204642021-02-17 16:30:02 -0500555 // Reset the Inliner.
556 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -0500557
558 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -0500559
560 while (fErrorCount == 0) {
Brian Osman0006ad02020-11-18 15:38:39 -0500561 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stilesf3a28db2021-03-10 23:00:47 -0500562 if (!fInliner.analyze(module.fElements, module.fSymbols, usage.get())) {
Brian Osman0006ad02020-11-18 15:38:39 -0500563 break;
564 }
565 }
566 return fErrorCount == 0;
567}
568
John Stiles0bfeae62021-03-11 09:09:42 -0500569bool Compiler::removeDeadFunctions(Program& program, ProgramUsage* usage) {
570 bool madeChanges = false;
571
572 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
573 auto isDeadFunction = [&](const ProgramElement* element) {
574 if (!element->is<FunctionDefinition>()) {
575 return false;
576 }
577 const FunctionDefinition& fn = element->as<FunctionDefinition>();
John Stilese8da4d22021-03-24 09:19:45 -0400578 if (fn.declaration().isMain() || usage->get(fn.declaration()) > 0) {
John Stiles0bfeae62021-03-11 09:09:42 -0500579 return false;
580 }
581 usage->remove(*element);
582 madeChanges = true;
583 return true;
584 };
585
586 program.fElements.erase(std::remove_if(program.fElements.begin(),
587 program.fElements.end(),
588 [&](const std::unique_ptr<ProgramElement>& element) {
589 return isDeadFunction(element.get());
590 }),
591 program.fElements.end());
592 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
593 program.fSharedElements.end(),
594 isDeadFunction),
595 program.fSharedElements.end());
596 }
597 return madeChanges;
598}
599
600bool Compiler::removeDeadGlobalVariables(Program& program, ProgramUsage* usage) {
601 bool madeChanges = false;
602
603 if (program.fConfig->fSettings.fRemoveDeadVariables) {
604 auto isDeadVariable = [&](const ProgramElement* element) {
605 if (!element->is<GlobalVarDeclaration>()) {
606 return false;
607 }
608 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
609 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
610 if (!usage->isDead(varDecl.var())) {
611 return false;
612 }
613 madeChanges = true;
614 return true;
615 };
616
617 program.fElements.erase(std::remove_if(program.fElements.begin(),
618 program.fElements.end(),
619 [&](const std::unique_ptr<ProgramElement>& element) {
620 return isDeadVariable(element.get());
621 }),
622 program.fElements.end());
623 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
624 program.fSharedElements.end(),
625 isDeadVariable),
626 program.fSharedElements.end());
627 }
628 return madeChanges;
629}
630
John Stiles26541872021-03-16 12:19:54 -0400631bool Compiler::removeDeadLocalVariables(Program& program, ProgramUsage* usage) {
632 class DeadLocalVariableEliminator : public ProgramWriter {
633 public:
634 DeadLocalVariableEliminator(const Context& context, ProgramUsage* usage)
635 : fContext(context)
636 , fUsage(usage) {}
637
638 using ProgramWriter::visitProgramElement;
639
640 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
641 // We don't need to look inside expressions at all.
642 return false;
643 }
644
645 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
646 if (stmt->is<VarDeclaration>()) {
647 VarDeclaration& varDecl = stmt->as<VarDeclaration>();
648 const Variable* var = &varDecl.var();
649 ProgramUsage::VariableCounts* counts = fUsage->fVariableCounts.find(var);
650 SkASSERT(counts);
651 SkASSERT(counts->fDeclared);
652 if (CanEliminate(var, *counts)) {
653 if (var->initialValue()) {
654 // The variable has an initial-value expression, which might have side
655 // effects. ExpressionStatement::Make will preserve side effects, but
656 // replaces pure expressions with Nop.
657 fUsage->remove(stmt.get());
658 stmt = ExpressionStatement::Make(fContext, std::move(varDecl.value()));
659 fUsage->add(stmt.get());
660 } else {
661 // The variable has no initial-value and can be cleanly eliminated.
662 fUsage->remove(stmt.get());
663 stmt = std::make_unique<Nop>();
664 }
665 fMadeChanges = true;
666 }
667 return false;
668 }
669 return INHERITED::visitStatementPtr(stmt);
670 }
671
672 static bool CanEliminate(const Variable* var, const ProgramUsage::VariableCounts& counts) {
673 if (!counts.fDeclared || counts.fRead || var->storage() != VariableStorage::kLocal) {
674 return false;
675 }
676 if (var->initialValue()) {
677 SkASSERT(counts.fWrite >= 1);
678 return counts.fWrite == 1;
679 } else {
680 return counts.fWrite == 0;
681 }
682 }
683
684 bool fMadeChanges = false;
685 const Context& fContext;
686 ProgramUsage* fUsage;
687
688 using INHERITED = ProgramWriter;
689 };
690
691 DeadLocalVariableEliminator visitor{*fContext, usage};
692
693 if (program.fConfig->fSettings.fRemoveDeadVariables) {
694 for (auto& [var, counts] : usage->fVariableCounts) {
695 if (DeadLocalVariableEliminator::CanEliminate(var, counts)) {
696 // This program contains at least one dead local variable.
697 // Scan the program for any dead local variables and eliminate them all.
698 for (std::unique_ptr<ProgramElement>& pe : program.ownedElements()) {
699 if (pe->is<FunctionDefinition>()) {
700 visitor.visitProgramElement(*pe);
701 }
702 }
703 break;
704 }
705 }
706 }
707
708 return visitor.fMadeChanges;
709}
710
Ethan Nicholas00543112018-07-31 09:44:36 -0400711bool Compiler::optimize(Program& program) {
John Stiles7247b482021-03-08 10:40:35 -0500712 // The optimizer only needs to run when it is enabled.
713 if (!program.fConfig->fSettings.fOptimize) {
714 return true;
715 }
716
Ethan Nicholas00543112018-07-31 09:44:36 -0400717 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -0400718 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -0400719
John Stilesb6664582021-03-19 09:46:00 -0400720 if (fErrorCount == 0) {
John Stiles87fc6572021-04-01 14:56:34 +0000721 // Run the inliner only once; it is expensive! Multiple passes can occasionally shake out
722 // more wins, but it's diminishing returns.
723 fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400724
John Stilesb6664582021-03-19 09:46:00 -0400725 while (this->removeDeadFunctions(program, usage)) {
726 // Removing dead functions may cause more functions to become unreferenced. Try again.
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400727 }
John Stilesb6664582021-03-19 09:46:00 -0400728 while (this->removeDeadLocalVariables(program, usage)) {
729 // Removing dead variables may cause more variables to become unreferenced. Try again.
730 }
731 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
732 this->removeDeadGlobalVariables(program, usage);
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500733 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400734 }
John Stilesbb1505f2021-02-12 09:17:53 -0500735
736 if (fErrorCount == 0) {
737 this->verifyStaticTests(program);
738 }
739
Ethan Nicholas00543112018-07-31 09:44:36 -0400740 return fErrorCount == 0;
741}
742
Brian Osmanfb32ddf2019-06-18 10:14:20 -0400743#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
744
Ethan Nicholas00543112018-07-31 09:44:36 -0400745bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400746 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toSPIRV");
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400747#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400748 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -0400749 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400750 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400751 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -0500752 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400753 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400754 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400755 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500756 String errors;
757 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
758 const char* m) {
759 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400760 };
761 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500762
763 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
764 // explaining the error. In standalone mode (skslc), we will send the message, plus the
765 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
766 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
767
768 if (!result) {
769#if defined(SKSL_STANDALONE)
770 // Convert the string-stream to a SPIR-V disassembly.
771 std::string disassembly;
772 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
773 errors.append(disassembly);
774 }
775 this->error(-1, errors);
776#else
777 SkDEBUGFAILF("%s", errors.c_str());
778#endif
779 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400780 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400781 }
782#else
Brian Osman88cda172020-10-09 12:05:16 -0400783 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400784 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500785 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400786#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -0500787 return result;
788}
789
Ethan Nicholas00543112018-07-31 09:44:36 -0400790bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400791 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500792 bool result = this->toSPIRV(program, buffer);
793 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400794 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500795 }
796 return result;
797}
798
Ethan Nicholas00543112018-07-31 09:44:36 -0400799bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400800 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -0400801 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400802 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500803 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500804 return result;
805}
806
Ethan Nicholas00543112018-07-31 09:44:36 -0400807bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400808 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500809 bool result = this->toGLSL(program, buffer);
810 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400811 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500812 }
813 return result;
814}
815
Brian Osmanc0243912020-02-19 15:35:26 -0500816bool Compiler::toHLSL(Program& program, String* out) {
817 String spirv;
818 if (!this->toSPIRV(program, &spirv)) {
819 return false;
820 }
821
822 return SPIRVtoHLSL(spirv, out);
823}
824
Ethan Nicholas00543112018-07-31 09:44:36 -0400825bool Compiler::toMetal(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400826 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toMetal");
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400827 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -0400828 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -0400829 return result;
830}
831
Ethan Nicholas00543112018-07-31 09:44:36 -0400832bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -0400833 StringStream buffer;
834 bool result = this->toMetal(program, buffer);
835 if (result) {
836 *out = buffer.str();
837 }
838 return result;
839}
840
Greg Daniela28ea672020-09-25 11:12:56 -0400841#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400842bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400843 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400844 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400845 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400846 return result;
847}
848
John Stiles82ab3402021-04-13 17:13:03 -0400849bool Compiler::toDSLCPP(Program& program, String name, OutputStream& out) {
850 AutoSource as(this, program.fSource.get());
851 DSLCPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
852 bool result = cg.generateCode();
853 return result;
854}
855
Ethan Nicholas00543112018-07-31 09:44:36 -0400856bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400857 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400858 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400859 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -0400860 return result;
861}
Greg Daniela28ea672020-09-25 11:12:56 -0400862#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400863
Ethan Nicholas2a479a52020-08-18 16:29:45 -0400864#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -0400865
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700866Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -0500867 if (fSource && offset >= 0) {
868 int line = 1;
869 int column = 1;
870 for (int i = 0; i < offset; i++) {
871 if ((*fSource)[i] == '\n') {
872 ++line;
873 column = 1;
874 }
875 else {
876 ++column;
877 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700878 }
Ethan Nicholas3c729892020-12-07 12:47:17 -0500879 return Position(line, column);
880 } else {
881 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700882 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700883}
884
885void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700886 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700887 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -0500888 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -0500889 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -0700890}
891
John Stiles8d3642e2021-01-22 09:50:04 -0500892void Compiler::setErrorCount(int c) {
893 if (c < fErrorCount) {
894 fErrorText.resize(fErrorTextLength[c]);
895 fErrorTextLength.resize(c);
896 fErrorCount = c;
897 }
898}
899
Ethan Nicholas95046142021-01-07 10:57:27 -0500900String Compiler::errorText(bool showCount) {
901 if (showCount) {
902 this->writeErrorCount();
903 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400904 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400905 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -0500906 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -0700907 return result;
908}
909
910void Compiler::writeErrorCount() {
911 if (fErrorCount) {
912 fErrorText += to_string(fErrorCount) + " error";
913 if (fErrorCount > 1) {
914 fErrorText += "s";
915 }
916 fErrorText += "\n";
917 }
918}
919
John Stilesa6841be2020-08-06 14:11:56 -0400920} // namespace SkSL