/ wezterm / extensions / gpu_adapter.lua
gpu_adapter.lua
  1  local platform = require('extensions.platform')()
  2  local wezterm = require('wezterm')
  3  
  4  ---@alias WeztermGPUBackend 'Vulkan'|'Metal'|'Gl'|'Dx12'
  5  ---@alias WeztermGPUDeviceType 'DiscreteGpu'|'IntegratedGpu'|'Cpu'|'Other'
  6  
  7  ---@class WeztermGPUAdapter
  8  ---@field name string
  9  ---@field backend WeztermGPUBackend
 10  ---@field device number
 11  ---@field device_type WeztermGPUDeviceType
 12  ---@field driver? string
 13  ---@field driver_info? string
 14  ---@field vendor string
 15  
 16  ---@alias AdapterMap { [WeztermGPUBackend]: WeztermGPUAdapter|nil }|nil
 17  
 18  ---@class GpuAdapters
 19  ---@field __backends WeztermGPUBackend[]
 20  ---@field __preferred_backend WeztermGPUBackend
 21  ---@field __preferred_device_type WeztermGPUDeviceType
 22  ---@field DiscreteGpu AdapterMap
 23  ---@field IntegratedGpu AdapterMap
 24  ---@field Cpu AdapterMap
 25  ---@field Other AdapterMap
 26  local GpuAdapters = {}
 27  GpuAdapters.__index = GpuAdapters
 28  
 29  ---See `https://github.com/gfx-rs/wgpu#supported-platforms` for more info on available backends
 30  GpuAdapters.AVAILABLE_BACKENDS = {
 31    mac = { 'Metal' },
 32    linux = { 'Vulkan', 'Gl' },
 33  }
 34  
 35  ---@type WeztermGPUAdapter[]
 36  GpuAdapters.ENUMERATED_GPUS = wezterm.gui.enumerate_gpus()
 37  
 38  ---@return GpuAdapters
 39  ---@private
 40  function GpuAdapters:init()
 41    local initial = {
 42      __backends = self.AVAILABLE_BACKENDS[platform.os],
 43      __preferred_backend = self.AVAILABLE_BACKENDS[platform.os][1],
 44      DiscreteGpu = nil,
 45      IntegratedGpu = nil,
 46      Cpu = nil,
 47      Other = nil,
 48    }
 49  
 50    -- iterate over the enumerated GPUs and create a lookup table (`AdapterMap`)
 51    for _, adapter in ipairs(self.ENUMERATED_GPUS) do
 52      if not initial[adapter.device_type] then
 53        initial[adapter.device_type] = {}
 54      end
 55      initial[adapter.device_type][adapter.backend] = adapter
 56    end
 57  
 58    local gpu_adapters = setmetatable(initial, self)
 59  
 60    return gpu_adapters
 61  end
 62  
 63  ---Will pick the best adapter based on the following criteria:
 64  ---   1. Best GPU available (Discrete > Integrated > Other (for wgpu's OpenGl implementation on Discrete GPU) > Cpu)
 65  ---   2. Best graphics API available (based off my very scientific scroll a big log file in neovim test 😁)
 66  ---
 67  ---Graphics API choices are based on the platform:
 68  ---   - Linux: Vulkan > OpenGl
 69  ---   - Mac: Metal
 70  ---@see GpuAdapters.AVAILABLE_BACKENDS
 71  ---
 72  ---If the best adapter combo is not found, it will return `nil` and lets Wezterm decide the best adapter.
 73  ---
 74  ---Please note these are my own personal preferences and may not be the best for your system.
 75  ---If you want to manually choose the adapter, use `GpuAdapters:pick_manual(backend, device_type)`
 76  ---Or feel free to re-arrange `GpuAdapters.AVAILABLE_BACKENDS` to you liking
 77  ---@return WeztermGPUAdapter|nil
 78  function GpuAdapters:pick_best()
 79    local adapters_options = self.DiscreteGpu
 80  
 81    if not adapters_options then
 82      adapters_options = self.IntegratedGpu
 83    end
 84  
 85    if not adapters_options then
 86      adapters_options = self.Other
 87    end
 88  
 89    if not adapters_options then
 90      adapters_options = self.Cpu
 91    end
 92  
 93    if not adapters_options then
 94      wezterm.log_error('No GPU adapters found. Using Default Adapter.')
 95      return nil
 96    end
 97  
 98    local adapter_choice = adapters_options[self.__preferred_backend]
 99  
100    if not adapter_choice then
101      wezterm.log_error('Preferred backend not available. Using Default Adapter.')
102      return nil
103    end
104  
105    return adapter_choice
106  end
107  
108  ---Manually pick the adapter based on the backend and device type.
109  ---If the adapter is not found, it will return nil and lets Wezterm decide the best adapter.
110  ---@param backend WeztermGPUBackend
111  ---@param device_type WeztermGPUDeviceType
112  ---@return WeztermGPUAdapter|nil
113  function GpuAdapters:pick_manual(backend, device_type)
114    local adapters_options = self[device_type]
115  
116    if not adapters_options then
117      wezterm.log_error('No GPU adapters found. Using Default Adapter.')
118      return nil
119    end
120  
121    local adapter_choice = adapters_options[backend]
122  
123    if not adapter_choice then
124      wezterm.log_error('Preferred backend not available. Using Default Adapter.')
125      return nil
126    end
127  
128    return adapter_choice
129  end
130  
131  return GpuAdapters:init()