First Commit

This commit is contained in:
2025-11-18 14:18:26 -07:00
parent 33eb6e3707
commit 27277ec342
6106 changed files with 3571167 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#include "dependency_info.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include "file.h"
#include "libshaderc_util/io_shaderc.h"
namespace glslc {
DependencyInfoDumpingHandler::DependencyInfoDumpingHandler() : mode_(not_set) {}
bool DependencyInfoDumpingHandler::DumpDependencyInfo(
std::string compilation_output_file_name, std::string source_file_name,
std::string* compilation_output_ptr,
const std::unordered_set<std::string>& dependent_files) {
std::string dep_target_label = GetTarget(compilation_output_file_name);
std::string dep_file_name =
GetDependencyFileName(compilation_output_file_name);
// Dump everything to a string stream first, then dump its content to either
// a file or compilation output string, depends on current dumping mode.
std::stringstream dep_string_stream;
// dump target label and the source_file_name.
dep_string_stream << dep_target_label << ": " << source_file_name;
// dump the dependent file names.
for (auto& dependent_file_name : dependent_files) {
dep_string_stream << " " << dependent_file_name;
}
dep_string_stream << std::endl;
if (mode_ == dump_as_compilation_output) {
compilation_output_ptr->assign(dep_string_stream.str());
} else if (mode_ == dump_as_extra_file) {
std::ofstream potential_file_stream_for_dep_info_dump;
std::ostream* dep_file_stream = shaderc_util::GetOutputStream(
dep_file_name, &potential_file_stream_for_dep_info_dump, &std::cerr);
*dep_file_stream << dep_string_stream.str();
if (dep_file_stream->fail()) {
std::cerr << "glslc: error: error writing dependent_files info to output "
"file: '"
<< dep_file_name << "'" << std::endl;
return false;
}
} else {
// mode_ should not be 'not_set', we should never be here.
return false;
}
return true;
}
std::string DependencyInfoDumpingHandler::GetTarget(
const std::string& compilation_output_file_name) {
if (!user_specified_dep_target_label_.empty()) {
return user_specified_dep_target_label_;
}
return compilation_output_file_name;
}
std::string DependencyInfoDumpingHandler::GetDependencyFileName(
const std::string& compilation_output_file_name) {
if (!user_specified_dep_file_name_.empty()) {
return user_specified_dep_file_name_;
}
return compilation_output_file_name + ".d";
}
bool DependencyInfoDumpingHandler::IsValid(std::string* error_msg_ptr,
size_t num_files) {
if (DumpingModeNotSet()) {
*error_msg_ptr =
"to generate dependencies you must specify either -M (-MM) or -MD";
return false;
}
if (!user_specified_dep_file_name_.empty() ||
!user_specified_dep_target_label_.empty()) {
if (num_files > 1) {
*error_msg_ptr =
"to specify dependency info file name or dependency info target, "
"only one input file is allowed.";
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,136 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#ifndef GLSLC_DEPENDENCY_INFO_H
#define GLSLC_DEPENDENCY_INFO_H
#include <unordered_set>
#include <string>
#include <string>
namespace glslc {
// An object to handle everything about dumping dependency info. Internally it
// has two valid dumping mode: 1) Dump to extra dependency info files, such as
// *.d files. This mode is used when we want to generate dependency info and
// also compile. 2) Overwrite the original compilation output and dump
// dependency info as compilation output. This mode is used when we do not want
// to compile the source code and want the dependency info only.
class DependencyInfoDumpingHandler {
public:
DependencyInfoDumpingHandler();
// Sets the dependency target explicitly. It's the same as the argument to
// -MT.
void SetTarget(const std::string& target_label) {
user_specified_dep_target_label_ = target_label;
}
// Sets the name of the file where dependency info will be written.
void SetDependencyFileName(const std::string& dep_file_name) {
user_specified_dep_file_name_ = dep_file_name;
}
// Dump depdendency info to a) an extra dependency info file, b) an string
// which holds the compilation output. The choice depends on the dump
// mode of the handler. Returns true if dumping is succeeded, false otherwise.
//
// The dependency file name and target are deduced based on 1) user
// specified dependency file name and target name, 2) the output filename when
// the compiler is in 'does not need linking' and 'not preprocessing-only'
// mode. It is passed through compilation_output_file_name.
//
// When the handler is set to dump dependency info as extra dependency info
// files, this method will open a file with the dependency file name and write
// the dependency info to it. Error messages caused by writing to the file are
// emitted to stderr.
//
// When the handler is set to dump dependency info as compilation output, the
// compilation output string, which is passed through compilation_output_ptr,
// will be cleared and this method will write dependency info to it. Then the
// dependency info should be emitted as normal compilation output.
//
// If the dump mode is not set when this method is called, return false.
bool DumpDependencyInfo(std::string compilation_output_file_name,
std::string source_file_name,
std::string* compilation_output_ptr,
const std::unordered_set<std::string>& dependent_files);
// Sets to always dump dependency info as an extra file, instead of the normal
// compilation output. This means the output name specified by -o options
// won't be used for the dependency info file.
void SetDumpToExtraDependencyInfoFiles() { mode_ = dump_as_extra_file; }
// Sets to dump dependency info as normal compilation output. The dependency
// info will be either saved in a file with -o option specified file, or, if
// no output file name specified, to stdout.
void SetDumpAsNormalCompilationOutput() {
mode_ = dump_as_compilation_output;
}
// Returns true if the handler's dumping mode is set to dump dependency info
// as extra dependency info files.
bool DumpingToExtraDependencyInfoFiles() {
return mode_ == dump_as_extra_file;
}
// Returns true if the handler's dumping mode is set to dump dependency info
// as normal compilation output.
bool DumpingAsCompilationOutput() {
return mode_ == dump_as_compilation_output;
}
// Returns true if the handler's dumping mode is not set.
bool DumpingModeNotSet() { return mode_ == not_set; }
// Returns true if the handler is at valid state for dumping dependency info.
bool IsValid(std::string* error_msg_ptr, size_t num_files);
private:
typedef enum {
// not_set mode tells that the dumping mode is not set yet, so the handler
// is not ready for dumping dependency info. Calling DumpDependencyInfo when
// the handler is in this mode will cause failure.
not_set = 0,
// Dumping dependency info as normal compilation output mode. In this mode,
// the dependency info will be dumped as compilation output by overwriting
// the string which holds the compilation output.
dump_as_compilation_output,
// Dumping dependency info as extra dependency info files mode. In this
// mode, dependency info will be dumped to a user specified dependency info
// file or a *.d file. Compilation output will still be generated along with
// the dependency info.
dump_as_extra_file,
} dump_mode;
// Returns the target file label to be used in depdendency info file. If -MT
// defined a label, use that string as the label. Otherwise returns the
// compilation output filename deduced in 'doesn't need linking' and 'not
// preprocessing-only' mode.
std::string GetTarget(const std::string& compilation_output_file_name);
// Returns the dependency file name to be used. If -MF defined a file name
// before, use it. Othwise, returns a filename formed by appending .d to the
// output filename deduced in 'doesn't need linking' and 'no
// preprocessing-only' mode.
std::string GetDependencyFileName(
const std::string& compilation_output_file_name);
std::string user_specified_dep_file_name_;
std::string user_specified_dep_target_label_;
dump_mode mode_;
};
}
#endif // GLSLC_DEPENDENCY_INFO_H

26
3rdparty/shaderc/glslc/src/file.cc vendored Normal file
View File

@@ -0,0 +1,26 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#include "file.h"
namespace glslc {
shaderc_util::string_piece GetFileExtension(
const shaderc_util::string_piece& filename) {
size_t dot_pos = filename.find_last_of(".");
if (dot_pos == shaderc_util::string_piece::npos) return "";
return filename.substr(dot_pos + 1);
}
} // namespace glslc

46
3rdparty/shaderc/glslc/src/file.h vendored Normal file
View File

@@ -0,0 +1,46 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#ifndef GLSLC_FILE_H_
#define GLSLC_FILE_H_
#include "libshaderc_util/string_piece.h"
namespace glslc {
// Given a file name, returns its extension. If no extension exists,
// returns an empty string_piece.
shaderc_util::string_piece GetFileExtension(
const shaderc_util::string_piece& filename);
// Returns true if the given file name ends with a known shader file extension.
inline bool IsStageFile(const shaderc_util::string_piece& filename) {
const shaderc_util::string_piece extension =
glslc::GetFileExtension(filename);
return extension == "vert" || extension == "frag" || extension == "tesc" ||
extension == "tese" || extension == "geom" || extension == "comp";
}
// Returns the file extension if is either "glsl" or "hlsl", or an empty
// string otherwise.
inline std::string GetGlslOrHlslExtension(
const shaderc_util::string_piece& filename) {
auto extension = glslc::GetFileExtension(filename);
if ((extension == "glsl") || (extension == "hlsl")) return extension.str();
return "";
}
} // namespace glslc
#endif // GLSLC_FILE_H_

View File

@@ -0,0 +1,435 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#include "file_compiler.h"
#include <cassert>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#if SHADERC_ENABLE_WGSL_OUTPUT == 1
#include "tint/tint.h"
#endif // SHADERC_ENABLE_WGSL_OUTPUT==1
#include "file.h"
#include "file_includer.h"
#include "shader_stage.h"
#include "libshaderc_util/io_shaderc.h"
#include "libshaderc_util/message.h"
namespace {
using shaderc_util::string_piece;
// A helper function to emit SPIR-V binary code as a list of hex numbers in
// text form. Returns true if a non-empty compilation result is emitted
// successfully. Return false if nothing should be emitted, either because the
// compilation result is empty, or the compilation output is not SPIR-V binary
// code.
template <typename CompilationResultType>
bool EmitSpirvBinaryAsCommaSeparatedNumbers(const CompilationResultType& result,
std::ostream* out) {
// Return early if the compilation output is not in SPIR-V binary code form.
if (!std::is_same<CompilationResultType,
shaderc::SpvCompilationResult>::value)
return false;
// Return early if the compilation result is empty.
if (result.cbegin() == result.cend()) return false;
std::ios::fmtflags output_stream_flag_cache(out->flags());
*out << std::hex << std::setfill('0');
auto RI = result.cbegin();
*out << "0x" << std::setw(8) << *RI++;
for (size_t counter = 1; RI != result.cend(); RI++, counter++) {
*out << ",";
// Break line for every four words.
if (counter % 4 == 0) {
*out << std::endl;
}
*out << "0x" << std::setw(8) << *RI;
}
out->flags(output_stream_flag_cache);
return true;
}
} // anonymous namespace
namespace glslc {
bool FileCompiler::CompileShaderFile(const InputFileSpec& input_file) {
std::vector<char> input_data;
std::string path = input_file.name;
if (!shaderc_util::ReadFile(path, &input_data)) {
return false;
}
std::string output_file_name = GetOutputFileName(input_file.name);
string_piece error_file_name = input_file.name;
if (error_file_name == "-") {
// If the input file was stdin, we want to output errors as <stdin>.
error_file_name = "<stdin>";
}
string_piece source_string = "";
if (!input_data.empty()) {
source_string = {&input_data.front(),
&input_data.front() + input_data.size()};
}
std::unique_ptr<FileIncluder> includer(
new FileIncluder(&include_file_finder_));
// Get a reference to the dependency trace before we pass the ownership to
// shaderc::CompileOptions.
const auto& used_source_files = includer->file_path_trace();
options_.SetIncluder(std::move(includer));
if (input_file.stage == shaderc_spirv_assembly) {
// Only act if the requested target is SPIR-V binary.
if (output_type_ == OutputType::SpirvBinary) {
const auto result =
compiler_.AssembleToSpv(source_string.data(), source_string.size());
return EmitCompiledResult(result, input_file.name, output_file_name,
error_file_name, used_source_files);
} else {
return true;
}
}
// Set the language. Since we only use the options object in this
// method, then it's ok to always set it without resetting it after
// compilation. A subsequent compilation will set it again anyway.
options_.SetSourceLanguage(input_file.language);
switch (output_type_) {
case OutputType::SpirvBinary: {
const auto result = compiler_.CompileGlslToSpv(
source_string.data(), source_string.size(), input_file.stage,
error_file_name.data(), input_file.entry_point_name.c_str(),
options_);
return EmitCompiledResult(result, input_file.name, output_file_name,
error_file_name, used_source_files);
}
case OutputType::SpirvAssemblyText: {
const auto result = compiler_.CompileGlslToSpvAssembly(
source_string.data(), source_string.size(), input_file.stage,
error_file_name.data(), input_file.entry_point_name.c_str(),
options_);
return EmitCompiledResult(result, input_file.name, output_file_name,
error_file_name, used_source_files);
}
case OutputType::PreprocessedText: {
const auto result = compiler_.PreprocessGlsl(
source_string.data(), source_string.size(), input_file.stage,
error_file_name.data(), options_);
return EmitCompiledResult(result, input_file.name, output_file_name,
error_file_name, used_source_files);
}
}
return false;
}
template <typename CompilationResultType>
bool FileCompiler::EmitCompiledResult(
const CompilationResultType& result, const std::string& input_file,
const std::string& output_file_name, string_piece error_file_name,
const std::unordered_set<std::string>& used_source_files) {
total_errors_ += result.GetNumErrors();
total_warnings_ += result.GetNumWarnings();
bool compilation_success =
result.GetCompilationStatus() == shaderc_compilation_status_success;
// Handle the error message for failing to deduce the shader kind.
if (result.GetCompilationStatus() ==
shaderc_compilation_status_invalid_stage) {
auto glsl_or_hlsl_extension = GetGlslOrHlslExtension(error_file_name);
if (glsl_or_hlsl_extension != "") {
std::cerr << "glslc: error: "
<< "'" << error_file_name << "': "
<< "." << glsl_or_hlsl_extension
<< " file encountered but no -fshader-stage specified ahead";
} else if (error_file_name == "<stdin>") {
std::cerr
<< "glslc: error: '-': -fshader-stage required when input is from "
"standard "
"input \"-\"";
} else {
std::cerr << "glslc: error: "
<< "'" << error_file_name << "': "
<< "file not recognized: File format not recognized";
}
std::cerr << "\n";
return false;
}
// Get a string_piece which refers to the normal compilation output for now.
// This string_piece might be redirected to the dependency info to be dumped
// later, if the handler is instantiated to dump as normal compilation output,
// and the original compilation output should be blocked. Otherwise it won't
// be touched. The main output stream dumps this string_piece later.
string_piece compilation_output(
reinterpret_cast<const char*>(result.cbegin()),
reinterpret_cast<const char*>(result.cend()));
// If we have dependency info dumping handler instantiated, we should dump
// dependency info first. This may redirect the compilation output
// string_piece to dependency info.
std::string potential_dependency_info_output;
if (dependency_info_dumping_handler_) {
if (!dependency_info_dumping_handler_->DumpDependencyInfo(
GetCandidateOutputFileName(input_file), error_file_name.data(),
&potential_dependency_info_output, used_source_files)) {
return false;
}
if (!potential_dependency_info_output.empty()) {
// If the potential_dependency_info_output string is not empty, it means
// we should dump dependency info as normal compilation output. Redirect
// the compilation output string_piece to the dependency info stored in
// potential_dependency_info_output to make it happen.
compilation_output = potential_dependency_info_output;
}
}
std::ostream* out = nullptr;
std::ofstream potential_file_stream;
if (compilation_success) {
out = shaderc_util::GetOutputStream(output_file_name,
&potential_file_stream, &std::cerr);
if (!out || out->fail()) {
// An error message has already been emitted to the stderr stream.
return false;
}
// Write compilation output to output file. If an output format for SPIR-V
// binary code is specified, it is handled here.
switch (binary_emission_format_) {
case SpirvBinaryEmissionFormat::Unspecified:
case SpirvBinaryEmissionFormat::Binary:
// The output format is unspecified or specified as binary output.
// On Windows, the output stream must be set to binary mode. By
// default the standard output stream is set to text mode, which
// translates newlines (\n) to carriage-return newline pairs
// (\r\n).
if (out == &std::cout) shaderc_util::FlushAndSetBinaryModeOnStdout();
out->write(compilation_output.data(), compilation_output.size());
if (out == &std::cout) shaderc_util::FlushAndSetTextModeOnStdout();
break;
case SpirvBinaryEmissionFormat::Numbers:
// The output format is specified to be a list of hex numbers, the
// compilation output must be in SPIR-V binary code form.
assert(output_type_ == OutputType::SpirvBinary);
if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
// Only emits the end-of-line character when the emitted compilation
// result is not empty.
*out << std::endl;
}
break;
case SpirvBinaryEmissionFormat::CInitList:
// The output format is specified to be a C-style initializer list, the
// compilation output must be in SPIR-V binary code form.
assert(output_type_ == OutputType::SpirvBinary);
if (result.begin() != result.end()) {
// Only emits the '{' when the compilation result is not empty.
*out << "{";
}
if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
// Only emits the end-of-line character when the emitted compilation
// result is not empty.
*out << "}" << std::endl;
}
break;
case SpirvBinaryEmissionFormat::WGSL: {
#if SHADERC_ENABLE_WGSL_OUTPUT == 1
tint::Context ctx;
tint::reader::spirv::Parser spv_reader(
&ctx, std::vector<uint32_t>(result.begin(), result.end()));
if (!spv_reader.Parse()) {
std::cout << "error: failed to convert SPIR-V binary to WGSL: "
<< spv_reader.error() << std::endl;
return false;
}
tint::writer::wgsl::Generator wgsl_writer(spv_reader.module());
if (!wgsl_writer.Generate()) {
std::cout << "error: failed to convert to WGSL: "
<< wgsl_writer.error() << std::endl;
return false;
}
*out << wgsl_writer.result();
#endif // SHADERC_ENABLE_WGSL_OUTPUT==1
break;
}
}
}
// Write error message to std::cerr.
std::cerr << result.GetErrorMessage();
if (out && out->fail()) {
// Something wrong happened on output.
if (out == &std::cout) {
std::cerr << "glslc: error: error writing to standard output"
<< std::endl;
} else {
std::cerr << "glslc: error: error writing to output file: '"
<< output_file_name_ << "'" << std::endl;
}
return false;
}
return compilation_success;
}
void FileCompiler::AddIncludeDirectory(const std::string& path) {
include_file_finder_.search_path().push_back(path);
}
void FileCompiler::SetIndividualCompilationFlag() {
if (output_type_ != OutputType::SpirvAssemblyText) {
needs_linking_ = false;
file_extension_ = ".spv";
}
}
void FileCompiler::SetDisassemblyFlag() {
if (!PreprocessingOnly()) {
output_type_ = OutputType::SpirvAssemblyText;
needs_linking_ = false;
file_extension_ = ".spvasm";
}
}
void FileCompiler::SetPreprocessingOnlyFlag() {
output_type_ = OutputType::PreprocessedText;
needs_linking_ = false;
if (output_file_name_.empty()) {
output_file_name_ = "-";
}
}
bool FileCompiler::ValidateOptions(size_t num_files) {
if (num_files == 0) {
std::cerr << "glslc: error: no input files" << std::endl;
return false;
}
if (num_files > 1 && needs_linking_) {
std::cerr << "glslc: error: linking multiple files is not supported yet. "
"Use -c to compile files individually."
<< std::endl;
return false;
}
// If we are outputting many object files, we cannot specify -o. Also
// if we are preprocessing multiple files they must be to stdout.
if (num_files > 1 && ((!PreprocessingOnly() && !needs_linking_ &&
!output_file_name_.empty()) ||
(PreprocessingOnly() && output_file_name_ != "-"))) {
std::cerr << "glslc: error: cannot specify -o when generating multiple"
" output files"
<< std::endl;
return false;
}
// If we have dependency info dumping handler instantiated, we should check
// its validity.
if (dependency_info_dumping_handler_) {
std::string dependency_info_dumping_hander_error_msg;
if (!dependency_info_dumping_handler_->IsValid(
&dependency_info_dumping_hander_error_msg, num_files)) {
std::cerr << "glslc: error: " << dependency_info_dumping_hander_error_msg
<< std::endl;
return false;
}
}
// If the output format is specified to be a binary, a list of hex numbers or
// a C-style initializer list, the output must be in SPIR-V binary code form.
if (binary_emission_format_ != SpirvBinaryEmissionFormat::Unspecified) {
if (output_type_ != OutputType::SpirvBinary) {
std::cerr << "glslc: error: cannot emit output as a ";
switch (binary_emission_format_) {
case SpirvBinaryEmissionFormat::Binary:
std::cerr << "binary";
break;
case SpirvBinaryEmissionFormat::Numbers:
std::cerr << "list of hex numbers";
break;
case SpirvBinaryEmissionFormat::CInitList:
std::cerr << "C-style initializer list";
break;
case SpirvBinaryEmissionFormat::WGSL:
std::cerr << "WGSL source program";
break;
case SpirvBinaryEmissionFormat::Unspecified:
// The compiler should never be here at runtime. This case is added to
// complete the switch cases.
break;
}
std::cerr << " when only preprocessing the source" << std::endl;
return false;
}
if (dependency_info_dumping_handler_ &&
dependency_info_dumping_handler_->DumpingAsCompilationOutput()) {
std::cerr << "glslc: error: cannot dump dependency info when specifying "
"any binary output format"
<< std::endl;
return false;
}
}
if (binary_emission_format_ == SpirvBinaryEmissionFormat::WGSL) {
#if SHADERC_ENABLE_WGSL_OUTPUT != 1
std::cerr << "glslc: error: can't output WGSL: glslc was built without "
"WGSL output support"
<< std::endl;
return false;
#endif
}
return true;
}
void FileCompiler::OutputMessages() {
shaderc_util::OutputMessages(&std::cerr, total_warnings_, total_errors_);
}
std::string FileCompiler::GetOutputFileName(std::string input_filename) {
if (output_file_name_.empty()) {
return needs_linking_ ? std::string("a.spv")
: GetCandidateOutputFileName(input_filename);
} else {
return output_file_name_.str();
}
}
std::string FileCompiler::GetCandidateOutputFileName(
std::string input_filename) {
if (!output_file_name_.empty() && !PreprocessingOnly()) {
return output_file_name_.str();
}
std::string extension = file_extension_;
if (PreprocessingOnly() || needs_linking_) {
extension = ".spv";
}
std::string candidate_output_file_name =
IsStageFile(input_filename)
? shaderc_util::GetBaseFileName(input_filename) + extension
: shaderc_util::GetBaseFileName(
input_filename.substr(0, input_filename.find_last_of('.')) +
extension);
return candidate_output_file_name;
}
} // namesapce glslc

View File

@@ -0,0 +1,234 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#ifndef GLSLC_FILE_COMPILER_H
#define GLSLC_FILE_COMPILER_H
#include <string>
#include "libshaderc_util/file_finder.h"
#include "libshaderc_util/string_piece.h"
#include "shaderc/shaderc.hpp"
#include "dependency_info.h"
namespace glslc {
// Describes an input file to be compiled.
struct InputFileSpec {
std::string name;
shaderc_shader_kind stage;
shaderc_source_language language;
std::string entry_point_name;
};
// Context for managing compilation of source GLSL files into destination
// SPIR-V files or preprocessed output.
class FileCompiler {
public:
enum class SpirvBinaryEmissionFormat {
Unspecified, // No binary output format specified, this is the only valid
// option when the compilation output is not in SPIR-V binary
// code form.
Binary, // Emits SPIR-V binary code directly.
Numbers, // Emits SPIR-V binary code as a list of hex numbers.
CInitList, // Emits SPIR-V binary code as a C-style initializer list
// of hex numbers.
WGSL, // Emits SPIR-V module converted to WGSL source text.
// Requires a build with Tint support.
};
FileCompiler()
: output_type_(OutputType::SpirvBinary),
binary_emission_format_(SpirvBinaryEmissionFormat::Unspecified),
needs_linking_(true),
total_warnings_(0),
total_errors_(0) {}
// Compiles a shader received as specified by input_file, returning true
// on success and false otherwise. If force_shader_stage is not
// shaderc_glsl_infer_source or any default shader stage then the given
// shader_stage will be used, otherwise it will be determined from the source
// or the file type.
//
// Places the compilation output into a new file whose name is derived from
// input_file according to the rules from glslc/README.asciidoc.
//
// If version/profile has been forced, the shader's version/profile is set to
// that value regardless of the #version directive in the source code.
//
// Any errors/warnings found in the shader source will be output to std::cerr
// and increment the counts reported by OutputMessages().
bool CompileShaderFile(const InputFileSpec& input_file);
// Adds a directory to be searched when processing #include directives.
//
// Best practice: if you add an empty string before any other path, that will
// correctly resolve both absolute paths and paths relative to the current
// working directory.
void AddIncludeDirectory(const std::string& path);
// Sets the output filename. A name of "-" indicates standard output.
void SetOutputFileName(const shaderc_util::string_piece& file) {
output_file_name_ = file;
}
// Sets the format for SPIR-V binary compilation output.
void SetSpirvBinaryOutputFormat(SpirvBinaryEmissionFormat format) {
binary_emission_format_ = format;
}
// Returns false if any options are incompatible. The num_files parameter
// represents the number of files that will be compiled.
bool ValidateOptions(size_t num_files);
// Outputs to std::cerr the number of warnings and errors if there are any.
void OutputMessages();
// Sets the flag to indicate individual compilation mode. In this mode, all
// files are compiled individually and written to separate output files
// instead of linked together. This method also disables linking and sets the
// output file extension to ".spv". Disassembly mode and preprocessing only
// mode override this mode and flags.
void SetIndividualCompilationFlag();
// Sets the flag to indicate disassembly mode. In this mode, the compiler
// emits disassembled textual output, instead of outputting object files.
// This method also sets the output file extension to ".spvasm" and disables
// linking. This mode overrides individual compilation mode, and preprocessing
// only mode overrides this mode.
void SetDisassemblyFlag();
// Sets the flag to indicate preprocessing only mode. In this mode, instead of
// outputting object files, the compiler emits the preprocessed source files.
// This method disables linking and sets the output file to stdout. This mode
// overrides disassembly mode and individual compilation mode.
void SetPreprocessingOnlyFlag();
// Gets the reference of the compiler options which reflects the command-line
// arguments.
shaderc::CompileOptions& options() { return options_; }
// Gets a pointer which points to the dependency info dumping hander. Creates
// such a handler if such one does not exist.
DependencyInfoDumpingHandler* GetDependencyDumpingHandler() {
if (!dependency_info_dumping_handler_) {
dependency_info_dumping_handler_.reset(
new DependencyInfoDumpingHandler());
}
return dependency_info_dumping_handler_.get();
}
private:
enum class OutputType {
SpirvBinary, // A binary module, as defined by the SPIR-V specification.
SpirvAssemblyText, // Assembly syntax defined by the SPIRV-Tools project.
PreprocessedText, // Preprocessed source code.
};
// Emits the compilation output from the given result to the given output
// file and returns true if the result represents a successful compilation
// step. Otherwise returns false, possibly emits messages to the standard
// error stream, and does not produce an output file. Accumulates error
// and warning counts for use by the OutputMessages() method.
template <typename CompilationResultType>
bool EmitCompiledResult(
const CompilationResultType& result, const std::string& input_file_name,
const std::string& output_file_name,
shaderc_util::string_piece error_file_name,
const std::unordered_set<std::string>& used_source_files);
// Returns the final file name to be used for the output file.
//
// If an output file name is specified by the SetOutputFileName(), use that
// argument as the final output file name.
//
// If the user did not specify an output filename:
// If linking is not required, and the input filename has a
// standard stage extension (e.g. .vert) then returns the input filename
// without directory names but with the result extenstion (e.g. .spv or
// .spvasm) appended.
//
// If linking is not required, and the input file name does not have a
// standard stage extension, then also returns the directory-stripped input
// filename, but replaces its extension with the result extension. (If the
// resolved input filename does not have an extension, then appends the
// result extension.)
//
// If linking is required and output filename is not specified, returns
// "a.spv".
std::string GetOutputFileName(std::string input_filename);
// Returns the candidate output file name deduced from input file name and
// user specified output file name. It is computed as follows:
//
// If the user did specify an output filename and the compiler is not in
// preprocessing-only mode, then returns that file name.
//
// If the user did not specify an output filename:
// If the input filename has a standard stage extension (e.g. .vert) then
// returns the input filename without directory names but with the result
// extenstion (e.g. .spv or .spvasm) appended.
//
// If the input file name does not have a standard stage extension, then also
// returns the directory-stripped input filename, but replaces its extension
// with the result extension. (If the resolved input filename does not have
// an extension, then appends the result extension.)
//
// When a resolved extension is not available because the compiler is in
// preprocessing-only mode or the compilation requires linking, use .spv as
// the extension.
std::string GetCandidateOutputFileName(std::string input_filename);
// Returns true if the compiler's output is preprocessed text.
bool PreprocessingOnly() {
return output_type_ == OutputType::PreprocessedText;
}
// Performs actual SPIR-V compilation on the contents of input files.
shaderc::Compiler compiler_;
// Reflects the command-line arguments and goes into
// compiler_.CompileGlslToSpv().
shaderc::CompileOptions options_;
// What kind of output will be produced?
OutputType output_type_;
// The Flag to indicate to which format the output SPIR-V binary code should
// be emitted.
SpirvBinaryEmissionFormat binary_emission_format_;
// A FileFinder used to substitute #include directives in the source code.
shaderc_util::FileFinder include_file_finder_;
// Indicates whether linking is needed to generate the final output.
bool needs_linking_;
// The ownership of dependency dumping handler.
std::unique_ptr<DependencyInfoDumpingHandler>
dependency_info_dumping_handler_ = nullptr;
// Reflects the type of file being generated.
std::string file_extension_;
// Name of the file where the compilation output will go.
shaderc_util::string_piece output_file_name_;
// Counts warnings encountered in all compilations via this object.
size_t total_warnings_;
// Counts errors encountered in all compilations via this object.
size_t total_errors_;
};
} // namespace glslc
#endif // GLSLC_FILE_COMPILER_H

View File

@@ -0,0 +1,66 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#include "file_includer.h"
#include <mutex>
#include <utility>
#include "libshaderc_util/io_shaderc.h"
namespace glslc {
shaderc_include_result* MakeErrorIncludeResult(const char* message) {
return new shaderc_include_result{"", 0, message, strlen(message)};
}
FileIncluder::~FileIncluder() = default;
shaderc_include_result* FileIncluder::GetInclude(
const char* requested_source, shaderc_include_type include_type,
const char* requesting_source, size_t) {
const std::string full_path =
(include_type == shaderc_include_type_relative)
? file_finder_.FindRelativeReadableFilepath(requesting_source,
requested_source)
: file_finder_.FindReadableFilepath(requested_source);
if (full_path.empty())
return MakeErrorIncludeResult("Cannot find or open include file.");
// In principle, several threads could be resolving includes at the same
// time. Protect the included_files.
// Read the file and save its full path and contents into stable addresses.
FileInfo* new_file_info = new FileInfo{full_path, {}};
if (!shaderc_util::ReadFile(full_path, &(new_file_info->contents))) {
return MakeErrorIncludeResult("Cannot read file");
}
included_files_.insert(full_path);
return new shaderc_include_result{
new_file_info->full_path.data(), new_file_info->full_path.length(),
new_file_info->contents.data(), new_file_info->contents.size(),
new_file_info};
}
void FileIncluder::ReleaseInclude(shaderc_include_result* include_result) {
FileInfo* info = static_cast<FileInfo*>(include_result->user_data);
delete info;
delete include_result;
}
} // namespace glslc

View File

@@ -0,0 +1,74 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#ifndef GLSLC_FILE_INCLUDER_H_
#define GLSLC_FILE_INCLUDER_H_
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <unordered_set>
#include "libshaderc_util/file_finder.h"
#include "shaderc/shaderc.hpp"
namespace glslc {
// An includer for files implementing shaderc's includer interface. It responds
// to the file including query from the compiler with the full path and content
// of the file to be included. In the case that the file is not found or cannot
// be opened, the full path field of in the response will point to an empty
// string, and error message will be passed to the content field.
// This class provides the basic thread-safety guarantee.
class FileIncluder : public shaderc::CompileOptions::IncluderInterface {
public:
explicit FileIncluder(const shaderc_util::FileFinder* file_finder)
: file_finder_(*file_finder) {}
~FileIncluder() override;
// Resolves a requested source file of a given type from a requesting
// source into a shaderc_include_result whose contents will remain valid
// until it's released.
shaderc_include_result* GetInclude(const char* requested_source,
shaderc_include_type type,
const char* requesting_source,
size_t include_depth) override;
// Releases an include result.
void ReleaseInclude(shaderc_include_result* include_result) override;
// Returns a reference to the member storing the set of included files.
const std::unordered_set<std::string>& file_path_trace() const {
return included_files_;
}
private:
// Used by GetInclude() to get the full filepath.
const shaderc_util::FileFinder& file_finder_;
// The full path and content of a source file.
struct FileInfo {
const std::string full_path;
std::vector<char> contents;
};
// The set of full paths of included files.
std::unordered_set<std::string> included_files_;
};
} // namespace glslc
#endif // GLSLC_FILE_INCLUDER_H_

96
3rdparty/shaderc/glslc/src/file_test.cc vendored Normal file
View File

@@ -0,0 +1,96 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#include "file.h"
#include <gmock/gmock.h>
namespace {
using glslc::GetFileExtension;
using glslc::IsStageFile;
using glslc::GetGlslOrHlslExtension;
using shaderc_util::string_piece;
using testing::Eq;
class FileExtensionTest : public testing::Test {
protected:
string_piece empty = "";
string_piece dot = ".";
string_piece no_ext = "shader";
string_piece trailing_dot = "shader.";
string_piece vert_ext = "shader.vert";
string_piece frag_ext = "shader.frag";
string_piece tesc_ext = "shader.tesc";
string_piece tese_ext = "shader.tese";
string_piece geom_ext = "shader.geom";
string_piece comp_ext = "shader.comp";
string_piece glsl_ext = "shader.glsl";
string_piece hlsl_ext = "shader.hlsl";
string_piece multi_dot = "shader.some..ext";
string_piece both_hg_ext = "shader.hlsl.glsl";
string_piece both_gh_ext = "shader.glsl.hlsl";
};
TEST_F(FileExtensionTest, GetFileExtension) {
EXPECT_EQ("", GetFileExtension(empty));
EXPECT_EQ("", GetFileExtension(dot));
EXPECT_EQ("", GetFileExtension(no_ext));
EXPECT_EQ("", GetFileExtension(trailing_dot));
EXPECT_EQ("vert", GetFileExtension(vert_ext));
EXPECT_EQ("frag", GetFileExtension(frag_ext));
EXPECT_EQ("tesc", GetFileExtension(tesc_ext));
EXPECT_EQ("tese", GetFileExtension(tese_ext));
EXPECT_EQ("geom", GetFileExtension(geom_ext));
EXPECT_EQ("comp", GetFileExtension(comp_ext));
EXPECT_EQ("glsl", GetFileExtension(glsl_ext));
EXPECT_EQ("ext", GetFileExtension(multi_dot));
EXPECT_EQ("glsl", GetFileExtension(both_hg_ext));
EXPECT_EQ("hlsl", GetFileExtension(both_gh_ext));
}
TEST_F(FileExtensionTest, GetGlslOrHlslExtension) {
EXPECT_THAT(GetGlslOrHlslExtension(empty), Eq(""));
EXPECT_THAT(GetGlslOrHlslExtension(dot), Eq(""));
EXPECT_THAT(GetGlslOrHlslExtension(no_ext), Eq(""));
EXPECT_THAT(GetGlslOrHlslExtension(trailing_dot), Eq(""));
EXPECT_THAT(GetGlslOrHlslExtension(vert_ext), Eq(""));
EXPECT_THAT(GetGlslOrHlslExtension(frag_ext), Eq(""));
EXPECT_THAT(GetGlslOrHlslExtension(tesc_ext), Eq(""));
EXPECT_THAT(GetGlslOrHlslExtension(tese_ext), Eq(""));
EXPECT_THAT(GetGlslOrHlslExtension(geom_ext), Eq(""));
EXPECT_THAT(GetGlslOrHlslExtension(comp_ext), Eq(""));
EXPECT_THAT(GetGlslOrHlslExtension(glsl_ext), Eq("glsl"));
EXPECT_THAT(GetGlslOrHlslExtension(hlsl_ext), Eq("hlsl"));
EXPECT_THAT(GetGlslOrHlslExtension(multi_dot), Eq(""));
EXPECT_THAT(GetGlslOrHlslExtension(both_hg_ext), Eq("glsl"));
EXPECT_THAT(GetGlslOrHlslExtension(both_gh_ext), Eq("hlsl"));
}
TEST_F(FileExtensionTest, IsStageFile) {
EXPECT_FALSE(IsStageFile(empty));
EXPECT_FALSE(IsStageFile(dot));
EXPECT_FALSE(IsStageFile(no_ext));
EXPECT_FALSE(IsStageFile(trailing_dot));
EXPECT_TRUE(IsStageFile(vert_ext));
EXPECT_TRUE(IsStageFile(frag_ext));
EXPECT_TRUE(IsStageFile(tesc_ext));
EXPECT_TRUE(IsStageFile(tese_ext));
EXPECT_TRUE(IsStageFile(geom_ext));
EXPECT_TRUE(IsStageFile(comp_ext));
EXPECT_FALSE(IsStageFile(glsl_ext));
EXPECT_FALSE(IsStageFile(multi_dot));
}
} // anonymous namespace

695
3rdparty/shaderc/glslc/src/main.cc vendored Normal file
View File

@@ -0,0 +1,695 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#include <cassert>
#include <cctype>
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <list>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include "file.h"
#include "file_compiler.h"
#include "libshaderc_util/args.h"
#include "libshaderc_util/compiler.h"
#include "libshaderc_util/io_shaderc.h"
#include "libshaderc_util/string_piece.h"
#include "resource_parse.h"
#include "shader_stage.h"
#include "shaderc/env.h"
#include "shaderc/shaderc.h"
#include "spirv-tools/libspirv.h"
using shaderc_util::string_piece;
namespace {
// Prints the help message.
void PrintHelp(std::ostream* out) {
*out << R"(glslc - Compile shaders into SPIR-V
Usage: glslc [options] file...
An input file of - represents standard input.
Options:
-c Only run preprocess, compile, and assemble steps.
-Dmacro[=defn] Add an implicit macro definition.
-E Outputs only the results of the preprocessing step.
Output defaults to standard output.
-fauto-bind-uniforms
Automatically assign bindings to uniform variables that
don't have an explicit 'binding' layout in the shader
source.
-fauto-map-locations
Automatically assign locations to uniform variables that
don't have an explicit 'location' layout in the shader
source.
-fauto-combined-image-sampler
Removes sampler variables and converts existing textures
to combined image-samplers.
-fentry-point=<name>
Specify the entry point name for HLSL compilation, for
all subsequent source files. Default is "main".
-fhlsl-16bit-types
Enable 16-bit type support for HLSL.
-fhlsl_functionality1, -fhlsl-functionality1
Enable extension SPV_GOOGLE_hlsl_functionality1 for HLSL
compilation.
-fhlsl-iomap Use HLSL IO mappings for bindings.
-fhlsl-offsets Use HLSL offset rules for packing members of blocks.
Affects only GLSL. HLSL rules are always used for HLSL.
-finvert-y Invert position.Y output in vertex shader.
-flimit=<settings>
Specify resource limits. Each limit is specified by a limit
name followed by an integer value. Tokens should be
separated by whitespace. If the same limit is specified
several times, only the last setting takes effect.
-flimit-file <file>
Set limits as specified in the given file.
-fnan-clamp Generate code for max and min builtins so that, when given
a NaN operand, the other operand is returned. Similarly,
the clamp builtin will favour the non-NaN operands, as if
clamp were implemented as a composition of max and min.
-fpreserve-bindings
Preserve all binding declarations, even if those bindings
are not used.
-fresource-set-binding [stage] <reg0> <set0> <binding0>
[<reg1> <set1> <binding1>...]
Explicitly sets the descriptor set and binding for
HLSL resources, by register name. Optionally restrict
it to a single stage.
-fcbuffer-binding-base [stage] <value>
Same as -fubo-binding-base.
-fimage-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
images. Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fsampler-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
samplers Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fssbo-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
shader storage buffer objects (SSBO). Optionally only set
it for a single shader stage. Only affects GLSL.
-ftexture-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
textures. Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fuav-binding-base [stage] <value>
For automatically assigned bindings for unordered access
views (UAV), the register number is added to this base to
determine the binding number. Optionally only set it for
a single shader stage. Only affects HLSL.
-fubo-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
uniform buffer objects (UBO). Optionally only set it for
a single shader stage.
For HLSL, the resource register number is added to this
base.
-fshader-stage=<stage>
Treat subsequent input files as having stage <stage>.
Valid stages are vertex, vert, fragment, frag, tesscontrol,
tesc, tesseval, tese, geometry, geom, compute, and comp.
-g Generate source-level debug information.
-h Display available options.
--help Display available options.
-I <value> Add directory to include search path.
-mfmt=<format> Output SPIR-V binary code using the selected format. This
option may be specified only when the compilation output is
in SPIR-V binary code form. Available options are:
bin - SPIR-V binary words. This is the default.
c - Binary words as C initializer list of 32-bit ints
num - List of comma-separated 32-bit hex integers
-M Generate make dependencies. Implies -E and -w.
-MM An alias for -M.
-MD Generate make dependencies and compile.
-MF <file> Write dependency output to the given file.
-MT <target> Specify the target of the rule emitted by dependency
generation.
-O Optimize the generated SPIR-V code for better performance.
-Os Optimize the generated SPIR-V code for smaller size.
-O0 Disable optimization.
-o <file> Write output to <file>.
A file name of '-' represents standard output.
-std=<value> Version and profile for GLSL input files. Possible values
are concatenations of version and profile, e.g. 310es,
450core, etc. Ignored for HLSL files.
-S Emit SPIR-V assembly instead of binary.
--show-limits Display available limit names and their default values.
--target-env=<environment>
Set the target client environment, and the semantics
of warnings and errors. An optional suffix can specify
the client version. Values are:
vulkan1.0 # The default
vulkan1.1
vulkan1.2
vulkan1.3
vulkan # Same as vulkan1.0
opengl4.5
opengl # Same as opengl4.5
--target-spv=<spirv-version>
Set the SPIR-V version to be used for the generated SPIR-V
module. The default is the highest version of SPIR-V
required to be supported for the target environment.
For example, default for vulkan1.0 is spv1.0, and
the default for vulkan1.1 is spv1.3,
the default for vulkan1.2 is spv1.5.
the default for vulkan1.3 is spv1.6.
Values are:
spv1.0, spv1.1, spv1.2, spv1.3, spv1.4, spv1.5, spv1.6
--version Display compiler version information.
-w Suppresses all warning messages.
-Werror Treat all warnings as errors.
-x <language> Treat subsequent input files as having type <language>.
Valid languages are: glsl, hlsl.
For files ending in .hlsl the default is hlsl.
Otherwise the default is glsl.
)";
}
// Sets resource limits according to the given string. The string
// should be formated as required for ParseResourceSettings.
// Returns true on success. Otherwise returns false and sets err
// to a descriptive error message.
bool SetResourceLimits(const std::string& str, shaderc::CompileOptions* options,
std::string* err) {
std::vector<glslc::ResourceSetting> settings;
if (!ParseResourceSettings(str, &settings, err)) {
return false;
}
for (const auto& setting : settings) {
options->SetLimit(setting.limit, setting.value);
}
return true;
}
const char kBuildVersion[] =
#include "build-version.inc"
;
// Gets an optional stage name followed by required offset argument. Returns
// false and emits a message to *errs if any errors occur. After calling this
// function, *index will be the index of the last command line argument
// consumed. If no stage name is provided, then *stage contains
// shaderc_glsl_infer_from_source.
bool GetOptionalStageThenOffsetArgument(const shaderc_util::string_piece option,
std::ostream* errs, int argc,
char** argv, int* index,
shaderc_shader_kind* shader_kind,
uint32_t* offset) {
int& argi = *index;
if (argi + 1 >= argc) {
*errs << "glslc: error: Option " << option
<< " requires at least one argument" << std::endl;
return false;
}
auto stage = glslc::MapStageNameToForcedKind(argv[argi + 1]);
if (stage != shaderc_glsl_infer_from_source) {
++argi;
if (argi + 1 >= argc) {
*errs << "glslc: error: Option " << option << " with stage "
<< argv[argi - 1] << " requires an offset argument" << std::endl;
return false;
}
}
if (!shaderc_util::ParseUint32(argv[argi + 1], offset)) {
*errs << "glslc: error: invalid offset value " << argv[argi + 1] << " for "
<< option << std::endl;
return false;
}
++argi;
*shader_kind = stage;
return true;
}
} // anonymous namespace
int main(int argc, char** argv) {
std::vector<glslc::InputFileSpec> input_files;
shaderc_shader_kind current_fshader_stage = shaderc_glsl_infer_from_source;
bool source_language_forced = false;
shaderc_source_language current_source_language =
shaderc_source_language_glsl;
std::string current_entry_point_name("main");
glslc::FileCompiler compiler;
bool success = true;
bool has_stdin_input = false;
// Shader stage for a single option.
shaderc_shader_kind arg_stage = shaderc_glsl_infer_from_source;
// Binding base for a single option.
uint32_t arg_base = 0;
// What kind of uniform variable are we setting the binding base for?
shaderc_uniform_kind u_kind = shaderc_uniform_kind_buffer;
// Sets binding base for the given uniform kind. If stage is
// shader_glsl_infer_from_source then set it for all shader stages.
auto set_binding_base = [&compiler](
shaderc_shader_kind stage, shaderc_uniform_kind kind, uint32_t base) {
if (stage == shaderc_glsl_infer_from_source)
compiler.options().SetBindingBase(kind, base);
else
compiler.options().SetBindingBaseForStage(stage, kind, base);
};
for (int i = 1; i < argc; ++i) {
const string_piece arg = argv[i];
if (arg == "--help" || arg == "-h") {
::PrintHelp(&std::cout);
return 0;
} else if (arg == "--show-limits") {
shaderc_util::Compiler default_compiler;
// The static cast here depends on us keeping the shaderc_limit enum in
// lockstep with the shaderc_util::Compiler::Limit enum. The risk of mismatch
// is low since both are generated from the same resources.inc file.
#define RESOURCE(NAME, FIELD, ENUM) \
std::cout << #NAME << " " \
<< default_compiler.GetLimit( \
static_cast<shaderc_util::Compiler::Limit>( \
shaderc_limit_##ENUM)) \
<< std::endl;
#include "libshaderc_util/resources.inc"
#undef RESOURCE
return 0;
} else if (arg == "--version") {
std::cout << kBuildVersion << std::endl;
std::cout << "Target: " << spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0)
<< std::endl;
return 0;
} else if (arg.starts_with("-o")) {
string_piece file_name;
if (!shaderc_util::GetOptionArgument(argc, argv, &i, "-o", &file_name)) {
std::cerr
<< "glslc: error: argument to '-o' is missing (expected 1 value)"
<< std::endl;
return 1;
}
compiler.SetOutputFileName(file_name);
} else if (arg.starts_with("-fshader-stage=")) {
const string_piece stage = arg.substr(std::strlen("-fshader-stage="));
current_fshader_stage = glslc::GetForcedShaderKindFromCmdLine(arg);
if (current_fshader_stage == shaderc_glsl_infer_from_source) {
std::cerr << "glslc: error: stage not recognized: '" << stage << "'"
<< std::endl;
return 1;
}
} else if (arg == "-fauto-bind-uniforms") {
compiler.options().SetAutoBindUniforms(true);
} else if (arg == "-fauto-combined-image-sampler") {
compiler.options().SetAutoSampledTextures(true);
} else if (arg == "-fauto-map-locations") {
compiler.options().SetAutoMapLocations(true);
} else if (arg == "-fhlsl-iomap") {
compiler.options().SetHlslIoMapping(true);
} else if (arg == "-fhlsl-offsets") {
compiler.options().SetHlslOffsets(true);
} else if (arg == "-fhlsl_functionality1" ||
arg == "-fhlsl-functionality1") {
compiler.options().SetHlslFunctionality1(true);
} else if (arg == "-fhlsl-16bit-types") {
compiler.options().SetHlsl16BitTypes(true);
} else if (arg == "-finvert-y") {
compiler.options().SetInvertY(true);
} else if (arg == "-fnan-clamp") {
compiler.options().SetNanClamp(true);
} else if (arg.starts_with("-fpreserve-bindings")) {
compiler.options().SetPreserveBindings(true);
} else if (((u_kind = shaderc_uniform_kind_image),
(arg == "-fimage-binding-base")) ||
((u_kind = shaderc_uniform_kind_texture),
(arg == "-ftexture-binding-base")) ||
((u_kind = shaderc_uniform_kind_sampler),
(arg == "-fsampler-binding-base")) ||
((u_kind = shaderc_uniform_kind_buffer),
(arg == "-fubo-binding-base")) ||
((u_kind = shaderc_uniform_kind_buffer),
(arg == "-fcbuffer-binding-base")) ||
((u_kind = shaderc_uniform_kind_storage_buffer),
(arg == "-fssbo-binding-base")) ||
((u_kind = shaderc_uniform_kind_unordered_access_view),
(arg == "-fuav-binding-base"))) {
if (!GetOptionalStageThenOffsetArgument(arg, &std::cerr, argc, argv, &i,
&arg_stage, &arg_base))
return 1;
set_binding_base(arg_stage, u_kind, arg_base);
} else if (arg == "-fresource-set-binding") {
auto need_three_args_err = []() {
std::cerr << "glsc: error: Option -fresource-set-binding"
<< " requires at least 3 arguments" << std::endl;
return 1;
};
if (i + 1 >= argc) return need_three_args_err();
auto stage = glslc::MapStageNameToForcedKind(argv[i + 1]);
if (stage != shaderc_glsl_infer_from_source) {
++i;
}
bool seen_triple = false;
while (i + 3 < argc && argv[i + 1][0] != '-' && argv[i + 2][0] != '-' &&
argv[i + 3][0] != '-') {
seen_triple = true;
uint32_t set = 0;
if (!shaderc_util::ParseUint32(argv[i + 2], &set)) {
std::cerr << "glslc: error: Invalid set number: " << argv[i + 2]
<< std::endl;
return 1;
}
uint32_t binding = 0;
if (!shaderc_util::ParseUint32(argv[i + 3], &binding)) {
std::cerr << "glslc: error: Invalid binding number: " << argv[i + 3]
<< std::endl;
return 1;
}
if (stage == shaderc_glsl_infer_from_source) {
compiler.options().SetHlslRegisterSetAndBinding(
argv[i + 1], argv[i + 2], argv[i + 3]);
} else {
compiler.options().SetHlslRegisterSetAndBindingForStage(
stage, argv[i + 1], argv[i + 2], argv[i + 3]);
}
i += 3;
}
if (!seen_triple) return need_three_args_err();
} else if (arg.starts_with("-fentry-point=")) {
current_entry_point_name =
arg.substr(std::strlen("-fentry-point=")).str();
} else if (arg.starts_with("-flimit=")) {
std::string err;
if (!SetResourceLimits(arg.substr(std::strlen("-flimit=")).str(),
&compiler.options(), &err)) {
std::cerr << "glslc: error: -flimit error: " << err << std::endl;
return 1;
}
} else if (arg.starts_with("-flimit-file")) {
std::string err;
string_piece limits_file;
if (!shaderc_util::GetOptionArgument(argc, argv, &i, "-flimit-file",
&limits_file)) {
std::cerr << "glslc: error: argument to '-flimit-file' is missing"
<< std::endl;
return 1;
}
std::vector<char> contents;
if (!shaderc_util::ReadFile(limits_file.str(), &contents)) {
std::cerr << "glslc: cannot read limits file: " << limits_file
<< std::endl;
return 1;
}
if (!SetResourceLimits(
string_piece(contents.data(), contents.data() + contents.size())
.str(),
&compiler.options(), &err)) {
std::cerr << "glslc: error: -flimit-file error: " << err << std::endl;
return 1;
}
} else if (arg.starts_with("-std=")) {
const string_piece standard = arg.substr(std::strlen("-std="));
int version;
shaderc_profile profile;
if (!shaderc_parse_version_profile(standard.begin(), &version,
&profile)) {
std::cerr << "glslc: error: invalid value '" << standard
<< "' in '-std=" << standard << "'" << std::endl;
return 1;
}
compiler.options().SetForcedVersionProfile(version, profile);
} else if (arg.starts_with("--target-env=")) {
shaderc_target_env target_env = shaderc_target_env_default;
const string_piece target_env_str =
arg.substr(std::strlen("--target-env="));
uint32_t version = 0; // Will default appropriately.
if (target_env_str == "vulkan") {
target_env = shaderc_target_env_vulkan;
} else if (target_env_str == "vulkan1.0") {
target_env = shaderc_target_env_vulkan;
version = shaderc_env_version_vulkan_1_0;
} else if (target_env_str == "vulkan1.1") {
target_env = shaderc_target_env_vulkan;
version = shaderc_env_version_vulkan_1_1;
} else if (target_env_str == "vulkan1.2") {
target_env = shaderc_target_env_vulkan;
version = shaderc_env_version_vulkan_1_2;
} else if (target_env_str == "vulkan1.3") {
target_env = shaderc_target_env_vulkan;
version = shaderc_env_version_vulkan_1_3;
} else if (target_env_str == "opengl") {
target_env = shaderc_target_env_opengl;
} else if (target_env_str == "opengl4.5") {
target_env = shaderc_target_env_opengl;
version = shaderc_env_version_opengl_4_5;
} else if (target_env_str == "opengl_compat") {
target_env = shaderc_target_env_opengl_compat;
std::cerr << "glslc: error: opengl_compat is no longer supported"
<< std::endl;
return 1;
} else {
std::cerr << "glslc: error: invalid value '" << target_env_str
<< "' in '--target-env=" << target_env_str << "'"
<< std::endl;
return 1;
}
compiler.options().SetTargetEnvironment(target_env, version);
} else if (arg.starts_with("--target-spv=")) {
shaderc_spirv_version ver = shaderc_spirv_version_1_0;
const string_piece ver_str = arg.substr(std::strlen("--target-spv="));
if (ver_str == "spv1.0") {
ver = shaderc_spirv_version_1_0;
} else if (ver_str == "spv1.1") {
ver = shaderc_spirv_version_1_1;
} else if (ver_str == "spv1.2") {
ver = shaderc_spirv_version_1_2;
} else if (ver_str == "spv1.3") {
ver = shaderc_spirv_version_1_3;
} else if (ver_str == "spv1.4") {
ver = shaderc_spirv_version_1_4;
} else if (ver_str == "spv1.5") {
ver = shaderc_spirv_version_1_5;
} else if (ver_str == "spv1.6") {
ver = shaderc_spirv_version_1_6;
} else {
std::cerr << "glslc: error: invalid value '" << ver_str
<< "' in '--target-spv=" << ver_str << "'" << std::endl;
return 1;
}
compiler.options().SetTargetSpirv(ver);
} else if (arg.starts_with("-mfmt=")) {
const string_piece binary_output_format =
arg.substr(std::strlen("-mfmt="));
if (binary_output_format == "bin") {
compiler.SetSpirvBinaryOutputFormat(
glslc::FileCompiler::SpirvBinaryEmissionFormat::Binary);
} else if (binary_output_format == "num") {
compiler.SetSpirvBinaryOutputFormat(
glslc::FileCompiler::SpirvBinaryEmissionFormat::Numbers);
} else if (binary_output_format == "c") {
compiler.SetSpirvBinaryOutputFormat(
glslc::FileCompiler::SpirvBinaryEmissionFormat::CInitList);
} else if (binary_output_format == "wgsl") {
compiler.SetSpirvBinaryOutputFormat(
glslc::FileCompiler::SpirvBinaryEmissionFormat::WGSL);
} else {
std::cerr << "glslc: error: invalid value '" << binary_output_format
<< "' in '-mfmt=" << binary_output_format << "'" << std::endl;
return 1;
}
} else if (arg.starts_with("-x")) {
string_piece option_arg;
if (!shaderc_util::GetOptionArgument(argc, argv, &i, "-x", &option_arg)) {
std::cerr
<< "glslc: error: argument to '-x' is missing (expected 1 value)"
<< std::endl;
success = false;
} else {
if (option_arg == "glsl") {
current_source_language = shaderc_source_language_glsl;
} else if (option_arg == "hlsl") {
current_source_language = shaderc_source_language_hlsl;
} else {
std::cerr << "glslc: error: language not recognized: '" << option_arg
<< "'" << std::endl;
return 1;
}
source_language_forced = true;
}
} else if (arg == "-c") {
compiler.SetIndividualCompilationFlag();
} else if (arg == "-E") {
compiler.SetPreprocessingOnlyFlag();
} else if (arg == "-M" || arg == "-MM") {
// -M implies -E and -w
compiler.SetPreprocessingOnlyFlag();
compiler.options().SetSuppressWarnings();
if (compiler.GetDependencyDumpingHandler()->DumpingModeNotSet()) {
compiler.GetDependencyDumpingHandler()
->SetDumpAsNormalCompilationOutput();
} else {
std::cerr << "glslc: error: both -M (or -MM) and -MD are specified. "
"Only one should be used at one time."
<< std::endl;
return 1;
}
} else if (arg == "-MD") {
if (compiler.GetDependencyDumpingHandler()->DumpingModeNotSet()) {
compiler.GetDependencyDumpingHandler()
->SetDumpToExtraDependencyInfoFiles();
} else {
std::cerr << "glslc: error: both -M (or -MM) and -MD are specified. "
"Only one should be used at one time."
<< std::endl;
return 1;
}
} else if (arg == "-MF") {
string_piece dep_file_name;
if (!shaderc_util::GetOptionArgument(argc, argv, &i, "-MF",
&dep_file_name)) {
std::cerr
<< "glslc: error: missing dependency info filename after '-MF'"
<< std::endl;
return 1;
}
compiler.GetDependencyDumpingHandler()->SetDependencyFileName(
std::string(dep_file_name.data(), dep_file_name.size()));
} else if (arg == "-MT") {
string_piece dep_file_name;
if (!shaderc_util::GetOptionArgument(argc, argv, &i, "-MT",
&dep_file_name)) {
std::cerr << "glslc: error: missing dependency info target after '-MT'"
<< std::endl;
return 1;
}
compiler.GetDependencyDumpingHandler()->SetTarget(
std::string(dep_file_name.data(), dep_file_name.size()));
} else if (arg == "-S") {
compiler.SetDisassemblyFlag();
} else if (arg.starts_with("-D")) {
const size_t length = arg.size();
if (length <= 2) {
std::cerr << "glslc: error: argument to '-D' is missing" << std::endl;
} else {
const string_piece argument = arg.substr(2);
// Get the exact length of the macro string.
size_t equal_sign_loc = argument.find_first_of('=');
size_t name_length = equal_sign_loc != shaderc_util::string_piece::npos
? equal_sign_loc
: argument.size();
const string_piece name_piece = argument.substr(0, name_length);
if (name_piece.starts_with("GL_")) {
std::cerr
<< "glslc: error: names beginning with 'GL_' cannot be defined: "
<< arg << std::endl;
return 1;
}
if (name_piece.find("__") != string_piece::npos) {
std::cerr
<< "glslc: warning: names containing consecutive underscores "
"are reserved: "
<< arg << std::endl;
}
const string_piece value_piece =
(equal_sign_loc == string_piece::npos ||
equal_sign_loc == argument.size() - 1)
? ""
: argument.substr(name_length + 1);
// TODO(deki): check arg for newlines.
compiler.options().AddMacroDefinition(
name_piece.data(), name_piece.size(), value_piece.data(),
value_piece.size());
}
} else if (arg.starts_with("-I")) {
string_piece option_arg;
if (!shaderc_util::GetOptionArgument(argc, argv, &i, "-I", &option_arg)) {
std::cerr
<< "glslc: error: argument to '-I' is missing (expected 1 value)"
<< std::endl;
success = false;
} else {
compiler.AddIncludeDirectory(option_arg.str());
}
} else if (arg == "-g") {
compiler.options().SetGenerateDebugInfo();
} else if (arg.starts_with("-O")) {
if (arg == "-O") {
compiler.options().SetOptimizationLevel(
shaderc_optimization_level_performance);
} else if (arg == "-Os") {
compiler.options().SetOptimizationLevel(
shaderc_optimization_level_size);
} else if (arg == "-O0") {
compiler.options().SetOptimizationLevel(
shaderc_optimization_level_zero);
} else {
std::cerr << "glslc: error: invalid value '"
<< arg.substr(std::strlen("-O")) << "' in '" << arg << "'"
<< std::endl;
return 1;
}
} else if (arg == "-w") {
compiler.options().SetSuppressWarnings();
} else if (arg == "-Werror") {
compiler.options().SetWarningsAsErrors();
} else if (!(arg == "-") && arg[0] == '-') {
std::cerr << "glslc: error: "
<< (arg[1] == '-' ? "unsupported option" : "unknown argument")
<< ": '" << arg << "'" << std::endl;
return 1;
} else {
if (arg == "-") {
if (has_stdin_input) {
std::cerr << "glslc: error: specifying standard input \"-\" as input "
<< "more than once is not allowed." << std::endl;
return 1;
}
has_stdin_input = true;
}
const auto language = source_language_forced
? current_source_language
: ((glslc::GetFileExtension(arg) == "hlsl")
? shaderc_source_language_hlsl
: shaderc_source_language_glsl);
// If current_fshader_stage is shaderc_glsl_infer_from_source, that means
// we didn't set forced shader kinds (otherwise an error should have
// already been emitted before). So we should deduce the shader kind
// from the file name. If current_fshader_stage is specifed to one of
// the forced shader kinds, use that for the following compilation.
input_files.emplace_back(glslc::InputFileSpec{
arg.str(), (current_fshader_stage == shaderc_glsl_infer_from_source
? glslc::DeduceDefaultShaderKindFromFileName(arg)
: current_fshader_stage),
language, current_entry_point_name});
}
}
if (!compiler.ValidateOptions(input_files.size())) return 1;
if (!success) return 1;
for (const auto& input_file : input_files) {
success &= compiler.CompileShaderFile(input_file);
}
compiler.OutputMessages();
return success ? 0 : 1;
}

View File

@@ -0,0 +1,97 @@
// Copyright 2016 The Shaderc Authors. All rights reserved.
//
// 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.
#include "resource_parse.h"
#include <algorithm>
#include <cstring>
#include <iterator>
#include <sstream>
#include <vector>
namespace {
// Converts a limit string to a limit enum. Returns true on successful
// conversion.
bool StringToLimit(const std::string& str, shaderc_limit* limit) {
const char* cstr = str.c_str();
#define RESOURCE(NAME, FIELD, ENUM) \
if (0 == std::strcmp(#NAME, cstr)) { \
*limit = shaderc_limit_##ENUM; \
return true; \
}
#include "libshaderc_util/resources.inc"
#undef RESOURCE
return false;
}
// Returns true if we should ignore the setting.
bool IgnoreSetting(const std::string& str) {
const std::string ignore_list[] = {
"nonInductiveForLoops",
"whileLoops",
"doWhileLoops",
"generalUniformIndexing",
"generalAttributeMatrixVectorIndexing",
"generalVaryingIndexing",
"generalSamplerIndexing",
"generalVariableIndexing",
"generalConstantMatrixVectorIndexing",
};
return std::find(std::begin(ignore_list), std::end(ignore_list), str) !=
std::end(ignore_list);
}
} // anonymous namespace
namespace glslc {
bool ParseResourceSettings(const std::string& input,
std::vector<ResourceSetting>* limits,
std::string* err) {
auto failure = [err, limits](std::string msg) {
*err = msg;
limits->clear();
return false;
};
std::istringstream input_stream(input);
std::istream_iterator<std::string> pos((input_stream));
limits->clear();
while (pos != std::istream_iterator<std::string>()) {
const std::string limit_name = *pos++;
shaderc_limit limit = static_cast<shaderc_limit>(0);
bool ignore = IgnoreSetting(limit_name);
if (!ignore) {
if (!StringToLimit(limit_name, &limit))
return failure(std::string("invalid resource limit: " + limit_name));
}
if (pos == std::istream_iterator<std::string>())
return failure(std::string("missing value after limit: ") + limit_name);
const std::string value_str = *pos;
int value;
std::istringstream value_stream(value_str);
value_stream >> value;
if (value_stream.bad() || !value_stream.eof() || value_stream.fail())
return failure(std::string("invalid integer: ") + value_str);
if (!ignore) limits->push_back({limit, value});
++pos;
}
return true;
}
} // anonymous namespace

View File

@@ -0,0 +1,60 @@
// Copyright 2016 The Shaderc Authors. All rights reserved.
//
// 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.
#ifndef GLSLC_RESOURCE_PARSE_H
#define GLSLC_RESOURCE_PARSE_H
#include <string>
#include <vector>
#include "shaderc/shaderc.h"
namespace glslc {
// A resource limit setting.
struct ResourceSetting {
shaderc_limit limit;
int value;
};
// Returns true when two resource setting structures are equal.
inline bool operator==(const ResourceSetting& lhs, const ResourceSetting& rhs) {
return (lhs.limit == rhs.limit) && (lhs.value == rhs.value);
}
// Parses a resource limit setting string. On success, returns true and populates
// the limits parameter. On failure returns failure and emits a message to err.
// The setting string should be a seqeuence of pairs, where each pair
// is a limit name followed by a decimal integer. Tokens should be separated
// by whitespace. In particular, this function accepts Glslang's configuration
// file syntax. If a limit is mentioned multiple times, then the last setting
// takes effect. Ignore settings for:
// nonInductiveForLoops
// whileLoops
// doWhileLoops
// generalUniformIndexing
// generalAttributeMatrixVectorIndexing
// generalVaryingIndexing
// generalSamplerIndexing
// generalVariableIndexing
// generalConstantMatrixVectorIndexing
bool ParseResourceSettings(const std::string& input,
std::vector<ResourceSetting>* limits,
std::string* err);
} // namespace glslc
#endif // GLSLC_FILE_H_

View File

@@ -0,0 +1,75 @@
// Copyright 2017 The Shaderc Authors. All rights reserved.
//
// 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.
#include "resource_parse.h"
#include <gmock/gmock.h>
namespace {
using glslc::ParseResourceSettings;
using glslc::ResourceSetting;
using testing::Eq;
struct ResourceSettingsCase {
std::string input;
bool success;
std::vector<ResourceSetting> settings;
std::string message;
};
using ParseResourceSettingsTest = ::testing::TestWithParam<ResourceSettingsCase>;
TEST_P(ParseResourceSettingsTest, Sample) {
std::vector<ResourceSetting> settings;
std::string err;
const bool succeeded = ParseResourceSettings(GetParam().input, &settings, &err);
EXPECT_THAT(succeeded, Eq(GetParam().success));
EXPECT_THAT(settings, Eq(GetParam().settings));
EXPECT_THAT(err, Eq(GetParam().message));
}
INSTANTIATE_TEST_SUITE_P(ParseResources, ParseResourceSettingsTest,
::testing::ValuesIn(std::vector<ResourceSettingsCase>{
{"", true, {}, ""},
{" \t \t \n ", true, {}, ""},
{" blorp blam", false, {}, "invalid resource limit: blorp"},
{"MaxLightsxyz", false, {}, "invalid resource limit: MaxLightsxyz"},
{"MaxLights", false, {}, "missing value after limit: MaxLights"},
{"MaxLights x", false, {}, "invalid integer: x"},
{"MaxLights 99x", false, {}, "invalid integer: 99x"},
{"MaxLights 12 blam", false, {}, "invalid resource limit: blam"},
{"MaxLights 12", true, {{shaderc_limit_max_lights, 12}}, ""},
// Test negative number
{"MinProgramTexelOffset -9", true, {{shaderc_limit_min_program_texel_offset, -9}}, ""},
// Test leading, intervening, and trailing whitespace
{" \tMaxLights \n 12 \t ", true, {{shaderc_limit_max_lights, 12}}, ""},
// Test more than one limit setting.
{"MinProgramTexelOffset -10 MaxLights 4", true, {{shaderc_limit_min_program_texel_offset, -10}, {shaderc_limit_max_lights, 4}}, ""},
// Check ignore cases.
{"nonInductiveForLoops", false, {}, "missing value after limit: nonInductiveForLoops"},
{"nonInductiveForLoops 1", true, {}, ""},
{"whileLoops 1", true, {}, ""},
{"doWhileLoops 1", true, {}, ""},
{"generalUniformIndexing 1", true, {}, ""},
{"generalAttributeMatrixVectorIndexing 1", true, {}, ""},
{"generalVaryingIndexing 1", true, {}, ""},
{"generalSamplerIndexing 1", true, {}, ""},
{"generalVariableIndexing 1", true, {}, ""},
{"generalConstantMatrixVectorIndexing 1", true, {}, ""},
// Check an ignore case with a regular case
{"whileLoops 1 MaxLights 99", true, {{shaderc_limit_max_lights, 99}}, ""},
}));
} // anonymous namespace

View File

@@ -0,0 +1,100 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#include "shader_stage.h"
#include "file.h"
using shaderc_util::string_piece;
namespace {
// Maps an identifier to a shader stage.
struct StageMapping {
const char* id;
shaderc_shader_kind stage;
};
} // anonymous namespace
namespace glslc {
shaderc_shader_kind MapStageNameToForcedKind(const string_piece& stage_name) {
const StageMapping string_to_kind[] = {
{"vertex", shaderc_glsl_vertex_shader},
{"vert", shaderc_glsl_vertex_shader},
{"fragment", shaderc_glsl_fragment_shader},
{"frag", shaderc_glsl_fragment_shader},
{"tesscontrol", shaderc_glsl_tess_control_shader},
{"tesc", shaderc_glsl_tess_control_shader},
{"tesseval", shaderc_glsl_tess_evaluation_shader},
{"tese", shaderc_glsl_tess_evaluation_shader},
{"geometry", shaderc_glsl_geometry_shader},
{"geom", shaderc_glsl_geometry_shader},
{"compute", shaderc_glsl_compute_shader},
{"comp", shaderc_glsl_compute_shader},
{"rgen", shaderc_glsl_raygen_shader },
{"rahit", shaderc_glsl_anyhit_shader },
{"rchit", shaderc_glsl_closesthit_shader },
{"rmiss", shaderc_glsl_miss_shader },
{"rint", shaderc_glsl_intersection_shader },
{"rcall", shaderc_glsl_callable_shader },
{"task", shaderc_glsl_task_shader },
{"mesh", shaderc_glsl_mesh_shader },
};
for (const auto& entry : string_to_kind) {
if (stage_name == entry.id) return entry.stage;
}
return shaderc_glsl_infer_from_source;
}
shaderc_shader_kind GetForcedShaderKindFromCmdLine(
const shaderc_util::string_piece& f_shader_stage_str) {
size_t equal_pos = f_shader_stage_str.find_first_of("=");
if (equal_pos == std::string::npos) return shaderc_glsl_infer_from_source;
return MapStageNameToForcedKind(f_shader_stage_str.substr(equal_pos + 1));
}
shaderc_shader_kind DeduceDefaultShaderKindFromFileName(
const string_piece file_name) {
// Add new stage types here.
static const StageMapping kStringToStage[] = {
{"vert", shaderc_glsl_default_vertex_shader},
{"frag", shaderc_glsl_default_fragment_shader},
{"tesc", shaderc_glsl_default_tess_control_shader},
{"tese", shaderc_glsl_default_tess_evaluation_shader},
{"geom", shaderc_glsl_default_geometry_shader},
{"comp", shaderc_glsl_default_compute_shader},
{"spvasm", shaderc_spirv_assembly},
{"rgen", shaderc_glsl_default_raygen_shader },
{"rahit", shaderc_glsl_default_anyhit_shader },
{"rchit", shaderc_glsl_default_closesthit_shader },
{"rmiss", shaderc_glsl_default_miss_shader },
{"rint", shaderc_glsl_default_intersection_shader },
{"rcall", shaderc_glsl_default_callable_shader },
{"task", shaderc_glsl_default_task_shader },
{"mesh", shaderc_glsl_default_mesh_shader },
};
const string_piece extension = glslc::GetFileExtension(file_name);
shaderc_shader_kind stage = shaderc_glsl_infer_from_source;
for (const auto& entry : kStringToStage) {
if (extension == entry.id) stage = entry.stage;
}
return stage;
}
} // namespace glslc

View File

@@ -0,0 +1,42 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
#ifndef GLSLC_SHADER_STAGE_H_
#define GLSLC_SHADER_STAGE_H_
#include <ostream>
#include "libshaderc_util/string_piece.h"
#include "shaderc/shaderc.h"
namespace glslc {
// Maps a shader stage name to a forced shader stage enum value. Returns
// 'shaderc_glsl_infer_from_source' if the stage name is unrecognized.
shaderc_shader_kind MapStageNameToForcedKind(
const shaderc_util::string_piece& f_shader_stage_str);
// Parse the string piece from command line to get the force shader stage.
// If the 'f_shader_stage_str' cannot be parsed to a valid force shader stage,
// returns 'shaderc_glsl_infer_from_source'. Requires the string to begin with
// '='.
shaderc_shader_kind GetForcedShaderKindFromCmdLine(
const shaderc_util::string_piece& f_shader_stage_str);
// Parse the file name extension to get the default shader kind.
shaderc_shader_kind DeduceDefaultShaderKindFromFileName(
shaderc_util::string_piece file_name);
} // namespace glslc
#endif // GLSLC_SHADER_STAGE_H_

View File

@@ -0,0 +1,92 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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.
// Some of the tests here check code paths that are not checked by
// integration tests.
// Generally, these would be conditions not generated by the Glslang
// compiler. It's easier to write these unit tests than to inject
// a dependency on a fake compiler.
#include <sstream>
#include <gtest/gtest.h>
#include "shaderc/shaderc.h"
#include "shader_stage.h"
using shaderc_util::string_piece;
namespace {
TEST(DeduceDefaultShaderKindFromFileName, ValidStage) {
std::stringstream error_stream;
EXPECT_EQ(shaderc_glsl_default_vertex_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.vert"));
EXPECT_EQ(shaderc_glsl_default_fragment_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.frag"));
EXPECT_EQ(shaderc_glsl_default_geometry_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.geom"));
EXPECT_EQ(shaderc_glsl_default_tess_control_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.tesc"));
EXPECT_EQ(shaderc_glsl_default_tess_evaluation_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.tese"));
EXPECT_EQ(shaderc_glsl_default_compute_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.comp"));
EXPECT_EQ(shaderc_glsl_default_raygen_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rgen"));
EXPECT_EQ(shaderc_glsl_default_anyhit_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rahit"));
EXPECT_EQ(shaderc_glsl_default_closesthit_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rchit"));
EXPECT_EQ(shaderc_glsl_default_miss_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rmiss"));
EXPECT_EQ(shaderc_glsl_default_intersection_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rint"));
EXPECT_EQ(shaderc_glsl_default_callable_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rcall"));
EXPECT_EQ(shaderc_glsl_default_task_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.task"));
EXPECT_EQ(shaderc_glsl_default_mesh_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.mesh"));
}
TEST(DeduceDefaultShaderKindFromFileName, InvalidStage) {
std::stringstream error_stream;
EXPECT_EQ(shaderc_glsl_infer_from_source,
glslc::DeduceDefaultShaderKindFromFileName("a.glsl"));
EXPECT_EQ(shaderc_glsl_infer_from_source,
glslc::DeduceDefaultShaderKindFromFileName("-"));
EXPECT_EQ(shaderc_glsl_infer_from_source,
glslc::DeduceDefaultShaderKindFromFileName("a.foo"));
EXPECT_EQ(shaderc_glsl_infer_from_source,
glslc::DeduceDefaultShaderKindFromFileName("no-file-extension"));
}
} // anonymous namespace