Browse Source

Progress on managing resources. Compute luminance pyramid shader is starting to do something.

Also looked at the Lanczos LUT resource and ran into some roadblocks there.
mac-autoexp
Nico de Poel 3 years ago
parent
commit
9489a19cd8
  1. 6
      Assets/Resources/FSR2/ffx_fsr2_accumulate_pass.compute
  2. 5
      Assets/Scripts/Fsr2.cs
  3. 80
      Assets/Scripts/Fsr2Context.cs
  4. 7
      Assets/Scripts/Fsr2Controller.cs
  5. 32
      Assets/Scripts/Fsr2Pipeline.cs

6
Assets/Resources/FSR2/ffx_fsr2_accumulate_pass.compute

@ -11,4 +11,10 @@
#define FFX_GPU // Compiling for GPU
#define FFX_HLSL // Compile for plain HLSL
// Ensure the correct value is defined for this keyword, as it is used to select one of multiple sampler functions
#ifdef FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE
#undef FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE
#define FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE 1
#endif
#include "shaders/ffx_fsr2_accumulate_pass.hlsl"

5
Assets/Scripts/Fsr2.cs

@ -13,7 +13,7 @@ namespace FidelityFX
/// <summary>
/// Creates a new FSR2 context with standard parameters that are appropriate for the current platform.
/// </summary>
public static Fsr2Context CreateContext(InitializationFlags flags = 0)
public static Fsr2Context CreateContext(Vector2Int displaySize, Vector2Int maxRenderSize, InitializationFlags flags = 0)
{
if (SystemInfo.usesReversedZBuffer)
flags |= InitializationFlags.EnableDepthInverted;
@ -23,7 +23,8 @@ namespace FidelityFX
var contextDescription = new ContextDescription
{
Flags = flags,
DisplaySize = new Vector2Int(Screen.width, Screen.height),
DisplaySize = displaySize,
MaxRenderSize = maxRenderSize,
Callbacks = GlobalCallbacks,
};

80
Assets/Scripts/Fsr2Context.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
namespace FidelityFX
@ -23,6 +24,9 @@ namespace FidelityFX
private Fsr2Pipeline _generateReactivePipeline;
private Fsr2Pipeline _tcrAutogeneratePipeline;
private Texture2D _lanczosLutResource;
private RenderTexture _autoExposureResource;
private ComputeBuffer _fsr2ConstantsBuffer;
private readonly Fsr2.Fsr2Constants[] _fsr2ConstantsArray = { new Fsr2.Fsr2Constants() };
private ref Fsr2.Fsr2Constants Constants => ref _fsr2ConstantsArray[0];
@ -58,10 +62,16 @@ namespace FidelityFX
Constants.displaySize = _contextDescription.DisplaySize;
CreateResources();
CreatePipelines();
}
private void CreateResources()
{
// Generate the data for the LUT
const uint lanczos2LutWidth = 128;
const int lanczos2LutWidth = 128;
short[] lanczos2Weights = new short[lanczos2LutWidth];
for (uint currentLanczosWidthIndex = 0; currentLanczosWidthIndex < lanczos2LutWidth; ++currentLanczosWidthIndex)
for (int currentLanczosWidthIndex = 0; currentLanczosWidthIndex < lanczos2LutWidth; ++currentLanczosWidthIndex)
{
float x = 2.0f * currentLanczosWidthIndex / (lanczos2LutWidth - 1);
float y = Fsr2.Lanczos2(x);
@ -73,10 +83,18 @@ namespace FidelityFX
// UAVs *may* be an issue with the PS4 not handling simultaneous reading and writing to an RT properly
// Unity does have Graphics.SetRandomWriteTarget for enabling UAV on ComputeBuffers or RTs
// Unity doesn't do 1D textures so just default to Texture2D
CreatePipelines();
}
// Resource FSR2_LanczosLutData: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE
// TODO FIXME: R16_SNorm not supported? That's weird... This really ought to be a ComputeBuffer, not a Texture2D. Or just use R16_SFloat and upload pre-normalized floats, I guess...
// _lanczosLutResource = new Texture2D(lanczos2LutWidth, 1, GraphicsFormat.R16_SNorm, TextureCreationFlags.None) { name = "FSR2_LanczosLutData" };
// _lanczosLutResource.SetPixelData(lanczos2Weights, 0);
// _lanczosLutResource.Apply();
// Resource FSR2_AutoExposure: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE
_autoExposureResource = new RenderTexture(1, 1, 1, GraphicsFormat.R32G32_SFloat) { name = "FSR2_AutoExposure", enableRandomWrite = true };
_autoExposureResource.Create();
}
// private void InitShaders()
// {
// LoadComputeShader("FSR2/ffx_fsr2_compute_luminance_pyramid_pass", ref _computeLuminancePyramidShader, out _computeLuminancePyramidKernel);
@ -92,7 +110,8 @@ namespace FidelityFX
private void CreatePipelines()
{
_computeLuminancePyramidPipeline = new Fsr2ComputeLuminancePyramidPipeline(_contextDescription.Callbacks, _contextDescription.Flags, _fsr2ConstantsBuffer, _spdConstantsBuffer);
_computeLuminancePyramidPipeline =
new Fsr2ComputeLuminancePyramidPipeline(_contextDescription.Callbacks, _contextDescription.Flags, _fsr2ConstantsBuffer, _spdConstantsBuffer, _autoExposureResource);
_accumulatePipeline = new Fsr2AccumulatePipeline(_contextDescription.Callbacks, _contextDescription.Flags, _fsr2ConstantsBuffer);
_accumulateSharpenPipeline = new Fsr2AccumulateSharpenPipeline(_contextDescription.Callbacks, _contextDescription.Flags, _fsr2ConstantsBuffer);
_rcasPipeline = new Fsr2RcasPipeline(_contextDescription.Callbacks, _contextDescription.Flags, _fsr2ConstantsBuffer, _rcasConstantsBuffer);
@ -110,6 +129,9 @@ namespace FidelityFX
DestroyPipeline(ref _reconstructPreviousDepthPipeline);
DestroyPipeline(ref _depthClipPipeline);
DestroyResource(ref _autoExposureResource);
DestroyResource(ref _lanczosLutResource);
DestroyConstantBuffer(ref _rcasConstantsBuffer);
DestroyConstantBuffer(ref _spdConstantsBuffer);
DestroyConstantBuffer(ref _fsr2ConstantsBuffer);
@ -214,32 +236,24 @@ namespace FidelityFX
dispatchParams.RenderSize.x > 0 ? dispatchParams.RenderSize.x : dispatchParams.Input.width,
dispatchParams.RenderSize.y > 0 ? dispatchParams.RenderSize.y : dispatchParams.Input.height);
constants.maxRenderSize = _contextDescription.MaxRenderSize;
constants.inputColorResourceDimensions =
new Vector2Int(dispatchParams.Input.width, dispatchParams.Input.height);
constants.inputColorResourceDimensions = new Vector2Int(dispatchParams.Input.width, dispatchParams.Input.height);
// Compute the horizontal FOV for the shader from the vertical one
float aspectRatio = (float)dispatchParams.RenderSize.x / dispatchParams.RenderSize.y;
float cameraAngleHorizontal = Mathf.Atan(Mathf.Tan(dispatchParams.CameraFovAngleVertical / 2.0f) * aspectRatio) * 2.0f;
constants.tanHalfFOV = Mathf.Tan(cameraAngleHorizontal * 0.5f);
constants.viewSpaceToMetersFactor =
(dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f;
constants.viewSpaceToMetersFactor = (dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f;
// Compute params to enable device depth to view space depth computation in shader
constants.deviceToViewDepth = SetupDeviceDepthToViewSpaceDepthParams(dispatchParams);
// To be updated if resource is larger than the actual image size
constants.downscaleFactor = new Vector2(
(float)constants.renderSize.x / _contextDescription.DisplaySize.x,
(float)constants.renderSize.y / _contextDescription.DisplaySize.y);
constants.downscaleFactor = new Vector2((float)constants.renderSize.x / _contextDescription.DisplaySize.x, (float)constants.renderSize.y / _contextDescription.DisplaySize.y);
constants.previousFramePreExposure = constants.preExposure;
constants.preExposure = (dispatchParams.PreExposure != 0) ? dispatchParams.PreExposure : 1.0f;
// Motion vector data
Vector2Int motionVectorsTargetSize =
(_contextDescription.Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) != 0
? constants.displaySize
: constants.renderSize;
Vector2Int motionVectorsTargetSize = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) != 0 ? constants.displaySize : constants.renderSize;
constants.motionVectorScale = dispatchParams.MotionVectorScale / motionVectorsTargetSize;
// Compute jitter cancellation
@ -302,8 +316,7 @@ namespace FidelityFX
// Revert x and y coords
float aspect = (float)dispatchParams.RenderSize.x / dispatchParams.RenderSize.y;
float cotHalfFovY = Mathf.Cos(0.5f * dispatchParams.CameraFovAngleVertical) /
Mathf.Sin(0.5f * dispatchParams.CameraFovAngleVertical);
float cotHalfFovY = Mathf.Cos(0.5f * dispatchParams.CameraFovAngleVertical) / Mathf.Sin(0.5f * dispatchParams.CameraFovAngleVertical);
int matrixIndex = (inverted ? 2 : 0) + (infinite ? 1 : 0);
return new Vector4(
@ -395,6 +408,33 @@ namespace FidelityFX
bufferRef = null;
}
private static void DestroyResource(ref ComputeBuffer resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
private static void DestroyResource(ref Texture2D resource)
{
if (resource == null)
return;
UnityEngine.Object.Destroy(resource);
resource = null;
}
private static void DestroyResource(ref RenderTexture resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
private static void DestroyPipeline(ref Fsr2Pipeline pipeline)
{
if (pipeline == null)

7
Assets/Scripts/Fsr2Controller.cs

@ -28,6 +28,9 @@ public class Fsr2Controller : MonoBehaviour
[HideInInspector]
public float renderScale;
private Vector2Int DisplaySize => new Vector2Int(Screen.width, Screen.height);
private Vector2Int RenderSize => new Vector2Int(Mathf.FloorToInt(Screen.width * renderScale), Mathf.FloorToInt(Screen.height * renderScale));
private Fsr2Context _context;
private readonly Fsr2.DispatchDescription _dispatchDescription = new Fsr2.DispatchDescription();
@ -54,7 +57,8 @@ public class Fsr2Controller : MonoBehaviour
{
RenderPipelineManager.endContextRendering += OnEndContextRendering;
_context = Fsr2.CreateContext();
// TODO: destroy and recreate context on screen resolution and/or quality mode change
_context = Fsr2.CreateContext(DisplaySize, RenderSize);
_upscaleRT = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGBHalf);
_upscaleRT.Create();
@ -118,6 +122,7 @@ public class Fsr2Controller : MonoBehaviour
_dispatchDescription.Sharpness = sharpness;
_dispatchDescription.MotionVectorScale.x = gameCamera.pixelWidth;
_dispatchDescription.MotionVectorScale.y = gameCamera.pixelHeight;
_dispatchDescription.RenderSize = RenderSize;
_dispatchDescription.FrameTimeDelta = Time.unscaledDeltaTime;
_dispatchDescription.CameraNear = gameCamera.nearClipPlane;
_dispatchDescription.CameraFar = gameCamera.farClipPlane;

32
Assets/Scripts/Fsr2Pipeline.cs

@ -1,6 +1,7 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
namespace FidelityFX
@ -58,13 +59,15 @@ namespace FidelityFX
shaderRef = _callbacks.LoadComputeShader(name);
kernelIndex = shaderRef.FindKernel("CS");
bool useLut = (SystemInfo.computeSubGroupSize == 64);
// This mirrors the permutation rules from the CreatePipeline* functions
if ((flags & Fsr2.InitializationFlags.EnableHighDynamicRange) != 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_HDR_COLOR_INPUT");
if ((flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS");
if ((flags & Fsr2.InitializationFlags.EnableMotionVectorsJitterCancellation) != 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS");
if ((flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_INVERTED_DEPTH");
// TODO: enable FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE if the device capabilities allow (default subgroup size == 32 or 64)
if (useLut) shaderRef.EnableKeyword("FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE");
// TODO: enable FFX_HALF if FP16 is supported (except RCAS)
}
@ -86,21 +89,44 @@ namespace FidelityFX
internal class Fsr2ComputeLuminancePyramidPipeline : Fsr2Pipeline
{
private readonly ComputeBuffer _spdConstants;
private readonly RenderTexture _autoExposure;
public Fsr2ComputeLuminancePyramidPipeline(Fsr2Callbacks callbacks, Fsr2.InitializationFlags flags, ComputeBuffer constants, ComputeBuffer spdConstants)
public Fsr2ComputeLuminancePyramidPipeline(Fsr2Callbacks callbacks, Fsr2.InitializationFlags flags, ComputeBuffer constants, ComputeBuffer spdConstants, RenderTexture autoExposure)
: base(callbacks, constants)
{
_spdConstants = spdConstants;
_autoExposure = autoExposure;
LoadComputeShader("FSR2/ffx_fsr2_compute_luminance_pyramid_pass", flags);
}
public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int dispatchX, int dispatchY)
{
// Problems to solve:
// - How do resources (render textures) relate to SRV/UAV bindings? How are those tied together?
// - What about the SRV/UAVs that are not related to any resources? Where are those filled in?
// - How do we clear the resources that need to be cleared at dispatch? (SetBufferData)
// - Shouldn't we use a ComputeBuffer for resources that are one-dimensional and clearly not image data? e.g. SPD atomic counter & Lanczos LUT data
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.Input);
// Resource FSR2_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE
commandBuffer.GetTemporaryRT(UavSpdAtomicCount, 1, 1, 0, FilterMode.Point, GraphicsFormat.R32_UInt, 1, true); // FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC
// Resource FSR2_ExposureMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE, mipCount = 0
// See `scheduleDispatch` for the song and dance to bind UAV mip levels to each luminance mipmap... and this shader specifically wants mip levels 4 and 5
// Looks like we can just bind two separate resources here, shouldn't be necessary to bother with mipmapping nonsense. Be sure to get the right dimensions though.
commandBuffer.GetTemporaryRT(UavExposureMipLumaChange, dispatchParams.RenderSize.x >> 4, dispatchParams.RenderSize.y >> 4, 0, FilterMode.Point, GraphicsFormat.R16_SFloat, 1, true); // FSR2_BIND_UAV_EXPOSURE_MIP_LUMA_CHANGE
commandBuffer.GetTemporaryRT(UavExposureMip5, dispatchParams.RenderSize.x >> 5, dispatchParams.RenderSize.y >> 5, 0, FilterMode.Point, GraphicsFormat.R16_SFloat, 1, true); // FSR2_BIND_UAV_EXPOSURE_MIP_5
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavAutoExposure, _autoExposure); // FSR2_BIND_UAV_AUTO_EXPOSURE
commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.Fsr2Constants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbSpd, _spdConstants, 0, Marshal.SizeOf<Fsr2.SpdConstants>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
// NOTE: since these temp RTs are not bound to a specific shader or kernel, we can set them globally one time and release them after dispatch.
// That way we can share aliasable resources between shaders without any complicated management.
commandBuffer.ReleaseTemporaryRT(UavSpdAtomicCount);
commandBuffer.ReleaseTemporaryRT(UavExposureMipLumaChange);
commandBuffer.ReleaseTemporaryRT(UavExposureMip5);
}
}

Loading…
Cancel
Save