From 045192e1021f80c52f0fabddb54cd0c8398fb898 Mon Sep 17 00:00:00 2001 From: Simon Kallweit Date: Tue, 20 Jan 2026 12:03:00 +0100 Subject: [PATCH] Add support for casting DescriptorHandle <-> uint64_t on CUDA --- source/slang/hlsl.meta.slang | 5 ++ .../desc-handle-cuda-uint64.slang | 58 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 tests/language-feature/descriptor-handle/desc-handle-cuda-uint64.slang diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index dd44b455ee..4b087b5ac0 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -24606,6 +24606,7 @@ struct DescriptorHandle : IComparable /// Constructor for uint64_t handles [ForceInline] [require(spvBindlessTextureNV)] + [require(cuda)] __intrinsic_op($(kIROp_CastUInt64ToDescriptorHandle)) __init(uint64_t handleValue); @@ -24615,6 +24616,7 @@ struct DescriptorHandle : IComparable __target_switch { case spvBindlessTextureNV: + case cuda: return (uint64_t)this == (uint64_t)other; default: return all(__vectorEql((uint2)this, (uint2)other)); @@ -24627,6 +24629,7 @@ struct DescriptorHandle : IComparable __target_switch { case spvBindlessTextureNV: + case cuda: return (uint64_t)this < (uint64_t)other; default: let vthis = ((uint2)this); @@ -24641,6 +24644,7 @@ struct DescriptorHandle : IComparable __target_switch { case spvBindlessTextureNV: + case cuda: return (uint64_t)this <= (uint64_t)other; default: let vthis = ((uint2)this); @@ -24663,6 +24667,7 @@ extension uint64_t { __intrinsic_op($(kIROp_CastDescriptorHandleToUInt64)) [require(spvBindlessTextureNV)] + [require(cuda)] __init(DescriptorHandle bindless); } diff --git a/tests/language-feature/descriptor-handle/desc-handle-cuda-uint64.slang b/tests/language-feature/descriptor-handle/desc-handle-cuda-uint64.slang new file mode 100644 index 0000000000..86321cc4a2 --- /dev/null +++ b/tests/language-feature/descriptor-handle/desc-handle-cuda-uint64.slang @@ -0,0 +1,58 @@ +//TEST:SIMPLE(filecheck=CUDA): -target cuda -entry computeMain -stage compute + +// Test that DescriptorHandle can be constructed from uint64_t in CUDA. +// In CUDA, DescriptorHandle becomes transparent and maps directly to the underlying +// resource type (CUtexObject/CUsurfObject which are ulonglong). This means: +// 1. uint64_t -> DescriptorHandle conversion is a no-op cast +// 2. DescriptorHandle -> uint64_t conversion is a no-op cast +// 3. Comparison methods (equals, lessThan, etc.) cannot be called directly because +// the handle type is erased to the resource type at compile time. + +// CUDA-DAG: ulonglong textureHandle +// CUDA-DAG: tex2DLod +// CUDA-DAG: void computeMain + +uniform uint64_t textureHandle; +uniform uint64_t textureHandle2; + +// Cast uint64_t to DescriptorHandle and use it +DescriptorHandle getTextureHandle(uint64_t h) +{ + return DescriptorHandle(h); +} + +// Cast DescriptorHandle to uint64_t +uint64_t getHandleValue(DescriptorHandle h) +{ + return (uint64_t)h; +} + +// Test that we can compare handles using uint64_t comparisons +// (since direct method calls aren't available in CUDA) +bool compareHandles(uint64_t h1, uint64_t h2) +{ + DescriptorHandle handle1 = DescriptorHandle(h1); + DescriptorHandle handle2 = DescriptorHandle(h2); + // Convert back to uint64_t for comparison + return (uint64_t)handle1 == (uint64_t)handle2; +} + +uniform RWStructuredBuffer output; + +[numthreads(1,1,1)] +void computeMain() +{ + // Test construction from uint64_t - creates a texture handle + DescriptorHandle tex = DescriptorHandle(textureHandle); + + // Test conversion to uint64_t and back + uint64_t handleValue = (uint64_t)tex; + DescriptorHandle tex2 = DescriptorHandle(handleValue); + + // Test comparison via uint64_t conversion + bool same = compareHandles(textureHandle, textureHandle2); + + // Sample the texture using the handle + output[0] = tex->SampleLevel(float2(0.0), 0.0); + output[1] = float4(same ? 1.0 : 0.0, 0.0, 0.0, 0.0); +}