diff options
Diffstat (limited to 'src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx')
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx | 310 |
1 files changed, 0 insertions, 310 deletions
diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx deleted file mode 100644 index 5c9539a8c..000000000 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx +++ /dev/null @@ -1,310 +0,0 @@ -// -// Implementation of the Wayland graphics driver. -// -// 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 -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include "Fl_Wayland_Graphics_Driver.H" -#include "Fl_Wayland_Screen_Driver.H" -#include "Fl_Wayland_Window_Driver.H" -#include <FL/Fl_Image_Surface.H> -#include <sys/mman.h> -#include <unistd.h> // for close() -#include <errno.h> -#include <string.h> // for strerror() -#include <cairo/cairo.h> - -extern "C" { -# include "../../../libdecor/src/os-compatibility.h" // for libdecor_os_create_anonymous_file() -} - -// used by create_shm_buffer and do_buffer_release -struct wl_shm_pool *Fl_Wayland_Graphics_Driver::current_pool = NULL; - - -static void do_buffer_release(struct Fl_Wayland_Graphics_Driver::wld_buffer *); - - -static void buffer_release_listener(void *user_data, struct wl_buffer *wl_buffer) -{ - struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = - (struct Fl_Wayland_Graphics_Driver::wld_buffer*)user_data; - buffer->in_use = false; - if (buffer->released) do_buffer_release(buffer); -} - - -static const struct wl_buffer_listener buffer_listener = { - buffer_release_listener -}; - - -void Fl_Wayland_Graphics_Driver::create_shm_buffer(Fl_Wayland_Graphics_Driver::wld_buffer *buffer) { - int width = buffer->draw_buffer.width; - int stride = buffer->draw_buffer.stride; - int height = buffer->draw_buffer.data_size / stride; - const size_t 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 = current_pool ? // data record attached to current pool - (struct wld_shm_pool_data *)wl_shm_pool_get_user_data(current_pool) : NULL; - size_t pool_size = current_pool ? pool_data->pool_size : default_pool_size; // current pool size - if (current_pool && !wl_list_empty(&pool_data->buffers)) { - // last wld_buffer created from current pool - struct wld_buffer *record = wl_container_of(pool_data->buffers.next, record, link); - chunk_offset = ((char*)record->data - pool_data->pool_memory) + - record->draw_buffer.data_size; - } - if (!current_pool || chunk_offset + buffer->draw_buffer.data_size > pool_size) { - // if true, a new pool is needed - if (current_pool && wl_list_empty(&pool_data->buffers)) { - wl_shm_pool_destroy(current_pool); - /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size); -// printf("create_shm_buffer munmap(%p)->%d\n", pool_data->pool_memory, err); - free(pool_data); - } - chunk_offset = 0; - pool_size = default_pool_size; - if (buffer->draw_buffer.data_size > pool_size) - pool_size = 2 * buffer->draw_buffer.data_size; // a larger pool is needed - int fd = libdecor_os_create_anonymous_file(pool_size); - if (fd < 0) { - Fl::fatal("libdecor_os_create_anonymous_file failed: %s\n", strerror(errno)); - } - 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(); - current_pool = wl_shm_create_pool(scr_driver->wl_shm, fd, (int32_t)pool_size); - close(fd); // does not prevent the mmap'ed memory from being used - //printf("wl_shm_create_pool %p size=%lu\n",pool_data->pool_memory , pool_size); - pool_data->pool_size = pool_size; - wl_list_init(&pool_data->buffers); - wl_shm_pool_set_user_data(current_pool, pool_data); - } - buffer->wl_buffer = wl_shm_pool_create_buffer(current_pool, chunk_offset, - width, height, stride, wld_format); - wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); - // add this buffer to head of list of current pool's buffers - wl_list_insert(&pool_data->buffers, &buffer->link); - buffer->shm_pool = current_pool; - buffer->data = (void*)(pool_data->pool_memory + chunk_offset); -//fprintf(stderr, "last=%p chunk_offset=%d ", pool_data->buffers.next, chunk_offset); -//fprintf(stderr, "create_shm_buffer: %dx%d = %d\n", width, height, size); -} - - -struct Fl_Wayland_Graphics_Driver::wld_buffer * - Fl_Wayland_Graphics_Driver::create_wld_buffer(int width, int height, bool with_shm) { - struct wld_buffer *buffer = (struct wld_buffer*)calloc(1, sizeof(struct wld_buffer)); - int stride = cairo_format_stride_for_width(cairo_format, width); - cairo_init(&buffer->draw_buffer, width, height, stride, cairo_format); - buffer->draw_buffer_needs_commit = true; - if (with_shm) create_shm_buffer(buffer); - return buffer; -} - - -// used to support both normal and progressive drawing and for top-level GL windows -static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { - struct wld_window *window = (struct wld_window *)data; - wl_callback_destroy(cb); - window->frame_cb = NULL; - if (window->buffer && window->buffer->draw_buffer_needs_commit) { - Fl_Wayland_Graphics_Driver::buffer_commit(window); - } -} - - -static const struct wl_callback_listener surface_frame_listener = { - .done = surface_frame_done, -}; - - -const struct wl_callback_listener *Fl_Wayland_Graphics_Driver::p_surface_frame_listener = - &surface_frame_listener; - - -// copy pixels in region r from the Cairo surface to the Wayland buffer -static void copy_region(struct wld_window *window, cairo_region_t *r) { - struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = window->buffer; - float f = Fl::screen_scale(window->fl_win->screen_num()); - int d = Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale(); - int count = cairo_region_num_rectangles(r); - cairo_rectangle_int_t rect; - for (int i = 0; i < count; i++) { - cairo_region_get_rectangle(r, i, &rect); - int left = d * int(rect.x * f); - int top = d * int(rect.y * f); - int right = d * ceil((rect.x + rect.width) * f); - if (right > d * int(window->fl_win->w() * f)) right = d * int(window->fl_win->w() * f); - int width = right - left; - int bottom = d * ceil((rect.y + rect.height) * f); - if (bottom > d * int(window->fl_win->h() * f)) bottom = d * int(window->fl_win->h() * f); - int height = bottom - top; - int offset = top * buffer->draw_buffer.stride + 4 * left; - int W4 = 4 * width; - for (int l = 0; l < height; l++) { - if (offset + W4 >= (int)buffer->draw_buffer.data_size) { - W4 = buffer->draw_buffer.data_size - offset; - if (W4 <= 0) break; - } - memcpy((uchar*)buffer->data + offset, buffer->draw_buffer.buffer + offset, W4); - offset += buffer->draw_buffer.stride; - } - wl_surface_damage_buffer(window->wl_surface, left, top, width, height); - } -} - - -void Fl_Wayland_Graphics_Driver::buffer_commit(struct wld_window *window, cairo_region_t *r) -{ - if (!window->buffer->wl_buffer) create_shm_buffer(window->buffer); - cairo_surface_t *surf = cairo_get_target(window->buffer->draw_buffer.cairo_); - cairo_surface_flush(surf); - if (r) copy_region(window, r); - else { - memcpy(window->buffer->data, window->buffer->draw_buffer.buffer, - window->buffer->draw_buffer.data_size); - wl_surface_damage_buffer(window->wl_surface, 0, 0, 1000000, 1000000); - } - window->buffer->in_use = true; - 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() ); - if (!window->covered) { // see issue #878 - window->frame_cb = wl_surface_frame(window->wl_surface); - wl_callback_add_listener(window->frame_cb, p_surface_frame_listener, window); - } - wl_surface_commit(window->wl_surface); - window->buffer->draw_buffer_needs_commit = false; -} - - -void Fl_Wayland_Graphics_Driver::cairo_init(struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer, - int width, int height, int stride, - cairo_format_t format) { - buffer->data_size = stride * height; - buffer->stride = stride; - buffer->buffer = new uchar[buffer->data_size]; - buffer->width = width; - cairo_surface_t *surf = cairo_image_surface_create_for_data(buffer->buffer, format, - width, height, stride); - if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) { - Fl::fatal("Can't create Cairo surface with cairo_image_surface_create_for_data()\n"); - return; - } - buffer->cairo_ = cairo_create(surf); - cairo_status_t err; - if ((err = cairo_status(buffer->cairo_)) != CAIRO_STATUS_SUCCESS) { - Fl::fatal("Cairo error during cairo_create() %s\n", cairo_status_to_string(err)); - return; - } - cairo_surface_destroy(surf); - memset(buffer->buffer, 0, buffer->data_size); // useful for transparent windows - cairo_set_source_rgba(buffer->cairo_, .0, .0, .0, 1.0); // Black default color - cairo_save(buffer->cairo_); -} - - -// runs when buffer->in_use is false and buffer->released is true -static void do_buffer_release(struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer) { - struct wl_shm_pool *my_pool = buffer->shm_pool; - if (buffer->wl_buffer) { - struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data *pool_data = - (struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data*) - wl_shm_pool_get_user_data(my_pool); - wl_buffer_destroy(buffer->wl_buffer); - // remove wld_buffer from list of pool's buffers - wl_list_remove(&buffer->link); - if (wl_list_empty(&pool_data->buffers) && my_pool != Fl_Wayland_Graphics_Driver::current_pool) { - // all buffers from pool are gone - wl_shm_pool_destroy(my_pool); - /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size); - //printf("do_buffer_release munmap(%p)->%d\n", pool_data->pool_memory, err); - free(pool_data); - } - } - free(buffer); -} - - -void Fl_Wayland_Graphics_Driver::buffer_release(struct wld_window *window) -{ - if (window->buffer && !window->buffer->released) { - window->buffer->released = true; - if (window->frame_cb) { wl_callback_destroy(window->frame_cb); window->frame_cb = NULL; } - delete[] window->buffer->draw_buffer.buffer; - window->buffer->draw_buffer.buffer = NULL; - cairo_destroy(window->buffer->draw_buffer.cairo_); - if (!window->buffer->in_use) do_buffer_release(window->buffer); - window->buffer = NULL; - } -} - - -// this refers to the same memory layout for pixel data as does CAIRO_FORMAT_ARGB32 -const uint32_t Fl_Wayland_Graphics_Driver::wld_format = WL_SHM_FORMAT_ARGB8888; - - -void Fl_Wayland_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, - Fl_Offscreen src, int srcx, int srcy) { - // draw portion srcx,srcy,w,h of osrc to position x,y (top-left) of - // the graphics driver's surface - cairo_matrix_t matrix; - cairo_get_matrix(cairo_, &matrix); - double s = matrix.xx; - cairo_save(cairo_); - cairo_rectangle(cairo_, x - 0.5, y - 0.5, w, h); - cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_NONE); - cairo_clip(cairo_); - cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_DEFAULT); - cairo_surface_t *surf = cairo_get_target((cairo_t *)src); - cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf); - cairo_set_source(cairo_, pat); - cairo_matrix_init_scale(&matrix, s, s); - cairo_matrix_translate(&matrix, -(x - srcx), -(y - srcy)); - cairo_pattern_set_matrix(pat, &matrix); - cairo_paint(cairo_); - cairo_pattern_destroy(pat); - cairo_restore(cairo_); - surface_needs_commit(); -} - - -const cairo_user_data_key_t Fl_Wayland_Graphics_Driver::key = {}; - - -struct Fl_Wayland_Graphics_Driver::draw_buffer* -Fl_Wayland_Graphics_Driver::offscreen_buffer(Fl_Offscreen offscreen) { - return (struct draw_buffer*)cairo_get_user_data((cairo_t*)offscreen, &key); -} - - -Fl_Image_Surface *Fl_Wayland_Graphics_Driver::custom_offscreen(int w, int h, - struct Fl_Wayland_Graphics_Driver::wld_buffer **p_off) { - struct wld_buffer *off = create_wld_buffer(w, h); - *p_off = off; - cairo_set_user_data(off->draw_buffer.cairo_, &key, &off->draw_buffer, NULL); - return new Fl_Image_Surface(w, h, 0, (Fl_Offscreen)off->draw_buffer.cairo_); -} - - -void Fl_Wayland_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height) { - Fl_Graphics_Driver::cache_size(img, width, height); - width *= wld_scale; - height *= wld_scale; -} |
