A game framework written with osu! in mind.
at master 103 lines 3.8 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using osu.Framework.Platform; 6using osuTK; 7using osuTK.Graphics.ES30; 8 9namespace osu.Framework.Graphics.OpenGL.Buffers 10{ 11 internal class RenderBuffer : IDisposable 12 { 13 private readonly RenderbufferInternalFormat format; 14 private readonly int renderBuffer; 15 private readonly int sizePerPixel; 16 17 private FramebufferAttachment attachment; 18 19 public RenderBuffer(RenderbufferInternalFormat format) 20 { 21 this.format = format; 22 23 renderBuffer = GL.GenRenderbuffer(); 24 25 GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderBuffer); 26 27 // OpenGL docs don't specify that this is required, but seems to be required on some platforms 28 // to correctly attach in the GL.FramebufferRenderbuffer() call below 29 GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, format, 1, 1); 30 31 attachment = format.GetAttachmentType(); 32 sizePerPixel = format.GetBytesPerPixel(); 33 34 GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, attachment, RenderbufferTarget.Renderbuffer, renderBuffer); 35 } 36 37 private Vector2 internalSize; 38 private NativeMemoryTracker.NativeMemoryLease memoryLease; 39 40 public void Bind(Vector2 size) 41 { 42 size = Vector2.Clamp(size, Vector2.One, new Vector2(GLWrapper.MaxRenderBufferSize)); 43 44 // See: https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_multisampled_render_to_texture.txt 45 // + https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html 46 // OpenGL ES allows the driver to discard renderbuffer contents after they are presented to the screen, so the storage must always be re-initialised for embedded devices. 47 // Such discard does not exist on non-embedded platforms, so they are only re-initialised when required. 48 if (GLWrapper.IsEmbedded || internalSize.X < size.X || internalSize.Y < size.Y) 49 { 50 GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderBuffer); 51 GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, format, (int)Math.Ceiling(size.X), (int)Math.Ceiling(size.Y)); 52 53 if (!GLWrapper.IsEmbedded) 54 { 55 memoryLease?.Dispose(); 56 memoryLease = NativeMemoryTracker.AddMemory(this, (long)(size.X * size.Y * sizePerPixel)); 57 } 58 59 internalSize = size; 60 } 61 } 62 63 public void Unbind() 64 { 65 if (GLWrapper.IsEmbedded) 66 { 67 // Renderbuffers are not automatically discarded on all embedded devices, so invalidation is forced for extra performance and to unify logic between devices. 68 GL.InvalidateFramebuffer(FramebufferTarget.Framebuffer, 1, ref attachment); 69 } 70 } 71 72 #region Disposal 73 74 ~RenderBuffer() 75 { 76 GLWrapper.ScheduleDisposal(() => Dispose(false)); 77 } 78 79 public void Dispose() 80 { 81 Dispose(true); 82 GC.SuppressFinalize(this); 83 } 84 85 private bool isDisposed; 86 87 protected virtual void Dispose(bool disposing) 88 { 89 if (isDisposed) 90 return; 91 92 if (renderBuffer != -1) 93 { 94 memoryLease?.Dispose(); 95 GL.DeleteRenderbuffer(renderBuffer); 96 } 97 98 isDisposed = true; 99 } 100 101 #endregion 102 } 103}