You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

190 lines
11 KiB

using UnityEngine;
using UnityEngine.Experimental.Rendering;
namespace FidelityFX.OpticalFlow
{
internal class OpticalFlowResources
{
internal const int OpticalFlowMaxPyramidLevels = 7;
internal const int HistogramBins = 256;
internal const int HistogramsPerDim = 3;
internal 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);
}
// TODO: move these to OpticalFlow class
internal 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]);
}
}
}