blob: 5e27b562e606e4b82fe53ee7c6f607b4eec41358 [file] [log] [blame]
// Copyright 2018 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 <spvc/spvc.hpp>
#include "spvc_log.h"
#include "spvc_private.h"
// MSVC 2013 doesn't define __func__
#ifndef __func__
#define __func__ __FUNCTION__
#endif
#define CHECK_CONTEXT(context) \
do { \
if (!context) { \
shaderc_spvc::ErrorLog(nullptr) \
<< "Invoked " << __func__ << " without an initialized context"; \
return shaderc_spvc_status_missing_context_error; \
} \
} while (0)
#define CHECK_CROSS_COMPILER(context, cross_compiler) \
do { \
if (!cross_compiler) { \
shaderc_spvc::ErrorLog(context) \
<< "Invoked " << __func__ \
<< " without an initialized cross compiler"; \
return shaderc_spvc_status_uninitialized_compiler_error; \
} \
} while (0)
#define CHECK_OPTIONS(context, options) \
do { \
if (!options) { \
shaderc_spvc::ErrorLog(context) \
<< "Invoked " << __func__ << " without an initialized options"; \
return shaderc_spvc_status_missing_options_error; \
} \
} while (0)
#define CHECK_RESULT(context, result) \
do { \
if (!result) { \
shaderc_spvc::ErrorLog(context) \
<< "Invoked " << __func__ << " without an initialized result"; \
return shaderc_spvc_status_missing_result_error; \
} \
} while (0)
#define CHECK_OUT_PARAM(context, param, param_str) \
do { \
if (!param) { \
shaderc_spvc::ErrorLog(context) \
<< "Invoked " << __func__ << " with invalid out param, " \
<< param_str; \
return shaderc_spvc_status_invalid_out_param; \
} \
} while (0)
#define CHECK_IN_PARAM(context, param, param_str) \
do { \
if (!param) { \
shaderc_spvc::ErrorLog(context) \
<< "Invoked " << __func__ << " with invalid in param, " \
<< param_str; \
return shaderc_spvc_status_invalid_in_param; \
} \
} while (0)
namespace {
spv::ExecutionModel spvc_model_to_spv_model(
shaderc_spvc_execution_model model) {
switch (model) {
case shaderc_spvc_execution_model_vertex:
return spv::ExecutionModel::ExecutionModelVertex;
case shaderc_spvc_execution_model_fragment:
return spv::ExecutionModel::ExecutionModelFragment;
case shaderc_spvc_execution_model_glcompute:
return spv::ExecutionModel::ExecutionModelGLCompute;
case shaderc_spvc_execution_model_invalid:
return spv::ExecutionModel::ExecutionModelMax;
}
// Older gcc doesn't recognize that all of the possible cases are covered
// above.
assert(false);
return spv::ExecutionModel::ExecutionModelMax;
}
shaderc_spvc_execution_model spv_model_to_spvc_model(
spv::ExecutionModel model) {
switch (model) {
case spv::ExecutionModel::ExecutionModelVertex:
return shaderc_spvc_execution_model_vertex;
case spv::ExecutionModel::ExecutionModelFragment:
return shaderc_spvc_execution_model_fragment;
case spv::ExecutionModel::ExecutionModelGLCompute:
return shaderc_spvc_execution_model_glcompute;
default:
return shaderc_spvc_execution_model_invalid;
}
}
const spirv_cross::SmallVector<spirv_cross::Resource>* get_shader_resources(
const spirv_cross::ShaderResources& resources,
shaderc_spvc_shader_resource resource) {
switch (resource) {
case shaderc_spvc_shader_resource_uniform_buffers:
return &(resources.uniform_buffers);
case shaderc_spvc_shader_resource_separate_images:
return &(resources.separate_images);
case shaderc_spvc_shader_resource_separate_samplers:
return &(resources.separate_samplers);
case shaderc_spvc_shader_resource_storage_buffers:
return &(resources.storage_buffers);
case shaderc_spvc_shader_resource_storage_images:
return &(resources.storage_images);
}
// Older gcc doesn't recognize that all of the possible cases are covered
// above.
assert(false);
return nullptr;
}
shaderc_spvc_texture_view_dimension spirv_dim_to_texture_view_dimension(
spv::Dim dim, bool arrayed) {
switch (dim) {
case spv::Dim::Dim1D:
return shaderc_spvc_texture_view_dimension_e1D;
case spv::Dim::Dim2D:
if (arrayed) {
return shaderc_spvc_texture_view_dimension_e2D_array;
} else {
return shaderc_spvc_texture_view_dimension_e2D;
}
case spv::Dim::Dim3D:
return shaderc_spvc_texture_view_dimension_e3D;
case spv::Dim::DimCube:
if (arrayed) {
return shaderc_spvc_texture_view_dimension_cube_array;
} else {
return shaderc_spvc_texture_view_dimension_cube;
}
default:
return shaderc_spvc_texture_view_dimension_undefined;
}
}
shaderc_spvc_texture_format_type spirv_cross_base_type_to_texture_format_type(
spirv_cross::SPIRType::BaseType type) {
switch (type) {
case spirv_cross::SPIRType::Float:
return shaderc_spvc_texture_format_type_float;
case spirv_cross::SPIRType::Int:
return shaderc_spvc_texture_format_type_sint;
case spirv_cross::SPIRType::UInt:
return shaderc_spvc_texture_format_type_uint;
default:
return shaderc_spvc_texture_format_type_other;
}
}
shaderc_spvc_storage_texture_format spv_image_format_to_storage_texture_format(
spv::ImageFormat format) {
switch (format) {
case spv::ImageFormatR8:
return shaderc_spvc_storage_texture_format_r8unorm;
case spv::ImageFormatR8Snorm:
return shaderc_spvc_storage_texture_format_r8snorm;
case spv::ImageFormatR8ui:
return shaderc_spvc_storage_texture_format_r8uint;
case spv::ImageFormatR8i:
return shaderc_spvc_storage_texture_format_r8sint;
case spv::ImageFormatR16ui:
return shaderc_spvc_storage_texture_format_r16uint;
case spv::ImageFormatR16i:
return shaderc_spvc_storage_texture_format_r16sint;
case spv::ImageFormatR16f:
return shaderc_spvc_storage_texture_format_r16float;
case spv::ImageFormatRg8:
return shaderc_spvc_storage_texture_format_rg8unorm;
case spv::ImageFormatRg8Snorm:
return shaderc_spvc_storage_texture_format_rg8snorm;
case spv::ImageFormatRg8ui:
return shaderc_spvc_storage_texture_format_rg8uint;
case spv::ImageFormatRg8i:
return shaderc_spvc_storage_texture_format_rg8sint;
case spv::ImageFormatR32f:
return shaderc_spvc_storage_texture_format_r32float;
case spv::ImageFormatR32ui:
return shaderc_spvc_storage_texture_format_r32uint;
case spv::ImageFormatR32i:
return shaderc_spvc_storage_texture_format_r32sint;
case spv::ImageFormatRg16ui:
return shaderc_spvc_storage_texture_format_rg16uint;
case spv::ImageFormatRg16i:
return shaderc_spvc_storage_texture_format_rg16sint;
case spv::ImageFormatRg16f:
return shaderc_spvc_storage_texture_format_rg16float;
case spv::ImageFormatRgba8:
return shaderc_spvc_storage_texture_format_rgba8unorm;
case spv::ImageFormatRgba8Snorm:
return shaderc_spvc_storage_texture_format_rgba8snorm;
case spv::ImageFormatRgba8ui:
return shaderc_spvc_storage_texture_format_rgba8uint;
case spv::ImageFormatRgba8i:
return shaderc_spvc_storage_texture_format_rgba8sint;
case spv::ImageFormatRgb10A2:
return shaderc_spvc_storage_texture_format_rgb10a2unorm;
case spv::ImageFormatR11fG11fB10f:
return shaderc_spvc_storage_texture_format_rg11b10float;
case spv::ImageFormatRg32f:
return shaderc_spvc_storage_texture_format_rg32float;
case spv::ImageFormatRg32ui:
return shaderc_spvc_storage_texture_format_rg32uint;
case spv::ImageFormatRg32i:
return shaderc_spvc_storage_texture_format_rg32sint;
case spv::ImageFormatRgba16ui:
return shaderc_spvc_storage_texture_format_rgba16uint;
case spv::ImageFormatRgba16i:
return shaderc_spvc_storage_texture_format_rgba16sint;
case spv::ImageFormatRgba16f:
return shaderc_spvc_storage_texture_format_rgba16float;
case spv::ImageFormatRgba32f:
return shaderc_spvc_storage_texture_format_rgba32float;
case spv::ImageFormatRgba32ui:
return shaderc_spvc_storage_texture_format_rgba32uint;
case spv::ImageFormatRgba32i:
return shaderc_spvc_storage_texture_format_rgba32sint;
default:
return shaderc_spvc_storage_texture_format_undefined;
}
}
spv_target_env shaderc_spvc_spv_env_to_spv_target_env(
shaderc_spvc_spv_env env) {
switch (env) {
case shaderc_spvc_spv_env_universal_1_0:
return SPV_ENV_UNIVERSAL_1_0;
case shaderc_spvc_spv_env_vulkan_1_0:
return SPV_ENV_VULKAN_1_0;
case shaderc_spvc_spv_env_universal_1_1:
return SPV_ENV_UNIVERSAL_1_1;
case shaderc_spvc_spv_env_opencl_2_1:
return SPV_ENV_OPENCL_2_1;
case shaderc_spvc_spv_env_opencl_2_2:
return SPV_ENV_OPENCL_2_2;
case shaderc_spvc_spv_env_opengl_4_0:
return SPV_ENV_OPENGL_4_0;
case shaderc_spvc_spv_env_opengl_4_1:
return SPV_ENV_OPENGL_4_1;
case shaderc_spvc_spv_env_opengl_4_2:
return SPV_ENV_OPENGL_4_2;
case shaderc_spvc_spv_env_opengl_4_3:
return SPV_ENV_OPENGL_4_3;
case shaderc_spvc_spv_env_opengl_4_5:
return SPV_ENV_OPENGL_4_5;
case shaderc_spvc_spv_env_universal_1_2:
return SPV_ENV_UNIVERSAL_1_2;
case shaderc_spvc_spv_env_opencl_1_2:
return SPV_ENV_OPENCL_1_2;
case shaderc_spvc_spv_env_opencl_embedded_1_2:
return SPV_ENV_OPENCL_EMBEDDED_1_2;
case shaderc_spvc_spv_env_opencl_2_0:
return SPV_ENV_OPENCL_2_0;
case shaderc_spvc_spv_env_opencl_embedded_2_0:
return SPV_ENV_OPENCL_EMBEDDED_2_0;
case shaderc_spvc_spv_env_opencl_embedded_2_1:
return SPV_ENV_OPENCL_EMBEDDED_2_1;
case shaderc_spvc_spv_env_opencl_embedded_2_2:
return SPV_ENV_OPENCL_EMBEDDED_2_2;
case shaderc_spvc_spv_env_universal_1_3:
return SPV_ENV_UNIVERSAL_1_3;
case shaderc_spvc_spv_env_vulkan_1_1:
return SPV_ENV_VULKAN_1_1;
case shaderc_spvc_spv_env_webgpu_0:
return SPV_ENV_WEBGPU_0;
case shaderc_spvc_spv_env_universal_1_4:
return SPV_ENV_UNIVERSAL_1_4;
case shaderc_spvc_spv_env_vulkan_1_1_spirv_1_4:
return SPV_ENV_VULKAN_1_1_SPIRV_1_4;
case shaderc_spvc_spv_env_universal_1_5:
return SPV_ENV_UNIVERSAL_1_5;
case shaderc_spvc_spv_env_vulkan_1_2:
return SPV_ENV_VULKAN_1_2;
}
shaderc_spvc::ErrorLog(nullptr)
<< "Attempted to convert unknown shaderc_spvc_spv_env value, " << env;
assert(false);
return SPV_ENV_UNIVERSAL_1_0;
}
shaderc_spvc_status get_location_info_impl(
spirv_cross::Compiler* compiler,
const spirv_cross::SmallVector<spirv_cross::Resource>& resources,
shaderc_spvc_resource_location_info* locations, size_t* location_count) {
*location_count = resources.size();
if (!locations) return shaderc_spvc_status_success;
for (const auto& resource : resources) {
if (!compiler->get_decoration_bitset(resource.id)
.get(spv::DecorationLocation)) {
return shaderc_spvc_status_internal_error;
}
locations->id = resource.id;
if (compiler->get_decoration_bitset(resource.id)
.get(spv::DecorationLocation)) {
locations->location =
compiler->get_decoration(resource.id, spv::DecorationLocation);
locations->has_location = true;
} else {
locations->has_location = false;
}
locations++;
}
return shaderc_spvc_status_success;
}
} // namespace
shaderc_spvc_context_t shaderc_spvc_context_create() {
return new (std::nothrow) shaderc_spvc_context;
}
void shaderc_spvc_context_destroy(shaderc_spvc_context_t context) {
if (context) delete context;
}
const char* shaderc_spvc_context_get_messages(
const shaderc_spvc_context_t context) {
for (const auto& message : context->messages) {
context->messages_string += message;
}
context->messages.clear();
return context->messages_string.c_str();
}
shaderc_spvc_status shaderc_spvc_context_get_compiler(
const shaderc_spvc_context_t context, void** compiler) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_OUT_PARAM(context, compiler, "compiler");
*compiler = context->cross_compiler.get();
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_context_set_use_spvc_parser(
shaderc_spvc_context_t context, bool b) {
CHECK_CONTEXT(context);
context->use_spvc_parser = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_compile_options_t shaderc_spvc_compile_options_create(
shaderc_spvc_spv_env source_env, shaderc_spvc_spv_env target_env) {
shaderc_spvc_compile_options_t options =
new (std::nothrow) shaderc_spvc_compile_options;
if (options) {
options->glsl.version = 0;
options->source_env = shaderc_spvc_spv_env_to_spv_target_env(source_env);
options->target_env = shaderc_spvc_spv_env_to_spv_target_env(target_env);
}
return options;
}
shaderc_spvc_compile_options_t shaderc_spvc_compile_options_clone(
shaderc_spvc_compile_options_t options) {
if (options) return new (std::nothrow) shaderc_spvc_compile_options(*options);
return nullptr;
}
void shaderc_spvc_compile_options_destroy(
shaderc_spvc_compile_options_t options) {
if (options) delete options;
}
// DEPRECATED
shaderc_spvc_status shaderc_spvc_compile_options_set_source_env(
shaderc_spvc_compile_options_t options, shaderc_target_env env,
shaderc_env_version version) {
CHECK_OPTIONS(nullptr, options);
options->source_env = spvc_private::get_spv_target_env(env, version);
return shaderc_spvc_status_success;
}
// DEPRECATED
shaderc_spvc_status shaderc_spvc_compile_options_set_target_env(
shaderc_spvc_compile_options_t options, shaderc_target_env env,
shaderc_env_version version) {
CHECK_OPTIONS(nullptr, options);
options->target_env = spvc_private::get_spv_target_env(env, version);
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_entry_point(
shaderc_spvc_compile_options_t options, const char* entry_point) {
CHECK_OPTIONS(nullptr, options);
CHECK_IN_PARAM(nullptr, entry_point, "entry_point");
options->entry_point = entry_point;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_remove_unused_variables(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->remove_unused_variables = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_robust_buffer_access_pass(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->robust_buffer_access_pass = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_emit_line_directives(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->glsl.emit_line_directives = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_vulkan_semantics(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->glsl.vulkan_semantics = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_separate_shader_objects(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->glsl.separate_shader_objects = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_flatten_ubo(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->flatten_ubo = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_glsl_language_version(
shaderc_spvc_compile_options_t options, uint32_t version) {
CHECK_OPTIONS(nullptr, options);
options->glsl.version = version;
return shaderc_spvc_status_success;
}
shaderc_spvc_status
shaderc_spvc_compile_options_set_flatten_multidimensional_arrays(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->glsl.flatten_multidimensional_arrays = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status
shaderc_spvc_compile_options_set_force_zero_initialized_variables(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->glsl.force_zero_initialized_variables = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_es(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->forced_es_setting = b;
options->force_es = true;
return shaderc_spvc_status_success;
}
shaderc_spvc_status
shaderc_spvc_compile_options_set_glsl_emit_push_constant_as_ubo(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->glsl.emit_push_constant_as_uniform_buffer = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_msl_language_version(
shaderc_spvc_compile_options_t options, uint32_t version) {
CHECK_OPTIONS(nullptr, options);
options->msl.msl_version = version;
return shaderc_spvc_status_success;
}
shaderc_spvc_status
shaderc_spvc_compile_options_set_msl_swizzle_texture_samples(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->msl.swizzle_texture_samples = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_msl_platform(
shaderc_spvc_compile_options_t options,
shaderc_spvc_msl_platform platform) {
CHECK_OPTIONS(nullptr, options);
switch (platform) {
case shaderc_spvc_msl_platform_ios:
options->msl.platform = spirv_cross::CompilerMSL::Options::iOS;
break;
case shaderc_spvc_msl_platform_macos:
options->msl.platform = spirv_cross::CompilerMSL::Options::macOS;
break;
}
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_msl_pad_fragment_output(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->msl.pad_fragment_output_components = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_msl_capture(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->msl.capture_output_to_buffer = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_msl_domain_lower_left(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->msl.tess_domain_origin_lower_left = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_msl_argument_buffers(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->msl.argument_buffers = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status
shaderc_spvc_compile_options_set_msl_discrete_descriptor_sets(
shaderc_spvc_compile_options_t options, const uint32_t* descriptors,
size_t num_descriptors) {
CHECK_OPTIONS(nullptr, options);
options->msl_discrete_descriptor_sets.resize(num_descriptors);
std::copy_n(descriptors, num_descriptors,
options->msl_discrete_descriptor_sets.begin());
return shaderc_spvc_status_success;
}
shaderc_spvc_status
shaderc_spvc_compile_options_set_msl_enable_point_size_builtin(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->msl.enable_point_size_builtin = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status
shaderc_spvc_compile_options_set_msl_buffer_size_buffer_index(
shaderc_spvc_compile_options_t options, uint32_t index) {
CHECK_OPTIONS(nullptr, options);
options->msl.buffer_size_buffer_index = index;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_hlsl_shader_model(
shaderc_spvc_compile_options_t options, uint32_t model) {
CHECK_OPTIONS(nullptr, options);
options->hlsl.shader_model = model;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_hlsl_point_size_compat(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->hlsl.point_size_compat = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_hlsl_point_coord_compat(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->hlsl.point_coord_compat = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_hlsl_enable_16bit_types(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->hlsl.enable_16bit_types = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status
shaderc_spvc_compile_options_set_hlsl_nonwritable_uav_texture_as_srv(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->hlsl.nonwritable_uav_texture_as_srv = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_set_hlsl_force_storage_buffer_as_uav(
const shaderc_spvc_context_t context, uint32_t desc_set, uint32_t binding) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
auto* hlsl_compiler = reinterpret_cast<spirv_cross::CompilerHLSL*>(
context->cross_compiler.get());
hlsl_compiler->set_hlsl_force_storage_buffer_as_uav(desc_set, binding);
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_fixup_clipspace(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->glsl.vertex.fixup_clipspace = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_flip_vert_y(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->glsl.vertex.flip_vert_y = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_validate(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->validate = b;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_compile_options_set_optimize(
shaderc_spvc_compile_options_t options, bool b) {
CHECK_OPTIONS(nullptr, options);
options->optimize = b;
return shaderc_spvc_status_success;
}
size_t shaderc_spvc_compile_options_set_for_fuzzing(
shaderc_spvc_compile_options_t options, const uint8_t* data, size_t size) {
if (!options || !data || size < sizeof(*options)) return 0;
memcpy(static_cast<void*>(options), data, sizeof(*options));
return sizeof(*options);
}
shaderc_spvc_status shaderc_spvc_initialize_impl(
const shaderc_spvc_context_t context, const uint32_t* source,
size_t source_len, shaderc_spvc_compile_options_t options,
shaderc_spvc_status (*generator)(const shaderc_spvc_context_t,
const uint32_t*, size_t,
shaderc_spvc_compile_options_t)) {
shaderc_spvc_status status = spvc_private::validate_and_translate_spirv(
context, source, source_len, options, &context->intermediate_shader);
if (status != shaderc_spvc_status_success) return status;
status = generator(context, context->intermediate_shader.data(),
context->intermediate_shader.size(), options);
if (status != shaderc_spvc_status_success) return status;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_initialize_for_glsl(
const shaderc_spvc_context_t context, const uint32_t* source,
size_t source_len, shaderc_spvc_compile_options_t options) {
CHECK_CONTEXT(context);
CHECK_OPTIONS(context, options);
CHECK_IN_PARAM(context, source, "source");
context->target_lang = SPVC_TARGET_LANG_GLSL;
return shaderc_spvc_initialize_impl(context, source, source_len, options,
spvc_private::generate_glsl_compiler);
}
shaderc_spvc_status shaderc_spvc_initialize_for_hlsl(
const shaderc_spvc_context_t context, const uint32_t* source,
size_t source_len, shaderc_spvc_compile_options_t options) {
CHECK_CONTEXT(context);
CHECK_OPTIONS(context, options);
CHECK_IN_PARAM(context, source, "source");
context->target_lang = SPVC_TARGET_LANG_HLSL;
return shaderc_spvc_initialize_impl(context, source, source_len, options,
spvc_private::generate_hlsl_compiler);
}
shaderc_spvc_status shaderc_spvc_initialize_for_msl(
const shaderc_spvc_context_t context, const uint32_t* source,
size_t source_len, shaderc_spvc_compile_options_t options) {
CHECK_CONTEXT(context);
CHECK_OPTIONS(context, options);
CHECK_IN_PARAM(context, source, "source");
context->target_lang = SPVC_TARGET_LANG_MSL;
return shaderc_spvc_initialize_impl(context, source, source_len, options,
spvc_private::generate_msl_compiler);
}
shaderc_spvc_status shaderc_spvc_initialize_for_vulkan(
const shaderc_spvc_context_t context, const uint32_t* source,
size_t source_len, shaderc_spvc_compile_options_t options) {
CHECK_CONTEXT(context);
CHECK_OPTIONS(context, options);
CHECK_IN_PARAM(context, source, "source");
context->target_lang = SPVC_TARGET_LANG_VULKAN;
return shaderc_spvc_initialize_impl(context, source, source_len, options,
spvc_private::generate_vulkan_compiler);
}
shaderc_spvc_status shaderc_spvc_compile_shader(
const shaderc_spvc_context_t context,
shaderc_spvc_compilation_result_t result) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
if (context->target_lang == SPVC_TARGET_LANG_UNKNOWN) {
shaderc_spvc::ErrorLog(context)
<< "Invoked compile_shader with unknown language";
return shaderc_spvc_status_configuration_error;
}
if (context->target_lang == SPVC_TARGET_LANG_VULKAN) {
// No actual cross compilation is needed, since the intermediate shader is
// already in Vulkan SPIR->V.
result->binary_output = context->intermediate_shader;
return shaderc_spvc_status_success;
} else {
shaderc_spvc_status status =
spvc_private::generate_shader(context->cross_compiler.get(), result);
if (status != shaderc_spvc_status_success) {
shaderc_spvc::ErrorLog(context) << "Compilation failed. Partial source:";
if (context->target_lang == SPVC_TARGET_LANG_GLSL) {
spirv_cross::CompilerGLSL* cast_compiler =
reinterpret_cast<spirv_cross::CompilerGLSL*>(
context->cross_compiler.get());
shaderc_spvc::ErrorLog(context) << cast_compiler->get_partial_source();
} else if (context->target_lang == SPVC_TARGET_LANG_HLSL) {
spirv_cross::CompilerHLSL* cast_compiler =
reinterpret_cast<spirv_cross::CompilerHLSL*>(
context->cross_compiler.get());
shaderc_spvc::ErrorLog(context) << cast_compiler->get_partial_source();
} else if (context->target_lang == SPVC_TARGET_LANG_MSL) {
spirv_cross::CompilerMSL* cast_compiler =
reinterpret_cast<spirv_cross::CompilerMSL*>(
context->cross_compiler.get());
shaderc_spvc::ErrorLog(context) << cast_compiler->get_partial_source();
} else {
shaderc_spvc::ErrorLog(context)
<< "Unexpected target language in context";
}
context->cross_compiler.reset();
}
return status;
}
}
shaderc_spvc_status shaderc_spvc_set_decoration(
const shaderc_spvc_context_t context, uint32_t id,
shaderc_spvc_decoration decoration, uint32_t argument) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
spv::Decoration spirv_cross_decoration;
shaderc_spvc_status status =
spvc_private::shaderc_spvc_decoration_to_spirv_cross_decoration(
decoration, &spirv_cross_decoration);
if (status == shaderc_spvc_status_success) {
context->cross_compiler->set_decoration(static_cast<spirv_cross::ID>(id),
spirv_cross_decoration, argument);
} else {
shaderc_spvc::ErrorLog(context) << "Decoration Conversion failed. "
"shaderc_spvc_decoration not supported.";
}
return status;
}
shaderc_spvc_status shaderc_spvc_get_decoration(
const shaderc_spvc_context_t context, uint32_t id,
shaderc_spvc_decoration decoration, uint32_t* value) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_OUT_PARAM(context, value, "value");
spv::Decoration spirv_cross_decoration;
shaderc_spvc_status status =
spvc_private::shaderc_spvc_decoration_to_spirv_cross_decoration(
decoration, &spirv_cross_decoration);
if (status != shaderc_spvc_status_success) {
shaderc_spvc::ErrorLog(context) << "Decoration conversion failed. "
"shaderc_spvc_decoration not supported.";
return status;
}
*value = context->cross_compiler->get_decoration(
static_cast<spirv_cross::ID>(id), spirv_cross_decoration);
if (*value == 0) {
shaderc_spvc::ErrorLog(context)
<< "Getting decoration failed. id not found.";
return shaderc_spvc_status_compilation_error;
}
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_unset_decoration(
const shaderc_spvc_context_t context, uint32_t id,
shaderc_spvc_decoration decoration) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
spv::Decoration spirv_cross_decoration;
shaderc_spvc_status status =
spvc_private::shaderc_spvc_decoration_to_spirv_cross_decoration(
decoration, &spirv_cross_decoration);
if (status == shaderc_spvc_status_success) {
context->cross_compiler->unset_decoration(static_cast<spirv_cross::ID>(id),
spirv_cross_decoration);
} else {
shaderc_spvc::ErrorLog(context) << "Decoration conversion failed. "
"shaderc_spvc_decoration not supported.";
}
return status;
}
shaderc_spvc_status shaderc_spvc_get_combined_image_samplers(
const shaderc_spvc_context_t context,
shaderc_spvc_combined_image_sampler* samplers, size_t* num_samplers) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_OUT_PARAM(context, num_samplers, "num_samplers");
*num_samplers = context->cross_compiler->get_combined_image_samplers().size();
if (!samplers) return shaderc_spvc_status_success;
for (const auto& combined :
context->cross_compiler->get_combined_image_samplers()) {
samplers->combined_id = combined.combined_id;
samplers->image_id = combined.image_id;
samplers->sampler_id = combined.sampler_id;
samplers++;
}
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_set_name(const shaderc_spvc_context_t context,
uint32_t id, const char* name) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_IN_PARAM(context, name, "name");
context->cross_compiler->set_name(id, name);
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_add_msl_resource_binding(
const shaderc_spvc_context_t context,
const shaderc_spvc_msl_resource_binding binding) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
if (context->target_lang != SPVC_TARGET_LANG_MSL) {
shaderc_spvc::ErrorLog(context)
<< "Invoked add_msl_resource_binding when target language was not MSL";
return shaderc_spvc_status_configuration_error;
}
spirv_cross::MSLResourceBinding cross_binding;
cross_binding.stage = spvc_model_to_spv_model(binding.stage);
cross_binding.binding = binding.binding;
cross_binding.desc_set = binding.desc_set;
cross_binding.msl_buffer = binding.msl_buffer;
cross_binding.msl_texture = binding.msl_texture;
cross_binding.msl_sampler = binding.msl_sampler;
reinterpret_cast<spirv_cross::CompilerMSL*>(context->cross_compiler.get())
->add_msl_resource_binding(cross_binding);
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_get_workgroup_size(
const shaderc_spvc_context_t context, const char* function_name,
shaderc_spvc_execution_model execution_model,
shaderc_spvc_workgroup_size* workgroup_size) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_IN_PARAM(context, function_name, "function_name");
CHECK_OUT_PARAM(context, workgroup_size, "workgroup_size");
const auto& cross_size =
context->cross_compiler
->get_entry_point(function_name,
spvc_model_to_spv_model(execution_model))
.workgroup_size;
workgroup_size->x = cross_size.x;
workgroup_size->y = cross_size.y;
workgroup_size->z = cross_size.z;
workgroup_size->constant = cross_size.constant;
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_needs_buffer_size_buffer(
const shaderc_spvc_context_t context, bool* b) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_OUT_PARAM(context, b, "b");
if (context->target_lang != SPVC_TARGET_LANG_MSL) {
shaderc_spvc::ErrorLog(context)
<< "Invoked needs_buffer_size_buffer when target language was not MSL";
return shaderc_spvc_status_configuration_error;
}
*b =
reinterpret_cast<spirv_cross::CompilerMSL*>(context->cross_compiler.get())
->needs_buffer_size_buffer();
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_build_combined_image_samplers(
const shaderc_spvc_context_t context) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
context->cross_compiler->build_combined_image_samplers();
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_get_execution_model(
const shaderc_spvc_context_t context,
shaderc_spvc_execution_model* execution_model) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_OUT_PARAM(context, execution_model, "execution_model");
auto spirv_model = context->cross_compiler->get_execution_model();
*execution_model = spv_model_to_spvc_model(spirv_model);
if (*execution_model == shaderc_spvc_execution_model_invalid) {
shaderc_spvc::ErrorLog(context)
<< "Shader execution model appears to be of an unsupported type";
return shaderc_spvc_status_internal_error;
}
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_get_push_constant_buffer_count(
const shaderc_spvc_context_t context, size_t* count) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_OUT_PARAM(context, count, "count");
*count = context->cross_compiler->get_shader_resources()
.push_constant_buffers.size();
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_get_binding_info(
const shaderc_spvc_context_t context, shaderc_spvc_shader_resource resource,
shaderc_spvc_binding_type binding_type, shaderc_spvc_binding_info* bindings,
size_t* binding_count) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_OUT_PARAM(context, binding_count, "binding_count");
auto* compiler = context->cross_compiler.get();
const auto& resources = compiler->get_shader_resources();
const auto* shader_resources = get_shader_resources(resources, resource);
*binding_count = shader_resources->size();
if (!bindings) return shaderc_spvc_status_success;
for (const auto& shader_resource : *shader_resources) {
bindings->texture_dimension = shaderc_spvc_texture_view_dimension_undefined;
bindings->texture_component_type = shaderc_spvc_texture_format_type_float;
if (!compiler->get_decoration_bitset(shader_resource.id)
.get(spv::DecorationBinding)) {
shaderc_spvc::ErrorLog(context)
<< "Unable to get binding decoration for shader resource";
return shaderc_spvc_status_internal_error;
}
uint32_t binding_decoration =
compiler->get_decoration(shader_resource.id, spv::DecorationBinding);
bindings->binding = binding_decoration;
if (!compiler->get_decoration_bitset(shader_resource.id)
.get(spv::DecorationDescriptorSet)) {
shaderc_spvc::ErrorLog(context)
<< "Unable to get descriptor set decoration for shader resource";
return shaderc_spvc_status_internal_error;
}
uint32_t descriptor_set_decoration = compiler->get_decoration(
shader_resource.id, spv::DecorationDescriptorSet);
bindings->set = descriptor_set_decoration;
bindings->id = shader_resource.id;
bindings->base_type_id = shader_resource.base_type_id;
if (binding_type == shaderc_spvc_binding_type_uniform_buffer ||
binding_type == shaderc_spvc_binding_type_storage_buffer) {
// Determine buffer size, with a minimum of 1 element in the runtime array
spirv_cross::SPIRType type =
compiler->get_type(shader_resource.base_type_id);
bindings->minimum_buffer_size =
compiler->get_declared_struct_size_runtime_array(type, 1);
}
switch (binding_type) {
case shaderc_spvc_binding_type_sampled_texture: {
spirv_cross::SPIRType::ImageType imageType =
compiler->get_type(bindings->base_type_id).image;
spirv_cross::SPIRType::BaseType textureComponentType =
compiler->get_type(imageType.type).basetype;
bindings->multisampled = imageType.ms;
bindings->texture_dimension = spirv_dim_to_texture_view_dimension(
imageType.dim, imageType.arrayed);
bindings->texture_component_type =
spirv_cross_base_type_to_texture_format_type(textureComponentType);
bindings->binding_type = binding_type;
} break;
case shaderc_spvc_binding_type_storage_buffer: {
// Differentiate between readonly storage bindings and writable ones
// based on the NonWritable decoration
spirv_cross::Bitset flags =
compiler->get_buffer_block_flags(shader_resource.id);
if (flags.get(spv::DecorationNonWritable)) {
bindings->binding_type =
shaderc_spvc_binding_type_readonly_storage_buffer;
} else {
bindings->binding_type = shaderc_spvc_binding_type_storage_buffer;
}
} break;
case shaderc_spvc_binding_type_storage_texture: {
spirv_cross::Bitset flags = compiler->get_decoration_bitset(shader_resource.id);
if (flags.get(spv::DecorationNonReadable)) {
bindings->binding_type = shaderc_spvc_binding_type_writeonly_storage_texture;
} else if (flags.get(spv::DecorationNonWritable)) {
bindings->binding_type = shaderc_spvc_binding_type_readonly_storage_texture;
} else {
bindings->binding_type = shaderc_spvc_binding_type_storage_texture;
}
spirv_cross::SPIRType::ImageType imageType =
compiler->get_type(bindings->base_type_id).image;
bindings->storage_texture_format =
spv_image_format_to_storage_texture_format(imageType.format);
bindings->texture_dimension = spirv_dim_to_texture_view_dimension(
imageType.dim, imageType.arrayed);
bindings->multisampled = imageType.ms;
} break;
case shaderc_spvc_binding_type_sampler: {
// The inheritance hierarchy here is odd, it goes
// Compiler->CompilerGLSL->CompilerHLSL/MSL/Reflection.
// CompilerGLSL is an intermediate super class for all of the other leaf
// classes. The method we need is defined on CompilerGLSL, not Compiler.
// This cast is safe, since we only should ever have a
// CompilerGLSL/HLSL/MSL/Reflection in |cross_compiler|.
auto* glsl_compiler = reinterpret_cast<spirv_cross::CompilerGLSL*>(
context->cross_compiler.get());
if (glsl_compiler->variable_is_depth_or_compare(shader_resource.id)) {
bindings->binding_type = shaderc_spvc_binding_type_comparison_sampler;
} else {
bindings->binding_type = shaderc_spvc_binding_type_sampler;
}
} break;
default:
bindings->binding_type = binding_type;
}
bindings++;
}
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_get_input_stage_location_info(
const shaderc_spvc_context_t context,
shaderc_spvc_resource_location_info* locations, size_t* location_count) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_OUT_PARAM(context, location_count, "location_count");
auto* compiler = context->cross_compiler.get();
shaderc_spvc_status status = get_location_info_impl(
compiler, compiler->get_shader_resources().stage_inputs, locations,
location_count);
if (status != shaderc_spvc_status_success) {
shaderc_spvc::ErrorLog(context)
<< "Unable to get location decoration for stage input";
}
return status;
}
shaderc_spvc_status shaderc_spvc_get_output_stage_location_info(
const shaderc_spvc_context_t context,
shaderc_spvc_resource_location_info* locations, size_t* location_count) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_OUT_PARAM(context, location_count, "location_count");
auto* compiler = context->cross_compiler.get();
shaderc_spvc_status status = get_location_info_impl(
compiler, compiler->get_shader_resources().stage_outputs, locations,
location_count);
if (status != shaderc_spvc_status_success) {
shaderc_spvc::ErrorLog(context)
<< "Unable to get location decoration for stage output";
}
return status;
}
shaderc_spvc_status shaderc_spvc_get_output_stage_type_info(
const shaderc_spvc_context_t context,
shaderc_spvc_resource_type_info* types, size_t* type_count) {
CHECK_CONTEXT(context);
CHECK_CROSS_COMPILER(context, context->cross_compiler);
CHECK_OUT_PARAM(context, type_count, "type_count");
auto* compiler = context->cross_compiler.get();
const auto& resources = compiler->get_shader_resources().stage_outputs;
*type_count = resources.size();
if (!types) return shaderc_spvc_status_success;
for (const auto& resource : resources) {
if (!compiler->get_decoration_bitset(resource.id)
.get(spv::DecorationLocation)) {
shaderc_spvc::ErrorLog(context)
<< "Unable to get location decoration for stage output";
return shaderc_spvc_status_internal_error;
}
types->location =
compiler->get_decoration(resource.id, spv::DecorationLocation);
spirv_cross::SPIRType::BaseType base_type =
compiler->get_type(resource.base_type_id).basetype;
types->type = spirv_cross_base_type_to_texture_format_type(base_type);
types++;
}
return shaderc_spvc_status_success;
}
shaderc_spvc_compilation_result_t shaderc_spvc_result_create() {
return new (std::nothrow) shaderc_spvc_compilation_result;
}
void shaderc_spvc_result_destroy(shaderc_spvc_compilation_result_t result) {
if (result) delete result;
}
shaderc_spvc_status shaderc_spvc_result_get_string_output(
const shaderc_spvc_compilation_result_t result, const char** str) {
CHECK_RESULT(nullptr, result);
CHECK_OUT_PARAM(nullptr, str, "str");
*str = result->string_output.c_str();
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_result_get_binary_output(
const shaderc_spvc_compilation_result_t result,
const uint32_t** binary_output) {
CHECK_RESULT(nullptr, result);
CHECK_OUT_PARAM(nullptr, binary_output, "binary_output");
*binary_output = result->binary_output.data();
return shaderc_spvc_status_success;
}
shaderc_spvc_status shaderc_spvc_result_get_binary_length(
const shaderc_spvc_compilation_result_t result, uint32_t* len) {
CHECK_RESULT(nullptr, result);
CHECK_OUT_PARAM(nullptr, len, "len");
*len = result->binary_output.size();
return shaderc_spvc_status_success;
}