Comments (12)
@Tom94 is this still an issue?
from osu-framework.
Yup, it still is. Note, that currently this is not a correctness problem, but rather makes invalidations slightly more inefficient than they could be. More specifically: if something like Color
is invalidated, then the entire DrawInfo
gets invalidated; potentially for the subtree if it depends on the DrawInfo
of its parent.
from osu-framework.
Just for documentation, there are a few special cases coded in to handle the fallout effects of this:
baba269#diff-74fa55675af99d2ab8d5ed0f726caf41R332
and
from osu-framework.
Now that the framework progressed quite a bit further than when this issue was initially opened I think the general problem is clearer: this issue surfaces whenever the same underlying Cached<>
is invalidated by different invalidation types. The solution to break this problem apart is to split DrawInfo
further into individual components as done with color in #1836.
from osu-framework.
An another case is illustrated in #1803 FillFlow2
and FillFlow2Simplified
.
from osu-framework.
I think this invariant should be maintained:
- If a
Cached
(SayA
) is invalid then otherCached
(SayB
) which depends onA
should be invalid.
Parent:
Cached<TypeA> Abacking;
TypeA A => Abacking.IsValid ? Abacking.Value : (Abacking.Value = ComputeA());
TypeA ComputeA() => ...;
Child:
Cached<TypeB> Bbacking;
TypeB B => Bbacking.IsValid ? Bbacking.Value : (Bbacking.Value = ComputeB());
TypeB ComputeB() => someFunc(Parent.A).
invariant: !Bbacking.IsValid || Parent.Abacking.IsValid;
from osu-framework.
Suppose there are two invalidations, I1
and I2
.
Suppose there are two drawables, X
and Y
with X
containing Y
.
Suppose X
has one cached value, C1
, and Y
has one cached value, C2
.
Suppose X
responds to both I1
and I2
and invalidates C1
.
Suppose Y
responds to I2
and invalidates C2
.
X
invalidates withI1
, it invalidatesC1
, propagates toY
, which then proceeds to do nothing.X
invalidates withI2
, it sees thatC1
is already invalid, so it doesn't propagate.Y
cannot respond toI2
becauseX
has determined it unnecessary to be propagated.
It seems like you're suggesting that C2
should depend on C1
, but I have not mentioned anything about the relationship between C1
and C2
- for all we know they may be completely independent of each other.
Rather the issue is that I1
and I2
both touch C1
.
from osu-framework.
That case can be implemented as follows:
- There are cached properies
CI1
andCI2
. X.C1
depends on bothX.CI1
andX.CI2
.Y.C2
depends onX.CI2
.
from osu-framework.
Here's another case of this happening:
public class TestCaseScratch : TestCase
{
public TestCaseScratch()
{
Child = new TestContainer
{
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.5f),
Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Width = 0.5f,
Colour = Color4.Red
},
new Box
{
RelativeSizeAxes = Axes.Both,
Width = 0.5f,
Colour = Color4.Green
},
}
},
};
}
private class TestContainer : CompositeDrawable
{
public Drawable Child
{
set => childContainer.Child = value;
}
private readonly Container childContainer;
public TestContainer()
{
InternalChild = childContainer = new Container();
}
protected override void Update()
{
base.Update();
childContainer.Size = DrawSize;
}
}
}
B.Invalidate(DrawSize)
doesn't get propagated on resize.
from osu-framework.
public class TestSceneFillFlowContainer : TestScene
{
public TestSceneFillFlowContainer()
{
TestContainer testContainer;
Add(testContainer = new TestContainer
{
RelativeSizeAxes = Axes.Both,
Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Height = 0.25f,
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Beige,
Width = 0.2f,
},
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Bisque,
Width = 0.2f,
},
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Aquamarine,
Width = 0.2f,
},
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Cornsilk,
Width = 0.2f,
},
}
}
});
AddSliderStep("Adjust scale", 0.5, 1.5, 1.0, b => testContainer.AdjustScale((float)b));
AddStep("Invalidate layout", () => testContainer.Invalidate());
}
private class TestContainer : Container<Drawable>
{
public void AdjustScale(float scale = 1.0f)
{
this.ScaleTo(new Vector2(scale));
this.ResizeTo(new Vector2(1 / scale));
}
}
}
from osu-framework.
Going to bump this up from candidate since we're reaching more and more cases where this is an issue.
from osu-framework.
As a bit of an update, I've started working on this issue in https://github.com/smoogipoo/osu-framework/tree/invalidation-rework .
I've come up with the following structure:
Drawable A:
- Layout L_A
- Drawable B:
- Layout L_B
- Drawable C
- Drawable B_1
Invalidate(A, type)
- If
{ A, L_A, B, B_1 }
have already been invalidated with all of the given invalidation type flags, stop execution, otherwise: - Invalidate the layout of
A
. - Recursively invalidate the layout dependencies
{ L_A, B, B_1 }
.
Validate(L_B, type)
- If
{ L_B }
has already been validated with all of the given invalidation type flags, stop execution. - Validate
{ L_B }
. - Recursively validate the dependent layout
{ B }
.
Explanation
For a given subtree, we only care about two states:
- The entire subtree is invalidated.
- Any of the subtree is validated.
During the validation stage, we make sure that (2) is satisfied. Since we only care about any being validated we can avoid the O(N^2) complexity by validating the dependents only once for any particular invalidation type.
During the invalidation stage, since the previous validation has propagated upwards, we know when a particular hierarchy will need a validation at some point. This will fix this issue, and will also allow us to optimise our invalidations a bit more (see the original commit mentioned in the OP).
There is one edge case that I've yet to tackle in my WIP branch, which is when a layout is conditionally invalidated (e.g. SpriteText
or DrawColourInfo
for size changes).
from osu-framework.
Related Issues (20)
- iOS window losing focus (popup or suspend) doesn't update game active state
- Only allow one drag event at a time
- `SpriteIcon`s are unnecessary expensive HOT 7
- Frame statistics GC boxes are broken
- Unable to open more than one osu!framework based project at the same time HOT 1
- Frame statistics graph causes the visuals to become unresponsive if window isn't focused for a long time
- `LastDisplayDevice` being overridden on game startup in Borderless and Fullscreen modes, based on the window position and size from Windowed mode
- Investigate receiving input without using window event flow HOT 2
- Tablet input should have a property to allow adjusting the mapping target area
- `CancellationToken` should probably always be present in BDL calls
- Input thread blocking causes mouse handling stutters on windows HOT 5
- Game window sometimes does not respond to window size changes
- Periodic AccessViolation somewhere in BASS HOT 1
- Allow custom clear color for the window background HOT 5
- Crash on startup with Wayland fractional scaling
- Implement `CADisplayLink` on macOS for potentially better frame timing HOT 1
- Masking sub-tree creation can be avoided with relative ease HOT 3
- Consider using `WS_EX_NOREDIRECTIONBITMAP` HOT 1
- Flickering on fullscreen Vulkan (AMD gpu, Windows)
- SDL3: Segfault on wayland backend HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from osu-framework.