From b77a116f60efdd68cf8e758c6c3504702de6c1b8 Mon Sep 17 00:00:00 2001 From: chrisf Date: Tue, 25 Mar 2008 02:07:15 +0000 Subject: [PATCH] MOAR PERF git-svn-id: svn://svn.ijw.co.nz/svn/OpenRa@1956 993157c7-ee19-0410-b2c4-bb4e9862e678 --- OpenRa.FileFormats/Format40.cs | 33 ++++++------------ OpenRa.FileFormats/Format80.cs | 60 ++++++++++++++++++++------------- OpenRa.FileFormats/Map.cs | 4 +-- OpenRa.FileFormats/ShpReader.cs | 13 +++---- OpenRa.Game/SpriteRenderer.cs | 24 ++++++------- OpenRa.Game/TerrainRenderer.cs | 40 +++++++++++----------- OpenRa.Game/Util.cs | 47 +++++++------------------- 7 files changed, 98 insertions(+), 123 deletions(-) diff --git a/OpenRa.FileFormats/Format40.cs b/OpenRa.FileFormats/Format40.cs index dc6abd3bbc..9f9e5264b1 100644 --- a/OpenRa.FileFormats/Format40.cs +++ b/OpenRa.FileFormats/Format40.cs @@ -7,35 +7,22 @@ namespace OpenRa.FileFormats { public static class Format40 { - static byte ReadByte( MemoryStream input ) - { - int inp = input.ReadByte(); - if( inp == -1 ) - throw new InvalidDataException(); - - return (byte)inp; - } - - static int ReadWord( MemoryStream input ) - { - int inp = ReadByte( input ); - return inp + ( ReadByte( input ) << 8 ); - } - - public static int DecodeInto( MemoryStream input, byte[] dest ) + public static int DecodeInto( byte[] src, byte[] dest ) { + var ctx = new FastByteReader(src); int destIndex = 0; + while( true ) { - byte i = ReadByte( input ); + byte i = ctx.ReadByte(); if( ( i & 0x80 ) == 0 ) { int count = i & 0x7F; if( count == 0 ) { // case 6 - count = ReadByte( input ); - byte value = ReadByte( input ); + count = ctx.ReadByte(); + byte value = ctx.ReadByte(); for( int end = destIndex + count ; destIndex < end ; destIndex++ ) dest[ destIndex ] ^= value; } @@ -43,7 +30,7 @@ namespace OpenRa.FileFormats { // case 5 for( int end = destIndex + count ; destIndex < end ; destIndex++ ) - dest[ destIndex ] ^= ReadByte( input ); + dest[destIndex] ^= ctx.ReadByte(); } } else @@ -51,7 +38,7 @@ namespace OpenRa.FileFormats int count = i & 0x7F; if( count == 0 ) { - count = ReadWord( input ); + count = ctx.ReadWord(); if( count == 0 ) return destIndex; @@ -64,12 +51,12 @@ namespace OpenRa.FileFormats { // case 3 for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ ) - dest[ destIndex ] ^= ReadByte( input ); + dest[destIndex] ^= ctx.ReadByte(); } else { // case 4 - byte value = ReadByte( input ); + byte value = ctx.ReadByte(); for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ ) dest[ destIndex ] ^= value; } diff --git a/OpenRa.FileFormats/Format80.cs b/OpenRa.FileFormats/Format80.cs index 0d3345dd58..f8138a5fe4 100644 --- a/OpenRa.FileFormats/Format80.cs +++ b/OpenRa.FileFormats/Format80.cs @@ -5,23 +5,33 @@ using System.IO; namespace OpenRa.FileFormats { + class FastByteReader + { + readonly byte[] src; + int offset = 0; + + public FastByteReader(byte[] src) + { + this.src = src; + } + + public bool Done() { return offset >= src.Length; } + public byte ReadByte() { return src[offset++]; } + public int ReadWord() + { + int x = ReadByte(); + return x | (ReadByte() << 8); + } + + public void CopyTo(byte[] dest, int offset, int count) + { + Array.Copy(src, this.offset, dest, offset, count); + this.offset += count; + } + } + public static class Format80 { - static byte ReadByte( MemoryStream input ) - { - int inp = input.ReadByte(); - if( inp == -1 ) - throw new InvalidDataException(); - - return (byte)inp; - } - - static int ReadWord( MemoryStream input ) - { - int inp = ReadByte( input ); - return inp + ( ReadByte( input ) << 8 ); - } - static void ReplicatePrevious( byte[] dest, int destIndex, int srcIndex, int count ) { if( srcIndex >= destIndex ) @@ -39,16 +49,18 @@ namespace OpenRa.FileFormats } } - public static int DecodeInto( MemoryStream input, byte[] dest ) + public static int DecodeInto( byte[] src, byte[] dest ) { + var ctx = new FastByteReader(src); int destIndex = 0; + while( true ) { - byte i = ReadByte( input ); + byte i = ctx.ReadByte(); if( ( i & 0x80 ) == 0 ) { // case 2 - byte secondByte = ReadByte( input ); + byte secondByte = ctx.ReadByte(); int count = ( ( i & 0x70 ) >> 4 ) + 3; int rpos = ( ( i & 0xf ) << 8 ) + secondByte; @@ -62,7 +74,7 @@ namespace OpenRa.FileFormats if( count == 0 ) return destIndex; - input.Read( dest, destIndex, count ); + ctx.CopyTo( dest, destIndex, count ); destIndex += count; } else @@ -71,8 +83,8 @@ namespace OpenRa.FileFormats if( count3 == 0x3E ) { // case 4 - int count = ReadWord( input ); - byte color = ReadByte( input ); + int count = ctx.ReadWord(); + byte color = ctx.ReadByte(); for( int end = destIndex + count ; destIndex < end ; destIndex++ ) dest[ destIndex ] = color; @@ -80,8 +92,8 @@ namespace OpenRa.FileFormats else if( count3 == 0x3F ) { // case 5 - int count = ReadWord( input ); - int srcIndex = ReadWord( input ); + int count = ctx.ReadWord(); + int srcIndex = ctx.ReadWord(); if( srcIndex >= destIndex ) throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) ); @@ -92,7 +104,7 @@ namespace OpenRa.FileFormats { // case 3 int count = count3 + 3; - int srcIndex = ReadWord( input ); + int srcIndex = ctx.ReadWord(); if( srcIndex >= destIndex ) throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) ); diff --git a/OpenRa.FileFormats/Map.cs b/OpenRa.FileFormats/Map.cs index 35273bd443..aa6da63604 100644 --- a/OpenRa.FileFormats/Map.cs +++ b/OpenRa.FileFormats/Map.cs @@ -72,7 +72,7 @@ namespace OpenRa.FileFormats byte[] dest = new byte[8192]; byte[] src = reader.ReadBytes((int)length); - int actualLength = Format80.DecodeInto(new MemoryStream(src), dest); + int actualLength = Format80.DecodeInto(src, dest); chunks.Add(dest); } @@ -113,7 +113,7 @@ namespace OpenRa.FileFormats for( int i = 0 ; i < 128 ; i++ ) for( int j = 0 ; j < 128 ; j++ ) { - MapTiles[ j, i ].image = ReadByte( ms ); + MapTiles[j, i].image = (byte)ms.ReadByte();// ReadByte(ms); if( MapTiles[ j, i ].tile == 0xff || MapTiles[ j, i ].tile == 0xffff ) MapTiles[ j, i ].image = (byte)( i % 4 + ( j % 4 ) * 4 ); } diff --git a/OpenRa.FileFormats/ShpReader.cs b/OpenRa.FileFormats/ShpReader.cs index efbc39f1b7..dc65213bc9 100644 --- a/OpenRa.FileFormats/ShpReader.cs +++ b/OpenRa.FileFormats/ShpReader.cs @@ -109,16 +109,13 @@ namespace OpenRa.FileFormats } h.Image = CopyImageData( h.RefImage.Image ); - - MemoryStream ms = ReadCompressedData( stream, h ); - Format40.DecodeInto( ms, h.Image ); + Format40.DecodeInto(ReadCompressedData(stream, h), h.Image); break; } case Format.Format80: { - MemoryStream ms = ReadCompressedData( stream, h ); byte[] imageBytes = new byte[ Width * Height ]; - Format80.DecodeInto( ms, imageBytes ); + Format80.DecodeInto( ReadCompressedData( stream, h ), imageBytes ); h.Image = imageBytes; break; } @@ -127,7 +124,7 @@ namespace OpenRa.FileFormats } } - private static MemoryStream ReadCompressedData( Stream stream, ImageHeader h ) + static byte[] ReadCompressedData( Stream stream, ImageHeader h ) { stream.Position = h.Offset; // Actually, far too big. There's no length field with the correct length though :( @@ -136,8 +133,8 @@ namespace OpenRa.FileFormats byte[] compressedBytes = new byte[ compressedLength ]; stream.Read( compressedBytes, 0, compressedLength ); - MemoryStream ms = new MemoryStream( compressedBytes ); - return ms; + //MemoryStream ms = new MemoryStream( compressedBytes ); + return compressedBytes; } private byte[] CopyImageData( byte[] baseImage ) diff --git a/OpenRa.Game/SpriteRenderer.cs b/OpenRa.Game/SpriteRenderer.cs index 51384c0d4d..fb9d51e5da 100644 --- a/OpenRa.Game/SpriteRenderer.cs +++ b/OpenRa.Game/SpriteRenderer.cs @@ -15,18 +15,19 @@ namespace OpenRa.Game const int spritesPerBatch = 1024; - List vertices = new List(); - List indices = new List(); + Vertex[] vertices = new Vertex[4 * spritesPerBatch]; + ushort[] indices = new ushort[6 * spritesPerBatch]; Sheet currentSheet = null; int sprites = 0; ShaderQuality quality; + int nv = 0, ni = 0; public SpriteRenderer(Renderer renderer, bool allowAlpha) { this.renderer = renderer; - vertexBuffer = new FvfVertexBuffer(renderer.Device, 4 * spritesPerBatch, Vertex.Format); - indexBuffer = new IndexBuffer(renderer.Device, 6 * spritesPerBatch); + vertexBuffer = new FvfVertexBuffer(renderer.Device, vertices.Length, Vertex.Format); + indexBuffer = new IndexBuffer(renderer.Device, indices.Length); quality = allowAlpha ? ShaderQuality.High : ShaderQuality.Low; } @@ -37,16 +38,15 @@ namespace OpenRa.Game { renderer.DrawWithShader(quality, delegate { - vertexBuffer.SetData(vertices.ToArray()); - indexBuffer.SetData(indices.ToArray()); + vertexBuffer.SetData(vertices); + indexBuffer.SetData(indices); renderer.DrawBatch(vertexBuffer, indexBuffer, - new Range(0, vertices.Count), - new Range(0, indices.Count), + new Range(0, nv), + new Range(0, ni), currentSheet.Texture); }); - vertices = new List(); - indices = new List(); + nv = 0; ni = 0; currentSheet = null; sprites = 0; } @@ -58,8 +58,8 @@ namespace OpenRa.Game Flush(); currentSheet = s.sheet; - Util.CreateQuad(vertices, indices, location, s, palette); - + Util.FastCreateQuad(vertices, indices, location, s, palette, nv, ni); + nv += 4; ni += 6; if (++sprites >= spritesPerBatch) Flush(); } diff --git a/OpenRa.Game/TerrainRenderer.cs b/OpenRa.Game/TerrainRenderer.cs index 4d7fb779ca..51b6971a80 100644 --- a/OpenRa.Game/TerrainRenderer.cs +++ b/OpenRa.Game/TerrainRenderer.cs @@ -7,6 +7,7 @@ using System.Drawing; using System.IO; using System.Windows.Forms; using Ijw.DirectX; +using IjwFramework.Collections; namespace OpenRa.Game { @@ -30,33 +31,32 @@ namespace OpenRa.Game tileSet = new TileSet( map.TileSuffix ); - Dictionary tileMapping = - new Dictionary(); + Size tileSize = new Size( 24, 24 ); - Size tileSize = new Size( 24, 24 ); + var tileMapping = new Cache( + x => SheetBuilder.Add(tileSet.GetBytes(x), tileSize)); - List vertices = new List(); - List indices = new List(); + Vertex[] vertices = new Vertex[4 * map.Height * map.Width]; + ushort[] indices = new ushort[6 * map.Height * map.Width]; + int nv = 0; + int ni = 0; for( int j = 0 ; j < map.Height ; j++ ) - for( int i = 0 ; i < map.Width ; i++ ) - { - TileReference tileRef = map.MapTiles[ i + map.XOffset, j + map.YOffset ]; - Sprite tile; + for (int i = 0; i < map.Width; i++) + { + Sprite tile = tileMapping[map.MapTiles[i + map.XOffset, j + map.YOffset]]; + Util.FastCreateQuad(vertices, indices, 24 * new float2(i, j), tile, 0, nv, ni); + nv += 4; + ni += 6; + } - if( !tileMapping.TryGetValue( tileRef, out tile ) ) - tileMapping.Add( tileRef, tile = SheetBuilder.Add( tileSet.GetBytes( tileRef ), tileSize ) ); + terrainSheet = tileMapping[map.MapTiles[map.XOffset, map.YOffset]].sheet; - terrainSheet = tile.sheet; + vertexBuffer = new FvfVertexBuffer( renderer.Device, vertices.Length, Vertex.Format ); + vertexBuffer.SetData( vertices ); - Util.CreateQuad( vertices, indices, 24 * new float2( i, j ), tile, 0 ); - } - - vertexBuffer = new FvfVertexBuffer( renderer.Device, vertices.Count, Vertex.Format ); - vertexBuffer.SetData( vertices.ToArray() ); - - indexBuffer = new IndexBuffer( renderer.Device, indices.Count ); - indexBuffer.SetData( indices.ToArray() ); + indexBuffer = new IndexBuffer( renderer.Device, indices.Length ); + indexBuffer.SetData( indices ); } void Draw() diff --git a/OpenRa.Game/Util.cs b/OpenRa.Game/Util.cs index 49a2869a66..c31ef34dc3 100644 --- a/OpenRa.Game/Util.cs +++ b/OpenRa.Game/Util.cs @@ -10,13 +10,6 @@ namespace OpenRa.Game { static class Util { - static float[] channelSelect = { 0.75f, 0.25f, -0.25f, -0.75f }; - - static float2 EncodeVertexAttributes(TextureChannel channel, int paletteLine) - { - return new float2(paletteLine / 16.0f, channelSelect[(int)channel]); - } - static float2 KLerp(float2 o, float2 d, int k) { switch (k) @@ -29,14 +22,6 @@ namespace OpenRa.Game } } - static Vertex MakeVertex(float2 o, int k, Sprite r, float2 attrib) - { - return new Vertex( - KLerp( o, r.size, k ), - r.FastMapTextureCoords(k), - attrib); - } - public static string[] ReadAllLines(Stream s) { List result = new List(); @@ -56,28 +41,22 @@ namespace OpenRa.Game return result; } - public static void CreateQuad(List vertices, List indices, float2 o, Sprite r, int palette) - { - ushort offset = (ushort)vertices.Count; - float2 attrib = EncodeVertexAttributes(r.channel, palette); + static float[] channelSelect = { 0.75f, 0.25f, -0.25f, -0.75f }; - Vertex[] v = new Vertex[] - { - Util.MakeVertex(o, 0, r, attrib), - Util.MakeVertex(o, 1, r, attrib), - Util.MakeVertex(o, 2, r, attrib), - Util.MakeVertex(o, 3, r, attrib), - }; + public static void FastCreateQuad(Vertex[] vertices, ushort[] indices, float2 o, Sprite r, int palette, int nv, int ni) + { + float2 attrib = new float2(palette / 16.0f, channelSelect[(int)r.channel]); - vertices.AddRange(v); + vertices[nv] = new Vertex(KLerp(o, r.size, 0), r.FastMapTextureCoords(0), attrib); + vertices[nv + 1] = new Vertex(KLerp(o, r.size, 1), r.FastMapTextureCoords(1), attrib); + vertices[nv + 2] = new Vertex(KLerp(o, r.size, 2), r.FastMapTextureCoords(2), attrib); + vertices[nv + 3] = new Vertex(KLerp(o, r.size, 3), r.FastMapTextureCoords(3), attrib); - ushort[] i = new ushort[] - { - offset, (ushort)(offset + 1), (ushort)(offset + 2), (ushort)(offset + 1), (ushort)(offset + 3), (ushort)(offset + 2) - }; - - indices.AddRange(i); - } + indices[ni] = (ushort)(nv); + indices[ni + 1] = indices[ni + 3] = (ushort)(nv + 1); + indices[ni + 2] = indices[ni + 5] = (ushort)(nv + 2); + indices[ni + 4] = (ushort)(nv + 3); + } public static void FastCopyIntoChannel(Sprite dest, byte[] src) {