@@ -10,25 +10,42 @@ use euclid::default::Size2D;
10
10
use log:: info;
11
11
12
12
use crate :: egl;
13
- use crate :: egl:: types:: EGLSurface ;
13
+ use crate :: egl:: types:: { EGLSurface , EGLint } ;
14
14
use crate :: gl;
15
15
use crate :: gl:: types:: { GLenum , GLuint } ;
16
+ use crate :: gl_utils;
17
+ use crate :: platform:: generic;
16
18
use crate :: platform:: generic:: egl:: device:: EGL_FUNCTIONS ;
19
+ use crate :: platform:: generic:: egl:: ffi:: EGLImageKHR ;
17
20
use crate :: platform:: generic:: egl:: ffi:: EGL_EXTENSION_FUNCTIONS ;
21
+ use crate :: platform:: generic:: egl:: ffi:: EGL_IMAGE_PRESERVED_KHR ;
22
+ use crate :: platform:: generic:: egl:: ffi:: EGL_NATIVE_BUFFER_ANDROID ;
18
23
use crate :: platform:: generic:: egl:: ffi:: EGL_NO_IMAGE_KHR ;
24
+ use crate :: renderbuffers:: Renderbuffers ;
19
25
use crate :: { Error , SurfaceAccess , SurfaceID , SurfaceInfo , SurfaceType } ;
20
26
21
27
use super :: super :: context:: { Context , GL_FUNCTIONS } ;
22
28
use super :: super :: device:: Device ;
23
29
use super :: super :: ohos_ffi:: {
24
- NativeWindowOperation , OHNativeWindow , OH_NativeWindow_NativeWindowHandleOpt ,
30
+ NativeWindowOperation , OHNativeWindow , OH_NativeBuffer , OH_NativeBuffer_Alloc ,
31
+ OH_NativeBuffer_Config , OH_NativeBuffer_Format , OH_NativeBuffer_Unreference ,
32
+ OH_NativeBuffer_Usage , OH_NativeWindow_NativeWindowHandleOpt ,
25
33
} ;
26
34
use super :: { Surface , SurfaceTexture } ;
27
35
28
36
const SURFACE_GL_TEXTURE_TARGET : GLenum = gl:: TEXTURE_2D ;
29
37
30
38
pub ( crate ) enum SurfaceObjects {
31
- Window { egl_surface : EGLSurface } ,
39
+ HardwareBuffer {
40
+ hardware_buffer : * mut OH_NativeBuffer ,
41
+ egl_image : EGLImageKHR ,
42
+ framebuffer_object : GLuint ,
43
+ texture_object : GLuint ,
44
+ renderbuffers : Renderbuffers ,
45
+ } ,
46
+ Window {
47
+ egl_surface : EGLSurface ,
48
+ } ,
32
49
}
33
50
34
51
/// An OHOS native window.
@@ -58,10 +75,65 @@ impl Device {
58
75
59
76
fn create_generic_surface (
60
77
& mut self ,
61
- _context : & Context ,
62
- _size : & Size2D < i32 > ,
78
+ context : & Context ,
79
+ size : & Size2D < i32 > ,
63
80
) -> Result < Surface , Error > {
64
- Err ( Error :: Unimplemented )
81
+ let _guard = self . temporarily_make_context_current ( context) ?;
82
+
83
+ let usage = OH_NativeBuffer_Usage :: HW_RENDER | OH_NativeBuffer_Usage :: HW_TEXTURE ;
84
+
85
+ let config = OH_NativeBuffer_Config {
86
+ width : size. width ,
87
+ height : size. height ,
88
+ format : OH_NativeBuffer_Format :: RGBA_8888 ,
89
+ usage : usage,
90
+ stride : 10 , // used same magic number as android. I have no idea
91
+ } ;
92
+
93
+ GL_FUNCTIONS . with ( |gl| {
94
+ unsafe {
95
+ let hardware_buffer = OH_NativeBuffer_Alloc ( & config as * const _ ) ;
96
+ assert ! ( !hardware_buffer. is_null( ) , "Failed to create native buffer" ) ;
97
+
98
+ // Create an EGL image, and bind it to a texture.
99
+ let egl_image = self . create_egl_image ( context, hardware_buffer) ;
100
+
101
+ // Initialize and bind the image to the texture.
102
+ let texture_object =
103
+ generic:: egl:: surface:: bind_egl_image_to_gl_texture ( gl, egl_image) ;
104
+
105
+ // Create the framebuffer, and bind the texture to it.
106
+ let framebuffer_object = gl_utils:: create_and_bind_framebuffer (
107
+ gl,
108
+ SURFACE_GL_TEXTURE_TARGET ,
109
+ texture_object,
110
+ ) ;
111
+
112
+ // Bind renderbuffers as appropriate.
113
+ let context_descriptor = self . context_descriptor ( context) ;
114
+ let context_attributes = self . context_descriptor_attributes ( & context_descriptor) ;
115
+ let renderbuffers = Renderbuffers :: new ( gl, size, & context_attributes) ;
116
+ renderbuffers. bind_to_current_framebuffer ( gl) ;
117
+
118
+ debug_assert_eq ! (
119
+ gl. CheckFramebufferStatus ( gl:: FRAMEBUFFER ) ,
120
+ gl:: FRAMEBUFFER_COMPLETE
121
+ ) ;
122
+
123
+ Ok ( Surface {
124
+ size : * size,
125
+ context_id : context. id ,
126
+ objects : SurfaceObjects :: HardwareBuffer {
127
+ hardware_buffer,
128
+ egl_image,
129
+ framebuffer_object,
130
+ texture_object,
131
+ renderbuffers,
132
+ } ,
133
+ destroyed : false ,
134
+ } )
135
+ }
136
+ } )
65
137
}
66
138
67
139
unsafe fn create_window_surface (
@@ -110,14 +182,34 @@ impl Device {
110
182
/// in another context.
111
183
///
112
184
/// Calling this method on a widget surface returns a `WidgetAttached` error.
113
- /// On OpenHarmony, currently only widget surfaces are implemented in surfman, so
114
- /// this method unconditionally returns the `WidgetAttached` error.
115
185
pub fn create_surface_texture (
116
186
& self ,
117
- _context : & mut Context ,
187
+ context : & mut Context ,
118
188
surface : Surface ,
119
189
) -> Result < SurfaceTexture , ( Error , Surface ) > {
120
- Err ( ( Error :: WidgetAttached , surface) )
190
+ unsafe {
191
+ match surface. objects {
192
+ SurfaceObjects :: Window { .. } => return Err ( ( Error :: WidgetAttached , surface) ) ,
193
+ SurfaceObjects :: HardwareBuffer {
194
+ hardware_buffer, ..
195
+ } => GL_FUNCTIONS . with ( |gl| {
196
+ let _guard = match self . temporarily_make_context_current ( context) {
197
+ Ok ( guard) => guard,
198
+ Err ( err) => return Err ( ( err, surface) ) ,
199
+ } ;
200
+
201
+ let local_egl_image = self . create_egl_image ( context, hardware_buffer) ;
202
+ let texture_object =
203
+ generic:: egl:: surface:: bind_egl_image_to_gl_texture ( gl, local_egl_image) ;
204
+ Ok ( SurfaceTexture {
205
+ surface,
206
+ local_egl_image,
207
+ texture_object,
208
+ phantom : PhantomData ,
209
+ } )
210
+ } ) ,
211
+ }
212
+ }
121
213
}
122
214
123
215
/// Displays the contents of a widget surface on screen.
@@ -138,6 +230,7 @@ impl Device {
138
230
egl. SwapBuffers ( self . egl_display , egl_surface) ;
139
231
Ok ( ( ) )
140
232
}
233
+ SurfaceObjects :: HardwareBuffer { .. } => Err ( Error :: NoWidgetAttached ) ,
141
234
}
142
235
} )
143
236
}
@@ -153,6 +246,42 @@ impl Device {
153
246
Ok ( ( ) )
154
247
}
155
248
249
+ #[ allow( non_snake_case) ]
250
+ unsafe fn create_egl_image (
251
+ & self ,
252
+ _: & Context ,
253
+ hardware_buffer : * mut OH_NativeBuffer ,
254
+ ) -> EGLImageKHR {
255
+ // Get the native client buffer.
256
+ // Note: `eglGetNativeClientBufferANDROID` is available starting with OpenHarmony 5.0.
257
+ // Its availability is documented here: https://docs.openharmony.cn/pages/v5.0/en/application-dev/reference/native-lib/egl-symbol.md
258
+ let eglGetNativeClientBufferANDROID =
259
+ EGL_EXTENSION_FUNCTIONS . GetNativeClientBufferANDROID . expect (
260
+ "Where's the `EGL_ANDROID_get_native_client_buffer` \
261
+ extension?",
262
+ ) ;
263
+ let client_buffer = eglGetNativeClientBufferANDROID ( hardware_buffer as * const _ ) ;
264
+ assert ! ( !client_buffer. is_null( ) ) ;
265
+
266
+ // Create the EGL image.
267
+ let egl_image_attributes = [
268
+ EGL_IMAGE_PRESERVED_KHR as EGLint ,
269
+ egl:: TRUE as EGLint ,
270
+ egl:: NONE as EGLint ,
271
+ 0 ,
272
+ ] ;
273
+ let egl_image = ( EGL_EXTENSION_FUNCTIONS . CreateImageKHR ) (
274
+ self . egl_display ,
275
+ egl:: NO_CONTEXT ,
276
+ EGL_NATIVE_BUFFER_ANDROID ,
277
+ client_buffer,
278
+ egl_image_attributes. as_ptr ( ) ,
279
+ ) ;
280
+ assert_ne ! ( egl_image, EGL_NO_IMAGE_KHR ) ;
281
+ info ! ( "surfman created an EGL image succesfully!" ) ;
282
+ egl_image
283
+ }
284
+
156
285
/// Destroys a surface.
157
286
///
158
287
/// The supplied context must be the context the surface is associated with, or this returns
@@ -171,6 +300,34 @@ impl Device {
171
300
172
301
unsafe {
173
302
match surface. objects {
303
+ SurfaceObjects :: HardwareBuffer {
304
+ ref mut hardware_buffer,
305
+ ref mut egl_image,
306
+ ref mut framebuffer_object,
307
+ ref mut texture_object,
308
+ ref mut renderbuffers,
309
+ } => {
310
+ GL_FUNCTIONS . with ( |gl| {
311
+ gl. BindFramebuffer ( gl:: FRAMEBUFFER , 0 ) ;
312
+ gl. DeleteFramebuffers ( 1 , framebuffer_object) ;
313
+ * framebuffer_object = 0 ;
314
+
315
+ renderbuffers. destroy ( gl) ;
316
+
317
+ gl. DeleteTextures ( 1 , texture_object) ;
318
+ * texture_object = 0 ;
319
+
320
+ let egl_display = self . egl_display ;
321
+ let result =
322
+ ( EGL_EXTENSION_FUNCTIONS . DestroyImageKHR ) ( egl_display, * egl_image) ;
323
+ assert_ne ! ( result, egl:: FALSE ) ;
324
+ * egl_image = EGL_NO_IMAGE_KHR ;
325
+
326
+ let res = OH_NativeBuffer_Unreference ( * hardware_buffer) ;
327
+ assert_eq ! ( res, 0 , "OH_NativeBuffer_Unreference failed" ) ;
328
+ * hardware_buffer = ptr:: null_mut ( ) ;
329
+ } ) ;
330
+ }
174
331
SurfaceObjects :: Window {
175
332
ref mut egl_surface,
176
333
} => EGL_FUNCTIONS . with ( |egl| {
@@ -242,6 +399,9 @@ impl Device {
242
399
id : surface. id ( ) ,
243
400
context_id : surface. context_id ,
244
401
framebuffer_object : match surface. objects {
402
+ SurfaceObjects :: HardwareBuffer {
403
+ framebuffer_object, ..
404
+ } => framebuffer_object,
245
405
SurfaceObjects :: Window { .. } => 0 ,
246
406
} ,
247
407
}
@@ -267,6 +427,7 @@ impl NativeWidget {
267
427
impl Surface {
268
428
pub ( super ) fn id ( & self ) -> SurfaceID {
269
429
match self . objects {
430
+ SurfaceObjects :: HardwareBuffer { egl_image, .. } => SurfaceID ( egl_image as usize ) ,
270
431
SurfaceObjects :: Window { egl_surface } => SurfaceID ( egl_surface as usize ) ,
271
432
}
272
433
}
0 commit comments