-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Separate the rendering and widgets #6447
Comments
Hi, By rendering you mean e.g. software rendering which actually draws a rectangles, text, etc, or even an upper layer which creates What would be use case for this separation? Who will do the rendering in the end? |
This can be useful in cases where WASM is used (notably with WAMR on embedded devices) where the client application is sandboxed, preventing direct access to host memory. A naive approach would be to have a buffer per client application (each instance running its own LVGL "rendering engine"), but this is not very memory-efficient. A better approach would be to compile LVGL as a WASM module without the rendering part (which is likely the heaviest part). The client application would then load this WASM LVGL module, create and set the necessary properties on its objects/widgets, and send references to the parent objects to the host containing the "rendering engine". These references would be attached by the host to one of the screens and then rendered. Minimizing the size of the WASM part is crucial since the entire code is compiled when building it as a WASM module (similar to a shared library). |
I see now but I'm not sure if it will work. Or have you already tried mixing the widget created by multiple LVGL instances? My concern is that (I assume) each instance will create the widgets in its own memory pool. However it can happen that an other LVGL instance will delete/free the widgets. In this case cc @liamHowatt |
Yes, that was also one of the points where I was not sure how to proceed. We would need to have a kind of
And normally this should resolve the issues between the different allocators, with the host owning the parent/screen and the WASM application owning the object in question. |
Could you please go into a bit more detail about what exactly |
Using a custom allocator which uses the host memory could be an option too. But I guess it beats the purpose of sand boxing. |
This function would do the same thing as
However, we wouldn't have the first part because |
Yes, in a raw manner, this is not a solution for executing unverified code since the passed host pointer could be modified at any point by the guest application. |
According to my understanding, do you just need to write a virtual draw driver? |
Yeah, could you write a draw driver that serializes the draw descriptors and coords and the host's LVGL deserializes the commands and calls In order to get any binary size savings, the serializer would have to be smaller than the rendering code it's replacing.
It would be good to actually measure the compiled code size somehow so this isn't a wasted effort. Fyi: #6313 |
How can we handle edge cases like this:
As the problem is only the deletion a solution could be this:
Now the application has full freedom, but can the host do?
What do you think? |
Yes, this approach seems quite good to me as well because it completely eliminates the problem of choosing the allocator. However, we need to ensure that these calls for each rendering to the API via FFI are not too frequent, as FFI calls are quite expensive in terms of CPU time. The same issue applies to serialization/deserialization also (we could also use CBOR, by the way). |
If I understand correctly, you want to create a new type of widget (a kind of container dedicated to FFI?). This is a very good idea and quite efficient. The fact that the host cannot do anything on the application's widgets doesn't seem too problematic to me because I don't see many scenarios where this would be useful. |
But yes, to start with, in order to be sure that all this is worth it, I can proceed with adding flags to exclude the rendering part from the compilation. However, before I start, I would like to know if you think this is feasible without major refactoring (with just the addition of #if here and there). Because I don't know to what extent the rendering part is intertwined with the widget "setting/getting" part. |
Actually rendering quite intertwined with the widgets as all widgets call
Option 2) would save much more flash as the extra code for rendering can be quite long. See e.g. here. However, I don't think it would work. If the rendering code is no there, when the host asks the applications' widgets to render themselves nothing will happen as the rendering logic is removed from the application. This way, it won't be possible for the applications to define custom draw events either. E.g. this. In light of that maybe the serialization path that @liamHowatt recommended could be better. A simpler approach could be to disable all rendering units (e.g. If we pass the application's main container's pointer to the host and the host will see the widgets as they were created there, the It just came t my mind: can we read the application's memory from the host? |
I didn't know that one could customize the rendering pipeline to this extent with LVGL. Yes, indeed, it seems like a good solution. However, how do you think we could proceed to add draw task to host draw tasks ? And yes, the host can access the guest application's memory, you just need to perform address translation beforehand. |
We need some feedback on this issue. Now we mark this as "stale" because there was no activity here for 14 days. Remove the "stale" label or comment else this will be closed in 7 days. |
I'm sorry, I missed your reply. 🙁 Let's say you have an lv_obj_t * wasm_attach_lvgl_app(lv_obj_t * parent_in_host, lv_obj_t * root_widget_of_the_app); This function manually adds a new child to Do we need the address translation if LVGL call the callbacks and uses the children in C? I hope not. 😄 🤞 |
Yes, that should be the most appropriate solution (essentially what I meant with my For the callbacks (I assume you mean the event callback), a custom function should be added to register event callbacks (specifically for address translation). However, the Another issue is that the WASM LVGL part is still quite large in terms of binary size when compiled as a WASM module. This is somewhat expected since all of the drawing code is still included (even though it is completely unnecessary). The compiler treats a WASM module like a dynamic library and does not remove unused code, I believe. We could link LVGL statically to allow further optimization; however, that would mean each WASM module instance has a copy of the LVGL code, which is not ideal in memory-constrained environments. |
Regarding Regarding the events: I think/hope events registered in the app will work in the app, without any further action. However, I see how events added to the app from the host can be tricky. Regarding memory size: It would be huge to use LVGL as a library which can be linked to multiple apps. However, as I described above probably the drawing routines cannot be removed to let the users use them in custom draw events. But maybe it's not so important, because it seems we can have this setup:
What do you think? |
We need some feedback on this issue. Now we mark this as "stale" because there was no activity here for 14 days. Remove the "stale" label or comment else this will be closed in 7 days. |
As there was no activity here for a while we close this issue. But don't worry, the conversation is still here and you can get back to it at any time. So feel free to comment if you have remarks or ideas on this topic. |
Introduce the problem
It would be good to be able to get rid of the rendering part when needed (with a
#define
inlv_conf.h
), somewhat like having a "client" side and a "server" side.Proposal
The client side would only be responsible for setting up and configuring the data structure structures, and the server side for the rendering and input device. Currently, LVGL compiled in WASM occupies ~600 KB, which is significant. I think we can reduce this by getting rid of the rendering part.
The text was updated successfully, but these errors were encountered: