Optimise DecalOverlay (#25266)

ChunkSize is still 32 so doesn't cut down on heaps of decals atm though we avoid passing many decals to drawing with the coordinates bounds check now.
This commit is contained in:
metalgearsloth
2024-02-23 18:12:23 +11:00
committed by GitHub
parent 033f232a87
commit d8e5f5c24b
8 changed files with 64 additions and 87 deletions

View File

@@ -50,16 +50,8 @@ namespace Content.Client.Decals
protected override void OnDecalRemoved(EntityUid gridId, uint decalId, DecalGridComponent component, Vector2i indices, DecalChunk chunk)
{
base.OnDecalRemoved(gridId, decalId, component, indices, chunk);
if (!component.DecalZIndexIndex.Remove(decalId, out var zIndex))
return;
if (!component.DecalRenderIndex.TryGetValue(zIndex, out var renderIndex))
return;
renderIndex.Remove(decalId);
if (renderIndex.Count == 0)
component.DecalRenderIndex.Remove(zIndex);
DebugTools.Assert(chunk.Decals.ContainsKey(decalId));
chunk.Decals.Remove(decalId);
}
private void OnHandleState(EntityUid gridUid, DecalGridComponent gridComp, ref ComponentHandleState args)
@@ -133,8 +125,6 @@ namespace Content.Client.Decals
private void UpdateChunks(EntityUid gridId, DecalGridComponent gridComp, Dictionary<Vector2i, DecalChunk> updatedGridChunks)
{
var chunkCollection = gridComp.ChunkCollection.ChunkCollection;
var renderIndex = gridComp.DecalRenderIndex;
var zIndexIndex = gridComp.DecalZIndexIndex;
// Update any existing data / remove decals we didn't receive data for.
foreach (var (indices, newChunkData) in updatedGridChunks)
@@ -155,11 +145,6 @@ namespace Content.Client.Decals
foreach (var (uid, decal) in newChunkData.Decals)
{
if (zIndexIndex.TryGetValue(uid, out var zIndex))
renderIndex[zIndex].Remove(uid);
renderIndex.GetOrNew(decal.ZIndex)[uid] = decal;
zIndexIndex[uid] = decal.ZIndex;
gridComp.DecalIndex[uid] = indices;
}
}

View File

@@ -3,6 +3,7 @@ using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Map.Enumerators;
using Robust.Shared.Prototypes;
namespace Content.Client.Decals.Overlays
@@ -15,6 +16,8 @@ namespace Content.Client.Decals.Overlays
private readonly Dictionary<string, (Texture Texture, bool SnapCardinals)> _cachedTextures = new(64);
private readonly List<(uint Id, Decal Decal)> _decals = new();
public DecalOverlay(
SpriteSystem sprites,
IEntityManager entManager,
@@ -30,10 +33,10 @@ namespace Content.Client.Decals.Overlays
if (args.MapId == MapId.Nullspace)
return;
var grid = Grid;
var owner = Grid.Owner;
if (!_entManager.TryGetComponent(grid, out DecalGridComponent? decalGrid) ||
!_entManager.TryGetComponent(grid, out TransformComponent? xform))
if (!_entManager.TryGetComponent(owner, out DecalGridComponent? decalGrid) ||
!_entManager.TryGetComponent(owner, out TransformComponent? xform))
{
return;
}
@@ -46,18 +49,41 @@ namespace Content.Client.Decals.Overlays
var xformSystem = _entManager.System<TransformSystem>();
var eyeAngle = args.Viewport.Eye?.Rotation ?? Angle.Zero;
var zIndexDictionary = decalGrid.DecalRenderIndex;
var gridAABB = xformSystem.GetInvWorldMatrix(xform).TransformBox(args.WorldBounds.Enlarged(1f));
var chunkEnumerator = new ChunkIndicesEnumerator(gridAABB, SharedDecalSystem.ChunkSize);
_decals.Clear();
if (zIndexDictionary.Count == 0)
while (chunkEnumerator.MoveNext(out var index))
{
if (!decalGrid.ChunkCollection.ChunkCollection.TryGetValue(index.Value, out var chunk))
continue;
foreach (var (id, decal) in chunk.Decals)
{
if (!gridAABB.Contains(decal.Coordinates))
continue;
_decals.Add((id, decal));
}
}
if (_decals.Count == 0)
return;
var (_, worldRot, worldMatrix) = xformSystem.GetWorldPositionRotationMatrix(xform);
_decals.Sort((x, y) =>
{
var zComp = x.Decal.ZIndex.CompareTo(y.Decal.ZIndex);
if (zComp != 0)
return zComp;
return x.Id.CompareTo(y.Id);
});
var (_, worldRot, worldMatrix) = xformSystem.GetWorldPositionRotationMatrix(xform);
handle.SetTransform(worldMatrix);
foreach (var decals in zIndexDictionary.Values)
{
foreach (var decal in decals.Values)
foreach (var (_, decal) in _decals)
{
if (!_cachedTextures.TryGetValue(decal.Id, out var cache))
{
@@ -86,7 +112,6 @@ namespace Content.Client.Decals.Overlays
else
handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color);
}
}
handle.SetTransform(Matrix3.Identity);
}

View File

@@ -8,6 +8,7 @@ using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Player;
using Robust.Shared.Utility;
using ChunkIndicesEnumerator = Robust.Shared.Map.Enumerators.ChunkIndicesEnumerator;
namespace Content.Shared.Chunking;

View File

@@ -21,6 +21,7 @@ using Robust.Shared.Threading;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using static Content.Shared.Decals.DecalGridComponent;
using ChunkIndicesEnumerator = Robust.Shared.Map.Enumerators.ChunkIndicesEnumerator;
namespace Content.Server.Decals
{

View File

@@ -29,6 +29,7 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Threading;
using Robust.Shared.Utility;
using ChunkIndicesEnumerator = Robust.Shared.Map.Enumerators.ChunkIndicesEnumerator;
namespace Content.Server.Parallax;

View File

@@ -12,7 +12,8 @@ namespace Content.Shared.Decals
[NetworkedComponent]
public sealed partial class DecalGridComponent : Component
{
[DataField("chunkCollection", serverOnly: true)]
[Access(Other = AccessPermissions.ReadExecute)]
[DataField(serverOnly: true)]
public DecalGridChunkCollection ChunkCollection = new(new ());
/// <summary>
@@ -25,10 +26,6 @@ namespace Content.Shared.Decals
/// </summary>
public GameTick ForceTick { get; set; }
// client-side data. I CBF creating a separate client-side comp for this. The server can survive with some empty dictionaries.
public readonly Dictionary<uint, int> DecalZIndexIndex = new();
public readonly SortedDictionary<int, SortedDictionary<uint, Decal>> DecalRenderIndex = new();
[DataDefinition]
[Serializable, NetSerializable]
public sealed partial class DecalChunk

View File

@@ -122,39 +122,6 @@ namespace Content.Shared.Decals
}
}
// TODO: Pretty sure paul was moving this somewhere but just so people know
public struct ChunkIndicesEnumerator
{
private Vector2i _chunkLB;
private Vector2i _chunkRT;
private int _xIndex;
private int _yIndex;
public ChunkIndicesEnumerator(Box2 localAABB, int chunkSize)
{
_chunkLB = new Vector2i((int)Math.Floor(localAABB.Left / chunkSize), (int)Math.Floor(localAABB.Bottom / chunkSize));
_chunkRT = new Vector2i((int)Math.Floor(localAABB.Right / chunkSize), (int)Math.Floor(localAABB.Top / chunkSize));
_xIndex = _chunkLB.X;
_yIndex = _chunkLB.Y;
}
public bool MoveNext([NotNullWhen(true)] out Vector2i? indices)
{
if (_yIndex > _chunkRT.Y)
{
_yIndex = _chunkLB.Y;
_xIndex += 1;
}
indices = new Vector2i(_xIndex, _yIndex);
_yIndex += 1;
return _xIndex <= _chunkRT.X;
}
}
/// <summary>
/// Sent by clients to request that a decal is placed on the server.
/// </summary>