Skip to content

Commit

Permalink
spvc: Add some flags. (google#579)
Browse files Browse the repository at this point in the history
Implement the following spvc flags and update the test:
  --entry
  --version
  --remove-unused-variables
  --vulkan-semantics
  --separate-shader-objects
  --flatten-ubo
The old --version flag is now -v.
  • Loading branch information
fjhenigman authored Mar 28, 2019
1 parent f7fa8ce commit 067a749
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 17 deletions.
22 changes: 22 additions & 0 deletions libshaderc_spvc/include/shaderc/spvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,34 @@ shaderc_spvc_compile_options_clone(
SHADERC_EXPORT void shaderc_spvc_compile_options_release(
shaderc_spvc_compile_options_t options);

// Sets the entry point.
SHADERC_EXPORT void shaderc_spvc_compile_options_set_entry_point(
shaderc_spvc_compile_options_t options, const char* entry_point);

// If true, unused variables will not appear in the output.
SHADERC_EXPORT void shaderc_spvc_compile_options_set_remove_unused_variables(
shaderc_spvc_compile_options_t options, bool b);

// Sets the target shader environment, affecting which warnings or errors will
// be issued during validation.
SHADERC_EXPORT void shaderc_spvc_compile_options_set_target_env(
shaderc_spvc_compile_options_t options, shaderc_target_env target,
shaderc_env_version version);

// If true, Vulkan GLSL features are used instead of GL-compatible features.
SHADERC_EXPORT void shaderc_spvc_compile_options_set_vulkan_semantics(
shaderc_spvc_compile_options_t options, bool b);

// If true, gl_PerVertex is explicitly redeclared in vertex, geometry and
// tessellation shaders. The members of gl_PerVertex is determined by which
// built-ins are declared by the shader.
SHADERC_EXPORT void shaderc_spvc_compile_options_set_separate_shader_objects(
shaderc_spvc_compile_options_t options, bool b);

// Flatten uniform or push constant variable into (i|u)vec4 array.
SHADERC_EXPORT void shaderc_spvc_compile_options_set_flatten_ubo(
shaderc_spvc_compile_options_t options, bool b);

// Set language version. Default is 450.
SHADERC_EXPORT void shaderc_spvc_compile_options_set_output_language_version(
shaderc_spvc_compile_options_t options, uint32_t version);
Expand Down
27 changes: 27 additions & 0 deletions libshaderc_spvc/include/shaderc/spvc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,33 @@ class CompileOptions {
shaderc_spvc_compile_options_set_target_env(options_, target, version);
}

// Set the entry point.
void SetEntryPoint(const std::string& entry_point) {
shaderc_spvc_compile_options_set_entry_point(options_, entry_point.c_str());
}

// If true, unused variables will not appear in the output.
void SetRemoveUnusedVariables(bool b) {
shaderc_spvc_compile_options_set_remove_unused_variables(options_, b);
}

// If true, Vulkan GLSL features are used instead of GL-compatible features.
void SetVulkanSemantics(bool b) {
shaderc_spvc_compile_options_set_vulkan_semantics(options_, b);
}

// If true, gl_PerVertex is explicitly redeclared in vertex, geometry and
// tessellation shaders. The members of gl_PerVertex is determined by which
// built-ins are declared by the shader.
void SetSeparateShaderObjects(bool b) {
shaderc_spvc_compile_options_set_separate_shader_objects(options_, b);
}

// Flatten uniform or push constant variable into (i|u)vec4 array.
void SetFlattenUbo(bool b) {
shaderc_spvc_compile_options_set_flatten_ubo(options_, b);
}

// Which GLSL version should be produced. Default is 450.
void SetOutputLanguageVersion(uint32_t version) {
shaderc_spvc_compile_options_set_output_language_version(options_, version);
Expand Down
119 changes: 118 additions & 1 deletion libshaderc_spvc/src/spvc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
#include "spirv-cross/spirv_msl.hpp"
#include "spirv-tools/libspirv.hpp"

// GLSL version produced when none specified nor detected from source.
#define DEFAULT_GLSL_VERSION 450

struct shaderc_spvc_compiler {};

// Described in spvc.h.
Expand All @@ -32,14 +35,20 @@ struct shaderc_spvc_compilation_result {

struct shaderc_spvc_compile_options {
bool validate = true;
bool remove_unused_variables = false;
bool flatten_ubo = false;
std::string entry_point;
spv_target_env target_env = SPV_ENV_VULKAN_1_0;
spirv_cross::CompilerGLSL::Options glsl;
spirv_cross::CompilerHLSL::Options hlsl;
spirv_cross::CompilerMSL::Options msl;
};

shaderc_spvc_compile_options_t shaderc_spvc_compile_options_initialize() {
return new (std::nothrow) shaderc_spvc_compile_options;
shaderc_spvc_compile_options_t options =
new (std::nothrow) shaderc_spvc_compile_options;
if (options) options->glsl.version = 0;
return options;
}

shaderc_spvc_compile_options_t shaderc_spvc_compile_options_clone(
Expand Down Expand Up @@ -84,6 +93,31 @@ void shaderc_spvc_compile_options_set_target_env(
}
}

void shaderc_spvc_compile_options_set_entry_point(
shaderc_spvc_compile_options_t options, const char* entry_point) {
options->entry_point = entry_point;
}

void shaderc_spvc_compile_options_set_remove_unused_variables(
shaderc_spvc_compile_options_t options, bool b) {
options->remove_unused_variables = b;
}

void shaderc_spvc_compile_options_set_vulkan_semantics(
shaderc_spvc_compile_options_t options, bool b) {
options->glsl.vulkan_semantics = b;
}

void shaderc_spvc_compile_options_set_separate_shader_objects(
shaderc_spvc_compile_options_t options, bool b) {
options->glsl.separate_shader_objects = b;
}

void shaderc_spvc_compile_options_set_flatten_ubo(
shaderc_spvc_compile_options_t options, bool b) {
options->flatten_ubo = b;
}

void shaderc_spvc_compile_options_set_output_language_version(
shaderc_spvc_compile_options_t options, uint32_t version) {
options->glsl.version = version;
Expand Down Expand Up @@ -171,7 +205,90 @@ shaderc_spvc_compilation_result_t validate_and_compile(
shaderc_spvc_compilation_result_t shaderc_spvc_compile_into_glsl(
const shaderc_spvc_compiler_t, const uint32_t* source, size_t source_len,
shaderc_spvc_compile_options_t options) {
auto* result = new (std::nothrow) shaderc_spvc_compilation_result;
if (!result) return nullptr;

spirv_cross::CompilerGLSL compiler(source, source_len);

if (options->glsl.version == 0) {
// no version requested, was one detected in source?
options->glsl.version = compiler.get_common_options().version;
if (options->glsl.version == 0) {
// no version detected in source, use default
options->glsl.version = DEFAULT_GLSL_VERSION;
} else {
// version detected implies ES also detected
options->glsl.es = compiler.get_common_options().es;
}
}

auto entry_points = compiler.get_entry_points_and_stages();
spv::ExecutionModel model = spv::ExecutionModelMax;
if (!options->entry_point.empty()) {
// Make sure there is just one entry point with this name, or the stage is
// ambiguous.
uint32_t stage_count = 0;
for (auto& e : entry_points) {
if (e.name == options->entry_point) {
stage_count++;
model = e.execution_model;
}
}
if (stage_count != 1) {
result->status = shaderc_compilation_status_compilation_error;
if (stage_count == 0)
result->messages =
"There is no entry point with name: " + options->entry_point;
else
result->messages = "There is more than one entry point with name: " +
options->entry_point + ". Use --stage.";
return result;
}
}
if (!options->entry_point.empty()) {
compiler.set_entry_point(options->entry_point, model);
}

if (!options->glsl.vulkan_semantics) {
uint32_t sampler = compiler.build_dummy_sampler_for_combined_images();
if (sampler) {
// Set some defaults to make validation happy.
compiler.set_decoration(sampler, spv::DecorationDescriptorSet, 0);
compiler.set_decoration(sampler, spv::DecorationBinding, 0);
}
}

spirv_cross::ShaderResources res;
if (options->remove_unused_variables) {
auto active = compiler.get_active_interface_variables();
res = compiler.get_shader_resources(active);
compiler.set_enabled_interface_variables(move(active));
} else {
res = compiler.get_shader_resources();
}

if (options->flatten_ubo) {
for (auto& ubo : res.uniform_buffers) compiler.flatten_buffer_block(ubo.id);
for (auto& ubo : res.push_constant_buffers)
compiler.flatten_buffer_block(ubo.id);
}

if (!options->glsl.vulkan_semantics) {
compiler.build_combined_image_samplers();

// if (args.combined_samplers_inherit_bindings)
// spirv_cross_util::inherit_combined_sampler_bindings(*compiler);

// Give the remapped combined samplers new names.
for (auto& remap : compiler.get_combined_image_samplers()) {
compiler.set_name(remap.combined_id,
spirv_cross::join("SPIRV_Cross_Combined",
compiler.get_name(remap.image_id),
compiler.get_name(remap.sampler_id)));
}
}

shaderc_spvc_result_release(result);
compiler.set_common_options(options->glsl);
return validate_and_compile(&compiler, source, source_len, options);
}
Expand Down
77 changes: 65 additions & 12 deletions spvc/src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,24 @@ An input file of - represents standard input.
Options:
--help Display available options.
--version Display compiler version information.
-v Display compiler version information.
-o <output file> '-' means standard output.
--validate=[<env>] Validate SPIR-V source with given environment
<env> is empty to skip validation, or one of the following:
vulkan1.0 (default) vulkan1.1 opengl opengl4.5
--validate=<env> Validate SPIR-V source with given environment
<env> is vulkan1.0 (the default) or vulkan1.1
--entry=<name> Specify entry point.
--version=<unsigned> Specify GLSL output language version, e.g. 100
Default is 450 if not detected from input.
The following flags behave as in spirv-cross:
--remove-unused-variables
--vulkan-semantics
--separate-shader-objects
--flatten-ubo
)";
}

// TODO(fjhenigman): factor out
// TODO(fjhenigman): factor out with glslc
// Gets the option argument for the option at *index in argv in a way consistent
// with clang/gcc. On success, returns true and writes the parsed argument into
// *option_argument. Returns false if any errors occur. After calling this
Expand All @@ -72,6 +81,29 @@ bool GetOptionArgument(int argc, char** argv, int* index,

}

// TODO(fjhenigman): factor out with glslc
// Parses the given string as a number of the specified type. Returns true
// if parsing succeeded, and stores the parsed value via |value|.
bool ParseUint32(const std::string& str, uint32_t* value) {
std::istringstream iss(str);

iss >> std::setbase(0);
iss >> *value;

// We should have read something.
bool ok = !str.empty() && !iss.bad();
// It should have been all the text.
ok = ok && iss.eof();
// It should have been in range.
ok = ok && !iss.fail();

// Work around a bugs in various C++ standard libraries.
// Count any negative number as an error, including "-0".
ok = ok && (str[0] != '-');

return ok;
}

const char kBuildVersion[] = ""
// TODO(fjhenigman): #include "build-version.inc"
;
Expand Down Expand Up @@ -111,7 +143,7 @@ int main(int argc, char** argv) {
if (arg == "--help") {
::PrintHelp(&std::cout);
return 0;
} else if (arg == "--version") {
} else if (arg == "-v") {
std::cout << kBuildVersion << std::endl;
std::cout << "Target: " << spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0)
<< std::endl;
Expand All @@ -123,23 +155,44 @@ int main(int argc, char** argv) {
<< std::endl;
return 1;
}
} else if (arg.starts_with("--entry=")) {
string_piece entry_point;
GetOptionArgument(argc, argv, &i, "--entry=", &entry_point);
options.SetEntryPoint(entry_point.data());
} else if (arg.starts_with("--version=")) {
string_piece version_str;
GetOptionArgument(argc, argv, &i, "--version=", &version_str);
uint32_t version_num;
if (!ParseUint32(version_str.str(), &version_num)) {
std::cerr << "spvc: error: invalid value '" << version_str
<< "' in --version=" << std::endl;
return 1;
}
options.SetOutputLanguageVersion(version_num);
} else if (arg == "--remove-unused-variables") {
// TODO
options.SetRemoveUnusedVariables(true);
} else if (arg == "--vulkan-semantics") {
options.SetVulkanSemantics(true);
} else if (arg == "--separate-shader-objects") {
options.SetSeparateShaderObjects(true);
} else if (arg == "--flatten-ubo") {
options.SetFlattenUbo(true);
} else if (arg == "--flatten-multidimensional-arrays") {
// TODO(fjhenigman)
} else if (arg == "--es") {
// TODO(fjhenigman)
} else if (arg.starts_with("--validate=")) {
string_piece target_env;
GetOptionArgument(argc, argv, &i, "--validate=", &target_env);
if (target_env == "vulkan") {
options.SetTargetEnvironment(shaderc_target_env_vulkan,
shaderc_env_version_vulkan_1_0);
} else if (target_env == "vulkan1.0") {
if (target_env == "vulkan1.0") {
options.SetTargetEnvironment(shaderc_target_env_vulkan,
shaderc_env_version_vulkan_1_0);
} else if (target_env == "vulkan1.1") {
options.SetTargetEnvironment(shaderc_target_env_vulkan,
shaderc_env_version_vulkan_1_1);
} else {
std::cerr << "spvc: error: invalid value '" << target_env
<< "' in '--validate=" << target_env << "'" << std::endl;
<< "' in --validate=" << std::endl;
return 1;
}
} else {
Expand Down
19 changes: 15 additions & 4 deletions spvc/test/run_spirv_cross_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,27 @@ def test_glsl(shader, filename, optimize):
# Run spvc to convert Vulkan to GLSL. Up to two tests are performed:
# - Regular test on most files
# - Vulkan-specific test on Vulkan test input
flags = []
flags = ['--entry=main']
if not '.noeliminate' in filename:
flags.append('--remove-unused-variables')
if '.legacy.' in filename:
flags.extend(['--version=100', '--es'])
if '.flatten.' in filename:
flags.append('--flatten-ubo')
if '.flatten_dim.' in filename:
flags.append('--flatten-multidimensional-arrays')
if '.sso.' in filename:
flags.append('--separate-shader-objects')

output = None
if not '.nocompat.' in filename:
test_count += 1
output = spvc(tmpfile, tmpfile + filename , flags)

output_vk = None
if '.vk.' in filename or '.asm.' in filename:
#TODO(fjhenigman): add Vulkan-specific flags.
test_count += 1
output_vk = spvc(tmpfile, tmpfile + 'vk' + filename, flags)
output_vk = spvc(tmpfile, tmpfile + 'vk' + filename, flags + ['--vulkan-semantics'])

# Check results.
# Compare either or both files produced above to appropriate reference file.
Expand Down Expand Up @@ -163,4 +174,4 @@ def main(shader_dir):
main(spirv_cross_dir)

# TODO: remove the magic number once all tests pass
sys.exit(pass_count != 169)
sys.exit(pass_count != 526)

0 comments on commit 067a749

Please sign in to comment.