Skip to content

Commit

Permalink
Reduce allocations/generated garbage in renderers
Browse files Browse the repository at this point in the history
- CharacterRenderer: don't reallocate RT color data array unless recreating the target.
- MapRenderer: use for loops instead of foreach loops to reduce garbage generated from enumerators.
- MainCharacterEntityRenderer: direct comparison instead of call to params method with only one parameter.
  • Loading branch information
ethanmoffat committed May 31, 2024
1 parent cd8be8c commit 8ba3f1a
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 17 deletions.
38 changes: 24 additions & 14 deletions EndlessClient/Rendering/Character/CharacterRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,14 @@ public CharacterRenderer(Game game,

_chatBubble = new Lazy<IChatBubble>(() => _chatBubbleFactory.CreateChatBubble(this));

_clientWindowSizeRepository.GameWindowSizeChanged += RecreateRenderTarget;
_clientWindowSizeRepository.GameWindowSizeChanged += RecreateRenderTargetEvent;
}

#region Game Component

public override void Initialize()
{
lock(_rt_locker_)
_charRenderTarget = _renderTargetFactory.CreateRenderTarget();
RecreateRenderTarget();

_sb = new SpriteBatch(Game.GraphicsDevice);

Expand Down Expand Up @@ -437,16 +436,20 @@ private void ClipHair()
_hatMetadataProvider.GetValueOrDefault(Character.RenderProperties.HatGraphic).ClipMode != HatMaskType.Standard)
return;

// oof. I really need to learn how to use shaders or stencil buffer.
// https://gamedev.stackexchange.com/questions/38118/best-way-to-mask-2d-sprites-in-xna/38150#38150
_rtColorData = new Color[_charRenderTarget.Width * _charRenderTarget.Height];
_charRenderTarget.GetData(_rtColorData);
for (int i = 0; i < _rtColorData.Length; i++)
lock (_rt_locker_)
{
if (_rtColorData[i] == Color.Black)
_rtColorData[i].A = 0;
// oof. I really need to learn how to use shaders or stencil buffer.
// https://gamedev.stackexchange.com/questions/38118/best-way-to-mask-2d-sprites-in-xna/38150#38150

// note: this operation causes a high number of GC events as the character's frame changes (walking/attacking)
_charRenderTarget.GetData(_rtColorData);
for (int i = 0; i < _rtColorData.Length; i++)
{
if (_rtColorData[i] == Color.Black)
_rtColorData[i].A = 0;
}
_charRenderTarget.SetData(_rtColorData);
}
_charRenderTarget.SetData(_rtColorData);
}

#endregion
Expand Down Expand Up @@ -507,13 +510,20 @@ public void ShowChatBubble(string message, bool isGroupChat)
_chatBubble.Value.SetMessage(message, isGroupChat);
}

private void RecreateRenderTarget(object sender, EventArgs e)
private void RecreateRenderTarget()
{
lock (_rt_locker_)
{
_charRenderTarget.Dispose();
_charRenderTarget?.Dispose();
_charRenderTarget = _renderTargetFactory.CreateRenderTarget();

_rtColorData = new Color[_charRenderTarget.Width * _charRenderTarget.Height];
}
}

private void RecreateRenderTargetEvent(object sender, EventArgs e)
{
RecreateRenderTarget();

if (_character == _characterProvider.MainCharacter)
SetToCenterScreenPosition();
Expand All @@ -534,7 +544,7 @@ protected override void Dispose(bool disposing)

_sb?.Dispose();

_clientWindowSizeRepository.GameWindowSizeChanged -= RecreateRenderTarget;
_clientWindowSizeRepository.GameWindowSizeChanged -= RecreateRenderTargetEvent;

lock(_rt_locker_)
_charRenderTarget?.Dispose();
Expand Down
7 changes: 5 additions & 2 deletions EndlessClient/Rendering/Map/MapRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,10 @@ void RenderGridSpace(int row, int col)
{
var alpha = GetAlphaForCoordinates(col, row, immutableCharacter);

foreach (var renderer in _mapEntityRendererProvider.MapEntityRenderers)
for (int i = 0; i < _mapEntityRendererProvider.MapEntityRenderers.Count; i++)
{
var renderer = _mapEntityRendererProvider.MapEntityRenderers[i];

if (!renderer.CanRender(row, col))
continue;

Expand Down Expand Up @@ -432,8 +434,9 @@ private void DrawBaseLayers(SpriteBatch spriteBatch)
{
var alpha = GetAlphaForCoordinates(col, row, _characterProvider.MainCharacter);

foreach (var renderer in _mapEntityRendererProvider.BaseRenderers)
for (int i = 0; i < _mapEntityRendererProvider.BaseRenderers.Count; i++)
{
var renderer = _mapEntityRendererProvider.BaseRenderers[i];
if (renderer.CanRender(row, col))
renderer.RenderElementAt(spriteBatch, row, col, alpha, new Vector2(offset, 0));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public MainCharacterEntityRenderer(ICharacterProvider characterProvider,
protected override bool ElementExistsAt(int row, int col)
{
var rp = _characterProvider.MainCharacter.RenderProperties;
if (!rp.IsActing(CharacterActionState.Walking))
if (rp.CurrentAction != CharacterActionState.Walking)
{
return row == rp.MapY && col == rp.MapX;
}
Expand Down

0 comments on commit 8ba3f1a

Please sign in to comment.