diff --git a/documentation/src/wayland.dox b/documentation/src/wayland.dox index 4c9fbfd94..c621b8160 100644 --- a/documentation/src/wayland.dox +++ b/documentation/src/wayland.dox @@ -345,9 +345,10 @@ graphics data to the display. That is done by calling function \c Fl_Wayland_Graphics_Driver::buffer_commit() which copies the byte array of the Cairo surface to the Wayland buffer's starting memory address, and calls functions \c wl_surface_attach() and \c wl_surface_commit(). Before calling Fl_Window::flush(), -FLTK has computed a damaged region. \c Fl_Wayland_Window_Driver::flush() also calls function -\c wl_surface_damage_buffer() with that information to inform the compositor of what parts -of the surface need its attention. +FLTK has computed a damaged region. If that region is not null, +\c Fl_Wayland_Graphics_Driver::buffer_commit() copies only the damaged part of the Cairo +surface to the Wayland buffer and calls function \c wl_surface_damage_buffer() for these +parts to inform the compositor of what parts of the surface need its attention. An important detail here is that FLTK uses Wayland's synchronization mechanism to make sure the surface's \c wl_buffer is not changed until the surface is fully diff --git a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H index c2a7d4c54..6a782c3c5 100644 --- a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H +++ b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H @@ -28,12 +28,10 @@ typedef struct _PangoLayout PangoLayout; typedef struct _PangoContext PangoContext; typedef struct _PangoFontDescription PangoFontDescription; -#if USE_PANGO - struct flCairoRegion { - int count; - struct _cairo_rectangle *rects; - }; // a region is the union of a series of rectangles -#endif +struct flCairoRegion { + int count; + struct _cairo_rectangle *rects; +}; // a region is the union of a series of rectangles class Fl_Cairo_Font_Descriptor : public Fl_Font_Descriptor { public: diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H index d736df9de..5e3b13f8b 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H @@ -78,7 +78,7 @@ public: void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, int srcx, int srcy) FL_OVERRIDE; static struct fl_wld_buffer *create_shm_buffer(int width, int height); static void buffer_release(struct wld_window *window); - static void buffer_commit(struct wld_window *window, bool need_damage = true); + static void buffer_commit(struct wld_window *window, struct flCairoRegion *r = NULL); static void cairo_init(struct fl_wld_buffer *buffer, int width, int height, int stride, cairo_format_t format); void *gc() FL_OVERRIDE; void gc(void *gc) FL_OVERRIDE; diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx index 608a8c004..a7b3610d8 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx @@ -92,15 +92,44 @@ static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time } -void Fl_Wayland_Graphics_Driver::buffer_commit(struct wld_window *window, bool need_damage) { +// copy pixels in region r from the Cairo surface to the Wayland buffer +static void copy_region(struct wld_window *window, struct flCairoRegion *r) { + struct fl_wld_buffer *buffer = window->buffer; + float f = Fl::screen_scale(window->fl_win->screen_num()) * + Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale(); + for (int i = 0; i < r->count; i++) { + int left = r->rects[i].x * f; + int top = r->rects[i].y * f; + int width = r->rects[i].width * f; + int height = r->rects[i].height * f; + int offset = top * buffer->stride + 4 * left; + int W4 = 4 * width; + for (int l = 0; l < height; l++) { + if (offset + W4 >= buffer->data_size) { + W4 = buffer->data_size - offset; + if (W4 <= 0) break; + } + memcpy((uchar*)buffer->data + offset, buffer->draw_buffer + offset, W4); + offset += buffer->stride; + } + wl_surface_damage_buffer(window->wl_surface, left, top, width, height); + } +} + + +void Fl_Wayland_Graphics_Driver::buffer_commit(struct wld_window *window, + struct flCairoRegion *r) { cairo_surface_t *surf = cairo_get_target(window->buffer->cairo_); cairo_surface_flush(surf); - memcpy(window->buffer->data, window->buffer->draw_buffer, window->buffer->data_size); + if (r) copy_region(window, r); + else { + memcpy(window->buffer->data, window->buffer->draw_buffer, window->buffer->data_size); + wl_surface_damage_buffer(window->wl_surface, 0, 0, 1000000, 1000000); + } wl_surface_attach(window->wl_surface, window->buffer->wl_buffer, 0, 0); wl_surface_set_buffer_scale(window->wl_surface, Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale()); window->buffer->cb = wl_surface_frame(window->wl_surface); - if (need_damage) wl_surface_damage_buffer(window->wl_surface, 0, 0, 1000000, 1000000); wl_callback_add_listener(window->buffer->cb, &surface_frame_listener, window); wl_surface_commit(window->wl_surface); window->buffer->draw_buffer_needs_commit = false; diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx index d7031ace0..eee7892bf 100644 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx @@ -395,27 +395,13 @@ void Fl_Wayland_Window_Driver::flush() { Fl_X *ip = Fl_X::flx(pWindow); struct flCairoRegion* r = (struct flCairoRegion*)ip->region; - float f = Fl::screen_scale(pWindow->screen_num()) * wld_scale(); - if (r && window->buffer) { - for (int i = 0; i < r->count; i++) { - int left = r->rects[i].x * f; - int top = r->rects[i].y * f; - int width = r->rects[i].width * f; - int height = r->rects[i].height * f; - wl_surface_damage_buffer(window->wl_surface, left, top, width, height); -//fprintf(stderr, "damage %dx%d %dx%d\n", left, top, width, height); - } - } else { - wl_surface_damage_buffer(window->wl_surface, 0, 0, - pWindow->w() * f, pWindow->h() * f); -//fprintf(stderr, "damage 0x0 %dx%d\n", pWindow->w() * f, pWindow->h() * f); - } + if (!window->buffer) r = NULL; Fl_Wayland_Window_Driver::in_flush = true; Fl_Window_Driver::flush(); Fl_Wayland_Window_Driver::in_flush = false; if (window->buffer->cb) wl_callback_destroy(window->buffer->cb); - Fl_Wayland_Graphics_Driver::buffer_commit(window, false); + Fl_Wayland_Graphics_Driver::buffer_commit(window, r); } @@ -667,7 +653,7 @@ static void surface_enter(void *data, struct wl_surface *wl_surface, struct wl_o window->fl_win->size(window->fl_win->w(), window->fl_win->h()); win_driver->is_a_rescale(false); } else if (window->buffer) { - Fl_Wayland_Graphics_Driver::buffer_commit(window, true); + Fl_Wayland_Graphics_Driver::buffer_commit(window); } if (window->fl_win->as_gl_window()) wl_surface_set_buffer_scale(window->wl_surface, output->wld_scale);