Make backup surface to get fast cursor image 28/271428/1
authorJunkyeong, Kim <jk0430.kim@samsung.com>
Mon, 21 Feb 2022 06:13:47 +0000 (15:13 +0900)
committerJunkyeong, Kim <jk0430.kim@samsung.com>
Mon, 21 Feb 2022 06:13:52 +0000 (15:13 +0900)
Backup surface is capture image excepted cursor.
If there is no buffer changed and existed pointer moving only,
can get fast image from backup buffer.
Backup buffer is made when last buffer changed frame_timer handler.

Change-Id: I443782adde6c349570effff39b2c8c4427eaf159

src/e_mod_rdp.c

index 036ab8c..da4f682 100644 (file)
@@ -74,8 +74,10 @@ struct _E_Rdp_Output
 {
    E_Output *primary_output;
    Ecore_Timer *frame_timer;
-   pixman_image_t *pix_surface;
-   tbm_surface_h tbm_surface;
+   pixman_image_t *showing_surface;
+   tbm_surface_h prepare_tbm_surface;
+   tbm_surface_h showing_tbm_surface;
+   tbm_surface_h backup_tbm_surface;
    uint32_t w;
    uint32_t h;
 
@@ -93,6 +95,12 @@ struct _E_Rdp_Output
    double refresh_time;
    int refresh_count;
 
+   Eina_Bool mouse_moved;
+   Eina_Bool buffer_changed;
+
+   int mouse_x;
+   int mouse_y;
+
    struct wl_list peers;
 };
 
@@ -401,7 +409,7 @@ e_rdp_peer_refresh_raw(pixman_region32_t *region, pixman_image_t *image, freerdp
 }
 
 static void
-e_rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer, tbm_surface_h tbm_surface, pixman_image_t *pix_surface)
+e_rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer, pixman_image_t *pix_surface)
 {
    E_Rdp_Peer_Context *context = (E_Rdp_Peer_Context *)peer->context;
    E_Rdp_Output *output = context->rdpBackend->output;
@@ -414,13 +422,14 @@ e_rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer, tbm_sur
    else
      e_rdp_peer_refresh_raw(region, pix_surface, peer);
 
-   if (output->pix_surface)
-     pixman_image_unref(output->pix_surface);
-   output->pix_surface = pix_surface;
+   if (output->showing_surface)
+     pixman_image_unref(output->showing_surface);
+   output->showing_surface = pix_surface;
 
-   if (output->tbm_surface)
-     tbm_surface_destroy(output->tbm_surface);
-   output->tbm_surface = tbm_surface;
+   if (output->showing_tbm_surface)
+     tbm_surface_destroy(output->showing_tbm_surface);
+   output->showing_tbm_surface = output->prepare_tbm_surface;
+   output->prepare_tbm_surface = NULL;
 }
 
 static void
@@ -678,6 +687,9 @@ _e_rdp_pixman_output_image_composite_cursor(E_Rdp_Output *output, E_Hwc_Window *
 
    pixman_image_unref(pix_shm_src);
 
+   output->mouse_x = hwc_window->current.info.dst_pos.x;
+   output->mouse_y = hwc_window->current.info.dst_pos.y;
+
    return EINA_TRUE;
 }
 
@@ -768,51 +780,225 @@ _e_rdp_cb_hwc_window_sort(const void *d1, const void *d2)
    return (zpos1 - zpos2);
 }
 
+static void
+_e_rdp_tbm_surface_copy(tbm_surface_h src_tbm_surface, tbm_surface_info_s *src_info, tbm_surface_h dst_tbm_surface, tbm_surface_info_s *dst_info)
+{
+   memcpy(dst_info->planes[0].ptr, src_info->planes[0].ptr, src_info->planes[0].size);
+}
+
+static void
+_e_rdp_backup_buffer_create(E_Rdp_Output *output, tbm_surface_h src_tbm_surface, tbm_surface_info_s *src_info)
+{
+   tbm_surface_h new_tsurface = NULL;
+   tbm_surface_info_s info;
+   int ret = TBM_SURFACE_ERROR_NONE;
+
+    new_tsurface = tbm_surface_create(src_info->width, src_info->height, src_info->format);
+    if (!new_tsurface)
+      {
+         ERR("tbm_surface_create failed");
+         return;
+      }
+
+   ret = tbm_surface_map(new_tsurface, TBM_SURF_OPTION_WRITE, &info);
+   if (ret != TBM_SURFACE_ERROR_NONE)
+     {
+        ERR("tbm_surface_map failed");
+        tbm_surface_destroy(new_tsurface);
+        return;
+     }
+
+   _e_rdp_tbm_surface_copy(src_tbm_surface, src_info, new_tsurface, &info);
+
+   tbm_surface_unmap(new_tsurface);
+
+   if (output->backup_tbm_surface)
+     tbm_surface_destroy(output->backup_tbm_surface);
+   output->backup_tbm_surface = new_tsurface;
+}
+
 static pixman_image_t *
-_e_rdp_pixman_output_image_get(E_Rdp_Output *output, tbm_surface_h tbm_surface)
+_e_rdp_pixman_output_image_get_all(E_Rdp_Output *output, Eina_List *visible_list, E_Hwc_Window *hwc_window_cursor, int e_output_w, int e_output_h)
 {
-   E_Output *e_output = NULL;
+   tbm_surface_h tbm_surface = NULL;
+   tbm_surface_info_s info;
+   pixman_image_t *pix_surface = NULL;
+   pixman_format_code_t pix_format = 0;
    E_Hwc *hwc = NULL;
    E_Hwc_Window *hwc_window = NULL;
+   Eina_Bool target_window = EINA_TRUE;
    Eina_List *l;
-   Eina_List *visible_list = NULL;
-   Eina_Bool target_window = EINA_FALSE;
    int err;
-   tbm_surface_info_s info;
-   pixman_image_t *pix_surface = NULL;
-   pixman_format_code_t pix_format = 0;
-   int e_output_w, e_output_h;
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
-   EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surface, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(output->primary_output, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(output->primary_output->hwc, NULL);
 
-   e_output = output->primary_output;
-   EINA_SAFETY_ON_NULL_RETURN_VAL(e_output, NULL);
+   hwc = output->primary_output->hwc;
 
-   hwc = e_output->hwc;
-   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE);
+   tbm_surface = _e_rdp_tbm_image_create(output, output->w, output->h, 0x00000000);
+   if (tbm_surface == NULL)
+     {
+        ERR("create tbm surface failed");
+        output->prepare_tbm_surface = NULL;
+        return NULL;
+     }
 
-   e_output_w = e_output->config.mode.w;
-   e_output_h = e_output->config.mode.h;
+   err = tbm_surface_map(tbm_surface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info);
+   if (err)
+     {
+        ERR("tbm_surface_map failed");
+        tbm_surface_destroy(tbm_surface);
+        output->prepare_tbm_surface = NULL;
+        return NULL;
+     }
+
+   pix_format = _e_rdp_pixman_format_get(info.format);
+   if (pix_format == 0)
+     {
+        ERR("not supported format");
+        goto fail;
+     }
+
+   pix_surface = pixman_image_create_bits(pix_format, info.width, info.height, (uint32_t *)info.planes[0].ptr, info.planes[0].stride);
+   if (pix_surface == NULL)
+     {
+        ERR("create pixman image failed");
+        goto fail;
+     }
+
+   EINA_LIST_FOREACH(visible_list, l, hwc_window)
+     {
+        if (hwc_window->accepted_state == E_HWC_WINDOW_STATE_CLIENT)
+          {
+             if (target_window)
+               {
+                  target_window = EINA_FALSE;
+                  _e_rdp_pixman_output_image_composite(output, (E_Hwc_Window *)hwc->target_hwc_window, pix_surface, info.width, info.height, e_output_w, e_output_h);
+               }
+             continue;
+          }
+
+        _e_rdp_pixman_output_image_composite(output, hwc_window, pix_surface, info.width, info.height, e_output_w, e_output_h);
+     }
+
+   if (output->refresh_count == 0)
+     _e_rdp_backup_buffer_create(output, tbm_surface, &info);
+
+   if (hwc_window_cursor != NULL)
+     _e_rdp_pixman_output_image_composite_cursor(output, hwc_window_cursor, pix_surface, info.width, info.height, e_output_w, e_output_h);
+
+   tbm_surface_unmap(tbm_surface);
+
+   output->prepare_tbm_surface = tbm_surface;
+
+   return pix_surface;
+
+fail:
+   tbm_surface_unmap(tbm_surface);
+   tbm_surface_destroy(tbm_surface);
+   output->prepare_tbm_surface = NULL;
+   return NULL;
+}
+
+static pixman_image_t *
+_e_rdp_pixman_output_image_get_cursor(E_Rdp_Output *output, E_Hwc_Window *hwc_window_cursor, int e_output_w, int e_output_h)
+{
+   tbm_surface_h tbm_surface = NULL;
+   tbm_surface_info_s src_info, info;
+   pixman_image_t *pix_surface = NULL;
+   pixman_format_code_t pix_format = 0;
+   int err;
+
+   if ((output->mouse_x == hwc_window_cursor->current.info.dst_pos.x) &&
+       (output->mouse_y == hwc_window_cursor->current.info.dst_pos.y))
+     {
+//        INF("same position. do not update. (%dx%d)", output->mouse_x, output->mouse_y);
+        return NULL;
+     }
+
+   err = tbm_surface_map(output->backup_tbm_surface, TBM_SURF_OPTION_READ, &src_info);
+   if (err)
+     {
+        ERR("tbm_surface_map failed");
+        return NULL;
+     }
+
+   tbm_surface = _e_rdp_tbm_image_create(output, output->w, output->h, 0x00000000);
+   if (tbm_surface == NULL)
+     {
+        ERR("create tbm surface failed");
+        output->prepare_tbm_surface = NULL;
+        tbm_surface_unmap(output->backup_tbm_surface);
+        return NULL;
+     }
 
    err = tbm_surface_map(tbm_surface, TBM_SURF_OPTION_WRITE, &info);
    if (err)
-     return NULL;
+     {
+        ERR("tbm_surface_map failed");
+        tbm_surface_destroy(tbm_surface);
+        output->prepare_tbm_surface = NULL;
+        tbm_surface_unmap(output->backup_tbm_surface);
+        return NULL;
+     }
+
+   _e_rdp_tbm_surface_copy(output->backup_tbm_surface, &src_info, tbm_surface, &info);
 
    pix_format = _e_rdp_pixman_format_get(info.format);
    if (pix_format == 0)
      {
         ERR("not supported format");
-        goto out;
+        goto fail;
      }
 
    pix_surface = pixman_image_create_bits(pix_format, info.width, info.height, (uint32_t *)info.planes[0].ptr, info.planes[0].stride);
    if (pix_surface == NULL)
      {
         ERR("create pixman image failed");
-        goto out;
+        goto fail;
      }
 
+   if (hwc_window_cursor != NULL)
+     _e_rdp_pixman_output_image_composite_cursor(output, hwc_window_cursor, pix_surface, info.width, info.height, e_output_w, e_output_h);
+
+   tbm_surface_unmap(tbm_surface);
+   tbm_surface_unmap(output->backup_tbm_surface);
+
+   output->prepare_tbm_surface = tbm_surface;
+
+   return pix_surface;
+
+fail:
+   tbm_surface_unmap(tbm_surface);
+   tbm_surface_destroy(tbm_surface);
+   output->prepare_tbm_surface = NULL;
+   return NULL;
+}
+
+static pixman_image_t *
+_e_rdp_pixman_output_image_get(E_Rdp_Output *output)
+{
+   E_Output *e_output = NULL;
+   E_Hwc *hwc = NULL;
+   E_Hwc_Window *hwc_window = NULL;
+   E_Hwc_Window *hwc_window_cursor = NULL;
+   Eina_List *l;
+   Eina_List *visible_list = NULL;
+   int e_output_w, e_output_h;
+   pixman_image_t *pix_surface = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+
+   e_output = output->primary_output;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e_output, NULL);
+
+   hwc = e_output->hwc;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE);
+
+   e_output_w = e_output->config.mode.w;
+   e_output_h = e_output->config.mode.h;
+
    EINA_LIST_FOREACH(hwc->hwc_windows, l, hwc_window)
      {
         if (!hwc_window) continue;
@@ -822,7 +1008,6 @@ _e_rdp_pixman_output_image_get(E_Rdp_Output *output, tbm_surface_h tbm_surface)
 
         if (hwc_window->accepted_state == E_HWC_WINDOW_STATE_CLIENT)
           {
-             target_window = EINA_TRUE;
              visible_list = eina_list_append(visible_list, hwc_window);
              continue;
           }
@@ -833,39 +1018,27 @@ _e_rdp_pixman_output_image_get(E_Rdp_Output *output, tbm_surface_h tbm_surface)
         if (hwc_window->accepted_state == E_HWC_WINDOW_STATE_CURSOR)
           {
              if (hwc_window->cursor.buffer)
-               visible_list = eina_list_append(visible_list, hwc_window);
+               {
+                  hwc_window_cursor = hwc_window;
+               }
           }
      }
 
    if (eina_list_count(visible_list) == 0)
      {
         ERR("no visible hwc_window for capture");
-        _e_rdp_pixman_output_image_composite(output, (E_Hwc_Window *)hwc->target_hwc_window, pix_surface, info.width, info.height, e_output_w, e_output_h);
-        goto out;
+        return pix_surface;
      }
-
    visible_list = eina_list_sort(visible_list, eina_list_count(visible_list), _e_rdp_cb_hwc_window_sort);
 
-   EINA_LIST_FOREACH(visible_list, l, hwc_window)
+   if (output->buffer_changed)
      {
-        if (hwc_window->accepted_state == E_HWC_WINDOW_STATE_CLIENT)
-          {
-             if (target_window)
-               {
-                  target_window = EINA_FALSE;
-                  _e_rdp_pixman_output_image_composite(output, (E_Hwc_Window *)hwc->target_hwc_window, pix_surface, info.width, info.height, e_output_w, e_output_h);
-               }
-             continue;
-          }
-
-        if (hwc_window->is_cursor)
-          _e_rdp_pixman_output_image_composite_cursor(output, hwc_window, pix_surface, info.width, info.height, e_output_w, e_output_h);
-        else
-          _e_rdp_pixman_output_image_composite(output, hwc_window, pix_surface, info.width, info.height, e_output_w, e_output_h);
+        pix_surface = _e_rdp_pixman_output_image_get_all(output, visible_list, hwc_window_cursor, e_output_w, e_output_h);
+     }
+   else if ((output->mouse_moved) && (hwc_window_cursor != NULL))
+     {
+        pix_surface = _e_rdp_pixman_output_image_get_cursor(output, hwc_window_cursor, e_output_w, e_output_h);
      }
-
-out:
-   tbm_surface_unmap(tbm_surface);
 
    return pix_surface;
 }
@@ -874,7 +1047,6 @@ static Eina_Bool
 _e_rdp_frame_timer(void *data)
 {
    E_Rdp_Output *output;
-   tbm_surface_h tbm_surface = NULL;
    pixman_image_t *pix_surface = NULL;
    pixman_box32_t box;
    pixman_region32_t damage;
@@ -890,6 +1062,9 @@ _e_rdp_frame_timer(void *data)
      {
         output->frame_timer = NULL;
         output->refresh_count = 0;
+        output->mouse_moved = EINA_FALSE;
+        output->buffer_changed = EINA_FALSE;
+
         return ECORE_CALLBACK_CANCEL;
      }
 
@@ -898,18 +1073,13 @@ _e_rdp_frame_timer(void *data)
    gettimeofday(&start_tv, NULL);
 #endif
 
-   tbm_surface = _e_rdp_tbm_image_create(output, output->w, output->h, 0x00000000);
-   if (tbm_surface == NULL)
-     {
-        ERR("create tbm surface failed");
-        return ECORE_CALLBACK_RENEW;
-     }
-
-   pix_surface = _e_rdp_pixman_output_image_get(output, tbm_surface);
+   pix_surface = _e_rdp_pixman_output_image_get(output);
    if (pix_surface == NULL)
      {
-        ERR("create output pixman surface failed");
-        tbm_surface_destroy(tbm_surface);
+#if RDP_DEBUG
+        gettimeofday(&end_capture_tv, NULL);
+        INF("pixman capture time (no result): %ld ms", ((end_capture_tv.tv_sec * 1000 + end_capture_tv.tv_usec / 1000) - (start_tv.tv_sec * 1000 + start_tv.tv_usec / 1000)));
+#endif
         return ECORE_CALLBACK_RENEW;
      }
 
@@ -931,7 +1101,7 @@ _e_rdp_frame_timer(void *data)
         if (!client)
           continue;
 
-        e_rdp_peer_refresh_region(&damage, client, tbm_surface, pix_surface);
+        e_rdp_peer_refresh_region(&damage, client, pix_surface);
      }
    pixman_region32_fini(&damage);
 
@@ -984,6 +1154,7 @@ _e_rdp_cb_client_buffer_change(void *data, int type, void *event)
      }
    else
      output->refresh_count = 5;
+   output->buffer_changed = EINA_TRUE;
 
    return ECORE_CALLBACK_PASS_ON;
 }
@@ -1012,6 +1183,7 @@ _e_rdp_cb_pointer_mouse_move(void *data, E_Pointer *ptr)
      }
    else
      output->refresh_count = 5;
+   output->mouse_moved = EINA_TRUE;
 }
 
 static double
@@ -1155,7 +1327,9 @@ e_rdp_peer_activate(freerdp_peer *client)
    box.y2 = output->h;
    pixman_region32_init_with_extents(&damage, &box);
 
-   e_rdp_peer_refresh_region(&damage, client, tbm_surface, pix_surface);
+   output->prepare_tbm_surface = tbm_surface;
+
+   e_rdp_peer_refresh_region(&damage, client, pix_surface);
 
    pixman_region32_fini(&damage);
 
@@ -1164,6 +1338,7 @@ e_rdp_peer_activate(freerdp_peer *client)
    output->refresh_time = _e_rdp_refresh_time_set(output->w, output->h);
    output->refresh_count = 5;
    output->frame_timer = ecore_timer_add(output->refresh_time, _e_rdp_frame_timer, output);
+   output->buffer_changed = EINA_TRUE;
 
    return TRUE;
 }
@@ -1207,6 +1382,7 @@ e_rdp_input_synchronize_event(rdpInput *input, UINT32 flags)
      }
    else
      output->refresh_count = 5;
+   output->buffer_changed = EINA_TRUE;
 
    return TRUE;
 }
@@ -1371,6 +1547,30 @@ e_rdp_client_activity(int fd, uint32_t mask, void *data)
         output->frame_timer = NULL;
      }
 
+   if (b->client_count == 0)
+     {
+        if (output->showing_surface)
+          {
+             pixman_image_unref(output->showing_surface);
+             output->showing_surface = NULL;
+          }
+        if (output->prepare_tbm_surface)
+          {
+             tbm_surface_destroy(output->prepare_tbm_surface);
+             output->prepare_tbm_surface = NULL;
+          }
+        if (output->showing_tbm_surface)
+          {
+             tbm_surface_destroy(output->showing_tbm_surface);
+             output->showing_tbm_surface = NULL;
+          }
+        if (output->backup_tbm_surface)
+          {
+             tbm_surface_destroy(output->backup_tbm_surface);
+             output->backup_tbm_surface = NULL;
+          }
+     }
+
 out_clean:
    freerdp_peer_context_free(client);
    freerdp_peer_free(client);
@@ -1603,10 +1803,14 @@ e_rdp_output_destroy(E_Rdp_Output *output)
 {
    EINA_SAFETY_ON_NULL_RETURN(output);
 
-   if (output->pix_surface)
-     pixman_image_unref(output->pix_surface);
-   if (output->tbm_surface)
-     tbm_surface_destroy(output->tbm_surface);
+   if (output->showing_surface)
+     pixman_image_unref(output->showing_surface);
+   if (output->prepare_tbm_surface)
+     tbm_surface_destroy(output->prepare_tbm_surface);
+   if (output->showing_tbm_surface)
+     tbm_surface_destroy(output->showing_tbm_surface);
+   if (output->backup_tbm_surface)
+     tbm_surface_destroy(output->backup_tbm_surface);
 
    free(output);
 }