yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
3639e71df
master
1// cuda-device.cpp 2#include "cuda-device.h" 3 4#include "cuda-buffer.h" 5#include "cuda-command-queue.h" 6#include "cuda-pipeline-state.h" 7#include "cuda-query.h" 8#include "cuda-resource-views.h" 9#include "cuda-shader-object-layout.h" 10#include "cuda-shader-object.h" 11#include "cuda-shader-program.h" 12#include "cuda-texture.h" 13 14namespace gfx 15{ 16#ifdef GFX_ENABLE_CUDA 17using namespace Slang ; 18 19namespace cuda 20{ 21 22int DeviceImpl ::_calcSMCountPerMultiProcessor (int major ,int minor ) 23{ 24// Defines for GPU Architecture types (using the SM version to determine 25// the # of cores per SM 26struct SMInfo 27 { 28int sm ;// 0xMm (hexadecimal notation), M = SM Major version, and m = SM minor version 29int coreCount ; 30 }; 31 32static const SMInfo infos []= { 33 {0x30 ,192 }, 34 {0x32 ,192 }, 35 {0x35 ,192 }, 36 {0x37 ,192 }, 37 {0x50 ,128 }, 38 {0x52 ,128 }, 39 {0x53 ,128 }, 40 {0x60 ,64 }, 41 {0x61 ,128 }, 42 {0x62 ,128 }, 43 {0x70 ,64 }, 44 {0x72 ,64 }, 45 {0x75 ,64 }}; 46 47const int sm = ((major <<4 )+ minor ); 48for (Index i = 0 ;i < SLANG_COUNT_OF (infos );++ i ) 49 { 50if (infos [i ].sm == sm ) 51 { 52return infos [i ].coreCount ; 53 } 54 } 55 56const auto & last = infos [SLANG_COUNT_OF (infos )- 1 ]; 57 58// It must be newer presumably 59SLANG_ASSERT (sm > last .sm ); 60 61// Default to the last entry 62return last .coreCount ; 63} 64 65SlangResult DeviceImpl ::_findMaxFlopsDeviceIndex (int * outDeviceIndex ) 66{ 67int smPerMultiproc = 0 ; 68int maxPerfDevice = -1 ; 69int deviceCount = 0 ; 70int devicesProhibited = 0 ; 71 72uint64_t maxComputePerf = 0 ; 73SLANG_CUDA_RETURN_ON_FAIL (cuDeviceGetCount (& deviceCount )); 74 75// Find the best CUDA capable GPU device 76for (int currentDevice = 0 ;currentDevice < deviceCount ;++ currentDevice ) 77 { 78CUdevice device ; 79SLANG_CUDA_RETURN_ON_FAIL (cuDeviceGet (& device ,currentDevice )); 80int computeMode = -1 ,major = 0 ,minor = 0 ; 81SLANG_CUDA_RETURN_ON_FAIL ( 82cuDeviceGetAttribute (& computeMode ,CU_DEVICE_ATTRIBUTE_COMPUTE_MODE ,device )); 83SLANG_CUDA_RETURN_ON_FAIL ( 84cuDeviceGetAttribute (& major ,CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR ,device )); 85SLANG_CUDA_RETURN_ON_FAIL ( 86cuDeviceGetAttribute (& minor ,CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR ,device )); 87 88// If this GPU is not running on Compute Mode prohibited, 89// then we can add it to the list 90if (computeMode != CU_COMPUTEMODE_PROHIBITED ) 91 { 92if (major == 9999 && minor == 9999 ) 93 { 94smPerMultiproc = 1 ; 95 } 96else 97 { 98smPerMultiproc = _calcSMCountPerMultiProcessor (major ,minor ); 99 } 100 101int multiProcessorCount = 0 ,clockRate = 0 ; 102SLANG_CUDA_RETURN_ON_FAIL (cuDeviceGetAttribute ( 103& multiProcessorCount , 104CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT , 105device )); 106SLANG_CUDA_RETURN_ON_FAIL ( 107cuDeviceGetAttribute (& clockRate ,CU_DEVICE_ATTRIBUTE_CLOCK_RATE ,device )); 108uint64_t compute_perf = uint64_t (multiProcessorCount )* smPerMultiproc * clockRate ; 109 110if (compute_perf > maxComputePerf ) 111 { 112maxComputePerf = compute_perf ; 113maxPerfDevice = currentDevice ; 114 } 115 } 116else 117 { 118devicesProhibited ++ ; 119 } 120 } 121 122if (maxPerfDevice < 0 ) 123 { 124return SLANG_FAIL ; 125 } 126 127* outDeviceIndex = maxPerfDevice ; 128return SLANG_OK ; 129} 130 131SlangResult DeviceImpl ::_initCuda (CUDAReportStyle reportType ) 132{ 133static CUresult res = cuInit (0 ); 134SLANG_CUDA_RETURN_WITH_REPORT_ON_FAIL (res ,reportType ); 135return SLANG_OK ; 136} 137 138SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::getNativeDeviceHandles (InteropHandles * outHandles ) 139{ 140outHandles -> handles [0 ].handleValue = (uint64_t )m_device ; 141outHandles -> handles [0 ].api = InteropHandleAPI ::CUDA ; 142return SLANG_OK ; 143} 144 145SLANG_NO_THROW SlangResult SLANG_MCALL DeviceImpl ::initialize (const Desc & desc ) 146{ 147SLANG_RETURN_ON_FAIL (slangContext .initialize ( 148desc .slang , 149desc .extendedDescCount , 150desc .extendedDescs , 151SLANG_PTX , 152"cuda_sm_5_0" , 153makeArray (slang::PreprocessorMacroDesc {"__CUDA_COMPUTE__" ,"1" }).getView ())); 154 155SLANG_RETURN_ON_FAIL (RendererBase ::initialize (desc )); 156 157SLANG_RETURN_ON_FAIL (_initCuda (reportType )); 158 159if (desc .adapterLUID ) 160 { 161int deviceCount = -1 ; 162cuDeviceGetCount (& deviceCount ); 163for (int deviceIndex = 0 ;deviceIndex < deviceCount ;++ deviceIndex ) 164 { 165if (cuda::getAdapterLUID (deviceIndex )== * desc .adapterLUID ) 166 { 167m_deviceIndex = deviceIndex ; 168break ; 169 } 170 } 171if (m_deviceIndex >=deviceCount ) 172return SLANG_E_INVALID_ARG ; 173 } 174else 175 { 176SLANG_RETURN_ON_FAIL (_findMaxFlopsDeviceIndex (& m_deviceIndex )); 177 } 178 179m_context = new CUDAContext (); 180 181SLANG_CUDA_RETURN_ON_FAIL (cuDeviceGet (& m_device ,m_deviceIndex )); 182 183// Use version-aware context creation that works with both CUDA 12 and CUDA 13 184SLANG_CUDA_RETURN_WITH_REPORT_ON_FAIL ( 185createCudaContext (& m_context -> m_context ,0 ,m_device ), 186reportType ); 187 188 { 189// Not clear how to detect half support on CUDA. For now we'll assume we have it 190m_features .add ("half" ); 191 192// CUDA has support for realtime clock 193m_features .add ("realtime-clock" ); 194 195// Allows use of a ptr like type 196m_features .add ("has-ptr" ); 197 } 198 199// Initialize DeviceInfo 200 { 201m_info .deviceType = DeviceType ::CUDA ; 202m_info .bindingStyle = BindingStyle ::CUDA ; 203m_info .projectionStyle = ProjectionStyle ::DirectX ; 204m_info .apiName = "CUDA" ; 205static const float kIdentity []= {1 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,1 }; 206 ::memcpy (m_info .identityProjectionMatrix ,kIdentity ,sizeof (kIdentity )); 207char deviceName [256 ]; 208cuDeviceGetName (deviceName ,sizeof (deviceName ),m_device ); 209m_adapterName = deviceName ; 210m_info .adapterName = m_adapterName .begin (); 211m_info .timestampFrequency = 1000000 ; 212 } 213 214// Get device limits. 215 { 216CUresult lastResult = CUDA_SUCCESS ; 217auto getAttribute = [& ](CUdevice_attribute attribute )-> int 218 { 219int value ; 220CUresult result = cuDeviceGetAttribute (& value ,attribute ,m_device ); 221if (result != CUDA_SUCCESS ) 222lastResult = result ; 223return value ; 224 }; 225 226DeviceLimits limits = {}; 227 228limits .maxTextureDimension1D = getAttribute (CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE1D_WIDTH ); 229limits .maxTextureDimension2D = Math ::Min ( 230getAttribute (CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE2D_WIDTH ), 231getAttribute (CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE2D_HEIGHT )); 232limits .maxTextureDimension3D = Math ::Min ( 233getAttribute (CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE3D_WIDTH ), 234Math ::Min ( 235getAttribute (CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE3D_HEIGHT ), 236getAttribute (CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE3D_DEPTH ))); 237limits .maxTextureDimensionCube = 238getAttribute (CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACECUBEMAP_WIDTH ); 239limits .maxTextureArrayLayers = Math ::Min ( 240getAttribute (CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE1D_LAYERED_LAYERS ), 241getAttribute (CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE2D_LAYERED_LAYERS )); 242 243// limits.maxVertexInputElements 244// limits.maxVertexInputElementOffset 245// limits.maxVertexStreams 246// limits.maxVertexStreamStride 247 248limits .maxComputeThreadsPerGroup = getAttribute (CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK ); 249limits .maxComputeThreadGroupSize [0 ]= getAttribute (CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X ); 250limits .maxComputeThreadGroupSize [1 ]= getAttribute (CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Y ); 251limits .maxComputeThreadGroupSize [2 ]= getAttribute (CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Z ); 252limits .maxComputeDispatchThreadGroups [0 ]= getAttribute (CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X ); 253limits .maxComputeDispatchThreadGroups [1 ]= getAttribute (CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Y ); 254limits .maxComputeDispatchThreadGroups [2 ]= getAttribute (CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Z ); 255 256// limits.maxViewports 257// limits.maxViewportDimensions 258// limits.maxFramebufferDimensions 259 260// limits.maxShaderVisibleSamplers 261 262m_info .limits = limits ; 263 264SLANG_CUDA_RETURN_ON_FAIL (lastResult ); 265 } 266 267return SLANG_OK ; 268} 269 270Result DeviceImpl ::getCUDAFormat (Format format ,CUarray_format * outFormat ) 271{ 272// TODO: Expand to cover all available formats that can be supported in CUDA 273switch (format ) 274 { 275case Format ::R32G32B32A32_FLOAT : 276case Format ::R32G32B32_FLOAT : 277case Format ::R32G32_FLOAT : 278case Format ::R32_FLOAT : 279case Format ::D32_FLOAT : 280* outFormat = CU_AD_FORMAT_FLOAT ; 281return SLANG_OK ; 282case Format ::R16G16B16A16_FLOAT : 283case Format ::R16G16_FLOAT : 284case Format ::R16_FLOAT : 285* outFormat = CU_AD_FORMAT_HALF ; 286return SLANG_OK ; 287case Format ::R32G32B32A32_UINT : 288case Format ::R32G32B32_UINT : 289case Format ::R32G32_UINT : 290case Format ::R32_UINT : 291* outFormat = CU_AD_FORMAT_UNSIGNED_INT32 ; 292return SLANG_OK ; 293case Format ::R16G16B16A16_UINT : 294case Format ::R16G16_UINT : 295case Format ::R16_UINT : 296* outFormat = CU_AD_FORMAT_UNSIGNED_INT16 ; 297return SLANG_OK ; 298case Format ::R8G8B8A8_UINT : 299case Format ::R8G8_UINT : 300case Format ::R8_UINT : 301case Format ::R8G8B8A8_UNORM : 302* outFormat = CU_AD_FORMAT_UNSIGNED_INT8 ; 303return SLANG_OK ; 304case Format ::R32G32B32A32_SINT : 305case Format ::R32G32B32_SINT : 306case Format ::R32G32_SINT : 307case Format ::R32_SINT : 308* outFormat = CU_AD_FORMAT_SIGNED_INT32 ; 309return SLANG_OK ; 310case Format ::R16G16B16A16_SINT : 311case Format ::R16G16_SINT : 312case Format ::R16_SINT : 313* outFormat = CU_AD_FORMAT_SIGNED_INT16 ; 314return SLANG_OK ; 315case Format ::R8G8B8A8_SINT : 316case Format ::R8G8_SINT : 317case Format ::R8_SINT : 318* outFormat = CU_AD_FORMAT_SIGNED_INT8 ; 319return SLANG_OK ; 320default : 321SLANG_ASSERT (!"Only support R32_FLOAT/R8G8B8A8_UNORM formats for now" ); 322return SLANG_FAIL ; 323 } 324} 325 326SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createTextureResource ( 327const ITextureResource ::Desc & desc , 328const ITextureResource ::SubresourceData * initData , 329ITextureResource ** outResource ) 330{ 331TextureResource ::Desc srcDesc = fixupTextureDesc (desc ); 332 333RefPtr < TextureResourceImpl > tex = new TextureResourceImpl (srcDesc ); 334tex -> m_cudaContext = m_context ; 335 336CUresourcetype resourceType ; 337 338// The size of the element/texel in bytes 339size_t elementSize = 0 ; 340 341// Our `ITextureResource::Desc` uses an enumeration to specify 342// the "shape"/rank of a texture (1D, 2D, 3D, Cube), but CUDA's 343// `cuMipmappedArrayCreate` seemingly relies on a policy where 344// the extents of the array in dimenions above the rank are 345// specified as zero (e.g., a 1D texture requires `height==0`). 346// 347// We will start by massaging the extents as specified by the 348// user into a form that CUDA wants/expects, based on the 349// texture shape as specified in the `desc`. 350// 351int width = desc .size .width ; 352int height = desc .size .height ; 353int depth = desc .size .depth ; 354switch (desc .type ) 355 { 356case IResource ::Type ::Texture1D : 357height = 0 ; 358depth = 0 ; 359break ; 360 361case IResource ::Type ::Texture2D : 362depth = 0 ; 363break ; 364 365case IResource ::Type ::Texture3D : 366break ; 367 368case IResource ::Type ::TextureCube : 369depth = 1 ; 370break ; 371 } 372 373 { 374CUarray_format format = CU_AD_FORMAT_FLOAT ; 375int numChannels = 0 ; 376 377SLANG_RETURN_ON_FAIL (getCUDAFormat (desc .format ,& format )); 378FormatInfo info ; 379gfxGetFormatInfo (desc .format ,& info ); 380numChannels = info .channelCount ; 381 382switch (format ) 383 { 384case CU_AD_FORMAT_FLOAT : 385 { 386elementSize = sizeof (float )* numChannels ; 387break ; 388 } 389case CU_AD_FORMAT_HALF : 390 { 391elementSize = sizeof (uint16_t )* numChannels ; 392break ; 393 } 394case CU_AD_FORMAT_UNSIGNED_INT8 : 395 { 396elementSize = sizeof (uint8_t )* numChannels ; 397break ; 398 } 399default : 400 { 401SLANG_ASSERT (!"Only support R32_FLOAT/R8G8B8A8_UNORM formats for now" ); 402return SLANG_FAIL ; 403 } 404 } 405 406if (desc .numMipLevels > 1 ) 407 { 408resourceType = CU_RESOURCE_TYPE_MIPMAPPED_ARRAY ; 409 410CUDA_ARRAY3D_DESCRIPTOR arrayDesc ; 411memset (& arrayDesc ,0 ,sizeof (arrayDesc )); 412 413arrayDesc .Width = width ; 414arrayDesc .Height = height ; 415arrayDesc .Depth = depth ; 416arrayDesc .Format = format ; 417arrayDesc .NumChannels = numChannels ; 418arrayDesc .Flags = 0 ; 419 420if (desc .arraySize > 1 ) 421 { 422if (desc .type == IResource ::Type ::Texture1D || 423desc .type == IResource ::Type ::Texture2D || 424desc .type == IResource ::Type ::TextureCube ) 425 { 426arrayDesc .Flags |=CUDA_ARRAY3D_LAYERED ; 427arrayDesc .Depth = desc .arraySize ; 428 } 429else 430 { 431SLANG_ASSERT (!"Arrays only supported for 1D and 2D" ); 432return SLANG_FAIL ; 433 } 434 } 435 436if (desc .type == IResource ::Type ::TextureCube ) 437 { 438arrayDesc .Flags |=CUDA_ARRAY3D_CUBEMAP ; 439arrayDesc .Depth *=6 ; 440 } 441 442SLANG_CUDA_RETURN_ON_FAIL ( 443cuMipmappedArrayCreate (& tex -> m_cudaMipMappedArray ,& arrayDesc ,desc .numMipLevels )); 444 } 445else 446 { 447resourceType = CU_RESOURCE_TYPE_ARRAY ; 448 449if (desc .arraySize > 1 ) 450 { 451if (desc .type == IResource ::Type ::Texture1D || 452desc .type == IResource ::Type ::Texture2D || 453desc .type == IResource ::Type ::TextureCube ) 454 { 455SLANG_ASSERT (!"Only 1D, 2D and Cube arrays supported" ); 456return SLANG_FAIL ; 457 } 458 459CUDA_ARRAY3D_DESCRIPTOR arrayDesc ; 460memset (& arrayDesc ,0 ,sizeof (arrayDesc )); 461 462// Set the depth as the array length 463arrayDesc .Depth = desc .arraySize ; 464if (desc .type == IResource ::Type ::TextureCube ) 465 { 466arrayDesc .Depth *=6 ; 467 } 468 469arrayDesc .Height = height ; 470arrayDesc .Width = width ; 471arrayDesc .Format = format ; 472arrayDesc .NumChannels = numChannels ; 473 474if (desc .type == IResource ::Type ::TextureCube ) 475 { 476arrayDesc .Flags |=CUDA_ARRAY3D_CUBEMAP ; 477 } 478 479SLANG_CUDA_RETURN_ON_FAIL (cuArray3DCreate (& tex -> m_cudaArray ,& arrayDesc )); 480 } 481else if ( 482desc .type == IResource ::Type ::Texture3D || 483desc .type == IResource ::Type ::TextureCube ) 484 { 485CUDA_ARRAY3D_DESCRIPTOR arrayDesc ; 486memset (& arrayDesc ,0 ,sizeof (arrayDesc )); 487 488arrayDesc .Depth = depth ; 489arrayDesc .Height = height ; 490arrayDesc .Width = width ; 491arrayDesc .Format = format ; 492arrayDesc .NumChannels = numChannels ; 493 494arrayDesc .Flags = 0 ; 495 496// Handle cube texture 497if (desc .type == IResource ::Type ::TextureCube ) 498 { 499arrayDesc .Depth = 6 ; 500arrayDesc .Flags |=CUDA_ARRAY3D_CUBEMAP ; 501 } 502 503SLANG_CUDA_RETURN_ON_FAIL (cuArray3DCreate (& tex -> m_cudaArray ,& arrayDesc )); 504 } 505else 506 { 507CUDA_ARRAY_DESCRIPTOR arrayDesc ; 508memset (& arrayDesc ,0 ,sizeof (arrayDesc )); 509 510arrayDesc .Height = height ; 511arrayDesc .Width = width ; 512arrayDesc .Format = format ; 513arrayDesc .NumChannels = numChannels ; 514 515// Allocate the array, will work for 1D or 2D case 516SLANG_CUDA_RETURN_ON_FAIL (cuArrayCreate (& tex -> m_cudaArray ,& arrayDesc )); 517 } 518 } 519 } 520 521// Work space for holding data for uploading if it needs to be rearranged 522if (initData ) 523 { 524List < uint8_t > workspace ; 525for (int mipLevel = 0 ;mipLevel < desc .numMipLevels ;++ mipLevel ) 526 { 527int mipWidth = width >>mipLevel ; 528int mipHeight = height >>mipLevel ; 529int mipDepth = depth >>mipLevel ; 530 531mipWidth = (mipWidth == 0 ) ?1 :mipWidth ; 532mipHeight = (mipHeight == 0 ) ?1 :mipHeight ; 533mipDepth = (mipDepth == 0 ) ?1 :mipDepth ; 534 535// If it's a cubemap then the depth is always 6 536if (desc .type == IResource ::Type ::TextureCube ) 537 { 538mipDepth = 6 ; 539 } 540 541auto dstArray = tex -> m_cudaArray ; 542if (tex -> m_cudaMipMappedArray ) 543 { 544// Get the array for the mip level 545SLANG_CUDA_RETURN_ON_FAIL ( 546cuMipmappedArrayGetLevel (& dstArray ,tex -> m_cudaMipMappedArray ,mipLevel )); 547 } 548SLANG_ASSERT (dstArray ); 549 550// Check using the desc to see if it's plausible 551 { 552CUDA_ARRAY_DESCRIPTOR arrayDesc ; 553SLANG_CUDA_RETURN_ON_FAIL (cuArrayGetDescriptor (& arrayDesc ,dstArray )); 554 555SLANG_ASSERT (mipWidth == arrayDesc .Width ); 556SLANG_ASSERT ( 557mipHeight == arrayDesc .Height || (mipHeight == 1 && arrayDesc .Height == 0 )); 558 } 559 560const void * srcDataPtr = nullptr ; 561 562if (desc .arraySize > 1 ) 563 { 564SLANG_ASSERT ( 565desc .type == IResource ::Type ::Texture1D || 566desc .type == IResource ::Type ::Texture2D || 567desc .type == IResource ::Type ::TextureCube ); 568 569// TODO(JS): Here I assume that arrays are just held contiguously within a 570// 'face' This seems reasonable and works with the Copy3D. 571const size_t faceSizeInBytes = elementSize * mipWidth * mipHeight ; 572 573Index faceCount = desc .arraySize ; 574if (desc .type == IResource ::Type ::TextureCube ) 575 { 576faceCount *=6 ; 577 } 578 579const size_t mipSizeInBytes = faceSizeInBytes * faceCount ; 580workspace .setCount (mipSizeInBytes ); 581 582// We need to add the face data from each mip 583// We iterate over face count so we copy all of the cubemap faces 584for (Index j = 0 ;j < faceCount ;j ++ ) 585 { 586const auto srcData = initData [mipLevel + j * desc .numMipLevels ].data ; 587// Copy over to the workspace to make contiguous 588 ::memcpy (workspace .begin ()+ faceSizeInBytes * j ,srcData ,faceSizeInBytes ); 589 } 590 591srcDataPtr = workspace .getBuffer (); 592 } 593else 594 { 595if (desc .type == IResource ::Type ::TextureCube ) 596 { 597size_t faceSizeInBytes = elementSize * mipWidth * mipHeight ; 598 599workspace .setCount (faceSizeInBytes * 6 ); 600// Copy the data over to make contiguous 601for (Index j = 0 ;j < 6 ;j ++ ) 602 { 603const auto srcData = initData [mipLevel + j * desc .numMipLevels ].data ; 604 ::memcpy ( 605workspace .getBuffer ()+ faceSizeInBytes * j , 606srcData , 607faceSizeInBytes ); 608 } 609srcDataPtr = workspace .getBuffer (); 610 } 611else 612 { 613const auto srcData = initData [mipLevel ].data ; 614srcDataPtr = srcData ; 615 } 616 } 617 618if (desc .arraySize > 1 ) 619 { 620SLANG_ASSERT ( 621desc .type == IResource ::Type ::Texture1D || 622desc .type == IResource ::Type ::Texture2D || 623desc .type == IResource ::Type ::TextureCube ); 624 625CUDA_MEMCPY3D copyParam ; 626memset (& copyParam ,0 ,sizeof (copyParam )); 627 628copyParam .dstMemoryType = CU_MEMORYTYPE_ARRAY ; 629copyParam .dstArray = dstArray ; 630 631copyParam .srcMemoryType = CU_MEMORYTYPE_HOST ; 632copyParam .srcHost = srcDataPtr ; 633copyParam .srcPitch = mipWidth * elementSize ; 634copyParam .WidthInBytes = copyParam .srcPitch ; 635copyParam .Height = mipHeight ; 636// Set the depth to the array length 637copyParam .Depth = desc .arraySize ; 638 639if (desc .type == IResource ::Type ::TextureCube ) 640 { 641copyParam .Depth *=6 ; 642 } 643 644SLANG_CUDA_RETURN_ON_FAIL (cuMemcpy3D (& copyParam )); 645 } 646else 647 { 648switch (desc .type ) 649 { 650case IResource ::Type ::Texture1D : 651case IResource ::Type ::Texture2D : 652 { 653CUDA_MEMCPY2D copyParam ; 654memset (& copyParam ,0 ,sizeof (copyParam )); 655copyParam .dstMemoryType = CU_MEMORYTYPE_ARRAY ; 656copyParam .dstArray = dstArray ; 657copyParam .srcMemoryType = CU_MEMORYTYPE_HOST ; 658copyParam .srcHost = srcDataPtr ; 659copyParam .srcPitch = mipWidth * elementSize ; 660copyParam .WidthInBytes = copyParam .srcPitch ; 661copyParam .Height = mipHeight ; 662SLANG_CUDA_RETURN_ON_FAIL (cuMemcpy2D (& copyParam )); 663break ; 664 } 665case IResource ::Type ::Texture3D : 666case IResource ::Type ::TextureCube : 667 { 668CUDA_MEMCPY3D copyParam ; 669memset (& copyParam ,0 ,sizeof (copyParam )); 670 671copyParam .dstMemoryType = CU_MEMORYTYPE_ARRAY ; 672copyParam .dstArray = dstArray ; 673 674copyParam .srcMemoryType = CU_MEMORYTYPE_HOST ; 675copyParam .srcHost = srcDataPtr ; 676copyParam .srcPitch = mipWidth * elementSize ; 677copyParam .WidthInBytes = copyParam .srcPitch ; 678copyParam .Height = mipHeight ; 679copyParam .Depth = mipDepth ; 680 681SLANG_CUDA_RETURN_ON_FAIL (cuMemcpy3D (& copyParam )); 682break ; 683 } 684 685default : 686 { 687SLANG_ASSERT (!"Not implemented" ); 688break ; 689 } 690 } 691 } 692 } 693 } 694// Set up texture sampling parameters, and create final texture obj 695 696 { 697CUDA_RESOURCE_DESC resDesc ; 698memset (& resDesc ,0 ,sizeof (CUDA_RESOURCE_DESC )); 699resDesc .resType = resourceType ; 700 701if (tex -> m_cudaArray ) 702 { 703resDesc .res .array .hArray = tex -> m_cudaArray ; 704 } 705if (tex -> m_cudaMipMappedArray ) 706 { 707resDesc .res .mipmap .hMipmappedArray = tex -> m_cudaMipMappedArray ; 708 } 709 710// If the texture might be used as a UAV, then we need to allocate 711// a CUDA "surface" for it. 712// 713// Note: We cannot do this unconditionally, because it will fail 714// on surfaces that are not usable as UAVs (e.g., those with 715// mipmaps). 716// 717// TODO: We should really only be allocating the array at the 718// time we create a resource, and then allocate the surface or 719// texture objects as part of view creation. 720// 721if (desc .allowedStates .contains (ResourceState ::UnorderedAccess )) 722 { 723// On CUDA surfaces only support a single MIP map 724SLANG_ASSERT (desc .numMipLevels == 1 ); 725 726SLANG_CUDA_RETURN_ON_FAIL (cuSurfObjectCreate (& tex -> m_cudaSurfObj ,& resDesc )); 727 } 728 729 730// Create handle for sampling. 731CUDA_TEXTURE_DESC texDesc ; 732memset (& texDesc ,0 ,sizeof (CUDA_TEXTURE_DESC )); 733texDesc .addressMode [0 ]= CU_TR_ADDRESS_MODE_WRAP ; 734texDesc .addressMode [1 ]= CU_TR_ADDRESS_MODE_WRAP ; 735texDesc .addressMode [2 ]= CU_TR_ADDRESS_MODE_WRAP ; 736texDesc .filterMode = CU_TR_FILTER_MODE_LINEAR ; 737texDesc .flags = CU_TRSF_NORMALIZED_COORDINATES ; 738 739SLANG_CUDA_RETURN_ON_FAIL ( 740cuTexObjectCreate (& tex -> m_cudaTexObj ,& resDesc ,& texDesc ,nullptr )); 741 } 742 743returnComPtr (outResource ,tex ); 744return SLANG_OK ; 745} 746 747SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createBufferResource ( 748const IBufferResource ::Desc & descIn , 749const void * initData , 750IBufferResource ** outResource ) 751{ 752auto desc = fixupBufferDesc (descIn ); 753RefPtr < BufferResourceImpl > resource = new BufferResourceImpl (desc ); 754resource -> m_cudaContext = m_context ; 755SLANG_CUDA_RETURN_ON_FAIL (cuMemAllocManaged ( 756 (CUdeviceptr * )(& resource -> m_cudaMemory ), 757desc .sizeInBytes , 758CU_MEM_ATTACH_GLOBAL )); 759if (initData ) 760 { 761SLANG_CUDA_RETURN_ON_FAIL ( 762cuMemcpy ((CUdeviceptr )resource -> m_cudaMemory , (CUdeviceptr )initData ,desc .sizeInBytes )); 763 } 764returnComPtr (outResource ,resource ); 765return SLANG_OK ; 766} 767 768SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createBufferFromSharedHandle ( 769InteropHandle handle , 770const IBufferResource ::Desc & desc , 771IBufferResource ** outResource ) 772{ 773if (handle .handleValue == 0 ) 774 { 775* outResource = nullptr ; 776return SLANG_OK ; 777 } 778 779RefPtr < BufferResourceImpl > resource = new BufferResourceImpl (desc ); 780resource -> m_cudaContext = m_context ; 781 782// CUDA manages sharing of buffers through the idea of an 783// "external memory" object, which represents the relationship 784// with another API's objects. In order to create this external 785// memory association, we first need to fill in a descriptor struct. 786CUDA_EXTERNAL_MEMORY_HANDLE_DESC externalMemoryHandleDesc ; 787memset (& externalMemoryHandleDesc ,0 ,sizeof (externalMemoryHandleDesc )); 788switch (handle .api ) 789 { 790case InteropHandleAPI ::D3D12 : 791externalMemoryHandleDesc .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE ; 792break ; 793case InteropHandleAPI ::Vulkan : 794externalMemoryHandleDesc .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32 ; 795break ; 796default : 797return SLANG_FAIL ; 798 } 799externalMemoryHandleDesc .handle .win32 .handle = (void * )handle .handleValue ; 800externalMemoryHandleDesc .size = desc .sizeInBytes ; 801externalMemoryHandleDesc .flags = CUDA_EXTERNAL_MEMORY_DEDICATED ; 802 803// Once we have filled in the descriptor, we can request 804// that CUDA create the required association between the 805// external buffer and its own memory. 806CUexternalMemory externalMemory ; 807SLANG_CUDA_RETURN_ON_FAIL (cuImportExternalMemory (& externalMemory ,& externalMemoryHandleDesc )); 808resource -> m_cudaExternalMemory = externalMemory ; 809 810// The CUDA "external memory" handle is not itself a device 811// pointer, so we need to query for a suitable device address 812// for the buffer with another call. 813// 814// Just as for the external memory, we fill in a descriptor 815// structure (although in this case we only need to specify 816// the size). 817CUDA_EXTERNAL_MEMORY_BUFFER_DESC bufferDesc ; 818memset (& bufferDesc ,0 ,sizeof (bufferDesc )); 819bufferDesc .size = desc .sizeInBytes ; 820 821// Finally, we can "map" the buffer to get a device address. 822void * deviceAddress ; 823SLANG_CUDA_RETURN_ON_FAIL ( 824cuExternalMemoryGetMappedBuffer ((CUdeviceptr * )& deviceAddress ,externalMemory ,& bufferDesc )); 825resource -> m_cudaMemory = deviceAddress ; 826 827returnComPtr (outResource ,resource ); 828return SLANG_OK ; 829} 830 831SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createTextureFromSharedHandle ( 832InteropHandle handle , 833const ITextureResource ::Desc & desc , 834const size_t size , 835ITextureResource ** outResource ) 836{ 837if (handle .handleValue == 0 ) 838 { 839* outResource = nullptr ; 840return SLANG_OK ; 841 } 842 843RefPtr < TextureResourceImpl > resource = new TextureResourceImpl (desc ); 844resource -> m_cudaContext = m_context ; 845 846// CUDA manages sharing of buffers through the idea of an 847// "external memory" object, which represents the relationship 848// with another API's objects. In order to create this external 849// memory association, we first need to fill in a descriptor struct. 850CUDA_EXTERNAL_MEMORY_HANDLE_DESC externalMemoryHandleDesc ; 851memset (& externalMemoryHandleDesc ,0 ,sizeof (externalMemoryHandleDesc )); 852switch (handle .api ) 853 { 854case InteropHandleAPI ::D3D12 : 855externalMemoryHandleDesc .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE ; 856break ; 857case InteropHandleAPI ::Vulkan : 858externalMemoryHandleDesc .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32 ; 859break ; 860default : 861return SLANG_FAIL ; 862 } 863externalMemoryHandleDesc .handle .win32 .handle = (void * )handle .handleValue ; 864externalMemoryHandleDesc .size = size ; 865externalMemoryHandleDesc .flags = CUDA_EXTERNAL_MEMORY_DEDICATED ; 866 867CUexternalMemory externalMemory ; 868SLANG_CUDA_RETURN_ON_FAIL (cuImportExternalMemory (& externalMemory ,& externalMemoryHandleDesc )); 869resource -> m_cudaExternalMemory = externalMemory ; 870 871FormatInfo formatInfo ; 872SLANG_RETURN_ON_FAIL (gfxGetFormatInfo (desc .format ,& formatInfo )); 873CUDA_ARRAY3D_DESCRIPTOR arrayDesc ; 874arrayDesc .Depth = desc .size .depth ; 875arrayDesc .Height = desc .size .height ; 876arrayDesc .Width = desc .size .width ; 877arrayDesc .NumChannels = formatInfo .channelCount ; 878getCUDAFormat (desc .format ,& arrayDesc .Format ); 879arrayDesc .Flags = 0 ;// TODO: Flags? CUDA_ARRAY_LAYERED/SURFACE_LDST/CUBEMAP/TEXTURE_GATHER 880 881CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC externalMemoryMipDesc ; 882memset (& externalMemoryMipDesc ,0 ,sizeof (externalMemoryMipDesc )); 883externalMemoryMipDesc .offset = 0 ; 884externalMemoryMipDesc .arrayDesc = arrayDesc ; 885externalMemoryMipDesc .numLevels = desc .numMipLevels ; 886 887CUmipmappedArray mipArray ; 888SLANG_CUDA_RETURN_ON_FAIL ( 889cuExternalMemoryGetMappedMipmappedArray (& mipArray ,externalMemory ,& externalMemoryMipDesc )); 890resource -> m_cudaMipMappedArray = mipArray ; 891 892CUarray cuArray ; 893SLANG_CUDA_RETURN_ON_FAIL (cuMipmappedArrayGetLevel (& cuArray ,mipArray ,0 )); 894resource -> m_cudaArray = cuArray ; 895 896CUDA_RESOURCE_DESC surfDesc ; 897memset (& surfDesc ,0 ,sizeof (surfDesc )); 898surfDesc .resType = CU_RESOURCE_TYPE_ARRAY ; 899surfDesc .res .array .hArray = cuArray ; 900 901CUsurfObject surface ; 902SLANG_CUDA_RETURN_ON_FAIL (cuSurfObjectCreate (& surface ,& surfDesc )); 903resource -> m_cudaSurfObj = surface ; 904 905returnComPtr (outResource ,resource ); 906return SLANG_OK ; 907} 908 909SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createTextureView ( 910ITextureResource * texture , 911IResourceView ::Desc const & desc , 912IResourceView ** outView ) 913{ 914RefPtr < ResourceViewImpl > view = new ResourceViewImpl (); 915view -> m_desc = desc ; 916view -> textureResource = dynamic_cast < TextureResourceImpl *> (texture ); 917returnComPtr (outView ,view ); 918return SLANG_OK ; 919} 920 921SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createBufferView ( 922IBufferResource * buffer , 923IBufferResource * counterBuffer , 924IResourceView ::Desc const & desc , 925IResourceView ** outView ) 926{ 927RefPtr < ResourceViewImpl > view = new ResourceViewImpl (); 928view -> m_desc = desc ; 929view -> memoryResource = dynamic_cast < BufferResourceImpl *> (buffer ); 930returnComPtr (outView ,view ); 931return SLANG_OK ; 932} 933 934SLANG_NO_THROW Result SLANG_MCALL 935DeviceImpl ::createQueryPool (const IQueryPool ::Desc & desc ,IQueryPool ** outPool ) 936{ 937RefPtr < QueryPoolImpl > pool = new QueryPoolImpl (); 938SLANG_RETURN_ON_FAIL (pool -> init (desc )); 939returnComPtr (outPool ,pool ); 940return SLANG_OK ; 941} 942 943Result DeviceImpl ::createShaderObjectLayout ( 944 slang::ISession * session , 945 slang::TypeLayoutReflection * typeLayout , 946ShaderObjectLayoutBase ** outLayout ) 947{ 948RefPtr < ShaderObjectLayoutImpl > cudaLayout ; 949cudaLayout = new ShaderObjectLayoutImpl (this ,session ,typeLayout ); 950returnRefPtrMove (outLayout ,cudaLayout ); 951return SLANG_OK ; 952} 953 954Result DeviceImpl ::createShaderObject (ShaderObjectLayoutBase * layout ,IShaderObject ** outObject ) 955{ 956RefPtr < ShaderObjectImpl > result = new ShaderObjectImpl (); 957SLANG_RETURN_ON_FAIL (result -> init (this ,dynamic_cast < ShaderObjectLayoutImpl *> (layout ))); 958returnComPtr (outObject ,result ); 959return SLANG_OK ; 960} 961 962Result DeviceImpl ::createMutableShaderObject ( 963ShaderObjectLayoutBase * layout , 964IShaderObject ** outObject ) 965{ 966RefPtr < MutableShaderObjectImpl > result = new MutableShaderObjectImpl (); 967SLANG_RETURN_ON_FAIL (result -> init (this ,dynamic_cast < ShaderObjectLayoutImpl *> (layout ))); 968returnComPtr (outObject ,result ); 969return SLANG_OK ; 970} 971 972Result DeviceImpl ::createRootShaderObject (IShaderProgram * program ,ShaderObjectBase ** outObject ) 973{ 974auto cudaProgram = dynamic_cast < ShaderProgramImpl *> (program ); 975auto cudaLayout = cudaProgram -> layout ; 976 977RefPtr < RootShaderObjectImpl > result = new RootShaderObjectImpl (); 978SLANG_RETURN_ON_FAIL (result -> init (this ,cudaLayout )); 979returnRefPtrMove (outObject ,result ); 980return SLANG_OK ; 981} 982 983SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createProgram ( 984const IShaderProgram ::Desc & desc , 985IShaderProgram ** outProgram , 986ISlangBlob ** outDiagnosticBlob ) 987{ 988// If this is a specializable program, we just keep a reference to the slang program and 989// don't actually create any kernels. This program will be specialized later when we know 990// the shader object bindings. 991RefPtr < ShaderProgramImpl > cudaProgram = new ShaderProgramImpl (); 992cudaProgram -> init (desc ); 993cudaProgram -> cudaContext = m_context ; 994if (desc .slangGlobalScope -> getSpecializationParamCount ()!= 0 ) 995 { 996cudaProgram -> layout = 997new RootShaderObjectLayoutImpl (this ,desc .slangGlobalScope -> getLayout ()); 998returnComPtr (outProgram ,cudaProgram ); 999return SLANG_OK ; 1000 } 1001 1002ComPtr < ISlangBlob > kernelCode ; 1003ComPtr < ISlangBlob > diagnostics ; 1004auto compileResult = getEntryPointCodeFromShaderCache ( 1005desc .slangGlobalScope , 1006 (SlangInt )0 , 10070 , 1008kernelCode .writeRef (), 1009diagnostics .writeRef ()); 1010if (diagnostics ) 1011 { 1012getDebugCallback ()-> handleMessage ( 1013compileResult == SLANG_OK ?DebugMessageType ::Warning :DebugMessageType ::Error , 1014DebugMessageSource ::Slang , 1015 (char * )diagnostics -> getBufferPointer ()); 1016if (outDiagnosticBlob ) 1017returnComPtr (outDiagnosticBlob ,diagnostics ); 1018 } 1019SLANG_RETURN_ON_FAIL (compileResult ); 1020 1021SLANG_CUDA_RETURN_ON_FAIL ( 1022cuModuleLoadData (& cudaProgram -> cudaModule ,kernelCode -> getBufferPointer ())); 1023cudaProgram -> kernelName = 1024desc .slangGlobalScope -> getLayout ()-> getEntryPointByIndex (0 )-> getName (); 1025SLANG_CUDA_RETURN_ON_FAIL (cuModuleGetFunction ( 1026& cudaProgram -> cudaKernel , 1027cudaProgram -> cudaModule , 1028cudaProgram -> kernelName .getBuffer ())); 1029 1030auto slangGlobalScope = desc .slangGlobalScope ; 1031if (slangGlobalScope ) 1032 { 1033cudaProgram -> slangGlobalScope = slangGlobalScope ; 1034 1035auto slangProgramLayout = slangGlobalScope -> getLayout (); 1036if (!slangProgramLayout ) 1037return SLANG_FAIL ; 1038 1039RefPtr < RootShaderObjectLayoutImpl > cudaLayout ; 1040cudaLayout = new RootShaderObjectLayoutImpl (this ,slangProgramLayout ); 1041cudaLayout -> programLayout = slangProgramLayout ; 1042cudaProgram -> layout = cudaLayout ; 1043 } 1044 1045returnComPtr (outProgram ,cudaProgram ); 1046return SLANG_OK ; 1047} 1048 1049SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createComputePipelineState ( 1050const ComputePipelineStateDesc & desc , 1051IPipelineState ** outState ) 1052{ 1053RefPtr < ComputePipelineStateImpl > state = new ComputePipelineStateImpl (); 1054state -> shaderProgram = static_cast < ShaderProgramImpl *> (desc .program ); 1055state -> init (desc ); 1056returnComPtr (outState ,state ); 1057return Result (); 1058} 1059 1060void * DeviceImpl ::map (IBufferResource * buffer ) 1061{ 1062return static_cast < BufferResourceImpl *> (buffer )-> m_cudaMemory ; 1063} 1064 1065void DeviceImpl ::unmap (IBufferResource * buffer ) 1066{ 1067SLANG_UNUSED (buffer ); 1068} 1069 1070SLANG_NO_THROW const DeviceInfo & SLANG_MCALL DeviceImpl ::getDeviceInfo ()const 1071{ 1072return m_info ; 1073} 1074 1075SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createTransientResourceHeap ( 1076const ITransientResourceHeap ::Desc & desc , 1077ITransientResourceHeap ** outHeap ) 1078{ 1079RefPtr < TransientResourceHeapImpl > result = new TransientResourceHeapImpl (); 1080SLANG_RETURN_ON_FAIL (result -> init (this ,desc )); 1081returnComPtr (outHeap ,result ); 1082return SLANG_OK ; 1083} 1084 1085SLANG_NO_THROW Result SLANG_MCALL 1086DeviceImpl ::createCommandQueue (const ICommandQueue ::Desc & desc ,ICommandQueue ** outQueue ) 1087{ 1088RefPtr < CommandQueueImpl > queue = new CommandQueueImpl (); 1089queue -> init (this ); 1090returnComPtr (outQueue ,queue ); 1091return SLANG_OK ; 1092} 1093 1094SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createSwapchain ( 1095const ISwapchain ::Desc & desc , 1096WindowHandle window , 1097ISwapchain ** outSwapchain ) 1098{ 1099SLANG_UNUSED (desc ); 1100SLANG_UNUSED (window ); 1101SLANG_UNUSED (outSwapchain ); 1102return SLANG_FAIL ; 1103} 1104 1105SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createFramebufferLayout ( 1106const IFramebufferLayout ::Desc & desc , 1107IFramebufferLayout ** outLayout ) 1108{ 1109SLANG_UNUSED (desc ); 1110SLANG_UNUSED (outLayout ); 1111return SLANG_FAIL ; 1112} 1113 1114SLANG_NO_THROW Result SLANG_MCALL 1115DeviceImpl ::createFramebuffer (const IFramebuffer ::Desc & desc ,IFramebuffer ** outFramebuffer ) 1116{ 1117SLANG_UNUSED (desc ); 1118SLANG_UNUSED (outFramebuffer ); 1119return SLANG_FAIL ; 1120} 1121 1122SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createRenderPassLayout ( 1123const IRenderPassLayout ::Desc & desc , 1124IRenderPassLayout ** outRenderPassLayout ) 1125{ 1126SLANG_UNUSED (desc ); 1127SLANG_UNUSED (outRenderPassLayout ); 1128return SLANG_FAIL ; 1129} 1130 1131SLANG_NO_THROW Result SLANG_MCALL 1132DeviceImpl ::createSamplerState (ISamplerState ::Desc const & desc ,ISamplerState ** outSampler ) 1133{ 1134SLANG_UNUSED (desc ); 1135* outSampler = nullptr ; 1136return SLANG_OK ; 1137} 1138 1139SLANG_NO_THROW Result SLANG_MCALL 1140DeviceImpl ::createInputLayout (IInputLayout ::Desc const & desc ,IInputLayout ** outLayout ) 1141{ 1142SLANG_UNUSED (desc ); 1143SLANG_UNUSED (outLayout ); 1144return SLANG_E_NOT_AVAILABLE ; 1145} 1146 1147SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::createGraphicsPipelineState ( 1148const GraphicsPipelineStateDesc & desc , 1149IPipelineState ** outState ) 1150{ 1151SLANG_UNUSED (desc ); 1152SLANG_UNUSED (outState ); 1153return SLANG_E_NOT_AVAILABLE ; 1154} 1155 1156SLANG_NO_THROW SlangResult SLANG_MCALL DeviceImpl ::readTextureResource ( 1157ITextureResource * texture , 1158ResourceState state , 1159ISlangBlob ** outBlob , 1160size_t * outRowPitch , 1161size_t * outPixelSize ) 1162{ 1163auto textureImpl = static_cast < TextureResourceImpl *> (texture ); 1164 1165List < uint8_t > blobData ; 1166 1167auto desc = textureImpl -> getDesc (); 1168auto width = desc -> size .width ; 1169auto height = desc -> size .height ; 1170FormatInfo sizeInfo ; 1171SLANG_RETURN_ON_FAIL (gfxGetFormatInfo (desc -> format ,& sizeInfo )); 1172size_t pixelSize = sizeInfo .blockSizeInBytes /sizeInfo .pixelsPerBlock ; 1173size_t rowPitch = width * pixelSize ; 1174size_t size = height * rowPitch ; 1175blobData .setCount ((Index )size ); 1176 1177CUDA_MEMCPY2D copyParam ; 1178memset (& copyParam ,0 ,sizeof (copyParam )); 1179 1180copyParam .srcMemoryType = CU_MEMORYTYPE_ARRAY ; 1181copyParam .srcArray = textureImpl -> m_cudaArray ; 1182 1183copyParam .dstMemoryType = CU_MEMORYTYPE_HOST ; 1184copyParam .dstHost = blobData .getBuffer (); 1185copyParam .dstPitch = rowPitch ; 1186copyParam .WidthInBytes = copyParam .dstPitch ; 1187copyParam .Height = height ; 1188SLANG_CUDA_RETURN_ON_FAIL (cuMemcpy2D (& copyParam )); 1189 1190* outRowPitch = rowPitch ; 1191* outPixelSize = pixelSize ; 1192 1193auto blob = ListBlob ::moveCreate (blobData ); 1194 1195returnComPtr (outBlob ,blob ); 1196return SLANG_OK ; 1197} 1198 1199SLANG_NO_THROW Result SLANG_MCALL DeviceImpl ::readBufferResource ( 1200IBufferResource * buffer , 1201size_t offset , 1202size_t size , 1203ISlangBlob ** outBlob ) 1204{ 1205auto bufferImpl = static_cast < BufferResourceImpl *> (buffer ); 1206 1207List < uint8_t > blobData ; 1208 1209blobData .setCount ((Index )size ); 1210cuMemcpy ( 1211 (CUdeviceptr )blobData .getBuffer (), 1212 (CUdeviceptr )((uint8_t * )bufferImpl -> m_cudaMemory + offset ), 1213size ); 1214 1215auto blob = ListBlob ::moveCreate (blobData ); 1216 1217returnComPtr (outBlob ,blob ); 1218return SLANG_OK ; 1219} 1220 1221}// namespace cuda 1222#endif 1223}// namespace gfx