MonoGame Android 3.7.0.1708 : Texture2D.GetData corrupts the Texture2D object being read

Created on 19 Oct 2018  路  6Comments  路  Source: MonoGame/MonoGame

I've been using CocosSharp successfully with Monogame 3.6. However, when upgrading to 3.7 (or the latest 3.8 dev build), the following code is now corrupting loaded texture data

var b = new Color[rt.Texture.PixelsHigh * rt.Texture.PixelsWide]; rt.Texture.XNATexture.GetData<Color>(b);

It appears, rather than just reading out the data, to completely overwrite the texture with a section from a corner of the current screen.

To emphasise: this isn't just a case of it returning the wrong data. The texture being read becomes corrupted and overwritten entirely.

It seems the actual data being returned is correct. However, calling SetData on the texture straight afterwards has no effect.

What version of MonoGame does the bug occur on:

  • MonoGame.Framework.Android 3.7.0.1708

What operating system are you using:

  • MacOS Mojave 10.14

What MonoGame platform are you using:

  • Android
Android Help Wanted

Most helpful comment

I've reproduced this issue with android emulator and looked into it a bit.
It seems this line is the one to blame:
https://github.com/MonoGame/MonoGame/blob/142ea8393e5e316ad88c5ed9a7c40554a02d9e64/MonoGame.Framework/Graphics/Texture2D.OpenGL.cs#L213

If it is replaced with
C# GL.DeleteFramebuffers(1, ref framebufferId);
then everything works fine and texture isnt corrupted by GetData call.

All 6 comments

I can confirm that this occurs on iOS as well.

Having same issue here using vanilla Monogame Android project, nothing else. Calling someTexture.GetData(...)

For clarity, although #6727 was closed, the root issue turned out to be simply reading from the texture on Android caused the source texture to disappear. It's possible in the case of this "disappearing" to actually be a copy of the corner of the screen, as detailed on this Issue number (6506).

I've a possible work-around for the moment.
In my case, I'm processing a PNG just loaded, in preparation for use - so in my case, a one liner of inconvenience:

img = new Texture2D(graphicsDevice, img.Width, img.Height); img.SetData<Color>(colourData);

where img is a Texture2D that you've just called the "img.GetData(colorsArray);" method on.

Put simply, if the texture is corrupted, then create a new texture! You've got the Color[] data to do so, and the original texture can tell you the width and height the replacement texture needs to be.

This one line (in the right place) got my code working - until there's an official fix.

I've reproduced this issue with android emulator and looked into it a bit.
It seems this line is the one to blame:
https://github.com/MonoGame/MonoGame/blob/142ea8393e5e316ad88c5ed9a7c40554a02d9e64/MonoGame.Framework/Graphics/Texture2D.OpenGL.cs#L213

If it is replaced with
C# GL.DeleteFramebuffers(1, ref framebufferId);
then everything works fine and texture isnt corrupted by GetData call.

On a glance, the difference between deleting the frame buffer and disposing the frame buffer is that the former is immediate, whereas disposal is delayed to the next frame.

So deleting will detach the frame buffer from the texture immediately. However, since glReadPixels is synchronous (as per the spec) it is unclear why an operation AFTER it would affect client memory.

Perhaps the GLES implementation is doing some trickery and using a pixel buffer object under the hood?

Attaching a texture to a frame buffer won't work properly if the texture was not bound yet at some point. I haven't gone and traced this, but it looks like the Monogame implementation would have bound it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SenpaiSharp picture SenpaiSharp  路  3Comments

NET-D3v3l0p3r picture NET-D3v3l0p3r  路  3Comments

willmotil picture willmotil  路  5Comments

Grabiobot picture Grabiobot  路  5Comments

griseus picture griseus  路  5Comments