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.
 
 
 
 

181 lines
8.5 KiB

#if ENABLE_VIRTUALTEXTURES
using VirtualTexturing = UnityEngine.Rendering.VirtualTexturing;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
namespace UnityEngine.Rendering.HighDefinition
{
class VTBufferManager
{
public static TextureHandle CreateVTFeedbackBuffer(RenderGraph renderGraph, MSAASamples msaaSamples)
{
bool msaa = msaaSamples != MSAASamples.None;
#if UNITY_2020_2_OR_NEWER
FastMemoryDesc colorFastMemDesc;
colorFastMemDesc.inFastMemory = true;
colorFastMemDesc.residencyFraction = 1.0f;
colorFastMemDesc.flags = FastMemoryFlags.SpillTop;
#endif
return renderGraph.CreateTexture(
new TextureDesc(Vector2.one, true, true)
{
colorFormat = GetFeedbackBufferFormat(), enableRandomWrite = !msaa, bindTextureMS = msaa, msaaSamples = msaa ? msaaSamples : MSAASamples.None, clearBuffer = true, clearColor = Color.white, name = msaa ? "VTFeedbackMSAA" : "VTFeedback", fallBackToBlackTexture = true
#if UNITY_2020_2_OR_NEWER
,
fastMemoryDesc = colorFastMemDesc
#endif
});
}
public static GraphicsFormat GetFeedbackBufferFormat()
{
return GraphicsFormat.R16G16_UNorm;
}
const int kResolveScaleFactor = 16;
VirtualTexturing.Resolver m_Resolver = new VirtualTexturing.Resolver();
VirtualTexturing.Resolver m_ResolverMsaa = new VirtualTexturing.Resolver();
Vector2 m_ResolverScale = new Vector2(1.0f / (float)kResolveScaleFactor, 1.0f / (float)kResolveScaleFactor);
RTHandle m_LowresResolver; // This texture needs to be persistent because we do async gpu readback on it.
ComputeShader m_DownSampleCS = null;
int m_DownsampleKernel;
int m_DownsampleKernelMSAA;
public VTBufferManager()
{
}
public void Cleanup()
{
m_Resolver.Dispose();
m_ResolverMsaa.Dispose();
RTHandles.Release(m_LowresResolver);
m_LowresResolver = null;
}
public void BeginRender(HDCamera hdCamera)
{
// Lazy creation because creating this texture in the constructor can happen outside of proper RTHandleSystem initialization
// This can happen for example when cinemachine gets the HDCamera and ends up constructing VTBufferManager before HDRP is even initialized.
if (m_LowresResolver == null)
m_LowresResolver = RTHandles.Alloc(m_ResolverScale, colorFormat: GraphicsFormat.R8G8B8A8_UNorm, enableRandomWrite: true, autoGenerateMips: false, name: "VTFeedback lowres");
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.VirtualTexturing))
{
int width = hdCamera.actualWidth;
int height = hdCamera.actualHeight;
bool msaa = hdCamera.msaaEnabled;
GetResolveDimensions(ref width, ref height);
if (msaa)
{
CalculateResolverDimensions(ref width, ref height, m_ResolverMsaa);
m_ResolverMsaa.UpdateSize(width, height);
}
else
{
CalculateResolverDimensions(ref width, ref height, m_Resolver);
m_Resolver.UpdateSize(width, height);
}
}
}
class ResolveVTData
{
public int width, height;
public int lowresWidth, lowresHeight;
public VirtualTexturing.Resolver resolver;
public ComputeShader downsampleCS;
public int downsampleKernel;
public TextureHandle input;
public TextureHandle lowres;
}
public void Resolve(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle input)
{
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.VirtualTexturing))
{
if (m_DownSampleCS == null)
{
m_DownSampleCS = GraphicsSettings.GetRenderPipelineSettings<HDRenderPipelineRuntimeShaders>().VTFeedbackDownsample;
m_DownsampleKernel = m_DownSampleCS.FindKernel("KMain");
m_DownsampleKernelMSAA = m_DownSampleCS.FindKernel("KMainMSAA");
}
using (var builder = renderGraph.AddUnsafePass<ResolveVTData>("Resolve VT", out var passData, ProfilingSampler.Get(HDProfileId.VTFeedbackDownsample)))
{
// The output is never read outside the pass but is still useful for the VT system so we can't cull this pass.
builder.AllowPassCulling(false);
bool msaa = hdCamera.msaaEnabled;
passData.width = hdCamera.actualWidth;
passData.height = hdCamera.actualHeight;
passData.lowresWidth = passData.width;
passData.lowresHeight = passData.height;
GetResolveDimensions(ref passData.lowresWidth, ref passData.lowresHeight);
passData.resolver = msaa ? m_ResolverMsaa : m_Resolver;
passData.downsampleCS = m_DownSampleCS;
passData.downsampleKernel = msaa ? m_DownsampleKernelMSAA : m_DownsampleKernel;
passData.input = input;
builder.UseTexture(passData.input, AccessFlags.Read);
passData.lowres = renderGraph.ImportTexture(m_LowresResolver);
builder.UseTexture(passData.lowres, AccessFlags.Write);
builder.SetRenderFunc(
(ResolveVTData data, UnsafeGraphContext ctx) =>
{
var natCmd = CommandBufferHelpers.GetNativeCommandBuffer(ctx.cmd);
RTHandle lowresBuffer = data.lowres;
RTHandle buffer = data.input;
Debug.Assert(data.lowresWidth <= data.resolver.CurrentWidth && data.lowresHeight <= data.resolver.CurrentHeight);
Debug.Assert(data.lowresWidth <= lowresBuffer.referenceSize.x && data.lowresHeight <= lowresBuffer.referenceSize.y);
int inputID = (buffer.isMSAAEnabled) ? HDShaderIDs._InputTextureMSAA : HDShaderIDs._InputTexture;
natCmd.SetComputeTextureParam(data.downsampleCS, data.downsampleKernel, inputID, buffer);
natCmd.SetComputeTextureParam(data.downsampleCS, data.downsampleKernel, HDShaderIDs._OutputTexture, lowresBuffer);
var resolveCounter = 0;
var startOffsetX = (resolveCounter % kResolveScaleFactor);
var startOffsetY = (resolveCounter / kResolveScaleFactor) % kResolveScaleFactor;
natCmd.SetComputeVectorParam(data.downsampleCS, HDShaderIDs._Params, new Vector4(kResolveScaleFactor, startOffsetX, startOffsetY, /*unused*/ -1));
natCmd.SetComputeVectorParam(data.downsampleCS, HDShaderIDs._Params1, new Vector4(data.width, data.height, data.lowresWidth, data.lowresHeight));
var TGSize = 8; //Match shader
natCmd.DispatchCompute(data.downsampleCS, data.downsampleKernel, ((int)data.lowresWidth + (TGSize - 1)) / TGSize, ((int)data.lowresHeight + (TGSize - 1)) / TGSize, 1);
data.resolver.Process(natCmd, lowresBuffer, 0, data.lowresWidth, 0, data.lowresHeight, 0, 0);
VirtualTexturing.System.Update();
});
}
}
}
void GetResolveDimensions(ref int w, ref int h)
{
w = Mathf.Max(Mathf.RoundToInt(m_ResolverScale.x * w), 1);
h = Mathf.Max(Mathf.RoundToInt(m_ResolverScale.y * h), 1);
}
void CalculateResolverDimensions(ref int w, ref int h, VirtualTexturing.Resolver resolver)
{
//RT handles don't downscale in the editor but render with subrects.
#if UNITY_EDITOR
int currentWidth = resolver.CurrentWidth;
int currentHeight = resolver.CurrentHeight;
if (currentWidth < w || currentHeight < h)
{
w = currentWidth < w ? w : currentWidth;
h = currentHeight < h ? h : currentHeight;
}
#endif
}
}
}
#endif