perf(render): bound animation and alpha scratch residency
Complete Slice D3 by replacing the unbounded animation dictionary with a concurrent byte/count LRU and by putting the three retail alpha scratch owners behind one typed aggregate budget. Preserve immediate growth and draw order while reclaiming one-frame density spikes after sustained under-use. Close stale bounds-cache issue evidence without inventing a cache.
This commit is contained in:
parent
3e18fc2730
commit
f2644d42c2
18 changed files with 857 additions and 34 deletions
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using AcDream.App.Rendering.Residency;
|
||||
using AcDream.App.Rendering.Wb;
|
||||
using AcDream.Content;
|
||||
using AcDream.Core.Meshing;
|
||||
|
|
@ -181,6 +183,13 @@ public sealed unsafe class ParticleRenderer : IDisposable
|
|||
private DeferredParticleDraw[] _preparedAlpha = new DeferredParticleDraw[256];
|
||||
private uint[] _preparedInstanceOffsets = new uint[256];
|
||||
private int _preparedAlphaCount;
|
||||
private readonly RetainedScratchCapacityPolicy _alphaScratchPolicy;
|
||||
|
||||
internal long AlphaScratchBudgetBytes => _alphaScratchPolicy.BudgetBytes;
|
||||
internal long RetainedAlphaScratchBytes => checked(
|
||||
(long)_deferredAlpha.Capacity * Unsafe.SizeOf<DeferredParticleDraw>()
|
||||
+ (long)_preparedAlpha.Length * Unsafe.SizeOf<DeferredParticleDraw>()
|
||||
+ (long)_preparedInstanceOffsets.Length * sizeof(uint));
|
||||
|
||||
private sealed class AlphaDrawSource(ParticleRenderer owner) : IRetailAlphaDrawSource
|
||||
{
|
||||
|
|
@ -201,7 +210,8 @@ public sealed unsafe class ParticleRenderer : IDisposable
|
|||
TextureCache? textures = null,
|
||||
IDatReaderWriter? dats = null,
|
||||
WbMeshAdapter? meshAdapter = null,
|
||||
RetailAlphaQueue? alphaQueue = null)
|
||||
RetailAlphaQueue? alphaQueue = null,
|
||||
long? alphaScratchBudgetBytes = null)
|
||||
{
|
||||
_gl = gl ?? throw new ArgumentNullException(nameof(gl));
|
||||
_textures = textures;
|
||||
|
|
@ -210,6 +220,11 @@ public sealed unsafe class ParticleRenderer : IDisposable
|
|||
_particles = particles ?? throw new ArgumentNullException(nameof(particles));
|
||||
_alphaQueue = alphaQueue;
|
||||
_alphaSource = new AlphaDrawSource(this);
|
||||
long scratchBudget = alphaScratchBudgetBytes
|
||||
?? AlphaScratchBudgetProfile.Create(
|
||||
ResidencyBudgetOptions.Default.AlphaScratchBytes).ParticleBytes;
|
||||
_alphaScratchPolicy =
|
||||
new RetainedScratchCapacityPolicy(scratchBudget);
|
||||
if (_meshAdapter is not null)
|
||||
{
|
||||
_meshReferences = new ParticleMeshReferenceTracker(
|
||||
|
|
@ -732,8 +747,30 @@ public sealed unsafe class ParticleRenderer : IDisposable
|
|||
|
||||
private void ResetDeferredAlpha()
|
||||
{
|
||||
int observedCount = Math.Max(
|
||||
_deferredAlpha.Count,
|
||||
_preparedAlphaCount);
|
||||
_deferredAlpha.Clear();
|
||||
_preparedAlphaCount = 0;
|
||||
int currentCapacity = Math.Max(
|
||||
_deferredAlpha.Capacity,
|
||||
Math.Max(
|
||||
_preparedAlpha.Length,
|
||||
_preparedInstanceOffsets.Length));
|
||||
int bytesPerDraw = checked(
|
||||
2 * Unsafe.SizeOf<DeferredParticleDraw>() + sizeof(uint));
|
||||
int targetCapacity = _alphaScratchPolicy.ObserveAndSelectCapacity(
|
||||
currentCapacity,
|
||||
observedCount,
|
||||
bytesPerDraw,
|
||||
minimumCapacity: 256,
|
||||
growthQuantum: 256);
|
||||
if (targetCapacity >= currentCapacity)
|
||||
return;
|
||||
|
||||
_deferredAlpha.Capacity = targetCapacity;
|
||||
Array.Resize(ref _preparedAlpha, targetCapacity);
|
||||
Array.Resize(ref _preparedInstanceOffsets, targetCapacity);
|
||||
}
|
||||
|
||||
private void PrepareBillboardPipeline(Matrix4x4 viewProjection)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue