blob: cc01495433eff2c1f7789793d40179f022da6ee9 [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
136 TYPE(FragmentProcessor),
137 };
138
139 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500140 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
141 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
142 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
143 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
144 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
145
146 TYPE(GenUType), TYPE(UVec),
147 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
148
Brian Osmanc0f2b642020-12-22 13:35:55 -0500149 TYPE(Float2x3), TYPE(Float2x4),
150 TYPE(Float3x2), TYPE(Float3x4),
151 TYPE(Float4x2), TYPE(Float4x3),
152
Brian Osmanc63f4312020-12-23 11:44:14 -0500153 TYPE(Half2x3), TYPE(Half2x4),
154 TYPE(Half3x2), TYPE(Half3x4),
155 TYPE(Half4x2), TYPE(Half4x3),
156
Brian Osmanc0f2b642020-12-22 13:35:55 -0500157 TYPE(Mat), TYPE(HMat),
158
Brian Osmanb06301e2020-11-06 11:45:36 -0500159 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
160 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500161 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500162
163 TYPE(ISampler2D),
Brian Osmanb06301e2020-11-06 11:45:36 -0500164 TYPE(SubpassInput), TYPE(SubpassInputMS),
165
Brian Osmanb06301e2020-11-06 11:45:36 -0500166 TYPE(Sampler),
167 TYPE(Texture2D),
168 };
169
170 for (const SkSL::Symbol* type : rootTypes) {
171 fRootSymbolTable->addWithoutOwnership(type);
172 }
173 for (const SkSL::Symbol* type : privateTypes) {
174 fPrivateSymbolTable->addWithoutOwnership(type);
175 }
176
177#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700178
Brian Osman3887a012020-09-30 13:22:27 -0400179 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
180 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500181 fPrivateSymbolTable->add(
182 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500183 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500184 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500185 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500186 /*builtin=*/false,
187 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500188
Brian Osman3d87e9f2020-10-08 11:50:22 -0400189 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500190 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700191}
192
John Stilesdd13dba2020-10-29 10:45:34 -0400193Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700194
Brian Osman56269982020-11-20 12:38:07 -0500195const ParsedModule& Compiler::loadGPUModule() {
196 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500197 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500198 }
199 return fGPUModule;
200}
201
202const ParsedModule& Compiler::loadFragmentModule() {
203 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500204 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500205 this->loadGPUModule());
206 }
207 return fFragmentModule;
208}
209
210const ParsedModule& Compiler::loadVertexModule() {
211 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500212 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500213 this->loadGPUModule());
214 }
215 return fVertexModule;
216}
217
Brian Osman88cda172020-10-09 12:05:16 -0400218const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400219 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500220 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500221 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400222 }
Brian Osman88cda172020-10-09 12:05:16 -0400223 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400224}
225
Brian Osman88cda172020-10-09 12:05:16 -0400226const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400227 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500228 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500229 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400230 }
Brian Osman88cda172020-10-09 12:05:16 -0400231 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400232}
233
Brian Osmanb06301e2020-11-06 11:45:36 -0500234const ParsedModule& Compiler::loadPublicModule() {
235 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500236 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500237 }
238 return fPublicModule;
239}
240
Brian Osman91946752020-12-21 13:20:40 -0500241const ParsedModule& Compiler::loadRuntimeEffectModule() {
242 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500243 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500244 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400245
Brian Osman91946752020-12-21 13:20:40 -0500246 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500247 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400248
John Stiles54e7c052021-01-11 14:22:36 -0500249 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
250 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
251 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400252
John Stiles54e7c052021-01-11 14:22:36 -0500253 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
254 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
255 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400256
John Stiles54e7c052021-01-11 14:22:36 -0500257 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
258 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
259 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400260 }
Brian Osman91946752020-12-21 13:20:40 -0500261 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400262}
263
John Stilesdbd4e6f2021-02-16 13:29:15 -0500264const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400265 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500266 case ProgramKind::kVertex: return this->loadVertexModule(); break;
267 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
268 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
269 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
270 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
271 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400272 }
273 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400274}
275
John Stilesdbd4e6f2021-02-16 13:29:15 -0500276LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400277 ModuleData data,
John Stilesa935c3f2021-02-25 10:35:49 -0500278 std::shared_ptr<SymbolTable> base,
279 bool dehydrate) {
280 if (dehydrate) {
281 // NOTE: This is a workaround. When dehydrating includes, skslc doesn't know which module
282 // it's preparing, nor what the correct base module is. We can't use 'Root', because many
283 // GPU intrinsics reference private types, like samplers or textures. Today, 'Private' does
284 // contain the union of all known types, so this is safe. If we ever have types that only
285 // exist in 'Public' (for example), this logic needs to be smarter (by choosing the correct
286 // base for the module we're compiling).
Brian Osmanb06301e2020-11-06 11:45:36 -0500287 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400288 }
John Stilesa935c3f2021-02-25 10:35:49 -0500289 SkASSERT(base);
290
291 // Built-in modules always use default program settings.
292 ProgramConfig config;
293 config.fKind = kind;
294 config.fSettings.fReplaceSettings = !dehydrate;
295 AutoProgramConfig autoConfig(fContext, &config);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400296
297#if defined(SKSL_STANDALONE)
298 SkASSERT(data.fPath);
299 std::ifstream in(data.fPath);
John Stilesd51c9792021-03-18 11:40:14 -0400300 String text{std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()};
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400301 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400302 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400303 abort();
304 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400305 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400306 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500307
John Stiles881a10c2020-09-19 10:13:24 -0400308 SkASSERT(fIRGenerator->fCanInline);
309 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500310
Brian Osman88cda172020-10-09 12:05:16 -0400311 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500312 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
313 source->c_str(), source->length(),
314 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400315 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500316 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400317 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400318 if (this->fErrorCount) {
319 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400320 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400321 }
Brian Osman88cda172020-10-09 12:05:16 -0400322 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400323#else
324 SkASSERT(data.fData && (data.fSize != 0));
325 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
326 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500327 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400328 fModifiers.push_back(fIRGenerator->releaseModifiers());
329#endif
330
331 return module;
332}
333
John Stilesdbd4e6f2021-02-16 13:29:15 -0500334ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500335 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500336 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400337
338 // For modules that just declare (but don't define) intrinsic functions, there will be no new
339 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500340 if (module.fElements.empty()) {
341 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400342 }
343
344 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
345
346 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
347 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500348 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400349 switch (element->kind()) {
350 case ProgramElement::Kind::kFunction: {
351 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400352 SkASSERT(f.declaration().isBuiltin());
353 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400354 break;
355 }
John Stiles569249b2020-11-03 12:18:22 -0500356 case ProgramElement::Kind::kFunctionPrototype: {
357 // These are already in the symbol table.
358 break;
359 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400360 case ProgramElement::Kind::kEnum: {
361 const Enum& e = element->as<Enum>();
362 SkASSERT(e.isBuiltin());
363 intrinsics->insertOrDie(e.typeName(), std::move(element));
364 break;
365 }
366 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400367 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
368 const Variable& var = global.declaration()->as<VarDeclaration>().var();
369 SkASSERT(var.isBuiltin());
370 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400371 break;
372 }
373 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400374 const Variable& var = element->as<InterfaceBlock>().variable();
375 SkASSERT(var.isBuiltin());
376 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400377 break;
378 }
379 default:
380 printf("Unsupported element: %s\n", element->description().c_str());
381 SkASSERT(false);
382 break;
383 }
384 }
385
Brian Osman0006ad02020-11-18 15:38:39 -0500386 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400387}
388
Brian Osman32d53552020-09-23 13:55:20 -0400389std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -0500390 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -0400391 String text,
392 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500393 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400394 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -0500395
John Stilesdbd4e6f2021-02-16 13:29:15 -0500396 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400397
Brian Osman0006ad02020-11-18 15:38:39 -0500398 // Loading and optimizing our base module might reset the inliner, so do that first,
399 // *then* configure the inliner with the settings for this program.
400 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
401
John Stiles270cec22021-02-17 12:59:36 -0500402 // Update our context to point to the program configuration for the duration of compilation.
403 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -0500404 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -0500405
John Stiles2ee4d7a2021-03-30 10:30:47 -0400406 // Honor our optimization-override flags.
407 switch (sOptimizer) {
408 case OverrideFlag::kDefault:
409 break;
410 case OverrideFlag::kOff:
411 config->fSettings.fOptimize = false;
412 break;
413 case OverrideFlag::kOn:
414 config->fSettings.fOptimize = true;
415 break;
416 }
417
418 switch (sInliner) {
419 case OverrideFlag::kDefault:
420 break;
421 case OverrideFlag::kOff:
422 config->fSettings.fInlineThreshold = 0;
423 break;
424 case OverrideFlag::kOn:
425 if (config->fSettings.fInlineThreshold == 0) {
426 config->fSettings.fInlineThreshold = kDefaultInlineThreshold;
427 }
428 break;
429 }
John Stiles7247b482021-03-08 10:40:35 -0500430
431 // Disable optimization settings that depend on a parent setting which has been disabled.
John Stiles7247b482021-03-08 10:40:35 -0500432 config->fSettings.fInlineThreshold *= (int)config->fSettings.fOptimize;
John Stiles0bfeae62021-03-11 09:09:42 -0500433 config->fSettings.fRemoveDeadFunctions &= config->fSettings.fOptimize;
434 config->fSettings.fRemoveDeadVariables &= config->fSettings.fOptimize;
John Stiles7247b482021-03-08 10:40:35 -0500435
ethannicholasb3058bd2016-07-01 08:22:01 -0700436 fErrorText = "";
437 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -0500438 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -0400439
440 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700441 std::unique_ptr<String> textPtr(new String(std::move(text)));
442 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -0400443
John Stiles5c7bb322020-10-22 11:09:15 -0400444 // Enable node pooling while converting and optimizing the program for a performance boost.
445 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -0500446 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -0500447 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -0500448 pool = Pool::Create();
449 pool->attachToThread();
450 }
John Stilesd1204642021-02-17 16:30:02 -0500451 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
452 textPtr->c_str(), textPtr->size(),
453 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -0500454 auto program = std::make_unique<Program>(std::move(textPtr),
455 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -0400456 fContext,
457 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -0400458 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -0400459 std::move(ir.fModifiers),
460 std::move(ir.fSymbolTable),
461 std::move(pool),
462 ir.fInputs);
463 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500464 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -0400465 // Do not return programs that failed to compile.
John Stiles7247b482021-03-08 10:40:35 -0500466 } else if (!this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -0400467 // Do not return programs that failed to optimize.
468 } else {
469 // We have a successful program!
470 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500471 }
John Stiles5c7bb322020-10-22 11:09:15 -0400472
Brian Osman28f702c2021-02-02 11:52:07 -0500473 if (program->fPool) {
474 program->fPool->detachFromThread();
475 }
John Stiles5c7bb322020-10-22 11:09:15 -0400476 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500477}
478
John Stilesbb1505f2021-02-12 09:17:53 -0500479void Compiler::verifyStaticTests(const Program& program) {
480 class StaticTestVerifier : public ProgramVisitor {
481 public:
482 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
483
484 using ProgramVisitor::visitProgramElement;
485
486 bool visitStatement(const Statement& stmt) override {
487 switch (stmt.kind()) {
488 case Statement::Kind::kIf:
489 if (stmt.as<IfStatement>().isStatic()) {
490 fReporter->error(stmt.fOffset, "static if has non-static test");
491 }
492 break;
493
494 case Statement::Kind::kSwitch:
495 if (stmt.as<SwitchStatement>().isStatic()) {
496 fReporter->error(stmt.fOffset, "static switch has non-static test");
497 }
498 break;
499
500 default:
501 break;
502 }
503 return INHERITED::visitStatement(stmt);
504 }
505
John Stiles59e34562021-02-12 16:56:39 -0500506 bool visitExpression(const Expression&) override {
507 // We aren't looking for anything inside an Expression, so skip them entirely.
508 return false;
509 }
510
John Stilesbb1505f2021-02-12 09:17:53 -0500511 private:
512 using INHERITED = ProgramVisitor;
513 ErrorReporter* fReporter;
514 };
515
516 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -0500517 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -0500518 return;
519 }
520
521 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
522 StaticTestVerifier visitor{this};
523 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
524 if (element->is<FunctionDefinition>()) {
525 visitor.visitProgramElement(*element);
526 }
527 }
528}
529
Brian Osman0006ad02020-11-18 15:38:39 -0500530bool Compiler::optimize(LoadedModule& module) {
531 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -0500532
John Stiles270cec22021-02-17 12:59:36 -0500533 // Create a temporary program configuration with default settings.
534 ProgramConfig config;
535 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -0500536 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -0500537
John Stilesd1204642021-02-17 16:30:02 -0500538 // Reset the Inliner.
539 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -0500540
541 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -0500542
543 while (fErrorCount == 0) {
Brian Osman0006ad02020-11-18 15:38:39 -0500544 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stilesf3a28db2021-03-10 23:00:47 -0500545 if (!fInliner.analyze(module.fElements, module.fSymbols, usage.get())) {
Brian Osman0006ad02020-11-18 15:38:39 -0500546 break;
547 }
548 }
549 return fErrorCount == 0;
550}
551
John Stiles0bfeae62021-03-11 09:09:42 -0500552bool Compiler::removeDeadFunctions(Program& program, ProgramUsage* usage) {
553 bool madeChanges = false;
554
555 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
556 auto isDeadFunction = [&](const ProgramElement* element) {
557 if (!element->is<FunctionDefinition>()) {
558 return false;
559 }
560 const FunctionDefinition& fn = element->as<FunctionDefinition>();
John Stilese8da4d22021-03-24 09:19:45 -0400561 if (fn.declaration().isMain() || usage->get(fn.declaration()) > 0) {
John Stiles0bfeae62021-03-11 09:09:42 -0500562 return false;
563 }
564 usage->remove(*element);
565 madeChanges = true;
566 return true;
567 };
568
569 program.fElements.erase(std::remove_if(program.fElements.begin(),
570 program.fElements.end(),
571 [&](const std::unique_ptr<ProgramElement>& element) {
572 return isDeadFunction(element.get());
573 }),
574 program.fElements.end());
575 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
576 program.fSharedElements.end(),
577 isDeadFunction),
578 program.fSharedElements.end());
579 }
580 return madeChanges;
581}
582
583bool Compiler::removeDeadGlobalVariables(Program& program, ProgramUsage* usage) {
584 bool madeChanges = false;
585
586 if (program.fConfig->fSettings.fRemoveDeadVariables) {
587 auto isDeadVariable = [&](const ProgramElement* element) {
588 if (!element->is<GlobalVarDeclaration>()) {
589 return false;
590 }
591 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
592 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
593 if (!usage->isDead(varDecl.var())) {
594 return false;
595 }
596 madeChanges = true;
597 return true;
598 };
599
600 program.fElements.erase(std::remove_if(program.fElements.begin(),
601 program.fElements.end(),
602 [&](const std::unique_ptr<ProgramElement>& element) {
603 return isDeadVariable(element.get());
604 }),
605 program.fElements.end());
606 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
607 program.fSharedElements.end(),
608 isDeadVariable),
609 program.fSharedElements.end());
610 }
611 return madeChanges;
612}
613
John Stiles26541872021-03-16 12:19:54 -0400614bool Compiler::removeDeadLocalVariables(Program& program, ProgramUsage* usage) {
615 class DeadLocalVariableEliminator : public ProgramWriter {
616 public:
617 DeadLocalVariableEliminator(const Context& context, ProgramUsage* usage)
618 : fContext(context)
619 , fUsage(usage) {}
620
621 using ProgramWriter::visitProgramElement;
622
623 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
624 // We don't need to look inside expressions at all.
625 return false;
626 }
627
628 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
629 if (stmt->is<VarDeclaration>()) {
630 VarDeclaration& varDecl = stmt->as<VarDeclaration>();
631 const Variable* var = &varDecl.var();
632 ProgramUsage::VariableCounts* counts = fUsage->fVariableCounts.find(var);
633 SkASSERT(counts);
634 SkASSERT(counts->fDeclared);
635 if (CanEliminate(var, *counts)) {
636 if (var->initialValue()) {
637 // The variable has an initial-value expression, which might have side
638 // effects. ExpressionStatement::Make will preserve side effects, but
639 // replaces pure expressions with Nop.
640 fUsage->remove(stmt.get());
641 stmt = ExpressionStatement::Make(fContext, std::move(varDecl.value()));
642 fUsage->add(stmt.get());
643 } else {
644 // The variable has no initial-value and can be cleanly eliminated.
645 fUsage->remove(stmt.get());
646 stmt = std::make_unique<Nop>();
647 }
648 fMadeChanges = true;
649 }
650 return false;
651 }
652 return INHERITED::visitStatementPtr(stmt);
653 }
654
655 static bool CanEliminate(const Variable* var, const ProgramUsage::VariableCounts& counts) {
656 if (!counts.fDeclared || counts.fRead || var->storage() != VariableStorage::kLocal) {
657 return false;
658 }
659 if (var->initialValue()) {
660 SkASSERT(counts.fWrite >= 1);
661 return counts.fWrite == 1;
662 } else {
663 return counts.fWrite == 0;
664 }
665 }
666
667 bool fMadeChanges = false;
668 const Context& fContext;
669 ProgramUsage* fUsage;
670
671 using INHERITED = ProgramWriter;
672 };
673
674 DeadLocalVariableEliminator visitor{*fContext, usage};
675
676 if (program.fConfig->fSettings.fRemoveDeadVariables) {
677 for (auto& [var, counts] : usage->fVariableCounts) {
678 if (DeadLocalVariableEliminator::CanEliminate(var, counts)) {
679 // This program contains at least one dead local variable.
680 // Scan the program for any dead local variables and eliminate them all.
681 for (std::unique_ptr<ProgramElement>& pe : program.ownedElements()) {
682 if (pe->is<FunctionDefinition>()) {
683 visitor.visitProgramElement(*pe);
684 }
685 }
686 break;
687 }
688 }
689 }
690
691 return visitor.fMadeChanges;
692}
693
Ethan Nicholas00543112018-07-31 09:44:36 -0400694bool Compiler::optimize(Program& program) {
John Stiles7247b482021-03-08 10:40:35 -0500695 // The optimizer only needs to run when it is enabled.
696 if (!program.fConfig->fSettings.fOptimize) {
697 return true;
698 }
699
Ethan Nicholas00543112018-07-31 09:44:36 -0400700 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -0400701 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -0400702
John Stilesb6664582021-03-19 09:46:00 -0400703 if (fErrorCount == 0) {
John Stiles87fc6572021-04-01 14:56:34 +0000704 // Run the inliner only once; it is expensive! Multiple passes can occasionally shake out
705 // more wins, but it's diminishing returns.
706 fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400707
John Stilesb6664582021-03-19 09:46:00 -0400708 while (this->removeDeadFunctions(program, usage)) {
709 // Removing dead functions may cause more functions to become unreferenced. Try again.
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400710 }
John Stilesb6664582021-03-19 09:46:00 -0400711 while (this->removeDeadLocalVariables(program, usage)) {
712 // Removing dead variables may cause more variables to become unreferenced. Try again.
713 }
714 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
715 this->removeDeadGlobalVariables(program, usage);
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500716 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400717 }
John Stilesbb1505f2021-02-12 09:17:53 -0500718
719 if (fErrorCount == 0) {
720 this->verifyStaticTests(program);
721 }
722
Ethan Nicholas00543112018-07-31 09:44:36 -0400723 return fErrorCount == 0;
724}
725
Brian Osmanfb32ddf2019-06-18 10:14:20 -0400726#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
727
Ethan Nicholas00543112018-07-31 09:44:36 -0400728bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400729 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toSPIRV");
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400730#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400731 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -0400732 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400733 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400734 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -0500735 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400736 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400737 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400738 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500739 String errors;
740 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
741 const char* m) {
742 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400743 };
744 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500745
746 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
747 // explaining the error. In standalone mode (skslc), we will send the message, plus the
748 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
749 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
750
751 if (!result) {
752#if defined(SKSL_STANDALONE)
753 // Convert the string-stream to a SPIR-V disassembly.
754 std::string disassembly;
755 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
756 errors.append(disassembly);
757 }
758 this->error(-1, errors);
759#else
760 SkDEBUGFAILF("%s", errors.c_str());
761#endif
762 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400763 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400764 }
765#else
Brian Osman88cda172020-10-09 12:05:16 -0400766 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400767 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500768 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400769#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -0500770 return result;
771}
772
Ethan Nicholas00543112018-07-31 09:44:36 -0400773bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400774 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500775 bool result = this->toSPIRV(program, buffer);
776 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400777 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500778 }
779 return result;
780}
781
Ethan Nicholas00543112018-07-31 09:44:36 -0400782bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400783 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -0400784 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400785 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500786 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500787 return result;
788}
789
Ethan Nicholas00543112018-07-31 09:44:36 -0400790bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400791 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500792 bool result = this->toGLSL(program, buffer);
793 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400794 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500795 }
796 return result;
797}
798
Brian Osmanc0243912020-02-19 15:35:26 -0500799bool Compiler::toHLSL(Program& program, String* out) {
800 String spirv;
801 if (!this->toSPIRV(program, &spirv)) {
802 return false;
803 }
804
805 return SPIRVtoHLSL(spirv, out);
806}
807
Ethan Nicholas00543112018-07-31 09:44:36 -0400808bool Compiler::toMetal(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400809 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toMetal");
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400810 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -0400811 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -0400812 return result;
813}
814
Ethan Nicholas00543112018-07-31 09:44:36 -0400815bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -0400816 StringStream buffer;
817 bool result = this->toMetal(program, buffer);
818 if (result) {
819 *out = buffer.str();
820 }
821 return result;
822}
823
Greg Daniela28ea672020-09-25 11:12:56 -0400824#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400825bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400826 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400827 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400828 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400829 return result;
830}
831
Ethan Nicholas00543112018-07-31 09:44:36 -0400832bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400833 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400834 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400835 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -0400836 return result;
837}
Greg Daniela28ea672020-09-25 11:12:56 -0400838#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400839
Ethan Nicholas2a479a52020-08-18 16:29:45 -0400840#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -0400841
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700842Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -0500843 if (fSource && offset >= 0) {
844 int line = 1;
845 int column = 1;
846 for (int i = 0; i < offset; i++) {
847 if ((*fSource)[i] == '\n') {
848 ++line;
849 column = 1;
850 }
851 else {
852 ++column;
853 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700854 }
Ethan Nicholas3c729892020-12-07 12:47:17 -0500855 return Position(line, column);
856 } else {
857 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700858 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700859}
860
861void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700862 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700863 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -0500864 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -0500865 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -0700866}
867
John Stiles8d3642e2021-01-22 09:50:04 -0500868void Compiler::setErrorCount(int c) {
869 if (c < fErrorCount) {
870 fErrorText.resize(fErrorTextLength[c]);
871 fErrorTextLength.resize(c);
872 fErrorCount = c;
873 }
874}
875
Ethan Nicholas95046142021-01-07 10:57:27 -0500876String Compiler::errorText(bool showCount) {
877 if (showCount) {
878 this->writeErrorCount();
879 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400880 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400881 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -0500882 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -0700883 return result;
884}
885
886void Compiler::writeErrorCount() {
887 if (fErrorCount) {
888 fErrorText += to_string(fErrorCount) + " error";
889 if (fErrorCount > 1) {
890 fErrorText += "s";
891 }
892 fErrorText += "\n";
893 }
894}
895
John Stilesa6841be2020-08-06 14:11:56 -0400896} // namespace SkSL