2020-03-02 20:47:43 +00:00
|
|
|
// Copyright 2020 The Tint Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2020-04-30 01:16:12 +00:00
|
|
|
#include <cstdio>
|
2020-03-02 20:47:43 +00:00
|
|
|
#include <fstream>
|
|
|
|
#include <iostream>
|
|
|
|
#include <memory>
|
2020-09-30 00:05:23 +00:00
|
|
|
#include <sstream>
|
2020-04-30 01:16:12 +00:00
|
|
|
#include <string>
|
2020-03-02 20:47:43 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2020-06-22 14:36:34 +00:00
|
|
|
#if TINT_BUILD_SPV_READER
|
|
|
|
#include "spirv-tools/libspirv.hpp"
|
|
|
|
#endif // TINT_BUILD_SPV_READER
|
|
|
|
|
2021-06-02 21:02:34 +00:00
|
|
|
#include "src/utils/io/command.h"
|
|
|
|
#include "src/val/val.h"
|
2020-11-03 16:26:09 +00:00
|
|
|
#include "tint/tint.h"
|
2020-11-03 13:15:19 +00:00
|
|
|
|
2020-03-02 20:47:43 +00:00
|
|
|
namespace {
|
|
|
|
|
2021-02-24 15:55:24 +00:00
|
|
|
[[noreturn]] void TintInternalCompilerErrorReporter(
|
|
|
|
const tint::diag::List& diagnostics) {
|
2021-02-17 20:13:34 +00:00
|
|
|
auto printer = tint::diag::Printer::create(stderr, true);
|
|
|
|
tint::diag::Formatter{}.format(diagnostics, printer.get());
|
2021-08-04 20:19:28 +00:00
|
|
|
tint::diag::Style bold_red{tint::diag::Color::kRed, true};
|
|
|
|
constexpr const char* please_file_bug = R"(
|
|
|
|
********************************************************************
|
|
|
|
* The tint shader compiler has encountered an unexpected error. *
|
|
|
|
* *
|
|
|
|
* Please help us fix this issue by submitting a bug report at *
|
|
|
|
* crbug.com/tint with the source program that triggered the bug. *
|
|
|
|
********************************************************************
|
|
|
|
)";
|
|
|
|
printer->write(please_file_bug, bold_red);
|
2021-02-17 20:13:34 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2020-03-02 20:47:43 +00:00
|
|
|
enum class Format {
|
|
|
|
kNone = -1,
|
|
|
|
kSpirv,
|
|
|
|
kSpvAsm,
|
|
|
|
kWgsl,
|
2020-06-23 17:48:40 +00:00
|
|
|
kMsl,
|
2020-07-20 22:13:37 +00:00
|
|
|
kHlsl,
|
Implement GLSL writer backend.
This is a modified version of the HLSL writer.
Basic types, arrays, entry points, reserved keywords, uniforms,
builtin uniforms, structs, some builtin functions, zero initialization
are implemented. Textures, SSBOs and storage textures in particular are
unimplemented. All the unit tests "pass", but the output is not correct
in many cases.
triangle.wgsl outputs correct vertex and fragment shaders that pass
GLSL validation via glslang. compute_boids.wgsl outputs a valid but not
correct compute shader.
Change-Id: I96c7aaf60cf2d4237e45d732e5f51b345aea0552
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/57780
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
2021-10-06 18:55:10 +00:00
|
|
|
kGlsl,
|
2020-03-02 20:47:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Options {
|
|
|
|
bool show_help = false;
|
|
|
|
|
|
|
|
std::string input_filename;
|
2020-04-30 01:16:12 +00:00
|
|
|
std::string output_file = "-"; // Default to stdout
|
2020-03-02 20:47:43 +00:00
|
|
|
|
|
|
|
bool parse_only = false;
|
|
|
|
bool dump_ast = false;
|
2021-07-20 18:23:06 +00:00
|
|
|
bool disable_workgroup_init = false;
|
2021-06-02 21:02:34 +00:00
|
|
|
bool validate = false;
|
2021-01-05 22:45:50 +00:00
|
|
|
bool demangle = false;
|
2021-03-04 15:30:35 +00:00
|
|
|
bool dump_inspector_bindings = false;
|
2020-03-02 20:47:43 +00:00
|
|
|
|
2020-04-30 01:16:12 +00:00
|
|
|
Format format = Format::kNone;
|
2020-09-03 01:46:36 +00:00
|
|
|
|
|
|
|
bool emit_single_entry_point = false;
|
|
|
|
std::string ep_name;
|
2020-09-30 00:05:23 +00:00
|
|
|
|
|
|
|
std::vector<std::string> transforms;
|
2021-06-02 21:02:34 +00:00
|
|
|
|
2021-06-28 12:02:17 +00:00
|
|
|
bool use_fxc = false;
|
2021-06-02 21:02:34 +00:00
|
|
|
std::string dxc_path;
|
|
|
|
std::string xcrun_path;
|
2020-03-02 20:47:43 +00:00
|
|
|
};
|
|
|
|
|
2020-06-22 14:36:34 +00:00
|
|
|
const char kUsage[] = R"(Usage: tint [options] <input-file>
|
2020-03-02 20:47:43 +00:00
|
|
|
|
|
|
|
options:
|
2020-07-20 22:13:37 +00:00
|
|
|
--format <spirv|spvasm|wgsl|msl|hlsl> -- Output format.
|
2020-04-30 01:16:12 +00:00
|
|
|
If not provided, will be inferred from output
|
|
|
|
filename extension:
|
|
|
|
.spvasm -> spvasm
|
2020-07-20 22:13:37 +00:00
|
|
|
.spv -> spirv
|
|
|
|
.wgsl -> wgsl
|
|
|
|
.metal -> msl
|
|
|
|
.hlsl -> hlsl
|
2020-04-30 01:16:12 +00:00
|
|
|
If none matches, then default to SPIR-V assembly.
|
2021-04-28 15:33:03 +00:00
|
|
|
-ep <name> -- Output single entry point
|
2020-04-30 01:16:12 +00:00
|
|
|
--output-file <name> -- Output file name. Use "-" for standard output
|
|
|
|
-o <name> -- Output file name. Use "-" for standard output
|
2020-12-04 09:06:09 +00:00
|
|
|
--transform <name list> -- Runs transforms, name list is comma separated
|
2020-09-30 00:05:23 +00:00
|
|
|
Available transforms:
|
2020-12-08 21:07:24 +00:00
|
|
|
first_index_offset
|
2021-07-02 21:15:44 +00:00
|
|
|
fold_trivial_single_use_lets
|
2021-04-16 08:28:54 +00:00
|
|
|
renamer
|
2021-06-30 13:23:36 +00:00
|
|
|
robustness
|
2020-03-02 20:47:43 +00:00
|
|
|
--parse-only -- Stop after parsing the input
|
|
|
|
--dump-ast -- Dump the generated AST to stdout
|
2021-07-20 18:23:06 +00:00
|
|
|
--disable-workgroup-init -- Disable workgroup memory zero initialization.
|
2021-01-05 22:45:50 +00:00
|
|
|
--demangle -- Preserve original source names. Demangle them.
|
|
|
|
Affects AST dumping, and text-based output languages.
|
2021-03-04 15:30:35 +00:00
|
|
|
--dump-inspector-bindings -- Dump reflection data about bindins to stdout.
|
2021-06-02 21:02:34 +00:00
|
|
|
-h -- This help text
|
2021-06-28 12:02:17 +00:00
|
|
|
--validate -- Validates the generated shader
|
|
|
|
--fxc -- Ask to validate HLSL output using FXC instead of DXC.
|
|
|
|
When specified, automatically enables --validate
|
2021-06-02 21:02:34 +00:00
|
|
|
--dxc -- Path to DXC executable, used to validate HLSL output.
|
|
|
|
When specified, automatically enables --validate
|
|
|
|
--xcrun -- Path to xcrun executable, used to validate MSL output.
|
|
|
|
When specified, automatically enables --validate)";
|
2020-03-02 20:47:43 +00:00
|
|
|
|
|
|
|
Format parse_format(const std::string& fmt) {
|
2021-09-03 14:16:56 +00:00
|
|
|
(void)fmt;
|
2020-03-18 14:08:48 +00:00
|
|
|
|
|
|
|
#if TINT_BUILD_SPV_WRITER
|
2020-03-02 20:47:43 +00:00
|
|
|
if (fmt == "spirv")
|
|
|
|
return Format::kSpirv;
|
|
|
|
if (fmt == "spvasm")
|
|
|
|
return Format::kSpvAsm;
|
2020-03-18 14:08:48 +00:00
|
|
|
#endif // TINT_BUILD_SPV_WRITER
|
|
|
|
|
|
|
|
#if TINT_BUILD_WGSL_WRITER
|
2020-03-02 20:47:43 +00:00
|
|
|
if (fmt == "wgsl")
|
|
|
|
return Format::kWgsl;
|
2020-03-18 14:08:48 +00:00
|
|
|
#endif // TINT_BUILD_WGSL_WRITER
|
2020-03-02 20:47:43 +00:00
|
|
|
|
2020-06-23 17:48:40 +00:00
|
|
|
#if TINT_BUILD_MSL_WRITER
|
|
|
|
if (fmt == "msl")
|
|
|
|
return Format::kMsl;
|
|
|
|
#endif // TINT_BUILD_MSL_WRITER
|
|
|
|
|
2020-07-20 22:13:37 +00:00
|
|
|
#if TINT_BUILD_HLSL_WRITER
|
|
|
|
if (fmt == "hlsl")
|
|
|
|
return Format::kHlsl;
|
|
|
|
#endif // TINT_BUILD_HLSL_WRITER
|
|
|
|
|
Implement GLSL writer backend.
This is a modified version of the HLSL writer.
Basic types, arrays, entry points, reserved keywords, uniforms,
builtin uniforms, structs, some builtin functions, zero initialization
are implemented. Textures, SSBOs and storage textures in particular are
unimplemented. All the unit tests "pass", but the output is not correct
in many cases.
triangle.wgsl outputs correct vertex and fragment shaders that pass
GLSL validation via glslang. compute_boids.wgsl outputs a valid but not
correct compute shader.
Change-Id: I96c7aaf60cf2d4237e45d732e5f51b345aea0552
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/57780
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
2021-10-06 18:55:10 +00:00
|
|
|
#if TINT_BUILD_GLSL_WRITER
|
|
|
|
if (fmt == "glsl")
|
|
|
|
return Format::kGlsl;
|
|
|
|
#endif // TINT_BUILD_GLSL_WRITER
|
|
|
|
|
2020-03-02 20:47:43 +00:00
|
|
|
return Format::kNone;
|
|
|
|
}
|
|
|
|
|
2021-09-03 14:16:56 +00:00
|
|
|
#if TINT_BUILD_SPV_WRITER || TINT_BUILD_WGSL_WRITER || \
|
|
|
|
TINT_BUILD_MSL_WRITER || TINT_BUILD_HLSL_WRITER
|
2020-04-30 01:16:12 +00:00
|
|
|
/// @param input input string
|
|
|
|
/// @param suffix potential suffix string
|
|
|
|
/// @returns true if input ends with the given suffix.
|
|
|
|
bool ends_with(const std::string& input, const std::string& suffix) {
|
|
|
|
const auto input_len = input.size();
|
|
|
|
const auto suffix_len = suffix.size();
|
|
|
|
// Avoid integer overflow.
|
2020-05-01 16:17:03 +00:00
|
|
|
return (input_len >= suffix_len) &&
|
|
|
|
(input_len - suffix_len == input.rfind(suffix));
|
2020-04-30 01:16:12 +00:00
|
|
|
}
|
2021-09-03 14:16:56 +00:00
|
|
|
#endif
|
2020-04-30 01:16:12 +00:00
|
|
|
|
|
|
|
/// @param filename the filename to inspect
|
|
|
|
/// @returns the inferred format for the filename suffix
|
|
|
|
Format infer_format(const std::string& filename) {
|
2021-09-03 14:16:56 +00:00
|
|
|
(void)filename;
|
2020-06-23 17:48:40 +00:00
|
|
|
|
|
|
|
#if TINT_BUILD_SPV_WRITER
|
2020-04-30 01:16:12 +00:00
|
|
|
if (ends_with(filename, ".spv")) {
|
|
|
|
return Format::kSpirv;
|
|
|
|
}
|
|
|
|
if (ends_with(filename, ".spvasm")) {
|
|
|
|
return Format::kSpvAsm;
|
|
|
|
}
|
2020-06-23 17:48:40 +00:00
|
|
|
#endif // TINT_BUILD_SPV_WRITER
|
|
|
|
|
|
|
|
#if TINT_BUILD_WGSL_WRITER
|
2020-04-30 01:16:12 +00:00
|
|
|
if (ends_with(filename, ".wgsl")) {
|
|
|
|
return Format::kWgsl;
|
|
|
|
}
|
2020-06-23 17:48:40 +00:00
|
|
|
#endif // TINT_BUILD_WGSL_WRITER
|
|
|
|
|
|
|
|
#if TINT_BUILD_MSL_WRITER
|
|
|
|
if (ends_with(filename, ".metal")) {
|
|
|
|
return Format::kMsl;
|
|
|
|
}
|
2021-02-04 16:17:49 +00:00
|
|
|
#endif // TINT_BUILD_MSL_WRITER
|
|
|
|
|
|
|
|
#if TINT_BUILD_HLSL_WRITER
|
|
|
|
if (ends_with(filename, ".hlsl")) {
|
|
|
|
return Format::kHlsl;
|
|
|
|
}
|
|
|
|
#endif // TINT_BUILD_HLSL_WRITER
|
2020-06-23 17:48:40 +00:00
|
|
|
|
2020-04-30 01:16:12 +00:00
|
|
|
return Format::kNone;
|
|
|
|
}
|
|
|
|
|
2020-09-30 00:05:23 +00:00
|
|
|
std::vector<std::string> split_transform_names(std::string list) {
|
|
|
|
std::vector<std::string> res;
|
|
|
|
|
|
|
|
std::stringstream str(list);
|
|
|
|
while (str.good()) {
|
|
|
|
std::string substr;
|
|
|
|
getline(str, substr, ',');
|
|
|
|
res.push_back(substr);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2021-03-04 15:30:35 +00:00
|
|
|
std::string TextureDimensionToString(
|
|
|
|
tint::inspector::ResourceBinding::TextureDimension dim) {
|
|
|
|
switch (dim) {
|
|
|
|
case tint::inspector::ResourceBinding::TextureDimension::kNone:
|
|
|
|
return "None";
|
|
|
|
case tint::inspector::ResourceBinding::TextureDimension::k1d:
|
|
|
|
return "1d";
|
|
|
|
case tint::inspector::ResourceBinding::TextureDimension::k2d:
|
|
|
|
return "2d";
|
|
|
|
case tint::inspector::ResourceBinding::TextureDimension::k2dArray:
|
|
|
|
return "2dArray";
|
|
|
|
case tint::inspector::ResourceBinding::TextureDimension::k3d:
|
|
|
|
return "3d";
|
|
|
|
case tint::inspector::ResourceBinding::TextureDimension::kCube:
|
|
|
|
return "Cube";
|
|
|
|
case tint::inspector::ResourceBinding::TextureDimension::kCubeArray:
|
|
|
|
return "CubeArray";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string SampledKindToString(
|
|
|
|
tint::inspector::ResourceBinding::SampledKind kind) {
|
|
|
|
switch (kind) {
|
|
|
|
case tint::inspector::ResourceBinding::SampledKind::kFloat:
|
|
|
|
return "Float";
|
|
|
|
case tint::inspector::ResourceBinding::SampledKind::kUInt:
|
|
|
|
return "UInt";
|
|
|
|
case tint::inspector::ResourceBinding::SampledKind::kSInt:
|
|
|
|
return "SInt";
|
|
|
|
case tint::inspector::ResourceBinding::SampledKind::kUnknown:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string ImageFormatToString(
|
|
|
|
tint::inspector::ResourceBinding::ImageFormat format) {
|
|
|
|
switch (format) {
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kR8Unorm:
|
|
|
|
return "R8Unorm";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kR8Snorm:
|
|
|
|
return "R8Snorm";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kR8Uint:
|
|
|
|
return "R8Uint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kR8Sint:
|
|
|
|
return "R8Sint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kR16Uint:
|
|
|
|
return "R16Uint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kR16Sint:
|
|
|
|
return "R16Sint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kR16Float:
|
|
|
|
return "R16Float";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRg8Unorm:
|
|
|
|
return "Rg8Unorm";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRg8Snorm:
|
|
|
|
return "Rg8Snorm";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRg8Uint:
|
|
|
|
return "Rg8Uint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRg8Sint:
|
|
|
|
return "Rg8Sint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kR32Uint:
|
|
|
|
return "R32Uint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kR32Sint:
|
|
|
|
return "R32Sint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kR32Float:
|
|
|
|
return "R32Float";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRg16Uint:
|
|
|
|
return "Rg16Uint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRg16Sint:
|
|
|
|
return "Rg16Sint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRg16Float:
|
|
|
|
return "Rg16Float";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgba8Unorm:
|
|
|
|
return "Rgba8Unorm";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgba8UnormSrgb:
|
|
|
|
return "Rgba8UnormSrgb";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgba8Snorm:
|
|
|
|
return "Rgba8Snorm";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgba8Uint:
|
|
|
|
return "Rgba8Uint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgba8Sint:
|
|
|
|
return "Rgba8Sint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kBgra8Unorm:
|
|
|
|
return "Bgra8Unorm";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kBgra8UnormSrgb:
|
|
|
|
return "Bgra8UnormSrgb";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgb10A2Unorm:
|
|
|
|
return "Rgb10A2Unorm";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRg11B10Float:
|
|
|
|
return "Rg11B10Float";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRg32Uint:
|
|
|
|
return "Rg32Uint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRg32Sint:
|
|
|
|
return "Rg32Sint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRg32Float:
|
|
|
|
return "Rg32Float";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgba16Uint:
|
|
|
|
return "Rgba16Uint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgba16Sint:
|
|
|
|
return "Rgba16Sint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgba16Float:
|
|
|
|
return "Rgba16Float";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgba32Uint:
|
|
|
|
return "Rgba32Uint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgba32Sint:
|
|
|
|
return "Rgba32Sint";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kRgba32Float:
|
|
|
|
return "Rgba32Float";
|
|
|
|
case tint::inspector::ResourceBinding::ImageFormat::kNone:
|
|
|
|
return "None";
|
|
|
|
}
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string ResourceTypeToString(
|
|
|
|
tint::inspector::ResourceBinding::ResourceType type) {
|
|
|
|
switch (type) {
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kUniformBuffer:
|
|
|
|
return "UniformBuffer";
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kStorageBuffer:
|
|
|
|
return "StorageBuffer";
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kReadOnlyStorageBuffer:
|
|
|
|
return "ReadOnlyStorageBuffer";
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kSampler:
|
|
|
|
return "Sampler";
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kComparisonSampler:
|
|
|
|
return "ComparisonSampler";
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kSampledTexture:
|
|
|
|
return "SampledTexture";
|
2021-03-22 21:26:17 +00:00
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kMultisampledTexture:
|
|
|
|
return "MultisampledTexture";
|
2021-03-04 15:30:35 +00:00
|
|
|
case tint::inspector::ResourceBinding::ResourceType::
|
|
|
|
kReadOnlyStorageTexture:
|
|
|
|
return "ReadOnlyStorageTexture";
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::
|
|
|
|
kWriteOnlyStorageTexture:
|
|
|
|
return "WriteOnlyStorageTexture";
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kDepthTexture:
|
|
|
|
return "DepthTexture";
|
2021-07-26 22:19:48 +00:00
|
|
|
case tint::inspector::ResourceBinding::ResourceType::
|
|
|
|
kDepthMultisampledTexture:
|
|
|
|
return "DepthMultisampledTexture";
|
2021-05-17 17:40:17 +00:00
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kExternalTexture:
|
|
|
|
return "ExternalTexture";
|
2021-03-04 15:30:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
|
2020-03-02 20:47:43 +00:00
|
|
|
bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
|
|
|
|
for (size_t i = 1; i < args.size(); ++i) {
|
|
|
|
const std::string& arg = args[i];
|
|
|
|
if (arg == "--format") {
|
|
|
|
++i;
|
|
|
|
if (i >= args.size()) {
|
|
|
|
std::cerr << "Missing value for --format argument." << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
opts->format = parse_format(args[i]);
|
|
|
|
|
|
|
|
if (opts->format == Format::kNone) {
|
|
|
|
std::cerr << "Unknown output format: " << args[i] << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
2020-09-03 01:46:36 +00:00
|
|
|
} else if (arg == "-ep") {
|
2021-04-28 15:33:03 +00:00
|
|
|
if (i + 1 >= args.size()) {
|
|
|
|
std::cerr << "Missing value for -ep" << std::endl;
|
2020-09-03 01:46:36 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
opts->ep_name = args[i];
|
|
|
|
opts->emit_single_entry_point = true;
|
|
|
|
|
2020-07-08 15:28:26 +00:00
|
|
|
} else if (arg == "-o" || arg == "--output-name") {
|
2020-03-02 20:47:43 +00:00
|
|
|
++i;
|
|
|
|
if (i >= args.size()) {
|
2020-04-30 01:16:12 +00:00
|
|
|
std::cerr << "Missing value for " << arg << std::endl;
|
2020-03-02 20:47:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-04-30 01:16:12 +00:00
|
|
|
opts->output_file = args[i];
|
2020-03-02 20:47:43 +00:00
|
|
|
|
|
|
|
} else if (arg == "-h" || arg == "--help") {
|
|
|
|
opts->show_help = true;
|
2020-09-30 00:05:23 +00:00
|
|
|
} else if (arg == "--transform") {
|
|
|
|
++i;
|
|
|
|
if (i >= args.size()) {
|
|
|
|
std::cerr << "Missing value for " << arg << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
opts->transforms = split_transform_names(args[i]);
|
2020-03-02 20:47:43 +00:00
|
|
|
} else if (arg == "--parse-only") {
|
|
|
|
opts->parse_only = true;
|
|
|
|
} else if (arg == "--dump-ast") {
|
|
|
|
opts->dump_ast = true;
|
2021-07-20 18:23:06 +00:00
|
|
|
} else if (arg == "--disable-workgroup-init") {
|
|
|
|
opts->disable_workgroup_init = true;
|
2021-01-05 22:45:50 +00:00
|
|
|
} else if (arg == "--demangle") {
|
|
|
|
opts->demangle = true;
|
2021-03-04 15:30:35 +00:00
|
|
|
} else if (arg == "--dump-inspector-bindings") {
|
|
|
|
opts->dump_inspector_bindings = true;
|
2021-06-02 21:02:34 +00:00
|
|
|
} else if (arg == "--validate") {
|
|
|
|
opts->validate = true;
|
2021-06-28 12:02:17 +00:00
|
|
|
} else if (arg == "--fxc") {
|
|
|
|
opts->validate = true;
|
|
|
|
opts->use_fxc = true;
|
2021-06-02 21:02:34 +00:00
|
|
|
} else if (arg == "--dxc") {
|
|
|
|
++i;
|
|
|
|
if (i >= args.size()) {
|
|
|
|
std::cerr << "Missing value for " << arg << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
opts->dxc_path = args[i];
|
|
|
|
opts->validate = true;
|
|
|
|
} else if (arg == "--xcrun") {
|
|
|
|
++i;
|
|
|
|
if (i >= args.size()) {
|
|
|
|
std::cerr << "Missing value for " << arg << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
opts->xcrun_path = args[i];
|
|
|
|
opts->validate = true;
|
2020-03-02 20:47:43 +00:00
|
|
|
} else if (!arg.empty()) {
|
2020-07-06 13:15:26 +00:00
|
|
|
if (arg[0] == '-') {
|
|
|
|
std::cerr << "Unrecognized option: " << arg << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!opts->input_filename.empty()) {
|
|
|
|
std::cerr << "More than one input file specified: '"
|
|
|
|
<< opts->input_filename << "' and '" << arg << "'"
|
|
|
|
<< std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
2020-03-02 20:47:43 +00:00
|
|
|
opts->input_filename = arg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-12-02 15:31:08 +00:00
|
|
|
/// Copies the content from the file named `input_file` to `buffer`,
|
|
|
|
/// assuming each element in the file is of type `T`. If any error occurs,
|
2020-03-10 22:54:12 +00:00
|
|
|
/// writes error messages to the standard error stream and returns false.
|
2020-12-02 15:31:08 +00:00
|
|
|
/// Assumes the size of a `T` object is divisible by its required alignment.
|
2020-03-10 22:54:12 +00:00
|
|
|
/// @returns true if we successfully read the file.
|
|
|
|
template <typename T>
|
|
|
|
bool ReadFile(const std::string& input_file, std::vector<T>* buffer) {
|
|
|
|
if (!buffer) {
|
|
|
|
std::cerr << "The buffer pointer was null" << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-03-02 20:47:43 +00:00
|
|
|
FILE* file = nullptr;
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
fopen_s(&file, input_file.c_str(), "rb");
|
|
|
|
#else
|
|
|
|
file = fopen(input_file.c_str(), "rb");
|
|
|
|
#endif
|
|
|
|
if (!file) {
|
|
|
|
std::cerr << "Failed to open " << input_file << std::endl;
|
2020-03-10 22:54:12 +00:00
|
|
|
return false;
|
2020-03-02 20:47:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fseek(file, 0, SEEK_END);
|
|
|
|
uint64_t tell_file_size = static_cast<uint64_t>(ftell(file));
|
|
|
|
if (tell_file_size <= 0) {
|
|
|
|
std::cerr << "Input file of incorrect size: " << input_file << std::endl;
|
|
|
|
fclose(file);
|
|
|
|
return {};
|
|
|
|
}
|
2020-03-10 22:54:12 +00:00
|
|
|
const auto file_size = static_cast<size_t>(tell_file_size);
|
|
|
|
if (0 != (file_size % sizeof(T))) {
|
|
|
|
std::cerr << "File " << input_file
|
|
|
|
<< " does not contain an integral number of objects: "
|
|
|
|
<< file_size << " bytes in the file, require " << sizeof(T)
|
|
|
|
<< " bytes per object" << std::endl;
|
|
|
|
fclose(file);
|
|
|
|
return false;
|
|
|
|
}
|
2020-03-02 20:47:43 +00:00
|
|
|
fseek(file, 0, SEEK_SET);
|
|
|
|
|
2020-03-10 22:54:12 +00:00
|
|
|
buffer->clear();
|
|
|
|
buffer->resize(file_size / sizeof(T));
|
2020-03-02 20:47:43 +00:00
|
|
|
|
2020-03-10 22:54:12 +00:00
|
|
|
size_t bytes_read = fread(buffer->data(), 1, file_size, file);
|
2020-03-02 20:47:43 +00:00
|
|
|
fclose(file);
|
|
|
|
if (bytes_read != file_size) {
|
|
|
|
std::cerr << "Failed to read " << input_file << std::endl;
|
2020-03-10 22:54:12 +00:00
|
|
|
return false;
|
2020-03-02 20:47:43 +00:00
|
|
|
}
|
|
|
|
|
2020-03-10 22:54:12 +00:00
|
|
|
return true;
|
2020-03-02 20:47:43 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 15:31:08 +00:00
|
|
|
/// Writes the given `buffer` into the file named as `output_file` using the
|
|
|
|
/// given `mode`. If `output_file` is empty or "-", writes to standard
|
|
|
|
/// output. If any error occurs, returns false and outputs error message to
|
|
|
|
/// standard error. The ContainerT type must have data() and size() methods,
|
|
|
|
/// like `std::string` and `std::vector` do.
|
2020-04-30 01:16:12 +00:00
|
|
|
/// @returns true on success
|
|
|
|
template <typename ContainerT>
|
2020-05-01 16:17:03 +00:00
|
|
|
bool WriteFile(const std::string& output_file,
|
|
|
|
const std::string mode,
|
|
|
|
const ContainerT& buffer) {
|
2020-04-30 01:16:12 +00:00
|
|
|
const bool use_stdout = output_file.empty() || output_file == "-";
|
|
|
|
FILE* file = stdout;
|
|
|
|
|
|
|
|
if (!use_stdout) {
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
fopen_s(&file, output_file.c_str(), mode.c_str());
|
|
|
|
#else
|
|
|
|
file = fopen(output_file.c_str(), mode.c_str());
|
|
|
|
#endif
|
|
|
|
if (!file) {
|
|
|
|
std::cerr << "Could not open file " << output_file << " for writing"
|
|
|
|
<< std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-01 16:17:03 +00:00
|
|
|
size_t written =
|
|
|
|
fwrite(buffer.data(), sizeof(typename ContainerT::value_type),
|
|
|
|
buffer.size(), file);
|
2020-04-30 01:16:12 +00:00
|
|
|
if (buffer.size() != written) {
|
|
|
|
if (use_stdout) {
|
|
|
|
std::cerr << "Could not write all output to standard output" << std::endl;
|
|
|
|
} else {
|
|
|
|
std::cerr << "Could not write to file " << output_file << std::endl;
|
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!use_stdout) {
|
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-03-18 14:08:48 +00:00
|
|
|
#if TINT_BUILD_SPV_WRITER
|
2020-03-02 20:47:43 +00:00
|
|
|
std::string Disassemble(const std::vector<uint32_t>& data) {
|
|
|
|
std::string spv_errors;
|
|
|
|
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_0;
|
|
|
|
|
|
|
|
auto msg_consumer = [&spv_errors](spv_message_level_t level, const char*,
|
|
|
|
const spv_position_t& position,
|
|
|
|
const char* message) {
|
|
|
|
switch (level) {
|
|
|
|
case SPV_MSG_FATAL:
|
|
|
|
case SPV_MSG_INTERNAL_ERROR:
|
|
|
|
case SPV_MSG_ERROR:
|
|
|
|
spv_errors += "error: line " + std::to_string(position.index) + ": " +
|
|
|
|
message + "\n";
|
|
|
|
break;
|
|
|
|
case SPV_MSG_WARNING:
|
|
|
|
spv_errors += "warning: line " + std::to_string(position.index) + ": " +
|
|
|
|
message + "\n";
|
|
|
|
break;
|
|
|
|
case SPV_MSG_INFO:
|
|
|
|
spv_errors += "info: line " + std::to_string(position.index) + ": " +
|
|
|
|
message + "\n";
|
|
|
|
break;
|
|
|
|
case SPV_MSG_DEBUG:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
spvtools::SpirvTools tools(target_env);
|
|
|
|
tools.SetMessageConsumer(msg_consumer);
|
|
|
|
|
|
|
|
std::string result;
|
2020-04-01 23:40:53 +00:00
|
|
|
if (!tools.Disassemble(data, &result,
|
|
|
|
SPV_BINARY_TO_TEXT_OPTION_INDENT |
|
|
|
|
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES)) {
|
|
|
|
std::cerr << spv_errors << std::endl;
|
|
|
|
}
|
2020-03-02 20:47:43 +00:00
|
|
|
return result;
|
|
|
|
}
|
2020-03-18 14:08:48 +00:00
|
|
|
#endif // TINT_BUILD_SPV_WRITER
|
2020-03-02 20:47:43 +00:00
|
|
|
|
2021-05-21 20:49:33 +00:00
|
|
|
/// PrintWGSL writes the WGSL of the program to the provided ostream, if the
|
|
|
|
/// WGSL writer is enabled, otherwise it does nothing.
|
|
|
|
/// @param out the output stream to write the WGSL to
|
|
|
|
/// @param program the program
|
|
|
|
void PrintWGSL(std::ostream& out, const tint::Program& program) {
|
|
|
|
#if TINT_BUILD_WGSL_WRITER
|
2021-07-08 16:00:23 +00:00
|
|
|
tint::writer::wgsl::Options options;
|
|
|
|
auto result = tint::writer::wgsl::Generate(&program, options);
|
|
|
|
out << std::endl << result.wgsl << std::endl;
|
2021-09-03 14:16:56 +00:00
|
|
|
#else
|
|
|
|
(void)out;
|
|
|
|
(void)program;
|
2021-05-21 20:49:33 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-07-08 16:00:23 +00:00
|
|
|
/// Generate SPIR-V code for a program.
|
|
|
|
/// @param program the program to generate
|
|
|
|
/// @param options the options that Tint was invoked with
|
|
|
|
/// @returns true on success
|
|
|
|
bool GenerateSpirv(const tint::Program* program, const Options& options) {
|
|
|
|
#if TINT_BUILD_SPV_WRITER
|
|
|
|
// TODO(jrprice): Provide a way for the user to set non-default options.
|
|
|
|
tint::writer::spirv::Options gen_options;
|
2021-07-20 18:23:06 +00:00
|
|
|
gen_options.disable_workgroup_init = options.disable_workgroup_init;
|
2021-07-08 16:00:23 +00:00
|
|
|
auto result = tint::writer::spirv::Generate(program, gen_options);
|
|
|
|
if (!result.success) {
|
|
|
|
PrintWGSL(std::cerr, *program);
|
|
|
|
std::cerr << "Failed to generate: " << result.error << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.format == Format::kSpvAsm) {
|
|
|
|
if (!WriteFile(options.output_file, "w", Disassemble(result.spirv))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!WriteFile(options.output_file, "wb", result.spirv)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.validate) {
|
|
|
|
// Use Vulkan 1.1, since this is what Tint, internally, uses.
|
|
|
|
spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_1);
|
|
|
|
tools.SetMessageConsumer([](spv_message_level_t, const char*,
|
|
|
|
const spv_position_t& pos, const char* msg) {
|
|
|
|
std::cerr << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg
|
|
|
|
<< std::endl;
|
|
|
|
});
|
|
|
|
if (!tools.Validate(result.spirv.data(), result.spirv.size(),
|
|
|
|
spvtools::ValidatorOptions())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
#else
|
2021-09-03 14:16:56 +00:00
|
|
|
(void)program;
|
|
|
|
(void)options;
|
2021-07-08 16:00:23 +00:00
|
|
|
std::cerr << "SPIR-V writer not enabled in tint build" << std::endl;
|
|
|
|
return false;
|
|
|
|
#endif // TINT_BUILD_SPV_WRITER
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate WGSL code for a program.
|
|
|
|
/// @param program the program to generate
|
|
|
|
/// @param options the options that Tint was invoked with
|
|
|
|
/// @returns true on success
|
|
|
|
bool GenerateWgsl(const tint::Program* program, const Options& options) {
|
|
|
|
#if TINT_BUILD_WGSL_WRITER
|
|
|
|
// TODO(jrprice): Provide a way for the user to set non-default options.
|
|
|
|
tint::writer::wgsl::Options gen_options;
|
|
|
|
auto result = tint::writer::wgsl::Generate(program, gen_options);
|
|
|
|
if (!result.success) {
|
|
|
|
std::cerr << "Failed to generate: " << result.error << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return WriteFile(options.output_file, "w", result.wgsl);
|
|
|
|
#else
|
2021-09-03 14:16:56 +00:00
|
|
|
(void)program;
|
|
|
|
(void)options;
|
2021-07-08 16:00:23 +00:00
|
|
|
std::cerr << "WGSL writer not enabled in tint build" << std::endl;
|
|
|
|
return false;
|
|
|
|
#endif // TINT_BUILD_WGSL_WRITER
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate MSL code for a program.
|
|
|
|
/// @param program the program to generate
|
|
|
|
/// @param options the options that Tint was invoked with
|
|
|
|
/// @returns true on success
|
|
|
|
bool GenerateMsl(const tint::Program* program, const Options& options) {
|
|
|
|
#if TINT_BUILD_MSL_WRITER
|
2021-08-12 19:47:20 +00:00
|
|
|
const tint::Program* input_program = program;
|
|
|
|
|
|
|
|
// Remap resource numbers to a flat namespace.
|
|
|
|
// TODO(crbug.com/tint/1101): Make this more robust for multiple entry points.
|
|
|
|
using BindingPoint = tint::transform::BindingPoint;
|
|
|
|
tint::transform::BindingRemapper::BindingPoints binding_points;
|
|
|
|
uint32_t next_buffer_idx = 0;
|
|
|
|
uint32_t next_sampler_idx = 0;
|
|
|
|
uint32_t next_texture_idx = 0;
|
|
|
|
|
|
|
|
tint::inspector::Inspector inspector(program);
|
|
|
|
auto entry_points = inspector.GetEntryPoints();
|
|
|
|
for (auto& entry_point : entry_points) {
|
|
|
|
auto bindings = inspector.GetResourceBindings(entry_point.name);
|
|
|
|
for (auto& binding : bindings) {
|
|
|
|
BindingPoint src = {binding.bind_group, binding.binding};
|
|
|
|
if (binding_points.count(src)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
switch (binding.resource_type) {
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kUniformBuffer:
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kStorageBuffer:
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::
|
|
|
|
kReadOnlyStorageBuffer:
|
|
|
|
binding_points.emplace(src, BindingPoint{0, next_buffer_idx++});
|
|
|
|
break;
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kSampler:
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kComparisonSampler:
|
|
|
|
binding_points.emplace(src, BindingPoint{0, next_sampler_idx++});
|
|
|
|
break;
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kSampledTexture:
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::
|
|
|
|
kMultisampledTexture:
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::
|
|
|
|
kReadOnlyStorageTexture:
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::
|
|
|
|
kWriteOnlyStorageTexture:
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kDepthTexture:
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::
|
|
|
|
kDepthMultisampledTexture:
|
|
|
|
case tint::inspector::ResourceBinding::ResourceType::kExternalTexture:
|
|
|
|
binding_points.emplace(src, BindingPoint{0, next_texture_idx++});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run the binding remapper transform.
|
|
|
|
tint::transform::Output transform_output;
|
|
|
|
if (!binding_points.empty()) {
|
|
|
|
tint::transform::Manager manager;
|
|
|
|
tint::transform::DataMap inputs;
|
|
|
|
inputs.Add<tint::transform::BindingRemapper::Remappings>(
|
|
|
|
std::move(binding_points),
|
|
|
|
tint::transform::BindingRemapper::AccessControls{},
|
|
|
|
/* mayCollide */ true);
|
|
|
|
manager.Add<tint::transform::BindingRemapper>();
|
|
|
|
transform_output = manager.Run(program, inputs);
|
|
|
|
input_program = &transform_output.program;
|
|
|
|
}
|
|
|
|
|
2021-07-08 16:00:23 +00:00
|
|
|
// TODO(jrprice): Provide a way for the user to set non-default options.
|
|
|
|
tint::writer::msl::Options gen_options;
|
2021-07-20 18:23:06 +00:00
|
|
|
gen_options.disable_workgroup_init = options.disable_workgroup_init;
|
2021-08-12 19:47:20 +00:00
|
|
|
auto result = tint::writer::msl::Generate(input_program, gen_options);
|
2021-07-08 16:00:23 +00:00
|
|
|
if (!result.success) {
|
|
|
|
PrintWGSL(std::cerr, *program);
|
|
|
|
std::cerr << "Failed to generate: " << result.error << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!WriteFile(options.output_file, "w", result.msl)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.validate) {
|
|
|
|
tint::val::Result res;
|
|
|
|
#ifdef TINT_ENABLE_MSL_VALIDATION_USING_METAL_API
|
|
|
|
res = tint::val::MslUsingMetalAPI(result.msl);
|
|
|
|
#else
|
|
|
|
#ifdef _WIN32
|
|
|
|
const char* default_xcrun_exe = "metal.exe";
|
|
|
|
#else
|
|
|
|
const char* default_xcrun_exe = "xcrun";
|
|
|
|
#endif
|
|
|
|
auto xcrun = tint::utils::Command::LookPath(
|
|
|
|
options.xcrun_path.empty() ? default_xcrun_exe : options.xcrun_path);
|
|
|
|
if (xcrun.Found()) {
|
|
|
|
res = tint::val::Msl(xcrun.Path(), result.msl);
|
|
|
|
} else {
|
|
|
|
res.output = "xcrun executable not found. Cannot validate.";
|
|
|
|
res.failed = true;
|
|
|
|
}
|
|
|
|
#endif // TINT_ENABLE_MSL_VALIDATION_USING_METAL_API
|
|
|
|
if (res.failed) {
|
|
|
|
std::cerr << res.output << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
#else
|
2021-09-03 14:16:56 +00:00
|
|
|
(void)program;
|
|
|
|
(void)options;
|
2021-07-08 16:00:23 +00:00
|
|
|
std::cerr << "MSL writer not enabled in tint build" << std::endl;
|
|
|
|
return false;
|
|
|
|
#endif // TINT_BUILD_MSL_WRITER
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate HLSL code for a program.
|
|
|
|
/// @param program the program to generate
|
|
|
|
/// @param options the options that Tint was invoked with
|
|
|
|
/// @returns true on success
|
|
|
|
bool GenerateHlsl(const tint::Program* program, const Options& options) {
|
|
|
|
#if TINT_BUILD_HLSL_WRITER
|
|
|
|
// TODO(jrprice): Provide a way for the user to set non-default options.
|
|
|
|
tint::writer::hlsl::Options gen_options;
|
2021-07-20 18:23:06 +00:00
|
|
|
gen_options.disable_workgroup_init = options.disable_workgroup_init;
|
2021-07-08 16:00:23 +00:00
|
|
|
auto result = tint::writer::hlsl::Generate(program, gen_options);
|
|
|
|
if (!result.success) {
|
|
|
|
PrintWGSL(std::cerr, *program);
|
|
|
|
std::cerr << "Failed to generate: " << result.error << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!WriteFile(options.output_file, "w", result.hlsl)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.validate) {
|
|
|
|
tint::val::Result res;
|
|
|
|
if (options.use_fxc) {
|
|
|
|
#ifdef _WIN32
|
|
|
|
res = tint::val::HlslUsingFXC(result.hlsl, result.entry_points);
|
|
|
|
#else
|
|
|
|
res.failed = true;
|
|
|
|
res.output = "FXC can only be used on Windows. Sorry :X";
|
|
|
|
#endif // _WIN32
|
|
|
|
} else {
|
|
|
|
auto dxc = tint::utils::Command::LookPath(
|
|
|
|
options.dxc_path.empty() ? "dxc" : options.dxc_path);
|
|
|
|
if (dxc.Found()) {
|
|
|
|
res = tint::val::HlslUsingDXC(dxc.Path(), result.hlsl,
|
|
|
|
result.entry_points);
|
|
|
|
} else {
|
|
|
|
res.failed = true;
|
|
|
|
res.output = "DXC executable not found. Cannot validate";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (res.failed) {
|
|
|
|
std::cerr << res.output << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
#else
|
2021-09-03 14:16:56 +00:00
|
|
|
(void)program;
|
|
|
|
(void)options;
|
2021-09-02 14:50:50 +00:00
|
|
|
std::cerr << "HLSL writer not enabled in tint build" << std::endl;
|
2021-07-08 16:00:23 +00:00
|
|
|
return false;
|
|
|
|
#endif // TINT_BUILD_HLSL_WRITER
|
|
|
|
}
|
|
|
|
|
Implement GLSL writer backend.
This is a modified version of the HLSL writer.
Basic types, arrays, entry points, reserved keywords, uniforms,
builtin uniforms, structs, some builtin functions, zero initialization
are implemented. Textures, SSBOs and storage textures in particular are
unimplemented. All the unit tests "pass", but the output is not correct
in many cases.
triangle.wgsl outputs correct vertex and fragment shaders that pass
GLSL validation via glslang. compute_boids.wgsl outputs a valid but not
correct compute shader.
Change-Id: I96c7aaf60cf2d4237e45d732e5f51b345aea0552
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/57780
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
2021-10-06 18:55:10 +00:00
|
|
|
/// Generate GLSL code for a program.
|
|
|
|
/// @param program the program to generate
|
|
|
|
/// @param options the options that Tint was invoked with
|
|
|
|
/// @returns true on success
|
|
|
|
bool GenerateGlsl(const tint::Program* program, const Options& options) {
|
|
|
|
#if TINT_BUILD_GLSL_WRITER
|
|
|
|
tint::writer::glsl::Options gen_options;
|
|
|
|
auto result = tint::writer::glsl::Generate(program, gen_options);
|
|
|
|
if (!result.success) {
|
|
|
|
PrintWGSL(std::cerr, *program);
|
|
|
|
std::cerr << "Failed to generate: " << result.error << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!WriteFile(options.output_file, "w", result.glsl)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(senorblanco): implement GLSL validation
|
|
|
|
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
std::cerr << "GLSL writer not enabled in tint build" << std::endl;
|
|
|
|
return false;
|
|
|
|
#endif // TINT_BUILD_GLSL_WRITER
|
|
|
|
}
|
|
|
|
|
2020-03-02 20:47:43 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
int main(int argc, const char** argv) {
|
|
|
|
std::vector<std::string> args(argv, argv + argc);
|
|
|
|
Options options;
|
|
|
|
|
2021-02-17 20:13:34 +00:00
|
|
|
tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
|
|
|
|
|
2021-07-15 20:24:38 +00:00
|
|
|
#if TINT_BUILD_WGSL_WRITER
|
|
|
|
tint::Program::printer = [](const tint::Program* program) {
|
|
|
|
auto result = tint::writer::wgsl::Generate(program, {});
|
|
|
|
if (!result.error.empty()) {
|
|
|
|
return "error: " + result.error;
|
|
|
|
}
|
|
|
|
return result.wgsl;
|
|
|
|
};
|
|
|
|
#endif // TINT_BUILD_WGSL_WRITER
|
|
|
|
|
2020-03-02 20:47:43 +00:00
|
|
|
if (!ParseArgs(args, &options)) {
|
|
|
|
std::cerr << "Failed to parse arguments." << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.show_help) {
|
|
|
|
std::cout << kUsage << std::endl;
|
|
|
|
return 0;
|
|
|
|
}
|
2020-04-30 01:16:12 +00:00
|
|
|
|
|
|
|
// Implement output format defaults.
|
|
|
|
if (options.format == Format::kNone) {
|
|
|
|
// Try inferring from filename.
|
|
|
|
options.format = infer_format(options.output_file);
|
|
|
|
}
|
|
|
|
if (options.format == Format::kNone) {
|
|
|
|
// Ultimately, default to SPIR-V assembly. That's nice for interactive use.
|
|
|
|
options.format = Format::kSpvAsm;
|
2020-03-02 20:47:43 +00:00
|
|
|
}
|
|
|
|
|
2020-11-26 16:50:02 +00:00
|
|
|
auto diag_printer = tint::diag::Printer::create(stderr, true);
|
|
|
|
tint::diag::Formatter diag_formatter;
|
|
|
|
|
2021-01-27 18:49:05 +00:00
|
|
|
std::unique_ptr<tint::Program> program;
|
2020-10-30 20:44:53 +00:00
|
|
|
std::unique_ptr<tint::Source::File> source_file;
|
2020-03-18 14:08:48 +00:00
|
|
|
#if TINT_BUILD_WGSL_READER
|
2020-03-10 22:54:12 +00:00
|
|
|
if (options.input_filename.size() > 5 &&
|
|
|
|
options.input_filename.substr(options.input_filename.size() - 5) ==
|
|
|
|
".wgsl") {
|
|
|
|
std::vector<uint8_t> data;
|
|
|
|
if (!ReadFile<uint8_t>(options.input_filename, &data)) {
|
|
|
|
return 1;
|
|
|
|
}
|
2020-10-30 20:44:53 +00:00
|
|
|
source_file = std::make_unique<tint::Source::File>(
|
|
|
|
options.input_filename, std::string(data.begin(), data.end()));
|
2021-01-27 18:49:05 +00:00
|
|
|
program = std::make_unique<tint::Program>(
|
|
|
|
tint::reader::wgsl::Parse(source_file.get()));
|
2020-03-02 20:47:43 +00:00
|
|
|
}
|
2020-03-18 14:08:48 +00:00
|
|
|
#endif // TINT_BUILD_WGSL_READER
|
|
|
|
|
|
|
|
#if TINT_BUILD_SPV_READER
|
2020-06-22 14:36:34 +00:00
|
|
|
// Handle SPIR-V binary input, in files ending with .spv
|
2020-03-10 22:54:12 +00:00
|
|
|
if (options.input_filename.size() > 4 &&
|
|
|
|
options.input_filename.substr(options.input_filename.size() - 4) ==
|
|
|
|
".spv") {
|
|
|
|
std::vector<uint32_t> data;
|
|
|
|
if (!ReadFile<uint32_t>(options.input_filename, &data)) {
|
|
|
|
return 1;
|
|
|
|
}
|
2021-01-27 18:49:05 +00:00
|
|
|
program = std::make_unique<tint::Program>(tint::reader::spirv::Parse(data));
|
2020-03-10 22:54:12 +00:00
|
|
|
}
|
2020-06-22 14:36:34 +00:00
|
|
|
// Handle SPIR-V assembly input, in files ending with .spvasm
|
|
|
|
if (options.input_filename.size() > 7 &&
|
|
|
|
options.input_filename.substr(options.input_filename.size() - 7) ==
|
|
|
|
".spvasm") {
|
|
|
|
std::vector<char> text;
|
|
|
|
if (!ReadFile<char>(options.input_filename, &text)) {
|
|
|
|
return 1;
|
|
|
|
}
|
2020-08-13 17:33:59 +00:00
|
|
|
// Use Vulkan 1.1, since this is what Tint, internally, is expecting.
|
|
|
|
spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_1);
|
2020-06-22 14:36:34 +00:00
|
|
|
tools.SetMessageConsumer([](spv_message_level_t, const char*,
|
|
|
|
const spv_position_t& pos, const char* msg) {
|
|
|
|
std::cerr << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg
|
|
|
|
<< std::endl;
|
|
|
|
});
|
|
|
|
std::vector<uint32_t> data;
|
|
|
|
if (!tools.Assemble(text.data(), text.size(), &data,
|
|
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS)) {
|
|
|
|
return 1;
|
|
|
|
}
|
2021-01-27 18:49:05 +00:00
|
|
|
program = std::make_unique<tint::Program>(tint::reader::spirv::Parse(data));
|
2020-06-22 14:36:34 +00:00
|
|
|
}
|
2020-03-18 14:08:48 +00:00
|
|
|
#endif // TINT_BUILD_SPV_READER
|
|
|
|
|
2021-01-27 18:49:05 +00:00
|
|
|
if (!program) {
|
2020-03-02 20:47:43 +00:00
|
|
|
std::cerr << "Failed to create reader for input file: "
|
|
|
|
<< options.input_filename << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
2021-04-09 20:14:18 +00:00
|
|
|
if (program->Diagnostics().count() > 0) {
|
2021-01-27 18:49:05 +00:00
|
|
|
diag_formatter.format(program->Diagnostics(), diag_printer.get());
|
2021-04-09 20:14:18 +00:00
|
|
|
}
|
2020-04-06 18:43:56 +00:00
|
|
|
|
2020-11-16 14:46:27 +00:00
|
|
|
if (options.dump_ast) {
|
2021-01-29 11:22:40 +00:00
|
|
|
std::cout << std::endl << program->to_str(options.demangle) << std::endl;
|
2020-11-16 14:46:27 +00:00
|
|
|
}
|
2021-05-07 15:19:54 +00:00
|
|
|
|
|
|
|
if (!program->IsValid()) {
|
|
|
|
return 1;
|
|
|
|
}
|
2020-11-16 14:46:27 +00:00
|
|
|
if (options.parse_only) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-12-02 21:17:58 +00:00
|
|
|
tint::transform::Manager transform_manager;
|
2021-04-26 20:38:36 +00:00
|
|
|
tint::transform::DataMap transform_inputs;
|
2020-09-30 00:05:23 +00:00
|
|
|
for (const auto& name : options.transforms) {
|
|
|
|
// TODO(dsinclair): The vertex pulling transform requires setup code to
|
|
|
|
// be run that needs user input. Should we find a way to support that here
|
|
|
|
// maybe through a provided file?
|
|
|
|
|
2021-06-30 13:23:36 +00:00
|
|
|
if (name == "first_index_offset") {
|
2021-04-26 20:38:36 +00:00
|
|
|
transform_inputs.Add<tint::transform::FirstIndexOffset::BindingPoint>(0,
|
|
|
|
0);
|
|
|
|
transform_manager.Add<tint::transform::FirstIndexOffset>();
|
2021-07-02 21:15:44 +00:00
|
|
|
} else if (name == "fold_trivial_single_use_lets") {
|
|
|
|
transform_manager.Add<tint::transform::FoldTrivialSingleUseLets>();
|
2021-04-16 08:28:54 +00:00
|
|
|
} else if (name == "renamer") {
|
2021-04-26 20:38:36 +00:00
|
|
|
transform_manager.Add<tint::transform::Renamer>();
|
2021-06-30 13:23:36 +00:00
|
|
|
} else if (name == "robustness") {
|
|
|
|
transform_manager.Add<tint::transform::Robustness>();
|
2020-09-30 00:05:23 +00:00
|
|
|
} else {
|
|
|
|
std::cerr << "Unknown transform name: " << name << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2020-12-04 09:06:09 +00:00
|
|
|
|
2021-04-28 15:33:03 +00:00
|
|
|
if (options.emit_single_entry_point) {
|
|
|
|
transform_manager.append(
|
|
|
|
std::make_unique<tint::transform::SingleEntryPoint>());
|
|
|
|
transform_inputs.Add<tint::transform::SingleEntryPoint::Config>(
|
|
|
|
options.ep_name);
|
|
|
|
}
|
|
|
|
|
2021-02-10 21:22:03 +00:00
|
|
|
switch (options.format) {
|
2021-04-16 08:28:54 +00:00
|
|
|
case Format::kMsl: {
|
2021-09-03 14:16:56 +00:00
|
|
|
#if TINT_BUILD_MSL_WRITER
|
2021-07-06 10:20:19 +00:00
|
|
|
transform_inputs.Add<tint::transform::Renamer::Config>(
|
|
|
|
tint::transform::Renamer::Target::kMslKeywords);
|
|
|
|
transform_manager.Add<tint::transform::Renamer>();
|
2021-09-03 14:16:56 +00:00
|
|
|
#endif // TINT_BUILD_MSL_WRITER
|
2021-02-10 21:22:03 +00:00
|
|
|
break;
|
2021-04-16 08:28:54 +00:00
|
|
|
}
|
Implement GLSL writer backend.
This is a modified version of the HLSL writer.
Basic types, arrays, entry points, reserved keywords, uniforms,
builtin uniforms, structs, some builtin functions, zero initialization
are implemented. Textures, SSBOs and storage textures in particular are
unimplemented. All the unit tests "pass", but the output is not correct
in many cases.
triangle.wgsl outputs correct vertex and fragment shaders that pass
GLSL validation via glslang. compute_boids.wgsl outputs a valid but not
correct compute shader.
Change-Id: I96c7aaf60cf2d4237e45d732e5f51b345aea0552
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/57780
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
2021-10-06 18:55:10 +00:00
|
|
|
#if TINT_BUILD_GLSL_WRITER
|
|
|
|
case Format::kGlsl: {
|
|
|
|
transform_inputs.Add<tint::transform::Renamer::Config>(
|
|
|
|
tint::transform::Renamer::Target::kGlslKeywords);
|
|
|
|
transform_manager.Add<tint::transform::Renamer>();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif // TINT_BUILD_GLSL_WRITER
|
2021-04-16 08:28:54 +00:00
|
|
|
case Format::kHlsl: {
|
2021-09-03 14:16:56 +00:00
|
|
|
#if TINT_BUILD_HLSL_WRITER
|
2021-07-06 10:20:19 +00:00
|
|
|
transform_inputs.Add<tint::transform::Renamer::Config>(
|
|
|
|
tint::transform::Renamer::Target::kHlslKeywords);
|
|
|
|
transform_manager.Add<tint::transform::Renamer>();
|
2021-09-03 14:16:56 +00:00
|
|
|
#endif // TINT_BUILD_HLSL_WRITER
|
2021-02-10 21:22:03 +00:00
|
|
|
break;
|
2021-04-16 08:28:54 +00:00
|
|
|
}
|
2021-02-10 21:22:03 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-04-26 20:38:36 +00:00
|
|
|
auto out = transform_manager.Run(program.get(), std::move(transform_inputs));
|
2021-02-24 15:55:24 +00:00
|
|
|
if (!out.program.IsValid()) {
|
2021-05-21 20:49:33 +00:00
|
|
|
PrintWGSL(std::cerr, out.program);
|
2021-02-24 15:55:24 +00:00
|
|
|
diag_formatter.format(out.program.Diagnostics(), diag_printer.get());
|
2020-03-02 20:47:43 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-01-27 18:49:05 +00:00
|
|
|
*program = std::move(out.program);
|
2020-12-04 09:06:09 +00:00
|
|
|
|
2021-03-04 15:30:35 +00:00
|
|
|
if (options.dump_inspector_bindings) {
|
|
|
|
std::cout << std::string(80, '-') << std::endl;
|
|
|
|
tint::inspector::Inspector inspector(program.get());
|
|
|
|
auto entry_points = inspector.GetEntryPoints();
|
|
|
|
if (!inspector.error().empty()) {
|
|
|
|
std::cerr << "Failed to get entry points from Inspector: "
|
|
|
|
<< inspector.error() << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& entry_point : entry_points) {
|
|
|
|
auto bindings = inspector.GetResourceBindings(entry_point.name);
|
|
|
|
if (!inspector.error().empty()) {
|
|
|
|
std::cerr << "Failed to get bindings from Inspector: "
|
|
|
|
<< inspector.error() << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
std::cout << "Entry Point = " << entry_point.name << std::endl;
|
|
|
|
for (auto& binding : bindings) {
|
|
|
|
std::cout << "\t[" << binding.bind_group << "][" << binding.binding
|
|
|
|
<< "]:" << std::endl;
|
|
|
|
std::cout << "\t\t resource_type = "
|
|
|
|
<< ResourceTypeToString(binding.resource_type) << std::endl;
|
|
|
|
std::cout << "\t\t dim = " << TextureDimensionToString(binding.dim)
|
|
|
|
<< std::endl;
|
|
|
|
std::cout << "\t\t sampled_kind = "
|
|
|
|
<< SampledKindToString(binding.sampled_kind) << std::endl;
|
|
|
|
std::cout << "\t\t image_format = "
|
|
|
|
<< ImageFormatToString(binding.image_format) << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::cout << std::string(80, '-') << std::endl;
|
|
|
|
}
|
|
|
|
|
2021-07-08 16:00:23 +00:00
|
|
|
bool success = false;
|
2021-06-02 21:02:34 +00:00
|
|
|
switch (options.format) {
|
|
|
|
case Format::kSpirv:
|
|
|
|
case Format::kSpvAsm:
|
2021-07-08 16:00:23 +00:00
|
|
|
success = GenerateSpirv(program.get(), options);
|
2021-06-02 21:02:34 +00:00
|
|
|
break;
|
|
|
|
case Format::kWgsl:
|
2021-07-08 16:00:23 +00:00
|
|
|
success = GenerateWgsl(program.get(), options);
|
2021-06-02 21:02:34 +00:00
|
|
|
break;
|
|
|
|
case Format::kMsl:
|
2021-07-08 16:00:23 +00:00
|
|
|
success = GenerateMsl(program.get(), options);
|
2021-06-02 21:02:34 +00:00
|
|
|
break;
|
|
|
|
case Format::kHlsl:
|
2021-07-08 16:00:23 +00:00
|
|
|
success = GenerateHlsl(program.get(), options);
|
2021-06-02 21:02:34 +00:00
|
|
|
break;
|
Implement GLSL writer backend.
This is a modified version of the HLSL writer.
Basic types, arrays, entry points, reserved keywords, uniforms,
builtin uniforms, structs, some builtin functions, zero initialization
are implemented. Textures, SSBOs and storage textures in particular are
unimplemented. All the unit tests "pass", but the output is not correct
in many cases.
triangle.wgsl outputs correct vertex and fragment shaders that pass
GLSL validation via glslang. compute_boids.wgsl outputs a valid but not
correct compute shader.
Change-Id: I96c7aaf60cf2d4237e45d732e5f51b345aea0552
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/57780
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
2021-10-06 18:55:10 +00:00
|
|
|
case Format::kGlsl:
|
|
|
|
success = GenerateGlsl(program.get(), options);
|
|
|
|
break;
|
2021-06-02 21:02:34 +00:00
|
|
|
default:
|
|
|
|
std::cerr << "Unknown output format specified" << std::endl;
|
|
|
|
return 1;
|
2020-03-02 20:47:43 +00:00
|
|
|
}
|
2021-07-08 16:00:23 +00:00
|
|
|
if (!success) {
|
2020-10-08 20:22:35 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2020-03-18 14:08:48 +00:00
|
|
|
|
2020-03-02 20:47:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|