mirror of
https://github.com/SK-la/osu-framework.git
synced 2026-03-15 03:20:30 +00:00
Merge branch 'master' into mobile-ffmpeg
# Conflicts: # osu.Framework.Android/AndroidGameHost.cs
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
<TargetFrameworks>netcoreapp2.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Cake" Version="0.32.1" />
|
||||
<PackageReference Include="Cake.CoreCLR" Version="0.32.1" />
|
||||
<PackageReference Include="Cake" Version="0.34.1" />
|
||||
<PackageReference Include="Cake.CoreCLR" Version="0.34.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using osu.Framework.Android.Graphics.Textures;
|
||||
using osu.Framework.Android.Graphics.Video;
|
||||
using osu.Framework.Android.Input;
|
||||
@@ -13,6 +14,7 @@ using osu.Framework.Input;
|
||||
using osu.Framework.Input.Handlers;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Platform;
|
||||
using Uri = Android.Net.Uri;
|
||||
|
||||
namespace osu.Framework.Android
|
||||
{
|
||||
@@ -51,7 +53,13 @@ namespace osu.Framework.Android
|
||||
=> throw new NotImplementedException();
|
||||
|
||||
public override void OpenUrlExternally(string url)
|
||||
=> throw new NotImplementedException();
|
||||
{
|
||||
var activity = (Activity)gameView.Context;
|
||||
|
||||
using (var intent = new Intent(Intent.ActionView, Uri.Parse(url)))
|
||||
if (intent.ResolveActivity(activity.PackageManager) != null)
|
||||
activity.StartActivity(intent);
|
||||
}
|
||||
|
||||
public override IResourceStore<TextureUpload> CreateTextureLoaderStore(IResourceStore<byte[]> underlyingStore)
|
||||
=> new AndroidTextureLoaderStore(underlyingStore);
|
||||
|
||||
65
osu.Framework.Tests/Graphics/ShaderRegexTest.cs
Normal file
65
osu.Framework.Tests/Graphics/ShaderRegexTest.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
// 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.
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
|
||||
namespace osu.Framework.Tests.Graphics
|
||||
{
|
||||
[TestFixture]
|
||||
public class ShaderRegexTest
|
||||
{
|
||||
private readonly Regex shaderAttributeRegex = new Regex(ShaderPart.SHADER_ATTRIBUTE_PATTERN);
|
||||
|
||||
[Test]
|
||||
public void TestComment()
|
||||
{
|
||||
const string test_string = "// The following implementation using mix and step may be faster, but stackoverflow indicates it is in fact a lot slower on some GPUs.";
|
||||
performInvalidAttributeTest(test_string);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNonAttribute()
|
||||
{
|
||||
const string test_string = "varying vec3 name;";
|
||||
performInvalidAttributeTest(test_string);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestValidAttribute()
|
||||
{
|
||||
const string test_string = "attribute lowp float name;";
|
||||
performValidAttributeTest(test_string);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSpacedAttribute()
|
||||
{
|
||||
const string test_string = " attribute float name ;";
|
||||
performValidAttributeTest(test_string);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoPrecisionQualifier()
|
||||
{
|
||||
const string test_string = "attribute float name;";
|
||||
performValidAttributeTest(test_string);
|
||||
}
|
||||
|
||||
private void performValidAttributeTest(string testString)
|
||||
{
|
||||
var match = shaderAttributeRegex.Match(testString);
|
||||
|
||||
Assert.IsTrue(match.Success);
|
||||
Assert.AreEqual("name", match.Groups[1].Value.Trim());
|
||||
}
|
||||
|
||||
private void performInvalidAttributeTest(string testString)
|
||||
{
|
||||
var match = shaderAttributeRegex.Match(testString);
|
||||
|
||||
Assert.IsFalse(match.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,10 @@ using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
|
||||
namespace osu.Framework.Tests.Visual.Containers
|
||||
@@ -88,7 +90,7 @@ namespace osu.Framework.Tests.Visual.Containers
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the result of a <see cref="Container{T}.Contains(T)"/> operation is valid between multiple containers.
|
||||
/// This tests whether the comparator + equality operation in <see cref="CompositeDrawable.IndexOfInternal(Graphics.Drawable)"/> is valid.
|
||||
/// This tests whether the comparator + equality operation in <see cref="CompositeDrawable.IndexOfInternal(Drawable)"/> is valid.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestContainerContains()
|
||||
@@ -178,5 +180,59 @@ namespace osu.Framework.Tests.Visual.Containers
|
||||
|
||||
Assert.That(disposed, Is.EqualTo(shouldDispose));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAsyncLoadClearWhileAsyncDisposing()
|
||||
{
|
||||
Container safeContainer = null;
|
||||
DelayedLoadDrawable drawable = null;
|
||||
|
||||
// We are testing a disposal deadlock scenario. When the test runner exits, it will attempt to dispose the game hierarchy,
|
||||
// and will fall into the deadlocked state itself. For this reason an intermediate "safe" container is used, which is
|
||||
// removed from the hierarchy immediately after use and is thus not disposed when the test runner exits.
|
||||
// This does NOT free up the LoadComponentAsync thread pool for use by other tests - that thread is in a deadlocked state forever.
|
||||
AddStep("add safe container", () => Add(safeContainer = new Container()));
|
||||
|
||||
// Get the drawable into an async loading state
|
||||
AddStep("begin async load", () =>
|
||||
{
|
||||
safeContainer.LoadComponentAsync(drawable = new DelayedLoadDrawable(), _ => { });
|
||||
Remove(safeContainer);
|
||||
});
|
||||
|
||||
AddUntilStep("wait until loading", () => drawable.LoadState == LoadState.Loading);
|
||||
|
||||
// Make the async disposal queue attempt to dispose the drawable
|
||||
AddStep("enqueue async disposal", () => AsyncDisposalQueue.Enqueue(drawable));
|
||||
AddWaitStep("wait for disposal task to run", 10);
|
||||
|
||||
// Clear the contents of the drawable, causing a second async disposal
|
||||
AddStep("allow load", () => drawable.AllowLoad.Set());
|
||||
|
||||
AddUntilStep("drawable was cleared successfully", () => drawable.HasCleared);
|
||||
}
|
||||
|
||||
private class DelayedLoadDrawable : CompositeDrawable
|
||||
{
|
||||
public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim();
|
||||
|
||||
public bool HasCleared { get; private set; }
|
||||
|
||||
public DelayedLoadDrawable()
|
||||
{
|
||||
InternalChild = new Box();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
if (!AllowLoad.Wait(TimeSpan.FromSeconds(10)))
|
||||
throw new TimeoutException();
|
||||
|
||||
ClearInternal();
|
||||
|
||||
HasCleared = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
<Reference Include="mscorlib" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<NativeReference Include="..\osu.Framework.NativeLibs\ios\*.a">
|
||||
<NativeReference Include="..\osu.Framework.iOS\*.a">
|
||||
<Kind>Static</Kind>
|
||||
<SmartLink>False</SmartLink>
|
||||
<ForceLoad>True</ForceLoad>
|
||||
|
||||
@@ -35,4 +35,12 @@
|
||||
<PackageReference Include="ppy.osuTK.iOS" Version="1.0.111" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0006" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<NativeLibs Include="$(MSBuildThisFileDirectory)\*.a" />
|
||||
<None Include="@(NativeLibs)">
|
||||
<Pack>true</Pack>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -15,28 +15,36 @@ namespace osu.Framework.Allocation
|
||||
{
|
||||
private static readonly GlobalStatistic<string> last_disposal = GlobalStatistics.Get<string>("Drawable", "Last disposal");
|
||||
|
||||
private static readonly Queue<IDisposable> disposal_queue = new Queue<IDisposable>();
|
||||
private static readonly List<IDisposable> disposal_queue = new List<IDisposable>();
|
||||
|
||||
private static Task runTask;
|
||||
|
||||
public static void Enqueue(IDisposable disposable)
|
||||
{
|
||||
lock (disposal_queue)
|
||||
disposal_queue.Enqueue(disposable);
|
||||
disposal_queue.Add(disposable);
|
||||
|
||||
if (runTask?.Status < TaskStatus.Running)
|
||||
return;
|
||||
|
||||
runTask = Task.Run(() =>
|
||||
{
|
||||
IDisposable[] itemsToDispose;
|
||||
|
||||
lock (disposal_queue)
|
||||
{
|
||||
while (disposal_queue.Count > 0)
|
||||
{
|
||||
var toDispose = disposal_queue.Dequeue();
|
||||
last_disposal.Value = toDispose.ToString();
|
||||
toDispose.Dispose();
|
||||
}
|
||||
itemsToDispose = disposal_queue.ToArray();
|
||||
disposal_queue.Clear();
|
||||
}
|
||||
|
||||
for (int i = 0; i < itemsToDispose.Length; i++)
|
||||
{
|
||||
ref var item = ref itemsToDispose[i];
|
||||
|
||||
last_disposal.Value = item.ToString();
|
||||
item.Dispose();
|
||||
|
||||
item = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,11 +6,6 @@ using System;
|
||||
|
||||
namespace osu.Framework.Caching
|
||||
{
|
||||
public static class StaticCached
|
||||
{
|
||||
internal static bool BypassCache = false;
|
||||
}
|
||||
|
||||
public struct Cached<T>
|
||||
{
|
||||
private T value;
|
||||
@@ -35,7 +30,7 @@ namespace osu.Framework.Caching
|
||||
|
||||
private bool isValid;
|
||||
|
||||
public bool IsValid => !StaticCached.BypassCache && isValid;
|
||||
public bool IsValid => isValid;
|
||||
|
||||
public static implicit operator T(Cached<T> value) => value.Value;
|
||||
|
||||
@@ -60,7 +55,7 @@ namespace osu.Framework.Caching
|
||||
{
|
||||
private bool isValid;
|
||||
|
||||
public bool IsValid => !StaticCached.BypassCache && isValid;
|
||||
public bool IsValid => isValid;
|
||||
|
||||
/// <summary>
|
||||
/// Invalidate the cache of this object.
|
||||
|
||||
@@ -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.
|
||||
|
||||
using osu.Framework.Caching;
|
||||
|
||||
namespace osu.Framework.Configuration
|
||||
{
|
||||
public class FrameworkDebugConfigManager : IniConfigManager<DebugSetting>
|
||||
@@ -18,14 +16,12 @@ namespace osu.Framework.Configuration
|
||||
{
|
||||
base.InitialiseDefaults();
|
||||
|
||||
Set(DebugSetting.BypassCaching, false).ValueChanged += delegate { StaticCached.BypassCache = Get<bool>(DebugSetting.BypassCaching); };
|
||||
Set(DebugSetting.BypassFrontToBackPass, false);
|
||||
}
|
||||
}
|
||||
|
||||
public enum DebugSetting
|
||||
{
|
||||
BypassCaching,
|
||||
BypassFrontToBackPass
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ using osu.Framework.Graphics.OpenGL.Vertices;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Graphics.ES30;
|
||||
|
||||
namespace osu.Framework.Graphics
|
||||
{
|
||||
@@ -38,18 +37,11 @@ namespace osu.Framework.Graphics
|
||||
private RectangleF screenSpaceDrawRectangle;
|
||||
private Vector2 frameBufferSize;
|
||||
|
||||
private readonly All filteringMode;
|
||||
private readonly RenderbufferInternalFormat[] formats;
|
||||
|
||||
public BufferedDrawNode(IBufferedDrawable source, DrawNode child, BufferedDrawNodeSharedData sharedData, RenderbufferInternalFormat[] formats = null, bool pixelSnapping = false)
|
||||
public BufferedDrawNode(IBufferedDrawable source, DrawNode child, BufferedDrawNodeSharedData sharedData)
|
||||
: base(source)
|
||||
{
|
||||
this.formats = formats;
|
||||
|
||||
Child = child;
|
||||
SharedData = sharedData;
|
||||
|
||||
filteringMode = pixelSnapping ? All.Nearest : All.Linear;
|
||||
}
|
||||
|
||||
public override void ApplyState()
|
||||
@@ -61,7 +53,7 @@ namespace osu.Framework.Graphics
|
||||
DrawColourInfo = Source.FrameBufferDrawColour ?? new DrawColourInfo(Color4.White, base.DrawColourInfo.Blending);
|
||||
|
||||
frameBufferSize = new Vector2((float)Math.Ceiling(screenSpaceDrawRectangle.Width), (float)Math.Ceiling(screenSpaceDrawRectangle.Height));
|
||||
DrawRectangle = filteringMode == All.Nearest
|
||||
DrawRectangle = SharedData.PixelSnapping
|
||||
? new RectangleF(screenSpaceDrawRectangle.X, screenSpaceDrawRectangle.Y, frameBufferSize.X, frameBufferSize.Y)
|
||||
: screenSpaceDrawRectangle;
|
||||
|
||||
@@ -141,9 +133,6 @@ namespace osu.Framework.Graphics
|
||||
/// <returns>A token that must be disposed upon finishing use of <paramref name="frameBuffer"/>.</returns>
|
||||
protected ValueInvokeOnDisposal BindFrameBuffer(FrameBuffer frameBuffer)
|
||||
{
|
||||
if (!frameBuffer.IsInitialized)
|
||||
frameBuffer.Initialise(filteringMode, formats);
|
||||
|
||||
// This setter will also take care of allocating a texture of appropriate size within the frame buffer.
|
||||
frameBuffer.Size = frameBufferSize;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using osu.Framework.Graphics.OpenGL;
|
||||
using osu.Framework.Graphics.OpenGL.Buffers;
|
||||
using osuTK.Graphics.ES30;
|
||||
|
||||
namespace osu.Framework.Graphics
|
||||
{
|
||||
@@ -26,6 +27,12 @@ namespace osu.Framework.Graphics
|
||||
/// </summary>
|
||||
public FrameBuffer MainBuffer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the frame buffer position should be snapped to the nearest pixel when blitting.
|
||||
/// This amounts to setting the texture filtering mode to "nearest".
|
||||
/// </summary>
|
||||
public readonly bool PixelSnapping;
|
||||
|
||||
/// <summary>
|
||||
/// A set of <see cref="FrameBuffer"/>s which are used in a ping-pong manner to render effects to.
|
||||
/// </summary>
|
||||
@@ -34,8 +41,8 @@ namespace osu.Framework.Graphics
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="BufferedDrawNodeSharedData"/> with no effect buffers.
|
||||
/// </summary>
|
||||
public BufferedDrawNodeSharedData()
|
||||
: this(0)
|
||||
public BufferedDrawNodeSharedData(RenderbufferInternalFormat[] formats = null, bool pixelSnapping = false)
|
||||
: this(0, formats, pixelSnapping)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -43,17 +50,23 @@ namespace osu.Framework.Graphics
|
||||
/// Creates a new <see cref="BufferedDrawNodeSharedData"/> with a specific amount of effect buffers.
|
||||
/// </summary>
|
||||
/// <param name="effectBufferCount">The number of effect buffers.</param>
|
||||
/// <param name="formats">The render buffer formats to attach to each frame buffer.</param>
|
||||
/// <param name="pixelSnapping">Whether the frame buffer position should be snapped to the nearest pixel when blitting.
|
||||
/// This amounts to setting the texture filtering mode to "nearest".</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="effectBufferCount"/> is less than 0.</exception>
|
||||
public BufferedDrawNodeSharedData(int effectBufferCount)
|
||||
public BufferedDrawNodeSharedData(int effectBufferCount, RenderbufferInternalFormat[] formats = null, bool pixelSnapping = false)
|
||||
{
|
||||
if (effectBufferCount < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(effectBufferCount), "Must be positive.");
|
||||
|
||||
MainBuffer = new FrameBuffer();
|
||||
PixelSnapping = pixelSnapping;
|
||||
All filterMode = pixelSnapping ? All.Nearest : All.Linear;
|
||||
|
||||
MainBuffer = new FrameBuffer(formats, filterMode);
|
||||
effectBuffers = new FrameBuffer[effectBufferCount];
|
||||
|
||||
for (int i = 0; i < effectBufferCount; i++)
|
||||
effectBuffers[i] = new FrameBuffer();
|
||||
effectBuffers[i] = new FrameBuffer(formats, filterMode);
|
||||
}
|
||||
|
||||
private int currentEffectBuffer = -1;
|
||||
|
||||
@@ -9,8 +9,6 @@ using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.MathUtils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
|
||||
@@ -27,7 +25,12 @@ namespace osu.Framework.Graphics.Containers
|
||||
/// </summary>
|
||||
public class BufferedContainer : BufferedContainer<Drawable>
|
||||
{
|
||||
};
|
||||
/// <inheritdoc />
|
||||
public BufferedContainer(RenderbufferInternalFormat[] formats = null, bool pixelSnapping = false)
|
||||
: base(formats, pixelSnapping)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A container that renders its children to an internal framebuffer, and then
|
||||
@@ -97,25 +100,6 @@ namespace osu.Framework.Graphics.Containers
|
||||
}
|
||||
}
|
||||
|
||||
private bool pixelSnapping;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the framebuffer's position is snapped to the nearest pixel when blitting.
|
||||
/// Since the framebuffer's texels have the same size as pixels, this amounts to setting
|
||||
/// the texture filtering mode to "nearest".
|
||||
/// </summary>
|
||||
public bool PixelSnapping
|
||||
{
|
||||
get => pixelSnapping;
|
||||
set
|
||||
{
|
||||
if (sharedData.MainBuffer.IsInitialized)
|
||||
throw new InvalidOperationException("May only set PixelSnapping before FrameBuffers are initialized (i.e. before the first draw).");
|
||||
|
||||
pixelSnapping = value;
|
||||
}
|
||||
}
|
||||
|
||||
private ColourInfo effectColour = Color4.White;
|
||||
|
||||
/// <summary>
|
||||
@@ -223,14 +207,17 @@ namespace osu.Framework.Graphics.Containers
|
||||
|
||||
private IShader blurShader;
|
||||
|
||||
private readonly BufferedContainerDrawNodeSharedData sharedData;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an empty buffered container.
|
||||
/// </summary>
|
||||
public BufferedContainer()
|
||||
/// <param name="formats">The render buffer formats attached to the frame buffers of this <see cref="BufferedContainer"/>.</param>
|
||||
/// <param name="pixelSnapping">Whether the frame buffer position should be snapped to the nearest pixel when blitting.
|
||||
/// This amounts to setting the texture filtering mode to "nearest".</param>
|
||||
public BufferedContainer(RenderbufferInternalFormat[] formats = null, bool pixelSnapping = false)
|
||||
{
|
||||
// The initial draw cannot be cached, and thus we need to initialize
|
||||
// with a forced draw.
|
||||
ForceRedraw();
|
||||
sharedData = new BufferedContainerDrawNodeSharedData(formats, pixelSnapping);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@@ -241,30 +228,7 @@ namespace osu.Framework.Graphics.Containers
|
||||
blurShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.BLUR);
|
||||
}
|
||||
|
||||
private readonly BufferedContainerDrawNodeSharedData sharedData = new BufferedContainerDrawNodeSharedData();
|
||||
|
||||
protected override DrawNode CreateDrawNode() => new BufferedContainerDrawNode(this, sharedData, attachedFormats.ToArray(), PixelSnapping);
|
||||
|
||||
private readonly List<RenderbufferInternalFormat> attachedFormats = new List<RenderbufferInternalFormat>();
|
||||
|
||||
/// <summary>
|
||||
/// Attach an additional component to this <see cref="BufferedContainer{T}"/>. Such a component can e.g.
|
||||
/// be a depth component, such that the framebuffer can hold fragment depth information.
|
||||
/// </summary>
|
||||
/// <param name="format">The component format to attach.</param>
|
||||
public void Attach(RenderbufferInternalFormat format)
|
||||
{
|
||||
if (attachedFormats.Exists(f => f == format))
|
||||
return;
|
||||
|
||||
attachedFormats.Add(format);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detaches an additional component of this <see cref="BufferedContainer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="format">The component format to detach.</param>
|
||||
public void Detach(RenderbufferInternalFormat format) => attachedFormats.Remove(format);
|
||||
protected override DrawNode CreateDrawNode() => new BufferedContainerDrawNode(this, sharedData);
|
||||
|
||||
protected override RectangleF ComputeChildMaskingBounds(RectangleF maskingBounds) => ScreenSpaceDrawQuad.AABBFloat; // Make sure children never get masked away
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Graphics.OpenGL;
|
||||
using osu.Framework.Graphics.OpenGL.Buffers;
|
||||
using osuTK;
|
||||
using osuTK.Graphics.ES30;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using System;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.MathUtils;
|
||||
using osuTK.Graphics.ES30;
|
||||
|
||||
namespace osu.Framework.Graphics.Containers
|
||||
{
|
||||
@@ -36,9 +36,8 @@ namespace osu.Framework.Graphics.Containers
|
||||
|
||||
private IShader blurShader;
|
||||
|
||||
public BufferedContainerDrawNode(BufferedContainer<T> source, BufferedContainerDrawNodeSharedData sharedData, RenderbufferInternalFormat[] formats = null,
|
||||
bool pixelSnapping = false)
|
||||
: base(source, new CompositeDrawableDrawNode(source), sharedData, formats, pixelSnapping)
|
||||
public BufferedContainerDrawNode(BufferedContainer<T> source, BufferedContainerDrawNodeSharedData sharedData)
|
||||
: base(source, new CompositeDrawableDrawNode(source), sharedData)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -129,8 +128,8 @@ namespace osu.Framework.Graphics.Containers
|
||||
|
||||
private class BufferedContainerDrawNodeSharedData : BufferedDrawNodeSharedData
|
||||
{
|
||||
public BufferedContainerDrawNodeSharedData()
|
||||
: base(2)
|
||||
public BufferedContainerDrawNodeSharedData(RenderbufferInternalFormat[] formats, bool pixelSnapping)
|
||||
: base(2, formats, pixelSnapping)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1575,7 +1575,7 @@ namespace osu.Framework.Graphics.Containers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!StaticCached.BypassCache && !isComputingChildrenSizeDependencies && AutoSizeAxes.HasFlag(Axes.X))
|
||||
if (!isComputingChildrenSizeDependencies && AutoSizeAxes.HasFlag(Axes.X))
|
||||
updateChildrenSizeDependencies();
|
||||
return base.Width;
|
||||
}
|
||||
@@ -1593,7 +1593,7 @@ namespace osu.Framework.Graphics.Containers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!StaticCached.BypassCache && !isComputingChildrenSizeDependencies && AutoSizeAxes.HasFlag(Axes.Y))
|
||||
if (!isComputingChildrenSizeDependencies && AutoSizeAxes.HasFlag(Axes.Y))
|
||||
updateChildrenSizeDependencies();
|
||||
return base.Height;
|
||||
}
|
||||
@@ -1613,7 +1613,7 @@ namespace osu.Framework.Graphics.Containers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!StaticCached.BypassCache && !isComputingChildrenSizeDependencies && AutoSizeAxes != Axes.None)
|
||||
if (!isComputingChildrenSizeDependencies && AutoSizeAxes != Axes.None)
|
||||
updateChildrenSizeDependencies();
|
||||
return base.Size;
|
||||
}
|
||||
|
||||
@@ -18,24 +18,28 @@ namespace osu.Framework.Graphics.Containers.Markdown
|
||||
/// </code>
|
||||
public class MarkdownLinkText : CompositeDrawable, IHasTooltip, IMarkdownTextComponent
|
||||
{
|
||||
public string TooltipText => url;
|
||||
public string TooltipText => Url;
|
||||
|
||||
[Resolved]
|
||||
private IMarkdownTextComponent parentTextComponent { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
private readonly string text;
|
||||
private readonly string url;
|
||||
|
||||
protected readonly string Url;
|
||||
|
||||
public MarkdownLinkText(string text, LinkInline linkInline)
|
||||
{
|
||||
this.text = text;
|
||||
url = linkInline.Url ?? string.Empty;
|
||||
Url = linkInline.Url ?? string.Empty;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host)
|
||||
private void load()
|
||||
{
|
||||
SpriteText spriteText;
|
||||
InternalChildren = new Drawable[]
|
||||
@@ -44,13 +48,15 @@ namespace osu.Framework.Graphics.Containers.Markdown
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = spriteText = CreateSpriteText(),
|
||||
Action = () => host.OpenUrlExternally(url)
|
||||
Action = OnLinkPressed,
|
||||
}
|
||||
};
|
||||
|
||||
spriteText.Text = text;
|
||||
}
|
||||
|
||||
protected virtual void OnLinkPressed() => host.OpenUrlExternally(Url);
|
||||
|
||||
public virtual SpriteText CreateSpriteText()
|
||||
{
|
||||
var spriteText = parentTextComponent.CreateSpriteText();
|
||||
|
||||
@@ -274,9 +274,9 @@ namespace osu.Framework.Graphics.Lines
|
||||
|
||||
public Color4 BackgroundColour => new Color4(0, 0, 0, 0);
|
||||
|
||||
private readonly BufferedDrawNodeSharedData sharedData = new BufferedDrawNodeSharedData();
|
||||
private readonly BufferedDrawNodeSharedData sharedData = new BufferedDrawNodeSharedData(new[] { RenderbufferInternalFormat.DepthComponent16 });
|
||||
|
||||
protected override DrawNode CreateDrawNode() => new BufferedDrawNode(this, new PathDrawNode(this), sharedData, new[] { RenderbufferInternalFormat.DepthComponent16 });
|
||||
protected override DrawNode CreateDrawNode() => new BufferedDrawNode(this, new PathDrawNode(this), sharedData);
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
|
||||
@@ -18,28 +18,15 @@ namespace osu.Framework.Graphics.OpenGL.Buffers
|
||||
|
||||
private readonly List<RenderBuffer> attachedRenderBuffers = new List<RenderBuffer>();
|
||||
|
||||
public bool IsInitialized { get; private set; }
|
||||
private bool isInitialised;
|
||||
|
||||
public void Initialise(All filteringMode = All.Linear, RenderbufferInternalFormat[] renderBufferFormats = null)
|
||||
private readonly All filteringMode;
|
||||
private readonly RenderbufferInternalFormat[] renderBufferFormats;
|
||||
|
||||
public FrameBuffer(RenderbufferInternalFormat[] renderBufferFormats = null, All filteringMode = All.Linear)
|
||||
{
|
||||
frameBuffer = GL.GenFramebuffer();
|
||||
|
||||
Texture = new FrameBufferTexture(filteringMode);
|
||||
|
||||
Bind();
|
||||
|
||||
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget2d.Texture2D, Texture.TextureId, 0);
|
||||
GLWrapper.BindTexture(null);
|
||||
|
||||
if (renderBufferFormats != null)
|
||||
{
|
||||
foreach (var format in renderBufferFormats)
|
||||
attachedRenderBuffers.Add(new RenderBuffer(format));
|
||||
}
|
||||
|
||||
Unbind();
|
||||
|
||||
IsInitialized = true;
|
||||
this.renderBufferFormats = renderBufferFormats;
|
||||
this.filteringMode = filteringMode;
|
||||
}
|
||||
|
||||
private Vector2 size = Vector2.One;
|
||||
@@ -57,13 +44,33 @@ namespace osu.Framework.Graphics.OpenGL.Buffers
|
||||
|
||||
size = value;
|
||||
|
||||
Texture.Width = (int)Math.Ceiling(size.X);
|
||||
Texture.Height = (int)Math.Ceiling(size.Y);
|
||||
Texture.SetData(new TextureUpload());
|
||||
Texture.Upload();
|
||||
if (isInitialised)
|
||||
{
|
||||
Texture.Width = (int)Math.Ceiling(size.X);
|
||||
Texture.Height = (int)Math.Ceiling(size.Y);
|
||||
Texture.SetData(new TextureUpload());
|
||||
Texture.Upload();
|
||||
|
||||
foreach (var buffer in attachedRenderBuffers)
|
||||
buffer.Size = value;
|
||||
foreach (var buffer in attachedRenderBuffers)
|
||||
buffer.Size = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initialise()
|
||||
{
|
||||
frameBuffer = GL.GenFramebuffer();
|
||||
Texture = new FrameBufferTexture(Vector2.ComponentMax(Vector2.One, Size), filteringMode);
|
||||
|
||||
GLWrapper.BindFrameBuffer(frameBuffer);
|
||||
|
||||
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget2d.Texture2D, Texture.TextureId, 0);
|
||||
GLWrapper.BindTexture(null);
|
||||
|
||||
if (renderBufferFormats != null)
|
||||
{
|
||||
foreach (var format in renderBufferFormats)
|
||||
attachedRenderBuffers.Add(new RenderBuffer(format) { Size = Size });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +78,19 @@ namespace osu.Framework.Graphics.OpenGL.Buffers
|
||||
/// Binds the framebuffer.
|
||||
/// <para>Does not clear the buffer or reset the viewport/ortho.</para>
|
||||
/// </summary>
|
||||
public void Bind() => GLWrapper.BindFrameBuffer(frameBuffer);
|
||||
public void Bind()
|
||||
{
|
||||
if (!isInitialised)
|
||||
{
|
||||
initialise();
|
||||
isInitialised = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buffer is bound during initialisation
|
||||
GLWrapper.BindFrameBuffer(frameBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unbinds the framebuffer.
|
||||
@@ -98,13 +117,16 @@ namespace osu.Framework.Graphics.OpenGL.Buffers
|
||||
if (isDisposed)
|
||||
return;
|
||||
|
||||
Texture?.Dispose();
|
||||
Texture = null;
|
||||
if (isInitialised)
|
||||
{
|
||||
Texture?.Dispose();
|
||||
Texture = null;
|
||||
|
||||
GLWrapper.DeleteFrameBuffer(frameBuffer);
|
||||
GLWrapper.DeleteFrameBuffer(frameBuffer);
|
||||
|
||||
foreach (var buffer in attachedRenderBuffers)
|
||||
buffer.Dispose();
|
||||
foreach (var buffer in attachedRenderBuffers)
|
||||
buffer.Dispose();
|
||||
}
|
||||
|
||||
isDisposed = true;
|
||||
}
|
||||
@@ -113,8 +135,8 @@ namespace osu.Framework.Graphics.OpenGL.Buffers
|
||||
|
||||
private class FrameBufferTexture : TextureGLSingle
|
||||
{
|
||||
public FrameBufferTexture(All filteringMode = All.Linear)
|
||||
: base(1, 1, true, filteringMode)
|
||||
public FrameBufferTexture(Vector2 size, All filteringMode = All.Linear)
|
||||
: base((int)Math.Ceiling(size.X), (int)Math.Ceiling(size.Y), true, filteringMode)
|
||||
{
|
||||
SetData(new TextureUpload());
|
||||
Upload();
|
||||
|
||||
@@ -20,8 +20,13 @@ namespace osu.Framework.Graphics.OpenGL.Buffers
|
||||
this.format = format;
|
||||
|
||||
renderBuffer = GL.GenRenderbuffer();
|
||||
|
||||
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderBuffer);
|
||||
|
||||
// OpenGL docs don't specify that this is required, but seems to be required on some platforms
|
||||
// to correctly attach in the GL.FramebufferRenderbuffer() call below
|
||||
GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, format, 1, 1);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case RenderbufferInternalFormat.DepthComponent16:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// 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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using osu.Framework.Graphics.OpenGL;
|
||||
using osuTK;
|
||||
using osuTK.Graphics.ES30;
|
||||
@@ -11,8 +11,6 @@ namespace osu.Framework.Graphics.Shaders
|
||||
{
|
||||
public class Shader : IShader
|
||||
{
|
||||
internal StringBuilder Log = new StringBuilder();
|
||||
|
||||
public bool IsLoaded { get; private set; }
|
||||
|
||||
internal bool IsBound;
|
||||
@@ -37,7 +35,6 @@ namespace osu.Framework.Graphics.Shaders
|
||||
parts.RemoveAll(p => p == null);
|
||||
Uniforms.Clear();
|
||||
uniformsArray = null;
|
||||
Log.Clear();
|
||||
|
||||
if (parts.Count == 0)
|
||||
return;
|
||||
@@ -54,90 +51,79 @@ namespace osu.Framework.Graphics.Shaders
|
||||
}
|
||||
|
||||
GL.LinkProgram(this);
|
||||
|
||||
GL.GetProgram(this, GetProgramParameterName.LinkStatus, out int linkResult);
|
||||
string linkLog = GL.GetProgramInfoLog(this);
|
||||
|
||||
Log.AppendLine(string.Format(ShaderPart.BOUNDARY, name));
|
||||
Log.AppendLine($"Linked: {linkResult == 1}");
|
||||
|
||||
if (linkResult == 0)
|
||||
{
|
||||
Log.AppendLine("Log:");
|
||||
Log.AppendLine(linkLog);
|
||||
}
|
||||
|
||||
foreach (var part in parts)
|
||||
GL.DetachShader(this, part);
|
||||
|
||||
IsLoaded = linkResult == 1;
|
||||
|
||||
if (IsLoaded)
|
||||
if (!IsLoaded)
|
||||
throw new ProgramLinkingFailedException(name, GL.GetProgramInfoLog(this));
|
||||
|
||||
// Obtain all the shader uniforms
|
||||
GL.GetProgram(this, GetProgramParameterName.ActiveUniforms, out int uniformCount);
|
||||
uniformsArray = new IUniform[uniformCount];
|
||||
|
||||
for (int i = 0; i < uniformCount; i++)
|
||||
{
|
||||
// Obtain all the shader uniforms
|
||||
GL.GetProgram(this, GetProgramParameterName.ActiveUniforms, out int uniformCount);
|
||||
uniformsArray = new IUniform[uniformCount];
|
||||
GL.GetActiveUniform(this, i, 100, out _, out _, out ActiveUniformType type, out string uniformName);
|
||||
|
||||
for (int i = 0; i < uniformCount; i++)
|
||||
IUniform createUniform<T>(string name)
|
||||
where T : struct
|
||||
{
|
||||
GL.GetActiveUniform(this, i, 100, out _, out _, out ActiveUniformType type, out string uniformName);
|
||||
int location = GL.GetUniformLocation(this, name);
|
||||
|
||||
IUniform createUniform<T>(string name)
|
||||
where T : struct
|
||||
{
|
||||
int location = GL.GetUniformLocation(this, name);
|
||||
if (GlobalPropertyManager.CheckGlobalExists(name)) return new GlobalUniform<T>(this, name, location);
|
||||
|
||||
if (GlobalPropertyManager.CheckGlobalExists(name)) return new GlobalUniform<T>(this, name, location);
|
||||
|
||||
return new Uniform<T>(this, name, location);
|
||||
}
|
||||
|
||||
IUniform uniform;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ActiveUniformType.Bool:
|
||||
uniform = createUniform<bool>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.Float:
|
||||
uniform = createUniform<float>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.Int:
|
||||
uniform = createUniform<int>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.FloatMat3:
|
||||
uniform = createUniform<Matrix3>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.FloatMat4:
|
||||
uniform = createUniform<Matrix4>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.FloatVec2:
|
||||
uniform = createUniform<Vector2>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.FloatVec3:
|
||||
uniform = createUniform<Vector3>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.FloatVec4:
|
||||
uniform = createUniform<Vector4>(uniformName);
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
uniformsArray[i] = uniform;
|
||||
Uniforms.Add(uniformName, uniformsArray[i]);
|
||||
return new Uniform<T>(this, name, location);
|
||||
}
|
||||
|
||||
GlobalPropertyManager.Register(this);
|
||||
IUniform uniform;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ActiveUniformType.Bool:
|
||||
uniform = createUniform<bool>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.Float:
|
||||
uniform = createUniform<float>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.Int:
|
||||
uniform = createUniform<int>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.FloatMat3:
|
||||
uniform = createUniform<Matrix3>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.FloatMat4:
|
||||
uniform = createUniform<Matrix4>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.FloatVec2:
|
||||
uniform = createUniform<Vector2>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.FloatVec3:
|
||||
uniform = createUniform<Vector3>(uniformName);
|
||||
break;
|
||||
|
||||
case ActiveUniformType.FloatVec4:
|
||||
uniform = createUniform<Vector4>(uniformName);
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
uniformsArray[i] = uniform;
|
||||
Uniforms.Add(uniformName, uniformsArray[i]);
|
||||
}
|
||||
|
||||
GlobalPropertyManager.Register(this);
|
||||
}
|
||||
|
||||
internal void EnsureLoaded()
|
||||
@@ -187,5 +173,21 @@ namespace osu.Framework.Graphics.Shaders
|
||||
}
|
||||
|
||||
public static implicit operator int(Shader shader) => shader.programID;
|
||||
|
||||
public class PartCompilationFailedException : Exception
|
||||
{
|
||||
public PartCompilationFailedException(string partName, string log)
|
||||
: base($"A {typeof(ShaderPart)} failed to compile: {partName}:\n{log.Trim()}")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ProgramLinkingFailedException : Exception
|
||||
{
|
||||
public ProgramLinkingFailedException(string programName, string log)
|
||||
: base($"A {typeof(Shader)} failed to link: {programName}:\n{log.Trim()}")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Logging;
|
||||
using osuTK.Graphics.ES30;
|
||||
|
||||
namespace osu.Framework.Graphics.Shaders
|
||||
@@ -81,21 +79,7 @@ namespace osu.Framework.Graphics.Shaders
|
||||
createShaderPart(fragment, ShaderType.FragmentShader)
|
||||
};
|
||||
|
||||
shader = new Shader($"{vertex}/{fragment}", parts);
|
||||
|
||||
if (!shader.IsLoaded)
|
||||
{
|
||||
StringBuilder logContents = new StringBuilder();
|
||||
logContents.AppendLine($@"Loading shader {vertex}/{fragment}");
|
||||
logContents.Append(shader.Log);
|
||||
foreach (ShaderPart p in parts)
|
||||
logContents.Append(p.Log);
|
||||
Logger.Log(logContents.ToString().Trim('\n'), LoggingTarget.Runtime, LogLevel.Debug);
|
||||
}
|
||||
|
||||
shaderCache[tuple] = shader;
|
||||
|
||||
return shader;
|
||||
return shaderCache[tuple] = new Shader($"{vertex}/{fragment}", parts);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using osuTK.Graphics.ES30;
|
||||
|
||||
@@ -12,9 +11,7 @@ namespace osu.Framework.Graphics.Shaders
|
||||
{
|
||||
internal class ShaderPart
|
||||
{
|
||||
internal const string BOUNDARY = @"----------------------{0}";
|
||||
|
||||
internal StringBuilder Log = new StringBuilder();
|
||||
internal const string SHADER_ATTRIBUTE_PATTERN = "^\\s*(?>attribute|in)\\s+(?:(?:lowp|mediump|highp)\\s+)?\\w+\\s+(\\w+)";
|
||||
|
||||
internal List<ShaderInputInfo> ShaderInputs = new List<ShaderInputInfo>();
|
||||
|
||||
@@ -33,7 +30,7 @@ namespace osu.Framework.Graphics.Shaders
|
||||
private readonly List<string> shaderCodes = new List<string>();
|
||||
|
||||
private readonly Regex includeRegex = new Regex("^\\s*#\\s*include\\s+[\"<](.*)[\">]");
|
||||
private readonly Regex shaderInputRegex = new Regex("^\\s*(?>attribute|in)\\s+[^\\s]+\\s+([^;]+);");
|
||||
private readonly Regex shaderInputRegex = new Regex(SHADER_ATTRIBUTE_PATTERN);
|
||||
|
||||
private readonly ShaderManager manager;
|
||||
|
||||
@@ -107,14 +104,19 @@ namespace osu.Framework.Graphics.Shaders
|
||||
}
|
||||
}
|
||||
|
||||
if (mainFile && isVertexShader)
|
||||
if (mainFile)
|
||||
{
|
||||
string realMainName = "real_main_" + Guid.NewGuid().ToString("N");
|
||||
code = loadFile(manager.LoadRaw("sh_Precision_Internal.h"), false) + "\n" + code;
|
||||
|
||||
string backbufferCode = loadFile(manager.LoadRaw("sh_Backbuffer_Internal.h"), false);
|
||||
if (isVertexShader)
|
||||
{
|
||||
string realMainName = "real_main_" + Guid.NewGuid().ToString("N");
|
||||
|
||||
backbufferCode = backbufferCode.Replace("{{ real_main }}", realMainName);
|
||||
code = Regex.Replace(code, @"void main\((.*)\)", $"void {realMainName}()") + backbufferCode + '\n';
|
||||
string backbufferCode = loadFile(manager.LoadRaw("sh_Backbuffer_Internal.h"), false);
|
||||
|
||||
backbufferCode = backbufferCode.Replace("{{ real_main }}", realMainName);
|
||||
code = Regex.Replace(code, @"void main\((.*)\)", $"void {realMainName}()") + backbufferCode + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
@@ -139,20 +141,8 @@ namespace osu.Framework.Graphics.Shaders
|
||||
GL.GetShader(this, ShaderParameter.CompileStatus, out int compileResult);
|
||||
Compiled = compileResult == 1;
|
||||
|
||||
#if DEBUG
|
||||
string compileLog = GL.GetShaderInfoLog(this);
|
||||
Log.AppendLine(string.Format('\t' + BOUNDARY, Name));
|
||||
Log.AppendLine($"\tCompiled: {Compiled}");
|
||||
|
||||
if (!Compiled)
|
||||
{
|
||||
Log.AppendLine("\tLog:");
|
||||
Log.AppendLine('\t' + compileLog);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Compiled)
|
||||
delete();
|
||||
throw new Shader.PartCompilationFailedException(Name, GL.GetShaderInfoLog(this));
|
||||
|
||||
return Compiled;
|
||||
}
|
||||
|
||||
@@ -421,6 +421,18 @@ namespace osu.Framework.Graphics.UserInterface
|
||||
child.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Clear(bool disposeChildren)
|
||||
{
|
||||
tabVisibility.Clear();
|
||||
base.Clear(disposeChildren);
|
||||
}
|
||||
|
||||
public override bool Remove(TabItem<T> drawable)
|
||||
{
|
||||
tabVisibility.Remove(drawable);
|
||||
return base.Remove(drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Automatically included for every vertex shader.
|
||||
|
||||
attribute float m_BackbufferDrawDepth;
|
||||
attribute highp float m_BackbufferDrawDepth;
|
||||
|
||||
// Whether the backbuffer is currently being drawn to
|
||||
uniform bool g_BackbufferDraw;
|
||||
|
||||
@@ -1,35 +1,31 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
#include "sh_Utils.h"
|
||||
|
||||
#define INV_SQRT_2PI 0.39894
|
||||
|
||||
varying vec2 v_TexCoord;
|
||||
varying mediump vec2 v_TexCoord;
|
||||
|
||||
uniform sampler2D m_Sampler;
|
||||
uniform lowp sampler2D m_Sampler;
|
||||
|
||||
uniform vec2 g_TexSize;
|
||||
uniform mediump vec2 g_TexSize;
|
||||
uniform int g_Radius;
|
||||
uniform float g_Sigma;
|
||||
uniform vec2 g_BlurDirection;
|
||||
uniform mediump float g_Sigma;
|
||||
uniform highp vec2 g_BlurDirection;
|
||||
|
||||
float computeGauss(in float x, in float sigma)
|
||||
mediump float computeGauss(in mediump float x, in mediump float sigma)
|
||||
{
|
||||
return INV_SQRT_2PI * exp(-0.5*x*x / (sigma*sigma)) / sigma;
|
||||
}
|
||||
|
||||
vec4 blur(sampler2D tex, int radius, vec2 direction, vec2 texCoord, vec2 texSize, float sigma)
|
||||
lowp vec4 blur(sampler2D tex, int radius, highp vec2 direction, mediump vec2 texCoord, mediump vec2 texSize, mediump float sigma)
|
||||
{
|
||||
float factor = computeGauss(0.0, sigma);
|
||||
vec4 sum = texture2D(tex, texCoord) * factor;
|
||||
mediump float factor = computeGauss(0.0, sigma);
|
||||
mediump vec4 sum = texture2D(tex, texCoord) * factor;
|
||||
|
||||
float totalFactor = factor;
|
||||
mediump float totalFactor = factor;
|
||||
|
||||
for (int i = 2; i <= 200; i += 2)
|
||||
{
|
||||
float x = float(i) - 0.5;
|
||||
mediump float x = float(i) - 0.5;
|
||||
factor = computeGauss(x, sigma) * 2.0;
|
||||
totalFactor += 2.0 * factor;
|
||||
sum += texture2D(tex, texCoord + direction * x / texSize) * factor;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
attribute vec2 m_Position;
|
||||
attribute highp vec2 m_Position;
|
||||
|
||||
varying vec2 v_Position;
|
||||
varying highp vec2 v_Position;
|
||||
|
||||
uniform mat4 g_ProjMatrix;
|
||||
uniform highp mat4 g_ProjMatrix;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
||||
10
osu.Framework/Resources/Shaders/sh_Precision_Internal.h
Normal file
10
osu.Framework/Resources/Shaders/sh_Precision_Internal.h
Normal file
@@ -0,0 +1,10 @@
|
||||
// This file is automatically included in every shader
|
||||
|
||||
#ifndef GL_ES
|
||||
#define lowp
|
||||
#define mediump
|
||||
#define highp
|
||||
#else
|
||||
// GL_ES expects a defined precision for every member. Users may miss this requirement, so a default precision is specified.
|
||||
precision mediump float;
|
||||
#endif
|
||||
@@ -1,13 +1,9 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
#include "sh_Utils.h"
|
||||
|
||||
varying vec4 v_Colour;
|
||||
varying vec2 v_TexCoord;
|
||||
varying lowp vec4 v_Colour;
|
||||
varying mediump vec2 v_TexCoord;
|
||||
|
||||
uniform sampler2D m_Sampler;
|
||||
uniform lowp sampler2D m_Sampler;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
#include "sh_Utils.h"
|
||||
|
||||
attribute vec2 m_Position;
|
||||
attribute vec4 m_Colour;
|
||||
attribute vec2 m_TexCoord;
|
||||
attribute vec4 m_TexRect;
|
||||
attribute vec2 m_BlendRange;
|
||||
attribute highp vec2 m_Position;
|
||||
attribute lowp vec4 m_Colour;
|
||||
attribute mediump vec2 m_TexCoord;
|
||||
attribute mediump vec4 m_TexRect;
|
||||
attribute mediump vec2 m_BlendRange;
|
||||
|
||||
varying vec2 v_MaskingPosition;
|
||||
varying vec4 v_Colour;
|
||||
varying vec2 v_TexCoord;
|
||||
varying vec4 v_TexRect;
|
||||
varying vec2 v_BlendRange;
|
||||
varying highp vec2 v_MaskingPosition;
|
||||
varying lowp vec4 v_Colour;
|
||||
varying mediump vec2 v_TexCoord;
|
||||
varying mediump vec4 v_TexRect;
|
||||
varying mediump vec2 v_BlendRange;
|
||||
|
||||
uniform mat4 g_ProjMatrix;
|
||||
uniform mat3 g_ToMaskingSpace;
|
||||
uniform highp mat4 g_ProjMatrix;
|
||||
uniform highp mat3 g_ToMaskingSpace;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// Transform from screen space to masking space.
|
||||
vec3 maskingPos = g_ToMaskingSpace * vec3(m_Position, 1.0);
|
||||
highp vec3 maskingPos = g_ToMaskingSpace * vec3(m_Position, 1.0);
|
||||
v_MaskingPosition = maskingPos.xy / maskingPos.z;
|
||||
|
||||
v_Colour = m_Colour;
|
||||
@@ -27,4 +27,4 @@ void main(void)
|
||||
v_BlendRange = m_BlendRange;
|
||||
|
||||
gl_Position = g_ProjMatrix * vec4(m_Position, 1.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "sh_Utils.h"
|
||||
|
||||
attribute vec3 m_Position;
|
||||
attribute vec4 m_Colour;
|
||||
attribute vec2 m_TexCoord;
|
||||
attribute highp vec3 m_Position;
|
||||
attribute lowp vec4 m_Colour;
|
||||
attribute mediump vec2 m_TexCoord;
|
||||
|
||||
varying vec2 v_MaskingPosition;
|
||||
varying vec4 v_Colour;
|
||||
varying vec2 v_TexCoord;
|
||||
varying vec4 v_TexRect;
|
||||
varying vec2 v_BlendRange;
|
||||
varying highp vec2 v_MaskingPosition;
|
||||
varying lowp vec4 v_Colour;
|
||||
varying mediump vec2 v_TexCoord;
|
||||
varying mediump vec4 v_TexRect;
|
||||
varying mediump vec2 v_BlendRange;
|
||||
|
||||
uniform mat4 g_ProjMatrix;
|
||||
uniform mat3 g_ToMaskingSpace;
|
||||
@@ -25,4 +25,4 @@ void main(void)
|
||||
v_Colour = m_Colour;
|
||||
v_TexCoord = m_TexCoord;
|
||||
gl_Position = g_ProjMatrix * vec4(m_Position, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,39 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
#include "sh_Utils.h"
|
||||
|
||||
varying vec2 v_MaskingPosition;
|
||||
varying vec4 v_Colour;
|
||||
varying vec2 v_TexCoord;
|
||||
varying vec4 v_TexRect;
|
||||
varying vec2 v_BlendRange;
|
||||
varying highp vec2 v_MaskingPosition;
|
||||
varying lowp vec4 v_Colour;
|
||||
varying mediump vec2 v_TexCoord;
|
||||
varying mediump vec4 v_TexRect;
|
||||
varying mediump vec2 v_BlendRange;
|
||||
|
||||
uniform sampler2D m_Sampler;
|
||||
uniform float g_CornerRadius;
|
||||
uniform vec4 g_MaskingRect;
|
||||
uniform float g_BorderThickness;
|
||||
uniform vec4 g_BorderColour;
|
||||
uniform lowp sampler2D m_Sampler;
|
||||
uniform highp float g_CornerRadius;
|
||||
uniform highp vec4 g_MaskingRect;
|
||||
uniform highp float g_BorderThickness;
|
||||
uniform lowp vec4 g_BorderColour;
|
||||
|
||||
uniform float g_MaskingBlendRange;
|
||||
uniform mediump float g_MaskingBlendRange;
|
||||
|
||||
uniform float g_AlphaExponent;
|
||||
uniform lowp float g_AlphaExponent;
|
||||
|
||||
uniform vec2 g_EdgeOffset;
|
||||
uniform highp vec2 g_EdgeOffset;
|
||||
|
||||
uniform bool g_DiscardInner;
|
||||
uniform float g_InnerCornerRadius;
|
||||
uniform highp float g_InnerCornerRadius;
|
||||
|
||||
float distanceFromRoundedRect(vec2 offset, float radius)
|
||||
highp float distanceFromRoundedRect(highp vec2 offset, highp float radius)
|
||||
{
|
||||
vec2 maskingPosition = v_MaskingPosition + offset;
|
||||
highp vec2 maskingPosition = v_MaskingPosition + offset;
|
||||
|
||||
// Compute offset distance from masking rect in masking space.
|
||||
vec2 topLeftOffset = g_MaskingRect.xy - maskingPosition;
|
||||
vec2 bottomRightOffset = maskingPosition - g_MaskingRect.zw;
|
||||
highp vec2 topLeftOffset = g_MaskingRect.xy - maskingPosition;
|
||||
highp vec2 bottomRightOffset = maskingPosition - g_MaskingRect.zw;
|
||||
|
||||
vec2 distanceFromShrunkRect = max(
|
||||
highp vec2 distanceFromShrunkRect = max(
|
||||
bottomRightOffset + vec2(radius),
|
||||
topLeftOffset + vec2(radius));
|
||||
|
||||
float maxDist = max(distanceFromShrunkRect.x, distanceFromShrunkRect.y);
|
||||
highp float maxDist = max(distanceFromShrunkRect.x, distanceFromShrunkRect.y);
|
||||
|
||||
// Inside the shrunk rectangle
|
||||
if (maxDist <= 0.0)
|
||||
@@ -47,38 +43,38 @@ float distanceFromRoundedRect(vec2 offset, float radius)
|
||||
return length(max(vec2(0.0), distanceFromShrunkRect));
|
||||
}
|
||||
|
||||
float distanceFromDrawingRect()
|
||||
highp float distanceFromDrawingRect()
|
||||
{
|
||||
vec2 topLeftOffset = v_TexRect.xy - v_TexCoord;
|
||||
highp vec2 topLeftOffset = v_TexRect.xy - v_TexCoord;
|
||||
topLeftOffset = vec2(
|
||||
v_BlendRange.x > 0.0 ? topLeftOffset.x / v_BlendRange.x : 0.0,
|
||||
v_BlendRange.y > 0.0 ? topLeftOffset.y / v_BlendRange.y : 0.0);
|
||||
|
||||
vec2 bottomRightOffset = v_TexCoord - v_TexRect.zw;
|
||||
highp vec2 bottomRightOffset = v_TexCoord - v_TexRect.zw;
|
||||
bottomRightOffset = vec2(
|
||||
v_BlendRange.x > 0.0 ? bottomRightOffset.x / v_BlendRange.x : 0.0,
|
||||
v_BlendRange.y > 0.0 ? bottomRightOffset.y / v_BlendRange.y : 0.0);
|
||||
|
||||
vec2 xyDistance = max(topLeftOffset, bottomRightOffset);
|
||||
highp vec2 xyDistance = max(topLeftOffset, bottomRightOffset);
|
||||
return max(xyDistance.x, xyDistance.y);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
float dist = distanceFromRoundedRect(vec2(0.0), g_CornerRadius);
|
||||
float alphaFactor = 1.0;
|
||||
vec4 texel = texture2D(m_Sampler, v_TexCoord, -0.9);
|
||||
highp float dist = distanceFromRoundedRect(vec2(0.0), g_CornerRadius);
|
||||
lowp float alphaFactor = 1.0;
|
||||
lowp vec4 texel = texture2D(m_Sampler, v_TexCoord, -0.9);
|
||||
|
||||
// Discard inner pixels
|
||||
if (g_DiscardInner)
|
||||
{
|
||||
float innerDist = (g_EdgeOffset == vec2(0.0) && g_InnerCornerRadius == g_CornerRadius) ?
|
||||
highp float innerDist = (g_EdgeOffset == vec2(0.0) && g_InnerCornerRadius == g_CornerRadius) ?
|
||||
dist : distanceFromRoundedRect(g_EdgeOffset, g_InnerCornerRadius);
|
||||
|
||||
// v_BlendRange is set from outside in a hacky way to tell us the g_MaskingBlendRange used for the rounded
|
||||
// corners of the edge effect container itself. We can then derive the alpha factor for smooth inner edge
|
||||
// effect from that.
|
||||
float innerBlendFactor = (g_InnerCornerRadius - g_MaskingBlendRange - innerDist) / v_BlendRange.x;
|
||||
highp float innerBlendFactor = (g_InnerCornerRadius - g_MaskingBlendRange - innerDist) / v_BlendRange.x;
|
||||
if (innerBlendFactor > 1.0)
|
||||
{
|
||||
gl_FragColor = vec4(0.0);
|
||||
@@ -92,8 +88,8 @@ void main(void)
|
||||
dist /= g_MaskingBlendRange;
|
||||
|
||||
// This correction is needed to avoid fading of the alpha value for radii below 1px.
|
||||
float radiusCorrection = g_CornerRadius <= 0.0 ? g_MaskingBlendRange : max(0.0, g_MaskingBlendRange - g_CornerRadius);
|
||||
float fadeStart = (g_CornerRadius + radiusCorrection) / g_MaskingBlendRange;
|
||||
highp float radiusCorrection = g_CornerRadius <= 0.0 ? g_MaskingBlendRange : max(0.0, g_MaskingBlendRange - g_CornerRadius);
|
||||
highp float fadeStart = (g_CornerRadius + radiusCorrection) / g_MaskingBlendRange;
|
||||
alphaFactor *= min(fadeStart - dist, 1.0);
|
||||
|
||||
if (v_BlendRange.x > 0.0 || v_BlendRange.y > 0.0)
|
||||
@@ -108,8 +104,9 @@ void main(void)
|
||||
// This ends up softening glow without negatively affecting edge smoothness much.
|
||||
alphaFactor = pow(alphaFactor, g_AlphaExponent);
|
||||
|
||||
float borderStart = 1.0 + fadeStart - g_BorderThickness;
|
||||
float colourWeight = min(borderStart - dist, 1.0);
|
||||
highp float borderStart = 1.0 + fadeStart - g_BorderThickness;
|
||||
lowp float colourWeight = min(borderStart - dist, 1.0);
|
||||
|
||||
if (colourWeight <= 0.0)
|
||||
{
|
||||
gl_FragColor = toSRGB(vec4(g_BorderColour.rgb, g_BorderColour.a * alphaFactor));
|
||||
|
||||
@@ -2,22 +2,22 @@
|
||||
|
||||
uniform bool g_GammaCorrection;
|
||||
|
||||
float toLinear(float color)
|
||||
lowp float toLinear(lowp float color)
|
||||
{
|
||||
return color <= 0.04045 ? (color / 12.92) : pow((color + 0.055) / 1.055, GAMMA);
|
||||
}
|
||||
|
||||
vec4 toLinear(vec4 colour)
|
||||
lowp vec4 toLinear(lowp vec4 colour)
|
||||
{
|
||||
return vec4(toLinear(colour.r), toLinear(colour.g), toLinear(colour.b), colour.a);
|
||||
}
|
||||
|
||||
float toSRGB(float color)
|
||||
lowp float toSRGB(lowp float color)
|
||||
{
|
||||
return color < 0.0031308 ? (12.92 * color) : (1.055 * pow(color, 1.0 / GAMMA) - 0.055);
|
||||
}
|
||||
|
||||
vec4 toSRGB(vec4 colour)
|
||||
lowp vec4 toSRGB(lowp vec4 colour)
|
||||
{
|
||||
#ifdef GL_ES
|
||||
return g_GammaCorrection ? vec4(toSRGB(colour.r), toSRGB(colour.g), toSRGB(colour.b), colour.a) : colour;
|
||||
|
||||
Reference in New Issue
Block a user