xref: /aosp_15_r20/external/crosvm/rutabaga_gfx/kumquat/server/src/kumquat.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::collections::btree_map::Entry;
6 use std::collections::BTreeMap as Map;
7 use std::path::PathBuf;
8 
9 use rutabaga_gfx::kumquat_support::RutabagaListener;
10 use rutabaga_gfx::kumquat_support::RutabagaWaitContext;
11 use rutabaga_gfx::kumquat_support::RutabagaWaitTimeout;
12 use rutabaga_gfx::RutabagaAsBorrowedDescriptor as AsBorrowedDescriptor;
13 use rutabaga_gfx::RutabagaError;
14 use rutabaga_gfx::RutabagaResult;
15 
16 use crate::kumquat_gpu::KumquatGpu;
17 use crate::kumquat_gpu::KumquatGpuConnection;
18 
19 enum KumquatConnection {
20     GpuListener,
21     GpuConnection(KumquatGpuConnection),
22 }
23 
24 pub struct Kumquat {
25     connection_id: u64,
26     wait_ctx: RutabagaWaitContext,
27     kumquat_gpu_opt: Option<KumquatGpu>,
28     gpu_listener_opt: Option<RutabagaListener>,
29     connections: Map<u64, KumquatConnection>,
30 }
31 
32 impl Kumquat {
run(&mut self) -> RutabagaResult<()>33     pub fn run(&mut self) -> RutabagaResult<()> {
34         let events = self.wait_ctx.wait(RutabagaWaitTimeout::NoTimeout)?;
35         for event in events {
36             let mut hung_up = false;
37             match self.connections.entry(event.connection_id) {
38                 Entry::Occupied(mut o) => {
39                     let connection = o.get_mut();
40                     match connection {
41                         KumquatConnection::GpuListener => {
42                             if let Some(ref listener) = self.gpu_listener_opt {
43                                 let stream = listener.accept()?;
44                                 self.connection_id += 1;
45                                 let new_gpu_conn = KumquatGpuConnection::new(stream);
46                                 self.wait_ctx.add(
47                                     self.connection_id,
48                                     new_gpu_conn.as_borrowed_descriptor(),
49                                 )?;
50                                 self.connections.insert(
51                                     self.connection_id,
52                                     KumquatConnection::GpuConnection(new_gpu_conn),
53                                 );
54                             }
55                         }
56                         KumquatConnection::GpuConnection(ref mut gpu_conn) => {
57                             if event.readable {
58                                 if let Some(ref mut kumquat_gpu) = self.kumquat_gpu_opt {
59                                     hung_up =
60                                         !gpu_conn.process_command(kumquat_gpu)? && event.hung_up;
61                                 }
62                             }
63 
64                             if hung_up {
65                                 self.wait_ctx.delete(gpu_conn.as_borrowed_descriptor())?;
66                                 o.remove_entry();
67                             }
68                         }
69                     }
70                 }
71                 Entry::Vacant(_) => {
72                     return Err(RutabagaError::SpecViolation("no connection found"))
73                 }
74             }
75         }
76 
77         Ok(())
78     }
79 }
80 
81 pub struct KumquatBuilder {
82     capset_names_opt: Option<String>,
83     gpu_socket_opt: Option<String>,
84     renderer_features_opt: Option<String>,
85 }
86 
87 impl KumquatBuilder {
new() -> KumquatBuilder88     pub fn new() -> KumquatBuilder {
89         KumquatBuilder {
90             capset_names_opt: None,
91             gpu_socket_opt: None,
92             renderer_features_opt: None,
93         }
94     }
95 
set_capset_names(mut self, capset_names: String) -> KumquatBuilder96     pub fn set_capset_names(mut self, capset_names: String) -> KumquatBuilder {
97         self.capset_names_opt = Some(capset_names);
98         self
99     }
100 
set_gpu_socket(mut self, gpu_socket_opt: Option<String>) -> KumquatBuilder101     pub fn set_gpu_socket(mut self, gpu_socket_opt: Option<String>) -> KumquatBuilder {
102         self.gpu_socket_opt = gpu_socket_opt;
103         self
104     }
105 
set_renderer_features(mut self, renderer_features: String) -> KumquatBuilder106     pub fn set_renderer_features(mut self, renderer_features: String) -> KumquatBuilder {
107         self.renderer_features_opt = Some(renderer_features);
108         self
109     }
110 
build(self) -> RutabagaResult<Kumquat>111     pub fn build(self) -> RutabagaResult<Kumquat> {
112         let connection_id: u64 = 0;
113         let mut wait_ctx = RutabagaWaitContext::new()?;
114         let mut kumquat_gpu_opt: Option<KumquatGpu> = None;
115         let mut gpu_listener_opt: Option<RutabagaListener> = None;
116         let mut connections: Map<u64, KumquatConnection> = Default::default();
117 
118         if let Some(gpu_socket) = self.gpu_socket_opt {
119             // Remove path if it exists
120             let path = PathBuf::from(&gpu_socket);
121             let _ = std::fs::remove_file(&path);
122 
123             // Should not panic, since main.rs always calls set_capset_names and
124             // set_renderer_features, even with the empty string.
125             kumquat_gpu_opt = Some(KumquatGpu::new(
126                 self.capset_names_opt.unwrap(),
127                 self.renderer_features_opt.unwrap(),
128             )?);
129 
130             let gpu_listener = RutabagaListener::bind(path)?;
131             wait_ctx.add(connection_id, gpu_listener.as_borrowed_descriptor())?;
132             connections.insert(connection_id, KumquatConnection::GpuListener);
133             gpu_listener_opt = Some(gpu_listener);
134         }
135 
136         Ok(Kumquat {
137             connection_id,
138             wait_ctx,
139             kumquat_gpu_opt,
140             gpu_listener_opt,
141             connections,
142         })
143     }
144 }
145