View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0001301 | NoesisGUI | C# SDK | public | 2018-05-17 12:24 | 2020-06-19 16:04 |
| Reporter | ai_enabled | Assigned To | sfernandez | ||
| Priority | high | Severity | feature | ||
| Status | assigned | Resolution | open | ||
| Product Version | 2.1.0f1 | ||||
| Target Version | 3.0 | ||||
| Summary | 0001301: Cache for GUI.LoadComponent(object, string) | ||||
| Description | Hi guys, Getting XAML code every time a control of the specific type is loaded and passing the full string to C++ is not fast. Regards! | ||||
| Attached Files | |||||
| Platform | Any | ||||
|
Sorry, I was confused and thought that we're actually transferring the XAML content to load the component. Well, we're not doing that and only transferring the path to XAML. However, the problem is that NoesisGUI loads XAML every time - XamlProvider.LoadXaml(fileName) method is invoked for a control every time it's needed to be loaded and that's a huge waste of performance as we had to open the stream from the disk. The current implementation is useful in case when the XAML is changed to see the reloaded file, however, this implementation is wrong - you should create another method to invalidate the NoesisGUI cache for a particular fileName and, maybe, reload all the UserControls/ResourceDictionaries related to the loaded fileName (which is very hard, I think). Regards! |
|
|
Problem is, each time a new UserControl is loaded we need a new tree, we cannot reuse the same (this is something we were doing in Noesis 1.X but it was not WPF conformant). So, the only thing that can be done is caching the stream, and this is something you can already do in your provider... This is something we want to address in the future, but we are not sure yet how to do it. We could instantiate usercontrols by cloning a base one, each time it is requested. This is faster that loading the XAML but... we also have plans to support a compressed format of XAML (something like the BuildTool we have in Noesis 1.x but this time as an optional path, not mandatory in case you just want to directly load XAMLs) |
|
|
Yes, I understand that you need to build a new visual tree for every UserControl. The XAML parser is indeed very fast and effective, but in a such scenario it's not as fast as it might be (especially for applications on the less powerful, mobile devices). I believe that caching of the parsed data will minimize the overhead. It could be a kind of the tokenized structure which can instantly instantiate a visual tree ("compressed XAML" sounds good but it's not a real solution as it still involves a binary stream reading and C#<->C++ interop overhead every time a UserControl is instantiated). It seems it could be done without changing the current C# API. GUI.LoadComponent(object, string) on the C++ side can use a dictionary - binding the string (XAML file path) to the cached static visual tree. |
|
|
Before analyzing this with more detail (I want to measure the performance of cloning the tree vs reading a stream from file) are you observing a real performance issue here or a theoretical one? |
|
|
Mostly theoretical and with a hope of a possible trivial fix. I've observed a real performance issue on a simulated lower performance machine (I've clamped the CPU clock speed) when I was testing a relatively heavy user controls which were dynamically spawned when user moved the mouse cursor over UI elements or game world objects. Of course, such a heavy use case might be (or often should be) avoided in the game design itself. |
|
|
Thanks for the detailed clarifications! |
|
|
Hi, Even though I'm using items virtualization for this ItemsList, NoesisGUI is still creating a user control instance via Noesis.Extend.CreateInstance(IntPtr, IntPtr). Of course, I can easily fix this on my side. But it's a good example of massive unexpected performance loss. Imagine 1000+ entries list with each entry invoking LoadComponent! If there is a XAML cache it would be not an issue. See the attached screenshot. Oh, and I'm really curious what's wrong with the Virtualization. The xaml code is:
Regards! |
|
|
It seems UniformGrid and WrapPanel doesn't support virtualization. But I have the same problem with VirtualizingStackPanel. |
|
|
We have been discussing here for a long time about a solution for caching UserControls and I think we found a good solution (at least in theory, we still have to implement it). The idea is storing in the cache the internal parsing of the XAML, each time a new UserControl is requested we only have to instantiate that internal tree. That should be a lot faster that parsing directly from XAML. But in the case you mention, this optimization shouldn't be necessary if virtualization were properly working. @sfernandez could you have a look at this? There is a warning message we send to the console if virtualization cannot be enabled. Are you getting it? |
|
It seems the virtualization is working fine for VirtualizedStackPanel but it would be best if you can verify that it works fine for UserControls. In my case even though I have recycling mode enabled it still creating a new intance of my user control every time the entry is added to the observable collection bound to this items control. |
|
|
Is that ItemsControl using a custom template containing a ScrollViewer? the default template for ItemsControl doesn't have one. Please try the following (I set the Height to a fixed size just to make sure the control does not extend to the size of all items, what could occur if it is wrapped by a ScrollViewer or a vertical StackPanel): <ItemsControl ItemsSource="{Binding PlayersOnline}" Height="300" |
|
|
Thanks, Sergio. I've programmed it to simply remove-add-remove-add the same item into the observable items collection so the view control could be recycled, but unfortunately it's not recycled. |
|
|
If you want to try it in the game I can submit a code for you now so you can unpack Core.cpk and try it yourself :-) |
|
|
Are you getting any warning on the console? |
|
|
As far as I understand, if the item if being removed-added-removed-added but it is always visible, the usercontrol is going to be created each time. With virtualization only non-visible items are non created. But I could be wrong... @sfernandez |
|
|
I cannot see any warning or error regarding the virtualization from NoesisGUI (but there are a ton of binding failed messages, sounds like I will need to find some time to improve the game UI in this regard). |
|
|
@jsantos That's right, adding non visible items to the observable collection shouldn't instantiate the ItemTemplate. |
|
|
Hi, I created a small test trying to reproduce your scenario with an ItemsControl and an ItemTemplate with a custom control: <Grid x:Class="Testing.VirtualizationTest" This xaml shows 9 visible items, and only 9 'Testing.MyControl' objects are created, one for each visible item, and one extra object for the DataTemplate. If I scroll 1 line it ends reusing the previously created controls, so recycling is working. And if I add a new item to the collection no new control is created, even if the new item shows up in the visible area and there are recycled containers available. I'm pretty sure that in your case virtualization is not happening. Can I see the xaml where you have your ItemsControl?, maybe I see something that points me what could be happening. |
|
|
It is not the first time that this happens, I mean, the confusion about if virtualization is enabled or not. We need to improve this someway, I don't know, clearly the log message is not enough, maybe a new boolean synthesized property? The good thing about the property is that it can be inspected in the new inspector tool (coming with the next major version) |
|
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2018-05-17 12:24 | ai_enabled | New Issue | |
| 2018-05-17 12:25 | ai_enabled | Description Updated | |
| 2018-05-17 12:36 | ai_enabled | Description Updated | |
| 2018-05-17 13:22 | ai_enabled | Note Added: 0005201 | |
| 2018-05-17 13:22 | ai_enabled | Note Edited: 0005201 | |
| 2018-06-01 22:41 | jsantos | Assigned To | => sfernandez |
| 2018-06-01 22:41 | jsantos | Status | new => assigned |
| 2018-06-01 22:45 | jsantos | Note Added: 0005211 | |
| 2018-06-01 22:45 | jsantos | Status | assigned => feedback |
| 2018-06-02 08:15 | ai_enabled | Note Added: 0005212 | |
| 2018-06-02 08:15 | ai_enabled | Status | feedback => assigned |
| 2018-06-02 08:17 | ai_enabled | Note Edited: 0005212 | |
| 2018-06-05 20:39 | jsantos | Note Added: 0005217 | |
| 2018-06-05 20:39 | jsantos | Status | assigned => feedback |
| 2018-06-05 21:06 | ai_enabled | Note Added: 0005219 | |
| 2018-06-05 21:06 | ai_enabled | Status | feedback => assigned |
| 2018-06-05 21:06 | ai_enabled | Note Edited: 0005219 | |
| 2018-06-05 21:07 | ai_enabled | Note Edited: 0005219 | |
| 2018-06-05 21:10 | ai_enabled | Note Edited: 0005219 | |
| 2018-06-05 21:50 | jsantos | Note Added: 0005220 | |
| 2018-11-01 02:14 | jsantos | View Status | public => private |
| 2019-11-28 17:16 | ai_enabled | File Added: Screenshot at 20-15-34.jpg | |
| 2019-11-28 17:16 | ai_enabled | Note Added: 0006013 | |
| 2019-11-28 17:25 | ai_enabled | Note Added: 0006014 | |
| 2019-11-28 17:26 | ai_enabled | Note Edited: 0006014 | |
| 2019-11-28 17:31 | jsantos | Note Added: 0006015 | |
| 2019-11-28 17:32 | jsantos | Status | assigned => feedback |
| 2019-11-28 17:32 | jsantos | Note Edited: 0006015 | |
| 2019-11-28 17:34 | jsantos | Note Edited: 0006015 | |
| 2019-11-28 17:38 | ai_enabled | Note Added: 0006016 | |
| 2019-11-28 17:38 | ai_enabled | Status | feedback => assigned |
| 2019-11-28 18:04 | sfernandez | Status | assigned => feedback |
| 2019-11-28 18:04 | sfernandez | Note Added: 0006017 | |
| 2019-11-28 18:07 | sfernandez | Note Edited: 0006017 | |
| 2019-11-28 18:11 | ai_enabled | Note Added: 0006018 | |
| 2019-11-28 18:11 | ai_enabled | Status | feedback => assigned |
| 2019-11-28 18:12 | ai_enabled | Note Added: 0006019 | |
| 2019-11-28 18:13 | jsantos | Note Added: 0006020 | |
| 2019-11-28 18:15 | jsantos | Note Added: 0006021 | |
| 2019-11-28 18:35 | ai_enabled | Note Added: 0006022 | |
| 2019-11-28 19:18 | sfernandez | Note Added: 0006023 | |
| 2019-11-28 21:20 | sfernandez | Note Edited: 0006017 | |
| 2019-12-02 17:32 | sfernandez | Status | assigned => feedback |
| 2019-12-02 17:32 | sfernandez | Note Added: 0006027 | |
| 2019-12-02 17:40 | jsantos | Note Added: 0006029 | |
| 2020-06-19 13:02 | jsantos | Target Version | => 3.0 |
| 2020-06-19 13:02 | jsantos | Platform | => Any |
| 2020-06-19 13:15 | ai_enabled | Status | feedback => assigned |
| 2020-06-19 16:04 | jsantos | View Status | private => public |