blob: a2ec57cd3c3072fe167ac5cec2c7bb44a45245b6 [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
19pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
20
21use std::os::raw::c_void;
22use std::ptr;
23
24/// Wrapper around an opaque C AHardwareBuffer.
25pub struct AHardwareBuffer(*mut ffi::AHardwareBuffer);
26
27impl AHardwareBuffer {
28 /// Test whether the given format and usage flag combination is allocatable. If this function
29 /// returns true, it means that a buffer with the given description can be allocated on this
30 /// implementation, unless resource exhaustion occurs. If this function returns false, it means
31 /// that the allocation of the given description will never succeed.
32 ///
33 /// Available since API 29
34 pub fn is_supported(
35 width: u32,
36 height: u32,
37 layers: u32,
38 format: AHardwareBuffer_Format::Type,
39 usage: AHardwareBuffer_UsageFlags,
40 stride: u32,
41 ) -> bool {
42 let buffer_desc = ffi::AHardwareBuffer_Desc {
43 width,
44 height,
45 layers,
46 format,
47 usage: usage.0,
48 stride,
49 rfu0: 0,
50 rfu1: 0,
51 };
52 // SAFETY: *buffer_desc will never be null.
53 let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) };
54
55 status == 1
56 }
57
58 /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the
59 /// buffer can be used according to the usage flags specified in its description. If a buffer is
60 /// used in ways not compatible with its usage flags, the results are undefined and may include
61 /// program termination.
62 ///
63 /// Available since API level 26.
Jim Shargoe4680d72023-08-07 16:46:45 +000064 #[inline]
Jim Shargo7df9f752023-07-18 20:33:45 +000065 pub fn new(
66 width: u32,
67 height: u32,
68 layers: u32,
69 format: AHardwareBuffer_Format::Type,
70 usage: AHardwareBuffer_UsageFlags,
71 ) -> Option<Self> {
72 let buffer_desc = ffi::AHardwareBuffer_Desc {
73 width,
74 height,
75 layers,
76 format,
77 usage: usage.0,
78 stride: 0,
79 rfu0: 0,
80 rfu1: 0,
81 };
82 let mut buffer = ptr::null_mut();
83 // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail
84 // and return a status, but we check it later.
85 let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut buffer) };
86
87 if status == 0 {
88 Some(Self(buffer))
89 } else {
90 None
91 }
92 }
93
94 /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer.
95 ///
96 /// # Errors
97 ///
98 /// Will panic if buffer_ptr is null.
99 ///
100 /// # Safety
101 ///
102 /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the
103 /// caller uses the pointer after the created object is dropped it will cause a memory leak.
104 pub unsafe fn take_from_raw(buffer_ptr: *mut c_void) -> Self {
105 assert!(!buffer_ptr.is_null());
106 Self(buffer_ptr as *mut ffi::AHardwareBuffer)
107 }
108
109 /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme
110 /// and undocumented circumstances.
111 ///
112 /// Available since API level 31.
113 pub fn id(&self) -> u64 {
114 let mut out_id = 0;
115 // SAFETY: Neither pointers can be null.
116 let status = unsafe { ffi::AHardwareBuffer_getId(self.0, &mut out_id) };
117 assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}");
118
119 out_id
120 }
121
122 /// Get the width of this buffer
123 pub fn width(&self) -> u32 {
124 self.description().width
125 }
126
127 /// Get the height of this buffer
128 pub fn height(&self) -> u32 {
129 self.description().height
130 }
131
132 /// Get the number of layers of this buffer
133 pub fn layers(&self) -> u32 {
134 self.description().layers
135 }
136
137 /// Get the format of this buffer
138 pub fn format(&self) -> AHardwareBuffer_Format::Type {
139 self.description().format
140 }
141
142 /// Get the usage bitvector of this buffer
143 pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
144 AHardwareBuffer_UsageFlags(self.description().usage)
145 }
146
147 /// Get the stride of this buffer
148 pub fn stride(&self) -> u32 {
149 self.description().stride
150 }
151
152 fn description(&self) -> ffi::AHardwareBuffer_Desc {
153 let mut buffer_desc = ffi::AHardwareBuffer_Desc {
154 width: 0,
155 height: 0,
156 layers: 0,
157 format: 0,
158 usage: 0,
159 stride: 0,
160 rfu0: 0,
161 rfu1: 0,
162 };
163 // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
164 unsafe { ffi::AHardwareBuffer_describe(self.0, &mut buffer_desc) };
165 buffer_desc
166 }
167}
168
169impl Drop for AHardwareBuffer {
170 fn drop(&mut self) {
171 // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have
172 // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw
173 // pointer requiring callers to ensure the refcount is managed appropriately.
174 unsafe { ffi::AHardwareBuffer_release(self.0) }
175 }
176}
177
178#[cfg(test)]
179mod ahardwarebuffer_tests {
180 use super::*;
181
182 #[test]
183 fn create_valid_buffer_returns_ok() {
184 let buffer = AHardwareBuffer::new(
185 512,
186 512,
187 1,
188 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
189 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
190 );
191 assert!(buffer.is_some());
192 }
193
194 #[test]
195 fn create_invalid_buffer_returns_err() {
196 let buffer = AHardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0));
197 assert!(buffer.is_none());
198 }
199
200 #[test]
201 #[should_panic]
202 fn take_from_raw_panics_on_null() {
Andrew Walbran03350bc2023-08-03 16:02:51 +0000203 // SAFETY: Passing a null pointer is safe, it should just panic.
Jim Shargo7df9f752023-07-18 20:33:45 +0000204 unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) };
205 }
206
207 #[test]
208 fn take_from_raw_allows_getters() {
209 let buffer_desc = ffi::AHardwareBuffer_Desc {
210 width: 1024,
211 height: 512,
212 layers: 1,
213 format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
214 usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0,
215 stride: 0,
216 rfu0: 0,
217 rfu1: 0,
218 };
219 let mut raw_buffer_ptr = ptr::null_mut();
220
Andrew Walbran03350bc2023-08-03 16:02:51 +0000221 // SAFETY: The pointers are valid because they come from references, and
222 // `AHardwareBuffer_allocate` doesn't retain them after it returns.
Jim Shargo7df9f752023-07-18 20:33:45 +0000223 let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) };
224 assert_eq!(status, 0);
225
Andrew Walbran03350bc2023-08-03 16:02:51 +0000226 // SAFETY: The pointer must be valid because it was just allocated successfully, and we
227 // don't use it after calling this.
Jim Shargo7df9f752023-07-18 20:33:45 +0000228 let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) };
229 assert_eq!(buffer.width(), 1024);
230 }
231
232 #[test]
233 fn basic_getters() {
234 let buffer = AHardwareBuffer::new(
235 1024,
236 512,
237 1,
238 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
239 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
240 )
241 .expect("Buffer with some basic parameters was not created successfully");
242
243 assert_eq!(buffer.width(), 1024);
244 assert_eq!(buffer.height(), 512);
245 assert_eq!(buffer.layers(), 1);
246 assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
247 assert_eq!(
248 buffer.usage(),
249 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
250 );
251 }
252
253 #[test]
254 fn id_getter() {
255 let buffer = AHardwareBuffer::new(
256 1024,
257 512,
258 1,
259 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
260 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
261 )
262 .expect("Buffer with some basic parameters was not created successfully");
263
264 assert_ne!(0, buffer.id());
265 }
266}