Process render events with RenderQueue.#813
Conversation
|
Hi @StendProg, thank you for this fantastic contribution! There is a lot of code/architecture for me to study with this PR, so I waited until I had a lot of time to review it thoroughly. I am excited to work on this today, and I will start by adding XML documentation and renaming things if it would make them more easily understood. I'll keep my modifications limited to today so we don't get merge conflicts in case you want to keep working on this PR. I'll follow-up shortly with comments addressing the TODOs/questions in your original message. Thanks again for this wonderful PR! |
|
Hi @StendProg, I noticed the Thanks for your input! ScottPlot/src/ScottPlot/Control/EventProcess/EventsProcessor.cs Lines 129 to 171 in 07cc64e |
|
Hi @swharden,
This is a simple analogue of |
This commit simplifies render quality configuration by moving render quality state out of individual events and placing it in the control Configuration class. This commit replaces the decorated event factory, removes the interface from the factory, and also changes most class fields to be readonly.
No problem! I appreciate your contribution so much, and this is already an excellent improvement. I want to keep moving forward with regular releases and avoid long-running PRs, so I'm going to work on this a lot today and merge it in today or tomorrow. I'll continue to refactor it to reduce complexity, refine language, and add documentation. |
RenderLowThenHighQuality() has been added to controls. Resizing now uses the render queue to trigger LQ/HQ renders. Resizing produces flickering, but no longer blocks the UI thread. XML documentation has been added to public methods/fields in controls and the control back-end.
This commit fixes a bug where mouse events were getting sent to the queue for processing too early, and the host control did not have time to wire-up the event handler before processing them. This new strategy uses a flag to hold the event processor in an infinite loop until the host control calls Backend.StartProcessingEvents()
Previously bitmaps were displayed in the control when new bitmaps were created. This causes a problem where unfinished bitmaps are rendered to the screen. This problem wasn't observed previously because render events were UI blocking, but now that they're decoupled resizing causes flickering. This commit fixes this problem by moving the UpdateBitmap() call to inside the render loop, so it's only called after the new bitmap is rendered upon. This commit also improves behavior such that resize events trigger low-quality initial renders followed by a delayed high-quality render.
prevent duplicate low quality render
bring into consistency with FormsPlot
This lets developers enable/disable the experimental queue-based rendering system. This is off by default and the traditional (UI-blocking) render system is used. Delayed high quality render following the mouse wheel is no longer supported with the traditional rendering system.
|
@StendProg, thank you again for this excellent PR! I worked on it extensively and will merge it in and release a NuGet package today. Here are some important points: Summary of the New Render SystemWhen GUI events occur (mouse clicks, mouse drags to pan/zoom/drag, mouse moves which may require a cursor change, or window resize events) the user controls call a function in the backend module named according to that interaction. The backend module then constructs an event (using a factory for each event type) and decides how to process it. If If Right now the render queue is disabled by default. Compare Queue vs. Traditional RenderingThe sandbox folder contains I find it especially interesting to compare these methods paying close attention to click-drag pan/zoom responsiveness and also program responsiveness when resizing the window. The queue method is faster when interacting with complex plots, but slower when interacting with simple plots.
Next Steps / Room for Improvement?Responsiveness: The render queue method is slightly (but noticeably) less responsive while panning/zooming simple plots than the original method. This is the main reason I don't want to enable it by default. Considering how threading is handled, I'm not sure if it is possible to improve this. I welcome any ideas for improvement! For complex/intensive plots, it's great to have this render queue system in place. Documentation/API: I'll keep thinking about the best API to use here. It would be nice if the user had automatic and manual control of rendering. For example, when adding a complex dataset to a plot programmatically it would be nice if the user could trigger non-blocking renders (perhaps with an initial low quality render and an automatic high quality render afterword). I may continue to refactor the queue system over the next few weeks to improve simplicity, features, and documentation. @StendProg if you're interested in working on this system more let me know and I'll stop working on it for a while to avoid merge conflicts. Thanks again for all your support here! This is a great improvement for this library! |
|
Hi @swharden, Thank you for finishing this work, I was a little ashamed for leaving the unfinished for weeks, but after looking at what you did, I realized that only you could do it (added your video and greatly simplified it). I have several non-critical remarks, I will express them since I have already read your code, but all of them are essentially insignificant, as advice or reason to take note of for the future. It's common to name public properties with a capital letter and private fields with a lowercase letter (even with an underscore, but I just can't get used to it). In any case, looking at the code, it is convenient to understand what area of responsibility this or that variable has, and this is easy to understand if you follow the rules described above. capitalized private fields are a little confusing, but this is a minor detail. A readonly modifier protects only the object itself from changes, while the fields of this object may well be changeable. public RenderType RenderType => Configuration.QualityConfiguration.MouseInteractiveDragged;A property of this kind may look convenient, but it creates unnecessary dependencies in the code, and potentially there may be problems with logic and multithreading. The immutable class is preferable, there will definitely not be any problems with it. If you want to preserve the convenience of configuration, then you can copy the RenderType when creating the event object, and only then let it remain unchanged. (This is just a description of my initial motivation, in this particular case, I think there will be no problems with your option). while (Enable == false)
{
await Task.Delay(1);
}Looks like a big crutch. At first glance, you can unravel all this and run the initialization in the correct order, but I have not gotten to know this problem in detail, there may be some complications. |
I had a guess why this is, and it's not about the additional overhead, but about a different drawing order. After running the demo application that you provided, I caught myself thinking that I could not catch the difference, no matter how I tried. I cannot understand what my problem is. In any case, I will express my thoughts. |


Purpose:
Process all interactive events using
RenderQueue. #761Base concept:
There is 9 types of events:
For each of these types, there is a corresponding class that contains the Action with "math" logic and the
RenderType.After an interactive event occurs, the corresponding class is added to the queue. The logic handler is guaranteed to be called for it, but rendering will happen only when the queue is cleared, i.e. after processing the last event.
The behavior of the
Renderafter the last event is specified using theRenderTypeand can be unique for each event type.There is 5
RenderTypes:Renderwill be called if this event is last in queueRender` will be called if this event is last in queueRenderwill be called if this event is last in queue, HQ after, if new events not added duringLQRenderNoneevent behavior.ControlBackendcontain 2 fields:RenderType for classes can be customise using
UIEventFactoryDecorators.There is 5 types build in, but their number can be easily expanded.
TODO:
Control,Plotevents used to be tightly tied toRender, so now manyInteractionswill be skipped if rendering is not called for them. We need to call these events directly in the logic. Or is it not necessary?EventProcessor. At the very last moment, it is very helpful in understanding what is going on.New Functionality:
An example of setting different behaviors, in theory, the behavior can be changed on the fly (Not tested)