Skip to content
This repository has been archived by the owner on Nov 30, 2020. It is now read-only.

Fix to reduce the amount of allocations required when using MSVO and Dynamic Resolution #901

Draft
wants to merge 5 commits into
base: v2
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this package will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [3.0.1] - 2020-10-16
### Fixed
- Fix for MSVO when used with dynamic resolution reallocating temp render targets whenever the dynamic resolution scale was changed. Now those temp targets will use dynamic scaling as well. This will require a matching fix in Unity to work correctly (ADD COMPATIBLE VERSIONS HERE). (case XXXXXX).

## [3.0.0] - 2020-10-13

### Fixed
Expand Down
137 changes: 82 additions & 55 deletions PostProcessing/Runtime/Effects/MultiScaleVO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ enum Pass
readonly float[] m_InvThicknessTable = new float[12];
readonly float[] m_SampleWeightTable = new float[12];

// Scaled dimensions used with dynamic resolution
// Unscaled dimensions used for allocating targets that might scale themselves.
readonly int[] m_Widths = new int[7];
readonly int[] m_Heights = new int[7];

// Scaled dimensions adjusted for the current dynamic resolution scale
readonly int[] m_ScaledWidths = new int[7];
readonly int[] m_ScaledHeights = new int[7];

Expand Down Expand Up @@ -74,41 +78,59 @@ public void SetResources(PostProcessResources resources)
m_Resources = resources;
}

void Alloc(CommandBuffer cmd, int id, MipLevel size, RenderTextureFormat format, bool uav)
void Alloc(CommandBuffer cmd, int id, MipLevel size, RenderTextureFormat format, bool uav, bool dynamicScale)
{
int sizeId = (int)size;

cmd.GetTemporaryRT(id, new RenderTextureDescriptor
{
#if UNITY_2019_4_OR_NEWER
width = m_Widths[sizeId],
height = m_Heights[sizeId],
#else
width = m_ScaledWidths[sizeId],
height = m_ScaledHeights[sizeId],
#endif
colorFormat = format,
depthBufferBits = 0,
volumeDepth = 1,
autoGenerateMips = false,
msaaSamples = 1,
#if UNITY_2019_2_OR_NEWER
mipCount = 1,
#endif
#if UNITY_2019_4_OR_NEWER
useDynamicScale = dynamicScale,
#endif
enableRandomWrite = uav,
dimension = TextureDimension.Tex2D,
sRGB = false
}, FilterMode.Point);
}

void AllocArray(CommandBuffer cmd, int id, MipLevel size, RenderTextureFormat format, bool uav)
void AllocArray(CommandBuffer cmd, int id, MipLevel size, RenderTextureFormat format, bool uav, bool dynamicScale)
{
int sizeId = (int)size;

cmd.GetTemporaryRT(id, new RenderTextureDescriptor
{
#if UNITY_2019_4_OR_NEWER
width = m_Widths[sizeId],
height = m_Heights[sizeId],
#else
width = m_ScaledWidths[sizeId],
height = m_ScaledHeights[sizeId],
#endif
colorFormat = format,
depthBufferBits = 0,
volumeDepth = 16,
autoGenerateMips = false,
msaaSamples = 1,
#if UNITY_2019_2_OR_NEWER
mipCount = 1,
#endif
#if UNITY_2019_4_OR_NEWER
useDynamicScale = dynamicScale,
#endif
enableRandomWrite = uav,
dimension = TextureDimension.Tex2DArray,
Expand Down Expand Up @@ -152,24 +174,29 @@ Vector3 GetSizeArray(MipLevel mip)
public void GenerateAOMap(CommandBuffer cmd, Camera camera, RenderTargetIdentifier destination, RenderTargetIdentifier? depthMap, bool invert, bool isMSAA)
{
// Base size
m_Widths[0] = m_ScaledWidths[0] = camera.pixelWidth * (RuntimeUtilities.isSinglePassStereoEnabled ? 2 : 1);
m_Heights[0] = m_ScaledHeights[0] = camera.pixelHeight;
#if UNITY_2017_3_OR_NEWER
// Adjust the scaled dimensions based off the dynamic resolution resolution used at the moment.
m_ScaledWidths[0] = camera.scaledPixelWidth * (RuntimeUtilities.isSinglePassStereoEnabled ? 2 : 1);
m_ScaledHeights[0] = camera.scaledPixelHeight;
#else
m_ScaledWidths[0] = camera.pixelWidth * (RuntimeUtilities.isSinglePassStereoEnabled ? 2 : 1);
m_ScaledHeights[0] = camera.pixelHeight;
#endif

#endif
float widthScalingFactor = ScalableBufferManager.widthScaleFactor;
float heightScalingFactor = ScalableBufferManager.heightScaleFactor;
// L1 -> L6 sizes
for (int i = 1; i < 7; i++)
{
int div = 1 << i;
m_ScaledWidths[i] = (m_ScaledWidths[0] + (div - 1)) / div;
m_ScaledHeights[i] = (m_ScaledHeights[0] + (div - 1)) / div;
m_Widths[i] = (m_Widths[0] + (div - 1)) / div;
m_Heights[i] = (m_Heights[0] + (div - 1)) / div;
// Scaled width and heights have to match their calculations like will happen with dynamic resolution otherwise with odd numbers you can get a difference between what the dynamic resolution version
// generates and what we use here.
m_ScaledWidths[i] = Mathf.CeilToInt(m_Widths[i] * widthScalingFactor);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just comparing the maths to what the Switch does for scaling, Switch clamps the values between 1 and Width or 1 and Height. That's probably just the switch code being overly cautious e.g. the scale factor shouldn't be more than 1, but just double checking that wouldn't be needed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I've checked the engine code and the scaling factors are clamped to a max of 1 so we shouldn't need to clamp on the top end but I suppose it's possible this will produce a 0 sized render target in some cases which it sounds like Switch catches, I'm not sure if we catch this case on all platforms and might end up with a 0 sized RT which I don't imagine would produce good results.

m_ScaledHeights[i] = Mathf.CeilToInt(m_Heights[i] * heightScalingFactor);
}

// Allocate temporary textures
PushAllocCommands(cmd, isMSAA);
PushAllocCommands(cmd, isMSAA, camera);

// Render logic
PushDownsampleCommands(cmd, camera, depthMap, isMSAA);
Expand All @@ -189,53 +216,53 @@ public void GenerateAOMap(CommandBuffer cmd, Camera camera, RenderTargetIdentifi
PushReleaseCommands(cmd);
}

void PushAllocCommands(CommandBuffer cmd, bool isMSAA)
void PushAllocCommands(CommandBuffer cmd, bool isMSAA, Camera camera)
{
if(isMSAA)
{
Alloc(cmd, ShaderIDs.LinearDepth, MipLevel.Original, RenderTextureFormat.RGHalf, true);

Alloc(cmd, ShaderIDs.LowDepth1, MipLevel.L1, RenderTextureFormat.RGFloat, true);
Alloc(cmd, ShaderIDs.LowDepth2, MipLevel.L2, RenderTextureFormat.RGFloat, true);
Alloc(cmd, ShaderIDs.LowDepth3, MipLevel.L3, RenderTextureFormat.RGFloat, true);
Alloc(cmd, ShaderIDs.LowDepth4, MipLevel.L4, RenderTextureFormat.RGFloat, true);

AllocArray(cmd, ShaderIDs.TiledDepth1, MipLevel.L3, RenderTextureFormat.RGHalf, true);
AllocArray(cmd, ShaderIDs.TiledDepth2, MipLevel.L4, RenderTextureFormat.RGHalf, true);
AllocArray(cmd, ShaderIDs.TiledDepth3, MipLevel.L5, RenderTextureFormat.RGHalf, true);
AllocArray(cmd, ShaderIDs.TiledDepth4, MipLevel.L6, RenderTextureFormat.RGHalf, true);

Alloc(cmd, ShaderIDs.Occlusion1, MipLevel.L1, RenderTextureFormat.RG16, true);
Alloc(cmd, ShaderIDs.Occlusion2, MipLevel.L2, RenderTextureFormat.RG16, true);
Alloc(cmd, ShaderIDs.Occlusion3, MipLevel.L3, RenderTextureFormat.RG16, true);
Alloc(cmd, ShaderIDs.Occlusion4, MipLevel.L4, RenderTextureFormat.RG16, true);

Alloc(cmd, ShaderIDs.Combined1, MipLevel.L1, RenderTextureFormat.RG16, true);
Alloc(cmd, ShaderIDs.Combined2, MipLevel.L2, RenderTextureFormat.RG16, true);
Alloc(cmd, ShaderIDs.Combined3, MipLevel.L3, RenderTextureFormat.RG16, true);
Alloc(cmd, ShaderIDs.LinearDepth, MipLevel.Original, RenderTextureFormat.RGHalf, true, camera.allowDynamicResolution);

Alloc(cmd, ShaderIDs.LowDepth1, MipLevel.L1, RenderTextureFormat.RGFloat, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.LowDepth2, MipLevel.L2, RenderTextureFormat.RGFloat, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.LowDepth3, MipLevel.L3, RenderTextureFormat.RGFloat, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.LowDepth4, MipLevel.L4, RenderTextureFormat.RGFloat, true, camera.allowDynamicResolution);

AllocArray(cmd, ShaderIDs.TiledDepth1, MipLevel.L3, RenderTextureFormat.RGHalf, true, camera.allowDynamicResolution);
AllocArray(cmd, ShaderIDs.TiledDepth2, MipLevel.L4, RenderTextureFormat.RGHalf, true, camera.allowDynamicResolution);
AllocArray(cmd, ShaderIDs.TiledDepth3, MipLevel.L5, RenderTextureFormat.RGHalf, true, camera.allowDynamicResolution);
AllocArray(cmd, ShaderIDs.TiledDepth4, MipLevel.L6, RenderTextureFormat.RGHalf, true, camera.allowDynamicResolution);

Alloc(cmd, ShaderIDs.Occlusion1, MipLevel.L1, RenderTextureFormat.RG16, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.Occlusion2, MipLevel.L2, RenderTextureFormat.RG16, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.Occlusion3, MipLevel.L3, RenderTextureFormat.RG16, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.Occlusion4, MipLevel.L4, RenderTextureFormat.RG16, true, camera.allowDynamicResolution);

Alloc(cmd, ShaderIDs.Combined1, MipLevel.L1, RenderTextureFormat.RG16, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.Combined2, MipLevel.L2, RenderTextureFormat.RG16, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.Combined3, MipLevel.L3, RenderTextureFormat.RG16, true, camera.allowDynamicResolution);
}
else
{
Alloc(cmd, ShaderIDs.LinearDepth, MipLevel.Original, RenderTextureFormat.RHalf, true);

Alloc(cmd, ShaderIDs.LowDepth1, MipLevel.L1, RenderTextureFormat.RFloat, true);
Alloc(cmd, ShaderIDs.LowDepth2, MipLevel.L2, RenderTextureFormat.RFloat, true);
Alloc(cmd, ShaderIDs.LowDepth3, MipLevel.L3, RenderTextureFormat.RFloat, true);
Alloc(cmd, ShaderIDs.LowDepth4, MipLevel.L4, RenderTextureFormat.RFloat, true);

AllocArray(cmd, ShaderIDs.TiledDepth1, MipLevel.L3, RenderTextureFormat.RHalf, true);
AllocArray(cmd, ShaderIDs.TiledDepth2, MipLevel.L4, RenderTextureFormat.RHalf, true);
AllocArray(cmd, ShaderIDs.TiledDepth3, MipLevel.L5, RenderTextureFormat.RHalf, true);
AllocArray(cmd, ShaderIDs.TiledDepth4, MipLevel.L6, RenderTextureFormat.RHalf, true);

Alloc(cmd, ShaderIDs.Occlusion1, MipLevel.L1, RenderTextureFormat.R8, true);
Alloc(cmd, ShaderIDs.Occlusion2, MipLevel.L2, RenderTextureFormat.R8, true);
Alloc(cmd, ShaderIDs.Occlusion3, MipLevel.L3, RenderTextureFormat.R8, true);
Alloc(cmd, ShaderIDs.Occlusion4, MipLevel.L4, RenderTextureFormat.R8, true);

Alloc(cmd, ShaderIDs.Combined1, MipLevel.L1, RenderTextureFormat.R8, true);
Alloc(cmd, ShaderIDs.Combined2, MipLevel.L2, RenderTextureFormat.R8, true);
Alloc(cmd, ShaderIDs.Combined3, MipLevel.L3, RenderTextureFormat.R8, true);
Alloc(cmd, ShaderIDs.LinearDepth, MipLevel.Original, RenderTextureFormat.RHalf, true, camera.allowDynamicResolution);

Alloc(cmd, ShaderIDs.LowDepth1, MipLevel.L1, RenderTextureFormat.RFloat, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.LowDepth2, MipLevel.L2, RenderTextureFormat.RFloat, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.LowDepth3, MipLevel.L3, RenderTextureFormat.RFloat, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.LowDepth4, MipLevel.L4, RenderTextureFormat.RFloat, true, camera.allowDynamicResolution);

AllocArray(cmd, ShaderIDs.TiledDepth1, MipLevel.L3, RenderTextureFormat.RHalf, true, camera.allowDynamicResolution);
AllocArray(cmd, ShaderIDs.TiledDepth2, MipLevel.L4, RenderTextureFormat.RHalf, true, camera.allowDynamicResolution);
AllocArray(cmd, ShaderIDs.TiledDepth3, MipLevel.L5, RenderTextureFormat.RHalf, true, camera.allowDynamicResolution);
AllocArray(cmd, ShaderIDs.TiledDepth4, MipLevel.L6, RenderTextureFormat.RHalf, true, camera.allowDynamicResolution);

Alloc(cmd, ShaderIDs.Occlusion1, MipLevel.L1, RenderTextureFormat.R8, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.Occlusion2, MipLevel.L2, RenderTextureFormat.R8, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.Occlusion3, MipLevel.L3, RenderTextureFormat.R8, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.Occlusion4, MipLevel.L4, RenderTextureFormat.R8, true, camera.allowDynamicResolution);

Alloc(cmd, ShaderIDs.Combined1, MipLevel.L1, RenderTextureFormat.R8, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.Combined2, MipLevel.L2, RenderTextureFormat.R8, true, camera.allowDynamicResolution);
Alloc(cmd, ShaderIDs.Combined3, MipLevel.L3, RenderTextureFormat.R8, true, camera.allowDynamicResolution);
}
}

Expand All @@ -254,7 +281,7 @@ void PushDownsampleCommands(CommandBuffer cmd, Camera camera, RenderTargetIdenti
// buffer (it's only available in some specific situations).
if (!RuntimeUtilities.IsResolvedDepthAvailable(camera))
{
Alloc(cmd, ShaderIDs.DepthCopy, MipLevel.Original, RenderTextureFormat.RFloat, false);
Alloc(cmd, ShaderIDs.DepthCopy, MipLevel.Original, RenderTextureFormat.RFloat, false, camera.allowDynamicResolution);
depthMapId = new RenderTargetIdentifier(ShaderIDs.DepthCopy);
cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, depthMapId, m_PropertySheet, (int)Pass.DepthCopy);
needDepthMapRelease = true;
Expand Down Expand Up @@ -463,9 +490,9 @@ void PreparePropertySheet(PostProcessRenderContext context)
void CheckAOTexture(PostProcessRenderContext context)
{
bool AOUpdateNeeded = m_AmbientOnlyAO == null || !m_AmbientOnlyAO.IsCreated() || m_AmbientOnlyAO.width != context.width || m_AmbientOnlyAO.height != context.height;
#if UNITY_2017_3_OR_NEWER
#if UNITY_2017_3_OR_NEWER
AOUpdateNeeded = AOUpdateNeeded || m_AmbientOnlyAO.useDynamicScale != context.camera.allowDynamicResolution;
#endif
#endif
if (AOUpdateNeeded)
{
RuntimeUtilities.Destroy(m_AmbientOnlyAO);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "com.unity.postprocessing",
"version": "3.0.0",
"version": "3.0.1",
"displayName": "Post Processing",
"unity": "2018.4",
"description": "The post-processing stack (v2) comes with a collection of effects and image filters you can apply to your cameras to improve the visuals of your games.",
Expand Down