diff options
| author | Yong He <yonghe@outlook.com> | 2023-11-16 14:32:33 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-16 14:32:33 -0800 |
| commit | 4c78efd0c34442866f20e9d00bbb6908115c9a01 (patch) | |
| tree | 03ca8584847f0937a926f6b27386dcd982ed7780 | |
| parent | 12f7237e4060388494c549623f4a640327b7ca08 (diff) | |
Unify stdlib `Texture` types into one generic type. (#3327)
* Unify Texture types in stdlib into 1 generic type.
* Fixes.
* Fix.
* Fixes.
* Fix reflection.
* Fix binding reflection.
* Add gather intrinsics.
* Fix gather intrinsics.
* Fix texture type toText.
* Fix intrinsic.
* fix cuda intrinsic.
* Fix project files.
* cleanup.
* Fix.
* Fix.
* Fix sampler feedback test.
* Fix getDimension intrinsics.
* Fix spirv sample image intrinsics.
* Fix test.
* Fix GLSL intrinsic.
* Cleanup.
---------
Co-authored-by: Yong He <yhe@nvidia.com>
58 files changed, 2421 insertions, 1687 deletions
@@ -2020,6 +2020,8 @@ extern "C" SLANG_RESOURCE_ACCESS_APPEND, SLANG_RESOURCE_ACCESS_CONSUME, SLANG_RESOURCE_ACCESS_WRITE, + SLANG_RESOURCE_ACCESS_FEEDBACK, + SLANG_RESOURCE_ACCESS_UNKNOWN = 0x7FFFFFFF, }; typedef unsigned int SlangParameterCategoryIntegral; diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index b1437670e..3a19d345a 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -1476,25 +1476,6 @@ struct SamplerComparisonState { } -${{{{ - -for(auto& prefixInfo : kTexturePrefixes) -for(auto& shapeInfo : kBaseTextureShapes) -for(int isArray = 0; isArray < 2; ++isArray) -for(int isMultisample = 0; isMultisample < 2; ++isMultisample) -for(int isShadow = 0; isShadow < 2; ++isShadow) -for(auto& accessInfo : kBaseTextureAccessLevels) -{ - // Define `Shadow` flavored types only for combined texture-samplers. - if (!prefixInfo.combined && isShadow == 1) - continue; - - TextureTypeInfo info(prefixInfo, shapeInfo, isArray, isMultisample, isShadow, accessInfo, sb, path); - info.emitTypeDecl(); -} - -}}}} - //@ hidden: ${{{{ diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang index a9518f914..98f30cd3c 100644 --- a/source/slang/glsl.meta.slang +++ b/source/slang/glsl.meta.slang @@ -94,17 +94,20 @@ typealias usamplerCube = SamplerCube<uint4>; typealias isamplerCube = SamplerCube<int4>; typealias samplerCube = SamplerCube<float4>; -typealias usampler1DShadow = Sampler1DShadow<uint4>; -typealias isampler1DShadow = Sampler1DShadow<int4>; -typealias sampler1DShadow = Sampler1DShadow<float4>; +typealias Sampler1DShadow<T=float> = __TextureImpl<T, __Shape1D, /*isArray:*/ 0, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +typealias usampler1DShadow = Sampler1DShadow<uint>; +typealias isampler1DShadow = Sampler1DShadow<int>; +typealias sampler1DShadow = Sampler1DShadow<float>; -typealias usampler2DShadow = Sampler2DShadow<uint4>; -typealias isampler2DShadow = Sampler2DShadow<int4>; -typealias sampler2DShadow = Sampler2DShadow<float4>; +typealias Sampler2DShadow<T=float> = __TextureImpl<T, __Shape2D, /*isArray:*/ 0, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +typealias usampler2DShadow = Sampler2DShadow<uint>; +typealias isampler2DShadow = Sampler2DShadow<int>; +typealias sampler2DShadow = Sampler2DShadow<float>; -typealias usamplerCubeShadow = SamplerCubeShadow<uint4>; -typealias isamplerCubeShadow = SamplerCubeShadow<int4>; -typealias samplerCubeShadow = SamplerCubeShadow<float4>; +typealias SamplerCubeShadow<T=float> = __TextureImpl<T, __ShapeCube, /*isArray:*/ 0, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +typealias usamplerCubeShadow = SamplerCubeShadow<uint>; +typealias isamplerCubeShadow = SamplerCubeShadow<int>; +typealias samplerCubeShadow = SamplerCubeShadow<float>; typealias usampler1DArray = Sampler1DArray<uint4>; typealias isampler1DArray = Sampler1DArray<int4>; @@ -118,20 +121,20 @@ typealias usamplerCubeArray = SamplerCubeArray<uint4>; typealias isamplerCubeArray = SamplerCubeArray<int4>; typealias samplerCubeArray = SamplerCubeArray<float4>; -typealias usampler1DArrayShadow = Sampler1DArrayShadow<uint4>; -typealias isampler1DArrayShadow = Sampler1DArrayShadow<int4>; -typealias sampler1DArrayShadow = Sampler1DArrayShadow<float4>; +typealias Sampler1DArrayShadow<T=float> = __TextureImpl<T, __Shape1D, /*isArray:*/ 1, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +typealias usampler1DArrayShadow = Sampler1DArrayShadow<uint>; +typealias isampler1DArrayShadow = Sampler1DArrayShadow<int>; +typealias sampler1DArrayShadow = Sampler1DArrayShadow<float>; -typealias usampler2DArrayShadow = Sampler2DArrayShadow<uint4>; -typealias isampler2DArrayShadow = Sampler2DArrayShadow<int4>; -typealias sampler2DArrayShadow = Sampler2DArrayShadow<float4>; +typealias Sampler2DArrayShadow<T=float> = __TextureImpl<T, __Shape2D, /*isArray:*/ 1, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +typealias usampler2DArrayShadow = Sampler2DArrayShadow<uint>; +typealias isampler2DArrayShadow = Sampler2DArrayShadow<int>; +typealias sampler2DArrayShadow = Sampler2DArrayShadow<float>; -typealias usamplerCubeArrayShadow = SamplerCubeArrayShadow<uint4>; -typealias isamplerCubeArrayShadow = SamplerCubeArrayShadow<int4>; -typealias samplerCubeArrayShadow = SamplerCubeArrayShadow<float4>; - -__intrinsic_op(vectorReshape) -vector<T,N> __vectorReshape<let N : int, T, let M : int>(vector<T,M> vin); +typealias SamplerCubeArrayShadow<T=float> = __TextureImpl<T, __ShapeCube, /*isArray:*/ 1, /*isMS:*/ 0, /*sampleCount:*/ 0, /*access:*/ 0, /*isShadow: */ 1, /*isCombined: */ 1, /*format*/ 0>; +typealias usamplerCubeArrayShadow = SamplerCubeArrayShadow<uint>; +typealias isamplerCubeArrayShadow = SamplerCubeArrayShadow<int>; +typealias samplerCubeArrayShadow = SamplerCubeArrayShadow<float>; [ForceInline] vector<T,4> texelFetch<T:__BuiltinArithmeticType, let N : int> (Sampler1D<vector<T,N>> sampler, int p, int lod) @@ -235,45 +238,12 @@ float texture<T:__BuiltinArithmeticType, let N : int> (Sampler2DArrayShadow<vect return sampler.SampleCmp(p.xyz, p.w); } -// TODO: define `texture` for SamplerCubeArrayShadow. - - -vector<T,4> textureGrad<T:__BuiltinArithmeticType, let N : int> (Sampler1D<vector<T,N>> sampler, float P, float dPdx, float dPdy) -{ - return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); -} - -vector<T,4> textureGrad<T:__BuiltinArithmeticType, let N : int> (Sampler2D<vector<T,N>> sampler, vec2 P, vec2 dPdx, vec2 dPdy) -{ - return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); -} - -vector<T,4> textureGrad<T:__BuiltinArithmeticType, let N : int> (Sampler3D<vector<T,N>> sampler, vec3 P, vec3 dPdx, vec3 dPdy) -{ - return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); -} - -vector<T,4> textureGrad<T:__BuiltinArithmeticType, let N : int> (SamplerCube<vector<T,N>> sampler, vec3 P, vec3 dPdx, vec3 dPdy) -{ - return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); -} - -vector<T,4> textureGrad<T:__BuiltinArithmeticType, let N : int> (Sampler1DArray<vector<T,N>> sampler, vec2 P, float dPdx, float dPdy) -{ - return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); -} - -vector<T,4> textureGrad<T:__BuiltinArithmeticType, let N : int> (Sampler2DArray<vector<T,N>> sampler, vec3 P, vec2 dPdx, vec2 dPdy) +__generic<T:__BuiltinArithmeticType, let N : int, shape:__ITextureShape, let sampleCount: int, let isArray:int, let format:int> +vector<T,4> textureGrad(__TextureImpl<vector<T,N>, shape, isArray, 0, sampleCount, 0, 1, 1, format> sampler, vector<float, shape.dimensions+isArray> P, vector<float,shape.planeDimensions> dPdx, vector<float,shape.planeDimensions> dPdy) { return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); } -vector<T,4> textureGrad<T:__BuiltinArithmeticType, let N : int> (SamplerCubeArray<vector<T,N>> sampler, vec4 P, vec3 dPdx, vec3 dPdy) -{ - return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); -} - - out float4 gl_Position : SV_Position; out float gl_PointSize : SV_PointSize; in vec4 gl_FragCoord : SV_Position; diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 6520ab1fa..501723931 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -112,6 +112,1528 @@ struct ByteAddressBuffer } }; +// Texture +[sealed] +[builtin] +interface __ITextureShape +{ + static const int flavor; + static const int dimensions; + static const int planeDimensions; +} +__magic_type(TextureShape1DType) +__intrinsic_type($(kIROp_TextureShape1DType)) +struct __Shape1D : __ITextureShape +{ + static const int flavor = $(SLANG_TEXTURE_1D); + static const int dimensions = 1; + static const int planeDimensions = 1; +} +__magic_type(TextureShape2DType) +__intrinsic_type($(kIROp_TextureShape2DType)) +struct __Shape2D : __ITextureShape +{ + static const int flavor = $(SLANG_TEXTURE_2D); + static const int dimensions = 2; + static const int planeDimensions = 2; +} +__magic_type(TextureShape3DType) +__intrinsic_type($(kIROp_TextureShape3DType)) +struct __Shape3D : __ITextureShape +{ + static const int flavor = $(SLANG_TEXTURE_3D); + static const int dimensions = 3; + static const int planeDimensions = 3; +} +__magic_type(TextureShapeCubeType) +__intrinsic_type($(kIROp_TextureShapeCubeType)) +struct __ShapeCube : __ITextureShape +{ + static const int flavor = $(SLANG_TEXTURE_CUBE); + static const int dimensions = 3; + static const int planeDimensions = 2; +} +__magic_type(TextureShapeBufferType) +__intrinsic_type($(kIROp_TextureShapeBufferType)) +struct __ShapeBuffer : __ITextureShape +{ + static const int flavor = $(SLANG_TEXTURE_BUFFER); + static const int dimensions = 1; + static const int planeDimensions = 1; +} +__intrinsic_op(vectorReshape) +vector<T,N> __vectorReshape<let N : int, T, let M : int>(vector<T,M> vin); + +__intrinsic_op(makeVector) +__generic<T, let N:int> +vector<T,N+1> __makeVector(vector<T,N> vec, T scalar); + + +__magic_type(TextureType) +__intrinsic_type($(kIROp_TextureType)) +struct __TextureImpl<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int> +{ +} + +// Combined texture sampler specific functions +__generic<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let isShadow:int, let format:int> +extension __TextureImpl<T,Shape,isArray,isMS,sampleCount,0,isShadow,1,format> +{ + static const int access = 0; + + typealias TextureCoord = vector<float, Shape.dimensions>; + + __target_intrinsic(glsl, "textureQueryLod($0, $1).x") + float CalculateLevelOfDetail(TextureCoord location); + + __target_intrinsic(glsl, "textureQueryLod($0, $1).y") + float CalculateLevelOfDetailUnclamped(TextureCoord location); + + [__readNone] + T Sample(vector<float, Shape.dimensions+isArray> location) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Sample"; + case glsl: + __intrinsic_asm "$ctexture($0, $1)$z"; + case cuda: + if (isArray != 0) + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "tex1DLayered<$T0>($0, ($1).x, int(($1).y))"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "tex2DLayered<$T0>($0, ($1).x, ($1).y, int(($1).z))"; + case $(SLANG_TEXTURE_CUBE): + __intrinsic_asm "texCubemapLayered<$T0>($0, ($1).x, ($1).y, ($1).z, int(($1).w))"; + } + } + else + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "tex1D<$T0>($0, ($1))"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "tex2D<$T0>($0, ($1).x, ($1).y)"; + case $(SLANG_TEXTURE_3D): + __intrinsic_asm "tex3D<$T0>($0, ($1).x, ($1).y, ($1).z)"; + case $(SLANG_TEXTURE_CUBE): + __intrinsic_asm "texCubemap<$T0>($0, ($1).x, ($1).y, ($1).z)"; + } + } + case spirv: + return spirv_asm + { + %sampled : __sampledType(T) = OpImageSampleImplicitLod $this $location None; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + [__readNone] + __glsl_extension(GL_ARB_sparse_texture_clamp) + T Sample(vector<float, Shape.dimensions+isArray> location, vector<int, Shape.planeDimensions> offset, float clamp) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Sample"; + case glsl: + __intrinsic_asm "$ctextureOffsetClampARB($0, $1, $2, $3)$z"; + case spirv: + return spirv_asm + { + OpCapability MinLod; + %sampled : __sampledType(T) = OpImageSampleImplicitLod $this $location None|ConstOffset|MinLod $offset $clamp; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + [__readNone] + __target_intrinsic(hlsl) + T Sample(vector<float, Shape.dimensions+isArray> location, vector<int, Shape.planeDimensions> offset, float clamp, out uint status) + { + status = 0; + return Sample(location, offset, clamp); + } + + [__readNone] + T SampleBias(vector<float, Shape.dimensions+isArray> location, float bias) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleBias"; + case glsl: + __intrinsic_asm "$ctexture($0, $1, $2)$z"; + case spirv: + return spirv_asm + { + %sampled : __sampledType(T) = OpImageSampleImplicitLod $this $location None|Bias $bias; + __truncate $$T result __sampledType(T) %sampled; + + }; + } + } + + [__readNone] + T SampleBias(vector<float, Shape.dimensions+isArray> location, float bias, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleBias"; + case glsl: + __intrinsic_asm "$ctextureOffset($0, $1, $3, $2)$z"; + case spirv: + return spirv_asm + { + %sampled : __sampledType(T) = OpImageSampleImplicitLod $this $location None|Bias|ConstOffset $bias $offset; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + __target_intrinsic(glsl, "texture($0, $1)") + float __glsl_texture(vector<float, Shape.dimensions+isArray+1> value); + + __glsl_extension(GL_EXT_texture_shadow_lod) + __target_intrinsic(glsl, "textureOffset($0, $1, $2)") + float __glsl_texture_offset(vector<float, Shape.dimensions+isArray+1> value, constexpr vector<int, Shape.planeDimensions> offset); + + __glsl_extension(GL_EXT_texture_shadow_lod) + __target_intrinsic(glsl, "textureLod($0, $1, 0)") + float __glsl_texture_level_zero(vector<float, Shape.dimensions+isArray+1> value); + + __glsl_extension(GL_EXT_texture_shadow_lod) + __target_intrinsic(glsl, "textureLodOffset($0, $1, 0, $2)") + float __glsl_texture_offset_level_zero(vector<float, Shape.dimensions+isArray+1> value, constexpr vector<int, Shape.planeDimensions> offset); + + [__readNone] + [ForceInline] + float SampleCmp(vector<float, Shape.dimensions+isArray> location, float compareValue) + { + __target_switch + { + case glsl: + __glsl_texture(__makeVector(location, compareValue)); + case hlsl: + __intrinsic_asm ".SampleCmp"; + } + } + + [__readNone] + [ForceInline] + float SampleCmpLevelZero(vector<float, Shape.dimensions+isArray> location, float compareValue) + { + __target_switch + { + case glsl: + __glsl_texture_level_zero(__makeVector(location, compareValue)); + case hlsl: + __intrinsic_asm ".SampleCmpLevelZero"; + } + } + + [__readNone] + [ForceInline] + float SampleCmp(vector<float, Shape.dimensions+isArray> location, float compareValue, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case glsl: + __glsl_texture_offset(__makeVector(location, compareValue), offset); + case hlsl: + __intrinsic_asm ".SampleCmp"; + } + } + + [__readNone] + [ForceInline] + float SampleCmpLevelZero(vector<float, Shape.dimensions+isArray> location, float compareValue, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case glsl: + __glsl_texture_offset_level_zero(__makeVector(location, compareValue), offset); + case hlsl: + __intrinsic_asm ".SampleCmpLevelZero"; + } + } + + [__readNone] + T SampleGrad(vector<float, Shape.dimensions+isArray> location, vector<float, Shape.planeDimensions> gradX, vector<float, Shape.planeDimensions> gradY) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleGrad"; + case glsl: + __intrinsic_asm "$ctextureGrad($0, $1, $2, $3)$z"; + case spirv: + return spirv_asm + { + %sampled : __sampledType(T) = OpImageSampleExplicitLod $this $location None|Grad $gradX $gradY; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + [__readNone] + T SampleGrad(vector<float, Shape.dimensions+isArray> location, vector<float, Shape.planeDimensions> gradX, vector<float, Shape.planeDimensions> gradY, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleGrad"; + case glsl: + __intrinsic_asm "$ctextureGradOffset($0, $1, $2, $3, $4)$z"; + case spirv: + return spirv_asm + { + %sampled : __sampledType(T) = OpImageSampleExplicitLod $this $location None|Grad|ConstOffset $gradX $gradY $offset; + __truncate $$T result __sampledType(T) %sampled; + + }; + } + } + + __glsl_extension(GL_ARB_sparse_texture_clamp) + [__readNone] + T SampleGrad(vector<float, Shape.dimensions+isArray> location, vector<float, Shape.planeDimensions> gradX, vector<float, Shape.planeDimensions> gradY, constexpr vector<int, Shape.planeDimensions> offset, float lodClamp) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleGrad"; + case glsl: + __intrinsic_asm "$ctextureGradOffsetClampARB($0, $1, $2, $3, $4, $5)$z"; + case spirv: + return spirv_asm + { + OpCapability MinLod; + %sampled : __sampledType(T) = OpImageSampleExplicitLod $this $location None|Grad|ConstOffset|MinLod $gradX $gradY $offset $lodClamp; + __truncate $$T result __sampledType(T) %sampled; + + }; + } + } + + [__readNone] + T SampleLevel(vector<float, Shape.dimensions+isArray> location, float level) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleLevel"; + case glsl: + __intrinsic_asm "$ctextureLod($0, $1, $2)$z"; + case cuda: + if (isArray != 0) + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "tex1DLayeredLod<$T0>($0, ($1).x, int(($1).y), ($2))"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "tex2DLayeredLod<$T0>($0, ($1).x, ($1).y, int(($1).z), ($2))"; + case $(SLANG_TEXTURE_CUBE): + __intrinsic_asm "texCubemapLayeredLod<$T0>($0, ($1).x, ($1).y, ($1).z, int(($1).w), ($2))"; + default: + __intrinsic_asm "<invalid intrinsic>"; + } + } + else + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "tex1DLod<$T0>($0, ($1), ($2))"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "tex2DLod<$T0>($0, ($1).x, ($1).y, ($2))"; + case $(SLANG_TEXTURE_3D): + __intrinsic_asm "tex3DLod<$T0>($0, ($1).x, ($1).y, ($1).z, ($2))"; + case $(SLANG_TEXTURE_CUBE): + __intrinsic_asm "texCubemapLod<$T0>($0, ($1).x, ($1).y, ($1).z, ($2))"; + } + } + case spirv: + return spirv_asm + { + %sampled : __sampledType(T) = OpImageSampleExplicitLod $this $location None|Lod $level; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + [__readNone] + T SampleLevel(vector<float, Shape.dimensions+isArray> location, float level, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleLevel"; + case glsl: + __intrinsic_asm "$ctextureLodOffset($0, $1, $2, $3)$z"; + case spirv: + return spirv_asm + { + %sampled : __sampledType(T) = OpImageSampleExplicitLod $this $location None|Lod|ConstOffset $level $offset; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } +} + +// Non-combined texture types specific functions +__generic<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let format:int> +extension __TextureImpl<T,Shape,isArray,isMS,sampleCount,access,isShadow,0,format> +{ + typealias TextureCoord = vector<float, Shape.dimensions>; + + __target_intrinsic(glsl, "textureQueryLod($p, $2).x") + float CalculateLevelOfDetail(SamplerState s, TextureCoord location); + + __target_intrinsic(glsl, "textureQueryLod($p, $2).y") + float CalculateLevelOfDetailUnclamped(SamplerState s, TextureCoord location); + + [__readNone] + T Sample(SamplerState s, vector<float, Shape.dimensions+isArray> location) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Sample"; + case glsl: + __intrinsic_asm "$ctexture($p, $2)$z"; + case cuda: + if (isArray != 0) + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "tex1DLayered<$T0>($0, ($2).x, int(($2).y))"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "tex2DLayered<$T0>($0, ($2).x, ($2).y, int(($2).z))"; + case $(SLANG_TEXTURE_CUBE): + __intrinsic_asm "texCubemapLayered<$T0>($0, ($2).x, ($2).y, ($2).z, int(($2).w))"; + default: + __intrinsic_asm "<invalid intrinsic>"; + } + } + else + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "tex1D<$T0>($0, ($2))"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "tex2D<$T0>($0, ($2).x, ($2).y)"; + case $(SLANG_TEXTURE_3D): + __intrinsic_asm "tex3D<$T0>($0, ($2).x, ($2).y, ($2).z)"; + case $(SLANG_TEXTURE_CUBE): + __intrinsic_asm "texCubemap<$T0>($0, ($2).x, ($2).y, ($2).z)"; + } + } + case spirv: + return spirv_asm + { + %sampledImage : __sampledImageType(this) = OpSampledImage $this $s; + %sampled : __sampledType(T) = OpImageSampleImplicitLod %sampledImage $location None; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + [__readNone] + T Sample(SamplerState s, vector<float, Shape.dimensions+isArray> location, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Sample"; + case glsl: + __intrinsic_asm "$ctextureOffset($p, $2, $3)$z"; + case spirv: + return spirv_asm + { + %sampledImage : __sampledImageType(this) = OpSampledImage $this $s; + %sampled : __sampledType(T) = OpImageSampleImplicitLod %sampledImage $location None|ConstOffset $offset; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + [__readNone] + __glsl_extension(GL_ARB_sparse_texture_clamp) + T Sample(SamplerState s, vector<float, Shape.dimensions+isArray> location, constexpr vector<int, Shape.planeDimensions> offset, float clamp) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Sample"; + case glsl: + __intrinsic_asm "$ctextureOffsetClampARB($p, $2, $3, $4)$z"; + case spirv: + return spirv_asm + { + OpCapability MinLod; + %sampledImage : __sampledImageType(this) = OpSampledImage $this $s; + %sampled : __sampledType(T) = OpImageSampleImplicitLod %sampledImage $location None|ConstOffset|MinLod $offset $clamp; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + [__readNone] + __target_intrinsic(hlsl) + T Sample(SamplerState s, vector<float, Shape.dimensions+isArray> location, constexpr vector<int, Shape.planeDimensions> offset, float clamp, out uint status) + { + status = 0; + return Sample(s, location, offset, clamp); + } + + [__readNone] + T SampleBias(SamplerState s, vector<float, Shape.dimensions+isArray> location, float bias) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleBias"; + case glsl: + __intrinsic_asm "$ctexture($p, $2, $3)$z"; + case spirv: + return spirv_asm + { + %sampledImage : __sampledImageType(this) = OpSampledImage $this $s; + %sampled : __sampledType(T) = OpImageSampleImplicitLod %sampledImage $location None|Bias $bias; + __truncate $$T result __sampledType(T) %sampled; + + }; + } + } + + [__readNone] + T SampleBias(SamplerState s, vector<float, Shape.dimensions+isArray> location, float bias, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleBias"; + case glsl: + __intrinsic_asm "$ctextureOffset($p, $2, $4, $3)$z"; + case spirv: + return spirv_asm + { + %sampledImage : __sampledImageType(this) = OpSampledImage $this $s; + %sampled : __sampledType(T) = OpImageSampleImplicitLod %sampledImage $location None|Bias|ConstOffset $bias $offset; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + __target_intrinsic(glsl, "texture($p, $2)") + float __glsl_texture(SamplerComparisonState s, vector<float, Shape.dimensions+isArray+1> value); + + __glsl_extension(GL_EXT_texture_shadow_lod) + __target_intrinsic(glsl, "textureOffset($p, $2, $3)") + float __glsl_texture_offset(SamplerComparisonState s, vector<float, Shape.dimensions+isArray+1> value, constexpr vector<int, Shape.planeDimensions> offset); + + __glsl_extension(GL_EXT_texture_shadow_lod) + __target_intrinsic(glsl, "textureLod($p, $2, 0)") + float __glsl_texture_level_zero(SamplerComparisonState s, vector<float, Shape.dimensions+isArray+1> value); + + __glsl_extension(GL_EXT_texture_shadow_lod) + __target_intrinsic(glsl, "textureLodOffset($p, $2, 0, $3)") + float __glsl_texture_offset_level_zero(SamplerComparisonState s, vector<float, Shape.dimensions+isArray+1> value, constexpr vector<int, Shape.planeDimensions> offset); + + [__readNone] [ForceInline] + float SampleCmp(SamplerComparisonState s, vector<float, Shape.dimensions+isArray> location, float compareValue) + { + __target_switch + { + case glsl: + return __glsl_texture(s, __makeVector(location,compareValue)); + case hlsl: + __intrinsic_asm ".SampleCmp"; + } + } + + [__readNone] [ForceInline] + float SampleCmpLevelZero(SamplerComparisonState s, vector<float, Shape.dimensions+isArray> location, float compareValue) + { + __target_switch + { + case glsl: + return __glsl_texture_level_zero(s, __makeVector(location,compareValue)); + case hlsl: + __intrinsic_asm ".SampleCmpLevelZero"; + } + } + + [__readNone] [ForceInline] + float SampleCmp(SamplerComparisonState s, vector<float, Shape.dimensions+isArray> location, float compareValue, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case glsl: + return __glsl_texture_offset(s, __makeVector(location,compareValue), offset); + case hlsl: + __intrinsic_asm ".SampleCmpLevelZero"; + } + } + + [__readNone] [ForceInline] + float SampleCmpLevelZero(SamplerComparisonState s, vector<float, Shape.dimensions+isArray> location, float compareValue, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case glsl: + return __glsl_texture_offset_level_zero(s, __makeVector(location,compareValue), offset); + case hlsl: + __intrinsic_asm ".SampleCmpLevelZero"; + } + } + + [__readNone] + T SampleGrad(SamplerState s, vector<float, Shape.dimensions+isArray> location, vector<float, Shape.planeDimensions> gradX, vector<float, Shape.planeDimensions> gradY) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleGrad"; + case glsl: + __intrinsic_asm "$ctextureGrad($p, $2, $3, $4)$z"; + case spirv: + return spirv_asm + { + %sampledImage : __sampledImageType(this) = OpSampledImage $this $s; + %sampled : __sampledType(T) = OpImageSampleExplicitLod %sampledImage $location None|Grad $gradX $gradY; + __truncate $$T result __sampledType(T) %sampled; + + }; + } + } + + [__readNone] + T SampleGrad(SamplerState s, vector<float, Shape.dimensions+isArray> location, vector<float, Shape.planeDimensions> gradX, vector<float, Shape.planeDimensions> gradY, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleGrad"; + case glsl: + __intrinsic_asm "$ctextureGradOffset($p, $2, $3, $4, $5)$z"; + case spirv: + return spirv_asm + { + %sampledImage : __sampledImageType(this) = OpSampledImage $this $s; + %sampled : __sampledType(T) = OpImageSampleExplicitLod %sampledImage $location None|Grad|ConstOffset $gradX $gradY $offset; + __truncate $$T result __sampledType(T) %sampled; + + }; + } + } + + __glsl_extension(GL_ARB_sparse_texture_clamp) + [__readNone] + T SampleGrad(SamplerState s, vector<float, Shape.dimensions+isArray> location, vector<float, Shape.planeDimensions> gradX, vector<float, Shape.planeDimensions> gradY, constexpr vector<int, Shape.planeDimensions> offset, float lodClamp) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleGrad"; + case glsl: + __intrinsic_asm "$ctextureGradOffsetClampARB($p, $2, $3, $4, $5, $6)$z"; + case spirv: + return spirv_asm + { + OpCapability MinLod; + %sampledImage : __sampledImageType(this) = OpSampledImage $this $s; + %sampled : __sampledType(T) = OpImageSampleExplicitLod %sampledImage $location None|Grad|ConstOffset|MinLod $gradX $gradY $offset $lodClamp; + __truncate $$T result __sampledType(T) %sampled; + + }; + } + } + + [__readNone] + T SampleLevel(SamplerState s, vector<float, Shape.dimensions+isArray> location, float level) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleLevel"; + case glsl: + __intrinsic_asm "$ctextureLod($p, $2, $3)$z"; + case cuda: + if (isArray != 0) + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "tex1DLayeredLod<$T0>($0, ($2).x, int(($2).y), ($3))"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "tex2DLayeredLod<$T0>($0, ($2).x, ($2).y, int(($2).z), ($3))"; + case $(SLANG_TEXTURE_CUBE): + __intrinsic_asm "texCubemapLayeredLod<$T0>($0, ($2).x, ($2).y, ($2).z, int(($2).w), ($3))"; + default: + __intrinsic_asm "<invalid intrinsic>"; + } + } + else + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "tex1DLod<$T0>($0, ($2), ($3))"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "tex2DLod<$T0>($0, ($2).x, ($2).y, ($3))"; + case $(SLANG_TEXTURE_3D): + __intrinsic_asm "tex3DLod<$T0>($0, ($2).x, ($2).y, ($2).z, ($3))"; + case $(SLANG_TEXTURE_CUBE): + __intrinsic_asm "texCubemapLod<$T0>($0, ($2).x, ($2).y, ($2).z, ($3))"; + } + } + case spirv: + return spirv_asm + { + %sampledImage : __sampledImageType(this) = OpSampledImage $this $s; + %sampled : __sampledType(T) = OpImageSampleExplicitLod %sampledImage $location None|Lod $level; + __truncate $$T result __sampledType(T) %sampled; + + }; + } + } + + [__readNone] + T SampleLevel(SamplerState s, vector<float, Shape.dimensions+isArray> location, float level, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".SampleLevel"; + case glsl: + __intrinsic_asm "$ctextureLodOffset($p, $2, $3, $4)$z"; + case spirv: + return spirv_asm + { + %sampledImage : __sampledImageType(this) = OpSampledImage $this $s; + %sampled : __sampledType(T) = OpImageSampleExplicitLod %sampledImage $location None|Lod|ConstOffset $level $offset; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } +} + +// Texture.GetDimensions +${{{{ +const char* kTextureShapeTypeNames[] = { + "__Shape1D", "__Shape2D", "__Shape3D", "__ShapeCube"}; +for (int shapeIndex = 0; shapeIndex < 4; shapeIndex++) +for (int isArray = 0; isArray <= 1; isArray++) +for (int isMS = 0; isMS <= 1; isMS++) { + if (isMS) + { + if (shapeIndex != kStdlibShapeIndex2D) + continue; + } + if (isArray) + { + if (shapeIndex == kStdlibShapeIndex3D) + continue; + } + auto shapeTypeName = kTextureShapeTypeNames[shapeIndex]; + TextureTypeInfo textureTypeInfo(kBaseTextureShapes[shapeIndex], isArray, isMS, 0, sb, path); +}}}} + +__generic<T, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int> +extension __TextureImpl<T,$(shapeTypeName),$(isArray),$(isMS),sampleCount,access,isShadow,isCombined,format> +{ + ${{{{ + textureTypeInfo.writeGetDimensionFunctions(); + }}}} +} + +${{{{ +} +}}}} + +// Texture.GetSamplePosition(int s); +__generic<T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int> +extension __TextureImpl<T,Shape,isArray,1,sampleCount,access,isShadow,isCombined,format> +{ + float2 GetSamplePosition(int s); +} + +__intrinsic_op($(kIROp_MakeArray)) +Array<T,4> __makeArray<T>(T v0, T v1, T v2, T v3); + +// Gather for scalar textures. +__generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let access:int, let isShadow:int, let format:int> +[ForceInline] +vector<TElement,4> __glsl_gather(__TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerState s, vector<float, Shape.dimensions+isArray> location, int component) +{ + __target_switch + { + case glsl: + __intrinsic_asm "textureGather($p, $2, $3)"; + case spirv: + return spirv_asm { + %sampledImage : __sampledImageType(texture) = OpSampledImage $texture $s; + result:$$vector<TElement,4> = OpImageGather %sampledImage $location $component; + }; + } +} +__generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let access:int, let isShadow:int, let format:int> +[ForceInline] +vector<TElement,4> __glsl_gather_offset(__TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerState s, vector<float, Shape.dimensions+isArray> location, int component, vector<int, Shape.planeDimensions> offset) +{ + __target_switch + { + case glsl: + __intrinsic_asm "textureGatherOffset($p, $2, $3, $4)"; + case spirv: + return spirv_asm { + %sampledImage : __sampledImageType(texture) = OpSampledImage $texture $s; + result:$$vector<TElement,4> = OpImageGather %sampledImage $location $component ConstOffset $offset; + }; + } +} +__generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let access:int, let isShadow:int, let format:int> +[ForceInline] +vector<TElement,4> __glsl_gather_offsets(__TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerState s, vector<float, Shape.dimensions+isArray> location, int component, + vector<int, Shape.planeDimensions> offset1, + vector<int, Shape.planeDimensions> offset2, + vector<int, Shape.planeDimensions> offset3, + vector<int, Shape.planeDimensions> offset4) +{ + __target_switch + { + case glsl: + __intrinsic_asm "textureGatherOffsets($p, $2, $3, $T4[]($4, $5, $6, $7))"; + case spirv: + let offsets = __makeArray(offset1,offset2,offset3,offset4); + return spirv_asm { + OpCapability ImageGatherExtended; + %sampledImage : __sampledImageType(texture) = OpSampledImage $texture $s; + result:$$vector<TElement,4> = OpImageGather %sampledImage $location $component ConstOffsets $offsets; + }; + } +} +__generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let access:int, let isShadow:int, let format:int> +[ForceInline] +vector<TElement,4> __glsl_gatherCmp(__TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerComparisonState s, vector<float, Shape.dimensions+isArray> location, int componentIndex, TElement compareValue) +{ + __target_switch + { + case glsl: + __intrinsic_asm "textureGather($p, $2, $4)"; + case spirv: + return spirv_asm { + %sampledImage : __sampledImageType(texture) = OpSampledImage $texture $s; + result:$$vector<TElement,4> = OpImageDrefGather %sampledImage $location $compareValue; + }; + } +} +__generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let access:int, let isShadow:int, let format:int> +[ForceInline] +vector<TElement,4> __glsl_gatherCmp_offset(__TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerComparisonState s, vector<float, Shape.dimensions+isArray> location, int componentIndex, TElement compareValue, vector<int, Shape.planeDimensions> offset) +{ + __target_switch + { + case glsl: + __intrinsic_asm "textureGatherOffset($p, $2, $4, $5)"; + case spirv: + return spirv_asm { + %sampledImage : __sampledImageType(texture) = OpSampledImage $texture $s; + result:$$vector<TElement,4> = OpImageDrefGather %sampledImage $location $compareValue ConstOffset $offset; + }; + } +} +__generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let access:int, let isShadow:int, let format:int> +[ForceInline] +vector<TElement,4> __glsl_gatherCmp_offsets(__TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerComparisonState s, vector<float, Shape.dimensions+isArray> location, int componentIndex, TElement compareValue, + vector<int, Shape.planeDimensions> offset1, + vector<int, Shape.planeDimensions> offset2, + vector<int, Shape.planeDimensions> offset3, + vector<int, Shape.planeDimensions> offset4 + ) +{ + __target_switch + { + case glsl: + __intrinsic_asm "textureGatherOffsets($p, $2, $4, $T5[]($5, $6, $7, $8))"; + case spirv: + let offsets = __makeArray(offset1,offset2,offset3,offset4); + return spirv_asm { + OpCapability ImageGatherExtended; + %sampledImage : __sampledImageType(texture) = OpSampledImage $texture $s; + result:$$vector<TElement,4> = OpImageDrefGather %sampledImage $location $compareValue ConstOffsets $offsets; + }; + } +} + +${{{{ +for (int isScalarTexture = 0; isScalarTexture <= 1; isScalarTexture++) { + if (isScalarTexture == 0) + { + sb << "__generic<T:__BuiltinArithmeticType, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let format:int>\n"; + sb << "extension __TextureImpl<T,Shape,isArray,0,sampleCount,0,isShadow,0,format>\n"; + } + else + { + sb << "__generic<T:__BuiltinArithmeticType, let N:int, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let format:int>\n"; + sb << "extension __TextureImpl<vector<T,N>,Shape,isArray,0,sampleCount,0,isShadow,0,format>\n"; + } +}}}} +{ // begin extension for gather +${{{{ + // Gather component + for (int isCmp = 0; isCmp <= 1; ++isCmp) { + const char* cmp = isCmp ? "Cmp" : ""; + const char* cmpParam = isCmp? "T compareValue, " : ""; + const char* compareArg = isCmp ? "compareValue, " : ""; + const char* samplerStateType = isCmp ? "SamplerComparisonState" : "SamplerState"; + const char* componentNames[] = {"", "Red", "Green", "Blue", "Alpha"}; + for (auto componentId = 0; componentId < 4; componentId++) { + auto component = componentNames[componentId]; + auto componentIndex = componentId == 0 ? 0 : componentId - 1; + }}}} + [ForceInline] + vector<T,4> Gather$(cmp)$(component)($(samplerStateType) s, vector<float, Shape.dimensions+isArray> location, $(cmpParam)) + { + __target_switch + { + case hlsl: __intrinsic_asm ".Gather$(cmp)$(component)"; + case glsl: + case spirv: + return __glsl_gather$(cmp)<T>(this, s, location, $(componentIndex), $(compareArg)); + } + } + [ForceInline] + vector<T,4> Gather$(cmp)$(component)($(samplerStateType) s, vector<float, Shape.dimensions+isArray> location, $(cmpParam) vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case hlsl: __intrinsic_asm ".Gather$(cmp)$(component)"; + case glsl: + case spirv: + return __glsl_gather$(cmp)_offset<T>(this, s, location, $(componentIndex), $(compareArg) offset); + } + } + [ForceInline] + vector<T,4> Gather$(cmp)$(component)($(samplerStateType) s, vector<float, Shape.dimensions+isArray> location, $(cmpParam) + vector<int, Shape.planeDimensions> offset1, + vector<int, Shape.planeDimensions> offset2, + vector<int, Shape.planeDimensions> offset3, + vector<int, Shape.planeDimensions> offset4) + { + __target_switch + { + case hlsl: __intrinsic_asm ".Gather$(cmp)$(component)"; + case glsl: + case spirv: + return __glsl_gather$(cmp)_offsets<T>(this, s, location, $(componentIndex), $(compareArg) offset1,offset2,offset3,offset4); + } + } + ${{{{ + } // for (component) + } // for (isCmp) + }}}} +} // end extension for gather + +${{{{ +} // for (isScalarTexture) +}}}} + +// Load/Subscript for readonly, no MS textures + +__generic<T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let isCombined:int, let format:int> +extension __TextureImpl<T,Shape,isArray,0,sampleCount,0,isShadow,isCombined,format> +{ + static const int isMS = 0; + static const int access = $(kStdlibResourceAccessReadOnly); + + __glsl_extension(GL_EXT_samplerless_texture_functions) + [__readNone] + T __glsl_load(vector<int, Shape.dimensions+isArray> location) + { + __intrinsic_asm "$ctexelFetch($0, ($1), 0)$z"; + } + + __glsl_extension(GL_EXT_samplerless_texture_functions) + [__readNone] + [ForceInline] + T Load(vector<int, Shape.dimensions+isArray+1> location) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Load"; + case glsl: + __intrinsic_asm "$ctexelFetch($0, ($1).$w1b, ($1).$w1e)$z"; + case spirv: + const int lodLoc = Shape.dimensions+isArray; + let coord = __vectorReshape<Shape.dimensions+isArray>(location); + let lod = location[lodLoc]; + if (isCombined != 0) + { + return spirv_asm + { + %image:__imageType(this) = OpImage $this; + %sampled:__sampledType(T) = OpImageFetch %image $coord Lod $lod; + __truncate $$T result __sampledType(T) %sampled; + }; + } + else + { + return spirv_asm + { + %sampled:__sampledType(T) = OpImageFetch $this $coord Lod $lod; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + } + + __glsl_extension(GL_EXT_samplerless_texture_functions) + [__readNone] + [ForceInline] + T Load(vector<int, Shape.dimensions+isArray+1> location, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Load"; + case glsl: + __intrinsic_asm "$ctexelFetchOffset($0, ($1).$w1b, ($1).$w1e, ($2))$z"; + case spirv: + const int lodLoc = Shape.dimensions+isArray; + let coord = __vectorReshape<Shape.dimensions+isArray>(location); + let lod = location[lodLoc]; + if (isCombined != 0) + { + return spirv_asm + { + %image:__imageType(this) = OpImage $this; + %sampled:__sampledType(T) = OpImageFetch %image $coord Lod|ConstOffset $lod $offset; + __truncate $$T result __sampledType(T) %sampled; + }; + } + else + { + return spirv_asm + { + %sampled:__sampledType(T) = OpImageFetch $this $coord Lod|ConstOffset $lod $offset; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + } + + [__readNone] + [ForceInline] + __target_intrinsic(hlsl) + T Load(vector<int, Shape.dimensions+isArray+1> location, constexpr vector<int, Shape.planeDimensions> offset, out uint status) + { + status = 0; + return Load(location, offset); + } + + __subscript(vector<uint, Shape.dimensions+isArray> location) -> T + { + __glsl_extension(GL_EXT_samplerless_texture_functions) + [__readNone] + [ForceInline] + get + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".operator[]"; + case glsl: + return __glsl_load(location); + case spirv: + if (isCombined != 0) + { + return spirv_asm + { + %image:__imageType(this) = OpImage $this; + %sampled:__sampledType(T) = OpImageFetch %image $location; + __truncate $$T result __sampledType(T) %sampled; + }; + } + else + { + return spirv_asm + { + %sampled:__sampledType(T) = OpImageFetch $this $location; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + } + } +} + +// Texture Load/Subscript for readonly, MS textures + +__generic<T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let isCombined:int, let format:int> +extension __TextureImpl<T,Shape,isArray,1,sampleCount,0,isShadow,isCombined,format> +{ + static const int access = $(kStdlibResourceAccessReadOnly); + static const int isMS = 1; + + __glsl_extension(GL_EXT_samplerless_texture_functions) + [__readNone] + [ForceInline] + T Load(vector<int, Shape.dimensions+isArray> location, int sampleIndex) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Load"; + case glsl: + __intrinsic_asm "$ctexelFetch($0, $1, ($2))$z"; + case spirv: + if (isCombined != 0) + { + return spirv_asm + { + %image:__imageType(this) = OpImage $this; + %sampled:__sampledType(T) = OpImageFetch %image $location Sample $sampleIndex; + __truncate $$T result __sampledType(T) %sampled; + }; + } + else + { + return spirv_asm + { + %sampled:__sampledType(T) = OpImageFetch $this $location Sample $sampleIndex; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + } + + __glsl_extension(GL_EXT_samplerless_texture_functions) + [__readNone] + [ForceInline] + T Load(vector<int, Shape.dimensions+isArray> location, int sampleIndex, constexpr vector<int, Shape.planeDimensions> offset) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Load"; + case glsl: + __intrinsic_asm "$ctexelFetchOffset($0, $1, ($2), ($3))$z"; + case spirv: + if (isCombined != 0) + { + return spirv_asm + { + %image:__imageType(this) = OpImage $this; + %sampled:__sampledType(T) = OpImageFetch %image $location ConstOffset|Sample $offset $sampleIndex; + __truncate $$T result __sampledType(T) %sampled; + }; + } + else + { + return spirv_asm + { + %sampled:__sampledType(T) = OpImageFetch $this $location ConstOffset|Sample $offset $sampleIndex; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + } + + [__readNone] + [ForceInline] + __target_intrinsic(hlsl) + T Load(vector<int, Shape.dimensions+isArray> location, int sampleIndex, constexpr vector<int, Shape.planeDimensions> offset, out uint status) + { + status = 0; + return Load(location, sampleIndex, offset); + } + + __subscript(vector<uint, Shape.dimensions+isArray> location, int sampleIndex) -> T + { + __glsl_extension(GL_EXT_samplerless_texture_functions) + [__readNone] + [ForceInline] + get + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm "($0).sample[$2][$1]"; + case glsl: + case spirv: + case cuda: + return Load(location, sampleIndex); + } + } + } +} + +// Load/Subscript for readwrite textures +${{{{ + for (int access = kStdlibResourceAccessReadWrite; access<=kStdlibResourceAccessRasterizerOrdered; access++) { + const char* glslIntrinsic = "$cimageLoad($0, $1)$z"; + const char* glslIntrinsicOffset = "$cimageLoad($0, ($1)+($2))$z"; + const char* glslIntrinsicMS = "$cimageLoad($0, $1, $2)$z"; + const char* glslIntrinsicMSOffset = "$cimageLoad($0, ($1)+($3), $2)$z"; +}}}} +__generic<T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let format:int> +extension __TextureImpl<T,Shape,isArray,0,sampleCount,$(access),isShadow, 0,format> +{ + [__readNone] + [ForceInline] + T Load(vector<int, Shape.dimensions+isArray> location) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Load"; + case glsl: + __intrinsic_asm "$(glslIntrinsic)"; + case cuda: + if (isArray != 0) + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "surf1DLayeredread$C<$T0>($0, ($1).x * $E, ($1).y, SLANG_CUDA_BOUNDARY_MODE)"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "surf2DLayeredread$C<$T0>($0, ($1).x * $E, ($1).y, ($1).z, SLANG_CUDA_BOUNDARY_MODE)"; + case $(SLANG_TEXTURE_3D): + __intrinsic_asm "surf3DLayeredread$C<$T0>($0, ($1).x * $E, ($1).y, ($1).z, ($1).w, SLANG_CUDA_BOUNDARY_MODE)"; + default: + __intrinsic_asm "<invalid intrinsic>"; + } + } + else + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "surf1Dread$C<$T0>($0, ($1) * $E, SLANG_CUDA_BOUNDARY_MODE)"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "surf2Dread$C<$T0>($0, ($1).x * $E, ($1).y, SLANG_CUDA_BOUNDARY_MODE)"; + case $(SLANG_TEXTURE_3D): + __intrinsic_asm "surf3Dread$C<$T0>($0, ($1).x * $E, ($1).y, ($1).z, SLANG_CUDA_BOUNDARY_MODE)"; + default: + __intrinsic_asm "<invalid intrinsic>"; + } + } + case spirv: + return spirv_asm + { + %sampled:__sampledType(T) = OpImageRead $this $location; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + [__readNone] + [ForceInline] + T Load(vector<int, Shape.dimensions+isArray> location, vector<int, Shape.dimensions+isArray> offset) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Load"; + case glsl: + __intrinsic_asm "$(glslIntrinsicOffset)"; + case spirv: + return spirv_asm + { + %sampled:__sampledType(T) = OpImageRead $this $location ConstOffset $offset; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + [__readNone] + [ForceInline] + T Load(vector<int, Shape.dimensions+isArray> location, vector<int, Shape.dimensions+isArray> offset, out uint status) + { + __target_switch + { + case hlsl: + case cpp: + __intrinsic_asm ".Load"; + default: + status = 0; + return Load(location, offset); + } + } + + void __glslImageStore(vector<int, Shape.dimensions+isArray> location, T value) + { + __intrinsic_asm "imageStore($0, $1, $V2)"; + } + + __subscript(vector<uint, Shape.dimensions+isArray> location) -> T + { + [__readNone] + [ForceInline] + get + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".operator[]"; + case glsl: + case spirv: + case cuda: + return Load(location); + } + } + + [nonmutating] + [ForceInline] + set(T newValue) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".operator[]"; + case glsl: + __glslImageStore(location, newValue); + case cuda: + if (isArray != 0) + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "surf1DLayeredwrite$C<$T0>($2, $0, ($1).x * $E, ($1).y, SLANG_CUDA_BOUNDARY_MODE)"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "surf2DLayeredwrite$C<$T0>($2, $0, ($1).x * $E, ($1).y, ($1).z, SLANG_CUDA_BOUNDARY_MODE)"; + case $(SLANG_TEXTURE_3D): + __intrinsic_asm "surf3DLayeredwrite$C<$T0>($2, $0, ($1).x * $E, ($1).y, ($1).z, ($1).w, SLANG_CUDA_BOUNDARY_MODE)"; + default: + __intrinsic_asm "<invalid intrinsic>"; + } + } + else + { + switch(Shape.flavor) + { + case $(SLANG_TEXTURE_1D): + __intrinsic_asm "surf1Dwrite$C<$T0>($2, $0, ($1) * $E, SLANG_CUDA_BOUNDARY_MODE)"; + case $(SLANG_TEXTURE_2D): + __intrinsic_asm "surf2Dwrite$C<$T0>($2, $0, ($1).x * $E, ($1).y, SLANG_CUDA_BOUNDARY_MODE)"; + case $(SLANG_TEXTURE_3D): + __intrinsic_asm "surf3Dwrite$C<$T0>($2, $0, ($1).x * $E, ($1).y, ($1).z, SLANG_CUDA_BOUNDARY_MODE)"; + default: + __intrinsic_asm "<invalid intrinsic>"; + } + } + case spirv: + return spirv_asm + { + OpImageWrite $this $location $newValue; + }; + } + } + + __intrinsic_op($(kIROp_ImageSubscript)) ref; + } +} + +${{{{ +if (access == kStdlibResourceAccessReadWrite) { +}}}} +// RW MS textures. +__generic<T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let format:int> +extension __TextureImpl<T,Shape,isArray,1,sampleCount,$(access),isShadow, 0,format> +{ + [__readNone] + [ForceInline] + T Load(vector<int, Shape.dimensions+isArray> location, int sampleIndex) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Load"; + case glsl: + __intrinsic_asm "$(glslIntrinsicMS)"; + case spirv: + return spirv_asm + { + %sampled:__sampledType(T) = OpImageRead $this $location Sample $sampleIndex; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + [__readNone] + [ForceInline] + T Load(vector<int, Shape.dimensions+isArray> location, int sampleIndex, vector<int, Shape.dimensions+isArray> offset) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm ".Load"; + case glsl: + __intrinsic_asm "$(glslIntrinsicMSOffset)"; + case spirv: + return spirv_asm + { + %sampled:__sampledType(T) = OpImageRead $this $location ConstOffset|Sample $offset $sampleIndex; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } + + [__readNone] + [ForceInline] + T Load(vector<int, Shape.dimensions+isArray> location, int sampleIndex, vector<int, Shape.dimensions+isArray> offset, out uint status) + { + __target_switch + { + case hlsl: + case cpp: + __intrinsic_asm ".Load"; + default: + status = 0; + return Load(location, sampleIndex, offset); + } + } + + void __glslImageStore(vector<int, Shape.dimensions+isArray> location, int sampleIndex, T value) + { + __intrinsic_asm "imageStore($0, $1, $2, $V3)"; + } + + __subscript(vector<uint, Shape.dimensions+isArray> location, int sampleIndex) -> T + { + [__readNone] + [ForceInline] + get + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm "$0.sample[$2][$1]"; + case glsl: + case spirv: + case cuda: + return Load(location, sampleIndex); + } + } + + [nonmutating] + [ForceInline] + set(T newValue) + { + __target_switch + { + case cpp: + case hlsl: + __intrinsic_asm "$0.sample[$2][$1]"; + case glsl: + __glslImageStore(location, sampleIndex, newValue); + case spirv: + return spirv_asm + { + OpImageWrite $this $location $newValue Sample $sampleIndex; + }; + } + } + + __intrinsic_op($(kIROp_ImageSubscript)) ref; + } +} + +${{{{ +} // if (access == kStdlibResourceAccessReadWrite) // for RW MS textures. +} // for (access). +}}}} + +// Texture type aliases. +// T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int +${{{{ + const char* shapeTypeNames[] = {"1D", "2D", "3D", "Cube"}; + const char* accessPrefix[] = {"", "RW", "RasterizerOrdered", "Feedback"}; + const char* arrayPostFix[] = {"", "Array"}; + const char* msPostFix[] = {"", "MS"}; + for (int shape = 0; shape < 4; shape++) + for (int isArray = 0; isArray<=1; isArray++) + for (int isMS = 0; isMS<=1; isMS++) + for (int isCombined = 0; isCombined<=1; isCombined++) + for (int access = kStdlibResourceAccessReadOnly; access<=kStdlibResourceAccessFeedback; access++) { + if (access != kStdlibResourceAccessReadOnly) + { + // No RW Cube. + if (shape == kStdlibShapeIndexCube) continue; + } + if (access == kStdlibResourceAccessFeedback) + { + // Feedback only defined for Texture2D and Texture2DArray. + if (shape != 1) continue; + if (isMS) continue; + if (isCombined) continue; + } + if (isMS) + { + // Only Texture2DMS. + if (shape != kStdlibShapeIndex2D) + continue; + // Only Texture2DMS or RWTexture2DMS. + if (access >= kStdlibShapeIndex3D) + continue; + } + // No 3D Array. + if (shape == kStdlibShapeIndex3D && isArray == 1) + continue; + const char* textureTypeName = isCombined ? "Sampler" : "Texture"; +}}}} +typealias $(accessPrefix[access])$(textureTypeName)$(shapeTypeNames[shape])$(arrayPostFix[isArray])$(msPostFix[isMS])<T=float4, let sampleCount:int=0, let format:int=0> = __TextureImpl<T, __Shape$(shapeTypeNames[shape]), $(isArray), $(isMS), sampleCount, $(access), 0, $(isCombined), format>; +${{{{ +} +}}}} + // AtomicAdd // Make the GLSL atomicAdd available. @@ -4362,6 +5884,7 @@ __generic<let N : int> float noise(vector<float, N> x) /// is more semantically "correct." __glsl_extension(GL_EXT_nonuniform_qualifier) [__readNone] +[ForceInline] uint NonUniformResourceIndex(uint index) { __target_switch @@ -7289,8 +8812,6 @@ matrix<T,N,M> WaveMultiPrefixSum(matrix<T,N,M> value, uint4 mask); // `typedef`s to help with the fact that HLSL has been sorta-kinda case insensitive at various points typedef Texture2D texture2D; - - ${{{{ // Buffer types @@ -7308,19 +8829,21 @@ static const int kBaseBufferAccessLevelCount = sizeof(kBaseBufferAccessLevels) / for (int aa = 0; aa < kBaseBufferAccessLevelCount; ++aa) { auto access = kBaseBufferAccessLevels[aa].access; - bool isReadOnly = (access == SLANG_RESOURCE_ACCESS_READ); - auto flavor = TextureFlavor::create(TextureFlavor::Shape::ShapeBuffer, access).flavor; - sb << "__generic<T>\n"; - sb << "__magic_type(TextureType," << int(flavor) << ")\n"; - sb << "__intrinsic_type(" << (kIROp_TextureType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n"; - sb << "struct "; + sb << "__generic<T,let format:int=0>\n"; + sb << "typealias "; sb << kBaseBufferAccessLevels[aa].name; - sb << "Buffer {\n"; + sb << "Buffer = __TextureImpl<T, __ShapeBuffer, 0, 0, 0, " << aa << ", 0, 0, format>;\n"; + + bool isReadOnly = aa == 0; - char const* glslTextureSizeFunc = (access == SLANG_RESOURCE_ACCESS_READ) ? "textureSize" : "imageSize"; - char const* glslLoadFuncName = (access == SLANG_RESOURCE_ACCESS_READ) ? "texelFetch" : "imageLoad"; - char const* spvLoadInstName = (access == SLANG_RESOURCE_ACCESS_READ) ? "OpImageFetch" : "OpImageRead"; + char const* glslTextureSizeFunc = (isReadOnly) ? "textureSize" : "imageSize"; + char const* glslLoadFuncName = (isReadOnly) ? "texelFetch" : "imageLoad"; + char const* spvLoadInstName = (isReadOnly) ? "OpImageFetch" : "OpImageRead"; }}}} + +__generic<T, let format:int> +extension __TextureImpl<T, __ShapeBuffer, 0, 0, 0, $(aa), 0, 0, format> +{ [__readNone] void GetDimensions(out uint dim) { @@ -7380,10 +8903,10 @@ ${{{{ } // access != SLANG_RESOURCE_ACCESS_READ }}}} - } + } - }; + }; // end extension ${{{{ } }}}} @@ -8164,29 +9687,9 @@ __target_intrinsic(hlsl, SAMPLER_FEEDBACK_MIP_REGION_USED) struct SAMPLER_FEEDBACK_MIP_REGION_USED : __BuiltinSamplerFeedbackType {}; // All of these objects are write-only resources that point to a special kind of unordered access view meant for sampler feedback. - -// Calculate the flavor constants -${{{{ -static const int feedbackTexture2DFlavor = int(TextureFlavor::create(TextureFlavor::Shape::Shape2D, SLANG_RESOURCE_ACCESS_WRITE, SLANG_TEXTURE_FEEDBACK_FLAG).flavor); -static const int feedbackTexture2DArrayFlavor = int(TextureFlavor::create(TextureFlavor::Shape::Shape2D, SLANG_RESOURCE_ACCESS_WRITE, SLANG_TEXTURE_FEEDBACK_FLAG | SLANG_TEXTURE_ARRAY_FLAG).flavor); -}}}} - -__magic_type(TextureType, $(feedbackTexture2DFlavor)) -__intrinsic_type($(kIROp_TextureType + (feedbackTexture2DFlavor << kIROpMeta_OtherShift))) -struct FeedbackTexture2D<T : __BuiltinSamplerFeedbackType> +__generic<T:__BuiltinSamplerFeedbackType> +extension __TextureImpl<T,__Shape2D, 0, 0, 0, $(kStdlibResourceAccessFeedback), 0, 0, 0> { - __target_intrinsic - void GetDimensions(out uint width, out uint height); - - __target_intrinsic - void GetDimensions(uint mipLevel, out uint width, out uint height, out uint numberOfLevels); - - __target_intrinsic - void GetDimensions(out float width,out float height); - - __target_intrinsic - void GetDimensions(uint mipLevel, out float width,out float height, out float numberOfLevels); - // With Clamp __target_intrinsic(hlsl, "($0).WriteSamplerFeedback($1, $2, $3, $4)") @@ -8222,24 +9725,9 @@ struct FeedbackTexture2D<T : __BuiltinSamplerFeedbackType> void WriteSamplerFeedbackGrad<S>(Texture2D<S> tex, SamplerState samp, float2 location, float2 ddx, float2 ddy); }; - - -__magic_type(TextureType, $(feedbackTexture2DArrayFlavor)) -__intrinsic_type($(kIROp_TextureType + (feedbackTexture2DArrayFlavor << kIROpMeta_OtherShift))) -struct FeedbackTexture2DArray<T : __BuiltinSamplerFeedbackType> +__generic<T:__BuiltinSamplerFeedbackType> +extension __TextureImpl<T,__Shape2D, 1, 0, 0, $(kStdlibResourceAccessFeedback), 0, 0, 0> { - __target_intrinsic - void GetDimensions(out uint width,out uint height, out uint elements); - - __target_intrinsic - void GetDimensions(uint mipLevel, out uint width,out uint height, out uint elements, out uint numberOfLevels); - - __target_intrinsic - void GetDimensions(out float width,out float height, out float elements); - - __target_intrinsic - void GetDimensions(uint mipLevel, out float width,out float height, out float elements, out float numberOfLevels); - // With Clamp __target_intrinsic(hlsl, "($0).WriteSamplerFeedback($1, $2, $3, $4)") diff --git a/source/slang/slang-ast-dump.cpp b/source/slang/slang-ast-dump.cpp index 96a0afe6d..e05f0a455 100644 --- a/source/slang/slang-ast-dump.cpp +++ b/source/slang/slang-ast-dump.cpp @@ -435,13 +435,6 @@ struct ASTDumpContext ScopeWrite(this).getBuf() << "DeclCheckStateExt{" << extState.isBeingChecked() << ", " << Index(state) << "}"; } - void dump(TextureFlavor texFlavor) - { - m_buf.clear(); - m_buf << "TextureFlavor{" << Index(texFlavor.flavor) << "}"; - m_writer->emit(m_buf); - } - void dump(FeedbackType::Kind kind) { m_buf.clear(); diff --git a/source/slang/slang-ast-expr.h b/source/slang/slang-ast-expr.h index 5238cd4e2..b23b43430 100644 --- a/source/slang/slang-ast-expr.h +++ b/source/slang/slang-ast-expr.h @@ -658,6 +658,8 @@ public: SlangValueAddr, SlangType, SampledType, // __sampledType(T), this becomes a 4 vector of the component type of T + ImageType, // __imageType(texture), returns the equivalaent OpTypeImage of a given texture typed value. + SampledImageType, // __sampledImageType(texture), returns the equivalent OpTypeSampledImage of a given texture typed value. TruncateMarker, // __truncate, an invented instruction which coerces to the result type by truncating the element count EntryPoint, // __entryPoint, a placeholder for the id of a referencing entryPoint. BuiltinVar, diff --git a/source/slang/slang-ast-type.cpp b/source/slang/slang-ast-type.cpp index af4f6d124..e8d702062 100644 --- a/source/slang/slang-ast-type.cpp +++ b/source/slang/slang-ast-type.cpp @@ -770,10 +770,97 @@ FeedbackType::Kind FeedbackType::getKind() const return FeedbackType::Kind(magicMod->tag); } -TextureFlavor ResourceType::getFlavor() const +SlangResourceShape ResourceType::getBaseShape() +{ + auto shape = _getGenericTypeArg(getDeclRefBase(), 1); + if (as<TextureShape1DType>(shape)) + return SLANG_TEXTURE_1D; + else if (as<TextureShape2DType>(shape)) + return SLANG_TEXTURE_2D; + else if (as<TextureShape3DType>(shape)) + return SLANG_TEXTURE_3D; + else if (as<TextureShapeCubeType>(shape)) + return SLANG_TEXTURE_CUBE; + else if (as<TextureShapeBufferType>(shape)) + return SLANG_TEXTURE_BUFFER; + + return SLANG_RESOURCE_NONE; +} + +SlangResourceShape ResourceType::getShape() +{ + auto baseShape = (SlangResourceShape)getBaseShape(); + if (isArray()) + baseShape = (SlangResourceShape)((uint32_t)baseShape | SLANG_TEXTURE_ARRAY_FLAG); + if (isMultisample()) + baseShape = (SlangResourceShape)((uint32_t)baseShape | SLANG_TEXTURE_MULTISAMPLE_FLAG); + if (isShadow()) + baseShape = (SlangResourceShape)((uint32_t)baseShape | SLANG_TEXTURE_SHADOW_FLAG); + if (isFeedback()) + baseShape = (SlangResourceShape)((uint32_t)baseShape | SLANG_TEXTURE_FEEDBACK_FLAG); + return baseShape; +} + +bool ResourceType::isArray() +{ + auto isArray = _getGenericTypeArg(this, kStdlibTextureIsArrayParameterIndex); + if (auto constIntVal = as<ConstantIntVal>(isArray)) + return constIntVal->getValue() != 0; + return false; +} + +bool ResourceType::isMultisample() { - auto magicMod = getDeclRef().getDecl()->findModifier<MagicTypeModifier>(); - return TextureFlavor(magicMod->tag); + auto isMS = _getGenericTypeArg(this, kStdlibTextureIsMultisampleParameterIndex); + if (auto constIntVal = as<ConstantIntVal>(isMS)) + return constIntVal->getValue() != 0; + return false; +} + +bool ResourceType::isShadow() +{ + auto isShadow = _getGenericTypeArg(this, kStdlibTextureIsShadowParameterIndex); + if (auto constIntVal = as<ConstantIntVal>(isShadow)) + return constIntVal->getValue() != 0; + return false; +} + +bool ResourceType::isFeedback() +{ + auto access = _getGenericTypeArg(this, kStdlibTextureAccessParameterIndex); + if (auto constIntVal = as<ConstantIntVal>(access)) + return constIntVal->getValue() == kStdlibResourceAccessFeedback; + return false; +} + +bool ResourceType::isCombined() +{ + auto combined = _getGenericTypeArg(this, kStdlibTextureIsCombinedParameterIndex); + if (auto constIntVal = as<ConstantIntVal>(combined)) + return constIntVal->getValue() != 0; + return false; +} + +SlangResourceAccess ResourceType::getAccess() +{ + auto access = _getGenericTypeArg(this, kStdlibTextureAccessParameterIndex); + if (auto constIntVal = as<ConstantIntVal>(access)) + { + switch (constIntVal->getValue()) + { + case kStdlibResourceAccessReadOnly: + return SLANG_RESOURCE_ACCESS_READ; + case kStdlibResourceAccessReadWrite: + return SLANG_RESOURCE_ACCESS_READ_WRITE; + case kStdlibResourceAccessRasterizerOrdered: + return SLANG_RESOURCE_ACCESS_RASTER_ORDERED; + case kStdlibResourceAccessFeedback: + return SLANG_RESOURCE_ACCESS_FEEDBACK; + default: + break; + } + } + return SLANG_RESOURCE_ACCESS_NONE; } SamplerStateFlavor SamplerStateType::getFlavor() const @@ -792,9 +879,106 @@ Type* ResourceType::getElementType() return as<Type>(_getGenericTypeArg(this, 0)); } +void ResourceType::_toTextOverride(StringBuilder& out) +{ + auto tryPrintSimpleName = [&](String& outString) -> bool + { + StringBuilder resultSB; + auto access = getAccess(); + switch (access) + { + case SLANG_RESOURCE_ACCESS_READ: + break; + case SLANG_RESOURCE_ACCESS_READ_WRITE: + resultSB << "RW";; + break; + case SLANG_RESOURCE_ACCESS_RASTER_ORDERED: + resultSB << "RasterizerOrdered"; + break; + case SLANG_RESOURCE_ACCESS_FEEDBACK: + resultSB << "Feedback"; + break; + default: + return false; + } + auto combined = as<ConstantIntVal>(_getGenericTypeArg(this, 7)); + auto shapeVal = _getGenericTypeArg(this, 1); + if (!as<TextureShapeType>(shapeVal)) + return false; + auto shape = getBaseShape(); + if (!combined) + return false; + if (combined->getValue() != 0) + resultSB << "Sampler"; + else + { + if (shape == SLANG_TEXTURE_BUFFER) + resultSB << "Buffer"; + else + resultSB << "Texture"; + } + switch (shape) + { + case SLANG_TEXTURE_1D: + resultSB << "1D"; + break; + case SLANG_TEXTURE_2D: + resultSB << "2D"; + break; + case SLANG_TEXTURE_3D: + resultSB << "3D"; + break; + case SLANG_TEXTURE_CUBE: + resultSB << "Cube"; + break; + } + auto isArrayVal = as<ConstantIntVal>(_getGenericTypeArg(this, 2)); + if (!isArrayVal) + return false; + if (isArray()) + resultSB << "Array"; + auto isMultisampleVal = as<ConstantIntVal>(_getGenericTypeArg(this, 3)); + if (!isMultisampleVal) + return false; + if (isMultisample()) + resultSB << "MS"; + auto isShadowVal = as<ConstantIntVal>(_getGenericTypeArg(this, 6)); + if (!isShadowVal) + return false; + if (isShadow()) + return false; + auto elementType = getElementType(); + if (elementType) + { + resultSB << "<"; + resultSB << elementType->toString(); + auto sampleCount = _getGenericTypeArg(this, 4); + if (auto constIntVal = as<ConstantIntVal>(sampleCount)) + { + if (constIntVal->getValue() != 0) + resultSB << ", " << constIntVal->getValue(); + } + else + { + return false; + } + resultSB << ">"; + } + outString = resultSB.toString(); + return true; + }; + + String simpleName; + + if (tryPrintSimpleName(simpleName)) + out << simpleName; + else + DeclRefType::_toTextOverride(out); +} + Val* TextureTypeBase::getSampleCount() { - return as<Type>(_getGenericTypeArg(this, 1)); + return as<Type>(_getGenericTypeArg(this, 4)); } Type* removeParamDirType(Type* type) diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h index 638012652..214d80916 100644 --- a/source/slang/slang-ast-type.h +++ b/source/slang/slang-ast-type.h @@ -118,22 +118,47 @@ class FeedbackType : public BuiltinType Kind getKind() const; }; +class TextureShapeType : public BuiltinType +{ + SLANG_ABSTRACT_AST_CLASS(TextureShapeType) +}; + +class TextureShape1DType : public TextureShapeType +{ + SLANG_AST_CLASS(TextureShape1DType) +}; +class TextureShape2DType : public TextureShapeType +{ + SLANG_AST_CLASS(TextureShape2DType) +}; +class TextureShape3DType : public TextureShapeType +{ + SLANG_AST_CLASS(TextureShape3DType) +}; +class TextureShapeCubeType : public TextureShapeType +{ + SLANG_AST_CLASS(TextureShapeCubeType) +}; +class TextureShapeBufferType : public TextureShapeType +{ + SLANG_AST_CLASS(TextureShapeBufferType) +}; + // Resources that contain "elements" that can be fetched class ResourceType : public BuiltinType { SLANG_ABSTRACT_AST_CLASS(ResourceType) - TextureFlavor getFlavor() const; - - TextureFlavor::Shape getBaseShape() - { - return getFlavor().getBaseShape(); - } - bool isMultisample() { return getFlavor().isMultisample(); } - bool isArray() { return getFlavor().isArray(); } - SlangResourceShape getShape() const { return getFlavor().getShape(); } - SlangResourceAccess getAccess() { return getFlavor().getAccess(); } + bool isMultisample(); + bool isArray(); + bool isShadow(); + bool isFeedback(); + bool isCombined(); + SlangResourceShape getBaseShape(); + SlangResourceShape getShape(); + SlangResourceAccess getAccess(); Type* getElementType(); + void _toTextOverride(StringBuilder& out); }; class TextureTypeBase : public ResourceType @@ -143,21 +168,11 @@ class TextureTypeBase : public ResourceType Val* getSampleCount(); }; - - class TextureType : public TextureTypeBase { SLANG_AST_CLASS(TextureType) }; - -// This is a base type for texture/sampler pairs, -// as they exist in, e.g., GLSL -class TextureSamplerType : public TextureTypeBase -{ - SLANG_AST_CLASS(TextureSamplerType) -}; - // This is a base type for `image*` types, as they exist in GLSL class GLSLImageType : public TextureTypeBase { diff --git a/source/slang/slang-ast-val.cpp b/source/slang/slang-ast-val.cpp index 8afc6e689..e860e1ec6 100644 --- a/source/slang/slang-ast-val.cpp +++ b/source/slang/slang-ast-val.cpp @@ -810,6 +810,7 @@ Val* PolynomialIntVal::_substituteImplOverride(ASTBuilder* astBuilder, Substitut { int diff = 0; PolynomialIntValBuilder builder(astBuilder); + builder.constantTerm = getConstantTerm(); for (auto& term : getTerms()) { IntegerLiteralValue evaluatedTermConstFactor; @@ -835,6 +836,14 @@ Val* PolynomialIntVal::_substituteImplOverride(ASTBuilder* astBuilder, Substitut } else { + if (evaluatedTermParamFactors.getCount() == 1 && evaluatedTermParamFactors[0]->getPower() == 1) + { + if (auto polyTerm = as<PolynomialIntVal>(evaluatedTermParamFactors[0]->getParam())) + { + builder.addToPolynomialTerm(polyTerm, evaluatedTermConstFactor); + continue; + } + } auto newTerm = astBuilder->getOrCreate<PolynomialIntValTerm>( evaluatedTermConstFactor, evaluatedTermParamFactors.getArrayView()); builder.terms.add(newTerm); @@ -1335,14 +1344,19 @@ Val* WitnessLookupIntVal::_substituteImplOverride(ASTBuilder* astBuilder, Substi { int diff = 0; auto newWitness = getWitness()->substituteImpl(astBuilder, subst, &diff); - *ioDiff += diff; if (diff) { + *ioDiff += diff; auto witnessEntry = tryFoldOrNull(astBuilder, as<SubtypeWitness>(newWitness), getKey()); if (witnessEntry) + { return witnessEntry; + } + else + { + return astBuilder->getOrCreate<WitnessLookupIntVal>(getType(), newWitness, getKey()); + } } - // Nothing found: don't substitute. return this; } diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index e130275bb..7edf27b30 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -723,7 +723,11 @@ namespace Slang expr->loc = loc; if (auto declRefExpr = as<DeclRefExpr>(originalExpr)) expr->scope = declRefExpr->scope; - + else if (auto invokeExpr = as<InvokeExpr>(originalExpr)) + { + if (auto calleeDeclRefExpr = as<DeclRefExpr>(invokeExpr->originalFunctionExpr)) + expr->scope = calleeDeclRefExpr->scope; + } // Whether or not the implicit `this` is mutable depends // on the context in which it is used, and the lookup // logic will have computed an appropriate "mode" based @@ -2246,8 +2250,9 @@ namespace Slang Expr* SemanticsExprVisitor::visitInvokeExpr(InvokeExpr* expr) { // check the base expression first + if (!expr->originalFunctionExpr) + expr->originalFunctionExpr = expr->functionExpr; expr->functionExpr = CheckTerm(expr->functionExpr); - auto treatAsDifferentiableExpr = m_treatAsDifferentiableExpr; m_treatAsDifferentiableExpr = nullptr; // Next check the argument expressions @@ -4018,7 +4023,9 @@ namespace Slang operand.expr = typeExpr.exp; } else if(operand.flavor == SPIRVAsmOperand::SlangValue - || operand.flavor == SPIRVAsmOperand::SlangValueAddr) + || operand.flavor == SPIRVAsmOperand::SlangValueAddr + || operand.flavor == SPIRVAsmOperand::ImageType + || operand.flavor == SPIRVAsmOperand::SampledImageType) { // This is a $expr operand, check the expr operand.expr = dispatch(operand.expr); diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 7eebf1cac..d0efce0f5 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -1893,10 +1893,11 @@ void CLikeSourceEmitter::emitCallExpr(IRCall* inst, EmitOpInfo outerPrec) // We want to detect any call to an intrinsic operation, // that we can emit it directly without mangling, etc. UnownedStringSlice intrinsicDefinition; - if (findTargetIntrinsicDefinition(funcValue, intrinsicDefinition)) + auto resolvedFunc = getResolvedInstForDecorations(funcValue); + if (findTargetIntrinsicDefinition(resolvedFunc, intrinsicDefinition)) { // Make sure we register all required preludes for emit. - if (auto func = as<IRFunc>(getResolvedInstForDecorations(funcValue))) + if (auto func = as<IRFunc>(resolvedFunc)) { for (auto block : func->getBlocks()) { diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp index c48fa369d..95a6ea4ff 100644 --- a/source/slang/slang-emit-cpp.cpp +++ b/source/slang/slang-emit-cpp.cpp @@ -137,11 +137,8 @@ SlangResult CPPSourceEmitter::_calcCPPTextureTypeName(IRTextureTypeBase* texType case SLANG_RESOURCE_ACCESS_CONSUME: outName << "Consume"; break; - case SLANG_RESOURCE_ACCESS_WRITE: - if (texType->isFeedback()) - { - outName << "Feedback"; - } + case SLANG_RESOURCE_ACCESS_FEEDBACK: + outName << "Feedback"; break; default: SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled resource access mode"); @@ -150,11 +147,11 @@ SlangResult CPPSourceEmitter::_calcCPPTextureTypeName(IRTextureTypeBase* texType switch (texType->GetBaseShape()) { - case TextureFlavor::Shape::Shape1D: outName << "Texture1D"; break; - case TextureFlavor::Shape::Shape2D: outName << "Texture2D"; break; - case TextureFlavor::Shape::Shape3D: outName << "Texture3D"; break; - case TextureFlavor::Shape::ShapeCube: outName << "TextureCube"; break; - case TextureFlavor::Shape::ShapeBuffer: outName << "Buffer"; break; + case SLANG_TEXTURE_1D: outName << "Texture1D"; break; + case SLANG_TEXTURE_2D: outName << "Texture2D"; break; + case SLANG_TEXTURE_3D: outName << "Texture3D"; break; + case SLANG_TEXTURE_CUBE: outName << "TextureCube"; break; + case SLANG_TEXTURE_BUFFER: outName << "Buffer"; break; default: SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled resource shape"); return SLANG_FAIL; @@ -332,11 +329,7 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S if (auto texType = as<IRTextureTypeBase>(type)) { - // We don't support TextureSampler, so ignore that - if (texType->getOp() != kIROp_TextureSamplerType) - { - return _calcCPPTextureTypeName(texType, out); - } + return _calcCPPTextureTypeName(texType, out); } // If _getResourceTypePrefix returns something, we assume can output any specialization after it in order. diff --git a/source/slang/slang-emit-cuda.cpp b/source/slang/slang-emit-cuda.cpp index bd891928c..633b065c7 100644 --- a/source/slang/slang-emit-cuda.cpp +++ b/source/slang/slang-emit-cuda.cpp @@ -181,11 +181,7 @@ SlangResult CUDASourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, if (auto texType = as<IRTextureTypeBase>(type)) { - // We don't support TextureSampler, so ignore that - if (texType->getOp() != kIROp_TextureSamplerType) - { - return _calcCUDATextureTypeName(texType, out); - } + return _calcCUDATextureTypeName(texType, out); } switch (type->getOp()) diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp index 4a75e84a0..bbfefc75c 100644 --- a/source/slang/slang-emit-glsl.cpp +++ b/source/slang/slang-emit-glsl.cpp @@ -714,11 +714,11 @@ void GLSLSourceEmitter::_emitGLSLTextureOrTextureSamplerType(IRTextureTypeBase* m_writer->emit(baseName); switch (type->GetBaseShape()) { - case TextureFlavor::Shape::Shape1D: m_writer->emit("1D"); break; - case TextureFlavor::Shape::Shape2D: m_writer->emit("2D"); break; - case TextureFlavor::Shape::Shape3D: m_writer->emit("3D"); break; - case TextureFlavor::Shape::ShapeCube: m_writer->emit("Cube"); break; - case TextureFlavor::Shape::ShapeBuffer: m_writer->emit("Buffer"); break; + case SLANG_TEXTURE_1D: m_writer->emit("1D"); break; + case SLANG_TEXTURE_2D: m_writer->emit("2D"); break; + case SLANG_TEXTURE_3D: m_writer->emit("3D"); break; + case SLANG_TEXTURE_CUBE: m_writer->emit("Cube"); break; + case SLANG_TEXTURE_BUFFER: m_writer->emit("Buffer"); break; default: SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled resource shape"); break; @@ -2355,6 +2355,11 @@ void GLSLSourceEmitter::emitSimpleTypeImpl(IRType* type) // each of these IR opcodes. if (auto texType = as<IRTextureType>(type)) { + if (texType->isCombined()) + { + _emitGLSLTextureOrTextureSamplerType(texType, "sampler"); + return; + } switch (texType->getAccess()) { case SLANG_RESOURCE_ACCESS_READ_WRITE: @@ -2368,11 +2373,6 @@ void GLSLSourceEmitter::emitSimpleTypeImpl(IRType* type) } return; } - else if (auto textureSamplerType = as<IRTextureSamplerType>(type)) - { - _emitGLSLTextureOrTextureSamplerType(textureSamplerType, "sampler"); - return; - } else if (auto imageType = as<IRGLSLImageType>(type)) { _emitGLSLTextureOrTextureSamplerType(imageType, "image"); diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp index 9defc9adc..9b333c281 100644 --- a/source/slang/slang-emit-hlsl.cpp +++ b/source/slang/slang-emit-hlsl.cpp @@ -253,11 +253,8 @@ void HLSLSourceEmitter::_emitHLSLTextureType(IRTextureTypeBase* texType) m_writer->emit("Consume"); break; - case SLANG_RESOURCE_ACCESS_WRITE: - if (texType->isFeedback()) - { - m_writer->emit("Feedback"); - } + case SLANG_RESOURCE_ACCESS_FEEDBACK: + m_writer->emit("Feedback"); break; default: @@ -267,11 +264,11 @@ void HLSLSourceEmitter::_emitHLSLTextureType(IRTextureTypeBase* texType) switch (texType->GetBaseShape()) { - case TextureFlavor::Shape::Shape1D: m_writer->emit("Texture1D"); break; - case TextureFlavor::Shape::Shape2D: m_writer->emit("Texture2D"); break; - case TextureFlavor::Shape::Shape3D: m_writer->emit("Texture3D"); break; - case TextureFlavor::Shape::ShapeCube: m_writer->emit("TextureCube"); break; - case TextureFlavor::Shape::ShapeBuffer: m_writer->emit("Buffer"); break; + case SLANG_TEXTURE_1D: m_writer->emit("Texture1D"); break; + case SLANG_TEXTURE_2D: m_writer->emit("Texture2D"); break; + case SLANG_TEXTURE_3D: m_writer->emit("Texture3D"); break; + case SLANG_TEXTURE_CUBE: m_writer->emit("TextureCube"); break; + case SLANG_TEXTURE_BUFFER: m_writer->emit("Buffer"); break; default: SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled resource shape"); break; @@ -287,14 +284,11 @@ void HLSLSourceEmitter::_emitHLSLTextureType(IRTextureTypeBase* texType) } m_writer->emit("<"); emitType(texType->getElementType()); - if (texType->getOperandCount() == 2) + auto sampleCount = as<IRIntLit>(texType->getSampleCount()); + if (sampleCount->getValue() != 0) { - auto sampleCount = as<IRIntLit>(texType->getSampleCount()); - if (sampleCount->getValue() != 0) - { - m_writer->emit(", "); - m_writer->emit(sampleCount->getValue()); - } + m_writer->emit(", "); + m_writer->emit(sampleCount->getValue()); } m_writer->emit(" >"); } @@ -954,11 +948,6 @@ void HLSLSourceEmitter::emitSimpleTypeImpl(IRType* type) _emitHLSLTextureType(texType); return; } - else if (const auto textureSamplerType = as<IRTextureSamplerType>(type)) - { - SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "this target should see combined texture-sampler types"); - return; - } else if (auto imageType = as<IRGLSLImageType>(type)) { _emitHLSLTextureType(imageType); diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 19c46f373..4c802641d 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -1361,12 +1361,8 @@ struct SPIRVEmitContext case kIROp_TextureType: return ensureTextureType(inst, cast<IRTextureType>(inst)); case kIROp_SamplerStateType: + case kIROp_SamplerComparisonStateType: return emitOpTypeSampler(inst); - case kIROp_TextureSamplerType: - return emitOpTypeSampledImage( - inst, - ensureTextureType(nullptr, cast<IRTextureTypeBase>(inst)) - ); case kIROp_RaytracingAccelerationStructureType: requireSPIRVCapability(SpvCapabilityRayTracingKHR); @@ -1627,22 +1623,19 @@ struct SPIRVEmitContext SpvDim dim = SpvDim1D; // Silence uninitialized warnings from msvc... switch(inst->GetBaseShape()) { - case TextureFlavor::Shape1D: - case TextureFlavor::Shape1DArray: + case SLANG_TEXTURE_1D: dim = SpvDim1D; break; - case TextureFlavor::Shape2D: - case TextureFlavor::Shape2DArray: + case SLANG_TEXTURE_2D: dim = SpvDim2D; break; - case TextureFlavor::Shape3D: + case SLANG_TEXTURE_3D: dim = SpvDim3D; break; - case TextureFlavor::ShapeCube: - case TextureFlavor::ShapeCubeArray: + case SLANG_TEXTURE_CUBE: dim = SpvDimCube; break; - case TextureFlavor::ShapeBuffer: + case SLANG_TEXTURE_BUFFER: dim = SpvDimBuffer; break; } @@ -1717,6 +1710,24 @@ struct SPIRVEmitContext // // The op itself // + + if (inst->isCombined()) + { + auto imageType = emitOpTypeImage( + nullptr, + dropVector(sampledType), + dim, + SpvLiteralInteger::from32(depth), + SpvLiteralInteger::from32(arrayed), + SpvLiteralInteger::from32(ms), + SpvLiteralInteger::from32(sampled), + format + ); + return emitOpTypeSampledImage( + assignee, + imageType); + } + return emitOpTypeImage( assignee, dropVector(sampledType), @@ -4578,6 +4589,24 @@ struct SPIRVEmitContext emitOperand(ensureInst(sampledType)); break; } + case kIROp_SPIRVAsmOperandImageType: + case kIROp_SPIRVAsmOperandSampledImageType: + { + IRBuilder builder(m_irModule); + auto textureInst = as<IRTextureTypeBase>(operand->getValue()->getDataType()); + auto imageType = builder.getTextureType( + textureInst->getElementType(), + textureInst->getShapeInst(), + textureInst->getIsArrayInst(), + textureInst->getIsMultisampleInst(), + textureInst->getSampleCountInst(), + textureInst->getAccessInst(), + textureInst->getIsShadowInst(), + builder.getIntValue(builder.getIntType(), (operand->getOp() == kIROp_SPIRVAsmOperandSampledImageType ? 1 : 0)), + textureInst->getFormatInst()); + emitOperand(ensureInst(imageType)); + break; + } case kIROp_SPIRVAsmOperandBuiltinVar: { emitOperand(ensureInst(operand)); @@ -4774,7 +4803,7 @@ struct SPIRVEmitContext } else { - emitInstCustomOperandFunc( + last = emitInstCustomOperandFunc( opParent, assignedInst, opcode, diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 1ee5ba67c..bd7db604f 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -401,14 +401,16 @@ Result linkAndOptimizeIR( for (;;) { bool changed = false; - + auto b1 = dumpIRToString(irModule->getModuleInst()); dumpIRIfEnabled(codeGenContext, irModule, "BEFORE-SPECIALIZE"); if (!codeGenContext->isSpecializationDisabled()) changed |= specializeModule(irModule, codeGenContext->getSink()); if (codeGenContext->getSink()->getErrorCount() != 0) return SLANG_FAIL; dumpIRIfEnabled(codeGenContext, irModule, "AFTER-SPECIALIZE"); + auto b2 = dumpIRToString(irModule->getModuleInst()); + applySparseConditionalConstantPropagation(irModule, codeGenContext->getSink()); eliminateDeadCode(irModule); validateIRModuleIfEnabled(codeGenContext, irModule); @@ -420,9 +422,6 @@ Result linkAndOptimizeIR( // Unroll loops. if (codeGenContext->getSink()->getErrorCount() == 0) { - applySparseConditionalConstantPropagationForGlobalScope( - irModule, codeGenContext->getSink()); - if (!unrollLoopsInModule(irModule, codeGenContext->getSink())) return SLANG_FAIL; } @@ -587,11 +586,7 @@ Result linkAndOptimizeIR( sink); } - if(isKhronosTarget(targetRequest)) - { - // SPIR-V doesn't support 1-vectors - legalizeVectorTypes(irModule, sink); - } + legalizeVectorTypes(irModule, sink); // Once specialization and type legalization have been performed, // we should perform some of our basic optimization steps again, diff --git a/source/slang/slang-intrinsic-expand.cpp b/source/slang/slang-intrinsic-expand.cpp index f17f564c8..d65fdf8bb 100644 --- a/source/slang/slang-intrinsic-expand.cpp +++ b/source/slang/slang-intrinsic-expand.cpp @@ -351,47 +351,50 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor) SLANG_RELEASE_ASSERT(m_argCount >= 1); auto textureArg = m_args[0].get(); - - if (const auto baseTextureSamplerType = as<IRTextureSamplerType>(textureArg->getDataType())) - { - // If the base object (first argument) has a combined texture-sampler type, - // then we can simply use that argument as-is. - // - m_emitter->emitOperand(textureArg, getInfo(EmitOp::General)); - - // HACK: Because the target intrinsic strings are using indices based on the - // parameter list with the `SamplerState` parameter in place, seeing this opcode - // and this type tells us that we are about to have an off-by-one sort of - // situation. We quietly patch it up by offseting the index-based access for - // all the other operands. - // - m_argIndexOffset -= 1; - } - else if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType())) + + if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType())) { - // If the base object (first argument) has a texture type, then we expect - // the next argument to be a sampler to pair with it. - // - SLANG_RELEASE_ASSERT(m_argCount >= 2); - auto samplerArg = m_args[1].get(); - - // We will emit GLSL code to construct the corresponding combined texture/sampler - // type from the separate pieces. - // - m_emitter->emitTextureOrTextureSamplerType(baseTextureType, "sampler"); - if (auto samplerType = as<IRSamplerStateTypeBase>(samplerArg->getDataType())) + if (baseTextureType->isCombined()) { - if (as<IRSamplerComparisonStateType>(samplerType)) + // If the base object (first argument) has a combined texture-sampler type, + // then we can simply use that argument as-is. + // + m_emitter->emitOperand(textureArg, getInfo(EmitOp::General)); + + // HACK: Because the target intrinsic strings are using indices based on the + // parameter list with the `SamplerState` parameter in place, seeing this opcode + // and this type tells us that we are about to have an off-by-one sort of + // situation. We quietly patch it up by offseting the index-based access for + // all the other operands. + // + m_argIndexOffset -= 1; + } + else + { + // If the base object (first argument) has a texture type, then we expect + // the next argument to be a sampler to pair with it. + // + SLANG_RELEASE_ASSERT(m_argCount >= 2); + auto samplerArg = m_args[1].get(); + + // We will emit GLSL code to construct the corresponding combined texture/sampler + // type from the separate pieces. + // + m_emitter->emitTextureOrTextureSamplerType(baseTextureType, "sampler"); + if (auto samplerType = as<IRSamplerStateTypeBase>(samplerArg->getDataType())) { - m_writer->emit("Shadow"); + if (as<IRSamplerComparisonStateType>(samplerType)) + { + m_writer->emit("Shadow"); + } } - } - m_writer->emit("("); - m_emitter->emitOperand(textureArg, getInfo(EmitOp::General)); - m_writer->emit(","); - m_emitter->emitOperand(samplerArg, getInfo(EmitOp::General)); - m_writer->emit(")"); + m_writer->emit("("); + m_emitter->emitOperand(textureArg, getInfo(EmitOp::General)); + m_writer->emit(","); + m_emitter->emitOperand(samplerArg, getInfo(EmitOp::General)); + m_writer->emit(")"); + } } else { @@ -516,14 +519,10 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor) auto textureArg = m_args[0].get(); IRType* elementType = nullptr; - if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType())) + if (auto baseTextureType = as<IRTextureTypeBase>(textureArg->getDataType())) { elementType = baseTextureType->getElementType(); } - else if(auto baseTextureSamplerType = as<IRTextureSamplerType>(textureArg->getDataType())) - { - elementType = baseTextureSamplerType->getElementType(); - } else { SLANG_UNEXPECTED("bad format in intrinsic definition"); @@ -797,6 +796,31 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor) } break; + case 'w': + { + // Emit a swizzle of the argument. + Index argIndex = parseNat() + m_argIndexOffset; + SLANG_RELEASE_ASSERT((0 <= argIndex) && (argIndex < m_argCount)); + auto arg = m_args[argIndex]; + d = *cursor++; + auto vectorType = as<IRVectorType>(arg.get()->getDataType()); + auto vectorSize = as<IRIntLit>(vectorType->getElementCount())->getValue(); + const char swizzleNames[] = { 'x', 'y', 'z', 'w' }; + if (d == 'b') + { + // Emit the first half the vector up to the n-1'th element. + for (int i = 0; i < Math::Min(4, (int)vectorSize - 1); i++) + m_writer->emitChar(swizzleNames[i]); + } + else if (d == 'e') + { + // Emit the swizzle to get the last element. + if (vectorSize <= 4) + m_writer->emitChar(swizzleNames[vectorSize - 1]); + } + } + break; + default: SLANG_UNEXPECTED("bad format in intrinsic definition"); break; diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index 8f87d23e7..88d398070 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -133,23 +133,25 @@ INST(Nop, nop, 0, 0) INST(SamplerComparisonStateType, SamplerComparisonState, 0, HOISTABLE) INST_RANGE(SamplerStateTypeBase, SamplerStateType, SamplerComparisonStateType) + INST(TextureShape1DType, TextureShape1DType, 0, HOISTABLE) + INST(TextureShape2DType, TextureShape1DType, 0, HOISTABLE) + INST(TextureShape3DType, TextureShape1DType, 0, HOISTABLE) + INST(TextureShapeCubeType, TextureShape1DType, 0, HOISTABLE) + INST(TextureShapeBufferType, TextureShapeBufferType, 0, HOISTABLE) + // TODO: Why do we have all this hierarchy here, when everything // that actually matters is currently nested under `TextureTypeBase`? /* ResourceTypeBase */ /* ResourceType */ /* TextureTypeBase */ - // NOTE! TextureFlavor::Flavor is stored in 'other' bits for these types. /* TextureType */ - INST(TextureType, TextureType, 0, USE_OTHER | HOISTABLE) - /* TextureSamplerType */ - INST(TextureSamplerType, TextureSamplerType, 0, USE_OTHER | HOISTABLE) + INST(TextureType, TextureType, 8, HOISTABLE) /* GLSLImageType */ INST(GLSLImageType, GLSLImageType, 0, USE_OTHER | HOISTABLE) INST_RANGE(TextureTypeBase, TextureType, GLSLImageType) INST_RANGE(ResourceType, TextureType, GLSLImageType) INST_RANGE(ResourceTypeBase, TextureType, GLSLImageType) - /* UntypedBufferResourceType */ /* ByteAddressBufferTypeBase */ INST(HLSLByteAddressBufferType, ByteAddressBuffer, 0, HOISTABLE) @@ -1124,7 +1126,14 @@ INST(SPIRVAsmInst, SPIRVAsmInst, 1, 0) // A type function which returns the result type of sampling an image of // this component type INST(SPIRVAsmOperandSampledType, __sampledType, 1, HOISTABLE) -INST_RANGE(SPIRVAsmOperand, SPIRVAsmOperandLiteral, SPIRVAsmOperandSampledType) + + // A type function which returns the equivalent OpTypeImage type of sampled image value + INST(SPIRVAsmOperandImageType, __imageType, 1, HOISTABLE) + + // A type function which returns the equivalent OpTypeImage type of sampled image value + INST(SPIRVAsmOperandSampledImageType, __sampledImageType, 1, HOISTABLE) + +INST_RANGE(SPIRVAsmOperand, SPIRVAsmOperandLiteral, SPIRVAsmOperandSampledImageType) #undef PARENT diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 2869f7058..434f0305e 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -3274,7 +3274,16 @@ public: IRConstRefType* getConstRefType(IRType* valueType); IRPtrTypeBase* getPtrType(IROp op, IRType* valueType); IRPtrType* getPtrType(IROp op, IRType* valueType, IRIntegerValue addressSpace); - + IRTextureTypeBase* getTextureType( + IRType* elementType, + IRInst* shape, + IRInst* isArray, + IRInst* isMS, + IRInst* sampleCount, + IRInst* access, + IRInst* isShadow, + IRInst* isCombined, + IRInst* format); IRComPtrType* getComPtrType(IRType* valueType); /// Get a 'SPIRV literal' @@ -4063,6 +4072,8 @@ public: IRSPIRVAsmOperand* emitSPIRVAsmOperandBuiltinVar(IRInst* type, IRInst* builtinKind); IRSPIRVAsmOperand* emitSPIRVAsmOperandGLSL450Set(); IRSPIRVAsmOperand* emitSPIRVAsmOperandSampledType(IRType* elementType); + IRSPIRVAsmOperand* emitSPIRVAsmOperandImageType(IRInst* element); + IRSPIRVAsmOperand* emitSPIRVAsmOperandSampledImageType(IRInst* element); IRSPIRVAsmOperand* emitSPIRVAsmOperandTruncate(); IRSPIRVAsmOperand* emitSPIRVAsmOperandEntryPoint(); IRSPIRVAsmInst* emitSPIRVAsmInst(IRInst* opcode, List<IRInst*> operands); diff --git a/source/slang/slang-ir-lower-generic-call.cpp b/source/slang/slang-ir-lower-generic-call.cpp index aaa419b2e..c312d3c88 100644 --- a/source/slang/slang-ir-lower-generic-call.cpp +++ b/source/slang/slang-ir-lower-generic-call.cpp @@ -239,6 +239,13 @@ namespace Slang // If we see a call(specialize(gFunc, Targs), args), // translate it into call(gFunc, args, Targs). auto loweredFunc = specializeInst->getBase(); + + // Don't process intrinsic functions. + UnownedStringSlice intrinsicDef; + if (findTargetIntrinsicDefinition(getResolvedInstForDecorations(loweredFunc), + sharedContext->targetReq->getTargetCaps(), intrinsicDef)) + return; + // All callees should have already been lowered in lower-generic-functions pass. // For intrinsic generic functions, they are left as is, and we also need to ignore // them here. @@ -251,14 +258,6 @@ namespace Slang // All nested generic functions are supposed to be flattend before this pass. // If they are not, they represent an intrinsic function that should not be // modified in this pass. - auto innerMostFunc = findInnerMostSpecializingBase(static_cast<IRSpecialize*>(loweredFunc)); - if (innerMostFunc && innerMostFunc->getOp() == kIROp_Generic) - { - innerMostFunc = - findInnerMostGenericReturnVal(static_cast<IRGeneric*>(innerMostFunc)); - } - if (innerMostFunc->findDecoration<IRTargetIntrinsicDecoration>()) - return; SLANG_UNEXPECTED("Nested generics specialization."); } else if (loweredFunc->getOp() == kIROp_LookupWitness) diff --git a/source/slang/slang-ir-lower-generic-function.cpp b/source/slang/slang-ir-lower-generic-function.cpp index baedbbd22..1e15f4384 100644 --- a/source/slang/slang-ir-lower-generic-function.cpp +++ b/source/slang/slang-ir-lower-generic-function.cpp @@ -44,7 +44,8 @@ namespace Slang } SLANG_ASSERT(func); // Do not lower intrinsic functions. - if (!func->isDefinition() || func->findDecoration<IRTargetIntrinsicDecoration>()) + UnownedStringSlice intrinsicDef; + if (!func->isDefinition() || findTargetIntrinsicDefinition(func, sharedContext->targetReq->getTargetCaps(), intrinsicDef)) { sharedContext->loweredGenericFunctions[genericValue] = genericValue; return genericValue; diff --git a/source/slang/slang-ir-simplify-cfg.cpp b/source/slang/slang-ir-simplify-cfg.cpp index 127a515ce..ad10a8c48 100644 --- a/source/slang/slang-ir-simplify-cfg.cpp +++ b/source/slang/slang-ir-simplify-cfg.cpp @@ -943,6 +943,11 @@ bool simplifyCFG(IRModule* module, CFGSimplificationOptions options) bool simplifyCFG(IRGlobalValueWithCode* func, CFGSimplificationOptions options) { + if (auto genericFunc = as<IRGeneric>(func)) + { + if (auto inner = as<IRFunc>(findGenericReturnVal(genericFunc))) + processFunc(inner, options); + } return processFunc(func, options); } diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp index 2155ce499..7dbb02a71 100644 --- a/source/slang/slang-ir-spirv-legalize.cpp +++ b/source/slang/slang-ir-spirv-legalize.cpp @@ -298,7 +298,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase static void inferTextureFormat(IRInst* textureInst, IRTextureTypeBase* textureType) { - ImageFormat format = ImageFormat::unknown; + ImageFormat format = (ImageFormat)(textureType->getFormat()); if (auto decor = textureInst->findDecoration<IRFormatDecoration>()) { format = decor->getFormat(); @@ -390,15 +390,19 @@ struct SPIRVLegalizationContext : public SourceEmitterBase { IRBuilder builder(textureInst->getModule()); builder.setInsertBefore(textureInst); - List<IRInst*> args; - args.add(textureType->getOperand(0)); - if (textureType->getOperandCount() >= 2) - args.add(textureType->getOperand(1)); - else - args.add(builder.getIntValue(builder.getUIntType(), 0)); - args.add(builder.getIntValue(builder.getUIntType(), IRIntegerValue(format))); + auto formatArg = builder.getIntValue(builder.getUIntType(), IRIntegerValue(format)); + + auto newType = builder.getTextureType( + textureType->getElementType(), + textureType->getShapeInst(), + textureType->getIsArrayInst(), + textureType->getIsMultisampleInst(), + textureType->getSampleCountInst(), + textureType->getAccessInst(), + textureType->getIsShadowInst(), + textureType->getIsCombinedInst(), + formatArg); - auto newType = (IRType*)builder.emitIntrinsicInst(builder.getTypeKind(), textureType->getOp(), 3, args.getBuffer()); if (textureInst->getFullType() == textureType) { // Simple texture typed global param. diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index c40a62941..adac4cd10 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -2784,6 +2784,12 @@ namespace Slang return (IRPtrType*)getType(op, 2, operands); } + IRTextureTypeBase* IRBuilder::getTextureType(IRType* elementType, IRInst* shape, IRInst* isArray, IRInst* isMS, IRInst* sampleCount, IRInst* access, IRInst* isShadow, IRInst* isCombined, IRInst* format) + { + IRInst* args[] = {(IRInst*)elementType, shape, isArray, isMS, sampleCount, access, isShadow, isCombined, format}; + return as<IRTextureTypeBase>(emitIntrinsicInst(getTypeKind(), kIROp_TextureType, (UInt)(sizeof(args)/sizeof(IRInst*)), args)); + } + IRComPtrType* IRBuilder::getComPtrType(IRType* valueType) { return (IRComPtrType*)getType(kIROp_ComPtrType, valueType); @@ -5832,6 +5838,32 @@ namespace Slang return i; } + IRSPIRVAsmOperand* IRBuilder::emitSPIRVAsmOperandImageType(IRInst* element) + { + SLANG_ASSERT(as<IRSPIRVAsm>(m_insertLoc.getParent())); + const auto i = createInst<IRSPIRVAsmOperand>( + this, + kIROp_SPIRVAsmOperandImageType, + getTypeType(), + element + ); + addInst(i); + return i; + } + + IRSPIRVAsmOperand* IRBuilder::emitSPIRVAsmOperandSampledImageType(IRInst* element) + { + SLANG_ASSERT(as<IRSPIRVAsm>(m_insertLoc.getParent())); + const auto i = createInst<IRSPIRVAsmOperand>( + this, + kIROp_SPIRVAsmOperandSampledImageType, + getTypeType(), + element + ); + addInst(i); + return i; + } + IRSPIRVAsmOperand* IRBuilder::emitSPIRVAsmOperandTruncate() { SLANG_ASSERT(as<IRSPIRVAsm>(m_insertLoc.getParent())); @@ -6723,6 +6755,16 @@ namespace Slang dumpInstExpr(context, inst->getOperand(0)); dump(context, ")"); return; + case kIROp_SPIRVAsmOperandImageType: + dump(context, "__imageType("); + dumpInstExpr(context, inst->getOperand(0)); + dump(context, ")"); + return; + case kIROp_SPIRVAsmOperandSampledImageType: + dump(context, "__sampledImageType("); + dumpInstExpr(context, inst->getOperand(0)); + dump(context, ")"); + return; } dump(context, opInfo.name); @@ -7011,13 +7053,6 @@ namespace Slang // // We may want to care about decorations. - // If it's a resource type - special case the handling of the resource flavor - if (IRResourceTypeBase::isaImpl(opA) && - static_cast<const IRResourceTypeBase*>(a)->getFlavor() != static_cast<const IRResourceTypeBase*>(b)->getFlavor()) - { - return false; - } - // TODO(JS): There is a question here about what to do about decorations. // For now we ignore decorations. Are two types potentially different if there decorations different? // If decorations play a part in difference in types - the order of decorations presumably is not important. @@ -7940,13 +7975,13 @@ namespace Slang auto func = as<IRGlobalValueWithCode>(callee); if (!func) return false; - auto block = func->getFirstBlock(); - if (!block) - return false; - if (auto genAsm = as<IRGenericAsm>(block->getTerminator())) + for (auto block : func->getBlocks()) { - outDefinition = genAsm->getAsm(); - return true; + if (auto genAsm = as<IRGenericAsm>(block->getTerminator())) + { + outDefinition = genAsm->getAsm(); + return true; + } } return false; } diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index f0be72248..6b055b19e 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -1366,21 +1366,61 @@ SIMPLE_IR_TYPE(BasicBlockType, Type) struct IRResourceTypeBase : IRType { - TextureFlavor getFlavor() const - { - return TextureFlavor((getOp() >> kIROpMeta_OtherShift) & 0xFFFF); + IRInst* getShapeInst() { return getOperand(kStdlibTextureShapeParameterIndex); } + IRInst* getIsArrayInst() { return getOperand(kStdlibTextureIsArrayParameterIndex); } + IRInst* getIsMultisampleInst() { return getOperand(kStdlibTextureIsMultisampleParameterIndex); } + IRInst* getSampleCountInst() { return getOperand(kStdlibTextureSampleCountParameterIndex); } + IRInst* getAccessInst() { return getOperand(kStdlibTextureAccessParameterIndex); } + IRInst* getIsShadowInst() { return getOperand(kStdlibTextureIsShadowParameterIndex); } + IRInst* getIsCombinedInst() { return getOperand(kStdlibTextureIsCombinedParameterIndex); } + IRInst* getFormatInst() { return getOperand(kStdlibTextureFormatParameterIndex); } + + SlangResourceShape GetBaseShape() + { + switch (getOperand(1)->getOp()) + { + case kIROp_TextureShape1DType: + return SLANG_TEXTURE_1D; + case kIROp_TextureShape2DType: + return SLANG_TEXTURE_2D; + case kIROp_TextureShape3DType: + return SLANG_TEXTURE_3D; + case kIROp_TextureShapeCubeType: + return SLANG_TEXTURE_CUBE; + case kIROp_TextureShapeBufferType: + return SLANG_TEXTURE_BUFFER; + default: + return SLANG_RESOURCE_NONE; + } } - - TextureFlavor::Shape GetBaseShape() const + bool isFeedback() { return getIntVal(getAccessInst()) == kStdlibResourceAccessFeedback; } + bool isMultisample() { return getIntVal(getIsMultisampleInst()) != 0; } + bool isArray() { return getIntVal(getIsArrayInst()) != 0; } + bool isShadow() { return getIntVal(getIsShadowInst()) != 0; } + bool isCombined() { return getIntVal(getIsCombinedInst()) != 0; } + + SlangResourceShape getShape() { return (SlangResourceShape)((uint32_t)GetBaseShape() | (isArray() ? SLANG_TEXTURE_ARRAY_FLAG : 0)); } + SlangResourceAccess getAccess() { - return getFlavor().getBaseShape(); + auto constVal = as<IRIntLit>(getOperand(kStdlibTextureAccessParameterIndex)); + if (constVal) + { + switch (getIntVal(constVal)) + { + case kStdlibResourceAccessReadOnly: + return SLANG_RESOURCE_ACCESS_READ; + case kStdlibResourceAccessReadWrite: + return SLANG_RESOURCE_ACCESS_READ_WRITE; + case kStdlibResourceAccessRasterizerOrdered: + return SLANG_RESOURCE_ACCESS_RASTER_ORDERED; + case kStdlibResourceAccessFeedback: + return SLANG_RESOURCE_ACCESS_FEEDBACK; + default: + break; + } + } + return SLANG_RESOURCE_ACCESS_UNKNOWN; } - bool isFeedback() const { return getFlavor().isFeedback(); } - bool isMultisample() const { return getFlavor().isMultisample(); } - bool isArray() const { return getFlavor().isArray(); } - bool isShadow() const { return getFlavor().isShadow(); } - SlangResourceShape getShape() const { return getFlavor().getShape(); } - SlangResourceAccess getAccess() const { return getFlavor().getAccess(); } IR_PARENT_ISA(ResourceTypeBase); }; @@ -1388,9 +1428,9 @@ struct IRResourceTypeBase : IRType struct IRResourceType : IRResourceTypeBase { IRType* getElementType() { return (IRType*)getOperand(0); } - IRType* getSampleCount() { return (IRType*)getOperand(1); } - bool hasFormat() { return getOperandCount() >= 2; } - IRIntegerValue getFormat() { return getIntVal(getOperand(2)); } + IRInst* getSampleCount() { return getSampleCountInst(); } + bool hasFormat() { return getOperandCount() >= 9; } + IRIntegerValue getFormat() { return getIntVal(getFormatInst()); } IR_PARENT_ISA(ResourceType) }; @@ -1405,11 +1445,6 @@ struct IRTextureType : IRTextureTypeBase IR_LEAF_ISA(TextureType) }; -struct IRTextureSamplerType : IRTextureTypeBase -{ - IR_LEAF_ISA(TextureSamplerType) -}; - struct IRGLSLImageType : IRTextureTypeBase { IR_LEAF_ISA(GLSLImageType) diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp index b32236019..d71227b6c 100644 --- a/source/slang/slang-lookup.cpp +++ b/source/slang/slang-lookup.cpp @@ -406,6 +406,7 @@ static void _lookUpMembersInSuperTypeDeclImpl( else { auto selfType = DeclRefType::create(astBuilder, declRef); + selfType = selfType->getCanonicalType(); inheritanceInfo = semantics->getShared()->getInheritanceInfo(selfType); } diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 38651c5a4..cd9d19bcc 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -3983,6 +3983,26 @@ struct ExprLoweringVisitorBase : public ExprVisitor<Derived, LoweredValInfo> } return builder->emitSPIRVAsmOperandSampledType(i); } + case SPIRVAsmOperand::ImageType: + { + IRInst* i; + { + IRBuilderInsertLocScope insertScope(builder); + builder->setInsertBefore(spirvAsmInst); + i = getSimpleVal(context, lowerRValueExpr(context, operand.expr)); + } + return builder->emitSPIRVAsmOperandImageType(i); + } + case SPIRVAsmOperand::SampledImageType: + { + IRInst* i; + { + IRBuilderInsertLocScope insertScope(builder); + builder->setInsertBefore(spirvAsmInst); + i = getSimpleVal(context, lowerRValueExpr(context, operand.expr)); + } + return builder->emitSPIRVAsmOperandSampledImageType(i); + } case SPIRVAsmOperand::TruncateMarker: { return builder->emitSPIRVAsmOperandTruncate(); @@ -8945,6 +8965,9 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> IRFunc* irFunc = subBuilder->createFunc(); addNameHint(subContext, irFunc, decl); addLinkageDecoration(subContext, irFunc, decl); + + // Register the value now, to avoid any possible infinite recursion when lowering the body or attributes. + context->setGlobalValue(decl, LoweredValInfo::simple(findOuterMostGeneric(irFunc))); // Always force inline diff setter accessor to prevent downstream compiler from complaining // fields are not fully initialized for the first `inout` parameter. @@ -9226,9 +9249,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> addCatchAllIntrinsicDecorationIfNeeded(irFunc, decl); - // Register the value now, to avoid any possible infinite recursion when lowering ForwardDerivativeAttribute - context->setGlobalValue(decl, LoweredValInfo::simple(findOuterMostGeneric(irFunc))); - bool isInline = false; for (auto modifier : decl->modifiers) diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp index 7241fdd6e..4ddafa425 100644 --- a/source/slang/slang-parameter-binding.cpp +++ b/source/slang/slang-parameter-binding.cpp @@ -1135,9 +1135,10 @@ static void addExplicitParameterBindings_GLSL( // We can't infer TextureSampler from HLSL (it's not an HLSL concept) // So use default layout auto varType = varDecl.getDecl()->getType(); - if (as<TextureSamplerType>(varType)) + if (auto textureType = as<TextureType>(varType)) { - return; + if (textureType->isCombined()) + return; } // Can we map to a Vulkan kind in principal? diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 0a2076fd0..52c91cfbe 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -6494,6 +6494,21 @@ namespace Slang parser->ReadMatchingToken(TokenType::RParent); return SPIRVAsmOperand{SPIRVAsmOperand::SampledType, Token{}, typeExpr}; } + // The __imageType function + if (AdvanceIf(parser, "__imageType")) + { + parser->ReadToken(TokenType::LParent); + const auto typeExpr = parser->ParseExpression(); + parser->ReadMatchingToken(TokenType::RParent); + return SPIRVAsmOperand{ SPIRVAsmOperand::ImageType, Token{}, typeExpr }; + } + if (AdvanceIf(parser, "__sampledImageType")) + { + parser->ReadToken(TokenType::LParent); + const auto typeExpr = parser->ParseExpression(); + parser->ReadMatchingToken(TokenType::RParent); + return SPIRVAsmOperand{ SPIRVAsmOperand::SampledImageType, Token{}, typeExpr }; + } // The pseudo-operand for component truncation else if(parser->LookAheadToken("__truncate")) { diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp index 3a521589e..f0540deb3 100644 --- a/source/slang/slang-reflection-api.cpp +++ b/source/slang/slang-reflection-api.cpp @@ -1263,12 +1263,11 @@ namespace Slang SlangBindingType _calcResourceBindingType( Type* type) { - if(const auto combinedTextureSamplerType = as<TextureSamplerType>(type)) - { - return SLANG_BINDING_TYPE_COMBINED_TEXTURE_SAMPLER; - } - else if( auto resourceType = as<ResourceType>(type) ) + if( auto resourceType = as<ResourceType>(type) ) { + if (resourceType->isCombined()) + return SlangBindingType(SLANG_BINDING_TYPE_COMBINED_TEXTURE_SAMPLER); + auto shape = resourceType->getBaseShape(); auto access = resourceType->getAccess(); diff --git a/source/slang/slang-serialize-ir.cpp b/source/slang/slang-serialize-ir.cpp index d84049b74..ccd5a2e7d 100644 --- a/source/slang/slang-serialize-ir.cpp +++ b/source/slang/slang-serialize-ir.cpp @@ -10,12 +10,6 @@ namespace Slang { -static bool _isTextureTypeBase(IROp opIn) -{ - const int op = (kIROpMask_OpMask & opIn); - return op >= kIROp_FirstTextureTypeBase && op <= kIROp_LastTextureTypeBase; -} - static bool _isConstant(IROp opIn) { const int op = (kIROpMask_OpMask & opIn); @@ -246,15 +240,6 @@ Result IRSerialWriter::write(IRModule* module, SerialSourceLocWriter* sourceLocW continue; } - IRTextureTypeBase* textureBase = as<IRTextureTypeBase>(srcInst); - if (textureBase) - { - dstInst.m_payloadType = PayloadType::OperandAndUInt32; - dstInst.m_payload.m_operandAndUInt32.m_uint32 = uint32_t(srcInst->getOp()) >> kIROpMeta_OtherShift; - dstInst.m_payload.m_operandAndUInt32.m_operand = getInstIndex(textureBase->getElementType()); - continue; - } - // ModuleInst is different, in so far as it holds a pointer to IRModule, but we don't need // to save that off in a special way, so can just use regular path @@ -834,22 +819,6 @@ Result IRSerialReader::read(const IRSerialData& data, Session* session, SerialSo insts[i] = irConst; } - else if (_isTextureTypeBase(op)) - { - // TODO: We should clean up the IR encoding of texture types so that - // they do not need to have special-case suport in the serialization layer. - - // All IR texture types currently have a single operand - Int operandCount = 1; - IRTextureTypeBase* inst = module->_allocateInst<IRTextureTypeBase>(op, operandCount); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::OperandAndUInt32); - - // Reintroduce the texture type bits into the the - const uint32_t other = srcInst.m_payload.m_operandAndUInt32.m_uint32; - inst->m_op = IROp(uint32_t(inst->getOp()) | (other << kIROpMeta_OtherShift)); - - insts[i] = inst; - } else { int numOperands = srcInst.getNumOperands(); diff --git a/source/slang/slang-serialize-misc-type-info.h b/source/slang/slang-serialize-misc-type-info.h index d3d83e1d0..c40edc1e7 100644 --- a/source/slang/slang-serialize-misc-type-info.h +++ b/source/slang/slang-serialize-misc-type-info.h @@ -22,19 +22,6 @@ struct SerialTypeInfo<FeedbackType::Kind> : public SerialIdentityTypeInfo<Feedba template <> struct SerialTypeInfo<SamplerStateFlavor> : public SerialConvertTypeInfo<SamplerStateFlavor, uint8_t> {}; -// TextureFlavor - -template <> -struct SerialTypeInfo<TextureFlavor> -{ - typedef TextureFlavor NativeType; - typedef uint16_t SerialType; - enum { SerialAlignment = sizeof(SerialType) }; - - static void toSerial(SerialWriter* writer, const void* native, void* serial) { SLANG_UNUSED(writer); *(SerialType*)serial = ((const NativeType*)native)->flavor; } - static void toNative(SerialReader* reader, const void* serial, void* native) { SLANG_UNUSED(reader); ((NativeType*)native)->flavor = *(const SerialType*)serial; } -}; - // ImageFormat template <> struct SerialTypeInfo<ImageFormat> : public SerialConvertTypeInfo<ImageFormat, uint8_t> {}; diff --git a/source/slang/slang-stdlib-textures.cpp b/source/slang/slang-stdlib-textures.cpp index 98380033c..9ebfc54d6 100644 --- a/source/slang/slang-stdlib-textures.cpp +++ b/source/slang/slang-stdlib-textures.cpp @@ -46,20 +46,16 @@ struct BraceScope }; TextureTypeInfo::TextureTypeInfo( - TextureTypePrefixInfo const& prefixInfo, BaseTextureShapeInfo const& base, bool isArray, bool isMultisample, bool isShadow, - BaseTextureAccessInfo const& accessInfo, StringBuilder& inSB, String const& inPath) - : prefixInfo(prefixInfo) - , base(base) + : base(base) , isArray(isArray) , isMultisample(isMultisample) , isShadow(isShadow) - , accessInfo(accessInfo) , sb(inSB) , path(inPath) { @@ -82,7 +78,10 @@ void TextureTypeInfo::writeFuncBody( if(glsl.getLength()) { sb << i << "case glsl:\n"; - sb << i << "__intrinsic_asm \"" << glsl << "\";\n"; + if (glsl.startsWith("if")) + sb << glsl; + else + sb << i << "__intrinsic_asm \"" << glsl << "\";\n"; } if(cuda.getLength()) { @@ -99,16 +98,6 @@ void TextureTypeInfo::writeFuncBody( } } -void TextureTypeInfo::writeFuncDecorations( - const String& glsl, - const String& cuda) -{ - if(glsl.getLength()) - sb << i << "__target_intrinsic(glsl, \"" << glsl << "\")\n"; - if(cuda.getLength()) - sb << i << "__target_intrinsic(cuda, \"" << cuda << "\")\n"; -} - void TextureTypeInfo::writeFuncWithSig( const char* funcName, const String& sig, @@ -117,24 +106,12 @@ void TextureTypeInfo::writeFuncWithSig( const String& cuda, const ReadNoneMode readNoneMode) { - const bool isReadOnly = (accessInfo.access == SLANG_RESOURCE_ACCESS_READ); - const bool rn = - readNoneMode == ReadNoneMode::Always - || readNoneMode == ReadNoneMode::IfReadOnly && isReadOnly; - if(spirv.getLength()) - { - if(rn) - sb << i << "[__readNone]\n"; - sb << i << sig << "\n"; - writeFuncBody(funcName, glsl, cuda, spirv); - } - else - { - writeFuncDecorations(glsl, cuda); - if(rn) - sb << i << "[__readNone]\n"; - sb << i << sig << ";\n"; - } + if (readNoneMode == ReadNoneMode::Always) + sb << i << "[__readNone]\n"; + sb << i << "[__readNone]\n"; + sb << i << "[ForceInline]\n"; + sb << i << sig << "\n"; + writeFuncBody(funcName, glsl, cuda, spirv); sb << "\n"; } @@ -157,108 +134,14 @@ void TextureTypeInfo::writeFunc( ); } -void TextureTypeInfo::emitTypeDecl() -{ - char const* baseName = prefixInfo.name; - char const* baseShapeName = base.shapeName; - TextureFlavor::Shape baseShape = base.baseShape; - - // Arrays of 3D textures aren't allowed - if (isArray && baseShape == TextureFlavor::Shape::Shape3D) return; - - auto access = accessInfo.access; - - // No such thing as RWTextureCube - if (access == SLANG_RESOURCE_ACCESS_READ_WRITE && baseShape == TextureFlavor::Shape::ShapeCube) - { - return; - } - - // TODO: any constraints to enforce on what gets to be multisampled? - - unsigned flavor = baseShape; - if (isArray) flavor |= TextureFlavor::ArrayFlag; - if (isMultisample) flavor |= TextureFlavor::MultisampleFlag; - if (isShadow) flavor |= TextureFlavor::ShadowFlag; - - flavor |= (access << 8); - - // emit a generic signature - sb << "__generic<T = float4"; - // Multi-sample rw texture types have an optional sampleCount parameter. - if (isMultisample) - sb << ", let sampleCount : int = 0"; - sb << ">"; - - if(prefixInfo.combined) - { - sb << "__magic_type(TextureSamplerType," << int(flavor) << ")\n"; - sb << "__intrinsic_type(" << (kIROp_TextureSamplerType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n"; - } - else - { - sb << "__magic_type(TextureType," << int(flavor) << ")\n"; - sb << "__intrinsic_type(" << (kIROp_TextureType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n"; - } - sb << "struct "; - sb << accessInfo.name; - sb << baseName; - sb << baseShapeName; - if (isMultisample) sb << "MS"; - if (isArray) sb << "Array"; - if (isShadow) sb << "Shadow"; - sb << "\n"; - - // The struct body - { - BraceScope structBodyScope{i, sb, ";\n"}; - - writeQueryFunctions(); - - if(baseShape != TextureFlavor::Shape::ShapeCube) - writeSubscriptFunctions(); - - if( !isMultisample ) - writeSampleFunctions(); - } - - writeGatherExtensions(); -} // TextureTypeInfo::emitTypeDecl - -void TextureTypeInfo::writeQueryFunctions() +void TextureTypeInfo::writeGetDimensionFunctions() { static const char* kComponentNames[]{ "x", "y", "z", "w" }; - TextureFlavor::Shape baseShape = base.baseShape; - - char const* samplerStateParam = prefixInfo.combined ? "" : "SamplerState s, "; - auto access = accessInfo.access; - - if( !isMultisample ) - { - writeFunc( - "float", - "CalculateLevelOfDetail", - cat(samplerStateParam, "float", base.coordCount, " location"), - cat("textureQueryLod($p, $2).x"), - "", - "", - ReadNoneMode::Never - ); - - writeFunc( - "float", - "CalculateLevelOfDetailUnclamped", - cat(samplerStateParam, "float", base.coordCount, " location"), - cat("textureQueryLod($p, $2).y"), - "", - "", - ReadNoneMode::Never - ); - } + SlangResourceShape baseShape = base.baseShape; // `GetDimensions` - const char* dimParamTypes[] = {"out float ", "out int ", "out uint "}; + const char* dimParamTypes[] = { "out float ", "out int ", "out uint " }; const char* dimParamTypesInner[] = { "float", "int", "uint" }; for (int tid = 0; tid < 3; tid++) { @@ -274,19 +157,19 @@ void TextureTypeInfo::writeQueryFunctions() switch (baseShape) { - case TextureFlavor::Shape::Shape1D: + case SLANG_TEXTURE_1D: params << t << "width"; sizeDimCount = 1; break; - case TextureFlavor::Shape::Shape2D: - case TextureFlavor::Shape::ShapeCube: + case SLANG_TEXTURE_2D: + case SLANG_TEXTURE_CUBE: params << t << "width,"; params << t << "height"; sizeDimCount = 2; break; - case TextureFlavor::Shape::Shape3D: + case SLANG_TEXTURE_3D: params << t << "width,"; params << t << "height,"; params << t << "depth"; @@ -315,79 +198,77 @@ void TextureTypeInfo::writeQueryFunctions() StringBuilder glsl; { - glsl << "("; - - int aa = 1; - String lodStr = ", 0"; - if (includeMipInfo) - { - int mipLevelArg = aa++; - lodStr = ", int($"; - lodStr.append(mipLevelArg); - lodStr.append(")"); - } - - String opStr = " = textureSize($0" + lodStr; - switch (access) - { - case SLANG_RESOURCE_ACCESS_READ_WRITE: - case SLANG_RESOURCE_ACCESS_RASTER_ORDERED: - opStr = " = imageSize($0"; - break; - - default: - break; - } - - int cc = 0; - switch (baseShape) - { - case TextureFlavor::Shape::Shape1D: - glsl << "($" << aa++ << opStr << ")"; - if (isArray) + auto emitIntrinsic = [&](UnownedStringSlice funcName, bool useLodStr) { - glsl << ".x"; - } - glsl << ")"; - cc = 1; - break; - - case TextureFlavor::Shape::Shape2D: - case TextureFlavor::Shape::ShapeCube: - glsl << "($" << aa++ << opStr << ").x)"; - glsl << ", ($" << aa++ << opStr << ").y)"; - cc = 2; - break; - - case TextureFlavor::Shape::Shape3D: - glsl << "($" << aa++ << opStr << ").x)"; - glsl << ", ($" << aa++ << opStr << ").y)"; - glsl << ", ($" << aa++ << opStr << ").z)"; - cc = 3; - break; - - default: - SLANG_UNEXPECTED("unhandled resource shape"); - break; - } - - if (isArray) - { - glsl << ", ($" << aa++ << opStr << ")." << kComponentNames[cc] << ")"; - } - - if (isMultisample) - { - glsl << ", ($" << aa++ << " = textureSamples($0))"; - } + int aa = 1; + StringBuilder opStrSB; + opStrSB << " = " << funcName << "($0"; + if (useLodStr) + { + String lodStr = ", 0"; + if (includeMipInfo) + { + int mipLevelArg = aa++; + lodStr = ", int($"; + lodStr.append(mipLevelArg); + lodStr.append(")"); + } + opStrSB << lodStr; + } + auto opStr = opStrSB.produceString(); + int cc = 0; + switch (baseShape) + { + case SLANG_TEXTURE_1D: + glsl << "($" << aa++ << opStr << ")"; + if (isArray) + { + glsl << ".x"; + } + glsl << ")"; + cc = 1; + break; + + case SLANG_TEXTURE_2D: + case SLANG_TEXTURE_CUBE: + glsl << "($" << aa++ << opStr << ").x)"; + glsl << ", ($" << aa++ << opStr << ").y)"; + cc = 2; + break; + + case SLANG_TEXTURE_3D: + glsl << "($" << aa++ << opStr << ").x)"; + glsl << ", ($" << aa++ << opStr << ").y)"; + glsl << ", ($" << aa++ << opStr << ").z)"; + cc = 3; + break; + + default: + SLANG_UNEXPECTED("unhandled resource shape"); + break; + } - if (includeMipInfo) - { - glsl << ", ($" << aa++ << " = textureQueryLevels($0))"; - } + if (isArray) + { + glsl << ", ($" << aa++ << opStr << ")." << kComponentNames[cc] << ")"; + } + if (isMultisample) + { + glsl << ", ($" << aa++ << " = textureSamples($0))"; + } - glsl << ")"; + if (includeMipInfo) + { + glsl << ", ($" << aa++ << " = textureQueryLevels($0))"; + } + }; + glsl << "if (access == " << kStdlibResourceAccessReadOnly << ") __intrinsic_asm \""; + emitIntrinsic(toSlice("textureSize"), true); + glsl << "\";\n"; + glsl << "__intrinsic_asm \""; + emitIntrinsic(toSlice("imageSize"), false); + glsl << "\";\n"; } StringBuilder spirv; @@ -434,17 +315,17 @@ void TextureTypeInfo::writeQueryFunctions() }; switch (baseShape) { - case TextureFlavor::Shape::Shape1D: + case SLANG_TEXTURE_1D: extractSizeComponent(0, "width"); break; - case TextureFlavor::Shape::Shape2D: - case TextureFlavor::Shape::ShapeCube: + case SLANG_TEXTURE_2D: + case SLANG_TEXTURE_CUBE: extractSizeComponent(0, "width"); extractSizeComponent(1, "height"); break; - case TextureFlavor::Shape::Shape3D: + case SLANG_TEXTURE_3D: extractSizeComponent(0, "width"); extractSizeComponent(1, "height"); extractSizeComponent(2, "depth"); @@ -485,901 +366,6 @@ void TextureTypeInfo::writeQueryFunctions() ReadNoneMode::Always); } } - - // `GetSamplePosition()` - if( isMultisample ) - { - writeFunc("float2", "GetSamplePosition", "int s", "", "", "", ReadNoneMode::Never); - } - - // `Load()` - - if( base.coordCount + isArray < 4 ) - { - // The `Load()` operation on an ordinary `Texture2D` takes - // an `int3` for the location, where `.xy` holds the texel - // coordinates, and `.z` holds the mip level to use. - // - // The third coordinate for mip level is absent in - // `Texure2DMS.Load()` and `RWTexture2D.Load`. This pattern - // is repreated for all the other texture shapes. - // - bool needsMipLevel = !isMultisample && (access == SLANG_RESOURCE_ACCESS_READ); - - int loadCoordCount = base.coordCount + isArray + (needsMipLevel?1:0); - - char const* glslFuncName = (access == SLANG_RESOURCE_ACCESS_READ) ? "texelFetch" : "imageLoad"; - - // When translating to GLSL, we need to break apart the `location` argument. - // - // TODO: this should realy be handled by having this member actually get lowered! - static const char* kGLSLLoadCoordsSwizzle[] = { "", "", "x", "xy", "xyz", "xyzw" }; - static const char* kGLSLLoadLODSwizzle[] = { "", "", "y", "z", "w", "error" }; - - // TODO: The GLSL translations here only handle the read-only texture - // cases (stuff that lowers to `texture*` in GLSL) and not the stuff - // that lowers to `image*`. - // - // At some point it may make sense to separate the read-only and - // `RW`/`RasterizerOrdered` cases here rather than try to share code. - - // CUDA - StringBuilder cudaBuilder; - if(!isMultisample) - { - if (access == SLANG_RESOURCE_ACCESS_READ_WRITE) - { - const int coordCount = base.coordCount; - const int vecCount = coordCount + int(isArray); - - if( baseShape != TextureFlavor::Shape::ShapeCube ) - { - cudaBuilder << "surf" << coordCount << "D"; - if (isArray) - { - cudaBuilder << "Layered"; - } - cudaBuilder << "read"; - cudaBuilder << "<$T0>($0"; - for (int j = 0; j < coordCount; ++j) - { - cudaBuilder << ", ($1)"; - if (vecCount > 1) - { - cudaBuilder << '.' << char(j + 'x'); - } - - // Surface access is *byte* addressed in x in CUDA - if (j == 0) - { - cudaBuilder << " * $E"; - } - } - if (isArray) - { - cudaBuilder << ", int(($1)." << char(coordCount + 'x') << ")"; - } - cudaBuilder << ", SLANG_CUDA_BOUNDARY_MODE)"; - } - else - { - cudaBuilder << "__target_intrinsic(cuda, \"surfCubemap"; - if (isArray) - { - cudaBuilder << "Layered"; - } - cudaBuilder << "read"; - - // Surface access is *byte* addressed in x in CUDA - cudaBuilder << "<$T0>($0, ($1).x * $E, ($1).y, ($1).z"; - if (isArray) - { - cudaBuilder << ", int(($1).w)"; - } - cudaBuilder << ", SLANG_CUDA_BOUNDARY_MODE)"; - } - } - else if (access == SLANG_RESOURCE_ACCESS_READ) - { - // We can allow this on Texture1D - if( baseShape == TextureFlavor::Shape::Shape1D && isArray == false) - { - cudaBuilder << "tex1Dfetch<$T0>($0, ($1).x)"; - } - } - } - - // SPIRV - auto getSpirvIntrinsic = [&](bool hasSampleIndex, bool hasOffset) - { - StringBuilder spirv; - spirv << "%lod:$$int = OpCompositeExtract $location " << base.coordCount + isArray << "; "; - spirv << "%coord:$$int" << base.coordCount + isArray << " = OpVectorShuffle $location $location "; - for (int i = 0; i < base.coordCount + isArray; i++) - spirv << " " << i; - spirv << "; "; - spirv << "%sampled:__sampledType(T) = "; - if (access == SLANG_RESOURCE_ACCESS_READ_WRITE) - spirv << "OpImageRead"; - else - spirv << "OpImageFetch"; - spirv << " $this %coord "; - uint32_t operandMask = 0; - if (!hasSampleIndex) - operandMask |= SpvImageOperandsLodMask; - if (hasOffset) - operandMask |= SpvImageOperandsConstOffsetMask; - if (hasSampleIndex) - operandMask |= SpvImageOperandsSampleMask; - spirv << operandMask << " "; - if (operandMask & SpvImageOperandsLodMask) - spirv << " %lod"; - if (operandMask & SpvImageOperandsConstOffsetMask) - spirv << " $offset"; - if (operandMask & SpvImageOperandsSampleMask) - spirv << " $sampleIndex"; - spirv << ";"; - spirv << i << "__truncate $$T result __sampledType(T) %sampled;"; - return spirv.produceString(); - }; - - sb << i << "__glsl_extension(GL_EXT_samplerless_texture_functions)"; - writeFunc( - "T", - "Load", - cat("int", loadCoordCount, " location", isMultisample ? ", int sampleIndex" : ""), - isMultisample ? cat("$c", glslFuncName, "($0, $1, $2)$z") - : needsMipLevel ? cat( - "$c", - glslFuncName, - "($0, ($1).", - kGLSLLoadCoordsSwizzle[loadCoordCount], - ", ($1).", - kGLSLLoadLODSwizzle[loadCoordCount], - ")$z") - : cat("$c", glslFuncName, "($0, $1)$z"), - getSpirvIntrinsic(isMultisample, false), - cudaBuilder - ); - - glslFuncName = (access == SLANG_RESOURCE_ACCESS_READ) ? "texelFetchOffset" : "imageLoad"; - sb << i << "__glsl_extension(GL_EXT_samplerless_texture_functions)"; - writeFunc( - "T", - "Load", - cat( - "int", loadCoordCount, " location", - isMultisample ? ", int sampleIndex" : "", - ", constexpr int", base.coordCount, " offset" - ), - isMultisample ? cat("$c", glslFuncName, "($0, $0, $1, $2)$z") - : needsMipLevel ? cat( - "$c", glslFuncName, "($0, ($1).", kGLSLLoadCoordsSwizzle[loadCoordCount], - ", ($1).", kGLSLLoadLODSwizzle[loadCoordCount], - ", $2)$z") - : cat("$c", glslFuncName, "($0, $1, 0, $2)$z"), - getSpirvIntrinsic(isMultisample, true) - ); - - writeFunc( - "T", - "Load", - cat( - "int", loadCoordCount, " location", - isMultisample ? ", int sampleIndex" : "", - ", constexpr int", base.coordCount, " offset", - ", out uint status" - ) - ); - } -} - -static String spirvReadIntrinsic(SlangResourceAccess access) -{ - StringBuilder spirvBuilder; - const char* i = " "; - switch (access) - { - case SLANG_RESOURCE_ACCESS_NONE: - case SLANG_RESOURCE_ACCESS_READ: - spirvBuilder << i << "%sampled : __sampledType(T) = OpImageFetch $this $location;\n"; - spirvBuilder << i << "__truncate $$T result __sampledType(T) %sampled;"; - break; - - default: - spirvBuilder << i << "%sampled : __sampledType(T) = OpImageRead $this $location;\n"; - spirvBuilder << i << "__truncate $$T result __sampledType(T) %sampled;"; - break; - } - return spirvBuilder; -} - -static String spirvWriteIntrinsic() -{ - StringBuilder spirvBuilder; - const char* i = " "; - spirvBuilder << i << "OpImageWrite $this $location $newValue;"; - return spirvBuilder; -} - -void TextureTypeInfo::writeSubscriptFunctions() -{ - TextureFlavor::Shape baseShape = base.baseShape; - auto access = accessInfo.access; - - int N = base.coordCount + isArray; - - char const* uintNs[] = { "", "uint", "uint2", "uint3", "uint4" }; - char const* ivecNs[] = { "", "int", "ivec2", "ivec3", "ivec4" }; - - auto uintN = uintNs[N]; - auto ivecN = ivecNs[N]; - - // subscript operator - sb << i << "__subscript(" << uintN << " location) -> T\n"; - BraceScope subscriptScope{i, sb}; - - // !!!!!!!!!!!!!!!!!!!! get !!!!!!!!!!!!!!!!!!!!!!! - - // GLSL/SPIR-V distinguishes sampled vs. non-sampled images - StringBuilder glslBuilder; - { - switch( access ) - { - case SLANG_RESOURCE_ACCESS_NONE: - case SLANG_RESOURCE_ACCESS_READ: - sb << i << "__glsl_extension(GL_EXT_samplerless_texture_functions)\n"; - glslBuilder << "$ctexelFetch($0, " << ivecN << "($1)"; - if( !isMultisample ) - { - glslBuilder << ", 0"; - } - else - { - // TODO: how to handle passing through sample index? - glslBuilder << ", 0"; - } - break; - - default: - glslBuilder << "$cimageLoad($0, " << ivecN << "($1)"; - if( isMultisample ) - { - // TODO: how to handle passing through sample index? - glslBuilder << ", 0"; - } - break; - } - glslBuilder << ")$z"; - } - - // CUDA - StringBuilder cudaBuilder; - { - if (access == SLANG_RESOURCE_ACCESS_READ_WRITE) - { - const int coordCount = base.coordCount; - const int vecCount = coordCount + int(isArray); - - cudaBuilder << "surf"; - if( baseShape != TextureFlavor::Shape::ShapeCube ) - { - cudaBuilder << coordCount << "D"; - } - else - { - cudaBuilder << "Cubemap"; - } - - cudaBuilder << (isArray ? "Layered" : ""); - cudaBuilder << "read$C<$T0>($0"; - - for (int j = 0; j < vecCount; ++j) - { - cudaBuilder << ", ($1)"; - if (vecCount > 1) - { - cudaBuilder << '.' << char(j + 'x'); - } - // Surface access is *byte* addressed in x in CUDA - if (j == 0) - { - cudaBuilder << " * $E"; - } - } - - cudaBuilder << ", SLANG_CUDA_BOUNDARY_MODE)"; - } - else if (access == SLANG_RESOURCE_ACCESS_READ) - { - // We can allow this on Texture1D - if( baseShape == TextureFlavor::Shape::Shape1D && isArray == false) - { - cudaBuilder << "tex1Dfetch<$T0>($0, $1)"; - } - } - } - - // Output that has get - writeFuncWithSig( - "operator[]", - "get", - glslBuilder, - spirvReadIntrinsic(access), - cudaBuilder - ); - - // !!!!!!!!!!!!!!!!!!!! set !!!!!!!!!!!!!!!!!!!!!!! - - if (!(access == SLANG_RESOURCE_ACCESS_NONE || access == SLANG_RESOURCE_ACCESS_READ)) - { - // CUDA - cudaBuilder.clear(); - { - const int coordCount = base.coordCount; - const int vecCount = coordCount + int(isArray); - - cudaBuilder << "surf"; - if( baseShape != TextureFlavor::Shape::ShapeCube ) - { - cudaBuilder << coordCount << "D"; - } - else - { - cudaBuilder << "Cubemap"; - } - - cudaBuilder << (isArray ? "Layered" : ""); - cudaBuilder << "write$C<$T0>($2, $0"; - for (int j = 0; j < vecCount; ++j) - { - cudaBuilder << ", ($1)"; - if (vecCount > 1) - { - cudaBuilder << '.' << char(j + 'x'); - } - - // Surface access is *byte* addressed in x in CUDA - if (j == 0) - { - cudaBuilder << " * $E"; - } - } - - cudaBuilder << ", SLANG_CUDA_BOUNDARY_MODE)"; - } - - // Set - sb << i << "[nonmutating]\n"; - writeFuncWithSig( - "operator[]", - "set(T newValue)", - cat("imageStore($0, ", ivecN, "($1), $V2)"), - spirvWriteIntrinsic(), - cudaBuilder - ); - } - - // !!!!!!!!!!!!!!!!!! ref !!!!!!!!!!!!!!!!!!!!!!!!! - - // Depending on the access level of the texture type, - // we either have just a getter (the default), or both - // a getter and setter. - switch( access ) - { - case SLANG_RESOURCE_ACCESS_NONE: - case SLANG_RESOURCE_ACCESS_READ: - break; - default: - sb << i << "__intrinsic_op(" << int(kIROp_ImageSubscript) << ") ref;\n"; - break; - } -} - -static String cudaSampleIntrinsic(const bool isArray, const BaseTextureShapeInfo& base, bool sampleLevel) -{ - StringBuilder cudaBuilder; - - TextureFlavor::Shape baseShape = base.baseShape; - const int coordCount = base.coordCount; - - if( baseShape != TextureFlavor::Shape::ShapeCube ) - { - cudaBuilder << "tex" << coordCount << "D"; - if (isArray) - cudaBuilder << "Layered"; - if(sampleLevel) - cudaBuilder << "Lod"; - cudaBuilder << "<$T0>($0"; - for (int i = 0; i < coordCount; ++i) - { - cudaBuilder << ", ($2)"; - cudaBuilder << '.' << "xyzw"[i]; - } - if (isArray) - cudaBuilder << ", int(($2)." << char(coordCount + 'x') << ")"; - if(sampleLevel) - cudaBuilder << ", $3"; - cudaBuilder << ")"; - } - else - { - cudaBuilder << "texCubemap"; - if (isArray) - cudaBuilder << "Layered"; - if(sampleLevel) - cudaBuilder << "Lod"; - cudaBuilder << "<$T0>($0, ($2).x, ($2).y, ($2).z"; - if (isArray) - cudaBuilder << ", int(($2).w)"; - if(sampleLevel) - cudaBuilder << ", $3"; - cudaBuilder << ")"; - } - - return cudaBuilder; -} - -const char* noBias = nullptr; -const char* noLodLevel = nullptr; -const char* noGradX = nullptr; -const char* noGradY = nullptr; -const char* noConstOffset = nullptr; -const char* noMinLod = nullptr; - -static String spirvSampleIntrinsic( - const TextureTypePrefixInfo& prefixInfo, - const char* bias = nullptr, - const char* lodLevel = nullptr, - const char* gradX = nullptr, - const char* gradY = nullptr, - const char* constOffset = nullptr, - const char* minLod = nullptr) -{ - StringBuilder spirvBuilder; - const char* i = " "; - - SLANG_ASSERT(!(!gradX ^ !gradY)); - - if(minLod) - spirvBuilder << i << "OpCapability MinLod;\n"; - - const char* sampledImage; - if(prefixInfo.combined) - { - sampledImage = "$this"; - } - else - { - const char* sampledImageType = "%sampledImageType"; - sampledImage = "%sampledImage"; - spirvBuilder << i << sampledImageType << " = OpTypeSampledImage $$This;\n"; - spirvBuilder << i << sampledImage << " : " << sampledImageType << " = OpSampledImage $this $s;\n"; - } - - const char* op = lodLevel || gradX ? "OpImageSampleExplicitLod" : "OpImageSampleImplicitLod"; - spirvBuilder << i << "%sampled : __sampledType(T) = " << op << " " << sampledImage << " $location"; - spirvBuilder << " None"; - if(bias) - spirvBuilder << "|Bias"; - if(lodLevel) - spirvBuilder << "|Lod"; - if(gradX) - spirvBuilder << "|Grad"; - if(constOffset) - spirvBuilder << "|ConstOffset"; - if(minLod) - spirvBuilder << "|MinLod"; - - if(bias) - spirvBuilder << " $" << bias; - if(lodLevel) - spirvBuilder << " $" << lodLevel; - if(gradX) - spirvBuilder << " $" << gradX << " $" << gradY; - if(constOffset) - spirvBuilder << " $" << constOffset; - if(minLod) - spirvBuilder << " $" << minLod; - spirvBuilder << ";\n"; - spirvBuilder << i << "__truncate $$T result __sampledType(T) %sampled;\n"; - return spirvBuilder; -} - -void TextureTypeInfo::writeSampleFunctions() -{ - TextureFlavor::Shape baseShape = base.baseShape; - char const* samplerStateParam = prefixInfo.combined ? "" : "SamplerState s, "; - char const* comparisonSamplerStateParam = prefixInfo.combined ? "" : "SamplerComparisonState s, "; - // `Sample()` - - writeFunc( - "T", - "Sample", - cat(samplerStateParam, "float", base.coordCount + isArray, " location"), - "$ctexture($p, $2)$z", - spirvSampleIntrinsic(prefixInfo), - cudaSampleIntrinsic(isArray, base, false) - ); - - if( baseShape != TextureFlavor::Shape::ShapeCube ) - { - writeFunc( - "T", - "Sample", - cat(samplerStateParam, "float", base.coordCount + isArray, " location, ", "constexpr int", base.coordCount, " offset"), - "$ctextureOffset($p, $2, $3)$z", - spirvSampleIntrinsic(prefixInfo, noBias, noLodLevel, noGradX, noGradY, "offset") - ); - } - - writeFunc( - "T", - "Sample", - cat( - samplerStateParam, - "float", base.coordCount + isArray, " location, ", - baseShape == TextureFlavor::Shape::ShapeCube ? "" : cat("constexpr int", base.coordCount, " offset, "), - "float clamp" - ), - "", - spirvSampleIntrinsic( - prefixInfo, - noBias, - noLodLevel, - noGradX, - noGradY, - baseShape == TextureFlavor::Shape::ShapeCube ? nullptr : "offset", - "clamp" - ) - ); - - // SPIR-V todo, use OpImageSparseSampleImplicitLod - writeFunc( - "T", - "Sample", - cat( - samplerStateParam, - "float", base.coordCount + isArray, " location, ", - baseShape != TextureFlavor::Shape::ShapeCube ? cat("constexpr int", base.coordCount, " offset, ") : "", - "float clamp, out uint status" - ) - ); - - writeFunc( - "T", - "SampleBias", - cat( - samplerStateParam, - "float", base.coordCount + isArray, " location, ", - "float bias" - ), - "$ctexture($p, $2, $3)$z", - spirvSampleIntrinsic(prefixInfo, "bias") - ); - - if( baseShape != TextureFlavor::Shape::ShapeCube ) - { - writeFunc( - "T", - "SampleBias", - cat( - samplerStateParam, - "float", base.coordCount + isArray, " location, ", - "float bias, ", - "constexpr int", base.coordCount, " offset" - ), - "$ctextureOffset($p, $2, $3, $4)$z", - spirvSampleIntrinsic(prefixInfo, "bias", noLodLevel, noGradX, noGradY, "offset") - ); - } - int baseCoordCount = base.coordCount; - int arrCoordCount = baseCoordCount + isArray; - if (arrCoordCount <= 3) - { - // `SampleCmp()` and `SampleCmpLevelZero` - - writeFunc( - "float", - "SampleCmp", - cat( - comparisonSamplerStateParam, - "float", base.coordCount + isArray, " location, ", - "float compareValue" - ), - cat("texture($p, vec", arrCoordCount + 1, "($2, $3))") - ); - - sb << "__glsl_extension(GL_EXT_texture_shadow_lod)\n"; - writeFunc( - "float", - "SampleCmpLevelZero", - cat( - comparisonSamplerStateParam, - "float", base.coordCount + isArray, " location, ", - "float compareValue" - ), - cat("textureLod($p, vec", arrCoordCount + 1, "($2, $3), 0)") - ); - } - - if( baseShape != TextureFlavor::Shape::ShapeCube ) - { - // Note(tfoley): MSDN seems confused, and claims that the `offset` - // parameter for `SampleCmp` is available for everything but 3D - // textures, while `Sample` and `SampleBias` are consistent in - // saying they only exclude `offset` for cube maps (which makes - // sense). I'm going to assume the documentation for `SampleCmp` - // is just wrong. - writeFunc( - "float", - "SampleCmp", - cat( - comparisonSamplerStateParam, - "float", base.coordCount + isArray, " location, ", - "float compareValue, " - "constexpr int", base.coordCount, " offset" - ), - cat("textureOffset($p, vec", arrCoordCount + 1, "($2, $3), $4)") - ); - - sb << "__glsl_extension(GL_EXT_texture_shadow_lod)\n"; - writeFunc( - "float", - "SampleCmpLevelZero", - cat( - comparisonSamplerStateParam, - "float", base.coordCount + isArray, " location, ", - "float compareValue, " - "constexpr int", base.coordCount, " offset" - ), - cat("textureLodOffset($p, vec", arrCoordCount + 1, "($2, $3), 0, $4)") - ); - } - - // TODO(JS): Not clear how to map this to CUDA, because in HLSL, the gradient is a vector based on - // the dimension. On CUDA there is texNDGrad, but it always just takes ddx, ddy. - // I could just assume 0 for elements not supplied, and ignore z. For now will just leave - writeFunc( - "T", - "SampleGrad", - cat( - samplerStateParam, - "float", base.coordCount + isArray, " location, ", - "float", base.coordCount, " gradX, ", - "float", base.coordCount, " gradY, " - ), - "$ctextureGrad($p, $2, $3, $4)$z", - spirvSampleIntrinsic(prefixInfo, noBias, noLodLevel, "gradX", "gradY") - ); - - if( baseShape != TextureFlavor::Shape::ShapeCube ) - { - writeFunc( - "T", - "SampleGrad", - cat( - samplerStateParam, - "float", base.coordCount + isArray, " location, ", - "float", base.coordCount, " gradX, ", - "float", base.coordCount, " gradY, ", - "constexpr int", base.coordCount, " offset " - ), - "$ctextureGradOffset($p, $2, $3, $4, $5)$z", - spirvSampleIntrinsic(prefixInfo, noBias, noLodLevel, "gradX", "gradY", "offset") - ); - - sb << i << "__glsl_extension(GL_ARB_sparse_texture_clamp)\n"; - writeFunc( - "T", - "SampleGrad", - cat( - samplerStateParam, - "float", base.coordCount + isArray, " location, ", - "float", base.coordCount, " gradX, ", - "float", base.coordCount, " gradY, ", - "constexpr int", base.coordCount, " offset, ", - "float lodClamp" - ), - "$ctextureGradOffsetClampARB($p, $2, $3, $4, $5, $6)$z", - spirvSampleIntrinsic(prefixInfo, noBias, noLodLevel, "gradX", "gradY", "offset", "lodClamp") - ); - } - - // `SampleLevel` - - writeFunc( - "T", - "SampleLevel", - cat( - samplerStateParam, - "float", base.coordCount + isArray, " location, ", - "float level" - ), - "$ctextureLod($p, $2, $3)$z", - spirvSampleIntrinsic(prefixInfo, noBias, "level"), - cudaSampleIntrinsic(isArray, base, true) - ); - - if( baseShape != TextureFlavor::Shape::ShapeCube ) - { - writeFunc( - "T", - "SampleLevel", - cat( - samplerStateParam, - "float", base.coordCount + isArray, " location, ", - "float level, ", - "constexpr int", base.coordCount, " offset" - ), - "$ctextureLodOffset($p, $2, $3, $4)$z", - spirvSampleIntrinsic(prefixInfo, noBias, "level", noGradX, noGradY, "offset") - ); - } -} - -void TextureTypeInfo::writeGatherExtensions() -{ - char const* baseName = prefixInfo.name; - char const* baseShapeName = base.shapeName; - - auto access = accessInfo.access; - - bool isReadOnly = (access == SLANG_RESOURCE_ACCESS_READ); - - char const* samplerStateParam = prefixInfo.combined ? "" : "SamplerState s, "; - - // `Gather*()` operations are handled via an `extension` declaration, - // because this lets us capture the element type of the texture. - // - // TODO: longer-term there should be something like a `TextureElementType` - // interface, that both scalars and vectors implement, that then exposes - // a `Scalar` associated type, and `Gather` can return `vector<T.Scalar, 4>`. - // - static const struct { - char const* genericPrefix; - char const* elementType; - char const* outputType; - } kGatherExtensionCases[] = { - { "__generic<T, let N : int>", "vector<T,N>", "vector<T, 4>" }, - { "", "float", "vector<float, 4>" }, - { "", "int" , "vector<int, 4>"}, - { "", "uint", "vector<uint, 4>"}, - - // TODO: need a case here for scalars `T`, but also - // need to ensure that case doesn't accidentally match - // for `T = vector<...>`, which requires actual checking - // of constraints on generic parameters. - }; - for(auto cc : kGatherExtensionCases) - { - // TODO: this should really be an `if` around the entire `Gather` logic - if (isMultisample) break; - - EMIT_LINE_DIRECTIVE(); - sb << cc.genericPrefix << " __extension "; - sb << accessInfo.name; - sb << baseName; - sb << baseShapeName; - if (isArray) sb << "Array"; - sb << "<" << cc.elementType << " >"; - sb << "\n{\n"; - - // `Gather` - // (tricky because it returns a 4-vector of the element type - // of the texture components...) - // - // TODO: is it actually correct to restrict these so that, e.g., - // `GatherAlpha()` isn't allowed on `Texture2D<float3>` because - // it nominally doesn't have an alpha component? - static const struct { - int componentIndex; - char const* componentName; - } kGatherComponets[] = { - { 0, "" }, - { 0, "Red" }, - { 1, "Green" }, - { 2, "Blue" }, - { 3, "Alpha" }, - }; - enum Cmp - { NotCmp, - Cmp - }; - - for(auto cmp : {NotCmp, Cmp}) - for(auto kk : kGatherComponets) - { - auto samplerOrComparisonSampler = cmp == Cmp ? "SamplerComparisonState s, " : samplerStateParam; - - auto componentIndex = kk.componentIndex; - auto componentName = kk.componentName; - - auto outputType = cc.outputType; - - const auto cmpName = cmp == Cmp ? "Cmp" : ""; - const auto cmpValueParam = cmp == Cmp ? "float compareValue, " : ""; - const auto cmpValueParamEnd = cmp == Cmp ? ", float compareValue" : ""; - const auto supportsGLSL = componentIndex == 0 || cmp == NotCmp; - - EMIT_LINE_DIRECTIVE(); - - if(supportsGLSL) - { - if(cmp == Cmp) - sb << "__target_intrinsic(glsl, \"textureGather($p, $2, $3)\")\n"; - else - sb << "__target_intrinsic(glsl, \"textureGather($p, $2, " << componentIndex << ")\")\n"; - } - if (base.coordCount == 2 && cmp == NotCmp) - { - // Gather only works on 2D in CUDA without comparison - // "It is based on the base type of DataType except when readMode is equal to cudaReadModeNormalizedFloat (see Texture Reference API), in which case it is always float4." - sb << "__target_intrinsic(cuda, \"tex2Dgather<$T0>($0, ($2).x, ($2).y, " << componentIndex << ")\")\n"; - } - if (isReadOnly) - sb << "[__readNone]\n"; - sb << outputType << " Gather" << cmpName << componentName << "(" << samplerOrComparisonSampler; - sb << "float" << base.coordCount + isArray << " location" << cmpValueParamEnd << ");\n"; - - if (isReadOnly) - sb << "[__readNone]\n"; - EMIT_LINE_DIRECTIVE(); - if(supportsGLSL) - { - if(cmp == Cmp) - sb << "__target_intrinsic(glsl, \"textureGatherOffset($p, $2, $3, $4)\")\n"; - else - sb << "__target_intrinsic(glsl, \"textureGatherOffset($p, $2, $3, " << componentIndex << ")\")\n"; - } - sb << outputType << " Gather" << cmpName << componentName << "(" << samplerOrComparisonSampler; - sb << "float" << base.coordCount + isArray << " location, "; - sb << cmpValueParam; - sb << "constexpr int" << base.coordCount << " offset);\n"; - - if (isReadOnly) - sb << "[__readNone]\n"; - EMIT_LINE_DIRECTIVE(); - sb << outputType << " Gather" << cmpName << componentName << "(" << samplerOrComparisonSampler; - sb << "float" << base.coordCount + isArray << " location, "; - sb << cmpValueParam; - sb << "constexpr int" << base.coordCount << " offset, "; - sb << "out uint status);\n"; - - if (isReadOnly) - sb << "[__readNone]\n"; - EMIT_LINE_DIRECTIVE(); - if(supportsGLSL) - { - if(cmp == Cmp) - sb << "__target_intrinsic(glsl, \"textureGatherOffsets($p, $2, $3, ivec" << base.coordCount << "[]($4, $5, $6, $7))\")\n"; - else - sb << "__target_intrinsic(glsl, \"textureGatherOffsets($p, $2, ivec" << base.coordCount << "[]($3, $4, $5, $6), " << componentIndex << ")\")\n"; - } - sb << outputType << " Gather" << cmpName << componentName << "(" << samplerOrComparisonSampler; - sb << "float" << base.coordCount + isArray << " location, "; - sb << cmpValueParam; - sb << "int" << base.coordCount << " offset1, "; - sb << "int" << base.coordCount << " offset2, "; - sb << "int" << base.coordCount << " offset3, "; - sb << "int" << base.coordCount << " offset4);\n"; - - if (isReadOnly) - sb << "[__readNone]\n"; - EMIT_LINE_DIRECTIVE(); - sb << outputType << " Gather" << cmpName << componentName << "(" << samplerOrComparisonSampler; - sb << "float" << base.coordCount + isArray << " location, "; - sb << cmpValueParam; - sb << "int" << base.coordCount << " offset1, "; - sb << "int" << base.coordCount << " offset2, "; - sb << "int" << base.coordCount << " offset3, "; - sb << "int" << base.coordCount << " offset4, "; - sb << "out uint status);\n"; - } - - EMIT_LINE_DIRECTIVE(); - sb << "\n}\n"; - } } } diff --git a/source/slang/slang-stdlib-textures.h b/source/slang/slang-stdlib-textures.h index dc2f64a41..35aed3e27 100644 --- a/source/slang/slang-stdlib-textures.h +++ b/source/slang/slang-stdlib-textures.h @@ -9,65 +9,49 @@ namespace Slang static const struct BaseTextureShapeInfo { char const* shapeName; - TextureFlavor::Shape baseShape; + SlangResourceShape baseShape; int coordCount; } kBaseTextureShapes[] = { - { "1D", TextureFlavor::Shape::Shape1D, 1 }, - { "2D", TextureFlavor::Shape::Shape2D, 2 }, - { "3D", TextureFlavor::Shape::Shape3D, 3 }, - { "Cube", TextureFlavor::Shape::ShapeCube,3 }, + { "1D", SLANG_TEXTURE_1D, 1 }, + { "2D", SLANG_TEXTURE_2D, 2 }, + { "3D", SLANG_TEXTURE_3D, 3 }, + { "Cube", SLANG_TEXTURE_CUBE, 3 }, }; static const struct BaseTextureAccessInfo { - char const* name; + char const* name; SlangResourceAccess access; } kBaseTextureAccessLevels[] = { { "", SLANG_RESOURCE_ACCESS_READ }, { "RW", SLANG_RESOURCE_ACCESS_READ_WRITE }, { "RasterizerOrdered", SLANG_RESOURCE_ACCESS_RASTER_ORDERED }, -}; - -static const struct TextureTypePrefixInfo -{ - char const* name; - bool combined; -} kTexturePrefixes[] = -{ - { "Texture", false }, - { "Sampler", true }, + { "Feedback", SLANG_RESOURCE_ACCESS_FEEDBACK }, }; struct TextureTypeInfo { TextureTypeInfo( - TextureTypePrefixInfo const& prefixInfo, BaseTextureShapeInfo const& base, bool isArray, bool isMultisample, bool isShadow, - BaseTextureAccessInfo const& accessInfo, StringBuilder& inSB, String const& inPath); - TextureTypePrefixInfo const& prefixInfo; BaseTextureShapeInfo const& base; bool isArray; bool isMultisample; bool isShadow; - BaseTextureAccessInfo const& accessInfo; StringBuilder& sb; String path; void emitTypeDecl(); -private: +public: // // Functions for writing specific parts of a definition // - void writeQueryFunctions(); - void writeSubscriptFunctions(); - void writeSampleFunctions(); - void writeGatherExtensions(); + void writeGetDimensionFunctions(); // // More general utilities @@ -75,7 +59,6 @@ private: enum class ReadNoneMode { Never, - IfReadOnly, Always }; @@ -85,17 +68,13 @@ private: const String& cuda, const String& spirv ); - void writeFuncDecorations( - const String& glsl, - const String& cuda - ); void writeFuncWithSig( const char* funcName, const String& sig, const String& glsl = String{}, const String& spirv = String{}, const String& cuda = String{}, - const ReadNoneMode readNoneMode = ReadNoneMode::IfReadOnly + const ReadNoneMode readNoneMode = ReadNoneMode::Never ); void writeFunc( const char* returnType, @@ -104,7 +83,7 @@ private: const String& glsl = String{}, const String& spirv = String{}, const String& cuda = String{}, - const ReadNoneMode readNoneMode = ReadNoneMode::IfReadOnly + const ReadNoneMode readNoneMode = ReadNoneMode::Never ); // A pointer to a string representing the current level of indentation diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp index 5a977694a..7fbd021b1 100644 --- a/source/slang/slang-stdlib.cpp +++ b/source/slang/slang-stdlib.cpp @@ -304,7 +304,6 @@ namespace Slang coreLibraryCode = StringBlob::moveCreate(sb); } #endif - return coreLibraryCode; } @@ -316,6 +315,7 @@ namespace Slang const String path = getStdlibPath(); StringBuilder sb; #include "hlsl.meta.slang.h" + File::writeAllText("d:\\stdlib1.txt", sb.toString()); hlslLibraryCode = StringBlob::moveCreate(sb); } #endif diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp index ed2ce048b..53a02ed87 100644 --- a/source/slang/slang-syntax.cpp +++ b/source/slang/slang-syntax.cpp @@ -470,6 +470,12 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt return astBuilder->getOrCreate<ThisType>(declRef.declRefBase); } + else if (auto typedefDecl = as<TypeDefDecl>(declRef.getDecl())) + { + if (typedefDecl->type.type) + return as<Type>(typedefDecl->type.type->substitute(astBuilder, SubstitutionSet(declRef))); + return astBuilder->getErrorType(); + } else { declRef = createDefaultSubstitutionsIfNeeded(astBuilder, nullptr, declRef); diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp index 8c1108870..691e5864c 100644 --- a/source/slang/slang-type-layout.cpp +++ b/source/slang/slang-type-layout.cpp @@ -3813,15 +3813,31 @@ static TypeLayoutResult _createTypeLayout( // TODO: the logic here should really be defined by the rules, // and not at this top level... ShaderParameterKind kind; - switch( textureType->getAccess() ) + if (textureType->isCombined()) { - default: - kind = ShaderParameterKind::MutableTexture; - break; + switch (textureType->getAccess()) + { + default: + kind = ShaderParameterKind::MutableTextureSampler; + break; - case SLANG_RESOURCE_ACCESS_READ: - kind = ShaderParameterKind::Texture; - break; + case SLANG_RESOURCE_ACCESS_READ: + kind = ShaderParameterKind::TextureSampler; + break; + } + } + else + { + switch( textureType->getAccess() ) + { + default: + kind = ShaderParameterKind::MutableTexture; + break; + + case SLANG_RESOURCE_ACCESS_READ: + kind = ShaderParameterKind::Texture; + break; + } } return createSimpleTypeLayout( @@ -3850,27 +3866,6 @@ static TypeLayoutResult _createTypeLayout( type, rules); } - else if (auto textureSamplerType = as<TextureSamplerType>(type)) - { - // TODO: the logic here should really be defined by the rules, - // and not at this top level... - ShaderParameterKind kind; - switch( textureSamplerType->getAccess() ) - { - default: - kind = ShaderParameterKind::MutableTextureSampler; - break; - - case SLANG_RESOURCE_ACCESS_READ: - kind = ShaderParameterKind::TextureSampler; - break; - } - - return createSimpleTypeLayout( - rules->GetObjectLayout(kind, context.objectLayoutOptions), - type, - rules); - } // TODO: need a better way to handle this stuff... #define CASE(TYPE, KIND) \ diff --git a/source/slang/slang-type-system-shared.cpp b/source/slang/slang-type-system-shared.cpp index a8265de20..54e06a792 100644 --- a/source/slang/slang-type-system-shared.cpp +++ b/source/slang/slang-type-system-shared.cpp @@ -4,18 +4,4 @@ namespace Slang { - TextureFlavor TextureFlavor::create(SlangResourceShape shape, SlangResourceAccess access) - { - TextureFlavor rs; - rs.flavor = uint16_t(shape | (access << 8)); - return rs; - } - - TextureFlavor TextureFlavor::create(SlangResourceShape shape, SlangResourceAccess access, int flags) - { - SLANG_ASSERT((flags & ~int(SLANG_RESOURCE_EXT_SHAPE_MASK)) == 0); - TextureFlavor rs; - rs.flavor = uint16_t(shape | (access << 8) | flags); - return rs; - } } diff --git a/source/slang/slang-type-system-shared.h b/source/slang/slang-type-system-shared.h index 4fa48d23e..1c8dd56aa 100644 --- a/source/slang/slang-type-system-shared.h +++ b/source/slang/slang-type-system-shared.h @@ -33,80 +33,31 @@ FOREACH_BASE_TYPE(DEFINE_BASE_TYPE) CountOf, }; - struct TextureFlavor - { - typedef TextureFlavor ThisType; - enum - { - // Mask for the overall "shape" of the texture - BaseShapeMask = SLANG_RESOURCE_BASE_SHAPE_MASK, - - // Flag for whether the shape has "array-ness" - ArrayFlag = SLANG_TEXTURE_ARRAY_FLAG, - - // Whether or not the texture stores multiple samples per pixel - MultisampleFlag = SLANG_TEXTURE_MULTISAMPLE_FLAG, - - // Whether or not this is a shadow texture - ShadowFlag = SLANG_TEXTURE_SHADOW_FLAG, - - // For feedback texture - FeedbackFlag = SLANG_TEXTURE_FEEDBACK_FLAG, - }; - - enum Shape : uint8_t - { - Shape1D = SLANG_TEXTURE_1D, - Shape2D = SLANG_TEXTURE_2D, - Shape3D = SLANG_TEXTURE_3D, - ShapeCube = SLANG_TEXTURE_CUBE, - ShapeBuffer = SLANG_TEXTURE_BUFFER, - - Shape1DArray = Shape1D | ArrayFlag, - Shape2DArray = Shape2D | ArrayFlag, - // No Shape3DArray - ShapeCubeArray = ShapeCube | ArrayFlag, - }; - - enum - { - // This the total number of expressible flavors, - // which is *not* to say that every expressible - // flavor is actual valid. - Count = 0x10000, - }; - - uint16_t flavor; - - Shape getBaseShape() const { return Shape(flavor & BaseShapeMask); } - bool isArray() const { return (flavor & ArrayFlag) != 0; } - bool isMultisample() const { return (flavor & MultisampleFlag) != 0; } - bool isFeedback() const { return (flavor & FeedbackFlag) != 0; } - bool isShadow() const { return (flavor & ShadowFlag) != 0; } - - SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const { return flavor == rhs.flavor; } - SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - - SlangResourceShape getShape() const { return SlangResourceShape(flavor & 0xFF); } - SlangResourceAccess getAccess() const { return SlangResourceAccess((flavor >> 8) & 0xFF); } - - TextureFlavor() = default; - TextureFlavor(uint32_t tag) { flavor = (uint16_t)tag; } - - static TextureFlavor create(SlangResourceShape shape, SlangResourceAccess access); - static TextureFlavor create(SlangResourceShape shape, SlangResourceAccess access, int flags); - - static TextureFlavor create(TextureFlavor::Shape shape, SlangResourceAccess access) { return create(SlangResourceShape(shape), access); } - static TextureFlavor create(TextureFlavor::Shape shape, SlangResourceAccess access, int flags) { return create(SlangResourceShape(shape), access, flags); } - - }; - enum class SamplerStateFlavor : uint8_t { SamplerState, SamplerComparisonState, }; + const int kStdlibResourceAccessReadOnly = 0; + const int kStdlibResourceAccessReadWrite = 1; + const int kStdlibResourceAccessRasterizerOrdered = 2; + const int kStdlibResourceAccessFeedback = 3; + + const int kStdlibShapeIndex1D = 0; + const int kStdlibShapeIndex2D = 1; + const int kStdlibShapeIndex3D = 2; + const int kStdlibShapeIndexCube = 3; + const int kStdlibShapeIndexBuffer = 4; + + const int kStdlibTextureShapeParameterIndex = 1; + const int kStdlibTextureIsArrayParameterIndex = 2; + const int kStdlibTextureIsMultisampleParameterIndex = 3; + const int kStdlibTextureSampleCountParameterIndex = 4; + const int kStdlibTextureAccessParameterIndex = 5; + const int kStdlibTextureIsShadowParameterIndex = 6; + const int kStdlibTextureIsCombinedParameterIndex = 7; + const int kStdlibTextureFormatParameterIndex = 8; } #endif diff --git a/source/slang/slang.natvis b/source/slang/slang.natvis index 619b76b85..b1b52bc5c 100644 --- a/source/slang/slang.natvis +++ b/source/slang/slang.natvis @@ -546,7 +546,7 @@ </Expand> </Type> <Type Name="Slang::ValNodeOperand"> - <DisplayString Condition="kind==Slang::ValNodeOperandKind::ConstantValue">Const({values.intOperand})</DisplayString> + <DisplayString Optional="true" Condition="kind==Slang::ValNodeOperandKind::ConstantValue">Const({values.intOperand})#{_debugUID}</DisplayString> <DisplayString Condition="kind==Slang::ValNodeOperandKind::ValNode">{*(Val*)values.nodeOperand}</DisplayString> <DisplayString>{values.nodeOperand}</DisplayString> <Expand> @@ -561,6 +561,8 @@ <DisplayString Condition="astNodeType == Slang::ASTNodeType::GenericAppDeclRef">{*(Slang::GenericAppDeclRef*)this}</DisplayString> <DisplayString Condition="astNodeType == Slang::ASTNodeType::ConstantIntVal">{*(Slang::ConstantIntVal*)this}</DisplayString> <DisplayString Condition="astNodeType == Slang::ASTNodeType::PolynomialIntVal">{*(Slang::PolynomialIntVal*)this}</DisplayString> + <DisplayString Condition="astNodeType == Slang::ASTNodeType::PolynomialIntValTerm">{*(Slang::PolynomialIntValTerm*)this}</DisplayString> + <DisplayString Condition="astNodeType == Slang::ASTNodeType::PolynomialIntValFactor">{*(Slang::PolynomialIntValFactor*)this}</DisplayString> <DisplayString Condition="astNodeType == Slang::ASTNodeType::GenericParamIntVal">{*(Slang::GenericParamIntVal*)this}</DisplayString> <DisplayString Condition="astNodeType == Slang::ASTNodeType::DeclaredSubtypeWitness">{*(Slang::DeclaredSubtypeWitness*)this}</DisplayString> <DisplayString Condition="astNodeType == Slang::ASTNodeType::TransitiveSubtypeWitness">{*(Slang::TransitiveSubtypeWitness*)this}</DisplayString> @@ -644,6 +646,8 @@ <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::GenericAppDeclRef">(Slang::GenericAppDeclRef*)&astNodeType</ExpandedItem> <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::ConstantIntVal">(Slang::ConstantIntVal*)&astNodeType</ExpandedItem> <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::PolynomialIntVal">(Slang::PolynomialIntVal*)&astNodeType</ExpandedItem> + <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::PolynomialIntValTerm">(Slang::PolynomialIntValTerm*)&astNodeType</ExpandedItem> + <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::PolynomialIntValFactor">(Slang::PolynomialIntValFactor*)&astNodeType</ExpandedItem> <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::GenericParamIntVal">(Slang::GenericParamIntVal*)&astNodeType</ExpandedItem> <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::DeclaredSubtypeWitness">(Slang::DeclaredSubtypeWitness*)&astNodeType</ExpandedItem> <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::TransitiveSubtypeWitness">(Slang::TransitiveSubtypeWitness*)&astNodeType</ExpandedItem> @@ -794,11 +798,41 @@ </Type> <Type Name="Slang::ConstantIntVal"> + <DisplayString Optional="true">{astNodeType,en}#{_debugUID} ({m_operands.m_buffer[1].values.intOperand} : {*(Type*)m_operands.m_buffer[0].values.nodeOperand}) </DisplayString> <DisplayString>ConstantIntVal ({m_operands.m_buffer[1].values.intOperand} : {*(Type*)m_operands.m_buffer[0].values.nodeOperand})</DisplayString> </Type> - <Type Name="Slang::GenericParamIntVal"> - <DisplayString>GenericParamIntVal ({*(DeclRefBase*)m_operands.m_buffer[1].values.nodeOperand})</DisplayString> + <Type Name="Slang::PolynomialIntVal"> + <DisplayString Optional="true">{astNodeType,en}#{_debugUID} </DisplayString> + <DisplayString>{astNodeType,en}</DisplayString> + <Expand> + <ArrayItems> + <Size>m_operands.m_count</Size> + <ValuePointer>m_operands.m_buffer</ValuePointer> + </ArrayItems> + </Expand> + </Type> + + <Type Name="Slang::PolynomialIntValTerm"> + <DisplayString Optional="true">{astNodeType,en}#{_debugUID} </DisplayString> + <DisplayString>{astNodeType,en}</DisplayString> + <Expand> + <ArrayItems> + <Size>m_operands.m_count</Size> + <ValuePointer>m_operands.m_buffer</ValuePointer> + </ArrayItems> + </Expand> + </Type> + + <Type Name="Slang::PolynomialIntValFactor"> + <DisplayString Optional="true">{astNodeType,en}#{_debugUID} </DisplayString> + <DisplayString>{astNodeType,en}</DisplayString> + <Expand> + <ArrayItems> + <Size>m_operands.m_count</Size> + <ValuePointer>m_operands.m_buffer</ValuePointer> + </ArrayItems> + </Expand> </Type> <Type Name="Slang::BasicExpressionType"> diff --git a/tests/bugs/vk-image-write.slang b/tests/bugs/vk-image-write.slang index 10141384c..ce13ebf6a 100644 --- a/tests/bugs/vk-image-write.slang +++ b/tests/bugs/vk-image-write.slang @@ -1,4 +1,5 @@ -//TEST:CROSS_COMPILE: -profile ps_5_0 -entry main -target spirv-assembly +//TEST:SIMPLE(filecheck=CHECK): -profile ps_5_0 -entry main -target spirv-assembly +//TEST:SIMPLE(filecheck=CHECK): -profile ps_5_0 -entry main -target spirv-assembly -emit-spirv-directly // Ensure that we can lower to `imageStore` correctly. @@ -11,6 +12,8 @@ void writeColor(float3 v) float4 main() : SV_Target { + // CHECK: OpImageRead + // CHECK: OpImageWrite writeColor(float3(1.0)); return float4(0); } diff --git a/tests/bugs/vk-image-write.slang.glsl b/tests/bugs/vk-image-write.slang.glsl index 7b9bcebf9..7145c0e08 100644 --- a/tests/bugs/vk-image-write.slang.glsl +++ b/tests/bugs/vk-image-write.slang.glsl @@ -36,5 +36,4 @@ void main() writeColor_0(vec3(1.00000000000000000000)); _S7 = vec4(0); return; -} - +}
\ No newline at end of file diff --git a/tests/compute/half-texture.slang b/tests/compute/half-texture.slang index 6f131c568..c87f4359c 100644 --- a/tests/compute/half-texture.slang +++ b/tests/compute/half-texture.slang @@ -29,8 +29,7 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) half h = halfTexture[pos2]; half2 h2 = halfTexture2[pos2]; half4 h4 = halfTexture4[pos2]; -#endif - +#endif // Store a results halfTexture[pos] = h2.x + h2.y; halfTexture2[pos] = h4.xy; @@ -38,4 +37,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) int index = pos.x + pos.y * 4; outputBuffer[index] = index; -}
\ No newline at end of file +} diff --git a/tests/compute/half-texture.slang.glsl b/tests/compute/half-texture.slang.glsl index 16ff4d6e1..5e273234d 100644 --- a/tests/compute/half-texture.slang.glsl +++ b/tests/compute/half-texture.slang.glsl @@ -26,25 +26,23 @@ void main() { ivec2 pos_0 = ivec2(gl_GlobalInvocationID.xy); - int _S2 = pos_0.y; + int _S1 = pos_0.y; - int _S3 = pos_0.x; + int _S2 = pos_0.x; - uvec2 _S4 = uvec2(ivec2(3 - _S2, 3 - _S3)); + ivec2 _S3 = ivec2(uvec2(ivec2(3 - _S1, 3 - _S2))); - float16_t h_0 = (float16_t(imageLoad((halfTexture_0), ivec2((_S4))).x)); - f16vec2 h2_0 = (f16vec2(imageLoad((halfTexture2_0), ivec2((_S4))).xy)); - f16vec4 h4_0 = (f16vec4(imageLoad((halfTexture4_0), ivec2((_S4))))); + float16_t _S4 = (float16_t(imageLoad((halfTexture_0), (_S3)).x)); + f16vec2 _S5 = (f16vec2(imageLoad((halfTexture2_0), (_S3)).xy)); + f16vec4 _S6 = (f16vec4(imageLoad((halfTexture4_0), (_S3)))); + ivec2 _S7 = ivec2(uvec2(pos_0)); + imageStore((halfTexture_0), (_S7), f16vec4(_S5.x + _S5.y, float16_t(0), float16_t(0), float16_t(0))); + imageStore((halfTexture2_0), (_S7), f16vec4(_S6.xy, float16_t(0), float16_t(0))); + imageStore((halfTexture4_0), (_S7), f16vec4(_S5, _S4, _S4)); - uvec2 _S5 = uvec2(pos_0); - - imageStore((halfTexture_0), ivec2((_S5)), f16vec4(h2_0.x + h2_0.y, float16_t(0), float16_t(0), float16_t(0))); - imageStore((halfTexture2_0), ivec2((_S5)), f16vec4(h4_0.xy, float16_t(0), float16_t(0))); - imageStore((halfTexture4_0), ivec2((_S5)), f16vec4(h2_0, h_0, h_0)); - - int index_0 = _S3 + _S2 * 4; - ((outputBuffer_0)._data[(uint(index_0))]) = index_0; + int index_0 = _S2 + _S1 * 4; + outputBuffer_0._data[uint(index_0)] = index_0; return; } diff --git a/tests/cross-compile/glsl-samplecmplevelzero.slang b/tests/cross-compile/glsl-samplecmplevelzero.slang index 4bfd557cc..cd2ee54bd 100644 --- a/tests/cross-compile/glsl-samplecmplevelzero.slang +++ b/tests/cross-compile/glsl-samplecmplevelzero.slang @@ -1,7 +1,7 @@ //TEST:CROSS_COMPILE(filecheck=CHECK): -profile ps_5_0 -entry main -target glsl -// CHECK: float _S3 = (textureLod(sampler2DShadow(shadowMap_0,sampler_0), vec3((_S2), (0.0)), 0)); -// CHECK: float _S4 = (textureLodOffset(sampler2DShadow(shadowMap_0,sampler_0), vec3((_S2), (0.0)), 0, (ivec2(1, 1)))); +// CHECK: float _S3 = (textureLod(sampler2DShadow(shadowMap_0,sampler_0), (_S2), 0)); +// CHECK: float _S4 = (textureLodOffset(sampler2DShadow(shadowMap_0,sampler_0), (_S2), 0, (ivec2(1, 1)))); Texture2D shadowMap; SamplerComparisonState sampler; diff --git a/tests/cross-compile/glsl-texturegather.slang b/tests/cross-compile/glsl-texturegather.slang index 125cf6df1..1647faaac 100644 --- a/tests/cross-compile/glsl-texturegather.slang +++ b/tests/cross-compile/glsl-texturegather.slang @@ -1,9 +1,10 @@ -//TEST:CROSS_COMPILE(filecheck=CHECK): -profile ps_5_0 -entry main -target glsl +//TEST:SIMPLE(filecheck=CHECK): -stage fragment -entry main -target spirv -emit-spirv-directly +//TEST:SIMPLE(filecheck=CHECK): -stage fragment -entry main -target spirv -// CHECK: textureGather(sampler2DShadow(t_0,sc_0), (loc_0), (3.0)) -// CHECK: textureGatherOffset(sampler2DShadow(t_0,sc_0), (loc_0), (3.0), (off_0)) -// CHECK: textureGatherOffsets(sampler2DShadow(t_0,sc_0), (loc_0), (3.0), ivec2[]((off_0), (off_0), (off_0), (off_0))) -// CHECK: textureGatherOffsets(sampler2DShadow(t_0,sc_0), (loc_0), (3.0), ivec2[]((ivec2(6, 6)), (ivec2(7, 7)), (ivec2(8, 8)), (ivec2(9, 9)))) +// CHECK: OpImageDrefGather +// CHECK: OpImageDrefGather +// CHECK: OpImageDrefGather +// CHECK: OpImageDrefGather Texture2D t; SamplerState s; diff --git a/tests/cross-compile/image-load.slang b/tests/cross-compile/image-load.slang index dc80288e6..fa1430c38 100644 --- a/tests/cross-compile/image-load.slang +++ b/tests/cross-compile/image-load.slang @@ -4,7 +4,8 @@ // gets properly converted to a call to `imageLoad` // and not just `texelFetch` as it would for a `Texture*`. -//TEST:CROSS_COMPILE:-target spirv-assembly -entry main -stage compute +//TEST:SIMPLE(filecheck=CHECK): -target spirv -entry main -stage compute -emit-spirv-directly +//TEST:SIMPLE(filecheck=CHECK): -target spirv -entry main -stage compute struct Params { @@ -15,5 +16,8 @@ ParameterBlock<Params> gParams; void main(uint3 tid : SV_DispatchThreadID) { - float f = gParams.tex.Load(int3(int2(tid.xy), int(tid.z))); + // CHECK: OpImageRead + // CHECK: OpImageWrite + float f = gParams.tex.Load(int3(int2(tid.xy), int(tid.z))); + gParams.tex[tid] = f + 1.0; } diff --git a/tests/cross-compile/vk-texture-indexing.slang b/tests/cross-compile/vk-texture-indexing.slang index 9a086d5bd..ace0befd5 100644 --- a/tests/cross-compile/vk-texture-indexing.slang +++ b/tests/cross-compile/vk-texture-indexing.slang @@ -1,6 +1,7 @@ // vk-texture-indexing.slang -//TEST:CROSS_COMPILE:-target spirv-assembly -entry main -stage fragment +//TEST:SIMPLE(filecheck=CHECK):-target spirv -entry main -stage fragment +//TEST_DISABLED:SIMPLE(filecheck=CHECK):-target spirv -entry main -stage fragment -emit-spirv-directly struct Params { @@ -19,6 +20,8 @@ float4 main( uint3 uv : UV) : SV_Target { + // CHECK: OpDecorate %{{.*}} NonUniform + // CHECK: OpImageFetch float v = fetchData(uv.xy, uv.z); return v; } diff --git a/tests/glsl/basic-fragment-2.slang b/tests/glsl/basic-fragment-2.slang index c958b54b0..34a364152 100644 --- a/tests/glsl/basic-fragment-2.slang +++ b/tests/glsl/basic-fragment-2.slang @@ -1,5 +1,5 @@ //TEST:SIMPLE(filecheck=CHECK): -target spirv -stage fragment -entry main -allow-glsl - +//TEST:SIMPLE(filecheck=CHECK): -target spirv -stage fragment -entry main -allow-glsl -emit-spirv-directly #version 450 core layout(location = 0) out mediump vec4 o_color; layout(location = 0) in highp vec2 v_texCoord; diff --git a/tests/glsl/flat-in.slang b/tests/glsl/flat-in.slang index 4ca68df37..3de50d7ee 100644 --- a/tests/glsl/flat-in.slang +++ b/tests/glsl/flat-in.slang @@ -1,3 +1,4 @@ +//TEST:SIMPLE(filecheck=CHECK): -target spirv -stage fragment -entry main -allow-glsl -emit-spirv-directly //TEST:SIMPLE(filecheck=CHECK): -target spirv -stage fragment -entry main -allow-glsl #version 310 es diff --git a/tests/glsl/matrix-mul.slang b/tests/glsl/matrix-mul.slang index 6ac6613f2..c87c8ad18 100644 --- a/tests/glsl/matrix-mul.slang +++ b/tests/glsl/matrix-mul.slang @@ -1,3 +1,4 @@ +//TEST:SIMPLE(filecheck=CHECK): -target spirv -stage vertex -entry main -allow-glsl -emit-spirv-directly //TEST:SIMPLE(filecheck=CHECK): -target spirv -stage vertex -entry main -allow-glsl #version 310 es layout(location = 0) in highp vec4 a_position; diff --git a/tests/glsl/out-builtin-block-redeclaration.slang b/tests/glsl/out-builtin-block-redeclaration.slang index 7a2bfc1c9..9e50c5c37 100644 --- a/tests/glsl/out-builtin-block-redeclaration.slang +++ b/tests/glsl/out-builtin-block-redeclaration.slang @@ -1,3 +1,4 @@ +//TEST:SIMPLE(filecheck=CHECK): -target spirv -stage vertex -entry main -allow-glsl -emit-spirv-directly //TEST:SIMPLE(filecheck=CHECK): -target spirv -stage vertex -entry main -allow-glsl #version 450 core diff --git a/tests/glsl/struct-construct.slang b/tests/glsl/struct-construct.slang index a1538ed9b..747c9973c 100644 --- a/tests/glsl/struct-construct.slang +++ b/tests/glsl/struct-construct.slang @@ -1,3 +1,4 @@ +//TEST:SIMPLE(filecheck=CHECK): -target spirv -stage vertex -entry main -allow-glsl -emit-spirv-directly //TEST:SIMPLE(filecheck=CHECK): -target spirv -stage vertex -entry main -allow-glsl #version 310 es diff --git a/tests/hlsl-intrinsic/sampler-feedback/sampler-feedback-basic.slang.expected b/tests/hlsl-intrinsic/sampler-feedback/sampler-feedback-basic.slang.expected index 1d4dda6b0..3b04fe62a 100644 --- a/tests/hlsl-intrinsic/sampler-feedback/sampler-feedback-basic.slang.expected +++ b/tests/hlsl-intrinsic/sampler-feedback/sampler-feedback-basic.slang.expected @@ -11,7 +11,7 @@ standard output = { "kind": "resource", "baseShape": "texture2D", "feedback": true, - "access": "write", + "access": "feedback", "resultType": { "kind": "Feedback", "name": "SAMPLER_FEEDBACK_MIN_MIP" @@ -25,7 +25,7 @@ standard output = { "kind": "resource", "baseShape": "texture2D", "feedback": true, - "access": "write", + "access": "feedback", "resultType": { "kind": "Feedback", "name": "SAMPLER_FEEDBACK_MIP_REGION_USED" @@ -40,7 +40,7 @@ standard output = { "baseShape": "texture2D", "array": true, "feedback": true, - "access": "write", + "access": "feedback", "resultType": { "kind": "Feedback", "name": "SAMPLER_FEEDBACK_MIN_MIP" @@ -55,7 +55,7 @@ standard output = { "baseShape": "texture2D", "array": true, "feedback": true, - "access": "write", + "access": "feedback", "resultType": { "kind": "Feedback", "name": "SAMPLER_FEEDBACK_MIP_REGION_USED" diff --git a/tests/hlsl-intrinsic/texture/gather-texture2darray.slang b/tests/hlsl-intrinsic/texture/gather-texture2darray.slang index 49ce8e6a1..785305a22 100644 --- a/tests/hlsl-intrinsic/texture/gather-texture2darray.slang +++ b/tests/hlsl-intrinsic/texture/gather-texture2darray.slang @@ -1,10 +1,13 @@ // gather-texture2darray.slang -//TEST:CROSS_COMPILE: -target dxbc -profile sm_5_1 -entry main -stage compute +//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry main -stage compute -emit-spirv-directly +//TEST:SIMPLE(filecheck=DXIL): -target dxil -profile sm_6_1 -entry main -stage compute +//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry main -stage compute // Test gathering from a `Texture2DArray` Texture2DArray<uint> t; +Texture2DArray<float4> t1; SamplerState s; RWBuffer<uint4> b; @@ -12,5 +15,13 @@ RWBuffer<uint4> b; [numthreads(32, 1, 1)] void main(uint3 tid : SV_DispatchThreadID) { + // DXIL: @dx.op.textureGather.i32 + // DXIL: @dx.op.textureGather.f32 + + // SPIRV: OpImageGather + // SPIRV: OpImageGather + b[tid.x] = t.Gather(s, tid); + + b[tid.x] += uint4(t1.Gather(s, tid)); } diff --git a/tests/hlsl-intrinsic/texture/texture-sample-count.slang b/tests/hlsl-intrinsic/texture/texture-sample-count.slang index 59b82fc0b..0af7b92ba 100644 --- a/tests/hlsl-intrinsic/texture/texture-sample-count.slang +++ b/tests/hlsl-intrinsic/texture/texture-sample-count.slang @@ -1,15 +1,15 @@ //TEST:SIMPLE(filecheck=CHECK): -target hlsl -profile sm_6_6 -entry main -stage compute +//TEST:SIMPLE(filecheck=DXIL): -target dxil -profile sm_6_6 -entry main -stage compute -// Test that RWTexture2DMS accepts an optional sampleCount argument +// Test that Texture2DMS accepts an optional sampleCount argument // and the argument correctly appears in the output hlsl. -// CHECK: RWTexture2DMS<uint > t_0 : register(u0); -// CHECK: RWTexture2DMS<uint, 4 > tExplicit_0 : register(u1); -// CHECK: TextureCubeMS<float4, 3 > tCube_0 : register(t0); +// CHECK: Texture2DMS<uint > t_0 : register(t0); +// CHECK: Texture2DMS<uint, 4 > tExplicit_0 : register(t1); +// DXIL: main -RWTexture2DMS<uint> t; -RWTexture2DMS<uint, 4> tExplicit; -TextureCubeMS<float4, 3> tCube; +Texture2DMS<uint> t; +Texture2DMS<uint, 4> tExplicit; SamplerState s; RWBuffer<uint4> b; @@ -18,6 +18,6 @@ RWBuffer<uint4> b; [numthreads(32, 1, 1)] void main(uint3 tid : SV_DispatchThreadID) { - let v = t.Load(int2(0, 0), 1) + tExplicit.Load(int2(1,1),2) + int(tCube.Load(int3(0,0,0), 3).x); + let v = t.Load(int2(0, 0), 1) + tExplicit.Load(int2(1,1),2); b[tid.x] = v; } diff --git a/tools/slang-reflection-test/slang-reflection-test-main.cpp b/tools/slang-reflection-test/slang-reflection-test-main.cpp index 19d8f1a18..e9d241aac 100644 --- a/tools/slang-reflection-test/slang-reflection-test-main.cpp +++ b/tools/slang-reflection-test/slang-reflection-test-main.cpp @@ -634,6 +634,7 @@ static void emitReflectionResourceTypeBaseInfoJSON( case SLANG_RESOURCE_ACCESS_RASTER_ORDERED: writer << "rasterOrdered"; break; case SLANG_RESOURCE_ACCESS_APPEND: writer << "append"; break; case SLANG_RESOURCE_ACCESS_CONSUME: writer << "consume"; break; + case SLANG_RESOURCE_ACCESS_FEEDBACK: writer << "feedback"; break; } writer << "\""; } |
