xref: /aosp_15_r20/external/crosvm/devices/src/virtio/video/utils.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker // Not all video backends make use of the tools in this module.
6*bb4ee6a4SAndroid Build Coastguard Worker #![allow(dead_code)]
7*bb4ee6a4SAndroid Build Coastguard Worker 
8*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::btree_map::Entry;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::VecDeque;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
12*bb4ee6a4SAndroid Build Coastguard Worker 
13*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::EventExt;
16*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
17*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
18*bb4ee6a4SAndroid Build Coastguard Worker 
19*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::video::resource::GuestResource;
20*bb4ee6a4SAndroid Build Coastguard Worker 
21*bb4ee6a4SAndroid Build Coastguard Worker /// Manages a pollable queue of events to be sent to the decoder or encoder.
22*bb4ee6a4SAndroid Build Coastguard Worker pub struct EventQueue<T> {
23*bb4ee6a4SAndroid Build Coastguard Worker     /// Pipe used to signal available events.
24*bb4ee6a4SAndroid Build Coastguard Worker     event: Event,
25*bb4ee6a4SAndroid Build Coastguard Worker     /// FIFO of all pending events.
26*bb4ee6a4SAndroid Build Coastguard Worker     pending_events: VecDeque<T>,
27*bb4ee6a4SAndroid Build Coastguard Worker }
28*bb4ee6a4SAndroid Build Coastguard Worker 
29*bb4ee6a4SAndroid Build Coastguard Worker impl<T> EventQueue<T> {
30*bb4ee6a4SAndroid Build Coastguard Worker     /// Create a new event queue.
new() -> base::Result<Self>31*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new() -> base::Result<Self> {
32*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Self {
33*bb4ee6a4SAndroid Build Coastguard Worker             // Use semaphore semantics so `eventfd` can be `read` as many times as it has been
34*bb4ee6a4SAndroid Build Coastguard Worker             // `write`n to without blocking.
35*bb4ee6a4SAndroid Build Coastguard Worker             event: Event::new()?,
36*bb4ee6a4SAndroid Build Coastguard Worker             pending_events: Default::default(),
37*bb4ee6a4SAndroid Build Coastguard Worker         })
38*bb4ee6a4SAndroid Build Coastguard Worker     }
39*bb4ee6a4SAndroid Build Coastguard Worker 
40*bb4ee6a4SAndroid Build Coastguard Worker     /// Add `event` to the queue.
queue_event(&mut self, event: T) -> base::Result<()>41*bb4ee6a4SAndroid Build Coastguard Worker     pub fn queue_event(&mut self, event: T) -> base::Result<()> {
42*bb4ee6a4SAndroid Build Coastguard Worker         self.pending_events.push_back(event);
43*bb4ee6a4SAndroid Build Coastguard Worker         self.event.write_count(1)?;
44*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
45*bb4ee6a4SAndroid Build Coastguard Worker     }
46*bb4ee6a4SAndroid Build Coastguard Worker 
47*bb4ee6a4SAndroid Build Coastguard Worker     /// Read the next event, blocking until an event becomes available.
dequeue_event(&mut self) -> base::Result<T>48*bb4ee6a4SAndroid Build Coastguard Worker     pub fn dequeue_event(&mut self) -> base::Result<T> {
49*bb4ee6a4SAndroid Build Coastguard Worker         // Wait until at least one event is written, if necessary.
50*bb4ee6a4SAndroid Build Coastguard Worker         let cpt = self.event.read_count()?;
51*bb4ee6a4SAndroid Build Coastguard Worker         let event = match self.pending_events.pop_front() {
52*bb4ee6a4SAndroid Build Coastguard Worker             Some(event) => event,
53*bb4ee6a4SAndroid Build Coastguard Worker             None => panic!("event signaled but no pending event - this is a bug."),
54*bb4ee6a4SAndroid Build Coastguard Worker         };
55*bb4ee6a4SAndroid Build Coastguard Worker         // If we have more than one event pending, write the remainder back into the event so it
56*bb4ee6a4SAndroid Build Coastguard Worker         // keeps signalling.
57*bb4ee6a4SAndroid Build Coastguard Worker         if cpt > 1 {
58*bb4ee6a4SAndroid Build Coastguard Worker             self.event.write_count(cpt - 1)?;
59*bb4ee6a4SAndroid Build Coastguard Worker         }
60*bb4ee6a4SAndroid Build Coastguard Worker 
61*bb4ee6a4SAndroid Build Coastguard Worker         Ok(event)
62*bb4ee6a4SAndroid Build Coastguard Worker     }
63*bb4ee6a4SAndroid Build Coastguard Worker 
64*bb4ee6a4SAndroid Build Coastguard Worker     /// Remove all the posted events for which `predicate` returns `false`.
retain<P: FnMut(&T) -> bool>(&mut self, predicate: P)65*bb4ee6a4SAndroid Build Coastguard Worker     pub fn retain<P: FnMut(&T) -> bool>(&mut self, predicate: P) {
66*bb4ee6a4SAndroid Build Coastguard Worker         if !self.pending_events.is_empty() {
67*bb4ee6a4SAndroid Build Coastguard Worker             let _ = self
68*bb4ee6a4SAndroid Build Coastguard Worker                 .event
69*bb4ee6a4SAndroid Build Coastguard Worker                 .wait_timeout(Duration::from_millis(0))
70*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("wait_timeout failure");
71*bb4ee6a4SAndroid Build Coastguard Worker         }
72*bb4ee6a4SAndroid Build Coastguard Worker 
73*bb4ee6a4SAndroid Build Coastguard Worker         self.pending_events.retain(predicate);
74*bb4ee6a4SAndroid Build Coastguard Worker 
75*bb4ee6a4SAndroid Build Coastguard Worker         let num_pending_events = self.pending_events.len();
76*bb4ee6a4SAndroid Build Coastguard Worker         if num_pending_events > 0 {
77*bb4ee6a4SAndroid Build Coastguard Worker             self.event
78*bb4ee6a4SAndroid Build Coastguard Worker                 .write_count(num_pending_events as u64)
79*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("write failure");
80*bb4ee6a4SAndroid Build Coastguard Worker         }
81*bb4ee6a4SAndroid Build Coastguard Worker     }
82*bb4ee6a4SAndroid Build Coastguard Worker 
83*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns the number of events currently pending on this queue, i.e. the number of times
84*bb4ee6a4SAndroid Build Coastguard Worker     /// `dequeue_event` can be called without blocking.
85*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(test)]
len(&self) -> usize86*bb4ee6a4SAndroid Build Coastguard Worker     pub fn len(&self) -> usize {
87*bb4ee6a4SAndroid Build Coastguard Worker         self.pending_events.len()
88*bb4ee6a4SAndroid Build Coastguard Worker     }
89*bb4ee6a4SAndroid Build Coastguard Worker }
90*bb4ee6a4SAndroid Build Coastguard Worker 
91*bb4ee6a4SAndroid Build Coastguard Worker impl<T> AsRawDescriptor for EventQueue<T> {
as_raw_descriptor(&self) -> base::RawDescriptor92*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> base::RawDescriptor {
93*bb4ee6a4SAndroid Build Coastguard Worker         self.event.as_raw_descriptor()
94*bb4ee6a4SAndroid Build Coastguard Worker     }
95*bb4ee6a4SAndroid Build Coastguard Worker }
96*bb4ee6a4SAndroid Build Coastguard Worker 
97*bb4ee6a4SAndroid Build Coastguard Worker /// An `EventQueue` that is `Sync`, `Send`, and non-mut - i.e. that can easily be passed across
98*bb4ee6a4SAndroid Build Coastguard Worker /// threads and wrapped into a `Rc` or `Arc`.
99*bb4ee6a4SAndroid Build Coastguard Worker pub struct SyncEventQueue<T>(Mutex<EventQueue<T>>);
100*bb4ee6a4SAndroid Build Coastguard Worker 
101*bb4ee6a4SAndroid Build Coastguard Worker impl<T> From<EventQueue<T>> for SyncEventQueue<T> {
from(queue: EventQueue<T>) -> Self102*bb4ee6a4SAndroid Build Coastguard Worker     fn from(queue: EventQueue<T>) -> Self {
103*bb4ee6a4SAndroid Build Coastguard Worker         Self(Mutex::new(queue))
104*bb4ee6a4SAndroid Build Coastguard Worker     }
105*bb4ee6a4SAndroid Build Coastguard Worker }
106*bb4ee6a4SAndroid Build Coastguard Worker 
107*bb4ee6a4SAndroid Build Coastguard Worker impl<T> SyncEventQueue<T> {
108*bb4ee6a4SAndroid Build Coastguard Worker     /// Add `event` to the queue.
queue_event(&self, event: T) -> base::Result<()>109*bb4ee6a4SAndroid Build Coastguard Worker     pub fn queue_event(&self, event: T) -> base::Result<()> {
110*bb4ee6a4SAndroid Build Coastguard Worker         self.0.lock().queue_event(event)
111*bb4ee6a4SAndroid Build Coastguard Worker     }
112*bb4ee6a4SAndroid Build Coastguard Worker 
113*bb4ee6a4SAndroid Build Coastguard Worker     /// Read the next event, blocking until an event becomes available.
dequeue_event(&self) -> base::Result<T>114*bb4ee6a4SAndroid Build Coastguard Worker     pub fn dequeue_event(&self) -> base::Result<T> {
115*bb4ee6a4SAndroid Build Coastguard Worker         self.0.lock().dequeue_event()
116*bb4ee6a4SAndroid Build Coastguard Worker     }
117*bb4ee6a4SAndroid Build Coastguard Worker 
118*bb4ee6a4SAndroid Build Coastguard Worker     /// Remove all the posted events for which `predicate` returns `false`.
retain<P: FnMut(&T) -> bool>(&self, predicate: P)119*bb4ee6a4SAndroid Build Coastguard Worker     pub fn retain<P: FnMut(&T) -> bool>(&self, predicate: P) {
120*bb4ee6a4SAndroid Build Coastguard Worker         self.0.lock().retain(predicate)
121*bb4ee6a4SAndroid Build Coastguard Worker     }
122*bb4ee6a4SAndroid Build Coastguard Worker 
123*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns the number of events currently pending on this queue, i.e. the number of times
124*bb4ee6a4SAndroid Build Coastguard Worker     /// `dequeue_event` can be called without blocking.
125*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(test)]
len(&self) -> usize126*bb4ee6a4SAndroid Build Coastguard Worker     pub fn len(&self) -> usize {
127*bb4ee6a4SAndroid Build Coastguard Worker         self.0.lock().len()
128*bb4ee6a4SAndroid Build Coastguard Worker     }
129*bb4ee6a4SAndroid Build Coastguard Worker }
130*bb4ee6a4SAndroid Build Coastguard Worker 
131*bb4ee6a4SAndroid Build Coastguard Worker impl<T> AsRawDescriptor for SyncEventQueue<T> {
as_raw_descriptor(&self) -> base::RawDescriptor132*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> base::RawDescriptor {
133*bb4ee6a4SAndroid Build Coastguard Worker         self.0.lock().as_raw_descriptor()
134*bb4ee6a4SAndroid Build Coastguard Worker     }
135*bb4ee6a4SAndroid Build Coastguard Worker }
136*bb4ee6a4SAndroid Build Coastguard Worker 
137*bb4ee6a4SAndroid Build Coastguard Worker /// Queue of all the output buffers provided by crosvm.
138*bb4ee6a4SAndroid Build Coastguard Worker pub struct OutputQueue {
139*bb4ee6a4SAndroid Build Coastguard Worker     // Max number of output buffers that can be imported into this queue.
140*bb4ee6a4SAndroid Build Coastguard Worker     num_buffers: usize,
141*bb4ee6a4SAndroid Build Coastguard Worker     // Maps picture IDs to the corresponding guest resource.
142*bb4ee6a4SAndroid Build Coastguard Worker     buffers: BTreeMap<u32, GuestResource>,
143*bb4ee6a4SAndroid Build Coastguard Worker     // Picture IDs of output buffers we can write into.
144*bb4ee6a4SAndroid Build Coastguard Worker     ready_buffers: VecDeque<u32>,
145*bb4ee6a4SAndroid Build Coastguard Worker }
146*bb4ee6a4SAndroid Build Coastguard Worker 
147*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, ThisError)]
148*bb4ee6a4SAndroid Build Coastguard Worker pub enum OutputBufferImportError {
149*bb4ee6a4SAndroid Build Coastguard Worker     #[error("maximum number of imported buffers ({0}) already reached")]
150*bb4ee6a4SAndroid Build Coastguard Worker     MaxBuffersReached(usize),
151*bb4ee6a4SAndroid Build Coastguard Worker     #[error("a buffer with picture ID {0} is already imported")]
152*bb4ee6a4SAndroid Build Coastguard Worker     AlreadyImported(u32),
153*bb4ee6a4SAndroid Build Coastguard Worker }
154*bb4ee6a4SAndroid Build Coastguard Worker 
155*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, ThisError)]
156*bb4ee6a4SAndroid Build Coastguard Worker pub enum OutputBufferReuseError {
157*bb4ee6a4SAndroid Build Coastguard Worker     #[error("no buffer with picture ID {0} is imported at the moment")]
158*bb4ee6a4SAndroid Build Coastguard Worker     NotYetImported(u32),
159*bb4ee6a4SAndroid Build Coastguard Worker     #[error("buffer with picture ID {0} is already ready for use")]
160*bb4ee6a4SAndroid Build Coastguard Worker     AlreadyUsed(u32),
161*bb4ee6a4SAndroid Build Coastguard Worker }
162*bb4ee6a4SAndroid Build Coastguard Worker 
163*bb4ee6a4SAndroid Build Coastguard Worker impl OutputQueue {
164*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a new output queue capable of containing `num_buffers` buffers.
new(num_buffers: usize) -> Self165*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(num_buffers: usize) -> Self {
166*bb4ee6a4SAndroid Build Coastguard Worker         Self {
167*bb4ee6a4SAndroid Build Coastguard Worker             num_buffers,
168*bb4ee6a4SAndroid Build Coastguard Worker             buffers: Default::default(),
169*bb4ee6a4SAndroid Build Coastguard Worker             ready_buffers: Default::default(),
170*bb4ee6a4SAndroid Build Coastguard Worker         }
171*bb4ee6a4SAndroid Build Coastguard Worker     }
172*bb4ee6a4SAndroid Build Coastguard Worker 
173*bb4ee6a4SAndroid Build Coastguard Worker     /// Import a buffer, i.e. associate the buffer's `resource` to a given `picture_buffer_id`, and
174*bb4ee6a4SAndroid Build Coastguard Worker     /// make the buffer ready for use.
175*bb4ee6a4SAndroid Build Coastguard Worker     ///
176*bb4ee6a4SAndroid Build Coastguard Worker     /// A buffer with a given `picture_buffer_id` can only be imported once.
import_buffer( &mut self, picture_buffer_id: u32, resource: GuestResource, ) -> Result<(), OutputBufferImportError>177*bb4ee6a4SAndroid Build Coastguard Worker     pub fn import_buffer(
178*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
179*bb4ee6a4SAndroid Build Coastguard Worker         picture_buffer_id: u32,
180*bb4ee6a4SAndroid Build Coastguard Worker         resource: GuestResource,
181*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<(), OutputBufferImportError> {
182*bb4ee6a4SAndroid Build Coastguard Worker         if self.buffers.len() >= self.num_buffers {
183*bb4ee6a4SAndroid Build Coastguard Worker             return Err(OutputBufferImportError::MaxBuffersReached(self.num_buffers));
184*bb4ee6a4SAndroid Build Coastguard Worker         }
185*bb4ee6a4SAndroid Build Coastguard Worker 
186*bb4ee6a4SAndroid Build Coastguard Worker         match self.buffers.entry(picture_buffer_id) {
187*bb4ee6a4SAndroid Build Coastguard Worker             Entry::Vacant(o) => {
188*bb4ee6a4SAndroid Build Coastguard Worker                 o.insert(resource);
189*bb4ee6a4SAndroid Build Coastguard Worker             }
190*bb4ee6a4SAndroid Build Coastguard Worker             Entry::Occupied(_) => {
191*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(OutputBufferImportError::AlreadyImported(picture_buffer_id));
192*bb4ee6a4SAndroid Build Coastguard Worker             }
193*bb4ee6a4SAndroid Build Coastguard Worker         }
194*bb4ee6a4SAndroid Build Coastguard Worker 
195*bb4ee6a4SAndroid Build Coastguard Worker         self.ready_buffers.push_back(picture_buffer_id);
196*bb4ee6a4SAndroid Build Coastguard Worker 
197*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
198*bb4ee6a4SAndroid Build Coastguard Worker     }
199*bb4ee6a4SAndroid Build Coastguard Worker 
200*bb4ee6a4SAndroid Build Coastguard Worker     /// Mark the previously-imported buffer with ID `picture_buffer_id` as ready for being used.
reuse_buffer(&mut self, picture_buffer_id: u32) -> Result<(), OutputBufferReuseError>201*bb4ee6a4SAndroid Build Coastguard Worker     pub fn reuse_buffer(&mut self, picture_buffer_id: u32) -> Result<(), OutputBufferReuseError> {
202*bb4ee6a4SAndroid Build Coastguard Worker         if !self.buffers.contains_key(&picture_buffer_id) {
203*bb4ee6a4SAndroid Build Coastguard Worker             return Err(OutputBufferReuseError::NotYetImported(picture_buffer_id));
204*bb4ee6a4SAndroid Build Coastguard Worker         }
205*bb4ee6a4SAndroid Build Coastguard Worker 
206*bb4ee6a4SAndroid Build Coastguard Worker         if self.ready_buffers.contains(&picture_buffer_id) {
207*bb4ee6a4SAndroid Build Coastguard Worker             return Err(OutputBufferReuseError::AlreadyUsed(picture_buffer_id));
208*bb4ee6a4SAndroid Build Coastguard Worker         }
209*bb4ee6a4SAndroid Build Coastguard Worker 
210*bb4ee6a4SAndroid Build Coastguard Worker         self.ready_buffers.push_back(picture_buffer_id);
211*bb4ee6a4SAndroid Build Coastguard Worker 
212*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
213*bb4ee6a4SAndroid Build Coastguard Worker     }
214*bb4ee6a4SAndroid Build Coastguard Worker 
215*bb4ee6a4SAndroid Build Coastguard Worker     /// Get a buffer ready to be decoded into, if any is available.
try_get_ready_buffer(&mut self) -> Option<(u32, &mut GuestResource)>216*bb4ee6a4SAndroid Build Coastguard Worker     pub fn try_get_ready_buffer(&mut self) -> Option<(u32, &mut GuestResource)> {
217*bb4ee6a4SAndroid Build Coastguard Worker         let picture_buffer_id = self.ready_buffers.pop_front()?;
218*bb4ee6a4SAndroid Build Coastguard Worker         // Unwrapping is safe here because our interface guarantees that ids in `ready_buffers` are
219*bb4ee6a4SAndroid Build Coastguard Worker         // valid keys for `buffers`.
220*bb4ee6a4SAndroid Build Coastguard Worker         Some((
221*bb4ee6a4SAndroid Build Coastguard Worker             picture_buffer_id,
222*bb4ee6a4SAndroid Build Coastguard Worker             self.buffers
223*bb4ee6a4SAndroid Build Coastguard Worker                 .get_mut(&picture_buffer_id)
224*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("expected buffer not present in queue"),
225*bb4ee6a4SAndroid Build Coastguard Worker         ))
226*bb4ee6a4SAndroid Build Coastguard Worker     }
227*bb4ee6a4SAndroid Build Coastguard Worker 
clear_ready_buffers(&mut self)228*bb4ee6a4SAndroid Build Coastguard Worker     pub fn clear_ready_buffers(&mut self) {
229*bb4ee6a4SAndroid Build Coastguard Worker         self.ready_buffers.clear();
230*bb4ee6a4SAndroid Build Coastguard Worker     }
231*bb4ee6a4SAndroid Build Coastguard Worker }
232*bb4ee6a4SAndroid Build Coastguard Worker 
233*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
234*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
235*bb4ee6a4SAndroid Build Coastguard Worker     use std::time::Duration;
236*bb4ee6a4SAndroid Build Coastguard Worker 
237*bb4ee6a4SAndroid Build Coastguard Worker     use base::EventToken;
238*bb4ee6a4SAndroid Build Coastguard Worker     use base::WaitContext;
239*bb4ee6a4SAndroid Build Coastguard Worker 
240*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
241*bb4ee6a4SAndroid Build Coastguard Worker     use crate::virtio::video::error::VideoError;
242*bb4ee6a4SAndroid Build Coastguard Worker     use crate::virtio::video::error::VideoResult;
243*bb4ee6a4SAndroid Build Coastguard Worker     use crate::virtio::video::format::Rect;
244*bb4ee6a4SAndroid Build Coastguard Worker 
245*bb4ee6a4SAndroid Build Coastguard Worker     /// This is the same as DecoderEvent but copied here so that the test can be compiled
246*bb4ee6a4SAndroid Build Coastguard Worker     /// without depending on the "video-decoder" feature.
247*bb4ee6a4SAndroid Build Coastguard Worker     #[derive(Debug)]
248*bb4ee6a4SAndroid Build Coastguard Worker     pub enum TestEvent {
249*bb4ee6a4SAndroid Build Coastguard Worker         #[allow(dead_code)]
250*bb4ee6a4SAndroid Build Coastguard Worker         ProvidePictureBuffers {
251*bb4ee6a4SAndroid Build Coastguard Worker             min_num_buffers: u32,
252*bb4ee6a4SAndroid Build Coastguard Worker             width: i32,
253*bb4ee6a4SAndroid Build Coastguard Worker             height: i32,
254*bb4ee6a4SAndroid Build Coastguard Worker             visible_rect: Rect,
255*bb4ee6a4SAndroid Build Coastguard Worker         },
256*bb4ee6a4SAndroid Build Coastguard Worker         PictureReady {
257*bb4ee6a4SAndroid Build Coastguard Worker             picture_buffer_id: i32,
258*bb4ee6a4SAndroid Build Coastguard Worker             timestamp: u64,
259*bb4ee6a4SAndroid Build Coastguard Worker             visible_rect: Rect,
260*bb4ee6a4SAndroid Build Coastguard Worker         },
261*bb4ee6a4SAndroid Build Coastguard Worker         NotifyEndOfBitstreamBuffer(u32),
262*bb4ee6a4SAndroid Build Coastguard Worker         #[allow(dead_code)]
263*bb4ee6a4SAndroid Build Coastguard Worker         NotifyError(VideoError),
264*bb4ee6a4SAndroid Build Coastguard Worker         #[allow(dead_code)]
265*bb4ee6a4SAndroid Build Coastguard Worker         FlushCompleted(VideoResult<()>),
266*bb4ee6a4SAndroid Build Coastguard Worker         #[allow(dead_code)]
267*bb4ee6a4SAndroid Build Coastguard Worker         ResetCompleted(VideoResult<()>),
268*bb4ee6a4SAndroid Build Coastguard Worker     }
269*bb4ee6a4SAndroid Build Coastguard Worker 
270*bb4ee6a4SAndroid Build Coastguard Worker     /// Test basic queue/dequeue functionality of `EventQueue`.
271*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
event_queue()272*bb4ee6a4SAndroid Build Coastguard Worker     fn event_queue() {
273*bb4ee6a4SAndroid Build Coastguard Worker         let mut event_queue = EventQueue::new().unwrap();
274*bb4ee6a4SAndroid Build Coastguard Worker 
275*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
276*bb4ee6a4SAndroid Build Coastguard Worker             event_queue.queue_event(TestEvent::NotifyEndOfBitstreamBuffer(1)),
277*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
278*bb4ee6a4SAndroid Build Coastguard Worker         );
279*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(event_queue.len(), 1);
280*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
281*bb4ee6a4SAndroid Build Coastguard Worker             event_queue.queue_event(TestEvent::PictureReady {
282*bb4ee6a4SAndroid Build Coastguard Worker                 picture_buffer_id: 0,
283*bb4ee6a4SAndroid Build Coastguard Worker                 timestamp: 42,
284*bb4ee6a4SAndroid Build Coastguard Worker                 visible_rect: Rect {
285*bb4ee6a4SAndroid Build Coastguard Worker                     left: 0,
286*bb4ee6a4SAndroid Build Coastguard Worker                     top: 0,
287*bb4ee6a4SAndroid Build Coastguard Worker                     right: 320,
288*bb4ee6a4SAndroid Build Coastguard Worker                     bottom: 240,
289*bb4ee6a4SAndroid Build Coastguard Worker                 },
290*bb4ee6a4SAndroid Build Coastguard Worker             }),
291*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
292*bb4ee6a4SAndroid Build Coastguard Worker         );
293*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(event_queue.len(), 2);
294*bb4ee6a4SAndroid Build Coastguard Worker 
295*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(
296*bb4ee6a4SAndroid Build Coastguard Worker             event_queue.dequeue_event(),
297*bb4ee6a4SAndroid Build Coastguard Worker             Ok(TestEvent::NotifyEndOfBitstreamBuffer(1))
298*bb4ee6a4SAndroid Build Coastguard Worker         ));
299*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(event_queue.len(), 1);
300*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(
301*bb4ee6a4SAndroid Build Coastguard Worker             event_queue.dequeue_event(),
302*bb4ee6a4SAndroid Build Coastguard Worker             Ok(TestEvent::PictureReady {
303*bb4ee6a4SAndroid Build Coastguard Worker                 picture_buffer_id: 0,
304*bb4ee6a4SAndroid Build Coastguard Worker                 timestamp: 42,
305*bb4ee6a4SAndroid Build Coastguard Worker                 visible_rect: Rect {
306*bb4ee6a4SAndroid Build Coastguard Worker                     left: 0,
307*bb4ee6a4SAndroid Build Coastguard Worker                     top: 0,
308*bb4ee6a4SAndroid Build Coastguard Worker                     right: 320,
309*bb4ee6a4SAndroid Build Coastguard Worker                     bottom: 240,
310*bb4ee6a4SAndroid Build Coastguard Worker                 }
311*bb4ee6a4SAndroid Build Coastguard Worker             })
312*bb4ee6a4SAndroid Build Coastguard Worker         ));
313*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(event_queue.len(), 0);
314*bb4ee6a4SAndroid Build Coastguard Worker     }
315*bb4ee6a4SAndroid Build Coastguard Worker 
316*bb4ee6a4SAndroid Build Coastguard Worker     /// Test polling of `TestEventQueue`'s `event_pipe`.
317*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
decoder_event_queue_polling()318*bb4ee6a4SAndroid Build Coastguard Worker     fn decoder_event_queue_polling() {
319*bb4ee6a4SAndroid Build Coastguard Worker         #[derive(EventToken)]
320*bb4ee6a4SAndroid Build Coastguard Worker         enum Token {
321*bb4ee6a4SAndroid Build Coastguard Worker             Event,
322*bb4ee6a4SAndroid Build Coastguard Worker         }
323*bb4ee6a4SAndroid Build Coastguard Worker 
324*bb4ee6a4SAndroid Build Coastguard Worker         let mut event_queue = EventQueue::new().unwrap();
325*bb4ee6a4SAndroid Build Coastguard Worker         let wait_context = WaitContext::build_with(&[(&event_queue, Token::Event)]).unwrap();
326*bb4ee6a4SAndroid Build Coastguard Worker 
327*bb4ee6a4SAndroid Build Coastguard Worker         // The queue is empty, so `event_pipe` should not signal.
328*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(wait_context.wait_timeout(Duration::ZERO).unwrap().len(), 0);
329*bb4ee6a4SAndroid Build Coastguard Worker 
330*bb4ee6a4SAndroid Build Coastguard Worker         // `event_pipe` should signal as long as the queue is not empty.
331*bb4ee6a4SAndroid Build Coastguard Worker         event_queue
332*bb4ee6a4SAndroid Build Coastguard Worker             .queue_event(TestEvent::NotifyEndOfBitstreamBuffer(1))
333*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
334*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(wait_context.wait_timeout(Duration::ZERO).unwrap().len(), 1);
335*bb4ee6a4SAndroid Build Coastguard Worker         event_queue
336*bb4ee6a4SAndroid Build Coastguard Worker             .queue_event(TestEvent::NotifyEndOfBitstreamBuffer(2))
337*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
338*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(wait_context.wait_timeout(Duration::ZERO).unwrap().len(), 1);
339*bb4ee6a4SAndroid Build Coastguard Worker         event_queue
340*bb4ee6a4SAndroid Build Coastguard Worker             .queue_event(TestEvent::NotifyEndOfBitstreamBuffer(3))
341*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
342*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(wait_context.wait_timeout(Duration::ZERO).unwrap().len(), 1);
343*bb4ee6a4SAndroid Build Coastguard Worker 
344*bb4ee6a4SAndroid Build Coastguard Worker         event_queue.dequeue_event().unwrap();
345*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(wait_context.wait_timeout(Duration::ZERO).unwrap().len(), 1);
346*bb4ee6a4SAndroid Build Coastguard Worker         event_queue.dequeue_event().unwrap();
347*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(wait_context.wait_timeout(Duration::ZERO).unwrap().len(), 1);
348*bb4ee6a4SAndroid Build Coastguard Worker         event_queue.dequeue_event().unwrap();
349*bb4ee6a4SAndroid Build Coastguard Worker 
350*bb4ee6a4SAndroid Build Coastguard Worker         // The queue is empty again, so `event_pipe` should not signal.
351*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(wait_context.wait_timeout(Duration::ZERO).unwrap().len(), 0);
352*bb4ee6a4SAndroid Build Coastguard Worker     }
353*bb4ee6a4SAndroid Build Coastguard Worker }
354