private void PlatformSetData <T>(int level, Rectangle?rect, T[] data, int startIndex, int elementCount) where T : struct { int x, y, w, h; if (rect.HasValue) { x = rect.Value.X; y = rect.Value.Y; w = rect.Value.Width; h = rect.Value.Height; } else { x = 0; y = 0; w = Math.Max(width >> level, 1); h = Math.Max(height >> level, 1); // For DXT textures the width and height of each level is a multiple of 4. // OpenGL only: The last two mip levels require the width and height to be // passed as 2x2 and 1x1, but there needs to be enough data passed to occupy // a 4x4 block. // Ref: http://www.mentby.com/Group/mac-opengl/issue-with-dxt-mipmapped-textures.html if (_format == SurfaceFormat.Dxt1 || _format == SurfaceFormat.Dxt1a || _format == SurfaceFormat.Dxt3 || _format == SurfaceFormat.Dxt5) { if (w > 4) { w = (w + 3) & ~3; } if (h > 4) { h = (h + 3) & ~3; } } } _texture2D.SetPixels(level, data, _texture2D.Format, startIndex, 0, x, y, w, h); }
public void SetData<T>(int level, Rectangle? rect, T[] data, int startIndex, int elementCount) where T : struct { if (data == null) throw new ArgumentNullException("data"); #if OPENGL Threading.BlockOnUIThread(() => { #endif #if !PSM var elementSizeInByte = Marshal.SizeOf(typeof(T)); var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); // Use try..finally to make sure dataHandle is freed in case of an error try { var startBytes = startIndex * elementSizeInByte; var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startBytes); #endif int x, y, w, h; if (rect.HasValue) { x = rect.Value.X; y = rect.Value.Y; w = rect.Value.Width; h = rect.Value.Height; } else { x = 0; y = 0; w = Math.Max(width >> level, 1); h = Math.Max(height >> level, 1); // For DXT textures the width and height of each level is a multiple of 4. // OpenGL only: The last two mip levels require the width and height to be // passed as 2x2 and 1x1, but there needs to be enough data passed to occupy // a 4x4 block. // Ref: http://www.mentby.com/Group/mac-opengl/issue-with-dxt-mipmapped-textures.html if (_format == SurfaceFormat.Dxt1 || _format == SurfaceFormat.Dxt1a || _format == SurfaceFormat.Dxt3 || _format == SurfaceFormat.Dxt5) { #if DIRECTX w = (w + 3) & ~3; h = (h + 3) & ~3; #else if (w > 4) w = (w + 3) & ~3; if (h > 4) h = (h + 3) & ~3; #endif } } #if DIRECTX var box = new SharpDX.DataBox(dataPtr, GetPitch(w), 0); var region = new SharpDX.Direct3D11.ResourceRegion(); region.Top = y; region.Front = 0; region.Back = 1; region.Bottom = y + h; region.Left = x; region.Right = x + w; // TODO: We need to deal with threaded contexts here! var d3dContext = GraphicsDevice._d3dContext; lock (d3dContext) d3dContext.UpdateSubresource(box, GetTexture(), level, region); #elif PSM _texture2D.SetPixels(level, data, _texture2D.Format, startIndex, 0, x, y, w, h); #elif OPENGL // Store the current bound texture. var prevTexture = GraphicsExtensions.GetBoundTexture2D(); GenerateGLTextureIfRequired(); GL.BindTexture(TextureTarget.Texture2D, this.glTexture); GraphicsExtensions.CheckGLError(); if (glFormat == (GLPixelFormat)All.CompressedTextureFormats) { if (rect.HasValue) { GL.CompressedTexSubImage2D(TextureTarget.Texture2D, level, x, y, w, h, #if GLES glInternalFormat, #else glFormat, #endif data.Length - startBytes, dataPtr); GraphicsExtensions.CheckGLError(); } else { GL.CompressedTexImage2D(TextureTarget.Texture2D, level, glInternalFormat, w, h, 0, data.Length - startBytes, dataPtr); GraphicsExtensions.CheckGLError(); } } else { // Set pixel alignment to match texel size in bytes GL.PixelStore(PixelStoreParameter.UnpackAlignment, GraphicsExtensions.Size(this.Format)); if (rect.HasValue) { GL.TexSubImage2D(TextureTarget.Texture2D, level, x, y, w, h, glFormat, glType, dataPtr); GraphicsExtensions.CheckGLError(); } else { GL.TexImage2D(TextureTarget.Texture2D, level, #if GLES (int)glInternalFormat, #else glInternalFormat, #endif w, h, 0, glFormat, glType, dataPtr); GraphicsExtensions.CheckGLError(); } // Return to default pixel alignment GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4); } #if !ANDROID GL.Finish(); GraphicsExtensions.CheckGLError(); #endif // Restore the bound texture. GL.BindTexture(TextureTarget.Texture2D, prevTexture); GraphicsExtensions.CheckGLError(); #endif // OPENGL #if !PSM } finally { dataHandle.Free(); } #endif #if OPENGL #if !ANDROID // Required to make sure that any texture uploads on a thread are completed // before the main thread tries to use the texture. GL.Finish(); #endif }); #endif }