using System; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; namespace UnityEngine.Rendering.Universal { /// /// Draw screen space overlay UI into the given color and depth target /// internal class DrawScreenSpaceUIPass : ScriptableRenderPass { /// /// Creates a new DrawScreenSpaceUIPass instance. /// /// The RenderPassEvent to use. /// public DrawScreenSpaceUIPass(RenderPassEvent evt) { profilingSampler = ProfilingSampler.Get(URPProfileId.DrawScreenSpaceUI); renderPassEvent = evt; } /// /// Get a descriptor for the required color texture for offscreen UI pass. /// internal static void ConfigureOffscreenUITextureDesc(ref TextureDesc textureDesc) { textureDesc.format = GraphicsFormat.R8G8B8A8_SRGB; textureDesc.depthBufferBits = 0; textureDesc.width = Screen.width; textureDesc.height = Screen.height; } /// /// Get a descriptor for the required depth texture for this pass. /// /// Camera target descriptor. /// Depth stencil format required. /// The full screen width. /// The full screen height. /// private static void ConfigureDepthDescriptor(ref RenderTextureDescriptor descriptor, GraphicsFormat depthStencilFormat, int screenWidth, int screenHeight) { descriptor.graphicsFormat = GraphicsFormat.None; descriptor.depthStencilFormat = depthStencilFormat; descriptor.width = screenWidth; descriptor.height = screenHeight; } private static void ExecutePass(RasterCommandBuffer commandBuffer, PassData passData, RendererList rendererList) { commandBuffer.DrawRendererList(rendererList); } // Specific to RG cases which have to go through Unsafe commands private static void ExecutePass(UnsafeCommandBuffer commandBuffer, UnsafePassData passData, RendererList rendererList) { commandBuffer.DrawRendererList(rendererList); } public void Dispose() { } //RenderGraph path private class PassData { internal RendererListHandle rendererList; } // Specific to RG cases which have to go through Unsafe commands private class UnsafePassData { internal RendererListHandle rendererList; internal TextureHandle colorTarget; } internal void RenderOffscreen(RenderGraph renderGraph, ContextContainer frameData, GraphicsFormat depthStencilFormat, TextureHandle overlayUITexture) { UniversalCameraData cameraData = frameData.Get(); RenderTextureDescriptor depthDescriptor = cameraData.cameraTargetDescriptor; ConfigureDepthDescriptor(ref depthDescriptor, depthStencilFormat, Screen.width, Screen.height); TextureHandle depthBuffer = UniversalRenderer.CreateRenderGraphTexture(renderGraph, depthDescriptor, "_OverlayUITexture_Depth", false); // Render uGUI and UIToolkit overlays using (var builder = renderGraph.AddRasterRenderPass("Draw Screen Space UIToolkit/uGUI - Offscreen", out var passData, profilingSampler)) { // UIToolkit/uGUI pass accept custom shaders, we need to make sure we use all global textures builder.UseAllGlobalTextures(true); builder.SetRenderAttachment(overlayUITexture, 0); passData.rendererList = renderGraph.CreateUIOverlayRendererList(cameraData.camera, UISubset.UIToolkit_UGUI); builder.UseRendererList(passData.rendererList); builder.SetRenderAttachmentDepth(depthBuffer, AccessFlags.ReadWrite); if (overlayUITexture.IsValid()) builder.SetGlobalTextureAfterPass(overlayUITexture, ShaderPropertyId.overlayUITexture); builder.SetRenderFunc(static (PassData data, RasterGraphContext context) => { context.cmd.ClearRenderTarget(true, true, Color.clear); ExecutePass(context.cmd, data, data.rendererList); }); } // Render IMGUI overlay and software cursor in a UnsafePass // Doing so allow us to safely cover cases when graphics commands called through onGUI() in user scripts are not supported by RenderPass API // Besides, Vulkan backend doesn't support SetSRGWrite() in RenderPass API and we have some of them at IMGUI levels // Note, these specific UI calls doesn't need depth buffer unlike UIToolkit/uGUI using (var builder = renderGraph.AddUnsafePass("Draw Screen Space IMGUI/SoftwareCursor - Offscreen", out var passData, profilingSampler)) { passData.colorTarget = overlayUITexture; builder.UseTexture(overlayUITexture, AccessFlags.Write); passData.rendererList = renderGraph.CreateUIOverlayRendererList(cameraData.camera, UISubset.LowLevel); builder.UseRendererList(passData.rendererList); builder.SetRenderFunc(static (UnsafePassData data, UnsafeGraphContext context) => { context.cmd.SetRenderTarget(data.colorTarget); ExecutePass(context.cmd, data, data.rendererList); }); } } internal void RenderOverlay(RenderGraph renderGraph, ContextContainer frameData, in TextureHandle colorBuffer, in TextureHandle depthBuffer) { UniversalCameraData cameraData = frameData.Get(); UniversalResourceData resourceData = frameData.Get(); UniversalRenderer renderer = cameraData.renderer as UniversalRenderer; // Render uGUI and UIToolkit overlays using (var builder = renderGraph.AddRasterRenderPass("Draw UIToolkit/uGUI Overlay", out var passData, profilingSampler)) { // UIToolkit/uGUI pass accept custom shaders, we need to make sure we use all global textures builder.UseAllGlobalTextures(true); builder.SetRenderAttachment(colorBuffer, 0); builder.SetRenderAttachmentDepth(depthBuffer, AccessFlags.ReadWrite); passData.rendererList = renderGraph.CreateUIOverlayRendererList(cameraData.camera, UISubset.UIToolkit_UGUI); builder.UseRendererList(passData.rendererList); builder.SetRenderFunc(static (PassData data, RasterGraphContext context) => { ExecutePass(context.cmd, data, data.rendererList); }); } // Render IMGUI overlay and software cursor in a UnsafePass // Doing so allow us to safely cover cases when graphics commands called through onGUI() in user scripts are not supported by RenderPass API // Besides, Vulkan backend doesn't support SetSRGWrite() in RenderPass API and we have some of them at IMGUI levels // Note, these specific UI calls doesn't need depth buffer unlike UIToolkit/uGUI using (var builder = renderGraph.AddUnsafePass("Draw IMGUI/SoftwareCursor Overlay", out var passData, profilingSampler)) { passData.colorTarget = colorBuffer; builder.UseTexture(colorBuffer, AccessFlags.Write); passData.rendererList = renderGraph.CreateUIOverlayRendererList(cameraData.camera, UISubset.LowLevel); builder.UseRendererList(passData.rendererList); builder.SetRenderFunc(static (UnsafePassData data, UnsafeGraphContext context) => { context.cmd.SetRenderTarget(data.colorTarget); ExecutePass(context.cmd, data, data.rendererList); }); } } } }