blob: 9eddfcd497096f66fe9e8475a0555e8716fb8a27 [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
17use binder::{
18 binder_impl::{BorrowedParcel, UnstructuredParcelable},
19 impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable,
20 unstable_api::{status_result, AsNative},
21 StatusCode,
22};
Andrew Walbran78c65342024-09-27 14:52:38 +010023use bitflags::bitflags;
Andrew Walbran8ee0ef12024-01-12 15:56:14 +000024use nativewindow_bindgen::{
Andrew Walbran78c65342024-09-27 14:52:38 +010025 ADataSpace, AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire,
26 ANativeWindow_getBuffersDataSpace, ANativeWindow_getBuffersDefaultDataSpace,
27 ANativeWindow_getFormat, ANativeWindow_getHeight, ANativeWindow_getWidth,
28 ANativeWindow_readFromParcel, ANativeWindow_release, ANativeWindow_setBuffersDataSpace,
29 ANativeWindow_setBuffersGeometry, ANativeWindow_setBuffersTransform,
30 ANativeWindow_writeToParcel,
Andrew Walbran8ee0ef12024-01-12 15:56:14 +000031};
32use std::error::Error;
33use std::fmt::{self, Debug, Display, Formatter};
34use std::ptr::{null_mut, NonNull};
35
36/// Wrapper around an opaque C `ANativeWindow`.
37#[derive(PartialEq, Eq)]
38pub struct Surface(NonNull<ANativeWindow>);
39
40impl Surface {
41 /// Returns the current width in pixels of the window surface.
42 pub fn width(&self) -> Result<u32, ErrorCode> {
43 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
44 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
45 // and we have not yet released it.
46 let width = unsafe { ANativeWindow_getWidth(self.0.as_ptr()) };
47 width.try_into().map_err(|_| ErrorCode(width))
48 }
49
50 /// Returns the current height in pixels of the window surface.
51 pub fn height(&self) -> Result<u32, ErrorCode> {
52 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
53 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
54 // and we have not yet released it.
55 let height = unsafe { ANativeWindow_getHeight(self.0.as_ptr()) };
56 height.try_into().map_err(|_| ErrorCode(height))
57 }
58
59 /// Returns the current pixel format of the window surface.
60 pub fn format(&self) -> Result<AHardwareBuffer_Format::Type, ErrorCode> {
61 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
62 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
63 // and we have not yet released it.
64 let format = unsafe { ANativeWindow_getFormat(self.0.as_ptr()) };
65 format.try_into().map_err(|_| ErrorCode(format))
66 }
Andrew Walbran78c65342024-09-27 14:52:38 +010067
68 /// Changes the format and size of the window buffers.
69 ///
70 /// The width and height control the number of pixels in the buffers, not the dimensions of the
71 /// window on screen. If these are different than the window's physical size, then its buffer
72 /// will be scaled to match that size when compositing it to the screen. The width and height
73 /// must be either both zero or both non-zero. If both are 0 then the window's base value will
74 /// come back in force.
75 pub fn set_buffers_geometry(
76 &mut self,
77 width: i32,
78 height: i32,
79 format: AHardwareBuffer_Format::Type,
80 ) -> Result<(), ErrorCode> {
81 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
82 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
83 // and we have not yet released it.
84 let status = unsafe {
85 ANativeWindow_setBuffersGeometry(
86 self.0.as_ptr(),
87 width,
88 height,
89 format.try_into().expect("Invalid format"),
90 )
91 };
92
93 if status == 0 {
94 Ok(())
95 } else {
96 Err(ErrorCode(status))
97 }
98 }
99
100 /// Sets a transfom that will be applied to future buffers posted to the window.
101 pub fn set_buffers_transform(&mut self, transform: Transform) -> Result<(), ErrorCode> {
102 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
103 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
104 // and we have not yet released it.
105 let status =
106 unsafe { ANativeWindow_setBuffersTransform(self.0.as_ptr(), transform.bits() as i32) };
107
108 if status == 0 {
109 Ok(())
110 } else {
111 Err(ErrorCode(status))
112 }
113 }
114
115 /// Sets the data space that will be applied to future buffers posted to the window.
116 pub fn set_buffers_data_space(&mut self, data_space: ADataSpace) -> Result<(), ErrorCode> {
117 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
118 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
119 // and we have not yet released it.
120 let status = unsafe { ANativeWindow_setBuffersDataSpace(self.0.as_ptr(), data_space.0) };
121
122 if status == 0 {
123 Ok(())
124 } else {
125 Err(ErrorCode(status))
126 }
127 }
128
129 /// Gets the data space of the buffers in the window.
130 pub fn get_buffers_data_space(&mut self) -> Result<ADataSpace, ErrorCode> {
131 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
132 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
133 // and we have not yet released it.
134 let data_space = unsafe { ANativeWindow_getBuffersDataSpace(self.0.as_ptr()) };
135
136 if data_space < 0 {
137 Err(ErrorCode(data_space))
138 } else {
139 Ok(ADataSpace(data_space))
140 }
141 }
142
143 /// Gets the default data space of the buffers in the window as set by the consumer.
144 pub fn get_buffers_default_data_space(&mut self) -> Result<ADataSpace, ErrorCode> {
145 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
146 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
147 // and we have not yet released it.
148 let data_space = unsafe { ANativeWindow_getBuffersDefaultDataSpace(self.0.as_ptr()) };
149
150 if data_space < 0 {
151 Err(ErrorCode(data_space))
152 } else {
153 Ok(ADataSpace(data_space))
154 }
155 }
Andrew Walbran8ee0ef12024-01-12 15:56:14 +0000156}
157
158impl Drop for Surface {
159 fn drop(&mut self) {
160 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
161 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
162 // and we have not yet released it.
163 unsafe { ANativeWindow_release(self.0.as_ptr()) }
164 }
165}
166
167impl Debug for Surface {
168 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
169 f.debug_struct("Surface")
170 .field("width", &self.width())
171 .field("height", &self.height())
172 .field("format", &self.format())
173 .finish()
174 }
175}
176
177impl Clone for Surface {
178 fn clone(&self) -> Self {
179 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
180 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
181 // and we have not yet released it.
182 unsafe { ANativeWindow_acquire(self.0.as_ptr()) };
183 Self(self.0)
184 }
185}
186
187impl UnstructuredParcelable for Surface {
188 fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> {
189 let status =
190 // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
191 // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
192 // and we have not yet released it.
193 unsafe { ANativeWindow_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) };
194 status_result(status)
195 }
196
197 fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> {
198 let mut buffer = null_mut();
199
200 let status =
201 // SAFETY: Both pointers must be valid because they are obtained from references.
202 // `ANativeWindow_readFromParcel` doesn't store them or do anything else special
203 // with them. If it returns success then it will have allocated a new
204 // `ANativeWindow` and incremented the reference count, so we can use it until we
205 // release it.
206 unsafe { ANativeWindow_readFromParcel(parcel.as_native(), &mut buffer) };
207
208 status_result(status)?;
209
210 Ok(Self(
211 NonNull::new(buffer)
212 .expect("ANativeWindow_readFromParcel returned success but didn't allocate buffer"),
213 ))
214 }
215}
216
217impl_deserialize_for_unstructured_parcelable!(Surface);
218impl_serialize_for_unstructured_parcelable!(Surface);
219
220// SAFETY: The underlying *ANativeWindow can be moved between threads.
221unsafe impl Send for Surface {}
222
Andrew Walbrane741bdc2024-01-26 11:15:01 +0000223// SAFETY: The underlying *ANativeWindow can be used from multiple threads concurrently.
224unsafe impl Sync for Surface {}
225
Andrew Walbran8ee0ef12024-01-12 15:56:14 +0000226/// An error code returned by methods on [`Surface`].
227#[derive(Copy, Clone, Debug, Eq, PartialEq)]
228pub struct ErrorCode(i32);
229
230impl Error for ErrorCode {}
231
232impl Display for ErrorCode {
233 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
234 write!(f, "Error {}", self.0)
235 }
236}
Andrew Walbran78c65342024-09-27 14:52:38 +0100237
238bitflags! {
239 /// Transforms that can be applied to buffers as they are displayed to a window.
240 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
241 pub struct Transform: u32 {
242 const MIRROR_HORIZONTAL = 0x01;
243 const MIRROR_VERTICAL = 0x02;
244 const ROTATE_90 = 0x04;
245 }
246}
247
248impl Transform {
249 pub const IDENTITY: Self = Self::empty();
250 pub const ROTATE_180: Self = Self::MIRROR_HORIZONTAL.union(Self::MIRROR_VERTICAL);
251 pub const ROTATE_270: Self = Self::ROTATE_180.union(Self::ROTATE_90);
252}