-----BEGIN PGP SIGNATURE-----
 
 iQJOBAABCAA4FiEEcDKHej6x6uPk3J379jQS5glH1u8FAmTKgNAaHG1hcml1cy52
 bGFkQGNvbGxhYm9yYS5jb20ACgkQ9jQS5glH1u82JQ//f/n92pDChk/LMmGxN2iW
 1KYsB42vn6Fz0JNYue9HElnWNQzp1ZFYLBJFiks8fHx2kD7ppMRN7vgRrTS/hZjV
 qEUJI5OX5+U7My0q10OWJGXEYOPLM2vQOnjca4CDivvl66MebBYYI+h72/lo8oBe
 IojZY0BSNbI2wikAG3UTMoU4z3PwBj+ipn856AslXBf0a1cqzl2JFNX5l1B5DAwe
 E0XZ0KSu74sL8ObyqoW1kYLm9Cqid2iLbch9pBvDIqBlg7V2jySHVB2fvkfwHTxw
 Q4dl2NpeW5kKqj8Ql27nLEMG4g3hrAJq+dnNIWijSzO1a7M3BC2ZQ3YEWCaISmwN
 7rRFTXgAKIkn0YfXwBp5XG12oCNgyBhaCc8dUrefPZqyOiYRii2f4xYTM5TXhHv9
 fVvBj7iXigz3+iUkBe4aRVGVBJaKW6y7UkwMP4vhowyxpcb3XXHNszTEnfj7JiIs
 0xq8iA8KM9v2uYKpkLG6ND0IUmwiuZtGNKCIcaYd9Yr7vI0CohIZ7ZsI8YKYmSgK
 ONyAHDDzREDNcxuY4NBIqb0yr058yMhr3LuNJHaM6QCue+QOxjq4qJIpJ5sN/hgr
 GT6dbH6Rf/Pfld+/5Kdw9sdhSwQzPy8NxILRjF27GMRvZsnd7+5ZIA2eVvl5mfLw
 SegOoQASY1fY4ML0eaD5SIE=
 =VGPl
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEofGjA2bfgEEMn0uvXN7tFPSPp50FAmaabRUACgkQXN7tFPSP
 p5202xAAzEO1OrhT/UkyMLnIdY5OrPXAWtlx7fbOjQJpZ1bsRnuDg6Iae0WEr2go
 lkzrrkbO99sWFTqb+LmDf2AzPy2y6OQojrWSeyDC5m/woZPHehJwrdmG4oISQuwQ
 j70TPz0iKjNLjUeprD/bIOpEUbyjRLasltXoUv7wna39mY/4lDraaYZe8QRIdrTy
 oWqYj8Dnu2BR0IPawX1249v34nLY8ZG/v3MNn6TIlflZCQOYZ0+tQxLa2K+Bl18x
 yqAbvcw24TtrmJI8XWEz12bTuKzQu8EJXx0g/x7uQCkCdFRFYJMivt0l7mEjlERy
 mPqarpHaSdaS64fnxlRP0dmO7/LBNS/1QPxiGXOoUGUdDwLhhv57BQuUnSRsiCzi
 w1GgHKscqT48hsJNqj/+6r6jTavA2fs8YDWDkACYGso0dHnkVFma7rSH5pXf1LFv
 +jI2TlcP9BqAEtVXes7l0voryczQxKJijcaky7bwyIUKX2MK8oZjLdmFwpXi2CIR
 9Sd0SjQxOOMaguzCWZchanShSGwjjbo9zJEqepAn4P186yhwIdRaH0fAORRBfho/
 h8qBlZ+2aUN9rvxzfSGRCgz3MIEE9cQu0Pd0OQStZ2CedpZOr7vLEZ68CyvrvYV8
 8GCCVrmEdOT/3+dgMx4tMtAYfXUve4hKuOPuh5f9BxmiuaplWx8=
 =N3tk
 -----END PGP SIGNATURE-----

Merge tag '10.0.5' into backport-wl-shell

10.0.5

# -----BEGIN PGP SIGNATURE-----
#
# iQJOBAABCAA4FiEEcDKHej6x6uPk3J379jQS5glH1u8FAmTKgNAaHG1hcml1cy52
# bGFkQGNvbGxhYm9yYS5jb20ACgkQ9jQS5glH1u82JQ//f/n92pDChk/LMmGxN2iW
# 1KYsB42vn6Fz0JNYue9HElnWNQzp1ZFYLBJFiks8fHx2kD7ppMRN7vgRrTS/hZjV
# qEUJI5OX5+U7My0q10OWJGXEYOPLM2vQOnjca4CDivvl66MebBYYI+h72/lo8oBe
# IojZY0BSNbI2wikAG3UTMoU4z3PwBj+ipn856AslXBf0a1cqzl2JFNX5l1B5DAwe
# E0XZ0KSu74sL8ObyqoW1kYLm9Cqid2iLbch9pBvDIqBlg7V2jySHVB2fvkfwHTxw
# Q4dl2NpeW5kKqj8Ql27nLEMG4g3hrAJq+dnNIWijSzO1a7M3BC2ZQ3YEWCaISmwN
# 7rRFTXgAKIkn0YfXwBp5XG12oCNgyBhaCc8dUrefPZqyOiYRii2f4xYTM5TXhHv9
# fVvBj7iXigz3+iUkBe4aRVGVBJaKW6y7UkwMP4vhowyxpcb3XXHNszTEnfj7JiIs
# 0xq8iA8KM9v2uYKpkLG6ND0IUmwiuZtGNKCIcaYd9Yr7vI0CohIZ7ZsI8YKYmSgK
# ONyAHDDzREDNcxuY4NBIqb0yr058yMhr3LuNJHaM6QCue+QOxjq4qJIpJ5sN/hgr
# GT6dbH6Rf/Pfld+/5Kdw9sdhSwQzPy8NxILRjF27GMRvZsnd7+5ZIA2eVvl5mfLw
# SegOoQASY1fY4ML0eaD5SIE=
# =VGPl
# -----END PGP SIGNATURE-----
Nikita Tokarchuk 2 months ago
commit cf3c9c5182
  1. 4
      .gitlab-ci.yml
  2. 2
      clients/simple-dmabuf-egl.c
  3. 131
      clients/simple-dmabuf-feedback.c
  4. 2
      clients/simple-dmabuf-v4l.c
  5. 65
      clients/simple-egl.c
  6. 76
      clients/window.c
  7. 105
      desktop-shell/shell.c
  8. 3
      include/libweston/libweston.h
  9. 45
      kiosk-shell/kiosk-shell.c
  10. 2
      kiosk-shell/kiosk-shell.h
  11. 2
      libweston-desktop/xdg-shell.c
  12. 1
      libweston/backend-drm/drm-internal.h
  13. 6
      libweston/backend-drm/fb.c
  14. 2
      libweston/backend-drm/meson.build
  15. 3
      libweston/backend-drm/state-propose.c
  16. 80
      libweston/compositor.c
  17. 24
      libweston/input.c
  18. 67
      libweston/linux-dmabuf.c
  19. 43
      libweston/renderer-gl/fragment.glsl
  20. 4
      meson.build
  21. 2
      tests/devices-test.c
  22. 2
      tests/ivi-layout-test-plugin.c
  23. BIN
      tests/reference/subsurface_empty_mapping-00.png
  24. BIN
      tests/reference/subsurface_empty_mapping-01.png
  25. BIN
      tests/reference/subsurface_sync_damage_buffer-00.png
  26. BIN
      tests/reference/subsurface_sync_damage_buffer-01.png
  27. BIN
      tests/reference/subsurface_sync_damage_buffer-02.png
  28. 198
      tests/subsurface-shot-test.c

@ -296,7 +296,9 @@ x86_64-debian-full-build:
- .build-options-full
artifacts:
reports:
cobertura: $BUILDDIR/meson-logs/coverage.xml
coverage_report:
coverage_format: cobertura
path: $BUILDDIR/meson-logs/coverage.xml
aarch64-debian-full-build:
extends:

@ -131,7 +131,7 @@ struct buffer {
int release_fence_fd;
};
#define NUM_BUFFERS 3
#define NUM_BUFFERS 4
struct window {
struct display *display;

@ -26,11 +26,13 @@
#include "config.h"
#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <libudev.h>
#include <sys/mman.h>
#include <time.h>
#include "shared/helpers.h"
#include "shared/platform.h"
@ -47,7 +49,7 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#define NUM_BUFFERS 3
#define NUM_BUFFERS 4
/* We have to hack the DRM-backend to pretend that planes of the underlying
* hardware don't support this format. If you change the value of this constant,
@ -140,7 +142,11 @@ struct display {
struct buffer {
struct window *window;
struct wl_buffer *buffer;
bool busy;
enum {
NOT_CREATED,
IN_USE,
AVAILABLE
} status;
bool recreate;
int dmabuf_fds[4];
struct gbm_bo *bo;
@ -469,7 +475,7 @@ buffer_release(void *data, struct wl_buffer *buffer)
{
struct buffer *buf = data;
buf->busy = false;
buf->status = AVAILABLE;
if (buf->recreate)
buffer_recreate(buf);
@ -485,6 +491,7 @@ create_succeeded(void *data, struct zwp_linux_buffer_params_v1 *params,
{
struct buffer *buf = data;
buf->status = AVAILABLE;
buf->buffer = new_buffer;
wl_buffer_add_listener(buf->buffer, &buffer_listener, buf);
zwp_linux_buffer_params_v1_destroy(params);
@ -516,6 +523,7 @@ create_dmabuf_buffer(struct window *window, struct buffer *buf, uint32_t width,
struct zwp_linux_buffer_params_v1 *params;
int i;
buf->status = NOT_CREATED;
buf->window = window;
buf->width = width;
buf->height = height;
@ -573,8 +581,22 @@ window_next_buffer(struct window *window)
unsigned int i;
for (i = 0; i < NUM_BUFFERS; i++)
if (!window->buffers[i].busy)
if (window->buffers[i].status == AVAILABLE)
return &window->buffers[i];
/* In this client, we sometimes have to recreate the buffers. As we are
* not using the create_immed request from zwp_linux_dmabuf_v1, we need
* to wait an event from the server (what leads to create_succeeded()
* being called in this client). So if all buffers are busy, it may be
* the case in which all the buffers were recreated but the server still
* didn't send the events. This is very unlikely to happen, but a
* roundtrip() guarantees that we receive and process the events. */
wl_display_roundtrip(window->display->display);
for (i = 0; i < NUM_BUFFERS; i++)
if (window->buffers[i].status == AVAILABLE)
return &window->buffers[i];
return NULL;
}
@ -639,15 +661,13 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
window->callback = wl_surface_frame(window->surface);
wl_callback_add_listener(window->callback, &frame_listener, window);
wl_surface_commit(window->surface);
buf->busy = true;
buf->status = IN_USE;
region = wl_compositor_create_region(window->display->compositor);
wl_region_add(region, 0, 0, window->display->output.width,
window->display->output.height);
wl_surface_set_opaque_region(window->surface, region);
wl_region_destroy(region);
window->n_redraws++;
}
static const struct wl_callback_listener frame_listener = {
@ -1050,18 +1070,54 @@ dmabuf_feedback_tranche_formats(void *data,
}
}
static char
bits2graph(uint32_t value, unsigned bitoffset)
{
int c = (value >> bitoffset) & 0xff;
if (isgraph(c) || isspace(c))
return c;
return '?';
}
static void
fourcc2str(uint32_t format, char *str, int len)
{
int i;
assert(len >= 5);
for (i = 0; i < 4; i++)
str[i] = bits2graph(format, i * 8);
str[i] = '\0';
}
static void
print_tranche_format_modifier(uint32_t format, uint64_t modifier)
{
const struct pixel_format_info *fmt_info;
char *format_str;
char *mod_name;
int len;
fmt_info = pixel_format_get_info(format);
mod_name = pixel_format_get_modifier(modifier);
fmt_info = pixel_format_get_info(format);
if (fmt_info) {
len = asprintf(&format_str, "%s", fmt_info->drm_format_name);
} else {
char fourcc_str[5];
fourcc2str(format, fourcc_str, sizeof(fourcc_str));
len = asprintf(&format_str, "0x%08x (%s)", format, fourcc_str);
}
assert(len > 0);
fprintf(stderr, "│ ├────────tranche format/modifier pair - format %s, modifier %s\n",
fmt_info ? fmt_info->drm_format_name : "UNKNOWN", mod_name);
format_str, mod_name);
free(format_str);
free(mod_name);
}
@ -1103,7 +1159,7 @@ dmabuf_feedback_tranche_done(void *data,
dmabuf_feedback_tranche_init(&feedback->pending_tranche);
}
static void
static bool
pick_initial_format_from_renderer_tranche(struct window *window,
struct dmabuf_feedback_tranche *tranche)
{
@ -1117,13 +1173,12 @@ pick_initial_format_from_renderer_tranche(struct window *window,
window->format.format = fmt->format;
wl_array_copy(&window->format.modifiers, &fmt->modifiers);
return;
return true;
}
assert(0 && "error: INITIAL_BUFFER_FORMAT not supported by the hardware");
return false;
}
static void
static bool
pick_format_from_scanout_tranche(struct window *window,
struct dmabuf_feedback_tranche *tranche)
{
@ -1132,8 +1187,9 @@ pick_format_from_scanout_tranche(struct window *window,
wl_array_for_each(fmt, &tranche->formats.arr) {
/* Ignore format that we're already using. */
if (fmt->format == window->format.format)
/* Ignore the format that we want to pick from the render
* tranche. */
if (fmt->format == INITIAL_BUFFER_FORMAT)
continue;
/* Format should be supported by the compositor. */
@ -1147,10 +1203,9 @@ pick_format_from_scanout_tranche(struct window *window,
window->format.format = fmt->format;
wl_array_copy(&window->format.modifiers, &fmt->modifiers);
return;
return true;
}
assert(0 && "error: no valid pair of format/modifier in the scanout tranche");
return false;
}
static void
@ -1158,25 +1213,37 @@ dmabuf_feedback_done(void *data, struct zwp_linux_dmabuf_feedback_v1 *dmabuf_fee
{
struct window *window = data;
struct dmabuf_feedback_tranche *tranche;
bool got_scanout_tranche = false;
unsigned int i;
fprintf(stderr, "└end of dma-buf feedback\n\n");
/* The first time that we receive dma-buf feedback for a surface it
* contains only the renderer tranche. We pick the INITIAL_BUFFER_FORMAT
* contains only the renderer tranches. We pick the INITIAL_BUFFER_FORMAT
* from there. Then the compositor should detect that the format is
* unsupported by the underlying hardware (not actually, but you should
* have faked this in the DRM-backend) and send the scanout tranche. We
* use the formats/modifiers of the scanout tranche to reallocate our
* have faked this in the DRM-backend) and send the scanout tranches. We
* use the formats/modifiers of the scanout tranches to reallocate our
* buffers. */
wl_array_for_each(tranche, &window->pending_dmabuf_feedback.tranches) {
if (tranche->is_scanout_tranche) {
pick_format_from_scanout_tranche(window, tranche);
for (i = 0; i < NUM_BUFFERS; i++)
window->buffers[i].recreate = true;
break;
got_scanout_tranche = true;
if (pick_format_from_scanout_tranche(window, tranche)) {
for (i = 0; i < NUM_BUFFERS; i++)
window->buffers[i].recreate = true;
break;
}
}
pick_initial_format_from_renderer_tranche(window, tranche);
if (pick_initial_format_from_renderer_tranche(window, tranche))
break;
}
if (got_scanout_tranche) {
assert(window->format.format != INITIAL_BUFFER_FORMAT &&
"error: no valid pair of format/modifier in the scanout tranches");
} else {
assert(window->format.format == INITIAL_BUFFER_FORMAT &&
"error: INITIAL_BUFFER_FORMAT not supported by the hardware");
}
dmabuf_feedback_fini(&window->dmabuf_feedback);
@ -1383,6 +1450,9 @@ main(int argc, char **argv)
struct display *display;
struct window *window;
int ret = 0;
struct timespec start_time, current_time;
const time_t MAX_TIME_SECONDS = 3;
time_t delta_time = 0;
fprintf(stderr, "This client was written with the purpose of manually test " \
"Weston's dma-buf feedback implementation. See main() " \
@ -1391,9 +1461,14 @@ main(int argc, char **argv)
display = create_display();
window = create_window(display);
clock_gettime(CLOCK_MONOTONIC, &start_time);
redraw(window, NULL, 0);
while (ret != -1 && window->n_redraws < 200)
while (ret != -1 && delta_time < MAX_TIME_SECONDS) {
ret = wl_display_dispatch(display->display);
clock_gettime(CLOCK_MONOTONIC, &current_time);
delta_time = current_time.tv_sec - start_time.tv_sec;
}
destroy_window(window);
destroy_display(display);

@ -127,7 +127,7 @@ struct buffer {
int data_offsets[VIDEO_MAX_PLANES];
};
#define NUM_BUFFERS 3
#define NUM_BUFFERS 4
struct window {
struct display *display;

@ -262,6 +262,19 @@ init_gl(struct window *window)
GLuint frag, vert;
GLuint program;
GLint status;
EGLBoolean ret;
window->native = wl_egl_window_create(window->surface,
window->geometry.width,
window->geometry.height);
window->egl_surface =
weston_platform_create_egl_surface(window->display->egl.dpy,
window->display->egl.conf,
window->native, NULL);
ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
window->egl_surface, window->display->egl.ctx);
assert(ret == EGL_TRUE);
frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
@ -362,19 +375,9 @@ static void
create_surface(struct window *window)
{
struct display *display = window->display;
EGLBoolean ret;
window->surface = wl_compositor_create_surface(display->compositor);
window->native =
wl_egl_window_create(window->surface,
window->geometry.width,
window->geometry.height);
window->egl_surface =
weston_platform_create_egl_surface(display->egl.dpy,
display->egl.conf,
window->native, NULL);
window->xdg_surface = xdg_wm_base_get_xdg_surface(display->wm_base,
window->surface);
xdg_surface_add_listener(window->xdg_surface,
@ -389,21 +392,16 @@ create_surface(struct window *window)
xdg_toplevel_set_app_id(window->xdg_toplevel,
"org.freedesktop.weston.simple-egl");
if (window->fullscreen)
xdg_toplevel_set_fullscreen(window->xdg_toplevel, NULL);
else if (window->maximized)
xdg_toplevel_set_maximized(window->xdg_toplevel);
window->wait_for_configure = true;
wl_surface_commit(window->surface);
ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
window->egl_surface, window->display->egl.ctx);
assert(ret == EGL_TRUE);
if (!window->frame_sync)
eglSwapInterval(display->egl.dpy, 0);
if (!display->wm_base)
return;
if (window->fullscreen)
xdg_toplevel_set_fullscreen(window->xdg_toplevel, NULL);
}
static void
@ -806,6 +804,7 @@ usage(int error_code)
fprintf(stderr, "Usage: simple-egl [OPTIONS]\n\n"
" -d <us>\tBuffer swap delay in microseconds\n"
" -f\tRun in fullscreen mode\n"
" -m\tRun in maximized mode\n"
" -o\tCreate an opaque surface\n"
" -s\tUse a 16 bpp EGL config\n"
" -b\tDon't sync to compositor redraw (eglSwapInterval 0)\n"
@ -836,6 +835,8 @@ main(int argc, char **argv)
window.delay = atoi(argv[++i]);
else if (strcmp("-f", argv[i]) == 0)
window.fullscreen = 1;
else if (strcmp("-m", argv[i]) == 0)
window.maximized = 1;
else if (strcmp("-o", argv[i]) == 0)
window.opaque = 1;
else if (strcmp("-s", argv[i]) == 0)
@ -864,7 +865,17 @@ main(int argc, char **argv)
init_egl(&display, &window);
create_surface(&window);
init_gl(&window);
/* we already have wait_for_configure set after create_surface() */
while (running && ret != -1 && window.wait_for_configure) {
ret = wl_display_dispatch(display.display);
/* wait until xdg_surface::configure acks the new dimensions */
if (window.wait_for_configure)
continue;
init_gl(&window);
}
display.cursor_surface =
wl_compositor_create_surface(display.compositor);
@ -874,17 +885,9 @@ main(int argc, char **argv)
sigint.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &sigint, NULL);
/* The mainloop here is a little subtle. Redrawing will cause
* EGL to read events so we can just call
* wl_display_dispatch_pending() to handle any events that got
* queued up as a side effect. */
while (running && ret != -1) {
if (window.wait_for_configure) {
ret = wl_display_dispatch(display.display);
} else {
ret = wl_display_dispatch_pending(display.display);
redraw(&window, NULL, 0);
}
ret = wl_display_dispatch_pending(display.display);
redraw(&window, NULL, 0);
}
fprintf(stderr, "simple-egl exiting\n");

@ -352,8 +352,11 @@ struct input {
struct toytimer cursor_timer;
bool cursor_timer_running;
struct wl_surface *pointer_surface;
bool pointer_surface_has_role;
int hotspot_x, hotspot_y;
uint32_t modifiers;
uint32_t pointer_enter_serial;
uint32_t cursor_serial;
float sx, sy;
struct wl_list link;
@ -2748,12 +2751,6 @@ input_remove_pointer_focus(struct input *input)
input->pointer_focus = NULL;
input->current_cursor = CURSOR_UNSET;
cancel_pointer_image_update(input);
wl_surface_destroy(input->pointer_surface);
input->pointer_surface = NULL;
if (input->cursor_frame_cb) {
wl_callback_destroy(input->cursor_frame_cb);
input->cursor_frame_cb = NULL;
}
}
static void
@ -2782,6 +2779,16 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
input->pointer_enter_serial = serial;
input->pointer_focus = window;
/* Some compositors advertise wl_seat before wl_compositor. This
* makes it potentially impossible to create the pointer surface
* when we bind the seat, so we need to create our pointer surface
* now instead.
*/
if (!input->pointer_surface)
input->pointer_surface = wl_compositor_create_surface(input->display->compositor);
input->pointer_surface_has_role = false;
input->sx = sx;
input->sy = sy;
@ -3793,8 +3800,7 @@ input_set_pointer_image_index(struct input *input, int index)
struct wl_buffer *buffer;
struct wl_cursor *cursor;
struct wl_cursor_image *image;
struct wl_surface *prev_surface;
struct display *d = input->display;
int dx = 0, dy = 0;
if (!input->pointer)
return;
@ -3813,21 +3819,24 @@ input_set_pointer_image_index(struct input *input, int index)
if (!buffer)
return;
/* Don't re-use the previous surface, otherwise the new buffer and the
* new hotspot aren't applied atomically. */
prev_surface = input->pointer_surface;
input->pointer_surface = wl_compositor_create_surface(d->compositor);
wl_surface_attach(input->pointer_surface, buffer, 0, 0);
if (input->pointer_surface_has_role) {
dx = input->hotspot_x - image->hotspot_x;
dy = input->hotspot_y - image->hotspot_y;
}
wl_surface_attach(input->pointer_surface, buffer, dx, dy);
wl_surface_damage(input->pointer_surface, 0, 0,
image->width, image->height);
wl_surface_commit(input->pointer_surface);
wl_pointer_set_cursor(input->pointer, input->pointer_enter_serial,
input->pointer_surface,
image->hotspot_x, image->hotspot_y);
if (prev_surface)
wl_surface_destroy(prev_surface);
if (!input->pointer_surface_has_role) {
wl_pointer_set_cursor(input->pointer,
input->pointer_enter_serial,
input->pointer_surface,
image->hotspot_x, image->hotspot_y);
input->pointer_surface_has_role = true;
}
input->hotspot_x = image->hotspot_x;
input->hotspot_y = image->hotspot_y;
}
static const struct wl_callback_listener pointer_surface_listener;
@ -3839,11 +3848,14 @@ input_set_pointer_special(struct input *input)
wl_pointer_set_cursor(input->pointer,
input->pointer_enter_serial,
NULL, 0, 0);
input->pointer_surface_has_role = false;
return true;
}
if (input->current_cursor == CURSOR_UNSET)
if (input->current_cursor == CURSOR_UNSET) {
input->pointer_surface_has_role = false;
return true;
}
return false;
}
@ -3883,7 +3895,6 @@ schedule_pointer_image_update(struct input *input,
wl_callback_add_listener(input->cursor_frame_cb,
&pointer_surface_listener, input);
wl_surface_commit(input->pointer_surface);
}
static void
@ -3933,11 +3944,11 @@ pointer_surface_frame_callback(void *data, struct wl_callback *callback,
time - input->cursor_anim_start,
&duration);
input_set_pointer_image_index(input, i);
if (cursor->image_count > 1)
schedule_pointer_image_update(input, cursor, duration,
force_frame);
input_set_pointer_image_index(input, i);
}
static void
@ -3967,15 +3978,30 @@ static const struct wl_callback_listener pointer_surface_listener = {
void
input_set_pointer_image(struct input *input, int pointer)
{
int force = 0;
if (!input->pointer)
return;
if (pointer == input->current_cursor)
if (input->pointer_enter_serial > input->cursor_serial)
force = 1;
if (!force && pointer == input->current_cursor)
return;
input->current_cursor = pointer;
input->cursor_serial = input->pointer_enter_serial;
if (!input->cursor_frame_cb)
pointer_surface_frame_callback(input, NULL, 0);
else if (force && !input_set_pointer_special(input)) {
/* The current frame callback may be stuck if, for instance,
* the set cursor request was processed by the server after
* this client lost the focus. In this case the cursor surface
* might not be mapped and the frame callback wouldn't ever
* complete. Send a set_cursor and attach to try to map the
* cursor surface again so that the callback will finish */
input_set_pointer_image_index(input, 0);
}
}
struct wl_data_device *
@ -5923,6 +5949,8 @@ display_add_input(struct display *d, uint32_t id, int display_seat_version)
input);
}
input->pointer_surface_has_role = false;
toytimer_init(&input->cursor_timer, CLOCK_MONOTONIC, d,
cursor_timer_func);

@ -101,6 +101,8 @@ struct shell_surface {
struct weston_desktop_surface *desktop_surface;
struct weston_view *view;
struct weston_surface *wsurface_anim_fade;
struct weston_view *wview_anim_fade;
int32_t last_width, last_height;
struct desktop_shell *shell;
@ -194,6 +196,10 @@ struct shell_seat {
};
static struct weston_view *
shell_fade_create_fade_out_view(struct shell_surface *shsurf,
struct weston_surface *surface);
static struct desktop_shell *
shell_surface_get_shell(struct shell_surface *shsurf);
@ -261,10 +267,12 @@ desktop_shell_destroy_surface(struct shell_surface *shsurf)
wl_list_init(&shsurf_child->children_link);
}
wl_list_remove(&shsurf->children_link);
weston_desktop_surface_unlink_view(shsurf->view);
weston_view_destroy(shsurf->view);
wl_signal_emit(&shsurf->destroy_signal, shsurf);
weston_surface_destroy(shsurf->wsurface_anim_fade);
weston_view_destroy(shsurf->view);
if (shsurf->output_destroy_listener.notify) {
wl_list_remove(&shsurf->output_destroy_listener.link);
shsurf->output_destroy_listener.notify = NULL;
@ -877,7 +885,7 @@ animate_focus_change(struct desktop_shell *shell, struct workspace *ws,
}
static void
desktop_shell_destroy_views_on_layer(struct weston_layer *layer);
desktop_shell_destroy_layer(struct weston_layer *layer);
static void
workspace_destroy(struct workspace *ws)
@ -892,7 +900,7 @@ workspace_destroy(struct workspace *ws)
if (ws->fsurf_back)
focus_surface_destroy(ws->fsurf_back);
desktop_shell_destroy_views_on_layer(&ws->layer);
desktop_shell_destroy_layer(&ws->layer);
free(ws);
}
@ -1381,7 +1389,7 @@ touch_move_grab_motion(struct weston_touch_grab *grab,
int dx = wl_fixed_to_int(grab->touch->grab_x + move->dx);
int dy = wl_fixed_to_int(grab->touch->grab_y + move->dy);
if (!shsurf || !move->active)
if (!shsurf || !shsurf->desktop_surface || !move->active)
return;
es = weston_desktop_surface_get_surface(shsurf->desktop_surface);
@ -1513,7 +1521,7 @@ move_grab_motion(struct weston_pointer_grab *grab,
int cx, cy;
weston_pointer_move(pointer, event);
if (!shsurf)
if (!shsurf || !shsurf->desktop_surface)
return;
surface = weston_desktop_surface_get_surface(shsurf->desktop_surface);
@ -2253,8 +2261,8 @@ fade_out_done(struct weston_view_animation *animation, void *data)
loop = wl_display_get_event_loop(shsurf->shell->compositor->wl_display);
if (weston_view_is_mapped(shsurf->view)) {
weston_view_unmap(shsurf->view);
if (weston_view_is_mapped(shsurf->wview_anim_fade)) {
weston_view_unmap(shsurf->wview_anim_fade);
wl_event_loop_add_idle(loop, fade_out_done_idle_cb, shsurf);
}
}
@ -2364,7 +2372,6 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
weston_desktop_surface_set_user_data(shsurf->desktop_surface, NULL);
shsurf->desktop_surface = NULL;
weston_desktop_surface_unlink_view(shsurf->view);
if (weston_surface_is_mapped(surface) &&
shsurf->shell->win_close_animation_type == ANIMATION_FADE) {
@ -2373,11 +2380,26 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
pixman_region32_init(&surface->pending.input);
pixman_region32_fini(&surface->input);
pixman_region32_init(&surface->input);
weston_fade_run(shsurf->view, 1.0, 0.0, 300.0,
/* its location might have changed, but also might've
* migrated to a different output, so re-compute this
* as the animation requires having the same output as
* the view */
weston_view_set_output(shsurf->wview_anim_fade,
shsurf->view->output);
weston_view_set_position(shsurf->wview_anim_fade,
shsurf->view->geometry.x,
shsurf->view->geometry.y);
weston_layer_entry_insert(&shsurf->view->layer_link,
&shsurf->wview_anim_fade->layer_link);
/* unmap the "original" view */
weston_view_unmap(shsurf->view);
weston_fade_run(shsurf->wview_anim_fade, 1.0, 0.0, 300.0,
fade_out_done, shsurf);
return;
} else {
weston_surface_destroy(surface);
}
}
@ -2500,8 +2522,14 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
if (!weston_surface_is_mapped(surface)) {
map(shell, shsurf, sx, sy);
surface->is_mapped = true;
if (shsurf->shell->win_close_animation_type == ANIMATION_FADE)
++surface->ref_count;
/* as we need to survive the weston_surface destruction we'll
* need to take another reference */
if (shsurf->shell->win_close_animation_type == ANIMATION_FADE) {
surface->ref_count++;
shsurf->wsurface_anim_fade = surface;
shsurf->wview_anim_fade =
shell_fade_create_fade_out_view(shsurf, surface);
}
return;
}
@ -3992,6 +4020,29 @@ shell_fade_create_surface_for_output(struct desktop_shell *shell, struct shell_o
return view;
}
static struct weston_view *
shell_fade_create_fade_out_view(struct shell_surface *shsurf,
struct weston_surface *surface)
{
struct weston_view *view;
struct weston_output *woutput;
view = weston_view_create(surface);
if (!view)
return NULL;
woutput = get_focused_output(surface->compositor);
/* set the initial position and output just in case we happen to not
* move it around and just destroy it */
weston_view_set_output(view, woutput);
weston_view_set_position(view,
shsurf->view->geometry.x,
shsurf->view->geometry.y);
view->is_mapped = true;
return view;
}
static void
shell_fade(struct desktop_shell *shell, enum fade_type type)
{
@ -4905,7 +4956,7 @@ setup_output_destroy_handler(struct weston_compositor *ec,
}
static void
desktop_shell_destroy_views_on_layer(struct weston_layer *layer)
desktop_shell_destroy_layer(struct weston_layer *layer)
{
struct weston_view *view, *view_next;
@ -4916,9 +4967,17 @@ desktop_shell_destroy_views_on_layer(struct weston_layer *layer)
* additional black_view created and added to its layer_link
* fullscreen view. See shell_ensure_fullscreen_black_view()
*
* As that black_view it is not a weston_desktop_surface
* we can't have a shsurf for it so we just destroy it like
* we do it in desktop_surface_removed() */
* Note that we do not choose to destroy all other potential
* views we find in the layer, but instead we explicitly verify
* if the view in question was explicitly created by
* desktop-shell, rather than libweston-desktop (in
* desktop_surface_added()).
*
* This is particularly important because libweston-desktop
* could create additional views, which are managed implicitly,
* but which are still being added to the layer list.
*
*/
if (shsurf)
desktop_shell_destroy_surface(shsurf);
else
@ -4970,12 +5029,12 @@ shell_destroy(struct wl_listener *listener, void *data)
workspace_destroy(*ws);
wl_array_release(&shell->workspaces.array);
desktop_shell_destroy_views_on_layer(&shell->panel_layer);
desktop_shell_destroy_views_on_layer(&shell->background_layer);
desktop_shell_destroy_views_on_layer(&shell->lock_layer);
desktop_shell_destroy_views_on_layer(&shell->input_panel_layer);
desktop_shell_destroy_views_on_layer(&shell->minimized_layer);
desktop_shell_destroy_views_on_layer(&shell->fullscreen_layer);
desktop_shell_destroy_layer(&shell->panel_layer);
desktop_shell_destroy_layer(&shell->background_layer);
desktop_shell_destroy_layer(&shell->lock_layer);
desktop_shell_destroy_layer(&shell->input_panel_layer);
desktop_shell_destroy_layer(&shell->minimized_layer);
desktop_shell_destroy_layer(&shell->fullscreen_layer);
free(shell->client);
free(shell);

@ -1289,6 +1289,7 @@ struct weston_view {
struct weston_surface *surface;
struct wl_list surface_link;
struct wl_signal destroy_signal;
struct wl_signal unmap_signal;
/* struct weston_paint_node::view_link */
struct wl_list paint_node_list;
@ -1441,7 +1442,7 @@ struct weston_pointer_constraint {
bool hint_is_pending;
struct wl_listener pointer_destroy_listener;
struct wl_listener surface_destroy_listener;
struct wl_listener view_unmap_listener;
struct wl_listener surface_commit_listener;
struct wl_listener surface_activate_listener;
};

@ -173,8 +173,10 @@ kiosk_shell_surface_find_best_output(struct kiosk_shell_surface *shsurf)
app_id = weston_desktop_surface_get_app_id(shsurf->desktop_surface);
if (app_id) {
wl_list_for_each(shoutput, &shsurf->shell->output_list, link) {
if (kiosk_shell_output_has_app_id(shoutput, app_id))
if (kiosk_shell_output_has_app_id(shoutput, app_id)) {
shsurf->appid_output_assigned = true;
return shoutput->output;
}
}
}
@ -354,6 +356,7 @@ kiosk_shell_surface_create(struct kiosk_shell *shell,
shsurf->desktop_surface = desktop_surface;
shsurf->view = view;
shsurf->shell = shell;
shsurf->appid_output_assigned = false;
weston_desktop_surface_set_user_data(desktop_surface, shsurf);
@ -387,8 +390,10 @@ kiosk_shell_surface_activate(struct kiosk_shell_surface *shsurf,
/* removes it from the normal_layer and move it to inactive
* one, without occluding the top-level window if the new one
* is a child to that */
if (!shsurf->parent) {
* is a child to that. Also, do not occlude another view
* (currently focused one) on a different output when activating
* a new one. */
if (!shsurf->parent && (shsurf->output == current_focus->output)) {
weston_layer_entry_remove(&current_focus->view->layer_link);
weston_layer_entry_insert(&shsurf->shell->inactive_layer.view_list,
&current_focus->view->layer_link);
@ -645,12 +650,18 @@ find_focus_successor(struct weston_layer *layer,
struct weston_view *top_view = NULL;
struct weston_view *view;
/* we need to take into account that the surface being destroyed it not
* always the same as the focus_surface, which could result in picking
* and *activating* the wrong window, so avoid returning a view for
* that case. A particular case is when a top-level child window, would
* pick a parent window below the focused_surface. */
if (focused_surface != shsurf->view->surface)
* pick a parent window below the focused_surface.
*
* Apply that only on the same output to avoid incorrectly returning an
* invalid/empty view, which could happen if the view being destroyed
* is on a output different than the focused_surface output */
if (focused_surface && focused_surface != shsurf->view->surface &&
shsurf->output == focused_surface->output)
return top_view;
wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
@ -660,6 +671,10 @@ find_focus_successor(struct weston_layer *layer,
if (!view->is_mapped || view == shsurf->view)
continue;
/* pick views only on the same output */
if (view->output != shsurf->output)
continue;
view_shsurf = get_kiosk_shell_surface(view->surface);
if (!view_shsurf)
continue;
@ -721,6 +736,8 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
weston_desktop_surface_get_user_data(desktop_surface);
struct weston_surface *surface =
weston_desktop_surface_get_surface(desktop_surface);
const char *app_id =
weston_desktop_surface_get_app_id(desktop_surface);
bool is_resized;
bool is_fullscreen;
@ -729,6 +746,24 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
if (surface->width == 0)
return;
if (!shsurf->appid_output_assigned && app_id) {
struct weston_output *output = NULL;
/* reset previous output being set in _added() as the output is
* being cached */
shsurf->output = NULL;
output = kiosk_shell_surface_find_best_output(shsurf);
kiosk_shell_surface_set_output(shsurf, output);
weston_desktop_surface_set_size(shsurf->desktop_surface,
shsurf->output->width,
shsurf->output->height);
/* even if we couldn't find an appid set for a particular
* output still flag the shsurf as to a avoid changing the
* output every time */
shsurf->appid_output_assigned = true;
}
/* TODO: When the top-level surface is committed with a new size after an
* output resize, sometimes the view appears scaled. What state are we not
* updating?

@ -73,6 +73,8 @@ struct kiosk_shell_surface {
int32_t x;
int32_t y;
} xwayland;
bool appid_output_assigned;
};
struct kiosk_shell_seat {

@ -713,7 +713,7 @@ weston_desktop_xdg_toplevel_committed(struct weston_desktop_xdg_toplevel *toplev
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
"xdg_surface buffer (%" PRIi32 " x %" PRIi32 ") "
"xdg_surface geometry (%" PRIi32 " x %" PRIi32 ") "
"does not match the configured maximized state (%" PRIi32 " x %" PRIi32 ")",
geometry.width, geometry.height,
toplevel->next.size.width,

@ -236,6 +236,7 @@ enum try_view_on_plane_failure_reasons {
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE = (1 << 1),
FAILURE_REASONS_DMABUF_MODIFIER_INVALID = (1 << 2),
FAILURE_REASONS_ADD_FB_FAILED = (1 << 3),
FAILURE_REASONS_GBM_BO_IMPORT_FAILED = (1 << 4)
};
/**

@ -276,8 +276,12 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD_MODIFIER,
&import_mod, GBM_BO_USE_SCANOUT);
if (!fb->bo)
if (!fb->bo) {
if (try_view_on_plane_failure_reasons)
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_GBM_BO_IMPORT_FAILED;
goto err_free;
}
fb->width = dmabuf->attributes.width;
fb->height = dmabuf->attributes.height;

@ -42,7 +42,7 @@ deps_drm = [
]
if get_option('renderer-gl')
dep_gbm = dependency('gbm', required: false)
dep_gbm = dependency('gbm', required: false, version: '>= 21.1.1')
if not dep_gbm.found()
error('drm-backend with GL renderer requires gbm which was not found. Or, you can use \'-Drenderer-gl=false\'.')
endif

@ -602,7 +602,8 @@ dmabuf_feedback_maybe_update(struct drm_backend *b, struct weston_view *ev,
if (try_view_on_plane_failure_reasons &
(FAILURE_REASONS_ADD_FB_FAILED |
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE |
FAILURE_REASONS_DMABUF_MODIFIER_INVALID))
FAILURE_REASONS_DMABUF_MODIFIER_INVALID |
FAILURE_REASONS_GBM_BO_IMPORT_FAILED))
action_needed |= ACTION_NEEDED_ADD_SCANOUT_TRANCHE;
assert(action_needed != (ACTION_NEEDED_REMOVE_SCANOUT_TRANCHE |

@ -393,6 +393,7 @@ weston_view_create(struct weston_surface *surface)
wl_list_insert(&surface->views, &view->surface_link);
wl_signal_init(&view->destroy_signal);
wl_signal_init(&view->unmap_signal);
wl_list_init(&view->link);
wl_list_init(&view->layer_link.link);
wl_list_init(&view->paint_node_list);
@ -2225,22 +2226,22 @@ weston_view_unmap(struct weston_view *view)
view->output_mask = 0;
weston_surface_assign_output(view->surface);
if (weston_surface_is_mapped(view->surface))
return;
wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
struct weston_touch *touch = weston_seat_get_touch(seat);
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(seat);
if (keyboard && keyboard->focus == view->surface)
weston_keyboard_set_focus(keyboard, NULL);
if (pointer && pointer->focus == view)
weston_pointer_clear_focus(pointer);
if (touch && touch->focus == view)
weston_touch_set_focus(touch, NULL);
if (!weston_surface_is_mapped(view->surface)) {
wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
struct weston_touch *touch = weston_seat_get_touch(seat);
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(seat);
if (keyboard && keyboard->focus == view->surface)
weston_keyboard_set_focus(keyboard, NULL);
if (pointer && pointer->focus == view)
weston_pointer_clear_focus(pointer);
if (touch && touch->focus == view)
weston_touch_set_focus(touch, NULL);
}
}
weston_signal_emit_mutable(&view->unmap_signal, view);
}
WL_EXPORT void
@ -2306,6 +2307,10 @@ weston_surface_destroy(struct weston_surface *surface)
struct weston_pointer_constraint *constraint, *next_constraint;
struct weston_paint_node *pnode, *pntmp;
if (!surface)
return;
assert(surface->ref_count > 0);
if (--surface->ref_count > 0)
return;
@ -4044,54 +4049,22 @@ static const struct wl_surface_interface surface_interface = {
surface_damage_buffer
};
static int
create_surface_dmabuf_feedback(struct weston_compositor *ec,
struct weston_surface *surface)
{
struct weston_dmabuf_feedback_tranche *tranche;
dev_t main_device = ec->default_dmabuf_feedback->main_device;
uint32_t flags = 0;
surface->dmabuf_feedback = weston_dmabuf_feedback_create(main_device);
if (!surface->dmabuf_feedback)
return -1;
tranche = weston_dmabuf_feedback_tranche_create(surface->dmabuf_feedback,
ec->dmabuf_feedback_format_table,
main_device, flags,
RENDERER_PREF);
if (!tranche) {
weston_dmabuf_feedback_destroy(surface->dmabuf_feedback);
surface->dmabuf_feedback = NULL;
return -1;
}
return 0;
}
static void
compositor_create_surface(struct wl_client *client,
struct wl_resource *resource, uint32_t id)
{
struct weston_compositor *ec = wl_resource_get_user_data(resource);
struct weston_surface *surface;
int ret;
surface = weston_surface_create(ec);
if (surface == NULL)
goto err;
if (ec->default_dmabuf_feedback) {
ret = create_surface_dmabuf_feedback(ec, surface);
if (ret < 0)
goto err_dmabuf_feedback;
}
surface->resource =
wl_resource_create(client, &wl_surface_interface,
wl_resource_get_version(resource), id);
if (surface->resource == NULL)
goto err_dmabuf_feedback;
goto err_res;
wl_resource_set_implementation(surface->resource, &surface_interface,
surface, destroy_surface);
@ -4099,7 +4072,7 @@ compositor_create_surface(struct wl_client *client,
return;
err_dmabuf_feedback:
err_res:
weston_surface_destroy(surface);
err:
wl_resource_post_no_memory(resource);
@ -4211,6 +4184,11 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
&surface->pending.damage_surface);
pixman_region32_clear(&surface->pending.damage_surface);
pixman_region32_union(&sub->cached.damage_buffer,
&sub->cached.damage_buffer,
&surface->pending.damage_buffer);
pixman_region32_clear(&surface->pending.damage_buffer);
if (surface->pending.newly_attached) {
sub->cached.newly_attached = 1;
weston_surface_state_set_buffer(&sub->cached,
@ -4233,8 +4211,6 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
sub->cached.sx += surface->pending.sx;
sub->cached.sy += surface->pending.sy;
apply_damage_buffer(&sub->cached.damage_surface, surface, &surface->pending);
sub->cached.buffer_viewport.changed |=
surface->pending.buffer_viewport.changed;
sub->cached.buffer_viewport.buffer =
@ -4361,7 +4337,7 @@ subsurface_committed(struct weston_surface *surface, int32_t dx, int32_t dy)
*/
if (!weston_surface_is_mapped(surface)) {
surface->is_mapped = true;
surface->is_mapped = surface->buffer_ref.buffer != NULL;
/* Cannot call weston_view_update_transform(),
* because that would call it also for the parent surface,

@ -3655,8 +3655,8 @@ enable_pointer_constraint(struct weston_pointer_constraint *constraint,
constraint->view = view;
pointer_constraint_notify_activated(constraint);
weston_pointer_start_grab(constraint->pointer, &constraint->grab);
wl_list_remove(&constraint->surface_destroy_listener.link);
wl_list_init(&constraint->surface_destroy_listener.link);
wl_signal_add(&constraint->view->unmap_signal,
&constraint->view_unmap_listener);
}
static bool
@ -3671,6 +3671,8 @@ weston_pointer_constraint_disable(struct weston_pointer_constraint *constraint)
constraint->view = NULL;
pointer_constraint_notify_deactivated(constraint);
weston_pointer_end_grab(constraint->grab.pointer);
wl_list_remove(&constraint->view_unmap_listener.link);
wl_list_init(&constraint->view_unmap_listener.link);
}
void
@ -3680,7 +3682,6 @@ weston_pointer_constraint_destroy(struct weston_pointer_constraint *constraint)
weston_pointer_constraint_disable(constraint);
wl_list_remove(&constraint->pointer_destroy_listener.link);
wl_list_remove(&constraint->surface_destroy_listener.link);
wl_list_remove(&constraint->surface_commit_listener.link);
wl_list_remove(&constraint->surface_activate_listener.link);
@ -3877,13 +3878,13 @@ pointer_constraint_pointer_destroyed(struct wl_listener *listener, void *data)
}
static void
pointer_constraint_surface_destroyed(struct wl_listener *listener, void *data)
pointer_constraint_view_unmapped(struct wl_listener *listener, void *data)
{
struct weston_pointer_constraint *constraint =
container_of(listener, struct weston_pointer_constraint,
surface_destroy_listener);
struct weston_pointer_constraint *constraint =
container_of(listener, struct weston_pointer_constraint,
view_unmap_listener);
weston_pointer_constraint_destroy(constraint);
disable_pointer_constraint(constraint);
}
static void
@ -3947,8 +3948,8 @@ weston_pointer_constraint_create(struct weston_surface *surface,
constraint->surface_activate_listener.notify =
pointer_constraint_surface_activate;
constraint->surface_destroy_listener.notify =
pointer_constraint_surface_destroyed;
constraint->view_unmap_listener.notify =
pointer_constraint_view_unmapped;
constraint->surface_commit_listener.notify =
pointer_constraint_surface_committed;
constraint->pointer_destroy_listener.notify =
@ -3958,8 +3959,6 @@ weston_pointer_constraint_create(struct weston_surface *surface,
&constraint->surface_activate_listener);
wl_signal_add(&pointer->destroy_signal,
&constraint->pointer_destroy_listener);
wl_signal_add(&surface->destroy_signal,
&constraint->surface_destroy_listener);
wl_signal_add(&surface->commit_signal,
&constraint->surface_commit_listener);
@ -4729,6 +4728,7 @@ maybe_warp_confined_pointer(struct weston_pointer_constraint *constraint)
pixman_region32_intersect(&confine_region,
&constraint->view->surface->input,
&constraint->region);
assert(pixman_region32_not_empty(&confine_region));
region_to_outline(&confine_region, &borders);
pixman_region32_fini(&confine_region);

@ -684,6 +684,7 @@ weston_dmabuf_feedback_destroy(struct weston_dmabuf_feedback *dmabuf_feedback)
wl_resource_for_each_safe(res, res_tmp, &dmabuf_feedback->resource_list) {
wl_list_remove(wl_resource_get_link(res));
wl_list_init(wl_resource_get_link(res));
wl_resource_set_user_data(res, NULL);
}
free(dmabuf_feedback);
@ -786,6 +787,7 @@ weston_dmabuf_feedback_send_all(struct weston_dmabuf_feedback *dmabuf_feedback,
{
struct wl_resource *res;
assert(!wl_list_empty(&dmabuf_feedback->resource_list));
wl_resource_for_each(res, &dmabuf_feedback->resource_list)
weston_dmabuf_feedback_send(dmabuf_feedback,
format_table, res, false);
@ -794,7 +796,16 @@ weston_dmabuf_feedback_send_all(struct weston_dmabuf_feedback *dmabuf_feedback,
static void
dmabuf_feedback_resource_destroy(struct wl_resource *resource)
{
struct weston_surface *surface =
wl_resource_get_user_data(resource);
wl_list_remove(wl_resource_get_link(resource));
if (surface &&
wl_list_empty(&surface->dmabuf_feedback->resource_list)) {
weston_dmabuf_feedback_destroy(surface->dmabuf_feedback);
surface->dmabuf_feedback = NULL;
}
}
static void
@ -810,7 +821,8 @@ zwp_linux_dmabuf_feedback_implementation = {
static struct wl_resource *
dmabuf_feedback_resource_create(struct wl_resource *dmabuf_resource,
struct wl_client *client, uint32_t dmabuf_feedback_id)
struct wl_client *client, uint32_t dmabuf_feedback_id,
struct weston_surface *surface)
{
struct wl_resource *dmabuf_feedback_res;
uint32_t version;
@ -826,7 +838,7 @@ dmabuf_feedback_resource_create(struct wl_resource *dmabuf_resource,
wl_list_init(wl_resource_get_link(dmabuf_feedback_res));
wl_resource_set_implementation(dmabuf_feedback_res,
&zwp_linux_dmabuf_feedback_implementation,
NULL, dmabuf_feedback_resource_destroy);
surface, dmabuf_feedback_resource_destroy);
return dmabuf_feedback_res;
}
@ -842,7 +854,8 @@ linux_dmabuf_get_default_feedback(struct wl_client *client,
dmabuf_feedback_resource =
dmabuf_feedback_resource_create(dmabuf_resource,
client, dmabuf_feedback_id);
client, dmabuf_feedback_id,
NULL);
if (!dmabuf_feedback_resource) {
wl_resource_post_no_memory(dmabuf_resource);
return;
@ -853,22 +866,55 @@ linux_dmabuf_get_default_feedback(struct wl_client *client,
dmabuf_feedback_resource, true);
}
static int
create_surface_dmabuf_feedback(struct weston_compositor *ec,
struct weston_surface *surface)
{
struct weston_dmabuf_feedback_tranche *tranche;
dev_t main_device = ec->default_dmabuf_feedback->main_device;
uint32_t flags = 0;
surface->dmabuf_feedback = weston_dmabuf_feedback_create(main_device);
if (!surface->dmabuf_feedback)
return -1;
tranche = weston_dmabuf_feedback_tranche_create(surface->dmabuf_feedback,
ec->dmabuf_feedback_format_table,
main_device, flags,
RENDERER_PREF);
if (!tranche) {
weston_dmabuf_feedback_destroy(surface->dmabuf_feedback);
surface->dmabuf_feedback = NULL;
return -1;
}
return 0;
}
static void
linux_dmabuf_get_per_surface_feedback(struct wl_client *client,
struct wl_resource *dmabuf_resource,
uint32_t dmabuf_feedback_id,
struct wl_resource *surface_resource)
{
struct weston_compositor *compositor =
wl_resource_get_user_data(dmabuf_resource);
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
struct wl_resource *dmabuf_feedback_resource;
int ret;
dmabuf_feedback_resource =
dmabuf_feedback_resource_create(dmabuf_resource,
client, dmabuf_feedback_id);
if (!dmabuf_feedback_resource) {
wl_resource_post_no_memory(dmabuf_resource);
return;
client, dmabuf_feedback_id,
surface);
if (!dmabuf_feedback_resource)
goto err;
if (!surface->dmabuf_feedback) {
ret = create_surface_dmabuf_feedback(compositor, surface);
if (ret < 0)
goto err_feedback;
}
/* Surface dma-buf feedback is dynamic and may need to be resent to
@ -879,6 +925,13 @@ linux_dmabuf_get_per_surface_feedback(struct wl_client *client,
weston_dmabuf_feedback_send(surface->dmabuf_feedback,
surface->compositor->dmabuf_feedback_format_table,
dmabuf_feedback_resource, true);
return;
err_feedback:
wl_resource_set_user_data(dmabuf_feedback_resource, NULL);
wl_resource_destroy(dmabuf_feedback_resource);
err:
wl_resource_post_no_memory(dmabuf_resource);
}
/** Get the linux_dmabuf_buffer from a wl_buffer resource

@ -67,6 +67,9 @@ compile_const bool c_input_is_premult = DEF_INPUT_IS_PREMULT;
compile_const bool c_green_tint = DEF_GREEN_TINT;
compile_const int c_color_pre_curve = DEF_COLOR_PRE_CURVE;
compile_const bool c_need_color_pipeline =
c_color_pre_curve != SHADER_COLOR_CURVE_IDENTITY;
vec4
yuva2rgba(vec4 yuva)
{
@ -202,9 +205,6 @@ color_pre_curve(vec3 color)
vec4
color_pipeline(vec4 color)
{
/* View alpha (opacity) */
color.a *= alpha;
color.rgb = color_pre_curve(color.rgb);
return color;
@ -218,18 +218,35 @@ main()
/* Electrical (non-linear) RGBA values, may be premult or not */
color = sample_input_texture();
/* Ensure straight alpha */
if (c_input_is_premult) {
if (color.a == 0.0)
color.rgb = vec3(0, 0, 0);
else
color.rgb *= 1.0 / color.a;
}
if (c_need_color_pipeline) {
/* Ensure straight alpha */
if (c_input_is_premult) {
if (color.a == 0.0)
color.rgb = vec3(0, 0, 0);
else
color.rgb *= 1.0 / color.a;
}
color = color_pipeline(color);
color = color_pipeline(color);
/* pre-multiply for blending */
color.rgb *= color.a;
/* View alpha (opacity) */
color.a *= alpha;
/* pre-multiply for blending */
color.rgb *= color.a;
} else {
/* Fast path for disabled color management */
if (c_input_is_premult) {
/* View alpha (opacity) */
color *= alpha;
} else {
/* View alpha (opacity) */
color.a *= alpha;
/* pre-multiply for blending */
color.rgb *= color.a;
}
}
if (c_green_tint)
color = vec4(0.0, 0.3, 0.0, 0.2) + color * 0.8;

@ -1,6 +1,6 @@
project('weston',
'c',
version: '10.0.0',
version: '10.0.5',
default_options: [
'warning_level=3',
'c_std=gnu99',
@ -121,7 +121,7 @@ config_h.set10('TEST_GL_RENDERER', get_option('test-gl-renderer'))
backend_default = get_option('backend-default')
if backend_default == 'auto'
foreach b : [ 'headless', 'fbdev', 'x11', 'wayland', 'drm' ]
foreach b : [ 'headless', 'x11', 'wayland', 'drm' ]
if get_option('backend-' + b)
backend_default = b
endif

@ -36,6 +36,8 @@ fixture_setup(struct weston_test_harness *harness)
compositor_setup_defaults(&setup);
setup.shell = SHELL_TEST_DESKTOP;
return weston_test_harness_execute_as_client(harness, &setup);
}
DECLARE_FIXTURE_SETUP(fixture_setup);

@ -53,7 +53,7 @@ struct runner_test {
static void runner_func_##name(struct test_context *); \
\
const struct runner_test runner_test_##name \
__attribute__ ((section ("plugin_test_section"))) = \
__attribute__ ((used, section ("plugin_test_section"))) = \
{ \
#name, runner_func_##name \
}; \

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 887 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 857 B

@ -117,7 +117,7 @@ surface_commit_color(struct client *client, struct wl_surface *surface,
buf = create_shm_buffer_a8r8g8b8(client, width, height);
fill_image_with_color(buf->image, color);
wl_surface_attach(surface, buf->proxy, 0, 0);
wl_surface_damage(surface, 0, 0, width, height);
wl_surface_damage_buffer(surface, 0, 0, width, height);
wl_surface_commit(surface);
return buf;
@ -213,3 +213,199 @@ TEST(subsurface_z_order)
wl_subcompositor_destroy(subco);
client_destroy(client);
}
TEST(subsurface_sync_damage_buffer)
{
struct client *client;
struct wl_subcompositor *subco;
struct buffer *bufs[2] = { 0 };
struct wl_surface *surf[2] = { 0 };
struct wl_subsurface *sub[2] = { 0 };
struct rectangle clip = { 40, 40, 280, 200 };
int fail = 0;
unsigned i;
pixman_color_t red;
pixman_color_t blue;
pixman_color_t green;
color_rgb888(&red, 255, 0, 0);
color_rgb888(&blue, 0, 0, 255);
color_rgb888(&green, 0, 255, 0);
client = create_client_and_test_surface(100, 50, 100, 100);
assert(client);
subco = get_subcompositor(client);
/* move the pointer clearly away from our screenshooting area */
weston_test_move_pointer(client->test->weston_test, 0, 1, 0, 2, 30);
/* make the parent surface red */
surf[0] = client->surface->wl_surface;
client->surface->wl_surface = NULL; /* we stole it and destroy it */
bufs[0] = surface_commit_color(client, surf[0], &red, 100, 100);
/* sub[0] is not used */
fail += check_screen(client, "subsurface_sync_damage_buffer", 0, &clip, 0);
/* create a blue sub-surface above red */
surf[1] = wl_compositor_create_surface(client->wl_compositor);
sub[1] = wl_subcompositor_get_subsurface(subco, surf[1], surf[0]);
bufs[1] = surface_commit_color(client, surf[1], &blue, 100, 100);
wl_subsurface_set_position(sub[1], 20, 20);
wl_surface_commit(surf[0]);
fail += check_screen(client, "subsurface_sync_damage_buffer", 1, &clip, 1);
buffer_destroy(bufs[1]);
bufs[1] = surface_commit_color(client, surf[1], &green, 100, 100);
wl_surface_commit(surf[0]);
fail += check_screen(client, "subsurface_sync_damage_buffer", 2, &clip, 2);
assert(fail == 0);
for (i = 0; i < ARRAY_LENGTH(sub); i++)
if (sub[i])
wl_subsurface_destroy(sub[i]);
for (i = 0; i < ARRAY_LENGTH(surf); i++)
if (surf[i])
wl_surface_destroy(surf[i]);
for (i = 0; i < ARRAY_LENGTH(bufs); i++)
if (bufs[i])
buffer_destroy(bufs[i]);
wl_subcompositor_destroy(subco);
client_destroy(client);
}
TEST(subsurface_empty_mapping)
{
struct client *client;
struct wl_subcompositor *subco;
struct wp_viewporter *viewporter;
struct buffer *bufs[3] = { 0 };
struct wl_surface *surf[3] = { 0 };
struct wl_subsurface *sub[3] = { 0 };
struct wp_viewport *viewport;
struct rectangle clip = { 40, 40, 280, 200 };
int fail = 0;
unsigned i;
pixman_color_t red;
pixman_color_t blue;
pixman_color_t green;
color_rgb888(&red, 255, 0, 0);
color_rgb888(&blue, 0, 0, 255);
color_rgb888(&green, 0, 255, 0);
client = create_client_and_test_surface(100, 50, 100, 100);
assert(client);
subco = get_subcompositor(client);
viewporter = bind_to_singleton_global(client,
&wp_viewporter_interface, 1);
/* move the pointer clearly away from our screenshooting area */
weston_test_move_pointer(client->test->weston_test, 0, 1, 0, 2, 30);
/* make the parent surface red */
surf[0] = client->surface->wl_surface;
client->surface->wl_surface = NULL; /* we stole it and destroy it */
bufs[0] = surface_commit_color(client, surf[0], &red, 100, 100);
/* sub[0] is not used */
fail += check_screen(client, "subsurface_empty_mapping", 0, &clip, 0);
/* create an empty subsurface on top */
surf[1] = wl_compositor_create_surface(client->wl_compositor);
sub[1] = wl_subcompositor_get_subsurface(subco, surf[1], surf[0]);
wl_subsurface_set_desync (sub[1]);
wl_subsurface_set_position(sub[1], 20, 20);
wl_surface_commit(surf[0]);
fail += check_screen(client, "subsurface_empty_mapping", 0, &clip, 1);
/* create a green subsurface on top */
surf[2] = wl_compositor_create_surface(client->wl_compositor);
sub[2] = wl_subcompositor_get_subsurface(subco, surf[2], surf[1]);
wl_subsurface_set_desync (sub[2]);
bufs[2] = surface_commit_color(client, surf[2], &green, 100, 100);
wl_subsurface_set_position(sub[2], 20, 20);
wl_surface_commit(surf[1]);
fail += check_screen(client, "subsurface_empty_mapping", 0, &clip, 2);
wl_surface_attach(surf[1], NULL, 0, 0);
wl_surface_commit(surf[1]);
fail += check_screen(client, "subsurface_empty_mapping", 0, &clip, 3);
wl_surface_set_buffer_scale (surf[1], 1);
wl_surface_commit(surf[1]);
fail += check_screen(client, "subsurface_empty_mapping", 0, &clip, 4);
viewport = wp_viewporter_get_viewport(viewporter, surf[1]);
wp_viewport_set_destination(viewport, 5, 5);
wl_surface_commit(surf[1]);
fail += check_screen(client, "subsurface_empty_mapping", 0, &clip, 5);
wp_viewport_set_destination(viewport, -1, -1);
wl_surface_commit(surf[1]);
fail += check_screen(client, "subsurface_empty_mapping", 0, &clip, 6);
/* map the previously empty middle surface with a blue buffer */
bufs[1] = surface_commit_color(client, surf[1], &blue, 100, 100);
fail += check_screen(client, "subsurface_empty_mapping", 1, &clip, 7);
/* try to trigger a recomputation of the buffer size with the
* shm-buffer potentially being released already */
wl_surface_set_buffer_scale (surf[1], 1);
wl_surface_commit(surf[1]);
fail += check_screen(client, "subsurface_empty_mapping", 1, &clip, 8);
/* try more */
wp_viewport_set_destination(viewport, 100, 100);
wl_surface_commit(surf[1]);
fail += check_screen(client, "subsurface_empty_mapping", 1, &clip, 9);
/* unmap the middle surface again to ensure recursive unmapping */
wl_surface_attach(surf[1], NULL, 0, 0);
wl_surface_commit(surf[1]);
fail += check_screen(client, "subsurface_empty_mapping", 0, &clip, 10);
/* remap middle surface to ensure recursive mapping */
bufs[1] = surface_commit_color(client, surf[1], &blue, 100, 100);
fail += check_screen(client, "subsurface_empty_mapping", 1, &clip, 11);
assert(fail == 0);
wp_viewport_destroy(viewport);
for (i = 0; i < ARRAY_LENGTH(sub); i++)
if (sub[i])
wl_subsurface_destroy(sub[i]);
for (i = 0; i < ARRAY_LENGTH(surf); i++)
if (surf[i])
wl_surface_destroy(surf[i]);
for (i = 0; i < ARRAY_LENGTH(bufs); i++)
if (bufs[i])
buffer_destroy(bufs[i]);
wp_viewporter_destroy(viewporter);
wl_subcompositor_destroy(subco);
client_destroy(client);
}

Loading…
Cancel
Save