blob: b00582a2de1cef2ffb21290ef64f9d3e555da298 [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);
Brian Osmane498b3c2020-09-23 14:42:11 -0400302 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
303 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400304 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400305 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400306 abort();
307 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400308 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400309 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500310
John Stiles881a10c2020-09-19 10:13:24 -0400311 SkASSERT(fIRGenerator->fCanInline);
312 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500313
Brian Osman88cda172020-10-09 12:05:16 -0400314 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500315 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
316 source->c_str(), source->length(),
317 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400318 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500319 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400320 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400321 if (this->fErrorCount) {
322 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400323 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400324 }
Brian Osman88cda172020-10-09 12:05:16 -0400325 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400326#else
327 SkASSERT(data.fData && (data.fSize != 0));
328 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
329 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500330 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400331 fModifiers.push_back(fIRGenerator->releaseModifiers());
332#endif
333
334 return module;
335}
336
John Stilesdbd4e6f2021-02-16 13:29:15 -0500337ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500338 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500339 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400340
341 // For modules that just declare (but don't define) intrinsic functions, there will be no new
342 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500343 if (module.fElements.empty()) {
344 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400345 }
346
347 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
348
349 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
350 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500351 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400352 switch (element->kind()) {
353 case ProgramElement::Kind::kFunction: {
354 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400355 SkASSERT(f.declaration().isBuiltin());
356 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400357 break;
358 }
John Stiles569249b2020-11-03 12:18:22 -0500359 case ProgramElement::Kind::kFunctionPrototype: {
360 // These are already in the symbol table.
361 break;
362 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400363 case ProgramElement::Kind::kEnum: {
364 const Enum& e = element->as<Enum>();
365 SkASSERT(e.isBuiltin());
366 intrinsics->insertOrDie(e.typeName(), std::move(element));
367 break;
368 }
369 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400370 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
371 const Variable& var = global.declaration()->as<VarDeclaration>().var();
372 SkASSERT(var.isBuiltin());
373 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400374 break;
375 }
376 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400377 const Variable& var = element->as<InterfaceBlock>().variable();
378 SkASSERT(var.isBuiltin());
379 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400380 break;
381 }
382 default:
383 printf("Unsupported element: %s\n", element->description().c_str());
384 SkASSERT(false);
385 break;
386 }
387 }
388
Brian Osman0006ad02020-11-18 15:38:39 -0500389 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400390}
391
Brian Osman32d53552020-09-23 13:55:20 -0400392std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -0500393 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -0400394 String text,
395 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500396 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400397 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -0500398
John Stilesdbd4e6f2021-02-16 13:29:15 -0500399 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400400
Brian Osman0006ad02020-11-18 15:38:39 -0500401 // Loading and optimizing our base module might reset the inliner, so do that first,
402 // *then* configure the inliner with the settings for this program.
403 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
404
John Stiles270cec22021-02-17 12:59:36 -0500405 // Update our context to point to the program configuration for the duration of compilation.
406 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -0500407 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -0500408
John Stiles7247b482021-03-08 10:40:35 -0500409 // Honor our global optimization-disable flags.
410 config->fSettings.fOptimize &= gSkSLOptimizer;
John Stiles7247b482021-03-08 10:40:35 -0500411 config->fSettings.fInlineThreshold *= (int)gSkSLInliner;
John Stiles0bfeae62021-03-11 09:09:42 -0500412 config->fSettings.fRemoveDeadVariables &= gSkSLDeadCodeElimination;
413 config->fSettings.fRemoveDeadFunctions &= gSkSLDeadCodeElimination;
John Stiles7247b482021-03-08 10:40:35 -0500414
415 // Disable optimization settings that depend on a parent setting which has been disabled.
John Stiles7247b482021-03-08 10:40:35 -0500416 config->fSettings.fInlineThreshold *= (int)config->fSettings.fOptimize;
John Stiles0bfeae62021-03-11 09:09:42 -0500417 config->fSettings.fRemoveDeadFunctions &= config->fSettings.fOptimize;
418 config->fSettings.fRemoveDeadVariables &= config->fSettings.fOptimize;
John Stiles7247b482021-03-08 10:40:35 -0500419
ethannicholasb3058bd2016-07-01 08:22:01 -0700420 fErrorText = "";
421 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -0500422 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -0400423
424 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700425 std::unique_ptr<String> textPtr(new String(std::move(text)));
426 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -0400427
John Stiles5c7bb322020-10-22 11:09:15 -0400428 // Enable node pooling while converting and optimizing the program for a performance boost.
429 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -0500430 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -0500431 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -0500432 pool = Pool::Create();
433 pool->attachToThread();
434 }
John Stilesd1204642021-02-17 16:30:02 -0500435 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
436 textPtr->c_str(), textPtr->size(),
437 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -0500438 auto program = std::make_unique<Program>(std::move(textPtr),
439 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -0400440 fContext,
441 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -0400442 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -0400443 std::move(ir.fModifiers),
444 std::move(ir.fSymbolTable),
445 std::move(pool),
446 ir.fInputs);
447 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500448 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -0400449 // Do not return programs that failed to compile.
John Stiles7247b482021-03-08 10:40:35 -0500450 } else if (!this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -0400451 // Do not return programs that failed to optimize.
452 } else {
453 // We have a successful program!
454 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500455 }
John Stiles5c7bb322020-10-22 11:09:15 -0400456
Brian Osman28f702c2021-02-02 11:52:07 -0500457 if (program->fPool) {
458 program->fPool->detachFromThread();
459 }
John Stiles5c7bb322020-10-22 11:09:15 -0400460 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500461}
462
John Stilesbb1505f2021-02-12 09:17:53 -0500463void Compiler::verifyStaticTests(const Program& program) {
464 class StaticTestVerifier : public ProgramVisitor {
465 public:
466 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
467
468 using ProgramVisitor::visitProgramElement;
469
470 bool visitStatement(const Statement& stmt) override {
471 switch (stmt.kind()) {
472 case Statement::Kind::kIf:
473 if (stmt.as<IfStatement>().isStatic()) {
474 fReporter->error(stmt.fOffset, "static if has non-static test");
475 }
476 break;
477
478 case Statement::Kind::kSwitch:
479 if (stmt.as<SwitchStatement>().isStatic()) {
480 fReporter->error(stmt.fOffset, "static switch has non-static test");
481 }
482 break;
483
484 default:
485 break;
486 }
487 return INHERITED::visitStatement(stmt);
488 }
489
John Stiles59e34562021-02-12 16:56:39 -0500490 bool visitExpression(const Expression&) override {
491 // We aren't looking for anything inside an Expression, so skip them entirely.
492 return false;
493 }
494
John Stilesbb1505f2021-02-12 09:17:53 -0500495 private:
496 using INHERITED = ProgramVisitor;
497 ErrorReporter* fReporter;
498 };
499
500 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -0500501 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -0500502 return;
503 }
504
505 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
506 StaticTestVerifier visitor{this};
507 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
508 if (element->is<FunctionDefinition>()) {
509 visitor.visitProgramElement(*element);
510 }
511 }
512}
513
Brian Osman0006ad02020-11-18 15:38:39 -0500514bool Compiler::optimize(LoadedModule& module) {
515 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -0500516
John Stiles270cec22021-02-17 12:59:36 -0500517 // Create a temporary program configuration with default settings.
518 ProgramConfig config;
519 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -0500520 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -0500521
John Stilesd1204642021-02-17 16:30:02 -0500522 // Reset the Inliner.
523 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -0500524
525 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -0500526
527 while (fErrorCount == 0) {
Brian Osman0006ad02020-11-18 15:38:39 -0500528 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stilesf3a28db2021-03-10 23:00:47 -0500529 if (!fInliner.analyze(module.fElements, module.fSymbols, usage.get())) {
Brian Osman0006ad02020-11-18 15:38:39 -0500530 break;
531 }
532 }
533 return fErrorCount == 0;
534}
535
John Stiles0bfeae62021-03-11 09:09:42 -0500536bool Compiler::removeDeadFunctions(Program& program, ProgramUsage* usage) {
537 bool madeChanges = false;
538
539 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
540 auto isDeadFunction = [&](const ProgramElement* element) {
541 if (!element->is<FunctionDefinition>()) {
542 return false;
543 }
544 const FunctionDefinition& fn = element->as<FunctionDefinition>();
545 if (fn.declaration().name() == "main" || usage->get(fn.declaration()) > 0) {
546 return false;
547 }
548 usage->remove(*element);
549 madeChanges = true;
550 return true;
551 };
552
553 program.fElements.erase(std::remove_if(program.fElements.begin(),
554 program.fElements.end(),
555 [&](const std::unique_ptr<ProgramElement>& element) {
556 return isDeadFunction(element.get());
557 }),
558 program.fElements.end());
559 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
560 program.fSharedElements.end(),
561 isDeadFunction),
562 program.fSharedElements.end());
563 }
564 return madeChanges;
565}
566
567bool Compiler::removeDeadGlobalVariables(Program& program, ProgramUsage* usage) {
568 bool madeChanges = false;
569
570 if (program.fConfig->fSettings.fRemoveDeadVariables) {
571 auto isDeadVariable = [&](const ProgramElement* element) {
572 if (!element->is<GlobalVarDeclaration>()) {
573 return false;
574 }
575 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
576 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
577 if (!usage->isDead(varDecl.var())) {
578 return false;
579 }
580 madeChanges = true;
581 return true;
582 };
583
584 program.fElements.erase(std::remove_if(program.fElements.begin(),
585 program.fElements.end(),
586 [&](const std::unique_ptr<ProgramElement>& element) {
587 return isDeadVariable(element.get());
588 }),
589 program.fElements.end());
590 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
591 program.fSharedElements.end(),
592 isDeadVariable),
593 program.fSharedElements.end());
594 }
595 return madeChanges;
596}
597
John Stiles26541872021-03-16 12:19:54 -0400598bool Compiler::removeDeadLocalVariables(Program& program, ProgramUsage* usage) {
599 class DeadLocalVariableEliminator : public ProgramWriter {
600 public:
601 DeadLocalVariableEliminator(const Context& context, ProgramUsage* usage)
602 : fContext(context)
603 , fUsage(usage) {}
604
605 using ProgramWriter::visitProgramElement;
606
607 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
608 // We don't need to look inside expressions at all.
609 return false;
610 }
611
612 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
613 if (stmt->is<VarDeclaration>()) {
614 VarDeclaration& varDecl = stmt->as<VarDeclaration>();
615 const Variable* var = &varDecl.var();
616 ProgramUsage::VariableCounts* counts = fUsage->fVariableCounts.find(var);
617 SkASSERT(counts);
618 SkASSERT(counts->fDeclared);
619 if (CanEliminate(var, *counts)) {
620 if (var->initialValue()) {
621 // The variable has an initial-value expression, which might have side
622 // effects. ExpressionStatement::Make will preserve side effects, but
623 // replaces pure expressions with Nop.
624 fUsage->remove(stmt.get());
625 stmt = ExpressionStatement::Make(fContext, std::move(varDecl.value()));
626 fUsage->add(stmt.get());
627 } else {
628 // The variable has no initial-value and can be cleanly eliminated.
629 fUsage->remove(stmt.get());
630 stmt = std::make_unique<Nop>();
631 }
632 fMadeChanges = true;
633 }
634 return false;
635 }
636 return INHERITED::visitStatementPtr(stmt);
637 }
638
639 static bool CanEliminate(const Variable* var, const ProgramUsage::VariableCounts& counts) {
640 if (!counts.fDeclared || counts.fRead || var->storage() != VariableStorage::kLocal) {
641 return false;
642 }
643 if (var->initialValue()) {
644 SkASSERT(counts.fWrite >= 1);
645 return counts.fWrite == 1;
646 } else {
647 return counts.fWrite == 0;
648 }
649 }
650
651 bool fMadeChanges = false;
652 const Context& fContext;
653 ProgramUsage* fUsage;
654
655 using INHERITED = ProgramWriter;
656 };
657
658 DeadLocalVariableEliminator visitor{*fContext, usage};
659
660 if (program.fConfig->fSettings.fRemoveDeadVariables) {
661 for (auto& [var, counts] : usage->fVariableCounts) {
662 if (DeadLocalVariableEliminator::CanEliminate(var, counts)) {
663 // This program contains at least one dead local variable.
664 // Scan the program for any dead local variables and eliminate them all.
665 for (std::unique_ptr<ProgramElement>& pe : program.ownedElements()) {
666 if (pe->is<FunctionDefinition>()) {
667 visitor.visitProgramElement(*pe);
668 }
669 }
670 break;
671 }
672 }
673 }
674
675 return visitor.fMadeChanges;
676}
677
Ethan Nicholas00543112018-07-31 09:44:36 -0400678bool Compiler::optimize(Program& program) {
John Stiles7247b482021-03-08 10:40:35 -0500679 // The optimizer only needs to run when it is enabled.
680 if (!program.fConfig->fSettings.fOptimize) {
681 return true;
682 }
683
Ethan Nicholas00543112018-07-31 09:44:36 -0400684 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -0400685 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -0400686
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400687 while (fErrorCount == 0) {
John Stilesf3a28db2021-03-10 23:00:47 -0500688 bool madeChanges = fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400689
John Stiles0bfeae62021-03-11 09:09:42 -0500690 madeChanges |= this->removeDeadFunctions(program, usage);
John Stiles26541872021-03-16 12:19:54 -0400691 madeChanges |= this->removeDeadLocalVariables(program, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400692
John Stiles270cec22021-02-17 12:59:36 -0500693 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
John Stiles0bfeae62021-03-11 09:09:42 -0500694 madeChanges |= this->removeDeadGlobalVariables(program, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400695 }
John Stiles73a6bff2020-09-09 13:40:37 -0400696
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400697 if (!madeChanges) {
698 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500699 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400700 }
John Stilesbb1505f2021-02-12 09:17:53 -0500701
702 if (fErrorCount == 0) {
703 this->verifyStaticTests(program);
704 }
705
Ethan Nicholas00543112018-07-31 09:44:36 -0400706 return fErrorCount == 0;
707}
708
Brian Osmanfb32ddf2019-06-18 10:14:20 -0400709#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
710
Ethan Nicholas00543112018-07-31 09:44:36 -0400711bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400712 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toSPIRV");
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400713#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400714 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -0400715 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400716 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400717 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -0500718 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400719 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400720 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400721 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500722 String errors;
723 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
724 const char* m) {
725 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400726 };
727 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500728
729 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
730 // explaining the error. In standalone mode (skslc), we will send the message, plus the
731 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
732 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
733
734 if (!result) {
735#if defined(SKSL_STANDALONE)
736 // Convert the string-stream to a SPIR-V disassembly.
737 std::string disassembly;
738 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
739 errors.append(disassembly);
740 }
741 this->error(-1, errors);
742#else
743 SkDEBUGFAILF("%s", errors.c_str());
744#endif
745 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400746 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400747 }
748#else
Brian Osman88cda172020-10-09 12:05:16 -0400749 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400750 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500751 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400752#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -0500753 return result;
754}
755
Ethan Nicholas00543112018-07-31 09:44:36 -0400756bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400757 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500758 bool result = this->toSPIRV(program, buffer);
759 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400760 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500761 }
762 return result;
763}
764
Ethan Nicholas00543112018-07-31 09:44:36 -0400765bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400766 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -0400767 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400768 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500769 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500770 return result;
771}
772
Ethan Nicholas00543112018-07-31 09:44:36 -0400773bool Compiler::toGLSL(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->toGLSL(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
Brian Osmanc0243912020-02-19 15:35:26 -0500782bool Compiler::toHLSL(Program& program, String* out) {
783 String spirv;
784 if (!this->toSPIRV(program, &spirv)) {
785 return false;
786 }
787
788 return SPIRVtoHLSL(spirv, out);
789}
790
Ethan Nicholas00543112018-07-31 09:44:36 -0400791bool Compiler::toMetal(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400792 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toMetal");
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400793 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -0400794 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -0400795 return result;
796}
797
Ethan Nicholas00543112018-07-31 09:44:36 -0400798bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -0400799 StringStream buffer;
800 bool result = this->toMetal(program, buffer);
801 if (result) {
802 *out = buffer.str();
803 }
804 return result;
805}
806
Greg Daniela28ea672020-09-25 11:12:56 -0400807#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400808bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400809 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400810 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400811 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400812 return result;
813}
814
Ethan Nicholas00543112018-07-31 09:44:36 -0400815bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400816 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400817 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400818 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -0400819 return result;
820}
Greg Daniela28ea672020-09-25 11:12:56 -0400821#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400822
Ethan Nicholas2a479a52020-08-18 16:29:45 -0400823#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -0400824
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700825Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -0500826 if (fSource && offset >= 0) {
827 int line = 1;
828 int column = 1;
829 for (int i = 0; i < offset; i++) {
830 if ((*fSource)[i] == '\n') {
831 ++line;
832 column = 1;
833 }
834 else {
835 ++column;
836 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700837 }
Ethan Nicholas3c729892020-12-07 12:47:17 -0500838 return Position(line, column);
839 } else {
840 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700841 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700842}
843
844void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700845 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700846 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -0500847 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -0500848 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -0700849}
850
John Stiles8d3642e2021-01-22 09:50:04 -0500851void Compiler::setErrorCount(int c) {
852 if (c < fErrorCount) {
853 fErrorText.resize(fErrorTextLength[c]);
854 fErrorTextLength.resize(c);
855 fErrorCount = c;
856 }
857}
858
Ethan Nicholas95046142021-01-07 10:57:27 -0500859String Compiler::errorText(bool showCount) {
860 if (showCount) {
861 this->writeErrorCount();
862 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400863 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400864 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -0500865 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -0700866 return result;
867}
868
869void Compiler::writeErrorCount() {
870 if (fErrorCount) {
871 fErrorText += to_string(fErrorCount) + " error";
872 if (fErrorCount > 1) {
873 fErrorText += "s";
874 }
875 fErrorText += "\n";
876 }
877}
878
John Stilesa6841be2020-08-06 14:11:56 -0400879} // namespace SkSL