writer: Move sanitizers into the backends

Adds a new single-function API for the generators, which applies the
sanitizing transform and performs the generation in one step, and
returns a result object which contains the generated code and success
status/diagnostics.

The new APIs take an `Option` structure to control backend-specific
generation details (e.g. MSL fixed sample mask). The result objects
also provide backend-specific feedback (e.g. whether a UBO of buffer
lengths was generated).

HLSL needs a list of entry points to validate, and it's the HLSL
sanitizer that generates an entry point for programs that do not have
one. This change makes the HLSL generator return the list of
post-sanitize entry points so that the Tint executable can forward
them to the validation code.

Change-Id: I2d5aa27fda95d7c50c5bef41e206aee38f2fd2eb
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/57101
Auto-Submit: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@chromium.org>
This commit is contained in:
James Price
2021-07-08 16:00:23 +00:00
committed by Tint LUCI CQ
parent 08b0ab9b92
commit af89c729ed
15 changed files with 551 additions and 268 deletions

View File

@@ -14,8 +14,6 @@
#include "src/val/val.h"
#include "src/ast/module.h"
#include "src/program.h"
#include "src/utils/io/command.h"
#include "src/utils/io/tmpfile.h"
@@ -33,7 +31,7 @@ namespace val {
Result HlslUsingDXC(const std::string& dxc_path,
const std::string& source,
Program* program) {
const EntryPointList& entry_points) {
Result result;
auto dxc = utils::Command(dxc_path);
@@ -48,48 +46,42 @@ Result HlslUsingDXC(const std::string& dxc_path,
utils::TmpFile file;
file << source;
bool found_an_entrypoint = false;
for (auto* func : program->AST().Functions()) {
if (func->IsEntryPoint()) {
found_an_entrypoint = true;
for (auto ep : entry_points) {
const char* profile = "";
const char* profile = "";
switch (func->pipeline_stage()) {
case ast::PipelineStage::kNone:
result.output = "Invalid PipelineStage";
result.failed = true;
return result;
case ast::PipelineStage::kVertex:
profile = "-T vs_6_0";
break;
case ast::PipelineStage::kFragment:
profile = "-T ps_6_0";
break;
case ast::PipelineStage::kCompute:
profile = "-T cs_6_0";
break;
}
auto name = program->Symbols().NameFor(func->symbol());
auto res = dxc(profile, "-E " + name, file.Path());
if (!res.out.empty()) {
if (!result.output.empty()) {
result.output += "\n";
}
result.output += res.out;
}
if (!res.err.empty()) {
if (!result.output.empty()) {
result.output += "\n";
}
result.output += res.err;
}
result.failed = (res.error_code != 0);
switch (ep.second) {
case ast::PipelineStage::kNone:
result.output = "Invalid PipelineStage";
result.failed = true;
return result;
case ast::PipelineStage::kVertex:
profile = "-T vs_6_0";
break;
case ast::PipelineStage::kFragment:
profile = "-T ps_6_0";
break;
case ast::PipelineStage::kCompute:
profile = "-T cs_6_0";
break;
}
auto res = dxc(profile, "-E " + ep.first, file.Path());
if (!res.out.empty()) {
if (!result.output.empty()) {
result.output += "\n";
}
result.output += res.out;
}
if (!res.err.empty()) {
if (!result.output.empty()) {
result.output += "\n";
}
result.output += res.err;
}
result.failed = (res.error_code != 0);
}
if (!found_an_entrypoint) {
if (entry_points.empty()) {
result.output = "No entrypoint found";
result.failed = true;
return result;
@@ -99,7 +91,8 @@ Result HlslUsingDXC(const std::string& dxc_path,
}
#ifdef _WIN32
Result HlslUsingFXC(const std::string& source, Program* program) {
Result HlslUsingFXC(const std::string& source,
const EntryPointList& entry_points) {
Result result;
// This library leaks if an error happens in this function, but it is ok
@@ -122,45 +115,38 @@ Result HlslUsingFXC(const std::string& source, Program* program) {
result.source = source;
bool found_an_entrypoint = false;
for (auto* func : program->AST().Functions()) {
if (func->IsEntryPoint()) {
found_an_entrypoint = true;
const char* profile = "";
switch (func->pipeline_stage()) {
case ast::PipelineStage::kNone:
result.output = "Invalid PipelineStage";
result.failed = true;
return result;
case ast::PipelineStage::kVertex:
profile = "vs_5_1";
break;
case ast::PipelineStage::kFragment:
profile = "ps_5_1";
break;
case ast::PipelineStage::kCompute:
profile = "cs_5_1";
break;
}
auto name = program->Symbols().NameFor(func->symbol());
ComPtr<ID3DBlob> compiledShader;
ComPtr<ID3DBlob> errors;
if (FAILED(d3dCompile(source.c_str(), source.length(), nullptr, nullptr,
nullptr, name.c_str(), profile, 0, 0,
&compiledShader, &errors))) {
result.output = static_cast<char*>(errors->GetBufferPointer());
for (auto ep : entry_points) {
const char* profile = "";
switch (ep.second) {
case ast::PipelineStage::kNone:
result.output = "Invalid PipelineStage";
result.failed = true;
return result;
}
case ast::PipelineStage::kVertex:
profile = "vs_5_1";
break;
case ast::PipelineStage::kFragment:
profile = "ps_5_1";
break;
case ast::PipelineStage::kCompute:
profile = "cs_5_1";
break;
}
ComPtr<ID3DBlob> compiledShader;
ComPtr<ID3DBlob> errors;
if (FAILED(d3dCompile(source.c_str(), source.length(), nullptr, nullptr,
nullptr, ep.first.c_str(), profile, 0, 0,
&compiledShader, &errors))) {
result.output = static_cast<char*>(errors->GetBufferPointer());
result.failed = true;
return result;
}
}
FreeLibrary(fxcLib);
if (!found_an_entrypoint) {
if (entry_points.empty()) {
result.output = "No entrypoint found";
result.failed = true;
return result;

View File

@@ -16,6 +16,10 @@
#define SRC_VAL_VAL_H_
#include <string>
#include <utility>
#include <vector>
#include "src/ast/pipeline_stage.h"
// Forward declarations
namespace tint {
@@ -25,6 +29,8 @@ class Program;
namespace tint {
namespace val {
using EntryPointList = std::vector<std::pair<std::string, ast::PipelineStage>>;
/// The return structure of Validate()
struct Result {
/// True if validation passed
@@ -39,19 +45,20 @@ struct Result {
/// compiles successfully.
/// @param dxc_path path to DXC
/// @param source the generated HLSL source
/// @param program the HLSL program
/// @param entry_points the list of entry points to validate
/// @return the result of the compile
Result HlslUsingDXC(const std::string& dxc_path,
const std::string& source,
Program* program);
const EntryPointList& entry_points);
#ifdef _WIN32
/// Hlsl attempts to compile the shader with FXC, verifying that the shader
/// compiles successfully.
/// @param source the generated HLSL source
/// @param program the HLSL program
/// @param entry_points the list of entry points to validate
/// @return the result of the compile
Result HlslUsingFXC(const std::string& source, Program* program);
Result HlslUsingFXC(const std::string& source,
const EntryPointList& entry_points);
#endif // _WIN32
/// Msl attempts to compile the shader with the Metal Shader Compiler,