diff options
| author | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2023-06-05 11:00:33 +0200 |
|---|---|---|
| committer | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2023-06-05 11:00:33 +0200 |
| commit | 5be3fbf913210a8b81fe101c3927c141432fa724 (patch) | |
| tree | b79a0e6844573483dda34751ea47b60e130db308 /src/drivers | |
| parent | 5dfa51a8201ce0111220575956d2fb0db989fe90 (diff) | |
Improve re-use of client/compositor shared memory by Wayland buffers
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H | 41 | ||||
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx | 68 | ||||
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx | 46 |
3 files changed, 61 insertions, 94 deletions
diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H index b6697df40..81a3dbf8f 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H @@ -1,7 +1,7 @@ // // Definition of class Fl_Wayland_Graphics_Driver. // -// Copyright 2021-2022 by Bill Spitzak and others. +// Copyright 2021-2023 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -22,37 +22,10 @@ #ifndef FL_WAYLAND_GRAPHICS_DRIVER_H #define FL_WAYLAND_GRAPHICS_DRIVER_H - -/* Implementation note about buffers FLTK uses to support display graphics under Wayland. - - Each window is associated to an FLTK-defined object of type struct wld_window - containing itself an FLTK-defined struct fl_wld_buffer object holding all graphics data. - Among members of this latter structure are: - - struct wl_buffer wl_buffer - is a Wayland-defined type for a graphics buffer able to be attached to a wl_surface; - - void *data - points to the beginning of the memory zone where wl_buffer stores its graphics data; - - unsigned char *draw_buffer - contains a graphics buffer to which all Cairo drawings are directed; - draw_buffer and data both have the same organization called CAIRO_FORMAT_ARGB32 in Cairo parlance - and WL_SHM_FORMAT_ARGB8888 in Wayland parlance which means BGRA byte order. - - int width - gives the pixel width of the graphics buffer; - - int stride - gives the stride of this buffer; - - size_t data_size - gives the total buffer size in bytes (thus, data_size / stride gives the buffer height); - - struct wl_callback *cb - is used to synchronize drawing with the compositor during progressive drawing. - - When a graphics scene is to be committed, the data_size bytes of draw_buffer are copied by memcpy() - starting at data, and wl_buffer is attached to the wl_surface which is committed for display - by wl_surface_commit(). - */ - - #include "../Cairo/Fl_Cairo_Graphics_Driver.H" #include <stdint.h> // for uint32_t +#include <wayland-client.h> // for wl_list + struct fl_wld_buffer { struct wl_buffer *wl_buffer; @@ -64,19 +37,19 @@ struct fl_wld_buffer { struct wl_callback *cb; bool draw_buffer_needs_commit; cairo_t *cairo_; + struct wl_shm_pool *shm_pool; + struct wl_list link; // links all buffers from the same wl_shm_pool }; -struct wld_window; class Fl_Wayland_Graphics_Driver : public Fl_Cairo_Graphics_Driver { private: struct fl_wld_buffer *buffer_; public: - struct wld_shm_pool_data { // attached to wl_shm_pool objects + struct wld_shm_pool_data { // one record attached to each wl_shm_pool object char *pool_memory; // start of mmap'ed memory encapsulated by the wl_shm_pool int pool_size; // size of encapsulated memory - int use_count; // nber of active wl_buffer objects in this wl_shm_pool - bool destroyed; // true after the wl_shm_pool was destroyed + struct wl_list buffers; // to list of fl_wld_buffer's from this pool }; Fl_Wayland_Graphics_Driver(); static const uint32_t wld_format; diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx index cfe1ff494..4a5351701 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx @@ -27,53 +27,56 @@ extern "C" { # include "../../../libdecor/src/os-compatibility.h" // for os_create_anonymous_file() } +// used by create_shm_buffer and buffer_release +static struct wl_shm_pool *pool = NULL; // the current pool + struct fl_wld_buffer *Fl_Wayland_Graphics_Driver::create_shm_buffer(int width, int height) { struct fl_wld_buffer *buffer; int stride = cairo_format_stride_for_width(Fl_Cairo_Graphics_Driver::cairo_format, width); int size = stride * height; - static int pool_size = 10000000; // gets increased if necessary - static int chunk_offset = pool_size; - static int fd = -1; - static struct wl_shm_pool *pool = NULL; - if (chunk_offset + size > pool_size) { + const int default_pool_size = 10000000; // larger pools are possible if needed + int chunk_offset = 0; // offset to start of available memory in pool + struct wld_shm_pool_data *pool_data = pool ? // data record attached to current pool + (struct wld_shm_pool_data *)wl_shm_pool_get_user_data(pool) : NULL; + int pool_size = pool ? pool_data->pool_size : default_pool_size; // current pool size + if (pool) { + // last fl_wld_buffer created from current pool + struct fl_wld_buffer *record = wl_container_of(pool_data->buffers.next, record, link); + chunk_offset = ((char*)record->data - pool_data->pool_memory) + record->data_size; + } + if (!pool || chunk_offset + size > pool_size) { // if true, a new pool is needed chunk_offset = 0; - if (pool) { - struct wld_shm_pool_data *pool_data = - (struct wld_shm_pool_data *)wl_shm_pool_get_user_data(pool); - wl_shm_pool_destroy(pool); - close(fd); - pool_data->destroyed = true; - if (pool_data->use_count == 0) { - /*int err =*/ munmap(pool_data->pool_memory, pool_data->pool_size); -//printf("munmap(%p)->%d\n", pool_data->pool_memory, err); - free(pool_data); - } + pool_size = default_pool_size; + if (size > pool_size) pool_size = 2 * size; // a larger pool is needed + int fd = os_create_anonymous_file(pool_size); + if (fd < 0) { + Fl::fatal("os_create_anonymous_file failed: %s\n", strerror(errno)); } - if (size > pool_size) pool_size = 2 * size; - fd = os_create_anonymous_file(pool_size); - struct wld_shm_pool_data *pool_data = (struct wld_shm_pool_data*) - calloc(1, sizeof(struct wld_shm_pool_data)); - pool_data->pool_memory = (char*)mmap(NULL, pool_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + pool_data = (struct wld_shm_pool_data*)calloc(1, sizeof(struct wld_shm_pool_data)); + pool_data->pool_memory = (char*)mmap(NULL, pool_size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); if (pool_data->pool_memory == MAP_FAILED) { close(fd); Fl::fatal("mmap failed: %s\n", strerror(errno)); } Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); pool = wl_shm_create_pool(scr_driver->wl_shm, fd, pool_size); + close(fd); // does not prevent the mmap'ed memory from being used +//puts("wl_shm_create_pool"); pool_data->pool_size = pool_size; + wl_list_init(&pool_data->buffers); wl_shm_pool_set_user_data(pool, pool_data); } buffer = (struct fl_wld_buffer*)calloc(1, sizeof(struct fl_wld_buffer)); buffer->stride = stride; buffer->wl_buffer = wl_shm_pool_create_buffer(pool, chunk_offset, width, height, stride, Fl_Wayland_Graphics_Driver::wld_format); - struct wld_shm_pool_data *pool_data = - (struct wld_shm_pool_data *)wl_shm_pool_get_user_data(pool); - pool_data->use_count++; - wl_buffer_set_user_data(buffer->wl_buffer, pool_data); + // add this buffer to head of list of current pool's buffers + wl_list_insert(&pool_data->buffers, &buffer->link); + buffer->shm_pool = pool; buffer->data = (void*)(pool_data->pool_memory + chunk_offset); - chunk_offset += size; +//fprintf(stderr, "last=%p chunk_offset=%d ", pool_data->buffers.next, chunk_offset); buffer->data_size = size; buffer->width = width; buffer->draw_buffer = new uchar[buffer->data_size]; @@ -174,15 +177,20 @@ void Fl_Wayland_Graphics_Driver::buffer_release(struct wld_window *window) { if (window->buffer) { if (window->buffer->cb) wl_callback_destroy(window->buffer->cb); + struct wl_shm_pool *my_pool = window->buffer->shm_pool; struct wld_shm_pool_data *pool_data = - (struct wld_shm_pool_data *)wl_buffer_get_user_data(window->buffer->wl_buffer); + (struct wld_shm_pool_data*)wl_shm_pool_get_user_data(my_pool); wl_buffer_destroy(window->buffer->wl_buffer); //printf("wl_buffer_destroy(%p)\n",window->buffer->wl_buffer); - pool_data->use_count--; - if (pool_data->destroyed && pool_data->use_count == 0) { - /*int err =*/ munmap(pool_data->pool_memory, pool_data->pool_size); + // remove fl_wld_buffer from list of pool's buffers + wl_list_remove(&window->buffer->link); +//printf("last=%p\n", wl_list_empty(&pool_data->buffers) ? NULL : pool_data->buffers.next); + if (wl_list_empty(&pool_data->buffers)) { // all buffers from pool are gone + wl_shm_pool_destroy(my_pool); + /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size); //printf("munmap(%p)->%d\n", pool_data->pool_memory, err); free(pool_data); + if (my_pool == pool) pool = NULL; } delete[] window->buffer->draw_buffer; window->buffer->draw_buffer = NULL; diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx index dbd6acf32..735d8b527 100644 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx @@ -71,22 +71,12 @@ Fl_Wayland_Window_Driver::Fl_Wayland_Window_Driver(Fl_Window *win) : Fl_Window_D } -struct custom_cursor_data { - struct fl_wld_buffer *offscreen; - struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data *buf_data; -}; - - void Fl_Wayland_Window_Driver::delete_cursor_(struct wld_window *xid, bool delete_rgb) { struct wld_window::custom_cursor_ *custom = xid->custom_cursor; if (custom) { struct wl_cursor *wl_cursor = custom->wl_cursor; struct cursor_image *new_image = (struct cursor_image*)wl_cursor->images[0]; - custom_cursor_data *buf_data = - (custom_cursor_data *)wl_buffer_get_user_data(new_image->buffer); - struct fl_wld_buffer *offscreen = buf_data->offscreen; - wl_buffer_set_user_data(new_image->buffer, buf_data->buf_data); - free(buf_data); + struct fl_wld_buffer *offscreen = (struct fl_wld_buffer *)wl_buffer_get_user_data(new_image->buffer); struct wld_window fake_xid; fake_xid.buffer = offscreen; Fl_Wayland_Graphics_Driver::buffer_release(&fake_xid); @@ -676,13 +666,13 @@ static void surface_enter(void *data, struct wl_surface *wl_surface, struct wl_o i++; } } - if (window->kind == Fl_Wayland_Window_Driver::POPUP) { - Fl_Wayland_Graphics_Driver::buffer_release(window); - window->fl_win->redraw(); - } else { - float post_scale = Fl::screen_scale(win_driver->screen_num()) * output->wld_scale; - //printf("pre_scale=%.1f post_scale=%.1f\n", pre_scale, post_scale); - if (window->fl_win->as_gl_window() || post_scale != pre_scale) { + float post_scale = Fl::screen_scale(win_driver->screen_num()) * output->wld_scale; + //printf("pre_scale=%.1f post_scale=%.1f\n", pre_scale, post_scale); + if (window->fl_win->as_gl_window() || post_scale != pre_scale) { + if (window->kind == Fl_Wayland_Window_Driver::POPUP) { + Fl_Wayland_Graphics_Driver::buffer_release(window); + window->fl_win->redraw(); + } else { win_driver->is_a_rescale(true); window->fl_win->size(window->fl_win->w(), window->fl_win->h()); win_driver->is_a_rescale(false); @@ -691,16 +681,17 @@ static void surface_enter(void *data, struct wl_surface *wl_surface, struct wl_o win_driver->Fl_Window_Driver::flush(); Fl::add_timeout(0.01, (Fl_Timeout_Handler)delayed_redraw, window->fl_win); } - } else if (window->buffer) { - if (!window->buffer->cb) { - 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); + } else if (window->buffer) { + if (!window->buffer->cb) { + 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); } + static void surface_leave(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output) { // Do nothing because surface_leave old display arrives **after** surface_enter new display @@ -1565,12 +1556,7 @@ int Fl_Wayland_Window_Driver::set_cursor_4args(const Fl_RGB_Image *rgb, int hotx //create a Wayland buffer and have it used as an image of the new cursor struct fl_wld_buffer *offscreen = Fl_Wayland_Graphics_Driver::create_shm_buffer(new_image->image.width, new_image->image.height); new_image->buffer = offscreen->wl_buffer; - custom_cursor_data *new_buf_data = - (custom_cursor_data*)malloc(sizeof(custom_cursor_data)); - new_buf_data->buf_data = (struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data *) - wl_buffer_get_user_data(new_image->buffer); - new_buf_data->offscreen = offscreen; - wl_buffer_set_user_data(new_image->buffer, new_buf_data); + wl_buffer_set_user_data(new_image->buffer, offscreen); new_cursor->image_count = 1; new_cursor->images = (struct wl_cursor_image**)malloc(sizeof(struct wl_cursor_image*)); new_cursor->images[0] = (struct wl_cursor_image*)new_image; |
