VTK using on wayland

Hi @CHENG-HSUAN

While I understand your request and concerns, a partial implementation is not the correct approach because there are many moving parts here. As you have found out with your patch, the current vtkEGLRenderWindow won’t work with wayland since it does not have mechanism to use a wayland surface object which is required to correctly invoke eglCreateWindowSurface. In principle, this could be an X display/Wayland surface/Win32 HDC. The main area that needs work is to adapt vtkEGLRenderWindow to initialize from native window handles.

From my understanding, it looks like your broader objective is to get VTK applications to use native wayland (not xwayland/X). In this case, I propose extending the vtkEGLRenderWindow for onscreen rendering. There are two items that need worked on:

  1. Adapt the vtkEGLRenderWindow to initialize EGL context using a wayland surface. Basic samples here - EGL with Wayland give an idea of the API this class will use.
  2. Create a new vtkWaylandRenderWindowInteractor for user interaction on wayland. There is no VTK interactor for wayland. The Cylinder example program exited immediately because the default interactor was in use whose Start() method doesn’t do anything.

In case you want to play with something and get it to render onscreen for wayland without interaction, add these lines before you call eglCreateWindowSurface. This code is not tested and you will need to do some refactoring, like move the handlers in an internals class and declare the new member variables in the vtkInternals class. I mostly cribbed the code from other wayland-egl samples. Think of it as a teaser on the necessary plumbing.

  // Define static handler functions in global namespace and remove static.
  static void global_registry_handler(
    void* data, struct wl_registry* registry, uint32_t id, const char* interface, uint32_t version)
  {
    printf("Got a registry event for %s id %d\n", interface, id);
    if (strcmp(interface, "wl_compositor") == 0)
    {
      compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1);
    }
    else if (strcmp(interface, "wl_shell") == 0)
    {
      shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
    }
  }

  static void global_registry_remover(void* data, struct wl_registry* registry, uint32_t id)
  {
    printf("Got a registry losing event for %d\n", id);
  }

  static const struct wl_registry_listener registry_listener = { global_registry_handler,
    global_registry_remover };
  // Init the NativeDisplay and Display before eglInitialize.
  impl->NativeWaylandDisplay = wl_display_connect(NULL);
  if (impl->NativeWaylandDisplay == NULL)
  {
    fprintf(stderr, "Can't connect to display\n");
    exit(1);
  }
  impl->Display = eglGetDisplay((EGLNativeDisplayType)impl->NativeWaylandDisplay);

  struct wl_registry* registry = wl_display_get_registry(impl->NativeWaylandDisplay);
  wl_registry_add_listener(registry, &registry_listener, NULL);

  wl_display_dispatch(impl->NativeWaylandDisplay);
  wl_display_roundtrip(impl->NativeWaylandDisplay);

  if (impl->WaylandCompositor == NULL || impl->WaylandShell == NULL)
  {
    fprintf(stderr, "Can't find compositor or shell\n");
    exit(1);
  }
  else
  {
    fprintf(stderr, "Found compositor and shell\n");
  }
  impl->WaylandSurface = wl_compositor_create_surface(impl->WaylandCompositor);
  if (impl->WaylandSurface == NULL)
  {
    fprintf(stderr, "Can't create surface\n");
    exit(1);
  }
  else
  {
    fprintf(stderr, "Created surface\n");
  }

  impl->WaylandShellSurface = wl_shell_get_shell_surface(impl->WaylandShell, surface);
  wl_shell_surface_set_toplevel(impl->WaylandShellSurface);
  impl->Window = wl_egl_window_create(impl->Surface, this->Size[0], this->Size[1]);

  if (impl->Window == EGL_NO_SURFACE)
  {
    fprintf(stderr, "Can't create egl window\n");
    exit(1);
  }
  else
  {
    fprintf(stderr, "Created egl window\n");
  }