A game about forced loneliness, made by TACStudios
at master 777 lines 52 kB view raw
1using System; 2using System.Runtime.CompilerServices; 3using Unity.Mathematics; 4 5namespace UnityEngine.Rendering.RenderGraphModule.Util 6{ 7 /// <summary> 8 /// Helper functions used for RenderGraph. 9 /// </summary> 10 public static partial class RenderGraphUtils 11 { 12 static MaterialPropertyBlock s_PropertyBlock = new MaterialPropertyBlock(); 13 14 /// <summary> 15 /// Checks if the shader features required by the MSAA version of the copy pass is supported on current platform. 16 /// </summary> 17 /// <returns>Returns true if the shader features required by the copy pass is supported for MSAA, otherwise will it return false.</returns> 18 public static bool CanAddCopyPassMSAA() 19 { 20 return Blitter.CanCopyMSAA(); 21 } 22 23 class CopyPassData 24 { 25 public bool isMSAA; 26 } 27 28 /// <summary> 29 /// Adds a pass to copy data from a source texture to a destination texture. The data in the texture is copied pixel by pixel. The copy function can only do 1:1 copies it will not allow scaling the data or 30 /// doing texture filtering. Furthermore it requires the source and destination surfaces to be the same size in pixels and have the same number of MSAA samples. If the textures are multi sampled 31 /// individual samples will be copied. 32 /// 33 /// Copy is intentionally limited in functionally so it can be implemented using frame buffer fetch for optimal performance on tile based GPUs. If you are looking for a more generic 34 /// function please use the AddBlitPass function. 35 /// 36 /// For XR textures you will have to copy for each eye seperatly. 37 /// 38 /// For MSAA textures please use the CanAddCopyPassMSAA() function first to check if the CopyPass is supported on current platform. 39 /// 40 /// </summary> 41 /// <param name="graph">The RenderGraph adding this pass to.</param> 42 /// <param name="source">The texture the data is copied from.</param> 43 /// <param name="destination">The texture the data is copied to. This has to be different from souce.</param> 44 /// <param name="sourceSlice">The source slice of a Array of 3D texture to use. Must be 0 for regular 2D textures.</param> 45 /// <param name="destinationSlice">The destination slice of a Array of 3D texture to use. Must be 0 for regular 2D textures.</param> 46 /// <param name="sourceMip"> The first mipmap level to copy from. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures.</param> 47 /// <param name="destinationMip"> The first mipmap level to copy to. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures.</param> 48 /// <param name="passName">A name to use for debugging and error logging. This name will be shown in the rendergraph debugger. </param> 49 /// <param name="file">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param> 50 /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param> 51 public static void AddCopyPass( 52 this RenderGraph graph, 53 TextureHandle source, 54 TextureHandle destination, 55 int sourceSlice = 0, 56 int destinationSlice = 0, 57 int sourceMip = 0, 58 int destinationMip = 0, 59 string passName = "Copy Pass Utility" 60#if !CORE_PACKAGE_DOCTOOLS 61 , [CallerFilePath] string file = "", 62 [CallerLineNumber] int line = 0) 63#endif 64 { 65 if (!graph.nativeRenderPassesEnabled) 66 throw new ArgumentException("CopyPass only supported for native render pass. Please use the blit functions instead for non native render pass platforms."); 67 68 var sourceDesc = graph.GetTextureDesc(source); 69 var destinationDesc = graph.GetTextureDesc(destination); 70 71 if (sourceSlice < 0 || sourceSlice >= sourceDesc.slices) 72 throw new ArgumentException("Invalid sourceSlice."); 73 74 if (destinationSlice < 0 || destinationSlice >= destinationDesc.slices) 75 throw new ArgumentException("Invalid destinationSlice."); 76 77 int sourceMaxWidth = math.max(math.max(sourceDesc.width, sourceDesc.height), sourceDesc.slices); 78 int sourceTotalMipChainLevels = (int)math.log2(sourceMaxWidth) + 1; 79 if (sourceMip < 0 || sourceMip >= sourceMaxWidth) 80 throw new ArgumentException("Invalid sourceMip."); 81 82 int destinationMaxWidth = math.max(math.max(destinationDesc.width, destinationDesc.height), destinationDesc.slices); 83 int destinationTotalMipChainLevels = (int)math.log2(destinationMaxWidth) + 1; 84 if (destinationMip < 0 || destinationMip >= destinationMaxWidth) 85 throw new ArgumentException("Invalid destinationMip."); 86 87 if (sourceDesc.msaaSamples != destinationDesc.msaaSamples) 88 throw new ArgumentException("MSAA samples from source and destination texture doesn't match."); 89 90 var isMSAA = (int)sourceDesc.msaaSamples > 1; 91 92 // Note: Needs shader model ps_4.1 to support SV_SampleIndex which means the copy pass isn't supported for MSAA on some platforms. 93 // We can check this by checking the amout of shader passes the copy shader has. 94 // It would have 1 if the MSAA pass is not able to be used for target and 2 otherwise. 95 // https://docs.unity3d.com/2017.4/Documentation/Manual/SL-ShaderCompileTargets.html 96 // https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-to-get-sample-position 97 if (isMSAA && !Blitter.CanCopyMSAA()) 98 throw new ArgumentException("Target does not support MSAA for AddCopyPass. Please use the blit alternative or use non MSAA textures."); 99 100 using (var builder = graph.AddRasterRenderPass<CopyPassData>(passName, out var passData, file, line)) 101 { 102 passData.isMSAA = isMSAA; 103 builder.SetInputAttachment(source, 0, AccessFlags.Read, sourceMip, sourceSlice); 104 builder.SetRenderAttachment(destination, 0, AccessFlags.Write, destinationMip, destinationSlice); 105 builder.SetRenderFunc((CopyPassData data, RasterGraphContext context) => CopyRenderFunc(data, context)); 106 } 107 } 108 109 static void CopyRenderFunc(CopyPassData data, RasterGraphContext rgContext) 110 { 111 Blitter.CopyTexture(rgContext.cmd, data.isMSAA); 112 } 113 114 /// <summary> 115 /// Filtermode for the simple blit. 116 /// </summary> 117 public enum BlitFilterMode 118 { 119 /// <summary> 120 /// Clamp to the nearest pixel when selecting which pixel to blit from. 121 /// </summary> 122 ClampNearest, 123 /// <summary> 124 /// Use bileanear filtering when selecting which pixels to blit from. 125 /// </summary> 126 ClampBilinear 127 } 128 129 class BlitPassData 130 { 131 public TextureHandle source; 132 public TextureHandle destination; 133 public Vector2 scale; 134 public Vector2 offset; 135 public int sourceSlice; 136 public int destinationSlice; 137 public int numSlices; 138 public int sourceMip; 139 public int destinationMip; 140 public int numMips; 141 public BlitFilterMode filterMode; 142 143 } 144 145 /// <summary> 146 /// Add a render graph pass to blit an area of the source texture into the destination texture. Blitting is a high-level way to transfer texture data from a source to a destination texture. 147 /// It may scale and texture-filter the transferred data as well as doing data transformations on it (e.g. R8Unorm to float). 148 /// 149 /// This function does not have special handling for MSAA textures. This means that when the source is sampled this will be a resolved value (standard Unity behavior when sampling an MSAA render texture) 150 /// and when the destination is MSAA all written samples will contain the same values (e.g. as you would expect when rendering a full screen quad to an msaa buffer). If you need special MSAA 151 /// handling or custom resolving please use the overload that takes a Material and implement the appropriate behavior in the shader. 152 /// 153 /// This function works transparently with regular textures and XR textures (which may depending on the situation be 2D array textures). In the case of an XR array texture 154 /// the operation will be repeated for each slice in the texture if numSlices is set to -1. 155 /// 156 /// </summary> 157 /// <param name="graph">The RenderGraph adding this pass to.</param> 158 /// <param name="source">The texture the data is copied from.</param> 159 /// <param name="destination">The texture the data is copied to.</param> 160 /// <param name="scale">The scale that is applied to the texture coordinates used to sample the source texture.</param> 161 /// <param name="offset">The offset that is added to the texture coordinates used to sample the source texture.</param> 162 /// <param name="sourceSlice"> The first slice to copy from if the texture is an 3D or array texture. Must be zero for regular textures.</param> 163 /// <param name="destinationSlice"> The first slice to copy to if the texture is an 3D or array texture. Must be zero for regular textures.</param> 164 /// <param name="numSlices"> The number of slices to copy. -1 to copy all slices until the end of the texture. Arguments that copy invalid slices to be copied will lead to an error.</param> 165 /// <param name="sourceMip"> The first mipmap level to copy from. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures.</param> 166 /// <param name="destinationMip"> The first mipmap level to copy to. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures.</param> 167 /// <param name="numMips"> The number of mipmaps to copy. -1 to copy all mipmaps. Arguments that copy invalid mips to be copied will lead to an error.</param> 168 /// <param name="filterMode">The filtering used when blitting from source to destination.</param> 169 /// <param name="passName">A name to use for debugging and error logging. This name will be shown in the rendergraph debugger. </param> 170 /// <param name="file">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param> 171 /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param> 172 public static void AddBlitPass(this RenderGraph graph, 173 TextureHandle source, 174 TextureHandle destination, 175 Vector2 scale, 176 Vector2 offset, 177 int sourceSlice = 0, 178 int destinationSlice = 0, 179 int numSlices = -1, 180 int sourceMip = 0, 181 int destinationMip = 0, 182 int numMips = 1, 183 BlitFilterMode filterMode = BlitFilterMode.ClampBilinear, 184 string passName = "Blit Pass Utility" 185#if !CORE_PACKAGE_DOCTOOLS 186 , [CallerFilePath] string file = "", 187 [CallerLineNumber] int line = 0) 188#endif 189 { 190 var sourceDesc = graph.GetTextureDesc(source); 191 var destinationDesc = graph.GetTextureDesc(destination); 192 193 int sourceMaxWidth = math.max(math.max(sourceDesc.width, sourceDesc.height), sourceDesc.slices); 194 int sourceTotalMipChainLevels = (int)math.log2(sourceMaxWidth) + 1; 195 196 int destinationMaxWidth = math.max(math.max(destinationDesc.width, destinationDesc.height), destinationDesc.slices); 197 int destinationTotalMipChainLevels = (int)math.log2(destinationMaxWidth) + 1; 198 199 if (numSlices == -1) numSlices = sourceDesc.slices - sourceSlice; 200 if (numSlices > sourceDesc.slices - sourceSlice 201 || numSlices > destinationDesc.slices - destinationSlice) 202 { 203 throw new ArgumentException($"BlitPass: {passName} attempts to blit too many slices. The pass will be skipped."); 204 } 205 if (numMips == -1) numMips = sourceTotalMipChainLevels - sourceMip; 206 if (numMips > sourceTotalMipChainLevels - sourceMip 207 || numMips > destinationTotalMipChainLevels - destinationMip) 208 { 209 throw new ArgumentException($"BlitPass: {passName} attempts to blit too many mips. The pass will be skipped."); 210 } 211 212 using (var builder = graph.AddUnsafePass<BlitPassData>(passName, out var passData, file, line)) 213 { 214 passData.source = source; 215 passData.destination = destination; 216 passData.scale = scale; 217 passData.offset = offset; 218 passData.sourceSlice = sourceSlice; 219 passData.destinationSlice = destinationSlice; 220 passData.numSlices = numSlices; 221 passData.sourceMip = sourceMip; 222 passData.destinationMip = destinationMip; 223 passData.numMips = numMips; 224 passData.filterMode = filterMode; 225 226 builder.UseTexture(source, AccessFlags.Read); 227 builder.UseTexture(destination, AccessFlags.Write); 228 builder.SetRenderFunc((BlitPassData data, UnsafeGraphContext context) => BlitRenderFunc(data, context)); 229 } 230 } 231 static Vector4 s_BlitScaleBias = new Vector4(); 232 static void BlitRenderFunc(BlitPassData data, UnsafeGraphContext context) 233 { 234 s_BlitScaleBias.x = data.scale.x; 235 s_BlitScaleBias.y = data.scale.y; 236 s_BlitScaleBias.z = data.offset.x; 237 s_BlitScaleBias.w = data.offset.y; 238 239 CommandBuffer unsafeCmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd); 240 for (int currSlice = 0; currSlice < data.numSlices; currSlice++) 241 { 242 for (int currMip = 0; currMip < data.numMips; currMip++) 243 { 244 context.cmd.SetRenderTarget(data.destination, data.destinationMip + currMip, CubemapFace.Unknown, data.destinationSlice + currSlice); 245 Blitter.BlitTexture(unsafeCmd, data.source, s_BlitScaleBias, data.sourceMip + currMip, data.sourceSlice + currSlice, data.filterMode == BlitFilterMode.ClampBilinear); 246 } 247 } 248 249 } 250 251 /// <summary> 252 /// Enums to select what geometry used for the blit. 253 /// </summary> 254 public enum FullScreenGeometryType 255 { 256 /// <summary> 257 /// Draw a quad mesh built of two triangles. The texture coordinates of the mesh will cover the 0-1 texture space. This is the most compatible if you have an existing Unity Graphics.Blit shader. 258 /// This geometry allows you to use a simples vertex shader but has more rendering overhead on the CPU as a mesh and vertex buffers need to be bound to the pipeline. 259 /// </summary> 260 Mesh, 261 /// <summary> 262 /// A single triangle will be scheduled. The vertex shader will need to generate correct vertex data in the vertex shader for the tree vertices to cover the full screen. 263 /// To get the vertices in the vertex shader include "com.unity.render-pipelines.core\ShaderLibrary\Common.hlsl" and call the GetFullScreenTriangleTexCoord/GetFullScreenTriangleVertexPosition 264 /// </summary> 265 ProceduralTriangle, 266 /// <summary> 267 /// A four vertices forming two triangles will be scheduled. The vertex shader will need to generate correct vertex data in the vertex shader for the four vertices to cover the full screen. 268 /// While more intuitive this may be slower as the quad occupancy will be lower alongside the diagonal line where the two triangles meet. 269 /// To get the vertices in the vertex shader include "com.unity.render-pipelines.core\ShaderLibrary\Common.hlsl" and call the GetQuadTexCoord/GetQuadVertexPosition 270 /// </summary> 271 ProceduralQuad, 272 } 273 274 /// <summary> 275 /// This struct specifies all the arugments to the blit-with-material function. As there are many parameters with some of them only rarely used moving them to a struct 276 /// makes it easier to use the function. 277 /// 278 /// Use one of the constructor overloads for common use cases. 279 /// 280 /// 281 /// The shader properties defined in the struct or constructors is used for most common usecases but they are not required to be used in the shader. 282 /// By using the <c>MaterialPropertyBlock</c> can you add your shader properties with custom values. 283 /// </summary> 284 public struct BlitMaterialParameters 285 { 286 private static readonly int blitTextureProperty = Shader.PropertyToID("_BlitTexture"); 287 private static readonly int blitSliceProperty = Shader.PropertyToID("_BlitTexArraySlice"); 288 private static readonly int blitMipProperty = Shader.PropertyToID("_BlitMipLevel"); 289 private static readonly int blitScaleBias = Shader.PropertyToID("_BlitScaleBias"); 290 291 /// <summary> 292 /// Simple constructor to set a few amount of parameters to blit. 293 /// </summary> 294 /// <param name="source">The texture the data is copied from.</param> 295 /// <param name="destination">The texture the data is copied to.</param> 296 /// <param name="material">Material used for blitting.</param> 297 /// <param name="shaderPass">The shader pass index to use for the material.</param> 298 public BlitMaterialParameters(TextureHandle source, TextureHandle destination, Material material, int shaderPass) 299 : this(source, destination, Vector2.one, Vector2.zero, material, shaderPass) { } 300 301 /// <summary> 302 /// Simple constructor to set a few amount of parameters to blit. 303 /// </summary> 304 /// <param name="source">The texture the data is copied from.</param> 305 /// <param name="destination">The texture the data is copied to.</param> 306 /// <param name="scale">Scale for sampling the input texture.</param> 307 /// <param name="offset">Offset also known as bias for sampling the input texture</param> 308 /// <param name="material">Material used for blitting.</param> 309 /// <param name="shaderPass">The shader pass index to use for the material.</param> 310 public BlitMaterialParameters(TextureHandle source, TextureHandle destination, Vector2 scale, Vector2 offset, Material material, int shaderPass) 311 { 312 this.source = source; 313 this.destination = destination; 314 this.scale = scale; 315 this.offset = offset; 316 sourceSlice = -1; 317 destinationSlice = 0; 318 numSlices = 1; 319 sourceMip = -1; 320 destinationMip = 0; 321 numMips = 1; 322 this.material = material; 323 this.shaderPass = shaderPass; 324 propertyBlock = null; 325 sourceTexturePropertyID = blitTextureProperty; 326 sourceSlicePropertyID = blitSliceProperty; 327 sourceMipPropertyID = blitMipProperty; 328 scaleBiasPropertyID = blitScaleBias; 329 geometry = FullScreenGeometryType.ProceduralTriangle; 330 } 331 332 /// <summary> 333 /// Constructor to set the source and destination mip and slices as well as material property and IDs to interact with it. 334 /// </summary> 335 /// <param name="source">The texture the data is copied from.</param> 336 /// <param name="destination">The texture the data is copied to.</param> 337 /// <param name="material">Material used for blitting.</param> 338 /// <param name="shaderPass">The shader pass index to use for the material.</param> 339 /// <param name="mpb">Material property block to use to render the blit. This property should contain all data the shader needs.</param> 340 /// <param name="destinationSlice"> The first slice to copy to if the texture is an 3D or array texture. Must be zero for regular textures.</param> 341 /// <param name="destinationMip"> The first mipmap level to copy to. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures.</param> 342 /// <param name="numSlices"> The number of slices to copy. -1 to copy all slices until the end of the texture. Arguments that copy invalid slices to be copied will lead to an error.</param> 343 /// <param name="numMips"> The number of mipmaps to copy. -1 to copy all mipmaps. Arguments that copy invalid mips to be copied will lead to an error.</param> 344 /// <param name="sourceSlice"> The first slice to copy from if the texture is an 3D or array texture. Must be zero for regular textures. Default is set to -1 to ignore source slices and set it to 0 without looping for each destination slice</param> 345 /// <param name="sourceMip"> The first mipmap level to copy from. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures. Defaults to -1 to ignore source mips and set it to 0 without looping for each destination mip.</param> 346 /// <param name="geometry">Geometry used for blitting the source texture.</param> 347 /// <param name="sourceTexturePropertyID"> 348 /// The texture property to set with the source texture. If -1 the default "_BlitTexture" texture property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 349 /// If propertyBlock is null the texture will be applied directly to the material. 350 /// </param> 351 /// <param name="sourceSlicePropertyID"> 352 /// The scalar property to set with the source slice index. If -1 the default "_BlitTexArraySlice" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 353 /// If more than one slice is rendered using the blit function (numSlices>1) several full screen quads will be rendered for each slice with different sourceSlicePropertyID values set. 354 /// </param> 355 /// <param name="sourceMipPropertyID"> 356 /// The scalar property to set with the source mip index. If -1 the default "_BlitMipLevel" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 357 /// If more than one mip is rendered using the blit function (numMips>1) several full screen quads will be rendered for each slice with different sourceMipPropertyID values set. 358 /// </param> 359 public BlitMaterialParameters(TextureHandle source, TextureHandle destination, Material material, int shaderPass, 360 MaterialPropertyBlock mpb, 361 int destinationSlice, 362 int destinationMip, 363 int numSlices = 1, 364 int numMips = 1, 365 int sourceSlice = -1, 366 int sourceMip = -1, 367 FullScreenGeometryType geometry = FullScreenGeometryType.Mesh, 368 int sourceTexturePropertyID = -1, 369 int sourceSlicePropertyID = -1, 370 int sourceMipPropertyID = -1) 371 : this(source, destination, Vector2.one, Vector2.zero, material, shaderPass, 372 mpb, 373 destinationSlice, destinationMip, 374 numSlices, numMips, 375 sourceSlice, sourceMip, 376 geometry, 377 sourceTexturePropertyID, sourceSlicePropertyID, sourceMipPropertyID) { } 378 379 /// <summary> 380 /// Constructor to set the source and destination mip and slices as well as material property and IDs to interact with it. 381 /// </summary> 382 /// <param name="source">The texture the data is copied from.</param> 383 /// <param name="destination">The texture the data is copied to.</param> 384 /// <param name="scale">Scale for sampling the input texture.</param> 385 /// <param name="offset">Offset also known as bias for sampling the input texture</param> 386 /// <param name="material">Material used for blitting.</param> 387 /// <param name="shaderPass">The shader pass index to use for the material.</param> 388 /// <param name="mpb">Material property block to use to render the blit. This property should contain all data the shader needs.</param> 389 /// <param name="destinationSlice"> The first slice to copy to if the texture is an 3D or array texture. Must be zero for regular textures.</param> 390 /// <param name="destinationMip"> The first mipmap level to copy to. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures.</param> 391 /// <param name="numSlices"> The number of slices to copy. -1 to copy all slices until the end of the texture. Arguments that copy invalid slices to be copied will lead to an error.</param> 392 /// <param name="numMips"> The number of mipmaps to copy. -1 to copy all mipmaps. Arguments that copy invalid mips to be copied will lead to an error.</param> 393 /// <param name="sourceSlice"> The first slice to copy from if the texture is an 3D or array texture. Must be zero for regular textures. Default is set to -1 to ignore source slices and set it to 0 without looping for each destination slice</param> 394 /// <param name="sourceMip"> The first mipmap level to copy from. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures. Defaults to -1 to ignore source mips and set it to 0 without looping for each destination mip.</param> 395 /// <param name="geometry">Geometry used for blitting the source texture.</param> 396 /// <param name="sourceTexturePropertyID"> 397 /// The texture property to set with the source texture. If -1 the default "_BlitTexture" texture property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 398 /// If propertyBlock is null the texture will be applied directly to the material. 399 /// </param> 400 /// <param name="sourceSlicePropertyID"> 401 /// The scalar property to set with the source slice index. If -1 the default "_BlitTexArraySlice" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 402 /// If more than one slice is rendered using the blit function (numSlices>1) several full screen quads will be rendered for each slice with different sourceSlicePropertyID values set. 403 /// </param> 404 /// <param name="sourceMipPropertyID"> 405 /// The scalar property to set with the source mip index. If -1 the default "_BlitMipLevel" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 406 /// If more than one mip is rendered using the blit function (numMips>1) several full screen quads will be rendered for each slice with different sourceMipPropertyID values set. 407 /// </param> 408 /// <param name="scaleBiasPropertyID"> 409 /// The scalar property to set with the scale and bias known as offset. If -1 the default "_BlitScaleBias" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 410 /// </param> 411 public BlitMaterialParameters(TextureHandle source, TextureHandle destination, Vector2 scale, Vector2 offset, Material material, int shaderPass, 412 MaterialPropertyBlock mpb, 413 int destinationSlice, 414 int destinationMip, 415 int numSlices = 1, 416 int numMips = 1, 417 int sourceSlice = -1, 418 int sourceMip = -1, 419 FullScreenGeometryType geometry = FullScreenGeometryType.Mesh, 420 int sourceTexturePropertyID = -1, 421 int sourceSlicePropertyID = -1, 422 int sourceMipPropertyID = -1, 423 int scaleBiasPropertyID = -1) : this(source, destination, scale, offset, material, shaderPass) 424 { 425 this.propertyBlock = mpb; 426 this.sourceSlice = sourceSlice; 427 this.destinationSlice = destinationSlice; 428 this.numSlices = numSlices; 429 this.sourceMip = sourceMip; 430 this.destinationMip = destinationMip; 431 this.numMips = numMips; 432 if (sourceTexturePropertyID != -1) 433 this.sourceTexturePropertyID = sourceTexturePropertyID; 434 if (sourceSlicePropertyID != -1) 435 this.sourceSlicePropertyID = sourceSlicePropertyID; 436 if (sourceMipPropertyID != -1) 437 this.sourceMipPropertyID = sourceMipPropertyID; 438 if (scaleBiasPropertyID != -1) 439 this.scaleBiasPropertyID = scaleBiasPropertyID; 440 this.geometry = geometry; 441 } 442 443 /// <summary> 444 /// Constructor to set textures, material, shader pass and material property block. 445 /// </summary> 446 /// <param name="source">The texture the data is copied from.</param> 447 /// <param name="destination">The texture the data is copied to.</param> 448 /// <param name="material">Material used for blitting.</param> 449 /// <param name="shaderPass">The shader pass index to use for the material.</param> 450 /// <param name="mpb">Material property block to use to render the blit. This property should contain all data the shader needs.</param> 451 /// <param name="geometry">Geometry used for blitting the source texture.</param> 452 /// <param name="sourceTexturePropertyID"> 453 /// The texture property to set with the source texture. If -1 the default "_BlitTexture" texture property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 454 /// If propertyBlock is null the texture will be applied directly to the material. 455 /// </param> 456 /// <param name="sourceSlicePropertyID"> 457 /// The scalar property to set with the source slice index. If -1 the default "_BlitTexArraySlice" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 458 /// If more than one slice is rendered using the blit function (numSlices>1) several full screen quads will be rendered for each slice with different sourceSlicePropertyID values set. 459 /// </param> 460 /// <param name="sourceMipPropertyID"> 461 /// The scalar property to set with the source mip index. If -1 the default "_BlitMipLevel" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 462 /// If more than one mip is rendered using the blit function (numMips>1) several full screen quads will be rendered for each slice with different sourceMipPropertyID values set. 463 /// </param> 464 public BlitMaterialParameters(TextureHandle source, TextureHandle destination, Material material, int shaderPass, 465 MaterialPropertyBlock mpb, 466 FullScreenGeometryType geometry = FullScreenGeometryType.Mesh, 467 int sourceTexturePropertyID = -1, 468 int sourceSlicePropertyID = -1, 469 int sourceMipPropertyID = -1) 470 : this(source, destination, 471 Vector2.one, Vector2.zero, 472 material, shaderPass, 473 mpb, geometry, 474 sourceTexturePropertyID, sourceSlicePropertyID, sourceMipPropertyID) { } 475 476 /// <summary> 477 /// Constructor to set textures, material, shader pass and material property block. 478 /// </summary> 479 /// <param name="source">The texture the data is copied from.</param> 480 /// <param name="destination">The texture the data is copied to.</param> 481 /// <param name="scale">Scale for sampling the input texture.</param> 482 /// <param name="offset">Offset also known as bias for sampling the input texture</param> 483 /// <param name="material">Material used for blitting.</param> 484 /// <param name="shaderPass">The shader pass index to use for the material.</param> 485 /// <param name="mpb">Material property block to use to render the blit. This property should contain all data the shader needs.</param> 486 /// <param name="geometry">Geometry used for blitting the source texture.</param> 487 /// <param name="sourceTexturePropertyID"> 488 /// The texture property to set with the source texture. If -1 the default "_BlitTexture" texture property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 489 /// If propertyBlock is null the texture will be applied directly to the material. 490 /// </param> 491 /// <param name="sourceSlicePropertyID"> 492 /// The scalar property to set with the source slice index. If -1 the default "_BlitSlice" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 493 /// If more than one slice is rendered using the blit function (numSlices>1) several full screen quads will be rendered for each slice with different sourceSlicePropertyID values set. 494 /// </param> 495 /// <param name="sourceMipPropertyID"> 496 /// The scalar property to set with the source mip index. If -1 the default "_BlitMipLevel" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 497 /// If more than one mip is rendered using the blit function (numMips>1) several full screen quads will be rendered for each slice with different sourceMipPropertyID values set. 498 /// </param> 499 /// <param name="scaleBiasPropertyID"> 500 /// The scalar property to set with the scale and bias known as offset. If -1 the default "_BlitScaleBias" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 501 /// </param> 502 public BlitMaterialParameters(TextureHandle source, TextureHandle destination, Vector2 scale, Vector2 offset, Material material, int shaderPass, 503 MaterialPropertyBlock mpb, 504 FullScreenGeometryType geometry = FullScreenGeometryType.Mesh, 505 int sourceTexturePropertyID = -1, 506 int sourceSlicePropertyID = -1, 507 int sourceMipPropertyID = -1, 508 int scaleBiasPropertyID = -1) : this(source, destination, scale, offset, material, shaderPass) 509 { 510 this.propertyBlock = mpb; 511 if (sourceTexturePropertyID != -1) 512 this.sourceTexturePropertyID = sourceTexturePropertyID; 513 if (sourceSlicePropertyID != -1) 514 this.sourceSlicePropertyID = sourceSlicePropertyID; 515 if (sourceMipPropertyID != -1) 516 this.sourceMipPropertyID = sourceMipPropertyID; 517 if (scaleBiasPropertyID != -1) 518 this.scaleBiasPropertyID = scaleBiasPropertyID; 519 this.geometry = geometry; 520 } 521 522 /// <summary> 523 /// The source texture. This texture will be set on the specified material property block property with 524 /// the name specified sourceTexturePropertyID. If the property block is null, a temp property block will 525 /// be allocated by the blit function. 526 /// </summary> 527 public TextureHandle source; 528 529 /// <summary> 530 /// The texture to blit into. This subresources (mips,slices) of this texture texture will be set-up as a render attachment based on the destination argumments. 531 /// </summary> 532 public TextureHandle destination; 533 534 /// <summary> 535 /// The scale used for the blit operation. 536 /// </summary> 537 public Vector2 scale; 538 539 /// <summary> 540 /// The offset of the blit destination. 541 /// </summary> 542 public Vector2 offset; 543 544 /// <summary> 545 /// The first slice of the source texture to blit from. -1 to ignore source slices and set it to 0 without looping for each destination slice. 546 /// </summary> 547 public int sourceSlice; 548 549 /// <summary> 550 /// The first slice of the destination texture to blit into. 551 /// </summary> 552 public int destinationSlice; 553 554 /// <summary> 555 /// The number of slices to blit. -1 to blit all slices until the end of the texture starting from destinationSlice. Arguments that copy invalid slices (e.g. out of range or zero) will lead to an error. 556 /// </summary> 557 public int numSlices; 558 559 /// <summary> 560 /// The first source mipmap to blit from. -1 to ignore source mips and set it to 0 without looping for each destination mip. 561 /// </summary> 562 public int sourceMip; 563 564 /// <summary> 565 /// The first destination mipmap to blit into. 566 /// </summary> 567 public int destinationMip; 568 569 /// <summary> 570 /// The number of mipmaps to blit. -1 to blit all mipmaps until the end of the texture starting from destinationMip. Arguments that copy invalid slices (e.g. out of range or zero) will lead to an error. 571 /// </summary> 572 public int numMips; 573 574 /// <summary> 575 /// The material to use, cannot be null. The blit functions will not modify this material in any way. 576 /// </summary> 577 public Material material; 578 579 /// <summary> 580 /// The shader pass index to use. 581 /// </summary> 582 public int shaderPass; 583 584 /// <summary> 585 /// The material propery block to use, can be null. The blit functions will modify the sourceTexturePropertyID, sourceSliceProperty, and sourceMipPropertyID of this material poperty block as part of the blit. 586 /// Calling propertyBlock's SetTexture(...) function used by BlitMaterialParameters should be avoid since it will cause untracked textures when using RenderGraph. This can cause unexpected behaviours. 587 /// </summary> 588 public MaterialPropertyBlock propertyBlock; 589 590 /// <summary> 591 /// The texture property to set with the source texture. If -1 the default "_BlitTexture" texture property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 592 /// If propertyBlock is null the texture will be applied directly to the material. 593 /// </summary> 594 public int sourceTexturePropertyID; 595 596 /// <summary> 597 /// The scalar property to set with the source slice index. If -1 the default "_BlitTexArraySlice" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 598 /// If more than one slice is rendered using the blit function (numSlices>1) several full screen quads will be rendered for each slice with different sourceSlicePropertyID values set. 599 /// </summary> 600 public int sourceSlicePropertyID; 601 602 /// <summary> 603 /// The scalar property to set with the source mip index. If -1 the default "_BlitMipLevel" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 604 /// If more than one mip is rendered using the blit function (numMips>1) several full screen quads will be rendered for each slice with different sourceMipPropertyID values set./// 605 /// </summary> 606 public int sourceMipPropertyID; 607 608 /// <summary> 609 /// The scalar property to set with the scale and bias also known as offset from the source to distination. If -1 the default "_BlitScaleBias" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. 610 /// </summary> 611 public int scaleBiasPropertyID; 612 613 /// <summary> 614 /// The type of full-screen geometry to use when rendering the blit material. See FullScreenGeometryType for details. 615 /// </summary> 616 public FullScreenGeometryType geometry; 617 } 618 619 class BlitMaterialPassData 620 { 621 public int sourceTexturePropertyID; 622 public TextureHandle source; 623 public TextureHandle destination; 624 public Vector2 scale; 625 public Vector2 offset; 626 public Material material; 627 public int shaderPass; 628 public MaterialPropertyBlock propertyBlock; 629 public int sourceSlice; 630 public int destinationSlice; 631 public int numSlices; 632 public int sourceMip; 633 public int destinationMip; 634 public int numMips; 635 public FullScreenGeometryType geometry; 636 public int sourceSlicePropertyID; 637 public int sourceMipPropertyID; 638 public int scaleBiasPropertyID; 639 } 640 641 /// <summary> 642 /// Add a render graph pass to blit an area of the source texture into the destination texture. Blitting is a high-level way to transfer texture data from a source to a destination texture. 643 /// In this overload the data may be transformed by an arbitrary material. 644 /// 645 /// This function works transparently with regular textures and XR textures (which may depending on the situation be 2D array textures) if numSlices is set to -1 and the slice property works correctly. 646 /// 647 /// This is a helper function to schedule a simple pass calling a single blit. If you want to call a number of blits in a row (e.g. to a slice-by-slice or mip-by-mip blit) it's generally faster 648 /// to simple schedule a single pass and then do schedule blits directly on the command buffer. 649 /// 650 /// This function schedules a pass for execution on the rendergraph execution timeline. It's important to ensure the passed material and material property blocks correctly account for this behavior in 651 /// particular the following code will likely not behave as intented: 652 /// material.SetFloat("Visibility", 0.5); 653 /// renderGraph.AddBlitPass(... material ...); 654 /// material.SetFloat("Visibility", 0.8); 655 /// renderGraph.AddBlitPass(... material ...); 656 /// 657 /// This will result in both passes using the float value "Visibility" as when the graph is executed the value in the material is assigned 0.8. The correct way to handle such use cases is either using two separate 658 /// materials or using two separate material property blocks. E.g. : 659 /// 660 /// propertyBlock1.SetFloat("Visibility", 0.5); 661 /// renderGraph.AddBlitPass(... material, propertyBlock1, ...); 662 /// propertyBlock2.SetFloat("Visibility", 0.8); 663 /// renderGraph.AddBlitPass(... material, propertyBlock2, ...); 664 /// 665 /// Notes on using this function: 666 /// - If you need special handling of MSAA buffers this can be implemented using the bindMS flag on the source texture and per-sample pixel shader invocation on the destination texture (e.g. using SV_SampleIndex). 667 /// - MaterialPropertyBlocks used for this function should not contain any textures added by MaterialPropertyBlock.SetTexture(...) as it will cause untracked textures when using RenderGraph causing uninstended behaviour. 668 /// 669 /// </summary> 670 /// <param name="graph">The RenderGraph adding this pass to.</param> 671 /// <param name="blitParameters">Parameters used for rendering.</param> 672 /// <param name="passName">A name to use for debugging and error logging. This name will be shown in the rendergraph debugger. </param> 673 /// <param name="file">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param> 674 /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param> 675 public static void AddBlitPass(this RenderGraph graph, 676 BlitMaterialParameters blitParameters, 677 string passName = "Blit Pass Utility w. Material" 678#if !CORE_PACKAGE_DOCTOOLS 679 , [CallerFilePath] string file = "", 680 [CallerLineNumber] int line = 0) 681#endif 682 { 683 var sourceDesc = graph.GetTextureDesc(blitParameters.source); 684 var destinationDesc = graph.GetTextureDesc(blitParameters.destination); 685 686 int sourceMaxWidth = math.max(math.max(sourceDesc.width, sourceDesc.height), sourceDesc.slices); 687 int sourceTotalMipChainLevels = (int)math.log2(sourceMaxWidth) + 1; 688 689 int destinationMaxWidth = math.max(math.max(destinationDesc.width, destinationDesc.height), destinationDesc.slices); 690 int destinationTotalMipChainLevels = (int)math.log2(destinationMaxWidth) + 1; 691 692 if (blitParameters.numSlices == -1) blitParameters.numSlices = destinationDesc.slices - blitParameters.destinationSlice; 693 if (blitParameters.numSlices > destinationDesc.slices - blitParameters.destinationSlice 694 || (blitParameters.sourceSlice != -1 && blitParameters.numSlices > sourceDesc.slices - blitParameters.sourceSlice)) 695 { 696 throw new ArgumentException($"BlitPass: {passName} attempts to blit too many slices. The pass will be skipped."); 697 } 698 699 if (blitParameters.numMips == -1) blitParameters.numMips = destinationTotalMipChainLevels - blitParameters.destinationMip; 700 if (blitParameters.numMips > destinationTotalMipChainLevels - blitParameters.destinationMip 701 || (blitParameters.sourceMip != -1 && blitParameters.numMips > sourceTotalMipChainLevels - blitParameters.sourceMip)) 702 { 703 throw new ArgumentException($"BlitPass: {passName} attempts to blit too many mips. The pass will be skipped."); 704 } 705 706 using (var builder = graph.AddUnsafePass<BlitMaterialPassData>(passName, out var passData, file, line)) 707 { 708 passData.sourceTexturePropertyID = blitParameters.sourceTexturePropertyID; 709 passData.source = blitParameters.source; 710 passData.destination = blitParameters.destination; 711 passData.scale = blitParameters.scale; 712 passData.offset = blitParameters.offset; 713 passData.material = blitParameters.material; 714 passData.shaderPass = blitParameters.shaderPass; 715 passData.propertyBlock = blitParameters.propertyBlock; 716 passData.sourceSlice = blitParameters.sourceSlice; 717 passData.destinationSlice = blitParameters.destinationSlice; 718 passData.numSlices = blitParameters.numSlices; 719 passData.sourceMip = blitParameters.sourceMip; 720 passData.destinationMip = blitParameters.destinationMip; 721 passData.numMips = blitParameters.numMips; 722 passData.geometry = blitParameters.geometry; 723 passData.sourceSlicePropertyID = blitParameters.sourceSlicePropertyID; 724 passData.sourceMipPropertyID = blitParameters.sourceMipPropertyID; 725 passData.scaleBiasPropertyID = blitParameters.scaleBiasPropertyID; 726 727 builder.UseTexture(blitParameters.source); 728 builder.UseTexture(blitParameters.destination, AccessFlags.Write); 729 builder.SetRenderFunc((BlitMaterialPassData data, UnsafeGraphContext context) => BlitMaterialRenderFunc(data, context)); 730 } 731 } 732 733 static void BlitMaterialRenderFunc(BlitMaterialPassData data, UnsafeGraphContext context) 734 { 735 s_BlitScaleBias.x = data.scale.x; 736 s_BlitScaleBias.y = data.scale.y; 737 s_BlitScaleBias.z = data.offset.x; 738 s_BlitScaleBias.w = data.offset.y; 739 740 CommandBuffer unsafeCmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd); 741 742 if (data.propertyBlock == null) data.propertyBlock = s_PropertyBlock; 743 744 data.propertyBlock.SetTexture(data.sourceTexturePropertyID, data.source); 745 if (data.sourceSlice == -1) 746 data.propertyBlock.SetInt(data.sourceSlicePropertyID, 0); 747 if (data.sourceMip == -1) 748 data.propertyBlock.SetInt(data.sourceMipPropertyID, 0); 749 data.propertyBlock.SetVector(data.scaleBiasPropertyID, s_BlitScaleBias); 750 751 for (int currSlice = 0; currSlice < data.numSlices; currSlice++) 752 { 753 for (int currMip = 0; currMip < data.numMips; currMip++) 754 { 755 if (data.sourceSlice != -1) 756 data.propertyBlock.SetInt(data.sourceSlicePropertyID, data.sourceSlice + currSlice); 757 if (data.sourceMip != -1) 758 data.propertyBlock.SetInt(data.sourceMipPropertyID, data.sourceMip + currMip); 759 760 context.cmd.SetRenderTarget(data.destination, data.destinationMip + currMip, CubemapFace.Unknown, data.destinationSlice + currSlice); 761 switch (data.geometry) 762 { 763 case FullScreenGeometryType.Mesh: 764 Blitter.DrawQuadMesh(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); 765 break; 766 case FullScreenGeometryType.ProceduralQuad: 767 Blitter.DrawQuad(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); 768 break; 769 case FullScreenGeometryType.ProceduralTriangle: 770 Blitter.DrawTriangle(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); 771 break; 772 } 773 } 774 } 775 } 776 } 777}