1 // Copyright 2022 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 //! Utility functions used by several parts of this crate.
6 //!
7 //! This module is for anything that doesn't fit into the other top-level modules. Try not to add
8 //! new code here unless it really doesn't belong anywhere else.
9
10 use std::marker::Copy;
11 use std::ops::Add;
12 use std::ops::Div;
13 use std::ops::Mul;
14 use std::ops::Sub;
15 use std::os::fd::OwnedFd;
16
17 use crate::Fourcc;
18 use crate::FrameLayout;
19 use crate::PlaneLayout;
20 use crate::Resolution;
21
align_up<T>(x: T, alignment: T) -> T where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> + Mul<Output = T> + From<u8> + Copy,22 pub fn align_up<T>(x: T, alignment: T) -> T
23 where
24 T: Add<Output = T> + Sub<Output = T> + Div<Output = T> + Mul<Output = T> + From<u8> + Copy,
25 {
26 ((x + alignment - T::from(1)) / alignment) * alignment
27 }
28
29 // This is the formula we use to approximate the maximum compressed buffer size for a video frame.
buffer_size_for_area(width: u32, height: u32) -> u3230 pub fn buffer_size_for_area(width: u32, height: u32) -> u32 {
31 let area = width * height;
32 let mut buffer_size: u32 = 1024 * 1024;
33
34 if area > 720 * 480 {
35 buffer_size *= 2;
36 }
37 if area > 1920 * 1080 {
38 buffer_size *= 2;
39 }
40 buffer_size
41 }
42
43 /// A structure that holds user-allocated memory for a frame as well as its layout.
44 #[derive(Debug)]
45 pub struct UserPtrFrame {
46 pub buffers: Vec<*mut u8>,
47 pub mem_layout: std::alloc::Layout,
48 pub layout: FrameLayout,
49 }
50
51 impl UserPtrFrame {
52 /// Allocate enough memory to back a NV12 frame of `size` dimension.
new_nv12(size: Resolution) -> Self53 pub fn new_nv12(size: Resolution) -> Self {
54 /// Add what is needed to a value in order to make it a multiple of some alignment.
55 macro_rules! align {
56 ($n:expr, $r:expr) => {
57 ($n + ($r - 1)) & !($r - 1)
58 };
59 }
60
61 // Align according to VAAPI constraints.
62 let width = align!(size.width, 16) as usize;
63 let height = align!(size.height, 4) as usize;
64 let stride = align!(width, 64);
65 let uv_start = height * stride;
66 let uv_size = (height / 2) * stride;
67
68 Self::alloc(
69 FrameLayout {
70 format: (Fourcc::from(b"NV12"), 0),
71 size: Resolution::from((width as u32, height as u32)),
72 planes: vec![
73 PlaneLayout { buffer_index: 0, offset: 0, stride },
74 PlaneLayout { buffer_index: 0, offset: uv_start, stride },
75 ],
76 },
77 uv_start.max(uv_size),
78 )
79 }
80
alloc(layout: FrameLayout, buffer_size: usize) -> Self81 pub fn alloc(layout: FrameLayout, buffer_size: usize) -> Self {
82 let buffer_count = layout
83 .planes
84 .iter()
85 .map(|plane| plane.buffer_index)
86 .collect::<std::collections::HashSet<usize>>()
87 .len();
88
89 // SAFETY: the invariants of `Layout` are respected.
90 let mem_layout =
91 unsafe { std::alloc::Layout::from_size_align_unchecked(buffer_size, 4096) };
92
93 let buffers = (0..buffer_count)
94 .map(|_| {
95 // SAFETY: the invariants of `Layout` are respected.
96 unsafe { std::alloc::alloc(mem_layout) }
97 })
98 .collect();
99
100 Self { buffers, mem_layout, layout }
101 }
102 }
103
104 #[derive(Debug)]
105 pub struct DmabufFrame {
106 pub fds: Vec<OwnedFd>,
107 pub layout: FrameLayout,
108 }
109
110 impl Drop for UserPtrFrame {
drop(&mut self)111 fn drop(&mut self) {
112 for buffer in std::mem::take(&mut self.buffers).into_iter() {
113 // Safe because we allocated the memory using `std::alloc::alloc`.
114 unsafe { std::alloc::dealloc(buffer, self.mem_layout) }
115 }
116 }
117 }
118