When true double buffering is enabled, flush callback always receive area equal of LCD size. When framebuffers are located in cached memory, CPU cache need to be flushed for large memory block before the buffer can be processed by LCD controller. This is quite slow operation. Flush callback should receive array of invalidated areas, so smallest possible memory size can be flushed.
Currently flush CB receives the lv_disp_drv_t parameter, but if it would receive lv_disp_t parameter instead, inv_areas could be used for this.
The same issue appears also in general, when switching from CPU to any GPU(HW) operation. Before entering GPU related functions, CPU cache shuld be flushed to make sure HW see the results from previous CPU draw. Again, only regions that are in interest of GPU and were changed by CPU need to be flushed = as small area as possible. It would be good to have list of all areas accessed during current refresh cycle.
CPU cache flush could be as a callback, as it’s very HW and OS specific call.
The purpose of “true double buffering” is to provide the whole image and you only need to change the address of the frame buffer to the rendered image. If you got areas you needed to copy the areas to your frame buffers. That’s “normal double buffering”.
So if you need the areas but still want a screen sized large buffer for LVGL just the buffers’ size to hor. res. x ver. res. + 1.
My understanding of the use case you have described is that you refer to mechanism when screen is refreshed in multiple (smaller) areas. When I set smaller buffers than LCD size, I receive small areas in flush callback, as you described. These areas are always (LCD-width)x(max possible height that fits into buffer).
What I am looking for is little bit different - When I enter into flush callback, i need information what areas were touched by CPU. Something like: “I’m flushing region 0x0 - 100x100, but note that only area 10,10 - 20,20 was repainted”.
I don’t need to copy or process flushed area. But before I set FB address to LCD-controller, I need to flush CPU cache to make sure that all results will appear in RAM. With current implementation I need to flush complete FB area (even areas, that were not repainted). If I have invalidated areas list, I could flush only range 10x10 px sized. My understanding is that I can’t simply flush whole CPU cache, as it can impact other devices. Therefore I need to flush only selected areas, possibly only those invalidated.
I don’t think LVGL stores this information internally. I’m pretty sure the finest detail you can get is the areas that are sent to flush_cb. As far as I know, everything within those areas was technically rewritten to memory (even if it was the exact same set of pixels).
I thought that this information is stored in lv_disp_t in inv_areas array. Comment says also “Invalidated (marked to redraw) areas”. Is my understanding wrong please?
I agree that when flush_cb is entered, everything is written into memory. But I think this is true only if FB is in non-cached area. If the FB is in cached area, it depends on CPU cache settings. For write-back areas CPU can operate in cache only, and without explicit flushing, results may not get to memory at all. In fact, I can see artifacts on screen without cache flush calls. (And those are short horizontal lines, which I believe are exactly 16px wide, as one cache line is 32 bytes long).
I know this topic is more about integration when talking about LCD output, but it comes more LVGL sensitive when any HW module is involved during drawing.
Yes, obviously anything that changes in memory needs to be explicitly flushed if write-back cache is used.
I think the information you’re looking for in this case is already provided by LVGL. You can just flush each area as it’s given to you in flush_cb (or merge all the areas and flush them in monitor_cb).
Yes, doing it in flush_cb is possible solution and it works. However I need to flush complete area, even though only few pixels were repainted. So if the inv_areas could be available, I could flush only those few pixels, instead of complete area.
Could you provide some details about monitor_cb idea please?
The idea is that you keep a static lv_area_t variable around and keep merging it with the areas given to you in flush_cb. Then, in monitor_cb, you flush this area and set its size to zero (so the next flush will start with an empty area).
I got it, thanks for the explanations. inv_areas really stores what you need.
There is no direct API to get those area, but you can use _lv_refr_get_disp_refreshing() to get a pointer to the being refreshed display where you can find the invalidated areas.