SaveAsPng doesn´t work on iOS

Hi there,

i have a problem with SaveAsPng, which works on Android, Windows Phone, Windows but not on iOS. As soon as I call it, update and draw will still be called but the screen doesn´t refresh anymore.
I wrote a testproject to show the error. All it does is to change the color of the screen and as soon as you hit the screen (or click the mouse on the emulator) it writes the png-file and doesn´t refresh the screen anymore. What´s interesting is that the file is written correctly:

 public class Game1 : Game
 {
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Random rand;
    Texture2D mSpritePNGTest;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        graphics.IsFullScreen = true;
    }

    /// <summary>
    /// Allows the game to perform any initialization it needs to before starting to run.
    /// This is where it can query for any required services and load any non-graphic
    /// related content.  Calling base.Initialize will enumerate through any components
    /// and initialize them as well.
    /// </summary>
    protected override void Initialize()
    {
        // TODO: Add your initialization logic here
        rand = new Random();
        base.Initialize();
        mSpritePNGTest = new Texture2D(GraphicsDevice, 10, 10, false, SurfaceFormat.Color);
        mSpritePNGTest.SetData(new[] { Color.White });

    }

    /// <summary>
    /// LoadContent will be called once per game and is the place to load
    /// all of your content.
    /// </summary>
    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);

        //TODO: Use Content to load your game content here 
    }

    /// <summary>
    /// Allows the game to run logic such as updating the world,
    /// checking for collisions, gathering input, and playing audio.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Update(GameTime gameTime)
    {
        // For Mobile devices, this logic will close the Game when the Back button is pressed.
        // Exit() is obsolete on iOS
        TouchCollection touches = TouchPanel.GetState();

        foreach (TouchLocation location in touches)
        {
           if (location.State== TouchLocationState.Pressed) writeTextureAsync();                
        }


        // TODO: Add your update logic here            

        base.Update(gameTime);
    }

    async void writeTextureAsync()
    {
        IFolder rootFolder = FileSystem.Current.LocalStorage;
        await rootFolder.CreateFileAsync("test.png", CreationCollisionOption.ReplaceExisting);
        IFile file = await rootFolder.GetFileAsync("test.png");
        using (Stream stream = await file.OpenAsync(PCLStorage.FileAccess.ReadAndWrite))
        {
          
            mSpritePNGTest.SaveAsPng(stream, mSpritePNGTest.Width, mSpritePNGTest.Height);
            stream.Dispose();
        }
    }

    /// <summary>
    /// This is called when the game should draw itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Draw(GameTime gameTime)
    {
        if (rand.Next(2) <1) graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
        else graphics.GraphicsDevice.Clear(Color.Red);

        //TODO: Add your drawing code here

        base.Draw(gameTime);
    }
}

Does anybody know if that´s a bug in Monogame?

Thank you,

Harry

I checked a little bit further and discovered that GetData from Texture2D is the problem.
If you execute something like this the screen will freeze:

  private void GetColorData(Texture2D texture2D)
    {
        int colorDataLength = texture2D.Width * texture2D.Height;
        Color[]  colorData = new Color[colorDataLength];

        texture2D.GetData<Color>(colorData);
    }

GetData consists of some OpenGL specific code but it seems to be the same as on Android (where GetData works).
So I don´t really know what to do now?
Did anybody encounter that also and maybe even found a fix?

Thanks,

Harry

OpenGL ES 1 and 2 were never intended to support getting data back from GPU resources. Any implementation of Texture2D.GetData on these platforms is a hack.

Thank you KonajuGames.
That´s probably why it´s working on Android (at least the few devices I tested it on) and doesn´t work on iOS as the Implementations are probably different.
What I’m trying to do is that I want to save the current levelmap (of a 2D Jump’n’run) as thumbnail as PNG-File that can be shown when you are loading the level later on.
I´m kinda out of any ideas now. The only alternatives that comes to my mind is that I´m trying to write the tiles (that make up the level) to a Color[]-Array and save them to PNG without doing that extra-step via GetData. But to do that I would have to implement all the Draw-stuff to a Color[] structure myself including loading the tiles from png :frowning:
Can anybody else think of an alternative for that? The speed doesn´t matter. It can be awfully slow.

Thanks,

Harry

I found a solution for the problem:


If you build your own version of Monogame and just insert PlatformGetData and GetTextureData from the above link it should work.
That works at least in my game (so far tested on an iPad Pro and an iPhone 6).