1

I have in my application a 3D world and data for this 3D world. The UI around the application is done with WPF and so far it seems to be working ok. But now I am implementing the following functionality: If you click on the terrain in the 3D view it will show the textures used in this chunk of terrain in a WPF control. The image data of the textures is compressed (S3TC) and I handle creation of BGRA8 data in a separate thread. Once its ready I'm using the main windows dispatcher to do the WPF related tasks. Now to show you this in code:

foreach (var pair in loadTasks)
{
    var img = pair.Item2;
    var loadInfo = TextureLoader.LoadToArgbImage(pair.Item1);
    if (loadInfo == null)
        continue;

    EditorWindowController.Instance.WindowDispatcher.BeginInvoke(new Action(img =>
    {
        var watch = Stopwatch.StartNew();
        var source = BitmapSource.Create(loadInfo.Width, loadInfo.Height, 96, 96, PixelFormats.Bgra32,
                        null,
                        loadInfo.Layers[0], loadInfo.Width * 4);
        watch.Stop();
        img.Source = source;
        Log.Debug(watch.ElapsedMilliseconds);
    }));
}

While I cant argue with the visual output there is a weird performance issue. As you can see I have added a stopwatch to check where the time is consumed and I found the culprit: BitmapSource.Create.

Typically I have 5-6 elemets in loadTasks and the images are 256x256 pixels. Interestingly now the first invocation shows 280-285ms for BitmapSource.Create. The next 4-5 all are below 1ms. This consistently happens every time I click the terrain and the loop is started. The only way to avoid the penalty in the first element is to click on the terrain constantly but as soon as I don't click the terrain (and therefore do not invoke the code above) for 1-2 seconds the next call to BitmapSource.Create gets the 280ms penalty again.

Since anything above 5ms is far beyond any reasonable or acceptable time to create 256x256 bitmap (my S3TC decompression does all 10(!) mip layers in less than 2 ms) I guess there has to be something else going on here?

FYI: All properties of loadInfo are static properties and do not perform any calculations you cant see in the code.

Cromon
  • 821
  • 10
  • 24
  • First check if this does happen when you use byte array instead of loadInfo.Layers[0] IntPtr. – Dusan Feb 25 '15 at 12:32
  • Or check if switching to WriteableBitmap resolves issue: http://stackoverflow.com/questions/16220472/how-to-create-a-bitmapimage-from-a-pixel-byte-array-live-video-display – Dusan Feb 25 '15 at 12:35
  • I am currently a bit confused. When i create a minimal example that just creates a WriteableBitmap (only the constructor, no data is set) it uses 13ms, when i do it in my application outside my 3d render loop it uses 0 ms, when i do it in the function that handles the clicks it uses 280ms, if i do it in method that is above that in the callstack it uses 3ms. Im investigating this a bit more until i figure out what exactly is going on here and then edit my posting accordingly. – Cromon Feb 25 '15 at 13:19
  • You can use ILSpy tool (which is free) and examine source code of BitmapSource.Create and see what is going on under the hood. Probably some synchronization penalty. – Dusan Feb 25 '15 at 13:23
  • I did this and came to the conclusion that the only real work is done in the native function `MILSwDoubleBufferedBitmapCreate`. Also my investigations showed that its not important where I create the source but when I do so. The method above runs perfectly fine when the workload for the 3d renderer is little, when i render my world (in both cases its running at 60 Fps) it starts this madness with 300ms once every while. Its not related to the time used but to the fact that there is a 3d renderer present, i could verify that in a different application that uses the same layout but instead of – Cromon Feb 25 '15 at 14:53
  • rendering it just does a Thread.Sleep(16). Anyway, im now using a WindowsFormsHost that holds a PictureBox and use a System.Drawing.Bitmap and the world is ok now. It seems extremely wasteful and overcomplicated but at least it doesnt halt for half a second everytime i click my terrain... – Cromon Feb 25 '15 at 14:54

0 Answers0