diff --git a/src/Audio/DynamicSoundEffectInstance.cs b/src/Audio/DynamicSoundEffectInstance.cs index e34ab44..8ddea37 100644 --- a/src/Audio/DynamicSoundEffectInstance.cs +++ b/src/Audio/DynamicSoundEffectInstance.cs @@ -10,6 +10,7 @@ #region Using Statements using System; using System.Collections.Generic; +using System.Runtime.InteropServices; #endregion namespace Microsoft.Xna.Framework.Audio @@ -160,14 +161,16 @@ namespace Microsoft.Xna.Framework.Audio // Push the data to OpenAL. IALBuffer newBuf = availableBuffers.Dequeue(); + GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); AudioDevice.ALDevice.SetBufferData( newBuf, channels, - buffer, + handle.AddrOfPinnedObject(), offset, count, sampleRate ); + handle.Free(); // If we're already playing, queue immediately. if (INTERNAL_alSource != null) @@ -328,12 +331,15 @@ namespace Microsoft.Xna.Framework.Audio { if (INTERNAL_alSource != null && queuedBuffers.Count > 0) { + GCHandle handle = GCHandle.Alloc(samples, GCHandleType.Pinned); AudioDevice.ALDevice.GetBufferData( INTERNAL_alSource, queuedBuffers.ToArray(), // FIXME: Blech -flibit - samples, + handle.AddrOfPinnedObject(), + samples.Length, channels ); + handle.Free(); } else { @@ -365,14 +371,16 @@ namespace Microsoft.Xna.Framework.Audio // Push buffer to the AL. IALBuffer newBuf = availableBuffers.Dequeue(); + GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); AudioDevice.ALDevice.SetBufferData( newBuf, channels, - buffer, + handle.AddrOfPinnedObject(), offset, count, sampleRate ); + handle.Free(); // If we're already playing, queue immediately. if (INTERNAL_alSource != null) diff --git a/src/Audio/IALDevice.cs b/src/Audio/IALDevice.cs index d587340..6e22aa5 100644 --- a/src/Audio/IALDevice.cs +++ b/src/Audio/IALDevice.cs @@ -36,15 +36,15 @@ namespace Microsoft.Xna.Framework.Audio void SetBufferData( IALBuffer buffer, AudioChannels channels, - byte[] data, + IntPtr data, int offset, int count, int sampleRate ); - void SetBufferData( + void SetBufferFloatData( IALBuffer buffer, AudioChannels channels, - float[] data, + IntPtr data, int offset, int count, int sampleRate @@ -76,7 +76,8 @@ namespace Microsoft.Xna.Framework.Audio void GetBufferData( IALSource source, IALBuffer[] buffer, - float[] samples, + IntPtr samples, + int samplesLen, AudioChannels channels ); diff --git a/src/Audio/NullDevice.cs b/src/Audio/NullDevice.cs index cfa52dd..cefd382 100644 --- a/src/Audio/NullDevice.cs +++ b/src/Audio/NullDevice.cs @@ -91,7 +91,7 @@ namespace Microsoft.Xna.Framework.Audio public void SetBufferData( IALBuffer buffer, AudioChannels channels, - byte[] data, + IntPtr data, int offset, int count, int sampleRate @@ -99,10 +99,10 @@ namespace Microsoft.Xna.Framework.Audio // No-op, duh. } - public void SetBufferData( + public void SetBufferFloatData( IALBuffer buffer, AudioChannels channels, - float[] data, + IntPtr data, int offset, int count, int sampleRate @@ -219,7 +219,8 @@ namespace Microsoft.Xna.Framework.Audio public void GetBufferData( IALSource source, IALBuffer[] buffer, - float[] samples, + IntPtr samples, + int samplesLen, AudioChannels channels ) { // No-op, duh. diff --git a/src/Audio/OpenALDevice.cs b/src/Audio/OpenALDevice.cs index 6c545ee..41323aa 100644 --- a/src/Audio/OpenALDevice.cs +++ b/src/Audio/OpenALDevice.cs @@ -326,42 +326,38 @@ namespace Microsoft.Xna.Framework.Audio public void SetBufferData( IALBuffer buffer, AudioChannels channels, - byte[] data, + IntPtr data, int offset, int count, int sampleRate ) { - GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); AL10.alBufferData( (buffer as OpenALBuffer).Handle, XNAToShort[(int) channels], - handle.AddrOfPinnedObject() + offset, + data + offset, (IntPtr) count, (IntPtr) sampleRate ); - handle.Free(); #if VERBOSE_AL_DEBUGGING CheckALError(); #endif } - public void SetBufferData( + public void SetBufferFloatData( IALBuffer buffer, AudioChannels channels, - float[] data, + IntPtr data, int offset, int count, int sampleRate ) { - GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); AL10.alBufferData( (buffer as OpenALBuffer).Handle, XNAToFloat[(int) channels], - handle.AddrOfPinnedObject() + (offset * 4), + data + (offset * 4), (IntPtr) (count * 4), (IntPtr) sampleRate ); - handle.Free(); #if VERBOSE_AL_DEBUGGING CheckALError(); #endif @@ -659,10 +655,11 @@ namespace Microsoft.Xna.Framework.Audio public void GetBufferData( IALSource source, IALBuffer[] buffer, - float[] samples, + IntPtr samples, + int samplesLen, AudioChannels channels ) { - int copySize1 = samples.Length / (int) channels; + int copySize1 = samplesLen / (int) channels; int copySize2 = 0; // Where are we now? @@ -696,7 +693,6 @@ namespace Microsoft.Xna.Framework.Audio } // Copy! - GCHandle handle = GCHandle.Alloc(samples, GCHandleType.Pinned); if (copySize1 > 0) { ALEXT.alGetBufferSamplesSOFT( @@ -707,7 +703,7 @@ namespace Microsoft.Xna.Framework.Audio ALEXT.AL_STEREO_SOFT : ALEXT.AL_MONO_SOFT, ALEXT.AL_FLOAT_SOFT, - handle.AddrOfPinnedObject() + samples ); offset = 0; } @@ -721,10 +717,9 @@ namespace Microsoft.Xna.Framework.Audio ALEXT.AL_STEREO_SOFT : ALEXT.AL_MONO_SOFT, ALEXT.AL_FLOAT_SOFT, - handle.AddrOfPinnedObject() + (copySize1 * (int) channels) + samples + (copySize1 * (int) channels) ); } - handle.Free(); } #endregion diff --git a/src/Graphics/GraphicsDevice.cs b/src/Graphics/GraphicsDevice.cs index 37dd01a..ebed1e8 100644 --- a/src/Graphics/GraphicsDevice.cs +++ b/src/Graphics/GraphicsDevice.cs @@ -737,7 +737,7 @@ namespace Microsoft.Xna.Framework.Graphics public void GetBackBufferData(T[] data) where T : struct { - GLDevice.ReadBackbuffer(data, 0, data.Length, null); + GetBackBufferData(null, data, 0, data.Length); } public void GetBackBufferData( @@ -745,7 +745,7 @@ namespace Microsoft.Xna.Framework.Graphics int startIndex, int elementCount ) where T : struct { - GLDevice.ReadBackbuffer(data, startIndex, elementCount, null); + GetBackBufferData(null, data, startIndex, elementCount); } public void GetBackBufferData( @@ -754,7 +754,17 @@ namespace Microsoft.Xna.Framework.Graphics int startIndex, int elementCount ) where T : struct { - GLDevice.ReadBackbuffer(data, startIndex, elementCount, rect); + int elementSizeInBytes = Marshal.SizeOf(typeof(T)); + GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); + GLDevice.ReadBackbuffer( + handle.AddrOfPinnedObject(), + data.Length * elementSizeInBytes, + startIndex, + elementCount, + elementSizeInBytes, + rect + ); + handle.Free(); } #endregion diff --git a/src/Graphics/IGLDevice.cs b/src/Graphics/IGLDevice.cs index 0ec2e2f..6f17c87 100644 --- a/src/Graphics/IGLDevice.cs +++ b/src/Graphics/IGLDevice.cs @@ -148,12 +148,14 @@ namespace Microsoft.Xna.Framework.Graphics ); void ResolveTarget(RenderTargetBinding target); - void ReadBackbuffer( - T[] data, + void ReadBackbuffer( + IntPtr data, + int dataLen, int startIndex, int elementCount, + int elementSizeInBytes, Rectangle? rect - ) where T : struct; + ); IGLTexture CreateTexture2D( SurfaceFormat format, @@ -258,23 +260,24 @@ namespace Microsoft.Xna.Framework.Graphics int vertexStride ); void AddDisposeVertexBuffer(IGLBuffer buffer); - void SetVertexBufferData( + void SetVertexBufferData( IGLBuffer buffer, - int elementSizeInBytes, int offsetInBytes, - T[] data, + IntPtr data, int startIndex, int elementCount, + int elementSizeInBytes, SetDataOptions options - ) where T : struct; - void GetVertexBufferData( + ); + void GetVertexBufferData( IGLBuffer buffer, int offsetInBytes, - T[] data, + IntPtr data, int startIndex, int elementCount, + int elementSizeInBytes, int vertexStride - ) where T : struct; + ); IGLBuffer GenIndexBuffer( bool dynamic, @@ -282,21 +285,23 @@ namespace Microsoft.Xna.Framework.Graphics IndexElementSize indexElementSize ); void AddDisposeIndexBuffer(IGLBuffer buffer); - void SetIndexBufferData( + void SetIndexBufferData( IGLBuffer buffer, int offsetInBytes, - T[] data, + IntPtr data, int startIndex, int elementCount, + int elementSizeInBytes, SetDataOptions options - ) where T : struct; - void GetIndexBufferData( + ); + void GetIndexBufferData( IGLBuffer buffer, int offsetInBytes, - T[] data, + IntPtr data, int startIndex, - int elementCount - ) where T : struct; + int elementCount, + int elementSizeInBytes + ); IGLEffect CreateEffect(byte[] effectCode); IGLEffect CloneEffect(IGLEffect effect); diff --git a/src/Graphics/OpenGLDevice.cs b/src/Graphics/OpenGLDevice.cs index 4862790..94ef86b 100644 --- a/src/Graphics/OpenGLDevice.cs +++ b/src/Graphics/OpenGLDevice.cs @@ -2178,15 +2178,15 @@ namespace Microsoft.Xna.Framework.Graphics #region glSetBufferData Methods - public void SetVertexBufferData( + public void SetVertexBufferData( IGLBuffer buffer, - int elementSizeInBytes, int offsetInBytes, - T[] data, + IntPtr data, int startIndex, int elementCount, + int elementSizeInBytes, SetDataOptions options - ) where T : struct { + ) { #if !DISABLE_THREADING ForceToMainThread(() => { #endif @@ -2203,30 +2203,27 @@ namespace Microsoft.Xna.Framework.Graphics ); } - GCHandle dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); - glBufferSubData( GLenum.GL_ARRAY_BUFFER, (IntPtr) offsetInBytes, (IntPtr) (elementSizeInBytes * elementCount), - (IntPtr) (dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInBytes) + data + (startIndex * elementSizeInBytes) ); - dataHandle.Free(); - #if !DISABLE_THREADING }); #endif } - public void SetIndexBufferData( + public void SetIndexBufferData( IGLBuffer buffer, int offsetInBytes, - T[] data, + IntPtr data, int startIndex, int elementCount, + int elementSizeInBytes, SetDataOptions options - ) where T : struct { + ) { #if !DISABLE_THREADING ForceToMainThread(() => { #endif @@ -2243,18 +2240,13 @@ namespace Microsoft.Xna.Framework.Graphics ); } - GCHandle dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); - - int elementSizeInBytes = Marshal.SizeOf(typeof(T)); glBufferSubData( GLenum.GL_ELEMENT_ARRAY_BUFFER, (IntPtr) offsetInBytes, (IntPtr) (elementSizeInBytes * elementCount), - (IntPtr) (dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInBytes) + data + (startIndex * elementSizeInBytes) ); - dataHandle.Free(); - #if !DISABLE_THREADING }); #endif @@ -2264,61 +2256,54 @@ namespace Microsoft.Xna.Framework.Graphics #region glGetBufferData Methods - public void GetVertexBufferData( + public void GetVertexBufferData( IGLBuffer buffer, int offsetInBytes, - T[] data, + IntPtr data, int startIndex, int elementCount, + int elementSizeInBytes, int vertexStride - ) where T : struct { + ) { #if !DISABLE_THREADING ForceToMainThread(() => { #endif BindVertexBuffer(buffer); - GCHandle dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); - glGetBufferSubData( GLenum.GL_ARRAY_BUFFER, (IntPtr) offsetInBytes, (IntPtr) (elementCount * vertexStride), - dataHandle.AddrOfPinnedObject() + (startIndex * Marshal.SizeOf(typeof(T))) + data + (startIndex * elementSizeInBytes) ); - dataHandle.Free(); - #if !DISABLE_THREADING }); #endif } - public void GetIndexBufferData( + public void GetIndexBufferData( IGLBuffer buffer, int offsetInBytes, - T[] data, + IntPtr data, int startIndex, - int elementCount - ) where T : struct { + int elementCount, + int elementSizeInBytes + ) { #if !DISABLE_THREADING ForceToMainThread(() => { #endif BindIndexBuffer(buffer); - GCHandle dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); - - int typeSize = Marshal.SizeOf(typeof(T)); glGetBufferSubData( GLenum.GL_ELEMENT_ARRAY_BUFFER, (IntPtr) offsetInBytes, - (IntPtr) (elementCount * typeSize), - dataHandle.AddrOfPinnedObject() + (startIndex * typeSize) + (IntPtr) (elementCount * elementSizeInBytes), + data + (startIndex * elementSizeInBytes) ); - dataHandle.Free(); - #if !DISABLE_THREADING }); #endif @@ -3093,13 +3078,26 @@ namespace Microsoft.Xna.Framework.Graphics #region glReadPixels Methods - public void ReadBackbuffer( - T[] data, + public void ReadBackbuffer( + IntPtr data, + int dataLen, int startIndex, int elementCount, + int elementSizeInBytes, Rectangle? rect - ) where T : struct { - if (startIndex > 0 || elementCount != data.Length) + ) { + /* FIXME: Right now we're expecting one of the following: + * - byte[] + * - int[] + * - uint[] + * - Color[] + * Anything else will freak out because we're using + * color backbuffers. Maybe check this out when adding + * support for more backbuffer types! + * -flibit + */ + + if (startIndex > 0 || elementCount != (dataLen / elementSizeInBytes)) { throw new NotImplementedException( "ReadBackbuffer startIndex/elementCount" @@ -3132,36 +3130,34 @@ namespace Microsoft.Xna.Framework.Graphics h = Backbuffer.Height; } - GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); - try - { - glReadPixels( - x, - y, - w, - h, - GLenum.GL_RGBA, - GLenum.GL_UNSIGNED_BYTE, - handle.AddrOfPinnedObject() - ); - } - finally - { - handle.Free(); - } + glReadPixels( + x, + y, + w, + h, + GLenum.GL_RGBA, + GLenum.GL_UNSIGNED_BYTE, + data + ); BindReadFramebuffer(prevReadBuffer); // Now we get to do a software-based flip! Yes, really! -flibit - int pitch = w * 4 / Marshal.SizeOf(typeof(T)); - T[] tempRow = new T[pitch]; + int pitch = w * 4; + byte[] tempRow = new byte[pitch]; + GCHandle handle = GCHandle.Alloc(tempRow, GCHandleType.Pinned); + IntPtr temp = handle.AddrOfPinnedObject(); for (int row = 0; row < h / 2; row += 1) { - Array.Copy(data, row * pitch, tempRow, 0, pitch); - Array.Copy(data, (h - row - 1) * pitch, data, row * pitch, pitch); - Array.Copy(tempRow, 0, data, (h - row - 1) * pitch, pitch); + // Top to temp, bottom to top, temp to bottom + memcpy(temp, data + (row * pitch), (IntPtr) pitch); + memcpy(data + (row * pitch), data + ((h - row - 1) * pitch), (IntPtr) pitch); + memcpy(data + ((h - row - 1) * pitch), temp, (IntPtr) pitch); } + handle.Free(); } + [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern void memcpy(IntPtr dst, IntPtr src, IntPtr len); /// /// Attempts to read the texture data directly from the FBO using glReadPixels diff --git a/src/Graphics/Vertices/IndexBuffer.cs b/src/Graphics/Vertices/IndexBuffer.cs index 407c98f..39afb93 100644 --- a/src/Graphics/Vertices/IndexBuffer.cs +++ b/src/Graphics/Vertices/IndexBuffer.cs @@ -179,13 +179,16 @@ namespace Microsoft.Xna.Framework.Graphics ); } + GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); GraphicsDevice.GLDevice.GetIndexBufferData( buffer, offsetInBytes, - data, + handle.AddrOfPinnedObject(), startIndex, - elementCount + elementCount, + Marshal.SizeOf(typeof(T)) ); + handle.Free(); } #endregion @@ -254,14 +257,17 @@ namespace Microsoft.Xna.Framework.Graphics throw new InvalidOperationException("The array specified in the data parameter is not the correct size for the amount of data requested."); } + GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); GraphicsDevice.GLDevice.SetIndexBufferData( buffer, offsetInBytes, - data, + handle.AddrOfPinnedObject(), startIndex, elementCount, + Marshal.SizeOf(typeof(T)), options ); + handle.Free(); } #endregion diff --git a/src/Graphics/Vertices/VertexBuffer.cs b/src/Graphics/Vertices/VertexBuffer.cs index 38fc98e..fbbba8a 100644 --- a/src/Graphics/Vertices/VertexBuffer.cs +++ b/src/Graphics/Vertices/VertexBuffer.cs @@ -173,9 +173,10 @@ namespace Microsoft.Xna.Framework.Graphics throw new NotSupportedException("Calling GetData on a resource that was created with BufferUsage.WriteOnly is not supported."); } + int elementSizeInBytes = Marshal.SizeOf(typeof(T)); if (vertexStride == 0) { - vertexStride = Marshal.SizeOf(typeof(T)); + vertexStride = elementSizeInBytes; } if ( elementCount > 1 && (elementCount * vertexStride) > (VertexCount * VertexDeclaration.VertexStride) ) @@ -183,14 +184,17 @@ namespace Microsoft.Xna.Framework.Graphics throw new InvalidOperationException("The array is not the correct size for the amount of data requested."); } + GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); GraphicsDevice.GLDevice.GetVertexBufferData( buffer, offsetInBytes, - data, + handle.AddrOfPinnedObject(), startIndex, elementCount, + elementSizeInBytes, vertexStride ); + handle.Free(); } #endregion @@ -288,15 +292,17 @@ namespace Microsoft.Xna.Framework.Graphics ); } + GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); GraphicsDevice.GLDevice.SetVertexBufferData( buffer, - elementSizeInBytes, offsetInBytes, - data, + handle.AddrOfPinnedObject(), startIndex, elementCount, + elementSizeInBytes, options ); + handle.Free(); } #endregion