800 lines
30 KiB
C++
800 lines
30 KiB
C++
// 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 <algorithm>
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
#include "libshaderc_util/compiler.h"
|
|
#include "libshaderc_util/counting_includer.h"
|
|
#include "libshaderc_util/resources.h"
|
|
#include "libshaderc_util/spirv_tools_wrapper.h"
|
|
#include "libshaderc_util/version_profile.h"
|
|
#include "shaderc_private.h"
|
|
#include "spirv/unified1/spirv.hpp"
|
|
|
|
#if (defined(_MSC_VER) && !defined(_CPPUNWIND)) || !defined(__EXCEPTIONS)
|
|
#define TRY_IF_EXCEPTIONS_ENABLED
|
|
#define CATCH_IF_EXCEPTIONS_ENABLED(X) if (0)
|
|
#else
|
|
#define TRY_IF_EXCEPTIONS_ENABLED try
|
|
#define CATCH_IF_EXCEPTIONS_ENABLED(X) catch (X)
|
|
#endif
|
|
|
|
namespace {
|
|
|
|
// Returns shader stage (ie: vertex, fragment, etc.) in response to forced
|
|
// shader kinds. If the shader kind is not a forced kind, returns EshLangCount
|
|
// to let #pragma annotation or shader stage deducer determine the stage to
|
|
// use.
|
|
EShLanguage GetForcedStage(shaderc_shader_kind kind) {
|
|
switch (kind) {
|
|
case shaderc_glsl_vertex_shader:
|
|
return EShLangVertex;
|
|
case shaderc_glsl_fragment_shader:
|
|
return EShLangFragment;
|
|
case shaderc_glsl_compute_shader:
|
|
return EShLangCompute;
|
|
case shaderc_glsl_geometry_shader:
|
|
return EShLangGeometry;
|
|
case shaderc_glsl_tess_control_shader:
|
|
return EShLangTessControl;
|
|
case shaderc_glsl_tess_evaluation_shader:
|
|
return EShLangTessEvaluation;
|
|
|
|
case shaderc_glsl_raygen_shader:
|
|
return EShLangRayGenNV;
|
|
case shaderc_glsl_anyhit_shader:
|
|
return EShLangAnyHitNV;
|
|
case shaderc_glsl_closesthit_shader:
|
|
return EShLangClosestHitNV;
|
|
case shaderc_glsl_miss_shader:
|
|
return EShLangMissNV;
|
|
case shaderc_glsl_intersection_shader:
|
|
return EShLangIntersectNV;
|
|
case shaderc_glsl_callable_shader:
|
|
return EShLangCallableNV;
|
|
case shaderc_glsl_task_shader:
|
|
return EShLangTaskNV;
|
|
case shaderc_glsl_mesh_shader:
|
|
return EShLangMeshNV;
|
|
|
|
case shaderc_glsl_infer_from_source:
|
|
case shaderc_glsl_default_vertex_shader:
|
|
case shaderc_glsl_default_fragment_shader:
|
|
case shaderc_glsl_default_compute_shader:
|
|
case shaderc_glsl_default_geometry_shader:
|
|
case shaderc_glsl_default_tess_control_shader:
|
|
case shaderc_glsl_default_tess_evaluation_shader:
|
|
case shaderc_glsl_default_raygen_shader:
|
|
case shaderc_glsl_default_anyhit_shader:
|
|
case shaderc_glsl_default_closesthit_shader:
|
|
case shaderc_glsl_default_miss_shader:
|
|
case shaderc_glsl_default_intersection_shader:
|
|
case shaderc_glsl_default_callable_shader:
|
|
case shaderc_glsl_default_task_shader:
|
|
case shaderc_glsl_default_mesh_shader:
|
|
case shaderc_spirv_assembly:
|
|
return EShLangCount;
|
|
}
|
|
assert(0 && "Unhandled shaderc_shader_kind");
|
|
return EShLangCount;
|
|
}
|
|
|
|
// A wrapper functor class to be used as stage deducer for libshaderc_util
|
|
// Compile() interface. When the given shader kind is one of the default shader
|
|
// kinds, this functor will be called if #pragma is not found in the source
|
|
// code. And it returns the corresponding shader stage. When the shader kind is
|
|
// a forced shader kind, this functor won't be called and it simply returns
|
|
// EShLangCount to make the syntax correct. When the shader kind is set to
|
|
// shaderc_glsl_deduce_from_pragma, this functor also returns EShLangCount, but
|
|
// the compiler should emit error if #pragma annotation is not found in this
|
|
// case.
|
|
class StageDeducer {
|
|
public:
|
|
explicit StageDeducer(
|
|
shaderc_shader_kind kind = shaderc_glsl_infer_from_source)
|
|
: kind_(kind), error_(false){}
|
|
// The method that underlying glslang will call to determine the shader stage
|
|
// to be used in current compilation. It is called only when there is neither
|
|
// forced shader kind (or say stage, in the view of glslang), nor #pragma
|
|
// annotation in the source code. This method transforms an user defined
|
|
// 'default' shader kind to the corresponding shader stage. As this is the
|
|
// last trial to determine the shader stage, failing to find the corresponding
|
|
// shader stage will record an error.
|
|
// Note that calling this method more than once during one compilation will
|
|
// have the error recorded for the previous call been overwriten by the next
|
|
// call.
|
|
EShLanguage operator()(std::ostream* /*error_stream*/,
|
|
const shaderc_util::string_piece& /*error_tag*/) {
|
|
EShLanguage stage = GetDefaultStage(kind_);
|
|
if (stage == EShLangCount) {
|
|
error_ = true;
|
|
} else {
|
|
error_ = false;
|
|
}
|
|
return stage;
|
|
}
|
|
|
|
// Returns true if there is error during shader stage deduction.
|
|
bool error() const { return error_; }
|
|
|
|
private:
|
|
// Gets the corresponding shader stage for a given 'default' shader kind. All
|
|
// other kinds are mapped to EShLangCount which should not be used.
|
|
EShLanguage GetDefaultStage(shaderc_shader_kind kind) const {
|
|
switch (kind) {
|
|
case shaderc_glsl_vertex_shader:
|
|
case shaderc_glsl_fragment_shader:
|
|
case shaderc_glsl_compute_shader:
|
|
case shaderc_glsl_geometry_shader:
|
|
case shaderc_glsl_tess_control_shader:
|
|
case shaderc_glsl_tess_evaluation_shader:
|
|
case shaderc_glsl_infer_from_source:
|
|
case shaderc_glsl_raygen_shader:
|
|
case shaderc_glsl_anyhit_shader:
|
|
case shaderc_glsl_closesthit_shader:
|
|
case shaderc_glsl_miss_shader:
|
|
case shaderc_glsl_intersection_shader:
|
|
case shaderc_glsl_callable_shader:
|
|
case shaderc_glsl_task_shader:
|
|
case shaderc_glsl_mesh_shader:
|
|
return EShLangCount;
|
|
case shaderc_glsl_default_vertex_shader:
|
|
return EShLangVertex;
|
|
case shaderc_glsl_default_fragment_shader:
|
|
return EShLangFragment;
|
|
case shaderc_glsl_default_compute_shader:
|
|
return EShLangCompute;
|
|
case shaderc_glsl_default_geometry_shader:
|
|
return EShLangGeometry;
|
|
case shaderc_glsl_default_tess_control_shader:
|
|
return EShLangTessControl;
|
|
case shaderc_glsl_default_tess_evaluation_shader:
|
|
return EShLangTessEvaluation;
|
|
case shaderc_glsl_default_raygen_shader:
|
|
return EShLangRayGenNV;
|
|
case shaderc_glsl_default_anyhit_shader:
|
|
return EShLangAnyHitNV;
|
|
case shaderc_glsl_default_closesthit_shader:
|
|
return EShLangClosestHitNV;
|
|
case shaderc_glsl_default_miss_shader:
|
|
return EShLangMissNV;
|
|
case shaderc_glsl_default_intersection_shader:
|
|
return EShLangIntersectNV;
|
|
case shaderc_glsl_default_callable_shader:
|
|
return EShLangCallableNV;
|
|
case shaderc_glsl_default_task_shader:
|
|
return EShLangTaskNV;
|
|
case shaderc_glsl_default_mesh_shader:
|
|
return EShLangMeshNV;
|
|
case shaderc_spirv_assembly:
|
|
return EShLangCount;
|
|
}
|
|
assert(0 && "Unhandled shaderc_shader_kind");
|
|
return EShLangCount;
|
|
}
|
|
|
|
shaderc_shader_kind kind_;
|
|
bool error_;
|
|
};
|
|
|
|
// A bridge between the libshaderc includer and libshaderc_util includer.
|
|
class InternalFileIncluder : public shaderc_util::CountingIncluder {
|
|
public:
|
|
InternalFileIncluder(const shaderc_include_resolve_fn resolver,
|
|
const shaderc_include_result_release_fn result_releaser,
|
|
void* user_data)
|
|
: resolver_(resolver),
|
|
result_releaser_(result_releaser),
|
|
user_data_(user_data){}
|
|
InternalFileIncluder()
|
|
: resolver_(nullptr), result_releaser_(nullptr), user_data_(nullptr){}
|
|
|
|
private:
|
|
// Check the validity of the callbacks.
|
|
bool AreValidCallbacks() const {
|
|
return resolver_ != nullptr && result_releaser_ != nullptr;
|
|
}
|
|
|
|
// Maps CountingIncluder IncludeType value to a shaderc_include_type
|
|
// value.
|
|
shaderc_include_type GetIncludeType(IncludeType type) {
|
|
switch (type) {
|
|
case IncludeType::Local:
|
|
return shaderc_include_type_relative;
|
|
case IncludeType::System:
|
|
return shaderc_include_type_standard;
|
|
default:
|
|
break;
|
|
}
|
|
assert(0 && "Unhandled IncludeType");
|
|
return shaderc_include_type_relative;
|
|
}
|
|
|
|
// Resolves an include request for the requested source of the given
|
|
// type in the context of the specified requesting source. On success,
|
|
// returns a newly allocated IncludeResponse containing the fully resolved
|
|
// name of the requested source and the contents of that source.
|
|
// On failure, returns a newly allocated IncludeResponse where the
|
|
// resolved name member is an empty string, and the contents members
|
|
// contains error details.
|
|
virtual glslang::TShader::Includer::IncludeResult* include_delegate(
|
|
const char* requested_source, const char* requesting_source,
|
|
IncludeType type, size_t include_depth) override {
|
|
if (!AreValidCallbacks()) {
|
|
static const char kUnexpectedIncludeError[] =
|
|
"#error unexpected include directive";
|
|
return new glslang::TShader::Includer::IncludeResult{
|
|
"", kUnexpectedIncludeError, strlen(kUnexpectedIncludeError),
|
|
nullptr};
|
|
}
|
|
shaderc_include_result* include_result =
|
|
resolver_(user_data_, requested_source, GetIncludeType(type),
|
|
requesting_source, include_depth);
|
|
// Make a glslang IncludeResult from a shaderc_include_result. The
|
|
// user_data member of the IncludeResult is a pointer to the
|
|
// shaderc_include_result object, so we can later release the latter.
|
|
return new glslang::TShader::Includer::IncludeResult{
|
|
std::string(include_result->source_name,
|
|
include_result->source_name_length),
|
|
include_result->content, include_result->content_length,
|
|
include_result};
|
|
}
|
|
|
|
// Releases the given IncludeResult.
|
|
virtual void release_delegate(
|
|
glslang::TShader::Includer::IncludeResult* result) override {
|
|
if (result && result_releaser_) {
|
|
result_releaser_(user_data_,
|
|
static_cast<shaderc_include_result*>(result->userData));
|
|
}
|
|
delete result;
|
|
}
|
|
|
|
const shaderc_include_resolve_fn resolver_;
|
|
const shaderc_include_result_release_fn result_releaser_;
|
|
void* user_data_;
|
|
};
|
|
|
|
// Converts the target env to the corresponding one in shaderc_util::Compiler.
|
|
shaderc_util::Compiler::TargetEnv GetCompilerTargetEnv(shaderc_target_env env) {
|
|
switch (env) {
|
|
case shaderc_target_env_opengl:
|
|
return shaderc_util::Compiler::TargetEnv::OpenGL;
|
|
case shaderc_target_env_opengl_compat:
|
|
return shaderc_util::Compiler::TargetEnv::OpenGLCompat;
|
|
case shaderc_target_env_webgpu:
|
|
assert(false);
|
|
break;
|
|
case shaderc_target_env_vulkan:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return shaderc_util::Compiler::TargetEnv::Vulkan;
|
|
}
|
|
|
|
shaderc_util::Compiler::TargetEnvVersion GetCompilerTargetEnvVersion(
|
|
uint32_t version_number) {
|
|
using namespace shaderc_util;
|
|
|
|
if (static_cast<uint32_t>(Compiler::TargetEnvVersion::Vulkan_1_0) ==
|
|
version_number) {
|
|
return Compiler::TargetEnvVersion::Vulkan_1_0;
|
|
}
|
|
if (static_cast<uint32_t>(Compiler::TargetEnvVersion::Vulkan_1_1) ==
|
|
version_number) {
|
|
return Compiler::TargetEnvVersion::Vulkan_1_1;
|
|
}
|
|
if (static_cast<uint32_t>(Compiler::TargetEnvVersion::Vulkan_1_2) ==
|
|
version_number) {
|
|
return Compiler::TargetEnvVersion::Vulkan_1_2;
|
|
}
|
|
if (static_cast<uint32_t>(Compiler::TargetEnvVersion::Vulkan_1_3) ==
|
|
version_number) {
|
|
return Compiler::TargetEnvVersion::Vulkan_1_3;
|
|
}
|
|
if (static_cast<uint32_t>(Compiler::TargetEnvVersion::OpenGL_4_5) ==
|
|
version_number) {
|
|
return Compiler::TargetEnvVersion::OpenGL_4_5;
|
|
}
|
|
|
|
return Compiler::TargetEnvVersion::Default;
|
|
}
|
|
|
|
// Returns the Compiler::Limit enum for the given shaderc_limit enum.
|
|
shaderc_util::Compiler::Limit CompilerLimit(shaderc_limit limit) {
|
|
switch (limit) {
|
|
#define RESOURCE(NAME, FIELD, CNAME) \
|
|
case shaderc_limit_##CNAME: \
|
|
return shaderc_util::Compiler::Limit::NAME;
|
|
#include "libshaderc_util/resources.inc"
|
|
#undef RESOURCE
|
|
default:
|
|
break;
|
|
}
|
|
assert(0 && "Should not have reached here");
|
|
return static_cast<shaderc_util::Compiler::Limit>(0);
|
|
}
|
|
|
|
// Returns the Compiler::UniformKind for the given shaderc_uniform_kind.
|
|
shaderc_util::Compiler::UniformKind GetUniformKind(shaderc_uniform_kind kind) {
|
|
switch (kind) {
|
|
case shaderc_uniform_kind_texture:
|
|
return shaderc_util::Compiler::UniformKind::Texture;
|
|
case shaderc_uniform_kind_sampler:
|
|
return shaderc_util::Compiler::UniformKind::Sampler;
|
|
case shaderc_uniform_kind_image:
|
|
return shaderc_util::Compiler::UniformKind::Image;
|
|
case shaderc_uniform_kind_buffer:
|
|
return shaderc_util::Compiler::UniformKind::Buffer;
|
|
case shaderc_uniform_kind_storage_buffer:
|
|
return shaderc_util::Compiler::UniformKind::StorageBuffer;
|
|
case shaderc_uniform_kind_unordered_access_view:
|
|
return shaderc_util::Compiler::UniformKind::UnorderedAccessView;
|
|
}
|
|
assert(0 && "Should not have reached here");
|
|
return static_cast<shaderc_util::Compiler::UniformKind>(0);
|
|
}
|
|
|
|
// Returns the Compiler::Stage for generic stage values in shaderc_shader_kind.
|
|
shaderc_util::Compiler::Stage GetStage(shaderc_shader_kind kind) {
|
|
switch (kind) {
|
|
case shaderc_vertex_shader:
|
|
return shaderc_util::Compiler::Stage::Vertex;
|
|
case shaderc_fragment_shader:
|
|
return shaderc_util::Compiler::Stage::Fragment;
|
|
case shaderc_compute_shader:
|
|
return shaderc_util::Compiler::Stage::Compute;
|
|
case shaderc_tess_control_shader:
|
|
return shaderc_util::Compiler::Stage::TessControl;
|
|
case shaderc_tess_evaluation_shader:
|
|
return shaderc_util::Compiler::Stage::TessEval;
|
|
case shaderc_geometry_shader:
|
|
return shaderc_util::Compiler::Stage::Geometry;
|
|
default:
|
|
break;
|
|
}
|
|
assert(0 && "Should not have reached here");
|
|
return static_cast<shaderc_util::Compiler::Stage>(0);
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
struct shaderc_compile_options {
|
|
shaderc_target_env target_env = shaderc_target_env_default;
|
|
uint32_t target_env_version = 0;
|
|
shaderc_util::Compiler compiler;
|
|
shaderc_include_resolve_fn include_resolver = nullptr;
|
|
shaderc_include_result_release_fn include_result_releaser = nullptr;
|
|
void* include_user_data = nullptr;
|
|
};
|
|
|
|
shaderc_compile_options_t shaderc_compile_options_initialize() {
|
|
return new (std::nothrow) shaderc_compile_options;
|
|
}
|
|
|
|
shaderc_compile_options_t shaderc_compile_options_clone(
|
|
const shaderc_compile_options_t options) {
|
|
if (!options) {
|
|
return shaderc_compile_options_initialize();
|
|
}
|
|
return new (std::nothrow) shaderc_compile_options(*options);
|
|
}
|
|
|
|
void shaderc_compile_options_release(shaderc_compile_options_t options) {
|
|
delete options;
|
|
}
|
|
|
|
void shaderc_compile_options_add_macro_definition(
|
|
shaderc_compile_options_t options, const char* name, size_t name_length,
|
|
const char* value, size_t value_length) {
|
|
options->compiler.AddMacroDefinition(name, name_length, value, value_length);
|
|
}
|
|
|
|
void shaderc_compile_options_set_source_language(
|
|
shaderc_compile_options_t options, shaderc_source_language set_lang) {
|
|
auto lang = shaderc_util::Compiler::SourceLanguage::GLSL;
|
|
if (set_lang == shaderc_source_language_hlsl)
|
|
lang = shaderc_util::Compiler::SourceLanguage::HLSL;
|
|
options->compiler.SetSourceLanguage(lang);
|
|
}
|
|
|
|
void shaderc_compile_options_set_generate_debug_info(
|
|
shaderc_compile_options_t options) {
|
|
options->compiler.SetGenerateDebugInfo();
|
|
}
|
|
|
|
void shaderc_compile_options_set_optimization_level(
|
|
shaderc_compile_options_t options, shaderc_optimization_level level) {
|
|
auto opt_level = shaderc_util::Compiler::OptimizationLevel::Zero;
|
|
switch (level) {
|
|
case shaderc_optimization_level_size:
|
|
opt_level = shaderc_util::Compiler::OptimizationLevel::Size;
|
|
break;
|
|
case shaderc_optimization_level_performance:
|
|
opt_level = shaderc_util::Compiler::OptimizationLevel::Performance;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
options->compiler.SetOptimizationLevel(opt_level);
|
|
}
|
|
|
|
void shaderc_compile_options_set_forced_version_profile(
|
|
shaderc_compile_options_t options, int version, shaderc_profile profile) {
|
|
// Transfer the profile parameter from public enum type to glslang internal
|
|
// enum type. No default case here so that compiler will complain if new enum
|
|
// member is added later but not handled here.
|
|
switch (profile) {
|
|
case shaderc_profile_none:
|
|
options->compiler.SetForcedVersionProfile(version, ENoProfile);
|
|
break;
|
|
case shaderc_profile_core:
|
|
options->compiler.SetForcedVersionProfile(version, ECoreProfile);
|
|
break;
|
|
case shaderc_profile_compatibility:
|
|
options->compiler.SetForcedVersionProfile(version, ECompatibilityProfile);
|
|
break;
|
|
case shaderc_profile_es:
|
|
options->compiler.SetForcedVersionProfile(version, EEsProfile);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void shaderc_compile_options_set_include_callbacks(
|
|
shaderc_compile_options_t options, shaderc_include_resolve_fn resolver,
|
|
shaderc_include_result_release_fn result_releaser, void* user_data) {
|
|
options->include_resolver = resolver;
|
|
options->include_result_releaser = result_releaser;
|
|
options->include_user_data = user_data;
|
|
}
|
|
|
|
void shaderc_compile_options_set_suppress_warnings(
|
|
shaderc_compile_options_t options) {
|
|
options->compiler.SetSuppressWarnings();
|
|
}
|
|
|
|
void shaderc_compile_options_set_target_env(shaderc_compile_options_t options,
|
|
shaderc_target_env target,
|
|
uint32_t version) {
|
|
options->target_env = target;
|
|
options->compiler.SetTargetEnv(GetCompilerTargetEnv(target),
|
|
GetCompilerTargetEnvVersion(version));
|
|
}
|
|
|
|
void shaderc_compile_options_set_target_spirv(shaderc_compile_options_t options,
|
|
shaderc_spirv_version ver) {
|
|
// We made the values match, so we can get away with a static cast.
|
|
options->compiler.SetTargetSpirv(
|
|
static_cast<shaderc_util::Compiler::SpirvVersion>(ver));
|
|
}
|
|
|
|
void shaderc_compile_options_set_warnings_as_errors(
|
|
shaderc_compile_options_t options) {
|
|
options->compiler.SetWarningsAsErrors();
|
|
}
|
|
|
|
void shaderc_compile_options_set_limit(shaderc_compile_options_t options,
|
|
shaderc_limit limit, int value) {
|
|
options->compiler.SetLimit(CompilerLimit(limit), value);
|
|
}
|
|
|
|
void shaderc_compile_options_set_auto_bind_uniforms(
|
|
shaderc_compile_options_t options, bool auto_bind) {
|
|
options->compiler.SetAutoBindUniforms(auto_bind);
|
|
}
|
|
|
|
void shaderc_compile_options_set_auto_combined_image_sampler(
|
|
shaderc_compile_options_t options, bool upgrade) {
|
|
options->compiler.SetAutoCombinedImageSampler(upgrade);
|
|
}
|
|
|
|
void shaderc_compile_options_set_hlsl_io_mapping(
|
|
shaderc_compile_options_t options, bool hlsl_iomap) {
|
|
options->compiler.SetHlslIoMapping(hlsl_iomap);
|
|
}
|
|
|
|
void shaderc_compile_options_set_hlsl_offsets(shaderc_compile_options_t options,
|
|
bool hlsl_offsets) {
|
|
options->compiler.SetHlslOffsets(hlsl_offsets);
|
|
}
|
|
|
|
void shaderc_compile_options_set_binding_base(shaderc_compile_options_t options,
|
|
shaderc_uniform_kind kind,
|
|
uint32_t base) {
|
|
options->compiler.SetAutoBindingBase(GetUniformKind(kind), base);
|
|
}
|
|
|
|
void shaderc_compile_options_set_binding_base_for_stage(
|
|
shaderc_compile_options_t options, shaderc_shader_kind shader_kind,
|
|
shaderc_uniform_kind kind, uint32_t base) {
|
|
options->compiler.SetAutoBindingBaseForStage(GetStage(shader_kind),
|
|
GetUniformKind(kind), base);
|
|
}
|
|
|
|
void shaderc_compile_options_set_auto_map_locations(
|
|
shaderc_compile_options_t options, bool auto_map) {
|
|
options->compiler.SetAutoMapLocations(auto_map);
|
|
}
|
|
|
|
void shaderc_compile_options_set_hlsl_register_set_and_binding_for_stage(
|
|
shaderc_compile_options_t options, shaderc_shader_kind shader_kind,
|
|
const char* reg, const char* set, const char* binding) {
|
|
options->compiler.SetHlslRegisterSetAndBindingForStage(GetStage(shader_kind),
|
|
reg, set, binding);
|
|
}
|
|
|
|
void shaderc_compile_options_set_hlsl_register_set_and_binding(
|
|
shaderc_compile_options_t options, const char* reg, const char* set,
|
|
const char* binding) {
|
|
options->compiler.SetHlslRegisterSetAndBinding(reg, set, binding);
|
|
}
|
|
|
|
void shaderc_compile_options_set_hlsl_functionality1(
|
|
shaderc_compile_options_t options, bool enable) {
|
|
options->compiler.EnableHlslFunctionality1(enable);
|
|
}
|
|
|
|
void shaderc_compile_options_set_hlsl_16bit_types(
|
|
shaderc_compile_options_t options, bool enable) {
|
|
options->compiler.EnableHlsl16BitTypes(enable);
|
|
}
|
|
|
|
void shaderc_compile_options_set_invert_y(
|
|
shaderc_compile_options_t options, bool enable) {
|
|
options->compiler.EnableInvertY(enable);
|
|
}
|
|
|
|
void shaderc_compile_options_set_nan_clamp(shaderc_compile_options_t options,
|
|
bool enable) {
|
|
options->compiler.SetNanClamp(enable);
|
|
}
|
|
|
|
shaderc_compiler_t shaderc_compiler_initialize() {
|
|
shaderc_compiler_t compiler = new (std::nothrow) shaderc_compiler;
|
|
if (compiler) {
|
|
compiler->initializer.reset(new shaderc_util::GlslangInitializer);
|
|
}
|
|
return compiler;
|
|
}
|
|
|
|
void shaderc_compiler_release(shaderc_compiler_t compiler) {
|
|
delete compiler;
|
|
}
|
|
|
|
namespace {
|
|
shaderc_compilation_result_t CompileToSpecifiedOutputType(
|
|
const shaderc_compiler_t compiler, const char* source_text,
|
|
size_t source_text_size, shaderc_shader_kind shader_kind,
|
|
const char* input_file_name, const char* entry_point_name,
|
|
const shaderc_compile_options_t additional_options,
|
|
shaderc_util::Compiler::OutputType output_type) {
|
|
auto* result = new (std::nothrow) shaderc_compilation_result_vector;
|
|
if (!result) return nullptr;
|
|
|
|
if (!input_file_name) {
|
|
result->messages = "Input file name string was null.";
|
|
result->num_errors = 1;
|
|
result->compilation_status = shaderc_compilation_status_compilation_error;
|
|
return result;
|
|
}
|
|
result->compilation_status = shaderc_compilation_status_invalid_stage;
|
|
bool compilation_succeeded = false; // In case we exit early.
|
|
std::vector<uint32_t> compilation_output_data;
|
|
size_t compilation_output_data_size_in_bytes = 0u;
|
|
if (!compiler->initializer) return result;
|
|
TRY_IF_EXCEPTIONS_ENABLED {
|
|
std::stringstream errors;
|
|
size_t total_warnings = 0;
|
|
size_t total_errors = 0;
|
|
std::string input_file_name_str(input_file_name);
|
|
EShLanguage forced_stage = GetForcedStage(shader_kind);
|
|
shaderc_util::string_piece source_string =
|
|
shaderc_util::string_piece(source_text, source_text + source_text_size);
|
|
StageDeducer stage_deducer(shader_kind);
|
|
if (additional_options) {
|
|
InternalFileIncluder includer(additional_options->include_resolver,
|
|
additional_options->include_result_releaser,
|
|
additional_options->include_user_data);
|
|
// Depends on return value optimization to avoid extra copy.
|
|
std::tie(compilation_succeeded, compilation_output_data,
|
|
compilation_output_data_size_in_bytes) =
|
|
additional_options->compiler.Compile(
|
|
source_string, forced_stage, input_file_name_str, entry_point_name,
|
|
// stage_deducer has a flag: error_, which we need to check later.
|
|
// We need to make this a reference wrapper, so that std::function
|
|
// won't make a copy for this callable object.
|
|
std::ref(stage_deducer), includer, output_type, &errors,
|
|
&total_warnings, &total_errors);
|
|
} else {
|
|
// Compile with default options.
|
|
InternalFileIncluder includer;
|
|
std::tie(compilation_succeeded, compilation_output_data,
|
|
compilation_output_data_size_in_bytes) =
|
|
shaderc_util::Compiler().Compile(
|
|
source_string, forced_stage, input_file_name_str, entry_point_name,
|
|
std::ref(stage_deducer), includer, output_type, &errors,
|
|
&total_warnings, &total_errors);
|
|
}
|
|
|
|
result->messages = errors.str();
|
|
result->SetOutputData(std::move(compilation_output_data));
|
|
result->output_data_size = compilation_output_data_size_in_bytes;
|
|
result->num_warnings = total_warnings;
|
|
result->num_errors = total_errors;
|
|
if (compilation_succeeded) {
|
|
result->compilation_status = shaderc_compilation_status_success;
|
|
} else {
|
|
// Check whether the error is caused by failing to deduce the shader
|
|
// stage. If it is the case, set the error type to shader kind error.
|
|
// Otherwise, set it to compilation error.
|
|
result->compilation_status =
|
|
stage_deducer.error() ? shaderc_compilation_status_invalid_stage
|
|
: shaderc_compilation_status_compilation_error;
|
|
}
|
|
}
|
|
CATCH_IF_EXCEPTIONS_ENABLED(...) {
|
|
result->compilation_status = shaderc_compilation_status_internal_error;
|
|
}
|
|
return result;
|
|
}
|
|
} // anonymous namespace
|
|
|
|
shaderc_compilation_result_t shaderc_compile_into_spv(
|
|
const shaderc_compiler_t compiler, const char* source_text,
|
|
size_t source_text_size, shaderc_shader_kind shader_kind,
|
|
const char* input_file_name, const char* entry_point_name,
|
|
const shaderc_compile_options_t additional_options) {
|
|
return CompileToSpecifiedOutputType(
|
|
compiler, source_text, source_text_size, shader_kind, input_file_name,
|
|
entry_point_name, additional_options,
|
|
shaderc_util::Compiler::OutputType::SpirvBinary);
|
|
}
|
|
|
|
shaderc_compilation_result_t shaderc_compile_into_spv_assembly(
|
|
const shaderc_compiler_t compiler, const char* source_text,
|
|
size_t source_text_size, shaderc_shader_kind shader_kind,
|
|
const char* input_file_name, const char* entry_point_name,
|
|
const shaderc_compile_options_t additional_options) {
|
|
return CompileToSpecifiedOutputType(
|
|
compiler, source_text, source_text_size, shader_kind, input_file_name,
|
|
entry_point_name, additional_options,
|
|
shaderc_util::Compiler::OutputType::SpirvAssemblyText);
|
|
}
|
|
|
|
shaderc_compilation_result_t shaderc_compile_into_preprocessed_text(
|
|
const shaderc_compiler_t compiler, const char* source_text,
|
|
size_t source_text_size, shaderc_shader_kind shader_kind,
|
|
const char* input_file_name, const char* entry_point_name,
|
|
const shaderc_compile_options_t additional_options) {
|
|
return CompileToSpecifiedOutputType(
|
|
compiler, source_text, source_text_size, shader_kind, input_file_name,
|
|
entry_point_name, additional_options,
|
|
shaderc_util::Compiler::OutputType::PreprocessedText);
|
|
}
|
|
|
|
shaderc_compilation_result_t shaderc_assemble_into_spv(
|
|
const shaderc_compiler_t compiler, const char* source_assembly,
|
|
size_t source_assembly_size,
|
|
const shaderc_compile_options_t additional_options) {
|
|
auto* result = new (std::nothrow) shaderc_compilation_result_spv_binary;
|
|
if (!result) return nullptr;
|
|
result->compilation_status = shaderc_compilation_status_invalid_assembly;
|
|
if (!compiler->initializer) return result;
|
|
if (source_assembly == nullptr) return result;
|
|
|
|
TRY_IF_EXCEPTIONS_ENABLED {
|
|
spv_binary assembling_output_data = nullptr;
|
|
std::string errors;
|
|
const auto target_env = additional_options ? additional_options->target_env
|
|
: shaderc_target_env_default;
|
|
const uint32_t target_env_version =
|
|
additional_options ? additional_options->target_env_version : 0;
|
|
const bool assembling_succeeded = shaderc_util::SpirvToolsAssemble(
|
|
GetCompilerTargetEnv(target_env),
|
|
GetCompilerTargetEnvVersion(target_env_version),
|
|
{source_assembly, source_assembly + source_assembly_size},
|
|
&assembling_output_data, &errors);
|
|
result->num_errors = !assembling_succeeded;
|
|
if (assembling_succeeded) {
|
|
result->SetOutputData(assembling_output_data);
|
|
result->output_data_size =
|
|
assembling_output_data->wordCount * sizeof(uint32_t);
|
|
result->compilation_status = shaderc_compilation_status_success;
|
|
} else {
|
|
result->messages = std::move(errors);
|
|
result->compilation_status = shaderc_compilation_status_invalid_assembly;
|
|
}
|
|
}
|
|
CATCH_IF_EXCEPTIONS_ENABLED(...) {
|
|
result->compilation_status = shaderc_compilation_status_internal_error;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
size_t shaderc_result_get_length(const shaderc_compilation_result_t result) {
|
|
return result->output_data_size;
|
|
}
|
|
|
|
size_t shaderc_result_get_num_warnings(
|
|
const shaderc_compilation_result_t result) {
|
|
return result->num_warnings;
|
|
}
|
|
|
|
size_t shaderc_result_get_num_errors(
|
|
const shaderc_compilation_result_t result) {
|
|
return result->num_errors;
|
|
}
|
|
|
|
const char* shaderc_result_get_bytes(
|
|
const shaderc_compilation_result_t result) {
|
|
return result->GetBytes();
|
|
}
|
|
|
|
void shaderc_result_release(shaderc_compilation_result_t result) {
|
|
delete result;
|
|
}
|
|
|
|
const char* shaderc_result_get_error_message(
|
|
const shaderc_compilation_result_t result) {
|
|
return result->messages.c_str();
|
|
}
|
|
|
|
shaderc_compilation_status shaderc_result_get_compilation_status(
|
|
const shaderc_compilation_result_t result) {
|
|
return result->compilation_status;
|
|
}
|
|
|
|
void shaderc_get_spv_version(unsigned int* version, unsigned int* revision) {
|
|
*version = spv::Version;
|
|
*revision = spv::Revision;
|
|
}
|
|
|
|
bool shaderc_parse_version_profile(const char* str, int* version,
|
|
shaderc_profile* profile) {
|
|
EProfile glslang_profile;
|
|
bool success = shaderc_util::ParseVersionProfile(
|
|
std::string(str, strlen(str)), version, &glslang_profile);
|
|
if (!success) return false;
|
|
|
|
switch (glslang_profile) {
|
|
case EEsProfile:
|
|
*profile = shaderc_profile_es;
|
|
return true;
|
|
case ECoreProfile:
|
|
*profile = shaderc_profile_core;
|
|
return true;
|
|
case ECompatibilityProfile:
|
|
*profile = shaderc_profile_compatibility;
|
|
return true;
|
|
case ENoProfile:
|
|
*profile = shaderc_profile_none;
|
|
return true;
|
|
case EBadProfile:
|
|
case EProfileCount:
|
|
return false;
|
|
}
|
|
|
|
// Shouldn't reach here, all profile enum should be handled above.
|
|
// Be strict to return false.
|
|
return false;
|
|
}
|