[Mesa-dev] [RFC] loader: Automatic PRIME detection

Thierry Reding thierry.reding at gmail.com
Mon Jan 2 14:32:03 UTC 2017


On Tue, Dec 27, 2016 at 01:57:21PM +0100, Axel Davy wrote:
> Hi Thierry,
> 
> Could you explain why in this situation default_fd would be a non-renderable
> device node ?

This is preparatory work to allow drivers for split display/render
setups to be tied together within Mesa. If you want accelerated
rendering on those setups, you currently need to patch applications so
that they can deal with two separate devices (patches exist to allow
this for Weston and kmscube, and possibly others).

In order to avoid having to patch applications, the renderonly (the name
is slightly confusing) drivers (Christian Gmeiner sent out patches a few
weeks ago) open two devices internally and contain some magic to share
buffers between the two devices.

So the typical use-case would be that you have two separate DRM devices,
one representing the scanout device and another representing the GPU. In
most cases the scanout device will be display-only, so it will have a
/dev/dri/cardX node, but no corresponding /dev/dri/renderDY node. On the
other hand the GPU will have a "dummy" /dev/dri/cardX node that doesn't
expose any outputs and a corresponding /dev/dri/renderDY node that is
used for rendering.

A bare-metal application (kmscube, Weston, ...) will have to find a node
to perform a modeset with, so it will have to find a /dev/dri/cardX node
which exposes one or more outputs. That will be the scanout device node.
But given that there's no render node there's no way to accelerate using
that device.

Composite drivers will bind to the scanout device node and find a render
node for the GPU (these are usually ARM SoCs, so it's fairly easy to
find the correct render node) and bind the GPU driver to that node. Then
the GPU driver will export buffers used for scanout and have the scanout
driver import them. That way the application can transparently use those
buffers for DRM/KMS.

> In my understanding, for X11 DRI3 the Xserver is supposed to give you a
> renderable device node,
> and for Wayland, the device path advertised is the one used by the server
> for compositing.

Both X11 and Wayland will try to use the device used by the server for
compositing. In both cases they will receive the /dev/dri/cardX device
node for the scanout device.

Effectively X11 and Wayland will call back into the scanout driver for
acceleration. However with a minimal renderonly driver that's not going
to work. I had posted a complete wrapper driver a long time ago which I
think could be improved to allow even this use-case to work, but I got
significant pushback.

Anyway, both X11 and Wayland use the loader_get_user_preferred_fd()
function that this patch modifies to allow overriding the final file
descriptor to use. Currently the only way to override is by providing
the DRI_PRIME environment variable or by setting up a dri.conf
configuration file.

loader_get_user_preferred_fd() returns a file descriptor (same as the
default_fd by default, or the one referring to the DRI_PRIME node) and a
flag that specifies whether or not the devices are the same. This is
used in order to determine if DMA-BUF or FLINK should be used to share
buffers.

X11 has special code paths to deal with the PRIME use-case involving an
extra blit, which is somewhat unfortunate because on many devices that's
not going to be necessary.

For Wayland the EGL platform code checks for availability of a render
node to determine whether or not DMA-BUF should be used. That breaks for
this particular case as well because we do have a cardX node without a
corresponding renderDY node.

I suspect that with a full wrapper driver this could be solved more
nicely, including avoiding the extra blit in X11 DRI3. However it's a
lot more code to maintain than piggy-backing on top of PRIME support,
and a lot more complicated to get right (and more potential for breaking
existing use-cases).

Thierry

> On 23/12/2016 21:36, Thierry Reding wrote:
> > From: Thierry Reding <treding at nvidia.com>
> > 
> > If a device doesn't support rendering and support for PRIME isn't
> > enabled via the DRI_PRIME environment variable or dri.conf, attempt to
> > find a render node which can be used to offload rendering.
> > 
> > Signed-off-by: Thierry Reding <treding at nvidia.com>
> > ---
> > Along with platform and host1x bus support in the loader, this is the
> > final piece of the puzzle to automatically allow split scanout/render
> > devices to work with Wayland compositors and the X.Org server.
> > 
> > Note that this requires that the Wayland compositor and X.Org server
> > are accelerated with a DRI driver to make sure that the default file
> > descriptor is properly set up.
> > 
> >   src/loader/loader.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++---
> >   1 file changed, 67 insertions(+), 4 deletions(-)
> > 
> > diff --git a/src/loader/loader.c b/src/loader/loader.c
> > index 505c33133be6..6384432970f2 100644
> > --- a/src/loader/loader.c
> > +++ b/src/loader/loader.c
> > @@ -108,6 +108,71 @@ static char *loader_get_dri_config_device_id(void)
> >   }
> >   #endif
> > +/*
> > + * For all devices that do not support rendering, try to find a different
> > + * device that will.
> > + *
> > + * Note that the absence of a render node doesn't technically imply that
> > + * the device can't render, but in practice this should work out fine.
> > + */
> > +static int drm_detect_prime_fd(int default_fd, int *different_device)
> > +{
> > +   int err, fd = -ENODEV;
> > +   drmDevicePtr device;
> > +
> > +   err = drmGetDevice(default_fd, &device);
> > +   if (err < 0)
> > +      goto err;
> > +
> > +   if ((device->available_nodes & (1 << DRM_NODE_RENDER)) == 0) {
> > +      unsigned int num_devices, i;
> > +      drmDevicePtr *devices;
> > +
> > +      err = drmGetDevices(NULL, 0);
> > +      if (err < 0)
> > +         goto err;
> > +
> > +      num_devices = err;
> > +
> > +      devices = calloc(num_devices, sizeof(drmDevicePtr));
> > +      if (!devices)
> > +         goto err;
> > +
> > +      err = drmGetDevices(devices, num_devices);
> > +      if (err < 0) {
> > +         free(devices);
> > +         goto err;
> > +      }
> > +
> > +      num_devices = err;
> > +
> > +      for (i = 0; i < num_devices; i++) {
> > +         if (devices[i]->available_nodes & (1 << DRM_NODE_RENDER)) {
> > +            fd = loader_open_device(devices[i]->nodes[DRM_NODE_RENDER]);
> > +            if (fd < 0) {
> > +               fd = -errno;
> > +               continue;
> > +            }
> > +
> > +            close(default_fd);
> > +            break;
> > +         }
> > +      }
> > +
> > +      drmFreeDevices(devices, num_devices);
> > +      free(devices);
> > +   }
> > +
> > +err:
> > +   if (fd < 0) {
> > +      *different_device = 0;
> > +      return default_fd;
> > +   }
> > +
> > +   *different_device = 1;
> > +   return fd;
> > +}
> > +
> >   static char *drm_construct_id_path_tag(drmDevicePtr device)
> >   {
> >   /* Length of "pci-xxxx_xx_xx_x\0" */
> > @@ -213,10 +278,8 @@ int loader_get_user_preferred_fd(int default_fd, int *different_device)
> >         prime = loader_get_dri_config_device_id();
> >   #endif
> > -   if (prime == NULL) {
> > -      *different_device = 0;
> > -      return default_fd;
> > -   }
> > +   if (prime == NULL || *prime == '\0')
> > +      return drm_detect_prime_fd(default_fd, different_device);
> >      default_tag = drm_get_id_path_tag_for_fd(default_fd);
> >      if (default_tag == NULL)
> 
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20170102/bfe61b4e/attachment-0001.sig>


More information about the mesa-dev mailing list