Hi Emil,

On Friday, 3 August 2018 14:44:16 CEST Emil Velikov wrote:
> Hi all,
> 
> This series implements the following extensions:
>  - EGL_EXT_device_base
>  - EGL_MESA_device_software
>  - EGL_EXT_device_drm
>  - EGL_platform_device
> 
> As you know the APIs are used to enumerate, select and use EGLDevices.
> The second extension (proposed by Ajax) defines a 'software' device,
> alongside the existing DRM ones.
> 
> While there are many usecases for this work, my primary interest is
> allowing device selection, wrt testing. To achieve the goal, we would
> need to finalise EGL_EXT_explicit_device (also proposed by Ajax).
> 
> Piglit patches will be sent out shortly.
> 
> Any feedback is greatly appreciated.

>From a higher point of view the approach looks good.

To sum up, you basically associate an _EGLDevice with each _EGLDisplay
where the _EGLDevice only contains the meta information where to
find the device and the _EGLDisplay later contains open file descriptors
to work with ...

Nevertheless, running the tests and proof of concept programs that I used
back in the day brought up some questions and one crash.

At first the Crash: The attached eglcontext-pbuffer.c which goes the pbuffer 
approach
instead of going surfaceless just dumps core in pbuffer creation using
the patch series. I believe that it is legal what the program does, but may
be you want to double check that too.

Then if I use the patch series on an account that has no DISPLAY set and no
'display server' running, eglInitialize fails in device_probe_device due to at 
first
opening the '.../card0' device and bailing out when this does not work.
Means the current patch series goes via opening the primary node which
shall not be accessible by everyone and from that derives the rendernode
device which is finally used for _EGLDisplay initialization.
Can we alternatively go directly to the rendernode in some way?

For patch #7, can you explain why dri already provides the right format?
It's probably correct, but I am missing some bits of that context creation
big picture to give a review.

And finally, in patch #2 you mention that you want to avoid larger patches
and the announced extensions are not yet working as expected.
May be you can announce the extensions in a separate patch that follows
all the implementation patches? That probably helps people that want to
bisect something using piglit.

thanks for approaching this topic!

best
Mathias


> 
> Thanks
> Emil
> 
> Emil Velikov (9):
>   egl: add simple EGL_EXT_device_base implementation
>   egl: add EGL_MESA_device_software support
>   egl: add EGL_EXT_device_drm support
>   meson: egl: group dri2 bits separately from haiku
>   egl/surfaceless: inline surfaceless_alloc_image()
>   egl/surfaceless: honour the format passed to getBuffers
>   egl/surfaceless: remove no longer used dri2_egl_surface::visual
>   egl: add optional plat_opt to _eglFindDisplay()
>   egl: add EGL_platform_device support
> 
> Jonny Lamb (1):
>   egl: add initial boilerplate for EGL_EXT_device_base
> 
>  src/egl/Makefile.am                         |   3 +
>  src/egl/Makefile.sources                    |   2 +
>  src/egl/drivers/dri2/egl_dri2.c             |   3 +
>  src/egl/drivers/dri2/egl_dri2.h             |  13 +-
>  src/egl/drivers/dri2/platform_android.c     |   9 +
>  src/egl/drivers/dri2/platform_device.c      | 380 ++++++++++++++++++++
>  src/egl/drivers/dri2/platform_drm.c         |   9 +
>  src/egl/drivers/dri2/platform_surfaceless.c |  37 +-
>  src/egl/drivers/dri2/platform_wayland.c     |  18 +
>  src/egl/drivers/dri2/platform_x11.c         |  27 ++
>  src/egl/drivers/haiku/egl_haiku.cpp         |   8 +
>  src/egl/main/eglapi.c                       |  79 +++-
>  src/egl/main/egldevice.c                    | 306 ++++++++++++++++
>  src/egl/main/egldevice.h                    |  83 +++++
>  src/egl/main/egldisplay.c                   | 119 +++++-
>  src/egl/main/egldisplay.h                   |  14 +-
>  src/egl/main/eglentrypoint.h                |   4 +
>  src/egl/main/eglglobals.c                   |  10 +-
>  src/egl/main/eglglobals.h                   |   2 +
>  src/egl/main/egltypedefs.h                  |   2 +
>  src/egl/meson.build                         |  68 ++--
>  21 files changed, 1120 insertions(+), 76 deletions(-)
>  create mode 100644 src/egl/drivers/dri2/platform_device.c
>  create mode 100644 src/egl/main/egldevice.c
>  create mode 100644 src/egl/main/egldevice.h
> 
> 

// For RTLD_DEFAULT
#define _GNU_SOURCE

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>

// open/close for gbm
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <gbm.h>

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GL/gl.h>

static int
check_extension(EGLDisplay dpy, const char* name)
{
    const char *extensions = eglQueryString(dpy, EGL_EXTENSIONS);
    // It does not hurt to check this always, but by spec only
    // required if we look for client extensions
    if (/*dpy == EGL_NO_DISPLAY && */ !extensions)
      return 0;
    // Not great as we match substrings in the wrong way, but for a demo.
    return strstr(extensions, name) != NULL;
}


static EGLDisplay
displayViaQueryDevices()
{
  /* Check if we have client extensions */
  if (!check_extension(EGL_NO_DISPLAY, "EGL_EXT_client_extensions")) {
    printf("No EGL_EXT_client_extensions\n");
    return EGL_NO_DISPLAY;
  }
  // For eglQueryDevicesEXT
  if (!check_extension(EGL_NO_DISPLAY, "EGL_EXT_device_enumeration") &&
      !check_extension(EGL_NO_DISPLAY, "EGL_EXT_device_base")) {// includes the former
    printf("No EGL_EXT_device_enumeration or EGL_EXT_device_base\n");
    return EGL_NO_DISPLAY;
  }
  // For eglGetPlatformDisplayEXT
  if (!check_extension(EGL_NO_DISPLAY, "EGL_EXT_platform_base")) {
    printf("No EGL_EXT_platform_base\n");
    return EGL_NO_DISPLAY;
  }
  // For EGL_PLATFORM_DEVICE_EXT platform
  if (!check_extension(EGL_NO_DISPLAY, "EGL_EXT_platform_device")) {
    printf("No EGL_EXT_platform_device\n");
    return EGL_NO_DISPLAY;
  }

  PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
  eglQueryDevicesEXT = (void*)eglGetProcAddress("eglQueryDevicesEXT");
  if (!eglQueryDevicesEXT) {
    printf("eglQueryDevicesEXT\n");
    return EGL_NO_DISPLAY;
  }

  /* Ask how many devices */
  EGLint numDevices;
  if (!eglQueryDevicesEXT(0, NULL, &numDevices)) {
    printf("eglQueryDevicesEXT()\n");
    return EGL_NO_DISPLAY;
  }

  /* Get the devices */
  EGLDeviceEXT* devices = calloc(numDevices, sizeof(EGLDeviceEXT));
  if (!eglQueryDevicesEXT(numDevices, devices, &numDevices)) {
    printf("eglQueryDevicesEXT()\n");
    return EGL_NO_DISPLAY;
  }
  printf("Found %d devices\n", numDevices);

  /* We pick just the first, but may be iterate all, try to build
   * up everything down to the context take the first that
   * fits all our needs
   */
  EGLDeviceEXT device = devices[0];
  free(devices);

  PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
  eglGetPlatformDisplayEXT = (void*)eglGetProcAddress("eglGetPlatformDisplayEXT");
  if (!eglGetPlatformDisplayEXT) {
    printf("eglGetPlatformDisplayEXT\n");
    return EGL_NO_DISPLAY;
  }

  return eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, device, NULL);
}


static EGLDisplay
displayViaRenderNodeGBM(void)
{
  if (!check_extension(EGL_NO_DISPLAY, "EGL_EXT_client_extensions")) {
    printf("No EGL_EXT_client_extensions\n");
    return EGL_NO_DISPLAY;
  }
  /* Work with gbm */
  if (!check_extension(EGL_NO_DISPLAY, "EGL_MESA_platform_gbm")) {
    printf("No EGL_MESA_platform_gbm\n");
    return EGL_NO_DISPLAY;
  }
  // For eglGetPlatformDisplayEXT
  if (!check_extension(EGL_NO_DISPLAY, "EGL_EXT_platform_base")) {
    printf("No EGL_EXT_platform_base\n");
    return EGL_NO_DISPLAY;
  }

  // Check if anybody already pulls gbm, and take this one without hard linking against
  typedef struct gbm_device * (*GBMCREATEDEVICEPROC)(int fd);
  GBMCREATEDEVICEPROC gbm_create_device = dlsym(RTLD_DEFAULT, "gbm_create_device");
  if (!gbm_create_device) {
    printf("No gbm library available for symbol lookup!\n");
    return EGL_NO_DISPLAY;
  }

  struct gbm_device *gbm = NULL;
  int i;
  for (i = 128; i < 256; ++i) {
    char dev[256]; // 256 is long enough in this case - better implementation in production
    sprintf(dev, "/dev/dri/renderD%d", i);
    int fd = open(dev, O_RDWR | FD_CLOEXEC);
    if (fd < 0)
      continue;

    gbm = gbm_create_device(fd);
    if (gbm)
      break;

    close(fd);
  }
  if (!gbm) {
    printf("No gbm device\n");
    return EGL_NO_DISPLAY;
  }

  /* FIXME Release gbm resources on error paths */

  PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
  eglGetPlatformDisplayEXT = (void*)eglGetProcAddress("eglGetPlatformDisplayEXT");
  if (!eglGetPlatformDisplayEXT) {
    printf("eglGetPlatformDisplayEXT\n");
    return EGL_NO_DISPLAY;
  }

  return eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, gbm, NULL);
}


int main(int argc, char *argv[])
{
  // Before the first egl call - only needed if the MESA
  // hardwre surfaceless platform via
  // eglGetDisplay(EGL_DEFAULT_DISPLAY) is interresting
  //  setenv("EGL_PLATFORM", "surfaceless", 0);

  printf("EGL Client Extensions:\n");
  if (eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
    printf("%s\n", eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS));

  EGLDisplay dpy = EGL_NO_DISPLAY;
  /* Try current NVidias way to even choose a display */
  if (dpy == EGL_NO_DISPLAY) {
    dpy = displayViaQueryDevices();
  }

  /* Try OSS drivre stack way to even choose a display */
  /* if (dpy == EGL_NO_DISPLAY) { */
  /*   dpy = displayViaRenderNodeGBM(); */
  /* } */

  /* Either grab a surfaceless platform MESA Hardware context
     or a next best nvidia hardware context */
  if (EGL_NO_DISPLAY == dpy) {
    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  }

  /* Bail out if there is nothing */
  if (EGL_NO_DISPLAY == dpy) {
    printf("eglGetDisplay()\n");
    return EXIT_FAILURE;
  }

  // Initialize the display
  EGLint major, minor;
  if (!eglInitialize(dpy, &major, &minor)) {
    printf("eglInitialize()\n");
    return EXIT_FAILURE;
  }
  // Check the required EGL version
  if (major < 1 || (major == 1 && minor < 4)) {
    printf("egl version %d, %d\n", major, minor);
    return EXIT_FAILURE;
  }

  printf("Client APIS:\n%s\n", eglQueryString(dpy, EGL_CLIENT_APIS));
  printf("EGL Extensions:\n%s\n", eglQueryString(dpy, EGL_EXTENSIONS));

  // Select an appropriate configuration
  const EGLint configAttribs[] = {
    EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
    EGL_BLUE_SIZE, 8,
    EGL_GREEN_SIZE, 8,
    EGL_RED_SIZE, 8,
    EGL_DEPTH_SIZE, 8,
    EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
    EGL_NONE
  };
  EGLint numConfigs;
  EGLConfig config;
  if (!eglChooseConfig(dpy, configAttribs, &config, 1, &numConfigs)) {
    printf("eglChooseConfig()\n");
    return EXIT_FAILURE;
  }
  if (numConfigs <= 0){
    printf("eglChooseConfig: no configs\n");
    return EXIT_FAILURE;
  }

  // Create a PBuffer
  const EGLint pbufferAttribs[] = {
    EGL_WIDTH, 128,
    EGL_HEIGHT, 128,
    EGL_NONE
  };
  EGLSurface surface = eglCreatePbufferSurface(dpy, config, pbufferAttribs);
  if (EGL_NO_SURFACE == surface) {
    printf("eglCreatePbufferSurface()\n");
    return EXIT_FAILURE;
  }

  // We are after desktop OpenGL - like requested in the config
  if (!eglBindAPI(EGL_OPENGL_API)) {
    printf("eglBindAPI()\n");
    return EXIT_FAILURE;
  }

  // Create a context
  EGLContext ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL);
  if (EGL_NO_CONTEXT == ctx) {
    printf("eglCreateContext()\n");
    return EXIT_FAILURE;
  }

  // Make the cntext current
  if (!eglMakeCurrent(dpy, surface, surface, ctx)) {
    printf("eglMakeCurrent()\n");
    return EXIT_FAILURE;
  }

  // All worked well - rendering!!!
  printf("\nGL Vendor:\n%s\n", glGetString(GL_VENDOR));
  printf("\nGL Renderer:\n%s\n", glGetString(GL_RENDERER));
  printf("\nGL Version:\n%s\n", glGetString(GL_VERSION));
  printf("\nGL GLSL Version:\n%s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
  printf("\nGL Extensions:\n%s\n", glGetString(GL_EXTENSIONS));

  // Teardown
  if (!eglTerminate(dpy)) {
    printf("eglTerminate()\n");
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}
_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to