--- tags: Eevee/viewport, T101977 --- # T101977: GPU backend selection Related to https://developer.blender.org/T101977 ## Requirements * From the command line it should be possible to override the GPU backend selection. * From the user preferences it should be possible to override the GPU backend selection. * Blender should try multiple backends to find a matching backend. * ~~When an override is set in the user preferences that isn't supported by the running platform the default detection should be run.~~ * When an unsupported override is set blender should fallback to OpenGL. * The command line argument has more priority than the user preference setting. ## Current API ```plantuml @startuml package blender::gpu { object GPU_context.h { +GPU_backend_supported(): bool +GPU_backend_type_selection_set(backend_type: eGPUBackendType) +GPU_backend_type_selection_get(): eGPUBackendType +GPU_backend_get_type(): eGPUBackendType +GPU_context_create(ghost_window, ghost_context) +GPU_context_destroy() } } @enduml ``` * `GPU_context_create` creates a new context based on `GPU_backend_type_selection_get`. * `GPU_context_create` requires the correct `ghost_context` for the current `GPU_backend_type_selection_get`. Expect crashes when this isn't enforced. * `GPU_backend_supported` checks if the backend returned by `GPU_backend_type_selection_get` is supported by the platform. It doesn't require the context to be created. * `GPU_backend_type_selection_set` overrides the default backend with the given type. It is called during command line argument parsing for the `--gpu-backend` argument. It is also called by `ShaderBuilder` and test cases to check multiple backends during the same run. * `GPU_backend_get_type` returns the backend type that was initialized when the context is created. ## Proposal In the proposals `CallerComponent` is used to as a replacement for `WM` to keep the design focused on essentials. The implementation in WM is scattered in more layers. ### User Preferences In the user preferences system tab a new panel will be added "GPU Backend" with the next options: * Default * OpenGL * Metal For now the panel only appears on Apple ![](https://i.imgur.com/mTCd2xc.png) Changing this value requires a restart. This should be clearly communicated to the user. Technical the user could set an override to something that isn't supported by his system. For example when copying/syncing user preferences to other machines. This could be detected and automatically switch back to the default behavior. :::danger Q: Should this be hidden behind experimental feature? If so we might want to move this to the Experimental tab. ::: ### API Proposal 1a: GPU_backend_types Add a function that returns all compiled in GPU backends in order of priority. An auto detect function can go over this list to detect a supported one for the platform. ```plantuml @startuml activate CallerComponent CallerComponent -> GPU: GPU_backend_types_get() activate GPU deactivate GPU loop for each backend CallerComponent -> GPU: GPU_backend_type_selection_set() activate GPU deactivate GPU CallerComponent -> GPU: GPU_backend_supported() activate GPU deactivate GPU alt is backend supported CallerComponent -> GHOST: create and activate context activate GHOST deactivate GHOST note right: GHOST in this diagram is over-simplified CallerComponent -> GPU: GPU_context_create activate GPU deactivate GPU <-- CallerComponent: valid context end end CallerComponent -> GHOST: display OS error dialog activate GHOST deactivate GHOST deactivate CallerComponent @enduml ``` The `--gpu-backend` and the user preferences would be able to change the list of backends. `GPU_backend_type_selection_override()`. ### API Proposal 1b: GPU_backend_types with detection A variant of the previous one, but placing the for-loop inside the GPU module. Add a function that returns all compiled in GPU backends in order of priority. An auto detect function can go over this list to detect a supported one for the platform. ```plantuml @startuml activate CallerComponent CallerComponent -> GPU: GPU_backend_type_selection_detect() activate GPU loop for each backend GPU -> GPU: GPU_backend_type_selection_set() activate GPU deactivate GPU GPU -> GPU: GPU_backend_supported() activate GPU deactivate GPU alt is backend supported CallerComponent <-- GPU end end deactivate GPU CallerComponent -> GHOST: create and activate context activate GHOST deactivate GHOST note right: GHOST in this diagram is over-simplified CallerComponent -> GPU: GPU_context_create activate GPU deactivate GPU <-- CallerComponent: valid context deactivate CallerComponent @enduml ``` The `--gpu-backend` and the user preferences would be able to change the list of backends. `GPU_backend_types_override()`. ## Impact ```plantuml @startuml package blender::makesdna { class UserDef { +gpu_backend: eGPUBackendType } } package blender::gpu { object GPU_context.h { --- existing API functions --- +GPU_backend_supported(): bool +GPU_backend_type_selection_set(backend_type: eGPUBackendType) +GPU_backend_type_selection_get(): eGPUBackendType +GPU_backend_get_type(): eGPUBackendType +GPU_context_create(ghost_window, ghost_context) +GPU_context_destroy() --- new API functions --- +GPU_backend_type_selection_set_override(override: eGPUBackendType) +GPU_backend_type_selection_is_overridden() +GPU_backend_type_selection_detect() } } @enduml ``` ### User preference * [x] Add `gpu_backend` to `UserDef` structure in `DNA_userdef_types.h` * [ ] ~~Add `ePrefGPUBackendType` enum type containing all options for `UserDef.gpu_backend`. This would allow loading user prefs from other systems without loosing the information.~~ * [x] In `rna_userdef.c` define `gpu_backend` property. * [x] Add `USERPREF_PT_system_gpu_backend` to `space_userpref.py`. ### GPU module * [x] Implement the new API functions and tweak the existing ones. * [x] Cache the result of `GPU_backend_supported` until `GPU_backend_type_selection_set` is called. ### Command line arguments * [x] In `creator_args.c#arg_handle_gpu_backend_set` use `GPU_backend_type_selection_override`. ~~after checking if backend is supported.~~ ### Window manager * [x] In ~~`WM_init` just after reading home file~~,`wm_init_userdef` check if backend types are not yet overridden. If so override the backend types with the setting stored in the user preference. * [ ] ~~In `WM_init` when platform is overridden, but not supported, display error message to the user and exit. Best to reuse `WM_platform_support_perform_checks` for this.~~ * [x] In ~~`WM_init`~~ `wm_init_userdef`let the GPU_module detect which GPU backend should be used.