Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internalise FrameBuffer and expose via IFrameBuffer #5326

Merged
merged 10 commits into from
Aug 1, 2022
21 changes: 12 additions & 9 deletions osu.Framework/Graphics/BufferedDrawNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics.OpenGL;
using osu.Framework.Graphics.OpenGL.Buffers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Statistics;
Expand All @@ -20,12 +19,12 @@ public class BufferedDrawNode : TexturedShaderDrawNode
protected new IBufferedDrawable Source => (IBufferedDrawable)base.Source;

/// <summary>
/// The child <see cref="DrawNode"/> which is used to populate the <see cref="FrameBuffer"/>s with.
/// The child <see cref="DrawNode"/> which is used to populate the <see cref="IFrameBuffer"/>s with.
/// </summary>
protected DrawNode Child { get; private set; }

/// <summary>
/// Data shared amongst all <see cref="BufferedDrawNode"/>s, providing storage for <see cref="FrameBuffer"/>s.
/// Data shared amongst all <see cref="BufferedDrawNode"/>s, providing storage for <see cref="IFrameBuffer"/>s.
/// </summary>
protected readonly BufferedDrawNodeSharedData SharedData;

Expand Down Expand Up @@ -75,7 +74,7 @@ public override void ApplyState()

/// <summary>
/// Retrieves the version of the state of this <see cref="DrawNode"/>.
/// The <see cref="BufferedDrawNode"/> will only re-render if this version is greater than that of the rendered <see cref="FrameBuffer"/>s.
/// The <see cref="BufferedDrawNode"/> will only re-render if this version is greater than that of the rendered <see cref="IFrameBuffer"/>s.
/// </summary>
/// <remarks>
/// By default, the <see cref="BufferedDrawNode"/> is re-rendered with every <see cref="DrawNode"/> invalidation.
Expand All @@ -85,6 +84,9 @@ public override void ApplyState()

public sealed override void Draw(IRenderer renderer)
{
if (!SharedData.IsInitialised)
SharedData.Initialise(renderer);

if (RequiresRedraw)
{
FrameStatistics.Increment(StatisticsCounterType.FBORedraw);
Expand Down Expand Up @@ -139,26 +141,27 @@ protected virtual void DrawContents(IRenderer renderer)
}

/// <summary>
/// Binds and initialises a <see cref="FrameBuffer"/> if required.
/// Binds and initialises an <see cref="IFrameBuffer"/> if required.
/// </summary>
/// <param name="frameBuffer">The <see cref="FrameBuffer"/> to bind.</param>
/// <param name="frameBuffer">The <see cref="IFrameBuffer"/> to bind.</param>
/// <returns>A token that must be disposed upon finishing use of <paramref name="frameBuffer"/>.</returns>
protected IDisposable BindFrameBuffer(FrameBuffer frameBuffer)
protected IDisposable BindFrameBuffer(IFrameBuffer frameBuffer)
{
// This setter will also take care of allocating a texture of appropriate size within the frame buffer.
frameBuffer.Size = frameBufferSize;

frameBuffer.Bind();

return new ValueInvokeOnDisposal<FrameBuffer>(frameBuffer, b => b.Unbind());
return new ValueInvokeOnDisposal<IFrameBuffer>(frameBuffer, b => b.Unbind());
}

private IDisposable establishFrameBufferViewport()
{
// Disable masking for generating the frame buffer since masking will be re-applied
// when actually drawing later on anyways. This allows more information to be captured
// in the frame buffer and helps with cached buffers being re-used.
RectangleI screenSpaceMaskingRect = new RectangleI((int)Math.Floor(screenSpaceDrawRectangle.X), (int)Math.Floor(screenSpaceDrawRectangle.Y), (int)frameBufferSize.X + 1, (int)frameBufferSize.Y + 1);
RectangleI screenSpaceMaskingRect = new RectangleI((int)Math.Floor(screenSpaceDrawRectangle.X), (int)Math.Floor(screenSpaceDrawRectangle.Y), (int)frameBufferSize.X + 1,
(int)frameBufferSize.Y + 1);

GLWrapper.PushMaskingInfo(new MaskingInfo
{
Expand Down
55 changes: 35 additions & 20 deletions osu.Framework/Graphics/BufferedDrawNodeSharedData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

using System;
using osu.Framework.Graphics.OpenGL;
using osu.Framework.Graphics.OpenGL.Buffers;
using osuTK.Graphics.ES30;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Textures;

namespace osu.Framework.Graphics
{
Expand All @@ -25,9 +25,9 @@ public class BufferedDrawNodeSharedData : IDisposable
internal long DrawVersion = -1;

/// <summary>
/// The <see cref="FrameBuffer"/> which contains the original version of the rendered <see cref="Drawable"/>.
/// The <see cref="IFrameBuffer"/> which contains the original version of the rendered <see cref="Drawable"/>.
/// </summary>
public FrameBuffer MainBuffer { get; }
public IFrameBuffer MainBuffer { get; private set; }

/// <summary>
/// Whether the frame buffer position should be snapped to the nearest pixel when blitting.
Expand All @@ -40,15 +40,19 @@ public class BufferedDrawNodeSharedData : IDisposable
/// </summary>
public readonly bool ClipToRootNode;

public bool IsInitialised { get; private set; }

/// <summary>
/// A set of <see cref="FrameBuffer"/>s which are used in a ping-pong manner to render effects to.
/// A set of <see cref="IFrameBuffer"/>s which are used in a ping-pong manner to render effects to.
/// </summary>
private readonly FrameBuffer[] effectBuffers;
private readonly IFrameBuffer[] effectBuffers;

private readonly RenderBufferFormat[] formats;

/// <summary>
/// Creates a new <see cref="BufferedDrawNodeSharedData"/> with no effect buffers.
/// </summary>
public BufferedDrawNodeSharedData(RenderbufferInternalFormat[] formats = null, bool pixelSnapping = false, bool clipToRootNode = false)
public BufferedDrawNodeSharedData(RenderBufferFormat[] formats = null, bool pixelSnapping = false, bool clipToRootNode = false)
: this(0, formats, pixelSnapping, clipToRootNode)
{
}
Expand All @@ -62,35 +66,44 @@ public BufferedDrawNodeSharedData(RenderbufferInternalFormat[] formats = null, b
/// This amounts to setting the texture filtering mode to "nearest".</param>
/// <param name="clipToRootNode">Whether the frame buffer should be clipped to be contained in the root node..</param>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="effectBufferCount"/> is less than 0.</exception>
public BufferedDrawNodeSharedData(int effectBufferCount, RenderbufferInternalFormat[] formats = null, bool pixelSnapping = false, bool clipToRootNode = false)
public BufferedDrawNodeSharedData(int effectBufferCount, RenderBufferFormat[] formats = null, bool pixelSnapping = false, bool clipToRootNode = false)
{
if (effectBufferCount < 0)
throw new ArgumentOutOfRangeException(nameof(effectBufferCount), "Must be positive.");

this.formats = formats;
PixelSnapping = pixelSnapping;
All filterMode = pixelSnapping ? All.Nearest : All.Linear;

ClipToRootNode = clipToRootNode;

MainBuffer = new FrameBuffer(formats, filterMode);
effectBuffers = new FrameBuffer[effectBufferCount];
effectBuffers = new IFrameBuffer[effectBufferCount];
}

public void Initialise(IRenderer renderer)
{
if (IsInitialised)
return;

TextureFilteringMode filterMode = PixelSnapping ? TextureFilteringMode.Nearest : TextureFilteringMode.Linear;

MainBuffer = renderer.CreateFrameBuffer(formats, filterMode);
for (int i = 0; i < effectBuffers.Length; i++)
effectBuffers[i] = renderer.CreateFrameBuffer(formats, filterMode);

for (int i = 0; i < effectBufferCount; i++)
effectBuffers[i] = new FrameBuffer(formats, filterMode);
IsInitialised = true;
}

private int currentEffectBuffer = -1;

/// <summary>
/// The <see cref="FrameBuffer"/> which contains the most up-to-date drawn effect.
/// The <see cref="IFrameBuffer"/> which contains the most up-to-date drawn effect.
/// </summary>
public FrameBuffer CurrentEffectBuffer => currentEffectBuffer == -1 ? MainBuffer : effectBuffers[currentEffectBuffer];
public IFrameBuffer CurrentEffectBuffer => currentEffectBuffer == -1 ? MainBuffer : effectBuffers[currentEffectBuffer];

/// <summary>
/// Retrieves the next <see cref="FrameBuffer"/> which effects can be rendered to.
/// Retrieves the next <see cref="IFrameBuffer"/> which effects can be rendered to.
/// </summary>
/// <exception cref="InvalidOperationException">If there are no available effect buffers.</exception>
public FrameBuffer GetNextEffectBuffer()
public IFrameBuffer GetNextEffectBuffer()
{
if (effectBuffers.Length == 0)
throw new InvalidOperationException($"The {nameof(BufferedDrawNode)} requested an effect buffer, but none were available.");
Expand All @@ -114,10 +127,12 @@ public void Dispose()

protected virtual void Dispose(bool isDisposing)
{
MainBuffer.Dispose();
if (!IsInitialised)
return;

MainBuffer?.Dispose();
for (int i = 0; i < effectBuffers.Length; i++)
effectBuffers[i].Dispose();
effectBuffers[i]?.Dispose();
}
}
}
6 changes: 3 additions & 3 deletions osu.Framework/Graphics/Containers/BufferedContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

using osuTK;
using osuTK.Graphics;
using osuTK.Graphics.ES30;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Utils;
using osu.Framework.Graphics.Sprites;
Expand All @@ -28,7 +28,7 @@ namespace osu.Framework.Graphics.Containers
public class BufferedContainer : BufferedContainer<Drawable>
{
/// <inheritdoc />
public BufferedContainer(RenderbufferInternalFormat[] formats = null, bool pixelSnapping = false, bool cachedFrameBuffer = false)
public BufferedContainer(RenderBufferFormat[] formats = null, bool pixelSnapping = false, bool cachedFrameBuffer = false)
: base(formats, pixelSnapping, cachedFrameBuffer)
{
}
Expand Down Expand Up @@ -255,7 +255,7 @@ public bool RedrawOnScale
/// or the size of the container (i.e. framebuffer) changes.
/// When disabled, drawing will be clipped to the game window bounds. Enabling can allow drawing larger than (or outside) the game window bounds.
/// </param>
public BufferedContainer(RenderbufferInternalFormat[] formats = null, bool pixelSnapping = false, bool cachedFrameBuffer = false)
public BufferedContainer(RenderBufferFormat[] formats = null, bool pixelSnapping = false, bool cachedFrameBuffer = false)
{
UsingCachedFrameBuffer = cachedFrameBuffer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

using System.Collections.Generic;
using osu.Framework.Graphics.OpenGL;
using osu.Framework.Graphics.OpenGL.Buffers;
using osuTK;
using osuTK.Graphics;
using osu.Framework.Graphics.Primitives;
Expand All @@ -14,7 +13,6 @@
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Utils;
using osuTK.Graphics.ES30;

namespace osu.Framework.Graphics.Containers
{
Expand Down Expand Up @@ -97,8 +95,8 @@ protected override void DrawContents(IRenderer renderer)

private void drawBlurredFrameBuffer(int kernelRadius, float sigma, float blurRotation)
{
FrameBuffer current = SharedData.CurrentEffectBuffer;
FrameBuffer target = SharedData.GetNextEffectBuffer();
IFrameBuffer current = SharedData.CurrentEffectBuffer;
IFrameBuffer target = SharedData.GetNextEffectBuffer();

GLWrapper.SetBlend(BlendingParameters.None);

Expand Down Expand Up @@ -131,7 +129,7 @@ public List<DrawNode> Children

private class BufferedContainerDrawNodeSharedData : BufferedDrawNodeSharedData
{
public BufferedContainerDrawNodeSharedData(RenderbufferInternalFormat[] formats, bool pixelSnapping, bool clipToRootNode)
public BufferedContainerDrawNodeSharedData(RenderBufferFormat[] formats, bool pixelSnapping, bool clipToRootNode)
: base(2, formats, pixelSnapping, clipToRootNode)
{
}
Expand Down
11 changes: 5 additions & 6 deletions osu.Framework/Graphics/DrawNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.OpenGL;
using osu.Framework.Graphics.OpenGL.Batches;
using osu.Framework.Graphics.OpenGL.Buffers;
using osu.Framework.Graphics.OpenGL.Textures;
using osu.Framework.Graphics.OpenGL.Vertices;
using osu.Framework.Graphics.Primitives;
Expand Down Expand Up @@ -260,22 +259,22 @@ protected void DrawClipped<T>(ref T polygon, TextureGL texture, ColourInfo drawC
}

/// <summary>
/// Draws a <see cref="FrameBuffer"/> to the screen.
/// Draws an <see cref="IFrameBuffer"/> to the screen.
/// </summary>
/// <param name="frameBuffer">The <see cref="FrameBuffer"/> to draw.</param>
/// <param name="frameBuffer">The <see cref="IFrameBuffer"/> to draw.</param>
/// <param name="vertexQuad">The destination vertices.</param>
/// <param name="drawColour">The colour to draw the <paramref name="frameBuffer"/> with.</param>
/// <param name="vertexAction">An action that adds vertices to a <see cref="VertexBatch{T}"/>.</param>
/// <param name="inflationPercentage">The percentage amount that the frame buffer area should be inflated.</param>
/// <param name="blendRangeOverride">The range over which the edges of the frame buffer should be blended.</param>
protected void DrawFrameBuffer(FrameBuffer frameBuffer, Quad vertexQuad, ColourInfo drawColour, Action<TexturedVertex2D> vertexAction = null,
protected void DrawFrameBuffer(IFrameBuffer frameBuffer, Quad vertexQuad, ColourInfo drawColour, Action<TexturedVertex2D> vertexAction = null,
Vector2? inflationPercentage = null, Vector2? blendRangeOverride = null)
{
// The strange Y coordinate and Height are a result of OpenGL coordinate systems having Y grow upwards and not downwards.
RectangleF textureRect = new RectangleF(0, frameBuffer.Texture.Height, frameBuffer.Texture.Width, -frameBuffer.Texture.Height);

if (frameBuffer.Texture.Bind())
DrawQuad(frameBuffer.Texture, vertexQuad, drawColour, textureRect, vertexAction, inflationPercentage, blendRangeOverride);
if (frameBuffer.Texture.TextureGL.Bind())
DrawQuad(frameBuffer.Texture.TextureGL, vertexQuad, drawColour, textureRect, vertexAction, inflationPercentage, blendRangeOverride);
frenzibyte marked this conversation as resolved.
Show resolved Hide resolved
}

/// <summary>
Expand Down
14 changes: 7 additions & 7 deletions osu.Framework/Graphics/IBufferedDrawable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#nullable disable

using osu.Framework.Graphics.OpenGL.Buffers;
using osu.Framework.Graphics.Rendering;
using osuTK;
using osuTK.Graphics;

Expand All @@ -15,26 +15,26 @@ namespace osu.Framework.Graphics
public interface IBufferedDrawable : ITexturedShaderDrawable
{
/// <summary>
/// The background colour of the <see cref="FrameBuffer"/>s.
/// The background colour of the <see cref="IFrameBuffer"/>s.
/// Visually changes the colour which rendered alpha is blended against.
/// </summary>
/// <remarks>
/// This should generally be transparent-black or transparent-white, but can also be used to
/// colourise the background colour of the <see cref="FrameBuffer"/> with non-transparent colours.
/// colourise the background colour of the <see cref="IFrameBuffer"/> with non-transparent colours.
/// </remarks>
Color4 BackgroundColour { get; }

/// <summary>
/// The colour with which the <see cref="FrameBuffer"/>s are rendered to the screen.
/// A null value implies the <see cref="FrameBuffer"/>s should be drawn as they are.
/// The colour with which the <see cref="IFrameBuffer"/>s are rendered to the screen.
/// A null value implies the <see cref="IFrameBuffer"/>s should be drawn as they are.
/// </summary>
DrawColourInfo? FrameBufferDrawColour { get; }

/// <summary>
/// The scale of the <see cref="FrameBuffer"/>s drawn relative to the size of this <see cref="IBufferedDrawable"/>.
/// The scale of the <see cref="IFrameBuffer"/>s drawn relative to the size of this <see cref="IBufferedDrawable"/>.
/// </summary>
/// <remarks>
/// The contents of the <see cref="FrameBuffer"/>s are populated at this scale, however the scale of <see cref="Drawable"/>s remains unaffected.
/// The contents of the <see cref="IFrameBuffer"/>s are populated at this scale, however the scale of <see cref="Drawable"/>s remains unaffected.
/// </remarks>
Vector2 FrameBufferScale { get; }
}
Expand Down
4 changes: 2 additions & 2 deletions osu.Framework/Graphics/Lines/Path.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
using System.Collections.Generic;
using osu.Framework.Caching;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Rendering;
using osuTK.Graphics;
using osuTK.Graphics.ES30;

namespace osu.Framework.Graphics.Lines
{
Expand Down Expand Up @@ -281,7 +281,7 @@ protected Texture Texture

public Color4 BackgroundColour => new Color4(0, 0, 0, 0);

private readonly BufferedDrawNodeSharedData sharedData = new BufferedDrawNodeSharedData(new[] { RenderbufferInternalFormat.DepthComponent16 }, clipToRootNode: true);
private readonly BufferedDrawNodeSharedData sharedData = new BufferedDrawNodeSharedData(new[] { RenderBufferFormat.D16 }, clipToRootNode: true);

protected override DrawNode CreateDrawNode() => new BufferedDrawNode(this, new PathDrawNode(this), sharedData);

Expand Down
Loading