blob: ed52471aa1806c4f7392c79fc00f5c9df4b67ca9 [file] [log] [blame]
Andrew Walbran8ee0ef12024-01-12 15:56:14 +00001// Copyright (C) 2024 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//! Rust wrapper for `ANativeWindow` and related types.
16
Andrew Walbran30262982024-09-27 16:38:42 +010017pub(crate) mod buffer;
18
Andrew Walbran8ee0ef12024-01-12 15:56:14 +000019use binder::{
20 binder_impl::{BorrowedParcel, UnstructuredParcelable},
21 impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable,
22 unstable_api::{status_result, AsNative},
23 StatusCode,
24};
Andrew Walbran78c65342024-09-27 14:52:38 +010025use bitflags::bitflags;
Andrew Walbran30262982024-09-27 16:38:42 +010026use buffer::Buffer;
Andrew Walbran8ee0ef12024-01-12 15:56:14 +000027use nativewindow_bindgen::{
Andrew Walbran78c65342024-09-27 14:52:38 +010028 ADataSpace, AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire,
29 ANativeWindow_getBuffersDataSpace, ANativeWindow_getBuffersDefaultDataSpace,
Andrew Walbran30262982024-09-27 16:38:42 +010030 ANativeWindow_getFormat, ANativeWindow_getHeight, ANativeWindow_getWidth, ANativeWindow_lock,
Andrew Walbran78c65342024-09-27 14:52:38 +010031 ANativeWindow_readFromParcel, ANativeWindow_release, ANativeWindow_setBuffersDataSpace,
32 ANativeWindow_setBuffersGeometry, ANativeWindow_setBuffersTransform,
Andrew Walbran30262982024-09-27 16:38:42 +010033 ANativeWindow_unlockAndPost, ANativeWindow_writeToParcel, ARect,
Andrew Walbran8ee0ef12024-01-12 15:56:14 +000034};
35use std::error::Error;
36use std::fmt::{self, Debug, Display, Formatter};
Andrew Walbran30262982024-09-27 16:38:42 +010037use std::ptr::{self, null_mut, NonNull};
Andrew Walbran8ee0ef12024-01-12 15:56:14 +000038
39/// Wrapper around an opaque C `ANativeWindow`.
40#[derive(PartialEq, Eq)]
41pub struct Surface(NonNull<ANativeWindow>);
42
43impl Surface {
44 /// Returns the current width in pixels of the window surface.
45 pub fn width(&self) -> Result<u32, ErrorCode> {
46 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
47 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
48 // and we have not yet released it.
49 let width = unsafe { ANativeWindow_getWidth(self.0.as_ptr()) };
50 width.try_into().map_err(|_| ErrorCode(width))
51 }
52
53 /// Returns the current height in pixels of the window surface.
54 pub fn height(&self) -> Result<u32, ErrorCode> {
55 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
56 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
57 // and we have not yet released it.
58 let height = unsafe { ANativeWindow_getHeight(self.0.as_ptr()) };
59 height.try_into().map_err(|_| ErrorCode(height))
60 }
61
62 /// Returns the current pixel format of the window surface.
63 pub fn format(&self) -> Result<AHardwareBuffer_Format::Type, ErrorCode> {
64 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
65 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
66 // and we have not yet released it.
67 let format = unsafe { ANativeWindow_getFormat(self.0.as_ptr()) };
68 format.try_into().map_err(|_| ErrorCode(format))
69 }
Andrew Walbran78c65342024-09-27 14:52:38 +010070
71 /// Changes the format and size of the window buffers.
72 ///
73 /// The width and height control the number of pixels in the buffers, not the dimensions of the
74 /// window on screen. If these are different than the window's physical size, then its buffer
75 /// will be scaled to match that size when compositing it to the screen. The width and height
76 /// must be either both zero or both non-zero. If both are 0 then the window's base value will
77 /// come back in force.
78 pub fn set_buffers_geometry(
79 &mut self,
80 width: i32,
81 height: i32,
82 format: AHardwareBuffer_Format::Type,
83 ) -> Result<(), ErrorCode> {
84 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
85 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
86 // and we have not yet released it.
87 let status = unsafe {
88 ANativeWindow_setBuffersGeometry(
89 self.0.as_ptr(),
90 width,
91 height,
92 format.try_into().expect("Invalid format"),
93 )
94 };
95
96 if status == 0 {
97 Ok(())
98 } else {
99 Err(ErrorCode(status))
100 }
101 }
102
103 /// Sets a transfom that will be applied to future buffers posted to the window.
104 pub fn set_buffers_transform(&mut self, transform: Transform) -> Result<(), ErrorCode> {
105 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
106 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
107 // and we have not yet released it.
108 let status =
109 unsafe { ANativeWindow_setBuffersTransform(self.0.as_ptr(), transform.bits() as i32) };
110
111 if status == 0 {
112 Ok(())
113 } else {
114 Err(ErrorCode(status))
115 }
116 }
117
118 /// Sets the data space that will be applied to future buffers posted to the window.
119 pub fn set_buffers_data_space(&mut self, data_space: ADataSpace) -> Result<(), ErrorCode> {
120 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
121 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
122 // and we have not yet released it.
123 let status = unsafe { ANativeWindow_setBuffersDataSpace(self.0.as_ptr(), data_space.0) };
124
125 if status == 0 {
126 Ok(())
127 } else {
128 Err(ErrorCode(status))
129 }
130 }
131
132 /// Gets the data space of the buffers in the window.
133 pub fn get_buffers_data_space(&mut self) -> Result<ADataSpace, ErrorCode> {
134 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
135 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
136 // and we have not yet released it.
137 let data_space = unsafe { ANativeWindow_getBuffersDataSpace(self.0.as_ptr()) };
138
139 if data_space < 0 {
140 Err(ErrorCode(data_space))
141 } else {
142 Ok(ADataSpace(data_space))
143 }
144 }
145
146 /// Gets the default data space of the buffers in the window as set by the consumer.
147 pub fn get_buffers_default_data_space(&mut self) -> Result<ADataSpace, ErrorCode> {
148 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
149 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
150 // and we have not yet released it.
151 let data_space = unsafe { ANativeWindow_getBuffersDefaultDataSpace(self.0.as_ptr()) };
152
153 if data_space < 0 {
154 Err(ErrorCode(data_space))
155 } else {
156 Ok(ADataSpace(data_space))
157 }
158 }
Andrew Walbran30262982024-09-27 16:38:42 +0100159
160 /// Locks the window's next drawing surface for writing, and returns it.
161 pub fn lock(&mut self, bounds: Option<&mut ARect>) -> Result<Buffer, ErrorCode> {
162 let mut buffer = buffer::EMPTY;
163 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
164 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
165 // and we have not yet released it. The other pointers must be valid because the come from
166 // references, and aren't retained after the function returns.
167 let status = unsafe {
168 ANativeWindow_lock(
169 self.0.as_ptr(),
170 &mut buffer,
171 bounds.map(ptr::from_mut).unwrap_or(null_mut()),
172 )
173 };
174 if status != 0 {
175 return Err(ErrorCode(status));
176 }
177
178 Ok(Buffer::new(buffer, self))
179 }
180
181 /// Unlocks the window's drawing surface which was previously locked, posting the new buffer to
182 /// the display.
183 ///
184 /// This shouldn't be called directly but via the [`Buffer`], hence is not public here.
185 fn unlock_and_post(&mut self) -> Result<(), ErrorCode> {
186 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
187 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
188 // and we have not yet released it.
189 let status = unsafe { ANativeWindow_unlockAndPost(self.0.as_ptr()) };
190 if status == 0 {
191 Ok(())
192 } else {
193 Err(ErrorCode(status))
194 }
195 }
Andrew Walbran8ee0ef12024-01-12 15:56:14 +0000196}
197
198impl Drop for Surface {
199 fn drop(&mut self) {
200 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
201 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
202 // and we have not yet released it.
203 unsafe { ANativeWindow_release(self.0.as_ptr()) }
204 }
205}
206
207impl Debug for Surface {
208 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
209 f.debug_struct("Surface")
210 .field("width", &self.width())
211 .field("height", &self.height())
212 .field("format", &self.format())
213 .finish()
214 }
215}
216
217impl Clone for Surface {
218 fn clone(&self) -> Self {
219 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
220 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
221 // and we have not yet released it.
222 unsafe { ANativeWindow_acquire(self.0.as_ptr()) };
223 Self(self.0)
224 }
225}
226
227impl UnstructuredParcelable for Surface {
228 fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> {
229 let status =
230 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
231 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
232 // and we have not yet released it.
233 unsafe { ANativeWindow_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) };
234 status_result(status)
235 }
236
237 fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> {
238 let mut buffer = null_mut();
239
240 let status =
241 // SAFETY: Both pointers must be valid because they are obtained from references.
242 // `ANativeWindow_readFromParcel` doesn't store them or do anything else special
243 // with them. If it returns success then it will have allocated a new
244 // `ANativeWindow` and incremented the reference count, so we can use it until we
245 // release it.
246 unsafe { ANativeWindow_readFromParcel(parcel.as_native(), &mut buffer) };
247
248 status_result(status)?;
249
250 Ok(Self(
251 NonNull::new(buffer)
252 .expect("ANativeWindow_readFromParcel returned success but didn't allocate buffer"),
253 ))
254 }
255}
256
257impl_deserialize_for_unstructured_parcelable!(Surface);
258impl_serialize_for_unstructured_parcelable!(Surface);
259
260// SAFETY: The underlying *ANativeWindow can be moved between threads.
261unsafe impl Send for Surface {}
262
Andrew Walbrane741bdc2024-01-26 11:15:01 +0000263// SAFETY: The underlying *ANativeWindow can be used from multiple threads concurrently.
264unsafe impl Sync for Surface {}
265
Andrew Walbran8ee0ef12024-01-12 15:56:14 +0000266/// An error code returned by methods on [`Surface`].
267#[derive(Copy, Clone, Debug, Eq, PartialEq)]
268pub struct ErrorCode(i32);
269
270impl Error for ErrorCode {}
271
272impl Display for ErrorCode {
273 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
274 write!(f, "Error {}", self.0)
275 }
276}
Andrew Walbran78c65342024-09-27 14:52:38 +0100277
278bitflags! {
279 /// Transforms that can be applied to buffers as they are displayed to a window.
280 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
281 pub struct Transform: u32 {
282 const MIRROR_HORIZONTAL = 0x01;
283 const MIRROR_VERTICAL = 0x02;
284 const ROTATE_90 = 0x04;
285 }
286}
287
288impl Transform {
289 pub const IDENTITY: Self = Self::empty();
290 pub const ROTATE_180: Self = Self::MIRROR_HORIZONTAL.union(Self::MIRROR_VERTICAL);
291 pub const ROTATE_270: Self = Self::ROTATE_180.union(Self::ROTATE_90);
292}