Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rendering optimizations and XeGTAO
Summary
A collection of R4 rendering cleanup/optimizations, plus a dedicated AO pass and selectable XeGTAO implementation.
The optimization work mostly removes GPU work which was either unconditional despite having no consumer, or existed only to move the same display-sized image back and forth between render targets.
The AO work allows SSDO/GTAO evaluation to run separately from
combine_1, adds optional half-resolution evaluation for the existing methods, and provides the common AO output used by the new XeGTAO path. The original inline SSDO/GTAO path remains selectable.XeGTAO is adapted from Intel's MIT-licensed implementation.
Also adds a small Tracy profiler UI improvement for filtering GPU passes and exporting the current frame's GPU timings to CSV for easier comparison.
Skip unused depth snapshots
During normal scene rendering, the renderer previously copied the scene depth buffer three times per frame:
$user$temp_zbbefore HUD rendering for 3D-scope depth;$user$zbuffer_dofafter HUD rendering, before scope depth, for DOF;$user$zbufferafter HUD/scope depth for TAA, DLSS, FSR3 and other depth consumers.The first two copies are now conditional.
$user$temp_zbis only updated when the 3D-scope HUD depth draw map is non-empty.$user$zbuffer_dofis only updated when the exported DOF parameters pass the same non-zero check used byphase_dof.The main
$user$zbuffercopy remains unconditional in the normal scene-rendering path. It preserves a separate sampleable depth snapshot while the original scene depth is used as a DSV. Removing it would require reviewing the depth bindings and consumers, rather than simply redirecting them to the original texture.The copies also use
rt_Base_Depth->pSurfacedirectly instead of callingGetResource()/Release()on the DSV each time.While testing this,
CWeapon::UpdateDof()also turned out to export the DOF fade before clamping it. The last fade-out frame could leave non-zero parameters behind, including negative values. Since the caller stopped updating once the clamped fade reached zero, those parameters could remain active after aiming.Both
phase_dofand the new depth-copy gate use the same zero check, so this could keep both the DOF pass and its depth copy running.The fade is now clamped before exporting the parameters so the final fade-out frame actually writes
(0,0,0,0).Performance comparison
GPU timings on relevant passes, captured in Cordon:
copy_zbuffer_scopecopy_zbuffer_scope_depthDisplay post-processing ping-pong
A number of post-processing passes followed the same pattern:
$user$postprocess0;$user$generic_combine;CopyResourcethe result back into$user$postprocess0.That copy was repeated after CAS, screen-space sunshafts,
combine_2, DOF, LUT, gasmask effects, night vision, rain drops and other display-sized passes.rt_Postprocess_0andrt_Generic_combineare now treated as a ping-pong pair.The renderer tracks which one currently contains the latest image. Post effects participating in the pair read from the current buffer, write into the other one, then flip the state.
Shader bindings for
$user$postprocess0/$user$generic_combineare remapped to the current source while inside the post-processing chain.This removes the per-effect full-resolution RGBA16F copies while preserving those shader-facing texture names. The CAS shader setup also has a separate source binding for the temporal-upscaler path.
There are still seed/synchronization copies where they are actually required.
In particular, the existing 3D-scope reticle path expects
$user$generic_combineand cannot always participate in the remap because that could bind the same texture as both SRV and render target. If the latest image is already ingeneric_combine, no copy is needed. Otherwise the scope path synchronizes it first.TAA, SMAA and the non-temporal paths keep their existing initial seed behavior. A seed copy also remains after temporal upscaling when the CAS path which avoids it is not used.
Performance comparison
GPU timings on relevant passes, captured in Cordon:
CASphase_ss_sscombine_2copy_zbufferDedicated AO pass
SSDO and GTAO were previously evaluated directly inside
combine_1.They can now render visibility into a separate R16F AO texture which the AO-buffer variant of
combine_1consumes before the existing colored-AO / ambient-light treatment.Added:
r_ao_resolutionwith:
legacy- original inline AO evaluation insidecombine_1;full- dedicated AO evaluation at full internal render resolution, and the default setting;half- AO evaluation at one selected covered sample per 2x2 block, followed by depth/normal-aware reconstruction.fullis the default dedicated path and the baseline for comparing the separate pass againstlegacy.halfis the mode which actually reduces AO evaluation work. It trades some spatial detail for fewer evaluations, and still pays for the reconstruction pass.The half-resolution path selects the nearest covered G-buffer sample in each 2x2 block and stores its visibility, view depth and packed normal in an RGBA16F texture. Reconstruction combines four neighboring half-resolution samples with bilinear, depth and normal weights.
Odd render dimensions use rounded-up half-size targets with clamped integer coordinates.
There is no extra temporal history or depth copy involved in this SSDO/GTAO path.
With DLSS/FSR enabled, these resolutions are relative to the internal render size, not the final display resolution. That size can be reduced by the selected upscaling preset, or remain native for DLAA/native-AA modes.
When AO is disabled at renderer initialization or after
vid_restart, the dedicated AO resources are not allocated and no AO pass runs.Performance comparison
GPU timings on relevant passes, captured in Cordon:
phase_aocombine_1Final GPU timing cost decreased by 0.1250 (~6.3%).
XeGTAO
Added:
r_ao_mode st_xegtaoThis uses an adapted version of Intel's XeGTAO implementation.
The renderer already has linear view depth and G-buffer normals, so the integration reuses those rather than generating another set of normals or converting a hardware-depth snapshot.
The path is:
combine_1therefore still owns the existing OGSR colored-AO and ambient-light treatment instead of XeGTAO becoming a second unrelated lighting path.The
r2_ssaoquality presets map as:st_opt_low-> 1 slice / 2 steps;st_opt_medium-> 2 slices / 2 steps;st_opt_high-> 3 slices / 3 steps.Samples are taken on both sides of each slice.
Added:
r_xegtao_radiusDefault is
0.5, with a range of0.05to4.0in view-space units.The radius can be changed live and only affects XeGTAO.
r_xegtao_bent_normals on/offadds optional directional ambient lighting. Default isoff, requiresvid_restart, and only affects XeGTAO. It calculates and denoises the average unoccluded direction, whichcombine_1uses for diffuse environment sampling. Reflections and the material BRDF keep the surface normal.r_ao_resolutiononly changes the existing SSDO/GTAO paths. Selectinglegacyorhalfdoes not change XeGTAO's resolution or send it through another implementation.Currently XeGTAO currently always runs at full internal render resolution.
With DLSS/FSR, "full" internal resolution may of course already be significantly smaller than the display resolution, depending on the preset.
There is currently no separate XeGTAO temporal accumulation pass or AO history buffer.
When TAA, DLSS or FSR3 is selected, XeGTAO advances its sampling noise using the frame number modulo 64. Projection reconstruction separately accounts for the existing camera jitter. Without one of those temporal AA paths, the sampling noise remains fixed.
GTAO vs XeGTAO
GPU timings in milliseconds from the tracy captures:
phase_aocombine_1phase_ao+combine_1DEFER_COMBINE(context)Frame(context)XeGTAO used 86.8% less GPU time in
phase_aoin these captures, including its prefilter, evaluation, denoise and export. Frame andDEFER_COMBINEtotals include other rendering work.Renderer state and resources
XeGTAO exposed a missing compute-SRV invalidation in the D3D11 state cache. Compute SRV state is now reset alongside the other shader stages, and XeGTAO explicitly unbinds UAVs before reusing their outputs as SRVs.
Dedicated AO resources follow the render-target lifecycle and are recreated on renderer reset. XeGTAO compute resources are allocated only when XeGTAO is selected and AO is enabled; half-resolution SSDO/GTAO resources are not allocated for XeGTAO.
With SSDO/GTAO, both dedicated AO targets remain allocated so
r_ao_resolutioncan change live. Changing the AO method,r2_ssaoorr_xegtao_bent_normalsrequiresvid_restart.r_ao_resolutionis runtime-adjustable for SSDO/GTAO, whiler_xegtao_radiusis runtime-adjustable for XeGTAO.Compatibility
The existing modes remain available. The default method remains SSDO, and the default
r_ao_resolutionisfull. Existing saved settings and graphics presets can override defaults.XeGTAO is a different AO implementation and its radius/art direction has not been calibrated to reproduce OGSR GTAO exactly.
Benchmarks
3.564 GTAO
Optimized GTAO (
fullAO)XeGTAO (
fullAO,r_xegtao_radius0.5)Some with more focus on visual difference:
3.564 GTAO
XeGTAO (
fullAO,r_xegtao_radius0.5)Test plan
$user$zbuffercopy remains unconditional during normal scene renderingvid_restartacross methods, quality settings and AO off