From: Alexandros Frantzis alexandros.frantzis@collabora.com
When flushing a window_surface, copy from the window_surface only the pixel data contained in the flushed bounds. If any other pixel data are needed, get them from the latest window buffer for the wayland surface, to ensure the data are valid and unchanged. --- dlls/winewayland.drv/wayland_surface.c | 3 ++ dlls/winewayland.drv/waylanddrv.h | 1 + dlls/winewayland.drv/window_surface.c | 55 ++++++++++++++++++++++++-- 3 files changed, 56 insertions(+), 3 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index cf49140d8bc..ed9ae4ee0e4 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -148,6 +148,9 @@ void wayland_surface_destroy(struct wayland_surface *surface) pthread_mutex_unlock(&surface->mutex); pthread_mutex_unlock(&xdg_data_mutex);
+ if (surface->latest_window_buffer) + wayland_shm_buffer_unref(surface->latest_window_buffer); + wl_display_flush(process_wayland.wl_display);
pthread_mutex_destroy(&surface->mutex); diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 992f504e3d7..909c8ef5b7b 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -107,6 +107,7 @@ struct wayland_surface struct xdg_toplevel *xdg_toplevel; pthread_mutex_t mutex; uint32_t current_serial; + struct wayland_shm_buffer *latest_window_buffer; };
struct wayland_shm_buffer diff --git a/dlls/winewayland.drv/window_surface.c b/dlls/winewayland.drv/window_surface.c index d3bded821a7..f88b1eb6010 100644 --- a/dlls/winewayland.drv/window_surface.c +++ b/dlls/winewayland.drv/window_surface.c @@ -363,6 +363,16 @@ static void wayland_window_surface_copy_to_buffer(struct wayland_window_surface copy_pixel_region(wws->bits, &wws_rect, buffer->map_data, &buffer_rect, region); }
+static void wayland_shm_buffer_copy(struct wayland_shm_buffer *src, + struct wayland_shm_buffer *dst, + HRGN region) +{ + RECT src_rect = {0, 0, src->width, src->height}; + RECT dst_rect = {0, 0, dst->width, dst->height}; + TRACE("src=%p dst=%p\n", src, dst); + copy_pixel_region(src->map_data, &src_rect, dst->map_data, &dst_rect, region); +} + /*********************************************************************** * wayland_window_surface_flush */ @@ -372,7 +382,8 @@ static void wayland_window_surface_flush(struct window_surface *window_surface) struct wayland_shm_buffer *shm_buffer = NULL; BOOL flushed = FALSE; RECT damage_rect; - HRGN surface_damage_region; + HRGN surface_damage_region = NULL; + HRGN copy_from_window_region;
wayland_window_surface_lock(window_surface);
@@ -397,7 +408,6 @@ static void wayland_window_surface_flush(struct window_surface *window_surface) }
wayland_buffer_queue_add_damage(wws->wayland_buffer_queue, surface_damage_region); - NtGdiDeleteObjectApp(surface_damage_region);
shm_buffer = wayland_buffer_queue_acquire_buffer(wws->wayland_buffer_queue); if (!shm_buffer) @@ -406,7 +416,38 @@ static void wayland_window_surface_flush(struct window_surface *window_surface) goto done; }
- wayland_window_surface_copy_to_buffer(wws, shm_buffer, shm_buffer->damage_region); + if (wws->wayland_surface->latest_window_buffer) + { + TRACE("latest_window_buffer=%p\n", wws->wayland_surface->latest_window_buffer); + /* If we have a latest buffer, use it as the source of all pixel + * data that are not contained in the bounds of the flush... */ + if (wws->wayland_surface->latest_window_buffer != shm_buffer) + { + HRGN copy_from_latest_region = NtGdiCreateRectRgn(0, 0, 0, 0); + if (!copy_from_latest_region) + { + ERR("failed to create copy_from_latest region\n"); + goto done; + } + NtGdiCombineRgn(copy_from_latest_region, shm_buffer->damage_region, + surface_damage_region, RGN_DIFF); + wayland_shm_buffer_copy(wws->wayland_surface->latest_window_buffer, + shm_buffer, copy_from_latest_region); + NtGdiDeleteObjectApp(copy_from_latest_region); + } + /* ... and use the window_surface as the source of pixel data contained + * in the flush bounds. */ + copy_from_window_region = surface_damage_region; + } + else + { + TRACE("latest_window_buffer=NULL\n"); + /* If we don't have a latest buffer, use the window_surface as + * the source of all pixel data. */ + copy_from_window_region = shm_buffer->damage_region; + } + + wayland_window_surface_copy_to_buffer(wws, shm_buffer, copy_from_window_region);
pthread_mutex_lock(&wws->wayland_surface->mutex); if (wws->wayland_surface->current_serial) @@ -423,6 +464,13 @@ static void wayland_window_surface_flush(struct window_surface *window_surface) wl_display_flush(process_wayland.wl_display);
NtGdiSetRectRgn(shm_buffer->damage_region, 0, 0, 0, 0); + /* Update the latest window buffer for the wayland surface. Note that we + * only care whether the buffer contains the latest window contents, + * it's irrelevant if it was actually committed or not. */ + wayland_shm_buffer_ref(shm_buffer); + if (wws->wayland_surface->latest_window_buffer) + wayland_shm_buffer_unref(wws->wayland_surface->latest_window_buffer); + wws->wayland_surface->latest_window_buffer = shm_buffer;
done: if (flushed) @@ -437,6 +485,7 @@ done: wayland_shm_buffer_unref(shm_buffer); } } + if (surface_damage_region) NtGdiDeleteObjectApp(surface_damage_region); wayland_window_surface_unlock(window_surface); }