1use pagesift_gpu::GpuInfo;
4
5use crate::models::{MEDIUM_DET, MEDIUM_REC, Model, SMALL_DET, SMALL_REC};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum Device {
11 Cpu,
12 Gpu { index: usize },
13}
14
15#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct DeviceStatus {
18 pub requested: Device,
20 pub actual: Device,
22 pub gpu: Option<GpuInfo>,
24 pub fallback: Option<String>,
27}
28
29impl DeviceStatus {
30 pub fn fell_back(&self) -> bool {
32 self.fallback.is_some()
33 }
34
35 pub(crate) fn cpu() -> DeviceStatus {
37 DeviceStatus {
38 requested: Device::Cpu,
39 actual: Device::Cpu,
40 gpu: None,
41 fallback: None,
42 }
43 }
44
45 pub(crate) fn fallback(index: usize, why: String) -> DeviceStatus {
47 DeviceStatus {
48 requested: Device::Gpu { index },
49 actual: Device::Cpu,
50 gpu: None,
51 fallback: Some(why),
52 }
53 }
54
55 pub(crate) fn on_gpu(index: usize, info: GpuInfo) -> DeviceStatus {
57 let device = Device::Gpu { index };
58 DeviceStatus {
59 requested: device,
60 actual: device,
61 gpu: Some(info),
62 fallback: None,
63 }
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub enum Quality {
70 Auto,
72 Fast,
74 Accurate,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub struct ModelChoice {
81 pub det: Model,
82 pub rec: Model,
83 pub tier: &'static str,
85}
86
87impl ModelChoice {
88 fn small() -> ModelChoice {
89 ModelChoice {
90 det: SMALL_DET,
91 rec: SMALL_REC,
92 tier: "small",
93 }
94 }
95
96 fn medium() -> ModelChoice {
97 ModelChoice {
98 det: MEDIUM_DET,
99 rec: MEDIUM_REC,
100 tier: "medium",
101 }
102 }
103}
104
105pub fn medium_vram_bytes() -> u64 {
107 2288 << 20
110}
111
112pub fn select_models(quality: Quality, device: Device) -> ModelChoice {
115 match (quality, device) {
116 (Quality::Fast, _) | (Quality::Auto, Device::Cpu) => ModelChoice::small(),
117 (Quality::Accurate, _) => ModelChoice::medium(),
118 (Quality::Auto, Device::Gpu { index }) => match pagesift_gpu::probe(index) {
119 Ok(info) if info.memory_free >= medium_vram_bytes() => ModelChoice::medium(),
120 _ => ModelChoice::small(),
121 },
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn 按质量档选模型() {
131 let g = Device::Gpu { index: 0 };
132 assert_eq!(select_models(Quality::Fast, g).tier, "small");
133 assert_eq!(select_models(Quality::Auto, Device::Cpu).tier, "small");
134 assert_eq!(select_models(Quality::Accurate, Device::Cpu).tier, "medium");
135 }
136
137 #[test]
138 fn 不存在的显卡退回_cpu_并带原因() {
139 let e = pagesift_gpu::probe(9999).unwrap_err();
140 let s = DeviceStatus::fallback(9999, e);
141 assert_eq!(s.actual, Device::Cpu);
142 assert!(s.fell_back());
143 assert_eq!(s.requested, Device::Gpu { index: 9999 });
144 assert_eq!(
145 select_models(Quality::Auto, Device::Gpu { index: 9999 }).tier,
146 "small"
147 );
148 }
149}