blob: 6eb3bbcdb39d4d23bd1ed52022c3782b8b01578b [file] [log] [blame]
Jim Shargo7df9f752023-07-18 20:33:45 +00001// Copyright (C) 2023 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Pleasant Rust bindings for libnativewindow, including AHardwareBuffer
16
17extern crate nativewindow_bindgen as ffi;
18
Jim Shargob69c6ef2023-10-05 22:54:51 +000019pub use ffi::{AHardwareBuffer, AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
Jim Shargo7df9f752023-07-18 20:33:45 +000020
Jim Shargob69c6ef2023-10-05 22:54:51 +000021use std::fmt::{self, Debug, Formatter};
22use std::mem::ManuallyDrop;
23use std::ptr::{self, NonNull};
Jim Shargo7df9f752023-07-18 20:33:45 +000024
25/// Wrapper around an opaque C AHardwareBuffer.
Jim Shargob69c6ef2023-10-05 22:54:51 +000026#[derive(PartialEq, Eq)]
27pub struct HardwareBuffer(NonNull<AHardwareBuffer>);
Jim Shargo7df9f752023-07-18 20:33:45 +000028
Jim Shargob69c6ef2023-10-05 22:54:51 +000029impl HardwareBuffer {
Jim Shargo7df9f752023-07-18 20:33:45 +000030 /// Test whether the given format and usage flag combination is allocatable. If this function
31 /// returns true, it means that a buffer with the given description can be allocated on this
32 /// implementation, unless resource exhaustion occurs. If this function returns false, it means
33 /// that the allocation of the given description will never succeed.
34 ///
35 /// Available since API 29
36 pub fn is_supported(
37 width: u32,
38 height: u32,
39 layers: u32,
40 format: AHardwareBuffer_Format::Type,
41 usage: AHardwareBuffer_UsageFlags,
42 stride: u32,
43 ) -> bool {
44 let buffer_desc = ffi::AHardwareBuffer_Desc {
45 width,
46 height,
47 layers,
48 format,
49 usage: usage.0,
50 stride,
51 rfu0: 0,
52 rfu1: 0,
53 };
54 // SAFETY: *buffer_desc will never be null.
55 let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) };
56
57 status == 1
58 }
59
60 /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the
61 /// buffer can be used according to the usage flags specified in its description. If a buffer is
62 /// used in ways not compatible with its usage flags, the results are undefined and may include
63 /// program termination.
64 ///
65 /// Available since API level 26.
Jim Shargoe4680d72023-08-07 16:46:45 +000066 #[inline]
Jim Shargo7df9f752023-07-18 20:33:45 +000067 pub fn new(
68 width: u32,
69 height: u32,
70 layers: u32,
71 format: AHardwareBuffer_Format::Type,
72 usage: AHardwareBuffer_UsageFlags,
73 ) -> Option<Self> {
74 let buffer_desc = ffi::AHardwareBuffer_Desc {
75 width,
76 height,
77 layers,
78 format,
79 usage: usage.0,
80 stride: 0,
81 rfu0: 0,
82 rfu1: 0,
83 };
Jim Shargob69c6ef2023-10-05 22:54:51 +000084 let mut ptr = ptr::null_mut();
Jim Shargo7df9f752023-07-18 20:33:45 +000085 // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail
86 // and return a status, but we check it later.
Jim Shargob69c6ef2023-10-05 22:54:51 +000087 let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) };
Jim Shargo7df9f752023-07-18 20:33:45 +000088
89 if status == 0 {
Jim Shargob69c6ef2023-10-05 22:54:51 +000090 Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null")))
Jim Shargo7df9f752023-07-18 20:33:45 +000091 } else {
92 None
93 }
94 }
95
96 /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer.
97 ///
98 /// # Errors
99 ///
100 /// Will panic if buffer_ptr is null.
101 ///
102 /// # Safety
103 ///
104 /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the
105 /// caller uses the pointer after the created object is dropped it will cause a memory leak.
Jim Shargob69c6ef2023-10-05 22:54:51 +0000106 pub unsafe fn from_raw(buffer_ptr: NonNull<AHardwareBuffer>) -> Self {
107 Self(buffer_ptr)
108 }
109
110 /// Get the internal |AHardwareBuffer| pointer without decrementing the refcount. This can
111 /// be used to provide a pointer to the AHB for a C/C++ API over the FFI.
112 pub fn into_raw(self) -> NonNull<AHardwareBuffer> {
113 let buffer = ManuallyDrop::new(self);
114 buffer.0
Jim Shargo7df9f752023-07-18 20:33:45 +0000115 }
116
117 /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme
118 /// and undocumented circumstances.
119 ///
120 /// Available since API level 31.
121 pub fn id(&self) -> u64 {
122 let mut out_id = 0;
123 // SAFETY: Neither pointers can be null.
Jim Shargob69c6ef2023-10-05 22:54:51 +0000124 let status = unsafe { ffi::AHardwareBuffer_getId(self.0.as_ref(), &mut out_id) };
Jim Shargo7df9f752023-07-18 20:33:45 +0000125 assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}");
126
127 out_id
128 }
129
130 /// Get the width of this buffer
131 pub fn width(&self) -> u32 {
132 self.description().width
133 }
134
135 /// Get the height of this buffer
136 pub fn height(&self) -> u32 {
137 self.description().height
138 }
139
140 /// Get the number of layers of this buffer
141 pub fn layers(&self) -> u32 {
142 self.description().layers
143 }
144
145 /// Get the format of this buffer
146 pub fn format(&self) -> AHardwareBuffer_Format::Type {
147 self.description().format
148 }
149
150 /// Get the usage bitvector of this buffer
151 pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
152 AHardwareBuffer_UsageFlags(self.description().usage)
153 }
154
155 /// Get the stride of this buffer
156 pub fn stride(&self) -> u32 {
157 self.description().stride
158 }
159
160 fn description(&self) -> ffi::AHardwareBuffer_Desc {
161 let mut buffer_desc = ffi::AHardwareBuffer_Desc {
162 width: 0,
163 height: 0,
164 layers: 0,
165 format: 0,
166 usage: 0,
167 stride: 0,
168 rfu0: 0,
169 rfu1: 0,
170 };
171 // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
Jim Shargob69c6ef2023-10-05 22:54:51 +0000172 unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) };
Jim Shargo7df9f752023-07-18 20:33:45 +0000173 buffer_desc
174 }
175}
176
Jim Shargob69c6ef2023-10-05 22:54:51 +0000177impl Drop for HardwareBuffer {
Jim Shargo7df9f752023-07-18 20:33:45 +0000178 fn drop(&mut self) {
179 // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have
180 // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw
181 // pointer requiring callers to ensure the refcount is managed appropriately.
Jim Shargob69c6ef2023-10-05 22:54:51 +0000182 unsafe { ffi::AHardwareBuffer_release(self.0.as_ptr()) }
Jim Shargo7df9f752023-07-18 20:33:45 +0000183 }
184}
185
Jim Shargob69c6ef2023-10-05 22:54:51 +0000186impl Debug for HardwareBuffer {
187 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
188 f.debug_struct("HardwareBuffer").field("id", &self.id()).finish()
189 }
190}
191
192impl Clone for HardwareBuffer {
193 fn clone(&self) -> Self {
194 // SAFETY: ptr is guaranteed to be non-null and the acquire can not fail.
195 unsafe { ffi::AHardwareBuffer_acquire(self.0.as_ptr()) };
196 Self(self.0)
197 }
198}
199
200// SAFETY: The underlying *AHardwareBuffers can be moved between threads.
201unsafe impl Send for HardwareBuffer {}
202
203// SAFETY: The underlying *AHardwareBuffers can be used from multiple threads.
204//
205// AHardwareBuffers are backed by C++ GraphicBuffers, which are mostly immutable. The only cases
206// where they are not immutable are:
207//
208// - reallocation (which is never actually done across the codebase and requires special
209// privileges/platform code access to do)
210// - "locking" for reading/writing (which is explicitly allowed to be done across multiple threads
211// according to the docs on the underlying gralloc calls)
212unsafe impl Sync for HardwareBuffer {}
213
Jim Shargo7df9f752023-07-18 20:33:45 +0000214#[cfg(test)]
Jim Shargob69c6ef2023-10-05 22:54:51 +0000215mod test {
Jim Shargo7df9f752023-07-18 20:33:45 +0000216 use super::*;
217
218 #[test]
219 fn create_valid_buffer_returns_ok() {
Jim Shargob69c6ef2023-10-05 22:54:51 +0000220 let buffer = HardwareBuffer::new(
Jim Shargo7df9f752023-07-18 20:33:45 +0000221 512,
222 512,
223 1,
224 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
225 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
226 );
227 assert!(buffer.is_some());
228 }
229
230 #[test]
231 fn create_invalid_buffer_returns_err() {
Jim Shargob69c6ef2023-10-05 22:54:51 +0000232 let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0));
Jim Shargo7df9f752023-07-18 20:33:45 +0000233 assert!(buffer.is_none());
234 }
235
236 #[test]
Jim Shargob69c6ef2023-10-05 22:54:51 +0000237 fn from_raw_allows_getters() {
Jim Shargo7df9f752023-07-18 20:33:45 +0000238 let buffer_desc = ffi::AHardwareBuffer_Desc {
239 width: 1024,
240 height: 512,
241 layers: 1,
242 format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
243 usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0,
244 stride: 0,
245 rfu0: 0,
246 rfu1: 0,
247 };
248 let mut raw_buffer_ptr = ptr::null_mut();
249
Andrew Walbran03350bc2023-08-03 16:02:51 +0000250 // SAFETY: The pointers are valid because they come from references, and
251 // `AHardwareBuffer_allocate` doesn't retain them after it returns.
Jim Shargo7df9f752023-07-18 20:33:45 +0000252 let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) };
253 assert_eq!(status, 0);
254
Andrew Walbran03350bc2023-08-03 16:02:51 +0000255 // SAFETY: The pointer must be valid because it was just allocated successfully, and we
256 // don't use it after calling this.
Jim Shargob69c6ef2023-10-05 22:54:51 +0000257 let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) };
Jim Shargo7df9f752023-07-18 20:33:45 +0000258 assert_eq!(buffer.width(), 1024);
259 }
260
261 #[test]
262 fn basic_getters() {
Jim Shargob69c6ef2023-10-05 22:54:51 +0000263 let buffer = HardwareBuffer::new(
Jim Shargo7df9f752023-07-18 20:33:45 +0000264 1024,
265 512,
266 1,
267 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
268 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
269 )
270 .expect("Buffer with some basic parameters was not created successfully");
271
272 assert_eq!(buffer.width(), 1024);
273 assert_eq!(buffer.height(), 512);
274 assert_eq!(buffer.layers(), 1);
275 assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
276 assert_eq!(
277 buffer.usage(),
278 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
279 );
280 }
281
282 #[test]
283 fn id_getter() {
Jim Shargob69c6ef2023-10-05 22:54:51 +0000284 let buffer = HardwareBuffer::new(
Jim Shargo7df9f752023-07-18 20:33:45 +0000285 1024,
286 512,
287 1,
288 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
289 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
290 )
291 .expect("Buffer with some basic parameters was not created successfully");
292
293 assert_ne!(0, buffer.id());
294 }
Jim Shargob69c6ef2023-10-05 22:54:51 +0000295
296 #[test]
297 fn clone() {
298 let buffer = HardwareBuffer::new(
299 1024,
300 512,
301 1,
302 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
303 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
304 )
305 .expect("Buffer with some basic parameters was not created successfully");
306 let buffer2 = buffer.clone();
307
308 assert_eq!(buffer, buffer2);
309 }
310
311 #[test]
312 fn into_raw() {
313 let buffer = HardwareBuffer::new(
314 1024,
315 512,
316 1,
317 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
318 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
319 )
320 .expect("Buffer with some basic parameters was not created successfully");
321 let buffer2 = buffer.clone();
322
323 let raw_buffer = buffer.into_raw();
324 // SAFETY: This is the same pointer we had before.
325 let remade_buffer = unsafe { HardwareBuffer::from_raw(raw_buffer) };
326
327 assert_eq!(remade_buffer, buffer2);
328 }
Jim Shargo7df9f752023-07-18 20:33:45 +0000329}