Flutter Engine
The Flutter Engine
Main.cpp
Go to the documentation of this file.
1/*
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 */
7
10#include "src/core/SkOpts.h"
15#include "src/sksl/SkSLUtil.h"
30
31#include "spirv-tools/libspirv.hpp"
32
33#include <fstream>
34#include <limits.h>
35#include <optional>
36#include <stdarg.h>
37#include <stdio.h>
38
39void SkDebugf(const char format[], ...) {
40 va_list args;
42 vfprintf(stderr, format, args);
43 va_end(args);
44}
45
46namespace SkOpts {
48}
49
50static std::unique_ptr<SkWStream> as_SkWStream(SkSL::OutputStream& s) {
51 struct Adapter : public SkWStream {
52 public:
53 Adapter(SkSL::OutputStream& out) : fOut(out), fBytesWritten(0) {}
54
55 bool write(const void* buffer, size_t size) override {
56 fOut.write(buffer, size);
57 fBytesWritten += size;
58 return true;
59 }
60 void flush() override {}
61 size_t bytesWritten() const override { return fBytesWritten; }
62
63 private:
65 size_t fBytesWritten;
66 };
67
68 return std::make_unique<Adapter>(s);
69}
70
71static bool consume_suffix(std::string* str, const char suffix[]) {
72 if (!skstd::ends_with(*str, suffix)) {
73 return false;
74 }
75 str->resize(str->length() - strlen(suffix));
76 return true;
77}
78
80public:
82 static const SkSL::ShaderCaps* sCaps = []{
83 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
84 caps->fVersionDeclString = "#version 400";
85 caps->fAddAndTrueToLoopCondition = true;
86 return caps.release();
87 }();
88 return sCaps;
89 }
90
92 static const SkSL::ShaderCaps* sCaps = [] {
93 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
94 caps->fVersionDeclString = "#version 400";
95 caps->fCanUseFractForNegativeValues = false;
96 return caps.release();
97 }();
98 return sCaps;
99 }
100
102 static const SkSL::ShaderCaps* sCaps = [] {
103 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
104 caps->fVersionDeclString = "#version 400";
105 caps->fCanUseFragCoord = false;
106 return caps.release();
107 }();
108 return sCaps;
109 }
110
112 static const SkSL::ShaderCaps* sCaps = [] {
113 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
114 caps->fVersionDeclString = "#version 400";
115 caps->fCanUseMinAndAbsTogether = false;
116 return caps.release();
117 }();
118 return sCaps;
119 }
120
122 static const SkSL::ShaderCaps* sCaps = [] {
123 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
124 caps->fCanUseVoidInSequenceExpressions = false;
125 return caps.release();
126 }();
127 return sCaps;
128 }
129
130
132 static const SkSL::ShaderCaps* sCaps = [] {
133 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
134 caps->fDualSourceBlendingSupport = true;
135 return caps.release();
136 }();
137 return sCaps;
138 }
139
141 static const SkSL::ShaderCaps* sCaps = [] {
142 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
143 caps->fVersionDeclString = "#version 400";
144 caps->fEmulateAbsIntFunction = true;
145 return caps.release();
146 }();
147 return sCaps;
148 }
149
151 static const SkSL::ShaderCaps* sCaps = [] {
152 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
153 caps->fFBFetchSupport = true;
154 caps->fFBFetchColorName = "FramebufferFragColor"; // a nice, backend-neutral name
155 return caps.release();
156 }();
157 return sCaps;
158 }
159
161 static const SkSL::ShaderCaps* sCaps = [] {
162 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
163 caps->fMustDeclareFragmentFrontFacing = true;
164 return caps.release();
165 }();
166 return sCaps;
167 }
168
170 static const SkSL::ShaderCaps* sCaps = [] {
171 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
172 caps->fVersionDeclString = "#version 400";
173 caps->fMustForceNegatedAtanParamToFloat = true;
174 return caps.release();
175 }();
176 return sCaps;
177 }
178
180 static const SkSL::ShaderCaps* sCaps = [] {
181 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
182 caps->fVersionDeclString = "#version 400";
183 caps->fMustForceNegatedLdexpParamToMultiply = true;
184 return caps.release();
185 }();
186 return sCaps;
187 }
188
190 static const SkSL::ShaderCaps* sCaps = [] {
191 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
192 caps->fMustGuardDivisionEvenAfterExplicitZeroCheck = true;
193 return caps.release();
194 }();
195 return sCaps;
196 }
197
199 static const SkSL::ShaderCaps* sCaps = [] {
200 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
201 caps->fVersionDeclString = "#version 400";
202 caps->fBuiltinDeterminantSupport = false;
203 return caps.release();
204 }();
205 return sCaps;
206 }
207
209 static const SkSL::ShaderCaps* sCaps = [] {
210 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
211 caps->fVersionDeclString = "#version 400";
212 caps->fBuiltinFMASupport = false;
213 return caps.release();
214 }();
215 return sCaps;
216 }
217
219 static const SkSL::ShaderCaps* sCaps = [] {
220 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
221 caps->fVersionDeclString = "#version 400";
222 caps->fExternalTextureSupport = false;
223 return caps.release();
224 }();
225 return sCaps;
226 }
227
229 static const SkSL::ShaderCaps* sCaps = [] {
230 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
231 caps->fVersionDeclString = "#version 400";
232 caps->fRemovePowWithConstantExponent = true;
233 return caps.release();
234 }();
235 return sCaps;
236 }
237
239 static const SkSL::ShaderCaps* sCaps = [] {
240 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
241 caps->fVersionDeclString = "#version 400";
242 caps->fRewriteDoWhileLoops = true;
243 return caps.release();
244 }();
245 return sCaps;
246 }
247
249 static const SkSL::ShaderCaps* sCaps = [] {
250 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
251 caps->fRewriteMatrixComparisons = true;
252 caps->fUsesPrecisionModifiers = true;
253 return caps.release();
254 }();
255 return sCaps;
256 }
257
259 static const SkSL::ShaderCaps* sCaps = [] {
260 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
261 caps->fVersionDeclString = "#version 400";
262 caps->fRewriteMatrixVectorMultiply = true;
263 return caps.release();
264 }();
265 return sCaps;
266 }
267
269 static const SkSL::ShaderCaps* sCaps = [] {
270 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
271 caps->fVersionDeclString = "#version 400";
272 caps->fRewriteSwitchStatements = true;
273 return caps.release();
274 }();
275 return sCaps;
276 }
277
279 static const SkSL::ShaderCaps* sCaps = [] {
280 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
281 caps->fVersionDeclString = "#version 400";
282 caps->fShaderDerivativeSupport = true;
283 caps->fSampleMaskSupport = true;
284 return caps.release();
285 }();
286 return sCaps;
287 }
288
290 static const SkSL::ShaderCaps* sCaps = [] {
291 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
292 caps->fVersionDeclString = "#version 400";
293 caps->fShaderDerivativeSupport = true;
294 caps->fShaderDerivativeExtensionString = "GL_OES_standard_derivatives";
295 caps->fUsesPrecisionModifiers = true;
296 return caps.release();
297 }();
298 return sCaps;
299 }
300
302 static const SkSL::ShaderCaps* sCaps = [] {
303 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
304 caps->fVersionDeclString = "#version 400";
305 caps->fUnfoldShortCircuitAsTernary = true;
306 return caps.release();
307 }();
308 return sCaps;
309 }
310
312 static const SkSL::ShaderCaps* sCaps = [] {
313 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
314 caps->fVersionDeclString = "#version 400";
315 caps->fUsesPrecisionModifiers = true;
316 return caps.release();
317 }();
318 return sCaps;
319 }
320
321 static const SkSL::ShaderCaps* Version110() {
322 static const SkSL::ShaderCaps* sCaps = [] {
323 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
324 caps->fVersionDeclString = "#version 110";
325 caps->fGLSLGeneration = SkSL::GLSLGeneration::k110;
326 return caps.release();
327 }();
328 return sCaps;
329 }
330
332 static const SkSL::ShaderCaps* sCaps = [] {
333 std::unique_ptr<SkSL::ShaderCaps> caps = MakeShaderCaps();
334 caps->fVersionDeclString = "#version 450 core";
335 return caps.release();
336 }();
337 return sCaps;
338 }
339};
340
341// Given a string containing an SkSL program, searches for a #pragma settings comment, like so:
342// /*#pragma settings Default Sharpen*/
343// The passed-in Settings object will be updated accordingly. Any number of options can be provided.
344static bool detect_shader_settings(const std::string& text,
346 const SkSL::ShaderCaps** caps,
347 std::unique_ptr<SkSL::DebugTracePriv>* debugTrace) {
349
350 // Find a matching comment and isolate the name portion.
351 static constexpr char kPragmaSettings[] = "/*#pragma settings ";
352 const char* settingsPtr = strstr(text.c_str(), kPragmaSettings);
353 if (settingsPtr != nullptr) {
354 // Subtract one here in order to preserve the leading space, which is necessary to allow
355 // consumeSuffix to find the first item.
356 settingsPtr += strlen(kPragmaSettings) - 1;
357
358 const char* settingsEnd = strstr(settingsPtr, "*/");
359 if (settingsEnd != nullptr) {
360 std::string settingsText{settingsPtr, size_t(settingsEnd - settingsPtr)};
361
362 // Apply settings as requested. Since they can come in any order, repeat until we've
363 // consumed them all.
364 for (;;) {
365 const size_t startingLength = settingsText.length();
366
367 if (consume_suffix(&settingsText, " AddAndTrueToLoopCondition")) {
368 *caps = Factory::AddAndTrueToLoopCondition();
369 }
370 if (consume_suffix(&settingsText, " CannotUseFractForNegativeValues")) {
371 *caps = Factory::CannotUseFractForNegativeValues();
372 }
373 if (consume_suffix(&settingsText, " CannotUseFragCoord")) {
374 *caps = Factory::CannotUseFragCoord();
375 }
376 if (consume_suffix(&settingsText, " CannotUseMinAndAbsTogether")) {
377 *caps = Factory::CannotUseMinAndAbsTogether();
378 }
379 if (consume_suffix(&settingsText, " CannotUseVoidInSequenceExpressions")) {
380 *caps = Factory::CannotUseVoidInSequenceExpressions();
381 }
382 if (consume_suffix(&settingsText, " DualSourceBlending")) {
383 *caps = Factory::DualSourceBlending();
384 }
385 if (consume_suffix(&settingsText, " Default")) {
386 *caps = Factory::Default();
387 }
388 if (consume_suffix(&settingsText, " EmulateAbsIntFunction")) {
389 *caps = Factory::EmulateAbsIntFunction();
390 }
391 if (consume_suffix(&settingsText, " FramebufferFetchSupport")) {
392 *caps = Factory::FramebufferFetchSupport();
393 }
394 if (consume_suffix(&settingsText, " MustGuardDivisionEvenAfterExplicitZeroCheck")) {
395 *caps = Factory::MustGuardDivisionEvenAfterExplicitZeroCheck();
396 }
397 if (consume_suffix(&settingsText, " MustDeclareFragmentFrontFacing")) {
398 *caps = Factory::MustDeclareFragmentFrontFacing();
399 }
400 if (consume_suffix(&settingsText, " MustForceNegatedAtanParamToFloat")) {
401 *caps = Factory::MustForceNegatedAtanParamToFloat();
402 }
403 if (consume_suffix(&settingsText, " MustForceNegatedLdexpParamToMultiply")) {
404 *caps = Factory::MustForceNegatedLdexpParamToMultiply();
405 }
406 if (consume_suffix(&settingsText, " NoBuiltinDeterminantSupport")) {
407 *caps = Factory::NoBuiltinDeterminantSupport();
408 }
409 if (consume_suffix(&settingsText, " NoBuiltinFMASupport")) {
410 *caps = Factory::NoBuiltinFMASupport();
411 }
412 if (consume_suffix(&settingsText, " NoExternalTextureSupport")) {
413 *caps = Factory::NoExternalTextureSupport();
414 }
415 if (consume_suffix(&settingsText, " RemovePowWithConstantExponent")) {
416 *caps = Factory::RemovePowWithConstantExponent();
417 }
418 if (consume_suffix(&settingsText, " RewriteDoWhileLoops")) {
419 *caps = Factory::RewriteDoWhileLoops();
420 }
421 if (consume_suffix(&settingsText, " RewriteSwitchStatements")) {
422 *caps = Factory::RewriteSwitchStatements();
423 }
424 if (consume_suffix(&settingsText, " RewriteMatrixVectorMultiply")) {
425 *caps = Factory::RewriteMatrixVectorMultiply();
426 }
427 if (consume_suffix(&settingsText, " RewriteMatrixComparisons")) {
428 *caps = Factory::RewriteMatrixComparisons();
429 }
430 if (consume_suffix(&settingsText, " ShaderDerivativeExtensionString")) {
431 *caps = Factory::ShaderDerivativeExtensionString();
432 }
433 if (consume_suffix(&settingsText, " UnfoldShortCircuitAsTernary")) {
434 *caps = Factory::UnfoldShortCircuitAsTernary();
435 }
436 if (consume_suffix(&settingsText, " UsesPrecisionModifiers")) {
437 *caps = Factory::UsesPrecisionModifiers();
438 }
439 if (consume_suffix(&settingsText, " Version110")) {
440 *caps = Factory::Version110();
441 }
442 if (consume_suffix(&settingsText, " Version450Core")) {
443 *caps = Factory::Version450Core();
444 }
445 if (consume_suffix(&settingsText, " AllowNarrowingConversions")) {
446 settings->fAllowNarrowingConversions = true;
447 }
448 if (consume_suffix(&settingsText, " ForceHighPrecision")) {
449 settings->fForceHighPrecision = true;
450 }
451 if (consume_suffix(&settingsText, " NoInline")) {
452 settings->fInlineThreshold = 0;
453 }
454 if (consume_suffix(&settingsText, " NoOptimize")) {
455 settings->fOptimize = false;
456 settings->fInlineThreshold = 0;
457 }
458 if (consume_suffix(&settingsText, " NoRTFlip")) {
459 settings->fForceNoRTFlip = true;
460 }
461 if (consume_suffix(&settingsText, " InlineThresholdMax")) {
462 settings->fInlineThreshold = INT_MAX;
463 }
464 if (consume_suffix(&settingsText, " Sharpen")) {
465 settings->fSharpenTextures = true;
466 }
467 if (consume_suffix(&settingsText, " DebugTrace")) {
468 settings->fOptimize = false;
469 *debugTrace = std::make_unique<SkSL::DebugTracePriv>();
470 }
471
472 if (settingsText.empty()) {
473 break;
474 }
475 if (settingsText.length() == startingLength) {
476 printf("Unrecognized #pragma settings: %s\n", settingsText.c_str());
477 return false;
478 }
479 }
480 }
481 }
482
483 return true;
484}
485
486/**
487 * Displays a usage banner; used when the command line arguments don't make sense.
488 */
489static void show_usage() {
490 printf("usage: skslc <input> <output> <flags>\n"
491 " skslc <worklist>\n"
492 "\n"
493 "Allowed flags:\n"
494 "--settings: honor embedded /*#pragma settings*/ comments.\n"
495 "--nosettings: ignore /*#pragma settings*/ comments\n");
496}
497
498static bool set_flag(std::optional<bool>* flag, const char* name, bool value) {
499 if (flag->has_value()) {
500 printf("%s flag was specified multiple times\n", name);
501 return false;
502 }
503 *flag = value;
504 return true;
505}
506
507/**
508 * Handle a single input.
509 */
511 std::optional<bool> honorSettings;
512 std::vector<std::string> paths;
513 for (size_t i = 1; i < args.size(); ++i) {
514 const std::string& arg = args[i];
515 if (arg == "--settings") {
516 if (!set_flag(&honorSettings, "settings", true)) {
518 }
519 } else if (arg == "--nosettings") {
520 if (!set_flag(&honorSettings, "settings", false)) {
522 }
523 } else if (!skstd::starts_with(arg, "--")) {
524 paths.push_back(arg);
525 } else {
526 show_usage();
528 }
529 }
530 if (paths.size() != 2) {
531 show_usage();
533 }
534
535 if (!honorSettings.has_value()) {
536 honorSettings = true;
537 }
538
539 const std::string& inputPath = paths[0];
540 const std::string& outputPath = paths[1];
542 if (skstd::ends_with(inputPath, ".vert")) {
544 } else if (skstd::ends_with(inputPath, ".frag") || skstd::ends_with(inputPath, ".sksl")) {
546 } else if (skstd::ends_with(inputPath, ".mvert")) {
548 } else if (skstd::ends_with(inputPath, ".mfrag")) {
550 } else if (skstd::ends_with(inputPath, ".compute")) {
552 } else if (skstd::ends_with(inputPath, ".rtb")) {
554 } else if (skstd::ends_with(inputPath, ".rtcf")) {
556 } else if (skstd::ends_with(inputPath, ".rts")) {
558 } else if (skstd::ends_with(inputPath, ".privrts")) {
560 } else {
561 printf("input filename must end in '.vert', '.frag', '.mvert', '.mfrag', '.compute', "
562 "'.rtb', '.rtcf', '.rts', '.privrts', or '.sksl'\n");
564 }
565
566 std::ifstream in(inputPath);
567 std::string text((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
568 if (in.rdstate()) {
569 printf("error reading '%s'\n", inputPath.c_str());
571 }
572
575 std::unique_ptr<SkSL::DebugTracePriv> debugTrace;
576 if (*honorSettings) {
577 if (!detect_shader_settings(text, &settings, &caps, &debugTrace)) {
579 }
580 }
581
582 // This tells the compiler where the rt-flip uniform will live should it be required. For
583 // testing purposes we don't care where that is, but the compiler will report an error if we
584 // leave them at their default invalid values, or if the offset overlaps another uniform.
585 settings.fRTFlipOffset = 16384;
586 settings.fRTFlipSet = 0;
587 settings.fRTFlipBinding = 0;
588
589 auto emitCompileError = [&](const char* errorText) {
590 // Overwrite the compiler output, if any, with an error message.
591 SkSL::FileOutputStream errorStream(outputPath.c_str());
592 errorStream.writeText("### Compilation failed:\n\n");
593 errorStream.writeText(errorText);
594 errorStream.close();
595 // Also emit the error directly to stdout.
596 puts(errorText);
597 };
598
599 auto compileProgram = [&](const auto& writeFn) -> ResultCode {
600 SkSL::FileOutputStream out(outputPath.c_str());
602 if (!out.isValid()) {
603 printf("error writing '%s'\n", outputPath.c_str());
605 }
606 std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
607 if (!program || !writeFn(compiler, caps, *program, out)) {
608 out.close();
609 emitCompileError(compiler.errorText().c_str());
611 }
612 if (!out.close()) {
613 printf("error writing '%s'\n", outputPath.c_str());
615 }
617 };
618
619 auto compileProgramAsRuntimeShader = [&](const auto& writeFn) -> ResultCode {
620 if (kind == SkSL::ProgramKind::kVertex) {
621 emitCompileError("Runtime shaders do not support vertex programs\n");
623 }
624 if (kind == SkSL::ProgramKind::kFragment) {
625 // Handle .sksl and .frag programs as runtime shaders.
627 }
628 return compileProgram(writeFn);
629 };
630
631 if (skstd::ends_with(outputPath, ".spirv")) {
632 return compileProgram([](SkSL::Compiler& compiler,
633 const SkSL::ShaderCaps* shaderCaps,
634 SkSL::Program& program,
636 return SkSL::ToSPIRV(program, shaderCaps, out);
637 });
638 } else if (skstd::ends_with(outputPath, ".asm.frag") ||
639 skstd::ends_with(outputPath, ".asm.vert") ||
640 skstd::ends_with(outputPath, ".asm.comp")) {
641 return compileProgram(
643 const SkSL::ShaderCaps* shaderCaps,
644 SkSL::Program& program,
646 // Compile program to SPIR-V assembly in a string-stream.
647 SkSL::StringStream assembly;
648 if (!SkSL::ToSPIRV(program, shaderCaps, assembly)) {
649 return false;
650 }
651 // Convert the string-stream to a SPIR-V disassembly.
652 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
653 const std::string& spirv(assembly.str());
654 std::string disassembly;
655 uint32_t options = spvtools::SpirvTools::kDefaultDisassembleOption;
656 options |= SPV_BINARY_TO_TEXT_OPTION_INDENT;
657 if (!tools.Disassemble((const uint32_t*)spirv.data(),
658 spirv.size() / 4,
659 &disassembly,
660 options)) {
661 return false;
662 }
663 // Finally, write the disassembly to our output stream.
664 out.write(disassembly.data(), disassembly.size());
665 return true;
666 });
667 } else if (skstd::ends_with(outputPath, ".glsl")) {
668 return compileProgram(
670 const SkSL::ShaderCaps* shaderCaps,
671 SkSL::Program& program,
672 SkSL::OutputStream& out) { return SkSL::ToGLSL(program, shaderCaps, out); });
673 } else if (skstd::ends_with(outputPath, ".metal")) {
674 return compileProgram(
676 const SkSL::ShaderCaps* shaderCaps,
677 SkSL::Program& program,
678 SkSL::OutputStream& out) { return SkSL::ToMetal(program, shaderCaps, out); });
679 } else if (skstd::ends_with(outputPath, ".hlsl")) {
680 return compileProgram(
682 const SkSL::ShaderCaps* shaderCaps,
683 SkSL::Program& program,
684 SkSL::OutputStream& out) { return SkSL::ToHLSL(program, shaderCaps, out); });
685 } else if (skstd::ends_with(outputPath, ".wgsl")) {
686 return compileProgram(
688 const SkSL::ShaderCaps* shaderCaps,
689 SkSL::Program& program,
690 SkSL::OutputStream& out) { return SkSL::ToWGSL(program, shaderCaps, out); });
691 } else if (skstd::ends_with(outputPath, ".skrp")) {
692 settings.fMaxVersionAllowed = SkSL::Version::k300;
693 return compileProgramAsRuntimeShader([&](SkSL::Compiler& compiler,
694 const SkSL::ShaderCaps* shaderCaps,
695 SkSL::Program& program,
697 SkSL::DebugTracePriv skrpDebugTrace;
698 const SkSL::FunctionDeclaration* main = program.getFunction("main");
699 if (!main) {
700 compiler.errorReporter().error({}, "code has no entrypoint");
701 return false;
702 }
703 bool wantTraceOps = (debugTrace != nullptr);
704 std::unique_ptr<SkSL::RP::Program> rasterProg = SkSL::MakeRasterPipelineProgram(
705 program, *main->definition(), &skrpDebugTrace, wantTraceOps);
706 if (!rasterProg) {
707 compiler.errorReporter().error({}, "code is not supported");
708 return false;
709 }
710 rasterProg->dump(as_SkWStream(out).get(), /*writeInstructionCount=*/true);
711 return true;
712 });
713 } else if (skstd::ends_with(outputPath, ".stage")) {
714 return compileProgram([](SkSL::Compiler&,
715 const SkSL::ShaderCaps* shaderCaps,
716 SkSL::Program& program,
718 class Callbacks : public SkSL::PipelineStage::Callbacks {
719 public:
720 std::string getMangledName(const char* name) override {
721 return std::string(name) + "_0";
722 }
723
724 std::string declareUniform(const SkSL::VarDeclaration* decl) override {
725 fOutput += decl->description();
726 return std::string(decl->var()->name());
727 }
728
729 void defineFunction(const char* decl, const char* body, bool /*isMain*/) override {
730 fOutput += std::string(decl) + '{' + body + '}';
731 }
732
733 void declareFunction(const char* decl) override { fOutput += decl; }
734
735 void defineStruct(const char* definition) override { fOutput += definition; }
736
737 void declareGlobal(const char* declaration) override { fOutput += declaration; }
738
739 std::string sampleShader(int index, std::string coords) override {
740 return "child_" + std::to_string(index) + ".eval(" + coords + ')';
741 }
742
743 std::string sampleColorFilter(int index, std::string color) override {
744 return "child_" + std::to_string(index) + ".eval(" + color + ')';
745 }
746
747 std::string sampleBlender(int index, std::string src, std::string dst) override {
748 return "child_" + std::to_string(index) + ".eval(" + src + ", " + dst + ')';
749 }
750
751 std::string toLinearSrgb(std::string color) override {
752 return "toLinearSrgb(" + color + ')';
753 }
754 std::string fromLinearSrgb(std::string color) override {
755 return "fromLinearSrgb(" + color + ')';
756 }
757
758 std::string fOutput;
759 };
760 // The .stage output looks almost like valid SkSL, but not quite.
761 // The PipelineStageGenerator bridges the gap between the SkSL in `program`,
762 // and the C++ FP builder API (see GrSkSLFP). In that API, children don't need
763 // to be declared (so they don't emit declarations here). Children are sampled
764 // by index, not name - so all children here are just "child_N".
765 // The input color and coords have names in the original SkSL (as parameters to
766 // main), but those are ignored here. References to those variables become
767 // "_coords" and "_inColor". At runtime, those variable names are irrelevant
768 // when the new SkSL is emitted inside the FP - references to those variables
769 // are replaced with strings from EmitArgs, and might be varyings or differently
770 // named parameters.
771 Callbacks callbacks;
772 SkSL::PipelineStage::ConvertProgram(program, "_coords", "_inColor",
773 "_canvasColor", &callbacks);
774 out.writeString(SkShaderUtils::PrettyPrint(callbacks.fOutput));
775 return true;
776 });
777 } else {
778 printf("expected output path to end with one of: .glsl, .html, .metal, .hlsl, .wgsl, "
779 ".spirv, .asm.vert, .asm.frag, .asm.comp, .skrp, .stage (got '%s')\n",
780 outputPath.c_str());
782 }
784}
785
786int main(int argc, const char** argv) {
787 if (argc == 2) {
788 // Worklists are the only two-argument case for skslc, and we don't intend to support
789 // nested worklists, so we can process them here.
790 return (int)ProcessWorklist(argv[1], process_command);
791 } else {
792 // Process non-worklist inputs.
793 std::vector<std::string> args;
794 for (int index=0; index<argc; ++index) {
795 args.push_back(argv[index]);
796 }
797
798 return (int)process_command(args);
799 }
800}
const char * options
ResultCode ProcessWorklist(const char *worklistPath, const std::function< ResultCode(SkSpan< std::string > args)> &processCommandFn)
ResultCode
@ kConfigurationError
static const SkSL::ShaderCaps * Version110()
Definition: Main.cpp:321
static const SkSL::ShaderCaps * UsesPrecisionModifiers()
Definition: Main.cpp:311
static const SkSL::ShaderCaps * NoExternalTextureSupport()
Definition: Main.cpp:218
static const SkSL::ShaderCaps * CannotUseFractForNegativeValues()
Definition: Main.cpp:91
static const SkSL::ShaderCaps * MustForceNegatedLdexpParamToMultiply()
Definition: Main.cpp:179
static const SkSL::ShaderCaps * UnfoldShortCircuitAsTernary()
Definition: Main.cpp:301
static const SkSL::ShaderCaps * AddAndTrueToLoopCondition()
Definition: Main.cpp:81
static const SkSL::ShaderCaps * CannotUseVoidInSequenceExpressions()
Definition: Main.cpp:121
static const SkSL::ShaderCaps * RewriteSwitchStatements()
Definition: Main.cpp:268
static const SkSL::ShaderCaps * NoBuiltinDeterminantSupport()
Definition: Main.cpp:198
static const SkSL::ShaderCaps * MustForceNegatedAtanParamToFloat()
Definition: Main.cpp:169
static const SkSL::ShaderCaps * RemovePowWithConstantExponent()
Definition: Main.cpp:228
static const SkSL::ShaderCaps * Version450Core()
Definition: Main.cpp:331
static const SkSL::ShaderCaps * MustGuardDivisionEvenAfterExplicitZeroCheck()
Definition: Main.cpp:189
static const SkSL::ShaderCaps * NoBuiltinFMASupport()
Definition: Main.cpp:208
static const SkSL::ShaderCaps * SampleMaskSupport()
Definition: Main.cpp:278
static const SkSL::ShaderCaps * ShaderDerivativeExtensionString()
Definition: Main.cpp:289
static const SkSL::ShaderCaps * RewriteMatrixComparisons()
Definition: Main.cpp:248
static const SkSL::ShaderCaps * CannotUseMinAndAbsTogether()
Definition: Main.cpp:111
static const SkSL::ShaderCaps * RewriteDoWhileLoops()
Definition: Main.cpp:238
static const SkSL::ShaderCaps * RewriteMatrixVectorMultiply()
Definition: Main.cpp:258
static const SkSL::ShaderCaps * EmulateAbsIntFunction()
Definition: Main.cpp:140
static const SkSL::ShaderCaps * FramebufferFetchSupport()
Definition: Main.cpp:150
static const SkSL::ShaderCaps * CannotUseFragCoord()
Definition: Main.cpp:101
static const SkSL::ShaderCaps * MustDeclareFragmentFrontFacing()
Definition: Main.cpp:160
static const SkSL::ShaderCaps * DualSourceBlending()
Definition: Main.cpp:131
void writeText(const char *s) override
virtual std::string sampleShader(int index, std::string coords)=0
virtual std::string sampleBlender(int index, std::string src, std::string dst)=0
virtual void defineStruct(const char *definition)=0
virtual void declareFunction(const char *declaration)=0
virtual std::string toLinearSrgb(std::string color)=0
virtual void declareGlobal(const char *declaration)=0
virtual std::string sampleColorFilter(int index, std::string color)=0
virtual std::string fromLinearSrgb(std::string color)=0
virtual void defineFunction(const char *declaration, const char *body, bool isMain)=0
virtual std::string declareUniform(const VarDeclaration *)=0
virtual std::string getMangledName(const char *name)
static const ShaderCaps * Standalone()
Definition: SkSLUtil.h:178
static std::unique_ptr< ShaderCaps > MakeShaderCaps()
Definition: SkSLUtil.cpp:25
const std::string & str() const
std::string_view name() const
Definition: SkSLSymbol.h:51
std::string description() const override
Variable * var() const
virtual bool write(const void *buffer, size_t size)=0
virtual void flush()
Definition: SkStream.cpp:77
virtual size_t bytesWritten() const =0
DlColor color
struct MyStruct s
FlutterSemanticsFlag flag
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
uint32_t uint32_t * format
std::u16string text
char ** argv
Definition: library.h:9
size_t raster_pipeline_highp_stride
Definition: SkOpts.cpp:26
void ConvertProgram(const Program &program, const char *sampleCoords, const char *inputColor, const char *destColor, Callbacks *callbacks)
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: SkSLString.cpp:83
bool ToSPIRV(Program &program, const ShaderCaps *caps, OutputStream &out)
bool ToWGSL(Program &program, const ShaderCaps *caps, OutputStream &out)
bool ToGLSL(Program &program, const ShaderCaps *caps, OutputStream &out)
bool ToMetal(Program &program, const ShaderCaps *caps, OutputStream &out)
bool ToHLSL(Program &program, const ShaderCaps *caps, OutputStream &out)
std::unique_ptr< RP::Program > MakeRasterPipelineProgram(const SkSL::Program &program, const FunctionDefinition &function, DebugTracePriv *debugTrace, bool writeTraceOps)
std::string PrettyPrint(const std::string &string)
SKSHAPER_API sk_sp< Factory > Factory()
va_start(args, format)
va_end(args)
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dst
Definition: cp.py:12
Definition: main.py:1
compiler
Definition: malisc.py:17
const myers::Point & get(const myers::Segment &)
constexpr bool starts_with(std::string_view str, std::string_view prefix)
Definition: SkStringView.h:17
constexpr bool ends_with(std::string_view str, std::string_view suffix)
Definition: SkStringView.h:28
static SkString to_string(int n)
Definition: nanobench.cpp:119
int main(int argc, const char **argv)
Definition: Main.cpp:156
const FunctionDeclaration * getFunction(const char *functionName) const
Definition: SkSLProgram.cpp:56
static std::unique_ptr< SkWStream > as_SkWStream(SkSL::OutputStream &s)
Definition: Main.cpp:50
static void show_usage()
Definition: Main.cpp:489
static ResultCode process_command(SkSpan< std::string > args)
Definition: Main.cpp:510
static bool consume_suffix(std::string *str, const char suffix[])
Definition: Main.cpp:71
void SkDebugf(const char format[],...)
Definition: Main.cpp:39
static bool set_flag(std::optional< bool > *flag, const char *name, bool value)
Definition: Main.cpp:498
static bool detect_shader_settings(const std::string &text, SkSL::ProgramSettings *settings, const SkSL::ShaderCaps **caps, std::unique_ptr< SkSL::DebugTracePriv > *debugTrace)
Definition: Main.cpp:344