Improved efficiency of startup methods.
- ShpReader will copy the input stream into memory just once rather than for every header. - ShpReader.CopyImageData switched to use Array.Copy since that uses some unsafe magic for speed. - In ActorInfo, cache a GetType call and prevent needless materialization in PrerequisitesOf. - In ObjectCreator, cache type and ctor lookups since these are expensive and often repeated. - Implement IReadOnlyDictionary<T, U> on Cache<T, U> to provide some supplementary functions. - In TechTree.GatherOwnedPrerequisites, rearrange a Boolean 'and' expression to evaluate expensive functions later in the chain, and use ContainsKey to speed up name check.
This commit is contained in:
@@ -12,58 +12,58 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public static class Format40
|
||||
{
|
||||
public static int DecodeInto( byte[] src, byte[] dest )
|
||||
public static int DecodeInto(byte[] src, byte[] dest, int srcOffset)
|
||||
{
|
||||
var ctx = new FastByteReader(src);
|
||||
var ctx = new FastByteReader(src, srcOffset);
|
||||
int destIndex = 0;
|
||||
|
||||
while( true )
|
||||
while (true)
|
||||
{
|
||||
byte i = ctx.ReadByte();
|
||||
if( ( i & 0x80 ) == 0 )
|
||||
if ((i & 0x80) == 0)
|
||||
{
|
||||
int count = i & 0x7F;
|
||||
if( count == 0 )
|
||||
if (count == 0)
|
||||
{
|
||||
// case 6
|
||||
count = ctx.ReadByte();
|
||||
byte value = ctx.ReadByte();
|
||||
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
|
||||
dest[ destIndex ] ^= value;
|
||||
for (int end = destIndex + count; destIndex < end; destIndex++)
|
||||
dest[destIndex] ^= value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// case 5
|
||||
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
|
||||
for (int end = destIndex + count; destIndex < end; destIndex++)
|
||||
dest[destIndex] ^= ctx.ReadByte();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int count = i & 0x7F;
|
||||
if( count == 0 )
|
||||
if (count == 0)
|
||||
{
|
||||
count = ctx.ReadWord();
|
||||
if( count == 0 )
|
||||
if (count == 0)
|
||||
return destIndex;
|
||||
|
||||
if( ( count & 0x8000 ) == 0 )
|
||||
if ((count & 0x8000) == 0)
|
||||
{
|
||||
// case 2
|
||||
destIndex += ( count & 0x7FFF );
|
||||
destIndex += (count & 0x7FFF);
|
||||
}
|
||||
else if( ( count & 0x4000 ) == 0 )
|
||||
else if ((count & 0x4000) == 0)
|
||||
{
|
||||
// case 3
|
||||
for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ )
|
||||
for (int end = destIndex + (count & 0x3FFF); destIndex < end; destIndex++)
|
||||
dest[destIndex] ^= ctx.ReadByte();
|
||||
}
|
||||
else
|
||||
{
|
||||
// case 4
|
||||
byte value = ctx.ReadByte();
|
||||
for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ )
|
||||
dest[ destIndex ] ^= value;
|
||||
for (int end = destIndex + (count & 0x3FFF); destIndex < end; destIndex++)
|
||||
dest[destIndex] ^= value;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -16,11 +16,12 @@ namespace OpenRA.FileFormats
|
||||
class FastByteReader
|
||||
{
|
||||
readonly byte[] src;
|
||||
int offset = 0;
|
||||
int offset;
|
||||
|
||||
public FastByteReader(byte[] src)
|
||||
public FastByteReader(byte[] src, int offset = 0)
|
||||
{
|
||||
this.src = src;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public bool Done() { return offset >= src.Length; }
|
||||
@@ -59,9 +60,9 @@ namespace OpenRA.FileFormats
|
||||
}
|
||||
}
|
||||
|
||||
public static int DecodeInto(byte[] src, byte[] dest)
|
||||
public static int DecodeInto(byte[] src, byte[] dest, int srcOffset = 0)
|
||||
{
|
||||
var ctx = new FastByteReader(src);
|
||||
var ctx = new FastByteReader(src, srcOffset);
|
||||
var destIndex = 0;
|
||||
|
||||
while (true)
|
||||
|
||||
@@ -67,6 +67,9 @@ namespace OpenRA.FileFormats
|
||||
int recurseDepth = 0;
|
||||
readonly int imageCount;
|
||||
|
||||
readonly long shpBytesFileOffset;
|
||||
readonly byte[] shpBytes;
|
||||
|
||||
public ShpReader(Stream stream)
|
||||
{
|
||||
imageCount = stream.ReadUInt16();
|
||||
@@ -93,22 +96,16 @@ namespace OpenRA.FileFormats
|
||||
throw new InvalidDataException("Reference doesnt point to image data {0}->{1}".F(h.FileOffset, h.RefOffset));
|
||||
}
|
||||
|
||||
shpBytesFileOffset = stream.Position;
|
||||
shpBytes = stream.ReadBytes((int)(stream.Length - stream.Position));
|
||||
|
||||
foreach (var h in headers)
|
||||
Decompress(stream, h);
|
||||
Decompress(h);
|
||||
|
||||
spriteFrames = Exts.Lazy(() => headers.Cast<ISpriteFrame>());
|
||||
}
|
||||
|
||||
static byte[] ReadCompressedData(Stream stream, ImageHeader h)
|
||||
{
|
||||
stream.Position = h.FileOffset;
|
||||
|
||||
// Actually, far too big. There's no length field with the correct length though :(
|
||||
var compressedLength = (int)(stream.Length - stream.Position);
|
||||
return stream.ReadBytes(compressedLength);
|
||||
}
|
||||
|
||||
void Decompress(Stream stream, ImageHeader h)
|
||||
void Decompress(ImageHeader h)
|
||||
{
|
||||
// No extra work is required for empty frames
|
||||
if (h.Size.Width == 0 || h.Size.Height == 0)
|
||||
@@ -125,19 +122,19 @@ namespace OpenRA.FileFormats
|
||||
if (h.RefImage.Data == null)
|
||||
{
|
||||
++recurseDepth;
|
||||
Decompress(stream, h.RefImage);
|
||||
Decompress(h.RefImage);
|
||||
--recurseDepth;
|
||||
}
|
||||
|
||||
h.Data = CopyImageData(h.RefImage.Data);
|
||||
Format40.DecodeInto(ReadCompressedData(stream, h), h.Data);
|
||||
Format40.DecodeInto(shpBytes, h.Data, (int)(h.FileOffset - shpBytesFileOffset));
|
||||
break;
|
||||
}
|
||||
|
||||
case Format.Format80:
|
||||
{
|
||||
var imageBytes = new byte[Size.Width * Size.Height];
|
||||
Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes);
|
||||
Format80.DecodeInto(shpBytes, imageBytes, (int)(h.FileOffset - shpBytesFileOffset));
|
||||
h.Data = imageBytes;
|
||||
break;
|
||||
}
|
||||
@@ -150,9 +147,7 @@ namespace OpenRA.FileFormats
|
||||
byte[] CopyImageData(byte[] baseImage)
|
||||
{
|
||||
var imageData = new byte[Size.Width * Size.Height];
|
||||
for (var i = 0; i < Size.Width * Size.Height; i++)
|
||||
imageData[i] = baseImage[i];
|
||||
|
||||
Array.Copy(baseImage, imageData, imageData.Length);
|
||||
return imageData;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user