-
Notifications
You must be signed in to change notification settings - Fork 858
[Universal] MSAA store actions optimizations for forward renderer Drawobjects pass #4161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overall looks good, wrote down few suggestions for overall readability/usability
com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAssetEditor.cs
Outdated
Show resolved
Hide resolved
com.unity.render-pipelines.universal/Runtime/Passes/ScriptableRenderPass.cs
Outdated
Show resolved
Hide resolved
com.unity.render-pipelines.universal/Runtime/Passes/ScriptableRenderPass.cs
Outdated
Show resolved
Hide resolved
com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs
Outdated
Show resolved
Hide resolved
com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs
Outdated
Show resolved
Hide resolved
…timal configurations
…ctions and not override them with Store
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if this setting should be on the renderer or in the pipeline asset.
@TheoWong-pixel what do you think?
I think from API perspective I get concerned that we expose public API to configure store actions but not to configure load. It feels the API is imcomplete/only being added for this specific case, but my worry is that soon users might find use cases they want to optimize load actions as well. @hkr for awareness/comments.
Otherwise, PR seems mostly good to me, requesting changes and adding additional stakeholders.
| public static GUIContent mixedLightingSupportLabel = EditorGUIUtility.TrTextContent("Mixed Lighting", "Makes the render pipeline include mixed-lighting Shader Variants in the build."); | ||
| public static GUIContent debugLevel = EditorGUIUtility.TrTextContent("Debug Level", "Controls the level of debug information generated by the render pipeline. When Profiling is selected, the pipeline provides detailed profiling tags."); | ||
| public static GUIContent shaderVariantLogLevel = EditorGUIUtility.TrTextContent("Shader Variant Log Level", "Controls the level logging in of shader variants information is outputted when a build is performed. Information will appear in the Unity console when the build finishes."); | ||
| public static GUIContent storeActionsOptimizationText = EditorGUIUtility.TrTextContent("Store Actions", "Sets the store actions policy on mobile GPUs. 'Discard': discard as much as possible, 'Store': always store, 'Auto': Discard if no custom passes are injected, otherwise Store."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we say tile based GPUs instead of mobile?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
usually load actions are implicitly configured based on what store actions we have. Maybe I could name this setting differently? "Bandwidth optimization policy" or something like that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@phi-lira all code changes are done as discussed (except the ones we agreed shouldn't be changed).
I wait for documentation and UX reviewers feedback for changing UI/docs related stuff
com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs
Show resolved
Hide resolved
com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs
Show resolved
Hide resolved
com.unity.render-pipelines.universal/Runtime/Passes/ScriptableRenderPass.cs
Outdated
Show resolved
Hide resolved
com.unity.render-pipelines.universal/Runtime/Passes/ScriptableRenderPass.cs
Outdated
Show resolved
Hide resolved
| RenderBufferStoreAction[] m_ColorStoreActions = new RenderBufferStoreAction[] { RenderBufferStoreAction.Store }; | ||
| RenderBufferStoreAction m_DepthStoreAction = RenderBufferStoreAction.Store; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder why not backing the entire attachemnt setup with something like https://docs.unity3d.com/ScriptReference/Rendering.RenderTargetBinding.html
I also find it weird that we provide StoreActions but don't expose LoadAction. If we don't think in terms of API completeness I feel like very soon someone might ask for Load actions as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in engine load actions are inferred based on the store actions setup, and this change or every API implementation. The only proper way right now to set load/store actions without having to fight built-in logic is to use the RenderPass API.
So while exposing the load actions here is easy, I am not sure they will have much effect in terms of determining the final store action used by the device. So there would be a lot of work needed to allow that. If it is important can be done as a future task, but from my experience the engine does a good job in figuring out the load actions and the main problems were introduced by wrong stores, so not sure the effort to have an explicit Load action API is worth it (also considering RenderPasses will do that)
I agree having only stores exposed in the API makes it feel limited, but if we want load actions too then it might involve lot of extra work. Future PRs could address it if really needed. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. sounds good to me and fair justification.
| if (passColorAttachment != m_ActiveColorAttachments[0] || passDepthAttachment != m_ActiveDepthAttachment || finalClearFlag != ClearFlag.None || | ||
| renderPass.colorStoreAction != m_ActiveColorStoreActions[0] || renderPass.depthStoreAction != m_ActiveDepthStoreAction) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for this PR, but maybe for the future we could store the current attachment setup with something like https://docs.unity3d.com/ScriptReference/Rendering.RenderTargetBinding.html then it would make code more readable to compare pass binding with active binding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May this check introduce redundant render target switches? For example if the active store action is Store and the new action is DontCare then we still have one store in total + a render target switch that implies loads for other attachments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be the only place where m_ActiveColorStoreActions is read, but we only read m_ActiveColorStoreActions[0]. Is that on purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the non MRT path so there should be only one color attachment (the first check that was already there only checks for color[0]: passColorAttachment != m_ActiveColorAttachments[0])
In general this optimization PR is only for the forward renderer at the moment, so I didn't do anything in MRT/deferred branches
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
regarding redundant render target switches: I suppose that could happen potentially. It doesn't happen with the current optimizations I did, but if users want to customize further their store actions in some cases it could lead to unoptimal switches I guess. But not sure there is much we can do about it. If we expose more low level customization options this is one of the risks. more power->more responsibility?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also noticed that in some cases the engine would still do extra target switches compared to URP SetRenderTarget calls. i.e. is opaque would Store depth, and transparent would discard.
Without the store actions comparison check:
- Opaque SetRenderTarget is called: Opaque will store all the results
- Transparent SetRenderTarget is NOT called (because of no actions check): engine will still load from Opaque, will store the all results (waste of bandwidth)
With this new check introduced the behaviour will be the same in terms of loads but now the transparent pass will discard/resolve everything, no stores. Thanks to the second URP SetRenderTarget call with optimized actions, now happening
| m_ActiveColorAttachments[0] = colorAttachment; | ||
| for (int i = 1; i < m_ActiveColorAttachments.Length; ++i) | ||
| m_ActiveColorAttachments[i] = 0; | ||
|
|
||
| m_ActiveColorStoreActions[0] = colorStoreAction; | ||
| m_ActiveDepthStoreAction = depthStoreAction; | ||
| for (int i = 1; i < m_ActiveColorStoreActions.Length; ++i) | ||
| m_ActiveColorStoreActions[i] = RenderBufferStoreAction.Store; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hooking up on the previous idea, if we used RenderTargetBinding we could configure it here once.
| m_ActiveRenderPassQueue.Clear(); | ||
|
|
||
| m_StoreActionsOptimizationSetting = UniversalRenderPipeline.asset.storeActionsOptimization; | ||
| m_UseOptimizedStoreActions = m_StoreActionsOptimizationSetting != StoreActionsOptimization.Store; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
StoreActionsOptimization.Store should also remove store optimization from other passes like post-processing imo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure I understand what you mean?
Currently StoreActionsOptimization.Store will remove optimization from all the passes going through the new SetRenderTarget API that explicitely sets the store actions. So any passes using that new interface will be affected. Right now that is only the DrawOpaque and DrawTransparent passes, but it is extensible to other passes in the future including post processing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PostProcessingPass.cs has some optimizations to load and store with SetRenderTarget. F.ex, I think we never store depth after post but some users asked for it. I was asking if these settings should affect those optimizations we already have there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes that sounds like a good idea. This PR is focusing on the opaque/transparent passes on top of introducing the new API. But extending the optimization options to other passes in future PRs sounds trivial (should be a matter of making sure that the new explicit actions API is called by the postproc pass)
|
@TheoWong-pixel Qualit Audit will only happen after cutoff and from what I understand this was in the hope to land before. Advice? |
|
@TheoWong-pixel what is the advance menu? |
|
The work on the advance menu is outside of this PR. It is more structured around the UI and how we show advanced settings to users. This should be handled in another PR later. The location that @manuele-bonanno has placed this setting is fine. :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good on mobile side. Tested URP Examples and Boat attack. Played around with settings, couldn't find any issues on visual correctness as well as performance. It looks that the feature is disabled by default which is expected. Ran on Mali and Adreno devices, had no issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
approving, testing was done by mobile QA
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good with the editions!
# Conflicts: # com.unity.render-pipelines.universal/CHANGELOG.md # com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs # com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs
|
Failures also reproduced in master / XR related, known issue being fixed. |
Purpose of this PR
URP bandwidth usage is currently un-optimal on TBDR architectures.
This PR introduces a new "Store Actions" setting that allows us to improve bandwidth usage on certain passes.
When copying depth or color is enabled, the DrawObjects transparent pass will run as a separate pass after the DrawObjects opaque pass. With MSAA enabled, both opaque and transparent passes will StoreAndResolve color and store depth. These store actions are correct for the opaque pass (since its results will be used by copy color/copy depth and by the transparent pass) but a waste of bandwidth in the transparent pass case since, unless some extra passes which use its results were injected, the results of the transparent pass will not be used anymore in the frame.
With this optimization the transparent pass will now Resolve color and discard (DontCare) depth.
Applying this optimization to all possible scenarios, could potentially break any scenes were new passes are injected, as those could potentially try to use the results of the transparent pass, so we are giving multiple "Store Actions" options (in the URP Asset Advanced options).
Discard: discard results of passes which are not used later in the frame (safe in case no new passes that use those results are injected)
Store: always store, safest but unoptimal behaviour (same as current)
Auto: use the Discard behaviour if no external injected passes are detected, otherwise fallback to Store
On the low level side, we are adding Color store actions and depth store actions properties to ScriptableRenderPass: this will allow more explicit control of store actions for future optimizations (both using the RenderPass API path and the SetRenderTarget one)
Note:
to get fully optimized results on Metal, in terms of resolve store actions being applied correctly, this PR relies on some trunk fixes I made in this PR.
Testing status
Results when applying the Discard policy on iOS:
Opaque pass:

Transparent Pass:
