1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the following conditions are met: |
7 | * Redistributions of source code must retain the above copyright |
8 | notice, this list of conditions and the following disclaimer. |
9 | * Redistributions in binary form must reproduce the above copyright |
10 | notice, this list of conditions and the following disclaimer in the |
11 | documentation and/or other materials provided with the distribution. |
12 | * Neither the name of the copyright holder nor the |
13 | names of its contributors may be used to endorse or promote products |
14 | derived from this software without specific prior written permission. |
15 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | |
28 | #define VCOS_LOG_CATEGORY (&egl_client_log_cat) |
29 | |
30 | #include "interface/khronos/common/khrn_int_common.h" |
31 | |
32 | #include "interface/khronos/common/khrn_client_rpc.h" |
33 | #include "interface/khronos/common/khrn_client_platform.h" |
34 | |
35 | #include "interface/khronos/egl/egl_client_surface.h" |
36 | #include "interface/khronos/egl/egl_client_config.h" |
37 | |
38 | #include "interface/khronos/common/khrn_client.h" |
39 | |
40 | #ifdef KHRONOS_EGL_PLATFORM_OPENWFC |
41 | #include "interface/khronos/wf/wfc_int.h" |
42 | #include "interface/khronos/wf/wfc_client_stream.h" |
43 | #endif |
44 | |
45 | #ifdef RPC_DIRECT |
46 | #include "interface/khronos/egl/egl_int_impl.h" |
47 | #endif |
48 | |
49 | #include <stdlib.h> |
50 | |
51 | |
52 | /* |
53 | surface_pool |
54 | |
55 | cache for a small number of pre-allocated surface objects |
56 | |
57 | Validity: |
58 | surfaces[i] is valid if allocated & (1<<i) |
59 | */ |
60 | |
61 | #define EGL_SURFACE_POOL_SIZE 2 |
62 | static struct |
63 | { |
64 | EGL_SURFACE_T surfaces[EGL_SURFACE_POOL_SIZE]; |
65 | uint32_t allocated; |
66 | } surface_pool; |
67 | |
68 | extern VCOS_LOG_CAT_T egl_client_log_cat; |
69 | |
70 | /* |
71 | EGL_SURFACE_T* egl_surface_pool_alloc(void) |
72 | |
73 | Implementation notes: |
74 | |
75 | We have a small static pool of structures (surface_pool) which we try and allocate out of |
76 | in order to reduce memory fragmentation. When we have run out of space in the pool we |
77 | resort to khrn_platform_malloc. |
78 | |
79 | Preconditions: |
80 | |
81 | Whoever calls this must initialise (or free) the returned structure in order to satisfy the invariant |
82 | on surface_pool. |
83 | |
84 | Postconditions: |
85 | |
86 | Return value is NULL or an uninitialised EGL_SURFACE_T structure, valid until egl_surface_pool_free |
87 | is called. |
88 | */ |
89 | |
90 | static EGL_SURFACE_T* egl_surface_pool_alloc(void) |
91 | { |
92 | int i = 0; |
93 | |
94 | while(surface_pool.allocated & (1 << i)) |
95 | i++; |
96 | |
97 | if (i < EGL_SURFACE_POOL_SIZE) |
98 | { |
99 | surface_pool.allocated |= 1 << i; |
100 | return &surface_pool.surfaces[i]; |
101 | } |
102 | else |
103 | { |
104 | return (EGL_SURFACE_T*)khrn_platform_malloc(sizeof(EGL_SURFACE_T), "EGL_SURFACE_T" ); |
105 | } |
106 | } |
107 | |
108 | static void egl_surface_pool_free(EGL_SURFACE_T* surface) |
109 | { |
110 | unsigned int i = 0; |
111 | |
112 | /* todo: this doesn't belong here */ |
113 | //semaphore now gets destroyed on async callback from VC |
114 | if (surface->avail_buffers_valid) |
115 | khronos_platform_semaphore_destroy(&surface->avail_buffers); |
116 | surface->avail_buffers_valid = false; |
117 | |
118 | i = (unsigned int) (surface - surface_pool.surfaces); |
119 | |
120 | if (i < EGL_SURFACE_POOL_SIZE) |
121 | { |
122 | surface_pool.allocated &= ~(1 << i); |
123 | } |
124 | else |
125 | { |
126 | khrn_platform_free((void*)surface); |
127 | } |
128 | } |
129 | |
130 | /* |
131 | EGLBoolean egl_surface_check_attribs_window(const EGLint *attrib_list, EGLBoolean *linear, EGLBoolean *premult, EGLBoolean *single) |
132 | |
133 | TODO: are we actually supposed to validate our parameters and generate an |
134 | error if they're wrong? I can't find an explicit mention in the spec about it. |
135 | (except for EGL_WIDTH and EGL_HEIGHT in pbuffer) |
136 | |
137 | Preconditions: |
138 | |
139 | type in {WINDOW, PBUFFER, PIXMAP} |
140 | attrib_list is NULL or a pointer to an EGL_NONE-terminated list of attribute/value pairs |
141 | linear, premult are NULL or valid pointers |
142 | If type == WINDOW then single is NULL or a valid pointer |
143 | If type == PBUFFER then width, height, largest_pbuffer, texture_format, texture_target, mipmap_texture are NULL or valid pointers |
144 | |
145 | Postconditions: |
146 | |
147 | - |
148 | */ |
149 | |
150 | bool egl_surface_check_attribs( |
151 | EGL_SURFACE_TYPE_T type, |
152 | const EGLint *attrib_list, |
153 | bool *linear, |
154 | bool *premult, |
155 | bool *single, |
156 | int *width, |
157 | int *height, |
158 | bool *largest_pbuffer, |
159 | EGLenum *texture_format, |
160 | EGLenum *texture_target, |
161 | bool *mipmap_texture |
162 | ) |
163 | { |
164 | if (!attrib_list) |
165 | return true; |
166 | |
167 | while (*attrib_list != EGL_NONE) { |
168 | int name = *attrib_list++; |
169 | int value = *attrib_list++; |
170 | |
171 | switch (name) { |
172 | case EGL_VG_COLORSPACE: |
173 | if (value != EGL_VG_COLORSPACE_sRGB && value != EGL_VG_COLORSPACE_LINEAR) |
174 | return false; |
175 | if (value == EGL_VG_COLORSPACE_LINEAR && linear != NULL) |
176 | *linear = true; |
177 | break; |
178 | case EGL_VG_ALPHA_FORMAT: |
179 | if (value != EGL_VG_ALPHA_FORMAT_NONPRE && value != EGL_VG_ALPHA_FORMAT_PRE) |
180 | return false; |
181 | if (value == EGL_VG_ALPHA_FORMAT_PRE && premult != NULL) |
182 | *premult = true; |
183 | break; |
184 | |
185 | /* For WINDOW types only */ |
186 | case EGL_RENDER_BUFFER: |
187 | if (type != WINDOW || (value != EGL_SINGLE_BUFFER && value != EGL_BACK_BUFFER)) |
188 | return false; |
189 | if (value == EGL_SINGLE_BUFFER && single != NULL) |
190 | *single = true; |
191 | break; |
192 | |
193 | /* For PBUFFER types only */ |
194 | case EGL_WIDTH: |
195 | if (type != PBUFFER || value < 0) |
196 | return false; |
197 | if (width != NULL) |
198 | *width = value; |
199 | break; |
200 | case EGL_HEIGHT: |
201 | if (type != PBUFFER || value < 0) |
202 | return false; |
203 | if (height != NULL) |
204 | *height = value; |
205 | break; |
206 | case EGL_LARGEST_PBUFFER: |
207 | if (type != PBUFFER || (value != EGL_FALSE && value != EGL_TRUE)) |
208 | return false; |
209 | if (largest_pbuffer != NULL) |
210 | *largest_pbuffer = value; |
211 | break; |
212 | case EGL_TEXTURE_FORMAT: |
213 | if (type != PBUFFER || (value != EGL_NO_TEXTURE && value != EGL_TEXTURE_RGB && value != EGL_TEXTURE_RGBA)) |
214 | return false; |
215 | if (texture_format != NULL) |
216 | *texture_format = value; |
217 | break; |
218 | case EGL_TEXTURE_TARGET: |
219 | if (type != PBUFFER || (value != EGL_NO_TEXTURE && value != EGL_TEXTURE_2D)) |
220 | return false; |
221 | if (texture_target != NULL) |
222 | *texture_target = value; |
223 | break; |
224 | case EGL_MIPMAP_TEXTURE: |
225 | if (type != PBUFFER || (value != EGL_FALSE && value != EGL_TRUE)) |
226 | return false; |
227 | if (mipmap_texture != NULL) |
228 | *mipmap_texture = value; |
229 | break; |
230 | default: |
231 | return false; |
232 | } |
233 | } |
234 | |
235 | return true; |
236 | } |
237 | |
238 | /* |
239 | EGL_SURFACE_T *egl_surface_create( |
240 | EGLSurface name, |
241 | EGL_SURFACE_TYPE_T type, |
242 | EGL_SURFACE_COLORSPACE_T colorspace, |
243 | EGL_SURFACE_ALPHAFORMAT_T alphaformat, |
244 | uint32_t buffers, |
245 | uint32_t width, |
246 | uint32_t height, |
247 | EGLConfig config, |
248 | EGLNativeWindowType win, |
249 | uint32_t serverwin, |
250 | bool largest_pbuffer, |
251 | bool mipmap_texture, |
252 | EGLenum texture_format, |
253 | EGLenum texture_target, |
254 | EGLNativePixmapType pixmap, |
255 | const uint32_t *pixmap_server_handle) |
256 | |
257 | Implementation notes: |
258 | |
259 | TODO: respect largest_pbuffer? |
260 | |
261 | Preconditions: |
262 | type in {WINDOW,PBUFFER,PIXMAP} |
263 | colorspace in {SRGB,LINEAR} |
264 | alphaformat in {NONPRE,PRE} |
265 | 1 <= buffers <= EGL_MAX_BUFFERS |
266 | 0 < width, 0 < height |
267 | If !largest_pbuffer then width <= EGL_CONFIG_MAX_WIDTH, height <= EGL_CONFIG_MAX_HEIGHT |
268 | config is a valid EGL config |
269 | |
270 | If type == WINDOW then |
271 | win is a valid client-side handle to window W |
272 | serverwin is a valid server-side handle to window W |
273 | else |
274 | win == 0 |
275 | serverwin == PLATFORM_WIN_NONE |
276 | |
277 | If type == PBBUFFER then |
278 | texture_format in {EGL_NO_TEXTURE, EGL_TEXTURE_RGB, EGL_TEXTURE_RGBA} |
279 | texture_target in {EGL_NO_TEXTURE, EGL_TEXTURE_2D} |
280 | else |
281 | largest_pbuffer == mipmap_texture == false |
282 | texture_format == texture_target == EGL_NO_TEXTURE |
283 | |
284 | If type == PIXMAP then |
285 | pixmap is a valid client-side handle to pixmap P |
286 | If pixmap is a server-side pixmap then |
287 | pixmap_server_handle is a pointer to two elements, representing a valid server-side handle to pixmap P |
288 | else |
289 | pixmap_server_handle == 0 |
290 | else |
291 | pixmap == pixmap_server_handle == 0 |
292 | |
293 | Postconditions: |
294 | Return value is NULL or an EGL_SURFACE_T structure, valid until egl_surface_free is called |
295 | |
296 | Invariants preserved: |
297 | All invaraints on EGL_SURFACE_T |
298 | */ |
299 | |
300 | EGL_SURFACE_T *egl_surface_create( |
301 | EGLSurface name, |
302 | EGL_SURFACE_TYPE_T type, |
303 | EGL_SURFACE_COLORSPACE_T colorspace, |
304 | EGL_SURFACE_ALPHAFORMAT_T alphaformat, |
305 | uint32_t buffers, |
306 | uint32_t width, |
307 | uint32_t height, |
308 | EGLConfig config, |
309 | EGLNativeWindowType win, |
310 | uint32_t serverwin, |
311 | bool largest_pbuffer, |
312 | bool texture_compatibility, |
313 | bool mipmap_texture, |
314 | EGLenum texture_format, |
315 | EGLenum texture_target, |
316 | EGLNativePixmapType pixmap, |
317 | const uint32_t *pixmap_server_handle) |
318 | { |
319 | KHRN_IMAGE_FORMAT_T color; |
320 | KHRN_IMAGE_FORMAT_T depth; |
321 | KHRN_IMAGE_FORMAT_T mask; |
322 | KHRN_IMAGE_FORMAT_T multi; |
323 | uint32_t configid; |
324 | uint32_t sem_name; |
325 | EGLint config_depth_bits; |
326 | EGLint config_stencil_bits; |
327 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
328 | |
329 | EGL_SURFACE_T *surface = egl_surface_pool_alloc(); |
330 | |
331 | //vcos_assert(width > 0 && height > 0); |
332 | vcos_assert((width <= EGL_CONFIG_MAX_WIDTH && height <= EGL_CONFIG_MAX_HEIGHT) || largest_pbuffer); |
333 | |
334 | if (!surface) { |
335 | return 0; |
336 | } |
337 | |
338 | /* TODO: respect largest_pbuffer? */ |
339 | |
340 | surface->name = name; |
341 | surface->type = type; |
342 | |
343 | surface->colorspace = colorspace; |
344 | surface->alphaformat = alphaformat; |
345 | |
346 | surface->config = config; |
347 | surface->win = win; |
348 | surface->width = width; |
349 | surface->height = height; |
350 | surface->swap_interval = 1; |
351 | |
352 | surface->base_width = width; |
353 | surface->base_height = height; |
354 | |
355 | surface->internal_handle = serverwin; |
356 | |
357 | surface->largest_pbuffer = largest_pbuffer; |
358 | surface->mipmap_texture = mipmap_texture; |
359 | surface->mipmap_level = 0; |
360 | surface->texture_format = texture_format; |
361 | surface->texture_target = texture_target; |
362 | surface->pixmap = pixmap; |
363 | surface->pixmap_server_handle[0] = 0; |
364 | surface->pixmap_server_handle[1] = (uint32_t)-1; |
365 | surface->server_owned = false; |
366 | surface->swap_behavior = buffers > 1 ? EGL_BUFFER_DESTROYED : EGL_BUFFER_PRESERVED; |
367 | surface->multisample_resolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT; |
368 | |
369 | surface->context_binding_count = 0; |
370 | surface->is_destroyed = false; |
371 | |
372 | #if EGL_KHR_lock_surface |
373 | surface->is_locked = false; |
374 | surface->mapped_buffer = 0; |
375 | #endif |
376 | |
377 | configid = egl_config_to_id(config); |
378 | color = egl_config_get_color_format(configid); |
379 | if (texture_compatibility) { color = khrn_image_to_tf_format(color); } |
380 | if (alphaformat == PRE) { color = (KHRN_IMAGE_FORMAT_T)(color | IMAGE_FORMAT_PRE); } |
381 | if (colorspace == LINEAR) { color = (KHRN_IMAGE_FORMAT_T)(color | IMAGE_FORMAT_LIN); } |
382 | depth = egl_config_get_depth_format(configid); |
383 | mask = egl_config_get_mask_format(configid); |
384 | multi = egl_config_get_multisample_format(configid); |
385 | |
386 | /* Find depth and stencil bits from chosen config (these may NOT be the same as the underlying format!) */ |
387 | egl_config_get_attrib(configid, EGL_DEPTH_SIZE, &config_depth_bits); |
388 | egl_config_get_attrib(configid, EGL_STENCIL_SIZE, &config_stencil_bits); |
389 | |
390 | vcos_assert(color != IMAGE_FORMAT_INVALID); |
391 | |
392 | #ifdef KHRONOS_EGL_PLATFORM_OPENWFC |
393 | // Create stream for this window |
394 | if(type != PBUFFER) |
395 | { |
396 | WFCNativeStreamType stream = (WFCNativeStreamType) surface->internal_handle; |
397 | vcos_assert(stream != WFC_INVALID_HANDLE); |
398 | uint32_t failure = wfc_stream_create(stream, WFC_STREAM_FLAGS_EGL); |
399 | vcos_log_trace("Creating stream with handle %X" , stream); |
400 | vcos_assert(failure == 0); |
401 | } // if |
402 | #endif |
403 | |
404 | surface->buffers = buffers; |
405 | |
406 | if (pixmap_server_handle) { |
407 | vcos_assert(type == PIXMAP); |
408 | surface->pixmap_server_handle[0] = pixmap_server_handle[0]; |
409 | surface->pixmap_server_handle[1] = pixmap_server_handle[1]; |
410 | surface->serverbuffer = RPC_UINT_RES(RPC_CALL7_RES(eglIntCreateWrappedSurface_impl, |
411 | thread, |
412 | EGLINTCREATEWRAPPEDSURFACE_ID, |
413 | RPC_UINT(pixmap_server_handle[0]), |
414 | RPC_UINT(pixmap_server_handle[1]), |
415 | RPC_UINT(depth), |
416 | RPC_UINT(mask), |
417 | RPC_UINT(multi), |
418 | RPC_UINT(config_depth_bits), |
419 | RPC_UINT(config_stencil_bits))); |
420 | surface->avail_buffers_valid = false; |
421 | } else { |
422 | #ifdef __SYMBIAN32__ |
423 | uint32_t nbuff = 0; |
424 | surface->avail_buffers_valid = 0; |
425 | |
426 | if (surface->buffers > 1) { |
427 | uint64_t pid = rpc_get_client_id(thread); |
428 | int sem[3] = { (int)pid, (int)(pid >> 32), (int)name }; |
429 | if (khronos_platform_semaphore_create(&surface->avail_buffers, sem, surface->buffers) == KHR_SUCCESS) |
430 | surface->avail_buffers_valid = 1; |
431 | nbuff = (int)surface->avail_buffers; |
432 | } |
433 | |
434 | if (surface->buffers == 1 || surface->avail_buffers_valid) { |
435 | uint32_t results[3]; |
436 | |
437 | RPC_CALL15_OUT_CTRL(eglIntCreateSurface_impl, |
438 | thread, |
439 | EGLINTCREATESURFACE_ID, |
440 | RPC_UINT(serverwin), |
441 | RPC_UINT(buffers), |
442 | RPC_UINT(width), |
443 | RPC_UINT(height), |
444 | RPC_UINT(color), |
445 | RPC_UINT(depth), |
446 | RPC_UINT(mask), |
447 | RPC_UINT(multi), |
448 | RPC_UINT(largest_pbuffer), |
449 | RPC_UINT(mipmap_texture), |
450 | RPC_UINT(config_depth_bits), |
451 | RPC_UINT(config_stencil_bits), |
452 | RPC_UINT((int)nbuff), |
453 | RPC_UINT(type), |
454 | results); |
455 | #else |
456 | surface->avail_buffers_valid = false; |
457 | |
458 | sem_name = KHRN_NO_SEMAPHORE; |
459 | #ifndef KHRONOS_EGL_PLATFORM_OPENWFC |
460 | if (surface->buffers > 1) { |
461 | uint64_t pid = rpc_get_client_id(thread); |
462 | int sem[3]; |
463 | sem[0] = (int)pid; sem[1] = (int)(pid >> 32); sem[2] = (int)name; |
464 | |
465 | sem_name = (int)name; |
466 | if (khronos_platform_semaphore_create(&surface->avail_buffers, sem, surface->buffers) == KHR_SUCCESS) |
467 | surface->avail_buffers_valid = true; |
468 | } |
469 | if (sem_name == KHRN_NO_SEMAPHORE || surface->avail_buffers_valid) { |
470 | #else |
471 | sem_name = (uint32_t)surface->internal_handle; |
472 | vcos_log_trace("Surface create has semaphore %X" , sem_name); |
473 | #endif |
474 | uint32_t results[3]; |
475 | |
476 | RPC_CALL15_OUT_CTRL(eglIntCreateSurface_impl, |
477 | thread, |
478 | EGLINTCREATESURFACE_ID, |
479 | RPC_UINT(serverwin), |
480 | RPC_UINT(buffers), |
481 | RPC_UINT(width), |
482 | RPC_UINT(height), |
483 | RPC_UINT(color), |
484 | RPC_UINT(depth), |
485 | RPC_UINT(mask), |
486 | RPC_UINT(multi), |
487 | RPC_UINT(largest_pbuffer), |
488 | RPC_UINT(mipmap_texture), |
489 | RPC_UINT(config_depth_bits), |
490 | RPC_UINT(config_stencil_bits), |
491 | RPC_UINT(sem_name), |
492 | RPC_UINT(type), |
493 | results); |
494 | #endif |
495 | surface->width = results[0]; |
496 | surface->height = results[1]; |
497 | surface->serverbuffer = results[2]; |
498 | #ifndef KHRONOS_EGL_PLATFORM_OPENWFC |
499 | } else { |
500 | surface->serverbuffer = 0; |
501 | } |
502 | #endif |
503 | } |
504 | |
505 | if (surface->serverbuffer) |
506 | return surface; |
507 | else { |
508 | /* Server failed to create a surface due to out-of-memory or |
509 | we failed to create the named semaphore object. */ |
510 | egl_surface_pool_free(surface); |
511 | return 0; |
512 | } |
513 | } |
514 | |
515 | #ifndef NO_OPENVG |
516 | |
517 | /* Either returns a valid EGL_SURFACE_T, or returns null and sets error appropriately */ |
518 | |
519 | EGL_SURFACE_T *egl_surface_from_vg_image( |
520 | VGImage vg_handle, |
521 | EGLSurface name, |
522 | EGLConfig config, |
523 | EGLBoolean largest_pbuffer, |
524 | EGLBoolean mipmap_texture, |
525 | EGLenum texture_format, |
526 | EGLenum texture_target, |
527 | EGLint *error) |
528 | { |
529 | KHRN_IMAGE_FORMAT_T color; |
530 | KHRN_IMAGE_FORMAT_T depth; |
531 | KHRN_IMAGE_FORMAT_T mask; |
532 | KHRN_IMAGE_FORMAT_T multi; |
533 | EGLint config_depth_bits; |
534 | EGLint config_stencil_bits; |
535 | uint32_t results[5]; |
536 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
537 | |
538 | EGL_SURFACE_T *surface = egl_surface_pool_alloc(); |
539 | |
540 | if (!surface) { |
541 | *error = EGL_BAD_ALLOC; |
542 | return 0; |
543 | } |
544 | |
545 | /* TODO: respect largest_pbuffer? */ |
546 | |
547 | surface->name = name; |
548 | surface->type = PBUFFER; |
549 | |
550 | surface->config = config; |
551 | surface->win = 0; |
552 | surface->swap_interval = 1; |
553 | |
554 | surface->largest_pbuffer = largest_pbuffer; |
555 | surface->mipmap_texture = mipmap_texture; |
556 | surface->mipmap_level = 0; |
557 | surface->texture_format = texture_format; |
558 | surface->texture_target = texture_target; |
559 | surface->pixmap = 0; |
560 | surface->pixmap_server_handle[0] = 0; |
561 | surface->pixmap_server_handle[1] = (uint32_t)-1; |
562 | surface->server_owned = false; |
563 | |
564 | surface->context_binding_count = 0; |
565 | surface->is_destroyed = false; |
566 | |
567 | #if EGL_KHR_lock_surface |
568 | surface->is_locked = false; |
569 | surface->mapped_buffer = 0; |
570 | #endif |
571 | |
572 | color = egl_config_get_color_format((int)(size_t)config - 1); |
573 | depth = egl_config_get_depth_format((int)(size_t)config - 1); |
574 | mask = egl_config_get_mask_format((int)(size_t)config - 1); |
575 | multi = egl_config_get_multisample_format((int)(size_t)config - 1); |
576 | |
577 | /* Find depth and stencil bits from chosen config (these may NOT be the same as the underlying format!) */ |
578 | egl_config_get_attrib((int)(size_t)config - 1, EGL_DEPTH_SIZE, &config_depth_bits); |
579 | egl_config_get_attrib((int)(size_t)config - 1, EGL_STENCIL_SIZE, &config_stencil_bits); |
580 | |
581 | vcos_assert(color != IMAGE_FORMAT_INVALID); |
582 | |
583 | surface->buffers = 1; |
584 | |
585 | RPC_CALL9_OUT_CTRL(eglIntCreatePbufferFromVGImage_impl, |
586 | thread, |
587 | EGLINTCREATEPBUFFERFROMVGIMAGE_ID, |
588 | RPC_UINT(vg_handle), |
589 | RPC_UINT(color), |
590 | RPC_UINT(depth), |
591 | RPC_UINT(mask), |
592 | RPC_UINT(multi), |
593 | RPC_UINT(mipmap_texture), |
594 | RPC_UINT(config_depth_bits), |
595 | RPC_UINT(config_stencil_bits), |
596 | results); |
597 | |
598 | surface->avail_buffers_valid = false; |
599 | |
600 | if (results[0]) { |
601 | KHRN_IMAGE_FORMAT_T format = (KHRN_IMAGE_FORMAT_T)results[4]; |
602 | |
603 | surface->serverbuffer = results[0]; |
604 | surface->width = results[2]; |
605 | surface->height = results[3]; |
606 | |
607 | /* TODO: picking apart image formats like this seems messy */ |
608 | surface->colorspace = (format & IMAGE_FORMAT_LIN) ? LINEAR : SRGB; |
609 | surface->alphaformat = (format & IMAGE_FORMAT_PRE) ? PRE : NONPRE; |
610 | *error = EGL_SUCCESS; |
611 | return surface; |
612 | } else { |
613 | *error = results[1]; |
614 | egl_surface_pool_free(surface); |
615 | return 0; |
616 | } |
617 | } |
618 | |
619 | #endif /* NO_OPENVG */ |
620 | |
621 | /* |
622 | void egl_surface_free(EGL_SURFACE_T *surface) |
623 | |
624 | Preconditions: |
625 | |
626 | surface is a valid EGL_SURFACE_T returned from egl_surface_create or egl_surface_from_vg_image |
627 | |
628 | Postconditions: |
629 | |
630 | surface is freed and any associated server-side resources are dereferenced. |
631 | */ |
632 | |
633 | void egl_surface_free(EGL_SURFACE_T *surface) |
634 | { |
635 | CLIENT_THREAD_STATE_T *thread; |
636 | |
637 | vcos_log_trace("egl_surface_free" ); |
638 | |
639 | thread = CLIENT_GET_THREAD_STATE(); |
640 | |
641 | if( surface->type == WINDOW ) { |
642 | vcos_log_trace("egl_surface_free: calling platform_destroy_winhandle..." ); |
643 | platform_destroy_winhandle( surface->win, surface->internal_handle ); |
644 | } |
645 | /* return value ignored -- read performed to ensure blocking. we want this to |
646 | * block so clients can safely destroy the surface's window as soon as the |
647 | * egl call that destroys the surface returns (usually eglDestroySurface, but |
648 | * could be eg eglMakeCurrent) */ |
649 | vcos_log_trace("egl_surface_free: calling eglIntDestroySurface_impl via RPC...; " |
650 | "thread = 0x%X; serverbuffer = 0x%X" , |
651 | (uint32_t) thread, (uint32_t) surface->serverbuffer); |
652 | (void)RPC_INT_RES(RPC_CALL1_RES(eglIntDestroySurface_impl, |
653 | thread, |
654 | EGLINTDESTROYSURFACE_ID, |
655 | RPC_UINT(surface->serverbuffer))); |
656 | |
657 | #ifdef KHRONOS_EGL_PLATFORM_OPENWFC |
658 | if(surface->internal_handle != PLATFORM_WIN_NONE) // TODO what about pbuffers? |
659 | { |
660 | vcos_log_trace("egl_surface_free: calling wfc_stream_destroy..." ); |
661 | wfc_stream_destroy((WFCNativeStreamType) surface->internal_handle); |
662 | } |
663 | #endif |
664 | |
665 | vcos_log_trace("egl_surface_free: calling egl_surface_pool_free..." ); |
666 | egl_surface_pool_free(surface); |
667 | |
668 | vcos_log_trace("egl_surface_free: end" ); |
669 | } |
670 | |
671 | EGLint egl_surface_get_render_buffer(EGL_SURFACE_T *surface) |
672 | { |
673 | switch (surface->type) { |
674 | case WINDOW: |
675 | if (surface->buffers == 1) |
676 | return EGL_SINGLE_BUFFER; |
677 | else |
678 | return EGL_BACK_BUFFER; |
679 | case PBUFFER: |
680 | return EGL_BACK_BUFFER; |
681 | case PIXMAP: |
682 | return EGL_SINGLE_BUFFER; |
683 | default: |
684 | UNREACHABLE(); |
685 | return EGL_NONE; |
686 | } |
687 | } |
688 | |
689 | EGLBoolean egl_surface_get_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint *value) |
690 | { |
691 | switch (attrib) { |
692 | case EGL_VG_ALPHA_FORMAT: |
693 | if (surface->alphaformat == NONPRE) |
694 | *value = EGL_VG_ALPHA_FORMAT_NONPRE; |
695 | else |
696 | *value = EGL_VG_ALPHA_FORMAT_PRE; |
697 | return EGL_TRUE; |
698 | case EGL_VG_COLORSPACE: |
699 | if (surface->colorspace == SRGB) |
700 | *value = EGL_VG_COLORSPACE_sRGB; |
701 | else |
702 | *value = EGL_VG_COLORSPACE_LINEAR; |
703 | return EGL_TRUE; |
704 | case EGL_CONFIG_ID: |
705 | *value = (EGLint)(size_t)surface->config; |
706 | return EGL_TRUE; |
707 | case EGL_HEIGHT: |
708 | *value = surface->height; |
709 | return EGL_TRUE; |
710 | case EGL_HORIZONTAL_RESOLUTION: |
711 | case EGL_VERTICAL_RESOLUTION: |
712 | *value = EGL_UNKNOWN; |
713 | return EGL_TRUE; |
714 | case EGL_LARGEST_PBUFFER: |
715 | // For a window or pixmap surface, the contents of value are not modified. |
716 | if (surface->type == PBUFFER) |
717 | *value = surface->largest_pbuffer; |
718 | return EGL_TRUE; |
719 | case EGL_MIPMAP_TEXTURE: |
720 | // Querying EGL_MIPMAP_TEXTURE for a non-pbuffer surface is not |
721 | // an error, but value is not modified. |
722 | if (surface->type == PBUFFER) |
723 | *value = surface->mipmap_texture; |
724 | return EGL_TRUE; |
725 | case EGL_MIPMAP_LEVEL: |
726 | // Querying EGL_MIPMAP_LEVEL for a non-pbuffer surface is not |
727 | // an error, but value is not modified. |
728 | if (surface->type == PBUFFER) |
729 | *value = surface->mipmap_level; |
730 | return EGL_TRUE; |
731 | case EGL_PIXEL_ASPECT_RATIO: |
732 | *value = EGL_DISPLAY_SCALING; |
733 | return EGL_TRUE; |
734 | case EGL_RENDER_BUFFER: |
735 | *value = egl_surface_get_render_buffer(surface); |
736 | return EGL_TRUE; |
737 | case EGL_SWAP_BEHAVIOR: |
738 | *value = surface->swap_behavior; |
739 | return EGL_TRUE; |
740 | case EGL_MULTISAMPLE_RESOLVE: |
741 | *value = surface->multisample_resolve; |
742 | return EGL_TRUE; |
743 | case EGL_TEXTURE_FORMAT: |
744 | // Querying EGL_TEXTURE_FORMAT for a non-pbuffer surface is not |
745 | // an error, but value is not modified. |
746 | if (surface->type == PBUFFER) |
747 | *value = surface->texture_format; |
748 | return EGL_TRUE; |
749 | case EGL_TEXTURE_TARGET: |
750 | // Querying EGL_TEXTURE_TARGET for a non-pbuffer surface is not |
751 | // an error, but value is not modified. |
752 | if (surface->type == PBUFFER) |
753 | *value = surface->texture_target; |
754 | return EGL_TRUE; |
755 | case EGL_WIDTH: |
756 | *value = surface->width; |
757 | return EGL_TRUE; |
758 | default: |
759 | return EGL_FALSE; |
760 | } |
761 | } |
762 | |
763 | EGLint egl_surface_set_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint value) |
764 | { |
765 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
766 | switch (attrib) { |
767 | case EGL_MIPMAP_LEVEL: |
768 | if (surface->type == PBUFFER) { |
769 | RPC_CALL2(eglIntSelectMipmap_impl, |
770 | thread, |
771 | EGLINTSELECTMIPMAP_ID, |
772 | RPC_UINT(surface->serverbuffer), |
773 | RPC_INT(value)); |
774 | |
775 | surface->mipmap_level = value; |
776 | } |
777 | return EGL_SUCCESS; |
778 | case EGL_SWAP_BEHAVIOR: |
779 | switch (value) { |
780 | case EGL_BUFFER_PRESERVED: |
781 | case EGL_BUFFER_DESTROYED: |
782 | surface->swap_behavior = value; |
783 | return EGL_SUCCESS; |
784 | default: |
785 | return EGL_BAD_PARAMETER; |
786 | } |
787 | case EGL_MULTISAMPLE_RESOLVE: |
788 | switch (value) { |
789 | case EGL_MULTISAMPLE_RESOLVE_DEFAULT: |
790 | case EGL_MULTISAMPLE_RESOLVE_BOX: |
791 | surface->multisample_resolve = value; |
792 | return EGL_SUCCESS; |
793 | default: |
794 | return EGL_BAD_PARAMETER; |
795 | } |
796 | default: |
797 | return EGL_BAD_ATTRIBUTE; |
798 | } |
799 | } |
800 | |
801 | #if EGL_KHR_lock_surface |
802 | |
803 | EGLint egl_surface_get_mapped_buffer_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint *value) |
804 | { |
805 | KHRN_IMAGE_FORMAT_T format; |
806 | bool is565; |
807 | |
808 | vcos_assert(surface); |
809 | |
810 | if (attrib == EGL_BITMAP_POINTER_KHR || attrib == EGL_BITMAP_PITCH_KHR) { |
811 | // Querying either of these causes the buffer to be mapped (if it isn't already) |
812 | // They also require that the surface is locked |
813 | |
814 | if (!surface->is_locked) { |
815 | return EGL_BAD_ACCESS; // TODO is this the right error? |
816 | } |
817 | |
818 | if (!surface->mapped_buffer) { |
819 | uint32_t size; |
820 | void *buffer; |
821 | format = egl_config_get_mapped_format((int)((intptr_t)surface->config - 1)); // type juggling to avoid pointer truncation warnings |
822 | size = khrn_image_get_size(format, surface->width, surface->height); |
823 | buffer = khrn_platform_malloc(size, "EGL_SURFACE_T.mapped_buffer" ); |
824 | |
825 | if (!buffer) { |
826 | return EGL_BAD_ALLOC; |
827 | } |
828 | |
829 | surface->mapped_buffer = buffer; |
830 | } |
831 | } |
832 | |
833 | if (!egl_config_is_lockable((int)((intptr_t)surface->config-1))) { // type juggling to avoid pointer truncation warnings |
834 | // Calling any of these on unlockable surfaces is allowed but returns undefined results |
835 | *value = 0; |
836 | return EGL_SUCCESS; |
837 | } |
838 | |
839 | format = egl_config_get_mapped_format((int)((intptr_t)surface->config-1)); // type juggling to avoid pointer truncation warnings |
840 | vcos_assert(format == RGB_565_RSO || format == ARGB_8888_RSO); |
841 | is565 = (format == RGB_565_RSO); // else 888 |
842 | |
843 | switch (attrib) { |
844 | case EGL_BITMAP_POINTER_KHR: |
845 | *value = (EGLint)(intptr_t)surface->mapped_buffer; // type juggling to avoid pointer truncation warnings |
846 | return EGL_SUCCESS; |
847 | case EGL_BITMAP_PITCH_KHR: |
848 | *value = khrn_image_get_stride(format, surface->width); |
849 | return EGL_SUCCESS; |
850 | case EGL_BITMAP_ORIGIN_KHR: |
851 | *value = EGL_LOWER_LEFT_KHR; // TODO: is this correct? |
852 | return EGL_SUCCESS; |
853 | case EGL_BITMAP_PIXEL_RED_OFFSET_KHR: |
854 | *value = is565 ? 11 : 0; // TODO: I've probably got these wrong too |
855 | return EGL_SUCCESS; |
856 | case EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR: |
857 | *value = is565 ? 5 : 8; |
858 | return EGL_SUCCESS; |
859 | case EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR: |
860 | *value = is565 ? 0 : 16; |
861 | return EGL_SUCCESS; |
862 | case EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR: |
863 | *value = is565 ? 0 : 24; |
864 | return EGL_SUCCESS; |
865 | case EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR: |
866 | *value = 0; |
867 | return EGL_SUCCESS; |
868 | default: |
869 | UNREACHABLE(); |
870 | return EGL_BAD_PARAMETER; |
871 | } |
872 | } |
873 | #endif |
874 | |
875 | |
876 | /* |
877 | void egl_surface_maybe_free(EGL_SURFACE_T *surface) |
878 | |
879 | Frees a surface together with its server-side resources if: |
880 | - it has been destroyed |
881 | - it is no longer current |
882 | |
883 | Implementation notes: |
884 | |
885 | - |
886 | |
887 | Preconditions: |
888 | |
889 | surface is a valid pointer |
890 | |
891 | Postconditions: |
892 | |
893 | Either: |
894 | - surface->is_destroyed is false (we don't change this), or |
895 | - surface->context_binding_count > 0, or |
896 | - surface has been deleted. |
897 | |
898 | Invariants preserved: |
899 | |
900 | - |
901 | |
902 | Invariants used: |
903 | |
904 | - |
905 | */ |
906 | |
907 | void egl_surface_maybe_free(EGL_SURFACE_T *surface) |
908 | { |
909 | vcos_assert(surface); |
910 | |
911 | if (!surface->is_destroyed) |
912 | return; |
913 | |
914 | if (surface->context_binding_count) |
915 | return; |
916 | |
917 | egl_surface_free(surface); |
918 | } |
919 | |