[Mesa-dev] [PATCH 3/3] egl/android: Add DRM node probing and filtering

Robert Foss robert.foss at collabora.com
Sat Jun 9 16:56:59 UTC 2018


Hey Tomasz,

On 2018-05-25 09:27, Tomasz Figa wrote:
 > Hi Rob,
 >
 > Finally got to review this. Please see my comments inline.
 >
 > On Fri, May 11, 2018 at 10:48 PM Robert Foss <robert.foss at collabora.com>
 > wrote:
 > [snip]
 >> +EGLBoolean
 >> +droid_load_driver(_EGLDisplay *disp)
 >
 > Since this is not EGL-facing, I'd personally use bool.
 >
 >> +{
 >> +   struct dri2_egl_display *dri2_dpy = disp->DriverData;
 >> +   const char *err;
 >> +
 >> +   dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
 >> +   if (dri2_dpy->driver_name == NULL) {
 >> +      err = "DRI2: failed to get driver name";
 >> +      goto error;
 >
 > It shouldn't be an error if there is no driver for given render node. We
 > should just skip it and try next one, which I believe would be achieved by
 > just returning false here.
 >
 >> +   }
 >> +
 >> +   dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) ==
 > DRM_NODE_RENDER;
 >> +
 >> +   if (!dri2_dpy->is_render_node) {
 >> +   #ifdef HAVE_DRM_GRALLOC
 >> +       /* Handle control nodes using __DRI_DRI2_LOADER extension and GEM
 > names
 >> +        * for backwards compatibility with drm_gralloc. (Do not use on
 > new
 >> +        * systems.) */
 >> +       dri2_dpy->loader_extensions = droid_dri2_loader_extensions;
 >> +       if (!dri2_load_driver(disp)) {
 >> +          err = "DRI2: failed to load driver";
 >> +          goto error;
 >> +       }
 >> +   #else
 >> +       err = "DRI2: handle is not for a render node";
 >> +       goto error;
 >> +   #endif
 >> +   } else {
 >> +       dri2_dpy->loader_extensions = droid_image_loader_extensions;
 >> +       if (!dri2_load_driver_dri3(disp)) {
 >> +          err = "DRI3: failed to load driver";
 >> +          goto error;
 >> +       }
 >> +    }
 >> +
 >> +   return EGL_TRUE;
 >> +
 >> +error:
 >> +   free(dri2_dpy->driver_name);
 >> +   dri2_dpy->driver_name = NULL;
 >> +   return _eglError(EGL_NOT_INITIALIZED, err);
 >
 > Hmm, if we signal EGL error here, we should break the probing loop and just
 > bail out. This would suggest that a boolean is not the right type for this
 > function to return. Perhaps something like negative error, 0 for skip and 1
 > for success would make sense?
 >
 > Also, how does it play with the _eglError() called from the error path of
 > dri2_initialize_android()?

I can't say I put any though into that aspect, but dri2_initialize_android() 
would overwrite it. So maybe completely avoiding _eglError() in 
droid_load_driver() is the way to go.

 >
 >> +}
 >> +
 >> +static int
 >> +droid_probe_driver(_EGLDisplay *disp, int fd)
 >> +{
 >> +   struct dri2_egl_display *dri2_dpy = disp->DriverData;
 >> +   dri2_dpy->fd = fd;
 >> +
 >> +   if (!droid_load_driver(disp))
 >> +      return false;
 >
 > Given my other suggestion about distinguishing failure, render node skip
 > and success, I think it should be more like this:
 >
 >      int ret = droid_load_driver(disp);
 >      if (ret <= 0)
 >         return ret;
 >
 > Or actually, maybe we don't really need to go as far as loading the driver.
 > I'd say it should be enough to just check if we have a driver for the
 > device by looking at what loader_get_driver_for_fd() returns. (In that
 > case, we can ignore my comment about returning error on
 > loader_get_driver_for_fd() failure in droid_load_driver(), since the
 > skipping would be handling only here.)

If we don't need to actually load the driver, I think all of the above
comments can be fixed by just removing chunks out of dri related setup.

 >
 >> +
 >> +   /* Since this probe can succeed, but another filter may fail,
 >
 > What another filter could fail? I can see the vendor name being checked
 > before calling this function.
 >
 > The free() below is actually needed, just the comment is off. We need to
 > free the name to be able to probe remaining nodes, without leaking the name.

Ack, fixed by the above change.

 >
 >> +      this string needs to be deallocated either way.
 >> +      Once an FD has been found, this string will be set a second time.
 > */
 >> +   free(dri2_dpy->driver_name);
 >
 > Don't we also need to unload the driver?

Ack, fixed by the above change.

 >
 >> +   dri2_dpy->driver_name = NULL;
 >> +   return true;
 >
 > To match the change above:
 >
 >      return 1;
 >

Ack, fixed by the above change.

 >> +}
 >> +
 >> +static int
 >> +droid_probe_device(_EGLDisplay *disp, int fd, drmDevicePtr dev, char
 > *vendor)
 >> +{
 >> +   drmVersionPtr ver = drmGetVersion(fd);
 >> +       if (!ver)
 >> +               goto fail;
 >
 > Something wrong with indentation here.

Ack.

 >
 >> +
 >> +   size_t vendor_len = strlen(vendor);
 >> +   if (vendor_len != 0 && strncmp(vendor, ver->name, vendor_len))
 >> +      goto fail;
 >
 > Maybe it's just me, but I don't see any point in using strncmp() if the
 > length argument is obtained by calling strlen() first. Especially if the
 > strlen() call is on a string that comes from some external code
 > (property_get()).
 >
 > Perhaps we could just call strncmp() with PROPERTY_VALUE_MAX? This would
 > actually play nice with my other comment about using NULL for vendor
 > string, if the property is not present.

Ack, that's reasonable. Replacing with PROPRTY_VALUE_MAX.

 >
 > Also nit: The label could be named in a more meaningful way, e.g.
 > err_free_version.
 >

Ack.

 >> +
 >> +   if (!droid_probe_driver(disp, fd))
 >> +      goto fail;
 >> +
 >> +   drmFreeVersion(ver);
 >> +   return true;
 >> +
 >> +fail:
 >> +   drmFreeVersion(ver);
 >> +   return false;
 >
 > Given my other suggestion about distinguishing failure, render node skip
 > and success, I think it should be more like this:
 >
 >      ret = droid_probe_driver(disp, fd);
 > err_free_version:
 >      drmFreeVersion(ver);
 >      return ret;
 >

Ack, this is fixed by removing all of the conditions that could cause an error 
(but not the ones that cause skips) from the driver probing path.
So just using a bool signifying skip/no-skip should be ok.

 >> +}
 >> +
 >> +static int
 >> +droid_open_device(_EGLDisplay *disp)
 >> +{
 >> +   const int MAX_DRM_DEVICES = 32;
 >> +   int prop_set, num_devices, ret;
 >> +   int fd = -1, fallback_fd = -1;
 >> +
 >> +   char vendor_name[PROPERTY_VALUE_MAX];
 >> +   property_get("drm.gpu.vendor_name", vendor_name, NULL);
 >
 > vendor_name[] is uninitialized. property_get() with NULL 3rd argument
 > wouldn't touch the 2nd argument if the property is missing.
 >
 > However, I'd recommend checking the return value of property_get() and pass
 > NULL as vendor_name to droid_probe_device() if it's <= 0. The check for
 > existence of the filter will be simpler with this.
 >

Ack, fixing it.

 >> +
 >> +   drmDevicePtr devices[MAX_DRM_DEVICES];
 >> +   num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
 >> +
 >> +   if (num_devices < 0) {
 >> +      _eglLog(_EGL_WARNING, "Unable to find DRM devices, error %d",
 > num_devices);
 >> +      return -1;
 >> +   }
 >> +
 >> +   if (num_devices == 0) {
 >> +      _eglLog(_EGL_WARNING, "Failed to find any DRM devices");
 >> +      return -1;
 >> +   }
 >> +
 >> +   for (int i = 0; i < num_devices; i++) {
 >> +      char *dev_path = devices[i]->nodes[DRM_NODE_RENDER];
 >> +      fd = loader_open_device(dev_path);
 >> +      if (fd == -1) {
 >> +         _eglLog(_EGL_WARNING, "%s() Failed to open DRM device %s",
 >> +                 __func__, dev_path);
 >> +         continue;
 >> +      }
 >> +
 >> +      if (!droid_probe_device(disp, fd, devices[i], vendor_name))
 >> +         goto next;
 >> +
 >> +      break;
 >
 > Hmm.
 >
 > Why not just
 >
 >      if (droid_probe_device(disp, fd, devices[i], vendor_name))
 >         break;
 >
 > ?
 >
 > But actually, we need to distinguish the cases of failure and simply render
 > node not matching any drivers. We shouldn't use such render node as
 > fallback.
 >
 >      int ret = droid_probe_device(...);
 >      if (!ret)
 >         break; // Found desired render node.
 >      if (ret < 0)
 >         continue; // Did not match any drivers.
 >      // Matched a driver, but not our filter. Consider as fallback.
 >

With respect to this feedback I've taken a slightly different path and added a 
probe_result enum and cleaned up the goto labels.

 >> +
 >> +next:
 >> +      if (fallback_fd == -1) {
 >> +         fallback_fd = fd;
 >> +         fd = -1;
 >> +      } else {
 >> +         close(fd);
 >> +         fd = -1;
 >> +      }
 >
 > fd = -1; could be just put here, after the if.
 >

Ack.

 >> +      continue;
 >
 > No need for this continue.
 >
 > Best regards,
 > Tomasz
 >


More information about the mesa-dev mailing list