1// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// libEGL.cpp: Implements the exported EGL functions.
16
17#include "main.h"
18#include "Display.h"
19#include "Surface.hpp"
20#include "Texture.hpp"
21#include "Context.hpp"
22#include "common/Image.hpp"
23#include "common/debug.h"
24#include "Common/Version.h"
25
26#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD)
27#include <system/window.h>
28#elif defined(USE_X11)
29#include "Main/libX11.hpp"
30#endif
31
32#include <algorithm>
33#include <vector>
34#include <string.h>
35
36namespace egl
37{
38namespace
39{
40sw::RecursiveLock *getDisplayLock(egl::Display *display) {
41 if (!display) return nullptr;
42 return display->getLock();
43}
44
45bool validateDisplay(egl::Display *display)
46{
47 if(display == EGL_NO_DISPLAY)
48 {
49 return error(EGL_BAD_DISPLAY, false);
50 }
51
52 if(!display->isInitialized())
53 {
54 return error(EGL_NOT_INITIALIZED, false);
55 }
56
57 return true;
58}
59
60bool validateConfig(egl::Display *display, EGLConfig config)
61{
62 if(!validateDisplay(display))
63 {
64 return false;
65 }
66
67 if(!display->isValidConfig(config))
68 {
69 return error(EGL_BAD_CONFIG, false);
70 }
71
72 return true;
73}
74
75bool validateContext(egl::Display *display, egl::Context *context)
76{
77 if(!validateDisplay(display))
78 {
79 return false;
80 }
81
82 if(!display->isValidContext(context))
83 {
84 return error(EGL_BAD_CONTEXT, false);
85 }
86
87 return true;
88}
89
90bool validateSurface(egl::Display *display, egl::Surface *surface)
91{
92 if(!validateDisplay(display))
93 {
94 return false;
95 }
96
97 if(!display->isValidSurface(surface))
98 {
99 return error(EGL_BAD_SURFACE, false);
100 }
101
102 return true;
103}
104
105// Class to facilitate conversion from EGLint to EGLAttrib lists.
106class EGLAttribs
107{
108public:
109 explicit EGLAttribs(const EGLint *attrib_list)
110 {
111 if(attrib_list)
112 {
113 while(*attrib_list != EGL_NONE)
114 {
115 attrib.push_back(static_cast<EGLAttrib>(*attrib_list));
116 attrib_list++;
117 }
118 }
119
120 attrib.push_back(EGL_NONE);
121 }
122
123 const EGLAttrib *operator&() const
124 {
125 return &attrib[0];
126 }
127
128private:
129 std::vector<EGLAttrib> attrib;
130};
131}
132
133EGLint EGLAPIENTRY GetError(void)
134{
135 TRACE("()");
136
137 EGLint error = egl::getCurrentError();
138
139 if(error != EGL_SUCCESS)
140 {
141 egl::setCurrentError(EGL_SUCCESS);
142 }
143
144 return error;
145}
146
147EGLDisplay EGLAPIENTRY GetDisplay(EGLNativeDisplayType display_id)
148{
149 TRACE("(EGLNativeDisplayType display_id = %p)", display_id);
150
151 if(display_id != EGL_DEFAULT_DISPLAY)
152 {
153 // FIXME: Check if display_id is the default display
154 }
155
156 #if defined(__linux__) && !defined(__ANDROID__)
157 #if defined(USE_X11)
158 if(!libX11)
159 #endif // Non X11 linux is headless only
160 {
161 return success(HEADLESS_DISPLAY);
162 }
163 #endif
164
165 return success(PRIMARY_DISPLAY); // We only support the default display
166}
167
168EGLBoolean EGLAPIENTRY Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
169{
170 TRACE("(EGLDisplay dpy = %p, EGLint *major = %p, EGLint *minor = %p)",
171 dpy, major, minor);
172
173 egl::Display *display = egl::Display::get(dpy);
174
175 RecursiveLockGuard lock(egl::getDisplayLock(display));
176
177 if(!display)
178 {
179 return error(EGL_BAD_DISPLAY, EGL_FALSE);
180 }
181
182 if(!display->initialize())
183 {
184 return error(EGL_NOT_INITIALIZED, EGL_FALSE);
185 }
186
187 if(major) *major = 1;
188 if(minor) *minor = 4;
189
190 return success(EGL_TRUE);
191}
192
193EGLBoolean EGLAPIENTRY Terminate(EGLDisplay dpy)
194{
195 TRACE("(EGLDisplay dpy = %p)", dpy);
196
197 if(dpy == EGL_NO_DISPLAY)
198 {
199 return error(EGL_BAD_DISPLAY, EGL_FALSE);
200 }
201
202 egl::Display *display = egl::Display::get(dpy);
203
204 RecursiveLockGuard lock(egl::getDisplayLock(display));
205
206 display->terminate();
207
208 return success(EGL_TRUE);
209}
210
211const char *EGLAPIENTRY QueryString(EGLDisplay dpy, EGLint name)
212{
213 TRACE("(EGLDisplay dpy = %p, EGLint name = %d)", dpy, name);
214
215 if(dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
216 {
217 return success(
218 "EGL_KHR_client_get_all_proc_addresses "
219#if defined(__linux__) && !defined(__ANDROID__)
220 "EGL_KHR_platform_gbm "
221#endif
222#if defined(USE_X11)
223 "EGL_KHR_platform_x11 "
224#endif
225 "EGL_EXT_client_extensions "
226 "EGL_EXT_platform_base");
227 }
228
229 egl::Display *display = egl::Display::get(dpy);
230
231 RecursiveLockGuard lock(egl::getDisplayLock(display));
232
233 if(!validateDisplay(display))
234 {
235 return nullptr;
236 }
237
238 switch(name)
239 {
240 case EGL_CLIENT_APIS:
241 return success("OpenGL_ES");
242 case EGL_EXTENSIONS:
243 return success("EGL_KHR_create_context "
244 "EGL_KHR_get_all_proc_addresses "
245 "EGL_KHR_gl_texture_2D_image "
246 "EGL_KHR_gl_texture_cubemap_image "
247 "EGL_KHR_gl_renderbuffer_image "
248 "EGL_KHR_fence_sync "
249 "EGL_KHR_image_base "
250 "EGL_KHR_surfaceless_context "
251 "EGL_ANGLE_iosurface_client_buffer "
252 "EGL_ANDROID_framebuffer_target "
253 "EGL_ANDROID_recordable");
254 case EGL_VENDOR:
255 return success("Google Inc.");
256 case EGL_VERSION:
257 return success("1.4 SwiftShader " VERSION_STRING);
258 }
259
260 return error(EGL_BAD_PARAMETER, (const char*)nullptr);
261}
262
263EGLBoolean EGLAPIENTRY GetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
264{
265 TRACE("(EGLDisplay dpy = %p, EGLConfig *configs = %p, "
266 "EGLint config_size = %d, EGLint *num_config = %p)",
267 dpy, configs, config_size, num_config);
268
269 egl::Display *display = egl::Display::get(dpy);
270
271 RecursiveLockGuard lock(egl::getDisplayLock(display));
272
273 if(!validateDisplay(display))
274 {
275 return EGL_FALSE;
276 }
277
278 if(!num_config)
279 {
280 return error(EGL_BAD_PARAMETER, EGL_FALSE);
281 }
282
283 const EGLint attribList[] = {EGL_NONE};
284
285 if(!display->getConfigs(configs, attribList, config_size, num_config))
286 {
287 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
288 }
289
290 return success(EGL_TRUE);
291}
292
293EGLBoolean EGLAPIENTRY ChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
294{
295 TRACE("(EGLDisplay dpy = %p, const EGLint *attrib_list = %p, "
296 "EGLConfig *configs = %p, EGLint config_size = %d, EGLint *num_config = %p)",
297 dpy, attrib_list, configs, config_size, num_config);
298
299 egl::Display *display = egl::Display::get(dpy);
300
301 RecursiveLockGuard lock(egl::getDisplayLock(display));
302
303 if(!validateDisplay(display))
304 {
305 return EGL_FALSE;
306 }
307
308 if(!num_config)
309 {
310 return error(EGL_BAD_PARAMETER, EGL_FALSE);
311 }
312
313 const EGLint attribList[] = {EGL_NONE};
314
315 if(!attrib_list)
316 {
317 attrib_list = attribList;
318 }
319
320 if(!display->getConfigs(configs, attrib_list, config_size, num_config))
321 {
322 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
323 }
324
325 return success(EGL_TRUE);
326}
327
328EGLBoolean EGLAPIENTRY GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
329{
330 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLint attribute = %d, EGLint *value = %p)",
331 dpy, config, attribute, value);
332
333 egl::Display *display = egl::Display::get(dpy);
334
335 RecursiveLockGuard lock(egl::getDisplayLock(display));
336
337 if(!validateConfig(display, config))
338 {
339 return EGL_FALSE;
340 }
341
342 if(!display->getConfigAttrib(config, attribute, value))
343 {
344 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
345 }
346
347 return success(EGL_TRUE);
348}
349
350EGLSurface EGLAPIENTRY CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list)
351{
352 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_window = %p, "
353 "const EGLint *attrib_list = %p)", dpy, config, native_window, attrib_list);
354
355 egl::Display *display = egl::Display::get(dpy);
356
357 RecursiveLockGuard lock(egl::getDisplayLock(display));
358
359 if(!validateConfig(display, config))
360 {
361 return EGL_NO_SURFACE;
362 }
363
364 if(!display->isValidWindow((EGLNativeWindowType)native_window))
365 {
366 return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
367 }
368
369 return display->createWindowSurface((EGLNativeWindowType)native_window, config, attrib_list);
370}
371
372EGLSurface EGLAPIENTRY CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list)
373{
374 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_window = %p, "
375 "const EGLint *attrib_list = %p)", dpy, config, native_window, attrib_list);
376
377 EGLAttribs attribs(attrib_list);
378 return CreatePlatformWindowSurface(dpy, config, native_window, &attribs);
379}
380
381EGLSurface EGLAPIENTRY CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType window, const EGLint *attrib_list)
382{
383 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativeWindowType window = %p, "
384 "const EGLint *attrib_list = %p)", dpy, config, window, attrib_list);
385
386 EGLAttribs attribs(attrib_list);
387 return CreatePlatformWindowSurface(dpy, config, (void*)window, &attribs);
388}
389
390EGLSurface EGLAPIENTRY CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
391{
392 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, const EGLint *attrib_list = %p)",
393 dpy, config, attrib_list);
394
395 egl::Display *display = egl::Display::get(dpy);
396
397 RecursiveLockGuard lock(egl::getDisplayLock(display));
398
399 if(!validateConfig(display, config))
400 {
401 return EGL_NO_SURFACE;
402 }
403
404 return display->createPBufferSurface(config, attrib_list);
405}
406
407EGLSurface EGLAPIENTRY CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list)
408{
409 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_pixmap = %p, "
410 "const EGLint *attrib_list = %p)", dpy, config, native_pixmap, attrib_list);
411
412 egl::Display *display = egl::Display::get(dpy);
413
414 RecursiveLockGuard lock(egl::getDisplayLock(display));
415
416 if(!validateConfig(display, config))
417 {
418 return EGL_NO_SURFACE;
419 }
420
421 UNIMPLEMENTED(); // FIXME
422
423 return success(EGL_NO_SURFACE);
424}
425
426EGLSurface EGLAPIENTRY CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list)
427{
428 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_pixmap = %p, "
429 "const EGLint *attrib_list = %p)", dpy, config, native_pixmap, attrib_list);
430
431 EGLAttribs attribs(attrib_list);
432 return CreatePlatformPixmapSurface(dpy, config, native_pixmap, &attribs);
433}
434
435EGLSurface EGLAPIENTRY CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
436{
437 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativePixmapType pixmap = %p, "
438 "const EGLint *attrib_list = %p)", dpy, config, pixmap, attrib_list);
439
440 EGLAttribs attribs(attrib_list);
441 return CreatePlatformPixmapSurface(dpy, config, (void*)pixmap, &attribs);
442}
443
444EGLBoolean EGLAPIENTRY DestroySurface(EGLDisplay dpy, EGLSurface surface)
445{
446 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p)", dpy, surface);
447
448 egl::Display *display = egl::Display::get(dpy);
449 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
450
451 RecursiveLockGuard lock(egl::getDisplayLock(display));
452
453 if(!validateSurface(display, eglSurface))
454 {
455 return EGL_FALSE;
456 }
457
458 if(surface == EGL_NO_SURFACE)
459 {
460 return error(EGL_BAD_SURFACE, EGL_FALSE);
461 }
462
463 display->destroySurface((egl::Surface*)surface);
464
465 return success(EGL_TRUE);
466}
467
468EGLBoolean EGLAPIENTRY QuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
469{
470 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint attribute = %d, EGLint *value = %p)",
471 dpy, surface, attribute, value);
472
473 egl::Display *display = egl::Display::get(dpy);
474 egl::Surface *eglSurface = (egl::Surface*)surface;
475
476 RecursiveLockGuard lock(egl::getDisplayLock(display));
477
478 if(!validateSurface(display, eglSurface))
479 {
480 return EGL_FALSE;
481 }
482
483 if(surface == EGL_NO_SURFACE)
484 {
485 return error(EGL_BAD_SURFACE, EGL_FALSE);
486 }
487
488 switch(attribute)
489 {
490 case EGL_VG_ALPHA_FORMAT:
491 *value = EGL_VG_ALPHA_FORMAT_NONPRE; // Default
492 break;
493 case EGL_VG_COLORSPACE:
494 *value = EGL_VG_COLORSPACE_sRGB; // Default
495 break;
496 case EGL_CONFIG_ID:
497 *value = eglSurface->getConfigID();
498 break;
499 case EGL_HEIGHT:
500 *value = eglSurface->getHeight();
501 break;
502 case EGL_HORIZONTAL_RESOLUTION:
503 *value = EGL_UNKNOWN;
504 break;
505 case EGL_LARGEST_PBUFFER:
506 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
507 {
508 *value = eglSurface->getLargestPBuffer();
509 }
510 break;
511 case EGL_MIPMAP_TEXTURE:
512 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
513 {
514 *value = EGL_FALSE; // UNIMPLEMENTED
515 }
516 break;
517 case EGL_MIPMAP_LEVEL:
518 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
519 {
520 *value = eglSurface->getMipmapLevel();
521 }
522 break;
523 case EGL_MULTISAMPLE_RESOLVE:
524 *value = eglSurface->getMultisampleResolve();
525 break;
526 case EGL_PIXEL_ASPECT_RATIO:
527 *value = eglSurface->getPixelAspectRatio();
528 break;
529 case EGL_RENDER_BUFFER:
530 *value = eglSurface->getRenderBuffer();
531 break;
532 case EGL_SWAP_BEHAVIOR:
533 *value = eglSurface->getSwapBehavior();
534 break;
535 case EGL_TEXTURE_FORMAT:
536 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
537 {
538 *value = eglSurface->getTextureFormat();
539 }
540 break;
541 case EGL_TEXTURE_TARGET:
542 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
543 {
544 *value = eglSurface->getTextureTarget();
545 }
546 break;
547 case EGL_VERTICAL_RESOLUTION:
548 *value = EGL_UNKNOWN;
549 break;
550 case EGL_WIDTH:
551 *value = eglSurface->getWidth();
552 break;
553 default:
554 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
555 }
556
557 return success(EGL_TRUE);
558}
559
560EGLBoolean EGLAPIENTRY BindAPI(EGLenum api)
561{
562 TRACE("(EGLenum api = 0x%X)", api);
563
564 switch(api)
565 {
566 case EGL_OPENGL_API:
567 case EGL_OPENVG_API:
568 return error(EGL_BAD_PARAMETER, EGL_FALSE); // Not supported by this implementation
569 case EGL_OPENGL_ES_API:
570 break;
571 default:
572 return error(EGL_BAD_PARAMETER, EGL_FALSE);
573 }
574
575 egl::setCurrentAPI(api);
576
577 return success(EGL_TRUE);
578}
579
580EGLenum EGLAPIENTRY QueryAPI(void)
581{
582 TRACE("()");
583
584 EGLenum API = egl::getCurrentAPI();
585
586 return success(API);
587}
588
589EGLBoolean EGLAPIENTRY WaitClient(void)
590{
591 TRACE("()");
592
593 // eglWaitClient is ignored if there is no current EGL rendering context for the current rendering API.
594 egl::Context *context = egl::getCurrentContext();
595
596 if(context)
597 {
598 context->finish();
599 }
600
601 return success(EGL_TRUE);
602}
603
604EGLBoolean EGLAPIENTRY ReleaseThread(void)
605{
606 TRACE("()");
607
608 detachThread();
609
610 return EGL_TRUE; // success() is not called here because it would re-allocate thread-local storage.
611}
612
613EGLSurface EGLAPIENTRY CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
614{
615 TRACE("(EGLDisplay dpy = %p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = %p, "
616 "EGLConfig config = %p, const EGLint *attrib_list = %p)",
617 dpy, buftype, buffer, config, attrib_list);
618
619 switch(buftype)
620 {
621 case EGL_IOSURFACE_ANGLE:
622 {
623 egl::Display *display = egl::Display::get(dpy);
624
625 RecursiveLockGuard lock(egl::getDisplayLock(display));
626
627 if(!validateConfig(display, config))
628 {
629 return EGL_NO_SURFACE;
630 }
631
632 return display->createPBufferSurface(config, attrib_list, buffer);
633 }
634 case EGL_OPENVG_IMAGE:
635 UNIMPLEMENTED();
636 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
637 default:
638 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
639 };
640}
641
642EGLBoolean EGLAPIENTRY SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
643{
644 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint attribute = %d, EGLint value = %d)",
645 dpy, surface, attribute, value);
646
647 egl::Display *display = egl::Display::get(dpy);
648 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
649
650 RecursiveLockGuard lock(egl::getDisplayLock(display));
651
652 if(!validateSurface(display, eglSurface))
653 {
654 return EGL_FALSE;
655 }
656
657 switch(attribute)
658 {
659 case EGL_MIPMAP_LEVEL:
660 eglSurface->setMipmapLevel(value);
661 break;
662 case EGL_MULTISAMPLE_RESOLVE:
663 switch(value)
664 {
665 case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
666 break;
667 case EGL_MULTISAMPLE_RESOLVE_BOX:
668 if(!(eglSurface->getSurfaceType() & EGL_MULTISAMPLE_RESOLVE_BOX_BIT))
669 {
670 return error(EGL_BAD_MATCH, EGL_FALSE);
671 }
672 break;
673 default:
674 return error(EGL_BAD_PARAMETER, EGL_FALSE);
675 }
676 eglSurface->setMultisampleResolve(value);
677 break;
678 case EGL_SWAP_BEHAVIOR:
679 switch(value)
680 {
681 case EGL_BUFFER_DESTROYED:
682 break;
683 case EGL_BUFFER_PRESERVED:
684 if(!(eglSurface->getSurfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
685 {
686 return error(EGL_BAD_MATCH, EGL_FALSE);
687 }
688 break;
689 default:
690 return error(EGL_BAD_PARAMETER, EGL_FALSE);
691 }
692 eglSurface->setSwapBehavior(value);
693 break;
694 default:
695 return error(EGL_BAD_PARAMETER, EGL_FALSE);
696 }
697
698 return success(EGL_TRUE);
699}
700
701EGLBoolean EGLAPIENTRY BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
702{
703 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint buffer = %d)", dpy, surface, buffer);
704
705 egl::Display *display = egl::Display::get(dpy);
706 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
707
708 RecursiveLockGuard lock(egl::getDisplayLock(display));
709
710 if(!validateSurface(display, eglSurface))
711 {
712 return EGL_FALSE;
713 }
714
715 if(buffer != EGL_BACK_BUFFER)
716 {
717 return error(EGL_BAD_PARAMETER, EGL_FALSE);
718 }
719
720 if(surface == EGL_NO_SURFACE || eglSurface->isWindowSurface())
721 {
722 return error(EGL_BAD_SURFACE, EGL_FALSE);
723 }
724
725 if(eglSurface->getBoundTexture())
726 {
727 return error(EGL_BAD_ACCESS, EGL_FALSE);
728 }
729
730 if(eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
731 {
732 return error(EGL_BAD_MATCH, EGL_FALSE);
733 }
734
735 egl::Context *context = egl::getCurrentContext();
736
737 if(context)
738 {
739 context->bindTexImage(eglSurface);
740 }
741
742 return success(EGL_TRUE);
743}
744
745EGLBoolean EGLAPIENTRY ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
746{
747 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint buffer = %d)", dpy, surface, buffer);
748
749 egl::Display *display = egl::Display::get(dpy);
750 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
751
752 RecursiveLockGuard lock(egl::getDisplayLock(display));
753
754 if(!validateSurface(display, eglSurface))
755 {
756 return EGL_FALSE;
757 }
758
759 if(buffer != EGL_BACK_BUFFER)
760 {
761 return error(EGL_BAD_PARAMETER, EGL_FALSE);
762 }
763
764 if(surface == EGL_NO_SURFACE || eglSurface->isWindowSurface())
765 {
766 return error(EGL_BAD_SURFACE, EGL_FALSE);
767 }
768
769 if(eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
770 {
771 return error(EGL_BAD_MATCH, EGL_FALSE);
772 }
773
774 egl::Texture *texture = eglSurface->getBoundTexture();
775
776 if(texture)
777 {
778 texture->releaseTexImage();
779 }
780
781 return success(EGL_TRUE);
782}
783
784EGLBoolean EGLAPIENTRY SwapInterval(EGLDisplay dpy, EGLint interval)
785{
786 TRACE("(EGLDisplay dpy = %p, EGLint interval = %d)", dpy, interval);
787
788 egl::Display *display = egl::Display::get(dpy);
789 egl::Context *context = egl::getCurrentContext();
790
791 RecursiveLockGuard lock(egl::getDisplayLock(display));
792
793 if(!validateContext(display, context))
794 {
795 return EGL_FALSE;
796 }
797
798 egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface());
799
800 if(!draw_surface)
801 {
802 return error(EGL_BAD_SURFACE, EGL_FALSE);
803 }
804
805 draw_surface->setSwapInterval(interval);
806
807 return success(EGL_TRUE);
808}
809
810EGLContext EGLAPIENTRY CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
811{
812 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLContext share_context = %p, "
813 "const EGLint *attrib_list = %p)", dpy, config, share_context, attrib_list);
814
815 EGLint majorVersion = 1;
816 EGLint minorVersion = 0;
817
818 if(attrib_list)
819 {
820 for(const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2)
821 {
822 switch(attribute[0])
823 {
824 case EGL_CONTEXT_MAJOR_VERSION_KHR: // This token is an alias for EGL_CONTEXT_CLIENT_VERSION
825 majorVersion = attribute[1];
826 break;
827 case EGL_CONTEXT_MINOR_VERSION_KHR:
828 minorVersion = attribute[1];
829 break;
830 case EGL_CONTEXT_FLAGS_KHR:
831 switch(attribute[1])
832 {
833 case EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR:
834 // According to the EGL_KHR_create_context spec:
835 // "Khronos is still defining the expected and required features of debug contexts, so
836 // implementations are currently free to implement "debug contexts" with little or no debug
837 // functionality. However, OpenGL and OpenGL ES implementations supporting the GL_KHR_debug
838 // extension should enable it when this bit is set."
839 break;
840 case EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR:
841 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR:
842 // These bits are for OpenGL contexts only, not OpenGL ES contexts
843 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
844 default:
845 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
846 }
847 break;
848 case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
849 switch(attribute[1])
850 {
851 case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR:
852 case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR:
853 // These bits are for OpenGL contexts only, not OpenGL ES contexts
854 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
855 default:
856 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
857 }
858 break;
859 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
860 switch(attribute[1])
861 {
862 case EGL_NO_RESET_NOTIFICATION_KHR:
863 case EGL_LOSE_CONTEXT_ON_RESET_KHR:
864 // These bits are for OpenGL contexts only, not OpenGL ES contexts
865 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
866 default:
867 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
868 }
869 break;
870 default:
871 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
872 }
873 }
874 }
875
876 switch(majorVersion)
877 {
878 case 1:
879 if(minorVersion != 0 && minorVersion != 1)
880 {
881 // 1.X: Only OpenGL ES 1.0 and 1.1 contexts are supported
882 return error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
883 }
884 break;
885 case 2:
886 case 3:
887 if(minorVersion != 0)
888 {
889 // 2.X and 3.X: Only OpenGL ES 2.0 and 3.0 contexts are currently supported
890 return error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
891 }
892 break;
893 default:
894 return error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
895 }
896
897 egl::Display *display = egl::Display::get(dpy);
898 egl::Context *shareContext = static_cast<egl::Context*>(share_context);
899
900 RecursiveLockGuard lock(egl::getDisplayLock(display));
901
902 if(!validateConfig(display, config))
903 {
904 return EGL_NO_CONTEXT;
905 }
906
907 // Allow sharing between different context versions >= 2.0, but isolate 1.x
908 // contexts from 2.0+. Strict matching between context versions >= 2.0 is
909 // confusing for apps to navigate because of version promotion.
910 if(shareContext && ((shareContext->getClientVersion() >= 2) ^ (majorVersion >= 2)))
911 {
912 return error(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
913 }
914
915 return display->createContext(config, shareContext, majorVersion);
916}
917
918EGLBoolean EGLAPIENTRY DestroyContext(EGLDisplay dpy, EGLContext ctx)
919{
920 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p)", dpy, ctx);
921
922 egl::Display *display = egl::Display::get(dpy);
923 egl::Context *context = static_cast<egl::Context*>(ctx);
924
925 RecursiveLockGuard lock(egl::getDisplayLock(display));
926
927 if(!validateContext(display, context))
928 {
929 return EGL_FALSE;
930 }
931
932 if(ctx == EGL_NO_CONTEXT)
933 {
934 return error(EGL_BAD_CONTEXT, EGL_FALSE);
935 }
936
937 display->destroyContext(context);
938
939 return success(EGL_TRUE);
940}
941
942EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
943{
944 TRACE("(EGLDisplay dpy = %p, EGLSurface draw = %p, EGLSurface read = %p, EGLContext ctx = %p)",
945 dpy, draw, read, ctx);
946
947 egl::Display *display = egl::Display::get(dpy);
948 egl::Context *context = static_cast<egl::Context*>(ctx);
949 egl::Surface *drawSurface = static_cast<egl::Surface*>(draw);
950 egl::Surface *readSurface = static_cast<egl::Surface*>(read);
951
952 RecursiveLockGuard lock(egl::getDisplayLock(display));
953
954 if(ctx != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)
955 {
956 if(!validateDisplay(display))
957 {
958 return EGL_FALSE;
959 }
960 }
961
962 if(ctx == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
963 {
964 return error(EGL_BAD_MATCH, EGL_FALSE);
965 }
966
967 if(ctx != EGL_NO_CONTEXT && !validateContext(display, context))
968 {
969 return EGL_FALSE;
970 }
971
972 if((draw != EGL_NO_SURFACE && !validateSurface(display, drawSurface)) ||
973 (read != EGL_NO_SURFACE && !validateSurface(display, readSurface)))
974 {
975 return EGL_FALSE;
976 }
977
978 if((draw != EGL_NO_SURFACE) ^ (read != EGL_NO_SURFACE))
979 {
980 return error(EGL_BAD_MATCH, EGL_FALSE);
981 }
982
983 if(draw != read)
984 {
985 UNIMPLEMENTED(); // FIXME
986 }
987
988 egl::setCurrentDrawSurface(drawSurface);
989 egl::setCurrentReadSurface(readSurface);
990 egl::setCurrentContext(context);
991
992 if(context)
993 {
994 context->makeCurrent(drawSurface);
995 }
996
997 return success(EGL_TRUE);
998}
999
1000EGLContext EGLAPIENTRY GetCurrentContext(void)
1001{
1002 TRACE("()");
1003
1004 EGLContext context = egl::getCurrentContext();
1005
1006 return success(context);
1007}
1008
1009EGLSurface EGLAPIENTRY GetCurrentSurface(EGLint readdraw)
1010{
1011 TRACE("(EGLint readdraw = %d)", readdraw);
1012
1013 if(readdraw == EGL_READ)
1014 {
1015 EGLSurface read = egl::getCurrentReadSurface();
1016 return success(read);
1017 }
1018 else if(readdraw == EGL_DRAW)
1019 {
1020 EGLSurface draw = egl::getCurrentDrawSurface();
1021 return success(draw);
1022 }
1023 else
1024 {
1025 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1026 }
1027}
1028
1029EGLDisplay EGLAPIENTRY GetCurrentDisplay(void)
1030{
1031 TRACE("()");
1032
1033 egl::Context *context = egl::getCurrentContext();
1034
1035 if(!context)
1036 {
1037 return success(EGL_NO_DISPLAY);
1038 }
1039
1040 egl::Display *display = context->getDisplay();
1041
1042 if(!display)
1043 {
1044 return error(EGL_BAD_ACCESS, EGL_NO_DISPLAY);
1045 }
1046
1047 return success(display->getEGLDisplay());
1048}
1049
1050EGLBoolean EGLAPIENTRY QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
1051{
1052 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLint attribute = %d, EGLint *value = %p)",
1053 dpy, ctx, attribute, value);
1054
1055 egl::Display *display = egl::Display::get(dpy);
1056 egl::Context *context = static_cast<egl::Context*>(ctx);
1057
1058 RecursiveLockGuard lock(egl::getDisplayLock(display));
1059
1060 if(!validateContext(display, context))
1061 {
1062 return EGL_FALSE;
1063 }
1064
1065 switch(attribute)
1066 {
1067 case EGL_CONFIG_ID:
1068 *value = context->getConfigID();
1069 break;
1070 case EGL_CONTEXT_CLIENT_TYPE:
1071 *value = egl::getCurrentAPI();
1072 break;
1073 case EGL_CONTEXT_CLIENT_VERSION:
1074 *value = context->getClientVersion();
1075 break;
1076 case EGL_RENDER_BUFFER:
1077 *value = EGL_BACK_BUFFER;
1078 break;
1079 default:
1080 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1081 }
1082
1083 return success(EGL_TRUE);
1084}
1085
1086EGLBoolean EGLAPIENTRY WaitGL(void)
1087{
1088 TRACE("()");
1089
1090 // glWaitGL is ignored if there is no current EGL rendering context for OpenGL ES.
1091 egl::Context *context = egl::getCurrentContext();
1092
1093 if(context)
1094 {
1095 context->finish();
1096 }
1097
1098 return success(EGL_TRUE);
1099}
1100
1101EGLBoolean EGLAPIENTRY WaitNative(EGLint engine)
1102{
1103 TRACE("(EGLint engine = %d)", engine);
1104
1105 if(engine != EGL_CORE_NATIVE_ENGINE)
1106 {
1107 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1108 }
1109
1110 // eglWaitNative is ignored if there is no current EGL rendering context.
1111 egl::Context *context = egl::getCurrentContext();
1112
1113 if(context)
1114 {
1115 #if defined(USE_X11)
1116 egl::Display *display = context->getDisplay();
1117
1118 if(!display)
1119 {
1120 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1121 }
1122
1123 libX11->XSync((::Display*)display->getNativeDisplay(), False);
1124 #else
1125 UNIMPLEMENTED();
1126 #endif
1127 }
1128
1129 return success(EGL_TRUE);
1130}
1131
1132EGLBoolean EGLAPIENTRY SwapBuffers(EGLDisplay dpy, EGLSurface surface)
1133{
1134 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p)", dpy, surface);
1135
1136 egl::Display *display = egl::Display::get(dpy);
1137 egl::Surface *eglSurface = (egl::Surface*)surface;
1138
1139 {
1140 RecursiveLockGuard lock(egl::getDisplayLock(display));
1141
1142 if(!validateSurface(display, eglSurface))
1143 {
1144 return EGL_FALSE;
1145 }
1146 }
1147
1148 if(surface == EGL_NO_SURFACE)
1149 {
1150 return error(EGL_BAD_SURFACE, EGL_FALSE);
1151 }
1152
1153 eglSurface->swap();
1154
1155 return success(EGL_TRUE);
1156}
1157
1158EGLBoolean EGLAPIENTRY CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
1159{
1160 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLNativePixmapType target = %p)", dpy, surface, target);
1161
1162 egl::Display *display = egl::Display::get(dpy);
1163 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
1164
1165 RecursiveLockGuard lock(egl::getDisplayLock(display));
1166
1167 if(!validateSurface(display, eglSurface))
1168 {
1169 return EGL_FALSE;
1170 }
1171
1172 UNIMPLEMENTED(); // FIXME
1173
1174 return success(EGL_FALSE);
1175}
1176
1177EGLImage EGLAPIENTRY CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list)
1178{
1179 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLenum target = 0x%X, buffer = %p, const EGLAttrib *attrib_list = %p)", dpy, ctx, target, buffer, attrib_list);
1180
1181 egl::Display *display = egl::Display::get(dpy);
1182 egl::Context *context = static_cast<egl::Context*>(ctx);
1183
1184 RecursiveLockGuard lock(egl::getDisplayLock(display));
1185
1186 if(!validateDisplay(display))
1187 {
1188 return error(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1189 }
1190
1191 if(context != EGL_NO_CONTEXT && !display->isValidContext(context))
1192 {
1193 return error(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1194 }
1195
1196 EGLenum imagePreserved = EGL_FALSE;
1197 (void)imagePreserved; // currently unused
1198
1199 GLuint textureLevel = 0;
1200 if(attrib_list)
1201 {
1202 for(const EGLAttrib *attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2)
1203 {
1204 if(attribute[0] == EGL_IMAGE_PRESERVED_KHR)
1205 {
1206 imagePreserved = static_cast<EGLenum>(attribute[1]);
1207 }
1208 else if(attribute[0] == EGL_GL_TEXTURE_LEVEL_KHR)
1209 {
1210 textureLevel = static_cast<GLuint>(attribute[1]);
1211 }
1212 else
1213 {
1214 return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR);
1215 }
1216 }
1217 }
1218
1219 #if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD)
1220 if(target == EGL_NATIVE_BUFFER_ANDROID)
1221 {
1222 ANativeWindowBuffer *nativeBuffer = reinterpret_cast<ANativeWindowBuffer*>(buffer);
1223
1224 if(!nativeBuffer || GLPixelFormatFromAndroid(nativeBuffer->format) == GL_NONE)
1225 {
1226 ERR("%s badness unsupported HAL format=%x", __FUNCTION__, nativeBuffer ? nativeBuffer->format : 0);
1227 return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR);
1228 }
1229
1230 Image *image = new AndroidNativeImage(nativeBuffer);
1231 EGLImageKHR eglImage = display->createSharedImage(image);
1232
1233 return success(eglImage);
1234 }
1235 #endif
1236
1237 GLuint name = static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer));
1238
1239 if(name == 0)
1240 {
1241 return error(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1242 }
1243
1244 EGLenum validationResult = context->validateSharedImage(target, name, textureLevel);
1245
1246 if(validationResult != EGL_SUCCESS)
1247 {
1248 return error(validationResult, EGL_NO_IMAGE_KHR);
1249 }
1250
1251 Image *image = context->createSharedImage(target, name, textureLevel);
1252
1253 if(!image)
1254 {
1255 return error(EGL_BAD_MATCH, EGL_NO_IMAGE_KHR);
1256 }
1257
1258 if(image->getDepth() > 1)
1259 {
1260 return error(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1261 }
1262
1263 EGLImage eglImage = display->createSharedImage(image);
1264
1265 return success(eglImage);
1266}
1267
1268EGLImageKHR EGLAPIENTRY CreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
1269{
1270 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLenum target = 0x%X, buffer = %p, const EGLint attrib_list = %p)", dpy, ctx, target, buffer, attrib_list);
1271
1272 EGLAttribs attribs(attrib_list);
1273 return CreateImage(dpy, ctx, target, buffer, &attribs);
1274}
1275
1276EGLBoolean EGLAPIENTRY DestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
1277{
1278 TRACE("(EGLDisplay dpy = %p, EGLImageKHR image = %p)", dpy, image);
1279
1280 egl::Display *display = egl::Display::get(dpy);
1281
1282 RecursiveLockGuard lock(egl::getDisplayLock(display));
1283
1284 if(!validateDisplay(display))
1285 {
1286 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1287 }
1288
1289 if(!display->destroySharedImage(image))
1290 {
1291 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1292 }
1293
1294 return success(EGL_TRUE);
1295}
1296
1297EGLDisplay EGLAPIENTRY GetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list)
1298{
1299 TRACE("(EGLenum platform = 0x%X, void *native_display = %p, const EGLAttrib *attrib_list = %p)", platform, native_display, attrib_list);
1300
1301 #if defined(__linux__) && !defined(__ANDROID__)
1302 switch(platform)
1303 {
1304 #if defined(USE_X11)
1305 case EGL_PLATFORM_X11_EXT: break;
1306 #endif
1307 case EGL_PLATFORM_GBM_KHR: break;
1308 default:
1309 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
1310 }
1311
1312 if(platform == EGL_PLATFORM_GBM_KHR)
1313 {
1314 if(native_display != (void*)EGL_DEFAULT_DISPLAY)
1315 {
1316 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); // Unimplemented
1317 }
1318
1319 if(attrib_list && attrib_list[0] != EGL_NONE)
1320 {
1321 return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented
1322 }
1323
1324 return success(HEADLESS_DISPLAY);
1325 }
1326 #if defined(USE_X11)
1327 else if(platform == EGL_PLATFORM_X11_EXT)
1328 {
1329 if(!libX11)
1330 {
1331 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
1332 }
1333
1334 if(native_display != (void*)EGL_DEFAULT_DISPLAY)
1335 {
1336 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); // Unimplemented
1337 }
1338
1339 if(attrib_list && attrib_list[0] != EGL_NONE)
1340 {
1341 return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented
1342 }
1343 }
1344 #endif
1345
1346 return success(PRIMARY_DISPLAY); // We only support the default display
1347 #else
1348 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
1349 #endif
1350}
1351
1352EGLDisplay EGLAPIENTRY GetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list)
1353{
1354 TRACE("(EGLenum platform = 0x%X, void *native_display = %p, const EGLint *attrib_list = %p)", platform, native_display, attrib_list);
1355
1356 EGLAttribs attribs(attrib_list);
1357 return GetPlatformDisplay(platform, native_display, &attribs);
1358}
1359
1360EGLSync EGLAPIENTRY CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list)
1361{
1362 TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLAttrib *attrib_list=%p)", dpy, type, attrib_list);
1363
1364 egl::Display *display = egl::Display::get(dpy);
1365
1366 RecursiveLockGuard lock(egl::getDisplayLock(display));
1367
1368 if(!validateDisplay(display))
1369 {
1370 return error(EGL_BAD_DISPLAY, EGL_NO_SYNC_KHR);
1371 }
1372
1373 if(type != EGL_SYNC_FENCE_KHR)
1374 {
1375 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
1376 }
1377
1378 if(attrib_list && attrib_list[0] != EGL_NONE)
1379 {
1380 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
1381 }
1382
1383 egl::Context *context = egl::getCurrentContext();
1384
1385 if(!validateContext(display, context))
1386 {
1387 return error(EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
1388 }
1389
1390 EGLSyncKHR sync = display->createSync(context);
1391
1392 return success(sync);
1393}
1394
1395EGLSyncKHR EGLAPIENTRY CreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1396{
1397 TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLint *attrib_list=%p)", dpy, type, attrib_list);
1398
1399 EGLAttribs attribs(attrib_list);
1400 return CreateSync(dpy, type, &attribs);
1401}
1402
1403EGLBoolean EGLAPIENTRY DestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1404{
1405 TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p)", dpy, sync);
1406
1407 egl::Display *display = egl::Display::get(dpy);
1408 FenceSync *eglSync = static_cast<FenceSync*>(sync);
1409
1410 RecursiveLockGuard lock(egl::getDisplayLock(display));
1411
1412 if(!validateDisplay(display))
1413 {
1414 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1415 }
1416
1417 if(!display->isValidSync(eglSync))
1418 {
1419 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1420 }
1421
1422 display->destroySync(eglSync);
1423
1424 return success(EGL_TRUE);
1425}
1426
1427EGLint EGLAPIENTRY ClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
1428{
1429 TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint flags = %x, EGLTimeKHR value = %llx)", dpy, sync, flags, timeout);
1430
1431 egl::Display *display = egl::Display::get(dpy);
1432 FenceSync *eglSync = static_cast<FenceSync*>(sync);
1433
1434 RecursiveLockGuard lock(egl::getDisplayLock(display));
1435
1436 if(!validateDisplay(display))
1437 {
1438 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1439 }
1440
1441 if(!display->isValidSync(eglSync))
1442 {
1443 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1444 }
1445
1446 (void)flags;
1447 (void)timeout;
1448
1449 if(!eglSync->isSignaled())
1450 {
1451 eglSync->wait();
1452 }
1453
1454 return success(EGL_CONDITION_SATISFIED_KHR);
1455}
1456
1457EGLBoolean EGLAPIENTRY GetSyncAttrib(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLAttrib *value)
1458{
1459 TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint attribute = %x, EGLAttrib *value = %p)", dpy, sync, attribute, value);
1460
1461 egl::Display *display = egl::Display::get(dpy);
1462 FenceSync *eglSync = static_cast<FenceSync*>(sync);
1463
1464 RecursiveLockGuard lock(egl::getDisplayLock(display));
1465
1466 if(!validateDisplay(display))
1467 {
1468 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1469 }
1470
1471 if(!display->isValidSync(eglSync))
1472 {
1473 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1474 }
1475
1476 if(!value)
1477 {
1478 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1479 }
1480
1481 switch(attribute)
1482 {
1483 case EGL_SYNC_TYPE_KHR:
1484 *value = EGL_SYNC_FENCE_KHR;
1485 return success(EGL_TRUE);
1486 case EGL_SYNC_STATUS_KHR:
1487 eglSync->wait(); // TODO: Don't block. Just poll based on sw::Query.
1488 *value = eglSync->isSignaled() ? EGL_SIGNALED_KHR : EGL_UNSIGNALED_KHR;
1489 return success(EGL_TRUE);
1490 case EGL_SYNC_CONDITION_KHR:
1491 *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
1492 return success(EGL_TRUE);
1493 default:
1494 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1495 }
1496}
1497
1498EGLBoolean EGLAPIENTRY GetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
1499{
1500 EGLAttrib attrib_value;
1501 EGLBoolean result = GetSyncAttrib(dpy, sync, attribute, &attrib_value);
1502 *value = static_cast<EGLint>(attrib_value);
1503 return result;
1504}
1505
1506__eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *procname)
1507{
1508 TRACE("(const char *procname = \"%s\")", procname);
1509
1510 struct Function
1511 {
1512 const char *name;
1513 __eglMustCastToProperFunctionPointerType address;
1514 };
1515
1516 struct CompareFunctor
1517 {
1518 bool operator()(const Function &a, const Function &b) const
1519 {
1520 return strcmp(a.name, b.name) < 0;
1521 }
1522 };
1523
1524 // This array must be kept sorted with respect to strcmp(), so that binary search works correctly.
1525 // The Unix command "LC_COLLATE=C sort" will generate the correct order.
1526 static const Function eglFunctions[] =
1527 {
1528 #define FUNCTION(name) {#name, (__eglMustCastToProperFunctionPointerType)name}
1529
1530 FUNCTION(eglBindAPI),
1531 FUNCTION(eglBindTexImage),
1532 FUNCTION(eglChooseConfig),
1533 FUNCTION(eglClientWaitSync),
1534 FUNCTION(eglClientWaitSyncKHR),
1535 FUNCTION(eglCopyBuffers),
1536 FUNCTION(eglCreateContext),
1537 FUNCTION(eglCreateImage),
1538 FUNCTION(eglCreateImageKHR),
1539 FUNCTION(eglCreatePbufferFromClientBuffer),
1540 FUNCTION(eglCreatePbufferSurface),
1541 FUNCTION(eglCreatePixmapSurface),
1542 FUNCTION(eglCreatePlatformPixmapSurface),
1543 FUNCTION(eglCreatePlatformPixmapSurfaceEXT),
1544 FUNCTION(eglCreatePlatformWindowSurface),
1545 FUNCTION(eglCreatePlatformWindowSurfaceEXT),
1546 FUNCTION(eglCreateSync),
1547 FUNCTION(eglCreateSyncKHR),
1548 FUNCTION(eglCreateWindowSurface),
1549 FUNCTION(eglDestroyContext),
1550 FUNCTION(eglDestroyImage),
1551 FUNCTION(eglDestroyImageKHR),
1552 FUNCTION(eglDestroySurface),
1553 FUNCTION(eglDestroySync),
1554 FUNCTION(eglDestroySyncKHR),
1555 FUNCTION(eglGetConfigAttrib),
1556 FUNCTION(eglGetConfigs),
1557 FUNCTION(eglGetCurrentContext),
1558 FUNCTION(eglGetCurrentDisplay),
1559 FUNCTION(eglGetCurrentSurface),
1560 FUNCTION(eglGetDisplay),
1561 FUNCTION(eglGetError),
1562 FUNCTION(eglGetPlatformDisplay),
1563 FUNCTION(eglGetPlatformDisplayEXT),
1564 FUNCTION(eglGetProcAddress),
1565 FUNCTION(eglGetSyncAttrib),
1566 FUNCTION(eglGetSyncAttribKHR),
1567 FUNCTION(eglInitialize),
1568 FUNCTION(eglMakeCurrent),
1569 FUNCTION(eglQueryAPI),
1570 FUNCTION(eglQueryContext),
1571 FUNCTION(eglQueryString),
1572 FUNCTION(eglQuerySurface),
1573 FUNCTION(eglReleaseTexImage),
1574 FUNCTION(eglReleaseThread),
1575 FUNCTION(eglSurfaceAttrib),
1576 FUNCTION(eglSwapBuffers),
1577 FUNCTION(eglSwapInterval),
1578 FUNCTION(eglTerminate),
1579 FUNCTION(eglWaitClient),
1580 FUNCTION(eglWaitGL),
1581 FUNCTION(eglWaitNative),
1582 FUNCTION(eglWaitSync),
1583 FUNCTION(eglWaitSyncKHR),
1584
1585 #undef FUNCTION
1586 };
1587
1588 static const size_t numFunctions = sizeof eglFunctions / sizeof(Function);
1589 static const Function *const eglFunctionsEnd = eglFunctions + numFunctions;
1590
1591 Function needle;
1592 needle.name = procname;
1593
1594 if(procname && strncmp("egl", procname, 3) == 0)
1595 {
1596 const Function *result = std::lower_bound(eglFunctions, eglFunctionsEnd, needle, CompareFunctor());
1597 if (result != eglFunctionsEnd && strcmp(procname, result->name) == 0)
1598 {
1599 return success((__eglMustCastToProperFunctionPointerType)result->address);
1600 }
1601 }
1602
1603 if(libGLESv2)
1604 {
1605 __eglMustCastToProperFunctionPointerType proc = libGLESv2->es2GetProcAddress(procname);
1606 if(proc) return success(proc);
1607 }
1608
1609 if(libGLES_CM)
1610 {
1611 __eglMustCastToProperFunctionPointerType proc = libGLES_CM->es1GetProcAddress(procname);
1612 if(proc) return success(proc);
1613 }
1614
1615 return success((__eglMustCastToProperFunctionPointerType)NULL);
1616}
1617}
1618