ethannicholas | b3058bd | 2016-07-01 08:22:01 -0700 | [diff] [blame] | 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 | |
Brian Osman | 41d9067 | 2020-10-05 14:18:49 -0400 | [diff] [blame] | 8 | #define SK_OPTS_NS skslc_standalone |
| 9 | #include "src/opts/SkChecksum_opts.h" |
Brian Osman | 47726a1 | 2020-12-17 16:02:08 -0500 | [diff] [blame] | 10 | #include "src/opts/SkVM_opts.h" |
Brian Osman | 41d9067 | 2020-10-05 14:18:49 -0400 | [diff] [blame] | 11 | |
Brian Osman | 62b039b | 2021-02-08 13:49:53 -0500 | [diff] [blame] | 12 | #include "src/gpu/GrShaderUtils.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 13 | #include "src/sksl/SkSLCompiler.h" |
Ethan Nicholas | c18bb51 | 2020-07-28 14:46:53 -0400 | [diff] [blame] | 14 | #include "src/sksl/SkSLDehydrator.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 15 | #include "src/sksl/SkSLFileOutputStream.h" |
Ethan Nicholas | c18bb51 | 2020-07-28 14:46:53 -0400 | [diff] [blame] | 16 | #include "src/sksl/SkSLIRGenerator.h" |
| 17 | #include "src/sksl/SkSLStringStream.h" |
John Stiles | 194b9b9 | 2020-09-15 15:37:24 -0400 | [diff] [blame] | 18 | #include "src/sksl/SkSLUtil.h" |
John Stiles | 3738ef5 | 2021-04-13 10:41:57 -0400 | [diff] [blame] | 19 | #include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h" |
| 20 | #include "src/sksl/codegen/SkSLVMCodeGenerator.h" |
Ethan Nicholas | c18bb51 | 2020-07-28 14:46:53 -0400 | [diff] [blame] | 21 | #include "src/sksl/ir/SkSLUnresolvedFunction.h" |
ethannicholas | b3058bd | 2016-07-01 08:22:01 -0700 | [diff] [blame] | 22 | |
John Stiles | dda1d31 | 2020-11-20 16:28:50 -0500 | [diff] [blame] | 23 | #include "spirv-tools/libspirv.hpp" |
| 24 | |
Brian Osman | 41d9067 | 2020-10-05 14:18:49 -0400 | [diff] [blame] | 25 | #include <fstream> |
John Stiles | 031a767 | 2020-11-13 16:13:18 -0500 | [diff] [blame] | 26 | #include <limits.h> |
Brian Osman | a6ca975 | 2020-10-02 13:41:21 -0400 | [diff] [blame] | 27 | #include <stdarg.h> |
| 28 | #include <stdio.h> |
| 29 | |
| 30 | void SkDebugf(const char format[], ...) { |
| 31 | va_list args; |
| 32 | va_start(args, format); |
| 33 | vfprintf(stderr, format, args); |
| 34 | va_end(args); |
| 35 | } |
| 36 | |
Brian Osman | 41d9067 | 2020-10-05 14:18:49 -0400 | [diff] [blame] | 37 | namespace SkOpts { |
| 38 | decltype(hash_fn) hash_fn = skslc_standalone::hash_fn; |
Brian Osman | 47726a1 | 2020-12-17 16:02:08 -0500 | [diff] [blame] | 39 | decltype(interpret_skvm) interpret_skvm = skslc_standalone::interpret_skvm; |
Brian Osman | 41d9067 | 2020-10-05 14:18:49 -0400 | [diff] [blame] | 40 | } |
| 41 | |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 42 | enum class ResultCode { |
| 43 | kSuccess = 0, |
| 44 | kCompileError = 1, |
| 45 | kInputError = 2, |
| 46 | kOutputError = 3, |
John Stiles | dda1d31 | 2020-11-20 16:28:50 -0500 | [diff] [blame] | 47 | kConfigurationError = 4, |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 48 | }; |
| 49 | |
Brian Osman | 47726a1 | 2020-12-17 16:02:08 -0500 | [diff] [blame] | 50 | static 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: |
| 64 | SkSL::OutputStream& fOut; |
| 65 | size_t fBytesWritten; |
| 66 | }; |
| 67 | |
| 68 | return std::make_unique<Adapter>(s); |
| 69 | } |
| 70 | |
Ethan Nicholas | 762466e | 2017-06-29 10:03:38 -0400 | [diff] [blame] | 71 | // Given the path to a file (e.g. src/gpu/effects/GrFooFragmentProcessor.fp) and the expected |
| 72 | // filename prefix and suffix (e.g. "Gr" and ".fp"), returns the "base name" of the |
| 73 | // file (in this case, 'FooFragmentProcessor'). If no match, returns the empty string. |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 74 | static SkSL::String base_name(const SkSL::String& fpPath, const char* prefix, const char* suffix) { |
Ethan Nicholas | 762466e | 2017-06-29 10:03:38 -0400 | [diff] [blame] | 75 | SkSL::String result; |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 76 | const char* end = &*fpPath.end(); |
Ethan Nicholas | 762466e | 2017-06-29 10:03:38 -0400 | [diff] [blame] | 77 | const char* fileName = end; |
| 78 | // back up until we find a slash |
| 79 | while (fileName != fpPath && '/' != *(fileName - 1) && '\\' != *(fileName - 1)) { |
| 80 | --fileName; |
| 81 | } |
| 82 | if (!strncmp(fileName, prefix, strlen(prefix)) && |
| 83 | !strncmp(end - strlen(suffix), suffix, strlen(suffix))) { |
| 84 | result.append(fileName + strlen(prefix), end - fileName - strlen(prefix) - strlen(suffix)); |
| 85 | } |
| 86 | return result; |
| 87 | } |
| 88 | |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 89 | // Given a string containing an SkSL program, searches for a #pragma settings comment, like so: |
| 90 | // /*#pragma settings Default Sharpen*/ |
| 91 | // The passed-in Settings object will be updated accordingly. Any number of options can be provided. |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 92 | static bool detect_shader_settings(const SkSL::String& text, |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 93 | SkSL::Program::Settings* settings, |
| 94 | const SkSL::ShaderCapsClass** caps) { |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 95 | using Factory = SkSL::ShaderCapsFactory; |
| 96 | |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 97 | // Find a matching comment and isolate the name portion. |
| 98 | static constexpr char kPragmaSettings[] = "/*#pragma settings "; |
| 99 | const char* settingsPtr = strstr(text.c_str(), kPragmaSettings); |
| 100 | if (settingsPtr != nullptr) { |
| 101 | // Subtract one here in order to preserve the leading space, which is necessary to allow |
| 102 | // consumeSuffix to find the first item. |
| 103 | settingsPtr += strlen(kPragmaSettings) - 1; |
| 104 | |
| 105 | const char* settingsEnd = strstr(settingsPtr, "*/"); |
| 106 | if (settingsEnd != nullptr) { |
| 107 | SkSL::String settingsText{settingsPtr, size_t(settingsEnd - settingsPtr)}; |
| 108 | |
| 109 | // Apply settings as requested. Since they can come in any order, repeat until we've |
| 110 | // consumed them all. |
| 111 | for (;;) { |
| 112 | const size_t startingLength = settingsText.length(); |
| 113 | |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 114 | if (settingsText.consumeSuffix(" AddAndTrueToLoopCondition")) { |
| 115 | static auto s_addAndTrueCaps = Factory::AddAndTrueToLoopCondition(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 116 | *caps = s_addAndTrueCaps.get(); |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 117 | } |
John Stiles | 8f84cee | 2020-10-08 18:39:08 -0400 | [diff] [blame] | 118 | if (settingsText.consumeSuffix(" BlendModesFailRandomlyForAllZeroVec")) { |
| 119 | static auto s_blendZeroCaps = Factory::BlendModesFailRandomlyForAllZeroVec(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 120 | *caps = s_blendZeroCaps.get(); |
John Stiles | 8f84cee | 2020-10-08 18:39:08 -0400 | [diff] [blame] | 121 | } |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 122 | if (settingsText.consumeSuffix(" CannotUseFractForNegativeValues")) { |
| 123 | static auto s_negativeFractCaps = Factory::CannotUseFractForNegativeValues(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 124 | *caps = s_negativeFractCaps.get(); |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 125 | } |
John Stiles | be0a9ca | 2020-09-18 14:42:58 -0400 | [diff] [blame] | 126 | if (settingsText.consumeSuffix(" CannotUseFragCoord")) { |
| 127 | static auto s_noFragCoordCaps = Factory::CannotUseFragCoord(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 128 | *caps = s_noFragCoordCaps.get(); |
John Stiles | be0a9ca | 2020-09-18 14:42:58 -0400 | [diff] [blame] | 129 | } |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 130 | if (settingsText.consumeSuffix(" CannotUseMinAndAbsTogether")) { |
| 131 | static auto s_minAbsCaps = Factory::CannotUseMinAndAbsTogether(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 132 | *caps = s_minAbsCaps.get(); |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 133 | } |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 134 | if (settingsText.consumeSuffix(" Default")) { |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 135 | static auto s_defaultCaps = Factory::Default(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 136 | *caps = s_defaultCaps.get(); |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 137 | } |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 138 | if (settingsText.consumeSuffix(" EmulateAbsIntFunction")) { |
| 139 | static auto s_emulateAbsIntCaps = Factory::EmulateAbsIntFunction(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 140 | *caps = s_emulateAbsIntCaps.get(); |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 141 | } |
Brian Osman | a81e7e2 | 2021-09-15 10:28:27 -0400 | [diff] [blame^] | 142 | if (settingsText.consumeSuffix(" FramebufferFetchSupport")) { |
| 143 | static auto s_fbFetchSupport = Factory::FramebufferFetchSupport(); |
| 144 | *caps = s_fbFetchSupport.get(); |
| 145 | } |
John Stiles | be0a9ca | 2020-09-18 14:42:58 -0400 | [diff] [blame] | 146 | if (settingsText.consumeSuffix(" IncompleteShortIntPrecision")) { |
| 147 | static auto s_incompleteShortIntCaps = Factory::IncompleteShortIntPrecision(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 148 | *caps = s_incompleteShortIntCaps.get(); |
John Stiles | be0a9ca | 2020-09-18 14:42:58 -0400 | [diff] [blame] | 149 | } |
John Stiles | eaaa71b | 2020-10-08 22:18:10 -0400 | [diff] [blame] | 150 | if (settingsText.consumeSuffix(" MustGuardDivisionEvenAfterExplicitZeroCheck")) { |
| 151 | static auto s_div0Caps = Factory::MustGuardDivisionEvenAfterExplicitZeroCheck(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 152 | *caps = s_div0Caps.get(); |
John Stiles | eaaa71b | 2020-10-08 22:18:10 -0400 | [diff] [blame] | 153 | } |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 154 | if (settingsText.consumeSuffix(" MustForceNegatedAtanParamToFloat")) { |
| 155 | static auto s_negativeAtanCaps = Factory::MustForceNegatedAtanParamToFloat(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 156 | *caps = s_negativeAtanCaps.get(); |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 157 | } |
Chris Dalton | 155c33c | 2021-06-07 18:51:42 -0600 | [diff] [blame] | 158 | if (settingsText.consumeSuffix(" MustForceNegatedLdexpParamToMultiply")) { |
| 159 | static auto s_negativeLdexpCaps = |
| 160 | Factory::MustForceNegatedLdexpParamToMultiply(); |
| 161 | *caps = s_negativeLdexpCaps.get(); |
| 162 | } |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 163 | if (settingsText.consumeSuffix(" RemovePowWithConstantExponent")) { |
| 164 | static auto s_powCaps = Factory::RemovePowWithConstantExponent(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 165 | *caps = s_powCaps.get(); |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 166 | } |
John Stiles | be0a9ca | 2020-09-18 14:42:58 -0400 | [diff] [blame] | 167 | if (settingsText.consumeSuffix(" RewriteDoWhileLoops")) { |
| 168 | static auto s_rewriteLoopCaps = Factory::RewriteDoWhileLoops(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 169 | *caps = s_rewriteLoopCaps.get(); |
John Stiles | be0a9ca | 2020-09-18 14:42:58 -0400 | [diff] [blame] | 170 | } |
John Stiles | 85749c0 | 2021-03-23 17:12:03 -0400 | [diff] [blame] | 171 | if (settingsText.consumeSuffix(" RewriteMatrixVectorMultiply")) { |
| 172 | static auto s_rewriteMatVecMulCaps = Factory::RewriteMatrixVectorMultiply(); |
| 173 | *caps = s_rewriteMatVecMulCaps.get(); |
| 174 | } |
John Stiles | 5ee369f | 2021-05-21 17:27:57 -0400 | [diff] [blame] | 175 | if (settingsText.consumeSuffix(" RewriteMatrixComparisons")) { |
| 176 | static auto s_rewriteMatrixComparisons = Factory::RewriteMatrixComparisons(); |
| 177 | *caps = s_rewriteMatrixComparisons.get(); |
John Stiles | 36c5796 | 2021-05-20 18:00:39 -0400 | [diff] [blame] | 178 | } |
John Stiles | c884631 | 2020-09-18 12:03:42 -0400 | [diff] [blame] | 179 | if (settingsText.consumeSuffix(" ShaderDerivativeExtensionString")) { |
| 180 | static auto s_derivativeCaps = Factory::ShaderDerivativeExtensionString(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 181 | *caps = s_derivativeCaps.get(); |
John Stiles | c884631 | 2020-09-18 12:03:42 -0400 | [diff] [blame] | 182 | } |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 183 | if (settingsText.consumeSuffix(" UnfoldShortCircuitAsTernary")) { |
| 184 | static auto s_ternaryCaps = Factory::UnfoldShortCircuitAsTernary(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 185 | *caps = s_ternaryCaps.get(); |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 186 | } |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 187 | if (settingsText.consumeSuffix(" UsesPrecisionModifiers")) { |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 188 | static auto s_precisionCaps = Factory::UsesPrecisionModifiers(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 189 | *caps = s_precisionCaps.get(); |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 190 | } |
| 191 | if (settingsText.consumeSuffix(" Version110")) { |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 192 | static auto s_version110Caps = Factory::Version110(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 193 | *caps = s_version110Caps.get(); |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 194 | } |
| 195 | if (settingsText.consumeSuffix(" Version450Core")) { |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 196 | static auto s_version450CoreCaps = Factory::Version450Core(); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 197 | *caps = s_version450CoreCaps.get(); |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 198 | } |
John Stiles | 9fdcc51 | 2021-08-04 13:27:05 -0400 | [diff] [blame] | 199 | if (settingsText.consumeSuffix(" AllowNarrowingConversions")) { |
| 200 | settings->fAllowNarrowingConversions = true; |
| 201 | } |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 202 | if (settingsText.consumeSuffix(" ForceHighPrecision")) { |
| 203 | settings->fForceHighPrecision = true; |
| 204 | } |
John Stiles | 2195f94 | 2021-08-05 10:55:03 -0400 | [diff] [blame] | 205 | if (settingsText.consumeSuffix(" NoES2Restrictions")) { |
| 206 | settings->fEnforceES2Restrictions = false; |
| 207 | } |
John Stiles | f972313 | 2020-10-12 12:33:27 -0400 | [diff] [blame] | 208 | if (settingsText.consumeSuffix(" NoInline")) { |
| 209 | settings->fInlineThreshold = 0; |
| 210 | } |
John Stiles | 031a767 | 2020-11-13 16:13:18 -0500 | [diff] [blame] | 211 | if (settingsText.consumeSuffix(" InlineThresholdMax")) { |
| 212 | settings->fInlineThreshold = INT_MAX; |
| 213 | } |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 214 | if (settingsText.consumeSuffix(" Sharpen")) { |
| 215 | settings->fSharpenTextures = true; |
| 216 | } |
| 217 | |
| 218 | if (settingsText.empty()) { |
| 219 | break; |
| 220 | } |
| 221 | if (settingsText.length() == startingLength) { |
| 222 | printf("Unrecognized #pragma settings: %s\n", settingsText.c_str()); |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 223 | return false; |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 224 | } |
| 225 | } |
| 226 | } |
| 227 | } |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 228 | |
| 229 | return true; |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 230 | } |
| 231 | |
ethannicholas | b3058bd | 2016-07-01 08:22:01 -0700 | [diff] [blame] | 232 | /** |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 233 | * Displays a usage banner; used when the command line arguments don't make sense. |
ethannicholas | b3058bd | 2016-07-01 08:22:01 -0700 | [diff] [blame] | 234 | */ |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 235 | static void show_usage() { |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 236 | printf("usage: skslc <input> <output> <flags>\n" |
| 237 | " skslc <worklist>\n" |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 238 | "\n" |
| 239 | "Allowed flags:\n" |
| 240 | "--settings: honor embedded /*#pragma settings*/ comments.\n" |
| 241 | "--nosettings: ignore /*#pragma settings*/ comments\n"); |
| 242 | } |
| 243 | |
| 244 | /** |
| 245 | * Handle a single input. |
| 246 | */ |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 247 | ResultCode processCommand(std::vector<SkSL::String>& args) { |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 248 | bool honorSettings = true; |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 249 | if (args.size() == 4) { |
| 250 | // Handle four-argument case: `skslc in.sksl out.glsl --settings` |
| 251 | const SkSL::String& settingsArg = args[3]; |
| 252 | if (settingsArg == "--settings") { |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 253 | honorSettings = true; |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 254 | } else if (settingsArg == "--nosettings") { |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 255 | honorSettings = false; |
| 256 | } else { |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 257 | printf("unrecognized flag: %s\n\n", settingsArg.c_str()); |
| 258 | show_usage(); |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 259 | return ResultCode::kInputError; |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 260 | } |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 261 | } else if (args.size() != 3) { |
| 262 | show_usage(); |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 263 | return ResultCode::kInputError; |
ethannicholas | b3058bd | 2016-07-01 08:22:01 -0700 | [diff] [blame] | 264 | } |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 265 | |
John Stiles | dbd4e6f | 2021-02-16 13:29:15 -0500 | [diff] [blame] | 266 | SkSL::ProgramKind kind; |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 267 | const SkSL::String& inputPath = args[1]; |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 268 | if (inputPath.ends_with(".vert")) { |
John Stiles | dbd4e6f | 2021-02-16 13:29:15 -0500 | [diff] [blame] | 269 | kind = SkSL::ProgramKind::kVertex; |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 270 | } else if (inputPath.ends_with(".frag") || inputPath.ends_with(".sksl")) { |
John Stiles | dbd4e6f | 2021-02-16 13:29:15 -0500 | [diff] [blame] | 271 | kind = SkSL::ProgramKind::kFragment; |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 272 | } else if (inputPath.ends_with(".rtb")) { |
John Stiles | 2d8b835 | 2021-06-16 11:33:13 -0400 | [diff] [blame] | 273 | kind = SkSL::ProgramKind::kRuntimeBlender; |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 274 | } else if (inputPath.ends_with(".rtcf")) { |
Brian Osman | cbb60bd | 2021-04-12 09:49:20 -0400 | [diff] [blame] | 275 | kind = SkSL::ProgramKind::kRuntimeColorFilter; |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 276 | } else if (inputPath.ends_with(".rts")) { |
Brian Osman | cbb60bd | 2021-04-12 09:49:20 -0400 | [diff] [blame] | 277 | kind = SkSL::ProgramKind::kRuntimeShader; |
ethannicholas | b3058bd | 2016-07-01 08:22:01 -0700 | [diff] [blame] | 278 | } else { |
Brian Osman | 99ddd2a | 2021-08-27 11:21:12 -0400 | [diff] [blame] | 279 | printf("input filename must end in '.vert', '.frag', '.rtb', '.rtcf', " |
Brian Osman | cbb60bd | 2021-04-12 09:49:20 -0400 | [diff] [blame] | 280 | "'.rts', or '.sksl'\n"); |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 281 | return ResultCode::kInputError; |
ethannicholas | b3058bd | 2016-07-01 08:22:01 -0700 | [diff] [blame] | 282 | } |
| 283 | |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 284 | std::ifstream in(inputPath); |
John Stiles | 72664be | 2020-09-16 17:43:11 -0400 | [diff] [blame] | 285 | SkSL::String text((std::istreambuf_iterator<char>(in)), |
| 286 | std::istreambuf_iterator<char>()); |
ethannicholas | b3058bd | 2016-07-01 08:22:01 -0700 | [diff] [blame] | 287 | if (in.rdstate()) { |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 288 | printf("error reading '%s'\n", inputPath.c_str()); |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 289 | return ResultCode::kInputError; |
ethannicholas | b3058bd | 2016-07-01 08:22:01 -0700 | [diff] [blame] | 290 | } |
John Stiles | 194b9b9 | 2020-09-15 15:37:24 -0400 | [diff] [blame] | 291 | |
Ethan Nicholas | 941e7e2 | 2016-12-12 15:33:30 -0500 | [diff] [blame] | 292 | SkSL::Program::Settings settings; |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 293 | const SkSL::ShaderCapsClass* caps = &SkSL::standaloneCaps; |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 294 | if (honorSettings) { |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 295 | if (!detect_shader_settings(text, &settings, &caps)) { |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 296 | return ResultCode::kInputError; |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 297 | } |
John Stiles | 0ed9f31 | 2020-09-16 17:46:37 -0400 | [diff] [blame] | 298 | } |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 299 | |
Brian Salomon | d8d85b9 | 2021-07-07 09:41:17 -0400 | [diff] [blame] | 300 | // This tells the compiler where the rt-flip uniform will live should it be required. For |
| 301 | // testing purposes we don't care where that is, but the compiler will report an error if we |
John Stiles | b05f03d | 2021-08-12 16:09:21 -0400 | [diff] [blame] | 302 | // leave them at their default invalid values, or if the offset overlaps another uniform. |
| 303 | settings.fRTFlipOffset = 16384; |
Brian Salomon | d8d85b9 | 2021-07-07 09:41:17 -0400 | [diff] [blame] | 304 | settings.fRTFlipSet = 0; |
| 305 | settings.fRTFlipBinding = 0; |
| 306 | |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 307 | const SkSL::String& outputPath = args[2]; |
| 308 | auto emitCompileError = [&](SkSL::FileOutputStream& out, const char* errorText) { |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 309 | // Overwrite the compiler output, if any, with an error message. |
| 310 | out.close(); |
| 311 | SkSL::FileOutputStream errorStream(outputPath); |
| 312 | errorStream.writeText("### Compilation failed:\n\n"); |
| 313 | errorStream.writeText(errorText); |
| 314 | errorStream.close(); |
| 315 | // Also emit the error directly to stdout. |
| 316 | puts(errorText); |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 317 | }; |
| 318 | |
John Stiles | d6a5f449 | 2021-02-11 15:46:11 -0500 | [diff] [blame] | 319 | auto compileProgram = [&](const auto& writeFn) -> ResultCode { |
John Stiles | 445df8d | 2020-11-20 14:45:00 -0500 | [diff] [blame] | 320 | SkSL::FileOutputStream out(outputPath); |
John Stiles | d6a5f449 | 2021-02-11 15:46:11 -0500 | [diff] [blame] | 321 | SkSL::Compiler compiler(caps); |
John Stiles | 445df8d | 2020-11-20 14:45:00 -0500 | [diff] [blame] | 322 | if (!out.isValid()) { |
| 323 | printf("error writing '%s'\n", outputPath.c_str()); |
| 324 | return ResultCode::kOutputError; |
| 325 | } |
| 326 | std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings); |
| 327 | if (!program || !writeFn(compiler, *program, out)) { |
| 328 | emitCompileError(out, compiler.errorText().c_str()); |
| 329 | return ResultCode::kCompileError; |
| 330 | } |
| 331 | if (!out.close()) { |
| 332 | printf("error writing '%s'\n", outputPath.c_str()); |
| 333 | return ResultCode::kOutputError; |
| 334 | } |
| 335 | return ResultCode::kSuccess; |
| 336 | }; |
| 337 | |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 338 | if (outputPath.ends_with(".spirv")) { |
John Stiles | 445df8d | 2020-11-20 14:45:00 -0500 | [diff] [blame] | 339 | return compileProgram( |
John Stiles | 445df8d | 2020-11-20 14:45:00 -0500 | [diff] [blame] | 340 | [](SkSL::Compiler& compiler, SkSL::Program& program, SkSL::OutputStream& out) { |
| 341 | return compiler.toSPIRV(program, out); |
| 342 | }); |
Brian Osman | 99ddd2a | 2021-08-27 11:21:12 -0400 | [diff] [blame] | 343 | } else if (outputPath.ends_with(".asm.frag") || outputPath.ends_with(".asm.vert")) { |
John Stiles | dda1d31 | 2020-11-20 16:28:50 -0500 | [diff] [blame] | 344 | return compileProgram( |
John Stiles | dda1d31 | 2020-11-20 16:28:50 -0500 | [diff] [blame] | 345 | [](SkSL::Compiler& compiler, SkSL::Program& program, SkSL::OutputStream& out) { |
| 346 | // Compile program to SPIR-V assembly in a string-stream. |
| 347 | SkSL::StringStream assembly; |
| 348 | if (!compiler.toSPIRV(program, assembly)) { |
| 349 | return false; |
| 350 | } |
| 351 | // Convert the string-stream to a SPIR-V disassembly. |
| 352 | spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0); |
| 353 | const SkSL::String& spirv(assembly.str()); |
| 354 | std::string disassembly; |
| 355 | if (!tools.Disassemble((const uint32_t*)spirv.data(), |
| 356 | spirv.size() / 4, &disassembly)) { |
| 357 | return false; |
| 358 | } |
| 359 | // Finally, write the disassembly to our output stream. |
| 360 | out.write(disassembly.data(), disassembly.size()); |
| 361 | return true; |
| 362 | }); |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 363 | } else if (outputPath.ends_with(".glsl")) { |
John Stiles | 445df8d | 2020-11-20 14:45:00 -0500 | [diff] [blame] | 364 | return compileProgram( |
John Stiles | 445df8d | 2020-11-20 14:45:00 -0500 | [diff] [blame] | 365 | [](SkSL::Compiler& compiler, SkSL::Program& program, SkSL::OutputStream& out) { |
| 366 | return compiler.toGLSL(program, out); |
| 367 | }); |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 368 | } else if (outputPath.ends_with(".metal")) { |
John Stiles | 445df8d | 2020-11-20 14:45:00 -0500 | [diff] [blame] | 369 | return compileProgram( |
John Stiles | 445df8d | 2020-11-20 14:45:00 -0500 | [diff] [blame] | 370 | [](SkSL::Compiler& compiler, SkSL::Program& program, SkSL::OutputStream& out) { |
| 371 | return compiler.toMetal(program, out); |
| 372 | }); |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 373 | } else if (outputPath.ends_with(".skvm")) { |
Brian Osman | 23f00d7 | 2020-12-02 09:27:10 -0500 | [diff] [blame] | 374 | return compileProgram( |
Brian Osman | 47726a1 | 2020-12-17 16:02:08 -0500 | [diff] [blame] | 375 | [](SkSL::Compiler&, SkSL::Program& program, SkSL::OutputStream& out) { |
Mike Klein | 4535e61 | 2020-12-22 11:46:57 -0600 | [diff] [blame] | 376 | skvm::Builder builder{skvm::Features{}}; |
Brian Osman | 47726a1 | 2020-12-17 16:02:08 -0500 | [diff] [blame] | 377 | if (!SkSL::testingOnly_ProgramToSkVMShader(program, &builder)) { |
Brian Osman | 23f00d7 | 2020-12-02 09:27:10 -0500 | [diff] [blame] | 378 | return false; |
| 379 | } |
| 380 | |
Brian Osman | 47726a1 | 2020-12-17 16:02:08 -0500 | [diff] [blame] | 381 | std::unique_ptr<SkWStream> redirect = as_SkWStream(out); |
| 382 | builder.done().dump(redirect.get()); |
Brian Osman | 23f00d7 | 2020-12-02 09:27:10 -0500 | [diff] [blame] | 383 | return true; |
| 384 | }); |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 385 | } else if (outputPath.ends_with(".stage")) { |
John Stiles | d6a5f449 | 2021-02-11 15:46:11 -0500 | [diff] [blame] | 386 | return compileProgram( |
Brian Osman | 62b039b | 2021-02-08 13:49:53 -0500 | [diff] [blame] | 387 | [](SkSL::Compiler&, SkSL::Program& program, SkSL::OutputStream& out) { |
| 388 | class Callbacks : public SkSL::PipelineStage::Callbacks { |
| 389 | public: |
| 390 | using String = SkSL::String; |
| 391 | |
Brian Osman | a5ab63a | 2021-02-17 15:41:57 -0500 | [diff] [blame] | 392 | String getMangledName(const char* name) override { |
| 393 | return String(name) + "_0"; |
| 394 | } |
| 395 | |
Brian Osman | 62b039b | 2021-02-08 13:49:53 -0500 | [diff] [blame] | 396 | String declareUniform(const SkSL::VarDeclaration* decl) override { |
| 397 | fOutput += decl->description(); |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 398 | return String(decl->var().name()); |
Brian Osman | 62b039b | 2021-02-08 13:49:53 -0500 | [diff] [blame] | 399 | } |
| 400 | |
Brian Osman | 55761ae | 2021-02-09 16:52:53 -0500 | [diff] [blame] | 401 | void defineFunction(const char* decl, |
| 402 | const char* body, |
| 403 | bool /*isMain*/) override { |
| 404 | fOutput += String(decl) + "{" + body + "}"; |
Brian Osman | 62b039b | 2021-02-08 13:49:53 -0500 | [diff] [blame] | 405 | } |
| 406 | |
Brian Osman | 8e756f3 | 2021-02-10 10:19:27 -0500 | [diff] [blame] | 407 | void defineStruct(const char* definition) override { |
| 408 | fOutput += definition; |
| 409 | } |
| 410 | |
Brian Osman | 5e603c3 | 2021-02-17 15:39:06 -0500 | [diff] [blame] | 411 | void declareGlobal(const char* declaration) override { |
| 412 | fOutput += declaration; |
| 413 | } |
| 414 | |
John Stiles | d9a56b9 | 2021-07-23 15:50:39 -0400 | [diff] [blame] | 415 | String sampleShader(int index, String coords) override { |
Brian Osman | cbfa34a | 2021-09-02 09:26:27 -0400 | [diff] [blame] | 416 | return "child_" + SkSL::to_string(index) + ".eval(" + coords + ")"; |
John Stiles | 8050a4b | 2021-07-23 15:50:20 -0400 | [diff] [blame] | 417 | } |
| 418 | |
| 419 | String sampleColorFilter(int index, String color) override { |
Brian Osman | cbfa34a | 2021-09-02 09:26:27 -0400 | [diff] [blame] | 420 | return "child_" + SkSL::to_string(index) + ".eval(" + color + ")"; |
Brian Osman | 62b039b | 2021-02-08 13:49:53 -0500 | [diff] [blame] | 421 | } |
Brian Osman | 62b039b | 2021-02-08 13:49:53 -0500 | [diff] [blame] | 422 | |
John Stiles | 2955c26 | 2021-07-23 15:51:05 -0400 | [diff] [blame] | 423 | String sampleBlender(int index, String src, String dst) override { |
Brian Osman | cbfa34a | 2021-09-02 09:26:27 -0400 | [diff] [blame] | 424 | return "child_" + SkSL::to_string(index) + ".eval(" + src + ", " + |
John Stiles | 2955c26 | 2021-07-23 15:51:05 -0400 | [diff] [blame] | 425 | dst + ")"; |
| 426 | } |
| 427 | |
Brian Osman | c9125aa | 2021-04-21 09:57:19 -0400 | [diff] [blame] | 428 | String fOutput; |
Brian Osman | 62b039b | 2021-02-08 13:49:53 -0500 | [diff] [blame] | 429 | }; |
Brian Osman | 668496b | 2021-06-09 16:57:45 -0400 | [diff] [blame] | 430 | // The .stage output looks almost like valid SkSL, but not quite. |
| 431 | // The PipelineStageGenerator bridges the gap between the SkSL in `program`, |
| 432 | // and the C++ FP builder API (see GrSkSLFP). In that API, children don't need |
| 433 | // to be declared (so they don't emit declarations here). Children are sampled |
| 434 | // by index, not name - so all children here are just "child_N". |
| 435 | // The input color and coords have names in the original SkSL (as parameters to |
| 436 | // main), but those are ignored here. References to those variables become |
| 437 | // "_coords" and "_inColor". At runtime, those variable names are irrelevant |
| 438 | // when the new SkSL is emitted inside the FP - references to those variables |
| 439 | // are replaced with strings from EmitArgs, and might be varyings or differently |
| 440 | // named parameters. |
Brian Osman | 62b039b | 2021-02-08 13:49:53 -0500 | [diff] [blame] | 441 | Callbacks callbacks; |
John Stiles | 50d0d09 | 2021-06-09 17:24:31 -0400 | [diff] [blame] | 442 | SkSL::PipelineStage::ConvertProgram(program, "_coords", "_inColor", |
| 443 | "_canvasColor", &callbacks); |
Brian Osman | 62b039b | 2021-02-08 13:49:53 -0500 | [diff] [blame] | 444 | out.writeString(GrShaderUtils::PrettyPrint(callbacks.fOutput)); |
| 445 | return true; |
| 446 | }); |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 447 | } else if (outputPath.ends_with(".dehydrated.sksl")) { |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 448 | SkSL::FileOutputStream out(outputPath); |
Brian Osman | d7e7659 | 2020-11-02 12:26:22 -0500 | [diff] [blame] | 449 | SkSL::Compiler compiler(caps); |
Ethan Nicholas | c18bb51 | 2020-07-28 14:46:53 -0400 | [diff] [blame] | 450 | if (!out.isValid()) { |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 451 | printf("error writing '%s'\n", outputPath.c_str()); |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 452 | return ResultCode::kOutputError; |
Ethan Nicholas | c18bb51 | 2020-07-28 14:46:53 -0400 | [diff] [blame] | 453 | } |
John Stiles | a935c3f | 2021-02-25 10:35:49 -0500 | [diff] [blame] | 454 | SkSL::LoadedModule module = |
| 455 | compiler.loadModule(kind, SkSL::Compiler::MakeModulePath(inputPath.c_str()), |
| 456 | /*base=*/nullptr, /*dehydrate=*/true); |
Ethan Nicholas | c18bb51 | 2020-07-28 14:46:53 -0400 | [diff] [blame] | 457 | SkSL::Dehydrator dehydrator; |
Brian Osman | 0006ad0 | 2020-11-18 15:38:39 -0500 | [diff] [blame] | 458 | dehydrator.write(*module.fSymbols); |
| 459 | dehydrator.write(module.fElements); |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 460 | SkSL::String baseName = base_name(inputPath, "", ".sksl"); |
Ethan Nicholas | c18bb51 | 2020-07-28 14:46:53 -0400 | [diff] [blame] | 461 | SkSL::StringStream buffer; |
| 462 | dehydrator.finish(buffer); |
| 463 | const SkSL::String& data = buffer.str(); |
John Stiles | e1589a1 | 2020-10-08 13:56:46 -0400 | [diff] [blame] | 464 | out.printf("static uint8_t SKSL_INCLUDE_%s[] = {", baseName.c_str()); |
Ethan Nicholas | c18bb51 | 2020-07-28 14:46:53 -0400 | [diff] [blame] | 465 | for (size_t i = 0; i < data.length(); ++i) { |
John Stiles | e1589a1 | 2020-10-08 13:56:46 -0400 | [diff] [blame] | 466 | out.printf("%s%d,", dehydrator.prefixAtOffset(i), uint8_t(data[i])); |
Ethan Nicholas | c18bb51 | 2020-07-28 14:46:53 -0400 | [diff] [blame] | 467 | } |
| 468 | out.printf("};\n"); |
John Stiles | e1589a1 | 2020-10-08 13:56:46 -0400 | [diff] [blame] | 469 | out.printf("static constexpr size_t SKSL_INCLUDE_%s_LENGTH = sizeof(SKSL_INCLUDE_%s);\n", |
| 470 | baseName.c_str(), baseName.c_str()); |
Ethan Nicholas | c18bb51 | 2020-07-28 14:46:53 -0400 | [diff] [blame] | 471 | if (!out.close()) { |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 472 | printf("error writing '%s'\n", outputPath.c_str()); |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 473 | return ResultCode::kOutputError; |
Ethan Nicholas | c18bb51 | 2020-07-28 14:46:53 -0400 | [diff] [blame] | 474 | } |
ethannicholas | 5961bc9 | 2016-10-12 06:39:56 -0700 | [diff] [blame] | 475 | } else { |
John Stiles | a935c3f | 2021-02-25 10:35:49 -0500 | [diff] [blame] | 476 | printf("expected output path to end with one of: .glsl, .metal, .spirv, .asm.frag, .skvm, " |
Brian Osman | 99ddd2a | 2021-08-27 11:21:12 -0400 | [diff] [blame] | 477 | ".stage, .asm.vert (got '%s')\n", outputPath.c_str()); |
John Stiles | dda1d31 | 2020-11-20 16:28:50 -0500 | [diff] [blame] | 478 | return ResultCode::kConfigurationError; |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 479 | } |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 480 | return ResultCode::kSuccess; |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 481 | } |
| 482 | |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 483 | /** |
| 484 | * Processes multiple inputs in a single invocation of skslc. |
| 485 | */ |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 486 | ResultCode processWorklist(const char* worklistPath) { |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 487 | SkSL::String inputPath(worklistPath); |
Ethan Nicholas | d2e0960 | 2021-06-10 11:21:59 -0400 | [diff] [blame] | 488 | if (!inputPath.ends_with(".worklist")) { |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 489 | printf("expected .worklist file, found: %s\n\n", worklistPath); |
| 490 | show_usage(); |
John Stiles | dda1d31 | 2020-11-20 16:28:50 -0500 | [diff] [blame] | 491 | return ResultCode::kConfigurationError; |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 492 | } |
| 493 | |
| 494 | // The worklist contains one line per argument to pass to skslc. When a blank line is reached, |
| 495 | // those arguments will be passed to `processCommand`. |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 496 | auto resultCode = ResultCode::kSuccess; |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 497 | std::vector<SkSL::String> args = {"skslc"}; |
| 498 | std::ifstream in(worklistPath); |
| 499 | for (SkSL::String line; std::getline(in, line); ) { |
| 500 | if (in.rdstate()) { |
| 501 | printf("error reading '%s'\n", worklistPath); |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 502 | return ResultCode::kInputError; |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 503 | } |
| 504 | |
| 505 | if (!line.empty()) { |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 506 | // We found an argument. Remember it. |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 507 | args.push_back(std::move(line)); |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 508 | } else { |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 509 | // We found a blank line. If we have any arguments stored up, process them as a command. |
| 510 | if (!args.empty()) { |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 511 | ResultCode outcome = processCommand(args); |
| 512 | resultCode = std::max(resultCode, outcome); |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 513 | |
| 514 | // Clear every argument except the first ("skslc"). |
| 515 | args.resize(1); |
| 516 | } |
| 517 | } |
| 518 | } |
| 519 | |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 520 | // If the worklist ended with a list of arguments but no blank line, process those now. |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 521 | if (args.size() > 1) { |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 522 | ResultCode outcome = processCommand(args); |
| 523 | resultCode = std::max(resultCode, outcome); |
John Stiles | a1e8fe3 | 2020-11-11 17:29:28 -0500 | [diff] [blame] | 524 | } |
| 525 | |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 526 | // Return the "worst" status we encountered. For our purposes, compilation errors are the least |
| 527 | // serious, because they are expected to occur in unit tests. Other types of errors are not |
| 528 | // expected at all during a build. |
| 529 | return resultCode; |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 530 | } |
| 531 | |
| 532 | int main(int argc, const char** argv) { |
| 533 | if (argc == 2) { |
| 534 | // Worklists are the only two-argument case for skslc, and we don't intend to support |
| 535 | // nested worklists, so we can process them here. |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 536 | return (int)processWorklist(argv[1]); |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 537 | } else { |
| 538 | // Process non-worklist inputs. |
| 539 | std::vector<SkSL::String> args; |
| 540 | for (int index=0; index<argc; ++index) { |
| 541 | args.push_back(argv[index]); |
| 542 | } |
| 543 | |
John Stiles | a446ca1 | 2020-11-19 18:54:33 -0500 | [diff] [blame] | 544 | return (int)processCommand(args); |
Brian Osman | 7b23905 | 2020-11-18 17:04:33 +0000 | [diff] [blame] | 545 | } |
ethannicholas | b3058bd | 2016-07-01 08:22:01 -0700 | [diff] [blame] | 546 | } |