e_hwc_window_queue: separate buffer copy from main thread 56/297656/1
authorChangyeon Lee <cyeon.lee@samsung.com>
Fri, 11 Aug 2023 04:53:11 +0000 (13:53 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Tue, 22 Aug 2023 08:27:53 +0000 (17:27 +0900)
this patch uses thread for copying buffer of queue to prevent
block main thread.

Change-Id: I2f152c0f06f827456437877879c2821856c01d1b

src/bin/e_hwc_window_queue.c
src/bin/e_hwc_window_queue.h
src/bin/e_hwc_windows.c

index bdb937c..53dbe03 100644 (file)
@@ -77,15 +77,25 @@ static Eina_Bool ehwq_trace = EINA_FALSE;
 
 static Eina_Bool _e_hwc_window_queue_buffers_retrieve_done(E_Hwc_Window_Queue *queue);
 static void _e_hwc_window_queue_unset(E_Hwc_Window_Queue *queue);
+static void _e_hwc_window_queue_copy_thread_run_cb(void *data, Ecore_Thread *th);
+static void _e_hwc_window_queue_copy_thread_run_notify_cb(void *data, Ecore_Thread *thread, void *msg_data);
+static void _e_hwc_window_queue_copy_thread_run_end_cb(void *data, Ecore_Thread *th);
+static void _e_hwc_window_queue_copy_thread_run_cancel_cb(void *data, Ecore_Thread *th);
 
 typedef struct _E_Hwc_Window_Queue_Manager E_Hwc_Window_Queue_Manager;
 typedef struct _E_Hwc_Window_Queue_Event E_Hwc_Window_Queue_Event;
+typedef struct _E_Hwc_Window_Queue_Copy_Thread_Data E_Hwc_Window_Queue_Copy_Thread_Data;
 
 struct _E_Hwc_Window_Queue_Manager
 {
    Eina_List *hwc_winq_list;
    Eina_List *hwc_gbm_winq_list;
    Eina_List *event_handlers;
+
+   Ecore_Thread *copy_thread;
+   Eina_Bool copy_thread_canceled;
+   E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data;
+   Eina_List *pending_copy_thread_data_list;
 };
 
 struct _E_Hwc_Window_Queue_Event
@@ -93,9 +103,22 @@ struct _E_Hwc_Window_Queue_Event
    E_Hwc_Window_Queue *queue;
 };
 
+struct _E_Hwc_Window_Queue_Copy_Thread_Data
+{
+   E_Hwc_Window_Queue *queue;
+   E_Hwc_Window *hwc_window;
+
+   tbm_surface_h src_tsurface;
+   E_Comp_Wl_Buffer_Ref src_buffer_ref;
+   int src_transform;
+
+   tbm_surface_h dst_tsurface;
+};
+
 static Eina_List *hwc_window_queue_hwc_hooks = NULL;
 static Eina_List *hwc_window_queue_window_hooks = NULL;
 static Eina_List *hwc_window_queue_comp_wl_hooks = NULL;
+static Eina_List *hwc_window_queue_pixmap_hooks = NULL;
 static E_Hwc_Window_Queue_Manager *_hwc_winq_mgr = NULL;
 
 static uint32_t
@@ -141,17 +164,17 @@ static tbm_surface_h
 _backup_tsurface_create(tbm_surface_h tsurface)
 {
    tbm_surface_h new_tsurface;
-   tbm_surface_info_s src_info, dst_info;
+   tbm_surface_info_s src_info;
    int ret = TBM_SURFACE_ERROR_NONE;
 
-   ret = tbm_surface_map(tsurface, TBM_SURF_OPTION_READ, &src_info);
+   ret = tbm_surface_get_info(tsurface, &src_info);
    if (ret != TBM_SURFACE_ERROR_NONE)
      {
         EHWQERR("fail to map the tsurface", NULL, NULL, NULL);
         return NULL;
      }
 
-   EHWQINF("Backup buffer create w:%d h:%d fmt:%c%c%c%c", NULL, NULL, NULL,
+   EHWQINF("Copy Backup buffer create w:%d h:%d fmt:%c%c%c%c", NULL, NULL, NULL,
            src_info.width, src_info.height, EHW_FOURCC_STR(src_info.format));
 
    /* get the buffer from e20 module first, if no buffer from e20 module, then create the tbm_surface here. */
@@ -162,32 +185,67 @@ _backup_tsurface_create(tbm_surface_h tsurface)
         if (!new_tsurface)
           {
              EHWQERR("fail to allocate the new_tsurface", NULL, NULL, NULL);
-             tbm_surface_unmap(tsurface);
              return NULL;
           }
    }
 
-   EHWQINF("Backup buffer create done tsurface:%p", NULL, NULL, NULL, new_tsurface);
+   EHWQINF("Copy Backup buffer create done tsurface:%p", NULL, NULL, NULL, new_tsurface);
+
+   return new_tsurface;
+}
+
+static Eina_Bool
+_e_hwc_window_queue_copy_content(tbm_surface_h src_tsurface, tbm_surface_h dst_tsurface, Ecore_Thread *thread)
+{
+   tbm_surface_info_s src_info, dst_info;
+   int ret = TBM_SURFACE_ERROR_NONE;
+   void *src_ptr, *dst_ptr;
+   int i, height, extra_size;
+   void *thread_src_ptr1, *thread_dst_ptr1;
+   void *thread_src_ptr2, *thread_dst_ptr2;
+   void *thread_src_ptr3, *thread_dst_ptr3;
+   void *thread_src_ptr4, *thread_dst_ptr4;
+   int i1, i2, i3, i4, thread_height, thread_extra_height;
+   Eina_Bool thread_canceled = EINA_FALSE;
+
+   ret = tbm_surface_map(src_tsurface, TBM_SURF_OPTION_READ, &src_info);
+   if (ret != TBM_SURFACE_ERROR_NONE)
+     {
+        EHWQERR("fail to map the tsurface", NULL, NULL, NULL);
+        return EINA_FALSE;
+     }
 
-   ret = tbm_surface_map(new_tsurface, TBM_SURF_OPTION_WRITE, &dst_info);
+   ret = tbm_surface_map(dst_tsurface, TBM_SURF_OPTION_WRITE, &dst_info);
    if (ret != TBM_SURFACE_ERROR_NONE)
      {
         EHWQERR("fail to map the new_tsurface", NULL, NULL, NULL);
-        tbm_surface_destroy(new_tsurface);
-        tbm_surface_unmap(tsurface);
-        return NULL;
+        tbm_surface_unmap(src_tsurface);
+        return EINA_FALSE;
      }
 
+   src_ptr = src_info.planes[0].ptr;
+   dst_ptr = dst_info.planes[0].ptr;
+   height = src_info.size / src_info.planes[0].stride;
+   extra_size = src_info.size % src_info.planes[0].stride;
+
    /* copy from src to dst */
 #if HAVE_LIBGOMP
 # define LIBGOMP_COPY_THREAD_NUM 4
-# define LIBGOMP_COPY_PAGE_SIZE getpagesize()
-# define PAGE_ALIGN(addr) ((addr)&(~((LIBGOMP_COPY_PAGE_SIZE)-1)))
-   if (src_info.planes[0].size > (LIBGOMP_COPY_THREAD_NUM * LIBGOMP_COPY_PAGE_SIZE))
+   thread_height = height / LIBGOMP_COPY_THREAD_NUM;
+   thread_extra_height = height % LIBGOMP_COPY_THREAD_NUM;
+   if (thread_height)
      {
-        size_t step[2];
-        step[0] = PAGE_ALIGN(src_info.planes[0].size / LIBGOMP_COPY_THREAD_NUM);
-        step[1] = src_info.planes[0].size - (step[0] * (LIBGOMP_COPY_THREAD_NUM - 1));
+        thread_src_ptr1 = src_ptr;
+        thread_dst_ptr1 = dst_ptr;
+
+        thread_src_ptr2 = src_ptr + (thread_height * src_info.planes[0].stride);
+        thread_dst_ptr2 = dst_ptr + (thread_height * src_info.planes[0].stride);
+
+        thread_src_ptr3 = src_ptr + (thread_height * src_info.planes[0].stride * 2);
+        thread_dst_ptr3 = dst_ptr + (thread_height * src_info.planes[0].stride * 2);
+
+        thread_src_ptr4 = src_ptr + (thread_height * src_info.planes[0].stride * 3);
+        thread_dst_ptr4 = dst_ptr + (thread_height * src_info.planes[0].stride * 3);
 
         omp_set_num_threads(LIBGOMP_COPY_THREAD_NUM);
         #pragma omp parallel
@@ -195,66 +253,100 @@ _backup_tsurface_create(tbm_surface_h tsurface)
           {
              #pragma omp section
                {
-                  memcpy(dst_info.planes[0].ptr,
-                         src_info.planes[0].ptr,
-                         step[0]);
+                  for (i1 = 0; i1 < thread_height; i1++)
+                    {
+                       if ((thread) && (ecore_thread_check(thread)))
+                         {
+                            EHWQINF("Copy thread is canceled", NULL, NULL, NULL);
+                            thread_canceled = EINA_TRUE;
+                            break;
+                         }
+
+                       memcpy(thread_dst_ptr1, thread_src_ptr1, src_info.planes[0].stride);
+                       thread_src_ptr1 += dst_info.planes[0].stride;
+                       thread_dst_ptr1 += dst_info.planes[0].stride;
+                    }
                }
              #pragma omp section
                {
-                  memcpy(dst_info.planes[0].ptr + step[0],
-                         src_info.planes[0].ptr + step[0],
-                         step[0]);
+                  for (i2 = 0; i2 < thread_height; i2++)
+                    {
+                       if (thread_canceled) break;
+
+                       memcpy(thread_dst_ptr2, thread_src_ptr2, src_info.planes[0].stride);
+                       thread_src_ptr2 += dst_info.planes[0].stride;
+                       thread_dst_ptr2 += dst_info.planes[0].stride;
+                    }
                }
              #pragma omp section
                {
-                  memcpy(dst_info.planes[0].ptr + (step[0] * 2),
-                         src_info.planes[0].ptr + (step[0] * 2),
-                         step[0]);
+                  for (i3 = 0; i3 < thread_height; i3++)
+                    {
+                       if (thread_canceled) break;
+
+                       memcpy(thread_dst_ptr3, thread_src_ptr3, src_info.planes[0].stride);
+                       thread_src_ptr3 += dst_info.planes[0].stride;
+                       thread_dst_ptr3 += dst_info.planes[0].stride;
+                    }
                }
              #pragma omp section
                {
-                  memcpy(dst_info.planes[0].ptr + (step[0] * 3),
-                         src_info.planes[0].ptr + (step[0] * 3),
-                         step[1]);
+                  for (i4 = 0; i4 < thread_height + thread_extra_height; i4++)
+                    {
+                       if (thread_canceled) break;
+
+                       memcpy(thread_dst_ptr4, thread_src_ptr4, src_info.planes[0].stride);
+                       thread_src_ptr4 += dst_info.planes[0].stride;
+                       thread_dst_ptr4 += dst_info.planes[0].stride;
+                    }
+
+                  if (!thread_canceled)
+                    memcpy(thread_dst_ptr4, thread_src_ptr4, extra_size);
                }
           }
      }
    else
      {
-        memcpy(dst_info.planes[0].ptr,
-               src_info.planes[0].ptr,
-               src_info.planes[0].size);
-     }
-#else /* HAVE_LIBGOMP */
-   memcpy(dst_info.planes[0].ptr, src_info.planes[0].ptr, src_info.planes[0].size);
-#endif /* end of HAVE_LIBGOMP */
-
-   tbm_surface_unmap(new_tsurface);
-   tbm_surface_unmap(tsurface);
-
-   return new_tsurface;
-}
-
-static E_Comp_Wl_Buffer *
-_comp_wl_backup_buffer_get(tbm_surface_h tsurface)
-{
-   tbm_surface_h backup_tsurface;
-   E_Comp_Wl_Buffer *backup_buffer;
+        for (i = 0; i < height; i++)
+          {
+             if ((thread) && (ecore_thread_check(thread)))
+               {
+                  EHWQINF("Copy thread is canceled", NULL, NULL, NULL);
+                  thread_canceled = EINA_TRUE;
+                  break;
+               }
 
-   backup_tsurface = _backup_tsurface_create(tsurface);
-   EINA_SAFETY_ON_NULL_RETURN_VAL(backup_tsurface, NULL);
+             memcpy(dst_ptr, src_ptr, src_info.planes[0].stride);
+             src_ptr += dst_info.planes[0].stride;
+             dst_ptr += dst_info.planes[0].stride;
+          }
 
-   backup_buffer = e_comp_wl_tbm_buffer_get(backup_tsurface);
-   if (!backup_buffer)
+        if (!thread_canceled)
+          memcpy(dst_ptr, src_ptr, extra_size);
+     }
+#else /* HAVE_LIBGOMP */
+   for (i = 0; i < height; i++)
      {
-        EHWQERR("Fail to e_comp_wl_tbm_buffer_get", NULL, NULL, NULL);
-        tbm_surface_internal_unref(backup_tsurface);
-        return NULL;
+        if ((thread) && (ecore_thread_check(thread)))
+          {
+             EHWQINF("Copy thread is canceled", NULL, NULL, NULL);
+             thread_canceled = EINA_TRUE;
+             break;
+          }
+
+        memcpy(dst_ptr, src_ptr, src_info.planes[0].stride);
+        src_ptr += dst_info.planes[0].stride;
+        dst_ptr += dst_info.planes[0].stride;
      }
 
-   tbm_surface_internal_unref(backup_tsurface);
+   if (!thread_canceled)
+     memcpy(dst_ptr, src_ptr, extra_size);
+#endif /* end of HAVE_LIBGOMP */
+
+   tbm_surface_unmap(src_tsurface);
+   tbm_surface_unmap(dst_tsurface);
 
-   return backup_buffer;
+   return EINA_TRUE;
 }
 
 static tbm_surface_queue_h
@@ -398,7 +490,7 @@ _e_hwc_window_queue_exported_buffer_destroy_cb(struct wl_listener *listener, voi
        (queue->state == E_HWC_WINDOW_QUEUE_STATE_SET_WAITING_BUFFER))
      queue->state = E_HWC_WINDOW_QUEUE_STATE_SET_INVALID;
 
-   if (!queue_buffer->acquired && queue_buffer->dequeued)
+   if ((!queue_buffer->acquired) && (queue_buffer->dequeued) && (!queue_buffer->copying))
      e_hwc_window_queue_buffer_release(queue, queue_buffer);
 
    queue_buffer->usable = EINA_FALSE;
@@ -452,7 +544,7 @@ _e_hwc_window_queue_exported_buffer_detach_cb(struct wayland_tbm_client_queue *c
            queue_buffer->tsurface, queue->tqueue,
            queue_buffer->exported_wl_buffer);
 
-   if (!queue_buffer->acquired && queue_buffer->dequeued)
+   if ((!queue_buffer->acquired) && (queue_buffer->dequeued) && (!queue_buffer->copying))
      e_hwc_window_queue_buffer_release(queue, queue_buffer);
 
    queue_buffer->usable = EINA_FALSE;
@@ -610,7 +702,7 @@ _e_hwc_window_queue_wait_usable_cb(struct wayland_tbm_client_queue *cqueue, void
 }
 
 static Eina_Bool
-_e_hwc_window_queue_buffers_retrieve(E_Hwc_Window_Queue *queue, E_Hwc_Window *hwc_window)
+_e_hwc_window_queue_buffers_retrieve(E_Hwc_Window_Queue *queue)
 {
    if (queue->user)
      e_hwc_window_deactivate(queue->user);
@@ -633,6 +725,9 @@ _e_hwc_window_queue_buffers_retrieve_done(E_Hwc_Window_Queue *queue)
         if (queue_buffer->exported)
           return EINA_FALSE;
 
+        if (queue_buffer->copying)
+          return EINA_FALSE;
+
         if ((!queue->is_target) && (queue_buffer->acquired))
           return EINA_FALSE;
      }
@@ -797,67 +892,6 @@ fail:
    return EINA_FALSE;
 }
 
-static tbm_surface_h
-_e_hwc_window_queue_backup_buffer_set(E_Hwc_Window *hwc_window, Eina_Bool attach)
-{
-   E_Comp_Wl_Buffer *comp_buffer, *backup_buffer;
-   tbm_surface_h tsurface;
-   uint32_t flags = 0;
-   E_Client *ec = hwc_window->ec;
-
-   if (!ec) return NULL;
-
-   comp_buffer = _comp_wl_buffer_get(hwc_window->ec);
-   if (!comp_buffer) return NULL;
-   if (!comp_buffer->tbm_surface) return NULL;
-
-   tsurface = comp_buffer->tbm_surface;
-
-   if (comp_buffer->resource)
-     {
-        flags = _comp_wl_buffer_flags_get(comp_buffer);
-        if (flags !=  E_HWC_WINDOW_QUEUE_BUFFER_FLAGS)
-          return NULL;
-     }
-   else
-     {
-        if (tsurface != hwc_window->display.buffer.tsurface)
-          return NULL;
-
-        if (!hwc_window->display.buffer.from_queue)
-          return NULL;
-     }
-
-   EHWQINF("Backup buffer get ehw:%p origin:%p",
-           hwc_window->ec, hwc_window->hwc, NULL, hwc_window,
-           comp_buffer->tbm_surface);
-
-   backup_buffer = _comp_wl_backup_buffer_get(tsurface);
-   EINA_SAFETY_ON_NULL_RETURN_VAL(backup_buffer, NULL);
-
-   if (comp_buffer)
-     backup_buffer->transform = comp_buffer->transform;
-
-   EHWQINF("Backup buffer set ehw:%p origin:%p tsurface:%p",
-           hwc_window->ec, hwc_window->hwc, NULL, hwc_window,
-           comp_buffer->tbm_surface, backup_buffer->tbm_surface);
-
-   if (attach)
-     {
-        e_comp_wl_surface_attach(ec, backup_buffer);
-     }
-   else
-     {
-        E_Comp_Wl_Client_Data *cdata = e_client_cdata_get(ec);
-        e_comp_wl_buffer_reference(&cdata->buffer_ref, backup_buffer);
-        e_pixmap_resource_set(ec->pixmap, backup_buffer);
-        e_pixmap_dirty(ec->pixmap);
-        e_pixmap_refresh(ec->pixmap);
-     }
-
-   return tsurface;
-}
-
 static Eina_Bool
 _e_hwc_window_queue_prepare_set(E_Hwc_Window_Queue *queue, E_Hwc_Window *hwc_window)
 {
@@ -959,48 +993,562 @@ _e_hwc_window_queue_set(E_Hwc_Window_Queue *queue)
 }
 
 static void
-_e_hwc_window_queue_prepare_unset(E_Hwc_Window_Queue *queue)
+_e_hwc_window_queue_copy_thread_data_destroy(E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data)
 {
-   E_Hwc_Window *hwc_window = queue->user;
+   E_Hwc_Window_Queue_Buffer *queue_buffer;
+
+   if (!copy_thread_data) return;
+
+   EHWQINF("Destroy Copy tdata:%p src:%p dst:%p",
+           copy_thread_data->hwc_window->ec,
+           copy_thread_data->hwc_window->hwc,
+           copy_thread_data->queue,
+           copy_thread_data,
+           copy_thread_data->src_tsurface,
+           copy_thread_data->dst_tsurface);
+
+   queue_buffer = e_hwc_window_queue_buffer_find(copy_thread_data->queue, copy_thread_data->src_tsurface);
+   if (queue_buffer)
+     {
+        queue_buffer->copying = EINA_FALSE;
+
+        if ((!queue_buffer->acquired) && (queue_buffer->dequeued))
+          e_hwc_window_queue_buffer_release(copy_thread_data->queue, queue_buffer);
+     }
+
+   e_object_unref(E_OBJECT(copy_thread_data->queue));
+
+   e_comp_wl_buffer_reference(&copy_thread_data->src_buffer_ref, NULL);
+
+   if (copy_thread_data->src_tsurface)
+     tbm_surface_internal_unref(copy_thread_data->src_tsurface);
+
+   if (copy_thread_data->dst_tsurface)
+     tbm_surface_internal_unref(copy_thread_data->dst_tsurface);
+
+   e_hwc_window_unref(copy_thread_data->hwc_window);
+
+   free(copy_thread_data);
+}
+
+static E_Hwc_Window_Queue_Copy_Thread_Data *
+_e_hwc_window_queue_copy_thread_data_create(E_Hwc_Window_Queue *queue,
+                                            E_Hwc_Window *hwc_window,
+                                            E_Comp_Wl_Buffer *buffer)
+{
+   E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data;
+   E_Hwc_Window_Queue_Buffer *queue_buffer;
+
+   copy_thread_data = E_NEW(E_Hwc_Window_Queue_Copy_Thread_Data, 1);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(copy_thread_data, NULL);
+
+   copy_thread_data->queue = queue;
+   e_object_ref(E_OBJECT(queue));
+
+   copy_thread_data->hwc_window = hwc_window;
+   e_hwc_window_ref(hwc_window);
+
+   copy_thread_data->src_tsurface = buffer->tbm_surface;
+   tbm_surface_internal_ref(buffer->tbm_surface);
+
+   copy_thread_data->src_transform = buffer->transform;
+
+   e_comp_wl_buffer_reference(&copy_thread_data->src_buffer_ref, buffer);
+
+   queue_buffer = e_hwc_window_queue_buffer_find(queue, buffer->tbm_surface);
+   if (queue_buffer)
+     queue_buffer->copying = EINA_TRUE;
+
+   EHWQINF("Create Copy tdata:%p src:%p",
+           copy_thread_data->hwc_window->ec,
+           copy_thread_data->hwc_window->hwc,
+           copy_thread_data->queue,
+           copy_thread_data,
+           copy_thread_data->src_tsurface);
+
+   return copy_thread_data;
+}
+
+static void
+_e_hwc_window_queue_copy_thread_cancel_buffer_reuse(E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data)
+{
+   E_Hwc_Window_Queue_Copy_Thread_Data *tdata;
+   Eina_List *l;
+   tbm_surface_info_s src_info, dst_info;
+   tbm_surface_error_e ret = TBM_SURFACE_ERROR_NONE;
+
+   if (!_hwc_winq_mgr) return;
+   if (!copy_thread_data->dst_tsurface) return;
+
+   ret = tbm_surface_get_info(copy_thread_data->dst_tsurface, &dst_info);
+   if (ret != TBM_SURFACE_ERROR_NONE)
+     {
+        EHWQERR("fail to map the tsurface", NULL, NULL, NULL);
+        return;
+     }
+
+   EINA_LIST_FOREACH(_hwc_winq_mgr->pending_copy_thread_data_list, l, tdata)
+     {
+        if (copy_thread_data == tdata) continue;
+        if (tdata->dst_tsurface) continue;
+
+        ret = tbm_surface_get_info(tdata->src_tsurface, &src_info);
+        if (ret != TBM_SURFACE_ERROR_NONE) continue;
+
+        if ((src_info.width != dst_info.width) ||
+            (src_info.height != dst_info.height) ||
+            (src_info.format != dst_info.format))
+           continue;
+
+        tbm_surface_internal_ref(copy_thread_data->dst_tsurface);
+        tdata->dst_tsurface = copy_thread_data->dst_tsurface;
+        break;
+     }
+}
+
+static void
+_e_hwc_window_queue_copy_thread_cancel(E_Hwc_Window *hwc_window,
+                                       E_Hwc_Window_Queue_Copy_Thread_Data *pending_except)
+{
+   E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data;
+   Eina_List *l, *ll;
+
+   EINA_LIST_FOREACH_SAFE(_hwc_winq_mgr->pending_copy_thread_data_list, l, ll, copy_thread_data)
+     {
+        if (copy_thread_data == pending_except) continue;
+        if (copy_thread_data->hwc_window != hwc_window) continue;
+
+        _hwc_winq_mgr->pending_copy_thread_data_list =
+           eina_list_remove_list(_hwc_winq_mgr->pending_copy_thread_data_list, l);
+
+        _e_hwc_window_queue_copy_thread_cancel_buffer_reuse(copy_thread_data);
+        _e_hwc_window_queue_copy_thread_data_destroy(copy_thread_data);
+     }
+
+   if ((!_hwc_winq_mgr->copy_thread_canceled) &&
+       (_hwc_winq_mgr->copy_thread) &&
+       (_hwc_winq_mgr->copy_thread_data))
+     {
+        if (_hwc_winq_mgr->copy_thread_data->hwc_window == hwc_window)
+          {
+             EHWQINF("Cancel Copy ecore thread tdata:%p src:%p dst:%p",
+                     _hwc_winq_mgr->copy_thread_data->hwc_window->ec,
+                     _hwc_winq_mgr->copy_thread_data->hwc_window->hwc,
+                     _hwc_winq_mgr->copy_thread_data->queue,
+                     _hwc_winq_mgr->copy_thread_data,
+                     _hwc_winq_mgr->copy_thread_data->src_tsurface,
+                     _hwc_winq_mgr->copy_thread_data->dst_tsurface);
+
+             _e_hwc_window_queue_copy_thread_cancel_buffer_reuse(_hwc_winq_mgr->copy_thread_data);
+             ecore_thread_cancel(_hwc_winq_mgr->copy_thread);
+             _hwc_winq_mgr->copy_thread_canceled = EINA_TRUE;
+          }
+     }
+}
+
+static void
+_e_hwc_window_queue_copy_thread_sync_run(E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data)
+{
+   if (!copy_thread_data->dst_tsurface)
+     {
+        copy_thread_data->dst_tsurface = _backup_tsurface_create(copy_thread_data->src_tsurface);
+        if (!copy_thread_data->dst_tsurface)
+          {
+             EHWQERR("fail to dst_tsurface tdata:%p src:%p",
+                     copy_thread_data->hwc_window->ec,
+                     copy_thread_data->hwc_window->hwc,
+                     copy_thread_data->queue,
+                     copy_thread_data,
+                     copy_thread_data->src_tsurface);
+
+             _e_hwc_window_queue_copy_thread_data_destroy(copy_thread_data);
+             return;
+          }
+     }
+
+   _hwc_winq_mgr->copy_thread_data = copy_thread_data;
+
+   _e_hwc_window_queue_copy_thread_run_cb(copy_thread_data, NULL);
+   _e_hwc_window_queue_copy_thread_run_end_cb(copy_thread_data, NULL);
+}
+
+static Eina_Bool
+_e_hwc_window_queue_copy_thread_run(E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data)
+{
+   if (!copy_thread_data->dst_tsurface)
+     {
+        copy_thread_data->dst_tsurface = _backup_tsurface_create(copy_thread_data->src_tsurface);
+        if (!copy_thread_data->dst_tsurface)
+          {
+             EHWQERR("fail to dst_tsurface tdata:%p src:%p",
+                     copy_thread_data->hwc_window->ec,
+                     copy_thread_data->hwc_window->hwc,
+                     copy_thread_data->queue,
+                     copy_thread_data,
+                     copy_thread_data->src_tsurface);
+
+             return EINA_FALSE;
+          }
+     }
+
+   _hwc_winq_mgr->copy_thread_data = copy_thread_data;
+   _hwc_winq_mgr->copy_thread_canceled = EINA_FALSE;
+   _hwc_winq_mgr->copy_thread = ecore_thread_feedback_run(_e_hwc_window_queue_copy_thread_run_cb,
+                                                          _e_hwc_window_queue_copy_thread_run_notify_cb,
+                                                          _e_hwc_window_queue_copy_thread_run_end_cb,
+                                                          _e_hwc_window_queue_copy_thread_run_cancel_cb,
+                                                          copy_thread_data,
+                                                          EINA_TRUE);
+   if (!_hwc_winq_mgr->copy_thread)
+     {
+        EHWQERR("fail to run Copy tdata:%p src:%p dst:%p",
+                copy_thread_data->hwc_window->ec,
+                copy_thread_data->hwc_window->hwc,
+                copy_thread_data->queue,
+                copy_thread_data,
+                copy_thread_data->src_tsurface,
+                copy_thread_data->dst_tsurface);
+
+        _hwc_winq_mgr->copy_thread_data = NULL;
+        return EINA_FALSE;
+     }
+
+   EHWQINF("Run Copy tdata:%p src:%p dst:%p",
+           copy_thread_data->hwc_window->ec,
+           copy_thread_data->hwc_window->hwc,
+           copy_thread_data->queue,
+           copy_thread_data,
+           copy_thread_data->src_tsurface,
+           copy_thread_data->dst_tsurface);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_hwc_window_queue_pending_copy_thread_check_and_run(void)
+{
+   E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data, *tdata;
+
+   if (!_hwc_winq_mgr) return EINA_TRUE;
+
+   if (!eina_list_count(_hwc_winq_mgr->pending_copy_thread_data_list))
+      return EINA_TRUE;
+
+   copy_thread_data = eina_list_nth(_hwc_winq_mgr->pending_copy_thread_data_list, 0);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(copy_thread_data, EINA_FALSE);
+
+   _hwc_winq_mgr->pending_copy_thread_data_list =
+      eina_list_remove(_hwc_winq_mgr->pending_copy_thread_data_list, copy_thread_data);
+
+   if (!_e_hwc_window_queue_copy_thread_run(copy_thread_data))
+     {
+        EHWQERR("fail to run copy thread tdata:%p src:%p dst:%p",
+                copy_thread_data->hwc_window->ec,
+                copy_thread_data->hwc_window->hwc,
+                copy_thread_data->queue,
+                copy_thread_data,
+                copy_thread_data->src_tsurface,
+                copy_thread_data->dst_tsurface);
+
+        _e_hwc_window_queue_copy_thread_sync_run(copy_thread_data);
+
+        EINA_LIST_FREE(_hwc_winq_mgr->pending_copy_thread_data_list, tdata)
+          _e_hwc_window_queue_copy_thread_sync_run(tdata);
+
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static void
+_e_hwc_window_queue_copy_thread_run_cb(void *data, Ecore_Thread *thread)
+{
+   E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data;
+
+   if (!(copy_thread_data = data)) return;
+
+   if (thread)
+     eina_thread_name_set(eina_thread_self(), "e_hwc_widnow_queue_copy_thread");
+
+   EHWQINF("Copy buffer tdata:%p src:%p dst:%p",
+           NULL,
+           NULL,
+           NULL,
+           copy_thread_data,
+           copy_thread_data->src_tsurface,
+           copy_thread_data->dst_tsurface);
+
+   if (!_e_hwc_window_queue_copy_content(copy_thread_data->src_tsurface,
+                                         copy_thread_data->dst_tsurface,
+                                         thread))
+     {
+        EHWQERR("fail to copy content tdata:%p src:%p dst:%p",
+                NULL,
+                NULL,
+                NULL,
+                copy_thread_data,
+                copy_thread_data->src_tsurface,
+                copy_thread_data->dst_tsurface);
+     }
+
+   EHWQINF("Copy buffer done tdata:%p src:%p dst:%p",
+           NULL,
+           NULL,
+           NULL,
+           copy_thread_data,
+           copy_thread_data->src_tsurface,
+           copy_thread_data->dst_tsurface);
+}
+
+static void
+_e_hwc_window_queue_copy_thread_run_notify_cb(void *data, Ecore_Thread *thread, void *msg_data)
+{
+}
+
+static void
+_e_hwc_window_queue_copy_thread_run_end_cb(void *data, Ecore_Thread *thread)
+{
+   E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data;
+   E_Comp_Wl_Buffer *comp_buffer, *copy_comp_buffer;
+   E_Client *ec;
+   E_Hwc_Window_Queue *queue;
+
+   if (!(copy_thread_data = data)) return;
+
+   queue = copy_thread_data->queue;
+
+   e_object_ref(E_OBJECT(queue));
+
+   EHWQINF("End Copy tdata:%p src:%p",
+           copy_thread_data->hwc_window->ec,
+           copy_thread_data->hwc_window->hwc,
+           copy_thread_data->queue,
+           copy_thread_data,
+           copy_thread_data->src_tsurface);
+
+   if (!(ec = copy_thread_data->hwc_window->ec)) goto end;
+
+   if ((!evas_object_visible_get(ec->frame)) &&
+       (ec->exp_iconify.buffer_flush) &&
+       (e_policy_visibility_client_is_iconic(ec)))
+     goto end;
+
+   comp_buffer = _comp_wl_buffer_get(ec);
+   if (!comp_buffer) goto end;
+   if (!comp_buffer->tbm_surface) goto end;
+   if (comp_buffer->tbm_surface != copy_thread_data->src_tsurface) goto end;
+
+   copy_comp_buffer = e_comp_wl_tbm_buffer_get(copy_thread_data->dst_tsurface);
+   EINA_SAFETY_ON_NULL_GOTO(copy_comp_buffer, end);
+
+   copy_comp_buffer->transform = copy_thread_data->src_transform;
+
+   e_comp_wl_surface_attach(ec, copy_comp_buffer);
+   e_pixmap_image_refresh(ec->pixmap);
+   e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
+   e_comp_object_dirty(ec->frame);
+   e_comp_object_render(ec->frame);
+
+end:
+   _e_hwc_window_queue_copy_thread_data_destroy(copy_thread_data);
+
+   if (_hwc_winq_mgr)
+     {
+        _hwc_winq_mgr->copy_thread_data = NULL;
+        _hwc_winq_mgr->copy_thread_canceled = EINA_FALSE;
+        _hwc_winq_mgr->copy_thread = NULL;
+     }
+
+   if (_e_hwc_window_queue_buffers_retrieve_done(queue))
+     _e_hwc_window_queue_unset(queue);
+
+   e_object_unref(E_OBJECT(queue));
+
+   if (!thread) return;
+
+   if (!_e_hwc_window_queue_pending_copy_thread_check_and_run())
+     {
+        EHWQERR("fail to run pending copy thread", NULL, NULL, NULL);
+        return;
+     }
+}
+
+static void
+_e_hwc_window_queue_copy_thread_run_cancel_cb(void *data, Ecore_Thread *thread)
+{
+   E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data;
+   E_Hwc_Window_Queue *queue;
+
+   if (!(copy_thread_data = data)) return;
+
+   queue = copy_thread_data->queue;
+
+   e_object_ref(E_OBJECT(queue));
+
+   EHWQINF("Cancel Copy tdata:%p src:%p",
+           copy_thread_data->hwc_window->ec,
+           copy_thread_data->hwc_window->hwc,
+           copy_thread_data->queue,
+           copy_thread_data,
+           copy_thread_data->src_tsurface);
+
+   _e_hwc_window_queue_copy_thread_data_destroy(copy_thread_data);
+
+   if (_hwc_winq_mgr)
+     {
+        _hwc_winq_mgr->copy_thread_data = NULL;
+        _hwc_winq_mgr->copy_thread_canceled = EINA_FALSE;
+        _hwc_winq_mgr->copy_thread = NULL;
+     }
+
+   if (_e_hwc_window_queue_buffers_retrieve_done(queue))
+     _e_hwc_window_queue_unset(queue);
+
+   e_object_unref(E_OBJECT(queue));
+
+   if (!thread) return;
+
+   if (!_e_hwc_window_queue_pending_copy_thread_check_and_run())
+     {
+        EHWQERR("fail to run pending copy thread", NULL, NULL, NULL);
+        return;
+     }
+}
+
+static E_Hwc_Window_Queue_Buffer *
+_e_hwc_window_queue_buffer_find_from_tbm_surface(tbm_surface_h tsurface)
+{
+   E_Hwc_Window_Queue *queue;
+   E_Hwc_Window_Queue_Buffer *queue_buffer;
+   Eina_List *l, *ll;
+
+   if (!_hwc_winq_mgr) return NULL;
+
+   EINA_LIST_FOREACH_SAFE(_hwc_winq_mgr->hwc_winq_list, l, ll, queue)
+     {
+        queue_buffer = e_hwc_window_queue_buffer_find(queue, tsurface);
+        if (!queue_buffer) continue;
+
+        return queue_buffer;
+     }
+
+   return NULL;
+}
+
+static void
+_e_hwc_window_queue_copy_thread_check_and_run(E_Hwc_Window *hwc_window)
+{
+   E_Comp_Wl_Buffer *comp_buffer;
    tbm_surface_h tsurface;
+   uint32_t flags = 0;
+   E_Client *ec = hwc_window->ec;
+   E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data;
+   E_Hwc_Window_Queue *queue;
    E_Hwc_Window_Queue_Buffer *queue_buffer;
 
+   if (!_hwc_winq_mgr) return;
+   if (!ec) return;
+
+   comp_buffer = _comp_wl_buffer_get(hwc_window->ec);
+   if (!comp_buffer) return;
+   if (!comp_buffer->tbm_surface) return;
+
+   tsurface = comp_buffer->tbm_surface;
+
+   if (comp_buffer->resource)
+     {
+        flags = _comp_wl_buffer_flags_get(comp_buffer);
+        if (flags !=  E_HWC_WINDOW_QUEUE_BUFFER_FLAGS)
+          return;
+     }
+   else
+     {
+        if (tsurface != hwc_window->display.buffer.tsurface)
+          return;
+
+        if (!hwc_window->display.buffer.from_queue)
+          return;
+     }
+
+   queue_buffer = _e_hwc_window_queue_buffer_find_from_tbm_surface(tsurface);
+   EINA_SAFETY_ON_NULL_RETURN(queue_buffer);
+
+   if (queue_buffer->copying) return;
+
+   queue = queue_buffer->queue;
+   EINA_SAFETY_ON_NULL_RETURN(queue);
+
+   if (queue->state != E_HWC_WINDOW_QUEUE_STATE_UNSET_WAITING)
+     return;
+
+   copy_thread_data = _e_hwc_window_queue_copy_thread_data_create(queue, hwc_window, comp_buffer);
+   EINA_SAFETY_ON_NULL_RETURN(copy_thread_data);
+
+   if (_hwc_winq_mgr->copy_thread)
+     {
+        if (queue->is_target)
+          {
+             _hwc_winq_mgr->pending_copy_thread_data_list =
+                eina_list_prepend(_hwc_winq_mgr->pending_copy_thread_data_list, copy_thread_data);
+          }
+        else
+          {
+             _hwc_winq_mgr->pending_copy_thread_data_list =
+                eina_list_append(_hwc_winq_mgr->pending_copy_thread_data_list, copy_thread_data);
+          }
+
+        _e_hwc_window_queue_copy_thread_cancel(hwc_window, copy_thread_data);
+     }
+   else
+     {
+        if (!_e_hwc_window_queue_copy_thread_run(copy_thread_data))
+          {
+             EHWQERR("fail to run copy thread tdata:%p src:%p dst:%p",
+                     copy_thread_data->hwc_window->ec,
+                     copy_thread_data->hwc_window->hwc,
+                     copy_thread_data->queue,
+                     copy_thread_data,
+                     copy_thread_data->src_tsurface,
+                     copy_thread_data->dst_tsurface);
+
+             _e_hwc_window_queue_copy_thread_sync_run(copy_thread_data);
+          }
+     }
+}
+
+static void
+_e_hwc_window_queue_prepare_unset(E_Hwc_Window_Queue *queue)
+{
+   E_Hwc_Window *hwc_window = queue->user;
+
+   if (queue->state == E_HWC_WINDOW_QUEUE_STATE_UNSET_WAITING)
+     return;
+
    tbm_surface_queue_remove_dequeuable_cb(queue->tqueue,
                                           _e_hwc_window_queue_cb_dequeueable,
                                           (void *)queue);
 
-   if ((hwc_window) && (hwc_window->cqueue))
+   if (hwc_window->cqueue)
      wayland_tbm_server_client_queue_set_wait_usable_cb(hwc_window->cqueue, NULL, NULL);
 
    /* queue retrieve the buffers from the hwc_window */
-   _e_hwc_window_queue_buffers_retrieve(queue, queue->user);
+   _e_hwc_window_queue_buffers_retrieve(queue);
+
+   queue->state = E_HWC_WINDOW_QUEUE_STATE_UNSET_WAITING;
+
+   EHWQINF("Unset Waiting user ehw:%p - {%s}",
+            hwc_window->ec, queue->hwc, queue, hwc_window,
+            (hwc_window->ec ? hwc_window->ec->icccm.title : "UNKNOWN"));
 
-   if ((!hwc_window) || (!hwc_window->ec)) return;
+   if (!hwc_window->ec) return;
 
    if ((!evas_object_visible_get(hwc_window->ec->frame)) &&
        (hwc_window->ec->exp_iconify.buffer_flush) &&
        (e_policy_visibility_client_is_iconic(hwc_window->ec)))
-    return;
-
-   tsurface = _e_hwc_window_queue_backup_buffer_set(hwc_window, EINA_TRUE);
-   if (tsurface)
-     {
-        if(hwc_window->render_target)
-          {
-             e_pixmap_image_refresh(hwc_window->ec->pixmap);
-             e_comp_object_damage(hwc_window->ec->frame, 0, 0,
-                                  hwc_window->ec->w, hwc_window->ec->h);
-             e_comp_object_dirty(hwc_window->ec->frame);
-             e_comp_object_render(hwc_window->ec->frame);
-          }
+     return;
 
-        queue_buffer = e_hwc_window_queue_buffer_find(queue, tsurface);
-        if (queue_buffer)
-          {
-             if (!queue_buffer->acquired && queue_buffer->dequeued)
-               e_hwc_window_queue_buffer_release(queue, queue_buffer);
-          }
-     }
+   _e_hwc_window_queue_copy_thread_check_and_run(hwc_window);
 }
 
 static void
@@ -1062,15 +1610,12 @@ _e_hwc_window_queue_unset(E_Hwc_Window_Queue *queue)
    E_Hwc_Window_Queue_Buffer *queue_buffer;
    Eina_List *l;
 
-   if (queue->state == E_HWC_WINDOW_QUEUE_STATE_UNSET_WAITING)
-     {
-        queue->user = queue->user_waiting_unset;
-        queue->user_waiting_unset = NULL;
-     }
+   if (queue->state == E_HWC_WINDOW_QUEUE_STATE_UNSET)
+     return;
 
    EINA_LIST_FOREACH(queue->buffers, l, queue_buffer)
      {
-        if (!queue_buffer->acquired && queue_buffer->dequeued)
+        if ((!queue_buffer->acquired) && (queue_buffer->dequeued))
           e_hwc_window_queue_buffer_release(queue, queue_buffer);
      }
 
@@ -1095,61 +1640,18 @@ _e_hwc_window_queue_unset(E_Hwc_Window_Queue *queue)
 }
 
 static void
-_e_hwc_window_unkown_queue_release(tbm_surface_h tsurface)
-{
-   E_Hwc_Window_Queue *queue;
-   E_Hwc_Window_Queue_Buffer *queue_buffer;
-   Eina_List *l, *ll;
-
-   if (!_hwc_winq_mgr) return;
-
-   EINA_LIST_FOREACH_SAFE(_hwc_winq_mgr->hwc_winq_list, l, ll, queue)
-     {
-        queue_buffer = e_hwc_window_queue_buffer_find(queue, tsurface);
-        if (!queue_buffer) continue;
-
-        if (!queue_buffer->acquired && queue_buffer->dequeued)
-          e_hwc_window_queue_buffer_release(queue, queue_buffer);
-     }
-}
-
-static void
 _e_hwc_window_queue_cb_buffer_change(void *data, E_Client *ec)
 {
    E_Hwc_Window *hwc_window;
-   E_Comp_Wl_Buffer *comp_buffer;
-   uint32_t flags = 0;
-   tbm_surface_h tsurface;
 
    EINA_SAFETY_ON_NULL_RETURN(ec);
 
    hwc_window = ec->hwc_window;
    if (!hwc_window) return;
-   if ((hwc_window->queue) &&
-       ((e_hwc_window_device_state_available_get(hwc_window)) || (!ec->redirected)))
-     {
-        if (hwc_window->queue->state == E_HWC_WINDOW_QUEUE_STATE_SET)
-          return;
-
-        comp_buffer = _comp_wl_buffer_get(ec);
-        if (!comp_buffer) return;
-        if (!comp_buffer->resource) return;
-        if (!comp_buffer->tbm_surface) return;
-
-        flags = _comp_wl_buffer_flags_get(comp_buffer);
-        if (flags !=  E_HWC_WINDOW_QUEUE_BUFFER_FLAGS) return;
-
-        if ((hwc_window->queue->user == hwc_window) &&
-            (e_hwc_window_queue_buffer_find(hwc_window->queue, comp_buffer->tbm_surface)))
-          return;
-     }
-
    if ((ec->exp_iconify.buffer_flush) && (e_policy_visibility_client_is_iconic(ec)))
      return;
 
-   tsurface = _e_hwc_window_queue_backup_buffer_set(hwc_window, EINA_FALSE);
-   if (tsurface)
-     _e_hwc_window_unkown_queue_release(tsurface);
+   _e_hwc_window_queue_copy_thread_check_and_run(hwc_window);
 }
 
 void
@@ -1379,6 +1881,24 @@ _e_hwc_window_queue_cb_norender_set(void *data, E_Hwc *hwc)
      }
 }
 
+static void
+_e_hwc_window_queue_cb_pixmap_buffer_clear(void *data EINA_UNUSED, E_Pixmap *cp)
+{
+   E_Hwc_Window *hwc_window;
+   E_Client *ec;
+
+   if (!cp) return;
+   if (!_hwc_winq_mgr) return;
+
+   ec = e_pixmap_client_get(cp);
+   if (!ec) return;
+
+   hwc_window = ec->hwc_window;
+   if (!hwc_window) return;
+
+   _e_hwc_window_queue_copy_thread_cancel(hwc_window, NULL);
+}
+
 EINTERN Eina_Bool
 e_hwc_window_queue_init(void)
 {
@@ -1395,6 +1915,8 @@ e_hwc_window_queue_init(void)
                             _e_hwc_window_queue_cb_accepted_state_set, NULL);
    E_COMP_WL_HOOK_APPEND(hwc_window_queue_comp_wl_hooks, E_COMP_WL_HOOK_BUFFER_CHANGE,
                          _e_hwc_window_queue_cb_buffer_change, NULL);
+   E_PIXMAP_HOOK_APPEND(hwc_window_queue_pixmap_hooks, E_PIXMAP_HOOK_BUFFER_CLEAR,
+                        _e_hwc_window_queue_cb_pixmap_buffer_clear, NULL);
 
    return EINA_TRUE;
 }
@@ -1402,14 +1924,23 @@ e_hwc_window_queue_init(void)
 EINTERN void
 e_hwc_window_queue_deinit(void)
 {
+   E_Hwc_Window_Queue_Copy_Thread_Data *copy_thread_data;
+
    if (!_hwc_winq_mgr) return;
 
+   if (_hwc_winq_mgr->copy_thread)
+     ecore_thread_cancel(_hwc_winq_mgr->copy_thread);
+
+   EINA_LIST_FREE(_hwc_winq_mgr->pending_copy_thread_data_list, copy_thread_data)
+     _e_hwc_window_queue_copy_thread_data_destroy(copy_thread_data);
+
    _hwc_winq_mgr->hwc_winq_list = eina_list_free(_hwc_winq_mgr->hwc_winq_list);
 
    E_FREE_LIST(_hwc_winq_mgr->event_handlers, ecore_event_handler_del);
    E_FREE_LIST(hwc_window_queue_hwc_hooks, e_hwc_hook_del);
    E_FREE_LIST(hwc_window_queue_window_hooks, e_hwc_window_hook_del);
    E_FREE_LIST(hwc_window_queue_comp_wl_hooks, e_comp_wl_hook_del);
+   E_FREE_LIST(hwc_window_queue_pixmap_hooks, e_pixmap_hook_del);
 
    E_FREE(_hwc_winq_mgr);
    _hwc_winq_mgr = NULL;
@@ -1477,8 +2008,7 @@ e_hwc_window_queue_user_set(E_Hwc_Window *hwc_window)
    if (queue->hwc != hwc_window->hwc)
      queue->hwc = hwc_window->hwc;
 
-   if (queue->user ||
-       queue->state == E_HWC_WINDOW_QUEUE_STATE_UNSET_WAITING)
+   if (queue->user)
      {
         _e_hwc_window_queue_user_pending_set_add(queue, hwc_window);
 
@@ -1530,16 +2060,6 @@ e_hwc_window_queue_user_unset(E_Hwc_Window_Queue *queue, E_Hwc_Window *hwc_windo
 
    if (_e_hwc_window_queue_buffers_retrieve_done(queue))
      _e_hwc_window_queue_unset(queue);
-   else
-     {
-        queue->state = E_HWC_WINDOW_QUEUE_STATE_UNSET_WAITING;
-        queue->user_waiting_unset = queue->user;
-        queue->user = NULL;
-
-        EHWQINF("Unset Waiting user ehw:%p - {%s}",
-                hwc_window->ec, queue->hwc, queue, hwc_window,
-                (hwc_window->ec ? hwc_window->ec->icccm.title : "UNKNOWN"));
-     }
 }
 
 static E_Hwc_Window_Queue_Buffer *
@@ -1984,14 +2504,11 @@ e_hwc_window_queue_debug_info_get(Eldbus_Message_Iter *iter)
         if (!queue) continue;
 
         snprintf(info_str, sizeof(info_str),
-                "[%2d] Queue(%8p) tqueue(%8p) target(%d) state(%s) user(%8p):win(0x%08zx)"
-                " unset_waiting_user(%8p):win(0x%08zx)",
+                "[%2d] Queue(%8p) tqueue(%8p) target(%d) state(%s) user(%8p):win(0x%08zx)",
                 ++idx, queue, queue->tqueue, queue->is_target,
                 _e_hwc_window_queue_state_string_get(queue->state),
                 queue->user,
-                queue->user ? e_client_util_win_get(queue->user->ec) : 0,
-                queue->user_waiting_unset,
-                queue->user_waiting_unset ? e_client_util_win_get(queue->user_waiting_unset->ec) : 0);
+                queue->user ? e_client_util_win_get(queue->user->ec) : 0);
         eldbus_message_iter_basic_append(line_array, 's', info_str);
 
         pending_set_idx = 0;
@@ -2008,11 +2525,11 @@ e_hwc_window_queue_debug_info_get(Eldbus_Message_Iter *iter)
           {
              snprintf(info_str, sizeof(info_str),
                       " └─ [%2d] Queue_Buffer(%8p) tsurface(%8p) exported_wl_buffer(%u)"
-                      " exported(%d) usable(%d) released(%d) acquired(%d) dequeued(%d)",
+                      " exported(%d) usable(%d) released(%d) acquired(%d) dequeued(%d) copying(%d)",
                       ++buf_idx, queue_buffer, queue_buffer->tsurface,
                       queue_buffer->exported_wl_buffer ? wl_resource_get_id(queue_buffer->exported_wl_buffer) : 0,
                       queue_buffer->exported, queue_buffer->usable, queue_buffer->released,
-                      queue_buffer->acquired, queue_buffer->dequeued);
+                      queue_buffer->acquired, queue_buffer->dequeued, queue_buffer->copying);
              eldbus_message_iter_basic_append(line_array, 's', info_str);
           }
         eldbus_message_iter_basic_append(line_array, 's', "");
index 5b7eaad..de3a519 100644 (file)
@@ -77,6 +77,7 @@ struct _E_Hwc_Window_Queue_Buffer
    Eina_Bool                      acquired;
    Eina_Bool                      dequeued;
    Eina_Bool                      reseted;
+   Eina_Bool                      copying;
 
    int                            busy;
 
index 1a1c535..0741dd0 100644 (file)
@@ -4414,7 +4414,7 @@ e_hwc_windows_client_type_override(E_Hwc *hwc)
 
    EINA_SAFETY_ON_NULL_RETURN(hwc);
 
-   EINA_LIST_FOREACH(hwc->hwc_windows, l, hwc_window)
+   EINA_LIST_REVERSE_FOREACH(hwc->visible_windows, l, hwc_window)
      {
         if (hwc_window->is_target) continue;