Skip to content

Commit

Permalink
Merge pull request #5924 from frenzibyte/fix-texture-upload-on-intel-mac
Browse files Browse the repository at this point in the history
Fix texture uploads getting corrupted on Metal with non-Apple GPUs
  • Loading branch information
peppy authored Jul 12, 2023
2 parents 7a22dc8 + 0b90a58 commit 4f605e2
Showing 1 changed file with 35 additions and 1 deletion.
36 changes: 35 additions & 1 deletion osu.Framework/Graphics/Veldrid/VeldridRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ protected internal override bool AllowTearing
public CommandList Commands { get; private set; } = null!;
public CommandList BufferUpdateCommands { get; private set; } = null!;

public CommandList TextureUpdateCommands { get; private set; } = null!;

private bool beganTextureUpdateCommands;

/// <summary>
/// A list of fences which tracks in-flight frames for the purpose of knowing the last completed frame.
/// This is tracked for the purpose of exposing <see cref="LatestCompletedFrameIndex"/>.
Expand Down Expand Up @@ -215,6 +219,7 @@ protected override void Initialise(IGraphicsSurface graphicsSurface)

Commands = Factory.CreateCommandList();
BufferUpdateCommands = Factory.CreateCommandList();
TextureUpdateCommands = Factory.CreateCommandList();

pipeline.Outputs = Device.SwapchainFramebuffer.OutputDescription;
}
Expand Down Expand Up @@ -355,9 +360,11 @@ protected override bool SetTextureImplementation(INativeTexture? texture, int un
public void UpdateTexture<T>(global::Veldrid.Texture texture, int x, int y, int width, int height, int level, ReadOnlySpan<T> data)
where T : unmanaged
{
ensureTextureUploadCommandsBegan();

var staging = stagingTexturePool.Get(width, height, texture.Format);
Device.UpdateTexture(staging, data, 0, 0, 0, (uint)width, (uint)height, 1, (uint)level, 0);
BufferUpdateCommands.CopyTexture(staging, 0, 0, 0, 0, 0, texture, (uint)x, (uint)y, 0, (uint)level, 0, (uint)width, (uint)height, 1, 1);
TextureUpdateCommands.CopyTexture(staging, 0, 0, 0, 0, 0, texture, (uint)x, (uint)y, 0, (uint)level, 0, (uint)width, (uint)height, 1, 1);
}

/// <summary>
Expand Down Expand Up @@ -490,6 +497,13 @@ public void BindUniformBuffer(string blockName, IVeldridUniformBuffer veldridBuf

public void DrawVertices(PrimitiveTopology type, int indexStart, int indicesCount)
{
// normally we would flush/submit all texture upload commands at the end of the frame, since no actual rendering by the GPU will happen until then,
// but turns out on macOS with non-apple GPU, this results in rendering corruption.
// flushing the texture upload commands here before a draw call fixes the corruption, and there's no explanation as to why that's the case,
// but there is nothing to be lost in flushing here except for a frame that contains many sprites with Texture.BypassTextureUploadQueue = true.
// until that appears to be problem, let's just flush here.
flushTextureUploadCommands();

var veldridShader = (VeldridShader)Shader!;

pipeline.PrimitiveTopology = type;
Expand Down Expand Up @@ -541,6 +555,26 @@ public void DrawVertices(PrimitiveTopology type, int indexStart, int indicesCoun
Commands.DrawIndexed((uint)indicesCount, 1, (uint)indexStart, 0, 0);
}

private void ensureTextureUploadCommandsBegan()
{
if (beganTextureUpdateCommands)
return;

TextureUpdateCommands.Begin();
beganTextureUpdateCommands = true;
}

private void flushTextureUploadCommands()
{
if (!beganTextureUpdateCommands)
return;

TextureUpdateCommands.End();
Device.SubmitCommands(TextureUpdateCommands);

beganTextureUpdateCommands = false;
}

/// <summary>
/// Checks whether the given frame buffer is currently bound.
/// </summary>
Expand Down

0 comments on commit 4f605e2

Please sign in to comment.