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

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.