blob: 0ed381eac5fdd00b1970296c1f882ab49d57bb51 [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.
64 pub fn new(
65 width: u32,
66 height: u32,
67 layers: u32,
68 format: AHardwareBuffer_Format::Type,
69 usage: AHardwareBuffer_UsageFlags,
70 ) -> Option<Self> {
71 let buffer_desc = ffi::AHardwareBuffer_Desc {
72 width,
73 height,
74 layers,
75 format,
76 usage: usage.0,
77 stride: 0,
78 rfu0: 0,
79 rfu1: 0,
80 };
81 let mut buffer = ptr::null_mut();
82 // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail
83 // and return a status, but we check it later.
84 let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut buffer) };
85
86 if status == 0 {
87 Some(Self(buffer))
88 } else {
89 None
90 }
91 }
92
93 /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer.
94 ///
95 /// # Errors
96 ///
97 /// Will panic if buffer_ptr is null.
98 ///
99 /// # Safety
100 ///
101 /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the
102 /// caller uses the pointer after the created object is dropped it will cause a memory leak.
103 pub unsafe fn take_from_raw(buffer_ptr: *mut c_void) -> Self {
104 assert!(!buffer_ptr.is_null());
105 Self(buffer_ptr as *mut ffi::AHardwareBuffer)
106 }
107
108 /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme
109 /// and undocumented circumstances.
110 ///
111 /// Available since API level 31.
112 pub fn id(&self) -> u64 {
113 let mut out_id = 0;
114 // SAFETY: Neither pointers can be null.
115 let status = unsafe { ffi::AHardwareBuffer_getId(self.0, &mut out_id) };
116 assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}");
117
118 out_id
119 }
120
121 /// Get the width of this buffer
122 pub fn width(&self) -> u32 {
123 self.description().width
124 }
125
126 /// Get the height of this buffer
127 pub fn height(&self) -> u32 {
128 self.description().height
129 }
130
131 /// Get the number of layers of this buffer
132 pub fn layers(&self) -> u32 {
133 self.description().layers
134 }
135
136 /// Get the format of this buffer
137 pub fn format(&self) -> AHardwareBuffer_Format::Type {
138 self.description().format
139 }
140
141 /// Get the usage bitvector of this buffer
142 pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
143 AHardwareBuffer_UsageFlags(self.description().usage)
144 }
145
146 /// Get the stride of this buffer
147 pub fn stride(&self) -> u32 {
148 self.description().stride
149 }
150
151 fn description(&self) -> ffi::AHardwareBuffer_Desc {
152 let mut buffer_desc = ffi::AHardwareBuffer_Desc {
153 width: 0,
154 height: 0,
155 layers: 0,
156 format: 0,
157 usage: 0,
158 stride: 0,
159 rfu0: 0,
160 rfu1: 0,
161 };
162 // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
163 unsafe { ffi::AHardwareBuffer_describe(self.0, &mut buffer_desc) };
164 buffer_desc
165 }
166}
167
168impl Drop for AHardwareBuffer {
169 fn drop(&mut self) {
170 // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have
171 // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw
172 // pointer requiring callers to ensure the refcount is managed appropriately.
173 unsafe { ffi::AHardwareBuffer_release(self.0) }
174 }
175}
176
177#[cfg(test)]
178mod ahardwarebuffer_tests {
179 use super::*;
180
181 #[test]
182 fn create_valid_buffer_returns_ok() {
183 let buffer = AHardwareBuffer::new(
184 512,
185 512,
186 1,
187 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
188 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
189 );
190 assert!(buffer.is_some());
191 }
192
193 #[test]
194 fn create_invalid_buffer_returns_err() {
195 let buffer = AHardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0));
196 assert!(buffer.is_none());
197 }
198
199 #[test]
200 #[should_panic]
201 fn take_from_raw_panics_on_null() {
Andrew Walbran03350bc2023-08-03 16:02:51 +0000202 // SAFETY: Passing a null pointer is safe, it should just panic.
Jim Shargo7df9f752023-07-18 20:33:45 +0000203 unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) };
204 }
205
206 #[test]
207 fn take_from_raw_allows_getters() {
208 let buffer_desc = ffi::AHardwareBuffer_Desc {
209 width: 1024,
210 height: 512,
211 layers: 1,
212 format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
213 usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0,
214 stride: 0,
215 rfu0: 0,
216 rfu1: 0,
217 };
218 let mut raw_buffer_ptr = ptr::null_mut();
219
Andrew Walbran03350bc2023-08-03 16:02:51 +0000220 // SAFETY: The pointers are valid because they come from references, and
221 // `AHardwareBuffer_allocate` doesn't retain them after it returns.
Jim Shargo7df9f752023-07-18 20:33:45 +0000222 let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) };
223 assert_eq!(status, 0);
224
Andrew Walbran03350bc2023-08-03 16:02:51 +0000225 // SAFETY: The pointer must be valid because it was just allocated successfully, and we
226 // don't use it after calling this.
Jim Shargo7df9f752023-07-18 20:33:45 +0000227 let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) };
228 assert_eq!(buffer.width(), 1024);
229 }
230
231 #[test]
232 fn basic_getters() {
233 let buffer = AHardwareBuffer::new(
234 1024,
235 512,
236 1,
237 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
238 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
239 )
240 .expect("Buffer with some basic parameters was not created successfully");
241
242 assert_eq!(buffer.width(), 1024);
243 assert_eq!(buffer.height(), 512);
244 assert_eq!(buffer.layers(), 1);
245 assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
246 assert_eq!(
247 buffer.usage(),
248 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
249 );
250 }
251
252 #[test]
253 fn id_getter() {
254 let buffer = AHardwareBuffer::new(
255 1024,
256 512,
257 1,
258 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
259 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
260 )
261 .expect("Buffer with some basic parameters was not created successfully");
262
263 assert_ne!(0, buffer.id());
264 }
265}