SPIRV: Add the support of missing image functions #72
This commit is contained in:
parent
d4782c10d4
commit
fc6189197d
@ -95,7 +95,7 @@ protected:
|
||||
void makeGlobalInitializers(const glslang::TIntermSequence&);
|
||||
void visitFunctions(const glslang::TIntermSequence&);
|
||||
void handleFunctionEntry(const glslang::TIntermAggregate* node);
|
||||
void translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments);
|
||||
void translateArguments(glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments);
|
||||
void translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments);
|
||||
spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node);
|
||||
spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
|
||||
@ -177,6 +177,8 @@ spv::StorageClass TranslateStorageClass(const glslang::TType& type)
|
||||
else if (type.getQualifier().isUniformOrBuffer()) {
|
||||
if (type.getBasicType() == glslang::EbtBlock)
|
||||
return spv::StorageClassUniform;
|
||||
else if (type.getBasicType() == glslang::EbtAtomicUint)
|
||||
return spv::StorageClassAtomicCounter;
|
||||
else
|
||||
return spv::StorageClassUniformConstant;
|
||||
// TODO: how are we distuingishing between default and non-default non-writable uniforms? Do default uniforms even exist?
|
||||
@ -343,6 +345,56 @@ spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)
|
||||
}
|
||||
}
|
||||
|
||||
// Translate glslang image layout format to SPIR-V image format.
|
||||
spv::ImageFormat TranslateImageFormat(const glslang::TType& type)
|
||||
{
|
||||
assert(type.getBasicType() == glslang::EbtSampler);
|
||||
|
||||
switch (type.getQualifier().layoutFormat) {
|
||||
case glslang::ElfNone: return spv::ImageFormatUnknown;
|
||||
case glslang::ElfRgba32f: return spv::ImageFormatRgba32f;
|
||||
case glslang::ElfRgba16f: return spv::ImageFormatRgba16f;
|
||||
case glslang::ElfR32f: return spv::ImageFormatR32f;
|
||||
case glslang::ElfRgba8: return spv::ImageFormatRgba8;
|
||||
case glslang::ElfRgba8Snorm: return spv::ImageFormatRgba8Snorm;
|
||||
case glslang::ElfRg32f: return spv::ImageFormatRg32f;
|
||||
case glslang::ElfRg16f: return spv::ImageFormatRg16f;
|
||||
case glslang::ElfR11fG11fB10f: return spv::ImageFormatR11fG11fB10f;
|
||||
case glslang::ElfR16f: return spv::ImageFormatR16f;
|
||||
case glslang::ElfRgba16: return spv::ImageFormatRgba16;
|
||||
case glslang::ElfRgb10A2: return spv::ImageFormatRgb10A2;
|
||||
case glslang::ElfRg16: return spv::ImageFormatRg16;
|
||||
case glslang::ElfRg8: return spv::ImageFormatRg8;
|
||||
case glslang::ElfR16: return spv::ImageFormatR16;
|
||||
case glslang::ElfR8: return spv::ImageFormatR8;
|
||||
case glslang::ElfRgba16Snorm: return spv::ImageFormatRgba16Snorm;
|
||||
case glslang::ElfRg16Snorm: return spv::ImageFormatRg16Snorm;
|
||||
case glslang::ElfRg8Snorm: return spv::ImageFormatRg8Snorm;
|
||||
case glslang::ElfR16Snorm: return spv::ImageFormatR16Snorm;
|
||||
case glslang::ElfR8Snorm: return spv::ImageFormatR8Snorm;
|
||||
case glslang::ElfRgba32i: return spv::ImageFormatRgba32i;
|
||||
case glslang::ElfRgba16i: return spv::ImageFormatRgba16i;
|
||||
case glslang::ElfRgba8i: return spv::ImageFormatRgba8i;
|
||||
case glslang::ElfR32i: return spv::ImageFormatR32i;
|
||||
case glslang::ElfRg32i: return spv::ImageFormatRg32i;
|
||||
case glslang::ElfRg16i: return spv::ImageFormatRg16i;
|
||||
case glslang::ElfRg8i: return spv::ImageFormatRg8i;
|
||||
case glslang::ElfR16i: return spv::ImageFormatR16i;
|
||||
case glslang::ElfR8i: return spv::ImageFormatR8i;
|
||||
case glslang::ElfRgba32ui: return spv::ImageFormatRgba32ui;
|
||||
case glslang::ElfRgba16ui: return spv::ImageFormatRgba16ui;
|
||||
case glslang::ElfRgba8ui: return spv::ImageFormatRgba8ui;
|
||||
case glslang::ElfR32ui: return spv::ImageFormatR32ui;
|
||||
case glslang::ElfRg32ui: return spv::ImageFormatRg32ui;
|
||||
case glslang::ElfRg16ui: return spv::ImageFormatRg16ui;
|
||||
case glslang::ElfRgb10a2ui: return spv::ImageFormatRgb10a2ui;
|
||||
case glslang::ElfRg8ui: return spv::ImageFormatRg8ui;
|
||||
case glslang::ElfR16ui: return spv::ImageFormatR16ui;
|
||||
case glslang::ElfR8ui: return spv::ImageFormatR8ui;
|
||||
default: return (spv::ImageFormat)spv::BadValue;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Implement the TGlslangToSpvTraverser class.
|
||||
//
|
||||
@ -680,7 +732,14 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
|
||||
|
||||
builder.clearAccessChain();
|
||||
node->getOperand()->traverse(this);
|
||||
spv::Id operand = builder.accessChainLoad(TranslatePrecisionDecoration(node->getOperand()->getType()));
|
||||
spv::Id operand = spv::NoResult;
|
||||
|
||||
if (node->getOp() == glslang::EOpAtomicCounterIncrement ||
|
||||
node->getOp() == glslang::EOpAtomicCounterDecrement ||
|
||||
node->getOp() == glslang::EOpAtomicCounter)
|
||||
operand = builder.accessChainGetLValue(); // Special case l-value operands
|
||||
else
|
||||
operand = builder.accessChainLoad(TranslatePrecisionDecoration(node->getOperand()->getType()));
|
||||
|
||||
spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
|
||||
|
||||
@ -764,6 +823,11 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (node->getOp() == glslang::EOpImageStore)
|
||||
{
|
||||
// "imageStore" is a special case, which has no result
|
||||
return false;
|
||||
}
|
||||
|
||||
glslang::TOperator binOp = glslang::EOpNull;
|
||||
bool reduceComparison = true;
|
||||
@ -901,7 +965,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
case glslang::EOpConstructStruct:
|
||||
{
|
||||
std::vector<spv::Id> arguments;
|
||||
translateArguments(node->getSequence(), arguments);
|
||||
translateArguments(*node, arguments);
|
||||
spv::Id resultTypeId = convertGlslangToSpvType(node->getType());
|
||||
spv::Id constructed;
|
||||
if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) {
|
||||
@ -1361,7 +1425,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
||||
{
|
||||
const glslang::TSampler& sampler = type.getSampler();
|
||||
spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
|
||||
sampler.image ? 2 : 1, spv::ImageFormatUnknown); // TODO: translate format, needed for GLSL image ops
|
||||
sampler.image ? 2 : 1, TranslateImageFormat(type));
|
||||
// OpenGL "textures" need to be combined with a sampler
|
||||
if (! sampler.image)
|
||||
spvType = builder.makeSampledImageType(spvType);
|
||||
@ -1609,12 +1673,37 @@ void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate
|
||||
builder.setBuildPoint(functionBlock);
|
||||
}
|
||||
|
||||
void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments)
|
||||
void TGlslangToSpvTraverser::translateArguments(glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments)
|
||||
{
|
||||
const glslang::TIntermSequence& glslangArguments = node.getSequence();
|
||||
for (int i = 0; i < (int)glslangArguments.size(); ++i) {
|
||||
builder.clearAccessChain();
|
||||
glslangArguments[i]->traverse(this);
|
||||
arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArguments[i]->getAsTyped()->getType())));
|
||||
|
||||
// Special case l-value operands
|
||||
bool lvalue = false;
|
||||
switch (node.getOp()) {
|
||||
case glslang::EOpImageAtomicAdd:
|
||||
case glslang::EOpImageAtomicMin:
|
||||
case glslang::EOpImageAtomicMax:
|
||||
case glslang::EOpImageAtomicAnd:
|
||||
case glslang::EOpImageAtomicOr:
|
||||
case glslang::EOpImageAtomicXor:
|
||||
case glslang::EOpImageAtomicExchange:
|
||||
case glslang::EOpImageAtomicCompSwap:
|
||||
if (i == 0)
|
||||
lvalue = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (lvalue) {
|
||||
arguments.push_back(builder.accessChainGetLValue());
|
||||
}
|
||||
else {
|
||||
arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArguments[i]->getAsTyped()->getType())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1627,10 +1716,7 @@ void TGlslangToSpvTraverser::translateArguments(glslang::TIntermUnary& node, std
|
||||
|
||||
spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node)
|
||||
{
|
||||
if (node->isImage()) {
|
||||
spv::MissingFunctionality("GLSL image function");
|
||||
return spv::NoResult;
|
||||
} else if (! node->isTexture()) {
|
||||
if (! node->isImage() && ! node->isTexture()) {
|
||||
return spv::NoResult;
|
||||
}
|
||||
|
||||
@ -1643,7 +1729,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
|
||||
: node->getAsUnaryNode()->getOperand()->getAsTyped()->getType().getSampler();
|
||||
std::vector<spv::Id> arguments;
|
||||
if (node->getAsAggregate())
|
||||
translateArguments(node->getAsAggregate()->getSequence(), arguments);
|
||||
translateArguments(*node->getAsAggregate(), arguments);
|
||||
else
|
||||
translateArguments(*node->getAsUnaryNode(), arguments);
|
||||
spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
|
||||
@ -1675,8 +1761,37 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
|
||||
}
|
||||
}
|
||||
|
||||
// This is no longer a query....
|
||||
// Check for image functions other than queries
|
||||
if (node->isImage()) {
|
||||
if (node->getOp() == glslang::EOpImageLoad) {
|
||||
return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), arguments);
|
||||
}
|
||||
else if (node->getOp() == glslang::EOpImageStore) {
|
||||
builder.createNoResultOp(spv::OpImageWrite, arguments);
|
||||
return spv::NoResult;
|
||||
}
|
||||
else {
|
||||
// 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.
|
||||
std::vector<spv::Id> imageParams;
|
||||
auto opIt = arguments.begin();
|
||||
imageParams.push_back(*(opIt++));
|
||||
imageParams.push_back(*(opIt++));
|
||||
imageParams.push_back(sampler.ms ? *(opIt++) : 0); // For non-MS, the value should be 0
|
||||
|
||||
spv::Id resultTypeId = builder.makePointer(spv::StorageClassImage, convertGlslangToSpvType(node->getType()));
|
||||
spv::Id pointer = builder.createOp(spv::OpImageTexelPointer, resultTypeId, imageParams);
|
||||
|
||||
std::vector<spv::Id> operands;
|
||||
operands.push_back(pointer);
|
||||
for (; opIt != arguments.end(); ++opIt)
|
||||
operands.push_back(*opIt);
|
||||
|
||||
return createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for texture functions other than queries
|
||||
if (cracked.fetch)
|
||||
spv::MissingFunctionality("texel fetch");
|
||||
if (cracked.gather)
|
||||
@ -2438,27 +2553,35 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
|
||||
|
||||
switch (op) {
|
||||
case glslang::EOpAtomicAdd:
|
||||
case glslang::EOpImageAtomicAdd:
|
||||
opCode = spv::OpAtomicIAdd;
|
||||
break;
|
||||
case glslang::EOpAtomicMin:
|
||||
opCode = spv::OpAtomicSMin;
|
||||
case glslang::EOpImageAtomicMin:
|
||||
opCode = builder.isSignedType(typeId) ? spv::OpAtomicUMin : spv::OpAtomicSMin;
|
||||
break;
|
||||
case glslang::EOpAtomicMax:
|
||||
opCode = spv::OpAtomicSMax;
|
||||
case glslang::EOpImageAtomicMax:
|
||||
opCode = builder.isSignedType(typeId) ? spv::OpAtomicUMax : spv::OpAtomicSMax;
|
||||
break;
|
||||
case glslang::EOpAtomicAnd:
|
||||
case glslang::EOpImageAtomicAnd:
|
||||
opCode = spv::OpAtomicAnd;
|
||||
break;
|
||||
case glslang::EOpAtomicOr:
|
||||
case glslang::EOpImageAtomicOr:
|
||||
opCode = spv::OpAtomicOr;
|
||||
break;
|
||||
case glslang::EOpAtomicXor:
|
||||
case glslang::EOpImageAtomicXor:
|
||||
opCode = spv::OpAtomicXor;
|
||||
break;
|
||||
case glslang::EOpAtomicExchange:
|
||||
case glslang::EOpImageAtomicExchange:
|
||||
opCode = spv::OpAtomicExchange;
|
||||
break;
|
||||
case glslang::EOpAtomicCompSwap:
|
||||
case glslang::EOpImageAtomicCompSwap:
|
||||
opCode = spv::OpAtomicCompareExchange;
|
||||
break;
|
||||
case glslang::EOpAtomicCounterIncrement:
|
||||
|
||||
@ -822,6 +822,7 @@ Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
|
||||
case StorageClassWorkgroupLocal:
|
||||
case StorageClassPrivateGlobal:
|
||||
case StorageClassWorkgroupGlobal:
|
||||
case StorageClassAtomicCounter:
|
||||
constantsTypesGlobals.push_back(inst);
|
||||
module.mapInstruction(inst);
|
||||
break;
|
||||
@ -975,6 +976,15 @@ void Builder::createNoResultOp(Op opCode, Id operand)
|
||||
buildPoint->addInstruction(op);
|
||||
}
|
||||
|
||||
// An opcode that has one operand, no result id, and no type
|
||||
void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
|
||||
{
|
||||
Instruction* op = new Instruction(opCode);
|
||||
for (auto operand : operands)
|
||||
op->addIdOperand(operand);
|
||||
buildPoint->addInstruction(op);
|
||||
}
|
||||
|
||||
void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
|
||||
{
|
||||
Instruction* op = new Instruction(OpControlBarrier);
|
||||
|
||||
@ -137,6 +137,11 @@ public:
|
||||
|
||||
bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
|
||||
unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
|
||||
bool isSignedType(Id typeId) const
|
||||
{
|
||||
assert(getTypeClass(typeId) == OpTypeInt);
|
||||
return module.getInstruction(typeId)->getImmediateOperand(1) == 0u;
|
||||
}
|
||||
|
||||
int getTypeNumColumns(Id typeId) const
|
||||
{
|
||||
@ -241,6 +246,7 @@ public:
|
||||
|
||||
void createNoResultOp(Op);
|
||||
void createNoResultOp(Op, Id operand);
|
||||
void createNoResultOp(Op, const std::vector<Id>& operands);
|
||||
void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
|
||||
void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
|
||||
Id createUnaryOp(Op, Id typeId, Id operand);
|
||||
|
||||
@ -768,7 +768,7 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
|
||||
}
|
||||
break;
|
||||
case EOpReflect:
|
||||
// I – 2 * dot(N, I) * N: Arguments are (I, N).
|
||||
// I - 2 * dot(N, I) * N: Arguments are (I, N).
|
||||
dot = childConstUnions[0].dot(childConstUnions[1]);
|
||||
dot *= 2.0;
|
||||
for (int comp = 0; comp < numComps; ++comp)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user