diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index b4a1ab6d5f8..24e093833c4 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -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}}, diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 759b222c562..44bc807c7dd 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -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, diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 91a458e347f..7c241a4fa12 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -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 diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 86793d38b0b..a7e99e7df2e 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -10,6 +10,7 @@ set(INC ../depsgraph ../draw ../editors/include + ../gpu ../imbuf ../makesdna ../makesrna diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index b4890131861..10a21356c8f 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -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. * diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h index ac82774039a..fd20283380f 100644 --- a/source/blender/gpu/GPU_context.h +++ b/source/blender/gpu/GPU_context.h @@ -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; diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index 0443417a32a..101542802e6 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -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 g_backend_type_override = std::nullopt; +static std::optional 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 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); diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 8a644803fd7..18c4508efae 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -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; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b93983d0a87..db12ac82f38 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -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); diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 7b1fcf2a231..712bee6ef8b 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -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 */ diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 2ebdcdb35ba..e942c0d18ee 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -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; }