diff options
| -rw-r--r-- | source/slang/hlsl.meta.slang | 63 | ||||
| -rw-r--r-- | source/slang/slang-emit-metal.cpp | 6 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.h | 6 | ||||
| -rw-r--r-- | source/slang/slang-ir-metal-legalize.cpp | 44 | ||||
| -rw-r--r-- | tests/metal/texture-write.slang | 57 |
5 files changed, 117 insertions, 59 deletions
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index ed1c9fcb6..907822060 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -3498,6 +3498,14 @@ extension _Texture<T,Shape,isArray,0,sampleCount,$(access),isShadow, 0,format> { __intrinsic_asm "imageStore($0, $1, $V2)"; } + + [require(metal, texture_sm_4_1)] + __intrinsic_op($(kIROp_ImageStore)) + static void __metalImageStoreArray(This val, vector<uint, Shape.dimensions> location, T value, uint arrayIndex); + + [require(metal, texture_sm_4_1)] + __intrinsic_op($(kIROp_ImageStore)) + static void __metalImageStore(This val, vector<uint, Shape.dimensions+isArray> location, T value); __subscript(vector<uint, Shape.dimensions+isArray> location) -> T { @@ -3567,55 +3575,14 @@ extension _Texture<T,Shape,isArray,0,sampleCount,$(access),isShadow, 0,format> OpImageWrite $this $location __convertTexel(newValue); }; case metal: - switch (Shape.flavor) + if (isArray != 0) { - case $(SLANG_TEXTURE_1D): - // lod is not supported for 1D texture - if (isArray == 1) - // void write(Tv color, uint coord, uint array, uint lod = 0) const - __intrinsic_asm "$0.write($2, uint(($1).x), uint(($1).y))"; - else - // void write(Tv color, uint coord, uint lod = 0) const - __intrinsic_asm "$0.write($2, uint($1))"; - break; - case $(SLANG_TEXTURE_2D): - if (isShadow == 1) - { - if (isArray == 1) - // void write(Tv color, uint2 coord, uint array, uint lod = 0) const - __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy), uint(($1).z))"; - else - // void write(Tv color, uint2 coord, uint lod = 0) const - __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy))"; - } - else - { - if (isArray == 1) - // void write(Tv color, uint2 coord, uint array, uint lod = 0) const - __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy), uint(($1).z))"; - else - // void write(Tv color, uint2 coord, uint lod = 0) const - __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy))"; - } - break; - case $(SLANG_TEXTURE_3D): - if (isShadow == 0 && isArray == 0) - // void write(Tv color, uint3 coord, uint lod = 0) const - __intrinsic_asm "$0.write($2, vec<uint,3>(($1).xyz))"; - break; - case $(SLANG_TEXTURE_CUBE): - static_assert(isArray == 0, "Unsupported 'Store' of 'texture cube array' for 'metal' target"); - if (isShadow == 1) - { - // void write(Tv color, uint2 coord, uint face, uint lod = 0) const - __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy), uint(($1).z), uint(($1).w))"; - } - else - { - // void write(Tv color, uint2 coord, uint face, uint lod = 0) const - __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy), uint(($1).z), uint(($1).w))"; - } - break; + // last arg will be replaced with the split off array index + __metalImageStoreArray(this, __vectorReshape<Shape.dimensions>(location), newValue, location[Shape.dimensions + isArray - 1]); + } + else + { + __metalImageStore(this, location, newValue); } case wgsl: static_assert(Shape.flavor == $(SLANG_TEXTURE_1D) diff --git a/source/slang/slang-emit-metal.cpp b/source/slang/slang-emit-metal.cpp index 56b55d57a..2d5a7d56b 100644 --- a/source/slang/slang-emit-metal.cpp +++ b/source/slang/slang-emit-metal.cpp @@ -644,7 +644,6 @@ bool MetalSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inO } case kIROp_ImageStore: { - auto imageOp = as<IRImageStore>(inst); emitOperand(imageOp->getImage(), getInfo(EmitOp::General)); m_writer->emit(".write("); @@ -656,11 +655,6 @@ bool MetalSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inO m_writer->emit(","); emitOperand(imageOp->getAuxCoord1(), getInfo(EmitOp::General)); } - if(imageOp->hasAuxCoord2()) - { - m_writer->emit(","); - emitOperand(imageOp->getAuxCoord2(), getInfo(EmitOp::General)); - } m_writer->emit(")"); return true; } diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index c2fd9da0a..eef9b86bc 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -2539,13 +2539,9 @@ struct IRImageStore : IRInst IRInst* getValue() { return getOperand(2); } /// If GLSL/SPIR-V, Sample coord - /// If Metal, Array or Sample coord + /// Metal array/face index bool hasAuxCoord1() { return getOperandCount() > 3 && getOperand(3) != nullptr; } IRInst* getAuxCoord1() { return getOperand(3); } - - /// If Metal, Sample coord - bool hasAuxCoord2() { return getOperandCount() > 4 && getOperand(4) != nullptr; } - IRInst* getAuxCoord2() { return getOperand(4); } }; // Terminators diff --git a/source/slang/slang-ir-metal-legalize.cpp b/source/slang/slang-ir-metal-legalize.cpp index 00f70b00d..a92039210 100644 --- a/source/slang/slang-ir-metal-legalize.cpp +++ b/source/slang/slang-ir-metal-legalize.cpp @@ -1740,6 +1740,46 @@ namespace Slang } }; + // metal textures only support writing 4-component values, even if the texture is only 1, 2, or 3-component + // in this case the other channels get ignored, but the signature still doesnt match + // so now we have to replace the value being written with a 4-component vector where + // the new components get ignored, nice + void legalizeImageStoreValue(IRBuilder& builder, IRImageStore* imageStore) + { + builder.setInsertBefore(imageStore); + auto originalValue = imageStore->getValue(); + auto valueBaseType = originalValue->getDataType(); + IRType* elementType = nullptr; + List<IRInst*> components; + if(auto valueVectorType = as<IRVectorType>(valueBaseType)) + { + if(auto originalElementCount = as<IRIntLit>(valueVectorType->getElementCount())) + { + if(originalElementCount->getValue() == 4) + { + return; + } + } + elementType = valueVectorType->getElementType(); + auto vectorValue = as<IRMakeVector>(originalValue); + for(UInt i = 0; i < vectorValue->getOperandCount(); i++) + { + components.add(vectorValue->getOperand(i)); + } + } + else + { + elementType = valueBaseType; + components.add(originalValue); + } + for(UInt i = components.getCount(); i < 4; i++) + { + components.add(builder.getIntValue(builder.getIntType(), 0)); + } + auto fourComponentVectorType = builder.getVectorType(elementType, 4); + imageStore->setOperand(2, builder.emitMakeVector(fourComponentVectorType, components)); + } + void legalizeFuncBody(IRFunc* func) { IRBuilder builder(func); @@ -1796,6 +1836,10 @@ namespace Slang arg->set(temp); } } + if(auto write = as<IRImageStore>(inst)) + { + legalizeImageStoreValue(builder, write); + } } } } diff --git a/tests/metal/texture-write.slang b/tests/metal/texture-write.slang new file mode 100644 index 000000000..7967e1d16 --- /dev/null +++ b/tests/metal/texture-write.slang @@ -0,0 +1,57 @@ +//TEST:SIMPLE(filecheck=METAL): -stage compute -entry computeMain -target metal -DEMIT_SOURCE +//TEST:SIMPLE(filecheck=METALLIB): -stage compute -entry computeMain -target metallib +// for some reason, metal textures dont have an overload for less-than-four component +// writes, they need to be converted to 4-components in a legalize step, as the other components +// get discarded +struct TextureWrite +{ + //TEST_INPUT: RWTexture2D(size=4, content = zero):name t2D_f32 + RWTexture2D<float> tex1; + //TEST_INPUT: RWTexture2D(size=4, content = zero):name t2D_f32v2 + RWTexture2D<float2> tex2; + //TEST_INPUT: RWTexture2D(size=4, content = zero):name t2D_f32v3 + RWTexture2D<float3> tex3; + //TEST_INPUT: RWTexture2D(size=4, content = zero):name t2D_f32v4 + RWTexture2D<float4> tex4; + + //TEST_INPUT: RWTexture2DArray(size=4, content = zero):name t2D_f32 + RWTexture2DArray<float> tex1Array; + //TEST_INPUT: RWTexture2DArray(size=4, content = zero):name t2D_f32v2 + RWTexture2DArray<float2> tex2Array; + //TEST_INPUT: RWTexture2DArray(size=4, content = zero):name t2D_f32v3 + RWTexture2DArray<float3> tex3Array; + //TEST_INPUT: RWTexture2DArray(size=4, content = zero):name t2D_f32v4 + RWTexture2DArray<float4> tex4Array; +} +ParameterBlock<TextureWrite> pWrites; + +[numthreads(1, 1, 1)] +void computeMain() +{ + // TODO: check for the type of first parameter to be a 4-component vector + // METALLIB: call {{.*}}.write_texture_2d.v4f32( + // METAL: .write( + pWrites.tex1[uint2(1, 1)] = 1; + // METALLIB: call {{.*}}.write_texture_2d.v4f32( + // METAL: .write( + pWrites.tex2[uint2(2, 2)] = float2(1, 2); + // METALLIB: call {{.*}}.write_texture_2d.v4f32( + // METAL: .write( + pWrites.tex3[uint2(3, 3)] = float3(1, 2, 3); + // METALLIB: call {{.*}}.write_texture_2d.v4f32( + // METAL: .write( + pWrites.tex4[uint2(4, 4)] = float4(1, 2, 3, 4); + + // METALLIB: call {{.*}}.write_texture_2d_array.v4f32( + // METAL: .write( + pWrites.tex1Array[uint3(1, 1, 1)] = 1; + // METALLIB: call {{.*}}.write_texture_2d_array.v4f32( + // METAL: .write( + pWrites.tex2Array[uint3(2, 2, 2)] = float2(1, 2); + // METALLIB: call {{.*}}.write_texture_2d_array.v4f32( + // METAL: .write( + pWrites.tex3Array[uint3(3, 3, 3)] = float3(1, 2, 3); + // METALLIB: call {{.*}}.write_texture_2d_array.v4f32( + // METAL: .write( + pWrites.tex4Array[uint3(4, 4, 4)] = float4(1, 2, 3, 4); +}
\ No newline at end of file |
