• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #![allow(dead_code)]
6 #![allow(non_camel_case_types)]
7 
8 use std::cmp::min;
9 use std::convert::From;
10 use std::fmt::{self, Display};
11 use std::io::{self, Write};
12 use std::marker::PhantomData;
13 use std::mem::{size_of, size_of_val};
14 use std::str::from_utf8;
15 
16 use super::super::DescriptorError;
17 use super::{Reader, Writer};
18 use base::Error as SysError;
19 use base::{ExternalMappingError, TubeError};
20 use data_model::{DataInit, Le32, Le64};
21 use gpu_display::GpuDisplayError;
22 use rutabaga_gfx::RutabagaError;
23 
24 use crate::virtio::gpu::udmabuf::UdmabufError;
25 
26 pub const VIRTIO_GPU_F_VIRGL: u32 = 0;
27 pub const VIRTIO_GPU_F_EDID: u32 = 1;
28 pub const VIRTIO_GPU_F_RESOURCE_UUID: u32 = 2;
29 pub const VIRTIO_GPU_F_RESOURCE_BLOB: u32 = 3;
30 /* The following capabilities are not upstreamed. */
31 pub const VIRTIO_GPU_F_CONTEXT_INIT: u32 = 4;
32 pub const VIRTIO_GPU_F_CREATE_GUEST_HANDLE: u32 = 5;
33 pub const VIRTIO_GPU_F_RESOURCE_SYNC: u32 = 6;
34 
35 pub const VIRTIO_GPU_UNDEFINED: u32 = 0x0;
36 
37 /* 2d commands */
38 pub const VIRTIO_GPU_CMD_GET_DISPLAY_INFO: u32 = 0x100;
39 pub const VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: u32 = 0x101;
40 pub const VIRTIO_GPU_CMD_RESOURCE_UNREF: u32 = 0x102;
41 pub const VIRTIO_GPU_CMD_SET_SCANOUT: u32 = 0x103;
42 pub const VIRTIO_GPU_CMD_RESOURCE_FLUSH: u32 = 0x104;
43 pub const VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: u32 = 0x105;
44 pub const VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING: u32 = 0x106;
45 pub const VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: u32 = 0x107;
46 pub const VIRTIO_GPU_CMD_GET_CAPSET_INFO: u32 = 0x108;
47 pub const VIRTIO_GPU_CMD_GET_CAPSET: u32 = 0x109;
48 pub const VIRTIO_GPU_CMD_GET_EDID: u32 = 0x10a;
49 pub const VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID: u32 = 0x10b;
50 pub const VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB: u32 = 0x10c;
51 pub const VIRTIO_GPU_CMD_SET_SCANOUT_BLOB: u32 = 0x10d;
52 
53 /* 3d commands */
54 pub const VIRTIO_GPU_CMD_CTX_CREATE: u32 = 0x200;
55 pub const VIRTIO_GPU_CMD_CTX_DESTROY: u32 = 0x201;
56 pub const VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE: u32 = 0x202;
57 pub const VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE: u32 = 0x203;
58 pub const VIRTIO_GPU_CMD_RESOURCE_CREATE_3D: u32 = 0x204;
59 pub const VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D: u32 = 0x205;
60 pub const VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D: u32 = 0x206;
61 pub const VIRTIO_GPU_CMD_SUBMIT_3D: u32 = 0x207;
62 pub const VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB: u32 = 0x208;
63 pub const VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB: u32 = 0x209;
64 
65 /* cursor commands */
66 pub const VIRTIO_GPU_CMD_UPDATE_CURSOR: u32 = 0x300;
67 pub const VIRTIO_GPU_CMD_MOVE_CURSOR: u32 = 0x301;
68 
69 /* success responses */
70 pub const VIRTIO_GPU_RESP_OK_NODATA: u32 = 0x1100;
71 pub const VIRTIO_GPU_RESP_OK_DISPLAY_INFO: u32 = 0x1101;
72 pub const VIRTIO_GPU_RESP_OK_CAPSET_INFO: u32 = 0x1102;
73 pub const VIRTIO_GPU_RESP_OK_CAPSET: u32 = 0x1103;
74 pub const VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO: u32 = 0x1104;
75 pub const VIRTIO_GPU_RESP_OK_EDID: u32 = 0x1105;
76 pub const VIRTIO_GPU_RESP_OK_RESOURCE_UUID: u32 = 0x1105;
77 pub const VIRTIO_GPU_RESP_OK_MAP_INFO: u32 = 0x1106;
78 
79 /* error responses */
80 pub const VIRTIO_GPU_RESP_ERR_UNSPEC: u32 = 0x1200;
81 pub const VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY: u32 = 0x1201;
82 pub const VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID: u32 = 0x1202;
83 pub const VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID: u32 = 0x1203;
84 pub const VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID: u32 = 0x1204;
85 pub const VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER: u32 = 0x1205;
86 
87 pub const VIRTIO_GPU_BLOB_MEM_GUEST: u32 = 0x0001;
88 pub const VIRTIO_GPU_BLOB_MEM_HOST3D: u32 = 0x0002;
89 pub const VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST: u32 = 0x0003;
90 
91 pub const VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE: u32 = 0x0001;
92 pub const VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE: u32 = 0x0002;
93 pub const VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE: u32 = 0x0004;
94 /* Create a OS-specific handle from guest memory (not upstreamed). */
95 pub const VIRTIO_GPU_BLOB_FLAG_CREATE_GUEST_HANDLE: u32 = 0x0008;
96 
97 pub const VIRTIO_GPU_SHM_ID_NONE: u8 = 0x0000;
98 pub const VIRTIO_GPU_SHM_ID_HOST_VISIBLE: u8 = 0x0001;
99 
100 /* This matches the limit in udmabuf.c */
101 pub const VIRTIO_GPU_MAX_IOVEC_ENTRIES: u32 = 1024;
102 
virtio_gpu_cmd_str(cmd: u32) -> &'static str103 pub fn virtio_gpu_cmd_str(cmd: u32) -> &'static str {
104     match cmd {
105         VIRTIO_GPU_CMD_GET_DISPLAY_INFO => "VIRTIO_GPU_CMD_GET_DISPLAY_INFO",
106         VIRTIO_GPU_CMD_RESOURCE_CREATE_2D => "VIRTIO_GPU_CMD_RESOURCE_CREATE_2D",
107         VIRTIO_GPU_CMD_RESOURCE_UNREF => "VIRTIO_GPU_CMD_RESOURCE_UNREF",
108         VIRTIO_GPU_CMD_SET_SCANOUT => "VIRTIO_GPU_CMD_SET_SCANOUT",
109         VIRTIO_GPU_CMD_SET_SCANOUT_BLOB => "VIRTIO_GPU_CMD_SET_SCANOUT_BLOB",
110         VIRTIO_GPU_CMD_RESOURCE_FLUSH => "VIRTIO_GPU_CMD_RESOURCE_FLUSH",
111         VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D => "VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D",
112         VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING => "VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING",
113         VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING => "VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING",
114         VIRTIO_GPU_CMD_GET_CAPSET_INFO => "VIRTIO_GPU_CMD_GET_CAPSET_INFO",
115         VIRTIO_GPU_CMD_GET_CAPSET => "VIRTIO_GPU_CMD_GET_CAPSET",
116         VIRTIO_GPU_CMD_GET_EDID => "VIRTIO_GPU_CMD_GET_EDID",
117         VIRTIO_GPU_CMD_CTX_CREATE => "VIRTIO_GPU_CMD_CTX_CREATE",
118         VIRTIO_GPU_CMD_CTX_DESTROY => "VIRTIO_GPU_CMD_CTX_DESTROY",
119         VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE => "VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE",
120         VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE => "VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE",
121         VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID => "VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID",
122         VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB => "VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB",
123         VIRTIO_GPU_CMD_RESOURCE_CREATE_3D => "VIRTIO_GPU_CMD_RESOURCE_CREATE_3D",
124         VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D => "VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D",
125         VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D => "VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D",
126         VIRTIO_GPU_CMD_SUBMIT_3D => "VIRTIO_GPU_CMD_SUBMIT_3D",
127         VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB => "VIRTIO_GPU_RESOURCE_MAP_BLOB",
128         VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB => "VIRTIO_GPU_RESOURCE_UNMAP_BLOB",
129         VIRTIO_GPU_CMD_UPDATE_CURSOR => "VIRTIO_GPU_CMD_UPDATE_CURSOR",
130         VIRTIO_GPU_CMD_MOVE_CURSOR => "VIRTIO_GPU_CMD_MOVE_CURSOR",
131         VIRTIO_GPU_RESP_OK_NODATA => "VIRTIO_GPU_RESP_OK_NODATA",
132         VIRTIO_GPU_RESP_OK_DISPLAY_INFO => "VIRTIO_GPU_RESP_OK_DISPLAY_INFO",
133         VIRTIO_GPU_RESP_OK_CAPSET_INFO => "VIRTIO_GPU_RESP_OK_CAPSET_INFO",
134         VIRTIO_GPU_RESP_OK_CAPSET => "VIRTIO_GPU_RESP_OK_CAPSET",
135         VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO => "VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO",
136         VIRTIO_GPU_RESP_OK_RESOURCE_UUID => "VIRTIO_GPU_RESP_OK_RESOURCE_UUID",
137         VIRTIO_GPU_RESP_OK_MAP_INFO => "VIRTIO_GPU_RESP_OK_MAP_INFO",
138         VIRTIO_GPU_RESP_ERR_UNSPEC => "VIRTIO_GPU_RESP_ERR_UNSPEC",
139         VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY => "VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY",
140         VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID => "VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID",
141         VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID => "VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID",
142         VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID => "VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID",
143         VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER => "VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER",
144         _ => "UNKNOWN",
145     }
146 }
147 
148 pub const VIRTIO_GPU_FLAG_FENCE: u32 = 1 << 0;
149 /* Fence context index info flag not upstreamed. */
150 pub const VIRTIO_GPU_FLAG_INFO_FENCE_CTX_IDX: u32 = 1 << 1;
151 
152 #[derive(Copy, Clone, Debug, Default)]
153 #[repr(C)]
154 pub struct virtio_gpu_ctrl_hdr {
155     pub type_: Le32,
156     pub flags: Le32,
157     pub fence_id: Le64,
158     pub ctx_id: Le32,
159     pub info: Le32,
160 }
161 
162 unsafe impl DataInit for virtio_gpu_ctrl_hdr {}
163 
164 /* data passed in the cursor vq */
165 
166 #[derive(Copy, Clone, Debug, Default)]
167 #[repr(C)]
168 pub struct virtio_gpu_cursor_pos {
169     pub scanout_id: Le32,
170     pub x: Le32,
171     pub y: Le32,
172     pub padding: Le32,
173 }
174 
175 unsafe impl DataInit for virtio_gpu_cursor_pos {}
176 
177 /* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */
178 #[derive(Copy, Clone, Debug, Default)]
179 #[repr(C)]
180 pub struct virtio_gpu_update_cursor {
181     pub hdr: virtio_gpu_ctrl_hdr,
182     pub pos: virtio_gpu_cursor_pos, /* update & move */
183     pub resource_id: Le32,          /* update only */
184     pub hot_x: Le32,                /* update only */
185     pub hot_y: Le32,                /* update only */
186     pub padding: Le32,
187 }
188 
189 unsafe impl DataInit for virtio_gpu_update_cursor {}
190 
191 /* data passed in the control vq, 2d related */
192 
193 #[derive(Copy, Clone, Debug, Default)]
194 #[repr(C)]
195 pub struct virtio_gpu_rect {
196     pub x: Le32,
197     pub y: Le32,
198     pub width: Le32,
199     pub height: Le32,
200 }
201 
202 unsafe impl DataInit for virtio_gpu_rect {}
203 
204 /* VIRTIO_GPU_CMD_RESOURCE_UNREF */
205 #[derive(Copy, Clone, Debug, Default)]
206 #[repr(C)]
207 pub struct virtio_gpu_resource_unref {
208     pub hdr: virtio_gpu_ctrl_hdr,
209     pub resource_id: Le32,
210     pub padding: Le32,
211 }
212 
213 unsafe impl DataInit for virtio_gpu_resource_unref {}
214 
215 /* VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: create a 2d resource with a format */
216 #[derive(Copy, Clone, Debug, Default)]
217 #[repr(C)]
218 pub struct virtio_gpu_resource_create_2d {
219     pub hdr: virtio_gpu_ctrl_hdr,
220     pub resource_id: Le32,
221     pub format: Le32,
222     pub width: Le32,
223     pub height: Le32,
224 }
225 
226 unsafe impl DataInit for virtio_gpu_resource_create_2d {}
227 
228 /* VIRTIO_GPU_CMD_SET_SCANOUT */
229 #[derive(Copy, Clone, Debug, Default)]
230 #[repr(C)]
231 pub struct virtio_gpu_set_scanout {
232     pub hdr: virtio_gpu_ctrl_hdr,
233     pub r: virtio_gpu_rect,
234     pub scanout_id: Le32,
235     pub resource_id: Le32,
236 }
237 
238 unsafe impl DataInit for virtio_gpu_set_scanout {}
239 
240 /* VIRTIO_GPU_CMD_RESOURCE_FLUSH */
241 #[derive(Copy, Clone, Debug, Default)]
242 #[repr(C)]
243 pub struct virtio_gpu_resource_flush {
244     pub hdr: virtio_gpu_ctrl_hdr,
245     pub r: virtio_gpu_rect,
246     pub resource_id: Le32,
247     pub padding: Le32,
248 }
249 
250 unsafe impl DataInit for virtio_gpu_resource_flush {}
251 
252 /* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */
253 #[derive(Copy, Clone, Debug, Default)]
254 #[repr(C)]
255 pub struct virtio_gpu_transfer_to_host_2d {
256     pub hdr: virtio_gpu_ctrl_hdr,
257     pub r: virtio_gpu_rect,
258     pub offset: Le64,
259     pub resource_id: Le32,
260     pub padding: Le32,
261 }
262 
263 unsafe impl DataInit for virtio_gpu_transfer_to_host_2d {}
264 
265 #[derive(Copy, Clone, Debug, Default)]
266 #[repr(C)]
267 pub struct virtio_gpu_mem_entry {
268     pub addr: Le64,
269     pub length: Le32,
270     pub padding: Le32,
271 }
272 
273 unsafe impl DataInit for virtio_gpu_mem_entry {}
274 
275 /* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */
276 #[derive(Copy, Clone, Debug, Default)]
277 #[repr(C)]
278 pub struct virtio_gpu_resource_attach_backing {
279     pub hdr: virtio_gpu_ctrl_hdr,
280     pub resource_id: Le32,
281     pub nr_entries: Le32,
282 }
283 
284 unsafe impl DataInit for virtio_gpu_resource_attach_backing {}
285 
286 /* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */
287 #[derive(Copy, Clone, Debug, Default)]
288 #[repr(C)]
289 pub struct virtio_gpu_resource_detach_backing {
290     pub hdr: virtio_gpu_ctrl_hdr,
291     pub resource_id: Le32,
292     pub padding: Le32,
293 }
294 
295 unsafe impl DataInit for virtio_gpu_resource_detach_backing {}
296 
297 #[derive(Copy, Clone, Debug, Default)]
298 #[repr(C)]
299 pub struct virtio_gpu_display_one {
300     pub r: virtio_gpu_rect,
301     pub enabled: Le32,
302     pub flags: Le32,
303 }
304 
305 unsafe impl DataInit for virtio_gpu_display_one {}
306 
307 /* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */
308 const VIRTIO_GPU_MAX_SCANOUTS: usize = 16;
309 #[derive(Copy, Clone, Debug, Default)]
310 #[repr(C)]
311 pub struct virtio_gpu_resp_display_info {
312     pub hdr: virtio_gpu_ctrl_hdr,
313     pub pmodes: [virtio_gpu_display_one; VIRTIO_GPU_MAX_SCANOUTS],
314 }
315 
316 unsafe impl DataInit for virtio_gpu_resp_display_info {}
317 
318 /* data passed in the control vq, 3d related */
319 
320 #[derive(Copy, Clone, Debug, Default)]
321 #[repr(C)]
322 pub struct virtio_gpu_box {
323     pub x: Le32,
324     pub y: Le32,
325     pub z: Le32,
326     pub w: Le32,
327     pub h: Le32,
328     pub d: Le32,
329 }
330 
331 unsafe impl DataInit for virtio_gpu_box {}
332 
333 /* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D */
334 #[derive(Copy, Clone, Debug, Default)]
335 #[repr(C)]
336 pub struct virtio_gpu_transfer_host_3d {
337     pub hdr: virtio_gpu_ctrl_hdr,
338     pub box_: virtio_gpu_box,
339     pub offset: Le64,
340     pub resource_id: Le32,
341     pub level: Le32,
342     pub stride: Le32,
343     pub layer_stride: Le32,
344 }
345 
346 unsafe impl DataInit for virtio_gpu_transfer_host_3d {}
347 
348 /* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D */
349 pub const VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP: u32 = 1 << 0;
350 #[derive(Copy, Clone, Debug, Default)]
351 #[repr(C)]
352 pub struct virtio_gpu_resource_create_3d {
353     pub hdr: virtio_gpu_ctrl_hdr,
354     pub resource_id: Le32,
355     pub target: Le32,
356     pub format: Le32,
357     pub bind: Le32,
358     pub width: Le32,
359     pub height: Le32,
360     pub depth: Le32,
361     pub array_size: Le32,
362     pub last_level: Le32,
363     pub nr_samples: Le32,
364     pub flags: Le32,
365     pub padding: Le32,
366 }
367 
368 unsafe impl DataInit for virtio_gpu_resource_create_3d {}
369 
370 /* VIRTIO_GPU_CMD_CTX_CREATE (context_init not upstreamed) */
371 pub const VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK: u32 = 1 << 0;
372 #[derive(Copy)]
373 #[repr(C)]
374 pub struct virtio_gpu_ctx_create {
375     pub hdr: virtio_gpu_ctrl_hdr,
376     pub nlen: Le32,
377     pub context_init: Le32,
378     pub debug_name: [u8; 64],
379 }
380 
381 impl Default for virtio_gpu_ctx_create {
default() -> Self382     fn default() -> Self {
383         unsafe { ::std::mem::zeroed() }
384     }
385 }
386 
387 unsafe impl DataInit for virtio_gpu_ctx_create {}
388 
389 impl Clone for virtio_gpu_ctx_create {
clone(&self) -> virtio_gpu_ctx_create390     fn clone(&self) -> virtio_gpu_ctx_create {
391         *self
392     }
393 }
394 
395 impl fmt::Debug for virtio_gpu_ctx_create {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result396     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
397         let debug_name = from_utf8(&self.debug_name[..min(64, self.nlen.to_native() as usize)])
398             .unwrap_or("<invalid>");
399         f.debug_struct("virtio_gpu_ctx_create")
400             .field("hdr", &self.hdr)
401             .field("debug_name", &debug_name)
402             .finish()
403     }
404 }
405 
406 /* VIRTIO_GPU_CMD_CTX_DESTROY */
407 #[derive(Copy, Clone, Debug, Default)]
408 #[repr(C)]
409 pub struct virtio_gpu_ctx_destroy {
410     pub hdr: virtio_gpu_ctrl_hdr,
411 }
412 
413 unsafe impl DataInit for virtio_gpu_ctx_destroy {}
414 
415 /* VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE */
416 #[derive(Copy, Clone, Debug, Default)]
417 #[repr(C)]
418 pub struct virtio_gpu_ctx_resource {
419     pub hdr: virtio_gpu_ctrl_hdr,
420     pub resource_id: Le32,
421     pub padding: Le32,
422 }
423 
424 unsafe impl DataInit for virtio_gpu_ctx_resource {}
425 
426 /* VIRTIO_GPU_CMD_SUBMIT_3D */
427 #[derive(Copy, Clone, Debug, Default)]
428 #[repr(C)]
429 pub struct virtio_gpu_cmd_submit {
430     pub hdr: virtio_gpu_ctrl_hdr,
431     pub size: Le32,
432     pub padding: Le32,
433 }
434 
435 unsafe impl DataInit for virtio_gpu_cmd_submit {}
436 
437 pub const VIRTIO_GPU_CAPSET_VIRGL: u32 = 1;
438 pub const VIRTIO_GPU_CAPSET_VIRGL2: u32 = 2;
439 /* New capset IDs (not upstreamed) */
440 pub const VIRTIO_GPU_CAPSET_GFXSTREAM: u32 = 3;
441 pub const VIRTIO_GPU_CAPSET_VENUS: u32 = 4;
442 pub const VIRTIO_GPU_CAPSET_CROSS_DOMAIN: u32 = 5;
443 
444 /* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
445 #[derive(Copy, Clone, Debug, Default)]
446 #[repr(C)]
447 pub struct virtio_gpu_get_capset_info {
448     pub hdr: virtio_gpu_ctrl_hdr,
449     pub capset_index: Le32,
450     pub padding: Le32,
451 }
452 
453 unsafe impl DataInit for virtio_gpu_get_capset_info {}
454 
455 /* VIRTIO_GPU_RESP_OK_CAPSET_INFO */
456 #[derive(Copy, Clone, Debug, Default)]
457 #[repr(C)]
458 pub struct virtio_gpu_resp_capset_info {
459     pub hdr: virtio_gpu_ctrl_hdr,
460     pub capset_id: Le32,
461     pub capset_max_version: Le32,
462     pub capset_max_size: Le32,
463     pub padding: Le32,
464 }
465 
466 unsafe impl DataInit for virtio_gpu_resp_capset_info {}
467 
468 /* VIRTIO_GPU_CMD_GET_CAPSET */
469 #[derive(Copy, Clone, Debug, Default)]
470 #[repr(C)]
471 pub struct virtio_gpu_get_capset {
472     pub hdr: virtio_gpu_ctrl_hdr,
473     pub capset_id: Le32,
474     pub capset_version: Le32,
475 }
476 
477 unsafe impl DataInit for virtio_gpu_get_capset {}
478 
479 /* VIRTIO_GPU_RESP_OK_CAPSET */
480 #[derive(Copy, Clone, Debug, Default)]
481 #[repr(C)]
482 pub struct virtio_gpu_resp_capset {
483     pub hdr: virtio_gpu_ctrl_hdr,
484     pub capset_data: PhantomData<[u8]>,
485 }
486 
487 unsafe impl DataInit for virtio_gpu_resp_capset {}
488 
489 /* VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO */
490 #[derive(Copy, Clone, Debug, Default)]
491 #[repr(C)]
492 pub struct virtio_gpu_resp_resource_plane_info {
493     pub hdr: virtio_gpu_ctrl_hdr,
494     pub count: Le32,
495     pub padding: Le32,
496     pub format_modifier: Le64,
497     pub strides: [Le32; 4],
498     pub offsets: [Le32; 4],
499 }
500 
501 unsafe impl DataInit for virtio_gpu_resp_resource_plane_info {}
502 
503 pub const PLANE_INFO_MAX_COUNT: usize = 4;
504 
505 pub const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0;
506 
507 #[derive(Copy, Clone, Debug, Default)]
508 #[repr(C)]
509 pub struct virtio_gpu_config {
510     pub events_read: Le32,
511     pub events_clear: Le32,
512     pub num_scanouts: Le32,
513     pub num_capsets: Le32,
514 }
515 
516 unsafe impl DataInit for virtio_gpu_config {}
517 
518 #[derive(Copy, Clone, Debug, Default)]
519 #[repr(C)]
520 pub struct virtio_gpu_resource_create_blob {
521     pub hdr: virtio_gpu_ctrl_hdr,
522     pub resource_id: Le32,
523     pub blob_mem: Le32,
524     pub blob_flags: Le32,
525     pub nr_entries: Le32,
526     pub blob_id: Le64,
527     pub size: Le64,
528 }
529 
530 unsafe impl DataInit for virtio_gpu_resource_create_blob {}
531 
532 #[derive(Copy, Clone, Debug, Default)]
533 #[repr(C)]
534 pub struct virtio_gpu_resource_map_blob {
535     pub hdr: virtio_gpu_ctrl_hdr,
536     pub resource_id: Le32,
537     pub padding: Le32,
538     pub offset: Le64,
539 }
540 
541 unsafe impl DataInit for virtio_gpu_resource_map_blob {}
542 
543 #[derive(Copy, Clone, Debug, Default)]
544 #[repr(C)]
545 pub struct virtio_gpu_resource_unmap_blob {
546     pub hdr: virtio_gpu_ctrl_hdr,
547     pub resource_id: Le32,
548     pub padding: Le32,
549 }
550 
551 unsafe impl DataInit for virtio_gpu_resource_unmap_blob {}
552 
553 #[derive(Copy, Clone, Debug, Default)]
554 #[repr(C)]
555 pub struct virtio_gpu_resp_map_info {
556     pub hdr: virtio_gpu_ctrl_hdr,
557     pub map_info: Le32,
558 }
559 
560 unsafe impl DataInit for virtio_gpu_resp_map_info {}
561 
562 #[derive(Copy, Clone, Debug, Default)]
563 #[repr(C)]
564 pub struct virtio_gpu_resource_assign_uuid {
565     pub hdr: virtio_gpu_ctrl_hdr,
566     pub resource_id: Le32,
567     pub padding: Le32,
568 }
569 
570 unsafe impl DataInit for virtio_gpu_resource_assign_uuid {}
571 
572 #[derive(Copy, Clone, Debug, Default)]
573 #[repr(C)]
574 pub struct virtio_gpu_resp_resource_uuid {
575     pub hdr: virtio_gpu_ctrl_hdr,
576     pub uuid: [u8; 16],
577 }
578 
579 unsafe impl DataInit for virtio_gpu_resp_resource_uuid {}
580 
581 /* VIRTIO_GPU_CMD_SET_SCANOUT_BLOB */
582 #[derive(Copy, Clone, Debug, Default)]
583 #[repr(C)]
584 pub struct virtio_gpu_set_scanout_blob {
585     pub hdr: virtio_gpu_ctrl_hdr,
586     pub r: virtio_gpu_rect,
587     pub scanout_id: Le32,
588     pub resource_id: Le32,
589     pub width: Le32,
590     pub height: Le32,
591     pub format: Le32,
592     pub padding: Le32,
593     pub strides: [Le32; 4],
594     pub offsets: [Le32; 4],
595 }
596 
597 unsafe impl DataInit for virtio_gpu_set_scanout_blob {}
598 
599 /* simple formats for fbcon/X use */
600 pub const VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: u32 = 1;
601 pub const VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: u32 = 2;
602 pub const VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM: u32 = 3;
603 pub const VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM: u32 = 4;
604 pub const VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM: u32 = 67;
605 pub const VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM: u32 = 68;
606 pub const VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM: u32 = 121;
607 pub const VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: u32 = 134;
608 
609 /// A virtio gpu command and associated metadata specific to each command.
610 #[derive(Copy, Clone)]
611 pub enum GpuCommand {
612     GetDisplayInfo(virtio_gpu_ctrl_hdr),
613     ResourceCreate2d(virtio_gpu_resource_create_2d),
614     ResourceUnref(virtio_gpu_resource_unref),
615     SetScanout(virtio_gpu_set_scanout),
616     SetScanoutBlob(virtio_gpu_set_scanout_blob),
617     ResourceFlush(virtio_gpu_resource_flush),
618     TransferToHost2d(virtio_gpu_transfer_to_host_2d),
619     ResourceAttachBacking(virtio_gpu_resource_attach_backing),
620     ResourceDetachBacking(virtio_gpu_resource_detach_backing),
621     GetCapsetInfo(virtio_gpu_get_capset_info),
622     GetCapset(virtio_gpu_get_capset),
623     CtxCreate(virtio_gpu_ctx_create),
624     CtxDestroy(virtio_gpu_ctx_destroy),
625     CtxAttachResource(virtio_gpu_ctx_resource),
626     CtxDetachResource(virtio_gpu_ctx_resource),
627     ResourceCreate3d(virtio_gpu_resource_create_3d),
628     TransferToHost3d(virtio_gpu_transfer_host_3d),
629     TransferFromHost3d(virtio_gpu_transfer_host_3d),
630     CmdSubmit3d(virtio_gpu_cmd_submit),
631     ResourceCreateBlob(virtio_gpu_resource_create_blob),
632     ResourceMapBlob(virtio_gpu_resource_map_blob),
633     ResourceUnmapBlob(virtio_gpu_resource_unmap_blob),
634     UpdateCursor(virtio_gpu_update_cursor),
635     MoveCursor(virtio_gpu_update_cursor),
636     ResourceAssignUuid(virtio_gpu_resource_assign_uuid),
637 }
638 
639 /// An error indicating something went wrong decoding a `GpuCommand`. These correspond to
640 /// `VIRTIO_GPU_CMD_*`.
641 #[derive(Debug)]
642 pub enum GpuCommandDecodeError {
643     /// The command referenced an inaccessible area of memory.
644     Memory(DescriptorError),
645     /// The type of the command was invalid.
646     InvalidType(u32),
647     /// An I/O error occurred.
648     IO(io::Error),
649 }
650 
651 impl Display for GpuCommandDecodeError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result652     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
653         use self::GpuCommandDecodeError::*;
654 
655         match self {
656             Memory(e) => write!(
657                 f,
658                 "command referenced an inaccessible area of memory: {}",
659                 e,
660             ),
661             InvalidType(n) => write!(f, "invalid command type ({})", n),
662             IO(e) => write!(f, "an I/O error occurred: {}", e),
663         }
664     }
665 }
666 
667 impl From<DescriptorError> for GpuCommandDecodeError {
from(e: DescriptorError) -> GpuCommandDecodeError668     fn from(e: DescriptorError) -> GpuCommandDecodeError {
669         GpuCommandDecodeError::Memory(e)
670     }
671 }
672 
673 impl From<io::Error> for GpuCommandDecodeError {
from(e: io::Error) -> GpuCommandDecodeError674     fn from(e: io::Error) -> GpuCommandDecodeError {
675         GpuCommandDecodeError::IO(e)
676     }
677 }
678 
679 impl fmt::Debug for GpuCommand {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result680     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
681         use self::GpuCommand::*;
682         match self {
683             GetDisplayInfo(_info) => f.debug_struct("GetDisplayInfo").finish(),
684             ResourceCreate2d(_info) => f.debug_struct("ResourceCreate2d").finish(),
685             ResourceUnref(_info) => f.debug_struct("ResourceUnref").finish(),
686             SetScanout(_info) => f.debug_struct("SetScanout").finish(),
687             SetScanoutBlob(_info) => f.debug_struct("SetScanoutBlob").finish(),
688             ResourceFlush(_info) => f.debug_struct("ResourceFlush").finish(),
689             TransferToHost2d(_info) => f.debug_struct("TransferToHost2d").finish(),
690             ResourceAttachBacking(_info) => f.debug_struct("ResourceAttachBacking").finish(),
691             ResourceDetachBacking(_info) => f.debug_struct("ResourceDetachBacking").finish(),
692             GetCapsetInfo(_info) => f.debug_struct("GetCapsetInfo").finish(),
693             GetCapset(_info) => f.debug_struct("GetCapset").finish(),
694             CtxCreate(_info) => f.debug_struct("CtxCreate").finish(),
695             CtxDestroy(_info) => f.debug_struct("CtxDestroy").finish(),
696             CtxAttachResource(_info) => f.debug_struct("CtxAttachResource").finish(),
697             CtxDetachResource(_info) => f.debug_struct("CtxDetachResource").finish(),
698             ResourceCreate3d(_info) => f.debug_struct("ResourceCreate3d").finish(),
699             TransferToHost3d(_info) => f.debug_struct("TransferToHost3d").finish(),
700             TransferFromHost3d(_info) => f.debug_struct("TransferFromHost3d").finish(),
701             CmdSubmit3d(_info) => f.debug_struct("CmdSubmit3d").finish(),
702             ResourceCreateBlob(_info) => f.debug_struct("ResourceCreateBlob").finish(),
703             ResourceMapBlob(_info) => f.debug_struct("ResourceMapBlob").finish(),
704             ResourceUnmapBlob(_info) => f.debug_struct("ResourceUnmapBlob").finish(),
705             UpdateCursor(_info) => f.debug_struct("UpdateCursor").finish(),
706             MoveCursor(_info) => f.debug_struct("MoveCursor").finish(),
707             ResourceAssignUuid(_info) => f.debug_struct("ResourceAssignUuid").finish(),
708         }
709     }
710 }
711 
712 impl GpuCommand {
713     /// Decodes a command from the given chunk of memory.
decode(cmd: &mut Reader) -> Result<GpuCommand, GpuCommandDecodeError>714     pub fn decode(cmd: &mut Reader) -> Result<GpuCommand, GpuCommandDecodeError> {
715         use self::GpuCommand::*;
716         let hdr = cmd.clone().read_obj::<virtio_gpu_ctrl_hdr>()?;
717         Ok(match hdr.type_.into() {
718             VIRTIO_GPU_CMD_GET_DISPLAY_INFO => GetDisplayInfo(cmd.read_obj()?),
719             VIRTIO_GPU_CMD_RESOURCE_CREATE_2D => ResourceCreate2d(cmd.read_obj()?),
720             VIRTIO_GPU_CMD_RESOURCE_UNREF => ResourceUnref(cmd.read_obj()?),
721             VIRTIO_GPU_CMD_SET_SCANOUT => SetScanout(cmd.read_obj()?),
722             VIRTIO_GPU_CMD_SET_SCANOUT_BLOB => SetScanoutBlob(cmd.read_obj()?),
723             VIRTIO_GPU_CMD_RESOURCE_FLUSH => ResourceFlush(cmd.read_obj()?),
724             VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D => TransferToHost2d(cmd.read_obj()?),
725             VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING => ResourceAttachBacking(cmd.read_obj()?),
726             VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING => ResourceDetachBacking(cmd.read_obj()?),
727             VIRTIO_GPU_CMD_GET_CAPSET_INFO => GetCapsetInfo(cmd.read_obj()?),
728             VIRTIO_GPU_CMD_GET_CAPSET => GetCapset(cmd.read_obj()?),
729             VIRTIO_GPU_CMD_CTX_CREATE => CtxCreate(cmd.read_obj()?),
730             VIRTIO_GPU_CMD_CTX_DESTROY => CtxDestroy(cmd.read_obj()?),
731             VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE => CtxAttachResource(cmd.read_obj()?),
732             VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE => CtxDetachResource(cmd.read_obj()?),
733             VIRTIO_GPU_CMD_RESOURCE_CREATE_3D => ResourceCreate3d(cmd.read_obj()?),
734             VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D => TransferToHost3d(cmd.read_obj()?),
735             VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D => TransferFromHost3d(cmd.read_obj()?),
736             VIRTIO_GPU_CMD_SUBMIT_3D => CmdSubmit3d(cmd.read_obj()?),
737             VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB => ResourceCreateBlob(cmd.read_obj()?),
738             VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB => ResourceMapBlob(cmd.read_obj()?),
739             VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB => ResourceUnmapBlob(cmd.read_obj()?),
740             VIRTIO_GPU_CMD_UPDATE_CURSOR => UpdateCursor(cmd.read_obj()?),
741             VIRTIO_GPU_CMD_MOVE_CURSOR => MoveCursor(cmd.read_obj()?),
742             VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID => ResourceAssignUuid(cmd.read_obj()?),
743             _ => return Err(GpuCommandDecodeError::InvalidType(hdr.type_.into())),
744         })
745     }
746 
747     /// Gets the generic `virtio_gpu_ctrl_hdr` from this command.
ctrl_hdr(&self) -> &virtio_gpu_ctrl_hdr748     pub fn ctrl_hdr(&self) -> &virtio_gpu_ctrl_hdr {
749         use self::GpuCommand::*;
750         match self {
751             GetDisplayInfo(info) => info,
752             ResourceCreate2d(info) => &info.hdr,
753             ResourceUnref(info) => &info.hdr,
754             SetScanout(info) => &info.hdr,
755             SetScanoutBlob(info) => &info.hdr,
756             ResourceFlush(info) => &info.hdr,
757             TransferToHost2d(info) => &info.hdr,
758             ResourceAttachBacking(info) => &info.hdr,
759             ResourceDetachBacking(info) => &info.hdr,
760             GetCapsetInfo(info) => &info.hdr,
761             GetCapset(info) => &info.hdr,
762             CtxCreate(info) => &info.hdr,
763             CtxDestroy(info) => &info.hdr,
764             CtxAttachResource(info) => &info.hdr,
765             CtxDetachResource(info) => &info.hdr,
766             ResourceCreate3d(info) => &info.hdr,
767             TransferToHost3d(info) => &info.hdr,
768             TransferFromHost3d(info) => &info.hdr,
769             CmdSubmit3d(info) => &info.hdr,
770             ResourceCreateBlob(info) => &info.hdr,
771             ResourceMapBlob(info) => &info.hdr,
772             ResourceUnmapBlob(info) => &info.hdr,
773             UpdateCursor(info) => &info.hdr,
774             MoveCursor(info) => &info.hdr,
775             ResourceAssignUuid(info) => &info.hdr,
776         }
777     }
778 }
779 
780 #[derive(Debug, PartialEq)]
781 pub struct GpuResponsePlaneInfo {
782     pub stride: u32,
783     pub offset: u32,
784 }
785 
786 /// A response to a `GpuCommand`. These correspond to `VIRTIO_GPU_RESP_*`.
787 #[derive(Debug)]
788 pub enum GpuResponse {
789     OkNoData,
790     OkDisplayInfo(Vec<(u32, u32)>),
791     OkCapsetInfo {
792         capset_id: u32,
793         version: u32,
794         size: u32,
795     },
796     OkCapset(Vec<u8>),
797     OkResourcePlaneInfo {
798         format_modifier: u64,
799         plane_info: Vec<GpuResponsePlaneInfo>,
800     },
801     OkResourceUuid {
802         uuid: [u8; 16],
803     },
804     OkMapInfo {
805         map_info: u32,
806     },
807     ErrUnspec,
808     ErrMsg(TubeError),
809     ErrSys(SysError),
810     ErrRutabaga(RutabagaError),
811     ErrDisplay(GpuDisplayError),
812     ErrMapping(ExternalMappingError),
813     ErrScanout {
814         num_scanouts: u32,
815     },
816     ErrOutOfMemory,
817     ErrInvalidScanoutId,
818     ErrInvalidResourceId,
819     ErrInvalidContextId,
820     ErrInvalidParameter,
821     ErrUdmabuf(UdmabufError),
822 }
823 
824 impl From<TubeError> for GpuResponse {
from(e: TubeError) -> GpuResponse825     fn from(e: TubeError) -> GpuResponse {
826         GpuResponse::ErrMsg(e)
827     }
828 }
829 
830 impl From<RutabagaError> for GpuResponse {
from(e: RutabagaError) -> GpuResponse831     fn from(e: RutabagaError) -> GpuResponse {
832         GpuResponse::ErrRutabaga(e)
833     }
834 }
835 
836 impl From<GpuDisplayError> for GpuResponse {
from(e: GpuDisplayError) -> GpuResponse837     fn from(e: GpuDisplayError) -> GpuResponse {
838         GpuResponse::ErrDisplay(e)
839     }
840 }
841 
842 impl From<ExternalMappingError> for GpuResponse {
from(e: ExternalMappingError) -> GpuResponse843     fn from(e: ExternalMappingError) -> GpuResponse {
844         GpuResponse::ErrMapping(e)
845     }
846 }
847 
848 impl From<UdmabufError> for GpuResponse {
from(e: UdmabufError) -> GpuResponse849     fn from(e: UdmabufError) -> GpuResponse {
850         GpuResponse::ErrUdmabuf(e)
851     }
852 }
853 
854 impl Display for GpuResponse {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result855     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
856         use self::GpuResponse::*;
857         match self {
858             ErrMsg(e) => write!(f, "msg-on-socket error: {}", e),
859             ErrSys(e) => write!(f, "system error: {}", e),
860             ErrRutabaga(e) => write!(f, "renderer error: {}", e),
861             ErrDisplay(e) => write!(f, "display error: {}", e),
862             ErrScanout { num_scanouts } => write!(f, "non-zero scanout: {}", num_scanouts),
863             ErrUdmabuf(e) => write!(f, "udmabuf error: {}", e),
864             _ => Ok(()),
865         }
866     }
867 }
868 
869 /// An error indicating something went wrong decoding a `GpuCommand`.
870 #[derive(Debug)]
871 pub enum GpuResponseEncodeError {
872     /// The response was encoded to an inaccessible area of memory.
873     Memory(DescriptorError),
874     /// More displays than are valid were in a `OkDisplayInfo`.
875     TooManyDisplays(usize),
876     /// More planes than are valid were in a `OkResourcePlaneInfo`.
877     TooManyPlanes(usize),
878     /// An I/O error occurred.
879     IO(io::Error),
880 }
881 
882 impl Display for GpuResponseEncodeError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result883     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
884         use self::GpuResponseEncodeError::*;
885 
886         match self {
887             Memory(e) => write!(
888                 f,
889                 "response was encoded to an inaccessible area of memory: {}",
890                 e,
891             ),
892             TooManyDisplays(n) => write!(f, "{} is more displays than are valid", n),
893             TooManyPlanes(n) => write!(f, "{} is more planes than are valid", n),
894             IO(e) => write!(f, "an I/O error occurred: {}", e),
895         }
896     }
897 }
898 
899 impl From<DescriptorError> for GpuResponseEncodeError {
from(e: DescriptorError) -> GpuResponseEncodeError900     fn from(e: DescriptorError) -> GpuResponseEncodeError {
901         GpuResponseEncodeError::Memory(e)
902     }
903 }
904 
905 impl From<io::Error> for GpuResponseEncodeError {
from(e: io::Error) -> GpuResponseEncodeError906     fn from(e: io::Error) -> GpuResponseEncodeError {
907         GpuResponseEncodeError::IO(e)
908     }
909 }
910 
911 pub type VirtioGpuResult = std::result::Result<GpuResponse, GpuResponse>;
912 
913 impl GpuResponse {
914     /// Encodes a this `GpuResponse` into `resp` and the given set of metadata.
encode( &self, flags: u32, fence_id: u64, ctx_id: u32, info: u32, resp: &mut Writer, ) -> Result<u32, GpuResponseEncodeError>915     pub fn encode(
916         &self,
917         flags: u32,
918         fence_id: u64,
919         ctx_id: u32,
920         info: u32,
921         resp: &mut Writer,
922     ) -> Result<u32, GpuResponseEncodeError> {
923         let hdr = virtio_gpu_ctrl_hdr {
924             type_: Le32::from(self.get_type()),
925             flags: Le32::from(flags),
926             fence_id: Le64::from(fence_id),
927             ctx_id: Le32::from(ctx_id),
928             info: Le32::from(info),
929         };
930         let len = match *self {
931             GpuResponse::OkDisplayInfo(ref info) => {
932                 if info.len() > VIRTIO_GPU_MAX_SCANOUTS {
933                     return Err(GpuResponseEncodeError::TooManyDisplays(info.len()));
934                 }
935                 let mut disp_info = virtio_gpu_resp_display_info {
936                     hdr,
937                     pmodes: Default::default(),
938                 };
939                 for (disp_mode, &(width, height)) in disp_info.pmodes.iter_mut().zip(info) {
940                     disp_mode.r.width = Le32::from(width);
941                     disp_mode.r.height = Le32::from(height);
942                     disp_mode.enabled = Le32::from(1);
943                 }
944                 resp.write_obj(disp_info)?;
945                 size_of_val(&disp_info)
946             }
947             GpuResponse::OkCapsetInfo {
948                 capset_id,
949                 version,
950                 size,
951             } => {
952                 resp.write_obj(virtio_gpu_resp_capset_info {
953                     hdr,
954                     capset_id: Le32::from(capset_id),
955                     capset_max_version: Le32::from(version),
956                     capset_max_size: Le32::from(size),
957                     padding: Le32::from(0),
958                 })?;
959                 size_of::<virtio_gpu_resp_capset_info>()
960             }
961             GpuResponse::OkCapset(ref data) => {
962                 resp.write_obj(hdr)?;
963                 resp.write_all(data)?;
964                 size_of_val(&hdr) + data.len()
965             }
966             GpuResponse::OkResourcePlaneInfo {
967                 format_modifier,
968                 ref plane_info,
969             } => {
970                 if plane_info.len() > PLANE_INFO_MAX_COUNT {
971                     return Err(GpuResponseEncodeError::TooManyPlanes(plane_info.len()));
972                 }
973                 let mut strides = [Le32::default(); PLANE_INFO_MAX_COUNT];
974                 let mut offsets = [Le32::default(); PLANE_INFO_MAX_COUNT];
975                 for (plane_index, plane) in plane_info.iter().enumerate() {
976                     strides[plane_index] = plane.stride.into();
977                     offsets[plane_index] = plane.offset.into();
978                 }
979                 let plane_info = virtio_gpu_resp_resource_plane_info {
980                     hdr,
981                     count: Le32::from(plane_info.len() as u32),
982                     padding: 0.into(),
983                     format_modifier: format_modifier.into(),
984                     strides,
985                     offsets,
986                 };
987                 if resp.available_bytes() >= size_of_val(&plane_info) {
988                     resp.write_obj(plane_info)?;
989                     size_of_val(&plane_info)
990                 } else {
991                     // In case there is too little room in the response slice to store the
992                     // entire virtio_gpu_resp_resource_plane_info, convert response to a regular
993                     // VIRTIO_GPU_RESP_OK_NODATA and attempt to return that.
994                     resp.write_obj(virtio_gpu_ctrl_hdr {
995                         type_: Le32::from(VIRTIO_GPU_RESP_OK_NODATA),
996                         ..hdr
997                     })?;
998                     size_of_val(&hdr)
999                 }
1000             }
1001             GpuResponse::OkResourceUuid { uuid } => {
1002                 let resp_info = virtio_gpu_resp_resource_uuid { hdr, uuid };
1003 
1004                 resp.write_obj(resp_info)?;
1005                 size_of_val(&resp_info)
1006             }
1007             GpuResponse::OkMapInfo { map_info } => {
1008                 let resp_info = virtio_gpu_resp_map_info {
1009                     hdr,
1010                     map_info: Le32::from(map_info),
1011                 };
1012 
1013                 resp.write_obj(resp_info)?;
1014                 size_of_val(&resp_info)
1015             }
1016             _ => {
1017                 resp.write_obj(hdr)?;
1018                 size_of_val(&hdr)
1019             }
1020         };
1021         Ok(len as u32)
1022     }
1023 
1024     /// Gets the `VIRTIO_GPU_*` enum value that corresponds to this variant.
get_type(&self) -> u321025     pub fn get_type(&self) -> u32 {
1026         match self {
1027             GpuResponse::OkNoData => VIRTIO_GPU_RESP_OK_NODATA,
1028             GpuResponse::OkDisplayInfo(_) => VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
1029             GpuResponse::OkCapsetInfo { .. } => VIRTIO_GPU_RESP_OK_CAPSET_INFO,
1030             GpuResponse::OkCapset(_) => VIRTIO_GPU_RESP_OK_CAPSET,
1031             GpuResponse::OkResourcePlaneInfo { .. } => VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO,
1032             GpuResponse::OkResourceUuid { .. } => VIRTIO_GPU_RESP_OK_RESOURCE_UUID,
1033             GpuResponse::OkMapInfo { .. } => VIRTIO_GPU_RESP_OK_MAP_INFO,
1034             GpuResponse::ErrUnspec => VIRTIO_GPU_RESP_ERR_UNSPEC,
1035             GpuResponse::ErrMsg(_) => VIRTIO_GPU_RESP_ERR_UNSPEC,
1036             GpuResponse::ErrSys(_) => VIRTIO_GPU_RESP_ERR_UNSPEC,
1037             GpuResponse::ErrRutabaga(_) => VIRTIO_GPU_RESP_ERR_UNSPEC,
1038             GpuResponse::ErrDisplay(_) => VIRTIO_GPU_RESP_ERR_UNSPEC,
1039             GpuResponse::ErrMapping(_) => VIRTIO_GPU_RESP_ERR_UNSPEC,
1040             GpuResponse::ErrUdmabuf(_) => VIRTIO_GPU_RESP_ERR_UNSPEC,
1041             GpuResponse::ErrScanout { num_scanouts: _ } => VIRTIO_GPU_RESP_ERR_UNSPEC,
1042             GpuResponse::ErrOutOfMemory => VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
1043             GpuResponse::ErrInvalidScanoutId => VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
1044             GpuResponse::ErrInvalidResourceId => VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
1045             GpuResponse::ErrInvalidContextId => VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
1046             GpuResponse::ErrInvalidParameter => VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
1047         }
1048     }
1049 }
1050