FSR2 tests in Unity based on built-in render pipeline
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
5.8 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
public class FSR2Thing : MonoBehaviour
{
[SerializeField]
private bool performSharpenPass = true;
[SerializeField, Range(0, 1)]
private float sharpness = 0.8f;
[HideInInspector]
public Camera gameCamera;
[HideInInspector]
public Camera outputCamera;
[HideInInspector]
public float renderScale;
private RenderTexture _upscaleRT;
private RenderTexture _rcasOutput;
private Texture2D _exposure;
private Material _testMaterial;
private Material TestMaterial
{
get
{
if (_testMaterial == null)
{
var testShader = Shader.Find("FSR2/FSRTest");
_testMaterial = new Material(testShader);
}
return _testMaterial;
}
}
private ComputeShader _rcasComputeShader;
private ComputeShader RCASComputeShader
{
get
{
if (_rcasComputeShader == null)
{
// TODO: this is nasty, I don't like this. How do we manage/bind compute shaders best?
// GPUInstancer used Resources, we modified that to load stuff from asset bundles instead. Maybe provide a custom loader callback interface?
_rcasComputeShader = Resources.Load<ComputeShader>("Shaders/ffx_fsr2_rcas_pass");
}
return _rcasComputeShader;
}
}
private ComputeBuffer _rcasConstantBuffer;
private RcasConfig[] _rcasConfig = new RcasConfig[1];
private void OnEnable()
{
RenderPipelineManager.endContextRendering += OnEndContextRendering;
_upscaleRT = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGBHalf);
_upscaleRT.Create();
_rcasOutput = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGBHalf);
_rcasOutput.enableRandomWrite = true;
_rcasOutput.Create();
_exposure = new Texture2D(1, 1);
_exposure.name = "FSR2 Exposure";
_exposure.SetPixel(0, 0, Color.white);
_exposure.Apply();
_rcasConstantBuffer = new ComputeBuffer(1, Marshal.SizeOf<RcasConfig>(), ComputeBufferType.Constant);
}
private void OnDisable()
{
if (_rcasConstantBuffer != null)
{
_rcasConstantBuffer.Release();
_rcasConstantBuffer = null;
}
if (_exposure != null)
{
Destroy(_exposure);
_exposure = null;
}
if (_rcasOutput != null)
{
_rcasOutput.Release();
_rcasOutput = null;
}
if (_upscaleRT != null)
{
_upscaleRT.Release();
_upscaleRT = null;
}
RenderPipelineManager.endContextRendering -= OnEndContextRendering;
}
// For scriptable rendering pipeline
private void OnEndContextRendering(ScriptableRenderContext context, List<Camera> cameras)
{
Debug.Log($"OnEndContentRendering, cameras = {string.Join(", ", cameras.Select(c => c.name))}");
}
// For legacy built-in render pipeline
private void OnRenderImage(RenderTexture src, RenderTexture dest)
{
// Do a dumb upscale first
Graphics.Blit(gameCamera.targetTexture, _upscaleRT, TestMaterial);
if (performSharpenPass)
{
int sharpnessIndex = Mathf.RoundToInt(Mathf.Clamp01(sharpness) * (RcasConfigs.Count - 1));
_rcasConfig[0] = RcasConfigs[sharpnessIndex];
_rcasConstantBuffer.SetData(_rcasConfig);
// Run the RCAS sharpening filter on the upscaled image
int rcasKernel = RCASComputeShader.FindKernel("CS");
// TODO: create constant buffer (cbFSR2) with fPreExposure set to 1.0
RCASComputeShader.SetTexture(rcasKernel, "r_exposure", _exposure);
RCASComputeShader.SetTexture(rcasKernel, "r_rcas_input", _upscaleRT);
RCASComputeShader.SetTexture(rcasKernel, "rw_upscaled_output", _rcasOutput);
RCASComputeShader.SetConstantBuffer("cbRCAS", _rcasConstantBuffer, 0, Marshal.SizeOf<RcasConfig>());
RCASComputeShader.Dispatch(rcasKernel, Screen.width, Screen.height, 1); // TODO: not sure how these thread groups work...
// Output sharpened image to screen
Graphics.Blit(_rcasOutput, dest);
}
else
{
Graphics.Blit(_upscaleRT, dest);
}
}
[Serializable]
private struct RcasConfig
{
public RcasConfig(uint sharpness, uint halfSharp)
{
this.sharpness = sharpness;
this.halfSharp = halfSharp;
dummy0 = dummy1 = 0;
}
public uint sharpness;
public uint halfSharp;
public uint dummy0;
public uint dummy1;
}
private static readonly List<RcasConfig> RcasConfigs = new()
{
new(1048576000u, 872428544u),
new(1049178080u, 877212745u),
new(1049823372u, 882390168u),
new(1050514979u, 887895276u),
new(1051256227u, 893859143u),
new(1052050675u, 900216232u),
new(1052902144u, 907032080u),
new(1053814727u, 914306687u),
new(1054792807u, 922105590u),
new(1055841087u, 930494326u),
new(1056964608u, 939538432u),
new(1057566688u, 944322633u),
new(1058211980u, 949500056u),
new(1058903587u, 955005164u),
new(1059644835u, 960969031u),
new(1060439283u, 967326120u),
new(1061290752u, 974141968u),
new(1062203335u, 981416575u),
new(1063181415u, 989215478u),
new(1064229695u, 997604214u),
new(1065353216u, 1006648320),
};
}