HLSL: Add conversions for image ops during SPV construction
HLSL allows image and texture types to be templatized on sub-vec4 types,
or even structures. This was mostly handled already during creation of
sampling operations. However, for operator[] which can generate image
loads, this wasn't happening.
It also isn't very easy to do at that point in time, because operator[]
does not know where the results it produces will end up. They may be
an lvalue or an rvalue, and there's a post-process to convert loads to
stores. They may end up in atomic ops.
To bypass that difficulty, GlslangToSpv now looks for this case and
adds the appropriate conversion. LIMITATION: this only works for
cases for which a simple conversion opcode suffices. That is to say,
it will not work if the type is templatized on a struct.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 6e9fb38..dc644e5 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -777,7 +777,7 @@
control = control | spv::LoopControlDontUnrollMask;
if (loopNode.getUnroll())
control = control | spv::LoopControlUnrollMask;
- if (loopNode.getLoopDependency() == glslang::TIntermLoop::dependencyInfinite)
+ if (unsigned(loopNode.getLoopDependency()) == glslang::TIntermLoop::dependencyInfinite)
control = control | spv::LoopControlDependencyInfiniteMask;
else if (loopNode.getLoopDependency() > 0) {
control = control | spv::LoopControlDependencyLengthMask;
@@ -3229,8 +3229,6 @@
builder.setLine(node->getLoc().line);
- auto resultType = [&node,this]{ return convertGlslangToSpvType(node->getType()); };
-
// Process a GLSL texturing op (will be SPV image)
const glslang::TSampler sampler = node->getAsAggregate() ? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType().getSampler()
: node->getAsUnaryNode()->getOperand()->getAsTyped()->getType().getSampler();
@@ -3279,6 +3277,20 @@
}
}
+ 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); };
+
// Check for image functions other than queries
if (node->isImage()) {
std::vector<spv::Id> operands;
@@ -3325,9 +3337,14 @@
if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown)
builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);
- spv::Id result = builder.createOp(spv::OpImageRead, resultType(), operands);
- builder.setPrecision(result, precision);
- return result;
+ std::vector<spv::Id> result = { builder.createOp(spv::OpImageRead, resultType(), operands) };
+ 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];
#ifdef AMD_EXTENSIONS
} else if (node->getOp() == glslang::EOpImageStore || node->getOp() == glslang::EOpImageStoreLod) {
#else
@@ -3601,7 +3618,14 @@
}
}
- return builder.createTextureCall(precision, resultType(), sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params);
+ std::vector<spv::Id> result = {
+ builder.createTextureCall(precision, resultType(), sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params)
+ };
+
+ if (components != node->getType().getVectorSize())
+ result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType()));
+
+ return result[0];
}
spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)