tint/test-runner: Split expectations for FXC and DXC

Change tint's `--fxc` flag to take the path of the FXC compiler DLL.
Have tint attempt to validate with both FXC and DXC if `--validate` is
passed.

Fix the 'dirsWithNoPassExpectations' logic which looks like it got
broken with the tint -> dawn merge. It also incorrectly applied
filepath.FromSlash() on windows.

Change-Id: I0f46aa5c21bc48a2abc48402c41f846aff4a8633
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/96800
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
This commit is contained in:
Ben Clayton
2022-07-22 17:43:27 +00:00
committed by Dawn LUCI CQ
parent 0778d9a48f
commit 7d34de88f1
5122 changed files with 73624 additions and 206 deletions

View File

@@ -67,6 +67,7 @@ enum class Format {
struct Options {
bool show_help = false;
bool verbose = false;
std::string input_filename;
std::string output_file = "-"; // Default to stdout
@@ -84,7 +85,7 @@ struct Options {
std::vector<std::string> transforms;
bool use_fxc = false;
std::string fxc_path;
std::string dxc_path;
std::string xcrun_path;
std::unordered_map<std::string, double> overrides;
@@ -120,13 +121,13 @@ ${transforms}
used for num_workgroups in HLSL. If not specified, then
default to binding 0 of the largest used group plus 1,
or group 0 if no resource bound.
--validate -- Validates the generated shader
--fxc -- Ask to validate HLSL output using FXC instead of DXC.
When specified, automatically enables --validate
--validate -- Validates the generated shader with all available validators
--fxc -- Path to FXC dll, used to validate HLSL output.
When specified, automatically enables HLSL validation with FXC
--dxc -- Path to DXC executable, used to validate HLSL output.
When specified, automatically enables --validate
When specified, automatically enables HLSL validation with DXC
--xcrun -- Path to xcrun executable, used to validate MSL output.
When specified, automatically enables --validate
When specified, automatically enables MSL validation
--overrides -- Override values as IDENTIFIER=VALUE, comma-separated.
)";
@@ -397,6 +398,8 @@ bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
} else if (arg == "-h" || arg == "--help") {
opts->show_help = true;
} else if (arg == "-v" || arg == "--verbose") {
opts->verbose = true;
} else if (arg == "--transform") {
++i;
if (i >= args.size()) {
@@ -415,8 +418,12 @@ bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
} else if (arg == "--validate") {
opts->validate = true;
} else if (arg == "--fxc") {
opts->validate = true;
opts->use_fxc = true;
++i;
if (i >= args.size()) {
std::cerr << "Missing value for " << arg << std::endl;
return false;
}
opts->fxc_path = args[i];
} else if (arg == "--dxc") {
++i;
if (i >= args.size()) {
@@ -424,7 +431,6 @@ bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
return false;
}
opts->dxc_path = args[i];
opts->validate = true;
} else if (arg == "--xcrun") {
++i;
if (i >= args.size()) {
@@ -801,29 +807,71 @@ bool GenerateHlsl(const tint::Program* program, const Options& options) {
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 {
// If --fxc or --dxc was passed, then we must explicitly find and validate with that respective
// compiler.
const bool must_validate_dxc = !options.dxc_path.empty();
const bool must_validate_fxc = !options.fxc_path.empty();
if (options.validate || must_validate_dxc || must_validate_fxc) {
tint::val::Result dxc_res;
bool dxc_found = false;
if (options.validate || must_validate_dxc) {
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";
dxc_found = true;
dxc_res = tint::val::HlslUsingDXC(dxc.Path(), result.hlsl, result.entry_points);
} else if (must_validate_dxc) {
// DXC was explicitly requested. Error if it could not be found.
dxc_res.failed = true;
dxc_res.output =
"DXC executable '" + options.dxc_path + "' not found. Cannot validate";
}
}
if (res.failed) {
std::cerr << res.output << std::endl;
tint::val::Result fxc_res;
bool fxc_found = false;
if (options.validate || must_validate_fxc) {
auto fxc = tint::utils::Command::LookPath(
options.fxc_path.empty() ? tint::val::kFxcDLLName : options.fxc_path);
#ifdef _WIN32
if (fxc.Found()) {
fxc_found = true;
fxc_res = tint::val::HlslUsingFXC(fxc.Path(), result.hlsl, result.entry_points);
} else if (must_validate_fxc) {
// FXC was explicitly requested. Error if it could not be found.
fxc_res.failed = true;
fxc_res.output = "FXC DLL '" + options.fxc_path + "' not found. Cannot validate";
}
#else
if (must_validate_dxc) {
fxc_res.failed = true;
fxc_res.output = "FXC can only be used on Windows.";
}
#endif // _WIN32
}
if (fxc_res.failed) {
std::cerr << "FXC validation failure:" << std::endl << fxc_res.output << std::endl;
}
if (dxc_res.failed) {
std::cerr << "DXC validation failure:" << std::endl << dxc_res.output << std::endl;
}
if (fxc_res.failed || dxc_res.failed) {
return false;
}
if (!fxc_found && !dxc_found) {
std::cerr << "Couldn't find FXC or DXC. Cannot validate" << std::endl;
return false;
}
if (options.verbose) {
if (fxc_found && !fxc_res.failed) {
std::cout << "Passed FXC validation" << std::endl;
}
if (dxc_found && !dxc_res.failed) {
std::cout << "Passed DXC validation" << std::endl;
}
}
}
return true;

View File

@@ -16,9 +16,12 @@
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
#include <dbghelp.h>
#include <sstream>
#include <string>
#include "src/tint/utils/defer.h"
namespace tint::utils {
namespace {
@@ -97,9 +100,34 @@ class Pipe {
Handle write;
};
/// Queries whether the file at the given path is an executable or DLL.
bool ExecutableExists(const std::string& path) {
DWORD type = 0;
return GetBinaryTypeA(path.c_str(), &type);
auto file = Handle(CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_READONLY, NULL));
if (!file) {
return false;
}
auto map = Handle(CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL));
if (map == INVALID_HANDLE_VALUE) {
return false;
}
void* addr_header = MapViewOfFileEx(map, FILE_MAP_READ, 0, 0, 0, NULL);
// Dynamically obtain the address of, and call ImageNtHeader. This is done to avoid tint.exe
// needing to statically link Dbghelp.lib.
static auto* dbg_help = LoadLibraryA("Dbghelp.dll"); // Leaks, but who cares?
if (dbg_help) {
if (FARPROC proc = GetProcAddress(dbg_help, "ImageNtHeader")) {
using ImageNtHeaderPtr = decltype(&ImageNtHeader);
auto* image_nt_header = reinterpret_cast<ImageNtHeaderPtr>(proc)(addr_header);
return image_nt_header != nullptr;
}
}
// Couldn't call ImageNtHeader, assume it is executable
return false;
}
std::string FindExecutable(const std::string& name) {
@@ -187,7 +215,8 @@ Command::Output Command::Exec(std::initializer_list<std::string> arguments) cons
&si, // Pointer to STARTUPINFO structure
&pi)) { // Pointer to PROCESS_INFORMATION structure
Output out;
out.err = "Command::Exec() CreateProcess() failed";
out.err = "Command::Exec() CreateProcess('" + args.str() + "') failed";
out.error_code = 1;
return out;
}

View File

@@ -95,13 +95,15 @@ Result HlslUsingDXC(const std::string& dxc_path,
}
#ifdef _WIN32
Result HlslUsingFXC(const std::string& source, const EntryPointList& entry_points) {
Result HlslUsingFXC(const std::string& fxc_path,
const std::string& source,
const EntryPointList& entry_points) {
Result result;
// This library leaks if an error happens in this function, but it is ok
// because it is loaded at most once, and the executables using HlslUsingFXC
// are short-lived.
HMODULE fxcLib = LoadLibraryA("d3dcompiler_47.dll");
HMODULE fxcLib = LoadLibraryA(fxc_path.c_str());
if (fxcLib == nullptr) {
result.output = "Couldn't load FXC";
result.failed = true;

View File

@@ -30,6 +30,9 @@ namespace tint::val {
using EntryPointList = std::vector<std::pair<std::string, ast::PipelineStage>>;
/// Name of the FXC compiler DLL
static constexpr const char kFxcDLLName[] = "d3dcompiler_47.dll";
/// The return structure of Validate()
struct Result {
/// True if validation passed
@@ -51,10 +54,13 @@ Result HlslUsingDXC(const std::string& dxc_path,
#ifdef _WIN32
/// Hlsl attempts to compile the shader with FXC, verifying that the shader
/// compiles successfully.
/// @param fxc_path path to the FXC DLL
/// @param source the generated HLSL source
/// @param entry_points the list of entry points to validate
/// @return the result of the compile
Result HlslUsingFXC(const std::string& source, const EntryPointList& entry_points);
Result HlslUsingFXC(const std::string& fxc_path,
const std::string& source,
const EntryPointList& entry_points);
#endif // _WIN32
/// Msl attempts to compile the shader with the Metal Shader Compiler,