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.
189 lines
11 KiB
189 lines
11 KiB
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]);
|
|
}
|
|
}
|
|
}
|