diff options
| author | Yong He <yonghe@outlook.com> | 2025-01-10 10:57:04 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-10 10:57:04 -0800 |
| commit | 5290c580632cfb56847b863a32dc020a21d1c93e (patch) | |
| tree | 4c543f28d13f62a1dc3293b76151dda7585743ab /docs | |
| parent | 4cfae806a6f9c0203ce44c4ce04df5ad66cdc8a2 (diff) | |
Initial implementation of SP#015 `DescriptorHandle<T>`. (#6028)
* Initial implementation of `ResourcePtr<T>`.
* Update docs
* Fix build error.
* Add more discussion.
* Update documentation.
* Update TOC.
* Fix.
* Fix.
* Add test case for custom `getResourceFromBindlessHandle`.
* Add namehint to generated descriptor heap param.
* Fix.
* Fix.
* format code
* Rename to `DescriptorHandle`, and add `T.Handle` alias.
* Fix compiler error.
* Fix.
* Fix build.
* Renames.
* Fix documentation.
* Documentation fix.
---------
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/proposals/015-bindless-t.md | 199 | ||||
| -rw-r--r-- | docs/proposals/015-descriptor-handle.md | 260 | ||||
| -rw-r--r-- | docs/user-guide/03-convenience-features.md | 114 | ||||
| -rw-r--r-- | docs/user-guide/toc.html | 1 |
4 files changed, 375 insertions, 199 deletions
diff --git a/docs/proposals/015-bindless-t.md b/docs/proposals/015-bindless-t.md deleted file mode 100644 index 89640f29a..000000000 --- a/docs/proposals/015-bindless-t.md +++ /dev/null @@ -1,199 +0,0 @@ -SP #015 - `Bindless<T>` type -============== - -## Status - -Author: Yong He - -Status: Design review. - -Implementation: - -Reviewed by: Theresa Foley - -## Background - -Textures, sampler states and buffers are typically passed to shader as opaque handles whose size and storage address is undefined. These handles are communicated to the GPU via "bind states" that are modified with host-side APIs. Because the handle has unknown size, it is not possible to read, copy or construct such a handle from the shader code, and it is not possible to store the handle in buffer memory. This makes both host code and shader code difficult to write and prevents more flexible encapsulation or clean object-oriented designs. - -With the recent advancement in hardware capabilities, a lot of modern graphics systems are adopting a "bindless" parameter passing idiom, where all resource handles are passed to the shader in a single global array, and all remaining references to texture, buffers or sampler states are represented as a single integer index into the array. This allows the shader code to workaround the restrictions around the opaque handle types. - -Direct3D Shader Model 6.6 introduces the "Dynamic Resources" capability, which further simplifies the way to write bindless shader code by removing the need to even declare the global array. - -We believe that graphics developers will greatly benefit from a system defined programming model for the bindless parameter passing idom that is versatile and cross-platform, which will provide a consistent interface so that different shader libraries using the bindless pattern can interop with each other without barriers. - -## Proposed Approach - -We introduce a `Bindless<T>` type that is defined as: -``` -struct Bindless<T> : IComparable<Bindless<T>> - where T : IOpaqueHandle -{ - __init(uint64_t value); -} -``` -Where `IOpaqueHandle` is an interface that is implemented by all texture, buffer and sampler state types: - -```slang -enum ResourceKind -{ - Unknown, Texture, ConstantBuffer, StorageBuffer, Sampler -} -interface IOpaqueHandle -{ - static const ResourceKind kind; -} -``` - -### Basic Usage - -`Bindless<T>` should provide the following features: - -- Construction/explicit cast from a 64-bit integer. -- Explicit cast to a 64-bit integer. -- Equality comparison. -- Implicit dereference to `T`. -- Implicit conversion to `T`. - -For example: - -```slang -uniform Bindless<Texture2D> texture; -uniform Bindless<SamplerState> sampler; - -void test() -{ - // Explicit cast from bindless handle to uint64_t value. - let idx = (uint64_t)texture; - - // Constructing bindless handle from uint64_t value. - let t = Bindless<Texture2D>(idx); - - // Comparison. - ASSERT(t == texture); - - // OK, `t` is first implicitly dereferenced to producee `Texture2D`, and - // then `Texture2D::Sample` is called. - // The `sampler` argument is implicitly converted from `Bindless<SamplerState>` - // to `SamplerState`. - t.Sample(sampler, float2(0,0)); -} -``` - -A `Bindless<T>` type is a concrete type whose size is always 8 bytes and is internally a 64-bit integer. -This means that you can use a `Bindless<T>` type in any context where an ordinary data type, e.g. `int` type -is allowed, such as in buffer elements. - -On targets where resource handles are already concrete and sized types, `Bindless<T>` simply translates to just `T`. -If `T` has native size or alignment that is less than 8 bytes, it will be rounded up to 8 bytes. If the native size for -`T` is greater than 8 bytes, it will be treated as an opaque type instead of translating to `T`. - -### Obtaining Actual Resource Handle from `Bindless<T>` - -Depending on the target platform and the design choices of the user's application, the way to obtain the actual -resource handle from a `Bindless<T>` integer handle can vary. Slang does not dictate how this conversion is done, -and instead, this is left to the user via Slang's link-time specialization ability. - -Slang defines the following core module declarations: - -```slang -extern T getResourceFromBindlessHandle(uint64_t handle) where T : IOpaqueHandle -{ - // Default Implementation - // ... -} -``` - -The `getResourceFromBindlessHandle` is used to convert from a bindless handle to actual opaque resource handle. -If this function is not provided by the user, the default implementation defined in the core module will be used. - -By default, the core module implementation of `getResourceFromBindlessHandle` should use the `ResourceDescriptorHeap` and -`SamplerDescriptorHeap` builtin object when generating HLSL code. When generating code on other targets, `getResourceFromBindlessHandle` -will fetch the resource handle from a system defined global array of the corresponding resource type. - -If/when SPIRV is extended to expose similar capabilities as D3D's `ResourceDescriptorHeap` feature, we should change the default implementation -to use that instead. Until we know the default implementation of `getResourceFromBindlessHandle` is stable, we should advise users -to provide their own implementation of `getResourceFromBindlessHandle` to prevent breakages. - -If the user application requires a different bindless implementation, this default behavior can be overrided by defining -`getResourceFromBindlessHandle` in the user code. Below is a possible user-space implementation of `getResourceFromBindlessHandle` -for Vulkan: - -```slang - -// All texture and buffer handles are defined in descriptor set 100. -[vk::binding(0, 100)] -__DynamicResource<__DynamicResourceKind.General> resourceHandles[]; - -// All sampler handles are defined in descriptor set 101. -[vk::binding(0, 101)] -__DynamicResource<__DynamicResourceKind.Sampler> samplerHandles[]; - -export getResourceFromBindlessHandle<T>(uint64_t handle) where T : IOpaqueHandle -{ - if (T.kind == ResourceKind.Sampler) - return (T)samplerHandles[handle]; - else - return (T)resourceHandles[handle]; -} -``` - -### Invalid Handle - -We reserve `uint64_t.maxValue` as a special handle value of `Bindless<T>` types to mean an invalid/null resource. -This will allow us to optimize `Optional<Bindless<Texture2D>>` to use the reserved value to mean no-value. - -The user should also be able to use `Bindless<T>.invalid` to refer to such an invalid value: - -```slang -struct Bindless<T> where T:IOpaqueHandle -{ - static const Bindless<T> invalid = Bindless<T>(uint64_t.maxValue); -} -``` - -## Alternatives Considered - -We initially considered to support a more general `Bindless<T>` where `T` can be any composite type, for example, allowing the following: - -```slang -struct Foo -{ - Texture2D t; - SamplerState s; - float ordinaryData; -} - -uniform Bindless<Foo> foo; -``` - -which is equivalent to: - -```slang -struct Bindless_Foo -{ - Bindless<Texture2D> t; - Bindless<SamplerState> s; - float s; -} -uniform Bindless_Foo foo; -``` - -While relaxing `T` this way adds an extra layer of convenience, it introduces complicated -semantic rules to the type system, and there is increased chance of exposing tricky corner -cases that are hard to get right. - -An argument for allowing `T` to be general composite types is that it enables sharing the same -code for both bindless systems and bindful systems. But this argument can also be countered by -allowing the compiler to treat `Bindless<T>` as `T` in a special mode if this feature is found to be useful. - -For now we think that restricting `T` to be an `IOpaqueHandle` type will result in a much simpler implementation, and is likely sufficient for current needs. Given that the trend of modern GPU architecture is moving towards bindless idioms and the whole idea of opaque handles may disappear in the future, we should be cautious at inventing too many heavy weight mechanisms around opaque handles. Nevertheless, this proposal still allows us to relax this requirement in the future if it becomes clear that such feature is valuable to our users. - -## Conclusion - -This proposal introduces a standard way to achieve bindless parameter passing idom on current graphics platforms. -Standardizing the way of writing bindless parameter binding code is essential for creating reusable shader code -libraries. The convenience language features around `Bindless<T>` type should also make shader code easier to write -and to maintain. Finally, by using Slang's link time specialization feature, -this proposal allows Slang to not get into the way of dicatating one specific way of passing -the actual resource handles to the shader code, and allows the user to customize how the conversion from integer handle -to resource handle is done in a way that best suites the application's design.
\ No newline at end of file diff --git a/docs/proposals/015-descriptor-handle.md b/docs/proposals/015-descriptor-handle.md new file mode 100644 index 000000000..b123a3980 --- /dev/null +++ b/docs/proposals/015-descriptor-handle.md @@ -0,0 +1,260 @@ +SP #015 - `DescriptorHandle<T>` type +============== + +## Status + +Author: Yong He + +Status: In Experiment. + +Implementation: [PR 6028](https://github.com/shader-slang/slang/pull/6028) + +Reviewed by: Theresa Foley, Jay Kwak + +## Background + +Textures, sampler states and buffers are typically passed to shader as opaque handles whose size and storage address is undefined. These handles are communicated to the GPU via "bind states" that are modified with host-side APIs. Because the handle has unknown size, it is not possible to read, copy or construct such a handle from the shader code, and it is not possible to store the handle in buffer memory. This makes both host code and shader code difficult to write and prevents more flexible encapsulation or clean object-oriented designs. + +With the recent advancement in hardware capabilities, a lot of modern graphics systems are adopting a "bindless" parameter passing idiom, where all resource handles are passed to the shader in a single global array, and all remaining references to texture, buffers or sampler states are represented as a single integer index into the array. This allows the shader code to workaround the restrictions around the opaque handle types. + +Direct3D Shader Model 6.6 introduces the "Dynamic Resources" capability, which further simplifies the way to write bindless shader code by removing the need to even declare the global array. + +We believe that graphics developers will greatly benefit from a system defined programming model for the bindless parameter passing idom that is versatile and cross-platform, which will provide a consistent interface so that different shader libraries using the bindless pattern can interop with each other without barriers. + +## Proposed Approach + +We introduce a `DescriptorHandle<T>` type that is defined as: +``` +struct DescriptorHandle<T> : IComparable + where T : IOpaqueDescriptor +{ + [require(hlsl_glsl_spirv)] + __init(uint2 value); // For HLSL, GLSL and SPIRV targets only. +} +``` +Where `IOpaqueDescriptor` is an interface that is implemented by all texture, buffer and sampler state types: + +```slang +enum DescriptorKind +{ + Unknown, + Texture, + CombinedTextureSampler, + Buffer, + Sampler, + AccelerationStructure, +} +interface IOpaqueDescriptor +{ + static const DescriptorKind kind; +} +``` + +All builtin types that implements `IOpaqueDescriptor` interface provide a convenience typealias for `DescriptorHandle<T>`. For example, `Texture2D.Handle` is an alias for `DescriptorHandle<Texture2D>`. + +### Basic Usage + +`DescriptorHandle<T>` should provide the following features: + +- `operator *` to deference the pointer and obatin the actual descriptor handle `T`. +- Implicit conversion to `T` when used in a location that expects `T`. +- When targeting HLSL, GLSL and SPIRV, `DescriptorHandle<T>` can be explicitly casted to and from a `uint2` value. +- Equality comparison. + +For example: + +```slang +uniform DescriptorHandle<Texture2D> texture; + +// `SamplerState.Handle` is equivalent to `DescriptorHandle<SamplerState>`. +uniform SamplerState.Handle sampler; + +void test() +{ + // Explicit cast from bindless handle to an uint2 value. + // (Available on HLSL, GLSL and SPIRV targets only) + let idx = (uint2)texture; + + // Constructing bindless handle from uint2 value. + // (Available on HLSL, GLSL and SPIRV targets only) + let t = DescriptorHandle<Texture2D>(idx); + + // Comparison. + ASSERT(t == texture); + + // OK, `t` is first implicitly dereferenced to producee `Texture2D`, and + // then `Texture2D::Sample` is called. + // The `sampler` argument is implicitly converted from `DescriptorHandle<SamplerState>` + // to `SamplerState`. + t.Sample(sampler, float2(0,0)); + + // Alternatively, the following syntax is also allowed, to + // make `DescriptorHandle` appear more like a pointer: + t->Sample(*sampler, float2(0, 0)); +} +``` + +A `DescriptorHandle<T>` type has target-dependent size, but it is always a concrete/physical data type and valid in all memory locations. For HLSL and SPIRV targets, it is represented by a two-component vector of 32-bit unsigned integer (`uint2`), and laid out as such. On these targets, builtin conversion functions are provided to construct +a `DescriptorHandle<T>` from a `uint2` value. + +On targets where descriptor handles are already concrete and sized types, `DescriptorHandle<T>` simply translates to `T`, and has size and alignment that matches the corresponding native type, which is queryable with Slang's reflection API. + +This means that on all targets where `DescriptorHandle<T>` is supported, you can use a `DescriptorHandle<T>` type in any context where an ordinary data type, e.g. `int` type is allowed, such as in buffer elements. + +### Obtaining Descriptor from `DescriptorHandle<T>` + +Depending on the target platform and the design choices of the user's application, the way to obtain the actual +descriptor handle from a `DescriptorHandle<T>` integer handle can vary. Slang does not dictate how this conversion is done, +and instead, this is left to the user via Slang's link-time specialization ability. + +Slang defines the following core module declarations: + +```slang +extern T getDescriptorFromHandle(DescriptorHandle<T> handle) where T : IOpaqueDescriptor +{ + // Default Implementation + return defaultGetDescriptorFromHandle(handle); +} +``` + +The `getDescriptorFromHandle` is used to convert from a bindless handle to actual opaque resource handle. +If this function is not provided by the user, the default implementation defined in the core module will be used. + +By default, the core module implementation of `getDescriptorFromHandle` should use the `ResourceDescriptorHeap` and +`SamplerDescriptorHeap` builtin object when generating HLSL code. When generating code on other targets, `getDescriptorFromHandle` +will fetch the descriptor handle from a system defined global array of the corresponding descriptor type. + +If/when SPIRV is extended to expose similar capabilities as D3D's `ResourceDescriptorHeap` feature, we should change the default implementation +to use that instead. Until we know the default implementation of `getDescriptorFromHandle` is stable, we should advise users +to provide their own implementation of `getDescriptorFromHandle` to prevent breakages. + +If the user application requires a different bindless implementation, this default behavior can be overrided by defining +`getDescriptorFromHandle` in the user code. Below is a possible user-space implementation of `getDescriptorFromHandle` +for Vulkan: + +```slang + +// All texture and buffer handles are defined in descriptor set 100. +[vk::binding(0, 100)] +__DynamicResource<__DynamicResourceKind.General> resourceHandles[]; + +// All sampler handles are defined in descriptor set 101. +[vk::binding(0, 101)] +__DynamicResource<__DynamicResourceKind.Sampler> samplerHandles[]; + +export T getDescriptorFromHandle<T>(DescriptorHandle<T> handle) where T : IOpaqueDescriptor +{ + if (T.kind == ResourceKind.Sampler) + return samplerHandles[((uint2)handle).x].asOpaqueDescriptor<T>(); + else + return resourceHandles[((uint2)handle).x].asOpaqueDescriptor<T>(); +} +``` + +The user can call `defaultGetDescriptorFromHandle` function from their implementation of `getDescriptorFromBindlessHandle` to dispatch to the default behavior. + +### Uniformity + +By default, the value of a `DescriptorHandle<T>` object is assumed to be dynamically uniform across all +execution threads. If this is not the case, the user is required to mark the `DescriptorHandle` as `nonuniform` +*immediately* before dereferencing it: +```slang +void test(DescriptorHandle<Texture2D> t) +{ + nonuniform(t)->Sample(...); +} +``` + +If the descriptor handle value is not uniform and `nonuniform` is not called, the result may be +undefined. + +### Combined Texture Samplers + +On platforms without native support for combined texture samplers, we will use both components of the +underlying `uint2` value: the `x` component stores the bindless handle for the texture, and the `y` component stores the bindless handle for the sampler. + +For example, given: + +```slang +uniform DescriptorHandle<Sampler2D> s; +void main() +{ + float2 uv = ...; + s.SampleLevel(uv, 0.0); +} +``` + +The Slang compiler should emit HLSL as follows: + +```hlsl +uniform uint2 s; +void main() +{ + float2 uv = ...; + Texture2D(ResourceDescriptorHeap[s.x]).SampleLevel( + SamplerState(SamplerDescriptorHeap[s.y]), + uv, + 0.0); +} +``` + +## Alternatives Considered + +We initially considered to support a more general `DescriptorHandle<T>` where `T` can be any composite type, for example, allowing the following: + +```slang +struct Foo +{ + Texture2D t; + SamplerState s; + float ordinaryData; +} + +uniform DescriptorHandle<Foo> foo; +``` + +which is equivalent to: + +```slang +struct Bindless_Foo +{ + DescriptorHandle<Texture2D> t; + DescriptorHandle<SamplerState> s; + float s; +} +uniform Bindless_Foo foo; +``` + +While relaxing `T` this way adds an extra layer of convenience, it introduces complicated +semantic rules to the type system, and there is increased chance of exposing tricky corner +cases that are hard to get right. + +An argument for allowing `T` to be general composite types is that it enables sharing the same +code for both bindless systems and bindful systems. But this argument can also be countered by +allowing the compiler to treat `DescriptorHandle<T>` as `T` in a special mode if this feature is found to be useful. + +For now we think that restricting `T` to be an `IOpaqueDescriptor` type will result in a much simpler implementation, and is likely sufficient for current needs. Given that the trend of modern GPU architecture is moving towards bindless idioms and the whole idea of opaque handles may disappear in the future, we should be cautious at inventing too many heavy weight mechanisms around opaque handles. Nevertheless, this proposal still allows us to relax this requirement in the future if it becomes clear that such feature is valuable to our users. + +In the initial version of this propsoal, `DescriptorHandle<T>` is named `Bindless<T>`. During discussion, we determined that this naming can be confusing to users who are coming from general GPU compute community and haven't heard of the term "bindless resources". We believe `DescriptorHandle<T>` is a better name because it reflects the essense of the type more accurately, and is consistent with D3D12 terminology in that `DescriptorHandle<T>` is the shader side representation of the `D3D12_GPU_DESCRIPTOR_HANDLE` structure. + +The initial version of the proposal defines `DescriptorHandle<T>` to be backed by an 8-byte integer value independent of the target. This is changed +so that Slang only guarantees `DescriptorHandle<T>` to be a phyiscal data type, and will have target-dependent size. Slang guarantees that `DescriptorHandle<T>` +will be lowered to a `uint2` value when targeting HLSL, GLSL and SPIRV, but not on other targets. This is because on targets where `T` is already a +phyisical type, their size can vary and may not fit in an 8-byte structure. For example, `StructuredBuffer<T>` maps to a `{T*, size_t}` structure when +targeting CUDA, which takes 16 bytes. In the meanwhile, forcing `DescriptorHandle<T>` to be `uint64_t` makes the feature unusable for lower-tier hardware +where 64-bit integers are not supported. Representing the handle with `uint2` allows the feature to be used without requiring this additional +capability. + +The initial proposal also reserves a value for invalid/null handle. This is removed because we cannot find +a safe value that won't be used across all targets we support. In particular, this is not possible on CUDA +and Metal because it is not possible to interpret these handles as plain integers. + +## Conclusion + +This proposal introduces a standard way to achieve bindless parameter passing idom on current graphics platforms. +Standardizing the way of writing bindless parameter binding code is essential for creating reusable shader code +libraries. The convenience language features around `DescriptorHandle<T>` type should also make shader code easier to write +and to maintain. Finally, by using Slang's link time specialization feature, +this proposal allows Slang to not get into the way of dicatating one specific way of passing +the actual descriptor handles to the shader code, and allows the user to customize how the conversion from integer handle +to descriptor handle is done in a way that best suites the application's design.
\ No newline at end of file diff --git a/docs/user-guide/03-convenience-features.md b/docs/user-guide/03-convenience-features.md index aeec8eb28..e6b337eed 100644 --- a/docs/user-guide/03-convenience-features.md +++ b/docs/user-guide/03-convenience-features.md @@ -531,12 +531,126 @@ Pointer types can also be specified using the generic syntax: `Ptr<MyType>` is e - Slang can produce pointers using the & operator from data in global memory. +- Slang doesn't support forming pointers to opaque handle types, e.g. `Texture2D`. For handle pointers, use `DescriptorHandle<T>` instead. + - Slang doesn't support coherent load/stores. - Slang doesn't support custom alignment specification. - Slang currently does not support pointers to immutable values, i.e. `const T*`. +## `DescriptorHandle` for Bindless Descriptor Access + +Slang supports the `DescriptorHandle<T>` type that represents a bindless handle to a resource. This feature provides a portable way of implementing +the bindless resource idiom. When targeting HLSL, GLSL and SPIRV where descriptor types (e.g. textures, samplers and buffers) are opaque handles, +`DescriptorHandle<T>` will translate into a `uint2` so it can be defined in any memory location. The underlying `uint2` value is treated as an index +to access the global descriptor heap or resource array in order to obtain the actual resource handle. On targets with where resource handles +are not opaque handles, `DescriptorHandle<T>` maps to `T` and will have the same size and alignment defined by the target. + +`DescriptorHandle<T>` is declared as: +```slang +struct DescriptorHandle<T> where T:IOpaqueDescriptor {} +``` +where `IOpaqueDescriptor` is an interface implemented by all resource types, including textures, +`ConstantBuffer`, `RaytracingAccelerationStructure`, `SamplerState`, `SamplerComparisonState` and all types of `StructuredBuffer`. + +You may also write `Texture2D.Handle` as a short-hand of `DescriptorHandle<Texture2D>`. + +`DescriptorHandle<T>` supports `operator *`, `operator ->`, and can implicitly convert to `T`, for example: + +```slang +uniform StructuredBuffer<DescriptorHandle<Texture2D>> textures; +uniform int textureIndex; + +// define a descriptor handle using builtin convenience typealias: +uniform StructuredBuffer<float4>.Handle output; + +[numthreads(1,1,1)] +void main() +{ + output[0] = textures[textureIndex].Load(int3(0)); + + // Alternatively, this syntax is also valid: + (*output)[0] = textures[textureIndex]->Load(int3(0)); +} +``` + +By default, when targeting HLSL, `DescriptorHandle<T>` translates to uses of `ResourceDescriptorHeap[index]` and `SamplerDescriptorHeap[index]`. +In particular, when combined with combined texture sampler types (e.g. `Sampler2D`), Slang will fetch the texture using the first +component of the handle, and the sampler state from the second component of the handle. For example: + +``` +uniform DescriptorHandle<Sampler2D> s; +void test() +{ + s.Sample(uv); +} +``` + +translates to: + +```hlsl +uniform uint2 s; +void test() +{ + Texture2D(ResourceDescriptorHeap[s.x]).Sample( + SamplerState(SamplerDescriptorHeap[s.y]), + uv + ); +} +``` + +When targeting SPIRV, Slang will introduce a global array of descriptors and fetch from the global array. +The descriptor set ID of the global descriptor array can be configured with the `-bindless-space-index` +(or `CompilerOptionName::BindlessSpaceIndex` when using the API) option. + +> #### Note +> The default implementation for SPIRV may change in the future if SPIRV is extended to provide what is +> equivalent to D3D's `ResourceDescriptorHeap` construct. + +Users can override the default behavior of convering from bindless handle to resource handle, by providing a +`getDescriptorFromHandle` in user code. For example: + +```slang +// All texture and buffer handles are defined in descriptor set 100. +[vk::binding(0, 100)] +__DynamicResource<__DynamicResourceKind.General> resourceHandles[]; + +// All sampler handles are defined in descriptor set 101. +[vk::binding(0, 101)] +__DynamicResource<__DynamicResourceKind.Sampler> samplerHandles[]; + +export T getDescriptorFromHandle<T>(DescriptorHandle<T> handle) where T : IOpaqueDescriptor +{ + __target_switch + { + case spirv: + if (T.kind == ResourceKind.Sampler) + return samplerHandles[((uint2)handle).x].asOpaqueDescriptor<T>(); + else + return resourceHandles[((uint2)handle).x].asOpaqueDescriptor<T>(); + default: + return defaultGetDescriptorFromHandle(handle); + } +} +``` + +The user can call `defaultGetDescriptorFromHandle` function from their implementation of +`getDescriptorFromHandle` to dispatch to the default behavior. + +By default, the value of a `DescriptorHandle<T>` object is assumed to be dynamically uniform across all +execution threads. If this is not the case, the user is required to mark the `DescriptorHandle` as `nonuniform` +*immediately* before dereferencing it: +```slang +void test(DescriptorHandle<Texture2D> t) +{ + nonuniform(t)->Sample(...); +} +``` + +If the resource pointer value is not uniform and `nonuniform` is not called, the result may be +undefined. + Extensions -------------------- Slang allows defining additional methods for a type outside its initial definition. For example, suppose we already have a type defined: diff --git a/docs/user-guide/toc.html b/docs/user-guide/toc.html index b5a6cccbb..9f9085cdd 100644 --- a/docs/user-guide/toc.html +++ b/docs/user-guide/toc.html @@ -45,6 +45,7 @@ <li data-link="convenience-features#if_let-syntax"><span>`if_let` syntax</span></li> <li data-link="convenience-features#reinterprett-operation"><span>`reinterpret<T>` operation</span></li> <li data-link="convenience-features#pointers-limited"><span>Pointers (limited)</span></li> +<li data-link="convenience-features#descriptorhandle-for-bindless-descriptor-access"><span>`DescriptorHandle` for Bindless Descriptor Access</span></li> <li data-link="convenience-features#extensions"><span>Extensions</span></li> <li data-link="convenience-features#multi-level-break"><span>Multi-level break</span></li> <li data-link="convenience-features#force-inlining"><span>Force inlining</span></li> |
