yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
3822f9243
master
1// shader-renderer-util.cpp 2 3#include "shader-renderer-util.h" 4 5namespace renderer_test 6{ 7 8using namespace Slang ; 9using Slang ::Result ; 10 11inline int calcMipSize (int size ,int level ) 12{ 13size = size >>level ; 14return size > 0 ?size :1 ; 15} 16 17inline Extent3D calcMipSize (Extent3D size ,int mipLevel ) 18{ 19Extent3D rs ; 20rs .width = calcMipSize (size .width ,mipLevel ); 21rs .height = calcMipSize (size .height ,mipLevel ); 22rs .depth = calcMipSize (size .depth ,mipLevel ); 23return rs ; 24} 25 26/// Given the type works out the maximum dimension size 27inline int calcMaxDimension (Extent3D size ,TextureType type ) 28{ 29switch (type ) 30 { 31case TextureType ::Texture1D : 32return size .width ; 33case TextureType ::Texture3D : 34return Math ::Max (Math ::Max (size .width ,size .height ),size .depth ); 35case TextureType ::TextureCube :// fallthru 36case TextureType ::Texture2D : 37 { 38return Math ::Max (size .width ,size .height ); 39 } 40default : 41return 0 ; 42 } 43} 44 45/// Given the type, calculates the number of mip maps. 0 on error 46inline int calcNumMipLevels (TextureType type ,Extent3D size ) 47{ 48const int maxDimensionSize = calcMaxDimension (size ,type ); 49return (maxDimensionSize > 0 ) ? (Math ::Log2Floor (maxDimensionSize )+ 1 ) :0 ; 50} 51 52/* static */ Result ShaderRendererUtil ::generateTexture ( 53const InputTextureDesc & inputDesc , 54ResourceState defaultState , 55IDevice * device , 56ComPtr < ITexture >& textureOut ) 57{ 58TextureData texData ; 59generateTextureData (texData ,inputDesc ); 60return createTexture (inputDesc ,texData ,defaultState ,device ,textureOut ); 61} 62 63/* static */ Result ShaderRendererUtil ::createTexture ( 64const InputTextureDesc & inputDesc , 65const TextureData & texData , 66ResourceState defaultState , 67IDevice * device , 68ComPtr < ITexture >& textureOut ) 69{ 70TextureDesc textureDesc = {}; 71 72// Default to RGBA8Unorm 73const Format format = 74 (inputDesc .format == Format ::Undefined ) ?Format ::RGBA8Unorm :inputDesc .format ; 75 76const FormatInfo & formatInfo = getFormatInfo (format ); 77 78bool isArray = inputDesc .arrayLength > 1 ; 79bool isMS = inputDesc .sampleCount > 1 ; 80 81textureDesc .sampleCount = inputDesc .sampleCount ; 82textureDesc .format = format ; 83textureDesc .mipCount = texData .m_mipLevels ; 84if (isArray ) 85 { 86textureDesc .arrayLength = inputDesc .arrayLength ; 87 } 88textureDesc .usage = TextureUsage ::CopyDestination |TextureUsage ::CopySource ; 89switch (defaultState ) 90 { 91case ResourceState ::ShaderResource : 92textureDesc .usage |=TextureUsage ::ShaderResource ; 93break ; 94case ResourceState ::UnorderedAccess : 95textureDesc .usage |=TextureUsage ::UnorderedAccess ; 96break ; 97default : 98return SLANG_FAIL ; 99 } 100textureDesc .defaultState = defaultState ; 101 102// It's the same size in all dimensions 103switch (inputDesc .dimension ) 104 { 105case 1 : 106 { 107textureDesc .type = isArray ?TextureType ::Texture1DArray :TextureType ::Texture1D ; 108textureDesc .size .width = inputDesc .size ; 109textureDesc .size .height = 1 ; 110textureDesc .size .depth = 1 ; 111 112break ; 113 } 114case 2 : 115 { 116textureDesc .type = 117isArray 118 ? (inputDesc .isCube 119 ?TextureType ::TextureCubeArray 120 : (isMS ?TextureType ::Texture2DMSArray :TextureType ::Texture2DArray )) 121 : (inputDesc .isCube 122 ?TextureType ::TextureCube 123 : (isMS ?TextureType ::Texture2DMS :TextureType ::Texture2D )); 124textureDesc .size .width = inputDesc .size ; 125textureDesc .size .height = inputDesc .size ; 126textureDesc .size .depth = 1 ; 127break ; 128 } 129case 3 : 130 { 131textureDesc .type = TextureType ::Texture3D ; 132textureDesc .size .width = inputDesc .size ; 133textureDesc .size .height = inputDesc .size ; 134textureDesc .size .depth = inputDesc .size ; 135break ; 136 } 137 } 138 139if (textureDesc .mipCount == 0 ) 140 { 141textureDesc .mipCount = calcNumMipLevels (textureDesc .type ,textureDesc .size ); 142 } 143 144// Metal doesn't support mip maps for 1D textures. 145if ((isMS )|| (device -> getDeviceType ()== DeviceType ::Metal && 146 (textureDesc .type == TextureType ::Texture1D || 147textureDesc .type == TextureType ::Texture1DArray ))) 148 { 149textureDesc .mipCount = 1 ; 150 } 151 152List < SubresourceData > initSubresources ; 153int layerCount = textureDesc .getLayerCount (); 154int subResourceCounter = 0 ; 155for (int a = 0 ;a < layerCount ;++ a ) 156 { 157for (int m = 0 ;m < textureDesc .mipCount ;++ m ) 158 { 159int subResourceIndex = subResourceCounter ++ ; 160const int mipWidth = calcMipSize (textureDesc .size .width ,m ); 161const int mipHeight = calcMipSize (textureDesc .size .height ,m ); 162 163size_t rowPitch = mipWidth * formatInfo .blockSizeInBytes ; 164size_t slicePitch = mipHeight * rowPitch ; 165 166SubresourceData subresourceData ; 167subresourceData .data = texData .m_slices [subResourceIndex ].values ; 168subresourceData .rowPitch = rowPitch ; 169subresourceData .slicePitch = slicePitch ; 170 171initSubresources .add (subresourceData ); 172 } 173 } 174 175if (isMS ) 176 { 177textureDesc .usage |=TextureUsage ::RenderTarget ; 178textureOut = device -> createTexture (textureDesc ); 179clearTexture (textureOut .get (),inputDesc .content ,device ); 180 } 181else 182 { 183textureOut = device -> createTexture (textureDesc ,initSubresources .getBuffer ()); 184 } 185 186return textureOut ?SLANG_OK :SLANG_FAIL ; 187} 188 189/* static */ Result ShaderRendererUtil ::createBuffer ( 190const InputBufferDesc & inputDesc , 191size_t bufferSize , 192const void * initData , 193IDevice * device , 194ComPtr < IBuffer >& bufferOut ) 195{ 196BufferDesc bufferDesc ; 197bufferDesc .size = bufferSize ; 198bufferDesc .format = inputDesc .format ; 199bufferDesc .elementSize = inputDesc .stride ; 200bufferDesc .usage = BufferUsage ::CopyDestination |BufferUsage ::CopySource | 201BufferUsage ::ShaderResource |BufferUsage ::UnorderedAccess ; 202bufferDesc .defaultState = ResourceState ::UnorderedAccess ; 203 204ComPtr < IBuffer > bufferResource = device -> createBuffer (bufferDesc ,initData ); 205if (!bufferResource ) 206 { 207return SLANG_FAIL ; 208 } 209 210bufferOut = bufferResource ; 211return SLANG_OK ; 212} 213 214/* static */ Result ShaderRendererUtil ::clearTexture ( 215ITexture * texture , 216InputTextureContent content , 217IDevice * device ) 218{ 219SLANG_ASSERT (texture ); 220ComPtr < ICommandQueue > queue ; 221SLANG_RETURN_ON_FAIL (device -> getQueue (QueueType ::Graphics ,queue .writeRef ())); 222 223ComPtr < ICommandEncoder > commandEncoder ; 224SLANG_RETURN_ON_FAIL (queue -> createCommandEncoder (commandEncoder .writeRef ())); 225 226TextureDesc desc = texture -> getDesc (); 227SubresourceRange range ; 228range .layer = 0 ; 229range .layerCount = texture -> getDesc ().arrayLength ; 230range .mip = 0 ; 231range .mipCount = texture -> getDesc ().mipCount ; 232 233FormatInfo formatInfo = getFormatInfo (desc .format ); 234switch (formatInfo .kind ) 235 { 236case FormatKind ::Float : 237 { 238float clearValue [4 ]= {0.0f ,0.0f ,0.0f ,0.0f }; 239switch (content ) 240 { 241case InputTextureContent ::Zero : 242// clearValue is already all zeros 243break ; 244case InputTextureContent ::One : 245clearValue [0 ]= clearValue [1 ]= clearValue [2 ]= clearValue [3 ]= 1.0f ; 246break ; 247case InputTextureContent ::ChessBoard : 248case InputTextureContent ::Gradient : 249// For chessboard or gradient, we can't use a single clear value 250// Instead, we should use a compute shader or multiple draw calls 251SLANG_ASSERT (!"ChessBoard or Gradient content type is not supported for " 252"multisampled textures - requires compute shader implementation" ); 253return SLANG_FAIL ; 254 } 255commandEncoder -> clearTextureFloat (texture ,range ,clearValue ); 256break ; 257 } 258case FormatKind ::Integer : 259 { 260uint32_t clearValue [4 ]= {0U ,0U ,0U ,0U }; 261switch (content ) 262 { 263case InputTextureContent ::Zero : 264// clearValue is already all zeros 265break ; 266case InputTextureContent ::One : 267clearValue [0 ]= clearValue [1 ]= clearValue [2 ]= clearValue [3 ]= 1U ; 268break ; 269case InputTextureContent ::ChessBoard : 270case InputTextureContent ::Gradient : 271// For chessboard or gradient, we can't use a single clear value 272// Instead, we should use a compute shader or multiple draw calls 273SLANG_ASSERT (!"ChessBoard or Gradient content type is not supported for " 274"multisampled textures - requires compute shader implementation" ); 275return SLANG_FAIL ; 276 } 277commandEncoder -> clearTextureUint (texture ,range ,clearValue ); 278break ; 279 } 280case FormatKind ::Normalized : 281 { 282int32_t clearValue [4 ]= {0 ,0 ,0 ,0 }; 283switch (content ) 284 { 285case InputTextureContent ::Zero : 286// clearValue is already all zeros 287break ; 288case InputTextureContent ::One : 289clearValue [0 ]= clearValue [1 ]= clearValue [2 ]= clearValue [3 ]= 1 ; 290break ; 291case InputTextureContent ::ChessBoard : 292case InputTextureContent ::Gradient : 293// For chessboard or gradient, we can't use a single clear value 294// Instead, we should use a compute shader or multiple draw calls 295SLANG_ASSERT (!"ChessBoard or Gradient content type is not supported for " 296"multisampled textures - requires compute shader implementation" ); 297return SLANG_FAIL ; 298 } 299commandEncoder -> clearTextureSint (texture ,range ,clearValue ); 300break ; 301 } 302case FormatKind ::DepthStencil : 303 { 304float depthValue = 0.f ; 305uint8_t stencilValue = 0U ; 306switch (content ) 307 { 308case InputTextureContent ::Zero : 309// clearValue is already all zeros 310break ; 311case InputTextureContent ::One : 312depthValue = 1 ; 313stencilValue = 1U ; 314break ; 315case InputTextureContent ::ChessBoard : 316case InputTextureContent ::Gradient : 317// For chessboard or gradient, we can't use a single clear value 318// Instead, we should use a compute shader or multiple draw calls 319SLANG_ASSERT (!"ChessBoard or Gradient content type is not supported for " 320"multisampled textures - requires compute shader implementation" ); 321return SLANG_FAIL ; 322 } 323commandEncoder 324-> clearTextureDepthStencil (texture ,range , true,depthValue , true,stencilValue ); 325break ; 326 } 327default : 328 { 329SLANG_ASSERT (!"Unsupported FormatKind type" ); 330return SLANG_FAIL ; 331 } 332 } 333 334SLANG_RETURN_ON_FAIL (queue -> submit (commandEncoder -> finish ())); 335 336return SLANG_OK ; 337} 338 339static SamplerDesc _calcSamplerDesc (const InputSamplerDesc & srcDesc ) 340{ 341SamplerDesc samplerDesc ; 342if (srcDesc .isCompareSampler ) 343 { 344samplerDesc .reductionOp = TextureReductionOp ::Comparison ; 345samplerDesc .comparisonFunc = ComparisonFunc ::Less ; 346 } 347samplerDesc .minFilter = srcDesc .filteringMode ; 348samplerDesc .magFilter = srcDesc .filteringMode ; 349samplerDesc .mipFilter = srcDesc .filteringMode ; 350return samplerDesc ; 351} 352 353ComPtr < ISampler > _createSampler (IDevice * device ,const InputSamplerDesc & srcDesc ) 354{ 355return device -> createSampler (_calcSamplerDesc (srcDesc )); 356} 357 358}// namespace renderer_test