| Jim Shargo | 7df9f75 | 2023-07-18 20:33:45 +0000 | [diff] [blame] | 1 | // 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 |  | 
|  | 17 | extern crate nativewindow_bindgen as ffi; | 
|  | 18 |  | 
|  | 19 | pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; | 
|  | 20 |  | 
|  | 21 | use std::os::raw::c_void; | 
|  | 22 | use std::ptr; | 
|  | 23 |  | 
|  | 24 | /// Wrapper around an opaque C AHardwareBuffer. | 
|  | 25 | pub struct AHardwareBuffer(*mut ffi::AHardwareBuffer); | 
|  | 26 |  | 
|  | 27 | impl 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 Shargo | e4680d7 | 2023-08-07 16:46:45 +0000 | [diff] [blame] | 64 | #[inline] | 
| Jim Shargo | 7df9f75 | 2023-07-18 20:33:45 +0000 | [diff] [blame] | 65 | 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 |  | 
|  | 169 | impl 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)] | 
|  | 179 | mod 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 Walbran | 03350bc | 2023-08-03 16:02:51 +0000 | [diff] [blame] | 203 | // SAFETY: Passing a null pointer is safe, it should just panic. | 
| Jim Shargo | 7df9f75 | 2023-07-18 20:33:45 +0000 | [diff] [blame] | 204 | 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 Walbran | 03350bc | 2023-08-03 16:02:51 +0000 | [diff] [blame] | 221 | // SAFETY: The pointers are valid because they come from references, and | 
|  | 222 | // `AHardwareBuffer_allocate` doesn't retain them after it returns. | 
| Jim Shargo | 7df9f75 | 2023-07-18 20:33:45 +0000 | [diff] [blame] | 223 | let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) }; | 
|  | 224 | assert_eq!(status, 0); | 
|  | 225 |  | 
| Andrew Walbran | 03350bc | 2023-08-03 16:02:51 +0000 | [diff] [blame] | 226 | // SAFETY: The pointer must be valid because it was just allocated successfully, and we | 
|  | 227 | // don't use it after calling this. | 
| Jim Shargo | 7df9f75 | 2023-07-18 20:33:45 +0000 | [diff] [blame] | 228 | 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 | } |