2016-10-01 06:03:16 +03:00
/*
2023-01-14 21:05:12 +03:00
* Copyright 2011 - 2023 Branimir Karadzic . All rights reserved .
2022-01-15 22:59:06 +03:00
* License : https : //github.com/bkaradzic/bgfx/blob/master/LICENSE
2016-10-01 06:03:16 +03:00
*/
# include "shaderc.h"
2023-11-28 09:27:59 +03:00
# include <iostream> // std::cout
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
2020-06-21 01:14:54 +03:00
BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC ( " -Wattributes " ) // warning: attribute ignored
BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC ( " -Wdeprecated-declarations " ) // warning: ‘ MSLVertexAttr’ is deprecated
BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC ( " -Wtype-limits " ) // warning: comparison of unsigned expression in ‘ < 0’ is always false
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>
2023-11-28 09:27:59 +03:00
# include <SPIRV/SpvTools.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 )
{
2023-04-24 05:19:22 +03:00
return bx : : alloc ( g_allocator , _bytes ) ;
2016-12-16 06:03:47 +03:00
}
void TinyStlAllocator : : static_deallocate ( void * _ptr , size_t /*_bytes*/ )
{
if ( NULL ! = _ptr )
{
2023-04-24 05:19:22 +03:00
bx : : free ( g_allocator , _ptr ) ;
2016-12-16 06:03:47 +03:00
}
}
} // 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 ;
2021-02-28 23:38:12 +03:00
# include "../../src/shader.h"
2021-04-22 08:11:36 +03:00
# include "../../src/shader_spirv.h"
2020-04-08 08:49:55 +03:00
# include "../../3rdparty/khronos/vulkan-local/vulkan.h"
2016-12-16 06:03:47 +03:00
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
2020-05-05 07:14:04 +03:00
0 , // maxMeshOutputVerticesNV
0 , // maxMeshOutputPrimitivesNV
0 , // maxMeshWorkGroupSizeX_NV
0 , // maxMeshWorkGroupSizeY_NV
0 , // maxMeshWorkGroupSizeZ_NV
0 , // maxTaskWorkGroupSizeX_NV
0 , // maxTaskWorkGroupSizeY_NV
0 , // maxTaskWorkGroupSizeZ_NV
2018-10-02 06:01:14 +03:00
0 , // maxMeshViewCountNV
2022-10-03 08:57:50 +03:00
0 , // maxMeshOutputVerticesEXT
0 , // maxMeshOutputPrimitivesEXT
0 , // maxMeshWorkGroupSizeX_EXT
0 , // maxMeshWorkGroupSizeY_EXT
0 , // maxMeshWorkGroupSizeZ_EXT
0 , // maxTaskWorkGroupSizeX_EXT
0 , // maxTaskWorkGroupSizeY_EXT
0 , // maxTaskWorkGroupSizeZ_EXT
0 , // maxMeshViewCountEXT
2020-05-05 07:14:04 +03:00
0 , // maxDualSourceDrawBuffersEXT
2018-10-02 06:01:14 +03:00
{ // 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
} ,
} ;
2021-04-21 06:18:49 +03:00
bgfx : : TextureComponentType : : Enum SpirvCrossBaseTypeToFormatType ( spirv_cross : : SPIRType : : BaseType spirvBaseType , bool depth )
2020-05-08 18:53:53 +03:00
{
2021-04-21 06:18:49 +03:00
if ( depth )
return bgfx : : TextureComponentType : : Depth ;
switch ( spirvBaseType )
2020-05-08 18:53:53 +03:00
{
case spirv_cross : : SPIRType : : Float :
2021-02-28 23:38:12 +03:00
return bgfx : : TextureComponentType : : Float ;
2020-05-08 18:53:53 +03:00
case spirv_cross : : SPIRType : : Int :
2021-02-28 23:38:12 +03:00
return bgfx : : TextureComponentType : : Int ;
2020-05-08 18:53:53 +03:00
case spirv_cross : : SPIRType : : UInt :
2021-02-28 23:38:12 +03:00
return bgfx : : TextureComponentType : : Uint ;
2020-05-08 18:53:53 +03:00
default :
2021-02-28 23:38:12 +03:00
return bgfx : : TextureComponentType : : Float ;
2020-05-08 18:53:53 +03:00
}
}
2021-02-28 23:38:12 +03:00
bgfx : : TextureDimension : : Enum SpirvDimToTextureViewDimension ( spv : : Dim _dim , bool _arrayed )
2020-05-08 18:53:53 +03:00
{
2021-02-28 23:38:12 +03:00
switch ( _dim )
2020-05-08 18:53:53 +03:00
{
case spv : : Dim : : Dim1D :
2021-02-28 23:38:12 +03:00
return bgfx : : TextureDimension : : Dimension1D ;
2020-05-08 18:53:53 +03:00
case spv : : Dim : : Dim2D :
2021-02-28 23:38:12 +03:00
return _arrayed
? bgfx : : TextureDimension : : Dimension2DArray
: bgfx : : TextureDimension : : Dimension2D
;
2020-05-08 18:53:53 +03:00
case spv : : Dim : : Dim3D :
2021-02-28 23:38:12 +03:00
return bgfx : : TextureDimension : : Dimension3D ;
2020-05-08 18:53:53 +03:00
case spv : : Dim : : DimCube :
2021-02-28 23:38:12 +03:00
return _arrayed
? bgfx : : TextureDimension : : DimensionCubeArray
: bgfx : : TextureDimension : : DimensionCube
;
2020-05-08 18:53:53 +03:00
default :
2021-02-28 23:38:12 +03:00
BX_ASSERT ( false , " Unknown texture dimension %d " , _dim ) ;
return bgfx : : TextureDimension : : Dimension2D ;
2020-05-08 18:53:53 +03:00
}
}
2021-04-21 06:18:49 +03:00
static bgfx : : TextureFormat : : Enum s_textureFormats [ ] =
{
bgfx : : TextureFormat : : Unknown , // spv::ImageFormatUnknown = 0
bgfx : : TextureFormat : : RGBA32F , // spv::ImageFormatRgba32f = 1
bgfx : : TextureFormat : : RGBA16F , // spv::ImageFormatRgba16f = 2
bgfx : : TextureFormat : : R32F , // spv::ImageFormatR32f = 3
bgfx : : TextureFormat : : RGBA8 , // spv::ImageFormatRgba8 = 4
bgfx : : TextureFormat : : RGBA8S , // spv::ImageFormatRgba8Snorm = 5
bgfx : : TextureFormat : : RG32F , // spv::ImageFormatRg32f = 6
bgfx : : TextureFormat : : RG16F , // spv::ImageFormatRg16f = 7
bgfx : : TextureFormat : : RG11B10F , // spv::ImageFormatR11fG11fB10f = 8
bgfx : : TextureFormat : : R16F , // spv::ImageFormatR16f = 9
bgfx : : TextureFormat : : RGBA16 , // spv::ImageFormatRgba16 = 10
bgfx : : TextureFormat : : RGB10A2 , // spv::ImageFormatRgb10A2 = 11
bgfx : : TextureFormat : : RG16 , // spv::ImageFormatRg16 = 12
bgfx : : TextureFormat : : RG8 , // spv::ImageFormatRg8 = 13
bgfx : : TextureFormat : : R16 , // spv::ImageFormatR16 = 14
bgfx : : TextureFormat : : R8 , // spv::ImageFormatR8 = 15
bgfx : : TextureFormat : : RGBA16S , // spv::ImageFormatRgba16Snorm = 16
bgfx : : TextureFormat : : RG16S , // spv::ImageFormatRg16Snorm = 17
bgfx : : TextureFormat : : RG8S , // spv::ImageFormatRg8Snorm = 18
bgfx : : TextureFormat : : R16S , // spv::ImageFormatR16Snorm = 19
bgfx : : TextureFormat : : R8S , // spv::ImageFormatR8Snorm = 20
bgfx : : TextureFormat : : RGBA32I , // spv::ImageFormatRgba32i = 21
bgfx : : TextureFormat : : RGBA16I , // spv::ImageFormatRgba16i = 22
bgfx : : TextureFormat : : RGBA8I , // spv::ImageFormatRgba8i = 23
bgfx : : TextureFormat : : R32I , // spv::ImageFormatR32i = 24
bgfx : : TextureFormat : : RG32I , // spv::ImageFormatRg32i = 25
bgfx : : TextureFormat : : RG16I , // spv::ImageFormatRg16i = 26
bgfx : : TextureFormat : : RG8I , // spv::ImageFormatRg8i = 27
bgfx : : TextureFormat : : R16I , // spv::ImageFormatR16i = 28
bgfx : : TextureFormat : : R8I , // spv::ImageFormatR8i = 29
bgfx : : TextureFormat : : RGBA32U , // spv::ImageFormatRgba32ui = 30
bgfx : : TextureFormat : : RGBA16U , // spv::ImageFormatRgba16ui = 31
bgfx : : TextureFormat : : RGBA8U , // spv::ImageFormatRgba8ui = 32
bgfx : : TextureFormat : : R32U , // spv::ImageFormatR32ui = 33
bgfx : : TextureFormat : : Unknown , // spv::ImageFormatRgb10a2ui = 34
bgfx : : TextureFormat : : RG32U , // spv::ImageFormatRg32ui = 35
bgfx : : TextureFormat : : RG16U , // spv::ImageFormatRg16ui = 36
bgfx : : TextureFormat : : RG8U , // spv::ImageFormatRg8ui = 37
bgfx : : TextureFormat : : R16U , // spv::ImageFormatR16ui = 38
bgfx : : TextureFormat : : R8U , // spv::ImageFormatR8ui = 39
bgfx : : TextureFormat : : Unknown , // spv::ImageFormatR64ui = 40
bgfx : : TextureFormat : : Unknown , // spv::ImageFormatR64i = 41
} ;
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-10-05 06:03:27 +03:00
static const char * s_samplerTypes [ ] =
{
" BgfxSampler2D " ,
" BgfxISampler2D " ,
" BgfxUSampler2D " ,
" BgfxSampler2DArray " ,
" BgfxSampler2DShadow " ,
" BgfxSampler2DArrayShadow " ,
" BgfxSampler3D " ,
" BgfxISampler3D " ,
" BgfxUSampler3D " ,
" BgfxSamplerCube " ,
" BgfxSamplerCubeShadow " ,
" BgfxSampler2DMS " ,
} ;
2023-03-06 21:30:06 +03:00
static uint16_t writeUniformArray ( bx : : WriterI * _shaderWriter , const UniformArray & uniforms , bool isFragmentShader )
2019-03-13 01:23:10 +03:00
{
uint16_t size = 0 ;
2021-10-26 05:26:38 +03:00
bx : : ErrorAssert err ;
2021-10-26 04:59:32 +03:00
2021-11-01 01:54:10 +03:00
uint16_t count = uint16_t ( uniforms . size ( ) ) ;
2023-03-06 21:30:06 +03:00
bx : : write ( _shaderWriter , count , & err ) ;
2019-03-13 01:23:10 +03:00
2020-06-19 07:20:01 +03:00
uint32_t fragmentBit = isFragmentShader ? kUniformFragmentBit : 0 ;
2020-06-21 01:14:54 +03:00
2019-03-13 01:23:10 +03:00
for ( uint16_t ii = 0 ; ii < count ; + + ii )
{
const Uniform & un = uniforms [ ii ] ;
2020-06-21 01:14:54 +03:00
if ( ( un . type & ~ kUniformMask ) > UniformType : : End )
{
size = bx : : max ( size , ( uint16_t ) ( un . regIndex + un . regCount * 16 ) ) ;
}
2019-03-13 01:23:10 +03:00
uint8_t nameSize = ( uint8_t ) un . name . size ( ) ;
2023-03-06 21:30:06 +03:00
bx : : write ( _shaderWriter , nameSize , & err ) ;
bx : : write ( _shaderWriter , un . name . c_str ( ) , nameSize , & err ) ;
bx : : write ( _shaderWriter , uint8_t ( un . type | fragmentBit ) , & err ) ;
bx : : write ( _shaderWriter , un . num , & err ) ;
bx : : write ( _shaderWriter , un . regIndex , & err ) ;
bx : : write ( _shaderWriter , un . regCount , & err ) ;
bx : : write ( _shaderWriter , un . texComponent , & err ) ;
bx : : write ( _shaderWriter , un . texDimension , & err ) ;
bx : : write ( _shaderWriter , un . texFormat , & err ) ;
2019-03-13 01:23:10 +03:00
BX_TRACE ( " %s, %s, %d, %d, %d "
, un . name . c_str ( )
2021-10-26 20:07:27 +03:00
, getUniformTypeName ( UniformType : : Enum ( un . type & ~ kUniformMask ) )
2019-03-13 01:23:10 +03:00
, un . num
, un . regIndex
, un . regCount
2020-06-21 01:14:54 +03:00
) ;
2019-03-13 01:23:10 +03:00
}
return size ;
}
2020-10-18 06:02:51 +03:00
static spv_target_env getSpirvTargetVersion ( uint32_t version )
{
switch ( version )
{
case 1010 :
return SPV_ENV_VULKAN_1_0 ;
case 1311 :
return SPV_ENV_VULKAN_1_1 ;
case 1411 :
return SPV_ENV_VULKAN_1_1_SPIRV_1_4 ;
case 1512 :
return SPV_ENV_VULKAN_1_2 ;
2023-01-07 20:07:15 +03:00
case 1613 :
return SPV_ENV_VULKAN_1_3 ;
2020-10-18 06:02:51 +03:00
default :
BX_ASSERT ( 0 , " Unknown SPIR-V version requested. Returning SPV_ENV_VULKAN_1_0 as default. " ) ;
return SPV_ENV_VULKAN_1_0 ;
}
}
static glslang : : EShTargetClientVersion getGlslangTargetVulkanVersion ( uint32_t version )
{
switch ( version )
{
case 1010 :
return glslang : : EShTargetVulkan_1_0 ;
case 1311 :
case 1411 :
return glslang : : EShTargetVulkan_1_1 ;
case 1512 :
return glslang : : EShTargetVulkan_1_2 ;
2023-01-07 20:07:15 +03:00
case 1613 :
return glslang : : EShTargetVulkan_1_3 ;
2020-10-18 06:02:51 +03:00
default :
BX_ASSERT ( 0 , " Unknown SPIR-V version requested. Returning EShTargetVulkan_1_0 as default. " ) ;
return glslang : : EShTargetVulkan_1_0 ;
}
}
static glslang : : EShTargetLanguageVersion getGlslangTargetSpirvVersion ( uint32_t version )
{
switch ( version )
{
case 1010 :
return glslang : : EShTargetSpv_1_0 ;
case 1311 :
return glslang : : EShTargetSpv_1_3 ;
case 1411 :
return glslang : : EShTargetSpv_1_4 ;
case 1512 :
return glslang : : EShTargetSpv_1_5 ;
2023-01-07 20:07:15 +03:00
case 1613 :
return glslang : : EShTargetSpv_1_6 ;
2020-10-18 06:02:51 +03:00
default :
BX_ASSERT ( 0 , " Unknown SPIR-V version requested. Returning EShTargetSpv_1_0 as default. " ) ;
return glslang : : EShTargetSpv_1_0 ;
}
}
/// This is the value used to fill out GLSLANG's SpvVersion object.
/// The required value is that which is defined by GL_KHR_vulkan_glsl, which is defined here:
/// https://github.com/KhronosGroup/GLSL/blob/master/extensions/khr/GL_KHR_vulkan_glsl.txt
/// The value is 100.
constexpr int s_GLSL_VULKAN_CLIENT_VERSION = 100 ;
2023-03-06 21:30:06 +03:00
static bool compile ( const Options & _options , uint32_t _version , const std : : string & _code , bx : : WriterI * _shaderWriter , bx : : WriterI * _messageWriter , 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
2023-03-06 21:30:06 +03:00
bx : : ErrorAssert messageErr ;
2016-12-16 06:03:47 +03:00
glslang : : InitializeProcess ( ) ;
2017-11-24 21:01:13 +03:00
EShLanguage stage = getLang ( _options . shaderType ) ;
2017-03-24 23:20:38 +03:00
if ( EShLangCount = = stage )
{
2023-03-06 21:30:06 +03:00
bx : : write ( _messageWriter , & messageErr , " Error: Unknown shader type '%c'. \n " , _options . shaderType ) ;
2017-03-24 23:20:38 +03:00
return false ;
}
2021-02-12 08:43:22 +03:00
glslang : : TProgram * program = new glslang : : TProgram ;
glslang : : TShader * shader = new glslang : : TShader ( stage ) ;
2016-12-16 06:03:47 +03:00
EShMessages messages = EShMessages ( 0
| EShMsgDefault
| EShMsgReadHlsl
| EShMsgVulkanRules
| EShMsgSpvRules
2023-11-06 22:14:29 +03:00
| EShMsgDebugInfo
2016-12-16 06:03:47 +03:00
) ;
2017-03-24 23:20:38 +03:00
shader - > setEntryPoint ( " main " ) ;
2019-07-16 11:42:25 +03:00
shader - > setAutoMapBindings ( true ) ;
2020-10-18 06:02:51 +03:00
shader - > setEnvInput ( glslang : : EShSourceHlsl , stage , glslang : : EShClientVulkan , s_GLSL_VULKAN_CLIENT_VERSION ) ;
shader - > setEnvClient ( glslang : : EShClientVulkan , getGlslangTargetVulkanVersion ( _version ) ) ;
shader - > setEnvTarget ( glslang : : EShTargetSpv , getGlslangTargetSpirvVersion ( _version ) ) ;
2021-04-21 19:33:12 +03:00
// Reserve two spots for the stage UBOs
shader - > setShiftBinding ( glslang : : EResUbo , ( stage = = EShLanguage : : EShLangFragment ? kSpirvFragmentBinding : kSpirvVertexBinding ) ) ;
shader - > setShiftBinding ( glslang : : EResTexture , kSpirvBindShift ) ;
shader - > setShiftBinding ( glslang : : EResSampler , kSpirvBindShift + kSpirvSamplerShift ) ;
shader - > setShiftBinding ( glslang : : EResSsbo , kSpirvBindShift ) ;
shader - > setShiftBinding ( glslang : : EResImage , kSpirvBindShift ) ;
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 ) ;
2023-03-06 21:30:06 +03:00
bx : : write ( _messageWriter , & messageErr , " %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 )
{
2023-03-06 21:30:06 +03:00
bx : : write ( _messageWriter , & messageErr , " %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 ;
2020-05-03 23:54:30 +03:00
struct Uniform
{
std : : string name ;
std : : string decl ;
} ;
std : : vector < Uniform > uniforms ;
2020-06-21 01:14:54 +03:00
bx : : LineReader reader ( _code . c_str ( ) ) ;
while ( ! reader . isDone ( ) )
2018-04-14 03:12:43 +03:00
{
2020-06-21 01:14:54 +03:00
bx : : StringView strLine = reader . next ( ) ;
2018-04-14 03:12:43 +03:00
2020-06-21 01:14:54 +03:00
bool moved = false ;
2020-05-03 23:54:30 +03:00
2020-06-21 01:14:54 +03:00
bx : : StringView str = strFind ( strLine , " uniform " ) ;
if ( ! str . isEmpty ( ) )
{
bool found = false ;
bool sampler = false ;
std : : string name = " " ;
2020-05-03 23:54:30 +03:00
2020-06-21 01:14:54 +03:00
// add to samplers
2018-04-14 20:30:00 +03:00
2020-06-21 01:14:54 +03:00
for ( uint32_t ii = 0 ; ii < BX_COUNTOF ( s_samplerTypes ) ; + + ii )
{
if ( ! bx : : findIdentifierMatch ( strLine , s_samplerTypes [ ii ] ) . isEmpty ( ) )
2018-04-14 03:12:43 +03:00
{
2020-06-21 01:14:54 +03:00
found = true ;
sampler = true ;
break ;
2019-01-19 10:28:37 +03:00
}
2020-06-21 01:14:54 +03:00
}
2019-10-05 19:52:04 +03:00
2020-06-21 01:14:54 +03:00
if ( ! found )
{
for ( int32_t ii = 0 , num = program - > getNumLiveUniformVariables ( ) ; ii < num ; + + ii )
2019-01-17 23:04:23 +03:00
{
2020-06-21 01:14:54 +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 , program - > getUniformName ( ii ) ) . isEmpty ( ) )
2018-04-14 20:30:00 +03:00
{
2020-06-21 01:14:54 +03:00
found = true ;
name = program - > getUniformName ( ii ) ;
break ;
2018-04-14 20:30:00 +03:00
}
2018-04-14 03:12:43 +03:00
}
2020-06-21 01:14:54 +03:00
}
2018-04-14 03:12:43 +03:00
2020-06-21 01:14:54 +03:00
if ( ! found )
{
output . append ( strLine . getPtr ( ) , str . getPtr ( ) ) ;
output + = " static " ;
output . append ( str . getTerm ( ) , strLine . getTerm ( ) ) ;
output + = " \n " ;
moved = true ;
2018-04-14 03:12:43 +03:00
}
2020-06-21 01:14:54 +03:00
else if ( ! sampler )
{
Uniform uniform ;
uniform . name = name ;
uniform . decl = std : : string ( strLine . getPtr ( ) , strLine . getTerm ( ) ) ;
uniforms . push_back ( uniform ) ;
moved = true ;
}
}
2018-04-14 03:12:43 +03:00
2020-06-21 01:14:54 +03:00
if ( ! moved )
{
output . append ( strLine . getPtr ( ) , strLine . getTerm ( ) ) ;
output + = " \n " ;
2018-04-14 03:12:43 +03:00
}
}
2020-05-03 23:54:30 +03:00
std : : string uniformBlock ;
uniformBlock + = " cbuffer UniformBlock \n " ;
uniformBlock + = " { \n " ;
2020-06-21 01:14:54 +03:00
2020-05-03 23:54:30 +03:00
for ( const Uniform & uniform : uniforms )
{
uniformBlock + = uniform . decl . substr ( 7 /* uniform */ ) ;
2020-06-21 01:14:54 +03:00
uniformBlock + = " \n " ;
2020-05-03 23:54:30 +03:00
}
2020-06-21 01:14:54 +03:00
2020-05-03 23:54:30 +03:00
uniformBlock + = " }; \n " ;
output = uniformBlock + output ;
2018-04-14 03:12:43 +03:00
// recompile with the unused uniforms converted to statics
2021-02-12 08:43:22 +03:00
delete program ;
delete shader ;
2023-03-06 21:30:06 +03:00
return compile ( _options , _version , output . c_str ( ) , _shaderWriter , _messageWriter , false ) ;
2018-04-14 03:12:43 +03:00
}
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
2021-10-02 06:13:46 +03:00
if ( bx : : hasSuffix ( un . name . c_str ( ) , " .@data " ) )
{
continue ;
}
2022-10-28 05:43:17 +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 ) ;
2022-10-28 05:43:17 +03:00
un . regCount = un . num ;
2018-04-13 06:20:41 +03:00
2020-06-21 01:14:54 +03:00
switch ( program - > getUniformType ( ii ) )
2017-02-17 20:35:09 +03:00
{
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 ;
2019-08-16 07:37:35 +03:00
2017-02-17 20:35:09 +03:00
case 0x8B52 : // GL_FLOAT_VEC4:
un . type = UniformType : : Vec4 ;
break ;
2019-08-16 07:37:35 +03:00
2017-02-17 20:35:09 +03:00
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 ;
2019-08-16 07:37:35 +03:00
2017-02-17 20:35:09 +03:00
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 ;
2019-08-16 07:37:35 +03:00
2017-02-17 20:35:09 +03:00
default :
2021-04-21 06:18:49 +03:00
continue ;
2017-02-17 20:35:09 +03:00
}
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
}
}
2019-08-16 07:37:35 +03:00
2017-03-24 23:20:38 +03:00
if ( g_verbose )
{
program - > dumpReflection ( ) ;
}
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 ;
2023-11-06 22:14:29 +03:00
options . disableOptimizer = _options . debugInformation ;
options . generateDebugInfo = _options . debugInformation ;
options . emitNonSemanticShaderDebugInfo = _options . debugInformation ;
options . emitNonSemanticShaderDebugSource = _options . debugInformation ;
2018-04-11 05:44:28 +03:00
glslang : : GlslangToSpv ( * intermediate , spirv , & options ) ;
2019-01-16 06:38:35 +03:00
2020-10-18 06:02:51 +03:00
spvtools : : Optimizer opt ( getSpirvTargetVersion ( _version ) ) ;
2019-01-16 06:38:35 +03:00
2023-03-06 21:30:06 +03:00
auto print_msg_to_stderr = [ _messageWriter , & messageErr ] (
2019-07-25 06:12:07 +03:00
spv_message_level_t
, const char *
, const spv_position_t &
, const char * m
)
{
2023-03-06 21:30:06 +03:00
bx : : write ( _messageWriter , & messageErr , " 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 ( ) ;
2019-08-16 07:37:35 +03:00
2019-09-26 22:00:44 +03:00
spvtools : : ValidatorOptions validatorOptions ;
validatorOptions . SetBeforeHlslLegalization ( true ) ;
2019-09-28 20:30:23 +03:00
if ( ! opt . Run (
spirv . data ( )
, spirv . size ( )
, & spirv
, validatorOptions
, false
) )
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
{
2020-05-11 03:48:25 +03:00
if ( g_verbose )
{
2021-04-21 17:45:03 +03:00
glslang : : SpirvToolsDisassemble ( std : : cout , spirv , getSpirvTargetVersion ( _version ) ) ;
2020-05-11 03:48:25 +03:00
}
2021-04-21 17:45:03 +03:00
spirv_cross : : CompilerReflection refl ( spirv ) ;
spirv_cross : : ShaderResources resourcesrefl = refl . get_shader_resources ( ) ;
2019-03-13 01:23:10 +03:00
// Loop through the separate_images, and extract the uniform names:
for ( auto & resource : resourcesrefl . separate_images )
{
std : : string name = refl . get_name ( resource . id ) ;
2021-04-21 06:18:49 +03:00
2019-08-16 07:37:35 +03:00
if ( name . size ( ) > 7
& & 0 = = bx : : strCmp ( name . c_str ( ) + name . length ( ) - 7 , " Texture " ) )
2019-03-13 01:23:10 +03:00
{
2021-04-21 06:18:49 +03:00
name = name . substr ( 0 , name . length ( ) - 7 ) ;
}
2020-05-08 18:53:53 +03:00
2021-04-21 06:18:49 +03:00
uint32_t binding_index = refl . get_decoration ( resource . id , spv : : Decoration : : DecorationBinding ) ;
2020-05-08 18:53:53 +03:00
2021-04-21 06:18:49 +03:00
auto imageType = refl . get_type ( resource . base_type_id ) . image ;
auto componentType = refl . get_type ( imageType . type ) . basetype ;
bool isCompareSampler = false ;
for ( auto & sampler : resourcesrefl . separate_samplers )
{
if ( binding_index + 16 = = refl . get_decoration ( sampler . id , spv : : Decoration : : DecorationBinding ) )
2020-05-08 18:53:53 +03:00
{
2021-04-21 06:18:49 +03:00
std : : string samplerName = refl . get_name ( sampler . id ) ;
isCompareSampler = refl . variable_is_depth_or_compare ( sampler . id ) | | samplerName . find ( " Comparison " ) ! = std : : string : : npos ;
break ;
2020-05-08 18:53:53 +03:00
}
2021-04-21 06:18:49 +03:00
}
2019-03-13 01:23:10 +03:00
2021-04-21 06:18:49 +03:00
Uniform un ;
un . name = name ;
un . type = UniformType : : Enum ( UniformType : : Sampler
| kUniformSamplerBit
| ( isCompareSampler ? kUniformCompareBit : 0 )
) ;
2019-03-13 01:23:10 +03:00
2021-04-21 06:18:49 +03:00
un . texComponent = textureComponentTypeToId ( SpirvCrossBaseTypeToFormatType ( componentType , imageType . depth ) ) ;
un . texDimension = textureDimensionToId ( SpirvDimToTextureViewDimension ( imageType . dim , imageType . arrayed ) ) ;
un . texFormat = uint16_t ( s_textureFormats [ imageType . format ] ) ;
2019-07-16 11:42:25 +03:00
2021-10-06 19:55:26 +03:00
un . regIndex = uint16_t ( binding_index ) ;
2021-04-21 06:18:49 +03:00
un . regCount = 0 ; // unused
2019-03-13 01:23:10 +03:00
2021-04-21 06:18:49 +03:00
uniforms . push_back ( un ) ;
2019-03-13 01:23:10 +03:00
}
2019-08-13 10:19:06 +03:00
Adds UAV support for D3D12, Vulkan and reworked for OpenGL, D3D11 (#2119)
* Adds UAV support for D3D12, Vulkan and reworked support for OpenGL, D3D11
UAV support is now uniform across compute and draw.
To set a UAV you just use bgfx::setImage() and IMAGE2D in the shader, just like in compute.
Due to these changes shaders will have to be recompiled.
The changes include:
- D3D11 requires patching of the UAV slot number (which is now done by modifying the DXBC instead of using a macro)
- If the DXBC binary includes a debug chunk, that is also patched to match the new slot number
- All the other renderers don't need any kind of patching
- There are some shader annotations to better convert the UAV format used in hlsl to spirv
Possibility of further enhancements:
- bgfx::setViewFrameBuffer() only supports binding to a framebuffer or, using BGFX_INVALID_HANDLE, to bind the default backbuffer. This doesn't allow for the case where there is no need to bind to either one of them, for example when using a fragment shader only to read and write to an UAV.
* Bump shader version, because they need to be recompiled.
2020-10-05 07:51:41 +03:00
// Loop through the storage_images, and extract the uniform names:
2019-08-13 10:19:06 +03:00
for ( auto & resource : resourcesrefl . storage_images )
{
std : : string name = refl . get_name ( resource . id ) ;
2019-08-16 07:37:35 +03:00
2021-04-21 06:18:49 +03:00
uint32_t binding_index = refl . get_decoration ( resource . id , spv : : Decoration : : DecorationBinding ) ;
2020-05-08 18:53:53 +03:00
2021-04-21 06:18:49 +03:00
auto imageType = refl . get_type ( resource . base_type_id ) . image ;
auto componentType = refl . get_type ( imageType . type ) . basetype ;
2020-05-08 18:53:53 +03:00
2021-04-21 06:18:49 +03:00
spirv_cross : : Bitset flags = refl . get_decoration_bitset ( resource . id ) ;
UniformType : : Enum type = flags . get ( spv : : DecorationNonWritable )
? UniformType : : Enum ( kUniformReadOnlyBit | UniformType : : End )
: UniformType : : End ;
2019-08-13 10:19:06 +03:00
2021-04-21 06:18:49 +03:00
Uniform un ;
un . name = name ;
un . type = type ;
2020-06-19 07:20:01 +03:00
2021-04-21 06:18:49 +03:00
un . texComponent = textureComponentTypeToId ( SpirvCrossBaseTypeToFormatType ( componentType , imageType . depth ) ) ;
un . texDimension = textureDimensionToId ( SpirvDimToTextureViewDimension ( imageType . dim , imageType . arrayed ) ) ;
un . texFormat = uint16_t ( s_textureFormats [ imageType . format ] ) ;
2020-05-08 18:53:53 +03:00
2021-10-06 19:55:26 +03:00
un . regIndex = uint16_t ( binding_index ) ;
2021-04-21 06:18:49 +03:00
un . regCount = descriptorTypeToId ( DescriptorType : : StorageImage ) ;
2019-08-13 10:19:06 +03:00
2021-04-21 06:18:49 +03:00
uniforms . push_back ( un ) ;
2019-08-13 10:19:06 +03:00
}
2021-10-26 04:59:32 +03:00
bx : : Error err ;
2019-08-13 10:19:06 +03:00
// Loop through the storage buffer, and extract the uniform names:
for ( auto & resource : resourcesrefl . storage_buffers )
{
std : : string name = refl . get_name ( resource . id ) ;
2021-10-02 06:13:46 +03:00
2021-04-21 06:18:49 +03:00
uint32_t binding_index = refl . get_decoration ( resource . id , spv : : Decoration : : DecorationBinding ) ;
2019-08-16 07:37:35 +03:00
2021-04-21 06:18:49 +03:00
spirv_cross : : Bitset flags = refl . get_buffer_block_flags ( resource . id ) ;
UniformType : : Enum type = flags . get ( spv : : DecorationNonWritable )
? UniformType : : Enum ( kUniformReadOnlyBit | UniformType : : End )
: UniformType : : End ;
2020-05-08 18:53:53 +03:00
2021-04-21 06:18:49 +03:00
Uniform un ;
un . name = name ;
un . type = type ;
un . num = 0 ;
2021-10-06 19:55:26 +03:00
un . regIndex = uint16_t ( binding_index ) ;
2021-04-21 06:18:49 +03:00
un . regCount = descriptorTypeToId ( DescriptorType : : StorageBuffer ) ;
uniforms . push_back ( un ) ;
2019-08-13 10:19:06 +03:00
}
2023-03-06 21:30:06 +03:00
uint16_t size = writeUniformArray ( _shaderWriter , uniforms , _options . shaderType = = ' f ' ) ;
2019-03-13 01:23:10 +03:00
2021-04-21 17:45:03 +03:00
uint32_t shaderSize = ( uint32_t ) spirv . size ( ) * sizeof ( uint32_t ) ;
2023-03-06 21:30:06 +03:00
bx : : write ( _shaderWriter , shaderSize , & err ) ;
bx : : write ( _shaderWriter , spirv . data ( ) , shaderSize , & err ) ;
2021-04-21 17:45:03 +03:00
uint8_t nul = 0 ;
2023-03-06 21:30:06 +03:00
bx : : write ( _shaderWriter , nul , & err ) ;
2019-08-16 07:37:35 +03:00
2019-01-16 00:12:48 +03:00
const uint8_t numAttr = ( uint8_t ) program - > getNumLiveAttributes ( ) ;
2023-03-06 21:30:06 +03:00
bx : : write ( _shaderWriter , numAttr , & err ) ;
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 )
{
2023-03-06 21:30:06 +03:00
bx : : write ( _shaderWriter , bgfx : : attribToId ( attr ) , & err ) ;
2019-01-16 00:12:48 +03:00
}
else
{
2023-03-06 21:30:06 +03:00
bx : : write ( _shaderWriter , uint16_t ( UINT16_MAX ) , & err ) ;
2019-01-16 00:12:48 +03:00
}
}
2019-01-16 06:38:35 +03:00
2023-03-06 21:30:06 +03:00
bx : : write ( _shaderWriter , size , & err ) ;
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
2023-03-06 21:30:06 +03:00
bool compileSPIRVShader ( const Options & _options , uint32_t _version , const std : : string & _code , bx : : WriterI * _shaderWriter , bx : : WriterI * _messageWriter )
2016-12-16 06:03:47 +03:00
{
2023-03-06 21:30:06 +03:00
return spirv : : compile ( _options , _version , _code , _shaderWriter , _messageWriter , true ) ;
2016-10-01 06:03:16 +03:00
}
} // namespace bgfx