diff --git a/src/Graphics/IGLDevice.cs b/src/Graphics/IGLDevice.cs index 9715ca3..3d7559d 100644 --- a/src/Graphics/IGLDevice.cs +++ b/src/Graphics/IGLDevice.cs @@ -219,29 +219,31 @@ namespace Microsoft.Xna.Framework.Graphics int elementSizeInBytes ); void SetTextureData2DPointer(Texture2D texture, IntPtr ptr); - void GetTextureData2D( + void GetTextureData2D( IGLTexture texture, SurfaceFormat format, int width, int height, int level, Rectangle? rect, - T[] data, + IntPtr data, int startIndex, - int elementCount - ) where T : struct; - // void GetTextureData3D(); - void GetTextureDataCube( + int elementCount, + int elementSizeInBytes + ); + // void GetTextureData3D(); + void GetTextureDataCube( IGLTexture texture, SurfaceFormat format, int size, CubeMapFace cubeMapFace, int level, Rectangle? rect, - T[] data, + IntPtr data, int startIndex, - int elementCount - ) where T : struct; + int elementCount, + int elementSizeInBytes + ); IGLRenderbuffer GenRenderbuffer( int width, diff --git a/src/Graphics/OpenGLDevice.cs b/src/Graphics/OpenGLDevice.cs index ea3b4bd..da0f981 100644 --- a/src/Graphics/OpenGLDevice.cs +++ b/src/Graphics/OpenGLDevice.cs @@ -2799,17 +2799,18 @@ namespace Microsoft.Xna.Framework.Graphics #region glGetTexImage Methods - public void GetTextureData2D( + public void GetTextureData2D( IGLTexture texture, SurfaceFormat format, int width, int height, int level, Rectangle? rect, - T[] data, + IntPtr data, int startIndex, - int elementCount - ) where T : struct { + int elementCount, + int elementSizeInBytes + ) { #if !DISABLE_THREADING ForceToMainThread(() => { #endif @@ -2834,41 +2835,25 @@ namespace Microsoft.Xna.Framework.Graphics else if (rect == null) { // Just throw the whole texture into the user array. - GCHandle ptr = GCHandle.Alloc(data, GCHandleType.Pinned); - try - { - glGetTexImage( - GLenum.GL_TEXTURE_2D, - 0, - glFormat, - XNAToGL.TextureDataType[(int) format], - ptr.AddrOfPinnedObject() - ); - } - finally - { - ptr.Free(); - } + glGetTexImage( + GLenum.GL_TEXTURE_2D, + 0, + glFormat, + XNAToGL.TextureDataType[(int) format], + data + ); } else { // Get the whole texture... - T[] texData = new T[width * height]; - GCHandle ptr = GCHandle.Alloc(texData, GCHandleType.Pinned); - try - { - glGetTexImage( - GLenum.GL_TEXTURE_2D, - 0, - glFormat, - XNAToGL.TextureDataType[(int) format], - ptr.AddrOfPinnedObject() - ); - } - finally - { - ptr.Free(); - } + IntPtr texData = Marshal.AllocHGlobal(width * height * elementSizeInBytes); + glGetTexImage( + GLenum.GL_TEXTURE_2D, + 0, + glFormat, + XNAToGL.TextureDataType[(int) format], + texData + ); // Now, blit the rect region into the user array. Rectangle region = rect.Value; @@ -2888,9 +2873,15 @@ namespace Microsoft.Xna.Framework.Graphics // If we're past the end, we're done! return; } - data[curPixel - startIndex] = texData[(row * width) + col]; + // FIXME: Can we copy via pitch instead, or something? -flibit + memcpy( + data + ((curPixel - startIndex) * elementSizeInBytes), + texData + (((row * width) + col) * elementSizeInBytes), + (IntPtr) elementSizeInBytes + ); } } + Marshal.FreeHGlobal(texData); } #if !DISABLE_THREADING @@ -2898,17 +2889,18 @@ namespace Microsoft.Xna.Framework.Graphics #endif } - public void GetTextureDataCube( + public void GetTextureDataCube( IGLTexture texture, SurfaceFormat format, int size, CubeMapFace cubeMapFace, int level, Rectangle? rect, - T[] data, + IntPtr data, int startIndex, - int elementCount - ) where T : struct { + int elementCount, + int elementSizeInBytes + ) { #if !DISABLE_THREADING ForceToMainThread(() => { #endif @@ -2922,41 +2914,25 @@ namespace Microsoft.Xna.Framework.Graphics else if (rect == null) { // Just throw the whole texture into the user array. - GCHandle ptr = GCHandle.Alloc(data, GCHandleType.Pinned); - try - { - glGetTexImage( - GLenum.GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int) cubeMapFace, - 0, - glFormat, - XNAToGL.TextureDataType[(int) format], - ptr.AddrOfPinnedObject() - ); - } - finally - { - ptr.Free(); - } + glGetTexImage( + GLenum.GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int) cubeMapFace, + 0, + glFormat, + XNAToGL.TextureDataType[(int) format], + data + ); } else { // Get the whole texture... - T[] texData = new T[size * size]; - GCHandle ptr = GCHandle.Alloc(texData, GCHandleType.Pinned); - try - { - glGetTexImage( - GLenum.GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int) cubeMapFace, - 0, - glFormat, - XNAToGL.TextureDataType[(int) format], - ptr.AddrOfPinnedObject() - ); - } - finally - { - ptr.Free(); - } + IntPtr texData = Marshal.AllocHGlobal(size * size * elementSizeInBytes); + glGetTexImage( + GLenum.GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int) cubeMapFace, + 0, + glFormat, + XNAToGL.TextureDataType[(int) format], + texData + ); // Now, blit the rect region into the user array. Rectangle region = rect.Value; @@ -2976,9 +2952,15 @@ namespace Microsoft.Xna.Framework.Graphics // If we're past the end, we're done! return; } - data[curPixel - startIndex] = texData[(row * size) + col]; + // FIXME: Can we copy via pitch instead, or something? -flibit + memcpy( + data + ((curPixel - startIndex) * elementSizeInBytes), + texData + (((row * size) + col) * elementSizeInBytes), + (IntPtr) elementSizeInBytes + ); } } + Marshal.FreeHGlobal(texData); } #if !DISABLE_THREADING @@ -3119,14 +3101,14 @@ namespace Microsoft.Xna.Framework.Graphics /// The texture data array /// The portion of the image to read from /// True if we successfully read the texture data - private bool ReadTargetIfApplicable( + private bool ReadTargetIfApplicable( IGLTexture texture, int width, int height, int level, - T[] data, + IntPtr data, Rectangle? rect - ) where T : struct { + ) { bool texUnbound = ( currentDrawBuffers != 1 || currentAttachments[0] != (texture as OpenGLTexture).Handle ); if (texUnbound && !useES2) @@ -3174,23 +3156,15 @@ namespace Microsoft.Xna.Framework.Graphics /* glReadPixels should be faster than reading * back from the render target if we are already bound. */ - GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); - try - { - glReadPixels( - x, - y, - w, - h, - GLenum.GL_RGBA, // FIXME: Assumption! - GLenum.GL_UNSIGNED_BYTE, - handle.AddrOfPinnedObject() - ); - } - finally - { - handle.Free(); - } + glReadPixels( + x, + y, + w, + h, + GLenum.GL_RGBA, // FIXME: Assumption! + GLenum.GL_UNSIGNED_BYTE, + data + ); if (texUnbound) { diff --git a/src/Graphics/Texture2D.cs b/src/Graphics/Texture2D.cs index 51dcb12..9cb68a2 100644 --- a/src/Graphics/Texture2D.cs +++ b/src/Graphics/Texture2D.cs @@ -204,6 +204,7 @@ namespace Microsoft.Xna.Framework.Graphics ); } + GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); GraphicsDevice.GLDevice.GetTextureData2D( texture, Format, @@ -211,10 +212,12 @@ namespace Microsoft.Xna.Framework.Graphics Height, level, rect, - data, + handle.AddrOfPinnedObject(), startIndex, - elementCount + elementCount, + Marshal.SizeOf(typeof(T)) ); + handle.Free(); } #endregion diff --git a/src/Graphics/TextureCube.cs b/src/Graphics/TextureCube.cs index 95b26c2..201e6db 100644 --- a/src/Graphics/TextureCube.cs +++ b/src/Graphics/TextureCube.cs @@ -190,6 +190,7 @@ namespace Microsoft.Xna.Framework.Graphics ); } + GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); GraphicsDevice.GLDevice.GetTextureDataCube( texture, Format, @@ -197,10 +198,12 @@ namespace Microsoft.Xna.Framework.Graphics cubeMapFace, level, rect, - data, + handle.AddrOfPinnedObject(), startIndex, - elementCount + elementCount, + Marshal.SizeOf(typeof(T)) ); + handle.Free(); } #endregion