You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2022/11/28 12:50:41 UTC

[GitHub] [nuttx-apps] tmedicci commented on a diff in pull request #1341: LVGL v8 upgrade

tmedicci commented on code in PR #1341:
URL: https://github.com/apache/nuttx-apps/pull/1341#discussion_r999530953


##########
graphics/lvgl/port/lv_port_fbdev.c:
##########
@@ -0,0 +1,755 @@
+/****************************************************************************
+ * apps/graphics/lvgl/port/lv_port_fbdev.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/video/fb.h>
+#include <nuttx/video/rgbcolors.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "lv_port_fbdev.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_FB_UPDATE)
+#  define FBDEV_UPDATE_AREA(obj, area) fbdev_update_area(obj, area)
+#else
+#  define FBDEV_UPDATE_AREA(obj, area)
+#endif
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+struct fbdev_obj_s
+{
+  lv_disp_draw_buf_t disp_draw_buf;
+  lv_disp_drv_t disp_drv;
+  FAR lv_disp_t *disp;
+  FAR void *last_buffer;
+  FAR void *act_buffer;
+  lv_area_t inv_areas[LV_INV_BUF_SIZE];
+  uint16_t inv_areas_len;
+  lv_area_t final_area;
+
+  int fd;
+  FAR void *fbmem;
+  uint32_t fbmem2_yoffset;
+  struct fb_videoinfo_s vinfo;
+  struct fb_planeinfo_s pinfo;
+
+  bool color_match;
+  bool double_buffer;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: buf_rotate_copy
+ ****************************************************************************/
+
+#if defined(CONFIG_FB_UPDATE)
+static void fbdev_update_area(FAR struct fbdev_obj_s *fbdev_obj,
+                              FAR const lv_area_t *area_p)
+{
+  struct fb_area_s fb_area;
+
+  fb_area.x = area_p->x1;
+  fb_area.y = area_p->y1;
+  fb_area.w = area_p->x2 - area_p->x1 + 1;
+  fb_area.h = area_p->y2 - area_p->y1 + 1;
+
+  LV_LOG_TRACE("area: (%d, %d) %d x %d",
+               fb_area.x, fb_area.y, fb_area.w, fb_area.h);
+
+  ioctl(fbdev_obj->fd, FBIO_UPDATE,
+        (unsigned long)((uintptr_t)&fb_area));
+
+  LV_LOG_TRACE("finished");
+}
+#endif
+
+/****************************************************************************
+ * Name: fbdev_copy_areas
+ ****************************************************************************/
+
+static void fbdev_copy_areas(FAR lv_color_t *fb_dest,
+                             FAR const lv_color_t *fb_src,
+                             FAR const lv_area_t *areas,
+                             uint16_t len,
+                             int fb_width)
+{
+  int i;
+  LV_LOG_TRACE("%p -> %p, len = %d", fb_src, fb_dest, len);
+
+  for (i = 0; i < len; i++)
+    {
+      int y;
+      FAR const lv_area_t *area = &(areas[i]);
+      int width = lv_area_get_width(area);
+      int height = lv_area_get_height(area);
+      FAR lv_color_t *dest_pos =
+                      fb_dest + area->y1 * fb_width + area->x1;
+      FAR const lv_color_t *src_pos =
+                            fb_src + area->y1 * fb_width + area->x1;
+      size_t hor_size = width * sizeof(lv_color_t);
+
+      LV_LOG_TRACE("area[%d]: (%d, %d) %d x %d",
+                   i, area->x1, area->y1, width, height);
+
+      for (y = 0; y < height; y++)
+        {
+          lv_memcpy(dest_pos, src_pos, hor_size);
+          dest_pos += fb_width;
+          src_pos += fb_width;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: fbdev_switch_buffer
+ ****************************************************************************/
+
+static void fbdev_switch_buffer(FAR struct fbdev_obj_s *fbdev_obj)
+{
+  FAR lv_disp_t *disp_refr = fbdev_obj->disp;
+  uint16_t inv_index;
+
+  /* check inv_areas_len, it must == 0 */
+
+  if (fbdev_obj->inv_areas_len != 0)
+    {
+      LV_LOG_ERROR("Repeated flush action detected! "
+                    "inv_areas_len(%d) != 0",
+                    fbdev_obj->inv_areas_len);
+      fbdev_obj->inv_areas_len = 0;
+    }
+
+  /* Save dirty area table for next synchronizationn */
+
+  for (inv_index = 0; inv_index < disp_refr->inv_p; inv_index++)
+    {
+      if (disp_refr->inv_area_joined[inv_index] == 0)
+        {
+          fbdev_obj->inv_areas[fbdev_obj->inv_areas_len] =
+              disp_refr->inv_areas[inv_index];
+          fbdev_obj->inv_areas_len++;
+        }
+    }
+
+  /* Save the buffer address for the next synchronization */
+
+  fbdev_obj->last_buffer = fbdev_obj->act_buffer;
+
+  LV_LOG_TRACE("Commit buffer = %p, yoffset = %" PRIu32,
+               fbdev_obj->act_buffer,
+               fbdev_obj->pinfo.yoffset);
+
+  if (fbdev_obj->act_buffer == fbdev_obj->fbmem)
+    {
+      fbdev_obj->pinfo.yoffset = 0;
+      fbdev_obj->act_buffer = fbdev_obj->fbmem
+        + fbdev_obj->fbmem2_yoffset * fbdev_obj->pinfo.stride;
+    }
+  else
+    {
+      fbdev_obj->pinfo.yoffset = fbdev_obj->fbmem2_yoffset;
+      fbdev_obj->act_buffer = fbdev_obj->fbmem;
+    }
+
+  /* Commit buffer to fb driver */
+
+  ioctl(fbdev_obj->fd, FBIOPAN_DISPLAY,
+        (unsigned long)((uintptr_t)&(fbdev_obj->pinfo)));
+
+  LV_LOG_TRACE("finished");
+}
+
+#if defined(CONFIG_FB_SYNC)
+
+/****************************************************************************
+ * Name: fbdev_disp_vsync_refr
+ ****************************************************************************/
+
+static void fbdev_disp_vsync_refr(FAR lv_timer_t *timer)
+{
+  int ret;
+  FAR struct fbdev_obj_s *fbdev_obj = timer->user_data;
+
+  LV_LOG_TRACE("Check vsync...");
+
+  ret = ioctl(fbdev_obj->fd, FBIO_WAITFORVSYNC, NULL);
+  if (ret != OK)
+    {
+      LV_LOG_TRACE("No vsync signal detect");
+      return;
+    }
+
+  LV_LOG_TRACE("Refresh start");
+
+  _lv_disp_refr_timer(NULL);
+}
+
+#endif /* CONFIG_FB_SYNC */
+
+/****************************************************************************
+ * Name: fbdev_render_start
+ ****************************************************************************/
+
+static void fbdev_render_start(FAR lv_disp_drv_t *disp_drv)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+  FAR lv_disp_t *disp_refr;
+  lv_coord_t hor_res;
+  lv_coord_t ver_res;
+  int i;
+
+  /* No need sync buffer when inv_areas_len == 0 */
+
+  if (fbdev_obj->inv_areas_len == 0)
+    {
+      return;
+    }
+
+  disp_refr = _lv_refr_get_disp_refreshing();
+  hor_res = disp_drv->hor_res;
+  ver_res = disp_drv->ver_res;
+
+  for (i = 0; i < disp_refr->inv_p; i++)
+    {
+      if (disp_refr->inv_area_joined[i] == 0)
+        {
+          FAR const lv_area_t *area_p = &disp_refr->inv_areas[i];
+
+          /* If a full screen redraw is detected, skip dirty areas sync */
+
+          if (lv_area_get_width(area_p) == hor_res
+           && lv_area_get_height(area_p) == ver_res)
+            {
+              LV_LOG_TRACE("Full screen redraw, skip dirty areas sync");
+              fbdev_obj->inv_areas_len = 0;
+              return;
+            }
+        }
+    }
+
+  /* Sync the dirty area of ​​the previous frame */
+
+  fbdev_copy_areas(fbdev_obj->act_buffer, fbdev_obj->last_buffer,
+                   fbdev_obj->inv_areas, fbdev_obj->inv_areas_len,
+                   fbdev_obj->vinfo.xres);
+
+  fbdev_obj->inv_areas_len = 0;
+}
+
+/****************************************************************************
+ * Name: fbdev_flush_direct
+ ****************************************************************************/
+
+static void fbdev_flush_direct(FAR lv_disp_drv_t *disp_drv,
+                               FAR const lv_area_t *area_p,
+                               FAR lv_color_t *color_p)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+
+  /* Commit the buffer after the last flush */
+
+  if (!lv_disp_flush_is_last(disp_drv))
+    {
+      lv_disp_flush_ready(disp_drv);
+      return;
+    }
+
+  fbdev_switch_buffer(fbdev_obj);
+
+  FBDEV_UPDATE_AREA(fbdev_obj, area_p);
+
+  /* Tell the flushing is ready */
+
+  lv_disp_flush_ready(disp_drv);
+}
+
+/****************************************************************************
+ * Name: fbdev_update_part
+ ****************************************************************************/
+
+static void fbdev_update_part(FAR struct fbdev_obj_s *fbdev_obj,
+                              FAR lv_disp_drv_t *disp_drv,
+                              FAR const lv_area_t *area_p)
+{
+  FAR lv_area_t *final_area = &fbdev_obj->final_area;
+
+  if (final_area->x1 < 0)
+    {
+      *final_area = *area_p;
+    }
+  else
+    {
+      _lv_area_join(final_area, final_area, area_p);
+    }
+
+  if (!lv_disp_flush_is_last(disp_drv))
+    {
+      lv_disp_flush_ready(disp_drv);
+      return;
+    }
+
+  if (fbdev_obj->double_buffer)
+    {
+      fbdev_switch_buffer(fbdev_obj);
+    }
+
+  FBDEV_UPDATE_AREA(fbdev_obj, final_area);
+
+  /* Mark it is invalid */
+
+  final_area->x1 = -1;
+
+  /* Tell the flushing is ready */
+
+  lv_disp_flush_ready(disp_drv);
+}
+
+/****************************************************************************
+ * Name: fbdev_flush_normal
+ ****************************************************************************/
+
+static void fbdev_flush_normal(FAR lv_disp_drv_t *disp_drv,
+                               FAR const lv_area_t *area_p,
+                               FAR lv_color_t *color_p)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+
+  int x1 = area_p->x1;
+  int y1 = area_p->y1;
+  int y2 = area_p->y2;
+  int y;
+  int w = lv_area_get_width(area_p);
+
+  FAR lv_color_t *fbp = fbdev_obj->act_buffer;
+  fb_coord_t fb_xres = fbdev_obj->vinfo.xres;
+  int hor_size = w * sizeof(lv_color_t);
+  FAR lv_color_t *cur_pos = fbp + y1 * fb_xres + x1;
+
+  LV_LOG_TRACE("start copy");
+
+  for (y = y1; y <= y2; y++)
+    {
+      lv_memcpy(cur_pos, color_p, hor_size);
+      cur_pos += fb_xres;
+      color_p += w;
+    }
+
+  LV_LOG_TRACE("end copy");
+
+  fbdev_update_part(fbdev_obj, disp_drv, area_p);
+}
+
+/****************************************************************************
+ * Name: fbdev_flush_convert
+ ****************************************************************************/
+
+static void fbdev_flush_convert(FAR lv_disp_drv_t *disp_drv,
+                                FAR const lv_area_t *area_p,
+                                FAR lv_color_t *color_p)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+  int x1 = area_p->x1;
+  int y1 = area_p->y1;
+  int x2 = area_p->x2;
+  int y2 = area_p->y2;
+
+  const uint8_t bpp = fbdev_obj->pinfo.bpp;
+  const fb_coord_t xres = fbdev_obj->vinfo.xres;
+  int x;
+  int y;
+
+  LV_LOG_TRACE("start copy");
+
+  switch (bpp)
+    {
+      case 32:
+      case 24:
+        {
+          FAR uint32_t *fbp = fbdev_obj->act_buffer;
+          for (y = y1; y <= y2; y++)
+            {
+              FAR uint32_t *cur_pos = fbp + (y * xres) + x1;
+              for (x = x1; x <= x2; x++)
+                {
+                  *cur_pos = lv_color_to32(*color_p);
+                  cur_pos++;
+                  color_p++;
+                }
+            }
+        }
+        break;
+      case 16:
+        {
+          FAR uint16_t *fbp = fbdev_obj->act_buffer;
+          for (y = y1; y <= y2; y++)
+            {
+              FAR uint16_t *cur_pos = fbp + (y * xres) + x1;
+              for (x = x1; x <= x2; x++)
+                {
+                  *cur_pos = lv_color_to16(*color_p);
+                  cur_pos++;
+                  color_p++;
+                }
+            }
+        }
+        break;
+      case 8:
+        {
+          FAR uint8_t *fbp = fbdev_obj->act_buffer;
+          for (y = y1; y <= y2; y++)
+            {
+              FAR uint8_t *cur_pos = fbp + (y * xres) + x1;
+              for (x = x1; x <= x2; x++)
+                {
+                  *cur_pos = lv_color_to8(*color_p);
+                  cur_pos++;
+                  color_p++;
+                }
+            }
+        }
+        break;
+      default:
+        break;
+    }
+
+  LV_LOG_TRACE("end copy");
+
+  fbdev_update_part(fbdev_obj, disp_drv, area_p);
+}
+
+/****************************************************************************
+ * Name: fbdev_get_pinfo
+ ****************************************************************************/
+
+static int fbdev_get_pinfo(int fd, FAR struct fb_planeinfo_s *pinfo)
+{
+  int ret = ioctl(fd, FBIOGET_PLANEINFO,
+                  (unsigned long)((uintptr_t)pinfo));
+  if (ret < 0)
+    {
+      LV_LOG_ERROR("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d", errno);
+      return ret;
+    }
+
+  LV_LOG_INFO("PlaneInfo (plane %d):", pinfo->display);
+  LV_LOG_INFO("    fbmem: %p", pinfo->fbmem);
+  LV_LOG_INFO("    fblen: %lu", (unsigned long)pinfo->fblen);
+  LV_LOG_INFO("   stride: %u", pinfo->stride);
+  LV_LOG_INFO("  display: %u", pinfo->display);
+  LV_LOG_INFO("      bpp: %u", pinfo->bpp);
+
+  /* Only these pixel depths are supported.  viinfo.fmt is ignored, only
+   * certain color formats are supported.
+   */
+
+  if (pinfo->bpp != 32 && pinfo->bpp != 16 &&
+      pinfo->bpp != 8  && pinfo->bpp != 1)
+    {
+      LV_LOG_ERROR("bpp = %u not supported", pinfo->bpp);
+      return -1;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: fbdev_try_init_fbmem2
+ ****************************************************************************/
+
+static int fbdev_try_init_fbmem2(FAR struct fbdev_obj_s *state)
+{
+  uintptr_t buf_offset;
+  struct fb_planeinfo_s pinfo;
+
+  memset(&pinfo, 0, sizeof(pinfo));
+
+  /* Get display[1] planeinfo */
+
+  pinfo.display = state->pinfo.display + 1;
+
+  if (fbdev_get_pinfo(state->fd, &pinfo) < 0)
+    {
+      return -1;
+    }
+
+  /* check displey and match bpp */

Review Comment:
   typo: `display`



##########
graphics/lvgl/port/lv_port_fbdev.c:
##########
@@ -0,0 +1,755 @@
+/****************************************************************************
+ * apps/graphics/lvgl/port/lv_port_fbdev.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/video/fb.h>
+#include <nuttx/video/rgbcolors.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "lv_port_fbdev.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_FB_UPDATE)
+#  define FBDEV_UPDATE_AREA(obj, area) fbdev_update_area(obj, area)
+#else
+#  define FBDEV_UPDATE_AREA(obj, area)
+#endif
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+struct fbdev_obj_s
+{
+  lv_disp_draw_buf_t disp_draw_buf;
+  lv_disp_drv_t disp_drv;
+  FAR lv_disp_t *disp;
+  FAR void *last_buffer;
+  FAR void *act_buffer;
+  lv_area_t inv_areas[LV_INV_BUF_SIZE];
+  uint16_t inv_areas_len;
+  lv_area_t final_area;
+
+  int fd;
+  FAR void *fbmem;
+  uint32_t fbmem2_yoffset;
+  struct fb_videoinfo_s vinfo;
+  struct fb_planeinfo_s pinfo;
+
+  bool color_match;
+  bool double_buffer;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: buf_rotate_copy
+ ****************************************************************************/
+
+#if defined(CONFIG_FB_UPDATE)
+static void fbdev_update_area(FAR struct fbdev_obj_s *fbdev_obj,
+                              FAR const lv_area_t *area_p)
+{
+  struct fb_area_s fb_area;
+
+  fb_area.x = area_p->x1;
+  fb_area.y = area_p->y1;
+  fb_area.w = area_p->x2 - area_p->x1 + 1;
+  fb_area.h = area_p->y2 - area_p->y1 + 1;
+
+  LV_LOG_TRACE("area: (%d, %d) %d x %d",
+               fb_area.x, fb_area.y, fb_area.w, fb_area.h);
+
+  ioctl(fbdev_obj->fd, FBIO_UPDATE,
+        (unsigned long)((uintptr_t)&fb_area));
+
+  LV_LOG_TRACE("finished");
+}
+#endif
+
+/****************************************************************************
+ * Name: fbdev_copy_areas
+ ****************************************************************************/
+
+static void fbdev_copy_areas(FAR lv_color_t *fb_dest,
+                             FAR const lv_color_t *fb_src,
+                             FAR const lv_area_t *areas,
+                             uint16_t len,
+                             int fb_width)
+{
+  int i;
+  LV_LOG_TRACE("%p -> %p, len = %d", fb_src, fb_dest, len);
+
+  for (i = 0; i < len; i++)
+    {
+      int y;
+      FAR const lv_area_t *area = &(areas[i]);
+      int width = lv_area_get_width(area);
+      int height = lv_area_get_height(area);
+      FAR lv_color_t *dest_pos =
+                      fb_dest + area->y1 * fb_width + area->x1;
+      FAR const lv_color_t *src_pos =
+                            fb_src + area->y1 * fb_width + area->x1;
+      size_t hor_size = width * sizeof(lv_color_t);
+
+      LV_LOG_TRACE("area[%d]: (%d, %d) %d x %d",
+                   i, area->x1, area->y1, width, height);
+
+      for (y = 0; y < height; y++)
+        {
+          lv_memcpy(dest_pos, src_pos, hor_size);
+          dest_pos += fb_width;
+          src_pos += fb_width;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: fbdev_switch_buffer
+ ****************************************************************************/
+
+static void fbdev_switch_buffer(FAR struct fbdev_obj_s *fbdev_obj)
+{
+  FAR lv_disp_t *disp_refr = fbdev_obj->disp;
+  uint16_t inv_index;
+
+  /* check inv_areas_len, it must == 0 */
+
+  if (fbdev_obj->inv_areas_len != 0)
+    {
+      LV_LOG_ERROR("Repeated flush action detected! "
+                    "inv_areas_len(%d) != 0",
+                    fbdev_obj->inv_areas_len);
+      fbdev_obj->inv_areas_len = 0;
+    }
+
+  /* Save dirty area table for next synchronizationn */
+
+  for (inv_index = 0; inv_index < disp_refr->inv_p; inv_index++)
+    {
+      if (disp_refr->inv_area_joined[inv_index] == 0)
+        {
+          fbdev_obj->inv_areas[fbdev_obj->inv_areas_len] =
+              disp_refr->inv_areas[inv_index];
+          fbdev_obj->inv_areas_len++;
+        }
+    }
+
+  /* Save the buffer address for the next synchronization */
+
+  fbdev_obj->last_buffer = fbdev_obj->act_buffer;
+
+  LV_LOG_TRACE("Commit buffer = %p, yoffset = %" PRIu32,
+               fbdev_obj->act_buffer,
+               fbdev_obj->pinfo.yoffset);
+
+  if (fbdev_obj->act_buffer == fbdev_obj->fbmem)
+    {
+      fbdev_obj->pinfo.yoffset = 0;
+      fbdev_obj->act_buffer = fbdev_obj->fbmem
+        + fbdev_obj->fbmem2_yoffset * fbdev_obj->pinfo.stride;
+    }
+  else
+    {
+      fbdev_obj->pinfo.yoffset = fbdev_obj->fbmem2_yoffset;
+      fbdev_obj->act_buffer = fbdev_obj->fbmem;
+    }
+
+  /* Commit buffer to fb driver */
+
+  ioctl(fbdev_obj->fd, FBIOPAN_DISPLAY,
+        (unsigned long)((uintptr_t)&(fbdev_obj->pinfo)));
+
+  LV_LOG_TRACE("finished");
+}
+
+#if defined(CONFIG_FB_SYNC)
+
+/****************************************************************************
+ * Name: fbdev_disp_vsync_refr
+ ****************************************************************************/
+
+static void fbdev_disp_vsync_refr(FAR lv_timer_t *timer)
+{
+  int ret;
+  FAR struct fbdev_obj_s *fbdev_obj = timer->user_data;
+
+  LV_LOG_TRACE("Check vsync...");
+
+  ret = ioctl(fbdev_obj->fd, FBIO_WAITFORVSYNC, NULL);
+  if (ret != OK)
+    {
+      LV_LOG_TRACE("No vsync signal detect");
+      return;
+    }
+
+  LV_LOG_TRACE("Refresh start");
+
+  _lv_disp_refr_timer(NULL);
+}
+
+#endif /* CONFIG_FB_SYNC */
+
+/****************************************************************************
+ * Name: fbdev_render_start
+ ****************************************************************************/
+
+static void fbdev_render_start(FAR lv_disp_drv_t *disp_drv)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+  FAR lv_disp_t *disp_refr;
+  lv_coord_t hor_res;
+  lv_coord_t ver_res;
+  int i;
+
+  /* No need sync buffer when inv_areas_len == 0 */
+
+  if (fbdev_obj->inv_areas_len == 0)
+    {
+      return;
+    }
+
+  disp_refr = _lv_refr_get_disp_refreshing();
+  hor_res = disp_drv->hor_res;
+  ver_res = disp_drv->ver_res;
+
+  for (i = 0; i < disp_refr->inv_p; i++)
+    {
+      if (disp_refr->inv_area_joined[i] == 0)
+        {
+          FAR const lv_area_t *area_p = &disp_refr->inv_areas[i];
+
+          /* If a full screen redraw is detected, skip dirty areas sync */
+
+          if (lv_area_get_width(area_p) == hor_res
+           && lv_area_get_height(area_p) == ver_res)
+            {
+              LV_LOG_TRACE("Full screen redraw, skip dirty areas sync");
+              fbdev_obj->inv_areas_len = 0;
+              return;
+            }
+        }
+    }
+
+  /* Sync the dirty area of ​​the previous frame */
+
+  fbdev_copy_areas(fbdev_obj->act_buffer, fbdev_obj->last_buffer,
+                   fbdev_obj->inv_areas, fbdev_obj->inv_areas_len,
+                   fbdev_obj->vinfo.xres);
+
+  fbdev_obj->inv_areas_len = 0;
+}
+
+/****************************************************************************
+ * Name: fbdev_flush_direct
+ ****************************************************************************/
+
+static void fbdev_flush_direct(FAR lv_disp_drv_t *disp_drv,
+                               FAR const lv_area_t *area_p,
+                               FAR lv_color_t *color_p)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+
+  /* Commit the buffer after the last flush */
+
+  if (!lv_disp_flush_is_last(disp_drv))
+    {
+      lv_disp_flush_ready(disp_drv);
+      return;
+    }
+
+  fbdev_switch_buffer(fbdev_obj);
+
+  FBDEV_UPDATE_AREA(fbdev_obj, area_p);
+
+  /* Tell the flushing is ready */
+
+  lv_disp_flush_ready(disp_drv);
+}
+
+/****************************************************************************
+ * Name: fbdev_update_part
+ ****************************************************************************/
+
+static void fbdev_update_part(FAR struct fbdev_obj_s *fbdev_obj,
+                              FAR lv_disp_drv_t *disp_drv,
+                              FAR const lv_area_t *area_p)
+{
+  FAR lv_area_t *final_area = &fbdev_obj->final_area;
+
+  if (final_area->x1 < 0)
+    {
+      *final_area = *area_p;
+    }
+  else
+    {
+      _lv_area_join(final_area, final_area, area_p);
+    }
+
+  if (!lv_disp_flush_is_last(disp_drv))
+    {
+      lv_disp_flush_ready(disp_drv);
+      return;
+    }
+
+  if (fbdev_obj->double_buffer)
+    {
+      fbdev_switch_buffer(fbdev_obj);
+    }
+
+  FBDEV_UPDATE_AREA(fbdev_obj, final_area);
+
+  /* Mark it is invalid */
+
+  final_area->x1 = -1;
+
+  /* Tell the flushing is ready */
+
+  lv_disp_flush_ready(disp_drv);
+}
+
+/****************************************************************************
+ * Name: fbdev_flush_normal
+ ****************************************************************************/
+
+static void fbdev_flush_normal(FAR lv_disp_drv_t *disp_drv,
+                               FAR const lv_area_t *area_p,
+                               FAR lv_color_t *color_p)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+
+  int x1 = area_p->x1;
+  int y1 = area_p->y1;
+  int y2 = area_p->y2;
+  int y;
+  int w = lv_area_get_width(area_p);
+
+  FAR lv_color_t *fbp = fbdev_obj->act_buffer;
+  fb_coord_t fb_xres = fbdev_obj->vinfo.xres;
+  int hor_size = w * sizeof(lv_color_t);
+  FAR lv_color_t *cur_pos = fbp + y1 * fb_xres + x1;
+
+  LV_LOG_TRACE("start copy");
+
+  for (y = y1; y <= y2; y++)
+    {
+      lv_memcpy(cur_pos, color_p, hor_size);
+      cur_pos += fb_xres;
+      color_p += w;
+    }
+
+  LV_LOG_TRACE("end copy");
+
+  fbdev_update_part(fbdev_obj, disp_drv, area_p);
+}
+
+/****************************************************************************
+ * Name: fbdev_flush_convert
+ ****************************************************************************/
+
+static void fbdev_flush_convert(FAR lv_disp_drv_t *disp_drv,
+                                FAR const lv_area_t *area_p,
+                                FAR lv_color_t *color_p)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+  int x1 = area_p->x1;
+  int y1 = area_p->y1;
+  int x2 = area_p->x2;
+  int y2 = area_p->y2;
+
+  const uint8_t bpp = fbdev_obj->pinfo.bpp;
+  const fb_coord_t xres = fbdev_obj->vinfo.xres;
+  int x;
+  int y;
+
+  LV_LOG_TRACE("start copy");
+
+  switch (bpp)
+    {
+      case 32:
+      case 24:
+        {
+          FAR uint32_t *fbp = fbdev_obj->act_buffer;
+          for (y = y1; y <= y2; y++)
+            {
+              FAR uint32_t *cur_pos = fbp + (y * xres) + x1;
+              for (x = x1; x <= x2; x++)
+                {
+                  *cur_pos = lv_color_to32(*color_p);
+                  cur_pos++;
+                  color_p++;
+                }
+            }
+        }
+        break;
+      case 16:
+        {
+          FAR uint16_t *fbp = fbdev_obj->act_buffer;
+          for (y = y1; y <= y2; y++)
+            {
+              FAR uint16_t *cur_pos = fbp + (y * xres) + x1;
+              for (x = x1; x <= x2; x++)
+                {
+                  *cur_pos = lv_color_to16(*color_p);
+                  cur_pos++;
+                  color_p++;
+                }
+            }
+        }
+        break;
+      case 8:
+        {
+          FAR uint8_t *fbp = fbdev_obj->act_buffer;
+          for (y = y1; y <= y2; y++)
+            {
+              FAR uint8_t *cur_pos = fbp + (y * xres) + x1;
+              for (x = x1; x <= x2; x++)
+                {
+                  *cur_pos = lv_color_to8(*color_p);
+                  cur_pos++;
+                  color_p++;
+                }
+            }
+        }
+        break;
+      default:
+        break;
+    }
+
+  LV_LOG_TRACE("end copy");
+
+  fbdev_update_part(fbdev_obj, disp_drv, area_p);
+}
+
+/****************************************************************************
+ * Name: fbdev_get_pinfo
+ ****************************************************************************/
+
+static int fbdev_get_pinfo(int fd, FAR struct fb_planeinfo_s *pinfo)
+{
+  int ret = ioctl(fd, FBIOGET_PLANEINFO,
+                  (unsigned long)((uintptr_t)pinfo));
+  if (ret < 0)
+    {
+      LV_LOG_ERROR("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d", errno);
+      return ret;
+    }
+
+  LV_LOG_INFO("PlaneInfo (plane %d):", pinfo->display);
+  LV_LOG_INFO("    fbmem: %p", pinfo->fbmem);
+  LV_LOG_INFO("    fblen: %lu", (unsigned long)pinfo->fblen);
+  LV_LOG_INFO("   stride: %u", pinfo->stride);
+  LV_LOG_INFO("  display: %u", pinfo->display);
+  LV_LOG_INFO("      bpp: %u", pinfo->bpp);
+
+  /* Only these pixel depths are supported.  viinfo.fmt is ignored, only
+   * certain color formats are supported.
+   */
+
+  if (pinfo->bpp != 32 && pinfo->bpp != 16 &&
+      pinfo->bpp != 8  && pinfo->bpp != 1)
+    {
+      LV_LOG_ERROR("bpp = %u not supported", pinfo->bpp);
+      return -1;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: fbdev_try_init_fbmem2
+ ****************************************************************************/
+
+static int fbdev_try_init_fbmem2(FAR struct fbdev_obj_s *state)
+{
+  uintptr_t buf_offset;
+  struct fb_planeinfo_s pinfo;
+
+  memset(&pinfo, 0, sizeof(pinfo));
+
+  /* Get display[1] planeinfo */
+
+  pinfo.display = state->pinfo.display + 1;
+
+  if (fbdev_get_pinfo(state->fd, &pinfo) < 0)
+    {
+      return -1;
+    }
+
+  /* check displey and match bpp */
+
+  if (!(pinfo.display != state->pinfo.display
+     && pinfo.bpp == state->pinfo.bpp))
+    {
+      LV_LOG_WARN("fbmem2 is incorrect");

Review Comment:
   Actually, the `ttgo_t_display_esp32:lvgl_fb` shows exactly this warning. I couldn't understand this implementation of the double buffer functionality. Do you check if there is a second "virtual" framebuffer device to use as a second buffer for the actual display? I don't recall any application that registers two framebuffers on such scheme... Could you please double-check this implementation? 



##########
graphics/lvgl/port/lv_port_fbdev.c:
##########
@@ -0,0 +1,755 @@
+/****************************************************************************
+ * apps/graphics/lvgl/port/lv_port_fbdev.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/video/fb.h>
+#include <nuttx/video/rgbcolors.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "lv_port_fbdev.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_FB_UPDATE)
+#  define FBDEV_UPDATE_AREA(obj, area) fbdev_update_area(obj, area)
+#else
+#  define FBDEV_UPDATE_AREA(obj, area)
+#endif
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+struct fbdev_obj_s
+{
+  lv_disp_draw_buf_t disp_draw_buf;
+  lv_disp_drv_t disp_drv;
+  FAR lv_disp_t *disp;
+  FAR void *last_buffer;
+  FAR void *act_buffer;
+  lv_area_t inv_areas[LV_INV_BUF_SIZE];
+  uint16_t inv_areas_len;
+  lv_area_t final_area;
+
+  int fd;
+  FAR void *fbmem;
+  uint32_t fbmem2_yoffset;
+  struct fb_videoinfo_s vinfo;
+  struct fb_planeinfo_s pinfo;
+
+  bool color_match;
+  bool double_buffer;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: buf_rotate_copy
+ ****************************************************************************/
+
+#if defined(CONFIG_FB_UPDATE)
+static void fbdev_update_area(FAR struct fbdev_obj_s *fbdev_obj,
+                              FAR const lv_area_t *area_p)
+{
+  struct fb_area_s fb_area;
+
+  fb_area.x = area_p->x1;
+  fb_area.y = area_p->y1;
+  fb_area.w = area_p->x2 - area_p->x1 + 1;
+  fb_area.h = area_p->y2 - area_p->y1 + 1;
+
+  LV_LOG_TRACE("area: (%d, %d) %d x %d",
+               fb_area.x, fb_area.y, fb_area.w, fb_area.h);
+
+  ioctl(fbdev_obj->fd, FBIO_UPDATE,
+        (unsigned long)((uintptr_t)&fb_area));
+
+  LV_LOG_TRACE("finished");
+}
+#endif
+
+/****************************************************************************
+ * Name: fbdev_copy_areas
+ ****************************************************************************/
+
+static void fbdev_copy_areas(FAR lv_color_t *fb_dest,
+                             FAR const lv_color_t *fb_src,
+                             FAR const lv_area_t *areas,
+                             uint16_t len,
+                             int fb_width)
+{
+  int i;
+  LV_LOG_TRACE("%p -> %p, len = %d", fb_src, fb_dest, len);
+
+  for (i = 0; i < len; i++)
+    {
+      int y;
+      FAR const lv_area_t *area = &(areas[i]);
+      int width = lv_area_get_width(area);
+      int height = lv_area_get_height(area);
+      FAR lv_color_t *dest_pos =
+                      fb_dest + area->y1 * fb_width + area->x1;
+      FAR const lv_color_t *src_pos =
+                            fb_src + area->y1 * fb_width + area->x1;
+      size_t hor_size = width * sizeof(lv_color_t);
+
+      LV_LOG_TRACE("area[%d]: (%d, %d) %d x %d",
+                   i, area->x1, area->y1, width, height);
+
+      for (y = 0; y < height; y++)
+        {
+          lv_memcpy(dest_pos, src_pos, hor_size);
+          dest_pos += fb_width;
+          src_pos += fb_width;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: fbdev_switch_buffer
+ ****************************************************************************/
+
+static void fbdev_switch_buffer(FAR struct fbdev_obj_s *fbdev_obj)
+{
+  FAR lv_disp_t *disp_refr = fbdev_obj->disp;
+  uint16_t inv_index;
+
+  /* check inv_areas_len, it must == 0 */
+
+  if (fbdev_obj->inv_areas_len != 0)
+    {
+      LV_LOG_ERROR("Repeated flush action detected! "
+                    "inv_areas_len(%d) != 0",
+                    fbdev_obj->inv_areas_len);
+      fbdev_obj->inv_areas_len = 0;
+    }
+
+  /* Save dirty area table for next synchronizationn */
+
+  for (inv_index = 0; inv_index < disp_refr->inv_p; inv_index++)
+    {
+      if (disp_refr->inv_area_joined[inv_index] == 0)
+        {
+          fbdev_obj->inv_areas[fbdev_obj->inv_areas_len] =
+              disp_refr->inv_areas[inv_index];
+          fbdev_obj->inv_areas_len++;
+        }
+    }
+
+  /* Save the buffer address for the next synchronization */
+
+  fbdev_obj->last_buffer = fbdev_obj->act_buffer;
+
+  LV_LOG_TRACE("Commit buffer = %p, yoffset = %" PRIu32,
+               fbdev_obj->act_buffer,
+               fbdev_obj->pinfo.yoffset);
+
+  if (fbdev_obj->act_buffer == fbdev_obj->fbmem)
+    {
+      fbdev_obj->pinfo.yoffset = 0;
+      fbdev_obj->act_buffer = fbdev_obj->fbmem
+        + fbdev_obj->fbmem2_yoffset * fbdev_obj->pinfo.stride;
+    }
+  else
+    {
+      fbdev_obj->pinfo.yoffset = fbdev_obj->fbmem2_yoffset;
+      fbdev_obj->act_buffer = fbdev_obj->fbmem;
+    }
+
+  /* Commit buffer to fb driver */
+
+  ioctl(fbdev_obj->fd, FBIOPAN_DISPLAY,
+        (unsigned long)((uintptr_t)&(fbdev_obj->pinfo)));
+
+  LV_LOG_TRACE("finished");
+}
+
+#if defined(CONFIG_FB_SYNC)
+
+/****************************************************************************
+ * Name: fbdev_disp_vsync_refr
+ ****************************************************************************/
+
+static void fbdev_disp_vsync_refr(FAR lv_timer_t *timer)
+{
+  int ret;
+  FAR struct fbdev_obj_s *fbdev_obj = timer->user_data;
+
+  LV_LOG_TRACE("Check vsync...");
+
+  ret = ioctl(fbdev_obj->fd, FBIO_WAITFORVSYNC, NULL);
+  if (ret != OK)
+    {
+      LV_LOG_TRACE("No vsync signal detect");
+      return;
+    }
+
+  LV_LOG_TRACE("Refresh start");
+
+  _lv_disp_refr_timer(NULL);
+}
+
+#endif /* CONFIG_FB_SYNC */
+
+/****************************************************************************
+ * Name: fbdev_render_start
+ ****************************************************************************/
+
+static void fbdev_render_start(FAR lv_disp_drv_t *disp_drv)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+  FAR lv_disp_t *disp_refr;
+  lv_coord_t hor_res;
+  lv_coord_t ver_res;
+  int i;
+
+  /* No need sync buffer when inv_areas_len == 0 */
+
+  if (fbdev_obj->inv_areas_len == 0)
+    {
+      return;
+    }
+
+  disp_refr = _lv_refr_get_disp_refreshing();
+  hor_res = disp_drv->hor_res;
+  ver_res = disp_drv->ver_res;
+
+  for (i = 0; i < disp_refr->inv_p; i++)
+    {
+      if (disp_refr->inv_area_joined[i] == 0)
+        {
+          FAR const lv_area_t *area_p = &disp_refr->inv_areas[i];
+
+          /* If a full screen redraw is detected, skip dirty areas sync */
+
+          if (lv_area_get_width(area_p) == hor_res
+           && lv_area_get_height(area_p) == ver_res)
+            {
+              LV_LOG_TRACE("Full screen redraw, skip dirty areas sync");
+              fbdev_obj->inv_areas_len = 0;
+              return;
+            }
+        }
+    }
+
+  /* Sync the dirty area of ​​the previous frame */
+
+  fbdev_copy_areas(fbdev_obj->act_buffer, fbdev_obj->last_buffer,
+                   fbdev_obj->inv_areas, fbdev_obj->inv_areas_len,
+                   fbdev_obj->vinfo.xres);
+
+  fbdev_obj->inv_areas_len = 0;
+}
+
+/****************************************************************************
+ * Name: fbdev_flush_direct
+ ****************************************************************************/
+
+static void fbdev_flush_direct(FAR lv_disp_drv_t *disp_drv,
+                               FAR const lv_area_t *area_p,
+                               FAR lv_color_t *color_p)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+
+  /* Commit the buffer after the last flush */
+
+  if (!lv_disp_flush_is_last(disp_drv))
+    {
+      lv_disp_flush_ready(disp_drv);
+      return;
+    }
+
+  fbdev_switch_buffer(fbdev_obj);
+
+  FBDEV_UPDATE_AREA(fbdev_obj, area_p);
+
+  /* Tell the flushing is ready */
+
+  lv_disp_flush_ready(disp_drv);
+}
+
+/****************************************************************************
+ * Name: fbdev_update_part
+ ****************************************************************************/
+
+static void fbdev_update_part(FAR struct fbdev_obj_s *fbdev_obj,
+                              FAR lv_disp_drv_t *disp_drv,
+                              FAR const lv_area_t *area_p)
+{
+  FAR lv_area_t *final_area = &fbdev_obj->final_area;
+
+  if (final_area->x1 < 0)
+    {
+      *final_area = *area_p;
+    }
+  else
+    {
+      _lv_area_join(final_area, final_area, area_p);
+    }
+
+  if (!lv_disp_flush_is_last(disp_drv))
+    {
+      lv_disp_flush_ready(disp_drv);
+      return;
+    }
+
+  if (fbdev_obj->double_buffer)
+    {
+      fbdev_switch_buffer(fbdev_obj);
+    }
+
+  FBDEV_UPDATE_AREA(fbdev_obj, final_area);
+
+  /* Mark it is invalid */
+
+  final_area->x1 = -1;
+
+  /* Tell the flushing is ready */
+
+  lv_disp_flush_ready(disp_drv);
+}
+
+/****************************************************************************
+ * Name: fbdev_flush_normal
+ ****************************************************************************/
+
+static void fbdev_flush_normal(FAR lv_disp_drv_t *disp_drv,
+                               FAR const lv_area_t *area_p,
+                               FAR lv_color_t *color_p)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+
+  int x1 = area_p->x1;
+  int y1 = area_p->y1;
+  int y2 = area_p->y2;
+  int y;
+  int w = lv_area_get_width(area_p);
+
+  FAR lv_color_t *fbp = fbdev_obj->act_buffer;
+  fb_coord_t fb_xres = fbdev_obj->vinfo.xres;
+  int hor_size = w * sizeof(lv_color_t);
+  FAR lv_color_t *cur_pos = fbp + y1 * fb_xres + x1;
+
+  LV_LOG_TRACE("start copy");
+
+  for (y = y1; y <= y2; y++)
+    {
+      lv_memcpy(cur_pos, color_p, hor_size);
+      cur_pos += fb_xres;
+      color_p += w;
+    }
+
+  LV_LOG_TRACE("end copy");
+
+  fbdev_update_part(fbdev_obj, disp_drv, area_p);
+}
+
+/****************************************************************************
+ * Name: fbdev_flush_convert
+ ****************************************************************************/
+
+static void fbdev_flush_convert(FAR lv_disp_drv_t *disp_drv,
+                                FAR const lv_area_t *area_p,
+                                FAR lv_color_t *color_p)
+{
+  FAR struct fbdev_obj_s *fbdev_obj = disp_drv->user_data;
+  int x1 = area_p->x1;
+  int y1 = area_p->y1;
+  int x2 = area_p->x2;
+  int y2 = area_p->y2;
+
+  const uint8_t bpp = fbdev_obj->pinfo.bpp;
+  const fb_coord_t xres = fbdev_obj->vinfo.xres;
+  int x;
+  int y;
+
+  LV_LOG_TRACE("start copy");
+
+  switch (bpp)
+    {
+      case 32:
+      case 24:
+        {
+          FAR uint32_t *fbp = fbdev_obj->act_buffer;
+          for (y = y1; y <= y2; y++)
+            {
+              FAR uint32_t *cur_pos = fbp + (y * xres) + x1;
+              for (x = x1; x <= x2; x++)
+                {
+                  *cur_pos = lv_color_to32(*color_p);
+                  cur_pos++;
+                  color_p++;
+                }
+            }
+        }
+        break;
+      case 16:
+        {
+          FAR uint16_t *fbp = fbdev_obj->act_buffer;
+          for (y = y1; y <= y2; y++)
+            {
+              FAR uint16_t *cur_pos = fbp + (y * xres) + x1;
+              for (x = x1; x <= x2; x++)
+                {
+                  *cur_pos = lv_color_to16(*color_p);
+                  cur_pos++;
+                  color_p++;
+                }
+            }
+        }
+        break;
+      case 8:
+        {
+          FAR uint8_t *fbp = fbdev_obj->act_buffer;
+          for (y = y1; y <= y2; y++)
+            {
+              FAR uint8_t *cur_pos = fbp + (y * xres) + x1;
+              for (x = x1; x <= x2; x++)
+                {
+                  *cur_pos = lv_color_to8(*color_p);
+                  cur_pos++;
+                  color_p++;
+                }
+            }
+        }
+        break;
+      default:
+        break;
+    }
+
+  LV_LOG_TRACE("end copy");
+
+  fbdev_update_part(fbdev_obj, disp_drv, area_p);
+}
+
+/****************************************************************************
+ * Name: fbdev_get_pinfo
+ ****************************************************************************/
+
+static int fbdev_get_pinfo(int fd, FAR struct fb_planeinfo_s *pinfo)
+{
+  int ret = ioctl(fd, FBIOGET_PLANEINFO,
+                  (unsigned long)((uintptr_t)pinfo));
+  if (ret < 0)
+    {
+      LV_LOG_ERROR("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d", errno);
+      return ret;
+    }
+
+  LV_LOG_INFO("PlaneInfo (plane %d):", pinfo->display);
+  LV_LOG_INFO("    fbmem: %p", pinfo->fbmem);
+  LV_LOG_INFO("    fblen: %lu", (unsigned long)pinfo->fblen);
+  LV_LOG_INFO("   stride: %u", pinfo->stride);
+  LV_LOG_INFO("  display: %u", pinfo->display);
+  LV_LOG_INFO("      bpp: %u", pinfo->bpp);
+
+  /* Only these pixel depths are supported.  viinfo.fmt is ignored, only
+   * certain color formats are supported.
+   */
+
+  if (pinfo->bpp != 32 && pinfo->bpp != 16 &&
+      pinfo->bpp != 8  && pinfo->bpp != 1)
+    {
+      LV_LOG_ERROR("bpp = %u not supported", pinfo->bpp);
+      return -1;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: fbdev_try_init_fbmem2
+ ****************************************************************************/
+
+static int fbdev_try_init_fbmem2(FAR struct fbdev_obj_s *state)
+{
+  uintptr_t buf_offset;
+  struct fb_planeinfo_s pinfo;
+
+  memset(&pinfo, 0, sizeof(pinfo));
+
+  /* Get display[1] planeinfo */
+
+  pinfo.display = state->pinfo.display + 1;
+
+  if (fbdev_get_pinfo(state->fd, &pinfo) < 0)
+    {
+      return -1;
+    }
+
+  /* check displey and match bpp */
+
+  if (!(pinfo.display != state->pinfo.display
+     && pinfo.bpp == state->pinfo.bpp))
+    {
+      LV_LOG_WARN("fbmem2 is incorrect");

Review Comment:
   I'm still getting this warning using the `ttgo_t_display_esp32:lvgl_fb`. I couldn't figure out the implementation, but I'd say to double-check the examples that use framebuffer.
   
   ```
   [LVGL] [Warn]   (18.030, +18030)         fbdev_try_init_fbmem2: fbmem2 is incorrect     (in lv_port_fbdev.c line #522)
   ```
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org