github ppy/osu-framework 2022.805.0

latest releases: 2024.528.1, 2024.528.0, 2024.523.0...
2 years ago

Thanks for following along! This is a tagged release (2022.805.0).

Breaking changes

IRenderer added as parameter to DrawNode

In order to allow the framework to interoperate with different rendering backends, all rendering functions are now performed through a new IRenderer interface and parameter.

- DrawNode.Draw(Action<TexturedVertex2D> vertexAction);
+ DrawNode.Draw(IRenderer renderer);
- DrawNode.DrawOpaqueInterior(Action<TexturedVertex2D> vertexAction);
+ DrawNode.DrawOpaqueInterior(IRenderer renderer);

In places where the vertexAction parameter was previously used (e.g. to draw textures), null can be given as a parameter instead.

GLWrapper removed, replaced by calls through IRenderer

The static GLWrapper class has been removed, and all drawing functions should be performed via the new DrawNode parameter instead. There is a 1-1 API correlation between the classes.

public class MyDrawNode : DrawNode
{
    public override void Draw(IRenderer renderer)
    {
        base.Draw(renderer);

-       GLWrapper.PushDepthInfo(...);
+       renderer.PushDepthInfo(...);

-       GLWrapper.SetBlend(...);
+       renderer.SetBlend(...);

-       GLWrapper.PopDepthInfo();
+       renderer.PopDepthInfo();
    }
}

Texture.WhitePixel has moved to IRenderer

For cases where it's used as a fallback texture, it can be retrieved by resolving an IRenderer into the Drawable class and accessing IRenderer.WhitePixel.

public class MyDrawable : Drawable
{
+   [BackgroundDependencyLoader]
+   private void load(IRenderer renderer)
+   {
+       texture ??= renderer.WhitePixel;
+   }

    private Texture texture;

    public Texture Texture
    {
-       get => texture ?? Texture.WhitePixel;
+       get => texture;
        set => texture = value;
    }
}

Texture drawing methods moved from DrawNode to IRenderer extension methods

Appearing alongside IRenderer is the new RendererExtensions class providing helper methods for common drawing procedures.

public class MyDrawNode : DrawNode
{
    public override void Draw(IRenderer renderer)
    {
        base.Draw(renderer);

-       DrawQuad(renderer.WhitePixel, ...);
+       renderer.DrawQuad(renderer.WhitePixel, ...);
    }
}

All of the following methods have been moved to this class:

DrawTriangle()
DrawQuad()
DrawClipped()
DrawFrameBuffer()

Textures must be created through the IRenderer

Resolve an IRenderer into the Drawable class and use IRenderer.CreateTexture() method to create textures.

public class MyDrawable : Drawable
{
-   private readonly Texture texture;

-   public MyDrawable()
-   {
-       texture = new Texture(100, 100);
-       texture.SetData(...);
-   }
+   private Texture texture;

+   [BackgroundDependencyLoader]
+   private void load(IRenderer renderer)
+   {
+       texture = renderer.CreateTexture(100, 100);
+       texture.SetData(...);
+   }
}

DummyRenderer may be used for cases where textures need to be created and neither an IRenderer nor GameHost is accessible:

[TestFixture]
public class MyTestFixture
{
    public void CreateATexture()
    {
-       Texture texture = new Texture(1, 1);
+       Texture texture = new DummyRenderer().CreateTexture(1, 1);
    }
}

TextureGL is no longer accessible

Properties such as TextureGL.BypassTextureUploadQueueing have been moved to Texture itself, and Texture can be used for all rendering procedures. When rendering, textures are now bound to different sampling units via an integer value.

public class MyDrawable : Drawable
{
    private Texture texture;

    [BackgroundDependencyLoader]
    private void load(IRenderer renderer)
    {
        texture = renderer.CreateTexture(100, 100);
-       texture.TextureGL.BypassUploadQueueing = true;
+       texture.BypassUploadQueueing = true;
        texture.SetData(...);
    }
}

public class MyDrawNode : DrawNode
{
    private Texture texture;

    public override void Draw(IRenderer renderer)
    {
        base.Draw(renderer);

-       texture.TextureGL.Bind();
-       texture.TextureGL.Bind(TextureUnit.Texture1);
+       texture.Bind();
+       texture.Bind(1);

        // Note: The texture binding above isn't required in either case for the call below.
-       DrawQuad(texture.TextureGL, ...);
+       renderer.DrawQuad(texture, ...);
    }
}

The QuadBatch<T> and LinearBatch<T> classes are no longer accessible

Create vertex batches via the IRenderer and store as an IVertexBatch<T> instead:

public class MyDrawNode : DrawNode
{
-   private readonly QuadBatch<TexturedVertex2D> quadBatch = new QuadBatch<TexturedVertex2D>(1, 1);
-   private readonly LinearBatch<TexturedVertex2D> linearBatch = new LinearBatch<TexturedVertex2D>(1, 1, PrimitiveType.Triangles);
+   private IVertexBatch<TexturedVertex2D> quadBatch;
+   private IVertexBatch<TexturedVertex2D> linearBatch;

    public override void Draw(IRenderer renderer)
    {
        base.Draw(renderer);

+       quadBatch ??= renderer.CreateQuadBatch<TexturedVertex2D>(1, 1);
+       linearBatch ??= renderer.CreateLinearBatch<TexturedVertex2D>(1, 1, PrimitiveTopology.Triangles);
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        batch?.Dispose();
    }
}

Beware that when creating linear batches, the type parameter has changed from PrimitiveType to PrimitiveTopology!

The FrameBuffer class is no longer accessible

Create frame buffers via the IRenderer and store as an IFrameBuffer.

public class MyDrawNode : DrawNode
{
-   private readonly FrameBuffer myFrameBuffer = new FrameBuffer(new[] { RenderbufferInternalFormat.DepthComponent16 }, All.Nearest);
+   private IFrameBuffer myFrameBuffer;

    public override void Draw(IRenderer renderer)
    {
        base.Draw(renderer);

+       myFrameBuffer ??= renderer.CreateFrameBuffer(new[] { RenderBufferFormat.D16 }, TextureFilteringMode.Nearest);
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        myFrameBuffer?.Dispose();
    }
}

Beware that the render buffer type parameter has changed from RenderbufferInternalFormat to RenderBufferFormat!

The Shader class is no longer accessible

Shaders are still created via the ShaderManager, but are now returned as IShaders.

public class MyDrawable : Drawable
{
-   private Shader shader;
+   private IShader shader;

    [BackgroundDependencyLoader]
    private void load(ShaderManager shaders)
    {
        shader = shaders.Load("a", "b");
    }
}

TextureStore, FontStore and LargeTextureStore require an IRenderer constructor parameter

One common use case is to provide a new texture store from inside a derived Game, for which the following change is required:

public class TestGame : osu.Framework.Game
{
    private DependencyContainer dependencies;

    protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
        dependencies = new DependencyContainer(base.CreateChildDependencies(parent));

    [BackgroundDependencyLoader]
    private void load()
    {
-       var largeStore = new LargeTextureStore(Host.CreateTextureLoaderStore(new NamespacedResourceStore<byte[]>(Resources, @"Textures")), All.Nearest);
+       var largeStore = new LargeTextureStore(Host.Renderer, Host.CreateTextureLoaderStore(new NamespacedResourceStore<byte[]>(Resources, @"Textures")), TextureFilteringMode.Nearest);
        largeStore.AddTextureSource(Host.CreateTextureLoaderStore(new OnlineStore()));
        dependencies.Cache(largeStore);
    }
}

Beware that the filter mode parameter has changed from All to TextureFilteringMode!

Some TexturedShaderDrawNode members now take an IRenderer parameter

public class MyDrawNode : TexturedShaderDrawNode
{
    public override void Draw(IRenderer renderer)
    {
        base.Draw(renderer);

-       Shader.Bind();
+       var shader = GetAppropriateShader(renderer);
+       shader.Bind();

        // ...

-       Shader.Unbind();
+       shader.Unbind();
    }

-   protected override bool RequiresRoundedShader => ...;
+   protected override bool RequiresRoundedShader(IRenderer renderer) => ...;
}

IVertex, TexturedVertex2D, et al. have been re-namespaced

They are now placed under the osu.Framework.Graphics.Rendering.Vertices namespace

Several enums have been re-namespaced

WrapMode    -> osu.Framework.Graphics.Textures.WrapMode
Opacity     -> osu.Framework.Graphics.Textures.Opacity
ClearInfo   -> osu.Framework.Graphics.Rendering.ClearInfo
MaskingInfo -> osu.Framework.Graphics.Rendering.MaskingInfo
DepthInfo   -> osu.Framework.Graphics.Rendering.DepthInfo

What's Changed

  • Add IRenderer and adjust DrawNode signature by @smoogipoo in #5324
  • Fix ModelBackedDrawable attempting to mutate children after disposal by @peppy in #5329
  • Internalise vertex batches and expose via IVertexBatch by @smoogipoo in #5325
  • Internalise FrameBuffer and expose via IFrameBuffer by @smoogipoo in #5326
  • Internalise Shader and expose via IShader by @smoogipoo in #5327
  • Guard against work being queued on an already-disposed ThreadedTaskScheduler by @peppy in #5320
  • Fix textbox initial commit of empty string being considered "new" due to null equality by @peppy in #5331
  • Internalise TextureGL and rewrite Texture to take its role by @smoogipoo in #5330
  • Fix GetLocalisableDescription() crashing on unnamed enum values by @smoogipoo in #5335
  • Remove GLWrapper and move implementation to IRenderer by @smoogipoo in #5332
  • Fix TestBrowser potentially crashing from null ref on quickly switching scenes by @peppy in #5333
  • Safely restore TPL capacity after test failures by @smoogipoo in #5334
  • Android input handlers refactor by @Susko3 in #5317
  • Move vertices out of the OpenGL namespace by @smoogipoo in #5336

Full Changelog: 2022.730.0...2022.805.0

Don't miss a new osu-framework release

NewReleases is sending notifications on new releases.