private void PlatformConstruct(int width, int height, bool mipmap, SurfaceFormat format, SurfaceType type, bool shared) { this.glTarget = TextureTarget.Texture2D; Threading.BlockOnUIThread(() => { // Store the current bound texture. var prevTexture = GraphicsExtensions.GetBoundTexture2D(); GenerateGLTextureIfRequired(); format.GetGLFormat(GraphicsDevice, out glInternalFormat, out glFormat, out glType); if (glFormat == (PixelFormat)GLPixelFormat.CompressedTextureFormats) { var imageSize = 0; switch (format) { case SurfaceFormat.RgbPvrtc2Bpp: case SurfaceFormat.RgbaPvrtc2Bpp: imageSize = (Math.Max(this.width, 16) * Math.Max(this.height, 8) * 2 + 7) / 8; break; case SurfaceFormat.RgbPvrtc4Bpp: case SurfaceFormat.RgbaPvrtc4Bpp: imageSize = (Math.Max(this.width, 8) * Math.Max(this.height, 8) * 4 + 7) / 8; break; case SurfaceFormat.Dxt1: case SurfaceFormat.Dxt1a: case SurfaceFormat.Dxt1SRgb: case SurfaceFormat.Dxt3: case SurfaceFormat.Dxt3SRgb: case SurfaceFormat.Dxt5: case SurfaceFormat.Dxt5SRgb: case SurfaceFormat.RgbEtc1: case SurfaceFormat.RgbaAtcExplicitAlpha: case SurfaceFormat.RgbaAtcInterpolatedAlpha: imageSize = ((this.width + 3) / 4) * ((this.height + 3) / 4) * GraphicsExtensions.GetSize(format); break; default: throw new NotSupportedException(); } GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, glInternalFormat, this.width, this.height, 0, imageSize, IntPtr.Zero); GraphicsExtensions.CheckGLError(); } else { GL.TexImage2D(TextureTarget.Texture2D, 0, glInternalFormat, this.width, this.height, 0, glFormat, glType, IntPtr.Zero); GraphicsExtensions.CheckGLError(); } // Restore the bound texture. GL.BindTexture(TextureTarget.Texture2D, prevTexture); GraphicsExtensions.CheckGLError(); }); }
private void PlatformSetData <T>(int level, int arraySlice, Rectangle?rect, T[] data, int startIndex, int elementCount) where T : struct { Threading.BlockOnUIThread(() => { 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); 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 || _format == SurfaceFormat.RgbaAtcExplicitAlpha || _format == SurfaceFormat.RgbaAtcInterpolatedAlpha || _format == SurfaceFormat.RgbPvrtc2Bpp || _format == SurfaceFormat.RgbPvrtc4Bpp || _format == SurfaceFormat.RgbaPvrtc2Bpp || _format == SurfaceFormat.RgbaPvrtc4Bpp || _format == SurfaceFormat.RgbEtc1 ) { if (w > 4) { w = (w + 3) & ~3; } if (h > 4) { h = (h + 3) & ~3; } } } // Store the current bound texture. var prevTexture = GraphicsExtensions.GetBoundTexture2D(); GenerateGLTextureIfRequired(); GL.BindTexture(TextureTarget.Texture2D, this.glTexture); GraphicsExtensions.CheckGLError(); if (glFormat == (PixelFormat)GLPixelFormat.CompressedTextureFormats) { if (rect.HasValue) { GL.CompressedTexSubImage2D(TextureTarget.Texture2D, level, x, y, w, h, glFormat, elementCount - startBytes, dataPtr); GraphicsExtensions.CheckGLError(); } else { GL.CompressedTexImage2D(TextureTarget.Texture2D, level, glInternalFormat, w, h, 0, elementCount - startBytes, dataPtr); GraphicsExtensions.CheckGLError(); } } else { // Set pixel alignment to match texel size in bytes GL.PixelStore(PixelStoreParameter.UnpackAlignment, GraphicsExtensions.GetSize(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, glInternalFormat, 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(); } finally { dataHandle.Free(); } #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 }); }