xref: /aosp_15_r20/external/crosvm/rutabaga_gfx/src/ipc/rutabaga_stream.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::VecDeque;
6 use std::mem::size_of;
7 
8 use zerocopy::AsBytes;
9 use zerocopy::FromBytes;
10 
11 use crate::bytestream::Reader;
12 use crate::bytestream::Writer;
13 use crate::ipc::kumquat_gpu_protocol::*;
14 use crate::rutabaga_os::AsBorrowedDescriptor;
15 use crate::rutabaga_os::AsRawDescriptor;
16 use crate::rutabaga_os::OwnedDescriptor;
17 use crate::rutabaga_os::RawDescriptor;
18 use crate::rutabaga_os::Tube;
19 use crate::rutabaga_os::DEFAULT_RAW_DESCRIPTOR;
20 use crate::rutabaga_utils::RutabagaError;
21 use crate::rutabaga_utils::RutabagaHandle;
22 use crate::rutabaga_utils::RutabagaResult;
23 use crate::rutabaga_utils::RUTABAGA_FENCE_HANDLE_TYPE_EVENT_FD;
24 
25 const MAX_DESCRIPTORS: usize = 1;
26 const MAX_COMMAND_SIZE: usize = 4096;
27 
28 pub struct RutabagaStream {
29     stream: Tube,
30     write_buffer: [u8; MAX_COMMAND_SIZE],
31     read_buffer: [u8; MAX_COMMAND_SIZE],
32     descriptors: [RawDescriptor; MAX_DESCRIPTORS],
33 }
34 
35 impl RutabagaStream {
new(stream: Tube) -> RutabagaStream36     pub fn new(stream: Tube) -> RutabagaStream {
37         RutabagaStream {
38             stream,
39             write_buffer: [0; MAX_COMMAND_SIZE],
40             read_buffer: [0; MAX_COMMAND_SIZE],
41             descriptors: [DEFAULT_RAW_DESCRIPTOR; MAX_DESCRIPTORS],
42         }
43     }
44 
write<T: FromBytes + AsBytes>( &mut self, encode: KumquatGpuProtocolWrite<T>, ) -> RutabagaResult<()>45     pub fn write<T: FromBytes + AsBytes>(
46         &mut self,
47         encode: KumquatGpuProtocolWrite<T>,
48     ) -> RutabagaResult<()> {
49         let mut writer = Writer::new(&mut self.write_buffer);
50         let mut num_descriptors = 0;
51 
52         let _handle_opt: Option<RutabagaHandle> = match encode {
53             KumquatGpuProtocolWrite::Cmd(cmd) => {
54                 writer.write_obj(cmd)?;
55                 None
56             }
57             KumquatGpuProtocolWrite::CmdWithHandle(cmd, handle) => {
58                 writer.write_obj(cmd)?;
59                 num_descriptors = 1;
60                 self.descriptors[0] = handle.os_handle.as_raw_descriptor();
61                 Some(handle)
62             }
63             KumquatGpuProtocolWrite::CmdWithData(cmd, data) => {
64                 writer.write_obj(cmd)?;
65                 writer.write_all(&data)?;
66                 None
67             }
68         };
69 
70         let bytes_written = writer.bytes_written();
71         self.stream.send(
72             &self.write_buffer[0..bytes_written],
73             &self.descriptors[0..num_descriptors],
74         )?;
75         Ok(())
76     }
77 
read(&mut self) -> RutabagaResult<Vec<KumquatGpuProtocol>>78     pub fn read(&mut self) -> RutabagaResult<Vec<KumquatGpuProtocol>> {
79         let mut vec: Vec<KumquatGpuProtocol> = Vec::new();
80         let (bytes_read, descriptor_vec) = self.stream.receive(&mut self.read_buffer)?;
81         let mut descriptors: VecDeque<OwnedDescriptor> = descriptor_vec.into();
82 
83         if bytes_read == 0 {
84             vec.push(KumquatGpuProtocol::OkNoData);
85             return Ok(vec);
86         }
87 
88         let mut reader = Reader::new(&self.read_buffer[0..bytes_read]);
89         while reader.available_bytes() != 0 {
90             let hdr = reader.peek_obj::<kumquat_gpu_protocol_ctrl_hdr>()?;
91             let protocol = match hdr.type_ {
92                 KUMQUAT_GPU_PROTOCOL_GET_NUM_CAPSETS => {
93                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
94                     KumquatGpuProtocol::GetNumCapsets
95                 }
96                 KUMQUAT_GPU_PROTOCOL_GET_CAPSET_INFO => {
97                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
98                     KumquatGpuProtocol::GetCapsetInfo(hdr.payload)
99                 }
100                 KUMQUAT_GPU_PROTOCOL_GET_CAPSET => {
101                     KumquatGpuProtocol::GetCapset(reader.read_obj()?)
102                 }
103                 KUMQUAT_GPU_PROTOCOL_CTX_CREATE => {
104                     KumquatGpuProtocol::CtxCreate(reader.read_obj()?)
105                 }
106                 KUMQUAT_GPU_PROTOCOL_CTX_DESTROY => {
107                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
108                     KumquatGpuProtocol::CtxDestroy(hdr.payload)
109                 }
110                 KUMQUAT_GPU_PROTOCOL_CTX_ATTACH_RESOURCE => {
111                     KumquatGpuProtocol::CtxAttachResource(reader.read_obj()?)
112                 }
113                 KUMQUAT_GPU_PROTOCOL_CTX_DETACH_RESOURCE => {
114                     KumquatGpuProtocol::CtxDetachResource(reader.read_obj()?)
115                 }
116                 KUMQUAT_GPU_PROTOCOL_RESOURCE_CREATE_3D => {
117                     KumquatGpuProtocol::ResourceCreate3d(reader.read_obj()?)
118                 }
119                 KUMQUAT_GPU_PROTOCOL_TRANSFER_TO_HOST_3D => {
120                     let os_handle = descriptors
121                         .pop_front()
122                         .ok_or(RutabagaError::InvalidResourceId)?;
123                     let resp: kumquat_gpu_protocol_transfer_host_3d = reader.read_obj()?;
124 
125                     let handle = RutabagaHandle {
126                         os_handle,
127                         handle_type: RUTABAGA_FENCE_HANDLE_TYPE_EVENT_FD,
128                     };
129 
130                     KumquatGpuProtocol::TransferToHost3d(resp, handle)
131                 }
132                 KUMQUAT_GPU_PROTOCOL_TRANSFER_FROM_HOST_3D => {
133                     let os_handle = descriptors
134                         .pop_front()
135                         .ok_or(RutabagaError::InvalidResourceId)?;
136                     let resp: kumquat_gpu_protocol_transfer_host_3d = reader.read_obj()?;
137 
138                     let handle = RutabagaHandle {
139                         os_handle,
140                         handle_type: RUTABAGA_FENCE_HANDLE_TYPE_EVENT_FD,
141                     };
142 
143                     KumquatGpuProtocol::TransferFromHost3d(resp, handle)
144                 }
145                 KUMQUAT_GPU_PROTOCOL_SUBMIT_3D => {
146                     let cmd: kumquat_gpu_protocol_cmd_submit = reader.read_obj()?;
147                     if reader.available_bytes() < cmd.size.try_into()? {
148                         // Large command buffers should handled via shared memory.
149                         return Err(RutabagaError::InvalidCommandBuffer);
150                     } else if reader.available_bytes() != 0 {
151                         let num_in_fences = cmd.num_in_fences as usize;
152                         let cmd_size = cmd.size as usize;
153                         let mut cmd_buf = vec![0; cmd_size];
154                         let mut fence_ids: Vec<u64> = Vec::with_capacity(num_in_fences);
155                         for _ in 0..num_in_fences {
156                             match reader.read_obj::<u64>() {
157                                 Ok(fence_id) => {
158                                     fence_ids.push(fence_id);
159                                 }
160                                 Err(_) => return Err(RutabagaError::InvalidIovec),
161                             }
162                         }
163                         reader.read_exact(&mut cmd_buf[..])?;
164                         KumquatGpuProtocol::CmdSubmit3d(cmd, cmd_buf, fence_ids)
165                     } else {
166                         KumquatGpuProtocol::CmdSubmit3d(cmd, Vec::new(), Vec::new())
167                     }
168                 }
169                 KUMQUAT_GPU_PROTOCOL_RESOURCE_CREATE_BLOB => {
170                     KumquatGpuProtocol::ResourceCreateBlob(reader.read_obj()?)
171                 }
172                 KUMQUAT_GPU_PROTOCOL_SNAPSHOT_SAVE => {
173                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
174                     KumquatGpuProtocol::SnapshotSave
175                 }
176                 KUMQUAT_GPU_PROTOCOL_SNAPSHOT_RESTORE => {
177                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
178                     KumquatGpuProtocol::SnapshotRestore
179                 }
180                 KUMQUAT_GPU_PROTOCOL_RESP_NUM_CAPSETS => {
181                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
182                     KumquatGpuProtocol::RespNumCapsets(hdr.payload)
183                 }
184                 KUMQUAT_GPU_PROTOCOL_RESP_CAPSET_INFO => {
185                     KumquatGpuProtocol::RespCapsetInfo(reader.read_obj()?)
186                 }
187                 KUMQUAT_GPU_PROTOCOL_RESP_CAPSET => {
188                     let len: usize = hdr.payload.try_into()?;
189                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
190                     let mut capset: Vec<u8> = vec![0; len];
191                     reader.read_exact(&mut capset)?;
192                     KumquatGpuProtocol::RespCapset(capset)
193                 }
194                 KUMQUAT_GPU_PROTOCOL_RESP_CONTEXT_CREATE => {
195                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
196                     KumquatGpuProtocol::RespContextCreate(hdr.payload)
197                 }
198                 KUMQUAT_GPU_PROTOCOL_RESP_RESOURCE_CREATE => {
199                     let os_handle = descriptors
200                         .pop_front()
201                         .ok_or(RutabagaError::InvalidResourceId)?;
202                     let resp: kumquat_gpu_protocol_resp_resource_create = reader.read_obj()?;
203 
204                     let handle = RutabagaHandle {
205                         os_handle,
206                         handle_type: resp.handle_type,
207                     };
208 
209                     KumquatGpuProtocol::RespResourceCreate(resp, handle)
210                 }
211                 KUMQUAT_GPU_PROTOCOL_RESP_CMD_SUBMIT_3D => {
212                     let os_handle = descriptors
213                         .pop_front()
214                         .ok_or(RutabagaError::InvalidResourceId)?;
215                     let resp: kumquat_gpu_protocol_resp_cmd_submit_3d = reader.read_obj()?;
216 
217                     let handle = RutabagaHandle {
218                         os_handle,
219                         handle_type: resp.handle_type,
220                     };
221 
222                     KumquatGpuProtocol::RespCmdSubmit3d(resp.fence_id, handle)
223                 }
224                 KUMQUAT_GPU_PROTOCOL_RESP_OK_SNAPSHOT => {
225                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
226                     KumquatGpuProtocol::RespOkSnapshot
227                 }
228                 _ => {
229                     return Err(RutabagaError::Unsupported);
230                 }
231             };
232 
233             vec.push(protocol);
234         }
235 
236         Ok(vec)
237     }
238 
as_borrowed_descriptor(&self) -> &OwnedDescriptor239     pub fn as_borrowed_descriptor(&self) -> &OwnedDescriptor {
240         self.stream.as_borrowed_descriptor()
241     }
242 }
243