skia2/src/sksl/SkSLMain.cpp

658 lines
28 KiB
C++
Raw Normal View History

/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#define SK_OPTS_NS skslc_standalone
#include "include/core/SkGraphics.h"
#include "include/core/SkStream.h"
#include "include/private/SkStringView.h"
Revert "Reland "Remove skstd::optional entirely."" This reverts commit d161e2f6ecc802d069a61de71a4e7d9bc6b419cd. Reason for revert: Need to wait for Flutter fix to roll into Google3. Original change's description: > Reland "Remove skstd::optional entirely." > > This reverts commit 98e51006b9c1c8747ab99d6e2a738f64f5fc4f3b. > > Flutter fix: https://github.com/flutter/engine/pull/31193 > > Original change's description: > > Revert "Remove skstd::optional entirely." > > > > This reverts commit 17d0fc087ced7f1deeea92de6404ce48f8433698. > > > > Reason for revert: flutter still uses the skstd class > > > > Original change's description: > > > Remove skstd::optional entirely. > > > > > > Skia now uses C++17's std::optional. > > > > > > Change-Id: I387069589baaefadd25e25bcec3f4cc6ee6fd090 > > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/501477 > > > Reviewed-by: Ben Wagner <bungeman@google.com> > > > Reviewed-by: Brian Osman <brianosman@google.com> > > > Commit-Queue: John Stiles <johnstiles@google.com> > > > Auto-Submit: John Stiles <johnstiles@google.com> > > > > Change-Id: I2c001588007640ac7b8c9f0760038b46c220a07e > > No-Presubmit: true > > No-Tree-Checks: true > > No-Try: true > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/502702 > > Auto-Submit: John Stiles <johnstiles@google.com> > > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > > Reviewed-by: Brian Osman <brianosman@google.com> > > Commit-Queue: Brian Osman <brianosman@google.com> > > Change-Id: Ia0cd41eda845b02f518c501a23293d344756a4eb > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/502703 > Reviewed-by: Brian Osman <brianosman@google.com> > Auto-Submit: John Stiles <johnstiles@google.com> > Commit-Queue: John Stiles <johnstiles@google.com> Change-Id: I8f89412292ba5dfe955c3f44c403c3c232cdad2b No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://skia-review.googlesource.com/c/skia/+/503336 Auto-Submit: Brian Osman <brianosman@google.com> Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
2022-02-02 16:47:55 +00:00
#include "include/private/SkTOptional.h"
#include "src/core/SkCpu.h"
#include "src/core/SkOpts.h"
#include "src/opts/SkChecksum_opts.h"
#include "src/opts/SkVM_opts.h"
#include "src/sksl/SkSLCompiler.h"
#include "src/sksl/SkSLDehydrator.h"
#include "src/sksl/SkSLFileOutputStream.h"
#include "src/sksl/SkSLStringStream.h"
#include "src/sksl/SkSLUtil.h"
#include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h"
#include "src/sksl/codegen/SkSLVMCodeGenerator.h"
#include "src/sksl/ir/SkSLUnresolvedFunction.h"
#include "src/sksl/ir/SkSLVarDeclarations.h"
#include "src/sksl/tracing/SkVMDebugTrace.h"
#include "src/utils/SkShaderUtils.h"
#include "src/utils/SkVMVisualizer.h"
#include "spirv-tools/libspirv.hpp"
#include <fstream>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
extern bool gSkVMAllowJIT;
void SkDebugf(const char format[], ...) {
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
}
namespace SkOpts {
decltype(hash_fn) hash_fn = skslc_standalone::hash_fn;
decltype(interpret_skvm) interpret_skvm = skslc_standalone::interpret_skvm;
}
enum class ResultCode {
kSuccess = 0,
kCompileError = 1,
kInputError = 2,
kOutputError = 3,
kConfigurationError = 4,
};
static std::unique_ptr<SkWStream> as_SkWStream(SkSL::OutputStream& s) {
struct Adapter : public SkWStream {
public:
Adapter(SkSL::OutputStream& out) : fOut(out), fBytesWritten(0) {}
bool write(const void* buffer, size_t size) override {
fOut.write(buffer, size);
fBytesWritten += size;
return true;
}
void flush() override {}
size_t bytesWritten() const override { return fBytesWritten; }
private:
SkSL::OutputStream& fOut;
size_t fBytesWritten;
};
return std::make_unique<Adapter>(s);
}
// Given the path to a file (e.g. src/gpu/effects/GrFooFragmentProcessor.fp) and the expected
// filename prefix and suffix (e.g. "Gr" and ".fp"), returns the "base name" of the
// file (in this case, 'FooFragmentProcessor'). If no match, returns the empty string.
static std::string base_name(const std::string& fpPath, const char* prefix, const char* suffix) {
std::string result;
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
const char* end = &*fpPath.end();
const char* fileName = end;
// back up until we find a slash
while (fileName != fpPath && '/' != *(fileName - 1) && '\\' != *(fileName - 1)) {
--fileName;
}
if (!strncmp(fileName, prefix, strlen(prefix)) &&
!strncmp(end - strlen(suffix), suffix, strlen(suffix))) {
result.append(fileName + strlen(prefix), end - fileName - strlen(prefix) - strlen(suffix));
}
return result;
}
static bool consume_suffix(std::string* str, const char suffix[]) {
if (!skstd::ends_with(*str, suffix)) {
return false;
}
str->resize(str->length() - strlen(suffix));
return true;
}
// Given a string containing an SkSL program, searches for a #pragma settings comment, like so:
// /*#pragma settings Default Sharpen*/
// The passed-in Settings object will be updated accordingly. Any number of options can be provided.
static bool detect_shader_settings(const std::string& text,
SkSL::Program::Settings* settings,
const SkSL::ShaderCaps** caps,
std::unique_ptr<SkSL::SkVMDebugTrace>* debugTrace) {
using Factory = SkSL::ShaderCapsFactory;
// Find a matching comment and isolate the name portion.
static constexpr char kPragmaSettings[] = "/*#pragma settings ";
const char* settingsPtr = strstr(text.c_str(), kPragmaSettings);
if (settingsPtr != nullptr) {
// Subtract one here in order to preserve the leading space, which is necessary to allow
// consumeSuffix to find the first item.
settingsPtr += strlen(kPragmaSettings) - 1;
const char* settingsEnd = strstr(settingsPtr, "*/");
if (settingsEnd != nullptr) {
std::string settingsText{settingsPtr, size_t(settingsEnd - settingsPtr)};
// Apply settings as requested. Since they can come in any order, repeat until we've
// consumed them all.
for (;;) {
const size_t startingLength = settingsText.length();
if (consume_suffix(&settingsText, " AddAndTrueToLoopCondition")) {
static auto s_addAndTrueCaps = Factory::AddAndTrueToLoopCondition();
*caps = s_addAndTrueCaps.get();
}
if (consume_suffix(&settingsText, " CannotUseFractForNegativeValues")) {
static auto s_negativeFractCaps = Factory::CannotUseFractForNegativeValues();
*caps = s_negativeFractCaps.get();
}
if (consume_suffix(&settingsText, " CannotUseFragCoord")) {
static auto s_noFragCoordCaps = Factory::CannotUseFragCoord();
*caps = s_noFragCoordCaps.get();
}
if (consume_suffix(&settingsText, " CannotUseMinAndAbsTogether")) {
static auto s_minAbsCaps = Factory::CannotUseMinAndAbsTogether();
*caps = s_minAbsCaps.get();
}
if (consume_suffix(&settingsText, " Default")) {
static auto s_defaultCaps = Factory::Default();
*caps = s_defaultCaps.get();
}
if (consume_suffix(&settingsText, " EmulateAbsIntFunction")) {
static auto s_emulateAbsIntCaps = Factory::EmulateAbsIntFunction();
*caps = s_emulateAbsIntCaps.get();
}
if (consume_suffix(&settingsText, " FramebufferFetchSupport")) {
static auto s_fbFetchSupport = Factory::FramebufferFetchSupport();
*caps = s_fbFetchSupport.get();
}
if (consume_suffix(&settingsText, " IncompleteShortIntPrecision")) {
static auto s_incompleteShortIntCaps = Factory::IncompleteShortIntPrecision();
*caps = s_incompleteShortIntCaps.get();
}
if (consume_suffix(&settingsText, " MustGuardDivisionEvenAfterExplicitZeroCheck")) {
static auto s_div0Caps = Factory::MustGuardDivisionEvenAfterExplicitZeroCheck();
*caps = s_div0Caps.get();
}
if (consume_suffix(&settingsText, " MustForceNegatedAtanParamToFloat")) {
static auto s_negativeAtanCaps = Factory::MustForceNegatedAtanParamToFloat();
*caps = s_negativeAtanCaps.get();
}
if (consume_suffix(&settingsText, " MustForceNegatedLdexpParamToMultiply")) {
static auto s_negativeLdexpCaps =
Factory::MustForceNegatedLdexpParamToMultiply();
*caps = s_negativeLdexpCaps.get();
}
if (consume_suffix(&settingsText, " RemovePowWithConstantExponent")) {
static auto s_powCaps = Factory::RemovePowWithConstantExponent();
*caps = s_powCaps.get();
}
if (consume_suffix(&settingsText, " RewriteDoWhileLoops")) {
static auto s_rewriteLoopCaps = Factory::RewriteDoWhileLoops();
*caps = s_rewriteLoopCaps.get();
}
if (consume_suffix(&settingsText, " RewriteSwitchStatements")) {
static auto s_rewriteSwitchCaps = Factory::RewriteSwitchStatements();
*caps = s_rewriteSwitchCaps.get();
}
if (consume_suffix(&settingsText, " RewriteMatrixVectorMultiply")) {
static auto s_rewriteMatVecMulCaps = Factory::RewriteMatrixVectorMultiply();
*caps = s_rewriteMatVecMulCaps.get();
}
if (consume_suffix(&settingsText, " RewriteMatrixComparisons")) {
static auto s_rewriteMatrixComparisons = Factory::RewriteMatrixComparisons();
*caps = s_rewriteMatrixComparisons.get();
}
if (consume_suffix(&settingsText, " ShaderDerivativeExtensionString")) {
static auto s_derivativeCaps = Factory::ShaderDerivativeExtensionString();
*caps = s_derivativeCaps.get();
}
if (consume_suffix(&settingsText, " UnfoldShortCircuitAsTernary")) {
static auto s_ternaryCaps = Factory::UnfoldShortCircuitAsTernary();
*caps = s_ternaryCaps.get();
}
if (consume_suffix(&settingsText, " UsesPrecisionModifiers")) {
static auto s_precisionCaps = Factory::UsesPrecisionModifiers();
*caps = s_precisionCaps.get();
}
if (consume_suffix(&settingsText, " Version110")) {
static auto s_version110Caps = Factory::Version110();
*caps = s_version110Caps.get();
}
if (consume_suffix(&settingsText, " Version450Core")) {
static auto s_version450CoreCaps = Factory::Version450Core();
*caps = s_version450CoreCaps.get();
}
if (consume_suffix(&settingsText, " AllowNarrowingConversions")) {
settings->fAllowNarrowingConversions = true;
}
if (consume_suffix(&settingsText, " ForceHighPrecision")) {
settings->fForceHighPrecision = true;
}
if (consume_suffix(&settingsText, " NoES2Restrictions")) {
settings->fEnforceES2Restrictions = false;
}
if (consume_suffix(&settingsText, " NoInline")) {
settings->fInlineThreshold = 0;
}
if (consume_suffix(&settingsText, " NoTraceVarInSkVMDebugTrace")) {
settings->fAllowTraceVarInSkVMDebugTrace = false;
}
if (consume_suffix(&settingsText, " InlineThresholdMax")) {
settings->fInlineThreshold = INT_MAX;
}
if (consume_suffix(&settingsText, " Sharpen")) {
settings->fSharpenTextures = true;
}
if (consume_suffix(&settingsText, " SkVMDebugTrace")) {
settings->fOptimize = false;
*debugTrace = std::make_unique<SkSL::SkVMDebugTrace>();
}
if (settingsText.empty()) {
break;
}
if (settingsText.length() == startingLength) {
printf("Unrecognized #pragma settings: %s\n", settingsText.c_str());
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
return false;
}
}
}
}
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
return true;
}
/**
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
* Displays a usage banner; used when the command line arguments don't make sense.
*/
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
static void show_usage() {
printf("usage: skslc <input> <output> <flags>\n"
" skslc <worklist>\n"
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
"\n"
"Allowed flags:\n"
"--settings: honor embedded /*#pragma settings*/ comments.\n"
"--nosettings: ignore /*#pragma settings*/ comments\n");
}
Revert "Reland "Remove skstd::optional entirely."" This reverts commit d161e2f6ecc802d069a61de71a4e7d9bc6b419cd. Reason for revert: Need to wait for Flutter fix to roll into Google3. Original change's description: > Reland "Remove skstd::optional entirely." > > This reverts commit 98e51006b9c1c8747ab99d6e2a738f64f5fc4f3b. > > Flutter fix: https://github.com/flutter/engine/pull/31193 > > Original change's description: > > Revert "Remove skstd::optional entirely." > > > > This reverts commit 17d0fc087ced7f1deeea92de6404ce48f8433698. > > > > Reason for revert: flutter still uses the skstd class > > > > Original change's description: > > > Remove skstd::optional entirely. > > > > > > Skia now uses C++17's std::optional. > > > > > > Change-Id: I387069589baaefadd25e25bcec3f4cc6ee6fd090 > > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/501477 > > > Reviewed-by: Ben Wagner <bungeman@google.com> > > > Reviewed-by: Brian Osman <brianosman@google.com> > > > Commit-Queue: John Stiles <johnstiles@google.com> > > > Auto-Submit: John Stiles <johnstiles@google.com> > > > > Change-Id: I2c001588007640ac7b8c9f0760038b46c220a07e > > No-Presubmit: true > > No-Tree-Checks: true > > No-Try: true > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/502702 > > Auto-Submit: John Stiles <johnstiles@google.com> > > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > > Reviewed-by: Brian Osman <brianosman@google.com> > > Commit-Queue: Brian Osman <brianosman@google.com> > > Change-Id: Ia0cd41eda845b02f518c501a23293d344756a4eb > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/502703 > Reviewed-by: Brian Osman <brianosman@google.com> > Auto-Submit: John Stiles <johnstiles@google.com> > Commit-Queue: John Stiles <johnstiles@google.com> Change-Id: I8f89412292ba5dfe955c3f44c403c3c232cdad2b No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://skia-review.googlesource.com/c/skia/+/503336 Auto-Submit: Brian Osman <brianosman@google.com> Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
2022-02-02 16:47:55 +00:00
static bool set_flag(skstd::optional<bool>* flag, const char* name, bool value) {
if (flag->has_value()) {
printf("%s flag was specified multiple times\n", name);
return false;
}
*flag = value;
return true;
}
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
/**
* Handle a single input.
*/
ResultCode processCommand(const std::vector<std::string>& args) {
Revert "Reland "Remove skstd::optional entirely."" This reverts commit d161e2f6ecc802d069a61de71a4e7d9bc6b419cd. Reason for revert: Need to wait for Flutter fix to roll into Google3. Original change's description: > Reland "Remove skstd::optional entirely." > > This reverts commit 98e51006b9c1c8747ab99d6e2a738f64f5fc4f3b. > > Flutter fix: https://github.com/flutter/engine/pull/31193 > > Original change's description: > > Revert "Remove skstd::optional entirely." > > > > This reverts commit 17d0fc087ced7f1deeea92de6404ce48f8433698. > > > > Reason for revert: flutter still uses the skstd class > > > > Original change's description: > > > Remove skstd::optional entirely. > > > > > > Skia now uses C++17's std::optional. > > > > > > Change-Id: I387069589baaefadd25e25bcec3f4cc6ee6fd090 > > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/501477 > > > Reviewed-by: Ben Wagner <bungeman@google.com> > > > Reviewed-by: Brian Osman <brianosman@google.com> > > > Commit-Queue: John Stiles <johnstiles@google.com> > > > Auto-Submit: John Stiles <johnstiles@google.com> > > > > Change-Id: I2c001588007640ac7b8c9f0760038b46c220a07e > > No-Presubmit: true > > No-Tree-Checks: true > > No-Try: true > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/502702 > > Auto-Submit: John Stiles <johnstiles@google.com> > > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > > Reviewed-by: Brian Osman <brianosman@google.com> > > Commit-Queue: Brian Osman <brianosman@google.com> > > Change-Id: Ia0cd41eda845b02f518c501a23293d344756a4eb > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/502703 > Reviewed-by: Brian Osman <brianosman@google.com> > Auto-Submit: John Stiles <johnstiles@google.com> > Commit-Queue: John Stiles <johnstiles@google.com> Change-Id: I8f89412292ba5dfe955c3f44c403c3c232cdad2b No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://skia-review.googlesource.com/c/skia/+/503336 Auto-Submit: Brian Osman <brianosman@google.com> Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
2022-02-02 16:47:55 +00:00
skstd::optional<bool> honorSettings;
std::vector<std::string> paths;
for (size_t i = 1; i < args.size(); ++i) {
const std::string& arg = args[i];
if (arg == "--settings") {
if (!set_flag(&honorSettings, "settings", true)) {
return ResultCode::kInputError;
}
} else if (arg == "--nosettings") {
if (!set_flag(&honorSettings, "settings", false)) {
return ResultCode::kInputError;
}
} else if (!skstd::starts_with(arg, "--")) {
paths.push_back(arg);
} else {
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
show_usage();
return ResultCode::kInputError;
}
}
if (paths.size() != 2) {
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
show_usage();
return ResultCode::kInputError;
}
if (!honorSettings.has_value()) {
honorSettings = true;
}
const std::string& inputPath = paths[0];
const std::string& outputPath = paths[1];
SkSL::ProgramKind kind;
if (skstd::ends_with(inputPath, ".vert")) {
kind = SkSL::ProgramKind::kVertex;
} else if (skstd::ends_with(inputPath, ".frag") || skstd::ends_with(inputPath, ".sksl")) {
kind = SkSL::ProgramKind::kFragment;
} else if (skstd::ends_with(inputPath, ".rtb")) {
kind = SkSL::ProgramKind::kRuntimeBlender;
} else if (skstd::ends_with(inputPath, ".rtcf")) {
kind = SkSL::ProgramKind::kRuntimeColorFilter;
} else if (skstd::ends_with(inputPath, ".rts")) {
kind = SkSL::ProgramKind::kRuntimeShader;
} else {
printf("input filename must end in '.vert', '.frag', '.rtb', '.rtcf', "
"'.rts' or '.sksl'\n");
return ResultCode::kInputError;
}
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
std::ifstream in(inputPath);
std::string text((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
if (in.rdstate()) {
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
printf("error reading '%s'\n", inputPath.c_str());
return ResultCode::kInputError;
}
SkSL::Program::Settings settings;
auto standaloneCaps = SkSL::ShaderCapsFactory::Standalone();
const SkSL::ShaderCaps* caps = standaloneCaps.get();
std::unique_ptr<SkSL::SkVMDebugTrace> debugTrace;
if (*honorSettings) {
if (!detect_shader_settings(text, &settings, &caps, &debugTrace)) {
return ResultCode::kInputError;
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
}
}
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
// This tells the compiler where the rt-flip uniform will live should it be required. For
// testing purposes we don't care where that is, but the compiler will report an error if we
// leave them at their default invalid values, or if the offset overlaps another uniform.
settings.fRTFlipOffset = 16384;
settings.fRTFlipSet = 0;
settings.fRTFlipBinding = 0;
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
auto emitCompileError = [&](SkSL::FileOutputStream& out, const char* errorText) {
// Overwrite the compiler output, if any, with an error message.
out.close();
SkSL::FileOutputStream errorStream(outputPath.c_str());
errorStream.writeText("### Compilation failed:\n\n");
errorStream.writeText(errorText);
errorStream.close();
// Also emit the error directly to stdout.
puts(errorText);
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
};
auto compileProgram = [&](const auto& writeFn) -> ResultCode {
SkSL::FileOutputStream out(outputPath.c_str());
SkSL::Compiler compiler(caps);
if (!out.isValid()) {
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
printf("error writing '%s'\n", outputPath.c_str());
return ResultCode::kOutputError;
}
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
if (!program || !writeFn(compiler, *program, out)) {
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
emitCompileError(out, compiler.errorText().c_str());
return ResultCode::kCompileError;
}
if (!out.close()) {
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
printf("error writing '%s'\n", outputPath.c_str());
return ResultCode::kOutputError;
}
return ResultCode::kSuccess;
};
auto compileProgramForSkVM = [&](const auto& writeFn) -> ResultCode {
if (kind == SkSL::ProgramKind::kVertex) {
printf("%s: SkVM does not support vertex programs\n", outputPath.c_str());
return ResultCode::kOutputError;
}
if (kind == SkSL::ProgramKind::kFragment) {
// Handle .sksl and .frag programs as runtime shaders.
kind = SkSL::ProgramKind::kRuntimeShader;
}
return compileProgram(writeFn);
};
if (skstd::ends_with(outputPath, ".spirv")) {
return compileProgram(
[](SkSL::Compiler& compiler, SkSL::Program& program, SkSL::OutputStream& out) {
return compiler.toSPIRV(program, out);
});
} else if (skstd::ends_with(outputPath, ".asm.frag") ||
skstd::ends_with(outputPath, ".asm.vert")) {
return compileProgram(
[](SkSL::Compiler& compiler, SkSL::Program& program, SkSL::OutputStream& out) {
// Compile program to SPIR-V assembly in a string-stream.
SkSL::StringStream assembly;
if (!compiler.toSPIRV(program, assembly)) {
return false;
}
// Convert the string-stream to a SPIR-V disassembly.
spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
const std::string& spirv(assembly.str());
std::string disassembly;
if (!tools.Disassemble((const uint32_t*)spirv.data(),
spirv.size() / 4, &disassembly)) {
return false;
}
// Finally, write the disassembly to our output stream.
out.write(disassembly.data(), disassembly.size());
return true;
});
} else if (skstd::ends_with(outputPath, ".glsl")) {
return compileProgram(
[](SkSL::Compiler& compiler, SkSL::Program& program, SkSL::OutputStream& out) {
return compiler.toGLSL(program, out);
});
} else if (skstd::ends_with(outputPath, ".metal")) {
return compileProgram(
[](SkSL::Compiler& compiler, SkSL::Program& program, SkSL::OutputStream& out) {
return compiler.toMetal(program, out);
});
} else if (skstd::ends_with(outputPath, ".hlsl")) {
return compileProgram(
[](SkSL::Compiler& compiler, SkSL::Program& program, SkSL::OutputStream& out) {
return compiler.toHLSL(program, out);
});
} else if (skstd::ends_with(outputPath, ".skvm")) {
return compileProgramForSkVM(
[&](SkSL::Compiler&, SkSL::Program& program, SkSL::OutputStream& out) {
skvm::Builder builder{skvm::Features{}};
if (!SkSL::testingOnly_ProgramToSkVMShader(program, &builder,
debugTrace.get())) {
return false;
}
std::unique_ptr<SkWStream> redirect = as_SkWStream(out);
if (debugTrace) {
debugTrace->dump(redirect.get());
}
builder.done().dump(redirect.get());
return true;
});
} else if (skstd::ends_with(outputPath, ".stage")) {
return compileProgram(
[](SkSL::Compiler&, SkSL::Program& program, SkSL::OutputStream& out) {
class Callbacks : public SkSL::PipelineStage::Callbacks {
public:
std::string getMangledName(const char* name) override {
return std::string(name) + "_0";
}
std::string declareUniform(const SkSL::VarDeclaration* decl) override {
fOutput += decl->description();
return std::string(decl->var().name());
}
void defineFunction(const char* decl,
const char* body,
bool /*isMain*/) override {
fOutput += std::string(decl) + "{" + body + "}";
}
void declareFunction(const char* decl) override {
fOutput += std::string(decl) + ";";
}
void defineStruct(const char* definition) override {
fOutput += definition;
}
void declareGlobal(const char* declaration) override {
fOutput += declaration;
}
std::string sampleShader(int index, std::string coords) override {
return "child_" + skstd::to_string(index) + ".eval(" + coords + ")";
}
std::string sampleColorFilter(int index, std::string color) override {
return "child_" + skstd::to_string(index) + ".eval(" + color + ")";
}
std::string sampleBlender(int index,
std::string src,
std::string dst) override {
return "child_" + skstd::to_string(index) + ".eval(" + src + ", " +
dst + ")";
}
std::string toLinearSrgb(std::string color) override {
return "toLinearSrgb(" + color + ")";
}
std::string fromLinearSrgb(std::string color) override {
return "fromLinearSrgb(" + color + ")";
}
std::string fOutput;
};
// The .stage output looks almost like valid SkSL, but not quite.
// The PipelineStageGenerator bridges the gap between the SkSL in `program`,
// and the C++ FP builder API (see GrSkSLFP). In that API, children don't need
// to be declared (so they don't emit declarations here). Children are sampled
// by index, not name - so all children here are just "child_N".
// The input color and coords have names in the original SkSL (as parameters to
// main), but those are ignored here. References to those variables become
// "_coords" and "_inColor". At runtime, those variable names are irrelevant
// when the new SkSL is emitted inside the FP - references to those variables
// are replaced with strings from EmitArgs, and might be varyings or differently
// named parameters.
Callbacks callbacks;
SkSL::PipelineStage::ConvertProgram(program, "_coords", "_inColor",
"_canvasColor", &callbacks);
out.writeString(SkShaderUtils::PrettyPrint(callbacks.fOutput));
return true;
});
} else if (skstd::ends_with(outputPath, ".dehydrated.sksl")) {
SkSL::FileOutputStream out(outputPath.c_str());
SkSL::Compiler compiler(caps);
if (!out.isValid()) {
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
printf("error writing '%s'\n", outputPath.c_str());
return ResultCode::kOutputError;
}
SkSL::LoadedModule module =
compiler.loadModule(kind, SkSL::Compiler::MakeModulePath(inputPath.c_str()),
/*base=*/nullptr, /*dehydrate=*/true);
SkSL::Dehydrator dehydrator;
dehydrator.write(*module.fSymbols);
dehydrator.write(module.fElements);
std::string baseName = base_name(inputPath, "", ".sksl");
SkSL::StringStream buffer;
dehydrator.finish(buffer);
const std::string& data = buffer.str();
out.printf("static uint8_t SKSL_INCLUDE_%s[] = {", baseName.c_str());
for (size_t i = 0; i < data.length(); ++i) {
out.printf("%s%d,", dehydrator.prefixAtOffset(i), uint8_t(data[i]));
}
out.printf("};\n");
out.printf("static constexpr size_t SKSL_INCLUDE_%s_LENGTH = sizeof(SKSL_INCLUDE_%s);\n",
baseName.c_str(), baseName.c_str());
if (!out.close()) {
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
printf("error writing '%s'\n", outputPath.c_str());
return ResultCode::kOutputError;
}
} else if (skstd::ends_with(outputPath, ".html")) {
settings.fAllowTraceVarInSkVMDebugTrace = false;
SkCpu::CacheRuntimeFeatures();
gSkVMAllowJIT = true;
return compileProgramForSkVM(
[&](SkSL::Compiler&, SkSL::Program& program, SkSL::OutputStream& out) {
if (!debugTrace) {
debugTrace = std::make_unique<SkSL::SkVMDebugTrace>();
debugTrace->setSource(text.c_str());
}
auto visualizer = std::make_unique<skvm::viz::Visualizer>(debugTrace.get());
skvm::Builder builder(skvm::Features{}, /*createDuplicates=*/true);
if (!SkSL::testingOnly_ProgramToSkVMShader(program, &builder, debugTrace.get())) {
return false;
}
std::unique_ptr<SkWStream> redirect = as_SkWStream(out);
skvm::Program p = builder.done(
/*debug_name=*/nullptr, /*allow_jit=*/true, std::move(visualizer));
#if defined(SKVM_JIT)
SkDynamicMemoryWStream asmFile;
p.disassemble(&asmFile);
auto dumpData = asmFile.detachAsData();
std::string dumpString(static_cast<const char*>(dumpData->data()),dumpData->size());
p.visualize(redirect.get(), dumpString.c_str());
#else
p.visualize(redirect.get(), nullptr);
#endif
return true;
});
} else {
printf("expected output path to end with one of: .glsl, .html, .metal, .hlsl, .spirv, "
".asm.frag, .skvm, .stage, .asm.vert, .dehydrated.sksl (got '%s')\n",
outputPath.c_str());
return ResultCode::kConfigurationError;
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
}
return ResultCode::kSuccess;
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
}
/**
* Processes multiple inputs in a single invocation of skslc.
*/
ResultCode processWorklist(const char* worklistPath) {
std::string inputPath(worklistPath);
if (!skstd::ends_with(inputPath, ".worklist")) {
printf("expected .worklist file, found: %s\n\n", worklistPath);
show_usage();
return ResultCode::kConfigurationError;
}
// The worklist contains one line per argument to pass to skslc. When a blank line is reached,
// those arguments will be passed to `processCommand`.
auto resultCode = ResultCode::kSuccess;
std::vector<std::string> args = {"skslc"};
std::ifstream in(worklistPath);
for (std::string line; std::getline(in, line); ) {
if (in.rdstate()) {
printf("error reading '%s'\n", worklistPath);
return ResultCode::kInputError;
}
if (!line.empty()) {
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
// We found an argument. Remember it.
args.push_back(std::move(line));
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
} else {
// We found a blank line. If we have any arguments stored up, process them as a command.
if (!args.empty()) {
ResultCode outcome = processCommand(args);
resultCode = std::max(resultCode, outcome);
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
// Clear every argument except the first ("skslc").
args.resize(1);
}
}
}
// If the worklist ended with a list of arguments but no blank line, process those now.
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
if (args.size() > 1) {
ResultCode outcome = processCommand(args);
resultCode = std::max(resultCode, outcome);
Update skslc to compile multiple files during one invocation. skslc can now take a `.worklist` file as an input, containing multiple "command lines" to run in sequence. compile_sksl_tests.py now assembles a worklist file and runs skslc one time, rather than running skslc once per each target. This improves compile times on Windows significantly (where spawning skslc hundreds of times is much more expensive than on Linux/Mac). One subtle behavioral difference with .worklist files: if an error is encountered, it is written to the output file instead of to stdout. Previously, compile_sksl_tests was in charge of for capturing stdout and overwriting the compiler output with the error message, but this doesn't work when many files are being compiled (which errors are associated with which files?) This refactor exposed a minor latent bug--when encountering an error, skslc would previously exit() immediately without closing its FileOutputStream. This led to an assertion when exit() was replaced with normal returns. Since FileOutputStream is only used by skslc, and in every case the desired behavior is just to close the stream cleanly, FileOutputStream now closes the file in its destructor instead of asserting that we haven't done so. Change-Id: Ia55baff0c11fe466923bde2e0c944df9f2ccd092 Bug: skia:10919 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334099 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
2020-11-11 22:29:28 +00:00
}
// Return the "worst" status we encountered. For our purposes, compilation errors are the least
// serious, because they are expected to occur in unit tests. Other types of errors are not
// expected at all during a build.
return resultCode;
}
int main(int argc, const char** argv) {
if (argc == 2) {
// Worklists are the only two-argument case for skslc, and we don't intend to support
// nested worklists, so we can process them here.
return (int)processWorklist(argv[1]);
} else {
// Process non-worklist inputs.
std::vector<std::string> args;
for (int index=0; index<argc; ++index) {
args.push_back(argv[index]);
}
return (int)processCommand(args);
}
}