Use Marshal.Copy for faster array copying.

- Rewrite several methods to use Marshal.Copy to copy data faster and more succinctly compared to doing it manually.
- Rewrite Sheet.AsBitmap(TextureChannel, Palette) with a faster and more self descriptive loop.
This commit is contained in:
RoosterDragon
2014-06-11 00:07:04 +01:00
parent e347cdfb32
commit 4ce8a4a648
2 changed files with 46 additions and 81 deletions

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -11,7 +11,7 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using OpenRA.FileFormats; using System.Runtime.InteropServices;
using OpenRA.FileSystem; using OpenRA.FileSystem;
namespace OpenRA.Graphics namespace OpenRA.Graphics
@@ -20,7 +20,7 @@ namespace OpenRA.Graphics
{ {
ITexture texture; ITexture texture;
bool dirty; bool dirty;
byte[] data; readonly byte[] data;
readonly object dirtyLock = new object(); readonly object dirtyLock = new object();
public readonly Size Size; public readonly Size Size;
@@ -29,7 +29,7 @@ namespace OpenRA.Graphics
public Sheet(Size size) public Sheet(Size size)
{ {
Size = size; Size = size;
data = new byte[4*Size.Width*Size.Height]; data = new byte[4 * Size.Width * Size.Height];
} }
public Sheet(ITexture texture) public Sheet(ITexture texture)
@@ -45,28 +45,14 @@ namespace OpenRA.Graphics
{ {
Size = bitmap.Size; Size = bitmap.Size;
data = new byte[4 * Size.Width * Size.Height]; var dataStride = 4 * Size.Width;
var b = bitmap.LockBits(bitmap.Bounds(), data = new byte[dataStride * Size.Height];
var bd = bitmap.LockBits(bitmap.Bounds(),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* c = (int*)b.Scan0;
for (var x = 0; x < Size.Width; x++)
for (var y = 0; y < Size.Height; y++) for (var y = 0; y < Size.Height; y++)
{ Marshal.Copy(IntPtr.Add(bd.Scan0, y * bd.Stride), data, y * dataStride, dataStride);
var i = 4 * Size.Width * y + 4 * x; bitmap.UnlockBits(bd);
// Convert argb to bgra
var argb = *(c + (y * b.Stride >> 2) + x);
data[i++] = (byte)(argb >> 0);
data[i++] = (byte)(argb >> 8);
data[i++] = (byte)(argb >> 16);
data[i++] = (byte)(argb >> 24);
}
}
bitmap.UnlockBits(b);
} }
} }
@@ -98,50 +84,44 @@ namespace OpenRA.Graphics
public Bitmap AsBitmap() public Bitmap AsBitmap()
{ {
var d = Data; var d = Data;
var b = new Bitmap(Size.Width, Size.Height); var dataStride = 4 * Size.Width;
var output = b.LockBits(new Rectangle(0, 0, Size.Width, Size.Height), var bitmap = new Bitmap(Size.Width, Size.Height);
var bd = bitmap.LockBits(bitmap.Bounds(),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* c = (int*)output.Scan0;
for (var x = 0; x < Size.Width; x++)
for (var y = 0; y < Size.Height; y++) for (var y = 0; y < Size.Height; y++)
{ Marshal.Copy(d, y * dataStride, IntPtr.Add(bd.Scan0, y * bd.Stride), dataStride);
var i = 4*Size.Width*y + 4*x; bitmap.UnlockBits(bd);
// Convert bgra to argb return bitmap;
var argb = (d[i+3] << 24) | (d[i+2] << 16) | (d[i+1] << 8) | d[i];
*(c + (y * output.Stride >> 2) + x) = argb;
}
}
b.UnlockBits(output);
return b;
} }
public Bitmap AsBitmap(TextureChannel channel, Palette pal) public Bitmap AsBitmap(TextureChannel channel, Palette pal)
{ {
var d = Data; var d = Data;
var b = new Bitmap(Size.Width, Size.Height); var dataStride = 4 * Size.Width;
var output = b.LockBits(new Rectangle(0, 0, Size.Width, Size.Height), var bitmap = new Bitmap(Size.Width, Size.Height);
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); var channelOffset = (int)channel;
var bd = bitmap.LockBits(bitmap.Bounds(),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe unsafe
{ {
int* c = (int*)output.Scan0; var colors = (uint*)bd.Scan0;
for (var x = 0; x < Size.Width; x++)
for (var y = 0; y < Size.Height; y++) for (var y = 0; y < Size.Height; y++)
{ {
var index = d[4*Size.Width*y + 4*x + (int)channel]; var dataRowIndex = y * dataStride + channelOffset;
*(c + (y * output.Stride >> 2) + x) = pal.GetColor(index).ToArgb(); var bdRowIndex = y * bd.Stride / 4;
for (var x = 0; x < Size.Width; x++)
{
var paletteIndex = d[dataRowIndex + 4 * x];
colors[bdRowIndex + x] = pal.Values[paletteIndex];
} }
} }
b.UnlockBits(output); }
bitmap.UnlockBits(bd);
return b; return bitmap;
} }
public void CommitData() public void CommitData()
@@ -150,9 +130,7 @@ namespace OpenRA.Graphics
throw new InvalidOperationException("Texture-wrappers are read-only"); throw new InvalidOperationException("Texture-wrappers are read-only");
lock (dirtyLock) lock (dirtyLock)
{
dirty = true; dirty = true;
} }
} }
}
} }

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -11,6 +11,7 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace OpenRA.Graphics namespace OpenRA.Graphics
{ {
@@ -62,32 +63,18 @@ namespace OpenRA.Graphics
public static void FastCopyIntoSprite(Sprite dest, Bitmap src) public static void FastCopyIntoSprite(Sprite dest, Bitmap src)
{ {
var destStride = dest.sheet.Size.Width; var data = dest.sheet.Data;
var width = dest.bounds.Width; var dataStride = dest.sheet.Size.Width * 4;
var x = dest.bounds.Left * 4;
var width = dest.bounds.Width * 4;
var y = dest.bounds.Top;
var height = dest.bounds.Height; var height = dest.bounds.Height;
var srcData = src.LockBits(src.Bounds(), var bd = src.LockBits(src.Bounds(),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
for (var row = 0; row < height; row++)
unsafe Marshal.Copy(IntPtr.Add(bd.Scan0, row * bd.Stride), data, (y + row) * dataStride + x, width);
{ src.UnlockBits(bd);
var c = (int*)srcData.Scan0;
// Cast the data to an int array so we can copy the src data directly
fixed (byte* bd = &dest.sheet.Data[0])
{
var data = (int*)bd;
var x = dest.bounds.Left;
var y = dest.bounds.Top;
for (var j = 0; j < height; j++)
for (var i = 0; i < width; i++)
data[(y + j) * destStride + x + i] = *(c + (j * srcData.Stride >> 2) + i);
}
}
src.UnlockBits(srcData);
} }
public static float[] IdentityMatrix() public static float[] IdentityMatrix()