using Chorizite.Core.Render; using Silk.NET.OpenGL; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AcDream.App.Rendering.Wb { /// /// Implementation of a framebuffer for OpenGL ES 3.0 using Silk.NET. /// public class ManagedGLFramebuffer : IFramebuffer { private readonly OpenGLGraphicsDevice _device; private GL _gl => _device.GL; private readonly uint _fboId; private readonly uint _depthStencilRenderbuffer; // 0 if not used private readonly ITexture _texture; private readonly int _width; private readonly int _height; public ITexture Texture => _texture; public IntPtr NativeHandle => new IntPtr(_fboId); public ManagedGLFramebuffer(OpenGLGraphicsDevice device, ITexture texture, int width, int height, bool hasDepthStencil) { _device = device; _texture = texture; _width = width; _height = height; // Generate and bind the framebuffer _fboId = _gl.GenFramebuffer(); GpuMemoryTracker.TrackResourceAllocation(GpuResourceType.FBO); _gl.BindFramebuffer(FramebufferTarget.Framebuffer, _fboId); // Attach the texture as the color attachment _gl.FramebufferTexture2D( FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, (uint)texture.NativePtr.ToInt32(), 0 ); // Create and attach a depth-stencil renderbuffer if requested if (true || hasDepthStencil) { _depthStencilRenderbuffer = _gl.GenRenderbuffer(); GpuMemoryTracker.TrackResourceAllocation(GpuResourceType.RBO); _gl.BindRenderbuffer(RenderbufferTarget.Renderbuffer, _depthStencilRenderbuffer); _gl.RenderbufferStorage( RenderbufferTarget.Renderbuffer, InternalFormat.Depth24Stencil8, (uint)width, (uint)height ); _gl.FramebufferRenderbuffer( FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, _depthStencilRenderbuffer ); GpuMemoryTracker.TrackAllocation(_width * _height * 4, GpuResourceType.RBO); // Depth24Stencil8 is 4 bytes per pixel } // Check framebuffer completeness var status = _gl.CheckFramebufferStatus(FramebufferTarget.Framebuffer); if (status != GLEnum.FramebufferComplete) { _gl.BindFramebuffer(FramebufferTarget.Framebuffer, 0); _gl.DeleteFramebuffer(_fboId); if (_depthStencilRenderbuffer != 0) { _gl.DeleteRenderbuffer(_depthStencilRenderbuffer); } throw new InvalidOperationException($"Framebuffer creation failed: {status}"); } var error = _gl.GetError(); if (error != GLEnum.NoError) { throw new InvalidOperationException($"OpenGL error during framebuffer setup: {error}"); } // Unbind the framebuffer _gl.BindFramebuffer(FramebufferTarget.Framebuffer, 0); } public void Dispose() { var fboId = _fboId; var depthStencilRenderbuffer = _depthStencilRenderbuffer; var width = _width; var height = _height; _device.QueueGLAction(gl => { if (fboId != 0) { gl.DeleteFramebuffer(fboId); GpuMemoryTracker.TrackResourceDeallocation(GpuResourceType.FBO); } if (depthStencilRenderbuffer != 0) { gl.DeleteRenderbuffer(depthStencilRenderbuffer); GpuMemoryTracker.TrackResourceDeallocation(GpuResourceType.RBO); GpuMemoryTracker.TrackDeallocation(width * height * 4, GpuResourceType.RBO); } }); } } }