GPU: Select GPU Backend from Preferences.

(MacOS) only: In the System tab of the user preferences the user has the
ability to select a GPU backend that Blender will use. After changing
the GPU backend setting, the user has to restart Blender before the
setting is used.

It was added to start collecting feedback on the Metal backend without
using the command lines.

By default Blender will select OpenGL as backend. When Metal is selected
(via `--gpu-backend metal` or via user preferences) OpenGL will be used as
fallback when the platform isn't capable of running Metal.
This commit is contained in:
Jeroen Bakker 2022-12-21 20:54:36 +01:00
parent b492dc3579
commit f4b03031e8
11 changed files with 174 additions and 8 deletions

View File

@ -14,6 +14,8 @@
#include "BKE_blender_version.h"
#include "GPU_platform.h"
#include "BLO_readfile.h" /* own include */
const UserDef U_default = {
@ -99,6 +101,7 @@ const UserDef U_default = {
.gp_euclideandist = 2,
.gp_eraser = 25,
.gp_settings = 0,
.gpu_backend = GPU_BACKEND_OPENGL,
/** Initialized by: #BKE_studiolight_default. */
.light_param = {{0}},

View File

@ -604,6 +604,27 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel):
del addon
class USERPREF_PT_system_gpu_backend(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "GPU Backend"
@classmethod
def poll(cls, _context):
# Only for Apple so far
import sys
return sys.platform == "darwin"
def draw_centered(self, context, layout):
import gpu
prefs = context.preferences
system = prefs.system
col = layout.column()
col.prop(system, "gpu_backend")
if system.gpu_backend != gpu.platform.backend_type_get():
layout.label(text="Requires a restart of Blender to take effect.", icon='INFO')
class USERPREF_PT_system_os_settings(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "Operating System Settings"
@ -2406,6 +2427,7 @@ classes = (
USERPREF_PT_animation_fcurves,
USERPREF_PT_system_cycles_devices,
USERPREF_PT_system_gpu_backend,
USERPREF_PT_system_os_settings,
USERPREF_PT_system_memory,
USERPREF_PT_system_video_sequencer,

View File

@ -25,7 +25,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 4
#define BLENDER_FILE_SUBVERSION 5
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@ -10,6 +10,7 @@ set(INC
../depsgraph
../draw
../editors/include
../gpu
../imbuf
../makesdna
../makesrna

View File

@ -31,6 +31,8 @@
#include "BLO_readfile.h"
#include "GPU_platform.h"
#include "readfile.h" /* Own include. */
#include "WM_types.h"
@ -766,6 +768,11 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->dupflag |= USER_DUP_CURVES | USER_DUP_POINTCLOUD;
}
/* Set GPU backend to OpenGL. */
if (!USER_VERSION_ATLEAST(305, 5)) {
userdef->gpu_backend = GPU_BACKEND_OPENGL;
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@ -25,6 +25,30 @@ void GPU_backend_type_selection_set(const eGPUBackendType backend);
eGPUBackendType GPU_backend_type_selection_get(void);
eGPUBackendType GPU_backend_get_type(void);
/**
* Detect the most suited eGPUBackendType.
*
* - The detected backend will be set in `GPU_backend_type_selection_set`.
* - When GPU_backend_type_selection_is_overridden it checks the overridden backend.
* When not overridden it checks a default list.
* - OpenGL backend will be checked as fallback for Metal.
*
* Returns true when detection found a supported backend, otherwise returns false.
* When no supported backend is found GPU_backend_type_selection_set is called with
* GPU_BACKEND_NONE.
*/
bool GPU_backend_type_selection_detect(void);
/**
* Alter the GPU_backend_type_selection_detect to only test a specific backend
*/
void GPU_backend_type_selection_set_override(eGPUBackendType backend_type);
/**
* Check if the GPU_backend_type_selection_detect is overridden to only test a specific backend.
*/
bool GPU_backend_type_selection_is_overridden(void);
/** Opaque type hiding blender::gpu::Context. */
typedef struct GPUContext GPUContext;

View File

@ -227,11 +227,14 @@ void GPU_render_step()
* Until a global switch is added, Metal also needs to be enabled in GHOST_ContextCGL:
* `m_useMetalForRendering = true`. */
static eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL;
static std::optional<eGPUBackendType> g_backend_type_override = std::nullopt;
static std::optional<bool> g_backend_type_supported = std::nullopt;
static GPUBackend *g_backend = nullptr;
void GPU_backend_type_selection_set(const eGPUBackendType backend)
{
g_backend_type = backend;
g_backend_type_supported = std::nullopt;
}
eGPUBackendType GPU_backend_type_selection_get()
@ -239,7 +242,44 @@ eGPUBackendType GPU_backend_type_selection_get()
return g_backend_type;
}
bool GPU_backend_supported(void)
void GPU_backend_type_selection_set_override(const eGPUBackendType backend_type)
{
g_backend_type_override = backend_type;
}
bool GPU_backend_type_selection_is_overridden(void)
{
return g_backend_type_override.has_value();
}
bool GPU_backend_type_selection_detect(void)
{
blender::Vector<eGPUBackendType> backends_to_check;
if (GPU_backend_type_selection_is_overridden()) {
backends_to_check.append(*g_backend_type_override);
}
else {
backends_to_check.append(GPU_BACKEND_OPENGL);
}
/* Add fallback to OpenGL when Metal backend is requested on a platform that doens't support
* metal. */
if (backends_to_check[0] == GPU_BACKEND_METAL) {
backends_to_check.append(GPU_BACKEND_OPENGL);
}
for (const eGPUBackendType backend_type : backends_to_check) {
GPU_backend_type_selection_set(backend_type);
if (GPU_backend_supported()) {
return true;
}
}
GPU_backend_type_selection_set(GPU_BACKEND_NONE);
return false;
}
static bool gpu_backend_supported()
{
switch (g_backend_type) {
case GPU_BACKEND_OPENGL:
@ -266,6 +306,14 @@ bool GPU_backend_supported(void)
}
}
bool GPU_backend_supported()
{
if (!g_backend_type_supported.has_value()) {
g_backend_type_supported = gpu_backend_supported();
}
return *g_backend_type_supported;
}
static void gpu_backend_create()
{
BLI_assert(g_backend == nullptr);

View File

@ -828,7 +828,10 @@ typedef struct UserDef {
/** Seconds to zoom around current frame. */
float view_frame_seconds;
char _pad7[6];
/** #eGPUBackendType */
short gpu_backend;
char _pad7[4];
/** Private, defaults to 20 for 72 DPI setting. */
short widget_unit;

View File

@ -29,6 +29,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "GPU_platform.h"
#include "UI_interface_icons.h"
#include "rna_internal.h"
@ -138,6 +140,13 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_preference_gpu_backend_items[] = {
{GPU_BACKEND_OPENGL, "OPENGL", 0, "OpenGL", "Use OpenGL backend"},
{GPU_BACKEND_METAL, "METAL", 0, "Metal", "Use Metal backend"},
{GPU_BACKEND_VULKAN, "VULKAN", 0, "Vulkan", "Use Vulkan backend"},
{0, NULL, 0, NULL, NULL},
};
#ifdef RNA_RUNTIME
# include "BLI_math_vector.h"
@ -1031,6 +1040,33 @@ int rna_show_statusbar_vram_editable(struct PointerRNA *UNUSED(ptr), const char
return GPU_mem_stats_supported() ? PROP_EDITABLE : 0;
}
static const EnumPropertyItem *rna_preference_gpu_backend_itemf(struct bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
int totitem = 0;
EnumPropertyItem *result = NULL;
for (int i = 0; rna_enum_preference_gpu_backend_items[i].identifier != NULL; i++) {
const EnumPropertyItem *item = &rna_enum_preference_gpu_backend_items[i];
# ifndef WITH_METAL_BACKEND
if (item->value == GPU_BACKEND_METAL) {
continue;
}
# endif
# ifndef WITH_VULKAN_BACKEND
if (item->value == GPU_BACKEND_VULKAN) {
continue;
}
# endif
RNA_enum_item_add(&result, &totitem, item);
}
RNA_enum_item_end(&result, &totitem);
*r_free = true;
return result;
}
#else
# define USERDEF_TAG_DIRTY_PROPERTY_UPDATE_ENABLE \
@ -5604,6 +5640,16 @@ static void rna_def_userdef_system(BlenderRNA *brna)
"modifiers in the stack");
RNA_def_property_update(prop, 0, "rna_UserDef_subdivision_update");
/* GPU backend selection */
prop = RNA_def_property(srna, "gpu_backend", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "gpu_backend");
RNA_def_property_enum_items(prop, rna_enum_preference_gpu_backend_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_preference_gpu_backend_itemf");
RNA_def_property_ui_text(
prop,
"GPU Backend",
"GPU backend to use. (Requires restarting Blender for changes to take effect)");
/* Audio */
prop = RNA_def_property(srna, "audio_mixing_buffer", PROP_ENUM, PROP_NONE);

View File

@ -107,6 +107,8 @@
#include "GHOST_C-api.h"
#include "GHOST_Path-api.h"
#include "GPU_context.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@ -442,6 +444,17 @@ static void wm_window_match_do(bContext *C,
/** \name Preferences Initialization & Versioning
* \{ */
static void wm_gpu_backend_override_from_userdef(void)
{
/* Check if GPU backend is already set from the command line arguments. The command line
* arguments have higher priority than user preferences. */
if (GPU_backend_type_selection_is_overridden()) {
return;
}
GPU_backend_type_selection_set_override(U.gpu_backend);
}
/**
* In case #UserDef was read, re-initialize values that depend on it.
*/
@ -475,6 +488,9 @@ static void wm_init_userdef(Main *bmain)
WM_init_input_devices();
BLO_sanitize_experimental_features_userpref_blend(&U);
wm_gpu_backend_override_from_userdef();
GPU_backend_type_selection_detect();
}
/* return codes */

View File

@ -1150,11 +1150,7 @@ static int arg_handle_gpu_backend_set(int argc, const char **argv, void *UNUSED(
return 0;
}
GPU_backend_type_selection_set(gpu_backend);
if (!GPU_backend_supported()) {
printf("\nError: GPU backend not supported.\n");
return 0;
}
GPU_backend_type_selection_set_override(gpu_backend);
return 1;
}