Merge pull request #23034 from peppy/fix-ruleset-shader-caching

Fix stutters during gameplay due to shaders not correctly using cache
This commit is contained in:
Dean Herbert 2023-04-03 00:20:48 +09:00 committed by GitHub
commit ea42e7f3fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 43 additions and 33 deletions

View File

@ -11,7 +11,7 @@
<AndroidManifestMerger>manifestmerger.jar</AndroidManifestMerger>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.327.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.402.1" />
</ItemGroup>
<ItemGroup>
<AndroidManifestOverlay Include="$(MSBuildThisFileDirectory)osu.Android\Properties\AndroidManifestOverlay.xml" />

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using NUnit.Framework;
@ -51,9 +49,11 @@ namespace osu.Game.Tests.Testing
[Test]
public void TestRetrieveShader()
{
AddAssert("ruleset shaders retrieved", () =>
Dependencies.Get<ShaderManager>().LoadRaw(@"sh_TestVertex.vs") != null &&
Dependencies.Get<ShaderManager>().LoadRaw(@"sh_TestFragment.fs") != null);
AddStep("ruleset shaders retrieved without error", () =>
{
Dependencies.Get<ShaderManager>().LoadRaw(@"sh_TestVertex.vs");
Dependencies.Get<ShaderManager>().LoadRaw(@"sh_TestFragment.fs");
});
}
[Test]
@ -76,12 +76,12 @@ namespace osu.Game.Tests.Testing
}
public override IResourceStore<byte[]> CreateResourceStore() => new NamespacedResourceStore<byte[]>(TestResources.GetStore(), @"Resources");
public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new TestRulesetConfigManager();
public override IRulesetConfigManager CreateConfig(SettingsStore? settings) => new TestRulesetConfigManager();
public override IEnumerable<Mod> GetModsFor(ModType type) => Array.Empty<Mod>();
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => null;
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => null;
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => null;
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod>? mods = null) => null!;
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => null!;
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => null!;
}
private class TestRulesetConfigManager : IRulesetConfigManager

View File

@ -55,7 +55,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu
set => valueText.Text = value.ToLocalisableString("N0");
}
public CountSection(LocalisableString header)
protected CountSection(LocalisableString header)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;

View File

@ -75,7 +75,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
if (window != null)
{
currentDisplay.BindTo(window.CurrentDisplayBindable);
windowModes.BindTo(window.SupportedWindowModes);
window.DisplaysChanged += onDisplaysChanged;
}
@ -87,7 +86,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
windowModeDropdown = new SettingsDropdown<WindowMode>
{
LabelText = GraphicsSettingsStrings.ScreenMode,
ItemSource = windowModes,
Items = window?.SupportedWindowModes,
Current = config.GetBindable<WindowMode>(FrameworkSetting.WindowMode),
},
displayDropdown = new DisplaySettingsDropdown

View File

@ -25,21 +25,28 @@ namespace osu.Game.Rulesets.UI
/// <summary>
/// The texture store to be used for the ruleset.
/// </summary>
/// <remarks>
/// Reads textures from the "Textures" folder in ruleset resources.
/// If not available locally, lookups will fallback to the global texture store.
/// </remarks>
public TextureStore TextureStore { get; }
/// <summary>
/// The sample store to be used for the ruleset.
/// </summary>
/// <remarks>
/// This is the local sample store pointing to the ruleset sample resources,
/// the cached sample store (<see cref="FallbackSampleStore"/>) retrieves from
/// this store and falls back to the parent store if this store doesn't have the requested sample.
/// Reads samples from the "Samples" folder in ruleset resources.
/// If not available locally, lookups will fallback to the global sample store.
/// </remarks>
public ISampleStore SampleStore { get; }
/// <summary>
/// The shader manager to be used for the ruleset.
/// </summary>
/// <remarks>
/// Reads shaders from the "Shaders" folder in ruleset resources.
/// If not available locally, lookups will fallback to the global shader manager.
/// </remarks>
public ShaderManager ShaderManager { get; }
/// <summary>
@ -61,8 +68,7 @@ namespace osu.Game.Rulesets.UI
SampleStore.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY;
CacheAs(SampleStore = new FallbackSampleStore(SampleStore, parent.Get<ISampleStore>()));
ShaderManager = new ShaderManager(host.Renderer, new NamespacedResourceStore<byte[]>(resources, @"Shaders"));
CacheAs(ShaderManager = new FallbackShaderManager(host.Renderer, ShaderManager, parent.Get<ShaderManager>()));
CacheAs(ShaderManager = new RulesetShaderManager(host.Renderer, new NamespacedResourceStore<byte[]>(resources, @"Shaders"), parent.Get<ShaderManager>()));
RulesetConfigManager = parent.Get<IRulesetConfigCache>().GetConfigFor(ruleset);
if (RulesetConfigManager != null)
@ -190,24 +196,27 @@ namespace osu.Game.Rulesets.UI
}
}
private class FallbackShaderManager : ShaderManager
private class RulesetShaderManager : ShaderManager
{
private readonly ShaderManager primary;
private readonly ShaderManager fallback;
private readonly ShaderManager parent;
public FallbackShaderManager(IRenderer renderer, ShaderManager primary, ShaderManager fallback)
: base(renderer, new ResourceStore<byte[]>())
public RulesetShaderManager(IRenderer renderer, NamespacedResourceStore<byte[]> rulesetResources, ShaderManager parent)
: base(renderer, rulesetResources)
{
this.primary = primary;
this.fallback = fallback;
this.parent = parent;
}
public override byte[]? LoadRaw(string name) => primary.LoadRaw(name) ?? fallback.LoadRaw(name);
protected override void Dispose(bool disposing)
public override IShader Load(string vertex, string fragment)
{
base.Dispose(disposing);
if (primary.IsNotNull()) primary.Dispose();
try
{
return base.Load(vertex, fragment);
}
catch
{
// Shader lookup is very non-standard. Rather than returning null on missing shaders, exceptions are thrown.
return parent.Load(vertex, fragment);
}
}
}
}

View File

@ -130,6 +130,8 @@ namespace osu.Game.Screens
loadTargets.Add(manager.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE));
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, "TriangleBorder"));
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_3, FragmentShaderDescriptor.TEXTURE));
}

View File

@ -36,8 +36,8 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Realm" Version="10.20.0" />
<PackageReference Include="ppy.osu.Framework" Version="2023.327.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.320.0" />
<PackageReference Include="ppy.osu.Framework" Version="2023.402.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.402.0" />
<PackageReference Include="Sentry" Version="3.28.1" />
<PackageReference Include="SharpCompress" Version="0.32.2" />
<PackageReference Include="NUnit" Version="3.13.3" />

View File

@ -16,6 +16,6 @@
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.327.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.402.1" />
</ItemGroup>
</Project>