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