1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON 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
25SOFTWARE, 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
62static struct
63{
64 EGL_SURFACE_T surfaces[EGL_SURFACE_POOL_SIZE];
65 uint32_t allocated;
66} surface_pool;
67
68extern 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
90static 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
108static 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
150bool 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
300EGL_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
519EGL_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
633void 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
671EGLint 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
689EGLBoolean 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
763EGLint 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
803EGLint 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
907void 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