xref: /aosp_15_r20/frameworks/native/libs/nativewindow/rust/src/surface.rs (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 // 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 
17 pub(crate) mod buffer;
18 
19 use 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 };
25 use bitflags::bitflags;
26 use buffer::Buffer;
27 use nativewindow_bindgen::{
28     ADataSpace, AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire,
29     ANativeWindow_getBuffersDataSpace, ANativeWindow_getBuffersDefaultDataSpace,
30     ANativeWindow_getFormat, ANativeWindow_getHeight, ANativeWindow_getWidth, ANativeWindow_lock,
31     ANativeWindow_readFromParcel, ANativeWindow_release, ANativeWindow_setBuffersDataSpace,
32     ANativeWindow_setBuffersGeometry, ANativeWindow_setBuffersTransform,
33     ANativeWindow_unlockAndPost, ANativeWindow_writeToParcel, ARect,
34 };
35 use std::error::Error;
36 use std::fmt::{self, Debug, Display, Formatter};
37 use std::ptr::{self, null_mut, NonNull};
38 
39 /// Wrapper around an opaque C `ANativeWindow`.
40 #[derive(PartialEq, Eq)]
41 pub struct Surface(NonNull<ANativeWindow>);
42 
43 impl Surface {
44     /// Returns the current width in pixels of the window surface.
width(&self) -> Result<u32, ErrorCode>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.
height(&self) -> Result<u32, ErrorCode>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.
format(&self) -> Result<AHardwareBuffer_Format::Type, ErrorCode>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     }
70 
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.
set_buffers_geometry( &mut self, width: i32, height: i32, format: AHardwareBuffer_Format::Type, ) -> Result<(), ErrorCode>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.
set_buffers_transform(&mut self, transform: Transform) -> Result<(), ErrorCode>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.
set_buffers_data_space(&mut self, data_space: ADataSpace) -> Result<(), ErrorCode>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.
get_buffers_data_space(&mut self) -> Result<ADataSpace, ErrorCode>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.
get_buffers_default_data_space(&mut self) -> Result<ADataSpace, ErrorCode>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     }
159 
160     /// Locks the window's next drawing surface for writing, and returns it.
lock(&mut self, bounds: Option<&mut ARect>) -> Result<Buffer, ErrorCode>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.
unlock_and_post(&mut self) -> Result<(), ErrorCode>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     }
196 }
197 
198 impl Drop for Surface {
drop(&mut self)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 
207 impl Debug for Surface {
fmt(&self, f: &mut Formatter) -> fmt::Result208     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 
217 impl Clone for Surface {
clone(&self) -> Self218     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 
227 impl UnstructuredParcelable for Surface {
write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode>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 
from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode>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 
257 impl_deserialize_for_unstructured_parcelable!(Surface);
258 impl_serialize_for_unstructured_parcelable!(Surface);
259 
260 // SAFETY: The underlying *ANativeWindow can be moved between threads.
261 unsafe impl Send for Surface {}
262 
263 // SAFETY: The underlying *ANativeWindow can be used from multiple threads concurrently.
264 unsafe impl Sync for Surface {}
265 
266 /// An error code returned by methods on [`Surface`].
267 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
268 pub struct ErrorCode(i32);
269 
270 impl Error for ErrorCode {}
271 
272 impl Display for ErrorCode {
fmt(&self, f: &mut Formatter) -> fmt::Result273     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
274         write!(f, "Error {}", self.0)
275     }
276 }
277 
278 bitflags! {
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 
288 impl 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 }
293