2015-03-03 17:09:43 +00:00
//
//Copyright (C) 2014 LunarG, Inc.
//
//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.
//
// Author: John Kessenich, LunarG
//
// Visit the nodes in the glslang intermediate tree representation to
// translate them to SPIR-V.
//
# include "spirv.h"
# include "GlslangToSpv.h"
# include "SpvBuilder.h"
# include "GLSL450Lib.h"
// Glslang includes
# include "glslang/MachineIndependent/localintermediate.h"
# include "glslang/MachineIndependent/SymbolTable.h"
# include <string>
# include <map>
# include <list>
# include <vector>
# include <stack>
# include <fstream>
namespace {
const int GlslangMagic = 0x51a ;
//
// The main holder of information for translating glslang to SPIR-V.
//
// Derives from the AST walking base class.
//
class TGlslangToSpvTraverser : public glslang : : TIntermTraverser {
public :
TGlslangToSpvTraverser ( const glslang : : TIntermediate * ) ;
virtual ~ TGlslangToSpvTraverser ( ) ;
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 * ) ;
void dumpSpv ( std : : vector < unsigned int > & out ) { builder . dump ( out ) ; }
protected :
spv : : Id createSpvVariable ( const glslang : : TIntermSymbol * ) ;
spv : : Id getSampledType ( const glslang : : TSampler & ) ;
spv : : Id convertGlslangToSpvType ( const glslang : : TType & type ) ;
bool isShaderEntrypoint ( const glslang : : TIntermAggregate * node ) ;
void makeFunctions ( const glslang : : TIntermSequence & ) ;
void makeGlobalInitializers ( const glslang : : TIntermSequence & ) ;
void visitFunctions ( const glslang : : TIntermSequence & ) ;
void handleFunctionEntry ( const glslang : : TIntermAggregate * node ) ;
void translateArguments ( const glslang : : TIntermSequence & glslangArguments , std : : vector < spv : : Id > & arguments ) ;
spv : : Id handleBuiltInFunctionCall ( const glslang : : TIntermAggregate * ) ;
spv : : Id handleUserFunctionCall ( const glslang : : TIntermAggregate * ) ;
spv : : Id createBinaryOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id typeId , spv : : Id left , spv : : Id right , glslang : : TBasicType typeProxy , bool reduceComparison = true ) ;
spv : : Id createUnaryOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id typeId , spv : : Id operand , bool isFloat ) ;
spv : : Id createConversion ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id destTypeId , spv : : Id operand ) ;
spv : : Id makeSmearedConstant ( spv : : Id constant , int vectorSize ) ;
2015-05-15 17:30:55 +00:00
spv : : Id createMiscOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id typeId , std : : vector < spv : : Id > & operands ) ;
2015-03-03 17:09:43 +00:00
spv : : Id createNoArgOperation ( glslang : : TOperator op ) ;
spv : : Id getSymbolId ( const glslang : : TIntermSymbol * node ) ;
void addDecoration ( spv : : Id id , spv : : Decoration dec ) ;
void addMemberDecoration ( spv : : Id id , int member , spv : : Decoration dec ) ;
spv : : Id createSpvConstant ( const glslang : : TType & type , const glslang : : TConstUnionArray & , int & nextConst ) ;
spv : : Function * shaderEntry ;
int sequenceDepth ;
// There is a 1:1 mapping between a spv builder and a module; this is thread safe
spv : : Builder builder ;
bool inMain ;
bool mainTerminated ;
bool linkageOnly ;
const glslang : : TIntermediate * glslangIntermediate ;
spv : : Id stdBuiltins ;
std : : map < int , spv : : Id > symbolValues ;
std : : set < int > constReadOnlyParameters ; // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once
std : : map < std : : string , spv : : Function * > functionMap ;
std : : map < const glslang : : TTypeList * , spv : : Id > structMap ;
std : : map < const glslang : : TTypeList * , std : : vector < int > > memberRemapper ; // for mapping glslang block indices to spv indices (e.g., due to hidden members)
std : : stack < bool > breakForLoop ; // false means break for switch
std : : stack < glslang : : TIntermTyped * > loopTerminal ; // code from the last part of a for loop: for(...; ...; terminal), needed for e.g., continue };
} ;
//
// Helper functions for translating glslang representations to SPIR-V enumerants.
//
2015-05-22 01:21:31 +00:00
// Translate glslang profile to SPIR-V source language.
spv : : SourceLanguage TranslateSourceLanguage ( EProfile profile )
{
switch ( profile ) {
case ENoProfile :
case ECoreProfile :
case ECompatibilityProfile :
return spv : : SourceLanguageGLSL ;
case EEsProfile :
return spv : : SourceLanguageESSL ;
default :
return spv : : SourceLanguageUnknown ;
}
}
2015-03-03 17:09:43 +00:00
// Translate glslang language (stage) to SPIR-V execution model.
spv : : ExecutionModel TranslateExecutionModel ( EShLanguage stage )
{
switch ( stage ) {
2015-03-30 17:41:16 +00:00
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 ;
2015-03-03 17:09:43 +00:00
default :
spv : : MissingFunctionality ( " GLSL stage " ) ;
2015-03-30 17:41:16 +00:00
return spv : : ExecutionModelFragment ;
2015-03-03 17:09:43 +00:00
}
}
// Translate glslang type to SPIR-V storage class.
spv : : StorageClass TranslateStorageClass ( const glslang : : TType & type )
{
if ( type . getQualifier ( ) . isPipeInput ( ) )
2015-03-30 17:41:16 +00:00
return spv : : StorageClassInput ;
2015-03-03 17:09:43 +00:00
else if ( type . getQualifier ( ) . isPipeOutput ( ) )
2015-03-30 17:41:16 +00:00
return spv : : StorageClassOutput ;
2015-03-03 17:09:43 +00:00
else if ( type . getQualifier ( ) . isUniformOrBuffer ( ) ) {
if ( type . getBasicType ( ) = = glslang : : EbtBlock )
2015-03-30 17:41:16 +00:00
return spv : : StorageClassUniform ;
2015-03-03 17:09:43 +00:00
else
2015-03-30 17:41:16 +00:00
return spv : : StorageClassUniformConstant ;
2015-03-03 17:09:43 +00:00
// TODO: how are we distuingishing between default and non-default non-writable uniforms? Do default uniforms even exist?
} else {
switch ( type . getQualifier ( ) . storage ) {
2015-03-30 17:41:16 +00:00
case glslang : : EvqShared : return spv : : StorageClassWorkgroupLocal ; break ;
case glslang : : EvqGlobal : return spv : : StorageClassPrivateGlobal ;
case glslang : : EvqConstReadOnly : return spv : : StorageClassFunction ;
case glslang : : EvqTemporary : return spv : : StorageClassFunction ;
2015-03-03 17:09:43 +00:00
default :
spv : : MissingFunctionality ( " unknown glslang storage class " ) ;
2015-03-30 17:41:16 +00:00
return spv : : StorageClassFunction ;
2015-03-03 17:09:43 +00:00
}
}
}
// Translate glslang sampler type to SPIR-V dimensionality.
2015-03-30 17:41:16 +00:00
spv : : Dim TranslateDimensionality ( const glslang : : TSampler & sampler )
2015-03-03 17:09:43 +00:00
{
switch ( sampler . dim ) {
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 ;
default :
spv : : MissingFunctionality ( " unknown sampler dimension " ) ;
return spv : : Dim2D ;
}
}
// Translate glslang type to SPIR-V precision decorations.
spv : : Decoration TranslatePrecisionDecoration ( const glslang : : TType & type )
{
switch ( type . getQualifier ( ) . precision ) {
2015-03-30 17:41:16 +00:00
case glslang : : EpqLow : return spv : : DecorationPrecisionLow ;
case glslang : : EpqMedium : return spv : : DecorationPrecisionMedium ;
case glslang : : EpqHigh : return spv : : DecorationPrecisionHigh ;
default :
return spv : : NoPrecision ;
2015-03-03 17:09:43 +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 ) {
2015-03-30 17:41:16 +00:00
case glslang : : EvqUniform : return spv : : DecorationBlock ;
case glslang : : EvqBuffer : return spv : : DecorationBufferBlock ;
case glslang : : EvqVaryingIn : return spv : : DecorationBlock ;
case glslang : : EvqVaryingOut : return spv : : DecorationBlock ;
2015-03-03 17:09:43 +00:00
default :
spv : : MissingFunctionality ( " kind of block " ) ;
break ;
}
}
2015-03-30 17:41:16 +00:00
return ( spv : : Decoration ) spv : : BadValue ;
2015-03-03 17:09:43 +00:00
}
// Translate glslang type to SPIR-V layout decorations.
spv : : Decoration TranslateLayoutDecoration ( const glslang : : TType & type )
{
if ( type . isMatrix ( ) ) {
switch ( type . getQualifier ( ) . layoutMatrix ) {
case glslang : : ElmRowMajor :
2015-03-30 17:41:16 +00:00
return spv : : DecorationRowMajor ;
2015-03-03 17:09:43 +00:00
default :
2015-03-30 17:41:16 +00:00
return spv : : DecorationColMajor ;
2015-03-03 17:09:43 +00:00
}
} else {
switch ( type . getBasicType ( ) ) {
default :
2015-03-30 17:41:16 +00:00
return ( spv : : Decoration ) spv : : BadValue ;
2015-03-03 17:09:43 +00:00
break ;
case glslang : : EbtBlock :
switch ( type . getQualifier ( ) . storage ) {
case glslang : : EvqUniform :
case glslang : : EvqBuffer :
switch ( type . getQualifier ( ) . layoutPacking ) {
2015-03-30 17:41:16 +00:00
case glslang : : ElpShared : return spv : : DecorationGLSLShared ;
case glslang : : ElpStd140 : return spv : : DecorationGLSLStd140 ;
case glslang : : ElpStd430 : return spv : : DecorationGLSLStd430 ;
case glslang : : ElpPacked : return spv : : DecorationGLSLPacked ;
2015-03-03 17:09:43 +00:00
default :
spv : : MissingFunctionality ( " uniform block layout " ) ;
2015-03-30 17:41:16 +00:00
return spv : : DecorationGLSLShared ;
2015-03-03 17:09:43 +00:00
}
case glslang : : EvqVaryingIn :
case glslang : : EvqVaryingOut :
if ( type . getQualifier ( ) . layoutPacking ! = glslang : : ElpNone )
spv : : MissingFunctionality ( " in/out block layout " ) ;
2015-03-30 17:41:16 +00:00
return ( spv : : Decoration ) spv : : BadValue ;
2015-03-03 17:09:43 +00:00
default :
spv : : MissingFunctionality ( " block storage qualification " ) ;
2015-03-30 17:41:16 +00:00
return ( spv : : Decoration ) spv : : BadValue ;
2015-03-03 17:09:43 +00:00
}
}
}
}
// Translate glslang type to SPIR-V interpolation decorations.
spv : : Decoration TranslateInterpolationDecoration ( const glslang : : TType & type )
{
if ( type . getQualifier ( ) . smooth )
2015-03-30 17:41:16 +00:00
return spv : : DecorationSmooth ;
2015-03-03 17:09:43 +00:00
if ( type . getQualifier ( ) . nopersp )
2015-03-30 17:41:16 +00:00
return spv : : DecorationNoperspective ;
2015-03-03 17:09:43 +00:00
else if ( type . getQualifier ( ) . patch )
2015-03-30 17:41:16 +00:00
return spv : : DecorationPatch ;
2015-03-03 17:09:43 +00:00
else if ( type . getQualifier ( ) . flat )
2015-03-30 17:41:16 +00:00
return spv : : DecorationFlat ;
2015-03-03 17:09:43 +00:00
else if ( type . getQualifier ( ) . centroid )
2015-03-30 17:41:16 +00:00
return spv : : DecorationCentroid ;
2015-03-03 17:09:43 +00:00
else if ( type . getQualifier ( ) . sample )
2015-03-30 17:41:16 +00:00
return spv : : DecorationSample ;
2015-03-03 17:09:43 +00:00
else
2015-03-30 17:41:16 +00:00
return ( spv : : Decoration ) spv : : BadValue ;
2015-03-03 17:09:43 +00:00
}
// If glslang type is invaraiant, return SPIR-V invariant decoration.
spv : : Decoration TranslateInvariantDecoration ( const glslang : : TType & type )
{
if ( type . getQualifier ( ) . invariant )
2015-03-30 17:41:16 +00:00
return spv : : DecorationInvariant ;
2015-03-03 17:09:43 +00:00
else
2015-03-30 17:41:16 +00:00
return ( spv : : Decoration ) spv : : BadValue ;
2015-03-03 17:09:43 +00:00
}
2015-04-01 20:35:23 +00:00
// Translate glslang built-in variable to SPIR-V built in decoration.
2015-05-22 01:53:15 +00:00
spv : : BuiltIn TranslateBuiltInDecoration ( glslang : : TBuiltInVariable builtIn )
2015-03-03 17:09:43 +00:00
{
2015-05-22 01:53:15 +00:00
switch ( builtIn ) {
2015-05-18 23:25:32 +00:00
case glslang : : EbvPosition : return spv : : BuiltInPosition ;
case glslang : : EbvPointSize : return spv : : BuiltInPointSize ;
case glslang : : EbvClipVertex : return spv : : BuiltInClipVertex ;
case glslang : : EbvClipDistance : return spv : : BuiltInClipDistance ;
case glslang : : EbvCullDistance : return spv : : BuiltInCullDistance ;
case glslang : : EbvVertexId : return spv : : BuiltInVertexId ;
case glslang : : EbvInstanceId : return spv : : BuiltInInstanceId ;
case glslang : : EbvPrimitiveId : return spv : : BuiltInPrimitiveId ;
case glslang : : EbvInvocationId : return spv : : BuiltInInvocationId ;
case glslang : : EbvLayer : return spv : : BuiltInLayer ;
case glslang : : EbvViewportIndex : return spv : : BuiltInViewportIndex ;
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 : : EbvSampleId : return spv : : BuiltInSampleId ;
case glslang : : EbvSamplePosition : return spv : : BuiltInSamplePosition ;
case glslang : : EbvSampleMask : return spv : : BuiltInSampleMask ;
case glslang : : EbvFragColor : return spv : : BuiltInFragColor ;
case glslang : : EbvFragData : return spv : : BuiltInFragColor ;
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 ;
default : return ( spv : : BuiltIn ) spv : : BadValue ;
2015-03-03 17:09:43 +00:00
}
}
//
// Implement the TGlslangToSpvTraverser class.
//
TGlslangToSpvTraverser : : TGlslangToSpvTraverser ( const glslang : : TIntermediate * glslangIntermediate )
: TIntermTraverser ( true , false , true ) , shaderEntry ( 0 ) , sequenceDepth ( 0 ) ,
builder ( GlslangMagic ) ,
inMain ( false ) , mainTerminated ( false ) , linkageOnly ( false ) ,
glslangIntermediate ( glslangIntermediate )
{
spv : : ExecutionModel executionModel = TranslateExecutionModel ( glslangIntermediate - > getStage ( ) ) ;
builder . clearAccessChain ( ) ;
2015-05-22 01:21:31 +00:00
builder . setSource ( TranslateSourceLanguage ( glslangIntermediate - > getProfile ( ) ) , glslangIntermediate - > getVersion ( ) ) ;
2015-03-03 17:09:43 +00:00
stdBuiltins = builder . import ( " GLSL.std.450 " ) ;
2015-03-30 17:41:16 +00:00
builder . setMemoryModel ( spv : : AddressingModelLogical , spv : : MemoryModelGLSL450 ) ;
2015-03-03 17:09:43 +00:00
shaderEntry = builder . makeMain ( ) ;
builder . addEntryPoint ( executionModel , shaderEntry ) ;
// Add the source extensions
const std : : set < std : : string > & sourceExtensions = glslangIntermediate - > getRequestedExtensions ( ) ;
for ( std : : set < std : : string > : : const_iterator it = sourceExtensions . begin ( ) ; it ! = sourceExtensions . end ( ) ; + + it )
builder . addSourceExtension ( it - > c_str ( ) ) ;
// Add the top-level modes for this shader.
if ( glslangIntermediate - > getXfbMode ( ) )
2015-03-30 17:41:16 +00:00
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeXfb ) ;
2015-03-03 17:09:43 +00:00
2015-06-10 23:23:12 +00:00
unsigned int mode ;
2015-03-03 17:09:43 +00:00
switch ( glslangIntermediate - > getStage ( ) ) {
case EShLangVertex :
break ;
case EShLangTessControl :
2015-03-30 17:41:16 +00:00
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeOutputVertices , glslangIntermediate - > getVertices ( ) ) ;
2015-03-03 17:09:43 +00:00
break ;
case EShLangTessEvaluation :
switch ( glslangIntermediate - > getInputPrimitive ( ) ) {
2015-03-30 17:41:16 +00:00
case glslang : : ElgTriangles : mode = spv : : ExecutionModeInputTriangles ; break ;
case glslang : : ElgQuads : mode = spv : : ExecutionModeInputQuads ; break ;
case glslang : : ElgIsolines : mode = spv : : ExecutionModeInputIsolines ; break ;
2015-06-10 23:23:12 +00:00
default : mode = spv : : BadValue ; break ;
2015-03-03 17:09:43 +00:00
}
2015-03-30 17:41:16 +00:00
if ( mode ! = spv : : BadValue )
2015-06-10 23:23:12 +00:00
builder . addExecutionMode ( shaderEntry , ( spv : : ExecutionMode ) mode ) ;
2015-03-03 17:09:43 +00:00
// TODO
//builder.addExecutionMode(spv::VertexSpacingMdName, glslangIntermediate->getVertexSpacing());
//builder.addExecutionMode(spv::VertexOrderMdName, glslangIntermediate->getVertexOrder());
//builder.addExecutionMode(spv::PointModeMdName, glslangIntermediate->getPointMode());
break ;
case EShLangGeometry :
switch ( glslangIntermediate - > getInputPrimitive ( ) ) {
2015-03-30 17:41:16 +00:00
case glslang : : ElgPoints : mode = spv : : ExecutionModeInputPoints ; break ;
case glslang : : ElgLines : mode = spv : : ExecutionModeInputLines ; break ;
case glslang : : ElgLinesAdjacency : mode = spv : : ExecutionModeInputLinesAdjacency ; break ;
case glslang : : ElgTriangles : mode = spv : : ExecutionModeInputTriangles ; break ;
case glslang : : ElgTrianglesAdjacency : mode = spv : : ExecutionModeInputTrianglesAdjacency ; break ;
2015-06-10 23:23:12 +00:00
default : mode = spv : : BadValue ; break ;
2015-03-03 17:09:43 +00:00
}
2015-03-30 17:41:16 +00:00
if ( mode ! = spv : : BadValue )
2015-06-10 23:23:12 +00:00
builder . addExecutionMode ( shaderEntry , ( spv : : ExecutionMode ) mode ) ;
2015-03-30 17:41:16 +00:00
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeInvocations , glslangIntermediate - > getInvocations ( ) ) ;
2015-03-03 17:09:43 +00:00
switch ( glslangIntermediate - > getOutputPrimitive ( ) ) {
2015-03-30 17:41:16 +00:00
case glslang : : ElgPoints : mode = spv : : ExecutionModeOutputPoints ; break ;
case glslang : : ElgLineStrip : mode = spv : : ExecutionModeOutputLineStrip ; break ;
case glslang : : ElgTriangleStrip : mode = spv : : ExecutionModeOutputTriangleStrip ; break ;
2015-06-10 23:23:12 +00:00
default : mode = spv : : BadValue ; break ;
2015-03-03 17:09:43 +00:00
}
2015-03-30 17:41:16 +00:00
if ( mode ! = spv : : BadValue )
2015-06-10 23:23:12 +00:00
builder . addExecutionMode ( shaderEntry , ( spv : : ExecutionMode ) mode ) ;
2015-03-30 17:41:16 +00:00
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeOutputVertices , glslangIntermediate - > getVertices ( ) ) ;
2015-03-03 17:09:43 +00:00
break ;
case EShLangFragment :
if ( glslangIntermediate - > getPixelCenterInteger ( ) )
2015-03-30 17:41:16 +00:00
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModePixelCenterInteger ) ;
2015-03-03 17:09:43 +00:00
if ( glslangIntermediate - > getOriginUpperLeft ( ) )
2015-03-30 17:41:16 +00:00
builder . addExecutionMode ( shaderEntry , spv : : ExecutionModeOriginUpperLeft ) ;
2015-03-03 17:09:43 +00:00
break ;
case EShLangCompute :
break ;
default :
break ;
}
}
TGlslangToSpvTraverser : : ~ TGlslangToSpvTraverser ( )
{
if ( ! mainTerminated ) {
spv : : Block * lastMainBlock = shaderEntry - > getLastBlock ( ) ;
builder . setBuildPoint ( lastMainBlock ) ;
builder . leaveFunction ( true ) ;
}
}
//
// 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.
//
//
// Symbols can turn into
// - 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 )
{
// getSymbolId() will set up all the IO decorations on the first call.
// Formal function parameters were mapped during makeFunctions().
spv : : Id id = getSymbolId ( symbol ) ;
if ( ! linkageOnly ) {
// 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,
// except for "const in" arguments to a function, which are an intermediate object.
// See comments in handleUserFunctionCall().
glslang : : TStorageQualifier qualifier = symbol - > getQualifier ( ) . storage ;
if ( qualifier = = glslang : : EvqConstReadOnly & & constReadOnlyParameters . find ( symbol - > getId ( ) ) ! = constReadOnlyParameters . end ( ) )
builder . setAccessChainRValue ( id ) ;
else
builder . setAccessChainLValue ( id ) ;
}
}
bool TGlslangToSpvTraverser : : visitBinary ( glslang : : TVisit /* visit */ , glslang : : TIntermBinary * node )
{
// 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 ) ;
spv : : Id rValue = builder . accessChainLoad ( TranslatePrecisionDecoration ( node - > getRight ( ) - > getType ( ) ) ) ;
if ( node - > getOp ( ) ! = glslang : : EOpAssign ) {
// the left is also an r-value
builder . setAccessChain ( lValue ) ;
spv : : Id leftRValue = builder . accessChainLoad ( TranslatePrecisionDecoration ( node - > getLeft ( ) - > getType ( ) ) ) ;
// do the operation
rValue = createBinaryOperation ( node - > getOp ( ) , TranslatePrecisionDecoration ( node - > getType ( ) ) ,
convertGlslangToSpvType ( node - > getType ( ) ) , leftRValue , rValue ,
node - > getType ( ) . getBasicType ( ) ) ;
// these all need their counterparts in createBinaryOperation()
if ( rValue = = 0 )
spv : : MissingFunctionality ( " createBinaryOperation " ) ;
}
// store the result
builder . setAccessChain ( lValue ) ;
builder . accessChainStore ( rValue ) ;
// 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
int index = 0 ;
if ( node - > getRight ( ) - > getAsConstantUnion ( ) = = 0 )
spv : : MissingFunctionality ( " direct index without a constant node " ) ;
else
index = node - > getRight ( ) - > getAsConstantUnion ( ) - > getConstArray ( ) [ 0 ] . getIConst ( ) ;
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 ( ) ] ;
if ( remapper . size ( ) = = 0 )
spv : : MissingFunctionality ( " block without member remapping " ) ;
else
index = remapper [ index ] ;
}
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 ;
swizzle . push_back ( node - > getRight ( ) - > getAsConstantUnion ( ) - > getConstArray ( ) [ 0 ] . getIConst ( ) ) ;
2015-06-10 22:05:48 +00:00
builder . accessChainPushSwizzle ( swizzle ) ;
2015-03-03 17:09:43 +00:00
} else {
// normal case for indexing array or structure or block
builder . accessChainPush ( builder . makeIntConstant ( index ) , convertGlslangToSpvType ( node - > getType ( ) ) ) ;
}
}
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 ) ;
spv : : Id index = builder . accessChainLoad ( TranslatePrecisionDecoration ( node - > getRight ( ) - > getType ( ) ) ) ;
// restore the saved access chain
builder . setAccessChain ( partial ) ;
if ( ! node - > getLeft ( ) - > getType ( ) . isArray ( ) & & node - > getLeft ( ) - > getType ( ) . isVector ( ) )
builder . accessChainPushComponent ( index ) ;
else
builder . accessChainPush ( index , convertGlslangToSpvType ( node - > getType ( ) ) ) ;
}
return false ;
case glslang : : EOpVectorSwizzle :
{
node - > getLeft ( ) - > traverse ( this ) ;
glslang : : TIntermSequence & swizzleSequence = node - > getRight ( ) - > getAsAggregate ( ) - > getSequence ( ) ;
std : : vector < unsigned > swizzle ;
for ( int i = 0 ; i < ( int ) swizzleSequence . size ( ) ; + + i )
swizzle . push_back ( swizzleSequence [ i ] - > getAsConstantUnion ( ) - > getConstArray ( ) [ 0 ] . getIConst ( ) ) ;
2015-06-10 22:05:48 +00:00
builder . accessChainPushSwizzle ( swizzle ) ;
2015-03-03 17:09:43 +00:00
}
return false ;
default :
break ;
}
// Assume generic binary op...
// Get the operands
builder . clearAccessChain ( ) ;
node - > getLeft ( ) - > traverse ( this ) ;
spv : : Id left = builder . accessChainLoad ( TranslatePrecisionDecoration ( node - > getLeft ( ) - > getType ( ) ) ) ;
builder . clearAccessChain ( ) ;
node - > getRight ( ) - > traverse ( this ) ;
spv : : Id right = builder . accessChainLoad ( TranslatePrecisionDecoration ( node - > getRight ( ) - > getType ( ) ) ) ;
spv : : Id result ;
spv : : Decoration precision = TranslatePrecisionDecoration ( node - > getType ( ) ) ;
result = createBinaryOperation ( node - > getOp ( ) , precision ,
convertGlslangToSpvType ( node - > getType ( ) ) , left , right ,
node - > getLeft ( ) - > getType ( ) . getBasicType ( ) ) ;
if ( ! result ) {
spv : : MissingFunctionality ( " glslang binary operation " ) ;
} else {
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( result ) ;
return false ;
}
return true ;
}
bool TGlslangToSpvTraverser : : visitUnary ( glslang : : TVisit /* visit */ , glslang : : TIntermUnary * node )
{
builder . clearAccessChain ( ) ;
node - > getOperand ( ) - > traverse ( this ) ;
spv : : Id operand = builder . accessChainLoad ( TranslatePrecisionDecoration ( node - > getOperand ( ) - > getType ( ) ) ) ;
spv : : Decoration precision = TranslatePrecisionDecoration ( node - > getType ( ) ) ;
// it could be a conversion
spv : : Id result = createConversion ( node - > getOp ( ) , precision , convertGlslangToSpvType ( node - > getType ( ) ) , operand ) ;
// if not, then possibly an operation
if ( ! result )
result = createUnaryOperation ( node - > getOp ( ) , precision , convertGlslangToSpvType ( node - > getType ( ) ) , operand , node - > getBasicType ( ) = = glslang : : EbtFloat | | node - > getBasicType ( ) = = glslang : : EbtDouble ) ;
if ( result ) {
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
spv : : Id one = node - > getBasicType ( ) = = glslang : : EbtFloat ?
builder . makeFloatConstant ( 1.0F ) :
builder . makeIntConstant ( 1 ) ;
glslang : : TOperator op ;
if ( node - > getOp ( ) = = glslang : : EOpPreIncrement | |
node - > getOp ( ) = = glslang : : EOpPostIncrement )
op = glslang : : EOpAdd ;
else
op = glslang : : EOpSub ;
spv : : Id result = createBinaryOperation ( op , TranslatePrecisionDecoration ( node - > getType ( ) ) ,
convertGlslangToSpvType ( node - > getType ( ) ) , operand , one ,
node - > getType ( ) . getBasicType ( ) ) ;
if ( result = = 0 )
spv : : MissingFunctionality ( " createBinaryOperation for unary " ) ;
// 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 ;
2015-03-24 00:32:50 +00:00
case glslang : : EOpEmitStreamVertex :
builder . createNoResultOp ( spv : : OpEmitStreamVertex , operand ) ;
return false ;
case glslang : : EOpEndStreamPrimitive :
builder . createNoResultOp ( spv : : OpEndStreamPrimitive , operand ) ;
return false ;
2015-03-03 17:09:43 +00:00
default :
spv : : MissingFunctionality ( " glslang unary " ) ;
break ;
}
return true ;
}
bool TGlslangToSpvTraverser : : visitAggregate ( glslang : : TVisit visit , glslang : : TIntermAggregate * node )
{
spv : : Id result ;
glslang : : TOperator binOp = glslang : : EOpNull ;
bool reduceComparison = true ;
bool isMatrix = false ;
bool noReturnValue = false ;
assert ( node - > getOp ( ) ) ;
spv : : Decoration precision = TranslatePrecisionDecoration ( node - > getType ( ) ) ;
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 ( ) ) ;
// Also, we want all globals initializers to go into the entry of main(), before
// anything else gets there, so visit out of order, doing them all now.
makeGlobalInitializers ( node - > getAsAggregate ( ) - > getSequence ( ) ) ;
// Initializers are done, don't want to visit again, but functions link objects need to be processed,
// 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 ) {
if ( isShaderEntrypoint ( node ) ) {
inMain = true ;
builder . setBuildPoint ( shaderEntry - > getLastBlock ( ) ) ;
} else {
handleFunctionEntry ( node ) ;
}
} else {
if ( inMain )
mainTerminated = true ;
builder . leaveFunction ( inMain ) ;
inMain = false ;
}
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 ) ;
else
result = handleBuiltInFunctionCall ( node ) ;
if ( ! result ) {
spv : : MissingFunctionality ( " glslang function call " ) ;
glslang : : TConstUnionArray emptyConsts ;
int nextConst = 0 ;
result = createSpvConstant ( node - > getType ( ) , emptyConsts , nextConst ) ;
}
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( result ) ;
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 :
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 :
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 :
case glslang : : EOpConstructStruct :
{
std : : vector < spv : : Id > arguments ;
translateArguments ( node - > getSequence ( ) , arguments ) ;
spv : : Id resultTypeId = convertGlslangToSpvType ( node - > getType ( ) ) ;
spv : : Id constructed ;
if ( node - > getOp ( ) = = glslang : : EOpConstructStruct | | node - > getType ( ) . isArray ( ) ) {
std : : vector < spv : : Id > constituents ;
for ( int c = 0 ; c < ( int ) arguments . size ( ) ; + + c )
constituents . push_back ( arguments [ c ] ) ;
constructed = builder . createCompositeConstruct ( resultTypeId , constituents ) ;
} else {
if ( isMatrix )
constructed = builder . createMatrixConstructor ( precision , arguments , resultTypeId ) ;
else
constructed = builder . createConstructor ( precision , arguments , resultTypeId ) ;
}
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 :
// compontent-wise matrix multiply
binOp = glslang : : EOpMul ;
break ;
case glslang : : EOpOuterProduct :
// two vectors multiplied to make a matrix
binOp = glslang : : EOpOuterProduct ;
break ;
case glslang : : EOpDot :
{
// for scalar dot product, use multiply
glslang : : TIntermSequence & glslangOperands = node - > getSequence ( ) ;
if ( ! glslangOperands [ 0 ] - > getAsTyped ( ) - > isVector ( ) )
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 : : EOpArrayLength :
{
glslang : : TIntermTyped * typedNode = node - > getSequence ( ) [ 0 ] - > getAsTyped ( ) ;
assert ( typedNode ) ;
spv : : Id length = builder . makeIntConstant ( typedNode - > getType ( ) . getArraySize ( ) ) ;
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( length ) ;
return false ;
}
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 :
noReturnValue = true ;
2015-03-24 00:32:50 +00:00
// These all have 0 operands and will naturally finish up in the code below for 0 operands
2015-03-03 17:09:43 +00:00
break ;
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 ) ;
spv : : Id leftId = builder . accessChainLoad ( TranslatePrecisionDecoration ( left - > getType ( ) ) ) ;
builder . clearAccessChain ( ) ;
right - > traverse ( this ) ;
spv : : Id rightId = builder . accessChainLoad ( TranslatePrecisionDecoration ( right - > getType ( ) ) ) ;
result = createBinaryOperation ( binOp , precision ,
convertGlslangToSpvType ( node - > getType ( ) ) , leftId , rightId ,
left - > getType ( ) . getBasicType ( ) , reduceComparison ) ;
// code above should only make binOp that exists in createBinaryOperation
if ( result = = 0 )
spv : : MissingFunctionality ( " createBinaryOperation for aggregate " ) ;
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( result ) ;
return false ;
}
glslang : : TIntermSequence & glslangOperands = node - > getSequence ( ) ;
std : : vector < spv : : Id > operands ;
for ( int arg = 0 ; arg < ( int ) glslangOperands . size ( ) ; + + arg ) {
builder . clearAccessChain ( ) ;
glslangOperands [ arg ] - > traverse ( this ) ;
// special case l-value operands; there are just a few
bool lvalue = false ;
switch ( node - > getOp ( ) ) {
//case glslang::EOpFrexp:
case glslang : : EOpModf :
if ( arg = = 1 )
lvalue = true ;
break ;
//case glslang::EOpUAddCarry:
//case glslang::EOpUSubBorrow:
//case glslang::EOpUMulExtended:
default :
break ;
}
if ( lvalue )
operands . push_back ( builder . accessChainGetLValue ( ) ) ;
else
operands . push_back ( builder . accessChainLoad ( TranslatePrecisionDecoration ( glslangOperands [ arg ] - > getAsTyped ( ) - > getType ( ) ) ) ) ;
}
switch ( glslangOperands . size ( ) ) {
case 0 :
result = createNoArgOperation ( node - > getOp ( ) ) ;
break ;
case 1 :
result = createUnaryOperation ( node - > getOp ( ) , precision , convertGlslangToSpvType ( node - > getType ( ) ) , operands . front ( ) , node - > getType ( ) . getBasicType ( ) = = glslang : : EbtFloat | | node - > getType ( ) . getBasicType ( ) = = glslang : : EbtDouble ) ;
break ;
default :
2015-05-15 17:30:55 +00:00
result = createMiscOperation ( node - > getOp ( ) , precision , convertGlslangToSpvType ( node - > getType ( ) ) , operands ) ;
break ;
2015-03-03 17:09:43 +00:00
}
if ( noReturnValue )
return false ;
if ( ! result ) {
spv : : MissingFunctionality ( " glslang aggregate " ) ;
return true ;
} 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
2015-03-30 17:41:16 +00:00
result = builder . createVariable ( spv : : StorageClassFunction , convertGlslangToSpvType ( node - > getType ( ) ) ) ;
2015-03-03 17:09:43 +00:00
}
// emit the condition before doing anything with selection
node - > getCondition ( ) - > traverse ( this ) ;
// make an "if" based on the value created by the condition
2015-03-30 17:41:16 +00:00
spv : : Builder : : If ifBuilder ( builder . accessChainLoad ( spv : : NoPrecision ) , builder ) ;
2015-03-03 17:09:43 +00:00
if ( node - > getTrueBlock ( ) ) {
// emit the "then" statement
node - > getTrueBlock ( ) - > traverse ( this ) ;
if ( result )
builder . createStore ( builder . accessChainLoad ( TranslatePrecisionDecoration ( node - > getTrueBlock ( ) - > getAsTyped ( ) - > getType ( ) ) ) , result ) ;
}
if ( node - > getFalseBlock ( ) ) {
ifBuilder . makeBeginElse ( ) ;
// emit the "else" statement
node - > getFalseBlock ( ) - > traverse ( this ) ;
if ( result )
builder . createStore ( builder . accessChainLoad ( TranslatePrecisionDecoration ( node - > getFalseBlock ( ) - > getAsTyped ( ) - > getType ( ) ) ) , result ) ;
}
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 ) ;
spv : : Id selector = builder . accessChainLoad ( TranslatePrecisionDecoration ( node - > getCondition ( ) - > getAsTyped ( ) - > getType ( ) ) ) ;
// 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 )
defaultSegment = codeSegments . size ( ) ;
else if ( child - > getAsBranchNode ( ) & & child - > getAsBranchNode ( ) - > getFlowOp ( ) = = glslang : : EOpCase ) {
valueIndexToSegment [ caseValues . size ( ) ] = codeSegments . size ( ) ;
caseValues . push_back ( child - > getAsBranchNode ( ) - > getExpression ( ) - > getAsConstantUnion ( ) - > getConstArray ( ) [ 0 ] . getIConst ( ) ) ;
} else
codeSegments . push_back ( child ) ;
}
// handle the case where the last code segment is missing, due to no code
// statements between the last case and the end of the switch statement
2015-06-12 22:34:37 +00:00
if ( ( caseValues . size ( ) & & ( int ) codeSegments . size ( ) = = valueIndexToSegment [ caseValues . size ( ) - 1 ] ) | |
( int ) codeSegments . size ( ) = = defaultSegment )
2015-05-18 01:59:45 +00:00
codeSegments . push_back ( nullptr ) ;
2015-03-03 17:09:43 +00:00
// make the switch statement
std : : vector < spv : : Block * > segmentBlocks ; // returned, as the blocks allocated in the call
builder . makeSwitch ( selector , codeSegments . size ( ) , caseValues , valueIndexToSegment , defaultSegment , segmentBlocks ) ;
// 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 ;
spv : : Id constant = createSpvConstant ( node - > getType ( ) , node - > getConstArray ( ) , nextConst ) ;
builder . clearAccessChain ( ) ;
builder . setAccessChainRValue ( constant ) ;
}
bool TGlslangToSpvTraverser : : visitLoop ( glslang : : TVisit /* visit */ , glslang : : TIntermLoop * node )
{
// body emission needs to know what the for-loop terminal is when it sees a "continue"
loopTerminal . push ( node - > getTerminal ( ) ) ;
builder . makeNewLoop ( ) ;
bool bodyOut = false ;
if ( ! node - > testFirst ( ) ) {
2015-05-15 18:44:16 +00:00
builder . endLoopHeaderWithoutTest ( ) ;
2015-03-03 17:09:43 +00:00
if ( node - > getBody ( ) ) {
breakForLoop . push ( true ) ;
node - > getBody ( ) - > traverse ( this ) ;
breakForLoop . pop ( ) ;
}
bodyOut = true ;
2015-05-15 18:44:16 +00:00
builder . createBranchToLoopTest ( ) ;
2015-03-03 17:09:43 +00:00
}
if ( node - > getTest ( ) ) {
node - > getTest ( ) - > traverse ( this ) ;
// the AST only contained the test computation, not the branch, we have to add it
spv : : Id condition = builder . accessChainLoad ( TranslatePrecisionDecoration ( node - > getTest ( ) - > getType ( ) ) ) ;
2015-05-15 18:44:16 +00:00
builder . createLoopTestBranch ( condition ) ;
2015-03-03 17:09:43 +00:00
}
if ( ! bodyOut & & node - > getBody ( ) ) {
breakForLoop . push ( true ) ;
node - > getBody ( ) - > traverse ( this ) ;
breakForLoop . pop ( ) ;
}
if ( loopTerminal . top ( ) )
loopTerminal . top ( ) - > traverse ( this ) ;
builder . closeLoop ( ) ;
loopTerminal . pop ( ) ;
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 :
if ( loopTerminal . top ( ) )
loopTerminal . top ( ) - > traverse ( this ) ;
2015-05-15 18:44:16 +00:00
builder . createLoopContinue ( ) ;
2015-03-03 17:09:43 +00:00
break ;
case glslang : : EOpReturn :
if ( inMain )
builder . makeMainReturn ( ) ;
else if ( node - > getExpression ( ) )
builder . makeReturn ( false , builder . accessChainLoad ( TranslatePrecisionDecoration ( node - > getExpression ( ) - > getType ( ) ) ) ) ;
else
builder . makeReturn ( ) ;
builder . clearAccessChain ( ) ;
break ;
default :
spv : : MissingFunctionality ( " branch type " ) ;
break ;
}
return false ;
}
spv : : Id TGlslangToSpvTraverser : : createSpvVariable ( const glslang : : TIntermSymbol * node )
{
// First, steer off constants, which are not SPIR-V variables, but
// can still have a mapping to a SPIR-V Id.
if ( node - > getQualifier ( ) . storage = = glslang : : EvqConst ) {
int nextConst = 0 ;
return createSpvConstant ( node - > getType ( ) , node - > getConstArray ( ) , nextConst ) ;
}
// 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 = " " ;
2015-06-10 23:23:12 +00:00
return builder . createVariable ( storageClass , spvType , name ) ;
2015-03-03 17:09:43 +00:00
}
// 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 :
spv : : MissingFunctionality ( " sampled type " ) ;
return builder . makeFloatType ( 32 ) ;
}
}
// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
spv : : Id TGlslangToSpvTraverser : : convertGlslangToSpvType ( const glslang : : TType & type )
{
2015-05-15 17:30:55 +00:00
spv : : Id spvType = 0 ;
2015-03-03 17:09:43 +00:00
switch ( type . getBasicType ( ) ) {
case glslang : : EbtVoid :
spvType = builder . makeVoidType ( ) ;
if ( type . isArray ( ) )
spv : : MissingFunctionality ( " array of void " ) ;
break ;
case glslang : : EbtFloat :
spvType = builder . makeFloatType ( 32 ) ;
break ;
case glslang : : EbtDouble :
spvType = builder . makeFloatType ( 64 ) ;
break ;
case glslang : : EbtBool :
spvType = builder . makeBoolType ( ) ;
break ;
case glslang : : EbtInt :
spvType = builder . makeIntType ( 32 ) ;
break ;
case glslang : : EbtUint :
spvType = builder . makeUintType ( 32 ) ;
break ;
case glslang : : EbtSampler :
{
const glslang : : TSampler & sampler = type . getSampler ( ) ;
spvType = builder . makeSampler ( getSampledType ( sampler ) , TranslateDimensionality ( sampler ) ,
sampler . image ? spv : : Builder : : samplerContentImage : spv : : Builder : : samplerContentTextureFilter ,
sampler . arrayed , sampler . shadow , sampler . ms ) ;
}
break ;
case glslang : : EbtStruct :
case glslang : : EbtBlock :
{
// If we've seen this struct type, return it
const glslang : : TTypeList * glslangStruct = type . getStruct ( ) ;
std : : vector < spv : : Id > structFields ;
spvType = structMap [ glslangStruct ] ;
if ( spvType )
break ;
// else, we haven't seen it...
// Create a vector of struct types for SPIR-V to consume
int memberDelta = 0 ; // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks
if ( type . getBasicType ( ) = = glslang : : EbtBlock )
memberRemapper [ glslangStruct ] . resize ( glslangStruct - > size ( ) ) ;
for ( int i = 0 ; i < ( int ) glslangStruct - > size ( ) ; i + + ) {
glslang : : TType & glslangType = * ( * glslangStruct ) [ i ] . type ;
if ( glslangType . hiddenMember ( ) ) {
+ + memberDelta ;
if ( type . getBasicType ( ) = = glslang : : EbtBlock )
memberRemapper [ glslangStruct ] [ i ] = - 1 ;
} else {
if ( type . getBasicType ( ) = = glslang : : EbtBlock )
memberRemapper [ glslangStruct ] [ i ] = i - memberDelta ;
structFields . push_back ( convertGlslangToSpvType ( glslangType ) ) ;
}
}
// Make the SPIR-V type
spvType = builder . makeStructType ( structFields , type . getTypeName ( ) . c_str ( ) ) ;
structMap [ glslangStruct ] = spvType ;
// Name and decorate the non-hidden members
for ( int i = 0 ; i < ( int ) glslangStruct - > size ( ) ; i + + ) {
glslang : : TType & glslangType = * ( * glslangStruct ) [ i ] . type ;
int member = i ;
if ( type . getBasicType ( ) = = glslang : : EbtBlock )
member = memberRemapper [ glslangStruct ] [ i ] ;
// using -1 above to indicate a hidden member
if ( member > = 0 ) {
builder . addMemberName ( spvType , member , glslangType . getFieldName ( ) . c_str ( ) ) ;
addMemberDecoration ( spvType , member , TranslateLayoutDecoration ( glslangType ) ) ;
addMemberDecoration ( spvType , member , TranslatePrecisionDecoration ( glslangType ) ) ;
addMemberDecoration ( spvType , member , TranslateInterpolationDecoration ( glslangType ) ) ;
addMemberDecoration ( spvType , member , TranslateInvariantDecoration ( glslangType ) ) ;
if ( glslangType . getQualifier ( ) . hasLocation ( ) )
2015-03-30 17:41:16 +00:00
builder . addMemberDecoration ( spvType , member , spv : : DecorationLocation , glslangType . getQualifier ( ) . layoutLocation ) ;
2015-03-03 17:09:43 +00:00
if ( glslangType . getQualifier ( ) . hasComponent ( ) )
2015-03-30 17:41:16 +00:00
builder . addMemberDecoration ( spvType , member , spv : : DecorationComponent , glslangType . getQualifier ( ) . layoutComponent ) ;
2015-03-03 17:09:43 +00:00
if ( glslangType . getQualifier ( ) . hasXfbOffset ( ) )
2015-03-30 17:41:16 +00:00
builder . addMemberDecoration ( spvType , member , spv : : DecorationOffset , glslangType . getQualifier ( ) . layoutXfbOffset ) ;
2015-05-22 01:53:15 +00:00
// built-in variable decorations
int builtIn = TranslateBuiltInDecoration ( glslangType . getQualifier ( ) . builtIn ) ;
if ( builtIn ! = spv : : BadValue )
builder . addMemberDecoration ( spvType , member , spv : : DecorationBuiltIn , builtIn ) ;
2015-03-03 17:09:43 +00:00
}
}
// Decorate the structure
addDecoration ( spvType , TranslateLayoutDecoration ( type ) ) ;
addDecoration ( spvType , TranslateBlockDecoration ( type ) ) ;
if ( type . getQualifier ( ) . hasStream ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( spvType , spv : : DecorationStream , type . getQualifier ( ) . layoutStream ) ;
2015-03-03 17:09:43 +00:00
if ( glslangIntermediate - > getXfbMode ( ) ) {
if ( type . getQualifier ( ) . hasXfbStride ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( spvType , spv : : DecorationStride , type . getQualifier ( ) . layoutXfbStride ) ;
2015-03-03 17:09:43 +00:00
if ( type . getQualifier ( ) . hasXfbBuffer ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( spvType , spv : : DecorationXfbBuffer , type . getQualifier ( ) . layoutXfbBuffer ) ;
2015-03-03 17:09:43 +00:00
}
}
break ;
default :
spv : : MissingFunctionality ( " basic type " ) ;
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 ( ) ) {
unsigned arraySize ;
if ( ! type . isExplicitlySizedArray ( ) ) {
spv : : MissingFunctionality ( " Unsized array " ) ;
arraySize = 8 ;
} else
arraySize = type . getArraySize ( ) ;
spvType = builder . makeArrayType ( spvType , arraySize ) ;
}
return spvType ;
}
bool TGlslangToSpvTraverser : : isShaderEntrypoint ( const glslang : : TIntermAggregate * node )
{
return node - > getName ( ) = = " main( " ;
}
// 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 ( ) ;
if ( ! glslFunction | | glslFunction - > getOp ( ) ! = glslang : : EOpFunction | | isShaderEntrypoint ( glslFunction ) )
continue ;
// We're on a user function. Set up the basic interface for the function now,
// so that it's available to call.
// Translating the body will happen later.
//
// Typically (except for a "const in" parameter), an address will be passed to the
// function. What it is an address of varies:
//
// - "in" parameters not marked as "const" can be written to without modifying the argument,
// so that write needs to be to a copy, hence the address of a copy works.
//
// - "const in" parameters can just be the r-value, as no writes need occur.
//
// - "out" and "inout" arguments can't be done as direct pointers, because GLSL has
// copy-in/copy-out semantics. They can be handled though with a pointer to a copy.
std : : vector < spv : : Id > paramTypes ;
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 ) ;
if ( paramType . getQualifier ( ) . storage ! = glslang : : EvqConstReadOnly )
2015-03-30 17:41:16 +00:00
typeId = builder . makePointer ( spv : : StorageClassFunction , typeId ) ;
2015-03-03 17:09:43 +00:00
else
constReadOnlyParameters . insert ( parameters [ p ] - > getAsSymbolNode ( ) - > getId ( ) ) ;
paramTypes . push_back ( typeId ) ;
}
spv : : Block * functionBlock ;
spv : : Function * function = builder . makeFunctionEntry ( convertGlslangToSpvType ( glslFunction - > getType ( ) ) , glslFunction - > getName ( ) . c_str ( ) ,
paramTypes , & functionBlock ) ;
// 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
// code goes into the beginning of main.
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 ( ) ;
if ( node & & ( node - > getOp ( ) = = glslang : : EOpFunction | | node - > getOp ( ) = = glslang : : EOpLinkerObjects ) )
node - > traverse ( this ) ;
}
}
void TGlslangToSpvTraverser : : handleFunctionEntry ( const glslang : : TIntermAggregate * node )
{
// SPIR-V functions should already be in the functionMap from the prepass
// that called makeFunctions().
spv : : Function * function = functionMap [ node - > getName ( ) . c_str ( ) ] ;
spv : : Block * functionBlock = function - > getEntryBlock ( ) ;
builder . setBuildPoint ( functionBlock ) ;
}
void TGlslangToSpvTraverser : : translateArguments ( const glslang : : TIntermSequence & glslangArguments , std : : vector < spv : : Id > & arguments )
{
for ( int i = 0 ; i < ( int ) glslangArguments . size ( ) ; + + i ) {
builder . clearAccessChain ( ) ;
glslangArguments [ i ] - > traverse ( this ) ;
arguments . push_back ( builder . accessChainLoad ( TranslatePrecisionDecoration ( glslangArguments [ i ] - > getAsTyped ( ) - > getType ( ) ) ) ) ;
}
}
spv : : Id TGlslangToSpvTraverser : : handleBuiltInFunctionCall ( const glslang : : TIntermAggregate * node )
{
std : : vector < spv : : Id > arguments ;
translateArguments ( node - > getSequence ( ) , arguments ) ;
std : : vector < spv : : Id > argTypes ;
for ( int a = 0 ; a < ( int ) arguments . size ( ) ; + + a )
argTypes . push_back ( builder . getTypeId ( arguments [ a ] ) ) ;
spv : : Decoration precision = TranslatePrecisionDecoration ( node - > getType ( ) ) ;
if ( node - > getName ( ) = = " ftransform( " ) {
spv : : MissingFunctionality ( " ftransform() " ) ;
//spv::Id vertex = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),
// "gl_Vertex_sim");
//spv::Id matrix = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),
// "gl_ModelViewProjectionMatrix_sim");
return 0 ;
}
if ( node - > getName ( ) . substr ( 0 , 7 ) = = " texture " | | node - > getName ( ) . substr ( 0 , 5 ) = = " texel " | | node - > getName ( ) . substr ( 0 , 6 ) = = " shadow " ) {
const glslang : : TSampler sampler = node - > getSequence ( ) [ 0 ] - > getAsTyped ( ) - > getType ( ) . getSampler ( ) ;
spv : : Builder : : TextureParameters params = { } ;
params . sampler = arguments [ 0 ] ;
// special case size query
if ( node - > getName ( ) . find ( " textureSize " , 0 ) ! = std : : string : : npos ) {
if ( arguments . size ( ) > 1 ) {
params . lod = arguments [ 1 ] ;
return builder . createTextureQueryCall ( spv : : OpTextureQuerySizeLod , params ) ;
} else
return builder . createTextureQueryCall ( spv : : OpTextureQuerySize , params ) ;
}
// special case the number of samples query
if ( node - > getName ( ) . find ( " textureSamples " , 0 ) ! = std : : string : : npos )
return builder . createTextureQueryCall ( spv : : OpTextureQuerySamples , params ) ;
// special case the other queries
if ( node - > getName ( ) . find ( " Query " , 0 ) ! = std : : string : : npos ) {
if ( node - > getName ( ) . find ( " Levels " , 0 ) ! = std : : string : : npos )
return builder . createTextureQueryCall ( spv : : OpTextureQueryLevels , params ) ;
else if ( node - > getName ( ) . find ( " Lod " , 0 ) ! = std : : string : : npos ) {
params . coords = arguments [ 1 ] ;
return builder . createTextureQueryCall ( spv : : OpTextureQueryLod , params ) ;
} else
spv : : MissingFunctionality ( " glslang texture query " ) ;
}
// This is no longer a query....
bool lod = node - > getName ( ) . find ( " Lod " , 0 ) ! = std : : string : : npos ;
bool proj = node - > getName ( ) . find ( " Proj " , 0 ) ! = std : : string : : npos ;
bool offsets = node - > getName ( ) . find ( " Offsets " , 0 ) ! = std : : string : : npos ;
bool offset = ! offsets & & node - > getName ( ) . find ( " Offset " , 0 ) ! = std : : string : : npos ;
bool fetch = node - > getName ( ) . find ( " Fetch " , 0 ) ! = std : : string : : npos ;
bool gather = node - > getName ( ) . find ( " Gather " , 0 ) ! = std : : string : : npos ;
bool grad = node - > getName ( ) . find ( " Grad " , 0 ) ! = std : : string : : npos ;
if ( fetch )
spv : : MissingFunctionality ( " texel fetch " ) ;
if ( gather )
spv : : MissingFunctionality ( " texture gather " ) ;
// check for bias argument
bool bias = false ;
if ( ! lod & & ! gather & & ! grad & & ! fetch ) {
int nonBiasArgCount = 2 ;
if ( offset )
+ + nonBiasArgCount ;
if ( grad )
nonBiasArgCount + = 2 ;
if ( ( int ) arguments . size ( ) > nonBiasArgCount )
bias = true ;
}
bool cubeCompare = sampler . dim = = glslang : : EsdCube & & sampler . arrayed & & sampler . shadow ;
// set the rest of the arguments
params . coords = arguments [ 1 ] ;
int extraArgs = 0 ;
if ( cubeCompare )
params . Dref = arguments [ 2 ] ;
if ( lod ) {
params . lod = arguments [ 2 ] ;
+ + extraArgs ;
}
if ( grad ) {
params . gradX = arguments [ 2 + extraArgs ] ;
params . gradY = arguments [ 3 + extraArgs ] ;
extraArgs + = 2 ;
}
//if (gather && compare) {
// params.compare = arguments[2 + extraArgs];
// ++extraArgs;
//}
if ( offset | offsets ) {
params . offset = arguments [ 2 + extraArgs ] ;
+ + extraArgs ;
}
if ( bias ) {
params . bias = arguments [ 2 + extraArgs ] ;
+ + extraArgs ;
}
return builder . createTextureCall ( precision , convertGlslangToSpvType ( node - > getType ( ) ) , proj , params ) ;
}
spv : : MissingFunctionality ( " built-in function call " ) ;
return 0 ;
}
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 ;
for ( int a = 0 ; a < ( int ) glslangArgs . size ( ) ; + + a ) {
// build l-value
builder . clearAccessChain ( ) ;
glslangArgs [ a ] - > traverse ( this ) ;
// keep outputs as l-values, evaluate input-only as r-values
if ( qualifiers [ a ] ! = glslang : : EvqConstReadOnly ) {
// save l-value
lValues . push_back ( builder . getAccessChain ( ) ) ;
} else {
// process r-value
rValues . push_back ( builder . accessChainLoad ( TranslatePrecisionDecoration ( glslangArgs [ a ] - > getAsTyped ( ) - > getType ( ) ) ) ) ;
}
}
// 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 ) {
spv : : Id arg ;
if ( qualifiers [ a ] ! = glslang : : EvqConstReadOnly ) {
// need space to hold the copy
const glslang : : TType & paramType = glslangArgs [ a ] - > getAsTyped ( ) - > getType ( ) ;
2015-03-30 17:41:16 +00:00
arg = builder . createVariable ( spv : : StorageClassFunction , convertGlslangToSpvType ( paramType ) , " param " ) ;
2015-03-03 17:09:43 +00:00
if ( qualifiers [ a ] = = glslang : : EvqIn | | qualifiers [ a ] = = glslang : : EvqInOut ) {
// need to copy the input into output space
builder . setAccessChain ( lValues [ lValueCount ] ) ;
2015-03-30 17:41:16 +00:00
spv : : Id copy = builder . accessChainLoad ( spv : : NoPrecision ) ; // TODO: get precision
2015-03-03 17:09:43 +00:00
builder . createStore ( copy , arg ) ;
}
+ + lValueCount ;
} else {
arg = rValues [ rValueCount ] ;
+ + rValueCount ;
}
spvArgs . push_back ( arg ) ;
}
// 3. Make the call.
spv : : Id result = builder . createFunctionCall ( function , spvArgs ) ;
// 4. Copy back out an "out" arguments.
lValueCount = 0 ;
for ( int a = 0 ; a < ( int ) glslangArgs . size ( ) ; + + a ) {
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 ] ) ;
builder . accessChainStore ( copy ) ;
}
+ + lValueCount ;
}
}
return result ;
}
2015-06-13 00:48:48 +00:00
// Translate AST operation to SPV operation, already having SPV-based operands/types.
2015-03-03 17:09:43 +00:00
spv : : Id TGlslangToSpvTraverser : : createBinaryOperation ( glslang : : TOperator op , spv : : Decoration precision ,
2015-06-13 00:48:48 +00:00
spv : : Id typeId , spv : : Id left , spv : : Id right ,
glslang : : TBasicType typeProxy , bool reduceComparison )
2015-03-03 17:09:43 +00:00
{
bool isUnsigned = typeProxy = = glslang : : EbtUint ;
bool isFloat = typeProxy = = glslang : : EbtFloat | | typeProxy = = glslang : : EbtDouble ;
2015-03-30 17:41:16 +00:00
spv : : Op binOp = spv : : OpNop ;
2015-03-03 17:09:43 +00:00
bool needsPromotion = true ;
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 :
2015-06-13 00:48:48 +00:00
if ( builder . isVector ( right ) )
std : : swap ( left , right ) ;
assert ( builder . isScalar ( right ) ) ;
2015-03-03 17:09:43 +00:00
binOp = spv : : OpVectorTimesScalar ;
needsPromotion = false ;
break ;
case glslang : : EOpVectorTimesMatrix :
case glslang : : EOpVectorTimesMatrixAssign :
2015-06-13 00:48:48 +00:00
assert ( builder . isVector ( left ) ) ;
assert ( builder . isMatrix ( right ) ) ;
2015-03-03 17:09:43 +00:00
binOp = spv : : OpVectorTimesMatrix ;
break ;
case glslang : : EOpMatrixTimesVector :
2015-06-13 00:48:48 +00:00
assert ( builder . isMatrix ( left ) ) ;
assert ( builder . isVector ( right ) ) ;
2015-03-03 17:09:43 +00:00
binOp = spv : : OpMatrixTimesVector ;
break ;
case glslang : : EOpMatrixTimesScalar :
case glslang : : EOpMatrixTimesScalarAssign :
2015-06-13 00:48:48 +00:00
if ( builder . isMatrix ( right ) )
std : : swap ( left , right ) ;
assert ( builder . isScalar ( right ) ) ;
2015-03-03 17:09:43 +00:00
binOp = spv : : OpMatrixTimesScalar ;
break ;
case glslang : : EOpMatrixTimesMatrix :
case glslang : : EOpMatrixTimesMatrixAssign :
2015-06-13 00:48:48 +00:00
assert ( builder . isMatrix ( left ) ) ;
assert ( builder . isMatrix ( right ) ) ;
2015-03-03 17:09:43 +00:00
binOp = spv : : OpMatrixTimesMatrix ;
break ;
case glslang : : EOpOuterProduct :
binOp = spv : : OpOuterProduct ;
needsPromotion = false ;
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 :
needsPromotion = false ;
binOp = spv : : OpLogicalAnd ;
break ;
case glslang : : EOpInclusiveOr :
case glslang : : EOpInclusiveOrAssign :
binOp = spv : : OpBitwiseOr ;
break ;
case glslang : : EOpLogicalOr :
needsPromotion = false ;
binOp = spv : : OpLogicalOr ;
break ;
case glslang : : EOpExclusiveOr :
case glslang : : EOpExclusiveOrAssign :
binOp = spv : : OpBitwiseXor ;
break ;
case glslang : : EOpLogicalXor :
needsPromotion = false ;
binOp = spv : : OpLogicalXor ;
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 ;
}
if ( binOp ! = spv : : OpNop ) {
if ( builder . isMatrix ( left ) | | builder . isMatrix ( right ) ) {
switch ( binOp ) {
case spv : : OpMatrixTimesScalar :
case spv : : OpVectorTimesMatrix :
case spv : : OpMatrixTimesVector :
case spv : : OpMatrixTimesMatrix :
break ;
case spv : : OpFDiv :
// turn it into a multiply...
assert ( builder . isMatrix ( left ) & & builder . isScalar ( right ) ) ;
right = builder . createBinOp ( spv : : OpFDiv , builder . getTypeId ( right ) , builder . makeFloatConstant ( 1.0F ) , right ) ;
binOp = spv : : OpFMul ;
break ;
default :
spv : : MissingFunctionality ( " binary operation on matrix " ) ;
break ;
}
spv : : Id id = builder . createBinOp ( binOp , typeId , left , right ) ;
builder . setPrecision ( id , precision ) ;
return id ;
}
// No matrix involved; make both operands be the same number of components, if needed
if ( needsPromotion )
builder . promoteScalar ( precision , left , right ) ;
spv : : Id id = builder . createBinOp ( binOp , typeId , left , right ) ;
builder . setPrecision ( id , precision ) ;
return id ;
}
if ( ! comparison )
return 0 ;
// Comparison instructions
if ( reduceComparison & & ( builder . isVector ( left ) | | builder . isMatrix ( left ) | | builder . isAggregate ( left ) ) ) {
assert ( op = = glslang : : EOpEqual | | op = = glslang : : EOpNotEqual ) ;
return builder . createCompare ( precision , left , right , op = = glslang : : EOpEqual ) ;
}
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 ;
else
binOp = spv : : OpIEqual ;
break ;
case glslang : : EOpNotEqual :
case glslang : : EOpVectorNotEqual :
if ( isFloat )
binOp = spv : : OpFOrdNotEqual ;
else
binOp = spv : : OpINotEqual ;
break ;
default :
break ;
}
if ( binOp ! = spv : : OpNop ) {
spv : : Id id = builder . createBinOp ( binOp , typeId , left , right ) ;
builder . setPrecision ( id , precision ) ;
return id ;
}
return 0 ;
}
spv : : Id TGlslangToSpvTraverser : : createUnaryOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id typeId , spv : : Id operand , bool isFloat )
{
2015-03-30 17:41:16 +00:00
spv : : Op unaryOp = spv : : OpNop ;
2015-03-03 17:09:43 +00:00
int libCall = - 1 ;
switch ( op ) {
case glslang : : EOpNegative :
if ( isFloat )
unaryOp = spv : : OpFNegate ;
else
unaryOp = spv : : OpSNegate ;
break ;
case glslang : : EOpLogicalNot :
case glslang : : EOpVectorLogicalNot :
case glslang : : EOpBitwiseNot :
unaryOp = spv : : OpNot ;
break ;
case glslang : : EOpDeterminant :
libCall = GLSL_STD_450 : : Determinant ;
break ;
case glslang : : EOpMatrixInverse :
libCall = GLSL_STD_450 : : MatrixInverse ;
break ;
case glslang : : EOpTranspose :
unaryOp = spv : : OpTranspose ;
break ;
case glslang : : EOpRadians :
libCall = GLSL_STD_450 : : Radians ;
break ;
case glslang : : EOpDegrees :
libCall = GLSL_STD_450 : : Degrees ;
break ;
case glslang : : EOpSin :
libCall = GLSL_STD_450 : : Sin ;
break ;
case glslang : : EOpCos :
libCall = GLSL_STD_450 : : Cos ;
break ;
case glslang : : EOpTan :
libCall = GLSL_STD_450 : : Tan ;
break ;
case glslang : : EOpAcos :
libCall = GLSL_STD_450 : : Acos ;
break ;
case glslang : : EOpAsin :
libCall = GLSL_STD_450 : : Asin ;
break ;
case glslang : : EOpAtan :
libCall = GLSL_STD_450 : : Atan ;
break ;
case glslang : : EOpAcosh :
libCall = GLSL_STD_450 : : Acosh ;
break ;
case glslang : : EOpAsinh :
libCall = GLSL_STD_450 : : Asinh ;
break ;
case glslang : : EOpAtanh :
libCall = GLSL_STD_450 : : Atanh ;
break ;
case glslang : : EOpTanh :
libCall = GLSL_STD_450 : : Tanh ;
break ;
case glslang : : EOpCosh :
libCall = GLSL_STD_450 : : Cosh ;
break ;
case glslang : : EOpSinh :
libCall = GLSL_STD_450 : : Sinh ;
break ;
case glslang : : EOpLength :
libCall = GLSL_STD_450 : : Length ;
break ;
case glslang : : EOpNormalize :
libCall = GLSL_STD_450 : : Normalize ;
break ;
case glslang : : EOpExp :
libCall = GLSL_STD_450 : : Exp ;
break ;
case glslang : : EOpLog :
libCall = GLSL_STD_450 : : Log ;
break ;
case glslang : : EOpExp2 :
libCall = GLSL_STD_450 : : Exp2 ;
break ;
case glslang : : EOpLog2 :
libCall = GLSL_STD_450 : : Log2 ;
break ;
case glslang : : EOpSqrt :
libCall = GLSL_STD_450 : : Sqrt ;
break ;
case glslang : : EOpInverseSqrt :
libCall = GLSL_STD_450 : : InverseSqrt ;
break ;
case glslang : : EOpFloor :
libCall = GLSL_STD_450 : : Floor ;
break ;
case glslang : : EOpTrunc :
libCall = GLSL_STD_450 : : Trunc ;
break ;
case glslang : : EOpRound :
libCall = GLSL_STD_450 : : Round ;
break ;
case glslang : : EOpRoundEven :
libCall = GLSL_STD_450 : : RoundEven ;
break ;
case glslang : : EOpCeil :
libCall = GLSL_STD_450 : : Ceil ;
break ;
case glslang : : EOpFract :
libCall = GLSL_STD_450 : : Fract ;
break ;
case glslang : : EOpIsNan :
unaryOp = spv : : OpIsNan ;
break ;
case glslang : : EOpIsInf :
unaryOp = spv : : OpIsInf ;
break ;
case glslang : : EOpFloatBitsToInt :
libCall = GLSL_STD_450 : : FloatBitsToInt ;
break ;
case glslang : : EOpFloatBitsToUint :
libCall = GLSL_STD_450 : : FloatBitsToUint ;
break ;
case glslang : : EOpIntBitsToFloat :
libCall = GLSL_STD_450 : : IntBitsToFloat ;
break ;
case glslang : : EOpUintBitsToFloat :
libCall = GLSL_STD_450 : : UintBitsToFloat ;
break ;
case glslang : : EOpPackSnorm2x16 :
libCall = GLSL_STD_450 : : PackSnorm2x16 ;
break ;
case glslang : : EOpUnpackSnorm2x16 :
libCall = GLSL_STD_450 : : UnpackSnorm2x16 ;
break ;
case glslang : : EOpPackUnorm2x16 :
libCall = GLSL_STD_450 : : PackUnorm2x16 ;
break ;
case glslang : : EOpUnpackUnorm2x16 :
libCall = GLSL_STD_450 : : UnpackUnorm2x16 ;
break ;
case glslang : : EOpPackHalf2x16 :
libCall = GLSL_STD_450 : : PackHalf2x16 ;
break ;
case glslang : : EOpUnpackHalf2x16 :
libCall = GLSL_STD_450 : : UnpackHalf2x16 ;
break ;
case glslang : : EOpDPdx :
unaryOp = spv : : OpDPdx ;
break ;
case glslang : : EOpDPdy :
unaryOp = spv : : OpDPdy ;
break ;
case glslang : : EOpFwidth :
unaryOp = spv : : OpFwidth ;
break ;
case glslang : : EOpDPdxFine :
unaryOp = spv : : OpDPdxFine ;
break ;
case glslang : : EOpDPdyFine :
unaryOp = spv : : OpDPdyFine ;
break ;
case glslang : : EOpFwidthFine :
unaryOp = spv : : OpFwidthFine ;
break ;
case glslang : : EOpDPdxCoarse :
unaryOp = spv : : OpDPdxCoarse ;
break ;
case glslang : : EOpDPdyCoarse :
unaryOp = spv : : OpDPdyCoarse ;
break ;
case glslang : : EOpFwidthCoarse :
unaryOp = spv : : OpFwidthCoarse ;
break ;
case glslang : : EOpAny :
unaryOp = spv : : OpAny ;
break ;
case glslang : : EOpAll :
unaryOp = spv : : OpAll ;
break ;
case glslang : : EOpAbs :
libCall = GLSL_STD_450 : : Abs ;
break ;
case glslang : : EOpSign :
libCall = GLSL_STD_450 : : Sign ;
break ;
default :
return 0 ;
}
spv : : Id id ;
if ( libCall > = 0 ) {
std : : vector < spv : : Id > args ;
args . push_back ( operand ) ;
id = builder . createBuiltinCall ( precision , typeId , stdBuiltins , libCall , args ) ;
} else
id = builder . createUnaryOp ( unaryOp , typeId , operand ) ;
builder . setPrecision ( id , precision ) ;
return id ;
}
spv : : Id TGlslangToSpvTraverser : : createConversion ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id destType , spv : : Id operand )
{
2015-03-30 17:41:16 +00:00
spv : : Op convOp = spv : : OpNop ;
2015-05-15 17:30:55 +00:00
spv : : Id zero = 0 ;
spv : : Id one = 0 ;
2015-03-03 17:09:43 +00:00
int vectorSize = builder . isVectorType ( destType ) ? builder . getNumTypeComponents ( destType ) : 0 ;
switch ( op ) {
case glslang : : EOpConvIntToBool :
case glslang : : EOpConvUintToBool :
zero = builder . makeUintConstant ( 0 ) ;
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 ) ;
case glslang : : EOpConvBoolToFloat :
convOp = spv : : OpSelect ;
zero = builder . makeFloatConstant ( 0.0 ) ;
one = builder . makeFloatConstant ( 1.0 ) ;
break ;
case glslang : : EOpConvBoolToDouble :
convOp = spv : : OpSelect ;
zero = builder . makeDoubleConstant ( 0.0 ) ;
one = builder . makeDoubleConstant ( 1.0 ) ;
break ;
case glslang : : EOpConvBoolToInt :
zero = builder . makeIntConstant ( 0 ) ;
one = builder . makeIntConstant ( 1 ) ;
convOp = spv : : OpSelect ;
break ;
case glslang : : EOpConvBoolToUint :
zero = builder . makeUintConstant ( 0 ) ;
one = builder . makeUintConstant ( 1 ) ;
convOp = spv : : OpSelect ;
break ;
case glslang : : EOpConvIntToFloat :
case glslang : : EOpConvIntToDouble :
convOp = spv : : OpConvertSToF ;
break ;
case glslang : : EOpConvUintToFloat :
case glslang : : EOpConvUintToDouble :
convOp = spv : : OpConvertUToF ;
break ;
2015-05-18 23:25:32 +00:00
2015-03-03 17:09:43 +00:00
case glslang : : EOpConvDoubleToFloat :
case glslang : : EOpConvFloatToDouble :
convOp = spv : : OpFConvert ;
break ;
case glslang : : EOpConvFloatToInt :
case glslang : : EOpConvDoubleToInt :
convOp = spv : : OpConvertFToS ;
break ;
case glslang : : EOpConvUintToInt :
case glslang : : EOpConvIntToUint :
convOp = spv : : OpBitcast ;
break ;
case glslang : : EOpConvFloatToUint :
case glslang : : EOpConvDoubleToUint :
convOp = spv : : OpConvertFToU ;
break ;
default :
break ;
}
spv : : Id result = 0 ;
if ( convOp = = spv : : OpNop )
return result ;
if ( convOp = = spv : : OpSelect ) {
zero = makeSmearedConstant ( zero , vectorSize ) ;
one = makeSmearedConstant ( one , vectorSize ) ;
2015-05-18 23:25:32 +00:00
result = builder . createTriOp ( convOp , destType , operand , one , zero ) ;
2015-03-03 17:09:43 +00:00
} else
result = builder . createUnaryOp ( convOp , destType , operand ) ;
builder . setPrecision ( result , precision ) ;
return result ;
}
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-05-15 17:30:55 +00:00
spv : : Id TGlslangToSpvTraverser : : createMiscOperation ( glslang : : TOperator op , spv : : Decoration precision , spv : : Id typeId , std : : vector < spv : : Id > & operands )
2015-03-03 17:09:43 +00:00
{
2015-03-30 17:41:16 +00:00
spv : : Op opCode = spv : : OpNop ;
2015-03-03 17:09:43 +00:00
int libCall = - 1 ;
switch ( op ) {
case glslang : : EOpMin :
libCall = GLSL_STD_450 : : Min ;
break ;
case glslang : : EOpModf :
libCall = GLSL_STD_450 : : Modf ;
break ;
case glslang : : EOpMax :
libCall = GLSL_STD_450 : : Max ;
break ;
case glslang : : EOpPow :
libCall = GLSL_STD_450 : : Pow ;
break ;
case glslang : : EOpDot :
opCode = spv : : OpDot ;
break ;
case glslang : : EOpAtan :
libCall = GLSL_STD_450 : : Atan2 ;
break ;
case glslang : : EOpClamp :
libCall = GLSL_STD_450 : : Clamp ;
break ;
case glslang : : EOpMix :
libCall = GLSL_STD_450 : : Mix ;
break ;
case glslang : : EOpStep :
libCall = GLSL_STD_450 : : Step ;
break ;
case glslang : : EOpSmoothStep :
libCall = GLSL_STD_450 : : SmoothStep ;
break ;
case glslang : : EOpDistance :
libCall = GLSL_STD_450 : : Distance ;
break ;
case glslang : : EOpCross :
libCall = GLSL_STD_450 : : Cross ;
break ;
case glslang : : EOpFaceForward :
libCall = GLSL_STD_450 : : FaceForward ;
break ;
case glslang : : EOpReflect :
libCall = GLSL_STD_450 : : Reflect ;
break ;
case glslang : : EOpRefract :
libCall = GLSL_STD_450 : : Refract ;
break ;
default :
return 0 ;
}
spv : : Id id = 0 ;
if ( libCall > = 0 )
id = builder . createBuiltinCall ( precision , typeId , stdBuiltins , libCall , operands ) ;
else {
switch ( operands . size ( ) ) {
case 0 :
2015-03-24 00:32:50 +00:00
// should all be handled by visitAggregate and createNoArgOperation
assert ( 0 ) ;
return 0 ;
2015-03-03 17:09:43 +00:00
case 1 :
// should all be handled by createUnaryOperation
assert ( 0 ) ;
2015-03-24 00:32:50 +00:00
return 0 ;
2015-03-03 17:09:43 +00:00
case 2 :
id = builder . createBinOp ( opCode , typeId , operands [ 0 ] , operands [ 1 ] ) ;
break ;
case 3 :
id = builder . createTernaryOp ( opCode , typeId , operands [ 0 ] , operands [ 1 ] , operands [ 2 ] ) ;
break ;
default :
// These do not exist yet
assert ( 0 & & " operation with more than 3 operands " ) ;
break ;
}
}
builder . setPrecision ( id , precision ) ;
return id ;
}
// Intrinsics with no arguments, no return value, and no precision.
spv : : Id TGlslangToSpvTraverser : : createNoArgOperation ( glslang : : TOperator op )
{
// TODO: get the barrier operands correct
switch ( op ) {
case glslang : : EOpEmitVertex :
2015-03-24 00:32:50 +00:00
builder . createNoResultOp ( spv : : OpEmitVertex ) ;
return 0 ;
2015-03-03 17:09:43 +00:00
case glslang : : EOpEndPrimitive :
2015-03-24 00:32:50 +00:00
builder . createNoResultOp ( spv : : OpEndPrimitive ) ;
return 0 ;
2015-03-03 17:09:43 +00:00
case glslang : : EOpBarrier :
builder . createMemoryBarrier ( spv : : ExecutionScopeDevice , spv : : MemorySemanticsAllMemory ) ;
builder . createControlBarrier ( spv : : ExecutionScopeDevice ) ;
return 0 ;
case glslang : : EOpMemoryBarrier :
builder . createMemoryBarrier ( spv : : ExecutionScopeDevice , spv : : MemorySemanticsAllMemory ) ;
return 0 ;
case glslang : : EOpMemoryBarrierAtomicCounter :
2015-03-30 17:41:16 +00:00
builder . createMemoryBarrier ( spv : : ExecutionScopeDevice , spv : : MemorySemanticsAtomicCounterMemoryMask ) ;
2015-03-03 17:09:43 +00:00
return 0 ;
case glslang : : EOpMemoryBarrierBuffer :
2015-03-30 17:41:16 +00:00
builder . createMemoryBarrier ( spv : : ExecutionScopeDevice , spv : : MemorySemanticsUniformMemoryMask ) ;
2015-03-03 17:09:43 +00:00
return 0 ;
case glslang : : EOpMemoryBarrierImage :
2015-03-30 17:41:16 +00:00
builder . createMemoryBarrier ( spv : : ExecutionScopeDevice , spv : : MemorySemanticsImageMemoryMask ) ;
2015-03-03 17:09:43 +00:00
return 0 ;
case glslang : : EOpMemoryBarrierShared :
2015-03-30 17:41:16 +00:00
builder . createMemoryBarrier ( spv : : ExecutionScopeDevice , spv : : MemorySemanticsWorkgroupLocalMemoryMask ) ;
2015-03-03 17:09:43 +00:00
return 0 ;
case glslang : : EOpGroupMemoryBarrier :
2015-03-30 17:41:16 +00:00
builder . createMemoryBarrier ( spv : : ExecutionScopeDevice , spv : : MemorySemanticsWorkgroupGlobalMemoryMask ) ;
2015-03-03 17:09:43 +00:00
return 0 ;
default :
spv : : MissingFunctionality ( " operation with no arguments " ) ;
return 0 ;
}
}
spv : : Id TGlslangToSpvTraverser : : getSymbolId ( const glslang : : TIntermSymbol * symbol )
{
std : : map < int , spv : : Id > : : iterator iter ;
iter = symbolValues . find ( symbol - > getId ( ) ) ;
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 ;
if ( ! symbol - > getType ( ) . isStruct ( ) ) {
addDecoration ( id , TranslatePrecisionDecoration ( symbol - > getType ( ) ) ) ;
addDecoration ( id , TranslateInterpolationDecoration ( symbol - > getType ( ) ) ) ;
if ( symbol - > getQualifier ( ) . hasLocation ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( id , spv : : DecorationLocation , symbol - > getQualifier ( ) . layoutLocation ) ;
2015-04-27 10:03:25 +00:00
if ( symbol - > getQualifier ( ) . hasIndex ( ) )
builder . addDecoration ( id , spv : : DecorationIndex , symbol - > getQualifier ( ) . layoutIndex ) ;
2015-03-03 17:09:43 +00:00
if ( symbol - > getQualifier ( ) . hasComponent ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( id , spv : : DecorationComponent , symbol - > getQualifier ( ) . layoutComponent ) ;
2015-03-03 17:09:43 +00:00
if ( glslangIntermediate - > getXfbMode ( ) ) {
if ( symbol - > getQualifier ( ) . hasXfbStride ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( id , spv : : DecorationStride , symbol - > getQualifier ( ) . layoutXfbStride ) ;
2015-03-03 17:09:43 +00:00
if ( symbol - > getQualifier ( ) . hasXfbBuffer ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( id , spv : : DecorationXfbBuffer , symbol - > getQualifier ( ) . layoutXfbBuffer ) ;
2015-03-03 17:09:43 +00:00
if ( symbol - > getQualifier ( ) . hasXfbOffset ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( id , spv : : DecorationOffset , symbol - > getQualifier ( ) . layoutXfbOffset ) ;
2015-03-03 17:09:43 +00:00
}
}
addDecoration ( id , TranslateInvariantDecoration ( symbol - > getType ( ) ) ) ;
if ( symbol - > getQualifier ( ) . hasStream ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( id , spv : : DecorationStream , symbol - > getQualifier ( ) . layoutStream ) ;
2015-03-03 17:09:43 +00:00
if ( symbol - > getQualifier ( ) . hasSet ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( id , spv : : DecorationDescriptorSet , symbol - > getQualifier ( ) . layoutSet ) ;
2015-03-03 17:09:43 +00:00
if ( symbol - > getQualifier ( ) . hasBinding ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( id , spv : : DecorationBinding , symbol - > getQualifier ( ) . layoutBinding ) ;
2015-03-03 17:09:43 +00:00
if ( glslangIntermediate - > getXfbMode ( ) ) {
if ( symbol - > getQualifier ( ) . hasXfbStride ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( id , spv : : DecorationStride , symbol - > getQualifier ( ) . layoutXfbStride ) ;
2015-03-03 17:09:43 +00:00
if ( symbol - > getQualifier ( ) . hasXfbBuffer ( ) )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( id , spv : : DecorationXfbBuffer , symbol - > getQualifier ( ) . layoutXfbBuffer ) ;
2015-03-03 17:09:43 +00:00
}
// built-in variable decorations
2015-05-22 01:53:15 +00:00
int builtIn = TranslateBuiltInDecoration ( symbol - > getQualifier ( ) . builtIn ) ;
if ( builtIn ! = spv : : BadValue )
builder . addDecoration ( id , spv : : DecorationBuiltIn , builtIn ) ;
2015-03-03 17:09:43 +00:00
if ( linkageOnly )
2015-03-30 17:41:16 +00:00
builder . addDecoration ( id , spv : : DecorationNoStaticUse ) ;
2015-03-03 17:09:43 +00:00
return id ;
}
void TGlslangToSpvTraverser : : addDecoration ( spv : : Id id , spv : : Decoration dec )
{
2015-03-30 17:41:16 +00:00
if ( dec ! = spv : : BadValue )
2015-03-03 17:09:43 +00:00
builder . addDecoration ( id , dec ) ;
}
void TGlslangToSpvTraverser : : addMemberDecoration ( spv : : Id id , int member , spv : : Decoration dec )
{
2015-03-30 17:41:16 +00:00
if ( dec ! = spv : : BadValue )
2015-03-03 17:09:43 +00:00
builder . addMemberDecoration ( id , ( unsigned ) member , dec ) ;
}
// 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.
//
spv : : Id TGlslangToSpvTraverser : : createSpvConstant ( const glslang : : TType & glslangType , const glslang : : TConstUnionArray & consts , int & nextConst )
{
// 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 ( ) ) {
glslang : : TType elementType ;
elementType . shallowCopy ( glslangType ) ; // TODO: desktop arrays of arrays functionality will need a deeper copy to avoid modifying the original
elementType . dereference ( ) ;
for ( int i = 0 ; i < glslangType . getArraySize ( ) ; + + i )
spvConsts . push_back ( createSpvConstant ( elementType , consts , nextConst ) ) ;
} else if ( glslangType . isMatrix ( ) ) {
glslang : : TType vectorType ;
vectorType . shallowCopy ( glslangType ) ;
vectorType . dereference ( ) ;
for ( int col = 0 ; col < glslangType . getMatrixCols ( ) ; + + col )
spvConsts . push_back ( createSpvConstant ( vectorType , consts , nextConst ) ) ;
} else if ( glslangType . getStruct ( ) ) {
glslang : : TVector < glslang : : TTypeLoc > : : const_iterator iter ;
for ( iter = glslangType . getStruct ( ) - > begin ( ) ; iter ! = glslangType . getStruct ( ) - > end ( ) ; + + iter )
spvConsts . push_back ( createSpvConstant ( * iter - > type , consts , nextConst ) ) ;
} else if ( glslangType . isVector ( ) ) {
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 ;
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 ;
case glslang : : EbtBool :
spvConsts . push_back ( builder . makeBoolConstant ( zero ? false : consts [ nextConst ] . getBConst ( ) ) ) ;
break ;
default :
spv : : MissingFunctionality ( " constant vector type " ) ;
break ;
}
+ + nextConst ;
}
} else {
// we have a non-aggregate (scalar) constant
bool zero = nextConst > = consts . size ( ) ;
2015-05-15 17:30:55 +00:00
spv : : Id scalar = 0 ;
2015-03-03 17:09:43 +00:00
switch ( glslangType . getBasicType ( ) ) {
case glslang : : EbtInt :
scalar = builder . makeIntConstant ( zero ? 0 : consts [ nextConst ] . getIConst ( ) ) ;
break ;
case glslang : : EbtUint :
scalar = builder . makeUintConstant ( zero ? 0 : consts [ nextConst ] . getUConst ( ) ) ;
break ;
case glslang : : EbtFloat :
scalar = builder . makeFloatConstant ( zero ? 0.0F : ( float ) consts [ nextConst ] . getDConst ( ) ) ;
break ;
case glslang : : EbtDouble :
scalar = builder . makeDoubleConstant ( zero ? 0.0 : consts [ nextConst ] . getDConst ( ) ) ;
break ;
case glslang : : EbtBool :
scalar = builder . makeBoolConstant ( zero ? false : consts [ nextConst ] . getBConst ( ) ) ;
break ;
default :
spv : : MissingFunctionality ( " constant scalar type " ) ;
break ;
}
+ + nextConst ;
return scalar ;
}
return builder . makeCompositeConstant ( typeId , spvConsts ) ;
}
} ; // end anonymous namespace
namespace glslang {
// Write SPIR-V out to a binary file
void OutputSpv ( const std : : vector < unsigned int > & spirv , const char * baseName )
{
std : : ofstream out ;
std : : string fileName ( baseName ) ;
fileName . append ( " .spv " ) ;
out . open ( fileName . c_str ( ) , std : : ios : : binary | std : : ios : : out ) ;
for ( int i = 0 ; i < ( int ) spirv . size ( ) ; + + i ) {
unsigned int word = spirv [ i ] ;
out . write ( ( const char * ) & word , 4 ) ;
}
out . close ( ) ;
}
//
// Set up the glslang traversal
//
void GlslangToSpv ( const glslang : : TIntermediate & intermediate , std : : vector < unsigned int > & spirv )
{
TIntermNode * root = intermediate . getTreeRoot ( ) ;
if ( root = = 0 )
return ;
glslang : : GetThreadPoolAllocator ( ) . push ( ) ;
TGlslangToSpvTraverser it ( & intermediate ) ;
root - > traverse ( & it ) ;
it . dumpSpv ( spirv ) ;
glslang : : GetThreadPoolAllocator ( ) . pop ( ) ;
}
} ; // end namespace glslang