Improve re-use of client/compositor shared memory by Wayland buffers
This commit is contained in:
parent
5dfa51a820
commit
5be3fbf913
@ -486,6 +486,12 @@ Each of these two objects encapsulates a byte array of the same size and the sam
|
||||
destined to contain the Fl_Window's graphics. The Cairo surface object is where FLTK draws.
|
||||
The Wayland buffer is what Wayland maps on the display. FLTK copies the Cairo surface's byte array
|
||||
to the Wayland buffer's byte array before beginning the mapping operation.
|
||||
If \c width and \c height are a window's dimensions in pixels,
|
||||
\code
|
||||
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
|
||||
int size = stride * height;
|
||||
\endcode
|
||||
give \c size, the common size of both byte arrays.
|
||||
|
||||
Section \ref wayland-buffer-factory below details how FLTK creates \c wl_buffer objects.
|
||||
|
||||
@ -552,75 +558,72 @@ Wayland names <em>buffer factory</em> a software procedure that constructs objec
|
||||
<tt>struct wl_buffer</tt> for use by a client application.
|
||||
FLTK creates a \c wl_buffer object each time an Fl_Window is mapped on a display or resized.
|
||||
That's done by member function \c Fl_Wayland_Graphics_Driver::create_shm_buffer()
|
||||
which follows this 3-step procedure to create a "buffer factory" for FLTK and construct
|
||||
which follows this 3-step procedure to create a "buffer factory" for FLTK and to construct
|
||||
Wayland buffers from it:
|
||||
- Libdecor function <tt>os_create_anonymous_file(off_t size)</tt> creates an adequate file and mmap's
|
||||
it. This file lives in RAM because it is created by function \c memfd_create().
|
||||
FLTK initially sets this file size to \c pool_size = 10 MB. This size will be increased when and
|
||||
if necessary.
|
||||
FLTK stores in variable \c pool_memory the address of the beginning of the mmap'ed memory structure.
|
||||
- Libdecor function <tt>os_create_anonymous_file(off_t size)</tt> creates an adequate file
|
||||
and mmap's it. This file lives in RAM because it is created by function \c memfd_create().
|
||||
FLTK sets this file size to 10 MB unless the size of the buffer to be created
|
||||
is larger; in that case the anonymous file is sized to twice the buffer size.
|
||||
- Wayland function \c wl_shm_create_pool() shares this mmap'ed memory with the
|
||||
Wayland compositor and returns an object of type <tt>struct wl_shm_pool</tt> which encapsulates
|
||||
this memory. FLTK initializes
|
||||
to 0 a variable called \c chunk_offset that represents the offset inside the mmap'ed memory available
|
||||
for further \c wl_buffer objects.
|
||||
- Wayland function \c wl_shm_pool_create_buffer() creates from the \c wl_shm_pool object a
|
||||
\c wl_buffer object which encapsulates a section of a given size of the shared memory structure
|
||||
beginning at offset \c chunk_offset in it. This function returns a pointer to the resulting
|
||||
\c wl_buffer object. Quantity <tt>pool_memory + chunk_offset</tt> is therefore the address of the
|
||||
Wayland compositor and returns an object of type <tt>struct wl_shm_pool</tt> which
|
||||
encapsulates this memory. A record of type
|
||||
<tt>struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data</tt> is created and associated to
|
||||
the newly created \c wl_shm_pool by \c wl_shm_pool_set_user_data(). This record stores
|
||||
the starting address (\c pool_memory) and size (\c pool_size) of the pool's encapsulated
|
||||
memory. The record also contains member \c buffers of type <tt>struct wl_list</tt> which
|
||||
stores the access point to the linked list of \c wl_buffer objects that will be created from
|
||||
the \c wl_shm_pool.
|
||||
- A variable named \c chunk_offset represents the offset within the pool's shared
|
||||
memory available for the buffer being constructed. It equals 0 when the pool has just been
|
||||
created and is updated as detailed below when one or more buffers have been previously created
|
||||
from the pool. A record of type <tt>struct fl_wld_buffer</tt> is created. This record will
|
||||
contain (member \c wl_buffer) the address of a \c wl_buffer object that's created by function
|
||||
\c wl_shm_pool_create_buffer(). This \c wl_buffer object encapsulates a section of a given
|
||||
size of the pool's shared memory beginning at offset \c chunk_offset in it.
|
||||
Quantity <tt>pool_memory + chunk_offset</tt> is therefore the address of the
|
||||
beginning of the mmap'ed memory section encapsulated by this \c wl_buffer.
|
||||
Variable \c chunk_offset is then increased by the length of this section.
|
||||
|
||||
A window's \c wl_buffer is re-used each time the window gets redrawn, and is destroyed by function
|
||||
\c Fl_Wayland_Graphics_Driver::buffer_release() which calls \c wl_buffer_destroy() when
|
||||
\c Fl_Window::hide() runs or the window is resized.
|
||||
|
||||
If \c width and \c height are a window's dimensions in pixels,
|
||||
Member \c shm_pool of the newly constructed \c fl_wld_buffer object is set to the address of
|
||||
the current \c wl_shm_pool object. This record is added to the head of the linked list of
|
||||
current pool's buffers by a call to \c wl_list_insert().
|
||||
At that point, a <tt>struct fl_wld_buffer</tt> record is part of the linked list of all
|
||||
such records corresponding to \c wl_buffer objects created from the same \c wl_shm_pool
|
||||
object, and member \c shm_pool of this record gives the address of this \c wl_shm_pool.
|
||||
When a new <tt>struct fl_wld_buffer</tt> record is to be created,
|
||||
\code
|
||||
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
|
||||
int size = stride * height;
|
||||
struct wld_shm_pool_data *pool_data =
|
||||
(struct wld_shm_pool_data *)wl_shm_pool_get_user_data(pool);
|
||||
struct fl_wld_buffer *record = wl_container_of(pool_data->buffers.next, record, link);
|
||||
int chunk_offset = ((char*)record->data - pool_data->pool_memory) + record->data_size;
|
||||
\endcode
|
||||
give \c size, the size in bytes of a memory buffer needed to store the window's graphics.
|
||||
If <tt>chunk_offset + size > pool_size</tt> holds when function \c create_shm_buffer() attempts to
|
||||
create a new \c wl_buffer object, \c chunk_offset is reset to 0,
|
||||
function \c wl_shm_pool_destroy() is called to destroy
|
||||
the current \c wl_shm_pool object, and a new \c wl_shm_pool object is created and used by FLTK's
|
||||
"buffer factory". If <tt>size > pool_size</tt> holds at that step, the value of \c pool_size
|
||||
is increased to <tt>2 * size</tt>. This mechanism allows to access new mmap'ed memory when
|
||||
\c chunk_offset reaches the end of the previous mmap'ed section, and to enlarge the size of the
|
||||
mmap'ed memory when necessary.
|
||||
gives the offset within the current pool's mmap'ed memory available for a new \c wl_buffer.
|
||||
Macro \c wl_container_of() gives the address of a record belonging to a linked list of
|
||||
records of the same type.
|
||||
|
||||
To free the memory used by a \c wl_shm_pool object, it's not enough to destroy
|
||||
all \c wl_buffer objects built from this \c wl_shm_pool object and to call
|
||||
\c wl_shm_pool_destroy(). It's also necessary to call \c munmap() on the mmap'ed memory
|
||||
shared between the client and the compositor and encapsulated by the \c wl_shm_pool.
|
||||
This explains this type definition inside class \c Fl_Wayland_Graphics_Driver:
|
||||
\code
|
||||
struct wld_shm_pool_data { // attached to wl_shm_pool objects
|
||||
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
|
||||
};
|
||||
\endcode
|
||||
A record of this type is created for each \c wl_shm_pool object and attached to it with
|
||||
a call to \c wl_shm_pool_set_user_data(). This record contains the starting address
|
||||
and the size of the mmap'ed memory section necessary for a future \c munmap() call.
|
||||
Member \c destroyed is turned to \c true after the call to \c wl_shm_pool_destroy().
|
||||
Member \c use_count starts at 0, is incremented each time a \c wl_buffer is created from
|
||||
this \c wl_shm_pool and decremented each time a \c wl_buffer is destroyed.
|
||||
The same record is also associated to each \c wl_buffer object created from
|
||||
this \c wl_shm_pool by \c wl_buffer_set_user_data().
|
||||
Overall, this allows FLTK to detect when all \c wl_buffer objects
|
||||
from a \c wl_shm_pool have been destroyed and to call \c munmap() to complete the release
|
||||
of that pool's memory resources.
|
||||
A window's \c wl_buffer is re-used each time the window gets redrawn, and is destroyed by
|
||||
function \c Fl_Wayland_Graphics_Driver::buffer_release() when \c Fl_Window::hide() runs or
|
||||
the window is resized. Function \c Fl_Wayland_Graphics_Driver::buffer_release() destroys the
|
||||
\c wl_buffer with \c wl_buffer_destroy() and removes the corresponding
|
||||
\c fl_wld_buffer record from the linked list of buffers from the same \c wl_shm_pool.
|
||||
Since new \c fl_wld_buffer records are added at the head of the linked list, and since
|
||||
the record at the head of this list is used to compute the offset within the pool's mmap'ed
|
||||
memory available for a new \c wl_buffer, destruction of the last created \c wl_buffer
|
||||
allows to re-use the destroyed buffer's pool's memory for a new \c wl_buffer.
|
||||
When the linked list results empty, the \c wl_shm_pool is destroyed by
|
||||
\c wl_shm_pool_destroy(), the pool's mmap'ed memory is munmap'ed, and the pool's associated
|
||||
<tt>struct wld_shm_pool_data</tt> is freed.
|
||||
|
||||
Wayland uses also \c wl_buffer objects to support cursors, and
|
||||
FLTK uses the "buffer factory" described here also when creating custom cursors (see
|
||||
\ref custom-cursor) with
|
||||
function <tt>Fl_Wayland_Window_Driver::set_cursor(const Fl_RGB_Image *,…)</tt> because
|
||||
\c create_shm_buffer() runs as well. In contrast, standard shaped-cursors (e.g., FL_CURSOR_INSERT)
|
||||
use their own "buffer factory" inside Wayland functions such as \c wl_cursor_theme_get_cursor().
|
||||
If the sum of \c chunk_offset plus the buffer size is larger than the current pool's size
|
||||
when function \c create_shm_buffer() is called, \c chunk_offset is reset
|
||||
to 0, and a new \c wl_shm_pool object is created and used by FLTK's "buffer factory".
|
||||
This mechanism allows to access new mmap'ed memory when \c chunk_offset reaches the end of
|
||||
the previous mmap'ed section.
|
||||
|
||||
Wayland uses also \c wl_buffer objects to support cursors. FLTK uses the "buffer factory"
|
||||
described here when creating custom cursors (see \ref custom-cursor) with
|
||||
function <tt>Fl_Wayland_Window_Driver::set_cursor(const Fl_RGB_Image *,…)</tt> which calls
|
||||
\c create_shm_buffer(). In contrast, standard shaped-cursors (e.g., FL_CURSOR_INSERT)
|
||||
use their own "buffer factory" inside Wayland functions such as
|
||||
\c wl_cursor_theme_get_cursor().
|
||||
Therefore, the fact that the \c wl_buffer objects behind standard cursors are never destroyed
|
||||
doesn't prevent disused <tt>struct wl_shm_pool</tt> objects from being freed because those
|
||||
buffers come from a distinct "buffer factory".
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user