[Bf-blender-cvs] [3195a381200] master: Introduce headless OpenGL rendering on Linux

Sebastian Parborg noreply at git.blender.org
Mon Aug 15 16:58:58 CEST 2022


Commit: 3195a381200eb98e6add8b0504f701318186946d
Author: Sebastian Parborg
Date:   Mon Aug 15 16:54:29 2022 +0200
Branches: master
https://developer.blender.org/rB3195a381200eb98e6add8b0504f701318186946d

Introduce headless OpenGL rendering on Linux

With this patch true headless OpenGL rendering is now possible on Linux.
It changes the logic of the WITH_HEADLESS build flag.

The headless backend is now always available with regular builds and
Blender will try to fall back to it if it fails to initialize other
backends while in background mode.

The headless backend only works on Linux as EGL is not used on Mac or Windows.
libepoxy does support windows and mac, so this can perhaps be remedied in the future.

Reviewed By: Brecht, Jeroen, Campbell

Differential Revision: http://developer.blender.org/D15555

===================================================================

M	CMakeLists.txt
M	intern/ghost/CMakeLists.txt
M	intern/ghost/GHOST_C-api.h
M	intern/ghost/GHOST_ISystem.h
M	intern/ghost/intern/GHOST_C-api.cpp
M	intern/ghost/intern/GHOST_ContextEGL.cpp
M	intern/ghost/intern/GHOST_DisplayManagerNULL.h
M	intern/ghost/intern/GHOST_ISystem.cpp
A	intern/ghost/intern/GHOST_SystemHeadless.h
D	intern/ghost/intern/GHOST_SystemNULL.h
M	intern/ghost/intern/GHOST_SystemSDL.cpp
M	intern/ghost/intern/GHOST_SystemX11.cpp
M	intern/ghost/intern/GHOST_WindowNULL.h
M	source/blender/windowmanager/intern/wm_init_exit.c
M	source/blender/windowmanager/intern/wm_window.c
M	source/blender/windowmanager/wm_window.h

===================================================================

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f72521266aa..f59a849cbf8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -536,10 +536,6 @@ mark_as_advanced(
   WITH_GPU_BUILDTIME_SHADER_BUILDER
 )
 
-if(WITH_HEADLESS)
-  set(WITH_OPENGL OFF)
-endif()
-
 # Metal
 
 if(APPLE)
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 84b68014e91..099785bafa8 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -103,42 +103,39 @@ if(WITH_INPUT_NDOF)
   )
 endif()
 
-if(WITH_HEADLESS OR WITH_GHOST_SDL)
-  if(WITH_HEADLESS)
-    list(APPEND SRC
-      intern/GHOST_DisplayManagerNULL.h
-      intern/GHOST_SystemNULL.h
-      intern/GHOST_WindowNULL.h
+list(APPEND SRC
+  intern/GHOST_DisplayManagerNULL.h
+  intern/GHOST_SystemHeadless.h
+  intern/GHOST_WindowNULL.h
+)
+
+if(WITH_HEADLESS)
+  add_definitions(-DWITH_HEADLESS)
+elseif (WITH_GHOST_SDL)
+  list(APPEND SRC
+    intern/GHOST_ContextSDL.cpp
+    intern/GHOST_DisplayManagerSDL.cpp
+    intern/GHOST_SystemSDL.cpp
+    intern/GHOST_WindowSDL.cpp
+
+    intern/GHOST_ContextSDL.h
+    intern/GHOST_DisplayManagerSDL.h
+    intern/GHOST_SystemSDL.h
+    intern/GHOST_WindowSDL.h
+  )
+  add_definitions(-DWITH_GHOST_SDL)
+
+  list(APPEND INC_SYS
+    ${SDL_INCLUDE_DIR}
+  )
+  if(WITH_SDL_DYNLOAD)
+    list(APPEND LIB
+      extern_sdlew
     )
-    add_definitions(-DWITH_HEADLESS)
   else()
-    list(APPEND SRC
-      intern/GHOST_ContextSDL.cpp
-      intern/GHOST_DisplayManagerSDL.cpp
-      intern/GHOST_SystemSDL.cpp
-      intern/GHOST_WindowSDL.cpp
-
-      intern/GHOST_ContextSDL.h
-      intern/GHOST_DisplayManagerSDL.h
-      intern/GHOST_SystemSDL.h
-      intern/GHOST_WindowSDL.h
-    )
-    add_definitions(-DWITH_GHOST_SDL)
-  endif()
-
-  if(NOT WITH_HEADLESS)
-    list(APPEND INC_SYS
-      ${SDL_INCLUDE_DIR}
+    list(APPEND LIB
+      ${SDL_LIBRARY}
     )
-    if(WITH_SDL_DYNLOAD)
-      list(APPEND LIB
-        extern_sdlew
-      )
-    else()
-      list(APPEND LIB
-        ${SDL_LIBRARY}
-      )
-    endif()
   endif()
 
 elseif(APPLE AND NOT WITH_GHOST_X11)
@@ -449,7 +446,7 @@ elseif(WIN32)
   endif()
 endif()
 
-if(NOT (WITH_HEADLESS OR WITH_GHOST_SDL))
+if(UNIX AND NOT APPLE)
   list(APPEND SRC
     intern/GHOST_ContextEGL.cpp
 
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 4cbc0d65b11..f01f439718f 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -27,6 +27,7 @@ typedef bool (*GHOST_EventCallbackProcPtr)(GHOST_EventHandle event, GHOST_TUserD
  * \return a handle to the system.
  */
 extern GHOST_SystemHandle GHOST_CreateSystem(void);
+extern GHOST_SystemHandle GHOST_CreateSystemBackground(void);
 
 /**
  * Specifies whether debug messages are to be enabled for the specific system handle.
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 89878a6d6a1..0dd855bb513 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -120,6 +120,7 @@ class GHOST_ISystem {
    * \return An indication of success.
    */
   static GHOST_TSuccess createSystem();
+  static GHOST_TSuccess createSystemBackground();
 
   /**
    * Disposes the one and only system.
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 65e7de707ec..62e1e470010 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -30,6 +30,14 @@ GHOST_SystemHandle GHOST_CreateSystem(void)
   return (GHOST_SystemHandle)system;
 }
 
+GHOST_SystemHandle GHOST_CreateSystemBackground(void)
+{
+  GHOST_ISystem::createSystemBackground();
+  GHOST_ISystem *system = GHOST_ISystem::getSystem();
+
+  return (GHOST_SystemHandle)system;
+}
+
 void GHOST_SystemInitDebug(GHOST_SystemHandle systemhandle, GHOST_Debug debug)
 {
   GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp
index 75c2655531f..6de161fda2a 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextEGL.cpp
@@ -334,14 +334,35 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
   EGLSurface prev_read = eglGetCurrentSurface(EGL_READ);
   EGLContext prev_context = eglGetCurrentContext();
 
-  EGLint egl_major, egl_minor;
+  EGLint egl_major = 0, egl_minor = 0;
 
   if (!EGL_CHK((m_display = ::eglGetDisplay(m_nativeDisplay)) != EGL_NO_DISPLAY)) {
     goto error;
   }
 
-  if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) {
-    goto error;
+  if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor)) ||
+      (egl_major == 0 && egl_minor == 0)) {
+    /* We failed to create a regular render window, retry and see if we can create a headless
+     * render context. */
+    ::eglTerminate(m_display);
+
+    const char *egl_extension_st = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+    assert(egl_extension_st != nullptr);
+    assert(strstr(egl_extension_st, "EGL_MESA_platform_surfaceless") != nullptr);
+    if (egl_extension_st == nullptr ||
+        strstr(egl_extension_st, "EGL_MESA_platform_surfaceless") == nullptr) {
+      goto error;
+    }
+
+    m_display = eglGetPlatformDisplayEXT(
+        EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, nullptr);
+
+    if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) {
+      goto error;
+    }
+    /* Because the first eglInitialize will print an error to the terminal, print a "success"
+     * message here to let the user know that we successfully recovered from the error. */
+    fprintf(stderr, "\nManaged to successfully fallback to surfaceless EGL rendering!\n\n");
   }
 #ifdef WITH_GHOST_DEBUG
   fprintf(stderr, "EGL Version %d.%d\n", egl_major, egl_minor);
diff --git a/intern/ghost/intern/GHOST_DisplayManagerNULL.h b/intern/ghost/intern/GHOST_DisplayManagerNULL.h
index ba72dcbe8dd..9adbe17c532 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerNULL.h
+++ b/intern/ghost/intern/GHOST_DisplayManagerNULL.h
@@ -8,38 +8,41 @@
 #pragma once
 
 #include "GHOST_DisplayManager.h"
-#include "GHOST_SystemNULL.h"
+#include "GHOST_SystemHeadless.h"
 
-class GHOST_SystemNULL;
+class GHOST_SystemHeadless;
 
 class GHOST_DisplayManagerNULL : public GHOST_DisplayManager {
  public:
-  GHOST_DisplayManagerNULL(GHOST_SystemNULL *system) : GHOST_DisplayManager(), m_system(system)
+  GHOST_DisplayManagerNULL(GHOST_SystemHeadless *system) : GHOST_DisplayManager(), m_system(system)
   { /* nop */
   }
-  GHOST_TSuccess getNumDisplays(uint8_t &numDisplays) const
+  GHOST_TSuccess getNumDisplays(uint8_t & /*numDisplays*/) const override
   {
     return GHOST_kFailure;
   }
-  GHOST_TSuccess getNumDisplaySettings(uint8_t display, int32_t &numSettings) const
+  GHOST_TSuccess getNumDisplaySettings(uint8_t /*display*/,
+                                       int32_t & /*numSettings*/) const override
   {
     return GHOST_kFailure;
   }
-  GHOST_TSuccess getDisplaySetting(uint8_t display,
-                                   int32_t index,
-                                   GHOST_DisplaySetting &setting) const
+  GHOST_TSuccess getDisplaySetting(uint8_t /*display*/,
+                                   int32_t /*index*/,
+                                   GHOST_DisplaySetting & /*setting*/) const override
   {
     return GHOST_kFailure;
   }
-  GHOST_TSuccess getCurrentDisplaySetting(uint8_t display, GHOST_DisplaySetting &setting) const
+  GHOST_TSuccess getCurrentDisplaySetting(uint8_t display,
+                                          GHOST_DisplaySetting &setting) const override
   {
     return getDisplaySetting(display, int32_t(0), setting);
   }
-  GHOST_TSuccess setCurrentDisplaySetting(uint8_t display, const GHOST_DisplaySetting &setting)
+  GHOST_TSuccess setCurrentDisplaySetting(uint8_t /*display*/,
+                                          const GHOST_DisplaySetting & /*setting*/) override
   {
     return GHOST_kSuccess;
   }
 
  private:
-  GHOST_SystemNULL *m_system;
+  GHOST_SystemHeadless *m_system;
 };
diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp
index 4f6a9531077..03bdcd2fc82 100644
--- a/intern/ghost/intern/GHOST_ISystem.cpp
+++ b/intern/ghost/intern/GHOST_ISystem.cpp
@@ -9,14 +9,14 @@
  * Copyright (C) 2001 NaN Technologies B.V.
  */
 
+#include <stdexcept>
+
 #include "GHOST_ISystem.h"
+#include "GHOST_SystemHeadless.h"
 
-#if defined(WITH_HEADLESS)
-#  include "GHOST_SystemNULL.h"
-#elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND)
+#if defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND)
 #  include "GHOST_SystemWayland.h"
 #  include "GHOST_SystemX11.h"
-#  include <stdexcept>
 #elif defined(WITH_GHOST_X11)
 #  include "GHOST_SystemX11.h"
 #elif defined(WITH_GHOST_WAYLAND)
@@ -49,26 +49,50 @@ GHOST_TSuccess GHOST_ISystem::createSystem()
 #endif
 
 #if defined(WITH_HEADLESS)
-    m_system = new GHOST_SystemNULL();
+    /* Pass. */
 #elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND)
     /* Special case, try Wayland, fall back to X11. */
     try {
       m_system = has_wayland_libraries ? new GHOST_SystemWayland() : nullptr;
     }
     catch (const std::runtime_error &) {
-      /* fallback to X11. */
       delete m_system;
       m_system = nullptr;
     }
     if (!m_system) {
-      m_system = new GHOST_SystemX11();
+      /* Try to fallback to X11. */
+      try {
+        m_system = new GHOST_SystemX11();
+      }
+      catch (const std::runtime_error &) {
+        delete m_system;
+        m_system = nullptr;
+      }
     }
 #elif defined(WITH_GHOST_X11)
-    m_system = new GHOST_SystemX11();
+    try {
+      m_system = new GHOST_SystemX11();
+    }
+    catch (const std::runtime_error &) {
+      delete m_system;
+      m_system = nullptr;
+    }
 #elif defined(WITH_GHOST_WAYLAND)
-    m_system = has_wayland_libraries ? new GHOST_SystemWayland() : nullptr;
+    try {
+      m_system = has_wayland_libraries ? new GHOST_SystemWayland() : nullptr;
+    }
+    catch (const std::runtime_error &) {
+      delete m_system;
+      m_system = nullptr;
+    }
 #elif defined(WITH_GHOST_SDL)
-    m_system = new GHOST_SystemSDL();
+    try {
+      m

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list