summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Kwak <82421531+jkwak-work@users.noreply.github.com>2024-09-23 16:32:47 -0700
committerGitHub <noreply@github.com>2024-09-23 16:32:47 -0700
commit3e950e11f46fa3d2a84f04345ea860907ae9715a (patch)
tree13c115fb9c41f6ceb6c270f35822cd762f624f68
parent14b1098c934927898488c057b8c517da84990595 (diff)
Implemented Combined-texture for WGSL (#5130)
* Implemented Combined-texture for WGSL * Remove unnecessary comment * Limit to std430 layout * Fix compiler warning for unused variable --------- Co-authored-by: Yong He <yonghe@outlook.com>
-rw-r--r--source/slang/slang-compiler.cpp1
-rw-r--r--source/slang/slang-emit.cpp3
-rw-r--r--source/slang/slang-ir-lower-combined-texture-sampler.cpp28
-rw-r--r--source/slang/slang-ir-lower-combined-texture-sampler.h2
-rw-r--r--source/slang/slang-type-layout.cpp120
-rw-r--r--tests/wgsl/texture-sampler-less.slang393
6 files changed, 537 insertions, 10 deletions
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index c89d94c80..1f962d625 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -547,6 +547,7 @@ namespace Slang
case CodeGenTarget::PyTorchCppBinding:
case CodeGenTarget::CSource:
case CodeGenTarget::Metal:
+ case CodeGenTarget::WGSL:
{
return PassThroughMode::None;
}
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index 6e3556064..71ef7ee33 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -973,8 +973,9 @@ Result linkAndOptimizeIR(
case CodeGenTarget::Metal:
case CodeGenTarget::MetalLib:
case CodeGenTarget::MetalLibAssembly:
+ case CodeGenTarget::WGSL:
if (requiredLoweringPassSet.combinedTextureSamplers)
- lowerCombinedTextureSamplers(irModule, sink);
+ lowerCombinedTextureSamplers(codeGenContext, irModule, sink);
break;
}
diff --git a/source/slang/slang-ir-lower-combined-texture-sampler.cpp b/source/slang/slang-ir-lower-combined-texture-sampler.cpp
index b6f65c933..656bd84a6 100644
--- a/source/slang/slang-ir-lower-combined-texture-sampler.cpp
+++ b/source/slang/slang-ir-lower-combined-texture-sampler.cpp
@@ -19,6 +19,7 @@ namespace Slang
struct LowerCombinedSamplerContext
{
Dictionary<IRType*, LoweredCombinedSamplerStructInfo> mapTypeToLoweredInfo;
+ CodeGenTarget codeGenTarget;
LoweredCombinedSamplerStructInfo lowerCombinedTextureSamplerType(IRTextureTypeBase* textureType)
{
@@ -57,8 +58,16 @@ namespace Slang
builder.createStructField(structType, info.sampler, info.samplerType);
// Type layout.
-
- auto textureResourceKind = isMutable ? LayoutResourceKind::UnorderedAccess : LayoutResourceKind::ShaderResource;
+
+ bool isWGSLTarget = codeGenTarget == CodeGenTarget::WGSL;
+ LayoutResourceKind textureResourceKind = isMutable ? LayoutResourceKind::UnorderedAccess : LayoutResourceKind::ShaderResource;
+ LayoutResourceKind samplerResourceKind = LayoutResourceKind::SamplerState;
+ if (isWGSLTarget)
+ {
+ textureResourceKind = LayoutResourceKind::DescriptorTableSlot;
+ samplerResourceKind = LayoutResourceKind::DescriptorTableSlot;
+ }
+
IRTypeLayout::Builder textureTypeLayoutBuilder(&builder);
textureTypeLayoutBuilder.addResourceUsage(
textureResourceKind,
@@ -67,7 +76,7 @@ namespace Slang
IRTypeLayout::Builder samplerTypeLayoutBuilder(&builder);
samplerTypeLayoutBuilder.addResourceUsage(
- LayoutResourceKind::SamplerState,
+ samplerResourceKind,
LayoutSize(1));
auto samplerTypeLayout = samplerTypeLayoutBuilder.build();
@@ -76,7 +85,7 @@ namespace Slang
auto textureVarLayout = textureVarLayoutBuilder.build();
IRVarLayout::Builder samplerVarLayoutBuilder(&builder, samplerTypeLayout);
- samplerVarLayoutBuilder.findOrAddResourceInfo(LayoutResourceKind::SamplerState)->offset = 0;
+ samplerVarLayoutBuilder.findOrAddResourceInfo(samplerResourceKind)->offset = isWGSLTarget ? 1 : 0;
auto samplerVarLayout = samplerVarLayoutBuilder.build();
IRStructTypeLayout::Builder layoutBuilder(&builder);
@@ -91,12 +100,14 @@ namespace Slang
};
void lowerCombinedTextureSamplers(
+ CodeGenContext* codeGenContext,
IRModule* module,
DiagnosticSink* sink)
{
SLANG_UNUSED(sink);
LowerCombinedSamplerContext context;
+ context.codeGenTarget = codeGenContext->getTargetFormat();
// Lower combined texture sampler type into a struct type.
for (auto globalInst : module->getGlobalInsts())
@@ -127,12 +138,13 @@ namespace Slang
for (auto offsetAttr : varLayout->getOffsetAttrs())
{
- if (offsetAttr->getResourceKind() == LayoutResourceKind::UnorderedAccess ||
- offsetAttr->getResourceKind() == LayoutResourceKind::ShaderResource)
+ LayoutResourceKind resKind = offsetAttr->getResourceKind();
+ if (resKind == LayoutResourceKind::UnorderedAccess ||
+ resKind == LayoutResourceKind::ShaderResource)
resOffsetAttr = offsetAttr;
- else if (offsetAttr->getResourceKind() == LayoutResourceKind::DescriptorTableSlot)
+ else if (resKind == LayoutResourceKind::DescriptorTableSlot)
descriptorTableSlotOffsetAttr = offsetAttr;
- auto info = newVarLayoutBuilder.findOrAddResourceInfo(offsetAttr->getResourceKind());
+ auto info = newVarLayoutBuilder.findOrAddResourceInfo(resKind);
info->offset = offsetAttr->getOffset();
info->space = offsetAttr->getSpace();
info->kind = offsetAttr->getResourceKind();
diff --git a/source/slang/slang-ir-lower-combined-texture-sampler.h b/source/slang/slang-ir-lower-combined-texture-sampler.h
index ccd448786..2cc3d4f75 100644
--- a/source/slang/slang-ir-lower-combined-texture-sampler.h
+++ b/source/slang/slang-ir-lower-combined-texture-sampler.h
@@ -4,11 +4,13 @@
namespace Slang
{
+ struct CodeGenContext;
struct IRModule;
class DiagnosticSink;
// Lower combined texture sampler types to structs.
void lowerCombinedTextureSamplers(
+ CodeGenContext* codeGenContext,
IRModule* module,
DiagnosticSink* sink
);
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index 57635122e..1fb8b57ab 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -896,6 +896,25 @@ struct HLSLObjectLayoutRulesImpl : ObjectLayoutRulesImpl
};
HLSLObjectLayoutRulesImpl kHLSLObjectLayoutRulesImpl;
+struct WGSLObjectLayoutRulesImpl : GLSLObjectLayoutRulesImpl
+{
+ virtual ObjectLayoutInfo GetObjectLayout(ShaderParameterKind kind, const Options& options) override
+ {
+ ObjectLayoutInfo info = GLSLObjectLayoutRulesImpl::GetObjectLayout(kind, options);
+
+ switch (kind)
+ {
+ case ShaderParameterKind::TextureSampler:
+ case ShaderParameterKind::MutableTextureSampler:
+ info.layoutInfos.add(SimpleLayoutInfo(LayoutResourceKind::DescriptorTableSlot, 1));
+ break;
+ }
+
+ return info;
+ }
+};
+WGSLObjectLayoutRulesImpl kWGSLObjectLayoutRulesImpl;
+
// HACK: Treating ray-tracing input/output as if it was another
// case of varying input/output when it really needs to be
// based on byte storage/layout.
@@ -1053,11 +1072,32 @@ struct MetalLayoutRulesFamilyImpl : LayoutRulesFamilyImpl
LayoutRulesImpl* getStructuredBufferRules(CompilerOptionSet& compilerOptions) override;
};
+struct WGSLLayoutRulesFamilyImpl : LayoutRulesFamilyImpl
+{
+ virtual LayoutRulesImpl* getAnyValueRules() override;
+ virtual LayoutRulesImpl* getConstantBufferRules(CompilerOptionSet& compilerOptions) override;
+ virtual LayoutRulesImpl* getPushConstantBufferRules() override;
+ virtual LayoutRulesImpl* getTextureBufferRules(CompilerOptionSet& compilerOptions) override;
+ virtual LayoutRulesImpl* getVaryingInputRules() override;
+ virtual LayoutRulesImpl* getVaryingOutputRules() override;
+ virtual LayoutRulesImpl* getSpecializationConstantRules() override;
+ virtual LayoutRulesImpl* getShaderStorageBufferRules(CompilerOptionSet& compilerOptions) override;
+ virtual LayoutRulesImpl* getParameterBlockRules(CompilerOptionSet& compilerOptions) override;
+
+ LayoutRulesImpl* getRayPayloadParameterRules() override;
+ LayoutRulesImpl* getCallablePayloadParameterRules() override;
+ LayoutRulesImpl* getHitAttributesParameterRules() override;
+
+ LayoutRulesImpl* getShaderRecordConstantBufferRules() override;
+ LayoutRulesImpl* getStructuredBufferRules(CompilerOptionSet& compilerOptions) override;
+};
+
GLSLLayoutRulesFamilyImpl kGLSLLayoutRulesFamilyImpl;
HLSLLayoutRulesFamilyImpl kHLSLLayoutRulesFamilyImpl;
CPULayoutRulesFamilyImpl kCPULayoutRulesFamilyImpl;
CUDALayoutRulesFamilyImpl kCUDALayoutRulesFamilyImpl;
MetalLayoutRulesFamilyImpl kMetalLayoutRulesFamilyImpl;
+WGSLLayoutRulesFamilyImpl kWGSLLayoutRulesFamilyImpl;
// CPU case
@@ -1816,6 +1856,82 @@ LayoutRulesImpl* MetalLayoutRulesFamilyImpl::getHitAttributesParameterRules()
return nullptr;
}
+// WGSL Family
+
+LayoutRulesImpl kWGSLConstantBufferLayoutRulesImpl_ = {
+ &kWGSLLayoutRulesFamilyImpl, &kStd140LayoutRulesImpl, &kWGSLObjectLayoutRulesImpl,
+};
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getAnyValueRules()
+{
+ return &kGLSLAnyValueLayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getConstantBufferRules(CompilerOptionSet&)
+{
+ return &kWGSLConstantBufferLayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getParameterBlockRules(CompilerOptionSet&)
+{
+ return &kStd140LayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getPushConstantBufferRules()
+{
+ return &kGLSLPushConstantLayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getShaderRecordConstantBufferRules()
+{
+ return &kGLSLShaderRecordLayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getTextureBufferRules(CompilerOptionSet&)
+{
+ return &kStd430LayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getVaryingInputRules()
+{
+ return &kGLSLVaryingInputLayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getVaryingOutputRules()
+{
+ return &kGLSLVaryingOutputLayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getSpecializationConstantRules()
+{
+ return &kGLSLSpecializationConstantLayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getShaderStorageBufferRules(CompilerOptionSet&)
+{
+ return &kStd430LayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getRayPayloadParameterRules()
+{
+ return &kGLSLRayPayloadParameterLayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getCallablePayloadParameterRules()
+{
+ return &kGLSLCallablePayloadParameterLayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getHitAttributesParameterRules()
+{
+ return &kGLSLHitAttributesParameterLayoutRulesImpl_;
+}
+
+LayoutRulesImpl* WGSLLayoutRulesFamilyImpl::getStructuredBufferRules(CompilerOptionSet&)
+{
+ return &kGLSLStructuredBufferLayoutRulesImpl_;
+}
+
LayoutRulesFamilyImpl* getDefaultLayoutRulesFamilyForTarget(TargetRequest* targetReq)
{
@@ -1831,9 +1947,11 @@ LayoutRulesFamilyImpl* getDefaultLayoutRulesFamilyForTarget(TargetRequest* targe
case CodeGenTarget::GLSL:
case CodeGenTarget::SPIRV:
case CodeGenTarget::SPIRVAssembly:
- case CodeGenTarget::WGSL:
return &kGLSLLayoutRulesFamilyImpl;
+ case CodeGenTarget::WGSL:
+ return &kWGSLLayoutRulesFamilyImpl;
+
case CodeGenTarget::HostHostCallable:
case CodeGenTarget::ShaderHostCallable:
case CodeGenTarget::HostExecutable:
diff --git a/tests/wgsl/texture-sampler-less.slang b/tests/wgsl/texture-sampler-less.slang
new file mode 100644
index 000000000..1a6cb5341
--- /dev/null
+++ b/tests/wgsl/texture-sampler-less.slang
@@ -0,0 +1,393 @@
+// WGSL supports "textureSample()" only in fragment shader
+//TEST:SIMPLE(filecheck=WGSL): -stage fragment -entry fragMain -target wgsl
+
+// TODO: offset variants requires the offset value to be compile-time constant
+// But the keyword, `constexpr`, doesn't seem to work for the combined-textures
+#define TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET 0
+
+//WGSL:@binding(0) {{.*}}t1D_f32v3{{.*}} : texture_1d<f32>;
+//WGSL:@binding(1) {{.*}}t1D_f32v3{{.*}} : sampler;
+//TEST_INPUT: TextureSampler1D(size=4, content = zero):name t1D_f32v3
+Sampler1D<float3> t1D_f32v3;
+
+//WGSL:@binding(2) {{.*}}t2D_f32v3{{.*}} : texture_2d<f32>;
+//WGSL:@binding(3) {{.*}}t2D_f32v3{{.*}} : sampler;
+//TEST_INPUT: TextureSampler2D(size=4, content = zero):name t2D_f32v3
+Sampler2D<float3> t2D_f32v3;
+
+//TEST_INPUT: TextureSampler3D(size=4, content = zero):name t3D_f32v3
+Sampler3D<float3> t3D_f32v3;
+//TEST_INPUT: TextureSamplerCube(size=4, content = zero):name tCube_f32v3
+SamplerCube<float3> tCube_f32v3;
+
+//TEST_INPUT: TextureSampler1D(size=4, content = zero, arrayLength=2):name t1DArray_f32v3
+Sampler1DArray<float3> t1DArray_f32v3;
+//TEST_INPUT: TextureSampler2D(size=4, content = zero, arrayLength=2):name t2DArray_f32v3
+Sampler2DArray<float3> t2DArray_f32v3;
+//TEST_INPUT: TextureSamplerCube(size=4, content = zero, arrayLength=2):name tCubeArray_f32v3
+SamplerCubeArray<float3> tCubeArray_f32v3;
+
+//TEST_INPUT: TextureSampler1D(size=4, content = zero):name t1D_f32v4
+Sampler1D<float4> t1D_f32v4;
+//TEST_INPUT: TextureSampler2D(size=4, content = zero):name t2D_f32v4
+Sampler2D<float4> t2D_f32v4;
+//TEST_INPUT: TextureSampler3D(size=4, content = zero):name t3D_f32v4
+Sampler3D<float4> t3D_f32v4;
+//TEST_INPUT: TextureSamplerCube(size=4, content = zero):name tCube_f32v4
+SamplerCube<float4> tCube_f32v4;
+
+//TEST_INPUT: TextureSampler1D(size=4, content = zero, arrayLength=2):name t1DArray_f32v4
+Sampler1DArray<float4> t1DArray_f32v4;
+//TEST_INPUT: TextureSampler2D(size=4, content = zero, arrayLength=2):name t2DArray_f32v4
+Sampler2DArray<float4> t2DArray_f32v4;
+//TEST_INPUT: TextureSamplerCube(size=4, content = zero, arrayLength=2):name tCubeArray_f32v4
+SamplerCubeArray<float4> tCubeArray_f32v4;
+
+__generic<T : __BuiltinType, let sampleCount:int=0, let format:int=0>
+typealias CombinedDepth2d = __TextureImpl<
+ T,
+ __Shape2D,
+ 0, // isArray
+ 0, // isMS
+ sampleCount,
+ 0, // access
+ 1, // isShadow
+ 1, // isCombined
+ format
+>;
+
+__generic<T : __BuiltinType, let sampleCount:int=0, let format:int=0>
+typealias CombinedDepth2d_array = __TextureImpl<
+ T,
+ __Shape2D,
+ 1, // isArray
+ 0, // isMS
+ sampleCount,
+ 0, // access
+ 1, // isShadow
+ 1, // isCombined
+ format
+>;
+
+__generic<T : __BuiltinType, let sampleCount:int=0, let format:int=0>
+typealias CombinedDepthcube = __TextureImpl<
+ T,
+ __ShapeCube,
+ 0, // isArray
+ 0, // isMS
+ sampleCount,
+ 0, // access
+ 1, // isShadow
+ 1, // isCombined
+ format
+>;
+
+__generic<T : __BuiltinType, let sampleCount:int=0, let format:int=0>
+typealias CombinedDepthcube_array = __TextureImpl<
+ T,
+ __ShapeCube,
+ 1, // isArray
+ 0, // isMS
+ sampleCount,
+ 0, // access
+ 1, // isShadow
+ 1, // isCombined
+ format
+>;
+
+//TEST_INPUT: TextureSampler2D(size=4, content = zero):name d2D
+CombinedDepth2d<float> d2D;
+//TEST_INPUT: TextureSamplerCube(size=4, content = zero):name dCube
+CombinedDepthcube<float> dCube;
+//TEST_INPUT: TextureSampler2D(size=4, content = zero, arrayLength=2):name d2DArray
+CombinedDepth2d_array<float> d2DArray;
+//TEST_INPUT: TextureSamplerCube(size=4, content = zero, arrayLength=2):name dCubeArray
+CombinedDepthcube_array<float> dCubeArray;
+
+//TEST_INPUT: ubuffer(data=[0], stride=4):out,name outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+
+__generic<T:__BuiltinArithmeticType, let N:int>
+bool TEST_texture(
+ Sampler1D<vector<T,N>> t1D,
+ Sampler2D<vector<T,N>> t2D,
+ Sampler3D<vector<T,N>> t3D,
+ SamplerCube<vector<T,N>> tCube,
+ Sampler1DArray<vector<T,N>> t1DArray,
+ Sampler2DArray<vector<T,N>> t2DArray,
+ SamplerCubeArray<vector<T,N>> tCubeArray
+)
+{
+ // WGSL-LABEL: TEST_texture
+ typealias Tvn = vector<T,N>;
+ typealias Tv4 = vector<T,4>;
+
+ float u = 0;
+ float u2 = 0.5;
+ constexpr const float ddx = 0.0f;
+ constexpr const float ddy = 0.0f;
+
+ bool result = true
+ // ===============================
+ // float CalculateLevelOfDetail()
+ // ===============================
+ // WGSL doesn't have a way to calculate mip-map level for the given coordinate
+
+ // ========================================
+ // float CalculateLevelOfDetailUnclamped()
+ // ========================================
+ // WGSL doesn't have a way to calculate mip-map level for the given coordinate
+
+ // ===========
+ // T Sample()
+ // https://www.w3.org/TR/WGSL/#texturesample
+ // ===========
+
+ // WGSL: textureSample({{\(*}}t1D
+ && all(Tvn(T(0)) == t1D.Sample(u))
+
+ // WGSL: textureSample({{\(*}}t2D
+ && all(Tvn(T(0)) == t2D.Sample(float2(u, u)))
+
+ // WGSL: textureSample({{\(*}}t3D
+ && all(Tvn(T(0)) == t3D.Sample(float3(u, u, u)))
+
+ // WGSL: textureSample({{\(*}}tCube
+ && all(Tvn(T(0)) == tCube.Sample(normalize(float3(u, 1 - u, u))))
+
+ // WGSL doesn't support textureSample for 1d_array and 3d_array; only 2d and cube
+
+ // WGSL: textureSample({{\(*}}t2DArray
+ && all(Tvn(T(0)) == t2DArray.Sample(float3(u, u, 0)))
+
+ // WGSL: textureSample({{\(*}}tCubeArray
+ && all(Tvn(T(0)) == tCubeArray.Sample(float4(normalize(float3(u, 1 - u, u)), 0)))
+
+#if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+ // Offset variant
+
+ // WGSL: textureSample({{\(*}}t1D
+ && all(Tvn(T(0)) == t1D.Sample(u, 1))
+
+ // WGSL: textureSample({{\(*}}t2D
+ && all(Tvn(T(0)) == t2D.Sample(float2(u, u), int2(1, 1)))
+
+ // WGSL: textureSample({{\(*}}t3D
+ && all(Tvn(T(0)) == t3D.Sample(float3(u, u, u), int3(1, 1, 1)))
+
+ // WGSL doesn't support offset variant for cube and cube_array
+
+ // WGSL: textureSample({{\(*}}t2DArray
+ && all(Tvn(T(0)) == t2DArray.Sample(float3(u, u, 0), int2(1, 1)))
+#endif // #if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+
+ // ===============
+ // T SampleBias()
+ // https://www.w3.org/TR/WGSL/#texturesamplebias
+ // ===============
+
+ // WGSL doesn't support Bias for 1D texture
+
+ // WGSL: textureSampleBias({{\(*}}t2D
+ && all(Tvn(T(0)) == t2D.SampleBias(float2(u, u), float(-1)))
+
+ // WGSL: textureSampleBias({{\(*}}t3D
+ && all(Tvn(T(0)) == t3D.SampleBias(float3(u, u, u), float(-1)))
+
+ // WGSL: textureSampleBias({{\(*}}tCube
+ && all(Tvn(T(0)) == tCube.SampleBias(normalize(float3(u, 1 - u, u)), float(-1)))
+
+ // WGSL: textureSampleBias({{\(*}}t2DArray
+ && all(Tvn(T(0)) == t2DArray.SampleBias(float3(u, u, 0), float(-1)))
+
+ // WGSL: textureSampleBias({{\(*}}tCubeArray
+ && all(Tvn(T(0)) == tCubeArray.SampleBias(float4(normalize(float3(u, 1 - u, u)), 0), float(-1)))
+
+#if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+ // Offset variant
+
+ // W-GSL: textureSampleBias({{\(*}}t2D
+ && all(Tvn(T(0)) == t2D.SampleBias(float2(u, u), float(-1), int2(1, 1)))
+
+ // W-GSL: textureSampleBias({{\(*}}t3D
+ && all(Tvn(T(0)) == t3D.SampleBias(float3(u, u, u), float(-1), int3(1, 1, 1)))
+
+ // W-GSL: textureSampleBias({{\(*}}t2DArray
+ && all(Tvn(T(0)) == t2DArray.SampleBias(float3(u, u, 0), float(-1), int2(1, 1)))
+#endif // #if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+
+ // ===================================
+ // T SampleLevel()
+ // https://www.w3.org/TR/WGSL/#texturesamplelevel
+ // ===================================
+
+ // WGSL doesn't support textureSampleLevel for 1D texture
+
+ // WGSL: textureSampleLevel({{\(*}}t2D
+ && all(Tvn(T(0)) == t2D.SampleLevel(float2(u, u), 0))
+
+ // WGSL: textureSampleLevel({{\(*}}t3D
+ && all(Tvn(T(0)) == t3D.SampleLevel(float3(u, u, u), 0))
+
+ // WGSL: textureSampleLevel({{\(*}}tCube
+ && all(Tvn(T(0)) == tCube.SampleLevel(normalize(float3(u, 1 - u, u)), 0))
+
+ // WGSL: textureSampleLevel({{\(*}}t2DArray
+ && all(Tvn(T(0)) == t2DArray.SampleLevel(float3(u, u, 0), 0))
+
+ // WGSL: textureSampleLevel({{\(*}}tCubeArray
+ && all(Tvn(T(0)) == tCubeArray.SampleLevel(float4(normalize(float3(u, 1 - u, u)), 0), 0))
+
+#if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+ // Offset variant
+
+ // W-GSL: textureSampleLevel({{\(*}}t2D
+ && all(Tvn(T(0)) == t2D.SampleLevel(float2(u, u), 0, int2(1, 1)))
+
+ // W-GSL: textureSampleLevel({{\(*}}t3D
+ && all(Tvn(T(0)) == t3D.SampleLevel(float3(u, u, u), 0, int3(1, 1, 1)))
+
+ // W-GSL: textureSampleLevel({{\(*}}t2DArray
+ && all(Tvn(T(0)) == t2DArray.SampleLevel(float3(u, u, 0), 0, int2(1, 1)))
+#endif // #if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+
+ // ==================
+ // float SampleCmp()
+ // https://www.w3.org/TR/WGSL/#texturesamplecompare
+ // ==================
+
+ // WGSL: textureSampleCompare({{\(*}}d2D
+ && float(0) == d2D.SampleCmp(float2(u, u), 0)
+
+ // WGSL: textureSampleCompare({{\(*}}d2DArray
+ && float(0) == d2DArray.SampleCmp(float3(u, u, 0), 0)
+
+ // WGSL: textureSampleCompare({{\(*}}dCube
+ && float(0) == dCube.SampleCmp(normalize(float3(u, 1 - u, u)), 0)
+
+ // WGSL: textureSampleCompare({{\(*}}dCubeArray
+ && float(0) == dCubeArray.SampleCmp(float4(normalize(float3(u, 1 - u, u)), 0), 0)
+
+#if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+ // Offset variant
+
+ // W-GSL: textureSampleCompare({{\(*}}d2D
+ && float(0) == d2D.SampleCmp(float2(u2, u), 0, int2(0, 0))
+
+ // W-GSL: textureSampleCompare({{\(*}}d2DArray
+ && float(0) == d2DArray.SampleCmp(float3(u2, u, u), 0, int2(0, 0))
+#endif // #if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+
+ // ===================================
+ // float SampleCmpLevelZero()
+ // https://www.w3.org/TR/WGSL/#texturesamplecomparelevel
+ // ===================================
+
+ // WGSL: textureSampleCompareLevel({{\(*}}d2D
+ && float(0) == d2D.SampleCmpLevelZero(float2(u, u), 0)
+
+ // WGSL: textureSampleCompareLevel({{\(*}}d2DArray
+ && float(0) == d2DArray.SampleCmpLevelZero(float3(u, u, 0), 0)
+
+ // WGSL: textureSampleCompareLevel({{\(*}}dCube
+ && float(0) == dCube.SampleCmpLevelZero(normalize(float3(u, 1 - u, u)), 0)
+
+ // WGSL: textureSampleCompareLevel({{\(*}}dCubeArray
+ && float(0) == dCubeArray.SampleCmpLevelZero(float4(normalize(float3(u, 1-u, u)), 0), 0)
+
+#if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+ // Offset variant
+
+ // W-GSL: textureSampleCompareLevel({{\(*}}d2D
+ && float(0) == d2D.SampleCmpLevelZero(float2(u2, u), 0, int2(0, 0))
+
+ // W-GSL: textureSampleCompareLevel({{\(*}}d2DArray
+ && float(0) == d2DArray.SampleCmpLevelZero(float3(u2, u, u), 0, int2(0, 0))
+#endif // #if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+
+ // ==================================
+ // vector<T,4> Gather()
+ // https://www.w3.org/TR/WGSL/#texturegather
+ // ==================================
+
+#if 0
+ && all(Tv4(T(0)) == t2D.Gather(float2(u, u)))
+
+ && all(Tv4(T(0)) == tCube.Gather(normalize(float3(u, 1 - u, u))))
+
+ && all(Tv4(T(0)) == t2DArray.Gather(float3(u, u, 0)))
+
+ && all(Tv4(T(0)) == tCubeArray.Gather(float4(normalize(float3(u, 1 - u, u)), 0)))
+
+#if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+ // Offset variant
+
+ && all(Tv4(T(0)) == t2D.Gather(float2(u2, u), int2(0, 0)))
+
+ && all(Tv4(T(0)) == t2DArray.Gather(float3(u2, u, 0), int2(0, 0)))
+#endif // #if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+#endif
+
+ // =====================================
+ // T SampleGrad()
+ // https://www.w3.org/TR/WGSL/#texturesamplegrad
+ // =====================================
+
+ // WGSL doesn't support textureSampleGrad for 1D textures
+
+ // WGSL: textureSampleGrad({{\(*}}t2D
+ && all(Tvn(T(0)) == t2D.SampleGrad(float2(u, u), float2(ddx, ddx), float2(ddy, ddy)))
+
+ // WGSL: textureSampleGrad({{\(*}}t3D
+ && all(Tvn(T(0)) == t3D.SampleGrad(float3(u, u, u), float3(ddx, ddx, ddx), float3(ddy, ddy, ddy)))
+
+ // WGSL: textureSampleGrad({{\(*}}tCube
+ && all(Tvn(T(0)) == tCube.SampleGrad(normalize(float3(u, 1 - u, u)), float3(ddx, ddx, ddx), float3(ddy, ddy, ddy)))
+
+ // WGSL: textureSampleGrad({{\(*}}t2DArray
+ && all(Tvn(T(0)) == t2DArray.SampleGrad(float3(u, u, 0.0f), float2(ddx, ddx), float2(ddy, ddy)))
+
+ // WGSL: textureSampleGrad({{\(*}}tCubeArray
+ && all(Tvn(T(0)) == tCubeArray.SampleGrad(float4(normalize(float3(u, 1 - u, u)), 0), float3(ddx, ddx, ddx), float3(ddy, ddy, ddy)))
+
+#if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+ // Offset variant
+
+ // W-GSL: textureSampleGrad({{\(*}}t2D
+ && all(Tvn(T(0)) == t2D.SampleGrad(float2(u2, u), float2(ddx, ddx), float2(ddy, ddy), int2(0, 0)))
+
+ // W-GSL: textureSampleGrad({{\(*}}t3D
+ && all(Tvn(T(0)) == t3D.SampleGrad(float3(u2, u, u), float3(ddx, ddx, ddx), float3(ddy, ddy, ddy), int3(0, 0, 0)))
+
+ // W-GSL: textureSampleGrad({{\(*}}t2DArray
+ && all(Tvn(T(0)) == t2DArray.SampleGrad(float3(u2, u, 0.0f), float2(ddx, ddx), float2(ddy, ddy), int2(0, 0)))
+#endif // #if TEST_WHEN_CONSTEXPR_WORKS_FOR_OFFSET
+ ;
+
+ return result;
+}
+
+void fragMain()
+{
+ bool result = true
+ && TEST_texture<float, 3>(
+ t1D_f32v3,
+ t2D_f32v3,
+ t3D_f32v3,
+ tCube_f32v3,
+ t1DArray_f32v3,
+ t2DArray_f32v3,
+ tCubeArray_f32v3)
+ && TEST_texture<float, 4>(
+ t1D_f32v4,
+ t2D_f32v4,
+ t3D_f32v4,
+ tCube_f32v4,
+ t1DArray_f32v4,
+ t2DArray_f32v4,
+ tCubeArray_f32v4)
+ ;
+
+ outputBuffer[0] = int(result);
+}