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.
This commit is contained in:
LoopDawg 2018-02-18 11:40:01 -07:00
parent b587fb6208
commit 4425f245a5
4 changed files with 182 additions and 7 deletions

View file

@ -777,7 +777,7 @@ spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang:
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 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
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 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
}
}
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 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
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 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
}
}
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)