From ec705e3d8d8df0147e5b8eaafccede17e96caa5c Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Fri, 26 Jul 2024 22:50:58 +0200 Subject: [PATCH] Implemented remaining dispatch code --- .../FrameInterpolationContext.cs | 78 ++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/Runtime/FrameInterpolation/FrameInterpolationContext.cs b/Runtime/FrameInterpolation/FrameInterpolationContext.cs index bd9e420..cc690d7 100644 --- a/Runtime/FrameInterpolation/FrameInterpolationContext.cs +++ b/Runtime/FrameInterpolation/FrameInterpolationContext.cs @@ -1,4 +1,5 @@ -using System.Runtime.InteropServices; +using System; +using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.Assertions; using UnityEngine.Profiling; @@ -191,9 +192,51 @@ namespace FidelityFX.FrameGen int opticalFlowDispatchSizeY = (int)(dispatchDescription.displaySize.y / (float)dispatchDescription.opticalFlowBlockSize + 7) / 8; bool executePreparationPasses = (Constants.reset == 0); + + // TODO: do we have to clear some buffers somewhere on reset? Probably uninitialized RTs are kept to NULL in FFX source... we might want to clear them. Specifically the inputs for InterpolationPass. // Schedule work for the interpolation command list - // TODO + _setupPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, renderDispatchSizeX, renderDispatchSizeY); + + Action dispatchGameVectorFieldInpaintingPyramid = () => + { + SetupSpdConstants(dispatchDescription.renderSize, out var dispatchThreadGroupCount); + commandBuffer.SetBufferData(_spdConstantsBuffer, _spdConstantsArray); + _gameVectorFieldInpaintingPyramidPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y); + }; + + // Only execute FG data preparation passes when reset wasn't triggered + if (executePreparationPasses) + { + // Clear estimated depth resources + bool inverted = (_contextDescription.flags & FrameInterpolation.InitializationFlags.EnableDepthInverted) == FrameInterpolation.InitializationFlags.EnableDepthInverted; + commandBuffer.SetRenderTarget(_resources.ReconstructedDepthInterpolatedFrame); + commandBuffer.ClearRenderTarget(false, true, inverted ? Color.clear : Color.white); + + _reconstructPreviousDepthPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, renderDispatchSizeX, renderDispatchSizeY); + _gameMotionVectorFieldPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, renderDispatchSizeX, renderDispatchSizeY); + dispatchGameVectorFieldInpaintingPyramid(); + _opticalFlowVectorFieldPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, opticalFlowDispatchSizeX, opticalFlowDispatchSizeY); + _disocclusionMaskPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, renderDispatchSizeX, renderDispatchSizeY); + } + + _interpolationPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, displayDispatchSizeX, displayDispatchSizeY); + + // Inpainting pyramid + SetupSpdConstants(dispatchDescription.displaySize, out var dispatchThreadGroupCount); + commandBuffer.SetBufferData(_spdConstantsBuffer, _spdConstantsArray); + _inpaintingPyramidPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y); + + _inpaintingPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, displayDispatchSizeX, displayDispatchSizeY); + + if ((dispatchDescription.flags & FrameInterpolation.DispatchFlags.DrawDebugView) != 0) + { + dispatchGameVectorFieldInpaintingPyramid(); + _debugViewPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, displayDispatchSizeX, displayDispatchSizeY); + } + + // Store current buffer + commandBuffer.CopyTexture(FrameInterpolationShaderIDs.SrvCurrentInterpolationSource, _resources.PreviousInterpolationSource); commandBuffer.EndSample(_sampler); } @@ -230,6 +273,37 @@ namespace FidelityFX.FrameGen aspect / cotHalfFovY, 1.0f / cotHalfFovY); } + + private void SetupSpdConstants(Vector2Int resolution, out Vector2Int dispatchThreadGroupCount) + { + const int resolutionMultiplier = 1; + + RectInt rectInfo = new RectInt(0, 0, resolution.x * resolutionMultiplier, resolution.y * resolutionMultiplier); + SpdSetup(rectInfo, out dispatchThreadGroupCount, out var workGroupOffset, out var numWorkGroupsAndMips, 4); + + ref FrameInterpolation.InpaintingPyramidConstants spdConstants = ref SpdConstants; + spdConstants.numWorkGroups = (uint)numWorkGroupsAndMips.x; + spdConstants.mips = (uint)numWorkGroupsAndMips.y; + spdConstants.workGroupOffsetX = (uint)workGroupOffset.x; + spdConstants.workGroupOffsetY = (uint)workGroupOffset.y; + } + + private static void SpdSetup(RectInt rectInfo, out Vector2Int dispatchThreadGroupCount, out Vector2Int workGroupOffset, out Vector2Int numWorkGroupsAndMips, int mips = -1) + { + workGroupOffset = new Vector2Int(rectInfo.x / 64, rectInfo.y / 64); + + int endIndexX = (rectInfo.x + rectInfo.width - 1) / 64; + int endIndexY = (rectInfo.y + rectInfo.height - 1) / 64; + + dispatchThreadGroupCount = new Vector2Int(endIndexX + 1 - workGroupOffset.x, endIndexY + 1 - workGroupOffset.y); + + numWorkGroupsAndMips = new Vector2Int(dispatchThreadGroupCount.x * dispatchThreadGroupCount.y, mips); + if (mips < 0) + { + float resolution = Math.Max(rectInfo.width, rectInfo.height); + numWorkGroupsAndMips.y = Math.Min(Mathf.FloorToInt(Mathf.Log(resolution, 2.0f)), 12); + } + } private int _debugIndex = 0; private static readonly float[] DebugBarColorSequence =