2016-10-01 06:03:16 +03:00
/*
2019-01-14 04:13:25 +03:00
* Copyright 2011 - 2019 Branimir Karadzic . All rights reserved .
2016-10-01 06:03:16 +03:00
* License : https : //github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
# include "shaderc.h"
2016-12-16 07:46:12 +03:00
BX_PRAGMA_DIAGNOSTIC_PUSH ( )
2017-01-12 09:46:41 +03:00
BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC ( 4100 ) // error C4100: 'inclusionDepth' : unreferenced formal parameter
2016-12-16 07:46:12 +03:00
BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC ( 4265 ) // error C4265: 'spv::spirvbin_t': class has virtual functions, but destructor is not virtual
2017-03-12 01:58:09 +03:00
BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC ( " -Wshadow " ) // warning: declaration of 'userData' shadows a member of 'glslang::TShader::Includer::IncludeResult'
2018-09-03 08:34:04 +03:00
# define ENABLE_OPT 1
2016-12-16 06:03:47 +03:00
# include <ShaderLang.h>
# include <ResourceLimits.h>
# include <SPIRV/SPVRemapper.h>
2017-06-03 21:11:11 +03:00
# include <SPIRV/GlslangToSpv.h>
2019-01-14 11:51:31 +03:00
# define SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
2019-01-14 11:24:06 +03:00
# include <spirv_msl.hpp>
2019-03-13 01:23:10 +03:00
# include <spirv_reflect.hpp>
2019-01-16 00:12:48 +03:00
# include <spirv-tools/optimizer.hpp>
2016-12-16 07:46:12 +03:00
BX_PRAGMA_DIAGNOSTIC_POP ( )
2016-12-16 06:03:47 +03:00
2016-10-01 06:03:16 +03:00
namespace bgfx
{
2017-06-11 08:31:59 +03:00
static bx : : DefaultAllocator s_allocator ;
2016-12-16 06:03:47 +03:00
bx : : AllocatorI * g_allocator = & s_allocator ;
struct TinyStlAllocator
{
static void * static_allocate ( size_t _bytes ) ;
static void static_deallocate ( void * _ptr , size_t /*_bytes*/ ) ;
} ;
void * TinyStlAllocator : : static_allocate ( size_t _bytes )
{
return BX_ALLOC ( g_allocator , _bytes ) ;
}
void TinyStlAllocator : : static_deallocate ( void * _ptr , size_t /*_bytes*/ )
{
if ( NULL ! = _ptr )
{
BX_FREE ( g_allocator , _ptr ) ;
}
}
} // namespace bgfx
# define TINYSTL_ALLOCATOR bgfx::TinyStlAllocator
# include <tinystl/allocator.h>
# include <tinystl/string.h>
# include <tinystl/unordered_map.h>
# include <tinystl/vector.h>
namespace stl = tinystl ;
# include "../../src/shader_spirv.h"
namespace bgfx { namespace spirv
{
const TBuiltInResource resourceLimits =
{
32 , // MaxLights
6 , // MaxClipPlanes
32 , // MaxTextureUnits
32 , // MaxTextureCoords
64 , // MaxVertexAttribs
4096 , // MaxVertexUniformComponents
64 , // MaxVaryingFloats
32 , // MaxVertexTextureImageUnits
80 , // MaxCombinedTextureImageUnits
32 , // MaxTextureImageUnits
4096 , // MaxFragmentUniformComponents
32 , // MaxDrawBuffers
128 , // MaxVertexUniformVectors
8 , // MaxVaryingVectors
16 , // MaxFragmentUniformVectors
16 , // MaxVertexOutputVectors
15 , // MaxFragmentInputVectors
- 8 , // MinProgramTexelOffset
7 , // MaxProgramTexelOffset
8 , // MaxClipDistances
65535 , // MaxComputeWorkGroupCountX
65535 , // MaxComputeWorkGroupCountY
65535 , // MaxComputeWorkGroupCountZ
1024 , // MaxComputeWorkGroupSizeX
1024 , // MaxComputeWorkGroupSizeY
64 , // MaxComputeWorkGroupSizeZ
1024 , // MaxComputeUniformComponents
16 , // MaxComputeTextureImageUnits
8 , // MaxComputeImageUniforms
8 , // MaxComputeAtomicCounters
1 , // MaxComputeAtomicCounterBuffers
60 , // MaxVaryingComponents
64 , // MaxVertexOutputComponents
64 , // MaxGeometryInputComponents
128 , // MaxGeometryOutputComponents
128 , // MaxFragmentInputComponents
8 , // MaxImageUnits
8 , // MaxCombinedImageUnitsAndFragmentOutputs
8 , // MaxCombinedShaderOutputResources
0 , // MaxImageSamples
0 , // MaxVertexImageUniforms
0 , // MaxTessControlImageUniforms
0 , // MaxTessEvaluationImageUniforms
0 , // MaxGeometryImageUniforms
8 , // MaxFragmentImageUniforms
8 , // MaxCombinedImageUniforms
16 , // MaxGeometryTextureImageUnits
256 , // MaxGeometryOutputVertices
1024 , // MaxGeometryTotalOutputComponents
1024 , // MaxGeometryUniformComponents
64 , // MaxGeometryVaryingComponents
128 , // MaxTessControlInputComponents
128 , // MaxTessControlOutputComponents
16 , // MaxTessControlTextureImageUnits
1024 , // MaxTessControlUniformComponents
4096 , // MaxTessControlTotalOutputComponents
128 , // MaxTessEvaluationInputComponents
128 , // MaxTessEvaluationOutputComponents
16 , // MaxTessEvaluationTextureImageUnits
1024 , // MaxTessEvaluationUniformComponents
120 , // MaxTessPatchComponents
32 , // MaxPatchVertices
64 , // MaxTessGenLevel
16 , // MaxViewports
0 , // MaxVertexAtomicCounters
0 , // MaxTessControlAtomicCounters
0 , // MaxTessEvaluationAtomicCounters
0 , // MaxGeometryAtomicCounters
8 , // MaxFragmentAtomicCounters
8 , // MaxCombinedAtomicCounters
1 , // MaxAtomicCounterBindings
0 , // MaxVertexAtomicCounterBuffers
0 , // MaxTessControlAtomicCounterBuffers
0 , // MaxTessEvaluationAtomicCounterBuffers
0 , // MaxGeometryAtomicCounterBuffers
1 , // MaxFragmentAtomicCounterBuffers
1 , // MaxCombinedAtomicCounterBuffers
16384 , // MaxAtomicCounterBufferSize
4 , // MaxTransformFeedbackBuffers
64 , // MaxTransformFeedbackInterleavedComponents
8 , // MaxCullDistances
8 , // MaxCombinedClipAndCullDistances
4 , // MaxSamples
2018-10-02 06:01:14 +03:00
0 , // maxMeshOutputVerticesNV;
0 , // maxMeshOutputPrimitivesNV;
0 , // maxMeshWorkGroupSizeX_NV;
0 , // maxMeshWorkGroupSizeY_NV;
0 , // maxMeshWorkGroupSizeZ_NV;
0 , // maxTaskWorkGroupSizeX_NV;
0 , // maxTaskWorkGroupSizeY_NV;
0 , // maxTaskWorkGroupSizeZ_NV;
0 , // maxMeshViewCountNV
{ // limits
true , // nonInductiveForLoops
true , // whileLoops
true , // doWhileLoops
true , // generalUniformIndexing
true , // generalAttributeMatrixVectorIndexing
true , // generalVaryingIndexing
true , // generalSamplerIndexing
true , // generalVariableIndexing
true , // generalConstantMatrixVectorIndexing
2016-12-16 06:03:47 +03:00
} ,
} ;
bool printAsm ( uint32_t _offset , const SpvInstruction & _instruction , void * _userData )
{
BX_UNUSED ( _userData ) ;
char temp [ 512 ] ;
toString ( temp , sizeof ( temp ) , _instruction ) ;
BX_TRACE ( " %5d: %s " , _offset , temp ) ;
return true ;
}
struct SpvReflection
{
struct TypeId
{
enum Enum
{
Void ,
Bool ,
Int32 ,
Int64 ,
Uint32 ,
Uint64 ,
Float ,
Double ,
Vector ,
Matrix ,
Count
} ;
TypeId ( )
: baseType ( Enum : : Count )
, type ( Enum : : Count )
2016-12-17 23:38:22 +03:00
, numComponents ( 0 )
2016-12-16 06:03:47 +03:00
{
}
Enum baseType ;
Enum type ;
uint32_t numComponents ;
stl : : string toString ( )
{
stl : : string result ;
switch ( type )
{
case Float :
result . append ( " float " ) ;
break ;
case Vector :
bx : : stringPrintf ( result , " vec%d "
, numComponents
) ;
break ;
case Matrix :
bx : : stringPrintf ( result , " mat%d "
, numComponents
) ;
default :
break ;
}
return result ;
}
} ;
struct Id
{
struct Variable
{
Variable ( )
: decoration ( SpvDecoration : : Count )
, builtin ( SpvBuiltin : : Count )
, storageClass ( SpvStorageClass : : Count )
, location ( UINT32_MAX )
, offset ( UINT32_MAX )
, type ( UINT32_MAX )
{
}
stl : : string name ;
SpvDecoration : : Enum decoration ;
SpvBuiltin : : Enum builtin ;
SpvStorageClass : : Enum storageClass ;
uint32_t location ;
uint32_t offset ;
uint32_t type ;
} ;
typedef stl : : vector < Variable > MemberArray ;
Variable var ;
MemberArray members ;
} ;
typedef stl : : unordered_map < uint32_t , TypeId > TypeIdMap ;
typedef stl : : unordered_map < uint32_t , Id > IdMap ;
TypeIdMap typeIdMap ;
IdMap idMap ;
stl : : string getTypeName ( uint32_t _typeId )
{
return getTypeId ( _typeId ) . toString ( ) ;
}
Id & getId ( uint32_t _id )
{
IdMap : : iterator it = idMap . find ( _id ) ;
if ( it = = idMap . end ( ) )
{
Id id ;
stl : : pair < IdMap : : iterator , bool > result = idMap . insert ( stl : : make_pair ( _id , id ) ) ;
it = result . first ;
}
return it - > second ;
}
Id : : Variable & get ( uint32_t _id , uint32_t _idx )
{
Id & id = getId ( _id ) ;
id . members . resize ( bx : : uint32_max ( _idx + 1 , uint32_t ( id . members . size ( ) ) ) ) ;
return id . members [ _idx ] ;
}
TypeId & getTypeId ( uint32_t _id )
{
TypeIdMap : : iterator it = typeIdMap . find ( _id ) ;
if ( it = = typeIdMap . end ( ) )
{
TypeId id ;
stl : : pair < TypeIdMap : : iterator , bool > result = typeIdMap . insert ( stl : : make_pair ( _id , id ) ) ;
it = result . first ;
}
return it - > second ;
}
void update ( uint32_t _id , const stl : : string & _name )
{
getId ( _id ) . var . name = _name ;
}
BX_NO_INLINE void update ( Id : : Variable & _variable , SpvDecoration : : Enum _decoration , uint32_t _literal )
{
_variable . decoration = _decoration ;
switch ( _decoration )
{
case SpvDecoration : : Location :
_variable . location = _literal ;
break ;
case SpvDecoration : : Offset :
_variable . offset = _literal ;
break ;
case SpvDecoration : : BuiltIn :
_variable . builtin = SpvBuiltin : : Enum ( _literal ) ;
break ;
default :
break ;
}
}
BX_NO_INLINE void update ( Id : : Variable & _variable , uint32_t _type , SpvStorageClass : : Enum _storageClass )
{
_variable . type = _type ;
_variable . storageClass = _storageClass ;
}
void update ( uint32_t _id , SpvDecoration : : Enum _decoration , uint32_t _literal )
{
update ( getId ( _id ) . var , _decoration , _literal ) ;
}
void update ( uint32_t _id , uint32_t _type , SpvStorageClass : : Enum _storageClass )
{
update ( getId ( _id ) . var , _type , _storageClass ) ;
}
void update ( uint32_t _id , uint32_t _idx , const stl : : string & _name )
{
Id : : Variable & var = get ( _id , _idx ) ;
var . name = _name ;
}
BX_NO_INLINE void update ( uint32_t _id , uint32_t _idx , SpvDecoration : : Enum _decoration , uint32_t _literal )
{
update ( get ( _id , _idx ) , _decoration , _literal ) ;
}
void update ( uint32_t _id , TypeId : : Enum _type )
{
TypeId & type = getTypeId ( _id ) ;
type . type = _type ;
}
void update ( uint32_t _id , TypeId : : Enum _type , uint32_t _baseTypeId , uint32_t _numComonents )
{
TypeId & type = getTypeId ( _id ) ;
type . type = _type ;
type . baseType = getTypeId ( _baseTypeId ) . type ;
type . numComponents = _numComonents ;
}
} ;
bool spvParse ( uint32_t _offset , const SpvInstruction & _instruction , void * _userData )
{
BX_UNUSED ( _offset ) ;
SpvReflection * spv = ( SpvReflection * ) _userData ;
switch ( _instruction . opcode )
{
case SpvOpcode : : Name :
spv - > update ( _instruction . result
, _instruction . operand [ 0 ] . literalString
) ;
break ;
case SpvOpcode : : Decorate :
spv - > update ( _instruction . operand [ 0 ] . data
, SpvDecoration : : Enum ( _instruction . operand [ 1 ] . data )
, _instruction . operand [ 2 ] . data
) ;
break ;
case SpvOpcode : : MemberName :
spv - > update ( _instruction . result
, _instruction . operand [ 0 ] . data
, _instruction . operand [ 1 ] . literalString
) ;
break ;
case SpvOpcode : : MemberDecorate :
spv - > update ( _instruction . operand [ 0 ] . data
, _instruction . operand [ 1 ] . data
, SpvDecoration : : Enum ( _instruction . operand [ 2 ] . data )
, _instruction . operand [ 3 ] . data
) ;
break ;
case SpvOpcode : : Variable :
spv - > update ( _instruction . result
, _instruction . type
, SpvStorageClass : : Enum ( _instruction . operand [ 0 ] . data )
) ;
break ;
case SpvOpcode : : TypeVoid :
spv - > update ( _instruction . result , SpvReflection : : TypeId : : Void ) ;
break ;
case SpvOpcode : : TypeBool :
spv - > update ( _instruction . result , SpvReflection : : TypeId : : Bool ) ;
break ;
case SpvOpcode : : TypeInt :
spv - > update ( _instruction . result
, 32 = = _instruction . operand [ 0 ] . data
? 0 = = _instruction . operand [ 1 ] . data
? SpvReflection : : TypeId : : Uint32
: SpvReflection : : TypeId : : Int32
: 0 = = _instruction . operand [ 1 ] . data
? SpvReflection : : TypeId : : Uint64
: SpvReflection : : TypeId : : Int64
) ;
break ;
case SpvOpcode : : TypeFloat :
spv - > update ( _instruction . result
, 32 = = _instruction . operand [ 0 ] . data
? SpvReflection : : TypeId : : Float
: SpvReflection : : TypeId : : Double
) ;
break ;
case SpvOpcode : : TypeVector :
spv - > update ( _instruction . result
, SpvReflection : : TypeId : : Vector
, _instruction . operand [ 0 ] . data
, _instruction . operand [ 1 ] . data
) ;
break ;
case SpvOpcode : : TypeMatrix :
spv - > update ( _instruction . result
, SpvReflection : : TypeId : : Matrix
, _instruction . operand [ 0 ] . data
, _instruction . operand [ 1 ] . data
) ;
break ;
case SpvOpcode : : TypeImage :
case SpvOpcode : : TypeSampler :
case SpvOpcode : : TypeSampledImage :
break ;
case SpvOpcode : : TypeStruct :
for ( uint32_t ii = 0 , num = _instruction . numOperands ; ii < num ; + + ii )
{
SpvReflection : : Id : : Variable & var = spv - > get ( _instruction . result , ii ) ;
var . type = _instruction . operand [ ii ] . data ;
}
break ;
default :
break ;
}
return true ;
}
2018-02-15 09:01:24 +03:00
# define DBG(...) // bx::debugPrintf(__VA_ARGS__)
2017-04-24 01:53:15 +03:00
2016-12-16 06:03:47 +03:00
void disassemble ( bx : : WriterI * _writer , bx : : ReaderSeekerI * _reader , bx : : Error * _err )
{
BX_UNUSED ( _writer ) ;
uint32_t magic ;
bx : : peek ( _reader , magic ) ;
SpvReflection spvx ;
if ( magic = = SPV_CHUNK_HEADER )
{
SpirV spirv ;
read ( _reader , spirv , _err ) ;
parse ( spirv . shader , spvParse , & spvx , _err ) ;
for ( SpvReflection : : IdMap : : const_iterator it = spvx . idMap . begin ( ) , itEnd = spvx . idMap . end ( ) ; it ! = itEnd ; + + it )
{
const SpvReflection : : Id & id = it - > second ;
uint32_t num = uint32_t ( id . members . size ( ) ) ;
if ( 0 < num
2017-04-23 00:47:02 +03:00
& & 0 ! = bx : : strCmp ( id . var . name . c_str ( ) , " gl_PerVertex " ) )
2016-12-16 06:03:47 +03:00
{
2017-04-24 01:53:15 +03:00
DBG ( " %3d: %s %d %s \n "
2016-12-16 06:03:47 +03:00
, it - > first
, id . var . name . c_str ( )
, id . var . location
, getName ( id . var . storageClass )
) ;
2017-04-24 01:53:15 +03:00
DBG ( " { \n " ) ;
2016-12-16 06:03:47 +03:00
for ( uint32_t ii = 0 ; ii < num ; + + ii )
{
const SpvReflection : : Id : : Variable & var = id . members [ ii ] ;
2017-04-24 01:53:15 +03:00
DBG ( " \t \t %s %s %d %s \n "
2016-12-16 06:03:47 +03:00
, spvx . getTypeName ( var . type ) . c_str ( )
, var . name . c_str ( )
, var . offset
, getName ( var . storageClass )
) ;
2017-04-24 01:53:15 +03:00
BX_UNUSED ( var ) ;
2016-12-16 06:03:47 +03:00
}
2017-04-24 01:53:15 +03:00
DBG ( " } \n " ) ;
2016-12-16 06:03:47 +03:00
}
}
}
}
static EShLanguage getLang ( char _p )
{
switch ( _p )
{
case ' c ' : return EShLangCompute ;
case ' f ' : return EShLangFragment ;
2017-03-24 23:20:38 +03:00
case ' v ' : return EShLangVertex ;
default : return EShLangCount ;
2016-12-16 06:03:47 +03:00
}
}
2018-04-14 20:30:00 +03:00
static const char * s_attribName [ ] =
{
" a_position " ,
" a_normal " ,
" a_tangent " ,
" a_bitangent " ,
" a_color0 " ,
" a_color1 " ,
" a_color2 " ,
" a_color3 " ,
" a_indices " ,
" a_weight " ,
" a_texcoord0 " ,
" a_texcoord1 " ,
" a_texcoord2 " ,
" a_texcoord3 " ,
" a_texcoord4 " ,
" a_texcoord5 " ,
" a_texcoord6 " ,
" a_texcoord7 " ,
} ;
BX_STATIC_ASSERT ( bgfx : : Attrib : : Count = = BX_COUNTOF ( s_attribName ) ) ;
bgfx : : Attrib : : Enum toAttribEnum ( const bx : : StringView & _name )
{
for ( uint8_t ii = 0 ; ii < Attrib : : Count ; + + ii )
{
if ( 0 = = bx : : strCmp ( s_attribName [ ii ] , _name ) )
{
return bgfx : : Attrib : : Enum ( ii ) ;
}
}
return bgfx : : Attrib : : Count ;
}
2019-03-13 01:23:10 +03:00
static uint16_t writeUniformArray ( bx : : WriterI * _writer , const UniformArray & uniforms , bool isFragmentShader )
{
uint16_t size = 0 ;
uint16_t count = static_cast < uint16_t > ( uniforms . size ( ) ) ;
bx : : write ( _writer , count ) ;
uint32_t fragmentBit = isFragmentShader ? BGFX_UNIFORM_FRAGMENTBIT : 0 ;
for ( uint16_t ii = 0 ; ii < count ; + + ii )
{
const Uniform & un = uniforms [ ii ] ;
size + = un . regCount * 16 ;
uint8_t nameSize = ( uint8_t ) un . name . size ( ) ;
bx : : write ( _writer , nameSize ) ;
bx : : write ( _writer , un . name . c_str ( ) , nameSize ) ;
bx : : write ( _writer , uint8_t ( un . type | fragmentBit ) ) ;
bx : : write ( _writer , un . num ) ;
bx : : write ( _writer , un . regIndex ) ;
bx : : write ( _writer , un . regCount ) ;
BX_TRACE ( " %s, %s, %d, %d, %d "
, un . name . c_str ( )
, getUniformTypeName ( un . type )
, un . num
, un . regIndex
, un . regCount
) ;
}
return size ;
}
2018-04-14 03:12:43 +03:00
static bool compile ( const Options & _options , uint32_t _version , const std : : string & _code , bx : : WriterI * _writer , bool _firstPass )
2016-10-01 06:03:16 +03:00
{
2017-11-24 21:01:13 +03:00
BX_UNUSED ( _version ) ;
2016-12-16 06:03:47 +03:00
glslang : : InitializeProcess ( ) ;
glslang : : TProgram * program = new glslang : : TProgram ;
2017-11-24 21:01:13 +03:00
EShLanguage stage = getLang ( _options . shaderType ) ;
2017-03-24 23:20:38 +03:00
if ( EShLangCount = = stage )
{
2019-07-25 06:12:07 +03:00
bx : : printf ( " Error: Unknown shader type '%c'. \n " , _options . shaderType ) ;
2017-03-24 23:20:38 +03:00
return false ;
}
2016-12-16 06:03:47 +03:00
glslang : : TShader * shader = new glslang : : TShader ( stage ) ;
EShMessages messages = EShMessages ( 0
| EShMsgDefault
| EShMsgReadHlsl
| EShMsgVulkanRules
| EShMsgSpvRules
) ;
2017-03-24 23:20:38 +03:00
shader - > setEntryPoint ( " main " ) ;
2016-12-16 06:03:47 +03:00
2017-03-24 23:20:38 +03:00
const char * shaderStrings [ ] = { _code . c_str ( ) } ;
shader - > setStrings (
2016-12-16 06:03:47 +03:00
shaderStrings
2017-03-24 23:20:38 +03:00
, BX_COUNTOF ( shaderStrings )
2016-12-16 06:03:47 +03:00
) ;
bool compiled = shader - > parse ( & resourceLimits
, 110
, false
, messages
) ;
bool linked = false ;
bool validated = true ;
if ( ! compiled )
{
const char * log = shader - > getInfoLog ( ) ;
if ( NULL ! = log )
{
int32_t source = 0 ;
int32_t line = 0 ;
int32_t column = 0 ;
int32_t start = 0 ;
int32_t end = INT32_MAX ;
2018-10-21 09:33:31 +03:00
bx : : StringView err = bx : : strFind ( log , " ERROR: " ) ;
2016-12-16 06:03:47 +03:00
bool found = false ;
2018-10-21 09:33:31 +03:00
if ( ! err . isEmpty ( ) )
2016-12-16 06:03:47 +03:00
{
2018-10-21 09:33:31 +03:00
found = 2 = = sscanf ( err . getPtr ( ) , " ERROR: %u:%u: ' " , & source , & line ) ;
2016-12-16 06:03:47 +03:00
if ( found )
{
+ + line ;
}
}
if ( found )
{
start = bx : : uint32_imax ( 1 , line - 10 ) ;
end = start + 20 ;
}
printCode ( _code . c_str ( ) , line , start , end , column ) ;
2019-07-25 06:12:07 +03:00
bx : : printf ( " %s \n " , log ) ;
2016-12-16 06:03:47 +03:00
}
}
else
{
program - > addShader ( shader ) ;
linked = true
& & program - > link ( messages )
& & program - > mapIO ( )
;
if ( ! linked )
{
const char * log = program - > getInfoLog ( ) ;
if ( NULL ! = log )
{
2019-07-25 06:12:07 +03:00
bx : : printf ( " %s \n " , log ) ;
2016-12-16 06:03:47 +03:00
}
}
else
{
2017-02-17 20:35:09 +03:00
program - > buildReflection ( ) ;
2018-04-14 03:12:43 +03:00
if ( _firstPass )
{
// first time through, we just find unused uniforms and get rid of them
std : : string output ;
bx : : Error err ;
LineReader reader ( _code . c_str ( ) ) ;
while ( err . isOk ( ) )
{
char str [ 4096 ] ;
int32_t len = bx : : read ( & reader , str , BX_COUNTOF ( str ) , & err ) ;
if ( err . isOk ( ) )
{
std : : string strLine ( str , len ) ;
2018-04-14 20:30:00 +03:00
size_t index = strLine . find ( " uniform " ) ;
if ( index ! = std : : string : : npos )
2018-04-14 03:12:43 +03:00
{
2018-04-14 20:30:00 +03:00
bool found = false ;
2019-01-20 13:16:58 +03:00
if ( ! bx : : findIdentifierMatch ( strLine . c_str ( ) , " SamplerState " ) . isEmpty ( ) | |
! bx : : findIdentifierMatch ( strLine . c_str ( ) , " SamplerComparisonState " ) . isEmpty ( ) )
2018-04-14 03:12:43 +03:00
{
2019-01-17 23:04:23 +03:00
found = true ;
2019-01-19 10:28:37 +03:00
}
2019-01-17 23:04:23 +03:00
else
{
for ( int32_t ii = 0 , num = program - > getNumLiveUniformVariables ( ) ; ii < num ; + + ii )
2018-04-14 20:30:00 +03:00
{
2019-01-17 23:04:23 +03:00
// matching lines like: uniform u_name;
// we want to replace "uniform" with "static" so that it's no longer
// included in the uniform blob that the application must upload
// we can't just remove them, because unused functions might still reference
// them and cause a compile error when they're gone
if ( ! bx : : findIdentifierMatch ( strLine . c_str ( ) , program - > getUniformName ( ii ) ) . isEmpty ( ) )
{
found = true ;
break ;
}
2018-04-14 20:30:00 +03:00
}
2018-04-14 03:12:43 +03:00
}
2018-04-14 20:30:00 +03:00
if ( ! found )
2018-04-14 03:12:43 +03:00
{
2019-01-19 10:28:37 +03:00
strLine = strLine . replace ( index , 7 /* uniform */ , " static " ) ;
2018-04-14 03:12:43 +03:00
}
}
output + = strLine ;
}
}
// recompile with the unused uniforms converted to statics
return compile ( _options , _version , output . c_str ( ) , _writer , false ) ;
}
2019-03-13 01:23:10 +03:00
UniformArray uniforms ;
2017-02-17 20:35:09 +03:00
{
uint16_t count = ( uint16_t ) program - > getNumLiveUniformVariables ( ) ;
for ( uint16_t ii = 0 ; ii < count ; + + ii )
{
Uniform un ;
un . name = program - > getUniformName ( ii ) ;
2018-04-13 06:20:41 +03:00
un . num = uint8_t ( program - > getUniformArraySize ( ii ) ) ;
2018-04-14 20:30:00 +03:00
const uint32_t offset = program - > getUniformBufferOffset ( ii ) ;
un . regIndex = uint16_t ( offset ) ;
2018-04-13 06:20:41 +03:00
un . regCount = un . num ;
2017-02-17 20:35:09 +03:00
switch ( program - > getUniformType ( ii ) )
{
case 0x1404 : // GL_INT:
2019-01-12 01:14:17 +03:00
un . type = UniformType : : Sampler ;
2017-02-17 20:35:09 +03:00
break ;
case 0x8B52 : // GL_FLOAT_VEC4:
un . type = UniformType : : Vec4 ;
break ;
case 0x8B5B : // GL_FLOAT_MAT3:
un . type = UniformType : : Mat3 ;
2018-04-13 06:20:41 +03:00
un . regCount * = 3 ;
2017-02-17 20:35:09 +03:00
break ;
case 0x8B5C : // GL_FLOAT_MAT4:
un . type = UniformType : : Mat4 ;
2018-04-13 06:20:41 +03:00
un . regCount * = 4 ;
2017-02-17 20:35:09 +03:00
break ;
default :
un . type = UniformType : : End ;
break ;
}
2018-04-13 06:20:41 +03:00
2019-03-13 01:23:10 +03:00
uniforms . push_back ( un ) ;
2017-02-17 20:35:09 +03:00
}
}
2017-03-24 23:20:38 +03:00
if ( g_verbose )
{
program - > dumpReflection ( ) ;
}
2016-12-16 06:03:47 +03:00
2016-12-17 23:38:22 +03:00
BX_UNUSED ( spv : : MemorySemanticsAllMemory ) ;
2016-12-16 06:03:47 +03:00
glslang : : TIntermediate * intermediate = program - > getIntermediate ( stage ) ;
std : : vector < uint32_t > spirv ;
2018-04-11 05:44:28 +03:00
glslang : : SpvOptions options ;
options . disableOptimizer = false ;
glslang : : GlslangToSpv ( * intermediate , spirv , & options ) ;
2019-01-16 06:38:35 +03:00
2019-01-16 00:12:48 +03:00
spvtools : : Optimizer opt ( SPV_ENV_VULKAN_1_0 ) ;
2019-01-16 06:38:35 +03:00
2019-07-25 06:12:07 +03:00
auto print_msg_to_stderr = [ ] (
spv_message_level_t
, const char *
, const spv_position_t &
, const char * m
)
{
bx : : printf ( " Error: %s \n " , m ) ;
2019-01-16 00:12:48 +03:00
} ;
2019-07-25 06:12:07 +03:00
2019-01-16 00:12:48 +03:00
opt . SetMessageConsumer ( print_msg_to_stderr ) ;
2019-01-16 06:38:35 +03:00
2019-01-16 00:12:48 +03:00
opt . RegisterLegalizationPasses ( ) ;
if ( ! opt . Run ( spirv . data ( ) , spirv . size ( ) , & spirv ) )
2019-01-14 11:24:06 +03:00
{
2019-01-16 00:12:48 +03:00
compiled = false ;
2019-01-14 11:24:06 +03:00
}
else
{
2019-01-16 00:12:48 +03:00
bx : : Error err ;
bx : : WriterI * writer = bx : : getDebugOut ( ) ;
bx : : MemoryReader reader ( spirv . data ( ) , uint32_t ( spirv . size ( ) * 4 ) ) ;
disassemble ( writer , & reader , & err ) ;
2019-01-16 06:38:35 +03:00
2019-03-13 01:23:10 +03:00
spirv_cross : : CompilerReflection refl ( spirv ) ;
spirv_cross : : ShaderResources resourcesrefl = refl . get_shader_resources ( ) ;
// Loop through the separate_images, and extract the uniform names:
for ( auto & resource : resourcesrefl . separate_images )
{
std : : string name = refl . get_name ( resource . id ) ;
if ( name . size ( ) > 7 & & 0 = = bx : : strCmp ( name . c_str ( ) + name . length ( ) - 7 , " Texture " ) )
{
auto uniform_name = name . substr ( 0 , name . length ( ) - 7 ) ;
Uniform un ;
un . name = uniform_name ;
un . type = UniformType : : Sampler ;
un . num = 0 ; // needed?
un . regIndex = 0 ; // needed?
un . regCount = 0 ; // needed?
uniforms . push_back ( un ) ;
}
}
uint16_t size = writeUniformArray ( _writer , uniforms , _options . shaderType = = ' f ' ) ;
2019-01-16 00:12:48 +03:00
if ( _version = = BX_MAKEFOURCC ( ' M ' , ' T ' , ' L ' , 0 ) )
2018-04-14 20:30:00 +03:00
{
2019-01-16 00:12:48 +03:00
if ( g_verbose )
{
glslang : : SpirvToolsDisassemble ( std : : cout , spirv ) ;
}
2019-01-16 06:38:35 +03:00
2019-01-16 00:12:48 +03:00
spirv_cross : : CompilerMSL msl ( std : : move ( spirv ) ) ;
2019-01-16 06:38:35 +03:00
2019-01-16 00:12:48 +03:00
spirv_cross : : ShaderResources resources = msl . get_shader_resources ( ) ;
2019-01-16 06:38:35 +03:00
2019-04-15 07:53:50 +03:00
spirv_cross : : SmallVector < spirv_cross : : EntryPoint > entryPoints = msl . get_entry_points_and_stages ( ) ;
2019-01-20 13:16:58 +03:00
if ( ! entryPoints . empty ( ) )
msl . rename_entry_point ( entryPoints [ 0 ] . name , " xlatMtlMain " , entryPoints [ 0 ] . execution_model ) ;
2019-01-16 06:38:35 +03:00
2019-01-16 00:12:48 +03:00
for ( auto & resource : resources . uniform_buffers )
{
msl . set_name ( resource . id , " _mtl_u " ) ;
}
2019-01-16 06:38:35 +03:00
2019-01-16 00:12:48 +03:00
for ( auto & resource : resources . storage_buffers )
{
unsigned binding = msl . get_decoration ( resource . id , spv : : DecorationBinding ) ;
msl . set_decoration ( resource . id , spv : : DecorationBinding , binding + 1 ) ;
}
2019-01-16 06:38:35 +03:00
2019-01-23 00:31:41 +03:00
for ( auto & resource : resources . separate_images )
{
std : : string name = msl . get_name ( resource . id ) ;
if ( name . size ( ) > 7 & & 0 = = bx : : strCmp ( name . c_str ( ) + name . length ( ) - 7 , " Texture " ) )
msl . set_name ( resource . id , name . substr ( 0 , name . length ( ) - 7 ) ) ;
}
2019-01-16 00:12:48 +03:00
std : : string source = msl . compile ( ) ;
2019-01-16 06:38:35 +03:00
2019-01-20 13:16:58 +03:00
if ( ' c ' = = _options . shaderType )
2019-01-16 00:12:48 +03:00
{
2019-01-20 13:16:58 +03:00
for ( int i = 0 ; i < 3 ; + + i )
{
uint16_t dim = ( uint16_t ) msl . get_execution_mode_argument ( spv : : ExecutionMode : : ExecutionModeLocalSize , i ) ;
bx : : write ( _writer , dim ) ;
}
2019-01-16 00:12:48 +03:00
}
2019-01-16 06:38:35 +03:00
2019-01-16 00:12:48 +03:00
uint32_t shaderSize = ( uint32_t ) source . size ( ) ;
bx : : write ( _writer , shaderSize ) ;
bx : : write ( _writer , source . c_str ( ) , shaderSize ) ;
uint8_t nul = 0 ;
bx : : write ( _writer , nul ) ;
2018-04-14 20:30:00 +03:00
}
else
{
2019-01-16 00:12:48 +03:00
uint32_t shaderSize = ( uint32_t ) spirv . size ( ) * sizeof ( uint32_t ) ;
bx : : write ( _writer , shaderSize ) ;
bx : : write ( _writer , spirv . data ( ) , shaderSize ) ;
uint8_t nul = 0 ;
bx : : write ( _writer , nul ) ;
2018-04-14 20:30:00 +03:00
}
2019-01-16 00:12:48 +03:00
//
const uint8_t numAttr = ( uint8_t ) program - > getNumLiveAttributes ( ) ;
bx : : write ( _writer , numAttr ) ;
2019-01-16 06:38:35 +03:00
2019-01-16 00:12:48 +03:00
for ( uint8_t ii = 0 ; ii < numAttr ; + + ii )
{
bgfx : : Attrib : : Enum attr = toAttribEnum ( program - > getAttributeName ( ii ) ) ;
if ( bgfx : : Attrib : : Count ! = attr )
{
bx : : write ( _writer , bgfx : : attribToId ( attr ) ) ;
}
else
{
bx : : write ( _writer , uint16_t ( UINT16_MAX ) ) ;
}
}
2019-01-16 06:38:35 +03:00
2019-01-16 00:12:48 +03:00
bx : : write ( _writer , size ) ;
2018-04-14 20:30:00 +03:00
}
2016-12-16 06:03:47 +03:00
}
}
delete program ;
delete shader ;
glslang : : FinalizeProcess ( ) ;
2018-04-13 06:20:41 +03:00
return compiled & & linked & & validated ;
2016-12-16 06:03:47 +03:00
}
} // namespace spirv
2017-11-24 21:01:13 +03:00
bool compileSPIRVShader ( const Options & _options , uint32_t _version , const std : : string & _code , bx : : WriterI * _writer )
2016-12-16 06:03:47 +03:00
{
2018-04-14 03:12:43 +03:00
return spirv : : compile ( _options , _version , _code , _writer , true ) ;
2016-10-01 06:03:16 +03:00
}
} // namespace bgfx