blob: d1a562b362cd80f9aafc30d84a35eb8b46b06380 [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 Osman91946752020-12-21 13:20:40 -050066#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040067#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
68
Brian Osman3d87e9f2020-10-08 11:50:22 -040069#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
70 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040071
72#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040073
ethannicholasb3058bd2016-07-01 08:22:01 -070074namespace SkSL {
75
John Stiles7247b482021-03-08 10:40:35 -050076// These flags allow tools like Viewer or Nanobench to override the compiler's ProgramSettings.
John Stiles2ee4d7a2021-03-30 10:30:47 -040077Compiler::OverrideFlag Compiler::sOptimizer = OverrideFlag::kDefault;
78Compiler::OverrideFlag Compiler::sInliner = OverrideFlag::kDefault;
John Stiles8ef4d6c2021-03-05 16:01:45 -050079
John Stiles47c0a742021-02-09 09:30:35 -050080using RefKind = VariableReference::RefKind;
81
Brian Osman88cda172020-10-09 12:05:16 -040082class AutoSource {
83public:
84 AutoSource(Compiler* compiler, const String* source)
85 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
86 fCompiler->fSource = source;
87 }
88
89 ~AutoSource() { fCompiler->fSource = fOldSource; }
90
91 Compiler* fCompiler;
92 const String* fOldSource;
93};
94
John Stilesa935c3f2021-02-25 10:35:49 -050095class AutoProgramConfig {
96public:
97 AutoProgramConfig(std::shared_ptr<Context>& context, ProgramConfig* config)
98 : fContext(context.get()) {
99 SkASSERT(!fContext->fConfig);
100 fContext->fConfig = config;
101 }
102
103 ~AutoProgramConfig() {
104 fContext->fConfig = nullptr;
105 }
106
107 Context* fContext;
108};
109
John Stilesd6a5f4492021-02-11 15:46:11 -0500110Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesc1a98b82021-02-24 13:35:02 -0500111 : fContext(std::make_shared<Context>(/*errors=*/*this, *caps))
John Stiles7b920442020-12-17 10:43:41 -0500112 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -0500113 , fErrorCount(0) {
John Stilesc1a98b82021-02-24 13:35:02 -0500114 SkASSERT(caps);
John Stiles7c3515b2020-10-16 18:38:39 -0400115 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -0500116 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesc1a98b82021-02-24 13:35:02 -0500117 fIRGenerator = std::make_unique<IRGenerator>(fContext.get());
ethannicholasb3058bd2016-07-01 08:22:01 -0700118
John Stiles54e7c052021-01-11 14:22:36 -0500119#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700120
Brian Osmanb06301e2020-11-06 11:45:36 -0500121 const SkSL::Symbol* rootTypes[] = {
122 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500123
Brian Osmanb06301e2020-11-06 11:45:36 -0500124 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
125 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
126 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500127 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500128
Brian Osmanc0f2b642020-12-22 13:35:55 -0500129 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500130 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500131
Brian Osmanc63f4312020-12-23 11:44:14 -0500132 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700133
Brian Osman20fad322020-12-23 12:42:33 -0500134 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
135 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500136
Brian Osman14d00962021-04-02 17:04:35 -0400137 TYPE(ColorFilter),
138 TYPE(Shader),
Brian Osmanb06301e2020-11-06 11:45:36 -0500139 };
140
141 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500142 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
143 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
144 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
145 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
146 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
147
148 TYPE(GenUType), TYPE(UVec),
149 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
150
Brian Osmanc0f2b642020-12-22 13:35:55 -0500151 TYPE(Float2x3), TYPE(Float2x4),
152 TYPE(Float3x2), TYPE(Float3x4),
153 TYPE(Float4x2), TYPE(Float4x3),
154
Brian Osmanc63f4312020-12-23 11:44:14 -0500155 TYPE(Half2x3), TYPE(Half2x4),
156 TYPE(Half3x2), TYPE(Half3x4),
157 TYPE(Half4x2), TYPE(Half4x3),
158
Brian Osmanc0f2b642020-12-22 13:35:55 -0500159 TYPE(Mat), TYPE(HMat),
160
Brian Osmanb06301e2020-11-06 11:45:36 -0500161 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
162 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500163 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500164
165 TYPE(ISampler2D),
Brian Osmanb06301e2020-11-06 11:45:36 -0500166 TYPE(SubpassInput), TYPE(SubpassInputMS),
167
Brian Osmanb06301e2020-11-06 11:45:36 -0500168 TYPE(Sampler),
169 TYPE(Texture2D),
Brian Osman14d00962021-04-02 17:04:35 -0400170
171 TYPE(FragmentProcessor),
Brian Osmanb06301e2020-11-06 11:45:36 -0500172 };
173
174 for (const SkSL::Symbol* type : rootTypes) {
175 fRootSymbolTable->addWithoutOwnership(type);
176 }
177 for (const SkSL::Symbol* type : privateTypes) {
178 fPrivateSymbolTable->addWithoutOwnership(type);
179 }
180
181#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700182
Brian Osman3887a012020-09-30 13:22:27 -0400183 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
184 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500185 fPrivateSymbolTable->add(
186 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500187 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500188 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500189 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500190 /*builtin=*/false,
191 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500192
Brian Osman3d87e9f2020-10-08 11:50:22 -0400193 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500194 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700195}
196
John Stilesdd13dba2020-10-29 10:45:34 -0400197Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700198
Brian Osman56269982020-11-20 12:38:07 -0500199const ParsedModule& Compiler::loadGPUModule() {
200 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500201 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500202 }
203 return fGPUModule;
204}
205
206const ParsedModule& Compiler::loadFragmentModule() {
207 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500208 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500209 this->loadGPUModule());
210 }
211 return fFragmentModule;
212}
213
214const ParsedModule& Compiler::loadVertexModule() {
215 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500216 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500217 this->loadGPUModule());
218 }
219 return fVertexModule;
220}
221
Brian Osman88cda172020-10-09 12:05:16 -0400222const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400223 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500224 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500225 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400226 }
Brian Osman88cda172020-10-09 12:05:16 -0400227 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400228}
229
Brian Osman88cda172020-10-09 12:05:16 -0400230const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400231 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500232 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500233 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400234 }
Brian Osman88cda172020-10-09 12:05:16 -0400235 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400236}
237
Brian Osmanb06301e2020-11-06 11:45:36 -0500238const ParsedModule& Compiler::loadPublicModule() {
239 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500240 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500241 }
242 return fPublicModule;
243}
244
Brian Osman91946752020-12-21 13:20:40 -0500245const ParsedModule& Compiler::loadRuntimeEffectModule() {
246 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500247 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500248 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400249
Brian Osman91946752020-12-21 13:20:40 -0500250 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500251 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
252 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
253 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400254
Brian Osman962e6142021-04-12 11:21:00 -0400255 fRuntimeEffectModule.fSymbols->addAlias("ivec2", fContext->fTypes.fInt2.get());
256 fRuntimeEffectModule.fSymbols->addAlias("ivec3", fContext->fTypes.fInt3.get());
257 fRuntimeEffectModule.fSymbols->addAlias("ivec4", fContext->fTypes.fInt4.get());
258
John Stiles54e7c052021-01-11 14:22:36 -0500259 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
260 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
261 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400262
John Stiles54e7c052021-01-11 14:22:36 -0500263 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
264 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
265 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400266 }
Brian Osman91946752020-12-21 13:20:40 -0500267 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400268}
269
John Stilesdbd4e6f2021-02-16 13:29:15 -0500270const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400271 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500272 case ProgramKind::kVertex: return this->loadVertexModule(); break;
273 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
274 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
275 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
276 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
277 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400278 }
279 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400280}
281
John Stilesdbd4e6f2021-02-16 13:29:15 -0500282LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400283 ModuleData data,
John Stilesa935c3f2021-02-25 10:35:49 -0500284 std::shared_ptr<SymbolTable> base,
285 bool dehydrate) {
286 if (dehydrate) {
287 // NOTE: This is a workaround. When dehydrating includes, skslc doesn't know which module
288 // it's preparing, nor what the correct base module is. We can't use 'Root', because many
289 // GPU intrinsics reference private types, like samplers or textures. Today, 'Private' does
290 // contain the union of all known types, so this is safe. If we ever have types that only
291 // exist in 'Public' (for example), this logic needs to be smarter (by choosing the correct
292 // base for the module we're compiling).
Brian Osmanb06301e2020-11-06 11:45:36 -0500293 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400294 }
John Stilesa935c3f2021-02-25 10:35:49 -0500295 SkASSERT(base);
296
297 // Built-in modules always use default program settings.
298 ProgramConfig config;
299 config.fKind = kind;
300 config.fSettings.fReplaceSettings = !dehydrate;
301 AutoProgramConfig autoConfig(fContext, &config);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400302
303#if defined(SKSL_STANDALONE)
304 SkASSERT(data.fPath);
305 std::ifstream in(data.fPath);
John Stilesd51c9792021-03-18 11:40:14 -0400306 String text{std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()};
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400307 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400308 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400309 abort();
310 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400311 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400312 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500313
John Stiles881a10c2020-09-19 10:13:24 -0400314 SkASSERT(fIRGenerator->fCanInline);
315 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500316
Brian Osman88cda172020-10-09 12:05:16 -0400317 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500318 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
319 source->c_str(), source->length(),
320 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400321 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500322 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400323 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400324 if (this->fErrorCount) {
325 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400326 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400327 }
Brian Osman88cda172020-10-09 12:05:16 -0400328 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400329#else
330 SkASSERT(data.fData && (data.fSize != 0));
331 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
332 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500333 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400334 fModifiers.push_back(fIRGenerator->releaseModifiers());
335#endif
336
337 return module;
338}
339
John Stilesdbd4e6f2021-02-16 13:29:15 -0500340ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500341 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500342 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400343
344 // For modules that just declare (but don't define) intrinsic functions, there will be no new
345 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500346 if (module.fElements.empty()) {
347 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400348 }
349
350 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
351
352 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
353 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500354 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400355 switch (element->kind()) {
356 case ProgramElement::Kind::kFunction: {
357 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400358 SkASSERT(f.declaration().isBuiltin());
359 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400360 break;
361 }
John Stiles569249b2020-11-03 12:18:22 -0500362 case ProgramElement::Kind::kFunctionPrototype: {
363 // These are already in the symbol table.
364 break;
365 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400366 case ProgramElement::Kind::kEnum: {
367 const Enum& e = element->as<Enum>();
368 SkASSERT(e.isBuiltin());
369 intrinsics->insertOrDie(e.typeName(), std::move(element));
370 break;
371 }
372 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400373 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
374 const Variable& var = global.declaration()->as<VarDeclaration>().var();
375 SkASSERT(var.isBuiltin());
376 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400377 break;
378 }
379 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400380 const Variable& var = element->as<InterfaceBlock>().variable();
381 SkASSERT(var.isBuiltin());
382 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400383 break;
384 }
385 default:
386 printf("Unsupported element: %s\n", element->description().c_str());
387 SkASSERT(false);
388 break;
389 }
390 }
391
Brian Osman0006ad02020-11-18 15:38:39 -0500392 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400393}
394
Brian Osman32d53552020-09-23 13:55:20 -0400395std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -0500396 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -0400397 String text,
398 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500399 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400400 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -0500401
John Stilesdbd4e6f2021-02-16 13:29:15 -0500402 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400403
Brian Osman0006ad02020-11-18 15:38:39 -0500404 // Loading and optimizing our base module might reset the inliner, so do that first,
405 // *then* configure the inliner with the settings for this program.
406 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
407
John Stiles270cec22021-02-17 12:59:36 -0500408 // Update our context to point to the program configuration for the duration of compilation.
409 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -0500410 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -0500411
John Stiles2ee4d7a2021-03-30 10:30:47 -0400412 // Honor our optimization-override flags.
413 switch (sOptimizer) {
414 case OverrideFlag::kDefault:
415 break;
416 case OverrideFlag::kOff:
417 config->fSettings.fOptimize = false;
418 break;
419 case OverrideFlag::kOn:
420 config->fSettings.fOptimize = true;
421 break;
422 }
423
424 switch (sInliner) {
425 case OverrideFlag::kDefault:
426 break;
427 case OverrideFlag::kOff:
428 config->fSettings.fInlineThreshold = 0;
429 break;
430 case OverrideFlag::kOn:
431 if (config->fSettings.fInlineThreshold == 0) {
432 config->fSettings.fInlineThreshold = kDefaultInlineThreshold;
433 }
434 break;
435 }
John Stiles7247b482021-03-08 10:40:35 -0500436
437 // Disable optimization settings that depend on a parent setting which has been disabled.
John Stiles7247b482021-03-08 10:40:35 -0500438 config->fSettings.fInlineThreshold *= (int)config->fSettings.fOptimize;
John Stiles0bfeae62021-03-11 09:09:42 -0500439 config->fSettings.fRemoveDeadFunctions &= config->fSettings.fOptimize;
440 config->fSettings.fRemoveDeadVariables &= config->fSettings.fOptimize;
John Stiles7247b482021-03-08 10:40:35 -0500441
ethannicholasb3058bd2016-07-01 08:22:01 -0700442 fErrorText = "";
443 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -0500444 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -0400445
446 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700447 std::unique_ptr<String> textPtr(new String(std::move(text)));
448 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -0400449
John Stiles5c7bb322020-10-22 11:09:15 -0400450 // Enable node pooling while converting and optimizing the program for a performance boost.
451 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -0500452 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -0500453 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -0500454 pool = Pool::Create();
455 pool->attachToThread();
456 }
John Stilesd1204642021-02-17 16:30:02 -0500457 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
458 textPtr->c_str(), textPtr->size(),
459 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -0500460 auto program = std::make_unique<Program>(std::move(textPtr),
461 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -0400462 fContext,
463 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -0400464 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -0400465 std::move(ir.fModifiers),
466 std::move(ir.fSymbolTable),
467 std::move(pool),
468 ir.fInputs);
469 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500470 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -0400471 // Do not return programs that failed to compile.
John Stiles7247b482021-03-08 10:40:35 -0500472 } else if (!this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -0400473 // Do not return programs that failed to optimize.
474 } else {
475 // We have a successful program!
476 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500477 }
John Stiles5c7bb322020-10-22 11:09:15 -0400478
Brian Osman28f702c2021-02-02 11:52:07 -0500479 if (program->fPool) {
480 program->fPool->detachFromThread();
481 }
John Stiles5c7bb322020-10-22 11:09:15 -0400482 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500483}
484
John Stilesbb1505f2021-02-12 09:17:53 -0500485void Compiler::verifyStaticTests(const Program& program) {
486 class StaticTestVerifier : public ProgramVisitor {
487 public:
488 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
489
490 using ProgramVisitor::visitProgramElement;
491
492 bool visitStatement(const Statement& stmt) override {
493 switch (stmt.kind()) {
494 case Statement::Kind::kIf:
495 if (stmt.as<IfStatement>().isStatic()) {
496 fReporter->error(stmt.fOffset, "static if has non-static test");
497 }
498 break;
499
500 case Statement::Kind::kSwitch:
501 if (stmt.as<SwitchStatement>().isStatic()) {
502 fReporter->error(stmt.fOffset, "static switch has non-static test");
503 }
504 break;
505
506 default:
507 break;
508 }
509 return INHERITED::visitStatement(stmt);
510 }
511
John Stiles59e34562021-02-12 16:56:39 -0500512 bool visitExpression(const Expression&) override {
513 // We aren't looking for anything inside an Expression, so skip them entirely.
514 return false;
515 }
516
John Stilesbb1505f2021-02-12 09:17:53 -0500517 private:
518 using INHERITED = ProgramVisitor;
519 ErrorReporter* fReporter;
520 };
521
522 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -0500523 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -0500524 return;
525 }
526
527 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
528 StaticTestVerifier visitor{this};
529 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
530 if (element->is<FunctionDefinition>()) {
531 visitor.visitProgramElement(*element);
532 }
533 }
534}
535
Brian Osman0006ad02020-11-18 15:38:39 -0500536bool Compiler::optimize(LoadedModule& module) {
537 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -0500538
John Stiles270cec22021-02-17 12:59:36 -0500539 // Create a temporary program configuration with default settings.
540 ProgramConfig config;
541 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -0500542 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -0500543
John Stilesd1204642021-02-17 16:30:02 -0500544 // Reset the Inliner.
545 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -0500546
547 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -0500548
549 while (fErrorCount == 0) {
Brian Osman0006ad02020-11-18 15:38:39 -0500550 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stilesf3a28db2021-03-10 23:00:47 -0500551 if (!fInliner.analyze(module.fElements, module.fSymbols, usage.get())) {
Brian Osman0006ad02020-11-18 15:38:39 -0500552 break;
553 }
554 }
555 return fErrorCount == 0;
556}
557
John Stiles0bfeae62021-03-11 09:09:42 -0500558bool Compiler::removeDeadFunctions(Program& program, ProgramUsage* usage) {
559 bool madeChanges = false;
560
561 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
562 auto isDeadFunction = [&](const ProgramElement* element) {
563 if (!element->is<FunctionDefinition>()) {
564 return false;
565 }
566 const FunctionDefinition& fn = element->as<FunctionDefinition>();
John Stilese8da4d22021-03-24 09:19:45 -0400567 if (fn.declaration().isMain() || usage->get(fn.declaration()) > 0) {
John Stiles0bfeae62021-03-11 09:09:42 -0500568 return false;
569 }
570 usage->remove(*element);
571 madeChanges = true;
572 return true;
573 };
574
575 program.fElements.erase(std::remove_if(program.fElements.begin(),
576 program.fElements.end(),
577 [&](const std::unique_ptr<ProgramElement>& element) {
578 return isDeadFunction(element.get());
579 }),
580 program.fElements.end());
581 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
582 program.fSharedElements.end(),
583 isDeadFunction),
584 program.fSharedElements.end());
585 }
586 return madeChanges;
587}
588
589bool Compiler::removeDeadGlobalVariables(Program& program, ProgramUsage* usage) {
590 bool madeChanges = false;
591
592 if (program.fConfig->fSettings.fRemoveDeadVariables) {
593 auto isDeadVariable = [&](const ProgramElement* element) {
594 if (!element->is<GlobalVarDeclaration>()) {
595 return false;
596 }
597 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
598 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
599 if (!usage->isDead(varDecl.var())) {
600 return false;
601 }
602 madeChanges = true;
603 return true;
604 };
605
606 program.fElements.erase(std::remove_if(program.fElements.begin(),
607 program.fElements.end(),
608 [&](const std::unique_ptr<ProgramElement>& element) {
609 return isDeadVariable(element.get());
610 }),
611 program.fElements.end());
612 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
613 program.fSharedElements.end(),
614 isDeadVariable),
615 program.fSharedElements.end());
616 }
617 return madeChanges;
618}
619
John Stiles26541872021-03-16 12:19:54 -0400620bool Compiler::removeDeadLocalVariables(Program& program, ProgramUsage* usage) {
621 class DeadLocalVariableEliminator : public ProgramWriter {
622 public:
623 DeadLocalVariableEliminator(const Context& context, ProgramUsage* usage)
624 : fContext(context)
625 , fUsage(usage) {}
626
627 using ProgramWriter::visitProgramElement;
628
629 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
630 // We don't need to look inside expressions at all.
631 return false;
632 }
633
634 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
635 if (stmt->is<VarDeclaration>()) {
636 VarDeclaration& varDecl = stmt->as<VarDeclaration>();
637 const Variable* var = &varDecl.var();
638 ProgramUsage::VariableCounts* counts = fUsage->fVariableCounts.find(var);
639 SkASSERT(counts);
640 SkASSERT(counts->fDeclared);
641 if (CanEliminate(var, *counts)) {
642 if (var->initialValue()) {
643 // The variable has an initial-value expression, which might have side
644 // effects. ExpressionStatement::Make will preserve side effects, but
645 // replaces pure expressions with Nop.
646 fUsage->remove(stmt.get());
647 stmt = ExpressionStatement::Make(fContext, std::move(varDecl.value()));
648 fUsage->add(stmt.get());
649 } else {
650 // The variable has no initial-value and can be cleanly eliminated.
651 fUsage->remove(stmt.get());
652 stmt = std::make_unique<Nop>();
653 }
654 fMadeChanges = true;
655 }
656 return false;
657 }
658 return INHERITED::visitStatementPtr(stmt);
659 }
660
661 static bool CanEliminate(const Variable* var, const ProgramUsage::VariableCounts& counts) {
662 if (!counts.fDeclared || counts.fRead || var->storage() != VariableStorage::kLocal) {
663 return false;
664 }
665 if (var->initialValue()) {
666 SkASSERT(counts.fWrite >= 1);
667 return counts.fWrite == 1;
668 } else {
669 return counts.fWrite == 0;
670 }
671 }
672
673 bool fMadeChanges = false;
674 const Context& fContext;
675 ProgramUsage* fUsage;
676
677 using INHERITED = ProgramWriter;
678 };
679
680 DeadLocalVariableEliminator visitor{*fContext, usage};
681
682 if (program.fConfig->fSettings.fRemoveDeadVariables) {
683 for (auto& [var, counts] : usage->fVariableCounts) {
684 if (DeadLocalVariableEliminator::CanEliminate(var, counts)) {
685 // This program contains at least one dead local variable.
686 // Scan the program for any dead local variables and eliminate them all.
687 for (std::unique_ptr<ProgramElement>& pe : program.ownedElements()) {
688 if (pe->is<FunctionDefinition>()) {
689 visitor.visitProgramElement(*pe);
690 }
691 }
692 break;
693 }
694 }
695 }
696
697 return visitor.fMadeChanges;
698}
699
Ethan Nicholas00543112018-07-31 09:44:36 -0400700bool Compiler::optimize(Program& program) {
John Stiles7247b482021-03-08 10:40:35 -0500701 // The optimizer only needs to run when it is enabled.
702 if (!program.fConfig->fSettings.fOptimize) {
703 return true;
704 }
705
Ethan Nicholas00543112018-07-31 09:44:36 -0400706 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -0400707 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -0400708
John Stilesb6664582021-03-19 09:46:00 -0400709 if (fErrorCount == 0) {
John Stiles87fc6572021-04-01 14:56:34 +0000710 // Run the inliner only once; it is expensive! Multiple passes can occasionally shake out
711 // more wins, but it's diminishing returns.
712 fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400713
John Stilesb6664582021-03-19 09:46:00 -0400714 while (this->removeDeadFunctions(program, usage)) {
715 // Removing dead functions may cause more functions to become unreferenced. Try again.
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400716 }
John Stilesb6664582021-03-19 09:46:00 -0400717 while (this->removeDeadLocalVariables(program, usage)) {
718 // Removing dead variables may cause more variables to become unreferenced. Try again.
719 }
720 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
721 this->removeDeadGlobalVariables(program, usage);
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500722 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400723 }
John Stilesbb1505f2021-02-12 09:17:53 -0500724
725 if (fErrorCount == 0) {
726 this->verifyStaticTests(program);
727 }
728
Ethan Nicholas00543112018-07-31 09:44:36 -0400729 return fErrorCount == 0;
730}
731
Brian Osmanfb32ddf2019-06-18 10:14:20 -0400732#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
733
Ethan Nicholas00543112018-07-31 09:44:36 -0400734bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400735 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toSPIRV");
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400736#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400737 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -0400738 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400739 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400740 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -0500741 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400742 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400743 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400744 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500745 String errors;
746 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
747 const char* m) {
748 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400749 };
750 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500751
752 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
753 // explaining the error. In standalone mode (skslc), we will send the message, plus the
754 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
755 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
756
757 if (!result) {
758#if defined(SKSL_STANDALONE)
759 // Convert the string-stream to a SPIR-V disassembly.
760 std::string disassembly;
761 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
762 errors.append(disassembly);
763 }
764 this->error(-1, errors);
765#else
766 SkDEBUGFAILF("%s", errors.c_str());
767#endif
768 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400769 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400770 }
771#else
Brian Osman88cda172020-10-09 12:05:16 -0400772 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400773 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500774 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400775#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -0500776 return result;
777}
778
Ethan Nicholas00543112018-07-31 09:44:36 -0400779bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400780 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500781 bool result = this->toSPIRV(program, buffer);
782 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400783 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500784 }
785 return result;
786}
787
Ethan Nicholas00543112018-07-31 09:44:36 -0400788bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400789 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -0400790 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400791 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500792 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500793 return result;
794}
795
Ethan Nicholas00543112018-07-31 09:44:36 -0400796bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400797 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500798 bool result = this->toGLSL(program, buffer);
799 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400800 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500801 }
802 return result;
803}
804
Brian Osmanc0243912020-02-19 15:35:26 -0500805bool Compiler::toHLSL(Program& program, String* out) {
806 String spirv;
807 if (!this->toSPIRV(program, &spirv)) {
808 return false;
809 }
810
811 return SPIRVtoHLSL(spirv, out);
812}
813
Ethan Nicholas00543112018-07-31 09:44:36 -0400814bool Compiler::toMetal(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400815 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toMetal");
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400816 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -0400817 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -0400818 return result;
819}
820
Ethan Nicholas00543112018-07-31 09:44:36 -0400821bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -0400822 StringStream buffer;
823 bool result = this->toMetal(program, buffer);
824 if (result) {
825 *out = buffer.str();
826 }
827 return result;
828}
829
Greg Daniela28ea672020-09-25 11:12:56 -0400830#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400831bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400832 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400833 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400834 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400835 return result;
836}
837
John Stiles82ab3402021-04-13 17:13:03 -0400838bool Compiler::toDSLCPP(Program& program, String name, OutputStream& out) {
839 AutoSource as(this, program.fSource.get());
840 DSLCPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
841 bool result = cg.generateCode();
842 return result;
843}
844
Ethan Nicholas00543112018-07-31 09:44:36 -0400845bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400846 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400847 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400848 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -0400849 return result;
850}
Greg Daniela28ea672020-09-25 11:12:56 -0400851#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400852
Ethan Nicholas2a479a52020-08-18 16:29:45 -0400853#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -0400854
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700855Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -0500856 if (fSource && offset >= 0) {
857 int line = 1;
858 int column = 1;
859 for (int i = 0; i < offset; i++) {
860 if ((*fSource)[i] == '\n') {
861 ++line;
862 column = 1;
863 }
864 else {
865 ++column;
866 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700867 }
Ethan Nicholas3c729892020-12-07 12:47:17 -0500868 return Position(line, column);
869 } else {
870 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700871 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700872}
873
874void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700875 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700876 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -0500877 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -0500878 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -0700879}
880
John Stiles8d3642e2021-01-22 09:50:04 -0500881void Compiler::setErrorCount(int c) {
882 if (c < fErrorCount) {
883 fErrorText.resize(fErrorTextLength[c]);
884 fErrorTextLength.resize(c);
885 fErrorCount = c;
886 }
887}
888
Ethan Nicholas95046142021-01-07 10:57:27 -0500889String Compiler::errorText(bool showCount) {
890 if (showCount) {
891 this->writeErrorCount();
892 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400893 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400894 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -0500895 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -0700896 return result;
897}
898
899void Compiler::writeErrorCount() {
900 if (fErrorCount) {
901 fErrorText += to_string(fErrorCount) + " error";
902 if (fErrorCount > 1) {
903 fErrorText += "s";
904 }
905 fErrorText += "\n";
906 }
907}
908
John Stilesa6841be2020-08-06 14:11:56 -0400909} // namespace SkSL