1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include <fstream>
9 #include "SkSLCompiler.h"
10 #include "SkSLFileOutputStream.h"
11 
12 // Given the path to a file (e.g. src/gpu/effects/GrFooFragmentProcessor.fp) and the expected
13 // filename prefix and suffix (e.g. "Gr" and ".fp"), returns the "base name" of the
14 // file (in this case, 'FooFragmentProcessor'). If no match, returns the empty string.
15 static SkSL::String base_name(const char* fpPath, const char* prefix, const char* suffix) {
16     SkSL::String result;
17     const char* end = fpPath + strlen(fpPath);
18     const char* fileName = end;
19     // back up until we find a slash
20     while (fileName != fpPath && '/' != *(fileName - 1) && '\\' != *(fileName - 1)) {
21         --fileName;
22     }
23     if (!strncmp(fileName, prefix, strlen(prefix)) &&
24         !strncmp(end - strlen(suffix), suffix, strlen(suffix))) {
25         result.append(fileName + strlen(prefix), end - fileName - strlen(prefix) - strlen(suffix));
26     }
27     return result;
28 }
29 
30 /**
31  * Very simple standalone executable to facilitate testing.
32  */
33 int main(int argc, const char** argv) {
34     if (argc != 3) {
35         printf("usage: skslc <input> <output>\n");
36         exit(1);
37     }
38     SkSL::Program::Kind kind;
39     SkSL::String input(argv[1]);
40     if (input.endsWith(".vert")) {
41         kind = SkSL::Program::kVertex_Kind;
42     } else if (input.endsWith(".frag")) {
43         kind = SkSL::Program::kFragment_Kind;
44     } else if (input.endsWith(".geom")) {
45         kind = SkSL::Program::kGeometry_Kind;
46     } else if (input.endsWith(".fp")) {
47         kind = SkSL::Program::kFragmentProcessor_Kind;
48     } else {
49         printf("input filename must end in '.vert', '.frag', '.geom', or '.fp'\n");
50         exit(1);
51     }
52 
53     std::ifstream in(argv[1]);
54     std::string stdText((std::istreambuf_iterator<char>(in)),
55                         std::istreambuf_iterator<char>());
56     SkSL::String text(stdText.c_str());
57     if (in.rdstate()) {
58         printf("error reading '%s'\n", argv[1]);
59         exit(2);
60     }
61     SkSL::Program::Settings settings;
62     settings.fArgs.insert(std::make_pair("gpImplementsDistanceVector", 1));
63     SkSL::String name(argv[2]);
64     if (name.endsWith(".spirv")) {
65         SkSL::FileOutputStream out(argv[2]);
66         SkSL::Compiler compiler;
67         if (!out.isValid()) {
68             printf("error writing '%s'\n", argv[2]);
69             exit(4);
70         }
71         std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
72         if (!program || !compiler.toSPIRV(*program, out)) {
73             printf("%s", compiler.errorText().c_str());
74             exit(3);
75         }
76         if (!out.close()) {
77             printf("error writing '%s'\n", argv[2]);
78             exit(4);
79         }
80     } else if (name.endsWith(".glsl")) {
81         SkSL::FileOutputStream out(argv[2]);
82         SkSL::Compiler compiler;
83         if (!out.isValid()) {
84             printf("error writing '%s'\n", argv[2]);
85             exit(4);
86         }
87         std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
88         if (!program || !compiler.toGLSL(*program, out)) {
89             printf("%s", compiler.errorText().c_str());
90             exit(3);
91         }
92         if (!out.close()) {
93             printf("error writing '%s'\n", argv[2]);
94             exit(4);
95         }
96     } else if (name.endsWith(".metal")) {
97         SkSL::FileOutputStream out(argv[2]);
98         SkSL::Compiler compiler;
99         if (!out.isValid()) {
100             printf("error writing '%s'\n", argv[2]);
101             exit(4);
102         }
103         std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
104         if (!program || !compiler.toMetal(*program, out)) {
105             printf("%s", compiler.errorText().c_str());
106             exit(3);
107         }
108         if (!out.close()) {
109             printf("error writing '%s'\n", argv[2]);
110             exit(4);
111         }
112     } else if (name.endsWith(".h")) {
113         SkSL::FileOutputStream out(argv[2]);
114         SkSL::Compiler compiler(SkSL::Compiler::kPermitInvalidStaticTests_Flag);
115         if (!out.isValid()) {
116             printf("error writing '%s'\n", argv[2]);
117             exit(4);
118         }
119         settings.fReplaceSettings = false;
120         std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
121         if (!program || !compiler.toH(*program, base_name(argv[1], "Gr", ".fp"), out)) {
122             printf("%s", compiler.errorText().c_str());
123             exit(3);
124         }
125         if (!out.close()) {
126             printf("error writing '%s'\n", argv[2]);
127             exit(4);
128         }
129     } else if (name.endsWith(".cpp")) {
130         SkSL::FileOutputStream out(argv[2]);
131         SkSL::Compiler compiler(SkSL::Compiler::kPermitInvalidStaticTests_Flag);
132         if (!out.isValid()) {
133             printf("error writing '%s'\n", argv[2]);
134             exit(4);
135         }
136         settings.fReplaceSettings = false;
137         std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
138         if (!program || !compiler.toCPP(*program, base_name(argv[1], "Gr", ".fp"), out)) {
139             printf("%s", compiler.errorText().c_str());
140             exit(3);
141         }
142         if (!out.close()) {
143             printf("error writing '%s'\n", argv[2]);
144             exit(4);
145         }
146     } else {
147         printf("expected output filename to end with '.spirv', '.glsl', '.cpp', '.h', or '.metal'");
148         exit(1);
149     }
150 }
151