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
This commit is contained in:
Sebastian Parborg 2022-08-15 16:54:29 +02:00
parent 8ffc11dbcb
commit 3195a38120
Notes: blender-bot 2024-01-15 03:40:10 +01:00
Referenced by issue #100913, Improve support for building Blender as a Python Module (WITH_PYTHON_MODULE)
16 changed files with 398 additions and 259 deletions

View File

@ -536,10 +536,6 @@ mark_as_advanced(
WITH_GPU_BUILDTIME_SHADER_BUILDER
)
if(WITH_HEADLESS)
set(WITH_OPENGL OFF)
endif()
# Metal
if(APPLE)

View File

@ -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
list(APPEND LIB
${SDL_LIBRARY}
)
add_definitions(-DWITH_GHOST_SDL)
endif()
if(NOT WITH_HEADLESS)
list(APPEND INC_SYS
${SDL_INCLUDE_DIR}
)
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

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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);

View File

@ -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;
};

View File

@ -9,14 +9,14 @@
* Copyright (C) 2001 NaN Technologies B.V.
*/
#include "GHOST_ISystem.h"
#include <stdexcept>
#if defined(WITH_HEADLESS)
# include "GHOST_SystemNULL.h"
#elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND)
#include "GHOST_ISystem.h"
#include "GHOST_SystemHeadless.h"
#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_system = new GHOST_SystemSDL();
}
catch (const std::runtime_error &) {
delete m_system;
m_system = nullptr;
}
#elif defined(WIN32)
m_system = new GHOST_SystemWin32();
#elif defined(__APPLE__)
@ -85,6 +109,30 @@ GHOST_TSuccess GHOST_ISystem::createSystem()
return success;
}
GHOST_TSuccess GHOST_ISystem::createSystemBackground()
{
GHOST_TSuccess success;
if (!m_system) {
#if !defined(WITH_HEADLESS)
/* Try to create a offscreen render surface with the graphical systems. */
success = createSystem();
if (success) {
return success;
}
/* Try to fallback to headless mode if all else fails. */
#endif
m_system = new GHOST_SystemHeadless();
success = m_system != nullptr ? GHOST_kSuccess : GHOST_kFailure;
}
else {
success = GHOST_kFailure;
}
if (success) {
success = m_system->init();
}
return success;
}
GHOST_TSuccess GHOST_ISystem::disposeSystem()
{
GHOST_TSuccess success = GHOST_kSuccess;

View File

@ -0,0 +1,167 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup GHOST
* Declaration of GHOST_SystemHeadless class.
*/
#pragma once
#include "../GHOST_Types.h"
#include "GHOST_DisplayManagerNULL.h"
#include "GHOST_System.h"
#include "GHOST_WindowNULL.h"
#ifdef __linux__
# include "GHOST_ContextEGL.h"
#endif
#include "GHOST_ContextNone.h"
class GHOST_WindowNULL;
class GHOST_SystemHeadless : public GHOST_System {
public:
GHOST_SystemHeadless() : GHOST_System()
{ /* nop */
}
~GHOST_SystemHeadless() override = default;
bool processEvents(bool /*waitForEvent*/) override
{
return false;
}
int setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) override
{
return 0;
}
GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys & /*keys*/) const override
{
return GHOST_kSuccess;
}
GHOST_TSuccess getButtons(GHOST_Buttons & /*buttons*/) const override
{
return GHOST_kSuccess;
}
char *getClipboard(bool /*selection*/) const override
{
return nullptr;
}
void putClipboard(const char * /*buffer*/, bool /*selection*/) const override
{ /* nop */
}
uint64_t getMilliSeconds() const override
{
return 0;
}
uint8_t getNumDisplays() const override
{
return uint8_t(1);
}
GHOST_TSuccess getCursorPosition(int32_t & /*x*/, int32_t & /*y*/) const override
{
return GHOST_kFailure;
}
GHOST_TSuccess setCursorPosition(int32_t /*x*/, int32_t /*y*/) override
{
return GHOST_kFailure;
}
void getMainDisplayDimensions(uint32_t & /*width*/, uint32_t & /*height*/) const override
{ /* nop */
}
void getAllDisplayDimensions(uint32_t & /*width*/, uint32_t & /*height*/) const override
{ /* nop */
}
GHOST_IContext *createOffscreenContext(GHOST_GLSettings /*glSettings*/) override
{
#ifdef __linux__
GHOST_Context *context;
for (int minor = 6; minor >= 0; --minor) {
context = new GHOST_ContextEGL((GHOST_System *)this,
false,
EGLNativeWindowType(0),
EGLNativeDisplayType(EGL_DEFAULT_DISPLAY),
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
4,
minor,
GHOST_OPENGL_EGL_CONTEXT_FLAGS,
GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
EGL_OPENGL_API);
if (context->initializeDrawingContext()) {
return context;
}
delete context;
context = nullptr;
}
context = new GHOST_ContextEGL((GHOST_System *)this,
false,
EGLNativeWindowType(0),
EGLNativeDisplayType(EGL_DEFAULT_DISPLAY),
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
3,
3,
GHOST_OPENGL_EGL_CONTEXT_FLAGS,
GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
EGL_OPENGL_API);
if (context->initializeDrawingContext() != GHOST_kSuccess) {
delete context;
context = nullptr;
}
return context;
#else
return nullptr;
#endif
}
GHOST_TSuccess disposeContext(GHOST_IContext *context) override
{
delete context;
return GHOST_kSuccess;
}
GHOST_TSuccess init() override
{
GHOST_TSuccess success = GHOST_System::init();
if (success) {
m_displayManager = new GHOST_DisplayManagerNULL(this);
if (m_displayManager) {
return GHOST_kSuccess;
}
}
return GHOST_kFailure;
}
GHOST_IWindow *createWindow(const char *title,
int32_t left,
int32_t top,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool /*exclusive*/,
const bool /*is_dialog*/,
const GHOST_IWindow *parentWindow) override
{
return new GHOST_WindowNULL(this,
title,
left,
top,
width,
height,
state,
parentWindow,
type,
((glSettings.flags & GHOST_glStereoVisual) != 0));
}
GHOST_IWindow *getWindowUnderCursor(int32_t /*x*/, int32_t /*y*/) override
{
return nullptr;
}
};

View File

@ -1,122 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup GHOST
* Declaration of GHOST_SystemNULL class.
*/
#pragma once
#include "../GHOST_Types.h"
#include "GHOST_DisplayManagerNULL.h"
#include "GHOST_System.h"
#include "GHOST_WindowNULL.h"
class GHOST_WindowNULL;
class GHOST_SystemNULL : public GHOST_System {
public:
GHOST_SystemNULL() : GHOST_System()
{ /* nop */
}
~GHOST_SystemNULL()
{ /* nop */
}
bool processEvents(bool waitForEvent)
{
return false;
}
int setConsoleWindowState(GHOST_TConsoleWindowState action)
{
return 0;
}
GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const
{
return GHOST_kSuccess;
}
GHOST_TSuccess getButtons(GHOST_Buttons &buttons) const
{
return GHOST_kSuccess;
}
char *getClipboard(bool selection) const
{
return nullptr;
}
void putClipboard(const char *buffer, bool selection) const
{ /* nop */
}
uint64_t getMilliSeconds() const
{
return 0;
}
uint8_t getNumDisplays() const
{
return uint8_t(1);
}
GHOST_TSuccess getCursorPosition(int32_t &x, int32_t &y) const
{
return GHOST_kFailure;
}
GHOST_TSuccess setCursorPosition(int32_t x, int32_t y)
{
return GHOST_kFailure;
}
void getMainDisplayDimensions(uint32_t &width, uint32_t &height) const
{ /* nop */
}
void getAllDisplayDimensions(uint32_t &width, uint32_t &height) const
{ /* nop */
}
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings)
{
return nullptr;
}
GHOST_TSuccess disposeContext(GHOST_IContext *context)
{
return GHOST_kFailure;
}
GHOST_TSuccess init()
{
GHOST_TSuccess success = GHOST_System::init();
if (success) {
m_displayManager = new GHOST_DisplayManagerNULL(this);
if (m_displayManager) {
return GHOST_kSuccess;
}
}
return GHOST_kFailure;
}
GHOST_IWindow *createWindow(const char *title,
int32_t left,
int32_t top,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,
const GHOST_IWindow *parentWindow)
{
return new GHOST_WindowNULL(this,
title,
left,
top,
width,
height,
state,
parentWindow,
type,
((glSettings.flags & GHOST_glStereoVisual) != 0));
}
GHOST_IWindow *getWindowUnderCursor(int32_t x, int32_t y)
{
return nullptr;
}
};

View File

@ -5,6 +5,7 @@
*/
#include <cassert>
#include <stdexcept>
#include "GHOST_ContextSDL.h"
#include "GHOST_SystemSDL.h"
@ -20,7 +21,7 @@
GHOST_SystemSDL::GHOST_SystemSDL() : GHOST_System()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
printf("Error initializing SDL: %s\n", SDL_GetError());
throw std::runtime_error("Error initializing SDL: " + std::string(SDL_GetError()));
}
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

View File

@ -101,8 +101,7 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(nullptr), m_sta
m_display = XOpenDisplay(nullptr);
if (!m_display) {
std::cerr << "Unable to open a display" << std::endl;
abort(); /* was return before, but this would just mean it will crash later */
throw std::runtime_error("X11: Unable to open a display");
}
#ifdef USE_X11_ERROR_HANDLERS

View File

@ -11,24 +11,24 @@
#include <map>
class GHOST_SystemNULL;
class GHOST_SystemHeadless;
class GHOST_WindowNULL : public GHOST_Window {
public:
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor)
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor /*cursorShape*/) override
{
return GHOST_kSuccess;
}
GHOST_WindowNULL(GHOST_SystemNULL *system,
GHOST_WindowNULL(GHOST_SystemHeadless *system,
const char *title,
int32_t left,
int32_t top,
int32_t /*left*/,
int32_t /*top*/,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
const GHOST_IWindow *parentWindow,
GHOST_TDrawingContextType type,
const GHOST_IWindow * /*parentWindow*/,
GHOST_TDrawingContextType /*type*/,
const bool stereoVisual)
: GHOST_Window(width, height, state, stereoVisual, false), m_system(system)
{
@ -36,7 +36,7 @@ class GHOST_WindowNULL : public GHOST_Window {
}
protected:
GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type)
GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType /*type*/)
{
return GHOST_kSuccess;
}
@ -44,114 +44,113 @@ class GHOST_WindowNULL : public GHOST_Window {
{
return GHOST_kSuccess;
}
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode)
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode /*mode*/) override
{
return GHOST_kSuccess;
}
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape)
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor /*shape*/) override
{
return GHOST_kSuccess;
}
GHOST_TSuccess setWindowCustomCursorShape(uint8_t *bitmap,
uint8_t *mask,
int sizex,
int sizey,
int hotX,
int hotY,
bool canInvertColor)
GHOST_TSuccess setWindowCustomCursorShape(uint8_t * /*bitmap*/,
uint8_t * /*mask*/,
int /*sizex*/,
int /*sizey*/,
int /*hotX*/,
int /*hotY*/,
bool /*canInvertColor*/) override
{
return GHOST_kSuccess;
}
bool getValid() const
bool getValid() const override
{
return true;
}
void setTitle(const char *title)
void setTitle(const char * /*title*/) override
{ /* nothing */
}
std::string getTitle() const
std::string getTitle() const override
{
return "untitled";
}
void getWindowBounds(GHOST_Rect &bounds) const
void getWindowBounds(GHOST_Rect &bounds) const override
{
getClientBounds(bounds);
}
void getClientBounds(GHOST_Rect &bounds) const
void getClientBounds(GHOST_Rect & /*bounds*/) const override
{ /* nothing */
}
GHOST_TSuccess setClientWidth(uint32_t width)
GHOST_TSuccess setClientWidth(uint32_t /*width*/) override
{
return GHOST_kFailure;
}
GHOST_TSuccess setClientHeight(uint32_t height)
GHOST_TSuccess setClientHeight(uint32_t /*height*/) override
{
return GHOST_kFailure;
}
GHOST_TSuccess setClientSize(uint32_t width, uint32_t height)
GHOST_TSuccess setClientSize(uint32_t /*width*/, uint32_t /*height*/) override
{
return GHOST_kFailure;
}
void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const
void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override
{
outX = inX;
outY = inY;
}
void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const
void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override
{
outX = inX;
outY = inY;
}
GHOST_TSuccess swapBuffers()
GHOST_TSuccess swapBuffers() override
{
return GHOST_kFailure;
}
GHOST_TSuccess activateDrawingContext()
GHOST_TSuccess activateDrawingContext() override
{
return GHOST_kFailure;
}
~GHOST_WindowNULL()
{ /* nothing */
}
GHOST_TSuccess setWindowCursorVisibility(bool visible)
~GHOST_WindowNULL() override = default;
GHOST_TSuccess setWindowCursorVisibility(bool /*visible*/) override
{
return GHOST_kSuccess;
}
GHOST_TSuccess setState(GHOST_TWindowState state)
GHOST_TSuccess setState(GHOST_TWindowState /*state*/) override
{
return GHOST_kSuccess;
}
GHOST_TWindowState getState() const
GHOST_TWindowState getState() const override
{
return GHOST_kWindowStateNormal;
}
GHOST_TSuccess invalidate()
GHOST_TSuccess invalidate() override
{
return GHOST_kSuccess;
}
GHOST_TSuccess setOrder(GHOST_TWindowOrder order)
GHOST_TSuccess setOrder(GHOST_TWindowOrder /*order*/) override
{
return GHOST_kSuccess;
}
GHOST_TSuccess beginFullScreen() const
GHOST_TSuccess beginFullScreen() const override
{
return GHOST_kSuccess;
}
GHOST_TSuccess endFullScreen() const
GHOST_TSuccess endFullScreen() const override
{
return GHOST_kSuccess;
}
private:
GHOST_SystemNULL *m_system;
GHOST_SystemHeadless *m_system;
/**
* \param type: The type of rendering context create.
* \return Indication of success.
*/
GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type)
GHOST_Context *newDrawingContext(GHOST_TDrawingContextType /*type*/) override
{
return nullptr;
}

View File

@ -166,7 +166,7 @@ void WM_init_opengl(void)
if (G.background) {
/* Ghost is still not initialized elsewhere in background mode. */
wm_ghost_init(NULL);
wm_ghost_init_background();
}
if (!GPU_backend_supported()) {

View File

@ -1558,36 +1558,55 @@ void wm_window_process_events(const bContext *C)
void wm_ghost_init(bContext *C)
{
if (!g_system) {
GHOST_EventConsumerHandle consumer;
if (C != NULL) {
consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
}
GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace);
g_system = GHOST_CreateSystem();
GHOST_Debug debug = {0};
if (G.debug & G_DEBUG_GHOST) {
debug.flags |= GHOST_kDebugDefault;
}
if (G.debug & G_DEBUG_WINTAB) {
debug.flags |= GHOST_kDebugWintab;
}
GHOST_SystemInitDebug(g_system, debug);
if (C != NULL) {
GHOST_AddEventConsumer(g_system, consumer);
}
if (wm_init_state.native_pixels) {
GHOST_UseNativePixels();
}
GHOST_UseWindowFocus(wm_init_state.window_focus);
if (g_system) {
return;
}
BLI_assert(C != NULL);
BLI_assert_msg(!G.background, "Use wm_ghost_init_background instead");
GHOST_EventConsumerHandle consumer;
consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace);
g_system = GHOST_CreateSystem();
GHOST_Debug debug = {0};
if (G.debug & G_DEBUG_GHOST) {
debug.flags |= GHOST_kDebugDefault;
}
if (G.debug & G_DEBUG_WINTAB) {
debug.flags |= GHOST_kDebugWintab;
}
GHOST_SystemInitDebug(g_system, debug);
GHOST_AddEventConsumer(g_system, consumer);
if (wm_init_state.native_pixels) {
GHOST_UseNativePixels();
}
GHOST_UseWindowFocus(wm_init_state.window_focus);
}
/* TODO move this to wm_init_exit.c. */
void wm_ghost_init_background(void)
{
if (g_system) {
return;
}
GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace);
g_system = GHOST_CreateSystemBackground();
GHOST_Debug debug = {0};
if (G.debug & G_DEBUG_GHOST) {
debug.flags |= GHOST_kDebugDefault;
}
GHOST_SystemInitDebug(g_system, debug);
}
void wm_ghost_exit(void)

View File

@ -20,6 +20,7 @@ extern "C" {
* need to event handling.
*/
void wm_ghost_init(bContext *C);
void wm_ghost_init_background(void);
void wm_ghost_exit(void);
/**