GLSL writer: validate all entry points with glslang.

Generate and validate all entry points individually.
This is required since GLSL has separate shader files, and
can only have a single "main" entry point.

Bug: tint:1217
Change-Id: Ie5cb510aaef3b7c8a7573f5fa9446815284afecb
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/61920
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
Stephen White 2021-10-14 14:39:36 +00:00 committed by Tint LUCI CQ
parent f3f2d0a218
commit 7cf3b28a87
11 changed files with 123 additions and 16 deletions

1
.gitignore vendored
View File

@ -16,6 +16,7 @@ out
testing
third_party/cpplint
third_party/binutils
third_party/glslang
third_party/googletest
third_party/gpuweb-cts
third_party/llvm-build

4
DEPS
View File

@ -9,6 +9,7 @@ vars = {
'build_revision': 'c6c4a4c3ae890f2c020a087c90fb8c0b8be2816a',
'buildtools_revision': 'e3db55b4639f2a331af6f3708ca1fbd22322aac3',
'clang_revision': 'eb5ab41f3801e2085208204fd71a490573d72dfd',
'glslang_revision': '4b7b86d568b40f4b076259dc2fc4cdd006340f34',
'googletest_revision': '5c8ca58edfb304b2dd5e6061f83387470826dd87',
'gpuweb_cts_revision': 'b0291fd966b55a5efc496772555b94842bde1085',
'protobuf_revision': 'fde7cf7358ec7cd69e8db9be4f1fa6a5c431386a',
@ -27,6 +28,9 @@ deps = {
'third_party/spirv-tools': Var('chromium_git') + Var('github') +
'/KhronosGroup//SPIRV-Tools.git@' + Var('spirv_tools_revision'),
'third_party/glslang': Var('chromium_git') + Var('github') +
'/KhronosGroup/glslang.git@' + Var('glslang_revision'),
# Dependencies required to use GN/Clang in standalone
'build': Var('chromium_git') + '/chromium/src/build@' +
Var('build_revision'),

View File

@ -0,0 +1,15 @@
# Copyright 2021 The Dawn 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.
glslang_spirv_tools_dir = "//third_party/spirv-tools"

View File

@ -25,6 +25,13 @@ executable("tint") {
"${tint_spirv_tools_dir}/:spvtools_val",
]
if (tint_build_glsl_writer) {
deps += [
"${tint_root_dir}/third_party/glslang:glslang_default_resource_limits_sources",
"${tint_root_dir}/third_party/glslang:glslang_lib_sources",
]
}
configs += [
"${tint_root_dir}/src:tint_common_config",
"${tint_root_dir}/src:tint_config",

View File

@ -25,4 +25,15 @@ if(${TINT_BUILD_SPV_READER} OR ${TINT_BUILD_SPV_WRITER})
target_link_libraries(tint SPIRV-Tools)
endif()
if(${TINT_BUILD_GLSL_WRITER})
target_link_libraries(tint glslang)
target_link_libraries(tint glslang-default-resource-limits)
if(NOT MSVC)
target_compile_options(tint PRIVATE
-Wno-reserved-id-macro
-Wno-shadow-field-in-constructor
-Wno-shadow
-Wno-weak-vtables
)
endif()
endif()

View File

@ -20,6 +20,11 @@
#include <string>
#include <vector>
#if TINT_BUILD_GLSL_WRITER
#include "StandAlone/ResourceLimits.h"
#include "glslang/Public/ShaderLang.h"
#endif
#if TINT_BUILD_SPV_READER
#include "spirv-tools/libspirv.hpp"
#endif // TINT_BUILD_SPV_READER
@ -845,25 +850,65 @@ bool GenerateHlsl(const tint::Program* program, const Options& options) {
#endif // TINT_BUILD_HLSL_WRITER
}
#if TINT_BUILD_GLSL_WRITER
EShLanguage pipeline_stage_to_esh_language(tint::ast::PipelineStage stage) {
switch (stage) {
case tint::ast::PipelineStage::kFragment:
return EShLangFragment;
case tint::ast::PipelineStage::kVertex:
return EShLangVertex;
case tint::ast::PipelineStage::kCompute:
return EShLangCompute;
default:
TINT_ASSERT(AST, false);
return EShLangVertex;
}
}
#endif
/// 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
if (options.validate) {
glslang::InitializeProcess();
}
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;
}
tint::inspector::Inspector inspector(program);
for (auto& entry_point : inspector.GetEntryPoints()) {
auto result =
tint::writer::glsl::Generate(program, gen_options, entry_point.name);
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;
}
if (!WriteFile(options.output_file, "w", result.glsl)) {
return false;
}
// TODO(senorblanco): implement GLSL validation
if (options.validate) {
for (auto entry_pt : result.entry_points) {
EShLanguage lang = pipeline_stage_to_esh_language(entry_pt.second);
glslang::TShader shader(lang);
const char* strings[1] = {result.glsl.c_str()};
int lengths[1] = {static_cast<int>(result.glsl.length())};
shader.setStringsWithLengths(strings, lengths, 1);
shader.setEntryPoint("main");
bool glslang_result =
shader.parse(&glslang::DefaultTBuiltInResource, 310, EEsProfile,
false, false, EShMsgDefault);
if (!glslang_result) {
std::cerr << "Error parsing GLSL shader:\n"
<< shader.getInfoLog() << "\n"
<< shader.getInfoDebugLog() << "\n";
}
}
}
}
return true;
#else

View File

@ -28,6 +28,7 @@
#include "src/transform/pad_array_elements.h"
#include "src/transform/promote_initializers_to_const_var.h"
#include "src/transform/simplify.h"
#include "src/transform/single_entry_point.h"
#include "src/transform/zero_init_workgroup_memory.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::Glsl);
@ -69,6 +70,10 @@ Output Glsl::Run(const Program* in, const DataMap& inputs) {
// variables directly.
data.Add<CanonicalizeEntryPointIO::Config>(
CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
if (cfg) {
manager.Add<SingleEntryPoint>();
data.Add<SingleEntryPoint::Config>(cfg->entry_point);
}
auto out = manager.Run(in, data);
if (!out.program.IsValid()) {
return out;
@ -94,7 +99,8 @@ void Glsl::AddEmptyEntryPoint(CloneContext& ctx) const {
ctx.dst->WorkgroupSize(1)});
}
Glsl::Config::Config(bool disable_wi) : disable_workgroup_init(disable_wi) {}
Glsl::Config::Config(const std::string& ep, bool disable_wi)
: entry_point(ep), disable_workgroup_init(disable_wi) {}
Glsl::Config::Config(const Config&) = default;
Glsl::Config::~Config() = default;

View File

@ -15,6 +15,8 @@
#ifndef SRC_TRANSFORM_GLSL_H_
#define SRC_TRANSFORM_GLSL_H_
#include <string>
#include "src/transform/transform.h"
namespace tint {
@ -32,9 +34,11 @@ class Glsl : public Castable<Glsl, Transform> {
/// Configuration options for the Glsl sanitizer transform.
struct Config : public Castable<Data, transform::Data> {
/// Constructor
/// @param entry_point the root entry point function to generate
/// @param disable_workgroup_init `true` to disable workgroup memory zero
/// initialization
explicit Config(bool disable_workgroup_init = false);
explicit Config(const std::string& entry_point,
bool disable_workgroup_init = false);
/// Copy constructor
Config(const Config&);
@ -42,6 +46,9 @@ class Glsl : public Castable<Glsl, Transform> {
/// Destructor
~Config() override;
/// GLSL generator wraps a single entry point in a main() function.
std::string entry_point;
/// Set to `true` to disable workgroup memory zero initialization
bool disable_workgroup_init = false;
};

View File

@ -25,12 +25,16 @@ Result::Result() = default;
Result::~Result() = default;
Result::Result(const Result&) = default;
Result Generate(const Program* program, const Options&) {
Result Generate(const Program* program,
const Options&,
const std::string& entry_point) {
Result result;
// Run the GLSL sanitizer.
transform::DataMap data;
data.Add<transform::Glsl::Config>(entry_point);
transform::Glsl sanitizer;
auto output = sanitizer.Run(program);
auto output = sanitizer.Run(program, data);
if (!output.program.IsValid()) {
result.success = false;
result.error = output.program.Diagnostics().str();

View File

@ -67,7 +67,9 @@ struct Result {
/// @param program the program to translate to GLSL
/// @param options the configuration options to use when generating GLSL
/// @returns the resulting GLSL and supplementary information
Result Generate(const Program* program, const Options& options);
Result Generate(const Program* program,
const Options& options,
const std::string& entry_point);
} // namespace glsl
} // namespace writer

View File

@ -39,3 +39,8 @@ if(${TINT_BUILD_SPV_READER} OR ${TINT_BUILD_SPV_WRITER})
add_subdirectory("${TINT_THIRD_PARTY_DIR}/spirv-tools" "${CMAKE_BINARY_DIR}/third_party/spirv-tools" EXCLUDE_FROM_ALL)
endif()
endif()
if(${TINT_BUILD_GLSL_WRITER})
set(SPIRV-Headers_SOURCE_DIR "${TINT_THIRD_PARTY_DIR}/glslang")
add_subdirectory("${TINT_THIRD_PARTY_DIR}/glslang" "${CMAKE_BINARY_DIR}/third_party/glslang" EXCLUDE_FROM_ALL)
endif()