Single flush for single frame buffer

I am using the FMC peripheral and parallel interface of my microcontroller and I was looking into the best approach for sending the frame update to the LCD. The behavior I’m after is all drawing is done into the full size frame buffer, I don’t see the point of drawing it into small buffers, then copying it to the frame buffer. Then get one call to flush once the frame is updated, with the minimum update area set.

I have hacked the library slightly which is giving me almost the result I want. I have passed the same buffer pointer into the init function.

lv_disp_buf_init(&displayBufffer, frameBuffer, frameBuffer, FRAME_BUFFER_SIZE);

Where FRAME_BUFFER_SIZE is the size of the LCD. This causes the lv_disp_is_true_double_buf() to return true so all drawing is done into the single frame buffer. I have then commented out the code that copies the data between the two frame buffers in _lv_disp_refr_task(), so the true double buffering code is effectively this.

if(lv_disp_is_true_double_buf(disp_refr) && disp_refr->driver.set_px_cb == NULL) {
    lv_refr_vdb_flush();
    while(vdb->flushing);
} /*End of true double buffer handling*/

I then get a single call to flush at the end of the frame update. The only downside to this is that the area is always set to the entire frame. So even if only a small area was updated Is I still have to send the whole frame.

I was wondering if there should be a single full buffer option, that behaves like true double buffering for drawing, but doesn’t perform the buffer copy in _lv_disp_refr_task() and also records the area affected during the frame update.

Does this sound like a good idea? Or have I missed a simpler way of doing this?

Hi,

You can do this by setting only one buffer (lv_disp_buf_init(&displayBufffer, frameBuffer, NULL, FRAME_BUFFER_SIZE);) and using rounder_cb in the display driver to round all areas to screen-sized.

Perfect thanks, I will give this a go.

This isn’t quite what I had in mind.

First of all using a single buffer means that lv_refr_area runs a lot more code to decide how much buffer it needs to use. This could be prevented with a special case that deals with single full frame buffers.

Then because we are rounding the minimum area up to the full frame, the flush callback always get the entire frame, even if less than the entire frame has been updated.

What I would really like is for LVGL to detect that the single buffer is the full frame size (this could be achieved simply with a function similar to lv_disp_is_true_double_buf) and therefore not run all the extra code in lv_refr_area. Then execute the flush callback with the start and end rows that have been updated after a the entire tick update has been performed.

I am only trying to optimise the flush functions and this may not be worth that much performance, but I thought it was worth asking.

Could you point to that “lot more code” that runs on lv_refr_area? I see only a few simple operations and short cycles.

If you already have a solution proposal in mind feel free to send a PR. It might be easier to discuss it if see an example implementation.

Hi, where i can found an example?
I have the same condition with a framebuffer pointer.

Thanks a lot.
Andrea

The documentation page @kisvegabor linked has an example. I think you would do something like this:

void my_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area)
{
   area->y1 = 0;
   area->y2 = <display height> - 1;
   area->x1 = 0;
   area->x2 = <display width> - 1;
}

Hi, thanks for reply!

Then with a framebuffer i add this code. But in flush_cb(…) i have to leave only
lv_disp_flush_ready(disp_drv) ?

I’m pretty sure that’s what he intended, though I haven’t tested it myself.