Wayland: limit copied pixels when window update is a region
This commit is contained in:
parent
5cedb9e174
commit
0c930b9ca3
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user