1package models
2
3import (
4 "strings"
5
6 "github.com/bnema/archup/internal/domain/system"
7)
8
9// GPUOption represents a selectable GPU driver option.
10type GPUOption struct {
11 Label string
12 Vendor system.GPUVendor
13 Drivers []string
14}
15
16// GPUModelImpl holds GPU selection state.
17type GPUModelImpl struct {
18 detected *system.GPU
19 options []GPUOption
20 selected int
21}
22
23// NewGPUModel creates a new GPU selection model.
24func NewGPUModel() *GPUModelImpl {
25 options := []GPUOption{
26 {
27 Label: "AMD",
28 Vendor: system.GPUVendorAMD,
29 Drivers: []string{"mesa", "vulkan-radeon", "libva-mesa-driver", "mesa-vdpau"},
30 },
31 {
32 Label: "Intel",
33 Vendor: system.GPUVendorIntel,
34 Drivers: []string{"mesa", "vulkan-intel", "intel-media-driver"},
35 },
36 {
37 Label: "NVIDIA (open)",
38 Vendor: system.GPUVendorNVIDIA,
39 Drivers: []string{"nvidia-open", "nvidia-utils", "libva-nvidia-driver"},
40 },
41 {
42 Label: "None / VM",
43 Vendor: system.GPUVendorUnknown,
44 Drivers: []string{},
45 },
46 }
47
48 return &GPUModelImpl{
49 options: options,
50 selected: 0,
51 }
52}
53
54// SetDetectedGPU sets the detected GPU and aligns selection.
55func (gm *GPUModelImpl) SetDetectedGPU(gpu *system.GPU) {
56 gm.detected = gpu
57 if gpu == nil {
58 return
59 }
60 if isVirtualGPUModel(gpu.Model()) || gpu.Vendor() == system.GPUVendorUnknown {
61 gm.selectUnknown()
62 return
63 }
64 for i, option := range gm.options {
65 if option.Vendor == gpu.Vendor() {
66 gm.selected = i
67 return
68 }
69 }
70}
71
72func (gm *GPUModelImpl) selectUnknown() {
73 for i, option := range gm.options {
74 if option.Vendor == system.GPUVendorUnknown {
75 gm.selected = i
76 return
77 }
78 }
79}
80
81func isVirtualGPUModel(model string) bool {
82 lower := strings.ToLower(model)
83 virtualMarkers := []string{
84 "virtualbox",
85 "vmware",
86 "qxl",
87 "virtio",
88 "bochs",
89 "hyper-v",
90 "microsoft",
91 "svga",
92 }
93 for _, marker := range virtualMarkers {
94 if strings.Contains(lower, marker) {
95 return true
96 }
97 }
98 return false
99}
100
101// DetectedGPU returns the detected GPU.
102func (gm *GPUModelImpl) DetectedGPU() *system.GPU {
103 return gm.detected
104}
105
106// Options returns the selectable options.
107func (gm *GPUModelImpl) Options() []GPUOption {
108 return gm.options
109}
110
111// SelectedIndex returns the current selection index.
112func (gm *GPUModelImpl) SelectedIndex() int {
113 return gm.selected
114}
115
116// SelectedOption returns the currently selected option.
117func (gm *GPUModelImpl) SelectedOption() GPUOption {
118 if gm.selected < 0 || gm.selected >= len(gm.options) {
119 return gm.options[0]
120 }
121 return gm.options[gm.selected]
122}
123
124// MoveUp moves selection up.
125func (gm *GPUModelImpl) MoveUp() {
126 if gm.selected == 0 {
127 gm.selected = len(gm.options) - 1
128 return
129 }
130 gm.selected--
131}
132
133// MoveDown moves selection down.
134func (gm *GPUModelImpl) MoveDown() {
135 gm.selected = (gm.selected + 1) % len(gm.options)
136}