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.
This commit is contained in:
RoosterDragon
2014-10-13 21:09:28 +01:00
committed by RoosterDragon
parent e6852e2b50
commit ff16690b86
7 changed files with 44 additions and 25 deletions

View File

@@ -25,14 +25,25 @@ namespace OpenRA.Graphics
byte[] data; byte[] data;
public readonly Size Size; public readonly Size Size;
public byte[] Data { get { return data ?? texture.GetData(); } } public byte[] Data
public bool Buffered { get { return data != null; } } {
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; Size = size;
if (buffered)
data = new byte[4 * Size.Width * Size.Height];
} }
public Sheet(ITexture texture) public Sheet(ITexture texture)
@@ -80,7 +91,7 @@ namespace OpenRA.Graphics
dirty = true; dirty = true;
} }
if (Buffered) if (data != null)
{ {
lock (textureLock) lock (textureLock)
{ {
@@ -141,20 +152,28 @@ namespace OpenRA.Graphics
public void CommitData() public void CommitData()
{ {
if (!Buffered) CommitData(false);
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;
} }
public void ReleaseBuffer() public void ReleaseBuffer()
{
CommitData(true);
}
void CommitData(bool releaseBuffer)
{ {
lock (textureLock) 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;
}
} }
} }
} }

View File

@@ -38,7 +38,7 @@ namespace OpenRA.Graphics
public static Sheet AllocateSheet() 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) public SheetBuilder(SheetType t)

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Graphics
throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter."); throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter.");
allocated = true; 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); sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate);

View File

@@ -61,7 +61,7 @@ namespace OpenRA.Widgets
var size = Math.Max(video.Width, video.Height); var size = Math.Max(video.Width, video.Height);
var textureSize = Exts.NextPowerOf2(size); 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.ScaleFilter = TextureScaleFilter.Linear;
videoSheet.Texture.SetData(video.FrameData); videoSheet.Texture.SetData(video.FrameData);
@@ -89,7 +89,7 @@ namespace OpenRA.Widgets
for (var y = 0; y < scaledHeight; y += 2) for (var y = 0; y < scaledHeight; y += 2)
overlay[y, 0] = black; 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); overlaySheet.Texture.SetData(overlay);
overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, scaledHeight), TextureChannel.Alpha); overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, scaledHeight), TextureChannel.Alpha);
} }

View File

@@ -51,7 +51,7 @@ namespace OpenRA.Mods.Common.Widgets
back = new byte[4*256*256]; 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 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); mixerSheet.Texture.SetData(front, 256, 256);
mixerSprite = new Sprite(mixerSheet, rect, TextureChannel.Alpha); mixerSprite = new Sprite(mixerSheet, rect, TextureChannel.Alpha);
} }

View File

@@ -28,7 +28,7 @@ namespace OpenRA.Mods.Common.Widgets
using (var hueBitmap = new Bitmap(256, 256)) 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); hueSprite = new Sprite(hueSheet, new Rectangle(0, 0, 256, 1), TextureChannel.Alpha);
var bitmapData = hueBitmap.LockBits(hueBitmap.Bounds(), var bitmapData = hueBitmap.LockBits(hueBitmap.Bounds(),

View File

@@ -73,14 +73,14 @@ namespace OpenRA.Mods.Common.Widgets
{ {
var r = new Rectangle(0, 0, width, height); var r = new Rectangle(0, 0, width, height);
var s = new Size(terrainBitmap.Width, terrainBitmap.Height); var s = new Size(terrainBitmap.Width, terrainBitmap.Height);
var terrainSheet = new Sheet(s, false); var terrainSheet = new Sheet(s);
terrainSheet.Texture.SetData(terrainBitmap); terrainSheet.Texture.SetData(terrainBitmap);
terrainSprite = new Sprite(terrainSheet, r, TextureChannel.Alpha); terrainSprite = new Sprite(terrainSheet, r, TextureChannel.Alpha);
// Data is set in Tick() // Data is set in Tick()
customTerrainSprite = new Sprite(new Sheet(s, false), r, TextureChannel.Alpha); customTerrainSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha);
actorSprite = new Sprite(new Sheet(s, false), r, TextureChannel.Alpha); actorSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha);
shroudSprite = new Sprite(new Sheet(s, false), r, TextureChannel.Alpha); shroudSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha);
} }
} }