Browse Source

Implemented resources, shader IDs, the skeleton for all passes, setup and destruction, a bunch of helper methods and dispatch of the prepare luma pass.

fsr3framegen
Nico de Poel 2 years ago
parent
commit
70121d1516
  1. 1
      Runtime/OpticalFlow/OpticalFlow.cs
  2. 186
      Runtime/OpticalFlow/OpticalFlowContext.cs
  3. 154
      Runtime/OpticalFlow/OpticalFlowPass.cs
  4. 11
      Runtime/OpticalFlow/OpticalFlowPass.cs.meta
  5. 189
      Runtime/OpticalFlow/OpticalFlowResources.cs
  6. 11
      Runtime/OpticalFlow/OpticalFlowResources.cs.meta
  7. 33
      Runtime/OpticalFlow/OpticalFlowShaderIDs.cs
  8. 11
      Runtime/OpticalFlow/OpticalFlowShaderIDs.cs.meta

1
Runtime/OpticalFlow/OpticalFlow.cs

@ -14,6 +14,7 @@ namespace FidelityFX.OpticalFlow
public struct ContextDescription public struct ContextDescription
{ {
public Vector2Int resolution; public Vector2Int resolution;
public OpticalFlowShaders shaders;
} }
public struct DispatchDescription public struct DispatchDescription

186
Runtime/OpticalFlow/OpticalFlowContext.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering; using UnityEngine.Rendering;
@ -6,12 +7,191 @@ namespace FidelityFX.OpticalFlow
{ {
public class OpticalFlowContext public class OpticalFlowContext
{ {
private bool _firstExecution = true;
private uint _resourceFrameIndex;
private const int MaxQueuedFrames = 16;
private OpticalFlow.ContextDescription _contextDescription;
private OpticalFlowPass _prepareLumaPass;
private OpticalFlowPass _generateInputPyramidPass;
private OpticalFlowPass _generateScdHistogramPass;
private OpticalFlowPass _computeScdDivergencePass;
private OpticalFlowPass _computeOpticalFlowPass;
private OpticalFlowPass _filterOpticalFlowPass;
private OpticalFlowPass _scaleOpticalFlowPass;
private readonly OpticalFlowResources _resources = new OpticalFlowResources();
private ComputeBuffer _opticalFlowConstantsBuffer;
private readonly OpticalFlow.OpticalFlowConstants[] _opticalFlowConstantsArray = { new OpticalFlow.OpticalFlowConstants() };
private ref OpticalFlow.OpticalFlowConstants Constants => ref _opticalFlowConstantsArray[0];
private ComputeBuffer _spdConstantsBuffer;
private readonly OpticalFlow.SpdConstants[] _spdConstantsArray = { new OpticalFlow.SpdConstants() };
private ref OpticalFlow.SpdConstants SpdConsts => ref _spdConstantsArray[0];
private bool _firstExecution;
private int _resourceFrameIndex;
public void Create(OpticalFlow.ContextDescription contextDescription)
{
_contextDescription = contextDescription;
_opticalFlowConstantsBuffer = CreateConstantBuffer<OpticalFlow.OpticalFlowConstants>();
_spdConstantsBuffer = CreateConstantBuffer<OpticalFlow.SpdConstants>();
_firstExecution = true;
_resourceFrameIndex = 0;
Constants.inputLumaResolution = _contextDescription.resolution;
_resources.Create(_contextDescription);
CreatePasses();
}
private void CreatePasses()
{
_prepareLumaPass = new OpticalFlowPrepareLumaPass(_contextDescription, _resources, _opticalFlowConstantsBuffer);
_generateInputPyramidPass = new OpticalFlowGenerateInputPyramidPass(_contextDescription, _resources, _opticalFlowConstantsBuffer, _spdConstantsBuffer);
_generateScdHistogramPass = new OpticalFlowGenerateSCDHistogramPass(_contextDescription, _resources, _opticalFlowConstantsBuffer);
_computeScdDivergencePass = new OpticalFlowComputeSCDDivergencePass(_contextDescription, _resources, _opticalFlowConstantsBuffer);
_computeOpticalFlowPass = new OpticalFlowComputePass(_contextDescription, _resources, _opticalFlowConstantsBuffer);
_filterOpticalFlowPass = new OpticalFlowFilterPass(_contextDescription, _resources, _opticalFlowConstantsBuffer);
_scaleOpticalFlowPass = new OpticalFlowScalePass(_contextDescription, _resources, _opticalFlowConstantsBuffer);
}
public void Destroy()
{
DestroyPass(ref _scaleOpticalFlowPass);
DestroyPass(ref _filterOpticalFlowPass);
DestroyPass(ref _computeOpticalFlowPass);
DestroyPass(ref _computeScdDivergencePass);
DestroyPass(ref _generateScdHistogramPass);
DestroyPass(ref _generateInputPyramidPass);
DestroyPass(ref _prepareLumaPass);
_resources.Destroy();
DestroyConstantBuffer(ref _spdConstantsBuffer);
DestroyConstantBuffer(ref _opticalFlowConstantsBuffer);
}
public void Dispatch(CommandBuffer commandBuffer, in OpticalFlow.DispatchDescription dispatchDescription) public void Dispatch(CommandBuffer commandBuffer, in OpticalFlow.DispatchDescription dispatchDescription)
{ {
throw new NotImplementedException();
const int advancedAlgorithmIterations = 7;
const int opticalFlowBlockSize = 8;
Constants.backbufferTransferFunction = (uint)dispatchDescription.backbufferTransferFunction;
Constants.minMaxLuminance = dispatchDescription.minMaxLuminance;
int frameIndex = _resourceFrameIndex % 2;
bool resetAccumulation = dispatchDescription.reset || _firstExecution;
_firstExecution = false;
if (resetAccumulation)
Constants.frameIndex = 0;
else
Constants.frameIndex++;
if (resetAccumulation)
{
commandBuffer.SetRenderTarget(_resources.OpticalFlowSCDTemp);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(dispatchDescription.opticalFlowSCD.RenderTarget);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.OpticalFlowSCDHistogram);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.OpticalFlowSCDPreviousHistogram);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
for (int i = 0; i < 2; ++i)
{
commandBuffer.SetRenderTarget(_resources.OpticalFlowInput[i]);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.OpticalFlowInputLevel1[i]);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.OpticalFlowInputLevel2[i]);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.OpticalFlowInputLevel3[i]);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.OpticalFlowInputLevel4[i]);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.OpticalFlowInputLevel5[i]);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.OpticalFlowInputLevel6[i]);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
}
}
SetupSpdConstants(out var dispatchThreadGroupCount);
commandBuffer.SetBufferData(_opticalFlowConstantsBuffer, _opticalFlowConstantsArray);
commandBuffer.SetBufferData(_spdConstantsBuffer, _spdConstantsArray);
{
const int threadGroupSizeX = 16;
const int threadGroupSizeY = 16;
const int threadPixelsX = 2;
const int threadPixelsY = 2;
int dispatchX = ((_contextDescription.resolution.x + (threadPixelsX - 1)) / threadPixelsX + (threadGroupSizeX - 1)) / threadGroupSizeX;
int dispatchY = ((_contextDescription.resolution.y + (threadPixelsY - 1)) / threadPixelsY + (threadGroupSizeY - 1)) / threadGroupSizeY;
_prepareLumaPass.ScheduleDispatch(commandBuffer, dispatchDescription, frameIndex, dispatchX, dispatchY);
}
_resourceFrameIndex = (_resourceFrameIndex + 1) % MaxQueuedFrames;
}
private void SetupSpdConstants(out Vector2Int dispatchThreadGroupCount)
{
const int resolutionMultiplier = 1;
RectInt rectInfo = new RectInt(0, 0, _contextDescription.resolution.x * resolutionMultiplier, _contextDescription.resolution.y * resolutionMultiplier);
SpdSetup(rectInfo, out dispatchThreadGroupCount, out var workGroupOffset, out var numWorkGroupsAndMips, 4);
ref OpticalFlow.SpdConstants spdConstants = ref SpdConsts;
spdConstants.numWorkGroups = (uint)numWorkGroupsAndMips.x;
spdConstants.mips = (uint)numWorkGroupsAndMips.y;
spdConstants.workGroupOffsetX = (uint)workGroupOffset.x;
spdConstants.workGroupOffsetY = (uint)workGroupOffset.y;
spdConstants.numWorkGroupsOpticalFlowInputPyramid = (uint)numWorkGroupsAndMips.x;
}
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 static ComputeBuffer CreateConstantBuffer<TConstants>() where TConstants: struct
{
return new ComputeBuffer(1, Marshal.SizeOf<TConstants>(), ComputeBufferType.Constant);
}
private static void DestroyConstantBuffer(ref ComputeBuffer bufferRef)
{
if (bufferRef == null)
return;
bufferRef.Release();
bufferRef = null;
}
private static void DestroyPass(ref OpticalFlowPass pass)
{
if (pass == null)
return;
pass.Dispose();
pass = null;
} }
} }
} }

154
Runtime/OpticalFlow/OpticalFlowPass.cs

@ -0,0 +1,154 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
namespace FidelityFX.OpticalFlow
{
internal abstract class OpticalFlowPass: IDisposable
{
protected readonly OpticalFlow.ContextDescription ContextDescription;
protected readonly OpticalFlowResources Resources;
protected readonly ComputeBuffer Constants;
protected ComputeShader ComputeShader;
protected int KernelIndex;
private CustomSampler _sampler;
protected OpticalFlowPass(OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
{
ContextDescription = contextDescription;
Resources = resources;
Constants = constants;
}
public virtual void Dispose()
{
}
public void ScheduleDispatch(CommandBuffer commandBuffer, OpticalFlow.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
commandBuffer.BeginSample(_sampler);
DoScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchX, dispatchY);
commandBuffer.EndSample(_sampler);
}
protected abstract void DoScheduleDispatch(CommandBuffer commandBuffer, OpticalFlow.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY);
protected void InitComputeShader(string passName, ComputeShader shader)
{
if (shader == null)
{
throw new MissingReferenceException($"Shader for Optical Flow pass '{passName}' could not be loaded! Please ensure it is included in the project correctly.");
}
ComputeShader = shader;
KernelIndex = ComputeShader.FindKernel("CS");
_sampler = CustomSampler.Create(passName);
}
}
internal class OpticalFlowPrepareLumaPass : OpticalFlowPass
{
public OpticalFlowPrepareLumaPass(OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
InitComputeShader("Prepare Luma", contextDescription.shaders.prepareLuma);
}
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, OpticalFlow.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
ref var color = ref dispatchParams.color;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowInput, Resources.OpticalFlowInput[frameIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, OpticalFlowShaderIDs.CbOpticalFlow, Constants, 0, Marshal.SizeOf<OpticalFlow.OpticalFlowConstants>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
}
internal class OpticalFlowGenerateInputPyramidPass : OpticalFlowPass
{
private ComputeBuffer _spdConstants;
public OpticalFlowGenerateInputPyramidPass(OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
: base(contextDescription, resources, constants)
{
_spdConstants = spdConstants;
}
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, OpticalFlow.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
throw new NotImplementedException();
}
}
internal class OpticalFlowGenerateSCDHistogramPass : OpticalFlowPass
{
public OpticalFlowGenerateSCDHistogramPass(OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
}
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, OpticalFlow.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
throw new NotImplementedException();
}
}
internal class OpticalFlowComputeSCDDivergencePass : OpticalFlowPass
{
public OpticalFlowComputeSCDDivergencePass(OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
}
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, OpticalFlow.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
throw new NotImplementedException();
}
}
internal class OpticalFlowComputePass : OpticalFlowPass
{
public OpticalFlowComputePass(OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
}
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, OpticalFlow.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
throw new NotImplementedException();
}
}
internal class OpticalFlowFilterPass : OpticalFlowPass
{
public OpticalFlowFilterPass(OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
}
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, OpticalFlow.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
throw new NotImplementedException();
}
}
internal class OpticalFlowScalePass : OpticalFlowPass
{
public OpticalFlowScalePass(OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
}
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, OpticalFlow.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
throw new NotImplementedException();
}
}
}

11
Runtime/OpticalFlow/OpticalFlowPass.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a509b94b3bffef549b9d3316b44df221
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

189
Runtime/OpticalFlow/OpticalFlowResources.cs

@ -0,0 +1,189 @@
using UnityEngine;
using UnityEngine.Experimental.Rendering;
namespace FidelityFX.OpticalFlow
{
internal class OpticalFlowResources
{
private const int OpticalFlowMaxPyramidLevels = 7;
private const int HistogramBins = 256;
private const int HistogramsPerDim = 3;
private const int HistogramShifts = 3;
public readonly RenderTexture[] OpticalFlowInput = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowInputLevel1 = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowInputLevel2 = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowInputLevel3 = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowInputLevel4 = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowInputLevel5 = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowInputLevel6 = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlow = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowLevel1 = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowLevel2 = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowLevel3 = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowLevel4 = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowLevel5 = new RenderTexture[2];
public readonly RenderTexture[] OpticalFlowLevel6 = new RenderTexture[2];
public RenderTexture OpticalFlowSCDHistogram;
public RenderTexture OpticalFlowSCDPreviousHistogram;
public RenderTexture OpticalFlowSCDTemp;
public void Create(OpticalFlow.ContextDescription contextDescription)
{
Vector2Int opticalFlowInputTextureSize = contextDescription.resolution;
const int minBlockSize = 8;
Vector2Int opticalFlowTextureSize = GetOpticalFlowTextureSize(contextDescription.resolution, minBlockSize);
Vector2Int opticalFlowLevel1TextureSize = NextLevelSize(opticalFlowTextureSize);
Vector2Int opticalFlowLevel2TextureSize = NextLevelSize(opticalFlowLevel1TextureSize);
Vector2Int opticalFlowLevel3TextureSize = NextLevelSize(opticalFlowLevel2TextureSize);
Vector2Int opticalFlowLevel4TextureSize = NextLevelSize(opticalFlowLevel3TextureSize);
Vector2Int opticalFlowLevel5TextureSize = NextLevelSize(opticalFlowLevel4TextureSize);
Vector2Int opticalFlowLevel6TextureSize = NextLevelSize(opticalFlowLevel5TextureSize);
Vector2Int opticalFlowHistogramTextureSize = GetOpticalFlowHistogramSize(0);
Vector2Int globalMotionSearchMaxDispatchSize = GetGlobalMotionSearchDispatchSize(0);
int globalMotionSearchTextureWidth = 4 + (globalMotionSearchMaxDispatchSize.x * globalMotionSearchMaxDispatchSize.y);
CreateDoubleBufferedResource(OpticalFlowInput, "OPTICALFLOW_OpticalFlowInput", opticalFlowInputTextureSize, GraphicsFormat.R8_UInt);
opticalFlowInputTextureSize = new Vector2Int(opticalFlowInputTextureSize.x >> 1, opticalFlowInputTextureSize.y >> 1);
CreateDoubleBufferedResource(OpticalFlowInputLevel1, "OPTICALFLOW_OpticalFlowInputLevel1-", opticalFlowInputTextureSize, GraphicsFormat.R8_UInt);
opticalFlowInputTextureSize = new Vector2Int(opticalFlowInputTextureSize.x >> 1, opticalFlowInputTextureSize.y >> 1);
CreateDoubleBufferedResource(OpticalFlowInputLevel2, "OPTICALFLOW_OpticalFlowInputLevel2-", opticalFlowInputTextureSize, GraphicsFormat.R8_UInt);
opticalFlowInputTextureSize = new Vector2Int(opticalFlowInputTextureSize.x >> 1, opticalFlowInputTextureSize.y >> 1);
CreateDoubleBufferedResource(OpticalFlowInputLevel3, "OPTICALFLOW_OpticalFlowInputLevel3-", opticalFlowInputTextureSize, GraphicsFormat.R8_UInt);
opticalFlowInputTextureSize = new Vector2Int(opticalFlowInputTextureSize.x >> 1, opticalFlowInputTextureSize.y >> 1);
CreateDoubleBufferedResource(OpticalFlowInputLevel4, "OPTICALFLOW_OpticalFlowInputLevel4-", opticalFlowInputTextureSize, GraphicsFormat.R8_UInt);
opticalFlowInputTextureSize = new Vector2Int(opticalFlowInputTextureSize.x >> 1, opticalFlowInputTextureSize.y >> 1);
CreateDoubleBufferedResource(OpticalFlowInputLevel5, "OPTICALFLOW_OpticalFlowInputLevel5-", opticalFlowInputTextureSize, GraphicsFormat.R8_UInt);
opticalFlowInputTextureSize = new Vector2Int(opticalFlowInputTextureSize.x >> 1, opticalFlowInputTextureSize.y >> 1);
CreateDoubleBufferedResource(OpticalFlowInputLevel6, "OPTICALFLOW_OpticalFlowInputLevel6-", opticalFlowInputTextureSize, GraphicsFormat.R8_UInt);
CreateDoubleBufferedResource(OpticalFlow, "OPTICALFLOW_OpticalFlow", opticalFlowTextureSize, GraphicsFormat.R16G16_SInt);
CreateDoubleBufferedResource(OpticalFlowLevel1, "OPTICALFLOW_OpticalFlowLevel1-", opticalFlowLevel1TextureSize, GraphicsFormat.R16G16_SInt);
CreateDoubleBufferedResource(OpticalFlowLevel2, "OPTICALFLOW_OpticalFlowLevel2-", opticalFlowLevel2TextureSize, GraphicsFormat.R16G16_SInt);
CreateDoubleBufferedResource(OpticalFlowLevel3, "OPTICALFLOW_OpticalFlowLevel3-", opticalFlowLevel3TextureSize, GraphicsFormat.R16G16_SInt);
CreateDoubleBufferedResource(OpticalFlowLevel4, "OPTICALFLOW_OpticalFlowLevel4-", opticalFlowLevel4TextureSize, GraphicsFormat.R16G16_SInt);
CreateDoubleBufferedResource(OpticalFlowLevel5, "OPTICALFLOW_OpticalFlowLevel5-", opticalFlowLevel5TextureSize, GraphicsFormat.R16G16_SInt);
CreateDoubleBufferedResource(OpticalFlowLevel6, "OPTICALFLOW_OpticalFlowLevel6-", opticalFlowLevel6TextureSize, GraphicsFormat.R16G16_SInt);
OpticalFlowSCDHistogram = CreateResource("OPTICALFLOW_OpticalFlowSCDHistogram", new Vector2Int(GetSCDHistogramTextureWidth(), 1), GraphicsFormat.R32_UInt);
OpticalFlowSCDPreviousHistogram = CreateResource("OPTICALFLOW_OpticalFlowSCDPreviousHistogram", new Vector2Int(GetSCDHistogramTextureWidth(), 1), GraphicsFormat.R32_SFloat);
OpticalFlowSCDTemp = CreateResource("OPTICALFLOW_OpticalFlowSCDTemp", new Vector2Int(3, 1), GraphicsFormat.R32_UInt);
}
public void Destroy()
{
DestroyResource(ref OpticalFlowSCDTemp);
DestroyResource(ref OpticalFlowSCDPreviousHistogram);
DestroyResource(ref OpticalFlowSCDHistogram);
DestroyResource(OpticalFlowLevel6);
DestroyResource(OpticalFlowLevel5);
DestroyResource(OpticalFlowLevel4);
DestroyResource(OpticalFlowLevel3);
DestroyResource(OpticalFlowLevel2);
DestroyResource(OpticalFlowLevel1);
DestroyResource(OpticalFlow);
DestroyResource(OpticalFlowInputLevel6);
DestroyResource(OpticalFlowInputLevel5);
DestroyResource(OpticalFlowInputLevel4);
DestroyResource(OpticalFlowInputLevel3);
DestroyResource(OpticalFlowInputLevel2);
DestroyResource(OpticalFlowInputLevel1);
DestroyResource(OpticalFlowInput);
}
private static Vector2Int NextLevelSize(Vector2Int size)
{
return new Vector2Int(AlignUp(size.x, 2) / 2, AlignUp(size.y, 2) / 2);
}
private static int AlignUp(int x, int y)
{
return (x + (y - 1)) & ~(y - 1);
}
private static Vector2Int GetOpticalFlowTextureSize(Vector2Int displaySize, int opticalFlowBlockSize)
{
int width = (displaySize.x + opticalFlowBlockSize - 1) / opticalFlowBlockSize;
int height = (displaySize.y + opticalFlowBlockSize - 1) / opticalFlowBlockSize;
return new Vector2Int(width, height);
}
private static Vector2Int GetOpticalFlowHistogramSize(int level)
{
const int searchRadius = 8;
int maxVelocity = searchRadius * (1 << (OpticalFlowMaxPyramidLevels - 1 - level));
int binsPerDimension = 2 * maxVelocity + 1;
return new Vector2Int(binsPerDimension, binsPerDimension);
}
private static Vector2Int GetGlobalMotionSearchDispatchSize(int level)
{
const int threadGroupSizeX = 16;
const int threadGroupSizeY = 16;
Vector2Int opticalFlowHistogramSize = GetOpticalFlowHistogramSize(level);
int additionalElementsDueToShiftsX = opticalFlowHistogramSize.x / threadGroupSizeX;
int additionalElementsDueToShiftsY = opticalFlowHistogramSize.y / threadGroupSizeY;
int dispatchX = (opticalFlowHistogramSize.x + additionalElementsDueToShiftsX + threadGroupSizeX - 1) / threadGroupSizeX;
int dispatchY = (opticalFlowHistogramSize.y + additionalElementsDueToShiftsY + threadGroupSizeY - 1) / threadGroupSizeY;
return new Vector2Int(dispatchX, dispatchY);
}
private static int GetSCDHistogramTextureWidth()
{
return HistogramBins * (HistogramsPerDim * HistogramsPerDim);
}
private static RenderTexture CreateResource(string name, Vector2Int size, GraphicsFormat format)
{
var rt = new RenderTexture(size.x, size.y, 0, format) { name = name, enableRandomWrite = true };
rt.Create();
return rt;
}
private static void CreateDoubleBufferedResource(RenderTexture[] resource, string name, Vector2Int size, GraphicsFormat format)
{
for (int i = 0; i < 2; ++i)
{
resource[i] = new RenderTexture(size.x, size.y, 0, format) { name = name + (i + 1), enableRandomWrite = true };
resource[i].Create();
}
}
private static void DestroyResource(ref Texture2D resource)
{
if (resource == null)
return;
#if UNITY_EDITOR
if (Application.isPlaying && !UnityEditor.EditorApplication.isPaused)
UnityEngine.Object.Destroy(resource);
else
UnityEngine.Object.DestroyImmediate(resource);
#else
UnityEngine.Object.Destroy(resource);
#endif
resource = null;
}
private static void DestroyResource(ref RenderTexture resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
private static void DestroyResource(RenderTexture[] resource)
{
for (int i = 0; i < resource.Length; ++i)
DestroyResource(ref resource[i]);
}
}
}

11
Runtime/OpticalFlow/OpticalFlowResources.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 56e728c675f67404a966d919d71f9041
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

33
Runtime/OpticalFlow/OpticalFlowShaderIDs.cs

@ -0,0 +1,33 @@
using UnityEngine;
namespace FidelityFX.OpticalFlow
{
public static class OpticalFlowShaderIDs
{
// Shader resource views, i.e. read-only bindings
public static readonly int SrvInputColor = Shader.PropertyToID("r_input_color");
public static readonly int SrvOpticalFlowInput = Shader.PropertyToID("r_optical_flow_input");
public static readonly int SrvOpticalFlowPreviousInput = Shader.PropertyToID("r_optical_flow_previous_input");
public static readonly int SrvOpticalFlow = Shader.PropertyToID("r_optical_flow");
public static readonly int SrvOpticalFlowPrevious = Shader.PropertyToID("r_optical_flow_previous");
// Unordered access views, i.e. random read/write bindings
public static readonly int UavOpticalFlowInput = Shader.PropertyToID("rw_optical_flow_input");
public static readonly int UavOpticalFlowInputLevel1 = Shader.PropertyToID("rw_optical_flow_input_level_1");
public static readonly int UavOpticalFlowInputLevel2 = Shader.PropertyToID("rw_optical_flow_input_level_2");
public static readonly int UavOpticalFlowInputLevel3 = Shader.PropertyToID("rw_optical_flow_input_level_3");
public static readonly int UavOpticalFlowInputLevel4 = Shader.PropertyToID("rw_optical_flow_input_level_4");
public static readonly int UavOpticalFlowInputLevel5 = Shader.PropertyToID("rw_optical_flow_input_level_5");
public static readonly int UavOpticalFlowInputLevel6 = Shader.PropertyToID("rw_optical_flow_input_level_6");
public static readonly int UavOpticalFlow = Shader.PropertyToID("rw_optical_flow");
public static readonly int UavOpticalFlowNextLevel = Shader.PropertyToID("rw_optical_flow_next_level");
public static readonly int UavOpticalFlowScdHistogram = Shader.PropertyToID("rw_optical_flow_scd_histogram"); // scene change detection histogram
public static readonly int UavOpticalFlowScdPreviousHistogram = Shader.PropertyToID("rw_optical_flow_previous_histogram");
public static readonly int UavOpticalFlowScdTemp = Shader.PropertyToID("rw_optical_flow_scd_temp");
public static readonly int UavOpticalFlowScdOutput = Shader.PropertyToID("rw_optical_flow_scd_output");
// Constant buffer bindings
public static readonly int CbOpticalFlow = Shader.PropertyToID("cbOF");
public static readonly int CbSpd = Shader.PropertyToID("cbOF_SPD");
}
}

11
Runtime/OpticalFlow/OpticalFlowShaderIDs.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 12d00661151ef1b468cbe643922fc0cc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
Loading…
Cancel
Save