Fastest way to programatically load a texture from a generated PNG file?

I’ve tried the FileStream trick but the call that takes all day (8 - 15 seconds) is Texture2D.FromStream()

I’ve tried others’ loaders but they are all variations of this base method so they are even slower.

The application I’m writing is mathematical and I’m generating PNG images from LaTeX input on the fly using McTeK installed “latex.exe” and “dvipng.exe” on the Path.

Generating the PNG takes aboout 2 seconds! Who’d have thought the bottleneck would be loading the PNG IMAGE!!!

My first thought is to use the Pipelining tool and cache about 5,000 LaTeX -rendered PNGs of common expressions. If the object in the scene has to wait to render, then it will display the text “rendering $\mathbb{Z}$” or something…

But that is so shitty! Please provide me with the hack that speeds up loading PNGs for textures.

Thanks.

How large are these PNG images?? I’m not seeing even CLOSE to that large of a load time on my PNGs. I’m loading PNGs with this:

    /// <summary>
    /// LoadTextureStream method to speed up loading Texture2Ds from pngs,
    /// as described in
    /// http://jakepoz.com/jake_poznanski__speeding_up_xna.html
    /// </summary>
    /// <param name="graphics">Graphics device to use</param>
    /// <param name="loc">Location of the image, root of the path is in the Content folder</param>
    /// <returns>A Texture2D with premultiplied alpha</returns>

    public static Texture2D LoadTextureStream(GraphicsDevice graphics, string loc)
    {
        Texture2D file = null;
        RenderTarget2D result = null;

        using (Stream titleStream = TitleContainer.OpenStream("Content/" + loc + ".png"))
        {
            file = Texture2D.FromStream(graphics, titleStream);
        }

        //Setup a render target to hold our final texture which will have premulitplied alpha values
        result = new RenderTarget2D(graphics, file.Width, file.Height);

        graphics.SetRenderTarget(result);
        graphics.Clear(Color.Black);

        //Multiply each color by the source alpha, and write in just the color values into the final texture
        if (_blendColor == null)
        {
            _blendColor = new BlendState();
            _blendColor.ColorWriteChannels = ColorWriteChannels.Red | ColorWriteChannels.Green | ColorWriteChannels.Blue;

            _blendColor.AlphaDestinationBlend = Blend.Zero;
            _blendColor.ColorDestinationBlend = Blend.Zero;

            _blendColor.AlphaSourceBlend = Blend.SourceAlpha;
            _blendColor.ColorSourceBlend = Blend.SourceAlpha;
        }

        SpriteBatch spriteBatch = new SpriteBatch(graphics);
        spriteBatch.Begin(SpriteSortMode.Immediate, _blendColor);
        spriteBatch.Draw(file, file.Bounds, Color.White);
        spriteBatch.End();

        //Now copy over the alpha values from the PNG source texture to the final one, without multiplying them
        if (_blendAlpha == null)
        {
            _blendAlpha = new BlendState();
            _blendAlpha.ColorWriteChannels = ColorWriteChannels.Alpha;

            _blendAlpha.AlphaDestinationBlend = Blend.Zero;
            _blendAlpha.ColorDestinationBlend = Blend.Zero;

            _blendAlpha.AlphaSourceBlend = Blend.One;
            _blendAlpha.ColorSourceBlend = Blend.One;
        }

        spriteBatch.Begin(SpriteSortMode.Immediate, _blendAlpha);
        spriteBatch.Draw(file, file.Bounds, Color.White);
        spriteBatch.End();

        //Release the GPU back to drawing to the screen
        graphics.SetRenderTarget(null);

        return result as Texture2D;
    }

Maybe that will help? It’s also using Texture2D.FromStream however.

Yes that still takes 10 seconds to run.

How large are your textures, and which version of MonoGame are you on?

8KB pngs. They are just small images no more than 2000 x 1000 pixels but probably smaller.

Version of MonoGame? The latest release version. Installed just 2 days ago.

Can you test how fast it is with v3.6?
For a long term solution you can use the old MG code before PR #6008 and then create the textures from the bitmap.
However that code is platform specific.

Most likely the problem is not on MG’s end content loading but from your PNG generation, you are right that a 2000x1000 roughly 8KB on disk size and with a compiled PNG file, the size will be much bigger than the original file but it will be loaded much faster no decompression needed when loading internally. It’s a misnomer that loading a PNG file using stream is much faster than compiled PNG texture.

Loading time for stream loading around : 140 - 150 (Ms) Milliseconds
Loading time for compiled loading around : 12 - 18 (Ms) Milliseconds

If you share some of your PNG file, people here might test it and the result will be no different from the above or probably much faster ^_^y