diff options
| author | ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> | 2024-03-26 16:07:32 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-26 13:07:32 -0700 |
| commit | 0877d1a3e9d69fdbf4087581df96954e56e4dd97 (patch) | |
| tree | 3f7135d119908573013770ce0fbbee09701f6f26 | |
| parent | 57f514d09d3b879e238f37980456634e8286691c (diff) | |
Implement GLSL gimageDim & memory qualifiers with optional extension(s); resolves #3587 for GLSL & SPIR-V targets #3631 (#3810)
* [early push of code since memory qualifiers may be made into a seperate branch & pr and I rather make it simple to split the implementation if required]
all type & functions impl. for GLSL image type
added all memory qualifiers & tests for direct read/write [GLSL syntax] (DID NOT test or implement parameter qualifiers, that is next commit)
* this inlcudes emit-glsl & emit-spirv for qualifier decorations
* this also includes error handling
* this includes parsing
* full implementation other than Rect; all errors and basic tests are done & working
what is left:
1. need to now add Rect type support (additional TextureImpl flag)
2. tests
3. testing infrastructure to support variety of types
* testing framework now works with images of all types and imageBuffers -- next steps are actual tests
* push code for mostly working image atomics; missing int64/uint64 tests and slightly broken feature
likley due to missing code from master which I pushed for regular atomics
* fix all remaining shader image atomic issues and tests to work with float & i64/u64 fully
will now clean up code and squash the commits (since they are quite all over the place)
* refactor code to work & look correct, fix all regressions
Turned off tests for texture format R64 due to the shader use limitation of currently being only for storage buffers on most hardware (test fail cause, this is not allowed)
Changed raygen.slang & nv-ray-tracing-motion-blur.slang since both cross-compiled with glslang, which does not respect layout(rgba8) for RWBuffer's, in this scenario making the type into a SPIR-V rgba32f, which is incorrect and a known problem, this causes different code to be outputted from Slang & HLSL+GLSL->Slang paths
Clean up all code and better explain the "why" for the gimageDim definition we use various strings of Slang code, the gist is:
1. Parameters are structured as per IMAGE_PARAM keyword in spec, and we respect this in order to match specification (to allow easy code iteration)
2. sample parameters are required for functions
3. types are inconsistently named
fixed regression of breaking l-value lowering when r-value should be lowered (lower-to-ir)
fix compiler warnings
remove unneeded lambdas
`expr->type.isLeftValue = isMutableGLSLBufferBlockVarExpr(baseExpr) && (expr->type.hasReadOnlyOnTarget == false);` is an adjustment made such that a buffer block is mutable only if the block is mutable and the base expression is mutable (to handle case of readonly buffer block, immutable)
* remove rectangle parameter
* use proper const syntax and struct naming
* adjust syntax
* adjust modifier capabilitites: HLSL+GLSL --> GLSL. Notice most specifically, if the parent is a global struct we can put a memory qualifier, this does not include, struct inside a struct, with a member variable with a memory qualifier (since then you could use the struct in invalid ways). Added test for struct inside struct with member variable with memory qualifier.
adjust syntax and remove code which will rot
* adjust formatting for consistency
* addressing review feedback
addressing review feedback:
change testing code to handle int and float/half correctly in all cases
adjust testing code syntax as requested
change vkdevice code to fit a different form as requested
* adjust code as per requested for review:
1. adjusted testing code logic to handle non 0-1 values appropriately, notice int8_t will likley be the range and set order of {[0,127],[-1,-128]}, this is intentional
2. syntax adjustments for correctness
* trying to fix falcor regressions
* add back removed code for regression testing
* test removing changes which may break falcor
* Revert "test removing changes which may break falcor"
This reverts commit 240da97f06c23e98a26ac23cf1d385995c67b251.
* disable R64 support in attempt to fix falcor tests
* Revert "disable R64 support in attempt to fix falcor tests"
This reverts commit 317cb632eb2f47e980fc4aeafe418f8060f4c473.
* disable major device changes (still trying to figure out falcor fails -- locally working different than CI)
* test removing d3d changes
* remove all format changes
* add back removed code for regression testing
* try something to get code to work with falcor
* address review
* Add way to handle constref/ref/encapsulated texture objects with memory qualifiers as a parameter.
Fixed an issue (and improved codegen) for when we have a store(dst,load(src)) pattern, where dst is supposed to be equal to src for when resolving globalParam's (no need for work-arounds anymore)
* move recent-fix/change to textureType loading into a proper optimization pass which now runs after SPIR-V legalization to catch odd SPIR-V emitting after legalizing types for SPIR-V
* Revert most recent optimization pass change, add work around getting a unmangled global parameter address through a intrinsic op instead of spir-v intrinsic (works same as `__imagePointer()`)
* remove unneeded changes
* remove unneeded `__constref` in glsl.meta
* move memory qualifier checks to visitInvoke of check-expr.cpp
move GetLegalizedSPIRVGlobalParamAddr resolving to spirv-legalization pass
move error for "if using non texture type with memory qualifer in param" earlier such that we error with this first. No point in telling user "you are not putting correct memory qualifiers" when memory qualifiers should not have been used.
* add memory qualifier folding modifier 'MemoryQualifierCollectionModifier' to reduce searching and processing (later will be adapted to whole system) as suggested/asked.
The utility is a method to track memory qualifiers without doing a expensive linked-list traversal (image's have 4 modifiers normally).
* properly pass multiple qualifiers from checkModifier down to the `modifier`s list
* addressing review comments:
* change implementation to properly handle restrict modifier
* add comments about implementation for clarity
48 files changed, 3730 insertions, 192 deletions
diff --git a/slang-gfx.h b/slang-gfx.h index 0585de772..d705c8554 100644 --- a/slang-gfx.h +++ b/slang-gfx.h @@ -296,8 +296,12 @@ public: x(BC6H_UF16, 16, 16) \ x(BC6H_SF16, 16, 16) \ x(BC7_UNORM, 16, 16) \ - x(BC7_UNORM_SRGB, 16, 16) - + x(BC7_UNORM_SRGB, 16, 16) \ + \ + x(R64_UINT, 8, 1) \ + \ + x(R64_SINT, 8, 1) \ + \ // TODO: This should be generated from above // TODO: enum class should be explicitly uint32_t or whatever's appropriate /// Different formats of things like pixels or elements of vertices @@ -409,6 +413,10 @@ enum class Format BC7_UNORM, BC7_UNORM_SRGB, + R64_UINT, + + R64_SINT, + _Count, }; diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 1f4a2908d..583dd5923 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -2363,6 +2363,10 @@ int __naturalStrideOf() __intrinsic_op($(kIROp_TreatAsDynamicUniform)) T asDynamicUniform<T>(T v); +__generic<T> +__intrinsic_op($(kIROp_GetLegalizedSPIRVGlobalParamAddr)) +Ptr<T> __getLegalizedSPIRVGlobalParamAddr(T val); + // Binding Attributes __attributeTarget(DeclBase) diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang index 4101cc626..d7b646810 100644 --- a/source/slang/glsl.meta.slang +++ b/source/slang/glsl.meta.slang @@ -2821,6 +2821,466 @@ public vec4 shadow2DProjLod(sampler2DShadow sampler, vec4 coord, float lod) return textureProjLod(sampler, coord, lod); } +//// gimageDim Implementation + +public static const int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0; +public static const int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 1; +public static const int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 2; +public static const int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 3; +public static const int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 4; +public static const int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 5; + +__generic<T : __BuiltinType> +[ForceInline] void typeRequireChecks_image_atomic_tier1() +{ + __target_switch + { + case glsl: + { + if (__type_equals<T, float>()) + __requireGLSLExtension("GL_EXT_shader_atomic_float"); + } + case spirv: + if (__type_equals<T, float>()) + { + spirv_asm + { + OpExtension "SPV_EXT_shader_atomic_float_add"; + OpCapability AtomicFloat32AddEXT + }; + } + } +} + +__generic<T : __BuiltinType> +[ForceInline] void typeRequireChecks_image_atomic_tier2() +{ + __target_switch + { + case glsl: + { + if (__type_equals<T, float>()) + __requireGLSLExtension("GL_EXT_shader_atomic_float2"); + } + case spirv: + if (__type_equals<T, float>()) + { + spirv_asm + { + OpExtension "SPV_EXT_shader_atomic_float_min_max"; + OpCapability AtomicFloat32MinMaxEXT + }; + } + } +} + +__generic<T : __BuiltinType> +[ForceInline] void typeRequireChecks_image_atomic_int64() +{ + __target_switch + { + case spirv: + if (__type_equals<T, uint64_t>() + || __type_equals<T, int64_t>()) + { + spirv_asm + { + OpCapability Int64Atomics + }; + } + return; + } +} + +${{{{ +{ + struct ImageTypeInfo + { + const char *prefix; + const char *type; + bool isInt; + const char *SPVTypePrefix; + const char *SPVSubTypePrefix; + const char *SPVAtomicSuffix; + }; + static const ImageTypeInfo kTypeWithPrefix[] = + { + { "", "float", false, "F", "F", "EXT"}, + { "u", "uint", true, "I", "U", ""}, + { "i", "int", true, "I", "S", ""}, + { "u64", "uint64_t", true, "I", "U", ""}, + { "i64", "int64_t", true, "I", "S", ""}, + }; + struct ShapeTypeInfo + { + const char *suffix; + int imageSizeIVecDim; + int imageCoordIVecIndexerDim; + const char *shape; + int isArray; + int isMS; + bool isRect; + } + static const kShapeType[] = + { + { "1D", 1, 1,"__Shape1D", 0, 0, 0}, + + { "2D", 2, 2, "__Shape2D", 0, 0, 0}, + { "3D", 3, 3, "__Shape3D", 0, 0, 0}, + { "Cube", 2, 3, "__ShapeCube", 0, 0, 0}, + { "2DRect", 2, 2, "__Shape2D", 0, 0, 1}, + { "1DArray", 2, 2, "__Shape1D", 1, 0, 0}, + + { "2DArray", 3, 3, "__Shape2D", 1, 0, 0}, + { "CubeArray", 3, 3, "__ShapeCube", 1, 0, 0}, + { "Buffer", 1, 1, "__ShapeBuffer", 0, 0, 0}, + { "2DMS", 2, 2, "__Shape2D", 0, 1, 0}, + { "2DMSArray", 3, 3, "__Shape2D", 1, 1, 0}, + }; + for (const auto& targetType : kTypeWithPrefix) + for (const auto& targetShape : kShapeType) + { + // gimageDim is the format of image buffers, we + // need to resolve a type name from the format: + // targetType.prefix is the 'g' + // targetShape.suffix is the 'Dim' + StringBuilder fullTypeNameBuilder; + fullTypeNameBuilder << targetType.prefix << "image" << targetShape.suffix; + auto fullTypeName = fullTypeNameBuilder.toString(); + + // We need a string to resolve for the imageSize return type + // since each shape has a different return which may not be + // a vec + StringBuilder imageSizeIntOrIVecBuilder; + if (targetShape.imageSizeIVecDim == 1) + imageSizeIntOrIVecBuilder << "int"; + else + imageSizeIntOrIVecBuilder << "ivec" << targetShape.imageSizeIVecDim; + auto imageSizeIntOrIVec = imageSizeIntOrIVecBuilder.toString(); + + // Following OpenGL/Vulkan semantics, IMAGE_PARAMS string represents + // the changing list of parameters per gimageDim type + // https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf + StringBuilder IMAGE_PARAMSBuilder; + IMAGE_PARAMSBuilder << fullTypeName << " image,"; + int paramC = targetShape.imageCoordIVecIndexerDim; + if (paramC == 1) + IMAGE_PARAMSBuilder << "int"; + else + IMAGE_PARAMSBuilder << "ivec" << paramC; + IMAGE_PARAMSBuilder << " P"; + if (targetShape.isMS) + { + IMAGE_PARAMSBuilder << ", int sample"; + } + auto IMAGE_PARAMS = IMAGE_PARAMSBuilder.toString(); + + // SPIR-V requires a 'sample' parameter for all texture + // functions. We need to handle a dynamic creation of + // 'sample' if 'sample' parameter is not in IMAGE_PARAMS + StringBuilder SPV_PREFIX_IMAGE_PARAMSBuilder; + StringBuilder SPV_SUFFIX_IMAGE_PARAMSBuilder; + StringBuilder SPV_DEFAULT_SAMPLE_VAR_IF_MISSINGBuilder; + + SPV_PREFIX_IMAGE_PARAMSBuilder << "$image $P"; + SPV_SUFFIX_IMAGE_PARAMSBuilder; + if (targetShape.isMS) + { + SPV_SUFFIX_IMAGE_PARAMSBuilder << " Sample $sample"; + } + else + { + SPV_DEFAULT_SAMPLE_VAR_IF_MISSINGBuilder << "let sample = 0;"; + } + + auto SPV_PREFIX_IMAGE_PARAMS = SPV_PREFIX_IMAGE_PARAMSBuilder.toString(); + auto SPV_SUFFIX_IMAGE_PARAMS = SPV_SUFFIX_IMAGE_PARAMSBuilder.toString(); + auto SPV_DEFAULT_SAMPLE_VAR_IF_MISSING = SPV_DEFAULT_SAMPLE_VAR_IF_MISSINGBuilder.toString(); + }}}} + + __generic<let format:int=0> + public typealias $(fullTypeName) = __TextureImpl< + $(targetType.type), + $(targetShape.shape), + $(targetShape.isArray), // isArray + $(targetShape.isMS), // isMS + 0, // sampleCount + 1, // access + 0, // isShadow + 0, // isCombined + format + >; + +${{{{ + if(targetShape.isRect) + continue; +}}}} + + // readonly writeonly in GLSL means an object only allows information queries. + [require(spirv)] + [require(glsl)] + [__readNone] + [ForceInline] public $(imageSizeIntOrIVec) imageSize(readonly writeonly $(fullTypeName) image) + { + __target_switch + { + case glsl: __intrinsic_asm "imageSize($*0)"; + case spirv: + return spirv_asm + { + OpCapability ImageQuery; + result:$$$(imageSizeIntOrIVec) = OpImageQuerySize $image; + }; + } + } + [require(spirv)] + [require(glsl)] + [__NoSideEffect] + [ForceInline] public $(targetType.prefix)vec4 imageLoad(readonly $(IMAGE_PARAMS)) + { + __target_switch + { + case glsl: __intrinsic_asm "imageLoad($*0)"; + case spirv: + { + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + result:$$$(targetType.prefix)vec4 = OpImageRead $(SPV_PREFIX_IMAGE_PARAMS) $(SPV_SUFFIX_IMAGE_PARAMS); + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public void imageStore(writeonly $(IMAGE_PARAMS), $(targetType.prefix)vec4 data) + { + __target_switch + { + case glsl: __intrinsic_asm "imageStore($*0)"; + case spirv: + { + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpImageWrite $(SPV_PREFIX_IMAGE_PARAMS) $data $(SPV_SUFFIX_IMAGE_PARAMS); + }; + } + } + } + +${{{{ + if (targetShape.isMS) + { +}}}} + // readonly writeonly in GLSL means an object only allows information queries. + [require(spirv)] + [require(glsl)] + [__readNone] + [ForceInline] public int imageSamples(readonly writeonly $(fullTypeName) image) + { + __target_switch + { + case glsl: __intrinsic_asm "imageSamples($*0)"; + case spirv: + return spirv_asm + { + OpCapability ImageQuery; + result:$$int = OpImageQuerySamples $image; + }; + } + } +${{{{ + } +}}}} + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicAdd($(IMAGE_PARAMS), $(targetType.type) data) + { + typeRequireChecks_image_atomic_tier1<$(targetType.type)>(); + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicAdd($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomic$(targetType.SPVTypePrefix)Add$(targetType.SPVAtomicSuffix) %ptr Device None $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicExchange($(IMAGE_PARAMS), $(targetType.type) data) + { + typeRequireChecks_image_atomic_tier1<$(targetType.type)>(); + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicExchange($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomicExchange %ptr Device ImageMemory $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicMin($(IMAGE_PARAMS), $(targetType.type) data) + { + typeRequireChecks_image_atomic_tier2<$(targetType.type)>(); + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicMin($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomic$(targetType.SPVSubTypePrefix)Min$(targetType.SPVAtomicSuffix) %ptr Device ImageMemory $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicMax($(IMAGE_PARAMS), $(targetType.type) data) + { + typeRequireChecks_image_atomic_tier2<$(targetType.type)>(); + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicMax($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomic$(targetType.SPVSubTypePrefix)Max$(targetType.SPVAtomicSuffix) %ptr Device ImageMemory $data + }; + } + } + } +${{{{ + if (!targetType.isInt) + continue; +}}}} + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicAnd($(IMAGE_PARAMS), $(targetType.type) data) + { + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicAnd($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomicAnd %ptr Device ImageMemory $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicOr($(IMAGE_PARAMS), $(targetType.type) data) + { + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicOr($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomicOr %ptr Device ImageMemory $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicXor($(IMAGE_PARAMS), $(targetType.type) data) + { + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicXor($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomicXor %ptr Device ImageMemory $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicCompSwap($(IMAGE_PARAMS), $(targetType.type) compare, $(targetType.type) data) + { + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicCompSwap($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomicCompareExchange %ptr Device ImageMemory ImageMemory $data $compare + }; + } + } + } +${{{{ + } +} +}}}} //// RayTracing diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 87057b694..4ccca36ea 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -29,7 +29,6 @@ class PrefixModifier : public Modifier { SLANG_AST_CLASS(PrefixModifier)}; class PostfixModifier : public Modifier { SLANG_AST_CLASS(PostfixModifier)}; class ExportedModifier : public Modifier { SLANG_AST_CLASS(ExportedModifier)}; class ConstExprModifier : public Modifier { SLANG_AST_CLASS(ConstExprModifier)}; -class GloballyCoherentModifier : public Modifier { SLANG_AST_CLASS(GloballyCoherentModifier)}; class ExternCppModifier : public Modifier { SLANG_AST_CLASS(ExternCppModifier)}; class GLSLPrecisionModifier : public Modifier { SLANG_AST_CLASS(GLSLPrecisionModifier)}; class GLSLModuleModifier : public Modifier {SLANG_AST_CLASS(GLSLModuleModifier)}; @@ -1493,6 +1492,11 @@ class NoDiffModifier : public TypeModifier SLANG_AST_CLASS(NoDiffModifier) }; +class GloballyCoherentModifier : public SimpleModifier +{ + SLANG_AST_CLASS(GloballyCoherentModifier) +}; + // Some GLSL-specific modifiers class GLSLBufferModifier : public WrappingTypeModifier { @@ -1509,6 +1513,16 @@ class GLSLReadOnlyModifier : public SimpleModifier SLANG_AST_CLASS(GLSLReadOnlyModifier) }; +class GLSLVolatileModifier : public SimpleModifier +{ + SLANG_AST_CLASS(GLSLVolatileModifier) +}; + +class GLSLRestrictModifier : public SimpleModifier +{ + SLANG_AST_CLASS(GLSLRestrictModifier) +}; + class GLSLPatchModifier : public SimpleModifier { SLANG_AST_CLASS(GLSLPatchModifier) @@ -1531,4 +1545,35 @@ class DynamicUniformModifier : public Modifier SLANG_AST_CLASS(DynamicUniformModifier) }; +class MemoryQualifierCollectionModifier : public Modifier +{ + SLANG_AST_CLASS(MemoryQualifierCollectionModifier); + + List<Modifier*> memoryModifiers; + + uint32_t memoryQualifiers = 0; + +public: + struct Flags + { + enum MemoryQualifiersBit + { + kNone = 0b0, + kCoherent = 0b1, + kReadOnly = 0b10, + kWriteOnly = 0b100, + kVolatile = 0b1000, + kRestrict = 0b10000, + }; + }; + + void addQualifier(Modifier* mod, Flags::MemoryQualifiersBit type) + { + memoryModifiers.add(mod); + memoryQualifiers |= type; + } + uint32_t getMemoryQualifierBit() { return memoryQualifiers; } + List<Modifier*> getModifiers() { return memoryModifiers; } +}; + } // namespace Slang diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index 4ad5fc432..e4e3be384 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -549,6 +549,8 @@ namespace Slang Type* type = nullptr; bool isLeftValue; + bool hasReadOnlyOnTarget = false; + bool isWriteOnly = false; QualType() : isLeftValue(false) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 386a0bba1..c844fb82a 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -944,7 +944,27 @@ namespace Slang } } + // Ensures child of struct is set read-only or not + bool isWriteOnly = false; + { + for (auto mod : varDeclRef.getDecl()->modifiers) + { + if (as<GLSLReadOnlyModifier>(mod)) + { + isLValue = false; + qualType.hasReadOnlyOnTarget = true; + if (isLValue == false && isWriteOnly) break; + } + if (as<GLSLWriteOnlyModifier>(mod)) + { + isWriteOnly = true; + if (isLValue == false && isWriteOnly) break; + } + } + } + qualType.isLeftValue = isLValue; + qualType.isWriteOnly = isWriteOnly; return qualType; } else if( auto propertyDeclRef = declRef.as<PropertyDecl>() ) @@ -1846,6 +1866,8 @@ namespace Slang // initExpr = subVisitor.CheckTerm(initExpr); + if (initExpr->type.isWriteOnly) + getSink()->diagnose(initExpr, Diagnostics::readingFromWriteOnly); initExpr = coerce(CoercionSite::Initializer, varDecl->type.Ptr(), initExpr); varDecl->initExpr = initExpr; @@ -7023,6 +7045,16 @@ namespace Slang } } } + + // Only texture types are allowed to have memory qualifiers on parameters + if(!paramDecl->type || paramDecl->type->astNodeType != ASTNodeType::TextureType) + { + auto memoryQualifierCollection = paramDecl->findModifier<MemoryQualifierCollectionModifier>(); + if(!memoryQualifierCollection) + return; + for(auto mod : memoryQualifierCollection->getModifiers()) + getSink()->diagnose(paramDecl, Diagnostics::memoryQualifierNotAllowedOnANonImageTypeParameter, mod); + } } // This checks that the declaration is marked as "out" and changes the hlsl diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index dc7a2d35b..a31e17123 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -412,6 +412,11 @@ namespace Slang expr->declRef = declRef; expr->memberOperatorLoc = _getMemberOpLoc(originalExpr); + // If any member declares the following value is a + // write only, we must declare the parent as a write + // only to avoid modifying the child + expr->type.isWriteOnly = baseExpr->type.isWriteOnly || expr->type.isWriteOnly; + // When referring to a member through an expression, // the result is only an l-value if both the base // expression and the member agree that it should be. @@ -424,7 +429,7 @@ namespace Slang // One exception to this is if we're reading the contents // of a GLSL buffer interface block which isn't marked as // read_only - expr->type.isLeftValue = isMutableGLSLBufferBlockVarExpr(baseExpr); + expr->type.isLeftValue = isMutableGLSLBufferBlockVarExpr(baseExpr) && (expr->type.hasReadOnlyOnTarget == false); } else { @@ -2078,6 +2083,9 @@ namespace Slang Expr* SemanticsVisitor::checkAssignWithCheckedOperands(AssignExpr* expr) { + if (expr->right->type.isWriteOnly) + getSink()->diagnose(expr, Diagnostics::readingFromWriteOnly); + expr->left = maybeOpenRef(expr->left); auto type = expr->left->type; auto right = maybeOpenRef(expr->right); @@ -2177,6 +2185,44 @@ namespace Slang return _canLValueCoerceScalarType(a, b); } + + void SemanticsVisitor::compareMemoryQualifierOfParamToArgument( + ParamDecl* paramIn, + Expr* argIn) + { + auto arg = as<VarExpr>(argIn); + if (!paramIn || !arg) + return; + + auto argDeclRef = arg->declRef; + if (!argDeclRef) + return; + auto argDecl = argDeclRef.getDecl(); + auto argMemMods = argDecl->findModifier<MemoryQualifierCollectionModifier>(); + if(!argMemMods) + return; + uint32_t argQualifiers = argMemMods->getMemoryQualifierBit(); + + uint32_t paramQualifiers = 0; + auto paramMemMods = paramIn->findModifier<MemoryQualifierCollectionModifier>(); + if(paramMemMods) + paramQualifiers = paramMemMods->getMemoryQualifierBit(); + + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kCoherent + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kCoherent)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "coherent"); + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kReadOnly + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kReadOnly)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "readonly"); + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kWriteOnly + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kWriteOnly)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "writeonly"); + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kVolatile + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kVolatile)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "volatile"); + // dropping a `restrict` qualifier from arguments is allowed in GLSL with memory qualifiers + } + Expr* SemanticsVisitor::CheckInvokeExprWithCheckedOperands(InvokeExpr *expr) { auto rs = ResolveInvoke(expr); @@ -2194,10 +2240,25 @@ namespace Slang } } + auto funcDeclRefExpr = as<DeclRefExpr>(invoke->functionExpr); + FunctionDeclBase* funcDeclBase = nullptr; + if (funcDeclRefExpr) + funcDeclBase = as<FunctionDeclBase>(funcDeclRefExpr->declRef.getDecl()); + Index paramCount = funcType->getParamCount(); for (Index pp = 0; pp < paramCount; ++pp) { auto paramType = funcType->getParamType(pp); + Expr* argExpr = nullptr; + ParamDecl* paramDecl = nullptr; + if (pp < expr->arguments.getCount()) + { + argExpr = expr->arguments[pp]; + if(funcDeclBase) + paramDecl = funcDeclBase->getParameters()[pp]; + } + compareMemoryQualifierOfParamToArgument(paramDecl, argExpr); + if (as<OutTypeBase>(paramType) || as<RefType>(paramType)) { // `out`, `inout`, and `ref` parameters currently require @@ -2207,9 +2268,8 @@ namespace Slang // for an `inout` parameter to be converted in both // directions. // - if( pp < expr->arguments.getCount() ) + if( argExpr ) { - auto argExpr = expr->arguments[pp]; if( !argExpr->type.isLeftValue) { auto implicitCastExpr = as<ImplicitCastExpr>(argExpr); @@ -3280,6 +3340,8 @@ namespace Slang { auto elementType = QualType(pointerLikeType->getElementType()); elementType.isLeftValue = baseType.isLeftValue; + elementType.hasReadOnlyOnTarget = baseType.hasReadOnlyOnTarget; + elementType.isWriteOnly = baseType.isWriteOnly; auto derefExpr = m_astBuilder->create<DerefExpr>(); derefExpr->base = expr; diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 392d78c5a..278fc3265 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -2467,6 +2467,7 @@ namespace Slang Expr* CheckExpr(Expr* expr); + void compareMemoryQualifierOfParamToArgument(ParamDecl* paramIn, Expr* argIn); Expr* CheckInvokeExprWithCheckedOperands(InvokeExpr *expr); // Get the type to use when referencing a declaration QualType GetTypeForDeclRef(DeclRef<Decl> declRef, SourceLoc loc); diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index 0b9688cb0..942afd559 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -1010,6 +1010,8 @@ namespace Slang case ASTNodeType::GLSLBufferModifier: case ASTNodeType::GLSLWriteOnlyModifier: case ASTNodeType::GLSLReadOnlyModifier: + case ASTNodeType::GLSLVolatileModifier: + case ASTNodeType::GLSLRestrictModifier: case ASTNodeType::GLSLPatchModifier: case ASTNodeType::RayPayloadAccessSemantic: case ASTNodeType::RayPayloadReadSemantic: @@ -1092,16 +1094,26 @@ namespace Slang case ASTNodeType::RefModifier: case ASTNodeType::ConstRefModifier: case ASTNodeType::GLSLBufferModifier: - case ASTNodeType::GLSLWriteOnlyModifier: - case ASTNodeType::GLSLReadOnlyModifier: case ASTNodeType::GLSLPatchModifier: case ASTNodeType::RayPayloadAccessSemantic: case ASTNodeType::RayPayloadReadSemantic: case ASTNodeType::RayPayloadWriteSemantic: return (as<VarDeclBase>(decl) && isGlobalDecl(decl)) || as<ParamDecl>(decl) || as<GLSLInterfaceBlockDecl>(decl); + case ASTNodeType::GLSLWriteOnlyModifier: + case ASTNodeType::GLSLReadOnlyModifier: + case ASTNodeType::GLSLVolatileModifier: + case ASTNodeType::GLSLRestrictModifier: + if(isGLSLInput) + return (as<VarDeclBase>(decl) && (isGlobalDecl(decl)) || as<ParamDecl>(decl) || as<GLSLInterfaceBlockDecl>(decl)) + || as<StructDecl>(getParentDecl(decl)) && isGlobalDecl(getParentDecl(decl)); + return (as<VarDeclBase>(decl) && (isGlobalDecl(decl)) || as<ParamDecl>(decl) || as<GLSLInterfaceBlockDecl>(decl)); + case ASTNodeType::GloballyCoherentModifier: case ASTNodeType::HLSLVolatileModifier: + if(isGLSLInput) + return as<VarDecl>(decl) && (isGlobalDecl(decl) || as<StructDecl>(getParentDecl(decl)) || as<GLSLInterfaceBlockDecl>(decl)) + || as<VarDeclBase>(decl) && isGlobalDecl(decl) || as<ParamDecl>(decl) || (as<StructDecl>(getParentDecl(decl)) && isGlobalDecl(getParentDecl(decl))); return as<VarDecl>(decl) && (isGlobalDecl(decl) || as<StructDecl>(getParentDecl(decl)) || as<GLSLInterfaceBlockDecl>(decl)); // Allowed only on parameters, struct fields and global variables. @@ -1216,6 +1228,40 @@ namespace Slang } } + MemoryQualifierCollectionModifier::Flags::MemoryQualifiersBit memoryQualifierBit = + MemoryQualifierCollectionModifier::Flags::kNone; + if(as<GloballyCoherentModifier>(m)) + memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kCoherent; + else if(as<GLSLReadOnlyModifier>(m)) + memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kReadOnly; + else if(as<GLSLWriteOnlyModifier>(m)) + memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kWriteOnly; + else if(as<GLSLVolatileModifier>(m)) + memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kVolatile; + else if(as<GLSLRestrictModifier>(m)) + memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kRestrict; + if(memoryQualifierBit != MemoryQualifierCollectionModifier::Flags::kNone) + { + bool newModifier = false; + MemoryQualifierCollectionModifier* memoryQualifiers = syntaxNode->findModifier<MemoryQualifierCollectionModifier>(); + if(!memoryQualifiers) + { + newModifier = true; + memoryQualifiers = getASTBuilder()->create<MemoryQualifierCollectionModifier>(); + } + memoryQualifiers->addQualifier(m, + memoryQualifierBit); + if (newModifier) + { + // insert in modifiers list the memoryQualifierCollection + Modifier* mod = m->next; + m->next = memoryQualifiers; + memoryQualifiers->next = mod; + return m; + } + return m; + } + if (auto hlslSemantic = as<HLSLSimpleSemantic>(m)) { if (hlslSemantic->name.getName() == getSession()->getCompletionRequestTokenName()) @@ -1519,6 +1565,7 @@ namespace Slang if (as<SharedModifiers>(modifier)) ignoreUnallowedModifier = true; + // may return a list of modifiers auto checkedModifier = checkModifier(modifier, syntaxNode, ignoreUnallowedModifier); if(checkedModifier) diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 757ce94ee..e1c929f7e 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -298,6 +298,7 @@ DIAGNOSTIC(30035, Error, componentOverloadTypeMismatch, "'$0': type of overloade DIAGNOSTIC(30041, Error, bitOperationNonIntegral, "bit operation: operand must be integral type.") DIAGNOSTIC(30043, Error, getStringHashRequiresStringLiteral, "getStringHash parameter can only accept a string literal") DIAGNOSTIC(30047, Error, argumentExpectedLValue, "argument passed to parameter '$0' must be l-value.") +DIAGNOSTIC(30048, Error, argumentHasMoreMemoryQualifiersThanParam, "argument passed in to parameter has a memory qualifier the parameter type is missing: '$0'") DIAGNOSTIC(30049, Note, thisIsImmutableByDefault, "a 'this' parameter is an immutable parameter by default in Slang; apply the `[mutating]` attribute to the function declaration to opt in to a mutable `this`") DIAGNOSTIC(30050, Error, mutatingMethodOnImmutableValue, "mutating method '$0' cannot be called on an immutable value") @@ -355,6 +356,8 @@ DIAGNOSTIC(30098, Error, nonStaticMemberFunctionNotAllowedAsDiffOperand, "non-st DIAGNOSTIC(30099, Error, sizeOfArgumentIsInvalid, "argument to sizeof is invalid") +DIAGNOSTIC(30101, Error, readingFromWriteOnly, "cannot read from writeonly, check modifiers.") + // Include DIAGNOSTIC(30500, Error, includedFileMissingImplementing, "missing 'implementing' declaration in the included source file '$0'.") DIAGNOSTIC(30501, Error, includedFileMissingImplementingDoYouMeanImport, "missing 'implementing' declaration in the included source file '$0'. The file declares that it defines module '$1', do you mean 'import' instead?") @@ -444,6 +447,7 @@ DIAGNOSTIC(31202, Error, duplicateModifier, "modifier '$0' is redundant or confl DIAGNOSTIC(31203, Error, cannotExportIncompleteType, "cannot export incomplete type '$0'") DIAGNOSTIC(31204, Error, incompleteTypeCannotBeUsedInBuffer, "incomplete type '$0' cannot be used in a buffer") DIAGNOSTIC(31205, Error, incompleteTypeCannotBeUsedInUniformParameter, "incomplete type '$0' cannot be used in a uniform parameter") +DIAGNOSTIC(31206, Error, memoryQualifierNotAllowedOnANonImageTypeParameter, "modifier $0 is not allowed on a non image type parameter.") // Enums diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index af53b545f..b60e0a4ac 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -3537,6 +3537,7 @@ void CLikeSourceEmitter::emitStructDeclarationsBlock(IRStructType* structType, b emitPackOffsetModifier(fieldKey, fieldType, packOffsetDecoration); } } + emitMemoryQualifiers(fieldKey); emitType(fieldType, getName(fieldKey)); emitSemantics(fieldKey, allowOffsetLayout); m_writer->emit(";\n"); diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index 46cdf2145..fa99ae061 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -385,6 +385,7 @@ public: /// Emit type attributes that should appear after, e.g., a `struct` keyword void emitPostKeywordTypeAttributes(IRInst* inst) { emitPostKeywordTypeAttributesImpl(inst); } + virtual void emitMemoryQualifiers(IRInst* /*varInst*/) {}; void emitInterpolationModifiers(IRInst* varInst, IRType* valueType, IRVarLayout* layout); void emitMeshShaderModifiers(IRInst* varInst); virtual void emitPackOffsetModifier(IRInst* /*varInst*/, IRType* /*valueType*/, IRPackOffsetDecoration* /*decoration*/) {}; diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp index 7e5c84533..bbd869eda 100644 --- a/source/slang/slang-emit-glsl.cpp +++ b/source/slang/slang-emit-glsl.cpp @@ -114,6 +114,38 @@ void GLSLSourceEmitter::_requireGLSLVersion(int version) } } +void GLSLSourceEmitter::_emitMemoryQualifierDecorations(IRInst* varDecl) +{ + for (auto decoration : varDecl->getDecorations()) + { + if (as<IRGloballyCoherentDecoration>(decoration)) + { + m_writer->emit("coherent "); + } + else if (as<IRGLSLVolatileDecoration>(decoration)) + { + m_writer->emit("volatile "); + } + else if (as<IRGLSLRestrictDecoration>(decoration)) + { + m_writer->emit("restrict "); + } + else if (as<IRGLSLReadOnlyDecoration>(decoration)) + { + m_writer->emit("readonly "); + } + else if (as<IRGLSLWriteOnlyDecoration>(decoration)) + { + m_writer->emit("writeonly "); + } + } +} + +void GLSLSourceEmitter::emitMemoryQualifiers(IRInst* varDecl) +{ + _emitMemoryQualifierDecorations(varDecl); +} + void GLSLSourceEmitter::_emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSLStructuredBufferTypeBase* structuredBufferType) { // Shader storage buffer is an OpenGL 430 feature @@ -182,10 +214,7 @@ void GLSLSourceEmitter::_emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSL HLSLAppendStructuredBufferType - Write HLSLConsumeStructuredBufferType - TODO (JS): Its possible that this can be readonly, but we currently don't support on GLSL */ - if (varDecl->findDecoration<IRGloballyCoherentDecoration>()) - { - m_writer->emit("coherent "); - } + _emitMemoryQualifierDecorations(varDecl); if (as<IRHLSLStructuredBufferType>(structuredBufferType)) { m_writer->emit("readonly "); @@ -288,10 +317,7 @@ void GLSLSourceEmitter::emitSSBOHeader(IRGlobalParam* varDecl, IRType* bufferTyp } m_writer->emit(") "); - if (varDecl->findDecoration<IRGloballyCoherentDecoration>()) - { - m_writer->emit("coherent "); - } + _emitMemoryQualifierDecorations(varDecl); /* If the output type is a buffer, and we can determine it is only readonly we can prefix before @@ -461,6 +487,11 @@ void GLSLSourceEmitter::_emitGLSLImageFormatModifier(IRInst* var, IRTextureType* } else { + auto formatInfo = getImageFormatInfo(format); + if (formatInfo.scalarType == SLANG_SCALAR_TYPE_UINT64 || formatInfo.scalarType == SLANG_SCALAR_TYPE_INT64) + { + _requireGLSLExtension(UnownedStringSlice::fromLiteral("GL_EXT_shader_image_int64")); + } // If there is an explicit format specified, then we // should emit a `layout` modifier using the GLSL name // for the format. diff --git a/source/slang/slang-emit-glsl.h b/source/slang/slang-emit-glsl.h index 1a95cd346..610a961d2 100644 --- a/source/slang/slang-emit-glsl.h +++ b/source/slang/slang-emit-glsl.h @@ -35,6 +35,7 @@ protected: virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) SLANG_OVERRIDE; virtual void emitPackOffsetModifier(IRInst* varInst, IRType* valueType, IRPackOffsetDecoration* decoration) SLANG_OVERRIDE; + virtual void emitMemoryQualifiers(IRInst* varInst) SLANG_OVERRIDE; virtual void emitMeshShaderModifiersImpl(IRInst* varInst) SLANG_OVERRIDE; virtual void emitSimpleTypeImpl(IRType* type) SLANG_OVERRIDE; virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) SLANG_OVERRIDE; @@ -56,6 +57,7 @@ protected: virtual void emitSimpleValueImpl(IRInst* inst) SLANG_OVERRIDE; virtual void emitLoopControlDecorationImpl(IRLoopControlDecoration* decl) SLANG_OVERRIDE; + void _emitMemoryQualifierDecorations(IRInst* varDecl); void _emitGLSLTextureOrTextureSamplerType(IRTextureTypeBase* type, char const* baseName); void _emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSLStructuredBufferTypeBase* structuredBufferType); diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index c48f0e978..ddcd5ae4d 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -1765,6 +1765,40 @@ struct SPIRVEmitContext } } + void setImageFormatCapabilityAndExtension(SpvImageFormat format, SpvCapability_ setCapabilityMask) + { + switch (format) + { + case SpvImageFormatUnknown: + case SpvImageFormatRgba32f: + case SpvImageFormatRgba16f: + case SpvImageFormatR32f: + case SpvImageFormatRgba8: + case SpvImageFormatRgba8Snorm: + case SpvImageFormatRgba32i: + case SpvImageFormatRgba16i: + case SpvImageFormatRgba8i: + case SpvImageFormatR32i: + case SpvImageFormatRgba32ui: + case SpvImageFormatRgba16ui: + case SpvImageFormatRgba8ui: + case SpvImageFormatR32ui: + if(setCapabilityMask == SpvCapabilityShader) return; + requireSPIRVCapability(SpvCapabilityShader); + return; + case SpvImageFormatR64ui: + case SpvImageFormatR64i: + if(setCapabilityMask == SpvCapabilityInt64ImageEXT) return; + ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_shader_image_int64")); + requireSPIRVCapability(SpvCapabilityInt64ImageEXT); + return; + default: + if(setCapabilityMask == SpvCapabilityStorageImageExtendedFormats) return; + requireSPIRVCapability(SpvCapabilityStorageImageExtendedFormats); + return; + } + } + SpvInst* ensureTextureType(IRInst* assignee, IRTextureTypeBase* inst) { // Some untyped constants from OpTypeImage @@ -1895,6 +1929,8 @@ struct SPIRVEmitContext // // SPIR-V requires that the sampled/rw info on the image isn't unknown SLANG_ASSERT(sampled == sampledImage || sampled == readWriteImage); + if(isMultisampled) + requireSPIRVCapability(SpvCapabilityStorageImageMultisample); switch(dim) { case SpvDim1D: @@ -1933,9 +1969,7 @@ struct SPIRVEmitContext requireSPIRVCapability(SpvCapabilityStorageImageWriteWithoutFormat); } - auto formatCapability = getImageFormatCapability(format); - if (formatCapability != SpvCapabilityShader) - requireSPIRVCapability(formatCapability); + setImageFormatCapabilityAndExtension(format, SpvCapabilityShader); // // The op itself @@ -3266,6 +3300,30 @@ struct SPIRVEmitContext dstID, SpvDecorationCoherent); break; + case kIROp_GLSLVolatileDecoration: + emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), + decoration, + dstID, + SpvDecorationVolatile); + break; + case kIROp_GLSLRestrictDecoration: + emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), + decoration, + dstID, + SpvDecorationRestrict); + break; + case kIROp_GLSLReadOnlyDecoration: + emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), + decoration, + dstID, + SpvDecorationNonWritable); + break; + case kIROp_GLSLWriteOnlyDecoration: + emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), + decoration, + dstID, + SpvDecorationNonReadable); + break; // ... } diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index 63f063154..254a411cd 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -660,6 +660,8 @@ INST(GetOptiXSbtDataPtr, getOptiXSbtDataPointer, 0, 0) INST(GetVulkanRayTracingPayloadLocation, GetVulkanRayTracingPayloadLocation, 1, 0) +INST(GetLegalizedSPIRVGlobalParamAddr, kIROp_GetLegalizedSPIRVGlobalParamAddr, 1, 0) + INST(MakeArrayList, makeArrayList, 0, 0) INST(MakeTensorView, makeTensorView, 0, 0) INST(AllocateTorchTensor, allocTorchTensor, 0, 0) @@ -856,6 +858,10 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) INST(GlobalInputDecoration, output, 0, 0) INST(GLSLLocationDecoration, glslLocation, 1, 0) INST(GLSLOffsetDecoration, glslOffset, 1, 0) + INST(GLSLVolatileDecoration, glslVolatile, 1, 0) + INST(GLSLRestrictDecoration, glslRestrict, 1, 0) + INST(GLSLReadOnlyDecoration, glslReadonly, 1, 0) + INST(GLSLWriteOnlyDecoration, glslWriteonly, 1, 0) INST(PayloadDecoration, payload, 0, 0) /* Mesh Shader outputs */ diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 36f9159a8..c884dd35f 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -354,6 +354,10 @@ IR_SIMPLE_DECORATION(ReadNoneDecoration) IR_SIMPLE_DECORATION(NoSideEffectDecoration) IR_SIMPLE_DECORATION(EarlyDepthStencilDecoration) IR_SIMPLE_DECORATION(GloballyCoherentDecoration) +IR_SIMPLE_DECORATION(GLSLVolatileDecoration) +IR_SIMPLE_DECORATION(GLSLRestrictDecoration) +IR_SIMPLE_DECORATION(GLSLReadOnlyDecoration) +IR_SIMPLE_DECORATION(GLSLWriteOnlyDecoration) IR_SIMPLE_DECORATION(PreciseDecoration) IR_SIMPLE_DECORATION(PublicDecoration) IR_SIMPLE_DECORATION(HLSLExportDecoration) diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp index ca3729abc..68f1e02a2 100644 --- a/source/slang/slang-ir-spirv-legalize.cpp +++ b/source/slang/slang-ir-spirv-legalize.cpp @@ -217,7 +217,12 @@ struct SPIRVLegalizationContext : public SourceEmitterBase IRBuilder builder(user); builder.setInsertBefore(user); - if((as<IRGetElement>(user) || as<IRFieldExtract>(user)) && + if(user->getOp() == kIROp_GetLegalizedSPIRVGlobalParamAddr) + { + user->replaceUsesWith(use->get()); + user->removeAndDeallocate(); + } + else if((as<IRGetElement>(user) || as<IRFieldExtract>(user)) && use == user->getOperands()) { // If the use is the address operand of a getElement or FieldExtract, diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 3dd8da9f1..41638dc83 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -2217,6 +2217,22 @@ void addVarDecorations( { builder->addDynamicUniformDecoration(inst); } + else if (as<GLSLVolatileModifier>(mod)) + { + builder->addSimpleDecoration<IRGLSLVolatileDecoration>(inst); + } + else if (as<GLSLRestrictModifier>(mod)) + { + builder->addSimpleDecoration<IRGLSLRestrictDecoration>(inst); + } + else if (as<GLSLReadOnlyModifier>(mod)) + { + builder->addSimpleDecoration<IRGLSLReadOnlyDecoration>(inst); + } + else if (as<GLSLWriteOnlyModifier>(mod)) + { + builder->addSimpleDecoration<IRGLSLWriteOnlyDecoration>(inst); + } // TODO: what are other modifiers we need to propagate through? } if(auto t = composeGetters<IRMeshOutputType>(inst->getFullType(), &IROutTypeBase::getValueType)) diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index f7a0376ce..5b8a1af4f 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -7843,6 +7843,70 @@ namespace Slang parser->sink->diagnose(token, Diagnostics::invalidCUDASMVersion); return nullptr; } + static NodeBase* parseVolatileModifier(Parser* parser, void* /*userData*/) + { + ModifierListBuilder listBuilder; + + auto hlslMod = parser->astBuilder->create<HLSLVolatileModifier>(); + hlslMod->keywordName = getName(parser, "volatile"); + hlslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(hlslMod); + + auto glslMod = parser->astBuilder->create<GLSLVolatileModifier>(); + glslMod->keywordName = getName(parser, "volatile"); + glslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(glslMod); + + return listBuilder.getFirst(); + } + + static NodeBase* parseCoherentModifier(Parser* parser, void* /*userData*/) + { + ModifierListBuilder listBuilder; + + auto glslMod = parser->astBuilder->create<GloballyCoherentModifier>(); + glslMod->keywordName = getName(parser, "coherent"); + glslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(glslMod); + + return listBuilder.getFirst(); + } + + static NodeBase* parseRestrictModifier(Parser* parser, void* /*userData*/) + { + ModifierListBuilder listBuilder; + + auto glslMod = parser->astBuilder->create<GLSLRestrictModifier>(); + glslMod->keywordName = getName(parser, "restrict"); + glslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(glslMod); + + return listBuilder.getFirst(); + } + + static NodeBase* parseReadonlyModifier(Parser* parser, void* /*userData*/) + { + ModifierListBuilder listBuilder; + + auto glslMod = parser->astBuilder->create<GLSLReadOnlyModifier>(); + glslMod->keywordName = getName(parser, "readonly"); + glslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(glslMod); + + return listBuilder.getFirst(); + } + + static NodeBase* parseWriteonlyModifier(Parser* parser, void* /*userData*/) + { + ModifierListBuilder listBuilder; + + auto glslMod = parser->astBuilder->create<GLSLWriteOnlyModifier>(); + glslMod->keywordName = getName(parser, "writeonly"); + glslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(glslMod); + + return listBuilder.getFirst(); + } static NodeBase* parseLayoutModifier(Parser* parser, void* /*userData*/) { @@ -7850,6 +7914,8 @@ namespace Slang GLSLLayoutLocalSizeAttribute* numThreadsAttrib = nullptr; + ImageFormat format; + listBuilder.add(parser->astBuilder->create<GLSLLayoutModifierGroupBegin>()); parser->ReadToken(TokenType::LParent); @@ -7923,6 +7989,12 @@ namespace Slang } } } + else if(findImageFormatByName(nameText.getUnownedSlice(), &format)) + { + auto attr = parser->astBuilder->create<FormatAttribute>(); + attr->format = format; + listBuilder.add(attr); + } else { Modifier* modifier = nullptr; @@ -8208,7 +8280,11 @@ namespace Slang _makeParseModifier("groupshared", HLSLGroupSharedModifier::kReflectClassInfo), _makeParseModifier("static", HLSLStaticModifier::kReflectClassInfo), _makeParseModifier("uniform", HLSLUniformModifier::kReflectClassInfo), - _makeParseModifier("volatile", HLSLVolatileModifier::kReflectClassInfo), + _makeParseModifier("volatile", parseVolatileModifier), + _makeParseModifier("coherent", parseCoherentModifier), + _makeParseModifier("restrict", parseRestrictModifier), + _makeParseModifier("readonly", parseReadonlyModifier), + _makeParseModifier("writeonly", parseWriteonlyModifier), _makeParseModifier("export", HLSLExportModifier::kReflectClassInfo), _makeParseModifier("dynamic_uniform", DynamicUniformModifier::kReflectClassInfo), diff --git a/tests/glsl-intrinsic/image/i64imageDim.slang b/tests/glsl-intrinsic/image/i64imageDim.slang new file mode 100644 index 000000000..a6d38153e --- /dev/null +++ b/tests/glsl-intrinsic/image/i64imageDim.slang @@ -0,0 +1,476 @@ +//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl +//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly + +// As per vulkan specification: https://registry.khronos.org/vulkan/specs/1.3/html/chap34.html#formats-definition +// i64/u64 images do not require sampled image support; support is currently unlikley on hardware +//#define test_when_hardware_supports_i64_and_u64_sampled_textures +// i64/u64 images do not require texel buffers support; support is currently unlikley on hardware +//#define TEST_when_hardware_supports_i64_and_u64_buffers + +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer +buffer MyBlockName2 +{ + uint data[1]; +} outputBuffer; + +layout(local_size_x = 1) in; + +//TEST_INPUT: set image_1d = RWTexture1D(format=R64_SINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=0,r64i) i64image1D image_1d; +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers +//COM:TEST_INPUT: set image_buffer = RWTextureBuffer(format=R64_INT, stride=8, data=[0 1 0 1 0 1 0 1]) +uniform layout(binding=1,r64i) i64imageBuffer image_buffer; +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers +//TEST_INPUT: set image_1dArray = RWTexture1D(format=R64_SINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=2,r64i) i64image1DArray image_1dArray; +//TEST_INPUT: set image_2d = RWTexture2D(format=R64_SINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=3,r64i) i64image2D image_2d; +//TEST_INPUT: set image_2dRect = RWTexture2D(format=R64_SINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=4,r64i) i64image2DRect image_2dRect; +//TEST_INPUT: set image_2dArray = RWTexture2D(format=R64_SINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=6,r64i) i64image2DArray image_2dArray; +//TEST_INPUT: set image_3d = RWTexture3D(format=R64_SINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=7,r64i) i64image3D image_3d; +//TEST_INPUT: set image_cube = RWTextureCube(format=R64_SINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=8,r64i) i64imageCube image_cube; +//TEST_INPUT: set image_cubeArray = RWTextureCube(format=R64_SINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=9,r64i) i64imageCubeArray image_cubeArray; +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures +//COM:TEST_INPUT: set image_2dMultiSample = RWTexture2D(format=R64_SINT, size=4, content=one, mipMaps = 1, sampleCount = two) +uniform layout(binding=5,r64i) i64image2DMS image_2dMultiSample; +//COM:TEST_INPUT: set image_2dMultiSampleArray = RWTexture2D(format=R64_SINT, size=4, content=one, mipMaps = 1, arrayLength=2, sampleCount = two) +uniform layout(binding=10,r64i) i64image2DMSArray image_2dMultiSampleArray; +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + +bool checkAllImageSize() +{ + return true + && imageSize(image_1d) == int(4) +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageSize(image_buffer) == int(4) +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageSize(image_1dArray) == ivec2(4, 2) + && imageSize(image_2d) == ivec2(4) + && imageSize(image_2dArray) == ivec3(4, 4, 2) + && imageSize(image_2dRect) == ivec2(4) + && imageSize(image_3d) == ivec3(4) + && imageSize(image_cube) == ivec2(4) + && imageSize(image_cubeArray) == ivec3(4, 4, 2) +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageSize(image_2dMultiSample) == ivec2(4) + && imageSize(image_2dMultiSampleArray) == ivec3(4, 4, 2) +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageLoad() +{ + return true + && imageLoad(image_1d, 0).x == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageLoad(image_buffer, 0).x == 1 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageLoad(image_1dArray, ivec2(0)).x == 1 + && imageLoad(image_2d, ivec2(0)).x == 1 + && imageLoad(image_2dRect, ivec2(0)).x == 1 + && imageLoad(image_2dArray, ivec3(0)).x == 1 + && imageLoad(image_3d, ivec3(0)).x == 1 + && imageLoad(image_cube, ivec3(0)).x == 1 + && imageLoad(image_cubeArray, ivec3(0)).x == 1 + && imageLoad(image_cubeArray, ivec3(0)).x == 1 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageLoad(image_2dMultiSample, ivec2(0), 1).x == 1 + && imageLoad(image_2dMultiSampleArray, ivec3(0), 1).x == 1 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool resetAllImageValues() +{ + imageStore(image_1d, 0,i64vec4(1)); +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + imageStore(image_buffer, 0,i64vec4(1)); +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + imageStore(image_1dArray, ivec2(0),i64vec4(1)); + imageStore(image_2d, ivec2(0),i64vec4(1)); + imageStore(image_2dRect, ivec2(0),i64vec4(1)); + imageStore(image_2dArray, ivec3(0),i64vec4(1)); + imageStore(image_3d, ivec3(0),i64vec4(1)); + imageStore(image_cube, ivec3(0),i64vec4(1)); + imageStore(image_cubeArray, ivec3(0),i64vec4(1)); +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + imageStore(image_2dMultiSample, ivec2(0), 1, i64vec4(1)); + imageStore(image_2dMultiSampleArray, ivec3(0), 1,i64vec4(1)); +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + return true; +} +int64_t load_image_1d() +{ + return imageLoad(image_1d, 0).x; +} +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers +int64_t load_image_buffer() +{ + return imageLoad(image_buffer, 0).x; +} +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers +int64_t load_image_1dArray() +{ + return imageLoad(image_1dArray, ivec2(0)).x; +} +int64_t load_image_2d() +{ + return imageLoad(image_2d, ivec2(0)).x; +} +int64_t load_image_2dRect() +{ + return imageLoad(image_2dRect, ivec2(0)).x; +} +int64_t load_image_2dArray() +{ + return imageLoad(image_2dArray, ivec3(0)).x; +} +int64_t load_image_3d() +{ + return imageLoad(image_3d, ivec3(0)).x; +} +int64_t load_image_cube() +{ + return imageLoad(image_cube, ivec3(0)).x; +} +int64_t load_image_cubeArray() +{ + return imageLoad(image_cubeArray, ivec3(0)).x; +} +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures +int64_t load_image_2dMultiSample() +{ + return imageLoad(image_2dMultiSample, ivec2(0), 1).x; +} +int64_t load_image_2dMultiSampleArray() +{ + return imageLoad(image_2dMultiSampleArray, ivec3(0), 1).x; +} +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + +// requires ImageLoad test to pass +bool checkAllImageStore() +{ + bool loadCheck = true; + + imageStore(image_1d, 0,i64vec4(0)); + loadCheck = loadCheck && load_image_1d() == 0; +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + imageStore(image_buffer, 0,i64vec4(0)); + loadCheck = loadCheck && load_image_buffer() == 0; +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + imageStore(image_1dArray, ivec2(0),i64vec4(0)); + loadCheck = loadCheck && load_image_1dArray() == 0; + imageStore(image_2d, ivec2(0),i64vec4(0)); + loadCheck = loadCheck && load_image_2d() == 0; + imageStore(image_2dRect, ivec2(0),i64vec4(0)); + loadCheck = loadCheck && load_image_2dRect() == 0; + imageStore(image_2dArray, ivec3(0),i64vec4(0)); + loadCheck = loadCheck && load_image_2dArray() == 0; + imageStore(image_3d, ivec3(0),i64vec4(0)); + loadCheck = loadCheck && load_image_3d() == 0; + imageStore(image_cube, ivec3(0),i64vec4(0)); + loadCheck = loadCheck && load_image_cube() == 0; + imageStore(image_cubeArray, ivec3(0),i64vec4(0)); + loadCheck = loadCheck && load_image_cubeArray() == 0; +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + imageStore(image_2dMultiSample, ivec2(0), 1, i64vec4(0)); + loadCheck = loadCheck && load_image_2dMultiSample() == 0; + imageStore(image_2dMultiSampleArray, ivec3(0), 1,i64vec4(0)); + loadCheck = loadCheck && load_image_2dMultiSampleArray() == 0; +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + resetAllImageValues(); + return loadCheck; +} +bool checkAllImageSamples() +{ + resetAllImageValues(); + return true +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageSamples(image_2dMultiSample) == 2 + && imageSamples(image_2dMultiSampleArray) == 2 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicAdd() +{ + resetAllImageValues(); + return true + && imageAtomicAdd(image_1d, 0, 0) == 1 + && load_image_1d() == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicAdd(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicAdd(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 1 + && imageAtomicAdd(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicAdd(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicAdd(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 1 + && imageAtomicAdd(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicAdd(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicAdd(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicAdd(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicAdd(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicExchange() +{ + resetAllImageValues(); + return true + && imageAtomicExchange(image_1d, 0, 0) == 1 + && load_image_1d() == 0 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicExchange(image_buffer, 0, 2) == 1 + && load_image_buffer() == 2 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicExchange(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 0 + && imageAtomicExchange(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 2 + && imageAtomicExchange(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicExchange(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 0 + && imageAtomicExchange(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 2 + && imageAtomicExchange(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 2 + && imageAtomicExchange(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 2 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicExchange(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicExchange(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicMin() +{ + resetAllImageValues(); + return true + && imageAtomicMin(image_1d, 0, 0) == 1 + && load_image_1d() == 0 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicMin(image_buffer, 0, 2) == 1 + && load_image_buffer() == 1 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicMin(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 0 + && imageAtomicMin(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 1 + && imageAtomicMin(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 1 + && imageAtomicMin(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 0 + && imageAtomicMin(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 1 + && imageAtomicMin(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 1 + && imageAtomicMin(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 1 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicMin(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 1 + && imageAtomicMin(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 1 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicMax() +{ + resetAllImageValues(); + return true + && imageAtomicMax(image_1d, 0, 0) == 1 + && load_image_1d() == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicMax(image_buffer, 0, 2) == 1 + && load_image_buffer() == 2 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicMax(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 1 + && imageAtomicMax(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 2 + && imageAtomicMax(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicMax(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 1 + && imageAtomicMax(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 2 + && imageAtomicMax(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 2 + && imageAtomicMax(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 2 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicMax(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicMax(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicAnd() +{ + resetAllImageValues(); + return true + && imageAtomicAnd(image_1d, 0, 1) == 1 + && load_image_1d() == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicAnd(image_buffer, 0, 2) == 1 + && load_image_buffer() == 0 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicAnd(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 1 + && imageAtomicAnd(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 0 + && imageAtomicAnd(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 0 + && imageAtomicAnd(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 1 + && imageAtomicAnd(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 0 + && imageAtomicAnd(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 0 + && imageAtomicAnd(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 0 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicAnd(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 0 + && imageAtomicAnd(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 0 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicOr() +{ + resetAllImageValues(); + return true + && imageAtomicOr(image_1d, 0, 1) == 1 + && load_image_1d() == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicOr(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicOr(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 1 + && imageAtomicOr(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicOr(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicOr(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 1 + && imageAtomicOr(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicOr(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicOr(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicOr(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicOr(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicXor() +{ + resetAllImageValues(); + return true + && imageAtomicXor(image_1d, 0, 1) == 1 + && load_image_1d() == 0 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicXor(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicXor(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 0 + && imageAtomicXor(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicXor(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicXor(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 0 + && imageAtomicXor(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicXor(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicXor(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicXor(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicXor(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicCompSwap() +{ + resetAllImageValues(); + return true + && imageAtomicCompSwap(image_1d, 0, 0, 2) == 1 + && load_image_1d() == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicCompSwap(image_buffer, 0, 1, 2) == 1 + && load_image_buffer() == 2 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicCompSwap(image_1dArray, ivec2(0), 0, 2) == 1 + && load_image_1dArray() == 1 + && imageAtomicCompSwap(image_2d, ivec2(0), 1, 2) == 1 + && load_image_2d() == 2 + && imageAtomicCompSwap(image_2dRect, ivec2(0), 1, 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicCompSwap(image_2dArray, ivec3(0), 0, 2) == 1 + && load_image_2dArray() == 1 + && imageAtomicCompSwap(image_3d, ivec3(0), 1, 2) == 1 + && load_image_3d() == 2 + && imageAtomicCompSwap(image_cube, ivec3(0), 1, 2) == 1 + && load_image_cube() == 2 + && imageAtomicCompSwap(image_cubeArray, ivec3(0), 1, 2) == 1 + && load_image_cubeArray() == 2 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicCompSwap(image_2dMultiSample, ivec2(0), 1, 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicCompSwap(image_2dMultiSampleArray, ivec3(0), 1, 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} + +// CHECK_GLSL: void main( +// CHECK_SPV: OpEntryPoint +void computeMain() +{ + outputBuffer.data[0] = true + && checkAllImageSize() + && checkAllImageLoad() + && checkAllImageStore() + && checkAllImageSamples() + && checkAllImageAtomicAdd() + && checkAllImageAtomicExchange() + && checkAllImageAtomicMin() + && checkAllImageAtomicMax() + && checkAllImageAtomicAnd() + && checkAllImageAtomicOr() + && checkAllImageAtomicXor() + && checkAllImageAtomicCompSwap() + ; + // BUF: 1 +} diff --git a/tests/glsl-intrinsic/image/iimageDim.slang b/tests/glsl-intrinsic/image/iimageDim.slang new file mode 100644 index 000000000..cb9756d56 --- /dev/null +++ b/tests/glsl-intrinsic/image/iimageDim.slang @@ -0,0 +1,411 @@ +//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl +//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly + +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer +buffer MyBlockName2 +{ + uint data[1]; +} outputBuffer; + +layout(local_size_x = 1) in; + +//TEST_INPUT: set image_1d = RWTexture1D(format=R32_SINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=0,r32i) iimage1D image_1d; +//TEST_INPUT: set image_buffer = RWTextureBuffer(format=R32_SINT, stride=8, data=[1 1 1 1]) +uniform layout(binding=1,r32i) iimageBuffer image_buffer; +//TEST_INPUT: set image_1dArray = RWTexture1D(format=R32_SINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=2,r32i) iimage1DArray image_1dArray; +//TEST_INPUT: set image_2d = RWTexture2D(format=R32_SINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=3,r32i) iimage2D image_2d; +//TEST_INPUT: set image_2dRect = RWTexture2D(format=R32_SINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=4,r32i) iimage2DRect image_2dRect; +//TEST_INPUT: set image_2dMultiSample = RWTexture2D(format=R32_SINT, size=4, content=one, mipMaps = 1, sampleCount = two) +uniform layout(binding=5,r32i) iimage2DMS image_2dMultiSample; +//TEST_INPUT: set image_2dArray = RWTexture2D(format=R32_SINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=6,r32i) iimage2DArray image_2dArray; +//TEST_INPUT: set image_3d = RWTexture3D(format=R32_SINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=7,r32i) iimage3D image_3d; +//TEST_INPUT: set image_cube = RWTextureCube(format=R32_SINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=8,r32i) iimageCube image_cube; +//TEST_INPUT: set image_cubeArray = RWTextureCube(format=R32_SINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=9,r32i) iimageCubeArray image_cubeArray; +//TEST_INPUT: set image_2dMultiSampleArray = RWTexture2D(format=R32_SINT, size=4, content=one, mipMaps = 1, arrayLength=2, sampleCount = two) +uniform layout(binding=10,r32i) iimage2DMSArray image_2dMultiSampleArray; + +bool checkAllImageSize() +{ + return true + && imageSize(image_1d) == int(4) + && imageSize(image_buffer) == int(4) + && imageSize(image_1dArray) == ivec2(4, 2) + && imageSize(image_2d) == ivec2(4) + && imageSize(image_2dArray) == ivec3(4, 4, 2) + && imageSize(image_2dRect) == ivec2(4) + && imageSize(image_2dMultiSample) == ivec2(4) + && imageSize(image_3d) == ivec3(4) + && imageSize(image_cube) == ivec2(4) + && imageSize(image_cubeArray) == ivec3(4, 4, 2) + && imageSize(image_2dMultiSampleArray) == ivec3(4, 4, 2) + ; +} +bool checkAllImageLoad() +{ + return true + && imageLoad(image_1d, 0).x == 1 + && imageLoad(image_buffer, 0).x == 1 + && imageLoad(image_1dArray, ivec2(0)).x == 1 + && imageLoad(image_2d, ivec2(0)).x == 1 + && imageLoad(image_2dRect, ivec2(0)).x == 1 + && imageLoad(image_2dMultiSample, ivec2(0), 1).x == 1 + && imageLoad(image_2dArray, ivec3(0)).x == 1 + && imageLoad(image_3d, ivec3(0)).x == 1 + && imageLoad(image_cube, ivec3(0)).x == 1 + && imageLoad(image_cubeArray, ivec3(0)).x == 1 + && imageLoad(image_cubeArray, ivec3(0)).x == 1 + && imageLoad(image_2dMultiSampleArray, ivec3(0), 1).x == 1 + ; +} +bool resetAllImageValues() +{ + imageStore(image_1d, 0, ivec4(1)); + imageStore(image_buffer, 0, ivec4(1)); + imageStore(image_1dArray, ivec2(0), ivec4(1)); + imageStore(image_2d, ivec2(0), ivec4(1)); + imageStore(image_2dRect, ivec2(0), ivec4(1)); + imageStore(image_2dMultiSample, ivec2(0), 1, ivec4(1)); + imageStore(image_2dArray, ivec3(0), ivec4(1)); + imageStore(image_3d, ivec3(0), ivec4(1)); + imageStore(image_cube, ivec3(0), ivec4(1)); + imageStore(image_cubeArray, ivec3(0), ivec4(1)); + imageStore(image_2dMultiSampleArray, ivec3(0), 1, ivec4(1)); + return true; +} +int load_image_1d() +{ + return imageLoad(image_1d, 0).x; +} +int load_image_buffer() +{ + return imageLoad(image_buffer, 0).x; +} +int load_image_1dArray() +{ + return imageLoad(image_1dArray, ivec2(0)).x; +} +int load_image_2d() +{ + return imageLoad(image_2d, ivec2(0)).x; +} +int load_image_2dRect() +{ + return imageLoad(image_2dRect, ivec2(0)).x; +} +int load_image_2dMultiSample() +{ + return imageLoad(image_2dMultiSample, ivec2(0), 1).x; +} +int load_image_2dArray() +{ + return imageLoad(image_2dArray, ivec3(0)).x; +} +int load_image_3d() +{ + return imageLoad(image_3d, ivec3(0)).x; +} +int load_image_cube() +{ + return imageLoad(image_cube, ivec3(0)).x; +} +int load_image_cubeArray() +{ + return imageLoad(image_cubeArray, ivec3(0)).x; +} +int load_image_2dMultiSampleArray() +{ + return imageLoad(image_2dMultiSampleArray, ivec3(0), 1).x; +} +// requires ImageLoad test to pass +bool checkAllImageStore() +{ + bool loadCheck = true; + + imageStore(image_1d, 0, ivec4(0)); + loadCheck = loadCheck && load_image_1d() == 0; + imageStore(image_buffer, 0, ivec4(0)); + loadCheck = loadCheck && load_image_buffer() == 0; + imageStore(image_1dArray, ivec2(0), ivec4(0)); + loadCheck = loadCheck && load_image_1dArray() == 0; + imageStore(image_2d, ivec2(0), ivec4(0)); + loadCheck = loadCheck && load_image_2d() == 0; + imageStore(image_2dRect, ivec2(0), ivec4(0)); + loadCheck = loadCheck && load_image_2dRect() == 0; + imageStore(image_2dMultiSample, ivec2(0), 1, ivec4(0)); + loadCheck = loadCheck && load_image_2dMultiSample() == 0; + imageStore(image_2dArray, ivec3(0), ivec4(0)); + loadCheck = loadCheck && load_image_2dArray() == 0; + imageStore(image_3d, ivec3(0), ivec4(0)); + loadCheck = loadCheck && load_image_3d() == 0; + imageStore(image_cube, ivec3(0), ivec4(0)); + loadCheck = loadCheck && load_image_cube() == 0; + imageStore(image_cubeArray, ivec3(0), ivec4(0)); + loadCheck = loadCheck && load_image_cubeArray() == 0; + imageStore(image_2dMultiSampleArray, ivec3(0), 1, ivec4(0)); + loadCheck = loadCheck && load_image_2dMultiSampleArray() == 0; + resetAllImageValues(); + return loadCheck; +} +bool checkAllImageSamples() +{ + resetAllImageValues(); + return true + && imageSamples(image_2dMultiSample) == 2 + && imageSamples(image_2dMultiSampleArray) == 2 + ; +} +bool checkAllImageAtomicAdd() +{ + resetAllImageValues(); + return true + && imageAtomicAdd(image_1d, 0, 0) == 1 + && load_image_1d() == 1 + && imageAtomicAdd(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 + && imageAtomicAdd(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 1 + && imageAtomicAdd(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicAdd(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicAdd(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicAdd(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 1 + && imageAtomicAdd(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicAdd(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicAdd(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 + && imageAtomicAdd(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 + ; +} +bool checkAllImageAtomicExchange() +{ + resetAllImageValues(); + return true + && imageAtomicExchange(image_1d, 0, 0) == 1 + && load_image_1d() == 0 + && imageAtomicExchange(image_buffer, 0, 2) == 1 + && load_image_buffer() == 2 + && imageAtomicExchange(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 0 + && imageAtomicExchange(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 2 + && imageAtomicExchange(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicExchange(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicExchange(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 0 + && imageAtomicExchange(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 2 + && imageAtomicExchange(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 2 + && imageAtomicExchange(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 2 + && imageAtomicExchange(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 + ; +} +bool checkAllImageAtomicMin() +{ + resetAllImageValues(); + return true + && imageAtomicMin(image_1d, 0, 0) == 1 + && load_image_1d() == 0 + && imageAtomicMin(image_buffer, 0, 2) == 1 + && load_image_buffer() == 1 + && imageAtomicMin(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 0 + && imageAtomicMin(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 1 + && imageAtomicMin(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 1 + && imageAtomicMin(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 1 + && imageAtomicMin(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 0 + && imageAtomicMin(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 1 + && imageAtomicMin(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 1 + && imageAtomicMin(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 1 + && imageAtomicMin(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 1 + ; +} +bool checkAllImageAtomicMax() +{ + resetAllImageValues(); + return true + && imageAtomicMax(image_1d, 0, 0) == 1 + && load_image_1d() == 1 + && imageAtomicMax(image_buffer, 0, 2) == 1 + && load_image_buffer() == 2 + && imageAtomicMax(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 1 + && imageAtomicMax(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 2 + && imageAtomicMax(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicMax(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicMax(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 1 + && imageAtomicMax(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 2 + && imageAtomicMax(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 2 + && imageAtomicMax(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 2 + && imageAtomicMax(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 + ; +} +bool checkAllImageAtomicAnd() +{ + resetAllImageValues(); + return true + && imageAtomicAnd(image_1d, 0, 1) == 1 + && load_image_1d() == 1 + && imageAtomicAnd(image_buffer, 0, 2) == 1 + && load_image_buffer() == 0 + && imageAtomicAnd(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 1 + && imageAtomicAnd(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 0 + && imageAtomicAnd(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 0 + && imageAtomicAnd(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 0 + && imageAtomicAnd(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 1 + && imageAtomicAnd(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 0 + && imageAtomicAnd(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 0 + && imageAtomicAnd(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 0 + && imageAtomicAnd(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 0 + ; +} +bool checkAllImageAtomicOr() +{ + resetAllImageValues(); + return true + && imageAtomicOr(image_1d, 0, 1) == 1 + && load_image_1d() == 1 + && imageAtomicOr(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 + && imageAtomicOr(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 1 + && imageAtomicOr(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicOr(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicOr(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicOr(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 1 + && imageAtomicOr(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicOr(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicOr(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 + && imageAtomicOr(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 + ; +} +bool checkAllImageAtomicXor() +{ + resetAllImageValues(); + return true + && imageAtomicXor(image_1d, 0, 1) == 1 + && load_image_1d() == 0 + && imageAtomicXor(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 + && imageAtomicXor(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 0 + && imageAtomicXor(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicXor(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicXor(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicXor(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 0 + && imageAtomicXor(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicXor(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicXor(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 + && imageAtomicXor(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 + ; +} +bool checkAllImageAtomicCompSwap() +{ + resetAllImageValues(); + return true + && imageAtomicCompSwap(image_1d, 0, 0, 2) == 1 + && load_image_1d() == 1 + && imageAtomicCompSwap(image_buffer, 0, 1, 2) == 1 + && load_image_buffer() == 2 + && imageAtomicCompSwap(image_1dArray, ivec2(0), 0, 2) == 1 + && load_image_1dArray() == 1 + && imageAtomicCompSwap(image_2d, ivec2(0), 1, 2) == 1 + && load_image_2d() == 2 + && imageAtomicCompSwap(image_2dRect, ivec2(0), 1, 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicCompSwap(image_2dMultiSample, ivec2(0), 1, 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicCompSwap(image_2dArray, ivec3(0), 0, 2) == 1 + && load_image_2dArray() == 1 + && imageAtomicCompSwap(image_3d, ivec3(0), 1, 2) == 1 + && load_image_3d() == 2 + && imageAtomicCompSwap(image_cube, ivec3(0), 1, 2) == 1 + && load_image_cube() == 2 + && imageAtomicCompSwap(image_cubeArray, ivec3(0), 1, 2) == 1 + && load_image_cubeArray() == 2 + && imageAtomicCompSwap(image_2dMultiSampleArray, ivec3(0), 1, 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 + ; +} + +// CHECK_GLSL: void main( +// CHECK_SPV: OpEntryPoint +void computeMain() +{ + outputBuffer.data[0] = true + && checkAllImageSize() + && checkAllImageLoad() + && checkAllImageStore() + && checkAllImageSamples() + && checkAllImageAtomicAdd() + && checkAllImageAtomicExchange() + && checkAllImageAtomicMin() + && checkAllImageAtomicMax() + && checkAllImageAtomicAnd() + && checkAllImageAtomicOr() + && checkAllImageAtomicXor() + && checkAllImageAtomicCompSwap() + ; + // BUF: 1 +} diff --git a/tests/glsl-intrinsic/image/iimageDimTiny.slang b/tests/glsl-intrinsic/image/iimageDimTiny.slang new file mode 100644 index 000000000..28dca1bc3 --- /dev/null +++ b/tests/glsl-intrinsic/image/iimageDimTiny.slang @@ -0,0 +1,34 @@ +//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl +//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly + +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer +buffer MyBlockName2 +{ + uint data[1]; +} outputBuffer; + +layout(local_size_x = 1) in; + +//TEST_INPUT: set image_1d = RWTexture1D(format=R32_SINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=0,r32i) iimage1D image_1d; + +bool checkAllImageAtomicAdd() +{ + imageStore(image_1d, 0, ivec4(1)); + return true + && imageAtomicAdd(image_1d, 0, 0) == 1 + && imageLoad(image_1d, 0).x == 1 + ; +} + +// CHECK_GLSL: void main( +// CHECK_SPV: OpEntryPoint +void computeMain() +{ + outputBuffer.data[0] = true + && checkAllImageAtomicAdd() + ; + // BUF: 1 +} diff --git a/tests/glsl-intrinsic/image/imageAsParamWithMemoryQualifiers.slang b/tests/glsl-intrinsic/image/imageAsParamWithMemoryQualifiers.slang new file mode 100644 index 000000000..4766cb66f --- /dev/null +++ b/tests/glsl-intrinsic/image/imageAsParamWithMemoryQualifiers.slang @@ -0,0 +1,43 @@ +//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl +//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly + +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer +buffer MyBlockName2 +{ + uint data[1]; +} outputBuffer; + +layout(local_size_x = 4) in; + +//TEST_INPUT: set someImage = RWTexture2D(format=R16G16B16A16_FLOAT, size=1, content=one, mipMaps = 1) +uniform layout(binding=0,rgba16f) writeonly readonly image2D someImage; + +//TEST_INPUT: set someImage2 = RWTexture2D(format=R16G16B16A16_FLOAT, size=1, content=one, mipMaps = 1) +uniform layout(binding=1,rgba16f) writeonly image2D someImage2; + +bool checkAllImageSizesParamSameQualifiers(writeonly readonly image2D val) +{ + return true + && imageSize(val) == ivec2(1) + ; +} +bool checkAllImageSizesParamMoreQualifiers(readonly writeonly image2D val) +{ + return true + && imageSize(val) == ivec2(1) + ; +} + +// CHECK_GLSL: void main( +// CHECK_SPV: OpEntryPoint +void computeMain() +{ + outputBuffer.data[0] = true + && checkAllImageSizesParamSameQualifiers(someImage) + && checkAllImageSizesParamMoreQualifiers(someImage2) + ; + // BUF: 1 + +}
\ No newline at end of file diff --git a/tests/glsl-intrinsic/image/imageAsParamWithMemoryQualifiersError.slang b/tests/glsl-intrinsic/image/imageAsParamWithMemoryQualifiersError.slang new file mode 100644 index 000000000..cab9be395 --- /dev/null +++ b/tests/glsl-intrinsic/image/imageAsParamWithMemoryQualifiersError.slang @@ -0,0 +1,27 @@ +//TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target glsl +//TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer +buffer MyBlockName2 +{ + uint data[1]; +} outputBuffer; + +layout(local_size_x = 4) in; + +//TEST_INPUT: set someImage = RWTexture2D(format=R16G16B16A16_FLOAT, size=1, content=one, mipMaps = 1) +uniform layout(binding=0,rgba16f) readonly image2D someImage; + +// CHECK: error 30048 +bool checkAllImageSizes(writeonly image2D val) +{ + return true + && imageSize(val) == ivec2(1) + ; +} + +void computeMain() +{ + outputBuffer.data[0] = true + && checkAllImageSizes(someImage); + ; +}
\ No newline at end of file diff --git a/tests/glsl-intrinsic/image/imageDim.slang b/tests/glsl-intrinsic/image/imageDim.slang new file mode 100644 index 000000000..4699bc2ac --- /dev/null +++ b/tests/glsl-intrinsic/image/imageDim.slang @@ -0,0 +1,303 @@ +//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl +//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly + +// shader_atomic_float2 is currently a very new extension; most hardware lacks +// this extension and will fail this test if attempting to use atomic_float2 +// operations. +// #define TEST_when_shader_atomic_float2_is_available + +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer +buffer MyBlockName2 +{ + uint data[1]; +} outputBuffer; + +layout(local_size_x = 1) in; + +//TEST_INPUT: set image_1d = RWTexture1D(format=R32_FLOAT, size=4, content=one, mipMaps = 1) +uniform layout(binding=0,r32f) image1D image_1d; +//TEST_INPUT: set image_buffer = RWTextureBuffer(format=R32_FLOAT, stride=4, data=[1.0f 1.0f 1.0f 1.0f]) +uniform layout(binding=1,r32f) imageBuffer image_buffer; +//TEST_INPUT: set image_1dArray = RWTexture1D(format=R32_FLOAT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=2,r32f) image1DArray image_1dArray; +//TEST_INPUT: set image_2d = RWTexture2D(format=R32_FLOAT, size=4, content=one, mipMaps = 1) +uniform layout(binding=3,r32f) image2D image_2d; +//TEST_INPUT: set image_2dRect = RWTexture2D(format=R32_FLOAT, size=4, content=one, mipMaps = 1) +uniform layout(binding=4,r32f) image2DRect image_2dRect; +//TEST_INPUT: set image_2dMultiSample = RWTexture2D(format=R32_FLOAT, size=4, content=one, mipMaps = 1, sampleCount = two) +uniform layout(binding=5,r32f) image2DMS image_2dMultiSample; +//TEST_INPUT: set image_2dArray = RWTexture2D(format=R32_FLOAT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=6,r32f) image2DArray image_2dArray; +//TEST_INPUT: set image_3d = RWTexture3D(format=R32_FLOAT, size=4, content=one, mipMaps = 1) +uniform layout(binding=7,r32f) image3D image_3d; +//TEST_INPUT: set image_cube = RWTextureCube(format=R32_FLOAT, size=4, content=one, mipMaps = 1) +uniform layout(binding=8,r32f) imageCube image_cube; +//TEST_INPUT: set image_cubeArray = RWTextureCube(format=R32_FLOAT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=9,r32f) imageCubeArray image_cubeArray; +//TEST_INPUT: set image_2dMultiSampleArray = RWTexture2D(format=R32_FLOAT, size=4, content=one, mipMaps = 1, arrayLength=2, sampleCount = two) +uniform layout(binding=10,r32f) image2DMSArray image_2dMultiSampleArray; + +bool checkAllImageSize() +{ + return true + && imageSize(image_1d) == int(4) + && imageSize(image_buffer) == int(4) + && imageSize(image_1dArray) == ivec2(4, 2) + && imageSize(image_2d) == ivec2(4) + && imageSize(image_2dArray) == ivec3(4, 4, 2) + && imageSize(image_2dRect) == ivec2(4) + && imageSize(image_2dMultiSample) == ivec2(4) + && imageSize(image_3d) == ivec3(4) + && imageSize(image_cube) == ivec2(4) + && imageSize(image_cubeArray) == ivec3(4, 4, 2) + && imageSize(image_2dMultiSampleArray) == ivec3(4, 4, 2) + ; +} +bool checkAllImageLoad() +{ + return true + && imageLoad(image_1d, 0).x == 1 + && imageLoad(image_buffer, 0).x == 1 + && imageLoad(image_1dArray, ivec2(0)).x == 1 + && imageLoad(image_2d, ivec2(0)).x == 1 + && imageLoad(image_2dRect, ivec2(0)).x == 1 + && imageLoad(image_2dMultiSample, ivec2(0), 1).x == 1 + && imageLoad(image_2dArray, ivec3(0)).x == 1 + && imageLoad(image_3d, ivec3(0)).x == 1 + && imageLoad(image_cube, ivec3(0)).x == 1 + && imageLoad(image_cubeArray, ivec3(0)).x == 1 + && imageLoad(image_cubeArray, ivec3(0)).x == 1 + && imageLoad(image_2dMultiSampleArray, ivec3(0), 1).x == 1 + ; +} +bool resetAllImageValues() +{ + imageStore(image_1d, 0, vec4(1)); + imageStore(image_buffer, 0, vec4(1)); + imageStore(image_1dArray, ivec2(0), vec4(1)); + imageStore(image_2d, ivec2(0), vec4(1)); + imageStore(image_2dRect, ivec2(0), vec4(1)); + imageStore(image_2dMultiSample, ivec2(0), 1, vec4(1)); + imageStore(image_2dArray, ivec3(0), vec4(1)); + imageStore(image_3d, ivec3(0), vec4(1)); + imageStore(image_cube, ivec3(0), vec4(1)); + imageStore(image_cubeArray, ivec3(0), vec4(1)); + imageStore(image_2dMultiSampleArray, ivec3(0), 1, vec4(1)); + return true; +} +float load_image_1d() +{ + return imageLoad(image_1d, 0).x; +} +float load_image_buffer() +{ + return imageLoad(image_buffer, 0).x; +} +float load_image_1dArray() +{ + return imageLoad(image_1dArray, ivec2(0)).x; +} +float load_image_2d() +{ + return imageLoad(image_2d, ivec2(0)).x; +} +float load_image_2dRect() +{ + return imageLoad(image_2dRect, ivec2(0)).x; +} +float load_image_2dMultiSample() +{ + return imageLoad(image_2dMultiSample, ivec2(0), 1).x; +} +float load_image_2dArray() +{ + return imageLoad(image_2dArray, ivec3(0)).x; +} +float load_image_3d() +{ + return imageLoad(image_3d, ivec3(0)).x; +} +float load_image_cube() +{ + return imageLoad(image_cube, ivec3(0)).x; +} +float load_image_cubeArray() +{ + return imageLoad(image_cubeArray, ivec3(0)).x; +} +float load_image_2dMultiSampleArray() +{ + return imageLoad(image_2dMultiSampleArray, ivec3(0), 1).x; +} +// requires ImageLoad test to pass +bool checkAllImageStore() +{ + bool loadCheck = true; + imageStore(image_1d, 0, vec4(0)); + loadCheck = loadCheck && load_image_1d() == 0; + imageStore(image_buffer, 0, vec4(0)); + loadCheck = loadCheck && load_image_buffer() == 0; + imageStore(image_1dArray, ivec2(0), vec4(0)); + loadCheck = loadCheck && load_image_1dArray() == 0; + imageStore(image_2d, ivec2(0), vec4(0)); + loadCheck = loadCheck && load_image_2d() == 0; + imageStore(image_2dRect, ivec2(0), vec4(0)); + loadCheck = loadCheck && load_image_2dRect() == 0; + imageStore(image_2dMultiSample, ivec2(0), 1, vec4(0)); + loadCheck = loadCheck && load_image_2dMultiSample() == 0; + imageStore(image_2dArray, ivec3(0), vec4(0)); + loadCheck = loadCheck && load_image_2dArray() == 0; + imageStore(image_3d, ivec3(0), vec4(0)); + loadCheck = loadCheck && load_image_3d() == 0; + imageStore(image_cube, ivec3(0), vec4(0)); + loadCheck = loadCheck && load_image_cube() == 0; + imageStore(image_cubeArray, ivec3(0), vec4(0)); + loadCheck = loadCheck && load_image_cubeArray() == 0; + imageStore(image_2dMultiSampleArray, ivec3(0), 1, vec4(0)); + loadCheck = loadCheck && load_image_2dMultiSampleArray() == 0; + resetAllImageValues(); + return loadCheck; +} +bool checkAllImageSamples() +{ + resetAllImageValues(); + return true + && imageSamples(image_2dMultiSample) == 2 + && imageSamples(image_2dMultiSampleArray) == 2 + ; +} +bool checkAllImageAtomicAdd() +{ + resetAllImageValues(); + return true + && imageAtomicAdd(image_1d, 0, 0.0f) == 1 + && load_image_1d() == 1 + && imageAtomicAdd(image_buffer, 0, 2.0f) == 1 + && load_image_buffer() == 3 + && imageAtomicAdd(image_1dArray, ivec2(0), 0.0f) == 1 + && load_image_1dArray() == 1 + && imageAtomicAdd(image_2d, ivec2(0), 2.0f) == 1 + && load_image_2d() == 3 + && imageAtomicAdd(image_2dRect, ivec2(0), 2.0f) == 1 + && load_image_2dRect() == 3 + && imageAtomicAdd(image_2dMultiSample, ivec2(0), 1, 2.0f) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicAdd(image_2dArray, ivec3(0), 0.0f) == 1 + && load_image_2dArray() == 1 + && imageAtomicAdd(image_3d, ivec3(0), 2.0f) == 1 + && load_image_3d() == 3 + && imageAtomicAdd(image_cube, ivec3(0), 2.0f) == 1 + && load_image_cube() == 3 + && imageAtomicAdd(image_cubeArray, ivec3(0), 2.0f) == 1 + && load_image_cubeArray() == 3 + && imageAtomicAdd(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 + ; +} +bool checkAllImageAtomicExchange() +{ + resetAllImageValues(); + return true + && imageAtomicExchange(image_1d, 0, 0.0f) == 1 + && load_image_1d() == 0 + && imageAtomicExchange(image_buffer, 0, 2.0f) == 1 + && load_image_buffer() == 2 + && imageAtomicExchange(image_1dArray, ivec2(0), 0.0f) == 1 + && load_image_1dArray() == 0 + && imageAtomicExchange(image_2d, ivec2(0), 2.0f) == 1 + && load_image_2d() == 2 + && imageAtomicExchange(image_2dRect, ivec2(0), 2.0f) == 1 + && load_image_2dRect() == 2 + && imageAtomicExchange(image_2dMultiSample, ivec2(0), 1, 2.0f) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicExchange(image_2dArray, ivec3(0), 0.0f) == 1 + && load_image_2dArray() == 0 + && imageAtomicExchange(image_3d, ivec3(0), 2.0f) == 1 + && load_image_3d() == 2 + && imageAtomicExchange(image_cube, ivec3(0), 2.0f) == 1 + && load_image_cube() == 2 + && imageAtomicExchange(image_cubeArray, ivec3(0), 2.0f) == 1 + && load_image_cubeArray() == 2 + && imageAtomicExchange(image_2dMultiSampleArray, ivec3(0), 1, 2.0f) == 1 + && load_image_2dMultiSampleArray() == 2 + ; +} +#ifdef TEST_when_shader_atomic_float2_is_available +bool checkAllImageAtomicMin() +{ + resetAllImageValues(); + return true + && imageAtomicMin(image_1d, 0, 0.0f) == 1 + && load_image_1d() == 0 + && imageAtomicMin(image_buffer, 0, 2.0f) == 1 + && load_image_buffer() == 1 + && imageAtomicMin(image_1dArray, ivec2(0), 0.0f) == 1 + && load_image_1dArray() == 0 + && imageAtomicMin(image_2d, ivec2(0), 2.0f) == 1 + && load_image_2d() == 1 + && imageAtomicMin(image_2dRect, ivec2(0), 2.0f) == 1 + && load_image_2dRect() == 1 + && imageAtomicMin(image_2dMultiSample, ivec2(0), 1, 2.0f) == 1 + && load_image_2dMultiSample() == 1 + && imageAtomicMin(image_2dArray, ivec3(0), 0.0f) == 1 + && load_image_2dArray() == 0 + && imageAtomicMin(image_3d, ivec3(0), 2.0f) == 1 + && load_image_3d() == 1 + && imageAtomicMin(image_cube, ivec3(0), 2.0f) == 1 + && load_image_cube() == 1 + && imageAtomicMin(image_cubeArray, ivec3(0), 2.0f) == 1 + && load_image_cubeArray() == 1 + && imageAtomicMin(image_2dMultiSampleArray, ivec3(0), 1, 2.0f) == 1 + && load_image_2dMultiSampleArray() == 1 + ; +} +bool checkAllImageAtomicMax() +{ + resetAllImageValues(); + return true + && imageAtomicMax(image_1d, 0, 0) == 1 + && load_image_1d() == 1 + && imageAtomicMax(image_buffer, 0, 2) == 1 + && load_image_buffer() == 2 + && imageAtomicMax(image_1dArray, ivec2(0), 0.0f) == 1 + && load_image_1dArray() == 1 + && imageAtomicMax(image_2d, ivec2(0), 2.0f) == 1 + && load_image_2d() == 2 + && imageAtomicMax(image_2dRect, ivec2(0), 2.0f) == 1 + && load_image_2dRect() == 2 + && imageAtomicMax(image_2dMultiSample, ivec2(0), 1, 2.0f) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicMax(image_2dArray, ivec3(0), 0.0f) == 1 + && load_image_2dArray() == 1 + && imageAtomicMax(image_3d, ivec3(0), 2.0f) == 1 + && load_image_3d() == 2 + && imageAtomicMax(image_cube, ivec3(0), 2.0f) == 1 + && load_image_cube() == 2 + && imageAtomicMax(image_cubeArray, ivec3(0), 2.0f) == 1 + && load_image_cubeArray() == 2 + && imageAtomicMax(image_2dMultiSampleArray, ivec3(0), 1, 2.0f) == 1 + && load_image_2dMultiSampleArray() == 2 + ; +} +#endif // #ifdef TEST_when_shader_atomic_float2_is_available + +// CHECK_GLSL: void main( +// CHECK_SPV: OpEntryPoint +void computeMain() +{ + outputBuffer.data[0] = true + && checkAllImageSize() + && checkAllImageLoad() + && checkAllImageStore() + && checkAllImageSamples() + && checkAllImageAtomicAdd() + && checkAllImageAtomicExchange() +#ifdef TEST_when_shader_atomic_float2_is_available + && checkAllImageAtomicMin() + && checkAllImageAtomicMax() +#endif // #ifdef TEST_when_shader_atomic_float2_is_available + ; + // BUF: 1 +}
\ No newline at end of file diff --git a/tests/glsl-intrinsic/image/nonImageAsParamWithMemoryQualifierError.slang b/tests/glsl-intrinsic/image/nonImageAsParamWithMemoryQualifierError.slang new file mode 100644 index 000000000..1248020d4 --- /dev/null +++ b/tests/glsl-intrinsic/image/nonImageAsParamWithMemoryQualifierError.slang @@ -0,0 +1,26 @@ +//TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target glsl +//TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer + +// restrict modifier is allowed to be dropped as a parameter +buffer MyBlockName2 +{ + restrict uint data[1]; +} outputBuffer; + +layout(local_size_x = 4) in; + +// CHECK: error 31206 +bool checkAllImageSizes(writeonly uint val) +{ + return true + && val == 0 + ; +} + +void computeMain() +{ + outputBuffer.data[0] = true + && checkAllImageSizes(outputBuffer.data[0]) + ; +}
\ No newline at end of file diff --git a/tests/glsl-intrinsic/image/u64imageDim.slang b/tests/glsl-intrinsic/image/u64imageDim.slang new file mode 100644 index 000000000..ebcfd0796 --- /dev/null +++ b/tests/glsl-intrinsic/image/u64imageDim.slang @@ -0,0 +1,476 @@ +//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl +//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly + +// As per vulkan specification: https://registry.khronos.org/vulkan/specs/1.3/html/chap34.html#formats-definition +// i64/u64 images do not require sampled image support; support is currently unlikley on hardware +//#define test_when_hardware_supports_i64_and_u64_sampled_textures +// i64/u64 images do not require texel buffers support; support is currently unlikley on hardware +//#define TEST_when_hardware_supports_i64_and_u64_buffers + +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer +buffer MyBlockName2 +{ + uint data[1]; +} outputBuffer; + +layout(local_size_x = 1) in; + +//TEST_INPUT: set image_1d = RWTexture1D(format=R64_UINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=0,r64ui) u64image1D image_1d; +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers +//COM:TEST_INPUT: set image_buffer = RWTextureBuffer(format=R64_UINT, stride=8, data=[0 1 0 1 0 1 0 1]) +uniform layout(binding=1,r64ui) u64imageBuffer image_buffer; +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers +//TEST_INPUT: set image_1dArray = RWTexture1D(format=R64_UINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=2,r64ui) u64image1DArray image_1dArray; +//TEST_INPUT: set image_2d = RWTexture2D(format=R64_UINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=3,r64ui) u64image2D image_2d; +//TEST_INPUT: set image_2dRect = RWTexture2D(format=R64_UINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=4,r64ui) u64image2DRect image_2dRect; +//TEST_INPUT: set image_2dArray = RWTexture2D(format=R64_UINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=6,r64ui) u64image2DArray image_2dArray; +//TEST_INPUT: set image_3d = RWTexture3D(format=R64_UINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=7,r64ui) u64image3D image_3d; +//TEST_INPUT: set image_cube = RWTextureCube(format=R64_UINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=8,r64ui) u64imageCube image_cube; +//TEST_INPUT: set image_cubeArray = RWTextureCube(format=R64_UINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=9,r64ui) u64imageCubeArray image_cubeArray; +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures +//COM:TEST_INPUT: set image_2dMultiSample = RWTexture2D(format=R64_UINT, size=4, content=one, mipMaps = 1, sampleCount = two) +uniform layout(binding=5,r64ui) u64image2DMS image_2dMultiSample; +//COM:TEST_INPUT: set image_2dMultiSampleArray = RWTexture2D(format=R64_UINT, size=4, content=one, mipMaps = 1, arrayLength=2, sampleCount = two) +uniform layout(binding=10,r64ui) u64image2DMSArray image_2dMultiSampleArray; +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + +bool checkAllImageSize() +{ + return true + && imageSize(image_1d) == int(4) +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageSize(image_buffer) == int(4) +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageSize(image_1dArray) == ivec2(4, 2) + && imageSize(image_2d) == ivec2(4) + && imageSize(image_2dArray) == ivec3(4, 4, 2) + && imageSize(image_2dRect) == ivec2(4) + && imageSize(image_3d) == ivec3(4) + && imageSize(image_cube) == ivec2(4) + && imageSize(image_cubeArray) == ivec3(4, 4, 2) +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageSize(image_2dMultiSample) == ivec2(4) + && imageSize(image_2dMultiSampleArray) == ivec3(4, 4, 2) +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageLoad() +{ + return true + && imageLoad(image_1d, 0).x == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageLoad(image_buffer, 0).x == 1 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageLoad(image_1dArray, ivec2(0)).x == 1 + && imageLoad(image_2d, ivec2(0)).x == 1 + && imageLoad(image_2dRect, ivec2(0)).x == 1 + && imageLoad(image_2dArray, ivec3(0)).x == 1 + && imageLoad(image_3d, ivec3(0)).x == 1 + && imageLoad(image_cube, ivec3(0)).x == 1 + && imageLoad(image_cubeArray, ivec3(0)).x == 1 + && imageLoad(image_cubeArray, ivec3(0)).x == 1 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageLoad(image_2dMultiSample, ivec2(0), 1).x == 1 + && imageLoad(image_2dMultiSampleArray, ivec3(0), 1).x == 1 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool resetAllImageValues() +{ + imageStore(image_1d, 0,u64vec4(1)); +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + imageStore(image_buffer, 0,u64vec4(1)); +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + imageStore(image_1dArray, ivec2(0),u64vec4(1)); + imageStore(image_2d, ivec2(0),u64vec4(1)); + imageStore(image_2dRect, ivec2(0),u64vec4(1)); + imageStore(image_2dArray, ivec3(0),u64vec4(1)); + imageStore(image_3d, ivec3(0),u64vec4(1)); + imageStore(image_cube, ivec3(0),u64vec4(1)); + imageStore(image_cubeArray, ivec3(0),u64vec4(1)); +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + imageStore(image_2dMultiSample, ivec2(0), 1, u64vec4(1)); + imageStore(image_2dMultiSampleArray, ivec3(0), 1,u64vec4(1)); +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + return true; +} +uint64_t load_image_1d() +{ + return imageLoad(image_1d, 0).x; +} +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers +uint64_t load_image_buffer() +{ + return imageLoad(image_buffer, 0).x; +} +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers +uint64_t load_image_1dArray() +{ + return imageLoad(image_1dArray, ivec2(0)).x; +} +uint64_t load_image_2d() +{ + return imageLoad(image_2d, ivec2(0)).x; +} +uint64_t load_image_2dRect() +{ + return imageLoad(image_2dRect, ivec2(0)).x; +} +uint64_t load_image_2dArray() +{ + return imageLoad(image_2dArray, ivec3(0)).x; +} +uint64_t load_image_3d() +{ + return imageLoad(image_3d, ivec3(0)).x; +} +uint64_t load_image_cube() +{ + return imageLoad(image_cube, ivec3(0)).x; +} +uint64_t load_image_cubeArray() +{ + return imageLoad(image_cubeArray, ivec3(0)).x; +} +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures +uint64_t load_image_2dMultiSample() +{ + return imageLoad(image_2dMultiSample, ivec2(0), 1).x; +} +uint64_t load_image_2dMultiSampleArray() +{ + return imageLoad(image_2dMultiSampleArray, ivec3(0), 1).x; +} +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + +// requires ImageLoad test to pass +bool checkAllImageStore() +{ + bool loadCheck = true; + + imageStore(image_1d, 0,u64vec4(0)); + loadCheck = loadCheck && load_image_1d() == 0; +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + imageStore(image_buffer, 0,u64vec4(0)); + loadCheck = loadCheck && load_image_buffer() == 0; +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + imageStore(image_1dArray, ivec2(0),u64vec4(0)); + loadCheck = loadCheck && load_image_1dArray() == 0; + imageStore(image_2d, ivec2(0),u64vec4(0)); + loadCheck = loadCheck && load_image_2d() == 0; + imageStore(image_2dRect, ivec2(0),u64vec4(0)); + loadCheck = loadCheck && load_image_2dRect() == 0; + imageStore(image_2dArray, ivec3(0),u64vec4(0)); + loadCheck = loadCheck && load_image_2dArray() == 0; + imageStore(image_3d, ivec3(0),u64vec4(0)); + loadCheck = loadCheck && load_image_3d() == 0; + imageStore(image_cube, ivec3(0),u64vec4(0)); + loadCheck = loadCheck && load_image_cube() == 0; + imageStore(image_cubeArray, ivec3(0),u64vec4(0)); + loadCheck = loadCheck && load_image_cubeArray() == 0; +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + imageStore(image_2dMultiSample, ivec2(0), 1, u64vec4(0)); + loadCheck = loadCheck && load_image_2dMultiSample() == 0; + imageStore(image_2dMultiSampleArray, ivec3(0), 1,u64vec4(0)); + loadCheck = loadCheck && load_image_2dMultiSampleArray() == 0; +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + resetAllImageValues(); + return loadCheck; +} +bool checkAllImageSamples() +{ + resetAllImageValues(); + return true +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageSamples(image_2dMultiSample) == 2 + && imageSamples(image_2dMultiSampleArray) == 2 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicAdd() +{ + resetAllImageValues(); + return true + && imageAtomicAdd(image_1d, 0, 0) == 1 + && load_image_1d() == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicAdd(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicAdd(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 1 + && imageAtomicAdd(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicAdd(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicAdd(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 1 + && imageAtomicAdd(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicAdd(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicAdd(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicAdd(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicAdd(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicExchange() +{ + resetAllImageValues(); + return true + && imageAtomicExchange(image_1d, 0, 0) == 1 + && load_image_1d() == 0 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicExchange(image_buffer, 0, 2) == 1 + && load_image_buffer() == 2 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicExchange(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 0 + && imageAtomicExchange(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 2 + && imageAtomicExchange(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicExchange(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 0 + && imageAtomicExchange(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 2 + && imageAtomicExchange(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 2 + && imageAtomicExchange(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 2 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicExchange(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicExchange(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicMin() +{ + resetAllImageValues(); + return true + && imageAtomicMin(image_1d, 0, 0) == 1 + && load_image_1d() == 0 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicMin(image_buffer, 0, 2) == 1 + && load_image_buffer() == 1 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicMin(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 0 + && imageAtomicMin(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 1 + && imageAtomicMin(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 1 + && imageAtomicMin(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 0 + && imageAtomicMin(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 1 + && imageAtomicMin(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 1 + && imageAtomicMin(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 1 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicMin(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 1 + && imageAtomicMin(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 1 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicMax() +{ + resetAllImageValues(); + return true + && imageAtomicMax(image_1d, 0, 0) == 1 + && load_image_1d() == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicMax(image_buffer, 0, 2) == 1 + && load_image_buffer() == 2 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicMax(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 1 + && imageAtomicMax(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 2 + && imageAtomicMax(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicMax(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 1 + && imageAtomicMax(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 2 + && imageAtomicMax(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 2 + && imageAtomicMax(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 2 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicMax(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicMax(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicAnd() +{ + resetAllImageValues(); + return true + && imageAtomicAnd(image_1d, 0, 1) == 1 + && load_image_1d() == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicAnd(image_buffer, 0, 2) == 1 + && load_image_buffer() == 0 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicAnd(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 1 + && imageAtomicAnd(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 0 + && imageAtomicAnd(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 0 + && imageAtomicAnd(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 1 + && imageAtomicAnd(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 0 + && imageAtomicAnd(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 0 + && imageAtomicAnd(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 0 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicAnd(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 0 + && imageAtomicAnd(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 0 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicOr() +{ + resetAllImageValues(); + return true + && imageAtomicOr(image_1d, 0, 1) == 1 + && load_image_1d() == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicOr(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicOr(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 1 + && imageAtomicOr(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicOr(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicOr(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 1 + && imageAtomicOr(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicOr(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicOr(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicOr(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicOr(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicXor() +{ + resetAllImageValues(); + return true + && imageAtomicXor(image_1d, 0, 1) == 1 + && load_image_1d() == 0 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicXor(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicXor(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 0 + && imageAtomicXor(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicXor(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicXor(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 0 + && imageAtomicXor(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicXor(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicXor(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicXor(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicXor(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} +bool checkAllImageAtomicCompSwap() +{ + resetAllImageValues(); + return true + && imageAtomicCompSwap(image_1d, 0, 0, 2) == 1 + && load_image_1d() == 1 +#ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicCompSwap(image_buffer, 0, 1, 2) == 1 + && load_image_buffer() == 2 +#endif // #ifdef TEST_when_hardware_supports_i64_and_u64_buffers + && imageAtomicCompSwap(image_1dArray, ivec2(0), 0, 2) == 1 + && load_image_1dArray() == 1 + && imageAtomicCompSwap(image_2d, ivec2(0), 1, 2) == 1 + && load_image_2d() == 2 + && imageAtomicCompSwap(image_2dRect, ivec2(0), 1, 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicCompSwap(image_2dArray, ivec3(0), 0, 2) == 1 + && load_image_2dArray() == 1 + && imageAtomicCompSwap(image_3d, ivec3(0), 1, 2) == 1 + && load_image_3d() == 2 + && imageAtomicCompSwap(image_cube, ivec3(0), 1, 2) == 1 + && load_image_cube() == 2 + && imageAtomicCompSwap(image_cubeArray, ivec3(0), 1, 2) == 1 + && load_image_cubeArray() == 2 +#ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + && imageAtomicCompSwap(image_2dMultiSample, ivec2(0), 1, 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicCompSwap(image_2dMultiSampleArray, ivec3(0), 1, 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 +#endif // #ifdef test_when_hardware_supports_i64_and_u64_sampled_textures + ; +} + +// CHECK_GLSL: void main( +// CHECK_SPV: OpEntryPoint +void computeMain() +{ + outputBuffer.data[0] = true + && checkAllImageSize() + && checkAllImageLoad() + && checkAllImageStore() + && checkAllImageSamples() + && checkAllImageAtomicAdd() + && checkAllImageAtomicExchange() + && checkAllImageAtomicMin() + && checkAllImageAtomicMax() + && checkAllImageAtomicAnd() + && checkAllImageAtomicOr() + && checkAllImageAtomicXor() + && checkAllImageAtomicCompSwap() + ; + // BUF: 1 +}
\ No newline at end of file diff --git a/tests/glsl-intrinsic/image/uimageDim.slang b/tests/glsl-intrinsic/image/uimageDim.slang new file mode 100644 index 000000000..538855b7d --- /dev/null +++ b/tests/glsl-intrinsic/image/uimageDim.slang @@ -0,0 +1,410 @@ +//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl +//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly + +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer +buffer MyBlockName2 +{ + uint data[1]; +} outputBuffer; + +layout(local_size_x = 1) in; + +//TEST_INPUT: set image_1d = RWTexture1D(format=R32_UINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=0,r32ui) uimage1D image_1d; +//TEST_INPUT: set image_buffer = RWTextureBuffer(format=R32_UINT, stride=8, data=[1 1 1 1]) +uniform layout(binding=1,r32ui) uimageBuffer image_buffer; +//TEST_INPUT: set image_1dArray = RWTexture1D(format=R32_UINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=2,r32ui) uimage1DArray image_1dArray; +//TEST_INPUT: set image_2d = RWTexture2D(format=R32_UINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=3,r32ui) uimage2D image_2d; +//TEST_INPUT: set image_2dRect = RWTexture2D(format=R32_UINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=4,r32ui) uimage2DRect image_2dRect; +//TEST_INPUT: set image_2dMultiSample = RWTexture2D(format=R32_UINT, size=4, content=one, mipMaps = 1, sampleCount = two) +uniform layout(binding=5,r32ui) uimage2DMS image_2dMultiSample; +//TEST_INPUT: set image_2dArray = RWTexture2D(format=R32_UINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=6,r32ui) uimage2DArray image_2dArray; +//TEST_INPUT: set image_3d = RWTexture3D(format=R32_UINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=7,r32ui) uimage3D image_3d; +//TEST_INPUT: set image_cube = RWTextureCube(format=R32_UINT, size=4, content=one, mipMaps = 1) +uniform layout(binding=8,r32ui) uimageCube image_cube; +//TEST_INPUT: set image_cubeArray = RWTextureCube(format=R32_UINT, size=4, content=one, mipMaps = 1, arrayLength=2) +uniform layout(binding=9,r32ui) uimageCubeArray image_cubeArray; +//TEST_INPUT: set image_2dMultiSampleArray = RWTexture2D(format=R32_UINT, size=4, content=one, mipMaps = 1, arrayLength=2, sampleCount = two) +uniform layout(binding=10,r32ui) uimage2DMSArray image_2dMultiSampleArray; + +bool checkAllImageSize() +{ + return true + && imageSize(image_1d) == int(4) + && imageSize(image_buffer) == int(4) + && imageSize(image_1dArray) == ivec2(4, 2) + && imageSize(image_2d) == ivec2(4) + && imageSize(image_2dArray) == ivec3(4, 4, 2) + && imageSize(image_2dRect) == ivec2(4) + && imageSize(image_2dMultiSample) == ivec2(4) + && imageSize(image_3d) == ivec3(4) + && imageSize(image_cube) == ivec2(4) + && imageSize(image_cubeArray) == ivec3(4, 4, 2) + && imageSize(image_2dMultiSampleArray) == ivec3(4, 4, 2) + ; +} +bool checkAllImageLoad() +{ + return true + && imageLoad(image_1d, 0).x == 1 + && imageLoad(image_buffer, 0).x == 1 + && imageLoad(image_1dArray, ivec2(0)).x == 1 + && imageLoad(image_2d, ivec2(0)).x == 1 + && imageLoad(image_2dRect, ivec2(0)).x == 1 + && imageLoad(image_2dMultiSample, ivec2(0), 1).x == 1 + && imageLoad(image_2dArray, ivec3(0)).x == 1 + && imageLoad(image_3d, ivec3(0)).x == 1 + && imageLoad(image_cube, ivec3(0)).x == 1 + && imageLoad(image_cubeArray, ivec3(0)).x == 1 + && imageLoad(image_cubeArray, ivec3(0)).x == 1 + && imageLoad(image_2dMultiSampleArray, ivec3(0), 1).x == 1 + ; +} +bool resetAllImageValues() +{ + imageStore(image_1d, 0, uvec4(1)); + imageStore(image_buffer, 0, uvec4(1)); + imageStore(image_1dArray, ivec2(0), uvec4(1)); + imageStore(image_2d, ivec2(0), uvec4(1)); + imageStore(image_2dRect, ivec2(0), uvec4(1)); + imageStore(image_2dMultiSample, ivec2(0), 1, uvec4(1)); + imageStore(image_2dArray, ivec3(0), uvec4(1)); + imageStore(image_3d, ivec3(0), uvec4(1)); + imageStore(image_cube, ivec3(0), uvec4(1)); + imageStore(image_cubeArray, ivec3(0), uvec4(1)); + imageStore(image_2dMultiSampleArray, ivec3(0), 1, uvec4(1)); + return true; +} +uint load_image_1d() +{ + return imageLoad(image_1d, 0).x; +} +uint load_image_buffer() +{ + return imageLoad(image_buffer, 0).x; +} +uint load_image_1dArray() +{ + return imageLoad(image_1dArray, ivec2(0)).x; +} +uint load_image_2d() +{ + return imageLoad(image_2d, ivec2(0)).x; +} +uint load_image_2dRect() +{ + return imageLoad(image_2dRect, ivec2(0)).x; +} +uint load_image_2dMultiSample() +{ + return imageLoad(image_2dMultiSample, ivec2(0), 1).x; +} +uint load_image_2dArray() +{ + return imageLoad(image_2dArray, ivec3(0)).x; +} +uint load_image_3d() +{ + return imageLoad(image_3d, ivec3(0)).x; +} +uint load_image_cube() +{ + return imageLoad(image_cube, ivec3(0)).x; +} +uint load_image_cubeArray() +{ + return imageLoad(image_cubeArray, ivec3(0)).x; +} +uint load_image_2dMultiSampleArray() +{ + return imageLoad(image_2dMultiSampleArray, ivec3(0), 1).x; +} +// requires ImageLoad test to pass +bool checkAllImageStore() +{ + bool loadCheck = true; + imageStore(image_1d, 0, uvec4(0)); + loadCheck = loadCheck && load_image_1d() == 0; + imageStore(image_buffer, 0, uvec4(0)); + loadCheck = loadCheck && load_image_buffer() == 0; + imageStore(image_1dArray, ivec2(0), uvec4(0)); + loadCheck = loadCheck && load_image_1dArray() == 0; + imageStore(image_2d, ivec2(0), uvec4(0)); + loadCheck = loadCheck && load_image_2d() == 0; + imageStore(image_2dRect, ivec2(0), uvec4(0)); + loadCheck = loadCheck && load_image_2dRect() == 0; + imageStore(image_2dMultiSample, ivec2(0), 1, uvec4(0)); + loadCheck = loadCheck && load_image_2dMultiSample() == 0; + imageStore(image_2dArray, ivec3(0), uvec4(0)); + loadCheck = loadCheck && load_image_2dArray() == 0; + imageStore(image_3d, ivec3(0), uvec4(0)); + loadCheck = loadCheck && load_image_3d() == 0; + imageStore(image_cube, ivec3(0), uvec4(0)); + loadCheck = loadCheck && load_image_cube() == 0; + imageStore(image_cubeArray, ivec3(0), uvec4(0)); + loadCheck = loadCheck && load_image_cubeArray() == 0; + imageStore(image_2dMultiSampleArray, ivec3(0), 1, uvec4(0)); + loadCheck = loadCheck && load_image_2dMultiSampleArray() == 0; + resetAllImageValues(); + return loadCheck; +} +bool checkAllImageSamples() +{ + resetAllImageValues(); + return true + && imageSamples(image_2dMultiSample) == 2 + && imageSamples(image_2dMultiSampleArray) == 2 + ; +} +bool checkAllImageAtomicAdd() +{ + resetAllImageValues(); + return true + && imageAtomicAdd(image_1d, 0, 0) == 1 + && load_image_1d() == 1 + && imageAtomicAdd(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 + && imageAtomicAdd(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 1 + && imageAtomicAdd(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicAdd(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicAdd(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicAdd(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 1 + && imageAtomicAdd(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicAdd(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicAdd(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 + && imageAtomicAdd(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 + ; +} +bool checkAllImageAtomicExchange() +{ + resetAllImageValues(); + return true + && imageAtomicExchange(image_1d, 0, 0) == 1 + && load_image_1d() == 0 + && imageAtomicExchange(image_buffer, 0, 2) == 1 + && load_image_buffer() == 2 + && imageAtomicExchange(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 0 + && imageAtomicExchange(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 2 + && imageAtomicExchange(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicExchange(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicExchange(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 0 + && imageAtomicExchange(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 2 + && imageAtomicExchange(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 2 + && imageAtomicExchange(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 2 + && imageAtomicExchange(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 + ; +} +bool checkAllImageAtomicMin() +{ + resetAllImageValues(); + return true + && imageAtomicMin(image_1d, 0, 0) == 1 + && load_image_1d() == 0 + && imageAtomicMin(image_buffer, 0, 2) == 1 + && load_image_buffer() == 1 + && imageAtomicMin(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 0 + && imageAtomicMin(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 1 + && imageAtomicMin(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 1 + && imageAtomicMin(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 1 + && imageAtomicMin(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 0 + && imageAtomicMin(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 1 + && imageAtomicMin(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 1 + && imageAtomicMin(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 1 + && imageAtomicMin(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 1 + ; +} +bool checkAllImageAtomicMax() +{ + resetAllImageValues(); + return true + && imageAtomicMax(image_1d, 0, 0) == 1 + && load_image_1d() == 1 + && imageAtomicMax(image_buffer, 0, 2) == 1 + && load_image_buffer() == 2 + && imageAtomicMax(image_1dArray, ivec2(0), 0) == 1 + && load_image_1dArray() == 1 + && imageAtomicMax(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 2 + && imageAtomicMax(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicMax(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicMax(image_2dArray, ivec3(0), 0) == 1 + && load_image_2dArray() == 1 + && imageAtomicMax(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 2 + && imageAtomicMax(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 2 + && imageAtomicMax(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 2 + && imageAtomicMax(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 + ; +} +bool checkAllImageAtomicAnd() +{ + resetAllImageValues(); + return true + && imageAtomicAnd(image_1d, 0, 1) == 1 + && load_image_1d() == 1 + && imageAtomicAnd(image_buffer, 0, 2) == 1 + && load_image_buffer() == 0 + && imageAtomicAnd(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 1 + && imageAtomicAnd(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 0 + && imageAtomicAnd(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 0 + && imageAtomicAnd(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 0 + && imageAtomicAnd(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 1 + && imageAtomicAnd(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 0 + && imageAtomicAnd(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 0 + && imageAtomicAnd(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 0 + && imageAtomicAnd(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 0 + ; +} +bool checkAllImageAtomicOr() +{ + resetAllImageValues(); + return true + && imageAtomicOr(image_1d, 0, 1) == 1 + && load_image_1d() == 1 + && imageAtomicOr(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 + && imageAtomicOr(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 1 + && imageAtomicOr(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicOr(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicOr(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicOr(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 1 + && imageAtomicOr(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicOr(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicOr(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 + && imageAtomicOr(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 + ; +} +bool checkAllImageAtomicXor() +{ + resetAllImageValues(); + return true + && imageAtomicXor(image_1d, 0, 1) == 1 + && load_image_1d() == 0 + && imageAtomicXor(image_buffer, 0, 2) == 1 + && load_image_buffer() == 3 + && imageAtomicXor(image_1dArray, ivec2(0), 1) == 1 + && load_image_1dArray() == 0 + && imageAtomicXor(image_2d, ivec2(0), 2) == 1 + && load_image_2d() == 3 + && imageAtomicXor(image_2dRect, ivec2(0), 2) == 1 + && load_image_2dRect() == 3 + && imageAtomicXor(image_2dMultiSample, ivec2(0), 1, 2) == 1 + && load_image_2dMultiSample() == 3 + && imageAtomicXor(image_2dArray, ivec3(0), 1) == 1 + && load_image_2dArray() == 0 + && imageAtomicXor(image_3d, ivec3(0), 2) == 1 + && load_image_3d() == 3 + && imageAtomicXor(image_cube, ivec3(0), 2) == 1 + && load_image_cube() == 3 + && imageAtomicXor(image_cubeArray, ivec3(0), 2) == 1 + && load_image_cubeArray() == 3 + && imageAtomicXor(image_2dMultiSampleArray, ivec3(0), 1, 2) == 1 + && load_image_2dMultiSampleArray() == 3 + ; +} +bool checkAllImageAtomicCompSwap() +{ + resetAllImageValues(); + return true + && imageAtomicCompSwap(image_1d, 0, 0, 2) == 1 + && load_image_1d() == 1 + && imageAtomicCompSwap(image_buffer, 0, 1, 2) == 1 + && load_image_buffer() == 2 + && imageAtomicCompSwap(image_1dArray, ivec2(0), 0, 2) == 1 + && load_image_1dArray() == 1 + && imageAtomicCompSwap(image_2d, ivec2(0), 1, 2) == 1 + && load_image_2d() == 2 + && imageAtomicCompSwap(image_2dRect, ivec2(0), 1, 2) == 1 + && load_image_2dRect() == 2 + && imageAtomicCompSwap(image_2dMultiSample, ivec2(0), 1, 1, 2) == 1 + && load_image_2dMultiSample() == 2 + && imageAtomicCompSwap(image_2dArray, ivec3(0), 0, 2) == 1 + && load_image_2dArray() == 1 + && imageAtomicCompSwap(image_3d, ivec3(0), 1, 2) == 1 + && load_image_3d() == 2 + && imageAtomicCompSwap(image_cube, ivec3(0), 1, 2) == 1 + && load_image_cube() == 2 + && imageAtomicCompSwap(image_cubeArray, ivec3(0), 1, 2) == 1 + && load_image_cubeArray() == 2 + && imageAtomicCompSwap(image_2dMultiSampleArray, ivec3(0), 1, 1, 2) == 1 + && load_image_2dMultiSampleArray() == 2 + ; +} + +// CHECK_GLSL: void main( +// CHECK_SPV: OpEntryPoint +void computeMain() +{ + outputBuffer.data[0] = true + && checkAllImageSize() + && checkAllImageLoad() + && checkAllImageStore() + && checkAllImageSamples() + && checkAllImageAtomicAdd() + && checkAllImageAtomicExchange() + && checkAllImageAtomicMin() + && checkAllImageAtomicMax() + && checkAllImageAtomicAnd() + && checkAllImageAtomicOr() + && checkAllImageAtomicXor() + && checkAllImageAtomicCompSwap() + ; + // BUF: 1 +}
\ No newline at end of file diff --git a/tests/glsl/ssboMemberMemoryQualifier.slang b/tests/glsl/ssboMemberMemoryQualifier.slang new file mode 100644 index 000000000..78d029039 --- /dev/null +++ b/tests/glsl/ssboMemberMemoryQualifier.slang @@ -0,0 +1,54 @@ +//TEST:SIMPLE(filecheck=CHECK-GLSL): -stage compute -entry computeMain -allow-glsl -target glsl +//TEST:SIMPLE(filecheck=CHECK-SPV): -stage compute -entry computeMain -allow-glsl -target spirv -emit-spirv-directly + +// due to implementation limitations (slang-check-expr.cpp, `void visitMemberExpr()`) we are unable to +// implement and use .length with glsl vectors to test `readonly writeonly` +//#define TEST_whenVectorLengthIsImplemented + +volatile buffer Block1 +{ + restrict uint data1; + readonly uint data2; + readonly writeonly uint data3; + writeonly uint data4; + coherent uint data5; + volatile uint data6; +} inputBuffer1; + +coherent buffer Block2 { + readonly vec4 member1; + vec4 member2; +}inputBuffer2; + +buffer Block3 { + coherent readonly vec4 member1; + coherent vec4 member2; +}inputBuffer3; + +buffer Block4 { + struct structTmp + { + int val; + }; + readonly structTmp myStruct; + coherent readonly vec4 member1; + coherent vec4 member2; + readonly writeonly vec3 member3; +}inputBuffer4; + +// CHECK-GLSL: main +// CHECK-SPV: OpEntryPoint +layout(local_size_x = 1) in; +void computeMain() +{ + int v = inputBuffer1.data1; + v = inputBuffer1.data2; + inputBuffer1.data4 = 1; + inputBuffer1.data5 = 1; + inputBuffer1.data6 = 1; + inputBuffer2.member2 = inputBuffer2.member1; + inputBuffer3.member2 = inputBuffer3.member1; +#ifdef TEST_whenVectorLengthIsImplemented + v = inputBuffer4.member3.length(); +#endif +}
\ No newline at end of file diff --git a/tests/glsl/ssboMemberMemoryQualifierReadError.slang b/tests/glsl/ssboMemberMemoryQualifierReadError.slang new file mode 100644 index 000000000..fe2ea1943 --- /dev/null +++ b/tests/glsl/ssboMemberMemoryQualifierReadError.slang @@ -0,0 +1,17 @@ +//TEST:SIMPLE(filecheck=CHECK): -stage compute -entry computeMain -allow-glsl -target glsl +//TEST:SIMPLE(filecheck=CHECK): -stage compute -entry computeMain -allow-glsl -target spirv -emit-spirv-directly + +volatile buffer MyBlockName1 +{ + readonly uint data2; + readonly writeonly uint data3; +} inputBuffer1; + +layout(local_size_x = 1) in; +void computeMain() +{ +//CHECK: error 30011 + inputBuffer1.data2 = 1; +//CHECK: error 30011 + inputBuffer1.data3 = 1; +}
\ No newline at end of file diff --git a/tests/glsl/ssboMemberMemoryQualifierWriteError.slang b/tests/glsl/ssboMemberMemoryQualifierWriteError.slang new file mode 100644 index 000000000..f4423be25 --- /dev/null +++ b/tests/glsl/ssboMemberMemoryQualifierWriteError.slang @@ -0,0 +1,24 @@ +//TEST:SIMPLE(filecheck=CHECK): -stage compute -entry computeMain -allow-glsl -target glsl +//TEST:SIMPLE(filecheck=CHECK): -stage compute -entry computeMain -allow-glsl -target spirv -emit-spirv-directly + +volatile buffer MyBlockName1 +{ + writeonly uint data2; + readonly writeonly uint data3; +} inputBuffer1; + +buffer MyBlockName2 +{ + uint data; +} outputBuffer; + +layout(local_size_x = 1) in; +void computeMain() +{ +//CHECK: error 30101 + int a = inputBuffer1.data2; +//CHECK: error 30101 + int b = inputBuffer1.data3; +//CHECK: error 30101 + outputBuffer.data = inputBuffer1.data2; +}
\ No newline at end of file diff --git a/tests/glsl/ssboMemoryQualifier.slang b/tests/glsl/ssboMemoryQualifier.slang new file mode 100644 index 000000000..67da12e9e --- /dev/null +++ b/tests/glsl/ssboMemoryQualifier.slang @@ -0,0 +1,39 @@ +//TEST:SIMPLE(filecheck=CHECK-GLSL): -stage compute -entry computeMain -allow-glsl -target glsl +//TEST:SIMPLE(filecheck=CHECK-SPV): -stage compute -entry computeMain -allow-glsl -target spirv -emit-spirv-directly + +volatile buffer MyBlockName1 +{ + uint data1; +} inputBuffer1; +restrict buffer MyBlockName2 +{ + uint data1; +} inputBuffer2; +readonly writeonly buffer MyBlockName3 +{ + uint data1; +} inputBuffer3; +writeonly buffer MyBlockName4 +{ + uint data1; +} inputBuffer4; +readonly buffer MyBlockName5 +{ + uint data1; +} inputBuffer5; +coherent buffer MyBlockName6 +{ + uint data1; +} inputBuffer6; + +// CHECK-GLSL: main +// CHECK-SPV: OpEntryPoint +layout(local_size_x = 1) in; +void computeMain() +{ + inputBuffer1.data1 = 1; + inputBuffer2.data1 = 1; + inputBuffer4.data1 = 1; + int v = inputBuffer5.data1; + inputBuffer6.data1 = 1; +}
\ No newline at end of file diff --git a/tests/glsl/ssboMemoryQualifierReadError.slang b/tests/glsl/ssboMemoryQualifierReadError.slang new file mode 100644 index 000000000..cdd47d5b2 --- /dev/null +++ b/tests/glsl/ssboMemoryQualifierReadError.slang @@ -0,0 +1,27 @@ +//TEST:SIMPLE(filecheck=CHECK): -stage compute -entry computeMain -allow-glsl -target glsl +//TEST:SIMPLE(filecheck=CHECK): -stage compute -entry computeMain -allow-glsl -target spirv -emit-spirv-directly + +readonly writeonly buffer MyBlockName3 +{ + uint data1; +} inputBuffer1; + +readonly buffer MyBlockName5 +{ + uint data1; +} inputBuffer2; + +buffer dontOptimizeOutBlock +{ + uint data1; + uint data2; +} optimizeBlock; + +layout(local_size_x = 1) in; +void computeMain() +{ +//CHECK: error 30011 + inputBuffer1.data1 = optimizeBlock.data1; +//CHECK: error 30011 + inputBuffer2.data1 = optimizeBlock.data2; +}
\ No newline at end of file diff --git a/tests/glsl/ssboMemoryQualifierWriteError.slang b/tests/glsl/ssboMemoryQualifierWriteError.slang new file mode 100644 index 000000000..636641b3f --- /dev/null +++ b/tests/glsl/ssboMemoryQualifierWriteError.slang @@ -0,0 +1,29 @@ +//TEST:SIMPLE(filecheck=CHECK): -stage compute -entry computeMain -allow-glsl -target glsl +//TEST:SIMPLE(filecheck=CHECK): -stage compute -entry computeMain -allow-glsl -target spirv -emit-spirv-directly + +readonly writeonly buffer MyBlockName3 +{ + uint data1; +} inputBuffer1; + +writeonly buffer MyBlockName4 +{ + uint data1; +} inputBuffer2; + +buffer dontOptimizeOutBlock +{ + uint data1; + uint data2; +} optimizeBlock; + +layout(local_size_x = 1) in; +void computeMain() +{ +//CHECK: error 30101 + optimizeBlock.data1 = inputBuffer1.data1; +//CHECK: error 30101 + optimizeBlock.data2 = inputBuffer2.data1; +//CHECK: error 30101 + int a = inputBuffer2.data1; +}
\ No newline at end of file diff --git a/tests/glsl/ssboStructInsideStructMemoryQualifierError.slang b/tests/glsl/ssboStructInsideStructMemoryQualifierError.slang new file mode 100644 index 000000000..c5376b4a8 --- /dev/null +++ b/tests/glsl/ssboStructInsideStructMemoryQualifierError.slang @@ -0,0 +1,23 @@ +//TEST:SIMPLE(filecheck=CHECK-GLSL): -stage compute -entry computeMain -allow-glsl -target glsl +//TEST:SIMPLE(filecheck=CHECK-SPV): -stage compute -entry computeMain -allow-glsl -target spirv -emit-spirv-directly + +// This code should error since memory qualifiers are only allowed inside: +// Shader storage blocks, variables declared within shader storage blocks +// and variables declared as image types. Named structs inside a Interface +// block violates these rules +// CHECK-GLSL: error +// CHECK-SPV: error +buffer Block4 { + struct StructTmp + { + readonly int val; + }; + readonly structTmp myStruct; + coherent readonly vec4 member1; + coherent vec4 member2; +}inputBuffer4; + +layout(local_size_x = 1) in; +void computeMain() +{ +}
\ No newline at end of file diff --git a/tests/nv-extensions/nv-ray-tracing-motion-blur.slang b/tests/nv-extensions/nv-ray-tracing-motion-blur.slang index c66e69d14..753101d7e 100644 --- a/tests/nv-extensions/nv-ray-tracing-motion-blur.slang +++ b/tests/nv-extensions/nv-ray-tracing-motion-blur.slang @@ -20,7 +20,7 @@ struct Uniforms }; ConstantBuffer<Uniforms> ubo; -layout(rgba8) +layout(rgba32f) RWTexture2D<float4> outputImage; RaytracingAccelerationStructure as; diff --git a/tests/vkray/raygen.slang b/tests/vkray/raygen.slang index 9ba88095d..18ac74d4b 100644 --- a/tests/vkray/raygen.slang +++ b/tests/vkray/raygen.slang @@ -22,7 +22,7 @@ struct Uniforms ConstantBuffer<Uniforms> ubo; -layout(rgba8) +layout(rgba32f) RWTexture2D<float4> outputImage; RaytracingAccelerationStructure as; diff --git a/tools/gfx-unit-test/gfx-test-texture-util.cpp b/tools/gfx-unit-test/gfx-test-texture-util.cpp index ed651475d..3b3a1a760 100644 --- a/tools/gfx-unit-test/gfx-test-texture-util.cpp +++ b/tools/gfx-unit-test/gfx-test-texture-util.cpp @@ -80,6 +80,8 @@ namespace gfx_test case Format::R16G16_FLOAT: return new ValidationTextureFormat<uint16_t>(2); case Format::R16_FLOAT: return new ValidationTextureFormat<uint16_t>(1); + case Format::R64_UINT: return new ValidationTextureFormat<uint64_t>(1); + case Format::R32G32B32A32_UINT: return new ValidationTextureFormat<uint32_t>(4); case Format::R32G32B32_UINT: return new ValidationTextureFormat<uint32_t>(3); case Format::R32G32_UINT: return new ValidationTextureFormat<uint32_t>(2); @@ -93,6 +95,8 @@ namespace gfx_test case Format::R8G8_UINT: return new ValidationTextureFormat<uint8_t>(2); case Format::R8_UINT: return new ValidationTextureFormat<uint8_t>(1); + case Format::R64_SINT: return new ValidationTextureFormat<int64_t>(1); + case Format::R32G32B32A32_SINT: return new ValidationTextureFormat<int32_t>(4); case Format::R32G32B32_SINT: return new ValidationTextureFormat<int32_t>(3); case Format::R32G32_SINT: return new ValidationTextureFormat<int32_t>(2); diff --git a/tools/gfx/d3d/d3d-util.cpp b/tools/gfx/d3d/d3d-util.cpp index 34d615744..8d76c74b3 100644 --- a/tools/gfx/d3d/d3d-util.cpp +++ b/tools/gfx/d3d/d3d-util.cpp @@ -167,6 +167,8 @@ D3D12_DEPTH_STENCILOP_DESC D3DUtil::translateStencilOpDesc(DepthStencilOpDesc de case Format::R16G16_FLOAT: return DXGI_FORMAT_R16G16_FLOAT; case Format::R16_FLOAT: return DXGI_FORMAT_R16_FLOAT; + case Format::R64_UINT: return DXGI_FORMAT_R32G32_UINT; + case Format::R32G32B32A32_UINT: return DXGI_FORMAT_R32G32B32A32_UINT; case Format::R32G32B32_UINT: return DXGI_FORMAT_R32G32B32_UINT; case Format::R32G32_UINT: return DXGI_FORMAT_R32G32_UINT; @@ -180,6 +182,8 @@ D3D12_DEPTH_STENCILOP_DESC D3DUtil::translateStencilOpDesc(DepthStencilOpDesc de case Format::R8G8_UINT: return DXGI_FORMAT_R8G8_UINT; case Format::R8_UINT: return DXGI_FORMAT_R8_UINT; + case Format::R64_SINT: return DXGI_FORMAT_R32G32_SINT; + case Format::R32G32B32A32_SINT: return DXGI_FORMAT_R32G32B32A32_SINT; case Format::R32G32B32_SINT: return DXGI_FORMAT_R32G32B32_SINT; case Format::R32G32_SINT: return DXGI_FORMAT_R32G32_SINT; diff --git a/tools/gfx/gfx.slang b/tools/gfx/gfx.slang index e9a31445b..37ae5182d 100644 --- a/tools/gfx/gfx.slang +++ b/tools/gfx/gfx.slang @@ -150,6 +150,8 @@ public enum class Format R16G16_FLOAT, R16_FLOAT, + R64_UINT, + R32G32B32A32_UINT, R32G32B32_UINT, R32G32_UINT, @@ -163,6 +165,8 @@ public enum class Format R8G8_UINT, R8_UINT, + R64_SINT, + R32G32B32A32_SINT, R32G32B32_SINT, R32G32_SINT, diff --git a/tools/gfx/render.cpp b/tools/gfx/render.cpp index 6dd0c90dd..68f81fba5 100644 --- a/tools/gfx/render.cpp +++ b/tools/gfx/render.cpp @@ -86,6 +86,8 @@ struct FormatInfoMap set(Format::R16G16_FLOAT, SLANG_SCALAR_TYPE_FLOAT16, 2); set(Format::R16_FLOAT, SLANG_SCALAR_TYPE_FLOAT16, 1); + set(Format::R64_UINT, SLANG_SCALAR_TYPE_UINT64, 1); + set(Format::R32G32B32A32_UINT, SLANG_SCALAR_TYPE_UINT32, 4); set(Format::R32G32B32_UINT, SLANG_SCALAR_TYPE_UINT32, 3); set(Format::R32G32_UINT, SLANG_SCALAR_TYPE_UINT32, 2); @@ -99,6 +101,8 @@ struct FormatInfoMap set(Format::R8G8_UINT, SLANG_SCALAR_TYPE_UINT8, 2); set(Format::R8_UINT, SLANG_SCALAR_TYPE_UINT8, 1); + set(Format::R64_SINT, SLANG_SCALAR_TYPE_INT64, 1); + set(Format::R32G32B32A32_SINT, SLANG_SCALAR_TYPE_INT32, 4); set(Format::R32G32B32_SINT, SLANG_SCALAR_TYPE_INT32, 3); set(Format::R32G32_SINT, SLANG_SCALAR_TYPE_INT32, 2); diff --git a/tools/gfx/vulkan/vk-api.h b/tools/gfx/vulkan/vk-api.h index 27a19acfb..cceac20e1 100644 --- a/tools/gfx/vulkan/vk-api.h +++ b/tools/gfx/vulkan/vk-api.h @@ -250,6 +250,10 @@ struct VulkanExtendedFeatureProperties VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT atomicFloat2Features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT }; + // Image int64 atomic features + VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT imageInt64AtomicFeatures = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT + }; // Extended dynamic state features VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT diff --git a/tools/gfx/vulkan/vk-device.cpp b/tools/gfx/vulkan/vk-device.cpp index b2cbb03c1..dd8a674cb 100644 --- a/tools/gfx/vulkan/vk-device.cpp +++ b/tools/gfx/vulkan/vk-device.cpp @@ -487,6 +487,11 @@ Result DeviceImpl::initVulkanInstanceAndDevice( extendedFeatures.atomicFloat2Features.pNext = deviceFeatures2.pNext; deviceFeatures2.pNext = &extendedFeatures.atomicFloat2Features; + // Image Int64 Atomic + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT.html + extendedFeatures.imageInt64AtomicFeatures.pNext = deviceFeatures2.pNext; + deviceFeatures2.pNext = &extendedFeatures.imageInt64AtomicFeatures; + // mesh shader features extendedFeatures.meshShaderFeatures.pNext = deviceFeatures2.pNext; deviceFeatures2.pNext = &extendedFeatures.meshShaderFeatures; @@ -580,6 +585,13 @@ Result DeviceImpl::initVulkanInstanceAndDevice( ); SIMPLE_EXTENSION_FEATURE( + extendedFeatures.imageInt64AtomicFeatures, + shaderImageInt64Atomics, + VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME, + "image-atomic-int64" + ); + + SIMPLE_EXTENSION_FEATURE( extendedFeatures.extendedDynamicStateFeatures, extendedDynamicState, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, @@ -1638,6 +1650,97 @@ Result DeviceImpl::createTextureResource( VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + if(desc.sampleDesc.numSamples != 1) + { + // Handle senario where texture is sampled. We cannot use + // a simple buffer copy for sampled textures. ClearColorImage + // is not data accurate but it is fine for testing & works. + FormatInfo formatInfo; + gfxGetFormatInfo(desc.format, &formatInfo); + uint32_t data = 0; + VkClearColorValue clearColor; + switch(formatInfo.channelType) + { + case SLANG_SCALAR_TYPE_INT32: + for(int i = 0; i < 4; i++) + clearColor.int32[i] = *reinterpret_cast<int32_t*>(const_cast<void*>(initData->data)); + break; + case SLANG_SCALAR_TYPE_UINT32: + for(int i = 0; i < 4; i++) + clearColor.uint32[i] = *reinterpret_cast<uint32_t*>(const_cast<void*>(initData->data)); break; + break; + case SLANG_SCALAR_TYPE_INT64: + { + for(int i = 0; i < 4; i++) + clearColor.int32[i] = int32_t(*reinterpret_cast<int64_t*>(const_cast<void*>(initData->data))); + break; + } + case SLANG_SCALAR_TYPE_UINT64: + { + for(int i = 0; i < 4; i++) + clearColor.uint32[i] = uint32_t(*reinterpret_cast<uint64_t*>(const_cast<void*>(initData->data))); + break; + } + case SLANG_SCALAR_TYPE_FLOAT16: + { + for(int i = 0; i < 4; i++) + clearColor.float32[i] = HalfToFloat(*reinterpret_cast<uint16_t*>(const_cast<void*>(initData->data))); + break; + } + case SLANG_SCALAR_TYPE_FLOAT32: + { + for(int i = 0; i < 4; i++) + clearColor.float32[i] = (*reinterpret_cast<float*>(const_cast<void*>(initData->data))); + break; + } + case SLANG_SCALAR_TYPE_FLOAT64: + { + for(int i = 0; i < 4; i++) + clearColor.float32[i] = float(*reinterpret_cast<double*>(const_cast<void*>(initData->data))); + break; + } + case SLANG_SCALAR_TYPE_INT8: + { + for(int i = 0; i < 4; i++) + clearColor.int32[i] = int32_t(*reinterpret_cast<int8_t*>(const_cast<void*>(initData->data))); + break; + } + case SLANG_SCALAR_TYPE_UINT8: + { + for(int i = 0; i < 4; i++) + clearColor.uint32[i] = uint32_t(*reinterpret_cast<uint8_t*>(const_cast<void*>(initData->data))); + break; + } + case SLANG_SCALAR_TYPE_INT16: + { + for(int i = 0; i < 4; i++) + clearColor.int32[i] = int32_t(*reinterpret_cast<int16_t*>(const_cast<void*>(initData->data))); + break; + } + case SLANG_SCALAR_TYPE_UINT16: + { + for(int i = 0; i < 4; i++) + clearColor.uint32[i] = uint32_t(*reinterpret_cast<uint16_t*>(const_cast<void*>(initData->data))); + break; + } + }; + + VkImageSubresourceRange range{}; + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + range.baseMipLevel = 0; + range.levelCount = VK_REMAINING_MIP_LEVELS; + range.baseArrayLayer = 0; + range.layerCount = VK_REMAINING_ARRAY_LAYERS; + + m_api.vkCmdClearColorImage( + commandBuffer, + texture->m_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &clearColor, + 1, + &range); + } + else { Offset srcOffset = 0; for (int i = 0; i < arraySize; ++i) @@ -2154,6 +2257,23 @@ Result DeviceImpl::createBufferView( info.buffer = resourceImpl->m_buffer.m_buffer; info.offset = offset; info.range = size; + VkBufferUsageFlags2CreateInfoKHR bufferViewUsage{}; + bufferViewUsage.sType = VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO_KHR; + + if (desc.type == IResourceView::Type::UnorderedAccess) + { + info.pNext = &bufferViewUsage; + bufferViewUsage.usage = VK_BUFFER_USAGE_2_STORAGE_TEXEL_BUFFER_BIT_KHR; + } + else if (desc.type == IResourceView::Type::ShaderResource) + { + info.pNext = &bufferViewUsage; + bufferViewUsage.usage = VK_BUFFER_USAGE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR; + } + else + { + assert(!"unhandled"); + } SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateBufferView(m_device, &info, nullptr, &view)); } diff --git a/tools/gfx/vulkan/vk-util.cpp b/tools/gfx/vulkan/vk-util.cpp index e8007805a..1a571c812 100644 --- a/tools/gfx/vulkan/vk-util.cpp +++ b/tools/gfx/vulkan/vk-util.cpp @@ -25,6 +25,8 @@ namespace gfx { case Format::R8_TYPELESS: return VK_FORMAT_R8_UNORM; case Format::B8G8R8A8_TYPELESS: return VK_FORMAT_B8G8R8A8_UNORM; + case Format::R64_UINT: return VK_FORMAT_R64_UINT; + case Format::R32G32B32A32_FLOAT: return VK_FORMAT_R32G32B32A32_SFLOAT; case Format::R32G32B32_FLOAT: return VK_FORMAT_R32G32B32_SFLOAT; case Format::R32G32_FLOAT: return VK_FORMAT_R32G32_SFLOAT; @@ -47,6 +49,8 @@ namespace gfx { case Format::R8G8_UINT: return VK_FORMAT_R8G8_UINT; case Format::R8_UINT: return VK_FORMAT_R8_UINT; + case Format::R64_SINT: return VK_FORMAT_R64_SINT; + case Format::R32G32B32A32_SINT: return VK_FORMAT_R32G32B32A32_SINT; case Format::R32G32B32_SINT: return VK_FORMAT_R32G32B32_SINT; case Format::R32G32_SINT: return VK_FORMAT_R32G32_SINT; diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp index 6b30315fb..96f5db6e0 100644 --- a/tools/render-test/shader-input-layout.cpp +++ b/tools/render-test/shader-input-layout.cpp @@ -112,6 +112,25 @@ namespace renderer_test else val->textureDesc.content = InputTextureContent::Gradient; } + else if (word == "sampleCount") + { + parser.Read("="); + auto contentWord = parser.ReadWord(); + if(contentWord == "one") + val->textureDesc.sampleCount = InputTextureSampleCount::One; + else if(contentWord == "two") + val->textureDesc.sampleCount = InputTextureSampleCount::Two; + else if(contentWord == "four") + val->textureDesc.sampleCount = InputTextureSampleCount::Four; + else if(contentWord == "eight") + val->textureDesc.sampleCount = InputTextureSampleCount::Eight; + else if(contentWord == "sixteen") + val->textureDesc.sampleCount = InputTextureSampleCount::Sixteen; + else if(contentWord == "thirtyTwo") + val->textureDesc.sampleCount = InputTextureSampleCount::ThirtyTwo; + else if(contentWord == "sixtyFour") + val->textureDesc.sampleCount = InputTextureSampleCount::SixtyFour; + } else if(word == "mipMaps") { parser.Read("="); @@ -633,6 +652,13 @@ namespace renderer_test maybeParseOptions(parser, val.Ptr()); return val; } + else if (parser.AdvanceIf("RWTextureBuffer")) + { + RefPtr<ShaderInputLayout::BufferVal> val = new ShaderInputLayout::BufferVal; + val->bufferDesc.type = InputBufferType::StorageBuffer; + maybeParseOptions(parser, val.Ptr()); + return val; + } else if (parser.AdvanceIf("Texture2D")) { RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal; @@ -1100,7 +1126,99 @@ namespace renderer_test return SLANG_OK; } + void loadDataIntoHalf(uint16_t& out, const uint8_t& in) + { + out = FloatToHalf((float(in) / 255.0f)); + } + void loadDataIntoFloat(float& out, const uint8_t& in) + { + out = (float(in)/255.0f); + } + template<typename T> + void loadDataIntoUint(T& out, const uint8_t& in) + { + out = T(in); + } + template<typename T> + void loadDataIntoInt(T& out, const uint8_t& in) + { + out = T(in); + } + + // T for type to return, F for function pointer to operate on uint8->T + template<typename T, typename F> + void generateTextureDataWithTargetTStorage(TextureData& output, const InputTextureDesc& desc, gfx::FormatInfo& formatInfo, F loadUint8ToT) + { + // the following function assumes input of 0 or 1 since our testing framework only tests with 0 or 1 + TextureData work; + generateTextureDataRGB8(work, desc); + + output.init(desc.format); + + output.m_textureSize = work.m_textureSize; + output.m_mipLevels = work.m_mipLevels; + output.m_arraySize = work.m_arraySize; + List<TextureData::Slice>& dstSlices = output.m_slices; + + Index numSlices = work.m_slices.getCount(); + dstSlices.setCount(numSlices); + + for (int i = 0; i < numSlices; ++i) + { + const TextureData::Slice& srcSlice = work.m_slices[i]; + + const Index pixelCount = srcSlice.valuesCount; + const uint8_t* srcPixels = (const uint8_t*)srcSlice.values; + + T* dstPixels = (T*)output.setSliceCount(i, pixelCount); + switch (formatInfo.channelCount) + { + case 1: + { + for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels += 1) + { + // Copy out r + loadUint8ToT(dstPixels[0], srcPixels[0]); + } + break; + } + case 2: + { + for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels += 2) + { + // Copy out rg + loadUint8ToT(dstPixels[0], srcPixels[0]); + loadUint8ToT(dstPixels[1], srcPixels[1]); + } + break; + } + case 3: + { + for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels += 3) + { + // Copy out rgb + loadUint8ToT(dstPixels[0], srcPixels[0]); + loadUint8ToT(dstPixels[1], srcPixels[1]); + loadUint8ToT(dstPixels[2], srcPixels[2]); + } + break; + } + case 4: + { + for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels += 4) + { + // Copy out rgba + loadUint8ToT(dstPixels[0], srcPixels[0]); + loadUint8ToT(dstPixels[1], srcPixels[1]); + loadUint8ToT(dstPixels[2], srcPixels[2]); + loadUint8ToT(dstPixels[3], srcPixels[3]); + } + break; + } + } + } + } void generateTextureData(TextureData& output, const InputTextureDesc& desc) { gfx::FormatInfo formatInfo; @@ -1117,75 +1235,12 @@ namespace renderer_test case Format::R16G16_FLOAT: case Format::R16G16B16A16_FLOAT: { - TextureData work; - generateTextureDataRGB8(work, desc); - - output.init(desc.format); - - output.m_textureSize = work.m_textureSize; - output.m_mipLevels = work.m_mipLevels; - output.m_arraySize = work.m_arraySize; - - List<TextureData::Slice>& dstSlices = output.m_slices; - - Index numSlices = work.m_slices.getCount(); - dstSlices.setCount(numSlices); - - for (int i = 0; i < numSlices; ++i) - { - const TextureData::Slice& srcSlice = work.m_slices[i]; - - const Index pixelCount = srcSlice.valuesCount; - const uint8_t* srcPixels = (const uint8_t*)srcSlice.values; - - int16_t* dstPixels = (int16_t*)output.setSliceCount(i, pixelCount); - - switch (formatInfo.channelCount) - { - case 1: - { - for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels += 1) - { - // Copy out r - dstPixels[0] = FloatToHalf(srcPixels[0] * (1.0f / 255)); - } - break; - } - case 2: - { - for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels += 2) - { - // Copy out rg - dstPixels[0] = FloatToHalf(srcPixels[0] * (1.0f / 255)); - dstPixels[1] = FloatToHalf(srcPixels[1] * (1.0f / 255)); - } - break; - } - case 3: - { - for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels += 3) - { - // Copy out rgb - dstPixels[0] = FloatToHalf(srcPixels[0] * (1.0f / 255)); - dstPixels[1] = FloatToHalf(srcPixels[1] * (1.0f / 255)); - dstPixels[2] = FloatToHalf(srcPixels[2] * (1.0f / 255)); - } - break; - } - case 4: - { - for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels += 4) - { - // Copy out rgba - dstPixels[0] = FloatToHalf(srcPixels[0] * (1.0f / 255)); - dstPixels[1] = FloatToHalf(srcPixels[1] * (1.0f / 255)); - dstPixels[2] = FloatToHalf(srcPixels[2] * (1.0f / 255)); - dstPixels[3] = FloatToHalf(srcPixels[3] * (1.0f / 255)); - } - break; - } - } - } + generateTextureDataWithTargetTStorage<uint16_t>(output, desc, formatInfo, loadDataIntoHalf); + break; + } + case Format::R64_UINT: + { + generateTextureDataWithTargetTStorage<uint64_t>(output, desc, formatInfo, loadDataIntoUint<uint64_t>); break; } case Format::R32_FLOAT: @@ -1194,76 +1249,56 @@ namespace renderer_test case Format::R32G32B32A32_FLOAT: case Format::D32_FLOAT: { - TextureData work; - generateTextureDataRGB8(work, desc); - - output.init(desc.format); - - output.m_textureSize = work.m_textureSize; - output.m_mipLevels = work.m_mipLevels; - output.m_arraySize = work.m_arraySize; - - List<TextureData::Slice>& dstSlices = output.m_slices; - - Index numSlices = work.m_slices.getCount(); - dstSlices.setCount(numSlices); - - for (int i = 0; i < numSlices; ++i) - { - const TextureData::Slice& srcSlice = work.m_slices[i]; - - const Index pixelCount = srcSlice.valuesCount; - const uint8_t* srcPixels = (const uint8_t*)srcSlice.values; - - float* dstPixels = (float*)output.setSliceCount(i, pixelCount); - - switch (formatInfo.channelCount) - { - case 1: - { - for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels++) - { - // Copy out r - dstPixels[0] = srcPixels[0] * (1.0f / 255); - } - break; - } - case 2: - { - for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels += 2) - { - // Copy out rg - dstPixels[0] = srcPixels[0] * (1.0f / 255); - dstPixels[1] = srcPixels[1] * (1.0f / 255); - } - break; - } - case 3: - { - for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels += 3) - { - // Copy out rgb - dstPixels[0] = srcPixels[0] * (1.0f / 255); - dstPixels[1] = srcPixels[1] * (1.0f / 255); - dstPixels[2] = srcPixels[2] * (1.0f / 255); - } - break; - } - case 4: - { - - for (Index j = 0; j < pixelCount; ++j, srcPixels += 4, dstPixels += 4) - { - // Copy out rgba - dstPixels[0] = srcPixels[0] * (1.0f / 255); - dstPixels[1] = srcPixels[1] * (1.0f / 255); - dstPixels[2] = srcPixels[2] * (1.0f / 255); - dstPixels[3] = srcPixels[3] * (1.0f / 255); - } - break; - } - } - } + generateTextureDataWithTargetTStorage<float>(output, desc, formatInfo, loadDataIntoFloat); + break; + } + case Format::R32_UINT: + case Format::R32G32_UINT: + case Format::R32G32B32_UINT: + case Format::R32G32B32A32_UINT: + { + generateTextureDataWithTargetTStorage<uint32_t>(output, desc, formatInfo, loadDataIntoUint<uint32_t>); + break; + } + case Format::R16_UINT: + case Format::R16G16_UINT: + case Format::R16G16B16A16_UINT: + { + generateTextureDataWithTargetTStorage<uint16_t>(output, desc, formatInfo, loadDataIntoUint<uint16_t>); + break; + } + case Format::R8_UINT: + case Format::R8G8_UINT: + case Format::R8G8B8A8_UINT: + { + generateTextureDataWithTargetTStorage<uint8_t>(output, desc, formatInfo, loadDataIntoUint<uint8_t>); + break; + } + case Format::R64_SINT: + { + generateTextureDataWithTargetTStorage<int64_t>(output, desc, formatInfo, loadDataIntoInt<int64_t>); + break; + } + case Format::R32_SINT: + case Format::R32G32_SINT: + case Format::R32G32B32_SINT: + case Format::R32G32B32A32_SINT: + { + generateTextureDataWithTargetTStorage<int32_t>(output, desc, formatInfo, loadDataIntoInt<int32_t>); + break; + } + case Format::R16_SINT: + case Format::R16G16_SINT: + case Format::R16G16B16A16_SINT: + { + generateTextureDataWithTargetTStorage<int16_t>(output, desc, formatInfo, loadDataIntoInt<int16_t>); + break; + } + case Format::R8_SINT: + case Format::R8G8_SINT: + case Format::R8G8B8A8_SINT: + { + generateTextureDataWithTargetTStorage<int8_t>(output, desc, formatInfo, loadDataIntoInt<int8_t>); break; } default: @@ -1299,6 +1334,37 @@ namespace renderer_test output.init(Format::R8G8B8A8_UNORM); + enum class SimpleScalarType { + kUint, + kInt, + kFloat, + }; + SimpleScalarType type; + gfx::FormatInfo formatInfo; + gfxGetFormatInfo(inputDesc.format, &formatInfo); + switch (formatInfo.channelType) + { + case SLANG_SCALAR_TYPE_UINT64: + case SLANG_SCALAR_TYPE_UINT32: + case SLANG_SCALAR_TYPE_UINT16: + case SLANG_SCALAR_TYPE_UINT8: + type = SimpleScalarType::kUint; + break; + case SLANG_SCALAR_TYPE_INT64: + case SLANG_SCALAR_TYPE_INT32: + case SLANG_SCALAR_TYPE_INT16: + case SLANG_SCALAR_TYPE_INT8: + type = SimpleScalarType::kInt; + break; + case SLANG_SCALAR_TYPE_FLOAT64: + case SLANG_SCALAR_TYPE_FLOAT32: + case SLANG_SCALAR_TYPE_FLOAT16: + type = SimpleScalarType::kFloat; + break; + default: + type = SimpleScalarType::kUint; + break; + } //List<List<unsigned int>>& dataBuffer = output.dataBuffer; int arraySize = arrLen; if (inputDesc.isCube) @@ -1327,36 +1393,68 @@ namespace renderer_test uint32_t* dst = (uint32_t*)output.setSliceCount(slice, bufferLen); - _iteratePixels(inputDesc.dimension, size, dst, [&](int x, int y, int z) -> unsigned int - { - if (inputDesc.content == InputTextureContent::Zero) - { - return 0x0; - } - else if (inputDesc.content == InputTextureContent::One) - { - return 0xFFFFFFFF; - } - else if (inputDesc.content == InputTextureContent::Gradient) - { - unsigned char r = (unsigned char)(x / (float)(size - 1) * 255.0f); - unsigned char g = (unsigned char)(y / (float)(size - 1) * 255.0f); - unsigned char b = (unsigned char)(z / (float)(size - 1) * 255.0f); - return 0xFF000000 + r + (g << 8) + (b << 16); - } - else if (inputDesc.content == InputTextureContent::ChessBoard) - { - unsigned int xSig = x < (size >> 1) ? 1 : 0; - unsigned int ySig = y < (size >> 1) ? 1 : 0; - unsigned int zSig = z < (size >> 1) ? 1 : 0; - auto sig = xSig ^ ySig ^ zSig; - if (sig) - return 0xFFFFFFFF; - else - return 0xFF808080; - } - return 0x0; - }); + if (type == SimpleScalarType::kFloat) + _iteratePixels(inputDesc.dimension, size, dst, [&](int x, int y, int z) -> unsigned int + { + if (inputDesc.content == InputTextureContent::Zero) + { + return 0x0; + } + else if (inputDesc.content == InputTextureContent::One) + { + return 0xFFFFFFFF; + } + else if (inputDesc.content == InputTextureContent::Gradient) + { + unsigned char r = (unsigned char)(x / (float)(size - 1) * 255.0f); + unsigned char g = (unsigned char)(y / (float)(size - 1) * 255.0f); + unsigned char b = (unsigned char)(z / (float)(size - 1) * 255.0f); + return 0xFF000000 + r + (g << 8) + (b << 16); + } + else if (inputDesc.content == InputTextureContent::ChessBoard) + { + unsigned int xSig = x < (size >> 1) ? 1 : 0; + unsigned int ySig = y < (size >> 1) ? 1 : 0; + unsigned int zSig = z < (size >> 1) ? 1 : 0; + auto sig = xSig ^ ySig ^ zSig; + if (sig) + return 0xFFFFFFFF; + else + return 0xFF808080; + } + return 0x0; + }); + else if (type == SimpleScalarType::kUint || type == SimpleScalarType::kInt) + _iteratePixels(inputDesc.dimension, size, dst, [&](int x, int y, int z) -> unsigned int + { + if (inputDesc.content == InputTextureContent::Zero) + { + return 0x0; + } + else if (inputDesc.content == InputTextureContent::One) + { + return 0x01010101; + } + else if (inputDesc.content == InputTextureContent::Gradient) + { + unsigned char r = (unsigned char)(x / (float)(size - 1)); + unsigned char g = (unsigned char)(y / (float)(size - 1)); + unsigned char b = (unsigned char)(z / (float)(size - 1)); + return 0x01000000 + r + (g << 8) + (b << 16); + } + else if (inputDesc.content == InputTextureContent::ChessBoard) + { + unsigned int xSig = x < (size >> 1) ? 1 : 0; + unsigned int ySig = y < (size >> 1) ? 1 : 0; + unsigned int zSig = z < (size >> 1) ? 1 : 0; + auto sig = xSig ^ ySig ^ zSig; + if (sig) + return 0x01010101; + else + return 0x0; + } + return 0x0; + }); slice++; } } diff --git a/tools/render-test/shader-input-layout.h b/tools/render-test/shader-input-layout.h index 2803d1915..de1da3da9 100644 --- a/tools/render-test/shader-input-layout.h +++ b/tools/render-test/shader-input-layout.h @@ -31,6 +31,16 @@ enum class InputTextureContent Zero, One, ChessBoard, Gradient }; +enum InputTextureSampleCount +{ + One = 1, + Two = 2, + Four = 4, + Eight = 8, + Sixteen = 16, + ThirtyTwo = 32, + SixtyFour = 64, +}; struct InputTextureDesc { int dimension = 2; @@ -41,6 +51,7 @@ struct InputTextureDesc int size = 4; int mipMapCount = 0; ///< 0 means the maximum number of mips will be bound + InputTextureSampleCount sampleCount = InputTextureSampleCount::One; Format format = Format::R8G8B8A8_UNORM; InputTextureContent content = InputTextureContent::One; diff --git a/tools/render-test/shader-renderer-util.cpp b/tools/render-test/shader-renderer-util.cpp index bbc000594..fe726012e 100644 --- a/tools/render-test/shader-renderer-util.cpp +++ b/tools/render-test/shader-renderer-util.cpp @@ -32,6 +32,7 @@ using Slang::Result; // Default to R8G8B8A8_UNORM const Format format = (inputDesc.format == Format::Unknown) ? Format::R8G8B8A8_UNORM : inputDesc.format; + textureResourceDesc.sampleDesc = ITextureResource::SampleDesc{inputDesc.sampleCount, 0}; textureResourceDesc.format = format; textureResourceDesc.numMipLevels = texData.m_mipLevels; textureResourceDesc.arraySize = inputDesc.arrayLength; |
