blob: 268a1423fbbad6a023570339871f03d994bc93f7 [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"
22#include "src/sksl/codegen/SkSLGLSLCodeGenerator.h"
23#include "src/sksl/codegen/SkSLHCodeGenerator.h"
24#include "src/sksl/codegen/SkSLMetalCodeGenerator.h"
25#include "src/sksl/codegen/SkSLSPIRVCodeGenerator.h"
26#include "src/sksl/codegen/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "src/sksl/ir/SkSLEnum.h"
28#include "src/sksl/ir/SkSLExpression.h"
29#include "src/sksl/ir/SkSLExpressionStatement.h"
30#include "src/sksl/ir/SkSLFunctionCall.h"
31#include "src/sksl/ir/SkSLIntLiteral.h"
32#include "src/sksl/ir/SkSLModifiersDeclaration.h"
33#include "src/sksl/ir/SkSLNop.h"
34#include "src/sksl/ir/SkSLSymbolTable.h"
35#include "src/sksl/ir/SkSLTernaryExpression.h"
36#include "src/sksl/ir/SkSLUnresolvedFunction.h"
37#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040038#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070039
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040040#include <fstream>
41
Ethan Nicholasa11035b2019-11-26 16:27:47 -050042#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
43#include "include/gpu/GrContextOptions.h"
44#include "src/gpu/GrShaderCaps.h"
45#endif
46
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040047#ifdef SK_ENABLE_SPIRV_VALIDATION
48#include "spirv-tools/libspirv.hpp"
49#endif
50
Brian Osman3d87e9f2020-10-08 11:50:22 -040051#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040052
Brian Osman3d87e9f2020-10-08 11:50:22 -040053// In standalone mode, we load the textual sksl source files. GN generates or copies these files
54// to the skslc executable directory. The "data" in this mode is just the filename.
55#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
56
57#else
58
59// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040060#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
61#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
62#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
63#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050064#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050065#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040066#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
67
Brian Osman3d87e9f2020-10-08 11:50:22 -040068#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
69 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040070
71#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040072
ethannicholasb3058bd2016-07-01 08:22:01 -070073namespace SkSL {
74
John Stiles7247b482021-03-08 10:40:35 -050075// These flags allow tools like Viewer or Nanobench to override the compiler's ProgramSettings.
John Stiles2ee4d7a2021-03-30 10:30:47 -040076Compiler::OverrideFlag Compiler::sOptimizer = OverrideFlag::kDefault;
77Compiler::OverrideFlag Compiler::sInliner = OverrideFlag::kDefault;
John Stiles8ef4d6c2021-03-05 16:01:45 -050078
John Stiles47c0a742021-02-09 09:30:35 -050079using RefKind = VariableReference::RefKind;
80
Brian Osman88cda172020-10-09 12:05:16 -040081class AutoSource {
82public:
83 AutoSource(Compiler* compiler, const String* source)
84 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
85 fCompiler->fSource = source;
86 }
87
88 ~AutoSource() { fCompiler->fSource = fOldSource; }
89
90 Compiler* fCompiler;
91 const String* fOldSource;
92};
93
John Stilesa935c3f2021-02-25 10:35:49 -050094class AutoProgramConfig {
95public:
96 AutoProgramConfig(std::shared_ptr<Context>& context, ProgramConfig* config)
97 : fContext(context.get()) {
98 SkASSERT(!fContext->fConfig);
99 fContext->fConfig = config;
100 }
101
102 ~AutoProgramConfig() {
103 fContext->fConfig = nullptr;
104 }
105
106 Context* fContext;
107};
108
John Stilesd6a5f4492021-02-11 15:46:11 -0500109Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesc1a98b82021-02-24 13:35:02 -0500110 : fContext(std::make_shared<Context>(/*errors=*/*this, *caps))
John Stiles7b920442020-12-17 10:43:41 -0500111 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -0500112 , fErrorCount(0) {
John Stilesc1a98b82021-02-24 13:35:02 -0500113 SkASSERT(caps);
John Stiles7c3515b2020-10-16 18:38:39 -0400114 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -0500115 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesc1a98b82021-02-24 13:35:02 -0500116 fIRGenerator = std::make_unique<IRGenerator>(fContext.get());
ethannicholasb3058bd2016-07-01 08:22:01 -0700117
John Stiles54e7c052021-01-11 14:22:36 -0500118#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700119
Brian Osmanb06301e2020-11-06 11:45:36 -0500120 const SkSL::Symbol* rootTypes[] = {
121 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500122
Brian Osmanb06301e2020-11-06 11:45:36 -0500123 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
124 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
125 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500126 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500127
Brian Osmanc0f2b642020-12-22 13:35:55 -0500128 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500129 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500130
Brian Osmanc63f4312020-12-23 11:44:14 -0500131 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700132
Brian Osman20fad322020-12-23 12:42:33 -0500133 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
134 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500135
Brian Osman14d00962021-04-02 17:04:35 -0400136 TYPE(ColorFilter),
137 TYPE(Shader),
Brian Osmanb06301e2020-11-06 11:45:36 -0500138 };
139
140 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500141 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
142 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
143 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
144 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
145 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
146
147 TYPE(GenUType), TYPE(UVec),
148 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
149
Brian Osmanc0f2b642020-12-22 13:35:55 -0500150 TYPE(Float2x3), TYPE(Float2x4),
151 TYPE(Float3x2), TYPE(Float3x4),
152 TYPE(Float4x2), TYPE(Float4x3),
153
Brian Osmanc63f4312020-12-23 11:44:14 -0500154 TYPE(Half2x3), TYPE(Half2x4),
155 TYPE(Half3x2), TYPE(Half3x4),
156 TYPE(Half4x2), TYPE(Half4x3),
157
Brian Osmanc0f2b642020-12-22 13:35:55 -0500158 TYPE(Mat), TYPE(HMat),
159
Brian Osmanb06301e2020-11-06 11:45:36 -0500160 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
161 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500162 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500163
164 TYPE(ISampler2D),
Brian Osmanb06301e2020-11-06 11:45:36 -0500165 TYPE(SubpassInput), TYPE(SubpassInputMS),
166
Brian Osmanb06301e2020-11-06 11:45:36 -0500167 TYPE(Sampler),
168 TYPE(Texture2D),
Brian Osman14d00962021-04-02 17:04:35 -0400169
170 TYPE(FragmentProcessor),
Brian Osmanb06301e2020-11-06 11:45:36 -0500171 };
172
173 for (const SkSL::Symbol* type : rootTypes) {
174 fRootSymbolTable->addWithoutOwnership(type);
175 }
176 for (const SkSL::Symbol* type : privateTypes) {
177 fPrivateSymbolTable->addWithoutOwnership(type);
178 }
179
180#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700181
Brian Osman3887a012020-09-30 13:22:27 -0400182 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
183 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500184 fPrivateSymbolTable->add(
185 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500186 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500187 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500188 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500189 /*builtin=*/false,
190 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500191
Brian Osman3d87e9f2020-10-08 11:50:22 -0400192 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500193 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700194}
195
John Stilesdd13dba2020-10-29 10:45:34 -0400196Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700197
Brian Osman56269982020-11-20 12:38:07 -0500198const ParsedModule& Compiler::loadGPUModule() {
199 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500200 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500201 }
202 return fGPUModule;
203}
204
205const ParsedModule& Compiler::loadFragmentModule() {
206 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500207 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500208 this->loadGPUModule());
209 }
210 return fFragmentModule;
211}
212
213const ParsedModule& Compiler::loadVertexModule() {
214 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500215 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500216 this->loadGPUModule());
217 }
218 return fVertexModule;
219}
220
Brian Osman88cda172020-10-09 12:05:16 -0400221const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400222 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500223 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500224 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400225 }
Brian Osman88cda172020-10-09 12:05:16 -0400226 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400227}
228
Brian Osman88cda172020-10-09 12:05:16 -0400229const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400230 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500231 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500232 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400233 }
Brian Osman88cda172020-10-09 12:05:16 -0400234 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400235}
236
Brian Osmanb06301e2020-11-06 11:45:36 -0500237const ParsedModule& Compiler::loadPublicModule() {
238 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500239 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500240 }
241 return fPublicModule;
242}
243
Brian Osman91946752020-12-21 13:20:40 -0500244const ParsedModule& Compiler::loadRuntimeEffectModule() {
245 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500246 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500247 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400248
Brian Osman91946752020-12-21 13:20:40 -0500249 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500250 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
251 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
252 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400253
Brian Osman962e6142021-04-12 11:21:00 -0400254 fRuntimeEffectModule.fSymbols->addAlias("ivec2", fContext->fTypes.fInt2.get());
255 fRuntimeEffectModule.fSymbols->addAlias("ivec3", fContext->fTypes.fInt3.get());
256 fRuntimeEffectModule.fSymbols->addAlias("ivec4", fContext->fTypes.fInt4.get());
257
John Stiles54e7c052021-01-11 14:22:36 -0500258 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
259 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
260 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400261
John Stiles54e7c052021-01-11 14:22:36 -0500262 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
263 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
264 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400265 }
Brian Osman91946752020-12-21 13:20:40 -0500266 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400267}
268
John Stilesdbd4e6f2021-02-16 13:29:15 -0500269const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400270 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500271 case ProgramKind::kVertex: return this->loadVertexModule(); break;
272 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
273 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
274 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
275 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
276 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400277 }
278 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400279}
280
John Stilesdbd4e6f2021-02-16 13:29:15 -0500281LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400282 ModuleData data,
John Stilesa935c3f2021-02-25 10:35:49 -0500283 std::shared_ptr<SymbolTable> base,
284 bool dehydrate) {
285 if (dehydrate) {
286 // NOTE: This is a workaround. When dehydrating includes, skslc doesn't know which module
287 // it's preparing, nor what the correct base module is. We can't use 'Root', because many
288 // GPU intrinsics reference private types, like samplers or textures. Today, 'Private' does
289 // contain the union of all known types, so this is safe. If we ever have types that only
290 // exist in 'Public' (for example), this logic needs to be smarter (by choosing the correct
291 // base for the module we're compiling).
Brian Osmanb06301e2020-11-06 11:45:36 -0500292 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400293 }
John Stilesa935c3f2021-02-25 10:35:49 -0500294 SkASSERT(base);
295
296 // Built-in modules always use default program settings.
297 ProgramConfig config;
298 config.fKind = kind;
299 config.fSettings.fReplaceSettings = !dehydrate;
300 AutoProgramConfig autoConfig(fContext, &config);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400301
302#if defined(SKSL_STANDALONE)
303 SkASSERT(data.fPath);
304 std::ifstream in(data.fPath);
John Stilesd51c9792021-03-18 11:40:14 -0400305 String text{std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()};
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400306 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400307 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400308 abort();
309 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400310 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400311 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500312
John Stiles881a10c2020-09-19 10:13:24 -0400313 SkASSERT(fIRGenerator->fCanInline);
314 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500315
Brian Osman88cda172020-10-09 12:05:16 -0400316 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500317 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
318 source->c_str(), source->length(),
319 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400320 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500321 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400322 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400323 if (this->fErrorCount) {
324 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400325 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400326 }
Brian Osman88cda172020-10-09 12:05:16 -0400327 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400328#else
329 SkASSERT(data.fData && (data.fSize != 0));
330 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
331 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500332 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400333 fModifiers.push_back(fIRGenerator->releaseModifiers());
334#endif
335
336 return module;
337}
338
John Stilesdbd4e6f2021-02-16 13:29:15 -0500339ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500340 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500341 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400342
343 // For modules that just declare (but don't define) intrinsic functions, there will be no new
344 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500345 if (module.fElements.empty()) {
346 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400347 }
348
349 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
350
351 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
352 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500353 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400354 switch (element->kind()) {
355 case ProgramElement::Kind::kFunction: {
356 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400357 SkASSERT(f.declaration().isBuiltin());
358 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400359 break;
360 }
John Stiles569249b2020-11-03 12:18:22 -0500361 case ProgramElement::Kind::kFunctionPrototype: {
362 // These are already in the symbol table.
363 break;
364 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400365 case ProgramElement::Kind::kEnum: {
366 const Enum& e = element->as<Enum>();
367 SkASSERT(e.isBuiltin());
368 intrinsics->insertOrDie(e.typeName(), std::move(element));
369 break;
370 }
371 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400372 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
373 const Variable& var = global.declaration()->as<VarDeclaration>().var();
374 SkASSERT(var.isBuiltin());
375 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400376 break;
377 }
378 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400379 const Variable& var = element->as<InterfaceBlock>().variable();
380 SkASSERT(var.isBuiltin());
381 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400382 break;
383 }
384 default:
385 printf("Unsupported element: %s\n", element->description().c_str());
386 SkASSERT(false);
387 break;
388 }
389 }
390
Brian Osman0006ad02020-11-18 15:38:39 -0500391 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400392}
393
Brian Osman32d53552020-09-23 13:55:20 -0400394std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -0500395 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -0400396 String text,
397 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500398 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400399 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -0500400
John Stilesdbd4e6f2021-02-16 13:29:15 -0500401 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400402
Brian Osman0006ad02020-11-18 15:38:39 -0500403 // Loading and optimizing our base module might reset the inliner, so do that first,
404 // *then* configure the inliner with the settings for this program.
405 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
406
John Stiles270cec22021-02-17 12:59:36 -0500407 // Update our context to point to the program configuration for the duration of compilation.
408 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -0500409 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -0500410
John Stiles2ee4d7a2021-03-30 10:30:47 -0400411 // Honor our optimization-override flags.
412 switch (sOptimizer) {
413 case OverrideFlag::kDefault:
414 break;
415 case OverrideFlag::kOff:
416 config->fSettings.fOptimize = false;
417 break;
418 case OverrideFlag::kOn:
419 config->fSettings.fOptimize = true;
420 break;
421 }
422
423 switch (sInliner) {
424 case OverrideFlag::kDefault:
425 break;
426 case OverrideFlag::kOff:
427 config->fSettings.fInlineThreshold = 0;
428 break;
429 case OverrideFlag::kOn:
430 if (config->fSettings.fInlineThreshold == 0) {
431 config->fSettings.fInlineThreshold = kDefaultInlineThreshold;
432 }
433 break;
434 }
John Stiles7247b482021-03-08 10:40:35 -0500435
436 // Disable optimization settings that depend on a parent setting which has been disabled.
John Stiles7247b482021-03-08 10:40:35 -0500437 config->fSettings.fInlineThreshold *= (int)config->fSettings.fOptimize;
John Stiles0bfeae62021-03-11 09:09:42 -0500438 config->fSettings.fRemoveDeadFunctions &= config->fSettings.fOptimize;
439 config->fSettings.fRemoveDeadVariables &= config->fSettings.fOptimize;
John Stiles7247b482021-03-08 10:40:35 -0500440
ethannicholasb3058bd2016-07-01 08:22:01 -0700441 fErrorText = "";
442 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -0500443 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -0400444
445 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700446 std::unique_ptr<String> textPtr(new String(std::move(text)));
447 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -0400448
John Stiles5c7bb322020-10-22 11:09:15 -0400449 // Enable node pooling while converting and optimizing the program for a performance boost.
450 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -0500451 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -0500452 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -0500453 pool = Pool::Create();
454 pool->attachToThread();
455 }
John Stilesd1204642021-02-17 16:30:02 -0500456 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
457 textPtr->c_str(), textPtr->size(),
458 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -0500459 auto program = std::make_unique<Program>(std::move(textPtr),
460 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -0400461 fContext,
462 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -0400463 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -0400464 std::move(ir.fModifiers),
465 std::move(ir.fSymbolTable),
466 std::move(pool),
467 ir.fInputs);
468 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500469 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -0400470 // Do not return programs that failed to compile.
John Stiles7247b482021-03-08 10:40:35 -0500471 } else if (!this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -0400472 // Do not return programs that failed to optimize.
473 } else {
474 // We have a successful program!
475 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500476 }
John Stiles5c7bb322020-10-22 11:09:15 -0400477
Brian Osman28f702c2021-02-02 11:52:07 -0500478 if (program->fPool) {
479 program->fPool->detachFromThread();
480 }
John Stiles5c7bb322020-10-22 11:09:15 -0400481 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500482}
483
John Stilesbb1505f2021-02-12 09:17:53 -0500484void Compiler::verifyStaticTests(const Program& program) {
485 class StaticTestVerifier : public ProgramVisitor {
486 public:
487 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
488
489 using ProgramVisitor::visitProgramElement;
490
491 bool visitStatement(const Statement& stmt) override {
492 switch (stmt.kind()) {
493 case Statement::Kind::kIf:
494 if (stmt.as<IfStatement>().isStatic()) {
495 fReporter->error(stmt.fOffset, "static if has non-static test");
496 }
497 break;
498
499 case Statement::Kind::kSwitch:
500 if (stmt.as<SwitchStatement>().isStatic()) {
501 fReporter->error(stmt.fOffset, "static switch has non-static test");
502 }
503 break;
504
505 default:
506 break;
507 }
508 return INHERITED::visitStatement(stmt);
509 }
510
John Stiles59e34562021-02-12 16:56:39 -0500511 bool visitExpression(const Expression&) override {
512 // We aren't looking for anything inside an Expression, so skip them entirely.
513 return false;
514 }
515
John Stilesbb1505f2021-02-12 09:17:53 -0500516 private:
517 using INHERITED = ProgramVisitor;
518 ErrorReporter* fReporter;
519 };
520
521 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -0500522 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -0500523 return;
524 }
525
526 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
527 StaticTestVerifier visitor{this};
528 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
529 if (element->is<FunctionDefinition>()) {
530 visitor.visitProgramElement(*element);
531 }
532 }
533}
534
Brian Osman0006ad02020-11-18 15:38:39 -0500535bool Compiler::optimize(LoadedModule& module) {
536 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -0500537
John Stiles270cec22021-02-17 12:59:36 -0500538 // Create a temporary program configuration with default settings.
539 ProgramConfig config;
540 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -0500541 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -0500542
John Stilesd1204642021-02-17 16:30:02 -0500543 // Reset the Inliner.
544 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -0500545
546 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -0500547
548 while (fErrorCount == 0) {
Brian Osman0006ad02020-11-18 15:38:39 -0500549 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stilesf3a28db2021-03-10 23:00:47 -0500550 if (!fInliner.analyze(module.fElements, module.fSymbols, usage.get())) {
Brian Osman0006ad02020-11-18 15:38:39 -0500551 break;
552 }
553 }
554 return fErrorCount == 0;
555}
556
John Stiles0bfeae62021-03-11 09:09:42 -0500557bool Compiler::removeDeadFunctions(Program& program, ProgramUsage* usage) {
558 bool madeChanges = false;
559
560 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
561 auto isDeadFunction = [&](const ProgramElement* element) {
562 if (!element->is<FunctionDefinition>()) {
563 return false;
564 }
565 const FunctionDefinition& fn = element->as<FunctionDefinition>();
John Stilese8da4d22021-03-24 09:19:45 -0400566 if (fn.declaration().isMain() || usage->get(fn.declaration()) > 0) {
John Stiles0bfeae62021-03-11 09:09:42 -0500567 return false;
568 }
569 usage->remove(*element);
570 madeChanges = true;
571 return true;
572 };
573
574 program.fElements.erase(std::remove_if(program.fElements.begin(),
575 program.fElements.end(),
576 [&](const std::unique_ptr<ProgramElement>& element) {
577 return isDeadFunction(element.get());
578 }),
579 program.fElements.end());
580 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
581 program.fSharedElements.end(),
582 isDeadFunction),
583 program.fSharedElements.end());
584 }
585 return madeChanges;
586}
587
588bool Compiler::removeDeadGlobalVariables(Program& program, ProgramUsage* usage) {
589 bool madeChanges = false;
590
591 if (program.fConfig->fSettings.fRemoveDeadVariables) {
592 auto isDeadVariable = [&](const ProgramElement* element) {
593 if (!element->is<GlobalVarDeclaration>()) {
594 return false;
595 }
596 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
597 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
598 if (!usage->isDead(varDecl.var())) {
599 return false;
600 }
601 madeChanges = true;
602 return true;
603 };
604
605 program.fElements.erase(std::remove_if(program.fElements.begin(),
606 program.fElements.end(),
607 [&](const std::unique_ptr<ProgramElement>& element) {
608 return isDeadVariable(element.get());
609 }),
610 program.fElements.end());
611 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
612 program.fSharedElements.end(),
613 isDeadVariable),
614 program.fSharedElements.end());
615 }
616 return madeChanges;
617}
618
John Stiles26541872021-03-16 12:19:54 -0400619bool Compiler::removeDeadLocalVariables(Program& program, ProgramUsage* usage) {
620 class DeadLocalVariableEliminator : public ProgramWriter {
621 public:
622 DeadLocalVariableEliminator(const Context& context, ProgramUsage* usage)
623 : fContext(context)
624 , fUsage(usage) {}
625
626 using ProgramWriter::visitProgramElement;
627
628 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
629 // We don't need to look inside expressions at all.
630 return false;
631 }
632
633 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
634 if (stmt->is<VarDeclaration>()) {
635 VarDeclaration& varDecl = stmt->as<VarDeclaration>();
636 const Variable* var = &varDecl.var();
637 ProgramUsage::VariableCounts* counts = fUsage->fVariableCounts.find(var);
638 SkASSERT(counts);
639 SkASSERT(counts->fDeclared);
640 if (CanEliminate(var, *counts)) {
641 if (var->initialValue()) {
642 // The variable has an initial-value expression, which might have side
643 // effects. ExpressionStatement::Make will preserve side effects, but
644 // replaces pure expressions with Nop.
645 fUsage->remove(stmt.get());
646 stmt = ExpressionStatement::Make(fContext, std::move(varDecl.value()));
647 fUsage->add(stmt.get());
648 } else {
649 // The variable has no initial-value and can be cleanly eliminated.
650 fUsage->remove(stmt.get());
651 stmt = std::make_unique<Nop>();
652 }
653 fMadeChanges = true;
654 }
655 return false;
656 }
657 return INHERITED::visitStatementPtr(stmt);
658 }
659
660 static bool CanEliminate(const Variable* var, const ProgramUsage::VariableCounts& counts) {
661 if (!counts.fDeclared || counts.fRead || var->storage() != VariableStorage::kLocal) {
662 return false;
663 }
664 if (var->initialValue()) {
665 SkASSERT(counts.fWrite >= 1);
666 return counts.fWrite == 1;
667 } else {
668 return counts.fWrite == 0;
669 }
670 }
671
672 bool fMadeChanges = false;
673 const Context& fContext;
674 ProgramUsage* fUsage;
675
676 using INHERITED = ProgramWriter;
677 };
678
679 DeadLocalVariableEliminator visitor{*fContext, usage};
680
681 if (program.fConfig->fSettings.fRemoveDeadVariables) {
682 for (auto& [var, counts] : usage->fVariableCounts) {
683 if (DeadLocalVariableEliminator::CanEliminate(var, counts)) {
684 // This program contains at least one dead local variable.
685 // Scan the program for any dead local variables and eliminate them all.
686 for (std::unique_ptr<ProgramElement>& pe : program.ownedElements()) {
687 if (pe->is<FunctionDefinition>()) {
688 visitor.visitProgramElement(*pe);
689 }
690 }
691 break;
692 }
693 }
694 }
695
696 return visitor.fMadeChanges;
697}
698
Ethan Nicholas00543112018-07-31 09:44:36 -0400699bool Compiler::optimize(Program& program) {
John Stiles7247b482021-03-08 10:40:35 -0500700 // The optimizer only needs to run when it is enabled.
701 if (!program.fConfig->fSettings.fOptimize) {
702 return true;
703 }
704
Ethan Nicholas00543112018-07-31 09:44:36 -0400705 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -0400706 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -0400707
John Stilesb6664582021-03-19 09:46:00 -0400708 if (fErrorCount == 0) {
John Stiles87fc6572021-04-01 14:56:34 +0000709 // Run the inliner only once; it is expensive! Multiple passes can occasionally shake out
710 // more wins, but it's diminishing returns.
711 fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400712
John Stilesb6664582021-03-19 09:46:00 -0400713 while (this->removeDeadFunctions(program, usage)) {
714 // Removing dead functions may cause more functions to become unreferenced. Try again.
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400715 }
John Stilesb6664582021-03-19 09:46:00 -0400716 while (this->removeDeadLocalVariables(program, usage)) {
717 // Removing dead variables may cause more variables to become unreferenced. Try again.
718 }
719 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
720 this->removeDeadGlobalVariables(program, usage);
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500721 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400722 }
John Stilesbb1505f2021-02-12 09:17:53 -0500723
724 if (fErrorCount == 0) {
725 this->verifyStaticTests(program);
726 }
727
Ethan Nicholas00543112018-07-31 09:44:36 -0400728 return fErrorCount == 0;
729}
730
Brian Osmanfb32ddf2019-06-18 10:14:20 -0400731#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
732
Ethan Nicholas00543112018-07-31 09:44:36 -0400733bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400734 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toSPIRV");
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400735#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400736 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -0400737 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400738 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400739 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -0500740 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400741 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400742 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400743 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500744 String errors;
745 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
746 const char* m) {
747 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400748 };
749 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500750
751 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
752 // explaining the error. In standalone mode (skslc), we will send the message, plus the
753 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
754 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
755
756 if (!result) {
757#if defined(SKSL_STANDALONE)
758 // Convert the string-stream to a SPIR-V disassembly.
759 std::string disassembly;
760 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
761 errors.append(disassembly);
762 }
763 this->error(-1, errors);
764#else
765 SkDEBUGFAILF("%s", errors.c_str());
766#endif
767 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400768 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400769 }
770#else
Brian Osman88cda172020-10-09 12:05:16 -0400771 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400772 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500773 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400774#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -0500775 return result;
776}
777
Ethan Nicholas00543112018-07-31 09:44:36 -0400778bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400779 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500780 bool result = this->toSPIRV(program, buffer);
781 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400782 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500783 }
784 return result;
785}
786
Ethan Nicholas00543112018-07-31 09:44:36 -0400787bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400788 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -0400789 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400790 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500791 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500792 return result;
793}
794
Ethan Nicholas00543112018-07-31 09:44:36 -0400795bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400796 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500797 bool result = this->toGLSL(program, buffer);
798 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400799 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500800 }
801 return result;
802}
803
Brian Osmanc0243912020-02-19 15:35:26 -0500804bool Compiler::toHLSL(Program& program, String* out) {
805 String spirv;
806 if (!this->toSPIRV(program, &spirv)) {
807 return false;
808 }
809
810 return SPIRVtoHLSL(spirv, out);
811}
812
Ethan Nicholas00543112018-07-31 09:44:36 -0400813bool Compiler::toMetal(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400814 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toMetal");
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400815 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -0400816 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -0400817 return result;
818}
819
Ethan Nicholas00543112018-07-31 09:44:36 -0400820bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -0400821 StringStream buffer;
822 bool result = this->toMetal(program, buffer);
823 if (result) {
824 *out = buffer.str();
825 }
826 return result;
827}
828
Greg Daniela28ea672020-09-25 11:12:56 -0400829#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400830bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400831 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400832 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400833 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400834 return result;
835}
836
Ethan Nicholas00543112018-07-31 09:44:36 -0400837bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400838 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400839 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400840 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -0400841 return result;
842}
Greg Daniela28ea672020-09-25 11:12:56 -0400843#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400844
Ethan Nicholas2a479a52020-08-18 16:29:45 -0400845#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -0400846
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700847Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -0500848 if (fSource && offset >= 0) {
849 int line = 1;
850 int column = 1;
851 for (int i = 0; i < offset; i++) {
852 if ((*fSource)[i] == '\n') {
853 ++line;
854 column = 1;
855 }
856 else {
857 ++column;
858 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700859 }
Ethan Nicholas3c729892020-12-07 12:47:17 -0500860 return Position(line, column);
861 } else {
862 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700863 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700864}
865
866void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700867 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700868 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -0500869 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -0500870 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -0700871}
872
John Stiles8d3642e2021-01-22 09:50:04 -0500873void Compiler::setErrorCount(int c) {
874 if (c < fErrorCount) {
875 fErrorText.resize(fErrorTextLength[c]);
876 fErrorTextLength.resize(c);
877 fErrorCount = c;
878 }
879}
880
Ethan Nicholas95046142021-01-07 10:57:27 -0500881String Compiler::errorText(bool showCount) {
882 if (showCount) {
883 this->writeErrorCount();
884 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400885 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400886 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -0500887 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -0700888 return result;
889}
890
891void Compiler::writeErrorCount() {
892 if (fErrorCount) {
893 fErrorText += to_string(fErrorCount) + " error";
894 if (fErrorCount > 1) {
895 fErrorText += "s";
896 }
897 fErrorText += "\n";
898 }
899}
900
John Stilesa6841be2020-08-06 14:11:56 -0400901} // namespace SkSL