2015-06-26 22:58:36 +00:00
|
|
|
//
|
2017-01-06 19:34:14 +00:00
|
|
|
// Copyright (C) 2014-2016 LunarG, Inc.
|
2018-12-14 17:47:35 +00:00
|
|
|
// Copyright (C) 2015-2018 Google, Inc.
|
2018-03-06 23:12:04 +00:00
|
|
|
// Copyright (C) 2017 ARM Limited.
|
2015-06-26 22:58:36 +00:00
|
|
|
//
|
2017-01-06 19:34:14 +00:00
|
|
|
// All rights reserved.
|
2015-06-26 22:58:36 +00:00
|
|
|
//
|
2017-01-06 19:34:14 +00:00
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions
|
|
|
|
// are met:
|
2015-06-26 22:58:36 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2017-01-06 19:34:14 +00:00
|
|
|
// 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.
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Visit the nodes in the glslang intermediate tree representation to
|
|
|
|
// translate them to SPIR-V.
|
|
|
|
//
|
|
|
|
|
2015-08-07 04:53:06 +00:00
|
|
|
#include "spirv.hpp"
|
2015-06-26 22:58:36 +00:00
|
|
|
#include "GlslangToSpv.h"
|
|
|
|
#include "SpvBuilder.h"
|
2015-08-07 04:53:06 +00:00
|
|
|
namespace spv {
|
2016-09-21 10:56:12 +00:00
|
|
|
#include "GLSL.std.450.h"
|
|
|
|
#include "GLSL.ext.KHR.h"
|
2017-12-13 20:07:22 +00:00
|
|
|
#include "GLSL.ext.EXT.h"
|
2016-09-21 10:56:12 +00:00
|
|
|
#include "GLSL.ext.AMD.h"
|
2016-12-20 00:29:34 +00:00
|
|
|
#include "GLSL.ext.NV.h"
|
2015-08-07 04:53:06 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
// Glslang includes
|
2015-07-08 13:11:59 +00:00
|
|
|
#include "../glslang/MachineIndependent/localintermediate.h"
|
|
|
|
#include "../glslang/MachineIndependent/SymbolTable.h"
|
2015-08-07 04:53:06 +00:00
|
|
|
#include "../glslang/Include/Common.h"
|
2016-05-27 17:55:53 +00:00
|
|
|
#include "../glslang/Include/revision.h"
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2016-05-04 19:55:59 +00:00
|
|
|
#include <fstream>
|
2016-05-27 17:55:53 +00:00
|
|
|
#include <iomanip>
|
2015-06-26 22:58:36 +00:00
|
|
|
#include <list>
|
2016-05-04 19:55:59 +00:00
|
|
|
#include <map>
|
2015-06-26 22:58:36 +00:00
|
|
|
#include <stack>
|
2016-05-04 19:55:59 +00:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2016-04-01 14:35:16 +00:00
|
|
|
namespace {
|
|
|
|
class SpecConstantOpModeGuard {
|
|
|
|
public:
|
|
|
|
SpecConstantOpModeGuard(spv::Builder* builder)
|
|
|
|
: builder_(builder) {
|
|
|
|
previous_flag_ = builder->isInSpecConstCodeGenMode();
|
|
|
|
}
|
|
|
|
~SpecConstantOpModeGuard() {
|
|
|
|
previous_flag_ ? builder_->setToSpecConstCodeGenMode()
|
|
|
|
: builder_->setToNormalCodeGenMode();
|
|
|
|
}
|
2016-04-04 02:20:42 +00:00
|
|
|
void turnOnSpecConstantOpMode() {
|
|
|
|
builder_->setToSpecConstCodeGenMode();
|
|
|
|
}
|
2016-04-01 14:35:16 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
spv::Builder* builder_;
|
|
|
|
bool previous_flag_;
|
|
|
|
};
|
2018-03-29 00:01:20 +00:00
|
|
|
|
|
|
|
struct OpDecorations {
|
2019-08-11 13:41:45 +00:00
|
|
|
public:
|
|
|
|
OpDecorations(spv::Decoration precision, spv::Decoration noContraction, spv::Decoration nonUniform) :
|
|
|
|
precision(precision)
|
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
,
|
|
|
|
noContraction(noContraction),
|
|
|
|
nonUniform(nonUniform)
|
|
|
|
#endif
|
|
|
|
{ }
|
|
|
|
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Decoration precision;
|
2019-08-11 13:41:45 +00:00
|
|
|
|
|
|
|
#ifdef GLSLANG_WEB
|
|
|
|
void addNoContraction(spv::Builder&, spv::Id) const { };
|
|
|
|
void addNonUniform(spv::Builder&, spv::Id) const { };
|
|
|
|
#else
|
|
|
|
void addNoContraction(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, noContraction); };
|
|
|
|
void addNonUniform(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, nonUniform); };
|
|
|
|
protected:
|
|
|
|
spv::Decoration noContraction;
|
|
|
|
spv::Decoration nonUniform;
|
|
|
|
#endif
|
|
|
|
|
2018-03-29 00:01:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
2016-04-01 14:35:16 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
//
|
|
|
|
// The main holder of information for translating glslang to SPIR-V.
|
|
|
|
//
|
|
|
|
// Derives from the AST walking base class.
|
|
|
|
//
|
|
|
|
class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
|
|
|
|
public:
|
2018-02-01 01:35:56 +00:00
|
|
|
TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate*, spv::SpvBuildLogger* logger,
|
|
|
|
glslang::SpvOptions& options);
|
2016-11-26 20:23:20 +00:00
|
|
|
virtual ~TGlslangToSpvTraverser() { }
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);
|
|
|
|
bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);
|
|
|
|
void visitConstantUnion(glslang::TIntermConstantUnion*);
|
|
|
|
bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);
|
|
|
|
bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);
|
|
|
|
void visitSymbol(glslang::TIntermSymbol* symbol);
|
|
|
|
bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);
|
|
|
|
bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);
|
|
|
|
bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);
|
|
|
|
|
2016-11-26 20:23:20 +00:00
|
|
|
void finishSpv();
|
2015-12-21 00:37:07 +00:00
|
|
|
void dumpSpv(std::vector<unsigned int>& out);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
protected:
|
2018-03-08 01:05:55 +00:00
|
|
|
TGlslangToSpvTraverser(TGlslangToSpvTraverser&);
|
|
|
|
TGlslangToSpvTraverser& operator=(TGlslangToSpvTraverser&);
|
|
|
|
|
2016-10-14 09:41:45 +00:00
|
|
|
spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier);
|
2016-05-21 01:40:44 +00:00
|
|
|
spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
|
2018-04-05 17:25:02 +00:00
|
|
|
spv::Decoration TranslateNonUniformDecoration(const glslang::TQualifier& qualifier);
|
2018-09-05 15:11:41 +00:00
|
|
|
spv::Builder::AccessChain::CoherentFlags TranslateCoherent(const glslang::TType& type);
|
|
|
|
spv::MemoryAccessMask TranslateMemoryAccess(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
|
|
|
|
spv::ImageOperandsMask TranslateImageOperands(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
|
|
|
|
spv::Scope TranslateMemoryScope(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
|
2016-06-08 13:11:40 +00:00
|
|
|
spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
|
2016-02-15 18:57:00 +00:00
|
|
|
spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
|
2018-01-30 18:01:39 +00:00
|
|
|
spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
|
|
|
|
spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
|
2019-01-12 10:31:41 +00:00
|
|
|
spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, std::vector<unsigned int>& operands) const;
|
2017-05-05 11:09:58 +00:00
|
|
|
spv::StorageClass TranslateStorageClass(const glslang::TType&);
|
2018-04-05 17:25:02 +00:00
|
|
|
void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType);
|
2019-06-17 14:38:35 +00:00
|
|
|
spv::Id createSpvVariable(const glslang::TIntermSymbol*, spv::Id forcedType);
|
2015-06-26 22:58:36 +00:00
|
|
|
spv::Id getSampledType(const glslang::TSampler&);
|
2016-07-26 18:50:38 +00:00
|
|
|
spv::Id getInvertedSwizzleType(const glslang::TIntermTyped&);
|
|
|
|
spv::Id createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped&, spv::Id parentResult);
|
|
|
|
void convertSwizzle(const glslang::TIntermAggregate&, std::vector<unsigned>& swizzle);
|
2019-01-06 23:58:04 +00:00
|
|
|
spv::Id convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly = false);
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&,
|
2019-01-06 23:58:04 +00:00
|
|
|
bool lastBufferBlockMember, bool forwardReferenceOnly = false);
|
2017-03-25 00:38:16 +00:00
|
|
|
bool filterMember(const glslang::TType& member);
|
2016-07-01 03:18:02 +00:00
|
|
|
spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct,
|
|
|
|
glslang::TLayoutPacking, const glslang::TQualifier&);
|
|
|
|
void decorateStructType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking,
|
|
|
|
const glslang::TQualifier&, spv::Id);
|
2016-02-16 03:58:50 +00:00
|
|
|
spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim);
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Id accessChainLoad(const glslang::TType& type);
|
2016-02-23 09:51:09 +00:00
|
|
|
void accessChainStore(const glslang::TType& type, spv::Id rvalue);
|
2016-09-02 17:20:21 +00:00
|
|
|
void multiTypeStore(const glslang::TType&, spv::Id rValue);
|
2015-12-19 20:57:10 +00:00
|
|
|
glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const;
|
2015-12-20 18:29:16 +00:00
|
|
|
int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
|
|
|
|
int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
|
2018-03-08 01:05:55 +00:00
|
|
|
void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset,
|
|
|
|
int& nextOffset, glslang::TLayoutPacking, glslang::TLayoutMatrix);
|
2016-06-08 13:11:40 +00:00
|
|
|
void declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2016-09-19 22:01:41 +00:00
|
|
|
bool isShaderEntryPoint(const glslang::TIntermAggregate* node);
|
2018-05-04 17:43:03 +00:00
|
|
|
bool writableParam(glslang::TStorageQualifier) const;
|
2017-09-10 21:21:05 +00:00
|
|
|
bool originalParam(glslang::TStorageQualifier, const glslang::TType&, bool implicitThisParam);
|
2015-06-26 22:58:36 +00:00
|
|
|
void makeFunctions(const glslang::TIntermSequence&);
|
|
|
|
void makeGlobalInitializers(const glslang::TIntermSequence&);
|
|
|
|
void visitFunctions(const glslang::TIntermSequence&);
|
|
|
|
void handleFunctionEntry(const glslang::TIntermAggregate* node);
|
2019-06-14 14:56:28 +00:00
|
|
|
void translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments, spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags);
|
2015-08-19 19:34:18 +00:00
|
|
|
void translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments);
|
|
|
|
spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node);
|
2015-06-26 22:58:36 +00:00
|
|
|
spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
|
|
|
|
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id createBinaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right,
|
|
|
|
glslang::TBasicType typeProxy, bool reduceComparison = true);
|
|
|
|
spv::Id createBinaryMatrixOperation(spv::Op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right);
|
|
|
|
spv::Id createUnaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id operand,
|
2019-06-14 14:56:28 +00:00
|
|
|
glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags);
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id createUnaryMatrixOperation(spv::Op op, OpDecorations&, spv::Id typeId, spv::Id operand,
|
|
|
|
glslang::TBasicType typeProxy);
|
|
|
|
spv::Id createConversion(glslang::TOperator op, OpDecorations&, spv::Id destTypeId, spv::Id operand,
|
|
|
|
glslang::TBasicType typeProxy);
|
2018-06-05 01:11:25 +00:00
|
|
|
spv::Id createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize);
|
2015-06-26 22:58:36 +00:00
|
|
|
spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
|
2019-06-14 14:56:28 +00:00
|
|
|
spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags);
|
2016-09-21 10:56:12 +00:00
|
|
|
spv::Id createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
|
2016-10-14 09:22:23 +00:00
|
|
|
spv::Id CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation, spv::Id typeId, std::vector<spv::Id>& operands);
|
2018-03-06 23:12:04 +00:00
|
|
|
spv::Id createSubgroupOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
|
2015-08-07 04:53:06 +00:00
|
|
|
spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
|
2016-05-05 04:30:44 +00:00
|
|
|
spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId);
|
2015-06-26 22:58:36 +00:00
|
|
|
spv::Id getSymbolId(const glslang::TIntermSymbol* node);
|
2018-09-19 18:41:59 +00:00
|
|
|
void addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier & qualifier);
|
2016-03-21 13:51:37 +00:00
|
|
|
spv::Id createSpvConstant(const glslang::TIntermTyped&);
|
|
|
|
spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
|
2015-10-15 19:29:11 +00:00
|
|
|
bool isTrivialLeaf(const glslang::TIntermTyped* node);
|
|
|
|
bool isTrivial(const glslang::TIntermTyped* node);
|
|
|
|
spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
|
2016-05-05 04:30:44 +00:00
|
|
|
spv::Id getExtBuiltins(const char* name);
|
2018-03-06 23:12:04 +00:00
|
|
|
void addPre13Extension(const char* ext)
|
|
|
|
{
|
|
|
|
if (builder.getSpvVersion() < glslang::EShTargetSpv_1_3)
|
|
|
|
builder.addExtension(ext);
|
|
|
|
}
|
2019-06-17 14:38:35 +00:00
|
|
|
std::pair<spv::Id, spv::Id> getForcedType(spv::BuiltIn, const glslang::TType&);
|
|
|
|
spv::Id translateForcedType(spv::Id object);
|
2019-06-25 18:31:10 +00:00
|
|
|
spv::Id createCompositeConstruct(spv::Id typeId, std::vector<spv::Id> constituents);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2017-05-31 23:11:16 +00:00
|
|
|
glslang::SpvOptions& options;
|
2015-06-26 22:58:36 +00:00
|
|
|
spv::Function* shaderEntry;
|
2016-10-06 18:59:51 +00:00
|
|
|
spv::Function* currentFunction;
|
2015-11-16 04:33:39 +00:00
|
|
|
spv::Instruction* entryPoint;
|
2015-06-26 22:58:36 +00:00
|
|
|
int sequenceDepth;
|
|
|
|
|
2016-05-04 19:55:59 +00:00
|
|
|
spv::SpvBuildLogger* logger;
|
2016-05-02 22:11:54 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
// There is a 1:1 mapping between a spv builder and a module; this is thread safe
|
|
|
|
spv::Builder builder;
|
2016-11-26 20:31:47 +00:00
|
|
|
bool inEntryPoint;
|
|
|
|
bool entryPointTerminated;
|
2015-12-21 00:37:07 +00:00
|
|
|
bool linkageOnly; // true when visiting the set of objects in the AST present only for establishing interface, whether or not they were statically used
|
2015-12-21 18:45:34 +00:00
|
|
|
std::set<spv::Id> iOSet; // all input/output variables from either static use or declaration of interface
|
2015-06-26 22:58:36 +00:00
|
|
|
const glslang::TIntermediate* glslangIntermediate;
|
2019-06-18 05:33:09 +00:00
|
|
|
bool nanMinMaxClamp; // true if use NMin/NMax/NClamp instead of FMin/FMax/FClamp
|
2015-06-26 22:58:36 +00:00
|
|
|
spv::Id stdBuiltins;
|
2016-05-05 04:30:44 +00:00
|
|
|
std::unordered_map<const char*, spv::Id> extBuiltinMap;
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2015-07-19 04:34:27 +00:00
|
|
|
std::unordered_map<int, spv::Id> symbolValues;
|
2016-09-02 17:20:21 +00:00
|
|
|
std::unordered_set<int> rValueParameters; // set of formal function parameters passed as rValues, rather than a pointer
|
2015-07-19 04:34:27 +00:00
|
|
|
std::unordered_map<std::string, spv::Function*> functionMap;
|
2015-12-20 18:29:16 +00:00
|
|
|
std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount];
|
2018-03-08 01:05:55 +00:00
|
|
|
// for mapping glslang block indices to spv indices (e.g., due to hidden members):
|
|
|
|
std::unordered_map<const glslang::TTypeList*, std::vector<int> > memberRemapper;
|
2015-06-26 22:58:36 +00:00
|
|
|
std::stack<bool> breakForLoop; // false means break for switch
|
2018-03-08 01:05:55 +00:00
|
|
|
std::unordered_map<std::string, const glslang::TIntermSymbol*> counterOriginator;
|
2019-01-06 23:58:04 +00:00
|
|
|
// Map pointee types for EbtReference to their forward pointers
|
|
|
|
std::map<const glslang::TType *, spv::Id> forwardPointers;
|
2019-06-17 14:38:35 +00:00
|
|
|
// Type forcing, for when SPIR-V wants a different type than the AST,
|
|
|
|
// requiring local translation to and from SPIR-V type on every access.
|
|
|
|
// Maps <builtin-variable-id -> AST-required-type-id>
|
|
|
|
std::unordered_map<spv::Id, spv::Id> forceType;
|
2015-06-26 22:58:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// Helper functions for translating glslang representations to SPIR-V enumerants.
|
|
|
|
//
|
|
|
|
|
|
|
|
// Translate glslang profile to SPIR-V source language.
|
2016-03-13 01:34:36 +00:00
|
|
|
spv::SourceLanguage TranslateSourceLanguage(glslang::EShSource source, EProfile profile)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2019-08-09 05:29:20 +00:00
|
|
|
#ifdef GLSLANG_WEB
|
|
|
|
return spv::SourceLanguageESSL;
|
|
|
|
#endif
|
|
|
|
|
2016-03-13 01:34:36 +00:00
|
|
|
switch (source) {
|
|
|
|
case glslang::EShSourceGlsl:
|
|
|
|
switch (profile) {
|
|
|
|
case ENoProfile:
|
|
|
|
case ECoreProfile:
|
|
|
|
case ECompatibilityProfile:
|
|
|
|
return spv::SourceLanguageGLSL;
|
|
|
|
case EEsProfile:
|
|
|
|
return spv::SourceLanguageESSL;
|
|
|
|
default:
|
|
|
|
return spv::SourceLanguageUnknown;
|
|
|
|
}
|
|
|
|
case glslang::EShSourceHlsl:
|
2017-04-07 21:33:08 +00:00
|
|
|
return spv::SourceLanguageHLSL;
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
|
|
|
return spv::SourceLanguageUnknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translate glslang language (stage) to SPIR-V execution model.
|
|
|
|
spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)
|
|
|
|
{
|
|
|
|
switch (stage) {
|
|
|
|
case EShLangVertex: return spv::ExecutionModelVertex;
|
2019-08-06 13:00:58 +00:00
|
|
|
case EShLangFragment: return spv::ExecutionModelFragment;
|
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
case EShLangCompute: return spv::ExecutionModelGLCompute;
|
2015-06-26 22:58:36 +00:00
|
|
|
case EShLangTessControl: return spv::ExecutionModelTessellationControl;
|
|
|
|
case EShLangTessEvaluation: return spv::ExecutionModelTessellationEvaluation;
|
|
|
|
case EShLangGeometry: return spv::ExecutionModelGeometry;
|
2018-10-22 23:41:44 +00:00
|
|
|
case EShLangRayGenNV: return spv::ExecutionModelRayGenerationNV;
|
|
|
|
case EShLangIntersectNV: return spv::ExecutionModelIntersectionNV;
|
|
|
|
case EShLangAnyHitNV: return spv::ExecutionModelAnyHitNV;
|
|
|
|
case EShLangClosestHitNV: return spv::ExecutionModelClosestHitNV;
|
|
|
|
case EShLangMissNV: return spv::ExecutionModelMissNV;
|
|
|
|
case EShLangCallableNV: return spv::ExecutionModelCallableNV;
|
2018-09-19 18:41:59 +00:00
|
|
|
case EShLangTaskNV: return spv::ExecutionModelTaskNV;
|
|
|
|
case EShLangMeshNV: return spv::ExecutionModelMeshNV;
|
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(0);
|
2015-06-26 22:58:36 +00:00
|
|
|
return spv::ExecutionModelFragment;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translate glslang sampler type to SPIR-V dimensionality.
|
|
|
|
spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
|
|
|
|
{
|
|
|
|
switch (sampler.dim) {
|
2015-11-16 04:33:39 +00:00
|
|
|
case glslang::Esd1D: return spv::Dim1D;
|
|
|
|
case glslang::Esd2D: return spv::Dim2D;
|
|
|
|
case glslang::Esd3D: return spv::Dim3D;
|
|
|
|
case glslang::EsdCube: return spv::DimCube;
|
|
|
|
case glslang::EsdRect: return spv::DimRect;
|
|
|
|
case glslang::EsdBuffer: return spv::DimBuffer;
|
2016-02-16 03:58:50 +00:00
|
|
|
case glslang::EsdSubpass: return spv::DimSubpassData;
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(0);
|
2015-06-26 22:58:36 +00:00
|
|
|
return spv::Dim2D;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-02 01:44:00 +00:00
|
|
|
// Translate glslang precision to SPIR-V precision decorations.
|
|
|
|
spv::Decoration TranslatePrecisionDecoration(glslang::TPrecisionQualifier glslangPrecision)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2016-08-02 01:44:00 +00:00
|
|
|
switch (glslangPrecision) {
|
2015-12-15 01:21:19 +00:00
|
|
|
case glslang::EpqLow: return spv::DecorationRelaxedPrecision;
|
2015-08-07 04:53:06 +00:00
|
|
|
case glslang::EpqMedium: return spv::DecorationRelaxedPrecision;
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
|
|
|
return spv::NoPrecision;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-02 01:44:00 +00:00
|
|
|
// Translate glslang type to SPIR-V precision decorations.
|
|
|
|
spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
|
|
|
|
{
|
|
|
|
return TranslatePrecisionDecoration(type.getQualifier().precision);
|
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
// Translate glslang type to SPIR-V block decorations.
|
2017-04-20 00:34:49 +00:00
|
|
|
spv::Decoration TranslateBlockDecoration(const glslang::TType& type, bool useStorageBuffer)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
|
|
|
if (type.getBasicType() == glslang::EbtBlock) {
|
|
|
|
switch (type.getQualifier().storage) {
|
|
|
|
case glslang::EvqUniform: return spv::DecorationBlock;
|
2017-04-20 00:34:49 +00:00
|
|
|
case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock;
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EvqVaryingIn: return spv::DecorationBlock;
|
|
|
|
case glslang::EvqVaryingOut: return spv::DecorationBlock;
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EvqPayloadNV: return spv::DecorationBlock;
|
|
|
|
case glslang::EvqPayloadInNV: return spv::DecorationBlock;
|
|
|
|
case glslang::EvqHitAttrNV: return spv::DecorationBlock;
|
2018-10-22 23:41:44 +00:00
|
|
|
case glslang::EvqCallableDataNV: return spv::DecorationBlock;
|
|
|
|
case glslang::EvqCallableDataInNV: return spv::DecorationBlock;
|
2018-09-19 18:42:24 +00:00
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(0);
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-15 17:53:56 +00:00
|
|
|
return spv::DecorationMax;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
2016-02-21 12:59:01 +00:00
|
|
|
// Translate glslang type to SPIR-V memory decorations.
|
2018-09-05 15:11:41 +00:00
|
|
|
void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector<spv::Decoration>& memory, bool useVulkanMemoryModel)
|
2016-02-21 12:59:01 +00:00
|
|
|
{
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-09-05 15:11:41 +00:00
|
|
|
if (!useVulkanMemoryModel) {
|
|
|
|
if (qualifier.coherent)
|
|
|
|
memory.push_back(spv::DecorationCoherent);
|
|
|
|
if (qualifier.volatil) {
|
|
|
|
memory.push_back(spv::DecorationVolatile);
|
|
|
|
memory.push_back(spv::DecorationCoherent);
|
|
|
|
}
|
2018-06-04 21:36:03 +00:00
|
|
|
}
|
2016-02-21 12:59:01 +00:00
|
|
|
if (qualifier.restrict)
|
|
|
|
memory.push_back(spv::DecorationRestrict);
|
|
|
|
if (qualifier.readonly)
|
|
|
|
memory.push_back(spv::DecorationNonWritable);
|
|
|
|
if (qualifier.writeonly)
|
|
|
|
memory.push_back(spv::DecorationNonReadable);
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2016-02-21 12:59:01 +00:00
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
// Translate glslang type to SPIR-V layout decorations.
|
2015-12-20 18:29:16 +00:00
|
|
|
spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::TLayoutMatrix matrixLayout)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
|
|
|
if (type.isMatrix()) {
|
2015-12-20 18:29:16 +00:00
|
|
|
switch (matrixLayout) {
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::ElmRowMajor:
|
|
|
|
return spv::DecorationRowMajor;
|
2015-12-20 18:29:16 +00:00
|
|
|
case glslang::ElmColumnMajor:
|
2015-06-26 22:58:36 +00:00
|
|
|
return spv::DecorationColMajor;
|
2015-12-20 18:29:16 +00:00
|
|
|
default:
|
|
|
|
// opaque layouts don't need a majorness
|
2016-07-15 17:53:56 +00:00
|
|
|
return spv::DecorationMax;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (type.getBasicType()) {
|
|
|
|
default:
|
2016-07-15 17:53:56 +00:00
|
|
|
return spv::DecorationMax;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EbtBlock:
|
|
|
|
switch (type.getQualifier().storage) {
|
|
|
|
case glslang::EvqUniform:
|
|
|
|
case glslang::EvqBuffer:
|
|
|
|
switch (type.getQualifier().layoutPacking) {
|
|
|
|
case glslang::ElpShared: return spv::DecorationGLSLShared;
|
|
|
|
case glslang::ElpPacked: return spv::DecorationGLSLPacked;
|
|
|
|
default:
|
2016-07-15 17:53:56 +00:00
|
|
|
return spv::DecorationMax;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
case glslang::EvqVaryingIn:
|
|
|
|
case glslang::EvqVaryingOut:
|
2018-09-19 18:41:59 +00:00
|
|
|
if (type.getQualifier().isTaskMemory()) {
|
|
|
|
switch (type.getQualifier().layoutPacking) {
|
|
|
|
case glslang::ElpShared: return spv::DecorationGLSLShared;
|
|
|
|
case glslang::ElpPacked: return spv::DecorationGLSLPacked;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(type.getQualifier().layoutPacking == glslang::ElpNone);
|
|
|
|
}
|
2016-07-15 17:53:56 +00:00
|
|
|
return spv::DecorationMax;
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EvqPayloadNV:
|
|
|
|
case glslang::EvqPayloadInNV:
|
|
|
|
case glslang::EvqHitAttrNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
case glslang::EvqCallableDataNV:
|
|
|
|
case glslang::EvqCallableDataInNV:
|
2018-09-19 18:42:24 +00:00
|
|
|
return spv::DecorationMax;
|
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(0);
|
2016-07-15 17:53:56 +00:00
|
|
|
return spv::DecorationMax;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translate glslang type to SPIR-V interpolation decorations.
|
2016-07-15 17:53:56 +00:00
|
|
|
// Returns spv::DecorationMax when no decoration
|
2015-11-16 04:33:39 +00:00
|
|
|
// should be applied.
|
2016-10-14 09:41:45 +00:00
|
|
|
spv::Decoration TGlslangToSpvTraverser::TranslateInterpolationDecoration(const glslang::TQualifier& qualifier)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2016-05-21 01:40:44 +00:00
|
|
|
if (qualifier.smooth)
|
2015-11-16 04:33:39 +00:00
|
|
|
// Smooth decoration doesn't exist in SPIR-V 1.0
|
2016-07-15 17:53:56 +00:00
|
|
|
return spv::DecorationMax;
|
2019-08-01 09:28:08 +00:00
|
|
|
else if (qualifier.isNonPerspective())
|
2015-11-16 04:33:39 +00:00
|
|
|
return spv::DecorationNoPerspective;
|
2015-12-24 17:30:13 +00:00
|
|
|
else if (qualifier.flat)
|
2015-06-26 22:58:36 +00:00
|
|
|
return spv::DecorationFlat;
|
2019-08-06 13:00:58 +00:00
|
|
|
else if (qualifier.isExplicitInterpolation()) {
|
2016-10-14 09:41:45 +00:00
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
|
2016-05-05 04:30:44 +00:00
|
|
|
return spv::DecorationExplicitInterpAMD;
|
2016-10-14 09:41:45 +00:00
|
|
|
}
|
2016-05-21 01:40:44 +00:00
|
|
|
else
|
2016-07-15 17:53:56 +00:00
|
|
|
return spv::DecorationMax;
|
2016-05-21 01:40:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Translate glslang type to SPIR-V auxiliary storage decorations.
|
2016-07-15 17:53:56 +00:00
|
|
|
// Returns spv::DecorationMax when no decoration
|
2016-05-21 01:40:44 +00:00
|
|
|
// should be applied.
|
|
|
|
spv::Decoration TGlslangToSpvTraverser::TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier)
|
|
|
|
{
|
2019-08-11 13:41:45 +00:00
|
|
|
if (qualifier.centroid)
|
2015-06-26 22:58:36 +00:00
|
|
|
return spv::DecorationCentroid;
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
else if (qualifier.patch)
|
|
|
|
return spv::DecorationPatch;
|
2016-02-15 18:09:46 +00:00
|
|
|
else if (qualifier.sample) {
|
|
|
|
builder.addCapability(spv::CapabilitySampleRateShading);
|
2015-06-26 22:58:36 +00:00
|
|
|
return spv::DecorationSample;
|
2019-08-11 13:41:45 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return spv::DecorationMax;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
2016-02-01 20:45:25 +00:00
|
|
|
// If glslang type is invariant, return SPIR-V invariant decoration.
|
2015-12-24 17:30:13 +00:00
|
|
|
spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifier)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2015-12-24 17:30:13 +00:00
|
|
|
if (qualifier.invariant)
|
2015-06-26 22:58:36 +00:00
|
|
|
return spv::DecorationInvariant;
|
|
|
|
else
|
2016-07-15 17:53:56 +00:00
|
|
|
return spv::DecorationMax;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
Precise and noContraction propagation
Reimplement the whole workflow to make that: precise'ness of struct
members won't spread to other non-precise members of the same struct
instance.
Approach:
1. Build the map from symbols to their defining nodes. And for each
object node (StructIndex, DirectIndex, Symbol nodes, etc), generates an
accesschain path. Different AST nodes that indicating a same object
should have the same accesschain path.
2. Along the building phase in step 1, collect the initial set of
'precise' (AST qualifier: 'noContraction') objects' accesschain paths.
3. Start with the initial set of 'precise' accesschain paths, use it as
a worklist, do as the following steps until the worklist is empty:
1) Pop an accesschain path from worklist.
2) Get the symbol part from the accesschain path.
3) Find the defining nodes of that symbol.
4) For each defining node, check whether it is defining a 'precise'
object, or its assignee has nested 'precise' object. Get the
incremental path from assignee to its nested 'precise' object (if
any).
5) Traverse the right side of the defining node, obtain the
accesschain paths of the corresponding involved 'precise' objects.
Update the worklist with those new objects' accesschain paths.
Label involved operations with 'noContraction'.
In each step, whenever we find the parent object of an nested object is
'precise' (has 'noContraction' qualifier), we let the nested object
inherit the 'precise'ness from its parent object.
2016-05-04 21:34:38 +00:00
|
|
|
// If glslang type is noContraction, return SPIR-V NoContraction decoration.
|
|
|
|
spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier)
|
|
|
|
{
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2019-08-06 13:00:58 +00:00
|
|
|
if (qualifier.isNoContraction())
|
Precise and noContraction propagation
Reimplement the whole workflow to make that: precise'ness of struct
members won't spread to other non-precise members of the same struct
instance.
Approach:
1. Build the map from symbols to their defining nodes. And for each
object node (StructIndex, DirectIndex, Symbol nodes, etc), generates an
accesschain path. Different AST nodes that indicating a same object
should have the same accesschain path.
2. Along the building phase in step 1, collect the initial set of
'precise' (AST qualifier: 'noContraction') objects' accesschain paths.
3. Start with the initial set of 'precise' accesschain paths, use it as
a worklist, do as the following steps until the worklist is empty:
1) Pop an accesschain path from worklist.
2) Get the symbol part from the accesschain path.
3) Find the defining nodes of that symbol.
4) For each defining node, check whether it is defining a 'precise'
object, or its assignee has nested 'precise' object. Get the
incremental path from assignee to its nested 'precise' object (if
any).
5) Traverse the right side of the defining node, obtain the
accesschain paths of the corresponding involved 'precise' objects.
Update the worklist with those new objects' accesschain paths.
Label involved operations with 'noContraction'.
In each step, whenever we find the parent object of an nested object is
'precise' (has 'noContraction' qualifier), we let the nested object
inherit the 'precise'ness from its parent object.
2016-05-04 21:34:38 +00:00
|
|
|
return spv::DecorationNoContraction;
|
|
|
|
else
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2016-07-15 17:53:56 +00:00
|
|
|
return spv::DecorationMax;
|
Precise and noContraction propagation
Reimplement the whole workflow to make that: precise'ness of struct
members won't spread to other non-precise members of the same struct
instance.
Approach:
1. Build the map from symbols to their defining nodes. And for each
object node (StructIndex, DirectIndex, Symbol nodes, etc), generates an
accesschain path. Different AST nodes that indicating a same object
should have the same accesschain path.
2. Along the building phase in step 1, collect the initial set of
'precise' (AST qualifier: 'noContraction') objects' accesschain paths.
3. Start with the initial set of 'precise' accesschain paths, use it as
a worklist, do as the following steps until the worklist is empty:
1) Pop an accesschain path from worklist.
2) Get the symbol part from the accesschain path.
3) Find the defining nodes of that symbol.
4) For each defining node, check whether it is defining a 'precise'
object, or its assignee has nested 'precise' object. Get the
incremental path from assignee to its nested 'precise' object (if
any).
5) Traverse the right side of the defining node, obtain the
accesschain paths of the corresponding involved 'precise' objects.
Update the worklist with those new objects' accesschain paths.
Label involved operations with 'noContraction'.
In each step, whenever we find the parent object of an nested object is
'precise' (has 'noContraction' qualifier), we let the nested object
inherit the 'precise'ness from its parent object.
2016-05-04 21:34:38 +00:00
|
|
|
}
|
|
|
|
|
2018-04-05 17:25:02 +00:00
|
|
|
// If glslang type is nonUniform, return SPIR-V NonUniform decoration.
|
|
|
|
spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glslang::TQualifier& qualifier)
|
|
|
|
{
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-04-05 17:25:02 +00:00
|
|
|
if (qualifier.isNonUniform()) {
|
|
|
|
builder.addExtension("SPV_EXT_descriptor_indexing");
|
|
|
|
builder.addCapability(spv::CapabilityShaderNonUniformEXT);
|
|
|
|
return spv::DecorationNonUniformEXT;
|
|
|
|
} else
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2018-04-05 17:25:02 +00:00
|
|
|
return spv::DecorationMax;
|
|
|
|
}
|
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess(
|
|
|
|
const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
|
2018-09-05 15:11:41 +00:00
|
|
|
{
|
|
|
|
spv::MemoryAccessMask mask = spv::MemoryAccessMaskNone;
|
2019-08-11 13:41:45 +00:00
|
|
|
|
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
if (!glslangIntermediate->usingVulkanMemoryModel() || coherentFlags.isImage)
|
|
|
|
return mask;
|
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
if (coherentFlags.volatil ||
|
|
|
|
coherentFlags.coherent ||
|
|
|
|
coherentFlags.devicecoherent ||
|
|
|
|
coherentFlags.queuefamilycoherent ||
|
|
|
|
coherentFlags.workgroupcoherent ||
|
|
|
|
coherentFlags.subgroupcoherent) {
|
|
|
|
mask = mask | spv::MemoryAccessMakePointerAvailableKHRMask |
|
|
|
|
spv::MemoryAccessMakePointerVisibleKHRMask;
|
|
|
|
}
|
|
|
|
if (coherentFlags.nonprivate) {
|
|
|
|
mask = mask | spv::MemoryAccessNonPrivatePointerKHRMask;
|
|
|
|
}
|
|
|
|
if (coherentFlags.volatil) {
|
|
|
|
mask = mask | spv::MemoryAccessVolatileMask;
|
|
|
|
}
|
|
|
|
if (mask != spv::MemoryAccessMaskNone) {
|
|
|
|
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
|
|
|
|
}
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands(
|
|
|
|
const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
|
2018-09-05 15:11:41 +00:00
|
|
|
{
|
|
|
|
spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
|
2019-08-11 13:41:45 +00:00
|
|
|
|
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
if (!glslangIntermediate->usingVulkanMemoryModel())
|
|
|
|
return mask;
|
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
if (coherentFlags.volatil ||
|
|
|
|
coherentFlags.coherent ||
|
|
|
|
coherentFlags.devicecoherent ||
|
|
|
|
coherentFlags.queuefamilycoherent ||
|
|
|
|
coherentFlags.workgroupcoherent ||
|
|
|
|
coherentFlags.subgroupcoherent) {
|
|
|
|
mask = mask | spv::ImageOperandsMakeTexelAvailableKHRMask |
|
|
|
|
spv::ImageOperandsMakeTexelVisibleKHRMask;
|
|
|
|
}
|
|
|
|
if (coherentFlags.nonprivate) {
|
|
|
|
mask = mask | spv::ImageOperandsNonPrivateTexelKHRMask;
|
|
|
|
}
|
|
|
|
if (coherentFlags.volatil) {
|
|
|
|
mask = mask | spv::ImageOperandsVolatileTexelKHRMask;
|
|
|
|
}
|
|
|
|
if (mask != spv::ImageOperandsMaskNone) {
|
|
|
|
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
|
|
|
|
}
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCoherent(const glslang::TType& type)
|
|
|
|
{
|
2019-08-11 13:41:45 +00:00
|
|
|
spv::Builder::AccessChain::CoherentFlags flags = {};
|
|
|
|
#ifndef GLSLANG_WEB
|
2018-09-05 15:11:41 +00:00
|
|
|
flags.coherent = type.getQualifier().coherent;
|
|
|
|
flags.devicecoherent = type.getQualifier().devicecoherent;
|
|
|
|
flags.queuefamilycoherent = type.getQualifier().queuefamilycoherent;
|
|
|
|
// shared variables are implicitly workgroupcoherent in GLSL.
|
|
|
|
flags.workgroupcoherent = type.getQualifier().workgroupcoherent ||
|
|
|
|
type.getQualifier().storage == glslang::EvqShared;
|
|
|
|
flags.subgroupcoherent = type.getQualifier().subgroupcoherent;
|
2019-03-05 20:40:07 +00:00
|
|
|
flags.volatil = type.getQualifier().volatil;
|
2018-09-05 15:11:41 +00:00
|
|
|
// *coherent variables are implicitly nonprivate in GLSL
|
|
|
|
flags.nonprivate = type.getQualifier().nonprivate ||
|
2018-10-16 03:46:48 +00:00
|
|
|
flags.subgroupcoherent ||
|
|
|
|
flags.workgroupcoherent ||
|
|
|
|
flags.queuefamilycoherent ||
|
|
|
|
flags.devicecoherent ||
|
2019-03-05 20:40:07 +00:00
|
|
|
flags.coherent ||
|
|
|
|
flags.volatil;
|
2018-09-05 15:11:41 +00:00
|
|
|
flags.isImage = type.getBasicType() == glslang::EbtSampler;
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2018-09-05 15:11:41 +00:00
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope(
|
|
|
|
const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
|
2018-09-05 15:11:41 +00:00
|
|
|
{
|
2019-08-11 13:41:45 +00:00
|
|
|
spv::Scope scope = spv::ScopeMax;
|
|
|
|
|
|
|
|
#ifndef GLSLANG_WEB
|
2019-03-05 20:40:07 +00:00
|
|
|
if (coherentFlags.volatil || coherentFlags.coherent) {
|
2018-09-05 15:11:41 +00:00
|
|
|
// coherent defaults to Device scope in the old model, QueueFamilyKHR scope in the new model
|
|
|
|
scope = glslangIntermediate->usingVulkanMemoryModel() ? spv::ScopeQueueFamilyKHR : spv::ScopeDevice;
|
|
|
|
} else if (coherentFlags.devicecoherent) {
|
|
|
|
scope = spv::ScopeDevice;
|
|
|
|
} else if (coherentFlags.queuefamilycoherent) {
|
|
|
|
scope = spv::ScopeQueueFamilyKHR;
|
|
|
|
} else if (coherentFlags.workgroupcoherent) {
|
|
|
|
scope = spv::ScopeWorkgroup;
|
|
|
|
} else if (coherentFlags.subgroupcoherent) {
|
|
|
|
scope = spv::ScopeSubgroup;
|
|
|
|
}
|
|
|
|
if (glslangIntermediate->usingVulkanMemoryModel() && scope == spv::ScopeDevice) {
|
|
|
|
builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
|
|
|
|
}
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
return scope;
|
|
|
|
}
|
|
|
|
|
2016-06-08 13:11:40 +00:00
|
|
|
// Translate a glslang built-in variable to a SPIR-V built in decoration. Also generate
|
|
|
|
// associated capabilities when required. For some built-in variables, a capability
|
|
|
|
// is generated only when using the variable in an executable instruction, but not when
|
|
|
|
// just declaring a struct member variable with it. This is true for PointSize,
|
|
|
|
// ClipDistance, and CullDistance.
|
|
|
|
spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn, bool memberDeclaration)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
|
|
|
switch (builtIn) {
|
2016-02-01 20:45:25 +00:00
|
|
|
case glslang::EbvPointSize:
|
2019-08-09 05:29:20 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2016-07-08 20:05:15 +00:00
|
|
|
// Defer adding the capability until the built-in is actually used.
|
|
|
|
if (! memberDeclaration) {
|
|
|
|
switch (glslangIntermediate->getStage()) {
|
|
|
|
case EShLangGeometry:
|
|
|
|
builder.addCapability(spv::CapabilityGeometryPointSize);
|
|
|
|
break;
|
|
|
|
case EShLangTessControl:
|
|
|
|
case EShLangTessEvaluation:
|
|
|
|
builder.addCapability(spv::CapabilityTessellationPointSize);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-02-01 20:45:25 +00:00
|
|
|
}
|
2019-08-09 05:29:20 +00:00
|
|
|
#endif
|
2016-02-01 20:45:25 +00:00
|
|
|
return spv::BuiltInPointSize;
|
|
|
|
|
2019-08-06 13:00:58 +00:00
|
|
|
case glslang::EbvPosition: return spv::BuiltInPosition;
|
|
|
|
case glslang::EbvVertexId: return spv::BuiltInVertexId;
|
|
|
|
case glslang::EbvInstanceId: return spv::BuiltInInstanceId;
|
|
|
|
case glslang::EbvVertexIndex: return spv::BuiltInVertexIndex;
|
|
|
|
case glslang::EbvInstanceIndex: return spv::BuiltInInstanceIndex;
|
|
|
|
|
|
|
|
case glslang::EbvFragCoord: return spv::BuiltInFragCoord;
|
|
|
|
case glslang::EbvPointCoord: return spv::BuiltInPointCoord;
|
|
|
|
case glslang::EbvFace: return spv::BuiltInFrontFacing;
|
|
|
|
case glslang::EbvFragDepth: return spv::BuiltInFragDepth;
|
|
|
|
|
|
|
|
#ifndef GLSLANG_WEB
|
2016-05-17 01:22:05 +00:00
|
|
|
// These *Distance capabilities logically belong here, but if the member is declared and
|
|
|
|
// then never used, consumers of SPIR-V prefer the capability not be declared.
|
|
|
|
// They are now generated when used, rather than here when declared.
|
|
|
|
// Potentially, the specification should be more clear what the minimum
|
|
|
|
// use needed is to trigger the capability.
|
|
|
|
//
|
2016-02-01 20:45:25 +00:00
|
|
|
case glslang::EbvClipDistance:
|
2016-06-08 13:11:40 +00:00
|
|
|
if (!memberDeclaration)
|
2017-02-22 08:44:48 +00:00
|
|
|
builder.addCapability(spv::CapabilityClipDistance);
|
2016-02-01 20:45:25 +00:00
|
|
|
return spv::BuiltInClipDistance;
|
|
|
|
|
|
|
|
case glslang::EbvCullDistance:
|
2016-06-08 13:11:40 +00:00
|
|
|
if (!memberDeclaration)
|
2017-02-22 08:44:48 +00:00
|
|
|
builder.addCapability(spv::CapabilityCullDistance);
|
2016-02-01 20:45:25 +00:00
|
|
|
return spv::BuiltInCullDistance;
|
|
|
|
|
|
|
|
case glslang::EbvViewportIndex:
|
2017-09-13 19:22:50 +00:00
|
|
|
builder.addCapability(spv::CapabilityMultiViewport);
|
|
|
|
if (glslangIntermediate->getStage() == EShLangVertex ||
|
|
|
|
glslangIntermediate->getStage() == EShLangTessControl ||
|
|
|
|
glslangIntermediate->getStage() == EShLangTessEvaluation) {
|
2017-03-16 15:02:39 +00:00
|
|
|
|
2017-09-13 19:22:50 +00:00
|
|
|
builder.addExtension(spv::E_SPV_EXT_shader_viewport_index_layer);
|
|
|
|
builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT);
|
2017-03-16 15:02:39 +00:00
|
|
|
}
|
2016-02-01 20:45:25 +00:00
|
|
|
return spv::BuiltInViewportIndex;
|
|
|
|
|
2016-02-15 18:09:46 +00:00
|
|
|
case glslang::EbvSampleId:
|
|
|
|
builder.addCapability(spv::CapabilitySampleRateShading);
|
|
|
|
return spv::BuiltInSampleId;
|
|
|
|
|
|
|
|
case glslang::EbvSamplePosition:
|
|
|
|
builder.addCapability(spv::CapabilitySampleRateShading);
|
|
|
|
return spv::BuiltInSamplePosition;
|
|
|
|
|
|
|
|
case glslang::EbvSampleMask:
|
|
|
|
return spv::BuiltInSampleMask;
|
|
|
|
|
2016-07-08 20:05:15 +00:00
|
|
|
case glslang::EbvLayer:
|
2018-09-19 18:41:59 +00:00
|
|
|
if (glslangIntermediate->getStage() == EShLangMeshNV) {
|
|
|
|
return spv::BuiltInLayer;
|
|
|
|
}
|
2017-09-13 19:22:50 +00:00
|
|
|
builder.addCapability(spv::CapabilityGeometry);
|
|
|
|
if (glslangIntermediate->getStage() == EShLangVertex ||
|
|
|
|
glslangIntermediate->getStage() == EShLangTessControl ||
|
|
|
|
glslangIntermediate->getStage() == EShLangTessEvaluation) {
|
2017-03-16 15:02:39 +00:00
|
|
|
|
2017-09-13 19:22:50 +00:00
|
|
|
builder.addExtension(spv::E_SPV_EXT_shader_viewport_index_layer);
|
|
|
|
builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT);
|
2017-03-16 15:02:39 +00:00
|
|
|
}
|
2016-07-08 20:05:15 +00:00
|
|
|
return spv::BuiltInLayer;
|
|
|
|
|
2015-10-14 20:10:30 +00:00
|
|
|
case glslang::EbvBaseVertex:
|
2018-03-06 23:12:04 +00:00
|
|
|
addPre13Extension(spv::E_SPV_KHR_shader_draw_parameters);
|
2016-07-22 10:15:31 +00:00
|
|
|
builder.addCapability(spv::CapabilityDrawParameters);
|
|
|
|
return spv::BuiltInBaseVertex;
|
|
|
|
|
2015-10-14 20:10:30 +00:00
|
|
|
case glslang::EbvBaseInstance:
|
2018-03-06 23:12:04 +00:00
|
|
|
addPre13Extension(spv::E_SPV_KHR_shader_draw_parameters);
|
2016-07-22 10:15:31 +00:00
|
|
|
builder.addCapability(spv::CapabilityDrawParameters);
|
|
|
|
return spv::BuiltInBaseInstance;
|
2016-09-26 14:49:09 +00:00
|
|
|
|
2015-10-14 20:10:30 +00:00
|
|
|
case glslang::EbvDrawId:
|
2018-03-06 23:12:04 +00:00
|
|
|
addPre13Extension(spv::E_SPV_KHR_shader_draw_parameters);
|
2016-07-22 10:15:31 +00:00
|
|
|
builder.addCapability(spv::CapabilityDrawParameters);
|
|
|
|
return spv::BuiltInDrawIndex;
|
2016-09-26 14:49:09 +00:00
|
|
|
|
|
|
|
case glslang::EbvPrimitiveId:
|
|
|
|
if (glslangIntermediate->getStage() == EShLangFragment)
|
|
|
|
builder.addCapability(spv::CapabilityGeometry);
|
|
|
|
return spv::BuiltInPrimitiveId;
|
|
|
|
|
2017-06-29 09:46:34 +00:00
|
|
|
case glslang::EbvFragStencilRef:
|
2017-08-23 15:24:42 +00:00
|
|
|
builder.addExtension(spv::E_SPV_EXT_shader_stencil_export);
|
|
|
|
builder.addCapability(spv::CapabilityStencilExportEXT);
|
|
|
|
return spv::BuiltInFragStencilRefEXT;
|
2017-06-29 09:46:34 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EbvInvocationId: return spv::BuiltInInvocationId;
|
|
|
|
case glslang::EbvTessLevelInner: return spv::BuiltInTessLevelInner;
|
|
|
|
case glslang::EbvTessLevelOuter: return spv::BuiltInTessLevelOuter;
|
|
|
|
case glslang::EbvTessCoord: return spv::BuiltInTessCoord;
|
|
|
|
case glslang::EbvPatchVertices: return spv::BuiltInPatchVertices;
|
|
|
|
case glslang::EbvHelperInvocation: return spv::BuiltInHelperInvocation;
|
|
|
|
case glslang::EbvNumWorkGroups: return spv::BuiltInNumWorkgroups;
|
|
|
|
case glslang::EbvWorkGroupSize: return spv::BuiltInWorkgroupSize;
|
|
|
|
case glslang::EbvWorkGroupId: return spv::BuiltInWorkgroupId;
|
|
|
|
case glslang::EbvLocalInvocationId: return spv::BuiltInLocalInvocationId;
|
|
|
|
case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;
|
|
|
|
case glslang::EbvGlobalInvocationId: return spv::BuiltInGlobalInvocationId;
|
2016-09-21 10:56:12 +00:00
|
|
|
|
2016-04-14 08:53:07 +00:00
|
|
|
case glslang::EbvSubGroupSize:
|
2016-09-23 14:13:43 +00:00
|
|
|
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
|
2016-09-21 10:56:12 +00:00
|
|
|
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
|
|
|
|
return spv::BuiltInSubgroupSize;
|
|
|
|
|
2016-04-14 08:53:07 +00:00
|
|
|
case glslang::EbvSubGroupInvocation:
|
2016-09-23 14:13:43 +00:00
|
|
|
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
|
2016-09-21 10:56:12 +00:00
|
|
|
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
|
|
|
|
return spv::BuiltInSubgroupLocalInvocationId;
|
|
|
|
|
2016-04-14 08:53:07 +00:00
|
|
|
case glslang::EbvSubGroupEqMask:
|
2016-09-21 10:56:12 +00:00
|
|
|
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
|
|
|
|
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
|
2019-06-17 14:38:35 +00:00
|
|
|
return spv::BuiltInSubgroupEqMask;
|
2016-09-21 10:56:12 +00:00
|
|
|
|
2016-04-14 08:53:07 +00:00
|
|
|
case glslang::EbvSubGroupGeMask:
|
2016-09-21 10:56:12 +00:00
|
|
|
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
|
|
|
|
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
|
2019-06-17 14:38:35 +00:00
|
|
|
return spv::BuiltInSubgroupGeMask;
|
2016-09-21 10:56:12 +00:00
|
|
|
|
2016-04-14 08:53:07 +00:00
|
|
|
case glslang::EbvSubGroupGtMask:
|
2016-09-21 10:56:12 +00:00
|
|
|
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
|
|
|
|
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
|
2019-06-17 14:38:35 +00:00
|
|
|
return spv::BuiltInSubgroupGtMask;
|
2016-09-21 10:56:12 +00:00
|
|
|
|
2016-04-14 08:53:07 +00:00
|
|
|
case glslang::EbvSubGroupLeMask:
|
2016-09-21 10:56:12 +00:00
|
|
|
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
|
|
|
|
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
|
2019-06-17 14:38:35 +00:00
|
|
|
return spv::BuiltInSubgroupLeMask;
|
2016-09-21 10:56:12 +00:00
|
|
|
|
2016-04-14 08:53:07 +00:00
|
|
|
case glslang::EbvSubGroupLtMask:
|
2016-09-21 10:56:12 +00:00
|
|
|
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
|
|
|
|
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
|
2019-06-17 14:38:35 +00:00
|
|
|
return spv::BuiltInSubgroupLtMask;
|
2016-09-21 10:56:12 +00:00
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EbvNumSubgroups:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
return spv::BuiltInNumSubgroups;
|
|
|
|
|
|
|
|
case glslang::EbvSubgroupID:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
return spv::BuiltInSubgroupId;
|
|
|
|
|
|
|
|
case glslang::EbvSubgroupSize2:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
return spv::BuiltInSubgroupSize;
|
|
|
|
|
|
|
|
case glslang::EbvSubgroupInvocation2:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
return spv::BuiltInSubgroupLocalInvocationId;
|
|
|
|
|
|
|
|
case glslang::EbvSubgroupEqMask2:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
|
|
|
|
return spv::BuiltInSubgroupEqMask;
|
|
|
|
|
|
|
|
case glslang::EbvSubgroupGeMask2:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
|
|
|
|
return spv::BuiltInSubgroupGeMask;
|
|
|
|
|
|
|
|
case glslang::EbvSubgroupGtMask2:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
|
|
|
|
return spv::BuiltInSubgroupGtMask;
|
|
|
|
|
|
|
|
case glslang::EbvSubgroupLeMask2:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
|
|
|
|
return spv::BuiltInSubgroupLeMask;
|
|
|
|
|
|
|
|
case glslang::EbvSubgroupLtMask2:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
|
|
|
|
return spv::BuiltInSubgroupLtMask;
|
2019-06-17 14:38:35 +00:00
|
|
|
|
2016-10-14 09:41:45 +00:00
|
|
|
case glslang::EbvBaryCoordNoPersp:
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
|
|
|
|
return spv::BuiltInBaryCoordNoPerspAMD;
|
|
|
|
|
|
|
|
case glslang::EbvBaryCoordNoPerspCentroid:
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
|
|
|
|
return spv::BuiltInBaryCoordNoPerspCentroidAMD;
|
|
|
|
|
|
|
|
case glslang::EbvBaryCoordNoPerspSample:
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
|
|
|
|
return spv::BuiltInBaryCoordNoPerspSampleAMD;
|
|
|
|
|
|
|
|
case glslang::EbvBaryCoordSmooth:
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
|
|
|
|
return spv::BuiltInBaryCoordSmoothAMD;
|
|
|
|
|
|
|
|
case glslang::EbvBaryCoordSmoothCentroid:
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
|
|
|
|
return spv::BuiltInBaryCoordSmoothCentroidAMD;
|
|
|
|
|
|
|
|
case glslang::EbvBaryCoordSmoothSample:
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
|
|
|
|
return spv::BuiltInBaryCoordSmoothSampleAMD;
|
|
|
|
|
|
|
|
case glslang::EbvBaryCoordPullModel:
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
|
|
|
|
return spv::BuiltInBaryCoordPullModelAMD;
|
2017-01-13 09:10:53 +00:00
|
|
|
|
2017-02-27 08:20:51 +00:00
|
|
|
case glslang::EbvDeviceIndex:
|
2018-03-06 23:12:04 +00:00
|
|
|
addPre13Extension(spv::E_SPV_KHR_device_group);
|
2017-02-27 08:20:51 +00:00
|
|
|
builder.addCapability(spv::CapabilityDeviceGroup);
|
2017-02-27 08:50:28 +00:00
|
|
|
return spv::BuiltInDeviceIndex;
|
2017-02-27 08:20:51 +00:00
|
|
|
|
|
|
|
case glslang::EbvViewIndex:
|
2018-03-06 23:12:04 +00:00
|
|
|
addPre13Extension(spv::E_SPV_KHR_multiview);
|
2017-02-27 08:20:51 +00:00
|
|
|
builder.addCapability(spv::CapabilityMultiView);
|
2017-02-27 08:50:28 +00:00
|
|
|
return spv::BuiltInViewIndex;
|
2017-02-27 08:20:51 +00:00
|
|
|
|
2018-11-26 15:01:58 +00:00
|
|
|
case glslang::EbvFragSizeEXT:
|
|
|
|
builder.addExtension(spv::E_SPV_EXT_fragment_invocation_density);
|
|
|
|
builder.addCapability(spv::CapabilityFragmentDensityEXT);
|
|
|
|
return spv::BuiltInFragSizeEXT;
|
|
|
|
|
|
|
|
case glslang::EbvFragInvocationCountEXT:
|
|
|
|
builder.addExtension(spv::E_SPV_EXT_fragment_invocation_density);
|
|
|
|
builder.addCapability(spv::CapabilityFragmentDensityEXT);
|
|
|
|
return spv::BuiltInFragInvocationCountEXT;
|
|
|
|
|
2017-01-13 09:10:53 +00:00
|
|
|
case glslang::EbvViewportMaskNV:
|
2017-03-16 15:02:39 +00:00
|
|
|
if (!memberDeclaration) {
|
|
|
|
builder.addExtension(spv::E_SPV_NV_viewport_array2);
|
|
|
|
builder.addCapability(spv::CapabilityShaderViewportMaskNV);
|
|
|
|
}
|
2017-01-13 09:10:53 +00:00
|
|
|
return spv::BuiltInViewportMaskNV;
|
|
|
|
case glslang::EbvSecondaryPositionNV:
|
2017-02-22 08:44:48 +00:00
|
|
|
if (!memberDeclaration) {
|
|
|
|
builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
|
|
|
|
builder.addCapability(spv::CapabilityShaderStereoViewNV);
|
|
|
|
}
|
2017-01-13 09:10:53 +00:00
|
|
|
return spv::BuiltInSecondaryPositionNV;
|
|
|
|
case glslang::EbvSecondaryViewportMaskNV:
|
2017-02-22 08:44:48 +00:00
|
|
|
if (!memberDeclaration) {
|
|
|
|
builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
|
|
|
|
builder.addCapability(spv::CapabilityShaderStereoViewNV);
|
|
|
|
}
|
2017-01-13 09:10:53 +00:00
|
|
|
return spv::BuiltInSecondaryViewportMaskNV;
|
2017-02-14 22:52:34 +00:00
|
|
|
case glslang::EbvPositionPerViewNV:
|
2017-02-22 08:44:48 +00:00
|
|
|
if (!memberDeclaration) {
|
|
|
|
builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes);
|
|
|
|
builder.addCapability(spv::CapabilityPerViewAttributesNV);
|
|
|
|
}
|
2017-02-14 22:52:34 +00:00
|
|
|
return spv::BuiltInPositionPerViewNV;
|
|
|
|
case glslang::EbvViewportMaskPerViewNV:
|
2017-02-22 08:44:48 +00:00
|
|
|
if (!memberDeclaration) {
|
|
|
|
builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes);
|
|
|
|
builder.addCapability(spv::CapabilityPerViewAttributesNV);
|
|
|
|
}
|
2017-02-14 22:52:34 +00:00
|
|
|
return spv::BuiltInViewportMaskPerViewNV;
|
2017-12-13 20:07:22 +00:00
|
|
|
case glslang::EbvFragFullyCoveredNV:
|
|
|
|
builder.addExtension(spv::E_SPV_EXT_fragment_fully_covered);
|
|
|
|
builder.addCapability(spv::CapabilityFragmentFullyCoveredEXT);
|
|
|
|
return spv::BuiltInFullyCoveredEXT;
|
2018-09-19 18:43:21 +00:00
|
|
|
case glslang::EbvFragmentSizeNV:
|
|
|
|
builder.addExtension(spv::E_SPV_NV_shading_rate);
|
|
|
|
builder.addCapability(spv::CapabilityShadingRateNV);
|
|
|
|
return spv::BuiltInFragmentSizeNV;
|
|
|
|
case glslang::EbvInvocationsPerPixelNV:
|
|
|
|
builder.addExtension(spv::E_SPV_NV_shading_rate);
|
|
|
|
builder.addCapability(spv::CapabilityShadingRateNV);
|
|
|
|
return spv::BuiltInInvocationsPerPixelNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
|
2019-05-27 20:46:31 +00:00
|
|
|
// ray tracing
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvLaunchIdNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInLaunchIdNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvLaunchSizeNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInLaunchSizeNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvWorldRayOriginNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInWorldRayOriginNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvWorldRayDirectionNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInWorldRayDirectionNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvObjectRayOriginNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInObjectRayOriginNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvObjectRayDirectionNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInObjectRayDirectionNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvRayTminNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInRayTminNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvRayTmaxNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInRayTmaxNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvInstanceCustomIndexNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInInstanceCustomIndexNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvHitTNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInHitTNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvHitKindNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInHitKindNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvObjectToWorldNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInObjectToWorldNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbvWorldToObjectNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
return spv::BuiltInWorldToObjectNV;
|
|
|
|
case glslang::EbvIncomingRayFlagsNV:
|
|
|
|
return spv::BuiltInIncomingRayFlagsNV;
|
2019-05-27 20:46:31 +00:00
|
|
|
|
|
|
|
// barycentrics
|
2018-09-19 18:39:56 +00:00
|
|
|
case glslang::EbvBaryCoordNV:
|
|
|
|
builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
|
|
|
|
builder.addCapability(spv::CapabilityFragmentBarycentricNV);
|
|
|
|
return spv::BuiltInBaryCoordNV;
|
|
|
|
case glslang::EbvBaryCoordNoPerspNV:
|
|
|
|
builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
|
|
|
|
builder.addCapability(spv::CapabilityFragmentBarycentricNV);
|
|
|
|
return spv::BuiltInBaryCoordNoPerspNV;
|
2019-05-27 20:46:31 +00:00
|
|
|
|
|
|
|
// mesh shaders
|
|
|
|
case glslang::EbvTaskCountNV:
|
2018-09-19 18:41:59 +00:00
|
|
|
return spv::BuiltInTaskCountNV;
|
2019-05-27 20:46:31 +00:00
|
|
|
case glslang::EbvPrimitiveCountNV:
|
2018-09-19 18:41:59 +00:00
|
|
|
return spv::BuiltInPrimitiveCountNV;
|
2019-05-27 20:46:31 +00:00
|
|
|
case glslang::EbvPrimitiveIndicesNV:
|
2018-09-19 18:41:59 +00:00
|
|
|
return spv::BuiltInPrimitiveIndicesNV;
|
2019-05-27 20:46:31 +00:00
|
|
|
case glslang::EbvClipDistancePerViewNV:
|
2018-09-19 18:41:59 +00:00
|
|
|
return spv::BuiltInClipDistancePerViewNV;
|
2019-05-27 20:46:31 +00:00
|
|
|
case glslang::EbvCullDistancePerViewNV:
|
2018-09-19 18:41:59 +00:00
|
|
|
return spv::BuiltInCullDistancePerViewNV;
|
2019-05-27 20:46:31 +00:00
|
|
|
case glslang::EbvLayerPerViewNV:
|
2018-09-19 18:41:59 +00:00
|
|
|
return spv::BuiltInLayerPerViewNV;
|
2019-05-27 20:46:31 +00:00
|
|
|
case glslang::EbvMeshViewCountNV:
|
2018-09-19 18:41:59 +00:00
|
|
|
return spv::BuiltInMeshViewCountNV;
|
2019-05-27 20:46:31 +00:00
|
|
|
case glslang::EbvMeshViewIndicesNV:
|
2018-09-19 18:41:59 +00:00
|
|
|
return spv::BuiltInMeshViewIndicesNV;
|
2019-06-04 12:43:32 +00:00
|
|
|
|
|
|
|
// sm builtins
|
|
|
|
case glslang::EbvWarpsPerSM:
|
|
|
|
builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
|
|
|
|
builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
|
|
|
|
return spv::BuiltInWarpsPerSMNV;
|
|
|
|
case glslang::EbvSMCount:
|
|
|
|
builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
|
|
|
|
builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
|
|
|
|
return spv::BuiltInSMCountNV;
|
|
|
|
case glslang::EbvWarpID:
|
|
|
|
builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
|
|
|
|
builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
|
|
|
|
return spv::BuiltInWarpIDNV;
|
|
|
|
case glslang::EbvSMID:
|
|
|
|
builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
|
|
|
|
builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
|
|
|
|
return spv::BuiltInSMIDNV;
|
2019-08-06 13:00:58 +00:00
|
|
|
#endif
|
|
|
|
|
2017-02-22 08:44:48 +00:00
|
|
|
default:
|
|
|
|
return spv::BuiltInMax;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-09 08:42:49 +00:00
|
|
|
// Translate glslang image layout format to SPIR-V image format.
|
2016-02-15 18:57:00 +00:00
|
|
|
spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TType& type)
|
2015-09-09 08:42:49 +00:00
|
|
|
{
|
|
|
|
assert(type.getBasicType() == glslang::EbtSampler);
|
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifdef GLSLANG_WEB
|
|
|
|
return spv::ImageFormatUnknown;
|
|
|
|
#endif
|
|
|
|
|
2016-02-15 18:57:00 +00:00
|
|
|
// Check for capabilities
|
2019-08-01 09:28:08 +00:00
|
|
|
switch (type.getQualifier().getFormat()) {
|
2016-02-15 18:57:00 +00:00
|
|
|
case glslang::ElfRg32f:
|
|
|
|
case glslang::ElfRg16f:
|
|
|
|
case glslang::ElfR11fG11fB10f:
|
|
|
|
case glslang::ElfR16f:
|
|
|
|
case glslang::ElfRgba16:
|
|
|
|
case glslang::ElfRgb10A2:
|
|
|
|
case glslang::ElfRg16:
|
|
|
|
case glslang::ElfRg8:
|
|
|
|
case glslang::ElfR16:
|
|
|
|
case glslang::ElfR8:
|
|
|
|
case glslang::ElfRgba16Snorm:
|
|
|
|
case glslang::ElfRg16Snorm:
|
|
|
|
case glslang::ElfRg8Snorm:
|
|
|
|
case glslang::ElfR16Snorm:
|
|
|
|
case glslang::ElfR8Snorm:
|
|
|
|
|
|
|
|
case glslang::ElfRg32i:
|
|
|
|
case glslang::ElfRg16i:
|
|
|
|
case glslang::ElfRg8i:
|
|
|
|
case glslang::ElfR16i:
|
|
|
|
case glslang::ElfR8i:
|
|
|
|
|
|
|
|
case glslang::ElfRgb10a2ui:
|
|
|
|
case glslang::ElfRg32ui:
|
|
|
|
case glslang::ElfRg16ui:
|
|
|
|
case glslang::ElfRg8ui:
|
|
|
|
case glslang::ElfR16ui:
|
|
|
|
case glslang::ElfR8ui:
|
|
|
|
builder.addCapability(spv::CapabilityStorageImageExtendedFormats);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// do the translation
|
2019-08-01 09:28:08 +00:00
|
|
|
switch (type.getQualifier().getFormat()) {
|
2015-09-09 08:42:49 +00:00
|
|
|
case glslang::ElfNone: return spv::ImageFormatUnknown;
|
|
|
|
case glslang::ElfRgba32f: return spv::ImageFormatRgba32f;
|
|
|
|
case glslang::ElfRgba16f: return spv::ImageFormatRgba16f;
|
|
|
|
case glslang::ElfR32f: return spv::ImageFormatR32f;
|
|
|
|
case glslang::ElfRgba8: return spv::ImageFormatRgba8;
|
|
|
|
case glslang::ElfRgba8Snorm: return spv::ImageFormatRgba8Snorm;
|
|
|
|
case glslang::ElfRg32f: return spv::ImageFormatRg32f;
|
|
|
|
case glslang::ElfRg16f: return spv::ImageFormatRg16f;
|
|
|
|
case glslang::ElfR11fG11fB10f: return spv::ImageFormatR11fG11fB10f;
|
|
|
|
case glslang::ElfR16f: return spv::ImageFormatR16f;
|
|
|
|
case glslang::ElfRgba16: return spv::ImageFormatRgba16;
|
|
|
|
case glslang::ElfRgb10A2: return spv::ImageFormatRgb10A2;
|
|
|
|
case glslang::ElfRg16: return spv::ImageFormatRg16;
|
|
|
|
case glslang::ElfRg8: return spv::ImageFormatRg8;
|
|
|
|
case glslang::ElfR16: return spv::ImageFormatR16;
|
|
|
|
case glslang::ElfR8: return spv::ImageFormatR8;
|
|
|
|
case glslang::ElfRgba16Snorm: return spv::ImageFormatRgba16Snorm;
|
|
|
|
case glslang::ElfRg16Snorm: return spv::ImageFormatRg16Snorm;
|
|
|
|
case glslang::ElfRg8Snorm: return spv::ImageFormatRg8Snorm;
|
|
|
|
case glslang::ElfR16Snorm: return spv::ImageFormatR16Snorm;
|
|
|
|
case glslang::ElfR8Snorm: return spv::ImageFormatR8Snorm;
|
|
|
|
case glslang::ElfRgba32i: return spv::ImageFormatRgba32i;
|
|
|
|
case glslang::ElfRgba16i: return spv::ImageFormatRgba16i;
|
|
|
|
case glslang::ElfRgba8i: return spv::ImageFormatRgba8i;
|
|
|
|
case glslang::ElfR32i: return spv::ImageFormatR32i;
|
|
|
|
case glslang::ElfRg32i: return spv::ImageFormatRg32i;
|
|
|
|
case glslang::ElfRg16i: return spv::ImageFormatRg16i;
|
|
|
|
case glslang::ElfRg8i: return spv::ImageFormatRg8i;
|
|
|
|
case glslang::ElfR16i: return spv::ImageFormatR16i;
|
|
|
|
case glslang::ElfR8i: return spv::ImageFormatR8i;
|
|
|
|
case glslang::ElfRgba32ui: return spv::ImageFormatRgba32ui;
|
|
|
|
case glslang::ElfRgba16ui: return spv::ImageFormatRgba16ui;
|
|
|
|
case glslang::ElfRgba8ui: return spv::ImageFormatRgba8ui;
|
|
|
|
case glslang::ElfR32ui: return spv::ImageFormatR32ui;
|
|
|
|
case glslang::ElfRg32ui: return spv::ImageFormatRg32ui;
|
|
|
|
case glslang::ElfRg16ui: return spv::ImageFormatRg16ui;
|
|
|
|
case glslang::ElfRgb10a2ui: return spv::ImageFormatRgb10a2ui;
|
|
|
|
case glslang::ElfRg8ui: return spv::ImageFormatRg8ui;
|
|
|
|
case glslang::ElfR16ui: return spv::ImageFormatR16ui;
|
|
|
|
case glslang::ElfR8ui: return spv::ImageFormatR8ui;
|
2016-07-15 17:53:56 +00:00
|
|
|
default: return spv::ImageFormatMax;
|
2015-09-09 08:42:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-30 18:01:39 +00:00
|
|
|
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(const glslang::TIntermSelection& selectionNode) const
|
2017-07-04 15:23:40 +00:00
|
|
|
{
|
2018-01-30 18:01:39 +00:00
|
|
|
if (selectionNode.getFlatten())
|
|
|
|
return spv::SelectionControlFlattenMask;
|
|
|
|
if (selectionNode.getDontFlatten())
|
|
|
|
return spv::SelectionControlDontFlattenMask;
|
|
|
|
return spv::SelectionControlMaskNone;
|
2017-07-04 15:23:40 +00:00
|
|
|
}
|
|
|
|
|
2018-01-30 18:01:39 +00:00
|
|
|
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode) const
|
2017-05-03 02:14:50 +00:00
|
|
|
{
|
2018-01-30 18:01:39 +00:00
|
|
|
if (switchNode.getFlatten())
|
|
|
|
return spv::SelectionControlFlattenMask;
|
|
|
|
if (switchNode.getDontFlatten())
|
|
|
|
return spv::SelectionControlDontFlattenMask;
|
|
|
|
return spv::SelectionControlMaskNone;
|
|
|
|
}
|
|
|
|
|
2018-01-31 15:11:18 +00:00
|
|
|
// return a non-0 dependency if the dependency argument must be set
|
|
|
|
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode,
|
2019-01-12 10:31:41 +00:00
|
|
|
std::vector<unsigned int>& operands) const
|
2018-01-30 18:01:39 +00:00
|
|
|
{
|
|
|
|
spv::LoopControlMask control = spv::LoopControlMaskNone;
|
|
|
|
|
|
|
|
if (loopNode.getDontUnroll())
|
|
|
|
control = control | spv::LoopControlDontUnrollMask;
|
|
|
|
if (loopNode.getUnroll())
|
|
|
|
control = control | spv::LoopControlUnrollMask;
|
2018-02-18 18:40:01 +00:00
|
|
|
if (unsigned(loopNode.getLoopDependency()) == glslang::TIntermLoop::dependencyInfinite)
|
2018-01-31 15:11:18 +00:00
|
|
|
control = control | spv::LoopControlDependencyInfiniteMask;
|
|
|
|
else if (loopNode.getLoopDependency() > 0) {
|
|
|
|
control = control | spv::LoopControlDependencyLengthMask;
|
2019-01-12 10:31:41 +00:00
|
|
|
operands.push_back((unsigned int)loopNode.getLoopDependency());
|
|
|
|
}
|
|
|
|
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
|
|
|
|
if (loopNode.getMinIterations() > 0) {
|
|
|
|
control = control | spv::LoopControlMinIterationsMask;
|
|
|
|
operands.push_back(loopNode.getMinIterations());
|
|
|
|
}
|
|
|
|
if (loopNode.getMaxIterations() < glslang::TIntermLoop::iterationsInfinite) {
|
|
|
|
control = control | spv::LoopControlMaxIterationsMask;
|
|
|
|
operands.push_back(loopNode.getMaxIterations());
|
|
|
|
}
|
|
|
|
if (loopNode.getIterationMultiple() > 1) {
|
|
|
|
control = control | spv::LoopControlIterationMultipleMask;
|
|
|
|
operands.push_back(loopNode.getIterationMultiple());
|
|
|
|
}
|
|
|
|
if (loopNode.getPeelCount() > 0) {
|
|
|
|
control = control | spv::LoopControlPeelCountMask;
|
|
|
|
operands.push_back(loopNode.getPeelCount());
|
|
|
|
}
|
|
|
|
if (loopNode.getPartialCount() > 0) {
|
|
|
|
control = control | spv::LoopControlPartialCountMask;
|
|
|
|
operands.push_back(loopNode.getPartialCount());
|
|
|
|
}
|
2018-01-31 15:11:18 +00:00
|
|
|
}
|
2018-01-30 18:01:39 +00:00
|
|
|
|
|
|
|
return control;
|
2017-05-03 02:14:50 +00:00
|
|
|
}
|
|
|
|
|
2017-05-05 11:09:58 +00:00
|
|
|
// Translate glslang type to SPIR-V storage class.
|
|
|
|
spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::TType& type)
|
|
|
|
{
|
|
|
|
if (type.getQualifier().isPipeInput())
|
|
|
|
return spv::StorageClassInput;
|
2017-09-08 08:38:07 +00:00
|
|
|
if (type.getQualifier().isPipeOutput())
|
2017-05-05 11:09:58 +00:00
|
|
|
return spv::StorageClassOutput;
|
2017-09-08 08:38:07 +00:00
|
|
|
|
|
|
|
if (glslangIntermediate->getSource() != glslang::EShSourceHlsl ||
|
2019-08-06 13:00:58 +00:00
|
|
|
type.getQualifier().storage == glslang::EvqUniform) {
|
|
|
|
#ifndef GLSLANG_WEB
|
2017-09-08 08:38:07 +00:00
|
|
|
if (type.getBasicType() == glslang::EbtAtomicUint)
|
|
|
|
return spv::StorageClassAtomicCounter;
|
2019-08-06 13:00:58 +00:00
|
|
|
#endif
|
2017-09-08 08:38:07 +00:00
|
|
|
if (type.containsOpaque())
|
|
|
|
return spv::StorageClassUniformConstant;
|
|
|
|
}
|
|
|
|
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-12-15 02:59:53 +00:00
|
|
|
if (type.getQualifier().isUniformOrBuffer() &&
|
|
|
|
type.getQualifier().layoutShaderRecordNV) {
|
|
|
|
return spv::StorageClassShaderRecordBufferNV;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-09-08 08:38:07 +00:00
|
|
|
if (glslangIntermediate->usingStorageBuffer() && type.getQualifier().storage == glslang::EvqBuffer) {
|
2018-03-06 23:12:04 +00:00
|
|
|
addPre13Extension(spv::E_SPV_KHR_storage_buffer_storage_class);
|
2017-05-05 11:09:58 +00:00
|
|
|
return spv::StorageClassStorageBuffer;
|
2017-09-08 08:38:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (type.getQualifier().isUniformOrBuffer()) {
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2019-08-01 09:28:08 +00:00
|
|
|
if (type.getQualifier().isPushConstant())
|
2017-05-05 11:09:58 +00:00
|
|
|
return spv::StorageClassPushConstant;
|
2019-08-06 13:00:58 +00:00
|
|
|
#endif
|
2017-05-05 11:09:58 +00:00
|
|
|
if (type.getBasicType() == glslang::EbtBlock)
|
|
|
|
return spv::StorageClassUniform;
|
2017-09-08 08:38:07 +00:00
|
|
|
return spv::StorageClassUniformConstant;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type.getQualifier().storage) {
|
|
|
|
case glslang::EvqGlobal: return spv::StorageClassPrivate;
|
|
|
|
case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
|
|
|
|
case glslang::EvqTemporary: return spv::StorageClassFunction;
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
case glslang::EvqShared: return spv::StorageClassWorkgroup;
|
2018-10-22 23:41:44 +00:00
|
|
|
case glslang::EvqPayloadNV: return spv::StorageClassRayPayloadNV;
|
|
|
|
case glslang::EvqPayloadInNV: return spv::StorageClassIncomingRayPayloadNV;
|
|
|
|
case glslang::EvqHitAttrNV: return spv::StorageClassHitAttributeNV;
|
|
|
|
case glslang::EvqCallableDataNV: return spv::StorageClassCallableDataNV;
|
|
|
|
case glslang::EvqCallableDataInNV: return spv::StorageClassIncomingCallableDataNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
#endif
|
2017-09-08 08:38:07 +00:00
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
break;
|
2017-05-05 11:09:58 +00:00
|
|
|
}
|
2017-09-08 08:38:07 +00:00
|
|
|
|
|
|
|
return spv::StorageClassFunction;
|
2017-05-05 11:09:58 +00:00
|
|
|
}
|
|
|
|
|
2018-04-05 17:25:02 +00:00
|
|
|
// Add capabilities pertaining to how an array is indexed.
|
|
|
|
void TGlslangToSpvTraverser::addIndirectionIndexCapabilities(const glslang::TType& baseType,
|
|
|
|
const glslang::TType& indexType)
|
|
|
|
{
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-04-05 17:25:02 +00:00
|
|
|
if (indexType.getQualifier().isNonUniform()) {
|
|
|
|
// deal with an asserted non-uniform index
|
2018-07-12 21:51:18 +00:00
|
|
|
// SPV_EXT_descriptor_indexing already added in TranslateNonUniformDecoration
|
2018-04-05 17:25:02 +00:00
|
|
|
if (baseType.getBasicType() == glslang::EbtSampler) {
|
|
|
|
if (baseType.getQualifier().hasAttachment())
|
|
|
|
builder.addCapability(spv::CapabilityInputAttachmentArrayNonUniformIndexingEXT);
|
2019-08-08 07:15:24 +00:00
|
|
|
else if (baseType.isImage() && baseType.getSampler().isBuffer())
|
2018-04-05 17:25:02 +00:00
|
|
|
builder.addCapability(spv::CapabilityStorageTexelBufferArrayNonUniformIndexingEXT);
|
2019-08-08 07:15:24 +00:00
|
|
|
else if (baseType.isTexture() && baseType.getSampler().isBuffer())
|
2018-04-05 17:25:02 +00:00
|
|
|
builder.addCapability(spv::CapabilityUniformTexelBufferArrayNonUniformIndexingEXT);
|
|
|
|
else if (baseType.isImage())
|
|
|
|
builder.addCapability(spv::CapabilityStorageImageArrayNonUniformIndexingEXT);
|
|
|
|
else if (baseType.isTexture())
|
|
|
|
builder.addCapability(spv::CapabilitySampledImageArrayNonUniformIndexingEXT);
|
|
|
|
} else if (baseType.getBasicType() == glslang::EbtBlock) {
|
|
|
|
if (baseType.getQualifier().storage == glslang::EvqBuffer)
|
|
|
|
builder.addCapability(spv::CapabilityStorageBufferArrayNonUniformIndexingEXT);
|
|
|
|
else if (baseType.getQualifier().storage == glslang::EvqUniform)
|
|
|
|
builder.addCapability(spv::CapabilityUniformBufferArrayNonUniformIndexingEXT);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// assume a dynamically uniform index
|
|
|
|
if (baseType.getBasicType() == glslang::EbtSampler) {
|
2018-07-12 21:51:18 +00:00
|
|
|
if (baseType.getQualifier().hasAttachment()) {
|
|
|
|
builder.addExtension("SPV_EXT_descriptor_indexing");
|
2018-04-05 17:25:02 +00:00
|
|
|
builder.addCapability(spv::CapabilityInputAttachmentArrayDynamicIndexingEXT);
|
2019-08-08 07:15:24 +00:00
|
|
|
} else if (baseType.isImage() && baseType.getSampler().isBuffer()) {
|
2018-07-12 21:51:18 +00:00
|
|
|
builder.addExtension("SPV_EXT_descriptor_indexing");
|
2018-04-05 17:25:02 +00:00
|
|
|
builder.addCapability(spv::CapabilityStorageTexelBufferArrayDynamicIndexingEXT);
|
2019-08-08 07:15:24 +00:00
|
|
|
} else if (baseType.isTexture() && baseType.getSampler().isBuffer()) {
|
2018-07-12 21:51:18 +00:00
|
|
|
builder.addExtension("SPV_EXT_descriptor_indexing");
|
2018-04-05 17:25:02 +00:00
|
|
|
builder.addCapability(spv::CapabilityUniformTexelBufferArrayDynamicIndexingEXT);
|
2018-07-12 21:51:18 +00:00
|
|
|
}
|
2018-04-05 17:25:02 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2018-04-05 17:25:02 +00:00
|
|
|
}
|
|
|
|
|
2016-05-06 21:25:16 +00:00
|
|
|
// Return whether or not the given type is something that should be tied to a
|
2016-02-16 03:58:50 +00:00
|
|
|
// descriptor set.
|
|
|
|
bool IsDescriptorResource(const glslang::TType& type)
|
|
|
|
{
|
2016-03-09 04:36:22 +00:00
|
|
|
// uniform and buffer blocks are included, unless it is a push_constant
|
2016-02-16 03:58:50 +00:00
|
|
|
if (type.getBasicType() == glslang::EbtBlock)
|
2018-09-19 18:42:24 +00:00
|
|
|
return type.getQualifier().isUniformOrBuffer() &&
|
2019-08-01 09:28:08 +00:00
|
|
|
! type.getQualifier().isShaderRecordNV() &&
|
|
|
|
! type.getQualifier().isPushConstant();
|
2016-02-16 03:58:50 +00:00
|
|
|
|
|
|
|
// non block...
|
|
|
|
// basically samplerXXX/subpass/sampler/texture are all included
|
|
|
|
// if they are the global-scope-class, not the function parameter
|
|
|
|
// (or local, if they ever exist) class.
|
|
|
|
if (type.getBasicType() == glslang::EbtSampler)
|
|
|
|
return type.getQualifier().isUniformOrBuffer();
|
|
|
|
|
|
|
|
// None of the above.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-12-24 17:30:13 +00:00
|
|
|
void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& parent)
|
|
|
|
{
|
|
|
|
if (child.layoutMatrix == glslang::ElmNone)
|
|
|
|
child.layoutMatrix = parent.layoutMatrix;
|
|
|
|
|
|
|
|
if (parent.invariant)
|
|
|
|
child.invariant = true;
|
2019-08-06 13:00:58 +00:00
|
|
|
if (parent.flat)
|
|
|
|
child.flat = true;
|
|
|
|
if (parent.centroid)
|
|
|
|
child.centroid = true;
|
2019-08-01 09:28:08 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2015-12-24 17:30:13 +00:00
|
|
|
if (parent.nopersp)
|
|
|
|
child.nopersp = true;
|
2016-05-05 04:30:44 +00:00
|
|
|
if (parent.explicitInterp)
|
|
|
|
child.explicitInterp = true;
|
2019-08-06 13:00:58 +00:00
|
|
|
if (parent.perPrimitiveNV)
|
|
|
|
child.perPrimitiveNV = true;
|
|
|
|
if (parent.perViewNV)
|
|
|
|
child.perViewNV = true;
|
|
|
|
if (parent.perTaskNV)
|
|
|
|
child.perTaskNV = true;
|
2015-12-24 17:30:13 +00:00
|
|
|
if (parent.patch)
|
|
|
|
child.patch = true;
|
|
|
|
if (parent.sample)
|
|
|
|
child.sample = true;
|
2016-02-21 12:59:01 +00:00
|
|
|
if (parent.coherent)
|
|
|
|
child.coherent = true;
|
2018-09-05 15:11:41 +00:00
|
|
|
if (parent.devicecoherent)
|
|
|
|
child.devicecoherent = true;
|
|
|
|
if (parent.queuefamilycoherent)
|
|
|
|
child.queuefamilycoherent = true;
|
|
|
|
if (parent.workgroupcoherent)
|
|
|
|
child.workgroupcoherent = true;
|
|
|
|
if (parent.subgroupcoherent)
|
|
|
|
child.subgroupcoherent = true;
|
|
|
|
if (parent.nonprivate)
|
|
|
|
child.nonprivate = true;
|
2016-02-21 12:59:01 +00:00
|
|
|
if (parent.volatil)
|
|
|
|
child.volatil = true;
|
|
|
|
if (parent.restrict)
|
|
|
|
child.restrict = true;
|
|
|
|
if (parent.readonly)
|
|
|
|
child.readonly = true;
|
|
|
|
if (parent.writeonly)
|
|
|
|
child.writeonly = true;
|
2018-09-19 18:41:59 +00:00
|
|
|
#endif
|
2015-12-24 17:30:13 +00:00
|
|
|
}
|
|
|
|
|
2016-09-01 23:05:23 +00:00
|
|
|
bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifier& qualifier)
|
2015-12-24 17:30:13 +00:00
|
|
|
{
|
2016-01-22 01:56:57 +00:00
|
|
|
// This should list qualifiers that simultaneous satisfy:
|
2016-09-01 23:05:23 +00:00
|
|
|
// - struct members might inherit from a struct declaration
|
|
|
|
// (note that non-block structs don't explicitly inherit,
|
|
|
|
// only implicitly, meaning no decoration involved)
|
|
|
|
// - affect decorations on the struct members
|
|
|
|
// (note smooth does not, and expecting something like volatile
|
|
|
|
// to effect the whole object)
|
2015-12-24 17:30:13 +00:00
|
|
|
// - are not part of the offset/st430/etc or row/column-major layout
|
2016-09-01 23:05:23 +00:00
|
|
|
return qualifier.invariant || (qualifier.hasLocation() && type.getBasicType() == glslang::EbtBlock);
|
2015-12-24 17:30:13 +00:00
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
//
|
|
|
|
// Implement the TGlslangToSpvTraverser class.
|
|
|
|
//
|
|
|
|
|
2018-02-01 01:35:56 +00:00
|
|
|
TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate* glslangIntermediate,
|
2017-05-31 23:11:16 +00:00
|
|
|
spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options)
|
|
|
|
: TIntermTraverser(true, false, true),
|
|
|
|
options(options),
|
|
|
|
shaderEntry(nullptr), currentFunction(nullptr),
|
2016-10-06 18:59:51 +00:00
|
|
|
sequenceDepth(0), logger(buildLogger),
|
2018-02-01 01:35:56 +00:00
|
|
|
builder(spvVersion, (glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger),
|
2016-11-26 20:31:47 +00:00
|
|
|
inEntryPoint(false), entryPointTerminated(false), linkageOnly(false),
|
2019-06-18 05:33:09 +00:00
|
|
|
glslangIntermediate(glslangIntermediate),
|
|
|
|
nanMinMaxClamp(glslangIntermediate->getNanMinMaxClamp())
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
|
|
|
spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());
|
|
|
|
|
|
|
|
builder.clearAccessChain();
|
2017-07-21 02:00:36 +00:00
|
|
|
builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()),
|
|
|
|
glslangIntermediate->getVersion());
|
|
|
|
|
2017-05-31 23:11:16 +00:00
|
|
|
if (options.generateDebugInfo) {
|
2017-06-01 00:50:53 +00:00
|
|
|
builder.setEmitOpLines();
|
2017-07-21 02:00:36 +00:00
|
|
|
builder.setSourceFile(glslangIntermediate->getSourceFile());
|
|
|
|
|
|
|
|
// Set the source shader's text. If for SPV version 1.0, include
|
|
|
|
// a preamble in comments stating the OpModuleProcessed instructions.
|
|
|
|
// Otherwise, emit those as actual instructions.
|
|
|
|
std::string text;
|
|
|
|
const std::vector<std::string>& processes = glslangIntermediate->getProcesses();
|
|
|
|
for (int p = 0; p < (int)processes.size(); ++p) {
|
2018-10-26 16:12:32 +00:00
|
|
|
if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_1) {
|
2017-07-21 02:00:36 +00:00
|
|
|
text.append("// OpModuleProcessed ");
|
|
|
|
text.append(processes[p]);
|
|
|
|
text.append("\n");
|
|
|
|
} else
|
|
|
|
builder.addModuleProcessed(processes[p]);
|
|
|
|
}
|
2018-10-26 16:12:32 +00:00
|
|
|
if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_1 && (int)processes.size() > 0)
|
2017-07-21 02:00:36 +00:00
|
|
|
text.append("#line 1\n");
|
|
|
|
text.append(glslangIntermediate->getSourceText());
|
|
|
|
builder.setSourceText(text);
|
2018-12-06 18:13:15 +00:00
|
|
|
// Pass name and text for all included files
|
|
|
|
const std::map<std::string, std::string>& include_txt = glslangIntermediate->getIncludeText();
|
|
|
|
for (auto iItr = include_txt.begin(); iItr != include_txt.end(); ++iItr)
|
|
|
|
builder.addInclude(iItr->first, iItr->second);
|
2017-05-31 23:11:16 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
stdBuiltins = builder.import("GLSL.std.450");
|
2019-01-06 23:58:04 +00:00
|
|
|
|
|
|
|
spv::AddressingModel addressingModel = spv::AddressingModelLogical;
|
|
|
|
spv::MemoryModel memoryModel = spv::MemoryModelGLSL450;
|
|
|
|
|
|
|
|
if (glslangIntermediate->usingPhysicalStorageBuffer()) {
|
|
|
|
addressingModel = spv::AddressingModelPhysicalStorageBuffer64EXT;
|
|
|
|
builder.addExtension(spv::E_SPV_EXT_physical_storage_buffer);
|
|
|
|
builder.addCapability(spv::CapabilityPhysicalStorageBufferAddressesEXT);
|
|
|
|
};
|
2018-09-05 15:11:41 +00:00
|
|
|
if (glslangIntermediate->usingVulkanMemoryModel()) {
|
2019-01-06 23:58:04 +00:00
|
|
|
memoryModel = spv::MemoryModelVulkanKHR;
|
|
|
|
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
|
2018-09-05 15:11:41 +00:00
|
|
|
builder.addExtension(spv::E_SPV_KHR_vulkan_memory_model);
|
|
|
|
}
|
2019-01-06 23:58:04 +00:00
|
|
|
builder.setMemoryModel(addressingModel, memoryModel);
|
|
|
|
|
2019-02-19 19:10:32 +00:00
|
|
|
if (glslangIntermediate->usingVariablePointers()) {
|
|
|
|
builder.addCapability(spv::CapabilityVariablePointers);
|
|
|
|
}
|
|
|
|
|
2016-09-20 00:09:30 +00:00
|
|
|
shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str());
|
|
|
|
entryPoint = builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
// Add the source extensions
|
2015-07-19 04:34:27 +00:00
|
|
|
const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
|
|
|
|
for (auto it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.addSourceExtension(it->c_str());
|
|
|
|
|
|
|
|
// Add the top-level modes for this shader.
|
|
|
|
|
2016-02-01 20:45:25 +00:00
|
|
|
if (glslangIntermediate->getXfbMode()) {
|
|
|
|
builder.addCapability(spv::CapabilityTransformFeedback);
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);
|
2016-02-01 20:45:25 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
unsigned int mode;
|
|
|
|
switch (glslangIntermediate->getStage()) {
|
|
|
|
case EShLangVertex:
|
2015-08-07 04:53:06 +00:00
|
|
|
builder.addCapability(spv::CapabilityShader);
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EShLangFragment:
|
2015-08-07 04:53:06 +00:00
|
|
|
builder.addCapability(spv::CapabilityShader);
|
2015-06-26 22:58:36 +00:00
|
|
|
if (glslangIntermediate->getPixelCenterInteger())
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);
|
2015-10-13 22:29:02 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
if (glslangIntermediate->getOriginUpperLeft())
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);
|
2015-08-07 04:53:06 +00:00
|
|
|
else
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginLowerLeft);
|
2015-10-13 22:29:02 +00:00
|
|
|
|
|
|
|
if (glslangIntermediate->getEarlyFragmentTests())
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests);
|
|
|
|
|
2017-07-01 00:14:30 +00:00
|
|
|
if (glslangIntermediate->getPostDepthCoverage()) {
|
|
|
|
builder.addCapability(spv::CapabilitySampleMaskPostDepthCoverage);
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModePostDepthCoverage);
|
|
|
|
builder.addExtension(spv::E_SPV_KHR_post_depth_coverage);
|
|
|
|
}
|
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
if (glslangIntermediate->getDepth() != glslang::EldUnchanged && glslangIntermediate->isDepthReplacing())
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing);
|
|
|
|
|
|
|
|
#ifndef GLSLANG_WEB
|
2015-10-13 22:29:02 +00:00
|
|
|
switch(glslangIntermediate->getDepth()) {
|
|
|
|
case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break;
|
|
|
|
case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break;
|
2016-07-15 17:53:56 +00:00
|
|
|
default: mode = spv::ExecutionModeMax; break;
|
2015-10-13 22:29:02 +00:00
|
|
|
}
|
2016-07-15 17:53:56 +00:00
|
|
|
if (mode != spv::ExecutionModeMax)
|
2015-10-13 22:29:02 +00:00
|
|
|
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
|
2019-06-03 16:33:50 +00:00
|
|
|
switch (glslangIntermediate->getInterlockOrdering()) {
|
|
|
|
case glslang::EioPixelInterlockOrdered: mode = spv::ExecutionModePixelInterlockOrderedEXT; break;
|
|
|
|
case glslang::EioPixelInterlockUnordered: mode = spv::ExecutionModePixelInterlockUnorderedEXT; break;
|
|
|
|
case glslang::EioSampleInterlockOrdered: mode = spv::ExecutionModeSampleInterlockOrderedEXT; break;
|
|
|
|
case glslang::EioSampleInterlockUnordered: mode = spv::ExecutionModeSampleInterlockUnorderedEXT; break;
|
|
|
|
case glslang::EioShadingRateInterlockOrdered: mode = spv::ExecutionModeShadingRateInterlockOrderedEXT; break;
|
|
|
|
case glslang::EioShadingRateInterlockUnordered: mode = spv::ExecutionModeShadingRateInterlockUnorderedEXT; break;
|
|
|
|
default: mode = spv::ExecutionModeMax; break;
|
|
|
|
}
|
|
|
|
if (mode != spv::ExecutionModeMax) {
|
|
|
|
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
|
|
|
|
if (mode == spv::ExecutionModeShadingRateInterlockOrderedEXT ||
|
|
|
|
mode == spv::ExecutionModeShadingRateInterlockUnorderedEXT) {
|
|
|
|
builder.addCapability(spv::CapabilityFragmentShaderShadingRateInterlockEXT);
|
|
|
|
} else if (mode == spv::ExecutionModePixelInterlockOrderedEXT ||
|
|
|
|
mode == spv::ExecutionModePixelInterlockUnorderedEXT) {
|
|
|
|
builder.addCapability(spv::CapabilityFragmentShaderPixelInterlockEXT);
|
|
|
|
} else {
|
|
|
|
builder.addCapability(spv::CapabilityFragmentShaderSampleInterlockEXT);
|
|
|
|
}
|
|
|
|
builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock);
|
|
|
|
}
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2015-06-26 22:58:36 +00:00
|
|
|
case EShLangCompute:
|
2015-08-07 04:53:06 +00:00
|
|
|
builder.addCapability(spv::CapabilityShader);
|
2015-09-16 22:04:05 +00:00
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0),
|
|
|
|
glslangIntermediate->getLocalSize(1),
|
|
|
|
glslangIntermediate->getLocalSize(2));
|
2018-09-19 18:40:45 +00:00
|
|
|
if (glslangIntermediate->getLayoutDerivativeModeNone() == glslang::LayoutDerivativeGroupQuads) {
|
|
|
|
builder.addCapability(spv::CapabilityComputeDerivativeGroupQuadsNV);
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeDerivativeGroupQuadsNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives);
|
|
|
|
} else if (glslangIntermediate->getLayoutDerivativeModeNone() == glslang::LayoutDerivativeGroupLinear) {
|
|
|
|
builder.addCapability(spv::CapabilityComputeDerivativeGroupLinearNV);
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeDerivativeGroupLinearNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives);
|
|
|
|
}
|
2019-08-06 13:00:58 +00:00
|
|
|
break;
|
|
|
|
case EShLangTessEvaluation:
|
|
|
|
case EShLangTessControl:
|
|
|
|
builder.addCapability(spv::CapabilityTessellation);
|
|
|
|
|
|
|
|
glslang::TLayoutGeometry primitive;
|
|
|
|
|
|
|
|
if (glslangIntermediate->getStage() == EShLangTessControl) {
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
|
|
|
|
primitive = glslangIntermediate->getOutputPrimitive();
|
|
|
|
} else {
|
|
|
|
primitive = glslangIntermediate->getInputPrimitive();
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (primitive) {
|
|
|
|
case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break;
|
|
|
|
case glslang::ElgQuads: mode = spv::ExecutionModeQuads; break;
|
|
|
|
case glslang::ElgIsolines: mode = spv::ExecutionModeIsolines; break;
|
|
|
|
default: mode = spv::ExecutionModeMax; break;
|
|
|
|
}
|
|
|
|
if (mode != spv::ExecutionModeMax)
|
|
|
|
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
|
|
|
|
|
|
|
|
switch (glslangIntermediate->getVertexSpacing()) {
|
|
|
|
case glslang::EvsEqual: mode = spv::ExecutionModeSpacingEqual; break;
|
|
|
|
case glslang::EvsFractionalEven: mode = spv::ExecutionModeSpacingFractionalEven; break;
|
|
|
|
case glslang::EvsFractionalOdd: mode = spv::ExecutionModeSpacingFractionalOdd; break;
|
|
|
|
default: mode = spv::ExecutionModeMax; break;
|
|
|
|
}
|
|
|
|
if (mode != spv::ExecutionModeMax)
|
|
|
|
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
|
|
|
|
|
|
|
|
switch (glslangIntermediate->getVertexOrder()) {
|
|
|
|
case glslang::EvoCw: mode = spv::ExecutionModeVertexOrderCw; break;
|
|
|
|
case glslang::EvoCcw: mode = spv::ExecutionModeVertexOrderCcw; break;
|
|
|
|
default: mode = spv::ExecutionModeMax; break;
|
|
|
|
}
|
|
|
|
if (mode != spv::ExecutionModeMax)
|
|
|
|
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
|
|
|
|
|
|
|
|
if (glslangIntermediate->getPointMode())
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModePointMode);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EShLangGeometry:
|
|
|
|
builder.addCapability(spv::CapabilityGeometry);
|
|
|
|
switch (glslangIntermediate->getInputPrimitive()) {
|
|
|
|
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::ExecutionModeTriangles; break;
|
|
|
|
case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
|
|
|
|
default: mode = spv::ExecutionModeMax; break;
|
|
|
|
}
|
|
|
|
if (mode != spv::ExecutionModeMax)
|
|
|
|
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
|
|
|
|
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());
|
|
|
|
|
|
|
|
switch (glslangIntermediate->getOutputPrimitive()) {
|
|
|
|
case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break;
|
|
|
|
case glslang::ElgLineStrip: mode = spv::ExecutionModeOutputLineStrip; break;
|
|
|
|
case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip; break;
|
|
|
|
default: mode = spv::ExecutionModeMax; break;
|
|
|
|
}
|
|
|
|
if (mode != spv::ExecutionModeMax)
|
|
|
|
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
2018-09-19 18:42:24 +00:00
|
|
|
case EShLangRayGenNV:
|
|
|
|
case EShLangIntersectNV:
|
|
|
|
case EShLangAnyHitNV:
|
|
|
|
case EShLangClosestHitNV:
|
|
|
|
case EShLangMissNV:
|
|
|
|
case EShLangCallableNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
builder.addCapability(spv::CapabilityRayTracingNV);
|
|
|
|
builder.addExtension("SPV_NV_ray_tracing");
|
2018-09-19 18:42:24 +00:00
|
|
|
break;
|
2018-09-19 18:41:59 +00:00
|
|
|
case EShLangTaskNV:
|
|
|
|
case EShLangMeshNV:
|
|
|
|
builder.addCapability(spv::CapabilityMeshShadingNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_mesh_shader);
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0),
|
|
|
|
glslangIntermediate->getLocalSize(1),
|
|
|
|
glslangIntermediate->getLocalSize(2));
|
|
|
|
if (glslangIntermediate->getStage() == EShLangMeshNV) {
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
|
|
|
|
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputPrimitivesNV, glslangIntermediate->getPrimitives());
|
|
|
|
|
|
|
|
switch (glslangIntermediate->getOutputPrimitive()) {
|
|
|
|
case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break;
|
|
|
|
case glslang::ElgLines: mode = spv::ExecutionModeOutputLinesNV; break;
|
|
|
|
case glslang::ElgTriangles: mode = spv::ExecutionModeOutputTrianglesNV; break;
|
|
|
|
default: mode = spv::ExecutionModeMax; break;
|
|
|
|
}
|
|
|
|
if (mode != spv::ExecutionModeMax)
|
|
|
|
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-26 20:23:20 +00:00
|
|
|
// Finish creating SPV, after the traversal is complete.
|
|
|
|
void TGlslangToSpvTraverser::finishSpv()
|
2015-12-21 00:37:07 +00:00
|
|
|
{
|
2018-08-03 21:56:12 +00:00
|
|
|
// Finish the entry point function
|
2016-11-26 20:31:47 +00:00
|
|
|
if (! entryPointTerminated) {
|
2016-11-26 20:23:20 +00:00
|
|
|
builder.setBuildPoint(shaderEntry->getLastBlock());
|
|
|
|
builder.leaveFunction();
|
|
|
|
}
|
|
|
|
|
2015-12-21 00:37:07 +00:00
|
|
|
// finish off the entry-point SPV instruction by adding the Input/Output <id>
|
2016-02-23 21:17:38 +00:00
|
|
|
for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it)
|
|
|
|
entryPoint->addIdOperand(*it);
|
2015-12-21 00:37:07 +00:00
|
|
|
|
2019-07-28 08:12:10 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-08-03 21:56:12 +00:00
|
|
|
// Add capabilities, extensions, remove unneeded decorations, etc.,
|
|
|
|
// based on the resulting SPIR-V.
|
|
|
|
builder.postProcess();
|
2019-07-28 08:12:10 +00:00
|
|
|
#endif
|
2015-12-21 00:37:07 +00:00
|
|
|
}
|
|
|
|
|
2016-11-26 20:23:20 +00:00
|
|
|
// Write the SPV into 'out'.
|
|
|
|
void TGlslangToSpvTraverser::dumpSpv(std::vector<unsigned int>& out)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2016-11-26 20:23:20 +00:00
|
|
|
builder.dump(out);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Implement the traversal functions.
|
|
|
|
//
|
|
|
|
// Return true from interior nodes to have the external traversal
|
|
|
|
// continue on to children. Return false if children were
|
|
|
|
// already processed.
|
|
|
|
//
|
|
|
|
|
|
|
|
//
|
2016-05-06 21:25:16 +00:00
|
|
|
// Symbols can turn into
|
2015-06-26 22:58:36 +00:00
|
|
|
// - uniform/input reads
|
|
|
|
// - output writes
|
|
|
|
// - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain
|
|
|
|
// - something simple that degenerates into the last bullet
|
|
|
|
//
|
|
|
|
void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
|
|
|
|
{
|
2016-04-06 18:42:01 +00:00
|
|
|
SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
|
|
|
|
if (symbol->getType().getQualifier().isSpecConstant())
|
|
|
|
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
// getSymbolId() will set up all the IO decorations on the first call.
|
|
|
|
// Formal function parameters were mapped during makeFunctions().
|
|
|
|
spv::Id id = getSymbolId(symbol);
|
2015-12-21 00:37:07 +00:00
|
|
|
|
|
|
|
if (builder.isPointer(id)) {
|
2019-06-17 14:38:35 +00:00
|
|
|
// Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction
|
2019-01-04 09:47:06 +00:00
|
|
|
// Consider adding to the OpEntryPoint interface list.
|
|
|
|
// Only looking at structures if they have at least one member.
|
|
|
|
if (!symbol->getType().isStruct() || symbol->getType().getStruct()->size() > 0) {
|
|
|
|
spv::StorageClass sc = builder.getStorageClass(id);
|
|
|
|
// Before SPIR-V 1.4, we only want to include Input and Output.
|
|
|
|
// Starting with SPIR-V 1.4, we want all globals.
|
|
|
|
if ((glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4 && sc != spv::StorageClassFunction) ||
|
|
|
|
(sc == spv::StorageClassInput || sc == spv::StorageClassOutput)) {
|
2017-09-19 17:09:59 +00:00
|
|
|
iOSet.insert(id);
|
2019-01-04 09:47:06 +00:00
|
|
|
}
|
2017-09-19 17:09:59 +00:00
|
|
|
}
|
2019-06-17 14:38:35 +00:00
|
|
|
|
|
|
|
// If the SPIR-V type is required to be different than the AST type,
|
|
|
|
// translate now from the SPIR-V type to the AST type, for the consuming
|
|
|
|
// operation.
|
|
|
|
// Note this turns it from an l-value to an r-value.
|
|
|
|
// Currently, all symbols needing this are inputs; avoid the map lookup when non-input.
|
|
|
|
if (symbol->getType().getQualifier().storage == glslang::EvqVaryingIn)
|
|
|
|
id = translateForcedType(id);
|
2015-12-21 00:37:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Only process non-linkage-only nodes for generating actual static uses
|
2016-02-16 03:58:50 +00:00
|
|
|
if (! linkageOnly || symbol->getQualifier().isSpecConstant()) {
|
2015-06-26 22:58:36 +00:00
|
|
|
// Prepare to generate code for the access
|
|
|
|
|
|
|
|
// L-value chains will be computed left to right. We're on the symbol now,
|
|
|
|
// which is the left-most part of the access chain, so now is "clear" time,
|
|
|
|
// followed by setting the base.
|
|
|
|
builder.clearAccessChain();
|
|
|
|
|
|
|
|
// For now, we consider all user variables as being in memory, so they are pointers,
|
2016-02-16 03:58:50 +00:00
|
|
|
// except for
|
2016-09-02 17:20:21 +00:00
|
|
|
// A) R-Value arguments to a function, which are an intermediate object.
|
2016-02-16 03:58:50 +00:00
|
|
|
// See comments in handleUserFunctionCall().
|
2016-09-02 17:20:21 +00:00
|
|
|
// B) Specialization constants (normal constants don't even come in as a variable),
|
2016-02-16 03:58:50 +00:00
|
|
|
// These are also pure R-values.
|
2019-06-17 14:38:35 +00:00
|
|
|
// C) R-Values from type translation, see above call to translateForcedType()
|
2016-02-16 03:58:50 +00:00
|
|
|
glslang::TQualifier qualifier = symbol->getQualifier();
|
2019-06-17 14:38:35 +00:00
|
|
|
if (qualifier.isSpecConstant() || rValueParameters.find(symbol->getId()) != rValueParameters.end() ||
|
|
|
|
!builder.isPointerType(builder.getTypeId(id)))
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.setAccessChainRValue(id);
|
|
|
|
else
|
|
|
|
builder.setAccessChainLValue(id);
|
|
|
|
}
|
2018-03-08 01:05:55 +00:00
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifdef ENABLE_HLSL
|
2018-03-08 01:05:55 +00:00
|
|
|
// Process linkage-only nodes for any special additional interface work.
|
|
|
|
if (linkageOnly) {
|
|
|
|
if (glslangIntermediate->getHlslFunctionality1()) {
|
|
|
|
// Map implicit counter buffers to their originating buffers, which should have been
|
|
|
|
// seen by now, given earlier pruning of unused counters, and preservation of order
|
|
|
|
// of declaration.
|
|
|
|
if (symbol->getType().getQualifier().isUniformOrBuffer()) {
|
|
|
|
if (!glslangIntermediate->hasCounterBufferName(symbol->getName())) {
|
|
|
|
// Save possible originating buffers for counter buffers, keyed by
|
|
|
|
// making the potential counter-buffer name.
|
|
|
|
std::string keyName = symbol->getName().c_str();
|
|
|
|
keyName = glslangIntermediate->addCounterBufferName(keyName);
|
|
|
|
counterOriginator[keyName] = symbol;
|
|
|
|
} else {
|
|
|
|
// Handle a counter buffer, by finding the saved originating buffer.
|
|
|
|
std::string keyName = symbol->getName().c_str();
|
|
|
|
auto it = counterOriginator.find(keyName);
|
|
|
|
if (it != counterOriginator.end()) {
|
|
|
|
id = getSymbolId(it->second);
|
|
|
|
if (id != spv::NoResult) {
|
|
|
|
spv::Id counterId = getSymbolId(symbol);
|
2018-04-06 01:35:38 +00:00
|
|
|
if (counterId != spv::NoResult) {
|
|
|
|
builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
|
2018-03-08 01:05:55 +00:00
|
|
|
builder.addDecorationId(id, spv::DecorationHlslCounterBufferGOOGLE, counterId);
|
2018-04-06 01:35:38 +00:00
|
|
|
}
|
2018-03-08 01:05:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-09 05:29:20 +00:00
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)
|
|
|
|
{
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2017-06-01 00:50:53 +00:00
|
|
|
|
2016-04-04 02:20:42 +00:00
|
|
|
SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
|
|
|
|
if (node->getType().getQualifier().isSpecConstant())
|
|
|
|
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
// First, handle special cases
|
|
|
|
switch (node->getOp()) {
|
|
|
|
case glslang::EOpAssign:
|
|
|
|
case glslang::EOpAddAssign:
|
|
|
|
case glslang::EOpSubAssign:
|
|
|
|
case glslang::EOpMulAssign:
|
|
|
|
case glslang::EOpVectorTimesMatrixAssign:
|
|
|
|
case glslang::EOpVectorTimesScalarAssign:
|
|
|
|
case glslang::EOpMatrixTimesScalarAssign:
|
|
|
|
case glslang::EOpMatrixTimesMatrixAssign:
|
|
|
|
case glslang::EOpDivAssign:
|
|
|
|
case glslang::EOpModAssign:
|
|
|
|
case glslang::EOpAndAssign:
|
|
|
|
case glslang::EOpInclusiveOrAssign:
|
|
|
|
case glslang::EOpExclusiveOrAssign:
|
|
|
|
case glslang::EOpLeftShiftAssign:
|
|
|
|
case glslang::EOpRightShiftAssign:
|
|
|
|
// A bin-op assign "a += b" means the same thing as "a = a + b"
|
|
|
|
// where a is evaluated before b. For a simple assignment, GLSL
|
|
|
|
// says to evaluate the left before the right. So, always, left
|
|
|
|
// node then right node.
|
|
|
|
{
|
|
|
|
// get the left l-value, save it away
|
|
|
|
builder.clearAccessChain();
|
|
|
|
node->getLeft()->traverse(this);
|
|
|
|
spv::Builder::AccessChain lValue = builder.getAccessChain();
|
|
|
|
|
|
|
|
// evaluate the right
|
|
|
|
builder.clearAccessChain();
|
|
|
|
node->getRight()->traverse(this);
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Id rValue = accessChainLoad(node->getRight()->getType());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
if (node->getOp() != glslang::EOpAssign) {
|
|
|
|
// the left is also an r-value
|
|
|
|
builder.setAccessChain(lValue);
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Id leftRValue = accessChainLoad(node->getLeft()->getType());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
// do the operation
|
2018-03-29 00:01:20 +00:00
|
|
|
OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
|
2018-04-05 17:25:02 +00:00
|
|
|
TranslateNoContractionDecoration(node->getType().getQualifier()),
|
|
|
|
TranslateNonUniformDecoration(node->getType().getQualifier()) };
|
2018-03-29 00:01:20 +00:00
|
|
|
rValue = createBinaryOperation(node->getOp(), decorations,
|
2015-06-26 22:58:36 +00:00
|
|
|
convertGlslangToSpvType(node->getType()), leftRValue, rValue,
|
|
|
|
node->getType().getBasicType());
|
|
|
|
|
|
|
|
// these all need their counterparts in createBinaryOperation()
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(rValue != spv::NoResult);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// store the result
|
|
|
|
builder.setAccessChain(lValue);
|
2018-09-05 15:11:41 +00:00
|
|
|
multiTypeStore(node->getLeft()->getType(), rValue);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
// assignments are expressions having an rValue after they are evaluated...
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(rValue);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case glslang::EOpIndexDirect:
|
|
|
|
case glslang::EOpIndexDirectStruct:
|
|
|
|
{
|
2019-02-07 15:04:12 +00:00
|
|
|
// Structure, array, matrix, or vector indirection with statically known index.
|
2015-06-26 22:58:36 +00:00
|
|
|
// Get the left part of the access chain.
|
|
|
|
node->getLeft()->traverse(this);
|
|
|
|
|
|
|
|
// Add the next element in the chain
|
|
|
|
|
2016-06-08 13:11:40 +00:00
|
|
|
const int glslangIndex = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
2015-06-26 22:58:36 +00:00
|
|
|
if (! node->getLeft()->getType().isArray() &&
|
|
|
|
node->getLeft()->getType().isVector() &&
|
|
|
|
node->getOp() == glslang::EOpIndexDirect) {
|
|
|
|
// This is essentially a hard-coded vector swizzle of size 1,
|
|
|
|
// so short circuit the access-chain stuff with a swizzle.
|
|
|
|
std::vector<unsigned> swizzle;
|
2016-06-08 13:11:40 +00:00
|
|
|
swizzle.push_back(glslangIndex);
|
2019-01-06 23:58:04 +00:00
|
|
|
int dummySize;
|
|
|
|
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
|
|
|
|
TranslateCoherent(node->getLeft()->getType()),
|
|
|
|
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize));
|
2015-06-26 22:58:36 +00:00
|
|
|
} else {
|
2019-01-06 23:58:04 +00:00
|
|
|
|
|
|
|
// Load through a block reference is performed with a dot operator that
|
|
|
|
// is mapped to EOpIndexDirectStruct. When we get to the actual reference,
|
|
|
|
// do a load and reset the access chain.
|
2019-08-01 09:28:08 +00:00
|
|
|
if (node->getLeft()->isReference() &&
|
2019-01-06 23:58:04 +00:00
|
|
|
!node->getLeft()->getType().isArray() &&
|
|
|
|
node->getOp() == glslang::EOpIndexDirectStruct)
|
|
|
|
{
|
|
|
|
spv::Id left = accessChainLoad(node->getLeft()->getType());
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainLValue(left);
|
|
|
|
}
|
|
|
|
|
2016-06-08 13:11:40 +00:00
|
|
|
int spvIndex = glslangIndex;
|
|
|
|
if (node->getLeft()->getBasicType() == glslang::EbtBlock &&
|
|
|
|
node->getOp() == glslang::EOpIndexDirectStruct)
|
|
|
|
{
|
|
|
|
// This may be, e.g., an anonymous block-member selection, which generally need
|
|
|
|
// index remapping due to hidden members in anonymous blocks.
|
|
|
|
std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];
|
|
|
|
assert(remapper.size() > 0);
|
|
|
|
spvIndex = remapper[glslangIndex];
|
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
// normal case for indexing array or structure or block
|
2019-03-06 19:34:10 +00:00
|
|
|
builder.accessChainPush(builder.makeIntConstant(spvIndex), TranslateCoherent(node->getLeft()->getType()), node->getLeft()->getType().getBufferReferenceAlignment());
|
2016-05-17 01:22:05 +00:00
|
|
|
|
2016-06-08 13:11:40 +00:00
|
|
|
// Add capabilities here for accessing PointSize and clip/cull distance.
|
|
|
|
// We have deferred generation of associated capabilities until now.
|
2016-05-17 01:22:05 +00:00
|
|
|
if (node->getLeft()->getType().isStruct() && ! node->getLeft()->getType().isArray())
|
2016-06-08 13:11:40 +00:00
|
|
|
declareUseOfStructMember(*(node->getLeft()->getType().getStruct()), glslangIndex);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case glslang::EOpIndexIndirect:
|
|
|
|
{
|
2019-02-07 15:04:12 +00:00
|
|
|
// Array, matrix, or vector indirection with variable index.
|
|
|
|
// Will use native SPIR-V access-chain for and array indirection;
|
2015-06-26 22:58:36 +00:00
|
|
|
// matrices are arrays of vectors, so will also work for a matrix.
|
|
|
|
// Will use the access chain's 'component' for variable index into a vector.
|
|
|
|
|
|
|
|
// This adapter is building access chains left to right.
|
|
|
|
// Set up the access chain to the left.
|
|
|
|
node->getLeft()->traverse(this);
|
|
|
|
|
|
|
|
// save it so that computing the right side doesn't trash it
|
|
|
|
spv::Builder::AccessChain partial = builder.getAccessChain();
|
|
|
|
|
|
|
|
// compute the next index in the chain
|
|
|
|
builder.clearAccessChain();
|
|
|
|
node->getRight()->traverse(this);
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Id index = accessChainLoad(node->getRight()->getType());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2018-04-05 17:25:02 +00:00
|
|
|
addIndirectionIndexCapabilities(node->getLeft()->getType(), node->getRight()->getType());
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
// restore the saved access chain
|
|
|
|
builder.setAccessChain(partial);
|
|
|
|
|
2019-01-06 23:58:04 +00:00
|
|
|
if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector()) {
|
|
|
|
int dummySize;
|
|
|
|
builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()),
|
|
|
|
TranslateCoherent(node->getLeft()->getType()),
|
|
|
|
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize));
|
|
|
|
} else
|
2019-03-06 19:34:10 +00:00
|
|
|
builder.accessChainPush(index, TranslateCoherent(node->getLeft()->getType()), node->getLeft()->getType().getBufferReferenceAlignment());
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case glslang::EOpVectorSwizzle:
|
|
|
|
{
|
|
|
|
node->getLeft()->traverse(this);
|
|
|
|
std::vector<unsigned> swizzle;
|
2016-07-26 18:50:38 +00:00
|
|
|
convertSwizzle(*node->getRight()->getAsAggregate(), swizzle);
|
2019-01-06 23:58:04 +00:00
|
|
|
int dummySize;
|
|
|
|
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
|
|
|
|
TranslateCoherent(node->getLeft()->getType()),
|
|
|
|
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize));
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
return false;
|
2017-01-13 19:27:52 +00:00
|
|
|
case glslang::EOpMatrixSwizzle:
|
|
|
|
logger->missingFunctionality("matrix swizzle");
|
|
|
|
return true;
|
2015-10-15 19:29:11 +00:00
|
|
|
case glslang::EOpLogicalOr:
|
|
|
|
case glslang::EOpLogicalAnd:
|
|
|
|
{
|
|
|
|
|
|
|
|
// These may require short circuiting, but can sometimes be done as straight
|
|
|
|
// binary operations. The right operand must be short circuited if it has
|
|
|
|
// side effects, and should probably be if it is complex.
|
|
|
|
if (isTrivial(node->getRight()->getAsTyped()))
|
|
|
|
break; // handle below as a normal binary operation
|
|
|
|
// otherwise, we need to do dynamic short circuiting on the right operand
|
|
|
|
spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(), *node->getRight()->getAsTyped());
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(result);
|
|
|
|
}
|
|
|
|
return false;
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assume generic binary op...
|
|
|
|
|
2016-02-02 19:37:46 +00:00
|
|
|
// get right operand
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.clearAccessChain();
|
|
|
|
node->getLeft()->traverse(this);
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Id left = accessChainLoad(node->getLeft()->getType());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2016-02-02 19:37:46 +00:00
|
|
|
// get left operand
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.clearAccessChain();
|
|
|
|
node->getRight()->traverse(this);
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Id right = accessChainLoad(node->getRight()->getType());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2016-02-02 19:37:46 +00:00
|
|
|
// get result
|
2018-03-29 00:01:20 +00:00
|
|
|
OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
|
2018-04-05 17:25:02 +00:00
|
|
|
TranslateNoContractionDecoration(node->getType().getQualifier()),
|
|
|
|
TranslateNonUniformDecoration(node->getType().getQualifier()) };
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id result = createBinaryOperation(node->getOp(), decorations,
|
2016-02-02 19:37:46 +00:00
|
|
|
convertGlslangToSpvType(node->getType()), left, right,
|
|
|
|
node->getLeft()->getType().getBasicType());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2015-12-22 04:21:11 +00:00
|
|
|
builder.clearAccessChain();
|
2015-06-26 22:58:36 +00:00
|
|
|
if (! result) {
|
2016-05-04 19:55:59 +00:00
|
|
|
logger->missingFunctionality("unknown glslang binary operation");
|
2015-12-22 04:21:11 +00:00
|
|
|
return true; // pick up a child as the place-holder result
|
2015-06-26 22:58:36 +00:00
|
|
|
} else {
|
|
|
|
builder.setAccessChainRValue(result);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-17 14:38:35 +00:00
|
|
|
// Figure out what, if any, type changes are needed when accessing a specific built-in.
|
|
|
|
// Returns <the type SPIR-V requires for declarion, the type to translate to on use>.
|
|
|
|
// Also see comment for 'forceType', regarding tracking SPIR-V-required types.
|
|
|
|
std::pair<spv::Id, spv::Id> TGlslangToSpvTraverser::getForcedType(spv::BuiltIn builtIn,
|
|
|
|
const glslang::TType& glslangType)
|
|
|
|
{
|
|
|
|
switch(builtIn)
|
|
|
|
{
|
|
|
|
case spv::BuiltInSubgroupEqMask:
|
|
|
|
case spv::BuiltInSubgroupGeMask:
|
|
|
|
case spv::BuiltInSubgroupGtMask:
|
|
|
|
case spv::BuiltInSubgroupLeMask:
|
|
|
|
case spv::BuiltInSubgroupLtMask: {
|
|
|
|
// these require changing a 64-bit scaler -> a vector of 32-bit components
|
|
|
|
if (glslangType.isVector())
|
|
|
|
break;
|
|
|
|
std::pair<spv::Id, spv::Id> ret(builder.makeVectorType(builder.makeUintType(32), 4),
|
|
|
|
builder.makeUintType(64));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<spv::Id, spv::Id> ret(spv::NoType, spv::NoType);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For an object previously identified (see getForcedType() and forceType)
|
|
|
|
// as needing type translations, do the translation needed for a load, turning
|
|
|
|
// an L-value into in R-value.
|
|
|
|
spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object)
|
|
|
|
{
|
|
|
|
const auto forceIt = forceType.find(object);
|
|
|
|
if (forceIt == forceType.end())
|
|
|
|
return object;
|
|
|
|
|
|
|
|
spv::Id desiredTypeId = forceIt->second;
|
|
|
|
spv::Id objectTypeId = builder.getTypeId(object);
|
|
|
|
assert(builder.isPointerType(objectTypeId));
|
|
|
|
objectTypeId = builder.getContainedTypeId(objectTypeId);
|
|
|
|
if (builder.isVectorType(objectTypeId) &&
|
|
|
|
builder.getScalarTypeWidth(builder.getContainedTypeId(objectTypeId)) == 32) {
|
|
|
|
if (builder.getScalarTypeWidth(desiredTypeId) == 64) {
|
|
|
|
// handle 32-bit v.xy* -> 64-bit
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainLValue(object);
|
|
|
|
object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, objectTypeId);
|
|
|
|
std::vector<spv::Id> components;
|
|
|
|
components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 0));
|
|
|
|
components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 1));
|
|
|
|
|
|
|
|
spv::Id vecType = builder.makeVectorType(builder.getContainedTypeId(objectTypeId), 2);
|
|
|
|
return builder.createUnaryOp(spv::OpBitcast, desiredTypeId,
|
|
|
|
builder.createCompositeConstruct(vecType, components));
|
|
|
|
} else {
|
|
|
|
logger->missingFunctionality("forcing 32-bit vector type to non 64-bit scalar");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
logger->missingFunctionality("forcing non 32-bit vector type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)
|
|
|
|
{
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2017-06-01 00:50:53 +00:00
|
|
|
|
2016-04-04 02:20:42 +00:00
|
|
|
SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
|
|
|
|
if (node->getType().getQualifier().isSpecConstant())
|
|
|
|
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
|
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
spv::Id result = spv::NoResult;
|
|
|
|
|
|
|
|
// try texturing first
|
|
|
|
result = createImageTextureFunctionCall(node);
|
|
|
|
if (result != spv::NoResult) {
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(result);
|
|
|
|
|
|
|
|
return false; // done with this node
|
|
|
|
}
|
|
|
|
|
|
|
|
// Non-texturing.
|
2015-09-12 18:17:44 +00:00
|
|
|
|
|
|
|
if (node->getOp() == glslang::EOpArrayLength) {
|
|
|
|
// Quite special; won't want to evaluate the operand.
|
|
|
|
|
2018-04-05 17:25:02 +00:00
|
|
|
// Currently, the front-end does not allow .length() on an array until it is sized,
|
|
|
|
// except for the last block membeor of an SSBO.
|
|
|
|
// TODO: If this changes, link-time sized arrays might show up here, and need their
|
|
|
|
// size extracted.
|
|
|
|
|
2015-09-12 18:17:44 +00:00
|
|
|
// Normal .length() would have been constant folded by the front-end.
|
|
|
|
// So, this has to be block.lastMember.length().
|
2015-09-22 03:50:29 +00:00
|
|
|
// SPV wants "block" and member number as the operands, go get them.
|
2018-03-29 00:01:20 +00:00
|
|
|
|
2019-02-19 19:10:32 +00:00
|
|
|
spv::Id length;
|
|
|
|
if (node->getOperand()->getType().isCoopMat()) {
|
|
|
|
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
|
|
|
|
|
|
|
|
spv::Id typeId = convertGlslangToSpvType(node->getOperand()->getType());
|
|
|
|
assert(builder.isCooperativeMatrixType(typeId));
|
|
|
|
|
|
|
|
length = builder.createCooperativeMatrixLength(typeId);
|
|
|
|
} else {
|
|
|
|
glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft();
|
|
|
|
block->traverse(this);
|
|
|
|
unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()->getConstArray()[0].getUConst();
|
|
|
|
length = builder.createArrayLength(builder.accessChainGetLValue(), member);
|
|
|
|
}
|
2015-09-12 18:17:44 +00:00
|
|
|
|
2018-11-28 14:01:37 +00:00
|
|
|
// GLSL semantics say the result of .length() is an int, while SPIR-V says
|
|
|
|
// signedness must be 0. So, convert from SPIR-V unsigned back to GLSL's
|
|
|
|
// AST expectation of a signed result.
|
2019-02-19 19:10:32 +00:00
|
|
|
if (glslangIntermediate->getSource() == glslang::EShSourceGlsl) {
|
|
|
|
if (builder.isInSpecConstCodeGenMode()) {
|
|
|
|
length = builder.createBinOp(spv::OpIAdd, builder.makeIntType(32), length, builder.makeIntConstant(0));
|
|
|
|
} else {
|
|
|
|
length = builder.createUnaryOp(spv::OpBitcast, builder.makeIntType(32), length);
|
|
|
|
}
|
|
|
|
}
|
2018-11-28 14:01:37 +00:00
|
|
|
|
2015-09-12 18:17:44 +00:00
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(length);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
// Start by evaluating the operand
|
|
|
|
|
2016-07-26 18:50:38 +00:00
|
|
|
// Does it need a swizzle inversion? If so, evaluation is inverted;
|
|
|
|
// operate first on the swizzle base, then apply the swizzle.
|
|
|
|
spv::Id invertedType = spv::NoType;
|
|
|
|
auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? invertedType : convertGlslangToSpvType(node->getType()); };
|
|
|
|
if (node->getOp() == glslang::EOpInterpolateAtCentroid)
|
|
|
|
invertedType = getInvertedSwizzleType(*node->getOperand());
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.clearAccessChain();
|
2019-06-14 14:56:28 +00:00
|
|
|
TIntermNode *operandNode;
|
2016-07-26 18:50:38 +00:00
|
|
|
if (invertedType != spv::NoType)
|
2019-06-14 14:56:28 +00:00
|
|
|
operandNode = node->getOperand()->getAsBinaryNode()->getLeft();
|
2016-07-26 18:50:38 +00:00
|
|
|
else
|
2019-06-14 14:56:28 +00:00
|
|
|
operandNode = node->getOperand();
|
|
|
|
|
|
|
|
operandNode->traverse(this);
|
2015-09-14 02:38:56 +00:00
|
|
|
|
2015-09-09 08:42:49 +00:00
|
|
|
spv::Id operand = spv::NoResult;
|
|
|
|
|
2019-06-14 14:56:28 +00:00
|
|
|
spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
|
|
|
|
|
2019-08-09 09:49:15 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2015-09-09 08:42:49 +00:00
|
|
|
if (node->getOp() == glslang::EOpAtomicCounterIncrement ||
|
|
|
|
node->getOp() == glslang::EOpAtomicCounterDecrement ||
|
2015-12-08 09:12:09 +00:00
|
|
|
node->getOp() == glslang::EOpAtomicCounter ||
|
2019-06-14 14:56:28 +00:00
|
|
|
node->getOp() == glslang::EOpInterpolateAtCentroid) {
|
2015-09-09 08:42:49 +00:00
|
|
|
operand = builder.accessChainGetLValue(); // Special case l-value operands
|
2019-06-14 14:56:28 +00:00
|
|
|
lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
|
|
|
|
lvalueCoherentFlags |= TranslateCoherent(operandNode->getAsTyped()->getType());
|
|
|
|
} else
|
2019-08-09 09:49:15 +00:00
|
|
|
#endif
|
|
|
|
{
|
2016-02-02 19:37:46 +00:00
|
|
|
operand = accessChainLoad(node->getOperand()->getType());
|
2019-08-09 09:49:15 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2018-03-29 00:01:20 +00:00
|
|
|
OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
|
2018-04-05 17:25:02 +00:00
|
|
|
TranslateNoContractionDecoration(node->getType().getQualifier()),
|
|
|
|
TranslateNonUniformDecoration(node->getType().getQualifier()) };
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
// it could be a conversion
|
2015-08-19 19:34:18 +00:00
|
|
|
if (! result)
|
2018-03-29 00:01:20 +00:00
|
|
|
result = createConversion(node->getOp(), decorations, resultType(), operand, node->getOperand()->getBasicType());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
// if not, then possibly an operation
|
|
|
|
if (! result)
|
2019-06-14 14:56:28 +00:00
|
|
|
result = createUnaryOperation(node->getOp(), decorations, resultType(), operand, node->getOperand()->getBasicType(), lvalueCoherentFlags);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
if (result) {
|
2018-04-05 17:25:02 +00:00
|
|
|
if (invertedType) {
|
2018-03-29 00:01:20 +00:00
|
|
|
result = createInvertedSwizzle(decorations.precision, *node->getOperand(), result);
|
2019-08-11 13:41:45 +00:00
|
|
|
decorations.addNonUniform(builder, result);
|
2018-04-05 17:25:02 +00:00
|
|
|
}
|
2016-07-26 18:50:38 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(result);
|
|
|
|
|
|
|
|
return false; // done with this node
|
|
|
|
}
|
|
|
|
|
|
|
|
// it must be a special case, check...
|
|
|
|
switch (node->getOp()) {
|
|
|
|
case glslang::EOpPostIncrement:
|
|
|
|
case glslang::EOpPostDecrement:
|
|
|
|
case glslang::EOpPreIncrement:
|
|
|
|
case glslang::EOpPreDecrement:
|
|
|
|
{
|
|
|
|
// we need the integer value "1" or the floating point "1.0" to add/subtract
|
2016-04-22 08:51:45 +00:00
|
|
|
spv::Id one = 0;
|
|
|
|
if (node->getBasicType() == glslang::EbtFloat)
|
|
|
|
one = builder.makeFloatConstant(1.0F);
|
2019-08-08 16:35:51 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2016-07-29 08:13:04 +00:00
|
|
|
else if (node->getBasicType() == glslang::EbtDouble)
|
|
|
|
one = builder.makeDoubleConstant(1.0);
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
else if (node->getBasicType() == glslang::EbtFloat16)
|
|
|
|
one = builder.makeFloat16Constant(1.0F);
|
2018-03-06 23:12:04 +00:00
|
|
|
else if (node->getBasicType() == glslang::EbtInt8 || node->getBasicType() == glslang::EbtUint8)
|
|
|
|
one = builder.makeInt8Constant(1);
|
2017-03-24 05:41:14 +00:00
|
|
|
else if (node->getBasicType() == glslang::EbtInt16 || node->getBasicType() == glslang::EbtUint16)
|
|
|
|
one = builder.makeInt16Constant(1);
|
2018-03-06 23:12:04 +00:00
|
|
|
else if (node->getBasicType() == glslang::EbtInt64 || node->getBasicType() == glslang::EbtUint64)
|
|
|
|
one = builder.makeInt64Constant(1);
|
2019-08-08 16:35:51 +00:00
|
|
|
#endif
|
2016-04-22 08:51:45 +00:00
|
|
|
else
|
|
|
|
one = builder.makeIntConstant(1);
|
2015-06-26 22:58:36 +00:00
|
|
|
glslang::TOperator op;
|
|
|
|
if (node->getOp() == glslang::EOpPreIncrement ||
|
|
|
|
node->getOp() == glslang::EOpPostIncrement)
|
|
|
|
op = glslang::EOpAdd;
|
|
|
|
else
|
|
|
|
op = glslang::EOpSub;
|
|
|
|
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id result = createBinaryOperation(op, decorations,
|
2016-04-22 08:51:45 +00:00
|
|
|
convertGlslangToSpvType(node->getType()), operand, one,
|
|
|
|
node->getType().getBasicType());
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(result != spv::NoResult);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
// The result of operation is always stored, but conditionally the
|
|
|
|
// consumed result. The consumed result is always an r-value.
|
|
|
|
builder.accessChainStore(result);
|
|
|
|
builder.clearAccessChain();
|
|
|
|
if (node->getOp() == glslang::EOpPreIncrement ||
|
|
|
|
node->getOp() == glslang::EOpPreDecrement)
|
|
|
|
builder.setAccessChainRValue(result);
|
|
|
|
else
|
|
|
|
builder.setAccessChainRValue(operand);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
2019-08-09 05:29:20 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpEmitStreamVertex:
|
|
|
|
builder.createNoResultOp(spv::OpEmitStreamVertex, operand);
|
|
|
|
return false;
|
|
|
|
case glslang::EOpEndStreamPrimitive:
|
|
|
|
builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);
|
|
|
|
return false;
|
2019-08-09 05:29:20 +00:00
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
default:
|
2016-05-04 19:55:59 +00:00
|
|
|
logger->missingFunctionality("unknown glslang unary");
|
2015-12-22 04:21:11 +00:00
|
|
|
return true; // pick up operand as placeholder result
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-25 18:31:10 +00:00
|
|
|
// Construct a composite object, recursively copying members if their types don't match
|
|
|
|
spv::Id TGlslangToSpvTraverser::createCompositeConstruct(spv::Id resultTypeId, std::vector<spv::Id> constituents)
|
|
|
|
{
|
|
|
|
for (int c = 0; c < (int)constituents.size(); ++c) {
|
|
|
|
spv::Id& constituent = constituents[c];
|
|
|
|
spv::Id lType = builder.getContainedTypeId(resultTypeId, c);
|
|
|
|
spv::Id rType = builder.getTypeId(constituent);
|
|
|
|
if (lType != rType) {
|
|
|
|
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
|
|
|
|
constituent = builder.createUnaryOp(spv::OpCopyLogical, lType, constituent);
|
|
|
|
} else if (builder.isStructType(rType)) {
|
|
|
|
std::vector<spv::Id> rTypeConstituents;
|
|
|
|
int numrTypeConstituents = builder.getNumTypeConstituents(rType);
|
|
|
|
for (int i = 0; i < numrTypeConstituents; ++i) {
|
|
|
|
rTypeConstituents.push_back(builder.createCompositeExtract(constituent, builder.getContainedTypeId(rType, i), i));
|
|
|
|
}
|
|
|
|
constituents[c] = createCompositeConstruct(lType, rTypeConstituents);
|
|
|
|
} else {
|
|
|
|
assert(builder.isArrayType(rType));
|
|
|
|
std::vector<spv::Id> rTypeConstituents;
|
|
|
|
int numrTypeConstituents = builder.getNumTypeConstituents(rType);
|
|
|
|
|
|
|
|
spv::Id elementRType = builder.getContainedTypeId(rType);
|
|
|
|
for (int i = 0; i < numrTypeConstituents; ++i) {
|
|
|
|
rTypeConstituents.push_back(builder.createCompositeExtract(constituent, elementRType, i));
|
|
|
|
}
|
|
|
|
constituents[c] = createCompositeConstruct(lType, rTypeConstituents);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return builder.createCompositeConstruct(resultTypeId, constituents);
|
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)
|
|
|
|
{
|
2016-04-14 20:40:20 +00:00
|
|
|
SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
|
|
|
|
if (node->getType().getQualifier().isSpecConstant())
|
|
|
|
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
|
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
spv::Id result = spv::NoResult;
|
2016-07-26 18:50:38 +00:00
|
|
|
spv::Id invertedType = spv::NoType; // to use to override the natural type of the node
|
|
|
|
auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? invertedType : convertGlslangToSpvType(node->getType()); };
|
2015-08-19 19:34:18 +00:00
|
|
|
|
|
|
|
// try texturing
|
|
|
|
result = createImageTextureFunctionCall(node);
|
|
|
|
if (result != spv::NoResult) {
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(result);
|
|
|
|
|
|
|
|
return false;
|
2019-08-06 13:00:58 +00:00
|
|
|
}
|
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
else if (node->getOp() == glslang::EOpImageStore ||
|
2018-09-05 15:11:41 +00:00
|
|
|
node->getOp() == glslang::EOpImageStoreLod ||
|
|
|
|
node->getOp() == glslang::EOpImageAtomicStore) {
|
2015-09-09 08:42:49 +00:00
|
|
|
// "imageStore" is a special case, which has no result
|
|
|
|
return false;
|
|
|
|
}
|
2019-08-06 13:00:58 +00:00
|
|
|
#endif
|
2015-08-19 19:34:18 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
glslang::TOperator binOp = glslang::EOpNull;
|
|
|
|
bool reduceComparison = true;
|
|
|
|
bool isMatrix = false;
|
|
|
|
bool noReturnValue = false;
|
2015-07-23 16:22:48 +00:00
|
|
|
bool atomic = false;
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2019-06-14 14:56:28 +00:00
|
|
|
spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
assert(node->getOp());
|
|
|
|
|
2016-08-02 01:44:00 +00:00
|
|
|
spv::Decoration precision = TranslatePrecisionDecoration(node->getOperationPrecision());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
switch (node->getOp()) {
|
|
|
|
case glslang::EOpSequence:
|
|
|
|
{
|
|
|
|
if (preVisit)
|
|
|
|
++sequenceDepth;
|
|
|
|
else
|
|
|
|
--sequenceDepth;
|
|
|
|
|
|
|
|
if (sequenceDepth == 1) {
|
|
|
|
// If this is the parent node of all the functions, we want to see them
|
|
|
|
// early, so all call points have actual SPIR-V functions to reference.
|
|
|
|
// In all cases, still let the traverser visit the children for us.
|
|
|
|
makeFunctions(node->getAsAggregate()->getSequence());
|
|
|
|
|
2016-09-19 22:01:41 +00:00
|
|
|
// Also, we want all globals initializers to go into the beginning of the entry point, before
|
2015-06-26 22:58:36 +00:00
|
|
|
// anything else gets there, so visit out of order, doing them all now.
|
|
|
|
makeGlobalInitializers(node->getAsAggregate()->getSequence());
|
|
|
|
|
2016-12-09 04:01:59 +00:00
|
|
|
// Initializers are done, don't want to visit again, but functions and link objects need to be processed,
|
2015-06-26 22:58:36 +00:00
|
|
|
// so do them manually.
|
|
|
|
visitFunctions(node->getAsAggregate()->getSequence());
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case glslang::EOpLinkerObjects:
|
|
|
|
{
|
|
|
|
if (visit == glslang::EvPreVisit)
|
|
|
|
linkageOnly = true;
|
|
|
|
else
|
|
|
|
linkageOnly = false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case glslang::EOpComma:
|
|
|
|
{
|
|
|
|
// processing from left to right naturally leaves the right-most
|
|
|
|
// lying around in the access chain
|
|
|
|
glslang::TIntermSequence& glslangOperands = node->getSequence();
|
|
|
|
for (int i = 0; i < (int)glslangOperands.size(); ++i)
|
|
|
|
glslangOperands[i]->traverse(this);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
case glslang::EOpFunction:
|
|
|
|
if (visit == glslang::EvPreVisit) {
|
2016-09-19 22:01:41 +00:00
|
|
|
if (isShaderEntryPoint(node)) {
|
2016-11-26 20:31:47 +00:00
|
|
|
inEntryPoint = true;
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.setBuildPoint(shaderEntry->getLastBlock());
|
2016-10-06 18:59:51 +00:00
|
|
|
currentFunction = shaderEntry;
|
2015-06-26 22:58:36 +00:00
|
|
|
} else {
|
|
|
|
handleFunctionEntry(node);
|
|
|
|
}
|
|
|
|
} else {
|
2016-11-26 20:31:47 +00:00
|
|
|
if (inEntryPoint)
|
|
|
|
entryPointTerminated = true;
|
2015-09-15 02:58:02 +00:00
|
|
|
builder.leaveFunction();
|
2016-11-26 20:31:47 +00:00
|
|
|
inEntryPoint = false;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
case glslang::EOpParameters:
|
|
|
|
// Parameters will have been consumed by EOpFunction processing, but not
|
|
|
|
// the body, so we still visited the function node's children, making this
|
|
|
|
// child redundant.
|
|
|
|
return false;
|
|
|
|
case glslang::EOpFunctionCall:
|
|
|
|
{
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2015-06-26 22:58:36 +00:00
|
|
|
if (node->isUserDefined())
|
|
|
|
result = handleUserFunctionCall(node);
|
2017-01-06 19:34:14 +00:00
|
|
|
// assert(result); // this can happen for bad shaders because the call graph completeness checking is not yet done
|
2016-02-16 03:58:50 +00:00
|
|
|
if (result) {
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(result);
|
|
|
|
} else
|
2016-05-04 19:55:59 +00:00
|
|
|
logger->missingFunctionality("missing user function; linker needs to catch that");
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
case glslang::EOpConstructMat2x2:
|
|
|
|
case glslang::EOpConstructMat2x3:
|
|
|
|
case glslang::EOpConstructMat2x4:
|
|
|
|
case glslang::EOpConstructMat3x2:
|
|
|
|
case glslang::EOpConstructMat3x3:
|
|
|
|
case glslang::EOpConstructMat3x4:
|
|
|
|
case glslang::EOpConstructMat4x2:
|
|
|
|
case glslang::EOpConstructMat4x3:
|
|
|
|
case glslang::EOpConstructMat4x4:
|
|
|
|
case glslang::EOpConstructDMat2x2:
|
|
|
|
case glslang::EOpConstructDMat2x3:
|
|
|
|
case glslang::EOpConstructDMat2x4:
|
|
|
|
case glslang::EOpConstructDMat3x2:
|
|
|
|
case glslang::EOpConstructDMat3x3:
|
|
|
|
case glslang::EOpConstructDMat3x4:
|
|
|
|
case glslang::EOpConstructDMat4x2:
|
|
|
|
case glslang::EOpConstructDMat4x3:
|
|
|
|
case glslang::EOpConstructDMat4x4:
|
2017-05-21 03:40:27 +00:00
|
|
|
case glslang::EOpConstructIMat2x2:
|
|
|
|
case glslang::EOpConstructIMat2x3:
|
|
|
|
case glslang::EOpConstructIMat2x4:
|
|
|
|
case glslang::EOpConstructIMat3x2:
|
|
|
|
case glslang::EOpConstructIMat3x3:
|
|
|
|
case glslang::EOpConstructIMat3x4:
|
|
|
|
case glslang::EOpConstructIMat4x2:
|
|
|
|
case glslang::EOpConstructIMat4x3:
|
|
|
|
case glslang::EOpConstructIMat4x4:
|
|
|
|
case glslang::EOpConstructUMat2x2:
|
|
|
|
case glslang::EOpConstructUMat2x3:
|
|
|
|
case glslang::EOpConstructUMat2x4:
|
|
|
|
case glslang::EOpConstructUMat3x2:
|
|
|
|
case glslang::EOpConstructUMat3x3:
|
|
|
|
case glslang::EOpConstructUMat3x4:
|
|
|
|
case glslang::EOpConstructUMat4x2:
|
|
|
|
case glslang::EOpConstructUMat4x3:
|
|
|
|
case glslang::EOpConstructUMat4x4:
|
|
|
|
case glslang::EOpConstructBMat2x2:
|
|
|
|
case glslang::EOpConstructBMat2x3:
|
|
|
|
case glslang::EOpConstructBMat2x4:
|
|
|
|
case glslang::EOpConstructBMat3x2:
|
|
|
|
case glslang::EOpConstructBMat3x3:
|
|
|
|
case glslang::EOpConstructBMat3x4:
|
|
|
|
case glslang::EOpConstructBMat4x2:
|
|
|
|
case glslang::EOpConstructBMat4x3:
|
|
|
|
case glslang::EOpConstructBMat4x4:
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
case glslang::EOpConstructF16Mat2x2:
|
|
|
|
case glslang::EOpConstructF16Mat2x3:
|
|
|
|
case glslang::EOpConstructF16Mat2x4:
|
|
|
|
case glslang::EOpConstructF16Mat3x2:
|
|
|
|
case glslang::EOpConstructF16Mat3x3:
|
|
|
|
case glslang::EOpConstructF16Mat3x4:
|
|
|
|
case glslang::EOpConstructF16Mat4x2:
|
|
|
|
case glslang::EOpConstructF16Mat4x3:
|
|
|
|
case glslang::EOpConstructF16Mat4x4:
|
2015-06-26 22:58:36 +00:00
|
|
|
isMatrix = true;
|
|
|
|
// fall through
|
|
|
|
case glslang::EOpConstructFloat:
|
|
|
|
case glslang::EOpConstructVec2:
|
|
|
|
case glslang::EOpConstructVec3:
|
|
|
|
case glslang::EOpConstructVec4:
|
|
|
|
case glslang::EOpConstructDouble:
|
|
|
|
case glslang::EOpConstructDVec2:
|
|
|
|
case glslang::EOpConstructDVec3:
|
|
|
|
case glslang::EOpConstructDVec4:
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
case glslang::EOpConstructFloat16:
|
|
|
|
case glslang::EOpConstructF16Vec2:
|
|
|
|
case glslang::EOpConstructF16Vec3:
|
|
|
|
case glslang::EOpConstructF16Vec4:
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpConstructBool:
|
|
|
|
case glslang::EOpConstructBVec2:
|
|
|
|
case glslang::EOpConstructBVec3:
|
|
|
|
case glslang::EOpConstructBVec4:
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConstructInt8:
|
|
|
|
case glslang::EOpConstructI8Vec2:
|
|
|
|
case glslang::EOpConstructI8Vec3:
|
|
|
|
case glslang::EOpConstructI8Vec4:
|
|
|
|
case glslang::EOpConstructUint8:
|
|
|
|
case glslang::EOpConstructU8Vec2:
|
|
|
|
case glslang::EOpConstructU8Vec3:
|
|
|
|
case glslang::EOpConstructU8Vec4:
|
|
|
|
case glslang::EOpConstructInt16:
|
|
|
|
case glslang::EOpConstructI16Vec2:
|
|
|
|
case glslang::EOpConstructI16Vec3:
|
|
|
|
case glslang::EOpConstructI16Vec4:
|
|
|
|
case glslang::EOpConstructUint16:
|
|
|
|
case glslang::EOpConstructU16Vec2:
|
|
|
|
case glslang::EOpConstructU16Vec3:
|
|
|
|
case glslang::EOpConstructU16Vec4:
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpConstructInt:
|
|
|
|
case glslang::EOpConstructIVec2:
|
|
|
|
case glslang::EOpConstructIVec3:
|
|
|
|
case glslang::EOpConstructIVec4:
|
|
|
|
case glslang::EOpConstructUint:
|
|
|
|
case glslang::EOpConstructUVec2:
|
|
|
|
case glslang::EOpConstructUVec3:
|
|
|
|
case glslang::EOpConstructUVec4:
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EOpConstructInt64:
|
|
|
|
case glslang::EOpConstructI64Vec2:
|
|
|
|
case glslang::EOpConstructI64Vec3:
|
|
|
|
case glslang::EOpConstructI64Vec4:
|
|
|
|
case glslang::EOpConstructUint64:
|
|
|
|
case glslang::EOpConstructU64Vec2:
|
|
|
|
case glslang::EOpConstructU64Vec3:
|
|
|
|
case glslang::EOpConstructU64Vec4:
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpConstructStruct:
|
2016-02-16 03:58:50 +00:00
|
|
|
case glslang::EOpConstructTextureSampler:
|
2019-01-06 23:58:04 +00:00
|
|
|
case glslang::EOpConstructReference:
|
2019-02-19 19:10:32 +00:00
|
|
|
case glslang::EOpConstructCooperativeMatrix:
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2015-06-26 22:58:36 +00:00
|
|
|
std::vector<spv::Id> arguments;
|
2019-06-14 14:56:28 +00:00
|
|
|
translateArguments(*node, arguments, lvalueCoherentFlags);
|
2015-06-26 22:58:36 +00:00
|
|
|
spv::Id constructed;
|
2016-02-16 03:58:50 +00:00
|
|
|
if (node->getOp() == glslang::EOpConstructTextureSampler)
|
2016-07-26 18:50:38 +00:00
|
|
|
constructed = builder.createOp(spv::OpSampledImage, resultType(), arguments);
|
2019-02-19 19:10:32 +00:00
|
|
|
else if (node->getOp() == glslang::EOpConstructStruct ||
|
|
|
|
node->getOp() == glslang::EOpConstructCooperativeMatrix ||
|
|
|
|
node->getType().isArray()) {
|
2015-06-26 22:58:36 +00:00
|
|
|
std::vector<spv::Id> constituents;
|
|
|
|
for (int c = 0; c < (int)arguments.size(); ++c)
|
|
|
|
constituents.push_back(arguments[c]);
|
2019-06-25 18:31:10 +00:00
|
|
|
constructed = createCompositeConstruct(resultType(), constituents);
|
2015-11-16 04:33:39 +00:00
|
|
|
} else if (isMatrix)
|
2016-07-26 18:50:38 +00:00
|
|
|
constructed = builder.createMatrixConstructor(precision, arguments, resultType());
|
2015-11-16 04:33:39 +00:00
|
|
|
else
|
2016-07-26 18:50:38 +00:00
|
|
|
constructed = builder.createConstructor(precision, arguments, resultType());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(constructed);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// These six are component-wise compares with component-wise results.
|
|
|
|
// Forward on to createBinaryOperation(), requesting a vector result.
|
|
|
|
case glslang::EOpLessThan:
|
|
|
|
case glslang::EOpGreaterThan:
|
|
|
|
case glslang::EOpLessThanEqual:
|
|
|
|
case glslang::EOpGreaterThanEqual:
|
|
|
|
case glslang::EOpVectorEqual:
|
|
|
|
case glslang::EOpVectorNotEqual:
|
|
|
|
{
|
|
|
|
// Map the operation to a binary
|
|
|
|
binOp = node->getOp();
|
|
|
|
reduceComparison = false;
|
|
|
|
switch (node->getOp()) {
|
|
|
|
case glslang::EOpVectorEqual: binOp = glslang::EOpVectorEqual; break;
|
|
|
|
case glslang::EOpVectorNotEqual: binOp = glslang::EOpVectorNotEqual; break;
|
|
|
|
default: binOp = node->getOp(); break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case glslang::EOpMul:
|
2016-07-26 18:50:38 +00:00
|
|
|
// component-wise matrix multiply
|
2015-06-26 22:58:36 +00:00
|
|
|
binOp = glslang::EOpMul;
|
|
|
|
break;
|
|
|
|
case glslang::EOpOuterProduct:
|
|
|
|
// two vectors multiplied to make a matrix
|
|
|
|
binOp = glslang::EOpOuterProduct;
|
|
|
|
break;
|
|
|
|
case glslang::EOpDot:
|
|
|
|
{
|
2016-05-06 21:25:16 +00:00
|
|
|
// for scalar dot product, use multiply
|
2015-06-26 22:58:36 +00:00
|
|
|
glslang::TIntermSequence& glslangOperands = node->getSequence();
|
2016-05-20 18:06:03 +00:00
|
|
|
if (glslangOperands[0]->getAsTyped()->getVectorSize() == 1)
|
2015-06-26 22:58:36 +00:00
|
|
|
binOp = glslang::EOpMul;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case glslang::EOpMod:
|
|
|
|
// when an aggregate, this is the floating-point mod built-in function,
|
|
|
|
// which can be emitted by the one in createBinaryOperation()
|
|
|
|
binOp = glslang::EOpMod;
|
|
|
|
break;
|
2019-08-06 13:00:58 +00:00
|
|
|
|
|
|
|
#ifndef GLSLANG_WEB
|
2015-06-26 22:58:36 +00:00
|
|
|
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:
|
2017-12-13 05:50:53 +00:00
|
|
|
case glslang::EOpDeviceMemoryBarrier:
|
2016-06-15 15:50:24 +00:00
|
|
|
case glslang::EOpAllMemoryBarrierWithGroupSync:
|
2017-12-13 05:50:53 +00:00
|
|
|
case glslang::EOpDeviceMemoryBarrierWithGroupSync:
|
2016-06-15 15:50:24 +00:00
|
|
|
case glslang::EOpWorkgroupMemoryBarrier:
|
|
|
|
case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpSubgroupBarrier:
|
|
|
|
case glslang::EOpSubgroupMemoryBarrier:
|
|
|
|
case glslang::EOpSubgroupMemoryBarrierBuffer:
|
|
|
|
case glslang::EOpSubgroupMemoryBarrierImage:
|
|
|
|
case glslang::EOpSubgroupMemoryBarrierShared:
|
2015-06-26 22:58:36 +00:00
|
|
|
noReturnValue = true;
|
|
|
|
// These all have 0 operands and will naturally finish up in the code below for 0 operands
|
|
|
|
break;
|
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
case glslang::EOpAtomicStore:
|
|
|
|
noReturnValue = true;
|
|
|
|
// fallthrough
|
|
|
|
case glslang::EOpAtomicLoad:
|
2015-07-23 16:22:48 +00:00
|
|
|
case glslang::EOpAtomicAdd:
|
|
|
|
case glslang::EOpAtomicMin:
|
|
|
|
case glslang::EOpAtomicMax:
|
|
|
|
case glslang::EOpAtomicAnd:
|
|
|
|
case glslang::EOpAtomicOr:
|
|
|
|
case glslang::EOpAtomicXor:
|
|
|
|
case glslang::EOpAtomicExchange:
|
|
|
|
case glslang::EOpAtomicCompSwap:
|
|
|
|
atomic = true;
|
|
|
|
break;
|
|
|
|
|
2017-07-23 22:08:26 +00:00
|
|
|
case glslang::EOpAtomicCounterAdd:
|
|
|
|
case glslang::EOpAtomicCounterSubtract:
|
|
|
|
case glslang::EOpAtomicCounterMin:
|
|
|
|
case glslang::EOpAtomicCounterMax:
|
|
|
|
case glslang::EOpAtomicCounterAnd:
|
|
|
|
case glslang::EOpAtomicCounterOr:
|
|
|
|
case glslang::EOpAtomicCounterXor:
|
|
|
|
case glslang::EOpAtomicCounterExchange:
|
|
|
|
case glslang::EOpAtomicCounterCompSwap:
|
|
|
|
builder.addExtension("SPV_KHR_shader_atomic_counter_ops");
|
|
|
|
builder.addCapability(spv::CapabilityAtomicStorageOps);
|
|
|
|
atomic = true;
|
|
|
|
break;
|
|
|
|
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EOpIgnoreIntersectionNV:
|
|
|
|
case glslang::EOpTerminateRayNV:
|
|
|
|
case glslang::EOpTraceNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
case glslang::EOpExecuteCallableNV:
|
2018-09-19 18:41:59 +00:00
|
|
|
case glslang::EOpWritePackedPrimitiveIndices4x8NV:
|
|
|
|
noReturnValue = true;
|
|
|
|
break;
|
2019-02-19 19:10:32 +00:00
|
|
|
case glslang::EOpCooperativeMatrixLoad:
|
|
|
|
case glslang::EOpCooperativeMatrixStore:
|
|
|
|
noReturnValue = true;
|
|
|
|
break;
|
2019-06-03 16:33:50 +00:00
|
|
|
case glslang::EOpBeginInvocationInterlock:
|
|
|
|
case glslang::EOpEndInvocationInterlock:
|
|
|
|
builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock);
|
|
|
|
noReturnValue = true;
|
|
|
|
break;
|
2019-08-06 13:00:58 +00:00
|
|
|
#endif
|
2018-09-19 18:41:59 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// See if it maps to a regular operation.
|
|
|
|
//
|
|
|
|
if (binOp != glslang::EOpNull) {
|
|
|
|
glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
|
|
|
|
glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
|
|
|
|
assert(left && right);
|
|
|
|
|
|
|
|
builder.clearAccessChain();
|
|
|
|
left->traverse(this);
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Id leftId = accessChainLoad(left->getType());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
builder.clearAccessChain();
|
|
|
|
right->traverse(this);
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Id rightId = accessChainLoad(right->getType());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2018-03-29 00:01:20 +00:00
|
|
|
OpDecorations decorations = { precision,
|
2018-04-05 17:25:02 +00:00
|
|
|
TranslateNoContractionDecoration(node->getType().getQualifier()),
|
|
|
|
TranslateNonUniformDecoration(node->getType().getQualifier()) };
|
2018-03-29 00:01:20 +00:00
|
|
|
result = createBinaryOperation(binOp, decorations,
|
2016-07-26 18:50:38 +00:00
|
|
|
resultType(), leftId, rightId,
|
2015-06-26 22:58:36 +00:00
|
|
|
left->getType().getBasicType(), reduceComparison);
|
|
|
|
|
|
|
|
// code above should only make binOp that exists in createBinaryOperation
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(result != spv::NoResult);
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(result);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-23 16:22:48 +00:00
|
|
|
//
|
|
|
|
// Create the list of operands.
|
|
|
|
//
|
2015-06-26 22:58:36 +00:00
|
|
|
glslang::TIntermSequence& glslangOperands = node->getSequence();
|
|
|
|
std::vector<spv::Id> operands;
|
2019-02-19 19:10:32 +00:00
|
|
|
std::vector<spv::IdImmediate> memoryAccessOperands;
|
2015-06-26 22:58:36 +00:00
|
|
|
for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
|
|
|
|
// special case l-value operands; there are just a few
|
|
|
|
bool lvalue = false;
|
|
|
|
switch (node->getOp()) {
|
|
|
|
case glslang::EOpModf:
|
|
|
|
if (arg == 1)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
case glslang::EOpFrexp:
|
|
|
|
if (arg == 1)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2015-12-08 09:12:09 +00:00
|
|
|
case glslang::EOpInterpolateAtSample:
|
|
|
|
case glslang::EOpInterpolateAtOffset:
|
2016-05-05 04:30:44 +00:00
|
|
|
case glslang::EOpInterpolateAtVertex:
|
2016-07-26 18:50:38 +00:00
|
|
|
if (arg == 0) {
|
2015-12-08 09:12:09 +00:00
|
|
|
lvalue = true;
|
2016-07-26 18:50:38 +00:00
|
|
|
|
|
|
|
// Does it need a swizzle inversion? If so, evaluation is inverted;
|
|
|
|
// operate first on the swizzle base, then apply the swizzle.
|
2017-01-06 07:34:48 +00:00
|
|
|
if (glslangOperands[0]->getAsOperator() &&
|
2016-07-26 18:50:38 +00:00
|
|
|
glslangOperands[0]->getAsOperator()->getOp() == glslang::EOpVectorSwizzle)
|
|
|
|
invertedType = convertGlslangToSpvType(glslangOperands[0]->getAsBinaryNode()->getLeft()->getType());
|
|
|
|
}
|
2015-12-08 09:12:09 +00:00
|
|
|
break;
|
2015-09-06 08:30:11 +00:00
|
|
|
case glslang::EOpAtomicAdd:
|
|
|
|
case glslang::EOpAtomicMin:
|
|
|
|
case glslang::EOpAtomicMax:
|
|
|
|
case glslang::EOpAtomicAnd:
|
|
|
|
case glslang::EOpAtomicOr:
|
|
|
|
case glslang::EOpAtomicXor:
|
|
|
|
case glslang::EOpAtomicExchange:
|
|
|
|
case glslang::EOpAtomicCompSwap:
|
2018-09-05 15:11:41 +00:00
|
|
|
case glslang::EOpAtomicLoad:
|
|
|
|
case glslang::EOpAtomicStore:
|
2017-07-23 22:08:26 +00:00
|
|
|
case glslang::EOpAtomicCounterAdd:
|
|
|
|
case glslang::EOpAtomicCounterSubtract:
|
|
|
|
case glslang::EOpAtomicCounterMin:
|
|
|
|
case glslang::EOpAtomicCounterMax:
|
|
|
|
case glslang::EOpAtomicCounterAnd:
|
|
|
|
case glslang::EOpAtomicCounterOr:
|
|
|
|
case glslang::EOpAtomicCounterXor:
|
|
|
|
case glslang::EOpAtomicCounterExchange:
|
|
|
|
case glslang::EOpAtomicCounterCompSwap:
|
2015-09-06 08:30:11 +00:00
|
|
|
if (arg == 0)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2015-11-16 04:33:39 +00:00
|
|
|
case glslang::EOpAddCarry:
|
|
|
|
case glslang::EOpSubBorrow:
|
|
|
|
if (arg == 2)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpUMulExtended:
|
|
|
|
case glslang::EOpIMulExtended:
|
|
|
|
if (arg >= 2)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2019-02-19 19:10:32 +00:00
|
|
|
case glslang::EOpCooperativeMatrixLoad:
|
|
|
|
if (arg == 0 || arg == 1)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpCooperativeMatrixStore:
|
|
|
|
if (arg == 1)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2019-08-06 13:00:58 +00:00
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-07-26 18:50:38 +00:00
|
|
|
builder.clearAccessChain();
|
|
|
|
if (invertedType != spv::NoType && arg == 0)
|
|
|
|
glslangOperands[0]->getAsBinaryNode()->getLeft()->traverse(this);
|
|
|
|
else
|
|
|
|
glslangOperands[arg]->traverse(this);
|
2019-02-19 19:10:32 +00:00
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2019-02-19 19:10:32 +00:00
|
|
|
if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||
|
|
|
|
node->getOp() == glslang::EOpCooperativeMatrixStore) {
|
|
|
|
|
|
|
|
if (arg == 1) {
|
|
|
|
// fold "element" parameter into the access chain
|
|
|
|
spv::Builder::AccessChain save = builder.getAccessChain();
|
|
|
|
builder.clearAccessChain();
|
|
|
|
glslangOperands[2]->traverse(this);
|
|
|
|
|
|
|
|
spv::Id elementId = accessChainLoad(glslangOperands[2]->getAsTyped()->getType());
|
|
|
|
|
|
|
|
builder.setAccessChain(save);
|
|
|
|
|
|
|
|
// Point to the first element of the array.
|
|
|
|
builder.accessChainPush(elementId, TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType()),
|
2019-03-06 19:34:10 +00:00
|
|
|
glslangOperands[arg]->getAsTyped()->getType().getBufferReferenceAlignment());
|
2019-02-19 19:10:32 +00:00
|
|
|
|
|
|
|
spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
|
|
|
|
unsigned int alignment = builder.getAccessChain().alignment;
|
|
|
|
|
|
|
|
int memoryAccess = TranslateMemoryAccess(coherentFlags);
|
|
|
|
if (node->getOp() == glslang::EOpCooperativeMatrixLoad)
|
|
|
|
memoryAccess &= ~spv::MemoryAccessMakePointerAvailableKHRMask;
|
|
|
|
if (node->getOp() == glslang::EOpCooperativeMatrixStore)
|
|
|
|
memoryAccess &= ~spv::MemoryAccessMakePointerVisibleKHRMask;
|
|
|
|
if (builder.getStorageClass(builder.getAccessChain().base) == spv::StorageClassPhysicalStorageBufferEXT) {
|
|
|
|
memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
memoryAccessOperands.push_back(spv::IdImmediate(false, memoryAccess));
|
|
|
|
|
|
|
|
if (memoryAccess & spv::MemoryAccessAlignedMask) {
|
|
|
|
memoryAccessOperands.push_back(spv::IdImmediate(false, alignment));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memoryAccess & (spv::MemoryAccessMakePointerAvailableKHRMask | spv::MemoryAccessMakePointerVisibleKHRMask)) {
|
|
|
|
memoryAccessOperands.push_back(spv::IdImmediate(true, builder.makeUintConstant(TranslateMemoryScope(coherentFlags))));
|
|
|
|
}
|
|
|
|
} else if (arg == 2) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2019-02-19 19:10:32 +00:00
|
|
|
|
2019-06-14 14:56:28 +00:00
|
|
|
if (lvalue) {
|
2015-06-26 22:58:36 +00:00
|
|
|
operands.push_back(builder.accessChainGetLValue());
|
2019-06-14 14:56:28 +00:00
|
|
|
lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
|
|
|
|
lvalueCoherentFlags |= TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType());
|
|
|
|
} else {
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2016-02-02 19:37:46 +00:00
|
|
|
operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType()));
|
2017-06-01 00:50:53 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
2015-07-23 16:22:48 +00:00
|
|
|
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2019-02-19 19:10:32 +00:00
|
|
|
if (node->getOp() == glslang::EOpCooperativeMatrixLoad) {
|
|
|
|
std::vector<spv::IdImmediate> idImmOps;
|
|
|
|
|
|
|
|
idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
|
|
|
|
idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
|
|
|
|
idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor
|
|
|
|
idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());
|
|
|
|
// get the pointee type
|
|
|
|
spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
|
|
|
|
assert(builder.isCooperativeMatrixType(typeId));
|
|
|
|
// do the op
|
|
|
|
spv::Id result = builder.createOp(spv::OpCooperativeMatrixLoadNV, typeId, idImmOps);
|
|
|
|
// store the result to the pointer (out param 'm')
|
|
|
|
builder.createStore(result, operands[0]);
|
|
|
|
result = 0;
|
|
|
|
} else if (node->getOp() == glslang::EOpCooperativeMatrixStore) {
|
|
|
|
std::vector<spv::IdImmediate> idImmOps;
|
|
|
|
|
|
|
|
idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
|
|
|
|
idImmOps.push_back(spv::IdImmediate(true, operands[0])); // object
|
|
|
|
idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
|
|
|
|
idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor
|
|
|
|
idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());
|
|
|
|
|
|
|
|
builder.createNoResultOp(spv::OpCooperativeMatrixStoreNV, idImmOps);
|
|
|
|
result = 0;
|
|
|
|
} else if (atomic) {
|
2015-07-23 16:22:48 +00:00
|
|
|
// Handle all atomics
|
2019-06-14 14:56:28 +00:00
|
|
|
result = createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType(), lvalueCoherentFlags);
|
2019-08-11 13:41:45 +00:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2015-07-23 16:22:48 +00:00
|
|
|
// Pass through to generic operations.
|
|
|
|
switch (glslangOperands.size()) {
|
|
|
|
case 0:
|
2016-07-26 18:50:38 +00:00
|
|
|
result = createNoArgOperation(node->getOp(), precision, resultType());
|
2015-07-23 16:22:48 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
2018-03-29 00:01:20 +00:00
|
|
|
{
|
|
|
|
OpDecorations decorations = { precision,
|
2018-04-05 17:25:02 +00:00
|
|
|
TranslateNoContractionDecoration(node->getType().getQualifier()),
|
|
|
|
TranslateNonUniformDecoration(node->getType().getQualifier()) };
|
2018-03-29 00:01:20 +00:00
|
|
|
result = createUnaryOperation(
|
|
|
|
node->getOp(), decorations,
|
|
|
|
resultType(), operands.front(),
|
2019-06-14 14:56:28 +00:00
|
|
|
glslangOperands[0]->getAsTyped()->getBasicType(), lvalueCoherentFlags);
|
2018-03-29 00:01:20 +00:00
|
|
|
}
|
2015-07-23 16:22:48 +00:00
|
|
|
break;
|
|
|
|
default:
|
2016-07-26 18:50:38 +00:00
|
|
|
result = createMiscOperation(node->getOp(), precision, resultType(), operands, node->getBasicType());
|
2015-07-23 16:22:48 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-07-26 18:50:38 +00:00
|
|
|
if (invertedType)
|
|
|
|
result = createInvertedSwizzle(precision, *glslangOperands[0]->getAsBinaryNode(), result);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (noReturnValue)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (! result) {
|
2016-05-04 19:55:59 +00:00
|
|
|
logger->missingFunctionality("unknown glslang aggregate");
|
2015-12-22 04:21:11 +00:00
|
|
|
return true; // pick up a child as a placeholder operand
|
2015-06-26 22:58:36 +00:00
|
|
|
} else {
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(result);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-27 03:31:11 +00:00
|
|
|
// This path handles both if-then-else and ?:
|
|
|
|
// The if-then-else has a node type of void, while
|
|
|
|
// ?: has either a void or a non-void node type
|
|
|
|
//
|
|
|
|
// Leaving the result, when not void:
|
|
|
|
// 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
|
2015-06-26 22:58:36 +00:00
|
|
|
bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)
|
|
|
|
{
|
2019-01-10 11:23:06 +00:00
|
|
|
// see if OpSelect can handle it
|
|
|
|
const auto isOpSelectable = [&]() {
|
|
|
|
if (node->getBasicType() == glslang::EbtVoid)
|
|
|
|
return false;
|
|
|
|
// OpSelect can do all other types starting with SPV 1.4
|
|
|
|
if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4) {
|
|
|
|
// pre-1.4, only scalars and vectors can be handled
|
|
|
|
if ((!node->getType().isScalar() && !node->getType().isVector()))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// See if it simple and safe, or required, to execute both sides.
|
|
|
|
// Crucially, side effects must be either semantically required or avoided,
|
|
|
|
// and there are performance trade-offs.
|
|
|
|
// Return true if required or a good idea (and safe) to execute both sides,
|
|
|
|
// false otherwise.
|
|
|
|
const auto bothSidesPolicy = [&]() -> bool {
|
|
|
|
// do we have both sides?
|
2017-01-27 03:31:11 +00:00
|
|
|
if (node->getTrueBlock() == nullptr ||
|
|
|
|
node->getFalseBlock() == nullptr)
|
|
|
|
return false;
|
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// required? (unless we write additional code to look for side effects
|
|
|
|
// and make performance trade-offs if none are present)
|
|
|
|
if (!node->getShortCircuit())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// if not required to execute both, decide based on performance/practicality...
|
|
|
|
|
2019-01-10 11:23:06 +00:00
|
|
|
if (!isOpSelectable())
|
2018-02-21 04:29:05 +00:00
|
|
|
return false;
|
|
|
|
|
2017-01-27 03:31:11 +00:00
|
|
|
assert(node->getType() == node->getTrueBlock() ->getAsTyped()->getType() &&
|
|
|
|
node->getType() == node->getFalseBlock()->getAsTyped()->getType());
|
|
|
|
|
|
|
|
// return true if a single operand to ? : is okay for OpSelect
|
|
|
|
const auto operandOkay = [](glslang::TIntermTyped* node) {
|
2017-01-29 02:29:42 +00:00
|
|
|
return node->getAsSymbolNode() || node->getType().getQualifier().isConstant();
|
2017-01-27 03:31:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
return operandOkay(node->getTrueBlock() ->getAsTyped()) &&
|
|
|
|
operandOkay(node->getFalseBlock()->getAsTyped());
|
|
|
|
};
|
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
spv::Id result = spv::NoResult; // upcoming result selecting between trueValue and falseValue
|
|
|
|
// emit the condition before doing anything with selection
|
|
|
|
node->getCondition()->traverse(this);
|
|
|
|
spv::Id condition = accessChainLoad(node->getCondition()->getType());
|
|
|
|
|
|
|
|
// Find a way of executing both sides and selecting the right result.
|
|
|
|
const auto executeBothSides = [&]() -> void {
|
|
|
|
// execute both sides
|
2017-01-27 03:31:11 +00:00
|
|
|
node->getTrueBlock()->traverse(this);
|
|
|
|
spv::Id trueValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
|
|
|
|
node->getFalseBlock()->traverse(this);
|
|
|
|
spv::Id falseValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
|
|
|
|
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2017-06-01 00:50:53 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// done if void
|
|
|
|
if (node->getBasicType() == glslang::EbtVoid)
|
|
|
|
return;
|
2017-03-30 16:09:28 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// emit code to select between trueValue and falseValue
|
2017-01-27 03:31:11 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// see if OpSelect can handle it
|
2019-01-10 11:23:06 +00:00
|
|
|
if (isOpSelectable()) {
|
2018-02-21 04:29:05 +00:00
|
|
|
// Emit OpSelect for this selection.
|
2017-01-27 03:31:11 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// smear condition to vector, if necessary (AST is always scalar)
|
2019-01-10 11:23:06 +00:00
|
|
|
// Before 1.4, smear like for mix(), starting with 1.4, keep it scalar
|
|
|
|
if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4 && builder.isVector(trueValue)) {
|
2018-02-21 04:29:05 +00:00
|
|
|
condition = builder.smearScalar(spv::NoPrecision, condition,
|
|
|
|
builder.makeVectorType(builder.makeBoolType(),
|
|
|
|
builder.getNumComponents(trueValue)));
|
2019-01-10 11:23:06 +00:00
|
|
|
}
|
2017-01-29 02:29:42 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// OpSelect
|
|
|
|
result = builder.createTriOp(spv::OpSelect,
|
|
|
|
convertGlslangToSpvType(node->getType()), condition,
|
|
|
|
trueValue, falseValue);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(result);
|
|
|
|
} else {
|
|
|
|
// We need control flow to select the result.
|
|
|
|
// TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path.
|
|
|
|
result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));
|
2017-01-27 03:31:11 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// Selection control:
|
|
|
|
const spv::SelectionControlMask control = TranslateSelectionControl(*node);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// make an "if" based on the value created by the condition
|
|
|
|
spv::Builder::If ifBuilder(condition, control, builder);
|
2017-07-04 15:23:40 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// emit the "then" statement
|
|
|
|
builder.createStore(trueValue, result);
|
|
|
|
ifBuilder.makeBeginElse();
|
|
|
|
// emit the "else" statement
|
|
|
|
builder.createStore(falseValue, result);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// finish off the control flow
|
|
|
|
ifBuilder.makeEndIf();
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainLValue(result);
|
|
|
|
}
|
|
|
|
};
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// Execute the one side needed, as per the condition
|
|
|
|
const auto executeOneSide = [&]() {
|
|
|
|
// Always emit control flow.
|
|
|
|
if (node->getBasicType() != glslang::EbtVoid)
|
|
|
|
result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2018-02-21 04:29:05 +00:00
|
|
|
// Selection control:
|
|
|
|
const spv::SelectionControlMask control = TranslateSelectionControl(*node);
|
|
|
|
|
|
|
|
// make an "if" based on the value created by the condition
|
|
|
|
spv::Builder::If ifBuilder(condition, control, builder);
|
|
|
|
|
|
|
|
// emit the "then" statement
|
|
|
|
if (node->getTrueBlock() != nullptr) {
|
|
|
|
node->getTrueBlock()->traverse(this);
|
|
|
|
if (result != spv::NoResult)
|
|
|
|
builder.createStore(accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()), result);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->getFalseBlock() != nullptr) {
|
|
|
|
ifBuilder.makeBeginElse();
|
|
|
|
// emit the "else" statement
|
|
|
|
node->getFalseBlock()->traverse(this);
|
|
|
|
if (result != spv::NoResult)
|
|
|
|
builder.createStore(accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()), result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// finish off the control flow
|
|
|
|
ifBuilder.makeEndIf();
|
|
|
|
|
|
|
|
if (result != spv::NoResult) {
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainLValue(result);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Try for OpSelect (or a requirement to execute both sides)
|
|
|
|
if (bothSidesPolicy()) {
|
|
|
|
SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
|
|
|
|
if (node->getType().getQualifier().isSpecConstant())
|
|
|
|
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
|
|
|
|
executeBothSides();
|
|
|
|
} else
|
|
|
|
executeOneSide();
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)
|
|
|
|
{
|
|
|
|
// emit and get the condition before doing anything with switch
|
|
|
|
node->getCondition()->traverse(this);
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2017-07-04 15:23:40 +00:00
|
|
|
// Selection control:
|
2018-01-30 18:01:39 +00:00
|
|
|
const spv::SelectionControlMask control = TranslateSwitchControl(*node);
|
2017-07-04 15:23:40 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
// browse the children to sort out code segments
|
|
|
|
int defaultSegment = -1;
|
|
|
|
std::vector<TIntermNode*> codeSegments;
|
|
|
|
glslang::TIntermSequence& sequence = node->getBody()->getSequence();
|
|
|
|
std::vector<int> caseValues;
|
|
|
|
std::vector<int> valueIndexToSegment(sequence.size()); // note: probably not all are used, it is an overestimate
|
|
|
|
for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {
|
|
|
|
TIntermNode* child = *c;
|
|
|
|
if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)
|
2015-07-12 09:32:58 +00:00
|
|
|
defaultSegment = (int)codeSegments.size();
|
2015-06-26 22:58:36 +00:00
|
|
|
else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
|
2015-07-12 09:32:58 +00:00
|
|
|
valueIndexToSegment[caseValues.size()] = (int)codeSegments.size();
|
2015-06-26 22:58:36 +00:00
|
|
|
caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst());
|
|
|
|
} else
|
|
|
|
codeSegments.push_back(child);
|
|
|
|
}
|
|
|
|
|
2016-05-06 21:25:16 +00:00
|
|
|
// handle the case where the last code segment is missing, due to no code
|
2015-06-26 22:58:36 +00:00
|
|
|
// statements between the last case and the end of the switch statement
|
|
|
|
if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||
|
|
|
|
(int)codeSegments.size() == defaultSegment)
|
|
|
|
codeSegments.push_back(nullptr);
|
|
|
|
|
|
|
|
// make the switch statement
|
|
|
|
std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
|
2017-07-04 15:23:40 +00:00
|
|
|
builder.makeSwitch(selector, control, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
// emit all the code in the segments
|
|
|
|
breakForLoop.push(false);
|
|
|
|
for (unsigned int s = 0; s < codeSegments.size(); ++s) {
|
|
|
|
builder.nextSwitchSegment(segmentBlocks, s);
|
|
|
|
if (codeSegments[s])
|
|
|
|
codeSegments[s]->traverse(this);
|
|
|
|
else
|
|
|
|
builder.addSwitchBreak();
|
|
|
|
}
|
|
|
|
breakForLoop.pop();
|
|
|
|
|
|
|
|
builder.endSwitch(segmentBlocks);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
|
|
|
|
{
|
|
|
|
int nextConst = 0;
|
2016-03-21 13:51:37 +00:00
|
|
|
spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainRValue(constant);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)
|
|
|
|
{
|
2016-01-10 17:15:13 +00:00
|
|
|
auto blocks = builder.makeNewLoop();
|
2016-01-11 20:57:11 +00:00
|
|
|
builder.createBranch(&blocks.head);
|
2017-05-03 02:14:50 +00:00
|
|
|
|
|
|
|
// Loop control:
|
2019-01-12 10:31:41 +00:00
|
|
|
std::vector<unsigned int> operands;
|
|
|
|
const spv::LoopControlMask control = TranslateLoopControl(*node, operands);
|
2017-05-03 02:14:50 +00:00
|
|
|
|
2016-01-20 16:51:43 +00:00
|
|
|
// Spec requires back edges to target header blocks, and every header block
|
|
|
|
// must dominate its merge block. Make a header block first to ensure these
|
|
|
|
// conditions are met. By definition, it will contain OpLoopMerge, followed
|
|
|
|
// by a block-ending branch. But we don't want to put any other body/test
|
|
|
|
// instructions in it, since the body/test may have arbitrary instructions,
|
|
|
|
// including merges of its own.
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2016-01-20 16:51:43 +00:00
|
|
|
builder.setBuildPoint(&blocks.head);
|
2019-01-12 10:31:41 +00:00
|
|
|
builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, operands);
|
2016-01-10 17:15:13 +00:00
|
|
|
if (node->testFirst() && node->getTest()) {
|
2016-01-20 16:51:43 +00:00
|
|
|
spv::Block& test = builder.makeNewBlock();
|
|
|
|
builder.createBranch(&test);
|
|
|
|
|
|
|
|
builder.setBuildPoint(&test);
|
2015-06-26 22:58:36 +00:00
|
|
|
node->getTest()->traverse(this);
|
2017-06-01 00:50:53 +00:00
|
|
|
spv::Id condition = accessChainLoad(node->getTest()->getType());
|
2016-01-10 17:15:13 +00:00
|
|
|
builder.createConditionalBranch(condition, &blocks.body, &blocks.merge);
|
|
|
|
|
|
|
|
builder.setBuildPoint(&blocks.body);
|
2016-01-11 20:57:11 +00:00
|
|
|
breakForLoop.push(true);
|
2016-01-10 17:15:13 +00:00
|
|
|
if (node->getBody())
|
2016-01-11 00:37:00 +00:00
|
|
|
node->getBody()->traverse(this);
|
2016-01-10 17:15:13 +00:00
|
|
|
builder.createBranch(&blocks.continue_target);
|
2016-01-11 19:48:36 +00:00
|
|
|
breakForLoop.pop();
|
2016-01-10 17:15:13 +00:00
|
|
|
|
|
|
|
builder.setBuildPoint(&blocks.continue_target);
|
|
|
|
if (node->getTerminal())
|
|
|
|
node->getTerminal()->traverse(this);
|
2016-01-11 20:57:11 +00:00
|
|
|
builder.createBranch(&blocks.head);
|
2015-07-15 20:21:26 +00:00
|
|
|
} else {
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2016-01-10 17:15:13 +00:00
|
|
|
builder.createBranch(&blocks.body);
|
|
|
|
|
2016-01-11 19:48:36 +00:00
|
|
|
breakForLoop.push(true);
|
2016-01-10 17:15:13 +00:00
|
|
|
builder.setBuildPoint(&blocks.body);
|
|
|
|
if (node->getBody())
|
2016-01-11 00:37:00 +00:00
|
|
|
node->getBody()->traverse(this);
|
2016-01-10 17:15:13 +00:00
|
|
|
builder.createBranch(&blocks.continue_target);
|
2016-01-11 19:48:36 +00:00
|
|
|
breakForLoop.pop();
|
2016-01-10 17:15:13 +00:00
|
|
|
|
|
|
|
builder.setBuildPoint(&blocks.continue_target);
|
|
|
|
if (node->getTerminal())
|
|
|
|
node->getTerminal()->traverse(this);
|
|
|
|
if (node->getTest()) {
|
|
|
|
node->getTest()->traverse(this);
|
|
|
|
spv::Id condition =
|
2016-02-02 19:37:46 +00:00
|
|
|
accessChainLoad(node->getTest()->getType());
|
2016-01-11 20:57:11 +00:00
|
|
|
builder.createConditionalBranch(condition, &blocks.head, &blocks.merge);
|
2016-01-10 17:15:13 +00:00
|
|
|
} else {
|
2016-01-20 02:13:38 +00:00
|
|
|
// TODO: unless there was a break/return/discard instruction
|
|
|
|
// somewhere in the body, this is an infinite loop, so we should
|
|
|
|
// issue a warning.
|
2016-01-11 20:57:11 +00:00
|
|
|
builder.createBranch(&blocks.head);
|
2016-01-10 17:15:13 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
2016-01-10 17:15:13 +00:00
|
|
|
builder.setBuildPoint(&blocks.merge);
|
2016-01-11 19:48:36 +00:00
|
|
|
builder.closeLoop();
|
2015-06-26 22:58:36 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)
|
|
|
|
{
|
|
|
|
if (node->getExpression())
|
|
|
|
node->getExpression()->traverse(this);
|
|
|
|
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2017-06-01 00:50:53 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
switch (node->getFlowOp()) {
|
|
|
|
case glslang::EOpKill:
|
|
|
|
builder.makeDiscard();
|
|
|
|
break;
|
|
|
|
case glslang::EOpBreak:
|
|
|
|
if (breakForLoop.top())
|
|
|
|
builder.createLoopExit();
|
|
|
|
else
|
|
|
|
builder.addSwitchBreak();
|
|
|
|
break;
|
|
|
|
case glslang::EOpContinue:
|
|
|
|
builder.createLoopContinue();
|
|
|
|
break;
|
|
|
|
case glslang::EOpReturn:
|
2016-10-06 18:59:51 +00:00
|
|
|
if (node->getExpression()) {
|
|
|
|
const glslang::TType& glslangReturnType = node->getExpression()->getType();
|
|
|
|
spv::Id returnId = accessChainLoad(glslangReturnType);
|
|
|
|
if (builder.getTypeId(returnId) != currentFunction->getReturnType()) {
|
|
|
|
builder.clearAccessChain();
|
|
|
|
spv::Id copyId = builder.createVariable(spv::StorageClassFunction, currentFunction->getReturnType());
|
|
|
|
builder.setAccessChainLValue(copyId);
|
|
|
|
multiTypeStore(glslangReturnType, returnId);
|
|
|
|
returnId = builder.createLoad(copyId);
|
|
|
|
}
|
|
|
|
builder.makeReturn(false, returnId);
|
|
|
|
} else
|
2015-09-15 02:58:02 +00:00
|
|
|
builder.makeReturn(false);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
builder.clearAccessChain();
|
|
|
|
break;
|
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2019-07-01 14:23:23 +00:00
|
|
|
case glslang::EOpDemote:
|
|
|
|
builder.createNoResultOp(spv::OpDemoteToHelperInvocationEXT);
|
|
|
|
builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation);
|
|
|
|
builder.addCapability(spv::CapabilityDemoteToHelperInvocationEXT);
|
|
|
|
break;
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2019-07-01 14:23:23 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(0);
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-17 14:38:35 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node, spv::Id forcedType)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2016-05-06 21:25:16 +00:00
|
|
|
// First, steer off constants, which are not SPIR-V variables, but
|
2015-06-26 22:58:36 +00:00
|
|
|
// can still have a mapping to a SPIR-V Id.
|
2015-11-16 04:33:39 +00:00
|
|
|
// This includes specialization constants.
|
2016-03-20 06:46:02 +00:00
|
|
|
if (node->getQualifier().isConstant()) {
|
2018-11-13 14:17:44 +00:00
|
|
|
spv::Id result = createSpvConstant(*node);
|
|
|
|
if (result != spv::NoResult)
|
|
|
|
return result;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now, handle actual variables
|
2017-05-05 11:09:58 +00:00
|
|
|
spv::StorageClass storageClass = TranslateStorageClass(node->getType());
|
2019-06-17 14:38:35 +00:00
|
|
|
spv::Id spvType = forcedType == spv::NoType ? convertGlslangToSpvType(node->getType())
|
|
|
|
: forcedType;
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
const bool contains16BitType = node->getType().contains16BitFloat() ||
|
|
|
|
node->getType().contains16BitInt();
|
2017-04-07 15:22:33 +00:00
|
|
|
if (contains16BitType) {
|
2018-05-15 04:08:53 +00:00
|
|
|
switch (storageClass) {
|
|
|
|
case spv::StorageClassInput:
|
|
|
|
case spv::StorageClassOutput:
|
2018-03-06 23:12:04 +00:00
|
|
|
addPre13Extension(spv::E_SPV_KHR_16bit_storage);
|
2017-04-07 15:22:33 +00:00
|
|
|
builder.addCapability(spv::CapabilityStorageInputOutput16);
|
2018-05-15 04:08:53 +00:00
|
|
|
break;
|
|
|
|
case spv::StorageClassUniform:
|
2018-03-06 23:12:04 +00:00
|
|
|
addPre13Extension(spv::E_SPV_KHR_16bit_storage);
|
2017-04-07 15:22:33 +00:00
|
|
|
if (node->getType().getQualifier().storage == glslang::EvqBuffer)
|
|
|
|
builder.addCapability(spv::CapabilityStorageUniformBufferBlock16);
|
2018-05-15 04:08:53 +00:00
|
|
|
else
|
|
|
|
builder.addCapability(spv::CapabilityStorageUniform16);
|
|
|
|
break;
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
case spv::StorageClassPushConstant:
|
|
|
|
addPre13Extension(spv::E_SPV_KHR_16bit_storage);
|
|
|
|
builder.addCapability(spv::CapabilityStoragePushConstant16);
|
|
|
|
break;
|
2018-05-15 04:08:53 +00:00
|
|
|
case spv::StorageClassStorageBuffer:
|
2019-01-06 23:58:04 +00:00
|
|
|
case spv::StorageClassPhysicalStorageBufferEXT:
|
2018-05-15 04:08:53 +00:00
|
|
|
addPre13Extension(spv::E_SPV_KHR_16bit_storage);
|
|
|
|
builder.addCapability(spv::CapabilityStorageUniformBufferBlock16);
|
|
|
|
break;
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2018-05-15 04:08:53 +00:00
|
|
|
default:
|
2019-08-11 13:41:45 +00:00
|
|
|
if (node->getType().contains16BitFloat())
|
2019-02-18 04:49:28 +00:00
|
|
|
builder.addCapability(spv::CapabilityFloat16);
|
2019-08-11 13:41:45 +00:00
|
|
|
if (node->getType().contains16BitInt())
|
2019-02-18 04:49:28 +00:00
|
|
|
builder.addCapability(spv::CapabilityInt16);
|
2018-05-15 04:08:53 +00:00
|
|
|
break;
|
2017-04-07 15:22:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
if (node->getType().contains8BitInt()) {
|
2018-07-03 19:19:51 +00:00
|
|
|
if (storageClass == spv::StorageClassPushConstant) {
|
|
|
|
builder.addExtension(spv::E_SPV_KHR_8bit_storage);
|
|
|
|
builder.addCapability(spv::CapabilityStoragePushConstant8);
|
|
|
|
} else if (storageClass == spv::StorageClassUniform) {
|
|
|
|
builder.addExtension(spv::E_SPV_KHR_8bit_storage);
|
|
|
|
builder.addCapability(spv::CapabilityUniformAndStorageBuffer8BitAccess);
|
2018-10-23 14:02:29 +00:00
|
|
|
} else if (storageClass == spv::StorageClassStorageBuffer) {
|
|
|
|
builder.addExtension(spv::E_SPV_KHR_8bit_storage);
|
|
|
|
builder.addCapability(spv::CapabilityStorageBuffer8BitAccess);
|
2019-02-18 04:49:28 +00:00
|
|
|
} else {
|
|
|
|
builder.addCapability(spv::CapabilityInt8);
|
2018-07-03 19:19:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
const char* name = node->getName().c_str();
|
|
|
|
if (glslang::IsAnonymous(name))
|
|
|
|
name = "";
|
|
|
|
|
|
|
|
return builder.createVariable(storageClass, spvType, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return type Id of the sampled type.
|
|
|
|
spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
|
|
|
|
{
|
|
|
|
switch (sampler.type) {
|
2019-08-06 13:00:58 +00:00
|
|
|
case glslang::EbtInt: return builder.makeIntType(32);
|
|
|
|
case glslang::EbtUint: return builder.makeUintType(32);
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EbtFloat: return builder.makeFloatType(32);
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2016-11-29 09:36:31 +00:00
|
|
|
case glslang::EbtFloat16:
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float_fetch);
|
|
|
|
builder.addCapability(spv::CapabilityFloat16ImageAMD);
|
|
|
|
return builder.makeFloatType(16);
|
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(0);
|
2015-06-26 22:58:36 +00:00
|
|
|
return builder.makeFloatType(32);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-26 18:50:38 +00:00
|
|
|
// If node is a swizzle operation, return the type that should be used if
|
|
|
|
// the swizzle base is first consumed by another operation, before the swizzle
|
|
|
|
// is applied.
|
|
|
|
spv::Id TGlslangToSpvTraverser::getInvertedSwizzleType(const glslang::TIntermTyped& node)
|
|
|
|
{
|
2017-01-06 07:34:48 +00:00
|
|
|
if (node.getAsOperator() &&
|
2016-07-26 18:50:38 +00:00
|
|
|
node.getAsOperator()->getOp() == glslang::EOpVectorSwizzle)
|
|
|
|
return convertGlslangToSpvType(node.getAsBinaryNode()->getLeft()->getType());
|
|
|
|
else
|
|
|
|
return spv::NoType;
|
|
|
|
}
|
|
|
|
|
|
|
|
// When inverting a swizzle with a parent op, this function
|
|
|
|
// will apply the swizzle operation to a completed parent operation.
|
|
|
|
spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped& node, spv::Id parentResult)
|
|
|
|
{
|
|
|
|
std::vector<unsigned> swizzle;
|
|
|
|
convertSwizzle(*node.getAsBinaryNode()->getRight()->getAsAggregate(), swizzle);
|
|
|
|
return builder.createRvalueSwizzle(precision, convertGlslangToSpvType(node.getType()), parentResult, swizzle);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert a glslang AST swizzle node to a swizzle vector for building SPIR-V.
|
|
|
|
void TGlslangToSpvTraverser::convertSwizzle(const glslang::TIntermAggregate& node, std::vector<unsigned>& swizzle)
|
|
|
|
{
|
|
|
|
const glslang::TIntermSequence& swizzleSequence = node.getSequence();
|
|
|
|
for (int i = 0; i < (int)swizzleSequence.size(); ++i)
|
|
|
|
swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());
|
|
|
|
}
|
|
|
|
|
2015-12-20 18:29:16 +00:00
|
|
|
// Convert from a glslang type to an SPV type, by calling into a
|
|
|
|
// recursive version of this function. This establishes the inherited
|
|
|
|
// layout state rooted from the top-level type.
|
2019-01-06 23:58:04 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly)
|
2015-09-09 23:51:38 +00:00
|
|
|
{
|
2019-01-06 23:58:04 +00:00
|
|
|
return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false, forwardReferenceOnly);
|
2015-09-09 23:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
|
2016-01-22 01:56:57 +00:00
|
|
|
// explicitLayout can be kept the same throughout the hierarchical recursive walk.
|
2016-07-01 03:18:02 +00:00
|
|
|
// Mutually recursive with convertGlslangStructToSpvType().
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type,
|
2019-01-06 23:58:04 +00:00
|
|
|
glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier,
|
|
|
|
bool lastBufferBlockMember, bool forwardReferenceOnly)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2015-12-24 17:30:13 +00:00
|
|
|
spv::Id spvType = spv::NoResult;
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
switch (type.getBasicType()) {
|
|
|
|
case glslang::EbtVoid:
|
|
|
|
spvType = builder.makeVoidType();
|
2015-11-16 04:33:39 +00:00
|
|
|
assert (! type.isArray());
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
2019-08-06 13:00:58 +00:00
|
|
|
case glslang::EbtBool:
|
|
|
|
// "transparent" bool doesn't exist in SPIR-V. The GLSL convention is
|
|
|
|
// a 32-bit int where non-0 means true.
|
|
|
|
if (explicitLayout != glslang::ElpNone)
|
|
|
|
spvType = builder.makeUintType(32);
|
|
|
|
else
|
|
|
|
spvType = builder.makeBoolType();
|
|
|
|
break;
|
|
|
|
case glslang::EbtInt:
|
|
|
|
spvType = builder.makeIntType(32);
|
|
|
|
break;
|
|
|
|
case glslang::EbtUint:
|
|
|
|
spvType = builder.makeUintType(32);
|
|
|
|
break;
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EbtFloat:
|
|
|
|
spvType = builder.makeFloatType(32);
|
|
|
|
break;
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EbtDouble:
|
|
|
|
spvType = builder.makeFloatType(64);
|
|
|
|
break;
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
case glslang::EbtFloat16:
|
|
|
|
spvType = builder.makeFloatType(16);
|
|
|
|
break;
|
2018-08-15 19:54:09 +00:00
|
|
|
case glslang::EbtInt8:
|
2018-03-06 23:12:04 +00:00
|
|
|
spvType = builder.makeIntType(8);
|
|
|
|
break;
|
|
|
|
case glslang::EbtUint8:
|
|
|
|
spvType = builder.makeUintType(8);
|
|
|
|
break;
|
2018-08-15 19:54:09 +00:00
|
|
|
case glslang::EbtInt16:
|
2018-03-06 23:12:04 +00:00
|
|
|
spvType = builder.makeIntType(16);
|
|
|
|
break;
|
|
|
|
case glslang::EbtUint16:
|
|
|
|
spvType = builder.makeUintType(16);
|
|
|
|
break;
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EbtInt64:
|
|
|
|
spvType = builder.makeIntType(64);
|
|
|
|
break;
|
|
|
|
case glslang::EbtUint64:
|
|
|
|
spvType = builder.makeUintType(64);
|
|
|
|
break;
|
2015-07-23 16:22:48 +00:00
|
|
|
case glslang::EbtAtomicUint:
|
2016-07-07 19:20:00 +00:00
|
|
|
builder.addCapability(spv::CapabilityAtomicStorage);
|
2015-07-23 16:22:48 +00:00
|
|
|
spvType = builder.makeUintType(32);
|
|
|
|
break;
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EbtAccStructNV:
|
|
|
|
spvType = builder.makeAccelerationStructureNVType();
|
|
|
|
break;
|
2019-08-06 13:00:58 +00:00
|
|
|
case glslang::EbtReference:
|
|
|
|
{
|
|
|
|
// Make the forward pointer, then recurse to convert the structure type, then
|
|
|
|
// patch up the forward pointer with a real pointer type.
|
|
|
|
if (forwardPointers.find(type.getReferentType()) == forwardPointers.end()) {
|
|
|
|
spv::Id forwardId = builder.makeForwardPointer(spv::StorageClassPhysicalStorageBufferEXT);
|
|
|
|
forwardPointers[type.getReferentType()] = forwardId;
|
|
|
|
}
|
|
|
|
spvType = forwardPointers[type.getReferentType()];
|
|
|
|
if (!forwardReferenceOnly) {
|
|
|
|
spv::Id referentType = convertGlslangToSpvType(*type.getReferentType());
|
|
|
|
builder.makePointerFromForwardPointer(spv::StorageClassPhysicalStorageBufferEXT,
|
|
|
|
forwardPointers[type.getReferentType()],
|
|
|
|
referentType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2018-09-19 18:42:24 +00:00
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EbtSampler:
|
|
|
|
{
|
|
|
|
const glslang::TSampler& sampler = type.getSampler();
|
2019-08-08 07:15:24 +00:00
|
|
|
if (sampler.isPureSampler()) {
|
2016-02-16 03:58:50 +00:00
|
|
|
spvType = builder.makeSamplerType();
|
|
|
|
} else {
|
|
|
|
// an image is present, make its type
|
2019-08-08 07:15:24 +00:00
|
|
|
spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler),
|
|
|
|
sampler.isShadow(), sampler.isArrayed(), sampler.isMultiSample(),
|
|
|
|
sampler.isImageClass() ? 2 : 1, TranslateImageFormat(type));
|
|
|
|
if (sampler.isCombined()) {
|
2016-02-16 03:58:50 +00:00
|
|
|
// already has both image and sampler, make the combined type
|
|
|
|
spvType = builder.makeSampledImageType(spvType);
|
|
|
|
}
|
2015-11-16 04:33:39 +00:00
|
|
|
}
|
2015-12-24 17:30:13 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EbtStruct:
|
|
|
|
case glslang::EbtBlock:
|
|
|
|
{
|
|
|
|
// If we've seen this struct type, return it
|
2016-07-01 03:18:02 +00:00
|
|
|
const glslang::TTypeList* glslangMembers = type.getStruct();
|
2015-12-24 17:30:13 +00:00
|
|
|
|
|
|
|
// Try to share structs for different layouts, but not yet for other
|
|
|
|
// kinds of qualification (primarily not yet including interpolant qualification).
|
2016-09-01 23:05:23 +00:00
|
|
|
if (! HasNonLayoutQualifiers(type, qualifier))
|
2016-07-01 03:18:02 +00:00
|
|
|
spvType = structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers];
|
2015-12-24 17:30:13 +00:00
|
|
|
if (spvType != spv::NoResult)
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
// else, we haven't seen it...
|
|
|
|
if (type.getBasicType() == glslang::EbtBlock)
|
2016-07-01 03:18:02 +00:00
|
|
|
memberRemapper[glslangMembers].resize(glslangMembers->size());
|
|
|
|
spvType = convertGlslangStructToSpvType(type, glslangMembers, explicitLayout, qualifier);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(0);
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type.isMatrix())
|
|
|
|
spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());
|
|
|
|
else {
|
|
|
|
// If this variable has a vector element count greater than 1, create a SPIR-V vector
|
|
|
|
if (type.getVectorSize() > 1)
|
|
|
|
spvType = builder.makeVectorType(spvType, type.getVectorSize());
|
|
|
|
}
|
|
|
|
|
2019-02-19 19:10:32 +00:00
|
|
|
if (type.isCoopMat()) {
|
|
|
|
builder.addCapability(spv::CapabilityCooperativeMatrixNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_cooperative_matrix);
|
|
|
|
if (type.getBasicType() == glslang::EbtFloat16)
|
|
|
|
builder.addCapability(spv::CapabilityFloat16);
|
|
|
|
|
|
|
|
spv::Id scope = makeArraySizeId(*type.getTypeParameters(), 1);
|
|
|
|
spv::Id rows = makeArraySizeId(*type.getTypeParameters(), 2);
|
|
|
|
spv::Id cols = makeArraySizeId(*type.getTypeParameters(), 3);
|
|
|
|
|
|
|
|
spvType = builder.makeCooperativeMatrixType(spvType, scope, rows, cols);
|
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
if (type.isArray()) {
|
2015-12-30 04:27:24 +00:00
|
|
|
int stride = 0; // keep this 0 unless doing an explicit layout; 0 will mean no decoration, no stride
|
|
|
|
|
2015-09-12 18:17:44 +00:00
|
|
|
// Do all but the outer dimension
|
2015-12-30 04:27:24 +00:00
|
|
|
if (type.getArraySizes()->getNumDims() > 1) {
|
2016-01-05 02:22:56 +00:00
|
|
|
// We need to decorate array strides for types needing explicit layout, except blocks.
|
|
|
|
if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock) {
|
2015-12-30 04:27:24 +00:00
|
|
|
// Use a dummy glslang type for querying internal strides of
|
|
|
|
// arrays of arrays, but using just a one-dimensional array.
|
|
|
|
glslang::TType simpleArrayType(type, 0); // deference type of the array
|
2018-03-26 06:38:53 +00:00
|
|
|
while (simpleArrayType.getArraySizes()->getNumDims() > 1)
|
|
|
|
simpleArrayType.getArraySizes()->dereference();
|
2015-12-30 04:27:24 +00:00
|
|
|
|
|
|
|
// Will compute the higher-order strides here, rather than making a whole
|
|
|
|
// pile of types and doing repetitive recursion on their contents.
|
|
|
|
stride = getArrayStride(simpleArrayType, explicitLayout, qualifier.layoutMatrix);
|
|
|
|
}
|
2016-01-05 02:22:56 +00:00
|
|
|
|
|
|
|
// make the arrays
|
2015-12-30 04:27:24 +00:00
|
|
|
for (int dim = type.getArraySizes()->getNumDims() - 1; dim > 0; --dim) {
|
2016-02-16 03:58:50 +00:00
|
|
|
spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), dim), stride);
|
2015-12-30 04:27:24 +00:00
|
|
|
if (stride > 0)
|
|
|
|
builder.addDecoration(spvType, spv::DecorationArrayStride, stride);
|
2016-02-16 03:58:50 +00:00
|
|
|
stride *= type.getArraySizes()->getDimSize(dim);
|
2015-12-30 04:27:24 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// single-dimensional array, and don't yet have stride
|
|
|
|
|
2016-01-05 02:22:56 +00:00
|
|
|
// We need to decorate array strides for types needing explicit layout, except blocks.
|
2015-12-30 04:27:24 +00:00
|
|
|
if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock)
|
|
|
|
stride = getArrayStride(type, explicitLayout, qualifier.layoutMatrix);
|
2015-09-12 18:17:44 +00:00
|
|
|
}
|
|
|
|
|
2018-03-29 00:01:20 +00:00
|
|
|
// Do the outer dimension, which might not be known for a runtime-sized array.
|
|
|
|
// (Unsized arrays that survive through linking will be runtime-sized arrays)
|
|
|
|
if (type.isSizedArray())
|
2016-02-16 03:58:50 +00:00
|
|
|
spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), 0), stride);
|
2018-04-05 17:25:02 +00:00
|
|
|
else {
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-04-05 17:25:02 +00:00
|
|
|
if (!lastBufferBlockMember) {
|
|
|
|
builder.addExtension("SPV_EXT_descriptor_indexing");
|
|
|
|
builder.addCapability(spv::CapabilityRuntimeDescriptorArrayEXT);
|
|
|
|
}
|
2018-03-29 00:01:20 +00:00
|
|
|
spvType = builder.makeRuntimeArray(spvType);
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2018-04-05 17:25:02 +00:00
|
|
|
}
|
2015-12-30 04:27:24 +00:00
|
|
|
if (stride > 0)
|
|
|
|
builder.addDecoration(spvType, spv::DecorationArrayStride, stride);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return spvType;
|
|
|
|
}
|
|
|
|
|
2017-03-25 00:38:16 +00:00
|
|
|
// TODO: this functionality should exist at a higher level, in creating the AST
|
|
|
|
//
|
|
|
|
// Identify interface members that don't have their required extension turned on.
|
|
|
|
//
|
|
|
|
bool TGlslangToSpvTraverser::filterMember(const glslang::TType& member)
|
|
|
|
{
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2017-03-25 00:38:16 +00:00
|
|
|
auto& extensions = glslangIntermediate->getRequestedExtensions();
|
|
|
|
|
2017-03-29 15:01:36 +00:00
|
|
|
if (member.getFieldName() == "gl_SecondaryViewportMaskNV" &&
|
|
|
|
extensions.find("GL_NV_stereo_view_rendering") == extensions.end())
|
|
|
|
return true;
|
2017-03-25 00:38:16 +00:00
|
|
|
if (member.getFieldName() == "gl_SecondaryPositionNV" &&
|
|
|
|
extensions.find("GL_NV_stereo_view_rendering") == extensions.end())
|
|
|
|
return true;
|
2018-09-19 18:41:59 +00:00
|
|
|
|
|
|
|
if (glslangIntermediate->getStage() != EShLangMeshNV) {
|
|
|
|
if (member.getFieldName() == "gl_ViewportMask" &&
|
|
|
|
extensions.find("GL_NV_viewport_array2") == extensions.end())
|
|
|
|
return true;
|
|
|
|
if (member.getFieldName() == "gl_PositionPerViewNV" &&
|
|
|
|
extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end())
|
|
|
|
return true;
|
|
|
|
if (member.getFieldName() == "gl_ViewportMaskPerViewNV" &&
|
|
|
|
extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
2017-03-25 00:38:16 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2016-07-01 03:18:02 +00:00
|
|
|
// Do full recursive conversion of a glslang structure (or block) type to a SPIR-V Id.
|
|
|
|
// explicitLayout can be kept the same throughout the hierarchical recursive walk.
|
|
|
|
// Mutually recursive with convertGlslangToSpvType().
|
|
|
|
spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TType& type,
|
|
|
|
const glslang::TTypeList* glslangMembers,
|
|
|
|
glslang::TLayoutPacking explicitLayout,
|
|
|
|
const glslang::TQualifier& qualifier)
|
|
|
|
{
|
|
|
|
// Create a vector of struct types for SPIR-V to consume
|
|
|
|
std::vector<spv::Id> spvMembers;
|
|
|
|
int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks
|
2019-01-06 23:58:04 +00:00
|
|
|
std::vector<std::pair<glslang::TType*, glslang::TQualifier> > deferredForwardPointers;
|
2016-07-01 03:18:02 +00:00
|
|
|
for (int i = 0; i < (int)glslangMembers->size(); i++) {
|
|
|
|
glslang::TType& glslangMember = *(*glslangMembers)[i].type;
|
|
|
|
if (glslangMember.hiddenMember()) {
|
|
|
|
++memberDelta;
|
|
|
|
if (type.getBasicType() == glslang::EbtBlock)
|
|
|
|
memberRemapper[glslangMembers][i] = -1;
|
|
|
|
} else {
|
2017-03-25 00:38:16 +00:00
|
|
|
if (type.getBasicType() == glslang::EbtBlock) {
|
2019-07-22 19:36:38 +00:00
|
|
|
if (filterMember(glslangMember)) {
|
|
|
|
memberDelta++;
|
|
|
|
memberRemapper[glslangMembers][i] = -1;
|
2017-03-25 00:38:16 +00:00
|
|
|
continue;
|
2019-07-22 19:36:38 +00:00
|
|
|
}
|
|
|
|
memberRemapper[glslangMembers][i] = i - memberDelta;
|
2017-03-25 00:38:16 +00:00
|
|
|
}
|
2016-07-01 03:18:02 +00:00
|
|
|
// modify just this child's view of the qualifier
|
|
|
|
glslang::TQualifier memberQualifier = glslangMember.getQualifier();
|
|
|
|
InheritQualifiers(memberQualifier, qualifier);
|
|
|
|
|
2017-06-04 19:22:39 +00:00
|
|
|
// manually inherit location
|
2016-07-01 03:18:02 +00:00
|
|
|
if (! memberQualifier.hasLocation() && qualifier.hasLocation())
|
2017-06-04 19:22:39 +00:00
|
|
|
memberQualifier.layoutLocation = qualifier.layoutLocation;
|
2016-07-01 03:18:02 +00:00
|
|
|
|
|
|
|
// recurse
|
2018-03-29 00:01:20 +00:00
|
|
|
bool lastBufferBlockMember = qualifier.storage == glslang::EvqBuffer &&
|
|
|
|
i == (int)glslangMembers->size() - 1;
|
2019-01-06 23:58:04 +00:00
|
|
|
|
|
|
|
// Make forward pointers for any pointer members, and create a list of members to
|
|
|
|
// convert to spirv types after creating the struct.
|
2019-08-01 09:28:08 +00:00
|
|
|
if (glslangMember.isReference()) {
|
2019-01-06 23:58:04 +00:00
|
|
|
if (forwardPointers.find(glslangMember.getReferentType()) == forwardPointers.end()) {
|
|
|
|
deferredForwardPointers.push_back(std::make_pair(&glslangMember, memberQualifier));
|
|
|
|
}
|
|
|
|
spvMembers.push_back(
|
|
|
|
convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, true));
|
|
|
|
} else {
|
|
|
|
spvMembers.push_back(
|
|
|
|
convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, false));
|
|
|
|
}
|
2016-07-01 03:18:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make the SPIR-V type
|
|
|
|
spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str());
|
2016-09-01 23:05:23 +00:00
|
|
|
if (! HasNonLayoutQualifiers(type, qualifier))
|
2016-07-01 03:18:02 +00:00
|
|
|
structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers] = spvType;
|
|
|
|
|
|
|
|
// Decorate it
|
|
|
|
decorateStructType(type, glslangMembers, explicitLayout, qualifier, spvType);
|
|
|
|
|
2019-01-16 07:55:37 +00:00
|
|
|
for (int i = 0; i < (int)deferredForwardPointers.size(); ++i) {
|
2019-01-06 23:58:04 +00:00
|
|
|
auto it = deferredForwardPointers[i];
|
|
|
|
convertGlslangToSpvType(*it.first, explicitLayout, it.second, false);
|
|
|
|
}
|
|
|
|
|
2016-07-01 03:18:02 +00:00
|
|
|
return spvType;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type,
|
|
|
|
const glslang::TTypeList* glslangMembers,
|
|
|
|
glslang::TLayoutPacking explicitLayout,
|
|
|
|
const glslang::TQualifier& qualifier,
|
|
|
|
spv::Id spvType)
|
|
|
|
{
|
|
|
|
// Name and decorate the non-hidden members
|
|
|
|
int offset = -1;
|
|
|
|
int locationOffset = 0; // for use within the members of this struct
|
|
|
|
for (int i = 0; i < (int)glslangMembers->size(); i++) {
|
|
|
|
glslang::TType& glslangMember = *(*glslangMembers)[i].type;
|
|
|
|
int member = i;
|
2017-03-25 00:38:16 +00:00
|
|
|
if (type.getBasicType() == glslang::EbtBlock) {
|
2016-07-01 03:18:02 +00:00
|
|
|
member = memberRemapper[glslangMembers][i];
|
2017-03-25 00:38:16 +00:00
|
|
|
if (filterMember(glslangMember))
|
|
|
|
continue;
|
|
|
|
}
|
2016-07-01 03:18:02 +00:00
|
|
|
|
|
|
|
// modify just this child's view of the qualifier
|
|
|
|
glslang::TQualifier memberQualifier = glslangMember.getQualifier();
|
|
|
|
InheritQualifiers(memberQualifier, qualifier);
|
|
|
|
|
|
|
|
// using -1 above to indicate a hidden member
|
2018-03-08 01:05:55 +00:00
|
|
|
if (member < 0)
|
|
|
|
continue;
|
2016-07-01 03:18:02 +00:00
|
|
|
|
2018-03-08 01:05:55 +00:00
|
|
|
builder.addMemberName(spvType, member, glslangMember.getFieldName().c_str());
|
|
|
|
builder.addMemberDecoration(spvType, member,
|
|
|
|
TranslateLayoutDecoration(glslangMember, memberQualifier.layoutMatrix));
|
|
|
|
builder.addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangMember));
|
|
|
|
// Add interpolation and auxiliary storage decorations only to
|
|
|
|
// top-level members of Input and Output storage classes
|
|
|
|
if (type.getQualifier().storage == glslang::EvqVaryingIn ||
|
|
|
|
type.getQualifier().storage == glslang::EvqVaryingOut) {
|
|
|
|
if (type.getBasicType() == glslang::EbtBlock ||
|
|
|
|
glslangIntermediate->getSource() == glslang::EShSourceHlsl) {
|
|
|
|
builder.addMemberDecoration(spvType, member, TranslateInterpolationDecoration(memberQualifier));
|
|
|
|
builder.addMemberDecoration(spvType, member, TranslateAuxiliaryStorageDecoration(memberQualifier));
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-09-19 18:41:59 +00:00
|
|
|
addMeshNVDecoration(spvType, member, memberQualifier);
|
|
|
|
#endif
|
2016-07-01 03:18:02 +00:00
|
|
|
}
|
2018-03-08 01:05:55 +00:00
|
|
|
}
|
|
|
|
builder.addMemberDecoration(spvType, member, TranslateInvariantDecoration(memberQualifier));
|
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-03-08 01:05:55 +00:00
|
|
|
if (type.getBasicType() == glslang::EbtBlock &&
|
|
|
|
qualifier.storage == glslang::EvqBuffer) {
|
|
|
|
// Add memory decorations only to top-level members of shader storage block
|
|
|
|
std::vector<spv::Decoration> memory;
|
2018-09-05 15:11:41 +00:00
|
|
|
TranslateMemoryDecoration(memberQualifier, memory, glslangIntermediate->usingVulkanMemoryModel());
|
2018-03-08 01:05:55 +00:00
|
|
|
for (unsigned int i = 0; i < memory.size(); ++i)
|
|
|
|
builder.addMemberDecoration(spvType, member, memory[i]);
|
|
|
|
}
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2018-03-08 01:05:55 +00:00
|
|
|
|
|
|
|
// Location assignment was already completed correctly by the front end,
|
|
|
|
// just track whether a member needs to be decorated.
|
|
|
|
// Ignore member locations if the container is an array, as that's
|
|
|
|
// ill-specified and decisions have been made to not allow this.
|
|
|
|
if (! type.isArray() && memberQualifier.hasLocation())
|
|
|
|
builder.addMemberDecoration(spvType, member, spv::DecorationLocation, memberQualifier.layoutLocation);
|
|
|
|
|
|
|
|
if (qualifier.hasLocation()) // track for upcoming inheritance
|
|
|
|
locationOffset += glslangIntermediate->computeTypeLocationSize(
|
|
|
|
glslangMember, glslangIntermediate->getStage());
|
|
|
|
|
|
|
|
// component, XFB, others
|
|
|
|
if (glslangMember.getQualifier().hasComponent())
|
|
|
|
builder.addMemberDecoration(spvType, member, spv::DecorationComponent,
|
|
|
|
glslangMember.getQualifier().layoutComponent);
|
|
|
|
if (glslangMember.getQualifier().hasXfbOffset())
|
|
|
|
builder.addMemberDecoration(spvType, member, spv::DecorationOffset,
|
|
|
|
glslangMember.getQualifier().layoutXfbOffset);
|
|
|
|
else if (explicitLayout != glslang::ElpNone) {
|
|
|
|
// figure out what to do with offset, which is accumulating
|
|
|
|
int nextOffset;
|
|
|
|
updateMemberOffset(type, glslangMember, offset, nextOffset, explicitLayout, memberQualifier.layoutMatrix);
|
|
|
|
if (offset >= 0)
|
|
|
|
builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset);
|
|
|
|
offset = nextOffset;
|
|
|
|
}
|
2016-07-01 03:18:02 +00:00
|
|
|
|
2018-03-08 01:05:55 +00:00
|
|
|
if (glslangMember.isMatrix() && explicitLayout != glslang::ElpNone)
|
|
|
|
builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride,
|
|
|
|
getMatrixStride(glslangMember, explicitLayout, memberQualifier.layoutMatrix));
|
2016-07-01 03:18:02 +00:00
|
|
|
|
2018-03-08 01:05:55 +00:00
|
|
|
// built-in variable decorations
|
|
|
|
spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangMember.getQualifier().builtIn, true);
|
|
|
|
if (builtIn != spv::BuiltInMax)
|
|
|
|
builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn);
|
2017-01-13 09:10:53 +00:00
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-04-05 17:25:02 +00:00
|
|
|
// nonuniform
|
|
|
|
builder.addMemberDecoration(spvType, member, TranslateNonUniformDecoration(glslangMember.getQualifier()));
|
|
|
|
|
2018-03-29 00:01:20 +00:00
|
|
|
if (glslangIntermediate->getHlslFunctionality1() && memberQualifier.semanticName != nullptr) {
|
|
|
|
builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
|
|
|
|
builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE,
|
|
|
|
memberQualifier.semanticName);
|
|
|
|
}
|
|
|
|
|
2018-03-08 01:05:55 +00:00
|
|
|
if (builtIn == spv::BuiltInLayer) {
|
|
|
|
// SPV_NV_viewport_array2 extension
|
|
|
|
if (glslangMember.getQualifier().layoutViewportRelative){
|
|
|
|
builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationViewportRelativeNV);
|
|
|
|
builder.addCapability(spv::CapabilityShaderViewportMaskNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_viewport_array2);
|
2017-01-13 09:10:53 +00:00
|
|
|
}
|
2018-03-08 01:05:55 +00:00
|
|
|
if (glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset != -2048){
|
|
|
|
builder.addMemberDecoration(spvType, member,
|
|
|
|
(spv::Decoration)spv::DecorationSecondaryViewportRelativeNV,
|
|
|
|
glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset);
|
|
|
|
builder.addCapability(spv::CapabilityShaderStereoViewNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
|
2017-02-14 22:52:34 +00:00
|
|
|
}
|
2018-03-08 01:05:55 +00:00
|
|
|
}
|
|
|
|
if (glslangMember.getQualifier().layoutPassthrough) {
|
|
|
|
builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationPassthroughNV);
|
|
|
|
builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);
|
|
|
|
}
|
2017-01-13 09:10:53 +00:00
|
|
|
#endif
|
2016-07-01 03:18:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Decorate the structure
|
2018-03-08 01:05:55 +00:00
|
|
|
builder.addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix));
|
|
|
|
builder.addDecoration(spvType, TranslateBlockDecoration(type, glslangIntermediate->usingStorageBuffer()));
|
2016-07-01 03:18:02 +00:00
|
|
|
}
|
|
|
|
|
2016-02-16 03:58:50 +00:00
|
|
|
// Turn the expression forming the array size into an id.
|
|
|
|
// This is not quite trivial, because of specialization constants.
|
|
|
|
// Sometimes, a raw constant is turned into an Id, and sometimes
|
|
|
|
// a specialization constant expression is.
|
|
|
|
spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arraySizes, int dim)
|
|
|
|
{
|
|
|
|
// First, see if this is sized with a node, meaning a specialization constant:
|
|
|
|
glslang::TIntermTyped* specNode = arraySizes.getDimNode(dim);
|
|
|
|
if (specNode != nullptr) {
|
|
|
|
builder.clearAccessChain();
|
|
|
|
specNode->traverse(this);
|
|
|
|
return accessChainLoad(specNode->getAsTyped()->getType());
|
|
|
|
}
|
2016-05-06 21:25:16 +00:00
|
|
|
|
2016-02-16 03:58:50 +00:00
|
|
|
// Otherwise, need a compile-time (front end) size, get it:
|
|
|
|
int size = arraySizes.getDimSize(dim);
|
|
|
|
assert(size > 0);
|
|
|
|
return builder.makeUintConstant(size);
|
|
|
|
}
|
|
|
|
|
2016-02-09 04:38:15 +00:00
|
|
|
// Wrap the builder's accessChainLoad to:
|
|
|
|
// - localize handling of RelaxedPrecision
|
|
|
|
// - use the SPIR-V inferred type instead of another conversion of the glslang type
|
|
|
|
// (avoids unnecessary work and possible type punning for structures)
|
|
|
|
// - do conversion of concrete to abstract type
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
|
|
|
|
{
|
2016-02-09 04:38:15 +00:00
|
|
|
spv::Id nominalTypeId = builder.accessChainGetInferredType();
|
2018-09-05 15:11:41 +00:00
|
|
|
|
|
|
|
spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
|
|
|
|
coherentFlags |= TranslateCoherent(type);
|
|
|
|
|
2019-01-06 23:58:04 +00:00
|
|
|
unsigned int alignment = builder.getAccessChain().alignment;
|
2019-03-06 19:34:10 +00:00
|
|
|
alignment |= type.getBufferReferenceAlignment();
|
2019-01-06 23:58:04 +00:00
|
|
|
|
2018-04-05 17:25:02 +00:00
|
|
|
spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type),
|
2018-09-05 15:11:41 +00:00
|
|
|
TranslateNonUniformDecoration(type.getQualifier()),
|
|
|
|
nominalTypeId,
|
|
|
|
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask),
|
2019-01-06 23:58:04 +00:00
|
|
|
TranslateMemoryScope(coherentFlags),
|
|
|
|
alignment);
|
2016-02-09 04:38:15 +00:00
|
|
|
|
|
|
|
// Need to convert to abstract types when necessary
|
2016-02-23 09:51:09 +00:00
|
|
|
if (type.getBasicType() == glslang::EbtBool) {
|
|
|
|
if (builder.isScalarType(nominalTypeId)) {
|
|
|
|
// Conversion for bool
|
|
|
|
spv::Id boolType = builder.makeBoolType();
|
|
|
|
if (nominalTypeId != boolType)
|
|
|
|
loadedId = builder.createBinOp(spv::OpINotEqual, boolType, loadedId, builder.makeUintConstant(0));
|
|
|
|
} else if (builder.isVectorType(nominalTypeId)) {
|
|
|
|
// Conversion for bvec
|
|
|
|
int vecSize = builder.getNumTypeComponents(nominalTypeId);
|
|
|
|
spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);
|
|
|
|
if (nominalTypeId != bvecType)
|
|
|
|
loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId, makeSmearedConstant(builder.makeUintConstant(0), vecSize));
|
|
|
|
}
|
|
|
|
}
|
2016-02-09 04:38:15 +00:00
|
|
|
|
|
|
|
return loadedId;
|
2016-02-02 19:37:46 +00:00
|
|
|
}
|
|
|
|
|
2016-02-23 09:51:09 +00:00
|
|
|
// Wrap the builder's accessChainStore to:
|
|
|
|
// - do conversion of concrete to abstract type
|
2016-09-02 17:20:21 +00:00
|
|
|
//
|
|
|
|
// Implicitly uses the existing builder.accessChain as the storage target.
|
2016-02-23 09:51:09 +00:00
|
|
|
void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::Id rvalue)
|
|
|
|
{
|
|
|
|
// Need to convert to abstract types when necessary
|
|
|
|
if (type.getBasicType() == glslang::EbtBool) {
|
|
|
|
spv::Id nominalTypeId = builder.accessChainGetInferredType();
|
|
|
|
|
|
|
|
if (builder.isScalarType(nominalTypeId)) {
|
|
|
|
// Conversion for bool
|
|
|
|
spv::Id boolType = builder.makeBoolType();
|
2017-05-20 05:29:50 +00:00
|
|
|
if (nominalTypeId != boolType) {
|
|
|
|
// keep these outside arguments, for determinant order-of-evaluation
|
|
|
|
spv::Id one = builder.makeUintConstant(1);
|
|
|
|
spv::Id zero = builder.makeUintConstant(0);
|
|
|
|
rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero);
|
|
|
|
} else if (builder.getTypeId(rvalue) != boolType)
|
2017-05-20 05:00:13 +00:00
|
|
|
rvalue = builder.createBinOp(spv::OpINotEqual, boolType, rvalue, builder.makeUintConstant(0));
|
2016-02-23 09:51:09 +00:00
|
|
|
} else if (builder.isVectorType(nominalTypeId)) {
|
|
|
|
// Conversion for bvec
|
|
|
|
int vecSize = builder.getNumTypeComponents(nominalTypeId);
|
|
|
|
spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);
|
2017-05-20 05:29:50 +00:00
|
|
|
if (nominalTypeId != bvecType) {
|
|
|
|
// keep these outside arguments, for determinant order-of-evaluation
|
2017-05-20 05:44:51 +00:00
|
|
|
spv::Id one = makeSmearedConstant(builder.makeUintConstant(1), vecSize);
|
|
|
|
spv::Id zero = makeSmearedConstant(builder.makeUintConstant(0), vecSize);
|
|
|
|
rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero);
|
2017-05-20 05:29:50 +00:00
|
|
|
} else if (builder.getTypeId(rvalue) != bvecType)
|
2017-05-20 05:00:13 +00:00
|
|
|
rvalue = builder.createBinOp(spv::OpINotEqual, bvecType, rvalue,
|
|
|
|
makeSmearedConstant(builder.makeUintConstant(0), vecSize));
|
2016-02-23 09:51:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
|
|
|
|
coherentFlags |= TranslateCoherent(type);
|
|
|
|
|
2019-01-06 23:58:04 +00:00
|
|
|
unsigned int alignment = builder.getAccessChain().alignment;
|
2019-03-06 19:34:10 +00:00
|
|
|
alignment |= type.getBufferReferenceAlignment();
|
2019-01-06 23:58:04 +00:00
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
builder.accessChainStore(rvalue,
|
|
|
|
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerVisibleKHRMask),
|
2019-01-06 23:58:04 +00:00
|
|
|
TranslateMemoryScope(coherentFlags), alignment);
|
2016-02-23 09:51:09 +00:00
|
|
|
}
|
|
|
|
|
2016-09-02 17:20:21 +00:00
|
|
|
// For storing when types match at the glslang level, but not might match at the
|
|
|
|
// SPIR-V level.
|
|
|
|
//
|
|
|
|
// This especially happens when a single glslang type expands to multiple
|
2016-10-06 18:59:51 +00:00
|
|
|
// SPIR-V types, like a struct that is used in a member-undecorated way as well
|
2016-09-02 17:20:21 +00:00
|
|
|
// as in a member-decorated way.
|
|
|
|
//
|
|
|
|
// NOTE: This function can handle any store request; if it's not special it
|
|
|
|
// simplifies to a simple OpStore.
|
|
|
|
//
|
|
|
|
// Implicitly uses the existing builder.accessChain as the storage target.
|
|
|
|
void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id rValue)
|
|
|
|
{
|
2016-09-11 18:33:43 +00:00
|
|
|
// we only do the complex path here if it's an aggregate
|
|
|
|
if (! type.isStruct() && ! type.isArray()) {
|
2016-09-02 17:20:21 +00:00
|
|
|
accessChainStore(type, rValue);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-11 18:33:43 +00:00
|
|
|
// and, it has to be a case of type aliasing
|
2016-09-02 17:20:21 +00:00
|
|
|
spv::Id rType = builder.getTypeId(rValue);
|
|
|
|
spv::Id lValue = builder.accessChainGetLValue();
|
|
|
|
spv::Id lType = builder.getContainedTypeId(builder.getTypeId(lValue));
|
|
|
|
if (lType == rType) {
|
|
|
|
accessChainStore(type, rValue);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-11 18:33:43 +00:00
|
|
|
// Recursively (as needed) copy an aggregate type to a different aggregate type,
|
2016-09-02 17:20:21 +00:00
|
|
|
// where the two types were the same type in GLSL. This requires member
|
|
|
|
// by member copy, recursively.
|
|
|
|
|
2019-01-15 14:48:27 +00:00
|
|
|
// SPIR-V 1.4 added an instruction to do help do this.
|
|
|
|
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
|
|
|
|
// However, bool in uniform space is changed to int, so
|
|
|
|
// OpCopyLogical does not work for that.
|
|
|
|
// TODO: It would be more robust to do a full recursive verification of the types satisfying SPIR-V rules.
|
|
|
|
bool rBool = builder.containsType(builder.getTypeId(rValue), spv::OpTypeBool, 0);
|
|
|
|
bool lBool = builder.containsType(lType, spv::OpTypeBool, 0);
|
|
|
|
if (lBool == rBool) {
|
|
|
|
spv::Id logicalCopy = builder.createUnaryOp(spv::OpCopyLogical, lType, rValue);
|
|
|
|
accessChainStore(type, logicalCopy);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-11 18:33:43 +00:00
|
|
|
// If an array, copy element by element.
|
|
|
|
if (type.isArray()) {
|
|
|
|
glslang::TType glslangElementType(type, 0);
|
|
|
|
spv::Id elementRType = builder.getContainedTypeId(rType);
|
|
|
|
for (int index = 0; index < type.getOuterArraySize(); ++index) {
|
|
|
|
// get the source member
|
|
|
|
spv::Id elementRValue = builder.createCompositeExtract(rValue, elementRType, index);
|
2016-09-02 17:20:21 +00:00
|
|
|
|
2016-09-11 18:33:43 +00:00
|
|
|
// set up the target storage
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainLValue(lValue);
|
2019-03-06 19:34:10 +00:00
|
|
|
builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type), type.getBufferReferenceAlignment());
|
2016-09-02 17:20:21 +00:00
|
|
|
|
2016-09-11 18:33:43 +00:00
|
|
|
// store the member
|
|
|
|
multiTypeStore(glslangElementType, elementRValue);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(type.isStruct());
|
2016-09-02 17:20:21 +00:00
|
|
|
|
2016-09-11 18:33:43 +00:00
|
|
|
// loop over structure members
|
|
|
|
const glslang::TTypeList& members = *type.getStruct();
|
|
|
|
for (int m = 0; m < (int)members.size(); ++m) {
|
|
|
|
const glslang::TType& glslangMemberType = *members[m].type;
|
|
|
|
|
|
|
|
// get the source member
|
|
|
|
spv::Id memberRType = builder.getContainedTypeId(rType, m);
|
|
|
|
spv::Id memberRValue = builder.createCompositeExtract(rValue, memberRType, m);
|
|
|
|
|
|
|
|
// set up the target storage
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainLValue(lValue);
|
2019-03-06 19:34:10 +00:00
|
|
|
builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type), type.getBufferReferenceAlignment());
|
2016-09-11 18:33:43 +00:00
|
|
|
|
|
|
|
// store the member
|
|
|
|
multiTypeStore(glslangMemberType, memberRValue);
|
|
|
|
}
|
2016-09-02 17:20:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-19 20:57:10 +00:00
|
|
|
// Decide whether or not this type should be
|
|
|
|
// decorated with offsets and strides, and if so
|
|
|
|
// whether std140 or std430 rules should be applied.
|
|
|
|
glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang::TType& type) const
|
2015-09-09 23:51:38 +00:00
|
|
|
{
|
2015-12-19 20:57:10 +00:00
|
|
|
// has to be a block
|
|
|
|
if (type.getBasicType() != glslang::EbtBlock)
|
|
|
|
return glslang::ElpNone;
|
|
|
|
|
2018-09-19 18:41:59 +00:00
|
|
|
// has to be a uniform or buffer block or task in/out blocks
|
2015-12-19 20:57:10 +00:00
|
|
|
if (type.getQualifier().storage != glslang::EvqUniform &&
|
2018-09-19 18:41:59 +00:00
|
|
|
type.getQualifier().storage != glslang::EvqBuffer &&
|
|
|
|
!type.getQualifier().isTaskMemory())
|
2015-12-19 20:57:10 +00:00
|
|
|
return glslang::ElpNone;
|
|
|
|
|
|
|
|
// return the layout to use
|
|
|
|
switch (type.getQualifier().layoutPacking) {
|
|
|
|
case glslang::ElpStd140:
|
|
|
|
case glslang::ElpStd430:
|
2018-11-14 15:30:53 +00:00
|
|
|
case glslang::ElpScalar:
|
2015-12-19 20:57:10 +00:00
|
|
|
return type.getQualifier().layoutPacking;
|
|
|
|
default:
|
|
|
|
return glslang::ElpNone;
|
|
|
|
}
|
2015-09-09 23:51:38 +00:00
|
|
|
}
|
|
|
|
|
2015-09-05 16:50:58 +00:00
|
|
|
// Given an array type, returns the integer stride required for that array
|
2015-12-20 18:29:16 +00:00
|
|
|
int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
|
2015-09-05 16:50:58 +00:00
|
|
|
{
|
|
|
|
int size;
|
2015-12-30 00:11:44 +00:00
|
|
|
int stride;
|
2018-11-14 15:30:53 +00:00
|
|
|
glslangIntermediate->getMemberAlignment(arrayType, size, stride, explicitLayout, matrixLayout == glslang::ElmRowMajor);
|
2015-12-07 02:17:49 +00:00
|
|
|
|
|
|
|
return stride;
|
2015-09-05 16:50:58 +00:00
|
|
|
}
|
|
|
|
|
2015-12-30 00:11:44 +00:00
|
|
|
// Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix
|
2015-09-05 16:50:58 +00:00
|
|
|
// when used as a member of an interface block
|
2015-12-20 18:29:16 +00:00
|
|
|
int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
|
2015-09-05 16:50:58 +00:00
|
|
|
{
|
2015-12-30 00:11:44 +00:00
|
|
|
glslang::TType elementType;
|
|
|
|
elementType.shallowCopy(matrixType);
|
|
|
|
elementType.clearArraySizes();
|
|
|
|
|
2015-09-05 16:50:58 +00:00
|
|
|
int size;
|
2015-12-30 00:11:44 +00:00
|
|
|
int stride;
|
2018-11-14 15:30:53 +00:00
|
|
|
glslangIntermediate->getMemberAlignment(elementType, size, stride, explicitLayout, matrixLayout == glslang::ElmRowMajor);
|
2015-12-30 00:11:44 +00:00
|
|
|
|
|
|
|
return stride;
|
2015-09-05 16:50:58 +00:00
|
|
|
}
|
|
|
|
|
2015-08-07 04:53:06 +00:00
|
|
|
// Given a member type of a struct, realign the current offset for it, and compute
|
|
|
|
// the next (not yet aligned) offset for the next member, which will get aligned
|
|
|
|
// on the next call.
|
|
|
|
// 'currentOffset' should be passed in already initialized, ready to modify, and reflecting
|
|
|
|
// the migration of data from nextOffset -> currentOffset. It should be -1 on the first call.
|
|
|
|
// -1 means a non-forced member offset (no decoration needed).
|
2017-07-13 17:39:16 +00:00
|
|
|
void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset,
|
2015-12-20 18:29:16 +00:00
|
|
|
glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
|
2015-08-07 04:53:06 +00:00
|
|
|
{
|
|
|
|
// this will get a positive value when deemed necessary
|
|
|
|
nextOffset = -1;
|
|
|
|
|
|
|
|
// override anything in currentOffset with user-set offset
|
|
|
|
if (memberType.getQualifier().hasOffset())
|
|
|
|
currentOffset = memberType.getQualifier().layoutOffset;
|
|
|
|
|
|
|
|
// It could be that current linker usage in glslang updated all the layoutOffset,
|
|
|
|
// in which case the following code does not matter. But, that's not quite right
|
|
|
|
// once cross-compilation unit GLSL validation is done, as the original user
|
|
|
|
// settings are needed in layoutOffset, and then the following will come into play.
|
|
|
|
|
2015-12-19 20:57:10 +00:00
|
|
|
if (explicitLayout == glslang::ElpNone) {
|
2015-08-07 04:53:06 +00:00
|
|
|
if (! memberType.getQualifier().hasOffset())
|
|
|
|
currentOffset = -1;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-12-19 20:57:10 +00:00
|
|
|
// Getting this far means we need explicit offsets
|
2015-08-07 04:53:06 +00:00
|
|
|
if (currentOffset < 0)
|
|
|
|
currentOffset = 0;
|
2016-05-06 21:25:16 +00:00
|
|
|
|
2015-08-07 04:53:06 +00:00
|
|
|
// Now, currentOffset is valid (either 0, or from a previous nextOffset),
|
|
|
|
// but possibly not yet correctly aligned.
|
|
|
|
|
|
|
|
int memberSize;
|
2015-12-30 00:11:44 +00:00
|
|
|
int dummyStride;
|
2018-11-14 15:30:53 +00:00
|
|
|
int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout, matrixLayout == glslang::ElmRowMajor);
|
2017-04-05 23:38:20 +00:00
|
|
|
|
|
|
|
// Adjust alignment for HLSL rules
|
2017-07-13 17:39:16 +00:00
|
|
|
// TODO: make this consistent in early phases of code:
|
|
|
|
// adjusting this late means inconsistencies with earlier code, which for reflection is an issue
|
|
|
|
// Until reflection is brought in sync with these adjustments, don't apply to $Global,
|
|
|
|
// which is the most likely to rely on reflection, and least likely to rely implicit layouts
|
2018-08-22 23:12:46 +00:00
|
|
|
if (glslangIntermediate->usingHlslOffsets() &&
|
2017-07-13 17:39:16 +00:00
|
|
|
! memberType.isArray() && memberType.isVector() && structType.getTypeName().compare("$Global") != 0) {
|
2017-04-05 23:38:20 +00:00
|
|
|
int dummySize;
|
|
|
|
int componentAlignment = glslangIntermediate->getBaseAlignmentScalar(memberType, dummySize);
|
|
|
|
if (componentAlignment <= 4)
|
|
|
|
memberAlignment = componentAlignment;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bump up to member alignment
|
2015-08-07 04:53:06 +00:00
|
|
|
glslang::RoundToPow2(currentOffset, memberAlignment);
|
2017-04-05 23:38:20 +00:00
|
|
|
|
|
|
|
// Bump up to vec4 if there is a bad straddle
|
2018-11-14 15:30:53 +00:00
|
|
|
if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize, currentOffset))
|
2017-04-05 23:38:20 +00:00
|
|
|
glslang::RoundToPow2(currentOffset, 16);
|
|
|
|
|
2015-08-07 04:53:06 +00:00
|
|
|
nextOffset = currentOffset + memberSize;
|
|
|
|
}
|
|
|
|
|
2016-06-08 13:11:40 +00:00
|
|
|
void TGlslangToSpvTraverser::declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember)
|
2016-05-17 01:22:05 +00:00
|
|
|
{
|
2016-06-08 13:11:40 +00:00
|
|
|
const glslang::TBuiltInVariable glslangBuiltIn = members[glslangMember].type->getQualifier().builtIn;
|
|
|
|
switch (glslangBuiltIn)
|
|
|
|
{
|
2019-08-06 13:00:58 +00:00
|
|
|
case glslang::EbvPointSize:
|
|
|
|
#ifndef GLSLANG_WEB
|
2016-06-08 13:11:40 +00:00
|
|
|
case glslang::EbvClipDistance:
|
|
|
|
case glslang::EbvCullDistance:
|
2017-01-13 09:10:53 +00:00
|
|
|
case glslang::EbvViewportMaskNV:
|
|
|
|
case glslang::EbvSecondaryPositionNV:
|
|
|
|
case glslang::EbvSecondaryViewportMaskNV:
|
2017-02-14 22:52:34 +00:00
|
|
|
case glslang::EbvPositionPerViewNV:
|
|
|
|
case glslang::EbvViewportMaskPerViewNV:
|
2018-09-19 18:41:59 +00:00
|
|
|
case glslang::EbvTaskCountNV:
|
|
|
|
case glslang::EbvPrimitiveCountNV:
|
|
|
|
case glslang::EbvPrimitiveIndicesNV:
|
|
|
|
case glslang::EbvClipDistancePerViewNV:
|
|
|
|
case glslang::EbvCullDistancePerViewNV:
|
|
|
|
case glslang::EbvLayerPerViewNV:
|
|
|
|
case glslang::EbvMeshViewCountNV:
|
|
|
|
case glslang::EbvMeshViewIndicesNV:
|
2017-01-13 09:10:53 +00:00
|
|
|
#endif
|
2016-06-08 13:11:40 +00:00
|
|
|
// Generate the associated capability. Delegate to TranslateBuiltInDecoration.
|
|
|
|
// Alternately, we could just call this for any glslang built-in, since the
|
|
|
|
// capability already guards against duplicates.
|
|
|
|
TranslateBuiltInDecoration(glslangBuiltIn, false);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Capabilities were already generated when the struct was declared.
|
|
|
|
break;
|
|
|
|
}
|
2016-05-17 01:22:05 +00:00
|
|
|
}
|
|
|
|
|
2016-09-19 22:01:41 +00:00
|
|
|
bool TGlslangToSpvTraverser::isShaderEntryPoint(const glslang::TIntermAggregate* node)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2016-09-20 00:09:30 +00:00
|
|
|
return node->getName().compare(glslangIntermediate->getEntryPointMangledName().c_str()) == 0;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
2017-09-10 21:21:05 +00:00
|
|
|
// Does parameter need a place to keep writes, separate from the original?
|
2017-12-04 09:48:10 +00:00
|
|
|
// Assumes called after originalParam(), which filters out block/buffer/opaque-based
|
|
|
|
// qualifiers such that we should have only in/out/inout/constreadonly here.
|
2018-05-04 17:43:03 +00:00
|
|
|
bool TGlslangToSpvTraverser::writableParam(glslang::TStorageQualifier qualifier) const
|
2017-09-10 21:21:05 +00:00
|
|
|
{
|
2017-12-04 09:48:10 +00:00
|
|
|
assert(qualifier == glslang::EvqIn ||
|
|
|
|
qualifier == glslang::EvqOut ||
|
|
|
|
qualifier == glslang::EvqInOut ||
|
|
|
|
qualifier == glslang::EvqConstReadOnly);
|
2017-09-10 21:21:05 +00:00
|
|
|
return qualifier != glslang::EvqConstReadOnly;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is parameter pass-by-original?
|
|
|
|
bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier, const glslang::TType& paramType,
|
|
|
|
bool implicitThisParam)
|
|
|
|
{
|
|
|
|
if (implicitThisParam) // implicit this
|
|
|
|
return true;
|
|
|
|
if (glslangIntermediate->getSource() == glslang::EShSourceHlsl)
|
2017-12-04 09:48:10 +00:00
|
|
|
return paramType.getBasicType() == glslang::EbtBlock;
|
2017-09-10 21:21:05 +00:00
|
|
|
return paramType.containsOpaque() || // sampler, etc.
|
|
|
|
(paramType.getBasicType() == glslang::EbtBlock && qualifier == glslang::EvqBuffer); // SSBO
|
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
// Make all the functions, skeletally, without actually visiting their bodies.
|
|
|
|
void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
|
|
|
|
{
|
2019-01-06 23:58:04 +00:00
|
|
|
const auto getParamDecorations = [&](std::vector<spv::Decoration>& decorations, const glslang::TType& type, bool useVulkanMemoryModel) {
|
2017-07-18 08:35:46 +00:00
|
|
|
spv::Decoration paramPrecision = TranslatePrecisionDecoration(type);
|
|
|
|
if (paramPrecision != spv::NoPrecision)
|
|
|
|
decorations.push_back(paramPrecision);
|
2018-09-05 15:11:41 +00:00
|
|
|
TranslateMemoryDecoration(type.getQualifier(), decorations, useVulkanMemoryModel);
|
2019-08-01 09:28:08 +00:00
|
|
|
if (type.isReference()) {
|
2019-01-06 23:58:04 +00:00
|
|
|
// Original and non-writable params pass the pointer directly and
|
|
|
|
// use restrict/aliased, others are stored to a pointer in Function
|
|
|
|
// memory and use RestrictPointer/AliasedPointer.
|
|
|
|
if (originalParam(type.getQualifier().storage, type, false) ||
|
|
|
|
!writableParam(type.getQualifier().storage)) {
|
|
|
|
decorations.push_back(type.getQualifier().restrict ? spv::DecorationRestrict : spv::DecorationAliased);
|
|
|
|
} else {
|
|
|
|
decorations.push_back(type.getQualifier().restrict ? spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT);
|
|
|
|
}
|
|
|
|
}
|
2017-07-18 08:35:46 +00:00
|
|
|
};
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
for (int f = 0; f < (int)glslFunctions.size(); ++f) {
|
|
|
|
glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
|
2016-09-19 22:01:41 +00:00
|
|
|
if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntryPoint(glslFunction))
|
2015-06-26 22:58:36 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// We're on a user function. Set up the basic interface for the function now,
|
2016-09-02 17:20:21 +00:00
|
|
|
// so that it's available to call. Translating the body will happen later.
|
2015-06-26 22:58:36 +00:00
|
|
|
//
|
2016-05-06 21:25:16 +00:00
|
|
|
// Typically (except for a "const in" parameter), an address will be passed to the
|
2015-06-26 22:58:36 +00:00
|
|
|
// function. What it is an address of varies:
|
|
|
|
//
|
2016-09-02 17:20:21 +00:00
|
|
|
// - "in" parameters not marked as "const" can be written to without modifying the calling
|
|
|
|
// argument so that write needs to be to a copy, hence the address of a copy works.
|
2015-06-26 22:58:36 +00:00
|
|
|
//
|
|
|
|
// - "const in" parameters can just be the r-value, as no writes need occur.
|
|
|
|
//
|
2016-09-02 17:20:21 +00:00
|
|
|
// - "out" and "inout" arguments can't be done as pointers to the calling argument, because
|
|
|
|
// GLSL has copy-in/copy-out semantics. They can be handled though with a pointer to a copy.
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
std::vector<spv::Id> paramTypes;
|
2017-07-18 08:35:46 +00:00
|
|
|
std::vector<std::vector<spv::Decoration>> paramDecorations; // list of decorations per parameter
|
2015-06-26 22:58:36 +00:00
|
|
|
glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
|
|
|
|
|
2019-08-09 05:29:20 +00:00
|
|
|
#ifdef ENABLE_HLSL
|
2017-07-18 08:35:46 +00:00
|
|
|
bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() ==
|
|
|
|
glslangIntermediate->implicitThisName;
|
2019-08-09 05:29:20 +00:00
|
|
|
#else
|
|
|
|
bool implicitThis = false;
|
|
|
|
#endif
|
2017-03-22 05:56:40 +00:00
|
|
|
|
2017-07-18 08:35:46 +00:00
|
|
|
paramDecorations.resize(parameters.size());
|
2015-06-26 22:58:36 +00:00
|
|
|
for (int p = 0; p < (int)parameters.size(); ++p) {
|
|
|
|
const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
|
|
|
|
spv::Id typeId = convertGlslangToSpvType(paramType);
|
2017-09-10 21:21:05 +00:00
|
|
|
if (originalParam(paramType.getQualifier().storage, paramType, implicitThis && p == 0))
|
2017-05-05 11:09:58 +00:00
|
|
|
typeId = builder.makePointer(TranslateStorageClass(paramType), typeId);
|
2017-09-10 21:21:05 +00:00
|
|
|
else if (writableParam(paramType.getQualifier().storage))
|
2015-06-26 22:58:36 +00:00
|
|
|
typeId = builder.makePointer(spv::StorageClassFunction, typeId);
|
|
|
|
else
|
2016-09-02 17:20:21 +00:00
|
|
|
rValueParameters.insert(parameters[p]->getAsSymbolNode()->getId());
|
2018-09-05 15:11:41 +00:00
|
|
|
getParamDecorations(paramDecorations[p], paramType, glslangIntermediate->usingVulkanMemoryModel());
|
2015-06-26 22:58:36 +00:00
|
|
|
paramTypes.push_back(typeId);
|
|
|
|
}
|
|
|
|
|
|
|
|
spv::Block* functionBlock;
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Function *function = builder.makeFunctionEntry(TranslatePrecisionDecoration(glslFunction->getType()),
|
|
|
|
convertGlslangToSpvType(glslFunction->getType()),
|
2017-07-18 08:35:46 +00:00
|
|
|
glslFunction->getName().c_str(), paramTypes,
|
|
|
|
paramDecorations, &functionBlock);
|
2017-03-22 05:56:40 +00:00
|
|
|
if (implicitThis)
|
|
|
|
function->setImplicitThis();
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
// Track function to emit/call later
|
|
|
|
functionMap[glslFunction->getName().c_str()] = function;
|
|
|
|
|
|
|
|
// Set the parameter id's
|
|
|
|
for (int p = 0; p < (int)parameters.size(); ++p) {
|
|
|
|
symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);
|
|
|
|
// give a name too
|
|
|
|
builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());
|
2019-02-18 04:49:28 +00:00
|
|
|
|
|
|
|
const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
|
2019-08-11 13:41:45 +00:00
|
|
|
if (paramType.contains8BitInt())
|
2019-02-18 04:49:28 +00:00
|
|
|
builder.addCapability(spv::CapabilityInt8);
|
2019-08-11 13:41:45 +00:00
|
|
|
if (paramType.contains16BitInt())
|
2019-02-18 04:49:28 +00:00
|
|
|
builder.addCapability(spv::CapabilityInt16);
|
2019-08-11 13:41:45 +00:00
|
|
|
if (paramType.contains16BitFloat())
|
2019-02-18 04:49:28 +00:00
|
|
|
builder.addCapability(spv::CapabilityFloat16);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process all the initializers, while skipping the functions and link objects
|
|
|
|
void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)
|
|
|
|
{
|
|
|
|
builder.setBuildPoint(shaderEntry->getLastBlock());
|
|
|
|
for (int i = 0; i < (int)initializers.size(); ++i) {
|
|
|
|
glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();
|
|
|
|
if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) {
|
|
|
|
|
|
|
|
// We're on a top-level node that's not a function. Treat as an initializer, whose
|
2016-09-19 22:01:41 +00:00
|
|
|
// code goes into the beginning of the entry point.
|
2015-06-26 22:58:36 +00:00
|
|
|
initializer->traverse(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process all the functions, while skipping initializers.
|
|
|
|
void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)
|
|
|
|
{
|
|
|
|
for (int f = 0; f < (int)glslFunctions.size(); ++f) {
|
|
|
|
glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();
|
2016-12-09 04:01:59 +00:00
|
|
|
if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang::EOpLinkerObjects))
|
2015-06-26 22:58:36 +00:00
|
|
|
node->traverse(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)
|
|
|
|
{
|
2016-05-06 21:25:16 +00:00
|
|
|
// SPIR-V functions should already be in the functionMap from the prepass
|
2015-06-26 22:58:36 +00:00
|
|
|
// that called makeFunctions().
|
2016-10-06 18:59:51 +00:00
|
|
|
currentFunction = functionMap[node->getName().c_str()];
|
|
|
|
spv::Block* functionBlock = currentFunction->getEntryBlock();
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.setBuildPoint(functionBlock);
|
|
|
|
}
|
|
|
|
|
2019-06-14 14:56:28 +00:00
|
|
|
void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments, spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2015-09-09 08:42:49 +00:00
|
|
|
const glslang::TIntermSequence& glslangArguments = node.getSequence();
|
2015-12-31 08:11:41 +00:00
|
|
|
|
|
|
|
glslang::TSampler sampler = {};
|
|
|
|
bool cubeCompare = false;
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2016-11-29 09:36:31 +00:00
|
|
|
bool f16ShadowCompare = false;
|
|
|
|
#endif
|
2016-02-19 14:24:03 +00:00
|
|
|
if (node.isTexture() || node.isImage()) {
|
2015-12-31 08:11:41 +00:00
|
|
|
sampler = glslangArguments[0]->getAsTyped()->getType().getSampler();
|
|
|
|
cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2016-11-29 09:36:31 +00:00
|
|
|
f16ShadowCompare = sampler.shadow && glslangArguments[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16;
|
|
|
|
#endif
|
2015-12-31 08:11:41 +00:00
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
for (int i = 0; i < (int)glslangArguments.size(); ++i) {
|
|
|
|
builder.clearAccessChain();
|
|
|
|
glslangArguments[i]->traverse(this);
|
2015-09-09 08:42:49 +00:00
|
|
|
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2015-09-09 08:42:49 +00:00
|
|
|
// Special case l-value operands
|
|
|
|
bool lvalue = false;
|
|
|
|
switch (node.getOp()) {
|
|
|
|
case glslang::EOpImageAtomicAdd:
|
|
|
|
case glslang::EOpImageAtomicMin:
|
|
|
|
case glslang::EOpImageAtomicMax:
|
|
|
|
case glslang::EOpImageAtomicAnd:
|
|
|
|
case glslang::EOpImageAtomicOr:
|
|
|
|
case glslang::EOpImageAtomicXor:
|
|
|
|
case glslang::EOpImageAtomicExchange:
|
|
|
|
case glslang::EOpImageAtomicCompSwap:
|
2018-09-05 15:11:41 +00:00
|
|
|
case glslang::EOpImageAtomicLoad:
|
|
|
|
case glslang::EOpImageAtomicStore:
|
2015-09-09 08:42:49 +00:00
|
|
|
if (i == 0)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2016-02-19 14:24:03 +00:00
|
|
|
case glslang::EOpSparseImageLoad:
|
|
|
|
if ((sampler.ms && i == 3) || (! sampler.ms && i == 2))
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2016-11-29 09:36:31 +00:00
|
|
|
case glslang::EOpSparseTexture:
|
|
|
|
if (((cubeCompare || f16ShadowCompare) && i == 3) || (! (cubeCompare || f16ShadowCompare) && i == 2))
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpSparseTextureClamp:
|
|
|
|
if (((cubeCompare || f16ShadowCompare) && i == 4) || (! (cubeCompare || f16ShadowCompare) && i == 3))
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpSparseTextureLod:
|
|
|
|
case glslang::EOpSparseTextureOffset:
|
|
|
|
if ((f16ShadowCompare && i == 4) || (! f16ShadowCompare && i == 3))
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2015-12-31 08:11:41 +00:00
|
|
|
case glslang::EOpSparseTextureFetch:
|
|
|
|
if ((sampler.dim != glslang::EsdRect && i == 3) || (sampler.dim == glslang::EsdRect && i == 2))
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpSparseTextureFetchOffset:
|
|
|
|
if ((sampler.dim != glslang::EsdRect && i == 4) || (sampler.dim == glslang::EsdRect && i == 3))
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2016-11-29 09:36:31 +00:00
|
|
|
case glslang::EOpSparseTextureLodOffset:
|
|
|
|
case glslang::EOpSparseTextureGrad:
|
|
|
|
case glslang::EOpSparseTextureOffsetClamp:
|
|
|
|
if ((f16ShadowCompare && i == 5) || (! f16ShadowCompare && i == 4))
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpSparseTextureGradOffset:
|
|
|
|
case glslang::EOpSparseTextureGradClamp:
|
|
|
|
if ((f16ShadowCompare && i == 6) || (! f16ShadowCompare && i == 5))
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpSparseTextureGradOffsetClamp:
|
|
|
|
if ((f16ShadowCompare && i == 7) || (! f16ShadowCompare && i == 6))
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2016-11-17 09:47:59 +00:00
|
|
|
case glslang::EOpSparseTextureGather:
|
2015-12-31 08:11:41 +00:00
|
|
|
if ((sampler.shadow && i == 3) || (! sampler.shadow && i == 2))
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpSparseTextureGatherOffset:
|
|
|
|
case glslang::EOpSparseTextureGatherOffsets:
|
|
|
|
if ((sampler.shadow && i == 4) || (! sampler.shadow && i == 3))
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2016-11-17 09:47:59 +00:00
|
|
|
case glslang::EOpSparseTextureGatherLod:
|
|
|
|
if (i == 3)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpSparseTextureGatherLodOffset:
|
|
|
|
case glslang::EOpSparseTextureGatherLodOffsets:
|
|
|
|
if (i == 4)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2017-07-05 09:23:28 +00:00
|
|
|
case glslang::EOpSparseImageLoadLod:
|
|
|
|
if (i == 3)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2018-09-19 18:41:27 +00:00
|
|
|
case glslang::EOpImageSampleFootprintNV:
|
|
|
|
if (i == 4)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpImageSampleFootprintClampNV:
|
|
|
|
case glslang::EOpImageSampleFootprintLodNV:
|
|
|
|
if (i == 5)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpImageSampleFootprintGradNV:
|
|
|
|
if (i == 6)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
|
|
|
case glslang::EOpImageSampleFootprintGradClampNV:
|
|
|
|
if (i == 7)
|
|
|
|
lvalue = true;
|
|
|
|
break;
|
2015-09-09 08:42:49 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-06-14 14:56:28 +00:00
|
|
|
if (lvalue) {
|
2015-09-09 08:42:49 +00:00
|
|
|
arguments.push_back(builder.accessChainGetLValue());
|
2019-06-14 14:56:28 +00:00
|
|
|
lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
|
|
|
|
lvalueCoherentFlags |= TranslateCoherent(glslangArguments[i]->getAsTyped()->getType());
|
|
|
|
} else
|
2019-08-06 13:00:58 +00:00
|
|
|
#endif
|
2016-02-02 19:37:46 +00:00
|
|
|
arguments.push_back(accessChainLoad(glslangArguments[i]->getAsTyped()->getType()));
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
void TGlslangToSpvTraverser::translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2015-08-19 19:34:18 +00:00
|
|
|
builder.clearAccessChain();
|
|
|
|
node.getOperand()->traverse(this);
|
2016-02-02 19:37:46 +00:00
|
|
|
arguments.push_back(accessChainLoad(node.getOperand()->getType()));
|
2015-08-19 19:34:18 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node)
|
|
|
|
{
|
2017-06-01 00:50:53 +00:00
|
|
|
if (! node->isImage() && ! node->isTexture())
|
2015-08-19 19:34:18 +00:00
|
|
|
return spv::NoResult;
|
2017-06-01 00:50:53 +00:00
|
|
|
|
2018-12-08 00:36:33 +00:00
|
|
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
2017-06-01 00:50:53 +00:00
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
// Process a GLSL texturing op (will be SPV image)
|
2018-09-05 15:11:41 +00:00
|
|
|
|
2019-03-31 16:51:57 +00:00
|
|
|
const glslang::TType &imageType = node->getAsAggregate()
|
|
|
|
? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType()
|
|
|
|
: node->getAsUnaryNode()->getOperand()->getAsTyped()->getType();
|
2018-09-05 15:11:41 +00:00
|
|
|
const glslang::TSampler sampler = imageType.getSampler();
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifdef GLSLANG_WEB
|
|
|
|
const bool f16ShadowCompare = false;
|
|
|
|
#else
|
2016-11-29 09:36:31 +00:00
|
|
|
bool f16ShadowCompare = (sampler.shadow && node->getAsAggregate())
|
2019-03-31 16:51:57 +00:00
|
|
|
? node->getAsAggregate()->getSequence()[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16
|
|
|
|
: false;
|
2016-11-29 09:36:31 +00:00
|
|
|
#endif
|
|
|
|
|
2019-03-31 16:51:57 +00:00
|
|
|
const auto signExtensionMask = [&]() {
|
|
|
|
if (builder.getSpvVersion() >= spv::Spv_1_4) {
|
|
|
|
if (sampler.type == glslang::EbtUint)
|
|
|
|
return spv::ImageOperandsZeroExtendMask;
|
|
|
|
else if (sampler.type == glslang::EbtInt)
|
|
|
|
return spv::ImageOperandsSignExtendMask;
|
|
|
|
}
|
|
|
|
return spv::ImageOperandsMaskNone;
|
|
|
|
};
|
|
|
|
|
2019-06-14 14:56:28 +00:00
|
|
|
spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
|
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
std::vector<spv::Id> arguments;
|
|
|
|
if (node->getAsAggregate())
|
2019-06-14 14:56:28 +00:00
|
|
|
translateArguments(*node->getAsAggregate(), arguments, lvalueCoherentFlags);
|
2015-08-19 19:34:18 +00:00
|
|
|
else
|
|
|
|
translateArguments(*node->getAsUnaryNode(), arguments);
|
2016-08-02 01:44:00 +00:00
|
|
|
spv::Decoration precision = TranslatePrecisionDecoration(node->getOperationPrecision());
|
2015-08-19 19:34:18 +00:00
|
|
|
|
|
|
|
spv::Builder::TextureParameters params = { };
|
|
|
|
params.sampler = arguments[0];
|
|
|
|
|
2015-09-16 03:44:02 +00:00
|
|
|
glslang::TCrackedTextureOp cracked;
|
|
|
|
node->crackTexture(sampler, cracked);
|
|
|
|
|
2017-06-13 20:53:02 +00:00
|
|
|
const bool isUnsignedResult = node->getType().getBasicType() == glslang::EbtUint;
|
2017-03-10 19:45:50 +00:00
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
// Check for queries
|
|
|
|
if (cracked.query) {
|
2016-10-12 13:40:37 +00:00
|
|
|
// OpImageQueryLod works on a sampled image, for other queries the image has to be extracted first
|
|
|
|
if (node->getOp() != glslang::EOpTextureQueryLod && builder.isSampledImage(params.sampler))
|
2015-12-09 02:32:47 +00:00
|
|
|
params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler);
|
2016-10-12 13:40:37 +00:00
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
switch (node->getOp()) {
|
|
|
|
case glslang::EOpImageQuerySize:
|
|
|
|
case glslang::EOpTextureQuerySize:
|
2015-06-26 22:58:36 +00:00
|
|
|
if (arguments.size() > 1) {
|
|
|
|
params.lod = arguments[1];
|
2017-03-10 19:45:50 +00:00
|
|
|
return builder.createTextureQueryCall(spv::OpImageQuerySizeLod, params, isUnsignedResult);
|
2015-06-26 22:58:36 +00:00
|
|
|
} else
|
2017-03-10 19:45:50 +00:00
|
|
|
return builder.createTextureQueryCall(spv::OpImageQuerySize, params, isUnsignedResult);
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2015-08-19 19:34:18 +00:00
|
|
|
case glslang::EOpImageQuerySamples:
|
|
|
|
case glslang::EOpTextureQuerySamples:
|
2017-03-10 19:45:50 +00:00
|
|
|
return builder.createTextureQueryCall(spv::OpImageQuerySamples, params, isUnsignedResult);
|
2015-08-19 19:34:18 +00:00
|
|
|
case glslang::EOpTextureQueryLod:
|
|
|
|
params.coords = arguments[1];
|
2017-03-10 19:45:50 +00:00
|
|
|
return builder.createTextureQueryCall(spv::OpImageQueryLod, params, isUnsignedResult);
|
2015-08-19 19:34:18 +00:00
|
|
|
case glslang::EOpTextureQueryLevels:
|
2017-03-10 19:45:50 +00:00
|
|
|
return builder.createTextureQueryCall(spv::OpImageQueryLevels, params, isUnsignedResult);
|
2015-12-31 08:11:41 +00:00
|
|
|
case glslang::EOpSparseTexelsResident:
|
|
|
|
return builder.createUnaryOp(spv::OpImageSparseTexelsResident, builder.makeBoolType(), arguments[0]);
|
2019-08-06 13:00:58 +00:00
|
|
|
#endif
|
2015-08-19 19:34:18 +00:00
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
break;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
2015-08-19 19:34:18 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2018-02-18 18:40:01 +00:00
|
|
|
int components = node->getType().getVectorSize();
|
|
|
|
|
|
|
|
if (node->getOp() == glslang::EOpTextureFetch) {
|
|
|
|
// These must produce 4 components, per SPIR-V spec. We'll add a conversion constructor if needed.
|
|
|
|
// This will only happen through the HLSL path for operator[], so we do not have to handle e.g.
|
|
|
|
// the EOpTexture/Proj/Lod/etc family. It would be harmless to do so, but would need more logic
|
|
|
|
// here around e.g. which ones return scalars or other types.
|
|
|
|
components = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
glslang::TType returnType(node->getType().getBasicType(), glslang::EvqTemporary, components);
|
|
|
|
|
|
|
|
auto resultType = [&returnType,this]{ return convertGlslangToSpvType(returnType); };
|
|
|
|
|
2015-09-09 08:42:49 +00:00
|
|
|
// Check for image functions other than queries
|
|
|
|
if (node->isImage()) {
|
2018-08-14 19:31:43 +00:00
|
|
|
std::vector<spv::IdImmediate> operands;
|
2015-09-16 16:54:31 +00:00
|
|
|
auto opIt = arguments.begin();
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::IdImmediate image = { true, *(opIt++) };
|
|
|
|
operands.push_back(image);
|
2016-02-16 03:58:50 +00:00
|
|
|
|
|
|
|
// Handle subpass operations
|
|
|
|
// TODO: GLSL should change to have the "MS" only on the type rather than the
|
|
|
|
// built-in function.
|
|
|
|
if (cracked.subpass) {
|
|
|
|
// add on the (0,0) coordinate
|
|
|
|
spv::Id zero = builder.makeIntConstant(0);
|
|
|
|
std::vector<spv::Id> comps;
|
|
|
|
comps.push_back(zero);
|
|
|
|
comps.push_back(zero);
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::IdImmediate coord = { true,
|
|
|
|
builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps) };
|
|
|
|
operands.push_back(coord);
|
2019-03-31 16:51:57 +00:00
|
|
|
spv::IdImmediate imageOperands = { false, spv::ImageOperandsMaskNone };
|
|
|
|
imageOperands.word = imageOperands.word | signExtensionMask();
|
2019-08-08 07:15:24 +00:00
|
|
|
if (sampler.isMultiSample()) {
|
2019-03-31 16:51:57 +00:00
|
|
|
imageOperands.word = imageOperands.word | spv::ImageOperandsSampleMask;
|
|
|
|
}
|
|
|
|
if (imageOperands.word != spv::ImageOperandsMaskNone) {
|
2018-08-14 19:31:43 +00:00
|
|
|
operands.push_back(imageOperands);
|
2019-08-08 07:15:24 +00:00
|
|
|
if (sampler.isMultiSample()) {
|
2019-03-31 16:51:57 +00:00
|
|
|
spv::IdImmediate imageOperand = { true, *(opIt++) };
|
|
|
|
operands.push_back(imageOperand);
|
|
|
|
}
|
2016-02-16 03:58:50 +00:00
|
|
|
}
|
2017-10-19 08:07:30 +00:00
|
|
|
spv::Id result = builder.createOp(spv::OpImageRead, resultType(), operands);
|
|
|
|
builder.setPrecision(result, precision);
|
|
|
|
return result;
|
2016-02-16 03:58:50 +00:00
|
|
|
}
|
|
|
|
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::IdImmediate coord = { true, *(opIt++) };
|
|
|
|
operands.push_back(coord);
|
2017-07-05 09:23:28 +00:00
|
|
|
if (node->getOp() == glslang::EOpImageLoad || node->getOp() == glslang::EOpImageLoadLod) {
|
2018-09-05 15:11:41 +00:00
|
|
|
spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
|
2019-08-08 07:15:24 +00:00
|
|
|
if (sampler.isMultiSample()) {
|
2018-09-05 15:11:41 +00:00
|
|
|
mask = mask | spv::ImageOperandsSampleMask;
|
|
|
|
}
|
|
|
|
if (cracked.lod) {
|
2017-07-05 09:23:28 +00:00
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
|
|
|
|
builder.addCapability(spv::CapabilityImageReadWriteLodAMD);
|
2018-09-05 15:11:41 +00:00
|
|
|
mask = mask | spv::ImageOperandsLodMask;
|
|
|
|
}
|
|
|
|
mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
|
|
|
|
mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelAvailableKHRMask);
|
2019-03-31 16:51:57 +00:00
|
|
|
mask = mask | signExtensionMask();
|
2019-05-10 12:47:00 +00:00
|
|
|
if (mask != spv::ImageOperandsMaskNone) {
|
2018-09-05 15:11:41 +00:00
|
|
|
spv::IdImmediate imageOperands = { false, (unsigned int)mask };
|
2018-08-14 19:31:43 +00:00
|
|
|
operands.push_back(imageOperands);
|
2018-09-05 15:11:41 +00:00
|
|
|
}
|
|
|
|
if (mask & spv::ImageOperandsSampleMask) {
|
|
|
|
spv::IdImmediate imageOperand = { true, *opIt++ };
|
|
|
|
operands.push_back(imageOperand);
|
|
|
|
}
|
|
|
|
if (mask & spv::ImageOperandsLodMask) {
|
|
|
|
spv::IdImmediate imageOperand = { true, *opIt++ };
|
2018-08-14 19:31:43 +00:00
|
|
|
operands.push_back(imageOperand);
|
2018-09-05 15:11:41 +00:00
|
|
|
}
|
|
|
|
if (mask & spv::ImageOperandsMakeTexelVisibleKHRMask) {
|
2019-03-31 16:51:57 +00:00
|
|
|
spv::IdImmediate imageOperand = { true,
|
|
|
|
builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) };
|
2018-09-05 15:11:41 +00:00
|
|
|
operands.push_back(imageOperand);
|
2015-11-16 04:33:39 +00:00
|
|
|
}
|
2018-09-05 15:11:41 +00:00
|
|
|
|
2018-08-14 19:31:43 +00:00
|
|
|
if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)
|
2016-02-15 18:57:00 +00:00
|
|
|
builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);
|
2017-10-19 08:07:30 +00:00
|
|
|
|
2018-08-14 19:31:43 +00:00
|
|
|
std::vector<spv::Id> result(1, builder.createOp(spv::OpImageRead, resultType(), operands));
|
2018-02-18 18:40:01 +00:00
|
|
|
builder.setPrecision(result[0], precision);
|
|
|
|
|
|
|
|
// If needed, add a conversion constructor to the proper size.
|
|
|
|
if (components != node->getType().getVectorSize())
|
|
|
|
result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType()));
|
|
|
|
|
|
|
|
return result[0];
|
2017-07-05 09:23:28 +00:00
|
|
|
} else if (node->getOp() == glslang::EOpImageStore || node->getOp() == glslang::EOpImageStoreLod) {
|
2018-09-05 15:11:41 +00:00
|
|
|
|
|
|
|
// Push the texel value before the operands
|
2019-08-08 07:15:24 +00:00
|
|
|
if (sampler.isMultiSample() || cracked.lod) {
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::IdImmediate texel = { true, *(opIt + 1) };
|
|
|
|
operands.push_back(texel);
|
2018-09-05 15:11:41 +00:00
|
|
|
} else {
|
|
|
|
spv::IdImmediate texel = { true, *opIt };
|
|
|
|
operands.push_back(texel);
|
|
|
|
}
|
|
|
|
|
|
|
|
spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
|
2019-08-08 07:15:24 +00:00
|
|
|
if (sampler.isMultiSample()) {
|
2018-09-05 15:11:41 +00:00
|
|
|
mask = mask | spv::ImageOperandsSampleMask;
|
|
|
|
}
|
|
|
|
if (cracked.lod) {
|
2017-07-05 09:23:28 +00:00
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
|
|
|
|
builder.addCapability(spv::CapabilityImageReadWriteLodAMD);
|
2018-09-05 15:11:41 +00:00
|
|
|
mask = mask | spv::ImageOperandsLodMask;
|
|
|
|
}
|
|
|
|
mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
|
|
|
|
mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelVisibleKHRMask);
|
2019-03-31 16:51:57 +00:00
|
|
|
mask = mask | signExtensionMask();
|
2019-05-10 12:47:00 +00:00
|
|
|
if (mask != spv::ImageOperandsMaskNone) {
|
2018-09-05 15:11:41 +00:00
|
|
|
spv::IdImmediate imageOperands = { false, (unsigned int)mask };
|
2018-08-14 19:31:43 +00:00
|
|
|
operands.push_back(imageOperands);
|
2018-09-05 15:11:41 +00:00
|
|
|
}
|
|
|
|
if (mask & spv::ImageOperandsSampleMask) {
|
|
|
|
spv::IdImmediate imageOperand = { true, *opIt++ };
|
|
|
|
operands.push_back(imageOperand);
|
|
|
|
}
|
|
|
|
if (mask & spv::ImageOperandsLodMask) {
|
|
|
|
spv::IdImmediate imageOperand = { true, *opIt++ };
|
2018-08-14 19:31:43 +00:00
|
|
|
operands.push_back(imageOperand);
|
2018-09-05 15:11:41 +00:00
|
|
|
}
|
|
|
|
if (mask & spv::ImageOperandsMakeTexelAvailableKHRMask) {
|
2019-03-31 16:51:57 +00:00
|
|
|
spv::IdImmediate imageOperand = { true,
|
|
|
|
builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) };
|
2018-09-05 15:11:41 +00:00
|
|
|
operands.push_back(imageOperand);
|
2018-08-14 19:31:43 +00:00
|
|
|
}
|
2018-09-05 15:11:41 +00:00
|
|
|
|
2015-09-16 16:54:31 +00:00
|
|
|
builder.createNoResultOp(spv::OpImageWrite, operands);
|
2018-08-14 19:31:43 +00:00
|
|
|
if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)
|
2016-02-15 18:57:00 +00:00
|
|
|
builder.addCapability(spv::CapabilityStorageImageWriteWithoutFormat);
|
2015-09-16 16:54:31 +00:00
|
|
|
return spv::NoResult;
|
2019-03-31 16:51:57 +00:00
|
|
|
} else if (node->getOp() == glslang::EOpSparseImageLoad ||
|
|
|
|
node->getOp() == glslang::EOpSparseImageLoadLod) {
|
2016-02-19 14:24:03 +00:00
|
|
|
builder.addCapability(spv::CapabilitySparseResidency);
|
2018-08-14 19:31:43 +00:00
|
|
|
if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)
|
2016-02-19 14:24:03 +00:00
|
|
|
builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);
|
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
|
2019-08-08 07:15:24 +00:00
|
|
|
if (sampler.isMultiSample()) {
|
2018-09-05 15:11:41 +00:00
|
|
|
mask = mask | spv::ImageOperandsSampleMask;
|
|
|
|
}
|
|
|
|
if (cracked.lod) {
|
2017-07-05 09:23:28 +00:00
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
|
|
|
|
builder.addCapability(spv::CapabilityImageReadWriteLodAMD);
|
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
mask = mask | spv::ImageOperandsLodMask;
|
|
|
|
}
|
|
|
|
mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
|
|
|
|
mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelAvailableKHRMask);
|
2019-03-31 16:51:57 +00:00
|
|
|
mask = mask | signExtensionMask();
|
2019-05-10 12:47:00 +00:00
|
|
|
if (mask != spv::ImageOperandsMaskNone) {
|
2018-09-05 15:11:41 +00:00
|
|
|
spv::IdImmediate imageOperands = { false, (unsigned int)mask };
|
2018-08-14 19:31:43 +00:00
|
|
|
operands.push_back(imageOperands);
|
2018-09-05 15:11:41 +00:00
|
|
|
}
|
|
|
|
if (mask & spv::ImageOperandsSampleMask) {
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::IdImmediate imageOperand = { true, *opIt++ };
|
|
|
|
operands.push_back(imageOperand);
|
2018-09-05 15:11:41 +00:00
|
|
|
}
|
|
|
|
if (mask & spv::ImageOperandsLodMask) {
|
|
|
|
spv::IdImmediate imageOperand = { true, *opIt++ };
|
|
|
|
operands.push_back(imageOperand);
|
|
|
|
}
|
|
|
|
if (mask & spv::ImageOperandsMakeTexelVisibleKHRMask) {
|
|
|
|
spv::IdImmediate imageOperand = { true, builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) };
|
|
|
|
operands.push_back(imageOperand);
|
2016-02-19 14:24:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the return type that was a special structure
|
|
|
|
spv::Id texelOut = *opIt;
|
2016-07-26 18:50:38 +00:00
|
|
|
spv::Id typeId0 = resultType();
|
2016-02-19 14:24:03 +00:00
|
|
|
spv::Id typeId1 = builder.getDerefTypeId(texelOut);
|
|
|
|
spv::Id resultTypeId = builder.makeStructResultType(typeId0, typeId1);
|
|
|
|
|
|
|
|
spv::Id resultId = builder.createOp(spv::OpImageSparseRead, resultTypeId, operands);
|
|
|
|
|
|
|
|
// Decode the return type
|
|
|
|
builder.createStore(builder.createCompositeExtract(resultId, typeId1, 1), texelOut);
|
|
|
|
return builder.createCompositeExtract(resultId, typeId0, 0);
|
2016-01-22 16:54:12 +00:00
|
|
|
} else {
|
2015-09-16 09:48:22 +00:00
|
|
|
// Process image atomic operations
|
|
|
|
|
|
|
|
// GLSL "IMAGE_PARAMS" will involve in constructing an image texel pointer and this pointer,
|
|
|
|
// as the first source operand, is required by SPIR-V atomic operations.
|
2018-08-14 19:31:43 +00:00
|
|
|
// For non-MS, the sample value should be 0
|
2019-08-08 07:15:24 +00:00
|
|
|
spv::IdImmediate sample = { true, sampler.isMultiSample() ? *(opIt++) : builder.makeUintConstant(0) };
|
2018-08-14 19:31:43 +00:00
|
|
|
operands.push_back(sample);
|
2015-09-09 08:42:49 +00:00
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
spv::Id resultTypeId;
|
|
|
|
// imageAtomicStore has a void return type so base the pointer type on
|
|
|
|
// the type of the value operand.
|
|
|
|
if (node->getOp() == glslang::EOpImageAtomicStore) {
|
|
|
|
resultTypeId = builder.makePointer(spv::StorageClassImage, builder.getTypeId(operands[2].word));
|
|
|
|
} else {
|
|
|
|
resultTypeId = builder.makePointer(spv::StorageClassImage, resultType());
|
|
|
|
}
|
2015-09-16 16:54:31 +00:00
|
|
|
spv::Id pointer = builder.createOp(spv::OpImageTexelPointer, resultTypeId, operands);
|
2015-09-09 08:42:49 +00:00
|
|
|
|
|
|
|
std::vector<spv::Id> operands;
|
|
|
|
operands.push_back(pointer);
|
|
|
|
for (; opIt != arguments.end(); ++opIt)
|
|
|
|
operands.push_back(*opIt);
|
|
|
|
|
2019-06-14 14:56:28 +00:00
|
|
|
return createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType(), lvalueCoherentFlags);
|
2015-09-09 08:42:49 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2017-06-13 20:53:02 +00:00
|
|
|
// Check for fragment mask functions other than queries
|
|
|
|
if (cracked.fragMask) {
|
|
|
|
assert(sampler.ms);
|
|
|
|
|
|
|
|
auto opIt = arguments.begin();
|
|
|
|
std::vector<spv::Id> operands;
|
|
|
|
|
|
|
|
// Extract the image if necessary
|
|
|
|
if (builder.isSampledImage(params.sampler))
|
|
|
|
params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler);
|
|
|
|
|
|
|
|
operands.push_back(params.sampler);
|
|
|
|
++opIt;
|
|
|
|
|
|
|
|
if (sampler.isSubpass()) {
|
|
|
|
// add on the (0,0) coordinate
|
|
|
|
spv::Id zero = builder.makeIntConstant(0);
|
|
|
|
std::vector<spv::Id> comps;
|
|
|
|
comps.push_back(zero);
|
|
|
|
comps.push_back(zero);
|
|
|
|
operands.push_back(builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; opIt != arguments.end(); ++opIt)
|
|
|
|
operands.push_back(*opIt);
|
|
|
|
|
|
|
|
spv::Op fragMaskOp = spv::OpNop;
|
|
|
|
if (node->getOp() == glslang::EOpFragmentMaskFetch)
|
|
|
|
fragMaskOp = spv::OpFragmentMaskFetchAMD;
|
|
|
|
else if (node->getOp() == glslang::EOpFragmentFetch)
|
|
|
|
fragMaskOp = spv::OpFragmentFetchAMD;
|
|
|
|
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_fragment_mask);
|
|
|
|
builder.addCapability(spv::CapabilityFragmentMaskAMD);
|
|
|
|
return builder.createOp(fragMaskOp, resultType(), operands);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-09-09 08:42:49 +00:00
|
|
|
// Check for texture functions other than queries
|
2015-12-31 08:11:41 +00:00
|
|
|
bool sparse = node->isSparseTexture();
|
2018-09-19 18:41:27 +00:00
|
|
|
bool imageFootprint = node->isImageFootprint();
|
2019-08-08 07:15:24 +00:00
|
|
|
bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.isArrayed() && sampler.isShadow();
|
2015-11-11 07:35:47 +00:00
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
// check for bias argument
|
|
|
|
bool bias = false;
|
2016-11-17 09:47:59 +00:00
|
|
|
if (! cracked.lod && ! cracked.grad && ! cracked.fetch && ! cubeCompare) {
|
2015-08-19 19:34:18 +00:00
|
|
|
int nonBiasArgCount = 2;
|
2016-11-17 09:47:59 +00:00
|
|
|
if (cracked.gather)
|
|
|
|
++nonBiasArgCount; // comp argument should be present when bias argument is present
|
2016-11-29 09:36:31 +00:00
|
|
|
|
|
|
|
if (f16ShadowCompare)
|
|
|
|
++nonBiasArgCount;
|
2015-08-19 19:34:18 +00:00
|
|
|
if (cracked.offset)
|
|
|
|
++nonBiasArgCount;
|
2016-11-17 09:47:59 +00:00
|
|
|
else if (cracked.offsets)
|
|
|
|
++nonBiasArgCount;
|
2015-08-19 19:34:18 +00:00
|
|
|
if (cracked.grad)
|
|
|
|
nonBiasArgCount += 2;
|
2015-12-31 08:11:41 +00:00
|
|
|
if (cracked.lodClamp)
|
|
|
|
++nonBiasArgCount;
|
|
|
|
if (sparse)
|
|
|
|
++nonBiasArgCount;
|
2018-09-19 18:41:27 +00:00
|
|
|
if (imageFootprint)
|
|
|
|
//Following three extra arguments
|
|
|
|
// int granularity, bool coarse, out gl_TextureFootprint2DNV footprint
|
|
|
|
nonBiasArgCount += 3;
|
2015-08-19 19:34:18 +00:00
|
|
|
if ((int)arguments.size() > nonBiasArgCount)
|
|
|
|
bias = true;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-03 05:45:21 +00:00
|
|
|
// See if the sampler param should really be just the SPV image part
|
|
|
|
if (cracked.fetch) {
|
|
|
|
// a fetch needs to have the image extracted first
|
|
|
|
if (builder.isSampledImage(params.sampler))
|
|
|
|
params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler);
|
|
|
|
}
|
|
|
|
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2016-11-17 09:47:59 +00:00
|
|
|
if (cracked.gather) {
|
|
|
|
const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
|
|
|
|
if (bias || cracked.lod ||
|
|
|
|
sourceExtensions.find(glslang::E_GL_AMD_texture_gather_bias_lod) != sourceExtensions.end()) {
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_texture_gather_bias_lod);
|
2017-06-14 15:09:39 +00:00
|
|
|
builder.addCapability(spv::CapabilityImageGatherBiasLodAMD);
|
2016-11-17 09:47:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
// set the rest of the arguments
|
2015-11-16 04:33:39 +00:00
|
|
|
|
2015-08-19 19:34:18 +00:00
|
|
|
params.coords = arguments[1];
|
|
|
|
int extraArgs = 0;
|
2016-02-15 22:40:42 +00:00
|
|
|
bool noImplicitLod = false;
|
2015-11-16 04:33:39 +00:00
|
|
|
|
|
|
|
// sort out where Dref is coming from
|
2016-11-29 09:36:31 +00:00
|
|
|
if (cubeCompare || f16ShadowCompare) {
|
2015-11-16 04:33:39 +00:00
|
|
|
params.Dref = arguments[2];
|
2015-12-31 08:11:41 +00:00
|
|
|
++extraArgs;
|
|
|
|
} else if (sampler.shadow && cracked.gather) {
|
2015-08-19 19:34:18 +00:00
|
|
|
params.Dref = arguments[2];
|
2015-11-16 04:33:39 +00:00
|
|
|
++extraArgs;
|
|
|
|
} else if (sampler.shadow) {
|
2015-08-19 19:34:18 +00:00
|
|
|
std::vector<spv::Id> indexes;
|
2016-06-16 18:43:23 +00:00
|
|
|
int dRefComp;
|
2015-08-19 19:34:18 +00:00
|
|
|
if (cracked.proj)
|
2016-06-16 18:43:23 +00:00
|
|
|
dRefComp = 2; // "The resulting 3rd component of P in the shadow forms is used as Dref"
|
2015-08-19 19:34:18 +00:00
|
|
|
else
|
2016-06-16 18:43:23 +00:00
|
|
|
dRefComp = builder.getNumComponents(params.coords) - 1;
|
|
|
|
indexes.push_back(dRefComp);
|
2015-08-19 19:34:18 +00:00
|
|
|
params.Dref = builder.createCompositeExtract(params.coords, builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes);
|
|
|
|
}
|
2016-06-16 18:43:23 +00:00
|
|
|
|
|
|
|
// lod
|
2015-08-19 19:34:18 +00:00
|
|
|
if (cracked.lod) {
|
2017-07-25 00:45:37 +00:00
|
|
|
params.lod = arguments[2 + extraArgs];
|
2015-08-19 19:34:18 +00:00
|
|
|
++extraArgs;
|
2019-08-11 13:41:45 +00:00
|
|
|
} else if (glslangIntermediate->getStage() != EShLangFragment &&
|
|
|
|
!(glslangIntermediate->getStage() == EShLangCompute &&
|
|
|
|
glslangIntermediate->hasLayoutDerivativeModeNone())) {
|
2016-02-15 22:40:42 +00:00
|
|
|
// we need to invent the default lod for an explicit lod instruction for a non-fragment stage
|
|
|
|
noImplicitLod = true;
|
|
|
|
}
|
2016-06-16 18:43:23 +00:00
|
|
|
|
|
|
|
// multisample
|
2019-08-08 07:15:24 +00:00
|
|
|
if (sampler.isMultiSample()) {
|
2017-07-25 00:45:37 +00:00
|
|
|
params.sample = arguments[2 + extraArgs]; // For MS, "sample" should be specified
|
2015-09-16 03:44:02 +00:00
|
|
|
++extraArgs;
|
2015-08-19 19:34:18 +00:00
|
|
|
}
|
2016-06-16 18:43:23 +00:00
|
|
|
|
|
|
|
// gradient
|
2015-08-19 19:34:18 +00:00
|
|
|
if (cracked.grad) {
|
|
|
|
params.gradX = arguments[2 + extraArgs];
|
|
|
|
params.gradY = arguments[3 + extraArgs];
|
|
|
|
extraArgs += 2;
|
|
|
|
}
|
2016-06-16 18:43:23 +00:00
|
|
|
|
|
|
|
// offset and offsets
|
2015-11-16 04:33:39 +00:00
|
|
|
if (cracked.offset) {
|
2015-08-19 19:34:18 +00:00
|
|
|
params.offset = arguments[2 + extraArgs];
|
|
|
|
++extraArgs;
|
2015-11-16 04:33:39 +00:00
|
|
|
} else if (cracked.offsets) {
|
|
|
|
params.offsets = arguments[2 + extraArgs];
|
|
|
|
++extraArgs;
|
2015-08-19 19:34:18 +00:00
|
|
|
}
|
2016-06-16 18:43:23 +00:00
|
|
|
|
2019-08-08 07:15:24 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2016-06-16 18:43:23 +00:00
|
|
|
// lod clamp
|
2015-12-31 08:11:41 +00:00
|
|
|
if (cracked.lodClamp) {
|
|
|
|
params.lodClamp = arguments[2 + extraArgs];
|
|
|
|
++extraArgs;
|
|
|
|
}
|
2016-06-16 18:43:23 +00:00
|
|
|
// sparse
|
2015-12-31 08:11:41 +00:00
|
|
|
if (sparse) {
|
|
|
|
params.texelOut = arguments[2 + extraArgs];
|
|
|
|
++extraArgs;
|
|
|
|
}
|
2016-06-16 18:43:23 +00:00
|
|
|
// gather component
|
2015-11-16 04:33:39 +00:00
|
|
|
if (cracked.gather && ! sampler.shadow) {
|
|
|
|
// default component is 0, if missing, otherwise an argument
|
|
|
|
if (2 + extraArgs < (int)arguments.size()) {
|
2016-06-16 18:43:23 +00:00
|
|
|
params.component = arguments[2 + extraArgs];
|
2015-11-16 04:33:39 +00:00
|
|
|
++extraArgs;
|
2016-11-17 09:47:59 +00:00
|
|
|
} else
|
2016-06-16 18:43:23 +00:00
|
|
|
params.component = builder.makeIntConstant(0);
|
2016-11-17 09:47:59 +00:00
|
|
|
}
|
2018-09-19 18:41:27 +00:00
|
|
|
spv::Id resultStruct = spv::NoResult;
|
|
|
|
if (imageFootprint) {
|
|
|
|
//Following three extra arguments
|
|
|
|
// int granularity, bool coarse, out gl_TextureFootprint2DNV footprint
|
|
|
|
params.granularity = arguments[2 + extraArgs];
|
|
|
|
params.coarse = arguments[3 + extraArgs];
|
|
|
|
resultStruct = arguments[4 + extraArgs];
|
|
|
|
extraArgs += 3;
|
|
|
|
}
|
|
|
|
#endif
|
2016-11-17 09:47:59 +00:00
|
|
|
// bias
|
|
|
|
if (bias) {
|
|
|
|
params.bias = arguments[2 + extraArgs];
|
|
|
|
++extraArgs;
|
2015-11-16 04:33:39 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-09-19 18:41:27 +00:00
|
|
|
if (imageFootprint) {
|
|
|
|
builder.addExtension(spv::E_SPV_NV_shader_image_footprint);
|
|
|
|
builder.addCapability(spv::CapabilityImageFootprintNV);
|
|
|
|
|
|
|
|
|
|
|
|
//resultStructType(OpenGL type) contains 5 elements:
|
|
|
|
//struct gl_TextureFootprint2DNV {
|
|
|
|
// uvec2 anchor;
|
|
|
|
// uvec2 offset;
|
|
|
|
// uvec2 mask;
|
|
|
|
// uint lod;
|
|
|
|
// uint granularity;
|
|
|
|
//};
|
|
|
|
//or
|
|
|
|
//struct gl_TextureFootprint3DNV {
|
|
|
|
// uvec3 anchor;
|
|
|
|
// uvec3 offset;
|
|
|
|
// uvec2 mask;
|
|
|
|
// uint lod;
|
|
|
|
// uint granularity;
|
|
|
|
//};
|
|
|
|
spv::Id resultStructType = builder.getContainedTypeId(builder.getTypeId(resultStruct));
|
|
|
|
assert(builder.isStructType(resultStructType));
|
|
|
|
|
|
|
|
//resType (SPIR-V type) contains 6 elements:
|
|
|
|
//Member 0 must be a Boolean type scalar(LOD),
|
|
|
|
//Member 1 must be a vector of integer type, whose Signedness operand is 0(anchor),
|
|
|
|
//Member 2 must be a vector of integer type, whose Signedness operand is 0(offset),
|
|
|
|
//Member 3 must be a vector of integer type, whose Signedness operand is 0(mask),
|
|
|
|
//Member 4 must be a scalar of integer type, whose Signedness operand is 0(lod),
|
|
|
|
//Member 5 must be a scalar of integer type, whose Signedness operand is 0(granularity).
|
|
|
|
std::vector<spv::Id> members;
|
|
|
|
members.push_back(resultType());
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
|
|
members.push_back(builder.getContainedTypeId(resultStructType, i));
|
|
|
|
}
|
|
|
|
spv::Id resType = builder.makeStructType(members, "ResType");
|
|
|
|
|
|
|
|
//call ImageFootprintNV
|
2019-03-31 16:51:57 +00:00
|
|
|
spv::Id res = builder.createTextureCall(precision, resType, sparse, cracked.fetch, cracked.proj,
|
|
|
|
cracked.gather, noImplicitLod, params, signExtensionMask());
|
2018-09-19 18:41:27 +00:00
|
|
|
|
|
|
|
//copy resType (SPIR-V type) to resultStructType(OpenGL type)
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainLValue(resultStruct);
|
|
|
|
|
|
|
|
//Accessing to a struct we created, no coherent flag is set
|
|
|
|
spv::Builder::AccessChain::CoherentFlags flags;
|
|
|
|
flags.clear();
|
|
|
|
|
2019-01-06 23:58:04 +00:00
|
|
|
builder.accessChainPush(builder.makeIntConstant(i), flags, 0);
|
2018-09-19 18:41:27 +00:00
|
|
|
builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1), i+1));
|
|
|
|
}
|
|
|
|
return builder.createCompositeExtract(res, resultType(), 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-06-16 20:06:26 +00:00
|
|
|
// projective component (might not to move)
|
|
|
|
// GLSL: "The texture coordinates consumed from P, not including the last component of P,
|
|
|
|
// are divided by the last component of P."
|
|
|
|
// SPIR-V: "... (u [, v] [, w], q)... It may be a vector larger than needed, but all
|
|
|
|
// unused components will appear after all used components."
|
|
|
|
if (cracked.proj) {
|
|
|
|
int projSourceComp = builder.getNumComponents(params.coords) - 1;
|
|
|
|
int projTargetComp;
|
|
|
|
switch (sampler.dim) {
|
|
|
|
case glslang::Esd1D: projTargetComp = 1; break;
|
|
|
|
case glslang::Esd2D: projTargetComp = 2; break;
|
|
|
|
case glslang::EsdRect: projTargetComp = 2; break;
|
|
|
|
default: projTargetComp = projSourceComp; break;
|
|
|
|
}
|
|
|
|
// copy the projective coordinate if we have to
|
|
|
|
if (projTargetComp != projSourceComp) {
|
2017-01-06 07:34:48 +00:00
|
|
|
spv::Id projComp = builder.createCompositeExtract(params.coords,
|
2016-06-16 20:06:26 +00:00
|
|
|
builder.getScalarTypeId(builder.getTypeId(params.coords)),
|
|
|
|
projSourceComp);
|
|
|
|
params.coords = builder.createCompositeInsert(projComp, params.coords,
|
|
|
|
builder.getTypeId(params.coords), projTargetComp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
// nonprivate
|
|
|
|
if (imageType.getQualifier().nonprivate) {
|
|
|
|
params.nonprivate = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// volatile
|
|
|
|
if (imageType.getQualifier().volatil) {
|
|
|
|
params.volatil = true;
|
|
|
|
}
|
|
|
|
|
2018-04-09 19:08:14 +00:00
|
|
|
std::vector<spv::Id> result( 1,
|
2019-03-31 16:51:57 +00:00
|
|
|
builder.createTextureCall(precision, resultType(), sparse, cracked.fetch, cracked.proj, cracked.gather,
|
|
|
|
noImplicitLod, params, signExtensionMask())
|
2018-04-09 19:08:14 +00:00
|
|
|
);
|
2018-02-18 18:40:01 +00:00
|
|
|
|
|
|
|
if (components != node->getType().getVectorSize())
|
|
|
|
result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType()));
|
|
|
|
|
|
|
|
return result[0];
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
|
|
|
|
{
|
|
|
|
// Grab the function's pointer from the previously created function
|
|
|
|
spv::Function* function = functionMap[node->getName().c_str()];
|
|
|
|
if (! function)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
const glslang::TIntermSequence& glslangArgs = node->getSequence();
|
|
|
|
const glslang::TQualifierList& qualifiers = node->getQualifierList();
|
|
|
|
|
|
|
|
// See comments in makeFunctions() for details about the semantics for parameter passing.
|
|
|
|
//
|
|
|
|
// These imply we need a four step process:
|
|
|
|
// 1. Evaluate the arguments
|
|
|
|
// 2. Allocate and make copies of in, out, and inout arguments
|
|
|
|
// 3. Make the call
|
|
|
|
// 4. Copy back the results
|
|
|
|
|
2018-05-04 17:43:03 +00:00
|
|
|
// 1. Evaluate the arguments and their types
|
2015-06-26 22:58:36 +00:00
|
|
|
std::vector<spv::Builder::AccessChain> lValues;
|
|
|
|
std::vector<spv::Id> rValues;
|
2016-02-02 19:37:46 +00:00
|
|
|
std::vector<const glslang::TType*> argTypes;
|
2015-06-26 22:58:36 +00:00
|
|
|
for (int a = 0; a < (int)glslangArgs.size(); ++a) {
|
2018-05-04 17:43:03 +00:00
|
|
|
argTypes.push_back(&glslangArgs[a]->getAsTyped()->getType());
|
2015-06-26 22:58:36 +00:00
|
|
|
// build l-value
|
|
|
|
builder.clearAccessChain();
|
|
|
|
glslangArgs[a]->traverse(this);
|
2017-09-10 21:21:05 +00:00
|
|
|
// keep outputs and pass-by-originals as l-values, evaluate others as r-values
|
2018-05-04 17:43:03 +00:00
|
|
|
if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0) ||
|
2017-12-04 09:48:10 +00:00
|
|
|
writableParam(qualifiers[a])) {
|
2015-06-26 22:58:36 +00:00
|
|
|
// save l-value
|
|
|
|
lValues.push_back(builder.getAccessChain());
|
|
|
|
} else {
|
|
|
|
// process r-value
|
2016-02-02 19:37:46 +00:00
|
|
|
rValues.push_back(accessChainLoad(*argTypes.back()));
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 2. Allocate space for anything needing a copy, and if it's "in" or "inout"
|
|
|
|
// copy the original into that space.
|
|
|
|
//
|
|
|
|
// Also, build up the list of actual arguments to pass in for the call
|
|
|
|
int lValueCount = 0;
|
|
|
|
int rValueCount = 0;
|
|
|
|
std::vector<spv::Id> spvArgs;
|
|
|
|
for (int a = 0; a < (int)glslangArgs.size(); ++a) {
|
|
|
|
spv::Id arg;
|
2018-05-04 17:43:03 +00:00
|
|
|
if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0)) {
|
2016-05-25 18:50:21 +00:00
|
|
|
builder.setAccessChain(lValues[lValueCount]);
|
|
|
|
arg = builder.accessChainGetLValue();
|
|
|
|
++lValueCount;
|
2017-09-10 21:21:05 +00:00
|
|
|
} else if (writableParam(qualifiers[a])) {
|
2015-06-26 22:58:36 +00:00
|
|
|
// need space to hold the copy
|
2018-05-04 17:43:03 +00:00
|
|
|
arg = builder.createVariable(spv::StorageClassFunction, builder.getContainedTypeId(function->getParamType(a)), "param");
|
2015-06-26 22:58:36 +00:00
|
|
|
if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
|
|
|
|
// need to copy the input into output space
|
|
|
|
builder.setAccessChain(lValues[lValueCount]);
|
2016-02-02 19:37:46 +00:00
|
|
|
spv::Id copy = accessChainLoad(*argTypes[a]);
|
2016-09-02 17:20:21 +00:00
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainLValue(arg);
|
2018-05-04 17:43:03 +00:00
|
|
|
multiTypeStore(*argTypes[a], copy);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
++lValueCount;
|
|
|
|
} else {
|
2018-05-04 17:43:03 +00:00
|
|
|
// process r-value, which involves a copy for a type mismatch
|
|
|
|
if (function->getParamType(a) != convertGlslangToSpvType(*argTypes[a])) {
|
|
|
|
spv::Id argCopy = builder.createVariable(spv::StorageClassFunction, function->getParamType(a), "arg");
|
|
|
|
builder.clearAccessChain();
|
|
|
|
builder.setAccessChainLValue(argCopy);
|
|
|
|
multiTypeStore(*argTypes[a], rValues[rValueCount]);
|
|
|
|
arg = builder.createLoad(argCopy);
|
|
|
|
} else
|
|
|
|
arg = rValues[rValueCount];
|
2015-06-26 22:58:36 +00:00
|
|
|
++rValueCount;
|
|
|
|
}
|
|
|
|
spvArgs.push_back(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3. Make the call.
|
|
|
|
spv::Id result = builder.createFunctionCall(function, spvArgs);
|
2016-02-02 19:37:46 +00:00
|
|
|
builder.setPrecision(result, TranslatePrecisionDecoration(node->getType()));
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
// 4. Copy back out an "out" arguments.
|
|
|
|
lValueCount = 0;
|
|
|
|
for (int a = 0; a < (int)glslangArgs.size(); ++a) {
|
2018-05-04 17:43:03 +00:00
|
|
|
if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0))
|
2017-09-10 21:21:05 +00:00
|
|
|
++lValueCount;
|
|
|
|
else if (writableParam(qualifiers[a])) {
|
2015-06-26 22:58:36 +00:00
|
|
|
if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
|
|
|
|
spv::Id copy = builder.createLoad(spvArgs[a]);
|
|
|
|
builder.setAccessChain(lValues[lValueCount]);
|
2018-05-04 17:43:03 +00:00
|
|
|
multiTypeStore(*argTypes[a], copy);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
++lValueCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translate AST operation to SPV operation, already having SPV-based operands/types.
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, OpDecorations& decorations,
|
2015-06-26 22:58:36 +00:00
|
|
|
spv::Id typeId, spv::Id left, spv::Id right,
|
|
|
|
glslang::TBasicType typeProxy, bool reduceComparison)
|
|
|
|
{
|
2018-03-06 23:12:04 +00:00
|
|
|
bool isUnsigned = isTypeUnsignedInt(typeProxy);
|
|
|
|
bool isFloat = isTypeFloat(typeProxy);
|
2016-04-27 00:15:37 +00:00
|
|
|
bool isBool = typeProxy == glslang::EbtBool;
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
spv::Op binOp = spv::OpNop;
|
2015-07-04 23:17:31 +00:00
|
|
|
bool needMatchingVectors = true; // for non-matrix ops, would a scalar need to smear to match a vector?
|
2015-06-26 22:58:36 +00:00
|
|
|
bool comparison = false;
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpAdd:
|
|
|
|
case glslang::EOpAddAssign:
|
|
|
|
if (isFloat)
|
|
|
|
binOp = spv::OpFAdd;
|
|
|
|
else
|
|
|
|
binOp = spv::OpIAdd;
|
|
|
|
break;
|
|
|
|
case glslang::EOpSub:
|
|
|
|
case glslang::EOpSubAssign:
|
|
|
|
if (isFloat)
|
|
|
|
binOp = spv::OpFSub;
|
|
|
|
else
|
|
|
|
binOp = spv::OpISub;
|
|
|
|
break;
|
|
|
|
case glslang::EOpMul:
|
|
|
|
case glslang::EOpMulAssign:
|
|
|
|
if (isFloat)
|
|
|
|
binOp = spv::OpFMul;
|
|
|
|
else
|
|
|
|
binOp = spv::OpIMul;
|
|
|
|
break;
|
|
|
|
case glslang::EOpVectorTimesScalar:
|
|
|
|
case glslang::EOpVectorTimesScalarAssign:
|
2016-05-20 18:06:03 +00:00
|
|
|
if (isFloat && (builder.isVector(left) || builder.isVector(right))) {
|
2015-07-04 23:17:31 +00:00
|
|
|
if (builder.isVector(right))
|
|
|
|
std::swap(left, right);
|
|
|
|
assert(builder.isScalar(right));
|
|
|
|
needMatchingVectors = false;
|
|
|
|
binOp = spv::OpVectorTimesScalar;
|
2018-11-14 12:04:39 +00:00
|
|
|
} else if (isFloat)
|
|
|
|
binOp = spv::OpFMul;
|
|
|
|
else
|
2015-07-04 23:17:31 +00:00
|
|
|
binOp = spv::OpIMul;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpVectorTimesMatrix:
|
|
|
|
case glslang::EOpVectorTimesMatrixAssign:
|
|
|
|
binOp = spv::OpVectorTimesMatrix;
|
|
|
|
break;
|
|
|
|
case glslang::EOpMatrixTimesVector:
|
|
|
|
binOp = spv::OpMatrixTimesVector;
|
|
|
|
break;
|
|
|
|
case glslang::EOpMatrixTimesScalar:
|
|
|
|
case glslang::EOpMatrixTimesScalarAssign:
|
|
|
|
binOp = spv::OpMatrixTimesScalar;
|
|
|
|
break;
|
|
|
|
case glslang::EOpMatrixTimesMatrix:
|
|
|
|
case glslang::EOpMatrixTimesMatrixAssign:
|
|
|
|
binOp = spv::OpMatrixTimesMatrix;
|
|
|
|
break;
|
|
|
|
case glslang::EOpOuterProduct:
|
|
|
|
binOp = spv::OpOuterProduct;
|
2015-07-04 23:17:31 +00:00
|
|
|
needMatchingVectors = false;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpDiv:
|
|
|
|
case glslang::EOpDivAssign:
|
|
|
|
if (isFloat)
|
|
|
|
binOp = spv::OpFDiv;
|
|
|
|
else if (isUnsigned)
|
|
|
|
binOp = spv::OpUDiv;
|
|
|
|
else
|
|
|
|
binOp = spv::OpSDiv;
|
|
|
|
break;
|
|
|
|
case glslang::EOpMod:
|
|
|
|
case glslang::EOpModAssign:
|
|
|
|
if (isFloat)
|
|
|
|
binOp = spv::OpFMod;
|
|
|
|
else if (isUnsigned)
|
|
|
|
binOp = spv::OpUMod;
|
|
|
|
else
|
|
|
|
binOp = spv::OpSMod;
|
|
|
|
break;
|
|
|
|
case glslang::EOpRightShift:
|
|
|
|
case glslang::EOpRightShiftAssign:
|
|
|
|
if (isUnsigned)
|
|
|
|
binOp = spv::OpShiftRightLogical;
|
|
|
|
else
|
|
|
|
binOp = spv::OpShiftRightArithmetic;
|
|
|
|
break;
|
|
|
|
case glslang::EOpLeftShift:
|
|
|
|
case glslang::EOpLeftShiftAssign:
|
|
|
|
binOp = spv::OpShiftLeftLogical;
|
|
|
|
break;
|
|
|
|
case glslang::EOpAnd:
|
|
|
|
case glslang::EOpAndAssign:
|
|
|
|
binOp = spv::OpBitwiseAnd;
|
|
|
|
break;
|
|
|
|
case glslang::EOpLogicalAnd:
|
2015-07-04 23:17:31 +00:00
|
|
|
needMatchingVectors = false;
|
2015-06-26 22:58:36 +00:00
|
|
|
binOp = spv::OpLogicalAnd;
|
|
|
|
break;
|
|
|
|
case glslang::EOpInclusiveOr:
|
|
|
|
case glslang::EOpInclusiveOrAssign:
|
|
|
|
binOp = spv::OpBitwiseOr;
|
|
|
|
break;
|
|
|
|
case glslang::EOpLogicalOr:
|
2015-07-04 23:17:31 +00:00
|
|
|
needMatchingVectors = false;
|
2015-06-26 22:58:36 +00:00
|
|
|
binOp = spv::OpLogicalOr;
|
|
|
|
break;
|
|
|
|
case glslang::EOpExclusiveOr:
|
|
|
|
case glslang::EOpExclusiveOrAssign:
|
|
|
|
binOp = spv::OpBitwiseXor;
|
|
|
|
break;
|
|
|
|
case glslang::EOpLogicalXor:
|
2015-07-04 23:17:31 +00:00
|
|
|
needMatchingVectors = false;
|
2015-08-07 04:53:06 +00:00
|
|
|
binOp = spv::OpLogicalNotEqual;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpLessThan:
|
|
|
|
case glslang::EOpGreaterThan:
|
|
|
|
case glslang::EOpLessThanEqual:
|
|
|
|
case glslang::EOpGreaterThanEqual:
|
|
|
|
case glslang::EOpEqual:
|
|
|
|
case glslang::EOpNotEqual:
|
|
|
|
case glslang::EOpVectorEqual:
|
|
|
|
case glslang::EOpVectorNotEqual:
|
|
|
|
comparison = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-10-15 19:29:11 +00:00
|
|
|
// handle mapped binary operations (should be non-comparison)
|
2015-06-26 22:58:36 +00:00
|
|
|
if (binOp != spv::OpNop) {
|
2015-10-15 19:29:11 +00:00
|
|
|
assert(comparison == false);
|
2019-02-19 19:10:32 +00:00
|
|
|
if (builder.isMatrix(left) || builder.isMatrix(right) ||
|
|
|
|
builder.isCooperativeMatrix(left) || builder.isCooperativeMatrix(right))
|
2018-03-29 00:01:20 +00:00
|
|
|
return createBinaryMatrixOperation(binOp, decorations, typeId, left, right);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
// No matrix involved; make both operands be the same number of components, if needed
|
2015-07-04 23:17:31 +00:00
|
|
|
if (needMatchingVectors)
|
2018-03-29 00:01:20 +00:00
|
|
|
builder.promoteScalar(decorations.precision, left, right);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2016-05-06 21:25:16 +00:00
|
|
|
spv::Id result = builder.createBinOp(binOp, typeId, left, right);
|
2019-08-11 13:41:45 +00:00
|
|
|
decorations.addNoContraction(builder, result);
|
|
|
|
decorations.addNonUniform(builder, result);
|
2018-03-29 00:01:20 +00:00
|
|
|
return builder.setPrecision(result, decorations.precision);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (! comparison)
|
|
|
|
return 0;
|
|
|
|
|
2015-10-15 19:29:11 +00:00
|
|
|
// Handle comparison instructions
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2016-08-08 01:14:22 +00:00
|
|
|
if (reduceComparison && (op == glslang::EOpEqual || op == glslang::EOpNotEqual)
|
2018-03-29 00:01:20 +00:00
|
|
|
&& (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {
|
|
|
|
spv::Id result = builder.createCompositeCompare(decorations.precision, left, right, op == glslang::EOpEqual);
|
2019-08-11 13:41:45 +00:00
|
|
|
decorations.addNonUniform(builder, result);
|
2018-03-29 00:01:20 +00:00
|
|
|
return result;
|
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpLessThan:
|
|
|
|
if (isFloat)
|
|
|
|
binOp = spv::OpFOrdLessThan;
|
|
|
|
else if (isUnsigned)
|
|
|
|
binOp = spv::OpULessThan;
|
|
|
|
else
|
|
|
|
binOp = spv::OpSLessThan;
|
|
|
|
break;
|
|
|
|
case glslang::EOpGreaterThan:
|
|
|
|
if (isFloat)
|
|
|
|
binOp = spv::OpFOrdGreaterThan;
|
|
|
|
else if (isUnsigned)
|
|
|
|
binOp = spv::OpUGreaterThan;
|
|
|
|
else
|
|
|
|
binOp = spv::OpSGreaterThan;
|
|
|
|
break;
|
|
|
|
case glslang::EOpLessThanEqual:
|
|
|
|
if (isFloat)
|
|
|
|
binOp = spv::OpFOrdLessThanEqual;
|
|
|
|
else if (isUnsigned)
|
|
|
|
binOp = spv::OpULessThanEqual;
|
|
|
|
else
|
|
|
|
binOp = spv::OpSLessThanEqual;
|
|
|
|
break;
|
|
|
|
case glslang::EOpGreaterThanEqual:
|
|
|
|
if (isFloat)
|
|
|
|
binOp = spv::OpFOrdGreaterThanEqual;
|
|
|
|
else if (isUnsigned)
|
|
|
|
binOp = spv::OpUGreaterThanEqual;
|
|
|
|
else
|
|
|
|
binOp = spv::OpSGreaterThanEqual;
|
|
|
|
break;
|
|
|
|
case glslang::EOpEqual:
|
|
|
|
case glslang::EOpVectorEqual:
|
|
|
|
if (isFloat)
|
|
|
|
binOp = spv::OpFOrdEqual;
|
2016-04-27 00:15:37 +00:00
|
|
|
else if (isBool)
|
|
|
|
binOp = spv::OpLogicalEqual;
|
2015-06-26 22:58:36 +00:00
|
|
|
else
|
|
|
|
binOp = spv::OpIEqual;
|
|
|
|
break;
|
|
|
|
case glslang::EOpNotEqual:
|
|
|
|
case glslang::EOpVectorNotEqual:
|
|
|
|
if (isFloat)
|
|
|
|
binOp = spv::OpFOrdNotEqual;
|
2016-04-27 00:15:37 +00:00
|
|
|
else if (isBool)
|
|
|
|
binOp = spv::OpLogicalNotEqual;
|
2015-06-26 22:58:36 +00:00
|
|
|
else
|
|
|
|
binOp = spv::OpINotEqual;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-05-06 21:25:16 +00:00
|
|
|
if (binOp != spv::OpNop) {
|
|
|
|
spv::Id result = builder.createBinOp(binOp, typeId, left, right);
|
2019-08-11 13:41:45 +00:00
|
|
|
decorations.addNoContraction(builder, result);
|
|
|
|
decorations.addNonUniform(builder, result);
|
2018-03-29 00:01:20 +00:00
|
|
|
return builder.setPrecision(result, decorations.precision);
|
2016-05-06 21:25:16 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-12 19:28:14 +00:00
|
|
|
//
|
|
|
|
// Translate AST matrix operation to SPV operation, already having SPV-based operands/types.
|
|
|
|
// These can be any of:
|
|
|
|
//
|
|
|
|
// matrix * scalar
|
|
|
|
// scalar * matrix
|
|
|
|
// matrix * matrix linear algebraic
|
|
|
|
// matrix * vector
|
|
|
|
// vector * matrix
|
|
|
|
// matrix * matrix componentwise
|
|
|
|
// matrix op matrix op in {+, -, /}
|
|
|
|
// matrix op scalar op in {+, -, /}
|
|
|
|
// scalar op matrix op in {+, -, /}
|
|
|
|
//
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId,
|
|
|
|
spv::Id left, spv::Id right)
|
2015-12-12 19:28:14 +00:00
|
|
|
{
|
|
|
|
bool firstClass = true;
|
|
|
|
|
|
|
|
// First, handle first-class matrix operations (* and matrix/scalar)
|
|
|
|
switch (op) {
|
|
|
|
case spv::OpFDiv:
|
|
|
|
if (builder.isMatrix(left) && builder.isScalar(right)) {
|
|
|
|
// turn matrix / scalar into a multiply...
|
2018-03-13 09:57:59 +00:00
|
|
|
spv::Id resultType = builder.getTypeId(right);
|
|
|
|
right = builder.createBinOp(spv::OpFDiv, resultType, builder.makeFpConstant(resultType, 1.0), right);
|
2015-12-12 19:28:14 +00:00
|
|
|
op = spv::OpMatrixTimesScalar;
|
|
|
|
} else
|
|
|
|
firstClass = false;
|
|
|
|
break;
|
|
|
|
case spv::OpMatrixTimesScalar:
|
2019-02-19 19:10:32 +00:00
|
|
|
if (builder.isMatrix(right) || builder.isCooperativeMatrix(right))
|
2015-12-12 19:28:14 +00:00
|
|
|
std::swap(left, right);
|
|
|
|
assert(builder.isScalar(right));
|
|
|
|
break;
|
|
|
|
case spv::OpVectorTimesMatrix:
|
|
|
|
assert(builder.isVector(left));
|
|
|
|
assert(builder.isMatrix(right));
|
|
|
|
break;
|
|
|
|
case spv::OpMatrixTimesVector:
|
|
|
|
assert(builder.isMatrix(left));
|
|
|
|
assert(builder.isVector(right));
|
|
|
|
break;
|
|
|
|
case spv::OpMatrixTimesMatrix:
|
|
|
|
assert(builder.isMatrix(left));
|
|
|
|
assert(builder.isMatrix(right));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
firstClass = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-02-19 19:10:32 +00:00
|
|
|
if (builder.isCooperativeMatrix(left) || builder.isCooperativeMatrix(right))
|
|
|
|
firstClass = true;
|
|
|
|
|
2016-05-06 21:25:16 +00:00
|
|
|
if (firstClass) {
|
|
|
|
spv::Id result = builder.createBinOp(op, typeId, left, right);
|
2019-08-11 13:41:45 +00:00
|
|
|
decorations.addNoContraction(builder, result);
|
|
|
|
decorations.addNonUniform(builder, result);
|
2018-03-29 00:01:20 +00:00
|
|
|
return builder.setPrecision(result, decorations.precision);
|
2016-05-06 21:25:16 +00:00
|
|
|
}
|
2015-12-12 19:28:14 +00:00
|
|
|
|
2016-06-09 14:57:35 +00:00
|
|
|
// Handle component-wise +, -, *, %, and / for all combinations of type.
|
2015-12-12 19:28:14 +00:00
|
|
|
// The result type of all of them is the same type as the (a) matrix operand.
|
|
|
|
// The algorithm is to:
|
|
|
|
// - break the matrix(es) into vectors
|
|
|
|
// - smear any scalar to a vector
|
|
|
|
// - do vector operations
|
|
|
|
// - make a matrix out the vector results
|
|
|
|
switch (op) {
|
|
|
|
case spv::OpFAdd:
|
|
|
|
case spv::OpFSub:
|
|
|
|
case spv::OpFDiv:
|
2016-06-09 14:57:35 +00:00
|
|
|
case spv::OpFMod:
|
2015-12-12 19:28:14 +00:00
|
|
|
case spv::OpFMul:
|
|
|
|
{
|
|
|
|
// one time set up...
|
|
|
|
bool leftMat = builder.isMatrix(left);
|
|
|
|
bool rightMat = builder.isMatrix(right);
|
|
|
|
unsigned int numCols = leftMat ? builder.getNumColumns(left) : builder.getNumColumns(right);
|
|
|
|
int numRows = leftMat ? builder.getNumRows(left) : builder.getNumRows(right);
|
|
|
|
spv::Id scalarType = builder.getScalarTypeId(typeId);
|
|
|
|
spv::Id vecType = builder.makeVectorType(scalarType, numRows);
|
|
|
|
std::vector<spv::Id> results;
|
|
|
|
spv::Id smearVec = spv::NoResult;
|
|
|
|
if (builder.isScalar(left))
|
2018-03-29 00:01:20 +00:00
|
|
|
smearVec = builder.smearScalar(decorations.precision, left, vecType);
|
2015-12-12 19:28:14 +00:00
|
|
|
else if (builder.isScalar(right))
|
2018-03-29 00:01:20 +00:00
|
|
|
smearVec = builder.smearScalar(decorations.precision, right, vecType);
|
2015-12-12 19:28:14 +00:00
|
|
|
|
|
|
|
// do each vector op
|
|
|
|
for (unsigned int c = 0; c < numCols; ++c) {
|
|
|
|
std::vector<unsigned int> indexes;
|
|
|
|
indexes.push_back(c);
|
|
|
|
spv::Id leftVec = leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec;
|
|
|
|
spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec;
|
2016-05-06 21:25:16 +00:00
|
|
|
spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec);
|
2019-08-11 13:41:45 +00:00
|
|
|
decorations.addNoContraction(builder, result);
|
|
|
|
decorations.addNonUniform(builder, result);
|
2018-03-29 00:01:20 +00:00
|
|
|
results.push_back(builder.setPrecision(result, decorations.precision));
|
2015-12-12 19:28:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// put the pieces together
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);
|
2019-08-11 13:41:45 +00:00
|
|
|
decorations.addNonUniform(builder, result);
|
2018-03-29 00:01:20 +00:00
|
|
|
return result;
|
2015-12-12 19:28:14 +00:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
return spv::NoResult;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDecorations& decorations, spv::Id typeId,
|
2019-06-14 14:56:28 +00:00
|
|
|
spv::Id operand, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
|
|
|
spv::Op unaryOp = spv::OpNop;
|
2016-05-05 04:30:44 +00:00
|
|
|
int extBuiltins = -1;
|
2015-06-26 22:58:36 +00:00
|
|
|
int libCall = -1;
|
2018-03-06 23:12:04 +00:00
|
|
|
bool isUnsigned = isTypeUnsignedInt(typeProxy);
|
|
|
|
bool isFloat = isTypeFloat(typeProxy);
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpNegative:
|
2016-01-20 18:19:27 +00:00
|
|
|
if (isFloat) {
|
2015-06-26 22:58:36 +00:00
|
|
|
unaryOp = spv::OpFNegate;
|
2016-01-20 18:19:27 +00:00
|
|
|
if (builder.isMatrixType(typeId))
|
2018-03-29 00:01:20 +00:00
|
|
|
return createUnaryMatrixOperation(unaryOp, decorations, typeId, operand, typeProxy);
|
2016-01-20 18:19:27 +00:00
|
|
|
} else
|
2015-06-26 22:58:36 +00:00
|
|
|
unaryOp = spv::OpSNegate;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpLogicalNot:
|
|
|
|
case glslang::EOpVectorLogicalNot:
|
2015-08-07 04:53:06 +00:00
|
|
|
unaryOp = spv::OpLogicalNot;
|
|
|
|
break;
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpBitwiseNot:
|
|
|
|
unaryOp = spv::OpNot;
|
|
|
|
break;
|
2015-08-07 04:53:06 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpDeterminant:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Determinant;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpMatrixInverse:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450MatrixInverse;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpTranspose:
|
|
|
|
unaryOp = spv::OpTranspose;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpRadians:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Radians;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpDegrees:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Degrees;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpSin:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Sin;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpCos:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Cos;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpTan:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Tan;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpAcos:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Acos;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpAsin:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Asin;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpAtan:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Atan;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpAcosh:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Acosh;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpAsinh:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Asinh;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpAtanh:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Atanh;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpTanh:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Tanh;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpCosh:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Cosh;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpSinh:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Sinh;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpLength:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Length;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpNormalize:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Normalize;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpExp:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Exp;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpLog:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Log;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpExp2:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Exp2;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpLog2:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Log2;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpSqrt:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Sqrt;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpInverseSqrt:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450InverseSqrt;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpFloor:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Floor;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpTrunc:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Trunc;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpRound:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Round;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpRoundEven:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450RoundEven;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpCeil:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Ceil;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpFract:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Fract;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpIsNan:
|
|
|
|
unaryOp = spv::OpIsNan;
|
|
|
|
break;
|
|
|
|
case glslang::EOpIsInf:
|
|
|
|
unaryOp = spv::OpIsInf;
|
|
|
|
break;
|
2016-06-09 14:57:35 +00:00
|
|
|
case glslang::EOpIsFinite:
|
|
|
|
unaryOp = spv::OpIsFinite;
|
|
|
|
break;
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2015-12-15 08:03:10 +00:00
|
|
|
case glslang::EOpFloatBitsToInt:
|
|
|
|
case glslang::EOpFloatBitsToUint:
|
|
|
|
case glslang::EOpIntBitsToFloat:
|
|
|
|
case glslang::EOpUintBitsToFloat:
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EOpDoubleBitsToInt64:
|
|
|
|
case glslang::EOpDoubleBitsToUint64:
|
|
|
|
case glslang::EOpInt64BitsToDouble:
|
|
|
|
case glslang::EOpUint64BitsToDouble:
|
2017-03-24 05:41:14 +00:00
|
|
|
case glslang::EOpFloat16BitsToInt16:
|
|
|
|
case glslang::EOpFloat16BitsToUint16:
|
|
|
|
case glslang::EOpInt16BitsToFloat16:
|
|
|
|
case glslang::EOpUint16BitsToFloat16:
|
2015-12-15 08:03:10 +00:00
|
|
|
unaryOp = spv::OpBitcast;
|
|
|
|
break;
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpPackSnorm2x16:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450PackSnorm2x16;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpUnpackSnorm2x16:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450UnpackSnorm2x16;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpPackUnorm2x16:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450PackUnorm2x16;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpUnpackUnorm2x16:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450UnpackUnorm2x16;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpPackHalf2x16:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450PackHalf2x16;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpUnpackHalf2x16:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450UnpackHalf2x16;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2015-08-19 19:34:18 +00:00
|
|
|
case glslang::EOpPackSnorm4x8:
|
|
|
|
libCall = spv::GLSLstd450PackSnorm4x8;
|
|
|
|
break;
|
|
|
|
case glslang::EOpUnpackSnorm4x8:
|
|
|
|
libCall = spv::GLSLstd450UnpackSnorm4x8;
|
|
|
|
break;
|
|
|
|
case glslang::EOpPackUnorm4x8:
|
|
|
|
libCall = spv::GLSLstd450PackUnorm4x8;
|
|
|
|
break;
|
|
|
|
case glslang::EOpUnpackUnorm4x8:
|
|
|
|
libCall = spv::GLSLstd450UnpackUnorm4x8;
|
|
|
|
break;
|
|
|
|
case glslang::EOpPackDouble2x32:
|
|
|
|
libCall = spv::GLSLstd450PackDouble2x32;
|
|
|
|
break;
|
|
|
|
case glslang::EOpUnpackDouble2x32:
|
|
|
|
libCall = spv::GLSLstd450UnpackDouble2x32;
|
|
|
|
break;
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EOpPackInt2x32:
|
|
|
|
case glslang::EOpUnpackInt2x32:
|
|
|
|
case glslang::EOpPackUint2x32:
|
|
|
|
case glslang::EOpUnpackUint2x32:
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpPack16:
|
|
|
|
case glslang::EOpPack32:
|
|
|
|
case glslang::EOpPack64:
|
|
|
|
case glslang::EOpUnpack32:
|
|
|
|
case glslang::EOpUnpack16:
|
|
|
|
case glslang::EOpUnpack8:
|
2017-03-24 05:41:14 +00:00
|
|
|
case glslang::EOpPackInt2x16:
|
|
|
|
case glslang::EOpUnpackInt2x16:
|
|
|
|
case glslang::EOpPackUint2x16:
|
|
|
|
case glslang::EOpUnpackUint2x16:
|
|
|
|
case glslang::EOpPackInt4x16:
|
|
|
|
case glslang::EOpUnpackInt4x16:
|
|
|
|
case glslang::EOpPackUint4x16:
|
|
|
|
case glslang::EOpUnpackUint4x16:
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
case glslang::EOpPackFloat2x16:
|
|
|
|
case glslang::EOpUnpackFloat2x16:
|
|
|
|
unaryOp = spv::OpBitcast;
|
|
|
|
break;
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpDPdx:
|
|
|
|
unaryOp = spv::OpDPdx;
|
|
|
|
break;
|
|
|
|
case glslang::EOpDPdy:
|
|
|
|
unaryOp = spv::OpDPdy;
|
|
|
|
break;
|
|
|
|
case glslang::EOpFwidth:
|
|
|
|
unaryOp = spv::OpFwidth;
|
|
|
|
break;
|
2019-08-06 13:00:58 +00:00
|
|
|
|
|
|
|
case glslang::EOpAny:
|
|
|
|
unaryOp = spv::OpAny;
|
|
|
|
break;
|
|
|
|
case glslang::EOpAll:
|
|
|
|
unaryOp = spv::OpAll;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpAbs:
|
|
|
|
if (isFloat)
|
|
|
|
libCall = spv::GLSLstd450FAbs;
|
|
|
|
else
|
|
|
|
libCall = spv::GLSLstd450SAbs;
|
|
|
|
break;
|
|
|
|
case glslang::EOpSign:
|
|
|
|
if (isFloat)
|
|
|
|
libCall = spv::GLSLstd450FSign;
|
|
|
|
else
|
|
|
|
libCall = spv::GLSLstd450SSign;
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifndef GLSLANG_WEB
|
2015-06-26 22:58:36 +00:00
|
|
|
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;
|
2015-12-08 09:12:09 +00:00
|
|
|
case glslang::EOpInterpolateAtCentroid:
|
2018-05-17 05:51:28 +00:00
|
|
|
if (typeProxy == glslang::EbtFloat16)
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
2015-12-08 09:12:09 +00:00
|
|
|
libCall = spv::GLSLstd450InterpolateAtCentroid;
|
|
|
|
break;
|
2015-08-19 19:34:18 +00:00
|
|
|
case glslang::EOpAtomicCounterIncrement:
|
|
|
|
case glslang::EOpAtomicCounterDecrement:
|
|
|
|
case glslang::EOpAtomicCounter:
|
|
|
|
{
|
|
|
|
// Handle all of the atomics in one place, in createAtomicOperation()
|
|
|
|
std::vector<spv::Id> operands;
|
|
|
|
operands.push_back(operand);
|
2019-06-14 14:56:28 +00:00
|
|
|
return createAtomicOperation(op, decorations.precision, typeId, operands, typeProxy, lvalueCoherentFlags);
|
2015-08-19 19:34:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case glslang::EOpBitFieldReverse:
|
|
|
|
unaryOp = spv::OpBitReverse;
|
|
|
|
break;
|
|
|
|
case glslang::EOpBitCount:
|
|
|
|
unaryOp = spv::OpBitCount;
|
|
|
|
break;
|
|
|
|
case glslang::EOpFindLSB:
|
2015-11-16 04:33:39 +00:00
|
|
|
libCall = spv::GLSLstd450FindILsb;
|
2015-08-19 19:34:18 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpFindMSB:
|
2015-11-16 04:33:39 +00:00
|
|
|
if (isUnsigned)
|
|
|
|
libCall = spv::GLSLstd450FindUMsb;
|
|
|
|
else
|
|
|
|
libCall = spv::GLSLstd450FindSMsb;
|
2015-08-19 19:34:18 +00:00
|
|
|
break;
|
|
|
|
|
2016-04-14 08:53:07 +00:00
|
|
|
case glslang::EOpBallot:
|
|
|
|
case glslang::EOpReadFirstInvocation:
|
2016-05-05 12:38:33 +00:00
|
|
|
case glslang::EOpAnyInvocation:
|
|
|
|
case glslang::EOpAllInvocations:
|
|
|
|
case glslang::EOpAllInvocationsEqual:
|
2016-05-05 04:30:44 +00:00
|
|
|
case glslang::EOpMinInvocations:
|
|
|
|
case glslang::EOpMaxInvocations:
|
|
|
|
case glslang::EOpAddInvocations:
|
|
|
|
case glslang::EOpMinInvocationsNonUniform:
|
|
|
|
case glslang::EOpMaxInvocationsNonUniform:
|
|
|
|
case glslang::EOpAddInvocationsNonUniform:
|
2016-10-14 09:22:23 +00:00
|
|
|
case glslang::EOpMinInvocationsInclusiveScan:
|
|
|
|
case glslang::EOpMaxInvocationsInclusiveScan:
|
|
|
|
case glslang::EOpAddInvocationsInclusiveScan:
|
|
|
|
case glslang::EOpMinInvocationsInclusiveScanNonUniform:
|
|
|
|
case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
|
|
|
|
case glslang::EOpAddInvocationsInclusiveScanNonUniform:
|
|
|
|
case glslang::EOpMinInvocationsExclusiveScan:
|
|
|
|
case glslang::EOpMaxInvocationsExclusiveScan:
|
|
|
|
case glslang::EOpAddInvocationsExclusiveScan:
|
|
|
|
case glslang::EOpMinInvocationsExclusiveScanNonUniform:
|
|
|
|
case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
|
|
|
|
case glslang::EOpAddInvocationsExclusiveScanNonUniform:
|
2016-09-21 10:56:12 +00:00
|
|
|
{
|
|
|
|
std::vector<spv::Id> operands;
|
|
|
|
operands.push_back(operand);
|
|
|
|
return createInvocationsOperation(op, typeId, operands, typeProxy);
|
|
|
|
}
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpSubgroupAll:
|
|
|
|
case glslang::EOpSubgroupAny:
|
|
|
|
case glslang::EOpSubgroupAllEqual:
|
|
|
|
case glslang::EOpSubgroupBroadcastFirst:
|
|
|
|
case glslang::EOpSubgroupBallot:
|
|
|
|
case glslang::EOpSubgroupInverseBallot:
|
|
|
|
case glslang::EOpSubgroupBallotBitCount:
|
|
|
|
case glslang::EOpSubgroupBallotInclusiveBitCount:
|
|
|
|
case glslang::EOpSubgroupBallotExclusiveBitCount:
|
|
|
|
case glslang::EOpSubgroupBallotFindLSB:
|
|
|
|
case glslang::EOpSubgroupBallotFindMSB:
|
|
|
|
case glslang::EOpSubgroupAdd:
|
|
|
|
case glslang::EOpSubgroupMul:
|
|
|
|
case glslang::EOpSubgroupMin:
|
|
|
|
case glslang::EOpSubgroupMax:
|
|
|
|
case glslang::EOpSubgroupAnd:
|
|
|
|
case glslang::EOpSubgroupOr:
|
|
|
|
case glslang::EOpSubgroupXor:
|
|
|
|
case glslang::EOpSubgroupInclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupInclusiveMul:
|
|
|
|
case glslang::EOpSubgroupInclusiveMin:
|
|
|
|
case glslang::EOpSubgroupInclusiveMax:
|
|
|
|
case glslang::EOpSubgroupInclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupInclusiveOr:
|
|
|
|
case glslang::EOpSubgroupInclusiveXor:
|
|
|
|
case glslang::EOpSubgroupExclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupExclusiveMul:
|
|
|
|
case glslang::EOpSubgroupExclusiveMin:
|
|
|
|
case glslang::EOpSubgroupExclusiveMax:
|
|
|
|
case glslang::EOpSubgroupExclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupExclusiveOr:
|
|
|
|
case glslang::EOpSubgroupExclusiveXor:
|
|
|
|
case glslang::EOpSubgroupQuadSwapHorizontal:
|
|
|
|
case glslang::EOpSubgroupQuadSwapVertical:
|
|
|
|
case glslang::EOpSubgroupQuadSwapDiagonal: {
|
|
|
|
std::vector<spv::Id> operands;
|
|
|
|
operands.push_back(operand);
|
|
|
|
return createSubgroupOperation(op, typeId, operands, typeProxy);
|
|
|
|
}
|
2016-05-05 04:30:44 +00:00
|
|
|
case glslang::EOpMbcnt:
|
|
|
|
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
|
|
|
|
libCall = spv::MbcntAMD;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpCubeFaceIndex:
|
|
|
|
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);
|
|
|
|
libCall = spv::CubeFaceIndexAMD;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpCubeFaceCoord:
|
|
|
|
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);
|
|
|
|
libCall = spv::CubeFaceCoordAMD;
|
|
|
|
break;
|
2018-03-30 03:52:17 +00:00
|
|
|
case glslang::EOpSubgroupPartition:
|
|
|
|
unaryOp = spv::OpGroupNonUniformPartitionNV;
|
|
|
|
break;
|
2019-01-06 23:58:04 +00:00
|
|
|
case glslang::EOpConstructReference:
|
|
|
|
unaryOp = spv::OpBitcast;
|
|
|
|
break;
|
2019-08-06 13:00:58 +00:00
|
|
|
#endif
|
2019-05-08 15:24:46 +00:00
|
|
|
|
|
|
|
case glslang::EOpCopyObject:
|
|
|
|
unaryOp = spv::OpCopyObject;
|
|
|
|
break;
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
spv::Id id;
|
|
|
|
if (libCall >= 0) {
|
|
|
|
std::vector<spv::Id> args;
|
|
|
|
args.push_back(operand);
|
2016-05-05 04:30:44 +00:00
|
|
|
id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, args);
|
2016-05-05 12:38:33 +00:00
|
|
|
} else {
|
2016-05-05 22:45:40 +00:00
|
|
|
id = builder.createUnaryOp(unaryOp, typeId, operand);
|
2016-05-05 12:38:33 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
decorations.addNoContraction(builder, id);
|
|
|
|
decorations.addNonUniform(builder, id);
|
2018-03-29 00:01:20 +00:00
|
|
|
return builder.setPrecision(id, decorations.precision);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
2016-01-20 18:19:27 +00:00
|
|
|
// Create a unary operation on a matrix
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId,
|
|
|
|
spv::Id operand, glslang::TBasicType /* typeProxy */)
|
2016-01-20 18:19:27 +00:00
|
|
|
{
|
|
|
|
// Handle unary operations vector by vector.
|
|
|
|
// The result type is the same type as the original type.
|
|
|
|
// The algorithm is to:
|
|
|
|
// - break the matrix into vectors
|
|
|
|
// - apply the operation to each vector
|
|
|
|
// - make a matrix out the vector results
|
|
|
|
|
|
|
|
// get the types sorted out
|
|
|
|
int numCols = builder.getNumColumns(operand);
|
|
|
|
int numRows = builder.getNumRows(operand);
|
2016-05-17 10:57:18 +00:00
|
|
|
spv::Id srcVecType = builder.makeVectorType(builder.getScalarTypeId(builder.getTypeId(operand)), numRows);
|
|
|
|
spv::Id destVecType = builder.makeVectorType(builder.getScalarTypeId(typeId), numRows);
|
2016-01-20 18:19:27 +00:00
|
|
|
std::vector<spv::Id> results;
|
|
|
|
|
|
|
|
// do each vector op
|
|
|
|
for (int c = 0; c < numCols; ++c) {
|
|
|
|
std::vector<unsigned int> indexes;
|
|
|
|
indexes.push_back(c);
|
2016-05-17 10:57:18 +00:00
|
|
|
spv::Id srcVec = builder.createCompositeExtract(operand, srcVecType, indexes);
|
|
|
|
spv::Id destVec = builder.createUnaryOp(op, destVecType, srcVec);
|
2019-08-11 13:41:45 +00:00
|
|
|
decorations.addNoContraction(builder, destVec);
|
|
|
|
decorations.addNonUniform(builder, destVec);
|
2018-03-29 00:01:20 +00:00
|
|
|
results.push_back(builder.setPrecision(destVec, decorations.precision));
|
2016-01-20 18:19:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// put the pieces together
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);
|
2019-08-11 13:41:45 +00:00
|
|
|
decorations.addNonUniform(builder, result);
|
2018-03-29 00:01:20 +00:00
|
|
|
return result;
|
2016-01-20 18:19:27 +00:00
|
|
|
}
|
|
|
|
|
2018-06-05 01:11:25 +00:00
|
|
|
// For converting integers where both the bitwidth and the signedness could
|
|
|
|
// change, but only do the width change here. The caller is still responsible
|
|
|
|
// for the signedness conversion.
|
|
|
|
spv::Id TGlslangToSpvTraverser::createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize)
|
2018-03-06 23:12:04 +00:00
|
|
|
{
|
2018-06-05 01:11:25 +00:00
|
|
|
// Get the result type width, based on the type to convert to.
|
|
|
|
int width = 32;
|
2018-03-06 23:12:04 +00:00
|
|
|
switch(op) {
|
2018-06-05 01:11:25 +00:00
|
|
|
case glslang::EOpConvInt16ToUint8:
|
|
|
|
case glslang::EOpConvIntToUint8:
|
|
|
|
case glslang::EOpConvInt64ToUint8:
|
|
|
|
case glslang::EOpConvUint16ToInt8:
|
|
|
|
case glslang::EOpConvUintToInt8:
|
|
|
|
case glslang::EOpConvUint64ToInt8:
|
|
|
|
width = 8;
|
|
|
|
break;
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvInt8ToUint16:
|
2018-06-05 01:11:25 +00:00
|
|
|
case glslang::EOpConvIntToUint16:
|
|
|
|
case glslang::EOpConvInt64ToUint16:
|
|
|
|
case glslang::EOpConvUint8ToInt16:
|
|
|
|
case glslang::EOpConvUintToInt16:
|
|
|
|
case glslang::EOpConvUint64ToInt16:
|
|
|
|
width = 16;
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpConvInt8ToUint:
|
2018-06-05 01:11:25 +00:00
|
|
|
case glslang::EOpConvInt16ToUint:
|
|
|
|
case glslang::EOpConvInt64ToUint:
|
|
|
|
case glslang::EOpConvUint8ToInt:
|
|
|
|
case glslang::EOpConvUint16ToInt:
|
|
|
|
case glslang::EOpConvUint64ToInt:
|
|
|
|
width = 32;
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpConvInt8ToUint64:
|
2018-06-05 01:11:25 +00:00
|
|
|
case glslang::EOpConvInt16ToUint64:
|
|
|
|
case glslang::EOpConvIntToUint64:
|
|
|
|
case glslang::EOpConvUint8ToInt64:
|
|
|
|
case glslang::EOpConvUint16ToInt64:
|
|
|
|
case glslang::EOpConvUintToInt64:
|
|
|
|
width = 64;
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
2018-06-05 01:11:25 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
assert(false && "Default missing");
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
2018-06-05 01:11:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the conversion operation and result type,
|
|
|
|
// based on the target width, but the source type.
|
|
|
|
spv::Id type = spv::NoType;
|
|
|
|
spv::Op convOp = spv::OpNop;
|
|
|
|
switch(op) {
|
|
|
|
case glslang::EOpConvInt8ToUint16:
|
|
|
|
case glslang::EOpConvInt8ToUint:
|
|
|
|
case glslang::EOpConvInt8ToUint64:
|
|
|
|
case glslang::EOpConvInt16ToUint8:
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvInt16ToUint:
|
|
|
|
case glslang::EOpConvInt16ToUint64:
|
|
|
|
case glslang::EOpConvIntToUint8:
|
|
|
|
case glslang::EOpConvIntToUint16:
|
|
|
|
case glslang::EOpConvIntToUint64:
|
|
|
|
case glslang::EOpConvInt64ToUint8:
|
|
|
|
case glslang::EOpConvInt64ToUint16:
|
|
|
|
case glslang::EOpConvInt64ToUint:
|
|
|
|
convOp = spv::OpSConvert;
|
2018-06-05 01:11:25 +00:00
|
|
|
type = builder.makeIntType(width);
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
|
|
|
default:
|
2018-06-05 01:11:25 +00:00
|
|
|
convOp = spv::OpUConvert;
|
|
|
|
type = builder.makeUintType(width);
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vectorSize > 0)
|
|
|
|
type = builder.makeVectorType(type, vectorSize);
|
|
|
|
|
2018-06-05 01:11:25 +00:00
|
|
|
return builder.createUnaryOp(convOp, type, operand);
|
2018-03-06 23:12:04 +00:00
|
|
|
}
|
|
|
|
|
2018-03-29 00:01:20 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecorations& decorations, spv::Id destType,
|
|
|
|
spv::Id operand, glslang::TBasicType typeProxy)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
|
|
|
spv::Op convOp = spv::OpNop;
|
|
|
|
spv::Id zero = 0;
|
|
|
|
spv::Id one = 0;
|
|
|
|
|
|
|
|
int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpConvIntToBool:
|
|
|
|
case glslang::EOpConvUintToBool:
|
2018-03-06 23:12:04 +00:00
|
|
|
zero = builder.makeUintConstant(0);
|
|
|
|
zero = makeSmearedConstant(zero, vectorSize);
|
|
|
|
return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpConvFloatToBool:
|
|
|
|
zero = builder.makeFloatConstant(0.0F);
|
|
|
|
zero = makeSmearedConstant(zero, vectorSize);
|
|
|
|
return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
|
|
|
|
case glslang::EOpConvBoolToFloat:
|
|
|
|
convOp = spv::OpSelect;
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
zero = builder.makeFloatConstant(0.0F);
|
|
|
|
one = builder.makeFloatConstant(1.0F);
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpConvBoolToInt:
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EOpConvBoolToInt64:
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
if (op == glslang::EOpConvBoolToInt64) {
|
2017-03-24 05:41:14 +00:00
|
|
|
zero = builder.makeInt64Constant(0);
|
|
|
|
one = builder.makeInt64Constant(1);
|
2019-08-11 13:41:45 +00:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
zero = builder.makeIntConstant(0);
|
2017-03-24 05:41:14 +00:00
|
|
|
one = builder.makeIntConstant(1);
|
2019-08-11 13:41:45 +00:00
|
|
|
}
|
2017-03-24 05:41:14 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
convOp = spv::OpSelect;
|
|
|
|
break;
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpConvBoolToUint:
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EOpConvBoolToUint64:
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
if (op == glslang::EOpConvBoolToUint64) {
|
2017-03-24 05:41:14 +00:00
|
|
|
zero = builder.makeUint64Constant(0);
|
|
|
|
one = builder.makeUint64Constant(1);
|
2019-08-11 13:41:45 +00:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
zero = builder.makeUintConstant(0);
|
2017-03-24 05:41:14 +00:00
|
|
|
one = builder.makeUintConstant(1);
|
2019-08-11 13:41:45 +00:00
|
|
|
}
|
2017-03-24 05:41:14 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
convOp = spv::OpSelect;
|
|
|
|
break;
|
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvInt8ToFloat16:
|
|
|
|
case glslang::EOpConvInt8ToFloat:
|
|
|
|
case glslang::EOpConvInt8ToDouble:
|
|
|
|
case glslang::EOpConvInt16ToFloat16:
|
|
|
|
case glslang::EOpConvInt16ToFloat:
|
|
|
|
case glslang::EOpConvInt16ToDouble:
|
|
|
|
case glslang::EOpConvIntToFloat16:
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpConvIntToFloat:
|
|
|
|
case glslang::EOpConvIntToDouble:
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EOpConvInt64ToFloat:
|
|
|
|
case glslang::EOpConvInt64ToDouble:
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
case glslang::EOpConvInt64ToFloat16:
|
2015-06-26 22:58:36 +00:00
|
|
|
convOp = spv::OpConvertSToF;
|
|
|
|
break;
|
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvUint8ToFloat16:
|
|
|
|
case glslang::EOpConvUint8ToFloat:
|
|
|
|
case glslang::EOpConvUint8ToDouble:
|
|
|
|
case glslang::EOpConvUint16ToFloat16:
|
|
|
|
case glslang::EOpConvUint16ToFloat:
|
|
|
|
case glslang::EOpConvUint16ToDouble:
|
|
|
|
case glslang::EOpConvUintToFloat16:
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpConvUintToFloat:
|
|
|
|
case glslang::EOpConvUintToDouble:
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EOpConvUint64ToFloat:
|
|
|
|
case glslang::EOpConvUint64ToDouble:
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
case glslang::EOpConvUint64ToFloat16:
|
2015-06-26 22:58:36 +00:00
|
|
|
convOp = spv::OpConvertUToF;
|
|
|
|
break;
|
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvFloat16ToInt8:
|
|
|
|
case glslang::EOpConvFloatToInt8:
|
|
|
|
case glslang::EOpConvDoubleToInt8:
|
|
|
|
case glslang::EOpConvFloat16ToInt16:
|
2017-03-24 05:41:14 +00:00
|
|
|
case glslang::EOpConvFloatToInt16:
|
|
|
|
case glslang::EOpConvDoubleToInt16:
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
case glslang::EOpConvFloat16ToInt:
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvFloatToInt:
|
|
|
|
case glslang::EOpConvDoubleToInt:
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
case glslang::EOpConvFloat16ToInt64:
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvFloatToInt64:
|
|
|
|
case glslang::EOpConvDoubleToInt64:
|
2015-06-26 22:58:36 +00:00
|
|
|
convOp = spv::OpConvertFToS;
|
|
|
|
break;
|
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvUint8ToInt8:
|
|
|
|
case glslang::EOpConvInt8ToUint8:
|
|
|
|
case glslang::EOpConvUint16ToInt16:
|
|
|
|
case glslang::EOpConvInt16ToUint16:
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpConvUintToInt:
|
|
|
|
case glslang::EOpConvIntToUint:
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EOpConvUint64ToInt64:
|
|
|
|
case glslang::EOpConvInt64ToUint64:
|
2016-04-07 19:40:27 +00:00
|
|
|
if (builder.isInSpecConstCodeGenMode()) {
|
|
|
|
// Build zero scalar or vector for OpIAdd.
|
2019-08-08 16:35:51 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-03-06 23:12:04 +00:00
|
|
|
if(op == glslang::EOpConvUint8ToInt8 || op == glslang::EOpConvInt8ToUint8) {
|
|
|
|
zero = builder.makeUint8Constant(0);
|
|
|
|
} else if (op == glslang::EOpConvUint16ToInt16 || op == glslang::EOpConvInt16ToUint16) {
|
2017-03-24 05:41:14 +00:00
|
|
|
zero = builder.makeUint16Constant(0);
|
2018-03-06 23:12:04 +00:00
|
|
|
} else if (op == glslang::EOpConvUint64ToInt64 || op == glslang::EOpConvInt64ToUint64) {
|
|
|
|
zero = builder.makeUint64Constant(0);
|
2019-08-08 16:35:51 +00:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2017-03-24 05:41:14 +00:00
|
|
|
zero = builder.makeUintConstant(0);
|
2018-03-06 23:12:04 +00:00
|
|
|
}
|
2016-04-13 03:16:20 +00:00
|
|
|
zero = makeSmearedConstant(zero, vectorSize);
|
2016-04-07 19:40:27 +00:00
|
|
|
// Use OpIAdd, instead of OpBitcast to do the conversion when
|
|
|
|
// generating for OpSpecConstantOp instruction.
|
|
|
|
return builder.createBinOp(spv::OpIAdd, destType, operand, zero);
|
|
|
|
}
|
|
|
|
// For normal run-time conversion instruction, use OpBitcast.
|
2015-06-26 22:58:36 +00:00
|
|
|
convOp = spv::OpBitcast;
|
|
|
|
break;
|
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvFloat16ToUint8:
|
|
|
|
case glslang::EOpConvFloatToUint8:
|
|
|
|
case glslang::EOpConvDoubleToUint8:
|
|
|
|
case glslang::EOpConvFloat16ToUint16:
|
|
|
|
case glslang::EOpConvFloatToUint16:
|
|
|
|
case glslang::EOpConvDoubleToUint16:
|
|
|
|
case glslang::EOpConvFloat16ToUint:
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EOpConvFloatToUint:
|
|
|
|
case glslang::EOpConvDoubleToUint:
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EOpConvFloatToUint64:
|
|
|
|
case glslang::EOpConvDoubleToUint64:
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
case glslang::EOpConvFloat16ToUint64:
|
2015-06-26 22:58:36 +00:00
|
|
|
convOp = spv::OpConvertFToU;
|
|
|
|
break;
|
2016-04-22 08:51:45 +00:00
|
|
|
|
2019-08-08 16:35:51 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
case glslang::EOpConvInt8ToBool:
|
|
|
|
case glslang::EOpConvUint8ToBool:
|
|
|
|
zero = builder.makeUint8Constant(0);
|
|
|
|
zero = makeSmearedConstant(zero, vectorSize);
|
|
|
|
return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
|
|
|
|
case glslang::EOpConvInt16ToBool:
|
|
|
|
case glslang::EOpConvUint16ToBool:
|
|
|
|
zero = builder.makeUint16Constant(0);
|
|
|
|
zero = makeSmearedConstant(zero, vectorSize);
|
|
|
|
return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
|
|
|
|
case glslang::EOpConvInt64ToBool:
|
|
|
|
case glslang::EOpConvUint64ToBool:
|
|
|
|
zero = builder.makeUint64Constant(0);
|
|
|
|
zero = makeSmearedConstant(zero, vectorSize);
|
|
|
|
return builder.createBinOp(spv::OpINotEqual, 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::EOpConvFloat16ToBool:
|
|
|
|
zero = builder.makeFloat16Constant(0.0F);
|
|
|
|
zero = makeSmearedConstant(zero, vectorSize);
|
|
|
|
return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
|
|
|
|
case glslang::EOpConvBoolToDouble:
|
|
|
|
convOp = spv::OpSelect;
|
|
|
|
zero = builder.makeDoubleConstant(0.0);
|
|
|
|
one = builder.makeDoubleConstant(1.0);
|
|
|
|
break;
|
|
|
|
case glslang::EOpConvBoolToFloat16:
|
|
|
|
convOp = spv::OpSelect;
|
|
|
|
zero = builder.makeFloat16Constant(0.0F);
|
|
|
|
one = builder.makeFloat16Constant(1.0F);
|
|
|
|
break;
|
|
|
|
case glslang::EOpConvBoolToInt8:
|
|
|
|
zero = builder.makeInt8Constant(0);
|
|
|
|
one = builder.makeInt8Constant(1);
|
|
|
|
convOp = spv::OpSelect;
|
|
|
|
break;
|
|
|
|
case glslang::EOpConvBoolToUint8:
|
|
|
|
zero = builder.makeUint8Constant(0);
|
|
|
|
one = builder.makeUint8Constant(1);
|
|
|
|
convOp = spv::OpSelect;
|
|
|
|
break;
|
|
|
|
case glslang::EOpConvBoolToInt16:
|
|
|
|
zero = builder.makeInt16Constant(0);
|
|
|
|
one = builder.makeInt16Constant(1);
|
|
|
|
convOp = spv::OpSelect;
|
|
|
|
break;
|
|
|
|
case glslang::EOpConvBoolToUint16:
|
|
|
|
zero = builder.makeUint16Constant(0);
|
|
|
|
one = builder.makeUint16Constant(1);
|
|
|
|
convOp = spv::OpSelect;
|
|
|
|
break;
|
|
|
|
case glslang::EOpConvDoubleToFloat:
|
|
|
|
case glslang::EOpConvFloatToDouble:
|
|
|
|
case glslang::EOpConvDoubleToFloat16:
|
|
|
|
case glslang::EOpConvFloat16ToDouble:
|
|
|
|
case glslang::EOpConvFloatToFloat16:
|
|
|
|
case glslang::EOpConvFloat16ToFloat:
|
|
|
|
convOp = spv::OpFConvert;
|
|
|
|
if (builder.isMatrixType(destType))
|
|
|
|
return createUnaryMatrixOperation(convOp, decorations, destType, operand, typeProxy);
|
|
|
|
break;
|
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvInt8ToInt16:
|
|
|
|
case glslang::EOpConvInt8ToInt:
|
|
|
|
case glslang::EOpConvInt8ToInt64:
|
|
|
|
case glslang::EOpConvInt16ToInt8:
|
2017-03-24 05:41:14 +00:00
|
|
|
case glslang::EOpConvInt16ToInt:
|
|
|
|
case glslang::EOpConvInt16ToInt64:
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvIntToInt8:
|
|
|
|
case glslang::EOpConvIntToInt16:
|
|
|
|
case glslang::EOpConvIntToInt64:
|
|
|
|
case glslang::EOpConvInt64ToInt8:
|
|
|
|
case glslang::EOpConvInt64ToInt16:
|
|
|
|
case glslang::EOpConvInt64ToInt:
|
2016-04-22 08:51:45 +00:00
|
|
|
convOp = spv::OpSConvert;
|
|
|
|
break;
|
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvUint8ToUint16:
|
|
|
|
case glslang::EOpConvUint8ToUint:
|
|
|
|
case glslang::EOpConvUint8ToUint64:
|
|
|
|
case glslang::EOpConvUint16ToUint8:
|
2017-03-24 05:41:14 +00:00
|
|
|
case glslang::EOpConvUint16ToUint:
|
|
|
|
case glslang::EOpConvUint16ToUint64:
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvUintToUint8:
|
|
|
|
case glslang::EOpConvUintToUint16:
|
|
|
|
case glslang::EOpConvUintToUint64:
|
|
|
|
case glslang::EOpConvUint64ToUint8:
|
|
|
|
case glslang::EOpConvUint64ToUint16:
|
|
|
|
case glslang::EOpConvUint64ToUint:
|
2016-04-22 08:51:45 +00:00
|
|
|
convOp = spv::OpUConvert;
|
|
|
|
break;
|
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvInt8ToUint16:
|
|
|
|
case glslang::EOpConvInt8ToUint:
|
|
|
|
case glslang::EOpConvInt8ToUint64:
|
|
|
|
case glslang::EOpConvInt16ToUint8:
|
2017-03-24 05:41:14 +00:00
|
|
|
case glslang::EOpConvInt16ToUint:
|
|
|
|
case glslang::EOpConvInt16ToUint64:
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvIntToUint8:
|
2017-03-24 05:41:14 +00:00
|
|
|
case glslang::EOpConvIntToUint16:
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvIntToUint64:
|
|
|
|
case glslang::EOpConvInt64ToUint8:
|
2017-03-24 05:41:14 +00:00
|
|
|
case glslang::EOpConvInt64ToUint16:
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpConvInt64ToUint:
|
|
|
|
case glslang::EOpConvUint8ToInt16:
|
|
|
|
case glslang::EOpConvUint8ToInt:
|
|
|
|
case glslang::EOpConvUint8ToInt64:
|
|
|
|
case glslang::EOpConvUint16ToInt8:
|
|
|
|
case glslang::EOpConvUint16ToInt:
|
|
|
|
case glslang::EOpConvUint16ToInt64:
|
|
|
|
case glslang::EOpConvUintToInt8:
|
|
|
|
case glslang::EOpConvUintToInt16:
|
|
|
|
case glslang::EOpConvUintToInt64:
|
|
|
|
case glslang::EOpConvUint64ToInt8:
|
|
|
|
case glslang::EOpConvUint64ToInt16:
|
|
|
|
case glslang::EOpConvUint64ToInt:
|
2016-04-22 08:51:45 +00:00
|
|
|
// OpSConvert/OpUConvert + OpBitCast
|
2018-06-05 01:11:25 +00:00
|
|
|
operand = createIntWidthConversion(op, operand, vectorSize);
|
2016-04-22 08:51:45 +00:00
|
|
|
|
|
|
|
if (builder.isInSpecConstCodeGenMode()) {
|
|
|
|
// Build zero scalar or vector for OpIAdd.
|
2018-03-06 23:12:04 +00:00
|
|
|
switch(op) {
|
|
|
|
case glslang::EOpConvInt16ToUint8:
|
|
|
|
case glslang::EOpConvIntToUint8:
|
|
|
|
case glslang::EOpConvInt64ToUint8:
|
|
|
|
case glslang::EOpConvUint16ToInt8:
|
|
|
|
case glslang::EOpConvUintToInt8:
|
|
|
|
case glslang::EOpConvUint64ToInt8:
|
|
|
|
zero = builder.makeUint8Constant(0);
|
|
|
|
break;
|
|
|
|
case glslang::EOpConvInt8ToUint16:
|
|
|
|
case glslang::EOpConvIntToUint16:
|
|
|
|
case glslang::EOpConvInt64ToUint16:
|
|
|
|
case glslang::EOpConvUint8ToInt16:
|
|
|
|
case glslang::EOpConvUintToInt16:
|
|
|
|
case glslang::EOpConvUint64ToInt16:
|
2017-03-24 05:41:14 +00:00
|
|
|
zero = builder.makeUint16Constant(0);
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpConvInt8ToUint:
|
|
|
|
case glslang::EOpConvInt16ToUint:
|
|
|
|
case glslang::EOpConvInt64ToUint:
|
|
|
|
case glslang::EOpConvUint8ToInt:
|
|
|
|
case glslang::EOpConvUint16ToInt:
|
|
|
|
case glslang::EOpConvUint64ToInt:
|
2017-03-24 05:41:14 +00:00
|
|
|
zero = builder.makeUintConstant(0);
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpConvInt8ToUint64:
|
|
|
|
case glslang::EOpConvInt16ToUint64:
|
|
|
|
case glslang::EOpConvIntToUint64:
|
|
|
|
case glslang::EOpConvUint8ToInt64:
|
|
|
|
case glslang::EOpConvUint16ToInt64:
|
|
|
|
case glslang::EOpConvUintToInt64:
|
2017-03-24 05:41:14 +00:00
|
|
|
zero = builder.makeUint64Constant(0);
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(false && "Default missing");
|
|
|
|
break;
|
|
|
|
}
|
2016-04-22 08:51:45 +00:00
|
|
|
zero = makeSmearedConstant(zero, vectorSize);
|
|
|
|
// Use OpIAdd, instead of OpBitcast to do the conversion when
|
|
|
|
// generating for OpSpecConstantOp instruction.
|
|
|
|
return builder.createBinOp(spv::OpIAdd, destType, operand, zero);
|
|
|
|
}
|
|
|
|
// For normal run-time conversion instruction, use OpBitcast.
|
|
|
|
convOp = spv::OpBitcast;
|
|
|
|
break;
|
2019-01-06 23:58:04 +00:00
|
|
|
case glslang::EOpConvUint64ToPtr:
|
|
|
|
convOp = spv::OpConvertUToPtr;
|
|
|
|
break;
|
|
|
|
case glslang::EOpConvPtrToUint64:
|
|
|
|
convOp = spv::OpConvertPtrToU;
|
|
|
|
break;
|
2019-08-08 16:35:51 +00:00
|
|
|
#endif
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
spv::Id result = 0;
|
|
|
|
if (convOp == spv::OpNop)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
if (convOp == spv::OpSelect) {
|
|
|
|
zero = makeSmearedConstant(zero, vectorSize);
|
|
|
|
one = makeSmearedConstant(one, vectorSize);
|
|
|
|
result = builder.createTriOp(convOp, destType, operand, one, zero);
|
|
|
|
} else
|
|
|
|
result = builder.createUnaryOp(convOp, destType, operand);
|
|
|
|
|
2018-03-29 00:01:20 +00:00
|
|
|
result = builder.setPrecision(result, decorations.precision);
|
2019-08-11 13:41:45 +00:00
|
|
|
decorations.addNonUniform(builder, result);
|
2018-03-29 00:01:20 +00:00
|
|
|
return result;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)
|
|
|
|
{
|
|
|
|
if (vectorSize == 0)
|
|
|
|
return constant;
|
|
|
|
|
|
|
|
spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);
|
|
|
|
std::vector<spv::Id> components;
|
|
|
|
for (int c = 0; c < vectorSize; ++c)
|
|
|
|
components.push_back(constant);
|
|
|
|
return builder.makeCompositeConstant(vectorTypeId, components);
|
|
|
|
}
|
|
|
|
|
2015-07-23 16:22:48 +00:00
|
|
|
// For glslang ops that map to SPV atomic opCodes
|
2019-06-14 14:56:28 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags)
|
2015-07-23 16:22:48 +00:00
|
|
|
{
|
|
|
|
spv::Op opCode = spv::OpNop;
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpAtomicAdd:
|
2015-09-09 08:42:49 +00:00
|
|
|
case glslang::EOpImageAtomicAdd:
|
2017-07-23 22:08:26 +00:00
|
|
|
case glslang::EOpAtomicCounterAdd:
|
2015-07-23 16:22:48 +00:00
|
|
|
opCode = spv::OpAtomicIAdd;
|
|
|
|
break;
|
2017-07-23 22:08:26 +00:00
|
|
|
case glslang::EOpAtomicCounterSubtract:
|
|
|
|
opCode = spv::OpAtomicISub;
|
|
|
|
break;
|
2015-07-23 16:22:48 +00:00
|
|
|
case glslang::EOpAtomicMin:
|
2015-09-09 08:42:49 +00:00
|
|
|
case glslang::EOpImageAtomicMin:
|
2017-07-23 22:08:26 +00:00
|
|
|
case glslang::EOpAtomicCounterMin:
|
2017-09-26 07:42:56 +00:00
|
|
|
opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ? spv::OpAtomicUMin : spv::OpAtomicSMin;
|
2015-07-23 16:22:48 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpAtomicMax:
|
2015-09-09 08:42:49 +00:00
|
|
|
case glslang::EOpImageAtomicMax:
|
2017-07-23 22:08:26 +00:00
|
|
|
case glslang::EOpAtomicCounterMax:
|
2017-09-26 07:42:56 +00:00
|
|
|
opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ? spv::OpAtomicUMax : spv::OpAtomicSMax;
|
2015-07-23 16:22:48 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpAtomicAnd:
|
2015-09-09 08:42:49 +00:00
|
|
|
case glslang::EOpImageAtomicAnd:
|
2017-07-23 22:08:26 +00:00
|
|
|
case glslang::EOpAtomicCounterAnd:
|
2015-07-23 16:22:48 +00:00
|
|
|
opCode = spv::OpAtomicAnd;
|
|
|
|
break;
|
|
|
|
case glslang::EOpAtomicOr:
|
2015-09-09 08:42:49 +00:00
|
|
|
case glslang::EOpImageAtomicOr:
|
2017-07-23 22:08:26 +00:00
|
|
|
case glslang::EOpAtomicCounterOr:
|
2015-07-23 16:22:48 +00:00
|
|
|
opCode = spv::OpAtomicOr;
|
|
|
|
break;
|
|
|
|
case glslang::EOpAtomicXor:
|
2015-09-09 08:42:49 +00:00
|
|
|
case glslang::EOpImageAtomicXor:
|
2017-07-23 22:08:26 +00:00
|
|
|
case glslang::EOpAtomicCounterXor:
|
2015-07-23 16:22:48 +00:00
|
|
|
opCode = spv::OpAtomicXor;
|
|
|
|
break;
|
|
|
|
case glslang::EOpAtomicExchange:
|
2015-09-09 08:42:49 +00:00
|
|
|
case glslang::EOpImageAtomicExchange:
|
2017-07-23 22:08:26 +00:00
|
|
|
case glslang::EOpAtomicCounterExchange:
|
2015-07-23 16:22:48 +00:00
|
|
|
opCode = spv::OpAtomicExchange;
|
|
|
|
break;
|
|
|
|
case glslang::EOpAtomicCompSwap:
|
2015-09-09 08:42:49 +00:00
|
|
|
case glslang::EOpImageAtomicCompSwap:
|
2017-07-23 22:08:26 +00:00
|
|
|
case glslang::EOpAtomicCounterCompSwap:
|
2015-07-23 16:22:48 +00:00
|
|
|
opCode = spv::OpAtomicCompareExchange;
|
|
|
|
break;
|
|
|
|
case glslang::EOpAtomicCounterIncrement:
|
|
|
|
opCode = spv::OpAtomicIIncrement;
|
|
|
|
break;
|
|
|
|
case glslang::EOpAtomicCounterDecrement:
|
|
|
|
opCode = spv::OpAtomicIDecrement;
|
|
|
|
break;
|
|
|
|
case glslang::EOpAtomicCounter:
|
2018-09-05 15:11:41 +00:00
|
|
|
case glslang::EOpImageAtomicLoad:
|
|
|
|
case glslang::EOpAtomicLoad:
|
2015-07-23 16:22:48 +00:00
|
|
|
opCode = spv::OpAtomicLoad;
|
|
|
|
break;
|
2018-09-05 15:11:41 +00:00
|
|
|
case glslang::EOpAtomicStore:
|
|
|
|
case glslang::EOpImageAtomicStore:
|
|
|
|
opCode = spv::OpAtomicStore;
|
|
|
|
break;
|
2015-07-23 16:22:48 +00:00
|
|
|
default:
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(0);
|
2015-07-23 16:22:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-09-26 07:42:56 +00:00
|
|
|
if (typeProxy == glslang::EbtInt64 || typeProxy == glslang::EbtUint64)
|
|
|
|
builder.addCapability(spv::CapabilityInt64Atomics);
|
|
|
|
|
2015-07-23 16:22:48 +00:00
|
|
|
// Sort out the operands
|
|
|
|
// - mapping from glslang -> SPV
|
2018-09-05 15:11:41 +00:00
|
|
|
// - there are extra SPV operands that are optional in glslang
|
2015-09-15 04:45:16 +00:00
|
|
|
// - compare-exchange swaps the value and comparator
|
|
|
|
// - compare-exchange has an extra memory semantics
|
2017-10-07 03:21:48 +00:00
|
|
|
// - EOpAtomicCounterDecrement needs a post decrement
|
2018-09-05 15:11:41 +00:00
|
|
|
spv::Id pointerId = 0, compareId = 0, valueId = 0;
|
|
|
|
// scope defaults to Device in the old model, QueueFamilyKHR in the new model
|
|
|
|
spv::Id scopeId;
|
|
|
|
if (glslangIntermediate->usingVulkanMemoryModel()) {
|
|
|
|
scopeId = builder.makeUintConstant(spv::ScopeQueueFamilyKHR);
|
|
|
|
} else {
|
|
|
|
scopeId = builder.makeUintConstant(spv::ScopeDevice);
|
|
|
|
}
|
|
|
|
// semantics default to relaxed
|
2019-08-11 13:41:45 +00:00
|
|
|
spv::Id semanticsId = builder.makeUintConstant(lvalueCoherentFlags.isVolatile() ?
|
|
|
|
spv::MemorySemanticsVolatileMask :
|
|
|
|
spv::MemorySemanticsMaskNone);
|
2018-09-05 15:11:41 +00:00
|
|
|
spv::Id semanticsId2 = semanticsId;
|
|
|
|
|
|
|
|
pointerId = operands[0];
|
|
|
|
if (opCode == spv::OpAtomicIIncrement || opCode == spv::OpAtomicIDecrement) {
|
|
|
|
// no additional operands
|
|
|
|
} else if (opCode == spv::OpAtomicCompareExchange) {
|
|
|
|
compareId = operands[1];
|
|
|
|
valueId = operands[2];
|
|
|
|
if (operands.size() > 3) {
|
|
|
|
scopeId = operands[3];
|
|
|
|
semanticsId = builder.makeUintConstant(builder.getConstantScalar(operands[4]) | builder.getConstantScalar(operands[5]));
|
|
|
|
semanticsId2 = builder.makeUintConstant(builder.getConstantScalar(operands[6]) | builder.getConstantScalar(operands[7]));
|
|
|
|
}
|
|
|
|
} else if (opCode == spv::OpAtomicLoad) {
|
|
|
|
if (operands.size() > 1) {
|
|
|
|
scopeId = operands[1];
|
|
|
|
semanticsId = builder.makeUintConstant(builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// atomic store or RMW
|
|
|
|
valueId = operands[1];
|
|
|
|
if (operands.size() > 2) {
|
|
|
|
scopeId = operands[2];
|
|
|
|
semanticsId = builder.makeUintConstant(builder.getConstantScalar(operands[3]) | builder.getConstantScalar(operands[4]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for capabilities
|
|
|
|
unsigned semanticsImmediate = builder.getConstantScalar(semanticsId) | builder.getConstantScalar(semanticsId2);
|
2019-06-14 14:56:28 +00:00
|
|
|
if (semanticsImmediate & (spv::MemorySemanticsMakeAvailableKHRMask |
|
|
|
|
spv::MemorySemanticsMakeVisibleKHRMask |
|
|
|
|
spv::MemorySemanticsOutputMemoryKHRMask |
|
|
|
|
spv::MemorySemanticsVolatileMask)) {
|
2018-09-05 15:11:41 +00:00
|
|
|
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (glslangIntermediate->usingVulkanMemoryModel() && builder.getConstantScalar(scopeId) == spv::ScopeDevice) {
|
|
|
|
builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
|
|
|
|
}
|
|
|
|
|
2015-07-23 16:22:48 +00:00
|
|
|
std::vector<spv::Id> spvAtomicOperands; // hold the spv operands
|
2018-09-05 15:11:41 +00:00
|
|
|
spvAtomicOperands.push_back(pointerId);
|
|
|
|
spvAtomicOperands.push_back(scopeId);
|
|
|
|
spvAtomicOperands.push_back(semanticsId);
|
2015-09-16 03:44:02 +00:00
|
|
|
if (opCode == spv::OpAtomicCompareExchange) {
|
2018-09-05 15:11:41 +00:00
|
|
|
spvAtomicOperands.push_back(semanticsId2);
|
|
|
|
spvAtomicOperands.push_back(valueId);
|
|
|
|
spvAtomicOperands.push_back(compareId);
|
|
|
|
} else if (opCode != spv::OpAtomicLoad && opCode != spv::OpAtomicIIncrement && opCode != spv::OpAtomicIDecrement) {
|
|
|
|
spvAtomicOperands.push_back(valueId);
|
2015-09-16 03:44:02 +00:00
|
|
|
}
|
2015-07-23 16:22:48 +00:00
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
if (opCode == spv::OpAtomicStore) {
|
|
|
|
builder.createNoResultOp(opCode, spvAtomicOperands);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
spv::Id resultId = builder.createOp(opCode, typeId, spvAtomicOperands);
|
2017-10-07 03:21:48 +00:00
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
// GLSL and HLSL atomic-counter decrement return post-decrement value,
|
|
|
|
// while SPIR-V returns pre-decrement value. Translate between these semantics.
|
|
|
|
if (op == glslang::EOpAtomicCounterDecrement)
|
|
|
|
resultId = builder.createBinOp(spv::OpISub, typeId, resultId, builder.makeIntConstant(1));
|
2017-10-07 03:21:48 +00:00
|
|
|
|
2018-09-05 15:11:41 +00:00
|
|
|
return resultId;
|
|
|
|
}
|
2015-07-23 16:22:48 +00:00
|
|
|
}
|
|
|
|
|
2016-05-05 22:45:40 +00:00
|
|
|
// Create group invocation operations.
|
2016-09-21 10:56:12 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
|
2016-05-05 22:45:40 +00:00
|
|
|
{
|
2018-03-06 23:12:04 +00:00
|
|
|
bool isUnsigned = isTypeUnsignedInt(typeProxy);
|
|
|
|
bool isFloat = isTypeFloat(typeProxy);
|
2016-05-05 04:30:44 +00:00
|
|
|
|
2016-09-21 10:56:12 +00:00
|
|
|
spv::Op opCode = spv::OpNop;
|
2018-08-14 19:31:43 +00:00
|
|
|
std::vector<spv::IdImmediate> spvGroupOperands;
|
2016-10-14 09:22:23 +00:00
|
|
|
spv::GroupOperation groupOperation = spv::GroupOperationMax;
|
|
|
|
|
2016-12-20 20:44:35 +00:00
|
|
|
if (op == glslang::EOpBallot || op == glslang::EOpReadFirstInvocation ||
|
|
|
|
op == glslang::EOpReadInvocation) {
|
2016-09-21 10:56:12 +00:00
|
|
|
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
|
|
|
|
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
|
2017-01-18 22:16:49 +00:00
|
|
|
} else if (op == glslang::EOpAnyInvocation ||
|
|
|
|
op == glslang::EOpAllInvocations ||
|
|
|
|
op == glslang::EOpAllInvocationsEqual) {
|
|
|
|
builder.addExtension(spv::E_SPV_KHR_subgroup_vote);
|
|
|
|
builder.addCapability(spv::CapabilitySubgroupVoteKHR);
|
2016-09-21 10:56:12 +00:00
|
|
|
} else {
|
|
|
|
builder.addCapability(spv::CapabilityGroups);
|
2016-10-14 09:41:45 +00:00
|
|
|
if (op == glslang::EOpMinInvocationsNonUniform ||
|
|
|
|
op == glslang::EOpMaxInvocationsNonUniform ||
|
2016-10-14 09:22:23 +00:00
|
|
|
op == glslang::EOpAddInvocationsNonUniform ||
|
|
|
|
op == glslang::EOpMinInvocationsInclusiveScanNonUniform ||
|
|
|
|
op == glslang::EOpMaxInvocationsInclusiveScanNonUniform ||
|
|
|
|
op == glslang::EOpAddInvocationsInclusiveScanNonUniform ||
|
|
|
|
op == glslang::EOpMinInvocationsExclusiveScanNonUniform ||
|
|
|
|
op == glslang::EOpMaxInvocationsExclusiveScanNonUniform ||
|
|
|
|
op == glslang::EOpAddInvocationsExclusiveScanNonUniform)
|
2016-10-14 09:41:45 +00:00
|
|
|
builder.addExtension(spv::E_SPV_AMD_shader_ballot);
|
2016-09-21 10:56:12 +00:00
|
|
|
|
2016-10-14 09:22:23 +00:00
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpMinInvocations:
|
|
|
|
case glslang::EOpMaxInvocations:
|
|
|
|
case glslang::EOpAddInvocations:
|
|
|
|
case glslang::EOpMinInvocationsNonUniform:
|
|
|
|
case glslang::EOpMaxInvocationsNonUniform:
|
|
|
|
case glslang::EOpAddInvocationsNonUniform:
|
|
|
|
groupOperation = spv::GroupOperationReduce;
|
|
|
|
break;
|
|
|
|
case glslang::EOpMinInvocationsInclusiveScan:
|
|
|
|
case glslang::EOpMaxInvocationsInclusiveScan:
|
|
|
|
case glslang::EOpAddInvocationsInclusiveScan:
|
|
|
|
case glslang::EOpMinInvocationsInclusiveScanNonUniform:
|
|
|
|
case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
|
|
|
|
case glslang::EOpAddInvocationsInclusiveScanNonUniform:
|
|
|
|
groupOperation = spv::GroupOperationInclusiveScan;
|
|
|
|
break;
|
|
|
|
case glslang::EOpMinInvocationsExclusiveScan:
|
|
|
|
case glslang::EOpMaxInvocationsExclusiveScan:
|
|
|
|
case glslang::EOpAddInvocationsExclusiveScan:
|
|
|
|
case glslang::EOpMinInvocationsExclusiveScanNonUniform:
|
|
|
|
case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
|
|
|
|
case glslang::EOpAddInvocationsExclusiveScanNonUniform:
|
|
|
|
groupOperation = spv::GroupOperationExclusiveScan;
|
|
|
|
break;
|
2017-01-20 20:34:10 +00:00
|
|
|
default:
|
|
|
|
break;
|
2016-10-14 09:22:23 +00:00
|
|
|
}
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
|
|
|
|
spvGroupOperands.push_back(scope);
|
|
|
|
if (groupOperation != spv::GroupOperationMax) {
|
2018-09-18 09:43:30 +00:00
|
|
|
spv::IdImmediate groupOp = { false, (unsigned)groupOperation };
|
2018-08-14 19:31:43 +00:00
|
|
|
spvGroupOperands.push_back(groupOp);
|
|
|
|
}
|
2016-09-21 10:56:12 +00:00
|
|
|
}
|
|
|
|
|
2018-08-14 19:31:43 +00:00
|
|
|
for (auto opIt = operands.begin(); opIt != operands.end(); ++opIt) {
|
|
|
|
spv::IdImmediate op = { true, *opIt };
|
|
|
|
spvGroupOperands.push_back(op);
|
|
|
|
}
|
2016-05-05 22:45:40 +00:00
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpAnyInvocation:
|
2017-01-18 22:16:49 +00:00
|
|
|
opCode = spv::OpSubgroupAnyKHR;
|
2016-09-21 10:56:12 +00:00
|
|
|
break;
|
2016-05-05 22:45:40 +00:00
|
|
|
case glslang::EOpAllInvocations:
|
2017-01-18 22:16:49 +00:00
|
|
|
opCode = spv::OpSubgroupAllKHR;
|
2016-09-21 10:56:12 +00:00
|
|
|
break;
|
2016-05-05 22:45:40 +00:00
|
|
|
case glslang::EOpAllInvocationsEqual:
|
2017-01-18 22:16:49 +00:00
|
|
|
opCode = spv::OpSubgroupAllEqualKHR;
|
|
|
|
break;
|
2016-09-21 10:56:12 +00:00
|
|
|
case glslang::EOpReadInvocation:
|
2016-12-20 20:44:35 +00:00
|
|
|
opCode = spv::OpSubgroupReadInvocationKHR;
|
2016-09-26 07:53:40 +00:00
|
|
|
if (builder.isVectorType(typeId))
|
2016-10-14 09:22:23 +00:00
|
|
|
return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
|
2016-09-21 10:56:12 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpReadFirstInvocation:
|
|
|
|
opCode = spv::OpSubgroupFirstInvocationKHR;
|
|
|
|
break;
|
|
|
|
case glslang::EOpBallot:
|
|
|
|
{
|
|
|
|
// NOTE: According to the spec, the result type of "OpSubgroupBallotKHR" must be a 4 component vector of 32
|
|
|
|
// bit integer types. The GLSL built-in function "ballotARB()" assumes the maximum number of invocations in
|
|
|
|
// a subgroup is 64. Thus, we have to convert uvec4.xy to uint64_t as follow:
|
|
|
|
//
|
|
|
|
// result = Bitcast(SubgroupBallotKHR(Predicate).xy)
|
|
|
|
//
|
|
|
|
spv::Id uintType = builder.makeUintType(32);
|
|
|
|
spv::Id uvec4Type = builder.makeVectorType(uintType, 4);
|
|
|
|
spv::Id result = builder.createOp(spv::OpSubgroupBallotKHR, uvec4Type, spvGroupOperands);
|
|
|
|
|
|
|
|
std::vector<spv::Id> components;
|
|
|
|
components.push_back(builder.createCompositeExtract(result, uintType, 0));
|
|
|
|
components.push_back(builder.createCompositeExtract(result, uintType, 1));
|
|
|
|
|
|
|
|
spv::Id uvec2Type = builder.makeVectorType(uintType, 2);
|
|
|
|
return builder.createUnaryOp(spv::OpBitcast, typeId,
|
|
|
|
builder.createCompositeConstruct(uvec2Type, components));
|
|
|
|
}
|
|
|
|
|
2016-05-05 04:30:44 +00:00
|
|
|
case glslang::EOpMinInvocations:
|
|
|
|
case glslang::EOpMaxInvocations:
|
|
|
|
case glslang::EOpAddInvocations:
|
2016-10-14 09:22:23 +00:00
|
|
|
case glslang::EOpMinInvocationsInclusiveScan:
|
|
|
|
case glslang::EOpMaxInvocationsInclusiveScan:
|
|
|
|
case glslang::EOpAddInvocationsInclusiveScan:
|
|
|
|
case glslang::EOpMinInvocationsExclusiveScan:
|
|
|
|
case glslang::EOpMaxInvocationsExclusiveScan:
|
|
|
|
case glslang::EOpAddInvocationsExclusiveScan:
|
|
|
|
if (op == glslang::EOpMinInvocations ||
|
|
|
|
op == glslang::EOpMinInvocationsInclusiveScan ||
|
|
|
|
op == glslang::EOpMinInvocationsExclusiveScan) {
|
2016-05-05 04:30:44 +00:00
|
|
|
if (isFloat)
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupFMin;
|
2016-05-05 04:30:44 +00:00
|
|
|
else {
|
|
|
|
if (isUnsigned)
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupUMin;
|
2016-05-05 04:30:44 +00:00
|
|
|
else
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupSMin;
|
2016-05-05 04:30:44 +00:00
|
|
|
}
|
2016-10-14 09:22:23 +00:00
|
|
|
} else if (op == glslang::EOpMaxInvocations ||
|
|
|
|
op == glslang::EOpMaxInvocationsInclusiveScan ||
|
|
|
|
op == glslang::EOpMaxInvocationsExclusiveScan) {
|
2016-05-05 04:30:44 +00:00
|
|
|
if (isFloat)
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupFMax;
|
2016-05-05 04:30:44 +00:00
|
|
|
else {
|
|
|
|
if (isUnsigned)
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupUMax;
|
2016-05-05 04:30:44 +00:00
|
|
|
else
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupSMax;
|
2016-05-05 04:30:44 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (isFloat)
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupFAdd;
|
2016-05-05 04:30:44 +00:00
|
|
|
else
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupIAdd;
|
2016-05-05 04:30:44 +00:00
|
|
|
}
|
|
|
|
|
2016-08-23 07:41:05 +00:00
|
|
|
if (builder.isVectorType(typeId))
|
2016-10-14 09:22:23 +00:00
|
|
|
return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
|
2016-09-21 10:56:12 +00:00
|
|
|
|
|
|
|
break;
|
2016-05-05 04:30:44 +00:00
|
|
|
case glslang::EOpMinInvocationsNonUniform:
|
|
|
|
case glslang::EOpMaxInvocationsNonUniform:
|
|
|
|
case glslang::EOpAddInvocationsNonUniform:
|
2016-10-14 09:22:23 +00:00
|
|
|
case glslang::EOpMinInvocationsInclusiveScanNonUniform:
|
|
|
|
case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
|
|
|
|
case glslang::EOpAddInvocationsInclusiveScanNonUniform:
|
|
|
|
case glslang::EOpMinInvocationsExclusiveScanNonUniform:
|
|
|
|
case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
|
|
|
|
case glslang::EOpAddInvocationsExclusiveScanNonUniform:
|
|
|
|
if (op == glslang::EOpMinInvocationsNonUniform ||
|
|
|
|
op == glslang::EOpMinInvocationsInclusiveScanNonUniform ||
|
|
|
|
op == glslang::EOpMinInvocationsExclusiveScanNonUniform) {
|
2016-05-05 04:30:44 +00:00
|
|
|
if (isFloat)
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupFMinNonUniformAMD;
|
2016-05-05 04:30:44 +00:00
|
|
|
else {
|
|
|
|
if (isUnsigned)
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupUMinNonUniformAMD;
|
2016-05-05 04:30:44 +00:00
|
|
|
else
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupSMinNonUniformAMD;
|
2016-05-05 04:30:44 +00:00
|
|
|
}
|
|
|
|
}
|
2016-10-14 09:22:23 +00:00
|
|
|
else if (op == glslang::EOpMaxInvocationsNonUniform ||
|
|
|
|
op == glslang::EOpMaxInvocationsInclusiveScanNonUniform ||
|
|
|
|
op == glslang::EOpMaxInvocationsExclusiveScanNonUniform) {
|
2016-05-05 04:30:44 +00:00
|
|
|
if (isFloat)
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupFMaxNonUniformAMD;
|
2016-05-05 04:30:44 +00:00
|
|
|
else {
|
|
|
|
if (isUnsigned)
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupUMaxNonUniformAMD;
|
2016-05-05 04:30:44 +00:00
|
|
|
else
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupSMaxNonUniformAMD;
|
2016-05-05 04:30:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (isFloat)
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupFAddNonUniformAMD;
|
2016-05-05 04:30:44 +00:00
|
|
|
else
|
2016-09-21 10:56:12 +00:00
|
|
|
opCode = spv::OpGroupIAddNonUniformAMD;
|
2016-05-05 04:30:44 +00:00
|
|
|
}
|
|
|
|
|
2016-08-23 07:41:05 +00:00
|
|
|
if (builder.isVectorType(typeId))
|
2016-10-14 09:22:23 +00:00
|
|
|
return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
|
2016-09-21 10:56:12 +00:00
|
|
|
|
|
|
|
break;
|
2016-05-05 22:45:40 +00:00
|
|
|
default:
|
|
|
|
logger->missingFunctionality("invocation operation");
|
|
|
|
return spv::NoResult;
|
|
|
|
}
|
2016-09-21 10:56:12 +00:00
|
|
|
|
|
|
|
assert(opCode != spv::OpNop);
|
|
|
|
return builder.createOp(opCode, typeId, spvGroupOperands);
|
2016-05-05 22:45:40 +00:00
|
|
|
}
|
|
|
|
|
2016-08-23 07:41:05 +00:00
|
|
|
// Create group invocation operations on a vector
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation,
|
|
|
|
spv::Id typeId, std::vector<spv::Id>& operands)
|
2016-08-23 07:41:05 +00:00
|
|
|
{
|
|
|
|
assert(op == spv::OpGroupFMin || op == spv::OpGroupUMin || op == spv::OpGroupSMin ||
|
|
|
|
op == spv::OpGroupFMax || op == spv::OpGroupUMax || op == spv::OpGroupSMax ||
|
2016-09-26 07:53:40 +00:00
|
|
|
op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast ||
|
2016-12-20 20:44:35 +00:00
|
|
|
op == spv::OpSubgroupReadInvocationKHR ||
|
2016-08-23 07:41:05 +00:00
|
|
|
op == spv::OpGroupFMinNonUniformAMD || op == spv::OpGroupUMinNonUniformAMD || op == spv::OpGroupSMinNonUniformAMD ||
|
|
|
|
op == spv::OpGroupFMaxNonUniformAMD || op == spv::OpGroupUMaxNonUniformAMD || op == spv::OpGroupSMaxNonUniformAMD ||
|
|
|
|
op == spv::OpGroupFAddNonUniformAMD || op == spv::OpGroupIAddNonUniformAMD);
|
|
|
|
|
|
|
|
// Handle group invocation operations scalar by scalar.
|
|
|
|
// The result type is the same type as the original type.
|
|
|
|
// The algorithm is to:
|
|
|
|
// - break the vector into scalars
|
|
|
|
// - apply the operation to each scalar
|
|
|
|
// - make a vector out the scalar results
|
|
|
|
|
|
|
|
// get the types sorted out
|
2016-09-26 07:53:40 +00:00
|
|
|
int numComponents = builder.getNumComponents(operands[0]);
|
|
|
|
spv::Id scalarType = builder.getScalarTypeId(builder.getTypeId(operands[0]));
|
2016-08-23 07:41:05 +00:00
|
|
|
std::vector<spv::Id> results;
|
|
|
|
|
|
|
|
// do each scalar op
|
|
|
|
for (int comp = 0; comp < numComponents; ++comp) {
|
|
|
|
std::vector<unsigned int> indexes;
|
|
|
|
indexes.push_back(comp);
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::IdImmediate scalar = { true, builder.createCompositeExtract(operands[0], scalarType, indexes) };
|
|
|
|
std::vector<spv::IdImmediate> spvGroupOperands;
|
2016-12-20 20:44:35 +00:00
|
|
|
if (op == spv::OpSubgroupReadInvocationKHR) {
|
|
|
|
spvGroupOperands.push_back(scalar);
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::IdImmediate operand = { true, operands[1] };
|
|
|
|
spvGroupOperands.push_back(operand);
|
2016-12-20 20:44:35 +00:00
|
|
|
} else if (op == spv::OpGroupBroadcast) {
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
|
|
|
|
spvGroupOperands.push_back(scope);
|
2016-09-26 07:53:40 +00:00
|
|
|
spvGroupOperands.push_back(scalar);
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::IdImmediate operand = { true, operands[1] };
|
|
|
|
spvGroupOperands.push_back(operand);
|
2016-09-26 07:53:40 +00:00
|
|
|
} else {
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
|
|
|
|
spvGroupOperands.push_back(scope);
|
2018-09-18 09:43:30 +00:00
|
|
|
spv::IdImmediate groupOp = { false, (unsigned)groupOperation };
|
2018-08-14 19:31:43 +00:00
|
|
|
spvGroupOperands.push_back(groupOp);
|
2016-09-26 07:53:40 +00:00
|
|
|
spvGroupOperands.push_back(scalar);
|
|
|
|
}
|
2016-08-23 07:41:05 +00:00
|
|
|
|
2016-09-26 07:53:40 +00:00
|
|
|
results.push_back(builder.createOp(op, scalarType, spvGroupOperands));
|
2016-08-23 07:41:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// put the pieces together
|
|
|
|
return builder.createCompositeConstruct(typeId, results);
|
|
|
|
}
|
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
// Create subgroup invocation operations.
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, spv::Id typeId,
|
|
|
|
std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
|
2018-03-06 23:12:04 +00:00
|
|
|
{
|
|
|
|
// Add the required capabilities.
|
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpSubgroupElect:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupAll:
|
|
|
|
case glslang::EOpSubgroupAny:
|
|
|
|
case glslang::EOpSubgroupAllEqual:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformVote);
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupBroadcast:
|
|
|
|
case glslang::EOpSubgroupBroadcastFirst:
|
|
|
|
case glslang::EOpSubgroupBallot:
|
|
|
|
case glslang::EOpSubgroupInverseBallot:
|
|
|
|
case glslang::EOpSubgroupBallotBitExtract:
|
|
|
|
case glslang::EOpSubgroupBallotBitCount:
|
|
|
|
case glslang::EOpSubgroupBallotInclusiveBitCount:
|
|
|
|
case glslang::EOpSubgroupBallotExclusiveBitCount:
|
|
|
|
case glslang::EOpSubgroupBallotFindLSB:
|
|
|
|
case glslang::EOpSubgroupBallotFindMSB:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupShuffle:
|
|
|
|
case glslang::EOpSubgroupShuffleXor:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformShuffle);
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupShuffleUp:
|
|
|
|
case glslang::EOpSubgroupShuffleDown:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformShuffleRelative);
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupAdd:
|
|
|
|
case glslang::EOpSubgroupMul:
|
|
|
|
case glslang::EOpSubgroupMin:
|
|
|
|
case glslang::EOpSubgroupMax:
|
|
|
|
case glslang::EOpSubgroupAnd:
|
|
|
|
case glslang::EOpSubgroupOr:
|
|
|
|
case glslang::EOpSubgroupXor:
|
|
|
|
case glslang::EOpSubgroupInclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupInclusiveMul:
|
|
|
|
case glslang::EOpSubgroupInclusiveMin:
|
|
|
|
case glslang::EOpSubgroupInclusiveMax:
|
|
|
|
case glslang::EOpSubgroupInclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupInclusiveOr:
|
|
|
|
case glslang::EOpSubgroupInclusiveXor:
|
|
|
|
case glslang::EOpSubgroupExclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupExclusiveMul:
|
|
|
|
case glslang::EOpSubgroupExclusiveMin:
|
|
|
|
case glslang::EOpSubgroupExclusiveMax:
|
|
|
|
case glslang::EOpSubgroupExclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupExclusiveOr:
|
|
|
|
case glslang::EOpSubgroupExclusiveXor:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformArithmetic);
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupClusteredAdd:
|
|
|
|
case glslang::EOpSubgroupClusteredMul:
|
|
|
|
case glslang::EOpSubgroupClusteredMin:
|
|
|
|
case glslang::EOpSubgroupClusteredMax:
|
|
|
|
case glslang::EOpSubgroupClusteredAnd:
|
|
|
|
case glslang::EOpSubgroupClusteredOr:
|
|
|
|
case glslang::EOpSubgroupClusteredXor:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformClustered);
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupQuadBroadcast:
|
|
|
|
case glslang::EOpSubgroupQuadSwapHorizontal:
|
|
|
|
case glslang::EOpSubgroupQuadSwapVertical:
|
|
|
|
case glslang::EOpSubgroupQuadSwapDiagonal:
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniform);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformQuad);
|
|
|
|
break;
|
2018-03-30 03:52:17 +00:00
|
|
|
case glslang::EOpSubgroupPartitionedAdd:
|
|
|
|
case glslang::EOpSubgroupPartitionedMul:
|
|
|
|
case glslang::EOpSubgroupPartitionedMin:
|
|
|
|
case glslang::EOpSubgroupPartitionedMax:
|
|
|
|
case glslang::EOpSubgroupPartitionedAnd:
|
|
|
|
case glslang::EOpSubgroupPartitionedOr:
|
|
|
|
case glslang::EOpSubgroupPartitionedXor:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMul:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMin:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMax:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveOr:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveXor:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMul:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMin:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMax:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveOr:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveXor:
|
|
|
|
builder.addExtension(spv::E_SPV_NV_shader_subgroup_partitioned);
|
|
|
|
builder.addCapability(spv::CapabilityGroupNonUniformPartitionedNV);
|
|
|
|
break;
|
2018-03-06 23:12:04 +00:00
|
|
|
default: assert(0 && "Unhandled subgroup operation!");
|
|
|
|
}
|
|
|
|
|
|
|
|
const bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64;
|
|
|
|
const bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
|
|
|
|
const bool isBool = typeProxy == glslang::EbtBool;
|
|
|
|
|
|
|
|
spv::Op opCode = spv::OpNop;
|
|
|
|
|
|
|
|
// Figure out which opcode to use.
|
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpSubgroupElect: opCode = spv::OpGroupNonUniformElect; break;
|
|
|
|
case glslang::EOpSubgroupAll: opCode = spv::OpGroupNonUniformAll; break;
|
|
|
|
case glslang::EOpSubgroupAny: opCode = spv::OpGroupNonUniformAny; break;
|
|
|
|
case glslang::EOpSubgroupAllEqual: opCode = spv::OpGroupNonUniformAllEqual; break;
|
|
|
|
case glslang::EOpSubgroupBroadcast: opCode = spv::OpGroupNonUniformBroadcast; break;
|
|
|
|
case glslang::EOpSubgroupBroadcastFirst: opCode = spv::OpGroupNonUniformBroadcastFirst; break;
|
|
|
|
case glslang::EOpSubgroupBallot: opCode = spv::OpGroupNonUniformBallot; break;
|
|
|
|
case glslang::EOpSubgroupInverseBallot: opCode = spv::OpGroupNonUniformInverseBallot; break;
|
|
|
|
case glslang::EOpSubgroupBallotBitExtract: opCode = spv::OpGroupNonUniformBallotBitExtract; break;
|
|
|
|
case glslang::EOpSubgroupBallotBitCount:
|
|
|
|
case glslang::EOpSubgroupBallotInclusiveBitCount:
|
|
|
|
case glslang::EOpSubgroupBallotExclusiveBitCount: opCode = spv::OpGroupNonUniformBallotBitCount; break;
|
|
|
|
case glslang::EOpSubgroupBallotFindLSB: opCode = spv::OpGroupNonUniformBallotFindLSB; break;
|
|
|
|
case glslang::EOpSubgroupBallotFindMSB: opCode = spv::OpGroupNonUniformBallotFindMSB; break;
|
|
|
|
case glslang::EOpSubgroupShuffle: opCode = spv::OpGroupNonUniformShuffle; break;
|
|
|
|
case glslang::EOpSubgroupShuffleXor: opCode = spv::OpGroupNonUniformShuffleXor; break;
|
|
|
|
case glslang::EOpSubgroupShuffleUp: opCode = spv::OpGroupNonUniformShuffleUp; break;
|
|
|
|
case glslang::EOpSubgroupShuffleDown: opCode = spv::OpGroupNonUniformShuffleDown; break;
|
|
|
|
case glslang::EOpSubgroupAdd:
|
|
|
|
case glslang::EOpSubgroupInclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupExclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupClusteredAdd:
|
2018-03-30 03:52:17 +00:00
|
|
|
case glslang::EOpSubgroupPartitionedAdd:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveAdd:
|
2018-03-06 23:12:04 +00:00
|
|
|
if (isFloat) {
|
|
|
|
opCode = spv::OpGroupNonUniformFAdd;
|
|
|
|
} else {
|
|
|
|
opCode = spv::OpGroupNonUniformIAdd;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupMul:
|
|
|
|
case glslang::EOpSubgroupInclusiveMul:
|
|
|
|
case glslang::EOpSubgroupExclusiveMul:
|
|
|
|
case glslang::EOpSubgroupClusteredMul:
|
2018-03-30 03:52:17 +00:00
|
|
|
case glslang::EOpSubgroupPartitionedMul:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMul:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMul:
|
2018-03-06 23:12:04 +00:00
|
|
|
if (isFloat) {
|
|
|
|
opCode = spv::OpGroupNonUniformFMul;
|
|
|
|
} else {
|
|
|
|
opCode = spv::OpGroupNonUniformIMul;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupMin:
|
|
|
|
case glslang::EOpSubgroupInclusiveMin:
|
|
|
|
case glslang::EOpSubgroupExclusiveMin:
|
|
|
|
case glslang::EOpSubgroupClusteredMin:
|
2018-03-30 03:52:17 +00:00
|
|
|
case glslang::EOpSubgroupPartitionedMin:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMin:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMin:
|
2018-03-06 23:12:04 +00:00
|
|
|
if (isFloat) {
|
|
|
|
opCode = spv::OpGroupNonUniformFMin;
|
|
|
|
} else if (isUnsigned) {
|
|
|
|
opCode = spv::OpGroupNonUniformUMin;
|
|
|
|
} else {
|
|
|
|
opCode = spv::OpGroupNonUniformSMin;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupMax:
|
|
|
|
case glslang::EOpSubgroupInclusiveMax:
|
|
|
|
case glslang::EOpSubgroupExclusiveMax:
|
|
|
|
case glslang::EOpSubgroupClusteredMax:
|
2018-03-30 03:52:17 +00:00
|
|
|
case glslang::EOpSubgroupPartitionedMax:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMax:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMax:
|
2018-03-06 23:12:04 +00:00
|
|
|
if (isFloat) {
|
|
|
|
opCode = spv::OpGroupNonUniformFMax;
|
|
|
|
} else if (isUnsigned) {
|
|
|
|
opCode = spv::OpGroupNonUniformUMax;
|
|
|
|
} else {
|
|
|
|
opCode = spv::OpGroupNonUniformSMax;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupAnd:
|
|
|
|
case glslang::EOpSubgroupInclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupExclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupClusteredAnd:
|
2018-03-30 03:52:17 +00:00
|
|
|
case glslang::EOpSubgroupPartitionedAnd:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveAnd:
|
2018-03-06 23:12:04 +00:00
|
|
|
if (isBool) {
|
|
|
|
opCode = spv::OpGroupNonUniformLogicalAnd;
|
|
|
|
} else {
|
|
|
|
opCode = spv::OpGroupNonUniformBitwiseAnd;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupOr:
|
|
|
|
case glslang::EOpSubgroupInclusiveOr:
|
|
|
|
case glslang::EOpSubgroupExclusiveOr:
|
|
|
|
case glslang::EOpSubgroupClusteredOr:
|
2018-03-30 03:52:17 +00:00
|
|
|
case glslang::EOpSubgroupPartitionedOr:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveOr:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveOr:
|
2018-03-06 23:12:04 +00:00
|
|
|
if (isBool) {
|
|
|
|
opCode = spv::OpGroupNonUniformLogicalOr;
|
|
|
|
} else {
|
|
|
|
opCode = spv::OpGroupNonUniformBitwiseOr;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupXor:
|
|
|
|
case glslang::EOpSubgroupInclusiveXor:
|
|
|
|
case glslang::EOpSubgroupExclusiveXor:
|
|
|
|
case glslang::EOpSubgroupClusteredXor:
|
2018-03-30 03:52:17 +00:00
|
|
|
case glslang::EOpSubgroupPartitionedXor:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveXor:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveXor:
|
2018-03-06 23:12:04 +00:00
|
|
|
if (isBool) {
|
|
|
|
opCode = spv::OpGroupNonUniformLogicalXor;
|
|
|
|
} else {
|
|
|
|
opCode = spv::OpGroupNonUniformBitwiseXor;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupQuadBroadcast: opCode = spv::OpGroupNonUniformQuadBroadcast; break;
|
|
|
|
case glslang::EOpSubgroupQuadSwapHorizontal:
|
|
|
|
case glslang::EOpSubgroupQuadSwapVertical:
|
|
|
|
case glslang::EOpSubgroupQuadSwapDiagonal: opCode = spv::OpGroupNonUniformQuadSwap; break;
|
|
|
|
default: assert(0 && "Unhandled subgroup operation!");
|
|
|
|
}
|
|
|
|
|
2018-08-14 19:31:43 +00:00
|
|
|
// get the right Group Operation
|
|
|
|
spv::GroupOperation groupOperation = spv::GroupOperationMax;
|
2018-03-06 23:12:04 +00:00
|
|
|
switch (op) {
|
2018-08-14 19:31:43 +00:00
|
|
|
default:
|
|
|
|
break;
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpSubgroupBallotBitCount:
|
|
|
|
case glslang::EOpSubgroupAdd:
|
|
|
|
case glslang::EOpSubgroupMul:
|
|
|
|
case glslang::EOpSubgroupMin:
|
|
|
|
case glslang::EOpSubgroupMax:
|
|
|
|
case glslang::EOpSubgroupAnd:
|
|
|
|
case glslang::EOpSubgroupOr:
|
|
|
|
case glslang::EOpSubgroupXor:
|
2018-08-14 19:31:43 +00:00
|
|
|
groupOperation = spv::GroupOperationReduce;
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupBallotInclusiveBitCount:
|
|
|
|
case glslang::EOpSubgroupInclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupInclusiveMul:
|
|
|
|
case glslang::EOpSubgroupInclusiveMin:
|
|
|
|
case glslang::EOpSubgroupInclusiveMax:
|
|
|
|
case glslang::EOpSubgroupInclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupInclusiveOr:
|
|
|
|
case glslang::EOpSubgroupInclusiveXor:
|
2018-08-14 19:31:43 +00:00
|
|
|
groupOperation = spv::GroupOperationInclusiveScan;
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupBallotExclusiveBitCount:
|
|
|
|
case glslang::EOpSubgroupExclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupExclusiveMul:
|
|
|
|
case glslang::EOpSubgroupExclusiveMin:
|
|
|
|
case glslang::EOpSubgroupExclusiveMax:
|
|
|
|
case glslang::EOpSubgroupExclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupExclusiveOr:
|
|
|
|
case glslang::EOpSubgroupExclusiveXor:
|
2018-08-14 19:31:43 +00:00
|
|
|
groupOperation = spv::GroupOperationExclusiveScan;
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupClusteredAdd:
|
|
|
|
case glslang::EOpSubgroupClusteredMul:
|
|
|
|
case glslang::EOpSubgroupClusteredMin:
|
|
|
|
case glslang::EOpSubgroupClusteredMax:
|
|
|
|
case glslang::EOpSubgroupClusteredAnd:
|
|
|
|
case glslang::EOpSubgroupClusteredOr:
|
|
|
|
case glslang::EOpSubgroupClusteredXor:
|
2018-08-14 19:31:43 +00:00
|
|
|
groupOperation = spv::GroupOperationClusteredReduce;
|
2018-03-06 23:12:04 +00:00
|
|
|
break;
|
2018-03-30 03:52:17 +00:00
|
|
|
case glslang::EOpSubgroupPartitionedAdd:
|
|
|
|
case glslang::EOpSubgroupPartitionedMul:
|
|
|
|
case glslang::EOpSubgroupPartitionedMin:
|
|
|
|
case glslang::EOpSubgroupPartitionedMax:
|
|
|
|
case glslang::EOpSubgroupPartitionedAnd:
|
|
|
|
case glslang::EOpSubgroupPartitionedOr:
|
|
|
|
case glslang::EOpSubgroupPartitionedXor:
|
2018-08-14 19:31:43 +00:00
|
|
|
groupOperation = spv::GroupOperationPartitionedReduceNV;
|
2018-03-30 03:52:17 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMul:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMin:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMax:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveOr:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveXor:
|
2018-08-14 19:31:43 +00:00
|
|
|
groupOperation = spv::GroupOperationPartitionedInclusiveScanNV;
|
2018-03-30 03:52:17 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMul:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMin:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMax:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveOr:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveXor:
|
2018-08-14 19:31:43 +00:00
|
|
|
groupOperation = spv::GroupOperationPartitionedExclusiveScanNV;
|
2018-03-30 03:52:17 +00:00
|
|
|
break;
|
2018-03-06 23:12:04 +00:00
|
|
|
}
|
|
|
|
|
2018-08-14 19:31:43 +00:00
|
|
|
// build the instruction
|
|
|
|
std::vector<spv::IdImmediate> spvGroupOperands;
|
|
|
|
|
|
|
|
// Every operation begins with the Execution Scope operand.
|
|
|
|
spv::IdImmediate executionScope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
|
|
|
|
spvGroupOperands.push_back(executionScope);
|
|
|
|
|
|
|
|
// Next, for all operations that use a Group Operation, push that as an operand.
|
|
|
|
if (groupOperation != spv::GroupOperationMax) {
|
2018-09-18 09:43:30 +00:00
|
|
|
spv::IdImmediate groupOperand = { false, (unsigned)groupOperation };
|
2018-08-14 19:31:43 +00:00
|
|
|
spvGroupOperands.push_back(groupOperand);
|
|
|
|
}
|
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
// Push back the operands next.
|
2018-08-14 19:31:43 +00:00
|
|
|
for (auto opIt = operands.cbegin(); opIt != operands.cend(); ++opIt) {
|
|
|
|
spv::IdImmediate operand = { true, *opIt };
|
|
|
|
spvGroupOperands.push_back(operand);
|
2018-03-06 23:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Some opcodes have additional operands.
|
2018-08-14 19:31:43 +00:00
|
|
|
spv::Id directionId = spv::NoResult;
|
2018-03-06 23:12:04 +00:00
|
|
|
switch (op) {
|
|
|
|
default: break;
|
2018-08-14 19:31:43 +00:00
|
|
|
case glslang::EOpSubgroupQuadSwapHorizontal: directionId = builder.makeUintConstant(0); break;
|
|
|
|
case glslang::EOpSubgroupQuadSwapVertical: directionId = builder.makeUintConstant(1); break;
|
|
|
|
case glslang::EOpSubgroupQuadSwapDiagonal: directionId = builder.makeUintConstant(2); break;
|
|
|
|
}
|
|
|
|
if (directionId != spv::NoResult) {
|
|
|
|
spv::IdImmediate direction = { true, directionId };
|
|
|
|
spvGroupOperands.push_back(direction);
|
2018-03-06 23:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return builder.createOp(opCode, typeId, spvGroupOperands);
|
|
|
|
}
|
|
|
|
|
2015-08-07 04:53:06 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2018-03-06 23:12:04 +00:00
|
|
|
bool isUnsigned = isTypeUnsignedInt(typeProxy);
|
|
|
|
bool isFloat = isTypeFloat(typeProxy);
|
2015-08-07 04:53:06 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
spv::Op opCode = spv::OpNop;
|
2016-05-05 04:30:44 +00:00
|
|
|
int extBuiltins = -1;
|
2015-06-26 22:58:36 +00:00
|
|
|
int libCall = -1;
|
2016-01-06 18:41:02 +00:00
|
|
|
size_t consumedOperands = operands.size();
|
2015-11-16 04:33:39 +00:00
|
|
|
spv::Id typeId0 = 0;
|
|
|
|
if (consumedOperands > 0)
|
|
|
|
typeId0 = builder.getTypeId(operands[0]);
|
2017-03-29 09:12:40 +00:00
|
|
|
spv::Id typeId1 = 0;
|
|
|
|
if (consumedOperands > 1)
|
|
|
|
typeId1 = builder.getTypeId(operands[1]);
|
2015-11-16 04:33:39 +00:00
|
|
|
spv::Id frexpIntType = 0;
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpMin:
|
2015-08-07 04:53:06 +00:00
|
|
|
if (isFloat)
|
2019-06-18 05:33:09 +00:00
|
|
|
libCall = nanMinMaxClamp ? spv::GLSLstd450NMin : spv::GLSLstd450FMin;
|
2015-08-07 04:53:06 +00:00
|
|
|
else if (isUnsigned)
|
|
|
|
libCall = spv::GLSLstd450UMin;
|
|
|
|
else
|
|
|
|
libCall = spv::GLSLstd450SMin;
|
2015-12-13 20:34:37 +00:00
|
|
|
builder.promoteScalar(precision, operands.front(), operands.back());
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpModf:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Modf;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpMax:
|
2015-08-07 04:53:06 +00:00
|
|
|
if (isFloat)
|
2019-06-18 05:33:09 +00:00
|
|
|
libCall = nanMinMaxClamp ? spv::GLSLstd450NMax : spv::GLSLstd450FMax;
|
2015-08-07 04:53:06 +00:00
|
|
|
else if (isUnsigned)
|
|
|
|
libCall = spv::GLSLstd450UMax;
|
|
|
|
else
|
|
|
|
libCall = spv::GLSLstd450SMax;
|
2015-12-13 20:34:37 +00:00
|
|
|
builder.promoteScalar(precision, operands.front(), operands.back());
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpPow:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Pow;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpDot:
|
|
|
|
opCode = spv::OpDot;
|
|
|
|
break;
|
|
|
|
case glslang::EOpAtan:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Atan2;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpClamp:
|
2015-08-07 04:53:06 +00:00
|
|
|
if (isFloat)
|
2019-06-18 05:33:09 +00:00
|
|
|
libCall = nanMinMaxClamp ? spv::GLSLstd450NClamp : spv::GLSLstd450FClamp;
|
2015-08-07 04:53:06 +00:00
|
|
|
else if (isUnsigned)
|
|
|
|
libCall = spv::GLSLstd450UClamp;
|
|
|
|
else
|
|
|
|
libCall = spv::GLSLstd450SClamp;
|
2015-12-13 20:34:37 +00:00
|
|
|
builder.promoteScalar(precision, operands.front(), operands[1]);
|
|
|
|
builder.promoteScalar(precision, operands.front(), operands[2]);
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpMix:
|
2016-03-15 04:08:31 +00:00
|
|
|
if (! builder.isBoolType(builder.getScalarTypeId(builder.getTypeId(operands.back())))) {
|
|
|
|
assert(isFloat);
|
2015-11-16 04:33:39 +00:00
|
|
|
libCall = spv::GLSLstd450FMix;
|
2016-03-15 04:08:31 +00:00
|
|
|
} else {
|
2016-02-16 03:58:50 +00:00
|
|
|
opCode = spv::OpSelect;
|
2016-03-15 04:08:31 +00:00
|
|
|
std::swap(operands.front(), operands.back());
|
2016-02-16 03:58:50 +00:00
|
|
|
}
|
2015-12-13 20:34:37 +00:00
|
|
|
builder.promoteScalar(precision, operands.front(), operands.back());
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpStep:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Step;
|
2015-12-13 20:34:37 +00:00
|
|
|
builder.promoteScalar(precision, operands.front(), operands.back());
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpSmoothStep:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450SmoothStep;
|
2015-12-13 20:34:37 +00:00
|
|
|
builder.promoteScalar(precision, operands[0], operands[2]);
|
|
|
|
builder.promoteScalar(precision, operands[1], operands[2]);
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpDistance:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Distance;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpCross:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Cross;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpFaceForward:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450FaceForward;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpReflect:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Reflect;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpRefract:
|
2015-08-07 04:53:06 +00:00
|
|
|
libCall = spv::GLSLstd450Refract;
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2015-12-08 09:12:09 +00:00
|
|
|
case glslang::EOpInterpolateAtSample:
|
2018-05-17 05:51:28 +00:00
|
|
|
if (typeProxy == glslang::EbtFloat16)
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
2015-12-08 09:12:09 +00:00
|
|
|
libCall = spv::GLSLstd450InterpolateAtSample;
|
|
|
|
break;
|
|
|
|
case glslang::EOpInterpolateAtOffset:
|
2018-05-17 05:51:28 +00:00
|
|
|
if (typeProxy == glslang::EbtFloat16)
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
2015-12-08 09:12:09 +00:00
|
|
|
libCall = spv::GLSLstd450InterpolateAtOffset;
|
|
|
|
break;
|
2015-11-16 04:33:39 +00:00
|
|
|
case glslang::EOpAddCarry:
|
|
|
|
opCode = spv::OpIAddCarry;
|
|
|
|
typeId = builder.makeStructResultType(typeId0, typeId0);
|
|
|
|
consumedOperands = 2;
|
|
|
|
break;
|
|
|
|
case glslang::EOpSubBorrow:
|
|
|
|
opCode = spv::OpISubBorrow;
|
|
|
|
typeId = builder.makeStructResultType(typeId0, typeId0);
|
|
|
|
consumedOperands = 2;
|
|
|
|
break;
|
|
|
|
case glslang::EOpUMulExtended:
|
|
|
|
opCode = spv::OpUMulExtended;
|
|
|
|
typeId = builder.makeStructResultType(typeId0, typeId0);
|
|
|
|
consumedOperands = 2;
|
|
|
|
break;
|
|
|
|
case glslang::EOpIMulExtended:
|
|
|
|
opCode = spv::OpSMulExtended;
|
|
|
|
typeId = builder.makeStructResultType(typeId0, typeId0);
|
|
|
|
consumedOperands = 2;
|
|
|
|
break;
|
|
|
|
case glslang::EOpBitfieldExtract:
|
|
|
|
if (isUnsigned)
|
|
|
|
opCode = spv::OpBitFieldUExtract;
|
|
|
|
else
|
|
|
|
opCode = spv::OpBitFieldSExtract;
|
|
|
|
break;
|
|
|
|
case glslang::EOpBitfieldInsert:
|
|
|
|
opCode = spv::OpBitFieldInsert;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpFma:
|
|
|
|
libCall = spv::GLSLstd450Fma;
|
|
|
|
break;
|
|
|
|
case glslang::EOpFrexp:
|
2017-03-29 09:12:40 +00:00
|
|
|
{
|
|
|
|
libCall = spv::GLSLstd450FrexpStruct;
|
|
|
|
assert(builder.isPointerType(typeId1));
|
|
|
|
typeId1 = builder.getContainedTypeId(typeId1);
|
|
|
|
int width = builder.getScalarTypeWidth(typeId1);
|
2018-04-11 08:56:50 +00:00
|
|
|
if (width == 16)
|
|
|
|
// Using 16-bit exp operand, enable extension SPV_AMD_gpu_shader_int16
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16);
|
2017-03-29 09:12:40 +00:00
|
|
|
if (builder.getNumComponents(operands[0]) == 1)
|
|
|
|
frexpIntType = builder.makeIntegerType(width, true);
|
|
|
|
else
|
|
|
|
frexpIntType = builder.makeVectorType(builder.makeIntegerType(width, true), builder.getNumComponents(operands[0]));
|
|
|
|
typeId = builder.makeStructResultType(typeId0, frexpIntType);
|
|
|
|
consumedOperands = 1;
|
|
|
|
}
|
2015-11-16 04:33:39 +00:00
|
|
|
break;
|
|
|
|
case glslang::EOpLdexp:
|
|
|
|
libCall = spv::GLSLstd450Ldexp;
|
|
|
|
break;
|
|
|
|
|
2016-04-14 08:53:07 +00:00
|
|
|
case glslang::EOpReadInvocation:
|
2016-09-21 10:56:12 +00:00
|
|
|
return createInvocationsOperation(op, typeId, operands, typeProxy);
|
2016-04-14 08:53:07 +00:00
|
|
|
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpSubgroupBroadcast:
|
|
|
|
case glslang::EOpSubgroupBallotBitExtract:
|
|
|
|
case glslang::EOpSubgroupShuffle:
|
|
|
|
case glslang::EOpSubgroupShuffleXor:
|
|
|
|
case glslang::EOpSubgroupShuffleUp:
|
|
|
|
case glslang::EOpSubgroupShuffleDown:
|
|
|
|
case glslang::EOpSubgroupClusteredAdd:
|
|
|
|
case glslang::EOpSubgroupClusteredMul:
|
|
|
|
case glslang::EOpSubgroupClusteredMin:
|
|
|
|
case glslang::EOpSubgroupClusteredMax:
|
|
|
|
case glslang::EOpSubgroupClusteredAnd:
|
|
|
|
case glslang::EOpSubgroupClusteredOr:
|
|
|
|
case glslang::EOpSubgroupClusteredXor:
|
|
|
|
case glslang::EOpSubgroupQuadBroadcast:
|
2018-03-30 03:52:17 +00:00
|
|
|
case glslang::EOpSubgroupPartitionedAdd:
|
|
|
|
case glslang::EOpSubgroupPartitionedMul:
|
|
|
|
case glslang::EOpSubgroupPartitionedMin:
|
|
|
|
case glslang::EOpSubgroupPartitionedMax:
|
|
|
|
case glslang::EOpSubgroupPartitionedAnd:
|
|
|
|
case glslang::EOpSubgroupPartitionedOr:
|
|
|
|
case glslang::EOpSubgroupPartitionedXor:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMul:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMin:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveMax:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveOr:
|
|
|
|
case glslang::EOpSubgroupPartitionedInclusiveXor:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveAdd:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMul:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMin:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveMax:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveAnd:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveOr:
|
|
|
|
case glslang::EOpSubgroupPartitionedExclusiveXor:
|
2018-03-06 23:12:04 +00:00
|
|
|
return createSubgroupOperation(op, typeId, operands, typeProxy);
|
|
|
|
|
2016-05-05 04:30:44 +00:00
|
|
|
case glslang::EOpSwizzleInvocations:
|
|
|
|
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
|
|
|
|
libCall = spv::SwizzleInvocationsAMD;
|
|
|
|
break;
|
|
|
|
case glslang::EOpSwizzleInvocationsMasked:
|
|
|
|
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
|
|
|
|
libCall = spv::SwizzleInvocationsMaskedAMD;
|
|
|
|
break;
|
|
|
|
case glslang::EOpWriteInvocation:
|
|
|
|
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
|
|
|
|
libCall = spv::WriteInvocationAMD;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpMin3:
|
|
|
|
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
|
|
|
|
if (isFloat)
|
|
|
|
libCall = spv::FMin3AMD;
|
|
|
|
else {
|
|
|
|
if (isUnsigned)
|
|
|
|
libCall = spv::UMin3AMD;
|
|
|
|
else
|
|
|
|
libCall = spv::SMin3AMD;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpMax3:
|
|
|
|
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
|
|
|
|
if (isFloat)
|
|
|
|
libCall = spv::FMax3AMD;
|
|
|
|
else {
|
|
|
|
if (isUnsigned)
|
|
|
|
libCall = spv::UMax3AMD;
|
|
|
|
else
|
|
|
|
libCall = spv::SMax3AMD;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpMid3:
|
|
|
|
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
|
|
|
|
if (isFloat)
|
|
|
|
libCall = spv::FMid3AMD;
|
|
|
|
else {
|
|
|
|
if (isUnsigned)
|
|
|
|
libCall = spv::UMid3AMD;
|
|
|
|
else
|
|
|
|
libCall = spv::SMid3AMD;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case glslang::EOpInterpolateAtVertex:
|
2018-05-17 05:51:28 +00:00
|
|
|
if (typeProxy == glslang::EbtFloat16)
|
|
|
|
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
2016-05-05 04:30:44 +00:00
|
|
|
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
|
|
|
|
libCall = spv::InterpolateAtVertexAMD;
|
|
|
|
break;
|
2018-09-05 15:11:41 +00:00
|
|
|
case glslang::EOpBarrier:
|
|
|
|
{
|
|
|
|
// This is for the extended controlBarrier function, with four operands.
|
|
|
|
// The unextended barrier() goes through createNoArgOperation.
|
|
|
|
assert(operands.size() == 4);
|
|
|
|
unsigned int executionScope = builder.getConstantScalar(operands[0]);
|
|
|
|
unsigned int memoryScope = builder.getConstantScalar(operands[1]);
|
|
|
|
unsigned int semantics = builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]);
|
|
|
|
builder.createControlBarrier((spv::Scope)executionScope, (spv::Scope)memoryScope, (spv::MemorySemanticsMask)semantics);
|
2019-06-14 14:56:28 +00:00
|
|
|
if (semantics & (spv::MemorySemanticsMakeAvailableKHRMask |
|
|
|
|
spv::MemorySemanticsMakeVisibleKHRMask |
|
|
|
|
spv::MemorySemanticsOutputMemoryKHRMask |
|
|
|
|
spv::MemorySemanticsVolatileMask)) {
|
2018-09-05 15:11:41 +00:00
|
|
|
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
|
|
|
|
}
|
|
|
|
if (glslangIntermediate->usingVulkanMemoryModel() && (executionScope == spv::ScopeDevice || memoryScope == spv::ScopeDevice)) {
|
|
|
|
builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpMemoryBarrier:
|
|
|
|
{
|
|
|
|
// This is for the extended memoryBarrier function, with three operands.
|
|
|
|
// The unextended memoryBarrier() goes through createNoArgOperation.
|
|
|
|
assert(operands.size() == 3);
|
|
|
|
unsigned int memoryScope = builder.getConstantScalar(operands[0]);
|
|
|
|
unsigned int semantics = builder.getConstantScalar(operands[1]) | builder.getConstantScalar(operands[2]);
|
|
|
|
builder.createMemoryBarrier((spv::Scope)memoryScope, (spv::MemorySemanticsMask)semantics);
|
2019-06-14 14:56:28 +00:00
|
|
|
if (semantics & (spv::MemorySemanticsMakeAvailableKHRMask |
|
|
|
|
spv::MemorySemanticsMakeVisibleKHRMask |
|
|
|
|
spv::MemorySemanticsOutputMemoryKHRMask |
|
|
|
|
spv::MemorySemanticsVolatileMask)) {
|
2018-09-05 15:11:41 +00:00
|
|
|
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
|
|
|
|
}
|
|
|
|
if (glslangIntermediate->usingVulkanMemoryModel() && memoryScope == spv::ScopeDevice) {
|
|
|
|
builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
2018-09-19 18:41:59 +00:00
|
|
|
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EOpReportIntersectionNV:
|
|
|
|
{
|
|
|
|
typeId = builder.makeBoolType();
|
2018-10-22 23:41:44 +00:00
|
|
|
opCode = spv::OpReportIntersectionNV;
|
2018-09-19 18:42:24 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpTraceNV:
|
|
|
|
{
|
2018-10-22 23:41:44 +00:00
|
|
|
builder.createNoResultOp(spv::OpTraceNV, operands);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case glslang::EOpExecuteCallableNV:
|
|
|
|
{
|
|
|
|
builder.createNoResultOp(spv::OpExecuteCallableNV, operands);
|
2018-09-19 18:42:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
2018-09-19 18:41:59 +00:00
|
|
|
case glslang::EOpWritePackedPrimitiveIndices4x8NV:
|
|
|
|
builder.createNoResultOp(spv::OpWritePackedPrimitiveIndices4x8NV, operands);
|
|
|
|
return 0;
|
2019-02-19 19:10:32 +00:00
|
|
|
case glslang::EOpCooperativeMatrixMulAdd:
|
|
|
|
opCode = spv::OpCooperativeMatrixMulAddNV;
|
|
|
|
break;
|
2019-08-06 13:00:58 +00:00
|
|
|
#endif // GLSLANG_WEB
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
spv::Id id = 0;
|
2015-12-07 02:29:11 +00:00
|
|
|
if (libCall >= 0) {
|
2015-12-07 21:17:06 +00:00
|
|
|
// Use an extended instruction from the standard library.
|
|
|
|
// Construct the call arguments, without modifying the original operands vector.
|
|
|
|
// We might need the remaining arguments, e.g. in the EOpFrexp case.
|
|
|
|
std::vector<spv::Id> callArguments(operands.begin(), operands.begin() + consumedOperands);
|
2016-05-05 04:30:44 +00:00
|
|
|
id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, callArguments);
|
2018-11-15 09:21:36 +00:00
|
|
|
} else if (opCode == spv::OpDot && !isFloat) {
|
|
|
|
// int dot(int, int)
|
|
|
|
// NOTE: never called for scalar/vector1, this is turned into simple mul before this can be reached
|
|
|
|
const int componentCount = builder.getNumComponents(operands[0]);
|
|
|
|
spv::Id mulOp = builder.createBinOp(spv::OpIMul, builder.getTypeId(operands[0]), operands[0], operands[1]);
|
|
|
|
builder.setPrecision(mulOp, precision);
|
|
|
|
id = builder.createCompositeExtract(mulOp, typeId, 0);
|
|
|
|
for (int i = 1; i < componentCount; ++i) {
|
|
|
|
builder.setPrecision(id, precision);
|
|
|
|
id = builder.createBinOp(spv::OpIAdd, typeId, id, builder.createCompositeExtract(operands[0], typeId, i));
|
|
|
|
}
|
2015-12-07 02:29:11 +00:00
|
|
|
} else {
|
2015-11-16 04:33:39 +00:00
|
|
|
switch (consumedOperands) {
|
2015-06-26 22:58:36 +00:00
|
|
|
case 0:
|
|
|
|
// should all be handled by visitAggregate and createNoArgOperation
|
|
|
|
assert(0);
|
|
|
|
return 0;
|
|
|
|
case 1:
|
|
|
|
// should all be handled by createUnaryOperation
|
|
|
|
assert(0);
|
|
|
|
return 0;
|
|
|
|
case 2:
|
|
|
|
id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
|
|
|
|
break;
|
|
|
|
default:
|
2015-11-16 04:33:39 +00:00
|
|
|
// anything 3 or over doesn't have l-value operands, so all should be consumed
|
|
|
|
assert(consumedOperands == operands.size());
|
|
|
|
id = builder.createOp(opCode, typeId, operands);
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2015-11-16 04:33:39 +00:00
|
|
|
// Decode the return types that were structures
|
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpAddCarry:
|
|
|
|
case glslang::EOpSubBorrow:
|
|
|
|
builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
|
|
|
|
id = builder.createCompositeExtract(id, typeId0, 0);
|
|
|
|
break;
|
|
|
|
case glslang::EOpUMulExtended:
|
|
|
|
case glslang::EOpIMulExtended:
|
|
|
|
builder.createStore(builder.createCompositeExtract(id, typeId0, 0), operands[3]);
|
|
|
|
builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
|
|
|
|
break;
|
|
|
|
case glslang::EOpFrexp:
|
2017-03-29 09:12:40 +00:00
|
|
|
{
|
|
|
|
assert(operands.size() == 2);
|
|
|
|
if (builder.isFloatType(builder.getScalarTypeId(typeId1))) {
|
|
|
|
// "exp" is floating-point type (from HLSL intrinsic)
|
|
|
|
spv::Id member1 = builder.createCompositeExtract(id, frexpIntType, 1);
|
|
|
|
member1 = builder.createUnaryOp(spv::OpConvertSToF, typeId1, member1);
|
|
|
|
builder.createStore(member1, operands[1]);
|
|
|
|
} else
|
|
|
|
// "exp" is integer type (from GLSL built-in function)
|
|
|
|
builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]);
|
|
|
|
id = builder.createCompositeExtract(id, typeId0, 0);
|
|
|
|
}
|
2015-11-16 04:33:39 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2015-11-16 04:33:39 +00:00
|
|
|
|
2016-02-02 19:37:46 +00:00
|
|
|
return builder.setPrecision(id, precision);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
2016-05-05 04:30:44 +00:00
|
|
|
// Intrinsics with no arguments (or no return value, and no precision).
|
|
|
|
spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
2019-08-09 05:29:20 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-09-05 15:11:41 +00:00
|
|
|
// GLSL memory barriers use queuefamily scope in new model, device scope in old model
|
|
|
|
spv::Scope memoryBarrierScope = glslangIntermediate->usingVulkanMemoryModel() ? spv::ScopeQueueFamilyKHR : spv::ScopeDevice;
|
2015-06-26 22:58:36 +00:00
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case glslang::EOpEmitVertex:
|
|
|
|
builder.createNoResultOp(spv::OpEmitVertex);
|
|
|
|
return 0;
|
|
|
|
case glslang::EOpEndPrimitive:
|
|
|
|
builder.createNoResultOp(spv::OpEndPrimitive);
|
|
|
|
return 0;
|
|
|
|
case glslang::EOpBarrier:
|
2017-12-11 11:02:24 +00:00
|
|
|
if (glslangIntermediate->getStage() == EShLangTessControl) {
|
2018-09-05 15:11:41 +00:00
|
|
|
if (glslangIntermediate->usingVulkanMemoryModel()) {
|
|
|
|
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,
|
|
|
|
spv::MemorySemanticsOutputMemoryKHRMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
|
|
|
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
|
|
|
|
} else {
|
|
|
|
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeInvocation, spv::MemorySemanticsMaskNone);
|
|
|
|
}
|
2017-12-11 11:02:24 +00:00
|
|
|
} else {
|
|
|
|
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,
|
|
|
|
spv::MemorySemanticsWorkgroupMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
return 0;
|
|
|
|
case glslang::EOpMemoryBarrier:
|
2018-09-05 15:11:41 +00:00
|
|
|
builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsAllMemory |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
2015-06-26 22:58:36 +00:00
|
|
|
return 0;
|
|
|
|
case glslang::EOpMemoryBarrierAtomicCounter:
|
2018-09-05 15:11:41 +00:00
|
|
|
builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsAtomicCounterMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
2015-06-26 22:58:36 +00:00
|
|
|
return 0;
|
|
|
|
case glslang::EOpMemoryBarrierBuffer:
|
2018-09-05 15:11:41 +00:00
|
|
|
builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsUniformMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
2015-06-26 22:58:36 +00:00
|
|
|
return 0;
|
|
|
|
case glslang::EOpMemoryBarrierImage:
|
2018-09-05 15:11:41 +00:00
|
|
|
builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsImageMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
2015-06-26 22:58:36 +00:00
|
|
|
return 0;
|
|
|
|
case glslang::EOpMemoryBarrierShared:
|
2018-09-05 15:11:41 +00:00
|
|
|
builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsWorkgroupMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
2015-06-26 22:58:36 +00:00
|
|
|
return 0;
|
|
|
|
case glslang::EOpGroupMemoryBarrier:
|
2017-12-11 11:02:24 +00:00
|
|
|
builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsAllMemory |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
2015-06-26 22:58:36 +00:00
|
|
|
return 0;
|
2016-06-15 15:50:24 +00:00
|
|
|
case glslang::EOpAllMemoryBarrierWithGroupSync:
|
2017-12-13 05:50:53 +00:00
|
|
|
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeDevice,
|
2017-12-11 11:02:24 +00:00
|
|
|
spv::MemorySemanticsAllMemory |
|
2017-12-13 05:50:53 +00:00
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
2016-06-15 15:50:24 +00:00
|
|
|
return 0;
|
2017-12-13 05:50:53 +00:00
|
|
|
case glslang::EOpDeviceMemoryBarrier:
|
|
|
|
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask |
|
|
|
|
spv::MemorySemanticsImageMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
|
|
|
return 0;
|
|
|
|
case glslang::EOpDeviceMemoryBarrierWithGroupSync:
|
|
|
|
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask |
|
|
|
|
spv::MemorySemanticsImageMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
2016-06-15 15:50:24 +00:00
|
|
|
return 0;
|
|
|
|
case glslang::EOpWorkgroupMemoryBarrier:
|
2017-12-13 05:50:53 +00:00
|
|
|
builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
2016-06-15 15:50:24 +00:00
|
|
|
return 0;
|
|
|
|
case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:
|
2017-12-13 05:50:53 +00:00
|
|
|
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,
|
|
|
|
spv::MemorySemanticsWorkgroupMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
2016-06-15 15:50:24 +00:00
|
|
|
return 0;
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EOpSubgroupBarrier:
|
|
|
|
builder.createControlBarrier(spv::ScopeSubgroup, spv::ScopeSubgroup, spv::MemorySemanticsAllMemory |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
|
|
|
return spv::NoResult;
|
|
|
|
case glslang::EOpSubgroupMemoryBarrier:
|
|
|
|
builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsAllMemory |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
|
|
|
return spv::NoResult;
|
|
|
|
case glslang::EOpSubgroupMemoryBarrierBuffer:
|
|
|
|
builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsUniformMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
|
|
|
return spv::NoResult;
|
|
|
|
case glslang::EOpSubgroupMemoryBarrierImage:
|
|
|
|
builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsImageMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
|
|
|
return spv::NoResult;
|
|
|
|
case glslang::EOpSubgroupMemoryBarrierShared:
|
|
|
|
builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsWorkgroupMemoryMask |
|
|
|
|
spv::MemorySemanticsAcquireReleaseMask);
|
|
|
|
return spv::NoResult;
|
|
|
|
case glslang::EOpSubgroupElect: {
|
|
|
|
std::vector<spv::Id> operands;
|
|
|
|
return createSubgroupOperation(op, typeId, operands, glslang::EbtVoid);
|
|
|
|
}
|
2016-05-05 04:30:44 +00:00
|
|
|
case glslang::EOpTime:
|
|
|
|
{
|
|
|
|
std::vector<spv::Id> args; // Dummy arguments
|
|
|
|
spv::Id id = builder.createBuiltinCall(typeId, getExtBuiltins(spv::E_SPV_AMD_gcn_shader), spv::TimeAMD, args);
|
|
|
|
return builder.setPrecision(id, precision);
|
|
|
|
}
|
2018-09-19 18:42:24 +00:00
|
|
|
case glslang::EOpIgnoreIntersectionNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
builder.createNoResultOp(spv::OpIgnoreIntersectionNV);
|
2018-09-19 18:42:24 +00:00
|
|
|
return 0;
|
|
|
|
case glslang::EOpTerminateRayNV:
|
2018-10-22 23:41:44 +00:00
|
|
|
builder.createNoResultOp(spv::OpTerminateRayNV);
|
2018-09-19 18:42:24 +00:00
|
|
|
return 0;
|
2019-06-03 16:33:50 +00:00
|
|
|
|
|
|
|
case glslang::EOpBeginInvocationInterlock:
|
|
|
|
builder.createNoResultOp(spv::OpBeginInvocationInterlockEXT);
|
|
|
|
return 0;
|
|
|
|
case glslang::EOpEndInvocationInterlock:
|
|
|
|
builder.createNoResultOp(spv::OpEndInvocationInterlockEXT);
|
|
|
|
return 0;
|
|
|
|
|
2019-07-01 14:23:23 +00:00
|
|
|
case glslang::EOpIsHelperInvocation:
|
|
|
|
{
|
|
|
|
std::vector<spv::Id> args; // Dummy arguments
|
2019-07-15 06:57:20 +00:00
|
|
|
builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation);
|
|
|
|
builder.addCapability(spv::CapabilityDemoteToHelperInvocationEXT);
|
|
|
|
return builder.createOp(spv::OpIsHelperInvocationEXT, typeId, args);
|
2019-07-01 14:23:23 +00:00
|
|
|
}
|
|
|
|
|
2019-07-11 01:14:38 +00:00
|
|
|
case glslang::EOpReadClockSubgroupKHR: {
|
|
|
|
std::vector<spv::Id> args;
|
|
|
|
args.push_back(builder.makeUintConstant(spv::ScopeSubgroup));
|
|
|
|
builder.addExtension(spv::E_SPV_KHR_shader_clock);
|
|
|
|
builder.addCapability(spv::CapabilityShaderClockKHR);
|
|
|
|
return builder.createOp(spv::OpReadClockKHR, typeId, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
case glslang::EOpReadClockDeviceKHR: {
|
|
|
|
std::vector<spv::Id> args;
|
|
|
|
args.push_back(builder.makeUintConstant(spv::ScopeDevice));
|
|
|
|
builder.addExtension(spv::E_SPV_KHR_shader_clock);
|
|
|
|
builder.addCapability(spv::CapabilityShaderClockKHR);
|
|
|
|
return builder.createOp(spv::OpReadClockKHR, typeId, args);
|
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
2019-08-09 05:29:20 +00:00
|
|
|
break;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
2019-08-09 05:29:20 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
logger->missingFunctionality("unknown operation with no arguments");
|
|
|
|
|
|
|
|
return 0;
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)
|
|
|
|
{
|
2015-07-19 04:34:27 +00:00
|
|
|
auto iter = symbolValues.find(symbol->getId());
|
2015-06-26 22:58:36 +00:00
|
|
|
spv::Id id;
|
|
|
|
if (symbolValues.end() != iter) {
|
|
|
|
id = iter->second;
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
// it was not found, create it
|
2019-06-17 14:38:35 +00:00
|
|
|
spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn, false);
|
|
|
|
auto forcedType = getForcedType(builtIn, symbol->getType());
|
|
|
|
id = createSpvVariable(symbol, forcedType.first);
|
2015-06-26 22:58:36 +00:00
|
|
|
symbolValues[symbol->getId()] = id;
|
2019-06-17 14:38:35 +00:00
|
|
|
if (forcedType.second != spv::NoType)
|
|
|
|
forceType[id] = forcedType.second;
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2016-06-29 07:03:44 +00:00
|
|
|
if (symbol->getBasicType() != glslang::EbtBlock) {
|
2018-03-08 01:05:55 +00:00
|
|
|
builder.addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));
|
|
|
|
builder.addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier()));
|
|
|
|
builder.addDecoration(id, TranslateAuxiliaryStorageDecoration(symbol->getType().getQualifier()));
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-09-19 18:41:59 +00:00
|
|
|
addMeshNVDecoration(id, /*member*/ -1, symbol->getType().getQualifier());
|
2019-08-11 13:41:45 +00:00
|
|
|
if (symbol->getQualifier().hasComponent())
|
|
|
|
builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);
|
|
|
|
if (symbol->getQualifier().hasIndex())
|
|
|
|
builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);
|
2018-09-19 18:41:59 +00:00
|
|
|
#endif
|
2016-02-16 03:58:50 +00:00
|
|
|
if (symbol->getType().getQualifier().hasSpecConstantId())
|
2018-03-08 01:05:55 +00:00
|
|
|
builder.addDecoration(id, spv::DecorationSpecId, symbol->getType().getQualifier().layoutSpecConstantId);
|
2016-07-07 23:46:42 +00:00
|
|
|
// atomic counters use this:
|
|
|
|
if (symbol->getQualifier().hasOffset())
|
|
|
|
builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutOffset);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
2016-05-18 16:09:17 +00:00
|
|
|
if (symbol->getQualifier().hasLocation())
|
|
|
|
builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);
|
2018-03-08 01:05:55 +00:00
|
|
|
builder.addDecoration(id, TranslateInvariantDecoration(symbol->getType().getQualifier()));
|
2016-03-04 05:29:11 +00:00
|
|
|
if (symbol->getQualifier().hasStream() && glslangIntermediate->isMultiStream()) {
|
2016-02-01 20:45:25 +00:00
|
|
|
builder.addCapability(spv::CapabilityGeometryStreams);
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);
|
2016-02-01 20:45:25 +00:00
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
if (symbol->getQualifier().hasSet())
|
|
|
|
builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);
|
2016-02-16 03:58:50 +00:00
|
|
|
else if (IsDescriptorResource(symbol->getType())) {
|
|
|
|
// default to 0
|
|
|
|
builder.addDecoration(id, spv::DecorationDescriptorSet, 0);
|
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
if (symbol->getQualifier().hasBinding())
|
|
|
|
builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);
|
2018-12-12 02:53:59 +00:00
|
|
|
else if (IsDescriptorResource(symbol->getType())) {
|
|
|
|
// default to 0
|
|
|
|
builder.addDecoration(id, spv::DecorationBinding, 0);
|
|
|
|
}
|
2016-02-16 03:58:50 +00:00
|
|
|
if (symbol->getQualifier().hasAttachment())
|
|
|
|
builder.addDecoration(id, spv::DecorationInputAttachmentIndex, symbol->getQualifier().layoutAttachment);
|
2015-06-26 22:58:36 +00:00
|
|
|
if (glslangIntermediate->getXfbMode()) {
|
2016-02-01 20:45:25 +00:00
|
|
|
builder.addCapability(spv::CapabilityTransformFeedback);
|
2017-12-15 13:21:46 +00:00
|
|
|
if (symbol->getQualifier().hasXfbBuffer()) {
|
2015-06-26 22:58:36 +00:00
|
|
|
builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
|
2017-12-15 13:21:46 +00:00
|
|
|
unsigned stride = glslangIntermediate->getXfbStride(symbol->getQualifier().layoutXfbBuffer);
|
|
|
|
if (stride != glslang::TQualifier::layoutXfbStrideEnd)
|
|
|
|
builder.addDecoration(id, spv::DecorationXfbStride, stride);
|
|
|
|
}
|
|
|
|
if (symbol->getQualifier().hasXfbOffset())
|
|
|
|
builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
2019-08-11 13:41:45 +00:00
|
|
|
// add built-in variable decoration
|
|
|
|
if (builtIn != spv::BuiltInMax) {
|
|
|
|
builder.addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef GLSLANG_WEB
|
2016-02-21 12:59:01 +00:00
|
|
|
if (symbol->getType().isImage()) {
|
|
|
|
std::vector<spv::Decoration> memory;
|
2018-09-05 15:11:41 +00:00
|
|
|
TranslateMemoryDecoration(symbol->getType().getQualifier(), memory, glslangIntermediate->usingVulkanMemoryModel());
|
2016-02-21 12:59:01 +00:00
|
|
|
for (unsigned int i = 0; i < memory.size(); ++i)
|
2018-03-08 01:05:55 +00:00
|
|
|
builder.addDecoration(id, memory[i]);
|
2016-02-21 12:59:01 +00:00
|
|
|
}
|
|
|
|
|
2018-04-05 17:25:02 +00:00
|
|
|
// nonuniform
|
|
|
|
builder.addDecoration(id, TranslateNonUniformDecoration(symbol->getType().getQualifier()));
|
|
|
|
|
2016-12-20 00:29:34 +00:00
|
|
|
if (builtIn == spv::BuiltInSampleMask) {
|
|
|
|
spv::Decoration decoration;
|
|
|
|
// GL_NV_sample_mask_override_coverage extension
|
|
|
|
if (glslangIntermediate->getLayoutOverrideCoverage())
|
2017-01-13 09:10:53 +00:00
|
|
|
decoration = (spv::Decoration)spv::DecorationOverrideCoverageNV;
|
2016-12-20 00:29:34 +00:00
|
|
|
else
|
|
|
|
decoration = (spv::Decoration)spv::DecorationMax;
|
2018-03-08 01:05:55 +00:00
|
|
|
builder.addDecoration(id, decoration);
|
2016-12-20 00:29:34 +00:00
|
|
|
if (decoration != spv::DecorationMax) {
|
2019-07-12 21:33:02 +00:00
|
|
|
builder.addCapability(spv::CapabilitySampleMaskOverrideCoverageNV);
|
2016-12-20 00:29:34 +00:00
|
|
|
builder.addExtension(spv::E_SPV_NV_sample_mask_override_coverage);
|
|
|
|
}
|
|
|
|
}
|
2017-01-13 09:10:53 +00:00
|
|
|
else if (builtIn == spv::BuiltInLayer) {
|
|
|
|
// SPV_NV_viewport_array2 extension
|
2017-08-11 19:07:17 +00:00
|
|
|
if (symbol->getQualifier().layoutViewportRelative) {
|
2018-03-08 01:05:55 +00:00
|
|
|
builder.addDecoration(id, (spv::Decoration)spv::DecorationViewportRelativeNV);
|
2017-01-13 09:10:53 +00:00
|
|
|
builder.addCapability(spv::CapabilityShaderViewportMaskNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_viewport_array2);
|
|
|
|
}
|
2017-08-11 19:07:17 +00:00
|
|
|
if (symbol->getQualifier().layoutSecondaryViewportRelativeOffset != -2048) {
|
2018-03-08 01:05:55 +00:00
|
|
|
builder.addDecoration(id, (spv::Decoration)spv::DecorationSecondaryViewportRelativeNV,
|
|
|
|
symbol->getQualifier().layoutSecondaryViewportRelativeOffset);
|
2017-01-13 09:10:53 +00:00
|
|
|
builder.addCapability(spv::CapabilityShaderStereoViewNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-20 21:28:52 +00:00
|
|
|
if (symbol->getQualifier().layoutPassthrough) {
|
2018-03-08 01:05:55 +00:00
|
|
|
builder.addDecoration(id, spv::DecorationPassthroughNV);
|
2017-01-13 09:10:53 +00:00
|
|
|
builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV);
|
2016-12-20 21:28:52 +00:00
|
|
|
builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);
|
|
|
|
}
|
2018-09-19 18:39:56 +00:00
|
|
|
if (symbol->getQualifier().pervertexNV) {
|
|
|
|
builder.addDecoration(id, spv::DecorationPerVertexNV);
|
|
|
|
builder.addCapability(spv::CapabilityFragmentBarycentricNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
|
|
|
|
}
|
2016-12-20 00:29:34 +00:00
|
|
|
|
2018-03-08 01:05:55 +00:00
|
|
|
if (glslangIntermediate->getHlslFunctionality1() && symbol->getType().getQualifier().semanticName != nullptr) {
|
|
|
|
builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
|
|
|
|
builder.addDecoration(id, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE,
|
|
|
|
symbol->getType().getQualifier().semanticName);
|
|
|
|
}
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2019-08-01 09:28:08 +00:00
|
|
|
if (symbol->isReference()) {
|
2019-01-06 23:58:04 +00:00
|
|
|
builder.addDecoration(id, symbol->getType().getQualifier().restrict ? spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT);
|
|
|
|
}
|
2019-08-11 13:41:45 +00:00
|
|
|
#endif
|
2019-01-06 23:58:04 +00:00
|
|
|
|
2018-03-08 01:05:55 +00:00
|
|
|
return id;
|
2016-02-01 20:45:25 +00:00
|
|
|
}
|
|
|
|
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2018-09-19 18:41:59 +00:00
|
|
|
// add per-primitive, per-view. per-task decorations to a struct member (member >= 0) or an object
|
|
|
|
void TGlslangToSpvTraverser::addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier& qualifier)
|
|
|
|
{
|
|
|
|
if (member >= 0) {
|
2018-10-26 06:50:59 +00:00
|
|
|
if (qualifier.perPrimitiveNV) {
|
|
|
|
// Need to add capability/extension for fragment shader.
|
|
|
|
// Mesh shader already adds this by default.
|
|
|
|
if (glslangIntermediate->getStage() == EShLangFragment) {
|
|
|
|
builder.addCapability(spv::CapabilityMeshShadingNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_mesh_shader);
|
|
|
|
}
|
2018-09-19 18:41:59 +00:00
|
|
|
builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerPrimitiveNV);
|
2018-10-26 06:50:59 +00:00
|
|
|
}
|
2018-09-19 18:41:59 +00:00
|
|
|
if (qualifier.perViewNV)
|
|
|
|
builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerViewNV);
|
|
|
|
if (qualifier.perTaskNV)
|
|
|
|
builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerTaskNV);
|
|
|
|
} else {
|
2018-10-26 06:50:59 +00:00
|
|
|
if (qualifier.perPrimitiveNV) {
|
|
|
|
// Need to add capability/extension for fragment shader.
|
|
|
|
// Mesh shader already adds this by default.
|
|
|
|
if (glslangIntermediate->getStage() == EShLangFragment) {
|
|
|
|
builder.addCapability(spv::CapabilityMeshShadingNV);
|
|
|
|
builder.addExtension(spv::E_SPV_NV_mesh_shader);
|
|
|
|
}
|
2018-09-19 18:41:59 +00:00
|
|
|
builder.addDecoration(id, spv::DecorationPerPrimitiveNV);
|
2018-10-26 06:50:59 +00:00
|
|
|
}
|
2018-09-19 18:41:59 +00:00
|
|
|
if (qualifier.perViewNV)
|
|
|
|
builder.addDecoration(id, spv::DecorationPerViewNV);
|
|
|
|
if (qualifier.perTaskNV)
|
|
|
|
builder.addDecoration(id, spv::DecorationPerTaskNV);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-11-16 04:33:39 +00:00
|
|
|
// Make a full tree of instructions to build a SPIR-V specialization constant,
|
2016-02-16 03:58:50 +00:00
|
|
|
// or regular constant if possible.
|
2015-11-16 04:33:39 +00:00
|
|
|
//
|
|
|
|
// TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though
|
|
|
|
//
|
|
|
|
// Recursively walk the nodes. The nodes form a tree whose leaves are
|
|
|
|
// regular constants, which themselves are trees that createSpvConstant()
|
|
|
|
// recursively walks. So, this function walks the "top" of the tree:
|
|
|
|
// - emit specialization constant-building instructions for specConstant
|
|
|
|
// - when running into a non-spec-constant, switch to createSpvConstant()
|
2016-03-21 13:51:37 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& node)
|
2015-11-16 04:33:39 +00:00
|
|
|
{
|
2016-03-20 06:46:02 +00:00
|
|
|
assert(node.getQualifier().isConstant());
|
2015-11-16 04:33:39 +00:00
|
|
|
|
2016-04-04 03:55:17 +00:00
|
|
|
// Handle front-end constants first (non-specialization constants).
|
2016-02-16 03:58:50 +00:00
|
|
|
if (! node.getQualifier().specConstant) {
|
|
|
|
// hand off to the non-spec-constant path
|
|
|
|
assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
|
|
|
|
int nextConst = 0;
|
2016-03-21 13:51:37 +00:00
|
|
|
return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
|
2016-02-16 03:58:50 +00:00
|
|
|
nextConst, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We now know we have a specialization constant to build
|
|
|
|
|
2019-08-09 05:29:20 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2016-05-31 01:29:40 +00:00
|
|
|
// gl_WorkGroupSize is a special case until the front-end handles hierarchical specialization constants,
|
2016-04-04 03:55:17 +00:00
|
|
|
// even then, it's specialization ids are handled by special case syntax in GLSL: layout(local_size_x = ...
|
|
|
|
if (node.getType().getQualifier().builtIn == glslang::EbvWorkGroupSize) {
|
|
|
|
std::vector<spv::Id> dimConstId;
|
|
|
|
for (int dim = 0; dim < 3; ++dim) {
|
|
|
|
bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);
|
|
|
|
dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));
|
2018-03-08 01:05:55 +00:00
|
|
|
if (specConst) {
|
|
|
|
builder.addDecoration(dimConstId.back(), spv::DecorationSpecId,
|
|
|
|
glslangIntermediate->getLocalSizeSpecId(dim));
|
|
|
|
}
|
2016-02-16 03:58:50 +00:00
|
|
|
}
|
2016-04-04 03:55:17 +00:00
|
|
|
return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);
|
2016-02-16 03:58:50 +00:00
|
|
|
}
|
2019-08-09 05:29:20 +00:00
|
|
|
#endif
|
2016-04-04 03:55:17 +00:00
|
|
|
|
|
|
|
// An AST node labelled as specialization constant should be a symbol node.
|
|
|
|
// Its initializer should either be a sub tree with constant nodes, or a constant union array.
|
|
|
|
if (auto* sn = node.getAsSymbolNode()) {
|
2018-10-30 05:56:44 +00:00
|
|
|
spv::Id result;
|
2016-04-04 03:55:17 +00:00
|
|
|
if (auto* sub_tree = sn->getConstSubtree()) {
|
2016-04-14 20:40:20 +00:00
|
|
|
// Traverse the constant constructor sub tree like generating normal run-time instructions.
|
|
|
|
// During the AST traversal, if the node is marked as 'specConstant', SpecConstantOpModeGuard
|
|
|
|
// will set the builder into spec constant op instruction generating mode.
|
|
|
|
sub_tree->traverse(this);
|
2018-10-30 05:56:44 +00:00
|
|
|
result = accessChainLoad(sub_tree->getType());
|
|
|
|
} else if (auto* const_union_array = &sn->getConstArray()) {
|
2016-04-04 03:55:17 +00:00
|
|
|
int nextConst = 0;
|
2018-10-30 05:56:44 +00:00
|
|
|
result = createSpvConstantFromConstUnionArray(sn->getType(), *const_union_array, nextConst, true);
|
2018-11-12 18:56:52 +00:00
|
|
|
} else {
|
|
|
|
logger->missingFunctionality("Invalid initializer for spec onstant.");
|
|
|
|
return spv::NoResult;
|
2016-04-04 03:55:17 +00:00
|
|
|
}
|
2018-10-30 05:56:44 +00:00
|
|
|
builder.addName(result, sn->getName().c_str());
|
|
|
|
return result;
|
2016-04-04 03:55:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Neither a front-end constant node, nor a specialization constant node with constant union array or
|
|
|
|
// constant sub tree as initializer.
|
2016-05-04 19:55:59 +00:00
|
|
|
logger->missingFunctionality("Neither a front-end constant nor a spec constant.");
|
2016-04-04 03:55:17 +00:00
|
|
|
return spv::NoResult;
|
2015-11-16 04:33:39 +00:00
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
// Use 'consts' as the flattened glslang source of scalar constants to recursively
|
|
|
|
// build the aggregate SPIR-V constant.
|
|
|
|
//
|
|
|
|
// If there are not enough elements present in 'consts', 0 will be substituted;
|
|
|
|
// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
|
|
|
|
//
|
2016-03-21 13:51:37 +00:00
|
|
|
spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
|
|
|
// vector of constants for SPIR-V
|
|
|
|
std::vector<spv::Id> spvConsts;
|
|
|
|
|
|
|
|
// Type is used for struct and array constants
|
|
|
|
spv::Id typeId = convertGlslangToSpvType(glslangType);
|
|
|
|
|
|
|
|
if (glslangType.isArray()) {
|
2015-08-10 23:08:55 +00:00
|
|
|
glslang::TType elementType(glslangType, 0);
|
|
|
|
for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
|
2016-03-21 13:51:37 +00:00
|
|
|
spvConsts.push_back(createSpvConstantFromConstUnionArray(elementType, consts, nextConst, false));
|
2015-06-26 22:58:36 +00:00
|
|
|
} else if (glslangType.isMatrix()) {
|
2015-08-10 23:08:55 +00:00
|
|
|
glslang::TType vectorType(glslangType, 0);
|
2015-06-26 22:58:36 +00:00
|
|
|
for (int col = 0; col < glslangType.getMatrixCols(); ++col)
|
2016-03-21 13:51:37 +00:00
|
|
|
spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false));
|
2019-02-19 19:10:32 +00:00
|
|
|
} else if (glslangType.isCoopMat()) {
|
|
|
|
glslang::TType componentType(glslangType.getBasicType());
|
|
|
|
spvConsts.push_back(createSpvConstantFromConstUnionArray(componentType, consts, nextConst, false));
|
2019-01-06 23:58:04 +00:00
|
|
|
} else if (glslangType.isStruct()) {
|
2015-06-26 22:58:36 +00:00
|
|
|
glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
|
|
|
|
for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
|
2016-03-21 13:51:37 +00:00
|
|
|
spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));
|
2016-05-20 18:06:03 +00:00
|
|
|
} else if (glslangType.getVectorSize() > 1) {
|
2015-06-26 22:58:36 +00:00
|
|
|
for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
|
|
|
|
bool zero = nextConst >= consts.size();
|
|
|
|
switch (glslangType.getBasicType()) {
|
2019-08-08 16:35:51 +00:00
|
|
|
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::EbtBool:
|
|
|
|
spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
|
|
|
|
break;
|
|
|
|
#ifndef GLSLANG_WEB
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EbtInt8:
|
|
|
|
spvConsts.push_back(builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const()));
|
|
|
|
break;
|
|
|
|
case glslang::EbtUint8:
|
|
|
|
spvConsts.push_back(builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const()));
|
|
|
|
break;
|
|
|
|
case glslang::EbtInt16:
|
|
|
|
spvConsts.push_back(builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const()));
|
|
|
|
break;
|
|
|
|
case glslang::EbtUint16:
|
|
|
|
spvConsts.push_back(builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const()));
|
|
|
|
break;
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EbtInt64:
|
|
|
|
spvConsts.push_back(builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const()));
|
|
|
|
break;
|
|
|
|
case glslang::EbtUint64:
|
|
|
|
spvConsts.push_back(builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const()));
|
|
|
|
break;
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EbtDouble:
|
|
|
|
spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));
|
|
|
|
break;
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
case glslang::EbtFloat16:
|
|
|
|
spvConsts.push_back(builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
|
|
|
|
break;
|
2019-08-08 16:35:51 +00:00
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(0);
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
++nextConst;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// we have a non-aggregate (scalar) constant
|
|
|
|
bool zero = nextConst >= consts.size();
|
|
|
|
spv::Id scalar = 0;
|
|
|
|
switch (glslangType.getBasicType()) {
|
2019-08-08 16:35:51 +00:00
|
|
|
case glslang::EbtInt:
|
|
|
|
scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant);
|
|
|
|
break;
|
|
|
|
case glslang::EbtUint:
|
|
|
|
scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst(), specConstant);
|
|
|
|
break;
|
|
|
|
case glslang::EbtFloat:
|
|
|
|
scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
|
|
|
|
break;
|
|
|
|
case glslang::EbtBool:
|
|
|
|
scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant);
|
|
|
|
break;
|
|
|
|
#ifndef GLSLANG_WEB
|
2018-03-06 23:12:04 +00:00
|
|
|
case glslang::EbtInt8:
|
|
|
|
scalar = builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const(), specConstant);
|
|
|
|
break;
|
|
|
|
case glslang::EbtUint8:
|
|
|
|
scalar = builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const(), specConstant);
|
|
|
|
break;
|
|
|
|
case glslang::EbtInt16:
|
|
|
|
scalar = builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const(), specConstant);
|
|
|
|
break;
|
|
|
|
case glslang::EbtUint16:
|
|
|
|
scalar = builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const(), specConstant);
|
|
|
|
break;
|
2016-04-22 08:51:45 +00:00
|
|
|
case glslang::EbtInt64:
|
|
|
|
scalar = builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const(), specConstant);
|
|
|
|
break;
|
|
|
|
case glslang::EbtUint64:
|
|
|
|
scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant);
|
|
|
|
break;
|
2015-06-26 22:58:36 +00:00
|
|
|
case glslang::EbtDouble:
|
2015-11-16 04:33:39 +00:00
|
|
|
scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant);
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
Parser: Implement extension GL_AMD_gpu_shader_half_float.
- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
*=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
2016-07-29 08:00:05 +00:00
|
|
|
case glslang::EbtFloat16:
|
|
|
|
scalar = builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
|
|
|
|
break;
|
2019-03-06 05:27:09 +00:00
|
|
|
case glslang::EbtReference:
|
|
|
|
scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant);
|
|
|
|
scalar = builder.createUnaryOp(spv::OpBitcast, typeId, scalar);
|
|
|
|
break;
|
2019-08-08 16:35:51 +00:00
|
|
|
#endif
|
2015-06-26 22:58:36 +00:00
|
|
|
default:
|
2015-11-16 04:33:39 +00:00
|
|
|
assert(0);
|
2015-06-26 22:58:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
++nextConst;
|
|
|
|
return scalar;
|
|
|
|
}
|
|
|
|
|
|
|
|
return builder.makeCompositeConstant(typeId, spvConsts);
|
|
|
|
}
|
|
|
|
|
2015-10-15 19:29:11 +00:00
|
|
|
// Return true if the node is a constant or symbol whose reading has no
|
|
|
|
// non-trivial observable cost or effect.
|
|
|
|
bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)
|
|
|
|
{
|
|
|
|
// don't know what this is
|
|
|
|
if (node == nullptr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// a constant is safe
|
|
|
|
if (node->getAsConstantUnion() != nullptr)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// not a symbol means non-trivial
|
|
|
|
if (node->getAsSymbolNode() == nullptr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// a symbol, depends on what's being read
|
|
|
|
switch (node->getType().getQualifier().storage) {
|
|
|
|
case glslang::EvqTemporary:
|
|
|
|
case glslang::EvqGlobal:
|
|
|
|
case glslang::EvqIn:
|
|
|
|
case glslang::EvqInOut:
|
|
|
|
case glslang::EvqConst:
|
|
|
|
case glslang::EvqConstReadOnly:
|
|
|
|
case glslang::EvqUniform:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2016-05-06 21:25:16 +00:00
|
|
|
}
|
2015-10-15 19:29:11 +00:00
|
|
|
|
|
|
|
// A node is trivial if it is a single operation with no side effects.
|
2017-05-24 22:44:47 +00:00
|
|
|
// HLSL (and/or vectors) are always trivial, as it does not short circuit.
|
2017-05-20 02:19:00 +00:00
|
|
|
// Otherwise, error on the side of saying non-trivial.
|
2015-10-15 19:29:11 +00:00
|
|
|
// Return true if trivial.
|
|
|
|
bool TGlslangToSpvTraverser::isTrivial(const glslang::TIntermTyped* node)
|
|
|
|
{
|
|
|
|
if (node == nullptr)
|
|
|
|
return false;
|
|
|
|
|
2017-05-24 22:44:47 +00:00
|
|
|
// count non scalars as trivial, as well as anything coming from HLSL
|
|
|
|
if (! node->getType().isScalarOrVec1() || glslangIntermediate->getSource() == glslang::EShSourceHlsl)
|
2017-05-20 02:19:00 +00:00
|
|
|
return true;
|
|
|
|
|
2015-10-15 19:29:11 +00:00
|
|
|
// symbols and constants are trivial
|
|
|
|
if (isTrivialLeaf(node))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// otherwise, it needs to be a simple operation or one or two leaf nodes
|
|
|
|
|
|
|
|
// not a simple operation
|
|
|
|
const glslang::TIntermBinary* binaryNode = node->getAsBinaryNode();
|
|
|
|
const glslang::TIntermUnary* unaryNode = node->getAsUnaryNode();
|
|
|
|
if (binaryNode == nullptr && unaryNode == nullptr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// not on leaf nodes
|
|
|
|
if (binaryNode && (! isTrivialLeaf(binaryNode->getLeft()) || ! isTrivialLeaf(binaryNode->getRight())))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (unaryNode && ! isTrivialLeaf(unaryNode->getOperand())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (node->getAsOperator()->getOp()) {
|
|
|
|
case glslang::EOpLogicalNot:
|
|
|
|
case glslang::EOpConvIntToBool:
|
|
|
|
case glslang::EOpConvUintToBool:
|
|
|
|
case glslang::EOpConvFloatToBool:
|
|
|
|
case glslang::EOpConvDoubleToBool:
|
|
|
|
case glslang::EOpEqual:
|
|
|
|
case glslang::EOpNotEqual:
|
|
|
|
case glslang::EOpLessThan:
|
|
|
|
case glslang::EOpGreaterThan:
|
|
|
|
case glslang::EOpLessThanEqual:
|
|
|
|
case glslang::EOpGreaterThanEqual:
|
|
|
|
case glslang::EOpIndexDirect:
|
|
|
|
case glslang::EOpIndexDirectStruct:
|
|
|
|
case glslang::EOpLogicalXor:
|
|
|
|
case glslang::EOpAny:
|
|
|
|
case glslang::EOpAll:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit short-circuiting code, where 'right' is never evaluated unless
|
|
|
|
// the left side is true (for &&) or false (for ||).
|
|
|
|
spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left, glslang::TIntermTyped& right)
|
|
|
|
{
|
|
|
|
spv::Id boolTypeId = builder.makeBoolType();
|
|
|
|
|
|
|
|
// emit left operand
|
|
|
|
builder.clearAccessChain();
|
|
|
|
left.traverse(this);
|
2016-03-03 06:38:51 +00:00
|
|
|
spv::Id leftId = accessChainLoad(left.getType());
|
2015-10-15 19:29:11 +00:00
|
|
|
|
|
|
|
// Operands to accumulate OpPhi operands
|
|
|
|
std::vector<spv::Id> phiOperands;
|
|
|
|
// accumulate left operand's phi information
|
|
|
|
phiOperands.push_back(leftId);
|
|
|
|
phiOperands.push_back(builder.getBuildPoint()->getId());
|
|
|
|
|
|
|
|
// Make the two kinds of operation symmetric with a "!"
|
|
|
|
// || => emit "if (! left) result = right"
|
|
|
|
// && => emit "if ( left) result = right"
|
|
|
|
//
|
|
|
|
// TODO: this runtime "not" for || could be avoided by adding functionality
|
|
|
|
// to 'builder' to have an "else" without an "then"
|
|
|
|
if (op == glslang::EOpLogicalOr)
|
|
|
|
leftId = builder.createUnaryOp(spv::OpLogicalNot, boolTypeId, leftId);
|
|
|
|
|
|
|
|
// make an "if" based on the left value
|
2017-07-04 15:23:40 +00:00
|
|
|
spv::Builder::If ifBuilder(leftId, spv::SelectionControlMaskNone, builder);
|
2015-10-15 19:29:11 +00:00
|
|
|
|
|
|
|
// emit right operand as the "then" part of the "if"
|
|
|
|
builder.clearAccessChain();
|
|
|
|
right.traverse(this);
|
2016-03-03 06:38:51 +00:00
|
|
|
spv::Id rightId = accessChainLoad(right.getType());
|
2015-10-15 19:29:11 +00:00
|
|
|
|
|
|
|
// accumulate left operand's phi information
|
|
|
|
phiOperands.push_back(rightId);
|
|
|
|
phiOperands.push_back(builder.getBuildPoint()->getId());
|
|
|
|
|
|
|
|
// finish the "if"
|
|
|
|
ifBuilder.makeEndIf();
|
|
|
|
|
|
|
|
// phi together the two results
|
|
|
|
return builder.createOp(spv::OpPhi, boolTypeId, phiOperands);
|
|
|
|
}
|
|
|
|
|
2019-08-06 13:00:58 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2016-05-05 04:30:44 +00:00
|
|
|
// Return type Id of the imported set of extended instructions corresponds to the name.
|
|
|
|
// Import this set if it has not been imported yet.
|
|
|
|
spv::Id TGlslangToSpvTraverser::getExtBuiltins(const char* name)
|
|
|
|
{
|
|
|
|
if (extBuiltinMap.find(name) != extBuiltinMap.end())
|
|
|
|
return extBuiltinMap[name];
|
|
|
|
else {
|
2016-09-21 10:56:12 +00:00
|
|
|
builder.addExtension(name);
|
2016-05-05 04:30:44 +00:00
|
|
|
spv::Id extBuiltins = builder.import(name);
|
|
|
|
extBuiltinMap[name] = extBuiltins;
|
|
|
|
return extBuiltins;
|
|
|
|
}
|
|
|
|
}
|
2018-01-16 05:18:26 +00:00
|
|
|
#endif
|
2016-05-05 04:30:44 +00:00
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
}; // end anonymous namespace
|
|
|
|
|
|
|
|
namespace glslang {
|
|
|
|
|
2015-07-13 01:28:10 +00:00
|
|
|
void GetSpirvVersion(std::string& version)
|
|
|
|
{
|
2015-07-15 16:03:39 +00:00
|
|
|
const int bufSize = 100;
|
2015-07-13 01:39:51 +00:00
|
|
|
char buf[bufSize];
|
2015-11-16 04:33:39 +00:00
|
|
|
snprintf(buf, bufSize, "0x%08x, Revision %d", spv::Version, spv::Revision);
|
2015-07-13 01:28:10 +00:00
|
|
|
version = buf;
|
|
|
|
}
|
|
|
|
|
2017-11-03 04:32:14 +00:00
|
|
|
// For low-order part of the generator's magic number. Bump up
|
|
|
|
// when there is a change in the style (e.g., if SSA form changes,
|
|
|
|
// or a different instruction sequence to do something gets used).
|
|
|
|
int GetSpirvGeneratorVersion()
|
|
|
|
{
|
2017-12-17 06:46:37 +00:00
|
|
|
// return 1; // start
|
|
|
|
// return 2; // EOpAtomicCounterDecrement gets a post decrement, to map between GLSL -> SPIR-V
|
2018-02-06 15:06:36 +00:00
|
|
|
// return 3; // change/correct barrier-instruction operands, to match memory model group decisions
|
2018-03-03 18:47:07 +00:00
|
|
|
// return 4; // some deeper access chains: for dynamic vector component, and local Boolean component
|
2018-03-07 18:24:50 +00:00
|
|
|
// return 5; // make OpArrayLength result type be an int with signedness of 0
|
2018-06-04 21:33:31 +00:00
|
|
|
// return 6; // revert version 5 change, which makes a different (new) kind of incorrect code,
|
|
|
|
// versions 4 and 6 each generate OpArrayLength as it has long been done
|
|
|
|
return 7; // GLSL volatile keyword maps to both SPIR-V decorations Volatile and Coherent
|
2017-11-03 04:32:14 +00:00
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
// Write SPIR-V out to a binary file
|
2016-05-27 17:55:53 +00:00
|
|
|
void OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
|
|
|
std::ofstream out;
|
2015-07-13 01:28:10 +00:00
|
|
|
out.open(baseName, std::ios::binary | std::ios::out);
|
2017-02-18 16:45:40 +00:00
|
|
|
if (out.fail())
|
|
|
|
printf("ERROR: Failed to open file: %s\n", baseName);
|
2015-06-26 22:58:36 +00:00
|
|
|
for (int i = 0; i < (int)spirv.size(); ++i) {
|
|
|
|
unsigned int word = spirv[i];
|
|
|
|
out.write((const char*)&word, 4);
|
|
|
|
}
|
|
|
|
out.close();
|
|
|
|
}
|
|
|
|
|
2016-05-27 17:55:53 +00:00
|
|
|
// Write SPIR-V out to a text file with 32-bit hexadecimal words
|
2017-02-06 19:46:35 +00:00
|
|
|
void OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName, const char* varName)
|
2016-05-27 17:55:53 +00:00
|
|
|
{
|
2019-08-09 05:29:20 +00:00
|
|
|
#ifndef GLSLANG_WEB
|
2016-05-27 17:55:53 +00:00
|
|
|
std::ofstream out;
|
|
|
|
out.open(baseName, std::ios::binary | std::ios::out);
|
2017-02-18 16:45:40 +00:00
|
|
|
if (out.fail())
|
|
|
|
printf("ERROR: Failed to open file: %s\n", baseName);
|
2018-03-06 05:23:17 +00:00
|
|
|
out << "\t// " <<
|
2018-08-30 22:56:59 +00:00
|
|
|
GetSpirvGeneratorVersion() << "." << GLSLANG_MINOR_VERSION << "." << GLSLANG_PATCH_LEVEL <<
|
2018-03-06 05:23:17 +00:00
|
|
|
std::endl;
|
2017-02-15 22:29:33 +00:00
|
|
|
if (varName != nullptr) {
|
|
|
|
out << "\t #pragma once" << std::endl;
|
|
|
|
out << "const uint32_t " << varName << "[] = {" << std::endl;
|
|
|
|
}
|
2016-05-27 17:55:53 +00:00
|
|
|
const int WORDS_PER_LINE = 8;
|
|
|
|
for (int i = 0; i < (int)spirv.size(); i += WORDS_PER_LINE) {
|
|
|
|
out << "\t";
|
|
|
|
for (int j = 0; j < WORDS_PER_LINE && i + j < (int)spirv.size(); ++j) {
|
|
|
|
const unsigned int word = spirv[i + j];
|
|
|
|
out << "0x" << std::hex << std::setw(8) << std::setfill('0') << word;
|
|
|
|
if (i + j + 1 < (int)spirv.size()) {
|
|
|
|
out << ",";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out << std::endl;
|
|
|
|
}
|
2017-02-15 22:29:33 +00:00
|
|
|
if (varName != nullptr) {
|
|
|
|
out << "};";
|
|
|
|
}
|
2016-05-27 17:55:53 +00:00
|
|
|
out.close();
|
2019-08-09 05:29:20 +00:00
|
|
|
#endif
|
2016-05-27 17:55:53 +00:00
|
|
|
}
|
|
|
|
|
2015-06-26 22:58:36 +00:00
|
|
|
//
|
|
|
|
// Set up the glslang traversal
|
|
|
|
//
|
2018-08-30 22:56:59 +00:00
|
|
|
void GlslangToSpv(const TIntermediate& intermediate, std::vector<unsigned int>& spirv, SpvOptions* options)
|
2016-05-02 22:11:54 +00:00
|
|
|
{
|
2016-05-04 19:55:59 +00:00
|
|
|
spv::SpvBuildLogger logger;
|
2017-05-31 23:11:16 +00:00
|
|
|
GlslangToSpv(intermediate, spirv, &logger, options);
|
2016-05-02 22:11:54 +00:00
|
|
|
}
|
|
|
|
|
2018-08-30 22:56:59 +00:00
|
|
|
void GlslangToSpv(const TIntermediate& intermediate, std::vector<unsigned int>& spirv,
|
2017-05-31 23:11:16 +00:00
|
|
|
spv::SpvBuildLogger* logger, SpvOptions* options)
|
2015-06-26 22:58:36 +00:00
|
|
|
{
|
|
|
|
TIntermNode* root = intermediate.getTreeRoot();
|
|
|
|
|
|
|
|
if (root == 0)
|
|
|
|
return;
|
|
|
|
|
2018-08-30 22:56:59 +00:00
|
|
|
SpvOptions defaultOptions;
|
2017-05-31 23:11:16 +00:00
|
|
|
if (options == nullptr)
|
|
|
|
options = &defaultOptions;
|
|
|
|
|
2018-08-30 22:56:59 +00:00
|
|
|
GetThreadPoolAllocator().push();
|
2015-06-26 22:58:36 +00:00
|
|
|
|
2018-02-01 01:35:56 +00:00
|
|
|
TGlslangToSpvTraverser it(intermediate.getSpv().spv, &intermediate, logger, *options);
|
2015-06-26 22:58:36 +00:00
|
|
|
root->traverse(&it);
|
2016-11-26 20:23:20 +00:00
|
|
|
it.finishSpv();
|
2015-06-26 22:58:36 +00:00
|
|
|
it.dumpSpv(spirv);
|
|
|
|
|
2018-03-29 17:49:14 +00:00
|
|
|
#if ENABLE_OPT
|
2017-09-22 00:40:22 +00:00
|
|
|
// If from HLSL, run spirv-opt to "legalize" the SPIR-V for Vulkan
|
|
|
|
// eg. forward and remove memory writes of opaque types.
|
2019-06-07 19:42:08 +00:00
|
|
|
bool prelegalization = intermediate.getSource() == EShSourceHlsl;
|
|
|
|
if ((intermediate.getSource() == EShSourceHlsl || options->optimizeSize) && !options->disableOptimizer) {
|
2018-08-22 23:12:46 +00:00
|
|
|
SpirvToolsLegalize(intermediate, spirv, logger, options);
|
2019-06-07 19:42:08 +00:00
|
|
|
prelegalization = false;
|
|
|
|
}
|
2018-08-23 21:17:10 +00:00
|
|
|
|
2018-08-30 22:56:59 +00:00
|
|
|
if (options->validate)
|
2019-06-07 19:42:08 +00:00
|
|
|
SpirvToolsValidate(intermediate, spirv, logger, prelegalization);
|
2018-08-30 22:56:59 +00:00
|
|
|
|
2018-08-23 21:17:10 +00:00
|
|
|
if (options->disassemble)
|
2018-08-30 22:56:59 +00:00
|
|
|
SpirvToolsDisassemble(std::cout, spirv);
|
2018-08-23 21:17:10 +00:00
|
|
|
|
2017-09-22 00:40:22 +00:00
|
|
|
#endif
|
|
|
|
|
2018-08-30 22:56:59 +00:00
|
|
|
GetThreadPoolAllocator().pop();
|
2015-06-26 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}; // end namespace glslang
|