using UnityEngine.Rendering; using UnityEngine.SubsystemsImplementation.Extensions; using UnityEngine.XR.ARFoundation.InternalUtils; #if URP_7_OR_NEWER using UnityEngine.Rendering.Universal; using UnityEngine.XR.ARSubsystems; using System; #if URP_17_OR_NEWER using UnityEngine.Rendering.RenderGraphModule; #else using UnityEngine.Experimental.Rendering; #endif // URP_17_OR_NEWER #else using ScriptableRendererFeature = UnityEngine.ScriptableObject; #endif // URP_7_OR_NEWER namespace UnityEngine.XR.ARFoundation { /// /// A renderer feature that gives support to XRSessionSubsystem providers that need access to URP /// command buffers. /// public class ARCommandBufferSupportRendererFeature : ScriptableRendererFeature { #if URP_7_OR_NEWER /// /// A non-render pass that only injects the plugin event callback into command buffer to support session subsystem /// rendering modification. /// class EventInjectionRenderPass : ScriptableRenderPass { public EventInjectionRenderPass() { // Configure the event to be invoked before rendering started. // This ensures that necessary resources are ready when required during rendering. renderPassEvent = RenderPassEvent.BeforeRendering; } static readonly string k_NonRenderGraphPassName = "XRSessionSubsystem Command Buffer Event Injection Pass (Render Graph Disabled)"; #if URP_17_OR_NEWER /// /// No data is passed during this pass. /// private class PassData { } /// /// Name of our RenderGraph render pass. /// static readonly string k_RenderGraphPassName = "XRSessionSubsystem Command Buffer Event Injection Pass (Render Graph Enabled)"; /// /// Execute the commands to inject the plugin event callback with RenderGraph enabled. /// /// PassData is unused for this render pass. /// The UnsafeGraphContext object that gives us access to the native /// CommandBuffer object to enqueue rendering instructions for this RenderGraph pass. static void ExecutePass(PassData data, UnsafeGraphContext unsafeContext) { var nativeCommandBuffer = CommandBufferHelpers.GetNativeCommandBuffer(unsafeContext.cmd); ExecuteRenderPass(nativeCommandBuffer); } /// /// Add the unsafe pass to the RenderGraph object in order to inject the plugin event callback. /// /// The RenderGraph object that we add the unsafe render pass to. /// A ContextContainer object that is unused for this RenderGraph pass. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { if (RequiresCommandBufferSupport(out var sessionSubsystem)) { using (var builder = renderGraph.AddUnsafePass(k_RenderGraphPassName, out PassData passData)) { builder.AllowPassCulling(false); builder.SetRenderFunc(ExecutePass); } sessionSubsystem.OnCommandBufferSupportEnabled(); } } #endif // URP_17_OR_NEWER /// /// Execute the commands to inject the plugin event callback. This function is used for both RenderGraph and /// non-RenderGraph paths. /// /// The CommandBuffer object that allows us to enqueue rendering instructions for this render pass. /// The data that is passed to the function that executes this render pass. static void ExecuteRenderPass(CommandBuffer commandBuffer) { if (RequiresCommandBufferSupport(out var sessionSubsystem)) sessionSubsystem.OnCommandBufferExecute(commandBuffer); } /// /// Execute the commands to inject the plugin event callback with RenderGraph disabled. /// /// The render context for executing the render commands. /// Additional rendering data about the current state of rendering. #pragma warning disable CS0672 public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) #pragma warning restore CS0672 { var commandBuffer = CommandBufferPool.Get(k_NonRenderGraphPassName); ExecuteRenderPass(commandBuffer); context.ExecuteCommandBuffer(commandBuffer); CommandBufferPool.Release(commandBuffer); } } EventInjectionRenderPass m_EventInjectionPass; /// /// Create the scriptable render pass. /// public override void Create() { m_EventInjectionPass = new EventInjectionRenderPass(); if (RequiresCommandBufferSupport(out var sessionSubsystem)) sessionSubsystem.GetProvider().OnCommandBufferSupportEnabled(); } /// /// Add the render pass to inject the plugin event callback. /// /// The scriptable renderer in which to enqueue the render pass. /// Additional rendering data about the current state of rendering. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { if (RequiresCommandBufferSupport(out var _)) { renderer.EnqueuePass(m_EventInjectionPass); } } static bool RequiresCommandBufferSupport(out XRSessionSubsystem sessionSubsystem) { return SubsystemUtils.TryGetLoadedSubsystem(out sessionSubsystem) && (sessionSubsystem?.requiresCommandBuffer ?? false); } #endif // URP_7_OR_NEWER } }