diff --git a/README b/README
index 7ba6d9f..d072bea 100644
--- a/README
+++ b/README
@@ -16,7 +16,7 @@ extensions:
Nonrectangular Window Shape Extension, version 1.1 or later
MIT Shared Memory Extension, version 1.2 or later
- X Resize, Rotate and Reflect Extension, version 1.3 or later
+ X Resize, Rotate and Reflect Extension, version 1.4 or later
X Synchronization Extension, version 1.0 or later
X Rendering Extension, version 1.2 or later
X Input Extension, version 2.3 or later
@@ -84,14 +84,6 @@ Extension, the following Wayland protocol is also supported:
'zwp_pointer_gestures_v1', version: 3
-With the main caveat being that zwp_linux_dmabuf_v1 has no real
-support for multiple-provider setups (help wanted).
-
-Window decorations are also not supported, even though they fit in
-nicely with X window management.
-
-It would also be nice to have pinch gesture support.
-
This directory is organized as follows:
Imakefile - the top level Makefile template
diff --git a/compositor.h b/compositor.h
index 10919dd..436beec 100644
--- a/compositor.h
+++ b/compositor.h
@@ -455,8 +455,9 @@ struct _BufferFuncs
0 formats if nothing is supported. */
DrmFormat *(*get_drm_formats) (int *);
- /* Get the DRM device node. */
- dev_t (*get_render_device) (Bool *);
+ /* Get a list of DRM device nodes for each provider. Return NULL if
+ the provider list could not be initialized. */
+ dev_t *(*get_render_devices) (int *);
/* Get SHM formats supported by this renderer. */
ShmFormat *(*get_shm_formats) (int *);
@@ -570,7 +571,7 @@ extern PresentCompletionKey RenderPresentToWindow (RenderTarget, RenderBuffer,
extern void RenderCancelPresentationCallback (PresentCompletionKey);
extern DrmFormat *RenderGetDrmFormats (int *);
-extern dev_t RenderGetRenderDevice (Bool *);
+extern dev_t *RenderGetRenderDevices (int *);
extern ShmFormat *RenderGetShmFormats (int *);
extern RenderBuffer RenderBufferFromDmaBuf (DmaBufAttributes *, Bool *);
extern void RenderBufferFromDmaBufAsync (DmaBufAttributes *, DmaBufSuccessFunc,
diff --git a/dmabuf.c b/dmabuf.c
index 347f03d..27f9d64 100644
--- a/dmabuf.c
+++ b/dmabuf.c
@@ -111,9 +111,11 @@ static int format_table_fd;
/* Size of the format table. */
static ssize_t format_table_size;
-/* Device node of the DRM device. TODO: make this
- output-specific. */
-static dev_t drm_device_node;
+/* Device nodes of the DRM device. */
+static dev_t *drm_device_nodes;
+
+/* The number of DRM device nodes present. */
+static int num_device_nodes;
/* DRM formats supported by the renderer. */
static DrmFormat *supported_formats;
@@ -836,31 +838,27 @@ static struct zwp_linux_dmabuf_feedback_v1_interface zld_feedback_v1_impl =
.destroy = Destroy,
};
-/* TODO: dynamically switch tranche for surface feedbacks based on the
- provider of the crtc the surface is in. */
-
static void
MakeFeedback (struct wl_client *client, struct wl_resource *resource,
uint32_t id)
{
- struct wl_resource *feedback_resource;
- struct wl_array main_device_array, format_array;
- int i;
+ struct wl_resource *feedback;
+ struct wl_array main_device_array, format_array, array;
+ int i, provider;
ptrdiff_t format_array_size;
uint16_t *format_array_data;
- feedback_resource = wl_resource_create (client,
- &zwp_linux_dmabuf_feedback_v1_interface,
- wl_resource_get_version (resource), id);
+ feedback = wl_resource_create (client,
+ &zwp_linux_dmabuf_feedback_v1_interface,
+ wl_resource_get_version (resource), id);
- if (!resource)
+ if (!feedback)
{
wl_resource_post_no_memory (resource);
return;
}
- wl_resource_set_implementation (feedback_resource,
- &zld_feedback_v1_impl,
+ wl_resource_set_implementation (feedback, &zld_feedback_v1_impl,
NULL, NULL);
/* Now, send the relevant information. This should eventually be
@@ -868,50 +866,56 @@ MakeFeedback (struct wl_client *client, struct wl_resource *resource,
/* First, send the format table. */
- zwp_linux_dmabuf_feedback_v1_send_format_table (feedback_resource,
+ zwp_linux_dmabuf_feedback_v1_send_format_table (feedback,
format_table_fd,
format_table_size);
- /* Next, send the main device. */
-
- main_device_array.size = sizeof drm_device_node;
- main_device_array.data = &drm_device_node;
+ /* Next, send the main device. The first provider returned by
+ RRGetProviders is considered to be the main device. */
+ main_device_array.size = sizeof drm_device_nodes[0];
+ main_device_array.data = &drm_device_nodes[0];
main_device_array.alloc = main_device_array.size;
- zwp_linux_dmabuf_feedback_v1_send_main_device (feedback_resource,
+
+ zwp_linux_dmabuf_feedback_v1_send_main_device (feedback,
&main_device_array);
- /* Then, send the first tranche. Right now, the only tranche
- contains the formats supported by the default provider. */
+ /* Then, send the one tranche for each device. */
+ for (provider = 0; provider < num_device_nodes; ++provider)
+ {
+ array.size = sizeof drm_device_nodes[provider];
+ array.data = &drm_device_nodes[provider];
+ array.alloc = array.size;
- zwp_linux_dmabuf_feedback_v1_send_tranche_target_device (feedback_resource,
- &main_device_array);
+ zwp_linux_dmabuf_feedback_v1_send_tranche_target_device (feedback,
+ &array);
- /* Populate the formats array with the contents of the format
- table, and send it to the client. */
+ /* Populate the formats array with the contents of the format
+ table, and send it to the client. */
- format_array_size = format_table_size / sizeof (FormatModifierPair);
- format_array.size = format_array_size * sizeof (uint16_t);
- format_array.data = format_array_data = alloca (format_array.size);
+ format_array_size = format_table_size / sizeof (FormatModifierPair);
+ format_array.size = format_array_size * sizeof (uint16_t);
+ format_array.data = format_array_data = alloca (format_array.size);
- /* This must be reset too. */
- format_array.alloc = format_array.size;
+ /* This must be reset too. */
+ format_array.alloc = format_array.size;
- /* Simply announce every format to the client. */
- for (i = 0; i < format_array_size; ++i)
- format_array_data[i] = i;
+ /* Simply announce every format to the client. */
+ for (i = 0; i < format_array_size; ++i)
+ format_array_data[i] = i;
- zwp_linux_dmabuf_feedback_v1_send_tranche_formats (feedback_resource,
- &format_array);
+ zwp_linux_dmabuf_feedback_v1_send_tranche_formats (feedback,
+ &format_array);
- /* Send flags. We don't currently support direct scanout, so send
- nothing. */
+ /* Send flags. We don't currently support direct scanout, so send
+ nothing. */
- zwp_linux_dmabuf_feedback_v1_send_tranche_flags (feedback_resource, 0);
+ zwp_linux_dmabuf_feedback_v1_send_tranche_flags (feedback, 0);
- /* Mark the end of the tranche. */
+ /* Mark the end of the tranche. */
- zwp_linux_dmabuf_feedback_v1_send_tranche_done (feedback_resource);
+ zwp_linux_dmabuf_feedback_v1_send_tranche_done (feedback);
+ }
}
static void
@@ -991,15 +995,12 @@ HandleBind (struct wl_client *client, void *data,
}
static Bool
-InitDrmDevice (void)
+InitDrmDevices (void)
{
- Bool error;
+ /* These can either be master nodes or render nodes. */
+ drm_device_nodes = RenderGetRenderDevices (&num_device_nodes);
- error = False;
-
- /* This can either be a master node or a render node. */
- drm_device_node = RenderGetRenderDevice (&error);
- return !error;
+ return num_device_nodes > 0;
}
static ssize_t
@@ -1011,7 +1012,7 @@ WriteFormatTable (void)
/* Before writing the format table, make sure the DRM device node
can be obtained. */
- if (!InitDrmDevice ())
+ if (!InitDrmDevices ())
{
fprintf (stderr, "Failed to get direct rendering device node. "
"Hardware acceleration will probably be unavailable.\n");
diff --git a/egl.c b/egl.c
index 84cd53c..8621504 100644
--- a/egl.c
+++ b/egl.c
@@ -1720,11 +1720,17 @@ GetDrmFormats (int *num_formats)
return drm_formats;
}
-static dev_t
-GetRenderDevice (Bool *error)
+static dev_t *
+GetRenderDevices (int *num_devices)
{
- *error = !drm_device_available;
- return drm_device;
+ if (!drm_device_available)
+ {
+ *num_devices = 0;
+ return NULL;
+ }
+
+ *num_devices = 1;
+ return &drm_device;
}
static ShmFormat *
@@ -2559,7 +2565,7 @@ IsBufferOpaque (RenderBuffer buffer)
static BufferFuncs egl_buffer_funcs =
{
.get_drm_formats = GetDrmFormats,
- .get_render_device = GetRenderDevice,
+ .get_render_devices = GetRenderDevices,
.get_shm_formats = GetShmFormats,
.buffer_from_dma_buf = BufferFromDmaBuf,
.buffer_from_dma_buf_async = BufferFromDmaBufAsync,
diff --git a/output.c b/output.c
index 351f1ea..0e990fc 100644
--- a/output.c
+++ b/output.c
@@ -1192,7 +1192,7 @@ XLInitRROutputs (void)
if (compositor.rr_major < 1
|| (compositor.rr_major == 1
- && compositor.rr_minor < 3))
+ && compositor.rr_minor < 4))
{
fprintf (stderr, "Display '%s' does not support a"
" sufficiently new version of the RandR extension\n",
@@ -1216,21 +1216,13 @@ XLInitRROutputs (void)
scale_callbacks.next = &scale_callbacks;
scale_callbacks.last = &scale_callbacks;
- if (compositor.rr_major > 1
- && (compositor.rr_major == 1
- && compositor.rr_minor >= 4))
- XRRSelectInput (compositor.display,
- DefaultRootWindow (compositor.display),
- (RRCrtcChangeNotifyMask
- | RROutputChangeNotifyMask
- | RROutputPropertyNotifyMask
- | RRResourceChangeNotifyMask));
- else
- XRRSelectInput (compositor.display,
- DefaultRootWindow (compositor.display),
- (RRCrtcChangeNotifyMask
- | RROutputChangeNotifyMask
- | RROutputPropertyNotifyMask));
+ /* Select for various kinds of required input. */
+ XRRSelectInput (compositor.display,
+ DefaultRootWindow (compositor.display),
+ (RRCrtcChangeNotifyMask
+ | RROutputChangeNotifyMask
+ | RROutputPropertyNotifyMask
+ | RRResourceChangeNotifyMask));
all_outputs = BuildOutputTree ();
MakeGlobalsForOutputTree (all_outputs);
diff --git a/picture_renderer.c b/picture_renderer.c
index 8bacfdf..86b08f4 100644
--- a/picture_renderer.c
+++ b/picture_renderer.c
@@ -29,6 +29,7 @@ along with 12to11. If not, see . */
#include "drm_modifiers.h"
#include
+#include
#include
#include
@@ -453,6 +454,12 @@ static PresentCompletionCallback all_completion_callbacks;
/* Whether or not direct presentation should be used. */
static Bool use_direct_presentation;
+/* The device nodes of each provider. */
+static dev_t *render_devices;
+
+/* The number of device nodes. */
+static int num_render_devices;
+
/* XRender, DRI3 and XPresent-based renderer. A RenderTarget is just
a Picture. Here is a rough explanation of how the buffer release
machinery works.
@@ -2287,60 +2294,117 @@ GetDrmFormats (int *num_formats)
}
static dev_t
-GetRenderDevice (Bool *error)
+GetRenderDevice (xcb_dri3_open_reply_t *reply, Bool *error)
{
- xcb_dri3_open_cookie_t cookie;
- xcb_dri3_open_reply_t *reply;
int *fds, fd;
struct stat dev_stat;
- cookie = xcb_dri3_open (compositor.conn,
- DefaultRootWindow (compositor.display),
- None);
- reply = xcb_dri3_open_reply (compositor.conn, cookie, NULL);
-
- if (!reply)
- {
- *error = True;
- return (dev_t) 0;
- }
-
fds = xcb_dri3_open_reply_fds (compositor.conn, reply);
if (!fds)
{
- free (reply);
*error = True;
-
return (dev_t) 0;
}
fd = fds[0];
- XLAddFdFlag (fd, FD_CLOEXEC, True);
-
if (fstat (fd, &dev_stat) != 0)
{
close (fd);
- free (reply);
*error = True;
-
- return (dev_t) 0;
- }
-
- if (!dev_stat.st_rdev)
- {
- close (fd);
- free (reply);
- *error = True;
-
return (dev_t) 0;
}
close (fd);
+ return dev_stat.st_rdev;
+}
+
+static dev_t *
+GetRenderDevices (int *num_devices)
+{
+ Window root;
+ xcb_randr_get_providers_cookie_t cookie;
+ xcb_randr_get_providers_reply_t *reply;
+ xcb_randr_provider_t *providers;
+ int nproviders;
+ xcb_dri3_open_cookie_t *open_cookies;
+ xcb_dri3_open_reply_t *open_reply;
+ xcb_generic_error_t *error;
+ int ndevices, i;
+ dev_t *devices;
+ Bool error_experienced;
+
+ if (render_devices)
+ {
+ *num_devices = num_render_devices;
+ return render_devices;
+ }
+
+ root = DefaultRootWindow (compositor.display);
+
+ /* Get a list of all providers on the default screen. */
+ cookie = xcb_randr_get_providers (compositor.conn,
+ root);
+ reply = xcb_randr_get_providers_reply (compositor.conn,
+ cookie, NULL);
+
+ if (!reply)
+ return NULL;
+
+ providers = xcb_randr_get_providers_providers (reply);
+ nproviders = xcb_randr_get_providers_providers_length (reply);
+
+ /* Now, open each and every provider. */
+ open_cookies = alloca (nproviders * sizeof *open_cookies);
+
+ for (i = 0; i < nproviders; ++i)
+ open_cookies[i] = xcb_dri3_open (compositor.conn, root,
+ providers[i]);
+
+ /* Free the provider list and wait for replies from the X server.
+ Also, allocate an array large enough to hold each device. */
+
free (reply);
- return dev_stat.st_rdev;
+ /* Allocate 1 extra provider so that render_devices is not set to
+ NULL if there are no providers. */
+ devices = XLCalloc (nproviders + 1, sizeof *devices);
+ ndevices = 0;
+
+ for (i = 0; i < nproviders; ++i)
+ {
+ open_reply = xcb_dri3_open_reply (compositor.conn, open_cookies[i],
+ &error);
+
+ if (error || !open_reply)
+ {
+ if (error)
+ free (error);
+
+ continue;
+ }
+
+ /* Now obtain the device node associated with the opened DRM
+ node. */
+ error_experienced = False;
+ devices[ndevices] = GetRenderDevice (open_reply, &error_experienced);
+ free (open_reply);
+
+ if (error_experienced)
+ /* An error occured. */
+ continue;
+
+ /* Otherwise, increment ndevices. */
+ ndevices++;
+ }
+
+ num_render_devices = ndevices;
+ render_devices = devices;
+
+ /* Return the device list. */
+ *num_devices = ndevices;
+ return devices;
}
static ShmFormat *
@@ -3242,7 +3306,7 @@ IsBufferOpaque (RenderBuffer buffer)
static BufferFuncs picture_buffer_funcs =
{
.get_drm_formats = GetDrmFormats,
- .get_render_device = GetRenderDevice,
+ .get_render_devices = GetRenderDevices,
.get_shm_formats = GetShmFormats,
.buffer_from_dma_buf = BufferFromDmaBuf,
.buffer_from_dma_buf_async = BufferFromDmaBufAsync,
diff --git a/renderer.c b/renderer.c
index 3ccf559..d13eb28 100644
--- a/renderer.c
+++ b/renderer.c
@@ -230,10 +230,10 @@ RenderGetDrmFormats (int *n_formats)
return buffer_funcs.get_drm_formats (n_formats);
}
-dev_t
-RenderGetRenderDevice (Bool *error)
+dev_t *
+RenderGetRenderDevices (int *num_devices)
{
- return buffer_funcs.get_render_device (error);
+ return buffer_funcs.get_render_devices (num_devices);
}
ShmFormat *