From e1d0ef2002d7b0f459cf689ec1f8e37c4ff2afba Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 26 Jun 2024 09:37:18 -0400 Subject: Expand upon existing `ImageSubscript` support (Metal, GLSL, SPIRV) (#4408) * Add additional `ImageSubscript` features: 1. Added ImageSubscript support for Metal & a test case * Merge GLSL/SPIRV/Metal `ImageSubscript` legalization pass 2. Added multisample support to glsl/spirv/metal for when using ImageSubscript * Added in this PR since the overhaul of the code merges together GLSL/SPIRV/Metal implementation 3. Fixed minor metal texture `Load`/`Read` bugs * [HLSL methods of access do not support subscript accessor for texture cube array](https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/texturecubearray) * removed swizzling of uint/int/float * other odd bugs which were causing compile errors note: Compute tests do not work due to what seems to be the GFX backend (causes crash without error report). The tests are disabled. * disable LOD with texture 1d seems that LOD for 1d textures need to be a compile time constant as per an error metal throws * syntax error in hlsl.meta * static_assert alone with intrinsic_asm error provides cleaner errors Note: `static_assert` seems to be unstable and not be fully respected (still require `intrinsic_asm` to avoid a stdlib compile error) * change comment to `// lod is not supported for 1D texture * add `static_assert` in related code gen paths * address review * address review * add asserts as per review comment, NOTE: unclear if these should be release 'asserts' as well --- source/slang/slang-ir-legalize-image-subscript.cpp | 203 +++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 source/slang/slang-ir-legalize-image-subscript.cpp (limited to 'source/slang/slang-ir-legalize-image-subscript.cpp') diff --git a/source/slang/slang-ir-legalize-image-subscript.cpp b/source/slang/slang-ir-legalize-image-subscript.cpp new file mode 100644 index 000000000..b5b240675 --- /dev/null +++ b/source/slang/slang-ir-legalize-image-subscript.cpp @@ -0,0 +1,203 @@ +#include "slang-ir-legalize-image-subscript.h" + +#include "slang-ir.h" +#include "slang-ir-insts.h" +#include "slang-ir-util.h" +#include "slang-ir-clone.h" +#include "slang-ir-specialize-address-space.h" +#include "slang-parameter-binding.h" +#include "slang-ir-legalize-varying-params.h" + +namespace Slang +{ + void legalizeStore(TargetRequest* target, IRBuilder& builder, IRInst* storeInst, DiagnosticSink* sink) + { + SLANG_ASSERT(storeInst); + + builder.setInsertBefore(storeInst); + IRImageSubscript* imageSubscript = nullptr; + auto getElementPtr = as(storeInst->getOperand(0)); + if(getElementPtr) + { + imageSubscript = as(getElementPtr->getBase()); + } + else + { + imageSubscript = as(storeInst->getOperand(0)); + } + SLANG_ASSERT(imageSubscript); + SLANG_ASSERT(imageSubscript->getImage()); + IRTextureType* textureType = as(imageSubscript->getImage()->getFullType()); + SLANG_ASSERT(textureType); + auto imageElementType = cast(imageSubscript->getDataType())->getValueType(); + auto vectorBaseType = getIRVectorBaseType(imageElementType); + IRType* vector4Type = builder.getVectorType(vectorBaseType, 4); + IRType* coordType = imageSubscript->getCoord()->getDataType(); + int coordVectorSize = getIRVectorElementSize(coordType); + + bool seperateArrayCoord = (isMetalTarget(target) && textureType->isArray()); // seperate array param + bool seperateSampleCoord = (textureType->isMultisample()); // seperate sample param + + if(seperateSampleCoord && isMetalTarget(target)) + sink->diagnose(imageSubscript->getImage(), Diagnostics::multiSampledTextureDoesNotAllowWrites, target->getTarget()); + + IRType* indexingType = builder.getIntType(); + if(isMetalTarget(target)) + indexingType = builder.getUIntType(); + + if (coordVectorSize != 1) + { + coordType = builder.getVectorType( + indexingType, builder.getIntValue(builder.getIntType(), coordVectorSize)); + } + else + { + coordType = indexingType; + } + + auto legalizedCoord = imageSubscript->getCoord(); + if (coordType != imageSubscript->getCoord()->getDataType()) + { + legalizedCoord = builder.emitCast(coordType, legalizedCoord); + } + + const Index kCoordParamIndex = 1; + const Index kValueParamIndex = 2; + + ShortList loadParams; + loadParams.reserveOverflowBuffer(4); + loadParams.add(imageSubscript->getImage()); // image + loadParams.add(legalizedCoord); // coord + + ShortList storeParams; + storeParams.reserveOverflowBuffer(5); + storeParams.add(imageSubscript->getImage()); // image + storeParams.add(legalizedCoord); // coord + storeParams.add(nullptr); // value + + if (seperateArrayCoord) + { + + UInt paramIndexToFetch = coordVectorSize - 1; + + auto seperatedParam = builder.emitSwizzle(indexingType, legalizedCoord, 1, ¶mIndexToFetch); + loadParams.add(seperatedParam); + storeParams.add(seperatedParam); + + coordVectorSize -= 1; + ShortList paramToFetch; + paramToFetch.reserveOverflowBuffer(coordVectorSize); + for (int i = 0; i < coordVectorSize; i++) + { + paramToFetch.add(i); + } + auto newCoord = builder.emitSwizzle(builder.getVectorType(indexingType, builder.getIntValue(builder.getIntType(), coordVectorSize)), legalizedCoord, coordVectorSize, paramToFetch.getArrayView().getBuffer()); + storeParams[kCoordParamIndex] = newCoord; + loadParams[kCoordParamIndex] = newCoord; + } + if (seperateSampleCoord) + { + loadParams.add(imageSubscript->getSampleCoord()); + storeParams.add(imageSubscript->getSampleCoord()); + } + + IRInst* legalizedStore = storeInst->getOperand(1); + switch (storeInst->getOp()) + { + case kIROp_Store: + { + IRInst* newValue = nullptr; + if (getElementPtr) + { + auto originalValue = builder.emitImageLoad(vector4Type, loadParams); + auto index = getElementPtr->getIndex(); + newValue = builder.emitSwizzleSet(vector4Type, originalValue, legalizedStore, 1, &index); + } + else + { + newValue = legalizedStore; + if (getIRVectorElementSize(imageElementType) != 4) + { + newValue = builder.emitVectorReshape( + builder.getVectorType( + vectorBaseType, builder.getIntValue(builder.getIntType(), 4)), + newValue); + } + } + + storeParams[kValueParamIndex] = newValue; + auto imageStore = builder.emitImageStore( + builder.getVoidType(), + storeParams); + storeInst->replaceUsesWith(imageStore); + storeInst->removeAndDeallocate(); + if (!imageSubscript->hasUses()) + { + imageSubscript->removeAndDeallocate(); + } + } + break; + case kIROp_SwizzledStore: + { + auto swizzledStore = cast(storeInst); + // Here we assume the imageElementType is already lowered into float4/uint4 types from any + // user-defined type. + assert(imageElementType->getOp() == kIROp_VectorType); + auto originalValue = builder.emitImageLoad(vector4Type, loadParams); + Array indices; + for (UInt i = 0; i < swizzledStore->getElementCount(); i++) + { + indices.add(swizzledStore->getElementIndex(i)); + } + auto newValue = builder.emitSwizzleSet( + vector4Type, + originalValue, + swizzledStore->getSource(), + swizzledStore->getElementCount(), + indices.getBuffer()); + storeParams[kValueParamIndex] = newValue; + auto imageStore = builder.emitImageStore( + builder.getVoidType(), + storeParams); + storeInst->replaceUsesWith(imageStore); + storeInst->removeAndDeallocate(); + if (!imageSubscript->hasUses()) + { + imageSubscript->removeAndDeallocate(); + } + } + break; + default: + break; + } + } + void legalizeImageSubscript(TargetRequest* target, IRModule* module, DiagnosticSink* sink) + { + IRBuilder builder(module); + for (auto globalInst : module->getModuleInst()->getChildren()) + { + auto func = as(globalInst); + if (!func) + continue; + for (auto block : func->getBlocks()) + { + auto inst = block->getFirstInst(); + IRInst* next; + for ( ; inst; inst = next) + { + next = inst->getNextInst(); + switch (inst->getOp()) + { + case kIROp_Store: + case kIROp_SwizzledStore: + if (getRootAddr(inst->getOperand(0))->getOp() == kIROp_ImageSubscript) + { + legalizeStore(target, builder, inst, sink); + } + } + } + } + } + } +} + -- cgit v1.2.3