yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
01510f2c9
master
1#define SLANG_PRELUDE_EXPORT 2 3#ifdef __CUDACC_RTC__ 4#define SLANG_CUDA_RTC 1 5#else 6#define SLANG_CUDA_RTC 0 7#endif 8 9#if SLANG_CUDA_RTC 10 11#else 12 13#include <cstdint> 14#include <stdio.h> 15 16#endif 17 18// Define SLANG_CUDA_ENABLE_HALF to use the cuda_fp16 include to add half support. 19// For this to work NVRTC needs to have the path to the CUDA SDK. 20// 21// As it stands the includes paths defined for Slang are passed down to NVRTC. Similarly defines 22// defined for the Slang compile are passed down. 23 24#ifdef SLANG_CUDA_ENABLE_HALF 25// We don't want half2 operators, because it will implement comparison operators that return a 26// bool(!). We want to generate those functions. Doing so means that we will have to define all 27// the other half2 operators. 28#define __CUDA_NO_HALF2_OPERATORS__ 29#include <cuda_fp16.h> 30#endif 31 32#ifdef SLANG_CUDA_ENABLE_OPTIX 33#include <optix.h> 34#endif 35 36// Define slang offsetof implementation 37#ifndef SLANG_OFFSET_OF 38#define SLANG_OFFSET_OF (type ,member ) (size_t)((char*)&(((type*)0)->member) - (char*)0) 39#endif 40 41// Must be large enough to cause overflow and therefore infinity 42#ifndef SLANG_INFINITY 43#define SLANG_INFINITY ((float)(1e+300 * 1e+300)) 44#endif 45 46// For now we'll disable any asserts in this prelude 47#define SLANG_PRELUDE_ASSERT (x ) 48 49#ifndef SLANG_CUDA_WARP_SIZE 50#define SLANG_CUDA_WARP_SIZE 32 51#endif 52 53#define SLANG_CUDA_WARP_MASK \ 54 (SLANG_CUDA_WARP_SIZE - 1) // Used for masking threadIdx.x to the warp lane index 55#define SLANG_CUDA_WARP_BITMASK (~int(0)) 56 57// 58#define SLANG_FORCE_INLINE inline 59 60#define SLANG_CUDA_CALL __device__ 61 62#define SLANG_FORCE_INLINE inline 63#define SLANG_INLINE inline 64 65 66// Since we are using unsigned arithmatic care is need in this comparison. 67// It is *assumed* that sizeInBytes >= elemSize. Which means (sizeInBytes >= elemSize) >= 0 68// Which means only a single test is needed 69 70// Asserts for bounds checking. 71// It is assumed index/count are unsigned types. 72#define SLANG_BOUND_ASSERT (index ,count ) SLANG_PRELUDE_ASSERT(index < count); 73#define SLANG_BOUND_ASSERT_BYTE_ADDRESS (index ,elemSize ,sizeInBytes ) \ 74 SLANG_PRELUDE_ASSERT(index <= (sizeInBytes - elemSize) && (index & 3) == 0); 75 76// Macros to zero index if an access is out of range 77#define SLANG_BOUND_ZERO_INDEX (index ,count ) index = (index < count) ? index : 0; 78#define SLANG_BOUND_ZERO_INDEX_BYTE_ADDRESS (index ,elemSize ,sizeInBytes ) \ 79 index = (index <= (sizeInBytes - elemSize)) ? index : 0; 80 81// The 'FIX' macro define how the index is fixed. The default is to do nothing. If 82// SLANG_ENABLE_BOUND_ZERO_INDEX the fix macro will zero the index, if out of range 83#ifdef SLANG_ENABLE_BOUND_ZERO_INDEX 84#define SLANG_BOUND_FIX (index ,count ) SLANG_BOUND_ZERO_INDEX(index, count) 85#define SLANG_BOUND_FIX_BYTE_ADDRESS (index ,elemSize ,sizeInBytes ) \ 86 SLANG_BOUND_ZERO_INDEX_BYTE_ADDRESS(index, elemSize, sizeInBytes) 87#define SLANG_BOUND_FIX_FIXED_ARRAY (index ,count ) \ 88 SLANG_BOUND_ZERO_INDEX(index, count) SLANG_BOUND_ZERO_INDEX(index, count) 89#else 90#define SLANG_BOUND_FIX (index ,count ) 91#define SLANG_BOUND_FIX_BYTE_ADDRESS (index ,elemSize ,sizeInBytes ) 92#define SLANG_BOUND_FIX_FIXED_ARRAY (index ,count ) 93#endif 94 95#ifndef SLANG_BOUND_CHECK 96#define SLANG_BOUND_CHECK (index ,count ) \ 97 SLANG_BOUND_ASSERT(index, count) SLANG_BOUND_FIX(index, count) 98#endif 99 100#ifndef SLANG_BOUND_CHECK_BYTE_ADDRESS 101#define SLANG_BOUND_CHECK_BYTE_ADDRESS (index ,elemSize ,sizeInBytes ) \ 102 SLANG_BOUND_ASSERT_BYTE_ADDRESS(index, elemSize, sizeInBytes) \ 103 SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) 104#endif 105 106#ifndef SLANG_BOUND_CHECK_FIXED_ARRAY 107#define SLANG_BOUND_CHECK_FIXED_ARRAY (index ,count ) \ 108 SLANG_BOUND_ASSERT(index, count) SLANG_BOUND_FIX_FIXED_ARRAY(index, count) 109#endif 110 111// This macro handles how out-of-range surface coordinates are handled; 112// I can equal 113// cudaBoundaryModeClamp, in which case out-of-range coordinates are clamped to the valid range 114// cudaBoundaryModeZero, in which case out-of-range reads return zero and out-of-range writes are 115// ignored cudaBoundaryModeTrap, in which case out-of-range accesses cause the kernel execution to 116// fail. 117 118#ifndef SLANG_CUDA_BOUNDARY_MODE 119#define SLANG_CUDA_BOUNDARY_MODE cudaBoundaryModeZero 120 121// Can be one of SLANG_CUDA_PTX_BOUNDARY_MODE. Only applies *PTX* emitted CUDA operations 122// which currently is just RWTextureRW format writes 123// 124// .trap causes an execution trap on out-of-bounds addresses 125// .clamp stores data at the nearest surface location (sized appropriately) 126// .zero drops stores to out-of-bounds addresses 127 128#define SLANG_PTX_BOUNDARY_MODE "zero" 129#endif 130 131struct TypeInfo 132{ 133size_t typeSize ; 134}; 135 136template < typename T ,size_t SIZE > 137struct FixedArray 138{ 139SLANG_CUDA_CALL const T & operator [](size_t index )const 140 { 141SLANG_BOUND_CHECK_FIXED_ARRAY (index ,SIZE ); 142return m_data [index ]; 143 } 144SLANG_CUDA_CALL T & operator [](size_t index ) 145 { 146SLANG_BOUND_CHECK_FIXED_ARRAY (index ,SIZE ); 147return m_data [index ]; 148 } 149 150T m_data [SIZE ]; 151}; 152 153// An array that has no specified size, becomes a 'Array'. This stores the size so it can 154// potentially do bounds checking. 155template < typename T > 156struct Array 157{ 158SLANG_CUDA_CALL const T & operator [](size_t index )const 159 { 160SLANG_BOUND_CHECK (index ,count ); 161return data [index ]; 162 } 163SLANG_CUDA_CALL T & operator [](size_t index ) 164 { 165SLANG_BOUND_CHECK (index ,count ); 166return data [index ]; 167 } 168 169T * data ; 170size_t count ; 171}; 172 173// Typically defined in cuda.h, but we can't ship/rely on that, so just define here 174typedef unsigned long long CUtexObject ; 175typedef unsigned long long CUsurfObject ; 176 177// On CUDA sampler state is actually bound up with the texture object. We have a SamplerState type, 178// backed as a pointer, to simplify code generation, with the downside that such a binding will take 179// up uniform space, even though it will have no effect. 180// TODO(JS): Consider ways to strip use of variables of this type so have no binding, 181struct SamplerStateUnused ; 182typedef SamplerStateUnused * SamplerState ; 183 184 185// TODO(JS): Not clear yet if this can be handled on CUDA, by just ignoring. 186// For now, just map to the index type. 187typedef size_t NonUniformResourceIndex ; 188 189// Code generator will generate the specific type 190template < typename T ,int ROWS ,int COLS > 191struct Matrix ; 192 193// Boolean vector types should follow CUDA's builtin vector alignment rules 194// Align boolX the same as charX according to CUDA spec: 195// char1/uchar1: 1-byte aligned, char2/uchar2: 2-byte aligned 196// char3/uchar3: 1-byte aligned, char4/uchar4: 4-byte aligned 197struct __align__ (1 )bool1 198{ 199bool x ; 200 201SLANG_FORCE_INLINE SLANG_CUDA_CALL bool & operator [](int idx ) 202 { 203return (& x )[idx ]; 204 } 205SLANG_FORCE_INLINE SLANG_CUDA_CALL const bool & operator [](int idx )const 206 { 207return (& x )[idx ]; 208 } 209}; 210 211struct __align__ (2 )bool2 212{ 213bool x ,y ; 214 215SLANG_FORCE_INLINE SLANG_CUDA_CALL bool & operator [](int idx ) 216 { 217return (& x )[idx ]; 218 } 219SLANG_FORCE_INLINE SLANG_CUDA_CALL const bool & operator [](int idx )const 220 { 221return (& x )[idx ]; 222 } 223}; 224 225struct __align__ (1 )bool3 226{ 227bool x ,y ,z ; 228 229SLANG_FORCE_INLINE SLANG_CUDA_CALL bool & operator [](int idx ) 230 { 231return (& x )[idx ]; 232 } 233SLANG_FORCE_INLINE SLANG_CUDA_CALL const bool & operator [](int idx )const 234 { 235return (& x )[idx ]; 236 } 237}; 238 239struct __align__ (4 )bool4 240{ 241bool x ,y ,z ,w ; 242 243SLANG_FORCE_INLINE SLANG_CUDA_CALL bool & operator [](int idx ) 244 { 245return (& x )[idx ]; 246 } 247SLANG_FORCE_INLINE SLANG_CUDA_CALL const bool & operator [](int idx )const 248 { 249return (& x )[idx ]; 250 } 251}; 252 253SLANG_FORCE_INLINE SLANG_CUDA_CALL bool __ldg (const bool * ptr ) 254{ 255return (bool )(__ldg ((const char * )ptr )); 256} 257 258SLANG_FORCE_INLINE SLANG_CUDA_CALL bool2 __ldg (const bool2 * ptr ) 259{ 260 autoval = __ldg (( const char2 * )ptr); 261return {val. x != 0 , val. y != 0 }; 262} 263 264SLANG_FORCE_INLINE SLANG_CUDA_CALL bool4 __ldg ( const bool4 * ptr) 265{ 266auto val = __ldg (( const char4 * )ptr); 267return {val. x != 0 , val. y != 0 , val. z != 0 , val. w != 0 }; 268} 269 270#if SLANG_CUDA_RTC 271 272typedef signed char int8_t ; 273typedef short int16_t ; 274typedef int int32_t ; 275typedef long long int64_t ; 276typedef ptrdiff_t intptr_t ; 277 278typedef unsigned char uint8_t ; 279typedef unsigned short uint16_t ; 280typedef unsigned int uint32_t ; 281typedef unsigned long long uint64_t ; 282typedef size_t uintptr_t ; 283 284#endif 285 286typedef long long longlong ; 287typedef unsigned long long ulonglong ; 288 289typedef unsigned char uchar ; 290typedef unsigned short ushort ; 291typedef unsigned int uint ; 292 293union Union32 294{ 295uint32_t u ; 296int32_t i ; 297float f ; 298}; 299 300union Union64 301{ 302uint64_t u ; 303int64_t i ; 304double d ; 305}; 306 307template < typename T > 308SLANG_FORCE_INLINE SLANG_CUDA_CALL float make_float ( T val) 309{ 310return ( float )val; 311} 312 313SLANG_FORCE_INLINE SLANG_CUDA_CALL float _slang_fmod ( float x, float y) 314{ 315return :: fmodf (x, y); 316} 317SLANG_FORCE_INLINE SLANG_CUDA_CALL double _slang_fmod ( double x, double y) 318{ 319return :: fmod (x, y); 320} 321 322#if SLANG_CUDA_ENABLE_HALF 323 324// Add the other vector half types 325struct __half1 326{ 327__half x ; 328}; 329struct __align__ ( 4 ) __half3 330{ 331__half x, y, z; 332}; 333struct __align__ ( 4 ) __half4 334{ 335__half x, y, z, w; 336}; 337#endif 338 339#define SLANG_VECTOR_GET_ELEMENT ( T ) \ 340SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##1 x, int index) \ 341{ \ 342return ((T*)(&x))[index]; \ 343} \ 344SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##2 x, int index) \ 345{ \ 346return ((T*)(&x))[index]; \ 347} \ 348SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##3 x, int index) \ 349{ \ 350return ((T*)(&x))[index]; \ 351} \ 352SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##4 x, int index) \ 353{ \ 354return ((T*)(&x))[index]; \ 355} 356SLANG_VECTOR_GET_ELEMENT ( int ) 357SLANG_VECTOR_GET_ELEMENT ( bool ) 358SLANG_VECTOR_GET_ELEMENT (uint) 359SLANG_VECTOR_GET_ELEMENT (short) 360SLANG_VECTOR_GET_ELEMENT (ushort) 361SLANG_VECTOR_GET_ELEMENT (char) 362SLANG_VECTOR_GET_ELEMENT (uchar) 363SLANG_VECTOR_GET_ELEMENT (longlong) 364SLANG_VECTOR_GET_ELEMENT (ulonglong) 365SLANG_VECTOR_GET_ELEMENT (float) 366SLANG_VECTOR_GET_ELEMENT (double) 367 368#define SLANG_VECTOR_GET_ELEMENT_PTR ( T ) \ 369SLANG_FORCE_INLINE SLANG_CUDA_CALL T * _slang_vector_get_element_ptr(const T # #1 * x, int index) \ 370{ \ 371return ((T*)(x)) + index; \ 372} \ 373SLANG_FORCE_INLINE SLANG_CUDA_CALL T* _slang_vector_get_element_ptr(const T##2 * x, int index) \ 374{ \ 375return ((T*)(x)) + index; \ 376} \ 377SLANG_FORCE_INLINE SLANG_CUDA_CALL T* _slang_vector_get_element_ptr(const T##3 * x, int index) \ 378{ \ 379return ((T*)(x)) + index; \ 380} \ 381SLANG_FORCE_INLINE SLANG_CUDA_CALL T* _slang_vector_get_element_ptr(const T##4 * x, int index) \ 382{ \ 383return ((T*)(x)) + index; \ 384} 385SLANG_VECTOR_GET_ELEMENT_PTR ( int ) 386SLANG_VECTOR_GET_ELEMENT_PTR ( bool ) 387SLANG_VECTOR_GET_ELEMENT_PTR (uint) 388SLANG_VECTOR_GET_ELEMENT_PTR (short) 389SLANG_VECTOR_GET_ELEMENT_PTR (ushort) 390SLANG_VECTOR_GET_ELEMENT_PTR (char) 391SLANG_VECTOR_GET_ELEMENT_PTR (uchar) 392SLANG_VECTOR_GET_ELEMENT_PTR (longlong) 393SLANG_VECTOR_GET_ELEMENT_PTR (ulonglong) 394SLANG_VECTOR_GET_ELEMENT_PTR (float) 395SLANG_VECTOR_GET_ELEMENT_PTR (double) 396 397#if SLANG_CUDA_ENABLE_HALF 398SLANG_VECTOR_GET_ELEMENT (__half) 399SLANG_VECTOR_GET_ELEMENT_PTR (__half) 400#endif 401 402#define SLANG_CUDA_VECTOR_BINARY_OP ( T , n, op) \ 403SLANG_FORCE_INLINE SLANG_CUDA_CALL T # #n operator op(T##n thisVal, T##n other) \ 404{ \ 405T##n result; \ 406for (int i = 0; i < n; i++) \ 407*_slang_vector_get_element_ptr(&result, i) = \ 408_slang_vector_get_element(thisVal, i) op _slang_vector_get_element(other, i); \ 409return result; \ 410} 411#define SLANG_CUDA_VECTOR_BINARY_COMPARE_OP ( T , n, op) \ 412SLANG_FORCE_INLINE SLANG_CUDA_CALL bool##n operator op(T##n thisVal, T##n other) \ 413{ \ 414bool##n result; \ 415for (int i = 0; i < n; i++) \ 416*_slang_vector_get_element_ptr(&result, i) = \ 417(_slang_vector_get_element(thisVal, i) op _slang_vector_get_element(other, i)); \ 418return result; \ 419} 420#define SLANG_CUDA_VECTOR_UNARY_OP ( T , n, op) \ 421SLANG_FORCE_INLINE SLANG_CUDA_CALL T##n operator op(T##n thisVal) \ 422{ \ 423T##n result; \ 424for (int i = 0; i < n; i++) \ 425*_slang_vector_get_element_ptr(&result, i) = op _slang_vector_get_element(thisVal, i); \ 426return result; \ 427} 428 429#define SLANG_CUDA_VECTOR_INT_OP ( T , n) \ 430SLANG_CUDA_VECTOR_BINARY_OP(T, n, +) \ 431SLANG_CUDA_VECTOR_BINARY_OP(T, n, -) \ 432SLANG_CUDA_VECTOR_BINARY_OP(T, n, *) \ 433SLANG_CUDA_VECTOR_BINARY_OP(T, n, /) \ 434SLANG_CUDA_VECTOR_BINARY_OP(T, n, %) \ 435SLANG_CUDA_VECTOR_BINARY_OP(T, n, ^) \ 436SLANG_CUDA_VECTOR_BINARY_OP(T, n, &) \ 437SLANG_CUDA_VECTOR_BINARY_OP(T, n, |) \ 438SLANG_CUDA_VECTOR_BINARY_OP(T, n, &&) \ 439SLANG_CUDA_VECTOR_BINARY_OP(T, n, ||) \ 440SLANG_CUDA_VECTOR_BINARY_OP(T, n, >>) \ 441SLANG_CUDA_VECTOR_BINARY_OP(T, n, <<) \ 442SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, >) \ 443SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, <) \ 444SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, >=) \ 445SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, <=) \ 446SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, ==) \ 447SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, !=) \ 448SLANG_CUDA_VECTOR_UNARY_OP(T, n, !) \ 449SLANG_CUDA_VECTOR_UNARY_OP(T, n, -) \ 450SLANG_CUDA_VECTOR_UNARY_OP(T, n, ~) 451 452#define SLANG_CUDA_VECTOR_INT_OPS ( T ) \ 453SLANG_CUDA_VECTOR_INT_OP(T, 2) \ 454SLANG_CUDA_VECTOR_INT_OP(T, 3) \ 455SLANG_CUDA_VECTOR_INT_OP(T, 4) 456 457SLANG_CUDA_VECTOR_INT_OPS ( int ) 458SLANG_CUDA_VECTOR_INT_OPS ( bool ) 459SLANG_CUDA_VECTOR_INT_OPS (uint) 460SLANG_CUDA_VECTOR_INT_OPS (ushort) 461SLANG_CUDA_VECTOR_INT_OPS (short) 462SLANG_CUDA_VECTOR_INT_OPS (char) 463SLANG_CUDA_VECTOR_INT_OPS (uchar) 464SLANG_CUDA_VECTOR_INT_OPS (longlong) 465SLANG_CUDA_VECTOR_INT_OPS (ulonglong) 466 467#define SLANG_CUDA_VECTOR_FLOAT_OP ( T , n) \ 468SLANG_CUDA_VECTOR_BINARY_OP ( T , n, + ) \ 469SLANG_CUDA_VECTOR_BINARY_OP ( T , n, - ) \ 470SLANG_CUDA_VECTOR_BINARY_OP ( T , n, * ) \ 471SLANG_CUDA_VECTOR_BINARY_OP ( T , n, /) \ 472SLANG_CUDA_VECTOR_BINARY_OP ( T , n, && ) \ 473SLANG_CUDA_VECTOR_BINARY_OP ( T , n, || ) \ 474SLANG_CUDA_VECTOR_BINARY_COMPARE_OP ( T , n, > ) \ 475SLANG_CUDA_VECTOR_BINARY_COMPARE_OP ( T , n, < ) \ 476SLANG_CUDA_VECTOR_BINARY_COMPARE_OP ( T , n, >=) \ 477SLANG_CUDA_VECTOR_BINARY_COMPARE_OP ( T , n, <=) \ 478SLANG_CUDA_VECTOR_BINARY_COMPARE_OP ( T , n, == ) \ 479SLANG_CUDA_VECTOR_BINARY_COMPARE_OP ( T , n, ! = ) \ 480SLANG_CUDA_VECTOR_UNARY_OP ( T , n, - ) 481#define SLANG_CUDA_VECTOR_FLOAT_OPS ( T ) \ 482SLANG_CUDA_VECTOR_FLOAT_OP ( T , 2 ) \ 483SLANG_CUDA_VECTOR_FLOAT_OP ( T , 3 ) \ 484SLANG_CUDA_VECTOR_FLOAT_OP ( T , 4 ) 485 486SLANG_CUDA_VECTOR_FLOAT_OPS (float) 487SLANG_CUDA_VECTOR_FLOAT_OPS (double) 488#if SLANG_CUDA_ENABLE_HALF 489SLANG_CUDA_VECTOR_FLOAT_OPS (__half) 490#endif 491#define SLANG_CUDA_FLOAT_VECTOR_MOD_IMPL ( T , n) \ 492SLANG_FORCE_INLINE SLANG_CUDA_CALL T # #n operator%(const T # #n & left, const T # #n & right) \ 493{ \ 494T # #n result; \ 495for ( int i = 0 ; i < n; i ++ ) \ 496* _slang_vector_get_element_ptr( & result, i) = _slang_fmod( \ 497_slang_vector_get_element(left, i), \ 498_slang_vector_get_element (right, i)); \ 499return result; \ 500} 501#define SLANG_CUDA_FLOAT_VECTOR_MOD ( T ) \ 502SLANG_CUDA_FLOAT_VECTOR_MOD_IMPL ( T , 2 ) \ 503SLANG_CUDA_FLOAT_VECTOR_MOD_IMPL ( T , 3 ) \ 504SLANG_CUDA_FLOAT_VECTOR_MOD_IMPL ( T , 4 ) 505 506SLANG_CUDA_FLOAT_VECTOR_MOD ( float ) 507SLANG_CUDA_FLOAT_VECTOR_MOD ( double ) 508 509#if SLANG_CUDA_RTC || SLANG_CUDA_ENABLE_HALF 510#define SLANG_MAKE_VECTOR ( T ) \ 511SLANG_FORCE_INLINE SLANG_CUDA_CALL T # #2 make_##T##2(T x, T y) \ 512{ \ 513return T##2 {x, y}; \ 514} \ 515SLANG_FORCE_INLINE SLANG_CUDA_CALL T##3 make_##T##3(T x, T y, T z) \ 516{ \ 517return T##3 {x, y, z}; \ 518} \ 519SLANG_FORCE_INLINE SLANG_CUDA_CALL T##4 make_##T##4(T x, T y, T z, T w) \ 520{ \ 521return T##4 {x, y, z, w}; \ 522} 523#endif 524 525#if SLANG_CUDA_RTC 526SLANG_MAKE_VECTOR ( int ) 527SLANG_MAKE_VECTOR ( uint ) 528SLANG_MAKE_VECTOR (short) 529SLANG_MAKE_VECTOR (ushort) 530SLANG_MAKE_VECTOR (char) 531SLANG_MAKE_VECTOR (uchar) 532SLANG_MAKE_VECTOR (float) 533SLANG_MAKE_VECTOR (double) 534SLANG_MAKE_VECTOR (longlong) 535SLANG_MAKE_VECTOR (ulonglong) 536#endif 537 538#if SLANG_CUDA_ENABLE_HALF 539SLANG_MAKE_VECTOR (__half) 540#endif 541 542SLANG_FORCE_INLINE SLANG_CUDA_CALL bool1 make_bool1 (bool x) 543{ 544return bool1{x}; 545} 546SLANG_FORCE_INLINE SLANG_CUDA_CALL bool2 make_bool2 ( bool x, bool y) 547{ 548return bool2{x, y}; 549} 550SLANG_FORCE_INLINE SLANG_CUDA_CALL bool3 make_bool3 ( bool x, bool y, bool z) 551{ 552return bool3{x, y, z}; 553} 554SLANG_FORCE_INLINE SLANG_CUDA_CALL bool4 make_bool4 ( bool x, bool y, bool z, bool w) 555{ 556return bool4{x, y, z, w}; 557} 558SLANG_FORCE_INLINE SLANG_CUDA_CALL bool2 make_bool2 ( bool x) 559{ 560return bool2{x, x}; 561} 562SLANG_FORCE_INLINE SLANG_CUDA_CALL bool3 make_bool3 ( bool x) 563{ 564return bool3{x, x, x}; 565} 566SLANG_FORCE_INLINE SLANG_CUDA_CALL bool4 make_bool4 ( bool x) 567{ 568return bool4{x, x, x, x}; 569} 570 571#if SLANG_CUDA_RTC 572#define SLANG_MAKE_VECTOR_FROM_SCALAR ( T ) \ 573SLANG_FORCE_INLINE SLANG_CUDA_CALL T##1 make_##T##1(T x) \ 574{ \ 575return T##1 {x}; \ 576} \ 577SLANG_FORCE_INLINE SLANG_CUDA_CALL T##2 make_##T##2(T x) \ 578{ \ 579return make_##T##2(x, x); \ 580} \ 581SLANG_FORCE_INLINE SLANG_CUDA_CALL T##3 make_##T##3(T x) \ 582{ \ 583return make_##T##3(x, x, x); \ 584} \ 585SLANG_FORCE_INLINE SLANG_CUDA_CALL T##4 make_##T##4(T x) \ 586{ \ 587return make_##T##4(x, x, x, x); \ 588} 589#else 590#define SLANG_MAKE_VECTOR_FROM_SCALAR ( T ) \ 591SLANG_FORCE_INLINE SLANG_CUDA_CALL T##2 make_##T##2(T x) \ 592{ \ 593return make_##T##2(x, x); \ 594} \ 595SLANG_FORCE_INLINE SLANG_CUDA_CALL T##3 make_##T##3(T x) \ 596{ \ 597return make_##T##3(x, x, x); \ 598} \ 599SLANG_FORCE_INLINE SLANG_CUDA_CALL T##4 make_##T##4(T x) \ 600{ \ 601return make_##T##4(x, x, x, x); \ 602} 603#endif 604SLANG_MAKE_VECTOR_FROM_SCALAR ( int ) 605SLANG_MAKE_VECTOR_FROM_SCALAR ( uint ) 606SLANG_MAKE_VECTOR_FROM_SCALAR (short) 607SLANG_MAKE_VECTOR_FROM_SCALAR (ushort) 608SLANG_MAKE_VECTOR_FROM_SCALAR (char) 609SLANG_MAKE_VECTOR_FROM_SCALAR (uchar) 610SLANG_MAKE_VECTOR_FROM_SCALAR (longlong) 611SLANG_MAKE_VECTOR_FROM_SCALAR (ulonglong) 612SLANG_MAKE_VECTOR_FROM_SCALAR (float) 613SLANG_MAKE_VECTOR_FROM_SCALAR (double) 614#if SLANG_CUDA_ENABLE_HALF 615SLANG_MAKE_VECTOR_FROM_SCALAR (__half) 616#if ! SLANG_CUDA_RTC 617SLANG_FORCE_INLINE SLANG_CUDA_CALL __half1 make___half1 (__half x) 618{ 619return __half1{ x }; 620} 621#endif 622#endif 623 624#define SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (Fn, T , N ) \ 625SLANG_FORCE_INLINE SLANG_CUDA_CALL T##N Fn(T##N* address, T##N val) \ 626{ \ 627T##N result; \ 628for (int i = 0; i < N; i++) \ 629*_slang_vector_get_element_ptr(&result, i) = \ 630Fn(_slang_vector_get_element_ptr(address, i), _slang_vector_get_element(val, i)); \ 631return result; \ 632} 633 634#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 900 635SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, float, 2 ) 636SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, float, 4 ) 637#endif 638SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, float, 3 ) 639SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, int, 2 ) 640SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, int, 3 ) 641SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, int, 4 ) 642SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, uint, 2 ) 643SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, uint, 3 ) 644SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, uint, 4 ) 645SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, ulonglong, 2 ) 646SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, ulonglong, 3 ) 647SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL (atomicAdd, ulonglong, 4 ) 648 649template < typename T , int n > 650struct GetVectorTypeImpl 651{ 652}; 653 654#define GET_VECTOR_TYPE_IMPL ( T , n) \ 655template<> \ 656struct GetVectorTypeImpl<T, n> \ 657{ \ 658typedef T##n type; \ 659static SLANG_FORCE_INLINE SLANG_CUDA_CALL T##n fromScalar(T v) \ 660{ \ 661return make_##T##n(v); \ 662} \ 663}; 664#define GET_VECTOR_TYPE_IMPL_N ( T ) \ 665GET_VECTOR_TYPE_IMPL(T, 1) \ 666GET_VECTOR_TYPE_IMPL(T, 2) \ 667GET_VECTOR_TYPE_IMPL(T, 3) \ 668GET_VECTOR_TYPE_IMPL(T, 4) 669 670GET_VECTOR_TYPE_IMPL_N ( int ) 671GET_VECTOR_TYPE_IMPL_N ( bool ) 672GET_VECTOR_TYPE_IMPL_N (uint) 673GET_VECTOR_TYPE_IMPL_N (short) 674GET_VECTOR_TYPE_IMPL_N (ushort) 675GET_VECTOR_TYPE_IMPL_N (char) 676GET_VECTOR_TYPE_IMPL_N (uchar) 677GET_VECTOR_TYPE_IMPL_N (longlong) 678GET_VECTOR_TYPE_IMPL_N (ulonglong) 679GET_VECTOR_TYPE_IMPL_N (float) 680GET_VECTOR_TYPE_IMPL_N (double) 681#if SLANG_CUDA_ENABLE_HALF 682GET_VECTOR_TYPE_IMPL_N (__half) 683#endif 684template < typename T , int n > 685using Vector = typename GetVectorTypeImpl < T , n > ::type; 686 687template < typename T , int n, typename OtherT, int m > 688SLANG_FORCE_INLINE SLANG_CUDA_CALL Vector < T , n > _slang_vector_reshape (const Vector < OtherT, m > other) 689{ 690Vector < T , n > result; 691for ( int i = 0 ; i < n; i ++ ) 692{ 693OtherT otherElement = T ( 0 ); 694if (i < m) 695otherElement = _slang_vector_get_element (other, i); 696* _slang_vector_get_element_ptr ( & result, i) = ( T )otherElement; 697} 698return result; 699} 700 701template < typename T , int ROWS , int COLS > 702struct Matrix 703{ 704Vector < T , COLS > rows[ ROWS ]; 705SLANG_FORCE_INLINE SLANG_CUDA_CALL Vector < T , COLS >& operator[](size_t index) 706{ 707return rows[index]; 708} 709 710SLANG_FORCE_INLINE SLANG_CUDA_CALL const Vector < T , COLS >& operator[]( size_t index) const 711{ 712return rows[index]; 713} 714}; 715 716 717template < typename T , int ROWS , int COLS > 718SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix ( T scalar) 719{ 720Matrix < T , ROWS , COLS > result; 721for ( int i = 0 ; i < ROWS ; i ++ ) 722result. rows [i] = GetVectorTypeImpl < T , COLS > :: fromScalar (scalar); 723return result; 724} 725 726template < typename T , int ROWS , int COLS > 727SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix (const Vector < T , COLS >& row0) 728{ 729Matrix < T , ROWS , COLS > result; 730result. rows [ 0 ] = row0; 731return result; 732} 733 734template < typename T , int ROWS , int COLS > 735SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix ( 736const Vector < T , COLS >& row0, 737const Vector < T , COLS >& row1) 738{ 739Matrix < T , ROWS , COLS > result; 740result. rows [ 0 ] = row0; 741result. rows [ 1 ] = row1; 742return result; 743} 744 745template < typename T , int ROWS , int COLS > 746SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix ( 747const Vector < T , COLS >& row0, 748const Vector < T , COLS >& row1, 749const Vector < T , COLS >& row2) 750{ 751Matrix < T , ROWS , COLS > result; 752result. rows [ 0 ] = row0; 753result. rows [ 1 ] = row1; 754result. rows [ 2 ] = row2; 755return result; 756} 757 758template < typename T , int ROWS , int COLS > 759SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix ( 760const Vector < T , COLS >& row0, 761const Vector < T , COLS >& row1, 762const Vector < T , COLS >& row2, 763const Vector < T , COLS >& row3) 764{ 765Matrix < T , ROWS , COLS > result; 766result. rows [ 0 ] = row0; 767result. rows [ 1 ] = row1; 768result. rows [ 2 ] = row2; 769result. rows [ 3 ] = row3; 770return result; 771} 772 773template < typename T , int ROWS , int COLS , typename U , int otherRow, int otherCol > 774SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix ( 775const Matrix < U , otherRow, otherCol >& other) 776{ 777Matrix < T , ROWS , COLS > result; 778int minRow = ROWS ; 779int minCol = COLS ; 780if (minRow > otherRow) 781minRow = otherRow; 782if (minCol > otherCol) 783minCol = otherCol; 784for ( int i = 0 ; i < minRow; i ++ ) 785for ( int j = 0 ; j < minCol; j ++ ) 786* _slang_vector_get_element_ptr (result. rows + i, j) = 787( T ) _slang_vector_get_element (other. rows [i], j); 788return result; 789} 790 791template < typename T , int ROWS , int COLS > 792SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix ( T v0, T v1, T v2, T v3) 793{ 794Matrix < T , ROWS , COLS > rs; 795rs. rows [ 0 ]. x = v0; 796rs. rows [ 0 ]. y = v1; 797rs. rows [ 1 ]. x = v2; 798rs. rows [ 1 ]. y = v3; 799return rs; 800} 801 802template < typename T , int ROWS , int COLS > 803SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix ( 804T v0, 805T v1, 806T v2, 807T v3, 808T v4, 809T v5) 810{ 811Matrix < T , ROWS , COLS > rs; 812if ( COLS == 3 ) 813{ 814* _slang_vector_get_element_ptr ( & rs. rows [ 0 ], 0 ) = v0; 815* _slang_vector_get_element_ptr ( & rs. rows [ 0 ], 1 ) = v1; 816* _slang_vector_get_element_ptr ( & rs. rows [ 0 ], 2 ) = v2; 817* _slang_vector_get_element_ptr ( & rs. rows [ 1 ], 0 ) = v3; 818* _slang_vector_get_element_ptr ( & rs. rows [ 1 ], 1 ) = v4; 819* _slang_vector_get_element_ptr ( & rs. rows [ 1 ], 2 ) = v5; 820} 821else 822{ 823rs. rows [ 0 ]. x = v0; 824rs. rows [ 0 ]. y = v1; 825rs. rows [ 1 ]. x = v2; 826rs. rows [ 1 ]. y = v3; 827rs. rows [ 2 ]. x = v4; 828rs. rows [ 2 ]. y = v5; 829} 830return rs; 831} 832 833template < typename T , int ROWS , int COLS > 834SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix ( 835T v0, 836T v1, 837T v2, 838T v3, 839T v4, 840T v5, 841T v6, 842T v7) 843{ 844Matrix < T , ROWS , COLS > rs; 845if ( COLS == 4 ) 846{ 847* _slang_vector_get_element_ptr ( & rs. rows [ 0 ], 0 ) = v0; 848* _slang_vector_get_element_ptr ( & rs. rows [ 0 ], 1 ) = v1; 849* _slang_vector_get_element_ptr ( & rs. rows [ 0 ], 2 ) = v2; 850* _slang_vector_get_element_ptr ( & rs. rows [ 0 ], 3 ) = v3; 851* _slang_vector_get_element_ptr ( & rs. rows [ 1 ], 0 ) = v4; 852* _slang_vector_get_element_ptr ( & rs. rows [ 1 ], 1 ) = v5; 853* _slang_vector_get_element_ptr ( & rs. rows [ 1 ], 2 ) = v6; 854* _slang_vector_get_element_ptr ( & rs. rows [ 1 ], 3 ) = v7; 855} 856else 857{ 858rs. rows [ 0 ]. x = v0; 859rs. rows [ 0 ]. y = v1; 860rs. rows [ 1 ]. x = v2; 861rs. rows [ 1 ]. y = v3; 862rs. rows [ 2 ]. x = v4; 863rs. rows [ 2 ]. y = v5; 864rs. rows [ 3 ]. x = v6; 865rs. rows [ 3 ]. y = v7; 866} 867return rs; 868} 869 870template < typename T , int ROWS , int COLS > 871SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix ( 872T v0, 873T v1, 874T v2, 875T v3, 876T v4, 877T v5, 878T v6, 879T v7, 880T v8) 881{ 882Matrix < T , ROWS , COLS > rs; 883rs. rows [ 0 ]. x = v0; 884rs. rows [ 0 ]. y = v1; 885rs. rows [ 0 ]. z = v2; 886rs. rows [ 1 ]. x = v3; 887rs. rows [ 1 ]. y = v4; 888rs. rows [ 1 ]. z = v5; 889rs. rows [ 2 ]. x = v6; 890rs. rows [ 2 ]. y = v7; 891rs. rows [ 2 ]. z = v8; 892return rs; 893} 894 895template < typename T , int ROWS , int COLS > 896SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix ( 897T v0, 898T v1, 899T v2, 900T v3, 901T v4, 902T v5, 903T v6, 904T v7, 905T v8, 906T v9, 907T v10, 908T v11) 909{ 910Matrix < T , ROWS , COLS > rs; 911if ( COLS == 4 ) 912{ 913* _slang_vector_get_element_ptr ( & rs. rows [ 0 ], 0 ) = v0; 914* _slang_vector_get_element_ptr ( & rs. rows [ 0 ], 1 ) = v1; 915* _slang_vector_get_element_ptr ( & rs. rows [ 0 ], 2 ) = v2; 916* _slang_vector_get_element_ptr ( & rs. rows [ 0 ], 3 ) = v3; 917* _slang_vector_get_element_ptr ( & rs. rows [ 1 ], 0 ) = v4; 918* _slang_vector_get_element_ptr ( & rs. rows [ 1 ], 1 ) = v5; 919* _slang_vector_get_element_ptr ( & rs. rows [ 1 ], 2 ) = v6; 920* _slang_vector_get_element_ptr ( & rs. rows [ 1 ], 3 ) = v7; 921* _slang_vector_get_element_ptr ( & rs. rows [ 2 ], 0 ) = v8; 922* _slang_vector_get_element_ptr ( & rs. rows [ 2 ], 1 ) = v9; 923* _slang_vector_get_element_ptr ( & rs. rows [ 2 ], 2 ) = v10; 924* _slang_vector_get_element_ptr ( & rs. rows [ 2 ], 3 ) = v11; 925} 926else 927{ 928rs. rows [ 0 ]. x = v0; 929rs. rows [ 0 ]. y = v1; 930rs. rows [ 0 ]. z = v2; 931rs. rows [ 1 ]. x = v3; 932rs. rows [ 1 ]. y = v4; 933rs. rows [ 1 ]. z = v5; 934rs. rows [ 2 ]. x = v6; 935rs. rows [ 2 ]. y = v7; 936rs. rows [ 2 ]. z = v8; 937rs. rows [ 3 ]. x = v9; 938rs. rows [ 3 ]. y = v10; 939rs. rows [ 3 ]. z = v11; 940} 941return rs; 942} 943 944template < typename T , int ROWS , int COLS > 945SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , ROWS , COLS > makeMatrix ( 946T v0, 947T v1, 948T v2, 949T v3, 950T v4, 951T v5, 952T v6, 953T v7, 954T v8, 955T v9, 956T v10, 957T v11, 958T v12, 959T v13, 960T v14, 961T v15) 962{ 963Matrix < T , ROWS , COLS > rs; 964rs. rows [ 0 ]. x = v0; 965rs. rows [ 0 ]. y = v1; 966rs. rows [ 0 ]. z = v2; 967rs. rows [ 0 ]. w = v3; 968rs. rows [ 1 ]. x = v4; 969rs. rows [ 1 ]. y = v5; 970rs. rows [ 1 ]. z = v6; 971rs. rows [ 1 ]. w = v7; 972rs. rows [ 2 ]. x = v8; 973rs. rows [ 2 ]. y = v9; 974rs. rows [ 2 ]. z = v10; 975rs. rows [ 2 ]. w = v11; 976rs. rows [ 3 ]. x = v12; 977rs. rows [ 3 ]. y = v13; 978rs. rows [ 3 ]. z = v14; 979rs. rows [ 3 ]. w = v15; 980return rs; 981} 982 983#define SLANG_MATRIX_BINARY_OP ( T , op) \ 984template<int R, int C> \ 985SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix<T, R, C> operator op( \ 986const Matrix<T, R, C>& thisVal, \ 987const Matrix<T, R, C>& other) \ 988{ \ 989Matrix<T, R, C> result; \ 990for (int i = 0; i < R; i++) \ 991for (int j = 0; j < C; j++) \ 992*_slang_vector_get_element_ptr(result.rows + i, j) = \ 993_slang_vector_get_element(thisVal.rows[i], j) \ 994op _slang_vector_get_element(other.rows[i], j); \ 995return result; \ 996} 997 998#define SLANG_MATRIX_UNARY_OP ( T , op) \ 999template<int R, int C> \ 1000SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix<T, R, C> operator op(const Matrix<T, R, C>& thisVal) \ 1001{ \ 1002Matrix<T, R, C> result; \ 1003for (int i = 0; i < R; i++) \ 1004for (int j = 0; j < C; j++) \ 1005*_slang_vector_get_element_ptr(result.rows + i, j) = \ 1006op _slang_vector_get_element(thisVal.rows[i], j); \ 1007return result; \ 1008} 1009#define SLANG_INT_MATRIX_OPS ( T ) \ 1010SLANG_MATRIX_BINARY_OP(T, +) \ 1011SLANG_MATRIX_BINARY_OP(T, -) \ 1012SLANG_MATRIX_BINARY_OP(T, *) \ 1013SLANG_MATRIX_BINARY_OP(T, /) \ 1014SLANG_MATRIX_BINARY_OP(T, &) \ 1015SLANG_MATRIX_BINARY_OP(T, |) \ 1016SLANG_MATRIX_BINARY_OP(T, &&) \ 1017SLANG_MATRIX_BINARY_OP(T, ||) \ 1018SLANG_MATRIX_BINARY_OP(T, ^) \ 1019SLANG_MATRIX_BINARY_OP(T, %) \ 1020SLANG_MATRIX_UNARY_OP(T, !) \ 1021SLANG_MATRIX_UNARY_OP(T, ~) 1022#define SLANG_FLOAT_MATRIX_OPS ( T ) \ 1023SLANG_MATRIX_BINARY_OP(T, +) \ 1024SLANG_MATRIX_BINARY_OP(T, -) \ 1025SLANG_MATRIX_BINARY_OP(T, *) \ 1026SLANG_MATRIX_BINARY_OP(T, /) \ 1027SLANG_MATRIX_UNARY_OP(T, -) 1028SLANG_INT_MATRIX_OPS ( int ) 1029SLANG_INT_MATRIX_OPS ( uint ) 1030SLANG_INT_MATRIX_OPS (short) 1031SLANG_INT_MATRIX_OPS (ushort) 1032SLANG_INT_MATRIX_OPS (char) 1033SLANG_INT_MATRIX_OPS (uchar) 1034SLANG_INT_MATRIX_OPS (longlong) 1035SLANG_INT_MATRIX_OPS (ulonglong) 1036SLANG_FLOAT_MATRIX_OPS (float) 1037SLANG_FLOAT_MATRIX_OPS (double) 1038#if SLANG_CUDA_ENABLE_HALF 1039SLANG_FLOAT_MATRIX_OPS (__half) 1040#endif 1041#define SLANG_MATRIX_INT_NEG_OP ( T ) \ 1042template < int R , int C > \ 1043SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , R , C > operator - (Matrix < T , R , C > thisVal) \ 1044{ \ 1045Matrix < T , R , C > result; \ 1046for ( int i = 0 ; i < R ; i ++ ) \ 1047for ( int j = 0 ; j < C ; j ++ ) \ 1048* _slang_vector_get_element_ptr (result. rows + i, j) = \ 10490 - _slang_vector_get_element (thisVal. rows [i], j); \ 1050return result; \ 1051} 1052SLANG_MATRIX_INT_NEG_OP ( int ) 1053SLANG_MATRIX_INT_NEG_OP ( uint ) 1054SLANG_MATRIX_INT_NEG_OP (short) 1055SLANG_MATRIX_INT_NEG_OP (ushort) 1056SLANG_MATRIX_INT_NEG_OP (char) 1057SLANG_MATRIX_INT_NEG_OP (uchar) 1058SLANG_MATRIX_INT_NEG_OP (longlong) 1059SLANG_MATRIX_INT_NEG_OP (ulonglong) 1060 1061#define SLANG_FLOAT_MATRIX_MOD ( T ) \ 1062template < int R , int C > \ 1063SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < T , R , C > operator%( \ 1064Matrix < T , R , C > left, \ 1065Matrix < T , R , C > right) \ 1066{ \ 1067Matrix < T , R , C > result; \ 1068for ( int i = 0 ; i < R ; i ++ ) \ 1069for ( int j = 0 ; j < C ; j ++ ) \ 1070* _slang_vector_get_element_ptr (result. rows + i, j) = _slang_fmod ( \ 1071_slang_vector_get_element (left. rows [i], j), \ 1072_slang_vector_get_element (right. rows [i], j)); \ 1073return result; \ 1074} 1075 1076SLANG_FLOAT_MATRIX_MOD ( float ) 1077SLANG_FLOAT_MATRIX_MOD ( double ) 1078#if SLANG_CUDA_ENABLE_HALF 1079template < int R , int C > 1080SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix < __half, R , C > operator%( 1081Matrix < __half, R , C > left, 1082Matrix < __half, R , C > right) 1083{ 1084Matrix < __half, R , C > result; 1085for ( int i = 0 ; i < R ; i ++ ) 1086for ( int j = 0 ; j < C ; j ++ ) 1087* _slang_vector_get_element_ptr (result. rows + i, j) = __float2half ( _slang_fmod ( 1088__half2float ( _slang_vector_get_element (left. rows [i], j)), 1089__half2float ( _slang_vector_get_element (right. rows [i], j)))); 1090return result; 1091} 1092#endif 1093#undef SLANG_FLOAT_MATRIX_MOD 1094#undef SLANG_MATRIX_BINARY_OP 1095#undef SLANG_MATRIX_UNARY_OP 1096#undef SLANG_INT_MATRIX_OPS 1097#undef SLANG_FLOAT_MATRIX_OPS 1098#undef SLANG_MATRIX_INT_NEG_OP 1099#undef SLANG_FLOAT_MATRIX_MOD 1100 1101#define SLANG_SELECT_IMPL ( T , N ) \ 1102SLANG_FORCE_INLINE SLANG_CUDA_CALL Vector<T, N> _slang_select( \ 1103bool##N condition, \ 1104Vector<T, N> v0, \ 1105Vector<T, N> v1) \ 1106{ \ 1107Vector<T, N> result; \ 1108for (int i = 0; i < N; i++) \ 1109{ \ 1110*_slang_vector_get_element_ptr(&result, i) = _slang_vector_get_element(condition, i) \ 1111? _slang_vector_get_element(v0, i) \ 1112: _slang_vector_get_element(v1, i); \ 1113} \ 1114return result; \ 1115} 1116#define SLANG_SELECT_T ( T ) \ 1117SLANG_SELECT_IMPL(T, 2) \ 1118SLANG_SELECT_IMPL(T, 3) \ 1119SLANG_SELECT_IMPL(T, 4) 1120 1121SLANG_SELECT_T ( int ) 1122SLANG_SELECT_T ( bool ) 1123SLANG_SELECT_T (uint) 1124SLANG_SELECT_T (short) 1125SLANG_SELECT_T (ushort) 1126SLANG_SELECT_T (char) 1127SLANG_SELECT_T (uchar) 1128SLANG_SELECT_T (float) 1129SLANG_SELECT_T (double) 1130 1131template < typename T > 1132SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_select (bool condition, T v0, T v1) 1133{ 1134return condition ? v0 : v1; 1135} 1136 1137// 1138// Half support 1139// 1140 1141#if SLANG_CUDA_ENABLE_HALF 1142SLANG_SELECT_T ( __half ) 1143 1144// Convenience functions ushort -> half 1145 1146SLANG_FORCE_INLINE SLANG_CUDA_CALL __half2 __ushort_as_half ( const ushort2 & i) 1147{ 1148return __halves2half2 ( __ushort_as_half (i. x ), __ushort_as_half (i. y )); 1149} 1150SLANG_FORCE_INLINE SLANG_CUDA_CALL __half3 __ushort_as_half ( const ushort3 & i) 1151{ 1152return __half3{ __ushort_as_half (i. x ), __ushort_as_half (i. y ), __ushort_as_half (i. z )}; 1153} 1154SLANG_FORCE_INLINE SLANG_CUDA_CALL __half4 __ushort_as_half ( const ushort4 & i) 1155{ 1156return __half4{ 1157__ushort_as_half (i. x ), 1158__ushort_as_half (i. y ), 1159__ushort_as_half (i. z ), 1160__ushort_as_half (i. w )}; 1161} 1162 1163// Convenience functions half -> ushort 1164 1165SLANG_FORCE_INLINE SLANG_CUDA_CALL ushort2 __half_as_ushort ( const __half2 & i) 1166{ 1167return make_ushort2 ( __half_as_ushort (i. x ), __half_as_ushort (i. y )); 1168} 1169SLANG_FORCE_INLINE SLANG_CUDA_CALL ushort3 __half_as_ushort ( const __half3 & i) 1170{ 1171return make_ushort3 ( __half_as_ushort (i. x ), __half_as_ushort (i. y ), __half_as_ushort (i. z )); 1172} 1173SLANG_FORCE_INLINE SLANG_CUDA_CALL ushort4 __half_as_ushort ( const __half4 & i) 1174{ 1175return make_ushort4 ( 1176__half_as_ushort (i. x ), 1177__half_as_ushort (i. y ), 1178__half_as_ushort (i. z ), 1179__half_as_ushort (i. w )); 1180} 1181 1182// This is a little bit of a hack. Fortunately CUDA has the definitions of the templated types in 1183// include/surface_indirect_functions.h 1184// Here we find the template definition requires a specialization of __nv_isurf_trait to allow 1185// a specialization of the surface write functions. 1186// This *isn't* a problem on the read functions as they don't have a return type that uses this 1187// mechanism 1188 1189template <> 1190struct __nv_isurf_trait < __half > 1191{ 1192typedef void type ; 1193}; 1194template <> 1195struct __nv_isurf_trait < __half2 > 1196{ 1197typedef void type ; 1198}; 1199template <> 1200struct __nv_isurf_trait < __half4 > 1201{ 1202typedef void type ; 1203}; 1204 1205#define SLANG_DROP_PARENS (...) __VA_ARGS__ 1206 1207#define SLANG_SURFACE_READ ( FUNC_NAME , TYPE_ARGS , ARGS ) \ 1208template<> \ 1209SLANG_FORCE_INLINE SLANG_CUDA_CALL __half FUNC_NAME<__half>( \ 1210cudaSurfaceObject_t surfObj, \ 1211SLANG_DROP_PARENS TYPE_ARGS, \ 1212cudaSurfaceBoundaryMode boundaryMode) \ 1213{ \ 1214return __ushort_as_half(FUNC_NAME<ushort>(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ 1215} \ 1216\ 1217template<> \ 1218SLANG_FORCE_INLINE SLANG_CUDA_CALL __half2 FUNC_NAME<__half2>( \ 1219cudaSurfaceObject_t surfObj, \ 1220SLANG_DROP_PARENS TYPE_ARGS, \ 1221cudaSurfaceBoundaryMode boundaryMode) \ 1222{ \ 1223return __ushort_as_half( \ 1224FUNC_NAME<ushort2>(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ 1225} \ 1226\ 1227template<> \ 1228SLANG_FORCE_INLINE SLANG_CUDA_CALL __half4 FUNC_NAME<__half4>( \ 1229cudaSurfaceObject_t surfObj, \ 1230SLANG_DROP_PARENS TYPE_ARGS, \ 1231cudaSurfaceBoundaryMode boundaryMode) \ 1232{ \ 1233return __ushort_as_half( \ 1234FUNC_NAME<ushort4>(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ 1235} 1236 1237SLANG_SURFACE_READ (surf1Dread, ( int x), (x)) 1238SLANG_SURFACE_READ (surf2Dread, ( int x, int y), (x, y)) 1239SLANG_SURFACE_READ (surf3Dread, ( int x, int y, int z), (x, y, z)) 1240SLANG_SURFACE_READ (surf1DLayeredread, ( int x, int layer), (x, layer)) 1241SLANG_SURFACE_READ (surf2DLayeredread, ( int x, int y, int layer), (x, y, layer)) 1242SLANG_SURFACE_READ (surfCubemapread, ( int x, int y, int face), (x, y, face)) 1243SLANG_SURFACE_READ (surfCubemapLayeredread, ( int x, int y, int layerFace), (x, y, layerFace)) 1244 1245#define SLANG_SURFACE_WRITE ( FUNC_NAME , TYPE_ARGS , ARGS ) \ 1246template<> \ 1247SLANG_FORCE_INLINE SLANG_CUDA_CALL void FUNC_NAME<__half>( \ 1248__half data, \ 1249cudaSurfaceObject_t surfObj, \ 1250SLANG_DROP_PARENS TYPE_ARGS, \ 1251cudaSurfaceBoundaryMode boundaryMode) \ 1252{ \ 1253FUNC_NAME<ushort>(__half_as_ushort(data), surfObj, SLANG_DROP_PARENS ARGS, boundaryMode); \ 1254} \ 1255\ 1256template<> \ 1257SLANG_FORCE_INLINE SLANG_CUDA_CALL void FUNC_NAME<__half2>( \ 1258__half2 data, \ 1259cudaSurfaceObject_t surfObj, \ 1260SLANG_DROP_PARENS TYPE_ARGS, \ 1261cudaSurfaceBoundaryMode boundaryMode) \ 1262{ \ 1263FUNC_NAME<ushort2>(__half_as_ushort(data), surfObj, SLANG_DROP_PARENS ARGS, boundaryMode); \ 1264} \ 1265\ 1266template<> \ 1267SLANG_FORCE_INLINE SLANG_CUDA_CALL void FUNC_NAME<__half4>( \ 1268__half4 data, \ 1269cudaSurfaceObject_t surfObj, \ 1270SLANG_DROP_PARENS TYPE_ARGS, \ 1271cudaSurfaceBoundaryMode boundaryMode) \ 1272{ \ 1273FUNC_NAME<ushort4>(__half_as_ushort(data), surfObj, SLANG_DROP_PARENS ARGS, boundaryMode); \ 1274} 1275 1276SLANG_SURFACE_WRITE (surf1Dwrite, ( int x), (x)) 1277SLANG_SURFACE_WRITE (surf2Dwrite, ( int x, int y), (x, y)) 1278SLANG_SURFACE_WRITE (surf3Dwrite, ( int x, int y, int z), (x, y, z)) 1279SLANG_SURFACE_WRITE (surf1DLayeredwrite, ( int x, int layer), (x, layer)) 1280SLANG_SURFACE_WRITE (surf2DLayeredwrite, ( int x, int y, int layer), (x, y, layer)) 1281SLANG_SURFACE_WRITE (surfCubemapwrite, ( int x, int y, int face), (x, y, face)) 1282SLANG_SURFACE_WRITE (surfCubemapLayeredwrite, ( int x, int y, int layerFace), (x, y, layerFace)) 1283 1284// ! Hack to test out reading !!! 1285// Only works converting *from* half 1286 1287// template <typename T> 1288// SLANG_FORCE_INLINE SLANG_CUDA_CALL T surf2Dread_convert(cudaSurfaceObject_t surfObj, int x, int 1289// y, cudaSurfaceBoundaryMode boundaryMode); 1290 1291#define SLANG_SURFACE_READ_HALF_CONVERT ( FUNC_NAME , TYPE_ARGS , ARGS ) \ 1292\ 1293template<typename T> \ 1294SLANG_FORCE_INLINE SLANG_CUDA_CALL T FUNC_NAME##_convert( \ 1295cudaSurfaceObject_t surfObj, \ 1296SLANG_DROP_PARENS TYPE_ARGS, \ 1297cudaSurfaceBoundaryMode boundaryMode); \ 1298\ 1299template<> \ 1300SLANG_FORCE_INLINE SLANG_CUDA_CALL float FUNC_NAME##_convert<float>( \ 1301cudaSurfaceObject_t surfObj, \ 1302SLANG_DROP_PARENS TYPE_ARGS, \ 1303cudaSurfaceBoundaryMode boundaryMode) \ 1304{ \ 1305return __ushort_as_half( \ 1306FUNC_NAME<uint16_t>(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ 1307} \ 1308\ 1309template<> \ 1310SLANG_FORCE_INLINE SLANG_CUDA_CALL float2 FUNC_NAME##_convert<float2>( \ 1311cudaSurfaceObject_t surfObj, \ 1312SLANG_DROP_PARENS TYPE_ARGS, \ 1313cudaSurfaceBoundaryMode boundaryMode) \ 1314{ \ 1315const __half2 v = \ 1316__ushort_as_half(FUNC_NAME<ushort2>(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ 1317return float2{v.x, v.y}; \ 1318} \ 1319\ 1320template<> \ 1321SLANG_FORCE_INLINE SLANG_CUDA_CALL float4 FUNC_NAME##_convert<float4>( \ 1322cudaSurfaceObject_t surfObj, \ 1323SLANG_DROP_PARENS TYPE_ARGS, \ 1324cudaSurfaceBoundaryMode boundaryMode) \ 1325{ \ 1326const __half4 v = \ 1327__ushort_as_half(FUNC_NAME<ushort4>(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ 1328return float4{v.x, v.y, v.z, v.w}; \ 1329} 1330 1331SLANG_SURFACE_READ_HALF_CONVERT (surf1Dread, ( int x), (x)) 1332SLANG_SURFACE_READ_HALF_CONVERT (surf2Dread, ( int x, int y), (x, y)) 1333SLANG_SURFACE_READ_HALF_CONVERT (surf3Dread, ( int x, int y, int z), (x, y, z)) 1334 1335#endif 1336 1337// Support for doing format conversion when writing to a surface/RWTexture 1338 1339// NOTE! For normal surface access x values are *byte* addressed. 1340// For the _convert versions they are *not*. They don't need to be because sust.p does not require 1341// it. 1342 1343// https://docs.nvidia.com/cuda/inline-ptx-assembly/index.html 1344// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#surface-instructions-sust 1345 1346 1347// surf1Dwrite_convert 1348 1349template < typename T > 1350SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert ( 1351T v, 1352cudaSurfaceObject_t surfObj, 1353int x, 1354cudaSurfaceBoundaryMode boundaryMode); 1355 1356#define SLANG_SURF1DWRITE_CONVERT_IMPL ( T , c) \ 1357template<> \ 1358SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert<T>( \ 1359T v, \ 1360cudaSurfaceObject_t surfObj, \ 1361int x, \ 1362cudaSurfaceBoundaryMode boundaryMode) \ 1363{ \ 1364asm volatile( \ 1365"sust.p.1d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1}], {%2};" ::"l"(surfObj), \ 1366"r"(x), \ 1367c(v)); \ 1368} \ 1369template<> \ 1370SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert<T##2>( \ 1371T##2 v, \ 1372cudaSurfaceObject_t surfObj, \ 1373int x, \ 1374cudaSurfaceBoundaryMode boundaryMode) \ 1375{ \ 1376const T vx = v.x, vy = v.y; \ 1377asm volatile( \ 1378"sust.p.1d.v2.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1}], {%2, %3};" ::"l"(surfObj), \ 1379"r"(x), \ 1380c(vx), \ 1381c(vy)); \ 1382} \ 1383template<> \ 1384SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert<T##4>( \ 1385T##4 v, \ 1386cudaSurfaceObject_t surfObj, \ 1387int x, \ 1388cudaSurfaceBoundaryMode boundaryMode) \ 1389{ \ 1390const T vx = v.x, vy = v.y, vz = v.z, vw = v.w; \ 1391asm volatile( \ 1392"sust.p.1d.v4.b32." SLANG_PTX_BOUNDARY_MODE \ 1393" [%0, {%1}], {%2, %3, %4, %5};" ::"l"(surfObj), \ 1394"r"(x), \ 1395c(vx), \ 1396c(vy), \ 1397c(vz), \ 1398c(vw)); \ 1399} 1400 1401SLANG_SURF1DWRITE_CONVERT_IMPL (float, "f" ) 1402SLANG_SURF1DWRITE_CONVERT_IMPL (uint, "r" ) 1403SLANG_SURF1DWRITE_CONVERT_IMPL (int, "r" ) 1404 1405// surf1DLayeredwrite_convert (not supported) 1406 1407template < typename T > 1408SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1DLayeredwrite_convert ( 1409T v, 1410cudaSurfaceObject_t surfObj, 1411int x, 1412int layer, 1413cudaSurfaceBoundaryMode boundaryMode) 1414{ 1415static_assert (false, "CUDA doesn't support formatted surface writes on 1D array surfaces" ); 1416} 1417 1418// surf2Dwrite_convert 1419 1420template < typename T > 1421SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert ( 1422T v, 1423cudaSurfaceObject_t surfObj, 1424int x, 1425int y, 1426cudaSurfaceBoundaryMode boundaryMode); 1427 1428#define SLANG_SURF2DWRITE_CONVERT_IMPL ( T , c) \ 1429template<> \ 1430SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert<T>( \ 1431T v, \ 1432cudaSurfaceObject_t surfObj, \ 1433int x, \ 1434int y, \ 1435cudaSurfaceBoundaryMode boundaryMode) \ 1436{ \ 1437asm volatile( \ 1438"sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1, %2}], {%3};" ::"l"(surfObj), \ 1439"r"(x), \ 1440"r"(y), \ 1441c(v)); \ 1442} \ 1443template<> \ 1444SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert<T##2>( \ 1445T##2 v, \ 1446cudaSurfaceObject_t surfObj, \ 1447int x, \ 1448int y, \ 1449cudaSurfaceBoundaryMode boundaryMode) \ 1450{ \ 1451const T vx = v.x, vy = v.y; \ 1452asm volatile( \ 1453"sust.p.2d.v2.b32." SLANG_PTX_BOUNDARY_MODE \ 1454" [%0, {%1, %2}], {%3, %4};" ::"l"(surfObj), \ 1455"r"(x), \ 1456"r"(y), \ 1457c(vx), \ 1458c(vy)); \ 1459} \ 1460template<> \ 1461SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert<T##4>( \ 1462T##4 v, \ 1463cudaSurfaceObject_t surfObj, \ 1464int x, \ 1465int y, \ 1466cudaSurfaceBoundaryMode boundaryMode) \ 1467{ \ 1468const T vx = v.x, vy = v.y, vz = v.z, vw = v.w; \ 1469asm volatile( \ 1470"sust.p.2d.v4.b32." SLANG_PTX_BOUNDARY_MODE \ 1471" [%0, {%1, %2}], {%3, %4, %5, %6};" ::"l"(surfObj), \ 1472"r"(x), \ 1473"r"(y), \ 1474c(vx), \ 1475c(vy), \ 1476c(vz), \ 1477c(vw)); \ 1478} 1479 1480SLANG_SURF2DWRITE_CONVERT_IMPL (float, "f" ) 1481SLANG_SURF2DWRITE_CONVERT_IMPL (uint, "r" ) 1482SLANG_SURF2DWRITE_CONVERT_IMPL (int, "r" ) 1483 1484// surf2DLayeredwrite_convert (not supported) 1485 1486template < typename T > 1487SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2DLayeredwrite_convert ( 1488T v, 1489cudaSurfaceObject_t surfObj, 1490int x, 1491int y, 1492int layer, 1493cudaSurfaceBoundaryMode boundaryMode) 1494{ 1495static_assert (false, "CUDA doesn't support formatted surface writes on 2D array surfaces" ); 1496} 1497 1498// surf3Dwrite_convert 1499 1500template < typename T > 1501SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert ( 1502T v, 1503cudaSurfaceObject_t surfObj, 1504int x, 1505int y, 1506int z, 1507cudaSurfaceBoundaryMode boundaryMode); 1508 1509#define SLANG_SURF3DWRITE_CONVERT_IMPL ( T , c) \ 1510template<> \ 1511SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert<T>( \ 1512T v, \ 1513cudaSurfaceObject_t surfObj, \ 1514int x, \ 1515int y, \ 1516int z, \ 1517cudaSurfaceBoundaryMode boundaryMode) \ 1518{ \ 1519asm volatile( \ 1520"sust.p.3d.b32." SLANG_PTX_BOUNDARY_MODE \ 1521" [%0, {%1, %2, %3, %4}], {%5};" ::"l"(surfObj), \ 1522"r"(x), \ 1523"r"(y), \ 1524"r"(z), \ 1525"r"(0), \ 1526c(v)); \ 1527} \ 1528template<> \ 1529SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert<T##2>( \ 1530T##2 v, \ 1531cudaSurfaceObject_t surfObj, \ 1532int x, \ 1533int y, \ 1534int z, \ 1535cudaSurfaceBoundaryMode boundaryMode) \ 1536{ \ 1537const T vx = v.x, vy = v.y; \ 1538asm volatile( \ 1539"sust.p.3d.v2.b32." SLANG_PTX_BOUNDARY_MODE \ 1540" [%0, {%1, %2, %3, %4}], {%5, %6};" ::"l"(surfObj), \ 1541"r"(x), \ 1542"r"(y), \ 1543"r"(z), \ 1544"r"(0), \ 1545c(vx), \ 1546c(vy)); \ 1547} \ 1548template<> \ 1549SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert<T##4>( \ 1550T##4 v, \ 1551cudaSurfaceObject_t surfObj, \ 1552int x, \ 1553int y, \ 1554int z, \ 1555cudaSurfaceBoundaryMode boundaryMode) \ 1556{ \ 1557const T vx = v.x, vy = v.y, vz = v.z, vw = v.w; \ 1558asm volatile( \ 1559"sust.p.3d.v4.b32." SLANG_PTX_BOUNDARY_MODE \ 1560" [%0, {%1, %2, %3, %4}], {%5, %6, %7, %8};" ::"l"(surfObj), \ 1561"r"(x), \ 1562"r"(y), \ 1563"r"(z), \ 1564"r"(0), \ 1565c(vx), \ 1566c(vy), \ 1567c(vz), \ 1568c(vw)); \ 1569} 1570 1571SLANG_SURF3DWRITE_CONVERT_IMPL (float, "f" ) 1572SLANG_SURF3DWRITE_CONVERT_IMPL (uint, "r" ) 1573SLANG_SURF3DWRITE_CONVERT_IMPL (int, "r" ) 1574 1575// ----------------------------- F32 ----------------------------------------- 1576 1577// Unary 1578SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_ceil ( float f) 1579{ 1580return :: ceilf (f); 1581} 1582SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_floor ( float f) 1583{ 1584return :: floorf (f); 1585} 1586SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_round ( float f) 1587{ 1588return :: roundf (f); 1589} 1590SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sin ( float f) 1591{ 1592return :: sinf (f); 1593} 1594SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_cos ( float f) 1595{ 1596return :: cosf (f); 1597} 1598SLANG_FORCE_INLINE SLANG_CUDA_CALL void F32_sincos ( float f, float * s, float * c) 1599{ 1600:: sincosf (f, s, c); 1601} 1602SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_tan ( float f) 1603{ 1604return :: tanf (f); 1605} 1606SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_asin ( float f) 1607{ 1608return :: asinf (f); 1609} 1610SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_acos ( float f) 1611{ 1612return :: acosf (f); 1613} 1614SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_atan ( float f) 1615{ 1616return :: atanf (f); 1617} 1618SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sinh ( float f) 1619{ 1620return :: sinhf (f); 1621} 1622SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_cosh ( float f) 1623{ 1624return :: coshf (f); 1625} 1626SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_tanh ( float f) 1627{ 1628return :: tanhf (f); 1629} 1630SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_asinh ( float f) 1631{ 1632return :: asinhf (f); 1633} 1634SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_acosh ( float f) 1635{ 1636return :: acoshf (f); 1637} 1638SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_atanh ( float f) 1639{ 1640return :: atanhf (f); 1641} 1642SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_log2 ( float f) 1643{ 1644return :: log2f (f); 1645} 1646SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_log ( float f) 1647{ 1648return :: logf (f); 1649} 1650SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_log10 ( float f) 1651{ 1652return :: log10f (f); 1653} 1654SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_exp2 ( float f) 1655{ 1656return :: exp2f (f); 1657} 1658SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_exp ( float f) 1659{ 1660return :: expf (f); 1661} 1662SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_abs ( float f) 1663{ 1664return :: fabsf (f); 1665} 1666SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_trunc ( float f) 1667{ 1668return :: truncf (f); 1669} 1670SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sqrt ( float f) 1671{ 1672return :: sqrtf (f); 1673} 1674SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_rsqrt ( float f) 1675{ 1676return :: rsqrtf (f); 1677} 1678SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sign ( float f) 1679{ 1680return (f == 0.0f ) ? f : ((f < 0.0f ) ? -1.0f : 1.0f ); 1681} 1682SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_frac ( float f) 1683{ 1684return f - F32_floor (f); 1685} 1686 1687SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F32_isnan ( float f) 1688{ 1689return isnan (f); 1690} 1691SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F32_isfinite ( float f) 1692{ 1693return isfinite (f); 1694} 1695SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F32_isinf ( float f) 1696{ 1697return isinf (f); 1698} 1699 1700// Binary 1701SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_min ( float a, float b) 1702{ 1703return :: fminf (a, b); 1704} 1705SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_max ( float a, float b) 1706{ 1707return :: fmaxf (a, b); 1708} 1709SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_pow ( float a, float b) 1710{ 1711return :: powf (a, b); 1712} 1713SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_fmod ( float a, float b) 1714{ 1715return :: fmodf (a, b); 1716} 1717SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_remainder ( float a, float b) 1718{ 1719return :: remainderf (a, b); 1720} 1721SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_atan2 ( float a, float b) 1722{ 1723return float (:: atan2 (a, b)); 1724} 1725 1726SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_frexp ( float x, int * e) 1727{ 1728return frexpf (x, e); 1729} 1730 1731SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_modf ( float x, float * ip) 1732{ 1733return :: modff (x, ip); 1734} 1735 1736SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t F32_asuint ( float f) 1737{ 1738Union32 u; 1739u. f = f; 1740return u. u ; 1741} 1742SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t F32_asint ( float f) 1743{ 1744Union32 u; 1745u. f = f; 1746return u. i ; 1747} 1748 1749// Ternary 1750SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_fma ( float a, float b, float c) 1751{ 1752return :: fmaf (a, b, c); 1753} 1754 1755 1756// ----------------------------- F64 ----------------------------------------- 1757 1758// Unary 1759SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_ceil ( double f) 1760{ 1761return :: ceil (f); 1762} 1763SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_floor ( double f) 1764{ 1765return :: floor (f); 1766} 1767SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_round ( double f) 1768{ 1769return :: round (f); 1770} 1771SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sin ( double f) 1772{ 1773return :: sin (f); 1774} 1775SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_cos ( double f) 1776{ 1777return :: cos (f); 1778} 1779SLANG_FORCE_INLINE SLANG_CUDA_CALL void F64_sincos ( double f, double * s, double * c) 1780{ 1781:: sincos (f, s, c); 1782} 1783SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_tan ( double f) 1784{ 1785return :: tan (f); 1786} 1787SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_asin ( double f) 1788{ 1789return :: asin (f); 1790} 1791SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_acos ( double f) 1792{ 1793return :: acos (f); 1794} 1795SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_atan ( double f) 1796{ 1797return :: atan (f); 1798} 1799SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sinh ( double f) 1800{ 1801return :: sinh (f); 1802} 1803SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_cosh ( double f) 1804{ 1805return :: cosh (f); 1806} 1807SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_tanh ( double f) 1808{ 1809return :: tanh (f); 1810} 1811SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_log2 ( double f) 1812{ 1813return :: log2 (f); 1814} 1815SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_log ( double f) 1816{ 1817return :: log (f); 1818} 1819SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_log10 ( float f) 1820{ 1821return :: log10 (f); 1822} 1823SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_exp2 ( double f) 1824{ 1825return :: exp2 (f); 1826} 1827SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_exp ( double f) 1828{ 1829return :: exp (f); 1830} 1831SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_abs ( double f) 1832{ 1833return :: fabs (f); 1834} 1835SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_trunc ( double f) 1836{ 1837return :: trunc (f); 1838} 1839SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sqrt ( double f) 1840{ 1841return :: sqrt (f); 1842} 1843SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_rsqrt ( double f) 1844{ 1845return :: rsqrt (f); 1846} 1847SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sign ( double f) 1848{ 1849return (f == 0.0 ) ? f : ((f < 0.0 ) ? -1.0 : 1.0 ); 1850} 1851SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_frac ( double f) 1852{ 1853return f - F64_floor (f); 1854} 1855 1856SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F64_isnan ( double f) 1857{ 1858return isnan (f); 1859} 1860SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F64_isfinite ( double f) 1861{ 1862return isfinite (f); 1863} 1864SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F64_isinf ( double f) 1865{ 1866return isinf (f); 1867} 1868 1869// Binary 1870SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_min ( double a, double b) 1871{ 1872return :: fmin (a, b); 1873} 1874SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_max ( double a, double b) 1875{ 1876return :: fmax (a, b); 1877} 1878SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_pow ( double a, double b) 1879{ 1880return :: pow (a, b); 1881} 1882SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_fmod ( double a, double b) 1883{ 1884return :: fmod (a, b); 1885} 1886SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_remainder ( double a, double b) 1887{ 1888return :: remainder (a, b); 1889} 1890SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_atan2 ( double a, double b) 1891{ 1892return :: atan2 (a, b); 1893} 1894 1895SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_frexp ( double x, int * e) 1896{ 1897return :: frexp (x, e); 1898} 1899 1900SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_modf ( double x, double * ip) 1901{ 1902return :: modf (x, ip); 1903} 1904 1905SLANG_FORCE_INLINE SLANG_CUDA_CALL void F64_asuint ( double d, uint32_t * low, uint32_t * hi) 1906{ 1907Union64 u; 1908u. d = d; 1909* low = uint32_t (u. u ); 1910* hi = uint32_t (u. u >> 32 ); 1911} 1912 1913SLANG_FORCE_INLINE SLANG_CUDA_CALL void F64_asint ( double d, int32_t * low, int32_t * hi) 1914{ 1915Union64 u; 1916u. d = d; 1917* low = int32_t (u. u ); 1918* hi = int32_t (u. u >> 32 ); 1919} 1920 1921// Ternary 1922SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_fma ( double a, double b, double c) 1923{ 1924return :: fma (a, b, c); 1925} 1926 1927// ----------------------------- U8 ----------------------------------------- 1928 1929SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U8_countbits ( uint8_t v) 1930{ 1931// No native 8bit popc yet, just cast and use 32bit variant 1932return __popc ( uint32_t (v)); 1933} 1934 1935// ----------------------------- I8 ----------------------------------------- 1936 1937SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t I8_countbits ( int8_t v) 1938{ 1939return U8_countbits ( uint8_t (v)); 1940} 1941 1942// ----------------------------- U16 ----------------------------------------- 1943 1944SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U16_countbits ( uint16_t v) 1945{ 1946// No native 16bit popc yet, just cast and use 32bit variant 1947return __popc ( uint32_t (v)); 1948} 1949 1950// ----------------------------- I16 ----------------------------------------- 1951 1952SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t I16_countbits ( int16_t v) 1953{ 1954return U16_countbits ( uint16_t (v)); 1955} 1956 1957// ----------------------------- U32 ----------------------------------------- 1958 1959// Unary 1960SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_abs ( uint32_t f) 1961{ 1962return f; 1963} 1964 1965// Binary 1966SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_min ( uint32_t a, uint32_t b) 1967{ 1968return a < b ? a : b; 1969} 1970SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_max ( uint32_t a, uint32_t b) 1971{ 1972return a > b ? a : b; 1973} 1974 1975SLANG_FORCE_INLINE SLANG_CUDA_CALL float U32_asfloat ( uint32_t x) 1976{ 1977Union32 u; 1978u. u = x; 1979return u. f ; 1980} 1981SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_asint ( int32_t x) 1982{ 1983return uint32_t (x); 1984} 1985 1986SLANG_FORCE_INLINE SLANG_CUDA_CALL double U32_asdouble ( uint32_t low, uint32_t hi) 1987{ 1988Union64 u; 1989u. u = ( uint64_t ( hi ) << 32 ) | low; 1990return u. d ; 1991} 1992 1993SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_countbits ( uint32_t v) 1994{ 1995return __popc (v); 1996} 1997 1998SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_firstbitlow ( uint32_t v) 1999{ 2000// __ffs returns 1-based bit position or 0 if no bits set 2001// firstbitlow should return 0-based bit position or ~0u if no bits set 2002return v == 0 ? ~ 0u : ( __ffs (v) - 1 ); 2003} 2004 2005SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_firstbithigh ( uint32_t v) 2006{ 2007// maps to hlsl firstbithigh 2008if (( int32_t )v < 0 ) 2009v = ~v; 2010if (v == 0 ) 2011return ~ 0u ; 2012return 31 - __clz (v); 2013} 2014 2015// ----------------------------- I32 ----------------------------------------- 2016 2017// Unary 2018SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t I32_abs ( int32_t f) 2019{ 2020return (f < 0 ) ? - f : f; 2021} 2022 2023// Binary 2024SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t I32_min ( int32_t a, int32_t b) 2025{ 2026return a < b ? a : b; 2027} 2028SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t I32_max ( int32_t a, int32_t b) 2029{ 2030return a > b ? a : b; 2031} 2032 2033SLANG_FORCE_INLINE SLANG_CUDA_CALL float I32_asfloat ( int32_t x) 2034{ 2035Union32 u; 2036u. i = x; 2037return u. f ; 2038} 2039SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t I32_asuint ( int32_t x) 2040{ 2041return uint32_t (x); 2042} 2043SLANG_FORCE_INLINE SLANG_CUDA_CALL double I32_asdouble ( int32_t low, int32_t hi) 2044{ 2045Union64 u; 2046u. u = ( uint64_t ( hi ) << 32 ) | uint32_t (low); 2047return u. d ; 2048} 2049 2050SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t I32_countbits ( int32_t v) 2051{ 2052return U32_countbits ( uint32_t (v)); 2053} 2054 2055SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t I32_firstbitlow ( int32_t v) 2056{ 2057return U32_firstbitlow ( uint32_t (v)); 2058} 2059 2060SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t I32_firstbithigh ( int32_t v) 2061{ 2062return U32_firstbithigh ( uint32_t (v)); 2063} 2064 2065// ----------------------------- U64 ----------------------------------------- 2066 2067SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t U64_abs ( uint64_t f) 2068{ 2069return f; 2070} 2071 2072SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t U64_min ( uint64_t a, uint64_t b) 2073{ 2074return a < b ? a : b; 2075} 2076SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t U64_max ( uint64_t a, uint64_t b) 2077{ 2078return a > b ? a : b; 2079} 2080 2081SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U64_countbits ( uint64_t v) 2082{ 2083return __popcll (v); 2084} 2085 2086// ----------------------------- I64 ----------------------------------------- 2087 2088SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t I64_abs ( int64_t f) 2089{ 2090return (f < 0 ) ? - f : f; 2091} 2092 2093SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t I64_min ( int64_t a, int64_t b) 2094{ 2095return a < b ? a : b; 2096} 2097SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t I64_max ( int64_t a, int64_t b) 2098{ 2099return a > b ? a : b; 2100} 2101 2102SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t I64_countbits ( int64_t v) 2103{ 2104return U64_countbits ( uint64_t (v)); 2105} 2106 2107// ----------------------------- IPTR ----------------------------------------- 2108 2109SLANG_FORCE_INLINE SLANG_CUDA_CALL intptr_t IPTR_abs ( intptr_t f) 2110{ 2111return (f < 0 ) ? - f : f; 2112} 2113 2114SLANG_FORCE_INLINE SLANG_CUDA_CALL intptr_t IPTR_min ( intptr_t a, intptr_t b) 2115{ 2116return a < b ? a : b; 2117} 2118 2119SLANG_FORCE_INLINE SLANG_CUDA_CALL intptr_t IPTR_max ( intptr_t a, intptr_t b) 2120{ 2121return a > b ? a : b; 2122} 2123 2124// ----------------------------- UPTR ----------------------------------------- 2125 2126SLANG_FORCE_INLINE SLANG_CUDA_CALL uintptr_t UPTR_abs ( uintptr_t f) 2127{ 2128return f; 2129} 2130 2131SLANG_FORCE_INLINE SLANG_CUDA_CALL uintptr_t UPTR_min ( uintptr_t a, uintptr_t b) 2132{ 2133return a < b ? a : b; 2134} 2135 2136SLANG_FORCE_INLINE SLANG_CUDA_CALL uintptr_t UPTR_max ( uintptr_t a, uintptr_t b) 2137{ 2138return a > b ? a : b; 2139} 2140 2141// ----------------------------- ResourceType ----------------------------------------- 2142 2143 2144// https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-object-structuredbuffer-getdimensions 2145// Missing Load(_In_ int Location, _Out_ uint Status); 2146 2147template < typename T > 2148struct StructuredBuffer 2149{ 2150SLANG_CUDA_CALL T & operator[]( size_t index) const 2151{ 2152#ifndef SLANG_CUDA_STRUCTURED_BUFFER_NO_COUNT 2153SLANG_BOUND_CHECK (index, count); 2154#endif 2155return data[index]; 2156} 2157 2158SLANG_CUDA_CALL T & Load ( size_t index) const 2159{ 2160#ifndef SLANG_CUDA_STRUCTURED_BUFFER_NO_COUNT 2161SLANG_BOUND_CHECK (index, count); 2162#endif 2163return data[index]; 2164} 2165 2166#ifndef SLANG_CUDA_STRUCTURED_BUFFER_NO_COUNT 2167SLANG_CUDA_CALL void GetDimensions ( uint32_t * outNumStructs, uint32_t * outStride) const 2168{ 2169* outNumStructs = uint32_t (count); 2170* outStride = uint32_t ( sizeof ( T )); 2171} 2172#endif 2173 2174T * data; 2175#ifndef SLANG_CUDA_STRUCTURED_BUFFER_NO_COUNT 2176size_t count; 2177#endif 2178}; 2179 2180template < typename T > 2181struct RWStructuredBuffer : StructuredBuffer < T > 2182{ 2183SLANG_CUDA_CALL T & operator[]( size_t index) const 2184{ 2185#ifndef SLANG_CUDA_STRUCTURED_BUFFER_NO_COUNT 2186SLANG_BOUND_CHECK (index, this -> count ); 2187#endif 2188return this -> data [index]; 2189} 2190}; 2191 2192// Missing Load(_In_ int Location, _Out_ uint Status); 2193struct ByteAddressBuffer 2194{ 2195SLANG_CUDA_CALL void GetDimensions ( uint32_t * outDim) const { * outDim = uint32_t ( sizeInBytes ); } 2196SLANG_CUDA_CALL uint32_t Load ( size_t index) const 2197{ 2198SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 4 , sizeInBytes); 2199return data[index >> 2 ]; 2200} 2201SLANG_CUDA_CALL uint2 Load2 ( size_t index) const 2202{ 2203SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 8 , sizeInBytes); 2204const size_t dataIdx = index >> 2 ; 2205return uint2{data[dataIdx], data[dataIdx + 1 ]}; 2206} 2207SLANG_CUDA_CALL uint3 Load3 ( size_t index) const 2208{ 2209SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 12 , sizeInBytes); 2210const size_t dataIdx = index >> 2 ; 2211return uint3{data[dataIdx], data[dataIdx + 1 ], data[dataIdx + 2 ]}; 2212} 2213SLANG_CUDA_CALL uint4 Load4 ( size_t index) const 2214{ 2215SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 16 , sizeInBytes); 2216const size_t dataIdx = index >> 2 ; 2217return uint4{data[dataIdx], data[dataIdx + 1 ], data[dataIdx + 2 ], data[dataIdx + 3 ]}; 2218} 2219template < typename T > 2220SLANG_CUDA_CALL T Load ( size_t index) const 2221{ 2222SLANG_BOUND_CHECK_BYTE_ADDRESS (index, sizeof ( T ), sizeInBytes); 2223T data; 2224memcpy ( & data, (( const char * )this -> data ) + index, sizeof ( T )); 2225return data; 2226} 2227template < typename T > 2228SLANG_CUDA_CALL StructuredBuffer < T > asStructuredBuffer () const 2229{ 2230StructuredBuffer < T > rs; 2231rs. data = ( T * )data; 2232rs. count = sizeInBytes / sizeof ( T ); 2233return rs; 2234} 2235const uint32_t * data; 2236size_t sizeInBytes; //< Must be multiple of 4 2237}; 2238 2239// https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-object-rwbyteaddressbuffer 2240// Atomic operations support 2241 2242// Signed 64-bit atomic wrappers 2243// CUDA only supports unsigned long long atomics, so we cast signed to unsigned 2244__device__ __forceinline__ long long atomicExch ( long long * address, long long val) 2245{ 2246return ( long long ) atomicExch (( unsigned long long * )address, ( unsigned long long )val); 2247} 2248 2249__device__ __forceinline__ long long atomicCAS ( long long * address, long long compare, long long val) 2250{ 2251return ( long long ) atomicCAS ( 2252( unsigned long long * )address, 2253( unsigned long long )compare, 2254( unsigned long long )val); 2255} 2256 2257// Float bitwise atomic compare-and-swap 2258// Uses integer atomics to preserve exact float bit patterns 2259__device__ __forceinline__ float atomicCAS ( float * address, float compare, float val) 2260{ 2261int * addr_as_int = ( int * )address; 2262int old = atomicCAS (addr_as_int, __float_as_int (compare), __float_as_int (val)); 2263return __int_as_float (old); 2264} 2265 2266// Missing support for Load with status 2267struct RWByteAddressBuffer 2268{ 2269SLANG_CUDA_CALL void GetDimensions ( uint32_t * outDim) const { * outDim = uint32_t ( sizeInBytes ); } 2270 2271SLANG_CUDA_CALL uint32_t Load ( size_t index) const 2272{ 2273SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 4 , sizeInBytes); 2274return data[index >> 2 ]; 2275} 2276SLANG_CUDA_CALL uint2 Load2 ( size_t index) const 2277{ 2278SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 8 , sizeInBytes); 2279const size_t dataIdx = index >> 2 ; 2280return uint2{data[dataIdx], data[dataIdx + 1 ]}; 2281} 2282SLANG_CUDA_CALL uint3 Load3 ( size_t index) const 2283{ 2284SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 12 , sizeInBytes); 2285const size_t dataIdx = index >> 2 ; 2286return uint3{data[dataIdx], data[dataIdx + 1 ], data[dataIdx + 2 ]}; 2287} 2288SLANG_CUDA_CALL uint4 Load4 ( size_t index) const 2289{ 2290SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 16 , sizeInBytes); 2291const size_t dataIdx = index >> 2 ; 2292return uint4{data[dataIdx], data[dataIdx + 1 ], data[dataIdx + 2 ], data[dataIdx + 3 ]}; 2293} 2294template < typename T > 2295SLANG_CUDA_CALL T Load ( size_t index) const 2296{ 2297SLANG_BOUND_CHECK_BYTE_ADDRESS (index, sizeof ( T ), sizeInBytes); 2298T data; 2299memcpy ( & data, (( const char * )this -> data ) + index, sizeof ( T )); 2300return data; 2301} 2302 2303SLANG_CUDA_CALL void Store ( size_t index, uint32_t v) const 2304{ 2305SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 4 , sizeInBytes); 2306data[index >> 2 ] = v; 2307} 2308SLANG_CUDA_CALL void Store2 ( size_t index, uint2 v) const 2309{ 2310SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 8 , sizeInBytes); 2311const size_t dataIdx = index >> 2 ; 2312data[dataIdx + 0 ] = v. x ; 2313data[dataIdx + 1 ] = v. y ; 2314} 2315SLANG_CUDA_CALL void Store3 ( size_t index, uint3 v) const 2316{ 2317SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 12 , sizeInBytes); 2318const size_t dataIdx = index >> 2 ; 2319data[dataIdx + 0 ] = v. x ; 2320data[dataIdx + 1 ] = v. y ; 2321data[dataIdx + 2 ] = v. z ; 2322} 2323SLANG_CUDA_CALL void Store4 ( size_t index, uint4 v) const 2324{ 2325SLANG_BOUND_CHECK_BYTE_ADDRESS (index, 16 , sizeInBytes); 2326const size_t dataIdx = index >> 2 ; 2327data[dataIdx + 0 ] = v. x ; 2328data[dataIdx + 1 ] = v. y ; 2329data[dataIdx + 2 ] = v. z ; 2330data[dataIdx + 3 ] = v. w ; 2331} 2332template < typename T > 2333SLANG_CUDA_CALL void Store ( size_t index, T const & value) const 2334{ 2335SLANG_BOUND_CHECK_BYTE_ADDRESS (index, sizeof ( T ), sizeInBytes); 2336memcpy (( char * )data + index, & value, sizeof ( T )); 2337} 2338 2339/// Can be used in the core module to gain access 2340template < typename T > 2341SLANG_CUDA_CALL T * _getPtrAt ( size_t index) 2342{ 2343SLANG_BOUND_CHECK_BYTE_ADDRESS (index, sizeof ( T ), sizeInBytes); 2344return ( T * )((( char * )data) + index); 2345} 2346template < typename T > 2347SLANG_CUDA_CALL RWStructuredBuffer < T > asStructuredBuffer () const 2348{ 2349RWStructuredBuffer < T > rs; 2350rs. data = ( T * )data; 2351rs. count = sizeInBytes / sizeof ( T ); 2352return rs; 2353} 2354uint32_t * data; 2355size_t sizeInBytes; //< Must be multiple of 4 2356}; 2357 2358 2359// ---------------------- Wave -------------------------------------- 2360 2361// TODO(JS): It appears that cuda does not have a simple way to get a lane index. 2362// 2363// Another approach could be... 2364// laneId = ((threadIdx.z * blockDim.y + threadIdx.y) * blockDim.x + threadIdx.x) & 2365// SLANG_CUDA_WARP_MASK If that is really true another way to do this, would be for code generator 2366// to add this function with the [numthreads] baked in. 2367// 2368// For now I'll just assume you have a launch that makes the following correct if the kernel uses 2369// WaveGetLaneIndex() 2370#ifndef SLANG_USE_ASM_LANE_ID 2371__forceinline__ __device__ uint32_t _getLaneId () 2372{ 2373// If the launch is (or I guess some multiple of the warp size) 2374// we try this mechanism, which is apparently faster. 2375return threadIdx. x & SLANG_CUDA_WARP_MASK ; 2376} 2377#else 2378__forceinline__ __device__ uint32_t _getLaneId () 2379{ 2380// https://stackoverflow.com/questions/44337309/whats-the-most-efficient-way-to-calculate-the-warp-id-lane-id-in-a-1-d-grid# 2381// This mechanism is not the fastest way to do it, and that is why the other mechanism 2382// is the default. But the other mechanism relies on a launch that makes the assumption 2383// true. 2384unsigned ret; 2385asm volatile ( "mov.u32 %0, %laneid;" : "=r" (ret)); 2386return ret; 2387} 2388#endif 2389 2390typedef int WarpMask ; 2391 2392// It appears that the __activemask() cannot always be used because 2393// threads need to be converged. 2394// 2395// For CUDA the article claims mask has to be used carefully 2396// https://devblogs.nvidia.com/using-cuda-warp-level-primitives/ 2397// With the Warp intrinsics there is no mask, and it's just the 'active lanes'. 2398// __activemask() though does not require there is convergence, so that doesn't work. 2399// 2400// '__ballot_sync' produces a convergance. 2401// 2402// From the CUDA docs: 2403// ```For __all_sync, __any_sync, and __ballot_sync, a mask must be passed that specifies the 2404// threads participating in the call. A bit, representing the thread's lane ID, must be set for each 2405// participating thread to ensure they are properly converged before the intrinsic is executed by 2406// the hardware. All active threads named in mask must execute the same intrinsic with the same 2407// mask, or the result is undefined.``` 2408// 2409// Currently there isn't a mechanism to correctly get the mask without it being passed through. 2410// Doing so will most likely require some changes to slang code generation to track masks, for now 2411// then we use _getActiveMask. 2412 2413// Return mask of all the lanes less than the current lane 2414__forceinline__ __device__ WarpMask _getLaneLtMask () 2415{ 2416return ( int ( 1 ) << _getLaneId ()) - 1 ; 2417} 2418 2419// TODO(JS): 2420// THIS IS NOT CORRECT! That determining the appropriate active mask requires appropriate 2421// mask tracking. 2422__forceinline__ __device__ WarpMask _getActiveMask () 2423{ 2424return __ballot_sync ( __activemask (), true); 2425} 2426 2427// Return a mask suitable for the 'MultiPrefix' style functions 2428__forceinline__ __device__ WarpMask _getMultiPrefixMask ( int mask) 2429{ 2430return mask; 2431} 2432 2433// Note! Note will return true if mask is 0, but thats okay, because there must be one 2434// lane active to execute anything 2435__inline__ __device__ bool _waveIsSingleLane ( WarpMask mask) 2436{ 2437return (mask & (mask - 1 )) == 0 ; 2438} 2439 2440// Returns the power of 2 size of run of set bits. Returns 0 if not a suitable run. 2441// Examples: 2442// 0b00000000'00000000'00000000'11111111 -> 8 2443// 0b11111111'11111111'11111111'11111111 -> 32 2444// 0b00000000'00000000'00000000'00011111 -> 0 (since 5 is not a power of 2) 2445// 0b00000000'00000000'00000000'11110000 -> 0 (since the run of bits does not start at the LSB) 2446// 0b00000000'00000000'00000000'00100111 -> 0 (since it is not a single contiguous run) 2447__inline__ __device__ int _waveCalcPow2Offset ( WarpMask mask) 2448{ 2449// This should be the most common case, so fast path it 2450if (mask == SLANG_CUDA_WARP_BITMASK ) 2451{ 2452return SLANG_CUDA_WARP_SIZE ; 2453} 2454// Is it a contiguous run of bits? 2455if ((mask & (mask + 1 )) == 0 ) 2456{ 2457// const int offsetSize = __ffs(mask + 1) - 1; 2458const int offset = 32 - __clz (mask); 2459// Is it a power of 2 size 2460if ((offset & (offset - 1 )) == 0 ) 2461{ 2462return offset; 2463} 2464} 2465return 0 ; 2466} 2467 2468__inline__ __device__ bool _waveIsFirstLane () 2469{ 2470const WarpMask mask = __activemask (); 2471// We special case bit 0, as that most warps are expected to be fully active. 2472 2473// mask & -mask, isolates the lowest set bit. 2474// return (mask & 1 ) || ((mask & -mask) == (1 << _getLaneId())); 2475 2476// This mechanism is most similar to what was in an nVidia post, so assume it is prefered. 2477return (mask & 1 ) || (( __ffs (mask) - 1 ) == _getLaneId ()); 2478} 2479 2480template < typename T > 2481struct WaveOpOr 2482{ 2483__inline__ __device__ static T getInitial ( T a) { return 0 ; } 2484__inline__ __device__ static T doOp ( T a, T b) { return a | b; } 2485}; 2486 2487template < typename T > 2488struct WaveOpAnd 2489{ 2490__inline__ __device__ static T getInitial ( T a) { return ~ T ( 0 ); } 2491__inline__ __device__ static T doOp ( T a, T b) { return a & b; } 2492}; 2493 2494template < typename T > 2495struct WaveOpXor 2496{ 2497__inline__ __device__ static T getInitial ( T a) { return 0 ; } 2498__inline__ __device__ static T doOp ( T a, T b) { return a ^ b; } 2499__inline__ __device__ static T doInverse ( T a, T b) { return a ^ b; } 2500}; 2501 2502template < typename T > 2503struct WaveOpAdd 2504{ 2505__inline__ __device__ static T getInitial ( T a) { return 0 ; } 2506__inline__ __device__ static T doOp ( T a, T b) { return a + b; } 2507__inline__ __device__ static T doInverse ( T a, T b) { return a - b; } 2508}; 2509 2510template < typename T > 2511struct WaveOpMul 2512{ 2513__inline__ __device__ static T getInitial ( T a) { return T ( 1 ); } 2514__inline__ __device__ static T doOp ( T a, T b) { return a * b; } 2515// Using this inverse for int is probably undesirable - because in general it requires T to have 2516// more precision There is also a performance aspect to it, where divides are generally 2517// significantly slower 2518__inline__ __device__ static T doInverse ( T a, T b) { return a / b; } 2519}; 2520 2521template < typename T > 2522struct WaveOpMax 2523{ 2524__inline__ __device__ static T getInitial ( T a, bool exclusive = false); 2525__inline__ __device__ static T doOp ( T a, T b) { return a > b ? a : b; } 2526}; 2527 2528template < typename T > 2529struct WaveOpMin 2530{ 2531__inline__ __device__ static T getInitial ( T a, bool exclusive = false); 2532__inline__ __device__ static T doOp ( T a, T b) { return a < b ? a : b; } 2533}; 2534 2535// Compact specializations using macro for getInitial 2536#define SLANG_WAVE_MIN_SPEC ( T , EXCL_VAL ) \ 2537template<> \ 2538__inline__ __device__ T WaveOpMin<T>::getInitial(T a, bool exclusive) \ 2539{ \ 2540return exclusive ? (EXCL_VAL) : a; \ 2541} 2542 2543#define SLANG_WAVE_MAX_SPEC ( T , EXCL_VAL ) \ 2544template<> \ 2545__inline__ __device__ T WaveOpMax<T>::getInitial(T a, bool exclusive) \ 2546{ \ 2547return exclusive ? (EXCL_VAL) : a; \ 2548} 2549 2550// Min specializations (exclusive identity = max value) 2551SLANG_WAVE_MIN_SPEC (float, SLANG_INFINITY ) 2552SLANG_WAVE_MIN_SPEC (double, SLANG_INFINITY ) 2553SLANG_WAVE_MIN_SPEC (int, 0x7FFFFFFF ) 2554SLANG_WAVE_MIN_SPEC (uint, 0xFFFFFFFF ) 2555SLANG_WAVE_MIN_SPEC (char, ( char ) 0x7F ) 2556SLANG_WAVE_MIN_SPEC (int8_t, ( int8_t ) 0x7F ) 2557SLANG_WAVE_MIN_SPEC (uint8_t, ( uint8_t ) 0xFF ) 2558SLANG_WAVE_MIN_SPEC (int16_t, ( int16_t ) 0x7FFF ) 2559SLANG_WAVE_MIN_SPEC (uint16_t, ( uint16_t ) 0xFFFF ) 2560SLANG_WAVE_MIN_SPEC (int64_t, 0x7FFFFFFFFFFFFFFFLL ) 2561SLANG_WAVE_MIN_SPEC (uint64_t, 0xFFFFFFFFFFFFFFFFULL ) 2562#if SLANG_CUDA_ENABLE_HALF 2563SLANG_WAVE_MIN_SPEC (__half, __ushort_as_half ( 0x7BFF )) 2564#endif 2565 2566// Max specializations (exclusive identity = min value) 2567SLANG_WAVE_MAX_SPEC (float, - SLANG_INFINITY ) 2568SLANG_WAVE_MAX_SPEC (double, - SLANG_INFINITY ) 2569SLANG_WAVE_MAX_SPEC (int, ( int ) 0x80000000 ) 2570SLANG_WAVE_MAX_SPEC (uint, 0 ) 2571SLANG_WAVE_MAX_SPEC (char, ( char ) 0x80 ) 2572SLANG_WAVE_MAX_SPEC (int8_t, ( int8_t ) 0x80 ) 2573SLANG_WAVE_MAX_SPEC (uint8_t, 0 ) 2574SLANG_WAVE_MAX_SPEC (int16_t, ( int16_t ) 0x8000 ) 2575SLANG_WAVE_MAX_SPEC (uint16_t, 0 ) 2576SLANG_WAVE_MAX_SPEC (int64_t, ( int64_t ) 0x8000000000000000LL ) 2577SLANG_WAVE_MAX_SPEC (uint64_t, 0 ) 2578#if SLANG_CUDA_ENABLE_HALF 2579SLANG_WAVE_MAX_SPEC (__half, __ushort_as_half ( 0xFBFF )) 2580#endif 2581 2582#undef SLANG_WAVE_MIN_SPEC 2583#undef SLANG_WAVE_MAX_SPEC 2584 2585template < typename T > 2586struct ElementTypeTrait; 2587 2588// Scalar 2589template <> 2590struct ElementTypeTrait < int > 2591{ 2592typedef int Type ; 2593}; 2594template <> 2595struct ElementTypeTrait < uint > 2596{ 2597typedef uint Type ; 2598}; 2599template <> 2600struct ElementTypeTrait < float > 2601{ 2602typedef float Type ; 2603}; 2604template <> 2605struct ElementTypeTrait < double > 2606{ 2607typedef double Type ; 2608}; 2609template <> 2610struct ElementTypeTrait < uint64_t > 2611{ 2612typedef uint64_t Type ; 2613}; 2614template <> 2615struct ElementTypeTrait < int64_t > 2616{ 2617typedef int64_t Type ; 2618}; 2619template <> 2620struct ElementTypeTrait < char > 2621{ 2622typedef char Type ; 2623}; 2624template <> 2625struct ElementTypeTrait < uchar > 2626{ 2627typedef uchar Type ; 2628}; 2629template <> 2630struct ElementTypeTrait < short > 2631{ 2632typedef short Type ; 2633}; 2634template <> 2635struct ElementTypeTrait < ushort > 2636{ 2637typedef ushort Type ; 2638}; 2639#if SLANG_CUDA_ENABLE_HALF 2640template <> 2641struct ElementTypeTrait < __half > 2642{ 2643typedef __half Type ; 2644}; 2645#endif 2646 2647// Vector 2648template <> 2649struct ElementTypeTrait < int1 > 2650{ 2651typedef int Type ; 2652}; 2653template <> 2654struct ElementTypeTrait < int2 > 2655{ 2656typedef int Type ; 2657}; 2658template <> 2659struct ElementTypeTrait < int3 > 2660{ 2661typedef int Type ; 2662}; 2663template <> 2664struct ElementTypeTrait < int4 > 2665{ 2666typedef int Type ; 2667}; 2668 2669template <> 2670struct ElementTypeTrait < uint1 > 2671{ 2672typedef uint Type ; 2673}; 2674template <> 2675struct ElementTypeTrait < uint2 > 2676{ 2677typedef uint Type ; 2678}; 2679template <> 2680struct ElementTypeTrait < uint3 > 2681{ 2682typedef uint Type ; 2683}; 2684template <> 2685struct ElementTypeTrait < uint4 > 2686{ 2687typedef uint Type ; 2688}; 2689 2690template <> 2691struct ElementTypeTrait < float1 > 2692{ 2693typedef float Type ; 2694}; 2695template <> 2696struct ElementTypeTrait < float2 > 2697{ 2698typedef float Type ; 2699}; 2700template <> 2701struct ElementTypeTrait < float3 > 2702{ 2703typedef float Type ; 2704}; 2705template <> 2706struct ElementTypeTrait < float4 > 2707{ 2708typedef float Type ; 2709}; 2710 2711template <> 2712struct ElementTypeTrait < double1 > 2713{ 2714typedef double Type ; 2715}; 2716template <> 2717struct ElementTypeTrait < double2 > 2718{ 2719typedef double Type ; 2720}; 2721template <> 2722struct ElementTypeTrait < double3 > 2723{ 2724typedef double Type ; 2725}; 2726template <> 2727struct ElementTypeTrait < double4 > 2728{ 2729typedef double Type ; 2730}; 2731 2732// Additional vector types 2733template <> 2734struct ElementTypeTrait < char2 > 2735{ 2736typedef char Type ; 2737}; 2738template <> 2739struct ElementTypeTrait < char3 > 2740{ 2741typedef char Type ; 2742}; 2743template <> 2744struct ElementTypeTrait < char4 > 2745{ 2746typedef char Type ; 2747}; 2748template <> 2749struct ElementTypeTrait < uchar2 > 2750{ 2751typedef uchar Type ; 2752}; 2753template <> 2754struct ElementTypeTrait < uchar3 > 2755{ 2756typedef uchar Type ; 2757}; 2758template <> 2759struct ElementTypeTrait < uchar4 > 2760{ 2761typedef uchar Type ; 2762}; 2763template <> 2764struct ElementTypeTrait < short2 > 2765{ 2766typedef short Type ; 2767}; 2768template <> 2769struct ElementTypeTrait < short3 > 2770{ 2771typedef short Type ; 2772}; 2773template <> 2774struct ElementTypeTrait < short4 > 2775{ 2776typedef short Type ; 2777}; 2778template <> 2779struct ElementTypeTrait < ushort2 > 2780{ 2781typedef ushort Type ; 2782}; 2783template <> 2784struct ElementTypeTrait < ushort3 > 2785{ 2786typedef ushort Type ; 2787}; 2788template <> 2789struct ElementTypeTrait < ushort4 > 2790{ 2791typedef ushort Type ; 2792}; 2793template <> 2794struct ElementTypeTrait < longlong2 > 2795{ 2796typedef int64_t Type ; 2797}; 2798template <> 2799struct ElementTypeTrait < longlong3 > 2800{ 2801typedef int64_t Type ; 2802}; 2803template <> 2804struct ElementTypeTrait < longlong4 > 2805{ 2806typedef int64_t Type ; 2807}; 2808template <> 2809struct ElementTypeTrait < ulonglong2 > 2810{ 2811typedef uint64_t Type ; 2812}; 2813template <> 2814struct ElementTypeTrait < ulonglong3 > 2815{ 2816typedef uint64_t Type ; 2817}; 2818template <> 2819struct ElementTypeTrait < ulonglong4 > 2820{ 2821typedef uint64_t Type ; 2822}; 2823#if SLANG_CUDA_ENABLE_HALF 2824template <> 2825struct ElementTypeTrait < __half2 > 2826{ 2827typedef __half Type ; 2828}; 2829template <> 2830struct ElementTypeTrait < __half3 > 2831{ 2832typedef __half Type ; 2833}; 2834template <> 2835struct ElementTypeTrait < __half4 > 2836{ 2837typedef __half Type ; 2838}; 2839#endif 2840 2841// Matrix 2842template < typename T , int ROWS , int COLS > 2843struct ElementTypeTrait < Matrix < T , ROWS , COLS >> 2844{ 2845typedef T Type; 2846}; 2847 2848// Scalar 2849template < typename INTF , typename T > 2850__device__ T _waveReduceScalar ( WarpMask mask, T val) 2851{ 2852const int offsetSize = _waveCalcPow2Offset (mask); 2853if (offsetSize > 0 ) 2854{ 2855// Fast path O(log2(activeLanes)) 2856for ( int offset = offsetSize >> 1 ; offset > 0 ; offset >>= 1 ) 2857{ 2858val = INTF :: doOp (val, __shfl_xor_sync (mask, val, offset)); 2859} 2860} 2861else if (! _waveIsSingleLane (mask)) 2862{ 2863T result = INTF :: getInitial (val); 2864int remaining = mask; 2865while (remaining) 2866{ 2867const int laneBit = remaining & - remaining; 2868// Get the sourceLane 2869const int srcLane = __ffs (laneBit) - 1 ; 2870// Broadcast (can also broadcast to self) 2871result = INTF :: doOp (result, __shfl_sync (mask, val, srcLane)); 2872remaining &= ~laneBit; 2873} 2874return result; 2875} 2876return val; 2877} 2878 2879 2880// Multiple values 2881template < typename INTF , typename T , size_t COUNT > 2882__device__ void _waveReduceMultiple ( WarpMask mask, T * val) 2883{ 2884const int offsetSize = _waveCalcPow2Offset (mask); 2885if (offsetSize > 0 ) 2886{ 2887// Fast path O(log2(activeLanes)) 2888for ( int offset = offsetSize >> 1 ; offset > 0 ; offset >>= 1 ) 2889{ 2890for ( size_t i = 0 ; i < COUNT ; ++ i) 2891{ 2892val[i] = INTF :: doOp (val[i], __shfl_xor_sync (mask, val[i], offset)); 2893} 2894} 2895} 2896else if (! _waveIsSingleLane (mask)) 2897{ 2898// Copy the original 2899T originalVal[ COUNT ]; 2900for ( size_t i = 0 ; i < COUNT ; ++ i) 2901{ 2902const T v = val[i]; 2903originalVal[i] = v; 2904val[i] = INTF :: getInitial (v); 2905} 2906 2907int remaining = mask; 2908while (remaining) 2909{ 2910const int laneBit = remaining & - remaining; 2911// Get the sourceLane 2912const int srcLane = __ffs (laneBit) - 1 ; 2913// Broadcast (can also broadcast to self) 2914for ( size_t i = 0 ; i < COUNT ; ++ i) 2915{ 2916val[i] = INTF :: doOp (val[i], __shfl_sync (mask, originalVal[i], srcLane)); 2917} 2918remaining &= ~laneBit; 2919} 2920} 2921} 2922 2923template < typename INTF , typename T > 2924__device__ void _waveReduceMultiple ( WarpMask mask, T * val) 2925{ 2926typedef typename ElementTypeTrait < T > ::Type ElemType; 2927_waveReduceMultiple < INTF , ElemType, sizeof ( T ) / sizeof (ElemType) > (mask, ( ElemType * )val); 2928} 2929 2930template < typename T > 2931__inline__ __device__ T _waveOr ( WarpMask mask, T val) 2932{ 2933return _waveReduceScalar < WaveOpOr < T > , T > (mask, val); 2934} 2935 2936template < typename T > 2937__inline__ __device__ T _waveAnd ( WarpMask mask, T val) 2938{ 2939return _waveReduceScalar < WaveOpAnd < T > , T > (mask, val); 2940} 2941 2942template < typename T > 2943__inline__ __device__ T _waveXor ( WarpMask mask, T val) 2944{ 2945return _waveReduceScalar < WaveOpXor < T > , T > (mask, val); 2946} 2947 2948template < typename T > 2949__inline__ __device__ T _waveProduct ( WarpMask mask, T val) 2950{ 2951return _waveReduceScalar < WaveOpMul < T > , T > (mask, val); 2952} 2953 2954template < typename T > 2955__inline__ __device__ T _waveSum ( WarpMask mask, T val) 2956{ 2957return _waveReduceScalar < WaveOpAdd < T > , T > (mask, val); 2958} 2959 2960template < typename T > 2961__inline__ __device__ T _waveMin ( WarpMask mask, T val) 2962{ 2963return _waveReduceScalar < WaveOpMin < T > , T > (mask, val); 2964} 2965 2966template < typename T > 2967__inline__ __device__ T _waveMax ( WarpMask mask, T val) 2968{ 2969return _waveReduceScalar < WaveOpMax < T > , T > (mask, val); 2970} 2971 2972// Fast-path specializations when CUDA warp reduce operators are available 2973#if __CUDA_ARCH__ >= 800 // 8.x or higher 2974template <> 2975__inline__ __device__ unsigned _waveOr < unsigned > (WarpMask mask, unsigned val) 2976{ 2977return __reduce_or_sync (mask, val); 2978} 2979 2980template <> 2981__inline__ __device__ unsigned _waveAnd < unsigned > (WarpMask mask, unsigned val) 2982{ 2983return __reduce_and_sync (mask, val); 2984} 2985 2986template <> 2987__inline__ __device__ unsigned _waveXor < unsigned > (WarpMask mask, unsigned val) 2988{ 2989return __reduce_xor_sync (mask, val); 2990} 2991 2992template <> 2993__inline__ __device__ unsigned _waveSum < unsigned > (WarpMask mask, unsigned val) 2994{ 2995return __reduce_add_sync (mask, val); 2996} 2997 2998template <> 2999__inline__ __device__ int _waveSum < int > (WarpMask mask, int val) 3000{ 3001return __reduce_add_sync (mask, val); 3002} 3003 3004template <> 3005__inline__ __device__ unsigned _waveMin < unsigned > (WarpMask mask, unsigned val) 3006{ 3007return __reduce_min_sync (mask, val); 3008} 3009 3010template <> 3011__inline__ __device__ int _waveMin < int > (WarpMask mask, int val) 3012{ 3013return __reduce_min_sync (mask, val); 3014} 3015 3016template <> 3017__inline__ __device__ unsigned _waveMax < unsigned > (WarpMask mask, unsigned val) 3018{ 3019return __reduce_max_sync (mask, val); 3020} 3021 3022template <> 3023__inline__ __device__ int _waveMax < int > (WarpMask mask, int val) 3024{ 3025return __reduce_max_sync (mask, val); 3026} 3027#endif 3028 3029 3030// Multiple 3031 3032template < typename T > 3033__inline__ __device__ T _waveOrMultiple ( WarpMask mask, T val) 3034{ 3035typedef typename ElementTypeTrait < T > ::Type ElemType; 3036_waveReduceMultiple < WaveOpOr < ElemType>>(mask, & val); 3037return val; 3038} 3039 3040template < typename T > 3041__inline__ __device__ T _waveAndMultiple ( WarpMask mask, T val) 3042{ 3043typedef typename ElementTypeTrait < T > ::Type ElemType; 3044_waveReduceMultiple < WaveOpAnd < ElemType>>(mask, & val); 3045return val; 3046} 3047 3048template < typename T > 3049__inline__ __device__ T _waveXorMultiple ( WarpMask mask, T val) 3050{ 3051typedef typename ElementTypeTrait < T > ::Type ElemType; 3052_waveReduceMultiple < WaveOpXor < ElemType>>(mask, & val); 3053return val; 3054} 3055 3056template < typename T > 3057__inline__ __device__ T _waveProductMultiple ( WarpMask mask, T val) 3058{ 3059typedef typename ElementTypeTrait < T > ::Type ElemType; 3060_waveReduceMultiple < WaveOpMul < ElemType>>(mask, & val); 3061return val; 3062} 3063 3064template < typename T > 3065__inline__ __device__ T _waveSumMultiple ( WarpMask mask, T val) 3066{ 3067typedef typename ElementTypeTrait < T > ::Type ElemType; 3068_waveReduceMultiple < WaveOpAdd < ElemType>>(mask, & val); 3069return val; 3070} 3071 3072template < typename T > 3073__inline__ __device__ T _waveMinMultiple ( WarpMask mask, T val) 3074{ 3075typedef typename ElementTypeTrait < T > ::Type ElemType; 3076_waveReduceMultiple < WaveOpMin < ElemType>>(mask, & val); 3077return val; 3078} 3079 3080template < typename T > 3081__inline__ __device__ T _waveMaxMultiple ( WarpMask mask, T val) 3082{ 3083typedef typename ElementTypeTrait < T > ::Type ElemType; 3084_waveReduceMultiple < WaveOpMax < ElemType>>(mask, & val); 3085return val; 3086} 3087 3088 3089template < typename T > 3090__inline__ __device__ bool _waveAllEqual ( WarpMask mask, T val) 3091{ 3092int pred; 3093__match_all_sync (mask, val, & pred); 3094return pred != 0 ; 3095} 3096 3097template < typename T > 3098__inline__ __device__ bool _waveAllEqualMultiple ( WarpMask mask, T inVal) 3099{ 3100typedef typename ElementTypeTrait < T > ::Type ElemType; 3101const size_t count = sizeof ( T ) / sizeof (ElemType); 3102int pred; 3103const ElemType * src = ( const ElemType * ) & inVal; 3104for ( size_t i = 0 ; i < count; ++ i) 3105{ 3106__match_all_sync (mask, src[i], & pred); 3107if (pred == 0 ) 3108{ 3109return false; 3110} 3111} 3112return true; 3113} 3114 3115template < typename T > 3116__inline__ __device__ T _waveReadFirst ( WarpMask mask, T val) 3117{ 3118const int lowestLaneId = __ffs (mask) - 1 ; 3119return __shfl_sync (mask, val, lowestLaneId); 3120} 3121 3122template < typename T > 3123__inline__ __device__ T _waveReadFirstMultiple ( WarpMask mask, T inVal) 3124{ 3125typedef typename ElementTypeTrait < T > ::Type ElemType; 3126const size_t count = sizeof ( T ) / sizeof (ElemType); 3127T outVal; 3128const ElemType * src = ( const ElemType * ) & inVal; 3129ElemType * dst = ( ElemType * ) & outVal; 3130const int lowestLaneId = __ffs (mask) - 1 ; 3131for ( size_t i = 0 ; i < count; ++ i) 3132{ 3133dst[i] = __shfl_sync (mask, src[i], lowestLaneId); 3134} 3135return outVal; 3136} 3137 3138template < typename T > 3139__inline__ __device__ T _waveShuffleMultiple ( WarpMask mask, T inVal, int lane) 3140{ 3141typedef typename ElementTypeTrait < T > ::Type ElemType; 3142const size_t count = sizeof ( T ) / sizeof (ElemType); 3143T outVal; 3144const ElemType * src = ( const ElemType * ) & inVal; 3145ElemType * dst = ( ElemType * ) & outVal; 3146for ( size_t i = 0 ; i < count; ++ i) 3147{ 3148dst[i] = __shfl_sync (mask, src[i], lane); 3149} 3150return outVal; 3151} 3152 3153// Scalar 3154 3155// Invertable means that when we get to the end of the reduce, we can remove val (to make 3156// exclusive), using the inverse of the op. 3157template < typename INTF , typename T > 3158__device__ T _wavePrefixInvertableScalar ( WarpMask mask, T val) 3159{ 3160const int offsetSize = _waveCalcPow2Offset (mask); 3161 3162const int laneId = _getLaneId (); 3163T result; 3164if (offsetSize > 0 ) 3165{ 3166// Sum is calculated inclusive of this lanes value 3167result = val; 3168for ( int i = 1 ; i < offsetSize; i += i) 3169{ 3170const T readVal = __shfl_up_sync (mask, result, i, offsetSize); 3171if (laneId >= i) 3172{ 3173result = INTF :: doOp (result, readVal); 3174} 3175} 3176// Remove val from the result, by applyin inverse 3177result = INTF :: doInverse (result, val); 3178} 3179else 3180{ 3181result = INTF :: getInitial (val); 3182if (! _waveIsSingleLane (mask)) 3183{ 3184int remaining = mask; 3185while (remaining) 3186{ 3187const int laneBit = remaining & - remaining; 3188// Get the sourceLane 3189const int srcLane = __ffs (laneBit) - 1 ; 3190// Broadcast (can also broadcast to self) 3191const T readValue = __shfl_sync (mask, val, srcLane); 3192// Only accumulate if srcLane is less than this lane 3193if (srcLane < laneId) 3194{ 3195result = INTF :: doOp (result, readValue); 3196} 3197remaining &= ~laneBit; 3198} 3199} 3200} 3201return result; 3202} 3203 3204 3205// This implementation separately tracks the value to be propogated, and the value 3206// that is the final result 3207template < typename INTF , typename T > 3208__device__ T _wavePrefixScalar ( WarpMask mask, T val) 3209{ 3210const int offsetSize = _waveCalcPow2Offset (mask); 3211 3212const int laneId = _getLaneId (); 3213T result = INTF :: getInitial (val); 3214if (offsetSize > 0 ) 3215{ 3216// For transmitted value we will do it inclusively with this lanes value 3217// For the result we do not include the lanes value. This means an extra multiply for each 3218// iteration but means we don't need to have a divide at the end and also removes overflow 3219// issues in that scenario. 3220for ( int i = 1 ; i < offsetSize; i += i) 3221{ 3222const T readVal = __shfl_up_sync (mask, val, i, offsetSize); 3223if (laneId >= i) 3224{ 3225result = INTF :: doOp (result, readVal); 3226val = INTF :: doOp (val, readVal); 3227} 3228} 3229} 3230else 3231{ 3232if (! _waveIsSingleLane (mask)) 3233{ 3234int remaining = mask; 3235while (remaining) 3236{ 3237const int laneBit = remaining & - remaining; 3238// Get the sourceLane 3239const int srcLane = __ffs (laneBit) - 1 ; 3240// Broadcast (can also broadcast to self) 3241const T readValue = __shfl_sync (mask, val, srcLane); 3242// Only accumulate if srcLane is less than this lane 3243if (srcLane < laneId) 3244{ 3245result = INTF :: doOp (result, readValue); 3246} 3247remaining &= ~laneBit; 3248} 3249} 3250} 3251return result; 3252} 3253 3254 3255template < typename INTF , typename T , size_t COUNT > 3256__device__ T _waveOpCopy ( T * dst, const T * src) 3257{ 3258for ( size_t j = 0 ; j < COUNT ; ++ j) 3259{ 3260dst[j] = src[j]; 3261} 3262} 3263 3264 3265template < typename INTF , typename T , size_t COUNT > 3266__device__ T _waveOpDoInverse ( T * inOut, const T * val) 3267{ 3268for ( size_t j = 0 ; j < COUNT ; ++ j) 3269{ 3270inOut[j] = INTF :: doInverse (inOut[j], val[j]); 3271} 3272} 3273 3274template < typename INTF , typename T , size_t COUNT > 3275__device__ T _waveOpSetInitial ( T * out, const T * val) 3276{ 3277for ( size_t j = 0 ; j < COUNT ; ++ j) 3278{ 3279out[j] = INTF :: getInitial (val[j]); 3280} 3281} 3282 3283template < typename INTF , typename T , size_t COUNT > 3284__device__ T _wavePrefixInvertableMultiple ( WarpMask mask, T * val) 3285{ 3286const int offsetSize = _waveCalcPow2Offset (mask); 3287 3288const int laneId = _getLaneId (); 3289T originalVal[ COUNT ]; 3290_waveOpCopy < INTF , T , COUNT > (originalVal, val); 3291 3292if (offsetSize > 0 ) 3293{ 3294// Sum is calculated inclusive of this lanes value 3295for ( int i = 1 ; i < offsetSize; i += i) 3296{ 3297// TODO(JS): Note that here I don't split the laneId outside so it's only tested once. 3298// This may be better but it would also mean that there would be shfl between lanes 3299// that are on different (albeit identical) instructions. So this seems more likely to 3300// work as expected with everything in lock step. 3301for ( size_t j = 0 ; j < COUNT ; ++ j) 3302{ 3303const T readVal = __shfl_up_sync (mask, val[j], i, offsetSize); 3304if (laneId >= i) 3305{ 3306val[j] = INTF :: doOp (val[j], readVal); 3307} 3308} 3309} 3310// Remove originalVal from the result, by applyin inverse 3311_waveOpDoInverse < INTF , T , COUNT > (val, originalVal); 3312} 3313else 3314{ 3315_waveOpSetInitial < INTF , T , COUNT > (val, val); 3316if (! _waveIsSingleLane (mask)) 3317{ 3318int remaining = mask; 3319while (remaining) 3320{ 3321const int laneBit = remaining & - remaining; 3322// Get the sourceLane 3323const int srcLane = __ffs (laneBit) - 1 ; 3324 3325for ( size_t j = 0 ; j < COUNT ; ++ j) 3326{ 3327// Broadcast (can also broadcast to self) 3328const T readValue = __shfl_sync (mask, originalVal[j], srcLane); 3329// Only accumulate if srcLane is less than this lane 3330if (srcLane < laneId) 3331{ 3332val[j] = INTF :: doOp (val[j], readValue); 3333} 3334remaining &= ~laneBit; 3335} 3336} 3337} 3338} 3339} 3340 3341template < typename INTF , typename T , size_t COUNT > 3342__device__ T _wavePrefixMultiple ( WarpMask mask, T * val) 3343{ 3344const int offsetSize = _waveCalcPow2Offset (mask); 3345 3346const int laneId = _getLaneId (); 3347 3348T work[ COUNT ]; 3349_waveOpCopy < INTF , T , COUNT > (work, val); 3350_waveOpSetInitial < INTF , T , COUNT > (val, val); 3351 3352if (offsetSize > 0 ) 3353{ 3354// For transmitted value we will do it inclusively with this lanes value 3355// For the result we do not include the lanes value. This means an extra op for each 3356// iteration but means we don't need to have a divide at the end and also removes overflow 3357// issues in that scenario. 3358for ( int i = 1 ; i < offsetSize; i += i) 3359{ 3360for ( size_t j = 0 ; j < COUNT ; ++ j) 3361{ 3362const T readVal = __shfl_up_sync (mask, work[j], i, offsetSize); 3363if (laneId >= i) 3364{ 3365work[j] = INTF :: doOp (work[j], readVal); 3366val[j] = INTF :: doOp (val[j], readVal); 3367} 3368} 3369} 3370} 3371else 3372{ 3373if (! _waveIsSingleLane (mask)) 3374{ 3375int remaining = mask; 3376while (remaining) 3377{ 3378const int laneBit = remaining & - remaining; 3379// Get the sourceLane 3380const int srcLane = __ffs (laneBit) - 1 ; 3381 3382for ( size_t j = 0 ; j < COUNT ; ++ j) 3383{ 3384// Broadcast (can also broadcast to self) 3385const T readValue = __shfl_sync (mask, work[j], srcLane); 3386// Only accumulate if srcLane is less than this lane 3387if (srcLane < laneId) 3388{ 3389val[j] = INTF :: doOp (val[j], readValue); 3390} 3391} 3392remaining &= ~laneBit; 3393} 3394} 3395} 3396} 3397 3398template < typename T > 3399__inline__ __device__ T _wavePrefixProduct ( WarpMask mask, T val) 3400{ 3401return _wavePrefixScalar < WaveOpMul < T > , T > (mask, val); 3402} 3403 3404template < typename T > 3405__inline__ __device__ T _wavePrefixSum ( WarpMask mask, T val) 3406{ 3407return _wavePrefixInvertableScalar < WaveOpAdd < T > , T > (mask, val); 3408} 3409 3410template < typename T > 3411__inline__ __device__ T _wavePrefixXor ( WarpMask mask, T val) 3412{ 3413return _wavePrefixInvertableScalar < WaveOpXor < T > , T > (mask, val); 3414} 3415 3416template < typename T > 3417__inline__ __device__ T _wavePrefixOr ( WarpMask mask, T val) 3418{ 3419return _wavePrefixScalar < WaveOpOr < T > , T > (mask, val); 3420} 3421 3422template < typename T > 3423__inline__ __device__ T _wavePrefixAnd ( WarpMask mask, T val) 3424{ 3425return _wavePrefixScalar < WaveOpAnd < T > , T > (mask, val); 3426} 3427 3428 3429template < typename T > 3430__inline__ __device__ T _wavePrefixProductMultiple ( WarpMask mask, T val) 3431{ 3432typedef typename ElementTypeTrait < T > ::Type ElemType; 3433_wavePrefixInvertableMultiple < WaveOpMul < ElemType > , ElemType, sizeof ( T ) / sizeof (ElemType) > ( 3434mask, 3435( ElemType * ) & val); 3436return val; 3437} 3438 3439template < typename T > 3440__inline__ __device__ T _wavePrefixSumMultiple ( WarpMask mask, T val) 3441{ 3442typedef typename ElementTypeTrait < T > ::Type ElemType; 3443_wavePrefixInvertableMultiple < WaveOpAdd < ElemType > , ElemType, sizeof ( T ) / sizeof (ElemType) > ( 3444mask, 3445( ElemType * ) & val); 3446return val; 3447} 3448 3449template < typename T > 3450__inline__ __device__ T _wavePrefixXorMultiple ( WarpMask mask, T val) 3451{ 3452typedef typename ElementTypeTrait < T > ::Type ElemType; 3453_wavePrefixInvertableMultiple < WaveOpXor < ElemType > , ElemType, sizeof ( T ) / sizeof (ElemType) > ( 3454mask, 3455( ElemType * ) & val); 3456return val; 3457} 3458 3459template < typename T > 3460__inline__ __device__ T _wavePrefixOrMultiple ( WarpMask mask, T val) 3461{ 3462typedef typename ElementTypeTrait < T > ::Type ElemType; 3463_wavePrefixMultiple < WaveOpOr < ElemType > , ElemType, sizeof ( T ) / sizeof (ElemType) > ( 3464mask, 3465( ElemType * ) & val); 3466return val; 3467} 3468 3469template < typename T > 3470__inline__ __device__ T _wavePrefixAndMultiple ( WarpMask mask, T val) 3471{ 3472typedef typename ElementTypeTrait < T > ::Type ElemType; 3473_wavePrefixMultiple < WaveOpAnd < ElemType > , ElemType, sizeof ( T ) / sizeof (ElemType) > ( 3474mask, 3475( ElemType * ) & val); 3476return val; 3477} 3478 3479template < typename T > 3480__inline__ __device__ T _wavePrefixMin ( WarpMask mask, T val) 3481{ 3482return _wavePrefixScalar < WaveOpMin < T > , T > (mask, val); 3483} 3484 3485template < typename T > 3486__inline__ __device__ T _wavePrefixMax ( WarpMask mask, T val) 3487{ 3488return _wavePrefixScalar < WaveOpMax < T > , T > (mask, val); 3489} 3490 3491template < typename T > 3492__inline__ __device__ T _wavePrefixMinMultiple ( WarpMask mask, T val) 3493{ 3494typedef typename ElementTypeTrait < T > ::Type ElemType; 3495_wavePrefixMultiple < WaveOpMin < ElemType > , ElemType, sizeof ( T ) / sizeof (ElemType) > ( 3496mask, 3497( ElemType * ) & val); 3498return val; 3499} 3500 3501template < typename T > 3502__inline__ __device__ T _wavePrefixMaxMultiple ( WarpMask mask, T val) 3503{ 3504typedef typename ElementTypeTrait < T > ::Type ElemType; 3505_wavePrefixMultiple < WaveOpMax < ElemType > , ElemType, sizeof ( T ) / sizeof (ElemType) > ( 3506mask, 3507( ElemType * ) & val); 3508return val; 3509} 3510 3511// Wrapper structures for exclusive operations that use the overloaded getInitial method 3512template < typename T > 3513struct WaveOpExclusiveMin 3514{ 3515__inline__ __device__ static T getInitial ( T a) { return WaveOpMin < T > :: getInitial (a, true); } 3516__inline__ __device__ static T doOp ( T a, T b) { return WaveOpMin < T > :: doOp (a, b); } 3517}; 3518 3519template < typename T > 3520struct WaveOpExclusiveMax 3521{ 3522__inline__ __device__ static T getInitial ( T a) { return WaveOpMax < T > :: getInitial (a, true); } 3523__inline__ __device__ static T doOp ( T a, T b) { return WaveOpMax < T > :: doOp (a, b); } 3524}; 3525 3526// Inclusive prefix min/max functions (for WaveMultiPrefixInclusive*) 3527template < typename T > 3528__inline__ __device__ T _wavePrefixInclusiveMin ( WarpMask mask, T val) 3529{ 3530return _wavePrefixMin (mask, val); 3531} 3532 3533template < typename T > 3534__inline__ __device__ T _wavePrefixInclusiveMax ( WarpMask mask, T val) 3535{ 3536return _wavePrefixMax (mask, val); 3537} 3538 3539template < typename T > 3540__inline__ __device__ T _wavePrefixInclusiveMinMultiple ( WarpMask mask, T val) 3541{ 3542return _wavePrefixMinMultiple (mask, val); 3543} 3544 3545template < typename T > 3546__inline__ __device__ T _wavePrefixInclusiveMaxMultiple ( WarpMask mask, T val) 3547{ 3548return _wavePrefixMaxMultiple (mask, val); 3549} 3550 3551// Explicit exclusive prefix min/max functions (for WaveMultiPrefixExclusive*) 3552template < typename T > 3553__inline__ __device__ T _wavePrefixExclusiveMin ( WarpMask mask, T val) 3554{ 3555return _wavePrefixScalar < WaveOpExclusiveMin < T > , T > (mask, val); 3556} 3557 3558template < typename T > 3559__inline__ __device__ T _wavePrefixExclusiveMax ( WarpMask mask, T val) 3560{ 3561return _wavePrefixScalar < WaveOpExclusiveMax < T > , T > (mask, val); 3562} 3563 3564template < typename T > 3565__inline__ __device__ T _wavePrefixExclusiveMinMultiple ( WarpMask mask, T val) 3566{ 3567typedef typename ElementTypeTrait < T > ::Type ElemType; 3568_wavePrefixMultiple < WaveOpExclusiveMin < ElemType > , ElemType, sizeof ( T ) / sizeof (ElemType) > ( 3569mask, 3570( ElemType * ) & val); 3571return val; 3572} 3573 3574template < typename T > 3575__inline__ __device__ T _wavePrefixExclusiveMaxMultiple ( WarpMask mask, T val) 3576{ 3577typedef typename ElementTypeTrait < T > ::Type ElemType; 3578_wavePrefixMultiple < WaveOpExclusiveMax < ElemType > , ElemType, sizeof ( T ) / sizeof (ElemType) > ( 3579mask, 3580( ElemType * ) & val); 3581return val; 3582} 3583 3584template < typename T > 3585__inline__ __device__ uint4 _waveMatchScalar ( WarpMask mask, T val) 3586{ 3587int pred; 3588return make_uint4 ( __match_all_sync (mask, val, & pred), 0 , 0 , 0 ); 3589} 3590 3591template < typename T > 3592__inline__ __device__ uint4 _waveMatchMultiple ( WarpMask mask, const T & inVal) 3593{ 3594typedef typename ElementTypeTrait < T > ::Type ElemType; 3595const size_t count = sizeof ( T ) / sizeof (ElemType); 3596int pred; 3597const ElemType * src = ( const ElemType * ) & inVal; 3598uint matchBits = 0xffffffff ; 3599for ( size_t i = 0 ; i < count && matchBits; ++ i) 3600{ 3601matchBits = matchBits & __match_all_sync (mask, src[i], & pred); 3602} 3603return make_uint4 (matchBits, 0 , 0 , 0 ); 3604} 3605 3606__device__ uint getAt ( dim3 a, int b) 3607{ 3608SLANG_PRELUDE_ASSERT (b >= 0 && b < 3 ); 3609return ( & a. x )[b]; 3610} 3611__device__ uint3 operator * (uint3 a, dim3 b) 3612{ 3613uint3 r; 3614r. x = a. x * b. x ; 3615r. y = a. y * b. y ; 3616r. z = a. z * b. z ; 3617return r; 3618} 3619 3620template < typename TResult, typename TInput > 3621__inline__ __device__ TResult slang_bit_cast ( TInput val) 3622{ 3623return * ( TResult * )( & val); 3624} 3625 3626/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ 3627 3628 3629/* Type that defines the uniform entry point params. The actual content of this type is dependent on 3630the entry point parameters, and can be found via reflection or defined such that it matches the 3631shader appropriately. 3632*/ 3633struct UniformEntryPointParams ; 3634struct UniformState ; 3635 3636// ---------------------- OptiX Ray Payload -------------------------------------- 3637#ifdef SLANG_CUDA_ENABLE_OPTIX 3638 3639struct RayDesc 3640{ 3641float3 Origin ; 3642float TMin ; 3643float3 Direction ; 3644float TMax ; 3645}; 3646 3647static __forceinline__ __device__ void * unpackOptiXRayPayloadPointer ( uint32_t i0, uint32_t i1) 3648{ 3649const uint64_t uptr = static_cast < uint64_t > (i0) << 32 | i1; 3650void * ptr = reinterpret_cast < void *> (uptr); 3651return ptr; 3652} 3653 3654static __forceinline__ __device__ void packOptiXRayPayloadPointer ( 3655void * ptr, 3656uint32_t & i0, 3657uint32_t & i1) 3658{ 3659const uint64_t uptr = reinterpret_cast < uint64_t > (ptr); 3660i0 = uptr >> 32 ; 3661i1 = uptr & 0x00000000ffffffff ; 3662} 3663 3664static __forceinline__ __device__ void * getOptiXRayPayloadPtr () 3665{ 3666const uint32_t u0 = optixGetPayload_0 (); 3667const uint32_t u1 = optixGetPayload_1 (); 3668return unpackOptiXRayPayloadPointer (u0, u1); 3669} 3670 3671template < typename T > 3672__forceinline__ __device__ void * optixTrace ( 3673OptixTraversableHandle AccelerationStructure, 3674uint32_t RayFlags, 3675uint32_t InstanceInclusionMask, 3676uint32_t RayContributionToHitGroupIndex, 3677uint32_t MultiplierForGeometryContributionToHitGroupIndex, 3678uint32_t MissShaderIndex, 3679RayDesc Ray, 3680T * Payload) 3681{ 3682uint32_t r0, r1; 3683packOptiXRayPayloadPointer (( void * )Payload, r0, r1); 3684optixTrace ( 3685AccelerationStructure, 3686Ray. Origin , 3687Ray. Direction , 3688Ray. TMin , 3689Ray. TMax , 36900.f , /* Time for motion blur, currently unsupported in slang */ 3691InstanceInclusionMask, 3692RayFlags, 3693RayContributionToHitGroupIndex, 3694MultiplierForGeometryContributionToHitGroupIndex, 3695MissShaderIndex, 3696r0, 3697r1); 3698} 3699 3700#if ( OPTIX_VERSION >= 90000 ) 3701__forceinline__ __device__ float4 optixGetSpherePositionAndRadius () 3702{ 3703float4 data[ 1 ]; 3704optixGetSphereData (data); 3705return data[ 0 ]; 3706} 3707#endif 3708 3709#if ( OPTIX_VERSION >= 90000 ) 3710__forceinline__ __device__ float4 3711optixHitObjectGetSpherePositionAndRadius ( OptixTraversableHandle * Obj) 3712{ 3713float4 data[ 1 ]; 3714optixHitObjectGetSphereData (data); 3715return data[ 0 ]; 3716} 3717#endif 3718 3719#if ( OPTIX_VERSION >= 90000 ) 3720__forceinline__ __device__ Matrix < float, 2 , 4 > optixGetLssPositionsAndRadii () 3721{ 3722float4 data[ 2 ]; 3723optixGetLinearCurveVertexData (data); 3724return makeMatrix < float, 2 , 4 > (data[ 0 ], data[ 1 ]); 3725} 3726#endif 3727 3728#if ( OPTIX_VERSION >= 90000 ) 3729__forceinline__ __device__ Matrix < float, 2 , 4 > optixHitObjectGetLssPositionsAndRadii ( 3730OptixTraversableHandle * Obj) 3731{ 3732float4 data[ 2 ]; 3733optixHitObjectGetLinearCurveVertexData (data); 3734return makeMatrix < float, 2 , 4 > (data[ 0 ], data[ 1 ]); 3735} 3736#endif 3737 3738#if ( OPTIX_VERSION >= 90000 ) 3739__forceinline__ __device__ bool optixIsSphereHit () 3740{ 3741return optixGetPrimitiveType () == OPTIX_PRIMITIVE_TYPE_SPHERE ; 3742} 3743#endif 3744 3745#if ( OPTIX_VERSION >= 90000 ) 3746__forceinline__ __device__ bool optixHitObjectIsSphereHit ( OptixTraversableHandle * Obj) 3747{ 3748return optixGetPrimitiveType ( optixHitObjectGetHitKind ()) == OPTIX_PRIMITIVE_TYPE_SPHERE ; 3749} 3750#endif 3751 3752#if ( OPTIX_VERSION >= 90000 ) 3753__forceinline__ __device__ bool optixIsLSSHit () 3754{ 3755return optixGetPrimitiveType () == OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR ; 3756} 3757#endif 3758 3759#if ( OPTIX_VERSION >= 90000 ) 3760__forceinline__ __device__ bool optixHitObjectIsLSSHit ( OptixTraversableHandle * Obj) 3761{ 3762return optixGetPrimitiveType ( optixHitObjectGetHitKind ()) == OPTIX_PRIMITIVE_TYPE_ROUND_LINEAR ; 3763} 3764#endif 3765 3766template < typename T > 3767__forceinline__ __device__ void * optixTraverse ( 3768OptixTraversableHandle AccelerationStructure, 3769uint32_t RayFlags, 3770uint32_t InstanceInclusionMask, 3771uint32_t RayContributionToHitGroupIndex, 3772uint32_t MultiplierForGeometryContributionToHitGroupIndex, 3773uint32_t MissShaderIndex, 3774RayDesc Ray, 3775T * Payload, 3776OptixTraversableHandle * hitObj) 3777{ 3778uint32_t r0, r1; 3779packOptiXRayPayloadPointer (( void * )Payload, r0, r1); 3780optixTraverse ( 3781AccelerationStructure, 3782Ray. Origin , 3783Ray. Direction , 3784Ray. TMin , 3785Ray. TMax , 37860.f , /* Time for motion blur, currently unsupported in slang */ 3787InstanceInclusionMask, 3788RayFlags, 3789RayContributionToHitGroupIndex, 3790MultiplierForGeometryContributionToHitGroupIndex, 3791MissShaderIndex, 3792r0, 3793r1); 3794} 3795 3796template < typename T > 3797__forceinline__ __device__ void * optixTraverse ( 3798OptixTraversableHandle AccelerationStructure, 3799uint32_t RayFlags, 3800uint32_t InstanceInclusionMask, 3801uint32_t RayContributionToHitGroupIndex, 3802uint32_t MultiplierForGeometryContributionToHitGroupIndex, 3803uint32_t MissShaderIndex, 3804RayDesc Ray, 3805float RayTime, 3806T * Payload, 3807OptixTraversableHandle * hitObj) 3808{ 3809uint32_t r0, r1; 3810packOptiXRayPayloadPointer (( void * )Payload, r0, r1); 3811optixTraverse ( 3812AccelerationStructure, 3813Ray. Origin , 3814Ray. Direction , 3815Ray. TMin , 3816Ray. TMax , 3817RayTime, 3818InstanceInclusionMask, 3819RayFlags, 3820RayContributionToHitGroupIndex, 3821MultiplierForGeometryContributionToHitGroupIndex, 3822MissShaderIndex, 3823r0, 3824r1); 3825} 3826 3827#if ( OPTIX_VERSION >= 80100 ) 3828static __forceinline__ __device__ bool slangOptixHitObjectIsHit ( OptixTraversableHandle * hitObj) 3829{ 3830return optixHitObjectIsHit (); 3831} 3832#endif 3833 3834#if ( OPTIX_VERSION >= 80100 ) 3835static __forceinline__ __device__ bool slangOptixHitObjectIsMiss ( OptixTraversableHandle * hitObj) 3836{ 3837return optixHitObjectIsMiss (); 3838} 3839#endif 3840 3841#if ( OPTIX_VERSION >= 80100 ) 3842static __forceinline__ __device__ bool slangOptixHitObjectIsNop ( OptixTraversableHandle * hitObj) 3843{ 3844return optixHitObjectIsNop (); 3845} 3846#endif 3847 3848#if ( OPTIX_VERSION >= 90000 ) 3849static __forceinline__ __device__ uint 3850slangOptixHitObjectGetClusterId ( OptixTraversableHandle * hitObj) 3851{ 3852return optixHitObjectGetClusterId (); 3853} 3854#endif 3855 3856#if ( OPTIX_VERSION >= 80100 ) 3857static __forceinline__ __device__ void optixMakeMissHitObject ( 3858uint MissShaderIndex, 3859RayDesc Ray, 3860OptixTraversableHandle * missObj) 3861{ 3862optixMakeMissHitObject ( 3863MissShaderIndex, 3864Ray. Origin , 3865Ray. Direction , 3866Ray. TMin , 3867Ray. TMax , 38680.f /* rayTime */ 3869#if ( OPTIX_VERSION >= 90000 ) 3870, 3871OPTIX_RAY_FLAG_NONE /* rayFlags*/ 3872#endif 3873); 3874} 3875#endif 3876 3877#if ( OPTIX_VERSION >= 80100 ) 3878static __forceinline__ __device__ void optixMakeMissHitObject ( 3879uint MissShaderIndex, 3880RayDesc Ray, 3881float CurrentTime, 3882OptixTraversableHandle * missObj) 3883{ 3884optixMakeMissHitObject ( 3885MissShaderIndex, 3886Ray. Origin , 3887Ray. Direction , 3888Ray. TMin , 3889Ray. TMax , 3890CurrentTime 3891#if ( OPTIX_VERSION >= 90000 ) 3892, 3893OPTIX_RAY_FLAG_NONE /* rayFlags*/ 3894#endif 3895); 3896} 3897#endif 3898 3899#if ( OPTIX_VERSION >= 80100 ) 3900template < typename T > 3901static __forceinline__ __device__ void optixMakeHitObject ( 3902OptixTraversableHandle AccelerationStructure, 3903uint InstanceIndex, 3904uint GeometryIndex, 3905uint PrimitiveIndex, 3906uint HitKind, 3907uint RayContributionToHitGroupIndex, 3908uint MultiplierForGeometryContributionToHitGroupIndex, 3909RayDesc Ray, 3910T attr, 3911OptixTraversableHandle * handle) 3912{ 3913OptixTraverseData data{}; 3914optixHitObjectGetTraverseData ( & data); 3915optixMakeHitObject ( 3916AccelerationStructure, 3917Ray. Origin , 3918Ray. Direction , 3919Ray. TMin , 39200.f , 3921OPTIX_RAY_FLAG_NONE , /* rayFlags*/ 3922data, 3923nullptr , /*OptixTraversableHandle* transforms*/ 39240 /*numTransforms */ ); 3925} 3926#endif 3927 3928#if ( OPTIX_VERSION >= 80100 ) 3929template < typename T > 3930static __forceinline__ __device__ void optixMakeHitObject ( 3931uint HitGroupRecordIndex, 3932OptixTraversableHandle AccelerationStructure, 3933uint InstanceIndex, 3934uint GeometryIndex, 3935uint PrimitiveIndex, 3936uint HitKind, 3937RayDesc Ray, 3938T attr, 3939OptixTraversableHandle * handle) 3940{ 3941OptixTraverseData data{}; 3942optixHitObjectGetTraverseData ( & data); 3943optixMakeHitObject ( 3944AccelerationStructure, 3945Ray. Origin , 3946Ray. Direction , 3947Ray. TMin , 39480.f , 3949OPTIX_RAY_FLAG_NONE , /* rayFlags*/ 3950data, 3951nullptr , /*OptixTraversableHandle* transforms*/ 39520 /*numTransforms */ ); 3953} 3954#endif 3955 3956#if ( OPTIX_VERSION >= 80100 ) 3957template < typename T > 3958static __forceinline__ __device__ void optixMakeHitObject ( 3959OptixTraversableHandle AccelerationStructure, 3960uint InstanceIndex, 3961uint GeometryIndex, 3962uint PrimitiveIndex, 3963uint HitKind, 3964uint RayContributionToHitGroupIndex, 3965uint MultiplierForGeometryContributionToHitGroupIndex, 3966RayDesc Ray, 3967float CurrentTime, 3968T attr, 3969OptixTraversableHandle * handle) 3970{ 3971OptixTraverseData data{}; 3972optixHitObjectGetTraverseData ( & data); 3973optixMakeHitObject ( 3974AccelerationStructure, 3975Ray. Origin , 3976Ray. Direction , 3977Ray. TMin , 3978CurrentTime, 3979OPTIX_RAY_FLAG_NONE , /* rayFlags*/ 3980data, 3981nullptr , /*OptixTraversableHandle* transforms*/ 39820 /*numTransforms */ ); 3983} 3984#endif 3985 3986#if ( OPTIX_VERSION >= 80100 ) 3987template < typename T > 3988static __forceinline__ __device__ void optixMakeHitObject ( 3989uint HitGroupRecordIndex, 3990OptixTraversableHandle AccelerationStructure, 3991uint InstanceIndex, 3992uint GeometryIndex, 3993uint PrimitiveIndex, 3994uint HitKind, 3995RayDesc Ray, 3996float CurrentTime, 3997T attr, 3998OptixTraversableHandle * handle) 3999{ 4000OptixTraverseData data{}; 4001optixHitObjectGetTraverseData ( & data); 4002optixMakeHitObject ( 4003AccelerationStructure, 4004Ray. Origin , 4005Ray. Direction , 4006Ray. TMin , 4007CurrentTime, 4008OPTIX_RAY_FLAG_NONE , /* rayFlags*/ 4009data, 4010nullptr , /*OptixTraversableHandle* transforms*/ 40110 /*numTransforms */ ); 4012} 4013#endif 4014 4015#if ( OPTIX_VERSION >= 80100 ) 4016static __forceinline__ __device__ void slangOptixMakeNopHitObject ( OptixTraversableHandle * Obj) 4017{ 4018optixMakeNopHitObject (); 4019} 4020#endif 4021 4022#if ( OPTIX_VERSION >= 80100 ) 4023template < typename T > 4024static __forceinline__ __device__ void optixInvoke ( 4025OptixTraversableHandle AccelerationStructure, 4026OptixTraversableHandle * HitOrMiss, 4027T Payload) 4028{ 4029uint32_t r0, r1; 4030packOptiXRayPayloadPointer (( void * )Payload, r0, r1); 4031optixInvoke (r0, r1); 4032} 4033#endif 4034 4035#if ( OPTIX_VERSION >= 80100 ) 4036static __forceinline__ __device__ RayDesc optixHitObjectGetRayDesc ( OptixTraversableHandle * obj) 4037{ 4038RayDesc ray = { 4039optixHitObjectGetWorldRayOrigin (), 4040optixHitObjectGetRayTmin (), 4041optixHitObjectGetWorldRayDirection (), 4042optixHitObjectGetRayTmax ()}; 4043return ray; 4044} 4045#endif 4046 4047#if ( OPTIX_VERSION >= 80100 ) 4048static __forceinline__ __device__ uint 4049slangOptixHitObjectGetInstanceIndex ( OptixTraversableHandle * Obj) 4050{ 4051return optixHitObjectGetInstanceIndex (); 4052} 4053#endif 4054 4055#if ( OPTIX_VERSION >= 80100 ) 4056static __forceinline__ __device__ uint slangOptixHitObjectGetInstanceId ( OptixTraversableHandle * Obj) 4057{ 4058return optixHitObjectGetInstanceId (); 4059} 4060#endif 4061 4062#if ( OPTIX_VERSION >= 80100 ) 4063static __forceinline__ __device__ uint 4064slangOptixHitObjectGetSbtGASIndex ( OptixTraversableHandle * Obj) 4065{ 4066return optixHitObjectGetSbtGASIndex (); 4067} 4068#endif 4069 4070#if ( OPTIX_VERSION >= 80100 ) 4071static __forceinline__ __device__ uint 4072slangOptixHitObjectGetPrimitiveIndex ( OptixTraversableHandle * Obj) 4073{ 4074return optixHitObjectGetPrimitiveIndex (); 4075} 4076#endif 4077 4078#if ( OPTIX_VERSION >= 80100 ) 4079template < typename T > 4080static __forceinline__ __device__ T optixHitObjectGetAttribute ( OptixTraversableHandle * Obj) 4081{ 4082constexpr size_t numInts = ( sizeof ( T ) + sizeof ( uint32_t ) - 1 ) / 4083sizeof ( uint32_t ); // Number of 32-bit values, rounded up 4084static_assert (numInts <= 8 , "Attribute type is too large" ); 4085 4086// Create an array to hold the attribute values 4087uint32_t values[numInts == 0 ? 1 : numInts] = { 0 }; // Ensure we have at least one element 4088 4089// Read the appropriate number of attribute registers 4090if constexpr (numInts > 0 ) 4091values[ 0 ] = optixHitObjectGetAttribute_0 (); 4092if constexpr (numInts > 1 ) 4093values[ 1 ] = optixHitObjectGetAttribute_1 (); 4094if constexpr (numInts > 2 ) 4095values[ 2 ] = optixHitObjectGetAttribute_2 (); 4096if constexpr (numInts > 3 ) 4097values[ 3 ] = optixHitObjectGetAttribute_3 (); 4098if constexpr (numInts > 4 ) 4099values[ 4 ] = optixHitObjectGetAttribute_4 (); 4100if constexpr (numInts > 5 ) 4101values[ 5 ] = optixHitObjectGetAttribute_5 (); 4102if constexpr (numInts > 6 ) 4103values[ 6 ] = optixHitObjectGetAttribute_6 (); 4104if constexpr (numInts > 7 ) 4105values[ 7 ] = optixHitObjectGetAttribute_7 (); 4106 4107// Reinterpret the array as the desired type 4108T result; 4109memcpy ( & result, values, sizeof ( T )); 4110return result; 4111} 4112#endif 4113 4114#if ( OPTIX_VERSION >= 80100 ) 4115static __forceinline__ __device__ uint 4116slangOptixHitObjectGetSbtRecordIndex ( OptixTraversableHandle * Obj) 4117{ 4118return optixHitObjectGetSbtRecordIndex (); 4119} 4120#endif 4121 4122#if ( OPTIX_VERSION >= 90000 ) 4123static __forceinline__ __device__ uint 4124slangOptixHitObjectSetSbtRecordIndex ( OptixTraversableHandle * Obj, uint sbtRecordIndex) 4125{ 4126optixHitObjectSetSbtRecordIndex (sbtRecordIndex); // returns void 4127return sbtRecordIndex; 4128} 4129#endif 4130 4131#else 4132// Define OptixTraversableHandle even if OptiX is not enabled. 4133// This allows RaytracingAccelerationStructure to be properly reflected in non-OptiX code. 4134typedef unsigned long long OptixTraversableHandle ; 4135#endif 4136static const int kSlangTorchTensorMaxDim = 5 ; 4137 4138// TensorView 4139struct TensorView 4140{ 4141uint8_t * data ; 4142uint32_t strides [kSlangTorchTensorMaxDim]; 4143uint32_t sizes [kSlangTorchTensorMaxDim]; 4144uint32_t dimensionCount ; 4145 4146template < typename T > 4147__device__ T * data_ptr () 4148{ 4149return reinterpret_cast < T *> (data); 4150} 4151 4152template < typename T > 4153__device__ T * data_ptr_at ( uint32_t index) 4154{ 4155uint64_t offset = strides[ 0 ] * index; 4156return reinterpret_cast < T *> (data + offset); 4157} 4158 4159template < typename T > 4160__device__ T * data_ptr_at ( uint2 index) 4161{ 4162uint64_t offset = strides[ 0 ] * index. x + strides[ 1 ] * index. y ; 4163return reinterpret_cast < T *> (data + offset); 4164} 4165 4166template < typename T > 4167__device__ T * data_ptr_at ( uint3 index) 4168{ 4169uint64_t offset = strides[ 0 ] * index. x + strides[ 1 ] * index. y + strides[ 2 ] * index. z ; 4170return reinterpret_cast < T *> (data + offset); 4171} 4172 4173template < typename T > 4174__device__ T * data_ptr_at ( uint4 index) 4175{ 4176uint64_t offset = strides[ 0 ] * index. x + strides[ 1 ] * index. y + strides[ 2 ] * index. z + 4177strides[ 3 ] * index. w ; 4178return reinterpret_cast < T *> (data + offset); 4179} 4180 4181template < typename T , unsigned int N > 4182__device__ T * data_ptr_at ( uint index[ N ]) 4183{ 4184uint64_t offset = 0 ; 4185for ( unsigned int i = 0 ; i < N ; ++ i) 4186{ 4187offset += strides[i] * index[i]; 4188} 4189return reinterpret_cast < T *> (data + offset); 4190} 4191 4192template < typename T > 4193__device__ T & load (uint32_t x) 4194{ 4195return * reinterpret_cast < T *> (data + strides[ 0 ] * x); 4196} 4197template < typename T > 4198__device__ T & load (uint32_t x, uint32_t y) 4199{ 4200return * reinterpret_cast < T *> (data + strides[ 0 ] * x + strides[ 1 ] * y); 4201} 4202template < typename T > 4203__device__ T & load (uint2 index) 4204{ 4205return * reinterpret_cast < T *> (data + strides[ 0 ] * index. x + strides[ 1 ] * index. y ); 4206} 4207template < typename T > 4208__device__ T & load (uint32_t x, uint32_t y, uint32_t z) 4209{ 4210return * reinterpret_cast < T *> (data + strides[ 0 ] * x + strides[ 1 ] * y + strides[ 2 ] * z); 4211} 4212template < typename T > 4213__device__ T & load (uint3 index) 4214{ 4215return * reinterpret_cast < T *> ( 4216data + strides[ 0 ] * index. x + strides[ 1 ] * index. y + strides[ 2 ] * index. z ); 4217} 4218template < typename T > 4219__device__ T & load (uint32_t x, uint32_t y, uint32_t z, uint32_t w) 4220{ 4221return * reinterpret_cast < T *> ( 4222data + strides[ 0 ] * x + strides[ 1 ] * y + strides[ 2 ] * z + strides[ 3 ] * w); 4223} 4224template < typename T > 4225__device__ T & load (uint4 index) 4226{ 4227return * reinterpret_cast < T *> ( 4228data + strides[ 0 ] * index. x + strides[ 1 ] * index. y + strides[ 2 ] * index. z + 4229strides[ 3 ] * index. w ); 4230} 4231template < typename T > 4232__device__ T & load (uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4) 4233{ 4234return * reinterpret_cast < T *> ( 4235data + strides[ 0 ] * i0 + strides[ 1 ] * i1 + strides[ 2 ] * i2 + strides[ 3 ] * i3 + 4236strides[ 4 ] * i4); 4237} 4238 4239// Generic version of load 4240template < typename T , unsigned int N > 4241__device__ T & load (uint index[ N ]) 4242{ 4243uint64_t offset = 0 ; 4244for ( unsigned int i = 0 ; i < N ; ++ i) 4245{ 4246offset += strides[i] * index[i]; 4247} 4248return * reinterpret_cast < T *> (data + offset); 4249} 4250 4251template < typename T > 4252__device__ void store ( uint32_t x, T val) 4253{ 4254* reinterpret_cast < T *> (data + strides[ 0 ] * x) = val; 4255} 4256template < typename T > 4257__device__ void store ( uint32_t x, uint32_t y, T val) 4258{ 4259* reinterpret_cast < T *> (data + strides[ 0 ] * x + strides[ 1 ] * y) = val; 4260} 4261template < typename T > 4262__device__ void store ( uint2 index, T val) 4263{ 4264* reinterpret_cast < T *> (data + strides[ 0 ] * index. x + strides[ 1 ] * index. y ) = val; 4265} 4266template < typename T > 4267__device__ void store ( uint32_t x, uint32_t y, uint32_t z, T val) 4268{ 4269* reinterpret_cast < T *> (data + strides[ 0 ] * x + strides[ 1 ] * y + strides[ 2 ] * z) = val; 4270} 4271template < typename T > 4272__device__ void store ( uint3 index, T val) 4273{ 4274* reinterpret_cast < T *> ( 4275data + strides[ 0 ] * index. x + strides[ 1 ] * index. y + strides[ 2 ] * index. z ) = val; 4276} 4277template < typename T > 4278__device__ void store ( uint32_t x, uint32_t y, uint32_t z, uint32_t w, T val) 4279{ 4280* reinterpret_cast < T *> ( 4281data + strides[ 0 ] * x + strides[ 1 ] * y + strides[ 2 ] * z + strides[ 3 ] * w) = val; 4282} 4283template < typename T > 4284__device__ void store ( uint4 index, T val) 4285{ 4286* reinterpret_cast < T *> ( 4287data + strides[ 0 ] * index. x + strides[ 1 ] * index. y + strides[ 2 ] * index. z + 4288strides[ 3 ] * index. w ) = val; 4289} 4290template < typename T > 4291__device__ void store ( uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, T val) 4292{ 4293* reinterpret_cast < T *> ( 4294data + strides[ 0 ] * i0 + strides[ 1 ] * i1 + strides[ 2 ] * i2 + strides[ 3 ] * i3 + 4295strides[ 4 ] * i4) = val; 4296} 4297 4298// Generic version 4299template < typename T , unsigned int N > 4300__device__ void store ( uint index[ N ], T val) 4301{ 4302uint64_t offset = 0 ; 4303for ( unsigned int i = 0 ; i < N ; ++ i) 4304{ 4305offset += strides[i] * index[i]; 4306} 4307* reinterpret_cast < T *> (data + offset) = val; 4308} 4309}; 4310 4311// Implementations for texture fetch/load functions using tex PTX intrinsics 4312// These are used for read-only texture access with integer coordinates. 4313 4314// 1D is not supported via PTX. Keeping the implementation below in case it ever gets supported. 4315template < typename T > 4316SLANG_FORCE_INLINE SLANG_CUDA_CALL T tex1Dfetch_int ( CUtexObject texObj, int x, int mip) 4317{ 4318static_assert (false, "CUDA does not support fetching from 1D textures" ); 4319} 4320 4321#if 0 4322#define SLANG_TEX1DFETCH_INT_IMPL ( T , dtype, c) \ 4323template<> \ 4324SLANG_FORCE_INLINE SLANG_CUDA_CALL T tex1Dfetch_int(CUtexObject texObj, int x, int mip) \ 4325{ \ 4326T result; \ 4327T stub; \ 4328asm("tex.level.1d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5}], %6;" \ 4329: c(result), c(stub), c(stub), c(stub) \ 4330: "l"(texObj), "r"(x), "r"(mip)); \ 4331return result; \ 4332} \ 4333template<> \ 4334SLANG_FORCE_INLINE SLANG_CUDA_CALL T##2 tex1Dfetch_int(CUtexObject texObj, int x, int mip) \ 4335{ \ 4336T result_x, result_y; \ 4337T stub; \ 4338asm("tex.level.1d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5}], %6;" \ 4339: c(result_x), c(result_y), c(stub), c(stub) \ 4340: "l"(texObj), "r"(x), "r"(mip)); \ 4341return make_##T##2(result_x, result_y); \ 4342} \ 4343template<> \ 4344SLANG_FORCE_INLINE SLANG_CUDA_CALL T##4 tex1Dfetch_int(CUtexObject texObj, int x, int mip) \ 4345{ \ 4346T result_x, result_y, result_z, result_w; \ 4347asm("tex.level.1d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5}], %6;" \ 4348: c(result_x), c(result_y), c(result_z), c(result_w) \ 4349: "l"(texObj), "r"(x), "r"(mip)); \ 4350return make_##T##4(result_x, result_y, result_z, result_w); \ 4351} 4352 4353SLANG_TEX1DFETCH_INT_IMPL (float, "f32" , "=f" ) 4354SLANG_TEX1DFETCH_INT_IMPL (uint, "u32" , "=r" ) 4355SLANG_TEX1DFETCH_INT_IMPL (int, "s32" , "=r" ) 4356#endif 4357 4358template < typename T > 4359SLANG_FORCE_INLINE SLANG_CUDA_CALL T tex2Dfetch_int ( CUtexObject texObj, int x, int y, int mip); 4360 4361#define SLANG_TEX2DFETCH_INT_IMPL ( T , dtype, c) \ 4362template<> \ 4363SLANG_FORCE_INLINE SLANG_CUDA_CALL T tex2Dfetch_int(CUtexObject texObj, int x, int y, int mip) \ 4364{ \ 4365T result; \ 4366T stub; \ 4367asm("tex.level.2d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6}], %7;" \ 4368: c(result), c(stub), c(stub), c(stub) \ 4369: "l"(texObj), "r"(x), "r"(y), "r"(mip)); \ 4370return result; \ 4371} \ 4372template<> \ 4373SLANG_FORCE_INLINE SLANG_CUDA_CALL \ 4374T##2 tex2Dfetch_int(CUtexObject texObj, int x, int y, int mip) \ 4375{ \ 4376T result_x, result_y; \ 4377T stub; \ 4378asm("tex.level.2d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6}], %7;" \ 4379: c(result_x), c(result_y), c(stub), c(stub) \ 4380: "l"(texObj), "r"(x), "r"(y), "r"(mip)); \ 4381return make_##T##2(result_x, result_y); \ 4382} \ 4383template<> \ 4384SLANG_FORCE_INLINE SLANG_CUDA_CALL \ 4385T##4 tex2Dfetch_int(CUtexObject texObj, int x, int y, int mip) \ 4386{ \ 4387T result_x, result_y, result_z, result_w; \ 4388asm("tex.level.2d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6}], %7;" \ 4389: c(result_x), c(result_y), c(result_z), c(result_w) \ 4390: "l"(texObj), "r"(x), "r"(y), "r"(mip)); \ 4391return make_##T##4(result_x, result_y, result_z, result_w); \ 4392} 4393 4394SLANG_TEX2DFETCH_INT_IMPL (float, "f32" , "=f" ) 4395SLANG_TEX2DFETCH_INT_IMPL (uint, "u32" , "=r" ) 4396SLANG_TEX2DFETCH_INT_IMPL (int, "s32" , "=r" ) 4397 4398 4399template < typename T > 4400SLANG_FORCE_INLINE SLANG_CUDA_CALL T 4401tex3Dfetch_int ( CUtexObject texObj, int x, int y, int z, int mip); 4402 4403#define SLANG_TEX3DFETCH_INT_IMPL ( T , dtype, c) \ 4404template<> \ 4405SLANG_FORCE_INLINE SLANG_CUDA_CALL T \ 4406tex3Dfetch_int(CUtexObject texObj, int x, int y, int z, int mip) \ 4407{ \ 4408T result; \ 4409T stub; \ 4410asm("tex.level.3d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6, %7, %8}], %9;" \ 4411: c(result), c(stub), c(stub), c(stub) \ 4412: "l"(texObj), "r"(x), "r"(y), "r"(z), "r"(z) /* ignored */ , "r"(mip)); \ 4413return result; \ 4414} \ 4415template<> \ 4416SLANG_FORCE_INLINE SLANG_CUDA_CALL \ 4417T##2 tex3Dfetch_int(CUtexObject texObj, int x, int y, int z, int mip) \ 4418{ \ 4419T result_x, result_y; \ 4420T stub; \ 4421asm("tex.level.3d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6, %7, %8}], %9;" \ 4422: c(result_x), c(result_y), c(stub), c(stub) \ 4423: "l"(texObj), "r"(x), "r"(y), "r"(z), "r"(z) /* ignored */ , "r"(mip)); \ 4424return make_##T##2(result_x, result_y); \ 4425} \ 4426template<> \ 4427SLANG_FORCE_INLINE SLANG_CUDA_CALL \ 4428T##4 tex3Dfetch_int(CUtexObject texObj, int x, int y, int z, int mip) \ 4429{ \ 4430T result_x, result_y, result_z, result_w; \ 4431asm("tex.level.3d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6, %7, %8}], %9;" \ 4432: c(result_x), c(result_y), c(result_z), c(result_w) \ 4433: "l"(texObj), "r"(x), "r"(y), "r"(z), "r"(z) /* ignored */ , "r"(mip)); \ 4434return make_##T##4(result_x, result_y, result_z, result_w); \ 4435} 4436 4437SLANG_TEX3DFETCH_INT_IMPL (float, "f32" , "=f" ) 4438SLANG_TEX3DFETCH_INT_IMPL (uint, "u32" , "=r" ) 4439SLANG_TEX3DFETCH_INT_IMPL (int, "s32" , "=r" ) 4440 4441template < typename T > 4442SLANG_FORCE_INLINE SLANG_CUDA_CALL T 4443tex1DArrayfetch_int ( CUtexObject texObj, int x, int layer, int mip); 4444 4445#define SLANG_TEX1DARRAYFETCH_INT_IMPL ( T , dtype, c) \ 4446template<> \ 4447SLANG_FORCE_INLINE SLANG_CUDA_CALL T \ 4448tex1DArrayfetch_int(CUtexObject texObj, int x, int layer, int mip) \ 4449{ \ 4450T result; \ 4451T stub; \ 4452asm("tex.level.a1d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6}], %7;" \ 4453: c(result), c(stub), c(stub), c(stub) \ 4454: "l"(texObj), "r"(layer), "r"(x), "r"(mip)); \ 4455return result; \ 4456} \ 4457template<> \ 4458SLANG_FORCE_INLINE SLANG_CUDA_CALL \ 4459T##2 tex1DArrayfetch_int(CUtexObject texObj, int x, int layer, int mip) \ 4460{ \ 4461T result_x, result_y; \ 4462T stub; \ 4463asm("tex.level.a1d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6}], %7;" \ 4464: c(result_x), c(result_y), c(stub), c(stub) \ 4465: "l"(texObj), "r"(layer), "r"(x), "r"(mip)); \ 4466return make_##T##2(result_x, result_y); \ 4467} \ 4468template<> \ 4469SLANG_FORCE_INLINE SLANG_CUDA_CALL \ 4470T##4 tex1DArrayfetch_int(CUtexObject texObj, int x, int layer, int mip) \ 4471{ \ 4472T result_x, result_y, result_z, result_w; \ 4473asm("tex.level.a1d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6}], %7;" \ 4474: c(result_x), c(result_y), c(result_z), c(result_w) \ 4475: "l"(texObj), "r"(layer), "r"(x), "r"(mip)); \ 4476return make_##T##4(result_x, result_y, result_z, result_w); \ 4477} 4478 4479SLANG_TEX1DARRAYFETCH_INT_IMPL (float, "f32" , "=f" ) 4480SLANG_TEX1DARRAYFETCH_INT_IMPL (uint, "u32" , "=r" ) 4481SLANG_TEX1DARRAYFETCH_INT_IMPL (int, "s32" , "=r" ) 4482 4483template < typename T > 4484SLANG_FORCE_INLINE SLANG_CUDA_CALL T 4485tex2DArrayfetch_int ( CUtexObject texObj, int x, int y, int layer, int mip); 4486 4487#define SLANG_TEX2DARRAYFETCH_INT_IMPL ( T , dtype, c) \ 4488template<> \ 4489SLANG_FORCE_INLINE SLANG_CUDA_CALL T \ 4490tex2DArrayfetch_int(CUtexObject texObj, int x, int y, int layer, int mip) \ 4491{ \ 4492T result; \ 4493T stub; \ 4494asm("tex.level.a2d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6, %7, %8}], %9;" \ 4495: c(result), c(stub), c(stub), c(stub) \ 4496: "l"(texObj), "r"(layer), "r"(x), "r"(y), "r"(layer) /* ignored */ , "r"(mip)); \ 4497return result; \ 4498} \ 4499template<> \ 4500SLANG_FORCE_INLINE SLANG_CUDA_CALL \ 4501T##2 tex2DArrayfetch_int(CUtexObject texObj, int x, int y, int layer, int mip) \ 4502{ \ 4503T result_x, result_y; \ 4504T stub; \ 4505asm("tex.level.a2d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6, %7, %8}], %9;" \ 4506: c(result_x), c(result_y), c(stub), c(stub) \ 4507: "l"(texObj), "r"(layer), "r"(x), "r"(y), "r"(layer) /* ignored */ , "r"(mip)); \ 4508return make_##T##2(result_x, result_y); \ 4509} \ 4510template<> \ 4511SLANG_FORCE_INLINE SLANG_CUDA_CALL \ 4512T##4 tex2DArrayfetch_int(CUtexObject texObj, int x, int y, int layer, int mip) \ 4513{ \ 4514T result_x, result_y, result_z, result_w; \ 4515asm("tex.level.a2d.v4." dtype ".s32 {%0, %1, %2, %3}, [%4, {%5, %6, %7, %8}], %9;" \ 4516: c(result_x), c(result_y), c(result_z), c(result_w) \ 4517: "l"(texObj), "r"(layer), "r"(x), "r"(y), "r"(layer) /* ignored */ , "r"(mip)); \ 4518return make_##T##4(result_x, result_y, result_z, result_w); \ 4519} 4520 4521SLANG_TEX2DARRAYFETCH_INT_IMPL (float, "f32" , "=f" ) 4522SLANG_TEX2DARRAYFETCH_INT_IMPL (uint, "u32" , "=r" ) 4523SLANG_TEX2DARRAYFETCH_INT_IMPL (int, "s32" , "=r" ) 4524 4525// Wave rotate helper functions - templated approach 4526#define SLANG_WARP_FULL_MASK 0xFFFFFFFF 4527 4528// Macro-based wave rotate implementation following codebase patterns 4529#define SLANG_WAVE_ROTATE_IMPL ( T ) \ 4530__device__ __forceinline__ T##2 _slang_waveRotate(T##2 value, unsigned int delta) \ 4531{ \ 4532return make_##T##2( \ 4533(T)__shfl_sync( \ 4534SLANG_WARP_FULL_MASK, \ 4535value.x, \ 4536(_getLaneId() + delta) % SLANG_CUDA_WARP_SIZE), \ 4537(T)__shfl_sync( \ 4538SLANG_WARP_FULL_MASK, \ 4539value.y, \ 4540(_getLaneId() + delta) % SLANG_CUDA_WARP_SIZE)); \ 4541} \ 4542__device__ __forceinline__ T##3 _slang_waveRotate(T##3 value, unsigned int delta) \ 4543{ \ 4544return make_##T##3( \ 4545(T)__shfl_sync( \ 4546SLANG_WARP_FULL_MASK, \ 4547value.x, \ 4548(_getLaneId() + delta) % SLANG_CUDA_WARP_SIZE), \ 4549(T)__shfl_sync( \ 4550SLANG_WARP_FULL_MASK, \ 4551value.y, \ 4552(_getLaneId() + delta) % SLANG_CUDA_WARP_SIZE), \ 4553(T)__shfl_sync( \ 4554SLANG_WARP_FULL_MASK, \ 4555value.z, \ 4556(_getLaneId() + delta) % SLANG_CUDA_WARP_SIZE)); \ 4557} \ 4558__device__ __forceinline__ T##4 _slang_waveRotate(T##4 value, unsigned int delta) \ 4559{ \ 4560return make_##T##4( \ 4561(T)__shfl_sync( \ 4562SLANG_WARP_FULL_MASK, \ 4563value.x, \ 4564(_getLaneId() + delta) % SLANG_CUDA_WARP_SIZE), \ 4565(T)__shfl_sync( \ 4566SLANG_WARP_FULL_MASK, \ 4567value.y, \ 4568(_getLaneId() + delta) % SLANG_CUDA_WARP_SIZE), \ 4569(T)__shfl_sync( \ 4570SLANG_WARP_FULL_MASK, \ 4571value.z, \ 4572(_getLaneId() + delta) % SLANG_CUDA_WARP_SIZE), \ 4573(T)__shfl_sync( \ 4574SLANG_WARP_FULL_MASK, \ 4575value.w, \ 4576(_getLaneId() + delta) % SLANG_CUDA_WARP_SIZE)); \ 4577} 4578 4579// Generate wave rotate functions for all standard vector types 4580SLANG_WAVE_ROTATE_IMPL ( uint ) 4581SLANG_WAVE_ROTATE_IMPL ( int ) 4582SLANG_WAVE_ROTATE_IMPL (float) 4583SLANG_WAVE_ROTATE_IMPL (short) 4584SLANG_WAVE_ROTATE_IMPL (ushort) 4585SLANG_WAVE_ROTATE_IMPL (char) 4586SLANG_WAVE_ROTATE_IMPL (uchar) 4587SLANG_WAVE_ROTATE_IMPL (longlong) 4588SLANG_WAVE_ROTATE_IMPL (ulonglong) 4589 4590#ifdef SLANG_CUDA_ENABLE_HALF 4591SLANG_WAVE_ROTATE_IMPL (__half) 4592#endif 4593 4594// Special handling for boolean vectors (requires int conversion) 4595__device__ __forceinline__ bool2 _slang_waveRotate (bool2 value, unsigned int delta) 4596{ 4597int2 intValue = make_int2 (( int )value. x , ( int )value. y ); 4598int2 result = _slang_waveRotate (intValue, delta); 4599return make_bool2 (( bool )result. x , ( bool )result. y ); 4600} 4601 4602__device__ __forceinline__ bool3 _slang_waveRotate ( bool3 value, unsigned int delta) 4603{ 4604int3 intValue = make_int3 (( int )value. x , ( int )value. y , ( int )value. z ); 4605int3 result = _slang_waveRotate (intValue, delta); 4606return make_bool3 (( bool )result. x , ( bool )result. y , ( bool )result. z ); 4607} 4608 4609__device__ __forceinline__ bool4 _slang_waveRotate ( bool4 value, unsigned int delta) 4610{ 4611int4 intValue = make_int4 (( int )value. x , ( int )value. y , ( int )value. z , ( int )value. w ); 4612int4 result = _slang_waveRotate (intValue, delta); 4613return make_bool4 (( bool )result. x , ( bool )result. y , ( bool )result. z , ( bool )result. w ); 4614} 4615 4616#undef SLANG_WAVE_ROTATE_IMPL 4617 4618// Quad control operations for CUDA 4619__device__ __forceinline__ bool _slang_quadAny ( bool expr) 4620{ 4621// Get values from all 4 lanes in the quad 4622bool v0 = __shfl_sync ( 0xFFFFFFFF , expr, ( _getLaneId () & 0xFFFFFFFC ) | 0 ); 4623bool v1 = __shfl_sync ( 0xFFFFFFFF , expr, ( _getLaneId () & 0xFFFFFFFC ) | 1 ); 4624bool v2 = __shfl_sync ( 0xFFFFFFFF , expr, ( _getLaneId () & 0xFFFFFFFC ) | 2 ); 4625bool v3 = __shfl_sync ( 0xFFFFFFFF , expr, ( _getLaneId () & 0xFFFFFFFC ) | 3 ); 4626return v0 || v1 || v2 || v3; 4627} 4628 4629__device__ __forceinline__ bool _slang_quadAll ( bool expr) 4630{ 4631// Get values from all 4 lanes in the quad 4632bool v0 = __shfl_sync ( 0xFFFFFFFF , expr, ( _getLaneId () & 0xFFFFFFFC ) | 0 ); 4633bool v1 = __shfl_sync ( 0xFFFFFFFF , expr, ( _getLaneId () & 0xFFFFFFFC ) | 1 ); 4634bool v2 = __shfl_sync ( 0xFFFFFFFF , expr, ( _getLaneId () & 0xFFFFFFFC ) | 2 ); 4635bool v3 = __shfl_sync ( 0xFFFFFFFF , expr, ( _getLaneId () & 0xFFFFFFFC ) | 3 ); 4636return v0 && v1 && v2 && v3; 4637} 4638 4639// Clustered wave rotate operations for CUDA 4640// Clustered rotate rotates values within clusters of specified size 4641#define SLANG_WAVE_CLUSTERED_ROTATE_IMPL ( T ) \ 4642__device__ __forceinline__ T \ 4643_slang_waveClusteredRotate(T value, unsigned int delta, unsigned int clusterSize) \ 4644{ \ 4645unsigned int laneId = _getLaneId(); \ 4646unsigned int clusterStart = (laneId / clusterSize) * clusterSize; \ 4647unsigned int targetLane = clusterStart + ((laneId - clusterStart + delta) % clusterSize); \ 4648return __shfl_sync(SLANG_WARP_FULL_MASK, value, targetLane); \ 4649} \ 4650__device__ __forceinline__ \ 4651T##2 _slang_waveClusteredRotate(T##2 value, unsigned int delta, unsigned int clusterSize) \ 4652{ \ 4653unsigned int laneId = _getLaneId(); \ 4654unsigned int clusterStart = (laneId / clusterSize) * clusterSize; \ 4655unsigned int targetLane = clusterStart + ((laneId - clusterStart + delta) % clusterSize); \ 4656return make_##T##2( \ 4657(T)__shfl_sync(SLANG_WARP_FULL_MASK, value.x, targetLane), \ 4658(T)__shfl_sync(SLANG_WARP_FULL_MASK, value.y, targetLane)); \ 4659} \ 4660__device__ __forceinline__ \ 4661T##3 _slang_waveClusteredRotate(T##3 value, unsigned int delta, unsigned int clusterSize) \ 4662{ \ 4663unsigned int laneId = _getLaneId(); \ 4664unsigned int clusterStart = (laneId / clusterSize) * clusterSize; \ 4665unsigned int targetLane = clusterStart + ((laneId - clusterStart + delta) % clusterSize); \ 4666return make_##T##3( \ 4667(T)__shfl_sync(SLANG_WARP_FULL_MASK, value.x, targetLane), \ 4668(T)__shfl_sync(SLANG_WARP_FULL_MASK, value.y, targetLane), \ 4669(T)__shfl_sync(SLANG_WARP_FULL_MASK, value.z, targetLane)); \ 4670} \ 4671__device__ __forceinline__ \ 4672T##4 _slang_waveClusteredRotate(T##4 value, unsigned int delta, unsigned int clusterSize) \ 4673{ \ 4674unsigned int laneId = _getLaneId(); \ 4675unsigned int clusterStart = (laneId / clusterSize) * clusterSize; \ 4676unsigned int targetLane = clusterStart + ((laneId - clusterStart + delta) % clusterSize); \ 4677return make_##T##4( \ 4678(T)__shfl_sync(SLANG_WARP_FULL_MASK, value.x, targetLane), \ 4679(T)__shfl_sync(SLANG_WARP_FULL_MASK, value.y, targetLane), \ 4680(T)__shfl_sync(SLANG_WARP_FULL_MASK, value.z, targetLane), \ 4681(T)__shfl_sync(SLANG_WARP_FULL_MASK, value.w, targetLane)); \ 4682} 4683 4684// Generate clustered wave rotate functions for all standard types 4685SLANG_WAVE_CLUSTERED_ROTATE_IMPL ( uint ) 4686SLANG_WAVE_CLUSTERED_ROTATE_IMPL ( int ) 4687SLANG_WAVE_CLUSTERED_ROTATE_IMPL (float) 4688SLANG_WAVE_CLUSTERED_ROTATE_IMPL (short) 4689SLANG_WAVE_CLUSTERED_ROTATE_IMPL (ushort) 4690SLANG_WAVE_CLUSTERED_ROTATE_IMPL (char) 4691SLANG_WAVE_CLUSTERED_ROTATE_IMPL (uchar) 4692SLANG_WAVE_CLUSTERED_ROTATE_IMPL (longlong) 4693SLANG_WAVE_CLUSTERED_ROTATE_IMPL (ulonglong) 4694 4695#ifdef SLANG_CUDA_ENABLE_HALF 4696SLANG_WAVE_CLUSTERED_ROTATE_IMPL (__half) 4697#endif 4698 4699// Special handling for boolean clustered rotate 4700__device__ __forceinline__ bool _slang_waveClusteredRotate ( 4701bool value, 4702unsigned int delta, 4703unsigned int clusterSize) 4704{ 4705int intValue = ( int )value; 4706int result = _slang_waveClusteredRotate (intValue, delta, clusterSize); 4707return ( bool )result; 4708} 4709 4710__device__ __forceinline__ bool2 4711_slang_waveClusteredRotate ( bool2 value, unsigned int delta, unsigned int clusterSize) 4712{ 4713int2 intValue = make_int2 (( int )value. x , ( int )value. y ); 4714int2 result = _slang_waveClusteredRotate (intValue, delta, clusterSize); 4715return make_bool2 (( bool )result. x , ( bool )result. y ); 4716} 4717 4718__device__ __forceinline__ bool3 4719_slang_waveClusteredRotate ( bool3 value, unsigned int delta, unsigned int clusterSize) 4720{ 4721int3 intValue = make_int3 (( int )value. x , ( int )value. y , ( int )value. z ); 4722int3 result = _slang_waveClusteredRotate (intValue, delta, clusterSize); 4723return make_bool3 (( bool )result. x , ( bool )result. y , ( bool )result. z ); 4724} 4725 4726__device__ __forceinline__ bool4 4727_slang_waveClusteredRotate ( bool4 value, unsigned int delta, unsigned int clusterSize) 4728{ 4729int4 intValue = make_int4 (( int )value. x , ( int )value. y , ( int )value. z , ( int )value. w ); 4730int4 result = _slang_waveClusteredRotate (intValue, delta, clusterSize); 4731return make_bool4 (( bool )result. x , ( bool )result. y , ( bool )result. z , ( bool )result. w ); 4732} 4733 4734#undef SLANG_WAVE_CLUSTERED_ROTATE_IMPL