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

@@ -41,20 +41,22 @@ type outputFormat string
const (
testTimeout = 2 * time.Minute
glsl = outputFormat("glsl")
hlsl = outputFormat("hlsl")
msl = outputFormat("msl")
spvasm = outputFormat("spvasm")
wgsl = outputFormat("wgsl")
glsl = outputFormat("glsl")
hlslFXC = outputFormat("hlsl-fxc")
hlslDXC = outputFormat("hlsl-dxc")
msl = outputFormat("msl")
spvasm = outputFormat("spvasm")
wgsl = outputFormat("wgsl")
)
// Directories we don't generate expected PASS result files for.
// These directories contain large corpora of tests for which the generated code
// is uninteresting.
// These paths use unix-style slashes and do not contain the '/test/tint' prefix.
var dirsWithNoPassExpectations = []string{
"/test/tint/benchmark/",
"/test/tint/unittest/",
"/test/tint/vk-gl-cts/",
"benchmark/",
"unittest/",
"vk-gl-cts/",
}
func main() {
@@ -81,16 +83,15 @@ optional flags:`)
}
func run() error {
var formatList, filter, dxcPath, xcrunPath string
var formatList, filter, dxcPath, fxcPath, xcrunPath string
var maxFilenameColumnWidth int
numCPU := runtime.NumCPU()
fxc, fxcAndDxc, verbose, generateExpected, generateSkip := false, false, false, false, false
flag.StringVar(&formatList, "format", "all", "comma separated list of formats to emit. Possible values are: all, wgsl, spvasm, msl, hlsl, glsl")
verbose, generateExpected, generateSkip := false, false, false
flag.StringVar(&formatList, "format", "all", "comma separated list of formats to emit. Possible values are: all, wgsl, spvasm, msl, hlsl, hlsl-dxc, hlsl-fxc, glsl")
flag.StringVar(&filter, "filter", "**.wgsl, **.spvasm, **.spv", "comma separated list of glob patterns for test files")
flag.StringVar(&dxcPath, "dxc", "", "path to DXC executable for validating HLSL output")
flag.StringVar(&fxcPath, "fxc", "", "path to FXC DLL for validating HLSL output")
flag.StringVar(&xcrunPath, "xcrun", "", "path to xcrun executable for validating MSL output")
flag.BoolVar(&fxc, "fxc", false, "validate with FXC instead of DXC")
flag.BoolVar(&fxcAndDxc, "fxc-and-dxc", false, "validate with both FXC and DXC")
flag.BoolVar(&verbose, "verbose", false, "print all run tests, including rows that all pass")
flag.BoolVar(&generateExpected, "generate-expected", false, "create or update all expected outputs")
flag.BoolVar(&generateSkip, "generate-skip", false, "create or update all expected outputs that fail with SKIP")
@@ -104,10 +105,6 @@ func run() error {
showUsage()
}
if fxcAndDxc {
fxc = true
}
// executable path is the first argument
exe, args := args[0], args[1:]
@@ -163,7 +160,7 @@ func run() error {
// Parse --format into a list of outputFormat
formats := []outputFormat{}
if formatList == "all" {
formats = []outputFormat{wgsl, spvasm, msl, hlsl, glsl}
formats = []outputFormat{wgsl, spvasm, msl, hlslDXC, hlslFXC, glsl}
} else {
for _, f := range strings.Split(formatList, ",") {
switch strings.TrimSpace(f) {
@@ -174,7 +171,11 @@ func run() error {
case "msl":
formats = append(formats, msl)
case "hlsl":
formats = append(formats, hlsl)
formats = append(formats, hlslDXC, hlslFXC)
case "hlsl-dxc":
formats = append(formats, hlslDXC)
case "hlsl-fxc":
formats = append(formats, hlslFXC)
case "glsl":
formats = append(formats, glsl)
default:
@@ -195,7 +196,8 @@ func run() error {
lang string
path *string
}{
{"dxc", "hlsl", &dxcPath},
{"dxc", "hlsl-dxc", &dxcPath},
{"d3dcompiler_47.dll", "hlsl-fxc", &fxcPath},
{defaultMSLExe, "msl", &xcrunPath},
} {
if *tool.path == "" {
@@ -208,20 +210,11 @@ func run() error {
}
color.Set(color.FgCyan)
fmt.Printf("%-4s", tool.lang)
fmt.Printf("%-8s", tool.lang)
color.Unset()
fmt.Printf(" validation ")
if *tool.path != "" || (fxc && tool.lang == "hlsl") {
color.Set(color.FgGreen)
tool_path := *tool.path
if fxc && tool.lang == "hlsl" {
if fxcAndDxc {
tool_path += " AND Tint will use FXC dll in PATH"
} else {
tool_path = "Tint will use FXC dll in PATH"
}
}
fmt.Printf("ENABLED (" + tool_path + ")")
if *tool.path != "" {
fmt.Printf("ENABLED (" + *tool.path + ")")
} else {
color.Set(color.FgRed)
fmt.Printf("DISABLED")
@@ -245,10 +238,19 @@ func run() error {
pendingJobs := make(chan job, 256)
// Spawn numCPU job runners...
runCfg := runConfig{
wd: dir,
exe: exe,
dxcPath: dxcPath,
fxcPath: fxcPath,
xcrunPath: xcrunPath,
generateExpected: generateExpected,
generateSkip: generateSkip,
}
for cpu := 0; cpu < numCPU; cpu++ {
go func() {
for job := range pendingJobs {
job.run(dir, exe, fxc, fxcAndDxc, dxcPath, xcrunPath, generateExpected, generateSkip)
job.run(runCfg)
}
}()
}
@@ -506,10 +508,28 @@ type job struct {
result chan status
}
func (j job) run(wd, exe string, fxc, fxcAndDxc bool, dxcPath, xcrunPath string, generateExpected, generateSkip bool) {
type runConfig struct {
wd string
exe string
dxcPath string
fxcPath string
xcrunPath string
generateExpected bool
generateSkip bool
}
func (j job) run(cfg runConfig) {
j.result <- func() status {
// expectedFilePath is the path to the expected output file for the given test
expectedFilePath := j.file + ".expected." + string(j.format)
expectedFilePath := j.file + ".expected."
switch j.format {
case hlslDXC:
expectedFilePath += "dxc.hlsl"
case hlslFXC:
expectedFilePath += "fxc.hlsl"
default:
expectedFilePath += string(j.format)
}
// Is there an expected output file? If so, load it.
expected, expectedFileExists := "", false
@@ -525,7 +545,7 @@ func (j job) run(wd, exe string, fxc, fxcAndDxc bool, dxcPath, xcrunPath string,
expected = strings.ReplaceAll(expected, "\r\n", "\n")
file, err := filepath.Rel(wd, j.file)
file, err := filepath.Rel(cfg.wd, j.file)
if err != nil {
file = j.file
}
@@ -536,7 +556,7 @@ func (j job) run(wd, exe string, fxc, fxcAndDxc bool, dxcPath, xcrunPath string,
args := []string{
file,
"--format", string(j.format),
"--format", strings.Split(string(j.format), "-")[0], // 'hlsl-fxc' -> 'hlsl', etc.
}
// Can we validate?
@@ -547,52 +567,40 @@ func (j job) run(wd, exe string, fxc, fxcAndDxc bool, dxcPath, xcrunPath string,
case spvasm, glsl:
args = append(args, "--validate") // spirv-val and glslang are statically linked, always available
validate = true
case hlsl:
// Handled below
case msl:
if xcrunPath != "" {
args = append(args, "--xcrun", xcrunPath)
case hlslDXC:
if cfg.dxcPath != "" {
args = append(args, "--dxc", cfg.dxcPath)
validate = true
}
case hlslFXC:
if cfg.fxcPath != "" {
args = append(args, "--fxc", cfg.fxcPath)
validate = true
}
case msl:
if cfg.xcrunPath != "" {
args = append(args, "--xcrun", cfg.xcrunPath)
validate = true
}
default:
panic("unknown format: " + j.format)
}
// Invoke the compiler...
ok := false
var out string
args = append(args, j.flags...)
start := time.Now()
if j.format == hlsl {
// If fxcAndDxc is set, run FXC first as it's more likely to fail, then DXC iff FXC succeeded.
if fxc || fxcAndDxc {
validate = true
args_fxc := append(args, "--fxc")
args_fxc = append(args_fxc, j.flags...)
ok, out = invoke(wd, exe, args_fxc...)
}
if dxcPath != "" && (!fxc || (fxcAndDxc && ok)) {
validate = true
args_dxc := append(args, "--dxc", dxcPath)
args_dxc = append(args_dxc, j.flags...)
ok, out = invoke(wd, exe, args_dxc...)
}
// If we didn't run either fxc or dxc validation, run as usual
if !validate {
args = append(args, j.flags...)
ok, out = invoke(wd, exe, args...)
}
} else {
args = append(args, j.flags...)
ok, out = invoke(wd, exe, args...)
}
ok, out = invoke(cfg.wd, cfg.exe, args...)
timeTaken := time.Since(start)
out = strings.ReplaceAll(out, "\r\n", "\n")
matched := expected == "" || expected == out
canEmitPassExpectationFile := true
for _, noPass := range dirsWithNoPassExpectations {
if strings.Contains(j.file, filepath.FromSlash(noPass)) {
if strings.HasPrefix(file, noPass) {
canEmitPassExpectationFile = false
break
}
@@ -602,7 +610,7 @@ func (j job) run(wd, exe string, fxc, fxcAndDxc bool, dxcPath, xcrunPath string,
return ioutil.WriteFile(path, []byte(content), 0666)
}
if ok && generateExpected && (validate || !skipped) {
if ok && cfg.generateExpected && (validate || !skipped) {
// User requested to update PASS expectations, and test passed.
if canEmitPassExpectationFile {
saveExpectedFile(expectedFilePath, out)
@@ -623,14 +631,14 @@ func (j job) run(wd, exe string, fxc, fxcAndDxc bool, dxcPath, xcrunPath string,
// --- Below this point the test has failed ---
case skipped:
if generateSkip {
if cfg.generateSkip {
saveExpectedFile(expectedFilePath, "SKIP: FAILED\n\n"+out)
}
return status{code: skip, timeTaken: timeTaken}
case !ok:
// Compiler returned non-zero exit code
if generateSkip {
if cfg.generateSkip {
saveExpectedFile(expectedFilePath, "SKIP: FAILED\n\n"+out)
}
err := fmt.Errorf("%s", out)
@@ -638,7 +646,7 @@ func (j job) run(wd, exe string, fxc, fxcAndDxc bool, dxcPath, xcrunPath string,
default:
// Compiler returned zero exit code, or output was not as expected
if generateSkip {
if cfg.generateSkip {
saveExpectedFile(expectedFilePath, "SKIP: FAILED\n\n"+out)
}