2010-06-11 20:56:24 +04:00
|
|
|
/*
|
Change remaining GPLv2 headers to MIT
The files in question are copyright Benjamin Franzke (who agrees),
Intel Corporation, Red Hat and myself. On behalf of Red Hat,
Richard Fontana says:
"Therefore, to the extent that Red Hat, Inc. has any copyright
interest in the files you cited as of this date (compositor-drm.c,
compositor.c, compositor.h, screenshooter.c in
http://cgit.freedesktop.org/wayland/wayland-demos/tree/compositor),
Red Hat hereby elects to apply the CC0 1.0 Universal Public Domain
Dedication to such copyrighted material. See:
http://creativecommons.org/publicdomain/zero/1.0/legalcode .
Thanks,
Richard E. Fontana
Open Source Licensing and Patent Counsel
Red Hat, Inc."
2011-09-15 23:43:14 +04:00
|
|
|
* Copyright © 2008-2011 Kristian Høgsberg
|
|
|
|
* Copyright © 2011 Intel Corporation
|
2010-06-11 20:56:24 +04:00
|
|
|
*
|
Change remaining GPLv2 headers to MIT
The files in question are copyright Benjamin Franzke (who agrees),
Intel Corporation, Red Hat and myself. On behalf of Red Hat,
Richard Fontana says:
"Therefore, to the extent that Red Hat, Inc. has any copyright
interest in the files you cited as of this date (compositor-drm.c,
compositor.c, compositor.h, screenshooter.c in
http://cgit.freedesktop.org/wayland/wayland-demos/tree/compositor),
Red Hat hereby elects to apply the CC0 1.0 Universal Public Domain
Dedication to such copyrighted material. See:
http://creativecommons.org/publicdomain/zero/1.0/legalcode .
Thanks,
Richard E. Fontana
Open Source Licensing and Patent Counsel
Red Hat, Inc."
2011-09-15 23:43:14 +04:00
|
|
|
* Permission to use, copy, modify, distribute, and sell this software and
|
|
|
|
* its documentation for any purpose is hereby granted without fee, provided
|
|
|
|
* that the above copyright notice appear in all copies and that both that
|
|
|
|
* copyright notice and this permission notice appear in supporting
|
|
|
|
* documentation, and that the name of the copyright holders not be used in
|
|
|
|
* advertising or publicity pertaining to distribution of the software
|
|
|
|
* without specific, written prior permission. The copyright holders make
|
|
|
|
* no representations about the suitability of this software for any
|
|
|
|
* purpose. It is provided "as is" without express or implied warranty.
|
2010-06-11 20:56:24 +04:00
|
|
|
*
|
Change remaining GPLv2 headers to MIT
The files in question are copyright Benjamin Franzke (who agrees),
Intel Corporation, Red Hat and myself. On behalf of Red Hat,
Richard Fontana says:
"Therefore, to the extent that Red Hat, Inc. has any copyright
interest in the files you cited as of this date (compositor-drm.c,
compositor.c, compositor.h, screenshooter.c in
http://cgit.freedesktop.org/wayland/wayland-demos/tree/compositor),
Red Hat hereby elects to apply the CC0 1.0 Universal Public Domain
Dedication to such copyrighted material. See:
http://creativecommons.org/publicdomain/zero/1.0/legalcode .
Thanks,
Richard E. Fontana
Open Source Licensing and Patent Counsel
Red Hat, Inc."
2011-09-15 23:43:14 +04:00
|
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
|
|
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
|
|
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
|
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
|
|
|
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
|
|
|
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
2010-06-11 20:56:24 +04:00
|
|
|
*/
|
|
|
|
|
2013-05-22 19:03:19 +04:00
|
|
|
#include "config.h"
|
2011-04-12 19:34:32 +04:00
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
#include <errno.h>
|
2010-06-11 20:56:24 +04:00
|
|
|
#include <stdlib.h>
|
2013-04-24 17:58:02 +04:00
|
|
|
#include <ctype.h>
|
2010-06-11 20:56:24 +04:00
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
2012-04-10 08:11:50 +04:00
|
|
|
#include <linux/input.h>
|
2013-09-19 10:00:17 +04:00
|
|
|
#include <linux/vt.h>
|
2012-06-26 18:09:14 +04:00
|
|
|
#include <assert.h>
|
2013-01-25 17:13:04 +04:00
|
|
|
#include <sys/mman.h>
|
2013-10-14 16:57:11 +04:00
|
|
|
#include <dlfcn.h>
|
2013-05-07 15:16:59 +04:00
|
|
|
#include <time.h>
|
2010-06-11 20:56:24 +04:00
|
|
|
|
2011-03-02 13:56:04 +03:00
|
|
|
#include <xf86drm.h>
|
|
|
|
#include <xf86drmMode.h>
|
2012-02-23 18:45:49 +04:00
|
|
|
#include <drm_fourcc.h>
|
2011-03-02 13:56:04 +03:00
|
|
|
|
2011-04-30 11:32:11 +04:00
|
|
|
#include <gbm.h>
|
2012-08-03 21:30:30 +04:00
|
|
|
#include <libudev.h>
|
2011-04-30 11:32:11 +04:00
|
|
|
|
2014-01-28 11:02:35 +04:00
|
|
|
#include "libbacklight.h"
|
2010-06-11 20:56:24 +04:00
|
|
|
#include "compositor.h"
|
2012-11-13 22:10:28 +04:00
|
|
|
#include "gl-renderer.h"
|
2013-01-25 17:13:05 +04:00
|
|
|
#include "pixman-renderer.h"
|
2014-03-13 01:08:42 +04:00
|
|
|
#include "udev-input.h"
|
2012-01-30 17:04:04 +04:00
|
|
|
#include "launcher-util.h"
|
2013-08-23 18:15:48 +04:00
|
|
|
#include "vaapi-recorder.h"
|
2010-06-11 20:56:24 +04:00
|
|
|
|
2013-05-07 15:16:59 +04:00
|
|
|
#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
|
|
|
|
#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
|
|
|
|
#endif
|
|
|
|
|
2014-07-29 01:30:17 +04:00
|
|
|
#ifndef DRM_CAP_CURSOR_WIDTH
|
|
|
|
#define DRM_CAP_CURSOR_WIDTH 0x8
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef DRM_CAP_CURSOR_HEIGHT
|
|
|
|
#define DRM_CAP_CURSOR_HEIGHT 0x9
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef GBM_BO_USE_CURSOR
|
|
|
|
#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
|
|
|
|
#endif
|
|
|
|
|
2012-06-28 19:28:15 +04:00
|
|
|
static int option_current_mode = 0;
|
2012-07-31 05:51:08 +04:00
|
|
|
|
|
|
|
enum output_config {
|
|
|
|
OUTPUT_CONFIG_INVALID = 0,
|
|
|
|
OUTPUT_CONFIG_OFF,
|
|
|
|
OUTPUT_CONFIG_PREFERRED,
|
|
|
|
OUTPUT_CONFIG_CURRENT,
|
2012-08-01 01:30:41 +04:00
|
|
|
OUTPUT_CONFIG_MODE,
|
|
|
|
OUTPUT_CONFIG_MODELINE
|
2012-07-31 05:51:08 +04:00
|
|
|
};
|
|
|
|
|
2010-06-14 19:54:00 +04:00
|
|
|
struct drm_compositor {
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
struct weston_compositor base;
|
2010-06-14 19:54:00 +04:00
|
|
|
|
|
|
|
struct udev *udev;
|
|
|
|
struct wl_event_source *drm_source;
|
|
|
|
|
2011-03-15 17:08:41 +03:00
|
|
|
struct udev_monitor *udev_monitor;
|
|
|
|
struct wl_event_source *udev_drm_source;
|
|
|
|
|
2011-03-02 13:14:59 +03:00
|
|
|
struct {
|
2012-03-11 23:05:21 +04:00
|
|
|
int id;
|
2011-03-02 13:14:59 +03:00
|
|
|
int fd;
|
2013-08-23 18:15:48 +04:00
|
|
|
char *filename;
|
2011-03-02 13:14:59 +03:00
|
|
|
} drm;
|
2011-04-30 11:32:11 +04:00
|
|
|
struct gbm_device *gbm;
|
2012-02-23 18:45:49 +04:00
|
|
|
uint32_t *crtcs;
|
|
|
|
int num_crtcs;
|
2011-02-10 03:01:42 +03:00
|
|
|
uint32_t crtc_allocator;
|
2011-03-15 17:08:41 +03:00
|
|
|
uint32_t connector_allocator;
|
2013-09-18 03:02:57 +04:00
|
|
|
struct wl_listener session_listener;
|
2013-09-26 02:46:42 +04:00
|
|
|
uint32_t format;
|
2011-12-02 15:07:27 +04:00
|
|
|
|
2012-08-09 23:18:28 +04:00
|
|
|
/* we need these parameters in order to not fail drmModeAddFB2()
|
|
|
|
* due to out of bounds dimensions, and then mistakenly set
|
|
|
|
* sprites_are_broken:
|
|
|
|
*/
|
2012-11-09 16:19:05 +04:00
|
|
|
uint32_t min_width, max_width;
|
|
|
|
uint32_t min_height, max_height;
|
|
|
|
int no_addfb2;
|
2012-08-09 23:18:28 +04:00
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
struct wl_list sprite_list;
|
2012-03-06 04:57:35 +04:00
|
|
|
int sprites_are_broken;
|
2012-10-31 19:55:46 +04:00
|
|
|
int sprites_hidden;
|
2012-02-23 18:45:49 +04:00
|
|
|
|
2012-08-09 22:24:45 +04:00
|
|
|
int cursors_are_broken;
|
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
int use_pixman;
|
|
|
|
|
2011-12-02 15:07:27 +04:00
|
|
|
uint32_t prev_state;
|
2013-05-07 15:16:59 +04:00
|
|
|
|
2013-05-31 21:09:55 +04:00
|
|
|
struct udev_input input;
|
2014-07-29 01:30:17 +04:00
|
|
|
|
|
|
|
uint32_t cursor_width;
|
|
|
|
uint32_t cursor_height;
|
2010-06-14 19:54:00 +04:00
|
|
|
};
|
|
|
|
|
2011-06-21 19:16:58 +04:00
|
|
|
struct drm_mode {
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
struct weston_mode base;
|
2011-06-21 19:16:58 +04:00
|
|
|
drmModeModeInfo mode_info;
|
|
|
|
};
|
|
|
|
|
2012-05-02 17:42:21 +04:00
|
|
|
struct drm_output;
|
|
|
|
|
|
|
|
struct drm_fb {
|
|
|
|
struct drm_output *output;
|
2013-01-25 17:13:04 +04:00
|
|
|
uint32_t fb_id, stride, handle, size;
|
|
|
|
int fd;
|
2012-05-02 17:42:21 +04:00
|
|
|
int is_client_buffer;
|
compositor: introduce weston_buffer_reference
The wl_buffer reference counting API has been inconsistent. You would
manually increment the refcount and register a destroy listener, as
opposed to calling weston_buffer_post_release(), which internally
decremented the refcount, and then removing a list item.
Replace both cases with a single function:
weston_buffer_reference(weston_buffer_reference *ref, wl_buffer *buffer)
Buffer is assigned to ref->buffer, while taking care of all the refcounting
and release posting. You take a reference by passing a non-NULL buffer, and
release a reference by passing NULL as buffer. The function uses an
internal wl_buffer destroy listener, so the pointer gets reset on
destruction automatically.
This is inspired by the pipe_resource_reference() of Mesa, and modified
by krh's suggestion to add struct weston_buffer_reference.
Additionally, when a surface gets destroyed, the associated wl_buffer
will send a release event. Often the buffer is already destroyed on
client side, so the event will be discarded by libwayland-client.
Compositor-drm.c is converted to use weston_buffer_reference.
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2012-12-04 17:58:12 +04:00
|
|
|
struct weston_buffer_reference buffer_ref;
|
2013-01-25 17:13:04 +04:00
|
|
|
|
|
|
|
/* Used by gbm fbs */
|
|
|
|
struct gbm_bo *bo;
|
|
|
|
|
|
|
|
/* Used by dumb fbs */
|
|
|
|
void *map;
|
2012-05-02 17:42:21 +04:00
|
|
|
};
|
|
|
|
|
2013-04-24 17:58:02 +04:00
|
|
|
struct drm_edid {
|
|
|
|
char eisa_id[13];
|
|
|
|
char monitor_name[13];
|
|
|
|
char pnp_id[5];
|
|
|
|
char serial_number[13];
|
|
|
|
};
|
|
|
|
|
2010-06-14 19:54:00 +04:00
|
|
|
struct drm_output {
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
struct weston_output base;
|
2010-06-14 19:54:00 +04:00
|
|
|
|
|
|
|
uint32_t crtc_id;
|
2012-08-09 05:27:37 +04:00
|
|
|
int pipe;
|
2010-06-14 19:54:00 +04:00
|
|
|
uint32_t connector_id;
|
2011-08-30 00:52:23 +04:00
|
|
|
drmModeCrtcPtr original_crtc;
|
2013-04-24 17:58:02 +04:00
|
|
|
struct drm_edid edid;
|
2013-06-04 17:24:04 +04:00
|
|
|
drmModePropertyPtr dpms_prop;
|
2014-03-07 22:05:50 +04:00
|
|
|
uint32_t format;
|
2012-03-12 02:27:41 +04:00
|
|
|
|
2012-06-26 18:09:13 +04:00
|
|
|
int vblank_pending;
|
|
|
|
int page_flip_pending;
|
2013-10-11 10:43:07 +04:00
|
|
|
int destroy_pending;
|
2012-06-26 18:09:13 +04:00
|
|
|
|
2012-03-12 02:27:41 +04:00
|
|
|
struct gbm_surface *surface;
|
2012-05-03 19:39:35 +04:00
|
|
|
struct gbm_bo *cursor_bo[2];
|
2012-08-03 19:30:18 +04:00
|
|
|
struct weston_plane cursor_plane;
|
|
|
|
struct weston_plane fb_plane;
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
struct weston_view *cursor_view;
|
2012-08-03 19:50:05 +04:00
|
|
|
int current_cursor;
|
2012-05-02 17:42:21 +04:00
|
|
|
struct drm_fb *current, *next;
|
2012-02-29 21:53:50 +04:00
|
|
|
struct backlight *backlight;
|
2013-01-25 17:13:05 +04:00
|
|
|
|
|
|
|
struct drm_fb *dumb[2];
|
|
|
|
pixman_image_t *image[2];
|
|
|
|
int current_image;
|
|
|
|
pixman_region32_t previous_damage;
|
2013-08-23 18:15:48 +04:00
|
|
|
|
|
|
|
struct vaapi_recorder *recorder;
|
|
|
|
struct wl_listener recorder_frame_listener;
|
2010-06-14 19:54:00 +04:00
|
|
|
};
|
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
/*
|
|
|
|
* An output has a primary display plane plus zero or more sprites for
|
|
|
|
* blending display contents.
|
|
|
|
*/
|
|
|
|
struct drm_sprite {
|
|
|
|
struct wl_list link;
|
|
|
|
|
2012-08-03 19:30:18 +04:00
|
|
|
struct weston_plane plane;
|
2012-02-23 18:45:49 +04:00
|
|
|
|
2012-11-09 16:19:05 +04:00
|
|
|
struct drm_fb *current, *next;
|
2012-06-26 18:09:13 +04:00
|
|
|
struct drm_output *output;
|
2012-02-23 18:45:49 +04:00
|
|
|
struct drm_compositor *compositor;
|
|
|
|
|
|
|
|
uint32_t possible_crtcs;
|
|
|
|
uint32_t plane_id;
|
|
|
|
uint32_t count_formats;
|
|
|
|
|
|
|
|
int32_t src_x, src_y;
|
|
|
|
uint32_t src_w, src_h;
|
|
|
|
uint32_t dest_x, dest_y;
|
|
|
|
uint32_t dest_w, dest_h;
|
|
|
|
|
|
|
|
uint32_t formats[];
|
|
|
|
};
|
|
|
|
|
2013-10-17 03:15:11 +04:00
|
|
|
struct drm_parameters {
|
|
|
|
int connector;
|
|
|
|
int tty;
|
|
|
|
int use_pixman;
|
|
|
|
const char *seat_id;
|
|
|
|
};
|
|
|
|
|
2013-10-14 16:57:11 +04:00
|
|
|
static struct gl_renderer_interface *gl_renderer;
|
|
|
|
|
2013-02-19 01:15:53 +04:00
|
|
|
static const char default_seat[] = "seat0";
|
2012-08-03 21:30:30 +04:00
|
|
|
|
2012-08-03 19:50:05 +04:00
|
|
|
static void
|
|
|
|
drm_output_set_cursor(struct drm_output *output);
|
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
static int
|
|
|
|
drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
|
|
|
|
{
|
|
|
|
struct weston_compositor *ec = output_base->compositor;
|
|
|
|
struct drm_compositor *c =(struct drm_compositor *) ec;
|
|
|
|
struct drm_output *output = (struct drm_output *) output_base;
|
|
|
|
int crtc;
|
|
|
|
|
|
|
|
for (crtc = 0; crtc < c->num_crtcs; crtc++) {
|
|
|
|
if (c->crtcs[crtc] != output->crtc_id)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (supported & (1 << crtc))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-02 17:42:21 +04:00
|
|
|
static void
|
|
|
|
drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
|
|
|
|
{
|
|
|
|
struct drm_fb *fb = data;
|
|
|
|
struct gbm_device *gbm = gbm_bo_get_device(bo);
|
|
|
|
|
|
|
|
if (fb->fb_id)
|
|
|
|
drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
|
|
|
|
|
compositor: introduce weston_buffer_reference
The wl_buffer reference counting API has been inconsistent. You would
manually increment the refcount and register a destroy listener, as
opposed to calling weston_buffer_post_release(), which internally
decremented the refcount, and then removing a list item.
Replace both cases with a single function:
weston_buffer_reference(weston_buffer_reference *ref, wl_buffer *buffer)
Buffer is assigned to ref->buffer, while taking care of all the refcounting
and release posting. You take a reference by passing a non-NULL buffer, and
release a reference by passing NULL as buffer. The function uses an
internal wl_buffer destroy listener, so the pointer gets reset on
destruction automatically.
This is inspired by the pipe_resource_reference() of Mesa, and modified
by krh's suggestion to add struct weston_buffer_reference.
Additionally, when a surface gets destroyed, the associated wl_buffer
will send a release event. Often the buffer is already destroyed on
client side, so the event will be discarded by libwayland-client.
Compositor-drm.c is converted to use weston_buffer_reference.
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2012-12-04 17:58:12 +04:00
|
|
|
weston_buffer_reference(&fb->buffer_ref, NULL);
|
2012-05-02 17:42:21 +04:00
|
|
|
|
|
|
|
free(data);
|
|
|
|
}
|
|
|
|
|
2013-01-25 17:13:04 +04:00
|
|
|
static struct drm_fb *
|
|
|
|
drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
|
|
|
|
{
|
|
|
|
struct drm_fb *fb;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
struct drm_mode_create_dumb create_arg;
|
|
|
|
struct drm_mode_destroy_dumb destroy_arg;
|
|
|
|
struct drm_mode_map_dumb map_arg;
|
|
|
|
|
2013-08-08 05:57:05 +04:00
|
|
|
fb = zalloc(sizeof *fb);
|
2013-01-25 17:13:04 +04:00
|
|
|
if (!fb)
|
|
|
|
return NULL;
|
|
|
|
|
2013-08-22 09:14:14 +04:00
|
|
|
memset(&create_arg, 0, sizeof create_arg);
|
2013-01-25 17:13:04 +04:00
|
|
|
create_arg.bpp = 32;
|
|
|
|
create_arg.width = width;
|
|
|
|
create_arg.height = height;
|
|
|
|
|
|
|
|
ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
|
|
|
|
if (ret)
|
|
|
|
goto err_fb;
|
|
|
|
|
|
|
|
fb->handle = create_arg.handle;
|
|
|
|
fb->stride = create_arg.pitch;
|
|
|
|
fb->size = create_arg.size;
|
|
|
|
fb->fd = ec->drm.fd;
|
|
|
|
|
|
|
|
ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
|
|
|
|
fb->stride, fb->handle, &fb->fb_id);
|
|
|
|
if (ret)
|
|
|
|
goto err_bo;
|
|
|
|
|
2013-08-22 09:14:14 +04:00
|
|
|
memset(&map_arg, 0, sizeof map_arg);
|
2013-01-25 17:13:04 +04:00
|
|
|
map_arg.handle = fb->handle;
|
2013-05-02 05:26:02 +04:00
|
|
|
ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
|
2013-01-25 17:13:04 +04:00
|
|
|
if (ret)
|
|
|
|
goto err_add_fb;
|
|
|
|
|
|
|
|
fb->map = mmap(0, fb->size, PROT_WRITE,
|
|
|
|
MAP_SHARED, ec->drm.fd, map_arg.offset);
|
|
|
|
if (fb->map == MAP_FAILED)
|
|
|
|
goto err_add_fb;
|
|
|
|
|
|
|
|
return fb;
|
|
|
|
|
|
|
|
err_add_fb:
|
|
|
|
drmModeRmFB(ec->drm.fd, fb->fb_id);
|
|
|
|
err_bo:
|
|
|
|
memset(&destroy_arg, 0, sizeof(destroy_arg));
|
|
|
|
destroy_arg.handle = create_arg.handle;
|
|
|
|
drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
|
|
|
|
err_fb:
|
|
|
|
free(fb);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drm_fb_destroy_dumb(struct drm_fb *fb)
|
|
|
|
{
|
|
|
|
struct drm_mode_destroy_dumb destroy_arg;
|
|
|
|
|
|
|
|
if (!fb->map)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (fb->fb_id)
|
|
|
|
drmModeRmFB(fb->fd, fb->fb_id);
|
|
|
|
|
|
|
|
weston_buffer_reference(&fb->buffer_ref, NULL);
|
|
|
|
|
|
|
|
munmap(fb->map, fb->size);
|
|
|
|
|
|
|
|
memset(&destroy_arg, 0, sizeof(destroy_arg));
|
|
|
|
destroy_arg.handle = fb->handle;
|
|
|
|
drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
|
|
|
|
|
|
|
|
free(fb);
|
|
|
|
}
|
|
|
|
|
2012-05-02 17:42:21 +04:00
|
|
|
static struct drm_fb *
|
2012-12-07 21:37:58 +04:00
|
|
|
drm_fb_get_from_bo(struct gbm_bo *bo,
|
|
|
|
struct drm_compositor *compositor, uint32_t format)
|
2012-05-02 17:42:21 +04:00
|
|
|
{
|
|
|
|
struct drm_fb *fb = gbm_bo_get_user_data(bo);
|
2013-01-25 17:13:04 +04:00
|
|
|
uint32_t width, height;
|
2012-11-09 16:19:05 +04:00
|
|
|
uint32_t handles[4], pitches[4], offsets[4];
|
2012-05-02 17:42:21 +04:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (fb)
|
|
|
|
return fb;
|
|
|
|
|
2013-01-25 17:13:04 +04:00
|
|
|
fb = calloc(1, sizeof *fb);
|
|
|
|
if (!fb)
|
|
|
|
return NULL;
|
2012-05-02 17:42:21 +04:00
|
|
|
|
|
|
|
fb->bo = bo;
|
|
|
|
|
|
|
|
width = gbm_bo_get_width(bo);
|
|
|
|
height = gbm_bo_get_height(bo);
|
2013-01-25 17:13:04 +04:00
|
|
|
fb->stride = gbm_bo_get_stride(bo);
|
|
|
|
fb->handle = gbm_bo_get_handle(bo).u32;
|
|
|
|
fb->size = fb->stride * height;
|
|
|
|
fb->fd = compositor->drm.fd;
|
2012-05-02 17:42:21 +04:00
|
|
|
|
2012-11-09 16:19:05 +04:00
|
|
|
if (compositor->min_width > width || width > compositor->max_width ||
|
|
|
|
compositor->min_height > height ||
|
|
|
|
height > compositor->max_height) {
|
|
|
|
weston_log("bo geometry out of bounds\n");
|
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
if (format && !compositor->no_addfb2) {
|
2013-01-25 17:13:04 +04:00
|
|
|
handles[0] = fb->handle;
|
|
|
|
pitches[0] = fb->stride;
|
2012-11-09 16:19:05 +04:00
|
|
|
offsets[0] = 0;
|
|
|
|
|
|
|
|
ret = drmModeAddFB2(compositor->drm.fd, width, height,
|
|
|
|
format, handles, pitches, offsets,
|
|
|
|
&fb->fb_id, 0);
|
|
|
|
if (ret) {
|
|
|
|
weston_log("addfb2 failed: %m\n");
|
|
|
|
compositor->no_addfb2 = 1;
|
|
|
|
compositor->sprites_are_broken = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
|
2013-01-25 17:13:04 +04:00
|
|
|
fb->stride, fb->handle, &fb->fb_id);
|
2012-11-09 16:19:05 +04:00
|
|
|
|
2012-05-02 17:42:21 +04:00
|
|
|
if (ret) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("failed to create kms fb: %m\n");
|
2012-11-09 16:19:05 +04:00
|
|
|
goto err_free;
|
2012-05-02 17:42:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
|
|
|
|
|
|
|
|
return fb;
|
2012-11-09 16:19:05 +04:00
|
|
|
|
|
|
|
err_free:
|
|
|
|
free(fb);
|
|
|
|
return NULL;
|
2012-05-02 17:42:21 +04:00
|
|
|
}
|
|
|
|
|
2012-11-09 16:19:05 +04:00
|
|
|
static void
|
2013-06-21 05:38:23 +04:00
|
|
|
drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
|
2012-11-09 16:19:05 +04:00
|
|
|
{
|
compositor: introduce weston_buffer_reference
The wl_buffer reference counting API has been inconsistent. You would
manually increment the refcount and register a destroy listener, as
opposed to calling weston_buffer_post_release(), which internally
decremented the refcount, and then removing a list item.
Replace both cases with a single function:
weston_buffer_reference(weston_buffer_reference *ref, wl_buffer *buffer)
Buffer is assigned to ref->buffer, while taking care of all the refcounting
and release posting. You take a reference by passing a non-NULL buffer, and
release a reference by passing NULL as buffer. The function uses an
internal wl_buffer destroy listener, so the pointer gets reset on
destruction automatically.
This is inspired by the pipe_resource_reference() of Mesa, and modified
by krh's suggestion to add struct weston_buffer_reference.
Additionally, when a surface gets destroyed, the associated wl_buffer
will send a release event. Often the buffer is already destroyed on
client side, so the event will be discarded by libwayland-client.
Compositor-drm.c is converted to use weston_buffer_reference.
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2012-12-04 17:58:12 +04:00
|
|
|
assert(fb->buffer_ref.buffer == NULL);
|
2012-11-09 16:19:05 +04:00
|
|
|
|
|
|
|
fb->is_client_buffer = 1;
|
|
|
|
|
compositor: introduce weston_buffer_reference
The wl_buffer reference counting API has been inconsistent. You would
manually increment the refcount and register a destroy listener, as
opposed to calling weston_buffer_post_release(), which internally
decremented the refcount, and then removing a list item.
Replace both cases with a single function:
weston_buffer_reference(weston_buffer_reference *ref, wl_buffer *buffer)
Buffer is assigned to ref->buffer, while taking care of all the refcounting
and release posting. You take a reference by passing a non-NULL buffer, and
release a reference by passing NULL as buffer. The function uses an
internal wl_buffer destroy listener, so the pointer gets reset on
destruction automatically.
This is inspired by the pipe_resource_reference() of Mesa, and modified
by krh's suggestion to add struct weston_buffer_reference.
Additionally, when a surface gets destroyed, the associated wl_buffer
will send a release event. Often the buffer is already destroyed on
client side, so the event will be discarded by libwayland-client.
Compositor-drm.c is converted to use weston_buffer_reference.
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2012-12-04 17:58:12 +04:00
|
|
|
weston_buffer_reference(&fb->buffer_ref, buffer);
|
2012-11-09 16:19:05 +04:00
|
|
|
}
|
|
|
|
|
2013-01-25 17:13:03 +04:00
|
|
|
static void
|
|
|
|
drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
|
|
|
|
{
|
|
|
|
if (!fb)
|
|
|
|
return;
|
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
if (fb->map &&
|
|
|
|
(fb != output->dumb[0] && fb != output->dumb[1])) {
|
2013-01-25 17:13:04 +04:00
|
|
|
drm_fb_destroy_dumb(fb);
|
|
|
|
} else if (fb->bo) {
|
2013-01-25 17:13:03 +04:00
|
|
|
if (fb->is_client_buffer)
|
|
|
|
gbm_bo_destroy(fb->bo);
|
|
|
|
else
|
|
|
|
gbm_surface_release_buffer(output->surface,
|
2013-11-15 06:52:35 +04:00
|
|
|
fb->bo);
|
2013-01-25 17:13:03 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-07 21:37:58 +04:00
|
|
|
static uint32_t
|
2012-11-30 19:34:22 +04:00
|
|
|
drm_output_check_scanout_format(struct drm_output *output,
|
|
|
|
struct weston_surface *es, struct gbm_bo *bo)
|
|
|
|
{
|
|
|
|
uint32_t format;
|
|
|
|
pixman_region32_t r;
|
|
|
|
|
|
|
|
format = gbm_bo_get_format(bo);
|
|
|
|
|
2013-10-17 03:08:57 +04:00
|
|
|
if (format == GBM_FORMAT_ARGB8888) {
|
|
|
|
/* We can scanout an ARGB buffer if the surface's
|
|
|
|
* opaque region covers the whole output, but we have
|
|
|
|
* to use XRGB as the KMS format code. */
|
2014-01-18 02:22:41 +04:00
|
|
|
pixman_region32_init_rect(&r, 0, 0,
|
|
|
|
output->base.width,
|
|
|
|
output->base.height);
|
|
|
|
pixman_region32_subtract(&r, &r, &es->opaque);
|
2012-11-30 19:34:22 +04:00
|
|
|
|
|
|
|
if (!pixman_region32_not_empty(&r))
|
2012-12-07 21:37:58 +04:00
|
|
|
format = GBM_FORMAT_XRGB8888;
|
2012-11-30 19:34:22 +04:00
|
|
|
|
|
|
|
pixman_region32_fini(&r);
|
2013-10-17 03:08:57 +04:00
|
|
|
}
|
2012-11-30 19:34:22 +04:00
|
|
|
|
2014-03-07 22:05:50 +04:00
|
|
|
if (output->format == format)
|
2012-12-07 21:37:58 +04:00
|
|
|
return format;
|
2013-10-17 03:08:57 +04:00
|
|
|
|
|
|
|
return 0;
|
2012-11-30 19:34:22 +04:00
|
|
|
}
|
|
|
|
|
2012-08-03 19:30:18 +04:00
|
|
|
static struct weston_plane *
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
drm_output_prepare_scanout_view(struct weston_output *_output,
|
|
|
|
struct weston_view *ev)
|
2012-01-26 08:59:42 +04:00
|
|
|
{
|
2012-07-14 08:31:32 +04:00
|
|
|
struct drm_output *output = (struct drm_output *) _output;
|
2012-01-26 08:59:42 +04:00
|
|
|
struct drm_compositor *c =
|
|
|
|
(struct drm_compositor *) output->base.compositor;
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
|
2014-03-14 16:38:15 +04:00
|
|
|
struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
|
2012-05-02 17:42:21 +04:00
|
|
|
struct gbm_bo *bo;
|
2012-12-07 21:37:58 +04:00
|
|
|
uint32_t format;
|
2012-01-26 08:59:42 +04:00
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
if (ev->geometry.x != output->base.x ||
|
|
|
|
ev->geometry.y != output->base.y ||
|
2013-01-25 17:13:05 +04:00
|
|
|
buffer == NULL || c->gbm == NULL ||
|
2013-09-19 01:56:35 +04:00
|
|
|
buffer->width != output->base.current_mode->width ||
|
|
|
|
buffer->height != output->base.current_mode->height ||
|
2014-03-14 16:38:15 +04:00
|
|
|
output->base.transform != viewport->buffer.transform ||
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
ev->transform.enabled)
|
2012-08-03 19:30:18 +04:00
|
|
|
return NULL;
|
2012-01-26 08:59:42 +04:00
|
|
|
|
2012-07-14 06:54:43 +04:00
|
|
|
bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
|
2013-09-04 09:27:08 +04:00
|
|
|
buffer->resource, GBM_BO_USE_SCANOUT);
|
2012-05-02 17:42:21 +04:00
|
|
|
|
2012-09-15 02:25:41 +04:00
|
|
|
/* Unable to use the buffer for scanout */
|
|
|
|
if (!bo)
|
|
|
|
return NULL;
|
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
format = drm_output_check_scanout_format(output, ev->surface, bo);
|
2012-12-07 21:37:58 +04:00
|
|
|
if (format == 0) {
|
2012-05-02 17:42:22 +04:00
|
|
|
gbm_bo_destroy(bo);
|
2012-08-03 19:30:18 +04:00
|
|
|
return NULL;
|
2012-05-02 17:42:22 +04:00
|
|
|
}
|
|
|
|
|
2012-12-07 21:37:58 +04:00
|
|
|
output->next = drm_fb_get_from_bo(bo, c, format);
|
2012-05-02 17:42:21 +04:00
|
|
|
if (!output->next) {
|
|
|
|
gbm_bo_destroy(bo);
|
2012-08-03 19:30:18 +04:00
|
|
|
return NULL;
|
2012-05-02 17:42:21 +04:00
|
|
|
}
|
2012-01-26 08:59:42 +04:00
|
|
|
|
compositor: introduce weston_buffer_reference
The wl_buffer reference counting API has been inconsistent. You would
manually increment the refcount and register a destroy listener, as
opposed to calling weston_buffer_post_release(), which internally
decremented the refcount, and then removing a list item.
Replace both cases with a single function:
weston_buffer_reference(weston_buffer_reference *ref, wl_buffer *buffer)
Buffer is assigned to ref->buffer, while taking care of all the refcounting
and release posting. You take a reference by passing a non-NULL buffer, and
release a reference by passing NULL as buffer. The function uses an
internal wl_buffer destroy listener, so the pointer gets reset on
destruction automatically.
This is inspired by the pipe_resource_reference() of Mesa, and modified
by krh's suggestion to add struct weston_buffer_reference.
Additionally, when a surface gets destroyed, the associated wl_buffer
will send a release event. Often the buffer is already destroyed on
client side, so the event will be discarded by libwayland-client.
Compositor-drm.c is converted to use weston_buffer_reference.
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2012-12-04 17:58:12 +04:00
|
|
|
drm_fb_set_buffer(output->next, buffer);
|
2012-01-26 08:59:42 +04:00
|
|
|
|
2012-08-03 19:30:18 +04:00
|
|
|
return &output->fb_plane;
|
2012-01-26 08:59:42 +04:00
|
|
|
}
|
|
|
|
|
2012-03-12 02:27:41 +04:00
|
|
|
static void
|
2013-01-25 17:13:05 +04:00
|
|
|
drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
|
2012-03-12 02:27:41 +04:00
|
|
|
{
|
2012-11-09 16:19:05 +04:00
|
|
|
struct drm_compositor *c =
|
|
|
|
(struct drm_compositor *) output->base.compositor;
|
2012-05-02 17:42:21 +04:00
|
|
|
struct gbm_bo *bo;
|
2012-03-12 02:27:41 +04:00
|
|
|
|
2012-11-09 16:19:05 +04:00
|
|
|
c->base.renderer->repaint_output(&output->base, damage);
|
2012-03-12 02:27:41 +04:00
|
|
|
|
2012-05-02 17:42:21 +04:00
|
|
|
bo = gbm_surface_lock_front_buffer(output->surface);
|
|
|
|
if (!bo) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("failed to lock front buffer: %m\n");
|
2012-03-12 02:27:41 +04:00
|
|
|
return;
|
|
|
|
}
|
2012-05-02 17:42:21 +04:00
|
|
|
|
2014-03-07 22:05:50 +04:00
|
|
|
output->next = drm_fb_get_from_bo(bo, c, output->format);
|
2012-05-02 17:42:21 +04:00
|
|
|
if (!output->next) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("failed to get drm_fb for bo\n");
|
2012-05-02 17:42:21 +04:00
|
|
|
gbm_surface_release_buffer(output->surface, bo);
|
|
|
|
return;
|
|
|
|
}
|
2012-03-12 02:27:41 +04:00
|
|
|
}
|
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
static void
|
|
|
|
drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
|
|
|
|
{
|
|
|
|
struct weston_compositor *ec = output->base.compositor;
|
|
|
|
pixman_region32_t total_damage, previous_damage;
|
|
|
|
|
|
|
|
pixman_region32_init(&total_damage);
|
|
|
|
pixman_region32_init(&previous_damage);
|
|
|
|
|
|
|
|
pixman_region32_copy(&previous_damage, damage);
|
|
|
|
|
|
|
|
pixman_region32_union(&total_damage, damage, &output->previous_damage);
|
|
|
|
pixman_region32_copy(&output->previous_damage, &previous_damage);
|
|
|
|
|
|
|
|
output->current_image ^= 1;
|
|
|
|
|
|
|
|
output->next = output->dumb[output->current_image];
|
|
|
|
pixman_renderer_output_set_buffer(&output->base,
|
|
|
|
output->image[output->current_image]);
|
|
|
|
|
|
|
|
ec->renderer->repaint_output(&output->base, &total_damage);
|
|
|
|
|
|
|
|
pixman_region32_fini(&total_damage);
|
|
|
|
pixman_region32_fini(&previous_damage);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drm_output_render(struct drm_output *output, pixman_region32_t *damage)
|
|
|
|
{
|
|
|
|
struct drm_compositor *c =
|
|
|
|
(struct drm_compositor *) output->base.compositor;
|
|
|
|
|
|
|
|
if (c->use_pixman)
|
|
|
|
drm_output_render_pixman(output, damage);
|
|
|
|
else
|
|
|
|
drm_output_render_gl(output, damage);
|
|
|
|
|
|
|
|
pixman_region32_subtract(&c->base.primary_plane.damage,
|
|
|
|
&c->base.primary_plane.damage, damage);
|
|
|
|
}
|
|
|
|
|
2013-05-02 00:52:12 +04:00
|
|
|
static void
|
|
|
|
drm_output_set_gamma(struct weston_output *output_base,
|
|
|
|
uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct drm_output *output = (struct drm_output *) output_base;
|
|
|
|
struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
|
|
|
|
|
|
|
|
/* check */
|
|
|
|
if (output_base->gamma_size != size)
|
|
|
|
return;
|
|
|
|
if (!output->original_crtc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rc = drmModeCrtcSetGamma(compositor->drm.fd,
|
|
|
|
output->crtc_id,
|
|
|
|
size, r, g, b);
|
|
|
|
if (rc)
|
|
|
|
weston_log("set gamma failed: %m\n");
|
|
|
|
}
|
|
|
|
|
2013-10-22 19:11:26 +04:00
|
|
|
static int
|
2012-02-29 07:31:58 +04:00
|
|
|
drm_output_repaint(struct weston_output *output_base,
|
2012-09-06 05:54:15 +04:00
|
|
|
pixman_region32_t *damage)
|
2011-03-11 18:39:20 +03:00
|
|
|
{
|
|
|
|
struct drm_output *output = (struct drm_output *) output_base;
|
2012-01-26 08:47:45 +04:00
|
|
|
struct drm_compositor *compositor =
|
|
|
|
(struct drm_compositor *) output->base.compositor;
|
2012-02-23 18:45:49 +04:00
|
|
|
struct drm_sprite *s;
|
2012-03-12 02:27:41 +04:00
|
|
|
struct drm_mode *mode;
|
2012-02-23 18:45:49 +04:00
|
|
|
int ret = 0;
|
2011-03-11 18:39:20 +03:00
|
|
|
|
2013-10-11 10:43:07 +04:00
|
|
|
if (output->destroy_pending)
|
2013-10-22 19:11:26 +04:00
|
|
|
return -1;
|
2013-10-11 10:43:07 +04:00
|
|
|
|
2012-05-02 17:42:21 +04:00
|
|
|
if (!output->next)
|
2012-09-06 05:54:15 +04:00
|
|
|
drm_output_render(output, damage);
|
2012-05-02 17:42:21 +04:00
|
|
|
if (!output->next)
|
2013-10-22 19:11:26 +04:00
|
|
|
return -1;
|
2010-06-14 19:54:00 +04:00
|
|
|
|
2013-09-19 01:56:35 +04:00
|
|
|
mode = container_of(output->base.current_mode, struct drm_mode, base);
|
2013-11-19 17:22:04 +04:00
|
|
|
if (!output->current ||
|
|
|
|
output->current->stride != output->next->stride) {
|
2012-03-12 02:27:41 +04:00
|
|
|
ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
|
2012-05-02 17:42:21 +04:00
|
|
|
output->next->fb_id, 0, 0,
|
2012-03-12 02:27:41 +04:00
|
|
|
&output->connector_id, 1,
|
|
|
|
&mode->mode_info);
|
|
|
|
if (ret) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("set mode failed: %m\n");
|
2013-10-22 19:11:26 +04:00
|
|
|
goto err_pageflip;
|
2012-03-12 02:27:41 +04:00
|
|
|
}
|
2013-06-04 17:24:05 +04:00
|
|
|
output_base->set_dpms(output_base, WESTON_DPMS_ON);
|
2011-04-10 18:49:52 +04:00
|
|
|
}
|
|
|
|
|
2012-01-26 08:47:45 +04:00
|
|
|
if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
|
2012-05-02 17:42:21 +04:00
|
|
|
output->next->fb_id,
|
2012-01-18 20:47:41 +04:00
|
|
|
DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("queueing pageflip failed: %m\n");
|
2013-10-22 19:11:26 +04:00
|
|
|
goto err_pageflip;
|
2012-01-18 20:47:41 +04:00
|
|
|
}
|
2011-03-11 18:39:20 +03:00
|
|
|
|
2012-06-26 18:09:13 +04:00
|
|
|
output->page_flip_pending = 1;
|
|
|
|
|
2012-08-03 19:50:05 +04:00
|
|
|
drm_output_set_cursor(output);
|
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
/*
|
|
|
|
* Now, update all the sprite surfaces
|
|
|
|
*/
|
|
|
|
wl_list_for_each(s, &compositor->sprite_list, link) {
|
2012-11-09 16:19:05 +04:00
|
|
|
uint32_t flags = 0, fb_id = 0;
|
2012-02-23 18:45:49 +04:00
|
|
|
drmVBlank vbl = {
|
|
|
|
.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
|
|
|
|
.request.sequence = 1,
|
|
|
|
};
|
|
|
|
|
2012-11-09 16:19:05 +04:00
|
|
|
if ((!s->current && !s->next) ||
|
2012-11-09 16:19:03 +04:00
|
|
|
!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
|
2012-02-23 18:45:49 +04:00
|
|
|
continue;
|
|
|
|
|
2012-11-09 16:19:05 +04:00
|
|
|
if (s->next && !compositor->sprites_hidden)
|
|
|
|
fb_id = s->next->fb_id;
|
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
|
2012-11-09 16:19:05 +04:00
|
|
|
output->crtc_id, fb_id, flags,
|
2012-02-23 18:45:49 +04:00
|
|
|
s->dest_x, s->dest_y,
|
|
|
|
s->dest_w, s->dest_h,
|
|
|
|
s->src_x, s->src_y,
|
|
|
|
s->src_w, s->src_h);
|
|
|
|
if (ret)
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("setplane failed: %d: %s\n",
|
2012-02-23 18:45:49 +04:00
|
|
|
ret, strerror(errno));
|
|
|
|
|
2012-08-09 05:27:37 +04:00
|
|
|
if (output->pipe > 0)
|
|
|
|
vbl.request.type |= DRM_VBLANK_SECONDARY;
|
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
/*
|
|
|
|
* Queue a vblank signal so we know when the surface
|
|
|
|
* becomes active on the display or has been replaced.
|
|
|
|
*/
|
|
|
|
vbl.request.signal = (unsigned long)s;
|
|
|
|
ret = drmWaitVBlank(compositor->drm.fd, &vbl);
|
|
|
|
if (ret) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("vblank event request failed: %d: %s\n",
|
2012-02-23 18:45:49 +04:00
|
|
|
ret, strerror(errno));
|
|
|
|
}
|
2012-06-26 18:09:13 +04:00
|
|
|
|
|
|
|
s->output = output;
|
|
|
|
output->vblank_pending = 1;
|
2012-02-23 18:45:49 +04:00
|
|
|
}
|
|
|
|
|
2013-10-22 19:11:26 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_pageflip:
|
2014-01-24 04:25:06 +04:00
|
|
|
output->cursor_view = NULL;
|
2013-10-22 19:11:26 +04:00
|
|
|
if (output->next) {
|
|
|
|
drm_output_release_fb(output, output->next);
|
|
|
|
output->next = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2010-06-11 20:56:24 +04:00
|
|
|
}
|
|
|
|
|
2013-04-06 01:07:11 +04:00
|
|
|
static void
|
|
|
|
drm_output_start_repaint_loop(struct weston_output *output_base)
|
|
|
|
{
|
|
|
|
struct drm_output *output = (struct drm_output *) output_base;
|
|
|
|
struct drm_compositor *compositor = (struct drm_compositor *)
|
|
|
|
output_base->compositor;
|
|
|
|
uint32_t fb_id;
|
2013-05-07 15:16:59 +04:00
|
|
|
struct timespec ts;
|
|
|
|
|
2013-10-11 10:43:07 +04:00
|
|
|
if (output->destroy_pending)
|
|
|
|
return;
|
|
|
|
|
2013-05-07 15:16:59 +04:00
|
|
|
if (!output->current) {
|
|
|
|
/* We can't page flip if there's no mode set */
|
2013-10-22 19:11:25 +04:00
|
|
|
goto finish_frame;
|
2013-05-07 15:16:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
fb_id = output->current->fb_id;
|
2013-04-06 01:07:11 +04:00
|
|
|
|
|
|
|
if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
|
|
|
|
DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
|
|
|
|
weston_log("queueing pageflip failed: %m\n");
|
2013-10-22 19:11:25 +04:00
|
|
|
goto finish_frame;
|
2013-04-06 01:07:11 +04:00
|
|
|
}
|
2013-10-22 19:11:25 +04:00
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
finish_frame:
|
|
|
|
/* if we cannot page-flip, immediately finish frame */
|
2014-09-24 06:08:45 +04:00
|
|
|
clock_gettime(compositor->base.presentation_clock, &ts);
|
|
|
|
weston_output_finish_frame(output_base, &ts);
|
2013-04-06 01:07:11 +04:00
|
|
|
}
|
|
|
|
|
2014-09-24 06:08:47 +04:00
|
|
|
static void
|
|
|
|
drm_output_update_msc(struct drm_output *output, unsigned int seq)
|
|
|
|
{
|
|
|
|
uint64_t msc_hi = output->base.msc >> 32;
|
|
|
|
|
|
|
|
if (seq < (output->base.msc & 0xffffffff))
|
|
|
|
msc_hi++;
|
|
|
|
|
|
|
|
output->base.msc = (msc_hi << 32) + seq;
|
|
|
|
}
|
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
static void
|
|
|
|
vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct drm_sprite *s = (struct drm_sprite *)data;
|
2012-06-26 18:09:13 +04:00
|
|
|
struct drm_output *output = s->output;
|
2014-09-24 06:08:45 +04:00
|
|
|
struct timespec ts;
|
2012-06-26 18:09:13 +04:00
|
|
|
|
2014-09-24 06:08:47 +04:00
|
|
|
drm_output_update_msc(output, frame);
|
2012-06-26 18:09:13 +04:00
|
|
|
output->vblank_pending = 0;
|
2012-02-23 18:45:49 +04:00
|
|
|
|
2013-01-25 17:13:03 +04:00
|
|
|
drm_output_release_fb(output, s->current);
|
2012-11-09 16:19:05 +04:00
|
|
|
s->current = s->next;
|
|
|
|
s->next = NULL;
|
2012-06-26 18:09:13 +04:00
|
|
|
|
|
|
|
if (!output->page_flip_pending) {
|
2014-09-24 06:08:45 +04:00
|
|
|
ts.tv_sec = sec;
|
|
|
|
ts.tv_nsec = usec * 1000;
|
|
|
|
weston_output_finish_frame(&output->base, &ts);
|
2012-06-26 18:09:13 +04:00
|
|
|
}
|
2012-02-23 18:45:49 +04:00
|
|
|
}
|
|
|
|
|
2013-10-11 10:43:07 +04:00
|
|
|
static void
|
|
|
|
drm_output_destroy(struct weston_output *output_base);
|
|
|
|
|
2010-06-11 20:56:24 +04:00
|
|
|
static void
|
|
|
|
page_flip_handler(int fd, unsigned int frame,
|
|
|
|
unsigned int sec, unsigned int usec, void *data)
|
|
|
|
{
|
2011-04-10 18:49:52 +04:00
|
|
|
struct drm_output *output = (struct drm_output *) data;
|
2014-09-24 06:08:45 +04:00
|
|
|
struct timespec ts;
|
2010-06-11 20:56:24 +04:00
|
|
|
|
2014-09-24 06:08:47 +04:00
|
|
|
drm_output_update_msc(output, frame);
|
|
|
|
|
2013-04-06 01:07:11 +04:00
|
|
|
/* We don't set page_flip_pending on start_repaint_loop, in that case
|
|
|
|
* we just want to page flip to the current buffer to get an accurate
|
|
|
|
* timestamp */
|
|
|
|
if (output->page_flip_pending) {
|
|
|
|
drm_output_release_fb(output, output->current);
|
|
|
|
output->current = output->next;
|
|
|
|
output->next = NULL;
|
|
|
|
}
|
2012-06-26 18:09:13 +04:00
|
|
|
|
2013-04-06 01:07:11 +04:00
|
|
|
output->page_flip_pending = 0;
|
2012-03-12 02:27:41 +04:00
|
|
|
|
2013-10-11 10:43:07 +04:00
|
|
|
if (output->destroy_pending)
|
|
|
|
drm_output_destroy(&output->base);
|
|
|
|
else if (!output->vblank_pending) {
|
2014-09-24 06:08:45 +04:00
|
|
|
ts.tv_sec = sec;
|
|
|
|
ts.tv_nsec = usec * 1000;
|
|
|
|
weston_output_finish_frame(&output->base, &ts);
|
2013-08-23 18:15:48 +04:00
|
|
|
|
|
|
|
/* We can't call this from frame_notify, because the output's
|
|
|
|
* repaint needed flag is cleared just after that */
|
|
|
|
if (output->recorder)
|
|
|
|
weston_output_schedule_repaint(&output->base);
|
2012-06-26 18:09:13 +04:00
|
|
|
}
|
2011-04-10 18:49:52 +04:00
|
|
|
}
|
|
|
|
|
2012-12-07 21:37:58 +04:00
|
|
|
static uint32_t
|
|
|
|
drm_output_check_sprite_format(struct drm_sprite *s,
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
struct weston_view *ev, struct gbm_bo *bo)
|
2012-02-23 18:45:49 +04:00
|
|
|
{
|
2012-12-07 21:37:58 +04:00
|
|
|
uint32_t i, format;
|
|
|
|
|
|
|
|
format = gbm_bo_get_format(bo);
|
|
|
|
|
|
|
|
if (format == GBM_FORMAT_ARGB8888) {
|
|
|
|
pixman_region32_t r;
|
|
|
|
|
2013-03-01 23:29:16 +04:00
|
|
|
pixman_region32_init_rect(&r, 0, 0,
|
2013-12-03 07:01:53 +04:00
|
|
|
ev->surface->width,
|
|
|
|
ev->surface->height);
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
pixman_region32_subtract(&r, &r, &ev->surface->opaque);
|
2012-12-07 21:37:58 +04:00
|
|
|
|
|
|
|
if (!pixman_region32_not_empty(&r))
|
|
|
|
format = GBM_FORMAT_XRGB8888;
|
|
|
|
|
|
|
|
pixman_region32_fini(&r);
|
|
|
|
}
|
2012-02-23 18:45:49 +04:00
|
|
|
|
|
|
|
for (i = 0; i < s->count_formats; i++)
|
|
|
|
if (s->formats[i] == format)
|
2012-12-07 21:37:58 +04:00
|
|
|
return format;
|
2012-02-23 18:45:49 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
drm_view_transform_supported(struct weston_view *ev)
|
2012-02-23 18:45:49 +04:00
|
|
|
{
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
return !ev->transform.enabled ||
|
|
|
|
(ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
|
2012-02-23 18:45:49 +04:00
|
|
|
}
|
|
|
|
|
2012-08-03 19:30:18 +04:00
|
|
|
static struct weston_plane *
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
drm_output_prepare_overlay_view(struct weston_output *output_base,
|
|
|
|
struct weston_view *ev)
|
2012-02-23 18:45:49 +04:00
|
|
|
{
|
|
|
|
struct weston_compositor *ec = output_base->compositor;
|
|
|
|
struct drm_compositor *c =(struct drm_compositor *) ec;
|
2014-03-14 16:38:15 +04:00
|
|
|
struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
|
2012-02-23 18:45:49 +04:00
|
|
|
struct drm_sprite *s;
|
|
|
|
int found = 0;
|
|
|
|
struct gbm_bo *bo;
|
|
|
|
pixman_region32_t dest_rect, src_rect;
|
2012-12-05 17:14:04 +04:00
|
|
|
pixman_box32_t *box, tbox;
|
2012-02-23 18:45:49 +04:00
|
|
|
uint32_t format;
|
2012-07-13 23:25:07 +04:00
|
|
|
wl_fixed_t sx1, sy1, sx2, sy2;
|
2012-02-23 18:45:49 +04:00
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
if (c->gbm == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2014-03-14 16:38:15 +04:00
|
|
|
if (viewport->buffer.transform != output_base->transform)
|
2012-11-27 19:03:43 +04:00
|
|
|
return NULL;
|
|
|
|
|
2014-03-14 16:38:15 +04:00
|
|
|
if (viewport->buffer.scale != output_base->current_scale)
|
2013-05-22 16:41:39 +04:00
|
|
|
return NULL;
|
|
|
|
|
2012-03-06 04:57:35 +04:00
|
|
|
if (c->sprites_are_broken)
|
2012-08-03 19:30:18 +04:00
|
|
|
return NULL;
|
2012-03-06 04:57:35 +04:00
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
if (ev->output_mask != (1u << output_base->id))
|
2012-08-03 19:30:18 +04:00
|
|
|
return NULL;
|
2012-06-26 18:09:12 +04:00
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
if (ev->surface->buffer_ref.buffer == NULL)
|
2012-08-03 19:30:18 +04:00
|
|
|
return NULL;
|
2012-02-23 18:45:49 +04:00
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
if (ev->alpha != 1.0f)
|
2012-11-16 13:48:46 +04:00
|
|
|
return NULL;
|
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
|
2012-08-09 23:18:27 +04:00
|
|
|
return NULL;
|
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
if (!drm_view_transform_supported(ev))
|
2012-08-03 19:30:18 +04:00
|
|
|
return NULL;
|
2012-02-23 18:45:49 +04:00
|
|
|
|
|
|
|
wl_list_for_each(s, &c->sprite_list, link) {
|
|
|
|
if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
|
|
|
|
continue;
|
|
|
|
|
2012-11-09 16:19:05 +04:00
|
|
|
if (!s->next) {
|
2012-02-23 18:45:49 +04:00
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No sprites available */
|
|
|
|
if (!found)
|
2012-08-03 19:30:18 +04:00
|
|
|
return NULL;
|
2012-02-23 18:45:49 +04:00
|
|
|
|
2012-07-14 06:54:43 +04:00
|
|
|
bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
ev->surface->buffer_ref.buffer->resource,
|
2013-09-04 09:27:08 +04:00
|
|
|
GBM_BO_USE_SCANOUT);
|
2012-07-14 06:54:43 +04:00
|
|
|
if (!bo)
|
2012-08-03 19:30:18 +04:00
|
|
|
return NULL;
|
2012-07-14 06:54:43 +04:00
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
format = drm_output_check_sprite_format(s, ev, bo);
|
2012-12-07 21:37:58 +04:00
|
|
|
if (format == 0) {
|
2012-11-09 16:19:05 +04:00
|
|
|
gbm_bo_destroy(bo);
|
2012-08-03 19:30:18 +04:00
|
|
|
return NULL;
|
2012-11-09 16:19:05 +04:00
|
|
|
}
|
2012-02-23 18:45:49 +04:00
|
|
|
|
2012-12-07 15:18:11 +04:00
|
|
|
s->next = drm_fb_get_from_bo(bo, c, format);
|
2012-11-09 16:19:05 +04:00
|
|
|
if (!s->next) {
|
|
|
|
gbm_bo_destroy(bo);
|
2012-08-03 19:30:18 +04:00
|
|
|
return NULL;
|
2012-02-23 18:45:49 +04:00
|
|
|
}
|
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
|
2012-02-23 18:45:49 +04:00
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
box = pixman_region32_extents(&ev->transform.boundingbox);
|
2012-08-03 19:30:18 +04:00
|
|
|
s->plane.x = box->x1;
|
|
|
|
s->plane.y = box->y1;
|
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
/*
|
|
|
|
* Calculate the source & dest rects properly based on actual
|
2014-09-11 00:37:33 +04:00
|
|
|
* position (note the caller has called weston_view_update_transform()
|
2012-02-23 18:45:49 +04:00
|
|
|
* for us already).
|
|
|
|
*/
|
|
|
|
pixman_region32_init(&dest_rect);
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
|
2012-02-23 18:45:49 +04:00
|
|
|
&output_base->region);
|
|
|
|
pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
|
|
|
|
box = pixman_region32_extents(&dest_rect);
|
2012-12-05 17:14:04 +04:00
|
|
|
tbox = weston_transformed_rect(output_base->width,
|
|
|
|
output_base->height,
|
2013-05-22 16:41:37 +04:00
|
|
|
output_base->transform,
|
2013-09-19 01:56:35 +04:00
|
|
|
output_base->current_scale,
|
2013-05-22 16:41:39 +04:00
|
|
|
*box);
|
2012-12-05 17:14:04 +04:00
|
|
|
s->dest_x = tbox.x1;
|
|
|
|
s->dest_y = tbox.y1;
|
|
|
|
s->dest_w = tbox.x2 - tbox.x1;
|
|
|
|
s->dest_h = tbox.y2 - tbox.y1;
|
2012-02-23 18:45:49 +04:00
|
|
|
pixman_region32_fini(&dest_rect);
|
|
|
|
|
|
|
|
pixman_region32_init(&src_rect);
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
|
2012-02-23 18:45:49 +04:00
|
|
|
&output_base->region);
|
|
|
|
box = pixman_region32_extents(&src_rect);
|
2012-07-13 23:25:07 +04:00
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
weston_view_from_global_fixed(ev,
|
|
|
|
wl_fixed_from_int(box->x1),
|
|
|
|
wl_fixed_from_int(box->y1),
|
|
|
|
&sx1, &sy1);
|
|
|
|
weston_view_from_global_fixed(ev,
|
|
|
|
wl_fixed_from_int(box->x2),
|
|
|
|
wl_fixed_from_int(box->y2),
|
|
|
|
&sx2, &sy2);
|
2012-07-13 23:25:07 +04:00
|
|
|
|
|
|
|
if (sx1 < 0)
|
|
|
|
sx1 = 0;
|
|
|
|
if (sy1 < 0)
|
|
|
|
sy1 = 0;
|
2013-12-03 07:01:53 +04:00
|
|
|
if (sx2 > wl_fixed_from_int(ev->surface->width))
|
|
|
|
sx2 = wl_fixed_from_int(ev->surface->width);
|
|
|
|
if (sy2 > wl_fixed_from_int(ev->surface->height))
|
|
|
|
sy2 = wl_fixed_from_int(ev->surface->height);
|
2012-07-13 23:25:07 +04:00
|
|
|
|
2012-12-05 17:14:04 +04:00
|
|
|
tbox.x1 = sx1;
|
|
|
|
tbox.y1 = sy1;
|
|
|
|
tbox.x2 = sx2;
|
|
|
|
tbox.y2 = sy2;
|
|
|
|
|
2013-12-03 07:01:53 +04:00
|
|
|
tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
|
|
|
|
wl_fixed_from_int(ev->surface->height),
|
2014-03-14 16:38:15 +04:00
|
|
|
viewport->buffer.transform,
|
|
|
|
viewport->buffer.scale,
|
2013-11-26 21:19:41 +04:00
|
|
|
tbox);
|
2012-12-05 17:14:04 +04:00
|
|
|
|
|
|
|
s->src_x = tbox.x1 << 8;
|
|
|
|
s->src_y = tbox.y1 << 8;
|
|
|
|
s->src_w = (tbox.x2 - tbox.x1) << 8;
|
|
|
|
s->src_h = (tbox.y2 - tbox.y1) << 8;
|
2012-02-23 18:45:49 +04:00
|
|
|
pixman_region32_fini(&src_rect);
|
|
|
|
|
2012-08-03 19:30:18 +04:00
|
|
|
return &s->plane;
|
2012-02-23 18:45:49 +04:00
|
|
|
}
|
|
|
|
|
2012-08-03 19:30:18 +04:00
|
|
|
static struct weston_plane *
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
drm_output_prepare_cursor_view(struct weston_output *output_base,
|
|
|
|
struct weston_view *ev)
|
2012-02-24 08:03:14 +04:00
|
|
|
{
|
2012-08-10 01:19:23 +04:00
|
|
|
struct drm_compositor *c =
|
|
|
|
(struct drm_compositor *) output_base->compositor;
|
2014-05-01 21:00:41 +04:00
|
|
|
struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
|
2012-07-14 09:06:28 +04:00
|
|
|
struct drm_output *output = (struct drm_output *) output_base;
|
2012-08-03 19:50:05 +04:00
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
if (c->gbm == NULL)
|
|
|
|
return NULL;
|
2012-11-27 19:03:43 +04:00
|
|
|
if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
|
|
|
|
return NULL;
|
2014-05-01 21:00:41 +04:00
|
|
|
if (viewport->buffer.scale != output_base->current_scale)
|
|
|
|
return NULL;
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
if (output->cursor_view)
|
2012-08-03 19:50:05 +04:00
|
|
|
return NULL;
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
if (ev->output_mask != (1u << output_base->id))
|
2012-08-03 19:50:05 +04:00
|
|
|
return NULL;
|
2012-08-09 22:24:45 +04:00
|
|
|
if (c->cursors_are_broken)
|
2012-08-10 01:19:23 +04:00
|
|
|
return NULL;
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
if (ev->surface->buffer_ref.buffer == NULL ||
|
|
|
|
!wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
|
2013-12-03 07:01:53 +04:00
|
|
|
ev->surface->width > 64 || ev->surface->height > 64)
|
2012-08-03 19:50:05 +04:00
|
|
|
return NULL;
|
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
output->cursor_view = ev;
|
2012-08-03 19:50:05 +04:00
|
|
|
|
|
|
|
return &output->cursor_plane;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drm_output_set_cursor(struct drm_output *output)
|
|
|
|
{
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
struct weston_view *ev = output->cursor_view;
|
2013-11-13 19:44:06 +04:00
|
|
|
struct weston_buffer *buffer;
|
2012-07-14 09:06:28 +04:00
|
|
|
struct drm_compositor *c =
|
|
|
|
(struct drm_compositor *) output->base.compositor;
|
|
|
|
EGLint handle, stride;
|
|
|
|
struct gbm_bo *bo;
|
2014-07-29 01:30:17 +04:00
|
|
|
uint32_t buf[c->cursor_width * c->cursor_height];
|
2012-07-14 09:06:28 +04:00
|
|
|
unsigned char *s;
|
2012-07-18 20:08:37 +04:00
|
|
|
int i, x, y;
|
2012-07-14 09:06:28 +04:00
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
output->cursor_view = NULL;
|
|
|
|
if (ev == NULL) {
|
2012-08-03 19:50:05 +04:00
|
|
|
drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
|
|
|
|
return;
|
|
|
|
}
|
2012-02-24 08:03:14 +04:00
|
|
|
|
2013-11-13 19:44:06 +04:00
|
|
|
buffer = ev->surface->buffer_ref.buffer;
|
|
|
|
|
|
|
|
if (buffer &&
|
compositor: introduce weston_buffer_reference
The wl_buffer reference counting API has been inconsistent. You would
manually increment the refcount and register a destroy listener, as
opposed to calling weston_buffer_post_release(), which internally
decremented the refcount, and then removing a list item.
Replace both cases with a single function:
weston_buffer_reference(weston_buffer_reference *ref, wl_buffer *buffer)
Buffer is assigned to ref->buffer, while taking care of all the refcounting
and release posting. You take a reference by passing a non-NULL buffer, and
release a reference by passing NULL as buffer. The function uses an
internal wl_buffer destroy listener, so the pointer gets reset on
destruction automatically.
This is inspired by the pipe_resource_reference() of Mesa, and modified
by krh's suggestion to add struct weston_buffer_reference.
Additionally, when a surface gets destroyed, the associated wl_buffer
will send a release event. Often the buffer is already destroyed on
client side, so the event will be discarded by libwayland-client.
Compositor-drm.c is converted to use weston_buffer_reference.
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2012-12-04 17:58:12 +04:00
|
|
|
pixman_region32_not_empty(&output->cursor_plane.damage)) {
|
2012-08-03 19:50:05 +04:00
|
|
|
pixman_region32_fini(&output->cursor_plane.damage);
|
|
|
|
pixman_region32_init(&output->cursor_plane.damage);
|
2012-07-18 20:09:58 +04:00
|
|
|
output->current_cursor ^= 1;
|
|
|
|
bo = output->cursor_bo[output->current_cursor];
|
|
|
|
memset(buf, 0, sizeof buf);
|
2013-11-13 19:44:06 +04:00
|
|
|
stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
|
|
|
|
s = wl_shm_buffer_get_data(buffer->shm_buffer);
|
|
|
|
wl_shm_buffer_begin_access(buffer->shm_buffer);
|
2013-12-03 07:01:53 +04:00
|
|
|
for (i = 0; i < ev->surface->height; i++)
|
2014-07-29 01:30:17 +04:00
|
|
|
memcpy(buf + i * c->cursor_width, s + i * stride,
|
2013-12-03 07:01:53 +04:00
|
|
|
ev->surface->width * 4);
|
2013-11-13 19:44:06 +04:00
|
|
|
wl_shm_buffer_end_access(buffer->shm_buffer);
|
2012-07-18 20:09:58 +04:00
|
|
|
|
|
|
|
if (gbm_bo_write(bo, buf, sizeof buf) < 0)
|
2012-08-06 15:57:05 +04:00
|
|
|
weston_log("failed update cursor: %m\n");
|
2012-02-24 08:03:14 +04:00
|
|
|
|
2012-07-18 20:09:58 +04:00
|
|
|
handle = gbm_bo_get_handle(bo).s32;
|
2014-07-29 01:30:17 +04:00
|
|
|
if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
|
|
|
|
c->cursor_width, c->cursor_height)) {
|
2012-08-06 15:57:05 +04:00
|
|
|
weston_log("failed to set cursor: %m\n");
|
2012-08-09 22:24:45 +04:00
|
|
|
c->cursors_are_broken = 1;
|
|
|
|
}
|
2012-07-14 09:06:28 +04:00
|
|
|
}
|
2012-02-24 08:03:14 +04:00
|
|
|
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
x = (ev->geometry.x - output->base.x) * output->base.current_scale;
|
|
|
|
y = (ev->geometry.y - output->base.y) * output->base.current_scale;
|
2012-08-03 19:30:18 +04:00
|
|
|
if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
|
2012-08-09 22:24:45 +04:00
|
|
|
if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
|
2012-07-18 20:08:37 +04:00
|
|
|
weston_log("failed to move cursor: %m\n");
|
2012-08-09 22:24:45 +04:00
|
|
|
c->cursors_are_broken = 1;
|
|
|
|
}
|
|
|
|
|
2012-08-03 19:30:18 +04:00
|
|
|
output->cursor_plane.x = x;
|
|
|
|
output->cursor_plane.y = y;
|
2012-07-14 09:06:28 +04:00
|
|
|
}
|
2012-02-24 08:03:14 +04:00
|
|
|
}
|
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
static void
|
|
|
|
drm_assign_planes(struct weston_output *output)
|
|
|
|
{
|
2012-07-14 09:06:28 +04:00
|
|
|
struct drm_compositor *c =
|
|
|
|
(struct drm_compositor *) output->compositor;
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
struct weston_view *ev, *next;
|
2012-02-23 18:45:49 +04:00
|
|
|
pixman_region32_t overlap, surface_overlap;
|
2012-08-03 19:30:18 +04:00
|
|
|
struct weston_plane *primary, *next_plane;
|
2012-02-23 18:45:49 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Find a surface for each sprite in the output using some heuristics:
|
|
|
|
* 1) size
|
|
|
|
* 2) frequency of update
|
|
|
|
* 3) opacity (though some hw might support alpha blending)
|
|
|
|
* 4) clipping (this can be fixed with color keys)
|
|
|
|
*
|
|
|
|
* The idea is to save on blitting since this should save power.
|
|
|
|
* If we can get a large video surface on the sprite for example,
|
|
|
|
* the main display surface may not need to update at all, and
|
|
|
|
* the client buffer can be used directly for the sprite surface
|
|
|
|
* as we do for flipping full screen surfaces.
|
|
|
|
*/
|
|
|
|
pixman_region32_init(&overlap);
|
2012-08-03 19:30:18 +04:00
|
|
|
primary = &c->base.primary_plane;
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
|
|
|
|
wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
|
2013-11-19 17:22:05 +04:00
|
|
|
struct weston_surface *es = ev->surface;
|
|
|
|
|
|
|
|
/* 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.
|
2012-12-04 17:58:14 +04:00
|
|
|
*/
|
2013-11-19 17:22:05 +04:00
|
|
|
if (c->use_pixman ||
|
|
|
|
(es->buffer_ref.buffer &&
|
|
|
|
(!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
|
2013-12-03 07:01:53 +04:00
|
|
|
(ev->surface->width <= 64 && ev->surface->height <= 64))))
|
2013-11-19 17:22:05 +04:00
|
|
|
es->keep_buffer = 1;
|
|
|
|
else
|
|
|
|
es->keep_buffer = 0;
|
2012-12-04 17:58:14 +04:00
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
pixman_region32_init(&surface_overlap);
|
|
|
|
pixman_region32_intersect(&surface_overlap, &overlap,
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
&ev->transform.boundingbox);
|
2012-02-23 18:45:49 +04:00
|
|
|
|
2012-08-03 19:30:18 +04:00
|
|
|
next_plane = NULL;
|
2012-07-14 08:31:32 +04:00
|
|
|
if (pixman_region32_not_empty(&surface_overlap))
|
2012-08-03 19:30:18 +04:00
|
|
|
next_plane = primary;
|
|
|
|
if (next_plane == NULL)
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
next_plane = drm_output_prepare_cursor_view(output, ev);
|
2012-08-03 19:30:18 +04:00
|
|
|
if (next_plane == NULL)
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
next_plane = drm_output_prepare_scanout_view(output, ev);
|
2012-08-03 19:30:18 +04:00
|
|
|
if (next_plane == NULL)
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
next_plane = drm_output_prepare_overlay_view(output, ev);
|
2012-08-03 19:30:18 +04:00
|
|
|
if (next_plane == NULL)
|
|
|
|
next_plane = primary;
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
weston_view_move_to_plane(ev, next_plane);
|
2012-08-03 19:30:18 +04:00
|
|
|
if (next_plane == primary)
|
2012-02-23 18:45:49 +04:00
|
|
|
pixman_region32_union(&overlap, &overlap,
|
Split the geometry information from weston_surface out into weston_view
The weston_surface structure is split into two structures:
* The weston_surface structure storres everything required for a
client-side or server-side surface. This includes buffers; callbacks;
backend private data; input, damage, and opaque regions; and a few other
bookkeeping bits.
* The weston_view structure represents an entity in the scenegraph and
storres all of the geometry information. This includes clip region,
alpha, position, and the transformation list as well as all of the
temporary information derived from the geometry state. Because a view,
and not a surface, is a scenegraph element, the view is what is placed
in layers and planes.
There are a few things worth noting about the surface/view split:
1. This is *not* a modification to the protocol. It is, instead, a
modification to Weston's internal scenegraph to allow a single surface
to exist in multiple places at a time. Clients are completely unaware
of how many views to a particular surface exist.
2. A view is considered a direct child of a surface and is destroyed when
the surface is destroyed. Because of this, the view.surface pointer is
always valid and non-null.
3. The compositor's surface_list is replaced with a view_list. Due to
subsurfaces, building the view list is a little more complicated than
it used to be and involves building a tree of views on the fly whenever
subsurfaces are used. However, this means that backends can remain
completely subsurface-agnostic.
4. Surfaces and views both keep track of which outputs they are on.
5. The weston_surface structure now has width and height fields. These
are populated when a new buffer is attached before surface.configure
is called. This is because there are many surface-based operations
that really require the width and height and digging through the views
didn't work well.
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
2013-10-13 07:38:11 +04:00
|
|
|
&ev->transform.boundingbox);
|
2012-07-14 08:31:32 +04:00
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
pixman_region32_fini(&surface_overlap);
|
|
|
|
}
|
|
|
|
pixman_region32_fini(&overlap);
|
|
|
|
}
|
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
static void
|
|
|
|
drm_output_fini_pixman(struct drm_output *output);
|
|
|
|
|
2011-08-30 00:52:23 +04:00
|
|
|
static void
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
drm_output_destroy(struct weston_output *output_base)
|
2011-08-30 00:52:23 +04:00
|
|
|
{
|
|
|
|
struct drm_output *output = (struct drm_output *) output_base;
|
|
|
|
struct drm_compositor *c =
|
2011-08-30 13:38:26 +04:00
|
|
|
(struct drm_compositor *) output->base.compositor;
|
2011-08-30 00:52:23 +04:00
|
|
|
drmModeCrtcPtr origcrtc = output->original_crtc;
|
|
|
|
|
2013-10-11 10:43:07 +04:00
|
|
|
if (output->page_flip_pending) {
|
|
|
|
output->destroy_pending = 1;
|
|
|
|
weston_log("destroy output while page flip pending\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-29 21:53:50 +04:00
|
|
|
if (output->backlight)
|
|
|
|
backlight_destroy(output->backlight);
|
|
|
|
|
2013-06-04 17:24:04 +04:00
|
|
|
drmModeFreeProperty(output->dpms_prop);
|
|
|
|
|
2011-08-30 00:52:23 +04:00
|
|
|
/* Turn off hardware cursor */
|
2012-07-14 09:06:28 +04:00
|
|
|
drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
|
2011-08-30 00:52:23 +04:00
|
|
|
|
|
|
|
/* Restore original CRTC state */
|
|
|
|
drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
|
2011-08-30 13:38:26 +04:00
|
|
|
origcrtc->x, origcrtc->y,
|
|
|
|
&output->connector_id, 1, &origcrtc->mode);
|
2011-08-30 00:52:23 +04:00
|
|
|
drmModeFreeCrtc(origcrtc);
|
|
|
|
|
2011-08-30 13:44:56 +04:00
|
|
|
c->crtc_allocator &= ~(1 << output->crtc_id);
|
|
|
|
c->connector_allocator &= ~(1 << output->connector_id);
|
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
if (c->use_pixman) {
|
|
|
|
drm_output_fini_pixman(output);
|
|
|
|
} else {
|
2013-10-14 16:57:11 +04:00
|
|
|
gl_renderer->output_destroy(output_base);
|
2013-01-25 17:13:05 +04:00
|
|
|
gbm_surface_destroy(output->surface);
|
|
|
|
}
|
2012-03-12 02:27:41 +04:00
|
|
|
|
2012-08-03 19:30:18 +04:00
|
|
|
weston_plane_release(&output->fb_plane);
|
|
|
|
weston_plane_release(&output->cursor_plane);
|
|
|
|
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
weston_output_destroy(&output->base);
|
2011-08-30 13:44:56 +04:00
|
|
|
|
2011-08-30 00:52:23 +04:00
|
|
|
free(output);
|
|
|
|
}
|
|
|
|
|
2012-04-17 13:20:48 +04:00
|
|
|
static struct drm_mode *
|
|
|
|
choose_mode (struct drm_output *output, struct weston_mode *target_mode)
|
|
|
|
{
|
|
|
|
struct drm_mode *tmp_mode = NULL, *mode;
|
|
|
|
|
2013-09-19 01:56:35 +04:00
|
|
|
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 ||
|
2012-04-17 13:20:48 +04:00
|
|
|
target_mode->refresh == 0))
|
2013-09-19 01:56:35 +04:00
|
|
|
return (struct drm_mode *)output->base.current_mode;
|
2012-04-17 13:20:48 +04:00
|
|
|
|
|
|
|
wl_list_for_each(mode, &output->base.mode_list, base.link) {
|
|
|
|
if (mode->mode_info.hdisplay == target_mode->width &&
|
|
|
|
mode->mode_info.vdisplay == target_mode->height) {
|
|
|
|
if (mode->mode_info.vrefresh == target_mode->refresh ||
|
|
|
|
target_mode->refresh == 0) {
|
|
|
|
return mode;
|
|
|
|
} else if (!tmp_mode)
|
|
|
|
tmp_mode = mode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tmp_mode;
|
|
|
|
}
|
|
|
|
|
2012-12-14 19:37:30 +04:00
|
|
|
static int
|
|
|
|
drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
|
2013-01-25 17:13:05 +04:00
|
|
|
static int
|
|
|
|
drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
|
2012-12-14 19:37:30 +04:00
|
|
|
|
2012-04-17 13:20:48 +04:00
|
|
|
static int
|
|
|
|
drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
|
|
|
|
{
|
|
|
|
struct drm_output *output;
|
|
|
|
struct drm_mode *drm_mode;
|
|
|
|
struct drm_compositor *ec;
|
|
|
|
|
|
|
|
if (output_base == NULL) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("output is NULL.\n");
|
2012-04-17 13:20:48 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode == NULL) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("mode is NULL.\n");
|
2012-04-17 13:20:48 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ec = (struct drm_compositor *)output_base->compositor;
|
|
|
|
output = (struct drm_output *)output_base;
|
|
|
|
drm_mode = choose_mode (output, mode);
|
|
|
|
|
|
|
|
if (!drm_mode) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
|
2012-04-17 13:20:48 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-09-19 01:56:35 +04:00
|
|
|
if (&drm_mode->base == output->base.current_mode)
|
2012-12-14 19:37:30 +04:00
|
|
|
return 0;
|
2012-04-17 13:20:48 +04:00
|
|
|
|
2013-09-19 01:56:35 +04:00
|
|
|
output->base.current_mode->flags = 0;
|
2012-04-17 13:20:48 +04:00
|
|
|
|
2013-09-19 01:56:35 +04:00
|
|
|
output->base.current_mode = &drm_mode->base;
|
|
|
|
output->base.current_mode->flags =
|
2012-12-14 19:37:30 +04:00
|
|
|
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
|
2012-04-17 13:20:48 +04:00
|
|
|
|
|
|
|
/* reset rendering stuff. */
|
2013-01-25 17:13:03 +04:00
|
|
|
drm_output_release_fb(output, output->current);
|
|
|
|
drm_output_release_fb(output, output->next);
|
|
|
|
output->current = output->next = NULL;
|
2012-04-17 13:20:48 +04:00
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
if (ec->use_pixman) {
|
|
|
|
drm_output_fini_pixman(output);
|
|
|
|
if (drm_output_init_pixman(output, ec) < 0) {
|
|
|
|
weston_log("failed to init output pixman state with "
|
|
|
|
"new mode\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
2013-10-14 16:57:11 +04:00
|
|
|
gl_renderer->output_destroy(&output->base);
|
2013-01-25 17:13:05 +04:00
|
|
|
gbm_surface_destroy(output->surface);
|
2012-04-17 13:20:48 +04:00
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
if (drm_output_init_egl(output, ec) < 0) {
|
|
|
|
weston_log("failed to init output egl state with "
|
|
|
|
"new mode");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-12-14 19:37:30 +04:00
|
|
|
}
|
2012-04-17 13:20:48 +04:00
|
|
|
|
2012-12-14 19:37:30 +04:00
|
|
|
return 0;
|
2012-04-17 13:20:48 +04:00
|
|
|
}
|
|
|
|
|
2011-04-22 20:27:57 +04:00
|
|
|
static int
|
2010-06-11 20:56:24 +04:00
|
|
|
on_drm_input(int fd, uint32_t mask, void *data)
|
|
|
|
{
|
|
|
|
drmEventContext evctx;
|
|
|
|
|
|
|
|
memset(&evctx, 0, sizeof evctx);
|
|
|
|
evctx.version = DRM_EVENT_CONTEXT_VERSION;
|
|
|
|
evctx.page_flip_handler = page_flip_handler;
|
2012-02-23 18:45:49 +04:00
|
|
|
evctx.vblank_handler = vblank_handler;
|
2010-06-11 20:56:24 +04:00
|
|
|
drmHandleEvent(fd, &evctx);
|
2011-04-22 20:27:57 +04:00
|
|
|
|
|
|
|
return 1;
|
2010-06-11 20:56:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2013-01-25 17:13:02 +04:00
|
|
|
init_drm(struct drm_compositor *ec, struct udev_device *device)
|
2010-06-11 20:56:24 +04:00
|
|
|
{
|
2012-03-29 06:53:49 +04:00
|
|
|
const char *filename, *sysnum;
|
2013-05-07 15:16:59 +04:00
|
|
|
uint64_t cap;
|
|
|
|
int fd, ret;
|
2014-09-24 06:08:45 +04:00
|
|
|
clockid_t clk_id;
|
2012-03-12 02:27:41 +04:00
|
|
|
|
2012-05-10 20:28:35 +04:00
|
|
|
sysnum = udev_device_get_sysnum(device);
|
|
|
|
if (sysnum)
|
|
|
|
ec->drm.id = atoi(sysnum);
|
|
|
|
if (!sysnum || ec->drm.id < 0) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("cannot get device sysnum\n");
|
2012-05-10 20:28:35 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-08-09 22:43:33 +04:00
|
|
|
filename = udev_device_get_devnode(device);
|
2013-09-18 01:41:03 +04:00
|
|
|
fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
|
2010-08-09 22:43:33 +04:00
|
|
|
if (fd < 0) {
|
2010-06-11 20:56:24 +04:00
|
|
|
/* Probably permissions error */
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("couldn't open %s, skipping\n",
|
2010-06-11 20:56:24 +04:00
|
|
|
udev_device_get_devnode(device));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-06-09 00:45:33 +04:00
|
|
|
weston_log("using %s\n", filename);
|
|
|
|
|
2011-03-02 13:14:59 +03:00
|
|
|
ec->drm.fd = fd;
|
2013-08-23 18:15:48 +04:00
|
|
|
ec->drm.filename = strdup(filename);
|
2013-01-25 17:13:02 +04:00
|
|
|
|
2013-05-07 15:16:59 +04:00
|
|
|
ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
|
|
|
|
if (ret == 0 && cap == 1)
|
2014-09-24 06:08:45 +04:00
|
|
|
clk_id = CLOCK_MONOTONIC;
|
2013-05-07 15:16:59 +04:00
|
|
|
else
|
2014-09-24 06:08:45 +04:00
|
|
|
clk_id = CLOCK_REALTIME;
|
|
|
|
|
|
|
|
if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
|
|
|
|
weston_log("Error: failed to set presentation clock %d.\n",
|
|
|
|
clk_id);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-01-25 17:13:04 +04:00
|
|
|
|
2014-07-29 01:30:17 +04:00
|
|
|
ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
|
|
|
|
if (ret == 0)
|
|
|
|
ec->cursor_width = cap;
|
|
|
|
else
|
|
|
|
ec->cursor_width = 64;
|
|
|
|
|
|
|
|
ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
|
|
|
|
if (ret == 0)
|
|
|
|
ec->cursor_height = cap;
|
|
|
|
else
|
|
|
|
ec->cursor_height = 64;
|
|
|
|
|
2013-01-25 17:13:02 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-11-19 17:22:04 +04:00
|
|
|
static struct gbm_device *
|
|
|
|
create_gbm_device(int fd)
|
2013-01-25 17:13:02 +04:00
|
|
|
{
|
2013-11-19 17:22:04 +04:00
|
|
|
struct gbm_device *gbm;
|
2013-10-02 20:51:05 +04:00
|
|
|
|
2013-10-14 16:57:11 +04:00
|
|
|
gl_renderer = weston_load_module("gl-renderer.so",
|
|
|
|
"gl_renderer_interface");
|
|
|
|
if (!gl_renderer)
|
2013-11-19 17:22:04 +04:00
|
|
|
return NULL;
|
2013-10-14 16:57:11 +04:00
|
|
|
|
|
|
|
/* GBM will load a dri driver, but even though they need symbols from
|
|
|
|
* libglapi, in some version of Mesa they are not linked to it. Since
|
|
|
|
* only the gl-renderer module links to it, the call above won't make
|
|
|
|
* these symbols globally available, and loading the DRI driver fails.
|
|
|
|
* Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
|
|
|
|
dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
|
|
|
|
|
2013-11-19 17:22:04 +04:00
|
|
|
gbm = gbm_create_device(fd);
|
2010-06-11 20:56:24 +04:00
|
|
|
|
2013-11-19 17:22:04 +04:00
|
|
|
return gbm;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
drm_compositor_create_gl_renderer(struct drm_compositor *ec)
|
|
|
|
{
|
|
|
|
EGLint format;
|
2013-03-02 15:27:39 +04:00
|
|
|
|
2013-10-02 20:51:05 +04:00
|
|
|
format = ec->format;
|
2013-10-14 16:57:11 +04:00
|
|
|
if (gl_renderer->create(&ec->base, ec->gbm,
|
|
|
|
gl_renderer->opaque_attribs, &format) < 0) {
|
2013-11-19 17:22:04 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
init_egl(struct drm_compositor *ec)
|
|
|
|
{
|
|
|
|
ec->gbm = create_gbm_device(ec->drm.fd);
|
|
|
|
|
|
|
|
if (!ec->gbm)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (drm_compositor_create_gl_renderer(ec) < 0) {
|
2012-11-13 22:10:19 +04:00
|
|
|
gbm_device_destroy(ec->gbm);
|
2012-03-12 02:27:41 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-06-11 20:56:24 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
static int
|
|
|
|
init_pixman(struct drm_compositor *ec)
|
|
|
|
{
|
|
|
|
return pixman_renderer_init(&ec->base);
|
|
|
|
}
|
|
|
|
|
2012-08-09 17:45:00 +04:00
|
|
|
static struct drm_mode *
|
2013-05-28 18:23:36 +04:00
|
|
|
drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
|
2011-06-21 19:16:58 +04:00
|
|
|
{
|
|
|
|
struct drm_mode *mode;
|
2012-05-10 20:23:53 +04:00
|
|
|
uint64_t refresh;
|
2011-06-21 19:16:58 +04:00
|
|
|
|
|
|
|
mode = malloc(sizeof *mode);
|
|
|
|
if (mode == NULL)
|
2012-08-09 17:45:00 +04:00
|
|
|
return NULL;
|
2011-06-21 19:16:58 +04:00
|
|
|
|
|
|
|
mode->base.flags = 0;
|
2013-05-28 18:23:36 +04:00
|
|
|
mode->base.width = info->hdisplay;
|
|
|
|
mode->base.height = info->vdisplay;
|
2012-05-10 20:23:53 +04:00
|
|
|
|
|
|
|
/* Calculate higher precision (mHz) refresh rate */
|
|
|
|
refresh = (info->clock * 1000000LL / info->htotal +
|
|
|
|
info->vtotal / 2) / info->vtotal;
|
|
|
|
|
|
|
|
if (info->flags & DRM_MODE_FLAG_INTERLACE)
|
|
|
|
refresh *= 2;
|
|
|
|
if (info->flags & DRM_MODE_FLAG_DBLSCAN)
|
|
|
|
refresh /= 2;
|
|
|
|
if (info->vscan > 1)
|
|
|
|
refresh /= info->vscan;
|
|
|
|
|
|
|
|
mode->base.refresh = refresh;
|
2011-06-21 19:16:58 +04:00
|
|
|
mode->mode_info = *info;
|
2012-06-28 19:28:15 +04:00
|
|
|
|
|
|
|
if (info->type & DRM_MODE_TYPE_PREFERRED)
|
|
|
|
mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
|
|
|
|
|
2011-06-21 19:16:58 +04:00
|
|
|
wl_list_insert(output->base.mode_list.prev, &mode->base.link);
|
|
|
|
|
2012-08-09 17:45:00 +04:00
|
|
|
return mode;
|
2011-06-21 19:16:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
drm_subpixel_to_wayland(int drm_value)
|
|
|
|
{
|
|
|
|
switch (drm_value) {
|
|
|
|
default:
|
|
|
|
case DRM_MODE_SUBPIXEL_UNKNOWN:
|
|
|
|
return WL_OUTPUT_SUBPIXEL_UNKNOWN;
|
|
|
|
case DRM_MODE_SUBPIXEL_NONE:
|
|
|
|
return WL_OUTPUT_SUBPIXEL_NONE;
|
|
|
|
case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
|
|
|
|
return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
|
|
|
|
case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
|
|
|
|
return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
|
|
|
|
case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
|
|
|
|
return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
|
|
|
|
case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
|
|
|
|
return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-13 02:40:09 +04:00
|
|
|
/* returns a value between 0-255 range, where higher is brighter */
|
2012-02-29 21:53:50 +04:00
|
|
|
static uint32_t
|
|
|
|
drm_get_backlight(struct drm_output *output)
|
|
|
|
{
|
|
|
|
long brightness, max_brightness, norm;
|
|
|
|
|
|
|
|
brightness = backlight_get_brightness(output->backlight);
|
|
|
|
max_brightness = backlight_get_max_brightness(output->backlight);
|
|
|
|
|
2012-03-13 02:40:09 +04:00
|
|
|
/* convert it on a scale of 0 to 255 */
|
|
|
|
norm = (brightness * 255)/(max_brightness);
|
2012-02-29 21:53:50 +04:00
|
|
|
|
|
|
|
return (uint32_t) norm;
|
|
|
|
}
|
|
|
|
|
2012-03-13 02:40:09 +04:00
|
|
|
/* values accepted are between 0-255 range */
|
2012-02-29 21:53:50 +04:00
|
|
|
static void
|
|
|
|
drm_set_backlight(struct weston_output *output_base, uint32_t value)
|
|
|
|
{
|
|
|
|
struct drm_output *output = (struct drm_output *) output_base;
|
|
|
|
long max_brightness, new_brightness;
|
|
|
|
|
|
|
|
if (!output->backlight)
|
|
|
|
return;
|
|
|
|
|
2012-03-30 19:52:39 +04:00
|
|
|
if (value > 255)
|
2012-02-29 21:53:50 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
max_brightness = backlight_get_max_brightness(output->backlight);
|
|
|
|
|
|
|
|
/* get denormalized value */
|
2012-03-13 02:40:09 +04:00
|
|
|
new_brightness = (value * max_brightness) / 255;
|
2012-02-29 21:53:50 +04:00
|
|
|
|
|
|
|
backlight_set_brightness(output->backlight, new_brightness);
|
|
|
|
}
|
|
|
|
|
|
|
|
static drmModePropertyPtr
|
|
|
|
drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
|
|
|
|
{
|
|
|
|
drmModePropertyPtr props;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < connector->count_props; i++) {
|
|
|
|
props = drmModeGetProperty(fd, connector->props[i]);
|
|
|
|
if (!props)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!strcmp(props->name, name))
|
|
|
|
return props;
|
|
|
|
|
|
|
|
drmModeFreeProperty(props);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
|
|
|
|
{
|
|
|
|
struct drm_output *output = (struct drm_output *) output_base;
|
|
|
|
struct weston_compositor *ec = output_base->compositor;
|
|
|
|
struct drm_compositor *c = (struct drm_compositor *) ec;
|
|
|
|
|
2013-06-04 17:24:04 +04:00
|
|
|
if (!output->dpms_prop)
|
2012-02-29 21:53:50 +04:00
|
|
|
return;
|
|
|
|
|
2013-06-04 17:24:04 +04:00
|
|
|
drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
|
|
|
|
output->dpms_prop->prop_id, level);
|
2012-02-29 21:53:50 +04:00
|
|
|
}
|
|
|
|
|
2012-07-27 01:57:15 +04:00
|
|
|
static const char *connector_type_names[] = {
|
|
|
|
"None",
|
|
|
|
"VGA",
|
|
|
|
"DVI",
|
|
|
|
"DVI",
|
|
|
|
"DVI",
|
|
|
|
"Composite",
|
|
|
|
"TV",
|
|
|
|
"LVDS",
|
|
|
|
"CTV",
|
|
|
|
"DIN",
|
|
|
|
"DP",
|
|
|
|
"HDMI",
|
|
|
|
"HDMI",
|
|
|
|
"TV",
|
|
|
|
"eDP",
|
|
|
|
};
|
|
|
|
|
2012-07-27 06:44:55 +04:00
|
|
|
static int
|
|
|
|
find_crtc_for_connector(struct drm_compositor *ec,
|
|
|
|
drmModeRes *resources, drmModeConnector *connector)
|
|
|
|
{
|
|
|
|
drmModeEncoder *encoder;
|
|
|
|
uint32_t possible_crtcs;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (j = 0; j < connector->count_encoders; j++) {
|
|
|
|
encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
|
|
|
|
if (encoder == NULL) {
|
|
|
|
weston_log("Failed to get encoder.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
possible_crtcs = encoder->possible_crtcs;
|
|
|
|
drmModeFreeEncoder(encoder);
|
|
|
|
|
|
|
|
for (i = 0; i < resources->count_crtcs; i++) {
|
|
|
|
if (possible_crtcs & (1 << i) &&
|
|
|
|
!(ec->crtc_allocator & (1 << resources->crtcs[i])))
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-12-14 19:37:29 +04:00
|
|
|
/* Init output state that depends on gl or gbm */
|
|
|
|
static int
|
|
|
|
drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
|
|
|
|
{
|
2014-03-07 22:05:50 +04:00
|
|
|
EGLint format = output->format;
|
2012-12-14 19:37:30 +04:00
|
|
|
int i, flags;
|
|
|
|
|
2012-12-14 19:37:29 +04:00
|
|
|
output->surface = gbm_surface_create(ec->gbm,
|
2013-09-19 01:56:35 +04:00
|
|
|
output->base.current_mode->width,
|
|
|
|
output->base.current_mode->height,
|
2014-03-07 22:05:50 +04:00
|
|
|
format,
|
2012-12-14 19:37:29 +04:00
|
|
|
GBM_BO_USE_SCANOUT |
|
|
|
|
GBM_BO_USE_RENDERING);
|
|
|
|
if (!output->surface) {
|
|
|
|
weston_log("failed to create gbm surface\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-03-07 22:05:50 +04:00
|
|
|
if (gl_renderer->output_create(&output->base, output->surface,
|
|
|
|
gl_renderer->opaque_attribs,
|
|
|
|
&format) < 0) {
|
2012-12-14 19:37:30 +04:00
|
|
|
weston_log("failed to create gl renderer output state\n");
|
2012-12-14 19:37:29 +04:00
|
|
|
gbm_surface_destroy(output->surface);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-07-29 01:30:17 +04:00
|
|
|
flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
|
2012-12-14 19:37:30 +04:00
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
if (output->cursor_bo[i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
output->cursor_bo[i] =
|
2014-07-29 01:30:17 +04:00
|
|
|
gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
|
|
|
|
GBM_FORMAT_ARGB8888, flags);
|
2012-12-14 19:37:30 +04:00
|
|
|
}
|
|
|
|
|
2012-12-14 19:37:29 +04:00
|
|
|
if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
|
|
|
|
weston_log("cursor buffers unavailable, using gl cursors\n");
|
|
|
|
ec->cursors_are_broken = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
static int
|
|
|
|
drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
|
|
|
|
{
|
2013-09-19 01:56:35 +04:00
|
|
|
int w = output->base.current_mode->width;
|
|
|
|
int h = output->base.current_mode->height;
|
2013-01-25 17:13:05 +04:00
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
/* FIXME error checking */
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
|
2013-05-28 18:23:36 +04:00
|
|
|
output->dumb[i] = drm_fb_create_dumb(c, w, h);
|
2013-01-25 17:13:05 +04:00
|
|
|
if (!output->dumb[i])
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
output->image[i] =
|
2013-05-28 18:23:36 +04:00
|
|
|
pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
|
2013-01-25 17:13:05 +04:00
|
|
|
output->dumb[i]->map,
|
|
|
|
output->dumb[i]->stride);
|
|
|
|
if (!output->image[i])
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pixman_renderer_output_create(&output->base) < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
pixman_region32_init_rect(&output->previous_damage,
|
2013-05-28 18:23:36 +04:00
|
|
|
output->base.x, output->base.y, output->base.width, output->base.height);
|
2013-01-25 17:13:05 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
|
|
|
|
if (output->dumb[i])
|
|
|
|
drm_fb_destroy_dumb(output->dumb[i]);
|
|
|
|
if (output->image[i])
|
|
|
|
pixman_image_unref(output->image[i]);
|
|
|
|
|
|
|
|
output->dumb[i] = NULL;
|
|
|
|
output->image[i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drm_output_fini_pixman(struct drm_output *output)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
pixman_renderer_output_destroy(&output->base);
|
|
|
|
pixman_region32_fini(&output->previous_damage);
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
|
|
|
|
drm_fb_destroy_dumb(output->dumb[i]);
|
|
|
|
pixman_image_unref(output->image[i]);
|
|
|
|
output->dumb[i] = NULL;
|
|
|
|
output->image[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-24 17:58:02 +04:00
|
|
|
static void
|
|
|
|
edid_parse_string(const uint8_t *data, char text[])
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int replaced = 0;
|
|
|
|
|
|
|
|
/* this is always 12 bytes, but we can't guarantee it's null
|
|
|
|
* terminated or not junk. */
|
|
|
|
strncpy(text, (const char *) data, 12);
|
|
|
|
|
|
|
|
/* remove insane chars */
|
|
|
|
for (i = 0; text[i] != '\0'; i++) {
|
|
|
|
if (text[i] == '\n' ||
|
|
|
|
text[i] == '\r') {
|
|
|
|
text[i] = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ensure string is printable */
|
|
|
|
for (i = 0; text[i] != '\0'; i++) {
|
|
|
|
if (!isprint(text[i])) {
|
|
|
|
text[i] = '-';
|
|
|
|
replaced++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if the string is random junk, ignore the string */
|
|
|
|
if (replaced > 4)
|
|
|
|
text[0] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
|
|
|
|
#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
|
|
|
|
#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
|
|
|
|
#define EDID_OFFSET_DATA_BLOCKS 0x36
|
|
|
|
#define EDID_OFFSET_LAST_BLOCK 0x6c
|
|
|
|
#define EDID_OFFSET_PNPID 0x08
|
|
|
|
#define EDID_OFFSET_SERIAL 0x0c
|
|
|
|
|
|
|
|
static int
|
|
|
|
edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
uint32_t serial_number;
|
|
|
|
|
|
|
|
/* check header */
|
|
|
|
if (length < 128)
|
|
|
|
return -1;
|
|
|
|
if (data[0] != 0x00 || data[1] != 0xff)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* decode the PNP ID from three 5 bit words packed into 2 bytes
|
|
|
|
* /--08--\/--09--\
|
|
|
|
* 7654321076543210
|
|
|
|
* |\---/\---/\---/
|
|
|
|
* R C1 C2 C3 */
|
|
|
|
edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
|
|
|
|
edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
|
|
|
|
edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
|
|
|
|
edid->pnp_id[3] = '\0';
|
|
|
|
|
|
|
|
/* maybe there isn't a ASCII serial number descriptor, so use this instead */
|
|
|
|
serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
|
|
|
|
serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
|
|
|
|
serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
|
|
|
|
serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
|
|
|
|
if (serial_number > 0)
|
|
|
|
sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
|
|
|
|
|
|
|
|
/* parse EDID data */
|
|
|
|
for (i = EDID_OFFSET_DATA_BLOCKS;
|
|
|
|
i <= EDID_OFFSET_LAST_BLOCK;
|
|
|
|
i += 18) {
|
|
|
|
/* ignore pixel clock data */
|
|
|
|
if (data[i] != 0)
|
|
|
|
continue;
|
|
|
|
if (data[i+2] != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* any useful blocks? */
|
|
|
|
if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
|
|
|
|
edid_parse_string(&data[i+5],
|
|
|
|
edid->monitor_name);
|
|
|
|
} else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
|
|
|
|
edid_parse_string(&data[i+5],
|
|
|
|
edid->serial_number);
|
|
|
|
} else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
|
|
|
|
edid_parse_string(&data[i+5],
|
|
|
|
edid->eisa_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
find_and_parse_output_edid(struct drm_compositor *ec,
|
|
|
|
struct drm_output *output,
|
|
|
|
drmModeConnector *connector)
|
|
|
|
{
|
|
|
|
drmModePropertyBlobPtr edid_blob = NULL;
|
|
|
|
drmModePropertyPtr property;
|
|
|
|
int i;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
for (i = 0; i < connector->count_props && !edid_blob; i++) {
|
|
|
|
property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
|
|
|
|
if (!property)
|
|
|
|
continue;
|
|
|
|
if ((property->flags & DRM_MODE_PROP_BLOB) &&
|
|
|
|
!strcmp(property->name, "EDID")) {
|
|
|
|
edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
|
|
|
|
connector->prop_values[i]);
|
|
|
|
}
|
|
|
|
drmModeFreeProperty(property);
|
|
|
|
}
|
|
|
|
if (!edid_blob)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rc = edid_parse(&output->edid,
|
|
|
|
edid_blob->data,
|
|
|
|
edid_blob->length);
|
|
|
|
if (!rc) {
|
|
|
|
weston_log("EDID data '%s', '%s', '%s'\n",
|
|
|
|
output->edid.pnp_id,
|
|
|
|
output->edid.monitor_name,
|
|
|
|
output->edid.serial_number);
|
|
|
|
if (output->edid.pnp_id[0] != '\0')
|
|
|
|
output->base.make = output->edid.pnp_id;
|
|
|
|
if (output->edid.monitor_name[0] != '\0')
|
|
|
|
output->base.model = output->edid.monitor_name;
|
|
|
|
if (output->edid.serial_number[0] != '\0')
|
|
|
|
output->base.serial_number = output->edid.serial_number;
|
|
|
|
}
|
|
|
|
drmModeFreePropertyBlob(edid_blob);
|
|
|
|
}
|
|
|
|
|
2013-05-24 01:23:15 +04:00
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
parse_modeline(const char *s, drmModeModeInfo *mode)
|
|
|
|
{
|
|
|
|
char hsync[16];
|
|
|
|
char vsync[16];
|
|
|
|
float fclock;
|
|
|
|
|
|
|
|
mode->type = DRM_MODE_TYPE_USERDEF;
|
|
|
|
mode->hskew = 0;
|
|
|
|
mode->vscan = 0;
|
|
|
|
mode->vrefresh = 0;
|
|
|
|
mode->flags = 0;
|
|
|
|
|
2013-07-26 19:29:40 +04:00
|
|
|
if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
|
2013-05-24 01:23:15 +04:00
|
|
|
&fclock,
|
|
|
|
&mode->hdisplay,
|
|
|
|
&mode->hsync_start,
|
|
|
|
&mode->hsync_end,
|
|
|
|
&mode->htotal,
|
|
|
|
&mode->vdisplay,
|
|
|
|
&mode->vsync_start,
|
|
|
|
&mode->vsync_end,
|
|
|
|
&mode->vtotal, hsync, vsync) != 11)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
mode->clock = fclock * 1000;
|
|
|
|
if (strcmp(hsync, "+hsync") == 0)
|
|
|
|
mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
|
|
|
else if (strcmp(hsync, "-hsync") == 0)
|
|
|
|
mode->flags |= DRM_MODE_FLAG_NHSYNC;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (strcmp(vsync, "+vsync") == 0)
|
|
|
|
mode->flags |= DRM_MODE_FLAG_PVSYNC;
|
|
|
|
else if (strcmp(vsync, "-vsync") == 0)
|
|
|
|
mode->flags |= DRM_MODE_FLAG_NVSYNC;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
parse_transform(const char *transform, const char *output_name)
|
|
|
|
{
|
|
|
|
static const struct { const char *name; uint32_t token; } names[] = {
|
|
|
|
{ "normal", WL_OUTPUT_TRANSFORM_NORMAL },
|
|
|
|
{ "90", WL_OUTPUT_TRANSFORM_90 },
|
|
|
|
{ "180", WL_OUTPUT_TRANSFORM_180 },
|
|
|
|
{ "270", WL_OUTPUT_TRANSFORM_270 },
|
|
|
|
{ "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
|
|
|
|
{ "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
|
|
|
|
{ "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
|
|
|
|
{ "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
|
|
|
|
};
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_LENGTH(names); i++)
|
|
|
|
if (strcmp(names[i].name, transform) == 0)
|
|
|
|
return names[i].token;
|
|
|
|
|
|
|
|
weston_log("Invalid transform \"%s\" for output %s\n",
|
|
|
|
transform, output_name);
|
|
|
|
|
|
|
|
return WL_OUTPUT_TRANSFORM_NORMAL;
|
|
|
|
}
|
|
|
|
|
2013-06-25 21:56:42 +04:00
|
|
|
static void
|
|
|
|
setup_output_seat_constraint(struct drm_compositor *ec,
|
|
|
|
struct weston_output *output,
|
|
|
|
const char *s)
|
|
|
|
{
|
|
|
|
if (strcmp(s, "") != 0) {
|
|
|
|
struct udev_seat *seat;
|
|
|
|
|
2014-03-13 01:08:40 +04:00
|
|
|
seat = udev_seat_get_named(&ec->input, s);
|
2013-06-25 21:56:42 +04:00
|
|
|
if (seat)
|
|
|
|
seat->base.output = output;
|
|
|
|
|
|
|
|
if (seat && seat->base.pointer)
|
|
|
|
weston_pointer_clamp(seat->base.pointer,
|
|
|
|
&seat->base.pointer->x,
|
|
|
|
&seat->base.pointer->y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-07 22:05:50 +04:00
|
|
|
static int
|
|
|
|
get_gbm_format_from_section(struct weston_config_section *section,
|
|
|
|
uint32_t default_value,
|
|
|
|
uint32_t *format)
|
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
weston_config_section_get_string(section,
|
|
|
|
"gbm-format", &s, NULL);
|
|
|
|
|
|
|
|
if (s == NULL)
|
|
|
|
*format = default_value;
|
|
|
|
else if (strcmp(s, "xrgb8888") == 0)
|
|
|
|
*format = GBM_FORMAT_XRGB8888;
|
|
|
|
else if (strcmp(s, "rgb565") == 0)
|
|
|
|
*format = GBM_FORMAT_RGB565;
|
|
|
|
else if (strcmp(s, "xrgb2101010") == 0)
|
|
|
|
*format = GBM_FORMAT_XRGB2101010;
|
|
|
|
else {
|
|
|
|
weston_log("fatal: unrecognized pixel format: %s\n", s);
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(s);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-06-11 20:56:24 +04:00
|
|
|
static int
|
2010-06-14 19:54:00 +04:00
|
|
|
create_output_for_connector(struct drm_compositor *ec,
|
2010-06-11 20:56:24 +04:00
|
|
|
drmModeRes *resources,
|
2011-03-11 18:39:20 +03:00
|
|
|
drmModeConnector *connector,
|
2012-02-29 21:53:50 +04:00
|
|
|
int x, int y, struct udev_device *drm_device)
|
2010-06-11 20:56:24 +04:00
|
|
|
{
|
2010-06-14 19:54:00 +04:00
|
|
|
struct drm_output *output;
|
2013-12-12 20:13:56 +04:00
|
|
|
struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
|
2012-08-09 17:45:00 +04:00
|
|
|
struct weston_mode *m;
|
2013-05-24 01:23:15 +04:00
|
|
|
struct weston_config_section *section;
|
2010-06-11 20:56:24 +04:00
|
|
|
drmModeEncoder *encoder;
|
2013-05-24 01:23:15 +04:00
|
|
|
drmModeModeInfo crtc_mode, modeline;
|
2012-06-28 19:28:15 +04:00
|
|
|
drmModeCrtc *crtc;
|
2013-05-24 01:23:15 +04:00
|
|
|
int i, width, height, scale;
|
|
|
|
char name[32], *s;
|
2012-07-27 01:57:15 +04:00
|
|
|
const char *type_name;
|
2013-05-24 01:23:15 +04:00
|
|
|
enum output_config config;
|
|
|
|
uint32_t transform;
|
2010-06-11 20:56:24 +04:00
|
|
|
|
2012-07-27 06:44:55 +04:00
|
|
|
i = find_crtc_for_connector(ec, resources, connector);
|
|
|
|
if (i < 0) {
|
|
|
|
weston_log("No usable crtc/encoder pair for connector.\n");
|
2010-06-11 20:56:24 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-08-08 05:57:05 +04:00
|
|
|
output = zalloc(sizeof *output);
|
2012-07-27 06:44:55 +04:00
|
|
|
if (output == NULL)
|
2011-06-21 19:16:58 +04:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
|
|
|
|
output->base.make = "unknown";
|
|
|
|
output->base.model = "unknown";
|
2013-04-24 17:58:02 +04:00
|
|
|
output->base.serial_number = "unknown";
|
2011-06-21 19:16:58 +04:00
|
|
|
wl_list_init(&output->base.mode_list);
|
2010-06-14 19:54:00 +04:00
|
|
|
|
2012-07-27 01:57:15 +04:00
|
|
|
if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
|
|
|
|
type_name = connector_type_names[connector->connector_type];
|
|
|
|
else
|
|
|
|
type_name = "UNKNOWN";
|
|
|
|
snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
|
2013-05-02 13:10:04 +04:00
|
|
|
output->base.name = strdup(name);
|
2012-07-27 01:57:15 +04:00
|
|
|
|
2013-05-24 01:23:15 +04:00
|
|
|
section = weston_config_get_section(ec->base.config, "output", "name",
|
|
|
|
output->base.name);
|
|
|
|
weston_config_section_get_string(section, "mode", &s, "preferred");
|
|
|
|
if (strcmp(s, "off") == 0)
|
|
|
|
config = OUTPUT_CONFIG_OFF;
|
|
|
|
else if (strcmp(s, "preferred") == 0)
|
|
|
|
config = OUTPUT_CONFIG_PREFERRED;
|
|
|
|
else if (strcmp(s, "current") == 0)
|
|
|
|
config = OUTPUT_CONFIG_CURRENT;
|
|
|
|
else if (sscanf(s, "%dx%d", &width, &height) == 2)
|
|
|
|
config = OUTPUT_CONFIG_MODE;
|
|
|
|
else if (parse_modeline(s, &modeline) == 0)
|
|
|
|
config = OUTPUT_CONFIG_MODELINE;
|
|
|
|
else {
|
|
|
|
weston_log("Invalid mode \"%s\" for output %s\n",
|
|
|
|
s, output->base.name);
|
|
|
|
config = OUTPUT_CONFIG_PREFERRED;
|
2013-05-22 16:41:39 +04:00
|
|
|
}
|
2013-05-24 01:23:15 +04:00
|
|
|
free(s);
|
|
|
|
|
|
|
|
weston_config_section_get_int(section, "scale", &scale, 1);
|
|
|
|
weston_config_section_get_string(section, "transform", &s, "normal");
|
|
|
|
transform = parse_transform(s, output->base.name);
|
|
|
|
free(s);
|
2013-05-22 16:41:39 +04:00
|
|
|
|
2014-03-07 22:05:50 +04:00
|
|
|
if (get_gbm_format_from_section(section,
|
|
|
|
ec->format,
|
|
|
|
&output->format) == -1)
|
|
|
|
output->format = ec->format;
|
|
|
|
|
2013-06-25 21:56:42 +04:00
|
|
|
weston_config_section_get_string(section, "seat", &s, "");
|
|
|
|
setup_output_seat_constraint(ec, &output->base, s);
|
|
|
|
free(s);
|
|
|
|
|
2010-06-11 20:56:24 +04:00
|
|
|
output->crtc_id = resources->crtcs[i];
|
2012-08-09 05:27:37 +04:00
|
|
|
output->pipe = i;
|
2011-03-15 17:08:41 +03:00
|
|
|
ec->crtc_allocator |= (1 << output->crtc_id);
|
2010-06-11 20:56:24 +04:00
|
|
|
output->connector_id = connector->connector_id;
|
2011-03-15 17:08:41 +03:00
|
|
|
ec->connector_allocator |= (1 << output->connector_id);
|
2011-06-21 19:16:58 +04:00
|
|
|
|
2011-08-30 00:52:23 +04:00
|
|
|
output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
|
2013-06-04 17:24:04 +04:00
|
|
|
output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
|
2011-12-08 20:05:45 +04:00
|
|
|
|
2012-06-28 19:28:15 +04:00
|
|
|
/* Get the current mode on the crtc that's currently driving
|
|
|
|
* this connector. */
|
|
|
|
encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
|
2012-07-31 02:09:46 +04:00
|
|
|
memset(&crtc_mode, 0, sizeof crtc_mode);
|
|
|
|
if (encoder != NULL) {
|
|
|
|
crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
|
|
|
|
drmModeFreeEncoder(encoder);
|
|
|
|
if (crtc == NULL)
|
|
|
|
goto err_free;
|
|
|
|
if (crtc->mode_valid)
|
|
|
|
crtc_mode = crtc->mode;
|
|
|
|
drmModeFreeCrtc(crtc);
|
|
|
|
}
|
2012-06-28 19:28:15 +04:00
|
|
|
|
2011-12-08 20:05:45 +04:00
|
|
|
for (i = 0; i < connector->count_modes; i++) {
|
2013-05-28 18:23:36 +04:00
|
|
|
drm_mode = drm_output_add_mode(output, &connector->modes[i]);
|
2012-08-09 17:45:00 +04:00
|
|
|
if (!drm_mode)
|
2011-12-08 20:05:45 +04:00
|
|
|
goto err_free;
|
|
|
|
}
|
2011-08-30 00:52:23 +04:00
|
|
|
|
2013-05-24 01:23:15 +04:00
|
|
|
if (config == OUTPUT_CONFIG_OFF) {
|
|
|
|
weston_log("Disabling output %s\n", output->base.name);
|
2012-07-31 05:51:08 +04:00
|
|
|
drmModeSetCrtc(ec->drm.fd, output->crtc_id,
|
2013-05-24 01:23:15 +04:00
|
|
|
0, 0, 0, 0, 0, NULL);
|
2012-07-31 05:51:08 +04:00
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
|
2013-05-24 01:23:15 +04:00
|
|
|
preferred = NULL;
|
|
|
|
current = NULL;
|
|
|
|
configured = NULL;
|
2013-12-12 20:13:56 +04:00
|
|
|
best = NULL;
|
2013-05-24 01:23:15 +04:00
|
|
|
|
2013-06-19 17:19:19 +04:00
|
|
|
wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
|
2013-05-24 01:23:15 +04:00
|
|
|
if (config == OUTPUT_CONFIG_MODE &&
|
2013-05-28 18:23:36 +04:00
|
|
|
width == drm_mode->base.width &&
|
|
|
|
height == drm_mode->base.height)
|
2012-08-09 17:45:00 +04:00
|
|
|
configured = drm_mode;
|
2012-07-31 02:09:46 +04:00
|
|
|
if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
|
2012-08-09 17:45:00 +04:00
|
|
|
current = drm_mode;
|
2012-06-28 19:28:15 +04:00
|
|
|
if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
|
2012-08-09 17:45:00 +04:00
|
|
|
preferred = drm_mode;
|
2013-12-12 20:13:56 +04:00
|
|
|
best = drm_mode;
|
2012-06-28 19:28:15 +04:00
|
|
|
}
|
|
|
|
|
2013-05-24 01:23:15 +04:00
|
|
|
if (config == OUTPUT_CONFIG_MODELINE) {
|
2013-05-28 18:23:36 +04:00
|
|
|
configured = drm_output_add_mode(output, &modeline);
|
2012-08-09 17:45:00 +04:00
|
|
|
if (!configured)
|
2012-08-01 01:30:41 +04:00
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
|
2012-07-31 02:09:46 +04:00
|
|
|
if (current == NULL && crtc_mode.clock != 0) {
|
2013-05-28 18:23:36 +04:00
|
|
|
current = drm_output_add_mode(output, &crtc_mode);
|
2012-08-09 17:45:00 +04:00
|
|
|
if (!current)
|
2011-12-08 20:05:45 +04:00
|
|
|
goto err_free;
|
|
|
|
}
|
2011-06-21 19:16:58 +04:00
|
|
|
|
2013-05-24 01:23:15 +04:00
|
|
|
if (config == OUTPUT_CONFIG_CURRENT)
|
2012-07-31 05:51:08 +04:00
|
|
|
configured = current;
|
|
|
|
|
2012-07-31 02:09:46 +04:00
|
|
|
if (option_current_mode && current)
|
2013-09-19 01:56:35 +04:00
|
|
|
output->base.current_mode = ¤t->base;
|
2012-07-31 05:51:08 +04:00
|
|
|
else if (configured)
|
2013-09-19 01:56:35 +04:00
|
|
|
output->base.current_mode = &configured->base;
|
2012-07-31 02:09:46 +04:00
|
|
|
else if (preferred)
|
2013-09-19 01:56:35 +04:00
|
|
|
output->base.current_mode = &preferred->base;
|
2012-07-31 02:09:46 +04:00
|
|
|
else if (current)
|
2013-09-19 01:56:35 +04:00
|
|
|
output->base.current_mode = ¤t->base;
|
2013-12-12 20:13:56 +04:00
|
|
|
else if (best)
|
|
|
|
output->base.current_mode = &best->base;
|
2012-07-31 02:09:46 +04:00
|
|
|
|
2013-09-19 01:56:35 +04:00
|
|
|
if (output->base.current_mode == NULL) {
|
2013-05-02 13:10:04 +04:00
|
|
|
weston_log("no available modes for %s\n", output->base.name);
|
2012-07-31 02:09:46 +04:00
|
|
|
goto err_free;
|
2012-06-28 19:28:15 +04:00
|
|
|
}
|
2011-06-21 19:16:58 +04:00
|
|
|
|
2013-09-19 01:56:35 +04:00
|
|
|
output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
|
2012-07-31 02:09:46 +04:00
|
|
|
|
2012-11-13 22:10:18 +04:00
|
|
|
weston_output_init(&output->base, &ec->base, x, y,
|
|
|
|
connector->mmWidth, connector->mmHeight,
|
2013-05-24 01:23:15 +04:00
|
|
|
transform, scale);
|
2012-11-13 22:10:18 +04:00
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
if (ec->use_pixman) {
|
|
|
|
if (drm_output_init_pixman(output, ec) < 0) {
|
|
|
|
weston_log("Failed to init output pixman state\n");
|
|
|
|
goto err_output;
|
|
|
|
}
|
|
|
|
} else if (drm_output_init_egl(output, ec) < 0) {
|
2012-12-14 19:37:29 +04:00
|
|
|
weston_log("Failed to init output gl state\n");
|
2012-11-13 22:10:18 +04:00
|
|
|
goto err_output;
|
2012-10-21 21:29:26 +04:00
|
|
|
}
|
2012-05-03 19:39:35 +04:00
|
|
|
|
2012-02-29 21:53:50 +04:00
|
|
|
output->backlight = backlight_init(drm_device,
|
|
|
|
connector->connector_type);
|
|
|
|
if (output->backlight) {
|
2013-05-24 04:29:40 +04:00
|
|
|
weston_log("Initialized backlight, device %s\n",
|
|
|
|
output->backlight->path);
|
2012-02-29 21:53:50 +04:00
|
|
|
output->base.set_backlight = drm_set_backlight;
|
|
|
|
output->base.backlight_current = drm_get_backlight(output);
|
2013-05-24 04:29:40 +04:00
|
|
|
} else {
|
|
|
|
weston_log("Failed to initialize backlight\n");
|
2012-02-29 21:53:50 +04:00
|
|
|
}
|
|
|
|
|
2011-10-24 21:26:32 +04:00
|
|
|
wl_list_insert(ec->base.output_list.prev, &output->base.link);
|
|
|
|
|
2013-04-24 17:58:02 +04:00
|
|
|
find_and_parse_output_edid(ec, output, connector);
|
2013-05-09 23:31:09 +04:00
|
|
|
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
|
|
|
|
output->base.connection_internal = 1;
|
2013-04-24 17:58:02 +04:00
|
|
|
|
2013-04-06 01:07:11 +04:00
|
|
|
output->base.start_repaint_loop = drm_output_start_repaint_loop;
|
2012-01-26 08:32:28 +04:00
|
|
|
output->base.repaint = drm_output_repaint;
|
2011-08-30 00:52:23 +04:00
|
|
|
output->base.destroy = drm_output_destroy;
|
2012-02-23 18:45:49 +04:00
|
|
|
output->base.assign_planes = drm_assign_planes;
|
2012-02-29 21:53:50 +04:00
|
|
|
output->base.set_dpms = drm_set_dpms;
|
2012-04-17 13:20:48 +04:00
|
|
|
output->base.switch_mode = drm_output_switch_mode;
|
2011-03-11 18:39:20 +03:00
|
|
|
|
2013-05-02 00:52:12 +04:00
|
|
|
output->base.gamma_size = output->original_crtc->gamma_size;
|
|
|
|
output->base.set_gamma = drm_output_set_gamma;
|
|
|
|
|
2013-10-23 09:58:31 +04:00
|
|
|
weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
|
|
|
|
weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
|
2012-08-03 19:30:18 +04:00
|
|
|
|
2013-03-05 19:30:27 +04:00
|
|
|
weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
|
|
|
|
weston_compositor_stack_plane(&ec->base, &output->fb_plane,
|
|
|
|
&ec->base.primary_plane);
|
|
|
|
|
2012-07-27 01:57:15 +04:00
|
|
|
weston_log("Output %s, (connector %d, crtc %d)\n",
|
2013-05-02 13:10:04 +04:00
|
|
|
output->base.name, output->connector_id, output->crtc_id);
|
2012-06-28 19:28:15 +04:00
|
|
|
wl_list_for_each(m, &output->base.mode_list, link)
|
2014-01-10 22:15:17 +04:00
|
|
|
weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
|
2012-06-28 19:28:15 +04:00
|
|
|
m->width, m->height, m->refresh / 1000.0,
|
|
|
|
m->flags & WL_OUTPUT_MODE_PREFERRED ?
|
|
|
|
", preferred" : "",
|
|
|
|
m->flags & WL_OUTPUT_MODE_CURRENT ?
|
|
|
|
", current" : "",
|
|
|
|
connector->count_modes == 0 ?
|
|
|
|
", built-in" : "");
|
2012-06-09 00:45:33 +04:00
|
|
|
|
2010-06-11 20:56:24 +04:00
|
|
|
return 0;
|
2011-12-08 20:05:45 +04:00
|
|
|
|
2012-11-13 22:10:18 +04:00
|
|
|
err_output:
|
|
|
|
weston_output_destroy(&output->base);
|
2011-12-08 20:05:45 +04:00
|
|
|
err_free:
|
|
|
|
wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
|
|
|
|
base.link) {
|
|
|
|
wl_list_remove(&drm_mode->base.link);
|
|
|
|
free(drm_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreeCrtc(output->original_crtc);
|
|
|
|
ec->crtc_allocator &= ~(1 << output->crtc_id);
|
|
|
|
ec->connector_allocator &= ~(1 << output->connector_id);
|
|
|
|
free(output);
|
2012-03-12 02:27:41 +04:00
|
|
|
|
2011-12-08 20:05:45 +04:00
|
|
|
return -1;
|
2010-06-11 20:56:24 +04:00
|
|
|
}
|
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
static void
|
|
|
|
create_sprites(struct drm_compositor *ec)
|
|
|
|
{
|
|
|
|
struct drm_sprite *sprite;
|
|
|
|
drmModePlaneRes *plane_res;
|
|
|
|
drmModePlane *plane;
|
2012-03-30 19:52:39 +04:00
|
|
|
uint32_t i;
|
2012-02-23 18:45:49 +04:00
|
|
|
|
|
|
|
plane_res = drmModeGetPlaneResources(ec->drm.fd);
|
|
|
|
if (!plane_res) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("failed to get plane resources: %s\n",
|
2012-02-23 18:45:49 +04:00
|
|
|
strerror(errno));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < plane_res->count_planes; i++) {
|
|
|
|
plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
|
|
|
|
if (!plane)
|
|
|
|
continue;
|
|
|
|
|
2013-08-08 05:57:05 +04:00
|
|
|
sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
|
2012-02-23 18:45:49 +04:00
|
|
|
plane->count_formats));
|
|
|
|
if (!sprite) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("%s: out of memory\n",
|
2012-02-23 18:45:49 +04:00
|
|
|
__func__);
|
2014-01-02 15:39:40 +04:00
|
|
|
drmModeFreePlane(plane);
|
2012-02-23 18:45:49 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprite->possible_crtcs = plane->possible_crtcs;
|
|
|
|
sprite->plane_id = plane->plane_id;
|
2012-11-09 16:19:05 +04:00
|
|
|
sprite->current = NULL;
|
|
|
|
sprite->next = NULL;
|
2012-02-23 18:45:49 +04:00
|
|
|
sprite->compositor = ec;
|
|
|
|
sprite->count_formats = plane->count_formats;
|
|
|
|
memcpy(sprite->formats, plane->formats,
|
2012-03-12 04:48:44 +04:00
|
|
|
plane->count_formats * sizeof(plane->formats[0]));
|
2012-02-23 18:45:49 +04:00
|
|
|
drmModeFreePlane(plane);
|
2013-10-23 09:58:31 +04:00
|
|
|
weston_plane_init(&sprite->plane, &ec->base, 0, 0);
|
2013-03-05 19:30:27 +04:00
|
|
|
weston_compositor_stack_plane(&ec->base, &sprite->plane,
|
|
|
|
&ec->base.primary_plane);
|
2012-02-23 18:45:49 +04:00
|
|
|
|
|
|
|
wl_list_insert(&ec->sprite_list, &sprite->link);
|
|
|
|
}
|
|
|
|
|
2013-06-13 12:03:33 +04:00
|
|
|
drmModeFreePlaneResources(plane_res);
|
2012-02-23 18:45:49 +04:00
|
|
|
}
|
|
|
|
|
2012-02-24 06:45:32 +04:00
|
|
|
static void
|
|
|
|
destroy_sprites(struct drm_compositor *compositor)
|
|
|
|
{
|
|
|
|
struct drm_sprite *sprite, *next;
|
|
|
|
struct drm_output *output;
|
|
|
|
|
|
|
|
output = container_of(compositor->base.output_list.next,
|
|
|
|
struct drm_output, base.link);
|
|
|
|
|
|
|
|
wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
|
|
|
|
drmModeSetPlane(compositor->drm.fd,
|
|
|
|
sprite->plane_id,
|
|
|
|
output->crtc_id, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0);
|
2013-01-25 17:13:03 +04:00
|
|
|
drm_output_release_fb(output, sprite->current);
|
|
|
|
drm_output_release_fb(output, sprite->next);
|
2012-08-03 19:30:18 +04:00
|
|
|
weston_plane_release(&sprite->plane);
|
2012-02-24 06:45:32 +04:00
|
|
|
free(sprite);
|
|
|
|
}
|
|
|
|
}
|
2012-02-23 18:45:49 +04:00
|
|
|
|
2010-06-11 20:56:24 +04:00
|
|
|
static int
|
2012-03-30 19:52:39 +04:00
|
|
|
create_outputs(struct drm_compositor *ec, uint32_t option_connector,
|
2012-02-29 21:53:50 +04:00
|
|
|
struct udev_device *drm_device)
|
2010-06-11 20:56:24 +04:00
|
|
|
{
|
|
|
|
drmModeConnector *connector;
|
|
|
|
drmModeRes *resources;
|
|
|
|
int i;
|
2011-03-11 18:39:20 +03:00
|
|
|
int x = 0, y = 0;
|
2010-06-11 20:56:24 +04:00
|
|
|
|
2011-03-02 13:14:59 +03:00
|
|
|
resources = drmModeGetResources(ec->drm.fd);
|
2010-06-11 20:56:24 +04:00
|
|
|
if (!resources) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("drmModeGetResources failed\n");
|
2010-06-11 20:56:24 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
|
2012-03-07 23:55:21 +04:00
|
|
|
if (!ec->crtcs) {
|
|
|
|
drmModeFreeResources(resources);
|
2012-02-23 18:45:49 +04:00
|
|
|
return -1;
|
2012-03-07 23:55:21 +04:00
|
|
|
}
|
2012-02-23 18:45:49 +04:00
|
|
|
|
2012-08-09 23:18:28 +04:00
|
|
|
ec->min_width = resources->min_width;
|
|
|
|
ec->max_width = resources->max_width;
|
|
|
|
ec->min_height = resources->min_height;
|
|
|
|
ec->max_height = resources->max_height;
|
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
ec->num_crtcs = resources->count_crtcs;
|
|
|
|
memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
|
|
|
|
|
2010-06-11 20:56:24 +04:00
|
|
|
for (i = 0; i < resources->count_connectors; i++) {
|
2011-08-30 13:38:26 +04:00
|
|
|
connector = drmModeGetConnector(ec->drm.fd,
|
|
|
|
resources->connectors[i]);
|
2010-06-11 20:56:24 +04:00
|
|
|
if (connector == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (connector->connection == DRM_MODE_CONNECTED &&
|
|
|
|
(option_connector == 0 ||
|
2011-08-02 15:03:54 +04:00
|
|
|
connector->connector_id == option_connector)) {
|
2011-03-11 18:39:20 +03:00
|
|
|
if (create_output_for_connector(ec, resources,
|
2012-02-29 21:53:50 +04:00
|
|
|
connector, x, y,
|
|
|
|
drm_device) < 0) {
|
2011-10-07 10:20:53 +04:00
|
|
|
drmModeFreeConnector(connector);
|
|
|
|
continue;
|
|
|
|
}
|
2010-06-11 20:56:24 +04:00
|
|
|
|
2011-08-02 15:03:54 +04:00
|
|
|
x += container_of(ec->base.output_list.prev,
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
struct weston_output,
|
2012-08-18 11:04:05 +04:00
|
|
|
link)->width;
|
2011-08-02 15:03:54 +04:00
|
|
|
}
|
2011-03-11 18:39:20 +03:00
|
|
|
|
2010-06-11 20:56:24 +04:00
|
|
|
drmModeFreeConnector(connector);
|
|
|
|
}
|
|
|
|
|
2010-06-14 19:54:00 +04:00
|
|
|
if (wl_list_empty(&ec->base.output_list)) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("No currently active connector found.\n");
|
2012-03-07 23:55:21 +04:00
|
|
|
drmModeFreeResources(resources);
|
2010-06-11 20:56:24 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreeResources(resources);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-03-15 17:08:41 +03:00
|
|
|
static void
|
2012-02-29 21:53:50 +04:00
|
|
|
update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
|
2011-03-15 17:08:41 +03:00
|
|
|
{
|
|
|
|
drmModeConnector *connector;
|
|
|
|
drmModeRes *resources;
|
|
|
|
struct drm_output *output, *next;
|
|
|
|
int x = 0, y = 0;
|
|
|
|
uint32_t connected = 0, disconnects = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
resources = drmModeGetResources(ec->drm.fd);
|
|
|
|
if (!resources) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("drmModeGetResources failed\n");
|
2011-03-15 17:08:41 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* collect new connects */
|
|
|
|
for (i = 0; i < resources->count_connectors; i++) {
|
2011-08-30 13:38:26 +04:00
|
|
|
int connector_id = resources->connectors[i];
|
|
|
|
|
|
|
|
connector = drmModeGetConnector(ec->drm.fd, connector_id);
|
2011-12-08 20:05:43 +04:00
|
|
|
if (connector == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (connector->connection != DRM_MODE_CONNECTED) {
|
|
|
|
drmModeFreeConnector(connector);
|
2011-03-15 17:08:41 +03:00
|
|
|
continue;
|
2011-12-08 20:05:43 +04:00
|
|
|
}
|
2011-03-15 17:08:41 +03:00
|
|
|
|
2011-08-30 13:38:26 +04:00
|
|
|
connected |= (1 << connector_id);
|
|
|
|
|
|
|
|
if (!(ec->connector_allocator & (1 << connector_id))) {
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
struct weston_output *last =
|
2011-03-15 17:08:41 +03:00
|
|
|
container_of(ec->base.output_list.prev,
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
struct weston_output, link);
|
2011-03-15 17:08:41 +03:00
|
|
|
|
|
|
|
/* XXX: not yet needed, we die with 0 outputs */
|
|
|
|
if (!wl_list_empty(&ec->base.output_list))
|
2012-08-18 11:04:05 +04:00
|
|
|
x = last->x + last->width;
|
2011-03-15 17:08:41 +03:00
|
|
|
else
|
|
|
|
x = 0;
|
|
|
|
y = 0;
|
|
|
|
create_output_for_connector(ec, resources,
|
2012-02-29 21:53:50 +04:00
|
|
|
connector, x, y,
|
|
|
|
drm_device);
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("connector %d connected\n", connector_id);
|
2011-08-30 13:38:26 +04:00
|
|
|
|
2011-03-15 17:08:41 +03:00
|
|
|
}
|
|
|
|
drmModeFreeConnector(connector);
|
|
|
|
}
|
|
|
|
drmModeFreeResources(resources);
|
|
|
|
|
|
|
|
disconnects = ec->connector_allocator & ~connected;
|
|
|
|
if (disconnects) {
|
|
|
|
wl_list_for_each_safe(output, next, &ec->base.output_list,
|
|
|
|
base.link) {
|
|
|
|
if (disconnects & (1 << output->connector_id)) {
|
|
|
|
disconnects &= ~(1 << output->connector_id);
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("connector %d disconnected\n",
|
2011-03-15 17:08:41 +03:00
|
|
|
output->connector_id);
|
2011-08-30 13:44:56 +04:00
|
|
|
drm_output_destroy(&output->base);
|
2011-03-15 17:08:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: handle zero outputs, without terminating */
|
|
|
|
if (ec->connector_allocator == 0)
|
|
|
|
wl_display_terminate(ec->base.wl_display);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-11 23:05:21 +04:00
|
|
|
udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
|
2011-03-15 17:08:41 +03:00
|
|
|
{
|
2012-03-11 23:05:21 +04:00
|
|
|
const char *sysnum;
|
2012-03-11 23:05:22 +04:00
|
|
|
const char *val;
|
2012-03-11 23:05:21 +04:00
|
|
|
|
|
|
|
sysnum = udev_device_get_sysnum(device);
|
|
|
|
if (!sysnum || atoi(sysnum) != ec->drm.id)
|
|
|
|
return 0;
|
2011-08-30 13:38:26 +04:00
|
|
|
|
2012-03-11 23:05:22 +04:00
|
|
|
val = udev_device_get_property_value(device, "HOTPLUG");
|
|
|
|
if (!val)
|
2011-03-15 17:08:41 +03:00
|
|
|
return 0;
|
|
|
|
|
2012-03-11 23:05:22 +04:00
|
|
|
return strcmp(val, "1") == 0;
|
2011-03-15 17:08:41 +03:00
|
|
|
}
|
|
|
|
|
2011-04-22 20:27:57 +04:00
|
|
|
static int
|
2011-03-15 17:08:41 +03:00
|
|
|
udev_drm_event(int fd, uint32_t mask, void *data)
|
|
|
|
{
|
|
|
|
struct drm_compositor *ec = data;
|
|
|
|
struct udev_device *event;
|
|
|
|
|
|
|
|
event = udev_monitor_receive_device(ec->udev_monitor);
|
2011-08-30 13:38:26 +04:00
|
|
|
|
2012-03-11 23:05:21 +04:00
|
|
|
if (udev_event_is_hotplug(ec, event))
|
2012-02-29 21:53:50 +04:00
|
|
|
update_outputs(ec, event);
|
2011-03-15 17:08:41 +03:00
|
|
|
|
|
|
|
udev_device_unref(event);
|
2011-04-22 20:27:57 +04:00
|
|
|
|
|
|
|
return 1;
|
2011-03-15 17:08:41 +03:00
|
|
|
}
|
|
|
|
|
2012-07-31 22:32:01 +04:00
|
|
|
static void
|
|
|
|
drm_restore(struct weston_compositor *ec)
|
|
|
|
{
|
2013-09-19 10:00:17 +04:00
|
|
|
weston_launcher_restore(ec->launcher);
|
2012-07-31 22:32:01 +04:00
|
|
|
}
|
|
|
|
|
2010-12-02 00:52:15 +03:00
|
|
|
static void
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
drm_destroy(struct weston_compositor *ec)
|
2010-12-02 00:52:15 +03:00
|
|
|
{
|
|
|
|
struct drm_compositor *d = (struct drm_compositor *) ec;
|
|
|
|
|
2013-05-31 21:09:55 +04:00
|
|
|
udev_input_destroy(&d->input);
|
2012-03-29 00:36:09 +04:00
|
|
|
|
|
|
|
wl_event_source_remove(d->udev_drm_source);
|
|
|
|
wl_event_source_remove(d->drm_source);
|
|
|
|
|
2013-05-10 20:36:04 +04:00
|
|
|
destroy_sprites(d);
|
|
|
|
|
2013-10-25 17:26:32 +04:00
|
|
|
weston_compositor_shutdown(ec);
|
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
if (d->gbm)
|
|
|
|
gbm_device_destroy(d->gbm);
|
|
|
|
|
2013-09-19 10:00:17 +04:00
|
|
|
weston_launcher_destroy(d->base.launcher);
|
2010-12-02 00:52:15 +03:00
|
|
|
|
2013-07-26 19:29:35 +04:00
|
|
|
close(d->drm.fd);
|
|
|
|
|
2011-01-14 22:59:13 +03:00
|
|
|
free(d);
|
2010-12-02 00:52:15 +03:00
|
|
|
}
|
|
|
|
|
2012-01-18 20:48:46 +04:00
|
|
|
static void
|
|
|
|
drm_compositor_set_modes(struct drm_compositor *compositor)
|
|
|
|
{
|
|
|
|
struct drm_output *output;
|
|
|
|
struct drm_mode *drm_mode;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
wl_list_for_each(output, &compositor->base.output_list, base.link) {
|
2013-02-26 15:44:58 +04:00
|
|
|
if (!output->current) {
|
|
|
|
/* If something that would cause the output to
|
|
|
|
* switch mode happened while in another vt, we
|
|
|
|
* might not have a current drm_fb. In that case,
|
|
|
|
* schedule a repaint and let drm_output_repaint
|
|
|
|
* handle setting the mode. */
|
|
|
|
weston_output_schedule_repaint(&output->base);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-09-19 01:56:35 +04:00
|
|
|
drm_mode = (struct drm_mode *) output->base.current_mode;
|
2012-01-18 20:48:46 +04:00
|
|
|
ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
|
2012-05-02 17:42:21 +04:00
|
|
|
output->current->fb_id, 0, 0,
|
2012-01-18 20:48:46 +04:00
|
|
|
&output->connector_id, 1,
|
|
|
|
&drm_mode->mode_info);
|
|
|
|
if (ret < 0) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log(
|
2012-03-12 02:27:41 +04:00
|
|
|
"failed to set mode %dx%d for output at %d,%d: %m\n",
|
2012-01-18 20:48:46 +04:00
|
|
|
drm_mode->base.width, drm_mode->base.height,
|
|
|
|
output->base.x, output->base.y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-06 23:15:37 +04:00
|
|
|
static void
|
2013-09-18 03:02:57 +04:00
|
|
|
session_notify(struct wl_listener *listener, void *data)
|
2011-05-06 23:15:37 +04:00
|
|
|
{
|
2013-09-18 03:02:57 +04:00
|
|
|
struct weston_compositor *compositor = data;
|
|
|
|
struct drm_compositor *ec = data;
|
2012-02-24 06:45:32 +04:00
|
|
|
struct drm_sprite *sprite;
|
2012-07-14 09:06:28 +04:00
|
|
|
struct drm_output *output;
|
2011-05-06 23:15:37 +04:00
|
|
|
|
2013-09-18 03:02:57 +04:00
|
|
|
if (ec->base.session_active) {
|
|
|
|
weston_log("activating session\n");
|
2011-12-02 15:07:27 +04:00
|
|
|
compositor->state = ec->prev_state;
|
2012-01-18 20:48:46 +04:00
|
|
|
drm_compositor_set_modes(ec);
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
weston_compositor_damage_all(compositor);
|
2014-03-13 01:08:41 +04:00
|
|
|
udev_input_enable(&ec->input);
|
2013-09-18 03:02:57 +04:00
|
|
|
} else {
|
|
|
|
weston_log("deactivating session\n");
|
2013-05-31 21:09:55 +04:00
|
|
|
udev_input_disable(&ec->input);
|
2012-04-10 08:08:45 +04:00
|
|
|
|
2011-12-02 15:07:27 +04:00
|
|
|
ec->prev_state = compositor->state;
|
2013-03-29 16:01:56 +04:00
|
|
|
weston_compositor_offscreen(compositor);
|
2011-05-06 23:38:28 +04:00
|
|
|
|
2012-01-18 20:50:31 +04:00
|
|
|
/* If we have a repaint scheduled (either from a
|
|
|
|
* pending pageflip or the idle handler), make sure we
|
|
|
|
* cancel that so we don't try to pageflip when we're
|
2013-03-29 16:01:56 +04:00
|
|
|
* vt switched away. The OFFSCREEN state will prevent
|
2012-01-18 20:50:31 +04:00
|
|
|
* further attemps at repainting. When we switch
|
|
|
|
* back, we schedule a repaint, which will process
|
|
|
|
* pending frame callbacks. */
|
|
|
|
|
2012-07-14 09:06:28 +04:00
|
|
|
wl_list_for_each(output, &ec->base.output_list, base.link) {
|
|
|
|
output->base.repaint_needed = 0;
|
|
|
|
drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
|
2012-01-18 20:50:31 +04:00
|
|
|
}
|
|
|
|
|
2012-07-14 09:06:28 +04:00
|
|
|
output = container_of(ec->base.output_list.next,
|
|
|
|
struct drm_output, base.link);
|
2012-02-24 06:45:32 +04:00
|
|
|
|
|
|
|
wl_list_for_each(sprite, &ec->sprite_list, link)
|
|
|
|
drmModeSetPlane(ec->drm.fd,
|
|
|
|
sprite->plane_id,
|
2012-07-14 09:06:28 +04:00
|
|
|
output->crtc_id, 0, 0,
|
2012-02-24 06:45:32 +04:00
|
|
|
0, 0, 0, 0, 0, 0, 0, 0);
|
2011-05-06 23:15:37 +04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-04-10 08:11:50 +04:00
|
|
|
static void
|
2013-05-07 07:19:49 +04:00
|
|
|
switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
|
2012-04-10 08:11:50 +04:00
|
|
|
{
|
2013-09-19 10:00:17 +04:00
|
|
|
struct weston_compositor *compositor = data;
|
2012-04-10 08:11:50 +04:00
|
|
|
|
2013-09-19 10:00:17 +04:00
|
|
|
weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
|
2012-04-10 08:11:50 +04:00
|
|
|
}
|
|
|
|
|
2012-10-29 22:21:16 +04:00
|
|
|
/*
|
|
|
|
* Find primary GPU
|
|
|
|
* Some systems may have multiple DRM devices attached to a single seat. This
|
|
|
|
* function loops over all devices and tries to find a PCI device with the
|
|
|
|
* boot_vga sysfs attribute set to 1.
|
|
|
|
* If no such device is found, the first DRM device reported by udev is used.
|
|
|
|
*/
|
|
|
|
static struct udev_device*
|
|
|
|
find_primary_gpu(struct drm_compositor *ec, const char *seat)
|
|
|
|
{
|
|
|
|
struct udev_enumerate *e;
|
|
|
|
struct udev_list_entry *entry;
|
|
|
|
const char *path, *device_seat, *id;
|
|
|
|
struct udev_device *device, *drm_device, *pci;
|
|
|
|
|
|
|
|
e = udev_enumerate_new(ec->udev);
|
|
|
|
udev_enumerate_add_match_subsystem(e, "drm");
|
|
|
|
udev_enumerate_add_match_sysname(e, "card[0-9]*");
|
|
|
|
|
|
|
|
udev_enumerate_scan_devices(e);
|
|
|
|
drm_device = NULL;
|
|
|
|
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
|
|
|
|
path = udev_list_entry_get_name(entry);
|
|
|
|
device = udev_device_new_from_syspath(ec->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")) {
|
|
|
|
if (drm_device)
|
|
|
|
udev_device_unref(drm_device);
|
|
|
|
drm_device = device;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!drm_device)
|
|
|
|
drm_device = device;
|
|
|
|
else
|
|
|
|
udev_device_unref(device);
|
|
|
|
}
|
|
|
|
|
|
|
|
udev_enumerate_unref(e);
|
|
|
|
return drm_device;
|
|
|
|
}
|
|
|
|
|
2012-10-31 19:55:46 +04:00
|
|
|
static void
|
2013-05-07 07:19:49 +04:00
|
|
|
planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
|
2012-10-31 19:55:46 +04:00
|
|
|
{
|
|
|
|
struct drm_compositor *c = data;
|
|
|
|
|
2012-11-22 17:56:59 +04:00
|
|
|
switch (key) {
|
|
|
|
case KEY_C:
|
|
|
|
c->cursors_are_broken ^= 1;
|
|
|
|
break;
|
|
|
|
case KEY_V:
|
|
|
|
c->sprites_are_broken ^= 1;
|
|
|
|
break;
|
|
|
|
case KEY_O:
|
|
|
|
c->sprites_hidden ^= 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2012-11-21 17:11:37 +04:00
|
|
|
}
|
|
|
|
|
2013-08-31 01:28:22 +04:00
|
|
|
#ifdef BUILD_VAAPI_RECORDER
|
2014-05-09 16:57:38 +04:00
|
|
|
static void
|
|
|
|
recorder_destroy(struct drm_output *output)
|
|
|
|
{
|
|
|
|
vaapi_recorder_destroy(output->recorder);
|
|
|
|
output->recorder = NULL;
|
|
|
|
|
|
|
|
output->base.disable_planes--;
|
|
|
|
|
|
|
|
wl_list_remove(&output->recorder_frame_listener.link);
|
|
|
|
weston_log("[libva recorder] done\n");
|
|
|
|
}
|
|
|
|
|
2013-08-23 18:15:48 +04:00
|
|
|
static void
|
|
|
|
recorder_frame_notify(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct drm_output *output;
|
|
|
|
struct drm_compositor *c;
|
|
|
|
int fd, ret;
|
|
|
|
|
|
|
|
output = container_of(listener, struct drm_output,
|
|
|
|
recorder_frame_listener);
|
|
|
|
c = (struct drm_compositor *) output->base.compositor;
|
|
|
|
|
|
|
|
if (!output->recorder)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
|
|
|
|
DRM_CLOEXEC, &fd);
|
|
|
|
if (ret) {
|
|
|
|
weston_log("[libva recorder] "
|
|
|
|
"failed to create prime fd for front buffer\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-09 16:57:38 +04:00
|
|
|
ret = vaapi_recorder_frame(output->recorder, fd,
|
|
|
|
output->current->stride);
|
|
|
|
if (ret < 0) {
|
|
|
|
weston_log("[libva recorder] aborted: %m\n");
|
|
|
|
recorder_destroy(output);
|
|
|
|
}
|
2013-08-23 18:15:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
create_recorder(struct drm_compositor *c, int width, int height,
|
|
|
|
const char *filename)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
drm_magic_t magic;
|
|
|
|
|
|
|
|
fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
|
|
|
|
if (fd < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
drmGetMagic(fd, &magic);
|
|
|
|
drmAuthMagic(c->drm.fd, magic);
|
|
|
|
|
|
|
|
return vaapi_recorder_create(fd, width, height, filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct drm_compositor *c = data;
|
|
|
|
struct drm_output *output;
|
|
|
|
int width, height;
|
|
|
|
|
|
|
|
output = container_of(c->base.output_list.next,
|
|
|
|
struct drm_output, base.link);
|
|
|
|
|
|
|
|
if (!output->recorder) {
|
2014-05-06 17:49:06 +04:00
|
|
|
if (output->format != GBM_FORMAT_XRGB8888) {
|
|
|
|
weston_log("failed to start vaapi recorder: "
|
|
|
|
"output format not supported\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-19 01:56:35 +04:00
|
|
|
width = output->base.current_mode->width;
|
|
|
|
height = output->base.current_mode->height;
|
2013-08-23 18:15:48 +04:00
|
|
|
|
|
|
|
output->recorder =
|
|
|
|
create_recorder(c, width, height, "capture.h264");
|
|
|
|
if (!output->recorder) {
|
|
|
|
weston_log("failed to create vaapi recorder\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
output->base.disable_planes++;
|
|
|
|
|
|
|
|
output->recorder_frame_listener.notify = recorder_frame_notify;
|
|
|
|
wl_signal_add(&output->base.frame_signal,
|
|
|
|
&output->recorder_frame_listener);
|
|
|
|
|
|
|
|
weston_output_schedule_repaint(&output->base);
|
|
|
|
|
|
|
|
weston_log("[libva recorder] initialized\n");
|
|
|
|
} else {
|
2014-05-09 16:57:38 +04:00
|
|
|
recorder_destroy(output);
|
2013-08-23 18:15:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static void
|
|
|
|
recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
weston_log("Compiled without libva support\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-11-19 17:22:04 +04:00
|
|
|
static void
|
|
|
|
switch_to_gl_renderer(struct drm_compositor *c)
|
|
|
|
{
|
|
|
|
struct drm_output *output;
|
|
|
|
|
|
|
|
if (!c->use_pixman)
|
|
|
|
return;
|
|
|
|
|
|
|
|
weston_log("Switching to GL renderer\n");
|
|
|
|
|
|
|
|
c->gbm = create_gbm_device(c->drm.fd);
|
|
|
|
if (!c->gbm) {
|
|
|
|
weston_log("Failed to create gbm device. "
|
|
|
|
"Aborting renderer switch\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
wl_list_for_each(output, &c->base.output_list, base.link)
|
|
|
|
pixman_renderer_output_destroy(&output->base);
|
|
|
|
|
|
|
|
c->base.renderer->destroy(&c->base);
|
|
|
|
|
|
|
|
if (drm_compositor_create_gl_renderer(c) < 0) {
|
|
|
|
gbm_device_destroy(c->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, &c->base.output_list, base.link)
|
|
|
|
drm_output_init_egl(output, c);
|
|
|
|
|
|
|
|
c->use_pixman = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
|
|
|
|
|
|
|
|
switch_to_gl_renderer(c);
|
|
|
|
}
|
|
|
|
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
static struct weston_compositor *
|
2011-07-16 05:28:38 +04:00
|
|
|
drm_compositor_create(struct wl_display *display,
|
2013-10-17 03:15:11 +04:00
|
|
|
struct drm_parameters *param,
|
2013-05-27 05:48:14 +04:00
|
|
|
int *argc, char *argv[],
|
|
|
|
struct weston_config *config)
|
2010-06-11 20:56:24 +04:00
|
|
|
{
|
2010-06-14 19:54:00 +04:00
|
|
|
struct drm_compositor *ec;
|
2013-10-17 03:31:42 +04:00
|
|
|
struct weston_config_section *section;
|
2012-10-29 22:21:16 +04:00
|
|
|
struct udev_device *drm_device;
|
2010-06-11 20:56:24 +04:00
|
|
|
struct wl_event_loop *loop;
|
2012-10-29 22:21:16 +04:00
|
|
|
const char *path;
|
2012-04-10 08:11:50 +04:00
|
|
|
uint32_t key;
|
2010-06-11 20:56:24 +04:00
|
|
|
|
2012-06-09 00:45:33 +04:00
|
|
|
weston_log("initializing drm backend\n");
|
|
|
|
|
2013-08-08 05:57:05 +04:00
|
|
|
ec = zalloc(sizeof *ec);
|
2010-06-14 19:54:00 +04:00
|
|
|
if (ec == NULL)
|
|
|
|
return NULL;
|
2012-06-22 17:04:36 +04:00
|
|
|
|
2012-11-02 18:14:40 +04:00
|
|
|
/* KMS support for sprites is not complete yet, so disable the
|
|
|
|
* functionality for now. */
|
|
|
|
ec->sprites_are_broken = 1;
|
2013-10-17 03:31:42 +04:00
|
|
|
|
|
|
|
section = weston_config_get_section(config, "core", NULL, NULL);
|
2014-03-07 22:05:50 +04:00
|
|
|
if (get_gbm_format_from_section(section,
|
|
|
|
GBM_FORMAT_XRGB8888,
|
|
|
|
&ec->format) == -1)
|
2013-10-17 03:31:42 +04:00
|
|
|
goto err_base;
|
|
|
|
|
2013-10-17 03:15:11 +04:00
|
|
|
ec->use_pixman = param->use_pixman;
|
2013-01-25 17:13:05 +04:00
|
|
|
|
2012-06-22 17:04:36 +04:00
|
|
|
if (weston_compositor_init(&ec->base, display, argc, argv,
|
2013-05-27 05:48:14 +04:00
|
|
|
config) < 0) {
|
2013-02-23 23:04:56 +04:00
|
|
|
weston_log("%s failed\n", __func__);
|
2012-06-22 17:04:37 +04:00
|
|
|
goto err_base;
|
|
|
|
}
|
2012-06-22 17:04:36 +04:00
|
|
|
|
2013-03-27 21:39:28 +04:00
|
|
|
/* Check if we run drm-backend using weston-launch */
|
2013-10-22 02:28:09 +04:00
|
|
|
ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
|
|
|
|
param->seat_id);
|
2013-09-19 10:00:17 +04:00
|
|
|
if (ec->base.launcher == NULL) {
|
2013-03-27 21:39:28 +04:00
|
|
|
weston_log("fatal: drm backend should be run "
|
2013-04-05 05:36:20 +04:00
|
|
|
"using weston-launch binary or as root\n");
|
2013-03-27 21:39:28 +04:00
|
|
|
goto err_compositor;
|
|
|
|
}
|
|
|
|
|
2010-06-11 20:56:24 +04:00
|
|
|
ec->udev = udev_new();
|
|
|
|
if (ec->udev == NULL) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("failed to initialize udev context\n");
|
2013-09-19 10:00:17 +04:00
|
|
|
goto err_launcher;
|
2010-06-11 20:56:24 +04:00
|
|
|
}
|
|
|
|
|
2012-01-15 23:29:09 +04:00
|
|
|
ec->base.wl_display = display;
|
2013-09-18 03:02:57 +04:00
|
|
|
ec->session_listener.notify = session_notify;
|
|
|
|
wl_signal_add(&ec->base.session_signal, &ec->session_listener);
|
2012-01-15 23:29:09 +04:00
|
|
|
|
2013-10-17 03:15:11 +04:00
|
|
|
drm_device = find_primary_gpu(ec, param->seat_id);
|
2011-07-16 05:28:38 +04:00
|
|
|
if (drm_device == NULL) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("no drm device found\n");
|
2013-09-19 10:00:17 +04:00
|
|
|
goto err_udev;
|
2010-06-14 19:54:00 +04:00
|
|
|
}
|
2012-10-29 22:21:16 +04:00
|
|
|
path = udev_device_get_syspath(drm_device);
|
2010-06-11 20:56:24 +04:00
|
|
|
|
2013-01-25 17:13:02 +04:00
|
|
|
if (init_drm(ec, drm_device) < 0) {
|
|
|
|
weston_log("failed to initialize kms\n");
|
|
|
|
goto err_udev_dev;
|
|
|
|
}
|
|
|
|
|
2013-01-25 17:13:05 +04:00
|
|
|
if (ec->use_pixman) {
|
|
|
|
if (init_pixman(ec) < 0) {
|
|
|
|
weston_log("failed to initialize pixman renderer\n");
|
|
|
|
goto err_udev_dev;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (init_egl(ec) < 0) {
|
|
|
|
weston_log("failed to initialize egl\n");
|
|
|
|
goto err_udev_dev;
|
|
|
|
}
|
2010-06-11 20:56:24 +04:00
|
|
|
}
|
2011-01-15 00:20:21 +03:00
|
|
|
|
|
|
|
ec->base.destroy = drm_destroy;
|
2012-07-31 22:32:01 +04:00
|
|
|
ec->base.restore = drm_restore;
|
2011-04-20 13:02:58 +04:00
|
|
|
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
|
2011-12-02 15:07:27 +04:00
|
|
|
|
2012-04-10 08:11:50 +04:00
|
|
|
for (key = KEY_F1; key < KEY_F9; key++)
|
2012-05-30 19:31:58 +04:00
|
|
|
weston_compositor_add_key_binding(&ec->base, key,
|
|
|
|
MODIFIER_CTRL | MODIFIER_ALT,
|
|
|
|
switch_vt_binding, ec);
|
2012-04-10 08:11:50 +04:00
|
|
|
|
2012-02-23 18:45:49 +04:00
|
|
|
wl_list_init(&ec->sprite_list);
|
|
|
|
create_sprites(ec);
|
|
|
|
|
2014-04-17 14:08:45 +04:00
|
|
|
if (udev_input_init(&ec->input,
|
|
|
|
&ec->base, ec->udev, param->seat_id) < 0) {
|
|
|
|
weston_log("failed to create input devices\n");
|
|
|
|
goto err_sprite;
|
|
|
|
}
|
|
|
|
|
2013-10-17 03:15:11 +04:00
|
|
|
if (create_outputs(ec, param->connector, drm_device) < 0) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("failed to create output for %s\n", path);
|
2014-04-17 14:08:45 +04:00
|
|
|
goto err_udev_input;
|
2010-06-14 19:54:00 +04:00
|
|
|
}
|
|
|
|
|
2014-04-03 04:53:46 +04:00
|
|
|
/* A this point we have some idea of whether or not we have a working
|
|
|
|
* cursor plane. */
|
|
|
|
if (!ec->cursors_are_broken)
|
|
|
|
ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
|
|
|
|
|
2011-10-07 10:27:26 +04:00
|
|
|
path = NULL;
|
|
|
|
|
2010-06-14 19:54:00 +04:00
|
|
|
loop = wl_display_get_event_loop(ec->base.wl_display);
|
|
|
|
ec->drm_source =
|
2011-03-02 13:14:59 +03:00
|
|
|
wl_event_loop_add_fd(loop, ec->drm.fd,
|
2010-06-14 19:54:00 +04:00
|
|
|
WL_EVENT_READABLE, on_drm_input, ec);
|
2010-06-11 20:56:24 +04:00
|
|
|
|
2011-03-15 17:08:41 +03:00
|
|
|
ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
|
|
|
|
if (ec->udev_monitor == NULL) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("failed to intialize udev monitor\n");
|
2012-06-22 17:04:37 +04:00
|
|
|
goto err_drm_source;
|
2011-03-15 17:08:41 +03:00
|
|
|
}
|
|
|
|
udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
|
|
|
|
"drm", NULL);
|
|
|
|
ec->udev_drm_source =
|
2011-08-30 13:38:26 +04:00
|
|
|
wl_event_loop_add_fd(loop,
|
|
|
|
udev_monitor_get_fd(ec->udev_monitor),
|
2011-03-15 17:08:41 +03:00
|
|
|
WL_EVENT_READABLE, udev_drm_event, ec);
|
|
|
|
|
|
|
|
if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
|
2012-06-07 20:01:59 +04:00
|
|
|
weston_log("failed to enable udev-monitor receiving\n");
|
2012-06-22 17:04:37 +04:00
|
|
|
goto err_udev_monitor;
|
2011-03-15 17:08:41 +03:00
|
|
|
}
|
|
|
|
|
2012-06-22 17:04:37 +04:00
|
|
|
udev_device_unref(drm_device);
|
|
|
|
|
2012-11-08 19:20:45 +04:00
|
|
|
weston_compositor_add_debug_binding(&ec->base, KEY_O,
|
2012-11-22 17:56:59 +04:00
|
|
|
planes_binding, ec);
|
2012-11-21 17:11:37 +04:00
|
|
|
weston_compositor_add_debug_binding(&ec->base, KEY_C,
|
2012-11-22 17:56:59 +04:00
|
|
|
planes_binding, ec);
|
|
|
|
weston_compositor_add_debug_binding(&ec->base, KEY_V,
|
|
|
|
planes_binding, ec);
|
2013-08-23 18:15:48 +04:00
|
|
|
weston_compositor_add_debug_binding(&ec->base, KEY_Q,
|
|
|
|
recorder_binding, ec);
|
2013-11-19 17:22:04 +04:00
|
|
|
weston_compositor_add_debug_binding(&ec->base, KEY_W,
|
|
|
|
renderer_switch_binding, ec);
|
2012-10-31 19:55:46 +04:00
|
|
|
|
2010-06-14 19:54:00 +04:00
|
|
|
return &ec->base;
|
2012-06-22 17:04:37 +04:00
|
|
|
|
|
|
|
err_udev_monitor:
|
|
|
|
wl_event_source_remove(ec->udev_drm_source);
|
|
|
|
udev_monitor_unref(ec->udev_monitor);
|
|
|
|
err_drm_source:
|
|
|
|
wl_event_source_remove(ec->drm_source);
|
2014-04-17 14:08:45 +04:00
|
|
|
err_udev_input:
|
2013-05-31 21:09:55 +04:00
|
|
|
udev_input_destroy(&ec->input);
|
2012-09-07 04:51:00 +04:00
|
|
|
err_sprite:
|
2013-01-08 20:09:01 +04:00
|
|
|
ec->base.renderer->destroy(&ec->base);
|
2012-11-13 22:10:19 +04:00
|
|
|
gbm_device_destroy(ec->gbm);
|
2012-09-07 04:51:00 +04:00
|
|
|
destroy_sprites(ec);
|
2012-06-22 17:04:37 +04:00
|
|
|
err_udev_dev:
|
|
|
|
udev_device_unref(drm_device);
|
2013-09-19 10:00:17 +04:00
|
|
|
err_launcher:
|
|
|
|
weston_launcher_destroy(ec->base.launcher);
|
2012-06-22 17:04:37 +04:00
|
|
|
err_udev:
|
|
|
|
udev_unref(ec->udev);
|
|
|
|
err_compositor:
|
|
|
|
weston_compositor_shutdown(&ec->base);
|
|
|
|
err_base:
|
|
|
|
free(ec);
|
|
|
|
return NULL;
|
2010-06-11 20:56:24 +04:00
|
|
|
}
|
2011-05-03 06:09:20 +04:00
|
|
|
|
Rename wayland-compositor to weston
This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.
1) Initially, we had one big repository with protocol code, sample
compositor and sample clients. We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code. At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message. The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.
2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor. Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example. Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.
We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
2012-01-03 19:29:47 +04:00
|
|
|
WL_EXPORT struct weston_compositor *
|
2013-02-21 00:27:49 +04:00
|
|
|
backend_init(struct wl_display *display, int *argc, char *argv[],
|
2013-05-27 05:48:14 +04:00
|
|
|
struct weston_config *config)
|
2011-05-03 06:09:20 +04:00
|
|
|
{
|
2013-10-17 03:15:11 +04:00
|
|
|
struct drm_parameters param = { 0, };
|
2012-03-12 05:05:57 +04:00
|
|
|
|
|
|
|
const struct weston_option drm_options[] = {
|
2013-10-17 03:15:11 +04:00
|
|
|
{ WESTON_OPTION_INTEGER, "connector", 0, ¶m.connector },
|
|
|
|
{ WESTON_OPTION_STRING, "seat", 0, ¶m.seat_id },
|
|
|
|
{ WESTON_OPTION_INTEGER, "tty", 0, ¶m.tty },
|
2012-06-28 19:28:15 +04:00
|
|
|
{ WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
|
2013-10-17 03:15:11 +04:00
|
|
|
{ WESTON_OPTION_BOOLEAN, "use-pixman", 0, ¶m.use_pixman },
|
2012-03-12 05:05:57 +04:00
|
|
|
};
|
|
|
|
|
2013-10-17 03:15:11 +04:00
|
|
|
param.seat_id = default_seat;
|
|
|
|
|
2012-03-12 05:05:57 +04:00
|
|
|
parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
|
2011-05-03 06:09:20 +04:00
|
|
|
|
2013-10-17 03:15:11 +04:00
|
|
|
return drm_compositor_create(display, ¶m, argc, argv, config);
|
2011-05-03 06:09:20 +04:00
|
|
|
}
|