Blender: Add command line argument to switch gpu backends.

Add command line argument to switch gpu backend. Add `--gpu-backend` option to
override the gpu backend selected by Blender.

Values for this option that will be available in releases for now are:
* opengl: Force blender to select OpenGL backend.

During development and depending on compile options additional values can exist:
* metal: Force Blender to select Metal backend.

When this option isn't provided the internal logic for GPU backend selection will be used.
Note that this is at the time of writing the same as always selecting the opengl backend.

Reviewed By: fclem, brecht, MichaelPW

Differential Revision: https://developer.blender.org/D16297
This commit is contained in:
Jeroen Bakker 2022-10-19 15:13:15 +02:00 committed by Jeroen Bakker
parent ead3fc4a07
commit 3655eb7ff0
Notes: blender-bot 2023-02-14 08:47:25 +01:00
Referenced by issue #101905, Blender: Add command line argument to switch gpu backends
28 changed files with 166 additions and 62 deletions

View File

@ -162,7 +162,6 @@ extern void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle,
* \param height: The height the window.
* \param state: The state of the window when opened.
* \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized.
* \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL options.
* \return A handle to the new window ( == NULL if creation failed).
*/
@ -175,7 +174,6 @@ extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
uint32_t height,
GHOST_TWindowState state,
bool is_dialog,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings);
/**

View File

@ -232,7 +232,6 @@ class GHOST_ISystem {
* \param width: The width the window.
* \param height: The height the window.
* \param state: The state of the window when opened.
* \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
* \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized.
@ -245,7 +244,6 @@ class GHOST_ISystem {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
const bool is_dialog = false,

View File

@ -60,10 +60,6 @@ typedef struct {
int hot_spot[2];
} GHOST_CursorBitmapRef;
typedef struct {
int flags;
} GHOST_GLSettings;
typedef enum {
GHOST_glStereoVisual = (1 << 0),
GHOST_glDebugContext = (1 << 1),
@ -157,6 +153,9 @@ typedef enum {
#ifdef WIN32
GHOST_kDrawingContextTypeD3D,
#endif
#ifdef __APPLE__
GHOST_kDrawingContextTypeMetal,
#endif
} GHOST_TDrawingContextType;
typedef enum {
@ -598,6 +597,11 @@ typedef struct {
uint32_t frequency;
} GHOST_DisplaySetting;
typedef struct {
int flags;
GHOST_TDrawingContextType context_type;
} GHOST_GLSettings;
typedef enum {
/** Axis that cursor grab will wrap. */
GHOST_kDebugDefault = (1 << 1),

View File

@ -161,7 +161,6 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
uint32_t height,
GHOST_TWindowState state,
bool is_dialog,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
@ -172,7 +171,6 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
width,
height,
state,
type,
glSettings,
false,
is_dialog,

View File

@ -30,7 +30,8 @@ class GHOST_ContextCGL : public GHOST_Context {
GHOST_ContextCGL(bool stereoVisual,
NSView *metalView,
CAMetalLayer *metalLayer,
NSOpenGLView *openglView);
NSOpenGLView *openglView,
GHOST_TDrawingContextType type);
/**
* Destructor.

View File

@ -46,8 +46,10 @@ int GHOST_ContextCGL::s_sharedCount = 0;
GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
NSView *metalView,
CAMetalLayer *metalLayer,
NSOpenGLView *openGLView)
NSOpenGLView *openGLView,
GHOST_TDrawingContextType type)
: GHOST_Context(stereoVisual),
m_useMetalForRendering(type == GHOST_kDrawingContextTypeMetal),
m_metalView(metalView),
m_metalLayer(metalLayer),
m_metalCmdQueue(nil),

View File

@ -384,6 +384,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
if (stereoVisual) {
glSettings.flags |= GHOST_glStereoVisual;
}
glSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
/* NOTE: don't use #getCurrentDisplaySetting() because on X11 we may
* be zoomed in and the desktop may be bigger than the viewport. */
GHOST_ASSERT(m_displayManager,
@ -395,7 +396,6 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
settings.xPixels,
settings.yPixels,
GHOST_kWindowStateNormal,
GHOST_kDrawingContextTypeOpenGL,
glSettings,
true /* exclusive */);
return (*window == nullptr) ? GHOST_kFailure : GHOST_kSuccess;

View File

@ -77,7 +77,6 @@ class GHOST_SystemCocoa : public GHOST_System {
* \param width: The width the window.
* \param height: The height the window.
* \param state: The state of the window when opened.
* \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
* \param parentWindow: Parent (embedder) window.
@ -89,7 +88,6 @@ class GHOST_SystemCocoa : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
const bool is_dialog = false,

View File

@ -689,7 +689,6 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,
@ -719,7 +718,7 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
width,
height,
state,
type,
glSettings.context_type,
glSettings.flags & GHOST_glStereoVisual,
glSettings.flags & GHOST_glDebugContext,
is_dialog,
@ -751,7 +750,7 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
*/
GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GLSettings glSettings)
{
GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL);
GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL, glSettings.context_type);
if (context->initializeDrawingContext())
return context;
else

View File

@ -142,7 +142,6 @@ class GHOST_SystemHeadless : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool /*exclusive*/,
const bool /*is_dialog*/,
@ -155,7 +154,7 @@ class GHOST_SystemHeadless : public GHOST_System {
height,
state,
parentWindow,
type,
glSettings.context_type,
((glSettings.flags & GHOST_glStereoVisual) != 0));
}

View File

@ -42,7 +42,6 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
const bool /* is_dialog */,
@ -57,7 +56,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
width,
height,
state,
type,
glSettings.context_type,
((glSettings.flags & GHOST_glStereoVisual) != 0),
exclusive,
parentWindow);

View File

@ -71,7 +71,6 @@ class GHOST_SystemSDL : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
const bool is_dialog = false,

View File

@ -3813,7 +3813,6 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
const uint32_t width,
const uint32_t height,
const GHOST_TWindowState state,
const GHOST_TDrawingContextType type,
const GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,
@ -3833,7 +3832,7 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
height,
state,
parentWindow,
type,
glSettings.context_type,
is_dialog,
((glSettings.flags & GHOST_glStereoVisual) != 0),
exclusive);

View File

@ -128,7 +128,6 @@ class GHOST_SystemWayland : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,

View File

@ -213,7 +213,6 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,
@ -227,7 +226,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
width,
height,
state,
type,
glSettings.context_type,
((glSettings.flags & GHOST_glStereoVisual) != 0),
false,
(GHOST_WindowWin32 *)parentWindow,

View File

@ -103,7 +103,6 @@ class GHOST_SystemWin32 : public GHOST_System {
* \param width: The width the window.
* \param height: The height the window.
* \param state: The state of the window when opened.
* \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
* \param parentWindow: Parent window.
@ -115,7 +114,6 @@ class GHOST_SystemWin32 : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
const bool is_dialog = false,

View File

@ -308,7 +308,6 @@ void GHOST_SystemX11::getAllDisplayDimensions(uint32_t &width, uint32_t &height)
* \param width: The width the window.
* \param height: The height the window.
* \param state: The state of the window when opened.
* \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
* \param parentWindow: Parent window.
@ -320,7 +319,6 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,
@ -341,7 +339,7 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
height,
state,
(GHOST_WindowX11 *)parentWindow,
type,
glSettings.context_type,
is_dialog,
((glSettings.flags & GHOST_glStereoVisual) != 0),
exclusive,

View File

@ -113,7 +113,6 @@ class GHOST_SystemX11 : public GHOST_System {
* \param width: The width the window.
* \param height: The height the window.
* \param state: The state of the window when opened.
* \param type: The type of drawing context installed in this window.
* \param stereoVisual: Create a stereo visual for quad buffered stereo.
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
* \param parentWindow: Parent (embedder) window.
@ -125,7 +124,6 @@ class GHOST_SystemX11 : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
const bool is_dialog = false,

View File

@ -803,10 +803,10 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType type)
{
if (type == GHOST_kDrawingContextTypeOpenGL) {
if (type == GHOST_kDrawingContextTypeOpenGL || type == GHOST_kDrawingContextTypeMetal) {
GHOST_Context *context = new GHOST_ContextCGL(
m_wantStereoVisual, m_metalView, m_metalLayer, m_openGLView);
m_wantStereoVisual, m_metalView, m_metalLayer, m_openGLView, type);
if (context->initializeDrawingContext())
return context;

View File

@ -407,17 +407,12 @@ Application::Application(GHOST_ISystem *system)
stereo(false)
{
GHOST_GLSettings glSettings = {0};
glSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
fApp = this;
// Create the main window
m_mainWindow = system->createWindow("gears - main window",
10,
64,
320,
200,
GHOST_kWindowStateNormal,
GHOST_kDrawingContextTypeOpenGL,
glSettings);
m_mainWindow = system->createWindow(
"gears - main window", 10, 64, 320, 200, GHOST_kWindowStateNormal, glSettings);
if (!m_mainWindow) {
std::cout << "could not create main window\n";
@ -425,14 +420,8 @@ Application::Application(GHOST_ISystem *system)
}
// Create a secondary window
m_secondaryWindow = system->createWindow("gears - secondary window",
340,
64,
320,
200,
GHOST_kWindowStateNormal,
GHOST_kDrawingContextTypeOpenGL,
glSettings);
m_secondaryWindow = system->createWindow(
"gears - secondary window", 340, 64, 320, 200, GHOST_kWindowStateNormal, glSettings);
if (!m_secondaryWindow) {
std::cout << "could not create secondary window\n";
exit(-1);

View File

@ -21,6 +21,8 @@ extern "C" {
* automatically initializes the back-end, and #GPU_context_discard frees it when there
* are no more contexts. */
bool GPU_backend_supported(void);
void GPU_backend_type_selection_set(const eGPUBackendType backend);
eGPUBackendType GPU_backend_type_selection_get(void);
eGPUBackendType GPU_backend_get_type(void);
/** Opaque type hiding blender::gpu::Context. */

View File

@ -223,9 +223,19 @@ void GPU_render_step()
/* NOTE: To enable Metal API, we need to temporarily change this to `GPU_BACKEND_METAL`.
* Until a global switch is added, Metal also needs to be enabled in GHOST_ContextCGL:
* `m_useMetalForRendering = true`. */
static const eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL;
static eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL;
static GPUBackend *g_backend = nullptr;
void GPU_backend_type_selection_set(const eGPUBackendType backend)
{
g_backend_type = backend;
}
eGPUBackendType GPU_backend_type_selection_get()
{
return g_backend_type;
}
bool GPU_backend_supported(void)
{
switch (g_backend_type) {

View File

@ -15,6 +15,8 @@
#include "GPU_init_exit.h"
#include "gpu_shader_create_info_private.hh"
#include "BLI_vector.hh"
#include "CLG_log.h"
namespace blender::gpu::shader_builder {
@ -41,6 +43,22 @@ void ShaderBuilder::init()
CLG_init();
GHOST_GLSettings glSettings = {0};
switch (GPU_backend_type_selection_get()) {
case GPU_BACKEND_OPENGL:
glSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
break;
#ifdef WITH_METAL_BACKEND
case GPU_BACKEND_METAL:
glSettings.context_type = GHOST_kDrawingContextTypeMetal;
break;
#endif
default:
BLI_assert_unreachable();
break;
}
ghost_system_ = GHOST_CreateSystem();
ghost_context_ = GHOST_CreateOpenGLContext(ghost_system_, glSettings);
GHOST_ActivateOpenGLContext(ghost_context_);
@ -73,13 +91,32 @@ int main(int argc, const char *argv[])
int exit_code = 0;
blender::gpu::shader_builder::ShaderBuilder builder;
builder.init();
if (!builder.bake_create_infos()) {
exit_code = 1;
struct NamedBackend {
std::string name;
eGPUBackendType backend;
};
blender::Vector<NamedBackend> backends_to_validate;
backends_to_validate.append({"OpenGL", GPU_BACKEND_OPENGL});
#ifdef WITH_METAL_BACKEND
backends_to_validate.append({"Metal", GPU_BACKEND_METAL});
#endif
for (NamedBackend &backend : backends_to_validate) {
GPU_backend_type_selection_set(backend.backend);
if (!GPU_backend_supported()) {
printf("%s isn't supported on this platform. Shader compilation is skipped\n",
backend.name.c_str());
continue;
}
blender::gpu::shader_builder::ShaderBuilder builder;
builder.init();
if (!builder.bake_create_infos()) {
printf("Shader compilation failed for %s backend\n", backend.name.c_str());
exit_code = 1;
}
builder.exit();
exit(exit_code);
}
builder.exit();
exit(exit_code);
return exit_code;
}

View File

@ -46,6 +46,15 @@ void IMB_freeImBuf(ImBuf * /*ibuf*/)
BLI_assert_unreachable();
}
struct ImBuf *IMB_allocImBuf(unsigned int /*x*/,
unsigned int /*y*/,
unsigned char /*planes*/,
unsigned int /*flags*/)
{
BLI_assert_unreachable();
return nullptr;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -59,6 +59,8 @@
#include "DEG_depsgraph.h"
#include "wm_window_private.h"
#include "WM_api.h" /* only for WM_main_playanim */
#ifdef WITH_AUDASPACE
@ -1340,6 +1342,8 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey)
{
GHOST_GLSettings glsettings = {0};
const eGPUBackendType gpu_backend = GPU_backend_type_selection_get();
glsettings.context_type = wm_ghost_drawing_context_type(gpu_backend);
uint32_t scr_w, scr_h;
GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &scr_w, &scr_h);
@ -1356,7 +1360,6 @@ static void playanim_window_open(const char *title, int posx, int posy, int size
/* Could optionally start full-screen. */
GHOST_kWindowStateNormal,
false,
GHOST_kDrawingContextTypeOpenGL,
glsettings);
}

View File

@ -556,6 +556,9 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm,
glSettings.flags |= GHOST_glDebugContext;
}
eGPUBackendType gpu_backend = GPU_backend_type_selection_get();
glSettings.context_type = wm_ghost_drawing_context_type(gpu_backend);
int scr_w, scr_h;
wm_get_desktopsize(&scr_w, &scr_h);
int posy = (scr_h - win->posy - win->sizey);
@ -573,7 +576,6 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm,
win->sizey,
(GHOST_TWindowState)win->windowstate,
is_dialog,
GHOST_kDrawingContextTypeOpenGL,
glSettings);
if (ghostwin) {
@ -1615,6 +1617,23 @@ const char *WM_ghost_backend(void)
#endif
}
GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend)
{
switch (gpu_backend) {
case GPU_BACKEND_NONE:
return GHOST_kDrawingContextTypeNone;
case GPU_BACKEND_ANY:
case GPU_BACKEND_OPENGL:
return GHOST_kDrawingContextTypeOpenGL;
#ifdef WITH_METAL_BACKEND
case GPU_BACKEND_METAL:
return GHOST_kDrawingContextTypeMetal;
#endif
}
BLI_assert_unreachable();
return GHOST_kDrawingContextTypeNone;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -7,8 +7,11 @@
#pragma once
#include "BLI_sys_types.h"
#include "GHOST_Types.h"
#include "GPU_context.h"
/* *************** Message box *************** */
/* `WM_ghost_show_message_box` is implemented in `wm_windows.c` it is
* defined here as it was implemented to be used for showing
@ -21,3 +24,5 @@ void WM_ghost_show_message_box(const char *title,
const char *continue_label,
const char *link,
GHOST_DialogOptions dialog_options);
GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend);

View File

@ -42,6 +42,8 @@
# include "BKE_scene.h"
# include "BKE_sound.h"
# include "GPU_context.h"
# ifdef WITH_FFMPEG
# include "IMB_imbuf.h"
# endif
@ -1111,6 +1113,44 @@ static int arg_handle_debug_gpu_set(int UNUSED(argc),
return 0;
}
static const char arg_handle_gpu_backend_set_doc[] =
"\n"
"\tForce to use a specific GPU backend. Valid options: "
# ifdef WITH_METAL_BACKEND
"'metal', "
# endif
"'opengl').";
static int arg_handle_gpu_backend_set(int argc, const char **argv, void *UNUSED(data))
{
if (argc == 0) {
printf("\nError: GPU backend must follow '--gpu-backend'.\n");
return 0;
}
eGPUBackendType gpu_backend = GPU_BACKEND_NONE;
if (STREQ(argv[1], "opengl")) {
gpu_backend = GPU_BACKEND_OPENGL;
}
# ifdef WITH_METAL_BACKEND
else if (STREQ(argv[1], "metal")) {
gpu_backend = GPU_BACKEND_METAL;
}
# endif
else {
printf("\nError: Unrecognized GPU backend for '--gpu-backend'.\n");
return 0;
}
GPU_backend_type_selection_set(gpu_backend);
if (!GPU_backend_supported()) {
printf("\nError: GPU backend not supported.\n");
return 0;
}
return 1;
}
static const char arg_handle_debug_fpe_set_doc[] =
"\n\t"
"Enable floating-point exceptions.";
@ -2074,6 +2114,10 @@ void main_args_setup(bContext *C, bArgs *ba)
BLI_args_add(ba, NULL, "--log-show-timestamp", CB(arg_handle_log_show_timestamp_set), ba);
BLI_args_add(ba, NULL, "--log-file", CB(arg_handle_log_file_set), ba);
/* GPU backend selection should be part of ARG_PASS_ENVIRONMENT for correct GPU context selection
* for anim player. */
BLI_args_add(ba, NULL, "--gpu-backend", CB(arg_handle_gpu_backend_set), NULL);
/* Pass: Background Mode & Settings
*
* Also and commands that exit after usage. */