2019-01-10 06:23:47 +03:00
/*
2020-02-05 08:38:12 +03:00
* Copyright 2015 - 2020 Arm Limited
2019-01-10 06:23:47 +03:00
*
* 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 .
*/
2020-12-06 06:13:26 +03:00
/*
* At your option , you may choose to accept this material under either :
* 1. The Apache License , Version 2.0 , found at < http : //www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License , found at < http : //opensource.org/licenses/MIT>.
* SPDX - License - Identifier : Apache - 2.0 OR MIT .
*/
2019-01-10 06:23:47 +03:00
# include "spirv_cpp.hpp"
# include "spirv_cross_util.hpp"
# include "spirv_glsl.hpp"
# include "spirv_hlsl.hpp"
# include "spirv_msl.hpp"
# include "spirv_parser.hpp"
# include "spirv_reflect.hpp"
# include <algorithm>
# include <cstdio>
# include <cstring>
# include <functional>
# include <limits>
# include <memory>
# include <stdexcept>
# include <unordered_map>
# include <unordered_set>
2019-06-07 08:04:16 +03:00
# ifdef HAVE_SPIRV_CROSS_GIT_VERSION
# include "gitversion.h"
# endif
2019-01-10 06:23:47 +03:00
using namespace spv ;
2019-03-31 07:03:28 +03:00
using namespace SPIRV_CROSS_NAMESPACE ;
2019-01-10 06:23:47 +03:00
using namespace std ;
# ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
static inline void THROW ( const char * str )
{
fprintf ( stderr , " SPIRV-Cross will abort: %s \n " , str ) ;
fflush ( stderr ) ;
abort ( ) ;
}
# else
# define THROW(x) throw runtime_error(x)
# endif
struct CLIParser ;
struct CLICallbacks
{
void add ( const char * cli , const function < void ( CLIParser & ) > & func )
{
callbacks [ cli ] = func ;
}
unordered_map < string , function < void ( CLIParser & ) > > callbacks ;
function < void ( ) > error_handler ;
function < void ( const char * ) > default_handler ;
} ;
struct CLIParser
{
CLIParser ( CLICallbacks cbs_ , int argc_ , char * argv_ [ ] )
: cbs ( move ( cbs_ ) )
, argc ( argc_ )
, argv ( argv_ )
{
}
bool parse ( )
{
# ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
try
# endif
{
while ( argc & & ! ended_state )
{
const char * next = * argv + + ;
argc - - ;
if ( * next ! = ' - ' & & cbs . default_handler )
{
cbs . default_handler ( next ) ;
}
else
{
auto itr = cbs . callbacks . find ( next ) ;
if ( itr = = : : end ( cbs . callbacks ) )
{
THROW ( " Invalid argument " ) ;
}
itr - > second ( * this ) ;
}
}
return true ;
}
# ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
catch ( . . . )
{
if ( cbs . error_handler )
{
cbs . error_handler ( ) ;
}
return false ;
}
# endif
}
void end ( )
{
ended_state = true ;
}
uint32_t next_uint ( )
{
if ( ! argc )
{
THROW ( " Tried to parse uint, but nothing left in arguments " ) ;
}
uint64_t val = stoul ( * argv ) ;
if ( val > numeric_limits < uint32_t > : : max ( ) )
{
THROW ( " next_uint() out of range " ) ;
}
argc - - ;
argv + + ;
return uint32_t ( val ) ;
}
2020-04-25 05:07:42 +03:00
uint32_t next_hex_uint ( )
{
if ( ! argc )
{
THROW ( " Tried to parse uint, but nothing left in arguments " ) ;
}
uint64_t val = stoul ( * argv , nullptr , 16 ) ;
if ( val > numeric_limits < uint32_t > : : max ( ) )
{
THROW ( " next_uint() out of range " ) ;
}
argc - - ;
argv + + ;
return uint32_t ( val ) ;
}
2019-01-10 06:23:47 +03:00
double next_double ( )
{
if ( ! argc )
{
THROW ( " Tried to parse double, but nothing left in arguments " ) ;
}
double val = stod ( * argv ) ;
argc - - ;
argv + + ;
return val ;
}
// Return a string only if it's not prefixed with `--`, otherwise return the default value
const char * next_value_string ( const char * default_value )
{
if ( ! argc )
{
return default_value ;
}
if ( 0 = = strncmp ( " -- " , * argv , 2 ) )
{
return default_value ;
}
return next_string ( ) ;
}
const char * next_string ( )
{
if ( ! argc )
{
THROW ( " Tried to parse string, but nothing left in arguments " ) ;
}
const char * ret = * argv ;
argc - - ;
argv + + ;
return ret ;
}
CLICallbacks cbs ;
int argc ;
char * * argv ;
bool ended_state = false ;
} ;
2020-04-10 02:55:23 +03:00
# if defined(__clang__) || defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# elif defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4996)
# endif
2019-01-10 06:23:47 +03:00
static vector < uint32_t > read_spirv_file ( const char * path )
{
FILE * file = fopen ( path , " rb " ) ;
if ( ! file )
{
fprintf ( stderr , " Failed to open SPIR-V file: %s \n " , path ) ;
return { } ;
}
fseek ( file , 0 , SEEK_END ) ;
long len = ftell ( file ) / sizeof ( uint32_t ) ;
rewind ( file ) ;
vector < uint32_t > spirv ( len ) ;
if ( fread ( spirv . data ( ) , sizeof ( uint32_t ) , len , file ) ! = size_t ( len ) )
spirv . clear ( ) ;
fclose ( file ) ;
return spirv ;
}
static bool write_string_to_file ( const char * path , const char * string )
{
FILE * file = fopen ( path , " w " ) ;
if ( ! file )
{
fprintf ( stderr , " Failed to write file: %s \n " , path ) ;
return false ;
}
fprintf ( file , " %s " , string ) ;
fclose ( file ) ;
return true ;
}
2020-04-10 02:55:23 +03:00
# if defined(__clang__) || defined(__GNUC__)
# pragma GCC diagnostic pop
# elif defined(_MSC_VER)
# pragma warning(pop)
# endif
2019-04-15 07:53:50 +03:00
static void print_resources ( const Compiler & compiler , const char * tag , const SmallVector < Resource > & resources )
2019-01-10 06:23:47 +03:00
{
fprintf ( stderr , " %s \n " , tag ) ;
fprintf ( stderr , " ============= \n \n " ) ;
bool print_ssbo = ! strcmp ( tag , " ssbos " ) ;
for ( auto & res : resources )
{
auto & type = compiler . get_type ( res . type_id ) ;
if ( print_ssbo & & compiler . buffer_is_hlsl_counter_buffer ( res . id ) )
continue ;
// If we don't have a name, use the fallback for the type instead of the variable
// for SSBOs and UBOs since those are the only meaningful names to use externally.
// Push constant blocks are still accessed by name and not block name, even though they are technically Blocks.
bool is_push_constant = compiler . get_storage_class ( res . id ) = = StorageClassPushConstant ;
bool is_block = compiler . get_decoration_bitset ( type . self ) . get ( DecorationBlock ) | |
compiler . get_decoration_bitset ( type . self ) . get ( DecorationBufferBlock ) ;
bool is_sized_block = is_block & & ( compiler . get_storage_class ( res . id ) = = StorageClassUniform | |
compiler . get_storage_class ( res . id ) = = StorageClassUniformConstant ) ;
2019-09-07 18:07:48 +03:00
ID fallback_id = ! is_push_constant & & is_block ? ID ( res . base_type_id ) : ID ( res . id ) ;
2019-01-10 06:23:47 +03:00
uint32_t block_size = 0 ;
uint32_t runtime_array_stride = 0 ;
if ( is_sized_block )
{
auto & base_type = compiler . get_type ( res . base_type_id ) ;
block_size = uint32_t ( compiler . get_declared_struct_size ( base_type ) ) ;
runtime_array_stride = uint32_t ( compiler . get_declared_struct_size_runtime_array ( base_type , 1 ) -
compiler . get_declared_struct_size_runtime_array ( base_type , 0 ) ) ;
}
Bitset mask ;
if ( print_ssbo )
mask = compiler . get_buffer_block_flags ( res . id ) ;
else
mask = compiler . get_decoration_bitset ( res . id ) ;
string array ;
for ( auto arr : type . array )
array = join ( " [ " , arr ? convert_to_string ( arr ) : " " , " ] " ) + array ;
2019-09-07 18:07:48 +03:00
fprintf ( stderr , " ID %03u : %s%s " , uint32_t ( res . id ) ,
2019-01-10 06:23:47 +03:00
! res . name . empty ( ) ? res . name . c_str ( ) : compiler . get_fallback_name ( fallback_id ) . c_str ( ) , array . c_str ( ) ) ;
if ( mask . get ( DecorationLocation ) )
fprintf ( stderr , " (Location : %u) " , compiler . get_decoration ( res . id , DecorationLocation ) ) ;
if ( mask . get ( DecorationDescriptorSet ) )
fprintf ( stderr , " (Set : %u) " , compiler . get_decoration ( res . id , DecorationDescriptorSet ) ) ;
if ( mask . get ( DecorationBinding ) )
fprintf ( stderr , " (Binding : %u) " , compiler . get_decoration ( res . id , DecorationBinding ) ) ;
2020-04-05 04:56:27 +03:00
if ( static_cast < const CompilerGLSL & > ( compiler ) . variable_is_depth_or_compare ( res . id ) )
fprintf ( stderr , " (comparison) " ) ;
2019-01-10 06:23:47 +03:00
if ( mask . get ( DecorationInputAttachmentIndex ) )
fprintf ( stderr , " (Attachment : %u) " , compiler . get_decoration ( res . id , DecorationInputAttachmentIndex ) ) ;
if ( mask . get ( DecorationNonReadable ) )
fprintf ( stderr , " writeonly " ) ;
if ( mask . get ( DecorationNonWritable ) )
fprintf ( stderr , " readonly " ) ;
if ( is_sized_block )
{
fprintf ( stderr , " (BlockSize : %u bytes) " , block_size ) ;
if ( runtime_array_stride )
fprintf ( stderr , " (Unsized array stride: %u bytes) " , runtime_array_stride ) ;
}
uint32_t counter_id = 0 ;
if ( print_ssbo & & compiler . buffer_get_hlsl_counter_buffer ( res . id , counter_id ) )
fprintf ( stderr , " (HLSL counter buffer ID: %u) " , counter_id ) ;
fprintf ( stderr , " \n " ) ;
}
fprintf ( stderr , " ============= \n \n " ) ;
}
static const char * execution_model_to_str ( spv : : ExecutionModel model )
{
switch ( model )
{
case spv : : ExecutionModelVertex :
return " vertex " ;
case spv : : ExecutionModelTessellationControl :
return " tessellation control " ;
case ExecutionModelTessellationEvaluation :
return " tessellation evaluation " ;
case ExecutionModelGeometry :
return " geometry " ;
case ExecutionModelFragment :
return " fragment " ;
case ExecutionModelGLCompute :
return " compute " ;
2019-03-31 07:03:28 +03:00
case ExecutionModelRayGenerationNV :
return " raygenNV " ;
case ExecutionModelIntersectionNV :
return " intersectionNV " ;
case ExecutionModelCallableNV :
return " callableNV " ;
case ExecutionModelAnyHitNV :
return " anyhitNV " ;
case ExecutionModelClosestHitNV :
return " closesthitNV " ;
case ExecutionModelMissNV :
return " missNV " ;
2019-01-10 06:23:47 +03:00
default :
return " ??? " ;
}
}
static void print_resources ( const Compiler & compiler , const ShaderResources & res )
{
auto & modes = compiler . get_execution_mode_bitset ( ) ;
fprintf ( stderr , " Entry points: \n " ) ;
auto entry_points = compiler . get_entry_points_and_stages ( ) ;
for ( auto & e : entry_points )
fprintf ( stderr , " %s (%s) \n " , e . name . c_str ( ) , execution_model_to_str ( e . execution_model ) ) ;
fprintf ( stderr , " \n " ) ;
fprintf ( stderr , " Execution modes: \n " ) ;
modes . for_each_bit ( [ & ] ( uint32_t i ) {
auto mode = static_cast < ExecutionMode > ( i ) ;
uint32_t arg0 = compiler . get_execution_mode_argument ( mode , 0 ) ;
uint32_t arg1 = compiler . get_execution_mode_argument ( mode , 1 ) ;
uint32_t arg2 = compiler . get_execution_mode_argument ( mode , 2 ) ;
switch ( static_cast < ExecutionMode > ( i ) )
{
case ExecutionModeInvocations :
fprintf ( stderr , " Invocations: %u \n " , arg0 ) ;
break ;
case ExecutionModeLocalSize :
fprintf ( stderr , " LocalSize: (%u, %u, %u) \n " , arg0 , arg1 , arg2 ) ;
break ;
case ExecutionModeOutputVertices :
fprintf ( stderr , " OutputVertices: %u \n " , arg0 ) ;
break ;
# define CHECK_MODE(m) \
case ExecutionMode # # m : \
fprintf ( stderr , " %s \n " , # m ) ; \
break
CHECK_MODE ( SpacingEqual ) ;
CHECK_MODE ( SpacingFractionalEven ) ;
CHECK_MODE ( SpacingFractionalOdd ) ;
CHECK_MODE ( VertexOrderCw ) ;
CHECK_MODE ( VertexOrderCcw ) ;
CHECK_MODE ( PixelCenterInteger ) ;
CHECK_MODE ( OriginUpperLeft ) ;
CHECK_MODE ( OriginLowerLeft ) ;
CHECK_MODE ( EarlyFragmentTests ) ;
CHECK_MODE ( PointMode ) ;
CHECK_MODE ( Xfb ) ;
CHECK_MODE ( DepthReplacing ) ;
CHECK_MODE ( DepthGreater ) ;
CHECK_MODE ( DepthLess ) ;
CHECK_MODE ( DepthUnchanged ) ;
CHECK_MODE ( LocalSizeHint ) ;
CHECK_MODE ( InputPoints ) ;
CHECK_MODE ( InputLines ) ;
CHECK_MODE ( InputLinesAdjacency ) ;
CHECK_MODE ( Triangles ) ;
CHECK_MODE ( InputTrianglesAdjacency ) ;
CHECK_MODE ( Quads ) ;
CHECK_MODE ( Isolines ) ;
CHECK_MODE ( OutputPoints ) ;
CHECK_MODE ( OutputLineStrip ) ;
CHECK_MODE ( OutputTriangleStrip ) ;
CHECK_MODE ( VecTypeHint ) ;
CHECK_MODE ( ContractionOff ) ;
default :
break ;
}
} ) ;
fprintf ( stderr , " \n " ) ;
print_resources ( compiler , " subpass inputs " , res . subpass_inputs ) ;
print_resources ( compiler , " inputs " , res . stage_inputs ) ;
print_resources ( compiler , " outputs " , res . stage_outputs ) ;
print_resources ( compiler , " textures " , res . sampled_images ) ;
print_resources ( compiler , " separate images " , res . separate_images ) ;
print_resources ( compiler , " separate samplers " , res . separate_samplers ) ;
print_resources ( compiler , " images " , res . storage_images ) ;
print_resources ( compiler , " ssbos " , res . storage_buffers ) ;
print_resources ( compiler , " ubos " , res . uniform_buffers ) ;
print_resources ( compiler , " push " , res . push_constant_buffers ) ;
print_resources ( compiler , " counters " , res . atomic_counters ) ;
2019-03-31 07:03:28 +03:00
print_resources ( compiler , " acceleration structures " , res . acceleration_structures ) ;
2019-01-10 06:23:47 +03:00
}
2019-04-15 07:53:50 +03:00
static void print_push_constant_resources ( const Compiler & compiler , const SmallVector < Resource > & res )
2019-01-10 06:23:47 +03:00
{
for ( auto & block : res )
{
auto ranges = compiler . get_active_buffer_ranges ( block . id ) ;
fprintf ( stderr , " Active members in buffer: %s \n " ,
! block . name . empty ( ) ? block . name . c_str ( ) : compiler . get_fallback_name ( block . id ) . c_str ( ) ) ;
fprintf ( stderr , " ================== \n \n " ) ;
for ( auto & range : ranges )
{
const auto & name = compiler . get_member_name ( block . base_type_id , range . index ) ;
fprintf ( stderr , " Member #%3u (%s): Offset: %4u, Range: %4u \n " , range . index ,
! name . empty ( ) ? name . c_str ( ) : compiler . get_fallback_member_name ( range . index ) . c_str ( ) ,
unsigned ( range . offset ) , unsigned ( range . range ) ) ;
}
fprintf ( stderr , " ================== \n \n " ) ;
}
}
static void print_spec_constants ( const Compiler & compiler )
{
auto spec_constants = compiler . get_specialization_constants ( ) ;
fprintf ( stderr , " Specialization constants \n " ) ;
fprintf ( stderr , " ================== \n \n " ) ;
for ( auto & c : spec_constants )
2019-09-07 18:07:48 +03:00
fprintf ( stderr , " ID: %u, Spec ID: %u \n " , uint32_t ( c . id ) , c . constant_id ) ;
2019-01-10 06:23:47 +03:00
fprintf ( stderr , " ================== \n \n " ) ;
}
static void print_capabilities_and_extensions ( const Compiler & compiler )
{
fprintf ( stderr , " Capabilities \n " ) ;
fprintf ( stderr , " ============ \n " ) ;
for ( auto & capability : compiler . get_declared_capabilities ( ) )
fprintf ( stderr , " Capability: %u \n " , static_cast < unsigned > ( capability ) ) ;
fprintf ( stderr , " ============ \n \n " ) ;
fprintf ( stderr , " Extensions \n " ) ;
fprintf ( stderr , " ============ \n " ) ;
for ( auto & ext : compiler . get_declared_extensions ( ) )
fprintf ( stderr , " Extension: %s \n " , ext . c_str ( ) ) ;
fprintf ( stderr , " ============ \n \n " ) ;
}
struct PLSArg
{
PlsFormat format ;
string name ;
} ;
struct Remap
{
string src_name ;
string dst_name ;
unsigned components ;
} ;
struct VariableTypeRemap
{
string variable_name ;
string new_variable_type ;
} ;
struct InterfaceVariableRename
{
StorageClass storageClass ;
uint32_t location ;
string variable_name ;
} ;
struct CLIArguments
{
const char * input = nullptr ;
const char * output = nullptr ;
const char * cpp_interface_name = nullptr ;
uint32_t version = 0 ;
uint32_t shader_model = 0 ;
uint32_t msl_version = 0 ;
bool es = false ;
bool set_version = false ;
bool set_shader_model = false ;
bool set_msl_version = false ;
bool set_es = false ;
bool dump_resources = false ;
bool force_temporary = false ;
bool flatten_ubo = false ;
bool fixup = false ;
bool yflip = false ;
bool sso = false ;
bool support_nonzero_baseinstance = true ;
2019-02-09 23:44:48 +03:00
bool msl_capture_output_to_buffer = false ;
2019-01-10 06:23:47 +03:00
bool msl_swizzle_texture_samples = false ;
bool msl_ios = false ;
2019-01-17 05:50:01 +03:00
bool msl_pad_fragment_output = false ;
2019-02-23 07:54:12 +03:00
bool msl_domain_lower_left = false ;
2019-03-17 06:30:56 +03:00
bool msl_argument_buffers = false ;
2019-04-28 00:14:44 +03:00
bool msl_texture_buffer_native = false ;
2019-10-29 05:55:41 +03:00
bool msl_framebuffer_fetch = false ;
bool msl_invariant_float_math = false ;
bool msl_emulate_cube_array = false ;
2019-07-03 18:10:12 +03:00
bool msl_multiview = false ;
2020-09-05 21:33:56 +03:00
bool msl_multiview_layered_rendering = true ;
2019-07-20 20:45:34 +03:00
bool msl_view_index_from_device_index = false ;
2019-08-10 06:33:38 +03:00
bool msl_dispatch_base = false ;
2019-12-08 09:06:39 +03:00
bool msl_decoration_binding = false ;
2020-02-05 08:38:12 +03:00
bool msl_force_active_argument_buffer_resources = false ;
2020-03-14 23:22:45 +03:00
bool msl_force_native_arrays = false ;
2020-04-25 05:07:42 +03:00
bool msl_enable_frag_depth_builtin = true ;
bool msl_enable_frag_stencil_ref_builtin = true ;
uint32_t msl_enable_frag_output_mask = 0xffffffff ;
bool msl_enable_clip_distance_user_varying = true ;
2020-07-27 03:02:41 +03:00
bool msl_multi_patch_workgroup = false ;
bool msl_vertex_for_tessellation = false ;
uint32_t msl_additional_fixed_sample_mask = 0xffffffff ;
2020-09-05 21:33:56 +03:00
bool msl_arrayed_subpass_input = false ;
2020-10-18 08:52:04 +03:00
uint32_t msl_r32ui_linear_texture_alignment = 4 ;
uint32_t msl_r32ui_alignment_constant_id = 65535 ;
2020-11-02 08:41:59 +03:00
bool msl_texture_1d_as_2d = false ;
2020-11-30 05:54:52 +03:00
bool msl_ios_use_simdgroup_functions = false ;
bool msl_emulate_subgroups = false ;
uint32_t msl_fixed_subgroup_size = 0 ;
bool msl_force_sample_rate_shading = false ;
2019-03-22 23:18:09 +03:00
bool glsl_emit_push_constant_as_ubo = false ;
2019-05-18 22:28:43 +03:00
bool glsl_emit_ubo_as_plain_uniforms = false ;
2020-08-03 05:33:25 +03:00
bool glsl_force_flattened_io_blocks = false ;
2020-03-21 06:30:44 +03:00
SmallVector < pair < uint32_t , uint32_t > > glsl_ext_framebuffer_fetch ;
2019-08-10 06:33:38 +03:00
bool vulkan_glsl_disable_ext_samplerless_texture_functions = false ;
2019-06-07 08:04:16 +03:00
bool emit_line_directives = false ;
2020-03-14 23:22:45 +03:00
bool enable_storage_image_qualifier_deduction = true ;
2020-03-29 02:26:16 +03:00
bool force_zero_initialized_variables = false ;
2019-04-15 07:53:50 +03:00
SmallVector < uint32_t > msl_discrete_descriptor_sets ;
2019-10-20 08:33:06 +03:00
SmallVector < uint32_t > msl_device_argument_buffers ;
2019-09-07 18:07:48 +03:00
SmallVector < pair < uint32_t , uint32_t > > msl_dynamic_buffers ;
2020-02-05 08:38:12 +03:00
SmallVector < pair < uint32_t , uint32_t > > msl_inline_uniform_blocks ;
2020-06-19 07:50:44 +03:00
SmallVector < MSLShaderInput > msl_shader_inputs ;
2019-04-15 07:53:50 +03:00
SmallVector < PLSArg > pls_in ;
SmallVector < PLSArg > pls_out ;
SmallVector < Remap > remaps ;
SmallVector < string > extensions ;
SmallVector < VariableTypeRemap > variable_type_remaps ;
SmallVector < InterfaceVariableRename > interface_variable_renames ;
SmallVector < HLSLVertexAttributeRemap > hlsl_attr_remap ;
2019-01-10 06:23:47 +03:00
string entry ;
string entry_stage ;
struct Rename
{
string old_name ;
string new_name ;
ExecutionModel execution_model ;
} ;
2019-04-15 07:53:50 +03:00
SmallVector < Rename > entry_point_rename ;
2019-01-10 06:23:47 +03:00
uint32_t iterations = 1 ;
bool cpp = false ;
string reflect ;
bool msl = false ;
bool hlsl = false ;
bool hlsl_compat = false ;
2019-01-17 05:50:01 +03:00
bool hlsl_support_nonzero_base = false ;
2020-03-14 23:22:45 +03:00
bool hlsl_force_storage_buffer_as_uav = false ;
2020-04-05 04:56:27 +03:00
bool hlsl_nonwritable_uav_texture_as_srv = false ;
2020-06-13 08:07:11 +03:00
bool hlsl_enable_16bit_types = false ;
2020-11-08 01:46:56 +03:00
bool hlsl_flatten_matrix_vertex_input_semantics = false ;
2019-11-16 08:33:36 +03:00
HLSLBindingFlags hlsl_binding_flags = 0 ;
2019-01-10 06:23:47 +03:00
bool vulkan_semantics = false ;
bool flatten_multidimensional_arrays = false ;
bool use_420pack_extension = true ;
bool remove_unused = false ;
bool combined_samplers_inherit_bindings = false ;
} ;
2019-06-07 08:04:16 +03:00
static void print_version ( )
{
# ifdef HAVE_SPIRV_CROSS_GIT_VERSION
fprintf ( stderr , " %s \n " , SPIRV_CROSS_GIT_REVISION ) ;
# else
fprintf ( stderr , " Git revision unknown. Build with CMake to create timestamp and revision info. \n " ) ;
# endif
}
2020-05-30 06:28:00 +03:00
static void print_help_backend ( )
{
2020-07-04 04:29:29 +03:00
// clang-format off
2020-05-30 06:28:00 +03:00
fprintf ( stderr , " \n Select backend: \n "
" \t By default, OpenGL-style GLSL is the target, with #version and GLSL/ESSL information inherited from the SPIR-V module if present. \n "
" \t [--vulkan-semantics] or [-V]: \n \t \t Emit Vulkan GLSL instead of plain GLSL. Makes use of Vulkan-only features to match SPIR-V. \n "
" \t [--msl]: \n \t \t Emit Metal Shading Language (MSL). \n "
" \t [--hlsl]: \n \t \t Emit HLSL. \n "
" \t [--reflect]: \n \t \t Emit JSON reflection. \n "
" \t [--cpp]: \n \t \t DEPRECATED. Emits C++ code. \n "
) ;
2020-07-04 04:29:29 +03:00
// clang-format on
2020-05-30 06:28:00 +03:00
}
static void print_help_glsl ( )
{
2020-07-04 04:29:29 +03:00
// clang-format off
2020-05-30 06:28:00 +03:00
fprintf ( stderr , " \n GLSL options: \n "
" \t [--es]: \n \t \t Force ESSL. \n "
" \t [--no-es]: \n \t \t Force desktop GLSL. \n "
" \t [--version <GLSL version>]: \n \t \t E.g. --version 450 will emit '#version 450' in shader. \n "
" \t \t Code generation will depend on the version used. \n "
" \t [--flatten-ubo]: \n \t \t Emit UBOs as plain uniform arrays which are suitable for use with glUniform4*v(). \n "
" \t \t This can be an optimization on GL implementations where this is faster or works around buggy driver implementations. \n "
" \t \t E.g.: uniform MyUBO { vec4 a; float b, c, d, e; }; will be emitted as uniform vec4 MyUBO[2]; \n "
" \t \t Caveat: You cannot mix and match floating-point and integer in the same UBO with this option. \n "
" \t \t Legacy GLSL/ESSL (where this flattening makes sense) does not support bit-casting, which would have been the obvious workaround. \n "
" \t [--extension ext]: \n \t \t Add #extension string of your choosing to GLSL output. \n "
" \t \t Useful if you use variable name remapping to something that requires an extension unknown to SPIRV-Cross. \n "
" \t [--remove-unused-variables]: \n \t \t Do not emit interface variables which are not statically accessed by the shader. \n "
" \t [--separate-shader-objects]: \n \t \t Redeclare gl_PerVertex blocks to be suitable for desktop GL separate shader objects. \n "
" \t [--glsl-emit-push-constant-as-ubo]: \n \t \t Instead of a plain uniform of struct for push constants, emit a UBO block instead. \n "
" \t [--glsl-emit-ubo-as-plain-uniforms]: \n \t \t Instead of emitting UBOs, emit them as plain uniform structs. \n "
" \t [--glsl-remap-ext-framebuffer-fetch input-attachment color-location]: \n \t \t Remaps an input attachment to use GL_EXT_shader_framebuffer_fetch. \n "
" \t \t gl_LastFragData[location] is read from. The attachment to read from must be declared as an output in the shader. \n "
" \t [--vulkan-glsl-disable-ext-samplerless-texture-functions]: \n \t \t Do not allow use of GL_EXT_samperless_texture_functions, even in Vulkan GLSL. \n "
" \t \t Use of texelFetch and similar might have to create dummy samplers to work around it. \n "
" \t [--combined-samplers-inherit-bindings]: \n \t \t Inherit binding information from the textures when building combined image samplers from separate textures and samplers. \n "
" \t [--no-support-nonzero-baseinstance]: \n \t \t When using gl_InstanceIndex with desktop GL, \n "
" \t \t assume that base instance is always 0, and do not attempt to fix up gl_InstanceID to match Vulkan semantics. \n "
" \t [--pls-in format input-name]: \n \t \t Remaps a subpass input with name into a GL_EXT_pixel_local_storage input. \n "
" \t \t Entry in PLS block is ordered where first --pls-in marks the first entry. Can be called multiple times. \n "
" \t \t Formats allowed: r11f_g11f_b10f, r32f, rg16f, rg16, rgb10_a2, rgba8, rgba8i, rgba8ui, rg16i, rgb10_a2ui, rg16ui, r32ui. \n "
" \t \t Requires ESSL. \n "
" \t [--pls-out format output-name]: \n \t \t Remaps a color output with name into a GL_EXT_pixel_local_storage output. \n "
" \t \t Entry in PLS block is ordered where first --pls-output marks the first entry. Can be called multiple times. \n "
" \t \t Formats allowed: r11f_g11f_b10f, r32f, rg16f, rg16, rgb10_a2, rgba8, rgba8i, rgba8ui, rg16i, rgb10_a2ui, rg16ui, r32ui. \n "
" \t \t Requires ESSL. \n "
" \t [--remap source_name target_name components]: \n \t \t Remaps a variable to a different name with N components. \n "
" \t \t Main use case is to remap a subpass input to gl_LastFragDepthARM. \n "
" \t \t E.g.: \n "
" \t \t uniform subpassInput uDepth; \n "
" \t \t --remap uDepth gl_LastFragDepthARM 1 --extension GL_ARM_shader_framebuffer_fetch_depth_stencil \n "
" \t [--no-420pack-extension]: \n \t \t Do not make use of GL_ARB_shading_language_420pack in older GL targets to support layout(binding). \n "
" \t [--remap-variable-type <variable_name> <new_variable_type>]: \n \t \t Remaps a variable type based on name. \n "
" \t \t Primary use case is supporting external samplers in ESSL for video rendering on Android where you could remap a texture to a YUV one. \n "
2020-08-03 05:33:25 +03:00
" \t [--glsl-force-flattened-io-blocks]: \n \t \t Always flatten I/O blocks and structs. \n "
2020-05-30 06:28:00 +03:00
) ;
2020-07-04 04:29:29 +03:00
// clang-format on
2020-05-30 06:28:00 +03:00
}
static void print_help_hlsl ( )
{
2020-07-04 04:29:29 +03:00
// clang-format off
2020-05-30 06:28:00 +03:00
fprintf ( stderr , " \n HLSL options: \n "
" \t [--shader-model]: \n \t \t Enables a specific shader model, e.g. --shader-model 50 for SM 5.0. \n "
" \t [--hlsl-enable-compat]: \n \t \t Allow point size and point coord to be used, even if they won't work as expected. \n "
" \t \t PointSize is ignored, and PointCoord returns (0.5, 0.5). \n "
" \t [--hlsl-support-nonzero-basevertex-baseinstance]: \n \t \t Support base vertex and base instance by emitting a special cbuffer declared as: \n "
" \t \t cbuffer SPIRV_Cross_VertexInfo { int SPIRV_Cross_BaseVertex; int SPIRV_Cross_BaseInstance; }; \n "
" \t [--hlsl-auto-binding (push, cbv, srv, uav, sampler, all)] \n "
" \t \t Do not emit any : register(#) bindings for specific resource types, and rely on HLSL compiler to assign something. \n "
" \t [--hlsl-force-storage-buffer-as-uav]: \n \t \t Always emit SSBOs as UAVs, even when marked as read-only. \n "
" \t \t Normally, SSBOs marked with NonWritable will be emitted as SRVs. \n "
" \t [--hlsl-nonwritable-uav-texture-as-srv]: \n \t \t Emit NonWritable storage images as SRV textures instead of UAV. \n "
" \t \t Using this option messes with the type system. SPIRV-Cross cannot guarantee that this will work. \n "
" \t \t One major problem area with this feature is function arguments, where we won't know if we're seeing a UAV or SRV. \n "
" \t \t Shader must ensure that read/write state is consistent at all call sites. \n "
" \t [--set-hlsl-vertex-input-semantic <location> <semantic>]: \n \t \t Emits a specific vertex input semantic for a given location. \n "
" \t \t Otherwise, TEXCOORD# is used as semantics, where # is location. \n "
2020-06-13 08:07:11 +03:00
" \t [--hlsl-enable-16bit-types]: \n \t \t Enables native use of half/int16_t/uint16_t and ByteAddressBuffer interaction with these types. Requires SM 6.2. \n "
2020-11-08 01:46:56 +03:00
" \t [--hlsl-flatten-matrix-vertex-input-semantics]: \n \t \t Emits matrix vertex inputs with input semantics as if they were independent vectors, e.g. TEXCOORD{2,3,4} rather than matrix form TEXCOORD2_{0,1,2}. \n "
2020-05-30 06:28:00 +03:00
) ;
2020-07-04 04:29:29 +03:00
// clang-format on
2020-05-30 06:28:00 +03:00
}
static void print_help_msl ( )
{
2020-07-04 04:29:29 +03:00
// clang-format off
2020-05-30 06:28:00 +03:00
fprintf ( stderr , " \n MSL options: \n "
" \t [--msl-version <MMmmpp>]: \n \t \t Uses a specific MSL version, e.g. --msl-version 20100 for MSL 2.1. \n "
" \t [--msl-capture-output]: \n \t \t Writes geometry varyings to a buffer instead of as stage-outputs. \n "
" \t [--msl-swizzle-texture-samples]: \n \t \t Works around lack of support for VkImageView component swizzles. \n "
" \t \t This has a massive impact on performance and bloat. Do not use this unless you are absolutely forced to. \n "
" \t \t To use this feature, the API side must pass down swizzle buffers. \n "
" \t \t Should only be used by translation layers as a last resort. \n "
" \t \t Recent Metal versions do not require this workaround. \n "
" \t [--msl-ios]: \n \t \t Target iOS Metal instead of macOS Metal. \n "
" \t [--msl-pad-fragment-output]: \n \t \t Always emit color outputs as 4-component variables. \n "
" \t \t In Metal, the fragment shader must emit at least as many components as the render target format. \n "
" \t [--msl-domain-lower-left]: \n \t \t Use a lower-left tessellation domain. \n "
" \t [--msl-argument-buffers]: \n \t \t Emit Indirect Argument buffers instead of plain bindings. \n "
" \t \t Requires MSL 2.0 to be enabled. \n "
" \t [--msl-texture-buffer-native]: \n \t \t Enable native support for texel buffers. Otherwise, it is emulated as a normal texture. \n "
" \t [--msl-framebuffer-fetch]: \n \t \t Implement subpass inputs with frame buffer fetch. \n "
" \t \t Emits [[color(N)]] inputs in fragment stage. \n "
2020-11-02 08:41:59 +03:00
" \t \t Requires an Apple GPU. \n "
2020-05-30 06:28:00 +03:00
" \t [--msl-emulate-cube-array]: \n \t \t Emulate cube arrays with 2D array and manual math. \n "
" \t [--msl-discrete-descriptor-set <index>]: \n \t \t When using argument buffers, forces a specific descriptor set to be implemented without argument buffers. \n "
" \t \t Useful for implementing push descriptors in emulation layers. \n "
" \t \t Can be used multiple times for each descriptor set in question. \n "
" \t [--msl-device-argument-buffer <descriptor set index>]: \n \t \t Use device address space to hold indirect argument buffers instead of constant. \n "
" \t \t Comes up when trying to support argument buffers which are larger than 64 KiB. \n "
" \t [--msl-multiview]: \n \t \t Enable SPV_KHR_multiview emulation. \n "
2020-09-05 21:33:56 +03:00
" \t [--msl-multiview-no-layered-rendering]: \n \t \t Don't set [[render_target_array_index]] in multiview shaders. \n "
" \t \t Useful for devices which don't support layered rendering. Only effective when --msl-multiview is enabled. \n "
2020-05-30 06:28:00 +03:00
" \t [--msl-view-index-from-device-index]: \n \t \t Treat the view index as the device index instead. \n "
" \t \t For multi-GPU rendering. \n "
" \t [--msl-dispatch-base]: \n \t \t Add support for vkCmdDispatchBase() or similar APIs. \n "
" \t \t Offsets the workgroup ID based on a buffer. \n "
" \t [--msl-dynamic-buffer <set index> <binding>]: \n \t \t Marks a buffer as having dynamic offset. \n "
" \t \t The offset is applied in the shader with pointer arithmetic. \n "
" \t \t Useful for argument buffers where it is non-trivial to apply dynamic offset otherwise. \n "
" \t [--msl-inline-uniform-block <set index> <binding>]: \n \t \t In argument buffers, mark an UBO as being an inline uniform block which is embedded into the argument buffer itself. \n "
" \t [--msl-decoration-binding]: \n \t \t Use SPIR-V bindings directly as MSL bindings. \n "
" \t \t This does not work in the general case as there is no descriptor set support, and combined image samplers are split up. \n "
" \t \t However, if the shader author knows of binding limitations, this option will avoid the need for reflection on Metal side. \n "
" \t [--msl-force-active-argument-buffer-resources]: \n \t \t Always emit resources which are part of argument buffers. \n "
" \t \t This makes sure that similar shaders with same resource declarations can share the argument buffer as declaring an argument buffer implies an ABI. \n "
" \t [--msl-force-native-arrays]: \n \t \t Rather than implementing array types as a templated value type ala std::array<T>, use plain, native arrays. \n "
" \t \t This will lead to worse code-gen, but can work around driver bugs on certain driver revisions of certain Intel-based Macbooks where template arrays break. \n "
" \t [--msl-disable-frag-depth-builtin]: \n \t \t Disables FragDepth output. Useful if pipeline does not enable depth, as pipeline creation might otherwise fail. \n "
" \t [--msl-disable-frag-stencil-ref-builtin]: \n \t \t Disable FragStencilRef output. Useful if pipeline does not enable stencil output, as pipeline creation might otherwise fail. \n "
" \t [--msl-enable-frag-output-mask <mask>]: \n \t \t Only selectively enable fragment outputs. Useful if pipeline does not enable fragment output for certain locations, as pipeline creation might otherwise fail. \n "
" \t [--msl-no-clip-distance-user-varying]: \n \t \t Do not emit user varyings to emulate gl_ClipDistance in fragment shaders. \n "
2020-06-19 07:50:44 +03:00
" \t [--msl-shader-input <index> <format> <size>]: \n \t \t Specify the format of the shader input at <index>. \n "
2020-07-27 03:02:41 +03:00
" \t \t <format> can be 'any32', 'any16', 'u16', 'u8', or 'other', to indicate a 32-bit opaque value, 16-bit opaque value, 16-bit unsigned integer, 8-bit unsigned integer, "
2020-06-19 07:50:44 +03:00
" or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader. \n "
2020-07-27 03:02:41 +03:00
" \t \t Useful if shader stage interfaces don't match up, as pipeline creation might otherwise fail. \n "
" \t [--msl-multi-patch-workgroup]: \n \t \t Use the new style of tessellation control processing, where multiple patches are processed per workgroup. \n "
" \t \t This should increase throughput by ensuring all the GPU's SIMD lanes are occupied, but it is not compatible with the old style. \n "
" \t \t In addition, this style also passes input variables in buffers directly instead of using vertex attribute processing. \n "
" \t \t In a future version of SPIRV-Cross, this will become the default. \n "
" \t [--msl-vertex-for-tessellation]: \n \t \t When handling a vertex shader, marks it as one that will be used with a new-style tessellation control shader. \n "
" \t \t The vertex shader is output to MSL as a compute kernel which outputs vertices to the buffer in the order they are received, rather than in index order as with --msl-capture-output normally. \n "
" \t [--msl-additional-fixed-sample-mask <mask>]: \n "
2020-09-05 21:33:56 +03:00
" \t \t Set an additional fixed sample mask. If the shader outputs a sample mask, then the final sample mask will be a bitwise AND of the two. \n "
" \t [--msl-arrayed-subpass-input]: \n \t \t Assume that images of dimension SubpassData have multiple layers. Layered input attachments are accessed relative to BuiltInLayer. \n "
2020-10-18 08:52:04 +03:00
" \t \t This option has no effect if multiview is also enabled. \n "
" \t [--msl-r32ui-linear-texture-align <alignment>]: \n \t \t The required alignment of linear textures of format MTLPixelFormatR32Uint. \n "
" \t \t This is used to align the row stride for atomic accesses to such images. \n "
" \t [--msl-r32ui-linear-texture-align-constant-id <id>]: \n \t \t The function constant ID to use for the linear texture alignment. \n "
2020-11-02 08:41:59 +03:00
" \t \t On MSL 1.2 or later, you can override the alignment by setting this function constant. \n "
" \t [--msl-texture-1d-as-2d]: \n \t \t Emit Image variables of dimension Dim1D as texture2d. \n "
2020-11-30 05:54:52 +03:00
" \t \t In Metal, 1D textures do not support all features that 2D textures do. Use this option if your code relies on these features. \n "
" \t [--msl-ios-use-simdgroup-functions]: \n \t \t Use simd_*() functions for subgroup ops instead of quad_*(). \n "
" \t \t Recent Apple GPUs support SIMD-groups larger than a quad. Use this option to take advantage of this support. \n "
" \t [--msl-emulate-subgroups]: \n \t \t Assume subgroups of size 1. \n "
" \t \t Intended for Vulkan Portability implementations where Metal support for SIMD-groups is insufficient for true subgroups. \n "
" \t [--msl-fixed-subgroup-size <size>]: \n \t \t Assign a constant <size> to the SubgroupSize builtin. \n "
" \t \t Intended for Vulkan Portability implementations where VK_EXT_subgroup_size_control is not supported or disabled. \n "
" \t \t If 0, assume variable subgroup size as actually exposed by Metal. \n "
" \t [--msl-force-sample-rate-shading]: \n \t \t Force fragment shaders to run per sample. \n "
" \t \t This adds a [[sample_id]] parameter if none is already present. \n " ) ;
2020-07-04 04:29:29 +03:00
// clang-format on
2020-05-30 06:28:00 +03:00
}
static void print_help_common ( )
{
2020-07-04 04:29:29 +03:00
// clang-format off
2020-05-30 06:28:00 +03:00
fprintf ( stderr , " \n Common options: \n "
" \t [--entry name]: \n \t \t Use a specific entry point. By default, the first entry point in the module is used. \n "
" \t [--stage <stage (vert, frag, geom, tesc, tese comp)>]: \n \t \t Forces use of a certain shader stage. \n "
" \t \t Can disambiguate the entry point if more than one entry point exists with same name, but different stage. \n "
" \t [--emit-line-directives]: \n \t \t If SPIR-V has OpLine directives, aim to emit those accurately in output code as well. \n "
" \t [--rename-entry-point <old> <new> <stage>]: \n \t \t Renames an entry point from what is declared in SPIR-V to code output. \n "
" \t \t Mostly relevant for HLSL or MSL. \n "
" \t [--rename-interface-variable <in|out> <location> <new_variable_name>]: \n \t \t Rename an interface variable based on location decoration. \n "
" \t [--force-zero-initialized-variables]: \n \t \t Forces temporary variables to be initialized to zero. \n "
" \t \t Can be useful in environments where compilers do not allow potentially uninitialized variables. \n "
" \t \t This usually comes up with Phi temporaries. \n "
" \t [--fixup-clipspace]: \n \t \t Fixup Z clip-space at the end of a vertex shader. The behavior is backend-dependent. \n "
" \t \t GLSL: Rewrites [0, w] Z range (D3D/Metal/Vulkan) to GL-style [-w, w]. \n "
" \t \t HLSL/MSL: Rewrites [-w, w] Z range (GL) to D3D/Metal/Vulkan-style [0, w]. \n "
" \t [--flip-vert-y]: \n \t \t Inverts gl_Position.y (or equivalent) at the end of a vertex shader. This is equivalent to using negative viewport height. \n "
) ;
2020-07-04 04:29:29 +03:00
// clang-format on
2020-05-30 06:28:00 +03:00
}
static void print_help_obscure ( )
{
2020-07-04 04:29:29 +03:00
// clang-format off
2020-05-30 06:28:00 +03:00
fprintf ( stderr , " \n Obscure options: \n "
" \t These options are not meant to be used on a regular basis. They have some occasional uses in the test suite. \n "
" \t [--force-temporary]: \n \t \t Aggressively emit temporary expressions instead of forwarding expressions. Very rarely used and under-tested. \n "
" \t [--revision]: \n \t \t Prints build timestamp and Git commit information (updated when cmake is configured). \n "
" \t [--iterations iter]: \n \t \t Recompiles the same shader over and over, benchmarking related. \n "
" \t [--disable-storage-image-qualifier-deduction]: \n \t \t If storage images are received without any nonwritable or nonreadable information, \n " " "
" \t \t do not attempt to analyze usage, and always emit read/write state. \n "
" \t [--flatten-multidimensional-arrays]: \n \t \t Do not support multi-dimensional arrays and flatten them to one dimension. \n "
" \t [--cpp-interface-name <name>]: \n \t \t Emit a specific class name in C++ codegen. \n "
) ;
2020-07-04 04:29:29 +03:00
// clang-format on
2020-05-30 06:28:00 +03:00
}
2019-01-10 06:23:47 +03:00
static void print_help ( )
{
2019-06-07 08:04:16 +03:00
print_version ( ) ;
2020-07-04 04:29:29 +03:00
// clang-format off
2020-05-30 06:28:00 +03:00
fprintf ( stderr , " Usage: spirv-cross <...> \n "
" \n Basic: \n "
2019-01-10 06:23:47 +03:00
" \t [SPIR-V file] \n "
2020-05-30 06:28:00 +03:00
" \t [--output <output path>]: If not provided, prints output to stdout. \n "
" \t [--dump-resources]: \n \t \t Prints a basic reflection of the SPIR-V module along with other output. \n "
" \t [--help]: \n \t \t Prints this help message. \n "
) ;
2020-07-04 04:29:29 +03:00
// clang-format on
2020-05-30 06:28:00 +03:00
print_help_backend ( ) ;
print_help_common ( ) ;
print_help_glsl ( ) ;
print_help_msl ( ) ;
print_help_hlsl ( ) ;
print_help_obscure ( ) ;
2019-01-10 06:23:47 +03:00
}
2019-04-15 07:53:50 +03:00
static bool remap_generic ( Compiler & compiler , const SmallVector < Resource > & resources , const Remap & remap )
2019-01-10 06:23:47 +03:00
{
auto itr =
find_if ( begin ( resources ) , end ( resources ) , [ & remap ] ( const Resource & res ) { return res . name = = remap . src_name ; } ) ;
if ( itr ! = end ( resources ) )
{
compiler . set_remapped_variable_state ( itr - > id , true ) ;
compiler . set_name ( itr - > id , remap . dst_name ) ;
compiler . set_subpass_input_remapped_components ( itr - > id , remap . components ) ;
return true ;
}
else
return false ;
}
2019-04-15 07:53:50 +03:00
static vector < PlsRemap > remap_pls ( const SmallVector < PLSArg > & pls_variables , const SmallVector < Resource > & resources ,
const SmallVector < Resource > * secondary_resources )
2019-01-10 06:23:47 +03:00
{
vector < PlsRemap > ret ;
for ( auto & pls : pls_variables )
{
bool found = false ;
for ( auto & res : resources )
{
if ( res . name = = pls . name )
{
ret . push_back ( { res . id , pls . format } ) ;
found = true ;
break ;
}
}
if ( ! found & & secondary_resources )
{
for ( auto & res : * secondary_resources )
{
if ( res . name = = pls . name )
{
ret . push_back ( { res . id , pls . format } ) ;
found = true ;
break ;
}
}
}
if ( ! found )
fprintf ( stderr , " Did not find stage input/output/target with name \" %s \" . \n " , pls . name . c_str ( ) ) ;
}
return ret ;
}
static PlsFormat pls_format ( const char * str )
{
if ( ! strcmp ( str , " r11f_g11f_b10f " ) )
return PlsR11FG11FB10F ;
else if ( ! strcmp ( str , " r32f " ) )
return PlsR32F ;
else if ( ! strcmp ( str , " rg16f " ) )
return PlsRG16F ;
else if ( ! strcmp ( str , " rg16 " ) )
return PlsRG16 ;
else if ( ! strcmp ( str , " rgb10_a2 " ) )
return PlsRGB10A2 ;
else if ( ! strcmp ( str , " rgba8 " ) )
return PlsRGBA8 ;
else if ( ! strcmp ( str , " rgba8i " ) )
return PlsRGBA8I ;
else if ( ! strcmp ( str , " rgba8ui " ) )
return PlsRGBA8UI ;
else if ( ! strcmp ( str , " rg16i " ) )
return PlsRG16I ;
else if ( ! strcmp ( str , " rgb10_a2ui " ) )
return PlsRGB10A2UI ;
else if ( ! strcmp ( str , " rg16ui " ) )
return PlsRG16UI ;
else if ( ! strcmp ( str , " r32ui " ) )
return PlsR32UI ;
else
return PlsNone ;
}
static ExecutionModel stage_to_execution_model ( const std : : string & stage )
{
if ( stage = = " vert " )
return ExecutionModelVertex ;
else if ( stage = = " frag " )
return ExecutionModelFragment ;
else if ( stage = = " comp " )
return ExecutionModelGLCompute ;
else if ( stage = = " tesc " )
return ExecutionModelTessellationControl ;
else if ( stage = = " tese " )
return ExecutionModelTessellationEvaluation ;
else if ( stage = = " geom " )
return ExecutionModelGeometry ;
else
SPIRV_CROSS_THROW ( " Invalid stage. " ) ;
}
2019-11-16 08:33:36 +03:00
static HLSLBindingFlags hlsl_resource_type_to_flag ( const std : : string & arg )
{
if ( arg = = " push " )
return HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT ;
else if ( arg = = " cbv " )
return HLSL_BINDING_AUTO_CBV_BIT ;
else if ( arg = = " srv " )
return HLSL_BINDING_AUTO_SRV_BIT ;
else if ( arg = = " uav " )
return HLSL_BINDING_AUTO_UAV_BIT ;
else if ( arg = = " sampler " )
return HLSL_BINDING_AUTO_SAMPLER_BIT ;
else if ( arg = = " all " )
return HLSL_BINDING_AUTO_ALL ;
else
{
fprintf ( stderr , " Invalid resource type for --hlsl-auto-binding: %s \n " , arg . c_str ( ) ) ;
return 0 ;
}
}
2019-04-15 07:53:50 +03:00
static string compile_iteration ( const CLIArguments & args , std : : vector < uint32_t > spirv_file )
2019-01-10 06:23:47 +03:00
{
Parser spirv_parser ( move ( spirv_file ) ) ;
spirv_parser . parse ( ) ;
unique_ptr < CompilerGLSL > compiler ;
bool combined_image_samplers = false ;
bool build_dummy_sampler = false ;
if ( args . cpp )
{
compiler . reset ( new CompilerCPP ( move ( spirv_parser . get_parsed_ir ( ) ) ) ) ;
if ( args . cpp_interface_name )
static_cast < CompilerCPP * > ( compiler . get ( ) ) - > set_interface_name ( args . cpp_interface_name ) ;
}
else if ( args . msl )
{
compiler . reset ( new CompilerMSL ( move ( spirv_parser . get_parsed_ir ( ) ) ) ) ;
auto * msl_comp = static_cast < CompilerMSL * > ( compiler . get ( ) ) ;
auto msl_opts = msl_comp - > get_msl_options ( ) ;
if ( args . set_msl_version )
msl_opts . msl_version = args . msl_version ;
2019-02-09 23:44:48 +03:00
msl_opts . capture_output_to_buffer = args . msl_capture_output_to_buffer ;
2019-01-10 06:23:47 +03:00
msl_opts . swizzle_texture_samples = args . msl_swizzle_texture_samples ;
2019-10-29 05:55:41 +03:00
msl_opts . invariant_float_math = args . msl_invariant_float_math ;
2019-01-10 06:23:47 +03:00
if ( args . msl_ios )
2019-10-29 05:55:41 +03:00
{
2019-01-10 06:23:47 +03:00
msl_opts . platform = CompilerMSL : : Options : : iOS ;
2019-10-29 05:55:41 +03:00
msl_opts . emulate_cube_array = args . msl_emulate_cube_array ;
}
2020-11-02 08:41:59 +03:00
msl_opts . use_framebuffer_fetch_subpasses = args . msl_framebuffer_fetch ;
2019-01-17 05:50:01 +03:00
msl_opts . pad_fragment_output_components = args . msl_pad_fragment_output ;
2019-02-23 07:54:12 +03:00
msl_opts . tess_domain_origin_lower_left = args . msl_domain_lower_left ;
2019-03-17 06:30:56 +03:00
msl_opts . argument_buffers = args . msl_argument_buffers ;
2019-04-28 00:14:44 +03:00
msl_opts . texture_buffer_native = args . msl_texture_buffer_native ;
2019-07-03 18:10:12 +03:00
msl_opts . multiview = args . msl_multiview ;
2020-09-05 21:33:56 +03:00
msl_opts . multiview_layered_rendering = args . msl_multiview_layered_rendering ;
2019-07-20 20:45:34 +03:00
msl_opts . view_index_from_device_index = args . msl_view_index_from_device_index ;
2019-08-10 06:33:38 +03:00
msl_opts . dispatch_base = args . msl_dispatch_base ;
2019-12-08 09:06:39 +03:00
msl_opts . enable_decoration_binding = args . msl_decoration_binding ;
2020-02-05 08:38:12 +03:00
msl_opts . force_active_argument_buffer_resources = args . msl_force_active_argument_buffer_resources ;
2020-03-14 23:22:45 +03:00
msl_opts . force_native_arrays = args . msl_force_native_arrays ;
2020-04-25 05:07:42 +03:00
msl_opts . enable_frag_depth_builtin = args . msl_enable_frag_depth_builtin ;
msl_opts . enable_frag_stencil_ref_builtin = args . msl_enable_frag_stencil_ref_builtin ;
msl_opts . enable_frag_output_mask = args . msl_enable_frag_output_mask ;
msl_opts . enable_clip_distance_user_varying = args . msl_enable_clip_distance_user_varying ;
2020-07-27 03:02:41 +03:00
msl_opts . multi_patch_workgroup = args . msl_multi_patch_workgroup ;
msl_opts . vertex_for_tessellation = args . msl_vertex_for_tessellation ;
msl_opts . additional_fixed_sample_mask = args . msl_additional_fixed_sample_mask ;
2020-09-05 21:33:56 +03:00
msl_opts . arrayed_subpass_input = args . msl_arrayed_subpass_input ;
2020-10-18 08:52:04 +03:00
msl_opts . r32ui_linear_texture_alignment = args . msl_r32ui_linear_texture_alignment ;
msl_opts . r32ui_alignment_constant_id = args . msl_r32ui_alignment_constant_id ;
2020-11-02 08:41:59 +03:00
msl_opts . texture_1D_as_2D = args . msl_texture_1d_as_2d ;
2020-11-30 05:54:52 +03:00
msl_opts . ios_use_simdgroup_functions = args . msl_ios_use_simdgroup_functions ;
msl_opts . emulate_subgroups = args . msl_emulate_subgroups ;
msl_opts . fixed_subgroup_size = args . msl_fixed_subgroup_size ;
msl_opts . force_sample_rate_shading = args . msl_force_sample_rate_shading ;
2019-01-10 06:23:47 +03:00
msl_comp - > set_msl_options ( msl_opts ) ;
2019-03-17 06:30:56 +03:00
for ( auto & v : args . msl_discrete_descriptor_sets )
msl_comp - > add_discrete_descriptor_set ( v ) ;
2019-10-20 08:33:06 +03:00
for ( auto & v : args . msl_device_argument_buffers )
msl_comp - > set_argument_buffer_device_address_space ( v , true ) ;
2019-09-07 18:07:48 +03:00
uint32_t i = 0 ;
for ( auto & v : args . msl_dynamic_buffers )
msl_comp - > add_dynamic_buffer ( v . first , v . second , i + + ) ;
2020-02-05 08:38:12 +03:00
for ( auto & v : args . msl_inline_uniform_blocks )
msl_comp - > add_inline_uniform_block ( v . first , v . second ) ;
2020-06-19 07:50:44 +03:00
for ( auto & v : args . msl_shader_inputs )
msl_comp - > add_msl_shader_input ( v ) ;
2019-01-10 06:23:47 +03:00
}
else if ( args . hlsl )
compiler . reset ( new CompilerHLSL ( move ( spirv_parser . get_parsed_ir ( ) ) ) ) ;
else
{
combined_image_samplers = ! args . vulkan_semantics ;
2019-08-10 06:33:38 +03:00
if ( ! args . vulkan_semantics | | args . vulkan_glsl_disable_ext_samplerless_texture_functions )
2019-01-10 06:23:47 +03:00
build_dummy_sampler = true ;
compiler . reset ( new CompilerGLSL ( move ( spirv_parser . get_parsed_ir ( ) ) ) ) ;
}
if ( ! args . variable_type_remaps . empty ( ) )
{
auto remap_cb = [ & ] ( const SPIRType & , const string & name , string & out ) - > void {
for ( const VariableTypeRemap & remap : args . variable_type_remaps )
if ( name = = remap . variable_name )
out = remap . new_variable_type ;
} ;
compiler - > set_variable_type_remap_callback ( move ( remap_cb ) ) ;
}
for ( auto & rename : args . entry_point_rename )
compiler - > rename_entry_point ( rename . old_name , rename . new_name , rename . execution_model ) ;
auto entry_points = compiler - > get_entry_points_and_stages ( ) ;
auto entry_point = args . entry ;
ExecutionModel model = ExecutionModelMax ;
if ( ! args . entry_stage . empty ( ) )
{
model = stage_to_execution_model ( args . entry_stage ) ;
if ( entry_point . empty ( ) )
{
// Just use the first entry point with this stage.
for ( auto & e : entry_points )
{
if ( e . execution_model = = model )
{
entry_point = e . name ;
break ;
}
}
if ( entry_point . empty ( ) )
{
fprintf ( stderr , " Could not find an entry point with stage: %s \n " , args . entry_stage . c_str ( ) ) ;
2019-04-15 07:53:50 +03:00
exit ( EXIT_FAILURE ) ;
2019-01-10 06:23:47 +03:00
}
}
else
{
// Make sure both stage and name exists.
bool exists = false ;
for ( auto & e : entry_points )
{
if ( e . execution_model = = model & & e . name = = entry_point )
{
exists = true ;
break ;
}
}
if ( ! exists )
{
fprintf ( stderr , " Could not find an entry point %s with stage: %s \n " , entry_point . c_str ( ) ,
args . entry_stage . c_str ( ) ) ;
2019-04-15 07:53:50 +03:00
exit ( EXIT_FAILURE ) ;
2019-01-10 06:23:47 +03:00
}
}
}
else if ( ! 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 = = entry_point )
{
stage_count + + ;
model = e . execution_model ;
}
}
if ( stage_count = = 0 )
{
fprintf ( stderr , " There is no entry point with name: %s \n " , entry_point . c_str ( ) ) ;
2019-04-15 07:53:50 +03:00
exit ( EXIT_FAILURE ) ;
2019-01-10 06:23:47 +03:00
}
else if ( stage_count > 1 )
{
fprintf ( stderr , " There is more than one entry point with name: %s. Use --stage. \n " , entry_point . c_str ( ) ) ;
2019-04-15 07:53:50 +03:00
exit ( EXIT_FAILURE ) ;
2019-01-10 06:23:47 +03:00
}
}
if ( ! entry_point . empty ( ) )
compiler - > set_entry_point ( entry_point , model ) ;
if ( ! args . set_version & & ! compiler - > get_common_options ( ) . version )
{
fprintf ( stderr , " Didn't specify GLSL version and SPIR-V did not specify language. \n " ) ;
print_help ( ) ;
2019-04-15 07:53:50 +03:00
exit ( EXIT_FAILURE ) ;
2019-01-10 06:23:47 +03:00
}
CompilerGLSL : : Options opts = compiler - > get_common_options ( ) ;
if ( args . set_version )
opts . version = args . version ;
if ( args . set_es )
opts . es = args . es ;
opts . force_temporary = args . force_temporary ;
opts . separate_shader_objects = args . sso ;
opts . flatten_multidimensional_arrays = args . flatten_multidimensional_arrays ;
opts . enable_420pack_extension = args . use_420pack_extension ;
opts . vulkan_semantics = args . vulkan_semantics ;
opts . vertex . fixup_clipspace = args . fixup ;
opts . vertex . flip_vert_y = args . yflip ;
opts . vertex . support_nonzero_base_instance = args . support_nonzero_baseinstance ;
2019-03-22 23:18:09 +03:00
opts . emit_push_constant_as_uniform_buffer = args . glsl_emit_push_constant_as_ubo ;
2019-05-18 22:28:43 +03:00
opts . emit_uniform_buffer_as_plain_uniforms = args . glsl_emit_ubo_as_plain_uniforms ;
2020-08-03 05:33:25 +03:00
opts . force_flattened_io_blocks = args . glsl_force_flattened_io_blocks ;
2019-06-07 08:04:16 +03:00
opts . emit_line_directives = args . emit_line_directives ;
2020-03-14 23:22:45 +03:00
opts . enable_storage_image_qualifier_deduction = args . enable_storage_image_qualifier_deduction ;
2020-03-29 02:26:16 +03:00
opts . force_zero_initialized_variables = args . force_zero_initialized_variables ;
2019-01-10 06:23:47 +03:00
compiler - > set_common_options ( opts ) ;
2020-03-21 06:30:44 +03:00
for ( auto & fetch : args . glsl_ext_framebuffer_fetch )
compiler - > remap_ext_framebuffer_fetch ( fetch . first , fetch . second ) ;
2019-01-10 06:23:47 +03:00
// Set HLSL specific options.
if ( args . hlsl )
{
auto * hlsl = static_cast < CompilerHLSL * > ( compiler . get ( ) ) ;
auto hlsl_opts = hlsl - > get_hlsl_options ( ) ;
if ( args . set_shader_model )
{
if ( args . shader_model < 30 )
{
fprintf ( stderr , " Shader model earlier than 30 (3.0) not supported. \n " ) ;
2019-04-15 07:53:50 +03:00
exit ( EXIT_FAILURE ) ;
2019-01-10 06:23:47 +03:00
}
hlsl_opts . shader_model = args . shader_model ;
}
if ( args . hlsl_compat )
{
// Enable all compat options.
hlsl_opts . point_size_compat = true ;
hlsl_opts . point_coord_compat = true ;
}
if ( hlsl_opts . shader_model < = 30 )
{
combined_image_samplers = true ;
build_dummy_sampler = true ;
}
2019-01-17 05:50:01 +03:00
hlsl_opts . support_nonzero_base_vertex_base_instance = args . hlsl_support_nonzero_base ;
2020-03-14 23:22:45 +03:00
hlsl_opts . force_storage_buffer_as_uav = args . hlsl_force_storage_buffer_as_uav ;
2020-04-05 04:56:27 +03:00
hlsl_opts . nonwritable_uav_texture_as_srv = args . hlsl_nonwritable_uav_texture_as_srv ;
2020-06-13 08:07:11 +03:00
hlsl_opts . enable_16bit_types = args . hlsl_enable_16bit_types ;
2020-11-08 01:46:56 +03:00
hlsl_opts . flatten_matrix_vertex_input_semantics = args . hlsl_flatten_matrix_vertex_input_semantics ;
2019-01-10 06:23:47 +03:00
hlsl - > set_hlsl_options ( hlsl_opts ) ;
2019-11-16 08:33:36 +03:00
hlsl - > set_resource_binding_flags ( args . hlsl_binding_flags ) ;
2019-01-10 06:23:47 +03:00
}
if ( build_dummy_sampler )
{
uint32_t sampler = compiler - > build_dummy_sampler_for_combined_images ( ) ;
if ( sampler ! = 0 )
{
// Set some defaults to make validation happy.
compiler - > set_decoration ( sampler , DecorationDescriptorSet , 0 ) ;
compiler - > set_decoration ( sampler , DecorationBinding , 0 ) ;
}
}
ShaderResources res ;
if ( args . remove_unused )
{
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 ( args . 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 ) ;
}
auto pls_inputs = remap_pls ( args . pls_in , res . stage_inputs , & res . subpass_inputs ) ;
auto pls_outputs = remap_pls ( args . pls_out , res . stage_outputs , nullptr ) ;
compiler - > remap_pixel_local_storage ( move ( pls_inputs ) , move ( pls_outputs ) ) ;
for ( auto & ext : args . extensions )
compiler - > require_extension ( ext ) ;
for ( auto & remap : args . remaps )
{
if ( remap_generic ( * compiler , res . stage_inputs , remap ) )
continue ;
if ( remap_generic ( * compiler , res . stage_outputs , remap ) )
continue ;
if ( remap_generic ( * compiler , res . subpass_inputs , remap ) )
continue ;
}
for ( auto & rename : args . interface_variable_renames )
{
if ( rename . storageClass = = StorageClassInput )
spirv_cross_util : : rename_interface_variable ( * compiler , res . stage_inputs , rename . location ,
rename . variable_name ) ;
else if ( rename . storageClass = = StorageClassOutput )
spirv_cross_util : : rename_interface_variable ( * compiler , res . stage_outputs , rename . location ,
rename . variable_name ) ;
else
{
fprintf ( stderr , " error at --rename-interface-variable <in|out> ... \n " ) ;
2019-04-15 07:53:50 +03:00
exit ( EXIT_FAILURE ) ;
2019-01-10 06:23:47 +03:00
}
}
if ( combined_image_samplers )
{
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 , join ( " SPIRV_Cross_Combined " , compiler - > get_name ( remap . image_id ) ,
compiler - > get_name ( remap . sampler_id ) ) ) ;
}
}
if ( args . hlsl )
{
auto * hlsl_compiler = static_cast < CompilerHLSL * > ( compiler . get ( ) ) ;
uint32_t new_builtin = hlsl_compiler - > remap_num_workgroups_builtin ( ) ;
if ( new_builtin )
{
hlsl_compiler - > set_decoration ( new_builtin , DecorationDescriptorSet , 0 ) ;
hlsl_compiler - > set_decoration ( new_builtin , DecorationBinding , 0 ) ;
}
}
2019-04-15 07:53:50 +03:00
if ( args . hlsl )
2019-01-10 06:23:47 +03:00
{
2019-04-15 07:53:50 +03:00
for ( auto & remap : args . hlsl_attr_remap )
static_cast < CompilerHLSL * > ( compiler . get ( ) ) - > add_vertex_attribute_remap ( remap ) ;
}
2020-04-05 04:56:27 +03:00
auto ret = compiler - > compile ( ) ;
if ( args . dump_resources )
{
print_resources ( * compiler , res ) ;
print_push_constant_resources ( * compiler , res . push_constant_buffers ) ;
print_spec_constants ( * compiler ) ;
print_capabilities_and_extensions ( * compiler ) ;
}
return ret ;
2019-04-15 07:53:50 +03:00
}
static int main_inner ( int argc , char * argv [ ] )
{
CLIArguments args ;
CLICallbacks cbs ;
2019-03-09 21:20:48 +03:00
2019-04-15 07:53:50 +03:00
cbs . add ( " --help " , [ ] ( CLIParser & parser ) {
print_help ( ) ;
parser . end ( ) ;
} ) ;
2019-06-07 08:04:16 +03:00
cbs . add ( " --revision " , [ ] ( CLIParser & parser ) {
print_version ( ) ;
parser . end ( ) ;
} ) ;
2019-04-15 07:53:50 +03:00
cbs . add ( " --output " , [ & args ] ( CLIParser & parser ) { args . output = parser . next_string ( ) ; } ) ;
cbs . add ( " --es " , [ & args ] ( CLIParser & ) {
args . es = true ;
args . set_es = true ;
} ) ;
cbs . add ( " --no-es " , [ & args ] ( CLIParser & ) {
args . es = false ;
args . set_es = true ;
} ) ;
cbs . add ( " --version " , [ & args ] ( CLIParser & parser ) {
args . version = parser . next_uint ( ) ;
args . set_version = true ;
} ) ;
cbs . add ( " --dump-resources " , [ & args ] ( CLIParser & ) { args . dump_resources = true ; } ) ;
cbs . add ( " --force-temporary " , [ & args ] ( CLIParser & ) { args . force_temporary = true ; } ) ;
cbs . add ( " --flatten-ubo " , [ & args ] ( CLIParser & ) { args . flatten_ubo = true ; } ) ;
cbs . add ( " --fixup-clipspace " , [ & args ] ( CLIParser & ) { args . fixup = true ; } ) ;
cbs . add ( " --flip-vert-y " , [ & args ] ( CLIParser & ) { args . yflip = true ; } ) ;
cbs . add ( " --iterations " , [ & args ] ( CLIParser & parser ) { args . iterations = parser . next_uint ( ) ; } ) ;
cbs . add ( " --cpp " , [ & args ] ( CLIParser & ) { args . cpp = true ; } ) ;
cbs . add ( " --reflect " , [ & args ] ( CLIParser & parser ) { args . reflect = parser . next_value_string ( " json " ) ; } ) ;
cbs . add ( " --cpp-interface-name " , [ & args ] ( CLIParser & parser ) { args . cpp_interface_name = parser . next_string ( ) ; } ) ;
cbs . add ( " --metal " , [ & args ] ( CLIParser & ) { args . msl = true ; } ) ; // Legacy compatibility
cbs . add ( " --glsl-emit-push-constant-as-ubo " , [ & args ] ( CLIParser & ) { args . glsl_emit_push_constant_as_ubo = true ; } ) ;
2019-05-18 22:28:43 +03:00
cbs . add ( " --glsl-emit-ubo-as-plain-uniforms " , [ & args ] ( CLIParser & ) { args . glsl_emit_ubo_as_plain_uniforms = true ; } ) ;
2020-08-03 05:33:25 +03:00
cbs . add ( " --glsl-force-flattened-io-blocks " , [ & args ] ( CLIParser & ) { args . glsl_force_flattened_io_blocks = true ; } ) ;
2020-03-21 06:30:44 +03:00
cbs . add ( " --glsl-remap-ext-framebuffer-fetch " , [ & args ] ( CLIParser & parser ) {
uint32_t input_index = parser . next_uint ( ) ;
uint32_t color_attachment = parser . next_uint ( ) ;
args . glsl_ext_framebuffer_fetch . push_back ( { input_index , color_attachment } ) ;
} ) ;
2019-08-10 06:33:38 +03:00
cbs . add ( " --vulkan-glsl-disable-ext-samplerless-texture-functions " ,
[ & args ] ( CLIParser & ) { args . vulkan_glsl_disable_ext_samplerless_texture_functions = true ; } ) ;
2020-03-21 06:30:44 +03:00
cbs . add ( " --disable-storage-image-qualifier-deduction " ,
[ & args ] ( CLIParser & ) { args . enable_storage_image_qualifier_deduction = false ; } ) ;
2020-03-29 02:26:16 +03:00
cbs . add ( " --force-zero-initialized-variables " ,
[ & args ] ( CLIParser & ) { args . force_zero_initialized_variables = true ; } ) ;
2019-04-15 07:53:50 +03:00
cbs . add ( " --msl " , [ & args ] ( CLIParser & ) { args . msl = true ; } ) ;
cbs . add ( " --hlsl " , [ & args ] ( CLIParser & ) { args . hlsl = true ; } ) ;
cbs . add ( " --hlsl-enable-compat " , [ & args ] ( CLIParser & ) { args . hlsl_compat = true ; } ) ;
cbs . add ( " --hlsl-support-nonzero-basevertex-baseinstance " ,
[ & args ] ( CLIParser & ) { args . hlsl_support_nonzero_base = true ; } ) ;
2019-11-16 08:33:36 +03:00
cbs . add ( " --hlsl-auto-binding " , [ & args ] ( CLIParser & parser ) {
args . hlsl_binding_flags | = hlsl_resource_type_to_flag ( parser . next_string ( ) ) ;
} ) ;
2020-03-21 06:30:44 +03:00
cbs . add ( " --hlsl-force-storage-buffer-as-uav " ,
[ & args ] ( CLIParser & ) { args . hlsl_force_storage_buffer_as_uav = true ; } ) ;
2020-04-05 04:56:27 +03:00
cbs . add ( " --hlsl-nonwritable-uav-texture-as-srv " ,
[ & args ] ( CLIParser & ) { args . hlsl_nonwritable_uav_texture_as_srv = true ; } ) ;
2020-06-13 08:07:11 +03:00
cbs . add ( " --hlsl-enable-16bit-types " , [ & args ] ( CLIParser & ) { args . hlsl_enable_16bit_types = true ; } ) ;
2020-11-30 05:54:52 +03:00
cbs . add ( " --hlsl-flatten-matrix-vertex-input-semantics " ,
[ & args ] ( CLIParser & ) { args . hlsl_flatten_matrix_vertex_input_semantics = true ; } ) ;
2019-04-15 07:53:50 +03:00
cbs . add ( " --vulkan-semantics " , [ & args ] ( CLIParser & ) { args . vulkan_semantics = true ; } ) ;
2020-03-14 23:22:45 +03:00
cbs . add ( " -V " , [ & args ] ( CLIParser & ) { args . vulkan_semantics = true ; } ) ;
2019-04-15 07:53:50 +03:00
cbs . add ( " --flatten-multidimensional-arrays " , [ & args ] ( CLIParser & ) { args . flatten_multidimensional_arrays = true ; } ) ;
cbs . add ( " --no-420pack-extension " , [ & args ] ( CLIParser & ) { args . use_420pack_extension = false ; } ) ;
cbs . add ( " --msl-capture-output " , [ & args ] ( CLIParser & ) { args . msl_capture_output_to_buffer = true ; } ) ;
cbs . add ( " --msl-swizzle-texture-samples " , [ & args ] ( CLIParser & ) { args . msl_swizzle_texture_samples = true ; } ) ;
cbs . add ( " --msl-ios " , [ & args ] ( CLIParser & ) { args . msl_ios = true ; } ) ;
cbs . add ( " --msl-pad-fragment-output " , [ & args ] ( CLIParser & ) { args . msl_pad_fragment_output = true ; } ) ;
cbs . add ( " --msl-domain-lower-left " , [ & args ] ( CLIParser & ) { args . msl_domain_lower_left = true ; } ) ;
cbs . add ( " --msl-argument-buffers " , [ & args ] ( CLIParser & ) { args . msl_argument_buffers = true ; } ) ;
cbs . add ( " --msl-discrete-descriptor-set " ,
[ & args ] ( CLIParser & parser ) { args . msl_discrete_descriptor_sets . push_back ( parser . next_uint ( ) ) ; } ) ;
2019-10-20 08:33:06 +03:00
cbs . add ( " --msl-device-argument-buffer " ,
[ & args ] ( CLIParser & parser ) { args . msl_device_argument_buffers . push_back ( parser . next_uint ( ) ) ; } ) ;
2019-04-28 00:14:44 +03:00
cbs . add ( " --msl-texture-buffer-native " , [ & args ] ( CLIParser & ) { args . msl_texture_buffer_native = true ; } ) ;
2019-10-29 05:55:41 +03:00
cbs . add ( " --msl-framebuffer-fetch " , [ & args ] ( CLIParser & ) { args . msl_framebuffer_fetch = true ; } ) ;
cbs . add ( " --msl-invariant-float-math " , [ & args ] ( CLIParser & ) { args . msl_invariant_float_math = true ; } ) ;
cbs . add ( " --msl-emulate-cube-array " , [ & args ] ( CLIParser & ) { args . msl_emulate_cube_array = true ; } ) ;
2019-07-03 18:10:12 +03:00
cbs . add ( " --msl-multiview " , [ & args ] ( CLIParser & ) { args . msl_multiview = true ; } ) ;
2020-09-05 21:33:56 +03:00
cbs . add ( " --msl-multiview-no-layered-rendering " ,
[ & args ] ( CLIParser & ) { args . msl_multiview_layered_rendering = false ; } ) ;
2019-07-20 20:45:34 +03:00
cbs . add ( " --msl-view-index-from-device-index " ,
[ & args ] ( CLIParser & ) { args . msl_view_index_from_device_index = true ; } ) ;
2019-08-10 06:33:38 +03:00
cbs . add ( " --msl-dispatch-base " , [ & args ] ( CLIParser & ) { args . msl_dispatch_base = true ; } ) ;
2019-09-07 18:07:48 +03:00
cbs . add ( " --msl-dynamic-buffer " , [ & args ] ( CLIParser & parser ) {
args . msl_argument_buffers = true ;
// Make sure next_uint() is called in-order.
uint32_t desc_set = parser . next_uint ( ) ;
uint32_t binding = parser . next_uint ( ) ;
args . msl_dynamic_buffers . push_back ( make_pair ( desc_set , binding ) ) ;
} ) ;
2019-12-08 09:06:39 +03:00
cbs . add ( " --msl-decoration-binding " , [ & args ] ( CLIParser & ) { args . msl_decoration_binding = true ; } ) ;
2020-02-05 08:38:12 +03:00
cbs . add ( " --msl-force-active-argument-buffer-resources " ,
[ & args ] ( CLIParser & ) { args . msl_force_active_argument_buffer_resources = true ; } ) ;
cbs . add ( " --msl-inline-uniform-block " , [ & args ] ( CLIParser & parser ) {
args . msl_argument_buffers = true ;
// Make sure next_uint() is called in-order.
uint32_t desc_set = parser . next_uint ( ) ;
uint32_t binding = parser . next_uint ( ) ;
args . msl_inline_uniform_blocks . push_back ( make_pair ( desc_set , binding ) ) ;
} ) ;
2020-03-21 06:30:44 +03:00
cbs . add ( " --msl-force-native-arrays " , [ & args ] ( CLIParser & ) { args . msl_force_native_arrays = true ; } ) ;
2020-04-25 05:07:42 +03:00
cbs . add ( " --msl-disable-frag-depth-builtin " , [ & args ] ( CLIParser & ) { args . msl_enable_frag_depth_builtin = false ; } ) ;
cbs . add ( " --msl-disable-frag-stencil-ref-builtin " ,
[ & args ] ( CLIParser & ) { args . msl_enable_frag_stencil_ref_builtin = false ; } ) ;
cbs . add ( " --msl-enable-frag-output-mask " ,
[ & args ] ( CLIParser & parser ) { args . msl_enable_frag_output_mask = parser . next_hex_uint ( ) ; } ) ;
cbs . add ( " --msl-no-clip-distance-user-varying " ,
[ & args ] ( CLIParser & ) { args . msl_enable_clip_distance_user_varying = false ; } ) ;
2020-06-19 07:50:44 +03:00
cbs . add ( " --msl-shader-input " , [ & args ] ( CLIParser & parser ) {
MSLShaderInput input ;
// Make sure next_uint() is called in-order.
input . location = parser . next_uint ( ) ;
const char * format = parser . next_value_string ( " other " ) ;
2020-07-27 03:02:41 +03:00
if ( strcmp ( format , " any32 " ) = = 0 )
input . format = MSL_SHADER_INPUT_FORMAT_ANY32 ;
else if ( strcmp ( format , " any16 " ) = = 0 )
input . format = MSL_SHADER_INPUT_FORMAT_ANY16 ;
else if ( strcmp ( format , " u16 " ) = = 0 )
input . format = MSL_SHADER_INPUT_FORMAT_UINT16 ;
2020-06-19 07:50:44 +03:00
else if ( strcmp ( format , " u8 " ) = = 0 )
2020-07-27 03:02:41 +03:00
input . format = MSL_SHADER_INPUT_FORMAT_UINT8 ;
2020-06-19 07:50:44 +03:00
else
2020-07-27 03:02:41 +03:00
input . format = MSL_SHADER_INPUT_FORMAT_OTHER ;
2020-06-19 07:50:44 +03:00
input . vecsize = parser . next_uint ( ) ;
args . msl_shader_inputs . push_back ( input ) ;
} ) ;
2020-07-27 03:02:41 +03:00
cbs . add ( " --msl-multi-patch-workgroup " , [ & args ] ( CLIParser & ) { args . msl_multi_patch_workgroup = true ; } ) ;
cbs . add ( " --msl-vertex-for-tessellation " , [ & args ] ( CLIParser & ) { args . msl_vertex_for_tessellation = true ; } ) ;
cbs . add ( " --msl-additional-fixed-sample-mask " ,
[ & args ] ( CLIParser & parser ) { args . msl_additional_fixed_sample_mask = parser . next_hex_uint ( ) ; } ) ;
2020-09-05 21:33:56 +03:00
cbs . add ( " --msl-arrayed-subpass-input " , [ & args ] ( CLIParser & ) { args . msl_arrayed_subpass_input = true ; } ) ;
2020-10-18 08:52:04 +03:00
cbs . add ( " --msl-r32ui-linear-texture-align " ,
[ & args ] ( CLIParser & parser ) { args . msl_r32ui_linear_texture_alignment = parser . next_uint ( ) ; } ) ;
cbs . add ( " --msl-r32ui-linear-texture-align-constant-id " ,
[ & args ] ( CLIParser & parser ) { args . msl_r32ui_alignment_constant_id = parser . next_uint ( ) ; } ) ;
2020-11-02 08:41:59 +03:00
cbs . add ( " --msl-texture-1d-as-2d " , [ & args ] ( CLIParser & ) { args . msl_texture_1d_as_2d = true ; } ) ;
2020-11-30 05:54:52 +03:00
cbs . add ( " --msl-ios-use-simdgroup-functions " , [ & args ] ( CLIParser & ) { args . msl_ios_use_simdgroup_functions = true ; } ) ;
cbs . add ( " --msl-emulate-subgroups " , [ & args ] ( CLIParser & ) { args . msl_emulate_subgroups = true ; } ) ;
cbs . add ( " --msl-fixed-subgroup-size " ,
[ & args ] ( CLIParser & parser ) { args . msl_fixed_subgroup_size = parser . next_uint ( ) ; } ) ;
cbs . add ( " --msl-force-sample-rate-shading " , [ & args ] ( CLIParser & ) { args . msl_force_sample_rate_shading = true ; } ) ;
2019-04-15 07:53:50 +03:00
cbs . add ( " --extension " , [ & args ] ( CLIParser & parser ) { args . extensions . push_back ( parser . next_string ( ) ) ; } ) ;
cbs . add ( " --rename-entry-point " , [ & args ] ( CLIParser & parser ) {
auto old_name = parser . next_string ( ) ;
auto new_name = parser . next_string ( ) ;
auto model = stage_to_execution_model ( parser . next_string ( ) ) ;
args . entry_point_rename . push_back ( { old_name , new_name , move ( model ) } ) ;
} ) ;
cbs . add ( " --entry " , [ & args ] ( CLIParser & parser ) { args . entry = parser . next_string ( ) ; } ) ;
cbs . add ( " --stage " , [ & args ] ( CLIParser & parser ) { args . entry_stage = parser . next_string ( ) ; } ) ;
cbs . add ( " --separate-shader-objects " , [ & args ] ( CLIParser & ) { args . sso = true ; } ) ;
cbs . add ( " --set-hlsl-vertex-input-semantic " , [ & args ] ( CLIParser & parser ) {
HLSLVertexAttributeRemap remap ;
remap . location = parser . next_uint ( ) ;
remap . semantic = parser . next_string ( ) ;
args . hlsl_attr_remap . push_back ( move ( remap ) ) ;
} ) ;
cbs . add ( " --remap " , [ & args ] ( CLIParser & parser ) {
string src = parser . next_string ( ) ;
string dst = parser . next_string ( ) ;
uint32_t components = parser . next_uint ( ) ;
args . remaps . push_back ( { move ( src ) , move ( dst ) , components } ) ;
} ) ;
cbs . add ( " --remap-variable-type " , [ & args ] ( CLIParser & parser ) {
string var_name = parser . next_string ( ) ;
string new_type = parser . next_string ( ) ;
args . variable_type_remaps . push_back ( { move ( var_name ) , move ( new_type ) } ) ;
} ) ;
cbs . add ( " --rename-interface-variable " , [ & args ] ( CLIParser & parser ) {
StorageClass cls = StorageClassMax ;
string clsStr = parser . next_string ( ) ;
if ( clsStr = = " in " )
cls = StorageClassInput ;
else if ( clsStr = = " out " )
cls = StorageClassOutput ;
uint32_t loc = parser . next_uint ( ) ;
string var_name = parser . next_string ( ) ;
args . interface_variable_renames . push_back ( { cls , loc , move ( var_name ) } ) ;
} ) ;
cbs . add ( " --pls-in " , [ & args ] ( CLIParser & parser ) {
auto fmt = pls_format ( parser . next_string ( ) ) ;
auto name = parser . next_string ( ) ;
args . pls_in . push_back ( { move ( fmt ) , move ( name ) } ) ;
} ) ;
cbs . add ( " --pls-out " , [ & args ] ( CLIParser & parser ) {
auto fmt = pls_format ( parser . next_string ( ) ) ;
auto name = parser . next_string ( ) ;
args . pls_out . push_back ( { move ( fmt ) , move ( name ) } ) ;
} ) ;
cbs . add ( " --shader-model " , [ & args ] ( CLIParser & parser ) {
args . shader_model = parser . next_uint ( ) ;
args . set_shader_model = true ;
} ) ;
cbs . add ( " --msl-version " , [ & args ] ( CLIParser & parser ) {
args . msl_version = parser . next_uint ( ) ;
args . set_msl_version = true ;
} ) ;
cbs . add ( " --remove-unused-variables " , [ & args ] ( CLIParser & ) { args . remove_unused = true ; } ) ;
cbs . add ( " --combined-samplers-inherit-bindings " ,
[ & args ] ( CLIParser & ) { args . combined_samplers_inherit_bindings = true ; } ) ;
cbs . add ( " --no-support-nonzero-baseinstance " , [ & ] ( CLIParser & ) { args . support_nonzero_baseinstance = false ; } ) ;
2019-06-07 08:04:16 +03:00
cbs . add ( " --emit-line-directives " , [ & args ] ( CLIParser & ) { args . emit_line_directives = true ; } ) ;
2019-04-15 07:53:50 +03:00
cbs . default_handler = [ & args ] ( const char * value ) { args . input = value ; } ;
cbs . error_handler = [ ] { print_help ( ) ; } ;
CLIParser parser { move ( cbs ) , argc - 1 , argv + 1 } ;
if ( ! parser . parse ( ) )
return EXIT_FAILURE ;
else if ( parser . ended_state )
return EXIT_SUCCESS ;
if ( ! args . input )
{
fprintf ( stderr , " Didn't specify input file. \n " ) ;
print_help ( ) ;
return EXIT_FAILURE ;
}
auto spirv_file = read_spirv_file ( args . input ) ;
if ( spirv_file . empty ( ) )
return EXIT_FAILURE ;
// Special case reflection because it has little to do with the path followed by code-outputting compilers
if ( ! args . reflect . empty ( ) )
{
Parser spirv_parser ( move ( spirv_file ) ) ;
spirv_parser . parse ( ) ;
CompilerReflection compiler ( move ( spirv_parser . get_parsed_ir ( ) ) ) ;
compiler . set_format ( args . reflect ) ;
auto json = compiler . compile ( ) ;
if ( args . output )
write_string_to_file ( args . output , json . c_str ( ) ) ;
else
printf ( " %s " , json . c_str ( ) ) ;
return EXIT_SUCCESS ;
}
string compiled_output ;
if ( args . iterations = = 1 )
compiled_output = compile_iteration ( args , move ( spirv_file ) ) ;
else
{
for ( unsigned i = 0 ; i < args . iterations ; i + + )
compiled_output = compile_iteration ( args , spirv_file ) ;
2019-01-10 06:23:47 +03:00
}
if ( args . output )
2019-04-15 07:53:50 +03:00
write_string_to_file ( args . output , compiled_output . c_str ( ) ) ;
2019-01-10 06:23:47 +03:00
else
2019-04-15 07:53:50 +03:00
printf ( " %s " , compiled_output . c_str ( ) ) ;
2019-01-10 06:23:47 +03:00
return EXIT_SUCCESS ;
}
int main ( int argc , char * argv [ ] )
{
# ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
return main_inner ( argc , argv ) ;
# else
// Make sure we catch the exception or it just disappears into the aether on Windows.
try
{
return main_inner ( argc , argv ) ;
}
catch ( const std : : exception & e )
{
fprintf ( stderr , " SPIRV-Cross threw an exception: %s \n " , e . what ( ) ) ;
return EXIT_FAILURE ;
}
# endif
}