blob: 3fe29ad4f704567882a1b32ed7324e9431cbe7bf [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// Set these flags to `false` to disable optimization passes unilaterally.
76// These flags allow tools like Viewer or Nanobench to override the compiler's ProgramSettings.
77bool gSkSLOptimizer = true;
78bool gSkSLInliner = true;
John Stiles0bfeae62021-03-11 09:09:42 -050079bool gSkSLDeadCodeElimination = true;
John Stiles8ef4d6c2021-03-05 16:01:45 -050080
John Stiles47c0a742021-02-09 09:30:35 -050081using RefKind = VariableReference::RefKind;
82
Brian Osman88cda172020-10-09 12:05:16 -040083class AutoSource {
84public:
85 AutoSource(Compiler* compiler, const String* source)
86 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
87 fCompiler->fSource = source;
88 }
89
90 ~AutoSource() { fCompiler->fSource = fOldSource; }
91
92 Compiler* fCompiler;
93 const String* fOldSource;
94};
95
John Stilesa935c3f2021-02-25 10:35:49 -050096class AutoProgramConfig {
97public:
98 AutoProgramConfig(std::shared_ptr<Context>& context, ProgramConfig* config)
99 : fContext(context.get()) {
100 SkASSERT(!fContext->fConfig);
101 fContext->fConfig = config;
102 }
103
104 ~AutoProgramConfig() {
105 fContext->fConfig = nullptr;
106 }
107
108 Context* fContext;
109};
110
John Stilesd6a5f4492021-02-11 15:46:11 -0500111Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesc1a98b82021-02-24 13:35:02 -0500112 : fContext(std::make_shared<Context>(/*errors=*/*this, *caps))
John Stiles7b920442020-12-17 10:43:41 -0500113 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -0500114 , fErrorCount(0) {
John Stilesc1a98b82021-02-24 13:35:02 -0500115 SkASSERT(caps);
John Stiles7c3515b2020-10-16 18:38:39 -0400116 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -0500117 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesc1a98b82021-02-24 13:35:02 -0500118 fIRGenerator = std::make_unique<IRGenerator>(fContext.get());
ethannicholasb3058bd2016-07-01 08:22:01 -0700119
John Stiles54e7c052021-01-11 14:22:36 -0500120#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700121
Brian Osmanb06301e2020-11-06 11:45:36 -0500122 const SkSL::Symbol* rootTypes[] = {
123 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500124
Brian Osmanb06301e2020-11-06 11:45:36 -0500125 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
126 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
127 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500128 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500129
Brian Osmanc0f2b642020-12-22 13:35:55 -0500130 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500131 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500132
Brian Osmanc63f4312020-12-23 11:44:14 -0500133 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700134
Brian Osman20fad322020-12-23 12:42:33 -0500135 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
136 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500137
138 TYPE(FragmentProcessor),
139 };
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),
170 };
171
172 for (const SkSL::Symbol* type : rootTypes) {
173 fRootSymbolTable->addWithoutOwnership(type);
174 }
175 for (const SkSL::Symbol* type : privateTypes) {
176 fPrivateSymbolTable->addWithoutOwnership(type);
177 }
178
179#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700180
Brian Osman3887a012020-09-30 13:22:27 -0400181 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
182 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500183 fPrivateSymbolTable->add(
184 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500185 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500186 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500187 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500188 /*builtin=*/false,
189 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500190
Brian Osman3d87e9f2020-10-08 11:50:22 -0400191 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500192 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700193}
194
John Stilesdd13dba2020-10-29 10:45:34 -0400195Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700196
Brian Osman56269982020-11-20 12:38:07 -0500197const ParsedModule& Compiler::loadGPUModule() {
198 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500199 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500200 }
201 return fGPUModule;
202}
203
204const ParsedModule& Compiler::loadFragmentModule() {
205 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500206 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500207 this->loadGPUModule());
208 }
209 return fFragmentModule;
210}
211
212const ParsedModule& Compiler::loadVertexModule() {
213 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500214 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500215 this->loadGPUModule());
216 }
217 return fVertexModule;
218}
219
Brian Osman88cda172020-10-09 12:05:16 -0400220const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400221 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500222 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500223 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400224 }
Brian Osman88cda172020-10-09 12:05:16 -0400225 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400226}
227
Brian Osman88cda172020-10-09 12:05:16 -0400228const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400229 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500230 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500231 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400232 }
Brian Osman88cda172020-10-09 12:05:16 -0400233 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400234}
235
Brian Osmanb06301e2020-11-06 11:45:36 -0500236const ParsedModule& Compiler::loadPublicModule() {
237 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500238 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500239 }
240 return fPublicModule;
241}
242
Brian Osman91946752020-12-21 13:20:40 -0500243const ParsedModule& Compiler::loadRuntimeEffectModule() {
244 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500245 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500246 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400247
Brian Osman91946752020-12-21 13:20:40 -0500248 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500249 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400250
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
John Stiles54e7c052021-01-11 14:22:36 -0500255 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
256 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
257 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400258
John Stiles54e7c052021-01-11 14:22:36 -0500259 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
260 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
261 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400262 }
Brian Osman91946752020-12-21 13:20:40 -0500263 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400264}
265
John Stilesdbd4e6f2021-02-16 13:29:15 -0500266const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400267 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500268 case ProgramKind::kVertex: return this->loadVertexModule(); break;
269 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
270 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
271 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
272 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
273 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400274 }
275 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400276}
277
John Stilesdbd4e6f2021-02-16 13:29:15 -0500278LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400279 ModuleData data,
John Stilesa935c3f2021-02-25 10:35:49 -0500280 std::shared_ptr<SymbolTable> base,
281 bool dehydrate) {
282 if (dehydrate) {
283 // NOTE: This is a workaround. When dehydrating includes, skslc doesn't know which module
284 // it's preparing, nor what the correct base module is. We can't use 'Root', because many
285 // GPU intrinsics reference private types, like samplers or textures. Today, 'Private' does
286 // contain the union of all known types, so this is safe. If we ever have types that only
287 // exist in 'Public' (for example), this logic needs to be smarter (by choosing the correct
288 // base for the module we're compiling).
Brian Osmanb06301e2020-11-06 11:45:36 -0500289 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400290 }
John Stilesa935c3f2021-02-25 10:35:49 -0500291 SkASSERT(base);
292
293 // Built-in modules always use default program settings.
294 ProgramConfig config;
295 config.fKind = kind;
296 config.fSettings.fReplaceSettings = !dehydrate;
297 AutoProgramConfig autoConfig(fContext, &config);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400298
299#if defined(SKSL_STANDALONE)
300 SkASSERT(data.fPath);
301 std::ifstream in(data.fPath);
John Stilesd51c9792021-03-18 11:40:14 -0400302 String text{std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()};
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400303 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400304 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400305 abort();
306 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400307 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400308 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500309
John Stiles881a10c2020-09-19 10:13:24 -0400310 SkASSERT(fIRGenerator->fCanInline);
311 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500312
Brian Osman88cda172020-10-09 12:05:16 -0400313 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500314 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
315 source->c_str(), source->length(),
316 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400317 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500318 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400319 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400320 if (this->fErrorCount) {
321 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400322 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400323 }
Brian Osman88cda172020-10-09 12:05:16 -0400324 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400325#else
326 SkASSERT(data.fData && (data.fSize != 0));
327 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
328 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500329 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400330 fModifiers.push_back(fIRGenerator->releaseModifiers());
331#endif
332
333 return module;
334}
335
John Stilesdbd4e6f2021-02-16 13:29:15 -0500336ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500337 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500338 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400339
340 // For modules that just declare (but don't define) intrinsic functions, there will be no new
341 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500342 if (module.fElements.empty()) {
343 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400344 }
345
346 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
347
348 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
349 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500350 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400351 switch (element->kind()) {
352 case ProgramElement::Kind::kFunction: {
353 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400354 SkASSERT(f.declaration().isBuiltin());
355 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400356 break;
357 }
John Stiles569249b2020-11-03 12:18:22 -0500358 case ProgramElement::Kind::kFunctionPrototype: {
359 // These are already in the symbol table.
360 break;
361 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400362 case ProgramElement::Kind::kEnum: {
363 const Enum& e = element->as<Enum>();
364 SkASSERT(e.isBuiltin());
365 intrinsics->insertOrDie(e.typeName(), std::move(element));
366 break;
367 }
368 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400369 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
370 const Variable& var = global.declaration()->as<VarDeclaration>().var();
371 SkASSERT(var.isBuiltin());
372 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400373 break;
374 }
375 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400376 const Variable& var = element->as<InterfaceBlock>().variable();
377 SkASSERT(var.isBuiltin());
378 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400379 break;
380 }
381 default:
382 printf("Unsupported element: %s\n", element->description().c_str());
383 SkASSERT(false);
384 break;
385 }
386 }
387
Brian Osman0006ad02020-11-18 15:38:39 -0500388 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400389}
390
Brian Osman32d53552020-09-23 13:55:20 -0400391std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -0500392 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -0400393 String text,
394 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500395 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400396 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -0500397
John Stilesdbd4e6f2021-02-16 13:29:15 -0500398 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400399
Brian Osman0006ad02020-11-18 15:38:39 -0500400 // Loading and optimizing our base module might reset the inliner, so do that first,
401 // *then* configure the inliner with the settings for this program.
402 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
403
John Stiles270cec22021-02-17 12:59:36 -0500404 // Update our context to point to the program configuration for the duration of compilation.
405 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -0500406 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -0500407
John Stiles7247b482021-03-08 10:40:35 -0500408 // Honor our global optimization-disable flags.
409 config->fSettings.fOptimize &= gSkSLOptimizer;
John Stiles7247b482021-03-08 10:40:35 -0500410 config->fSettings.fInlineThreshold *= (int)gSkSLInliner;
John Stiles0bfeae62021-03-11 09:09:42 -0500411 config->fSettings.fRemoveDeadVariables &= gSkSLDeadCodeElimination;
412 config->fSettings.fRemoveDeadFunctions &= gSkSLDeadCodeElimination;
John Stiles7247b482021-03-08 10:40:35 -0500413
414 // Disable optimization settings that depend on a parent setting which has been disabled.
John Stiles7247b482021-03-08 10:40:35 -0500415 config->fSettings.fInlineThreshold *= (int)config->fSettings.fOptimize;
John Stiles0bfeae62021-03-11 09:09:42 -0500416 config->fSettings.fRemoveDeadFunctions &= config->fSettings.fOptimize;
417 config->fSettings.fRemoveDeadVariables &= config->fSettings.fOptimize;
John Stiles7247b482021-03-08 10:40:35 -0500418
ethannicholasb3058bd2016-07-01 08:22:01 -0700419 fErrorText = "";
420 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -0500421 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -0400422
423 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700424 std::unique_ptr<String> textPtr(new String(std::move(text)));
425 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -0400426
John Stiles5c7bb322020-10-22 11:09:15 -0400427 // Enable node pooling while converting and optimizing the program for a performance boost.
428 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -0500429 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -0500430 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -0500431 pool = Pool::Create();
432 pool->attachToThread();
433 }
John Stilesd1204642021-02-17 16:30:02 -0500434 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
435 textPtr->c_str(), textPtr->size(),
436 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -0500437 auto program = std::make_unique<Program>(std::move(textPtr),
438 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -0400439 fContext,
440 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -0400441 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -0400442 std::move(ir.fModifiers),
443 std::move(ir.fSymbolTable),
444 std::move(pool),
445 ir.fInputs);
446 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500447 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -0400448 // Do not return programs that failed to compile.
John Stiles7247b482021-03-08 10:40:35 -0500449 } else if (!this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -0400450 // Do not return programs that failed to optimize.
451 } else {
452 // We have a successful program!
453 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500454 }
John Stiles5c7bb322020-10-22 11:09:15 -0400455
Brian Osman28f702c2021-02-02 11:52:07 -0500456 if (program->fPool) {
457 program->fPool->detachFromThread();
458 }
John Stiles5c7bb322020-10-22 11:09:15 -0400459 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500460}
461
John Stilesbb1505f2021-02-12 09:17:53 -0500462void Compiler::verifyStaticTests(const Program& program) {
463 class StaticTestVerifier : public ProgramVisitor {
464 public:
465 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
466
467 using ProgramVisitor::visitProgramElement;
468
469 bool visitStatement(const Statement& stmt) override {
470 switch (stmt.kind()) {
471 case Statement::Kind::kIf:
472 if (stmt.as<IfStatement>().isStatic()) {
473 fReporter->error(stmt.fOffset, "static if has non-static test");
474 }
475 break;
476
477 case Statement::Kind::kSwitch:
478 if (stmt.as<SwitchStatement>().isStatic()) {
479 fReporter->error(stmt.fOffset, "static switch has non-static test");
480 }
481 break;
482
483 default:
484 break;
485 }
486 return INHERITED::visitStatement(stmt);
487 }
488
John Stiles59e34562021-02-12 16:56:39 -0500489 bool visitExpression(const Expression&) override {
490 // We aren't looking for anything inside an Expression, so skip them entirely.
491 return false;
492 }
493
John Stilesbb1505f2021-02-12 09:17:53 -0500494 private:
495 using INHERITED = ProgramVisitor;
496 ErrorReporter* fReporter;
497 };
498
499 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -0500500 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -0500501 return;
502 }
503
504 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
505 StaticTestVerifier visitor{this};
506 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
507 if (element->is<FunctionDefinition>()) {
508 visitor.visitProgramElement(*element);
509 }
510 }
511}
512
Brian Osman0006ad02020-11-18 15:38:39 -0500513bool Compiler::optimize(LoadedModule& module) {
514 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -0500515
John Stiles270cec22021-02-17 12:59:36 -0500516 // Create a temporary program configuration with default settings.
517 ProgramConfig config;
518 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -0500519 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -0500520
John Stilesd1204642021-02-17 16:30:02 -0500521 // Reset the Inliner.
522 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -0500523
524 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -0500525
526 while (fErrorCount == 0) {
Brian Osman0006ad02020-11-18 15:38:39 -0500527 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stilesf3a28db2021-03-10 23:00:47 -0500528 if (!fInliner.analyze(module.fElements, module.fSymbols, usage.get())) {
Brian Osman0006ad02020-11-18 15:38:39 -0500529 break;
530 }
531 }
532 return fErrorCount == 0;
533}
534
John Stiles0bfeae62021-03-11 09:09:42 -0500535bool Compiler::removeDeadFunctions(Program& program, ProgramUsage* usage) {
536 bool madeChanges = false;
537
538 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
539 auto isDeadFunction = [&](const ProgramElement* element) {
540 if (!element->is<FunctionDefinition>()) {
541 return false;
542 }
543 const FunctionDefinition& fn = element->as<FunctionDefinition>();
544 if (fn.declaration().name() == "main" || usage->get(fn.declaration()) > 0) {
545 return false;
546 }
547 usage->remove(*element);
548 madeChanges = true;
549 return true;
550 };
551
552 program.fElements.erase(std::remove_if(program.fElements.begin(),
553 program.fElements.end(),
554 [&](const std::unique_ptr<ProgramElement>& element) {
555 return isDeadFunction(element.get());
556 }),
557 program.fElements.end());
558 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
559 program.fSharedElements.end(),
560 isDeadFunction),
561 program.fSharedElements.end());
562 }
563 return madeChanges;
564}
565
566bool Compiler::removeDeadGlobalVariables(Program& program, ProgramUsage* usage) {
567 bool madeChanges = false;
568
569 if (program.fConfig->fSettings.fRemoveDeadVariables) {
570 auto isDeadVariable = [&](const ProgramElement* element) {
571 if (!element->is<GlobalVarDeclaration>()) {
572 return false;
573 }
574 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
575 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
576 if (!usage->isDead(varDecl.var())) {
577 return false;
578 }
579 madeChanges = true;
580 return true;
581 };
582
583 program.fElements.erase(std::remove_if(program.fElements.begin(),
584 program.fElements.end(),
585 [&](const std::unique_ptr<ProgramElement>& element) {
586 return isDeadVariable(element.get());
587 }),
588 program.fElements.end());
589 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
590 program.fSharedElements.end(),
591 isDeadVariable),
592 program.fSharedElements.end());
593 }
594 return madeChanges;
595}
596
John Stiles26541872021-03-16 12:19:54 -0400597bool Compiler::removeDeadLocalVariables(Program& program, ProgramUsage* usage) {
598 class DeadLocalVariableEliminator : public ProgramWriter {
599 public:
600 DeadLocalVariableEliminator(const Context& context, ProgramUsage* usage)
601 : fContext(context)
602 , fUsage(usage) {}
603
604 using ProgramWriter::visitProgramElement;
605
606 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
607 // We don't need to look inside expressions at all.
608 return false;
609 }
610
611 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
612 if (stmt->is<VarDeclaration>()) {
613 VarDeclaration& varDecl = stmt->as<VarDeclaration>();
614 const Variable* var = &varDecl.var();
615 ProgramUsage::VariableCounts* counts = fUsage->fVariableCounts.find(var);
616 SkASSERT(counts);
617 SkASSERT(counts->fDeclared);
618 if (CanEliminate(var, *counts)) {
619 if (var->initialValue()) {
620 // The variable has an initial-value expression, which might have side
621 // effects. ExpressionStatement::Make will preserve side effects, but
622 // replaces pure expressions with Nop.
623 fUsage->remove(stmt.get());
624 stmt = ExpressionStatement::Make(fContext, std::move(varDecl.value()));
625 fUsage->add(stmt.get());
626 } else {
627 // The variable has no initial-value and can be cleanly eliminated.
628 fUsage->remove(stmt.get());
629 stmt = std::make_unique<Nop>();
630 }
631 fMadeChanges = true;
632 }
633 return false;
634 }
635 return INHERITED::visitStatementPtr(stmt);
636 }
637
638 static bool CanEliminate(const Variable* var, const ProgramUsage::VariableCounts& counts) {
639 if (!counts.fDeclared || counts.fRead || var->storage() != VariableStorage::kLocal) {
640 return false;
641 }
642 if (var->initialValue()) {
643 SkASSERT(counts.fWrite >= 1);
644 return counts.fWrite == 1;
645 } else {
646 return counts.fWrite == 0;
647 }
648 }
649
650 bool fMadeChanges = false;
651 const Context& fContext;
652 ProgramUsage* fUsage;
653
654 using INHERITED = ProgramWriter;
655 };
656
657 DeadLocalVariableEliminator visitor{*fContext, usage};
658
659 if (program.fConfig->fSettings.fRemoveDeadVariables) {
660 for (auto& [var, counts] : usage->fVariableCounts) {
661 if (DeadLocalVariableEliminator::CanEliminate(var, counts)) {
662 // This program contains at least one dead local variable.
663 // Scan the program for any dead local variables and eliminate them all.
664 for (std::unique_ptr<ProgramElement>& pe : program.ownedElements()) {
665 if (pe->is<FunctionDefinition>()) {
666 visitor.visitProgramElement(*pe);
667 }
668 }
669 break;
670 }
671 }
672 }
673
674 return visitor.fMadeChanges;
675}
676
Ethan Nicholas00543112018-07-31 09:44:36 -0400677bool Compiler::optimize(Program& program) {
John Stiles7247b482021-03-08 10:40:35 -0500678 // The optimizer only needs to run when it is enabled.
679 if (!program.fConfig->fSettings.fOptimize) {
680 return true;
681 }
682
Ethan Nicholas00543112018-07-31 09:44:36 -0400683 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -0400684 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -0400685
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400686 while (fErrorCount == 0) {
John Stilesf3a28db2021-03-10 23:00:47 -0500687 bool madeChanges = fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400688
John Stiles0bfeae62021-03-11 09:09:42 -0500689 madeChanges |= this->removeDeadFunctions(program, usage);
John Stiles26541872021-03-16 12:19:54 -0400690 madeChanges |= this->removeDeadLocalVariables(program, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400691
John Stiles270cec22021-02-17 12:59:36 -0500692 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
John Stiles0bfeae62021-03-11 09:09:42 -0500693 madeChanges |= this->removeDeadGlobalVariables(program, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400694 }
John Stiles73a6bff2020-09-09 13:40:37 -0400695
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400696 if (!madeChanges) {
697 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500698 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400699 }
John Stilesbb1505f2021-02-12 09:17:53 -0500700
701 if (fErrorCount == 0) {
702 this->verifyStaticTests(program);
703 }
704
Ethan Nicholas00543112018-07-31 09:44:36 -0400705 return fErrorCount == 0;
706}
707
Brian Osmanfb32ddf2019-06-18 10:14:20 -0400708#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
709
Ethan Nicholas00543112018-07-31 09:44:36 -0400710bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400711 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toSPIRV");
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400712#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400713 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -0400714 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400715 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400716 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -0500717 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400718 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400719 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400720 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500721 String errors;
722 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
723 const char* m) {
724 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400725 };
726 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500727
728 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
729 // explaining the error. In standalone mode (skslc), we will send the message, plus the
730 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
731 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
732
733 if (!result) {
734#if defined(SKSL_STANDALONE)
735 // Convert the string-stream to a SPIR-V disassembly.
736 std::string disassembly;
737 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
738 errors.append(disassembly);
739 }
740 this->error(-1, errors);
741#else
742 SkDEBUGFAILF("%s", errors.c_str());
743#endif
744 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400745 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400746 }
747#else
Brian Osman88cda172020-10-09 12:05:16 -0400748 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400749 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500750 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400751#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -0500752 return result;
753}
754
Ethan Nicholas00543112018-07-31 09:44:36 -0400755bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400756 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500757 bool result = this->toSPIRV(program, buffer);
758 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400759 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500760 }
761 return result;
762}
763
Ethan Nicholas00543112018-07-31 09:44:36 -0400764bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400765 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -0400766 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400767 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500768 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500769 return result;
770}
771
Ethan Nicholas00543112018-07-31 09:44:36 -0400772bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400773 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500774 bool result = this->toGLSL(program, buffer);
775 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400776 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500777 }
778 return result;
779}
780
Brian Osmanc0243912020-02-19 15:35:26 -0500781bool Compiler::toHLSL(Program& program, String* out) {
782 String spirv;
783 if (!this->toSPIRV(program, &spirv)) {
784 return false;
785 }
786
787 return SPIRVtoHLSL(spirv, out);
788}
789
Ethan Nicholas00543112018-07-31 09:44:36 -0400790bool Compiler::toMetal(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400791 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toMetal");
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400792 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -0400793 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -0400794 return result;
795}
796
Ethan Nicholas00543112018-07-31 09:44:36 -0400797bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -0400798 StringStream buffer;
799 bool result = this->toMetal(program, buffer);
800 if (result) {
801 *out = buffer.str();
802 }
803 return result;
804}
805
Greg Daniela28ea672020-09-25 11:12:56 -0400806#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400807bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400808 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400809 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400810 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400811 return result;
812}
813
Ethan Nicholas00543112018-07-31 09:44:36 -0400814bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400815 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400816 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400817 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -0400818 return result;
819}
Greg Daniela28ea672020-09-25 11:12:56 -0400820#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400821
Ethan Nicholas2a479a52020-08-18 16:29:45 -0400822#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -0400823
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700824Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -0500825 if (fSource && offset >= 0) {
826 int line = 1;
827 int column = 1;
828 for (int i = 0; i < offset; i++) {
829 if ((*fSource)[i] == '\n') {
830 ++line;
831 column = 1;
832 }
833 else {
834 ++column;
835 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700836 }
Ethan Nicholas3c729892020-12-07 12:47:17 -0500837 return Position(line, column);
838 } else {
839 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700840 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700841}
842
843void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700844 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700845 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -0500846 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -0500847 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -0700848}
849
John Stiles8d3642e2021-01-22 09:50:04 -0500850void Compiler::setErrorCount(int c) {
851 if (c < fErrorCount) {
852 fErrorText.resize(fErrorTextLength[c]);
853 fErrorTextLength.resize(c);
854 fErrorCount = c;
855 }
856}
857
Ethan Nicholas95046142021-01-07 10:57:27 -0500858String Compiler::errorText(bool showCount) {
859 if (showCount) {
860 this->writeErrorCount();
861 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400862 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400863 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -0500864 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -0700865 return result;
866}
867
868void Compiler::writeErrorCount() {
869 if (fErrorCount) {
870 fErrorText += to_string(fErrorCount) + " error";
871 if (fErrorCount > 1) {
872 fErrorText += "s";
873 }
874 fErrorText += "\n";
875 }
876}
877
John Stilesa6841be2020-08-06 14:11:56 -0400878} // namespace SkSL