blob: 952555b34ca61fbad3f5d4fda04ba3d0402833cd [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/sksl/SkSLCPPCodeGenerator.h"
John Stilesf3a28db2021-03-10 23:00:47 -050017#include "src/sksl/SkSLConstantFolder.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/sksl/SkSLGLSLCodeGenerator.h"
19#include "src/sksl/SkSLHCodeGenerator.h"
20#include "src/sksl/SkSLIRGenerator.h"
21#include "src/sksl/SkSLMetalCodeGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050022#include "src/sksl/SkSLOperators.h"
John Stiles270cec22021-02-17 12:59:36 -050023#include "src/sksl/SkSLProgramSettings.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040024#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050026#include "src/sksl/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
John Stiles54e7c052021-01-11 14:22:36 -0500254 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
255 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
256 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400257
John Stiles54e7c052021-01-11 14:22:36 -0500258 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
259 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
260 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400261 }
Brian Osman91946752020-12-21 13:20:40 -0500262 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400263}
264
John Stilesdbd4e6f2021-02-16 13:29:15 -0500265const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400266 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500267 case ProgramKind::kVertex: return this->loadVertexModule(); break;
268 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
269 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
270 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
271 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
272 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400273 }
274 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400275}
276
John Stilesdbd4e6f2021-02-16 13:29:15 -0500277LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400278 ModuleData data,
John Stilesa935c3f2021-02-25 10:35:49 -0500279 std::shared_ptr<SymbolTable> base,
280 bool dehydrate) {
281 if (dehydrate) {
282 // NOTE: This is a workaround. When dehydrating includes, skslc doesn't know which module
283 // it's preparing, nor what the correct base module is. We can't use 'Root', because many
284 // GPU intrinsics reference private types, like samplers or textures. Today, 'Private' does
285 // contain the union of all known types, so this is safe. If we ever have types that only
286 // exist in 'Public' (for example), this logic needs to be smarter (by choosing the correct
287 // base for the module we're compiling).
Brian Osmanb06301e2020-11-06 11:45:36 -0500288 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400289 }
John Stilesa935c3f2021-02-25 10:35:49 -0500290 SkASSERT(base);
291
292 // Built-in modules always use default program settings.
293 ProgramConfig config;
294 config.fKind = kind;
295 config.fSettings.fReplaceSettings = !dehydrate;
296 AutoProgramConfig autoConfig(fContext, &config);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400297
298#if defined(SKSL_STANDALONE)
299 SkASSERT(data.fPath);
300 std::ifstream in(data.fPath);
John Stilesd51c9792021-03-18 11:40:14 -0400301 String text{std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()};
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400302 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400303 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400304 abort();
305 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400306 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400307 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500308
John Stiles881a10c2020-09-19 10:13:24 -0400309 SkASSERT(fIRGenerator->fCanInline);
310 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500311
Brian Osman88cda172020-10-09 12:05:16 -0400312 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500313 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
314 source->c_str(), source->length(),
315 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400316 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500317 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400318 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400319 if (this->fErrorCount) {
320 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400321 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400322 }
Brian Osman88cda172020-10-09 12:05:16 -0400323 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400324#else
325 SkASSERT(data.fData && (data.fSize != 0));
326 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
327 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500328 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400329 fModifiers.push_back(fIRGenerator->releaseModifiers());
330#endif
331
332 return module;
333}
334
John Stilesdbd4e6f2021-02-16 13:29:15 -0500335ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500336 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500337 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400338
339 // For modules that just declare (but don't define) intrinsic functions, there will be no new
340 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500341 if (module.fElements.empty()) {
342 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400343 }
344
345 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
346
347 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
348 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500349 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400350 switch (element->kind()) {
351 case ProgramElement::Kind::kFunction: {
352 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400353 SkASSERT(f.declaration().isBuiltin());
354 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400355 break;
356 }
John Stiles569249b2020-11-03 12:18:22 -0500357 case ProgramElement::Kind::kFunctionPrototype: {
358 // These are already in the symbol table.
359 break;
360 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400361 case ProgramElement::Kind::kEnum: {
362 const Enum& e = element->as<Enum>();
363 SkASSERT(e.isBuiltin());
364 intrinsics->insertOrDie(e.typeName(), std::move(element));
365 break;
366 }
367 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400368 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
369 const Variable& var = global.declaration()->as<VarDeclaration>().var();
370 SkASSERT(var.isBuiltin());
371 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400372 break;
373 }
374 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400375 const Variable& var = element->as<InterfaceBlock>().variable();
376 SkASSERT(var.isBuiltin());
377 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400378 break;
379 }
380 default:
381 printf("Unsupported element: %s\n", element->description().c_str());
382 SkASSERT(false);
383 break;
384 }
385 }
386
Brian Osman0006ad02020-11-18 15:38:39 -0500387 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400388}
389
Brian Osman32d53552020-09-23 13:55:20 -0400390std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -0500391 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -0400392 String text,
393 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500394 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400395 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -0500396
John Stilesdbd4e6f2021-02-16 13:29:15 -0500397 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400398
Brian Osman0006ad02020-11-18 15:38:39 -0500399 // Loading and optimizing our base module might reset the inliner, so do that first,
400 // *then* configure the inliner with the settings for this program.
401 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
402
John Stiles270cec22021-02-17 12:59:36 -0500403 // Update our context to point to the program configuration for the duration of compilation.
404 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -0500405 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -0500406
John Stiles2ee4d7a2021-03-30 10:30:47 -0400407 // Honor our optimization-override flags.
408 switch (sOptimizer) {
409 case OverrideFlag::kDefault:
410 break;
411 case OverrideFlag::kOff:
412 config->fSettings.fOptimize = false;
413 break;
414 case OverrideFlag::kOn:
415 config->fSettings.fOptimize = true;
416 break;
417 }
418
419 switch (sInliner) {
420 case OverrideFlag::kDefault:
421 break;
422 case OverrideFlag::kOff:
423 config->fSettings.fInlineThreshold = 0;
424 break;
425 case OverrideFlag::kOn:
426 if (config->fSettings.fInlineThreshold == 0) {
427 config->fSettings.fInlineThreshold = kDefaultInlineThreshold;
428 }
429 break;
430 }
John Stiles7247b482021-03-08 10:40:35 -0500431
432 // Disable optimization settings that depend on a parent setting which has been disabled.
John Stiles7247b482021-03-08 10:40:35 -0500433 config->fSettings.fInlineThreshold *= (int)config->fSettings.fOptimize;
John Stiles0bfeae62021-03-11 09:09:42 -0500434 config->fSettings.fRemoveDeadFunctions &= config->fSettings.fOptimize;
435 config->fSettings.fRemoveDeadVariables &= config->fSettings.fOptimize;
John Stiles7247b482021-03-08 10:40:35 -0500436
ethannicholasb3058bd2016-07-01 08:22:01 -0700437 fErrorText = "";
438 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -0500439 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -0400440
441 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700442 std::unique_ptr<String> textPtr(new String(std::move(text)));
443 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -0400444
John Stiles5c7bb322020-10-22 11:09:15 -0400445 // Enable node pooling while converting and optimizing the program for a performance boost.
446 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -0500447 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -0500448 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -0500449 pool = Pool::Create();
450 pool->attachToThread();
451 }
John Stilesd1204642021-02-17 16:30:02 -0500452 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
453 textPtr->c_str(), textPtr->size(),
454 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -0500455 auto program = std::make_unique<Program>(std::move(textPtr),
456 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -0400457 fContext,
458 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -0400459 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -0400460 std::move(ir.fModifiers),
461 std::move(ir.fSymbolTable),
462 std::move(pool),
463 ir.fInputs);
464 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500465 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -0400466 // Do not return programs that failed to compile.
John Stiles7247b482021-03-08 10:40:35 -0500467 } else if (!this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -0400468 // Do not return programs that failed to optimize.
469 } else {
470 // We have a successful program!
471 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500472 }
John Stiles5c7bb322020-10-22 11:09:15 -0400473
Brian Osman28f702c2021-02-02 11:52:07 -0500474 if (program->fPool) {
475 program->fPool->detachFromThread();
476 }
John Stiles5c7bb322020-10-22 11:09:15 -0400477 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500478}
479
John Stilesbb1505f2021-02-12 09:17:53 -0500480void Compiler::verifyStaticTests(const Program& program) {
481 class StaticTestVerifier : public ProgramVisitor {
482 public:
483 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
484
485 using ProgramVisitor::visitProgramElement;
486
487 bool visitStatement(const Statement& stmt) override {
488 switch (stmt.kind()) {
489 case Statement::Kind::kIf:
490 if (stmt.as<IfStatement>().isStatic()) {
491 fReporter->error(stmt.fOffset, "static if has non-static test");
492 }
493 break;
494
495 case Statement::Kind::kSwitch:
496 if (stmt.as<SwitchStatement>().isStatic()) {
497 fReporter->error(stmt.fOffset, "static switch has non-static test");
498 }
499 break;
500
501 default:
502 break;
503 }
504 return INHERITED::visitStatement(stmt);
505 }
506
John Stiles59e34562021-02-12 16:56:39 -0500507 bool visitExpression(const Expression&) override {
508 // We aren't looking for anything inside an Expression, so skip them entirely.
509 return false;
510 }
511
John Stilesbb1505f2021-02-12 09:17:53 -0500512 private:
513 using INHERITED = ProgramVisitor;
514 ErrorReporter* fReporter;
515 };
516
517 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -0500518 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -0500519 return;
520 }
521
522 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
523 StaticTestVerifier visitor{this};
524 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
525 if (element->is<FunctionDefinition>()) {
526 visitor.visitProgramElement(*element);
527 }
528 }
529}
530
Brian Osman0006ad02020-11-18 15:38:39 -0500531bool Compiler::optimize(LoadedModule& module) {
532 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -0500533
John Stiles270cec22021-02-17 12:59:36 -0500534 // Create a temporary program configuration with default settings.
535 ProgramConfig config;
536 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -0500537 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -0500538
John Stilesd1204642021-02-17 16:30:02 -0500539 // Reset the Inliner.
540 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -0500541
542 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -0500543
544 while (fErrorCount == 0) {
Brian Osman0006ad02020-11-18 15:38:39 -0500545 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stilesf3a28db2021-03-10 23:00:47 -0500546 if (!fInliner.analyze(module.fElements, module.fSymbols, usage.get())) {
Brian Osman0006ad02020-11-18 15:38:39 -0500547 break;
548 }
549 }
550 return fErrorCount == 0;
551}
552
John Stiles0bfeae62021-03-11 09:09:42 -0500553bool Compiler::removeDeadFunctions(Program& program, ProgramUsage* usage) {
554 bool madeChanges = false;
555
556 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
557 auto isDeadFunction = [&](const ProgramElement* element) {
558 if (!element->is<FunctionDefinition>()) {
559 return false;
560 }
561 const FunctionDefinition& fn = element->as<FunctionDefinition>();
John Stilese8da4d22021-03-24 09:19:45 -0400562 if (fn.declaration().isMain() || usage->get(fn.declaration()) > 0) {
John Stiles0bfeae62021-03-11 09:09:42 -0500563 return false;
564 }
565 usage->remove(*element);
566 madeChanges = true;
567 return true;
568 };
569
570 program.fElements.erase(std::remove_if(program.fElements.begin(),
571 program.fElements.end(),
572 [&](const std::unique_ptr<ProgramElement>& element) {
573 return isDeadFunction(element.get());
574 }),
575 program.fElements.end());
576 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
577 program.fSharedElements.end(),
578 isDeadFunction),
579 program.fSharedElements.end());
580 }
581 return madeChanges;
582}
583
584bool Compiler::removeDeadGlobalVariables(Program& program, ProgramUsage* usage) {
585 bool madeChanges = false;
586
587 if (program.fConfig->fSettings.fRemoveDeadVariables) {
588 auto isDeadVariable = [&](const ProgramElement* element) {
589 if (!element->is<GlobalVarDeclaration>()) {
590 return false;
591 }
592 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
593 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
594 if (!usage->isDead(varDecl.var())) {
595 return false;
596 }
597 madeChanges = true;
598 return true;
599 };
600
601 program.fElements.erase(std::remove_if(program.fElements.begin(),
602 program.fElements.end(),
603 [&](const std::unique_ptr<ProgramElement>& element) {
604 return isDeadVariable(element.get());
605 }),
606 program.fElements.end());
607 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
608 program.fSharedElements.end(),
609 isDeadVariable),
610 program.fSharedElements.end());
611 }
612 return madeChanges;
613}
614
John Stiles26541872021-03-16 12:19:54 -0400615bool Compiler::removeDeadLocalVariables(Program& program, ProgramUsage* usage) {
616 class DeadLocalVariableEliminator : public ProgramWriter {
617 public:
618 DeadLocalVariableEliminator(const Context& context, ProgramUsage* usage)
619 : fContext(context)
620 , fUsage(usage) {}
621
622 using ProgramWriter::visitProgramElement;
623
624 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
625 // We don't need to look inside expressions at all.
626 return false;
627 }
628
629 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
630 if (stmt->is<VarDeclaration>()) {
631 VarDeclaration& varDecl = stmt->as<VarDeclaration>();
632 const Variable* var = &varDecl.var();
633 ProgramUsage::VariableCounts* counts = fUsage->fVariableCounts.find(var);
634 SkASSERT(counts);
635 SkASSERT(counts->fDeclared);
636 if (CanEliminate(var, *counts)) {
637 if (var->initialValue()) {
638 // The variable has an initial-value expression, which might have side
639 // effects. ExpressionStatement::Make will preserve side effects, but
640 // replaces pure expressions with Nop.
641 fUsage->remove(stmt.get());
642 stmt = ExpressionStatement::Make(fContext, std::move(varDecl.value()));
643 fUsage->add(stmt.get());
644 } else {
645 // The variable has no initial-value and can be cleanly eliminated.
646 fUsage->remove(stmt.get());
647 stmt = std::make_unique<Nop>();
648 }
649 fMadeChanges = true;
650 }
651 return false;
652 }
653 return INHERITED::visitStatementPtr(stmt);
654 }
655
656 static bool CanEliminate(const Variable* var, const ProgramUsage::VariableCounts& counts) {
657 if (!counts.fDeclared || counts.fRead || var->storage() != VariableStorage::kLocal) {
658 return false;
659 }
660 if (var->initialValue()) {
661 SkASSERT(counts.fWrite >= 1);
662 return counts.fWrite == 1;
663 } else {
664 return counts.fWrite == 0;
665 }
666 }
667
668 bool fMadeChanges = false;
669 const Context& fContext;
670 ProgramUsage* fUsage;
671
672 using INHERITED = ProgramWriter;
673 };
674
675 DeadLocalVariableEliminator visitor{*fContext, usage};
676
677 if (program.fConfig->fSettings.fRemoveDeadVariables) {
678 for (auto& [var, counts] : usage->fVariableCounts) {
679 if (DeadLocalVariableEliminator::CanEliminate(var, counts)) {
680 // This program contains at least one dead local variable.
681 // Scan the program for any dead local variables and eliminate them all.
682 for (std::unique_ptr<ProgramElement>& pe : program.ownedElements()) {
683 if (pe->is<FunctionDefinition>()) {
684 visitor.visitProgramElement(*pe);
685 }
686 }
687 break;
688 }
689 }
690 }
691
692 return visitor.fMadeChanges;
693}
694
Ethan Nicholas00543112018-07-31 09:44:36 -0400695bool Compiler::optimize(Program& program) {
John Stiles7247b482021-03-08 10:40:35 -0500696 // The optimizer only needs to run when it is enabled.
697 if (!program.fConfig->fSettings.fOptimize) {
698 return true;
699 }
700
Ethan Nicholas00543112018-07-31 09:44:36 -0400701 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -0400702 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -0400703
John Stilesb6664582021-03-19 09:46:00 -0400704 if (fErrorCount == 0) {
John Stiles87fc6572021-04-01 14:56:34 +0000705 // Run the inliner only once; it is expensive! Multiple passes can occasionally shake out
706 // more wins, but it's diminishing returns.
707 fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400708
John Stilesb6664582021-03-19 09:46:00 -0400709 while (this->removeDeadFunctions(program, usage)) {
710 // Removing dead functions may cause more functions to become unreferenced. Try again.
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400711 }
John Stilesb6664582021-03-19 09:46:00 -0400712 while (this->removeDeadLocalVariables(program, usage)) {
713 // Removing dead variables may cause more variables to become unreferenced. Try again.
714 }
715 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
716 this->removeDeadGlobalVariables(program, usage);
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500717 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400718 }
John Stilesbb1505f2021-02-12 09:17:53 -0500719
720 if (fErrorCount == 0) {
721 this->verifyStaticTests(program);
722 }
723
Ethan Nicholas00543112018-07-31 09:44:36 -0400724 return fErrorCount == 0;
725}
726
Brian Osmanfb32ddf2019-06-18 10:14:20 -0400727#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
728
Ethan Nicholas00543112018-07-31 09:44:36 -0400729bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400730 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toSPIRV");
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400731#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400732 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -0400733 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400734 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400735 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -0500736 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400737 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400738 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400739 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500740 String errors;
741 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
742 const char* m) {
743 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400744 };
745 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500746
747 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
748 // explaining the error. In standalone mode (skslc), we will send the message, plus the
749 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
750 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
751
752 if (!result) {
753#if defined(SKSL_STANDALONE)
754 // Convert the string-stream to a SPIR-V disassembly.
755 std::string disassembly;
756 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
757 errors.append(disassembly);
758 }
759 this->error(-1, errors);
760#else
761 SkDEBUGFAILF("%s", errors.c_str());
762#endif
763 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400764 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400765 }
766#else
Brian Osman88cda172020-10-09 12:05:16 -0400767 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400768 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500769 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400770#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -0500771 return result;
772}
773
Ethan Nicholas00543112018-07-31 09:44:36 -0400774bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400775 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500776 bool result = this->toSPIRV(program, buffer);
777 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400778 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500779 }
780 return result;
781}
782
Ethan Nicholas00543112018-07-31 09:44:36 -0400783bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400784 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -0400785 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400786 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500787 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500788 return result;
789}
790
Ethan Nicholas00543112018-07-31 09:44:36 -0400791bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400792 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500793 bool result = this->toGLSL(program, buffer);
794 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400795 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500796 }
797 return result;
798}
799
Brian Osmanc0243912020-02-19 15:35:26 -0500800bool Compiler::toHLSL(Program& program, String* out) {
801 String spirv;
802 if (!this->toSPIRV(program, &spirv)) {
803 return false;
804 }
805
806 return SPIRVtoHLSL(spirv, out);
807}
808
Ethan Nicholas00543112018-07-31 09:44:36 -0400809bool Compiler::toMetal(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400810 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toMetal");
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400811 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -0400812 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -0400813 return result;
814}
815
Ethan Nicholas00543112018-07-31 09:44:36 -0400816bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -0400817 StringStream buffer;
818 bool result = this->toMetal(program, buffer);
819 if (result) {
820 *out = buffer.str();
821 }
822 return result;
823}
824
Greg Daniela28ea672020-09-25 11:12:56 -0400825#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400826bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400827 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400828 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400829 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400830 return result;
831}
832
Ethan Nicholas00543112018-07-31 09:44:36 -0400833bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400834 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400835 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400836 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -0400837 return result;
838}
Greg Daniela28ea672020-09-25 11:12:56 -0400839#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400840
Ethan Nicholas2a479a52020-08-18 16:29:45 -0400841#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -0400842
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700843Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -0500844 if (fSource && offset >= 0) {
845 int line = 1;
846 int column = 1;
847 for (int i = 0; i < offset; i++) {
848 if ((*fSource)[i] == '\n') {
849 ++line;
850 column = 1;
851 }
852 else {
853 ++column;
854 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700855 }
Ethan Nicholas3c729892020-12-07 12:47:17 -0500856 return Position(line, column);
857 } else {
858 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700859 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700860}
861
862void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700863 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700864 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -0500865 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -0500866 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -0700867}
868
John Stiles8d3642e2021-01-22 09:50:04 -0500869void Compiler::setErrorCount(int c) {
870 if (c < fErrorCount) {
871 fErrorText.resize(fErrorTextLength[c]);
872 fErrorTextLength.resize(c);
873 fErrorCount = c;
874 }
875}
876
Ethan Nicholas95046142021-01-07 10:57:27 -0500877String Compiler::errorText(bool showCount) {
878 if (showCount) {
879 this->writeErrorCount();
880 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400881 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400882 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -0500883 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -0700884 return result;
885}
886
887void Compiler::writeErrorCount() {
888 if (fErrorCount) {
889 fErrorText += to_string(fErrorCount) + " error";
890 if (fErrorCount > 1) {
891 fErrorText += "s";
892 }
893 fErrorText += "\n";
894 }
895}
896
John Stilesa6841be2020-08-06 14:11:56 -0400897} // namespace SkSL