Пример #1
0
        public void SetTexture(int index, ShaderStage stage, ITexture texture)
        {
            int unit = _program.GetTextureUnit(stage, index);

            if (unit != -1 && texture != null)
            {
                if (unit == 0)
                {
                    _unit0Texture = ((TextureView)texture);
                }
                else
                {
                    ((TextureView)texture).Bind(unit);
                }
            }
        }
Пример #2
0
        public void AttachColor(int index, TextureView color)
        {
            FramebufferAttachment attachment = FramebufferAttachment.ColorAttachment0 + index;

            if (HwCapabilities.Vendor == HwCapabilities.GpuVendor.Amd ||
                HwCapabilities.Vendor == HwCapabilities.GpuVendor.Intel)
            {
                GL.FramebufferTexture(FramebufferTarget.Framebuffer, attachment, color?.GetIncompatibleFormatViewHandle() ?? 0, 0);

                _colors[index] = color;
            }
            else
            {
                GL.FramebufferTexture(FramebufferTarget.Framebuffer, attachment, color?.Handle ?? 0, 0);
            }
        }
Пример #3
0
        public void Copy(
            TextureView src,
            TextureView dst,
            Extents2D srcRegion,
            Extents2D dstRegion,
            bool linearFilter)
        {
            int oldReadFramebufferHandle = GL.GetInteger(GetPName.ReadFramebufferBinding);
            int oldDrawFramebufferHandle = GL.GetInteger(GetPName.DrawFramebufferBinding);

            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetSrcFramebufferLazy());
            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetDstFramebufferLazy());

            Attach(FramebufferTarget.ReadFramebuffer, src.Format, src.Handle);
            Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle);

            ClearBufferMask mask = GetMask(src.Format);

            BlitFramebufferFilter filter = linearFilter
                ? BlitFramebufferFilter.Linear
                : BlitFramebufferFilter.Nearest;

            GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
            GL.DrawBuffer(DrawBufferMode.ColorAttachment0);

            GL.Disable(EnableCap.RasterizerDiscard);
            GL.Disable(IndexedEnableCap.ScissorTest, 0);

            GL.BlitFramebuffer(
                srcRegion.X1,
                srcRegion.Y1,
                srcRegion.X2,
                srcRegion.Y2,
                dstRegion.X1,
                dstRegion.Y1,
                dstRegion.X2,
                dstRegion.Y2,
                mask,
                filter);

            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);

            ((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
            ((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
        }
Пример #4
0
        public void Dispose()
        {
            if (_incompatibleFormatView != null)
            {
                _incompatibleFormatView.Dispose();

                _incompatibleFormatView = null;
            }

            if (Handle != 0)
            {
                GL.DeleteTexture(Handle);

                _parent.DecrementViewsCount();

                Handle = 0;
            }
        }
Пример #5
0
        public void Copy(
            TextureView src,
            TextureView dst,
            Extents2D srcRegion,
            Extents2D dstRegion,
            bool linearFilter)
        {
            GL.Disable(EnableCap.FramebufferSrgb);

            int oldReadFramebufferHandle = GL.GetInteger(GetPName.ReadFramebufferBinding);
            int oldDrawFramebufferHandle = GL.GetInteger(GetPName.DrawFramebufferBinding);

            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetSrcFramebufferLazy());
            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetDstFramebufferLazy());

            Attach(FramebufferTarget.ReadFramebuffer, src.Format, src.Handle);
            Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle);

            ClearBufferMask mask = GetMask(src.Format);

            BlitFramebufferFilter filter = linearFilter
                ? BlitFramebufferFilter.Linear
                : BlitFramebufferFilter.Nearest;

            GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
            GL.DrawBuffer(DrawBufferMode.ColorAttachment0);

            GL.BlitFramebuffer(
                srcRegion.X1,
                srcRegion.Y1,
                srcRegion.X2,
                srcRegion.Y2,
                dstRegion.X1,
                dstRegion.Y1,
                dstRegion.X2,
                dstRegion.Y2,
                mask,
                filter);

            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);

            GL.Enable(EnableCap.FramebufferSrgb);
        }
Пример #6
0
        public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
        {
            TextureView destinationView = (TextureView)destination;

            TextureCopyUnscaled.Copy(_info, destinationView._info, Handle, destinationView.Handle, 0, firstLayer, 0, firstLevel);

            if (destinationView._emulatedViewParent != null)
            {
                TextureCopyUnscaled.Copy(
                    _info,
                    destinationView._emulatedViewParent._info,
                    Handle,
                    destinationView._emulatedViewParent.Handle,
                    0,
                    destinationView.FirstLayer,
                    0,
                    destinationView.FirstLevel);
            }
        }
Пример #7
0
        public void Draw(
            TextureView texture,
            Sampler sampler,
            float x0,
            float y0,
            float x1,
            float y1,
            float s0,
            float t0,
            float s1,
            float t1)
        {
            EnsureInitialized();

            GL.UseProgram(_programHandle);

            texture.Bind(0);
            sampler.Bind(0);

            if (x0 > x1)
            {
                float temp = s0;
                s0 = s1;
                s1 = temp;
            }

            if (y0 > y1)
            {
                float temp = t0;
                t0 = t1;
                t1 = temp;
            }

            GL.Uniform1(_uniformSrcX0Location, s0);
            GL.Uniform1(_uniformSrcY0Location, t0);
            GL.Uniform1(_uniformSrcX1Location, s1);
            GL.Uniform1(_uniformSrcY1Location, t1);

            GL.ViewportIndexed(0, MathF.Min(x0, x1), MathF.Min(y0, y1), MathF.Abs(x1 - x0), MathF.Abs(y1 - y0));

            GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
        }
Пример #8
0
        public int GetIncompatibleFormatViewHandle()
        {
            // AMD and Intel has a bug where the view format is always ignored,
            // it uses the parent format instead.
            // As workaround we create a new texture with the correct
            // format, and then do a copy after the draw.
            if (_parent.Info.Format != Format)
            {
                if (_incompatibleFormatView == null)
                {
                    _incompatibleFormatView = (TextureView)_renderer.CreateTexture(_info);
                }

                TextureCopyUnscaled.Copy(_parent.Info, _incompatibleFormatView._info, _parent.Handle, _incompatibleFormatView.Handle, FirstLayer, 0, FirstLevel, 0);

                return(_incompatibleFormatView.Handle);
            }

            return(Handle);
        }
Пример #9
0
        /// <summary>
        /// Add a texture that is not being used anymore to the resource pool to be used later.
        /// Both the texture's view and storage should be completely unused.
        /// </summary>
        /// <param name="view">The texture's view</param>
        public void AddTexture(TextureView view)
        {
            lock (_lock)
            {
                List <DisposedTexture> list;
                if (!_textures.TryGetValue(view.Info, out list))
                {
                    list = new List <DisposedTexture>();
                    _textures.Add(view.Info, list);
                }

                list.Add(new DisposedTexture()
                {
                    Info            = view.Info,
                    View            = view,
                    ScaleFactor     = view.ScaleFactor,
                    RemainingFrames = DisposedLiveFrames
                });
            }
        }
Пример #10
0
        public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
        {
            EnsureFramebuffer();

            for (int index = 0; index < colors.Length; index++)
            {
                TextureView color = (TextureView)colors[index];

                _framebuffer.AttachColor(index, color);
            }

            TextureView depthStencilView = (TextureView)depthStencil;

            _framebuffer.AttachDepthStencil(depthStencilView);

            _framebuffer.SetDrawBuffers(colors.Length);

            _hasDepthBuffer = depthStencil != null && depthStencilView.Format != Format.S8Uint;

            UpdateDepthTest();
        }
Пример #11
0
        public void AttachDepthStencil(TextureView depthStencil)
        {
            // Detach the last depth/stencil buffer if there is any.
            if (_lastDsAttachment != 0)
            {
                GL.FramebufferTexture(FramebufferTarget.Framebuffer, _lastDsAttachment, 0, 0);
            }

            if (depthStencil != null)
            {
                FramebufferAttachment attachment;

                if (IsPackedDepthStencilFormat(depthStencil.Format))
                {
                    attachment = FramebufferAttachment.DepthStencilAttachment;
                }
                else if (IsDepthOnlyFormat(depthStencil.Format))
                {
                    attachment = FramebufferAttachment.DepthAttachment;
                }
                else
                {
                    attachment = FramebufferAttachment.StencilAttachment;
                }

                GL.FramebufferTexture(
                    FramebufferTarget.Framebuffer,
                    attachment,
                    depthStencil.Handle,
                    0);

                _lastDsAttachment = attachment;
            }
            else
            {
                _lastDsAttachment = 0;
            }
        }
Пример #12
0
        private void CopyTextureToFrameBufferRGB(int drawFramebuffer, int readFramebuffer, TextureView view, ImageCrop crop)
        {
            (int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers();

            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, drawFramebuffer);
            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, readFramebuffer);

            TextureView viewConverted = view.Format.IsBgr() ? _renderer.TextureCopy.BgraSwap(view) : view;

            GL.FramebufferTexture(
                FramebufferTarget.ReadFramebuffer,
                FramebufferAttachment.ColorAttachment0,
                viewConverted.Handle,
                0);

            GL.ReadBuffer(ReadBufferMode.ColorAttachment0);

            GL.Disable(EnableCap.RasterizerDiscard);
            GL.Disable(IndexedEnableCap.ScissorTest, 0);

            GL.Clear(ClearBufferMask.ColorBufferBit);

            int   srcX0, srcX1, srcY0, srcY1;
            float scale = view.ScaleFactor;

            if (crop.Left == 0 && crop.Right == 0)
            {
                srcX0 = 0;
                srcX1 = (int)(view.Width / scale);
            }
            else
            {
                srcX0 = crop.Left;
                srcX1 = crop.Right;
            }

            if (crop.Top == 0 && crop.Bottom == 0)
            {
                srcY0 = 0;
                srcY1 = (int)(view.Height / scale);
            }
            else
            {
                srcY0 = crop.Top;
                srcY1 = crop.Bottom;
            }

            if (scale != 1f)
            {
                srcX0 = (int)(srcX0 * scale);
                srcY0 = (int)(srcY0 * scale);
                srcX1 = (int)Math.Ceiling(srcX1 * scale);
                srcY1 = (int)Math.Ceiling(srcY1 * scale);
            }

            float ratioX = crop.IsStretched ? 1.0f : MathF.Min(1.0f, _height * crop.AspectRatioX / (_width * crop.AspectRatioY));
            float ratioY = crop.IsStretched ? 1.0f : MathF.Min(1.0f, _width * crop.AspectRatioY / (_height * crop.AspectRatioX));

            int dstWidth  = (int)(_width * ratioX);
            int dstHeight = (int)(_height * ratioY);

            int dstPaddingX = (_width - dstWidth) / 2;
            int dstPaddingY = (_height - dstHeight) / 2;

            int dstX0 = crop.FlipX ? _width - dstPaddingX : dstPaddingX;
            int dstX1 = crop.FlipX ? dstPaddingX : _width - dstPaddingX;

            int dstY0 = crop.FlipY ? dstPaddingY : _height - dstPaddingY;
            int dstY1 = crop.FlipY ? _height - dstPaddingY : dstPaddingY;

            if (ScreenCaptureRequested)
            {
                CaptureFrame(srcX0, srcY0, srcX1, srcY1, view.Format.IsBgr(), crop.FlipX, crop.FlipY);

                ScreenCaptureRequested = false;
            }

            GL.BlitFramebuffer(
                srcX0,
                srcY0,
                srcX1,
                srcY1,
                dstX0,
                dstY0,
                dstX1,
                dstY1,
                ClearBufferMask.ColorBufferBit,
                BlitFramebufferFilter.Linear);

            // Remove Alpha channel
            GL.ColorMask(false, false, false, true);
            GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            GL.Clear(ClearBufferMask.ColorBufferBit);

            for (int i = 0; i < Constants.MaxRenderTargets; i++)
            {
                ((Pipeline)_renderer.Pipeline).RestoreComponentMask(i);
            }

            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);

            ((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
            ((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();

            if (viewConverted != view)
            {
                viewConverted.Dispose();
            }
        }
Пример #13
0
        private void CopyTextureToFrameBufferRGB(int drawFramebuffer, int readFramebuffer, TextureView view, ImageCrop crop)
        {
            bool[] oldFramebufferColorWritemask = new bool[4];

            (int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers();

            GL.GetBoolean(GetIndexedPName.ColorWritemask, drawFramebuffer, oldFramebufferColorWritemask);

            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, drawFramebuffer);
            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, readFramebuffer);

            GL.FramebufferTexture(
                FramebufferTarget.ReadFramebuffer,
                FramebufferAttachment.ColorAttachment0,
                view.Handle,
                0);

            GL.ReadBuffer(ReadBufferMode.ColorAttachment0);

            GL.Disable(EnableCap.RasterizerDiscard);
            GL.Disable(IndexedEnableCap.ScissorTest, 0);

            GL.Clear(ClearBufferMask.ColorBufferBit);

            int srcX0, srcX1, srcY0, srcY1;

            if (crop.Left == 0 && crop.Right == 0)
            {
                srcX0 = 0;
                srcX1 = view.Width;
            }
            else
            {
                srcX0 = crop.Left;
                srcX1 = crop.Right;
            }

            if (crop.Top == 0 && crop.Bottom == 0)
            {
                srcY0 = 0;
                srcY1 = view.Height;
            }
            else
            {
                srcY0 = crop.Top;
                srcY1 = crop.Bottom;
            }

            float ratioX = MathF.Min(1f, (_height * (float)NativeWidth) / ((float)NativeHeight * _width));
            float ratioY = MathF.Min(1f, (_width * (float)NativeHeight) / ((float)NativeWidth * _height));

            int dstWidth  = (int)(_width * ratioX);
            int dstHeight = (int)(_height * ratioY);

            int dstPaddingX = (_width - dstWidth) / 2;
            int dstPaddingY = (_height - dstHeight) / 2;

            int dstX0 = crop.FlipX ? _width - dstPaddingX : dstPaddingX;
            int dstX1 = crop.FlipX ? dstPaddingX : _width - dstPaddingX;

            int dstY0 = crop.FlipY ? dstPaddingY : _height - dstPaddingY;
            int dstY1 = crop.FlipY ? _height - dstPaddingY : dstPaddingY;

            GL.BlitFramebuffer(
                srcX0,
                srcY0,
                srcX1,
                srcY1,
                dstX0,
                dstY0,
                dstX1,
                dstY1,
                ClearBufferMask.ColorBufferBit,
                BlitFramebufferFilter.Linear);

            // Remove Alpha channel
            GL.ColorMask(drawFramebuffer, false, false, false, true);
            GL.ClearBuffer(ClearBuffer.Color, 0, new float[] { 0.0f, 0.0f, 0.0f, 1.0f });
            GL.ColorMask(drawFramebuffer,
                         oldFramebufferColorWritemask[0],
                         oldFramebufferColorWritemask[1],
                         oldFramebufferColorWritemask[2],
                         oldFramebufferColorWritemask[3]);

            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);

            ((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
            ((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
        }
Пример #14
0
        public static void Copy(TextureView src, TextureView dst, int dstLayer, int dstLevel)
        {
            int srcWidth  = src.Width;
            int srcHeight = src.Height;
            int srcDepth  = src.DepthOrLayers;
            int srcLevels = src.Levels;

            srcWidth  = Math.Max(1, srcWidth >> dstLevel);
            srcHeight = Math.Max(1, srcHeight >> dstLevel);

            if (src.Target == Target.Texture3D)
            {
                srcDepth = Math.Max(1, srcDepth >> dstLevel);
            }

            int dstWidth  = dst.Width;
            int dstHeight = dst.Height;
            int dstDepth  = dst.DepthOrLayers;
            int dstLevels = dst.Levels;

            // When copying from a compressed to a non-compressed format,
            // the non-compressed texture will have the size of the texture
            // in blocks (not in texels), so we must adjust that size to
            // match the size in texels of the compressed texture.
            if (!src.IsCompressed && dst.IsCompressed)
            {
                dstWidth  = BitUtils.DivRoundUp(dstWidth, dst.BlockWidth);
                dstHeight = BitUtils.DivRoundUp(dstHeight, dst.BlockHeight);
            }
            else if (src.IsCompressed && !dst.IsCompressed)
            {
                dstWidth  *= dst.BlockWidth;
                dstHeight *= dst.BlockHeight;
            }

            int width  = Math.Min(srcWidth, dstWidth);
            int height = Math.Min(srcHeight, dstHeight);
            int depth  = Math.Min(srcDepth, dstDepth);
            int levels = Math.Min(srcLevels, dstLevels);

            for (int level = 0; level < levels; level++)
            {
                // Stop copy if we are already out of the levels range.
                if (level >= src.Levels || dstLevel + level >= dst.Levels)
                {
                    break;
                }

                GL.CopyImageSubData(
                    src.Handle,
                    src.Target.ConvertToImageTarget(),
                    level,
                    0,
                    0,
                    0,
                    dst.Handle,
                    dst.Target.ConvertToImageTarget(),
                    dstLevel + level,
                    0,
                    0,
                    dstLayer,
                    width,
                    height,
                    depth);

                width  = Math.Max(1, width >> 1);
                height = Math.Max(1, height >> 1);

                if (src.Target == Target.Texture3D)
                {
                    depth = Math.Max(1, depth >> 1);
                }
            }
        }
Пример #15
0
        private void CopyTextureToFrameBufferRGB(int drawFramebuffer, int readFramebuffer, TextureView view, ImageCrop crop, Action <object> swapBuffersCallback)
        {
            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, drawFramebuffer);
            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, readFramebuffer);

            GL.FramebufferTexture2D(FramebufferTarget.DrawFramebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, _stagingTextures[_currentTexture], 0);

            TextureView viewConverted = view.Format.IsBgr() ? _renderer.TextureCopy.BgraSwap(view) : view;

            GL.FramebufferTexture(
                FramebufferTarget.ReadFramebuffer,
                FramebufferAttachment.ColorAttachment0,
                viewConverted.Handle,
                0);

            GL.ReadBuffer(ReadBufferMode.ColorAttachment0);

            GL.Disable(EnableCap.RasterizerDiscard);
            GL.Disable(IndexedEnableCap.ScissorTest, 0);

            GL.Clear(ClearBufferMask.ColorBufferBit);

            int   srcX0, srcX1, srcY0, srcY1;
            float scale = view.ScaleFactor;

            if (crop.Left == 0 && crop.Right == 0)
            {
                srcX0 = 0;
                srcX1 = (int)(view.Width / scale);
            }
            else
            {
                srcX0 = crop.Left;
                srcX1 = crop.Right;
            }

            if (crop.Top == 0 && crop.Bottom == 0)
            {
                srcY0 = 0;
                srcY1 = (int)(view.Height / scale);
            }
            else
            {
                srcY0 = crop.Top;
                srcY1 = crop.Bottom;
            }

            if (scale != 1f)
            {
                srcX0 = (int)(srcX0 * scale);
                srcY0 = (int)(srcY0 * scale);
                srcX1 = (int)Math.Ceiling(srcX1 * scale);
                srcY1 = (int)Math.Ceiling(srcY1 * scale);
            }

            float ratioX = crop.IsStretched ? 1.0f : MathF.Min(1.0f, _height * crop.AspectRatioX / (_width * crop.AspectRatioY));
            float ratioY = crop.IsStretched ? 1.0f : MathF.Min(1.0f, _width * crop.AspectRatioY / (_height * crop.AspectRatioX));

            int dstWidth  = (int)(_width * ratioX);
            int dstHeight = (int)(_height * ratioY);

            int dstPaddingX = (_width - dstWidth) / 2;
            int dstPaddingY = (_height - dstHeight) / 2;

            int dstX0 = crop.FlipX ? _width - dstPaddingX : dstPaddingX;
            int dstX1 = crop.FlipX ? dstPaddingX : _width - dstPaddingX;

            int dstY0 = crop.FlipY ? dstPaddingY : _height - dstPaddingY;
            int dstY1 = crop.FlipY ? _height - dstPaddingY : dstPaddingY;

            if (ScreenCaptureRequested)
            {
                CaptureFrame(srcX0, srcY0, srcX1, srcY1, view.Format.IsBgr(), crop.FlipX, crop.FlipY);

                ScreenCaptureRequested = false;
            }

            GL.BlitFramebuffer(
                srcX0,
                srcY0,
                srcX1,
                srcY1,
                dstX0,
                dstY0,
                dstX1,
                dstY1,
                ClearBufferMask.ColorBufferBit,
                BlitFramebufferFilter.Linear);

            // Remove Alpha channel
            GL.ColorMask(false, false, false, true);
            GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            GL.Clear(ClearBufferMask.ColorBufferBit);

            for (int i = 0; i < Constants.MaxRenderTargets; i++)
            {
                ((Pipeline)_renderer.Pipeline).RestoreComponentMask(i);
            }

            // Set clip control, viewport and the framebuffer to the output to placate overlays and OBS capture.
            GL.ClipControl(ClipOrigin.LowerLeft, ClipDepthMode.NegativeOneToOne);
            GL.Viewport(0, 0, _width, _height);
            GL.BindFramebuffer(FramebufferTarget.Framebuffer, drawFramebuffer);

            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, _stagingFrameBuffer);

            swapBuffersCallback((object)_stagingTextures[_currentTexture]);
            _currentTexture = ++_currentTexture % _stagingTextures.Length;

            ((Pipeline)_renderer.Pipeline).RestoreClipControl();
            ((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
            ((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
            ((Pipeline)_renderer.Pipeline).RestoreViewport0();

            if (viewConverted != view)
            {
                viewConverted.Dispose();
            }
        }
Пример #16
0
        public void Present(ITexture texture, ImageCrop crop)
        {
            TextureView view = (TextureView)texture;

            GL.Disable(EnableCap.FramebufferSrgb);

            int oldReadFramebufferHandle = GL.GetInteger(GetPName.ReadFramebufferBinding);
            int oldDrawFramebufferHandle = GL.GetInteger(GetPName.DrawFramebufferBinding);

            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetCopyFramebufferHandleLazy());

            GL.FramebufferTexture(
                FramebufferTarget.ReadFramebuffer,
                FramebufferAttachment.ColorAttachment0,
                view.Handle,
                0);

            GL.ReadBuffer(ReadBufferMode.ColorAttachment0);

            GL.Clear(ClearBufferMask.ColorBufferBit);

            int srcX0, srcX1, srcY0, srcY1;

            if (crop.Left == 0 && crop.Right == 0)
            {
                srcX0 = 0;
                srcX1 = view.Width;
            }
            else
            {
                srcX0 = crop.Left;
                srcX1 = crop.Right;
            }

            if (crop.Top == 0 && crop.Bottom == 0)
            {
                srcY0 = 0;
                srcY1 = view.Height;
            }
            else
            {
                srcY0 = crop.Top;
                srcY1 = crop.Bottom;
            }

            float ratioX = MathF.Min(1f, (_height * (float)NativeWidth) / ((float)NativeHeight * _width));
            float ratioY = MathF.Min(1f, (_width * (float)NativeHeight) / ((float)NativeWidth * _height));

            int dstWidth  = (int)(_width * ratioX);
            int dstHeight = (int)(_height * ratioY);

            int dstPaddingX = (_width - dstWidth) / 2;
            int dstPaddingY = (_height - dstHeight) / 2;

            int dstX0 = crop.FlipX ? _width - dstPaddingX : dstPaddingX;
            int dstX1 = crop.FlipX ? dstPaddingX : _width - dstPaddingX;

            int dstY0 = crop.FlipY ? dstPaddingY : _height - dstPaddingY;
            int dstY1 = crop.FlipY ? _height - dstPaddingY : dstPaddingY;

            GL.BlitFramebuffer(
                srcX0,
                srcY0,
                srcX1,
                srcY1,
                dstX0,
                dstY0,
                dstX1,
                dstY1,
                ClearBufferMask.ColorBufferBit,
                BlitFramebufferFilter.Linear);

            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);

            GL.Enable(EnableCap.FramebufferSrgb);
        }