1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright 2020 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Definition of the trait `Device` that each backend video device must implement.

use base::EventToken;
use base::WaitContext;

use crate::virtio::video::async_cmd_desc_map::AsyncCmdDescMap;
use crate::virtio::video::command::QueueType;
use crate::virtio::video::command::VideoCmd;
use crate::virtio::video::error::*;
use crate::virtio::video::event::VideoEvt;
use crate::virtio::video::response;

#[derive(EventToken, Debug)]
pub enum Token {
    CmdQueue,
    EventQueue,
    Event {
        id: u32,
    },
    /// Signals that processing of a given buffer has completed. Used for cases where the guest CPU
    /// may access the buffer, in which case it cannot be handed over to the guest until operations
    /// on it have completed.
    BufferBarrier {
        id: u32,
    },
    Kill,
    InterruptResample,
}

/// A tag for commands being processed asynchronously in the back-end device.
///
/// TODO(b/149720783): Remove this enum by using async primitives.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub enum AsyncCmdTag {
    Queue {
        stream_id: u32,
        queue_type: QueueType,
        resource_id: u32,
    },
    Drain {
        stream_id: u32,
    },
    Clear {
        stream_id: u32,
        queue_type: QueueType,
    },
    // Used exclusively by the encoder.
    #[cfg(feature = "video-encoder")]
    GetParams {
        stream_id: u32,
        queue_type: QueueType,
    },
}

/// A return value when a command from the guest is processed.
#[derive(Debug)]
pub enum VideoCmdResponseType {
    /// The response for a synchronous command. This can be returned to the guest immediately via
    /// command virtqueue.
    Sync(response::CmdResponse),
    /// The tag for an asynchronous command that the back-end device will complete.
    /// Once the command is completed, its result will be sent with the same tag.
    /// This can be seen as a poor man's future pattern.
    Async(AsyncCmdTag),
}

/// A response for an asynchronous command that was enqueued through `process_cmd` before.
/// The `tag` must be same as the one returned when the command was enqueued.
#[derive(Debug)]
pub struct AsyncCmdResponse {
    pub tag: AsyncCmdTag,
    pub response: VideoResult<response::CmdResponse>,
}

impl AsyncCmdResponse {
    pub fn from_response(tag: AsyncCmdTag, response: response::CmdResponse) -> Self {
        Self {
            tag,
            response: Ok(response),
        }
    }

    pub fn from_error(tag: AsyncCmdTag, error: VideoError) -> Self {
        Self {
            tag,
            response: Err(error),
        }
    }
}

/// A return value when processing a event the back-end device sent.
#[derive(Debug)]
pub enum VideoEvtResponseType {
    /// The responses for an asynchronous command.
    AsyncCmd(AsyncCmdResponse),
    /// The event that happened in the back-end device.
    Event(VideoEvt),
}

pub trait Device {
    /// Processes a virtio-video command.
    /// If the command expects a synchronous response, it returns a response as
    /// `VideoCmdResponseType::Sync`. Otherwise, it returns a name of the descriptor chain that
    /// will be used when a response is prepared. Implementations of this method is passed a
    /// WaitContext object which can be used to add or remove descriptors to wait on. It is
    /// expected that only Token::Event items would be added. When a Token::Event event arrives,
    /// process_event() will be invoked.
    ///
    /// TODO(b/149720783): Make this an async function.
    fn process_cmd(
        &mut self,
        cmd: VideoCmd,
        wait_ctx: &WaitContext<Token>,
    ) -> (
        VideoCmdResponseType,
        Option<(u32, Vec<VideoEvtResponseType>)>,
    );

    /// Processes an available `Token::Event` event and returns a list of `VideoEvtResponseType`
    /// responses. It returns None if an invalid event comes.
    /// For responses to be sent via command queue, the return type is
    /// `VideoEvtResponseType::AsyncCmd`. For responses to be sent via event queue, the return
    /// type is `VideoEvtResponseType::Event`.
    ///
    /// TODO(b/149720783): Make this an async function.
    fn process_event(
        &mut self,
        desc_map: &mut AsyncCmdDescMap,
        stream_id: u32,
        wait_ctx: &WaitContext<Token>,
    ) -> Option<Vec<VideoEvtResponseType>>;

    /// Processes a `Token::BufferBarrier` event and returns a list of `VideoEvtResponseType`
    /// responses. Only needs to be implemented for devices that adds `Token::BufferBarrier` tokens
    /// to the wait context.
    fn process_buffer_barrier(
        &mut self,
        _stream_id: u32,
        _wait_ctx: &WaitContext<Token>,
    ) -> Option<Vec<VideoEvtResponseType>> {
        None
    }
}