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/*
29 Global preconditions?
30
31 Server is up (needed by RPC_CALL[n]_RES)
32
33
34 Spec ambiguity:
35
36 What should we do if eglGetError is called twice? Currently we reset the error to EGL_SUCCESS.
37
38 eglGetConfigs:
39 "The number of configurations is returned in num config"
40 We assume this refers to the number of configurations returned, rather than the total number of
41 configurations available. (These are different values if config_size is too small).
42
43 eglChooseConfig:
44 Fail if the same attribute is specified more than once?
45 (I can't find anything in the spec saying what to do in this case)
46
47 In general, which attribute values are accepted and which raise
48 EGL_BAD_ATTRIBUTE is vague.
49
50 In particular, what do we do about the "ignored" and conditionally
51 ignored ones?
52
53 Currently ignoring ("ignored"):
54 case EGL_MAX_PBUFFER_HEIGHT:
55 case EGL_MAX_PBUFFER_PIXELS:
56 case EGL_MAX_PBUFFER_WIDTH:
57 case EGL_NATIVE_VISUAL_ID:
58
59 Currently not ignoring ("conditionally ignored")
60 case EGL_TRANSPARENT_BLUE_VALUE:
61 case EGL_TRANSPARENT_GREEN_VALUE:
62 case EGL_TRANSPARENT_RED_VALUE:
63
64 Currently ignoring ("conditionally ignored")
65 case EGL_NATIVE_VISUAL_TYPE:
66
67 The following sentences in the spec seem to contradict each other:
68 "If EGL_MATCH_NATIVE_PIXMAP is specified in attrib list, it must be followed
69by an attribute value"
70
71 "If EGL_DONT_CARE is specified as an attribute value, then the
72 attribute will not be checked. EGL_DONT_CARE may be specified for all attributes
73 except EGL_LEVEL."
74
75 In addition, EGL_NONE is listed as the default match value for EGL_MATCH_NATIVE_PIXMAP.
76 What happens if EGL_DONT_CARE or EGL_NONE is a valid native pixmap value?
77
78 What we actually do is we always treat the value supplied with EGL_MATCH_NATIVE_PIXMAP
79 as a valid handle (and fail if it's invalid), and ignore it only if it's not in the list
80 at all.
81
82
83 EGL_MATCH_NATIVE_PIXMAP: todo: we'll set thread->error to something like EGL_BAD_ATTRIBUTE; should we be setting it to EGL_BAD_NATIVE_PIXMAP?
84 What is EGL_PRESERVED_RESOURCES?
85
86
87
88 Do we need to do anything for EGL_LEVEL?
89
90 What is EGL_PRESERVED_RESOURCES?
91 What exactly are EGL_NATIVE_VISUAL_ID, EGL_NATIVE_VISUAL_TYPE?
92
93
94 Implementation notes:
95
96 We only support one display. This is assumed to have a native display_id
97 of 0 (==EGL_DEFAULT_DISPLAY) and an EGLDisplay id of 1
98
99 All EGL client functions preserve the invariant (CLIENT_THREAD_STATE_ERROR)
100
101 It would be nice for the EGL version to only be defined in one place (rather than both eglInitialize and eglQueryString).
102
103 We allow implicit casts from bool to EGLint
104
105
106 We make the following assumptions:
107
108 EGL_CONFIG_CAVEAT (all EGL_NONE)
109 EGL_COLOR_BUFFER_TYPE (all EGL_RGB_BUFFER)
110 EGL_SAMPLES (if EGL_SAMPLES is 1 then all 4 else all 0)
111 EGL_NATIVE_RENDERABLE is true
112 EGL_MAX_PBUFFER_WIDTH, EGL_MAX_PBUFFER_HEIGHT, EGL_MIN_SWAP_INTERVAL, EGL_MAX_SWAP_INTERVAL are the same for all configs
113
114 All configs support all of:
115 (EGL_PBUFFER_BIT | EGL_PIXMAP_BIT | EGL_WINDOW_BIT | EGL_VG_COLORSPACE_LINEAR_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT | EGL_MULTISAMPLE_RESOLVE_BOX_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT);
116
117
118 EGL_OPTIMAL_FORMAT_BIT_KHR: Considered optimal if no format conversion needs doing
119
120 EGL_TRANSPARENT_TYPE is always EGL_NONE because we don't support EGL_TRANSPARENT_RGB. Should there be an EGL_TRANSPARENT_ALPHA?
121*/
122
123#define VCOS_LOG_CATEGORY (&egl_client_log_cat)
124
125#include "interface/khronos/common/khrn_client_mangle.h"
126
127#include "interface/khronos/common/khrn_int_common.h"
128#include "interface/khronos/common/khrn_options.h"
129
130#include "interface/khronos/egl/egl_client_surface.h"
131#include "interface/khronos/egl/egl_client_context.h"
132#include "interface/khronos/egl/egl_client_config.h"
133
134#include "interface/khronos/common/khrn_client.h"
135#include "interface/khronos/common/khrn_client_rpc.h"
136
137#ifdef RPC_DIRECT
138#include "interface/khronos/egl/egl_int_impl.h"
139#endif
140
141#if defined(WIN32) || defined(__mips__)
142#include "interface/khronos/common/khrn_int_misc_impl.h"
143#endif
144
145#ifdef KHRONOS_EGL_PLATFORM_OPENWFC
146#include "interface/khronos/wf/wfc_client_stream.h"
147#endif
148
149#if defined(RPC_DIRECT_MULTI)
150#include "middleware/khronos/egl/egl_server.h"
151#endif
152
153#include <stdlib.h>
154#include <string.h>
155
156
157#include "interface/khronos/egl/egl_client_cr.c"
158
159VCOS_LOG_CAT_T egl_client_log_cat;
160
161static void egl_current_release(CLIENT_PROCESS_STATE_T *process, EGL_CURRENT_T *current);
162void egl_gl_flush_callback(bool wait);
163void egl_vg_flush_callback(bool wait);
164
165/*
166TODO: do an RPC call to make sure the Khronos vll is loaded (and that it stays loaded until eglTerminate)
167Also affects global image (and possibly others?)
168 EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
169
170 Khronos documentation:
171
172 EGL may be initialized on a display by calling
173 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint
174 *major, EGLint *minor);
175 EGL TRUE is returned on success, and major and minor are updated with the major
176 and minor version numbers of the EGL implementation (for example, in an EGL
177 1.2 implementation, the values of *major and *minor would be 1 and 2, respectively).
178 major and minor are not updated if they are specified as NULL.
179 EGL FALSE is returned on failure and major and minor are not updated. An
180 EGL BAD DISPLAY error is generated if the dpy argument does not refer to a valid
181 EGLDisplay. An EGL NOT INITIALIZED error is generated if EGL cannot be
182 initialized for an otherwise valid dpy.
183 Initializing an already-initialized display is allowed, but the only effect of such
184 a call is to return EGL TRUE and update the EGL version numbers. An initialized
185 display may be used from other threads in the same address space without being
186 initalized again in those threads.
187
188 Implementation notes:
189
190 client_egl_get_process_state sets some errors for us.
191
192 Preconditions:
193
194 major is NULL or a valid pointer
195 minor is NULL or a valid pointer
196 eglTerminate(dpy) must be called at some point after calling this function if we return EGL_TRUE.
197
198 Postconditions:
199
200 The following conditions cause error to assume the specified value
201
202 EGL_BAD_DISPLAY An EGLDisplay argument does not name a valid EGLDisplay
203 EGL_NOT_INITIALIZED EGL is not initialized, or could not be initialized, for the specified display.
204 EGL_SUCCESS Function succeeded.
205
206 if more than one condition holds, the first error is generated.
207
208 Invariants preserved:
209
210 -
211
212 Invariants used:
213
214 -
215*/
216
217EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
218{
219 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
220 EGLBoolean result;
221
222 CLIENT_LOCK();
223
224 {
225 CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_FALSE);
226
227 if (process) {
228 if (!client_process_state_init(process))
229 {
230 thread->error = EGL_NOT_INITIALIZED;
231 result = EGL_FALSE;
232 }
233 else
234 {
235 thread->error = EGL_SUCCESS;
236 result = EGL_TRUE;
237 }
238 } else
239 result = EGL_FALSE;
240
241 if (result) {
242 if (major)
243 *major = 1;
244 if (minor)
245 *minor = 4;
246 }
247 }
248
249 CLIENT_UNLOCK();
250
251 vcos_log_set_level(&egl_client_log_cat, VCOS_LOG_WARN);
252 vcos_log_register("egl_client", &egl_client_log_cat);
253 vcos_log_info("eglInitialize end. dpy=%d.", (int)dpy);
254 khrn_init_options();
255
256 return result;
257}
258
259/*
260 EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy)
261
262 Khronos documentation:
263
264 To release resources associated with use of EGL and client APIs on a display,
265 call
266 EGLBoolean eglTerminate(EGLDisplay dpy);
267 Termination marks all EGL-specific resources associated with the specified display
268 for deletion. If contexts or surfaces created with respect to dpy are current (see
269 section 3.7.3) to any thread, then they are not actually released while they remain
270 current. Such contexts and surfaces will be destroyed, and all future references to
271 them will become invalid, as soon as any otherwise valid eglMakeCurrent call is
272 made from the thread they are bound to.
273 eglTerminate returns EGL TRUE on success.
274 If the dpy argument does not refer to a valid EGLDisplay, EGL FALSE is
275 returned, and an EGL BAD DISPLAY error is generated.
276 Termination of a display that has already been terminated, or has not yet been
277 initialized, is allowed, but the only effect of such a call is to return EGL TRUE, since
278 there are no EGL resources associated with the display to release. A terminated
279 display may be re-initialized by calling eglInitialize again. When re-initializing
280 a terminated display, resources which were marked for deletion as a result of the
281 earlier termination remain so marked, and references to them are not valid.
282
283 Implementation notes:
284
285 -
286
287 Preconditions:
288
289 -
290
291 Postconditions:
292
293 The following conditions cause error to assume the specified value
294
295 EGL_BAD_DISPLAY An EGLDisplay argument does not name a valid EGLDisplay
296 EGL_SUCCESS Function succeeded.
297
298 if more than one condition holds, the first error is generated.
299
300 Invariants preserved:
301
302 -
303
304 Invariants used:
305
306 -
307*/
308
309EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy)
310{
311 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
312
313 vcos_log_trace("eglTerminate start. dpy=%d", (int)dpy);
314
315#ifdef RPC_DIRECT_MULTI
316 return true; //it is moved to khronos_exit
317#else
318 {
319 EGLBoolean result;
320 CLIENT_LOCK();
321
322 {
323 CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_FALSE);
324
325 if (process) {
326 client_process_state_term(process);
327
328 thread->error = EGL_SUCCESS;
329 result = EGL_TRUE;
330
331 client_try_unload_server(process);
332 } else
333 result = EGL_FALSE;
334 }
335
336 CLIENT_UNLOCK();
337
338 vcos_log_trace("eglTerminate end. dpy=%d", (int)dpy);
339 vcos_log_unregister(&egl_client_log_cat);
340 return result;
341 }
342#endif
343}
344
345/*
346 EGLAPI const char EGLAPIENTRY * eglQueryString(EGLDisplay dpy, EGLint name)
347
348 Khronos documentation:
349
350 3.3 EGL Versioning
351const char *eglQueryString(EGLDisplay dpy, EGLint
352name);
353eglQueryString returns a pointer to a static, zero-terminated string describing
354some aspect of the EGL implementation running on the specified display.
355name may be one of EGL CLIENT APIS, EGL EXTENSIONS, EGL VENDOR, or
356EGL VERSION.
357The EGL CLIENT APIS string describes which client rendering APIs are supported.
358It is zero-terminated and contains a space-separated list of API names,
359which must include at least one of ‘‘OpenGL ES’’ or ‘‘OpenVG’’.
360Version 1.3 - December 4, 2006
3613.4. CONFIGURATION MANAGEMENT 13
362The EGL EXTENSIONS string describes which EGL extensions are supported
363by the EGL implementation running on the specified display. The string is zeroterminated
364and contains a space-separated list of extension names; extension names
365themselves do not contain spaces. If there are no extensions to EGL, then the empty
366string is returned.
367The format and contents of the EGL VENDOR string is implementation dependent.
368The format of the EGL VERSION string is:
369<major version.minor version><space><vendor specific info>
370Both the major and minor portions of the version number are numeric. Their values
371must match the major and minor values returned by eglInitialize (see section 3.2).
372The vendor-specific information is optional; if present, its format and contents are
373implementation specific.
374On failure, NULL is returned. An EGL NOT INITIALIZED error is generated if
375EGL is not initialized for dpy. An EGL BAD PARAMETER error is generated if name
376is not one of the values described above.
377
378 Implementation notes:
379
380 We support the following extensions but they can be removed from the driver if defined to zero.
381 EGL_KHR_image extensions
382 EGL_KHR_lock_surface
383
384 Preconditions:
385
386 -
387
388 Postconditions:
389
390 The following conditions cause error to assume the specified value
391
392 EGL_BAD_DISPLAY An EGLDisplay argument does not name a valid EGLDisplay
393 EGL_NOT_INITIALIZED EGL is not initialized for the specified display.
394 EGL_BAD_PARAMETER name is not one of {EGL_CLIENT_APIS, EGL_EXTENSIONS, EGL_VENDOR, EGL_VERSION}
395 EGL_SUCCESS Function succeeded.
396
397 if more than one condition holds, the first error is generated.
398
399 Return value is NULL or a pointer to a null-terminated string which is valid forever.
400
401 Invariants preserved:
402
403 -
404
405 Invariants used:
406
407 -
408*/
409
410EGLAPI const char EGLAPIENTRY * eglQueryString(EGLDisplay dpy, EGLint name)
411{
412 CLIENT_THREAD_STATE_T *thread;
413 CLIENT_PROCESS_STATE_T *process;
414 const char *result = NULL;
415
416 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
417 {
418 thread->error = EGL_SUCCESS;
419 switch (name) {
420 case EGL_CLIENT_APIS:
421 result = "OpenGL_ES OpenVG";
422 break;
423 case EGL_EXTENSIONS:
424 //TODO: this list isn't quite correct
425 result = ""
426#if EGL_KHR_image
427 "EGL_KHR_image EGL_KHR_image_base EGL_KHR_image_pixmap EGL_KHR_vg_parent_image EGL_KHR_gl_texture_2D_image EGL_KHR_gl_texture_cubemap_image "
428#endif
429#if EGL_KHR_lock_surface
430 "EGL_KHR_lock_surface "
431#endif
432#if EGL_ANDROID_swap_rectangle
433 "EGL_ANDROID_swap_rectangle "
434#endif
435#ifdef ANDROID
436 "EGL_ANDROID_image_native_buffer "
437#endif
438#ifdef ANDROID
439#ifdef EGL_KHR_fence_sync
440 "EGL_KHR_fence_sync "
441#endif
442#endif
443 ;
444 break;
445 case EGL_VENDOR:
446 result = "Broadcom";
447 break;
448 case EGL_VERSION:
449 result = "1.4";
450 break;
451 default:
452 thread->error = EGL_BAD_PARAMETER;
453 result = NULL;
454 }
455 CLIENT_UNLOCK();
456 } else
457 result = NULL;
458
459 return result;
460}
461
462/*
463 EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
464
465 Khronos documentation:
466
467 3.5.1 Creating On-Screen Rendering Surfaces
468 To create an on-screen rendering surface, first create a native platform window
469 with attributes corresponding to the desired EGLConfig (e.g. with the same color
470 depth, with other constraints specific to the platform). Using the platform-specific
471 type EGLNativeWindowType, which is the type of a handle to that native window,
472 then call:
473
474 EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win,
475 const EGLint *attrib_list);
476
477 eglCreateWindowSurface creates an onscreen EGLSurface and returns a handle
478 to it. Any EGL context created with a compatible EGLConfig can be used to
479 render into this surface.
480
481 attrib list specifies a list of attributes for the window. The list has the same
482 structure as described for eglChooseConfig. Attributes that can be specified in
483 attrib list include EGL_RENDER_BUFFER, EGL_VG_COLORSPACE, and EGL_VG_ALPHA_FORMAT.
484 It is possible that some platforms will define additional attributes specific to
485 those environments, as an EGL extension.
486
487 attrib list may be NULL or empty (first attribute is EGL_NONE), in which case
488 all attributes assumes their default value as described below.
489 EGL_RENDER_BUFFER specifies which buffer should be used for client API
490 rendering to the window, as described in section 2.2.2. If its value is EGL_SINGLE_BUFFER,
491 then client APIs should render directly into the visible window.
492
493 If its value is EGL_BACK_BUFFER, then all client APIs should render into the back
494 buffer. The default value of EGL_RENDER_BUFFER is EGL_BACK_BUFFER.
495
496 Client APIs may not be able to respect the requested rendering buffer. To
497 determine the actual buffer being rendered to by a context, call eglQueryContext
498 (see section 3.7.4).
499
500 EGL_VG_COLORSPACE specifies the color space used by OpenVG when
501 rendering to the surface. If its value is EGL_VG_COLORSPACE_sRGB, then
502 a non-linear, perceptually uniform color space is assumed, with a corresponding
503 VGImageFormat of form VG_s*. If its value is EGL_VG_-
504 COLORSPACE_LINEAR, then a linear color space is assumed, with a corresponding
505 VGImageFormat of form VG_l*. The default value of EGL_VG_COLORSPACE
506 is EGL_VG_COLORSPACE_sRGB.
507
508 EGL_VG_ALPHA_FORMAT specifies how alpha values are interpreted by
509 OpenVG when rendering to the surface. If its value is EGL_VG_ALPHA_FORMAT_-
510 NONPRE, then alpha values are not premultipled. If its value is EGL_VG_ALPHA_-
511 FORMAT_PRE, then alpha values are premultiplied. The default value of EGL_VG_-
512 ALPHA_FORMAT is EGL_VG_ALPHA_FORMAT_NONPRE.
513
514 Note that the EGL_VG_COLORSPACE and EGL_VG_ALPHA_FORMAT attributes
515 are used only by OpenVG . EGL itself, and other client APIs such as OpenGL and
516 OpenGL ES , do not distinguish multiple colorspace models. Refer to section 11.2
517 of the OpenVG 1.0 specification for more information.
518
519 Similarly, the EGL_VG_ALPHA_FORMAT attribute does not necessarily control
520 or affect the window system’s interpretation of alpha values, even when the window
521 system makes use of alpha to composite surfaces at display time. The window system's
522 use and interpretation of alpha values is outside the scope of EGL. However,
523 the preferred behavior is for window systems to ignore the value of EGL_VG_-
524 ALPHA_FORMAT when compositing window surfaces.
525
526 On failure eglCreateWindowSurface returns EGL_NO_SURFACE. If the attributes
527 of win do not correspond to config, then an EGL_BAD_MATCH error is generated.
528 If config does not support rendering to windows (the EGL_SURFACE_TYPE
529 attribute does not contain EGL_WINDOW_BIT), an EGL_BAD_MATCH error is generated.
530 If config does not support the colorspace or alpha format attributes specified
531 in attrib list (as defined for eglCreateWindowSurface), an EGL_BAD_MATCH error
532 is generated. If config is not a valid EGLConfig, an EGL_BAD_CONFIG error
533 is generated. If win is not a valid native window handle, then an EGL_BAD_NATIVE_WINDOW
534 error should be generated. If there is already an EGLConfig
535 associated with win (as a result of a previous eglCreateWindowSurface call), then
536 an EGL_BAD_ALLOC error is generated. Finally, if the implementation cannot allocate
537 resources for the new EGL window, an EGL_BAD_ALLOC error is generated.
538
539 Implementation notes:
540
541 -
542
543 Preconditions:
544
545 attrib_list is NULL or a pointer to an EGL_NONE-terminated list of attribute/value pairs
546
547 Postconditions:
548
549 The following conditions cause error to assume the specified value
550
551 EGL_BAD_DISPLAY An EGLDisplay argument does not name a valid EGLDisplay
552 EGL_NOT_INITIALIZED EGL is not initialized for the specified display.
553 EGL_BAD_CONFIG config is not a valid EGLConfig
554 EGL_BAD_NATIVE_WINDOW win is not a valid native window handle
555 EGL_BAD_ATTRIBUTE attrib_list contains an undefined EGL attribute or an attribute value that is unrecognized or out of range.
556 (TODO: EGL_BAD_ATTRIBUTE not mentioned in spec)
557 EGL_BAD_NATIVE_WINDOW window is larger than EGL_CONFIG_MAX_WIDTH x EGL_CONFIG_MAX_HEIGHT
558 (TODO: Maybe EGL_BAD_ALLOC might be more appropriate?)
559 EGL_BAD_ALLOC implementation cannot allocate resources for the new EGL window
560 (TODO: If there is already an EGLConfig associated with win)
561 EGL_SUCCESS Function succeeded.
562
563 if more than one condition holds, the first error is generated.
564
565 Return value is EGL_NO_SURFACE or an EGLSurface handle which is valid until the EGL session ends or
566 eglDestroySurface is called.
567
568 Invariants preserved:
569
570 (CLIENT_PROCESS_STATE_SURFACES)
571 (CLIENT_PROCESS_STATE_NEXT_SURFACE)
572
573 Invariants used:
574
575 -
576*/
577
578EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
579{
580 CLIENT_THREAD_STATE_T *thread;
581 CLIENT_PROCESS_STATE_T *process;
582 EGLSurface result;
583
584 vcos_log_trace("eglCreateWindowSurface for window %p", win);
585
586 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
587 {
588 uint32_t handle = platform_get_handle(dpy, win);
589
590 if ((int)(size_t)config < 1 || (int)(size_t)config > EGL_MAX_CONFIGS) {
591 thread->error = EGL_BAD_CONFIG;
592 result = EGL_NO_SURFACE;
593 } else if (handle == PLATFORM_WIN_NONE) {
594 // The platform reports that this is an invalid window handle
595 thread->error = EGL_BAD_NATIVE_WINDOW;
596 result = EGL_NO_SURFACE;
597 } else {
598 bool linear = false;
599 bool premult = false;
600 bool single = false;
601
602 if (!egl_surface_check_attribs(WINDOW, attrib_list, &linear, &premult, &single, 0, 0, 0, 0, 0, 0)) {
603 thread->error = EGL_BAD_ATTRIBUTE;
604 result = EGL_NO_SURFACE;
605 } else {
606 EGL_SURFACE_T *surface;
607
608 uint32_t width, height;
609 uint32_t num_buffers = 3;
610 uint32_t swapchain_count;
611
612 platform_get_dimensions(dpy,
613 win, &width, &height, &swapchain_count);
614
615 if (swapchain_count > 0)
616 num_buffers = swapchain_count;
617 else
618 {
619 if (khrn_options.double_buffer)
620 num_buffers = 2;
621 }
622
623 if (width <= 0 || width > EGL_CONFIG_MAX_WIDTH || height <= 0 || height > EGL_CONFIG_MAX_HEIGHT) {
624 /* TODO: Maybe EGL_BAD_ALLOC might be more appropriate? */
625 thread->error = EGL_BAD_NATIVE_WINDOW;
626 result = EGL_NO_SURFACE;
627 } else {
628 surface = egl_surface_create(
629 (EGLSurface)(size_t)process->next_surface,
630 WINDOW,
631 linear ? LINEAR : SRGB,
632 premult ? PRE : NONPRE,
633#ifdef DIRECT_RENDERING
634 1,
635#else
636 (uint32_t)(single ? 1 : num_buffers),
637#endif
638 width, height,
639 config,
640 win,
641 handle,
642 false,
643 false,
644 false,
645 EGL_NO_TEXTURE,
646 EGL_NO_TEXTURE,
647 0, 0);
648
649 if (surface) {
650 if (khrn_pointer_map_insert(&process->surfaces, process->next_surface, surface)) {
651 thread->error = EGL_SUCCESS;
652 result = (EGLSurface)(size_t)process->next_surface++;
653 } else {
654 thread->error = EGL_BAD_ALLOC;
655 result = EGL_NO_SURFACE;
656 egl_surface_free(surface);
657 }
658 } else {
659 thread->error = EGL_BAD_ALLOC;
660 result = EGL_NO_SURFACE;
661 }
662 }
663 }
664 }
665 CLIENT_UNLOCK();
666 }
667 else
668 result = EGL_NO_SURFACE;
669
670 vcos_log_trace("eglCreateWindowSurface end %i", (int) result);
671
672 return result;
673}
674
675/*
676 EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
677
678 Khronos documentation:
679
680 3.5.2 Creating Off-Screen Rendering Surfaces
681 EGL supports off-screen rendering surfaces in pbuffers. Pbuffers differ from windows
682 in the following ways:
683
684 1. Pbuffers are typically allocated in offscreen (non-visible) graphics memory
685 and are intended only for accelerated offscreen rendering. Allocation can fail
686 if there are insufficient graphics resources (implementations are not required
687 to virtualize framebuffer memory). Clients should deallocate pbuffers when
688 they are no longer in use, since graphics memory is often a scarce resource.
689
690 2. Pbuffers are EGL resources and have no associated native window or native
691 window type. It may not be possible to render to pbuffers using native
692 rendering APIs.
693
694 To create a pbuffer, call
695
696 EGLSurface eglCreatePbufferSurface(EGLDisplay dpy,
697 EGLConfig config, const EGLint
698 *attrib_list);
699
700 This creates a single pbuffer surface and returns a handle to it.
701 attrib list specifies a list of attributes for the pbuffer. The list has the same
702 structure as described for eglChooseConfig. Attributes that can be specified in
703 attrib list include EGL_WIDTH, EGL_HEIGHT, EGL_LARGEST_PBUFFER, EGL_TEXTURE_FORMAT,
704 EGL_TEXTURE_TARGET, EGL_MIPMAP_TEXTURE, EGL_VG_COLORSPACE, and EGL_VG_ALPHA_FORMAT.
705
706 It is possible that some platforms will define additional attributes specific to
707 those environments, as an EGL extension.
708
709 attrib list may be NULL or empty (first attribute is EGL_NONE), in which case
710 all the attributes assume their default values as described below.
711
712 EGL_WIDTH and EGL_HEIGHT specify the pixel width and height of the rectangular
713 pbuffer. If the value of EGLConfig attribute EGL_TEXTURE_FORMAT is
714 not EGL_NO_TEXTURE, then the pbuffer width and height specify the size of the
715 level zero texture image. The default values for EGL_WIDTH and EGL_HEIGHT are
716 zero.
717
718 EGL_TEXTURE_FORMAT specifies the format of the OpenGL ES texture that
719 will be created when a pbuffer is bound to a texture map. It can be set to EGL_-
720 TEXTURE_RGB, EGL_TEXTURE_RGBA, or EGL_NO_TEXTURE. The default value of
721 EGL_TEXTURE_FORMAT is EGL_NO_TEXTURE.
722
723 EGL_TEXTURE_TARGET specifies the target for the OpenGL ES texture that
724 will be created when the pbuffer is created with a texture format of EGL_-
725 TEXTURE_RGB or EGL_TEXTURE_RGBA. The target can be set to EGL_NO_-
726 TEXTURE or EGL_TEXTURE_2D. The default value of EGL_TEXTURE_TARGET is
727 EGL_NO_TEXTURE.
728
729 EGL_MIPMAP_TEXTURE indicates whether storage for OpenGL ES mipmaps
730 should be allocated. Space for mipmaps will be set aside if the attribute value
731 is EGL_TRUE and EGL_TEXTURE_FORMAT is not EGL_NO_TEXTURE. The default
732 value for EGL_MIPMAP_TEXTURE is EGL_FALSE.
733
734 Use EGL_LARGEST_PBUFFER to get the largest available pbuffer when the allocation
735 of the pbuffer would otherwise fail. The width and height of the allocated
736 pbuffer will never exceed the values of EGL_WIDTH and EGL_HEIGHT, respectively.
737 If the pbuffer will be used as a OpenGL ES texture (i.e., the value of
738 EGL_TEXTURE_TARGET is EGL_TEXTURE_2D, and the value of EGL_TEXTURE_-
739 FORMAT is EGL_TEXTURE_RGB or EGL_TEXTURE_RGBA), then the aspect ratio
740 will be preserved and the new width and height will be valid sizes for the texture
741 target (e.g. if the underlying OpenGL ES implementation does not support
742 non-power-of-two textures, both the width and height will be a power of 2). Use
743 eglQuerySurface to retrieve the dimensions of the allocated pbuffer. The default
744 value of EGL_LARGEST_PBUFFER is EGL_FALSE.
745
746 EGL_VG_COLORSPACE and EGL_VG_ALPHA_FORMAT have the same meaning
747 and default values as when used with eglCreateWindowSurface.
748 The resulting pbuffer will contain color buffers and ancillary buffers as specified
749 by config.
750
751 The contents of the depth and stencil buffers may not be preserved when rendering
752 an OpenGL ES texture to the pbuffer and switching which image of the
753 texture is rendered to (e.g., switching from rendering one mipmap level to rendering
754 another).
755
756 On failure eglCreatePbufferSurface returns EGL_NO_SURFACE. If the pbuffer
757 could not be created due to insufficient resources, then an EGL_BAD_ALLOC error
758 is generated. If config is not a valid EGLConfig, an EGL_BAD_CONFIG error is
759 generated. If the value specified for either EGL_WIDTH or EGL_HEIGHT is less
760 than zero, an EGL_BAD_PARAMETER error is generated. If config does not support
761 pbuffers, an EGL_BAD_MATCH error is generated. In addition, an EGL_BAD_MATCH
762 error is generated if any of the following conditions are true:
763
764 The EGL_TEXTURE_FORMAT attribute is not EGL_NO_TEXTURE, and EGL_WIDTH
765 and/or EGL_HEIGHT specify an invalid size (e.g., the texture size is
766 not a power of two, and the underlying OpenGL ES implementation does not
767 support non-power-of-two textures).
768
769 The EGL_TEXTURE_FORMAT attribute is EGL_NO_TEXTURE, and EGL_TEXTURE_TARGET
770 is something other than EGL_NO_TEXTURE; or, EGL_TEXTURE_FORMAT is something
771 other than EGL_NO_TEXTURE, and EGL_TEXTURE_TARGET is EGL_NO_TEXTURE.
772
773 Finally, an EGL_BAD_ATTRIBUTE error is generated if any of the EGL_TEXTURE_FORMAT,
774 EGL_TEXTURE_TARGET, or EGL_MIPMAP_TEXTURE attributes
775 are specified, but config does not support OpenGL ES rendering (e.g.
776 the EGL_RENDERABLE_TYPE attribute does not include at least one of EGL_OPENGL_ES_BIT
777 or EGL_OPENGL_ES2_BIT.
778
779 Implementation notes:
780
781 -
782
783 attrib_list is NULL or a pointer to an EGL_NONE-terminated list of attribute/value pairs
784
785 Postconditions:
786
787 The following conditions cause error to assume the specified value
788
789 EGL_BAD_DISPLAY An EGLDisplay argument does not name a valid EGLDisplay
790 EGL_NOT_INITIALIZED EGL is not initialized for the specified display.
791 EGL_BAD_CONFIG config is not a valid EGLConfig
792 EGL_BAD_ATTRIBUTE attrib_list contains an undefined EGL attribute or an attribute value that is unrecognized or out of range.
793 (TODO: EGL_BAD_ATTRIBUTE not mentioned in spec)
794 EGL_BAD_MATCH config doesn't support EGL_BIND_TO_TEXTURE_RGB(A) and you specify EGL_TEXTURE_FORMAT=EGL_TEXTURE_RGB(A)
795 (TODO: no mention of this in the spec)
796 EGL_BAD_ALLOC requested dimensions are larger than EGL_CONFIG_MAX_WIDTH x EGL_CONFIG_MAX_HEIGHT
797 (TODO: no mention of this in the spec)
798 EGL_BAD_ALLOC implementation cannot allocate resources for the new EGL window
799 (TODO: If there is already an EGLConfig associated with win)
800 EGL_SUCCESS Function succeeded.
801
802 if more than one condition holds, the first error is generated.
803
804 Return value is EGL_NO_SURFACE or an EGLSurface handle which is valid until the EGL session ends or
805 eglDestroySurface is called.
806
807 Invariants preserved:
808
809 (CLIENT_PROCESS_STATE_SURFACES)
810 (CLIENT_PROCESS_STATE_NEXT_SURFACE)
811
812 Invariants used:
813
814 -
815*/
816
817EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
818 const EGLint *attrib_list)
819{
820 CLIENT_THREAD_STATE_T *thread;
821 CLIENT_PROCESS_STATE_T *process;
822 EGLSurface result;
823
824 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
825 {
826 if ((int)(size_t)config < 1 || (int)(size_t)config > EGL_MAX_CONFIGS) {
827 thread->error = EGL_BAD_CONFIG;
828 result = EGL_NO_SURFACE;
829 } else {
830 int width = 0;
831 int height = 0;
832 bool largest_pbuffer = 0;
833 EGLenum texture_format = EGL_NO_TEXTURE;
834 EGLenum texture_target = EGL_NO_TEXTURE;
835 bool mipmap_texture = EGL_FALSE;
836 bool linear = EGL_FALSE;
837 bool premult = EGL_FALSE;
838
839 if (!egl_surface_check_attribs(PBUFFER, attrib_list, &linear, &premult, 0, &width, &height, &largest_pbuffer, &texture_format, &texture_target, &mipmap_texture)) {
840 thread->error = EGL_BAD_ATTRIBUTE;
841 result = EGL_NO_SURFACE;
842 } else if (
843 (texture_format != EGL_NO_TEXTURE && (width == 0 || height == 0)) ||
844 ((texture_format == EGL_NO_TEXTURE) != (texture_target == EGL_NO_TEXTURE)) ||
845 !egl_config_bindable((int)(size_t)config - 1, texture_format)
846 ) {
847
848 /*
849 "In addition, an EGL_BAD_MATCH
850 error is generated if any of the following conditions are true:
851 - The EGL_TEXTURE_FORMAT attribute is not EGL_NO_TEXTURE, and
852 EGL_WIDTH and/or EGL_HEIGHT specify an invalid size (e.g., the texture size
853 is not a power of two, and the underlying OpenGL ES implementation does
854 not support non-power-of-two textures).
855 - The EGL_TEXTURE_FORMAT attribute is EGL_NO_TEXTURE, and
856 EGL_TEXTURE_TARGET is something other than EGL_NO_TEXTURE; or,
857 EGL_TEXTURE_FORMAT is something other than EGL_NO_TEXTURE, and
858 EGL_TEXTURE_TARGET is EGL_NO_TEXTURE."
859 */
860
861 /*
862 TODO It doesn't seem to explicitly say it in the spec, but I'm also
863 generating EGL_BAD_MATCH if the config doesn't support EGL_BIND_TO_TEXTURE_RGB(A)
864 and you specify EGL_TEXTURE_FORMAT=EGL_TEXTURE_RGB(A)
865 */
866 thread->error = EGL_BAD_MATCH;
867 result = EGL_NO_SURFACE;
868 } else if ((width > EGL_CONFIG_MAX_WIDTH || height > EGL_CONFIG_MAX_HEIGHT) && !largest_pbuffer) {
869 /*
870 TODO no mention of this in the spec, but clearly we fail if we try to allocate
871 an oversize pbuffer without the largest_pbuffer stuff enabled
872 */
873
874 thread->error = EGL_BAD_ALLOC;
875 result = EGL_NO_SURFACE;
876 } else {
877 EGL_SURFACE_T *surface = egl_surface_create(
878 (EGLSurface)(size_t)process->next_surface,
879 PBUFFER,
880 linear ? LINEAR : SRGB,
881 premult ? PRE : NONPRE,
882 1,
883 width, height,
884 config,
885 0,
886 PLATFORM_WIN_NONE,
887 largest_pbuffer,
888 true,
889 mipmap_texture,
890 texture_format,
891 texture_target,
892 0, 0);
893
894 if (surface) {
895 if (khrn_pointer_map_insert(&process->surfaces, process->next_surface, surface)) {
896 thread->error = EGL_SUCCESS;
897 result = (EGLSurface)(size_t)process->next_surface++;
898 } else {
899 thread->error = EGL_BAD_ALLOC;
900 result = EGL_NO_SURFACE;
901 egl_surface_free(surface);
902 }
903 } else {
904 thread->error = EGL_BAD_ALLOC;
905 result = EGL_NO_SURFACE;
906 }
907 }
908 }
909 CLIENT_UNLOCK();
910 }
911 else
912 result = EGL_NO_SURFACE;
913
914 return result;
915}
916
917typedef struct {
918 CLIENT_PROCESS_STATE_T *process;
919 EGLNativePixmapType pixmap;
920 uint32_t pixmap_server_handle[2];
921 int is_dup;
922} PIXMAP_CHECK_DATA_T;
923
924static void callback_check_duplicate_pixmap(KHRN_POINTER_MAP_T *map, uint32_t key, void *value, void *data)
925{
926 PIXMAP_CHECK_DATA_T *pixmap_check_data = (PIXMAP_CHECK_DATA_T *)data;
927 EGL_SURFACE_T *surface = (EGL_SURFACE_T *)value;
928
929 UNUSED_NDEBUG(map);
930 UNUSED_NDEBUG(key);
931
932 vcos_assert(map == &pixmap_check_data->process->surfaces);
933 vcos_assert(surface != NULL);
934 vcos_assert((uintptr_t)key == (uintptr_t)surface->name);
935
936 if ((surface->type == PIXMAP) && ((pixmap_check_data->pixmap_server_handle[0] || (pixmap_check_data->pixmap_server_handle[1] != (uint32_t)-1)) ?
937 /* compare server handles for server-side pixmaps */
938 ((surface->pixmap_server_handle[0] == pixmap_check_data->pixmap_server_handle[0]) &&
939 (surface->pixmap_server_handle[1] == pixmap_check_data->pixmap_server_handle[1])) :
940 /* compare EGLNativePixmapType for client-side pixmaps */
941 (!surface->pixmap_server_handle[0] && (surface->pixmap_server_handle[1] == (uint32_t)-1) &&
942 (surface->pixmap == pixmap_check_data->pixmap)))) {
943 pixmap_check_data->is_dup = 1;
944 }
945}
946
947EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
948 EGLNativePixmapType pixmap,
949 const EGLint *attrib_list)
950{
951 CLIENT_THREAD_STATE_T *thread;
952 CLIENT_PROCESS_STATE_T *process;
953 EGLSurface result;
954
955 vcos_log_trace("eglCreatePixmapSurface");
956
957 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
958 {
959 if ((int)(size_t)config < 1 || (int)(size_t)config > EGL_MAX_CONFIGS) {
960 thread->error = EGL_BAD_CONFIG;
961 result = EGL_NO_SURFACE;
962 } else {
963 bool linear = false;
964 bool premult = false;
965
966 if (!egl_surface_check_attribs(PIXMAP, attrib_list, &linear, &premult, 0, 0, 0, 0, 0, 0, 0)) {
967 thread->error = EGL_BAD_ATTRIBUTE;
968 result = EGL_NO_SURFACE;
969 } else {
970 EGL_SURFACE_T *surface;
971
972 KHRN_IMAGE_WRAP_T image;
973 if (!platform_get_pixmap_info(pixmap, &image)) {
974 thread->error = EGL_BAD_NATIVE_PIXMAP;
975 result = EGL_NO_SURFACE;
976 } else {
977 uint32_t server_handle[2] = {0, (uint32_t)-1};
978 platform_get_pixmap_server_handle(pixmap, server_handle);
979
980#if !EGL_BRCM_global_image
981 if (server_handle[1] != -1) {
982 thread->error = EGL_BAD_PARAMETER;
983 result = EGL_NO_SURFACE;
984 } else
985#endif
986 if (image.width > EGL_CONFIG_MAX_WIDTH || image.height > EGL_CONFIG_MAX_HEIGHT) {
987 /* Maybe EGL_BAD_ALLOC might be more appropriate? */
988 thread->error = EGL_BAD_NATIVE_WINDOW;
989 result = EGL_NO_SURFACE;
990 } else if (!egl_config_match_pixmap_info((int)(size_t)config - 1, &image) ||
991 !platform_match_pixmap_api_support(pixmap, egl_config_get_api_support((int)(size_t)config - 1))
992#if EGL_BRCM_global_image
993 || ((server_handle[1] != (uint32_t)(-1)) && (
994 (!(image.format & IMAGE_FORMAT_LIN) != !linear) ||
995 (!(image.format & IMAGE_FORMAT_PRE) != !premult)))
996#endif
997 ) {
998 thread->error = EGL_BAD_MATCH;
999 result = EGL_NO_SURFACE;
1000 } else {
1001 /*
1002 * Check that we didn't already use this pixmap in an
1003 * earlier call to eglCreatePixmapSurface()
1004 */
1005 PIXMAP_CHECK_DATA_T pixmap_check_data;
1006 pixmap_check_data.process = process;
1007 pixmap_check_data.pixmap = pixmap;
1008 pixmap_check_data.pixmap_server_handle[0] = 0;
1009 pixmap_check_data.pixmap_server_handle[1] = (uint32_t)-1;
1010 platform_get_pixmap_server_handle(pixmap, pixmap_check_data.pixmap_server_handle);
1011 pixmap_check_data.is_dup = 0;
1012
1013 khrn_pointer_map_iterate(&process->surfaces, callback_check_duplicate_pixmap, &pixmap_check_data);
1014
1015 if (pixmap_check_data.is_dup) {
1016 thread->error = EGL_BAD_ALLOC;
1017 result = EGL_NO_SURFACE;
1018 } else {
1019 surface = egl_surface_create(
1020 (EGLSurface)(size_t)process->next_surface,
1021 PIXMAP,
1022 linear ? LINEAR : SRGB,
1023 premult ? PRE : NONPRE,
1024 1,
1025 image.width, image.height,
1026 config,
1027 0,
1028 PLATFORM_WIN_NONE,
1029 false,
1030 false,
1031 false,
1032 EGL_NO_TEXTURE,
1033 EGL_NO_TEXTURE,
1034 pixmap, ((server_handle[0] == 0) && (server_handle[1] == (uint32_t)(-1))) ? NULL : server_handle);
1035
1036 if (surface) {
1037 if (khrn_pointer_map_insert(&process->surfaces, process->next_surface, surface)) {
1038 thread->error = EGL_SUCCESS;
1039 result = (EGLSurface)(size_t)process->next_surface++;
1040 } else {
1041 thread->error = EGL_BAD_ALLOC;
1042 result = EGL_NO_SURFACE;
1043 egl_surface_free(surface);
1044 }
1045 } else {
1046 thread->error = EGL_BAD_ALLOC;
1047 result = EGL_NO_SURFACE;
1048 }
1049 }
1050 }
1051 }
1052 }
1053 }
1054 CLIENT_UNLOCK();
1055 }
1056 else
1057 result = EGL_NO_SURFACE;
1058
1059 return result;
1060}
1061
1062//TODO: if this is a pixmap surface, should we make sure the pixmap gets
1063//updated?
1064//TODO: should this be a blocking call to the server, so that we know the EGL surface is really
1065//destroyed before subsequently destroying the associated window?
1066//TODO: is it safe for asynchronous swap notifications to come back after the surface has been
1067//destroyed, or do we need to wait for them? (and how?)
1068EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surf)
1069{
1070 CLIENT_THREAD_STATE_T *thread;
1071 CLIENT_PROCESS_STATE_T *process;
1072 EGLBoolean result;
1073
1074 vcos_log_trace("eglDestroySurface: surf=%d.\n calling CLIENT_LOCK_AND_GET_STATES...", (int)surf);
1075
1076 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
1077 {
1078 EGL_SURFACE_T *surface;
1079
1080 thread->error = EGL_SUCCESS;
1081
1082 vcos_log_trace("eglDestroySurface: calling client_egl_get_surface...");
1083 surface = client_egl_get_surface(thread, process, surf);
1084
1085 if (surface) {
1086 surface->is_destroyed = true;
1087 khrn_pointer_map_delete(&process->surfaces, (uint32_t)(uintptr_t)surf);
1088 vcos_log_trace("eglDestroySurface: calling egl_surface_maybe_free...");
1089 egl_surface_maybe_free(surface);
1090 }
1091
1092 result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
1093
1094 CLIENT_UNLOCK();
1095 } else
1096 result = EGL_FALSE;
1097
1098 vcos_log_trace("eglDestroySurface: end");
1099 return result;
1100}
1101
1102EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surf,
1103 EGLint attribute, EGLint *value)
1104{
1105 CLIENT_THREAD_STATE_T *thread;
1106 CLIENT_PROCESS_STATE_T *process;
1107 EGLBoolean result;
1108
1109 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
1110 {
1111 EGL_SURFACE_T *surface;
1112
1113 thread->error = EGL_SUCCESS;
1114
1115 surface = client_egl_get_locked_surface(thread, process, surf);
1116
1117 if (surface) {
1118#if EGL_KHR_lock_surface
1119 switch (attribute)
1120 {
1121 case EGL_BITMAP_POINTER_KHR:
1122 case EGL_BITMAP_PITCH_KHR:
1123 case EGL_BITMAP_ORIGIN_KHR:
1124 case EGL_BITMAP_PIXEL_RED_OFFSET_KHR:
1125 case EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR:
1126 case EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR:
1127 case EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR:
1128 case EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR:
1129 thread->error = egl_surface_get_mapped_buffer_attrib(surface, attribute, value);
1130
1131 CLIENT_UNLOCK();
1132 return (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
1133 default:
1134 /* Other attributes can only be queried if the surface is unlocked */
1135 if (surface->is_locked) {
1136 thread->error = EGL_BAD_ACCESS;
1137 CLIENT_UNLOCK();
1138 return EGL_FALSE;
1139 }
1140 }
1141#endif
1142 if (!egl_surface_get_attrib(surface, attribute, value))
1143 thread->error = EGL_BAD_ATTRIBUTE;
1144 }
1145
1146 result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
1147
1148 CLIENT_UNLOCK();
1149 } else
1150 result = EGL_FALSE;
1151
1152 return result;
1153}
1154
1155EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api)
1156{
1157 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1158
1159 switch (api) {
1160 case EGL_OPENVG_API:
1161 case EGL_OPENGL_ES_API:
1162 thread->bound_api = api;
1163
1164 thread->error = EGL_SUCCESS;
1165 return EGL_TRUE;
1166 default:
1167 thread->error = EGL_BAD_PARAMETER;
1168 return EGL_FALSE;
1169 }
1170}
1171
1172EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void)
1173{
1174 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1175
1176 return thread->bound_api;
1177}
1178
1179EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void)
1180{
1181 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1182
1183 //TODO: "If the surface associated with the calling thread's current context is no
1184 //longer valid, EGL_FALSE is returned and an EGL_BAD_CURRENT_SURFACE error is
1185 //generated".
1186
1187 (void) RPC_INT_RES(RPC_CALL2_RES(eglIntFlushAndWait_impl,
1188 thread,
1189 EGLINTFLUSHANDWAIT_ID,
1190 RPC_UINT(thread->bound_api == EGL_OPENGL_ES_API),
1191 RPC_UINT(thread->bound_api == EGL_OPENVG_API))); // return unimportant - read is just to cause blocking
1192
1193 if (thread->bound_api == EGL_OPENGL_ES_API)
1194 egl_gl_flush_callback(true);
1195 else
1196 egl_vg_flush_callback(true);
1197
1198 thread->error = EGL_SUCCESS;
1199 return EGL_TRUE;
1200}
1201
1202//TODO: update pixmap surfaces?
1203EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void)
1204{
1205 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1206 bool destroy = false;
1207
1208
1209 vcos_log_trace("eglReleaseThread start.");
1210
1211 CLIENT_LOCK();
1212
1213 {
1214 CLIENT_PROCESS_STATE_T *process = CLIENT_GET_PROCESS_STATE();
1215
1216 if (process) {
1217 egl_current_release(process, &thread->opengl);
1218 egl_current_release(process, &thread->openvg);
1219
1220#ifdef RPC_LIBRARY
1221 /* TODO: not thread safe */
1222 const KHRONOS_FUNC_TABLE_T *func_table = khronos_server_lock_func_table(client_library_get_connection());
1223 if (func_table) {
1224 func_table->khrn_misc_rpc_flush_impl();
1225 }
1226 khronos_server_unlock_func_table();
1227#else
1228 RPC_FLUSH(thread);
1229#endif
1230
1231#ifndef RPC_DIRECT_MULTI
1232 //move it to khronos_exit()
1233 client_try_unload_server(process);
1234#endif
1235
1236 thread->error = EGL_SUCCESS;
1237 destroy = true;
1238 }
1239 }
1240
1241 CLIENT_UNLOCK();
1242
1243 if (destroy)
1244 platform_hint_thread_finished();
1245
1246 vcos_log_trace("eglReleaseThread end.");
1247
1248 return EGL_TRUE;
1249
1250 //TODO free thread state?
1251}
1252
1253EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(
1254 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1255 EGLConfig config, const EGLint *attrib_list)
1256{
1257 CLIENT_THREAD_STATE_T *thread;
1258 CLIENT_PROCESS_STATE_T *process;
1259 EGLSurface result;
1260
1261 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
1262 {
1263#ifndef NO_OPENVG
1264 if (buftype != EGL_OPENVG_IMAGE) {
1265 thread->error = EGL_BAD_PARAMETER;
1266 result = EGL_NO_SURFACE;
1267 } else if ((int)(size_t)config < 1 || (int)(size_t)config > EGL_MAX_CONFIGS) {
1268 thread->error = EGL_BAD_CONFIG;
1269 result = EGL_NO_SURFACE;
1270 } else {
1271 bool largest_pbuffer = 0;
1272 EGLenum texture_format = EGL_NO_TEXTURE;
1273 EGLenum texture_target = EGL_NO_TEXTURE;
1274 bool mipmap_texture = EGL_FALSE;
1275
1276 /* Ignore the width and height as specified by attrib_list */
1277 /* Also ignore linear and premult */
1278 if (!egl_surface_check_attribs(PBUFFER, attrib_list, 0, 0, 0, 0, 0, &largest_pbuffer, &texture_format, &texture_target, &mipmap_texture)) {
1279 thread->error = EGL_BAD_ATTRIBUTE;
1280 result = EGL_NO_SURFACE;
1281 } else if (
1282 (texture_format == EGL_NO_TEXTURE) != (texture_target == EGL_NO_TEXTURE) ||
1283 !egl_config_bindable((int)(size_t)config - 1, texture_format)
1284 ) {
1285
1286 /*
1287 "In addition, an EGL_BAD_MATCH
1288 error is generated if any of the following conditions are true:
1289 - The EGL_TEXTURE_FORMAT attribute is not EGL_NO_TEXTURE, and
1290 EGL_WIDTH and/or EGL_HEIGHT specify an invalid size (e.g., the texture size
1291 is not a power of two, and the underlying OpenGL ES implementation does
1292 not support non-power-of-two textures).
1293 - The EGL_TEXTURE_FORMAT attribute is EGL_NO_TEXTURE, and
1294 EGL_TEXTURE_TARGET is something other than EGL_NO_TEXTURE; or,
1295 EGL_TEXTURE_FORMAT is something other than EGL_NO_TEXTURE, and
1296 EGL_TEXTURE_TARGET is EGL_NO_TEXTURE."
1297 */
1298
1299 /*
1300 It doesn't seem to explicitly say it in the spec, but I'm also
1301 generating EGL_BAD_MATCH if the config doesn't support EGL_BIND_TO_TEXTURE_RGB(A)
1302 and you specify EGL_TEXTURE_FORMAT=EGL_TEXTURE_RGB(A)
1303 */
1304 thread->error = EGL_BAD_MATCH;
1305 result = EGL_NO_SURFACE;
1306 } else {
1307 EGLint error;
1308 EGL_SURFACE_T *surface = egl_surface_from_vg_image(
1309 (VGImage)(size_t)buffer,
1310 (EGLSurface)(size_t)process->next_surface,
1311 config,
1312 largest_pbuffer,
1313 mipmap_texture,
1314 texture_format,
1315 texture_target,
1316 &error);
1317
1318 if (surface) {
1319 if (khrn_pointer_map_insert(&process->surfaces, process->next_surface, surface)) {
1320 thread->error = EGL_SUCCESS;
1321 result = (EGLSurface)(size_t)process->next_surface++;
1322 } else {
1323 thread->error = EGL_BAD_ALLOC;
1324 result = EGL_NO_SURFACE;
1325 egl_surface_free(surface);
1326 }
1327 } else {
1328 thread->error = error;
1329 result = EGL_NO_SURFACE;
1330 }
1331 }
1332 }
1333#else
1334 UNUSED(buftype);
1335 UNUSED(buffer);
1336 UNUSED(config);
1337 UNUSED(attrib_list);
1338
1339 thread->error = EGL_BAD_PARAMETER;
1340 result = EGL_NO_SURFACE;
1341#endif /* NO_OPENVG */
1342 CLIENT_UNLOCK();
1343 }
1344 else
1345 result = EGL_NO_SURFACE;
1346
1347 return result;
1348}
1349
1350EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surf,
1351 EGLint attribute, EGLint value)
1352{
1353 CLIENT_THREAD_STATE_T *thread;
1354 CLIENT_PROCESS_STATE_T *process;
1355 EGLBoolean result;
1356
1357 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
1358 {
1359 EGL_SURFACE_T *surface;
1360
1361 thread->error = EGL_SUCCESS;
1362
1363 surface = client_egl_get_surface(thread, process, surf);
1364
1365 if (surface)
1366 thread->error = egl_surface_set_attrib(surface, attribute, value);
1367
1368 result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
1369 CLIENT_UNLOCK();
1370 } else
1371 result = EGL_FALSE;
1372
1373 return result;
1374}
1375
1376EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surf, EGLint buffer)
1377{
1378 CLIENT_THREAD_STATE_T *thread;
1379 CLIENT_PROCESS_STATE_T *process;
1380 EGLBoolean result;
1381
1382 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
1383 {
1384//TODO: is behaviour correct if there is no current rendering context?
1385 EGL_SURFACE_T *surface;
1386
1387 thread->error = EGL_SUCCESS;
1388
1389 surface = client_egl_get_surface(thread, process, surf);
1390
1391 if (surface) {
1392 if (surface->texture_format != EGL_NO_TEXTURE) {
1393 if (buffer == EGL_BACK_BUFFER) {
1394 if (surface->type == PBUFFER && surface->texture_target == EGL_TEXTURE_2D) {
1395 result = (EGLBoolean) RPC_BOOLEAN_RES(RPC_CALL1_RES(eglIntBindTexImage_impl,
1396 thread,
1397 EGLINTBINDTEXIMAGE_ID,
1398 surface->serverbuffer));
1399 if (result != EGL_TRUE) {
1400 // If buffer is already bound to a texture then an
1401 // EGL_BAD_ACCESS error is returned.
1402 // But we don't know whether it is or not until we call
1403 // the server.
1404 thread->error = EGL_BAD_ACCESS;
1405 }
1406 } else {
1407 thread->error = EGL_BAD_SURFACE;
1408 result = EGL_FALSE;
1409 }
1410 } else {
1411 thread->error = EGL_BAD_PARAMETER;
1412 result = EGL_FALSE;
1413 }
1414 } else {
1415 thread->error = EGL_BAD_MATCH;
1416 result = EGL_FALSE;
1417 }
1418 }
1419
1420 result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
1421 CLIENT_UNLOCK();
1422 } else
1423 result = EGL_FALSE;
1424
1425 return result;
1426}
1427
1428EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surf, EGLint buffer)
1429{
1430 CLIENT_THREAD_STATE_T *thread;
1431 CLIENT_PROCESS_STATE_T *process;
1432 EGLBoolean result;
1433
1434 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
1435 {
1436 EGL_SURFACE_T *surface;
1437
1438 thread->error = EGL_SUCCESS;
1439
1440 surface = client_egl_get_surface(thread, process, surf);
1441
1442 if (surface) {
1443 if (surface->texture_format != EGL_NO_TEXTURE) {
1444 if (buffer == EGL_BACK_BUFFER) {
1445 if (surface->type == PBUFFER) {
1446 //TODO: not a "bound" pbuffer?
1447 RPC_CALL1(eglIntReleaseTexImage_impl,
1448 thread,
1449 EGLINTRELEASETEXIMAGE_ID,
1450 surface->serverbuffer);
1451 } else {
1452 thread->error = EGL_BAD_SURFACE;
1453 result = EGL_FALSE;
1454 }
1455 } else {
1456 thread->error = EGL_BAD_PARAMETER;
1457 result = EGL_FALSE;
1458 }
1459 } else {
1460 thread->error = EGL_BAD_MATCH;
1461 result = EGL_FALSE;
1462 }
1463 }
1464
1465 result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
1466 CLIENT_UNLOCK();
1467 } else
1468 result = EGL_FALSE;
1469
1470 return result;
1471}
1472
1473EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval)
1474{
1475 CLIENT_THREAD_STATE_T *thread;
1476 CLIENT_PROCESS_STATE_T *process;
1477 EGLBoolean result;
1478
1479 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
1480 {
1481 EGL_CURRENT_T *current;
1482 EGL_SURFACE_T *surface;
1483
1484 /* the spec says "the window associated with the current context". it
1485 * doesn't explicitly say "the current context for the current rendering
1486 * api" (which it does in most other places), but i'm assuming that's what
1487 * it means */
1488
1489 if (thread->bound_api == EGL_OPENVG_API)
1490 current = &thread->openvg;
1491 else
1492 current = &thread->opengl;
1493
1494 surface = current->draw;
1495
1496 if (surface) {
1497 if (surface->type == WINDOW) {
1498 if (interval < EGL_CONFIG_MIN_SWAP_INTERVAL)
1499 interval = EGL_CONFIG_MIN_SWAP_INTERVAL;
1500 if (interval > EGL_CONFIG_MAX_SWAP_INTERVAL)
1501 interval = EGL_CONFIG_MAX_SWAP_INTERVAL;
1502
1503 surface->swap_interval = (uint32_t) interval;
1504 }
1505
1506 RPC_CALL2(eglIntSwapInterval_impl,
1507 thread,
1508 EGLINTSWAPINTERVAL_ID,
1509 surface->serverbuffer,
1510 surface->swap_interval);
1511
1512 /* TODO: should we raise an error if it's not a window
1513 * surface, or silently ignore it?
1514 */
1515 thread->error = EGL_SUCCESS;
1516 result = EGL_TRUE;
1517 } else {
1518 /*
1519 "If there is no current context
1520 on the calling thread, a EGL BAD CONTEXT error is generated. If there is no surface
1521 bound to the current context, a EGL BAD SURFACE error is generated."
1522
1523 TODO
1524 This doesn't make sense to me - the current context always has surfaces
1525 bound to it, so which error do we raise?
1526 */
1527 thread->error = EGL_BAD_SURFACE;
1528 result = EGL_FALSE;
1529 }
1530 CLIENT_UNLOCK();
1531 }
1532 else
1533 result = EGL_FALSE;
1534
1535 return result;
1536}
1537
1538EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_ctx, const EGLint *attrib_list)
1539{
1540 CLIENT_THREAD_STATE_T *thread;
1541 CLIENT_PROCESS_STATE_T *process;
1542 EGLContext result;
1543
1544vcos_log_trace("eglCreateContext start");
1545
1546 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
1547 {
1548 if ((int)(size_t)config < 1 || (int)(size_t)config > EGL_MAX_CONFIGS) {
1549 thread->error = EGL_BAD_CONFIG;
1550 result = EGL_NO_CONTEXT;
1551 } else {
1552 EGLint max_version = (EGLint) (thread->bound_api == EGL_OPENGL_ES_API ? 2 : 1);
1553 EGLint version = 1;
1554
1555 if (!egl_context_check_attribs(attrib_list, max_version, &version)) {
1556 thread->error = EGL_BAD_ATTRIBUTE;
1557 result = EGL_NO_CONTEXT;
1558 } else if (!(egl_config_get_api_support((int)(intptr_t)config - 1) &
1559 ((thread->bound_api == EGL_OPENVG_API) ? EGL_OPENVG_BIT :
1560 ((version == 1) ? EGL_OPENGL_ES_BIT : EGL_OPENGL_ES2_BIT)))) {
1561 thread->error = EGL_BAD_CONFIG;
1562 result = EGL_NO_CONTEXT;
1563 } else {
1564 EGL_CONTEXT_T *share_context;
1565
1566 if (share_ctx != EGL_NO_CONTEXT) {
1567 share_context = client_egl_get_context(thread, process, share_ctx);
1568
1569 if (share_context) {
1570 if ((share_context->type == OPENVG && thread->bound_api != EGL_OPENVG_API) ||
1571 (share_context->type != OPENVG && thread->bound_api == EGL_OPENVG_API)) {
1572 thread->error = EGL_BAD_MATCH;
1573 share_context = NULL;
1574 }
1575 } else {
1576 thread->error = EGL_BAD_CONTEXT;
1577 }
1578 } else {
1579 share_context = NULL;
1580 }
1581
1582 if (share_ctx == EGL_NO_CONTEXT || share_context) {
1583 EGL_CONTEXT_T *context;
1584 EGL_CONTEXT_TYPE_T type;
1585
1586#ifndef NO_OPENVG
1587 if (thread->bound_api == EGL_OPENVG_API)
1588 type = OPENVG;
1589 else
1590#endif
1591 if (version == 1)
1592 type = OPENGL_ES_11;
1593 else
1594 type = OPENGL_ES_20;
1595
1596 context = egl_context_create(
1597 share_context,
1598 (EGLContext)(size_t)process->next_context,
1599 dpy, config, type);
1600
1601 if (context) {
1602 if (khrn_pointer_map_insert(&process->contexts, process->next_context, context)) {
1603 thread->error = EGL_SUCCESS;
1604 result = (EGLContext)(size_t)process->next_context++;
1605 } else {
1606 thread->error = EGL_BAD_ALLOC;
1607 result = EGL_NO_CONTEXT;
1608 egl_context_term(context);
1609 khrn_platform_free(context);
1610 }
1611 } else {
1612 thread->error = EGL_BAD_ALLOC;
1613 result = EGL_NO_CONTEXT;
1614 }
1615 } else {
1616 /* thread->error set above */
1617 result = EGL_NO_CONTEXT;
1618 }
1619 }
1620 }
1621 CLIENT_UNLOCK();
1622 }
1623 else
1624 result = EGL_NO_CONTEXT;
1625
1626 vcos_log_trace("eglCreateContext end");
1627
1628 return result;
1629}
1630
1631EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1632{
1633 CLIENT_THREAD_STATE_T *thread;
1634 CLIENT_PROCESS_STATE_T *process;
1635 EGLBoolean result;
1636
1637 vcos_log_trace("eglDestroyContext ctx=%d.", (int)ctx);
1638
1639 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
1640 {
1641 EGL_CONTEXT_T *context;
1642
1643 thread->error = EGL_SUCCESS;
1644
1645 context = client_egl_get_context(thread, process, ctx);
1646
1647 if (context) {
1648 context->is_destroyed = true;
1649 khrn_pointer_map_delete(&process->contexts, (uint32_t)(uintptr_t)ctx);
1650 egl_context_maybe_free(context);
1651 }
1652 result = thread->error == EGL_SUCCESS;
1653 CLIENT_UNLOCK();
1654 }
1655 else
1656 result = EGL_FALSE;
1657
1658 return result;
1659}
1660
1661static void egl_current_release(CLIENT_PROCESS_STATE_T *process, EGL_CURRENT_T *current)
1662{
1663 if (current->context) {
1664 EGL_CONTEXT_T *context = current->context;
1665 vcos_assert(context->is_current);
1666 context->is_current = false;
1667 context->renderbuffer = EGL_NONE;
1668 egl_context_set_callbacks(context, NULL, NULL, NULL, NULL);
1669
1670 current->context = 0;
1671
1672 egl_context_maybe_free(context);
1673
1674 vcos_assert(process->context_current_count > 0);
1675 process->context_current_count--;
1676 }
1677 if (current->draw) {
1678 EGL_SURFACE_T *draw = current->draw;
1679
1680 vcos_assert(draw->context_binding_count > 0);
1681 draw->context_binding_count--;
1682
1683 current->draw = 0;
1684
1685 egl_surface_maybe_free(draw);
1686 }
1687 if (current->read) {
1688 EGL_SURFACE_T *read = current->read;
1689
1690 vcos_assert(read->context_binding_count > 0);
1691 read->context_binding_count--;
1692
1693 current->read = 0;
1694
1695 egl_surface_maybe_free(read);
1696 }
1697}
1698
1699static void set_color_data(EGL_SURFACE_ID_T surface_id, KHRN_IMAGE_WRAP_T *image)
1700{
1701 int line_size = (image->stride < 0) ? -image->stride : image->stride;
1702 int lines = KHDISPATCH_WORKSPACE_SIZE / line_size;
1703 int offset = 0;
1704 int height = image->height;
1705
1706 if (khrn_image_is_brcm1(image->format))
1707 lines &= ~63;
1708
1709 vcos_assert(lines > 0);
1710
1711 while (height > 0) {
1712 int batch = _min(lines, height);
1713#ifndef RPC_DIRECT
1714 uint32_t len = batch * line_size;
1715#endif
1716
1717 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1718 int adjusted_offset = (image->stride < 0) ? (offset + (batch - 1)) : offset;
1719
1720 RPC_CALL7_IN_BULK(eglIntSetColorData_impl,
1721 thread,
1722 EGLINTSETCOLORDATA_ID,
1723 surface_id,
1724 image->format,
1725 image->width,
1726 batch,
1727 image->stride,
1728 offset,
1729 (const char *)image->storage + adjusted_offset * image->stride,
1730 len);
1731
1732 offset += batch;
1733 height -= batch;
1734 }
1735}
1736
1737static void send_pixmap(EGL_SURFACE_T *surface)
1738{
1739 if (surface && surface->type == PIXMAP && !surface->pixmap_server_handle[0] && (surface->pixmap_server_handle[1] == (uint32_t)-1) && !surface->server_owned) {
1740 KHRN_IMAGE_WRAP_T image;
1741
1742 if (!platform_get_pixmap_info(surface->pixmap, &image)) {
1743 (void)vcos_verify(0); /* the pixmap has become invalid... */
1744 return;
1745 }
1746
1747 set_color_data(surface->serverbuffer, &image);
1748
1749 platform_send_pixmap_completed(surface->pixmap);
1750
1751 surface->server_owned = true;
1752
1753 khrn_platform_release_pixmap_info(surface->pixmap, &image);
1754 }
1755}
1756
1757void egl_gl_render_callback(void)
1758{
1759 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1760
1761 CLIENT_LOCK();
1762
1763 send_pixmap(thread->opengl.draw);
1764
1765 CLIENT_UNLOCK();
1766}
1767
1768void egl_vg_render_callback(void)
1769{
1770 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1771
1772 CLIENT_LOCK();
1773
1774 send_pixmap(thread->openvg.draw);
1775
1776 CLIENT_UNLOCK();
1777}
1778
1779static void get_color_data(EGL_SURFACE_ID_T surface_id, KHRN_IMAGE_WRAP_T *image)
1780{
1781 int line_size = (image->stride < 0) ? -image->stride : image->stride;
1782 int lines = KHDISPATCH_WORKSPACE_SIZE / line_size;
1783 int offset = 0;
1784 int height = image->height;
1785
1786 if (khrn_image_is_brcm1(image->format))
1787 lines &= ~63;
1788
1789 vcos_assert(lines > 0);
1790
1791 while (height > 0) {
1792 int batch = _min(lines, height);
1793
1794 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1795 int adjusted_offset = (image->stride < 0) ? (offset + (batch - 1)) : offset;
1796
1797 RPC_CALL7_OUT_BULK(eglIntGetColorData_impl,
1798 thread,
1799 EGLINTGETCOLORDATA_ID,
1800 surface_id,
1801 image->format,
1802 image->width,
1803 batch,
1804 image->stride,
1805 offset,
1806 (char *)image->storage + adjusted_offset * image->stride);
1807
1808 offset += batch;
1809 height -= batch;
1810 }
1811}
1812
1813static void retrieve_pixmap(EGL_SURFACE_T *surface, bool wait)
1814{
1815 UNUSED(wait);
1816
1817 /*TODO: currently we always wait */
1818 if (surface && surface->type == PIXMAP && !surface->pixmap_server_handle[0] && (surface->pixmap_server_handle[1] == (uint32_t)-1) && surface->server_owned) {
1819 KHRN_IMAGE_WRAP_T image;
1820
1821 if (!platform_get_pixmap_info(surface->pixmap, &image)) {
1822 (void)vcos_verify(0); /* the pixmap has become invalid... */
1823 return;
1824 }
1825
1826 get_color_data(surface->serverbuffer, &image);
1827
1828//Do any platform specific syncronisation or notification of modification
1829 platform_retrieve_pixmap_completed(surface->pixmap);
1830
1831 surface->server_owned = false;
1832 khrn_platform_release_pixmap_info(surface->pixmap, &image);
1833 }
1834}
1835
1836void egl_gl_flush_callback(bool wait)
1837{
1838 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1839
1840 CLIENT_LOCK();
1841
1842 retrieve_pixmap(thread->opengl.draw, wait);
1843
1844 CLIENT_UNLOCK();
1845}
1846
1847void egl_vg_flush_callback(bool wait)
1848{
1849 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1850
1851 CLIENT_LOCK();
1852
1853 retrieve_pixmap(thread->openvg.draw, wait);
1854
1855 CLIENT_UNLOCK();
1856}
1857
1858static bool context_and_surface_are_compatible(EGL_CONTEXT_T *context, EGL_SURFACE_T *surface)
1859{
1860 /*
1861 from section 2.2 of the (1.3) spec, a context and surface are compatible
1862 if:
1863 1) they support the same type of color buffer (rgb or luminance). this is
1864 trivially true for us as we only support rgb color buffers
1865 2) they have color buffers and ancillary buffers of the same depth
1866 3) the surface was created with respect to an EGLConfig supporting client
1867 api rendering of the same type as the api type of the context
1868 4) they were created with respect to the same EGLDisplay. this is
1869 trivially true for us as we only have one EGLDisplay
1870 */
1871
1872 uint32_t api_type = 0;
1873 switch (context->type) {
1874 case OPENGL_ES_11: api_type = EGL_OPENGL_ES_BIT; break;
1875 case OPENGL_ES_20: api_type = EGL_OPENGL_ES2_BIT; break;
1876 case OPENVG: api_type = EGL_OPENVG_BIT; break;
1877 default: UNREACHABLE();
1878 }
1879
1880 return
1881 egl_config_bpps_match((int)(intptr_t)context->configname - 1, (int)(intptr_t)surface->config - 1) && /* (2) */
1882 (egl_config_get_api_support((int)(intptr_t)surface->config - 1) & api_type); /* (3) */
1883}
1884
1885static bool egl_current_set(CLIENT_PROCESS_STATE_T *process, CLIENT_THREAD_STATE_T *thread, EGL_CURRENT_T *current, EGL_CONTEXT_T *context, EGL_SURFACE_T *draw, EGL_SURFACE_T *read)
1886{
1887 bool result = false;
1888
1889 UNUSED(process);
1890
1891 if (context->is_current && context->thread != thread) {
1892 // Fail - context is current to some other thread
1893 thread->error = EGL_BAD_ACCESS;
1894 } else if (draw->context_binding_count && draw->thread != thread) {
1895 // Fail - draw surface is bound to context which is current to another thread
1896 thread->error = EGL_BAD_ACCESS;
1897 } else if (read->context_binding_count && read->thread != thread) {
1898 // Fail - read surface is bound to context which is current to another thread
1899 thread->error = EGL_BAD_ACCESS;
1900 } else if (!context_and_surface_are_compatible(context, draw)) {
1901 // Fail - draw surface is not compatible with context
1902 thread->error = EGL_BAD_MATCH;
1903 } else if (!context_and_surface_are_compatible(context, read)) {
1904 // Fail - read surface is not compatible with context
1905 thread->error = EGL_BAD_MATCH;
1906 } else {
1907 egl_current_release(process, current);
1908
1909 context->is_current = true;
1910 context->thread = thread;
1911
1912 /* TODO: GLES supposedly doesn't support single-buffered rendering. Should we take this into account? */
1913 context->renderbuffer = egl_surface_get_render_buffer(draw);
1914
1915 // Check surfaces are not bound to a different thread, and increase their reference count
1916
1917 draw->thread = thread;
1918 draw->context_binding_count++;
1919
1920 read->thread = thread;
1921 read->context_binding_count++;
1922
1923 current->context = context;
1924 current->draw = draw;
1925 current->read = read;
1926
1927 process->context_current_count++;
1928
1929 result = true;
1930 }
1931 if (draw->type == PIXMAP) {
1932 egl_context_set_callbacks(context, egl_gl_render_callback, egl_gl_flush_callback, egl_vg_render_callback, egl_vg_flush_callback);
1933 } else {
1934 egl_context_set_callbacks(context, NULL,NULL, NULL, NULL);
1935 }
1936
1937 return result;
1938}
1939
1940static void flush_current_api(CLIENT_THREAD_STATE_T *thread)
1941{
1942 RPC_CALL2(eglIntFlush_impl,
1943 thread,
1944 EGLINTFLUSH_ID,
1945 RPC_UINT(thread->bound_api == EGL_OPENGL_ES_API),
1946 RPC_UINT(thread->bound_api == EGL_OPENVG_API));
1947 RPC_FLUSH(thread);
1948
1949 if (thread->bound_api == EGL_OPENGL_ES_API)
1950 egl_gl_flush_callback(false);
1951 else
1952 egl_vg_flush_callback(false);
1953}
1954
1955EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface dr, EGLSurface rd, EGLContext ctx)
1956{
1957 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1958 EGLBoolean result;
1959 CLIENT_PROCESS_STATE_T *process = NULL; /* init to avoid warnings */
1960
1961 CLIENT_LOCK();
1962
1963 vcos_log_trace("Actual eglMakeCurrent %d %d %x", (int)ctx, (int)dr, (unsigned int) thread->error);
1964
1965 /*
1966 check whether we are trying to release the current context
1967 Note that we can do this even if the display isn't initted.
1968 */
1969
1970 if (dr == EGL_NO_SURFACE && rd == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT) {
1971 process = client_egl_get_process_state(thread, dpy, EGL_FALSE);
1972
1973 if (process) {
1974 /* spec says we should flush in this case */
1975 flush_current_api(thread);
1976
1977 egl_current_release(process,
1978 (thread->bound_api == EGL_OPENVG_API) ? &thread->openvg : &thread->opengl);
1979
1980 client_send_make_current(thread);
1981
1982 client_try_unload_server(process);
1983
1984 thread->error = EGL_SUCCESS;
1985 result = EGL_TRUE;
1986 } else {
1987 result = EGL_FALSE;
1988 }
1989 } else if (dr == EGL_NO_SURFACE || rd == EGL_NO_SURFACE || ctx == EGL_NO_CONTEXT) {
1990 thread->error = EGL_BAD_MATCH;
1991 result = EGL_FALSE;
1992 } else {
1993 /*
1994 get display
1995 */
1996
1997 process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
1998
1999 if (!process)
2000 result = EGL_FALSE;
2001 else {
2002 /*
2003 get context
2004 */
2005
2006 EGL_CONTEXT_T *context = client_egl_get_context(thread, process, ctx);
2007
2008 if (!context) {
2009 result = EGL_FALSE;
2010 } else {
2011
2012 /*
2013 get surfaces
2014 */
2015
2016 EGL_SURFACE_T *draw = client_egl_get_surface(thread, process, dr);
2017 EGL_SURFACE_T *read = client_egl_get_surface(thread, process, rd);
2018
2019 if (!draw || !read) {
2020 result = EGL_FALSE;
2021 } else if (context->type == OPENVG && dr != rd) {
2022 thread->error = EGL_BAD_MATCH; //TODO: what error are we supposed to return here?
2023 result = EGL_FALSE;
2024 } else {
2025 EGL_CURRENT_T *current;
2026
2027 if (context->type == OPENVG)
2028 current = &thread->openvg;
2029 else
2030 current = &thread->opengl;
2031
2032 if (!egl_current_set(process, thread, current, context, draw, read))
2033 result = EGL_FALSE;
2034 else {
2035 client_send_make_current(thread);
2036
2037 thread->error = EGL_SUCCESS;
2038 result = EGL_TRUE;
2039 }
2040 }
2041 }
2042 }
2043 }
2044
2045 CLIENT_UNLOCK();
2046
2047 vcos_log_trace("Actual eglMakeCurrent end %d %d %d %x", (int)ctx, (int)dr, result, (unsigned int)thread->error);
2048
2049 return result;
2050}
2051
2052EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void)
2053{
2054 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2055 EGLContext result;
2056
2057 CLIENT_LOCK();
2058
2059 {
2060 EGL_CURRENT_T *current;
2061
2062 if (thread->bound_api == EGL_OPENVG_API)
2063 current = &thread->openvg;
2064 else
2065 current = &thread->opengl;
2066
2067 if (!current->context)
2068 result = EGL_NO_CONTEXT;
2069 else
2070 result = current->context->name;
2071
2072 thread->error = EGL_SUCCESS;
2073 }
2074
2075 CLIENT_UNLOCK();
2076
2077 return result;
2078}
2079
2080EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw)
2081{
2082 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2083 EGLSurface result;
2084
2085 CLIENT_LOCK();
2086
2087 {
2088 EGL_CURRENT_T *current;
2089 EGL_SURFACE_T *surface;
2090
2091 if (thread->bound_api == EGL_OPENVG_API)
2092 current = &thread->openvg;
2093 else
2094 current = &thread->opengl;
2095
2096 switch (readdraw) {
2097 case EGL_READ:
2098 surface = current->read;
2099 thread->error = EGL_SUCCESS;
2100 break;
2101 case EGL_DRAW:
2102 surface = current->draw;
2103 thread->error = EGL_SUCCESS;
2104 break;
2105 default:
2106 surface = 0;
2107 thread->error = EGL_BAD_PARAMETER;
2108 break;
2109 }
2110
2111 if (!surface)
2112 result = EGL_NO_SURFACE;
2113 else
2114 result = surface->name;
2115 }
2116
2117 CLIENT_UNLOCK();
2118
2119 return result;
2120}
2121
2122EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void)
2123{
2124 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2125 EGLDisplay result;
2126
2127 CLIENT_LOCK();
2128
2129 {
2130 EGL_CURRENT_T *current;
2131
2132 if (thread->bound_api == EGL_OPENVG_API)
2133 current = &thread->openvg;
2134 else
2135 current = &thread->opengl;
2136
2137 if (!current->context)
2138 result = EGL_NO_DISPLAY;
2139 else
2140 result = current->context->display;
2141
2142 thread->error = EGL_SUCCESS;
2143 }
2144
2145 CLIENT_UNLOCK();
2146
2147 return result;
2148}
2149
2150EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
2151{
2152 CLIENT_THREAD_STATE_T *thread;
2153 CLIENT_PROCESS_STATE_T *process;
2154 EGLBoolean result;
2155
2156 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
2157 {
2158 if (!value) {
2159 thread->error = EGL_BAD_PARAMETER;
2160 result = EGL_FALSE;
2161 } else {
2162 EGL_CONTEXT_T *context;
2163
2164 thread->error = EGL_SUCCESS;
2165
2166 context = client_egl_get_context(thread, process, ctx);
2167
2168 if (context) {
2169 if (!egl_context_get_attrib(context, attribute, value))
2170 thread->error = EGL_BAD_ATTRIBUTE;
2171
2172 }
2173 result = thread->error == EGL_SUCCESS;
2174 }
2175 CLIENT_UNLOCK();
2176 }
2177 else
2178 result = EGL_FALSE;
2179
2180 return result;
2181}
2182
2183EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void)
2184{
2185 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2186 EGLBoolean result;
2187
2188 //TODO: "If the surface associated with the calling thread's current context is no
2189 //longer valid, EGL_FALSE is returned and an EGL_BAD_CURRENT_SURFACE error is
2190 //generated".
2191 (void) RPC_INT_RES(RPC_CALL2_RES(eglIntFlushAndWait_impl,
2192 thread,
2193 EGLINTFLUSHANDWAIT_ID,
2194 RPC_UINT(true),
2195 RPC_UINT(false))); // return unimportant - read is just to cause blocking
2196
2197 egl_gl_flush_callback(true);
2198
2199 thread->error = EGL_SUCCESS;
2200 result = EGL_TRUE;
2201
2202 return result;
2203}
2204
2205EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine)
2206{
2207 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2208 EGLBoolean result;
2209
2210 //TODO: "If the surface associated with the calling thread's current context is no
2211 //longer valid, EGL_FALSE is returned and an EGL_BAD_CURRENT_SURFACE error is
2212 //generated".
2213
2214 if (engine == EGL_CORE_NATIVE_ENGINE) {
2215 //TODO: currently nothing we can do here
2216 thread->error = EGL_SUCCESS;
2217 result = EGL_TRUE;
2218 } else {
2219 thread->error = EGL_BAD_PARAMETER;
2220 result = EGL_FALSE;
2221 }
2222
2223 return result;
2224}
2225
2226EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surf)
2227{
2228#ifdef DIRECT_RENDERING
2229 /* Wrapper layer shouldn't call eglSwapBuffers */
2230 UNREACHABLE();
2231 return EGL_FALSE;
2232#else
2233 CLIENT_THREAD_STATE_T *thread;
2234 CLIENT_PROCESS_STATE_T *process;
2235 EGLBoolean result;
2236
2237 vcos_log_trace("eglSwapBuffers start. dpy=%d. surf=%d.", (int)dpy, (int)surf);
2238
2239 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
2240 {
2241 EGL_SURFACE_T *surface;
2242
2243 thread->error = EGL_SUCCESS;
2244
2245 surface = client_egl_get_surface(thread, process, surf);
2246
2247 vcos_log_trace("eglSwapBuffers get surface %x",(int)surface);
2248
2249 if (surface) {
2250
2251#if !(EGL_KHR_lock_surface)
2252 /* Surface to be displayed must be bound to current context and API */
2253 /* This check is disabled if we have the EGL_KHR_lock_surface extension */
2254 if (thread->bound_api == EGL_OPENGL_ES_API && surface != thread->opengl.draw && surface != thread->opengl.read
2255 || thread->bound_api == EGL_OPENVG_API && surface != thread->openvg.draw) {
2256 thread->error = EGL_BAD_SURFACE;
2257 } else
2258#endif
2259 {
2260
2261 if (surface->type == WINDOW) {
2262 uint32_t width, height, swapchain_count;
2263
2264 /* the egl spec says eglSwapBuffers is supposed to be a no-op for
2265 * single-buffered surfaces, but we pass it through as the
2266 * semantics are potentially useful:
2267 * - any ops outstanding on the surface are flushed
2268 * - the surface is resubmitted to the display once the
2269 * outstanding ops complete (for displays which have their own
2270 * memory, this is useful)
2271 * - the surface is resized to fit the backing window */
2272
2273 // We need to check at this point if the surface has resized, and pass
2274 // size data down to the server.
2275
2276 width = surface->width;
2277 height = surface->height;
2278
2279 platform_get_dimensions(dpy, surface->win,
2280 &width, &height, &swapchain_count);
2281
2282 if((width!=surface->width)||(height!=surface->height)) {
2283 uint32_t handle = platform_get_handle(dpy, surface->win);
2284 surface->internal_handle = handle;
2285 surface->width = width;
2286 surface->height = height;
2287 }
2288
2289 vcos_log_trace("eglSwapBuffers comparison: %d %d, %d %d",
2290 surface->width, surface->base_width, surface->height,
2291 surface->base_height);
2292
2293 /* TODO: raise EGL_BAD_ALLOC if we try to enlarge window and then run out of memory
2294
2295 if (surface->width <= surface->base_width && surface->height <= surface->base_height ||
2296 surface->width <= surface->base_height && surface->height <= surface->base_width)
2297 */
2298 // We don't call flush_current_api() here because it's only relevant
2299 // for pixmap surfaces (eglIntSwapBuffers takes care of flushing on
2300 // the server side).
2301
2302 platform_surface_update(surface->internal_handle);
2303
2304 vcos_log_trace("eglSwapBuffers server call");
2305
2306 RPC_CALL6(eglIntSwapBuffers_impl,
2307 thread,
2308 EGLINTSWAPBUFFERS_ID,
2309 RPC_UINT(surface->serverbuffer),
2310 RPC_UINT(surface->width),
2311 RPC_UINT(surface->height),
2312 RPC_UINT(surface->internal_handle),
2313 RPC_UINT(surface->swap_behavior == EGL_BUFFER_PRESERVED ? 1 : 0),
2314 RPC_UINT(khrn_platform_get_window_position(surface->win)));
2315
2316 RPC_FLUSH(thread);
2317
2318#ifdef ANDROID
2319 CLIENT_UNLOCK();
2320 platform_dequeue(dpy, surface->win);
2321 CLIENT_LOCK();
2322#else
2323
2324# ifdef KHRONOS_EGL_PLATFORM_OPENWFC
2325 wfc_stream_await_buffer((WFCNativeStreamType) surface->internal_handle);
2326# else
2327# ifndef RPC_LIBRARY
2328 if (surface->buffers > 1) {
2329 //TODO implement khan (khronos async notification) receiver for linux
2330# ifndef RPC_DIRECT_MULTI
2331 vcos_log_trace("eglSwapBuffers waiting for semaphore");
2332 khronos_platform_semaphore_acquire(&surface->avail_buffers);
2333# endif
2334 }
2335# endif // RPC_LIBRARY
2336# endif // KHRONOS_EGL_PLATFORM_OPENWFC
2337
2338#endif /* ANDROID */
2339
2340 } else {
2341#ifdef KHRN_COMMAND_MODE_DISPLAY
2342//Check for single buffered windows surface (and VG) in which case call vgFlush to allow screen update for command mode screens
2343 EGL_SURFACE_T *surface = CLIENT_GET_THREAD_STATE()->openvg.draw;
2344 if (surface->type == WINDOW && surface->buffers==1 && thread->bound_api == EGL_OPENVG_API) {
2345 vgFlush();
2346 }
2347#endif
2348 }
2349 // else do nothing. eglSwapBuffers has no effect on pixmap or pbuffer surfaces
2350 }
2351 }
2352
2353 result = (thread->error == EGL_SUCCESS);
2354 CLIENT_UNLOCK();
2355 }
2356 else
2357 result = EGL_FALSE;
2358
2359 vcos_log_trace("eglSwapBuffers end");
2360
2361 return result;
2362#endif // DIRECT_RENDERING
2363}
2364
2365EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType target)
2366{
2367 CLIENT_THREAD_STATE_T *thread;
2368 CLIENT_PROCESS_STATE_T *process;
2369 EGLBoolean result;
2370
2371 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
2372 {
2373 EGL_SURFACE_T *surface;
2374
2375 thread->error = EGL_SUCCESS;
2376
2377 surface = client_egl_get_surface(thread, process, surf);
2378
2379 if ((thread->bound_api == EGL_OPENGL_ES_API && surface != thread->opengl.draw && surface != thread->opengl.read)
2380 || (thread->bound_api == EGL_OPENVG_API && surface != thread->openvg.draw)) {
2381 /* Surface to be displayed must be bound to current context and API */
2382 /* TODO remove this restriction, as we'll need to for eglSwapBuffers? */
2383 thread->error = EGL_BAD_SURFACE;
2384 } else if (surface) {
2385 KHRN_IMAGE_WRAP_T image;
2386
2387 if (!platform_get_pixmap_info(target, &image)) {
2388 thread->error = EGL_BAD_NATIVE_PIXMAP;
2389 } else {
2390 if (image.width != surface->width || image.height != surface->height) {
2391 thread->error = EGL_BAD_MATCH;
2392 } else {
2393 //Bear in mind it's possible to call eglCopyBuffers on a pixmap
2394 //surface which will result in the data being transferred twice, onto
2395 //two different native pixmaps.
2396
2397 //TODO: flush the other API too?
2398 //TODO: is this necessary?
2399 flush_current_api(thread);
2400
2401 get_color_data(surface->serverbuffer, &image);
2402 }
2403 khrn_platform_release_pixmap_info(target, &image);
2404 }
2405 }
2406
2407 result = (thread->error == EGL_SUCCESS);
2408 CLIENT_UNLOCK();
2409 }
2410 else
2411 result = EGL_FALSE;
2412
2413 return result;
2414}
2415
2416//#define EXPORT_DESTROY_BY_PID // define me to export a utility function which will destroy the resources associated with a given process
2417#ifdef EXPORT_DESTROY_BY_PID
2418EGLAPI void EGLAPIENTRY eglDestroyByPidBRCM(EGLDisplay dpy, uint32_t pid_0, uint32_t pid_1)
2419{
2420 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2421 EGLBoolean result;
2422
2423 CLIENT_LOCK();
2424
2425 {
2426 CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
2427
2428 if (!process)
2429 result = 0;
2430 else {
2431 RPC_CALL2(eglIntDestroyByPid_impl,
2432 thread,
2433 EGLINTDESTROYBYPID_ID,
2434 RPC_UINT(pid_0),
2435 RPC_UINT(pid_1));
2436
2437 result = 1;
2438 }
2439 }
2440
2441 CLIENT_UNLOCK();
2442}
2443#endif
2444
2445#ifdef DIRECT_RENDERING
2446EGLAPI EGLBoolean EGLAPIENTRY eglDirectRenderingPointer(EGLDisplay dpy, EGLSurface surf, void *image)
2447{
2448 CLIENT_THREAD_STATE_T *thread;
2449 CLIENT_PROCESS_STATE_T *process;
2450 EGLBoolean result = EGL_FALSE;
2451
2452 if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
2453 {
2454 EGL_SURFACE_T *surface;
2455
2456 thread->error = EGL_SUCCESS;
2457
2458 surface = client_egl_get_surface(thread, process, surf);
2459
2460 if (surface)
2461 {
2462 KHRN_IMAGE_WRAP_T *image_wrap = (KHRN_IMAGE_WRAP_T *)image;
2463 surface->width = image_wrap->width;
2464 surface->height = image_wrap->height;
2465 RPC_CALL6(eglDirectRenderingPointer_impl,
2466 thread,
2467 EGLDIRECTRENDERINGPOINTER_ID,
2468 surface->serverbuffer,
2469 (uint32_t)image_wrap->storage,
2470 image_wrap->format,
2471 image_wrap->width,
2472 image_wrap->height,
2473 image_wrap->stride);
2474 }
2475
2476 result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
2477
2478 CLIENT_UNLOCK();
2479 }
2480
2481 return result;
2482}
2483#endif
2484
2485#if EGL_proc_state_valid
2486EGLAPI void EGLAPIENTRY eglProcStateValid( EGLDisplay dpy, EGLBoolean *result )
2487{
2488 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2489
2490 CLIENT_LOCK();
2491
2492 vcos_log_trace("eglProcStateValid dpy=%d", (int)dpy );
2493
2494 {
2495 CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
2496
2497 if (!process) {
2498 *result = EGL_FALSE;
2499 }
2500 else {
2501 *result = EGL_TRUE;
2502 }
2503 }
2504
2505 CLIENT_UNLOCK();
2506
2507 vcos_log_trace("eglProcStateValid result=%d", *result );
2508 return;
2509}
2510#endif
2511
2512