blob: 7f64d1978d5d50f911193d48fb297b7869b792e6 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stiles270cec22021-02-17 12:59:36 -050013#include "src/core/SkScopeExit.h"
Leon Scrogginsb66214e2021-02-11 17:14:18 -050014#include "src/core/SkTraceEvent.h"
John Stilesb92641c2020-08-31 18:09:01 -040015#include "src/sksl/SkSLAnalysis.h"
John Stilesf3a28db2021-03-10 23:00:47 -050016#include "src/sksl/SkSLConstantFolder.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/sksl/SkSLIRGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050018#include "src/sksl/SkSLOperators.h"
John Stiles270cec22021-02-17 12:59:36 -050019#include "src/sksl/SkSLProgramSettings.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040020#include "src/sksl/SkSLRehydrator.h"
John Stiles3738ef52021-04-13 10:41:57 -040021#include "src/sksl/codegen/SkSLCPPCodeGenerator.h"
John Stiles82ab3402021-04-13 17:13:03 -040022#include "src/sksl/codegen/SkSLDSLCPPCodeGenerator.h"
John Stiles3738ef52021-04-13 10:41:57 -040023#include "src/sksl/codegen/SkSLGLSLCodeGenerator.h"
24#include "src/sksl/codegen/SkSLHCodeGenerator.h"
25#include "src/sksl/codegen/SkSLMetalCodeGenerator.h"
26#include "src/sksl/codegen/SkSLSPIRVCodeGenerator.h"
27#include "src/sksl/codegen/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050028#include "src/sksl/ir/SkSLEnum.h"
29#include "src/sksl/ir/SkSLExpression.h"
30#include "src/sksl/ir/SkSLExpressionStatement.h"
31#include "src/sksl/ir/SkSLFunctionCall.h"
32#include "src/sksl/ir/SkSLIntLiteral.h"
33#include "src/sksl/ir/SkSLModifiersDeclaration.h"
34#include "src/sksl/ir/SkSLNop.h"
35#include "src/sksl/ir/SkSLSymbolTable.h"
36#include "src/sksl/ir/SkSLTernaryExpression.h"
37#include "src/sksl/ir/SkSLUnresolvedFunction.h"
38#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040039#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070040
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040041#include <fstream>
42
Ethan Nicholasa11035b2019-11-26 16:27:47 -050043#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
44#include "include/gpu/GrContextOptions.h"
45#include "src/gpu/GrShaderCaps.h"
46#endif
47
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040048#ifdef SK_ENABLE_SPIRV_VALIDATION
49#include "spirv-tools/libspirv.hpp"
50#endif
51
Brian Osman3d87e9f2020-10-08 11:50:22 -040052#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040053
Brian Osman3d87e9f2020-10-08 11:50:22 -040054// In standalone mode, we load the textual sksl source files. GN generates or copies these files
55// to the skslc executable directory. The "data" in this mode is just the filename.
56#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
57
58#else
59
60// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040061#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
62#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
63#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
64#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050065#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osmancbb60bd2021-04-12 09:49:20 -040066#include "src/sksl/generated/sksl_rt_colorfilter.dehydrated.sksl"
67#include "src/sksl/generated/sksl_rt_shader.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050068#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040069#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
70
Brian Osman3d87e9f2020-10-08 11:50:22 -040071#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
72 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040073
74#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040075
ethannicholasb3058bd2016-07-01 08:22:01 -070076namespace SkSL {
77
John Stiles7247b482021-03-08 10:40:35 -050078// These flags allow tools like Viewer or Nanobench to override the compiler's ProgramSettings.
John Stiles2ee4d7a2021-03-30 10:30:47 -040079Compiler::OverrideFlag Compiler::sOptimizer = OverrideFlag::kDefault;
80Compiler::OverrideFlag Compiler::sInliner = OverrideFlag::kDefault;
John Stiles8ef4d6c2021-03-05 16:01:45 -050081
John Stiles47c0a742021-02-09 09:30:35 -050082using RefKind = VariableReference::RefKind;
83
Brian Osman88cda172020-10-09 12:05:16 -040084class AutoSource {
85public:
86 AutoSource(Compiler* compiler, const String* source)
87 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
88 fCompiler->fSource = source;
89 }
90
91 ~AutoSource() { fCompiler->fSource = fOldSource; }
92
93 Compiler* fCompiler;
94 const String* fOldSource;
95};
96
John Stilesa935c3f2021-02-25 10:35:49 -050097class AutoProgramConfig {
98public:
99 AutoProgramConfig(std::shared_ptr<Context>& context, ProgramConfig* config)
100 : fContext(context.get()) {
101 SkASSERT(!fContext->fConfig);
102 fContext->fConfig = config;
103 }
104
105 ~AutoProgramConfig() {
106 fContext->fConfig = nullptr;
107 }
108
109 Context* fContext;
110};
111
John Stilesd6a5f4492021-02-11 15:46:11 -0500112Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesc1a98b82021-02-24 13:35:02 -0500113 : fContext(std::make_shared<Context>(/*errors=*/*this, *caps))
John Stiles7b920442020-12-17 10:43:41 -0500114 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -0500115 , fErrorCount(0) {
John Stilesc1a98b82021-02-24 13:35:02 -0500116 SkASSERT(caps);
John Stiles7c3515b2020-10-16 18:38:39 -0400117 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -0500118 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesc1a98b82021-02-24 13:35:02 -0500119 fIRGenerator = std::make_unique<IRGenerator>(fContext.get());
ethannicholasb3058bd2016-07-01 08:22:01 -0700120
John Stiles54e7c052021-01-11 14:22:36 -0500121#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700122
Brian Osmanb06301e2020-11-06 11:45:36 -0500123 const SkSL::Symbol* rootTypes[] = {
124 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500125
Brian Osmanb06301e2020-11-06 11:45:36 -0500126 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
127 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
128 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500129 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500130
Brian Osmanc0f2b642020-12-22 13:35:55 -0500131 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500132 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500133
Brian Osmanc63f4312020-12-23 11:44:14 -0500134 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700135
Brian Osman20fad322020-12-23 12:42:33 -0500136 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
137 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500138
Brian Osman14d00962021-04-02 17:04:35 -0400139 TYPE(ColorFilter),
140 TYPE(Shader),
Brian Osmanb06301e2020-11-06 11:45:36 -0500141 };
142
143 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500144 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
145 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
146 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
147 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
148 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
149
150 TYPE(GenUType), TYPE(UVec),
151 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
152
Brian Osmanc0f2b642020-12-22 13:35:55 -0500153 TYPE(Float2x3), TYPE(Float2x4),
154 TYPE(Float3x2), TYPE(Float3x4),
155 TYPE(Float4x2), TYPE(Float4x3),
156
Brian Osmanc63f4312020-12-23 11:44:14 -0500157 TYPE(Half2x3), TYPE(Half2x4),
158 TYPE(Half3x2), TYPE(Half3x4),
159 TYPE(Half4x2), TYPE(Half4x3),
160
Brian Osmanc0f2b642020-12-22 13:35:55 -0500161 TYPE(Mat), TYPE(HMat),
162
Brian Osmanb06301e2020-11-06 11:45:36 -0500163 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
164 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500165 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500166
167 TYPE(ISampler2D),
Brian Osmanb06301e2020-11-06 11:45:36 -0500168 TYPE(SubpassInput), TYPE(SubpassInputMS),
169
Brian Osmanb06301e2020-11-06 11:45:36 -0500170 TYPE(Sampler),
171 TYPE(Texture2D),
Brian Osman14d00962021-04-02 17:04:35 -0400172
173 TYPE(FragmentProcessor),
Brian Osmanb06301e2020-11-06 11:45:36 -0500174 };
175
176 for (const SkSL::Symbol* type : rootTypes) {
177 fRootSymbolTable->addWithoutOwnership(type);
178 }
179 for (const SkSL::Symbol* type : privateTypes) {
180 fPrivateSymbolTable->addWithoutOwnership(type);
181 }
182
183#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700184
Brian Osman3887a012020-09-30 13:22:27 -0400185 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
186 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500187 fPrivateSymbolTable->add(
188 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500189 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500190 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500191 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500192 /*builtin=*/false,
193 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500194
Brian Osman3d87e9f2020-10-08 11:50:22 -0400195 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500196 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700197}
198
John Stilesdd13dba2020-10-29 10:45:34 -0400199Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700200
Brian Osman56269982020-11-20 12:38:07 -0500201const ParsedModule& Compiler::loadGPUModule() {
202 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500203 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500204 }
205 return fGPUModule;
206}
207
208const ParsedModule& Compiler::loadFragmentModule() {
209 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500210 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500211 this->loadGPUModule());
212 }
213 return fFragmentModule;
214}
215
216const ParsedModule& Compiler::loadVertexModule() {
217 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500218 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500219 this->loadGPUModule());
220 }
221 return fVertexModule;
222}
223
Brian Osman88cda172020-10-09 12:05:16 -0400224const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400225 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500226 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500227 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400228 }
Brian Osman88cda172020-10-09 12:05:16 -0400229 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400230}
231
Brian Osman88cda172020-10-09 12:05:16 -0400232const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400233 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500234 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500235 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400236 }
Brian Osman88cda172020-10-09 12:05:16 -0400237 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400238}
239
Brian Osmanb06301e2020-11-06 11:45:36 -0500240const ParsedModule& Compiler::loadPublicModule() {
241 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500242 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500243 }
244 return fPublicModule;
245}
246
Brian Osmancbb60bd2021-04-12 09:49:20 -0400247static void add_glsl_type_aliases(SkSL::SymbolTable* symbols, const SkSL::BuiltinTypes& types) {
248 // Add some aliases to the runtime effect modules so that it's friendlier, and more like GLSL
249 symbols->addAlias("vec2", types.fFloat2.get());
250 symbols->addAlias("vec3", types.fFloat3.get());
251 symbols->addAlias("vec4", types.fFloat4.get());
252
253 symbols->addAlias("ivec2", types.fInt2.get());
254 symbols->addAlias("ivec3", types.fInt3.get());
255 symbols->addAlias("ivec4", types.fInt4.get());
256
257 symbols->addAlias("bvec2", types.fBool2.get());
258 symbols->addAlias("bvec3", types.fBool3.get());
259 symbols->addAlias("bvec4", types.fBool4.get());
260
261 symbols->addAlias("mat2", types.fFloat2x2.get());
262 symbols->addAlias("mat3", types.fFloat3x3.get());
263 symbols->addAlias("mat4", types.fFloat4x4.get());
264}
265
Brian Osman91946752020-12-21 13:20:40 -0500266const ParsedModule& Compiler::loadRuntimeEffectModule() {
267 if (!fRuntimeEffectModule.fSymbols) {
Brian Osmancbb60bd2021-04-12 09:49:20 -0400268 fRuntimeEffectModule = this->parseModule(
269 ProgramKind::kRuntimeEffect, MODULE_DATA(runtime), this->loadPublicModule());
270 add_glsl_type_aliases(fRuntimeEffectModule.fSymbols.get(), fContext->fTypes);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400271 }
Brian Osman91946752020-12-21 13:20:40 -0500272 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400273}
274
Brian Osmancbb60bd2021-04-12 09:49:20 -0400275const ParsedModule& Compiler::loadRuntimeColorFilterModule() {
276 if (!fRuntimeColorFilterModule.fSymbols) {
277 fRuntimeColorFilterModule = this->parseModule(ProgramKind::kRuntimeColorFilter,
278 MODULE_DATA(rt_colorfilter),
279 this->loadPublicModule());
280 add_glsl_type_aliases(fRuntimeColorFilterModule.fSymbols.get(), fContext->fTypes);
281 }
282 return fRuntimeColorFilterModule;
283}
284
285const ParsedModule& Compiler::loadRuntimeShaderModule() {
286 if (!fRuntimeShaderModule.fSymbols) {
287 fRuntimeShaderModule = this->parseModule(
288 ProgramKind::kRuntimeShader, MODULE_DATA(rt_shader), this->loadPublicModule());
289 add_glsl_type_aliases(fRuntimeShaderModule.fSymbols.get(), fContext->fTypes);
290 }
291 return fRuntimeShaderModule;
292}
293
John Stilesdbd4e6f2021-02-16 13:29:15 -0500294const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400295 switch (kind) {
Brian Osmancbb60bd2021-04-12 09:49:20 -0400296 case ProgramKind::kVertex: return this->loadVertexModule(); break;
297 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
298 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
299 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
300 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
301 case ProgramKind::kRuntimeColorFilter: return this->loadRuntimeColorFilterModule(); break;
302 case ProgramKind::kRuntimeShader: return this->loadRuntimeShaderModule(); break;
303 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400304 }
305 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400306}
307
John Stilesdbd4e6f2021-02-16 13:29:15 -0500308LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400309 ModuleData data,
John Stilesa935c3f2021-02-25 10:35:49 -0500310 std::shared_ptr<SymbolTable> base,
311 bool dehydrate) {
312 if (dehydrate) {
313 // NOTE: This is a workaround. When dehydrating includes, skslc doesn't know which module
314 // it's preparing, nor what the correct base module is. We can't use 'Root', because many
315 // GPU intrinsics reference private types, like samplers or textures. Today, 'Private' does
316 // contain the union of all known types, so this is safe. If we ever have types that only
317 // exist in 'Public' (for example), this logic needs to be smarter (by choosing the correct
318 // base for the module we're compiling).
Brian Osmanb06301e2020-11-06 11:45:36 -0500319 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400320 }
John Stilesa935c3f2021-02-25 10:35:49 -0500321 SkASSERT(base);
322
323 // Built-in modules always use default program settings.
324 ProgramConfig config;
325 config.fKind = kind;
326 config.fSettings.fReplaceSettings = !dehydrate;
327 AutoProgramConfig autoConfig(fContext, &config);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400328
329#if defined(SKSL_STANDALONE)
330 SkASSERT(data.fPath);
331 std::ifstream in(data.fPath);
John Stilesd51c9792021-03-18 11:40:14 -0400332 String text{std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()};
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400333 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400334 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400335 abort();
336 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400337 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400338 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500339
John Stiles881a10c2020-09-19 10:13:24 -0400340 SkASSERT(fIRGenerator->fCanInline);
341 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500342
Brian Osman88cda172020-10-09 12:05:16 -0400343 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500344 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
345 source->c_str(), source->length(),
346 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400347 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500348 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400349 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400350 if (this->fErrorCount) {
351 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400352 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400353 }
Brian Osman88cda172020-10-09 12:05:16 -0400354 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400355#else
356 SkASSERT(data.fData && (data.fSize != 0));
357 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
358 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500359 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400360 fModifiers.push_back(fIRGenerator->releaseModifiers());
361#endif
362
363 return module;
364}
365
John Stilesdbd4e6f2021-02-16 13:29:15 -0500366ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500367 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500368 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400369
370 // For modules that just declare (but don't define) intrinsic functions, there will be no new
371 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500372 if (module.fElements.empty()) {
373 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400374 }
375
376 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
377
378 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
379 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500380 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400381 switch (element->kind()) {
382 case ProgramElement::Kind::kFunction: {
383 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400384 SkASSERT(f.declaration().isBuiltin());
385 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400386 break;
387 }
John Stiles569249b2020-11-03 12:18:22 -0500388 case ProgramElement::Kind::kFunctionPrototype: {
389 // These are already in the symbol table.
390 break;
391 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400392 case ProgramElement::Kind::kEnum: {
393 const Enum& e = element->as<Enum>();
394 SkASSERT(e.isBuiltin());
395 intrinsics->insertOrDie(e.typeName(), std::move(element));
396 break;
397 }
398 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400399 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
400 const Variable& var = global.declaration()->as<VarDeclaration>().var();
401 SkASSERT(var.isBuiltin());
402 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400403 break;
404 }
405 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400406 const Variable& var = element->as<InterfaceBlock>().variable();
407 SkASSERT(var.isBuiltin());
408 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400409 break;
410 }
411 default:
412 printf("Unsupported element: %s\n", element->description().c_str());
413 SkASSERT(false);
414 break;
415 }
416 }
417
Brian Osman0006ad02020-11-18 15:38:39 -0500418 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400419}
420
Brian Osman32d53552020-09-23 13:55:20 -0400421std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -0500422 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -0400423 String text,
424 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500425 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400426 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -0500427
John Stilesdbd4e6f2021-02-16 13:29:15 -0500428 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400429
Brian Osman0006ad02020-11-18 15:38:39 -0500430 // Loading and optimizing our base module might reset the inliner, so do that first,
431 // *then* configure the inliner with the settings for this program.
432 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
433
John Stiles270cec22021-02-17 12:59:36 -0500434 // Update our context to point to the program configuration for the duration of compilation.
435 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -0500436 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -0500437
John Stiles2ee4d7a2021-03-30 10:30:47 -0400438 // Honor our optimization-override flags.
439 switch (sOptimizer) {
440 case OverrideFlag::kDefault:
441 break;
442 case OverrideFlag::kOff:
443 config->fSettings.fOptimize = false;
444 break;
445 case OverrideFlag::kOn:
446 config->fSettings.fOptimize = true;
447 break;
448 }
449
450 switch (sInliner) {
451 case OverrideFlag::kDefault:
452 break;
453 case OverrideFlag::kOff:
454 config->fSettings.fInlineThreshold = 0;
455 break;
456 case OverrideFlag::kOn:
457 if (config->fSettings.fInlineThreshold == 0) {
458 config->fSettings.fInlineThreshold = kDefaultInlineThreshold;
459 }
460 break;
461 }
John Stiles7247b482021-03-08 10:40:35 -0500462
463 // Disable optimization settings that depend on a parent setting which has been disabled.
John Stiles7247b482021-03-08 10:40:35 -0500464 config->fSettings.fInlineThreshold *= (int)config->fSettings.fOptimize;
John Stiles0bfeae62021-03-11 09:09:42 -0500465 config->fSettings.fRemoveDeadFunctions &= config->fSettings.fOptimize;
466 config->fSettings.fRemoveDeadVariables &= config->fSettings.fOptimize;
John Stiles7247b482021-03-08 10:40:35 -0500467
ethannicholasb3058bd2016-07-01 08:22:01 -0700468 fErrorText = "";
469 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -0500470 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -0400471
472 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700473 std::unique_ptr<String> textPtr(new String(std::move(text)));
474 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -0400475
John Stiles5c7bb322020-10-22 11:09:15 -0400476 // Enable node pooling while converting and optimizing the program for a performance boost.
477 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -0500478 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -0500479 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -0500480 pool = Pool::Create();
481 pool->attachToThread();
482 }
John Stilesd1204642021-02-17 16:30:02 -0500483 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
484 textPtr->c_str(), textPtr->size(),
485 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -0500486 auto program = std::make_unique<Program>(std::move(textPtr),
487 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -0400488 fContext,
489 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -0400490 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -0400491 std::move(ir.fModifiers),
492 std::move(ir.fSymbolTable),
493 std::move(pool),
494 ir.fInputs);
495 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500496 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -0400497 // Do not return programs that failed to compile.
John Stiles7247b482021-03-08 10:40:35 -0500498 } else if (!this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -0400499 // Do not return programs that failed to optimize.
500 } else {
501 // We have a successful program!
502 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500503 }
John Stiles5c7bb322020-10-22 11:09:15 -0400504
Brian Osman28f702c2021-02-02 11:52:07 -0500505 if (program->fPool) {
506 program->fPool->detachFromThread();
507 }
John Stiles5c7bb322020-10-22 11:09:15 -0400508 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500509}
510
John Stilesbb1505f2021-02-12 09:17:53 -0500511void Compiler::verifyStaticTests(const Program& program) {
512 class StaticTestVerifier : public ProgramVisitor {
513 public:
514 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
515
516 using ProgramVisitor::visitProgramElement;
517
518 bool visitStatement(const Statement& stmt) override {
519 switch (stmt.kind()) {
520 case Statement::Kind::kIf:
521 if (stmt.as<IfStatement>().isStatic()) {
522 fReporter->error(stmt.fOffset, "static if has non-static test");
523 }
524 break;
525
526 case Statement::Kind::kSwitch:
527 if (stmt.as<SwitchStatement>().isStatic()) {
528 fReporter->error(stmt.fOffset, "static switch has non-static test");
529 }
530 break;
531
532 default:
533 break;
534 }
535 return INHERITED::visitStatement(stmt);
536 }
537
John Stiles59e34562021-02-12 16:56:39 -0500538 bool visitExpression(const Expression&) override {
539 // We aren't looking for anything inside an Expression, so skip them entirely.
540 return false;
541 }
542
John Stilesbb1505f2021-02-12 09:17:53 -0500543 private:
544 using INHERITED = ProgramVisitor;
545 ErrorReporter* fReporter;
546 };
547
548 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -0500549 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -0500550 return;
551 }
552
553 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
554 StaticTestVerifier visitor{this};
555 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
556 if (element->is<FunctionDefinition>()) {
557 visitor.visitProgramElement(*element);
558 }
559 }
560}
561
Brian Osman0006ad02020-11-18 15:38:39 -0500562bool Compiler::optimize(LoadedModule& module) {
563 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -0500564
John Stiles270cec22021-02-17 12:59:36 -0500565 // Create a temporary program configuration with default settings.
566 ProgramConfig config;
567 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -0500568 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -0500569
John Stilesd1204642021-02-17 16:30:02 -0500570 // Reset the Inliner.
571 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -0500572
573 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -0500574
575 while (fErrorCount == 0) {
Brian Osman0006ad02020-11-18 15:38:39 -0500576 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stilesf3a28db2021-03-10 23:00:47 -0500577 if (!fInliner.analyze(module.fElements, module.fSymbols, usage.get())) {
Brian Osman0006ad02020-11-18 15:38:39 -0500578 break;
579 }
580 }
581 return fErrorCount == 0;
582}
583
John Stiles0bfeae62021-03-11 09:09:42 -0500584bool Compiler::removeDeadFunctions(Program& program, ProgramUsage* usage) {
585 bool madeChanges = false;
586
587 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
588 auto isDeadFunction = [&](const ProgramElement* element) {
589 if (!element->is<FunctionDefinition>()) {
590 return false;
591 }
592 const FunctionDefinition& fn = element->as<FunctionDefinition>();
John Stilese8da4d22021-03-24 09:19:45 -0400593 if (fn.declaration().isMain() || usage->get(fn.declaration()) > 0) {
John Stiles0bfeae62021-03-11 09:09:42 -0500594 return false;
595 }
596 usage->remove(*element);
597 madeChanges = true;
598 return true;
599 };
600
601 program.fElements.erase(std::remove_if(program.fElements.begin(),
602 program.fElements.end(),
603 [&](const std::unique_ptr<ProgramElement>& element) {
604 return isDeadFunction(element.get());
605 }),
606 program.fElements.end());
607 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
608 program.fSharedElements.end(),
609 isDeadFunction),
610 program.fSharedElements.end());
611 }
612 return madeChanges;
613}
614
615bool Compiler::removeDeadGlobalVariables(Program& program, ProgramUsage* usage) {
616 bool madeChanges = false;
617
618 if (program.fConfig->fSettings.fRemoveDeadVariables) {
619 auto isDeadVariable = [&](const ProgramElement* element) {
620 if (!element->is<GlobalVarDeclaration>()) {
621 return false;
622 }
623 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
624 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
625 if (!usage->isDead(varDecl.var())) {
626 return false;
627 }
628 madeChanges = true;
629 return true;
630 };
631
632 program.fElements.erase(std::remove_if(program.fElements.begin(),
633 program.fElements.end(),
634 [&](const std::unique_ptr<ProgramElement>& element) {
635 return isDeadVariable(element.get());
636 }),
637 program.fElements.end());
638 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
639 program.fSharedElements.end(),
640 isDeadVariable),
641 program.fSharedElements.end());
642 }
643 return madeChanges;
644}
645
John Stiles26541872021-03-16 12:19:54 -0400646bool Compiler::removeDeadLocalVariables(Program& program, ProgramUsage* usage) {
647 class DeadLocalVariableEliminator : public ProgramWriter {
648 public:
649 DeadLocalVariableEliminator(const Context& context, ProgramUsage* usage)
650 : fContext(context)
651 , fUsage(usage) {}
652
653 using ProgramWriter::visitProgramElement;
654
655 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
656 // We don't need to look inside expressions at all.
657 return false;
658 }
659
660 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
661 if (stmt->is<VarDeclaration>()) {
662 VarDeclaration& varDecl = stmt->as<VarDeclaration>();
663 const Variable* var = &varDecl.var();
664 ProgramUsage::VariableCounts* counts = fUsage->fVariableCounts.find(var);
665 SkASSERT(counts);
666 SkASSERT(counts->fDeclared);
667 if (CanEliminate(var, *counts)) {
668 if (var->initialValue()) {
669 // The variable has an initial-value expression, which might have side
670 // effects. ExpressionStatement::Make will preserve side effects, but
671 // replaces pure expressions with Nop.
672 fUsage->remove(stmt.get());
673 stmt = ExpressionStatement::Make(fContext, std::move(varDecl.value()));
674 fUsage->add(stmt.get());
675 } else {
676 // The variable has no initial-value and can be cleanly eliminated.
677 fUsage->remove(stmt.get());
678 stmt = std::make_unique<Nop>();
679 }
680 fMadeChanges = true;
681 }
682 return false;
683 }
684 return INHERITED::visitStatementPtr(stmt);
685 }
686
687 static bool CanEliminate(const Variable* var, const ProgramUsage::VariableCounts& counts) {
688 if (!counts.fDeclared || counts.fRead || var->storage() != VariableStorage::kLocal) {
689 return false;
690 }
691 if (var->initialValue()) {
692 SkASSERT(counts.fWrite >= 1);
693 return counts.fWrite == 1;
694 } else {
695 return counts.fWrite == 0;
696 }
697 }
698
699 bool fMadeChanges = false;
700 const Context& fContext;
701 ProgramUsage* fUsage;
702
703 using INHERITED = ProgramWriter;
704 };
705
706 DeadLocalVariableEliminator visitor{*fContext, usage};
707
708 if (program.fConfig->fSettings.fRemoveDeadVariables) {
709 for (auto& [var, counts] : usage->fVariableCounts) {
710 if (DeadLocalVariableEliminator::CanEliminate(var, counts)) {
711 // This program contains at least one dead local variable.
712 // Scan the program for any dead local variables and eliminate them all.
713 for (std::unique_ptr<ProgramElement>& pe : program.ownedElements()) {
714 if (pe->is<FunctionDefinition>()) {
715 visitor.visitProgramElement(*pe);
716 }
717 }
718 break;
719 }
720 }
721 }
722
723 return visitor.fMadeChanges;
724}
725
Ethan Nicholas00543112018-07-31 09:44:36 -0400726bool Compiler::optimize(Program& program) {
John Stiles7247b482021-03-08 10:40:35 -0500727 // The optimizer only needs to run when it is enabled.
728 if (!program.fConfig->fSettings.fOptimize) {
729 return true;
730 }
731
Ethan Nicholas00543112018-07-31 09:44:36 -0400732 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -0400733 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -0400734
John Stilesb6664582021-03-19 09:46:00 -0400735 if (fErrorCount == 0) {
John Stiles87fc6572021-04-01 14:56:34 +0000736 // Run the inliner only once; it is expensive! Multiple passes can occasionally shake out
737 // more wins, but it's diminishing returns.
738 fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400739
John Stilesb6664582021-03-19 09:46:00 -0400740 while (this->removeDeadFunctions(program, usage)) {
741 // Removing dead functions may cause more functions to become unreferenced. Try again.
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400742 }
John Stilesb6664582021-03-19 09:46:00 -0400743 while (this->removeDeadLocalVariables(program, usage)) {
744 // Removing dead variables may cause more variables to become unreferenced. Try again.
745 }
746 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
747 this->removeDeadGlobalVariables(program, usage);
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500748 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400749 }
John Stilesbb1505f2021-02-12 09:17:53 -0500750
751 if (fErrorCount == 0) {
752 this->verifyStaticTests(program);
753 }
754
Ethan Nicholas00543112018-07-31 09:44:36 -0400755 return fErrorCount == 0;
756}
757
Brian Osmanfb32ddf2019-06-18 10:14:20 -0400758#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
759
Ethan Nicholas00543112018-07-31 09:44:36 -0400760bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400761 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toSPIRV");
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400762#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400763 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -0400764 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400765 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400766 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -0500767 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400768 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400769 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400770 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500771 String errors;
772 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
773 const char* m) {
774 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400775 };
776 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500777
778 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
779 // explaining the error. In standalone mode (skslc), we will send the message, plus the
780 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
781 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
782
783 if (!result) {
784#if defined(SKSL_STANDALONE)
785 // Convert the string-stream to a SPIR-V disassembly.
786 std::string disassembly;
787 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
788 errors.append(disassembly);
789 }
790 this->error(-1, errors);
791#else
792 SkDEBUGFAILF("%s", errors.c_str());
793#endif
794 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400795 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400796 }
797#else
Brian Osman88cda172020-10-09 12:05:16 -0400798 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400799 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500800 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400801#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -0500802 return result;
803}
804
Ethan Nicholas00543112018-07-31 09:44:36 -0400805bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400806 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500807 bool result = this->toSPIRV(program, buffer);
808 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400809 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500810 }
811 return result;
812}
813
Ethan Nicholas00543112018-07-31 09:44:36 -0400814bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400815 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -0400816 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400817 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500818 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500819 return result;
820}
821
Ethan Nicholas00543112018-07-31 09:44:36 -0400822bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400823 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500824 bool result = this->toGLSL(program, buffer);
825 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400826 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500827 }
828 return result;
829}
830
Brian Osmanc0243912020-02-19 15:35:26 -0500831bool Compiler::toHLSL(Program& program, String* out) {
832 String spirv;
833 if (!this->toSPIRV(program, &spirv)) {
834 return false;
835 }
836
837 return SPIRVtoHLSL(spirv, out);
838}
839
Ethan Nicholas00543112018-07-31 09:44:36 -0400840bool Compiler::toMetal(Program& program, OutputStream& out) {
Brian Osman7a20b5c2021-03-15 16:23:33 -0400841 TRACE_EVENT0("skia.shaders", "SkSL::Compiler::toMetal");
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400842 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -0400843 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -0400844 return result;
845}
846
Ethan Nicholas00543112018-07-31 09:44:36 -0400847bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -0400848 StringStream buffer;
849 bool result = this->toMetal(program, buffer);
850 if (result) {
851 *out = buffer.str();
852 }
853 return result;
854}
855
Greg Daniela28ea672020-09-25 11:12:56 -0400856#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400857bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400858 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400859 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400860 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400861 return result;
862}
863
John Stiles82ab3402021-04-13 17:13:03 -0400864bool Compiler::toDSLCPP(Program& program, String name, OutputStream& out) {
865 AutoSource as(this, program.fSource.get());
866 DSLCPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
867 bool result = cg.generateCode();
868 return result;
869}
870
Ethan Nicholas00543112018-07-31 09:44:36 -0400871bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400872 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400873 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400874 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -0400875 return result;
876}
Greg Daniela28ea672020-09-25 11:12:56 -0400877#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400878
Ethan Nicholas2a479a52020-08-18 16:29:45 -0400879#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -0400880
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700881Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -0500882 if (fSource && offset >= 0) {
883 int line = 1;
884 int column = 1;
885 for (int i = 0; i < offset; i++) {
886 if ((*fSource)[i] == '\n') {
887 ++line;
888 column = 1;
889 }
890 else {
891 ++column;
892 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700893 }
Ethan Nicholas3c729892020-12-07 12:47:17 -0500894 return Position(line, column);
895 } else {
896 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700897 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700898}
899
900void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700901 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700902 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -0500903 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -0500904 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -0700905}
906
John Stiles8d3642e2021-01-22 09:50:04 -0500907void Compiler::setErrorCount(int c) {
908 if (c < fErrorCount) {
909 fErrorText.resize(fErrorTextLength[c]);
910 fErrorTextLength.resize(c);
911 fErrorCount = c;
912 }
913}
914
Ethan Nicholas95046142021-01-07 10:57:27 -0500915String Compiler::errorText(bool showCount) {
916 if (showCount) {
917 this->writeErrorCount();
918 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400919 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400920 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -0500921 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -0700922 return result;
923}
924
925void Compiler::writeErrorCount() {
926 if (fErrorCount) {
927 fErrorText += to_string(fErrorCount) + " error";
928 if (fErrorCount > 1) {
929 fErrorText += "s";
930 }
931 fErrorText += "\n";
932 }
933}
934
John Stilesa6841be2020-08-06 14:11:56 -0400935} // namespace SkSL