blob: 7703f7afdab7f6bfc2ca96d2bab40c073b7f2975 [file] [log] [blame]
Austin Engcc2516a2023-10-17 20:57:54 +00001// Copyright 2023 The Dawn & Tint Authors
dan sinclair889edb12023-04-24 16:17:56 +00002//
Austin Engcc2516a2023-10-17 20:57:54 +00003// Redistribution and use in source and binary forms, with or without
4// modification, are permitted provided that the following conditions are met:
dan sinclair889edb12023-04-24 16:17:56 +00005//
Austin Engcc2516a2023-10-17 20:57:54 +00006// 1. Redistributions of source code must retain the above copyright notice, this
7// list of conditions and the following disclaimer.
dan sinclair889edb12023-04-24 16:17:56 +00008//
Austin Engcc2516a2023-10-17 20:57:54 +00009// 2. Redistributions in binary form must reproduce the above copyright notice,
10// this list of conditions and the following disclaimer in the documentation
11// and/or other materials provided with the distribution.
12//
13// 3. Neither the name of the copyright holder nor the names of its
14// contributors may be used to endorse or promote products derived from
15// this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dan sinclair889edb12023-04-24 16:17:56 +000027
28#include <iostream>
29
Ben Claytonb1cd47d2023-08-14 19:44:15 +000030#include "src/tint/api/tint.h"
Ben Clayton926a6ff2023-08-10 20:35:18 +000031#include "src/tint/cmd/common/generate_external_texture_bindings.h"
32#include "src/tint/cmd/common/helper.h"
dan sinclair97c37272023-07-24 17:11:53 +000033#include "src/tint/lang/core/ir/module.h"
dan sinclair889edb12023-04-24 16:17:56 +000034
Ben Claytonb1cd47d2023-08-14 19:44:15 +000035#if TINT_BUILD_GLSL_WRITER
36#include "src/tint/lang/glsl/writer/writer.h"
37#endif // TINT_BUILD_GLSL_WRITER
38
39#if TINT_BUILD_HLSL_WRITER
Antonio Maiorano26a41b92024-02-05 21:36:47 +000040#include "src/tint/lang/hlsl/writer/helpers/generate_bindings.h"
Ben Claytonb1cd47d2023-08-14 19:44:15 +000041#include "src/tint/lang/hlsl/writer/writer.h"
42#endif // TINT_BUILD_HLSL_WRITER
43
44#if TINT_BUILD_MSL_WRITER
dan sinclair4c88c1e2023-11-15 00:32:34 +000045#include "src/tint/lang/msl/writer/helpers/generate_bindings.h"
Ben Claytonb1cd47d2023-08-14 19:44:15 +000046#include "src/tint/lang/msl/writer/writer.h"
47#endif // TINT_BUILD_MSL_WRITER
48
49#if TINT_BUILD_SPV_READER
50#include "src/tint/lang/spirv/reader/reader.h"
51#endif // TINT_BUILD_SPV_READER
52
53#if TINT_BUILD_SPV_WRITER
Ben Claytonff671992023-11-23 08:08:53 +000054#include "src/tint/lang/spirv/writer/helpers/ast_generate_bindings.h"
Ben Claytonb1cd47d2023-08-14 19:44:15 +000055#include "src/tint/lang/spirv/writer/writer.h"
56#endif // TINT_BUILD_SPV_WRITER
57
58#if TINT_BUILD_WGSL_READER
Ben Clayton80b987e2023-10-11 14:28:15 +000059#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
Ben Claytonb1cd47d2023-08-14 19:44:15 +000060#include "src/tint/lang/wgsl/reader/reader.h"
61#endif // TINT_BUILD_WGSL_READER
62
63#if TINT_BUILD_WGSL_WRITER
64#include "src/tint/lang/wgsl/helpers/flatten_bindings.h"
65#include "src/tint/lang/wgsl/writer/writer.h"
66#endif // TINT_BUILD_WGSL_WRITER
67
dan sinclair889edb12023-04-24 16:17:56 +000068namespace {
69
70enum class Format {
71 kUnknown,
72 kNone,
73 kSpirv,
74 kWgsl,
75 kMsl,
76 kHlsl,
77 kGlsl,
78};
79
80enum class Looper {
81 kLoad,
82 kIRGenerate,
83 kWriter,
84};
85
86struct Options {
87 bool show_help = false;
88
89 std::string input_filename;
90 Format format = Format::kUnknown;
91
92 Looper loop = Looper::kLoad;
93 uint32_t loop_count = 100;
94};
95
96const char kUsage[] = R"(Usage: tint-loopy [options] <input-file>
97
98 options:
99 --format <spirv|wgsl|msl|hlsl|none> -- Generation format. Default SPIR-V.
100 --loop <load,ir-gen,writer> -- Item to loop
101 --loop-count <num> -- Number of loops to run, default 100.
102)";
103
104Format parse_format(const std::string& fmt) {
105 (void)fmt;
106
107#if TINT_BUILD_SPV_WRITER
108 if (fmt == "spirv") {
109 return Format::kSpirv;
110 }
111#endif // TINT_BUILD_SPV_WRITER
112
113#if TINT_BUILD_WGSL_WRITER
114 if (fmt == "wgsl") {
115 return Format::kWgsl;
116 }
117#endif // TINT_BUILD_WGSL_WRITER
118
119#if TINT_BUILD_MSL_WRITER
120 if (fmt == "msl") {
121 return Format::kMsl;
122 }
123#endif // TINT_BUILD_MSL_WRITER
124
125#if TINT_BUILD_HLSL_WRITER
126 if (fmt == "hlsl") {
127 return Format::kHlsl;
128 }
129#endif // TINT_BUILD_HLSL_WRITER
130
131#if TINT_BUILD_GLSL_WRITER
132 if (fmt == "glsl") {
133 return Format::kGlsl;
134 }
135#endif // TINT_BUILD_GLSL_WRITER
136
137 if (fmt == "none") {
138 return Format::kNone;
139 }
140
141 return Format::kUnknown;
142}
143
144bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
145 for (size_t i = 1; i < args.size(); ++i) {
146 const std::string& arg = args[i];
147 if (arg == "--format") {
148 ++i;
149 if (i >= args.size()) {
150 std::cerr << "Missing value for --format argument." << std::endl;
151 return false;
152 }
153 opts->format = parse_format(args[i]);
154
155 if (opts->format == Format::kUnknown) {
156 std::cerr << "Unknown output format: " << args[i] << std::endl;
157 return false;
158 }
159 } else if (arg == "-h" || arg == "--help") {
160 opts->show_help = true;
161 } else if (arg == "--loop") {
162 ++i;
163 if (i >= args.size()) {
164 std::cerr << "Missing value for --loop argument." << std::endl;
165 return false;
166 }
167 if (args[i] == "load") {
168 opts->loop = Looper::kLoad;
169 } else if (args[i] == "ir-gen") {
170 opts->loop = Looper::kIRGenerate;
171 } else if (args[i] == "writer") {
172 opts->loop = Looper::kWriter;
173 } else {
174 std::cerr << "Invalid loop value" << std::endl;
175 return false;
176 }
177 } else if (arg == "--loop-count") {
178 ++i;
179 if (i >= args.size()) {
180 std::cerr << "Missing value for --loop-count argument." << std::endl;
181 return false;
182 }
183 int32_t val = atoi(args[i].c_str());
184 if (val <= 0) {
185 std::cerr << "Loop count must be greater then 0" << std::endl;
186 return false;
187 }
188 opts->loop_count = static_cast<uint32_t>(val);
189 } else if (!arg.empty()) {
190 if (arg[0] == '-') {
191 std::cerr << "Unrecognized option: " << arg << std::endl;
192 return false;
193 }
194 if (!opts->input_filename.empty()) {
195 std::cerr << "More than one input file specified: '" << opts->input_filename
196 << "' and '" << arg << "'" << std::endl;
197 return false;
198 }
199 opts->input_filename = arg;
200 }
201 }
202 return true;
203}
204
205/// Generate SPIR-V code for a program.
206/// @param program the program to generate
207/// @returns true on success
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000208bool GenerateSpirv(const tint::Program& program) {
dan sinclair889edb12023-04-24 16:17:56 +0000209#if TINT_BUILD_SPV_WRITER
dan sinclair2dddb192023-07-26 20:31:48 +0000210 tint::spirv::writer::Options gen_options;
dan sinclair5294cb02023-10-04 00:22:01 +0000211 gen_options.bindings = tint::spirv::writer::GenerateBindings(program);
dan sinclair2dddb192023-07-26 20:31:48 +0000212 auto result = tint::spirv::writer::Generate(program, gen_options);
Ben Clayton89274f72024-01-03 10:53:42 +0000213 if (result != tint::Success) {
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000214 tint::cmd::PrintWGSL(std::cerr, program);
James Price85b138e2023-08-01 13:18:35 +0000215 std::cerr << "Failed to generate: " << result.Failure() << std::endl;
dan sinclair889edb12023-04-24 16:17:56 +0000216 return false;
217 }
218 return true;
219#else
220 (void)program;
221 std::cerr << "SPIR-V writer not enabled in tint build" << std::endl;
222 return false;
223#endif // TINT_BUILD_SPV_WRITER
224}
225
226/// Generate WGSL code for a program.
227/// @param program the program to generate
228/// @returns true on success
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000229bool GenerateWgsl(const tint::Program& program) {
dan sinclair889edb12023-04-24 16:17:56 +0000230#if TINT_BUILD_WGSL_WRITER
dan sinclairc1bf2252023-07-26 17:38:29 +0000231 tint::wgsl::writer::Options gen_options;
232 auto result = tint::wgsl::writer::Generate(program, gen_options);
Ben Clayton89274f72024-01-03 10:53:42 +0000233 if (result != tint::Success) {
James Priced3a56cb2023-08-02 19:46:00 +0000234 std::cerr << "Failed to generate: " << result.Failure() << std::endl;
dan sinclair889edb12023-04-24 16:17:56 +0000235 return false;
236 }
237
238 return true;
239#else
240 (void)program;
241 std::cerr << "WGSL writer not enabled in tint build" << std::endl;
242 return false;
243#endif // TINT_BUILD_WGSL_WRITER
244}
245
246/// Generate MSL code for a program.
247/// @param program the program to generate
248/// @returns true on success
Ben Clayton2550b492023-10-11 10:41:12 +0000249bool GenerateMsl([[maybe_unused]] const tint::Program& program) {
250#if !TINT_BUILD_MSL_WRITER
251 std::cerr << "MSL writer not enabled in tint build" << std::endl;
252 return false;
253#else
dan sinclair889edb12023-04-24 16:17:56 +0000254 // Remap resource numbers to a flat namespace.
255 // TODO(crbug.com/tint/1501): Do this via Options::BindingMap.
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000256 const tint::Program* input_program = &program;
Ben Clayton2550b492023-10-11 10:41:12 +0000257 auto flattened = tint::wgsl::FlattenBindings(program);
dan sinclair889edb12023-04-24 16:17:56 +0000258 if (flattened) {
259 input_program = &*flattened;
260 }
261
dan sinclaire7e4afc2023-07-26 02:28:30 +0000262 tint::msl::writer::Options gen_options;
dan sinclair4c88c1e2023-11-15 00:32:34 +0000263 gen_options.bindings = tint::msl::writer::GenerateBindings(program);
Ben Clayton87523662024-02-28 19:29:04 +0000264 gen_options.array_length_from_uniform.ubo_binding = 30;
Ben Clayton10252582023-07-25 20:53:25 +0000265 gen_options.array_length_from_uniform.bindpoint_to_size_index.emplace(tint::BindingPoint{0, 0},
266 0);
267 gen_options.array_length_from_uniform.bindpoint_to_size_index.emplace(tint::BindingPoint{0, 1},
268 1);
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000269 auto result = tint::msl::writer::Generate(*input_program, gen_options);
Ben Clayton89274f72024-01-03 10:53:42 +0000270 if (result != tint::Success) {
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000271 tint::cmd::PrintWGSL(std::cerr, program);
James Price6e209ea2023-08-02 17:35:23 +0000272 std::cerr << "Failed to generate: " << result.Failure() << std::endl;
dan sinclair889edb12023-04-24 16:17:56 +0000273 return false;
274 }
275
276 return true;
Ben Clayton2550b492023-10-11 10:41:12 +0000277#endif
dan sinclair889edb12023-04-24 16:17:56 +0000278}
279
280/// Generate HLSL code for a program.
281/// @param program the program to generate
282/// @returns true on success
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000283bool GenerateHlsl(const tint::Program& program) {
dan sinclair889edb12023-04-24 16:17:56 +0000284#if TINT_BUILD_HLSL_WRITER
dan sinclair0bfeaf92023-07-26 17:39:51 +0000285 tint::hlsl::writer::Options gen_options;
Antonio Maiorano26a41b92024-02-05 21:36:47 +0000286 gen_options.bindings = tint::hlsl::writer::GenerateBindings(program);
dan sinclair0bfeaf92023-07-26 17:39:51 +0000287 auto result = tint::hlsl::writer::Generate(program, gen_options);
Ben Clayton89274f72024-01-03 10:53:42 +0000288 if (result != tint::Success) {
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000289 tint::cmd::PrintWGSL(std::cerr, program);
James Priceec4dbe72023-08-02 18:14:29 +0000290 std::cerr << "Failed to generate: " << result.Failure() << std::endl;
dan sinclair889edb12023-04-24 16:17:56 +0000291 return false;
292 }
293
294 return true;
295#else
296 (void)program;
297 std::cerr << "HLSL writer not enabled in tint build" << std::endl;
298 return false;
299#endif // TINT_BUILD_HLSL_WRITER
300}
301
302/// Generate GLSL code for a program.
303/// @param program the program to generate
304/// @returns true on success
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000305bool GenerateGlsl(const tint::Program& program) {
dan sinclair889edb12023-04-24 16:17:56 +0000306#if TINT_BUILD_GLSL_WRITER
dan sinclair0f989022023-07-26 19:21:12 +0000307 tint::glsl::writer::Options gen_options;
dan sinclair889edb12023-04-24 16:17:56 +0000308 gen_options.external_texture_options.bindings_map =
309 tint::cmd::GenerateExternalTextureBindings(program);
dan sinclair0f989022023-07-26 19:21:12 +0000310 auto result = tint::glsl::writer::Generate(program, gen_options, "");
Ben Clayton89274f72024-01-03 10:53:42 +0000311 if (result == tint::Success) {
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000312 tint::cmd::PrintWGSL(std::cerr, program);
James Priceaf4dde72023-08-02 18:20:29 +0000313 std::cerr << "Failed to generate: " << result.Failure() << std::endl;
dan sinclair889edb12023-04-24 16:17:56 +0000314 return false;
315 }
316
317 return true;
318
319#else
320 (void)program;
321 std::cerr << "GLSL writer not enabled in tint build" << std::endl;
322 return false;
323#endif // TINT_BUILD_GLSL_WRITER
324}
325
326} // namespace
327
328int main(int argc, const char** argv) {
329 std::vector<std::string> args(argv, argv + argc);
330 Options options;
331
James Priced3a56cb2023-08-02 19:46:00 +0000332 tint::Initialize();
dan sinclair889edb12023-04-24 16:17:56 +0000333 tint::SetInternalCompilerErrorReporter(&tint::cmd::TintInternalCompilerErrorReporter);
334
dan sinclair889edb12023-04-24 16:17:56 +0000335 if (!ParseArgs(args, &options)) {
336 std::cerr << "Failed to parse arguments." << std::endl;
337 return 1;
338 }
339
340 if (options.show_help) {
341 std::cout << kUsage << std::endl;
342 return 0;
343 }
344
345 // Implement output format defaults.
346 if (options.format == Format::kUnknown) {
347 options.format = Format::kSpirv;
348 }
349
dan sinclair889edb12023-04-24 16:17:56 +0000350 std::unique_ptr<tint::Program> program;
351 std::unique_ptr<tint::Source::File> source_file;
352
353 if (options.loop == Looper::kLoad) {
354 if (options.input_filename.size() > 5 &&
355 options.input_filename.substr(options.input_filename.size() - 5) == ".wgsl") {
356#if TINT_BUILD_WGSL_READER
357 std::vector<uint8_t> data;
358 if (!tint::cmd::ReadFile<uint8_t>(options.input_filename, &data)) {
359 exit(1);
360 }
361 source_file = std::make_unique<tint::Source::File>(
362 options.input_filename, std::string(data.begin(), data.end()));
363
364 uint32_t loop_count = options.loop_count;
365 for (uint32_t i = 0; i < loop_count; ++i) {
366 program =
dan sinclair61190452023-07-26 20:47:54 +0000367 std::make_unique<tint::Program>(tint::wgsl::reader::Parse(source_file.get()));
dan sinclair889edb12023-04-24 16:17:56 +0000368 }
369#else
370 std::cerr << "Tint not built with the WGSL reader enabled" << std::endl;
371 exit(1);
372#endif // TINT_BUILD_WGSL_READER
373 } else {
374#if TINT_BUILD_SPV_READER
375 std::vector<uint32_t> data;
376 if (!tint::cmd::ReadFile<uint32_t>(options.input_filename, &data)) {
377 exit(1);
378 }
379
380 uint32_t loop_count = options.loop_count;
381 for (uint32_t i = 0; i < loop_count; ++i) {
Ben Clayton4ead3912023-08-11 18:43:05 +0000382 program = std::make_unique<tint::Program>(tint::spirv::reader::Read(data, {}));
dan sinclair889edb12023-04-24 16:17:56 +0000383 }
384#else
385 std::cerr << "Tint not built with the SPIR-V reader enabled" << std::endl;
386 exit(1);
387#endif // TINT_BUILD_SPV_READER
388 }
389 }
390
391 // Load the program that will actually be used
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000392 tint::cmd::LoadProgramOptions opts;
393 opts.filename = options.input_filename;
dan sinclair889edb12023-04-24 16:17:56 +0000394
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000395 auto info = tint::cmd::LoadProgramInfo(opts);
Ben Clayton80b987e2023-10-11 14:28:15 +0000396#if TINT_BUILD_WGSL_READER
dan sinclair889edb12023-04-24 16:17:56 +0000397 {
398 uint32_t loop_count = 1;
399 if (options.loop == Looper::kIRGenerate) {
400 loop_count = options.loop_count;
401 }
402 for (uint32_t i = 0; i < loop_count; ++i) {
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000403 auto result = tint::wgsl::reader::ProgramToIR(info.program);
Ben Clayton89274f72024-01-03 10:53:42 +0000404 if (result != tint::Success) {
dan sinclair889edb12023-04-24 16:17:56 +0000405 std::cerr << "Failed to build IR from program: " << result.Failure() << std::endl;
406 }
407 }
408 }
Ben Clayton80b987e2023-10-11 14:28:15 +0000409#endif // TINT_BUILD_WGSL_READER
dan sinclair889edb12023-04-24 16:17:56 +0000410
411 bool success = false;
412 {
413 uint32_t loop_count = 1;
414 if (options.loop == Looper::kWriter) {
415 loop_count = options.loop_count;
416 }
417
418 switch (options.format) {
419 case Format::kSpirv:
420 for (uint32_t i = 0; i < loop_count; ++i) {
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000421 success = GenerateSpirv(info.program);
dan sinclair889edb12023-04-24 16:17:56 +0000422 }
423 break;
424 case Format::kWgsl:
425 for (uint32_t i = 0; i < loop_count; ++i) {
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000426 success = GenerateWgsl(info.program);
dan sinclair889edb12023-04-24 16:17:56 +0000427 }
428 break;
429 case Format::kMsl:
430 for (uint32_t i = 0; i < loop_count; ++i) {
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000431 success = GenerateMsl(info.program);
dan sinclair889edb12023-04-24 16:17:56 +0000432 }
433 break;
434 case Format::kHlsl:
435 for (uint32_t i = 0; i < loop_count; ++i) {
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000436 success = GenerateHlsl(info.program);
dan sinclair889edb12023-04-24 16:17:56 +0000437 }
438 break;
439 case Format::kGlsl:
440 for (uint32_t i = 0; i < loop_count; ++i) {
Ben Clayton5ed5cc42023-09-22 10:31:04 +0000441 success = GenerateGlsl(info.program);
dan sinclair889edb12023-04-24 16:17:56 +0000442 }
443 break;
444 case Format::kNone:
445 break;
446 default:
447 std::cerr << "Unknown output format specified" << std::endl;
448 return 1;
449 }
450 }
Ben Clayton89274f72024-01-03 10:53:42 +0000451 if (success) {
dan sinclair889edb12023-04-24 16:17:56 +0000452 return 1;
453 }
454
455 return 0;
456}