8#define SK_OPTS_NS sksl_minify_standalone
29#include <forward_list>
51static std::string
base_name(
const std::string& path) {
52 size_t slashPos = path.find_last_of(
"/\\");
53 return path.substr(slashPos == std::string::npos ? 0 : slashPos + 1);
57 size_t dotPos = path.find_last_of(
'.');
58 return path.substr(0, dotPos);
65 printf(
"usage: sksl-minify <output> <input> [--frag|--vert|--compute|--shader|"
66 "--colorfilter|--blender|--meshfrag|--meshvert] [dependencies...]\n");
74 return std::isalnum(c) || c ==
'$' || c ==
'_';
78 return c ==
'+' || c ==
'-';
83 std::forward_list<std::unique_ptr<const SkSL::Module>> modules;
91 if (paths.
size() == 1) {
93 std::string defaultRuntimeShaderPaths[] = {
102 paths = paths.
first(1);
111 for (
auto modulePath = paths.
rbegin(); modulePath != paths.
rend(); ++modulePath) {
112 std::ifstream in(*modulePath);
113 std::string moduleSource{std::istreambuf_iterator<char>(in),
114 std::istreambuf_iterator<char>()};
116 printf(
"error reading '%s'\n", modulePath->c_str());
121 : modules.front().get();
122 std::unique_ptr<SkSL::Module> m =
compiler.compileModule(kind,
124 std::move(moduleSource),
136 modules.push_front(std::move(m));
143 std::string_view
text,
151 std::string_view lastTokenText =
" ";
154 token = lexer.
next();
155 if (token.
fKind == TokenKind::TK_END_OF_FILE) {
158 if (token.
fKind == TokenKind::TK_LINE_COMMENT ||
159 token.
fKind == TokenKind::TK_BLOCK_COMMENT ||
160 token.
fKind == TokenKind::TK_WHITESPACE) {
164 if (token.
fKind == TokenKind::TK_INVALID) {
165 printf(
"%.*s: unable to parse '%.*s' at offset %d\n",
166 (
int)inputPath.size(), inputPath.data(),
167 (
int)thisTokenText.size(), thisTokenText.data(),
171 if (thisTokenText.empty()) {
174 if (token.
fKind == TokenKind::TK_FLOAT_LITERAL) {
177 while (thisTokenText.back() ==
'0' && thisTokenText.size() >= 3) {
178 thisTokenText.remove_suffix(1);
183 thisTokenText.remove_prefix(1);
189 out.writeText(
"\"\n\"");
194 bool adjacentIdentifiers =
199 bool adjacentPlusOrMinus =
203 if (adjacentIdentifiers || adjacentPlusOrMinus) {
207 out.write(thisTokenText.data(), thisTokenText.size());
208 lineWidth += thisTokenText.size();
209 lastTokenText = thisTokenText;
216 size_t startingCount =
args->size();
217 auto iter = std::remove_if(
args->begin(),
args->end(),
218 [&](
const std::string&
a) { return a == flagName; });
219 *
args =
args->subspan(0, std::distance(
args->begin(), iter));
220 return args->size() < startingCount;
225 return std::count(
flags.begin(),
flags.end(),
true) > 1;
245 isBlender, isMeshFrag, isMeshVert})) {
253 }
else if (isCompute) {
255 }
else if (isColorFilter) {
257 }
else if (isBlender) {
259 }
else if (isMeshFrag) {
261 }
else if (isMeshVert) {
269 if (
args.size() < 2) {
273 const std::string& outputPath =
args[0];
277 std::forward_list<std::unique_ptr<const SkSL::Module>> modules =
279 if (modules.empty()) {
286 if (!out.isValid()) {
287 printf(
"error writing '%s'\n", outputPath.c_str());
293 out.printf(
"static constexpr char SKSL_MINIFIED_%s[] =\n\"", baseName.c_str());
298 for (
const std::unique_ptr<SkSL::ProgramElement>& element :
module->fElements) {
299 if ((isMeshFrag || isMeshVert) && element->is<SkSL::StructDefinition>()) {
300 std::string_view name = element->as<SkSL::StructDefinition>().type().name();
301 if (
name ==
"Attributes" ||
name ==
"Varyings") {
307 text += element->description();
316 out.writeText(
"\";");
321 printf(
"error writing '%s'\n", outputPath.c_str());
328int main(
int argc,
const char** argv) {
335 std::vector<std::string>
args;
336 for (
int index=0; index<argc; ++index) {
ResultCode ProcessWorklist(const char *worklistPath, const std::function< ResultCode(SkSpan< std::string > args)> &processCommandFn)
std::string SkGetExecutablePath()
static std::string base_name(const std::string &path)
static ResultCode process_command(SkSpan< std::string > args)
static bool find_boolean_flag(SkSpan< std::string > *args, std::string_view flagName)
void SkDebugf(const char format[],...)
static std::string_view stringize(const SkSL::Token &token, std::string_view text)
static std::forward_list< std::unique_ptr< const SkSL::Module > > compile_module_list(SkSpan< const std::string > paths, SkSL::ProgramKind kind)
static bool maybe_identifier(char c)
static std::string remove_extension(const std::string &path)
static bool generate_minified_text(std::string_view inputPath, std::string_view text, SkSL::FileOutputStream &out)
static SkSL::ProgramKind gProgramKind
static bool is_plus_or_minus(char c)
static bool has_overlapping_flags(SkSpan< const bool > flags)
static constexpr char SEPARATOR
static SkString Dirname(const char *fullPath)
void start(std::string_view text)
const Module * rootModule()
void addPublicTypeAliases(const SkSL::Module *module)
static ModuleLoader Get()
constexpr SkSpan< T > first(size_t prefixLen) const
constexpr T & front() const
constexpr SkSpan< T > subspan(size_t offset) const
constexpr auto rbegin() const
constexpr auto rend() const
constexpr size_t size() const
const char * c_str() const
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint32_t uint32_t * format
size_t raster_pipeline_highp_stride
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
constexpr bool starts_with(std::string_view str, std::string_view prefix)
constexpr bool contains(std::string_view str, std::string_view needle)
static bool IsRuntimeEffect(ProgramKind kind)