From 53f06ba09318a9c0e551c084ffb174ccf96234e4 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Wed, 7 Jan 2015 21:08:48 +0000 Subject: [PATCH] Implement dynamic hardware palette sizing. The HardwarePalette will now grow its palette buffer and texture in power-of-2 increments. This avoids it having to allocate memory for a full 256x256 texture up front. In practice the default mods use 22 or 23 palettes so a 32x256 texture is used. This means both the buffer and texture save neatly on memory. Additionally, HardwarePalette.ApplyModifiers sees a nice speedup as it has to transfer a much smaller amount of memory from the buffer to the texture. To facilitate this change, the MaxPalettes constant is no more. Instead the PaletteReference deals with the calculation of the index and this is passed into the appropriate methods. --- OpenRA.Game/Graphics/HardwarePalette.cs | 25 +++++++++++++++++-------- OpenRA.Game/Graphics/SoftwareCursor.cs | 2 +- OpenRA.Game/Graphics/SpriteRenderer.cs | 8 ++++---- OpenRA.Game/Graphics/TerrainRenderer.cs | 2 +- OpenRA.Game/Graphics/Util.cs | 15 +++++++-------- OpenRA.Game/Graphics/VoxelRenderer.cs | 10 ++++------ OpenRA.Game/Graphics/WorldRenderer.cs | 12 ++++++++---- 7 files changed, 42 insertions(+), 32 deletions(-) diff --git a/OpenRA.Game/Graphics/HardwarePalette.cs b/OpenRA.Game/Graphics/HardwarePalette.cs index df10a17b24..30d8a33323 100644 --- a/OpenRA.Game/Graphics/HardwarePalette.cs +++ b/OpenRA.Game/Graphics/HardwarePalette.cs @@ -16,14 +16,13 @@ namespace OpenRA.Graphics { public sealed class HardwarePalette : IDisposable { - public const int MaxPalettes = 256; - public ITexture Texture { get; private set; } + public int Height { get; private set; } readonly Dictionary palettes = new Dictionary(); readonly Dictionary modifiablePalettes = new Dictionary(); readonly IReadOnlyDictionary readOnlyModifiablePalettes; readonly Dictionary indices = new Dictionary(); - readonly uint[,] buffer = new uint[MaxPalettes, Palette.Size]; + byte[] buffer = new byte[0]; public HardwarePalette() { @@ -52,14 +51,19 @@ namespace OpenRA.Graphics public void AddPalette(string name, ImmutablePalette p, bool allowModifiers) { - if (palettes.Count >= MaxPalettes) - throw new InvalidOperationException("Limit of {0} palettes reached. Cannot add {1}.".F(MaxPalettes, name)); if (palettes.ContainsKey(name)) throw new InvalidOperationException("Palette {0} has already been defined".F(name)); int index = palettes.Count; indices.Add(name, index); palettes.Add(name, p); + + if (palettes.Count > Height) + { + Height = Exts.NextPowerOf2(palettes.Count); + Array.Resize(ref buffer, Height * Palette.Size * 4); + } + if (allowModifiers) modifiablePalettes.Add(name, new MutablePalette(p)); else @@ -74,13 +78,13 @@ namespace OpenRA.Graphics CopyPaletteToBuffer(indices[name], palettes[name] = new ImmutablePalette(p)); else throw new InvalidOperationException("Palette `{0}` does not exist".F(name)); - Texture.SetData(buffer); + CopyBufferToTexture(); } public void Initialize() { CopyModifiablePalettesToBuffer(); - Texture.SetData(buffer); + CopyBufferToTexture(); } void CopyPaletteToBuffer(int index, IPalette p) @@ -94,6 +98,11 @@ namespace OpenRA.Graphics CopyPaletteToBuffer(indices[kvp.Key], kvp.Value); } + void CopyBufferToTexture() + { + Texture.SetData(buffer, Palette.Size, Height); + } + public void ApplyModifiers(IEnumerable paletteMods) { foreach (var mod in paletteMods) @@ -101,7 +110,7 @@ namespace OpenRA.Graphics // Update our texture with the changes. CopyModifiablePalettesToBuffer(); - Texture.SetData(buffer); + CopyBufferToTexture(); // Reset modified palettes back to their original colors, ready for next time. foreach (var kvp in modifiablePalettes) diff --git a/OpenRA.Game/Graphics/SoftwareCursor.cs b/OpenRA.Game/Graphics/SoftwareCursor.cs index f5df1ff7c3..0d2eb99a98 100644 --- a/OpenRA.Game/Graphics/SoftwareCursor.cs +++ b/OpenRA.Game/Graphics/SoftwareCursor.cs @@ -57,7 +57,7 @@ namespace OpenRA.Graphics PaletteReference CreatePaletteReference(string name) { var pal = palette.GetPalette(name); - return new PaletteReference(name, palette.GetPaletteIndex(name), pal); + return new PaletteReference(name, palette.GetPaletteIndex(name), pal, palette); } string cursorName; diff --git a/OpenRA.Game/Graphics/SpriteRenderer.cs b/OpenRA.Game/Graphics/SpriteRenderer.cs index 2605f49b9a..2e7e812f63 100644 --- a/OpenRA.Game/Graphics/SpriteRenderer.cs +++ b/OpenRA.Game/Graphics/SpriteRenderer.cs @@ -51,15 +51,15 @@ namespace OpenRA.Graphics public void DrawSprite(Sprite s, float2 location, PaletteReference pal) { - DrawSprite(s, location, pal.Index, s.Size); + DrawSprite(s, location, pal.TextureIndex, s.Size); } public void DrawSprite(Sprite s, float2 location, PaletteReference pal, float2 size) { - DrawSprite(s, location, pal.Index, size); + DrawSprite(s, location, pal.TextureIndex, size); } - void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size) + void DrawSprite(Sprite s, float2 location, float paletteTextureIndex, float2 size) { renderer.CurrentBatchRenderer = this; @@ -74,7 +74,7 @@ namespace OpenRA.Graphics currentBlend = s.BlendMode; currentSheet = s.Sheet; - Util.FastCreateQuad(vertices, location + s.FractionalOffset * size, s, paletteIndex, nv, size); + Util.FastCreateQuad(vertices, location + s.FractionalOffset * size, s, paletteTextureIndex, nv, size); nv += 4; } diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index 2ab54a509f..8561ea03c6 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -24,7 +24,7 @@ namespace OpenRA.Graphics this.world = world; this.map = world.Map; - var terrainPalette = wr.Palette("terrain").Index; + var terrainPalette = wr.Palette("terrain").TextureIndex; var vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width]; var nv = 0; diff --git a/OpenRA.Game/Graphics/Util.cs b/OpenRA.Game/Graphics/Util.cs index b734c3fef4..6eb82c16b3 100644 --- a/OpenRA.Game/Graphics/Util.cs +++ b/OpenRA.Game/Graphics/Util.cs @@ -21,23 +21,22 @@ namespace OpenRA.Graphics static readonly int[] ChannelMasks = { 2, 1, 0, 3 }; static readonly float[] ChannelSelect = { 0.75f, 0.25f, -0.25f, -0.75f }; - public static void FastCreateQuad(Vertex[] vertices, float2 o, Sprite r, int palette, int nv, float2 size) + public static void FastCreateQuad(Vertex[] vertices, float2 o, Sprite r, float paletteTextureIndex, int nv, float2 size) { var b = new float2(o.X + size.X, o.Y); var c = new float2(o.X + size.X, o.Y + size.Y); var d = new float2(o.X, o.Y + size.Y); - FastCreateQuad(vertices, o, b, c, d, r, palette, nv); + FastCreateQuad(vertices, o, b, c, d, r, paletteTextureIndex, nv); } - public static void FastCreateQuad(Vertex[] vertices, float2 a, float2 b, float2 c, float2 d, Sprite r, int palette, int nv) + public static void FastCreateQuad(Vertex[] vertices, float2 a, float2 b, float2 c, float2 d, Sprite r, float paletteTextureIndex, int nv) { - var attribP = palette / (float)HardwarePalette.MaxPalettes; var attribC = ChannelSelect[(int)r.Channel]; - vertices[nv] = new Vertex(a, r.Left, r.Top, attribP, attribC); - vertices[nv + 1] = new Vertex(b, r.Right, r.Top, attribP, attribC); - vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, attribP, attribC); - vertices[nv + 3] = new Vertex(d, r.Left, r.Bottom, attribP, attribC); + vertices[nv] = new Vertex(a, r.Left, r.Top, paletteTextureIndex, attribC); + vertices[nv + 1] = new Vertex(b, r.Right, r.Top, paletteTextureIndex, attribC); + vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, paletteTextureIndex, attribC); + vertices[nv + 3] = new Vertex(d, r.Left, r.Bottom, paletteTextureIndex, attribC); } public static void FastCopyIntoChannel(Sprite dest, byte[] src) { FastCopyIntoChannel(dest, 0, src); } diff --git a/OpenRA.Game/Graphics/VoxelRenderer.cs b/OpenRA.Game/Graphics/VoxelRenderer.cs index 3f7b5879b2..508b116fee 100644 --- a/OpenRA.Game/Graphics/VoxelRenderer.cs +++ b/OpenRA.Game/Graphics/VoxelRenderer.cs @@ -203,11 +203,11 @@ namespace OpenRA.Graphics var lightDirection = ExtractRotationVector(Util.MatrixMultiply(Util.MatrixInverse(t), lightTransform)); Render(rd, Util.MatrixMultiply(transform, t), lightDirection, - lightAmbientColor, lightDiffuseColor, color.Index, normals.Index); + lightAmbientColor, lightDiffuseColor, color.TextureMidIndex, normals.TextureMidIndex); // Disable shadow normals by forcing zero diffuse and identity ambient light Render(rd, Util.MatrixMultiply(shadow, t), lightDirection, - ShadowAmbient, ShadowDiffuse, shadowPalette.Index, normals.Index); + ShadowAmbient, ShadowDiffuse, shadowPalette.TextureMidIndex, normals.TextureMidIndex); } } })); @@ -254,12 +254,10 @@ namespace OpenRA.Graphics VoxelRenderData renderData, float[] t, float[] lightDirection, float[] ambientLight, float[] diffuseLight, - int colorPalette, int normalsPalette) + float colorPaletteTextureMidIndex, float normalsPaletteTextureMidIndex) { shader.SetTexture("DiffuseTexture", renderData.Sheet.GetTexture()); - shader.SetVec("PaletteRows", - (colorPalette + 0.5f) / HardwarePalette.MaxPalettes, - (normalsPalette + 0.5f) / HardwarePalette.MaxPalettes); + shader.SetVec("PaletteRows", colorPaletteTextureMidIndex, normalsPaletteTextureMidIndex); shader.SetMatrix("TransformMatrix", t); shader.SetVec("LightDirection", lightDirection, 4); shader.SetVec("AmbientLight", ambientLight, 3); diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 072adf1635..3d9991213e 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -19,13 +19,17 @@ namespace OpenRA.Graphics public class PaletteReference { public readonly string Name; - public readonly int Index; public IPalette Palette { get; internal set; } - public PaletteReference(string name, int index, IPalette palette) + readonly float index; + readonly HardwarePalette hardwarePalette; + public float TextureIndex { get { return index / hardwarePalette.Height; } } + public float TextureMidIndex { get { return (index + 0.5f) / hardwarePalette.Height; } } + public PaletteReference(string name, int index, IPalette palette, HardwarePalette hardwarePalette) { Name = name; - Index = index; Palette = palette; + this.index = index; + this.hardwarePalette = hardwarePalette; } } @@ -59,7 +63,7 @@ namespace OpenRA.Graphics PaletteReference CreatePaletteReference(string name) { var pal = palette.GetPalette(name); - return new PaletteReference(name, palette.GetPaletteIndex(name), pal); + return new PaletteReference(name, palette.GetPaletteIndex(name), pal, palette); } public PaletteReference Palette(string name) { return palettes.GetOrAdd(name, CreatePaletteReference); }