Wayland: limit copied pixels when window update is a region

This commit is contained in:
ManoloFLTK 2023-04-05 23:21:43 +02:00
parent 5cedb9e174
commit 0c930b9ca3
5 changed files with 44 additions and 30 deletions

View File

@ -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

View File

@ -28,12 +28,10 @@ typedef struct _PangoLayout PangoLayout;
typedef struct _PangoContext PangoContext;
typedef struct _PangoFontDescription PangoFontDescription;
#if USE_PANGO
struct flCairoRegion {
struct flCairoRegion {
int count;
struct _cairo_rectangle *rects;
}; // a region is the union of a series of rectangles
#endif
}; // a region is the union of a series of rectangles
class Fl_Cairo_Font_Descriptor : public Fl_Font_Descriptor {
public:

View File

@ -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;

View File

@ -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);
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;

View File

@ -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);