Merge pull request #5712 from RoosterDragon/sheet-release-buffer

Release sheet buffers
This commit is contained in:
Paul Chote
2014-07-03 22:57:56 +12:00
11 changed files with 97 additions and 57 deletions

View File

@@ -271,6 +271,8 @@ namespace OpenRA
orderManager.LastTickTime = Environment.TickCount;
orderManager.StartGame();
worldRenderer.RefreshPalette();
GC.Collect();
}
public static bool IsHost

View File

@@ -46,6 +46,7 @@ namespace OpenRA.Graphics
var spriteLoader = new SpriteLoader(new string[0], new SheetBuilder(SheetType.Indexed));
foreach (var s in nodesDict["Cursors"].Nodes)
LoadSequencesForCursor(spriteLoader, s.Key, s.Value);
spriteLoader.SheetBuilder.Current.ReleaseBuffer();
palette.Initialize();
}

View File

@@ -18,18 +18,21 @@ namespace OpenRA.Graphics
{
public class Sheet
{
ITexture texture;
readonly object textureLock = new object();
bool dirty;
readonly byte[] data;
readonly object dirtyLock = new object();
bool releaseBufferOnCommit;
ITexture texture;
byte[] data;
public readonly Size Size;
public byte[] Data { get { return data ?? texture.GetData(); } }
public bool Buffered { get { return data != null; } }
public Sheet(Size size)
public Sheet(Size size, bool buffered)
{
Size = size;
data = new byte[4 * Size.Width * Size.Height];
if (buffered)
data = new byte[4 * Size.Width * Size.Height];
}
public Sheet(ITexture texture)
@@ -54,6 +57,8 @@ namespace OpenRA.Graphics
Marshal.Copy(IntPtr.Add(bd.Scan0, y * bd.Stride), data, y * dataStride, dataStride);
bitmap.UnlockBits(bd);
}
ReleaseBuffer();
}
public ITexture Texture
@@ -62,22 +67,31 @@ namespace OpenRA.Graphics
// is set from other threads too via CommitData().
get
{
if (texture == null)
{
texture = Game.Renderer.Device.CreateTexture();
dirty = true;
}
GenerateTexture();
return texture;
}
}
lock (dirtyLock)
void GenerateTexture()
{
if (texture == null)
{
texture = Game.Renderer.Device.CreateTexture();
dirty = true;
}
if (Buffered)
{
lock (textureLock)
{
if (dirty)
{
texture.SetData(data, Size.Width, Size.Height);
dirty = false;
if (releaseBufferOnCommit)
data = null;
}
}
return texture;
}
}
@@ -119,6 +133,7 @@ namespace OpenRA.Graphics
}
}
}
bitmap.UnlockBits(bd);
return bitmap;
@@ -126,11 +141,20 @@ namespace OpenRA.Graphics
public void CommitData()
{
if (data == null)
throw new InvalidOperationException("Texture-wrappers are read-only");
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 (dirtyLock)
lock (textureLock)
dirty = true;
}
public void ReleaseBuffer()
{
lock (textureLock)
releaseBufferOnCommit = true;
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -17,7 +17,7 @@ namespace OpenRA.Graphics
public class SheetOverflowException : Exception
{
public SheetOverflowException(string message)
: base(message) {}
: base(message) { }
}
public enum SheetType
@@ -38,11 +38,11 @@ namespace OpenRA.Graphics
public static Sheet AllocateSheet()
{
return new Sheet(new Size(Renderer.SheetSize, Renderer.SheetSize));
return new Sheet(new Size(Renderer.SheetSize, Renderer.SheetSize), true);
}
public SheetBuilder(SheetType t)
: this(t, AllocateSheet) {}
: this(t, AllocateSheet) { }
public SheetBuilder(SheetType t, Func<Sheet> allocateSheet)
{
@@ -109,6 +109,7 @@ namespace OpenRA.Graphics
var next = NextChannel(channel);
if (next == null)
{
current.ReleaseBuffer();
current = allocateSheet();
channel = TextureChannel.Red;
}
@@ -116,7 +117,7 @@ namespace OpenRA.Graphics
channel = next.Value;
rowHeight = imageSize.Height;
p = new Point(0,0);
p = new Point(0, 0);
}
var rect = new Sprite(current, new Rectangle(p, imageSize), spriteOffset, channel, BlendMode.Alpha);

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -58,7 +58,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));
return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize), true);
};
var sourceCache = new Dictionary<string, ISpriteSource>();
@@ -69,6 +69,8 @@ namespace OpenRA.Graphics
// 1x1px transparent tile
missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1));
Sheet.ReleaseBuffer();
}
public Sprite TileSprite(TerrainTile r)

View File

@@ -179,6 +179,7 @@ namespace OpenRA.Graphics
{
// Sheet overflow - allocate a new sheet and try once more
Log.Write("debug", "Voxel sheet overflow! Generating new sheet");
sheetBuilder.Current.ReleaseBuffer();
sheetBuilder = CreateSheetBuilder();
v = GenerateSlicePlanes(l).SelectMany(x => x).ToArray();
}
@@ -223,5 +224,10 @@ namespace OpenRA.Graphics
{
return voxels[Pair.New(vxl, hva)];
}
public void Finish()
{
sheetBuilder.Current.ReleaseBuffer();
}
}
}

View File

@@ -87,7 +87,7 @@ namespace OpenRA
FieldLoader.Translations = new Dictionary<string, string>();
return;
}
var yaml = Manifest.Translations.Select(MiniYaml.FromFile).Aggregate(MiniYaml.MergeLiberal);
Languages = yaml.Select(t => t.Key).ToArray();
@@ -100,7 +100,7 @@ namespace OpenRA
else if (y.Key == Game.Settings.Graphics.DefaultLanguage)
defaultTranslations = y.Value.ToDictionary(my => my.Value ?? "");
}
var translations = new Dictionary<string, string>();
foreach (var tkv in defaultTranslations.Concat(selectedTranslations))
{
@@ -140,6 +140,7 @@ namespace OpenRA
map.SequenceProvider.Preload();
VoxelProvider.Initialize(Manifest.VoxelSequences, map.VoxelSequenceDefinitions);
VoxelLoader.Finish();
return map;
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -27,14 +27,13 @@ namespace OpenRA.Widgets
bool stopped;
bool paused;
Action OnComplete;
Action onComplete;
public bool Paused { get { return paused; } }
readonly World world;
[ObjectCreator.UseCtor]
public VqaPlayerWidget( World world )
public VqaPlayerWidget(World world)
{
this.world = world;
}
@@ -48,33 +47,35 @@ namespace OpenRA.Widgets
stopped = true;
paused = true;
Sound.StopVideo();
OnComplete = () => {};
onComplete = () => { };
cachedVideo = filename;
video = new VqaReader(GlobalFileSystem.Open(filename));
invLength = video.Framerate*1f/video.Frames;
invLength = video.Framerate * 1f / video.Frames;
var size = Math.Max(video.Width, video.Height);
var textureSize = Exts.NextPowerOf2(size);
videoSprite = new Sprite(new Sheet(new Size(textureSize,textureSize)), new Rectangle( 0, 0, video.Width, video.Height ), TextureChannel.Alpha);
videoSprite.sheet.Texture.SetData(video.FrameData);
var videoSheet = new Sheet(new Size(textureSize, textureSize), false);
videoSheet.Texture.SetData(video.FrameData);
videoSprite = new Sprite(videoSheet, new Rectangle(0, 0, video.Width, video.Height), TextureChannel.Alpha);
var scale = Math.Min(RenderBounds.Width / video.Width, RenderBounds.Height / video.Height);
videoOrigin = new float2(RenderBounds.X + (RenderBounds.Width - scale*video.Width)/2, RenderBounds.Y + (RenderBounds.Height - scale*video.Height)/2);
videoOrigin = new float2(RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2, RenderBounds.Y + (RenderBounds.Height - scale * video.Height) / 2);
videoSize = new float2(video.Width * scale, video.Height * scale);
if (!DrawOverlay)
return;
overlay = new uint[2*textureSize, 2*textureSize];
overlay = new uint[2 * textureSize, 2 * textureSize];
var black = (uint)255 << 24;
for (var y = 0; y < video.Height; y++)
for (var x = 0; x < video.Width; x++)
overlay[2*y,x] = black;
overlay[2 * y, x] = black;
overlaySprite = new Sprite(new Sheet(new Size(2*textureSize,2*textureSize)), new Rectangle( 0, 0, video.Width, 2*video.Height ), TextureChannel.Alpha);
overlaySprite.sheet.Texture.SetData(overlay);
var overlaySheet = new Sheet(new Size(2 * textureSize, 2 * textureSize), false);
overlaySheet.Texture.SetData(overlay);
overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, video.Width, 2 * video.Height), TextureChannel.Alpha);
}
public override void Draw()
@@ -84,7 +85,7 @@ namespace OpenRA.Widgets
if (!(stopped || paused))
{
var nextFrame = (int)float2.Lerp(0, video.Frames, Sound.VideoSeekPosition*invLength);
var nextFrame = (int)float2.Lerp(0, video.Frames, Sound.VideoSeekPosition * invLength);
if (nextFrame > video.Frames)
{
Stop();
@@ -115,12 +116,13 @@ namespace OpenRA.Widgets
return true;
}
}
return false;
}
public void Play()
{
PlayThen(() => {});
PlayThen(() => { });
}
public void PlayThen(Action after)
@@ -128,7 +130,7 @@ namespace OpenRA.Widgets
if (video == null)
return;
OnComplete = after;
onComplete = after;
if (stopped)
Sound.PlayVideo(video.AudioData);
else
@@ -156,7 +158,7 @@ namespace OpenRA.Widgets
Sound.StopVideo();
video.Reset();
videoSprite.sheet.Texture.SetData(video.FrameData);
world.AddFrameEndTask(_ => OnComplete());
world.AddFrameEndTask(_ => onComplete());
}
}
}

View File

@@ -51,8 +51,9 @@ namespace OpenRA.Mods.RA.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);
mixerSprite = new Sprite(new Sheet(new Size(256, 256)), rect, TextureChannel.Alpha);
mixerSprite.sheet.Texture.SetData(front, 256, 256);
var mixerSheet = new Sheet(new Size(256, 256), false);
mixerSheet.Texture.SetData(front, 256, 256);
mixerSprite = new Sprite(mixerSheet, rect, TextureChannel.Alpha);
}
void GenerateBitmap()

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -19,8 +19,8 @@ namespace OpenRA.Mods.RA.Widgets
{
Sprite hueSprite;
public HueSliderWidget() {}
public HueSliderWidget(HueSliderWidget other) : base(other) {}
public HueSliderWidget() { }
public HueSliderWidget(HueSliderWidget other) : base(other) { }
public override void Initialize(WidgetArgs args)
{
@@ -28,7 +28,8 @@ namespace OpenRA.Mods.RA.Widgets
using (var hueBitmap = new Bitmap(256, 256))
{
hueSprite = new Sprite(new Sheet(new Size(256, 256)), new Rectangle(0, 0, 256, 1), TextureChannel.Alpha);
var hueSheet = new Sheet(new Size(256, 256), false);
hueSprite = new Sprite(hueSheet, new Rectangle(0, 0, 256, 1), TextureChannel.Alpha);
var bitmapData = hueBitmap.LockBits(hueBitmap.Bounds(),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
@@ -39,8 +40,7 @@ namespace OpenRA.Mods.RA.Widgets
*(c + h) = HSLColor.FromHSV(h / 255f, 1, 1).RGB.ToArgb();
}
hueBitmap.UnlockBits(bitmapData);
hueSprite.sheet.Texture.SetData(hueBitmap);
hueSheet.Texture.SetData(hueBitmap);
}
}
@@ -54,9 +54,8 @@ namespace OpenRA.Mods.RA.Widgets
Game.Renderer.RgbaSpriteRenderer.DrawSprite(hueSprite, ro, new float2(rb.Size));
var sprite = ChromeProvider.GetImage("lobby-bits", "huepicker");
var pos = RenderOrigin + new int2(PxFromValue(Value).Clamp(0, rb.Width-1) - sprite.bounds.Width/2, (rb.Height-sprite.bounds.Height)/2);
var pos = RenderOrigin + new int2(PxFromValue(Value).Clamp(0, rb.Width - 1) - sprite.bounds.Width / 2, (rb.Height - sprite.bounds.Height) / 2);
Game.Renderer.RgbaSpriteRenderer.DrawSprite(sprite, pos);
}
}
}

View File

@@ -72,13 +72,14 @@ namespace OpenRA.Mods.RA.Widgets
{
var r = new Rectangle(0, 0, width, height);
var s = new Size(terrainBitmap.Width, terrainBitmap.Height);
terrainSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha);
terrainSprite.sheet.Texture.SetData(terrainBitmap);
var terrainSheet = new Sheet(s, false);
terrainSheet.Texture.SetData(terrainBitmap);
terrainSprite = new Sprite(terrainSheet, r, TextureChannel.Alpha);
// Data is set in Tick()
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);
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);
}
}