yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
b118451e3
master
1// cuda-shader-object.cpp 2#include "cuda-shader-object.h" 3 4#include "cuda-helper-functions.h" 5#include "cuda-resource-views.h" 6#include "cuda-shader-object-layout.h" 7 8namespace gfx 9{ 10#ifdef GFX_ENABLE_CUDA 11using namespace Slang ; 12 13namespace cuda 14{ 15Result ShaderObjectData ::setCount (Index count ) 16{ 17if (isHostOnly ) 18 { 19m_cpuBuffer .setCount (count ); 20if (!m_bufferView ) 21 { 22IResourceView ::Desc viewDesc = {}; 23viewDesc .type = IResourceView ::Type ::UnorderedAccess ; 24m_bufferView = new ResourceViewImpl (); 25m_bufferView -> proxyBuffer = m_cpuBuffer .getBuffer (); 26m_bufferView -> m_desc = viewDesc ; 27 } 28return SLANG_OK ; 29 } 30 31if (!m_bufferResource ) 32 { 33IBufferResource ::Desc desc ; 34desc .type = IResource ::Type ::Buffer ; 35desc .sizeInBytes = count ; 36m_bufferResource = new BufferResourceImpl (desc ); 37if (count ) 38 { 39SLANG_CUDA_RETURN_ON_FAIL ( 40cuMemAlloc ((CUdeviceptr * )& m_bufferResource -> m_cudaMemory , (size_t )count )); 41 } 42IResourceView ::Desc viewDesc = {}; 43viewDesc .type = IResourceView ::Type ::UnorderedAccess ; 44m_bufferView = new ResourceViewImpl (); 45m_bufferView -> memoryResource = m_bufferResource ; 46m_bufferView -> m_desc = viewDesc ; 47 } 48auto oldSize = m_bufferResource -> getDesc ()-> sizeInBytes ; 49if ((size_t )count != oldSize ) 50 { 51void * newMemory = nullptr ; 52if (count ) 53 { 54SLANG_CUDA_RETURN_ON_FAIL (cuMemAlloc ((CUdeviceptr * )& newMemory , (size_t )count )); 55 } 56if (oldSize ) 57 { 58SLANG_CUDA_RETURN_ON_FAIL (cuMemcpy ( 59 (CUdeviceptr )newMemory , 60 (CUdeviceptr )m_bufferResource -> m_cudaMemory , 61Math ::Min ((size_t )count ,oldSize ))); 62 } 63cuMemFree ((CUdeviceptr )m_bufferResource -> m_cudaMemory ); 64m_bufferResource -> m_cudaMemory = newMemory ; 65m_bufferResource -> getDesc ()-> sizeInBytes = count ; 66 } 67return SLANG_OK ; 68} 69 70Slang ::Index ShaderObjectData ::getCount () 71{ 72if (isHostOnly ) 73return m_cpuBuffer .getCount (); 74if (m_bufferResource ) 75return (Slang ::Index )(m_bufferResource -> getDesc ()-> sizeInBytes ); 76else 77return 0 ; 78} 79 80void * ShaderObjectData ::getBuffer () 81{ 82if (isHostOnly ) 83return m_cpuBuffer .getBuffer (); 84 85if (m_bufferResource ) 86return m_bufferResource -> m_cudaMemory ; 87return nullptr ; 88} 89 90/// Returns a resource view for GPU access into the buffer content. 91ResourceViewBase * ShaderObjectData ::getResourceView ( 92RendererBase * device , 93 slang::TypeLayoutReflection * elementLayout , 94 slang::BindingType bindingType ) 95{ 96SLANG_UNUSED (device ); 97m_bufferResource -> getDesc ()-> elementSize = (int )elementLayout -> getSize (); 98return m_bufferView .Ptr (); 99} 100 101SlangResult ShaderObjectImpl ::init (IDevice * device ,ShaderObjectLayoutImpl * typeLayout ) 102{ 103m_layout = typeLayout ; 104 105// If the layout tells us that there is any uniform data, 106// then we need to allocate a constant buffer to hold that data. 107// 108// TODO: Do we need to allocate a shadow copy for use from 109// the CPU? 110// 111// TODO: When/where do we bind this constant buffer into 112// a descriptor set for later use? 113// 114auto slangLayout = getLayout ()-> getElementTypeLayout (); 115size_t uniformSize = slangLayout -> getSize (); 116if (uniformSize ) 117 { 118m_data .setCount ((Index )uniformSize ); 119 } 120 121// If the layout specifies that we have any resources or sub-objects, 122// then we need to size the appropriate arrays to account for them. 123// 124// Note: the counts here are the *total* number of resources/sub-objects 125// and not just the number of resource/sub-object ranges. 126// 127resources .setCount (typeLayout -> getResourceCount ()); 128m_objects .setCount (typeLayout -> getSubObjectCount ()); 129 130for (auto subObjectRange :getLayout ()-> subObjectRanges ) 131 { 132RefPtr < ShaderObjectLayoutImpl > subObjectLayout = subObjectRange .layout ; 133 134// In the case where the sub-object range represents an 135// existential-type leaf field (e.g., an `IBar`), we 136// cannot pre-allocate the object(s) to go into that 137// range, since we can't possibly know what to allocate 138// at this point. 139// 140if (!subObjectLayout ) 141continue ; 142// 143// Otherwise, we will allocate a sub-object to fill 144// in each entry in this range, based on the layout 145// information we already have. 146 147auto & bindingRangeInfo = getLayout ()-> m_bindingRanges [subObjectRange .bindingRangeIndex ]; 148for (Index i = 0 ;i < bindingRangeInfo .count ;++ i ) 149 { 150RefPtr < ShaderObjectImpl > subObject = new ShaderObjectImpl (); 151SLANG_RETURN_ON_FAIL (subObject -> init (device ,subObjectLayout )); 152 153ShaderOffset offset ; 154offset .uniformOffset = bindingRangeInfo .uniformOffset + sizeof (void * )* i ; 155offset .bindingRangeIndex = (GfxIndex )subObjectRange .bindingRangeIndex ; 156offset .bindingArrayIndex = (GfxIndex )i ; 157 158SLANG_RETURN_ON_FAIL (setObject (offset ,subObject )); 159 } 160 } 161return SLANG_OK ; 162} 163 164SLANG_NO_THROW GfxCount SLANG_MCALL ShaderObjectImpl ::getEntryPointCount () 165{ 166return 0 ; 167} 168 169SLANG_NO_THROW Result SLANG_MCALL 170ShaderObjectImpl ::getEntryPoint (GfxIndex index ,IShaderObject ** outEntryPoint ) 171{ 172* outEntryPoint = nullptr ; 173return SLANG_OK ; 174} 175 176SLANG_NO_THROW const void * SLANG_MCALL ShaderObjectImpl ::getRawData () 177{ 178return m_data .getBuffer (); 179} 180 181SLANG_NO_THROW Size SLANG_MCALL ShaderObjectImpl ::getSize () 182{ 183return (Size )m_data .getCount (); 184} 185 186SLANG_NO_THROW Result SLANG_MCALL 187ShaderObjectImpl ::setData (ShaderOffset const & offset ,void const * data ,Size size ) 188{ 189Size temp = m_data .getCount ()- (Size )offset .uniformOffset ; 190size = Math ::Min (size ,temp ); 191SLANG_CUDA_RETURN_ON_FAIL (cuMemcpy ( 192 (CUdeviceptr )((uint8_t * )m_data .getBuffer ()+ offset .uniformOffset ), 193 (CUdeviceptr )data , 194size )); 195return SLANG_OK ; 196} 197 198SLANG_NO_THROW Result SLANG_MCALL 199ShaderObjectImpl ::setResource (ShaderOffset const & offset ,IResourceView * resourceView ) 200{ 201if (!resourceView ) 202return SLANG_OK ; 203 204auto layout = getLayout (); 205 206auto bindingRangeIndex = offset .bindingRangeIndex ; 207SLANG_ASSERT (bindingRangeIndex >=0 ); 208SLANG_ASSERT (bindingRangeIndex < layout -> m_bindingRanges .getCount ()); 209 210auto & bindingRange = layout -> m_bindingRanges [bindingRangeIndex ]; 211 212auto viewIndex = bindingRange .baseIndex + offset .bindingArrayIndex ; 213auto cudaView = static_cast < ResourceViewImpl *> (resourceView ); 214 215resources [viewIndex ]= cudaView ; 216 217if (cudaView -> textureResource ) 218 { 219if (cudaView -> m_desc .type == IResourceView ::Type ::UnorderedAccess ) 220 { 221auto handle = cudaView -> textureResource -> m_cudaSurfObj ; 222setData (offset ,& handle ,sizeof (uint64_t )); 223 } 224else 225 { 226auto handle = cudaView -> textureResource -> getBindlessHandle (); 227setData (offset ,& handle ,sizeof (uint64_t )); 228 } 229 } 230else if (cudaView -> memoryResource ) 231 { 232auto handle = cudaView -> memoryResource -> getBindlessHandle (); 233setData (offset ,& handle ,sizeof (handle )); 234auto sizeOffset = offset ; 235sizeOffset .uniformOffset += sizeof (handle ); 236auto & desc = * cudaView -> memoryResource -> getDesc (); 237size_t size = desc .sizeInBytes ; 238if (desc .elementSize > 1 ) 239size /=desc .elementSize ; 240setData (sizeOffset ,& size ,sizeof (size )); 241 } 242else if (cudaView -> proxyBuffer ) 243 { 244auto handle = cudaView -> proxyBuffer ; 245setData (offset ,& handle ,sizeof (handle )); 246auto sizeOffset = offset ; 247sizeOffset .uniformOffset += sizeof (handle ); 248auto & desc = * cudaView -> memoryResource -> getDesc (); 249size_t size = desc .sizeInBytes ; 250if (desc .elementSize > 1 ) 251size /=desc .elementSize ; 252setData (sizeOffset ,& size ,sizeof (size )); 253 } 254return SLANG_OK ; 255} 256 257SLANG_NO_THROW Result SLANG_MCALL 258ShaderObjectImpl ::setObject (ShaderOffset const & offset ,IShaderObject * object ) 259{ 260SLANG_RETURN_ON_FAIL (Super ::setObject (offset ,object )); 261 262auto bindingRangeIndex = offset .bindingRangeIndex ; 263auto & bindingRange = getLayout ()-> m_bindingRanges [bindingRangeIndex ]; 264 265ShaderObjectImpl * subObject = static_cast < ShaderObjectImpl *> (object ); 266switch (bindingRange .bindingType ) 267 { 268default : 269 { 270void * subObjectDataBuffer = subObject -> getBuffer (); 271SLANG_RETURN_ON_FAIL (setData (offset ,& subObjectDataBuffer ,sizeof (void * ))); 272 } 273break ; 274case slang::BindingType ::ExistentialValue : 275case slang::BindingType ::RawBuffer : 276case slang::BindingType ::MutableRawBuffer : 277break ; 278 } 279return SLANG_OK ; 280} 281 282SLANG_NO_THROW Result SLANG_MCALL 283ShaderObjectImpl ::setSampler (ShaderOffset const & offset ,ISamplerState * sampler ) 284{ 285SLANG_UNUSED (sampler ); 286SLANG_UNUSED (offset ); 287return SLANG_OK ; 288} 289 290SLANG_NO_THROW Result SLANG_MCALL ShaderObjectImpl ::setCombinedTextureSampler ( 291ShaderOffset const & offset , 292IResourceView * textureView , 293ISamplerState * sampler ) 294{ 295SLANG_UNUSED (sampler ); 296setResource (offset ,textureView ); 297return SLANG_OK ; 298} 299 300EntryPointShaderObjectImpl ::EntryPointShaderObjectImpl () 301{ 302m_data .isHostOnly = true; 303} 304 305SLANG_NO_THROW uint32_t SLANG_MCALL RootShaderObjectImpl ::addRef () 306{ 307return 1 ; 308} 309 310SLANG_NO_THROW uint32_t SLANG_MCALL RootShaderObjectImpl ::release () 311{ 312return 1 ; 313} 314 315SlangResult RootShaderObjectImpl ::init (IDevice * device ,ShaderObjectLayoutImpl * typeLayout ) 316{ 317SLANG_RETURN_ON_FAIL (ShaderObjectImpl ::init (device ,typeLayout )); 318auto programLayout = dynamic_cast < RootShaderObjectLayoutImpl *> (typeLayout ); 319for (auto & entryPoint :programLayout -> entryPointLayouts ) 320 { 321RefPtr < EntryPointShaderObjectImpl > object = new EntryPointShaderObjectImpl (); 322SLANG_RETURN_ON_FAIL (object -> init (device ,entryPoint )); 323entryPointObjects .add (object ); 324 } 325return SLANG_OK ; 326} 327 328SLANG_NO_THROW GfxCount SLANG_MCALL RootShaderObjectImpl ::getEntryPointCount () 329{ 330return (GfxCount )entryPointObjects .getCount (); 331} 332 333SLANG_NO_THROW Result SLANG_MCALL 334RootShaderObjectImpl ::getEntryPoint (GfxIndex index ,IShaderObject ** outEntryPoint ) 335{ 336returnComPtr (outEntryPoint ,entryPointObjects [index ]); 337return SLANG_OK ; 338} 339 340Result RootShaderObjectImpl ::collectSpecializationArgs (ExtendedShaderObjectTypeList & args ) 341{ 342SLANG_RETURN_ON_FAIL (ShaderObjectImpl ::collectSpecializationArgs (args )); 343for (auto & entryPoint :entryPointObjects ) 344 { 345SLANG_RETURN_ON_FAIL (entryPoint -> collectSpecializationArgs (args )); 346 } 347return SLANG_OK ; 348} 349 350}// namespace cuda 351#endif 352}// namespace gfx