2015-06-26 22:58:36 +00:00
//
2016-06-09 14:57:35 +00:00
//Copyright (C) 2014-2016 LunarG, Inc.
2016-02-16 03:58:50 +00:00
//Copyright (C) 2015-2016 Google, Inc.
2015-06-26 22:58:36 +00:00
//
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions
//are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE.
//
// Visit the nodes in the glslang intermediate tree representation to
// translate them to SPIR-V.
//
2015-08-07 04:53:06 +00:00
# include "spirv.hpp"
2015-06-26 22:58:36 +00:00
# include "GlslangToSpv.h"
# include "SpvBuilder.h"
2015-08-07 04:53:06 +00:00
namespace spv {
2016-09-21 10:56:12 +00:00
# include "GLSL.std.450.h"
# include "GLSL.ext.KHR.h"
2016-05-05 04:30:44 +00:00
# ifdef AMD_EXTENSIONS
2016-09-21 10:56:12 +00:00
# include "GLSL.ext.AMD.h"
2016-05-05 04:30:44 +00:00
# endif
2015-08-07 04:53:06 +00:00
}
2015-06-26 22:58:36 +00:00
// Glslang includes
2015-07-08 13:11:59 +00:00
# include "../glslang/MachineIndependent/localintermediate.h"
# include "../glslang/MachineIndependent/SymbolTable.h"
2015-08-07 04:53:06 +00:00
# include "../glslang/Include/Common.h"
2016-05-27 17:55:53 +00:00
# include "../glslang/Include/revision.h"
2015-06-26 22:58:36 +00:00
2016-05-04 19:55:59 +00:00
# include <fstream>
2016-05-27 17:55:53 +00:00
# include <iomanip>
2015-06-26 22:58:36 +00:00
# include <list>
2016-05-04 19:55:59 +00:00
# include <map>
2015-06-26 22:58:36 +00:00
# include <stack>
2016-05-04 19:55:59 +00:00
# include <string>
# include <vector>
2015-06-26 22:58:36 +00:00
namespace {
2015-11-16 04:33:39 +00:00
// For low-order part of the generator's magic number. Bump up
// when there is a change in the style (e.g., if SSA form changes,
// or a different instruction sequence to do something gets used).
const int GeneratorVersion = 1 ;
2015-06-26 22:58:36 +00:00
2016-04-01 14:35:16 +00:00
namespace {
class SpecConstantOpModeGuard {
public :
SpecConstantOpModeGuard ( spv : : Builder * builder )
: builder_ ( builder ) {
previous_flag_ = builder - > isInSpecConstCodeGenMode ( ) ;
}
~ SpecConstantOpModeGuard ( ) {
previous_flag_ ? builder_ - > setToSpecConstCodeGenMode ( )
: builder_ - > setToNormalCodeGenMode ( ) ;
}
2016-04-04 02:20:42 +00:00
void turnOnSpecConstantOpMode ( ) {
builder_ - > setToSpecConstCodeGenMode ( ) ;
}
2016-04-01 14:35:16 +00:00
private :
spv : : Builder * builder_ ;
bool previous_flag_ ;
} ;
}
2015-06-26 22:58:36 +00:00
//
// The main holder of information for translating glslang to SPIR-V.
//
// Derives from the AST walking base class.
//
class TGlslangToSpvTraverser : public glslang : : TIntermTraverser {
public :
2016-05-04 19:55:59 +00:00
TGlslangToSpvTraverser ( const glslang : : TIntermediate * , spv : : SpvBuildLogger * logger ) ;
2016-11-26 20:23:20 +00:00
virtual ~ TGlslangToSpvTraverser ( ) { }
2015-06-26 22:58:36 +00:00
bool visitAggregate ( glslang : : TVisit , glslang : : TIntermAggregate * ) ;
bool visitBinary ( glslang : : TVisit , glslang : : TIntermBinary * ) ;
void visitConstantUnion ( glslang : : TIntermConstantUnion * ) ;
bool visitSelection ( glslang : : TVisit , glslang : : TIntermSelection * ) ;
bool visitSwitch ( glslang : : TVisit , glslang : : TIntermSwitch * ) ;
void visitSymbol ( glslang : : TIntermSymbol * symbol ) ;
bool visitUnary ( glslang : : TVisit , glslang : : TIntermUnary * ) ;
bool visitLoop ( glslang : : TVisit , glslang : : TIntermLoop * ) ;
bool visitBranch ( glslang : : TVisit visit , glslang : : TIntermBranch * ) ;
2016-11-26 20:23:20 +00:00
void finishSpv ( ) ;
2015-12-21 00:37:07 +00:00
void dumpSpv ( std : : vector < unsigned int > & out ) ;
2015-06-26 22:58:36 +00:00
protected :
2016-10-14 09:41:45 +00:00
spv : : Decoration TranslateInterpolationDecoration ( const glslang : : TQualifier & qualifier ) ;
2016-05-21 01:40:44 +00:00
spv : : Decoration TranslateAuxiliaryStorageDecoration ( const glslang : : TQualifier & qualifier ) ;
2016-06-08 13:11:40 +00:00
spv : : BuiltIn TranslateBuiltInDecoration ( glslang : : TBuiltInVariable , bool memberDeclaration ) ;
2016-02-15 18:57:00 +00:00
spv : : ImageFormat TranslateImageFormat ( const glslang : : TType & type ) ;
2015-06-26 22:58:36 +00:00
spv : : Id createSpvVariable ( const glslang : : TIntermSymbol * ) ;
spv : : Id getSampledType ( const glslang : : TSampler & ) ;
2016-07-26 18:50:38 +00:00
spv : : Id getInvertedSwizzleType ( const glslang : : TIntermTyped & ) ;
spv : : Id createInvertedSwizzle ( spv : : Decoration precision , const glslang : : TIntermTyped & , spv : : Id parentResult ) ;
void convertSwizzle ( const glslang : : TIntermAggregate & , std : : vector < unsigned > & swizzle ) ;
2015-06-26 22:58:36 +00:00
spv : : Id convertGlslangToSpvType ( const glslang : : TType & type ) ;
2015-12-24 17:30:13 +00:00
spv : : Id convertGlslangToSpvType ( const glslang : : TType & type , glslang : : TLayoutPacking , const glslang : : TQualifier & ) ;
2016-07-01 03:18:02 +00:00
spv : : Id convertGlslangStructToSpvType ( const glslang : : TType & , const glslang : : TTypeList * glslangStruct ,
glslang : : TLayoutPacking , const glslang : : TQualifier & ) ;
void decorateStructType ( const glslang : : TType & , const glslang : : TTypeList * glslangStruct , glslang : : TLayoutPacking ,
const glslang : : TQualifier & , spv : : Id ) ;
2016-02-16 03:58:50 +00:00
spv : : Id makeArraySizeId ( const glslang : : TArraySizes & , int dim ) ;
2016-02-02 19:37:46 +00:00
spv : : Id accessChainLoad ( const glslang : : TType & type ) ;
2016-02-23 09:51:09 +00:00
void accessChainStore ( const glslang : : TType & type , spv : : Id rvalue ) ;
2016-09-02 17:20:21 +00:00
void multiTypeStore ( const glslang : : TType & , spv : : Id rValue ) ;
2015-12-19 20:57:10 +00:00
glslang : : TLayoutPacking getExplicitLayout ( const glslang : : TType & type ) const ;
2015-12-20 18:29:16 +00:00
int getArrayStride ( const glslang : : TType & arrayType , glslang : : TLayoutPacking , glslang : : TLayoutMatrix ) ;
int getMatrixStride ( const glslang : : TType & matrixType , glslang : : TLayoutPacking , glslang : : TLayoutMatrix ) ;
void updateMemberOffset ( const glslang : : TType & structType , const glslang : : TType & memberType , int & currentOffset , int & nextOffset , glslang : : TLayoutPacking , glslang : : TLayoutMatrix ) ;
2016-06-08 13:11:40 +00:00
void declareUseOfStructMember ( const glslang : : TTypeList & members , int glslangMember ) ;
2015-06-26 22:58:36 +00:00
2016-09-19 22:01:41 +00:00
bool isShaderEntryPoint ( const glslang : : TIntermAggregate * node ) ;
2015-06-26 22:58:36 +00:00
void makeFunctions ( const glslang : : TIntermSequence & ) ;
void makeGlobalInitializers ( const glslang : : TIntermSequence & ) ;
void visitFunctions ( const glslang : : TIntermSequence & ) ;
void handleFunctionEntry ( const glslang : : TIntermAggregate * node ) ;
2015-09-16 03:44:02 +00:00
void translateArguments ( const glslang : : TIntermAggregate & node , std : : vector < spv : : Id > & arguments ) ;
2015-08-19 19:34:18 +00:00
void translateArguments ( glslang : : TIntermUnary & node , std : : vector < spv : : Id > & arguments ) ;
spv : : Id createImageTextureFunctionCall ( glslang : : TIntermOperator * node ) ;
2015-06-26 22:58:36 +00:00
spv : : Id handleUserFunctionCall ( const glslang : : TIntermAggregate * ) ;
2016-05-06 21:25:16 +00:00
spv : : Id createBinaryOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Decoration noContraction , spv : : Id typeId , spv : : Id left , spv : : Id right , glslang : : TBasicType typeProxy , bool reduceComparison = true ) ;
spv : : Id createBinaryMatrixOperation ( spv : : Op , spv : : Decoration precision , spv : : Decoration noContraction , spv : : Id typeId , spv : : Id left , spv : : Id right ) ;
spv : : Id createUnaryOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Decoration noContraction , spv : : Id typeId , spv : : Id operand , glslang : : TBasicType typeProxy ) ;
2016-08-23 07:41:05 +00:00
spv : : Id createUnaryMatrixOperation ( spv : : Op op , spv : : Decoration precision , spv : : Decoration noContraction , spv : : Id typeId , spv : : Id operand , glslang : : TBasicType typeProxy ) ;
2016-04-27 10:48:17 +00:00
spv : : Id createConversion ( glslang : : TOperator op , spv : : Decoration precision , spv : : Decoration noContraction , spv : : Id destTypeId , spv : : Id operand , glslang : : TBasicType typeProxy ) ;
2015-06-26 22:58:36 +00:00
spv : : Id makeSmearedConstant ( spv : : Id constant , int vectorSize ) ;
2015-09-16 03:44:02 +00:00
spv : : Id createAtomicOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id typeId , std : : vector < spv : : Id > & operands , glslang : : TBasicType typeProxy ) ;
2016-09-21 10:56:12 +00:00
spv : : Id createInvocationsOperation ( glslang : : TOperator op , spv : : Id typeId , std : : vector < spv : : Id > & operands , glslang : : TBasicType typeProxy ) ;
2016-09-26 07:53:40 +00:00
spv : : Id CreateInvocationsVectorOperation ( spv : : Op op , spv : : Id typeId , std : : vector < spv : : Id > & operands ) ;
2015-08-07 04:53:06 +00:00
spv : : Id createMiscOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id typeId , std : : vector < spv : : Id > & operands , glslang : : TBasicType typeProxy ) ;
2016-05-05 04:30:44 +00:00
spv : : Id createNoArgOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id typeId ) ;
2015-06-26 22:58:36 +00:00
spv : : Id getSymbolId ( const glslang : : TIntermSymbol * node ) ;
void addDecoration ( spv : : Id id , spv : : Decoration dec ) ;
2015-11-16 04:33:39 +00:00
void addDecoration ( spv : : Id id , spv : : Decoration dec , unsigned value ) ;
2015-06-26 22:58:36 +00:00
void addMemberDecoration ( spv : : Id id , int member , spv : : Decoration dec ) ;
2016-02-01 20:45:25 +00:00
void addMemberDecoration ( spv : : Id id , int member , spv : : Decoration dec , unsigned value ) ;
2016-03-21 13:51:37 +00:00
spv : : Id createSpvConstant ( const glslang : : TIntermTyped & ) ;
spv : : Id createSpvConstantFromConstUnionArray ( const glslang : : TType & type , const glslang : : TConstUnionArray & , int & nextConst , bool specConstant ) ;
2015-10-15 19:29:11 +00:00
bool isTrivialLeaf ( const glslang : : TIntermTyped * node ) ;
bool isTrivial ( const glslang : : TIntermTyped * node ) ;
spv : : Id createShortCircuit ( glslang : : TOperator , glslang : : TIntermTyped & left , glslang : : TIntermTyped & right ) ;
2016-05-05 04:30:44 +00:00
spv : : Id getExtBuiltins ( const char * name ) ;
2015-06-26 22:58:36 +00:00
spv : : Function * shaderEntry ;
2016-10-06 18:59:51 +00:00
spv : : Function * currentFunction ;
2015-11-16 04:33:39 +00:00
spv : : Instruction * entryPoint ;
2015-06-26 22:58:36 +00:00
int sequenceDepth ;
2016-05-04 19:55:59 +00:00
spv : : SpvBuildLogger * logger ;
2016-05-02 22:11:54 +00:00
2015-06-26 22:58:36 +00:00
// There is a 1:1 mapping between a spv builder and a module; this is thread safe
spv : : Builder builder ;
2016-11-26 20:31:47 +00:00
bool inEntryPoint ;
bool entryPointTerminated ;
2015-12-21 00:37:07 +00:00
bool linkageOnly ; // true when visiting the set of objects in the AST present only for establishing interface, whether or not they were statically used
2015-12-21 18:45:34 +00:00
std : : set < spv : : Id > iOSet ; // all input/output variables from either static use or declaration of interface
2015-06-26 22:58:36 +00:00
const glslang : : TIntermediate * glslangIntermediate ;
spv : : Id stdBuiltins ;
2016-05-05 04:30:44 +00:00
std : : unordered_map < const char * , spv : : Id > extBuiltinMap ;
2015-06-26 22:58:36 +00:00
2015-07-19 04:34:27 +00:00
std : : unordered_map < int , spv : : Id > symbolValues ;
2016-09-02 17:20:21 +00:00
std : : unordered_set < int > rValueParameters ; // set of formal function parameters passed as rValues, rather than a pointer
2015-07-19 04:34:27 +00:00
std : : unordered_map < std : : string , spv : : Function * > functionMap ;
2015-12-20 18:29:16 +00:00
std : : unordered_map < const glslang : : TTypeList * , spv : : Id > structMap [ glslang : : ElpCount ] [ glslang : : ElmCount ] ;
2015-07-19 04:34:27 +00:00
std : : unordered_map < const glslang : : TTypeList * , std : : vector < int > > memberRemapper ; // for mapping glslang block indices to spv indices (e.g., due to hidden members)
2015-06-26 22:58:36 +00:00
std : : stack < bool > breakForLoop ; // false means break for switch
} ;
//
// Helper functions for translating glslang representations to SPIR-V enumerants.
//
// Translate glslang profile to SPIR-V source language.
2016-03-13 01:34:36 +00:00
spv : : SourceLanguage TranslateSourceLanguage ( glslang : : EShSource source , EProfile profile )
2015-06-26 22:58:36 +00:00
{
2016-03-13 01:34:36 +00:00
switch ( source ) {
case glslang : : EShSourceGlsl :
switch ( profile ) {
case ENoProfile :
case ECoreProfile :
case ECompatibilityProfile :
return spv : : SourceLanguageGLSL ;
case EEsProfile :
return spv : : SourceLanguageESSL ;
default :
return spv : : SourceLanguageUnknown ;
}
case glslang : : EShSourceHlsl :
2016-08-15 20:05:45 +00:00
//Use SourceLanguageUnknown instead of SourceLanguageHLSL for now, until Vulkan knows what HLSL is
return spv : : SourceLanguageUnknown ;
2015-06-26 22:58:36 +00:00
default :
return spv : : SourceLanguageUnknown ;
}
}
// Translate glslang language (stage) to SPIR-V execution model.
spv : : ExecutionModel TranslateExecutionModel ( EShLanguage stage )
{
switch ( stage ) {
case EShLangVertex : return spv : : ExecutionModelVertex ;
case EShLangTessControl : return spv : : ExecutionModelTessellationControl ;
case EShLangTessEvaluation : return spv : : ExecutionModelTessellationEvaluation ;
case EShLangGeometry : return spv : : ExecutionModelGeometry ;
case EShLangFragment : return spv : : ExecutionModelFragment ;
case EShLangCompute : return spv : : ExecutionModelGLCompute ;
default :
2015-11-16 04:33:39 +00:00
assert ( 0 ) ;
2015-06-26 22:58:36 +00:00
return spv : : ExecutionModelFragment ;
}
}
// Translate glslang type to SPIR-V storage class.
spv : : StorageClass TranslateStorageClass ( const glslang : : TType & type )
{
if ( type . getQualifier ( ) . isPipeInput ( ) )
return spv : : StorageClassInput ;
else if ( type . getQualifier ( ) . isPipeOutput ( ) )
return spv : : StorageClassOutput ;
2016-06-08 20:52:36 +00:00
else if ( type . getBasicType ( ) = = glslang : : EbtSampler )
return spv : : StorageClassUniformConstant ;
else if ( type . getBasicType ( ) = = glslang : : EbtAtomicUint )
return spv : : StorageClassAtomicCounter ;
2015-06-26 22:58:36 +00:00
else if ( type . getQualifier ( ) . isUniformOrBuffer ( ) ) {
2016-02-16 03:58:50 +00:00
if ( type . getQualifier ( ) . layoutPushConstant )
return spv : : StorageClassPushConstant ;
2015-06-26 22:58:36 +00:00
if ( type . getBasicType ( ) = = glslang : : EbtBlock )
return spv : : StorageClassUniform ;
else
return spv : : StorageClassUniformConstant ;
2016-06-17 21:50:47 +00:00
// TODO: how are we distinguishing between default and non-default non-writable uniforms? Do default uniforms even exist?
2015-06-26 22:58:36 +00:00
} else {
switch ( type . getQualifier ( ) . storage ) {
2015-11-16 04:33:39 +00:00
case glslang : : EvqShared : return spv : : StorageClassWorkgroup ; break ;
case glslang : : EvqGlobal : return spv : : StorageClassPrivate ;
2015-06-26 22:58:36 +00:00
case glslang : : EvqConstReadOnly : return spv : : StorageClassFunction ;
case glslang : : EvqTemporary : return spv : : StorageClassFunction ;
2016-05-06 21:25:16 +00:00
default :
2015-11-16 04:33:39 +00:00
assert ( 0 ) ;
2015-06-26 22:58:36 +00:00
return spv : : StorageClassFunction ;
}
}
}
// Translate glslang sampler type to SPIR-V dimensionality.
spv : : Dim TranslateDimensionality ( const glslang : : TSampler & sampler )
{
switch ( sampler . dim ) {
2015-11-16 04:33:39 +00:00
case glslang : : Esd1D : return spv : : Dim1D ;
case glslang : : Esd2D : return spv : : Dim2D ;
case glslang : : Esd3D : return spv : : Dim3D ;
case glslang : : EsdCube : return spv : : DimCube ;
case glslang : : EsdRect : return spv : : DimRect ;
case glslang : : EsdBuffer : return spv : : DimBuffer ;
2016-02-16 03:58:50 +00:00
case glslang : : EsdSubpass : return spv : : DimSubpassData ;
2015-06-26 22:58:36 +00:00
default :
2015-11-16 04:33:39 +00:00
assert ( 0 ) ;
2015-06-26 22:58:36 +00:00
return spv : : Dim2D ;
}
}
2016-08-02 01:44:00 +00:00
// Translate glslang precision to SPIR-V precision decorations.
spv : : Decoration TranslatePrecisionDecoration ( glslang : : TPrecisionQualifier glslangPrecision )
2015-06-26 22:58:36 +00:00
{
2016-08-02 01:44:00 +00:00
switch ( glslangPrecision ) {
2015-12-15 01:21:19 +00:00
case glslang : : EpqLow : return spv : : DecorationRelaxedPrecision ;
2015-08-07 04:53:06 +00:00
case glslang : : EpqMedium : return spv : : DecorationRelaxedPrecision ;
2015-06-26 22:58:36 +00:00
default :
return spv : : NoPrecision ;
}
}
2016-08-02 01:44:00 +00:00
// Translate glslang type to SPIR-V precision decorations.
spv : : Decoration TranslatePrecisionDecoration ( const glslang : : TType & type )
{
return TranslatePrecisionDecoration ( type . getQualifier ( ) . precision ) ;
}
2015-06-26 22:58:36 +00:00
// Translate glslang type to SPIR-V block decorations.
spv : : Decoration TranslateBlockDecoration ( const glslang : : TType & type )
{
if ( type . getBasicType ( ) = = glslang : : EbtBlock ) {
switch ( type . getQualifier ( ) . storage ) {
case glslang : : EvqUniform : return spv : : DecorationBlock ;
case glslang : : EvqBuffer : return spv : : DecorationBufferBlock ;
case glslang : : EvqVaryingIn : return spv : : DecorationBlock ;
case glslang : : EvqVaryingOut : return spv : : DecorationBlock ;
default :
2015-11-16 04:33:39 +00:00
assert ( 0 ) ;
2015-06-26 22:58:36 +00:00
break ;
}
}
2016-07-15 17:53:56 +00:00
return spv : : DecorationMax ;
2015-06-26 22:58:36 +00:00
}
2016-02-21 12:59:01 +00:00
// Translate glslang type to SPIR-V memory decorations.
void TranslateMemoryDecoration ( const glslang : : TQualifier & qualifier , std : : vector < spv : : Decoration > & memory )
{
if ( qualifier . coherent )
memory . push_back ( spv : : DecorationCoherent ) ;
if ( qualifier . volatil )
memory . push_back ( spv : : DecorationVolatile ) ;
if ( qualifier . restrict )
memory . push_back ( spv : : DecorationRestrict ) ;
if ( qualifier . readonly )
memory . push_back ( spv : : DecorationNonWritable ) ;
if ( qualifier . writeonly )
memory . push_back ( spv : : DecorationNonReadable ) ;
}
2015-06-26 22:58:36 +00:00
// Translate glslang type to SPIR-V layout decorations.
2015-12-20 18:29:16 +00:00
spv : : Decoration TranslateLayoutDecoration ( const glslang : : TType & type , glslang : : TLayoutMatrix matrixLayout )
2015-06-26 22:58:36 +00:00
{
if ( type . isMatrix ( ) ) {
2015-12-20 18:29:16 +00:00
switch ( matrixLayout ) {
2015-06-26 22:58:36 +00:00
case glslang : : ElmRowMajor :
return spv : : DecorationRowMajor ;
2015-12-20 18:29:16 +00:00
case glslang : : ElmColumnMajor :
2015-06-26 22:58:36 +00:00
return spv : : DecorationColMajor ;
2015-12-20 18:29:16 +00:00
default :
// opaque layouts don't need a majorness
2016-07-15 17:53:56 +00:00
return spv : : DecorationMax ;
2015-06-26 22:58:36 +00:00
}
} else {
switch ( type . getBasicType ( ) ) {
default :
2016-07-15 17:53:56 +00:00
return spv : : DecorationMax ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EbtBlock :
switch ( type . getQualifier ( ) . storage ) {
case glslang : : EvqUniform :
case glslang : : EvqBuffer :
switch ( type . getQualifier ( ) . layoutPacking ) {
case glslang : : ElpShared : return spv : : DecorationGLSLShared ;
case glslang : : ElpPacked : return spv : : DecorationGLSLPacked ;
default :
2016-07-15 17:53:56 +00:00
return spv : : DecorationMax ;
2015-06-26 22:58:36 +00:00
}
case glslang : : EvqVaryingIn :
case glslang : : EvqVaryingOut :
2015-11-16 04:33:39 +00:00
assert ( type . getQualifier ( ) . layoutPacking = = glslang : : ElpNone ) ;
2016-07-15 17:53:56 +00:00
return spv : : DecorationMax ;
2015-06-26 22:58:36 +00:00
default :
2015-11-16 04:33:39 +00:00
assert ( 0 ) ;
2016-07-15 17:53:56 +00:00
return spv : : DecorationMax ;
2015-06-26 22:58:36 +00:00
}
}
}
}
// Translate glslang type to SPIR-V interpolation decorations.
2016-07-15 17:53:56 +00:00
// Returns spv::DecorationMax when no decoration
2015-11-16 04:33:39 +00:00
// should be applied.
2016-10-14 09:41:45 +00:00
spv : : Decoration TGlslangToSpvTraverser : : TranslateInterpolationDecoration ( const glslang : : TQualifier & qualifier )
2015-06-26 22:58:36 +00:00
{
2016-05-21 01:40:44 +00:00
if ( qualifier . smooth )
2015-11-16 04:33:39 +00:00
// Smooth decoration doesn't exist in SPIR-V 1.0
2016-07-15 17:53:56 +00:00
return spv : : DecorationMax ;
2016-05-21 01:40:44 +00:00
else if ( qualifier . nopersp )
2015-11-16 04:33:39 +00:00
return spv : : DecorationNoPerspective ;
2015-12-24 17:30:13 +00:00
else if ( qualifier . flat )
2015-06-26 22:58:36 +00:00
return spv : : DecorationFlat ;
2016-05-05 04:30:44 +00:00
# ifdef AMD_EXTENSIONS
2016-10-14 09:41:45 +00:00
else if ( qualifier . explicitInterp ) {
builder . addExtension ( spv : : E_SPV_AMD_shader_explicit_vertex_parameter ) ;
2016-05-05 04:30:44 +00:00
return spv : : DecorationExplicitInterpAMD ;
2016-10-14 09:41:45 +00:00
}
2016-05-05 04:30:44 +00:00
# endif
2016-05-21 01:40:44 +00:00
else
2016-07-15 17:53:56 +00:00
return spv : : DecorationMax ;
2016-05-21 01:40:44 +00:00
}
// Translate glslang type to SPIR-V auxiliary storage decorations.
2016-07-15 17:53:56 +00:00
// Returns spv::DecorationMax when no decoration
2016-05-21 01:40:44 +00:00
// should be applied.
spv : : Decoration TGlslangToSpvTraverser : : TranslateAuxiliaryStorageDecoration ( const glslang : : TQualifier & qualifier )
{
if ( qualifier . patch )
return spv : : DecorationPatch ;
2015-12-24 17:30:13 +00:00
else if ( qualifier . centroid )
2015-06-26 22:58:36 +00:00
return spv : : DecorationCentroid ;
2016-02-15 18:09:46 +00:00
else if ( qualifier . sample ) {
builder . addCapability ( spv : : CapabilitySampleRateShading ) ;
2015-06-26 22:58:36 +00:00
return spv : : DecorationSample ;
2016-02-15 18:09:46 +00:00
} else
2016-07-15 17:53:56 +00:00
return spv : : DecorationMax ;
2015-06-26 22:58:36 +00:00
}
2016-02-01 20:45:25 +00:00
// If glslang type is invariant, return SPIR-V invariant decoration.
2015-12-24 17:30:13 +00:00
spv : : Decoration TranslateInvariantDecoration ( const glslang : : TQualifier & qualifier )
2015-06-26 22:58:36 +00:00
{
2015-12-24 17:30:13 +00:00
if ( qualifier . invariant )
2015-06-26 22:58:36 +00:00
return spv : : DecorationInvariant ;
else
2016-07-15 17:53:56 +00:00
return spv : : DecorationMax ;
2015-06-26 22:58:36 +00:00
}
Precise and noContraction propagation
Reimplement the whole workflow to make that: precise'ness of struct
members won't spread to other non-precise members of the same struct
instance.
Approach:
1. Build the map from symbols to their defining nodes. And for each
object node (StructIndex, DirectIndex, Symbol nodes, etc), generates an
accesschain path. Different AST nodes that indicating a same object
should have the same accesschain path.
2. Along the building phase in step 1, collect the initial set of
'precise' (AST qualifier: 'noContraction') objects' accesschain paths.
3. Start with the initial set of 'precise' accesschain paths, use it as
a worklist, do as the following steps until the worklist is empty:
1) Pop an accesschain path from worklist.
2) Get the symbol part from the accesschain path.
3) Find the defining nodes of that symbol.
4) For each defining node, check whether it is defining a 'precise'
object, or its assignee has nested 'precise' object. Get the
incremental path from assignee to its nested 'precise' object (if
any).
5) Traverse the right side of the defining node, obtain the
accesschain paths of the corresponding involved 'precise' objects.
Update the worklist with those new objects' accesschain paths.
Label involved operations with 'noContraction'.
In each step, whenever we find the parent object of an nested object is
'precise' (has 'noContraction' qualifier), we let the nested object
inherit the 'precise'ness from its parent object.
2016-05-04 21:34:38 +00:00
// If glslang type is noContraction, return SPIR-V NoContraction decoration.
spv : : Decoration TranslateNoContractionDecoration ( const glslang : : TQualifier & qualifier )
{
if ( qualifier . noContraction )
return spv : : DecorationNoContraction ;
else
2016-07-15 17:53:56 +00:00
return spv : : DecorationMax ;
Precise and noContraction propagation
Reimplement the whole workflow to make that: precise'ness of struct
members won't spread to other non-precise members of the same struct
instance.
Approach:
1. Build the map from symbols to their defining nodes. And for each
object node (StructIndex, DirectIndex, Symbol nodes, etc), generates an
accesschain path. Different AST nodes that indicating a same object
should have the same accesschain path.
2. Along the building phase in step 1, collect the initial set of
'precise' (AST qualifier: 'noContraction') objects' accesschain paths.
3. Start with the initial set of 'precise' accesschain paths, use it as
a worklist, do as the following steps until the worklist is empty:
1) Pop an accesschain path from worklist.
2) Get the symbol part from the accesschain path.
3) Find the defining nodes of that symbol.
4) For each defining node, check whether it is defining a 'precise'
object, or its assignee has nested 'precise' object. Get the
incremental path from assignee to its nested 'precise' object (if
any).
5) Traverse the right side of the defining node, obtain the
accesschain paths of the corresponding involved 'precise' objects.
Update the worklist with those new objects' accesschain paths.
Label involved operations with 'noContraction'.
In each step, whenever we find the parent object of an nested object is
'precise' (has 'noContraction' qualifier), we let the nested object
inherit the 'precise'ness from its parent object.
2016-05-04 21:34:38 +00:00
}
2016-06-08 13:11:40 +00:00
// Translate a glslang built-in variable to a SPIR-V built in decoration. Also generate
// associated capabilities when required. For some built-in variables, a capability
// is generated only when using the variable in an executable instruction, but not when
// just declaring a struct member variable with it. This is true for PointSize,
// ClipDistance, and CullDistance.
spv : : BuiltIn TGlslangToSpvTraverser : : TranslateBuiltInDecoration ( glslang : : TBuiltInVariable builtIn , bool memberDeclaration )
2015-06-26 22:58:36 +00:00
{
switch ( builtIn ) {
2016-02-01 20:45:25 +00:00
case glslang : : EbvPointSize :
2016-07-08 20:05:15 +00:00
// Defer adding the capability until the built-in is actually used.
if ( ! memberDeclaration ) {
switch ( glslangIntermediate - > getStage ( ) ) {
case EShLangGeometry :
builder . addCapability ( spv : : CapabilityGeometryPointSize ) ;
break ;
case EShLangTessControl :
case EShLangTessEvaluation :
builder . addCapability ( spv : : CapabilityTessellationPointSize ) ;
break ;
default :
break ;
}
2016-02-01 20:45:25 +00:00
}
return spv : : BuiltInPointSize ;
2016-05-17 01:22:05 +00:00
// These *Distance capabilities logically belong here, but if the member is declared and
// then never used, consumers of SPIR-V prefer the capability not be declared.
// They are now generated when used, rather than here when declared.
// Potentially, the specification should be more clear what the minimum
// use needed is to trigger the capability.
//
2016-02-01 20:45:25 +00:00
case glslang : : EbvClipDistance :
2016-06-08 13:11:40 +00:00
if ( ! memberDeclaration )
2016-07-08 20:05:15 +00:00
builder . addCapability ( spv : : CapabilityClipDistance ) ;
2016-02-01 20:45:25 +00:00
return spv : : BuiltInClipDistance ;
case glslang : : EbvCullDistance :
2016-06-08 13:11:40 +00:00
if ( ! memberDeclaration )
2016-07-08 20:05:15 +00:00
builder . addCapability ( spv : : CapabilityCullDistance ) ;
2016-02-01 20:45:25 +00:00
return spv : : BuiltInCullDistance ;
case glslang : : EbvViewportIndex :
2016-03-08 02:32:15 +00:00
builder . addCapability ( spv : : CapabilityMultiViewport ) ;
2016-02-01 20:45:25 +00:00
return spv : : BuiltInViewportIndex ;
2016-02-15 18:09:46 +00:00
case glslang : : EbvSampleId :
builder . addCapability ( spv : : CapabilitySampleRateShading ) ;
return spv : : BuiltInSampleId ;
case glslang : : EbvSamplePosition :
builder . addCapability ( spv : : CapabilitySampleRateShading ) ;
return spv : : BuiltInSamplePosition ;
case glslang : : EbvSampleMask :
builder . addCapability ( spv : : CapabilitySampleRateShading ) ;
return spv : : BuiltInSampleMask ;
2016-07-08 20:05:15 +00:00
case glslang : : EbvLayer :
builder . addCapability ( spv : : CapabilityGeometry ) ;
return spv : : BuiltInLayer ;
2015-06-26 22:58:36 +00:00
case glslang : : EbvPosition : return spv : : BuiltInPosition ;
case glslang : : EbvVertexId : return spv : : BuiltInVertexId ;
case glslang : : EbvInstanceId : return spv : : BuiltInInstanceId ;
2016-02-16 03:58:50 +00:00
case glslang : : EbvVertexIndex : return spv : : BuiltInVertexIndex ;
case glslang : : EbvInstanceIndex : return spv : : BuiltInInstanceIndex ;
2016-07-22 10:15:31 +00:00
2015-10-14 20:10:30 +00:00
case glslang : : EbvBaseVertex :
2016-07-22 10:15:31 +00:00
builder . addExtension ( spv : : E_SPV_KHR_shader_draw_parameters ) ;
builder . addCapability ( spv : : CapabilityDrawParameters ) ;
return spv : : BuiltInBaseVertex ;
2015-10-14 20:10:30 +00:00
case glslang : : EbvBaseInstance :
2016-07-22 10:15:31 +00:00
builder . addExtension ( spv : : E_SPV_KHR_shader_draw_parameters ) ;
builder . addCapability ( spv : : CapabilityDrawParameters ) ;
return spv : : BuiltInBaseInstance ;
2016-09-26 14:49:09 +00:00
2015-10-14 20:10:30 +00:00
case glslang : : EbvDrawId :
2016-07-22 10:15:31 +00:00
builder . addExtension ( spv : : E_SPV_KHR_shader_draw_parameters ) ;
builder . addCapability ( spv : : CapabilityDrawParameters ) ;
return spv : : BuiltInDrawIndex ;
2016-09-26 14:49:09 +00:00
case glslang : : EbvPrimitiveId :
if ( glslangIntermediate - > getStage ( ) = = EShLangFragment )
builder . addCapability ( spv : : CapabilityGeometry ) ;
return spv : : BuiltInPrimitiveId ;
2015-06-26 22:58:36 +00:00
case glslang : : EbvInvocationId : return spv : : BuiltInInvocationId ;
case glslang : : EbvTessLevelInner : return spv : : BuiltInTessLevelInner ;
case glslang : : EbvTessLevelOuter : return spv : : BuiltInTessLevelOuter ;
case glslang : : EbvTessCoord : return spv : : BuiltInTessCoord ;
case glslang : : EbvPatchVertices : return spv : : BuiltInPatchVertices ;
case glslang : : EbvFragCoord : return spv : : BuiltInFragCoord ;
case glslang : : EbvPointCoord : return spv : : BuiltInPointCoord ;
case glslang : : EbvFace : return spv : : BuiltInFrontFacing ;
case glslang : : EbvFragDepth : return spv : : BuiltInFragDepth ;
case glslang : : EbvHelperInvocation : return spv : : BuiltInHelperInvocation ;
case glslang : : EbvNumWorkGroups : return spv : : BuiltInNumWorkgroups ;
case glslang : : EbvWorkGroupSize : return spv : : BuiltInWorkgroupSize ;
case glslang : : EbvWorkGroupId : return spv : : BuiltInWorkgroupId ;
case glslang : : EbvLocalInvocationId : return spv : : BuiltInLocalInvocationId ;
case glslang : : EbvLocalInvocationIndex : return spv : : BuiltInLocalInvocationIndex ;
case glslang : : EbvGlobalInvocationId : return spv : : BuiltInGlobalInvocationId ;
2016-09-21 10:56:12 +00:00
2016-04-14 08:53:07 +00:00
case glslang : : EbvSubGroupSize :
2016-09-23 14:13:43 +00:00
builder . addExtension ( spv : : E_SPV_KHR_shader_ballot ) ;
2016-09-21 10:56:12 +00:00
builder . addCapability ( spv : : CapabilitySubgroupBallotKHR ) ;
return spv : : BuiltInSubgroupSize ;
2016-04-14 08:53:07 +00:00
case glslang : : EbvSubGroupInvocation :
2016-09-23 14:13:43 +00:00
builder . addExtension ( spv : : E_SPV_KHR_shader_ballot ) ;
2016-09-21 10:56:12 +00:00
builder . addCapability ( spv : : CapabilitySubgroupBallotKHR ) ;
return spv : : BuiltInSubgroupLocalInvocationId ;
2016-04-14 08:53:07 +00:00
case glslang : : EbvSubGroupEqMask :
2016-09-21 10:56:12 +00:00
builder . addExtension ( spv : : E_SPV_KHR_shader_ballot ) ;
builder . addCapability ( spv : : CapabilitySubgroupBallotKHR ) ;
return spv : : BuiltInSubgroupEqMaskKHR ;
2016-04-14 08:53:07 +00:00
case glslang : : EbvSubGroupGeMask :
2016-09-21 10:56:12 +00:00
builder . addExtension ( spv : : E_SPV_KHR_shader_ballot ) ;
builder . addCapability ( spv : : CapabilitySubgroupBallotKHR ) ;
return spv : : BuiltInSubgroupGeMaskKHR ;
2016-04-14 08:53:07 +00:00
case glslang : : EbvSubGroupGtMask :
2016-09-21 10:56:12 +00:00
builder . addExtension ( spv : : E_SPV_KHR_shader_ballot ) ;
builder . addCapability ( spv : : CapabilitySubgroupBallotKHR ) ;
return spv : : BuiltInSubgroupGtMaskKHR ;
2016-04-14 08:53:07 +00:00
case glslang : : EbvSubGroupLeMask :
2016-09-21 10:56:12 +00:00
builder . addExtension ( spv : : E_SPV_KHR_shader_ballot ) ;
builder . addCapability ( spv : : CapabilitySubgroupBallotKHR ) ;
return spv : : BuiltInSubgroupLeMaskKHR ;
2016-04-14 08:53:07 +00:00
case glslang : : EbvSubGroupLtMask :
2016-09-21 10:56:12 +00:00
builder . addExtension ( spv : : E_SPV_KHR_shader_ballot ) ;
builder . addCapability ( spv : : CapabilitySubgroupBallotKHR ) ;
return spv : : BuiltInSubgroupLtMaskKHR ;
2016-05-05 04:30:44 +00:00
# ifdef AMD_EXTENSIONS
2016-10-14 09:41:45 +00:00
case glslang : : EbvBaryCoordNoPersp :
builder . addExtension ( spv : : E_SPV_AMD_shader_explicit_vertex_parameter ) ;
return spv : : BuiltInBaryCoordNoPerspAMD ;
case glslang : : EbvBaryCoordNoPerspCentroid :
builder . addExtension ( spv : : E_SPV_AMD_shader_explicit_vertex_parameter ) ;
return spv : : BuiltInBaryCoordNoPerspCentroidAMD ;
case glslang : : EbvBaryCoordNoPerspSample :
builder . addExtension ( spv : : E_SPV_AMD_shader_explicit_vertex_parameter ) ;
return spv : : BuiltInBaryCoordNoPerspSampleAMD ;
case glslang : : EbvBaryCoordSmooth :
builder . addExtension ( spv : : E_SPV_AMD_shader_explicit_vertex_parameter ) ;
return spv : : BuiltInBaryCoordSmoothAMD ;
case glslang : : EbvBaryCoordSmoothCentroid :
builder . addExtension ( spv : : E_SPV_AMD_shader_explicit_vertex_parameter ) ;
return spv : : BuiltInBaryCoordSmoothCentroidAMD ;
case glslang : : EbvBaryCoordSmoothSample :
builder . addExtension ( spv : : E_SPV_AMD_shader_explicit_vertex_parameter ) ;
return spv : : BuiltInBaryCoordSmoothSampleAMD ;
case glslang : : EbvBaryCoordPullModel :
builder . addExtension ( spv : : E_SPV_AMD_shader_explicit_vertex_parameter ) ;
return spv : : BuiltInBaryCoordPullModelAMD ;
2016-05-05 04:30:44 +00:00
# endif
2016-07-15 17:53:56 +00:00
default : return spv : : BuiltInMax ;
2015-06-26 22:58:36 +00:00
}
}
2015-09-09 08:42:49 +00:00
// Translate glslang image layout format to SPIR-V image format.
2016-02-15 18:57:00 +00:00
spv : : ImageFormat TGlslangToSpvTraverser : : TranslateImageFormat ( const glslang : : TType & type )
2015-09-09 08:42:49 +00:00
{
assert ( type . getBasicType ( ) = = glslang : : EbtSampler ) ;
2016-02-15 18:57:00 +00:00
// Check for capabilities
switch ( type . getQualifier ( ) . layoutFormat ) {
case glslang : : ElfRg32f :
case glslang : : ElfRg16f :
case glslang : : ElfR11fG11fB10f :
case glslang : : ElfR16f :
case glslang : : ElfRgba16 :
case glslang : : ElfRgb10A2 :
case glslang : : ElfRg16 :
case glslang : : ElfRg8 :
case glslang : : ElfR16 :
case glslang : : ElfR8 :
case glslang : : ElfRgba16Snorm :
case glslang : : ElfRg16Snorm :
case glslang : : ElfRg8Snorm :
case glslang : : ElfR16Snorm :
case glslang : : ElfR8Snorm :
case glslang : : ElfRg32i :
case glslang : : ElfRg16i :
case glslang : : ElfRg8i :
case glslang : : ElfR16i :
case glslang : : ElfR8i :
case glslang : : ElfRgb10a2ui :
case glslang : : ElfRg32ui :
case glslang : : ElfRg16ui :
case glslang : : ElfRg8ui :
case glslang : : ElfR16ui :
case glslang : : ElfR8ui :
builder . addCapability ( spv : : CapabilityStorageImageExtendedFormats ) ;
break ;
default :
break ;
}
// do the translation
2015-09-09 08:42:49 +00:00
switch ( type . getQualifier ( ) . layoutFormat ) {
case glslang : : ElfNone : return spv : : ImageFormatUnknown ;
case glslang : : ElfRgba32f : return spv : : ImageFormatRgba32f ;
case glslang : : ElfRgba16f : return spv : : ImageFormatRgba16f ;
case glslang : : ElfR32f : return spv : : ImageFormatR32f ;
case glslang : : ElfRgba8 : return spv : : ImageFormatRgba8 ;
case glslang : : ElfRgba8Snorm : return spv : : ImageFormatRgba8Snorm ;
case glslang : : ElfRg32f : return spv : : ImageFormatRg32f ;
case glslang : : ElfRg16f : return spv : : ImageFormatRg16f ;
case glslang : : ElfR11fG11fB10f : return spv : : ImageFormatR11fG11fB10f ;
case glslang : : ElfR16f : return spv : : ImageFormatR16f ;
case glslang : : ElfRgba16 : return spv : : ImageFormatRgba16 ;
case glslang : : ElfRgb10A2 : return spv : : ImageFormatRgb10A2 ;
case glslang : : ElfRg16 : return spv : : ImageFormatRg16 ;
case glslang : : ElfRg8 : return spv : : ImageFormatRg8 ;
case glslang : : ElfR16 : return spv : : ImageFormatR16 ;
case glslang : : ElfR8 : return spv : : ImageFormatR8 ;
case glslang : : ElfRgba16Snorm : return spv : : ImageFormatRgba16Snorm ;
case glslang : : ElfRg16Snorm : return spv : : ImageFormatRg16Snorm ;
case glslang : : ElfRg8Snorm : return spv : : ImageFormatRg8Snorm ;
case glslang : : ElfR16Snorm : return spv : : ImageFormatR16Snorm ;
case glslang : : ElfR8Snorm : return spv : : ImageFormatR8Snorm ;
case glslang : : ElfRgba32i : return spv : : ImageFormatRgba32i ;
case glslang : : ElfRgba16i : return spv : : ImageFormatRgba16i ;
case glslang : : ElfRgba8i : return spv : : ImageFormatRgba8i ;
case glslang : : ElfR32i : return spv : : ImageFormatR32i ;
case glslang : : ElfRg32i : return spv : : ImageFormatRg32i ;
case glslang : : ElfRg16i : return spv : : ImageFormatRg16i ;
case glslang : : ElfRg8i : return spv : : ImageFormatRg8i ;
case glslang : : ElfR16i : return spv : : ImageFormatR16i ;
case glslang : : ElfR8i : return spv : : ImageFormatR8i ;
case glslang : : ElfRgba32ui : return spv : : ImageFormatRgba32ui ;
case glslang : : ElfRgba16ui : return spv : : ImageFormatRgba16ui ;
case glslang : : ElfRgba8ui : return spv : : ImageFormatRgba8ui ;
case glslang : : ElfR32ui : return spv : : ImageFormatR32ui ;
case glslang : : ElfRg32ui : return spv : : ImageFormatRg32ui ;
case glslang : : ElfRg16ui : return spv : : ImageFormatRg16ui ;
case glslang : : ElfRgb10a2ui : return spv : : ImageFormatRgb10a2ui ;
case glslang : : ElfRg8ui : return spv : : ImageFormatRg8ui ;
case glslang : : ElfR16ui : return spv : : ImageFormatR16ui ;
case glslang : : ElfR8ui : return spv : : ImageFormatR8ui ;
2016-07-15 17:53:56 +00:00
default : return spv : : ImageFormatMax ;
2015-09-09 08:42:49 +00:00
}
}
2016-05-06 21:25:16 +00:00
// Return whether or not the given type is something that should be tied to a
2016-02-16 03:58:50 +00:00
// descriptor set.
bool IsDescriptorResource ( const glslang : : TType & type )
{
2016-03-09 04:36:22 +00:00
// uniform and buffer blocks are included, unless it is a push_constant
2016-02-16 03:58:50 +00:00
if ( type . getBasicType ( ) = = glslang : : EbtBlock )
2016-03-09 04:36:22 +00:00
return type . getQualifier ( ) . isUniformOrBuffer ( ) & & ! type . getQualifier ( ) . layoutPushConstant ;
2016-02-16 03:58:50 +00:00
// non block...
// basically samplerXXX/subpass/sampler/texture are all included
// if they are the global-scope-class, not the function parameter
// (or local, if they ever exist) class.
if ( type . getBasicType ( ) = = glslang : : EbtSampler )
return type . getQualifier ( ) . isUniformOrBuffer ( ) ;
// None of the above.
return false ;
}
2015-12-24 17:30:13 +00:00
void InheritQualifiers ( glslang : : TQualifier & child , const glslang : : TQualifier & parent )
{
if ( child . layoutMatrix = = glslang : : ElmNone )
child . layoutMatrix = parent . layoutMatrix ;
if ( parent . invariant )
child . invariant = true ;
if ( parent . nopersp )
child . nopersp = true ;
2016-05-05 04:30:44 +00:00
# ifdef AMD_EXTENSIONS
if ( parent . explicitInterp )
child . explicitInterp = true ;
# endif
2015-12-24 17:30:13 +00:00
if ( parent . flat )
child . flat = true ;
if ( parent . centroid )
child . centroid = true ;
if ( parent . patch )
child . patch = true ;
if ( parent . sample )
child . sample = true ;
2016-02-21 12:59:01 +00:00
if ( parent . coherent )
child . coherent = true ;
if ( parent . volatil )
child . volatil = true ;
if ( parent . restrict )
child . restrict = true ;
if ( parent . readonly )
child . readonly = true ;
if ( parent . writeonly )
child . writeonly = true ;
2015-12-24 17:30:13 +00:00
}
2016-09-01 23:05:23 +00:00
bool HasNonLayoutQualifiers ( const glslang : : TType & type , const glslang : : TQualifier & qualifier )
2015-12-24 17:30:13 +00:00
{
2016-01-22 01:56:57 +00:00
// This should list qualifiers that simultaneous satisfy:
2016-09-01 23:05:23 +00:00
// - struct members might inherit from a struct declaration
// (note that non-block structs don't explicitly inherit,
// only implicitly, meaning no decoration involved)
// - affect decorations on the struct members
// (note smooth does not, and expecting something like volatile
// to effect the whole object)
2015-12-24 17:30:13 +00:00
// - are not part of the offset/st430/etc or row/column-major layout
2016-09-01 23:05:23 +00:00
return qualifier . invariant | | ( qualifier . hasLocation ( ) & & type . getBasicType ( ) = = glslang : : EbtBlock ) ;
2015-12-24 17:30:13 +00:00
}
2015-06-26 22:58:36 +00:00
//
// Implement the TGlslangToSpvTraverser class.
//
2016-05-04 19:55:59 +00:00
TGlslangToSpvTraverser : : TGlslangToSpvTraverser ( const glslang : : TIntermediate * glslangIntermediate , spv : : SpvBuildLogger * buildLogger )
2016-10-06 18:59:51 +00:00
: TIntermTraverser ( true , false , true ) , shaderEntry ( nullptr ) , currentFunction ( nullptr ) ,
sequenceDepth ( 0 ) , logger ( buildLogger ) ,
2016-05-04 19:55:59 +00:00
builder ( ( glslang : : GetKhronosToolId ( ) < < 16 ) | GeneratorVersion , logger ) ,
2016-11-26 20:31:47 +00:00
inEntryPoint ( false ) , entryPointTerminated ( false ) , linkageOnly ( false ) ,
2015-06-26 22:58:36 +00:00
glslangIntermediate ( glslangIntermediate )
{
spv : : ExecutionModel executionModel = TranslateExecutionModel ( glslangIntermediate - > getStage ( ) ) ;
builder . clearAccessChain ( ) ;
2016-03-13 01:34:36 +00:00
builder . setSource ( TranslateSourceLanguage ( glslangIntermediate - > getSource ( ) , glslangIntermediate - > getProfile ( ) ) , glslangIntermediate - > getVersion ( ) ) ;
2015-06-26 22:58:36 +00:00
stdBuiltins = builder . import ( " GLSL.std.450 " ) ;
builder . setMemoryModel ( spv : : AddressingModelLogical , spv : : MemoryModelGLSL450 ) ;
2016-09-20 00:09:30 +00:00
shaderEntry = builder . makeEntryPoint ( glslangIntermediate - > getEntryPointName ( ) . c_str ( ) ) ;
entryPoint = builder . addEntryPoint ( executionModel , shaderEntry , glslangIntermediate - > getEntryPointName ( ) . c_str ( ) ) ;
2015-06-26 22:58:36 +00:00
// Add the source extensions
2015-07-19 04:34:27 +00:00
const auto & sourceExtensions = glslangIntermediate - > getRequestedExtensions ( ) ;
for ( auto it = sourceExtensions . begin ( ) ; it ! = sourceExtensions . end ( ) ; + + it )
2015-06-26 22:58:36 +00:00
builder . addSourceExtension ( it - > c_str ( ) ) ;
// Add the top-level modes for this shader.
2016-02-01 20:45:25 +00:00
if ( glslangIntermediate - > getXfbMode ( ) ) {
builder . addCapability ( spv : : CapabilityTransformFeedback ) ;
2015-06-26 22:58:36 +00:00
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeXfb ) ;
2016-02-01 20:45:25 +00:00
}
2015-06-26 22:58:36 +00:00
unsigned int mode ;
switch ( glslangIntermediate - > getStage ( ) ) {
case EShLangVertex :
2015-08-07 04:53:06 +00:00
builder . addCapability ( spv : : CapabilityShader ) ;
2015-06-26 22:58:36 +00:00
break ;
case EShLangTessControl :
2015-08-07 04:53:06 +00:00
builder . addCapability ( spv : : CapabilityTessellation ) ;
2015-06-26 22:58:36 +00:00
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeOutputVertices , glslangIntermediate - > getVertices ( ) ) ;
break ;
case EShLangTessEvaluation :
2015-08-07 04:53:06 +00:00
builder . addCapability ( spv : : CapabilityTessellation ) ;
2015-06-26 22:58:36 +00:00
switch ( glslangIntermediate - > getInputPrimitive ( ) ) {
2015-11-16 04:33:39 +00:00
case glslang : : ElgTriangles : mode = spv : : ExecutionModeTriangles ; break ;
case glslang : : ElgQuads : mode = spv : : ExecutionModeQuads ; break ;
case glslang : : ElgIsolines : mode = spv : : ExecutionModeIsolines ; break ;
2016-07-15 17:53:56 +00:00
default : mode = spv : : ExecutionModeMax ; break ;
2015-06-26 22:58:36 +00:00
}
2016-07-15 17:53:56 +00:00
if ( mode ! = spv : : ExecutionModeMax )
2015-06-26 22:58:36 +00:00
builder . addExecutionMode ( shaderEntry , ( spv : : ExecutionMode ) mode ) ;
2015-10-13 22:29:02 +00:00
switch ( glslangIntermediate - > getVertexSpacing ( ) ) {
case glslang : : EvsEqual : mode = spv : : ExecutionModeSpacingEqual ; break ;
case glslang : : EvsFractionalEven : mode = spv : : ExecutionModeSpacingFractionalEven ; break ;
case glslang : : EvsFractionalOdd : mode = spv : : ExecutionModeSpacingFractionalOdd ; break ;
2016-07-15 17:53:56 +00:00
default : mode = spv : : ExecutionModeMax ; break ;
2015-10-13 22:29:02 +00:00
}
2016-07-15 17:53:56 +00:00
if ( mode ! = spv : : ExecutionModeMax )
2015-10-13 22:29:02 +00:00
builder . addExecutionMode ( shaderEntry , ( spv : : ExecutionMode ) mode ) ;
switch ( glslangIntermediate - > getVertexOrder ( ) ) {
case glslang : : EvoCw : mode = spv : : ExecutionModeVertexOrderCw ; break ;
case glslang : : EvoCcw : mode = spv : : ExecutionModeVertexOrderCcw ; break ;
2016-07-15 17:53:56 +00:00
default : mode = spv : : ExecutionModeMax ; break ;
2015-10-13 22:29:02 +00:00
}
2016-07-15 17:53:56 +00:00
if ( mode ! = spv : : ExecutionModeMax )
2015-10-13 22:29:02 +00:00
builder . addExecutionMode ( shaderEntry , ( spv : : ExecutionMode ) mode ) ;
if ( glslangIntermediate - > getPointMode ( ) )
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModePointMode ) ;
2015-06-26 22:58:36 +00:00
break ;
case EShLangGeometry :
2015-08-07 04:53:06 +00:00
builder . addCapability ( spv : : CapabilityGeometry ) ;
2015-06-26 22:58:36 +00:00
switch ( glslangIntermediate - > getInputPrimitive ( ) ) {
case glslang : : ElgPoints : mode = spv : : ExecutionModeInputPoints ; break ;
case glslang : : ElgLines : mode = spv : : ExecutionModeInputLines ; break ;
case glslang : : ElgLinesAdjacency : mode = spv : : ExecutionModeInputLinesAdjacency ; break ;
2015-11-16 04:33:39 +00:00
case glslang : : ElgTriangles : mode = spv : : ExecutionModeTriangles ; break ;
2015-06-26 22:58:36 +00:00
case glslang : : ElgTrianglesAdjacency : mode = spv : : ExecutionModeInputTrianglesAdjacency ; break ;
2016-07-15 17:53:56 +00:00
default : mode = spv : : ExecutionModeMax ; break ;
2015-06-26 22:58:36 +00:00
}
2016-07-15 17:53:56 +00:00
if ( mode ! = spv : : ExecutionModeMax )
2015-06-26 22:58:36 +00:00
builder . addExecutionMode ( shaderEntry , ( spv : : ExecutionMode ) mode ) ;
2015-10-13 22:29:02 +00:00
2015-06-26 22:58:36 +00:00
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeInvocations , glslangIntermediate - > getInvocations ( ) ) ;
switch ( glslangIntermediate - > getOutputPrimitive ( ) ) {
case glslang : : ElgPoints : mode = spv : : ExecutionModeOutputPoints ; break ;
case glslang : : ElgLineStrip : mode = spv : : ExecutionModeOutputLineStrip ; break ;
case glslang : : ElgTriangleStrip : mode = spv : : ExecutionModeOutputTriangleStrip ; break ;
2016-07-15 17:53:56 +00:00
default : mode = spv : : ExecutionModeMax ; break ;
2015-06-26 22:58:36 +00:00
}
2016-07-15 17:53:56 +00:00
if ( mode ! = spv : : ExecutionModeMax )
2015-06-26 22:58:36 +00:00
builder . addExecutionMode ( shaderEntry , ( spv : : ExecutionMode ) mode ) ;
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeOutputVertices , glslangIntermediate - > getVertices ( ) ) ;
break ;
case EShLangFragment :
2015-08-07 04:53:06 +00:00
builder . addCapability ( spv : : CapabilityShader ) ;
2015-06-26 22:58:36 +00:00
if ( glslangIntermediate - > getPixelCenterInteger ( ) )
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModePixelCenterInteger ) ;
2015-10-13 22:29:02 +00:00
2015-06-26 22:58:36 +00:00
if ( glslangIntermediate - > getOriginUpperLeft ( ) )
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeOriginUpperLeft ) ;
2015-08-07 04:53:06 +00:00
else
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeOriginLowerLeft ) ;
2015-10-13 22:29:02 +00:00
if ( glslangIntermediate - > getEarlyFragmentTests ( ) )
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeEarlyFragmentTests ) ;
switch ( glslangIntermediate - > getDepth ( ) ) {
case glslang : : EldGreater : mode = spv : : ExecutionModeDepthGreater ; break ;
case glslang : : EldLess : mode = spv : : ExecutionModeDepthLess ; break ;
2016-07-15 17:53:56 +00:00
default : mode = spv : : ExecutionModeMax ; break ;
2015-10-13 22:29:02 +00:00
}
2016-07-15 17:53:56 +00:00
if ( mode ! = spv : : ExecutionModeMax )
2015-10-13 22:29:02 +00:00
builder . addExecutionMode ( shaderEntry , ( spv : : ExecutionMode ) mode ) ;
if ( glslangIntermediate - > getDepth ( ) ! = glslang : : EldUnchanged & & glslangIntermediate - > isDepthReplacing ( ) )
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeDepthReplacing ) ;
2015-06-26 22:58:36 +00:00
break ;
case EShLangCompute :
2015-08-07 04:53:06 +00:00
builder . addCapability ( spv : : CapabilityShader ) ;
2015-09-16 22:04:05 +00:00
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeLocalSize , glslangIntermediate - > getLocalSize ( 0 ) ,
glslangIntermediate - > getLocalSize ( 1 ) ,
glslangIntermediate - > getLocalSize ( 2 ) ) ;
2015-06-26 22:58:36 +00:00
break ;
default :
break ;
}
}
2016-11-26 20:23:20 +00:00
// Finish creating SPV, after the traversal is complete.
void TGlslangToSpvTraverser : : finishSpv ( )
2015-12-21 00:37:07 +00:00
{
2016-11-26 20:31:47 +00:00
if ( ! entryPointTerminated ) {
2016-11-26 20:23:20 +00:00
builder . setBuildPoint ( shaderEntry - > getLastBlock ( ) ) ;
builder . leaveFunction ( ) ;
}
2015-12-21 00:37:07 +00:00
// finish off the entry-point SPV instruction by adding the Input/Output <id>
2016-02-23 21:17:38 +00:00
for ( auto it = iOSet . cbegin ( ) ; it ! = iOSet . cend ( ) ; + + it )
entryPoint - > addIdOperand ( * it ) ;
2015-12-21 00:37:07 +00:00
2016-03-10 00:54:03 +00:00
builder . eliminateDeadDecorations ( ) ;
2015-12-21 00:37:07 +00:00
}
2016-11-26 20:23:20 +00:00
// Write the SPV into 'out'.
void TGlslangToSpvTraverser : : dumpSpv ( std : : vector < unsigned int > & out )
2015-06-26 22:58:36 +00:00
{
2016-11-26 20:23:20 +00:00
builder . dump ( out ) ;
2015-06-26 22:58:36 +00:00
}
//
// Implement the traversal functions.
//
// Return true from interior nodes to have the external traversal
// continue on to children. Return false if children were
// already processed.
//
//
2016-05-06 21:25:16 +00:00
// Symbols can turn into
2015-06-26 22:58:36 +00:00
// - uniform/input reads
// - output writes
// - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain
// - something simple that degenerates into the last bullet
//
void TGlslangToSpvTraverser : : visitSymbol ( glslang : : TIntermSymbol * symbol )
{
2016-04-06 18:42:01 +00:00
SpecConstantOpModeGuard spec_constant_op_mode_setter ( & builder ) ;
if ( symbol - > getType ( ) . getQualifier ( ) . isSpecConstant ( ) )
spec_constant_op_mode_setter . turnOnSpecConstantOpMode ( ) ;
2015-06-26 22:58:36 +00:00
// getSymbolId() will set up all the IO decorations on the first call.
// Formal function parameters were mapped during makeFunctions().
spv : : Id id = getSymbolId ( symbol ) ;
2015-12-21 00:37:07 +00:00
// Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction
if ( builder . isPointer ( id ) ) {
spv : : StorageClass sc = builder . getStorageClass ( id ) ;
if ( sc = = spv : : StorageClassInput | | sc = = spv : : StorageClassOutput )
iOSet . insert ( id ) ;
}
// Only process non-linkage-only nodes for generating actual static uses
2016-02-16 03:58:50 +00:00
if ( ! linkageOnly | | symbol - > getQualifier ( ) . isSpecConstant ( ) ) {
2015-06-26 22:58:36 +00:00
// Prepare to generate code for the access
// L-value chains will be computed left to right. We're on the symbol now,
// which is the left-most part of the access chain, so now is "clear" time,
// followed by setting the base.
builder . clearAccessChain ( ) ;
// For now, we consider all user variables as being in memory, so they are pointers,
2016-02-16 03:58:50 +00:00
// except for
2016-09-02 17:20:21 +00:00
// A) R-Value arguments to a function, which are an intermediate object.
2016-02-16 03:58:50 +00:00
// See comments in handleUserFunctionCall().
2016-09-02 17:20:21 +00:00
// B) Specialization constants (normal constants don't even come in as a variable),
2016-02-16 03:58:50 +00:00
// These are also pure R-values.
glslang : : TQualifier qualifier = symbol - > getQualifier ( ) ;
2016-09-02 17:20:21 +00:00
if ( qualifier . isSpecConstant ( ) | | rValueParameters . find ( symbol - > getId ( ) ) ! = rValueParameters . end ( ) )
2015-06-26 22:58:36 +00:00
builder . setAccessChainRValue ( id ) ;
else
builder . setAccessChainLValue ( id ) ;
}
}
bool TGlslangToSpvTraverser : : visitBinary ( glslang : : TVisit /* visit */ , glslang : : TIntermBinary * node )
{
2016-04-04 02:20:42 +00:00
SpecConstantOpModeGuard spec_constant_op_mode_setter ( & builder ) ;
if ( node - > getType ( ) . getQualifier ( ) . isSpecConstant ( ) )
spec_constant_op_mode_setter . turnOnSpecConstantOpMode ( ) ;
2015-06-26 22:58:36 +00:00
// First, handle special cases
switch ( node - > getOp ( ) ) {
case glslang : : EOpAssign :
case glslang : : EOpAddAssign :
case glslang : : EOpSubAssign :
case glslang : : EOpMulAssign :
case glslang : : EOpVectorTimesMatrixAssign :
case glslang : : EOpVectorTimesScalarAssign :
case glslang : : EOpMatrixTimesScalarAssign :
case glslang : : EOpMatrixTimesMatrixAssign :
case glslang : : EOpDivAssign :
case glslang : : EOpModAssign :
case glslang : : EOpAndAssign :
case glslang : : EOpInclusiveOrAssign :
case glslang : : EOpExclusiveOrAssign :
case glslang : : EOpLeftShiftAssign :
case glslang : : EOpRightShiftAssign :
// A bin-op assign "a += b" means the same thing as "a = a + b"
// where a is evaluated before b. For a simple assignment, GLSL
// says to evaluate the left before the right. So, always, left
// node then right node.
{
// get the left l-value, save it away
builder . clearAccessChain ( ) ;
node - > getLeft ( ) - > traverse ( this ) ;
spv : : Builder : : AccessChain lValue = builder . getAccessChain ( ) ;
// evaluate the right
builder . clearAccessChain ( ) ;
node - > getRight ( ) - > traverse ( this ) ;
2016-02-02 19:37:46 +00:00
spv : : Id rValue = accessChainLoad ( node - > getRight ( ) - > getType ( ) ) ;
2015-06-26 22:58:36 +00:00
if ( node - > getOp ( ) ! = glslang : : EOpAssign ) {
// the left is also an r-value
builder . setAccessChain ( lValue ) ;
2016-02-02 19:37:46 +00:00
spv : : Id leftRValue = accessChainLoad ( node - > getLeft ( ) - > getType ( ) ) ;
2015-06-26 22:58:36 +00:00
// do the operation
2016-08-02 01:44:00 +00:00
rValue = createBinaryOperation ( node - > getOp ( ) , TranslatePrecisionDecoration ( node - > getOperationPrecision ( ) ) ,
2016-05-06 21:25:16 +00:00
TranslateNoContractionDecoration ( node - > getType ( ) . getQualifier ( ) ) ,
2015-06-26 22:58:36 +00:00
convertGlslangToSpvType ( node - > getType ( ) ) , leftRValue , rValue ,
node - > getType ( ) . getBasicType ( ) ) ;
// these all need their counterparts in createBinaryOperation()
2015-11-16 04:33:39 +00:00
assert ( rValue ! = spv : : NoResult ) ;
2015-06-26 22:58:36 +00:00
}
// store the result
builder . setAccessChain ( lValue ) ;
2016-09-02 17:20:21 +00:00
multiTypeStore ( node - > getType ( ) , rValue ) ;
2015-06-26 22:58:36 +00:00
// assignments are expressions having an rValue after they are evaluated...
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( rValue ) ;
}
return false ;
case glslang : : EOpIndexDirect :
case glslang : : EOpIndexDirectStruct :
{
// Get the left part of the access chain.
node - > getLeft ( ) - > traverse ( this ) ;
// Add the next element in the chain
2016-06-08 13:11:40 +00:00
const int glslangIndex = node - > getRight ( ) - > getAsConstantUnion ( ) - > getConstArray ( ) [ 0 ] . getIConst ( ) ;
2015-06-26 22:58:36 +00:00
if ( ! node - > getLeft ( ) - > getType ( ) . isArray ( ) & &
node - > getLeft ( ) - > getType ( ) . isVector ( ) & &
node - > getOp ( ) = = glslang : : EOpIndexDirect ) {
// This is essentially a hard-coded vector swizzle of size 1,
// so short circuit the access-chain stuff with a swizzle.
std : : vector < unsigned > swizzle ;
2016-06-08 13:11:40 +00:00
swizzle . push_back ( glslangIndex ) ;
2015-09-13 20:46:30 +00:00
builder . accessChainPushSwizzle ( swizzle , convertGlslangToSpvType ( node - > getLeft ( ) - > getType ( ) ) ) ;
2015-06-26 22:58:36 +00:00
} else {
2016-06-08 13:11:40 +00:00
int spvIndex = glslangIndex ;
if ( node - > getLeft ( ) - > getBasicType ( ) = = glslang : : EbtBlock & &
node - > getOp ( ) = = glslang : : EOpIndexDirectStruct )
{
// This may be, e.g., an anonymous block-member selection, which generally need
// index remapping due to hidden members in anonymous blocks.
std : : vector < int > & remapper = memberRemapper [ node - > getLeft ( ) - > getType ( ) . getStruct ( ) ] ;
assert ( remapper . size ( ) > 0 ) ;
spvIndex = remapper [ glslangIndex ] ;
}
2015-06-26 22:58:36 +00:00
// normal case for indexing array or structure or block
2016-06-08 13:11:40 +00:00
builder . accessChainPush ( builder . makeIntConstant ( spvIndex ) ) ;
2016-05-17 01:22:05 +00:00
2016-06-08 13:11:40 +00:00
// Add capabilities here for accessing PointSize and clip/cull distance.
// We have deferred generation of associated capabilities until now.
2016-05-17 01:22:05 +00:00
if ( node - > getLeft ( ) - > getType ( ) . isStruct ( ) & & ! node - > getLeft ( ) - > getType ( ) . isArray ( ) )
2016-06-08 13:11:40 +00:00
declareUseOfStructMember ( * ( node - > getLeft ( ) - > getType ( ) . getStruct ( ) ) , glslangIndex ) ;
2015-06-26 22:58:36 +00:00
}
}
return false ;
case glslang : : EOpIndexIndirect :
{
// Structure or array or vector indirection.
// Will use native SPIR-V access-chain for struct and array indirection;
// matrices are arrays of vectors, so will also work for a matrix.
// Will use the access chain's 'component' for variable index into a vector.
// This adapter is building access chains left to right.
// Set up the access chain to the left.
node - > getLeft ( ) - > traverse ( this ) ;
// save it so that computing the right side doesn't trash it
spv : : Builder : : AccessChain partial = builder . getAccessChain ( ) ;
// compute the next index in the chain
builder . clearAccessChain ( ) ;
node - > getRight ( ) - > traverse ( this ) ;
2016-02-02 19:37:46 +00:00
spv : : Id index = accessChainLoad ( node - > getRight ( ) - > getType ( ) ) ;
2015-06-26 22:58:36 +00:00
// restore the saved access chain
builder . setAccessChain ( partial ) ;
if ( ! node - > getLeft ( ) - > getType ( ) . isArray ( ) & & node - > getLeft ( ) - > getType ( ) . isVector ( ) )
2015-09-13 20:46:30 +00:00
builder . accessChainPushComponent ( index , convertGlslangToSpvType ( node - > getLeft ( ) - > getType ( ) ) ) ;
2015-06-26 22:58:36 +00:00
else
2015-09-13 20:46:30 +00:00
builder . accessChainPush ( index ) ;
2015-06-26 22:58:36 +00:00
}
return false ;
case glslang : : EOpVectorSwizzle :
{
node - > getLeft ( ) - > traverse ( this ) ;
std : : vector < unsigned > swizzle ;
2016-07-26 18:50:38 +00:00
convertSwizzle ( * node - > getRight ( ) - > getAsAggregate ( ) , swizzle ) ;
2015-09-13 20:46:30 +00:00
builder . accessChainPushSwizzle ( swizzle , convertGlslangToSpvType ( node - > getLeft ( ) - > getType ( ) ) ) ;
2015-06-26 22:58:36 +00:00
}
return false ;
2015-10-15 19:29:11 +00:00
case glslang : : EOpLogicalOr :
case glslang : : EOpLogicalAnd :
{
// These may require short circuiting, but can sometimes be done as straight
// binary operations. The right operand must be short circuited if it has
// side effects, and should probably be if it is complex.
if ( isTrivial ( node - > getRight ( ) - > getAsTyped ( ) ) )
break ; // handle below as a normal binary operation
// otherwise, we need to do dynamic short circuiting on the right operand
spv : : Id result = createShortCircuit ( node - > getOp ( ) , * node - > getLeft ( ) - > getAsTyped ( ) , * node - > getRight ( ) - > getAsTyped ( ) ) ;
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( result ) ;
}
return false ;
2015-06-26 22:58:36 +00:00
default :
break ;
}
// Assume generic binary op...
2016-02-02 19:37:46 +00:00
// get right operand
2015-06-26 22:58:36 +00:00
builder . clearAccessChain ( ) ;
node - > getLeft ( ) - > traverse ( this ) ;
2016-02-02 19:37:46 +00:00
spv : : Id left = accessChainLoad ( node - > getLeft ( ) - > getType ( ) ) ;
2015-06-26 22:58:36 +00:00
2016-02-02 19:37:46 +00:00
// get left operand
2015-06-26 22:58:36 +00:00
builder . clearAccessChain ( ) ;
node - > getRight ( ) - > traverse ( this ) ;
2016-02-02 19:37:46 +00:00
spv : : Id right = accessChainLoad ( node - > getRight ( ) - > getType ( ) ) ;
2015-06-26 22:58:36 +00:00
2016-02-02 19:37:46 +00:00
// get result
2016-08-02 01:44:00 +00:00
spv : : Id result = createBinaryOperation ( node - > getOp ( ) , TranslatePrecisionDecoration ( node - > getOperationPrecision ( ) ) ,
2016-05-06 21:25:16 +00:00
TranslateNoContractionDecoration ( node - > getType ( ) . getQualifier ( ) ) ,
2016-02-02 19:37:46 +00:00
convertGlslangToSpvType ( node - > getType ( ) ) , left , right ,
node - > getLeft ( ) - > getType ( ) . getBasicType ( ) ) ;
2015-06-26 22:58:36 +00:00
2015-12-22 04:21:11 +00:00
builder . clearAccessChain ( ) ;
2015-06-26 22:58:36 +00:00
if ( ! result ) {
2016-05-04 19:55:59 +00:00
logger - > missingFunctionality ( " unknown glslang binary operation " ) ;
2015-12-22 04:21:11 +00:00
return true ; // pick up a child as the place-holder result
2015-06-26 22:58:36 +00:00
} else {
builder . setAccessChainRValue ( result ) ;
return false ;
}
}
bool TGlslangToSpvTraverser : : visitUnary ( glslang : : TVisit /* visit */ , glslang : : TIntermUnary * node )
{
2016-04-04 02:20:42 +00:00
SpecConstantOpModeGuard spec_constant_op_mode_setter ( & builder ) ;
if ( node - > getType ( ) . getQualifier ( ) . isSpecConstant ( ) )
spec_constant_op_mode_setter . turnOnSpecConstantOpMode ( ) ;
2015-08-19 19:34:18 +00:00
spv : : Id result = spv : : NoResult ;
// try texturing first
result = createImageTextureFunctionCall ( node ) ;
if ( result ! = spv : : NoResult ) {
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( result ) ;
return false ; // done with this node
}
// Non-texturing.
2015-09-12 18:17:44 +00:00
if ( node - > getOp ( ) = = glslang : : EOpArrayLength ) {
// Quite special; won't want to evaluate the operand.
// Normal .length() would have been constant folded by the front-end.
// So, this has to be block.lastMember.length().
2015-09-22 03:50:29 +00:00
// SPV wants "block" and member number as the operands, go get them.
2015-09-12 18:17:44 +00:00
assert ( node - > getOperand ( ) - > getType ( ) . isRuntimeSizedArray ( ) ) ;
glslang : : TIntermTyped * block = node - > getOperand ( ) - > getAsBinaryNode ( ) - > getLeft ( ) ;
block - > traverse ( this ) ;
2015-09-22 03:50:29 +00:00
unsigned int member = node - > getOperand ( ) - > getAsBinaryNode ( ) - > getRight ( ) - > getAsConstantUnion ( ) - > getConstArray ( ) [ 0 ] . getUConst ( ) ;
spv : : Id length = builder . createArrayLength ( builder . accessChainGetLValue ( ) , member ) ;
2015-09-12 18:17:44 +00:00
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( length ) ;
return false ;
}
2015-08-19 19:34:18 +00:00
// Start by evaluating the operand
2016-07-26 18:50:38 +00:00
// Does it need a swizzle inversion? If so, evaluation is inverted;
// operate first on the swizzle base, then apply the swizzle.
spv : : Id invertedType = spv : : NoType ;
auto resultType = [ & invertedType , & node , this ] ( ) { return invertedType ! = spv : : NoType ? invertedType : convertGlslangToSpvType ( node - > getType ( ) ) ; } ;
if ( node - > getOp ( ) = = glslang : : EOpInterpolateAtCentroid )
invertedType = getInvertedSwizzleType ( * node - > getOperand ( ) ) ;
2015-06-26 22:58:36 +00:00
builder . clearAccessChain ( ) ;
2016-07-26 18:50:38 +00:00
if ( invertedType ! = spv : : NoType )
node - > getOperand ( ) - > getAsBinaryNode ( ) - > getLeft ( ) - > traverse ( this ) ;
else
node - > getOperand ( ) - > traverse ( this ) ;
2015-09-14 02:38:56 +00:00
2015-09-09 08:42:49 +00:00
spv : : Id operand = spv : : NoResult ;
if ( node - > getOp ( ) = = glslang : : EOpAtomicCounterIncrement | |
node - > getOp ( ) = = glslang : : EOpAtomicCounterDecrement | |
2015-12-08 09:12:09 +00:00
node - > getOp ( ) = = glslang : : EOpAtomicCounter | |
node - > getOp ( ) = = glslang : : EOpInterpolateAtCentroid )
2015-09-09 08:42:49 +00:00
operand = builder . accessChainGetLValue ( ) ; // Special case l-value operands
else
2016-02-02 19:37:46 +00:00
operand = accessChainLoad ( node - > getOperand ( ) - > getType ( ) ) ;
2015-06-26 22:58:36 +00:00
2016-08-02 01:44:00 +00:00
spv : : Decoration precision = TranslatePrecisionDecoration ( node - > getOperationPrecision ( ) ) ;
2016-05-06 21:25:16 +00:00
spv : : Decoration noContraction = TranslateNoContractionDecoration ( node - > getType ( ) . getQualifier ( ) ) ;
2015-06-26 22:58:36 +00:00
// it could be a conversion
2015-08-19 19:34:18 +00:00
if ( ! result )
2016-07-26 18:50:38 +00:00
result = createConversion ( node - > getOp ( ) , precision , noContraction , resultType ( ) , operand , node - > getOperand ( ) - > getBasicType ( ) ) ;
2015-06-26 22:58:36 +00:00
// if not, then possibly an operation
if ( ! result )
2016-07-26 18:50:38 +00:00
result = createUnaryOperation ( node - > getOp ( ) , precision , noContraction , resultType ( ) , operand , node - > getOperand ( ) - > getBasicType ( ) ) ;
2015-06-26 22:58:36 +00:00
if ( result ) {
2016-07-26 18:50:38 +00:00
if ( invertedType )
result = createInvertedSwizzle ( precision , * node - > getOperand ( ) , result ) ;
2015-06-26 22:58:36 +00:00
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( result ) ;
return false ; // done with this node
}
// it must be a special case, check...
switch ( node - > getOp ( ) ) {
case glslang : : EOpPostIncrement :
case glslang : : EOpPostDecrement :
case glslang : : EOpPreIncrement :
case glslang : : EOpPreDecrement :
{
// we need the integer value "1" or the floating point "1.0" to add/subtract
2016-04-22 08:51:45 +00:00
spv : : Id one = 0 ;
if ( node - > getBasicType ( ) = = glslang : : EbtFloat )
one = builder . makeFloatConstant ( 1.0F ) ;
2016-07-29 08:13:04 +00:00
else if ( node - > getBasicType ( ) = = glslang : : EbtDouble )
one = builder . makeDoubleConstant ( 1.0 ) ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
else if ( node - > getBasicType ( ) = = glslang : : EbtFloat16 )
one = builder . makeFloat16Constant ( 1.0F ) ;
# endif
2016-04-22 08:51:45 +00:00
else if ( node - > getBasicType ( ) = = glslang : : EbtInt64 | | node - > getBasicType ( ) = = glslang : : EbtUint64 )
one = builder . makeInt64Constant ( 1 ) ;
else
one = builder . makeIntConstant ( 1 ) ;
2015-06-26 22:58:36 +00:00
glslang : : TOperator op ;
if ( node - > getOp ( ) = = glslang : : EOpPreIncrement | |
node - > getOp ( ) = = glslang : : EOpPostIncrement )
op = glslang : : EOpAdd ;
else
op = glslang : : EOpSub ;
2016-08-02 01:44:00 +00:00
spv : : Id result = createBinaryOperation ( op , precision ,
2016-05-06 21:25:16 +00:00
TranslateNoContractionDecoration ( node - > getType ( ) . getQualifier ( ) ) ,
2016-04-22 08:51:45 +00:00
convertGlslangToSpvType ( node - > getType ( ) ) , operand , one ,
node - > getType ( ) . getBasicType ( ) ) ;
2015-11-16 04:33:39 +00:00
assert ( result ! = spv : : NoResult ) ;
2015-06-26 22:58:36 +00:00
// The result of operation is always stored, but conditionally the
// consumed result. The consumed result is always an r-value.
builder . accessChainStore ( result ) ;
builder . clearAccessChain ( ) ;
if ( node - > getOp ( ) = = glslang : : EOpPreIncrement | |
node - > getOp ( ) = = glslang : : EOpPreDecrement )
builder . setAccessChainRValue ( result ) ;
else
builder . setAccessChainRValue ( operand ) ;
}
return false ;
case glslang : : EOpEmitStreamVertex :
builder . createNoResultOp ( spv : : OpEmitStreamVertex , operand ) ;
return false ;
case glslang : : EOpEndStreamPrimitive :
builder . createNoResultOp ( spv : : OpEndStreamPrimitive , operand ) ;
return false ;
default :
2016-05-04 19:55:59 +00:00
logger - > missingFunctionality ( " unknown glslang unary " ) ;
2015-12-22 04:21:11 +00:00
return true ; // pick up operand as placeholder result
2015-06-26 22:58:36 +00:00
}
}
bool TGlslangToSpvTraverser : : visitAggregate ( glslang : : TVisit visit , glslang : : TIntermAggregate * node )
{
2016-04-14 20:40:20 +00:00
SpecConstantOpModeGuard spec_constant_op_mode_setter ( & builder ) ;
if ( node - > getType ( ) . getQualifier ( ) . isSpecConstant ( ) )
spec_constant_op_mode_setter . turnOnSpecConstantOpMode ( ) ;
2015-08-19 19:34:18 +00:00
spv : : Id result = spv : : NoResult ;
2016-07-26 18:50:38 +00:00
spv : : Id invertedType = spv : : NoType ; // to use to override the natural type of the node
auto resultType = [ & invertedType , & node , this ] ( ) { return invertedType ! = spv : : NoType ? invertedType : convertGlslangToSpvType ( node - > getType ( ) ) ; } ;
2015-08-19 19:34:18 +00:00
// try texturing
result = createImageTextureFunctionCall ( node ) ;
if ( result ! = spv : : NoResult ) {
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( result ) ;
return false ;
2015-09-16 16:54:31 +00:00
} else if ( node - > getOp ( ) = = glslang : : EOpImageStore ) {
2015-09-09 08:42:49 +00:00
// "imageStore" is a special case, which has no result
return false ;
}
2015-08-19 19:34:18 +00:00
2015-06-26 22:58:36 +00:00
glslang : : TOperator binOp = glslang : : EOpNull ;
bool reduceComparison = true ;
bool isMatrix = false ;
bool noReturnValue = false ;
2015-07-23 16:22:48 +00:00
bool atomic = false ;
2015-06-26 22:58:36 +00:00
assert ( node - > getOp ( ) ) ;
2016-08-02 01:44:00 +00:00
spv : : Decoration precision = TranslatePrecisionDecoration ( node - > getOperationPrecision ( ) ) ;
2015-06-26 22:58:36 +00:00
switch ( node - > getOp ( ) ) {
case glslang : : EOpSequence :
{
if ( preVisit )
+ + sequenceDepth ;
else
- - sequenceDepth ;
if ( sequenceDepth = = 1 ) {
// If this is the parent node of all the functions, we want to see them
// early, so all call points have actual SPIR-V functions to reference.
// In all cases, still let the traverser visit the children for us.
makeFunctions ( node - > getAsAggregate ( ) - > getSequence ( ) ) ;
2016-09-19 22:01:41 +00:00
// Also, we want all globals initializers to go into the beginning of the entry point, before
2015-06-26 22:58:36 +00:00
// anything else gets there, so visit out of order, doing them all now.
makeGlobalInitializers ( node - > getAsAggregate ( ) - > getSequence ( ) ) ;
2016-12-09 04:01:59 +00:00
// Initializers are done, don't want to visit again, but functions and link objects need to be processed,
2015-06-26 22:58:36 +00:00
// so do them manually.
visitFunctions ( node - > getAsAggregate ( ) - > getSequence ( ) ) ;
return false ;
}
return true ;
}
case glslang : : EOpLinkerObjects :
{
if ( visit = = glslang : : EvPreVisit )
linkageOnly = true ;
else
linkageOnly = false ;
return true ;
}
case glslang : : EOpComma :
{
// processing from left to right naturally leaves the right-most
// lying around in the access chain
glslang : : TIntermSequence & glslangOperands = node - > getSequence ( ) ;
for ( int i = 0 ; i < ( int ) glslangOperands . size ( ) ; + + i )
glslangOperands [ i ] - > traverse ( this ) ;
return false ;
}
case glslang : : EOpFunction :
if ( visit = = glslang : : EvPreVisit ) {
2016-09-19 22:01:41 +00:00
if ( isShaderEntryPoint ( node ) ) {
2016-11-26 20:31:47 +00:00
inEntryPoint = true ;
2015-06-26 22:58:36 +00:00
builder . setBuildPoint ( shaderEntry - > getLastBlock ( ) ) ;
2016-10-06 18:59:51 +00:00
currentFunction = shaderEntry ;
2015-06-26 22:58:36 +00:00
} else {
handleFunctionEntry ( node ) ;
}
} else {
2016-11-26 20:31:47 +00:00
if ( inEntryPoint )
entryPointTerminated = true ;
2015-09-15 02:58:02 +00:00
builder . leaveFunction ( ) ;
2016-11-26 20:31:47 +00:00
inEntryPoint = false ;
2015-06-26 22:58:36 +00:00
}
return true ;
case glslang : : EOpParameters :
// Parameters will have been consumed by EOpFunction processing, but not
// the body, so we still visited the function node's children, making this
// child redundant.
return false ;
case glslang : : EOpFunctionCall :
{
if ( node - > isUserDefined ( ) )
result = handleUserFunctionCall ( node ) ;
2016-02-16 03:58:50 +00:00
//assert(result); // this can happen for bad shaders because the call graph completeness checking is not yet done
if ( result ) {
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( result ) ;
} else
2016-05-04 19:55:59 +00:00
logger - > missingFunctionality ( " missing user function; linker needs to catch that " ) ;
2015-06-26 22:58:36 +00:00
return false ;
}
case glslang : : EOpConstructMat2x2 :
case glslang : : EOpConstructMat2x3 :
case glslang : : EOpConstructMat2x4 :
case glslang : : EOpConstructMat3x2 :
case glslang : : EOpConstructMat3x3 :
case glslang : : EOpConstructMat3x4 :
case glslang : : EOpConstructMat4x2 :
case glslang : : EOpConstructMat4x3 :
case glslang : : EOpConstructMat4x4 :
case glslang : : EOpConstructDMat2x2 :
case glslang : : EOpConstructDMat2x3 :
case glslang : : EOpConstructDMat2x4 :
case glslang : : EOpConstructDMat3x2 :
case glslang : : EOpConstructDMat3x3 :
case glslang : : EOpConstructDMat3x4 :
case glslang : : EOpConstructDMat4x2 :
case glslang : : EOpConstructDMat4x3 :
case glslang : : EOpConstructDMat4x4 :
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpConstructF16Mat2x2 :
case glslang : : EOpConstructF16Mat2x3 :
case glslang : : EOpConstructF16Mat2x4 :
case glslang : : EOpConstructF16Mat3x2 :
case glslang : : EOpConstructF16Mat3x3 :
case glslang : : EOpConstructF16Mat3x4 :
case glslang : : EOpConstructF16Mat4x2 :
case glslang : : EOpConstructF16Mat4x3 :
case glslang : : EOpConstructF16Mat4x4 :
# endif
2015-06-26 22:58:36 +00:00
isMatrix = true ;
// fall through
case glslang : : EOpConstructFloat :
case glslang : : EOpConstructVec2 :
case glslang : : EOpConstructVec3 :
case glslang : : EOpConstructVec4 :
case glslang : : EOpConstructDouble :
case glslang : : EOpConstructDVec2 :
case glslang : : EOpConstructDVec3 :
case glslang : : EOpConstructDVec4 :
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpConstructFloat16 :
case glslang : : EOpConstructF16Vec2 :
case glslang : : EOpConstructF16Vec3 :
case glslang : : EOpConstructF16Vec4 :
# endif
2015-06-26 22:58:36 +00:00
case glslang : : EOpConstructBool :
case glslang : : EOpConstructBVec2 :
case glslang : : EOpConstructBVec3 :
case glslang : : EOpConstructBVec4 :
case glslang : : EOpConstructInt :
case glslang : : EOpConstructIVec2 :
case glslang : : EOpConstructIVec3 :
case glslang : : EOpConstructIVec4 :
case glslang : : EOpConstructUint :
case glslang : : EOpConstructUVec2 :
case glslang : : EOpConstructUVec3 :
case glslang : : EOpConstructUVec4 :
2016-04-22 08:51:45 +00:00
case glslang : : EOpConstructInt64 :
case glslang : : EOpConstructI64Vec2 :
case glslang : : EOpConstructI64Vec3 :
case glslang : : EOpConstructI64Vec4 :
case glslang : : EOpConstructUint64 :
case glslang : : EOpConstructU64Vec2 :
case glslang : : EOpConstructU64Vec3 :
case glslang : : EOpConstructU64Vec4 :
2015-06-26 22:58:36 +00:00
case glslang : : EOpConstructStruct :
2016-02-16 03:58:50 +00:00
case glslang : : EOpConstructTextureSampler :
2015-06-26 22:58:36 +00:00
{
std : : vector < spv : : Id > arguments ;
2015-09-09 08:42:49 +00:00
translateArguments ( * node , arguments ) ;
2015-06-26 22:58:36 +00:00
spv : : Id constructed ;
2016-02-16 03:58:50 +00:00
if ( node - > getOp ( ) = = glslang : : EOpConstructTextureSampler )
2016-07-26 18:50:38 +00:00
constructed = builder . createOp ( spv : : OpSampledImage , resultType ( ) , arguments ) ;
2016-02-16 03:58:50 +00:00
else if ( node - > getOp ( ) = = glslang : : EOpConstructStruct | | node - > getType ( ) . isArray ( ) ) {
2015-06-26 22:58:36 +00:00
std : : vector < spv : : Id > constituents ;
for ( int c = 0 ; c < ( int ) arguments . size ( ) ; + + c )
constituents . push_back ( arguments [ c ] ) ;
2016-07-26 18:50:38 +00:00
constructed = builder . createCompositeConstruct ( resultType ( ) , constituents ) ;
2015-11-16 04:33:39 +00:00
} else if ( isMatrix )
2016-07-26 18:50:38 +00:00
constructed = builder . createMatrixConstructor ( precision , arguments , resultType ( ) ) ;
2015-11-16 04:33:39 +00:00
else
2016-07-26 18:50:38 +00:00
constructed = builder . createConstructor ( precision , arguments , resultType ( ) ) ;
2015-06-26 22:58:36 +00:00
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( constructed ) ;
return false ;
}
// These six are component-wise compares with component-wise results.
// Forward on to createBinaryOperation(), requesting a vector result.
case glslang : : EOpLessThan :
case glslang : : EOpGreaterThan :
case glslang : : EOpLessThanEqual :
case glslang : : EOpGreaterThanEqual :
case glslang : : EOpVectorEqual :
case glslang : : EOpVectorNotEqual :
{
// Map the operation to a binary
binOp = node - > getOp ( ) ;
reduceComparison = false ;
switch ( node - > getOp ( ) ) {
case glslang : : EOpVectorEqual : binOp = glslang : : EOpVectorEqual ; break ;
case glslang : : EOpVectorNotEqual : binOp = glslang : : EOpVectorNotEqual ; break ;
default : binOp = node - > getOp ( ) ; break ;
}
break ;
}
case glslang : : EOpMul :
2016-07-26 18:50:38 +00:00
// component-wise matrix multiply
2015-06-26 22:58:36 +00:00
binOp = glslang : : EOpMul ;
break ;
case glslang : : EOpOuterProduct :
// two vectors multiplied to make a matrix
binOp = glslang : : EOpOuterProduct ;
break ;
case glslang : : EOpDot :
{
2016-05-06 21:25:16 +00:00
// for scalar dot product, use multiply
2015-06-26 22:58:36 +00:00
glslang : : TIntermSequence & glslangOperands = node - > getSequence ( ) ;
2016-05-20 18:06:03 +00:00
if ( glslangOperands [ 0 ] - > getAsTyped ( ) - > getVectorSize ( ) = = 1 )
2015-06-26 22:58:36 +00:00
binOp = glslang : : EOpMul ;
break ;
}
case glslang : : EOpMod :
// when an aggregate, this is the floating-point mod built-in function,
// which can be emitted by the one in createBinaryOperation()
binOp = glslang : : EOpMod ;
break ;
case glslang : : EOpEmitVertex :
case glslang : : EOpEndPrimitive :
case glslang : : EOpBarrier :
case glslang : : EOpMemoryBarrier :
case glslang : : EOpMemoryBarrierAtomicCounter :
case glslang : : EOpMemoryBarrierBuffer :
case glslang : : EOpMemoryBarrierImage :
case glslang : : EOpMemoryBarrierShared :
case glslang : : EOpGroupMemoryBarrier :
2016-06-15 15:50:24 +00:00
case glslang : : EOpAllMemoryBarrierWithGroupSync :
case glslang : : EOpGroupMemoryBarrierWithGroupSync :
case glslang : : EOpWorkgroupMemoryBarrier :
case glslang : : EOpWorkgroupMemoryBarrierWithGroupSync :
2015-06-26 22:58:36 +00:00
noReturnValue = true ;
// These all have 0 operands and will naturally finish up in the code below for 0 operands
break ;
2015-07-23 16:22:48 +00:00
case glslang : : EOpAtomicAdd :
case glslang : : EOpAtomicMin :
case glslang : : EOpAtomicMax :
case glslang : : EOpAtomicAnd :
case glslang : : EOpAtomicOr :
case glslang : : EOpAtomicXor :
case glslang : : EOpAtomicExchange :
case glslang : : EOpAtomicCompSwap :
atomic = true ;
break ;
2015-06-26 22:58:36 +00:00
default :
break ;
}
//
// See if it maps to a regular operation.
//
if ( binOp ! = glslang : : EOpNull ) {
glslang : : TIntermTyped * left = node - > getSequence ( ) [ 0 ] - > getAsTyped ( ) ;
glslang : : TIntermTyped * right = node - > getSequence ( ) [ 1 ] - > getAsTyped ( ) ;
assert ( left & & right ) ;
builder . clearAccessChain ( ) ;
left - > traverse ( this ) ;
2016-02-02 19:37:46 +00:00
spv : : Id leftId = accessChainLoad ( left - > getType ( ) ) ;
2015-06-26 22:58:36 +00:00
builder . clearAccessChain ( ) ;
right - > traverse ( this ) ;
2016-02-02 19:37:46 +00:00
spv : : Id rightId = accessChainLoad ( right - > getType ( ) ) ;
2015-06-26 22:58:36 +00:00
2016-05-06 21:25:16 +00:00
result = createBinaryOperation ( binOp , precision , TranslateNoContractionDecoration ( node - > getType ( ) . getQualifier ( ) ) ,
2016-07-26 18:50:38 +00:00
resultType ( ) , leftId , rightId ,
2015-06-26 22:58:36 +00:00
left - > getType ( ) . getBasicType ( ) , reduceComparison ) ;
// code above should only make binOp that exists in createBinaryOperation
2015-11-16 04:33:39 +00:00
assert ( result ! = spv : : NoResult ) ;
2015-06-26 22:58:36 +00:00
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( result ) ;
return false ;
}
2015-07-23 16:22:48 +00:00
//
// Create the list of operands.
//
2015-06-26 22:58:36 +00:00
glslang : : TIntermSequence & glslangOperands = node - > getSequence ( ) ;
std : : vector < spv : : Id > operands ;
for ( int arg = 0 ; arg < ( int ) glslangOperands . size ( ) ; + + arg ) {
// special case l-value operands; there are just a few
bool lvalue = false ;
switch ( node - > getOp ( ) ) {
2015-11-16 04:33:39 +00:00
case glslang : : EOpFrexp :
2015-06-26 22:58:36 +00:00
case glslang : : EOpModf :
if ( arg = = 1 )
lvalue = true ;
break ;
2015-12-08 09:12:09 +00:00
case glslang : : EOpInterpolateAtSample :
case glslang : : EOpInterpolateAtOffset :
2016-05-05 04:30:44 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpInterpolateAtVertex :
# endif
2016-07-26 18:50:38 +00:00
if ( arg = = 0 ) {
2015-12-08 09:12:09 +00:00
lvalue = true ;
2016-07-26 18:50:38 +00:00
// Does it need a swizzle inversion? If so, evaluation is inverted;
// operate first on the swizzle base, then apply the swizzle.
if ( glslangOperands [ 0 ] - > getAsOperator ( ) & &
glslangOperands [ 0 ] - > getAsOperator ( ) - > getOp ( ) = = glslang : : EOpVectorSwizzle )
invertedType = convertGlslangToSpvType ( glslangOperands [ 0 ] - > getAsBinaryNode ( ) - > getLeft ( ) - > getType ( ) ) ;
}
2015-12-08 09:12:09 +00:00
break ;
2015-09-06 08:30:11 +00:00
case glslang : : EOpAtomicAdd :
case glslang : : EOpAtomicMin :
case glslang : : EOpAtomicMax :
case glslang : : EOpAtomicAnd :
case glslang : : EOpAtomicOr :
case glslang : : EOpAtomicXor :
case glslang : : EOpAtomicExchange :
case glslang : : EOpAtomicCompSwap :
if ( arg = = 0 )
lvalue = true ;
break ;
2015-11-16 04:33:39 +00:00
case glslang : : EOpAddCarry :
case glslang : : EOpSubBorrow :
if ( arg = = 2 )
lvalue = true ;
break ;
case glslang : : EOpUMulExtended :
case glslang : : EOpIMulExtended :
if ( arg > = 2 )
lvalue = true ;
break ;
2015-06-26 22:58:36 +00:00
default :
break ;
}
2016-07-26 18:50:38 +00:00
builder . clearAccessChain ( ) ;
if ( invertedType ! = spv : : NoType & & arg = = 0 )
glslangOperands [ 0 ] - > getAsBinaryNode ( ) - > getLeft ( ) - > traverse ( this ) ;
else
glslangOperands [ arg ] - > traverse ( this ) ;
2015-06-26 22:58:36 +00:00
if ( lvalue )
operands . push_back ( builder . accessChainGetLValue ( ) ) ;
else
2016-02-02 19:37:46 +00:00
operands . push_back ( accessChainLoad ( glslangOperands [ arg ] - > getAsTyped ( ) - > getType ( ) ) ) ;
2015-06-26 22:58:36 +00:00
}
2015-07-23 16:22:48 +00:00
if ( atomic ) {
// Handle all atomics
2016-07-26 18:50:38 +00:00
result = createAtomicOperation ( node - > getOp ( ) , precision , resultType ( ) , operands , node - > getBasicType ( ) ) ;
2015-07-23 16:22:48 +00:00
} else {
// Pass through to generic operations.
switch ( glslangOperands . size ( ) ) {
case 0 :
2016-07-26 18:50:38 +00:00
result = createNoArgOperation ( node - > getOp ( ) , precision , resultType ( ) ) ;
2015-07-23 16:22:48 +00:00
break ;
case 1 :
2016-05-06 21:25:16 +00:00
result = createUnaryOperation (
node - > getOp ( ) , precision ,
TranslateNoContractionDecoration ( node - > getType ( ) . getQualifier ( ) ) ,
2016-07-26 18:50:38 +00:00
resultType ( ) , operands . front ( ) ,
2016-05-06 21:25:16 +00:00
glslangOperands [ 0 ] - > getAsTyped ( ) - > getBasicType ( ) ) ;
2015-07-23 16:22:48 +00:00
break ;
default :
2016-07-26 18:50:38 +00:00
result = createMiscOperation ( node - > getOp ( ) , precision , resultType ( ) , operands , node - > getBasicType ( ) ) ;
2015-07-23 16:22:48 +00:00
break ;
}
2016-07-26 18:50:38 +00:00
if ( invertedType )
result = createInvertedSwizzle ( precision , * glslangOperands [ 0 ] - > getAsBinaryNode ( ) , result ) ;
2015-06-26 22:58:36 +00:00
}
if ( noReturnValue )
return false ;
if ( ! result ) {
2016-05-04 19:55:59 +00:00
logger - > missingFunctionality ( " unknown glslang aggregate " ) ;
2015-12-22 04:21:11 +00:00
return true ; // pick up a child as a placeholder operand
2015-06-26 22:58:36 +00:00
} else {
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( result ) ;
return false ;
}
}
bool TGlslangToSpvTraverser : : visitSelection ( glslang : : TVisit /* visit */ , glslang : : TIntermSelection * node )
{
// This path handles both if-then-else and ?:
// The if-then-else has a node type of void, while
// ?: has a non-void node type
spv : : Id result = 0 ;
if ( node - > getBasicType ( ) ! = glslang : : EbtVoid ) {
// don't handle this as just on-the-fly temporaries, because there will be two names
// and better to leave SSA to later passes
result = builder . createVariable ( spv : : StorageClassFunction , convertGlslangToSpvType ( node - > getType ( ) ) ) ;
}
// emit the condition before doing anything with selection
node - > getCondition ( ) - > traverse ( this ) ;
// make an "if" based on the value created by the condition
2016-02-02 19:37:46 +00:00
spv : : Builder : : If ifBuilder ( accessChainLoad ( node - > getCondition ( ) - > getType ( ) ) , builder ) ;
2015-06-26 22:58:36 +00:00
if ( node - > getTrueBlock ( ) ) {
// emit the "then" statement
node - > getTrueBlock ( ) - > traverse ( this ) ;
if ( result )
2016-02-02 19:37:46 +00:00
builder . createStore ( accessChainLoad ( node - > getTrueBlock ( ) - > getAsTyped ( ) - > getType ( ) ) , result ) ;
2015-06-26 22:58:36 +00:00
}
if ( node - > getFalseBlock ( ) ) {
ifBuilder . makeBeginElse ( ) ;
// emit the "else" statement
node - > getFalseBlock ( ) - > traverse ( this ) ;
if ( result )
2016-02-02 19:37:46 +00:00
builder . createStore ( accessChainLoad ( node - > getFalseBlock ( ) - > getAsTyped ( ) - > getType ( ) ) , result ) ;
2015-06-26 22:58:36 +00:00
}
ifBuilder . makeEndIf ( ) ;
if ( result ) {
// GLSL only has r-values as the result of a :?, but
// if we have an l-value, that can be more efficient if it will
// become the base of a complex r-value expression, because the
// next layer copies r-values into memory to use the access-chain mechanism
builder . clearAccessChain ( ) ;
builder . setAccessChainLValue ( result ) ;
}
return false ;
}
bool TGlslangToSpvTraverser : : visitSwitch ( glslang : : TVisit /* visit */ , glslang : : TIntermSwitch * node )
{
// emit and get the condition before doing anything with switch
node - > getCondition ( ) - > traverse ( this ) ;
2016-02-02 19:37:46 +00:00
spv : : Id selector = accessChainLoad ( node - > getCondition ( ) - > getAsTyped ( ) - > getType ( ) ) ;
2015-06-26 22:58:36 +00:00
// browse the children to sort out code segments
int defaultSegment = - 1 ;
std : : vector < TIntermNode * > codeSegments ;
glslang : : TIntermSequence & sequence = node - > getBody ( ) - > getSequence ( ) ;
std : : vector < int > caseValues ;
std : : vector < int > valueIndexToSegment ( sequence . size ( ) ) ; // note: probably not all are used, it is an overestimate
for ( glslang : : TIntermSequence : : iterator c = sequence . begin ( ) ; c ! = sequence . end ( ) ; + + c ) {
TIntermNode * child = * c ;
if ( child - > getAsBranchNode ( ) & & child - > getAsBranchNode ( ) - > getFlowOp ( ) = = glslang : : EOpDefault )
2015-07-12 09:32:58 +00:00
defaultSegment = ( int ) codeSegments . size ( ) ;
2015-06-26 22:58:36 +00:00
else if ( child - > getAsBranchNode ( ) & & child - > getAsBranchNode ( ) - > getFlowOp ( ) = = glslang : : EOpCase ) {
2015-07-12 09:32:58 +00:00
valueIndexToSegment [ caseValues . size ( ) ] = ( int ) codeSegments . size ( ) ;
2015-06-26 22:58:36 +00:00
caseValues . push_back ( child - > getAsBranchNode ( ) - > getExpression ( ) - > getAsConstantUnion ( ) - > getConstArray ( ) [ 0 ] . getIConst ( ) ) ;
} else
codeSegments . push_back ( child ) ;
}
2016-05-06 21:25:16 +00:00
// handle the case where the last code segment is missing, due to no code
2015-06-26 22:58:36 +00:00
// statements between the last case and the end of the switch statement
if ( ( caseValues . size ( ) & & ( int ) codeSegments . size ( ) = = valueIndexToSegment [ caseValues . size ( ) - 1 ] ) | |
( int ) codeSegments . size ( ) = = defaultSegment )
codeSegments . push_back ( nullptr ) ;
// make the switch statement
std : : vector < spv : : Block * > segmentBlocks ; // returned, as the blocks allocated in the call
2015-07-12 09:32:58 +00:00
builder . makeSwitch ( selector , ( int ) codeSegments . size ( ) , caseValues , valueIndexToSegment , defaultSegment , segmentBlocks ) ;
2015-06-26 22:58:36 +00:00
// emit all the code in the segments
breakForLoop . push ( false ) ;
for ( unsigned int s = 0 ; s < codeSegments . size ( ) ; + + s ) {
builder . nextSwitchSegment ( segmentBlocks , s ) ;
if ( codeSegments [ s ] )
codeSegments [ s ] - > traverse ( this ) ;
else
builder . addSwitchBreak ( ) ;
}
breakForLoop . pop ( ) ;
builder . endSwitch ( segmentBlocks ) ;
return false ;
}
void TGlslangToSpvTraverser : : visitConstantUnion ( glslang : : TIntermConstantUnion * node )
{
int nextConst = 0 ;
2016-03-21 13:51:37 +00:00
spv : : Id constant = createSpvConstantFromConstUnionArray ( node - > getType ( ) , node - > getConstArray ( ) , nextConst , false ) ;
2015-06-26 22:58:36 +00:00
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( constant ) ;
}
bool TGlslangToSpvTraverser : : visitLoop ( glslang : : TVisit /* visit */ , glslang : : TIntermLoop * node )
{
2016-01-10 17:15:13 +00:00
auto blocks = builder . makeNewLoop ( ) ;
2016-01-11 20:57:11 +00:00
builder . createBranch ( & blocks . head ) ;
2016-01-20 16:51:43 +00:00
// Spec requires back edges to target header blocks, and every header block
// must dominate its merge block. Make a header block first to ensure these
// conditions are met. By definition, it will contain OpLoopMerge, followed
// by a block-ending branch. But we don't want to put any other body/test
// instructions in it, since the body/test may have arbitrary instructions,
// including merges of its own.
builder . setBuildPoint ( & blocks . head ) ;
builder . createLoopMerge ( & blocks . merge , & blocks . continue_target , spv : : LoopControlMaskNone ) ;
2016-01-10 17:15:13 +00:00
if ( node - > testFirst ( ) & & node - > getTest ( ) ) {
2016-01-20 16:51:43 +00:00
spv : : Block & test = builder . makeNewBlock ( ) ;
builder . createBranch ( & test ) ;
builder . setBuildPoint ( & test ) ;
2015-06-26 22:58:36 +00:00
node - > getTest ( ) - > traverse ( this ) ;
2016-01-10 17:15:13 +00:00
spv : : Id condition =
2016-02-02 19:37:46 +00:00
accessChainLoad ( node - > getTest ( ) - > getType ( ) ) ;
2016-01-10 17:15:13 +00:00
builder . createConditionalBranch ( condition , & blocks . body , & blocks . merge ) ;
builder . setBuildPoint ( & blocks . body ) ;
2016-01-11 20:57:11 +00:00
breakForLoop . push ( true ) ;
2016-01-10 17:15:13 +00:00
if ( node - > getBody ( ) )
2016-01-11 00:37:00 +00:00
node - > getBody ( ) - > traverse ( this ) ;
2016-01-10 17:15:13 +00:00
builder . createBranch ( & blocks . continue_target ) ;
2016-01-11 19:48:36 +00:00
breakForLoop . pop ( ) ;
2016-01-10 17:15:13 +00:00
builder . setBuildPoint ( & blocks . continue_target ) ;
if ( node - > getTerminal ( ) )
node - > getTerminal ( ) - > traverse ( this ) ;
2016-01-11 20:57:11 +00:00
builder . createBranch ( & blocks . head ) ;
2015-07-15 20:21:26 +00:00
} else {
2016-01-10 17:15:13 +00:00
builder . createBranch ( & blocks . body ) ;
2016-01-11 19:48:36 +00:00
breakForLoop . push ( true ) ;
2016-01-10 17:15:13 +00:00
builder . setBuildPoint ( & blocks . body ) ;
if ( node - > getBody ( ) )
2016-01-11 00:37:00 +00:00
node - > getBody ( ) - > traverse ( this ) ;
2016-01-10 17:15:13 +00:00
builder . createBranch ( & blocks . continue_target ) ;
2016-01-11 19:48:36 +00:00
breakForLoop . pop ( ) ;
2016-01-10 17:15:13 +00:00
builder . setBuildPoint ( & blocks . continue_target ) ;
if ( node - > getTerminal ( ) )
node - > getTerminal ( ) - > traverse ( this ) ;
if ( node - > getTest ( ) ) {
node - > getTest ( ) - > traverse ( this ) ;
spv : : Id condition =
2016-02-02 19:37:46 +00:00
accessChainLoad ( node - > getTest ( ) - > getType ( ) ) ;
2016-01-11 20:57:11 +00:00
builder . createConditionalBranch ( condition , & blocks . head , & blocks . merge ) ;
2016-01-10 17:15:13 +00:00
} else {
2016-01-20 02:13:38 +00:00
// TODO: unless there was a break/return/discard instruction
// somewhere in the body, this is an infinite loop, so we should
// issue a warning.
2016-01-11 20:57:11 +00:00
builder . createBranch ( & blocks . head ) ;
2016-01-10 17:15:13 +00:00
}
2015-06-26 22:58:36 +00:00
}
2016-01-10 17:15:13 +00:00
builder . setBuildPoint ( & blocks . merge ) ;
2016-01-11 19:48:36 +00:00
builder . closeLoop ( ) ;
2015-06-26 22:58:36 +00:00
return false ;
}
bool TGlslangToSpvTraverser : : visitBranch ( glslang : : TVisit /* visit */ , glslang : : TIntermBranch * node )
{
if ( node - > getExpression ( ) )
node - > getExpression ( ) - > traverse ( this ) ;
switch ( node - > getFlowOp ( ) ) {
case glslang : : EOpKill :
builder . makeDiscard ( ) ;
break ;
case glslang : : EOpBreak :
if ( breakForLoop . top ( ) )
builder . createLoopExit ( ) ;
else
builder . addSwitchBreak ( ) ;
break ;
case glslang : : EOpContinue :
builder . createLoopContinue ( ) ;
break ;
case glslang : : EOpReturn :
2016-10-06 18:59:51 +00:00
if ( node - > getExpression ( ) ) {
const glslang : : TType & glslangReturnType = node - > getExpression ( ) - > getType ( ) ;
spv : : Id returnId = accessChainLoad ( glslangReturnType ) ;
if ( builder . getTypeId ( returnId ) ! = currentFunction - > getReturnType ( ) ) {
builder . clearAccessChain ( ) ;
spv : : Id copyId = builder . createVariable ( spv : : StorageClassFunction , currentFunction - > getReturnType ( ) ) ;
builder . setAccessChainLValue ( copyId ) ;
multiTypeStore ( glslangReturnType , returnId ) ;
returnId = builder . createLoad ( copyId ) ;
}
builder . makeReturn ( false , returnId ) ;
} else
2015-09-15 02:58:02 +00:00
builder . makeReturn ( false ) ;
2015-06-26 22:58:36 +00:00
builder . clearAccessChain ( ) ;
break ;
default :
2015-11-16 04:33:39 +00:00
assert ( 0 ) ;
2015-06-26 22:58:36 +00:00
break ;
}
return false ;
}
spv : : Id TGlslangToSpvTraverser : : createSpvVariable ( const glslang : : TIntermSymbol * node )
{
2016-05-06 21:25:16 +00:00
// First, steer off constants, which are not SPIR-V variables, but
2015-06-26 22:58:36 +00:00
// can still have a mapping to a SPIR-V Id.
2015-11-16 04:33:39 +00:00
// This includes specialization constants.
2016-03-20 06:46:02 +00:00
if ( node - > getQualifier ( ) . isConstant ( ) ) {
2016-03-21 13:51:37 +00:00
return createSpvConstant ( * node ) ;
2015-06-26 22:58:36 +00:00
}
// Now, handle actual variables
spv : : StorageClass storageClass = TranslateStorageClass ( node - > getType ( ) ) ;
spv : : Id spvType = convertGlslangToSpvType ( node - > getType ( ) ) ;
const char * name = node - > getName ( ) . c_str ( ) ;
if ( glslang : : IsAnonymous ( name ) )
name = " " ;
return builder . createVariable ( storageClass , spvType , name ) ;
}
// Return type Id of the sampled type.
spv : : Id TGlslangToSpvTraverser : : getSampledType ( const glslang : : TSampler & sampler )
{
switch ( sampler . type ) {
case glslang : : EbtFloat : return builder . makeFloatType ( 32 ) ;
case glslang : : EbtInt : return builder . makeIntType ( 32 ) ;
case glslang : : EbtUint : return builder . makeUintType ( 32 ) ;
default :
2015-11-16 04:33:39 +00:00
assert ( 0 ) ;
2015-06-26 22:58:36 +00:00
return builder . makeFloatType ( 32 ) ;
}
}
2016-07-26 18:50:38 +00:00
// If node is a swizzle operation, return the type that should be used if
// the swizzle base is first consumed by another operation, before the swizzle
// is applied.
spv : : Id TGlslangToSpvTraverser : : getInvertedSwizzleType ( const glslang : : TIntermTyped & node )
{
if ( node . getAsOperator ( ) & &
node . getAsOperator ( ) - > getOp ( ) = = glslang : : EOpVectorSwizzle )
return convertGlslangToSpvType ( node . getAsBinaryNode ( ) - > getLeft ( ) - > getType ( ) ) ;
else
return spv : : NoType ;
}
// When inverting a swizzle with a parent op, this function
// will apply the swizzle operation to a completed parent operation.
spv : : Id TGlslangToSpvTraverser : : createInvertedSwizzle ( spv : : Decoration precision , const glslang : : TIntermTyped & node , spv : : Id parentResult )
{
std : : vector < unsigned > swizzle ;
convertSwizzle ( * node . getAsBinaryNode ( ) - > getRight ( ) - > getAsAggregate ( ) , swizzle ) ;
return builder . createRvalueSwizzle ( precision , convertGlslangToSpvType ( node . getType ( ) ) , parentResult , swizzle ) ;
}
// Convert a glslang AST swizzle node to a swizzle vector for building SPIR-V.
void TGlslangToSpvTraverser : : convertSwizzle ( const glslang : : TIntermAggregate & node , std : : vector < unsigned > & swizzle )
{
const glslang : : TIntermSequence & swizzleSequence = node . getSequence ( ) ;
for ( int i = 0 ; i < ( int ) swizzleSequence . size ( ) ; + + i )
swizzle . push_back ( swizzleSequence [ i ] - > getAsConstantUnion ( ) - > getConstArray ( ) [ 0 ] . getIConst ( ) ) ;
}
2015-12-20 18:29:16 +00:00
// Convert from a glslang type to an SPV type, by calling into a
// recursive version of this function. This establishes the inherited
// layout state rooted from the top-level type.
2015-06-26 22:58:36 +00:00
spv : : Id TGlslangToSpvTraverser : : convertGlslangToSpvType ( const glslang : : TType & type )
2015-09-09 23:51:38 +00:00
{
2015-12-24 17:30:13 +00:00
return convertGlslangToSpvType ( type , getExplicitLayout ( type ) , type . getQualifier ( ) ) ;
2015-09-09 23:51:38 +00:00
}
// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
2016-01-22 01:56:57 +00:00
// explicitLayout can be kept the same throughout the hierarchical recursive walk.
2016-07-01 03:18:02 +00:00
// Mutually recursive with convertGlslangStructToSpvType().
2015-12-24 17:30:13 +00:00
spv : : Id TGlslangToSpvTraverser : : convertGlslangToSpvType ( const glslang : : TType & type , glslang : : TLayoutPacking explicitLayout , const glslang : : TQualifier & qualifier )
2015-06-26 22:58:36 +00:00
{
2015-12-24 17:30:13 +00:00
spv : : Id spvType = spv : : NoResult ;
2015-06-26 22:58:36 +00:00
switch ( type . getBasicType ( ) ) {
case glslang : : EbtVoid :
spvType = builder . makeVoidType ( ) ;
2015-11-16 04:33:39 +00:00
assert ( ! type . isArray ( ) ) ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EbtFloat :
spvType = builder . makeFloatType ( 32 ) ;
break ;
case glslang : : EbtDouble :
spvType = builder . makeFloatType ( 64 ) ;
break ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EbtFloat16 :
builder . addExtension ( spv : : E_SPV_AMD_gpu_shader_half_float ) ;
builder . addCapability ( spv : : CapabilityFloat16 ) ;
spvType = builder . makeFloatType ( 16 ) ;
break ;
# endif
2015-06-26 22:58:36 +00:00
case glslang : : EbtBool :
2016-02-09 04:38:15 +00:00
// "transparent" bool doesn't exist in SPIR-V. The GLSL convention is
// a 32-bit int where non-0 means true.
if ( explicitLayout ! = glslang : : ElpNone )
spvType = builder . makeUintType ( 32 ) ;
else
spvType = builder . makeBoolType ( ) ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EbtInt :
spvType = builder . makeIntType ( 32 ) ;
break ;
case glslang : : EbtUint :
spvType = builder . makeUintType ( 32 ) ;
break ;
2016-04-22 08:51:45 +00:00
case glslang : : EbtInt64 :
builder . addCapability ( spv : : CapabilityInt64 ) ;
spvType = builder . makeIntType ( 64 ) ;
break ;
case glslang : : EbtUint64 :
builder . addCapability ( spv : : CapabilityInt64 ) ;
spvType = builder . makeUintType ( 64 ) ;
break ;
2015-07-23 16:22:48 +00:00
case glslang : : EbtAtomicUint :
2016-07-07 19:20:00 +00:00
builder . addCapability ( spv : : CapabilityAtomicStorage ) ;
2015-07-23 16:22:48 +00:00
spvType = builder . makeUintType ( 32 ) ;
break ;
2015-06-26 22:58:36 +00:00
case glslang : : EbtSampler :
{
const glslang : : TSampler & sampler = type . getSampler ( ) ;
2016-02-16 03:58:50 +00:00
if ( sampler . sampler ) {
// pure sampler
spvType = builder . makeSamplerType ( ) ;
} else {
// an image is present, make its type
spvType = builder . makeImageType ( getSampledType ( sampler ) , TranslateDimensionality ( sampler ) , sampler . shadow , sampler . arrayed , sampler . ms ,
sampler . image ? 2 : 1 , TranslateImageFormat ( type ) ) ;
if ( sampler . combined ) {
// already has both image and sampler, make the combined type
spvType = builder . makeSampledImageType ( spvType ) ;
}
2015-11-16 04:33:39 +00:00
}
2015-12-24 17:30:13 +00:00
}
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EbtStruct :
case glslang : : EbtBlock :
{
// If we've seen this struct type, return it
2016-07-01 03:18:02 +00:00
const glslang : : TTypeList * glslangMembers = type . getStruct ( ) ;
2015-12-24 17:30:13 +00:00
// Try to share structs for different layouts, but not yet for other
// kinds of qualification (primarily not yet including interpolant qualification).
2016-09-01 23:05:23 +00:00
if ( ! HasNonLayoutQualifiers ( type , qualifier ) )
2016-07-01 03:18:02 +00:00
spvType = structMap [ explicitLayout ] [ qualifier . layoutMatrix ] [ glslangMembers ] ;
2015-12-24 17:30:13 +00:00
if ( spvType ! = spv : : NoResult )
2015-06-26 22:58:36 +00:00
break ;
// else, we haven't seen it...
if ( type . getBasicType ( ) = = glslang : : EbtBlock )
2016-07-01 03:18:02 +00:00
memberRemapper [ glslangMembers ] . resize ( glslangMembers - > size ( ) ) ;
spvType = convertGlslangStructToSpvType ( type , glslangMembers , explicitLayout , qualifier ) ;
2015-06-26 22:58:36 +00:00
}
break ;
default :
2015-11-16 04:33:39 +00:00
assert ( 0 ) ;
2015-06-26 22:58:36 +00:00
break ;
}
if ( type . isMatrix ( ) )
spvType = builder . makeMatrixType ( spvType , type . getMatrixCols ( ) , type . getMatrixRows ( ) ) ;
else {
// If this variable has a vector element count greater than 1, create a SPIR-V vector
if ( type . getVectorSize ( ) > 1 )
spvType = builder . makeVectorType ( spvType , type . getVectorSize ( ) ) ;
}
if ( type . isArray ( ) ) {
2015-12-30 04:27:24 +00:00
int stride = 0 ; // keep this 0 unless doing an explicit layout; 0 will mean no decoration, no stride
2015-09-12 18:17:44 +00:00
// Do all but the outer dimension
2015-12-30 04:27:24 +00:00
if ( type . getArraySizes ( ) - > getNumDims ( ) > 1 ) {
2016-01-05 02:22:56 +00:00
// We need to decorate array strides for types needing explicit layout, except blocks.
if ( explicitLayout ! = glslang : : ElpNone & & type . getBasicType ( ) ! = glslang : : EbtBlock ) {
2015-12-30 04:27:24 +00:00
// Use a dummy glslang type for querying internal strides of
// arrays of arrays, but using just a one-dimensional array.
glslang : : TType simpleArrayType ( type , 0 ) ; // deference type of the array
while ( simpleArrayType . getArraySizes ( ) . getNumDims ( ) > 1 )
simpleArrayType . getArraySizes ( ) . dereference ( ) ;
// Will compute the higher-order strides here, rather than making a whole
// pile of types and doing repetitive recursion on their contents.
stride = getArrayStride ( simpleArrayType , explicitLayout , qualifier . layoutMatrix ) ;
}
2016-01-05 02:22:56 +00:00
// make the arrays
2015-12-30 04:27:24 +00:00
for ( int dim = type . getArraySizes ( ) - > getNumDims ( ) - 1 ; dim > 0 ; - - dim ) {
2016-02-16 03:58:50 +00:00
spvType = builder . makeArrayType ( spvType , makeArraySizeId ( * type . getArraySizes ( ) , dim ) , stride ) ;
2015-12-30 04:27:24 +00:00
if ( stride > 0 )
builder . addDecoration ( spvType , spv : : DecorationArrayStride , stride ) ;
2016-02-16 03:58:50 +00:00
stride * = type . getArraySizes ( ) - > getDimSize ( dim ) ;
2015-12-30 04:27:24 +00:00
}
} else {
// single-dimensional array, and don't yet have stride
2016-01-05 02:22:56 +00:00
// We need to decorate array strides for types needing explicit layout, except blocks.
2015-12-30 04:27:24 +00:00
if ( explicitLayout ! = glslang : : ElpNone & & type . getBasicType ( ) ! = glslang : : EbtBlock )
stride = getArrayStride ( type , explicitLayout , qualifier . layoutMatrix ) ;
2015-09-12 18:17:44 +00:00
}
// Do the outer dimension, which might not be known for a runtime-sized array
if ( type . isRuntimeSizedArray ( ) ) {
spvType = builder . makeRuntimeArray ( spvType ) ;
} else {
assert ( type . getOuterArraySize ( ) > 0 ) ;
2016-02-16 03:58:50 +00:00
spvType = builder . makeArrayType ( spvType , makeArraySizeId ( * type . getArraySizes ( ) , 0 ) , stride ) ;
2015-09-12 18:17:44 +00:00
}
2015-12-30 04:27:24 +00:00
if ( stride > 0 )
builder . addDecoration ( spvType , spv : : DecorationArrayStride , stride ) ;
2015-06-26 22:58:36 +00:00
}
return spvType ;
}
2016-07-01 03:18:02 +00:00
// Do full recursive conversion of a glslang structure (or block) type to a SPIR-V Id.
// explicitLayout can be kept the same throughout the hierarchical recursive walk.
// Mutually recursive with convertGlslangToSpvType().
spv : : Id TGlslangToSpvTraverser : : convertGlslangStructToSpvType ( const glslang : : TType & type ,
const glslang : : TTypeList * glslangMembers ,
glslang : : TLayoutPacking explicitLayout ,
const glslang : : TQualifier & qualifier )
{
// Create a vector of struct types for SPIR-V to consume
std : : vector < spv : : Id > spvMembers ;
int memberDelta = 0 ; // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks
int locationOffset = 0 ; // for use across struct members, when they are called recursively
for ( int i = 0 ; i < ( int ) glslangMembers - > size ( ) ; i + + ) {
glslang : : TType & glslangMember = * ( * glslangMembers ) [ i ] . type ;
if ( glslangMember . hiddenMember ( ) ) {
+ + memberDelta ;
if ( type . getBasicType ( ) = = glslang : : EbtBlock )
memberRemapper [ glslangMembers ] [ i ] = - 1 ;
} else {
if ( type . getBasicType ( ) = = glslang : : EbtBlock )
memberRemapper [ glslangMembers ] [ i ] = i - memberDelta ;
// modify just this child's view of the qualifier
glslang : : TQualifier memberQualifier = glslangMember . getQualifier ( ) ;
InheritQualifiers ( memberQualifier , qualifier ) ;
// manually inherit location; it's more complex
if ( ! memberQualifier . hasLocation ( ) & & qualifier . hasLocation ( ) )
memberQualifier . layoutLocation = qualifier . layoutLocation + locationOffset ;
if ( qualifier . hasLocation ( ) )
locationOffset + = glslangIntermediate - > computeTypeLocationSize ( glslangMember ) ;
// recurse
spvMembers . push_back ( convertGlslangToSpvType ( glslangMember , explicitLayout , memberQualifier ) ) ;
}
}
// Make the SPIR-V type
spv : : Id spvType = builder . makeStructType ( spvMembers , type . getTypeName ( ) . c_str ( ) ) ;
2016-09-01 23:05:23 +00:00
if ( ! HasNonLayoutQualifiers ( type , qualifier ) )
2016-07-01 03:18:02 +00:00
structMap [ explicitLayout ] [ qualifier . layoutMatrix ] [ glslangMembers ] = spvType ;
// Decorate it
decorateStructType ( type , glslangMembers , explicitLayout , qualifier , spvType ) ;
return spvType ;
}
void TGlslangToSpvTraverser : : decorateStructType ( const glslang : : TType & type ,
const glslang : : TTypeList * glslangMembers ,
glslang : : TLayoutPacking explicitLayout ,
const glslang : : TQualifier & qualifier ,
spv : : Id spvType )
{
// Name and decorate the non-hidden members
int offset = - 1 ;
int locationOffset = 0 ; // for use within the members of this struct
for ( int i = 0 ; i < ( int ) glslangMembers - > size ( ) ; i + + ) {
glslang : : TType & glslangMember = * ( * glslangMembers ) [ i ] . type ;
int member = i ;
if ( type . getBasicType ( ) = = glslang : : EbtBlock )
member = memberRemapper [ glslangMembers ] [ i ] ;
// modify just this child's view of the qualifier
glslang : : TQualifier memberQualifier = glslangMember . getQualifier ( ) ;
InheritQualifiers ( memberQualifier , qualifier ) ;
// using -1 above to indicate a hidden member
if ( member > = 0 ) {
builder . addMemberName ( spvType , member , glslangMember . getFieldName ( ) . c_str ( ) ) ;
addMemberDecoration ( spvType , member , TranslateLayoutDecoration ( glslangMember , memberQualifier . layoutMatrix ) ) ;
addMemberDecoration ( spvType , member , TranslatePrecisionDecoration ( glslangMember ) ) ;
// Add interpolation and auxiliary storage decorations only to top-level members of Input and Output storage classes
if ( type . getQualifier ( ) . storage = = glslang : : EvqVaryingIn | | type . getQualifier ( ) . storage = = glslang : : EvqVaryingOut ) {
if ( type . getBasicType ( ) = = glslang : : EbtBlock ) {
addMemberDecoration ( spvType , member , TranslateInterpolationDecoration ( memberQualifier ) ) ;
addMemberDecoration ( spvType , member , TranslateAuxiliaryStorageDecoration ( memberQualifier ) ) ;
}
}
addMemberDecoration ( spvType , member , TranslateInvariantDecoration ( memberQualifier ) ) ;
if ( qualifier . storage = = glslang : : EvqBuffer ) {
std : : vector < spv : : Decoration > memory ;
TranslateMemoryDecoration ( memberQualifier , memory ) ;
for ( unsigned int i = 0 ; i < memory . size ( ) ; + + i )
addMemberDecoration ( spvType , member , memory [ i ] ) ;
}
2016-07-01 03:47:35 +00:00
// Compute location decoration; tricky based on whether inheritance is at play and
// what kind of container we have, etc.
2016-07-01 03:18:02 +00:00
// TODO: This algorithm (and it's cousin above doing almost the same thing) should
// probably move to the linker stage of the front end proper, and just have the
// answer sitting already distributed throughout the individual member locations.
int location = - 1 ; // will only decorate if present or inherited
2016-07-01 03:47:35 +00:00
// Ignore member locations if the container is an array, as that's
// ill-specified and decisions have been made to not allow this anyway.
// The object itself must have a location, and that comes out from decorating the object,
// not the type (this code decorates types).
if ( ! type . isArray ( ) ) {
if ( memberQualifier . hasLocation ( ) ) { // no inheritance, or override of inheritance
// struct members should not have explicit locations
assert ( type . getBasicType ( ) ! = glslang : : EbtStruct ) ;
location = memberQualifier . layoutLocation ;
} else if ( type . getBasicType ( ) ! = glslang : : EbtBlock ) {
// If it is a not a Block, (...) Its members are assigned consecutive locations (...)
// The members, and their nested types, must not themselves have Location decorations.
} else if ( qualifier . hasLocation ( ) ) // inheritance
location = qualifier . layoutLocation + locationOffset ;
}
2016-07-01 03:18:02 +00:00
if ( location > = 0 )
builder . addMemberDecoration ( spvType , member , spv : : DecorationLocation , location ) ;
2016-07-01 03:47:35 +00:00
if ( qualifier . hasLocation ( ) ) // track for upcoming inheritance
locationOffset + = glslangIntermediate - > computeTypeLocationSize ( glslangMember ) ;
2016-07-01 03:18:02 +00:00
// component, XFB, others
if ( glslangMember . getQualifier ( ) . hasComponent ( ) )
builder . addMemberDecoration ( spvType , member , spv : : DecorationComponent , glslangMember . getQualifier ( ) . layoutComponent ) ;
if ( glslangMember . getQualifier ( ) . hasXfbOffset ( ) )
builder . addMemberDecoration ( spvType , member , spv : : DecorationOffset , glslangMember . getQualifier ( ) . layoutXfbOffset ) ;
else if ( explicitLayout ! = glslang : : ElpNone ) {
// figure out what to do with offset, which is accumulating
int nextOffset ;
updateMemberOffset ( type , glslangMember , offset , nextOffset , explicitLayout , memberQualifier . layoutMatrix ) ;
if ( offset > = 0 )
builder . addMemberDecoration ( spvType , member , spv : : DecorationOffset , offset ) ;
offset = nextOffset ;
}
if ( glslangMember . isMatrix ( ) & & explicitLayout ! = glslang : : ElpNone )
builder . addMemberDecoration ( spvType , member , spv : : DecorationMatrixStride , getMatrixStride ( glslangMember , explicitLayout , memberQualifier . layoutMatrix ) ) ;
// built-in variable decorations
spv : : BuiltIn builtIn = TranslateBuiltInDecoration ( glslangMember . getQualifier ( ) . builtIn , true ) ;
2016-07-15 17:53:56 +00:00
if ( builtIn ! = spv : : BuiltInMax )
2016-07-01 03:18:02 +00:00
addMemberDecoration ( spvType , member , spv : : DecorationBuiltIn , ( int ) builtIn ) ;
}
}
// Decorate the structure
addDecoration ( spvType , TranslateLayoutDecoration ( type , qualifier . layoutMatrix ) ) ;
addDecoration ( spvType , TranslateBlockDecoration ( type ) ) ;
if ( type . getQualifier ( ) . hasStream ( ) & & glslangIntermediate - > isMultiStream ( ) ) {
builder . addCapability ( spv : : CapabilityGeometryStreams ) ;
builder . addDecoration ( spvType , spv : : DecorationStream , type . getQualifier ( ) . layoutStream ) ;
}
if ( glslangIntermediate - > getXfbMode ( ) ) {
builder . addCapability ( spv : : CapabilityTransformFeedback ) ;
if ( type . getQualifier ( ) . hasXfbStride ( ) )
builder . addDecoration ( spvType , spv : : DecorationXfbStride , type . getQualifier ( ) . layoutXfbStride ) ;
if ( type . getQualifier ( ) . hasXfbBuffer ( ) )
builder . addDecoration ( spvType , spv : : DecorationXfbBuffer , type . getQualifier ( ) . layoutXfbBuffer ) ;
}
}
2016-02-16 03:58:50 +00:00
// Turn the expression forming the array size into an id.
// This is not quite trivial, because of specialization constants.
// Sometimes, a raw constant is turned into an Id, and sometimes
// a specialization constant expression is.
spv : : Id TGlslangToSpvTraverser : : makeArraySizeId ( const glslang : : TArraySizes & arraySizes , int dim )
{
// First, see if this is sized with a node, meaning a specialization constant:
glslang : : TIntermTyped * specNode = arraySizes . getDimNode ( dim ) ;
if ( specNode ! = nullptr ) {
builder . clearAccessChain ( ) ;
specNode - > traverse ( this ) ;
return accessChainLoad ( specNode - > getAsTyped ( ) - > getType ( ) ) ;
}
2016-05-06 21:25:16 +00:00
2016-02-16 03:58:50 +00:00
// Otherwise, need a compile-time (front end) size, get it:
int size = arraySizes . getDimSize ( dim ) ;
assert ( size > 0 ) ;
return builder . makeUintConstant ( size ) ;
}
2016-02-09 04:38:15 +00:00
// Wrap the builder's accessChainLoad to:
// - localize handling of RelaxedPrecision
// - use the SPIR-V inferred type instead of another conversion of the glslang type
// (avoids unnecessary work and possible type punning for structures)
// - do conversion of concrete to abstract type
2016-02-02 19:37:46 +00:00
spv : : Id TGlslangToSpvTraverser : : accessChainLoad ( const glslang : : TType & type )
{
2016-02-09 04:38:15 +00:00
spv : : Id nominalTypeId = builder . accessChainGetInferredType ( ) ;
spv : : Id loadedId = builder . accessChainLoad ( TranslatePrecisionDecoration ( type ) , nominalTypeId ) ;
// Need to convert to abstract types when necessary
2016-02-23 09:51:09 +00:00
if ( type . getBasicType ( ) = = glslang : : EbtBool ) {
if ( builder . isScalarType ( nominalTypeId ) ) {
// Conversion for bool
spv : : Id boolType = builder . makeBoolType ( ) ;
if ( nominalTypeId ! = boolType )
loadedId = builder . createBinOp ( spv : : OpINotEqual , boolType , loadedId , builder . makeUintConstant ( 0 ) ) ;
} else if ( builder . isVectorType ( nominalTypeId ) ) {
// Conversion for bvec
int vecSize = builder . getNumTypeComponents ( nominalTypeId ) ;
spv : : Id bvecType = builder . makeVectorType ( builder . makeBoolType ( ) , vecSize ) ;
if ( nominalTypeId ! = bvecType )
loadedId = builder . createBinOp ( spv : : OpINotEqual , bvecType , loadedId , makeSmearedConstant ( builder . makeUintConstant ( 0 ) , vecSize ) ) ;
}
}
2016-02-09 04:38:15 +00:00
return loadedId ;
2016-02-02 19:37:46 +00:00
}
2016-02-23 09:51:09 +00:00
// Wrap the builder's accessChainStore to:
// - do conversion of concrete to abstract type
2016-09-02 17:20:21 +00:00
//
// Implicitly uses the existing builder.accessChain as the storage target.
2016-02-23 09:51:09 +00:00
void TGlslangToSpvTraverser : : accessChainStore ( const glslang : : TType & type , spv : : Id rvalue )
{
// Need to convert to abstract types when necessary
if ( type . getBasicType ( ) = = glslang : : EbtBool ) {
spv : : Id nominalTypeId = builder . accessChainGetInferredType ( ) ;
if ( builder . isScalarType ( nominalTypeId ) ) {
// Conversion for bool
spv : : Id boolType = builder . makeBoolType ( ) ;
if ( nominalTypeId ! = boolType ) {
spv : : Id zero = builder . makeUintConstant ( 0 ) ;
spv : : Id one = builder . makeUintConstant ( 1 ) ;
rvalue = builder . createTriOp ( spv : : OpSelect , nominalTypeId , rvalue , one , zero ) ;
}
} else if ( builder . isVectorType ( nominalTypeId ) ) {
// Conversion for bvec
int vecSize = builder . getNumTypeComponents ( nominalTypeId ) ;
spv : : Id bvecType = builder . makeVectorType ( builder . makeBoolType ( ) , vecSize ) ;
if ( nominalTypeId ! = bvecType ) {
spv : : Id zero = makeSmearedConstant ( builder . makeUintConstant ( 0 ) , vecSize ) ;
spv : : Id one = makeSmearedConstant ( builder . makeUintConstant ( 1 ) , vecSize ) ;
rvalue = builder . createTriOp ( spv : : OpSelect , nominalTypeId , rvalue , one , zero ) ;
}
}
}
builder . accessChainStore ( rvalue ) ;
}
2016-09-02 17:20:21 +00:00
// For storing when types match at the glslang level, but not might match at the
// SPIR-V level.
//
// This especially happens when a single glslang type expands to multiple
2016-10-06 18:59:51 +00:00
// SPIR-V types, like a struct that is used in a member-undecorated way as well
2016-09-02 17:20:21 +00:00
// as in a member-decorated way.
//
// NOTE: This function can handle any store request; if it's not special it
// simplifies to a simple OpStore.
//
// Implicitly uses the existing builder.accessChain as the storage target.
void TGlslangToSpvTraverser : : multiTypeStore ( const glslang : : TType & type , spv : : Id rValue )
{
2016-09-11 18:33:43 +00:00
// we only do the complex path here if it's an aggregate
if ( ! type . isStruct ( ) & & ! type . isArray ( ) ) {
2016-09-02 17:20:21 +00:00
accessChainStore ( type , rValue ) ;
return ;
}
2016-09-11 18:33:43 +00:00
// and, it has to be a case of type aliasing
2016-09-02 17:20:21 +00:00
spv : : Id rType = builder . getTypeId ( rValue ) ;
spv : : Id lValue = builder . accessChainGetLValue ( ) ;
spv : : Id lType = builder . getContainedTypeId ( builder . getTypeId ( lValue ) ) ;
if ( lType = = rType ) {
accessChainStore ( type , rValue ) ;
return ;
}
2016-09-11 18:33:43 +00:00
// Recursively (as needed) copy an aggregate type to a different aggregate type,
2016-09-02 17:20:21 +00:00
// where the two types were the same type in GLSL. This requires member
// by member copy, recursively.
2016-09-11 18:33:43 +00:00
// If an array, copy element by element.
if ( type . isArray ( ) ) {
glslang : : TType glslangElementType ( type , 0 ) ;
spv : : Id elementRType = builder . getContainedTypeId ( rType ) ;
for ( int index = 0 ; index < type . getOuterArraySize ( ) ; + + index ) {
// get the source member
spv : : Id elementRValue = builder . createCompositeExtract ( rValue , elementRType , index ) ;
2016-09-02 17:20:21 +00:00
2016-09-11 18:33:43 +00:00
// set up the target storage
builder . clearAccessChain ( ) ;
builder . setAccessChainLValue ( lValue ) ;
builder . accessChainPush ( builder . makeIntConstant ( index ) ) ;
2016-09-02 17:20:21 +00:00
2016-09-11 18:33:43 +00:00
// store the member
multiTypeStore ( glslangElementType , elementRValue ) ;
}
} else {
assert ( type . isStruct ( ) ) ;
2016-09-02 17:20:21 +00:00
2016-09-11 18:33:43 +00:00
// loop over structure members
const glslang : : TTypeList & members = * type . getStruct ( ) ;
for ( int m = 0 ; m < ( int ) members . size ( ) ; + + m ) {
const glslang : : TType & glslangMemberType = * members [ m ] . type ;
// get the source member
spv : : Id memberRType = builder . getContainedTypeId ( rType , m ) ;
spv : : Id memberRValue = builder . createCompositeExtract ( rValue , memberRType , m ) ;
// set up the target storage
builder . clearAccessChain ( ) ;
builder . setAccessChainLValue ( lValue ) ;
builder . accessChainPush ( builder . makeIntConstant ( m ) ) ;
// store the member
multiTypeStore ( glslangMemberType , memberRValue ) ;
}
2016-09-02 17:20:21 +00:00
}
}
2015-12-19 20:57:10 +00:00
// Decide whether or not this type should be
// decorated with offsets and strides, and if so
// whether std140 or std430 rules should be applied.
glslang : : TLayoutPacking TGlslangToSpvTraverser : : getExplicitLayout ( const glslang : : TType & type ) const
2015-09-09 23:51:38 +00:00
{
2015-12-19 20:57:10 +00:00
// has to be a block
if ( type . getBasicType ( ) ! = glslang : : EbtBlock )
return glslang : : ElpNone ;
// has to be a uniform or buffer block
if ( type . getQualifier ( ) . storage ! = glslang : : EvqUniform & &
type . getQualifier ( ) . storage ! = glslang : : EvqBuffer )
return glslang : : ElpNone ;
// return the layout to use
switch ( type . getQualifier ( ) . layoutPacking ) {
case glslang : : ElpStd140 :
case glslang : : ElpStd430 :
return type . getQualifier ( ) . layoutPacking ;
default :
return glslang : : ElpNone ;
}
2015-09-09 23:51:38 +00:00
}
2015-09-05 16:50:58 +00:00
// Given an array type, returns the integer stride required for that array
2015-12-20 18:29:16 +00:00
int TGlslangToSpvTraverser : : getArrayStride ( const glslang : : TType & arrayType , glslang : : TLayoutPacking explicitLayout , glslang : : TLayoutMatrix matrixLayout )
2015-09-05 16:50:58 +00:00
{
int size ;
2015-12-30 00:11:44 +00:00
int stride ;
glslangIntermediate - > getBaseAlignment ( arrayType , size , stride , explicitLayout = = glslang : : ElpStd140 , matrixLayout = = glslang : : ElmRowMajor ) ;
2015-12-07 02:17:49 +00:00
return stride ;
2015-09-05 16:50:58 +00:00
}
2015-12-30 00:11:44 +00:00
// Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix
2015-09-05 16:50:58 +00:00
// when used as a member of an interface block
2015-12-20 18:29:16 +00:00
int TGlslangToSpvTraverser : : getMatrixStride ( const glslang : : TType & matrixType , glslang : : TLayoutPacking explicitLayout , glslang : : TLayoutMatrix matrixLayout )
2015-09-05 16:50:58 +00:00
{
2015-12-30 00:11:44 +00:00
glslang : : TType elementType ;
elementType . shallowCopy ( matrixType ) ;
elementType . clearArraySizes ( ) ;
2015-09-05 16:50:58 +00:00
int size ;
2015-12-30 00:11:44 +00:00
int stride ;
glslangIntermediate - > getBaseAlignment ( elementType , size , stride , explicitLayout = = glslang : : ElpStd140 , matrixLayout = = glslang : : ElmRowMajor ) ;
return stride ;
2015-09-05 16:50:58 +00:00
}
2015-08-07 04:53:06 +00:00
// Given a member type of a struct, realign the current offset for it, and compute
// the next (not yet aligned) offset for the next member, which will get aligned
// on the next call.
// 'currentOffset' should be passed in already initialized, ready to modify, and reflecting
// the migration of data from nextOffset -> currentOffset. It should be -1 on the first call.
// -1 means a non-forced member offset (no decoration needed).
2016-02-16 03:58:50 +00:00
void TGlslangToSpvTraverser : : updateMemberOffset ( const glslang : : TType & /*structType*/ , const glslang : : TType & memberType , int & currentOffset , int & nextOffset ,
2015-12-20 18:29:16 +00:00
glslang : : TLayoutPacking explicitLayout , glslang : : TLayoutMatrix matrixLayout )
2015-08-07 04:53:06 +00:00
{
// this will get a positive value when deemed necessary
nextOffset = - 1 ;
// override anything in currentOffset with user-set offset
if ( memberType . getQualifier ( ) . hasOffset ( ) )
currentOffset = memberType . getQualifier ( ) . layoutOffset ;
// It could be that current linker usage in glslang updated all the layoutOffset,
// in which case the following code does not matter. But, that's not quite right
// once cross-compilation unit GLSL validation is done, as the original user
// settings are needed in layoutOffset, and then the following will come into play.
2015-12-19 20:57:10 +00:00
if ( explicitLayout = = glslang : : ElpNone ) {
2015-08-07 04:53:06 +00:00
if ( ! memberType . getQualifier ( ) . hasOffset ( ) )
currentOffset = - 1 ;
return ;
}
2015-12-19 20:57:10 +00:00
// Getting this far means we need explicit offsets
2015-08-07 04:53:06 +00:00
if ( currentOffset < 0 )
currentOffset = 0 ;
2016-05-06 21:25:16 +00:00
2015-08-07 04:53:06 +00:00
// Now, currentOffset is valid (either 0, or from a previous nextOffset),
// but possibly not yet correctly aligned.
int memberSize ;
2015-12-30 00:11:44 +00:00
int dummyStride ;
int memberAlignment = glslangIntermediate - > getBaseAlignment ( memberType , memberSize , dummyStride , explicitLayout = = glslang : : ElpStd140 , matrixLayout = = glslang : : ElmRowMajor ) ;
2015-08-07 04:53:06 +00:00
glslang : : RoundToPow2 ( currentOffset , memberAlignment ) ;
nextOffset = currentOffset + memberSize ;
}
2016-06-08 13:11:40 +00:00
void TGlslangToSpvTraverser : : declareUseOfStructMember ( const glslang : : TTypeList & members , int glslangMember )
2016-05-17 01:22:05 +00:00
{
2016-06-08 13:11:40 +00:00
const glslang : : TBuiltInVariable glslangBuiltIn = members [ glslangMember ] . type - > getQualifier ( ) . builtIn ;
switch ( glslangBuiltIn )
{
case glslang : : EbvClipDistance :
case glslang : : EbvCullDistance :
case glslang : : EbvPointSize :
// Generate the associated capability. Delegate to TranslateBuiltInDecoration.
// Alternately, we could just call this for any glslang built-in, since the
// capability already guards against duplicates.
TranslateBuiltInDecoration ( glslangBuiltIn , false ) ;
break ;
default :
// Capabilities were already generated when the struct was declared.
break ;
}
2016-05-17 01:22:05 +00:00
}
2016-09-19 22:01:41 +00:00
bool TGlslangToSpvTraverser : : isShaderEntryPoint ( const glslang : : TIntermAggregate * node )
2015-06-26 22:58:36 +00:00
{
2016-09-20 00:09:30 +00:00
return node - > getName ( ) . compare ( glslangIntermediate - > getEntryPointMangledName ( ) . c_str ( ) ) = = 0 ;
2015-06-26 22:58:36 +00:00
}
// Make all the functions, skeletally, without actually visiting their bodies.
void TGlslangToSpvTraverser : : makeFunctions ( const glslang : : TIntermSequence & glslFunctions )
{
for ( int f = 0 ; f < ( int ) glslFunctions . size ( ) ; + + f ) {
glslang : : TIntermAggregate * glslFunction = glslFunctions [ f ] - > getAsAggregate ( ) ;
2016-09-19 22:01:41 +00:00
if ( ! glslFunction | | glslFunction - > getOp ( ) ! = glslang : : EOpFunction | | isShaderEntryPoint ( glslFunction ) )
2015-06-26 22:58:36 +00:00
continue ;
// We're on a user function. Set up the basic interface for the function now,
2016-09-02 17:20:21 +00:00
// so that it's available to call. Translating the body will happen later.
2015-06-26 22:58:36 +00:00
//
2016-05-06 21:25:16 +00:00
// Typically (except for a "const in" parameter), an address will be passed to the
2015-06-26 22:58:36 +00:00
// function. What it is an address of varies:
//
2016-09-02 17:20:21 +00:00
// - "in" parameters not marked as "const" can be written to without modifying the calling
// argument so that write needs to be to a copy, hence the address of a copy works.
2015-06-26 22:58:36 +00:00
//
// - "const in" parameters can just be the r-value, as no writes need occur.
//
2016-09-02 17:20:21 +00:00
// - "out" and "inout" arguments can't be done as pointers to the calling argument, because
// GLSL has copy-in/copy-out semantics. They can be handled though with a pointer to a copy.
2015-06-26 22:58:36 +00:00
std : : vector < spv : : Id > paramTypes ;
2016-02-02 19:37:46 +00:00
std : : vector < spv : : Decoration > paramPrecisions ;
2015-06-26 22:58:36 +00:00
glslang : : TIntermSequence & parameters = glslFunction - > getSequence ( ) [ 0 ] - > getAsAggregate ( ) - > getSequence ( ) ;
for ( int p = 0 ; p < ( int ) parameters . size ( ) ; + + p ) {
const glslang : : TType & paramType = parameters [ p ] - > getAsTyped ( ) - > getType ( ) ;
spv : : Id typeId = convertGlslangToSpvType ( paramType ) ;
2016-06-08 20:54:48 +00:00
if ( paramType . isOpaque ( ) )
typeId = builder . makePointer ( TranslateStorageClass ( paramType ) , typeId ) ;
else if ( paramType . getQualifier ( ) . storage ! = glslang : : EvqConstReadOnly )
2015-06-26 22:58:36 +00:00
typeId = builder . makePointer ( spv : : StorageClassFunction , typeId ) ;
else
2016-09-02 17:20:21 +00:00
rValueParameters . insert ( parameters [ p ] - > getAsSymbolNode ( ) - > getId ( ) ) ;
2016-02-02 19:37:46 +00:00
paramPrecisions . push_back ( TranslatePrecisionDecoration ( paramType ) ) ;
2015-06-26 22:58:36 +00:00
paramTypes . push_back ( typeId ) ;
}
spv : : Block * functionBlock ;
2016-02-02 19:37:46 +00:00
spv : : Function * function = builder . makeFunctionEntry ( TranslatePrecisionDecoration ( glslFunction - > getType ( ) ) ,
convertGlslangToSpvType ( glslFunction - > getType ( ) ) ,
glslFunction - > getName ( ) . c_str ( ) , paramTypes , paramPrecisions , & functionBlock ) ;
2015-06-26 22:58:36 +00:00
// Track function to emit/call later
functionMap [ glslFunction - > getName ( ) . c_str ( ) ] = function ;
// Set the parameter id's
for ( int p = 0 ; p < ( int ) parameters . size ( ) ; + + p ) {
symbolValues [ parameters [ p ] - > getAsSymbolNode ( ) - > getId ( ) ] = function - > getParamId ( p ) ;
// give a name too
builder . addName ( function - > getParamId ( p ) , parameters [ p ] - > getAsSymbolNode ( ) - > getName ( ) . c_str ( ) ) ;
}
}
}
// Process all the initializers, while skipping the functions and link objects
void TGlslangToSpvTraverser : : makeGlobalInitializers ( const glslang : : TIntermSequence & initializers )
{
builder . setBuildPoint ( shaderEntry - > getLastBlock ( ) ) ;
for ( int i = 0 ; i < ( int ) initializers . size ( ) ; + + i ) {
glslang : : TIntermAggregate * initializer = initializers [ i ] - > getAsAggregate ( ) ;
if ( initializer & & initializer - > getOp ( ) ! = glslang : : EOpFunction & & initializer - > getOp ( ) ! = glslang : : EOpLinkerObjects ) {
// We're on a top-level node that's not a function. Treat as an initializer, whose
2016-09-19 22:01:41 +00:00
// code goes into the beginning of the entry point.
2015-06-26 22:58:36 +00:00
initializer - > traverse ( this ) ;
}
}
}
// Process all the functions, while skipping initializers.
void TGlslangToSpvTraverser : : visitFunctions ( const glslang : : TIntermSequence & glslFunctions )
{
for ( int f = 0 ; f < ( int ) glslFunctions . size ( ) ; + + f ) {
glslang : : TIntermAggregate * node = glslFunctions [ f ] - > getAsAggregate ( ) ;
2016-12-09 04:01:59 +00:00
if ( node & & ( node - > getOp ( ) = = glslang : : EOpFunction | | node - > getOp ( ) = = glslang : : EOpLinkerObjects ) )
2015-06-26 22:58:36 +00:00
node - > traverse ( this ) ;
}
}
void TGlslangToSpvTraverser : : handleFunctionEntry ( const glslang : : TIntermAggregate * node )
{
2016-05-06 21:25:16 +00:00
// SPIR-V functions should already be in the functionMap from the prepass
2015-06-26 22:58:36 +00:00
// that called makeFunctions().
2016-10-06 18:59:51 +00:00
currentFunction = functionMap [ node - > getName ( ) . c_str ( ) ] ;
spv : : Block * functionBlock = currentFunction - > getEntryBlock ( ) ;
2015-06-26 22:58:36 +00:00
builder . setBuildPoint ( functionBlock ) ;
}
2015-09-16 03:44:02 +00:00
void TGlslangToSpvTraverser : : translateArguments ( const glslang : : TIntermAggregate & node , std : : vector < spv : : Id > & arguments )
2015-06-26 22:58:36 +00:00
{
2015-09-09 08:42:49 +00:00
const glslang : : TIntermSequence & glslangArguments = node . getSequence ( ) ;
2015-12-31 08:11:41 +00:00
glslang : : TSampler sampler = { } ;
bool cubeCompare = false ;
2016-02-19 14:24:03 +00:00
if ( node . isTexture ( ) | | node . isImage ( ) ) {
2015-12-31 08:11:41 +00:00
sampler = glslangArguments [ 0 ] - > getAsTyped ( ) - > getType ( ) . getSampler ( ) ;
cubeCompare = sampler . dim = = glslang : : EsdCube & & sampler . arrayed & & sampler . shadow ;
}
2015-06-26 22:58:36 +00:00
for ( int i = 0 ; i < ( int ) glslangArguments . size ( ) ; + + i ) {
builder . clearAccessChain ( ) ;
glslangArguments [ i ] - > traverse ( this ) ;
2015-09-09 08:42:49 +00:00
// Special case l-value operands
bool lvalue = false ;
switch ( node . getOp ( ) ) {
case glslang : : EOpImageAtomicAdd :
case glslang : : EOpImageAtomicMin :
case glslang : : EOpImageAtomicMax :
case glslang : : EOpImageAtomicAnd :
case glslang : : EOpImageAtomicOr :
case glslang : : EOpImageAtomicXor :
case glslang : : EOpImageAtomicExchange :
case glslang : : EOpImageAtomicCompSwap :
if ( i = = 0 )
lvalue = true ;
break ;
2016-02-19 14:24:03 +00:00
case glslang : : EOpSparseImageLoad :
if ( ( sampler . ms & & i = = 3 ) | | ( ! sampler . ms & & i = = 2 ) )
lvalue = true ;
break ;
2015-12-31 08:11:41 +00:00
case glslang : : EOpSparseTexture :
if ( ( cubeCompare & & i = = 3 ) | | ( ! cubeCompare & & i = = 2 ) )
lvalue = true ;
break ;
case glslang : : EOpSparseTextureClamp :
if ( ( cubeCompare & & i = = 4 ) | | ( ! cubeCompare & & i = = 3 ) )
lvalue = true ;
break ;
case glslang : : EOpSparseTextureLod :
case glslang : : EOpSparseTextureOffset :
if ( i = = 3 )
lvalue = true ;
break ;
case glslang : : EOpSparseTextureFetch :
if ( ( sampler . dim ! = glslang : : EsdRect & & i = = 3 ) | | ( sampler . dim = = glslang : : EsdRect & & i = = 2 ) )
lvalue = true ;
break ;
case glslang : : EOpSparseTextureFetchOffset :
if ( ( sampler . dim ! = glslang : : EsdRect & & i = = 4 ) | | ( sampler . dim = = glslang : : EsdRect & & i = = 3 ) )
lvalue = true ;
break ;
case glslang : : EOpSparseTextureLodOffset :
case glslang : : EOpSparseTextureGrad :
case glslang : : EOpSparseTextureOffsetClamp :
if ( i = = 4 )
lvalue = true ;
break ;
case glslang : : EOpSparseTextureGradOffset :
case glslang : : EOpSparseTextureGradClamp :
if ( i = = 5 )
lvalue = true ;
break ;
case glslang : : EOpSparseTextureGradOffsetClamp :
if ( i = = 6 )
lvalue = true ;
break ;
case glslang : : EOpSparseTextureGather :
if ( ( sampler . shadow & & i = = 3 ) | | ( ! sampler . shadow & & i = = 2 ) )
lvalue = true ;
break ;
case glslang : : EOpSparseTextureGatherOffset :
case glslang : : EOpSparseTextureGatherOffsets :
if ( ( sampler . shadow & & i = = 4 ) | | ( ! sampler . shadow & & i = = 3 ) )
lvalue = true ;
break ;
2015-09-09 08:42:49 +00:00
default :
break ;
}
2015-09-16 09:48:22 +00:00
if ( lvalue )
2015-09-09 08:42:49 +00:00
arguments . push_back ( builder . accessChainGetLValue ( ) ) ;
2015-09-16 09:48:22 +00:00
else
2016-02-02 19:37:46 +00:00
arguments . push_back ( accessChainLoad ( glslangArguments [ i ] - > getAsTyped ( ) - > getType ( ) ) ) ;
2015-06-26 22:58:36 +00:00
}
}
2015-08-19 19:34:18 +00:00
void TGlslangToSpvTraverser : : translateArguments ( glslang : : TIntermUnary & node , std : : vector < spv : : Id > & arguments )
2015-06-26 22:58:36 +00:00
{
2015-08-19 19:34:18 +00:00
builder . clearAccessChain ( ) ;
node . getOperand ( ) - > traverse ( this ) ;
2016-02-02 19:37:46 +00:00
arguments . push_back ( accessChainLoad ( node . getOperand ( ) - > getType ( ) ) ) ;
2015-08-19 19:34:18 +00:00
}
2015-06-26 22:58:36 +00:00
2015-08-19 19:34:18 +00:00
spv : : Id TGlslangToSpvTraverser : : createImageTextureFunctionCall ( glslang : : TIntermOperator * node )
{
2015-09-09 08:42:49 +00:00
if ( ! node - > isImage ( ) & & ! node - > isTexture ( ) ) {
2015-08-19 19:34:18 +00:00
return spv : : NoResult ;
2015-06-26 22:58:36 +00:00
}
2016-07-26 18:50:38 +00:00
auto resultType = [ & node , this ] { return convertGlslangToSpvType ( node - > getType ( ) ) ; } ;
2015-06-26 22:58:36 +00:00
2015-08-19 19:34:18 +00:00
// Process a GLSL texturing op (will be SPV image)
const glslang : : TSampler sampler = node - > getAsAggregate ( ) ? node - > getAsAggregate ( ) - > getSequence ( ) [ 0 ] - > getAsTyped ( ) - > getType ( ) . getSampler ( )
: node - > getAsUnaryNode ( ) - > getOperand ( ) - > getAsTyped ( ) - > getType ( ) . getSampler ( ) ;
std : : vector < spv : : Id > arguments ;
if ( node - > getAsAggregate ( ) )
2015-09-09 08:42:49 +00:00
translateArguments ( * node - > getAsAggregate ( ) , arguments ) ;
2015-08-19 19:34:18 +00:00
else
translateArguments ( * node - > getAsUnaryNode ( ) , arguments ) ;
2016-08-02 01:44:00 +00:00
spv : : Decoration precision = TranslatePrecisionDecoration ( node - > getOperationPrecision ( ) ) ;
2015-08-19 19:34:18 +00:00
spv : : Builder : : TextureParameters params = { } ;
params . sampler = arguments [ 0 ] ;
2015-09-16 03:44:02 +00:00
glslang : : TCrackedTextureOp cracked ;
node - > crackTexture ( sampler , cracked ) ;
2015-08-19 19:34:18 +00:00
// Check for queries
if ( cracked . query ) {
2016-10-12 13:40:37 +00:00
// OpImageQueryLod works on a sampled image, for other queries the image has to be extracted first
if ( node - > getOp ( ) ! = glslang : : EOpTextureQueryLod & & builder . isSampledImage ( params . sampler ) )
2015-12-09 02:32:47 +00:00
params . sampler = builder . createUnaryOp ( spv : : OpImage , builder . getImageType ( params . sampler ) , params . sampler ) ;
2016-10-12 13:40:37 +00:00
2015-08-19 19:34:18 +00:00
switch ( node - > getOp ( ) ) {
case glslang : : EOpImageQuerySize :
case glslang : : EOpTextureQuerySize :
2015-06-26 22:58:36 +00:00
if ( arguments . size ( ) > 1 ) {
params . lod = arguments [ 1 ] ;
2015-08-07 04:53:06 +00:00
return builder . createTextureQueryCall ( spv : : OpImageQuerySizeLod , params ) ;
2015-06-26 22:58:36 +00:00
} else
2015-08-07 04:53:06 +00:00
return builder . createTextureQueryCall ( spv : : OpImageQuerySize , params ) ;
2015-08-19 19:34:18 +00:00
case glslang : : EOpImageQuerySamples :
case glslang : : EOpTextureQuerySamples :
2015-08-07 04:53:06 +00:00
return builder . createTextureQueryCall ( spv : : OpImageQuerySamples , params ) ;
2015-08-19 19:34:18 +00:00
case glslang : : EOpTextureQueryLod :
params . coords = arguments [ 1 ] ;
return builder . createTextureQueryCall ( spv : : OpImageQueryLod , params ) ;
case glslang : : EOpTextureQueryLevels :
return builder . createTextureQueryCall ( spv : : OpImageQueryLevels , params ) ;
2015-12-31 08:11:41 +00:00
case glslang : : EOpSparseTexelsResident :
return builder . createUnaryOp ( spv : : OpImageSparseTexelsResident , builder . makeBoolType ( ) , arguments [ 0 ] ) ;
2015-08-19 19:34:18 +00:00
default :
assert ( 0 ) ;
break ;
2015-06-26 22:58:36 +00:00
}
2015-08-19 19:34:18 +00:00
}
2015-06-26 22:58:36 +00:00
2015-09-09 08:42:49 +00:00
// Check for image functions other than queries
if ( node - > isImage ( ) ) {
2015-09-16 16:54:31 +00:00
std : : vector < spv : : Id > operands ;
auto opIt = arguments . begin ( ) ;
operands . push_back ( * ( opIt + + ) ) ;
2016-02-16 03:58:50 +00:00
// Handle subpass operations
// TODO: GLSL should change to have the "MS" only on the type rather than the
// built-in function.
if ( cracked . subpass ) {
// add on the (0,0) coordinate
spv : : Id zero = builder . makeIntConstant ( 0 ) ;
std : : vector < spv : : Id > comps ;
comps . push_back ( zero ) ;
comps . push_back ( zero ) ;
operands . push_back ( builder . makeCompositeConstant ( builder . makeVectorType ( builder . makeIntType ( 32 ) , 2 ) , comps ) ) ;
if ( sampler . ms ) {
operands . push_back ( spv : : ImageOperandsSampleMask ) ;
operands . push_back ( * ( opIt + + ) ) ;
}
2016-07-26 18:50:38 +00:00
return builder . createOp ( spv : : OpImageRead , resultType ( ) , operands ) ;
2016-02-16 03:58:50 +00:00
}
2015-09-16 16:54:31 +00:00
operands . push_back ( * ( opIt + + ) ) ;
if ( node - > getOp ( ) = = glslang : : EOpImageLoad ) {
2015-11-16 04:33:39 +00:00
if ( sampler . ms ) {
operands . push_back ( spv : : ImageOperandsSampleMask ) ;
2015-12-15 09:52:45 +00:00
operands . push_back ( * opIt ) ;
2015-11-16 04:33:39 +00:00
}
2016-02-15 18:57:00 +00:00
if ( builder . getImageTypeFormat ( builder . getImageType ( operands . front ( ) ) ) = = spv : : ImageFormatUnknown )
builder . addCapability ( spv : : CapabilityStorageImageReadWithoutFormat ) ;
2016-07-26 18:50:38 +00:00
return builder . createOp ( spv : : OpImageRead , resultType ( ) , operands ) ;
2015-09-16 16:54:31 +00:00
} else if ( node - > getOp ( ) = = glslang : : EOpImageStore ) {
2015-12-15 09:52:45 +00:00
if ( sampler . ms ) {
operands . push_back ( * ( opIt + 1 ) ) ;
operands . push_back ( spv : : ImageOperandsSampleMask ) ;
operands . push_back ( * opIt ) ;
} else
operands . push_back ( * opIt ) ;
2015-09-16 16:54:31 +00:00
builder . createNoResultOp ( spv : : OpImageWrite , operands ) ;
2016-02-15 18:57:00 +00:00
if ( builder . getImageTypeFormat ( builder . getImageType ( operands . front ( ) ) ) = = spv : : ImageFormatUnknown )
builder . addCapability ( spv : : CapabilityStorageImageWriteWithoutFormat ) ;
2015-09-16 16:54:31 +00:00
return spv : : NoResult ;
2016-02-19 14:24:03 +00:00
} else if ( node - > getOp ( ) = = glslang : : EOpSparseImageLoad ) {
builder . addCapability ( spv : : CapabilitySparseResidency ) ;
if ( builder . getImageTypeFormat ( builder . getImageType ( operands . front ( ) ) ) = = spv : : ImageFormatUnknown )
builder . addCapability ( spv : : CapabilityStorageImageReadWithoutFormat ) ;
if ( sampler . ms ) {
operands . push_back ( spv : : ImageOperandsSampleMask ) ;
operands . push_back ( * opIt + + ) ;
}
// Create the return type that was a special structure
spv : : Id texelOut = * opIt ;
2016-07-26 18:50:38 +00:00
spv : : Id typeId0 = resultType ( ) ;
2016-02-19 14:24:03 +00:00
spv : : Id typeId1 = builder . getDerefTypeId ( texelOut ) ;
spv : : Id resultTypeId = builder . makeStructResultType ( typeId0 , typeId1 ) ;
spv : : Id resultId = builder . createOp ( spv : : OpImageSparseRead , resultTypeId , operands ) ;
// Decode the return type
builder . createStore ( builder . createCompositeExtract ( resultId , typeId1 , 1 ) , texelOut ) ;
return builder . createCompositeExtract ( resultId , typeId0 , 0 ) ;
2016-01-22 16:54:12 +00:00
} else {
2015-09-16 09:48:22 +00:00
// Process image atomic operations
// GLSL "IMAGE_PARAMS" will involve in constructing an image texel pointer and this pointer,
// as the first source operand, is required by SPIR-V atomic operations.
2016-01-22 16:54:12 +00:00
operands . push_back ( sampler . ms ? * ( opIt + + ) : builder . makeUintConstant ( 0 ) ) ; // For non-MS, the value should be 0
2015-09-09 08:42:49 +00:00
2016-07-26 18:50:38 +00:00
spv : : Id resultTypeId = builder . makePointer ( spv : : StorageClassImage , resultType ( ) ) ;
2015-09-16 16:54:31 +00:00
spv : : Id pointer = builder . createOp ( spv : : OpImageTexelPointer , resultTypeId , operands ) ;
2015-09-09 08:42:49 +00:00
std : : vector < spv : : Id > operands ;
operands . push_back ( pointer ) ;
for ( ; opIt ! = arguments . end ( ) ; + + opIt )
operands . push_back ( * opIt ) ;
2016-07-26 18:50:38 +00:00
return createAtomicOperation ( node - > getOp ( ) , precision , resultType ( ) , operands , node - > getBasicType ( ) ) ;
2015-09-09 08:42:49 +00:00
}
}
2015-06-26 22:58:36 +00:00
2015-09-09 08:42:49 +00:00
// Check for texture functions other than queries
2015-12-31 08:11:41 +00:00
bool sparse = node - > isSparseTexture ( ) ;
2015-11-11 07:35:47 +00:00
bool cubeCompare = sampler . dim = = glslang : : EsdCube & & sampler . arrayed & & sampler . shadow ;
2015-08-19 19:34:18 +00:00
// check for bias argument
bool bias = false ;
2015-11-11 07:35:47 +00:00
if ( ! cracked . lod & & ! cracked . gather & & ! cracked . grad & & ! cracked . fetch & & ! cubeCompare ) {
2015-08-19 19:34:18 +00:00
int nonBiasArgCount = 2 ;
if ( cracked . offset )
+ + nonBiasArgCount ;
if ( cracked . grad )
nonBiasArgCount + = 2 ;
2015-12-31 08:11:41 +00:00
if ( cracked . lodClamp )
+ + nonBiasArgCount ;
if ( sparse )
+ + nonBiasArgCount ;
2015-08-19 19:34:18 +00:00
if ( ( int ) arguments . size ( ) > nonBiasArgCount )
bias = true ;
2015-06-26 22:58:36 +00:00
}
2016-06-03 05:45:21 +00:00
// See if the sampler param should really be just the SPV image part
if ( cracked . fetch ) {
// a fetch needs to have the image extracted first
if ( builder . isSampledImage ( params . sampler ) )
params . sampler = builder . createUnaryOp ( spv : : OpImage , builder . getImageType ( params . sampler ) , params . sampler ) ;
}
2015-08-19 19:34:18 +00:00
// set the rest of the arguments
2015-11-16 04:33:39 +00:00
2015-08-19 19:34:18 +00:00
params . coords = arguments [ 1 ] ;
int extraArgs = 0 ;
2016-02-15 22:40:42 +00:00
bool noImplicitLod = false ;
2015-11-16 04:33:39 +00:00
// sort out where Dref is coming from
2015-12-31 08:11:41 +00:00
if ( cubeCompare ) {
2015-11-16 04:33:39 +00:00
params . Dref = arguments [ 2 ] ;
2015-12-31 08:11:41 +00:00
+ + extraArgs ;
} else if ( sampler . shadow & & cracked . gather ) {
2015-08-19 19:34:18 +00:00
params . Dref = arguments [ 2 ] ;
2015-11-16 04:33:39 +00:00
+ + extraArgs ;
} else if ( sampler . shadow ) {
2015-08-19 19:34:18 +00:00
std : : vector < spv : : Id > indexes ;
2016-06-16 18:43:23 +00:00
int dRefComp ;
2015-08-19 19:34:18 +00:00
if ( cracked . proj )
2016-06-16 18:43:23 +00:00
dRefComp = 2 ; // "The resulting 3rd component of P in the shadow forms is used as Dref"
2015-08-19 19:34:18 +00:00
else
2016-06-16 18:43:23 +00:00
dRefComp = builder . getNumComponents ( params . coords ) - 1 ;
indexes . push_back ( dRefComp ) ;
2015-08-19 19:34:18 +00:00
params . Dref = builder . createCompositeExtract ( params . coords , builder . getScalarTypeId ( builder . getTypeId ( params . coords ) ) , indexes ) ;
}
2016-06-16 18:43:23 +00:00
// lod
2015-08-19 19:34:18 +00:00
if ( cracked . lod ) {
params . lod = arguments [ 2 ] ;
+ + extraArgs ;
2016-02-15 22:40:42 +00:00
} else if ( glslangIntermediate - > getStage ( ) ! = EShLangFragment ) {
// we need to invent the default lod for an explicit lod instruction for a non-fragment stage
noImplicitLod = true ;
}
2016-06-16 18:43:23 +00:00
// multisample
2016-02-15 22:40:42 +00:00
if ( sampler . ms ) {
2015-09-16 09:48:22 +00:00
params . sample = arguments [ 2 ] ; // For MS, "sample" should be specified
2015-09-16 03:44:02 +00:00
+ + extraArgs ;
2015-08-19 19:34:18 +00:00
}
2016-06-16 18:43:23 +00:00
// gradient
2015-08-19 19:34:18 +00:00
if ( cracked . grad ) {
params . gradX = arguments [ 2 + extraArgs ] ;
params . gradY = arguments [ 3 + extraArgs ] ;
extraArgs + = 2 ;
}
2016-06-16 18:43:23 +00:00
// offset and offsets
2015-11-16 04:33:39 +00:00
if ( cracked . offset ) {
2015-08-19 19:34:18 +00:00
params . offset = arguments [ 2 + extraArgs ] ;
+ + extraArgs ;
2015-11-16 04:33:39 +00:00
} else if ( cracked . offsets ) {
params . offsets = arguments [ 2 + extraArgs ] ;
+ + extraArgs ;
2015-08-19 19:34:18 +00:00
}
2016-06-16 18:43:23 +00:00
// lod clamp
2015-12-31 08:11:41 +00:00
if ( cracked . lodClamp ) {
params . lodClamp = arguments [ 2 + extraArgs ] ;
+ + extraArgs ;
}
2016-06-16 18:43:23 +00:00
// sparse
2015-12-31 08:11:41 +00:00
if ( sparse ) {
params . texelOut = arguments [ 2 + extraArgs ] ;
+ + extraArgs ;
}
2016-06-16 18:43:23 +00:00
// bias
2015-08-19 19:34:18 +00:00
if ( bias ) {
params . bias = arguments [ 2 + extraArgs ] ;
+ + extraArgs ;
}
2016-06-16 18:43:23 +00:00
// gather component
2015-11-16 04:33:39 +00:00
if ( cracked . gather & & ! sampler . shadow ) {
// default component is 0, if missing, otherwise an argument
if ( 2 + extraArgs < ( int ) arguments . size ( ) ) {
2016-06-16 18:43:23 +00:00
params . component = arguments [ 2 + extraArgs ] ;
2015-11-16 04:33:39 +00:00
+ + extraArgs ;
} else {
2016-06-16 18:43:23 +00:00
params . component = builder . makeIntConstant ( 0 ) ;
2015-11-16 04:33:39 +00:00
}
}
2015-06-26 22:58:36 +00:00
2016-06-16 20:06:26 +00:00
// projective component (might not to move)
// GLSL: "The texture coordinates consumed from P, not including the last component of P,
// are divided by the last component of P."
// SPIR-V: "... (u [, v] [, w], q)... It may be a vector larger than needed, but all
// unused components will appear after all used components."
if ( cracked . proj ) {
int projSourceComp = builder . getNumComponents ( params . coords ) - 1 ;
int projTargetComp ;
switch ( sampler . dim ) {
case glslang : : Esd1D : projTargetComp = 1 ; break ;
case glslang : : Esd2D : projTargetComp = 2 ; break ;
case glslang : : EsdRect : projTargetComp = 2 ; break ;
default : projTargetComp = projSourceComp ; break ;
}
// copy the projective coordinate if we have to
if ( projTargetComp ! = projSourceComp ) {
spv : : Id projComp = builder . createCompositeExtract ( params . coords ,
builder . getScalarTypeId ( builder . getTypeId ( params . coords ) ) ,
projSourceComp ) ;
params . coords = builder . createCompositeInsert ( projComp , params . coords ,
builder . getTypeId ( params . coords ) , projTargetComp ) ;
}
}
2016-07-26 18:50:38 +00:00
return builder . createTextureCall ( precision , resultType ( ) , sparse , cracked . fetch , cracked . proj , cracked . gather , noImplicitLod , params ) ;
2015-06-26 22:58:36 +00:00
}
spv : : Id TGlslangToSpvTraverser : : handleUserFunctionCall ( const glslang : : TIntermAggregate * node )
{
// Grab the function's pointer from the previously created function
spv : : Function * function = functionMap [ node - > getName ( ) . c_str ( ) ] ;
if ( ! function )
return 0 ;
const glslang : : TIntermSequence & glslangArgs = node - > getSequence ( ) ;
const glslang : : TQualifierList & qualifiers = node - > getQualifierList ( ) ;
// See comments in makeFunctions() for details about the semantics for parameter passing.
//
// These imply we need a four step process:
// 1. Evaluate the arguments
// 2. Allocate and make copies of in, out, and inout arguments
// 3. Make the call
// 4. Copy back the results
// 1. Evaluate the arguments
std : : vector < spv : : Builder : : AccessChain > lValues ;
std : : vector < spv : : Id > rValues ;
2016-02-02 19:37:46 +00:00
std : : vector < const glslang : : TType * > argTypes ;
2015-06-26 22:58:36 +00:00
for ( int a = 0 ; a < ( int ) glslangArgs . size ( ) ; + + a ) {
2016-05-25 18:50:21 +00:00
const glslang : : TType & paramType = glslangArgs [ a ] - > getAsTyped ( ) - > getType ( ) ;
2015-06-26 22:58:36 +00:00
// build l-value
builder . clearAccessChain ( ) ;
glslangArgs [ a ] - > traverse ( this ) ;
2016-05-25 18:50:21 +00:00
argTypes . push_back ( & paramType ) ;
2016-07-31 18:39:46 +00:00
// keep outputs and opaque objects as l-values, evaluate input-only as r-values
2016-06-08 20:54:48 +00:00
if ( qualifiers [ a ] ! = glslang : : EvqConstReadOnly | | paramType . isOpaque ( ) ) {
2015-06-26 22:58:36 +00:00
// save l-value
lValues . push_back ( builder . getAccessChain ( ) ) ;
} else {
// process r-value
2016-02-02 19:37:46 +00:00
rValues . push_back ( accessChainLoad ( * argTypes . back ( ) ) ) ;
2015-06-26 22:58:36 +00:00
}
}
// 2. Allocate space for anything needing a copy, and if it's "in" or "inout"
// copy the original into that space.
//
// Also, build up the list of actual arguments to pass in for the call
int lValueCount = 0 ;
int rValueCount = 0 ;
std : : vector < spv : : Id > spvArgs ;
for ( int a = 0 ; a < ( int ) glslangArgs . size ( ) ; + + a ) {
2016-05-25 18:50:21 +00:00
const glslang : : TType & paramType = glslangArgs [ a ] - > getAsTyped ( ) - > getType ( ) ;
2015-06-26 22:58:36 +00:00
spv : : Id arg ;
2016-06-08 20:54:48 +00:00
if ( paramType . isOpaque ( ) ) {
2016-05-25 18:50:21 +00:00
builder . setAccessChain ( lValues [ lValueCount ] ) ;
arg = builder . accessChainGetLValue ( ) ;
+ + lValueCount ;
} else if ( qualifiers [ a ] ! = glslang : : EvqConstReadOnly ) {
2015-06-26 22:58:36 +00:00
// need space to hold the copy
arg = builder . createVariable ( spv : : StorageClassFunction , convertGlslangToSpvType ( paramType ) , " param " ) ;
if ( qualifiers [ a ] = = glslang : : EvqIn | | qualifiers [ a ] = = glslang : : EvqInOut ) {
// need to copy the input into output space
builder . setAccessChain ( lValues [ lValueCount ] ) ;
2016-02-02 19:37:46 +00:00
spv : : Id copy = accessChainLoad ( * argTypes [ a ] ) ;
2016-09-02 17:20:21 +00:00
builder . clearAccessChain ( ) ;
builder . setAccessChainLValue ( arg ) ;
multiTypeStore ( paramType , copy ) ;
2015-06-26 22:58:36 +00:00
}
+ + lValueCount ;
} else {
arg = rValues [ rValueCount ] ;
+ + rValueCount ;
}
spvArgs . push_back ( arg ) ;
}
// 3. Make the call.
spv : : Id result = builder . createFunctionCall ( function , spvArgs ) ;
2016-02-02 19:37:46 +00:00
builder . setPrecision ( result , TranslatePrecisionDecoration ( node - > getType ( ) ) ) ;
2015-06-26 22:58:36 +00:00
// 4. Copy back out an "out" arguments.
lValueCount = 0 ;
for ( int a = 0 ; a < ( int ) glslangArgs . size ( ) ; + + a ) {
2016-09-02 17:20:21 +00:00
const glslang : : TType & paramType = glslangArgs [ a ] - > getAsTyped ( ) - > getType ( ) ;
2015-06-26 22:58:36 +00:00
if ( qualifiers [ a ] ! = glslang : : EvqConstReadOnly ) {
if ( qualifiers [ a ] = = glslang : : EvqOut | | qualifiers [ a ] = = glslang : : EvqInOut ) {
spv : : Id copy = builder . createLoad ( spvArgs [ a ] ) ;
builder . setAccessChain ( lValues [ lValueCount ] ) ;
2016-09-02 17:20:21 +00:00
multiTypeStore ( paramType , copy ) ;
2015-06-26 22:58:36 +00:00
}
+ + lValueCount ;
}
}
return result ;
}
// Translate AST operation to SPV operation, already having SPV-based operands/types.
2016-05-06 21:25:16 +00:00
spv : : Id TGlslangToSpvTraverser : : createBinaryOperation ( glslang : : TOperator op , spv : : Decoration precision ,
spv : : Decoration noContraction ,
2015-06-26 22:58:36 +00:00
spv : : Id typeId , spv : : Id left , spv : : Id right ,
glslang : : TBasicType typeProxy , bool reduceComparison )
{
2016-04-22 08:51:45 +00:00
bool isUnsigned = typeProxy = = glslang : : EbtUint | | typeProxy = = glslang : : EbtUint64 ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
bool isFloat = typeProxy = = glslang : : EbtFloat | | typeProxy = = glslang : : EbtDouble | | typeProxy = = glslang : : EbtFloat16 ;
# else
2015-06-26 22:58:36 +00:00
bool isFloat = typeProxy = = glslang : : EbtFloat | | typeProxy = = glslang : : EbtDouble ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# endif
2016-04-27 00:15:37 +00:00
bool isBool = typeProxy = = glslang : : EbtBool ;
2015-06-26 22:58:36 +00:00
spv : : Op binOp = spv : : OpNop ;
2015-07-04 23:17:31 +00:00
bool needMatchingVectors = true ; // for non-matrix ops, would a scalar need to smear to match a vector?
2015-06-26 22:58:36 +00:00
bool comparison = false ;
switch ( op ) {
case glslang : : EOpAdd :
case glslang : : EOpAddAssign :
if ( isFloat )
binOp = spv : : OpFAdd ;
else
binOp = spv : : OpIAdd ;
break ;
case glslang : : EOpSub :
case glslang : : EOpSubAssign :
if ( isFloat )
binOp = spv : : OpFSub ;
else
binOp = spv : : OpISub ;
break ;
case glslang : : EOpMul :
case glslang : : EOpMulAssign :
if ( isFloat )
binOp = spv : : OpFMul ;
else
binOp = spv : : OpIMul ;
break ;
case glslang : : EOpVectorTimesScalar :
case glslang : : EOpVectorTimesScalarAssign :
2016-05-20 18:06:03 +00:00
if ( isFloat & & ( builder . isVector ( left ) | | builder . isVector ( right ) ) ) {
2015-07-04 23:17:31 +00:00
if ( builder . isVector ( right ) )
std : : swap ( left , right ) ;
assert ( builder . isScalar ( right ) ) ;
needMatchingVectors = false ;
binOp = spv : : OpVectorTimesScalar ;
} else
binOp = spv : : OpIMul ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpVectorTimesMatrix :
case glslang : : EOpVectorTimesMatrixAssign :
binOp = spv : : OpVectorTimesMatrix ;
break ;
case glslang : : EOpMatrixTimesVector :
binOp = spv : : OpMatrixTimesVector ;
break ;
case glslang : : EOpMatrixTimesScalar :
case glslang : : EOpMatrixTimesScalarAssign :
binOp = spv : : OpMatrixTimesScalar ;
break ;
case glslang : : EOpMatrixTimesMatrix :
case glslang : : EOpMatrixTimesMatrixAssign :
binOp = spv : : OpMatrixTimesMatrix ;
break ;
case glslang : : EOpOuterProduct :
binOp = spv : : OpOuterProduct ;
2015-07-04 23:17:31 +00:00
needMatchingVectors = false ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpDiv :
case glslang : : EOpDivAssign :
if ( isFloat )
binOp = spv : : OpFDiv ;
else if ( isUnsigned )
binOp = spv : : OpUDiv ;
else
binOp = spv : : OpSDiv ;
break ;
case glslang : : EOpMod :
case glslang : : EOpModAssign :
if ( isFloat )
binOp = spv : : OpFMod ;
else if ( isUnsigned )
binOp = spv : : OpUMod ;
else
binOp = spv : : OpSMod ;
break ;
case glslang : : EOpRightShift :
case glslang : : EOpRightShiftAssign :
if ( isUnsigned )
binOp = spv : : OpShiftRightLogical ;
else
binOp = spv : : OpShiftRightArithmetic ;
break ;
case glslang : : EOpLeftShift :
case glslang : : EOpLeftShiftAssign :
binOp = spv : : OpShiftLeftLogical ;
break ;
case glslang : : EOpAnd :
case glslang : : EOpAndAssign :
binOp = spv : : OpBitwiseAnd ;
break ;
case glslang : : EOpLogicalAnd :
2015-07-04 23:17:31 +00:00
needMatchingVectors = false ;
2015-06-26 22:58:36 +00:00
binOp = spv : : OpLogicalAnd ;
break ;
case glslang : : EOpInclusiveOr :
case glslang : : EOpInclusiveOrAssign :
binOp = spv : : OpBitwiseOr ;
break ;
case glslang : : EOpLogicalOr :
2015-07-04 23:17:31 +00:00
needMatchingVectors = false ;
2015-06-26 22:58:36 +00:00
binOp = spv : : OpLogicalOr ;
break ;
case glslang : : EOpExclusiveOr :
case glslang : : EOpExclusiveOrAssign :
binOp = spv : : OpBitwiseXor ;
break ;
case glslang : : EOpLogicalXor :
2015-07-04 23:17:31 +00:00
needMatchingVectors = false ;
2015-08-07 04:53:06 +00:00
binOp = spv : : OpLogicalNotEqual ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpLessThan :
case glslang : : EOpGreaterThan :
case glslang : : EOpLessThanEqual :
case glslang : : EOpGreaterThanEqual :
case glslang : : EOpEqual :
case glslang : : EOpNotEqual :
case glslang : : EOpVectorEqual :
case glslang : : EOpVectorNotEqual :
comparison = true ;
break ;
default :
break ;
}
2015-10-15 19:29:11 +00:00
// handle mapped binary operations (should be non-comparison)
2015-06-26 22:58:36 +00:00
if ( binOp ! = spv : : OpNop ) {
2015-10-15 19:29:11 +00:00
assert ( comparison = = false ) ;
2015-12-12 19:28:14 +00:00
if ( builder . isMatrix ( left ) | | builder . isMatrix ( right ) )
2016-05-06 21:25:16 +00:00
return createBinaryMatrixOperation ( binOp , precision , noContraction , typeId , left , right ) ;
2015-06-26 22:58:36 +00:00
// No matrix involved; make both operands be the same number of components, if needed
2015-07-04 23:17:31 +00:00
if ( needMatchingVectors )
2015-06-26 22:58:36 +00:00
builder . promoteScalar ( precision , left , right ) ;
2016-05-06 21:25:16 +00:00
spv : : Id result = builder . createBinOp ( binOp , typeId , left , right ) ;
addDecoration ( result , noContraction ) ;
return builder . setPrecision ( result , precision ) ;
2015-06-26 22:58:36 +00:00
}
if ( ! comparison )
return 0 ;
2015-10-15 19:29:11 +00:00
// Handle comparison instructions
2015-06-26 22:58:36 +00:00
2016-08-08 01:14:22 +00:00
if ( reduceComparison & & ( op = = glslang : : EOpEqual | | op = = glslang : : EOpNotEqual )
& & ( builder . isVector ( left ) | | builder . isMatrix ( left ) | | builder . isAggregate ( left ) ) )
2015-12-22 03:54:09 +00:00
return builder . createCompositeCompare ( precision , left , right , op = = glslang : : EOpEqual ) ;
2015-06-26 22:58:36 +00:00
switch ( op ) {
case glslang : : EOpLessThan :
if ( isFloat )
binOp = spv : : OpFOrdLessThan ;
else if ( isUnsigned )
binOp = spv : : OpULessThan ;
else
binOp = spv : : OpSLessThan ;
break ;
case glslang : : EOpGreaterThan :
if ( isFloat )
binOp = spv : : OpFOrdGreaterThan ;
else if ( isUnsigned )
binOp = spv : : OpUGreaterThan ;
else
binOp = spv : : OpSGreaterThan ;
break ;
case glslang : : EOpLessThanEqual :
if ( isFloat )
binOp = spv : : OpFOrdLessThanEqual ;
else if ( isUnsigned )
binOp = spv : : OpULessThanEqual ;
else
binOp = spv : : OpSLessThanEqual ;
break ;
case glslang : : EOpGreaterThanEqual :
if ( isFloat )
binOp = spv : : OpFOrdGreaterThanEqual ;
else if ( isUnsigned )
binOp = spv : : OpUGreaterThanEqual ;
else
binOp = spv : : OpSGreaterThanEqual ;
break ;
case glslang : : EOpEqual :
case glslang : : EOpVectorEqual :
if ( isFloat )
binOp = spv : : OpFOrdEqual ;
2016-04-27 00:15:37 +00:00
else if ( isBool )
binOp = spv : : OpLogicalEqual ;
2015-06-26 22:58:36 +00:00
else
binOp = spv : : OpIEqual ;
break ;
case glslang : : EOpNotEqual :
case glslang : : EOpVectorNotEqual :
if ( isFloat )
binOp = spv : : OpFOrdNotEqual ;
2016-04-27 00:15:37 +00:00
else if ( isBool )
binOp = spv : : OpLogicalNotEqual ;
2015-06-26 22:58:36 +00:00
else
binOp = spv : : OpINotEqual ;
break ;
default :
break ;
}
2016-05-06 21:25:16 +00:00
if ( binOp ! = spv : : OpNop ) {
spv : : Id result = builder . createBinOp ( binOp , typeId , left , right ) ;
addDecoration ( result , noContraction ) ;
return builder . setPrecision ( result , precision ) ;
}
2015-06-26 22:58:36 +00:00
return 0 ;
}
2015-12-12 19:28:14 +00:00
//
// Translate AST matrix operation to SPV operation, already having SPV-based operands/types.
// These can be any of:
//
// matrix * scalar
// scalar * matrix
// matrix * matrix linear algebraic
// matrix * vector
// vector * matrix
// matrix * matrix componentwise
// matrix op matrix op in {+, -, /}
// matrix op scalar op in {+, -, /}
// scalar op matrix op in {+, -, /}
//
2016-05-06 21:25:16 +00:00
spv : : Id TGlslangToSpvTraverser : : createBinaryMatrixOperation ( spv : : Op op , spv : : Decoration precision , spv : : Decoration noContraction , spv : : Id typeId , spv : : Id left , spv : : Id right )
2015-12-12 19:28:14 +00:00
{
bool firstClass = true ;
// First, handle first-class matrix operations (* and matrix/scalar)
switch ( op ) {
case spv : : OpFDiv :
if ( builder . isMatrix ( left ) & & builder . isScalar ( right ) ) {
// turn matrix / scalar into a multiply...
right = builder . createBinOp ( spv : : OpFDiv , builder . getTypeId ( right ) , builder . makeFloatConstant ( 1.0F ) , right ) ;
op = spv : : OpMatrixTimesScalar ;
} else
firstClass = false ;
break ;
case spv : : OpMatrixTimesScalar :
if ( builder . isMatrix ( right ) )
std : : swap ( left , right ) ;
assert ( builder . isScalar ( right ) ) ;
break ;
case spv : : OpVectorTimesMatrix :
assert ( builder . isVector ( left ) ) ;
assert ( builder . isMatrix ( right ) ) ;
break ;
case spv : : OpMatrixTimesVector :
assert ( builder . isMatrix ( left ) ) ;
assert ( builder . isVector ( right ) ) ;
break ;
case spv : : OpMatrixTimesMatrix :
assert ( builder . isMatrix ( left ) ) ;
assert ( builder . isMatrix ( right ) ) ;
break ;
default :
firstClass = false ;
break ;
}
2016-05-06 21:25:16 +00:00
if ( firstClass ) {
spv : : Id result = builder . createBinOp ( op , typeId , left , right ) ;
addDecoration ( result , noContraction ) ;
return builder . setPrecision ( result , precision ) ;
}
2015-12-12 19:28:14 +00:00
2016-06-09 14:57:35 +00:00
// Handle component-wise +, -, *, %, and / for all combinations of type.
2015-12-12 19:28:14 +00:00
// The result type of all of them is the same type as the (a) matrix operand.
// The algorithm is to:
// - break the matrix(es) into vectors
// - smear any scalar to a vector
// - do vector operations
// - make a matrix out the vector results
switch ( op ) {
case spv : : OpFAdd :
case spv : : OpFSub :
case spv : : OpFDiv :
2016-06-09 14:57:35 +00:00
case spv : : OpFMod :
2015-12-12 19:28:14 +00:00
case spv : : OpFMul :
{
// one time set up...
bool leftMat = builder . isMatrix ( left ) ;
bool rightMat = builder . isMatrix ( right ) ;
unsigned int numCols = leftMat ? builder . getNumColumns ( left ) : builder . getNumColumns ( right ) ;
int numRows = leftMat ? builder . getNumRows ( left ) : builder . getNumRows ( right ) ;
spv : : Id scalarType = builder . getScalarTypeId ( typeId ) ;
spv : : Id vecType = builder . makeVectorType ( scalarType , numRows ) ;
std : : vector < spv : : Id > results ;
spv : : Id smearVec = spv : : NoResult ;
if ( builder . isScalar ( left ) )
smearVec = builder . smearScalar ( precision , left , vecType ) ;
else if ( builder . isScalar ( right ) )
smearVec = builder . smearScalar ( precision , right , vecType ) ;
// do each vector op
for ( unsigned int c = 0 ; c < numCols ; + + c ) {
std : : vector < unsigned int > indexes ;
indexes . push_back ( c ) ;
spv : : Id leftVec = leftMat ? builder . createCompositeExtract ( left , vecType , indexes ) : smearVec ;
spv : : Id rightVec = rightMat ? builder . createCompositeExtract ( right , vecType , indexes ) : smearVec ;
2016-05-06 21:25:16 +00:00
spv : : Id result = builder . createBinOp ( op , vecType , leftVec , rightVec ) ;
addDecoration ( result , noContraction ) ;
results . push_back ( builder . setPrecision ( result , precision ) ) ;
2015-12-12 19:28:14 +00:00
}
// put the pieces together
2016-02-02 19:37:46 +00:00
return builder . setPrecision ( builder . createCompositeConstruct ( typeId , results ) , precision ) ;
2015-12-12 19:28:14 +00:00
}
default :
assert ( 0 ) ;
return spv : : NoResult ;
}
}
2016-05-06 21:25:16 +00:00
spv : : Id TGlslangToSpvTraverser : : createUnaryOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Decoration noContraction , spv : : Id typeId , spv : : Id operand , glslang : : TBasicType typeProxy )
2015-06-26 22:58:36 +00:00
{
spv : : Op unaryOp = spv : : OpNop ;
2016-05-05 04:30:44 +00:00
int extBuiltins = - 1 ;
2015-06-26 22:58:36 +00:00
int libCall = - 1 ;
2016-04-22 08:51:45 +00:00
bool isUnsigned = typeProxy = = glslang : : EbtUint | | typeProxy = = glslang : : EbtUint64 ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
bool isFloat = typeProxy = = glslang : : EbtFloat | | typeProxy = = glslang : : EbtDouble | | typeProxy = = glslang : : EbtFloat16 ;
# else
2015-09-16 03:44:02 +00:00
bool isFloat = typeProxy = = glslang : : EbtFloat | | typeProxy = = glslang : : EbtDouble ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# endif
2015-06-26 22:58:36 +00:00
switch ( op ) {
case glslang : : EOpNegative :
2016-01-20 18:19:27 +00:00
if ( isFloat ) {
2015-06-26 22:58:36 +00:00
unaryOp = spv : : OpFNegate ;
2016-01-20 18:19:27 +00:00
if ( builder . isMatrixType ( typeId ) )
2016-05-06 21:25:16 +00:00
return createUnaryMatrixOperation ( unaryOp , precision , noContraction , typeId , operand , typeProxy ) ;
2016-01-20 18:19:27 +00:00
} else
2015-06-26 22:58:36 +00:00
unaryOp = spv : : OpSNegate ;
break ;
case glslang : : EOpLogicalNot :
case glslang : : EOpVectorLogicalNot :
2015-08-07 04:53:06 +00:00
unaryOp = spv : : OpLogicalNot ;
break ;
2015-06-26 22:58:36 +00:00
case glslang : : EOpBitwiseNot :
unaryOp = spv : : OpNot ;
break ;
2015-08-07 04:53:06 +00:00
2015-06-26 22:58:36 +00:00
case glslang : : EOpDeterminant :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Determinant ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpMatrixInverse :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450MatrixInverse ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpTranspose :
unaryOp = spv : : OpTranspose ;
break ;
case glslang : : EOpRadians :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Radians ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpDegrees :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Degrees ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpSin :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Sin ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpCos :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Cos ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpTan :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Tan ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpAcos :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Acos ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpAsin :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Asin ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpAtan :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Atan ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpAcosh :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Acosh ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpAsinh :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Asinh ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpAtanh :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Atanh ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpTanh :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Tanh ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpCosh :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Cosh ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpSinh :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Sinh ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpLength :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Length ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpNormalize :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Normalize ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpExp :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Exp ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpLog :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Log ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpExp2 :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Exp2 ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpLog2 :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Log2 ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpSqrt :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Sqrt ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpInverseSqrt :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450InverseSqrt ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpFloor :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Floor ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpTrunc :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Trunc ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpRound :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Round ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpRoundEven :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450RoundEven ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpCeil :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Ceil ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpFract :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Fract ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpIsNan :
unaryOp = spv : : OpIsNan ;
break ;
case glslang : : EOpIsInf :
unaryOp = spv : : OpIsInf ;
break ;
2016-06-09 14:57:35 +00:00
case glslang : : EOpIsFinite :
unaryOp = spv : : OpIsFinite ;
break ;
2015-06-26 22:58:36 +00:00
2015-12-15 08:03:10 +00:00
case glslang : : EOpFloatBitsToInt :
case glslang : : EOpFloatBitsToUint :
case glslang : : EOpIntBitsToFloat :
case glslang : : EOpUintBitsToFloat :
2016-04-22 08:51:45 +00:00
case glslang : : EOpDoubleBitsToInt64 :
case glslang : : EOpDoubleBitsToUint64 :
case glslang : : EOpInt64BitsToDouble :
case glslang : : EOpUint64BitsToDouble :
2015-12-15 08:03:10 +00:00
unaryOp = spv : : OpBitcast ;
break ;
2015-06-26 22:58:36 +00:00
case glslang : : EOpPackSnorm2x16 :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450PackSnorm2x16 ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpUnpackSnorm2x16 :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450UnpackSnorm2x16 ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpPackUnorm2x16 :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450PackUnorm2x16 ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpUnpackUnorm2x16 :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450UnpackUnorm2x16 ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpPackHalf2x16 :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450PackHalf2x16 ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpUnpackHalf2x16 :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450UnpackHalf2x16 ;
2015-06-26 22:58:36 +00:00
break ;
2015-08-19 19:34:18 +00:00
case glslang : : EOpPackSnorm4x8 :
libCall = spv : : GLSLstd450PackSnorm4x8 ;
break ;
case glslang : : EOpUnpackSnorm4x8 :
libCall = spv : : GLSLstd450UnpackSnorm4x8 ;
break ;
case glslang : : EOpPackUnorm4x8 :
libCall = spv : : GLSLstd450PackUnorm4x8 ;
break ;
case glslang : : EOpUnpackUnorm4x8 :
libCall = spv : : GLSLstd450UnpackUnorm4x8 ;
break ;
case glslang : : EOpPackDouble2x32 :
libCall = spv : : GLSLstd450PackDouble2x32 ;
break ;
case glslang : : EOpUnpackDouble2x32 :
libCall = spv : : GLSLstd450UnpackDouble2x32 ;
break ;
2015-06-26 22:58:36 +00:00
2016-04-22 08:51:45 +00:00
case glslang : : EOpPackInt2x32 :
case glslang : : EOpUnpackInt2x32 :
case glslang : : EOpPackUint2x32 :
case glslang : : EOpUnpackUint2x32 :
2016-09-09 09:50:07 +00:00
unaryOp = spv : : OpBitcast ;
2016-04-22 08:51:45 +00:00
break ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpPackFloat2x16 :
case glslang : : EOpUnpackFloat2x16 :
unaryOp = spv : : OpBitcast ;
break ;
# endif
2015-06-26 22:58:36 +00:00
case glslang : : EOpDPdx :
unaryOp = spv : : OpDPdx ;
break ;
case glslang : : EOpDPdy :
unaryOp = spv : : OpDPdy ;
break ;
case glslang : : EOpFwidth :
unaryOp = spv : : OpFwidth ;
break ;
case glslang : : EOpDPdxFine :
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityDerivativeControl ) ;
2015-06-26 22:58:36 +00:00
unaryOp = spv : : OpDPdxFine ;
break ;
case glslang : : EOpDPdyFine :
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityDerivativeControl ) ;
2015-06-26 22:58:36 +00:00
unaryOp = spv : : OpDPdyFine ;
break ;
case glslang : : EOpFwidthFine :
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityDerivativeControl ) ;
2015-06-26 22:58:36 +00:00
unaryOp = spv : : OpFwidthFine ;
break ;
case glslang : : EOpDPdxCoarse :
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityDerivativeControl ) ;
2015-06-26 22:58:36 +00:00
unaryOp = spv : : OpDPdxCoarse ;
break ;
case glslang : : EOpDPdyCoarse :
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityDerivativeControl ) ;
2015-06-26 22:58:36 +00:00
unaryOp = spv : : OpDPdyCoarse ;
break ;
case glslang : : EOpFwidthCoarse :
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityDerivativeControl ) ;
2015-06-26 22:58:36 +00:00
unaryOp = spv : : OpFwidthCoarse ;
break ;
2015-12-08 09:12:09 +00:00
case glslang : : EOpInterpolateAtCentroid :
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityInterpolationFunction ) ;
2015-12-08 09:12:09 +00:00
libCall = spv : : GLSLstd450InterpolateAtCentroid ;
break ;
2015-06-26 22:58:36 +00:00
case glslang : : EOpAny :
unaryOp = spv : : OpAny ;
break ;
case glslang : : EOpAll :
unaryOp = spv : : OpAll ;
break ;
case glslang : : EOpAbs :
2015-08-07 04:53:06 +00:00
if ( isFloat )
libCall = spv : : GLSLstd450FAbs ;
else
libCall = spv : : GLSLstd450SAbs ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpSign :
2015-08-07 04:53:06 +00:00
if ( isFloat )
libCall = spv : : GLSLstd450FSign ;
else
libCall = spv : : GLSLstd450SSign ;
2015-06-26 22:58:36 +00:00
break ;
2015-08-19 19:34:18 +00:00
case glslang : : EOpAtomicCounterIncrement :
case glslang : : EOpAtomicCounterDecrement :
case glslang : : EOpAtomicCounter :
{
// Handle all of the atomics in one place, in createAtomicOperation()
std : : vector < spv : : Id > operands ;
operands . push_back ( operand ) ;
2015-09-16 03:44:02 +00:00
return createAtomicOperation ( op , precision , typeId , operands , typeProxy ) ;
2015-08-19 19:34:18 +00:00
}
case glslang : : EOpBitFieldReverse :
unaryOp = spv : : OpBitReverse ;
break ;
case glslang : : EOpBitCount :
unaryOp = spv : : OpBitCount ;
break ;
case glslang : : EOpFindLSB :
2015-11-16 04:33:39 +00:00
libCall = spv : : GLSLstd450FindILsb ;
2015-08-19 19:34:18 +00:00
break ;
case glslang : : EOpFindMSB :
2015-11-16 04:33:39 +00:00
if ( isUnsigned )
libCall = spv : : GLSLstd450FindUMsb ;
else
libCall = spv : : GLSLstd450FindSMsb ;
2015-08-19 19:34:18 +00:00
break ;
2016-04-14 08:53:07 +00:00
case glslang : : EOpBallot :
case glslang : : EOpReadFirstInvocation :
2016-05-05 12:38:33 +00:00
case glslang : : EOpAnyInvocation :
case glslang : : EOpAllInvocations :
case glslang : : EOpAllInvocationsEqual :
2016-05-05 04:30:44 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpMinInvocations :
case glslang : : EOpMaxInvocations :
case glslang : : EOpAddInvocations :
case glslang : : EOpMinInvocationsNonUniform :
case glslang : : EOpMaxInvocationsNonUniform :
case glslang : : EOpAddInvocationsNonUniform :
# endif
2016-09-21 10:56:12 +00:00
{
std : : vector < spv : : Id > operands ;
operands . push_back ( operand ) ;
return createInvocationsOperation ( op , typeId , operands , typeProxy ) ;
}
2016-05-05 04:30:44 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpMbcnt :
extBuiltins = getExtBuiltins ( spv : : E_SPV_AMD_shader_ballot ) ;
libCall = spv : : MbcntAMD ;
break ;
case glslang : : EOpCubeFaceIndex :
extBuiltins = getExtBuiltins ( spv : : E_SPV_AMD_gcn_shader ) ;
libCall = spv : : CubeFaceIndexAMD ;
break ;
case glslang : : EOpCubeFaceCoord :
extBuiltins = getExtBuiltins ( spv : : E_SPV_AMD_gcn_shader ) ;
libCall = spv : : CubeFaceCoordAMD ;
break ;
# endif
2016-05-05 12:38:33 +00:00
2015-06-26 22:58:36 +00:00
default :
return 0 ;
}
spv : : Id id ;
if ( libCall > = 0 ) {
std : : vector < spv : : Id > args ;
args . push_back ( operand ) ;
2016-05-05 04:30:44 +00:00
id = builder . createBuiltinCall ( typeId , extBuiltins > = 0 ? extBuiltins : stdBuiltins , libCall , args ) ;
2016-05-05 12:38:33 +00:00
} else {
2016-05-05 22:45:40 +00:00
id = builder . createUnaryOp ( unaryOp , typeId , operand ) ;
2016-05-05 12:38:33 +00:00
}
2015-06-26 22:58:36 +00:00
2016-05-06 21:25:16 +00:00
addDecoration ( id , noContraction ) ;
2016-02-02 19:37:46 +00:00
return builder . setPrecision ( id , precision ) ;
2015-06-26 22:58:36 +00:00
}
2016-01-20 18:19:27 +00:00
// Create a unary operation on a matrix
2016-05-06 21:25:16 +00:00
spv : : Id TGlslangToSpvTraverser : : createUnaryMatrixOperation ( spv : : Op op , spv : : Decoration precision , spv : : Decoration noContraction , spv : : Id typeId , spv : : Id operand , glslang : : TBasicType /* typeProxy */ )
2016-01-20 18:19:27 +00:00
{
// Handle unary operations vector by vector.
// The result type is the same type as the original type.
// The algorithm is to:
// - break the matrix into vectors
// - apply the operation to each vector
// - make a matrix out the vector results
// get the types sorted out
int numCols = builder . getNumColumns ( operand ) ;
int numRows = builder . getNumRows ( operand ) ;
2016-05-17 10:57:18 +00:00
spv : : Id srcVecType = builder . makeVectorType ( builder . getScalarTypeId ( builder . getTypeId ( operand ) ) , numRows ) ;
spv : : Id destVecType = builder . makeVectorType ( builder . getScalarTypeId ( typeId ) , numRows ) ;
2016-01-20 18:19:27 +00:00
std : : vector < spv : : Id > results ;
// do each vector op
for ( int c = 0 ; c < numCols ; + + c ) {
std : : vector < unsigned int > indexes ;
indexes . push_back ( c ) ;
2016-05-17 10:57:18 +00:00
spv : : Id srcVec = builder . createCompositeExtract ( operand , srcVecType , indexes ) ;
spv : : Id destVec = builder . createUnaryOp ( op , destVecType , srcVec ) ;
addDecoration ( destVec , noContraction ) ;
results . push_back ( builder . setPrecision ( destVec , precision ) ) ;
2016-01-20 18:19:27 +00:00
}
// put the pieces together
2016-02-02 19:37:46 +00:00
return builder . setPrecision ( builder . createCompositeConstruct ( typeId , results ) , precision ) ;
2016-01-20 18:19:27 +00:00
}
2016-04-27 10:48:17 +00:00
spv : : Id TGlslangToSpvTraverser : : createConversion ( glslang : : TOperator op , spv : : Decoration precision , spv : : Decoration noContraction , spv : : Id destType , spv : : Id operand , glslang : : TBasicType typeProxy )
2015-06-26 22:58:36 +00:00
{
spv : : Op convOp = spv : : OpNop ;
spv : : Id zero = 0 ;
spv : : Id one = 0 ;
2016-04-22 08:51:45 +00:00
spv : : Id type = 0 ;
2015-06-26 22:58:36 +00:00
int vectorSize = builder . isVectorType ( destType ) ? builder . getNumTypeComponents ( destType ) : 0 ;
switch ( op ) {
case glslang : : EOpConvIntToBool :
case glslang : : EOpConvUintToBool :
2016-04-22 08:51:45 +00:00
case glslang : : EOpConvInt64ToBool :
case glslang : : EOpConvUint64ToBool :
zero = ( op = = glslang : : EOpConvInt64ToBool | |
op = = glslang : : EOpConvUint64ToBool ) ? builder . makeUint64Constant ( 0 ) : builder . makeUintConstant ( 0 ) ;
2015-06-26 22:58:36 +00:00
zero = makeSmearedConstant ( zero , vectorSize ) ;
return builder . createBinOp ( spv : : OpINotEqual , destType , operand , zero ) ;
case glslang : : EOpConvFloatToBool :
zero = builder . makeFloatConstant ( 0.0F ) ;
zero = makeSmearedConstant ( zero , vectorSize ) ;
return builder . createBinOp ( spv : : OpFOrdNotEqual , destType , operand , zero ) ;
case glslang : : EOpConvDoubleToBool :
zero = builder . makeDoubleConstant ( 0.0 ) ;
zero = makeSmearedConstant ( zero , vectorSize ) ;
return builder . createBinOp ( spv : : OpFOrdNotEqual , destType , operand , zero ) ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpConvFloat16ToBool :
zero = builder . makeFloat16Constant ( 0.0F ) ;
zero = makeSmearedConstant ( zero , vectorSize ) ;
return builder . createBinOp ( spv : : OpFOrdNotEqual , destType , operand , zero ) ;
# endif
2015-06-26 22:58:36 +00:00
case glslang : : EOpConvBoolToFloat :
convOp = spv : : OpSelect ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
zero = builder . makeFloatConstant ( 0.0F ) ;
one = builder . makeFloatConstant ( 1.0F ) ;
2015-06-26 22:58:36 +00:00
break ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
2015-06-26 22:58:36 +00:00
case glslang : : EOpConvBoolToDouble :
convOp = spv : : OpSelect ;
zero = builder . makeDoubleConstant ( 0.0 ) ;
one = builder . makeDoubleConstant ( 1.0 ) ;
break ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpConvBoolToFloat16 :
convOp = spv : : OpSelect ;
zero = builder . makeFloat16Constant ( 0.0F ) ;
one = builder . makeFloat16Constant ( 1.0F ) ;
break ;
# endif
2015-06-26 22:58:36 +00:00
case glslang : : EOpConvBoolToInt :
2016-04-22 08:51:45 +00:00
case glslang : : EOpConvBoolToInt64 :
zero = ( op = = glslang : : EOpConvBoolToInt64 ) ? builder . makeInt64Constant ( 0 ) : builder . makeIntConstant ( 0 ) ;
one = ( op = = glslang : : EOpConvBoolToInt64 ) ? builder . makeInt64Constant ( 1 ) : builder . makeIntConstant ( 1 ) ;
2015-06-26 22:58:36 +00:00
convOp = spv : : OpSelect ;
break ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
2015-06-26 22:58:36 +00:00
case glslang : : EOpConvBoolToUint :
2016-04-22 08:51:45 +00:00
case glslang : : EOpConvBoolToUint64 :
zero = ( op = = glslang : : EOpConvBoolToUint64 ) ? builder . makeUint64Constant ( 0 ) : builder . makeUintConstant ( 0 ) ;
one = ( op = = glslang : : EOpConvBoolToUint64 ) ? builder . makeUint64Constant ( 1 ) : builder . makeUintConstant ( 1 ) ;
2015-06-26 22:58:36 +00:00
convOp = spv : : OpSelect ;
break ;
case glslang : : EOpConvIntToFloat :
case glslang : : EOpConvIntToDouble :
2016-04-22 08:51:45 +00:00
case glslang : : EOpConvInt64ToFloat :
case glslang : : EOpConvInt64ToDouble :
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpConvIntToFloat16 :
case glslang : : EOpConvInt64ToFloat16 :
# endif
2015-06-26 22:58:36 +00:00
convOp = spv : : OpConvertSToF ;
break ;
case glslang : : EOpConvUintToFloat :
case glslang : : EOpConvUintToDouble :
2016-04-22 08:51:45 +00:00
case glslang : : EOpConvUint64ToFloat :
case glslang : : EOpConvUint64ToDouble :
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpConvUintToFloat16 :
case glslang : : EOpConvUint64ToFloat16 :
# endif
2015-06-26 22:58:36 +00:00
convOp = spv : : OpConvertUToF ;
break ;
case glslang : : EOpConvDoubleToFloat :
case glslang : : EOpConvFloatToDouble :
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpConvDoubleToFloat16 :
case glslang : : EOpConvFloat16ToDouble :
case glslang : : EOpConvFloatToFloat16 :
case glslang : : EOpConvFloat16ToFloat :
# endif
2015-06-26 22:58:36 +00:00
convOp = spv : : OpFConvert ;
2016-04-27 10:48:17 +00:00
if ( builder . isMatrixType ( destType ) )
return createUnaryMatrixOperation ( convOp , precision , noContraction , destType , operand , typeProxy ) ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpConvFloatToInt :
case glslang : : EOpConvDoubleToInt :
2016-04-22 08:51:45 +00:00
case glslang : : EOpConvFloatToInt64 :
case glslang : : EOpConvDoubleToInt64 :
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpConvFloat16ToInt :
case glslang : : EOpConvFloat16ToInt64 :
# endif
2015-06-26 22:58:36 +00:00
convOp = spv : : OpConvertFToS ;
break ;
case glslang : : EOpConvUintToInt :
case glslang : : EOpConvIntToUint :
2016-04-22 08:51:45 +00:00
case glslang : : EOpConvUint64ToInt64 :
case glslang : : EOpConvInt64ToUint64 :
2016-04-07 19:40:27 +00:00
if ( builder . isInSpecConstCodeGenMode ( ) ) {
// Build zero scalar or vector for OpIAdd.
2016-09-05 08:10:14 +00:00
zero = ( op = = glslang : : EOpConvUint64ToInt64 | |
op = = glslang : : EOpConvInt64ToUint64 ) ? builder . makeUint64Constant ( 0 ) : builder . makeUintConstant ( 0 ) ;
2016-04-13 03:16:20 +00:00
zero = makeSmearedConstant ( zero , vectorSize ) ;
2016-04-07 19:40:27 +00:00
// Use OpIAdd, instead of OpBitcast to do the conversion when
// generating for OpSpecConstantOp instruction.
return builder . createBinOp ( spv : : OpIAdd , destType , operand , zero ) ;
}
// For normal run-time conversion instruction, use OpBitcast.
2015-06-26 22:58:36 +00:00
convOp = spv : : OpBitcast ;
break ;
case glslang : : EOpConvFloatToUint :
case glslang : : EOpConvDoubleToUint :
2016-04-22 08:51:45 +00:00
case glslang : : EOpConvFloatToUint64 :
case glslang : : EOpConvDoubleToUint64 :
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpConvFloat16ToUint :
case glslang : : EOpConvFloat16ToUint64 :
# endif
2015-06-26 22:58:36 +00:00
convOp = spv : : OpConvertFToU ;
break ;
2016-04-22 08:51:45 +00:00
case glslang : : EOpConvIntToInt64 :
case glslang : : EOpConvInt64ToInt :
convOp = spv : : OpSConvert ;
break ;
case glslang : : EOpConvUintToUint64 :
case glslang : : EOpConvUint64ToUint :
convOp = spv : : OpUConvert ;
break ;
case glslang : : EOpConvIntToUint64 :
case glslang : : EOpConvInt64ToUint :
case glslang : : EOpConvUint64ToInt :
case glslang : : EOpConvUintToInt64 :
// OpSConvert/OpUConvert + OpBitCast
switch ( op ) {
case glslang : : EOpConvIntToUint64 :
convOp = spv : : OpSConvert ;
type = builder . makeIntType ( 64 ) ;
break ;
case glslang : : EOpConvInt64ToUint :
convOp = spv : : OpSConvert ;
type = builder . makeIntType ( 32 ) ;
break ;
case glslang : : EOpConvUint64ToInt :
convOp = spv : : OpUConvert ;
type = builder . makeUintType ( 32 ) ;
break ;
case glslang : : EOpConvUintToInt64 :
convOp = spv : : OpUConvert ;
type = builder . makeUintType ( 64 ) ;
break ;
default :
assert ( 0 ) ;
break ;
}
if ( vectorSize > 0 )
type = builder . makeVectorType ( type , vectorSize ) ;
operand = builder . createUnaryOp ( convOp , type , operand ) ;
if ( builder . isInSpecConstCodeGenMode ( ) ) {
// Build zero scalar or vector for OpIAdd.
zero = ( op = = glslang : : EOpConvIntToUint64 | |
op = = glslang : : EOpConvUintToInt64 ) ? builder . makeUint64Constant ( 0 ) : builder . makeUintConstant ( 0 ) ;
zero = makeSmearedConstant ( zero , vectorSize ) ;
// Use OpIAdd, instead of OpBitcast to do the conversion when
// generating for OpSpecConstantOp instruction.
return builder . createBinOp ( spv : : OpIAdd , destType , operand , zero ) ;
}
// For normal run-time conversion instruction, use OpBitcast.
convOp = spv : : OpBitcast ;
break ;
2015-06-26 22:58:36 +00:00
default :
break ;
}
spv : : Id result = 0 ;
if ( convOp = = spv : : OpNop )
return result ;
if ( convOp = = spv : : OpSelect ) {
zero = makeSmearedConstant ( zero , vectorSize ) ;
one = makeSmearedConstant ( one , vectorSize ) ;
result = builder . createTriOp ( convOp , destType , operand , one , zero ) ;
} else
result = builder . createUnaryOp ( convOp , destType , operand ) ;
2016-02-02 19:37:46 +00:00
return builder . setPrecision ( result , precision ) ;
2015-06-26 22:58:36 +00:00
}
spv : : Id TGlslangToSpvTraverser : : makeSmearedConstant ( spv : : Id constant , int vectorSize )
{
if ( vectorSize = = 0 )
return constant ;
spv : : Id vectorTypeId = builder . makeVectorType ( builder . getTypeId ( constant ) , vectorSize ) ;
std : : vector < spv : : Id > components ;
for ( int c = 0 ; c < vectorSize ; + + c )
components . push_back ( constant ) ;
return builder . makeCompositeConstant ( vectorTypeId , components ) ;
}
2015-07-23 16:22:48 +00:00
// For glslang ops that map to SPV atomic opCodes
2016-02-16 03:58:50 +00:00
spv : : Id TGlslangToSpvTraverser : : createAtomicOperation ( glslang : : TOperator op , spv : : Decoration /*precision*/ , spv : : Id typeId , std : : vector < spv : : Id > & operands , glslang : : TBasicType typeProxy )
2015-07-23 16:22:48 +00:00
{
spv : : Op opCode = spv : : OpNop ;
switch ( op ) {
case glslang : : EOpAtomicAdd :
2015-09-09 08:42:49 +00:00
case glslang : : EOpImageAtomicAdd :
2015-07-23 16:22:48 +00:00
opCode = spv : : OpAtomicIAdd ;
break ;
case glslang : : EOpAtomicMin :
2015-09-09 08:42:49 +00:00
case glslang : : EOpImageAtomicMin :
2015-09-16 03:44:02 +00:00
opCode = typeProxy = = glslang : : EbtUint ? spv : : OpAtomicUMin : spv : : OpAtomicSMin ;
2015-07-23 16:22:48 +00:00
break ;
case glslang : : EOpAtomicMax :
2015-09-09 08:42:49 +00:00
case glslang : : EOpImageAtomicMax :
2015-09-16 03:44:02 +00:00
opCode = typeProxy = = glslang : : EbtUint ? spv : : OpAtomicUMax : spv : : OpAtomicSMax ;
2015-07-23 16:22:48 +00:00
break ;
case glslang : : EOpAtomicAnd :
2015-09-09 08:42:49 +00:00
case glslang : : EOpImageAtomicAnd :
2015-07-23 16:22:48 +00:00
opCode = spv : : OpAtomicAnd ;
break ;
case glslang : : EOpAtomicOr :
2015-09-09 08:42:49 +00:00
case glslang : : EOpImageAtomicOr :
2015-07-23 16:22:48 +00:00
opCode = spv : : OpAtomicOr ;
break ;
case glslang : : EOpAtomicXor :
2015-09-09 08:42:49 +00:00
case glslang : : EOpImageAtomicXor :
2015-07-23 16:22:48 +00:00
opCode = spv : : OpAtomicXor ;
break ;
case glslang : : EOpAtomicExchange :
2015-09-09 08:42:49 +00:00
case glslang : : EOpImageAtomicExchange :
2015-07-23 16:22:48 +00:00
opCode = spv : : OpAtomicExchange ;
break ;
case glslang : : EOpAtomicCompSwap :
2015-09-09 08:42:49 +00:00
case glslang : : EOpImageAtomicCompSwap :
2015-07-23 16:22:48 +00:00
opCode = spv : : OpAtomicCompareExchange ;
break ;
case glslang : : EOpAtomicCounterIncrement :
opCode = spv : : OpAtomicIIncrement ;
break ;
case glslang : : EOpAtomicCounterDecrement :
opCode = spv : : OpAtomicIDecrement ;
break ;
case glslang : : EOpAtomicCounter :
opCode = spv : : OpAtomicLoad ;
break ;
default :
2015-11-16 04:33:39 +00:00
assert ( 0 ) ;
2015-07-23 16:22:48 +00:00
break ;
}
// Sort out the operands
// - mapping from glslang -> SPV
// - there are extra SPV operands with no glslang source
2015-09-15 04:45:16 +00:00
// - compare-exchange swaps the value and comparator
// - compare-exchange has an extra memory semantics
2015-07-23 16:22:48 +00:00
std : : vector < spv : : Id > spvAtomicOperands ; // hold the spv operands
auto opIt = operands . begin ( ) ; // walk the glslang operands
spvAtomicOperands . push_back ( * ( opIt + + ) ) ;
2015-09-16 03:44:02 +00:00
spvAtomicOperands . push_back ( builder . makeUintConstant ( spv : : ScopeDevice ) ) ; // TBD: what is the correct scope?
spvAtomicOperands . push_back ( builder . makeUintConstant ( spv : : MemorySemanticsMaskNone ) ) ; // TBD: what are the correct memory semantics?
if ( opCode = = spv : : OpAtomicCompareExchange ) {
2015-09-16 05:20:37 +00:00
// There are 2 memory semantics for compare-exchange. And the operand order of "comparator" and "new value" in GLSL
// differs from that in SPIR-V. Hence, special processing is required.
2015-09-16 03:44:02 +00:00
spvAtomicOperands . push_back ( builder . makeUintConstant ( spv : : MemorySemanticsMaskNone ) ) ;
2015-09-15 04:45:16 +00:00
spvAtomicOperands . push_back ( * ( opIt + 1 ) ) ;
spvAtomicOperands . push_back ( * opIt ) ;
opIt + = 2 ;
2015-09-16 03:44:02 +00:00
}
2015-07-23 16:22:48 +00:00
2015-09-15 04:45:16 +00:00
// Add the rest of the operands, skipping any that were dealt with above.
2015-07-23 16:22:48 +00:00
for ( ; opIt ! = operands . end ( ) ; + + opIt )
spvAtomicOperands . push_back ( * opIt ) ;
return builder . createOp ( opCode , typeId , spvAtomicOperands ) ;
}
2016-05-05 22:45:40 +00:00
// Create group invocation operations.
2016-09-21 10:56:12 +00:00
spv : : Id TGlslangToSpvTraverser : : createInvocationsOperation ( glslang : : TOperator op , spv : : Id typeId , std : : vector < spv : : Id > & operands , glslang : : TBasicType typeProxy )
2016-05-05 22:45:40 +00:00
{
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
2016-11-09 18:49:24 +00:00
bool isUnsigned = typeProxy = = glslang : : EbtUint | | typeProxy = = glslang : : EbtUint64 ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
bool isFloat = typeProxy = = glslang : : EbtFloat | | typeProxy = = glslang : : EbtDouble | | typeProxy = = glslang : : EbtFloat16 ;
# endif
2016-05-05 04:30:44 +00:00
2016-09-21 10:56:12 +00:00
spv : : Op opCode = spv : : OpNop ;
2016-05-05 22:45:40 +00:00
2016-09-21 10:56:12 +00:00
std : : vector < spv : : Id > spvGroupOperands ;
if ( op = = glslang : : EOpBallot | | op = = glslang : : EOpReadFirstInvocation ) {
builder . addExtension ( spv : : E_SPV_KHR_shader_ballot ) ;
builder . addCapability ( spv : : CapabilitySubgroupBallotKHR ) ;
} else {
builder . addCapability ( spv : : CapabilityGroups ) ;
2016-10-19 14:16:29 +00:00
# ifdef AMD_EXTENSIONS
2016-10-14 09:41:45 +00:00
if ( op = = glslang : : EOpMinInvocationsNonUniform | |
op = = glslang : : EOpMaxInvocationsNonUniform | |
op = = glslang : : EOpAddInvocationsNonUniform )
builder . addExtension ( spv : : E_SPV_AMD_shader_ballot ) ;
2016-10-19 14:16:29 +00:00
# endif
2016-09-21 10:56:12 +00:00
spvGroupOperands . push_back ( builder . makeUintConstant ( spv : : ScopeSubgroup ) ) ;
2016-05-05 04:30:44 +00:00
# ifdef AMD_EXTENSIONS
2016-09-21 10:56:12 +00:00
if ( op = = glslang : : EOpMinInvocations | | op = = glslang : : EOpMaxInvocations | | op = = glslang : : EOpAddInvocations | |
op = = glslang : : EOpMinInvocationsNonUniform | | op = = glslang : : EOpMaxInvocationsNonUniform | | op = = glslang : : EOpAddInvocationsNonUniform )
spvGroupOperands . push_back ( spv : : GroupOperationReduce ) ;
2016-05-05 04:30:44 +00:00
# endif
2016-09-21 10:56:12 +00:00
}
for ( auto opIt = operands . begin ( ) ; opIt ! = operands . end ( ) ; + + opIt )
spvGroupOperands . push_back ( * opIt ) ;
2016-05-05 22:45:40 +00:00
switch ( op ) {
case glslang : : EOpAnyInvocation :
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupAny ;
break ;
2016-05-05 22:45:40 +00:00
case glslang : : EOpAllInvocations :
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupAll ;
break ;
2016-05-05 22:45:40 +00:00
case glslang : : EOpAllInvocationsEqual :
{
2016-09-21 10:56:12 +00:00
spv : : Id groupAll = builder . createOp ( spv : : OpGroupAll , typeId , spvGroupOperands ) ;
spv : : Id groupAny = builder . createOp ( spv : : OpGroupAny , typeId , spvGroupOperands ) ;
2016-05-05 22:45:40 +00:00
return builder . createBinOp ( spv : : OpLogicalOr , typeId , groupAll ,
builder . createUnaryOp ( spv : : OpLogicalNot , typeId , groupAny ) ) ;
}
2016-09-21 10:56:12 +00:00
case glslang : : EOpReadInvocation :
opCode = spv : : OpGroupBroadcast ;
2016-09-26 07:53:40 +00:00
if ( builder . isVectorType ( typeId ) )
return CreateInvocationsVectorOperation ( opCode , typeId , operands ) ;
2016-09-21 10:56:12 +00:00
break ;
case glslang : : EOpReadFirstInvocation :
opCode = spv : : OpSubgroupFirstInvocationKHR ;
break ;
case glslang : : EOpBallot :
{
// NOTE: According to the spec, the result type of "OpSubgroupBallotKHR" must be a 4 component vector of 32
// bit integer types. The GLSL built-in function "ballotARB()" assumes the maximum number of invocations in
// a subgroup is 64. Thus, we have to convert uvec4.xy to uint64_t as follow:
//
// result = Bitcast(SubgroupBallotKHR(Predicate).xy)
//
spv : : Id uintType = builder . makeUintType ( 32 ) ;
spv : : Id uvec4Type = builder . makeVectorType ( uintType , 4 ) ;
spv : : Id result = builder . createOp ( spv : : OpSubgroupBallotKHR , uvec4Type , spvGroupOperands ) ;
std : : vector < spv : : Id > components ;
components . push_back ( builder . createCompositeExtract ( result , uintType , 0 ) ) ;
components . push_back ( builder . createCompositeExtract ( result , uintType , 1 ) ) ;
spv : : Id uvec2Type = builder . makeVectorType ( uintType , 2 ) ;
return builder . createUnaryOp ( spv : : OpBitcast , typeId ,
builder . createCompositeConstruct ( uvec2Type , components ) ) ;
}
2016-05-05 04:30:44 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpMinInvocations :
case glslang : : EOpMaxInvocations :
case glslang : : EOpAddInvocations :
if ( op = = glslang : : EOpMinInvocations ) {
if ( isFloat )
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupFMin ;
2016-05-05 04:30:44 +00:00
else {
if ( isUnsigned )
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupUMin ;
2016-05-05 04:30:44 +00:00
else
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupSMin ;
2016-05-05 04:30:44 +00:00
}
} else if ( op = = glslang : : EOpMaxInvocations ) {
if ( isFloat )
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupFMax ;
2016-05-05 04:30:44 +00:00
else {
if ( isUnsigned )
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupUMax ;
2016-05-05 04:30:44 +00:00
else
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupSMax ;
2016-05-05 04:30:44 +00:00
}
} else {
if ( isFloat )
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupFAdd ;
2016-05-05 04:30:44 +00:00
else
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupIAdd ;
2016-05-05 04:30:44 +00:00
}
2016-08-23 07:41:05 +00:00
if ( builder . isVectorType ( typeId ) )
2016-09-26 07:53:40 +00:00
return CreateInvocationsVectorOperation ( opCode , typeId , operands ) ;
2016-09-21 10:56:12 +00:00
break ;
2016-05-05 04:30:44 +00:00
case glslang : : EOpMinInvocationsNonUniform :
case glslang : : EOpMaxInvocationsNonUniform :
case glslang : : EOpAddInvocationsNonUniform :
if ( op = = glslang : : EOpMinInvocationsNonUniform ) {
if ( isFloat )
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupFMinNonUniformAMD ;
2016-05-05 04:30:44 +00:00
else {
if ( isUnsigned )
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupUMinNonUniformAMD ;
2016-05-05 04:30:44 +00:00
else
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupSMinNonUniformAMD ;
2016-05-05 04:30:44 +00:00
}
}
else if ( op = = glslang : : EOpMaxInvocationsNonUniform ) {
if ( isFloat )
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupFMaxNonUniformAMD ;
2016-05-05 04:30:44 +00:00
else {
if ( isUnsigned )
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupUMaxNonUniformAMD ;
2016-05-05 04:30:44 +00:00
else
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupSMaxNonUniformAMD ;
2016-05-05 04:30:44 +00:00
}
}
else {
if ( isFloat )
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupFAddNonUniformAMD ;
2016-05-05 04:30:44 +00:00
else
2016-09-21 10:56:12 +00:00
opCode = spv : : OpGroupIAddNonUniformAMD ;
2016-05-05 04:30:44 +00:00
}
2016-08-23 07:41:05 +00:00
if ( builder . isVectorType ( typeId ) )
2016-09-26 07:53:40 +00:00
return CreateInvocationsVectorOperation ( opCode , typeId , operands ) ;
2016-09-21 10:56:12 +00:00
break ;
2016-05-05 04:30:44 +00:00
# endif
2016-05-05 22:45:40 +00:00
default :
logger - > missingFunctionality ( " invocation operation " ) ;
return spv : : NoResult ;
}
2016-09-21 10:56:12 +00:00
assert ( opCode ! = spv : : OpNop ) ;
return builder . createOp ( opCode , typeId , spvGroupOperands ) ;
2016-05-05 22:45:40 +00:00
}
2016-08-23 07:41:05 +00:00
// Create group invocation operations on a vector
2016-09-26 07:53:40 +00:00
spv : : Id TGlslangToSpvTraverser : : CreateInvocationsVectorOperation ( spv : : Op op , spv : : Id typeId , std : : vector < spv : : Id > & operands )
2016-08-23 07:41:05 +00:00
{
2016-09-26 07:53:40 +00:00
# ifdef AMD_EXTENSIONS
2016-08-23 07:41:05 +00:00
assert ( op = = spv : : OpGroupFMin | | op = = spv : : OpGroupUMin | | op = = spv : : OpGroupSMin | |
op = = spv : : OpGroupFMax | | op = = spv : : OpGroupUMax | | op = = spv : : OpGroupSMax | |
2016-09-26 07:53:40 +00:00
op = = spv : : OpGroupFAdd | | op = = spv : : OpGroupIAdd | | op = = spv : : OpGroupBroadcast | |
2016-08-23 07:41:05 +00:00
op = = spv : : OpGroupFMinNonUniformAMD | | op = = spv : : OpGroupUMinNonUniformAMD | | op = = spv : : OpGroupSMinNonUniformAMD | |
op = = spv : : OpGroupFMaxNonUniformAMD | | op = = spv : : OpGroupUMaxNonUniformAMD | | op = = spv : : OpGroupSMaxNonUniformAMD | |
op = = spv : : OpGroupFAddNonUniformAMD | | op = = spv : : OpGroupIAddNonUniformAMD ) ;
2016-09-26 07:53:40 +00:00
# else
assert ( op = = spv : : OpGroupFMin | | op = = spv : : OpGroupUMin | | op = = spv : : OpGroupSMin | |
op = = spv : : OpGroupFMax | | op = = spv : : OpGroupUMax | | op = = spv : : OpGroupSMax | |
op = = spv : : OpGroupFAdd | | op = = spv : : OpGroupIAdd | | op = = spv : : OpGroupBroadcast ) ;
# endif
2016-08-23 07:41:05 +00:00
// Handle group invocation operations scalar by scalar.
// The result type is the same type as the original type.
// The algorithm is to:
// - break the vector into scalars
// - apply the operation to each scalar
// - make a vector out the scalar results
// get the types sorted out
2016-09-26 07:53:40 +00:00
int numComponents = builder . getNumComponents ( operands [ 0 ] ) ;
spv : : Id scalarType = builder . getScalarTypeId ( builder . getTypeId ( operands [ 0 ] ) ) ;
2016-08-23 07:41:05 +00:00
std : : vector < spv : : Id > results ;
// do each scalar op
for ( int comp = 0 ; comp < numComponents ; + + comp ) {
std : : vector < unsigned int > indexes ;
indexes . push_back ( comp ) ;
2016-09-26 07:53:40 +00:00
spv : : Id scalar = builder . createCompositeExtract ( operands [ 0 ] , scalarType , indexes ) ;
2016-08-23 07:41:05 +00:00
2016-09-26 07:53:40 +00:00
std : : vector < spv : : Id > spvGroupOperands ;
spvGroupOperands . push_back ( builder . makeUintConstant ( spv : : ScopeSubgroup ) ) ;
if ( op = = spv : : OpGroupBroadcast ) {
spvGroupOperands . push_back ( scalar ) ;
spvGroupOperands . push_back ( operands [ 1 ] ) ;
} else {
spvGroupOperands . push_back ( spv : : GroupOperationReduce ) ;
spvGroupOperands . push_back ( scalar ) ;
}
2016-08-23 07:41:05 +00:00
2016-09-26 07:53:40 +00:00
results . push_back ( builder . createOp ( op , scalarType , spvGroupOperands ) ) ;
2016-08-23 07:41:05 +00:00
}
// put the pieces together
return builder . createCompositeConstruct ( typeId , results ) ;
}
2015-08-07 04:53:06 +00:00
spv : : Id TGlslangToSpvTraverser : : createMiscOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id typeId , std : : vector < spv : : Id > & operands , glslang : : TBasicType typeProxy )
2015-06-26 22:58:36 +00:00
{
2016-04-22 08:51:45 +00:00
bool isUnsigned = typeProxy = = glslang : : EbtUint | | typeProxy = = glslang : : EbtUint64 ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
bool isFloat = typeProxy = = glslang : : EbtFloat | | typeProxy = = glslang : : EbtDouble | | typeProxy = = glslang : : EbtFloat16 ;
# else
2015-08-07 04:53:06 +00:00
bool isFloat = typeProxy = = glslang : : EbtFloat | | typeProxy = = glslang : : EbtDouble ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# endif
2015-08-07 04:53:06 +00:00
2015-06-26 22:58:36 +00:00
spv : : Op opCode = spv : : OpNop ;
2016-05-05 04:30:44 +00:00
int extBuiltins = - 1 ;
2015-06-26 22:58:36 +00:00
int libCall = - 1 ;
2016-01-06 18:41:02 +00:00
size_t consumedOperands = operands . size ( ) ;
2015-11-16 04:33:39 +00:00
spv : : Id typeId0 = 0 ;
if ( consumedOperands > 0 )
typeId0 = builder . getTypeId ( operands [ 0 ] ) ;
spv : : Id frexpIntType = 0 ;
2015-06-26 22:58:36 +00:00
switch ( op ) {
case glslang : : EOpMin :
2015-08-07 04:53:06 +00:00
if ( isFloat )
libCall = spv : : GLSLstd450FMin ;
else if ( isUnsigned )
libCall = spv : : GLSLstd450UMin ;
else
libCall = spv : : GLSLstd450SMin ;
2015-12-13 20:34:37 +00:00
builder . promoteScalar ( precision , operands . front ( ) , operands . back ( ) ) ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpModf :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Modf ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpMax :
2015-08-07 04:53:06 +00:00
if ( isFloat )
libCall = spv : : GLSLstd450FMax ;
else if ( isUnsigned )
libCall = spv : : GLSLstd450UMax ;
else
libCall = spv : : GLSLstd450SMax ;
2015-12-13 20:34:37 +00:00
builder . promoteScalar ( precision , operands . front ( ) , operands . back ( ) ) ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpPow :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Pow ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpDot :
opCode = spv : : OpDot ;
break ;
case glslang : : EOpAtan :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Atan2 ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpClamp :
2015-08-07 04:53:06 +00:00
if ( isFloat )
libCall = spv : : GLSLstd450FClamp ;
else if ( isUnsigned )
libCall = spv : : GLSLstd450UClamp ;
else
libCall = spv : : GLSLstd450SClamp ;
2015-12-13 20:34:37 +00:00
builder . promoteScalar ( precision , operands . front ( ) , operands [ 1 ] ) ;
builder . promoteScalar ( precision , operands . front ( ) , operands [ 2 ] ) ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpMix :
2016-03-15 04:08:31 +00:00
if ( ! builder . isBoolType ( builder . getScalarTypeId ( builder . getTypeId ( operands . back ( ) ) ) ) ) {
assert ( isFloat ) ;
2015-11-16 04:33:39 +00:00
libCall = spv : : GLSLstd450FMix ;
2016-03-15 04:08:31 +00:00
} else {
2016-02-16 03:58:50 +00:00
opCode = spv : : OpSelect ;
2016-03-15 04:08:31 +00:00
std : : swap ( operands . front ( ) , operands . back ( ) ) ;
2016-02-16 03:58:50 +00:00
}
2015-12-13 20:34:37 +00:00
builder . promoteScalar ( precision , operands . front ( ) , operands . back ( ) ) ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpStep :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Step ;
2015-12-13 20:34:37 +00:00
builder . promoteScalar ( precision , operands . front ( ) , operands . back ( ) ) ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpSmoothStep :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450SmoothStep ;
2015-12-13 20:34:37 +00:00
builder . promoteScalar ( precision , operands [ 0 ] , operands [ 2 ] ) ;
builder . promoteScalar ( precision , operands [ 1 ] , operands [ 2 ] ) ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpDistance :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Distance ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpCross :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Cross ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpFaceForward :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450FaceForward ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpReflect :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Reflect ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EOpRefract :
2015-08-07 04:53:06 +00:00
libCall = spv : : GLSLstd450Refract ;
2015-06-26 22:58:36 +00:00
break ;
2015-12-08 09:12:09 +00:00
case glslang : : EOpInterpolateAtSample :
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityInterpolationFunction ) ;
2015-12-08 09:12:09 +00:00
libCall = spv : : GLSLstd450InterpolateAtSample ;
break ;
case glslang : : EOpInterpolateAtOffset :
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityInterpolationFunction ) ;
2015-12-08 09:12:09 +00:00
libCall = spv : : GLSLstd450InterpolateAtOffset ;
break ;
2015-11-16 04:33:39 +00:00
case glslang : : EOpAddCarry :
opCode = spv : : OpIAddCarry ;
typeId = builder . makeStructResultType ( typeId0 , typeId0 ) ;
consumedOperands = 2 ;
break ;
case glslang : : EOpSubBorrow :
opCode = spv : : OpISubBorrow ;
typeId = builder . makeStructResultType ( typeId0 , typeId0 ) ;
consumedOperands = 2 ;
break ;
case glslang : : EOpUMulExtended :
opCode = spv : : OpUMulExtended ;
typeId = builder . makeStructResultType ( typeId0 , typeId0 ) ;
consumedOperands = 2 ;
break ;
case glslang : : EOpIMulExtended :
opCode = spv : : OpSMulExtended ;
typeId = builder . makeStructResultType ( typeId0 , typeId0 ) ;
consumedOperands = 2 ;
break ;
case glslang : : EOpBitfieldExtract :
if ( isUnsigned )
opCode = spv : : OpBitFieldUExtract ;
else
opCode = spv : : OpBitFieldSExtract ;
break ;
case glslang : : EOpBitfieldInsert :
opCode = spv : : OpBitFieldInsert ;
break ;
case glslang : : EOpFma :
libCall = spv : : GLSLstd450Fma ;
break ;
case glslang : : EOpFrexp :
libCall = spv : : GLSLstd450FrexpStruct ;
if ( builder . getNumComponents ( operands [ 0 ] ) = = 1 )
frexpIntType = builder . makeIntegerType ( 32 , true ) ;
else
frexpIntType = builder . makeVectorType ( builder . makeIntegerType ( 32 , true ) , builder . getNumComponents ( operands [ 0 ] ) ) ;
typeId = builder . makeStructResultType ( typeId0 , frexpIntType ) ;
consumedOperands = 1 ;
break ;
case glslang : : EOpLdexp :
libCall = spv : : GLSLstd450Ldexp ;
break ;
2016-04-14 08:53:07 +00:00
case glslang : : EOpReadInvocation :
2016-09-21 10:56:12 +00:00
return createInvocationsOperation ( op , typeId , operands , typeProxy ) ;
2016-04-14 08:53:07 +00:00
2016-05-05 04:30:44 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpSwizzleInvocations :
extBuiltins = getExtBuiltins ( spv : : E_SPV_AMD_shader_ballot ) ;
libCall = spv : : SwizzleInvocationsAMD ;
break ;
case glslang : : EOpSwizzleInvocationsMasked :
extBuiltins = getExtBuiltins ( spv : : E_SPV_AMD_shader_ballot ) ;
libCall = spv : : SwizzleInvocationsMaskedAMD ;
break ;
case glslang : : EOpWriteInvocation :
extBuiltins = getExtBuiltins ( spv : : E_SPV_AMD_shader_ballot ) ;
libCall = spv : : WriteInvocationAMD ;
break ;
case glslang : : EOpMin3 :
extBuiltins = getExtBuiltins ( spv : : E_SPV_AMD_shader_trinary_minmax ) ;
if ( isFloat )
libCall = spv : : FMin3AMD ;
else {
if ( isUnsigned )
libCall = spv : : UMin3AMD ;
else
libCall = spv : : SMin3AMD ;
}
break ;
case glslang : : EOpMax3 :
extBuiltins = getExtBuiltins ( spv : : E_SPV_AMD_shader_trinary_minmax ) ;
if ( isFloat )
libCall = spv : : FMax3AMD ;
else {
if ( isUnsigned )
libCall = spv : : UMax3AMD ;
else
libCall = spv : : SMax3AMD ;
}
break ;
case glslang : : EOpMid3 :
extBuiltins = getExtBuiltins ( spv : : E_SPV_AMD_shader_trinary_minmax ) ;
if ( isFloat )
libCall = spv : : FMid3AMD ;
else {
if ( isUnsigned )
libCall = spv : : UMid3AMD ;
else
libCall = spv : : SMid3AMD ;
}
break ;
case glslang : : EOpInterpolateAtVertex :
extBuiltins = getExtBuiltins ( spv : : E_SPV_AMD_shader_explicit_vertex_parameter ) ;
libCall = spv : : InterpolateAtVertexAMD ;
break ;
# endif
2015-06-26 22:58:36 +00:00
default :
return 0 ;
}
spv : : Id id = 0 ;
2015-12-07 02:29:11 +00:00
if ( libCall > = 0 ) {
2015-12-07 21:17:06 +00:00
// Use an extended instruction from the standard library.
// Construct the call arguments, without modifying the original operands vector.
// We might need the remaining arguments, e.g. in the EOpFrexp case.
std : : vector < spv : : Id > callArguments ( operands . begin ( ) , operands . begin ( ) + consumedOperands ) ;
2016-05-05 04:30:44 +00:00
id = builder . createBuiltinCall ( typeId , extBuiltins > = 0 ? extBuiltins : stdBuiltins , libCall , callArguments ) ;
2015-12-07 02:29:11 +00:00
} else {
2015-11-16 04:33:39 +00:00
switch ( consumedOperands ) {
2015-06-26 22:58:36 +00:00
case 0 :
// should all be handled by visitAggregate and createNoArgOperation
assert ( 0 ) ;
return 0 ;
case 1 :
// should all be handled by createUnaryOperation
assert ( 0 ) ;
return 0 ;
case 2 :
id = builder . createBinOp ( opCode , typeId , operands [ 0 ] , operands [ 1 ] ) ;
break ;
default :
2015-11-16 04:33:39 +00:00
// anything 3 or over doesn't have l-value operands, so all should be consumed
assert ( consumedOperands = = operands . size ( ) ) ;
id = builder . createOp ( opCode , typeId , operands ) ;
2015-06-26 22:58:36 +00:00
break ;
}
}
2015-11-16 04:33:39 +00:00
// Decode the return types that were structures
switch ( op ) {
case glslang : : EOpAddCarry :
case glslang : : EOpSubBorrow :
builder . createStore ( builder . createCompositeExtract ( id , typeId0 , 1 ) , operands [ 2 ] ) ;
id = builder . createCompositeExtract ( id , typeId0 , 0 ) ;
break ;
case glslang : : EOpUMulExtended :
case glslang : : EOpIMulExtended :
builder . createStore ( builder . createCompositeExtract ( id , typeId0 , 0 ) , operands [ 3 ] ) ;
builder . createStore ( builder . createCompositeExtract ( id , typeId0 , 1 ) , operands [ 2 ] ) ;
break ;
case glslang : : EOpFrexp :
2015-12-07 21:17:06 +00:00
assert ( operands . size ( ) = = 2 ) ;
2015-11-16 04:33:39 +00:00
builder . createStore ( builder . createCompositeExtract ( id , frexpIntType , 1 ) , operands [ 1 ] ) ;
id = builder . createCompositeExtract ( id , typeId0 , 0 ) ;
break ;
default :
break ;
}
2016-02-02 19:37:46 +00:00
return builder . setPrecision ( id , precision ) ;
2015-06-26 22:58:36 +00:00
}
2016-05-05 04:30:44 +00:00
// Intrinsics with no arguments (or no return value, and no precision).
spv : : Id TGlslangToSpvTraverser : : createNoArgOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id typeId )
2015-06-26 22:58:36 +00:00
{
// TODO: get the barrier operands correct
switch ( op ) {
case glslang : : EOpEmitVertex :
builder . createNoResultOp ( spv : : OpEmitVertex ) ;
return 0 ;
case glslang : : EOpEndPrimitive :
builder . createNoResultOp ( spv : : OpEndPrimitive ) ;
return 0 ;
case glslang : : EOpBarrier :
2016-11-14 09:10:05 +00:00
builder . createControlBarrier ( spv : : ScopeWorkgroup , spv : : ScopeDevice , spv : : MemorySemanticsMaskNone ) ;
2015-06-26 22:58:36 +00:00
return 0 ;
case glslang : : EOpMemoryBarrier :
2015-08-07 04:53:06 +00:00
builder . createMemoryBarrier ( spv : : ScopeDevice , spv : : MemorySemanticsAllMemory ) ;
2015-06-26 22:58:36 +00:00
return 0 ;
case glslang : : EOpMemoryBarrierAtomicCounter :
2015-08-07 04:53:06 +00:00
builder . createMemoryBarrier ( spv : : ScopeDevice , spv : : MemorySemanticsAtomicCounterMemoryMask ) ;
2015-06-26 22:58:36 +00:00
return 0 ;
case glslang : : EOpMemoryBarrierBuffer :
2015-08-07 04:53:06 +00:00
builder . createMemoryBarrier ( spv : : ScopeDevice , spv : : MemorySemanticsUniformMemoryMask ) ;
2015-06-26 22:58:36 +00:00
return 0 ;
case glslang : : EOpMemoryBarrierImage :
2015-08-07 04:53:06 +00:00
builder . createMemoryBarrier ( spv : : ScopeDevice , spv : : MemorySemanticsImageMemoryMask ) ;
2015-06-26 22:58:36 +00:00
return 0 ;
case glslang : : EOpMemoryBarrierShared :
2015-11-16 04:33:39 +00:00
builder . createMemoryBarrier ( spv : : ScopeDevice , spv : : MemorySemanticsWorkgroupMemoryMask ) ;
2015-06-26 22:58:36 +00:00
return 0 ;
case glslang : : EOpGroupMemoryBarrier :
2015-11-16 04:33:39 +00:00
builder . createMemoryBarrier ( spv : : ScopeDevice , spv : : MemorySemanticsCrossWorkgroupMemoryMask ) ;
2015-06-26 22:58:36 +00:00
return 0 ;
2016-06-15 15:50:24 +00:00
case glslang : : EOpAllMemoryBarrierWithGroupSync :
// Control barrier with non-"None" semantic is also a memory barrier.
builder . createControlBarrier ( spv : : ScopeDevice , spv : : ScopeDevice , spv : : MemorySemanticsAllMemory ) ;
return 0 ;
case glslang : : EOpGroupMemoryBarrierWithGroupSync :
// Control barrier with non-"None" semantic is also a memory barrier.
builder . createControlBarrier ( spv : : ScopeDevice , spv : : ScopeDevice , spv : : MemorySemanticsCrossWorkgroupMemoryMask ) ;
return 0 ;
case glslang : : EOpWorkgroupMemoryBarrier :
builder . createMemoryBarrier ( spv : : ScopeWorkgroup , spv : : MemorySemanticsWorkgroupMemoryMask ) ;
return 0 ;
case glslang : : EOpWorkgroupMemoryBarrierWithGroupSync :
// Control barrier with non-"None" semantic is also a memory barrier.
builder . createControlBarrier ( spv : : ScopeWorkgroup , spv : : ScopeWorkgroup , spv : : MemorySemanticsWorkgroupMemoryMask ) ;
return 0 ;
2016-05-05 04:30:44 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EOpTime :
{
std : : vector < spv : : Id > args ; // Dummy arguments
spv : : Id id = builder . createBuiltinCall ( typeId , getExtBuiltins ( spv : : E_SPV_AMD_gcn_shader ) , spv : : TimeAMD , args ) ;
return builder . setPrecision ( id , precision ) ;
}
# endif
2015-06-26 22:58:36 +00:00
default :
2016-05-04 19:55:59 +00:00
logger - > missingFunctionality ( " unknown operation with no arguments " ) ;
2015-06-26 22:58:36 +00:00
return 0 ;
}
}
spv : : Id TGlslangToSpvTraverser : : getSymbolId ( const glslang : : TIntermSymbol * symbol )
{
2015-07-19 04:34:27 +00:00
auto iter = symbolValues . find ( symbol - > getId ( ) ) ;
2015-06-26 22:58:36 +00:00
spv : : Id id ;
if ( symbolValues . end ( ) ! = iter ) {
id = iter - > second ;
return id ;
}
// it was not found, create it
id = createSpvVariable ( symbol ) ;
symbolValues [ symbol - > getId ( ) ] = id ;
2016-06-29 07:03:44 +00:00
if ( symbol - > getBasicType ( ) ! = glslang : : EbtBlock ) {
2015-06-26 22:58:36 +00:00
addDecoration ( id , TranslatePrecisionDecoration ( symbol - > getType ( ) ) ) ;
2015-12-24 17:30:13 +00:00
addDecoration ( id , TranslateInterpolationDecoration ( symbol - > getType ( ) . getQualifier ( ) ) ) ;
2016-05-21 01:40:44 +00:00
addDecoration ( id , TranslateAuxiliaryStorageDecoration ( symbol - > getType ( ) . getQualifier ( ) ) ) ;
2016-02-16 03:58:50 +00:00
if ( symbol - > getType ( ) . getQualifier ( ) . hasSpecConstantId ( ) )
addDecoration ( id , spv : : DecorationSpecId , symbol - > getType ( ) . getQualifier ( ) . layoutSpecConstantId ) ;
2015-06-26 22:58:36 +00:00
if ( symbol - > getQualifier ( ) . hasIndex ( ) )
builder . addDecoration ( id , spv : : DecorationIndex , symbol - > getQualifier ( ) . layoutIndex ) ;
if ( symbol - > getQualifier ( ) . hasComponent ( ) )
builder . addDecoration ( id , spv : : DecorationComponent , symbol - > getQualifier ( ) . layoutComponent ) ;
if ( glslangIntermediate - > getXfbMode ( ) ) {
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityTransformFeedback ) ;
2015-06-26 22:58:36 +00:00
if ( symbol - > getQualifier ( ) . hasXfbStride ( ) )
2015-08-07 04:53:06 +00:00
builder . addDecoration ( id , spv : : DecorationXfbStride , symbol - > getQualifier ( ) . layoutXfbStride ) ;
2015-06-26 22:58:36 +00:00
if ( symbol - > getQualifier ( ) . hasXfbBuffer ( ) )
builder . addDecoration ( id , spv : : DecorationXfbBuffer , symbol - > getQualifier ( ) . layoutXfbBuffer ) ;
if ( symbol - > getQualifier ( ) . hasXfbOffset ( ) )
builder . addDecoration ( id , spv : : DecorationOffset , symbol - > getQualifier ( ) . layoutXfbOffset ) ;
}
2016-07-07 23:46:42 +00:00
// atomic counters use this:
if ( symbol - > getQualifier ( ) . hasOffset ( ) )
builder . addDecoration ( id , spv : : DecorationOffset , symbol - > getQualifier ( ) . layoutOffset ) ;
2015-06-26 22:58:36 +00:00
}
2016-05-18 16:09:17 +00:00
if ( symbol - > getQualifier ( ) . hasLocation ( ) )
builder . addDecoration ( id , spv : : DecorationLocation , symbol - > getQualifier ( ) . layoutLocation ) ;
2015-12-24 17:30:13 +00:00
addDecoration ( id , TranslateInvariantDecoration ( symbol - > getType ( ) . getQualifier ( ) ) ) ;
2016-03-04 05:29:11 +00:00
if ( symbol - > getQualifier ( ) . hasStream ( ) & & glslangIntermediate - > isMultiStream ( ) ) {
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityGeometryStreams ) ;
2015-06-26 22:58:36 +00:00
builder . addDecoration ( id , spv : : DecorationStream , symbol - > getQualifier ( ) . layoutStream ) ;
2016-02-01 20:45:25 +00:00
}
2015-06-26 22:58:36 +00:00
if ( symbol - > getQualifier ( ) . hasSet ( ) )
builder . addDecoration ( id , spv : : DecorationDescriptorSet , symbol - > getQualifier ( ) . layoutSet ) ;
2016-02-16 03:58:50 +00:00
else if ( IsDescriptorResource ( symbol - > getType ( ) ) ) {
// default to 0
builder . addDecoration ( id , spv : : DecorationDescriptorSet , 0 ) ;
}
2015-06-26 22:58:36 +00:00
if ( symbol - > getQualifier ( ) . hasBinding ( ) )
builder . addDecoration ( id , spv : : DecorationBinding , symbol - > getQualifier ( ) . layoutBinding ) ;
2016-02-16 03:58:50 +00:00
if ( symbol - > getQualifier ( ) . hasAttachment ( ) )
builder . addDecoration ( id , spv : : DecorationInputAttachmentIndex , symbol - > getQualifier ( ) . layoutAttachment ) ;
2015-06-26 22:58:36 +00:00
if ( glslangIntermediate - > getXfbMode ( ) ) {
2016-02-01 20:45:25 +00:00
builder . addCapability ( spv : : CapabilityTransformFeedback ) ;
2015-06-26 22:58:36 +00:00
if ( symbol - > getQualifier ( ) . hasXfbStride ( ) )
2015-08-07 04:53:06 +00:00
builder . addDecoration ( id , spv : : DecorationXfbStride , symbol - > getQualifier ( ) . layoutXfbStride ) ;
2015-06-26 22:58:36 +00:00
if ( symbol - > getQualifier ( ) . hasXfbBuffer ( ) )
builder . addDecoration ( id , spv : : DecorationXfbBuffer , symbol - > getQualifier ( ) . layoutXfbBuffer ) ;
}
2016-02-21 12:59:01 +00:00
if ( symbol - > getType ( ) . isImage ( ) ) {
std : : vector < spv : : Decoration > memory ;
TranslateMemoryDecoration ( symbol - > getType ( ) . getQualifier ( ) , memory ) ;
for ( unsigned int i = 0 ; i < memory . size ( ) ; + + i )
addDecoration ( id , memory [ i ] ) ;
}
2015-06-26 22:58:36 +00:00
// built-in variable decorations
2016-05-17 01:22:05 +00:00
spv : : BuiltIn builtIn = TranslateBuiltInDecoration ( symbol - > getQualifier ( ) . builtIn , false ) ;
2016-07-15 17:53:56 +00:00
if ( builtIn ! = spv : : BuiltInMax )
2016-02-01 20:45:25 +00:00
addDecoration ( id , spv : : DecorationBuiltIn , ( int ) builtIn ) ;
2015-06-26 22:58:36 +00:00
return id ;
}
2015-11-16 04:33:39 +00:00
// If 'dec' is valid, add no-operand decoration to an object
2015-06-26 22:58:36 +00:00
void TGlslangToSpvTraverser : : addDecoration ( spv : : Id id , spv : : Decoration dec )
{
2016-07-15 17:53:56 +00:00
if ( dec ! = spv : : DecorationMax )
2015-06-26 22:58:36 +00:00
builder . addDecoration ( id , dec ) ;
}
2015-11-16 04:33:39 +00:00
// If 'dec' is valid, add a one-operand decoration to an object
void TGlslangToSpvTraverser : : addDecoration ( spv : : Id id , spv : : Decoration dec , unsigned value )
{
2016-07-15 17:53:56 +00:00
if ( dec ! = spv : : DecorationMax )
2015-11-16 04:33:39 +00:00
builder . addDecoration ( id , dec , value ) ;
}
// If 'dec' is valid, add a no-operand decoration to a struct member
2015-06-26 22:58:36 +00:00
void TGlslangToSpvTraverser : : addMemberDecoration ( spv : : Id id , int member , spv : : Decoration dec )
{
2016-07-15 17:53:56 +00:00
if ( dec ! = spv : : DecorationMax )
2015-06-26 22:58:36 +00:00
builder . addMemberDecoration ( id , ( unsigned ) member , dec ) ;
}
2016-02-01 20:45:25 +00:00
// If 'dec' is valid, add a one-operand decoration to a struct member
void TGlslangToSpvTraverser : : addMemberDecoration ( spv : : Id id , int member , spv : : Decoration dec , unsigned value )
{
2016-07-15 17:53:56 +00:00
if ( dec ! = spv : : DecorationMax )
2016-02-01 20:45:25 +00:00
builder . addMemberDecoration ( id , ( unsigned ) member , dec , value ) ;
}
2015-11-16 04:33:39 +00:00
// Make a full tree of instructions to build a SPIR-V specialization constant,
2016-02-16 03:58:50 +00:00
// or regular constant if possible.
2015-11-16 04:33:39 +00:00
//
// TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though
//
// Recursively walk the nodes. The nodes form a tree whose leaves are
// regular constants, which themselves are trees that createSpvConstant()
// recursively walks. So, this function walks the "top" of the tree:
// - emit specialization constant-building instructions for specConstant
// - when running into a non-spec-constant, switch to createSpvConstant()
2016-03-21 13:51:37 +00:00
spv : : Id TGlslangToSpvTraverser : : createSpvConstant ( const glslang : : TIntermTyped & node )
2015-11-16 04:33:39 +00:00
{
2016-03-20 06:46:02 +00:00
assert ( node . getQualifier ( ) . isConstant ( ) ) ;
2015-11-16 04:33:39 +00:00
2016-04-04 03:55:17 +00:00
// Handle front-end constants first (non-specialization constants).
2016-02-16 03:58:50 +00:00
if ( ! node . getQualifier ( ) . specConstant ) {
// hand off to the non-spec-constant path
assert ( node . getAsConstantUnion ( ) ! = nullptr | | node . getAsSymbolNode ( ) ! = nullptr ) ;
int nextConst = 0 ;
2016-03-21 13:51:37 +00:00
return createSpvConstantFromConstUnionArray ( node . getType ( ) , node . getAsConstantUnion ( ) ? node . getAsConstantUnion ( ) - > getConstArray ( ) : node . getAsSymbolNode ( ) - > getConstArray ( ) ,
2016-02-16 03:58:50 +00:00
nextConst , false ) ;
}
// We now know we have a specialization constant to build
2016-05-31 01:29:40 +00:00
// gl_WorkGroupSize is a special case until the front-end handles hierarchical specialization constants,
2016-04-04 03:55:17 +00:00
// even then, it's specialization ids are handled by special case syntax in GLSL: layout(local_size_x = ...
if ( node . getType ( ) . getQualifier ( ) . builtIn = = glslang : : EbvWorkGroupSize ) {
std : : vector < spv : : Id > dimConstId ;
for ( int dim = 0 ; dim < 3 ; + + dim ) {
bool specConst = ( glslangIntermediate - > getLocalSizeSpecId ( dim ) ! = glslang : : TQualifier : : layoutNotSet ) ;
dimConstId . push_back ( builder . makeUintConstant ( glslangIntermediate - > getLocalSize ( dim ) , specConst ) ) ;
if ( specConst )
addDecoration ( dimConstId . back ( ) , spv : : DecorationSpecId , glslangIntermediate - > getLocalSizeSpecId ( dim ) ) ;
2016-02-16 03:58:50 +00:00
}
2016-04-04 03:55:17 +00:00
return builder . makeCompositeConstant ( builder . makeVectorType ( builder . makeUintType ( 32 ) , 3 ) , dimConstId , true ) ;
2016-02-16 03:58:50 +00:00
}
2016-04-04 03:55:17 +00:00
// An AST node labelled as specialization constant should be a symbol node.
// Its initializer should either be a sub tree with constant nodes, or a constant union array.
if ( auto * sn = node . getAsSymbolNode ( ) ) {
if ( auto * sub_tree = sn - > getConstSubtree ( ) ) {
2016-04-14 20:40:20 +00:00
// Traverse the constant constructor sub tree like generating normal run-time instructions.
// During the AST traversal, if the node is marked as 'specConstant', SpecConstantOpModeGuard
// will set the builder into spec constant op instruction generating mode.
sub_tree - > traverse ( this ) ;
return accessChainLoad ( sub_tree - > getType ( ) ) ;
2016-04-04 03:55:17 +00:00
} else if ( auto * const_union_array = & sn - > getConstArray ( ) ) {
int nextConst = 0 ;
return createSpvConstantFromConstUnionArray ( sn - > getType ( ) , * const_union_array , nextConst , true ) ;
}
}
// Neither a front-end constant node, nor a specialization constant node with constant union array or
// constant sub tree as initializer.
2016-05-04 19:55:59 +00:00
logger - > missingFunctionality ( " Neither a front-end constant nor a spec constant. " ) ;
2016-04-04 03:55:17 +00:00
exit ( 1 ) ;
return spv : : NoResult ;
2015-11-16 04:33:39 +00:00
}
2015-06-26 22:58:36 +00:00
// Use 'consts' as the flattened glslang source of scalar constants to recursively
// build the aggregate SPIR-V constant.
//
// If there are not enough elements present in 'consts', 0 will be substituted;
// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
//
2016-03-21 13:51:37 +00:00
spv : : Id TGlslangToSpvTraverser : : createSpvConstantFromConstUnionArray ( const glslang : : TType & glslangType , const glslang : : TConstUnionArray & consts , int & nextConst , bool specConstant )
2015-06-26 22:58:36 +00:00
{
// vector of constants for SPIR-V
std : : vector < spv : : Id > spvConsts ;
// Type is used for struct and array constants
spv : : Id typeId = convertGlslangToSpvType ( glslangType ) ;
if ( glslangType . isArray ( ) ) {
2015-08-10 23:08:55 +00:00
glslang : : TType elementType ( glslangType , 0 ) ;
for ( int i = 0 ; i < glslangType . getOuterArraySize ( ) ; + + i )
2016-03-21 13:51:37 +00:00
spvConsts . push_back ( createSpvConstantFromConstUnionArray ( elementType , consts , nextConst , false ) ) ;
2015-06-26 22:58:36 +00:00
} else if ( glslangType . isMatrix ( ) ) {
2015-08-10 23:08:55 +00:00
glslang : : TType vectorType ( glslangType , 0 ) ;
2015-06-26 22:58:36 +00:00
for ( int col = 0 ; col < glslangType . getMatrixCols ( ) ; + + col )
2016-03-21 13:51:37 +00:00
spvConsts . push_back ( createSpvConstantFromConstUnionArray ( vectorType , consts , nextConst , false ) ) ;
2015-06-26 22:58:36 +00:00
} else if ( glslangType . getStruct ( ) ) {
glslang : : TVector < glslang : : TTypeLoc > : : const_iterator iter ;
for ( iter = glslangType . getStruct ( ) - > begin ( ) ; iter ! = glslangType . getStruct ( ) - > end ( ) ; + + iter )
2016-03-21 13:51:37 +00:00
spvConsts . push_back ( createSpvConstantFromConstUnionArray ( * iter - > type , consts , nextConst , false ) ) ;
2016-05-20 18:06:03 +00:00
} else if ( glslangType . getVectorSize ( ) > 1 ) {
2015-06-26 22:58:36 +00:00
for ( unsigned int i = 0 ; i < ( unsigned int ) glslangType . getVectorSize ( ) ; + + i ) {
bool zero = nextConst > = consts . size ( ) ;
switch ( glslangType . getBasicType ( ) ) {
case glslang : : EbtInt :
spvConsts . push_back ( builder . makeIntConstant ( zero ? 0 : consts [ nextConst ] . getIConst ( ) ) ) ;
break ;
case glslang : : EbtUint :
spvConsts . push_back ( builder . makeUintConstant ( zero ? 0 : consts [ nextConst ] . getUConst ( ) ) ) ;
break ;
2016-04-22 08:51:45 +00:00
case glslang : : EbtInt64 :
spvConsts . push_back ( builder . makeInt64Constant ( zero ? 0 : consts [ nextConst ] . getI64Const ( ) ) ) ;
break ;
case glslang : : EbtUint64 :
spvConsts . push_back ( builder . makeUint64Constant ( zero ? 0 : consts [ nextConst ] . getU64Const ( ) ) ) ;
break ;
2015-06-26 22:58:36 +00:00
case glslang : : EbtFloat :
spvConsts . push_back ( builder . makeFloatConstant ( zero ? 0.0F : ( float ) consts [ nextConst ] . getDConst ( ) ) ) ;
break ;
case glslang : : EbtDouble :
spvConsts . push_back ( builder . makeDoubleConstant ( zero ? 0.0 : consts [ nextConst ] . getDConst ( ) ) ) ;
break ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EbtFloat16 :
spvConsts . push_back ( builder . makeFloat16Constant ( zero ? 0.0F : ( float ) consts [ nextConst ] . getDConst ( ) ) ) ;
break ;
# endif
2015-06-26 22:58:36 +00:00
case glslang : : EbtBool :
spvConsts . push_back ( builder . makeBoolConstant ( zero ? false : consts [ nextConst ] . getBConst ( ) ) ) ;
break ;
default :
2015-11-16 04:33:39 +00:00
assert ( 0 ) ;
2015-06-26 22:58:36 +00:00
break ;
}
+ + nextConst ;
}
} else {
// we have a non-aggregate (scalar) constant
bool zero = nextConst > = consts . size ( ) ;
spv : : Id scalar = 0 ;
switch ( glslangType . getBasicType ( ) ) {
case glslang : : EbtInt :
2015-11-16 04:33:39 +00:00
scalar = builder . makeIntConstant ( zero ? 0 : consts [ nextConst ] . getIConst ( ) , specConstant ) ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EbtUint :
2015-11-16 04:33:39 +00:00
scalar = builder . makeUintConstant ( zero ? 0 : consts [ nextConst ] . getUConst ( ) , specConstant ) ;
2015-06-26 22:58:36 +00:00
break ;
2016-04-22 08:51:45 +00:00
case glslang : : EbtInt64 :
scalar = builder . makeInt64Constant ( zero ? 0 : consts [ nextConst ] . getI64Const ( ) , specConstant ) ;
break ;
case glslang : : EbtUint64 :
scalar = builder . makeUint64Constant ( zero ? 0 : consts [ nextConst ] . getU64Const ( ) , specConstant ) ;
break ;
2015-06-26 22:58:36 +00:00
case glslang : : EbtFloat :
2015-11-16 04:33:39 +00:00
scalar = builder . makeFloatConstant ( zero ? 0.0F : ( float ) consts [ nextConst ] . getDConst ( ) , specConstant ) ;
2015-06-26 22:58:36 +00:00
break ;
case glslang : : EbtDouble :
2015-11-16 04:33:39 +00:00
scalar = builder . makeDoubleConstant ( zero ? 0.0 : consts [ nextConst ] . getDConst ( ) , specConstant ) ;
2015-06-26 22:58:36 +00:00
break ;
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
# ifdef AMD_EXTENSIONS
case glslang : : EbtFloat16 :
scalar = builder . makeFloat16Constant ( zero ? 0.0F : ( float ) consts [ nextConst ] . getDConst ( ) , specConstant ) ;
break ;
# endif
2015-06-26 22:58:36 +00:00
case glslang : : EbtBool :
2015-11-16 04:33:39 +00:00
scalar = builder . makeBoolConstant ( zero ? false : consts [ nextConst ] . getBConst ( ) , specConstant ) ;
2015-06-26 22:58:36 +00:00
break ;
default :
2015-11-16 04:33:39 +00:00
assert ( 0 ) ;
2015-06-26 22:58:36 +00:00
break ;
}
+ + nextConst ;
return scalar ;
}
return builder . makeCompositeConstant ( typeId , spvConsts ) ;
}
2015-10-15 19:29:11 +00:00
// Return true if the node is a constant or symbol whose reading has no
// non-trivial observable cost or effect.
bool TGlslangToSpvTraverser : : isTrivialLeaf ( const glslang : : TIntermTyped * node )
{
// don't know what this is
if ( node = = nullptr )
return false ;
// a constant is safe
if ( node - > getAsConstantUnion ( ) ! = nullptr )
return true ;
// not a symbol means non-trivial
if ( node - > getAsSymbolNode ( ) = = nullptr )
return false ;
// a symbol, depends on what's being read
switch ( node - > getType ( ) . getQualifier ( ) . storage ) {
case glslang : : EvqTemporary :
case glslang : : EvqGlobal :
case glslang : : EvqIn :
case glslang : : EvqInOut :
case glslang : : EvqConst :
case glslang : : EvqConstReadOnly :
case glslang : : EvqUniform :
return true ;
default :
return false ;
}
2016-05-06 21:25:16 +00:00
}
2015-10-15 19:29:11 +00:00
// A node is trivial if it is a single operation with no side effects.
// Error on the side of saying non-trivial.
// Return true if trivial.
bool TGlslangToSpvTraverser : : isTrivial ( const glslang : : TIntermTyped * node )
{
if ( node = = nullptr )
return false ;
// symbols and constants are trivial
if ( isTrivialLeaf ( node ) )
return true ;
// otherwise, it needs to be a simple operation or one or two leaf nodes
// not a simple operation
const glslang : : TIntermBinary * binaryNode = node - > getAsBinaryNode ( ) ;
const glslang : : TIntermUnary * unaryNode = node - > getAsUnaryNode ( ) ;
if ( binaryNode = = nullptr & & unaryNode = = nullptr )
return false ;
// not on leaf nodes
if ( binaryNode & & ( ! isTrivialLeaf ( binaryNode - > getLeft ( ) ) | | ! isTrivialLeaf ( binaryNode - > getRight ( ) ) ) )
return false ;
if ( unaryNode & & ! isTrivialLeaf ( unaryNode - > getOperand ( ) ) ) {
return false ;
}
switch ( node - > getAsOperator ( ) - > getOp ( ) ) {
case glslang : : EOpLogicalNot :
case glslang : : EOpConvIntToBool :
case glslang : : EOpConvUintToBool :
case glslang : : EOpConvFloatToBool :
case glslang : : EOpConvDoubleToBool :
case glslang : : EOpEqual :
case glslang : : EOpNotEqual :
case glslang : : EOpLessThan :
case glslang : : EOpGreaterThan :
case glslang : : EOpLessThanEqual :
case glslang : : EOpGreaterThanEqual :
case glslang : : EOpIndexDirect :
case glslang : : EOpIndexDirectStruct :
case glslang : : EOpLogicalXor :
case glslang : : EOpAny :
case glslang : : EOpAll :
return true ;
default :
return false ;
}
}
// Emit short-circuiting code, where 'right' is never evaluated unless
// the left side is true (for &&) or false (for ||).
spv : : Id TGlslangToSpvTraverser : : createShortCircuit ( glslang : : TOperator op , glslang : : TIntermTyped & left , glslang : : TIntermTyped & right )
{
spv : : Id boolTypeId = builder . makeBoolType ( ) ;
// emit left operand
builder . clearAccessChain ( ) ;
left . traverse ( this ) ;
2016-03-03 06:38:51 +00:00
spv : : Id leftId = accessChainLoad ( left . getType ( ) ) ;
2015-10-15 19:29:11 +00:00
// Operands to accumulate OpPhi operands
std : : vector < spv : : Id > phiOperands ;
// accumulate left operand's phi information
phiOperands . push_back ( leftId ) ;
phiOperands . push_back ( builder . getBuildPoint ( ) - > getId ( ) ) ;
// Make the two kinds of operation symmetric with a "!"
// || => emit "if (! left) result = right"
// && => emit "if ( left) result = right"
//
// TODO: this runtime "not" for || could be avoided by adding functionality
// to 'builder' to have an "else" without an "then"
if ( op = = glslang : : EOpLogicalOr )
leftId = builder . createUnaryOp ( spv : : OpLogicalNot , boolTypeId , leftId ) ;
// make an "if" based on the left value
spv : : Builder : : If ifBuilder ( leftId , builder ) ;
// emit right operand as the "then" part of the "if"
builder . clearAccessChain ( ) ;
right . traverse ( this ) ;
2016-03-03 06:38:51 +00:00
spv : : Id rightId = accessChainLoad ( right . getType ( ) ) ;
2015-10-15 19:29:11 +00:00
// accumulate left operand's phi information
phiOperands . push_back ( rightId ) ;
phiOperands . push_back ( builder . getBuildPoint ( ) - > getId ( ) ) ;
// finish the "if"
ifBuilder . makeEndIf ( ) ;
// phi together the two results
return builder . createOp ( spv : : OpPhi , boolTypeId , phiOperands ) ;
}
2016-05-05 04:30:44 +00:00
// Return type Id of the imported set of extended instructions corresponds to the name.
// Import this set if it has not been imported yet.
spv : : Id TGlslangToSpvTraverser : : getExtBuiltins ( const char * name )
{
if ( extBuiltinMap . find ( name ) ! = extBuiltinMap . end ( ) )
return extBuiltinMap [ name ] ;
else {
2016-09-21 10:56:12 +00:00
builder . addExtension ( name ) ;
2016-05-05 04:30:44 +00:00
spv : : Id extBuiltins = builder . import ( name ) ;
extBuiltinMap [ name ] = extBuiltins ;
return extBuiltins ;
}
}
2015-06-26 22:58:36 +00:00
} ; // end anonymous namespace
namespace glslang {
2015-07-13 01:28:10 +00:00
void GetSpirvVersion ( std : : string & version )
{
2015-07-15 16:03:39 +00:00
const int bufSize = 100 ;
2015-07-13 01:39:51 +00:00
char buf [ bufSize ] ;
2015-11-16 04:33:39 +00:00
snprintf ( buf , bufSize , " 0x%08x, Revision %d " , spv : : Version , spv : : Revision ) ;
2015-07-13 01:28:10 +00:00
version = buf ;
}
2015-06-26 22:58:36 +00:00
// Write SPIR-V out to a binary file
2016-05-27 17:55:53 +00:00
void OutputSpvBin ( const std : : vector < unsigned int > & spirv , const char * baseName )
2015-06-26 22:58:36 +00:00
{
std : : ofstream out ;
2015-07-13 01:28:10 +00:00
out . open ( baseName , std : : ios : : binary | std : : ios : : out ) ;
2015-06-26 22:58:36 +00:00
for ( int i = 0 ; i < ( int ) spirv . size ( ) ; + + i ) {
unsigned int word = spirv [ i ] ;
out . write ( ( const char * ) & word , 4 ) ;
}
out . close ( ) ;
}
2016-05-27 17:55:53 +00:00
// Write SPIR-V out to a text file with 32-bit hexadecimal words
void OutputSpvHex ( const std : : vector < unsigned int > & spirv , const char * baseName )
{
std : : ofstream out ;
out . open ( baseName , std : : ios : : binary | std : : ios : : out ) ;
out < < " \t // " GLSLANG_REVISION " " GLSLANG_DATE < < std : : endl ;
const int WORDS_PER_LINE = 8 ;
for ( int i = 0 ; i < ( int ) spirv . size ( ) ; i + = WORDS_PER_LINE ) {
out < < " \t " ;
for ( int j = 0 ; j < WORDS_PER_LINE & & i + j < ( int ) spirv . size ( ) ; + + j ) {
const unsigned int word = spirv [ i + j ] ;
out < < " 0x " < < std : : hex < < std : : setw ( 8 ) < < std : : setfill ( ' 0 ' ) < < word ;
if ( i + j + 1 < ( int ) spirv . size ( ) ) {
out < < " , " ;
}
}
out < < std : : endl ;
}
out . close ( ) ;
}
2015-06-26 22:58:36 +00:00
//
// Set up the glslang traversal
//
void GlslangToSpv ( const glslang : : TIntermediate & intermediate , std : : vector < unsigned int > & spirv )
2016-05-02 22:11:54 +00:00
{
2016-05-04 19:55:59 +00:00
spv : : SpvBuildLogger logger ;
GlslangToSpv ( intermediate , spirv , & logger ) ;
2016-05-02 22:11:54 +00:00
}
2016-05-04 19:55:59 +00:00
void GlslangToSpv ( const glslang : : TIntermediate & intermediate , std : : vector < unsigned int > & spirv , spv : : SpvBuildLogger * logger )
2015-06-26 22:58:36 +00:00
{
TIntermNode * root = intermediate . getTreeRoot ( ) ;
if ( root = = 0 )
return ;
glslang : : GetThreadPoolAllocator ( ) . push ( ) ;
2016-05-04 19:55:59 +00:00
TGlslangToSpvTraverser it ( & intermediate , logger ) ;
2015-06-26 22:58:36 +00:00
root - > traverse ( & it ) ;
2016-11-26 20:23:20 +00:00
it . finishSpv ( ) ;
2015-06-26 22:58:36 +00:00
it . dumpSpv ( spirv ) ;
glslang : : GetThreadPoolAllocator ( ) . pop ( ) ;
}
} ; // end namespace glslang