builder.clearAccessChain();
node->getOperand()->traverse(this);
- spv::Id operand = builder.accessChainLoad(convertGlslangToSpvType(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()));
++ operand = builder.accessChainLoad(convertGlslangToSpvType(node->getOperand()->getType()));
spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
for (int i = 0; i < (int)glslangArguments.size(); ++i) {
builder.clearAccessChain();
glslangArguments[i]->traverse(this);
- arguments.push_back(builder.accessChainLoad(convertGlslangToSpvType(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())));
++ } else {
++ arguments.push_back(builder.accessChainLoad(convertGlslangToSpvType(glslangArguments[i]->getAsTyped()->getType())));
+ }
}
}
}
}
- // 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);
+ }
+ }
- if (cracked.fetch)
- spv::MissingFunctionality("texel fetch");
+ // Check for texture functions other than queries
if (cracked.gather)
spv::MissingFunctionality("texture gather");