11//! Implementation of software buffering for Android.
22
33use std:: marker:: PhantomData ;
4+ use std:: mem:: MaybeUninit ;
45use std:: num:: { NonZeroI32 , NonZeroU32 } ;
56
67use ndk:: {
@@ -12,7 +13,9 @@ use raw_window_handle::AndroidNdkWindowHandle;
1213use raw_window_handle:: { HasDisplayHandle , HasWindowHandle , RawWindowHandle } ;
1314
1415use crate :: error:: InitError ;
15- use crate :: { util, BufferInterface , Pixel , Rect , SoftBufferError , SurfaceInterface } ;
16+ use crate :: { BufferInterface , Pixel , Rect , SoftBufferError , SurfaceInterface } ;
17+
18+ const PIXEL_SIZE : usize = size_of :: < Pixel > ( ) ;
1619
1720/// The handle to a window for software buffering.
1821#[ derive( Debug ) ]
@@ -52,7 +55,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
5255 & self . window
5356 }
5457
55- /// Also changes the pixel format to [`HardwareBufferFormat::R8G8B8A8_UNORM `].
58+ /// Also changes the pixel format to [`HardwareBufferFormat::R8G8B8X8_UNORM `].
5659 fn resize ( & mut self , width : NonZeroU32 , height : NonZeroU32 ) -> Result < ( ) , SoftBufferError > {
5760 let ( width, height) = ( || {
5861 let width = NonZeroI32 :: try_from ( width) . ok ( ) ?;
@@ -77,7 +80,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
7780 }
7881
7982 fn next_buffer ( & mut self ) -> Result < BufferImpl < ' _ > , SoftBufferError > {
80- let native_window_buffer = self . native_window . lock ( None ) . map_err ( |err| {
83+ let mut native_window_buffer = self . native_window . lock ( None ) . map_err ( |err| {
8184 SoftBufferError :: PlatformError (
8285 Some ( "Failed to lock ANativeWindow" . to_owned ( ) ) ,
8386 Some ( Box :: new ( err) ) ,
@@ -99,12 +102,22 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
99102 ) ) ;
100103 }
101104
102- let buffer =
103- vec ! [ Pixel :: default ( ) ; native_window_buffer. stride( ) * native_window_buffer. height( ) ] ;
105+ assert_eq ! (
106+ native_window_buffer. format( ) . bytes_per_pixel( ) ,
107+ Some ( PIXEL_SIZE )
108+ ) ;
109+ let native_buffer = native_window_buffer. bytes ( ) . unwrap ( ) ;
110+
111+ // Zero-initialize the buffer, allowing it to be cast away from MaybeUninit and mapped as a Pixel slice
112+ native_buffer. fill ( MaybeUninit :: new ( 0 ) ) ;
113+
114+ assert_eq ! (
115+ native_buffer. len( ) ,
116+ native_window_buffer. stride( ) * native_window_buffer. height( ) * PIXEL_SIZE
117+ ) ;
104118
105119 Ok ( BufferImpl {
106120 native_window_buffer,
107- buffer : util:: PixelBuffer ( buffer) ,
108121 } )
109122 }
110123
@@ -117,15 +130,14 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
117130#[ derive( Debug ) ]
118131pub struct BufferImpl < ' surface > {
119132 native_window_buffer : NativeWindowBufferLockGuard < ' surface > ,
120- buffer : util:: PixelBuffer ,
121133}
122134
123135// TODO: Move to NativeWindowBufferLockGuard?
124136unsafe impl Send for BufferImpl < ' _ > { }
125137
126138impl BufferInterface for BufferImpl < ' _ > {
127139 fn byte_stride ( & self ) -> NonZeroU32 {
128- NonZeroU32 :: new ( self . native_window_buffer . stride ( ) as u32 * 4 ) . unwrap ( )
140+ NonZeroU32 :: new ( ( self . native_window_buffer . stride ( ) * PIXEL_SIZE ) as u32 ) . unwrap ( )
129141 }
130142
131143 fn width ( & self ) -> NonZeroU32 {
@@ -138,7 +150,15 @@ impl BufferInterface for BufferImpl<'_> {
138150
139151 #[ inline]
140152 fn pixels_mut ( & mut self ) -> & mut [ Pixel ] {
141- & mut self . buffer
153+ let native_buffer = self . native_window_buffer . bytes ( ) . unwrap ( ) ;
154+ // SAFETY: The buffer was zero-initialized and its length is always a multiple of the pixel
155+ // size (4 bytes), even when stride is applied
156+ unsafe {
157+ std:: slice:: from_raw_parts_mut (
158+ native_buffer. as_mut_ptr ( ) . cast ( ) ,
159+ native_buffer. len ( ) / PIXEL_SIZE ,
160+ )
161+ }
142162 }
143163
144164 #[ inline]
@@ -147,7 +167,7 @@ impl BufferInterface for BufferImpl<'_> {
147167 }
148168
149169 // TODO: This function is pretty slow this way
150- fn present_with_damage ( mut self , damage : & [ Rect ] ) -> Result < ( ) , SoftBufferError > {
170+ fn present_with_damage ( self , damage : & [ Rect ] ) -> Result < ( ) , SoftBufferError > {
151171 // TODO: Android requires the damage rect _at lock time_
152172 // Since we're faking the backing buffer _anyway_, we could even fake the surface lock
153173 // and lock it here (if it doesn't influence timings).
@@ -158,18 +178,8 @@ impl BufferInterface for BufferImpl<'_> {
158178 // when the enlarged damage region is not re-rendered?
159179 let _ = damage;
160180
161- // Unreachable as we checked before that this is a valid, mappable format
162- let native_buffer = self . native_window_buffer . bytes ( ) . unwrap ( ) ;
163-
164- // Write RGB(A) to the output.
165- // TODO: Use `slice::write_copy_of_slice` once stable and in MSRV.
166- // TODO(madsmtm): Verify that this compiles down to an efficient copy.
167- for ( pixel, output) in self . buffer . iter ( ) . zip ( native_buffer. chunks_mut ( 4 ) ) {
168- output[ 0 ] . write ( pixel. r ) ;
169- output[ 1 ] . write ( pixel. g ) ;
170- output[ 2 ] . write ( pixel. b ) ;
171- output[ 3 ] . write ( pixel. a ) ;
172- }
181+ // The surface will be presented when it is unlocked, which happens when the owned guard
182+ // is dropped.
173183
174184 Ok ( ( ) )
175185 }
0 commit comments