I am currently looking for performance optimizations for my game project. The bottleneck of my initialization process is loading the textures of my models. Loading and assigning a large texture takes up to 100ms. This is a problem, because I have a lot of them. I analyzed my code and found out, that most of the time (around 96%) is spent on the call of CopyPixels (see below).
I attached the function I use for importing all my textures below. This function works like a charm and is based on the official SharpDX-samples-master example codes. First, I load the image bytes from my custom file format (which takes around 2 ms for large textures). Then, I create the format converter and use it to copy the pixels to the data stream. However, copying the pixels is very slow.
Is there any faster way to achieve the same?
public static Resources.Texture ImportTexture(Resources.AResourceManager resourceManager, string resourcePackFileName, int bytePosition, out string resourceItemName)
{
// Load image bytes from file.
FileReader fileReader = new FileReader();
DataTypes.Content.ResourceItem resourceItem = fileReader.ImportTextureFromCollection(resourcePackFileName, bytePosition);
resourceItemName = resourceItem.Name;
// Create texture.
Resources.Texture tex = null;
using (SharpDX.WIC.BitmapDecoder bitmapDecoder = new SharpDX.WIC.BitmapDecoder(resourceManager.ImagingFactory, new MemoryStream(resourceItem.Data, false), SharpDX.WIC.DecodeOptions.CacheOnDemand))
{
using (SharpDX.WIC.FormatConverter formatConverter = new SharpDX.WIC.FormatConverter(resourceManager.ImagingFactory))
{
formatConverter.Initialize(bitmapDecoder.GetFrame(0), SharpDX.WIC.PixelFormat.Format32bppPRGBA, SharpDX.WIC.BitmapDitherType.None, null, 0.0, SharpDX.WIC.BitmapPaletteType.Custom);
SharpDX.DataStream dataStream = new SharpDX.DataStream(formatConverter.Size.Height * formatConverter.Size.Width * 4, true, true);
// This takes most of the time!
formatConverter.CopyPixels(formatConverter.Size.Width * 4, dataStream);
// Creating texture data structure.
tex = new Resources.Texture(formatConverter.Size.Width, formatConverter.Size.Height, formatConverter.Size.Width * 4)
{
DataStream = dataStream
};
}
}
return tex;
}
Looks like you are using bitmaps. Have you considered using DDS files instead? It supports both compressed and uncompressed formats – Asesh
Asesh was right. At first, I was sceptical, but I did some research and found an older article which states, that an average PNG texture takes less memory on hard drive than a comparable DDS texture. However, PNG textures need to be converted at run-time which is slower than using DDS textures.
I spent last night looking for proper conversion tools and after testing some stuff (like a plug-in for GIMP), I used the Compressonator from AMD to convert all my PNG textures to DDS textures. The new files take even less memory on my hard drive than the PNG files (1.7 GB instead of 2.1 GB).
My texture loading method I presented in the initial post still worked and was slightly faster. However, I decided to code a DDS importer based on several code samples I found online.
The result: A large textures takes only 1 ms instead of 103 ms to import. I think you can that an improvement. :-D
Thank you very much, Asesh!