From ff16690b86fd2b261c2c49e9bed05bcb1e0ba368 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Mon, 13 Oct 2014 21:09:28 +0100 Subject: [PATCH] Lazily generate buffer in Sheet. The managed byte buffer is created on demand, meaning a newly allocated sheet will not waste memory holding onto the buffer until some changes are actually required to be written. This avoids a newly allocated sheet wasting memory on buffers that do not differ from their backing texture. --- OpenRA.Game/Graphics/Sheet.cs | 49 +++++++++++++------ OpenRA.Game/Graphics/SheetBuilder.cs | 2 +- OpenRA.Game/Graphics/Theater.cs | 2 +- OpenRA.Game/Widgets/VqaPlayerWidget.cs | 4 +- .../Widgets/ColorMixerWidget.cs | 2 +- OpenRA.Mods.Common/Widgets/HueSliderWidget.cs | 2 +- OpenRA.Mods.Common/Widgets/RadarWidget.cs | 8 +-- 7 files changed, 44 insertions(+), 25 deletions(-) diff --git a/OpenRA.Game/Graphics/Sheet.cs b/OpenRA.Game/Graphics/Sheet.cs index 316c5d9790..116bf7f671 100644 --- a/OpenRA.Game/Graphics/Sheet.cs +++ b/OpenRA.Game/Graphics/Sheet.cs @@ -25,14 +25,25 @@ namespace OpenRA.Graphics byte[] data; public readonly Size Size; - public byte[] Data { get { return data ?? texture.GetData(); } } - public bool Buffered { get { return data != null; } } + public byte[] Data + { + get + { + if (data != null) + return data; + if (texture == null) + data = new byte[4 * Size.Width * Size.Height]; + else + data = texture.GetData(); + releaseBufferOnCommit = false; + return data; + } + } + public bool Buffered { get { return data != null || texture == null; } } - public Sheet(Size size, bool buffered) + public Sheet(Size size) { Size = size; - if (buffered) - data = new byte[4 * Size.Width * Size.Height]; } public Sheet(ITexture texture) @@ -80,7 +91,7 @@ namespace OpenRA.Graphics dirty = true; } - if (Buffered) + if (data != null) { lock (textureLock) { @@ -141,20 +152,28 @@ namespace OpenRA.Graphics public void CommitData() { - if (!Buffered) - throw new InvalidOperationException( - "This sheet is unbuffered. You cannot call CommitData on an unbuffered sheet. " + - "If you need to completely replace the texture data you should set data into the texture directly. " + - "If you need to make only small changes to the texture data consider creating a buffered sheet instead."); - - lock (textureLock) - dirty = true; + CommitData(false); } public void ReleaseBuffer() + { + CommitData(true); + } + + void CommitData(bool releaseBuffer) { lock (textureLock) - releaseBufferOnCommit = true; + { + if (!Buffered) + throw new InvalidOperationException( + "This sheet is unbuffered. You cannot call CommitData on an unbuffered sheet. " + + "If you need to completely replace the texture data you should set data into the texture directly. " + + "If you need to make only small changes to the texture data consider creating a buffered sheet instead."); + + dirty = true; + if (releaseBuffer) + releaseBufferOnCommit = true; + } } } } diff --git a/OpenRA.Game/Graphics/SheetBuilder.cs b/OpenRA.Game/Graphics/SheetBuilder.cs index 45d9148acd..eb1049f65f 100644 --- a/OpenRA.Game/Graphics/SheetBuilder.cs +++ b/OpenRA.Game/Graphics/SheetBuilder.cs @@ -38,7 +38,7 @@ namespace OpenRA.Graphics public static Sheet AllocateSheet() { - return new Sheet(new Size(Renderer.SheetSize, Renderer.SheetSize), true); + return new Sheet(new Size(Renderer.SheetSize, Renderer.SheetSize)); } public SheetBuilder(SheetType t) diff --git a/OpenRA.Game/Graphics/Theater.cs b/OpenRA.Game/Graphics/Theater.cs index dc7c9f3b57..f3e20a95cb 100644 --- a/OpenRA.Game/Graphics/Theater.cs +++ b/OpenRA.Game/Graphics/Theater.cs @@ -33,7 +33,7 @@ namespace OpenRA.Graphics throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter."); allocated = true; - return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize), true); + return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize)); }; sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); diff --git a/OpenRA.Game/Widgets/VqaPlayerWidget.cs b/OpenRA.Game/Widgets/VqaPlayerWidget.cs index 8831a9ddad..d7eca7ce55 100644 --- a/OpenRA.Game/Widgets/VqaPlayerWidget.cs +++ b/OpenRA.Game/Widgets/VqaPlayerWidget.cs @@ -61,7 +61,7 @@ namespace OpenRA.Widgets var size = Math.Max(video.Width, video.Height); var textureSize = Exts.NextPowerOf2(size); - var videoSheet = new Sheet(new Size(textureSize, textureSize), false); + var videoSheet = new Sheet(new Size(textureSize, textureSize)); videoSheet.Texture.ScaleFilter = TextureScaleFilter.Linear; videoSheet.Texture.SetData(video.FrameData); @@ -89,7 +89,7 @@ namespace OpenRA.Widgets for (var y = 0; y < scaledHeight; y += 2) overlay[y, 0] = black; - var overlaySheet = new Sheet(new Size(1, Exts.NextPowerOf2(scaledHeight)), false); + var overlaySheet = new Sheet(new Size(1, Exts.NextPowerOf2(scaledHeight))); overlaySheet.Texture.SetData(overlay); overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, scaledHeight), TextureChannel.Alpha); } diff --git a/OpenRA.Mods.Common/Widgets/ColorMixerWidget.cs b/OpenRA.Mods.Common/Widgets/ColorMixerWidget.cs index 43717ce3e1..38130c9b5f 100644 --- a/OpenRA.Mods.Common/Widgets/ColorMixerWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ColorMixerWidget.cs @@ -51,7 +51,7 @@ namespace OpenRA.Mods.Common.Widgets back = new byte[4*256*256]; var rect = new Rectangle((int)(255*SRange[0]), (int)(255*(1 - VRange[1])), (int)(255*(SRange[1] - SRange[0]))+1, (int)(255*(VRange[1] - VRange[0])) + 1); - var mixerSheet = new Sheet(new Size(256, 256), false); + var mixerSheet = new Sheet(new Size(256, 256)); mixerSheet.Texture.SetData(front, 256, 256); mixerSprite = new Sprite(mixerSheet, rect, TextureChannel.Alpha); } diff --git a/OpenRA.Mods.Common/Widgets/HueSliderWidget.cs b/OpenRA.Mods.Common/Widgets/HueSliderWidget.cs index 0e31f6c446..988244c731 100644 --- a/OpenRA.Mods.Common/Widgets/HueSliderWidget.cs +++ b/OpenRA.Mods.Common/Widgets/HueSliderWidget.cs @@ -28,7 +28,7 @@ namespace OpenRA.Mods.Common.Widgets using (var hueBitmap = new Bitmap(256, 256)) { - var hueSheet = new Sheet(new Size(256, 256), false); + var hueSheet = new Sheet(new Size(256, 256)); hueSprite = new Sprite(hueSheet, new Rectangle(0, 0, 256, 1), TextureChannel.Alpha); var bitmapData = hueBitmap.LockBits(hueBitmap.Bounds(), diff --git a/OpenRA.Mods.Common/Widgets/RadarWidget.cs b/OpenRA.Mods.Common/Widgets/RadarWidget.cs index 6091f50e95..088d2aecff 100644 --- a/OpenRA.Mods.Common/Widgets/RadarWidget.cs +++ b/OpenRA.Mods.Common/Widgets/RadarWidget.cs @@ -73,14 +73,14 @@ namespace OpenRA.Mods.Common.Widgets { var r = new Rectangle(0, 0, width, height); var s = new Size(terrainBitmap.Width, terrainBitmap.Height); - var terrainSheet = new Sheet(s, false); + var terrainSheet = new Sheet(s); terrainSheet.Texture.SetData(terrainBitmap); terrainSprite = new Sprite(terrainSheet, r, TextureChannel.Alpha); // Data is set in Tick() - customTerrainSprite = new Sprite(new Sheet(s, false), r, TextureChannel.Alpha); - actorSprite = new Sprite(new Sheet(s, false), r, TextureChannel.Alpha); - shroudSprite = new Sprite(new Sheet(s, false), r, TextureChannel.Alpha); + customTerrainSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); + actorSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); + shroudSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); } }