Merge tag '11.0.3' into dev

11.0.3
This commit is contained in:
2024-07-20 21:35:16 +02:00
217 changed files with 15749 additions and 15899 deletions
+18 -73
View File
@@ -118,8 +118,9 @@ drm_backend_create_gl_renderer(struct drm_backend *b)
int
init_egl(struct drm_backend *b)
{
b->gbm = create_gbm_device(b->drm.fd);
struct drm_device *device = b->drm;
b->gbm = create_gbm_device(device->drm.fd);
if (!b->gbm)
return -1;
@@ -145,6 +146,7 @@ static void drm_output_fini_cursor_egl(struct drm_output *output)
static int
drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
{
struct drm_device *device = output->device;
unsigned int i;
/* No point creating cursors if we don't have a plane for them. */
@@ -154,14 +156,14 @@ drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
struct gbm_bo *bo;
bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
bo = gbm_bo_create(b->gbm, device->cursor_width, device->cursor_height,
GBM_FORMAT_ARGB8888,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
if (!bo)
goto err;
output->gbm_cursor_fb[i] =
drm_fb_get_from_bo(bo, b, false, BUFFER_CURSOR);
drm_fb_get_from_bo(bo, device, false, BUFFER_CURSOR);
if (!output->gbm_cursor_fb[i]) {
gbm_bo_destroy(bo);
goto err;
@@ -173,7 +175,7 @@ drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
err:
weston_log("cursor buffers unavailable, using gl cursors\n");
b->cursors_are_broken = true;
device->cursors_are_broken = true;
drm_output_fini_cursor_egl(output);
return -1;
}
@@ -183,6 +185,7 @@ create_gbm_surface(struct gbm_device *gbm, struct drm_output *output)
{
struct weston_mode *mode = output->base.current_mode;
struct drm_plane *plane = output->scanout_plane;
const struct pixel_format_info *pixel_format;
struct weston_drm_format *fmt;
const uint64_t *modifiers;
unsigned int num_modifiers;
@@ -190,8 +193,15 @@ create_gbm_surface(struct gbm_device *gbm, struct drm_output *output)
fmt = weston_drm_format_array_find_format(&plane->formats,
output->gbm_format);
if (!fmt) {
weston_log("format 0x%x not supported by output %s\n",
output->gbm_format, output->base.name);
pixel_format = pixel_format_get_info(output->gbm_format);
if (pixel_format)
weston_log("format %s not supported by output %s\n",
pixel_format->drm_format_name,
output->base.name);
else
weston_log("format 0x%x not supported by output %s\n",
output->gbm_format,
output->base.name);
return;
}
@@ -280,7 +290,7 @@ struct drm_fb *
drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
{
struct drm_output *output = state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
struct gbm_bo *bo;
struct drm_fb *ret;
@@ -295,7 +305,7 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
}
/* The renderer always produces an opaque image. */
ret = drm_fb_get_from_bo(bo, b, true, BUFFER_GBM_SURFACE);
ret = drm_fb_get_from_bo(bo, device, true, BUFFER_GBM_SURFACE);
if (!ret) {
weston_log("failed to get drm_fb for bo\n");
gbm_surface_release_buffer(output->gbm_surface, bo);
@@ -305,68 +315,3 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
return ret;
}
static void
switch_to_gl_renderer(struct drm_backend *b)
{
struct drm_output *output;
bool dmabuf_support_inited;
bool linux_explicit_sync_inited;
if (!b->use_pixman)
return;
dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
linux_explicit_sync_inited =
b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC;
weston_log("Switching to GL renderer\n");
b->gbm = create_gbm_device(b->drm.fd);
if (!b->gbm) {
weston_log("Failed to create gbm device. "
"Aborting renderer switch\n");
return;
}
wl_list_for_each(output, &b->compositor->output_list, base.link)
pixman_renderer_output_destroy(&output->base);
b->compositor->renderer->destroy(b->compositor);
if (drm_backend_create_gl_renderer(b) < 0) {
gbm_device_destroy(b->gbm);
weston_log("Failed to create GL renderer. Quitting.\n");
/* FIXME: we need a function to shutdown cleanly */
assert(0);
}
wl_list_for_each(output, &b->compositor->output_list, base.link)
drm_output_init_egl(output, b);
b->use_pixman = 0;
if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
if (linux_dmabuf_setup(b->compositor) < 0)
weston_log("Error: initializing dmabuf "
"support failed.\n");
}
if (!linux_explicit_sync_inited &&
(b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC)) {
if (linux_explicit_synchronization_setup(b->compositor) < 0)
weston_log("Error: initializing explicit "
" synchronization support failed.\n");
}
}
void
renderer_switch_binding(struct weston_keyboard *keyboard,
const struct timespec *time, uint32_t key, void *data)
{
struct drm_backend *b =
to_drm_backend(keyboard->seat->compositor);
switch_to_gl_renderer(b);
}
+109 -81
View File
@@ -186,6 +186,8 @@ enum wdrm_connector_property {
WDRM_CONNECTOR_CONTENT_PROTECTION,
WDRM_CONNECTOR_HDCP_CONTENT_TYPE,
WDRM_CONNECTOR_PANEL_ORIENTATION,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
WDRM_CONNECTOR_MAX_BPC,
WDRM_CONNECTOR__COUNT
};
@@ -232,11 +234,20 @@ enum wdrm_crtc_property {
*/
enum try_view_on_plane_failure_reasons {
FAILURE_REASONS_NONE = 0,
FAILURE_REASONS_FORCE_RENDERER = (1 << 0),
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)
FAILURE_REASONS_FORCE_RENDERER = 1 << 0,
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE = 1 << 1,
FAILURE_REASONS_DMABUF_MODIFIER_INVALID = 1 << 2,
FAILURE_REASONS_ADD_FB_FAILED = 1 << 3,
FAILURE_REASONS_NO_PLANES_AVAILABLE = 1 << 4,
FAILURE_REASONS_PLANES_REJECTED = 1 << 5,
FAILURE_REASONS_INADEQUATE_CONTENT_PROTECTION = 1 << 6,
FAILURE_REASONS_INCOMPATIBLE_TRANSFORM = 1 << 7,
FAILURE_REASONS_NO_BUFFER = 1 << 8,
FAILURE_REASONS_BUFFER_TYPE = 1 << 9,
FAILURE_REASONS_GLOBAL_ALPHA = 1 << 10,
FAILURE_REASONS_NO_GBM = 1 << 11,
FAILURE_REASONS_GBM_BO_IMPORT_FAILED = 1 << 12,
FAILURE_REASONS_GBM_BO_GET_HANDLE_FAILED = 1 << 13,
};
/**
@@ -249,6 +260,48 @@ enum actions_needed_dmabuf_feedback {
ACTION_NEEDED_REMOVE_SCANOUT_TRANCHE = (1 << 1),
};
struct drm_device {
struct drm_backend *backend;
struct {
int id;
int fd;
char *filename;
dev_t devnum;
} drm;
/* drm_crtc::link */
struct wl_list crtc_list;
struct wl_list plane_list;
/* drm_writeback::link */
struct wl_list writeback_connector_list;
bool state_invalid;
bool atomic_modeset;
bool aspect_ratio_supported;
int32_t cursor_width;
int32_t cursor_height;
bool cursors_are_broken;
bool sprites_are_broken;
void *repaint_data;
bool fb_modifiers;
/* we need these parameters in order to not fail drmModeAddFB2()
* due to out of bounds dimensions, and then mistakenly set
* sprites_are_broken:
*/
int min_width, max_width;
int min_height, max_height;
};
struct drm_backend {
struct weston_backend base;
struct weston_compositor *compositor;
@@ -259,57 +312,20 @@ struct drm_backend {
struct udev_monitor *udev_monitor;
struct wl_event_source *udev_drm_source;
struct {
int id;
int fd;
char *filename;
dev_t devnum;
} drm;
struct drm_device *drm;
struct gbm_device *gbm;
struct wl_listener session_listener;
uint32_t gbm_format;
/* we need these parameters in order to not fail drmModeAddFB2()
* due to out of bounds dimensions, and then mistakenly set
* sprites_are_broken:
*/
int min_width, max_width;
int min_height, max_height;
struct wl_list plane_list;
uint32_t next_plane_idx;
void *repaint_data;
bool state_invalid;
/* drm_crtc::link */
struct wl_list crtc_list;
/* drm_writeback::link */
struct wl_list writeback_connector_list;
bool sprites_are_broken;
bool cursors_are_broken;
bool atomic_modeset;
bool use_pixman;
bool use_pixman_shadow;
struct udev_input input;
int32_t cursor_width;
int32_t cursor_height;
uint32_t pageflip_timeout;
bool shutting_down;
bool aspect_ratio_supported;
bool fb_modifiers;
struct weston_log_scope *debug;
};
@@ -373,7 +389,7 @@ struct drm_edid {
* output state will complete and be retired separately.
*/
struct drm_pending_state {
struct drm_backend *backend;
struct drm_device *device;
struct wl_list output_list;
};
@@ -396,16 +412,6 @@ struct drm_output_state {
struct wl_list plane_list;
};
/**
* An instance of this class is created each time we believe we have a plane
* suitable to be used by a view as a direct scan-out. The list is initialized
* and populated locally.
*/
struct drm_plane_zpos {
struct drm_plane *plane;
struct wl_list link; /**< :candidate_plane_zpos_list */
};
/**
* Plane state holds the dynamic state for a plane: where it is positioned,
* and which buffer it is currently displaying.
@@ -461,7 +467,7 @@ struct drm_plane_state {
struct drm_plane {
struct weston_plane base;
struct drm_backend *backend;
struct drm_device *device;
enum wdrm_plane_type type;
@@ -483,7 +489,7 @@ struct drm_plane {
};
struct drm_connector {
struct drm_backend *backend;
struct drm_device *device;
drmModeConnector *conn;
uint32_t connector_id;
@@ -495,16 +501,15 @@ struct drm_connector {
};
struct drm_writeback {
/* drm_backend::writeback_connector_list */
/* drm_device::writeback_connector_list */
struct wl_list link;
struct drm_backend *backend;
struct drm_device *device;
struct drm_connector connector;
};
struct drm_head {
struct weston_head base;
struct drm_backend *backend;
struct drm_connector connector;
struct drm_edid edid;
@@ -512,13 +517,17 @@ struct drm_head {
struct backlight *backlight;
drmModeModeInfo inherited_mode; /**< Original mode on the connector */
uint32_t inherited_max_bpc; /**< Original max_bpc on the connector */
uint32_t inherited_crtc_id; /**< Original CRTC assignment */
/* drm_output::disable_head */
struct wl_list disable_head_link;
};
struct drm_crtc {
/* drm_backend::crtc_list */
/* drm_device::crtc_list */
struct wl_list link;
struct drm_backend *backend;
struct drm_device *device;
/* The output driven by the CRTC */
struct drm_output *output;
@@ -532,14 +541,18 @@ struct drm_crtc {
struct drm_output {
struct weston_output base;
struct drm_backend *backend;
struct drm_device *device;
struct drm_crtc *crtc;
/* drm_head::disable_head_link */
struct wl_list disable_head;
bool page_flip_pending;
bool atomic_complete_pending;
bool destroy_pending;
bool disable_pending;
bool dpms_off_pending;
bool mode_switch_pending;
uint32_t gbm_cursor_handle[2];
struct drm_fb *gbm_cursor_fb[2];
@@ -552,6 +565,11 @@ struct drm_output {
uint32_t gbm_format;
uint32_t gbm_bo_flags;
uint32_t hdr_output_metadata_blob_id;
uint64_t ackd_color_outcome_serial;
unsigned max_bpc;
/* Plane being displayed directly on the CRTC */
struct drm_plane *scanout_plane;
@@ -572,19 +590,36 @@ struct drm_output {
struct wl_event_source *pageflip_timer;
bool virtual;
void (*virtual_destroy)(struct weston_output *base);
submit_frame_cb virtual_submit_frame;
};
void
drm_head_destroy(struct weston_head *head_base);
static inline struct drm_head *
to_drm_head(struct weston_head *base)
{
if (base->backend_id != drm_head_destroy)
return NULL;
return container_of(base, struct drm_head, base);
}
void
drm_output_destroy(struct weston_output *output_base);
void
drm_virtual_output_destroy(struct weston_output *output_base);
static inline struct drm_output *
to_drm_output(struct weston_output *base)
{
if (
#ifdef BUILD_DRM_VIRTUAL
base->destroy != drm_virtual_output_destroy &&
#endif
base->destroy != drm_output_destroy)
return NULL;
return container_of(base, struct drm_output, base);
}
@@ -617,7 +652,7 @@ drm_output_get_plane_type_name(struct drm_plane *p)
}
struct drm_crtc *
drm_crtc_find(struct drm_backend *b, uint32_t crtc_id);
drm_crtc_find(struct drm_device *device, uint32_t crtc_id);
struct drm_head *
drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id);
@@ -642,7 +677,7 @@ drm_view_transform_supported(struct weston_view *ev, struct weston_output *outpu
}
int
drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode);
drm_mode_ensure_blob(struct drm_device *device, struct drm_mode *mode);
struct drm_mode *
drm_output_choose_mode(struct drm_output *output,
@@ -651,7 +686,7 @@ void
update_head_from_connector(struct drm_head *head);
void
drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list);
drm_mode_list_destroy(struct drm_device *device, struct wl_list *mode_list);
void
drm_output_print_modes(struct drm_output *output);
@@ -662,7 +697,7 @@ drm_output_set_mode(struct weston_output *base,
const char *modeline);
void
drm_property_info_populate(struct drm_backend *b,
drm_property_info_populate(struct drm_device *device,
const struct drm_property_info *src,
struct drm_property_info *info,
unsigned int num_infos,
@@ -690,7 +725,7 @@ extern const struct drm_property_info connector_props[];
extern const struct drm_property_info crtc_props[];
int
init_kms_caps(struct drm_backend *b);
init_kms_caps(struct drm_device *device);
int
drm_pending_state_test(struct drm_pending_state *pending_state);
@@ -717,15 +752,18 @@ void
drm_fb_unref(struct drm_fb *fb);
struct drm_fb *
drm_fb_create_dumb(struct drm_backend *b, int width, int height,
drm_fb_create_dumb(struct drm_device *device, int width, int height,
uint32_t format);
struct drm_fb *
drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_device *device,
bool is_opaque, enum drm_fb_type type);
void
drm_output_set_cursor_view(struct drm_output *output, struct weston_view *ev);
int
drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output);
#ifdef BUILD_DRM_GBM
extern struct drm_fb *
drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
@@ -749,7 +787,7 @@ drm_can_scanout_dmabuf(struct weston_compositor *ec,
#endif
struct drm_pending_state *
drm_pending_state_alloc(struct drm_backend *backend);
drm_pending_state_alloc(struct drm_device *device);
void
drm_pending_state_free(struct drm_pending_state *pending_state);
struct drm_output_state *
@@ -800,7 +838,7 @@ void
drm_plane_reset_state(struct drm_plane *plane);
void
drm_assign_planes(struct weston_output *output_base, void *repaint_data);
drm_assign_planes(struct weston_output *output_base);
bool
drm_plane_is_available(struct drm_plane *plane, struct drm_output *output);
@@ -837,9 +875,6 @@ drm_output_fini_egl(struct drm_output *output);
struct drm_fb *
drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage);
void
renderer_switch_binding(struct weston_keyboard *keyboard,
const struct timespec *time, uint32_t key, void *data);
#else
inline static int
init_egl(struct drm_backend *b)
@@ -864,11 +899,4 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
{
return NULL;
}
inline static void
renderer_switch_binding(struct weston_keyboard *keyboard,
const struct timespec *time, uint32_t key, void *data)
{
weston_log("Compiled without GBM/EGL support\n");
}
#endif
+46 -18
View File
@@ -47,7 +47,7 @@
* CRTC's. Also, as this is a fake CRTC, it will not try to populate props.
*/
static struct drm_crtc *
drm_virtual_crtc_create(struct drm_backend *b, struct drm_output *output)
drm_virtual_crtc_create(struct drm_device *device, struct drm_output *output)
{
struct drm_crtc *crtc;
@@ -55,7 +55,7 @@ drm_virtual_crtc_create(struct drm_backend *b, struct drm_output *output)
if (!crtc)
return NULL;
crtc->backend = b;
crtc->device = device;
crtc->output = output;
crtc->crtc_id = 0;
@@ -81,17 +81,32 @@ drm_virtual_crtc_destroy(struct drm_crtc *crtc)
free(crtc);
}
static uint32_t
get_drm_plane_index_maximum(struct drm_device *device)
{
uint32_t max = 0;
struct drm_plane *p;
wl_list_for_each(p, &device->plane_list, link) {
if (p->plane_idx > max)
max = p->plane_idx;
}
return max;
}
/**
* Create a drm_plane for virtual output
*
* Call drm_virtual_plane_destroy to clean up the plane.
*
* @param b DRM compositor backend
* @param device DRM device
* @param output Output to create internal plane for
*/
static struct drm_plane *
drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output)
drm_virtual_plane_create(struct drm_device *device, struct drm_output *output)
{
struct drm_backend *b = device->backend;
struct drm_plane *plane;
struct weston_drm_format *fmt;
uint64_t mod;
@@ -103,7 +118,7 @@ drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output)
}
plane->type = WDRM_PLANE_TYPE_PRIMARY;
plane->backend = b;
plane->device = device;
plane->state_cur = drm_plane_state_alloc(NULL, plane);
plane->state_cur->complete = true;
@@ -115,7 +130,7 @@ drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output)
/* If output supports linear modifier, we add it to the plane.
* Otherwise we add DRM_FORMAT_MOD_INVALID, as explicit modifiers
* are not supported. */
if ((output->gbm_bo_flags & GBM_BO_USE_LINEAR) && b->fb_modifiers)
if ((output->gbm_bo_flags & GBM_BO_USE_LINEAR) && device->fb_modifiers)
mod = DRM_FORMAT_MOD_LINEAR;
else
mod = DRM_FORMAT_MOD_INVALID;
@@ -124,7 +139,8 @@ drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output)
goto err;
weston_plane_init(&plane->base, b->compositor, 0, 0);
wl_list_insert(&b->plane_list, &plane->link);
plane->plane_idx = get_drm_plane_index_maximum(device) + 1;
wl_list_insert(&device->plane_list, &plane->link);
return plane;
@@ -163,11 +179,10 @@ static int
drm_virtual_output_submit_frame(struct drm_output *output,
struct drm_fb *fb)
{
struct drm_backend *b = to_drm_backend(output->base.compositor);
int fd, ret;
assert(fb->num_planes == 1);
ret = drmPrimeHandleToFD(b->drm.fd, fb->handles[0], DRM_CLOEXEC, &fd);
ret = drmPrimeHandleToFD(fb->fd, fb->handles[0], DRM_CLOEXEC, &fd);
if (ret) {
weston_log("drmPrimeHandleFD failed, errno=%d\n", errno);
return -1;
@@ -185,17 +200,20 @@ drm_virtual_output_submit_frame(struct drm_output *output,
static int
drm_virtual_output_repaint(struct weston_output *output_base,
pixman_region32_t *damage,
void *repaint_data)
pixman_region32_t *damage)
{
struct drm_pending_state *pending_state = repaint_data;
struct drm_output_state *state = NULL;
struct drm_output *output = to_drm_output(output_base);
struct drm_plane *scanout_plane = output->scanout_plane;
struct drm_plane_state *scanout_state;
struct drm_pending_state *pending_state;
struct drm_device *device;
assert(output->virtual);
device = output->device;
pending_state = device->repaint_data;
if (output->disable_pending || output->destroy_pending)
goto err;
@@ -242,7 +260,7 @@ drm_virtual_output_deinit(struct weston_output *base)
drm_virtual_crtc_destroy(output->crtc);
}
static void
void
drm_virtual_output_destroy(struct weston_output *base)
{
struct drm_output *output = to_drm_output(base);
@@ -256,6 +274,9 @@ drm_virtual_output_destroy(struct weston_output *base)
drm_output_state_free(output->state_cur);
if (output->virtual_destroy)
output->virtual_destroy(base);
free(output);
}
@@ -263,7 +284,8 @@ static int
drm_virtual_output_enable(struct weston_output *output_base)
{
struct drm_output *output = to_drm_output(output_base);
struct drm_backend *b = to_drm_backend(output_base->compositor);
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
assert(output->virtual);
@@ -277,7 +299,7 @@ drm_virtual_output_enable(struct weston_output *output_base)
goto err;
}
output->scanout_plane = drm_virtual_plane_create(b, output);
output->scanout_plane = drm_virtual_plane_create(device, output);
if (!output->scanout_plane) {
weston_log("Failed to find primary plane for output %s\n",
output->base.name);
@@ -320,22 +342,27 @@ drm_virtual_output_disable(struct weston_output *base)
}
static struct weston_output *
drm_virtual_output_create(struct weston_compositor *c, char *name)
drm_virtual_output_create(struct weston_compositor *c, char *name,
void (*destroy_func)(struct weston_output *))
{
struct drm_output *output;
struct drm_backend *b = to_drm_backend(c);
/* Always use the main device for virtual outputs */
struct drm_device *device = b->drm;
output = zalloc(sizeof *output);
if (!output)
return NULL;
output->crtc = drm_virtual_crtc_create(b, output);
output->device = device;
output->crtc = drm_virtual_crtc_create(device, output);
if (!output->crtc) {
free(output);
return NULL;
}
output->virtual = true;
output->virtual_destroy = destroy_func;
output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING;
weston_output_init(&output->base, c, name);
@@ -357,7 +384,8 @@ drm_virtual_output_set_gbm_format(struct weston_output *base,
const char *gbm_format)
{
struct drm_output *output = to_drm_output(base);
struct drm_backend *b = to_drm_backend(base->compositor);
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
output->gbm_format = b->gbm_format;
File diff suppressed because it is too large Load Diff
+72 -46
View File
@@ -69,7 +69,7 @@ drm_fb_destroy_dumb(struct drm_fb *fb)
}
static int
drm_fb_addfb(struct drm_backend *b, struct drm_fb *fb)
drm_fb_addfb(struct drm_device *device, struct drm_fb *fb)
{
int ret = -EINVAL;
uint64_t mods[4] = { };
@@ -77,7 +77,7 @@ drm_fb_addfb(struct drm_backend *b, struct drm_fb *fb)
/* If we have a modifier set, we must only use the WithModifiers
* entrypoint; we cannot import it through legacy ioctls. */
if (b->fb_modifiers && fb->modifier != DRM_FORMAT_MOD_INVALID) {
if (device->fb_modifiers && fb->modifier != DRM_FORMAT_MOD_INVALID) {
/* KMS demands that if a modifier is set, it must be the same
* for all planes. */
for (i = 0; i < ARRAY_LENGTH(mods) && fb->handles[i]; i++)
@@ -98,7 +98,7 @@ drm_fb_addfb(struct drm_backend *b, struct drm_fb *fb)
/* Legacy AddFB can't always infer the format from depth/bpp alone, so
* check if our format is one of the lucky ones. */
if (!fb->format->depth || !fb->format->bpp)
if (!fb->format->addfb_legacy_depth || !fb->format->bpp)
return ret;
/* Cannot fall back to AddFB for multi-planar formats either. */
@@ -106,13 +106,13 @@ drm_fb_addfb(struct drm_backend *b, struct drm_fb *fb)
return ret;
ret = drmModeAddFB(fb->fd, fb->width, fb->height,
fb->format->depth, fb->format->bpp,
fb->format->addfb_legacy_depth, fb->format->bpp,
fb->strides[0], fb->handles[0], &fb->fb_id);
return ret;
}
struct drm_fb *
drm_fb_create_dumb(struct drm_backend *b, int width, int height,
drm_fb_create_dumb(struct drm_device *device, int width, int height,
uint32_t format)
{
struct drm_fb *fb;
@@ -134,7 +134,7 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
goto err_fb;
}
if (!fb->format->depth || !fb->format->bpp) {
if (!fb->format->addfb_legacy_depth || !fb->format->bpp) {
weston_log("format 0x%lx is not compatible with dumb buffers\n",
(unsigned long) format);
goto err_fb;
@@ -145,7 +145,7 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
create_arg.width = width;
create_arg.height = height;
ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
ret = drmIoctl(device->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
if (ret)
goto err_fb;
@@ -157,9 +157,9 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
fb->size = create_arg.size;
fb->width = width;
fb->height = height;
fb->fd = b->drm.fd;
fb->fd = device->drm.fd;
if (drm_fb_addfb(b, fb) != 0) {
if (drm_fb_addfb(device, fb) != 0) {
weston_log("failed to create kms fb: %s\n", strerror(errno));
goto err_bo;
}
@@ -171,18 +171,18 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
goto err_add_fb;
fb->map = mmap(NULL, fb->size, PROT_WRITE,
MAP_SHARED, b->drm.fd, map_arg.offset);
MAP_SHARED, device->drm.fd, map_arg.offset);
if (fb->map == MAP_FAILED)
goto err_add_fb;
return fb;
err_add_fb:
drmModeRmFB(b->drm.fd, fb->fb_id);
drmModeRmFB(device->drm.fd, fb->fb_id);
err_bo:
memset(&destroy_arg, 0, sizeof(destroy_arg));
destroy_arg.handle = create_arg.handle;
drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
drmIoctl(device->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
err_fb:
free(fb);
return NULL;
@@ -218,7 +218,7 @@ drm_fb_destroy_dmabuf(struct drm_fb *fb)
static struct drm_fb *
drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
struct drm_backend *backend, bool is_opaque,
struct drm_device *device, bool is_opaque,
uint32_t *try_view_on_plane_failure_reasons)
{
#ifndef HAVE_GBM_FD_IMPORT
@@ -227,6 +227,7 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
* of GBM_BO_IMPORT_FD_MODIFIER. */
return NULL;
#else
struct drm_backend *backend = device->backend;
struct drm_fb *fb;
int i;
struct gbm_import_fd_modifier_data import_mod = {
@@ -287,7 +288,7 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
fb->height = dmabuf->attributes.height;
fb->modifier = dmabuf->attributes.modifier[0];
fb->size = 0;
fb->fd = backend->drm.fd;
fb->fd = device->drm.fd;
ARRAY_COPY(fb->strides, dmabuf->attributes.stride);
ARRAY_COPY(fb->offsets, dmabuf->attributes.offset);
@@ -302,10 +303,10 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
if (is_opaque)
fb->format = pixel_format_get_opaque_substitute(fb->format);
if (backend->min_width > fb->width ||
fb->width > backend->max_width ||
backend->min_height > fb->height ||
fb->height > backend->max_height) {
if (device->min_width > fb->width ||
fb->width > device->max_width ||
device->min_height > fb->height ||
fb->height > device->max_height) {
weston_log("bo geometry out of bounds\n");
goto err_free;
}
@@ -315,12 +316,15 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
union gbm_bo_handle handle;
handle = gbm_bo_get_handle_for_plane(fb->bo, i);
if (handle.s32 == -1)
if (handle.s32 == -1) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_GBM_BO_GET_HANDLE_FAILED;
goto err_free;
}
fb->handles[i] = handle.u32;
}
if (drm_fb_addfb(backend, fb) != 0) {
if (drm_fb_addfb(device, fb) != 0) {
if (try_view_on_plane_failure_reasons)
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_ADD_FB_FAILED;
@@ -336,7 +340,7 @@ err_free:
}
struct drm_fb *
drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_device *device,
bool is_opaque, enum drm_fb_type type)
{
struct drm_fb *fb = gbm_bo_get_user_data(bo);
@@ -356,7 +360,7 @@ drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
fb->type = type;
fb->refcnt = 1;
fb->bo = bo;
fb->fd = backend->drm.fd;
fb->fd = device->drm.fd;
fb->width = gbm_bo_get_width(bo);
fb->height = gbm_bo_get_height(bo);
@@ -389,15 +393,15 @@ drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
if (is_opaque)
fb->format = pixel_format_get_opaque_substitute(fb->format);
if (backend->min_width > fb->width ||
fb->width > backend->max_width ||
backend->min_height > fb->height ||
fb->height > backend->max_height) {
if (device->min_width > fb->width ||
fb->width > device->max_width ||
device->min_height > fb->height ||
fb->height > device->max_height) {
weston_log("bo geometry out of bounds\n");
goto err_free;
}
if (drm_fb_addfb(backend, fb) != 0) {
if (drm_fb_addfb(device, fb) != 0) {
if (type == BUFFER_GBM_SURFACE)
weston_log("failed to create kms fb: %s\n",
strerror(errno));
@@ -453,22 +457,25 @@ drm_can_scanout_dmabuf(struct weston_compositor *ec,
{
struct drm_fb *fb;
struct drm_backend *b = to_drm_backend(ec);
struct drm_device *device = b->drm;
bool ret = false;
uint32_t try_reason = 0x0;
fb = drm_fb_get_from_dmabuf(dmabuf, b, true, NULL);
fb = drm_fb_get_from_dmabuf(dmabuf, device, true, &try_reason);
if (fb)
ret = true;
drm_fb_unref(fb);
drm_debug(b, "[dmabuf] dmabuf %p, import test %s\n", dmabuf,
ret ? "succeeded" : "failed");
drm_debug(b, "[dmabuf] dmabuf %p, import test %s, with reason 0x%x\n", dmabuf,
ret ? "succeeded" : "failed", try_reason);
return ret;
}
static bool
drm_fb_compatible_with_plane(struct drm_fb *fb, struct drm_plane *plane)
{
struct drm_backend *b = plane->backend;
struct drm_device *device = plane->device;
struct drm_backend *b = device->backend;
struct weston_drm_format *fmt;
/* Check whether the format is supported */
@@ -508,6 +515,8 @@ drm_fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
struct drm_buffer_fb *buf_fb =
container_of(listener, struct drm_buffer_fb, buffer_destroy_listener);
wl_list_remove(&buf_fb->buffer_destroy_listener.link);
if (buf_fb->fb) {
assert(buf_fb->fb->type == BUFFER_CLIENT ||
buf_fb->fb->type == BUFFER_DMABUF);
@@ -523,25 +532,36 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
{
struct drm_output *output = state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
struct drm_buffer_fb *buf_fb;
bool is_opaque = weston_view_is_opaque(ev, &ev->transform.boundingbox);
struct linux_dmabuf_buffer *dmabuf;
struct drm_fb *fb;
struct drm_plane *plane;
if (ev->alpha != 1.0f)
if (ev->alpha != 1.0f) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_GLOBAL_ALPHA;
return NULL;
}
if (!drm_view_transform_supported(ev, &output->base))
if (!drm_view_transform_supported(ev, &output->base)) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_INCOMPATIBLE_TRANSFORM;
return NULL;
}
if (ev->surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_ENFORCED &&
ev->surface->desired_protection > output->base.current_protection)
ev->surface->desired_protection > output->base.current_protection) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_INADEQUATE_CONTENT_PROTECTION;
return NULL;
}
if (!buffer)
if (!buffer) {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_NO_BUFFER;
return NULL;
}
if (buffer->backend_private) {
buf_fb = buffer->backend_private;
@@ -554,20 +574,18 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
buf_fb->buffer_destroy_listener.notify = drm_fb_handle_buffer_destroy;
wl_signal_add(&buffer->destroy_signal, &buf_fb->buffer_destroy_listener);
if (wl_shm_buffer_get(buffer->resource))
goto unsuitable;
/* GBM is used for dmabuf import as well as from client wl_buffer. */
if (!b->gbm)
if (!b->gbm) {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_NO_GBM;
goto unsuitable;
}
dmabuf = linux_dmabuf_buffer_get(buffer->resource);
if (dmabuf) {
fb = drm_fb_get_from_dmabuf(dmabuf, b, is_opaque,
if (buffer->type == WESTON_BUFFER_DMABUF) {
fb = drm_fb_get_from_dmabuf(buffer->dmabuf, device, is_opaque,
&buf_fb->failure_reasons);
if (!fb)
goto unsuitable;
} else {
} else if (buffer->type == WESTON_BUFFER_RENDERER_OPAQUE) {
struct gbm_bo *bo;
bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
@@ -575,16 +593,24 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
if (!bo)
goto unsuitable;
fb = drm_fb_get_from_bo(bo, b, is_opaque, BUFFER_CLIENT);
fb = drm_fb_get_from_bo(bo, device, is_opaque, BUFFER_CLIENT);
if (!fb) {
*try_view_on_plane_failure_reasons |=
(1 << FAILURE_REASONS_ADD_FB_FAILED);
gbm_bo_destroy(bo);
goto unsuitable;
}
} else {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_BUFFER_TYPE;
goto unsuitable;
}
/* Check if this buffer can ever go on any planes. If it can't, we have
* no reason to ever have a drm_fb, so we fail it here. */
wl_list_for_each(plane, &b->plane_list, link) {
wl_list_for_each(plane, &device->plane_list, link) {
/* only SHM buffers can go into cursor planes */
if (plane->type == WDRM_PLANE_TYPE_CURSOR)
continue;
if (drm_fb_compatible_with_plane(fb, plane))
fb->plane_mask |= (1 << plane->plane_idx);
}
+178
View File
@@ -0,0 +1,178 @@
/*
* Copyright 2021-2022 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdint.h>
#include <libweston/libweston.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include "drm-internal.h"
static inline uint16_t
color_xy_to_u16(float v)
{
assert(v >= 0.0f);
assert(v <= 1.0f);
/*
* CTA-861-G
* 6.9.1 Static Metadata Type 1
* chromaticity coordinate encoding
*/
return (uint16_t)round(v * 50000.0);
}
static inline uint16_t
nits_to_u16(float nits)
{
assert(nits >= 1.0f);
assert(nits <= 65535.0f);
/*
* CTA-861-G
* 6.9.1 Static Metadata Type 1
* max display mastering luminance, max content light level,
* max frame-average light level
*/
return (uint16_t)round(nits);
}
static inline uint16_t
nits_to_u16_dark(float nits)
{
assert(nits >= 0.0001f);
assert(nits <= 6.5535f);
/*
* CTA-861-G
* 6.9.1 Static Metadata Type 1
* min display mastering luminance
*/
return (uint16_t)round(nits * 10000.0);
}
static void
weston_hdr_metadata_type1_to_kms(struct hdr_metadata_infoframe *dst,
const struct weston_hdr_metadata_type1 *src)
{
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES) {
unsigned i;
for (i = 0; i < 3; i++) {
dst->display_primaries[i].x = color_xy_to_u16(src->primary[i].x);
dst->display_primaries[i].y = color_xy_to_u16(src->primary[i].y);
}
}
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_WHITE) {
dst->white_point.x = color_xy_to_u16(src->white.x);
dst->white_point.y = color_xy_to_u16(src->white.y);
}
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML)
dst->max_display_mastering_luminance = nits_to_u16(src->maxDML);
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MINDML)
dst->min_display_mastering_luminance = nits_to_u16_dark(src->minDML);
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL)
dst->max_cll = nits_to_u16(src->maxCLL);
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL)
dst->max_fall = nits_to_u16(src->maxFALL);
}
int
drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output)
{
struct drm_device *device = output->device;
const struct weston_hdr_metadata_type1 *src;
struct hdr_output_metadata meta;
uint32_t blob_id = 0;
int ret;
if (output->hdr_output_metadata_blob_id &&
output->ackd_color_outcome_serial == output->base.color_outcome_serial)
return 0;
src = weston_output_get_hdr_metadata_type1(&output->base);
/*
* Set up the data for Dynamic Range and Mastering InfoFrame,
* CTA-861-G, a.k.a the static HDR metadata.
*/
memset(&meta, 0, sizeof meta);
meta.metadata_type = 0; /* Static Metadata Type 1 */
/* Duplicated field in UABI struct */
meta.hdmi_metadata_type1.metadata_type = meta.metadata_type;
switch (output->base.eotf_mode) {
case WESTON_EOTF_MODE_NONE:
assert(0 && "bad eotf_mode: none");
return -1;
case WESTON_EOTF_MODE_SDR:
/*
* Do not send any static HDR metadata. Video sinks should
* respond by switching to traditional SDR mode. If they
* do not, the kernel should fix that up.
*/
assert(output->hdr_output_metadata_blob_id == 0);
return 0;
case WESTON_EOTF_MODE_TRADITIONAL_HDR:
meta.hdmi_metadata_type1.eotf = 1; /* from CTA-861-G */
break;
case WESTON_EOTF_MODE_ST2084:
meta.hdmi_metadata_type1.eotf = 2; /* from CTA-861-G */
weston_hdr_metadata_type1_to_kms(&meta.hdmi_metadata_type1, src);
break;
case WESTON_EOTF_MODE_HLG:
meta.hdmi_metadata_type1.eotf = 3; /* from CTA-861-G */
break;
}
if (meta.hdmi_metadata_type1.eotf == 0) {
assert(0 && "bad eotf_mode");
return -1;
}
ret = drmModeCreatePropertyBlob(device->drm.fd,
&meta, sizeof meta, &blob_id);
if (ret != 0) {
weston_log("Error: failed to create KMS blob for HDR metadata on output '%s': %s\n",
output->base.name, strerror(-ret));
return -1;
}
drmModeDestroyPropertyBlob(device->drm.fd,
output->hdr_output_metadata_blob_id);
output->hdr_output_metadata_blob_id = blob_id;
output->ackd_color_outcome_serial = output->base.color_outcome_serial;
return 0;
}
+180 -133
View File
@@ -143,6 +143,10 @@ const struct drm_property_info connector_props[] = {
.enum_values = panel_orientation_enums,
.num_enum_values = WDRM_PANEL_ORIENTATION__COUNT,
},
[WDRM_CONNECTOR_HDR_OUTPUT_METADATA] = {
.name = "HDR_OUTPUT_METADATA",
},
[WDRM_CONNECTOR_MAX_BPC] = { .name = "max bpc", },
};
const struct drm_property_info crtc_props[] = {
@@ -272,14 +276,14 @@ drm_property_get_range_values(struct drm_property_info *info,
* The values given in enum_names are searched for, and stored in the
* same-indexed field of the map array.
*
* @param b DRM backend object
* @param device DRM device object
* @param src DRM property info array to source from
* @param info DRM property info array to copy into
* @param num_infos Number of entries in the source array
* @param props DRM object properties for the object
*/
void
drm_property_info_populate(struct drm_backend *b,
drm_property_info_populate(struct drm_device *device,
const struct drm_property_info *src,
struct drm_property_info *info,
unsigned int num_infos,
@@ -311,7 +315,7 @@ drm_property_info_populate(struct drm_backend *b,
for (i = 0; i < props->count_props; i++) {
unsigned int k;
prop = drmModeGetProperty(b->drm.fd, props->props[i]);
prop = drmModeGetProperty(device->drm.fd, props->props[i]);
if (!prop)
continue;
@@ -411,19 +415,6 @@ drm_property_info_free(struct drm_property_info *info, int num_props)
memset(info, 0, sizeof(*info) * num_props);
}
static inline uint32_t *
formats_ptr(struct drm_format_modifier_blob *blob)
{
return (uint32_t *)(((char *)blob) + blob->formats_offset);
}
static inline struct drm_format_modifier *
modifiers_ptr(struct drm_format_modifier_blob *blob)
{
return (struct drm_format_modifier *)
(((char *)blob) + blob->modifiers_offset);
}
/**
* Populates the plane's formats array, using either the IN_FORMATS blob
* property (if available), or the plane's format list if not.
@@ -433,13 +424,11 @@ drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
const drmModeObjectProperties *props,
const bool use_modifiers)
{
unsigned i, j;
struct drm_device *device = plane->device;
uint32_t i, blob_id, fmt_prev = DRM_FORMAT_INVALID;
drmModeFormatModifierIterator drm_iter = {0};
struct weston_drm_format *fmt = NULL;
drmModePropertyBlobRes *blob = NULL;
struct drm_format_modifier_blob *fmt_mod_blob;
struct drm_format_modifier *blob_modifiers;
uint32_t *blob_formats;
uint32_t blob_id;
struct weston_drm_format *fmt;
int ret = 0;
if (!use_modifiers)
@@ -451,39 +440,26 @@ drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
if (blob_id == 0)
goto fallback;
blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id);
blob = drmModeGetPropertyBlob(device->drm.fd, blob_id);
if (!blob)
goto fallback;
fmt_mod_blob = blob->data;
blob_formats = formats_ptr(fmt_mod_blob);
blob_modifiers = modifiers_ptr(fmt_mod_blob);
assert(kplane->count_formats == fmt_mod_blob->count_formats);
for (i = 0; i < fmt_mod_blob->count_formats; i++) {
fmt = weston_drm_format_array_add_format(&plane->formats,
blob_formats[i]);
if (!fmt) {
ret = -1;
goto out;
}
for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
struct drm_format_modifier *mod = &blob_modifiers[j];
if ((i < mod->offset) || (i > mod->offset + 63))
continue;
if (!(mod->formats & (1 << (i - mod->offset))))
continue;
ret = weston_drm_format_add_modifier(fmt, mod->modifier);
if (ret < 0)
while (drmModeFormatModifierBlobIterNext(blob, &drm_iter)) {
if (fmt_prev != drm_iter.fmt) {
fmt = weston_drm_format_array_add_format(&plane->formats,
drm_iter.fmt);
if (!fmt) {
ret = -1;
goto out;
}
fmt_prev = drm_iter.fmt;
}
if (fmt->modifiers.size == 0)
weston_drm_format_array_remove_latest_format(&plane->formats);
ret = weston_drm_format_add_modifier(fmt, drm_iter.mod);
if (ret < 0)
goto out;
}
out:
@@ -510,14 +486,15 @@ drm_output_set_gamma(struct weston_output *output_base,
{
int rc;
struct drm_output *output = to_drm_output(output_base);
struct drm_backend *backend =
to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
assert(output);
/* check */
if (output_base->gamma_size != size)
return;
rc = drmModeCrtcSetGamma(backend->drm.fd,
rc = drmModeCrtcSetGamma(device->drm.fd,
output->crtc->crtc_id,
size, r, g, b);
if (rc)
@@ -535,7 +512,8 @@ drm_output_assign_state(struct drm_output_state *state,
enum drm_state_apply_mode mode)
{
struct drm_output *output = state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_plane_state *plane_state;
struct drm_head *head;
@@ -552,13 +530,13 @@ drm_output_assign_state(struct drm_output_state *state,
output->state_cur = state;
if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
if (device->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
drm_debug(b, "\t[CRTC:%u] setting pending flip\n",
output->crtc->crtc_id);
output->atomic_complete_pending = true;
}
if (b->atomic_modeset &&
if (device->atomic_modeset &&
state->protection == WESTON_HDCP_DISABLE)
wl_list_for_each(head, &output->base.head_list, base.output_link)
weston_head_set_content_protection_status(&head->base,
@@ -580,7 +558,7 @@ drm_output_assign_state(struct drm_output_state *state,
continue;
}
if (b->atomic_modeset)
if (device->atomic_modeset)
continue;
assert(plane->type != WDRM_PLANE_TYPE_OVERLAY);
@@ -593,7 +571,7 @@ static void
drm_output_set_cursor(struct drm_output_state *output_state)
{
struct drm_output *output = output_state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
struct drm_crtc *crtc = output->crtc;
struct drm_plane *plane = output->cursor_plane;
struct drm_plane_state *state;
@@ -609,7 +587,7 @@ drm_output_set_cursor(struct drm_output_state *output_state)
if (!state->fb) {
pixman_region32_fini(&plane->base.damage);
pixman_region32_init(&plane->base.damage);
drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
drmModeSetCursor(device->drm.fd, crtc->crtc_id, 0, 0, 0);
return;
}
@@ -618,8 +596,8 @@ drm_output_set_cursor(struct drm_output_state *output_state)
handle = output->gbm_cursor_handle[output->current_cursor];
if (plane->state_cur->fb != state->fb) {
if (drmModeSetCursor(b->drm.fd, crtc->crtc_id, handle,
b->cursor_width, b->cursor_height)) {
if (drmModeSetCursor(device->drm.fd, crtc->crtc_id, handle,
device->cursor_width, device->cursor_height)) {
weston_log("failed to set cursor: %s\n",
strerror(errno));
goto err;
@@ -629,7 +607,7 @@ drm_output_set_cursor(struct drm_output_state *output_state)
pixman_region32_fini(&plane->base.damage);
pixman_region32_init(&plane->base.damage);
if (drmModeMoveCursor(b->drm.fd, crtc->crtc_id,
if (drmModeMoveCursor(device->drm.fd, crtc->crtc_id,
state->dest_x, state->dest_y)) {
weston_log("failed to move cursor: %s\n", strerror(errno));
goto err;
@@ -638,15 +616,16 @@ drm_output_set_cursor(struct drm_output_state *output_state)
return;
err:
b->cursors_are_broken = true;
drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0);
device->cursors_are_broken = true;
drmModeSetCursor(device->drm.fd, crtc->crtc_id, 0, 0, 0);
}
static int
drm_output_apply_state_legacy(struct drm_output_state *state)
{
struct drm_output *output = state->output;
struct drm_backend *backend = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
struct drm_backend *backend = device->backend;
struct drm_plane *scanout_plane = output->scanout_plane;
struct drm_crtc *crtc = output->crtc;
struct drm_property_info *dpms_prop;
@@ -678,14 +657,14 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
if (state->dpms != WESTON_DPMS_ON) {
if (output->cursor_plane) {
ret = drmModeSetCursor(backend->drm.fd, crtc->crtc_id,
ret = drmModeSetCursor(device->drm.fd, crtc->crtc_id,
0, 0, 0);
if (ret)
weston_log("drmModeSetCursor failed disable: %s\n",
strerror(errno));
}
ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id, 0, 0, 0,
ret = drmModeSetCrtc(device->drm.fd, crtc->crtc_id, 0, 0, 0,
NULL, 0, NULL);
if (ret)
weston_log("drmModeSetCrtc failed disabling: %s\n",
@@ -719,12 +698,12 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
assert(scanout_state->in_fence_fd == -1);
mode = to_drm_mode(output->base.current_mode);
if (backend->state_invalid ||
if (device->state_invalid ||
!scanout_plane->state_cur->fb ||
scanout_plane->state_cur->fb->strides[0] !=
scanout_state->fb->strides[0]) {
ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id,
ret = drmModeSetCrtc(device->drm.fd, crtc->crtc_id,
scanout_state->fb->fb_id,
0, 0,
connectors, n_conn,
@@ -740,7 +719,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
crtc->crtc_id, scanout_state->plane->plane_id,
pinfo ? pinfo->drm_format_name : "UNKNOWN");
if (drmModePageFlip(backend->drm.fd, crtc->crtc_id,
if (drmModePageFlip(device->drm.fd, crtc->crtc_id,
scanout_state->fb->fb_id,
DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
weston_log("queueing pageflip failed: %s\n", strerror(errno));
@@ -761,7 +740,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
if (dpms_prop->prop_id == 0)
continue;
ret = drmModeConnectorSetProperty(backend->drm.fd,
ret = drmModeConnectorSetProperty(device->drm.fd,
head->connector.connector_id,
dpms_prop->prop_id,
state->dpms);
@@ -786,6 +765,8 @@ static int
crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc,
enum wdrm_crtc_property prop, uint64_t val)
{
struct drm_device *device = crtc->device;
struct drm_backend *b = device->backend;
struct drm_property_info *info = &crtc->props_crtc[prop];
int ret;
@@ -794,7 +775,7 @@ crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc,
ret = drmModeAtomicAddProperty(req, crtc->crtc_id, info->prop_id,
val);
drm_debug(crtc->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
(unsigned long) crtc->crtc_id,
(unsigned long) info->prop_id, info->name,
(unsigned long long) val, (unsigned long long) val);
@@ -805,6 +786,8 @@ static int
connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector,
enum wdrm_connector_property prop, uint64_t val)
{
struct drm_device *device = connector->device;
struct drm_backend *b = device->backend;
struct drm_property_info *info = &connector->props[prop];
uint32_t connector_id = connector->connector_id;
int ret;
@@ -813,7 +796,7 @@ connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector,
return -1;
ret = drmModeAtomicAddProperty(req, connector_id, info->prop_id, val);
drm_debug(connector->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
(unsigned long) connector_id,
(unsigned long) info->prop_id, info->name,
(unsigned long long) val, (unsigned long long) val);
@@ -824,6 +807,8 @@ static int
plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
enum wdrm_plane_property prop, uint64_t val)
{
struct drm_device *device = plane->device;
struct drm_backend *b = device->backend;
struct drm_property_info *info = &plane->props[prop];
int ret;
@@ -832,7 +817,7 @@ plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
val);
drm_debug(plane->backend, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
drm_debug(b, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
(unsigned long) plane->plane_id,
(unsigned long) info->prop_id, info->name,
(unsigned long long) val, (unsigned long long) val);
@@ -921,17 +906,52 @@ drm_connector_set_hdcp_property(struct drm_connector *connector,
assert(ret == 0);
}
static int
drm_connector_set_max_bpc(struct drm_connector *connector,
struct drm_output *output,
drmModeAtomicReq *req)
{
const struct drm_property_info *info;
struct drm_head *head;
struct drm_backend *backend = output->device->backend;
uint64_t max_bpc;
uint64_t a, b;
if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_MAX_BPC))
return 0;
if (output->max_bpc == 0) {
/* A value of 0 means that the current max_bpc must be programmed. */
head = drm_head_find_by_connector(backend, connector->connector_id);
max_bpc = head->inherited_max_bpc;
} else {
info = &connector->props[WDRM_CONNECTOR_MAX_BPC];
assert(info->flags & DRM_MODE_PROP_RANGE);
assert(info->num_range_values == 2);
a = info->range_values[0];
b = info->range_values[1];
assert(a <= b);
max_bpc = MAX(a, MIN(output->max_bpc, b));
}
return connector_add_prop(req, connector,
WDRM_CONNECTOR_MAX_BPC, max_bpc);
}
static int
drm_output_apply_state_atomic(struct drm_output_state *state,
drmModeAtomicReq *req,
uint32_t *flags)
{
struct drm_output *output = state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_crtc *crtc = output->crtc;
struct drm_plane_state *plane_state;
struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
struct drm_head *head;
struct drm_head *tmp;
int ret = 0;
drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
@@ -944,7 +964,7 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
}
if (state->dpms == WESTON_DPMS_ON) {
ret = drm_mode_ensure_blob(b, current_mode);
ret = drm_mode_ensure_blob(device, current_mode);
if (ret != 0)
return ret;
@@ -968,12 +988,30 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
wl_list_for_each(head, &output->base.head_list, base.output_link)
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_CRTC_ID, 0);
wl_list_for_each_safe(head, tmp, &output->disable_head,
disable_head_link) {
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_CRTC_ID, 0);
wl_list_remove(&head->disable_head_link);
wl_list_init(&head->disable_head_link);
}
}
wl_list_for_each(head, &output->base.head_list, base.output_link)
wl_list_for_each(head, &output->base.head_list, base.output_link) {
drm_connector_set_hdcp_property(&head->connector,
state->protection, req);
if (drm_connector_has_prop(&head->connector,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA)) {
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
output->hdr_output_metadata_blob_id);
}
ret |= drm_connector_set_max_bpc(&head->connector, output, req);
}
if (ret != 0) {
weston_log("couldn't set atomic CRTC/connector state\n");
return ret;
@@ -1010,9 +1048,9 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
if (plane_state->fb && plane_state->fb->format)
pinfo = plane_state->fb->format;
drm_debug(plane->backend, "\t\t\t[PLANE:%lu] FORMAT: %s\n",
(unsigned long) plane->plane_id,
pinfo ? pinfo->drm_format_name : "UNKNOWN");
drm_debug(b, "\t\t\t[PLANE:%lu] FORMAT: %s\n",
(unsigned long) plane->plane_id,
pinfo ? pinfo->drm_format_name : "UNKNOWN");
if (plane_state->in_fence_fd >= 0) {
ret |= plane_add_prop(req, plane,
@@ -1044,7 +1082,8 @@ static int
drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
enum drm_state_apply_mode mode)
{
struct drm_backend *b = pending_state->backend;
struct drm_device *device = pending_state->device;
struct drm_backend *b = device->backend;
struct drm_output_state *output_state, *tmp;
struct drm_plane *plane;
drmModeAtomicReq *req = drmModeAtomicAlloc();
@@ -1066,7 +1105,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
break;
}
if (b->state_invalid) {
if (device->state_invalid) {
struct weston_head *head_base;
struct drm_head *head;
struct drm_crtc *crtc;
@@ -1082,12 +1121,16 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
wl_list_for_each(head_base,
&b->compositor->head_list, compositor_link) {
struct drm_property_info *info;
head = to_drm_head(head_base);
if (!head)
continue;
if (weston_head_is_enabled(head_base))
continue;
head = to_drm_head(head_base);
connector_id = head->connector.connector_id;
if (head->connector.device != device)
continue;
drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
head_base->name);
@@ -1103,7 +1146,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
ret = -1;
}
wl_list_for_each(crtc, &b->crtc_list, link) {
wl_list_for_each(crtc, &device->crtc_list, link) {
struct drm_property_info *info;
drmModeObjectProperties *props;
uint64_t active;
@@ -1116,7 +1159,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
* off, as the kernel will refuse to generate an event
* for an off->off state and fail the commit.
*/
props = drmModeObjectGetProperties(b->drm.fd,
props = drmModeObjectGetProperties(device->drm.fd,
crtc->crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!props) {
@@ -1139,7 +1182,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
/* Disable all the planes; planes which are being used will
* override this state in the output-state application. */
wl_list_for_each(plane, &b->plane_list, link) {
wl_list_for_each(plane, &device->plane_list, link) {
drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n",
(unsigned long) plane->plane_id);
plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
@@ -1162,7 +1205,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
goto out;
}
ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
ret = drmModeAtomicCommit(device->drm.fd, req, flags, device);
drm_debug(b, "[atomic] drmModeAtomicCommit\n");
/* Test commits do not take ownership of the state; return
@@ -1182,7 +1225,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
link)
drm_output_assign_state(output_state, mode);
b->state_invalid = false;
device->state_invalid = false;
assert(wl_list_empty(&pending_state->output_list));
@@ -1213,9 +1256,9 @@ out:
int
drm_pending_state_test(struct drm_pending_state *pending_state)
{
struct drm_backend *b = pending_state->backend;
struct drm_device *device = pending_state->device;
if (b->atomic_modeset)
if (device->atomic_modeset)
return drm_pending_state_apply_atomic(pending_state,
DRM_STATE_TEST_ONLY);
@@ -1234,24 +1277,25 @@ drm_pending_state_test(struct drm_pending_state *pending_state)
int
drm_pending_state_apply(struct drm_pending_state *pending_state)
{
struct drm_backend *b = pending_state->backend;
struct drm_device *device = pending_state->device;
struct drm_backend *b = device->backend;
struct drm_output_state *output_state, *tmp;
struct drm_crtc *crtc;
if (b->atomic_modeset)
if (device->atomic_modeset)
return drm_pending_state_apply_atomic(pending_state,
DRM_STATE_APPLY_ASYNC);
if (b->state_invalid) {
if (device->state_invalid) {
/* If we need to reset all our state (e.g. because we've
* just started, or just been VT-switched in), explicitly
* disable all the CRTCs we aren't using. This also disables
* all connectors on these CRTCs, so we don't need to do that
* separately with the pre-atomic API. */
wl_list_for_each(crtc, &b->crtc_list, link) {
wl_list_for_each(crtc, &device->crtc_list, link) {
if (crtc->output)
continue;
drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0,
drmModeSetCrtc(device->drm.fd, crtc->crtc_id, 0, 0, 0,
NULL, 0, NULL);
}
}
@@ -1274,7 +1318,7 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
weston_output_repaint_failed(&output->base);
drm_output_state_free(output->state_cur);
output->state_cur = drm_output_state_alloc(output, NULL);
b->state_invalid = true;
device->state_invalid = true;
if (!b->use_pixman) {
drm_output_fini_egl(output);
drm_output_init_egl(output, b);
@@ -1282,7 +1326,7 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
}
}
b->state_invalid = false;
device->state_invalid = false;
assert(wl_list_empty(&pending_state->output_list));
@@ -1301,24 +1345,24 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
int
drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
{
struct drm_backend *b = pending_state->backend;
struct drm_device *device = pending_state->device;
struct drm_output_state *output_state, *tmp;
struct drm_crtc *crtc;
if (b->atomic_modeset)
if (device->atomic_modeset)
return drm_pending_state_apply_atomic(pending_state,
DRM_STATE_APPLY_SYNC);
if (b->state_invalid) {
if (device->state_invalid) {
/* If we need to reset all our state (e.g. because we've
* just started, or just been VT-switched in), explicitly
* disable all the CRTCs we aren't using. This also disables
* all connectors on these CRTCs, so we don't need to do that
* separately with the pre-atomic API. */
wl_list_for_each(crtc, &b->crtc_list, link) {
wl_list_for_each(crtc, &device->crtc_list, link) {
if (crtc->output)
continue;
drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0,
drmModeSetCrtc(device->drm.fd, crtc->crtc_id, 0, 0, 0,
NULL, 0, NULL);
}
}
@@ -1335,7 +1379,7 @@ drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
}
}
b->state_invalid = false;
device->state_invalid = false;
assert(wl_list_empty(&pending_state->output_list));
@@ -1360,14 +1404,14 @@ page_flip_handler(int fd, unsigned int frame,
unsigned int sec, unsigned int usec, void *data)
{
struct drm_output *output = data;
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
drm_output_update_msc(output, frame);
assert(!b->atomic_modeset);
assert(!device->atomic_modeset);
assert(output->page_flip_pending);
output->page_flip_pending = false;
@@ -1378,14 +1422,15 @@ static void
atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
unsigned int usec, unsigned int crtc_id, void *data)
{
struct drm_backend *b = data;
struct drm_device *device = data;
struct drm_backend *b = device->backend;
struct drm_crtc *crtc;
struct drm_output *output;
uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
crtc = drm_crtc_find(b, crtc_id);
crtc = drm_crtc_find(device, crtc_id);
assert(crtc);
output = crtc->output;
@@ -1399,7 +1444,7 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
drm_output_update_msc(output, frame);
drm_debug(b, "[atomic][CRTC:%u] flip processing started\n", crtc_id);
assert(b->atomic_modeset);
assert(device->atomic_modeset);
assert(output->atomic_complete_pending);
output->atomic_complete_pending = false;
@@ -1410,12 +1455,12 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
int
on_drm_input(int fd, uint32_t mask, void *data)
{
struct drm_backend *b = data;
struct drm_device *device = data;
drmEventContext evctx;
memset(&evctx, 0, sizeof evctx);
evctx.version = 3;
if (b->atomic_modeset)
if (device->atomic_modeset)
evctx.page_flip_handler2 = atomic_flip_handler;
else
evctx.page_flip_handler = page_flip_handler;
@@ -1425,61 +1470,63 @@ on_drm_input(int fd, uint32_t mask, void *data)
}
int
init_kms_caps(struct drm_backend *b)
init_kms_caps(struct drm_device *device)
{
struct drm_backend *b = device->backend;
struct weston_compositor *compositor = b->compositor;
uint64_t cap;
int ret;
weston_log("using %s\n", b->drm.filename);
weston_log("using %s\n", device->drm.filename);
ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
ret = drmGetCap(device->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
if (ret != 0 || cap != 1) {
weston_log("Error: kernel DRM KMS does not support DRM_CAP_TIMESTAMP_MONOTONIC.\n");
return -1;
}
if (weston_compositor_set_presentation_clock(b->compositor, CLOCK_MONOTONIC) < 0) {
if (weston_compositor_set_presentation_clock(compositor, CLOCK_MONOTONIC) < 0) {
weston_log("Error: failed to set presentation clock to CLOCK_MONOTONIC.\n");
return -1;
}
ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
ret = drmGetCap(device->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
if (ret == 0)
b->cursor_width = cap;
device->cursor_width = cap;
else
b->cursor_width = 64;
device->cursor_width = 64;
ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
ret = drmGetCap(device->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
if (ret == 0)
b->cursor_height = cap;
device->cursor_height = cap;
else
b->cursor_height = 64;
device->cursor_height = 64;
ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
ret = drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
if (ret) {
weston_log("Error: drm card doesn't support universal planes!\n");
return -1;
}
if (!getenv("WESTON_DISABLE_ATOMIC")) {
ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
ret = drmGetCap(device->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
if (ret != 0)
cap = 0;
ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
b->atomic_modeset = ((ret == 0) && (cap == 1));
ret = drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
device->atomic_modeset = ((ret == 0) && (cap == 1));
}
weston_log("DRM: %s atomic modesetting\n",
b->atomic_modeset ? "supports" : "does not support");
device->atomic_modeset ? "supports" : "does not support");
if (!getenv("WESTON_DISABLE_GBM_MODIFIERS")) {
ret = drmGetCap(b->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
ret = drmGetCap(device->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
if (ret == 0)
b->fb_modifiers = cap;
device->fb_modifiers = cap;
}
weston_log("DRM: %s GBM modifiers\n",
b->fb_modifiers ? "supports" : "does not support");
device->fb_modifiers ? "supports" : "does not support");
drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
/*
* KMS support for hardware planes cannot properly synchronize
@@ -1489,13 +1536,13 @@ init_kms_caps(struct drm_backend *b)
* to a fraction. For cursors, it's not so bad, so they are
* enabled.
*/
if (!b->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
b->sprites_are_broken = true;
if (!device->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
device->sprites_are_broken = true;
ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
b->aspect_ratio_supported = (ret == 0);
ret = drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
device->aspect_ratio_supported = (ret == 0);
weston_log("DRM: %s picture aspect ratio\n",
b->aspect_ratio_supported ? "supports" : "does not support");
device->aspect_ratio_supported ? "supports" : "does not support");
return 0;
}
+19 -8
View File
@@ -53,8 +53,10 @@ static long backlight_get(struct backlight *backlight, char *node)
int fd, value;
long ret;
if (asprintf(&path, "%s/%s", backlight->path, node) < 0)
str_printf(&path, "%s/%s", backlight->path, node);
if (!path)
return -ENOMEM;
fd = open(path, O_RDONLY);
if (fd < 0) {
ret = -1;
@@ -67,6 +69,9 @@ static long backlight_get(struct backlight *backlight, char *node)
goto out;
}
if (buffer[ret - 1] == '\n')
buffer[ret - 1] = '\0';
if (!safe_strtoint(buffer, &value)) {
ret = -1;
goto out;
@@ -103,7 +108,8 @@ long backlight_set_brightness(struct backlight *backlight, long brightness)
int fd;
long ret;
if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0)
str_printf(&path, "%s/%s", backlight->path, "brightness");
if (!path)
return -ENOMEM;
fd = open(path, O_RDWR);
@@ -118,7 +124,8 @@ long backlight_set_brightness(struct backlight *backlight, long brightness)
goto out;
}
if (asprintf(&buffer, "%ld", brightness) < 0) {
str_printf(&buffer, "%ld", brightness);
if (!buffer) {
ret = -1;
goto out;
}
@@ -171,7 +178,8 @@ struct backlight *backlight_init(struct udev_device *drm_device,
if (!syspath)
return NULL;
if (asprintf(&path, "%s/%s", syspath, "device") < 0)
str_printf(&path, "%s/%s", syspath, "device");
if (!path)
return NULL;
ret = readlink(path, buffer, sizeof(buffer) - 1);
@@ -214,11 +222,13 @@ struct backlight *backlight_init(struct udev_device *drm_device,
if (entry->d_name[0] == '.')
continue;
if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight",
entry->d_name) < 0)
str_printf(&backlight_path, "%s/%s", "/sys/class/backlight",
entry->d_name);
if (!backlight_path)
goto err;
if (asprintf(&path, "%s/%s", backlight_path, "type") < 0) {
str_printf(&path, "%s/%s", backlight_path, "type");
if (!path) {
free(backlight_path);
goto err;
}
@@ -255,7 +265,8 @@ struct backlight *backlight_init(struct udev_device *drm_device,
free (path);
if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
str_printf(&path, "%s/%s", backlight_path, "device");
if (!path)
goto err;
ret = readlink(path, buffer, sizeof(buffer) - 1);
+2
View File
@@ -24,6 +24,7 @@ srcs_drm = [
'fb.c',
'modes.c',
'kms.c',
'kms-color.c',
'state-helpers.c',
'state-propose.c',
linux_dmabuf_unstable_v1_protocol_c,
@@ -32,6 +33,7 @@ srcs_drm = [
]
deps_drm = [
dep_libm,
dep_libdl,
dep_libweston_private,
dep_session_helper,
+47 -25
View File
@@ -98,14 +98,15 @@ drm_subpixel_to_wayland(int drm_value)
}
int
drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
drm_mode_ensure_blob(struct drm_device *device, struct drm_mode *mode)
{
struct drm_backend *backend = device->backend;
int ret;
if (mode->blob_id)
return 0;
ret = drmModeCreatePropertyBlob(backend->drm.fd,
ret = drmModeCreatePropertyBlob(device->drm.fd,
&mode->mode_info,
sizeof(mode->mode_info),
&mode->blob_id);
@@ -304,6 +305,8 @@ edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
* \param[out] make The monitor make (PNP ID).
* \param[out] model The monitor model (name).
* \param[out] serial_number The monitor serial number.
* \param[out] eotf_mask The monitor supported EOTF modes, combination of
* enum weston_eotf_mode bits.
*
* Each of \c *make, \c *model and \c *serial_number are set only if the
* information is found in the EDID. The pointers they are set to must not
@@ -315,8 +318,10 @@ find_and_parse_output_edid(struct drm_head *head,
drmModeObjectPropertiesPtr props,
const char **make,
const char **model,
const char **serial_number)
const char **serial_number,
uint32_t *eotf_mask)
{
struct drm_device *device = head->connector.device;
drmModePropertyBlobPtr edid_blob = NULL;
uint32_t blob_id;
int rc;
@@ -328,7 +333,7 @@ find_and_parse_output_edid(struct drm_head *head,
if (!blob_id)
return;
edid_blob = drmModeGetPropertyBlob(head->backend->drm.fd, blob_id);
edid_blob = drmModeGetPropertyBlob(device->drm.fd, blob_id);
if (!edid_blob)
return;
@@ -344,6 +349,21 @@ find_and_parse_output_edid(struct drm_head *head,
*serial_number = head->edid.serial_number;
}
drmModeFreePropertyBlob(edid_blob);
/* TODO: parse this from EDID */
*eotf_mask = WESTON_EOTF_MODE_ALL_MASK;
}
static void
prune_eotf_modes_by_kms_support(struct drm_head *head, uint32_t *eotf_mask)
{
const struct drm_property_info *info;
/* Without the KMS property, cannot do anything but SDR. */
info = &head->connector.props[WDRM_CONNECTOR_HDR_OUTPUT_METADATA];
if (!head->connector.device->atomic_modeset || info->prop_id == 0)
*eotf_mask = WESTON_EOTF_MODE_SDR;
}
static uint32_t
@@ -406,26 +426,26 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
* Destroys a mode, and removes it from the list.
*/
static void
drm_output_destroy_mode(struct drm_backend *backend, struct drm_mode *mode)
drm_output_destroy_mode(struct drm_device *device, struct drm_mode *mode)
{
if (mode->blob_id)
drmModeDestroyPropertyBlob(backend->drm.fd, mode->blob_id);
drmModeDestroyPropertyBlob(device->drm.fd, mode->blob_id);
wl_list_remove(&mode->base.link);
free(mode);
}
/** Destroy a list of drm_modes
*
* @param backend The backend for releasing mode property blobs.
* @param device The device for releasing mode property blobs.
* @param mode_list The list linked by drm_mode::base.link.
*/
void
drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list)
drm_mode_list_destroy(struct drm_device *device, struct wl_list *mode_list)
{
struct drm_mode *mode, *next;
wl_list_for_each_safe(mode, next, mode_list, base.link)
drm_output_destroy_mode(backend, mode);
drm_output_destroy_mode(device, mode);
}
void
@@ -469,16 +489,16 @@ drm_output_choose_mode(struct drm_output *output,
struct drm_mode *tmp_mode = NULL, *mode_fall_back = NULL, *mode;
enum weston_mode_aspect_ratio src_aspect = WESTON_MODE_PIC_AR_NONE;
enum weston_mode_aspect_ratio target_aspect = WESTON_MODE_PIC_AR_NONE;
struct drm_backend *b;
struct drm_device *device;
b = to_drm_backend(output->base.compositor);
device = output->device;
target_aspect = target_mode->aspect_ratio;
src_aspect = output->base.current_mode->aspect_ratio;
if (output->base.current_mode->width == target_mode->width &&
output->base.current_mode->height == target_mode->height &&
(output->base.current_mode->refresh == target_mode->refresh ||
target_mode->refresh == 0)) {
if (!b->aspect_ratio_supported || src_aspect == target_aspect)
if (!device->aspect_ratio_supported || src_aspect == target_aspect)
return to_drm_mode(output->base.current_mode);
}
@@ -489,7 +509,7 @@ drm_output_choose_mode(struct drm_output *output,
mode->mode_info.vdisplay == target_mode->height) {
if (mode->base.refresh == target_mode->refresh ||
target_mode->refresh == 0) {
if (!b->aspect_ratio_supported ||
if (!device->aspect_ratio_supported ||
src_aspect == target_aspect)
return mode;
else if (!mode_fall_back)
@@ -515,9 +535,12 @@ update_head_from_connector(struct drm_head *head)
const char *make = "unknown";
const char *model = "unknown";
const char *serial_number = "unknown";
uint32_t eotf_mask = WESTON_EOTF_MODE_SDR;
find_and_parse_output_edid(head, props, &make, &model, &serial_number);
find_and_parse_output_edid(head, props, &make, &model, &serial_number, &eotf_mask);
weston_head_set_monitor_strings(&head->base, make, model, serial_number);
prune_eotf_modes_by_kms_support(head, &eotf_mask);
weston_head_set_supported_eotf_mask(&head->base, eotf_mask);
weston_head_set_non_desktop(&head->base,
check_non_desktop(connector, props));
weston_head_set_subpixel(&head->base,
@@ -539,7 +562,7 @@ update_head_from_connector(struct drm_head *head)
* Find the most suitable mode to use for initial setup (or reconfiguration on
* hotplug etc) for a DRM output.
*
* @param backend the DRM backend
* @param device the DRM device
* @param output DRM output to choose mode for
* @param mode Strategy and preference to use when choosing mode
* @param modeline Manually-entered mode (may be NULL)
@@ -547,7 +570,7 @@ update_head_from_connector(struct drm_head *head)
* @returns A mode from the output's mode list, or NULL if none available
*/
static struct drm_mode *
drm_output_choose_initial_mode(struct drm_backend *backend,
drm_output_choose_initial_mode(struct drm_device *device,
struct drm_output *output,
enum weston_drm_backend_output_mode mode,
const char *modeline,
@@ -571,7 +594,7 @@ drm_output_choose_initial_mode(struct drm_backend *backend,
if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) {
n = sscanf(modeline, "%dx%d@%d %u:%u", &width, &height,
&refresh, &aspect_width, &aspect_height);
if (backend->aspect_ratio_supported && n == 5) {
if (device->aspect_ratio_supported && n == 5) {
if (aspect_width == 4 && aspect_height == 3)
aspect_ratio = WESTON_MODE_PIC_AR_4_3;
else if (aspect_width == 16 && aspect_height == 9)
@@ -602,7 +625,7 @@ drm_output_choose_initial_mode(struct drm_backend *backend,
if (width == drm_mode->base.width &&
height == drm_mode->base.height &&
(refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) {
if (!backend->aspect_ratio_supported ||
if (!device->aspect_ratio_supported ||
aspect_ratio == drm_mode->base.aspect_ratio)
configured = drm_mode;
else
@@ -714,7 +737,7 @@ drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
{
struct weston_mode *base;
struct drm_mode *mode = NULL;
struct drm_backend *backend;
struct drm_device *device = output->device;
const drmModeModeInfo *chosen = NULL;
assert(info);
@@ -728,8 +751,7 @@ drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
if (chosen == info) {
assert(mode);
backend = to_drm_backend(output->base.compositor);
drm_output_destroy_mode(backend, mode);
drm_output_destroy_mode(device, mode);
chosen = NULL;
}
@@ -756,7 +778,7 @@ drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
static int
drm_output_update_modelist_from_heads(struct drm_output *output)
{
struct drm_backend *backend = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
struct weston_head *head_base;
struct drm_head *head;
drmModeConnector *conn;
@@ -765,7 +787,7 @@ drm_output_update_modelist_from_heads(struct drm_output *output)
assert(!output->base.enabled);
drm_mode_list_destroy(backend, &output->base.mode_list);
drm_mode_list_destroy(device, &output->base.mode_list);
wl_list_for_each(head_base, &output->base.head_list, output_link) {
head = to_drm_head(head_base);
@@ -786,7 +808,7 @@ drm_output_set_mode(struct weston_output *base,
const char *modeline)
{
struct drm_output *output = to_drm_output(base);
struct drm_backend *b = to_drm_backend(base->compositor);
struct drm_device *device = output->device;
struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
struct drm_mode *current;
@@ -797,7 +819,7 @@ drm_output_set_mode(struct weston_output *base,
if (drm_output_update_modelist_from_heads(output) < 0)
return -1;
current = drm_output_choose_initial_mode(b, output, mode, modeline,
current = drm_output_choose_initial_mode(device, output, mode, modeline,
&head->inherited_mode);
if (!current)
return -1;
+22 -7
View File
@@ -73,6 +73,8 @@ drm_plane_state_alloc(struct drm_output_state *state_output,
void
drm_plane_state_free(struct drm_plane_state *state, bool force)
{
struct drm_device *device;
if (!state)
return;
@@ -86,14 +88,17 @@ drm_plane_state_free(struct drm_plane_state *state, bool force)
* by the kernel, which means we can safely discard it.
*/
if (state->damage_blob_id != 0) {
drmModeDestroyPropertyBlob(state->plane->backend->drm.fd,
device = state->plane->device;
drmModeDestroyPropertyBlob(device->drm.fd,
state->damage_blob_id);
state->damage_blob_id = 0;
}
if (force || state != state->plane->state_cur) {
drm_fb_unref(state->fb);
weston_buffer_reference(&state->fb_ref.buffer, NULL);
weston_buffer_reference(&state->fb_ref.buffer, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&state->fb_ref.release, NULL);
free(state);
}
@@ -135,10 +140,20 @@ drm_plane_state_duplicate(struct drm_output_state *state_output,
* buffer, then we must also transfer the reference on the client
* buffer. */
if (src->fb) {
struct weston_buffer *buffer;
dst->fb = drm_fb_ref(src->fb);
memset(&dst->fb_ref, 0, sizeof(dst->fb_ref));
weston_buffer_reference(&dst->fb_ref.buffer,
src->fb_ref.buffer.buffer);
if (src->fb->type == BUFFER_CLIENT ||
src->fb->type == BUFFER_DMABUF) {
buffer = src->fb_ref.buffer.buffer;
} else {
buffer = NULL;
}
weston_buffer_reference(&dst->fb_ref.buffer, buffer,
buffer ? BUFFER_MAY_BE_ACCESSED :
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&dst->fb_ref.release,
src->fb_ref.release.buffer_release);
} else {
@@ -421,11 +436,11 @@ drm_output_state_free(struct drm_output_state *state)
* Allocate a new, empty, 'pending state' structure to be used across a
* repaint cycle or similar.
*
* @param backend DRM backend
* @param device DRM device
* @returns Newly-allocated pending state structure
*/
struct drm_pending_state *
drm_pending_state_alloc(struct drm_backend *backend)
drm_pending_state_alloc(struct drm_device *device)
{
struct drm_pending_state *ret;
@@ -433,7 +448,7 @@ drm_pending_state_alloc(struct drm_backend *backend)
if (!ret)
return NULL;
ret->backend = backend;
ret->device = device;
wl_list_init(&ret->output_list);
return ret;
+255 -427
View File
@@ -41,6 +41,7 @@
#include "color.h"
#include "linux-dmabuf.h"
#include "presentation-time-server-protocol.h"
#include "linux-dmabuf-unstable-v1-server-protocol.h"
enum drm_output_propose_state_mode {
DRM_OUTPUT_PROPOSE_STATE_MIXED, /**< mix renderer & planes */
@@ -63,55 +64,6 @@ drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode)
return drm_output_propose_state_mode_as_string[mode];
}
static void
drm_output_add_zpos_plane(struct drm_plane *plane, struct wl_list *planes)
{
struct drm_backend *b = plane->backend;
struct drm_plane_zpos *h_plane;
struct drm_plane_zpos *plane_zpos;
plane_zpos = zalloc(sizeof(*plane_zpos));
if (!plane_zpos)
return;
plane_zpos->plane = plane;
drm_debug(b, "\t\t\t\t[plane] plane %d added to candidate list\n",
plane->plane_id);
if (wl_list_empty(planes)) {
wl_list_insert(planes, &plane_zpos->link);
return;
}
h_plane = wl_container_of(planes->next, h_plane, link);
if (h_plane->plane->zpos_max >= plane->zpos_max) {
wl_list_insert(planes->prev, &plane_zpos->link);
} else {
struct drm_plane_zpos *p_zpos = NULL;
if (wl_list_length(planes) == 1) {
wl_list_insert(planes->prev, &plane_zpos->link);
return;
}
wl_list_for_each(p_zpos, planes, link) {
if (p_zpos->plane->zpos_max >
plane_zpos->plane->zpos_max)
break;
}
wl_list_insert(p_zpos->link.prev, &plane_zpos->link);
}
}
static void
drm_output_destroy_zpos_plane(struct drm_plane_zpos *plane_zpos)
{
wl_list_remove(&plane_zpos->link);
free(plane_zpos);
}
static bool
drm_output_check_plane_has_view_assigned(struct drm_plane *plane,
struct drm_output_state *output_state)
@@ -125,87 +77,79 @@ drm_output_check_plane_has_view_assigned(struct drm_plane *plane,
}
static struct drm_plane_state *
drm_output_prepare_overlay_view(struct drm_plane *plane,
struct drm_output_state *output_state,
struct weston_view *ev,
enum drm_output_propose_state_mode mode,
struct drm_fb *fb, uint64_t zpos)
drm_output_try_view_on_plane(struct drm_plane *plane,
struct drm_output_state *output_state,
struct weston_view *ev,
enum drm_output_propose_state_mode mode,
struct drm_fb *fb, uint64_t zpos)
{
struct drm_output *output = output_state->output;
struct weston_compositor *ec = output->base.compositor;
struct drm_backend *b = to_drm_backend(ec);
struct weston_surface *surface = ev->surface;
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_plane_state *state = NULL;
int ret;
assert(!b->sprites_are_broken);
assert(b->atomic_modeset);
if (!fb) {
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
" couldn't get fb\n", ev);
return NULL;
}
assert(!device->sprites_are_broken);
assert(device->atomic_modeset);
assert(fb);
assert(mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY ||
(mode == DRM_OUTPUT_PROPOSE_STATE_MIXED &&
plane->type == WDRM_PLANE_TYPE_OVERLAY));
state = drm_output_state_get_plane(output_state, plane);
/* we can't have a 'pending' framebuffer as never set one before reaching here */
assert(!state->fb);
state->ev = ev;
state->output = output;
if (!drm_plane_state_coords_for_view(state, ev, zpos)) {
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
drm_debug(b, "\t\t\t\t[view] not placing view %p on plane: "
"unsuitable transform\n", ev);
drm_plane_state_put_back(state);
state = NULL;
goto out;
}
/* If the surface buffer has an in-fence fd, but the plane
* doesn't support fences, we can't place the buffer on this
* plane. */
if (ev->surface->acquire_fence_fd >= 0 &&
plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
"no in-fence support\n", ev);
drm_plane_state_put_back(state);
state = NULL;
goto out;
/* Should've been ensured by weston_view_matches_entire_output. */
if (plane->type == WDRM_PLANE_TYPE_PRIMARY) {
assert(state->dest_x == 0 && state->dest_y == 0 &&
state->dest_w == (unsigned) output->base.current_mode->width &&
state->dest_h == (unsigned) output->base.current_mode->height);
}
/* We hold one reference for the lifetime of this function; from
* calling drm_fb_get_from_view() in drm_output_prepare_plane_view(),
* so, we take another reference here to live within the state. */
state->ev = ev;
state->fb = drm_fb_ref(fb);
state->in_fence_fd = ev->surface->acquire_fence_fd;
/* In planes-only mode, we don't have an incremental state to
* test against, so we just hope it'll work. */
if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) {
drm_debug(b, "\t\t\t[overlay] provisionally placing "
"view %p on overlay %lu in planes-only mode\n",
if (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY &&
drm_pending_state_test(output_state->pending_state) != 0) {
drm_debug(b, "\t\t\t[view] not placing view %p on plane %lu: "
"atomic test failed\n",
ev, (unsigned long) plane->plane_id);
goto out;
}
ret = drm_pending_state_test(output_state->pending_state);
if (ret == 0) {
drm_debug(b, "\t\t\t[overlay] provisionally placing "
"view %p on overlay %d in mixed mode\n",
ev, plane->plane_id);
goto out;
}
drm_debug(b, "\t\t\t[overlay] not placing view %p on overlay %lu "
"in mixed mode: kernel test failed\n",
drm_debug(b, "\t\t\t[view] provisionally placing view %p on plane %lu\n",
ev, (unsigned long) plane->plane_id);
drm_plane_state_put_back(state);
state = NULL;
/* Take a reference on the buffer so that we don't release it
* back to the client until we're done with it; cursor buffers
* don't require a reference since we copy them. */
assert(state->fb_ref.buffer.buffer == NULL);
assert(state->fb_ref.release.buffer_release == NULL);
weston_buffer_reference(&state->fb_ref.buffer,
surface->buffer_ref.buffer,
BUFFER_MAY_BE_ACCESSED);
weston_buffer_release_reference(&state->fb_ref.release,
surface->buffer_release_ref.buffer_release);
return state;
out:
return state;
drm_plane_state_put_back(state);
return NULL;
}
#ifdef BUILD_DRM_GBM
@@ -218,18 +162,18 @@ out:
static void
cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
{
struct drm_backend *b = plane_state->plane->backend;
struct drm_output *output = plane_state->output;
struct drm_device *device = output->device;
struct gbm_bo *bo = plane_state->fb->bo;
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
uint32_t buf[b->cursor_width * b->cursor_height];
uint32_t buf[device->cursor_width * device->cursor_height];
int32_t stride;
uint8_t *s;
int i;
assert(buffer && buffer->shm_buffer);
assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
assert(buffer->width <= b->cursor_width);
assert(buffer->height <= b->cursor_height);
assert(buffer->width <= device->cursor_width);
assert(buffer->height <= device->cursor_height);
memset(buf, 0, sizeof buf);
stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
@@ -237,7 +181,7 @@ cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
wl_shm_buffer_begin_access(buffer->shm_buffer);
for (i = 0; i < buffer->height; i++)
memcpy(buf + i * b->cursor_width,
memcpy(buf + i * device->cursor_width,
s + i * stride,
buffer->width * 4);
wl_shm_buffer_end_access(buffer->shm_buffer);
@@ -251,32 +195,23 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
struct weston_view *ev, uint64_t zpos)
{
struct drm_output *output = output_state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_plane *plane = output->cursor_plane;
struct drm_plane_state *plane_state;
bool needs_update = false;
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
const char *p_name = drm_output_get_plane_type_name(plane);
assert(!b->cursors_are_broken);
if (!plane)
return NULL;
if (!plane->state_cur->complete)
return NULL;
if (plane->state_cur->output && plane->state_cur->output != output)
return NULL;
assert(!device->cursors_are_broken);
assert(plane);
assert(plane->state_cur->complete);
assert(!plane->state_cur->output || plane->state_cur->output == output);
/* We use GBM to import SHM buffers. */
if (b->gbm == NULL)
return NULL;
assert(b->gbm);
plane_state = drm_output_state_get_plane(output_state, plane);
if (plane_state && plane_state->fb)
return NULL;
assert(!plane_state->fb);
/* We can't scale with the legacy API, and we don't try to account for
* simple cropping/translation in cursor_bo_update. */
@@ -287,19 +222,9 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
goto err;
}
if (buffer->width > b->cursor_width ||
buffer->height > b->cursor_height) {
drm_debug(b, "\t\t\t\t[%s] not assigning view %p to %s plane "
"(surface buffer (%dx%d) larger than permitted"
" (%dx%d))\n", p_name, ev, p_name,
buffer->width, buffer->height,
b->cursor_width, b->cursor_height);
goto err;
}
if (plane_state->src_x != 0 || plane_state->src_y != 0 ||
plane_state->src_w > (unsigned) b->cursor_width << 16 ||
plane_state->src_h > (unsigned) b->cursor_height << 16 ||
plane_state->src_w > (unsigned) device->cursor_width << 16 ||
plane_state->src_h > (unsigned) device->cursor_height << 16 ||
plane_state->src_w != plane_state->dest_w << 16 ||
plane_state->src_h != plane_state->dest_h << 16) {
drm_debug(b, "\t\t\t\t[%s] not assigning view %p to %s plane "
@@ -338,10 +263,10 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
* a buffer which is always cursor_width x cursor_height, even if the
* surface we want to promote is actually smaller than this. Manually
* mangle the plane state to deal with this. */
plane_state->src_w = b->cursor_width << 16;
plane_state->src_h = b->cursor_height << 16;
plane_state->dest_w = b->cursor_width;
plane_state->dest_h = b->cursor_height;
plane_state->src_w = device->cursor_width << 16;
plane_state->src_h = device->cursor_height << 16;
plane_state->dest_w = device->cursor_width;
plane_state->dest_h = device->cursor_height;
drm_debug(b, "\t\t\t\t[%s] provisionally assigned view %p to cursor\n",
p_name, ev);
@@ -361,190 +286,6 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
}
#endif
static struct drm_plane_state *
drm_output_prepare_scanout_view(struct drm_output_state *output_state,
struct weston_view *ev,
enum drm_output_propose_state_mode mode,
struct drm_fb *fb, uint64_t zpos)
{
struct drm_output *output = output_state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_plane *scanout_plane = output->scanout_plane;
struct drm_plane_state *state;
const char *p_name = drm_output_get_plane_type_name(scanout_plane);
assert(!b->sprites_are_broken);
assert(b->atomic_modeset);
assert(mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
/* Check the view spans exactly the output size, calculated in the
* logical co-ordinate space. */
if (!weston_view_matches_output_entirely(ev, &output->base)) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
" view does not match output entirely\n",
p_name, ev, p_name);
return NULL;
}
/* If the surface buffer has an in-fence fd, but the plane doesn't
* support fences, we can't place the buffer on this plane. */
if (ev->surface->acquire_fence_fd >= 0 &&
scanout_plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
"no in-fence support\n", p_name, ev, p_name);
return NULL;
}
if (!fb) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
" couldn't get fb\n", p_name, ev, p_name);
return NULL;
}
state = drm_output_state_get_plane(output_state, scanout_plane);
/* The only way we can already have a buffer in the scanout plane is
* if we are in mixed mode, or if a client buffer has already been
* placed into scanout. The former case will never call into here,
* and in the latter case, the view must have been marked as occluded,
* meaning we should never have ended up here. */
assert(!state->fb);
/* take another reference here to live within the state */
state->fb = drm_fb_ref(fb);
state->ev = ev;
state->output = output;
if (!drm_plane_state_coords_for_view(state, ev, zpos)) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
"unsuitable transform\n", p_name, ev, p_name);
goto err;
}
if (state->dest_x != 0 || state->dest_y != 0 ||
state->dest_w != (unsigned) output->base.current_mode->width ||
state->dest_h != (unsigned) output->base.current_mode->height) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
" invalid plane state\n", p_name, ev, p_name);
goto err;
}
state->in_fence_fd = ev->surface->acquire_fence_fd;
/* In plane-only mode, we don't need to test the state now, as we
* will only test it once at the end. */
return state;
err:
drm_plane_state_put_back(state);
return NULL;
}
static struct drm_plane_state *
drm_output_try_view_on_plane(struct drm_plane *plane,
struct drm_output_state *state,
struct weston_view *ev,
enum drm_output_propose_state_mode mode,
struct drm_fb *fb, uint64_t zpos)
{
struct drm_backend *b = state->pending_state->backend;
struct weston_output *wet_output = &state->output->base;
bool view_matches_entire_output, scanout_has_view_assigned;
struct drm_plane *scanout_plane = state->output->scanout_plane;
struct drm_plane_state *ps = NULL;
const char *p_name = drm_output_get_plane_type_name(plane);
struct weston_surface *surface = ev->surface;
enum {
NO_PLANES, /* generic err-handle */
NO_PLANES_ACCEPTED,
PLACED_ON_PLANE,
} availability = NO_PLANES;
/* sanity checks in case we over/underflow zpos or pass incorrect
* values */
assert(zpos <= plane->zpos_max ||
zpos != DRM_PLANE_ZPOS_INVALID_PLANE);
switch (plane->type) {
case WDRM_PLANE_TYPE_CURSOR:
if (b->cursors_are_broken) {
availability = NO_PLANES_ACCEPTED;
goto out;
}
ps = drm_output_prepare_cursor_view(state, ev, zpos);
if (ps)
availability = PLACED_ON_PLANE;
break;
case WDRM_PLANE_TYPE_OVERLAY:
/* do not attempt to place it in the overlay if we don't have
* anything in the scanout/primary and the view doesn't cover
* the entire output */
view_matches_entire_output =
weston_view_matches_output_entirely(ev, wet_output);
scanout_has_view_assigned =
drm_output_check_plane_has_view_assigned(scanout_plane,
state);
if (view_matches_entire_output && !scanout_has_view_assigned) {
availability = NO_PLANES_ACCEPTED;
goto out;
}
ps = drm_output_prepare_overlay_view(plane, state, ev, mode,
fb, zpos);
if (ps)
availability = PLACED_ON_PLANE;
break;
case WDRM_PLANE_TYPE_PRIMARY:
if (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) {
availability = NO_PLANES_ACCEPTED;
goto out;
}
ps = drm_output_prepare_scanout_view(state, ev, mode,
fb, zpos);
if (ps)
availability = PLACED_ON_PLANE;
break;
default:
assert(0);
break;
}
out:
switch (availability) {
case NO_PLANES:
/* set initial to this catch-all case, such that
* prepare_cursor/overlay/scanout() should have/contain the
* reason for failling */
break;
case NO_PLANES_ACCEPTED:
drm_debug(b, "\t\t\t\t[plane] plane %d refusing to "
"place view %p in %s\n",
plane->plane_id, ev, p_name);
break;
case PLACED_ON_PLANE:
/* Take a reference on the buffer so that we don't release it
* back to the client until we're done with it; cursor buffers
* don't require a reference since we copy them. */
assert(ps->fb_ref.buffer.buffer == NULL);
assert(ps->fb_ref.release.buffer_release == NULL);
if (ps->plane->type == WDRM_PLANE_TYPE_CURSOR) {
assert(ps->fb->type == BUFFER_CURSOR);
} else if (fb->type == BUFFER_CLIENT || fb->type == BUFFER_DMABUF) {
assert(ps->fb == fb);
weston_buffer_reference(&ps->fb_ref.buffer,
surface->buffer_ref.buffer);
weston_buffer_release_reference(&ps->fb_ref.release,
surface->buffer_release_ref.buffer_release);
}
break;
}
return ps;
}
static void
drm_output_check_zpos_plane_states(struct drm_output_state *state)
{
@@ -585,12 +326,13 @@ drm_output_check_zpos_plane_states(struct drm_output_state *state)
}
static bool
dmabuf_feedback_maybe_update(struct drm_backend *b, struct weston_view *ev,
dmabuf_feedback_maybe_update(struct drm_device *device, struct weston_view *ev,
uint32_t try_view_on_plane_failure_reasons)
{
struct weston_dmabuf_feedback *dmabuf_feedback = ev->surface->dmabuf_feedback;
struct weston_dmabuf_feedback_tranche *scanout_tranche;
dev_t scanout_dev = b->drm.devnum;
struct drm_backend *b = device->backend;
dev_t scanout_dev = device->drm.devnum;
uint32_t scanout_flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT;
uint32_t action_needed = ACTION_NEEDED_NONE;
struct timespec current_time, delta_time;
@@ -603,7 +345,8 @@ dmabuf_feedback_maybe_update(struct drm_backend *b, struct weston_view *ev,
(FAILURE_REASONS_ADD_FB_FAILED |
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE |
FAILURE_REASONS_DMABUF_MODIFIER_INVALID |
FAILURE_REASONS_GBM_BO_IMPORT_FAILED))
FAILURE_REASONS_GBM_BO_IMPORT_FAILED |
FAILURE_REASONS_GBM_BO_GET_HANDLE_FAILED))
action_needed |= ACTION_NEEDED_ADD_SCANOUT_TRANCHE;
assert(action_needed != (ACTION_NEEDED_REMOVE_SCANOUT_TRANCHE |
@@ -681,58 +424,161 @@ dmabuf_feedback_maybe_update(struct drm_backend *b, struct weston_view *ev,
}
static struct drm_plane_state *
drm_output_prepare_plane_view(struct drm_output_state *state,
struct weston_view *ev,
enum drm_output_propose_state_mode mode,
struct drm_plane_state *scanout_state,
uint64_t current_lowest_zpos,
uint32_t *try_view_on_plane_failure_reasons)
drm_output_find_plane_for_view(struct drm_output_state *state,
struct weston_paint_node *pnode,
enum drm_output_propose_state_mode mode,
struct drm_plane_state *scanout_state,
uint64_t current_lowest_zpos)
{
struct drm_output *output = state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_plane_state *ps = NULL;
struct drm_plane *plane;
struct drm_plane_zpos *p_zpos, *p_zpos_next;
struct wl_list zpos_candidate_list;
struct weston_view *ev = pnode->view;
struct weston_buffer *buffer;
struct wl_shm_buffer *shmbuf;
struct drm_fb *fb;
struct drm_fb *fb = NULL;
wl_list_init(&zpos_candidate_list);
bool view_matches_entire_output, scanout_has_view_assigned;
uint32_t possible_plane_mask = 0;
pnode->try_view_on_plane_failure_reasons = FAILURE_REASONS_NONE;
/* check view for valid buffer, doesn't make sense to even try */
if (!weston_view_has_valid_buffer(ev))
return ps;
if (!weston_view_has_valid_buffer(ev)) {
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL;
}
buffer = ev->surface->buffer_ref.buffer;
shmbuf = wl_shm_buffer_get(buffer->resource);
fb = drm_fb_get_from_view(state, ev, try_view_on_plane_failure_reasons);
if (!shmbuf && !fb)
if (buffer->type == WESTON_BUFFER_SOLID) {
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL;
} else if (buffer->type == WESTON_BUFFER_SHM) {
if (!output->cursor_plane || device->cursors_are_broken) {
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL;
}
/* Even though this is a SHM buffer, pixel_format stores the
* format code as DRM FourCC */
if (buffer->pixel_format->format != DRM_FORMAT_ARGB8888) {
drm_debug(b, "\t\t\t\t[view] not placing view %p on "
"plane; SHM buffers must be ARGB8888 for "
"cursor view\n", ev);
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL;
}
if (buffer->width > device->cursor_width ||
buffer->height > device->cursor_height) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
"(buffer (%dx%d) too large for cursor plane)\n",
ev, buffer->width, buffer->height);
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL;
}
possible_plane_mask = (1 << output->cursor_plane->plane_idx);
} else {
if (mode == DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p "
"to plane: renderer-only mode\n", ev);
return NULL;
}
fb = drm_fb_get_from_view(state, ev,
&pnode->try_view_on_plane_failure_reasons);
if (!fb) {
drm_debug(b, "\t\t\t[view] couldn't get FB for view: 0x%lx\n",
(unsigned long) pnode->try_view_on_plane_failure_reasons);
return NULL;
}
possible_plane_mask = fb->plane_mask;
}
view_matches_entire_output =
weston_view_matches_output_entirely(ev, &output->base);
scanout_has_view_assigned =
drm_output_check_plane_has_view_assigned(output->scanout_plane,
state);
/* assemble a list with possible candidates */
wl_list_for_each(plane, &b->plane_list, link) {
wl_list_for_each(plane, &device->plane_list, link) {
const char *p_name = drm_output_get_plane_type_name(plane);
uint64_t zpos;
if (possible_plane_mask == 0)
break;
if (!(possible_plane_mask & (1 << plane->plane_idx)))
continue;
possible_plane_mask &= ~(1 << plane->plane_idx);
switch (plane->type) {
case WDRM_PLANE_TYPE_CURSOR:
assert(buffer->shm_buffer);
assert(plane == output->cursor_plane);
break;
case WDRM_PLANE_TYPE_PRIMARY:
assert(fb);
if (plane != output->scanout_plane)
continue;
if (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY)
continue;
if (!view_matches_entire_output)
continue;
break;
case WDRM_PLANE_TYPE_OVERLAY:
assert(fb);
assert(mode != DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY);
/* if the view covers the whole output, put it in the
* scanout plane, not overlay */
if (view_matches_entire_output &&
!scanout_has_view_assigned)
continue;
break;
default:
assert(false && "unknown plane type");
}
if (!drm_plane_is_available(plane, output))
continue;
if (drm_output_check_plane_has_view_assigned(plane, state)) {
drm_debug(b, "\t\t\t\t[plane] not adding plane %d to"
" candidate list: view already assigned "
"to a plane\n", plane->plane_id);
drm_debug(b, "\t\t\t\t[plane] not trying plane %d: "
"another view already assigned\n",
plane->plane_id);
continue;
}
if (plane->zpos_min >= current_lowest_zpos) {
drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
"candidate list: minimum zpos (%"PRIu64") "
"plane's above current lowest zpos "
"(%"PRIu64")\n", plane->plane_id,
plane->zpos_min, current_lowest_zpos);
drm_debug(b, "\t\t\t\t[plane] not trying plane %d: "
"plane's minimum zpos (%"PRIu64") above "
"current lowest zpos (%"PRIu64")\n",
plane->plane_id, plane->zpos_min,
current_lowest_zpos);
continue;
}
/* If the surface buffer has an in-fence fd, but the plane doesn't
* support fences, we can't place the buffer on this plane. */
if (ev->surface->acquire_fence_fd >= 0 &&
plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
"no in-fence support\n", p_name, ev, p_name);
return NULL;
}
if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
assert(scanout_state != NULL);
if (scanout_state->zpos >= plane->zpos_max) {
@@ -746,49 +592,6 @@ drm_output_prepare_plane_view(struct drm_output_state *state,
}
}
if (mode == DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY &&
(plane->type == WDRM_PLANE_TYPE_OVERLAY ||
plane->type == WDRM_PLANE_TYPE_PRIMARY)) {
drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
"candidate list: renderer-only mode\n",
plane->plane_id);
continue;
}
if (plane->type == WDRM_PLANE_TYPE_CURSOR &&
(!shmbuf || wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888)) {
drm_debug(b, "\t\t\t\t[plane] not adding plane %d, type cursor to "
"candidate list: cursor planes only support ARGB8888"
"wl_shm buffers and the view buffer is of another type\n",
plane->plane_id);
continue;
}
if (plane->type != WDRM_PLANE_TYPE_CURSOR &&
(!fb || !(fb->plane_mask & (1 << plane->plane_idx)))) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
"candidate list: invalid pixel format\n",
plane->plane_id);
continue;
}
drm_output_add_zpos_plane(plane, &zpos_candidate_list);
}
/* go over the potential candidate list and try to find a possible
* plane suitable for \c ev; start with the highest zpos value of a
* plane to maximize our chances, but do note we pass the zpos value
* based on current tracked value by \c current_lowest_zpos_in_use */
while (!wl_list_empty(&zpos_candidate_list)) {
struct drm_plane_zpos *head_p_zpos =
wl_container_of(zpos_candidate_list.next,
head_p_zpos, link);
struct drm_plane *plane = head_p_zpos->plane;
const char *p_name = drm_output_get_plane_type_name(plane);
uint64_t zpos;
if (current_lowest_zpos == DRM_PLANE_ZPOS_INVALID_PLANE)
zpos = plane->zpos_max;
else
@@ -798,20 +601,32 @@ drm_output_prepare_plane_view(struct drm_output_state *state,
"from candidate list, type: %s\n",
plane->plane_id, p_name);
ps = drm_output_try_view_on_plane(plane, state, ev,
mode, fb, zpos);
drm_output_destroy_zpos_plane(head_p_zpos);
if (plane->type == WDRM_PLANE_TYPE_CURSOR) {
ps = drm_output_prepare_cursor_view(state, ev, zpos);
} else {
ps = drm_output_try_view_on_plane(plane, state, ev,
mode, fb, zpos);
}
if (ps) {
drm_debug(b, "\t\t\t\t[view] view %p has been placed to "
"%s plane with computed zpos %"PRIu64"\n",
ev, p_name, zpos);
break;
}
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_PLANES_REJECTED;
}
wl_list_for_each_safe(p_zpos, p_zpos_next, &zpos_candidate_list, link)
drm_output_destroy_zpos_plane(p_zpos);
if (!ps &&
pnode->try_view_on_plane_failure_reasons == FAILURE_REASONS_NONE) {
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_NO_PLANES_AVAILABLE;
}
/* if we have a plane state, it has its own ref to the fb; if not then
* we drop ours here */
drm_fb_unref(fb);
return ps;
}
@@ -822,7 +637,8 @@ drm_output_propose_state(struct weston_output *output_base,
enum drm_output_propose_state_mode mode)
{
struct drm_output *output = to_drm_output(output_base);
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct weston_paint_node *pnode;
struct drm_output_state *state;
struct drm_plane_state *scanout_state = NULL;
@@ -957,12 +773,29 @@ drm_output_propose_state(struct weston_output *output_base,
force_renderer = true;
}
if (!b->gbm) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
"(GBM not available)\n", ev);
force_renderer = true;
}
if (!weston_view_has_valid_buffer(ev)) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
"(no buffer available)\n", ev);
force_renderer = true;
}
/* We can support this with the 'CRTC background colour' property,
* if it is fullscreen (i.e. we disable the primary plane), and
* opaque (as it is only shown in the absence of any covering
* plane, not as a replacement for the primary plane per se). */
if (ev->surface->buffer_ref.buffer &&
ev->surface->buffer_ref.buffer->type == WESTON_BUFFER_SOLID) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
"(solid-colour surface)\n", ev);
force_renderer = true;
}
if (pnode->surf_xform.transform != NULL ||
!pnode->surf_xform.identity_pipeline) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
@@ -996,15 +829,9 @@ drm_output_propose_state(struct weston_output *output_base,
if (!force_renderer) {
drm_debug(b, "\t\t\t[plane] started with zpos %"PRIu64"\n",
current_lowest_zpos);
ps = drm_output_prepare_plane_view(state, ev, mode,
scanout_state,
current_lowest_zpos,
&pnode->try_view_on_plane_failure_reasons);
/* If we were able to place the view in a plane, set
* failure reasons to none. */
if (ps)
pnode->try_view_on_plane_failure_reasons =
FAILURE_REASONS_NONE;
ps = drm_output_find_plane_for_view(state, pnode, mode,
scanout_state,
current_lowest_zpos);
} else {
/* We are forced to place the view in the renderer, set
* the failure reason accordingly. */
@@ -1088,21 +915,24 @@ err:
}
void
drm_assign_planes(struct weston_output *output_base, void *repaint_data)
drm_assign_planes(struct weston_output *output_base)
{
struct drm_backend *b = to_drm_backend(output_base->compositor);
struct drm_pending_state *pending_state = repaint_data;
struct drm_output *output = to_drm_output(output_base);
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_pending_state *pending_state = device->repaint_data;
struct drm_output_state *state = NULL;
struct drm_plane_state *plane_state;
struct weston_paint_node *pnode;
struct weston_plane *primary = &output_base->compositor->primary_plane;
enum drm_output_propose_state_mode mode = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY;
assert(output);
drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n",
output_base->name, (unsigned long) output_base->id);
if (!b->sprites_are_broken && !output->virtual) {
if (!device->sprites_are_broken && !output->virtual && b->gbm) {
drm_debug(b, "\t[repaint] trying planes-only build state\n");
state = drm_output_propose_state(output_base, pending_state, mode);
if (!state) {
@@ -1144,26 +974,24 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
/* Update dmabuf-feedback if needed */
if (ev->surface->dmabuf_feedback)
dmabuf_feedback_maybe_update(b, ev,
dmabuf_feedback_maybe_update(device, ev,
pnode->try_view_on_plane_failure_reasons);
pnode->try_view_on_plane_failure_reasons = FAILURE_REASONS_NONE;
/* Test whether this buffer can ever go into a plane:
* non-shm, or small enough to be a cursor.
*
* Also, keep a reference when using the pixman renderer.
* That makes it possible to do a seamless switch to the GL
* renderer and since the pixman renderer keeps a reference
* to the buffer anyway, there is no side effects.
*/
if (b->use_pixman ||
(weston_view_has_valid_buffer(ev) &&
(!wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
(ev->surface->width <= b->cursor_width &&
ev->surface->height <= b->cursor_height))))
ev->surface->keep_buffer = true;
else
ev->surface->keep_buffer = false;
* non-shm, or small enough to be a cursor. */
ev->surface->keep_buffer = false;
if (weston_view_has_valid_buffer(ev)) {
struct weston_buffer *buffer =
ev->surface->buffer_ref.buffer;
if (buffer->type == WESTON_BUFFER_DMABUF ||
buffer->type == WESTON_BUFFER_RENDERER_OPAQUE)
ev->surface->keep_buffer = true;
else if (buffer->type == WESTON_BUFFER_SHM &&
(ev->surface->width <= device->cursor_width &&
ev->surface->height <= device->cursor_height))
ev->surface->keep_buffer = true;
}
/* This is a bit unpleasant, but lacking a temporary place to
* hang a plane off the view, we have to do a nested walk.
-998
View File
@@ -1,998 +0,0 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2011 Intel Corporation
* Copyright © 2012 Raspberry Pi Foundation
* Copyright © 2013 Philip Withnall
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fb.h>
#include <linux/input.h>
#include <assert.h>
#include <libudev.h>
#include "shared/helpers.h"
#include <libweston/libweston.h>
#include <libweston/backend-fbdev.h>
#include "launcher-util.h"
#include "pixman-renderer.h"
#include "libinput-seat.h"
#include "presentation-time-server-protocol.h"
struct fbdev_backend {
struct weston_backend base;
struct weston_compositor *compositor;
uint32_t prev_state;
struct udev *udev;
struct udev_input input;
uint32_t output_transform;
struct wl_listener session_listener;
};
struct fbdev_screeninfo {
unsigned int x_resolution; /* pixels, visible area */
unsigned int y_resolution; /* pixels, visible area */
unsigned int width_mm; /* visible screen width in mm */
unsigned int height_mm; /* visible screen height in mm */
unsigned int bits_per_pixel;
size_t buffer_length; /* length of frame buffer memory in bytes */
size_t line_length; /* length of a line in bytes */
char id[16]; /* screen identifier */
pixman_format_code_t pixel_format; /* frame buffer pixel format */
unsigned int refresh_rate; /* Hertz */
};
struct fbdev_head {
struct weston_head base;
/* Frame buffer details. */
char *device;
struct fbdev_screeninfo fb_info;
};
struct fbdev_output {
struct fbdev_backend *backend;
struct weston_output base;
struct weston_mode mode;
struct wl_event_source *finish_frame_timer;
/* framebuffer mmap details */
size_t buffer_length;
void *fb;
/* pixman details. */
pixman_image_t *hw_surface;
};
static const char default_seat[] = "seat0";
static inline struct fbdev_head *
to_fbdev_head(struct weston_head *base)
{
return container_of(base, struct fbdev_head, base);
}
static inline struct fbdev_output *
to_fbdev_output(struct weston_output *base)
{
return container_of(base, struct fbdev_output, base);
}
static inline struct fbdev_backend *
to_fbdev_backend(struct weston_compositor *base)
{
return container_of(base->backend, struct fbdev_backend, base);
}
static struct fbdev_head *
fbdev_output_get_head(struct fbdev_output *output)
{
if (wl_list_length(&output->base.head_list) != 1)
return NULL;
return container_of(output->base.head_list.next,
struct fbdev_head, base.output_link);
}
static int
fbdev_output_start_repaint_loop(struct weston_output *output)
{
struct timespec ts;
weston_compositor_read_presentation_clock(output->compositor, &ts);
weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
return 0;
}
static int
fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage,
void *repaint_data)
{
struct fbdev_output *output = to_fbdev_output(base);
struct weston_compositor *ec = output->base.compositor;
/* Repaint the damaged region onto the back buffer. */
pixman_renderer_output_set_buffer(base, output->hw_surface);
ec->renderer->repaint_output(base, damage);
/* Update the damage region. */
pixman_region32_subtract(&ec->primary_plane.damage,
&ec->primary_plane.damage, damage);
/* Schedule the end of the frame. We do not sync this to the frame
* buffer clock because users who want that should be using the DRM
* compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
* panning, which is broken in most kernel drivers.
*
* Finish the frame synchronised to the specified refresh rate. The
* refresh rate is given in mHz and the interval in ms. */
wl_event_source_timer_update(output->finish_frame_timer,
1000000 / output->mode.refresh);
return 0;
}
static int
finish_frame_handler(void *data)
{
struct fbdev_output *output = data;
struct timespec ts;
weston_compositor_read_presentation_clock(output->base.compositor, &ts);
weston_output_finish_frame(&output->base, &ts, 0);
return 1;
}
static pixman_format_code_t
calculate_pixman_format(struct fb_var_screeninfo *vinfo,
struct fb_fix_screeninfo *finfo)
{
/* Calculate the pixman format supported by the frame buffer from the
* buffer's metadata. Return 0 if no known pixman format is supported
* (since this has depth 0 it's guaranteed to not conflict with any
* actual pixman format).
*
* Documentation on the vinfo and finfo structures:
* http://www.mjmwired.net/kernel/Documentation/fb/api.txt
*
* TODO: Try a bit harder to support other formats, including setting
* the preferred format in the hardware. */
int type;
weston_log("Calculating pixman format from:\n"
STAMP_SPACE " - type: %i (aux: %i)\n"
STAMP_SPACE " - visual: %i\n"
STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
finfo->type, finfo->type_aux, finfo->visual,
vinfo->bits_per_pixel, vinfo->grayscale,
vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
vinfo->green.offset, vinfo->green.length,
vinfo->green.msb_right,
vinfo->blue.offset, vinfo->blue.length,
vinfo->blue.msb_right,
vinfo->transp.offset, vinfo->transp.length,
vinfo->transp.msb_right);
/* We only handle packed formats at the moment. */
if (finfo->type != FB_TYPE_PACKED_PIXELS)
return 0;
/* We only handle true-colour frame buffers at the moment. */
switch(finfo->visual) {
case FB_VISUAL_TRUECOLOR:
case FB_VISUAL_DIRECTCOLOR:
if (vinfo->grayscale != 0)
return 0;
break;
default:
return 0;
}
/* We only support formats with MSBs on the left. */
if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
vinfo->blue.msb_right != 0)
return 0;
/* Work out the format type from the offsets. We only support RGBA, ARGB
* and ABGR at the moment. */
type = PIXMAN_TYPE_OTHER;
if ((vinfo->transp.offset >= vinfo->red.offset ||
vinfo->transp.length == 0) &&
vinfo->red.offset >= vinfo->green.offset &&
vinfo->green.offset >= vinfo->blue.offset)
type = PIXMAN_TYPE_ARGB;
else if (vinfo->red.offset >= vinfo->green.offset &&
vinfo->green.offset >= vinfo->blue.offset &&
vinfo->blue.offset >= vinfo->transp.offset)
type = PIXMAN_TYPE_RGBA;
else if (vinfo->transp.offset >= vinfo->blue.offset &&
vinfo->blue.offset >= vinfo->green.offset &&
vinfo->green.offset >= vinfo->red.offset)
type = PIXMAN_TYPE_ABGR;
if (type == PIXMAN_TYPE_OTHER)
return 0;
/* Build the format. */
return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
vinfo->transp.length,
vinfo->red.length,
vinfo->green.length,
vinfo->blue.length);
}
static int
calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
{
uint64_t quot;
/* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
quot *= vinfo->pixclock;
if (quot > 0) {
uint64_t refresh_rate;
refresh_rate = 1000000000000000LLU / quot;
if (refresh_rate > 200000)
refresh_rate = 200000; /* cap at 200 Hz */
if (refresh_rate >= 1000) /* at least 1 Hz */
return refresh_rate;
}
return 60 * 1000; /* default to 60 Hz */
}
static int
fbdev_query_screen_info(int fd, struct fbdev_screeninfo *info)
{
struct fb_var_screeninfo varinfo;
struct fb_fix_screeninfo fixinfo;
/* Probe the device for screen information. */
if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
return -1;
}
/* Store the pertinent data. */
info->x_resolution = varinfo.xres;
info->y_resolution = varinfo.yres;
info->width_mm = varinfo.width;
info->height_mm = varinfo.height;
info->bits_per_pixel = varinfo.bits_per_pixel;
info->buffer_length = fixinfo.smem_len;
info->line_length = fixinfo.line_length;
strncpy(info->id, fixinfo.id, sizeof(info->id));
info->id[sizeof(info->id)-1] = '\0';
info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
info->refresh_rate = calculate_refresh_rate(&varinfo);
if (info->pixel_format == 0) {
weston_log("Frame buffer uses an unsupported format.\n");
return -1;
}
return 1;
}
static int
fbdev_set_screen_info(int fd, struct fbdev_screeninfo *info)
{
struct fb_var_screeninfo varinfo;
/* Grab the current screen information. */
if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
return -1;
}
/* Update the information. */
varinfo.xres = info->x_resolution;
varinfo.yres = info->y_resolution;
varinfo.width = info->width_mm;
varinfo.height = info->height_mm;
varinfo.bits_per_pixel = info->bits_per_pixel;
/* Try to set up an ARGB (x8r8g8b8) pixel format. */
varinfo.grayscale = 0;
varinfo.transp.offset = 24;
varinfo.transp.length = 0;
varinfo.transp.msb_right = 0;
varinfo.red.offset = 16;
varinfo.red.length = 8;
varinfo.red.msb_right = 0;
varinfo.green.offset = 8;
varinfo.green.length = 8;
varinfo.green.msb_right = 0;
varinfo.blue.offset = 0;
varinfo.blue.length = 8;
varinfo.blue.msb_right = 0;
/* Set the device's screen information. */
if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
return -1;
}
return 1;
}
static int
fbdev_wakeup_screen(int fd, struct fbdev_screeninfo *info)
{
struct fb_var_screeninfo varinfo;
/* Grab the current screen information. */
if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
return -1;
}
/* force the framebuffer to wake up */
varinfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
/* Set the device's screen information. */
if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
return -1;
}
return 1;
}
/* Returns an FD for the frame buffer device. */
static int
fbdev_frame_buffer_open(const char *fb_dev,
struct fbdev_screeninfo *screen_info)
{
int fd = -1;
weston_log("Opening fbdev frame buffer.\n");
/* Open the frame buffer device. */
fd = open(fb_dev, O_RDWR | O_CLOEXEC);
if (fd < 0) {
weston_log("Failed to open frame buffer device %s: %s\n",
fb_dev, strerror(errno));
return -1;
}
/* Grab the screen info. */
if (fbdev_query_screen_info(fd, screen_info) < 0) {
weston_log("Failed to get frame buffer info: %s\n",
strerror(errno));
close(fd);
return -1;
}
/* Attempt to wake up the framebuffer device, needed for secondary
* framebuffer devices */
if (fbdev_wakeup_screen(fd, screen_info) < 0) {
weston_log("Failed to activate framebuffer display. "
"Attempting to open output anyway.\n");
}
return fd;
}
/* Closes the FD on success or failure. */
static int
fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
{
struct fbdev_head *head;
int retval = -1;
head = fbdev_output_get_head(output);
weston_log("Mapping fbdev frame buffer.\n");
/* Map the frame buffer. Write-only mode, since we don't want to read
* anything back (because it's slow). */
output->buffer_length = head->fb_info.buffer_length;
output->fb = mmap(NULL, output->buffer_length,
PROT_WRITE, MAP_SHARED, fd, 0);
if (output->fb == MAP_FAILED) {
weston_log("Failed to mmap frame buffer: %s\n",
strerror(errno));
output->fb = NULL;
goto out_close;
}
/* Create a pixman image to wrap the memory mapped frame buffer. */
output->hw_surface =
pixman_image_create_bits(head->fb_info.pixel_format,
head->fb_info.x_resolution,
head->fb_info.y_resolution,
output->fb,
head->fb_info.line_length);
if (output->hw_surface == NULL) {
weston_log("Failed to create surface for frame buffer.\n");
goto out_unmap;
}
/* Success! */
retval = 0;
out_unmap:
if (retval != 0 && output->fb != NULL) {
munmap(output->fb, output->buffer_length);
output->fb = NULL;
}
out_close:
if (fd >= 0)
close(fd);
return retval;
}
static void
fbdev_frame_buffer_unmap(struct fbdev_output *output)
{
if (!output->fb) {
assert(!output->hw_surface);
return;
}
weston_log("Unmapping fbdev frame buffer.\n");
if (output->hw_surface)
pixman_image_unref(output->hw_surface);
output->hw_surface = NULL;
if (munmap(output->fb, output->buffer_length) < 0)
weston_log("Failed to munmap frame buffer: %s\n",
strerror(errno));
output->fb = NULL;
}
static int
fbdev_output_attach_head(struct weston_output *output_base,
struct weston_head *head_base)
{
struct fbdev_output *output = to_fbdev_output(output_base);
struct fbdev_head *head = to_fbdev_head(head_base);
/* Clones not supported. */
if (!wl_list_empty(&output->base.head_list))
return -1;
/* only one static mode in list */
output->mode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
output->mode.width = head->fb_info.x_resolution;
output->mode.height = head->fb_info.y_resolution;
output->mode.refresh = head->fb_info.refresh_rate;
wl_list_init(&output->base.mode_list);
wl_list_insert(&output->base.mode_list, &output->mode.link);
output->base.current_mode = &output->mode;
return 0;
}
static void fbdev_output_destroy(struct weston_output *base);
static int
fbdev_output_enable(struct weston_output *base)
{
struct fbdev_output *output = to_fbdev_output(base);
struct fbdev_backend *backend = to_fbdev_backend(base->compositor);
struct fbdev_head *head;
int fb_fd;
struct wl_event_loop *loop;
const struct pixman_renderer_output_options options = {
.use_shadow = true,
};
head = fbdev_output_get_head(output);
/* Create the frame buffer. */
fb_fd = fbdev_frame_buffer_open(head->device, &head->fb_info);
if (fb_fd < 0) {
weston_log("Creating frame buffer failed.\n");
return -1;
}
if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
weston_log("Mapping frame buffer failed.\n");
return -1;
}
output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
output->base.repaint = fbdev_output_repaint;
if (pixman_renderer_output_create(&output->base, &options) < 0)
goto out_hw_surface;
loop = wl_display_get_event_loop(backend->compositor->wl_display);
output->finish_frame_timer =
wl_event_loop_add_timer(loop, finish_frame_handler, output);
weston_log("fbdev output %d×%d px\n",
output->mode.width, output->mode.height);
weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
output->mode.refresh / 1000);
return 0;
out_hw_surface:
fbdev_frame_buffer_unmap(output);
return -1;
}
static int
fbdev_output_disable(struct weston_output *base)
{
struct fbdev_output *output = to_fbdev_output(base);
if (!base->enabled)
return 0;
wl_event_source_remove(output->finish_frame_timer);
output->finish_frame_timer = NULL;
pixman_renderer_output_destroy(&output->base);
fbdev_frame_buffer_unmap(output);
return 0;
}
static struct fbdev_head *
fbdev_head_create(struct fbdev_backend *backend, const char *device)
{
struct fbdev_head *head;
int fb_fd;
head = zalloc(sizeof *head);
if (!head)
return NULL;
head->device = strdup(device);
/* Create the frame buffer. */
fb_fd = fbdev_frame_buffer_open(head->device, &head->fb_info);
if (fb_fd < 0) {
weston_log("Creating frame buffer head failed.\n");
goto out_free;
}
close(fb_fd);
weston_head_init(&head->base, "fbdev");
weston_head_set_connection_status(&head->base, true);
weston_head_set_monitor_strings(&head->base, "unknown",
head->fb_info.id, NULL);
weston_head_set_subpixel(&head->base, WL_OUTPUT_SUBPIXEL_UNKNOWN);
weston_head_set_physical_size(&head->base, head->fb_info.width_mm,
head->fb_info.height_mm);
weston_compositor_add_head(backend->compositor, &head->base);
weston_log("Created head '%s' for device %s (%s)\n",
head->base.name, head->device, head->base.model);
return head;
out_free:
free(head->device);
free(head);
return NULL;
}
static void
fbdev_head_destroy(struct fbdev_head *head)
{
weston_head_release(&head->base);
free(head->device);
free(head);
}
static struct weston_output *
fbdev_output_create(struct weston_compositor *compositor,
const char *name)
{
struct fbdev_output *output;
weston_log("Creating fbdev output.\n");
output = zalloc(sizeof *output);
if (output == NULL)
return NULL;
output->backend = to_fbdev_backend(compositor);
weston_output_init(&output->base, compositor, name);
output->base.destroy = fbdev_output_destroy;
output->base.disable = fbdev_output_disable;
output->base.enable = fbdev_output_enable;
output->base.attach_head = fbdev_output_attach_head;
weston_compositor_add_pending_output(&output->base, compositor);
return &output->base;
}
static void
fbdev_output_destroy(struct weston_output *base)
{
struct fbdev_output *output = to_fbdev_output(base);
weston_log("Destroying fbdev output.\n");
fbdev_output_disable(base);
/* Remove the output. */
weston_output_release(&output->base);
free(output);
}
/* strcmp()-style return values. */
static int
compare_screen_info (const struct fbdev_screeninfo *a,
const struct fbdev_screeninfo *b)
{
if (a->x_resolution == b->x_resolution &&
a->y_resolution == b->y_resolution &&
a->width_mm == b->width_mm &&
a->height_mm == b->height_mm &&
a->bits_per_pixel == b->bits_per_pixel &&
a->pixel_format == b->pixel_format &&
a->refresh_rate == b->refresh_rate)
return 0;
return 1;
}
static int
fbdev_output_reenable(struct fbdev_backend *backend,
struct weston_output *base)
{
struct fbdev_output *output = to_fbdev_output(base);
struct fbdev_head *head;
struct fbdev_screeninfo new_screen_info;
int fb_fd;
head = fbdev_output_get_head(output);
weston_log("Re-enabling fbdev output.\n");
assert(output->base.enabled);
/* Create the frame buffer. */
fb_fd = fbdev_frame_buffer_open(head->device, &new_screen_info);
if (fb_fd < 0) {
weston_log("Creating frame buffer failed.\n");
return -1;
}
/* Check whether the frame buffer details have changed since we were
* disabled. */
if (compare_screen_info(&head->fb_info, &new_screen_info) != 0) {
/* Perform a mode-set to restore the old mode. */
if (fbdev_set_screen_info(fb_fd, &head->fb_info) < 0) {
weston_log("Failed to restore mode settings. "
"Attempting to re-open output anyway.\n");
}
close(fb_fd);
/* Disable and enable the output so that resources depending on
* the frame buffer X/Y resolution (such as the shadow buffer)
* are re-initialised. */
fbdev_output_disable(&output->base);
return fbdev_output_enable(&output->base);
}
/* Map the device if it has the same details as before. */
if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
weston_log("Mapping frame buffer failed.\n");
return -1;
}
return 0;
}
static void
fbdev_backend_destroy(struct weston_compositor *base)
{
struct fbdev_backend *backend = to_fbdev_backend(base);
struct weston_head *head, *next;
udev_input_destroy(&backend->input);
/* Destroy the output. */
weston_compositor_shutdown(base);
wl_list_for_each_safe(head, next, &base->head_list, compositor_link)
fbdev_head_destroy(to_fbdev_head(head));
/* Chain up. */
weston_launcher_destroy(base->launcher);
udev_unref(backend->udev);
free(backend);
}
static void
session_notify(struct wl_listener *listener, void *data)
{
struct weston_compositor *compositor = data;
struct fbdev_backend *backend = to_fbdev_backend(compositor);
struct weston_output *output;
if (compositor->session_active) {
weston_log("entering VT\n");
compositor->state = backend->prev_state;
wl_list_for_each(output, &compositor->output_list, link) {
fbdev_output_reenable(backend, output);
}
weston_compositor_damage_all(compositor);
udev_input_enable(&backend->input);
} else {
weston_log("leaving VT\n");
udev_input_disable(&backend->input);
wl_list_for_each(output, &compositor->output_list, link) {
fbdev_frame_buffer_unmap(to_fbdev_output(output));
}
backend->prev_state = compositor->state;
weston_compositor_offscreen(compositor);
/* If we have a repaint scheduled (from the idle handler), make
* sure we cancel that so we don't try to pageflip when we're
* vt switched away. The OFFSCREEN state will prevent
* further attempts at repainting. When we switch
* back, we schedule a repaint, which will process
* pending frame callbacks. */
wl_list_for_each(output,
&compositor->output_list, link) {
output->repaint_needed = false;
}
}
}
static char *
find_framebuffer_device(struct fbdev_backend *b, const char *seat)
{
struct udev_enumerate *e;
struct udev_list_entry *entry;
const char *path, *device_seat, *id;
char *fb_device_path = NULL;
struct udev_device *device, *fb_device, *pci;
e = udev_enumerate_new(b->udev);
udev_enumerate_add_match_subsystem(e, "graphics");
udev_enumerate_add_match_sysname(e, "fb[0-9]*");
udev_enumerate_scan_devices(e);
fb_device = NULL;
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
bool is_boot_vga = false;
path = udev_list_entry_get_name(entry);
device = udev_device_new_from_syspath(b->udev, path);
if (!device)
continue;
device_seat = udev_device_get_property_value(device, "ID_SEAT");
if (!device_seat)
device_seat = default_seat;
if (strcmp(device_seat, seat)) {
udev_device_unref(device);
continue;
}
pci = udev_device_get_parent_with_subsystem_devtype(device,
"pci", NULL);
if (pci) {
id = udev_device_get_sysattr_value(pci, "boot_vga");
if (id && !strcmp(id, "1"))
is_boot_vga = true;
}
/* If a framebuffer device was found, and this device isn't
* the boot-VGA device, don't use it. */
if (!is_boot_vga && fb_device) {
udev_device_unref(device);
continue;
}
/* There can only be one boot_vga device. Try to use it
* at all costs. */
if (is_boot_vga) {
if (fb_device)
udev_device_unref(fb_device);
fb_device = device;
break;
}
/* Per the (!is_boot_vga && fb_device) test above, only
* trump existing saved devices with boot-VGA devices, so if
* the test ends up here, this must be the first device seen. */
assert(!fb_device);
fb_device = device;
}
udev_enumerate_unref(e);
if (fb_device) {
fb_device_path = strdup(udev_device_get_devnode(fb_device));
udev_device_unref(fb_device);
}
return fb_device_path;
}
static struct fbdev_backend *
fbdev_backend_create(struct weston_compositor *compositor,
struct weston_fbdev_backend_config *param)
{
struct fbdev_backend *backend;
const char *seat_id = default_seat;
const char *session_seat;
session_seat = getenv("XDG_SEAT");
if (session_seat)
seat_id = session_seat;
if (param->seat_id)
seat_id = param->seat_id;
weston_log("initializing fbdev backend\n");
weston_log("warning: the fbdev backend is deprecated, please migrate "
"to the DRM backend\n");
backend = zalloc(sizeof *backend);
if (backend == NULL)
return NULL;
backend->compositor = compositor;
compositor->backend = &backend->base;
if (weston_compositor_set_presentation_clock_software(
compositor) < 0)
goto out_compositor;
backend->udev = udev_new();
if (backend->udev == NULL) {
weston_log("Failed to initialize udev context.\n");
goto out_compositor;
}
if (!param->device)
param->device = find_framebuffer_device(backend, seat_id);
if (!param->device) {
weston_log("fatal: no framebuffer devices detected.\n");
goto out_udev;
}
/* Set up the TTY. */
backend->session_listener.notify = session_notify;
wl_signal_add(&compositor->session_signal,
&backend->session_listener);
compositor->launcher =
weston_launcher_connect(compositor, param->tty, seat_id, false);
if (!compositor->launcher) {
weston_log("fatal: fbdev backend should be run using "
"weston-launch binary, or your system should "
"provide the logind D-Bus API.\n");
goto out_udev;
}
backend->base.destroy = fbdev_backend_destroy;
backend->base.create_output = fbdev_output_create;
backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
weston_setup_vt_switch_bindings(compositor);
if (pixman_renderer_init(compositor) < 0)
goto out_launcher;
if (!fbdev_head_create(backend, param->device))
goto out_launcher;
free(param->device);
udev_input_init(&backend->input, compositor, backend->udev,
seat_id, param->configure_device);
return backend;
out_launcher:
free(param->device);
weston_launcher_destroy(compositor->launcher);
out_udev:
udev_unref(backend->udev);
out_compositor:
weston_compositor_shutdown(compositor);
free(backend);
return NULL;
}
static void
config_init_to_defaults(struct weston_fbdev_backend_config *config)
{
config->tty = 0; /* default to current tty */
config->device = NULL;
config->seat_id = NULL;
}
WL_EXPORT int
weston_backend_init(struct weston_compositor *compositor,
struct weston_backend_config *config_base)
{
struct fbdev_backend *b;
struct weston_fbdev_backend_config config = {{ 0, }};
if (config_base == NULL ||
config_base->struct_version != WESTON_FBDEV_BACKEND_CONFIG_VERSION ||
config_base->struct_size > sizeof(struct weston_fbdev_backend_config)) {
weston_log("fbdev backend config structure is invalid\n");
return -1;
}
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
b = fbdev_backend_create(compositor, &config);
if (b == NULL)
return -1;
return 0;
}
-33
View File
@@ -1,33 +0,0 @@
if not get_option('deprecated-backend-fbdev')
subdir_done()
endif
warning('Support for the deprecated fbdev backend is enabled.')
warning('This feature will be removed in a future version.')
config_h.set('BUILD_FBDEV_COMPOSITOR', '1')
srcs_fbdev = [
'fbdev.c',
presentation_time_server_protocol_h,
]
deps_fbdev = [
dep_libweston_private,
dep_session_helper,
dep_libinput_backend,
dependency('libudev', version: '>= 136'),
]
plugin_fbdev = shared_library(
'fbdev-backend',
srcs_fbdev,
include_directories: common_inc,
dependencies: deps_fbdev,
name_prefix: '',
install: true,
install_dir: dir_module_libweston
)
env_modmap += 'fbdev-backend.so=@0@;'.format(plugin_fbdev.full_path())
install_headers(backend_fbdev_h, subdir: dir_include_libweston_install)
+56 -21
View File
@@ -37,6 +37,7 @@
#include <libweston/backend-headless.h>
#include "shared/helpers.h"
#include "linux-explicit-synchronization.h"
#include "pixel-formats.h"
#include "pixman-renderer.h"
#include "renderer-gl/gl-renderer.h"
#include "shared/weston-drm-fourcc.h"
@@ -70,24 +71,33 @@ struct headless_output {
struct weston_mode mode;
struct wl_event_source *finish_frame_timer;
uint32_t *image_buf;
pixman_image_t *image;
};
static const uint32_t headless_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XRGB8888, /* default for pixman-renderer */
DRM_FORMAT_ARGB8888,
};
static void
headless_head_destroy(struct weston_head *base);
static inline struct headless_head *
to_headless_head(struct weston_head *base)
{
if (base->backend_id != headless_head_destroy)
return NULL;
return container_of(base, struct headless_head, base);
}
static void
headless_output_destroy(struct weston_output *base);
static inline struct headless_output *
to_headless_output(struct weston_output *base)
{
if (base->destroy != headless_output_destroy)
return NULL;
return container_of(base, struct headless_output, base);
}
@@ -122,11 +132,14 @@ finish_frame_handler(void *data)
static int
headless_output_repaint(struct weston_output *output_base,
pixman_region32_t *damage,
void *repaint_data)
pixman_region32_t *damage)
{
struct headless_output *output = to_headless_output(output_base);
struct weston_compositor *ec = output->base.compositor;
struct weston_compositor *ec;
assert(output);
ec = output->base.compositor;
ec->renderer->repaint_output(&output->base, damage);
@@ -152,18 +165,21 @@ headless_output_disable_pixman(struct headless_output *output)
{
pixman_renderer_output_destroy(&output->base);
pixman_image_unref(output->image);
free(output->image_buf);
}
static int
headless_output_disable(struct weston_output *base)
{
struct headless_output *output = to_headless_output(base);
struct headless_backend *b = to_headless_backend(base->compositor);
struct headless_backend *b;
assert(output);
if (!output->base.enabled)
return 0;
b = to_headless_backend(base->compositor);
wl_event_source_remove(output->finish_frame_timer);
switch (b->renderer_type) {
@@ -185,6 +201,8 @@ headless_output_destroy(struct weston_output *base)
{
struct headless_output *output = to_headless_output(base);
assert(output);
headless_output_disable(&output->base);
weston_output_release(&output->base);
@@ -214,20 +232,20 @@ headless_output_enable_gl(struct headless_output *output)
static int
headless_output_enable_pixman(struct headless_output *output)
{
const struct pixel_format_info *pfmt;
const struct pixman_renderer_output_options options = {
.use_shadow = true,
};
output->image_buf = malloc(output->base.current_mode->width *
output->base.current_mode->height * 4);
if (!output->image_buf)
return -1;
pfmt = pixel_format_get_info(headless_formats[0]);
output->image = pixman_image_create_bits(PIXMAN_x8r8g8b8,
output->base.current_mode->width,
output->base.current_mode->height,
output->image_buf,
output->base.current_mode->width * 4);
output->image =
pixman_image_create_bits_no_clear(pfmt->pixman_format,
output->base.current_mode->width,
output->base.current_mode->height,
NULL, 0);
if (!output->image)
return -1;
if (pixman_renderer_output_create(&output->base, &options) < 0)
goto err_renderer;
@@ -238,7 +256,6 @@ headless_output_enable_pixman(struct headless_output *output)
err_renderer:
pixman_image_unref(output->image);
free(output->image_buf);
return -1;
}
@@ -247,10 +264,14 @@ static int
headless_output_enable(struct weston_output *base)
{
struct headless_output *output = to_headless_output(base);
struct headless_backend *b = to_headless_backend(base->compositor);
struct headless_backend *b;
struct wl_event_loop *loop;
int ret = 0;
assert(output);
b = to_headless_backend(base->compositor);
loop = wl_display_get_event_loop(b->compositor->wl_display);
output->finish_frame_timer =
wl_event_loop_add_timer(loop, finish_frame_handler, output);
@@ -287,6 +308,9 @@ headless_output_set_size(struct weston_output *base,
struct weston_head *head;
int output_width, output_height;
if (!output)
return -1;
/* We can only be called once. */
assert(!output->base.current_mode);
@@ -361,7 +385,12 @@ headless_head_create(struct weston_compositor *compositor,
return -1;
weston_head_init(&head->base, name);
head->base.backend_id = headless_head_destroy;
weston_head_set_connection_status(&head->base, true);
weston_head_set_supported_eotf_mask(&head->base,
WESTON_EOTF_MODE_ALL_MASK);
/* Ideally all attributes of the head would be set here, so that the
* user has all the information when deciding to create outputs.
@@ -374,8 +403,12 @@ headless_head_create(struct weston_compositor *compositor,
}
static void
headless_head_destroy(struct headless_head *head)
headless_head_destroy(struct weston_head *base)
{
struct headless_head *head = to_headless_head(base);
assert(head);
weston_head_release(&head->base);
free(head);
}
@@ -388,8 +421,10 @@ headless_destroy(struct weston_compositor *ec)
weston_compositor_shutdown(ec);
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
headless_head_destroy(to_headless_head(base));
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
if (to_headless_head(base))
headless_head_destroy(base);
}
free(b);
}
+17 -5
View File
@@ -4,24 +4,36 @@ endif
config_h.set('BUILD_RDP_COMPOSITOR', '1')
dep_frdp = dependency('freerdp2', version: '>= 2.2.0', required: false)
dep_frdp = dependency('freerdp2', version: '>= 2.3.0', required: false)
if not dep_frdp.found()
error('RDP-backend requires freerdp >= 2.2.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.')
error('RDP-backend requires freerdp >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.')
endif
dep_wpr = dependency('winpr2', version: '>= 2.2.0', required: false)
dep_frdp_server = dependency('freerdp-server2', version: '>= 2.3.0', required: false)
if not dep_frdp_server.found()
error('RDP-backend requires freerdp-server2 >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.')
endif
dep_wpr = dependency('winpr2', version: '>= 2.3.0', required: false)
if not dep_wpr.found()
error('RDP-backend requires winpr >= 2.2.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.')
error('RDP-backend requires winpr >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.')
endif
deps_rdp = [
dep_libweston_private,
dep_frdp,
dep_frdp_server,
dep_wpr,
]
srcs_rdp = [
'rdp.c',
'rdpclip.c',
'rdputil.c',
]
plugin_rdp = shared_library(
'rdp-backend',
'rdp.c',
srcs_rdp,
include_directories: common_inc,
dependencies: deps_rdp,
name_prefix: '',
File diff suppressed because it is too large Load Diff
+263
View File
@@ -0,0 +1,263 @@
/*
* Copyright © 2013 Hardening <rdp.effort@gmail.com>
* Copyright © 2020 Microsoft
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef RDP_H
#define RDP_H
#include <freerdp/version.h>
#include <freerdp/freerdp.h>
#include <freerdp/listener.h>
#include <freerdp/update.h>
#include <freerdp/input.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/codec/nsc.h>
#include <freerdp/locale/keyboard.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/server/cliprdr.h>
#include <libweston/libweston.h>
#include <libweston/backend-rdp.h>
#include <libweston/weston-log.h>
#include "backend.h"
#include "shared/helpers.h"
#include "shared/string-helpers.h"
#define MAX_FREERDP_FDS 32
#define DEFAULT_AXIS_STEP_DISTANCE 10
#define DEFAULT_PIXEL_FORMAT PIXEL_FORMAT_BGRA32
/* https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeyboardtype
* defines a keyboard type that isn't currently defined in FreeRDP, but is
* available for RDP connections */
#ifndef KBD_TYPE_KOREAN
#define KBD_TYPE_KOREAN 8
#endif
/* WinPR's GetVirtualKeyCodeFromVirtualScanCode() can't handle hangul/hanja keys */
/* 0x1f1 and 0x1f2 keys are only exists on Korean 103 keyboard (Type 8:SubType 6) */
/* From Linux's keyboard driver at drivers/input/keyboard/atkbd.c */
#define ATKBD_RET_HANJA 0xf1
#define ATKBD_RET_HANGEUL 0xf2
struct rdp_output;
struct rdp_backend {
struct weston_backend base;
struct weston_compositor *compositor;
freerdp_listener *listener;
struct wl_event_source *listener_events[MAX_FREERDP_FDS];
struct rdp_output *output;
struct weston_log_scope *debug;
struct weston_log_scope *verbose;
struct weston_log_scope *clipboard_debug;
struct weston_log_scope *clipboard_verbose;
struct wl_list peers;
char *server_cert;
char *server_key;
char *rdp_key;
int tls_enabled;
int no_clients_resize;
int force_no_compression;
bool remotefx_codec;
int external_listener_fd;
int rdp_monitor_refresh_rate;
pid_t compositor_tid;
rdp_audio_in_setup audio_in_setup;
rdp_audio_in_teardown audio_in_teardown;
rdp_audio_out_setup audio_out_setup;
rdp_audio_out_teardown audio_out_teardown;
};
enum peer_item_flags {
RDP_PEER_ACTIVATED = (1 << 0),
RDP_PEER_OUTPUT_ENABLED = (1 << 1),
};
struct rdp_peers_item {
int flags;
freerdp_peer *peer;
struct weston_seat *seat;
struct wl_list link;
};
struct rdp_head {
struct weston_head base;
};
struct rdp_output {
struct weston_output base;
struct wl_event_source *finish_frame_timer;
pixman_image_t *shadow_surface;
};
struct rdp_peer_context {
rdpContext _p;
struct rdp_backend *rdpBackend;
struct wl_event_source *events[MAX_FREERDP_FDS + 1]; /* +1 for WTSVirtualChannelManagerGetFileDescriptor */
RFX_CONTEXT *rfx_context;
wStream *encode_stream;
RFX_RECT *rfx_rects;
NSC_CONTEXT *nsc_context;
struct rdp_peers_item item;
bool button_state[5];
int verticalAccumWheelRotationPrecise;
int verticalAccumWheelRotationDiscrete;
int horizontalAccumWheelRotationPrecise;
int horizontalAccumWheelRotationDiscrete;
HANDLE vcm;
/* list of outstanding event_source sent from FreeRDP thread to display loop.*/
int loop_task_event_source_fd;
struct wl_event_source *loop_task_event_source;
pthread_mutex_t loop_task_list_mutex;
struct wl_list loop_task_list; /* struct rdp_loop_task::link */
/* Clipboard support */
CliprdrServerContext *clipboard_server_context;
void *audio_in_private;
void *audio_out_private;
struct rdp_clipboard_data_source *clipboard_client_data_source;
struct rdp_clipboard_data_source *clipboard_inflight_client_data_source;
struct wl_listener clipboard_selection_listener;
};
typedef struct rdp_peer_context RdpPeerContext;
typedef void (*rdp_loop_task_func_t)(bool freeOnly, void *data);
struct rdp_loop_task {
struct wl_list link;
RdpPeerContext *peerCtx;
rdp_loop_task_func_t func;
};
#define rdp_debug_verbose(b, ...) \
rdp_debug_print(b->verbose, false, __VA_ARGS__)
#define rdp_debug_verbose_continue(b, ...) \
rdp_debug_print(b->verbose, true, __VA_ARGS__)
#define rdp_debug(b, ...) \
rdp_debug_print(b->debug, false, __VA_ARGS__)
#define rdp_debug_continue(b, ...) \
rdp_debug_print(b->debug, true, __VA_ARGS__)
#define rdp_debug_clipboard_verbose(b, ...) \
rdp_debug_print(b->clipboard_verbose, false, __VA_ARGS__)
#define rdp_debug_clipboard_verbose_continue(b, ...) \
rdp_debug_print(b->clipboard_verbose, true, __VA_ARGS__)
#define rdp_debug_clipboard(b, ...) \
rdp_debug_print(b->clipboard_debug, false, __VA_ARGS__)
#define rdp_debug_clipboard_continue(b, ...) \
rdp_debug_print(b->clipboard_debug, true, __VA_ARGS__)
/* rdputil.c */
void
rdp_debug_print(struct weston_log_scope *log_scope, bool cont, char *fmt, ...);
int
rdp_wl_array_read_fd(struct wl_array *array, int fd);
void
convert_rdp_keyboard_to_xkb_rule_names(UINT32 KeyboardType, UINT32 KeyboardSubType, UINT32 KeyboardLayout, struct xkb_rule_names *xkbRuleNames);
void
assert_compositor_thread(struct rdp_backend *b);
void
assert_not_compositor_thread(struct rdp_backend *b);
bool
rdp_event_loop_add_fd(struct wl_event_loop *loop,
int fd, uint32_t mask,
wl_event_loop_fd_func_t func,
void *data,
struct wl_event_source **event_source);
void
rdp_dispatch_task_to_display_loop(RdpPeerContext *peerCtx,
rdp_loop_task_func_t func,
struct rdp_loop_task *task);
bool
rdp_initialize_dispatch_task_event_source(RdpPeerContext *peerCtx);
void
rdp_destroy_dispatch_task_event_source(RdpPeerContext *peerCtx);
/* rdpclip.c */
int
rdp_clipboard_init(freerdp_peer *client);
void
rdp_clipboard_destroy(RdpPeerContext *peerCtx);
void
rdp_head_destroy(struct weston_head *base);
static inline struct rdp_head *
to_rdp_head(struct weston_head *base)
{
if (base->backend_id != rdp_head_destroy)
return NULL;
return container_of(base, struct rdp_head, base);
}
void
rdp_output_destroy(struct weston_output *base);
static inline struct rdp_output *
to_rdp_output(struct weston_output *base)
{
if (base->destroy != rdp_output_destroy)
return NULL;
return container_of(base, struct rdp_output, base);
}
static inline struct rdp_backend *
to_rdp_backend(struct weston_compositor *base)
{
return container_of(base->backend, struct rdp_backend, base);
}
#endif
File diff suppressed because it is too large Load Diff
+262
View File
@@ -0,0 +1,262 @@
/*
* Copyright © 2020 Microsoft
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/eventfd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "rdp.h"
static int cached_tm_mday = -1;
void rdp_debug_print(struct weston_log_scope *log_scope, bool cont, char *fmt, ...)
{
char timestr[128];
int len_va;
char *str;
if (!log_scope || !weston_log_scope_is_enabled(log_scope))
return;
va_list ap;
va_start(ap, fmt);
if (cont) {
weston_log_scope_vprintf(log_scope, fmt, ap);
goto end;
}
weston_log_timestamp(timestr, sizeof(timestr), &cached_tm_mday);
len_va = vasprintf(&str, fmt, ap);
if (len_va >= 0) {
weston_log_scope_printf(log_scope, "%s %s",
timestr, str);
free(str);
} else {
const char *oom = "Out of memory";
weston_log_scope_printf(log_scope, "%s %s",
timestr, oom);
}
end:
va_end(ap);
}
void
assert_compositor_thread(struct rdp_backend *b)
{
assert(b->compositor_tid == gettid());
}
void
assert_not_compositor_thread(struct rdp_backend *b)
{
assert(b->compositor_tid != gettid());
}
bool
rdp_event_loop_add_fd(struct wl_event_loop *loop,
int fd, uint32_t mask,
wl_event_loop_fd_func_t func,
void *data, struct wl_event_source **event_source)
{
*event_source = wl_event_loop_add_fd(loop, fd, 0, func, data);
if (!*event_source) {
weston_log("%s: wl_event_loop_add_fd failed.\n", __func__);
return false;
}
wl_event_source_fd_update(*event_source, mask);
return true;
}
void
rdp_dispatch_task_to_display_loop(RdpPeerContext *peerCtx,
rdp_loop_task_func_t func,
struct rdp_loop_task *task)
{
/* this function is ONLY used to queue the task from FreeRDP thread,
* and the task to be processed at wayland display loop thread. */
assert_not_compositor_thread(peerCtx->rdpBackend);
task->peerCtx = peerCtx;
task->func = func;
pthread_mutex_lock(&peerCtx->loop_task_list_mutex);
/* this inserts at head */
wl_list_insert(&peerCtx->loop_task_list, &task->link);
pthread_mutex_unlock(&peerCtx->loop_task_list_mutex);
eventfd_write(peerCtx->loop_task_event_source_fd, 1);
}
static int
rdp_dispatch_task(int fd, uint32_t mask, void *arg)
{
RdpPeerContext *peerCtx = (RdpPeerContext *)arg;
struct rdp_loop_task *task, *tmp;
eventfd_t dummy;
/* this must be called back at wayland display loop thread */
assert_compositor_thread(peerCtx->rdpBackend);
eventfd_read(peerCtx->loop_task_event_source_fd, &dummy);
pthread_mutex_lock(&peerCtx->loop_task_list_mutex);
/* dequeue the first task which is at last, so use reverse. */
assert(!wl_list_empty(&peerCtx->loop_task_list));
wl_list_for_each_reverse_safe(task, tmp, &peerCtx->loop_task_list, link) {
wl_list_remove(&task->link);
break;
}
pthread_mutex_unlock(&peerCtx->loop_task_list_mutex);
/* Dispatch and task will be freed by caller. */
task->func(false, task);
return 0;
}
bool
rdp_initialize_dispatch_task_event_source(RdpPeerContext *peerCtx)
{
struct rdp_backend *b = peerCtx->rdpBackend;
struct wl_event_loop *loop;
bool ret;
if (pthread_mutex_init(&peerCtx->loop_task_list_mutex, NULL) == -1) {
weston_log("%s: pthread_mutex_init failed. %s\n", __func__, strerror(errno));
goto error_mutex;
}
assert(peerCtx->loop_task_event_source_fd == -1);
peerCtx->loop_task_event_source_fd = eventfd(0, EFD_SEMAPHORE | EFD_CLOEXEC);
if (peerCtx->loop_task_event_source_fd == -1) {
weston_log("%s: eventfd(EFD_SEMAPHORE) failed. %s\n", __func__, strerror(errno));
goto error_event_source_fd;
}
assert(wl_list_empty(&peerCtx->loop_task_list));
loop = wl_display_get_event_loop(b->compositor->wl_display);
assert(peerCtx->loop_task_event_source == NULL);
ret = rdp_event_loop_add_fd(loop,
peerCtx->loop_task_event_source_fd,
WL_EVENT_READABLE, rdp_dispatch_task,
peerCtx,
&peerCtx->loop_task_event_source);
if (!ret)
goto error_event_loop_add_fd;
return true;
error_event_loop_add_fd:
close(peerCtx->loop_task_event_source_fd);
peerCtx->loop_task_event_source_fd = -1;
error_event_source_fd:
pthread_mutex_destroy(&peerCtx->loop_task_list_mutex);
error_mutex:
return false;
}
void
rdp_destroy_dispatch_task_event_source(RdpPeerContext *peerCtx)
{
struct rdp_loop_task *task, *tmp;
/* This function must be called all virtual channel thread at FreeRDP is terminated,
* that ensures no more incoming tasks. */
if (peerCtx->loop_task_event_source) {
wl_event_source_remove(peerCtx->loop_task_event_source);
peerCtx->loop_task_event_source = NULL;
}
wl_list_for_each_reverse_safe(task, tmp, &peerCtx->loop_task_list, link) {
wl_list_remove(&task->link);
/* inform caller task is not really scheduled prior to context destruction,
* inform them to clean them up. */
task->func(true /* freeOnly */, task);
}
assert(wl_list_empty(&peerCtx->loop_task_list));
if (peerCtx->loop_task_event_source_fd != -1) {
close(peerCtx->loop_task_event_source_fd);
peerCtx->loop_task_event_source_fd = -1;
}
pthread_mutex_destroy(&peerCtx->loop_task_list_mutex);
}
/* This is a little tricky - it makes sure there's always at least
* one spare byte in the array in case the caller needs to add a
* null terminator to it. We can't just null terminate the array
* here, because some callers won't want that - and some won't
* like having an odd number of bytes.
*/
int
rdp_wl_array_read_fd(struct wl_array *array, int fd)
{
int len, size;
char *data;
/* Make sure we have at least 1024 bytes of space left */
if (array->alloc - array->size < 1024) {
if (!wl_array_add(array, 1024)) {
errno = ENOMEM;
return -1;
}
array->size -= 1024;
}
data = (char *)array->data + array->size;
/* Leave one char in case the caller needs space for a
* null terminator */
size = array->alloc - array->size - 1;
do {
len = read(fd, data, size);
} while (len == -1 && errno == EINTR);
if (len == -1)
return -1;
array->size += len;
return len;
}
+135 -160
View File
@@ -76,7 +76,6 @@ struct wayland_backend {
struct wl_display *wl_display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shell *shell;
struct xdg_wm_base *xdg_wm_base;
struct zwp_fullscreen_shell_v1 *fshell;
struct wl_shm *shm;
@@ -112,7 +111,6 @@ struct wayland_output {
struct wl_output *output;
uint32_t global_id;
struct wl_shell_surface *shell_surface;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
int configure_width, configure_height;
@@ -233,15 +231,25 @@ struct wayland_input {
struct gl_renderer_interface *gl_renderer;
static void
wayland_head_destroy(struct weston_head *base);
static inline struct wayland_head *
to_wayland_head(struct weston_head *base)
{
if (base->backend_id != wayland_head_destroy)
return NULL;
return container_of(base, struct wayland_head, base);
}
static void
wayland_output_destroy(struct weston_output *base);
static inline struct wayland_output *
to_wayland_output(struct weston_output *base)
{
if (base->destroy != wayland_output_destroy)
return NULL;
return container_of(base, struct wayland_output, base);
}
@@ -293,7 +301,7 @@ wayland_output_get_shm_buffer(struct wayland_output *output)
struct wl_shm_pool *pool;
int width, height, stride;
int32_t fx, fy;
struct weston_geometry area;
int fd;
unsigned char *data;
@@ -369,13 +377,20 @@ wayland_output_get_shm_buffer(struct wayland_output *output)
cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32,
width, height, stride);
fx = 0;
fy = 0;
if (output->frame)
frame_interior(output->frame, &fx, &fy, 0, 0);
if (output->frame) {
frame_interior(output->frame, &area.x, &area.y,
&area.width, &area.height);
} else {
area.x = 0;
area.y = 0;
area.width = output->base.current_mode->width;
area.height = output->base.current_mode->height;
}
/* Address only the interior, excluding output decorations */
sb->pm_image =
pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height,
(uint32_t *)(data + fy * stride) + fx,
pixman_image_create_bits(PIXMAN_a8r8g8b8, area.width, area.height,
(uint32_t *)(data + area.y * stride) + area.x,
stride);
return sb;
@@ -501,8 +516,11 @@ static int
wayland_output_start_repaint_loop(struct weston_output *output_base)
{
struct wayland_output *output = to_wayland_output(output_base);
struct wayland_backend *wb =
to_wayland_backend(output->base.compositor);
struct wayland_backend *wb;
assert(output);
wb = to_wayland_backend(output->base.compositor);
/* If this is the initial frame, we need to attach a buffer so that
* the compositor can map the surface and include it in its render
@@ -526,11 +544,14 @@ wayland_output_start_repaint_loop(struct weston_output *output_base)
#ifdef ENABLE_EGL
static int
wayland_output_repaint_gl(struct weston_output *output_base,
pixman_region32_t *damage,
void *repaint_data)
pixman_region32_t *damage)
{
struct wayland_output *output = to_wayland_output(output_base);
struct weston_compositor *ec = output->base.compositor;
struct weston_compositor *ec;
assert(output);
ec = output->base.compositor;
output->frame_cb = wl_surface_frame(output->parent.surface);
wl_callback_add_listener(output->frame_cb, &frame_listener, output);
@@ -638,14 +659,16 @@ wayland_shm_buffer_attach(struct wayland_shm_buffer *sb)
static int
wayland_output_repaint_pixman(struct weston_output *output_base,
pixman_region32_t *damage,
void *repaint_data)
pixman_region32_t *damage)
{
struct wayland_output *output = to_wayland_output(output_base);
struct wayland_backend *b =
to_wayland_backend(output->base.compositor);
struct wayland_backend *b;
struct wayland_shm_buffer *sb;
assert(output);
b = to_wayland_backend(output->base.compositor);
if (output->frame) {
if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
wl_list_for_each(sb, &output->shm.buffers, link)
@@ -692,11 +715,6 @@ wayland_backend_destroy_output_surface(struct wayland_output *output)
output->parent.xdg_surface = NULL;
}
if (output->parent.shell_surface) {
wl_shell_surface_destroy(output->parent.shell_surface);
output->parent.shell_surface = NULL;
}
wl_surface_destroy(output->parent.surface);
output->parent.surface = NULL;
}
@@ -718,7 +736,11 @@ static int
wayland_output_disable(struct weston_output *base)
{
struct wayland_output *output = to_wayland_output(base);
struct wayland_backend *b = to_wayland_backend(base->compositor);
struct wayland_backend *b;
assert(output);
b = to_wayland_backend(base->compositor);
if (!output->base.enabled)
return 0;
@@ -752,6 +774,8 @@ wayland_output_destroy(struct weston_output *base)
{
struct wayland_output *output = to_wayland_output(base);
assert(output);
wayland_output_disable(&output->base);
weston_output_release(&output->base);
@@ -763,8 +787,6 @@ wayland_output_destroy(struct weston_output *base)
free(output);
}
static const struct wl_shell_surface_listener shell_surface_listener;
#ifdef ENABLE_EGL
static int
wayland_output_init_gl_renderer(struct wayland_output *output)
@@ -816,64 +838,54 @@ wayland_output_init_pixman_renderer(struct wayland_output *output)
static void
wayland_output_resize_surface(struct wayland_output *output)
{
struct wayland_backend *b =
to_wayland_backend(output->base.compositor);
int32_t ix, iy, iwidth, iheight;
int32_t width, height;
struct wayland_backend *b = to_wayland_backend(output->base.compositor);
/* Defaults for without frame: */
struct weston_size fb_size = {
.width = output->base.current_mode->width,
.height = output->base.current_mode->height
};
struct weston_geometry area = {
.x = 0,
.y = 0,
.width = fb_size.width,
.height = fb_size.height
};
struct weston_geometry inp = area;
struct weston_geometry opa = area;
struct wl_region *region;
width = output->base.current_mode->width;
height = output->base.current_mode->height;
if (output->frame) {
frame_resize_inside(output->frame, width, height);
frame_resize_inside(output->frame, area.width, area.height);
frame_interior(output->frame, &area.x, &area.y, NULL, NULL);
fb_size.width = frame_width(output->frame);
fb_size.height = frame_height(output->frame);
frame_input_rect(output->frame, &ix, &iy, &iwidth, &iheight);
region = wl_compositor_create_region(b->parent.compositor);
wl_region_add(region, ix, iy, iwidth, iheight);
wl_surface_set_input_region(output->parent.surface, region);
wl_region_destroy(region);
if (output->parent.xdg_surface) {
xdg_surface_set_window_geometry(output->parent.xdg_surface,
ix,
iy,
iwidth,
iheight);
}
frame_opaque_rect(output->frame, &ix, &iy, &iwidth, &iheight);
region = wl_compositor_create_region(b->parent.compositor);
wl_region_add(region, ix, iy, iwidth, iheight);
wl_surface_set_opaque_region(output->parent.surface, region);
wl_region_destroy(region);
width = frame_width(output->frame);
height = frame_height(output->frame);
} else {
region = wl_compositor_create_region(b->parent.compositor);
wl_region_add(region, 0, 0, width, height);
wl_surface_set_input_region(output->parent.surface, region);
wl_region_destroy(region);
region = wl_compositor_create_region(b->parent.compositor);
wl_region_add(region, 0, 0, width, height);
wl_surface_set_opaque_region(output->parent.surface, region);
wl_region_destroy(region);
if (output->parent.xdg_surface) {
xdg_surface_set_window_geometry(output->parent.xdg_surface,
0,
0,
width,
height);
}
frame_input_rect(output->frame, &inp.x, &inp.y,
&inp.width, &inp.height);
frame_opaque_rect(output->frame, &opa.x, &opa.y,
&opa.width, &opa.height);
}
region = wl_compositor_create_region(b->parent.compositor);
wl_region_add(region, inp.x, inp.y, inp.width, inp.height);
wl_surface_set_input_region(output->parent.surface, region);
wl_region_destroy(region);
if (output->parent.xdg_surface) {
xdg_surface_set_window_geometry(output->parent.xdg_surface,
inp.x, inp.y,
inp.width, inp.height);
}
region = wl_compositor_create_region(b->parent.compositor);
wl_region_add(region, opa.x, opa.y, opa.width, opa.height);
wl_surface_set_opaque_region(output->parent.surface, region);
wl_region_destroy(region);
#ifdef ENABLE_EGL
if (output->gl.egl_window) {
wl_egl_window_resize(output->gl.egl_window,
width, height, 0, 0);
fb_size.width, fb_size.height, 0, 0);
/* These will need to be re-created due to the resize */
gl_renderer->output_set_border(&output->base,
@@ -928,8 +940,6 @@ wayland_output_set_windowed(struct wayland_output *output)
if (output->parent.xdg_toplevel) {
xdg_toplevel_unset_fullscreen(output->parent.xdg_toplevel);
} else if (output->parent.shell_surface) {
wl_shell_surface_set_toplevel(output->parent.shell_surface);
} else {
abort();
}
@@ -939,7 +949,6 @@ wayland_output_set_windowed(struct wayland_output *output)
static void
wayland_output_set_fullscreen(struct wayland_output *output,
enum wl_shell_surface_fullscreen_method method,
uint32_t framerate, struct wl_output *target)
{
if (output->frame) {
@@ -951,9 +960,6 @@ wayland_output_set_fullscreen(struct wayland_output *output,
if (output->parent.xdg_toplevel) {
xdg_toplevel_set_fullscreen(output->parent.xdg_toplevel, target);
} else if (output->parent.shell_surface) {
wl_shell_surface_set_fullscreen(output->parent.shell_surface,
method, framerate, target);
} else {
abort();
}
@@ -1062,7 +1068,7 @@ static int
wayland_output_switch_mode(struct weston_output *output_base,
struct weston_mode *mode)
{
struct wayland_output *output = to_wayland_output(output_base);
struct wayland_output *output;
struct wayland_backend *b;
struct wl_surface *old_surface;
struct weston_mode *old_mode;
@@ -1073,6 +1079,9 @@ wayland_output_switch_mode(struct weston_output *output_base,
return -1;
}
output = to_wayland_output(output_base);
assert(output);
if (mode == NULL) {
weston_log("mode is NULL.\n");
return -1;
@@ -1080,7 +1089,7 @@ wayland_output_switch_mode(struct weston_output *output_base,
b = to_wayland_backend(output_base->compositor);
if (output->parent.xdg_surface || output->parent.shell_surface || !b->parent.fshell)
if (output->parent.xdg_surface || !b->parent.fshell)
return -1;
mode = wayland_output_choose_mode(output, mode);
@@ -1221,20 +1230,6 @@ wayland_backend_create_output_surface(struct wayland_output *output)
weston_log("wayland-backend: Using xdg_wm_base\n");
}
else if (b->parent.shell) {
output->parent.shell_surface =
wl_shell_get_shell_surface(b->parent.shell,
output->parent.surface);
if (!output->parent.shell_surface) {
wl_surface_destroy(output->parent.surface);
return -1;
}
wl_shell_surface_add_listener(output->parent.shell_surface,
&shell_surface_listener, output);
weston_log("wayland-backend: Using wl_shell\n");
}
return 0;
}
@@ -1243,10 +1238,14 @@ static int
wayland_output_enable(struct weston_output *base)
{
struct wayland_output *output = to_wayland_output(base);
struct wayland_backend *b = to_wayland_backend(base->compositor);
struct wayland_backend *b;
enum mode_status mode_status;
int ret = 0;
assert(output);
b = to_wayland_backend(base->compositor);
wl_list_init(&output->shm.buffers);
wl_list_init(&output->shm.free_buffers);
@@ -1295,13 +1294,9 @@ wayland_output_enable(struct weston_output *base)
output->parent.draw_initial_frame = true;
}
} else {
wayland_output_set_fullscreen(output,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER,
output->mode.refresh, output->parent.output);
}
} else if (b->fullscreen) {
wayland_output_set_fullscreen(output, 0, 0, NULL);
wayland_output_set_fullscreen(output, 0, NULL);
} else {
wayland_output_set_windowed(output);
}
@@ -1326,9 +1321,16 @@ static int
wayland_output_attach_head(struct weston_output *output_base,
struct weston_head *head_base)
{
struct wayland_backend *b = to_wayland_backend(output_base->compositor);
struct wayland_output *output = to_wayland_output(output_base);
struct wayland_head *head = to_wayland_head(head_base);
struct wayland_backend *b;
assert(output);
if (!head)
return -1;
b = to_wayland_backend(output_base->compositor);
if (!wl_list_empty(&output->base.head_list))
return -1;
@@ -1353,6 +1355,8 @@ wayland_output_detach_head(struct weston_output *output_base,
{
struct wayland_output *output = to_wayland_output(output_base);
assert(output);
/* Rely on the disable hook if the output was enabled. We do not
* support cloned heads, so detaching is guaranteed to disable the
* output.
@@ -1411,6 +1415,9 @@ wayland_head_create(struct weston_compositor *compositor, const char *name)
return NULL;
weston_head_init(&head->base, name);
head->base.backend_id = wayland_head_destroy;
weston_head_set_connection_status(&head->base, true);
weston_compositor_add_head(compositor, &head->base);
@@ -1458,8 +1465,12 @@ wayland_head_create_for_parent_output(struct weston_compositor *compositor,
}
static void
wayland_head_destroy(struct wayland_head *head)
wayland_head_destroy(struct weston_head *base)
{
struct wayland_head *head = to_wayland_head(base);
assert(head);
if (head->parent_output)
head->parent_output->head = NULL;
@@ -1474,6 +1485,9 @@ wayland_output_set_size(struct weston_output *base, int width, int height)
struct weston_head *head;
int output_width, output_height;
if (!output)
return -1;
/* We can only be called once. */
assert(!output->base.current_mode);
@@ -1564,13 +1578,10 @@ wayland_output_setup_fullscreen(struct wayland_output *output,
return -1;
/* What should size be set if conditional is false? */
if (b->parent.xdg_wm_base || b->parent.shell) {
if (b->parent.xdg_wm_base) {
if (output->parent.xdg_toplevel)
xdg_toplevel_set_fullscreen(output->parent.xdg_toplevel,
output->parent.output);
else if (output->parent.shell_surface)
wl_shell_surface_set_fullscreen(output->parent.shell_surface,
0, 0, NULL);
wl_display_roundtrip(b->parent.wl_display);
@@ -1594,36 +1605,6 @@ err_set_size:
return -1;
}
static void
shell_surface_ping(void *data, struct wl_shell_surface *shell_surface,
uint32_t serial)
{
wl_shell_surface_pong(shell_surface, serial);
}
static void
shell_surface_configure(void *data, struct wl_shell_surface *shell_surface,
uint32_t edges, int32_t width, int32_t height)
{
struct wayland_output *output = data;
output->parent.configure_width = width;
output->parent.configure_height = height;
/* FIXME: implement resizing */
}
static void
shell_surface_popup_done(void *data, struct wl_shell_surface *shell_surface)
{
}
static const struct wl_shell_surface_listener shell_surface_listener = {
shell_surface_ping,
shell_surface_configure,
shell_surface_popup_done
};
/* Events received from the wayland-server this compositor is client of: */
/* parent input interface */
@@ -1801,9 +1782,6 @@ input_handle_button(void *data, struct wl_pointer *pointer,
if (input->output->parent.xdg_toplevel)
xdg_toplevel_move(input->output->parent.xdg_toplevel,
input->parent.seat, serial);
else if (input->output->parent.shell_surface)
wl_shell_surface_move(input->output->parent.shell_surface,
input->parent.seat, serial);
frame_status_clear(input->output->frame,
FRAME_STATUS_MOVE);
return;
@@ -2157,9 +2135,6 @@ input_handle_touch_down(void *data, struct wl_touch *wl_touch,
if (output->parent.xdg_toplevel)
xdg_toplevel_move(output->parent.xdg_toplevel,
input->parent.seat, serial);
else if (output->parent.shell_surface)
wl_shell_surface_move(output->parent.shell_surface,
input->parent.seat, serial);
frame_status_clear(output->frame,
FRAME_STATUS_MOVE);
return;
@@ -2187,10 +2162,6 @@ input_handle_touch_up(void *data, struct wl_touch *wl_touch,
timespec_from_msec(&ts, time);
input->touch_points--;
if (input->touch_points == 0) {
input->touch_focus = NULL;
input->touch_active = false;
}
if (!output)
return;
@@ -2253,6 +2224,11 @@ input_handle_touch_frame(void *data, struct wl_touch *wl_touch)
return;
notify_touch_frame(input->touch_device);
if (input->touch_points == 0) {
input->touch_focus = NULL;
input->touch_active = false;
}
}
static void
@@ -2629,7 +2605,7 @@ wayland_parent_output_destroy(struct wayland_parent_output *output)
wl_callback_destroy(output->sync_cb);
if (output->head)
wayland_head_destroy(output->head);
wayland_head_destroy(&output->head->base);
wl_output_destroy(output->global);
free(output->physical.make);
@@ -2671,10 +2647,6 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
&xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(b->parent.xdg_wm_base,
&wm_base_listener, b);
} else if (strcmp(interface, "wl_shell") == 0) {
b->parent.shell =
wl_registry_bind(registry, name,
&wl_shell_interface, 1);
} else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
b->parent.fshell =
wl_registry_bind(registry, name,
@@ -2742,14 +2714,20 @@ wayland_destroy(struct weston_compositor *ec)
{
struct wayland_backend *b = to_wayland_backend(ec);
struct weston_head *base, *next;
struct wayland_parent_output *output, *next_output;
struct wayland_input *input, *next_input;
wl_event_source_remove(b->parent.wl_source);
weston_compositor_shutdown(ec);
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
wayland_head_destroy(to_wayland_head(base));
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
if (to_wayland_head(base))
wayland_head_destroy(base);
}
wl_list_for_each_safe(output, next_output, &b->parent.output_list, link)
wayland_parent_output_destroy(output);
wl_list_for_each_safe(input, next_input, &b->input_list, link)
wayland_input_destroy(input);
@@ -2763,9 +2741,6 @@ wayland_destroy(struct weston_compositor *ec)
if (b->parent.xdg_wm_base)
xdg_wm_base_destroy(b->parent.xdg_wm_base);
if (b->parent.shell)
wl_shell_destroy(b->parent.shell);
if (b->parent.fshell)
zwp_fullscreen_shell_v1_release(b->parent.fshell);
@@ -2833,7 +2808,7 @@ fullscreen_binding(struct weston_keyboard *keyboard,
return;
if (input->output->frame)
wayland_output_set_fullscreen(input->output, 0, 0, NULL);
wayland_output_set_fullscreen(input->output, 0, NULL);
else
wayland_output_set_windowed(input->output);
+93 -47
View File
@@ -119,6 +119,7 @@ struct x11_backend {
xcb_atom_t cardinal;
xcb_atom_t xkb_names;
} atom;
xcb_generic_event_t *prev_event;
};
struct x11_head {
@@ -151,15 +152,25 @@ struct window_delete_data {
struct gl_renderer_interface *gl_renderer;
static void
x11_head_destroy(struct weston_head *base);
static inline struct x11_head *
to_x11_head(struct weston_head *base)
{
if (base->backend_id != x11_head_destroy)
return NULL;
return container_of(base, struct x11_head, base);
}
static void
x11_output_destroy(struct weston_output *base);
static inline struct x11_output *
to_x11_output(struct weston_output *base)
{
if (base->destroy != x11_output_destroy)
return NULL;
return container_of(base, struct x11_output, base);
}
@@ -417,11 +428,14 @@ x11_output_start_repaint_loop(struct weston_output *output)
static int
x11_output_repaint_gl(struct weston_output *output_base,
pixman_region32_t *damage,
void *repaint_data)
pixman_region32_t *damage)
{
struct x11_output *output = to_x11_output(output_base);
struct weston_compositor *ec = output->base.compositor;
struct weston_compositor *ec;
assert(output);
ec = output->base.compositor;
ec->renderer->repaint_output(output_base, damage);
@@ -436,8 +450,8 @@ static void
set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region)
{
struct x11_output *output = to_x11_output(output_base);
struct weston_compositor *ec = output->base.compositor;
struct x11_backend *b = to_x11_backend(ec);
struct weston_compositor *ec;
struct x11_backend *b;
pixman_region32_t transformed_region;
pixman_box32_t *rects;
xcb_rectangle_t *output_rects;
@@ -445,6 +459,12 @@ set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region
int nrects, i;
xcb_generic_error_t *err;
if (!output)
return;
ec = output->base.compositor;
b = to_x11_backend(ec);
pixman_region32_init(&transformed_region);
pixman_region32_copy(&transformed_region, region);
pixman_region32_translate(&transformed_region,
@@ -486,15 +506,19 @@ set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region
static int
x11_output_repaint_shm(struct weston_output *output_base,
pixman_region32_t *damage,
void *repaint_data)
pixman_region32_t *damage)
{
struct x11_output *output = to_x11_output(output_base);
struct weston_compositor *ec = output->base.compositor;
struct x11_backend *b = to_x11_backend(ec);
struct weston_compositor *ec;
struct x11_backend *b;
xcb_void_cookie_t cookie;
xcb_generic_error_t *err;
assert(output);
ec = output->base.compositor;
b = to_x11_backend(ec);
pixman_renderer_output_set_buffer(output_base, output->hw_surface);
ec->renderer->repaint_output(output_base, damage);
@@ -567,13 +591,13 @@ x11_output_set_wm_protocols(struct x11_backend *b,
}
struct wm_normal_hints {
uint32_t flags;
uint32_t flags;
uint32_t pad[4];
int32_t min_width, min_height;
int32_t max_width, max_height;
int32_t width_inc, height_inc;
int32_t min_aspect_x, min_aspect_y;
int32_t max_aspect_x, max_aspect_y;
int32_t width_inc, height_inc;
int32_t min_aspect_x, min_aspect_y;
int32_t max_aspect_x, max_aspect_y;
int32_t base_width, base_height;
int32_t win_gravity;
};
@@ -803,12 +827,13 @@ static int
x11_output_switch_mode(struct weston_output *base, struct weston_mode *mode)
{
struct x11_backend *b;
struct x11_output *output;
struct x11_output *output = to_x11_output(base);
static uint32_t values[2];
int ret;
assert(output);
b = to_x11_backend(base->compositor);
output = to_x11_output(base);
if (mode->width == output->mode.width &&
mode->height == output->mode.height)
@@ -880,7 +905,11 @@ static int
x11_output_disable(struct weston_output *base)
{
struct x11_output *output = to_x11_output(base);
struct x11_backend *backend = to_x11_backend(base->compositor);
struct x11_backend *backend;
assert(output);
backend = to_x11_backend(base->compositor);
if (!output->base.enabled)
return 0;
@@ -905,6 +934,8 @@ x11_output_destroy(struct weston_output *base)
{
struct x11_output *output = to_x11_output(base);
assert(output);
x11_output_disable(&output->base);
weston_output_release(&output->base);
@@ -915,7 +946,12 @@ static int
x11_output_enable(struct weston_output *base)
{
struct x11_output *output = to_x11_output(base);
struct x11_backend *b = to_x11_backend(base->compositor);
const struct weston_mode *mode = output->base.current_mode;
struct x11_backend *b;
assert(output);
b = to_x11_backend(base->compositor);
static const char name[] = "Weston Compositor";
static const char class[] = "weston-1\0Weston Compositor";
@@ -954,8 +990,7 @@ x11_output_enable(struct weston_output *base)
output->window,
screen->root,
0, 0,
output->base.current_mode->width,
output->base.current_mode->height,
mode->width, mode->height,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
@@ -1020,8 +1055,7 @@ x11_output_enable(struct weston_output *base)
.use_shadow = true,
};
if (x11_output_init_shm(b, output,
output->base.current_mode->width,
output->base.current_mode->height) < 0) {
mode->width, mode->height) < 0) {
weston_log("Failed to initialize SHM for the X11 output\n");
goto err;
}
@@ -1062,9 +1096,7 @@ x11_output_enable(struct weston_output *base)
wl_event_loop_add_timer(loop, finish_frame_handler, output);
weston_log("x11 output %dx%d, window id %d\n",
output->base.current_mode->width,
output->base.current_mode->height,
output->window);
mode->width, mode->height, output->window);
return 0;
@@ -1079,11 +1111,17 @@ static int
x11_output_set_size(struct weston_output *base, int width, int height)
{
struct x11_output *output = to_x11_output(base);
struct x11_backend *b = to_x11_backend(base->compositor);
struct x11_backend *b;
struct weston_head *head;
xcb_screen_t *scrn = b->screen;
xcb_screen_t *scrn;
int output_width, output_height;
if (!output)
return -1;
b = to_x11_backend(base->compositor);
scrn = b->screen;
/* We can only be called once. */
assert(!output->base.current_mode);
@@ -1165,6 +1203,9 @@ x11_head_create(struct weston_compositor *compositor, const char *name)
return -1;
weston_head_init(&head->base, name);
head->base.backend_id = x11_head_destroy;
weston_head_set_connection_status(&head->base, true);
weston_compositor_add_head(compositor, &head->base);
@@ -1172,8 +1213,12 @@ x11_head_create(struct weston_compositor *compositor, const char *name)
}
static void
x11_head_destroy(struct x11_head *head)
x11_head_destroy(struct weston_head *base)
{
struct x11_head *head = to_x11_head(base);
assert(head);
weston_head_release(&head->base);
free(head);
}
@@ -1450,7 +1495,7 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
{
struct x11_backend *b = data;
struct x11_output *output;
xcb_generic_event_t *event, *prev;
xcb_generic_event_t *event;
xcb_client_message_event_t *client_message;
xcb_enter_notify_event_t *enter_notify;
xcb_key_press_event_t *key_press, *key_release;
@@ -1466,16 +1511,15 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
int count;
struct timespec time;
prev = NULL;
count = 0;
while (x11_backend_next_event(b, &event, mask)) {
response_type = event->response_type & ~0x80;
switch (prev ? prev->response_type & ~0x80 : 0x80) {
switch (b->prev_event ? b->prev_event->response_type & ~0x80 : 0x80) {
case XCB_KEY_RELEASE:
/* Suppress key repeat events; this is only used if we
* don't have XCB XKB support. */
key_release = (xcb_key_press_event_t *) prev;
key_release = (xcb_key_press_event_t *) b->prev_event;
key_press = (xcb_key_press_event_t *) event;
if (response_type == XCB_KEY_PRESS &&
key_release->time == key_press->time &&
@@ -1483,8 +1527,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
/* Don't deliver the held key release
* event or the new key press event. */
free(event);
free(prev);
prev = NULL;
free(b->prev_event);
b->prev_event = NULL;
continue;
} else {
/* Deliver the held key release now
@@ -1497,8 +1541,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
key_release->detail - 8,
WL_KEYBOARD_KEY_STATE_RELEASED,
STATE_UPDATE_AUTOMATIC);
free(prev);
prev = NULL;
free(b->prev_event);
b->prev_event = NULL;
break;
}
@@ -1522,8 +1566,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
notify_keyboard_focus_in(&b->core_seat, &b->keys,
STATE_UPDATE_AUTOMATIC);
free(prev);
prev = NULL;
free(b->prev_event);
b->prev_event = NULL;
break;
default:
@@ -1548,7 +1592,7 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
/* If we don't have XKB, we need to use the lame
* autorepeat detection above. */
if (!b->has_xkb) {
prev = event;
b->prev_event = event;
break;
}
key_release = (xcb_key_press_event_t *) event;
@@ -1643,7 +1687,7 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED)
break;
prev = event;
b->prev_event = event;
break;
case XCB_FOCUS_OUT:
@@ -1677,13 +1721,13 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
#endif
count++;
if (prev != event)
free (event);
if (b->prev_event != event)
free(event);
}
switch (prev ? prev->response_type & ~0x80 : 0x80) {
switch (b->prev_event ? b->prev_event->response_type & ~0x80 : 0x80) {
case XCB_KEY_RELEASE:
key_release = (xcb_key_press_event_t *) prev;
key_release = (xcb_key_press_event_t *) b->prev_event;
update_xkb_state_from_core(b, key_release->state);
weston_compositor_get_time(&time);
notify_key(&b->core_seat,
@@ -1691,8 +1735,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
key_release->detail - 8,
WL_KEYBOARD_KEY_STATE_RELEASED,
STATE_UPDATE_AUTOMATIC);
free(prev);
prev = NULL;
free(b->prev_event);
b->prev_event = NULL;
break;
default:
break;
@@ -1792,8 +1836,10 @@ x11_destroy(struct weston_compositor *ec)
weston_compositor_shutdown(ec); /* destroys outputs, too */
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
x11_head_destroy(to_x11_head(base));
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
if (to_x11_head(base))
x11_head_destroy(base);
}
XCloseDisplay(backend->dpy);
free(backend);
+12 -12
View File
@@ -32,6 +32,8 @@
#ifndef LIBWESTON_BACKEND_INTERNAL_H
#define LIBWESTON_BACKEND_INTERNAL_H
struct weston_hdr_metadata_type1;
struct weston_backend {
void (*destroy)(struct weston_compositor *compositor);
@@ -46,27 +48,21 @@ struct weston_backend {
* Returns an opaque pointer, which the backend may use as private
* data referring to the repaint cycle.
*/
void * (*repaint_begin)(struct weston_compositor *compositor);
void (*repaint_begin)(struct weston_compositor *compositor);
/** Cancel a repaint sequence
*
* Cancels a repaint sequence, when an error has occurred during
* one output's repaint; see repaint_begin.
*
* @param repaint_data Data returned by repaint_begin
*/
void (*repaint_cancel)(struct weston_compositor *compositor,
void *repaint_data);
void (*repaint_cancel)(struct weston_compositor *compositor);
/** Conclude a repaint sequence
*
* Called on successful completion of a repaint sequence; see
* repaint_begin.
*
* @param repaint_data Data returned by repaint_begin
*/
int (*repaint_flush)(struct weston_compositor *compositor,
void *repaint_data);
int (*repaint_flush)(struct weston_compositor *compositor);
/** Allocate a new output
*
@@ -142,6 +138,10 @@ weston_head_set_subpixel(struct weston_head *head,
void
weston_head_set_transform(struct weston_head *head, uint32_t transform);
void
weston_head_set_supported_eotf_mask(struct weston_head *head,
uint32_t eotf_mask);
/* weston_output */
void
@@ -154,9 +154,6 @@ weston_output_damage(struct weston_output *output);
void
weston_output_release(struct weston_output *output);
void
weston_output_init_zoom(struct weston_output *output);
void
weston_output_finish_frame(struct weston_output *output,
const struct timespec *stamp,
@@ -178,6 +175,9 @@ void
weston_output_region_from_global(struct weston_output *output,
pixman_region32_t *region);
const struct weston_hdr_metadata_type1 *
weston_output_get_hdr_metadata_type1(const struct weston_output *output);
/* weston_seat */
void
+2 -2
View File
@@ -310,8 +310,8 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor,
/* If this was a key binding and it didn't
* install a keyboard grab, install one now to
* swallow the key press. */
if (keyboard->grab ==
&keyboard->default_grab)
if (keyboard->grab == &keyboard->default_grab ||
keyboard->grab == &keyboard->input_method_grab)
install_binding_grab(keyboard,
time,
key,
+1 -1
View File
@@ -110,7 +110,7 @@ clipboard_source_data(int fd, uint32_t mask, void *data)
static void
clipboard_source_accept(struct weston_data_source *source,
uint32_t time, const char *mime_type)
uint32_t serial, const char *mime_type)
{
}
+235 -48
View File
@@ -27,12 +27,37 @@
#include "config.h"
#include <assert.h>
#include <string.h>
#include <libweston/libweston.h>
#include "color.h"
#include "color-lcms.h"
#include "shared/helpers.h"
static cmsUInt32Number
cmlcms_get_render_intent(enum cmlcms_category cat,
struct weston_surface *surface,
struct weston_output *output)
{
/*
* TODO: Take into account client provided content profile,
* output profile, and the category of the wanted color
* transformation.
*/
cmsUInt32Number intent = INTENT_RELATIVE_COLORIMETRIC;
return intent;
}
static struct cmlcms_color_profile *
get_cprof_or_stock_sRGB(struct weston_color_manager_lcms *cm,
struct weston_color_profile *cprof_base)
{
if (cprof_base)
return get_cprof(cprof_base);
else
return cm->sRGB_profile;
}
static void
cmlcms_destroy_color_transform(struct weston_color_transform *xform_base)
{
@@ -48,47 +73,52 @@ cmlcms_get_surface_color_transform(struct weston_color_manager *cm_base,
struct weston_surface_color_transform *surf_xform)
{
struct weston_color_manager_lcms *cm = get_cmlcms(cm_base);
struct cmlcms_color_transform_search_param param = {
/*
* Assumes both content and output color spaces are sRGB SDR.
* This defines the blending space as optical sRGB SDR.
*/
.type = CMLCMS_TYPE_EOTF_sRGB,
};
struct cmlcms_color_transform *xform;
/* TODO: use output color profile */
if (output->color_profile)
return false;
/* TODO: take weston_output::eotf_mode into account */
struct cmlcms_color_transform_search_param param = {
.category = CMLCMS_CATEGORY_INPUT_TO_BLEND,
.input_profile = get_cprof_or_stock_sRGB(cm, NULL /* TODO: surface->color_profile */),
.output_profile = get_cprof_or_stock_sRGB(cm, output->color_profile),
};
param.intent_output = cmlcms_get_render_intent(param.category,
surface, output);
xform = cmlcms_color_transform_get(cm, &param);
if (!xform)
return false;
surf_xform->transform = &xform->base;
surf_xform->identity_pipeline = true;
/*
* When we introduce LCMS plug-in we can precisely answer this question
* by examining the color pipeline using precision parameters. For now
* we just compare if it is same pointer or not.
*/
if (xform->search_key.input_profile == xform->search_key.output_profile)
surf_xform->identity_pipeline = true;
else
surf_xform->identity_pipeline = false;
return true;
}
static bool
cmlcms_get_output_color_transform(struct weston_color_manager *cm_base,
struct weston_output *output,
struct weston_color_transform **xform_out)
cmlcms_get_blend_to_output_color_transform(struct weston_color_manager_lcms *cm,
struct weston_output *output,
struct weston_color_transform **xform_out)
{
struct weston_color_manager_lcms *cm = get_cmlcms(cm_base);
struct cmlcms_color_transform_search_param param = {
/*
* Assumes blending space is optical sRGB SDR and
* output color space is sRGB SDR.
*/
.type = CMLCMS_TYPE_EOTF_sRGB_INV,
};
struct cmlcms_color_transform *xform;
/* TODO: use output color profile */
if (output->color_profile)
return false;
/* TODO: take weston_output::eotf_mode into account */
struct cmlcms_color_transform_search_param param = {
.category = CMLCMS_CATEGORY_BLEND_TO_OUTPUT,
.input_profile = NULL,
.output_profile = get_cprof_or_stock_sRGB(cm, output->color_profile),
};
param.intent_output = cmlcms_get_render_intent(param.category,
NULL, output);
xform = cmlcms_color_transform_get(cm, &param);
if (!xform)
@@ -99,37 +129,54 @@ cmlcms_get_output_color_transform(struct weston_color_manager *cm_base,
}
static bool
cmlcms_get_sRGB_to_output_color_transform(struct weston_color_manager *cm_base,
cmlcms_get_sRGB_to_output_color_transform(struct weston_color_manager_lcms *cm,
struct weston_output *output,
struct weston_color_transform **xform_out)
{
/* Assumes output color space is sRGB SDR */
struct cmlcms_color_transform *xform;
/* TODO: use output color profile */
if (output->color_profile)
return false;
/* TODO: take weston_output::eotf_mode into account */
/* Identity transform */
*xform_out = NULL;
struct cmlcms_color_transform_search_param param = {
.category = CMLCMS_CATEGORY_INPUT_TO_OUTPUT,
.input_profile = cm->sRGB_profile,
.output_profile = get_cprof_or_stock_sRGB(cm, output->color_profile),
};
param.intent_output = cmlcms_get_render_intent(param.category,
NULL, output);
/*
* Create a color transformation when output profile is not stock
* sRGB profile.
*/
if (param.output_profile != cm->sRGB_profile) {
xform = cmlcms_color_transform_get(cm, &param);
if (!xform)
return false;
*xform_out = &xform->base;
} else {
*xform_out = NULL; /* Identity transform */
}
return true;
}
static bool
cmlcms_get_sRGB_to_blend_color_transform(struct weston_color_manager *cm_base,
cmlcms_get_sRGB_to_blend_color_transform(struct weston_color_manager_lcms *cm,
struct weston_output *output,
struct weston_color_transform **xform_out)
{
struct weston_color_manager_lcms *cm = get_cmlcms(cm_base);
struct cmlcms_color_transform_search_param param = {
/* Assumes blending space is optical sRGB SDR */
.type = CMLCMS_TYPE_EOTF_sRGB,
};
struct cmlcms_color_transform *xform;
/* TODO: use output color profile */
if (output->color_profile)
return false;
/* TODO: take weston_output::eotf_mode into account */
struct cmlcms_color_transform_search_param param = {
.category = CMLCMS_CATEGORY_INPUT_TO_BLEND,
.input_profile = cm->sRGB_profile,
.output_profile = get_cprof_or_stock_sRGB(cm, output->color_profile),
};
param.intent_output = cmlcms_get_render_intent(param.category,
NULL, output);
xform = cmlcms_color_transform_get(cm, &param);
if (!xform)
@@ -139,6 +186,145 @@ cmlcms_get_sRGB_to_blend_color_transform(struct weston_color_manager *cm_base,
return true;
}
static float
meta_clamp(float value, const char *valname, float min, float max,
struct weston_output *output)
{
float ret = value;
/* Paranoia against NaN */
if (!(ret >= min))
ret = min;
if (!(ret <= max))
ret = max;
if (ret != value) {
weston_log("output '%s' clamping %s value from %f to %f.\n",
output->name, valname, value, ret);
}
return ret;
}
static bool
cmlcms_get_hdr_meta(struct weston_output *output,
struct weston_hdr_metadata_type1 *hdr_meta)
{
const struct weston_color_characteristics *cc;
hdr_meta->group_mask = 0;
/* Only SMPTE ST 2084 mode uses HDR Static Metadata Type 1 */
if (weston_output_get_eotf_mode(output) != WESTON_EOTF_MODE_ST2084)
return true;
/* ICC profile overrides color characteristics */
if (output->color_profile) {
/*
* TODO: extract characteristics from profile?
* Get dynamic range from weston_color_characteristics?
*/
return true;
}
cc = weston_output_get_color_characteristics(output);
/* Target content chromaticity */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES) {
unsigned i;
for (i = 0; i < 3; i++) {
hdr_meta->primary[i].x = meta_clamp(cc->primary[i].x,
"primary", 0.0, 1.0,
output);
hdr_meta->primary[i].y = meta_clamp(cc->primary[i].y,
"primary", 0.0, 1.0,
output);
}
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES;
}
/* Target content white point */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_WHITE) {
hdr_meta->white.x = meta_clamp(cc->white.x, "white",
0.0, 1.0, output);
hdr_meta->white.y = meta_clamp(cc->white.y, "white",
0.0, 1.0, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_WHITE;
}
/* Target content peak and max mastering luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MAXL) {
hdr_meta->maxDML = meta_clamp(cc->max_luminance, "maxDML",
1.0, 65535.0, output);
hdr_meta->maxCLL = meta_clamp(cc->max_luminance, "maxCLL",
1.0, 65535.0, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML;
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL;
}
/* Target content min mastering luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MINL) {
hdr_meta->minDML = meta_clamp(cc->min_luminance, "minDML",
0.0001, 6.5535, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MINDML;
}
/* Target content max frame-average luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MAXFALL) {
hdr_meta->maxFALL = meta_clamp(cc->maxFALL, "maxFALL",
1.0, 65535.0, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL;
}
return true;
}
static struct weston_output_color_outcome *
cmlcms_create_output_color_outcome(struct weston_color_manager *cm_base,
struct weston_output *output)
{
struct weston_color_manager_lcms *cm = get_cmlcms(cm_base);
struct weston_output_color_outcome *co;
co = zalloc(sizeof *co);
if (!co)
return NULL;
if (!cmlcms_get_hdr_meta(output, &co->hdr_meta))
goto out_fail;
/*
* TODO: if output->color_profile is NULL, maybe manufacture a
* profile from weston_color_characteristics if it has enough
* information?
* Or let the frontend decide to call a "create a profile from
* characteristics" API?
*/
/* TODO: take container color space into account */
if (!cmlcms_get_blend_to_output_color_transform(cm, output,
&co->from_blend_to_output))
goto out_fail;
if (!cmlcms_get_sRGB_to_blend_color_transform(cm, output,
&co->from_sRGB_to_blend))
goto out_fail;
if (!cmlcms_get_sRGB_to_output_color_transform(cm, output,
&co->from_sRGB_to_output))
goto out_fail;
return co;
out_fail:
weston_output_color_outcome_destroy(&co);
return NULL;
}
static void
lcms_error_logger(cmsContext context_id,
cmsUInt32Number error_code,
@@ -165,6 +351,10 @@ cmlcms_init(struct weston_color_manager *cm_base)
cmsSetLogErrorHandlerTHR(cm->lcms_ctx, lcms_error_logger);
if (!cmlcms_create_stock_profile(cm)) {
weston_log("color-lcms: error: cmlcms_create_stock_profile failed\n");
return false;
}
weston_log("LittleCMS %d initialized.\n", cmsGetEncodedCMMversion());
return true;
@@ -175,6 +365,8 @@ cmlcms_destroy(struct weston_color_manager *cm_base)
{
struct weston_color_manager_lcms *cm = get_cmlcms(cm_base);
if (cm->sRGB_profile)
cmlcms_color_profile_destroy(cm->sRGB_profile);
assert(wl_list_empty(&cm->color_transform_list));
assert(wl_list_empty(&cm->color_profile_list));
@@ -199,13 +391,8 @@ weston_color_manager_create(struct weston_compositor *compositor)
cm->base.destroy_color_profile = cmlcms_destroy_color_profile;
cm->base.get_color_profile_from_icc = cmlcms_get_color_profile_from_icc;
cm->base.destroy_color_transform = cmlcms_destroy_color_transform;
cm->base.get_surface_color_transform =
cmlcms_get_surface_color_transform;
cm->base.get_output_color_transform = cmlcms_get_output_color_transform;
cm->base.get_sRGB_to_output_color_transform =
cmlcms_get_sRGB_to_output_color_transform;
cm->base.get_sRGB_to_blend_color_transform =
cmlcms_get_sRGB_to_blend_color_transform;
cm->base.get_surface_color_transform = cmlcms_get_surface_color_transform;
cm->base.create_output_color_outcome = cmlcms_create_output_color_outcome;
wl_list_init(&cm->color_transform_list);
wl_list_init(&cm->color_profile_list);
+89 -12
View File
@@ -39,6 +39,7 @@ struct weston_color_manager_lcms {
struct wl_list color_transform_list; /* cmlcms_color_transform::link */
struct wl_list color_profile_list; /* cmlcms_color_profile::link */
struct cmlcms_color_profile *sRGB_profile; /* stock profile */
};
static inline struct weston_color_manager_lcms *
@@ -59,6 +60,58 @@ struct cmlcms_color_profile {
cmsHPROFILE profile;
struct cmlcms_md5_sum md5sum;
/**
* If the profile does support being an output profile and it is used as an
* output then this field represents a light linearizing transfer function
* and it can not be null. The field is null only if the profile is not
* usable as an output profile. The field is set when cmlcms_color_profile
* is created.
*/
cmsToneCurve *output_eotf[3];
/**
* If the profile does support being an output profile and it is used as an
* output then this field represents a concatenation of inverse EOTF + VCGT,
* if the tag exists and it can not be null.
* VCGT is part of monitor calibration which means: even though we must
* apply VCGT in the compositor, we pretend that it happens inside the
* monitor. This is how the classic color management and ICC profiles work.
* The ICC profile (ignoring the VCGT tag) characterizes the output which
* is VCGT + monitor behavior. The field is null only if the profile is not
* usable as an output profile. The field is set when cmlcms_color_profile
* is created.
*/
cmsToneCurve *output_inv_eotf_vcgt[3];
/**
* VCGT tag cached from output profile, it could be null if not exist
*/
cmsToneCurve *vcgt[3];
};
/**
* Type of LCMS transforms
*/
enum cmlcms_category {
/**
* Uses combination of input profile with output profile, but
* without INV EOTF or with additional EOTF in the transform pipeline
* inputblend = input profile + output profile + output EOTF
*/
CMLCMS_CATEGORY_INPUT_TO_BLEND = 0,
/**
* Uses INV EOTF only concatenated with VCGT tag if present
* blendoutput = output inverse EOTF + VCGT
*/
CMLCMS_CATEGORY_BLEND_TO_OUTPUT,
/**
* Transform uses input profile and output profile as is
* inputoutput = input profile + output profile + VCGT
*/
CMLCMS_CATEGORY_INPUT_TO_OUTPUT,
};
static inline struct cmlcms_color_profile *
@@ -78,18 +131,12 @@ cmlcms_get_color_profile_from_icc(struct weston_color_manager *cm,
void
cmlcms_destroy_color_profile(struct weston_color_profile *cprof_base);
/*
* Perhaps a placeholder, until we get actual color spaces involved and
* see how this would work better.
*/
enum cmlcms_color_transform_type {
CMLCMS_TYPE_EOTF_sRGB = 0,
CMLCMS_TYPE_EOTF_sRGB_INV,
CMLCMS_TYPE__END,
};
struct cmlcms_color_transform_search_param {
enum cmlcms_color_transform_type type;
enum cmlcms_category category;
struct cmlcms_color_profile *input_profile;
struct cmlcms_color_profile *output_profile;
cmsUInt32Number intent_output; /* selected intent from output profile */
};
struct cmlcms_color_transform {
@@ -100,8 +147,15 @@ struct cmlcms_color_transform {
struct cmlcms_color_transform_search_param search_key;
/* for EOTF types */
cmsToneCurve *curve;
/**
* 3D LUT color mapping part of the transformation, if needed.
* For category CMLCMS_CATEGORY_INPUT_TO_OUTPUT it includes pre-curve and
* post-curve.
* For category CMLCMS_CATEGORY_INPUT_TO_BLEND it includes pre-curve.
* For category CMLCMS_CATEGORY_BLEND_TO_OUTPUT and when identity it is
* not used
*/
cmsHTRANSFORM cmap_3dlut;
};
static inline struct cmlcms_color_transform *
@@ -117,4 +171,27 @@ cmlcms_color_transform_get(struct weston_color_manager_lcms *cm,
void
cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform);
struct cmlcms_color_profile *
ref_cprof(struct cmlcms_color_profile *cprof);
void
unref_cprof(struct cmlcms_color_profile *cprof);
bool
cmlcms_create_stock_profile(struct weston_color_manager_lcms *cm);
void
cmlcms_color_profile_destroy(struct cmlcms_color_profile *cprof);
bool
retrieve_eotf_and_output_inv_eotf(cmsContext lcms_ctx,
cmsHPROFILE hProfile,
cmsToneCurve *output_eotf[3],
cmsToneCurve *output_inv_eotf_vcgt[3],
cmsToneCurve *vcgt[3],
unsigned int num_points);
unsigned int
cmlcms_reasonable_1D_points(void);
#endif /* WESTON_COLOR_LCMS_H */
+286 -1
View File
@@ -36,6 +36,223 @@
#include "shared/helpers.h"
#include "shared/string-helpers.h"
struct xyz_arr_flt {
float v[3];
};
static double
xyz_dot_prod(const struct xyz_arr_flt a, const struct xyz_arr_flt b)
{
return (double)a.v[0] * b.v[0] +
(double)a.v[1] * b.v[1] +
(double)a.v[2] * b.v[2];
}
/**
* Graeme sketched a linearization method there:
* https://lists.freedesktop.org/archives/wayland-devel/2019-March/040171.html
*/
static bool
build_eotf_from_clut_profile(cmsContext lcms_ctx,
cmsHPROFILE profile,
cmsToneCurve *output_eotf[3],
int num_points)
{
int ch, point;
float *curve_array[3];
float *red = NULL;
cmsHPROFILE xyz_profile = NULL;
cmsHTRANSFORM transform_rgb_to_xyz = NULL;
bool ret = false;
const float div = num_points - 1;
red = malloc(sizeof(float) * num_points * 3);
if (!red)
goto release;
curve_array[0] = red;
curve_array[1] = red + num_points;
curve_array[2] = red + 2 * num_points;
xyz_profile = cmsCreateXYZProfileTHR(lcms_ctx);
if (!xyz_profile)
goto release;
transform_rgb_to_xyz = cmsCreateTransformTHR(lcms_ctx, profile,
TYPE_RGB_FLT, xyz_profile,
TYPE_XYZ_FLT,
INTENT_ABSOLUTE_COLORIMETRIC,
0);
if (!transform_rgb_to_xyz)
goto release;
for (ch = 0; ch < 3; ch++) {
struct xyz_arr_flt prim_xyz_max;
struct xyz_arr_flt prim_xyz;
double xyz_square_magnitude;
float rgb[3] = { 0.0f, 0.0f, 0.0f };
rgb[ch] = 1.0f;
cmsDoTransform(transform_rgb_to_xyz, rgb, prim_xyz_max.v, 1);
/**
* Calculate xyz square of magnitude uses single channel 100% and
* others are zero.
*/
xyz_square_magnitude = xyz_dot_prod(prim_xyz_max, prim_xyz_max);
/**
* Build rgb tone curves
*/
for (point = 0; point < num_points; point++) {
rgb[ch] = (float)point / div;
cmsDoTransform(transform_rgb_to_xyz, rgb, prim_xyz.v, 1);
curve_array[ch][point] = xyz_dot_prod(prim_xyz,
prim_xyz_max) /
xyz_square_magnitude;
}
/**
* Create LCMS object of rgb tone curves and validate whether
* monotonic
*/
output_eotf[ch] = cmsBuildTabulatedToneCurveFloat(lcms_ctx,
num_points,
curve_array[ch]);
if (!output_eotf[ch])
goto release;
if (!cmsIsToneCurveMonotonic(output_eotf[ch])) {
/**
* It is interesting to see how this profile was created.
* We assume that such a curve could not be used for linearization
* of arbitrary profile.
*/
goto release;
}
}
ret = true;
release:
if (transform_rgb_to_xyz)
cmsDeleteTransform(transform_rgb_to_xyz);
if (xyz_profile)
cmsCloseProfile(xyz_profile);
free(red);
if (ret == false)
cmsFreeToneCurveTriple(output_eotf);
return ret;
}
/**
* Concatenation of two monotonic tone curves.
* LCMS API cmsJoinToneCurve does y = Y^-1(X(t)),
* but want to have y = Y^(X(t))
*/
static cmsToneCurve *
lcmsJoinToneCurve(cmsContext context_id, const cmsToneCurve *X,
const cmsToneCurve *Y, unsigned int resulting_points)
{
cmsToneCurve *out = NULL;
float t, x;
float *res = NULL;
unsigned int i;
res = zalloc(resulting_points * sizeof(float));
if (res == NULL)
goto error;
for (i = 0; i < resulting_points; i++) {
t = (float)i / (resulting_points - 1);
x = cmsEvalToneCurveFloat(X, t);
res[i] = cmsEvalToneCurveFloat(Y, x);
}
out = cmsBuildTabulatedToneCurveFloat(context_id, resulting_points, res);
error:
if (res != NULL)
free(res);
return out;
}
/**
* Extract EOTF from matrix-shaper and cLUT profiles,
* then invert and concatenate with 'vcgt' curve if it
* is available.
*/
bool
retrieve_eotf_and_output_inv_eotf(cmsContext lcms_ctx,
cmsHPROFILE hProfile,
cmsToneCurve *output_eotf[3],
cmsToneCurve *output_inv_eotf_vcgt[3],
cmsToneCurve *vcgt[3],
unsigned int num_points)
{
cmsToneCurve *curve = NULL;
const cmsToneCurve * const *vcgt_curves;
unsigned i;
cmsTagSignature tags[] = {
cmsSigRedTRCTag, cmsSigGreenTRCTag, cmsSigBlueTRCTag
};
if (cmsIsMatrixShaper(hProfile)) {
/**
* Optimization for matrix-shaper profile
* May have 1DLUT->3x3->3x3->1DLUT, 1DLUT->3x3->1DLUT
*/
for (i = 0 ; i < 3; i++) {
curve = cmsReadTag(hProfile, tags[i]);
if (!curve)
goto fail;
output_eotf[i] = cmsDupToneCurve(curve);
if (!output_eotf[i])
goto fail;
}
} else {
/**
* Linearization of cLUT profile may have 1DLUT->3DLUT->1DLUT,
* 1DLUT->3DLUT, 3DLUT
*/
if (!build_eotf_from_clut_profile(lcms_ctx, hProfile,
output_eotf, num_points))
goto fail;
}
/**
* If the caller looking for eotf only then return early.
* It could be used for input profile when identity case: EOTF + INV_EOTF
* in pipeline only.
*/
if (output_inv_eotf_vcgt == NULL)
return true;
for (i = 0; i < 3; i++) {
curve = cmsReverseToneCurve(output_eotf[i]);
if (!curve)
goto fail;
output_inv_eotf_vcgt[i] = curve;
}
vcgt_curves = cmsReadTag(hProfile, cmsSigVcgtTag);
if (vcgt_curves && vcgt_curves[0] && vcgt_curves[1] && vcgt_curves[2]) {
for (i = 0; i < 3; i++) {
curve = lcmsJoinToneCurve(lcms_ctx,
output_inv_eotf_vcgt[i],
vcgt_curves[i], num_points);
if (!curve)
goto fail;
cmsFreeToneCurve(output_inv_eotf_vcgt[i]);
output_inv_eotf_vcgt[i] = curve;
if (vcgt)
vcgt[i] = cmsDupToneCurve(vcgt_curves[i]);
}
}
return true;
fail:
cmsFreeToneCurveTriple(output_eotf);
cmsFreeToneCurveTriple(output_inv_eotf_vcgt);
return false;
}
/* FIXME: sync with spec! */
static bool
validate_icc_profile(cmsHPROFILE profile, char **errmsg)
@@ -102,15 +319,37 @@ cmlcms_color_profile_create(struct weston_color_manager_lcms *cm,
return cprof;
}
static void
void
cmlcms_color_profile_destroy(struct cmlcms_color_profile *cprof)
{
wl_list_remove(&cprof->link);
cmsFreeToneCurveTriple(cprof->vcgt);
cmsFreeToneCurveTriple(cprof->output_eotf);
cmsFreeToneCurveTriple(cprof->output_inv_eotf_vcgt);
cmsCloseProfile(cprof->profile);
free(cprof->base.description);
free(cprof);
}
struct cmlcms_color_profile *
ref_cprof(struct cmlcms_color_profile *cprof)
{
if (!cprof)
return NULL;
weston_color_profile_ref(&cprof->base);
return cprof;
}
void
unref_cprof(struct cmlcms_color_profile *cprof)
{
if (!cprof)
return;
weston_color_profile_unref(&cprof->base);
}
static char *
make_icc_file_description(cmsHPROFILE profile,
const struct cmlcms_md5_sum *md5sum,
@@ -131,6 +370,52 @@ make_icc_file_description(cmsHPROFILE profile,
return desc;
}
/**
*
* Build stock profile which available for clients unaware of color management
*/
bool
cmlcms_create_stock_profile(struct weston_color_manager_lcms *cm)
{
cmsHPROFILE profile;
struct cmlcms_md5_sum md5sum;
char *desc = NULL;
profile = cmsCreate_sRGBProfileTHR(cm->lcms_ctx);
if (!profile) {
weston_log("color-lcms: error: cmsCreate_sRGBProfileTHR failed\n");
return false;
}
if (!cmsMD5computeID(profile)) {
weston_log("Failed to compute MD5 for ICC profile\n");
goto err_close;
}
cmsGetHeaderProfileID(profile, md5sum.bytes);
desc = make_icc_file_description(profile, &md5sum, "sRGB stock");
if (!desc)
goto err_close;
cm->sRGB_profile = cmlcms_color_profile_create(cm, profile, desc, NULL);
if (!cm->sRGB_profile)
goto err_close;
if (!retrieve_eotf_and_output_inv_eotf(cm->lcms_ctx,
cm->sRGB_profile->profile,
cm->sRGB_profile->output_eotf,
cm->sRGB_profile->output_inv_eotf_vcgt,
cm->sRGB_profile->vcgt,
cmlcms_reasonable_1D_points()))
goto err_close;
return true;
err_close:
free(desc);
cmsCloseProfile(profile);
return false;
}
bool
cmlcms_get_color_profile_from_icc(struct weston_color_manager *cm_base,
const void *icc_data,
+186 -56
View File
@@ -33,48 +33,98 @@
#include "color-lcms.h"
#include "shared/helpers.h"
/* Arguments to cmsBuildParametricToneCurve() */
struct tone_curve_def {
cmsInt32Number cmstype;
cmsFloat64Number params[5];
};
/*
* LCMS uses the required number of 'params' based on 'cmstype', the parametric
* tone curve number. LCMS honors negative 'cmstype' as inverse function.
* These are LCMS built-in parametric tone curves.
/**
* The method is used in linearization of an arbitrary color profile
* when EOTF is retrieved we want to know a generic way to decide the number
* of points
*/
static const struct tone_curve_def predefined_eotf_curves[] = {
[CMLCMS_TYPE_EOTF_sRGB] = {
.cmstype = 4,
.params = { 2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045 },
},
[CMLCMS_TYPE_EOTF_sRGB_INV] = {
.cmstype = -4,
.params = { 2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045 },
},
};
unsigned int
cmlcms_reasonable_1D_points(void)
{
return 1024;
}
static unsigned int
cmlcms_reasonable_3D_points(void)
{
return 33;
}
static void
cmlcms_fill_in_tone_curve(struct weston_color_transform *xform_base,
float *values, unsigned len)
fill_in_curves(cmsToneCurve *curves[3], float *values, unsigned len)
{
struct cmlcms_color_transform *xform = get_xform(xform_base);
float *R_lut = values;
float *G_lut = R_lut + len;
float *B_lut = G_lut + len;
unsigned i;
cmsFloat32Number x, y;
assert(xform->curve != NULL);
assert(len > 1);
cmsFloat32Number x;
for (i = 0; i < len; i++) {
x = (double)i / (len - 1);
y = cmsEvalToneCurveFloat(xform->curve, x);
R_lut[i] = y;
G_lut[i] = y;
B_lut[i] = y;
R_lut[i] = cmsEvalToneCurveFloat(curves[0], x);
G_lut[i] = cmsEvalToneCurveFloat(curves[1], x);
B_lut[i] = cmsEvalToneCurveFloat(curves[2], x);
}
}
static void
cmlcms_fill_in_pre_curve(struct weston_color_transform *xform_base,
float *values, unsigned len)
{
struct cmlcms_color_transform *xform = get_xform(xform_base);
assert(xform->search_key.category == CMLCMS_CATEGORY_BLEND_TO_OUTPUT);
assert(len > 1);
fill_in_curves(xform->search_key.output_profile->output_inv_eotf_vcgt,
values, len);
}
/**
* Clamp value to [0.0, 1.0], except pass NaN through.
*
* This function is not intended for hiding NaN.
*/
static float
ensure_unorm(float v)
{
if (v <= 0.0f)
return 0.0f;
if (v > 1.0f)
return 1.0f;
return v;
}
static void
cmlcms_fill_in_3dlut(struct weston_color_transform *xform_base,
float *lut, unsigned int len)
{
struct cmlcms_color_transform *xform = get_xform(xform_base);
float rgb_in[3];
float rgb_out[3];
unsigned int index;
unsigned int value_b, value_r, value_g;
float divider = len - 1;
assert(xform->search_key.category == CMLCMS_CATEGORY_INPUT_TO_BLEND ||
xform->search_key.category == CMLCMS_CATEGORY_INPUT_TO_OUTPUT);
for (value_b = 0; value_b < len; value_b++) {
for (value_g = 0; value_g < len; value_g++) {
for (value_r = 0; value_r < len; value_r++) {
rgb_in[0] = (float)value_r / divider;
rgb_in[1] = (float)value_g / divider;
rgb_in[2] = (float)value_b / divider;
cmsDoTransform(xform->cmap_3dlut, rgb_in, rgb_out, 1);
index = 3 * (value_r + len * (value_g + len * value_b));
lut[index ] = ensure_unorm(rgb_out[0]);
lut[index + 1] = ensure_unorm(rgb_out[1]);
lut[index + 2] = ensure_unorm(rgb_out[2]);
}
}
}
}
@@ -82,55 +132,135 @@ void
cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform)
{
wl_list_remove(&xform->link);
if (xform->curve)
cmsFreeToneCurve(xform->curve);
if (xform->cmap_3dlut)
cmsDeleteTransform(xform->cmap_3dlut);
unref_cprof(xform->search_key.input_profile);
unref_cprof(xform->search_key.output_profile);
free(xform);
}
static bool
xform_set_cmap_3dlut(struct cmlcms_color_transform *xform,
cmsHPROFILE input_profile,
cmsHPROFILE output_profile,
cmsToneCurve *curves[3],
cmsUInt32Number intent)
{
struct weston_color_manager_lcms *cm = get_cmlcms(xform->base.cm);
cmsHPROFILE arr_prof[3] = { input_profile, output_profile, NULL };
int num_profiles = 2;
if (curves[0]) {
arr_prof[2] = cmsCreateLinearizationDeviceLinkTHR(cm->lcms_ctx,
cmsSigRgbData,
curves);
if (!arr_prof[2])
return false;
num_profiles = 3;
}
xform->cmap_3dlut = cmsCreateMultiprofileTransformTHR(cm->lcms_ctx,
arr_prof,
num_profiles,
TYPE_RGB_FLT,
TYPE_RGB_FLT,
intent,
0);
if (!xform->cmap_3dlut) {
cmsCloseProfile(arr_prof[2]);
weston_log("color-lcms error: fail cmsCreateMultiprofileTransformTHR.\n");
return false;
}
xform->base.mapping.type = WESTON_COLOR_MAPPING_TYPE_3D_LUT;
xform->base.mapping.u.lut3d.fill_in = cmlcms_fill_in_3dlut;
xform->base.mapping.u.lut3d.optimal_len =
cmlcms_reasonable_3D_points();
cmsCloseProfile(arr_prof[2]);
return true;
}
static struct cmlcms_color_transform *
cmlcms_color_transform_create(struct weston_color_manager_lcms *cm,
const struct cmlcms_color_transform_search_param *param)
const struct cmlcms_color_transform_search_param *search_param)
{
struct cmlcms_color_profile *input_profile = search_param->input_profile;
struct cmlcms_color_profile *output_profile = search_param->output_profile;
struct cmlcms_color_transform *xform;
const struct tone_curve_def *tonedef;
if (param->type < 0 || param->type >= CMLCMS_TYPE__END) {
weston_log("color-lcms error: bad color transform type in %s.\n",
__func__);
return NULL;
}
tonedef = &predefined_eotf_curves[param->type];
bool ok = false;
xform = zalloc(sizeof *xform);
if (!xform)
return NULL;
xform->curve = cmsBuildParametricToneCurve(cm->lcms_ctx,
tonedef->cmstype,
tonedef->params);
if (xform->curve == NULL) {
weston_log("color-lcms error: failed to build parametric tone curve.\n");
free(xform);
return NULL;
weston_color_transform_init(&xform->base, &cm->base);
wl_list_init(&xform->link);
xform->search_key = *search_param;
xform->search_key.input_profile = ref_cprof(input_profile);
xform->search_key.output_profile = ref_cprof(output_profile);
/* Ensure the linearization etc. have been extracted. */
if (!output_profile->output_eotf[0]) {
if (!retrieve_eotf_and_output_inv_eotf(cm->lcms_ctx,
output_profile->profile,
output_profile->output_eotf,
output_profile->output_inv_eotf_vcgt,
output_profile->vcgt,
cmlcms_reasonable_1D_points()))
goto error;
}
weston_color_transform_init(&xform->base, &cm->base);
xform->search_key = *param;
switch (search_param->category) {
case CMLCMS_CATEGORY_INPUT_TO_BLEND:
/* Use EOTF to linearize the result. */
ok = xform_set_cmap_3dlut(xform, input_profile->profile,
output_profile->profile,
output_profile->output_eotf,
search_param->intent_output);
break;
xform->base.pre_curve.type = WESTON_COLOR_CURVE_TYPE_LUT_3x1D;
xform->base.pre_curve.u.lut_3x1d.fill_in = cmlcms_fill_in_tone_curve;
xform->base.pre_curve.u.lut_3x1d.optimal_len = 256;
case CMLCMS_CATEGORY_INPUT_TO_OUTPUT:
/* Apply also VCGT if it exists. */
ok = xform_set_cmap_3dlut(xform, input_profile->profile,
output_profile->profile,
output_profile->vcgt,
search_param->intent_output);
break;
case CMLCMS_CATEGORY_BLEND_TO_OUTPUT:
xform->base.pre_curve.type = WESTON_COLOR_CURVE_TYPE_LUT_3x1D;
xform->base.pre_curve.u.lut_3x1d.fill_in = cmlcms_fill_in_pre_curve;
xform->base.pre_curve.u.lut_3x1d.optimal_len =
cmlcms_reasonable_1D_points();
ok = true;
break;
}
if (!ok)
goto error;
wl_list_insert(&cm->color_transform_list, &xform->link);
return xform;
error:
cmlcms_color_transform_destroy(xform);
weston_log("CM cmlcms_color_transform_create failed\n");
return NULL;
}
static bool
transform_matches_params(const struct cmlcms_color_transform *xform,
const struct cmlcms_color_transform_search_param *param)
{
if (xform->search_key.type != param->type)
if (xform->search_key.category != param->category)
return false;
if (xform->search_key.intent_output != param->intent_output ||
xform->search_key.output_profile != param->output_profile ||
xform->search_key.input_profile != param->input_profile)
return false;
return true;
-1
View File
@@ -2,7 +2,6 @@ if not get_option('color-management-lcms')
subdir_done()
endif
dep_lcms2 = dependency('lcms2', version: '>= 2.9', required: false)
if not dep_lcms2.found()
error('color-lcms plugin requires lcms2 which was not found. Or, you can use \'-Dcolor-management-lcms=false\'.')
endif
+33 -37
View File
@@ -35,6 +35,18 @@ struct weston_color_manager_noop {
struct weston_color_manager base;
};
static bool
check_output_eotf_mode(struct weston_output *output)
{
if (output->eotf_mode == WESTON_EOTF_MODE_SDR)
return true;
weston_log("Error: color manager no-op does not support EOTF mode %s of output %s.\n",
weston_eotf_mode_to_str(output->eotf_mode),
output->name);
return false;
}
static struct weston_color_manager_noop *
get_cmnoop(struct weston_color_manager *cm_base)
{
@@ -74,6 +86,9 @@ cmnoop_get_surface_color_transform(struct weston_color_manager *cm_base,
/* TODO: Assert surface has no colorspace set */
assert(output->color_profile == NULL);
if (!check_output_eotf_mode(output))
return false;
/* Identity transform */
surf_xform->transform = NULL;
surf_xform->identity_pipeline = true;
@@ -81,43 +96,29 @@ cmnoop_get_surface_color_transform(struct weston_color_manager *cm_base,
return true;
}
static bool
cmnoop_get_output_color_transform(struct weston_color_manager *cm_base,
struct weston_output *output,
struct weston_color_transform **xform_out)
static struct weston_output_color_outcome *
cmnoop_create_output_color_outcome(struct weston_color_manager *cm_base,
struct weston_output *output)
{
struct weston_output_color_outcome *co;
assert(output->color_profile == NULL);
/* Identity transform */
*xform_out = NULL;
if (!check_output_eotf_mode(output))
return NULL;
return true;
}
co = zalloc(sizeof *co);
if (!co)
return NULL;
static bool
cmnoop_get_sRGB_to_output_color_transform(struct weston_color_manager *cm_base,
struct weston_output *output,
struct weston_color_transform **xform_out)
{
assert(output->color_profile == NULL);
/* Identity transform on everything */
co->from_blend_to_output = NULL;
co->from_sRGB_to_blend = NULL;
co->from_sRGB_to_output = NULL;
/* Identity transform */
*xform_out = NULL;
co->hdr_meta.group_mask = 0;
return true;
}
static bool
cmnoop_get_sRGB_to_blend_color_transform(struct weston_color_manager *cm_base,
struct weston_output *output,
struct weston_color_transform **xform_out)
{
assert(output->color_profile == NULL);
/* Identity transform */
*xform_out = NULL;
return true;
return co;
}
static bool
@@ -153,13 +154,8 @@ weston_color_manager_noop_create(struct weston_compositor *compositor)
cm->base.destroy_color_profile = cmnoop_destroy_color_profile;
cm->base.get_color_profile_from_icc = cmnoop_get_color_profile_from_icc;
cm->base.destroy_color_transform = cmnoop_destroy_color_transform;
cm->base.get_surface_color_transform =
cmnoop_get_surface_color_transform;
cm->base.get_output_color_transform = cmnoop_get_output_color_transform;
cm->base.get_sRGB_to_output_color_transform =
cmnoop_get_sRGB_to_output_color_transform;
cm->base.get_sRGB_to_blend_color_transform =
cmnoop_get_sRGB_to_blend_color_transform;
cm->base.get_surface_color_transform = cmnoop_get_surface_color_transform;
cm->base.create_output_color_outcome = cmnoop_create_output_color_outcome;
return &cm->base;
}
+52
View File
@@ -297,3 +297,55 @@ out_close:
close(fd);
return cprof;
}
/** Get a string naming the EOTF mode
*
* \internal
*/
WL_EXPORT const char *
weston_eotf_mode_to_str(enum weston_eotf_mode e)
{
switch (e) {
case WESTON_EOTF_MODE_NONE: return "(none)";
case WESTON_EOTF_MODE_SDR: return "SDR";
case WESTON_EOTF_MODE_TRADITIONAL_HDR: return "traditional gamma HDR";
case WESTON_EOTF_MODE_ST2084: return "ST2084";
case WESTON_EOTF_MODE_HLG: return "HLG";
}
return "???";
}
/** A list of EOTF modes as a string
*
* \param eotf_mask Bitwise-or'd enum weston_eotf_mode values.
* \return Comma separated names of the listed EOTF modes. Must be free()'d by
* the caller.
*/
WL_EXPORT char *
weston_eotf_mask_to_str(uint32_t eotf_mask)
{
FILE *fp;
char *str = NULL;
size_t size = 0;
unsigned i;
const char *sep = "";
fp = open_memstream(&str, &size);
if (!fp)
return NULL;
for (i = 0; eotf_mask; i++) {
uint32_t bitmask = 1u << i;
if (eotf_mask & bitmask) {
fprintf(fp, "%s%s", sep,
weston_eotf_mode_to_str(bitmask));
sep = ", ";
}
eotf_mask &= ~bitmask;
}
fclose(fp);
return str;
}
+93 -44
View File
@@ -1,5 +1,6 @@
/*
* Copyright 2021 Collabora, Ltd.
* Copyright 2021 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -98,6 +99,79 @@ struct weston_color_curve {
} u;
};
/** Type or formula for a color mapping */
enum weston_color_mapping_type {
/** Identity function, no-op */
WESTON_COLOR_MAPPING_TYPE_IDENTITY = 0,
/** 3D-dimensional look-up table */
WESTON_COLOR_MAPPING_TYPE_3D_LUT,
};
/**
* A three-dimensional look-up table
*
* A 3D LUT is a three-dimensional array where each element is an RGB triplet.
* A 3D LUT is usually an approximation of some arbitrary color mapping
* function that cannot be represented in any simpler form. The array contains
* samples from the approximated function, and values between samples are
* estimated by interpolation. The array is accessed with three indices, one
* for each input dimension (color channel).
*
* Color channel values in the range [0.0, 1.0] are mapped linearly to
* 3D LUT indices such that 0.0 maps exactly to the first element and 1.0 maps
* exactly to the last element in each dimension.
*
* This object represents a 3D LUT and offers an interface for realizing it
* as a data array with a custom size.
*/
struct weston_color_mapping_3dlut {
/**
* Create a 3D LUT data array
*
* \param xform This color transformation object.
* \param values Memory to hold the resulting data array.
* \param len The number of elements in each dimension.
*
* The array \c values must be at least 3 * len * len * len elements
* in size.
*
* Given the red index ri, green index gi and blue index bi, the
* corresponding array element index
*
* i = 3 * (len * len * bi + len * gi + ri) + c
*
* where
*
* c = 0 for red output value,
* c = 1 for green output value, and
* c = 2 for blue output value
*/
void
(*fill_in)(struct weston_color_transform *xform,
float *values, unsigned len);
/** Optimal 3D LUT size along each dimension */
unsigned optimal_len;
};
/**
* Color mapping function
*
* This object can represent a 3D LUT to do a color space conversion
*
*/
struct weston_color_mapping {
/** Which member of 'u' defines the color mapping type */
enum weston_color_mapping_type type;
/** Parameters for the color mapping function */
union {
/* identity: no parameters */
struct weston_color_mapping_3dlut lut3d;
} u;
};
/**
* Describes a color transformation formula
*
@@ -124,7 +198,7 @@ struct weston_color_transform {
struct weston_color_curve pre_curve;
/** Step 3: color mapping */
/* TBD: e.g. a 3D LUT or a matrix */
struct weston_color_mapping mapping;
/** Step 4: color curve after color mapping */
/* struct weston_color_curve post_curve; */
@@ -223,53 +297,19 @@ struct weston_color_manager {
struct weston_output *output,
struct weston_surface_color_transform *surf_xform);
/** Get output's blending space to output transformation
/** Compute derived color properties for an output
*
* \param cm The color manager.
* \param output The output for the destination color space.
* \param xform_out Pointer for storing the weston_color_transform.
* \return True on success, false on failure.
* \param output The output.
* \return A new color_outcome object on success, NULL on failure.
*
* The callee is responsible for increasing the reference count on the
* weston_color_transform it stores via xform_out. On failure, xform_out
* is untouched.
* The callee (color manager) must inspect the weston_output (color
* profile, EOTF mode, etc.) and create a fully populated
* weston_output_color_outcome object.
*/
bool
(*get_output_color_transform)(struct weston_color_manager *cm,
struct weston_output *output,
struct weston_color_transform **xform_out);
/** Get sRGB to output transformation
*
* \param cm The color manager.
* \param output The output for the destination color space.
* \param xform_out Pointer for storing the weston_color_transform.
* \return True on success, false on failure.
*
* The callee is responsible for increasing the reference count on the
* weston_color_transform it stores via xform_out. On failure, xform_out
* is untouched.
*/
bool
(*get_sRGB_to_output_color_transform)(struct weston_color_manager *cm,
struct weston_output *output,
struct weston_color_transform **xform_out);
/** Get sRGB to output's blending space transformation
*
* \param cm The color manager.
* \param output The output for the destination blending color space.
* \param xform_out Pointer for storing the weston_color_transform.
* \return True on success, false on failure.
*
* The callee is responsible for increasing the reference count on the
* weston_color_transform it stores via xform_out. On failure, xform_out
* is untouched.
*/
bool
(*get_sRGB_to_blend_color_transform)(struct weston_color_manager *cm,
struct weston_output *output,
struct weston_color_transform **xform_out);
struct weston_output_color_outcome *
(*create_output_color_outcome)(struct weston_color_manager *cm,
struct weston_output *output);
};
void
@@ -305,4 +345,13 @@ weston_color_manager_noop_create(struct weston_compositor *compositor);
struct weston_color_manager *
weston_color_manager_create(struct weston_compositor *compositor);
const char *
weston_eotf_mode_to_str(enum weston_eotf_mode e);
char *
weston_eotf_mask_to_str(uint32_t eotf_mask);
void
weston_output_color_outcome_destroy(struct weston_output_color_outcome **pco);
#endif /* WESTON_COLOR_H */
+967 -283
View File
File diff suppressed because it is too large Load Diff
+10 -6
View File
@@ -420,7 +420,7 @@ drag_surface_configure(struct weston_drag *drag,
assert((pointer != NULL && touch == NULL) ||
(pointer == NULL && touch != NULL));
if (!weston_surface_is_mapped(es) && es->buffer_ref.buffer) {
if (!weston_surface_is_mapped(es) && weston_surface_has_content(es)) {
if (pointer && pointer->sprite &&
weston_view_is_mapped(pointer->sprite))
list = &pointer->sprite->layer_link;
@@ -431,7 +431,7 @@ drag_surface_configure(struct weston_drag *drag,
weston_layer_entry_insert(list, &drag->icon->layer_link);
weston_view_update_transform(drag->icon);
pixman_region32_clear(&es->pending.input);
es->is_mapped = true;
weston_surface_map(es);
drag->icon->is_mapped = true;
}
@@ -1057,13 +1057,17 @@ data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
touch->focus &&
touch->focus->surface == origin;
if (!is_pointer_grab && !is_touch_grab)
return;
/* FIXME: Check that the data source type array isn't empty. */
if (source_resource)
source = wl_resource_get_user_data(source_resource);
if (!is_pointer_grab && !is_touch_grab) {
if (source)
wl_data_source_send_cancelled(source->resource);
return;
}
if (icon_resource)
icon = wl_resource_get_user_data(icon_resource);
@@ -1235,7 +1239,7 @@ destroy_data_source(struct wl_resource *resource)
static void
client_source_accept(struct weston_data_source *source,
uint32_t time, const char *mime_type)
uint32_t serial, const char *mime_type)
{
wl_data_source_send_target(source->resource, mime_type);
}
+224
View File
@@ -0,0 +1,224 @@
/*
* Copyright © 2016 Quentin "Sardem FF7" Glidic
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <wayland-server.h>
#include <assert.h>
#include <libweston/libweston.h>
#include <libweston/zalloc.h>
#include <libweston-desktop/libweston-desktop.h>
#include "internal.h"
struct weston_desktop_client {
struct weston_desktop *desktop;
struct wl_client *client;
struct wl_resource *resource;
struct wl_list surface_list;
uint32_t ping_serial;
struct wl_event_source *ping_timer;
struct wl_signal destroy_signal;
};
void
weston_desktop_client_add_destroy_listener(struct weston_desktop_client *client,
struct wl_listener *listener)
{
wl_signal_add(&client->destroy_signal, listener);
}
void
weston_desktop_client_destroy(struct weston_desktop_client *client)
{
struct wl_list *list = &client->surface_list;
struct wl_list *link, *tmp;
assert(client->resource == NULL);
wl_signal_emit(&client->destroy_signal, client);
for (link = list->next, tmp = link->next;
link != list;
link = tmp, tmp = link->next) {
wl_list_remove(link);
wl_list_init(link);
}
if (client->ping_timer != NULL)
wl_event_source_remove(client->ping_timer);
free(client);
}
static void
weston_desktop_client_handle_destroy(struct wl_resource *resource)
{
struct weston_desktop_client *client =
wl_resource_get_user_data(resource);
assert(client->resource == resource);
client->resource = NULL;
weston_desktop_client_destroy(client);
}
static int
weston_desktop_client_ping_timeout(void *user_data)
{
struct weston_desktop_client *client = user_data;
weston_desktop_api_ping_timeout(client->desktop, client);
return 1;
}
struct weston_desktop_client *
weston_desktop_client_create(struct weston_desktop *desktop,
struct wl_client *wl_client,
wl_dispatcher_func_t dispatcher,
const struct wl_interface *interface,
const void *implementation, uint32_t version,
uint32_t id)
{
struct weston_desktop_client *client;
struct wl_display *display;
struct wl_event_loop *loop;
client = zalloc(sizeof(struct weston_desktop_client));
if (client == NULL) {
if (wl_client != NULL)
wl_client_post_no_memory(wl_client);
return NULL;
}
client->desktop = desktop;
client->client = wl_client;
wl_list_init(&client->surface_list);
wl_signal_init(&client->destroy_signal);
if (wl_client == NULL)
return client;
client->resource = wl_resource_create(wl_client, interface, version, id);
if (client->resource == NULL) {
wl_client_post_no_memory(wl_client);
free(client);
return NULL;
}
if (dispatcher != NULL)
wl_resource_set_dispatcher(client->resource, dispatcher,
weston_desktop_client_handle_destroy, client,
weston_desktop_client_handle_destroy);
else
wl_resource_set_implementation(client->resource, implementation,
client,
weston_desktop_client_handle_destroy);
display = wl_client_get_display(client->client);
loop = wl_display_get_event_loop(display);
client->ping_timer =
wl_event_loop_add_timer(loop,
weston_desktop_client_ping_timeout,
client);
if (client->ping_timer == NULL)
wl_client_post_no_memory(wl_client);
return client;
}
struct weston_desktop *
weston_desktop_client_get_desktop(struct weston_desktop_client *client)
{
return client->desktop;
}
struct wl_resource *
weston_desktop_client_get_resource(struct weston_desktop_client *client)
{
return client->resource;
}
struct wl_list *
weston_desktop_client_get_surface_list(struct weston_desktop_client *client)
{
return &client->surface_list;
}
WL_EXPORT struct wl_client *
weston_desktop_client_get_client(struct weston_desktop_client *client)
{
return client->client;
}
WL_EXPORT void
weston_desktop_client_for_each_surface(struct weston_desktop_client *client,
void (*callback)(struct weston_desktop_surface *surface, void *user_data),
void *user_data)
{
struct wl_list *list = &client->surface_list;
struct wl_list *link;
for (link = list->next; link != list; link = link->next)
callback(weston_desktop_surface_from_client_link(link),
user_data);
}
WL_EXPORT int
weston_desktop_client_ping(struct weston_desktop_client *client)
{
struct weston_desktop_surface *surface =
weston_desktop_surface_from_client_link(client->surface_list.next);
const struct weston_desktop_surface_implementation *implementation =
weston_desktop_surface_get_implementation(surface);
void *implementation_data =
weston_desktop_surface_get_implementation_data(surface);
if (implementation->ping == NULL)
return -1;
if (client->ping_serial != 0)
return 1;
client->ping_serial =
wl_display_next_serial(wl_client_get_display(client->client));
wl_event_source_timer_update(client->ping_timer, 10000);
implementation->ping(surface, client->ping_serial, implementation_data);
return 0;
}
void
weston_desktop_client_pong(struct weston_desktop_client *client, uint32_t serial)
{
if (client->ping_serial != serial)
return;
weston_desktop_api_pong(client->desktop, client);
wl_event_source_timer_update(client->ping_timer, 0);
client->ping_serial = 0;
}
+249
View File
@@ -0,0 +1,249 @@
/*
* Copyright © 2016 Quentin "Sardem FF7" Glidic
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef WESTON_DESKTOP_INTERNAL_H
#define WESTON_DESKTOP_INTERNAL_H
#include <libweston/libweston.h>
struct weston_desktop_seat;
struct weston_desktop_client;
struct weston_compositor *
weston_desktop_get_compositor(struct weston_desktop *desktop);
struct wl_display *
weston_desktop_get_display(struct weston_desktop *desktop);
void
weston_desktop_api_ping_timeout(struct weston_desktop *desktop,
struct weston_desktop_client *client);
void
weston_desktop_api_pong(struct weston_desktop *desktop,
struct weston_desktop_client *client);
void
weston_desktop_api_surface_added(struct weston_desktop *desktop,
struct weston_desktop_surface *surface);
void
weston_desktop_api_surface_removed(struct weston_desktop *desktop,
struct weston_desktop_surface *surface);
void
weston_desktop_api_committed(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
int32_t sx, int32_t sy);
void
weston_desktop_api_show_window_menu(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
struct weston_seat *seat,
int32_t x, int32_t y);
void
weston_desktop_api_set_parent(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
struct weston_desktop_surface *parent);
void
weston_desktop_api_move(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
struct weston_seat *seat, uint32_t serial);
void
weston_desktop_api_resize(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
struct weston_seat *seat, uint32_t serial,
enum weston_desktop_surface_edge edges);
void
weston_desktop_api_fullscreen_requested(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
bool fullscreen,
struct weston_output *output);
void
weston_desktop_api_maximized_requested(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
bool maximized);
void
weston_desktop_api_minimized_requested(struct weston_desktop *desktop,
struct weston_desktop_surface *surface);
void
weston_desktop_api_set_xwayland_position(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
int32_t x, int32_t y);
void
weston_desktop_api_get_position(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
int32_t *x, int32_t *y);
struct weston_desktop_seat *
weston_desktop_seat_from_seat(struct weston_seat *wseat);
struct weston_desktop_surface_implementation {
void (*set_activated)(struct weston_desktop_surface *surface,
void *user_data, bool activated);
void (*set_fullscreen)(struct weston_desktop_surface *surface,
void *user_data, bool fullscreen);
void (*set_maximized)(struct weston_desktop_surface *surface,
void *user_data, bool maximized);
void (*set_resizing)(struct weston_desktop_surface *surface,
void *user_data, bool resizing);
void (*set_size)(struct weston_desktop_surface *surface,
void *user_data, int32_t width, int32_t height);
void (*set_orientation)(struct weston_desktop_surface *surface,
void *user_data, enum weston_top_level_tiled_orientation tiled_orientation);
void (*committed)(struct weston_desktop_surface *surface, void *user_data,
int32_t sx, int32_t sy);
void (*update_position)(struct weston_desktop_surface *surface,
void *user_data);
void (*ping)(struct weston_desktop_surface *surface, uint32_t serial,
void *user_data);
void (*close)(struct weston_desktop_surface *surface, void *user_data);
bool (*get_activated)(struct weston_desktop_surface *surface,
void *user_data);
bool (*get_fullscreen)(struct weston_desktop_surface *surface,
void *user_data);
bool (*get_maximized)(struct weston_desktop_surface *surface,
void *user_data);
bool (*get_resizing)(struct weston_desktop_surface *surface,
void *user_data);
struct weston_size
(*get_max_size)(struct weston_desktop_surface *surface,
void *user_data);
struct weston_size
(*get_min_size)(struct weston_desktop_surface *surface,
void *user_data);
void (*destroy)(struct weston_desktop_surface *surface,
void *user_data);
};
struct weston_desktop_client *
weston_desktop_client_create(struct weston_desktop *desktop,
struct wl_client *client,
wl_dispatcher_func_t dispatcher,
const struct wl_interface *interface,
const void *implementation, uint32_t version,
uint32_t id);
void
weston_desktop_client_destroy(struct weston_desktop_client *client);
void
weston_desktop_client_add_destroy_listener(struct weston_desktop_client *client,
struct wl_listener *listener);
struct weston_desktop *
weston_desktop_client_get_desktop(struct weston_desktop_client *client);
struct wl_resource *
weston_desktop_client_get_resource(struct weston_desktop_client *client);
struct wl_list *
weston_desktop_client_get_surface_list(struct weston_desktop_client *client);
void
weston_desktop_client_pong(struct weston_desktop_client *client,
uint32_t serial);
struct weston_desktop_surface *
weston_desktop_surface_create(struct weston_desktop *desktop,
struct weston_desktop_client *client,
struct weston_surface *surface,
const struct weston_desktop_surface_implementation *implementation,
void *implementation_data);
void
weston_desktop_surface_destroy(struct weston_desktop_surface *surface);
void
weston_desktop_surface_resource_destroy(struct wl_resource *resource);
struct wl_resource *
weston_desktop_surface_add_resource(struct weston_desktop_surface *surface,
const struct wl_interface *interface,
const void *implementation, uint32_t id,
wl_resource_destroy_func_t destroy);
struct weston_desktop_surface *
weston_desktop_surface_from_grab_link(struct wl_list *grab_link);
struct wl_list *
weston_desktop_surface_get_client_link(struct weston_desktop_surface *surface);
struct weston_desktop_surface *
weston_desktop_surface_from_client_link(struct wl_list *link);
bool
weston_desktop_surface_has_implementation(struct weston_desktop_surface *surface,
const struct weston_desktop_surface_implementation *implementation);
const struct weston_desktop_surface_implementation *
weston_desktop_surface_get_implementation(struct weston_desktop_surface *surface);
void *
weston_desktop_surface_get_implementation_data(struct weston_desktop_surface *surface);
struct weston_desktop_surface *
weston_desktop_surface_get_parent(struct weston_desktop_surface *surface);
bool
weston_desktop_surface_get_grab(struct weston_desktop_surface *surface);
void
weston_desktop_surface_set_title(struct weston_desktop_surface *surface,
const char *title);
void
weston_desktop_surface_set_app_id(struct weston_desktop_surface *surface,
const char *app_id);
void
weston_desktop_surface_set_pid(struct weston_desktop_surface *surface,
pid_t pid);
void
weston_desktop_surface_set_geometry(struct weston_desktop_surface *surface,
struct weston_geometry geometry);
void
weston_desktop_surface_set_relative_to(struct weston_desktop_surface *surface,
struct weston_desktop_surface *parent,
int32_t x, int32_t y, bool use_geometry);
void
weston_desktop_surface_unset_relative_to(struct weston_desktop_surface *surface);
void
weston_desktop_surface_popup_grab(struct weston_desktop_surface *popup,
struct weston_desktop_seat *seat,
uint32_t serial);
void
weston_desktop_surface_popup_ungrab(struct weston_desktop_surface *popup,
struct weston_desktop_seat *seat);
void
weston_desktop_surface_popup_dismiss(struct weston_desktop_surface *surface);
struct weston_desktop_surface *
weston_desktop_seat_popup_grab_get_topmost_surface(struct weston_desktop_seat *seat);
bool
weston_desktop_seat_popup_grab_start(struct weston_desktop_seat *seat,
struct wl_client *client, uint32_t serial);
void
weston_desktop_seat_popup_grab_add_surface(struct weston_desktop_seat *seat,
struct wl_list *link);
void
weston_desktop_seat_popup_grab_remove_surface(struct weston_desktop_seat *seat,
struct wl_list *link);
void
weston_desktop_destroy_request(struct wl_client *client,
struct wl_resource *resource);
struct wl_global *
weston_desktop_xdg_wm_base_create(struct weston_desktop *desktop,
struct wl_display *display);
struct wl_global *
weston_desktop_xdg_shell_v6_create(struct weston_desktop *desktop,
struct wl_display *display);
void
weston_desktop_xwayland_init(struct weston_desktop *desktop);
void
weston_desktop_xwayland_fini(struct weston_desktop *desktop);
#endif /* WESTON_DESKTOP_INTERNAL_H */
+286
View File
@@ -0,0 +1,286 @@
/*
* Copyright © 2016 Quentin "Sardem FF7" Glidic
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <string.h>
#include <wayland-server.h>
#include <assert.h>
#include <libweston/libweston.h>
#include <libweston/zalloc.h>
#include "shared/helpers.h"
#include <libweston-desktop/libweston-desktop.h>
#include "internal.h"
struct weston_desktop {
struct weston_compositor *compositor;
struct weston_desktop_api api;
void *user_data;
struct wl_global *xdg_wm_base; /* Stable protocol xdg_shell replaces xdg_shell_unstable_v6 */
struct wl_global *xdg_shell_v6; /* Unstable xdg_shell_unstable_v6 protocol. */
};
void
weston_desktop_destroy_request(struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
WL_EXPORT struct weston_desktop *
weston_desktop_create(struct weston_compositor *compositor,
const struct weston_desktop_api *api, void *user_data)
{
struct weston_desktop *desktop;
struct wl_display *display = compositor->wl_display;
assert(api->surface_added);
assert(api->surface_removed);
desktop = zalloc(sizeof(struct weston_desktop));
desktop->compositor = compositor;
desktop->user_data = user_data;
desktop->api.struct_size =
MIN(sizeof(struct weston_desktop_api), api->struct_size);
memcpy(&desktop->api, api, desktop->api.struct_size);
desktop->xdg_wm_base =
weston_desktop_xdg_wm_base_create(desktop, display);
if (desktop->xdg_wm_base == NULL) {
weston_desktop_destroy(desktop);
return NULL;
}
weston_desktop_xwayland_init(desktop);
return desktop;
}
WL_EXPORT void
weston_desktop_destroy(struct weston_desktop *desktop)
{
if (desktop == NULL)
return;
weston_desktop_xwayland_fini(desktop);
if (desktop->xdg_shell_v6 != NULL)
wl_global_destroy(desktop->xdg_shell_v6);
if (desktop->xdg_wm_base != NULL)
wl_global_destroy(desktop->xdg_wm_base);
free(desktop);
}
struct weston_compositor *
weston_desktop_get_compositor(struct weston_desktop *desktop)
{
return desktop->compositor;
}
struct wl_display *
weston_desktop_get_display(struct weston_desktop *desktop)
{
return desktop->compositor->wl_display;
}
void
weston_desktop_api_ping_timeout(struct weston_desktop *desktop,
struct weston_desktop_client *client)
{
if (desktop->api.ping_timeout != NULL)
desktop->api.ping_timeout(client, desktop->user_data);
}
void
weston_desktop_api_pong(struct weston_desktop *desktop,
struct weston_desktop_client *client)
{
if (desktop->api.pong != NULL)
desktop->api.pong(client, desktop->user_data);
}
void
weston_desktop_api_surface_added(struct weston_desktop *desktop,
struct weston_desktop_surface *surface)
{
struct weston_desktop_client *client =
weston_desktop_surface_get_client(surface);
struct wl_list *list = weston_desktop_client_get_surface_list(client);
struct wl_list *link = weston_desktop_surface_get_client_link(surface);
desktop->api.surface_added(surface, desktop->user_data);
wl_list_insert(list, link);
}
void
weston_desktop_api_surface_removed(struct weston_desktop *desktop,
struct weston_desktop_surface *surface)
{
struct wl_list *link = weston_desktop_surface_get_client_link(surface);
wl_list_remove(link);
wl_list_init(link);
desktop->api.surface_removed(surface, desktop->user_data);
}
void
weston_desktop_api_committed(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
int32_t sx, int32_t sy)
{
if (desktop->api.committed != NULL)
desktop->api.committed(surface, sx, sy, desktop->user_data);
}
void
weston_desktop_api_show_window_menu(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
struct weston_seat *seat,
int32_t x, int32_t y)
{
if (desktop->api.show_window_menu != NULL)
desktop->api.show_window_menu(surface, seat, x, y,
desktop->user_data);
}
bool
weston_desktop_window_menu_supported(struct weston_desktop *desktop)
{
return desktop->api.show_window_menu != NULL;
}
void
weston_desktop_api_set_parent(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
struct weston_desktop_surface *parent)
{
if (desktop->api.set_parent != NULL)
desktop->api.set_parent(surface, parent, desktop->user_data);
}
void
weston_desktop_api_move(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
struct weston_seat *seat, uint32_t serial)
{
if (desktop->api.move != NULL)
desktop->api.move(surface, seat, serial, desktop->user_data);
}
bool
weston_desktop_move_supported(struct weston_desktop *desktop)
{
return desktop->api.move != NULL;
}
void
weston_desktop_api_resize(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
struct weston_seat *seat, uint32_t serial,
enum weston_desktop_surface_edge edges)
{
if (desktop->api.resize != NULL)
desktop->api.resize(surface, seat, serial, edges,
desktop->user_data);
}
bool
weston_desktop_resize_supported(struct weston_desktop *desktop)
{
return desktop->api.resize != NULL;
}
void
weston_desktop_api_fullscreen_requested(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
bool fullscreen,
struct weston_output *output)
{
if (desktop->api.fullscreen_requested != NULL)
desktop->api.fullscreen_requested(surface, fullscreen, output,
desktop->user_data);
}
bool
weston_desktop_fullscreen_supported(struct weston_desktop *desktop)
{
return desktop->api.fullscreen_requested != NULL;
}
void
weston_desktop_api_maximized_requested(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
bool maximized)
{
if (desktop->api.maximized_requested != NULL)
desktop->api.maximized_requested(surface, maximized,
desktop->user_data);
}
bool
weston_desktop_maximize_supported(struct weston_desktop *desktop)
{
return desktop->api.maximized_requested != NULL;
}
void
weston_desktop_api_minimized_requested(struct weston_desktop *desktop,
struct weston_desktop_surface *surface)
{
if (desktop->api.minimized_requested != NULL)
desktop->api.minimized_requested(surface, desktop->user_data);
}
bool
weston_desktop_minimize_supported(struct weston_desktop *desktop)
{
return desktop->api.minimized_requested != NULL;
}
void
weston_desktop_api_set_xwayland_position(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
int32_t x, int32_t y)
{
if (desktop->api.set_xwayland_position != NULL)
desktop->api.set_xwayland_position(surface, x, y,
desktop->user_data);
}
void
weston_desktop_api_get_position(struct weston_desktop *desktop,
struct weston_desktop_surface *surface,
int32_t *x, int32_t *y)
{
if (!desktop->api.get_position)
return;
desktop->api.get_position(surface, x, y, desktop->user_data);
}
+16
View File
@@ -0,0 +1,16 @@
srcs_libweston += files([
'libweston-desktop.c',
'client.c',
'seat.c',
'surface.c',
'xwayland.c',
'xdg-shell.c',
'xdg-shell-v6.c',
])
srcs_libweston += [
xdg_shell_unstable_v6_server_protocol_h,
xdg_shell_unstable_v6_protocol_c,
xdg_shell_server_protocol_h,
xdg_shell_protocol_c,
]
+381
View File
@@ -0,0 +1,381 @@
/*
* Copyright © 2010-2012 Intel Corporation
* Copyright © 2011-2012 Collabora, Ltd.
* Copyright © 2013 Raspberry Pi Foundation
* Copyright © 2016 Quentin "Sardem FF7" Glidic
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <assert.h>
#include <wayland-server.h>
#include <libweston/libweston.h>
#include <libweston/zalloc.h>
#include <libweston-desktop/libweston-desktop.h>
#include "internal.h"
#include "shared/timespec-util.h"
struct weston_desktop_seat {
struct wl_listener seat_destroy_listener;
struct weston_seat *seat;
struct {
struct weston_keyboard_grab keyboard;
struct weston_pointer_grab pointer;
struct weston_touch_grab touch;
bool initial_up;
struct wl_client *client;
struct wl_list surfaces;
} popup_grab;
};
static void weston_desktop_seat_popup_grab_end(struct weston_desktop_seat *seat);
static void
weston_desktop_seat_popup_grab_keyboard_key(struct weston_keyboard_grab *grab,
const struct timespec *time,
uint32_t key,
enum wl_keyboard_key_state state)
{
weston_keyboard_send_key(grab->keyboard, time, key, state);
}
static void
weston_desktop_seat_popup_grab_keyboard_modifiers(struct weston_keyboard_grab *grab,
uint32_t serial,
uint32_t mods_depressed,
uint32_t mods_latched,
uint32_t mods_locked,
uint32_t group)
{
weston_keyboard_send_modifiers(grab->keyboard, serial, mods_depressed,
mods_latched, mods_locked, group);
}
static void
weston_desktop_seat_popup_grab_keyboard_cancel(struct weston_keyboard_grab *grab)
{
struct weston_desktop_seat *seat =
wl_container_of(grab, seat, popup_grab.keyboard);
weston_desktop_seat_popup_grab_end(seat);
}
static const struct weston_keyboard_grab_interface weston_desktop_seat_keyboard_popup_grab_interface = {
.key = weston_desktop_seat_popup_grab_keyboard_key,
.modifiers = weston_desktop_seat_popup_grab_keyboard_modifiers,
.cancel = weston_desktop_seat_popup_grab_keyboard_cancel,
};
static void
weston_desktop_seat_popup_grab_pointer_focus(struct weston_pointer_grab *grab)
{
struct weston_desktop_seat *seat =
wl_container_of(grab, seat, popup_grab.pointer);
struct weston_pointer *pointer = grab->pointer;
struct weston_view *view;
wl_fixed_t sx, sy;
view = weston_compositor_pick_view(pointer->seat->compositor,
pointer->x, pointer->y, &sx, &sy);
if (view != NULL &&
view->surface->resource != NULL &&
wl_resource_get_client(view->surface->resource) == seat->popup_grab.client)
weston_pointer_set_focus(pointer, view, sx, sy);
else
weston_pointer_clear_focus(pointer);
}
static void
weston_desktop_seat_popup_grab_pointer_motion(struct weston_pointer_grab *grab,
const struct timespec *time,
struct weston_pointer_motion_event *event)
{
weston_pointer_send_motion(grab->pointer, time, event);
}
static void
weston_desktop_seat_popup_grab_pointer_button(struct weston_pointer_grab *grab,
const struct timespec *time,
uint32_t button,
enum wl_pointer_button_state state)
{
struct weston_desktop_seat *seat =
wl_container_of(grab, seat, popup_grab.pointer);
struct weston_pointer *pointer = grab->pointer;
bool initial_up = seat->popup_grab.initial_up;
if (state == WL_POINTER_BUTTON_STATE_RELEASED)
seat->popup_grab.initial_up = true;
if (weston_pointer_has_focus_resource(pointer))
weston_pointer_send_button(pointer, time, button, state);
else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
(initial_up ||
(timespec_sub_to_msec(time, &grab->pointer->grab_time) > 500)))
weston_desktop_seat_popup_grab_end(seat);
}
static void
weston_desktop_seat_popup_grab_pointer_axis(struct weston_pointer_grab *grab,
const struct timespec *time,
struct weston_pointer_axis_event *event)
{
weston_pointer_send_axis(grab->pointer, time, event);
}
static void
weston_desktop_seat_popup_grab_pointer_axis_source(struct weston_pointer_grab *grab,
uint32_t source)
{
weston_pointer_send_axis_source(grab->pointer, source);
}
static void
weston_desktop_seat_popup_grab_pointer_frame(struct weston_pointer_grab *grab)
{
weston_pointer_send_frame(grab->pointer);
}
static void
weston_desktop_seat_popup_grab_pointer_cancel(struct weston_pointer_grab *grab)
{
struct weston_desktop_seat *seat =
wl_container_of(grab, seat, popup_grab.pointer);
weston_desktop_seat_popup_grab_end(seat);
}
static const struct weston_pointer_grab_interface weston_desktop_seat_pointer_popup_grab_interface = {
.focus = weston_desktop_seat_popup_grab_pointer_focus,
.motion = weston_desktop_seat_popup_grab_pointer_motion,
.button = weston_desktop_seat_popup_grab_pointer_button,
.axis = weston_desktop_seat_popup_grab_pointer_axis,
.axis_source = weston_desktop_seat_popup_grab_pointer_axis_source,
.frame = weston_desktop_seat_popup_grab_pointer_frame,
.cancel = weston_desktop_seat_popup_grab_pointer_cancel,
};
static void
weston_desktop_seat_popup_grab_touch_down(struct weston_touch_grab *grab,
const struct timespec *time,
int touch_id,
wl_fixed_t sx, wl_fixed_t sy)
{
weston_touch_send_down(grab->touch, time, touch_id, sx, sy);
}
static void
weston_desktop_seat_popup_grab_touch_up(struct weston_touch_grab *grab,
const struct timespec *time,
int touch_id)
{
weston_touch_send_up(grab->touch, time, touch_id);
}
static void
weston_desktop_seat_popup_grab_touch_motion(struct weston_touch_grab *grab,
const struct timespec *time,
int touch_id,
wl_fixed_t sx, wl_fixed_t sy)
{
weston_touch_send_motion(grab->touch, time, touch_id, sx, sy);
}
static void
weston_desktop_seat_popup_grab_touch_frame(struct weston_touch_grab *grab)
{
weston_touch_send_frame(grab->touch);
}
static void
weston_desktop_seat_popup_grab_touch_cancel(struct weston_touch_grab *grab)
{
struct weston_desktop_seat *seat =
wl_container_of(grab, seat, popup_grab.touch);
weston_desktop_seat_popup_grab_end(seat);
}
static const struct weston_touch_grab_interface weston_desktop_seat_touch_popup_grab_interface = {
.down = weston_desktop_seat_popup_grab_touch_down,
.up = weston_desktop_seat_popup_grab_touch_up,
.motion = weston_desktop_seat_popup_grab_touch_motion,
.frame = weston_desktop_seat_popup_grab_touch_frame,
.cancel = weston_desktop_seat_popup_grab_touch_cancel,
};
static void
weston_desktop_seat_destroy(struct wl_listener *listener, void *data)
{
struct weston_desktop_seat *seat =
wl_container_of(listener, seat, seat_destroy_listener);
free(seat);
}
struct weston_desktop_seat *
weston_desktop_seat_from_seat(struct weston_seat *wseat)
{
struct wl_listener *listener;
struct weston_desktop_seat *seat;
if (wseat == NULL)
return NULL;
listener = wl_signal_get(&wseat->destroy_signal,
weston_desktop_seat_destroy);
if (listener != NULL)
return wl_container_of(listener, seat, seat_destroy_listener);
seat = zalloc(sizeof(struct weston_desktop_seat));
if (seat == NULL)
return NULL;
seat->seat = wseat;
seat->seat_destroy_listener.notify = weston_desktop_seat_destroy;
wl_signal_add(&wseat->destroy_signal, &seat->seat_destroy_listener);
seat->popup_grab.keyboard.interface =
&weston_desktop_seat_keyboard_popup_grab_interface;
seat->popup_grab.pointer.interface =
&weston_desktop_seat_pointer_popup_grab_interface;
seat->popup_grab.touch.interface =
&weston_desktop_seat_touch_popup_grab_interface;
wl_list_init(&seat->popup_grab.surfaces);
return seat;
}
struct weston_desktop_surface *
weston_desktop_seat_popup_grab_get_topmost_surface(struct weston_desktop_seat *seat)
{
if (seat == NULL || wl_list_empty(&seat->popup_grab.surfaces))
return NULL;
struct wl_list *grab_link = seat->popup_grab.surfaces.next;
return weston_desktop_surface_from_grab_link(grab_link);
}
bool
weston_desktop_seat_popup_grab_start(struct weston_desktop_seat *seat,
struct wl_client *client, uint32_t serial)
{
assert(seat == NULL || seat->popup_grab.client == NULL ||
seat->popup_grab.client == client);
struct weston_seat *wseat = seat != NULL ? seat->seat : NULL;
/* weston_seat_get_* functions can properly handle a NULL wseat */
struct weston_keyboard *keyboard = weston_seat_get_keyboard(wseat);
struct weston_pointer *pointer = weston_seat_get_pointer(wseat);
struct weston_touch *touch = weston_seat_get_touch(wseat);
if ((keyboard == NULL || keyboard->grab_serial != serial) &&
(pointer == NULL || pointer->grab_serial != serial) &&
(touch == NULL || touch->grab_serial != serial)) {
return false;
}
if (keyboard != NULL &&
keyboard->grab->interface != &weston_desktop_seat_keyboard_popup_grab_interface)
weston_keyboard_start_grab(keyboard, &seat->popup_grab.keyboard);
if (pointer != NULL &&
pointer->grab->interface != &weston_desktop_seat_pointer_popup_grab_interface)
weston_pointer_start_grab(pointer, &seat->popup_grab.pointer);
if (touch != NULL &&
touch->grab->interface != &weston_desktop_seat_touch_popup_grab_interface)
weston_touch_start_grab(touch, &seat->popup_grab.touch);
seat->popup_grab.initial_up =
(pointer == NULL || pointer->button_count == 0);
seat->popup_grab.client = client;
return true;
}
static void
weston_desktop_seat_popup_grab_end(struct weston_desktop_seat *seat)
{
struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat->seat);
struct weston_pointer *pointer = weston_seat_get_pointer(seat->seat);
struct weston_touch *touch = weston_seat_get_touch(seat->seat);
while (!wl_list_empty(&seat->popup_grab.surfaces)) {
struct wl_list *link = seat->popup_grab.surfaces.prev;
struct weston_desktop_surface *surface =
weston_desktop_surface_from_grab_link(link);
wl_list_remove(link);
wl_list_init(link);
weston_desktop_surface_popup_dismiss(surface);
}
if (keyboard != NULL &&
keyboard->grab->interface == &weston_desktop_seat_keyboard_popup_grab_interface)
weston_keyboard_end_grab(keyboard);
if (pointer != NULL &&
pointer->grab->interface == &weston_desktop_seat_pointer_popup_grab_interface)
weston_pointer_end_grab(pointer);
if (touch != NULL &&
touch->grab->interface == &weston_desktop_seat_touch_popup_grab_interface)
weston_touch_end_grab(touch);
seat->popup_grab.client = NULL;
}
void
weston_desktop_seat_popup_grab_add_surface(struct weston_desktop_seat *seat,
struct wl_list *link)
{
assert(seat->popup_grab.client != NULL);
wl_list_insert(&seat->popup_grab.surfaces, link);
}
void
weston_desktop_seat_popup_grab_remove_surface(struct weston_desktop_seat *seat,
struct wl_list *link)
{
assert(seat->popup_grab.client != NULL);
wl_list_remove(link);
wl_list_init(link);
if (wl_list_empty(&seat->popup_grab.surfaces))
weston_desktop_seat_popup_grab_end(seat);
}
WL_EXPORT void
weston_seat_break_desktop_grabs(struct weston_seat *wseat)
{
struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
weston_desktop_seat_popup_grab_end(seat);
}
+840
View File
@@ -0,0 +1,840 @@
/*
* Copyright © 2016 Quentin "Sardem FF7" Glidic
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <string.h>
#include <assert.h>
#include <wayland-server.h>
#include <libweston/libweston.h>
#include <libweston/zalloc.h>
#include <libweston-desktop/libweston-desktop.h>
#include "internal.h"
struct weston_desktop_view {
struct wl_list link;
struct weston_view *view;
struct weston_desktop_view *parent;
struct wl_list children_list;
struct wl_list children_link;
};
struct weston_desktop_surface {
struct weston_desktop *desktop;
struct weston_desktop_client *client;
struct wl_list client_link;
const struct weston_desktop_surface_implementation *implementation;
void *implementation_data;
void *user_data;
struct weston_surface *surface;
struct wl_list view_list;
struct weston_position buffer_move;
struct wl_listener surface_commit_listener;
struct wl_listener surface_destroy_listener;
struct wl_listener client_destroy_listener;
struct wl_list children_list;
struct wl_list resource_list;
bool has_geometry;
struct weston_geometry geometry;
struct {
char *title;
char *app_id;
pid_t pid;
struct wl_signal metadata_signal;
};
struct {
struct weston_desktop_surface *parent;
struct wl_list children_link;
struct weston_position position;
bool use_geometry;
};
struct {
struct wl_list grab_link;
};
};
static void
weston_desktop_surface_update_view_position(struct weston_desktop_surface *surface)
{
struct weston_desktop_view *view;
int32_t x, y;
x = surface->position.x;
y = surface->position.y;
if (surface->use_geometry) {
struct weston_desktop_surface *parent =
weston_desktop_surface_get_parent(surface);
struct weston_geometry geometry, parent_geometry;
geometry = weston_desktop_surface_get_geometry(surface);
parent_geometry = weston_desktop_surface_get_geometry(parent);
x += parent_geometry.x - geometry.x;
y += parent_geometry.y - geometry.y;
}
wl_list_for_each(view, &surface->view_list, link)
weston_view_set_position(view->view, x, y);
}
static void
weston_desktop_view_propagate_layer(struct weston_desktop_view *view);
static void
weston_desktop_view_destroy(struct weston_desktop_view *view)
{
struct weston_desktop_view *child_view, *tmp;
wl_list_for_each_safe(child_view, tmp, &view->children_list, children_link)
weston_desktop_view_destroy(child_view);
wl_list_remove(&view->children_link);
wl_list_remove(&view->link);
weston_view_damage_below(view->view);
if (view->parent != NULL)
weston_view_destroy(view->view);
free(view);
}
void
weston_desktop_surface_destroy(struct weston_desktop_surface *surface)
{
struct weston_desktop_view *view, *next_view;
struct weston_desktop_surface *child, *next_child;
wl_list_remove(&surface->surface_commit_listener.link);
wl_list_remove(&surface->surface_destroy_listener.link);
wl_list_remove(&surface->client_destroy_listener.link);
if (!wl_list_empty(&surface->resource_list)) {
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe(resource, tmp, &surface->resource_list) {
wl_resource_set_user_data(resource, NULL);
wl_list_remove(wl_resource_get_link(resource));
}
}
surface->implementation->destroy(surface, surface->implementation_data);
surface->surface->committed = NULL;
surface->surface->committed_private = NULL;
weston_desktop_surface_unset_relative_to(surface);
wl_list_remove(&surface->client_link);
wl_list_for_each_safe(child, next_child,
&surface->children_list,
children_link)
weston_desktop_surface_unset_relative_to(child);
wl_list_for_each_safe(view, next_view, &surface->view_list, link)
weston_desktop_view_destroy(view);
free(surface->title);
free(surface->app_id);
free(surface);
}
static void
weston_desktop_surface_surface_committed(struct wl_listener *listener,
void *data)
{
struct weston_desktop_surface *surface =
wl_container_of(listener, surface, surface_commit_listener);
if (surface->implementation->committed != NULL)
surface->implementation->committed(surface,
surface->implementation_data,
surface->buffer_move.x,
surface->buffer_move.y);
if (surface->parent != NULL) {
struct weston_desktop_view *view;
wl_list_for_each(view, &surface->view_list, link) {
weston_view_set_transform_parent(view->view,
view->parent->view);
weston_desktop_view_propagate_layer(view->parent);
}
weston_desktop_surface_update_view_position(surface);
}
if (!wl_list_empty(&surface->children_list)) {
struct weston_desktop_surface *child;
wl_list_for_each(child, &surface->children_list, children_link)
weston_desktop_surface_update_view_position(child);
}
surface->buffer_move.x = 0;
surface->buffer_move.y = 0;
}
static void
weston_desktop_surface_surface_destroyed(struct wl_listener *listener,
void *data)
{
struct weston_desktop_surface *surface =
wl_container_of(listener, surface, surface_destroy_listener);
weston_desktop_surface_destroy(surface);
}
void
weston_desktop_surface_resource_destroy(struct wl_resource *resource)
{
struct weston_desktop_surface *surface =
wl_resource_get_user_data(resource);
if (surface != NULL)
weston_desktop_surface_destroy(surface);
}
static void
weston_desktop_surface_committed(struct weston_surface *wsurface,
int32_t sx, int32_t sy)
{
struct weston_desktop_surface *surface = wsurface->committed_private;
surface->buffer_move.x = sx;
surface->buffer_move.y = sy;
}
static void
weston_desktop_surface_client_destroyed(struct wl_listener *listener,
void *data)
{
struct weston_desktop_surface *surface =
wl_container_of(listener, surface, client_destroy_listener);
weston_desktop_surface_destroy(surface);
}
struct weston_desktop_surface *
weston_desktop_surface_create(struct weston_desktop *desktop,
struct weston_desktop_client *client,
struct weston_surface *wsurface,
const struct weston_desktop_surface_implementation *implementation,
void *implementation_data)
{
assert(implementation->destroy != NULL);
struct weston_desktop_surface *surface;
surface = zalloc(sizeof(struct weston_desktop_surface));
if (surface == NULL) {
if (client != NULL)
wl_client_post_no_memory(weston_desktop_client_get_client(client));
return NULL;
}
surface->desktop = desktop;
surface->implementation = implementation;
surface->implementation_data = implementation_data;
surface->surface = wsurface;
surface->client = client;
surface->client_destroy_listener.notify =
weston_desktop_surface_client_destroyed;
weston_desktop_client_add_destroy_listener(
client, &surface->client_destroy_listener);
wsurface->committed = weston_desktop_surface_committed;
wsurface->committed_private = surface;
surface->pid = -1;
surface->surface_commit_listener.notify =
weston_desktop_surface_surface_committed;
wl_signal_add(&surface->surface->commit_signal,
&surface->surface_commit_listener);
surface->surface_destroy_listener.notify =
weston_desktop_surface_surface_destroyed;
wl_signal_add(&surface->surface->destroy_signal,
&surface->surface_destroy_listener);
wl_list_init(&surface->client_link);
wl_list_init(&surface->resource_list);
wl_list_init(&surface->children_list);
wl_list_init(&surface->children_link);
wl_list_init(&surface->view_list);
wl_list_init(&surface->grab_link);
wl_signal_init(&surface->metadata_signal);
return surface;
}
struct wl_resource *
weston_desktop_surface_add_resource(struct weston_desktop_surface *surface,
const struct wl_interface *interface,
const void *implementation, uint32_t id,
wl_resource_destroy_func_t destroy)
{
struct wl_resource *client_resource =
weston_desktop_client_get_resource(surface->client);
struct wl_client *wl_client =
weston_desktop_client_get_client(surface->client);
struct wl_resource *resource;
resource = wl_resource_create(wl_client,
interface,
wl_resource_get_version(client_resource),
id);
if (resource == NULL) {
wl_client_post_no_memory(wl_client);
weston_desktop_surface_destroy(surface);
return NULL;
}
if (destroy == NULL)
destroy = weston_desktop_surface_resource_destroy;
wl_resource_set_implementation(resource, implementation, surface, destroy);
wl_list_insert(&surface->resource_list, wl_resource_get_link(resource));
return resource;
}
struct weston_desktop_surface *
weston_desktop_surface_from_grab_link(struct wl_list *grab_link)
{
struct weston_desktop_surface *surface =
wl_container_of(grab_link, surface, grab_link);
return surface;
}
WL_EXPORT bool
weston_surface_is_desktop_surface(struct weston_surface *wsurface)
{
return wsurface->committed == weston_desktop_surface_committed;
}
WL_EXPORT struct weston_desktop_surface *
weston_surface_get_desktop_surface(struct weston_surface *wsurface)
{
if (!weston_surface_is_desktop_surface(wsurface))
return NULL;
return wsurface->committed_private;
}
WL_EXPORT void
weston_desktop_surface_set_user_data(struct weston_desktop_surface *surface,
void *user_data)
{
surface->user_data = user_data;
}
static struct weston_desktop_view *
weston_desktop_surface_create_desktop_view(struct weston_desktop_surface *surface)
{
struct wl_client *wl_client=
weston_desktop_client_get_client(surface->client);
struct weston_desktop_view *view, *child_view;
struct weston_view *wview;
struct weston_desktop_surface *child;
wview = weston_view_create(surface->surface);
if (wview == NULL) {
if (wl_client != NULL)
wl_client_post_no_memory(wl_client);
return NULL;
}
view = zalloc(sizeof(struct weston_desktop_view));
if (view == NULL) {
if (wl_client != NULL)
wl_client_post_no_memory(wl_client);
return NULL;
}
view->view = wview;
wl_list_init(&view->children_list);
wl_list_init(&view->children_link);
wl_list_insert(surface->view_list.prev, &view->link);
wl_list_for_each(child, &surface->children_list, children_link) {
child_view =
weston_desktop_surface_create_desktop_view(child);
if (child_view == NULL) {
weston_desktop_view_destroy(view);
return NULL;
}
child_view->parent = view;
wl_list_insert(view->children_list.prev,
&child_view->children_link);
}
return view;
}
WL_EXPORT struct weston_view *
weston_desktop_surface_create_view(struct weston_desktop_surface *surface)
{
struct weston_desktop_view *view;
view = weston_desktop_surface_create_desktop_view(surface);
if (view == NULL)
return NULL;
return view->view;
}
WL_EXPORT void
weston_desktop_surface_unlink_view(struct weston_view *wview)
{
struct weston_desktop_surface *surface;
struct weston_desktop_view *view;
if (!weston_surface_is_desktop_surface(wview->surface))
return;
surface = weston_surface_get_desktop_surface(wview->surface);
wl_list_for_each(view, &surface->view_list, link) {
if (view->view == wview) {
weston_desktop_view_destroy(view);
return;
}
}
}
static void
weston_desktop_view_propagate_layer(struct weston_desktop_view *view)
{
struct weston_desktop_view *child;
struct wl_list *link = &view->view->layer_link.link;
wl_list_for_each_reverse(child, &view->children_list, children_link) {
struct weston_layer_entry *prev =
wl_container_of(link->prev, prev, link);
if (prev == &child->view->layer_link)
continue;
child->view->is_mapped = true;
weston_view_damage_below(child->view);
weston_view_geometry_dirty(child->view);
weston_layer_entry_remove(&child->view->layer_link);
weston_layer_entry_insert(prev, &child->view->layer_link);
weston_view_geometry_dirty(child->view);
weston_surface_damage(child->view->surface);
weston_view_update_transform(child->view);
weston_desktop_view_propagate_layer(child);
}
}
WL_EXPORT void
weston_desktop_surface_propagate_layer(struct weston_desktop_surface *surface)
{
struct weston_desktop_view *view;
wl_list_for_each(view, &surface->view_list, link)
weston_desktop_view_propagate_layer(view);
}
WL_EXPORT void
weston_desktop_surface_set_activated(struct weston_desktop_surface *surface, bool activated)
{
if (surface->implementation->set_activated != NULL)
surface->implementation->set_activated(surface,
surface->implementation_data,
activated);
}
WL_EXPORT void
weston_desktop_surface_set_fullscreen(struct weston_desktop_surface *surface, bool fullscreen)
{
if (surface->implementation->set_fullscreen != NULL)
surface->implementation->set_fullscreen(surface,
surface->implementation_data,
fullscreen);
}
WL_EXPORT void
weston_desktop_surface_set_maximized(struct weston_desktop_surface *surface, bool maximized)
{
if (surface->implementation->set_maximized != NULL)
surface->implementation->set_maximized(surface,
surface->implementation_data,
maximized);
}
WL_EXPORT void
weston_desktop_surface_set_resizing(struct weston_desktop_surface *surface, bool resizing)
{
if (surface->implementation->set_resizing != NULL)
surface->implementation->set_resizing(surface,
surface->implementation_data,
resizing);
}
WL_EXPORT void
weston_desktop_surface_set_size(struct weston_desktop_surface *surface, int32_t width, int32_t height)
{
if (surface->implementation->set_size != NULL)
surface->implementation->set_size(surface,
surface->implementation_data,
width, height);
}
WL_EXPORT void
weston_desktop_surface_set_orientation(struct weston_desktop_surface *surface,
enum weston_top_level_tiled_orientation tile_orientation)
{
if (surface->implementation->set_orientation != NULL)
surface->implementation->set_orientation(surface,
surface->implementation_data,
tile_orientation);
}
WL_EXPORT void
weston_desktop_surface_close(struct weston_desktop_surface *surface)
{
if (surface->implementation->close != NULL)
surface->implementation->close(surface,
surface->implementation_data);
}
WL_EXPORT void
weston_desktop_surface_add_metadata_listener(struct weston_desktop_surface *surface,
struct wl_listener *listener)
{
wl_signal_add(&surface->metadata_signal, listener);
}
struct weston_desktop_surface *
weston_desktop_surface_from_client_link(struct wl_list *link)
{
struct weston_desktop_surface *surface;
surface = wl_container_of(link, surface, client_link);
return surface;
}
struct wl_list *
weston_desktop_surface_get_client_link(struct weston_desktop_surface *surface)
{
return &surface->client_link;
}
bool
weston_desktop_surface_has_implementation(struct weston_desktop_surface *surface,
const struct weston_desktop_surface_implementation *implementation)
{
return surface->implementation == implementation;
}
const struct weston_desktop_surface_implementation *
weston_desktop_surface_get_implementation(struct weston_desktop_surface *surface)
{
return surface->implementation;
}
void *
weston_desktop_surface_get_implementation_data(struct weston_desktop_surface *surface)
{
return surface->implementation_data;
}
struct weston_desktop_surface *
weston_desktop_surface_get_parent(struct weston_desktop_surface *surface)
{
return surface->parent;
}
bool
weston_desktop_surface_get_grab(struct weston_desktop_surface *surface)
{
return !wl_list_empty(&surface->grab_link);
}
WL_EXPORT struct weston_desktop_client *
weston_desktop_surface_get_client(struct weston_desktop_surface *surface)
{
return surface->client;
}
WL_EXPORT void *
weston_desktop_surface_get_user_data(struct weston_desktop_surface *surface)
{
return surface->user_data;
}
WL_EXPORT struct weston_surface *
weston_desktop_surface_get_surface(struct weston_desktop_surface *surface)
{
return surface->surface;
}
WL_EXPORT const char *
weston_desktop_surface_get_title(struct weston_desktop_surface *surface)
{
return surface->title;
}
WL_EXPORT const char *
weston_desktop_surface_get_app_id(struct weston_desktop_surface *surface)
{
return surface->app_id;
}
WL_EXPORT pid_t
weston_desktop_surface_get_pid(struct weston_desktop_surface *surface)
{
pid_t pid;
if (surface->pid != -1) {
pid = surface->pid;
} else {
struct weston_desktop_client *client =
weston_desktop_surface_get_client(surface);
struct wl_client *wl_client =
weston_desktop_client_get_client(client);
/* wl_client should always be valid, because only in the
* xwayland case it wouldn't be, but in that case we won't
* reach here, as the pid is initialized to 0. */
assert(wl_client);
wl_client_get_credentials(wl_client, &pid, NULL, NULL);
}
return pid;
}
WL_EXPORT bool
weston_desktop_surface_get_activated(struct weston_desktop_surface *surface)
{
if (surface->implementation->get_activated == NULL)
return false;
return surface->implementation->get_activated(surface,
surface->implementation_data);
}
WL_EXPORT bool
weston_desktop_surface_get_resizing(struct weston_desktop_surface *surface)
{
if (surface->implementation->get_resizing == NULL)
return false;
return surface->implementation->get_resizing(surface,
surface->implementation_data);
}
WL_EXPORT bool
weston_desktop_surface_get_maximized(struct weston_desktop_surface *surface)
{
if (surface->implementation->get_maximized == NULL)
return false;
return surface->implementation->get_maximized(surface,
surface->implementation_data);
}
WL_EXPORT bool
weston_desktop_surface_get_fullscreen(struct weston_desktop_surface *surface)
{
if (surface->implementation->get_fullscreen == NULL)
return false;
return surface->implementation->get_fullscreen(surface,
surface->implementation_data);
}
WL_EXPORT struct weston_geometry
weston_desktop_surface_get_geometry(struct weston_desktop_surface *surface)
{
if (surface->has_geometry)
return surface->geometry;
return weston_surface_get_bounding_box(surface->surface);
}
WL_EXPORT struct weston_size
weston_desktop_surface_get_max_size(struct weston_desktop_surface *surface)
{
struct weston_size size = { 0, 0 };
if (surface->implementation->get_max_size == NULL)
return size;
return surface->implementation->get_max_size(surface,
surface->implementation_data);
}
WL_EXPORT struct weston_size
weston_desktop_surface_get_min_size(struct weston_desktop_surface *surface)
{
struct weston_size size = { 0, 0 };
if (surface->implementation->get_min_size == NULL)
return size;
return surface->implementation->get_min_size(surface,
surface->implementation_data);
}
void
weston_desktop_surface_set_title(struct weston_desktop_surface *surface,
const char *title)
{
char *tmp, *old;
tmp = strdup(title);
if (tmp == NULL)
return;
old = surface->title;
surface->title = tmp;
wl_signal_emit(&surface->metadata_signal, surface);
free(old);
}
void
weston_desktop_surface_set_app_id(struct weston_desktop_surface *surface,
const char *app_id)
{
char *tmp, *old;
tmp = strdup(app_id);
if (tmp == NULL)
return;
old = surface->app_id;
surface->app_id = tmp;
wl_signal_emit(&surface->metadata_signal, surface);
free(old);
}
void
weston_desktop_surface_set_pid(struct weston_desktop_surface *surface,
pid_t pid)
{
surface->pid = pid;
}
void
weston_desktop_surface_set_geometry(struct weston_desktop_surface *surface,
struct weston_geometry geometry)
{
surface->has_geometry = true;
surface->geometry = geometry;
}
void
weston_desktop_surface_set_relative_to(struct weston_desktop_surface *surface,
struct weston_desktop_surface *parent,
int32_t x, int32_t y, bool use_geometry)
{
struct weston_desktop_view *view, *parent_view;
struct wl_list *link, *tmp;
assert(parent);
surface->position.x = x;
surface->position.y = y;
surface->use_geometry = use_geometry;
if (surface->parent == parent)
return;
surface->parent = parent;
wl_list_remove(&surface->children_link);
wl_list_insert(surface->parent->children_list.prev,
&surface->children_link);
link = surface->view_list.next;
tmp = link->next;
wl_list_for_each(parent_view, &parent->view_list, link) {
if (link == &surface->view_list) {
view = weston_desktop_surface_create_desktop_view(surface);
if (view == NULL)
return;
tmp = &surface->view_list;
} else {
view = wl_container_of(link, view, link);
wl_list_remove(&view->children_link);
}
view->parent = parent_view;
wl_list_insert(parent_view->children_list.prev,
&view->children_link);
weston_desktop_view_propagate_layer(view);
link = tmp;
tmp = link->next;
}
for (; link != &surface->view_list; link = tmp, tmp = link->next) {
view = wl_container_of(link, view, link);
weston_desktop_view_destroy(view);
}
}
void
weston_desktop_surface_unset_relative_to(struct weston_desktop_surface *surface)
{
struct weston_desktop_view *view, *tmp;
if (surface->parent == NULL)
return;
surface->parent = NULL;
wl_list_remove(&surface->children_link);
wl_list_init(&surface->children_link);
wl_list_for_each_safe(view, tmp, &surface->view_list, link)
weston_desktop_view_destroy(view);
}
void
weston_desktop_surface_popup_grab(struct weston_desktop_surface *surface,
struct weston_desktop_seat *seat,
uint32_t serial)
{
struct wl_client *wl_client =
weston_desktop_client_get_client(surface->client);
if (weston_desktop_seat_popup_grab_start(seat, wl_client, serial))
weston_desktop_seat_popup_grab_add_surface(seat, &surface->grab_link);
else
weston_desktop_surface_popup_dismiss(surface);
}
void
weston_desktop_surface_popup_ungrab(struct weston_desktop_surface *surface,
struct weston_desktop_seat *seat)
{
weston_desktop_seat_popup_grab_remove_surface(seat, &surface->grab_link);
}
void
weston_desktop_surface_popup_dismiss(struct weston_desktop_surface *surface)
{
struct weston_desktop_view *view, *tmp;
wl_list_for_each_safe(view, tmp, &surface->view_list, link)
weston_desktop_view_destroy(view);
wl_list_remove(&surface->grab_link);
wl_list_init(&surface->grab_link);
weston_desktop_surface_close(surface);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+494
View File
@@ -0,0 +1,494 @@
/*
* Copyright © 2010-2012 Intel Corporation
* Copyright © 2011-2012 Collabora, Ltd.
* Copyright © 2013 Raspberry Pi Foundation
* Copyright © 2016 Quentin "Sardem FF7" Glidic
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <assert.h>
#include <wayland-server.h>
#include <libweston/libweston.h>
#include <libweston/zalloc.h>
#include <libweston-desktop/libweston-desktop.h>
#include "internal.h"
#include "xwayland/xwayland-internal-interface.h"
enum weston_desktop_xwayland_surface_state {
NONE,
TOPLEVEL,
MAXIMIZED,
FULLSCREEN,
TRANSIENT,
XWAYLAND,
};
struct weston_desktop_xwayland {
struct weston_desktop *desktop;
struct weston_desktop_client *client;
struct weston_layer layer;
};
struct weston_desktop_xwayland_surface {
struct weston_desktop_xwayland *xwayland;
struct weston_desktop *desktop;
struct weston_desktop_surface *surface;
struct wl_listener resource_destroy_listener;
struct weston_view *view;
const struct weston_xwayland_client_interface *client_interface;
struct weston_geometry next_geometry;
bool has_next_geometry;
bool committed;
bool added;
enum weston_desktop_xwayland_surface_state state;
enum weston_desktop_xwayland_surface_state prev_state;
};
static void
weston_desktop_xwayland_surface_change_state(struct weston_desktop_xwayland_surface *surface,
enum weston_desktop_xwayland_surface_state state,
struct weston_desktop_surface *parent,
int32_t x, int32_t y)
{
struct weston_surface *wsurface;
bool to_add = (parent == NULL && state != XWAYLAND);
assert(state != NONE);
assert(!parent || state == TRANSIENT);
if (to_add && surface->added) {
surface->state = state;
return;
}
wsurface = weston_desktop_surface_get_surface(surface->surface);
if (surface->state != state) {
if (surface->state == XWAYLAND) {
assert(!surface->added);
weston_desktop_surface_unlink_view(surface->view);
weston_view_destroy(surface->view);
surface->view = NULL;
weston_surface_unmap(wsurface);
}
if (to_add) {
weston_desktop_surface_unset_relative_to(surface->surface);
weston_desktop_api_surface_added(surface->desktop,
surface->surface);
surface->added = true;
if (surface->state == NONE && surface->committed)
/* We had a race, and wl_surface.commit() was
* faster, just fake a commit to map the
* surface */
weston_desktop_api_committed(surface->desktop,
surface->surface,
0, 0);
} else if (surface->added) {
weston_desktop_api_surface_removed(surface->desktop,
surface->surface);
surface->added = false;
}
if (state == XWAYLAND) {
assert(!surface->added);
surface->view =
weston_desktop_surface_create_view(surface->surface);
weston_layer_entry_insert(&surface->xwayland->layer.view_list,
&surface->view->layer_link);
surface->view->is_mapped = true;
weston_surface_map(wsurface);
}
surface->state = state;
}
if (parent != NULL)
weston_desktop_surface_set_relative_to(surface->surface, parent,
x, y, false);
}
static void
weston_desktop_xwayland_surface_committed(struct weston_desktop_surface *dsurface,
void *user_data,
int32_t sx, int32_t sy)
{
struct weston_desktop_xwayland_surface *surface = user_data;
struct weston_geometry oldgeom;
assert(dsurface == surface->surface);
surface->committed = true;
#ifdef WM_DEBUG
weston_log("%s: xwayland surface %p\n", __func__, surface);
#endif
if (surface->has_next_geometry) {
oldgeom = weston_desktop_surface_get_geometry(surface->surface);
/* If we're transitioning away from fullscreen or maximized
* we've moved to old saved co-ordinates that were saved
* with window geometry in place, so avoid adajusting by
* the geometry in those cases.
*/
if (surface->state == surface->prev_state) {
sx -= surface->next_geometry.x - oldgeom.x;
sy -= surface->next_geometry.y - oldgeom.y;
}
surface->prev_state = surface->state;
surface->has_next_geometry = false;
weston_desktop_surface_set_geometry(surface->surface,
surface->next_geometry);
}
if (surface->added)
weston_desktop_api_committed(surface->desktop, surface->surface,
sx, sy);
}
static void
weston_desktop_xwayland_surface_set_size(struct weston_desktop_surface *dsurface,
void *user_data,
int32_t width, int32_t height)
{
struct weston_desktop_xwayland_surface *surface = user_data;
struct weston_surface *wsurface =
weston_desktop_surface_get_surface(surface->surface);
surface->client_interface->send_configure(wsurface, width, height);
}
static void
weston_desktop_xwayland_surface_destroy(struct weston_desktop_surface *dsurface,
void *user_data)
{
struct weston_desktop_xwayland_surface *surface = user_data;
wl_list_remove(&surface->resource_destroy_listener.link);
weston_desktop_surface_unset_relative_to(surface->surface);
if (surface->added)
weston_desktop_api_surface_removed(surface->desktop,
surface->surface);
else if (surface->state == XWAYLAND)
weston_desktop_surface_unlink_view(surface->view);
free(surface);
}
static void
weston_desktop_xwayland_surface_close(struct weston_desktop_surface *dsurface,
void *user_data)
{
struct weston_desktop_xwayland_surface *surface = user_data;
struct weston_surface *wsurface =
weston_desktop_surface_get_surface(surface->surface);
surface->client_interface->send_close(wsurface);
}
static bool
weston_desktop_xwayland_surface_get_maximized(struct weston_desktop_surface *dsurface,
void *user_data)
{
struct weston_desktop_xwayland_surface *surface = user_data;
return surface->state == MAXIMIZED;
}
static bool
weston_desktop_xwayland_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
void *user_data)
{
struct weston_desktop_xwayland_surface *surface = user_data;
return surface->state == FULLSCREEN;
}
static const struct weston_desktop_surface_implementation weston_desktop_xwayland_surface_internal_implementation = {
.committed = weston_desktop_xwayland_surface_committed,
.set_size = weston_desktop_xwayland_surface_set_size,
.get_maximized = weston_desktop_xwayland_surface_get_maximized,
.get_fullscreen = weston_desktop_xwayland_surface_get_fullscreen,
.destroy = weston_desktop_xwayland_surface_destroy,
.close = weston_desktop_xwayland_surface_close,
};
static void
weston_destop_xwayland_resource_destroyed(struct wl_listener *listener,
void *data)
{
struct weston_desktop_xwayland_surface *surface =
wl_container_of(listener, surface, resource_destroy_listener);
weston_desktop_surface_destroy(surface->surface);
}
static struct weston_desktop_xwayland_surface *
create_surface(struct weston_desktop_xwayland *xwayland,
struct weston_surface *wsurface,
const struct weston_xwayland_client_interface *client_interface)
{
struct weston_desktop_xwayland_surface *surface;
surface = zalloc(sizeof(struct weston_desktop_xwayland_surface));
if (surface == NULL)
return NULL;
surface->xwayland = xwayland;
surface->desktop = xwayland->desktop;
surface->client_interface = client_interface;
surface->surface =
weston_desktop_surface_create(surface->desktop,
xwayland->client, wsurface,
&weston_desktop_xwayland_surface_internal_implementation,
surface);
if (surface->surface == NULL) {
free(surface);
return NULL;
}
surface->resource_destroy_listener.notify =
weston_destop_xwayland_resource_destroyed;
wl_resource_add_destroy_listener(wsurface->resource,
&surface->resource_destroy_listener);
weston_desktop_surface_set_pid(surface->surface, 0);
return surface;
}
static void
set_toplevel(struct weston_desktop_xwayland_surface *surface)
{
weston_desktop_xwayland_surface_change_state(surface, TOPLEVEL, NULL,
0, 0);
}
static void
set_toplevel_with_position(struct weston_desktop_xwayland_surface *surface,
int32_t x, int32_t y)
{
weston_desktop_xwayland_surface_change_state(surface, TOPLEVEL, NULL,
0, 0);
weston_desktop_api_set_xwayland_position(surface->desktop,
surface->surface, x, y);
}
static void
set_parent(struct weston_desktop_xwayland_surface *surface,
struct weston_surface *wparent)
{
struct weston_desktop_surface *parent;
if (!weston_surface_is_desktop_surface(wparent))
return;
parent = weston_surface_get_desktop_surface(wparent);
weston_desktop_api_set_parent(surface->desktop, surface->surface, parent);
}
static void
set_transient(struct weston_desktop_xwayland_surface *surface,
struct weston_surface *wparent, int x, int y)
{
struct weston_desktop_surface *parent;
if (!weston_surface_is_desktop_surface(wparent))
return;
parent = weston_surface_get_desktop_surface(wparent);
weston_desktop_xwayland_surface_change_state(surface, TRANSIENT, parent,
x, y);
}
static void
set_fullscreen(struct weston_desktop_xwayland_surface *surface,
struct weston_output *output)
{
weston_desktop_xwayland_surface_change_state(surface, FULLSCREEN, NULL,
0, 0);
weston_desktop_api_fullscreen_requested(surface->desktop,
surface->surface, true, output);
}
static void
set_xwayland(struct weston_desktop_xwayland_surface *surface, int x, int y)
{
weston_desktop_xwayland_surface_change_state(surface, XWAYLAND, NULL,
x, y);
weston_view_set_position(surface->view, x, y);
}
static int
move(struct weston_desktop_xwayland_surface *surface,
struct weston_pointer *pointer)
{
if (surface->state == TOPLEVEL ||
surface->state == MAXIMIZED ||
surface->state == FULLSCREEN)
weston_desktop_api_move(surface->desktop, surface->surface,
pointer->seat, pointer->grab_serial);
return 0;
}
static int
resize(struct weston_desktop_xwayland_surface *surface,
struct weston_pointer *pointer, uint32_t edges)
{
if (surface->state == TOPLEVEL ||
surface->state == MAXIMIZED ||
surface->state == FULLSCREEN)
weston_desktop_api_resize(surface->desktop, surface->surface,
pointer->seat, pointer->grab_serial,
edges);
return 0;
}
static void
set_title(struct weston_desktop_xwayland_surface *surface, const char *title)
{
weston_desktop_surface_set_title(surface->surface, title);
}
static void
set_window_geometry(struct weston_desktop_xwayland_surface *surface,
int32_t x, int32_t y, int32_t width, int32_t height)
{
surface->has_next_geometry = true;
surface->next_geometry.x = x;
surface->next_geometry.y = y;
surface->next_geometry.width = width;
surface->next_geometry.height = height;
}
static void
set_maximized(struct weston_desktop_xwayland_surface *surface)
{
weston_desktop_xwayland_surface_change_state(surface, MAXIMIZED, NULL,
0, 0);
weston_desktop_api_maximized_requested(surface->desktop,
surface->surface, true);
}
static void
set_minimized(struct weston_desktop_xwayland_surface *surface)
{
weston_desktop_api_minimized_requested(surface->desktop,
surface->surface);
}
static void
set_pid(struct weston_desktop_xwayland_surface *surface, pid_t pid)
{
weston_desktop_surface_set_pid(surface->surface, pid);
}
static void
get_position(struct weston_desktop_xwayland_surface *surface,
int32_t *x, int32_t *y)
{
if (!surface->surface) {
*x = 0;
*y = 0;
return;
}
weston_desktop_api_get_position(surface->desktop, surface->surface, x, y);
}
static const struct weston_desktop_xwayland_interface weston_desktop_xwayland_interface = {
.create_surface = create_surface,
.set_toplevel = set_toplevel,
.set_toplevel_with_position = set_toplevel_with_position,
.set_parent = set_parent,
.set_transient = set_transient,
.set_fullscreen = set_fullscreen,
.set_xwayland = set_xwayland,
.move = move,
.resize = resize,
.set_title = set_title,
.set_window_geometry = set_window_geometry,
.set_maximized = set_maximized,
.set_minimized = set_minimized,
.set_pid = set_pid,
.get_position = get_position,
};
void
weston_desktop_xwayland_init(struct weston_desktop *desktop)
{
struct weston_compositor *compositor = weston_desktop_get_compositor(desktop);
struct weston_desktop_xwayland *xwayland;
xwayland = zalloc(sizeof(struct weston_desktop_xwayland));
if (xwayland == NULL)
return;
xwayland->desktop = desktop;
xwayland->client = weston_desktop_client_create(desktop, NULL, NULL, NULL, NULL, 0, 0);
weston_layer_init(&xwayland->layer, compositor);
/* This is the layer we use for override redirect "windows", which
* ends up used for tooltips and drop down menus, among other things.
* Previously this was WESTON_LAYER_POSITION_NORMAL + 1, but this is
* below the fullscreen layer, so fullscreen apps would be above their
* menus and tooltips.
*
* Moving this to just below the TOP_UI layer ensures visibility at all
* times, with the minor drawback that they could be rendered above
* DESKTOP_UI.
*
* For tooltips with no transient window hints, this is probably the best
* we can do.
*/
weston_layer_set_position(&xwayland->layer,
WESTON_LAYER_POSITION_TOP_UI - 1);
compositor->xwayland = xwayland;
compositor->xwayland_interface = &weston_desktop_xwayland_interface;
}
void
weston_desktop_xwayland_fini(struct weston_desktop *desktop)
{
struct weston_compositor *compositor = weston_desktop_get_compositor(desktop);
struct weston_desktop_xwayland *xwayland;
xwayland = compositor->xwayland;
weston_desktop_client_destroy(xwayland->client);
weston_layer_fini(&xwayland->layer);
free(xwayland);
compositor->xwayland = NULL;
compositor->xwayland_interface = NULL;
}
+69 -9
View File
@@ -75,6 +75,15 @@ struct border {
enum motion_direction blocking_dir;
};
struct pending_touch {
struct weston_touch_device *touch_device;
bool pending_focus_touch_reset;
struct wl_list touch_link;
};
static struct wl_list pending_touch_list;
static void
maybe_warp_confined_pointer(struct weston_pointer_constraint *constraint);
@@ -143,6 +152,7 @@ weston_touch_create_touch_device(struct weston_touch *touch,
const struct weston_touch_device_ops *ops)
{
struct weston_touch_device *device;
struct pending_touch *pt;
assert(syspath);
if (ops) {
@@ -164,20 +174,55 @@ weston_touch_create_touch_device(struct weston_touch *touch,
return NULL;
}
pt = zalloc(sizeof(*pt));
if (!pt) {
free(device);
return NULL;
}
device->backend_data = backend_data;
device->ops = ops;
pt->touch_device = device;
pt->pending_focus_touch_reset = false;
device->aggregate = touch;
wl_list_insert(touch->device_list.prev, &device->link);
wl_list_insert(&pending_touch_list, &pt->touch_link);
return device;
}
static struct pending_touch *
weston_touch_get_pending(struct weston_touch_device *dev)
{
struct pending_touch *pt_iter = NULL;
struct pending_touch *pt = NULL;
wl_list_for_each(pt_iter, &pending_touch_list, touch_link) {
if (pt_iter->touch_device == dev) {
pt = pt_iter;
break;
}
}
return pt;
}
/** Destroy the touch device. */
WL_EXPORT void
weston_touch_device_destroy(struct weston_touch_device *device)
{
struct pending_touch *pt = NULL;
wl_list_remove(&device->link);
pt = weston_touch_get_pending(device);
assert(pt);
wl_list_remove(&pt->touch_link);
free(pt);
wl_signal_emit(&device->destroy_signal, device);
free(device->syspath);
free(device);
@@ -2197,12 +2242,6 @@ notify_key(struct weston_seat *seat, const struct timespec *time, uint32_t key,
struct weston_keyboard_grab *grab = keyboard->grab;
uint32_t *k, *end;
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
weston_compositor_idle_inhibit(compositor);
} else {
weston_compositor_idle_release(compositor);
}
end = keyboard->keys.data + keyboard->keys.size;
for (k = keyboard->keys.data; k < end; k++) {
if (*k == key) {
@@ -2218,6 +2257,12 @@ notify_key(struct weston_seat *seat, const struct timespec *time, uint32_t key,
*k = key;
}
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
weston_compositor_idle_inhibit(compositor);
} else {
weston_compositor_idle_release(compositor);
}
if (grab == &keyboard->default_grab ||
grab == &keyboard->input_method_grab) {
weston_compositor_run_key_binding(compositor, keyboard, time,
@@ -2329,6 +2374,7 @@ notify_keyboard_focus_out(struct weston_seat *seat)
if (focus) {
seat->use_saved_kbd_focus = true;
seat->saved_kbd_focus = focus;
assert(seat->saved_kbd_focus_listener.notify == NULL);
seat->saved_kbd_focus_listener.notify =
destroy_device_saved_kbd_focus;
wl_signal_add(&focus->destroy_signal,
@@ -2387,6 +2433,7 @@ process_touch_normal(struct weston_touch_device *device,
struct weston_touch_grab *grab = device->aggregate->grab;
struct weston_compositor *ec = device->aggregate->seat->compositor;
struct weston_view *ev;
struct pending_touch *pt = NULL;
wl_fixed_t sx, sy;
wl_fixed_t x = wl_fixed_from_double(double_x);
wl_fixed_t y = wl_fixed_from_double(double_y);
@@ -2437,8 +2484,9 @@ process_touch_normal(struct weston_touch_device *device,
break;
case WL_TOUCH_UP:
grab->interface->up(grab, time, touch_id);
if (touch->num_tp == 0)
weston_touch_set_focus(touch, NULL);
pt = weston_touch_get_pending(device);
assert(pt);
pt->pending_focus_touch_reset = true;
break;
}
}
@@ -2627,12 +2675,22 @@ WL_EXPORT void
notify_touch_frame(struct weston_touch_device *device)
{
struct weston_touch_grab *grab;
struct pending_touch *pt;
switch (weston_touch_device_get_mode(device)) {
case WESTON_TOUCH_MODE_NORMAL:
case WESTON_TOUCH_MODE_PREP_CALIB:
grab = device->aggregate->grab;
grab->interface->frame(grab);
pt = weston_touch_get_pending(device);
assert(pt);
if (pt->pending_focus_touch_reset) {
if (grab->touch->num_tp == 0)
weston_touch_set_focus(grab->touch, NULL);
pt->pending_focus_touch_reset = false;
}
break;
case WESTON_TOUCH_MODE_CALIB:
case WESTON_TOUCH_MODE_PREP_NORMAL:
@@ -2697,7 +2755,7 @@ pointer_cursor_surface_committed(struct weston_surface *es,
weston_layer_entry_insert(&es->compositor->cursor_layer.view_list,
&pointer->sprite->layer_link);
weston_view_update_transform(pointer->sprite);
es->is_mapped = true;
weston_surface_map(es);
pointer->sprite->is_mapped = true;
}
}
@@ -5058,6 +5116,8 @@ bind_input_timestamps_manager(struct wl_client *client, void *data,
int
weston_input_init(struct weston_compositor *compositor)
{
wl_list_init(&pending_touch_list);
if (!wl_global_create(compositor->wl_display,
&zwp_relative_pointer_manager_v1_interface, 1,
compositor, bind_relative_pointer_manager))
-370
View File
@@ -1,370 +0,0 @@
/*
* Copyright © 2012 Benjamin Franzke
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <libweston/libweston.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/vt.h>
#include <linux/kd.h>
#include <linux/major.h>
#include "launcher-impl.h"
#define DRM_MAJOR 226
#ifndef KDSKBMUTE
#define KDSKBMUTE 0x4B51
#endif
/* major()/minor() */
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#endif
#ifdef MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#endif
#ifdef BUILD_DRM_COMPOSITOR
#include <xf86drm.h>
static inline int
is_drm_master(int drm_fd)
{
drm_magic_t magic;
return drmGetMagic(drm_fd, &magic) == 0 &&
drmAuthMagic(drm_fd, magic) == 0;
}
#else
static inline int
drmDropMaster(int drm_fd)
{
return 0;
}
static inline int
drmSetMaster(int drm_fd)
{
return 0;
}
static inline int
is_drm_master(int drm_fd)
{
return 0;
}
#endif
struct launcher_direct {
struct weston_launcher base;
struct weston_compositor *compositor;
int kb_mode, tty, drm_fd;
struct wl_event_source *vt_source;
};
static int
vt_handler(int signal_number, void *data)
{
struct launcher_direct *launcher = data;
struct weston_compositor *compositor = launcher->compositor;
if (compositor->session_active) {
compositor->session_active = false;
wl_signal_emit(&compositor->session_signal, compositor);
drmDropMaster(launcher->drm_fd);
ioctl(launcher->tty, VT_RELDISP, 1);
} else {
ioctl(launcher->tty, VT_RELDISP, VT_ACKACQ);
drmSetMaster(launcher->drm_fd);
compositor->session_active = true;
wl_signal_emit(&compositor->session_signal, compositor);
}
return 1;
}
static int
setup_tty(struct launcher_direct *launcher, int tty)
{
struct wl_event_loop *loop;
struct vt_mode mode = { 0 };
struct stat buf;
char tty_device[32] ="<stdin>";
int ret, kd_mode;
if (geteuid() != 0)
return -1;
if (tty == 0) {
launcher->tty = dup(tty);
if (launcher->tty == -1) {
weston_log("couldn't dup stdin: %s\n",
strerror(errno));
return -1;
}
} else {
snprintf(tty_device, sizeof tty_device, "/dev/tty%d", tty);
launcher->tty = open(tty_device, O_RDWR | O_CLOEXEC);
if (launcher->tty == -1) {
weston_log("couldn't open tty %s: %s\n", tty_device,
strerror(errno));
return -1;
}
}
if (fstat(launcher->tty, &buf) == -1 ||
major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0) {
weston_log("%s not a vt\n", tty_device);
weston_log("if running weston from ssh, "
"use --tty to specify a tty\n");
goto err_close;
}
ret = ioctl(launcher->tty, KDGETMODE, &kd_mode);
if (ret) {
weston_log("failed to get VT mode: %s\n", strerror(errno));
return -1;
}
if (kd_mode != KD_TEXT) {
weston_log("%s is already in graphics mode, "
"is another display server running?\n", tty_device);
}
ioctl(launcher->tty, VT_ACTIVATE, minor(buf.st_rdev));
ioctl(launcher->tty, VT_WAITACTIVE, minor(buf.st_rdev));
if (ioctl(launcher->tty, KDGKBMODE, &launcher->kb_mode)) {
weston_log("failed to read keyboard mode: %s\n",
strerror(errno));
goto err_close;
}
if (ioctl(launcher->tty, KDSKBMUTE, 1) &&
ioctl(launcher->tty, KDSKBMODE, K_OFF)) {
weston_log("failed to set K_OFF keyboard mode: %s\n",
strerror(errno));
goto err_close;
}
ret = ioctl(launcher->tty, KDSETMODE, KD_GRAPHICS);
if (ret) {
weston_log("failed to set KD_GRAPHICS mode on tty: %s\n",
strerror(errno));
goto err_close;
}
/*
* SIGRTMIN is used as global VT-acquire+release signal. Note that
* SIGRT* must be tested on runtime, as their exact values are not
* known at compile-time. POSIX requires 32 of them to be available.
*/
if (SIGRTMIN > SIGRTMAX) {
weston_log("not enough RT signals available: %u-%u\n",
SIGRTMIN, SIGRTMAX);
ret = -EINVAL;
goto err_close;
}
mode.mode = VT_PROCESS;
mode.relsig = SIGRTMIN;
mode.acqsig = SIGRTMIN;
if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0) {
weston_log("failed to take control of vt handling\n");
goto err_close;
}
loop = wl_display_get_event_loop(launcher->compositor->wl_display);
launcher->vt_source =
wl_event_loop_add_signal(loop, SIGRTMIN, vt_handler, launcher);
if (!launcher->vt_source) {
weston_log("failed to add SIGRTMIN signal\n");
goto err_close;
}
return 0;
err_close:
close(launcher->tty);
return -1;
}
static int
launcher_direct_open(struct weston_launcher *launcher_base, const char *path, int flags)
{
struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
struct stat s;
int fd;
fd = open(path, flags | O_CLOEXEC);
if (fd == -1) {
weston_log("couldn't open: %s! error=%s\n", path, strerror(errno));
return -1;
}
if (geteuid() != 0) {
weston_log("WARNING! Succeeded opening %s as non-root user."
" This implies your device can be spied on.\n",
path);
}
if (fstat(fd, &s) == -1) {
weston_log("couldn't fstat: %s! error=%s\n", path, strerror(errno));
close(fd);
return -1;
}
if (major(s.st_rdev) == DRM_MAJOR) {
launcher->drm_fd = fd;
if (!is_drm_master(fd)) {
weston_log("drm fd not master\n");
close(fd);
return -1;
}
}
return fd;
}
static void
launcher_direct_close(struct weston_launcher *launcher_base, int fd)
{
close(fd);
}
static void
launcher_direct_restore(struct weston_launcher *launcher_base)
{
struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
struct vt_mode mode = { 0 };
if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
weston_log("failed to restore kb mode: %s\n",
strerror(errno));
if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
weston_log("failed to set KD_TEXT mode on tty: %s\n",
strerror(errno));
/* We have to drop master before we switch the VT back in
* VT_AUTO, so we don't risk switching to a VT with another
* display server, that will then fail to set drm master. */
drmDropMaster(launcher->drm_fd);
mode.mode = VT_AUTO;
if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
weston_log("could not reset vt handling! error=%s\n",
strerror(errno));
}
static int
launcher_direct_activate_vt(struct weston_launcher *launcher_base, int vt)
{
struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
return ioctl(launcher->tty, VT_ACTIVATE, vt);
}
static int
launcher_direct_connect(struct weston_launcher **out, struct weston_compositor *compositor,
int tty, const char *seat_id, bool sync_drm)
{
struct launcher_direct *launcher;
struct stat buf;
launcher = zalloc(sizeof(*launcher));
if (launcher == NULL) {
weston_log("failed to alloc for launcher\n");
return -ENOMEM;
}
launcher->base.iface = &launcher_direct_iface;
launcher->compositor = compositor;
/* Checking the existance of /dev/tty0 and verifying it's a TTY
* device, as kernels compiled with CONFIG_VT=0 do not create these
* devices. */
if (stat("/dev/tty0", &buf) == 0 &&
strcmp("seat0", seat_id) == 0 && major(buf.st_rdev) == TTY_MAJOR) {
if (setup_tty(launcher, tty) == -1) {
free(launcher);
return -1;
}
} else {
launcher->tty = -1;
}
* (struct launcher_direct **) out = launcher;
return 0;
}
static void
launcher_direct_destroy(struct weston_launcher *launcher_base)
{
struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
if (launcher->tty >= 0) {
launcher_direct_restore(&launcher->base);
wl_event_source_remove(launcher->vt_source);
close(launcher->tty);
}
free(launcher);
}
static int
launcher_direct_get_vt(struct weston_launcher *base)
{
struct launcher_direct *launcher = wl_container_of(base, launcher, base);
struct stat s;
if (fstat(launcher->tty, &s) < 0) {
weston_log("couldn't fstat launcher tty: %s\n", strerror(errno));
return -1;
}
return minor(s.st_rdev);
}
const struct launcher_interface launcher_direct_iface = {
.name = "direct",
.connect = launcher_direct_connect,
.destroy = launcher_direct_destroy,
.open = launcher_direct_open,
.close = launcher_direct_close,
.activate_vt = launcher_direct_activate_vt,
.get_vt = launcher_direct_get_vt,
};
+1 -3
View File
@@ -32,7 +32,7 @@ struct weston_launcher;
struct launcher_interface {
char *name;
int (* connect) (struct weston_launcher **launcher_out, struct weston_compositor *compositor,
int tty, const char *seat_id, bool sync_drm);
const char *seat_id, bool sync_drm);
void (* destroy) (struct weston_launcher *launcher);
int (* open) (struct weston_launcher *launcher, const char *path, int flags);
void (* close) (struct weston_launcher *launcher, int fd);
@@ -47,5 +47,3 @@ struct weston_launcher {
extern const struct launcher_interface launcher_libseat_iface;
extern const struct launcher_interface launcher_logind_iface;
extern const struct launcher_interface launcher_weston_launch_iface;
extern const struct launcher_interface launcher_direct_iface;
+57 -1
View File
@@ -32,6 +32,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
@@ -40,6 +41,8 @@
#include <libseat.h>
#include <libweston/libweston.h>
#include <libweston/weston-log.h>
#include "weston-log-internal.h"
#include "backend.h"
#include "dbus.h"
#include "launcher-impl.h"
@@ -60,6 +63,11 @@ struct launcher_libseat {
struct wl_list devices;
};
/* debug messages go into a dedicated libseat-debug scope, while info and err
* log level messages go into the log_scope, which the compositor has a
* subscription by default*/
static struct weston_log_scope *libseat_debug_scope = NULL;
static struct launcher_libseat_device *
find_device_by_fd(struct launcher_libseat *wl, int fd)
{
@@ -179,9 +187,47 @@ libseat_event(int fd, uint32_t mask, void *data)
return 1;
}
static void
log_libseat_info_err(const char *fmt, va_list ap)
{
/* these all have been set-up by the compositor and use the 'log' scope */
weston_vlog(fmt, ap);
weston_log_continue("\n");
}
static void
log_libseat_debug(const char *fmt, va_list ap)
{
int len_va;
char *str;
const char *oom = "Out of memory";
if (!weston_log_scope_is_enabled(libseat_debug_scope))
return;
len_va = vasprintf(&str, fmt, ap);
if (len_va >= 0) {
weston_log_scope_printf(libseat_debug_scope, "%s\n", str);
free(str);
} else {
weston_log_scope_printf(libseat_debug_scope, "%s\n", oom);
}
}
static void log_libseat(enum libseat_log_level level,
const char *fmt, va_list ap)
{
if (level == LIBSEAT_LOG_LEVEL_DEBUG) {
log_libseat_debug(fmt, ap);
return;
}
log_libseat_info_err(fmt, ap);
}
static int
seat_open(struct weston_launcher **out, struct weston_compositor *compositor,
int tty, const char *seat_id, bool sync_drm)
const char *seat_id, bool sync_drm)
{
struct launcher_libseat *wl;
struct wl_event_loop *event_loop;
@@ -195,6 +241,13 @@ seat_open(struct weston_launcher **out, struct weston_compositor *compositor,
wl->compositor = compositor;
wl_list_init(&wl->devices);
libseat_debug_scope = compositor->libseat_debug;
assert(libseat_debug_scope);
libseat_set_log_handler(log_libseat);
/* includes (all) other log levels available <= LOG_LEVEL_DEBUG */
libseat_set_log_level(LIBSEAT_LOG_LEVEL_DEBUG);
wl->seat = libseat_open_seat(&seat_listener, wl);
if (wl->seat == NULL) {
weston_log("libseat: could not open seat\n");
@@ -231,6 +284,9 @@ seat_close(struct weston_launcher *launcher)
{
struct launcher_libseat *wl = wl_container_of(launcher, wl, base);
libseat_debug_scope = NULL;
libseat_set_log_handler(NULL);
if (wl->seat != NULL) {
libseat_close_seat(wl->seat);
}
+2 -33
View File
@@ -695,29 +695,6 @@ launcher_logind_release_control(struct launcher_logind *wl)
}
}
static int
weston_sd_session_get_vt(const char *sid, unsigned int *out)
{
#ifdef HAVE_SYSTEMD_LOGIN_209
return sd_session_get_vt(sid, out);
#else
int r;
char *tty;
r = sd_session_get_tty(sid, &tty);
if (r < 0)
return r;
r = sscanf(tty, "tty%u", out);
free(tty);
if (r != 1)
return -EINVAL;
return 0;
#endif
}
static int
launcher_logind_activate(struct launcher_logind *wl)
{
@@ -759,7 +736,7 @@ launcher_logind_get_session(char **session)
static int
launcher_logind_connect(struct weston_launcher **out, struct weston_compositor *compositor,
int tty, const char *seat_id, bool sync_drm)
const char *seat_id, bool sync_drm)
{
struct launcher_logind *wl;
struct wl_event_loop *loop;
@@ -803,15 +780,10 @@ launcher_logind_connect(struct weston_launcher **out, struct weston_compositor *
r = sd_seat_can_tty(t);
free(t);
if (r > 0) {
r = weston_sd_session_get_vt(wl->sid, &wl->vtnr);
r = sd_session_get_vt(wl->sid, &wl->vtnr);
if (r < 0) {
weston_log("logind: session not running on a VT\n");
goto err_session;
} else if (tty > 0 && wl->vtnr != (unsigned int )tty) {
weston_log("logind: requested VT --tty=%d differs from real session VT %u\n",
tty, wl->vtnr);
r = -EINVAL;
goto err_session;
}
} else if (r < 0) {
weston_log("logind: could not determine if seat %s has ttys or not", t);
@@ -881,9 +853,6 @@ static int
launcher_logind_get_vt(struct weston_launcher *launcher)
{
struct launcher_logind *wl = wl_container_of(launcher, wl, base);
if (wl->vtnr <= 0) {
return -EINVAL;
}
return wl->vtnr;
}
+2 -4
View File
@@ -43,13 +43,11 @@ static const struct launcher_interface *ifaces[] = {
#ifdef HAVE_SYSTEMD_LOGIN
&launcher_logind_iface,
#endif
&launcher_weston_launch_iface,
&launcher_direct_iface,
NULL,
};
WL_EXPORT struct weston_launcher *
weston_launcher_connect(struct weston_compositor *compositor, int tty,
weston_launcher_connect(struct weston_compositor *compositor,
const char *seat_id, bool sync_drm)
{
const struct launcher_interface **it;
@@ -59,7 +57,7 @@ weston_launcher_connect(struct weston_compositor *compositor, int tty,
struct weston_launcher *launcher;
weston_log("Trying %s launcher...\n", iface->name);
if (iface->connect(&launcher, compositor, tty, seat_id, sync_drm) == 0)
if (iface->connect(&launcher, compositor, seat_id, sync_drm) == 0)
return launcher;
}
+1 -1
View File
@@ -33,7 +33,7 @@
struct weston_launcher;
struct weston_launcher *
weston_launcher_connect(struct weston_compositor *compositor, int tty,
weston_launcher_connect(struct weston_compositor *compositor,
const char *seat_id, bool sync_drm);
void
-396
View File
@@ -1,396 +0,0 @@
/*
* Copyright © 2012 Benjamin Franzke
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/vt.h>
#include <linux/kd.h>
#include <linux/major.h>
#include <libweston/libweston.h>
#include "weston-launch.h"
#include "launcher-impl.h"
#include "shared/string-helpers.h"
#define DRM_MAJOR 226
#ifndef KDSKBMUTE
#define KDSKBMUTE 0x4B51
#endif
#ifdef BUILD_DRM_COMPOSITOR
#include <xf86drm.h>
#else
static inline int
drmDropMaster(int drm_fd)
{
return 0;
}
static inline int
drmSetMaster(int drm_fd)
{
return 0;
}
#endif
/* major()/minor() */
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#endif
#ifdef MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#endif
union cmsg_data { unsigned char b[4]; int fd; };
struct launcher_weston_launch {
struct weston_launcher base;
struct weston_compositor *compositor;
int fd;
struct wl_event_source *source;
int kb_mode, tty, drm_fd;
int deferred_deactivate;
};
static ssize_t
launcher_weston_launch_send(int sockfd, void *buf, size_t buflen)
{
ssize_t len;
do {
len = send(sockfd, buf, buflen, 0);
} while (len < 0 && errno == EINTR);
return len;
}
static void
handle_deactivate(struct launcher_weston_launch *launcher)
{
int reply;
launcher->compositor->session_active = false;
wl_signal_emit(&launcher->compositor->session_signal,
launcher->compositor);
reply = WESTON_LAUNCHER_DEACTIVATE_DONE;
launcher_weston_launch_send(launcher->fd, &reply, sizeof reply);
}
static void
idle_deactivate(void *data)
{
struct launcher_weston_launch *launcher = data;
if (launcher->deferred_deactivate) {
launcher->deferred_deactivate = 0;
handle_deactivate((struct launcher_weston_launch*)data);
}
}
static int
launcher_weston_launch_open(struct weston_launcher *launcher_base,
const char *path, int flags)
{
struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
int n;
struct msghdr msg;
struct cmsghdr *cmsg;
struct iovec iov;
union cmsg_data *data;
char control[CMSG_SPACE(sizeof data->fd)];
ssize_t len;
struct weston_launcher_open *message;
struct { int id; int ret; } event;
n = sizeof(*message) + strlen(path) + 1;
message = malloc(n);
if (!message)
return -1;
message->header.opcode = WESTON_LAUNCHER_OPEN;
message->flags = flags;
strcpy(message->path, path);
launcher_weston_launch_send(launcher->fd, message, n);
free(message);
memset(&msg, 0, sizeof msg);
iov.iov_base = &event;
iov.iov_len = sizeof event;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
while (1) {
msg.msg_controllen = sizeof control;
do {
len = recvmsg(launcher->fd, &msg, MSG_CMSG_CLOEXEC);
} while (len < 0 && errno == EINTR);
// Only OPEN_REPLY and up to one DEACTIVATE message should be possible here
if ((len == sizeof event) && (event.id == WESTON_LAUNCHER_OPEN_REPLY))
break;
if ((len == sizeof event.id) && (event.id == WESTON_LAUNCHER_DEACTIVATE) && (launcher->deferred_deactivate == 0)) {
wl_event_loop_add_idle(wl_display_get_event_loop(launcher->compositor->wl_display), idle_deactivate, launcher);
launcher->deferred_deactivate = 1;
} else {
weston_log("unexpected event %d (len=%zd) from weston-launch\n", event.id, len);
return -1;
}
}
if (event.ret < 0)
return -1;
cmsg = CMSG_FIRSTHDR(&msg);
if (!cmsg ||
cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS) {
fprintf(stderr, "invalid control message\n");
return -1;
}
data = (union cmsg_data *) CMSG_DATA(cmsg);
if (data->fd == -1) {
fprintf(stderr, "missing drm fd in socket request\n");
return -1;
}
return data->fd;
}
static void
launcher_weston_launch_close(struct weston_launcher *launcher_base, int fd)
{
close(fd);
}
static void
launcher_weston_launch_restore(struct weston_launcher *launcher_base)
{
struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
struct vt_mode mode = { 0 };
if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
weston_log("failed to restore kb mode: %s\n",
strerror(errno));
if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
weston_log("failed to set KD_TEXT mode on tty: %s\n",
strerror(errno));
/* We have to drop master before we switch the VT back in
* VT_AUTO, so we don't risk switching to a VT with another
* display server, that will then fail to set drm master. */
drmDropMaster(launcher->drm_fd);
mode.mode = VT_AUTO;
if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
weston_log("could not reset vt handling\n");
}
static int
launcher_weston_launch_data(int fd, uint32_t mask, void *data)
{
struct launcher_weston_launch *launcher = data;
int len, ret;
if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
weston_log("launcher socket closed, exiting\n");
/* Normally the weston-launch will reset the tty, but
* in this case it died or something, so do it here so
* we don't end up with a stuck vt. */
launcher_weston_launch_restore(&launcher->base);
exit(-1);
}
if (launcher->deferred_deactivate) {
launcher->deferred_deactivate = 0;
handle_deactivate(launcher);
return 1;
}
do {
len = recv(launcher->fd, &ret, sizeof ret, 0);
} while (len < 0 && errno == EINTR);
switch (ret) {
case WESTON_LAUNCHER_ACTIVATE:
launcher->compositor->session_active = true;
wl_signal_emit(&launcher->compositor->session_signal,
launcher->compositor);
break;
case WESTON_LAUNCHER_DEACTIVATE:
handle_deactivate(launcher);
break;
default:
weston_log("unexpected event from weston-launch\n");
break;
}
return 1;
}
static int
launcher_weston_launch_activate_vt(struct weston_launcher *launcher_base, int vt)
{
struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
return ioctl(launcher->tty, VT_ACTIVATE, vt);
}
static int
launcher_weston_environment_get_fd(const char *env)
{
char *e;
int fd, flags;
e = getenv(env);
if (!e || !safe_strtoint(e, &fd)) {
weston_log("could not get launcher fd from env\n");
return -1;
}
flags = fcntl(fd, F_GETFD);
if (flags == -1) {
weston_log("could not get fd flags!, env: %s, error: %s\n",
env, strerror(errno));
return -1;
}
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
unsetenv(env);
return fd;
}
static int
launcher_weston_launch_connect(struct weston_launcher **out, struct weston_compositor *compositor,
int tty, const char *seat_id, bool sync_drm)
{
struct launcher_weston_launch *launcher;
struct wl_event_loop *loop;
launcher = malloc(sizeof *launcher);
if (launcher == NULL)
return -ENOMEM;
launcher->base.iface = &launcher_weston_launch_iface;
launcher->compositor = compositor;
launcher->drm_fd = -1;
launcher->deferred_deactivate = 0;
launcher->fd = launcher_weston_environment_get_fd("WESTON_LAUNCHER_SOCK");
if (launcher->fd == -1) {
free(launcher);
return -1;
}
launcher->tty = launcher_weston_environment_get_fd("WESTON_TTY_FD");
/* We don't get a chance to read out the original kb
* mode for the tty, so just hard code K_UNICODE here
* in case we have to clean if weston-launch dies. */
launcher->kb_mode = K_UNICODE;
loop = wl_display_get_event_loop(compositor->wl_display);
launcher->source = wl_event_loop_add_fd(loop, launcher->fd,
WL_EVENT_READABLE,
launcher_weston_launch_data,
launcher);
if (launcher->source == NULL) {
free(launcher);
weston_log("failed to get weston-launcher socket fd event source\n");
return -ENOMEM;
}
* (struct launcher_weston_launch **) out = launcher;
return 0;
}
static void
launcher_weston_launch_destroy(struct weston_launcher *launcher_base)
{
struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
if (launcher->fd != -1) {
close(launcher->fd);
wl_event_source_remove(launcher->source);
} else {
launcher_weston_launch_restore(&launcher->base);
}
if (launcher->tty >= 0)
close(launcher->tty);
free(launcher);
}
static int
launcher_weston_launch_get_vt(struct weston_launcher *base)
{
struct launcher_weston_launch *launcher = wl_container_of(base, launcher, base);
struct stat s;
if (fstat(launcher->tty, &s) < 0) {
weston_log("could not fstat launcher tty: %s\n", strerror(errno));
return -1;
}
return minor(s.st_rdev);
}
const struct launcher_interface launcher_weston_launch_iface = {
.name = "weston_launch",
.connect = launcher_weston_launch_connect,
.destroy = launcher_weston_launch_destroy,
.open = launcher_weston_launch_open,
.close = launcher_weston_launch_close,
.activate_vt = launcher_weston_launch_activate_vt,
.get_vt = launcher_weston_launch_get_vt,
};
+40 -1
View File
@@ -43,6 +43,37 @@
#include <libweston/libweston.h>
#include "color.h"
/* compositor <-> renderer interface */
struct weston_renderer {
int (*read_pixels)(struct weston_output *output,
const struct pixel_format_info *format, void *pixels,
uint32_t x, uint32_t y,
uint32_t width, uint32_t height);
void (*repaint_output)(struct weston_output *output,
pixman_region32_t *output_damage);
void (*flush_damage)(struct weston_surface *surface,
struct weston_buffer *buffer);
void (*attach)(struct weston_surface *es, struct weston_buffer *buffer);
void (*destroy)(struct weston_compositor *ec);
/** See weston_surface_copy_content() */
int (*surface_copy_content)(struct weston_surface *surface,
void *target, size_t size,
int src_x, int src_y,
int width, int height);
/** See weston_compositor_import_dmabuf() */
bool (*import_dmabuf)(struct weston_compositor *ec,
struct linux_dmabuf_buffer *buffer);
const struct weston_drm_format_array *
(*get_supported_formats)(struct weston_compositor *ec);
bool (*fill_buffer_info)(struct weston_compositor *ec,
struct weston_buffer *buffer);
};
/* weston_buffer */
void
@@ -50,7 +81,8 @@ weston_buffer_send_server_error(struct weston_buffer *buffer,
const char *msg);
void
weston_buffer_reference(struct weston_buffer_reference *ref,
struct weston_buffer *buffer);
struct weston_buffer *buffer,
enum weston_buffer_reference_type type);
void
weston_buffer_release_move(struct weston_buffer_release_reference *dest,
@@ -389,6 +421,8 @@ const uint64_t *
weston_drm_format_get_modifiers(const struct weston_drm_format *format,
unsigned int *count_out);
void
weston_compositor_destroy_touch_calibrator(struct weston_compositor *compositor);
/**
* paint node
*
@@ -428,4 +462,9 @@ weston_view_find_paint_node(struct weston_view *view,
int
wl_data_device_manager_init(struct wl_display *display);
/* Exclusively for unit tests */
bool
weston_output_set_color_outcome(struct weston_output *output);
#endif
+1
View File
@@ -35,6 +35,7 @@
#include <libweston/libweston.h>
#include "linux-dmabuf.h"
#include "linux-dmabuf-unstable-v1-server-protocol.h"
#include "shared/os-compatibility.h"
#include "libweston-internal.h"
#include "shared/weston-drm-fourcc.h"
-1
View File
@@ -27,7 +27,6 @@
#define WESTON_LINUX_DMABUF_H
#include <stdint.h>
#include "linux-dmabuf-unstable-v1-server-protocol.h"
#define MAX_DMABUF_PLANES 4
+20 -30
View File
@@ -35,7 +35,6 @@ srcs_libweston = [
'weston-log-flight-rec.c',
'weston-log.c',
'weston-direct-display.c',
'zoom.c',
linux_dmabuf_unstable_v1_protocol_c,
linux_dmabuf_unstable_v1_server_protocol_h,
linux_explicit_synchronization_unstable_v1_protocol_c,
@@ -52,6 +51,8 @@ srcs_libweston = [
relative_pointer_unstable_v1_server_protocol_h,
weston_screenshooter_protocol_c,
weston_screenshooter_server_protocol_h,
single_pixel_buffer_v1_protocol_c,
single_pixel_buffer_v1_server_protocol_h,
text_cursor_position_protocol_c,
text_cursor_position_server_protocol_h,
text_input_unstable_v1_protocol_c,
@@ -70,6 +71,8 @@ srcs_libweston = [
weston_direct_display_server_protocol_h,
]
subdir('desktop')
if get_option('renderer-gl')
dep_egl = dependency('egl', required: false)
if not dep_egl.found()
@@ -131,6 +134,20 @@ pkgconfig.generate(
subdirs: dir_include_libweston
)
if version_weston.version_compare('>= 11.0.90')
error('Remove libweston-desktop.pc for Weston 12.x')
endif
pkgconfig.generate(
lib_weston,
filebase: 'libweston-desktop-@0@'.format(libweston_major),
name: 'libweston-desktop',
version: version_weston,
description: 'Desktop shell abstraction library for libweston compositors',
requires_private: deps_for_libweston_users,
subdirs: dir_include_libweston
)
pkgconfig.generate(
filebase: 'libweston-@0@-protocols'.format(libweston_major),
name: 'libWeston Protocols',
@@ -144,9 +161,7 @@ pkgconfig.generate(
)
srcs_session_helper = [
'launcher-direct.c',
'launcher-util.c',
'launcher-weston-launch.c',
]
deps_session_helper = [ dep_libweston_private_h ]
@@ -157,13 +172,8 @@ endif
systemd_dep = dependency('', required: false)
if get_option('launcher-logind')
systemd_dep = dependency('libsystemd', version: '>= 209', required: false)
if systemd_dep.found()
config_h.set('HAVE_SYSTEMD_LOGIN_209', '1')
else
systemd_dep = dependency('libsystemd-login', version: '>= 198', required: false)
if not systemd_dep.found()
error('logind support requires libsystemd or libsystemd-login but neither was found. Or, you can use \'-Dlauncher-logind=false\'')
endif
if not systemd_dep.found()
error('logind support requires libsystemd >= 209. Or, you can use \'-Dlauncher-logind=false\'')
endif
dbus_dep = dependency('dbus-1', version: '>= 1.6', required: false)
@@ -228,29 +238,9 @@ dep_vertex_clipping = declare_dependency(
include_directories: include_directories('.')
)
if get_option('deprecated-weston-launch')
warning('weston-launch is deprecated and will be removed in a future release. Please migrate to libseat and seatd-launch.')
dep_pam = cc.find_library('pam')
if not cc.has_function('pam_open_session', dependencies: dep_pam)
error('pam_open_session not found for weston-launch')
endif
executable(
'weston-launch',
'weston-launch.c',
dependencies: [dep_pam, systemd_dep, dep_libdrm],
include_directories: common_inc,
install: true
)
meson.add_install_script('echo', 'REMINDER: You are installing weston-launch, please make it setuid-root.')
endif
subdir('color-lcms')
subdir('renderer-gl')
subdir('backend-drm')
subdir('backend-fbdev')
subdir('backend-headless')
subdir('backend-rdp')
subdir('backend-wayland')
+38 -28
View File
@@ -31,11 +31,16 @@
#include <libweston/libweston.h>
#include "libweston-internal.h"
struct noop_renderer {
struct weston_renderer base;
unsigned char seed; /* see comment in attach() */
};
static int
noop_renderer_read_pixels(struct weston_output *output,
pixman_format_code_t format, void *pixels,
uint32_t x, uint32_t y,
uint32_t width, uint32_t height)
const struct pixel_format_info *format, void *pixels,
uint32_t x, uint32_t y,
uint32_t width, uint32_t height)
{
return 0;
}
@@ -47,32 +52,40 @@ noop_renderer_repaint_output(struct weston_output *output,
}
static void
noop_renderer_flush_damage(struct weston_surface *surface)
noop_renderer_flush_damage(struct weston_surface *surface,
struct weston_buffer *buffer)
{
}
static void
noop_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
struct noop_renderer *renderer =
wl_container_of(es->compositor->renderer, renderer, base);
struct wl_shm_buffer *shm_buffer;
uint8_t *data;
uint32_t size, i, width, height, stride;
volatile unsigned char unused = 0; /* volatile so it's not optimized out */
uint32_t size, i, height, stride;
unsigned char unused = 0;
if (!buffer)
return;
shm_buffer = wl_shm_buffer_get(buffer->resource);
if (!shm_buffer) {
switch (buffer->type) {
case WESTON_BUFFER_SOLID:
/* no-op, early exit */
return;
case WESTON_BUFFER_SHM:
/* fine */
break;
default:
weston_log("No-op renderer supports only SHM buffers\n");
return;
}
shm_buffer = buffer->shm_buffer;
data = wl_shm_buffer_get_data(shm_buffer);
stride = wl_shm_buffer_get_stride(shm_buffer);
width = wl_shm_buffer_get_width(shm_buffer);
height = wl_shm_buffer_get_height(shm_buffer);
height = buffer->height;
size = stride * height;
/* Access the buffer data to make sure the buffer's client gets killed
@@ -84,20 +97,18 @@ noop_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
unused ^= data[i];
wl_shm_buffer_end_access(shm_buffer);
buffer->shm_buffer = shm_buffer;
buffer->width = width;
buffer->height = height;
}
static void
noop_renderer_surface_set_color(struct weston_surface *surface,
float red, float green, float blue, float alpha)
{
/* Make sure that our unused is actually used, otherwise the compiler
* is free to notice that our reads have no effect and elide them. */
renderer->seed = unused;
}
static void
noop_renderer_destroy(struct weston_compositor *ec)
{
struct noop_renderer *renderer =
wl_container_of(ec->renderer, renderer, base);
weston_log("no-op renderer SHM seed: %d\n", renderer->seed);
free(ec->renderer);
ec->renderer = NULL;
}
@@ -105,19 +116,18 @@ noop_renderer_destroy(struct weston_compositor *ec)
WL_EXPORT int
noop_renderer_init(struct weston_compositor *ec)
{
struct weston_renderer *renderer;
struct noop_renderer *renderer;
renderer = zalloc(sizeof *renderer);
if (renderer == NULL)
return -1;
renderer->read_pixels = noop_renderer_read_pixels;
renderer->repaint_output = noop_renderer_repaint_output;
renderer->flush_damage = noop_renderer_flush_damage;
renderer->attach = noop_renderer_attach;
renderer->surface_set_color = noop_renderer_surface_set_color;
renderer->destroy = noop_renderer_destroy;
ec->renderer = renderer;
renderer->base.read_pixels = noop_renderer_read_pixels;
renderer->base.repaint_output = noop_renderer_repaint_output;
renderer->base.flush_damage = noop_renderer_flush_damage;
renderer->base.attach = noop_renderer_attach;
renderer->base.destroy = noop_renderer_destroy;
ec->renderer = &renderer->base;
return 0;
}
+149 -25
View File
@@ -48,6 +48,7 @@
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
#define GL_FORMAT(fmt) .gl_format = (fmt)
#define GL_TYPE(type) .gl_type = (type)
#define SAMPLER_TYPE(type) .sampler_type = (type)
@@ -64,6 +65,12 @@
.bits.b = b_, \
.bits.a = a_, \
.component_type = PIXEL_COMPONENT_TYPE_FIXED
#define BITS_RGBA_FLOAT(r_, g_, b_, a_) \
.bits.r = r_, \
.bits.g = g_, \
.bits.b = b_, \
.bits.a = a_, \
.component_type = PIXEL_COMPONENT_TYPE_FLOAT
#define PIXMAN_FMT(fmt) .pixman_format = (PIXMAN_ ## fmt)
@@ -75,27 +82,48 @@
* colour channels, are not supported.
*/
static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(R8),
BITS_RGBA_FIXED(8, 0, 0, 0),
.bpp = 8,
.hide_from_clients = true,
GL_FORMAT(GL_R8_EXT),
GL_TYPE(GL_UNSIGNED_BYTE),
},
{
DRM_FORMAT(GR88),
BITS_RGBA_FIXED(8, 8, 0, 0),
.bpp = 16,
.hide_from_clients = true,
GL_FORMAT(GL_RG8_EXT),
GL_TYPE(GL_UNSIGNED_BYTE),
},
{
DRM_FORMAT(XRGB4444),
BITS_RGBA_FIXED(4, 4, 4, 0),
.bpp = 16,
},
{
DRM_FORMAT(ARGB4444),
BITS_RGBA_FIXED(4, 4, 4, 4),
.bpp = 16,
.opaque_substitute = DRM_FORMAT_XRGB4444,
},
{
DRM_FORMAT(XBGR4444),
BITS_RGBA_FIXED(4, 4, 4, 0),
.bpp = 16,
},
{
DRM_FORMAT(ABGR4444),
BITS_RGBA_FIXED(4, 4, 4, 4),
.bpp = 16,
.opaque_substitute = DRM_FORMAT_XBGR4444,
},
{
DRM_FORMAT(RGBX4444),
BITS_RGBA_FIXED(4, 4, 4, 0),
.bpp = 16,
# if __BYTE_ORDER == __LITTLE_ENDIAN
GL_FORMAT(GL_RGBA),
GL_TYPE(GL_UNSIGNED_SHORT_4_4_4_4),
@@ -104,6 +132,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(RGBA4444),
BITS_RGBA_FIXED(4, 4, 4, 4),
.bpp = 16,
.opaque_substitute = DRM_FORMAT_RGBX4444,
# if __BYTE_ORDER == __LITTLE_ENDIAN
GL_FORMAT(GL_RGBA),
@@ -113,35 +142,41 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(BGRX4444),
BITS_RGBA_FIXED(4, 4, 4, 0),
.bpp = 16,
},
{
DRM_FORMAT(BGRA4444),
BITS_RGBA_FIXED(4, 4, 4, 4),
.bpp = 16,
.opaque_substitute = DRM_FORMAT_BGRX4444,
},
{
DRM_FORMAT(XRGB1555),
BITS_RGBA_FIXED(5, 5, 5, 0),
.depth = 15,
.addfb_legacy_depth = 15,
.bpp = 16,
},
{
DRM_FORMAT(ARGB1555),
BITS_RGBA_FIXED(5, 5, 5, 1),
.bpp = 16,
.opaque_substitute = DRM_FORMAT_XRGB1555,
},
{
DRM_FORMAT(XBGR1555),
BITS_RGBA_FIXED(5, 5, 5, 0),
.bpp = 16,
},
{
DRM_FORMAT(ABGR1555),
BITS_RGBA_FIXED(5, 5, 5, 1),
.bpp = 16,
.opaque_substitute = DRM_FORMAT_XBGR1555,
},
{
DRM_FORMAT(RGBX5551),
BITS_RGBA_FIXED(5, 5, 5, 0),
.bpp = 16,
# if __BYTE_ORDER == __LITTLE_ENDIAN
GL_FORMAT(GL_RGBA),
GL_TYPE(GL_UNSIGNED_SHORT_5_5_5_1),
@@ -150,6 +185,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(RGBA5551),
BITS_RGBA_FIXED(5, 5, 5, 1),
.bpp = 16,
.opaque_substitute = DRM_FORMAT_RGBX5551,
# if __BYTE_ORDER == __LITTLE_ENDIAN
GL_FORMAT(GL_RGBA),
@@ -159,16 +195,18 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(BGRX5551),
BITS_RGBA_FIXED(5, 5, 5, 0),
.bpp = 16,
},
{
DRM_FORMAT(BGRA5551),
BITS_RGBA_FIXED(5, 5, 5, 1),
.bpp = 16,
.opaque_substitute = DRM_FORMAT_BGRX5551,
},
{
DRM_FORMAT(RGB565),
BITS_RGBA_FIXED(5, 6, 5, 0),
.depth = 16,
.addfb_legacy_depth = 16,
.bpp = 16,
# if __BYTE_ORDER == __LITTLE_ENDIAN
GL_FORMAT(GL_RGB),
@@ -179,21 +217,24 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(BGR565),
BITS_RGBA_FIXED(5, 6, 5, 0),
.bpp = 16,
},
{
DRM_FORMAT(RGB888),
BITS_RGBA_FIXED(8, 8, 8, 0),
.bpp = 24,
},
{
DRM_FORMAT(BGR888),
BITS_RGBA_FIXED(8, 8, 8, 0),
.bpp = 24,
GL_FORMAT(GL_RGB),
GL_TYPE(GL_UNSIGNED_BYTE),
},
{
DRM_FORMAT(XRGB8888),
BITS_RGBA_FIXED(8, 8, 8, 0),
.depth = 24,
.addfb_legacy_depth = 24,
.bpp = 32,
GL_FORMAT(GL_BGRA_EXT),
GL_TYPE(GL_UNSIGNED_BYTE),
@@ -207,7 +248,7 @@ static const struct pixel_format_info pixel_format_table[] = {
DRM_FORMAT(ARGB8888),
BITS_RGBA_FIXED(8, 8, 8, 8),
.opaque_substitute = DRM_FORMAT_XRGB8888,
.depth = 32,
.addfb_legacy_depth = 32,
.bpp = 32,
GL_FORMAT(GL_BGRA_EXT),
GL_TYPE(GL_UNSIGNED_BYTE),
@@ -220,6 +261,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(XBGR8888),
BITS_RGBA_FIXED(8, 8, 8, 0),
.bpp = 32,
GL_FORMAT(GL_RGBA),
GL_TYPE(GL_UNSIGNED_BYTE),
#if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -231,6 +273,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(ABGR8888),
BITS_RGBA_FIXED(8, 8, 8, 8),
.bpp = 32,
.opaque_substitute = DRM_FORMAT_XBGR8888,
GL_FORMAT(GL_RGBA),
GL_TYPE(GL_UNSIGNED_BYTE),
@@ -243,6 +286,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(RGBX8888),
BITS_RGBA_FIXED(8, 8, 8, 0),
.bpp = 32,
#if __BYTE_ORDER == __LITTLE_ENDIAN
PIXMAN_FMT(r8g8b8x8),
#else
@@ -252,6 +296,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(RGBA8888),
BITS_RGBA_FIXED(8, 8, 8, 8),
.bpp = 32,
.opaque_substitute = DRM_FORMAT_RGBX8888,
#if __BYTE_ORDER == __LITTLE_ENDIAN
PIXMAN_FMT(r8g8b8a8),
@@ -262,6 +307,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(BGRX8888),
BITS_RGBA_FIXED(8, 8, 8, 0),
.bpp = 32,
#if __BYTE_ORDER == __LITTLE_ENDIAN
PIXMAN_FMT(b8g8r8x8),
#else
@@ -271,6 +317,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(BGRA8888),
BITS_RGBA_FIXED(8, 8, 8, 8),
.bpp = 32,
.opaque_substitute = DRM_FORMAT_BGRX8888,
#if __BYTE_ORDER == __LITTLE_ENDIAN
PIXMAN_FMT(b8g8r8a8),
@@ -281,7 +328,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(XRGB2101010),
BITS_RGBA_FIXED(10, 10, 10, 0),
.depth = 30,
.addfb_legacy_depth = 30,
.bpp = 32,
#if __BYTE_ORDER == __LITTLE_ENDIAN
PIXMAN_FMT(x2r10g10b10),
@@ -290,6 +337,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(ARGB2101010),
BITS_RGBA_FIXED(10, 10, 10, 2),
.bpp = 32,
.opaque_substitute = DRM_FORMAT_XRGB2101010,
#if __BYTE_ORDER == __LITTLE_ENDIAN
PIXMAN_FMT(a2r10g10b10),
@@ -298,6 +346,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(XBGR2101010),
BITS_RGBA_FIXED(10, 10, 10, 0),
.bpp = 32,
# if __BYTE_ORDER == __LITTLE_ENDIAN
GL_FORMAT(GL_RGBA),
GL_TYPE(GL_UNSIGNED_INT_2_10_10_10_REV_EXT),
@@ -307,6 +356,7 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(ABGR2101010),
BITS_RGBA_FIXED(10, 10, 10, 2),
.bpp = 32,
.opaque_substitute = DRM_FORMAT_XBGR2101010,
# if __BYTE_ORDER == __LITTLE_ENDIAN
GL_FORMAT(GL_RGBA),
@@ -317,21 +367,74 @@ static const struct pixel_format_info pixel_format_table[] = {
{
DRM_FORMAT(RGBX1010102),
BITS_RGBA_FIXED(10, 10, 10, 0),
.bpp = 32,
},
{
DRM_FORMAT(RGBA1010102),
BITS_RGBA_FIXED(10, 10, 10, 2),
.bpp = 32,
.opaque_substitute = DRM_FORMAT_RGBX1010102,
},
{
DRM_FORMAT(BGRX1010102),
BITS_RGBA_FIXED(10, 10, 10, 0),
.bpp = 32,
},
{
DRM_FORMAT(BGRA1010102),
BITS_RGBA_FIXED(10, 10, 10, 2),
.bpp = 32,
.opaque_substitute = DRM_FORMAT_BGRX1010102,
},
{
DRM_FORMAT(XBGR16161616),
BITS_RGBA_FIXED(16, 16, 16, 0),
.bpp = 64,
#if __BYTE_ORDER__ == __LITTLE_ENDIAN
GL_FORMAT(GL_RGBA16_EXT),
GL_TYPE(GL_UNSIGNED_SHORT),
#endif
},
{
DRM_FORMAT(ABGR16161616),
BITS_RGBA_FIXED(16, 16, 16, 16),
.bpp = 64,
.opaque_substitute = DRM_FORMAT_XBGR16161616,
#if __BYTE_ORDER__ == __LITTLE_ENDIAN
GL_FORMAT(GL_RGBA16_EXT),
GL_TYPE(GL_UNSIGNED_SHORT),
#endif
},
{
DRM_FORMAT(XBGR16161616F),
BITS_RGBA_FLOAT(16, 16, 16, 0),
.bpp = 64,
#if __BYTE_ORDER__ == __LITTLE_ENDIAN
GL_FORMAT(GL_RGBA16F),
GL_TYPE(GL_HALF_FLOAT),
#endif
},
{
DRM_FORMAT(ABGR16161616F),
BITS_RGBA_FLOAT(16, 16, 16, 16),
.bpp = 64,
.opaque_substitute = DRM_FORMAT_XBGR16161616F,
#if __BYTE_ORDER__ == __LITTLE_ENDIAN
GL_FORMAT(GL_RGBA16F),
GL_TYPE(GL_HALF_FLOAT),
#endif
},
{
DRM_FORMAT(XRGB16161616F),
BITS_RGBA_FLOAT(16, 16, 16, 0),
.bpp = 64,
},
{
DRM_FORMAT(ARGB16161616F),
BITS_RGBA_FLOAT(16, 16, 16, 16),
.bpp = 64,
.opaque_substitute = DRM_FORMAT_XRGB16161616F,
},
{
DRM_FORMAT(YUYV),
SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
@@ -472,6 +575,10 @@ static const struct pixel_format_info pixel_format_table[] = {
.num_planes = 3,
.chroma_order = ORDER_VU,
},
{
DRM_FORMAT(XYUV8888),
.bpp = 32,
},
};
WL_EXPORT const struct pixel_format_info *
@@ -529,6 +636,19 @@ pixel_format_get_info_by_drm_name(const char *drm_format_name)
return NULL;
}
WL_EXPORT const struct pixel_format_info *
pixel_format_get_info_by_pixman(pixman_format_code_t pixman_format)
{
unsigned int i;
for (i = 0; i < ARRAY_LENGTH(pixel_format_table); i++) {
if (pixel_format_table[i].pixman_format == pixman_format)
return &pixel_format_table[i];
}
return NULL;
}
WL_EXPORT unsigned int
pixel_format_get_plane_count(const struct pixel_format_info *info)
{
@@ -563,16 +683,34 @@ pixel_format_get_info_by_opaque_substitute(uint32_t format)
return NULL;
}
WL_EXPORT unsigned int
pixel_format_hsub(const struct pixel_format_info *info,
unsigned int plane)
{
/* We don't support any formats where the first plane is subsampled. */
if (plane == 0 || info->hsub == 0)
return 1;
return info->hsub;
}
WL_EXPORT unsigned int
pixel_format_vsub(const struct pixel_format_info *info,
unsigned int plane)
{
/* We don't support any formats where the first plane is subsampled. */
if (plane == 0 || info->vsub == 0)
return 1;
return info->vsub;
}
WL_EXPORT unsigned int
pixel_format_width_for_plane(const struct pixel_format_info *info,
unsigned int plane,
unsigned int width)
{
/* We don't support any formats where the first plane is subsampled. */
if (plane == 0 || !info->hsub)
return width;
return width / info->hsub;
return width / pixel_format_hsub(info, plane);
}
WL_EXPORT unsigned int
@@ -580,14 +718,9 @@ pixel_format_height_for_plane(const struct pixel_format_info *info,
unsigned int plane,
unsigned int height)
{
/* We don't support any formats where the first plane is subsampled. */
if (plane == 0 || !info->vsub)
return height;
return height / info->vsub;
return height / pixel_format_vsub(info, plane);
}
#ifdef HAVE_HUMAN_FORMAT_MODIFIER
WL_EXPORT char *
pixel_format_get_modifier(uint64_t modifier)
{
@@ -627,12 +760,3 @@ pixel_format_get_modifier(uint64_t modifier)
return mod_str;
}
#else
WL_EXPORT char *
pixel_format_get_modifier(uint64_t modifier)
{
char *mod_str;
str_printf(&mod_str, "0x%llx", (unsigned long long) modifier);
return mod_str;
}
#endif
+50 -2
View File
@@ -42,6 +42,10 @@ struct pixel_format_info {
/** The DRM format name without the DRM_FORMAT_ prefix. */
const char *drm_format_name;
/** If true, is only for internal use and should not be advertised to
* clients to allow them to create buffers of this format. */
bool hide_from_clients;
/** If non-zero, number of planes in base (non-modified) format. */
int num_planes;
@@ -76,9 +80,10 @@ struct pixel_format_info {
/** If set, this format can be used with the legacy drmModeAddFB()
* function (not AddFB2), using this and the bpp member. */
int depth;
int addfb_legacy_depth;
/** See 'depth' member above. */
/** Number of bits required to store a single pixel, for
* single-planar formats. */
int bpp;
/** Horizontal subsampling; if non-zero, divide the width by this
@@ -185,6 +190,19 @@ pixel_format_get_info_count(void);
const struct pixel_format_info *
pixel_format_get_info_by_drm_name(const char *drm_format_name);
/**
* Get pixel format information for a Pixman format code
*
* Given a Pixman format code, return a pixel format info structure describing
* the properties of that format.
*
* @param pixman_format Pixman format code to get info for
* @returns A pixel format structure (must not be freed), or NULL if the
* format could not be found
*/
const struct pixel_format_info *
pixel_format_get_info_by_pixman(pixman_format_code_t pixman_format);
/**
* Get number of planes used by a pixel format
*
@@ -247,6 +265,36 @@ pixel_format_get_opaque_substitute(const struct pixel_format_info *format);
const struct pixel_format_info *
pixel_format_get_info_by_opaque_substitute(uint32_t format);
/**
* Return the horizontal subsampling factor for a given plane
*
* When horizontal subsampling is effective, a sampler bound to a secondary
* plane must bind the sampler with a smaller effective width. This function
* returns the subsampling factor to use for the given plane.
*
* @param format Pixel format info structure
* @param plane Zero-indexed plane number
* @returns Horizontal subsampling factor for the given plane
*/
unsigned int
pixel_format_hsub(const struct pixel_format_info *format,
unsigned int plane);
/**
* Return the vertical subsampling factor for a given plane
*
* When vertical subsampling is effective, a sampler bound to a secondary
* plane must bind the sampler with a smaller effective height. This function
* returns the subsampling factor to use for the given plane.
*
* @param format Pixel format info structure
* @param plane Zero-indexed plane number
* @returns Vertical subsampling factor for the given plane
*/
unsigned int
pixel_format_vsub(const struct pixel_format_info *format,
unsigned int plane);
/**
* Return the effective sampling width for a given plane
*
+73 -74
View File
@@ -36,11 +36,11 @@
#include "color.h"
#include "pixel-formats.h"
#include "shared/helpers.h"
#include "shared/signal.h"
#include <linux/input.h>
struct pixman_output_state {
void *shadow_buffer;
pixman_image_t *shadow_image;
pixman_image_t *hw_buffer;
pixman_region32_t *hw_extra_damage;
@@ -94,9 +94,9 @@ get_renderer(struct weston_compositor *ec)
static int
pixman_renderer_read_pixels(struct weston_output *output,
pixman_format_code_t format, void *pixels,
uint32_t x, uint32_t y,
uint32_t width, uint32_t height)
const struct pixel_format_info *format, void *pixels,
uint32_t x, uint32_t y,
uint32_t width, uint32_t height)
{
struct pixman_output_state *po = get_output_state(output);
pixman_image_t *out_buf;
@@ -106,11 +106,11 @@ pixman_renderer_read_pixels(struct weston_output *output,
return -1;
}
out_buf = pixman_image_create_bits(format,
out_buf = pixman_image_create_bits(format->pixman_format,
width,
height,
pixels,
(PIXMAN_FORMAT_BPP(format) / 8) * width);
(PIXMAN_FORMAT_BPP(format->pixman_format) / 8) * width);
pixman_image_composite32(PIXMAN_OP_SRC,
po->hw_buffer, /* src */
@@ -489,6 +489,19 @@ draw_paint_node(struct weston_paint_node *pnode,
if (!ps->image)
return;
/* if we still have a reference, but the underlying buffer is no longer
* available signal that we should unref image_t as well. This happens
* when using close animations, with the reference surviving the
* animation while the underlying buffer went away as the client was
* terminated. This is a particular use-case and should probably be
* refactored to provide some analogue with the GL-renderer (as in, to
* still maintain the buffer and let the compositor dispose of it). */
if (ps->buffer_ref.buffer && !ps->buffer_ref.buffer->shm_buffer) {
pixman_image_unref(ps->image);
ps->image = NULL;
return;
}
pixman_region32_init(&repaint);
pixman_region32_intersect(&repaint,
&pnode->view->transform.boundingbox, damage);
@@ -568,7 +581,7 @@ pixman_renderer_repaint_output(struct weston_output *output,
pixman_region32_t hw_damage;
assert(output->from_blend_to_output_by_backend ||
output->from_blend_to_output == NULL);
output->color_outcome->from_blend_to_output == NULL);
if (!po->hw_buffer) {
po->hw_extra_damage = NULL;
@@ -598,7 +611,8 @@ pixman_renderer_repaint_output(struct weston_output *output,
}
static void
pixman_renderer_flush_damage(struct weston_surface *surface)
pixman_renderer_flush_damage(struct weston_surface *surface,
struct weston_buffer *buffer)
{
/* No-op for pixman renderer */
}
@@ -619,6 +633,26 @@ buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
ps->buffer_destroy_listener.notify = NULL;
}
static void
pixman_renderer_surface_set_color(struct weston_surface *es,
float red, float green, float blue, float alpha)
{
struct pixman_surface_state *ps = get_surface_state(es);
pixman_color_t color;
color.red = red * 0xffff;
color.green = green * 0xffff;
color.blue = blue * 0xffff;
color.alpha = alpha * 0xffff;
if (ps->image) {
pixman_image_unref(ps->image);
ps->image = NULL;
}
ps->image = pixman_image_create_solid_fill(&color);
}
static void
pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
@@ -626,7 +660,9 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
struct wl_shm_buffer *shm_buffer;
const struct pixel_format_info *pixel_info;
weston_buffer_reference(&ps->buffer_ref, buffer);
weston_buffer_reference(&ps->buffer_ref, buffer,
buffer ? BUFFER_MAY_BE_ACCESSED :
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&ps->buffer_release_ref,
es->buffer_release_ref.buffer_release);
@@ -643,32 +679,40 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
if (!buffer)
return;
shm_buffer = wl_shm_buffer_get(buffer->resource);
if (! shm_buffer) {
weston_log("Pixman renderer supports only SHM buffers\n");
weston_buffer_reference(&ps->buffer_ref, NULL);
if (buffer->type == WESTON_BUFFER_SOLID) {
pixman_renderer_surface_set_color(es,
buffer->solid.r,
buffer->solid.g,
buffer->solid.b,
buffer->solid.a);
weston_buffer_reference(&ps->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
return;
}
if (buffer->type != WESTON_BUFFER_SHM) {
weston_log("Pixman renderer supports only SHM buffers\n");
weston_buffer_reference(&ps->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
return;
}
shm_buffer = buffer->shm_buffer;
pixel_info = pixel_format_get_info_shm(wl_shm_buffer_get_format(shm_buffer));
if (!pixel_info || !pixman_format_supported_source(pixel_info->pixman_format)) {
weston_log("Unsupported SHM buffer format 0x%x\n",
wl_shm_buffer_get_format(shm_buffer));
weston_buffer_reference(&ps->buffer_ref, NULL);
weston_buffer_reference(&ps->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
weston_buffer_send_server_error(buffer,
"disconnecting due to unhandled buffer type");
return;
}
es->is_opaque = pixel_format_is_opaque(pixel_info);
buffer->shm_buffer = shm_buffer;
buffer->width = wl_shm_buffer_get_width(shm_buffer);
buffer->height = wl_shm_buffer_get_height(shm_buffer);
ps->image = pixman_image_create_bits(pixel_info->pixman_format,
buffer->width, buffer->height,
wl_shm_buffer_get_data(shm_buffer),
@@ -696,7 +740,8 @@ pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
pixman_image_unref(ps->image);
ps->image = NULL;
}
weston_buffer_reference(&ps->buffer_ref, NULL);
weston_buffer_reference(&ps->buffer_ref, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
free(ps);
}
@@ -750,26 +795,6 @@ pixman_renderer_create_surface(struct weston_surface *surface)
return 0;
}
static void
pixman_renderer_surface_set_color(struct weston_surface *es,
float red, float green, float blue, float alpha)
{
struct pixman_surface_state *ps = get_surface_state(es);
pixman_color_t color;
color.red = red * 0xffff;
color.green = green * 0xffff;
color.blue = blue * 0xffff;
color.alpha = alpha * 0xffff;
if (ps->image) {
pixman_image_unref(ps->image);
ps->image = NULL;
}
ps->image = pixman_image_create_solid_fill(&color);
}
static void
pixman_renderer_destroy(struct weston_compositor *ec)
{
@@ -782,21 +807,6 @@ pixman_renderer_destroy(struct weston_compositor *ec)
ec->renderer = NULL;
}
static void
pixman_renderer_surface_get_content_size(struct weston_surface *surface,
int *width, int *height)
{
struct pixman_surface_state *ps = get_surface_state(surface);
if (ps->image) {
*width = pixman_image_get_width(ps->image);
*height = pixman_image_get_height(ps->image);
} else {
*width = 0;
*height = 0;
}
}
static int
pixman_renderer_surface_copy_content(struct weston_surface *surface,
void *target, size_t size,
@@ -867,10 +877,7 @@ pixman_renderer_init(struct weston_compositor *ec)
renderer->base.repaint_output = pixman_renderer_repaint_output;
renderer->base.flush_damage = pixman_renderer_flush_damage;
renderer->base.attach = pixman_renderer_attach;
renderer->base.surface_set_color = pixman_renderer_surface_set_color;
renderer->base.destroy = pixman_renderer_destroy;
renderer->base.surface_get_content_size =
pixman_renderer_surface_get_content_size;
renderer->base.surface_copy_content =
pixman_renderer_surface_copy_content;
ec->renderer = &renderer->base;
@@ -907,13 +914,16 @@ pixman_renderer_output_set_buffer(struct weston_output *output,
pixman_image_t *buffer)
{
struct pixman_output_state *po = get_output_state(output);
pixman_format_code_t pixman_format;
if (po->hw_buffer)
pixman_image_unref(po->hw_buffer);
po->hw_buffer = buffer;
if (po->hw_buffer) {
output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
pixman_format = pixman_image_get_format(po->hw_buffer);
output->compositor->read_format =
pixel_format_get_info_by_pixman(pixman_format);
pixman_image_ref(po->hw_buffer);
}
}
@@ -943,19 +953,11 @@ pixman_renderer_output_create(struct weston_output *output,
w = output->current_mode->width;
h = output->current_mode->height;
po->shadow_buffer = malloc(w * h * 4);
if (!po->shadow_buffer) {
free(po);
return -1;
}
po->shadow_image =
pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
po->shadow_buffer, w * 4);
pixman_image_create_bits_no_clear(PIXMAN_x8r8g8b8,
w, h, NULL, 0);
if (!po->shadow_image) {
free(po->shadow_buffer);
free(po);
return -1;
}
@@ -977,9 +979,6 @@ pixman_renderer_output_destroy(struct weston_output *output)
if (po->hw_buffer)
pixman_image_unref(po->hw_buffer);
free(po->shadow_buffer);
po->shadow_buffer = NULL;
po->shadow_image = NULL;
po->hw_buffer = NULL;
+31 -6
View File
@@ -31,6 +31,7 @@
#include "shared/helpers.h"
#include "shared/platform.h"
#include "shared/string-helpers.h"
#include "gl-renderer.h"
#include "gl-renderer-internal.h"
@@ -477,7 +478,7 @@ gl_renderer_set_egl_device(struct gl_renderer *gr)
return;
}
gl_renderer_log_extensions("EGL device extensions", extensions);
gl_renderer_log_extensions(gr, "EGL device extensions", extensions);
/* Try to query the render node using EGL_DRM_RENDER_NODE_FILE_EXT */
if (weston_check_egl_extension(extensions, "EGL_EXT_device_drm_render_node"))
@@ -490,8 +491,10 @@ gl_renderer_set_egl_device(struct gl_renderer *gr)
gr->drm_device = gr->query_device_string(gr->egl_device,
EGL_DRM_DEVICE_FILE_EXT);
if (!gr->drm_device)
weston_log("failed to query DRM device from EGL\n");
if (gr->drm_device)
weston_log("Using rendering device: %s\n", gr->drm_device);
else
weston_log("warning: failed to query rendering device from EGL\n");
}
int
@@ -573,8 +576,7 @@ gl_renderer_setup_egl_client_extensions(struct gl_renderer *gr)
return 0;
}
gl_renderer_log_extensions("EGL client extensions",
extensions);
gl_renderer_log_extensions(gr, "EGL client extensions", extensions);
if (weston_check_egl_extension(extensions, "EGL_EXT_device_query")) {
gr->query_display_attrib =
@@ -594,8 +596,10 @@ gl_renderer_setup_egl_client_extensions(struct gl_renderer *gr)
weston_log("warning: EGL_EXT_platform_base not supported.\n");
/* Surfaceless is unusable without platform_base extension */
if (gr->platform == EGL_PLATFORM_SURFACELESS_MESA)
if (gr->platform == EGL_PLATFORM_SURFACELESS_MESA) {
weston_log("Error: EGL surfaceless platform cannot be used.\n");
return -1;
}
return 0;
}
@@ -615,6 +619,7 @@ gl_renderer_setup_egl_client_extensions(struct gl_renderer *gr)
/* at this point we definitely have some platform extensions but
* haven't found the supplied platform, so chances are it's
* not supported. */
weston_log("Error: EGL does not support %s platform.\n", extension_suffix);
return -1;
}
@@ -739,5 +744,25 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
"to missing EGL_KHR_wait_sync extension\n");
}
weston_log("EGL features:\n");
weston_log_continue(STAMP_SPACE "EGL Wayland extension: %s\n",
yesno(gr->has_bind_display));
weston_log_continue(STAMP_SPACE "context priority: %s\n",
yesno(gr->has_context_priority));
weston_log_continue(STAMP_SPACE "buffer age: %s\n",
yesno(gr->has_egl_buffer_age));
weston_log_continue(STAMP_SPACE "partial update: %s\n",
yesno(gr->has_egl_partial_update));
weston_log_continue(STAMP_SPACE "swap buffers with damage: %s\n",
yesno(gr->swap_buffers_with_damage));
weston_log_continue(STAMP_SPACE "configless context: %s\n",
yesno(gr->has_configless_context));
weston_log_continue(STAMP_SPACE "surfaceless context: %s\n",
yesno(gr->has_surfaceless_context));
weston_log_continue(STAMP_SPACE "dmabuf support: %s\n",
gr->has_dmabuf_import ?
(gr->has_dmabuf_import_modifiers ? "modifiers" : "legacy") :
"no");
return 0;
}
+62 -27
View File
@@ -2,6 +2,7 @@
* Copyright 2012 Intel Corporation
* Copyright 2015,2019,2021 Collabora, Ltd.
* Copyright 2016 NVIDIA Corporation
* Copyright 2021 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -46,10 +47,18 @@
#define SHADER_COLOR_CURVE_IDENTITY 0
#define SHADER_COLOR_CURVE_LUT_3x1D 1
/* enum gl_shader_color_mapping */
#define SHADER_COLOR_MAPPING_IDENTITY 0
#define SHADER_COLOR_MAPPING_3DLUT 1
#if DEF_VARIANT == SHADER_VARIANT_EXTERNAL
#extension GL_OES_EGL_image_external : require
#endif
#if DEF_COLOR_MAPPING == SHADER_COLOR_MAPPING_3DLUT
#extension GL_OES_texture_3D : require
#endif
#ifdef GL_FRAGMENT_PRECISION_HIGH
#define HIGHPRECISION highp
#else
@@ -66,6 +75,11 @@ compile_const int c_variant = DEF_VARIANT;
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 int c_color_mapping = DEF_COLOR_MAPPING;
compile_const bool c_need_color_pipeline =
c_color_pre_curve != SHADER_COLOR_CURVE_IDENTITY ||
c_color_mapping != SHADER_COLOR_MAPPING_IDENTITY;
compile_const bool c_need_color_pipeline =
c_color_pre_curve != SHADER_COLOR_CURVE_IDENTITY;
@@ -108,11 +122,16 @@ uniform sampler2D tex;
varying vec2 v_texcoord;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform float alpha;
uniform float view_alpha;
uniform vec4 unicolor;
uniform HIGHPRECISION sampler2D color_pre_curve_lut_2d;
uniform HIGHPRECISION vec2 color_pre_curve_lut_scale_offset;
#if DEF_COLOR_MAPPING == SHADER_COLOR_MAPPING_3DLUT
uniform HIGHPRECISION sampler3D color_mapping_lut_3d;
uniform HIGHPRECISION vec2 color_mapping_lut_scale_offset;
#endif
vec4
sample_input_texture()
{
@@ -171,6 +190,12 @@ lut_texcoord(float x, vec2 scale_offset)
return x * scale_offset.s + scale_offset.t;
}
vec3
lut_texcoord(vec3 pos, vec2 scale_offset)
{
return pos * scale_offset.s + scale_offset.t;
}
/*
* Sample a 1D LUT which is a single row of a 2D texture. The 2D texture has
* four rows so that the centers of texels have precise y-coordinates.
@@ -202,10 +227,41 @@ color_pre_curve(vec3 color)
}
}
vec3
sample_color_mapping_lut_3d(vec3 color)
{
vec3 pos, ret = vec3(0.0, 0.0, 0.0);
#if DEF_COLOR_MAPPING == SHADER_COLOR_MAPPING_3DLUT
pos = lut_texcoord(color, color_mapping_lut_scale_offset);
ret = texture3D(color_mapping_lut_3d, pos).rgb;
#endif
return ret;
}
vec3
color_mapping(vec3 color)
{
if (c_color_mapping == SHADER_COLOR_MAPPING_IDENTITY)
return color;
else if (c_color_mapping == SHADER_COLOR_MAPPING_3DLUT)
return sample_color_mapping_lut_3d(color);
else /* Never reached, bad c_color_mapping. */
return vec3(1.0, 0.3, 1.0);
}
vec4
color_pipeline(vec4 color)
{
/* 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.rgb = color_pre_curve(color.rgb);
color.rgb = color_mapping(color.rgb);
return color;
}
@@ -218,35 +274,14 @@ main()
/* Electrical (non-linear) RGBA values, may be premult or not */
color = sample_input_texture();
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;
}
if (c_need_color_pipeline)
color = color_pipeline(color); /* Produces straight alpha */
color = color_pipeline(color);
/* View alpha (opacity) */
color.a *= alpha;
/* pre-multiply for blending */
/* Ensure pre-multiplied for blending */
if (!c_input_is_premult || c_need_color_pipeline)
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;
}
}
color *= view_alpha;
if (c_green_tint)
color = vec4(0.0, 0.3, 0.0, 0.2) + color * 0.8;
+20 -3
View File
@@ -2,6 +2,7 @@
* Copyright © 2019 Collabora, Ltd.
* Copyright © 2019 Harish Krupo
* Copyright © 2019 Intel Corporation
* Copyright 2021 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -56,6 +57,12 @@ enum gl_shader_color_curve {
SHADER_COLOR_CURVE_LUT_3x1D,
};
/* Keep the following in sync with fragment.glsl. */
enum gl_shader_color_mapping {
SHADER_COLOR_MAPPING_IDENTITY = 0,
SHADER_COLOR_MAPPING_3DLUT,
};
/** GL shader requirements key
*
* This structure is used as a binary blob key for building and searching
@@ -70,13 +77,14 @@ struct gl_shader_requirements
unsigned variant:4; /* enum gl_shader_texture_variant */
bool input_is_premult:1;
bool green_tint:1;
unsigned color_pre_curve:1; /* enum gl_shader_color_curve */
unsigned color_pre_curve:1; /* enum gl_shader_color_curve */
unsigned color_mapping:1; /* enum gl_shader_color_mapping */
/*
* The total size of all bitfields plus pad_bits_ must fill up exactly
* how many bytes the compiler allocates for them together.
*/
unsigned pad_bits_:25;
unsigned pad_bits_:24;
};
static_assert(sizeof(struct gl_shader_requirements) ==
4 /* total bitfield size in bytes */,
@@ -96,11 +104,18 @@ struct gl_shader_config {
GLuint input_tex[GL_SHADER_INPUT_TEX_MAX];
GLuint color_pre_curve_lut_tex;
GLfloat color_pre_curve_lut_scale_offset[2];
union {
struct {
GLuint tex;
GLfloat scale_offset[2];
} lut3d;
} color_mapping;
};
struct gl_renderer {
struct weston_renderer base;
struct weston_compositor *compositor;
struct weston_log_scope *renderer_scope;
bool fragment_shader_debug;
bool fan_debug;
@@ -156,6 +171,7 @@ struct gl_renderer {
bool has_texture_type_2_10_10_10_rev;
bool has_gl_texture_rg;
bool has_texture_norm16;
struct gl_shader *current_shader;
struct gl_shader *fallback_shader;
@@ -198,7 +214,8 @@ void
gl_renderer_print_egl_error_state(void);
void
gl_renderer_log_extensions(const char *name, const char *extensions);
gl_renderer_log_extensions(struct gl_renderer *gr,
const char *name, const char *extensions);
void
log_egl_config_info(EGLDisplay egldpy, EGLConfig eglconfig);
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,6 @@
/*
* Copyright 2021 Collabora, Ltd.
* Copyright 2021 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -44,11 +45,22 @@ struct gl_renderer_color_curve {
float offset;
};
struct gl_renderer_color_mapping {
enum gl_shader_color_mapping type;
union {
struct {
GLuint tex3d;
float scale;
float offset;
} lut3d;
};
} ;
struct gl_renderer_color_transform {
struct weston_color_transform *owner;
struct wl_listener destroy_listener;
struct gl_renderer_color_curve pre_curve;
struct gl_renderer_color_mapping mapping;
};
static void
@@ -58,10 +70,19 @@ gl_renderer_color_curve_fini(struct gl_renderer_color_curve *gl_curve)
glDeleteTextures(1, &gl_curve->tex);
}
static void
gl_renderer_color_mapping_fini(struct gl_renderer_color_mapping *gl_mapping)
{
if (gl_mapping->type == SHADER_COLOR_MAPPING_3DLUT &&
gl_mapping->lut3d.tex3d)
glDeleteTextures(1, &gl_mapping->lut3d.tex3d);
}
static void
gl_renderer_color_transform_destroy(struct gl_renderer_color_transform *gl_xform)
{
gl_renderer_color_curve_fini(&gl_xform->pre_curve);
gl_renderer_color_mapping_fini(&gl_xform->mapping);
wl_list_remove(&gl_xform->destroy_listener.link);
free(gl_xform);
}
@@ -152,6 +173,47 @@ gl_color_curve_lut_3x1d(struct gl_renderer_color_curve *gl_curve,
return true;
}
static bool
gl_3d_lut(struct gl_renderer_color_transform *gl_xform,
struct weston_color_transform *xform)
{
GLuint tex3d;
float *lut;
const unsigned dim_size = xform->mapping.u.lut3d.optimal_len;
lut = calloc(3 * dim_size * dim_size * dim_size, sizeof *lut);
if (!lut)
return false;
xform->mapping.u.lut3d.fill_in(xform, lut, dim_size);
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &tex3d);
glBindTexture(GL_TEXTURE_3D, tex3d);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB32F, dim_size, dim_size, dim_size, 0,
GL_RGB, GL_FLOAT, lut);
glBindTexture(GL_TEXTURE_3D, 0);
gl_xform->mapping.type = SHADER_COLOR_MAPPING_3DLUT;
gl_xform->mapping.lut3d.tex3d = tex3d;
gl_xform->mapping.lut3d.scale = (float)(dim_size - 1) / dim_size;
gl_xform->mapping.lut3d.offset = 0.5f / dim_size;
free(lut);
return true;
}
static const struct gl_renderer_color_transform *
gl_renderer_color_transform_from(struct weston_color_transform *xform)
{
@@ -160,6 +222,7 @@ gl_renderer_color_transform_from(struct weston_color_transform *xform)
.pre_curve.tex = 0,
.pre_curve.scale = 0.0f,
.pre_curve.offset = 0.0f,
.mapping.type = SHADER_COLOR_MAPPING_IDENTITY,
};
struct gl_renderer_color_transform *gl_xform;
bool ok = false;
@@ -190,6 +253,19 @@ gl_renderer_color_transform_from(struct weston_color_transform *xform)
break;
}
if (!ok) {
gl_renderer_color_transform_destroy(gl_xform);
return NULL;
}
switch (xform->mapping.type) {
case WESTON_COLOR_MAPPING_TYPE_IDENTITY:
gl_xform->mapping = no_op_gl_xform.mapping;
ok = true;
break;
case WESTON_COLOR_MAPPING_TYPE_3D_LUT:
ok = gl_3d_lut(gl_xform, xform);
break;
}
if (!ok) {
gl_renderer_color_transform_destroy(gl_xform);
return NULL;
@@ -203,6 +279,7 @@ gl_shader_config_set_color_transform(struct gl_shader_config *sconf,
struct weston_color_transform *xform)
{
const struct gl_renderer_color_transform *gl_xform;
bool ret = false;
gl_xform = gl_renderer_color_transform_from(xform);
if (!gl_xform)
@@ -213,5 +290,22 @@ gl_shader_config_set_color_transform(struct gl_shader_config *sconf,
sconf->color_pre_curve_lut_scale_offset[0] = gl_xform->pre_curve.scale;
sconf->color_pre_curve_lut_scale_offset[1] = gl_xform->pre_curve.offset;
return true;
sconf->req.color_mapping = gl_xform->mapping.type;
switch (gl_xform->mapping.type) {
case SHADER_COLOR_MAPPING_3DLUT:
sconf->color_mapping.lut3d.tex = gl_xform->mapping.lut3d.tex3d;
sconf->color_mapping.lut3d.scale_offset[0] =
gl_xform->mapping.lut3d.scale;
sconf->color_mapping.lut3d.scale_offset[1] =
gl_xform->mapping.lut3d.offset;
assert(sconf->color_mapping.lut3d.scale_offset[0] > 0.0);
assert(sconf->color_mapping.lut3d.scale_offset[1] > 0.0);
ret = true;
break;
case SHADER_COLOR_MAPPING_IDENTITY:
ret = true;
break;
}
return ret;
}
+60 -8
View File
@@ -4,6 +4,7 @@
* Copyright 2016 NVIDIA Corporation
* Copyright 2019 Harish Krupo
* Copyright 2019 Intel Corporation
* Copyright 2021 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -56,10 +57,16 @@ struct gl_shader {
GLuint vertex_shader, fragment_shader;
GLint proj_uniform;
GLint tex_uniforms[3];
GLint alpha_uniform;
GLint view_alpha_uniform;
GLint color_uniform;
GLint color_pre_curve_lut_2d_uniform;
GLint color_pre_curve_lut_scale_offset_uniform;
union {
struct {
GLint tex_uniform;
GLint scale_offset_uniform;
} lut3d;
} color_mapping;
struct wl_list link; /* gl_renderer::shader_list */
struct timespec last_used;
};
@@ -97,6 +104,19 @@ gl_shader_color_curve_to_string(enum gl_shader_color_curve kind)
return "!?!?"; /* never reached */
}
static const char *
gl_shader_color_mapping_to_string(enum gl_shader_color_mapping kind)
{
switch (kind) {
#define CASERET(x) case x: return #x;
CASERET(SHADER_COLOR_MAPPING_IDENTITY)
CASERET(SHADER_COLOR_MAPPING_3DLUT)
#undef CASERET
}
return "!?!?"; /* never reached */
}
static void
dump_program_with_line_numbers(int count, const char **sources)
{
@@ -162,9 +182,10 @@ create_shader_description_string(const struct gl_shader_requirements *req)
int size;
char *str;
size = asprintf(&str, "%s %s %cinput_is_premult %cgreen",
size = asprintf(&str, "%s %s %s %cinput_is_premult %cgreen",
gl_shader_texture_variant_to_string(req->variant),
gl_shader_color_curve_to_string(req->color_pre_curve),
gl_shader_color_mapping_to_string(req->color_mapping),
req->input_is_premult ? '+' : '-',
req->green_tint ? '+' : '-');
if (size < 0)
@@ -182,10 +203,12 @@ create_shader_config_string(const struct gl_shader_requirements *req)
"#define DEF_GREEN_TINT %s\n"
"#define DEF_INPUT_IS_PREMULT %s\n"
"#define DEF_COLOR_PRE_CURVE %s\n"
"#define DEF_COLOR_MAPPING %s\n"
"#define DEF_VARIANT %s\n",
req->green_tint ? "true" : "false",
req->input_is_premult ? "true" : "false",
gl_shader_color_curve_to_string(req->color_pre_curve),
gl_shader_color_mapping_to_string(req->color_mapping),
gl_shader_texture_variant_to_string(req->variant));
if (size < 0)
return NULL;
@@ -260,7 +283,7 @@ gl_shader_create(struct gl_renderer *gr,
shader->tex_uniforms[0] = glGetUniformLocation(shader->program, "tex");
shader->tex_uniforms[1] = glGetUniformLocation(shader->program, "tex1");
shader->tex_uniforms[2] = glGetUniformLocation(shader->program, "tex2");
shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha");
shader->view_alpha_uniform = glGetUniformLocation(shader->program, "view_alpha");
shader->color_uniform = glGetUniformLocation(shader->program,
"unicolor");
shader->color_pre_curve_lut_2d_uniform =
@@ -268,6 +291,16 @@ gl_shader_create(struct gl_renderer *gr,
shader->color_pre_curve_lut_scale_offset_uniform =
glGetUniformLocation(shader->program, "color_pre_curve_lut_scale_offset");
switch(requirements->color_mapping) {
case SHADER_COLOR_MAPPING_3DLUT:
shader->color_mapping.lut3d.tex_uniform =
glGetUniformLocation(shader->program, "color_mapping_lut_3d");
shader->color_mapping.lut3d.scale_offset_uniform =
glGetUniformLocation(shader->program,"color_mapping_lut_scale_offset");
break;
case SHADER_COLOR_MAPPING_IDENTITY:
break;
}
free(conf);
wl_list_insert(&gr->shader_list, &shader->link);
@@ -376,6 +409,7 @@ gl_renderer_create_fallback_shader(struct gl_renderer *gr)
.variant = SHADER_VARIANT_SOLID,
.input_is_premult = true,
.color_pre_curve = SHADER_COLOR_CURVE_IDENTITY,
.color_mapping = SHADER_COLOR_MAPPING_IDENTITY,
};
struct gl_shader *shader;
@@ -481,7 +515,7 @@ gl_shader_load_config(struct gl_shader *shader,
glUniformMatrix4fv(shader->proj_uniform,
1, GL_FALSE, sconf->projection.d);
glUniform4fv(shader->color_uniform, 1, sconf->unicolor);
glUniform1f(shader->alpha_uniform, sconf->view_alpha);
glUniform1f(shader->view_alpha_uniform, sconf->view_alpha);
in_tgt = gl_shader_texture_variant_get_target(sconf->req.variant);
for (i = 0; i < GL_SHADER_INPUT_TEX_MAX; i++) {
@@ -497,9 +531,8 @@ gl_shader_load_config(struct gl_shader *shader,
glTexParameteri(in_tgt, GL_TEXTURE_MAG_FILTER, in_filter);
}
/* Fixed texture unit for color_pre_curve LUT */
/* Fixed texture unit for color_pre_curve LUT if it is available */
i = GL_SHADER_INPUT_TEX_MAX;
glActiveTexture(GL_TEXTURE0 + i);
switch (sconf->req.color_pre_curve) {
case SHADER_COLOR_CURVE_IDENTITY:
assert(sconf->color_pre_curve_lut_tex == 0);
@@ -508,13 +541,32 @@ gl_shader_load_config(struct gl_shader *shader,
assert(sconf->color_pre_curve_lut_tex != 0);
assert(shader->color_pre_curve_lut_2d_uniform != -1);
assert(shader->color_pre_curve_lut_scale_offset_uniform != -1);
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, sconf->color_pre_curve_lut_tex);
glUniform1i(shader->color_pre_curve_lut_2d_uniform, i);
i++;
glUniform2fv(shader->color_pre_curve_lut_scale_offset_uniform,
1, sconf->color_pre_curve_lut_scale_offset);
break;
}
switch (sconf->req.color_mapping) {
case SHADER_COLOR_MAPPING_IDENTITY:
break;
case SHADER_COLOR_MAPPING_3DLUT:
assert(shader->color_mapping.lut3d.tex_uniform != -1);
assert(sconf->color_mapping.lut3d.tex != 0);
assert(shader->color_mapping.lut3d.scale_offset_uniform != -1);
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_3D, sconf->color_mapping.lut3d.tex);
glUniform1i(shader->color_mapping.lut3d.tex_uniform, i);
glUniform2fv(shader->color_mapping.lut3d.scale_offset_uniform,
1, sconf->color_mapping.lut3d.scale_offset);
break;
default:
assert(false);
break;
}
}
bool
@@ -540,7 +592,7 @@ gl_renderer_use_program(struct gl_renderer *gr,
shader = gr->fallback_shader;
glUseProgram(shader->program);
glUniform4fv(shader->color_uniform, 1, fallback_shader_color);
glUniform1f(shader->alpha_uniform, 1.0f);
glUniform1f(shader->view_alpha_uniform, 1.0f);
return false;
}
+36 -12
View File
@@ -40,11 +40,13 @@
#include "shared/timespec-util.h"
#include "backend.h"
#include "libweston-internal.h"
#include "pixel-formats.h"
#include "wcap/wcap-decode.h"
struct screenshooter_frame_listener {
struct wl_listener listener;
struct wl_listener frame_listener;
struct wl_listener buffer_destroy_listener;
struct weston_buffer *buffer;
struct weston_output *output;
weston_screenshooter_done_func_t done;
@@ -119,15 +121,20 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data)
{
struct screenshooter_frame_listener *l =
container_of(listener,
struct screenshooter_frame_listener, listener);
struct screenshooter_frame_listener,
frame_listener);
struct weston_output *output = l->output;
struct weston_compositor *compositor = output->compositor;
const pixman_format_code_t pixman_format =
compositor->read_format->pixman_format;
int32_t stride;
uint8_t *pixels, *d, *s;
weston_output_disable_planes_decr(output);
wl_list_remove(&listener->link);
stride = l->buffer->width * (PIXMAN_FORMAT_BPP(compositor->read_format) / 8);
wl_list_remove(&l->buffer_destroy_listener.link);
stride = l->buffer->width * (PIXMAN_FORMAT_BPP(pixman_format) / 8);
pixels = malloc(stride * l->buffer->height);
if (pixels == NULL) {
@@ -148,7 +155,7 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data)
wl_shm_buffer_begin_access(l->buffer->shm_buffer);
switch (compositor->read_format) {
switch (pixman_format) {
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
@@ -174,6 +181,22 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data)
free(l);
}
static void
buffer_destroy_handle(struct wl_listener *listener, void *data)
{
struct screenshooter_frame_listener *l =
container_of(listener,
struct screenshooter_frame_listener,
buffer_destroy_listener);
weston_output_disable_planes_decr(l->output);
wl_list_remove(&listener->link);
wl_list_remove(&l->frame_listener.link);
l->done(l->data, WESTON_SCREENSHOOTER_BAD_BUFFER);
free(l);
}
WL_EXPORT int
weston_screenshooter_shoot(struct weston_output *output,
struct weston_buffer *buffer,
@@ -181,15 +204,11 @@ weston_screenshooter_shoot(struct weston_output *output,
{
struct screenshooter_frame_listener *l;
if (!wl_shm_buffer_get(buffer->resource)) {
if (buffer->type != WESTON_BUFFER_SHM) {
done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
return -1;
}
buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
if (buffer->width < output->current_mode->width ||
buffer->height < output->current_mode->height) {
done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
@@ -206,8 +225,13 @@ weston_screenshooter_shoot(struct weston_output *output,
l->output = output;
l->done = done;
l->data = data;
l->listener.notify = screenshooter_frame_notify;
wl_signal_add(&output->frame_signal, &l->listener);
l->frame_listener.notify = screenshooter_frame_notify;
wl_signal_add(&output->frame_signal, &l->frame_listener);
l->buffer_destroy_listener.notify = buffer_destroy_handle;
wl_signal_add(&buffer->destroy_signal, &l->buffer_destroy_listener);
weston_output_disable_planes_incr(output);
weston_output_schedule_repaint(output);
@@ -418,7 +442,7 @@ weston_recorder_create(struct weston_output *output, const char *filename)
header.magic = WCAP_HEADER_MAGIC;
switch (compositor->read_format) {
switch (compositor->read_format->pixman_format) {
case PIXMAN_x8r8g8b8:
case PIXMAN_a8r8g8b8:
header.format = WCAP_FORMAT_XRGB8888;
+11 -1
View File
@@ -206,7 +206,7 @@ map_calibrator(struct weston_touch_calibrator *calibrator)
calibrator->view->is_mapped = true;
calibrator->surface->output = calibrator->output;
calibrator->surface->is_mapped = true;
weston_surface_map(calibrator->surface);
weston_output_schedule_repaint(calibrator->output);
@@ -674,6 +674,16 @@ bind_touch_calibration(struct wl_client *client,
}
}
void
weston_compositor_destroy_touch_calibrator(struct weston_compositor *ec)
{
/* TODO: handle weston_compositor::touch_calibrator destruction
* see
* https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/819#note_1345191
*/
weston_layer_fini(&ec->calibrator_layer);
}
/** Advertise touch_calibration support
*
* \param compositor The compositor to init for.
+4 -3
View File
@@ -26,9 +26,10 @@
#include <float.h>
#include <math.h>
#include "shared/helpers.h"
#include "vertex-clipping.h"
float
WESTON_EXPORT_FOR_TESTS float
float_difference(float a, float b)
{
/* http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ */
@@ -282,7 +283,7 @@ clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
#define min(a, b) (((a) > (b)) ? (b) : (a))
#define clip(x, a, b) min(max(x, a), b)
int
WESTON_EXPORT_FOR_TESTS int
clip_simple(struct clip_context *ctx,
struct polygon8 *surf,
float *ex,
@@ -296,7 +297,7 @@ clip_simple(struct clip_context *ctx,
return surf->n;
}
int
WESTON_EXPORT_FOR_TESTS int
clip_transformed(struct clip_context *ctx,
struct polygon8 *surf,
float *ex,
-917
View File
@@ -1,917 +0,0 @@
/*
* Copyright © 2012 Benjamin Franzke
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <poll.h>
#include <errno.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/signalfd.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/vt.h>
#include <linux/major.h>
#include <linux/kd.h>
#include <pwd.h>
#include <grp.h>
#include <security/pam_appl.h>
#ifdef HAVE_SYSTEMD_LOGIN
#include <systemd/sd-login.h>
#endif
#include "weston-launch.h"
#define DRM_MAJOR 226
#ifndef KDSKBMUTE
#define KDSKBMUTE 0x4B51
#endif
#ifndef EVIOCREVOKE
#define EVIOCREVOKE _IOW('E', 0x91, int)
#endif
#define MAX_ARGV_SIZE 256
#ifdef BUILD_DRM_COMPOSITOR
#include <xf86drm.h>
#else
static inline int
drmDropMaster(int drm_fd)
{
return 0;
}
static inline int
drmSetMaster(int drm_fd)
{
return 0;
}
#endif
/* major()/minor() */
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
#endif
#ifdef MAJOR_IN_SYSMACROS
# include <sys/sysmacros.h>
#endif
struct weston_launch {
struct pam_conv pc;
pam_handle_t *ph;
int tty;
int ttynr;
int sock[2];
int drm_fd;
int last_input_fd;
int kb_mode;
struct passwd *pw;
int signalfd;
pid_t child;
int verbose;
char *new_user;
};
union cmsg_data { unsigned char b[4]; int fd; };
static gid_t *
read_groups(int *ngroups)
{
int n;
gid_t *groups;
n = getgroups(0, NULL);
if (n < 0) {
fprintf(stderr, "Unable to retrieve groups: %s\n",
strerror(errno));
return NULL;
}
groups = malloc(n * sizeof(gid_t));
if (!groups)
return NULL;
if (getgroups(n, groups) < 0) {
fprintf(stderr, "Unable to retrieve groups: %s\n",
strerror(errno));
free(groups);
return NULL;
}
*ngroups = n;
return groups;
}
static bool
weston_launch_allowed(struct weston_launch *wl)
{
struct group *gr;
gid_t *groups;
int ngroups;
#ifdef HAVE_SYSTEMD_LOGIN
char *session, *seat;
int err;
#endif
if (getuid() == 0)
return true;
gr = getgrnam("weston-launch");
if (gr) {
groups = read_groups(&ngroups);
if (groups && ngroups > 0) {
while (ngroups--) {
if (groups[ngroups] == gr->gr_gid) {
free(groups);
return true;
}
}
free(groups);
}
}
#ifdef HAVE_SYSTEMD_LOGIN
err = sd_pid_get_session(getpid(), &session);
if (err == 0 && session) {
if (sd_session_is_active(session) &&
sd_session_get_seat(session, &seat) == 0) {
free(seat);
free(session);
return true;
}
free(session);
}
#endif
return false;
}
static int
pam_conversation_fn(int msg_count,
const struct pam_message **messages,
struct pam_response **responses,
void *user_data)
{
return PAM_SUCCESS;
}
static int
setup_pam(struct weston_launch *wl)
{
int err;
wl->pc.conv = pam_conversation_fn;
wl->pc.appdata_ptr = wl;
err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
if (err != PAM_SUCCESS) {
fprintf(stderr, "failed to start pam transaction: %d: %s\n",
err, pam_strerror(wl->ph, err));
return -1;
}
err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
if (err != PAM_SUCCESS) {
fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
err, pam_strerror(wl->ph, err));
return -1;
}
err = pam_open_session(wl->ph, 0);
if (err != PAM_SUCCESS) {
fprintf(stderr, "failed to open pam session: %d: %s\n",
err, pam_strerror(wl->ph, err));
return -1;
}
return 0;
}
static int
setup_launcher_socket(struct weston_launch *wl)
{
if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0) {
fprintf(stderr, "weston: socketpair failed: %s\n",
strerror(errno));
return -1;
}
if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0) {
fprintf(stderr, "weston: fcntl failed: %s\n",
strerror(errno));
return -1;
}
return 0;
}
static int
setup_signals(struct weston_launch *wl)
{
int ret;
sigset_t mask;
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_handler = SIG_DFL;
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
ret = sigaction(SIGCHLD, &sa, NULL);
assert(ret == 0);
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigaction(SIGHUP, &sa, NULL);
ret = sigemptyset(&mask);
assert(ret == 0);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2);
ret = sigprocmask(SIG_BLOCK, &mask, NULL);
assert(ret == 0);
wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
if (wl->signalfd < 0)
return -errno;
return 0;
}
static void
setenv_fd(const char *env, int fd)
{
char buf[32];
snprintf(buf, sizeof buf, "%d", fd);
setenv(env, buf, 1);
}
static int
open_tty_by_number(int ttynr)
{
int ret;
char filename[16];
ret = snprintf(filename, sizeof filename, "/dev/tty%d", ttynr);
if (ret < 0)
return -1;
return open(filename, O_RDWR | O_NOCTTY);
}
static int
send_reply(struct weston_launch *wl, int reply)
{
int len;
do {
len = send(wl->sock[0], &reply, sizeof reply, 0);
} while (len < 0 && errno == EINTR);
return len;
}
static int
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
int fd = -1, ret = -1;
char control[CMSG_SPACE(sizeof(fd))];
struct cmsghdr *cmsg;
struct stat s;
struct msghdr nmsg;
struct iovec iov;
struct weston_launcher_open *message;
union cmsg_data *data;
message = msg->msg_iov->iov_base;
if ((size_t)len < sizeof(*message))
goto err0;
/* Ensure path is null-terminated */
((char *) message)[len-1] = '\0';
fd = open(message->path, message->flags);
if (fd < 0) {
fprintf(stderr, "Error opening device %s: %s\n",
message->path, strerror(errno));
goto err0;
}
if (fstat(fd, &s) < 0) {
close(fd);
fd = -1;
fprintf(stderr, "Failed to stat %s\n", message->path);
goto err0;
}
if (major(s.st_rdev) != INPUT_MAJOR &&
major(s.st_rdev) != DRM_MAJOR) {
close(fd);
fd = -1;
fprintf(stderr, "Device %s is not an input or drm device\n",
message->path);
goto err0;
}
err0:
memset(&nmsg, 0, sizeof nmsg);
nmsg.msg_iov = &iov;
nmsg.msg_iovlen = 1;
if (fd != -1) {
nmsg.msg_control = control;
nmsg.msg_controllen = sizeof control;
cmsg = CMSG_FIRSTHDR(&nmsg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
data = (union cmsg_data *) CMSG_DATA(cmsg);
data->fd = fd;
nmsg.msg_controllen = cmsg->cmsg_len;
ret = 0;
}
struct { int reply_id; int ret; } reply_iov_data = { WESTON_LAUNCHER_OPEN_REPLY, ret };
iov.iov_base = &reply_iov_data;
iov.iov_len = sizeof reply_iov_data;
if (wl->verbose)
fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
message->path, ret, fd);
do {
len = sendmsg(wl->sock[0], &nmsg, 0);
} while (len < 0 && errno == EINTR);
if (len < 0)
return -1;
if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
wl->drm_fd = fd;
if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
wl->last_input_fd < fd)
wl->last_input_fd = fd;
return 0;
}
static void
close_input_fds(struct weston_launch *wl)
{
struct stat s;
int fd;
for (fd = 3; fd <= wl->last_input_fd; fd++) {
if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
/* EVIOCREVOKE may fail if the kernel doesn't
* support it, but all we can do is ignore it. */
ioctl(fd, EVIOCREVOKE, 0);
close(fd);
}
}
}
static int
handle_socket_msg(struct weston_launch *wl)
{
char control[CMSG_SPACE(sizeof(int))];
char buf[BUFSIZ];
struct msghdr msg;
struct iovec iov;
int ret = -1;
ssize_t len;
struct weston_launcher_message *message;
memset(&msg, 0, sizeof(msg));
iov.iov_base = buf;
iov.iov_len = sizeof buf;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof control;
do {
len = recvmsg(wl->sock[0], &msg, 0);
} while (len < 0 && errno == EINTR);
if (len < 1)
return -1;
message = (void *) buf;
switch (message->opcode) {
case WESTON_LAUNCHER_OPEN:
ret = handle_open(wl, &msg, len);
break;
case WESTON_LAUNCHER_DEACTIVATE_DONE:
close_input_fds(wl);
drmDropMaster(wl->drm_fd);
ioctl(wl->tty, VT_RELDISP, 1);
break;
}
return ret;
}
static void
quit(struct weston_launch *wl, int status)
{
struct vt_mode mode = { 0 };
int err;
int oldtty;
close(wl->signalfd);
close(wl->sock[0]);
if (wl->new_user) {
err = pam_close_session(wl->ph, 0);
if (err)
fprintf(stderr, "pam_close_session failed: %d: %s\n",
err, pam_strerror(wl->ph, err));
pam_end(wl->ph, err);
}
/*
* Get a fresh handle to the tty as the previous one is in
* hang-up state since weston (the controlling process for
* the tty) exit at this point. Reopen before closing the
* file descriptor to avoid a potential race condition.
*
* A similar fix exists in logind, see:
* https://github.com/systemd/systemd/pull/990
*/
oldtty = wl->tty;
wl->tty = open_tty_by_number(wl->ttynr);
close(oldtty);
if (ioctl(wl->tty, KDSKBMUTE, 0) &&
ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
fprintf(stderr, "failed to restore keyboard mode: %s\n",
strerror(errno));
if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
fprintf(stderr, "failed to set KD_TEXT mode on tty: %s\n",
strerror(errno));
/* We have to drop master before we switch the VT back in
* VT_AUTO, so we don't risk switching to a VT with another
* display server, that will then fail to set drm master. */
drmDropMaster(wl->drm_fd);
mode.mode = VT_AUTO;
if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
fprintf(stderr, "could not reset vt handling\n");
if (wl->tty != STDIN_FILENO)
close(wl->tty);
exit(status);
}
static int
handle_signal(struct weston_launch *wl)
{
struct signalfd_siginfo sig;
int pid, status, ret;
if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
fprintf(stderr, "weston: reading signalfd failed: %s\n",
strerror(errno));
return -1;
}
switch (sig.ssi_signo) {
case SIGCHLD:
pid = waitpid(-1, &status, 0);
if (pid == wl->child) {
wl->child = 0;
if (WIFEXITED(status))
ret = WEXITSTATUS(status);
else if (WIFSIGNALED(status))
/*
* If weston dies because of signal N, we
* return 10+N. This is distinct from
* weston-launch dying because of a signal
* (128+N).
*/
ret = 10 + WTERMSIG(status);
else
ret = 0;
quit(wl, ret);
}
break;
case SIGTERM:
case SIGINT:
if (!wl->child)
break;
if (wl->verbose)
fprintf(stderr, "weston-launch: sending %s to pid %d\n",
strsignal(sig.ssi_signo), wl->child);
kill(wl->child, sig.ssi_signo);
break;
case SIGUSR1:
send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
break;
case SIGUSR2:
ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
drmSetMaster(wl->drm_fd);
send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
break;
default:
return -1;
}
return 0;
}
static int
setup_tty(struct weston_launch *wl, const char *tty)
{
struct stat buf;
struct vt_mode mode = { 0 };
char *t;
if (!wl->new_user) {
wl->tty = STDIN_FILENO;
} else if (tty) {
t = ttyname(STDIN_FILENO);
if (t && strcmp(t, tty) == 0)
wl->tty = STDIN_FILENO;
else
wl->tty = open(tty, O_RDWR | O_NOCTTY);
} else {
int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
if (tty0 < 0) {
fprintf(stderr, "weston: could not open tty0: %s\n",
strerror(errno));
return -1;
}
if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
{
fprintf(stderr, "weston: failed to find non-opened console: %s\n",
strerror(errno));
return -1;
}
wl->tty = open_tty_by_number(wl->ttynr);
close(tty0);
}
if (wl->tty < 0) {
fprintf(stderr, "weston: failed to open tty: %s\n",
strerror(errno));
return -1;
}
if (fstat(wl->tty, &buf) == -1 ||
major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0) {
fprintf(stderr, "weston: weston-launch must be run from a virtual terminal\n");
return -1;
}
if (!wl->new_user || tty) {
if (fstat(wl->tty, &buf) < 0) {
fprintf(stderr, "weston: stat %s failed: %s\n", tty,
strerror(errno));
return -1;
}
if (major(buf.st_rdev) != TTY_MAJOR) {
fprintf(stderr,
"weston: invalid tty device: %s\n", tty);
return -1;
}
wl->ttynr = minor(buf.st_rdev);
}
if (ioctl(wl->tty, VT_ACTIVATE, wl->ttynr) < 0) {
fprintf(stderr,
"weston: failed to activate VT: %s\n",
strerror(errno));
return -1;
}
if (ioctl(wl->tty, VT_WAITACTIVE, wl->ttynr) < 0) {
fprintf(stderr,
"weston: failed to wait for VT to be active: %s\n",
strerror(errno));
return -1;
}
if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode)) {
fprintf(stderr,
"weston: failed to get current keyboard mode: %s\n",
strerror(errno));
return -1;
}
if (ioctl(wl->tty, KDSKBMUTE, 1) &&
ioctl(wl->tty, KDSKBMODE, K_OFF)) {
fprintf(stderr,
"weston: failed to set K_OFF keyboard mode: %s\n",
strerror(errno));
return -1;
}
if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS)) {
fprintf(stderr,
"weston: failed to set KD_GRAPHICS mode on tty: %s\n",
strerror(errno));
return -1;
}
mode.mode = VT_PROCESS;
mode.relsig = SIGUSR1;
mode.acqsig = SIGUSR2;
if (ioctl(wl->tty, VT_SETMODE, &mode) < 0) {
fprintf(stderr,
"weston: failed to take control of vt handling %s\n",
strerror(errno));
return -1;
}
return 0;
}
static int
setup_session(struct weston_launch *wl, char **child_argv)
{
char **env;
char *term;
int i;
if (wl->tty != STDIN_FILENO) {
if (setsid() < 0) {
fprintf(stderr, "weston: setsid failed %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
if (ioctl(wl->tty, TIOCSCTTY, 0) < 0) {
fprintf(stderr, "TIOCSCTTY failed - tty is in use %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
}
term = getenv("TERM");
clearenv();
if (term)
setenv("TERM", term, 1);
setenv("USER", wl->pw->pw_name, 1);
setenv("LOGNAME", wl->pw->pw_name, 1);
setenv("HOME", wl->pw->pw_dir, 1);
setenv("SHELL", wl->pw->pw_shell, 1);
env = pam_getenvlist(wl->ph);
if (env) {
for (i = 0; env[i]; ++i) {
if (putenv(env[i]) != 0)
fprintf(stderr, "putenv %s failed\n", env[i]);
}
free(env);
}
/*
* We open a new session, so it makes sense
* to run a new login shell
*/
child_argv[0] = "/bin/sh";
child_argv[1] = "-l";
child_argv[2] = "-c";
child_argv[3] = "exec " BINDIR "/weston \"$@\"";
child_argv[4] = "weston";
return 5;
}
static void
drop_privileges(struct weston_launch *wl)
{
if (setgid(wl->pw->pw_gid) < 0 ||
#ifdef HAVE_INITGROUPS
initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
#endif
setuid(wl->pw->pw_uid) < 0) {
fprintf(stderr, "weston: dropping privileges failed %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
}
static void
launch_compositor(struct weston_launch *wl, int argc, char *argv[])
{
char *child_argv[MAX_ARGV_SIZE];
sigset_t mask;
int o, i;
if (wl->verbose)
printf("weston-launch: spawned weston with pid: %d\n", getpid());
if (wl->new_user) {
o = setup_session(wl, child_argv);
} else {
child_argv[0] = BINDIR "/weston";
o = 1;
}
for (i = 0; i < argc; ++i)
child_argv[o + i] = argv[i];
child_argv[o + i] = NULL;
if (geteuid() == 0)
drop_privileges(wl);
setenv_fd("WESTON_TTY_FD", wl->tty);
setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
unsetenv("DISPLAY");
/* Do not give our signal mask to the new process. */
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
execv(child_argv[0], child_argv);
fprintf(stderr, "weston: exec failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
static void
help(const char *name)
{
fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
fprintf(stderr, " -u, --user Start session as specified username,\n"
" e.g. -u joe, requires root.\n");
fprintf(stderr, " -t, --tty Start session on alternative tty,\n"
" e.g. -t /dev/tty4, requires -u option.\n");
fprintf(stderr, " -v, --verbose Be verbose\n");
fprintf(stderr, " -h, --help Display this help message\n");
}
int
main(int argc, char *argv[])
{
struct weston_launch wl;
int i, c;
char *tty = NULL;
struct option opts[] = {
{ "user", required_argument, NULL, 'u' },
{ "tty", required_argument, NULL, 't' },
{ "verbose", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, NULL, 0 }
};
memset(&wl, 0, sizeof wl);
while ((c = getopt_long(argc, argv, "u:t:vh", opts, &i)) != -1) {
switch (c) {
case 'u':
wl.new_user = optarg;
if (getuid() != 0) {
fprintf(stderr, "weston: Permission denied. -u allowed for root only\n");
exit(EXIT_FAILURE);
}
break;
case 't':
tty = optarg;
break;
case 'v':
wl.verbose = 1;
break;
case 'h':
help("weston-launch");
exit(EXIT_FAILURE);
default:
exit(EXIT_FAILURE);
}
}
if ((argc - optind) > (MAX_ARGV_SIZE - 6)) {
fprintf(stderr,
"weston: Too many arguments to pass to weston: %s\n",
strerror(E2BIG));
exit(EXIT_FAILURE);
}
if (tty && !wl.new_user) {
fprintf(stderr, "weston: -t/--tty option requires -u/--user option as well\n");
exit(EXIT_FAILURE);
}
if (wl.new_user)
wl.pw = getpwnam(wl.new_user);
else
wl.pw = getpwuid(getuid());
if (wl.pw == NULL) {
fprintf(stderr, "weston: failed to get username: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
if (!weston_launch_allowed(&wl)) {
fprintf(stderr, "Permission denied. You should either:\n"
#ifdef HAVE_SYSTEMD_LOGIN
" - run from an active and local (systemd) session.\n"
#else
" - enable systemd session support for weston-launch.\n"
#endif
" - or add yourself to the 'weston-launch' group.\n");
exit(EXIT_FAILURE);
}
if (setup_tty(&wl, tty) < 0)
exit(EXIT_FAILURE);
if (wl.new_user && setup_pam(&wl) < 0)
exit(EXIT_FAILURE);
if (setup_launcher_socket(&wl) < 0)
exit(EXIT_FAILURE);
if (setup_signals(&wl) < 0)
exit(EXIT_FAILURE);
wl.child = fork();
if (wl.child == -1) {
fprintf(stderr, "weston: fork failed %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (wl.child == 0)
launch_compositor(&wl, argc - optind, argv + optind);
close(wl.sock[1]);
while (1) {
struct pollfd fds[2];
int n;
fds[0].fd = wl.sock[0];
fds[0].events = POLLIN;
fds[1].fd = wl.signalfd;
fds[1].events = POLLIN;
n = poll(fds, 2, -1);
if (n < 0) {
fprintf(stderr, "poll failed: %s\n", strerror(errno));
return -1;
}
if (fds[0].revents & POLLIN)
handle_socket_msg(&wl);
if (fds[1].revents)
handle_signal(&wl);
}
return 0;
}
-51
View File
@@ -1,51 +0,0 @@
/*
* Copyright © 2012 Benjamin Franzke
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _WESTON_LAUNCH_H_
#define _WESTON_LAUNCH_H_
enum weston_launcher_opcode {
WESTON_LAUNCHER_OPEN,
};
enum weston_launcher_event {
WESTON_LAUNCHER_ACTIVATE,
WESTON_LAUNCHER_DEACTIVATE,
WESTON_LAUNCHER_DEACTIVATE_DONE,
// This event is followed by an fd handle
WESTON_LAUNCHER_OPEN_REPLY,
};
struct weston_launcher_message {
int opcode;
};
struct weston_launcher_open {
struct weston_launcher_message header;
int flags;
char path[0];
};
#endif
+50 -2
View File
@@ -238,8 +238,6 @@ weston_log_subscription_get_data(struct weston_log_subscription *sub)
* subscription
* @param scope the scope in order to add the subscription to the scope's
* subscription list
* @returns a weston_log_subscription object in case of success, or NULL
* otherwise
*
* @sa weston_log_subscription_destroy, weston_log_subscription_remove,
* weston_log_subscription_add
@@ -913,6 +911,56 @@ weston_log_scope_timestamp(struct weston_log_scope *scope,
return buf;
}
/** Returns a timestamp useful for adding it to a log scope.
*
* @example
* char timestr[128];
* static int cached_dm = -1;
* char *time_buff = weston_log_timestamp(timestr, sizeof(timestr), &cached_dm);
* weston_log_scope_printf(log_scope, "%s %s", time_buff, other_data);
*
* @param buf a user-supplied buffer
* @param len user-supplied length of the buffer
* @param cached_tm_mday a cached day of the month, as an integer. Setting this
* pointer different from NULL, to an integer value other than was retrieved as
* current day of the month, would add an additional line under the form of
* 'Date: Y-m-d Z\n'. Setting the pointer to NULL would not print any date, nor
* if the value matches the current day of month. Helps identify logs that
* spawn multiple days, while still having a shorter time stamp format.
* @ingroup log
*/
WL_EXPORT char *
weston_log_timestamp(char *buf, size_t len, int *cached_tm_mday)
{
struct timeval tv;
struct tm *brokendown_time;
char datestr[128];
char timestr[128];
gettimeofday(&tv, NULL);
brokendown_time = localtime(&tv.tv_sec);
if (brokendown_time == NULL) {
snprintf(buf, len, "%s", "[(NULL)localtime] ");
return buf;
}
memset(datestr, 0, sizeof(datestr));
if (cached_tm_mday && brokendown_time->tm_mday != *cached_tm_mday) {
strftime(datestr, sizeof(datestr), "Date: %Y-%m-%d %Z\n",
brokendown_time);
*cached_tm_mday = brokendown_time->tm_mday;
}
strftime(timestr, sizeof(timestr), "%H:%M:%S", brokendown_time);
/* if datestr is empty it prints only timestr*/
snprintf(buf, len, "%s[%s.%03li]", datestr,
timestr, (tv.tv_usec / 1000));
return buf;
}
void
weston_log_subscriber_release(struct weston_log_subscriber *subscriber)
{
-184
View File
@@ -1,184 +0,0 @@
/*
* Copyright © 2012 Scott Moreau
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <libweston/libweston.h>
#include "backend.h"
#include "libweston-internal.h"
#include "text-cursor-position-server-protocol.h"
#include "shared/helpers.h"
static void
weston_zoom_frame_z(struct weston_animation *animation,
struct weston_output *output,
const struct timespec *time)
{
if (animation->frame_counter <= 1)
output->zoom.spring_z.timestamp = *time;
weston_spring_update(&output->zoom.spring_z, time);
if (output->zoom.spring_z.current > output->zoom.max_level)
output->zoom.spring_z.current = output->zoom.max_level;
else if (output->zoom.spring_z.current < 0.0)
output->zoom.spring_z.current = 0.0;
if (weston_spring_done(&output->zoom.spring_z)) {
if (output->zoom.active && output->zoom.level <= 0.0) {
output->zoom.active = false;
output->zoom.seat = NULL;
weston_output_disable_planes_decr(output);
wl_list_remove(&output->zoom.motion_listener.link);
}
output->zoom.spring_z.current = output->zoom.level;
wl_list_remove(&animation->link);
wl_list_init(&animation->link);
}
output->dirty = 1;
weston_output_damage(output);
}
static void
zoom_area_center_from_point(struct weston_output *output,
double *x, double *y)
{
float level = output->zoom.spring_z.current;
*x = (*x - output->x) * level + output->width / 2.;
*y = (*y - output->y) * level + output->height / 2.;
}
static void
weston_output_update_zoom_transform(struct weston_output *output)
{
double x = output->zoom.current.x; /* global pointer coords */
double y = output->zoom.current.y;
float level;
level = output->zoom.spring_z.current;
if (!output->zoom.active || level > output->zoom.max_level ||
level == 0.0f)
return;
zoom_area_center_from_point(output, &x, &y);
output->zoom.trans_x = x - output->width / 2;
output->zoom.trans_y = y - output->height / 2;
if (output->zoom.trans_x < 0)
output->zoom.trans_x = 0;
if (output->zoom.trans_y < 0)
output->zoom.trans_y = 0;
if (output->zoom.trans_x > level * output->width)
output->zoom.trans_x = level * output->width;
if (output->zoom.trans_y > level * output->height)
output->zoom.trans_y = level * output->height;
}
static void
weston_zoom_transition(struct weston_output *output)
{
if (output->zoom.level != output->zoom.spring_z.current) {
output->zoom.spring_z.target = output->zoom.level;
if (wl_list_empty(&output->zoom.animation_z.link)) {
output->zoom.animation_z.frame_counter = 0;
wl_list_insert(output->animation_list.prev,
&output->zoom.animation_z.link);
}
}
output->dirty = 1;
weston_output_damage(output);
}
WL_EXPORT void
weston_output_update_zoom(struct weston_output *output)
{
struct weston_seat *seat = output->zoom.seat;
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
if (!pointer)
return;
assert(output->zoom.active);
output->zoom.current.x = wl_fixed_to_double(pointer->x);
output->zoom.current.y = wl_fixed_to_double(pointer->y);
weston_zoom_transition(output);
weston_output_update_zoom_transform(output);
}
static void
motion(struct wl_listener *listener, void *data)
{
struct weston_output_zoom *zoom =
container_of(listener, struct weston_output_zoom, motion_listener);
struct weston_output *output =
container_of(zoom, struct weston_output, zoom);
weston_output_update_zoom(output);
}
WL_EXPORT void
weston_output_activate_zoom(struct weston_output *output,
struct weston_seat *seat)
{
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
if (!pointer || output->zoom.active)
return;
output->zoom.active = true;
output->zoom.seat = seat;
weston_output_disable_planes_incr(output);
wl_signal_add(&pointer->motion_signal,
&output->zoom.motion_listener);
}
WL_EXPORT void
weston_output_init_zoom(struct weston_output *output)
{
output->zoom.active = false;
output->zoom.seat = NULL;
output->zoom.increment = 0.07;
output->zoom.max_level = 0.95;
output->zoom.level = 0.0;
output->zoom.trans_x = 0.0;
output->zoom.trans_y = 0.0;
weston_spring_init(&output->zoom.spring_z, 250.0, 0.0, 0.0);
output->zoom.spring_z.friction = 1000;
output->zoom.animation_z.frame = weston_zoom_frame_z;
wl_list_init(&output->zoom.animation_z.link);
output->zoom.motion_listener.notify = motion;
}