-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to create a custom rendering control ? #2176
Comments
Unfortunately, there is no easy solution. WritableBitmap would be faster than saving and loading the image to stream, but that will still involve a transfer from video memory to the main memory and back. For more performance we need a way to interact with native framebuffer texture like WPFs D3DImage does. The problem here is the variety of rendering APIs that can be actually used. Skia has support for OpenGL, OpenGL ES and Vulkan Win32:
Linux:
Mac OS X:
We have a set of abstractions for OpenGL/OpenGLES that allows us to manipulate OpenGL contexts in somewhat unified way: GlInterface, IGlContext and IGlDisplay. One can obtain glGetProcAddress from said abstraction, but that will most likely be not sufficient for a game engine that probably wants to initialize OpenGL itself. Another problem is that on some platforms we are using OpenGLES, on other desktop OpenGL gets initialized. We could expose a way to provide your own SkImage as a bitmap, but it has to be created by the same GL context. Another way would be to implement our windowing platform interfaces on top of your game engine and render Avalonia UI to a texture that gets later composed by the game engine itself. |
Another a bit hacky way would be to replace our |
I like the idea of having a special Bitmap for interop purposes. For Direct2D that would mean someone has to produce a shared bitmap from a scene graph he wants to display. That could very much be a 3D scene. Refreshing will still involve some invalidate visual calls. This solution isn't high performance but should still perform well. Rendering the Avalonia scene graph to some existing surface would perform better. |
Thanks @kekekeks for your tips
Yes is true, with the use of
Thats it's unfortunately not on what we want to focus in our team... Our game engine uses OpenGL, OpenGL ES, Vulkan, DirectX and Metal backends (not only OpenGL), depending on the executing platform and user settings. It will not easy for us to cover all these API for a proxy Avalonia renderer. And, if I understand well, we also have to create a proxy for Avalonia controls events, which means for us a lot of work that will not fit in our deadlines. With a benchmark test, we can say that our game rendering loop (running with up to 26 FPS) is not synchronized to the Avalonia renderer loop (running with up to 16 FPS), this is caused by invalidating the Image control at every game rendering passes, but the control will be rerendered at each Avalonia rendering passes. To bypass the Avalonia renderer (only for the Image control), after a - small - deep look at the Avalonia source code, we found a ImmediateRenderer class (Hallelujah!) which have a There is a way to get the current IRenderTarget of the window ? (Sincerely, I don't think that If it may help, we are running tests in a PC with our minimal requirements target:
For now we are only testing on Linux platforms (due to the broken state of the DirectX backend on Windows). Thanks again for your help. |
If you are planning to use ImmediateRenderer, you need to switch to it when initializing windowing platform (UseWin32, UseGtk3, UseAvaloniaNative) calls, otherwise rendering would be mixed with DeferredRenderer, which isn't a good thing. |
Another thing to consider is that DeferredRenderer's loop runs on 60FPS tick rate on a separate thread. We might want to add a way to hook to said renderer pass and update the bitmap. That would require to associate a layer to a control, but that should be doable. I'll try to figure something this month. The API would look somewhat like: class MyControl : Control, IThreadSafeRenderControl
{
WritableBitmap _bitmap = new WritableBitmap(100, 100);
bool IThreadSafeRenderControl.ThreadSafeRender(Func<DrawingContext> getContext, Size dimensions, bool alwaysProduceFrame)
{
using(var fb = bitmap.Lock())
{
// Do stuff
}
getContext().DrawBitmap(_bitmap);
return true; // We have produced a new frame
}
} This method would be called on every frame. If there is something new, you'll need to draw the bitmap. |
The API will be most likely changed a bit since we need something like that for playing GIF animations, but the general idea would be the same. |
Casting your window to https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Visuals/Rendering/IRenderRoot.cs should give you the instance of the currently used renderer. Starting your App with UseDeferredRendering to false should produce a ImmediateRenderer. That instance has an overload of the Render method that accepts an IVisual and a DrawingContext. As far as I understand you can create a DrawingContext for the currently used RenderTarget. Maybe this helps a bit. Haven't checked this info. |
@na2axl You can test it by installing |
Thanks for your work @kekekeks I'll will try this tonight ! |
Build |
🎉 🎉 🎉 Thanks very much @kekekeks for your PR, It's just awesome the window and the game loop are running at 60 FPS together ! No more graphics glitches and frame skips ! 🎉 🎉 🎉 Thanks again @kekekeks and @Gillibald for your help 😃 |
This PR comes with new exceptions thrown and debug warnings, but these doesn't block the program execution. If it may help you I will left this debug log here:
Lines starting with |
Hello, I've been meaning to work on a personal project which is of a very similar nature to the one OP describes. However, I notice the mentioned PR was never merged in. Is there an alternate solution to achieve the same result? I saw in the samples that there was an 'OpenGlPage' demo (but that doesn't seem to work in 0.9 I'm assuming its > 0.10?) but what about other APIs like DirectX? And I assume hosting a win32 window would lead to 'airspace' issues like in WPF? Apologie sin advance if I should have created a new issue. |
Native opengl context sharing is available in 0.10. Unfortunately on Windows it requires not-yet-stable WGL backend. There is planned support for DXGI surface sharing, but it it expected to land somewhere next Spring. |
Ok I will keep an eye out for that, thank you 👍 |
In conclusion, is it not recommend to implements a custom drawing control at this time (real-time chart purpose for me)? |
@GF-Huang I think you can easily have realtime charting with normal rendering control. https://github.com/AvaloniaCommunity/awesome-avalonia#chart--plot |
The The The |
You should be able to implement your own charting without the need for special rendering.. just implement a control and override render... obviously there is a lot more to it.. in terms of drawing the char... but I think it shouldnt need anything specialised. |
using |
It works, thank you. |
I suggest porting https://github.com/dotnet-ad/Microcharts to Avalonia. This should only require one custom control that is implemented with a few lines of code. |
|
Use SKCanvas directly (see
Just make sure that your drawing operation is actually thread safe. |
What difference to |
Aside from custom drawing operation, there is an API for low level graphics interop #9925 |
Hi,
I'm currently working on a game engine for my company, and with a lot of research, we found that Avalonia is the best choice for our cross platform game editor. However, I'm always new to Avalonia so excuse me if my problem is not really a problem or if I'm wrong somewhere...
I've understand that Avalonia use Skia + Direct2D or OpenGL backend for rendering the whole window, so its not very difficult to create a custom renderer for a whole window rendering. But what I want is not to render onto the whole window but just somewhere in it (like the scene manager of Unity3D for example).
I've tried to create an offscreen game rendering thread to render the game, and exporting the framebuffer texture to an image stream. Into the MainWindow, we have an Image control, which at each render passes of the game background thread, changes its Source property with the exported image stream.
This process is working, but we have a - unsupportable - performance issue because the rendered image seems to skip too much frames. We have tried to solve this issue but we got nothing satisfying our needs...
So my question is to know if I'm doing things wrong ? Avalonia has already a solution for this case ? Is there a better way to implement this rendering control ?
Thanks in advance.
The text was updated successfully, but these errors were encountered: