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 <vndk/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
36 namespace egl
37 {
38 namespace
39 {
getDisplayLock(egl::Display * display)40 sw::RecursiveLock *getDisplayLock(egl::Display *display) {
41 if (!display) return nullptr;
42 return display->getLock();
43 }
44
validateDisplay(egl::Display * display)45 bool 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
validateConfig(egl::Display * display,EGLConfig config)60 bool 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
validateContext(egl::Display * display,egl::Context * context)75 bool 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
validateSurface(egl::Display * display,egl::Surface * surface)90 bool 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.
106 class EGLAttribs
107 {
108 public:
EGLAttribs(const EGLint * attrib_list)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
operator &() const123 const EGLAttrib *operator&() const
124 {
125 return &attrib[0];
126 }
127
128 private:
129 std::vector<EGLAttrib> attrib;
130 };
131 }
132
GetError(void)133 EGLint 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
GetDisplay(EGLNativeDisplayType display_id)147 EGLDisplay 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(__FreeBSD) || defined(__DragonFly__)) && !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
Initialize(EGLDisplay dpy,EGLint * major,EGLint * minor)168 EGLBoolean 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
Terminate(EGLDisplay dpy)193 EGLBoolean 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
QueryString(EGLDisplay dpy,EGLint name)211 const 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(__FreeBSD__) || defined(__DragonFly__)) && !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
GetConfigs(EGLDisplay dpy,EGLConfig * configs,EGLint config_size,EGLint * num_config)263 EGLBoolean 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
ChooseConfig(EGLDisplay dpy,const EGLint * attrib_list,EGLConfig * configs,EGLint config_size,EGLint * num_config)293 EGLBoolean 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
GetConfigAttrib(EGLDisplay dpy,EGLConfig config,EGLint attribute,EGLint * value)328 EGLBoolean 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
CreatePlatformWindowSurface(EGLDisplay dpy,EGLConfig config,void * native_window,const EGLAttrib * attrib_list)350 EGLSurface 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 defined(USE_X11)
365 native_window = (void *)(*(::Window*)native_window);
366 #endif
367
368 if(!display->isValidWindow((EGLNativeWindowType)native_window))
369 {
370 return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
371 }
372
373 return display->createWindowSurface((EGLNativeWindowType)native_window, config, attrib_list);
374 }
375
CreatePlatformWindowSurfaceEXT(EGLDisplay dpy,EGLConfig config,void * native_window,const EGLint * attrib_list)376 EGLSurface EGLAPIENTRY CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list)
377 {
378 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_window = %p, "
379 "const EGLint *attrib_list = %p)", dpy, config, native_window, attrib_list);
380
381 EGLAttribs attribs(attrib_list);
382 return CreatePlatformWindowSurface(dpy, config, native_window, &attribs);
383 }
384
CreateWindowSurface(EGLDisplay dpy,EGLConfig config,EGLNativeWindowType window,const EGLint * attrib_list)385 EGLSurface EGLAPIENTRY CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType window, const EGLint *attrib_list)
386 {
387 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativeWindowType window = %p, "
388 "const EGLint *attrib_list = %p)", dpy, config, window, attrib_list);
389
390 EGLAttribs attribs(attrib_list);
391
392 #if defined(USE_X11)
393 return CreatePlatformWindowSurface(dpy, config, (void*)&window, &attribs);
394 #else
395 return CreatePlatformWindowSurface(dpy, config, (void*)window, &attribs);
396 #endif
397 }
398
CreatePbufferSurface(EGLDisplay dpy,EGLConfig config,const EGLint * attrib_list)399 EGLSurface EGLAPIENTRY CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
400 {
401 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, const EGLint *attrib_list = %p)",
402 dpy, config, attrib_list);
403
404 egl::Display *display = egl::Display::get(dpy);
405
406 RecursiveLockGuard lock(egl::getDisplayLock(display));
407
408 if(!validateConfig(display, config))
409 {
410 return EGL_NO_SURFACE;
411 }
412
413 return display->createPBufferSurface(config, attrib_list);
414 }
415
CreatePlatformPixmapSurface(EGLDisplay dpy,EGLConfig config,void * native_pixmap,const EGLAttrib * attrib_list)416 EGLSurface EGLAPIENTRY CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list)
417 {
418 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_pixmap = %p, "
419 "const EGLint *attrib_list = %p)", dpy, config, native_pixmap, attrib_list);
420
421 egl::Display *display = egl::Display::get(dpy);
422
423 RecursiveLockGuard lock(egl::getDisplayLock(display));
424
425 if(!validateConfig(display, config))
426 {
427 return EGL_NO_SURFACE;
428 }
429
430 UNIMPLEMENTED(); // FIXME
431
432 return success(EGL_NO_SURFACE);
433 }
434
CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy,EGLConfig config,void * native_pixmap,const EGLint * attrib_list)435 EGLSurface EGLAPIENTRY CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list)
436 {
437 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_pixmap = %p, "
438 "const EGLint *attrib_list = %p)", dpy, config, native_pixmap, attrib_list);
439
440 EGLAttribs attribs(attrib_list);
441 return CreatePlatformPixmapSurface(dpy, config, native_pixmap, &attribs);
442 }
443
CreatePixmapSurface(EGLDisplay dpy,EGLConfig config,EGLNativePixmapType pixmap,const EGLint * attrib_list)444 EGLSurface EGLAPIENTRY CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
445 {
446 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativePixmapType pixmap = %p, "
447 "const EGLint *attrib_list = %p)", dpy, config, pixmap, attrib_list);
448
449 EGLAttribs attribs(attrib_list);
450 return CreatePlatformPixmapSurface(dpy, config, (void*)pixmap, &attribs);
451 }
452
DestroySurface(EGLDisplay dpy,EGLSurface surface)453 EGLBoolean EGLAPIENTRY DestroySurface(EGLDisplay dpy, EGLSurface surface)
454 {
455 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p)", dpy, surface);
456
457 egl::Display *display = egl::Display::get(dpy);
458 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
459
460 RecursiveLockGuard lock(egl::getDisplayLock(display));
461
462 if(!validateSurface(display, eglSurface))
463 {
464 return EGL_FALSE;
465 }
466
467 if(surface == EGL_NO_SURFACE)
468 {
469 return error(EGL_BAD_SURFACE, EGL_FALSE);
470 }
471
472 display->destroySurface((egl::Surface*)surface);
473
474 return success(EGL_TRUE);
475 }
476
QuerySurface(EGLDisplay dpy,EGLSurface surface,EGLint attribute,EGLint * value)477 EGLBoolean EGLAPIENTRY QuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
478 {
479 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint attribute = %d, EGLint *value = %p)",
480 dpy, surface, attribute, value);
481
482 egl::Display *display = egl::Display::get(dpy);
483 egl::Surface *eglSurface = (egl::Surface*)surface;
484
485 RecursiveLockGuard lock(egl::getDisplayLock(display));
486
487 if(!validateSurface(display, eglSurface))
488 {
489 return EGL_FALSE;
490 }
491
492 if(surface == EGL_NO_SURFACE)
493 {
494 return error(EGL_BAD_SURFACE, EGL_FALSE);
495 }
496
497 switch(attribute)
498 {
499 case EGL_VG_ALPHA_FORMAT:
500 *value = EGL_VG_ALPHA_FORMAT_NONPRE; // Default
501 break;
502 case EGL_VG_COLORSPACE:
503 *value = EGL_VG_COLORSPACE_sRGB; // Default
504 break;
505 case EGL_CONFIG_ID:
506 *value = eglSurface->getConfigID();
507 break;
508 case EGL_HEIGHT:
509 *value = eglSurface->getHeight();
510 break;
511 case EGL_HORIZONTAL_RESOLUTION:
512 *value = EGL_UNKNOWN;
513 break;
514 case EGL_LARGEST_PBUFFER:
515 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
516 {
517 *value = eglSurface->getLargestPBuffer();
518 }
519 break;
520 case EGL_MIPMAP_TEXTURE:
521 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
522 {
523 *value = EGL_FALSE; // UNIMPLEMENTED
524 }
525 break;
526 case EGL_MIPMAP_LEVEL:
527 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
528 {
529 *value = eglSurface->getMipmapLevel();
530 }
531 break;
532 case EGL_MULTISAMPLE_RESOLVE:
533 *value = eglSurface->getMultisampleResolve();
534 break;
535 case EGL_PIXEL_ASPECT_RATIO:
536 *value = eglSurface->getPixelAspectRatio();
537 break;
538 case EGL_RENDER_BUFFER:
539 *value = eglSurface->getRenderBuffer();
540 break;
541 case EGL_SWAP_BEHAVIOR:
542 *value = eglSurface->getSwapBehavior();
543 break;
544 case EGL_TEXTURE_FORMAT:
545 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
546 {
547 *value = eglSurface->getTextureFormat();
548 }
549 break;
550 case EGL_TEXTURE_TARGET:
551 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
552 {
553 *value = eglSurface->getTextureTarget();
554 }
555 break;
556 case EGL_VERTICAL_RESOLUTION:
557 *value = EGL_UNKNOWN;
558 break;
559 case EGL_WIDTH:
560 *value = eglSurface->getWidth();
561 break;
562 default:
563 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
564 }
565
566 return success(EGL_TRUE);
567 }
568
BindAPI(EGLenum api)569 EGLBoolean EGLAPIENTRY BindAPI(EGLenum api)
570 {
571 TRACE("(EGLenum api = 0x%X)", api);
572
573 switch(api)
574 {
575 case EGL_OPENGL_API:
576 case EGL_OPENVG_API:
577 return error(EGL_BAD_PARAMETER, EGL_FALSE); // Not supported by this implementation
578 case EGL_OPENGL_ES_API:
579 break;
580 default:
581 return error(EGL_BAD_PARAMETER, EGL_FALSE);
582 }
583
584 egl::setCurrentAPI(api);
585
586 return success(EGL_TRUE);
587 }
588
QueryAPI(void)589 EGLenum EGLAPIENTRY QueryAPI(void)
590 {
591 TRACE("()");
592
593 EGLenum API = egl::getCurrentAPI();
594
595 return success(API);
596 }
597
WaitClient(void)598 EGLBoolean EGLAPIENTRY WaitClient(void)
599 {
600 TRACE("()");
601
602 // eglWaitClient is ignored if there is no current EGL rendering context for the current rendering API.
603 egl::Context *context = egl::getCurrentContext();
604
605 if(context)
606 {
607 context->finish();
608 }
609
610 return success(EGL_TRUE);
611 }
612
ReleaseThread(void)613 EGLBoolean EGLAPIENTRY ReleaseThread(void)
614 {
615 TRACE("()");
616
617 detachThread();
618
619 return EGL_TRUE; // success() is not called here because it would re-allocate thread-local storage.
620 }
621
CreatePbufferFromClientBuffer(EGLDisplay dpy,EGLenum buftype,EGLClientBuffer buffer,EGLConfig config,const EGLint * attrib_list)622 EGLSurface EGLAPIENTRY CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
623 {
624 TRACE("(EGLDisplay dpy = %p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = %p, "
625 "EGLConfig config = %p, const EGLint *attrib_list = %p)",
626 dpy, buftype, buffer, config, attrib_list);
627
628 switch(buftype)
629 {
630 case EGL_IOSURFACE_ANGLE:
631 {
632 egl::Display *display = egl::Display::get(dpy);
633
634 RecursiveLockGuard lock(egl::getDisplayLock(display));
635
636 if(!validateConfig(display, config))
637 {
638 return EGL_NO_SURFACE;
639 }
640
641 return display->createPBufferSurface(config, attrib_list, buffer);
642 }
643 case EGL_OPENVG_IMAGE:
644 UNIMPLEMENTED();
645 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
646 default:
647 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
648 };
649 }
650
SurfaceAttrib(EGLDisplay dpy,EGLSurface surface,EGLint attribute,EGLint value)651 EGLBoolean EGLAPIENTRY SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
652 {
653 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint attribute = %d, EGLint value = %d)",
654 dpy, surface, attribute, value);
655
656 egl::Display *display = egl::Display::get(dpy);
657 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
658
659 RecursiveLockGuard lock(egl::getDisplayLock(display));
660
661 if(!validateSurface(display, eglSurface))
662 {
663 return EGL_FALSE;
664 }
665
666 switch(attribute)
667 {
668 case EGL_MIPMAP_LEVEL:
669 eglSurface->setMipmapLevel(value);
670 break;
671 case EGL_MULTISAMPLE_RESOLVE:
672 switch(value)
673 {
674 case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
675 break;
676 case EGL_MULTISAMPLE_RESOLVE_BOX:
677 if(!(eglSurface->getSurfaceType() & EGL_MULTISAMPLE_RESOLVE_BOX_BIT))
678 {
679 return error(EGL_BAD_MATCH, EGL_FALSE);
680 }
681 break;
682 default:
683 return error(EGL_BAD_PARAMETER, EGL_FALSE);
684 }
685 eglSurface->setMultisampleResolve(value);
686 break;
687 case EGL_SWAP_BEHAVIOR:
688 switch(value)
689 {
690 case EGL_BUFFER_DESTROYED:
691 break;
692 case EGL_BUFFER_PRESERVED:
693 if(!(eglSurface->getSurfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
694 {
695 return error(EGL_BAD_MATCH, EGL_FALSE);
696 }
697 break;
698 default:
699 return error(EGL_BAD_PARAMETER, EGL_FALSE);
700 }
701 eglSurface->setSwapBehavior(value);
702 break;
703 default:
704 return error(EGL_BAD_PARAMETER, EGL_FALSE);
705 }
706
707 return success(EGL_TRUE);
708 }
709
BindTexImage(EGLDisplay dpy,EGLSurface surface,EGLint buffer)710 EGLBoolean EGLAPIENTRY BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
711 {
712 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint buffer = %d)", dpy, surface, buffer);
713
714 egl::Display *display = egl::Display::get(dpy);
715 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
716
717 RecursiveLockGuard lock(egl::getDisplayLock(display));
718
719 if(!validateSurface(display, eglSurface))
720 {
721 return EGL_FALSE;
722 }
723
724 if(buffer != EGL_BACK_BUFFER)
725 {
726 return error(EGL_BAD_PARAMETER, EGL_FALSE);
727 }
728
729 if(surface == EGL_NO_SURFACE || eglSurface->isWindowSurface())
730 {
731 return error(EGL_BAD_SURFACE, EGL_FALSE);
732 }
733
734 if(eglSurface->getBoundTexture())
735 {
736 return error(EGL_BAD_ACCESS, EGL_FALSE);
737 }
738
739 if(eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
740 {
741 return error(EGL_BAD_MATCH, EGL_FALSE);
742 }
743
744 egl::Context *context = egl::getCurrentContext();
745
746 if(context)
747 {
748 context->bindTexImage(eglSurface);
749 }
750
751 return success(EGL_TRUE);
752 }
753
ReleaseTexImage(EGLDisplay dpy,EGLSurface surface,EGLint buffer)754 EGLBoolean EGLAPIENTRY ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
755 {
756 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint buffer = %d)", dpy, surface, buffer);
757
758 egl::Display *display = egl::Display::get(dpy);
759 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
760
761 RecursiveLockGuard lock(egl::getDisplayLock(display));
762
763 if(!validateSurface(display, eglSurface))
764 {
765 return EGL_FALSE;
766 }
767
768 if(buffer != EGL_BACK_BUFFER)
769 {
770 return error(EGL_BAD_PARAMETER, EGL_FALSE);
771 }
772
773 if(surface == EGL_NO_SURFACE || eglSurface->isWindowSurface())
774 {
775 return error(EGL_BAD_SURFACE, EGL_FALSE);
776 }
777
778 if(eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
779 {
780 return error(EGL_BAD_MATCH, EGL_FALSE);
781 }
782
783 egl::Texture *texture = eglSurface->getBoundTexture();
784
785 if(texture)
786 {
787 texture->releaseTexImage();
788 }
789
790 return success(EGL_TRUE);
791 }
792
SwapInterval(EGLDisplay dpy,EGLint interval)793 EGLBoolean EGLAPIENTRY SwapInterval(EGLDisplay dpy, EGLint interval)
794 {
795 TRACE("(EGLDisplay dpy = %p, EGLint interval = %d)", dpy, interval);
796
797 egl::Display *display = egl::Display::get(dpy);
798 egl::Context *context = egl::getCurrentContext();
799
800 RecursiveLockGuard lock(egl::getDisplayLock(display));
801
802 if(!validateContext(display, context))
803 {
804 return EGL_FALSE;
805 }
806
807 egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface());
808
809 if(!draw_surface)
810 {
811 return error(EGL_BAD_SURFACE, EGL_FALSE);
812 }
813
814 draw_surface->setSwapInterval(interval);
815
816 return success(EGL_TRUE);
817 }
818
CreateContext(EGLDisplay dpy,EGLConfig config,EGLContext share_context,const EGLint * attrib_list)819 EGLContext EGLAPIENTRY CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
820 {
821 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLContext share_context = %p, "
822 "const EGLint *attrib_list = %p)", dpy, config, share_context, attrib_list);
823
824 EGLint majorVersion = 1;
825 EGLint minorVersion = 0;
826
827 if(attrib_list)
828 {
829 for(const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2)
830 {
831 switch(attribute[0])
832 {
833 case EGL_CONTEXT_MAJOR_VERSION_KHR: // This token is an alias for EGL_CONTEXT_CLIENT_VERSION
834 majorVersion = attribute[1];
835 break;
836 case EGL_CONTEXT_MINOR_VERSION_KHR:
837 minorVersion = attribute[1];
838 break;
839 case EGL_CONTEXT_FLAGS_KHR:
840 switch(attribute[1])
841 {
842 case EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR:
843 // According to the EGL_KHR_create_context spec:
844 // "Khronos is still defining the expected and required features of debug contexts, so
845 // implementations are currently free to implement "debug contexts" with little or no debug
846 // functionality. However, OpenGL and OpenGL ES implementations supporting the GL_KHR_debug
847 // extension should enable it when this bit is set."
848 break;
849 case EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR:
850 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR:
851 // These bits are for OpenGL contexts only, not OpenGL ES contexts
852 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
853 default:
854 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
855 }
856 break;
857 case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
858 switch(attribute[1])
859 {
860 case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR:
861 case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR:
862 // These bits are for OpenGL contexts only, not OpenGL ES contexts
863 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
864 default:
865 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
866 }
867 break;
868 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
869 switch(attribute[1])
870 {
871 case EGL_NO_RESET_NOTIFICATION_KHR:
872 case EGL_LOSE_CONTEXT_ON_RESET_KHR:
873 // These bits are for OpenGL contexts only, not OpenGL ES contexts
874 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
875 default:
876 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
877 }
878 break;
879 default:
880 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
881 }
882 }
883 }
884
885 switch(majorVersion)
886 {
887 case 1:
888 if(minorVersion != 0 && minorVersion != 1)
889 {
890 // 1.X: Only OpenGL ES 1.0 and 1.1 contexts are supported
891 return error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
892 }
893 break;
894 case 2:
895 case 3:
896 if(minorVersion != 0)
897 {
898 // 2.X and 3.X: Only OpenGL ES 2.0 and 3.0 contexts are currently supported
899 return error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
900 }
901 break;
902 default:
903 return error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
904 }
905
906 egl::Display *display = egl::Display::get(dpy);
907 egl::Context *shareContext = static_cast<egl::Context*>(share_context);
908
909 RecursiveLockGuard lock(egl::getDisplayLock(display));
910
911 if(!validateConfig(display, config))
912 {
913 return EGL_NO_CONTEXT;
914 }
915
916 // Allow sharing between different context versions >= 2.0, but isolate 1.x
917 // contexts from 2.0+. Strict matching between context versions >= 2.0 is
918 // confusing for apps to navigate because of version promotion.
919 if(shareContext && ((shareContext->getClientVersion() >= 2) ^ (majorVersion >= 2)))
920 {
921 return error(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
922 }
923
924 return display->createContext(config, shareContext, majorVersion);
925 }
926
DestroyContext(EGLDisplay dpy,EGLContext ctx)927 EGLBoolean EGLAPIENTRY DestroyContext(EGLDisplay dpy, EGLContext ctx)
928 {
929 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p)", dpy, ctx);
930
931 egl::Display *display = egl::Display::get(dpy);
932 egl::Context *context = static_cast<egl::Context*>(ctx);
933
934 RecursiveLockGuard lock(egl::getDisplayLock(display));
935
936 if(!validateContext(display, context))
937 {
938 return EGL_FALSE;
939 }
940
941 if(ctx == EGL_NO_CONTEXT)
942 {
943 return error(EGL_BAD_CONTEXT, EGL_FALSE);
944 }
945
946 display->destroyContext(context);
947
948 return success(EGL_TRUE);
949 }
950
MakeCurrent(EGLDisplay dpy,EGLSurface draw,EGLSurface read,EGLContext ctx)951 EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
952 {
953 TRACE("(EGLDisplay dpy = %p, EGLSurface draw = %p, EGLSurface read = %p, EGLContext ctx = %p)",
954 dpy, draw, read, ctx);
955
956 egl::Display *display = egl::Display::get(dpy);
957 egl::Context *context = static_cast<egl::Context*>(ctx);
958 egl::Surface *drawSurface = static_cast<egl::Surface*>(draw);
959 egl::Surface *readSurface = static_cast<egl::Surface*>(read);
960
961 RecursiveLockGuard lock(egl::getDisplayLock(display));
962
963 if(ctx != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)
964 {
965 if(!validateDisplay(display))
966 {
967 return EGL_FALSE;
968 }
969 }
970
971 if(ctx == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
972 {
973 return error(EGL_BAD_MATCH, EGL_FALSE);
974 }
975
976 if(ctx != EGL_NO_CONTEXT && !validateContext(display, context))
977 {
978 return EGL_FALSE;
979 }
980
981 if((draw != EGL_NO_SURFACE && !validateSurface(display, drawSurface)) ||
982 (read != EGL_NO_SURFACE && !validateSurface(display, readSurface)))
983 {
984 return EGL_FALSE;
985 }
986
987 if((draw != EGL_NO_SURFACE) ^ (read != EGL_NO_SURFACE))
988 {
989 return error(EGL_BAD_MATCH, EGL_FALSE);
990 }
991
992 if(draw != read)
993 {
994 UNIMPLEMENTED(); // FIXME
995 }
996
997 egl::setCurrentDrawSurface(drawSurface);
998 egl::setCurrentReadSurface(readSurface);
999 egl::setCurrentContext(context);
1000
1001 if(context)
1002 {
1003 context->makeCurrent(drawSurface);
1004 }
1005
1006 return success(EGL_TRUE);
1007 }
1008
GetCurrentContext(void)1009 EGLContext EGLAPIENTRY GetCurrentContext(void)
1010 {
1011 TRACE("()");
1012
1013 EGLContext context = egl::getCurrentContext();
1014
1015 return success(context);
1016 }
1017
GetCurrentSurface(EGLint readdraw)1018 EGLSurface EGLAPIENTRY GetCurrentSurface(EGLint readdraw)
1019 {
1020 TRACE("(EGLint readdraw = %d)", readdraw);
1021
1022 if(readdraw == EGL_READ)
1023 {
1024 EGLSurface read = egl::getCurrentReadSurface();
1025 return success(read);
1026 }
1027 else if(readdraw == EGL_DRAW)
1028 {
1029 EGLSurface draw = egl::getCurrentDrawSurface();
1030 return success(draw);
1031 }
1032 else
1033 {
1034 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1035 }
1036 }
1037
GetCurrentDisplay(void)1038 EGLDisplay EGLAPIENTRY GetCurrentDisplay(void)
1039 {
1040 TRACE("()");
1041
1042 egl::Context *context = egl::getCurrentContext();
1043
1044 if(!context)
1045 {
1046 return success(EGL_NO_DISPLAY);
1047 }
1048
1049 egl::Display *display = context->getDisplay();
1050
1051 if(!display)
1052 {
1053 return error(EGL_BAD_ACCESS, EGL_NO_DISPLAY);
1054 }
1055
1056 return success(display->getEGLDisplay());
1057 }
1058
QueryContext(EGLDisplay dpy,EGLContext ctx,EGLint attribute,EGLint * value)1059 EGLBoolean EGLAPIENTRY QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
1060 {
1061 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLint attribute = %d, EGLint *value = %p)",
1062 dpy, ctx, attribute, value);
1063
1064 egl::Display *display = egl::Display::get(dpy);
1065 egl::Context *context = static_cast<egl::Context*>(ctx);
1066
1067 RecursiveLockGuard lock(egl::getDisplayLock(display));
1068
1069 if(!validateContext(display, context))
1070 {
1071 return EGL_FALSE;
1072 }
1073
1074 switch(attribute)
1075 {
1076 case EGL_CONFIG_ID:
1077 *value = context->getConfigID();
1078 break;
1079 case EGL_CONTEXT_CLIENT_TYPE:
1080 *value = egl::getCurrentAPI();
1081 break;
1082 case EGL_CONTEXT_CLIENT_VERSION:
1083 *value = context->getClientVersion();
1084 break;
1085 case EGL_RENDER_BUFFER:
1086 *value = EGL_BACK_BUFFER;
1087 break;
1088 default:
1089 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1090 }
1091
1092 return success(EGL_TRUE);
1093 }
1094
WaitGL(void)1095 EGLBoolean EGLAPIENTRY WaitGL(void)
1096 {
1097 TRACE("()");
1098
1099 // glWaitGL is ignored if there is no current EGL rendering context for OpenGL ES.
1100 egl::Context *context = egl::getCurrentContext();
1101
1102 if(context)
1103 {
1104 context->finish();
1105 }
1106
1107 return success(EGL_TRUE);
1108 }
1109
WaitNative(EGLint engine)1110 EGLBoolean EGLAPIENTRY WaitNative(EGLint engine)
1111 {
1112 TRACE("(EGLint engine = %d)", engine);
1113
1114 if(engine != EGL_CORE_NATIVE_ENGINE)
1115 {
1116 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1117 }
1118
1119 // eglWaitNative is ignored if there is no current EGL rendering context.
1120 egl::Context *context = egl::getCurrentContext();
1121
1122 if(context)
1123 {
1124 #if defined(USE_X11)
1125 egl::Display *display = context->getDisplay();
1126
1127 if(!display)
1128 {
1129 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1130 }
1131
1132 libX11->XSync((::Display*)display->getNativeDisplay(), False);
1133 #else
1134 UNIMPLEMENTED();
1135 #endif
1136 }
1137
1138 return success(EGL_TRUE);
1139 }
1140
SwapBuffers(EGLDisplay dpy,EGLSurface surface)1141 EGLBoolean EGLAPIENTRY SwapBuffers(EGLDisplay dpy, EGLSurface surface)
1142 {
1143 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p)", dpy, surface);
1144
1145 egl::Display *display = egl::Display::get(dpy);
1146 egl::Surface *eglSurface = (egl::Surface*)surface;
1147
1148 {
1149 RecursiveLockGuard lock(egl::getDisplayLock(display));
1150
1151 if(!validateSurface(display, eglSurface))
1152 {
1153 return EGL_FALSE;
1154 }
1155 }
1156
1157 if(surface == EGL_NO_SURFACE)
1158 {
1159 return error(EGL_BAD_SURFACE, EGL_FALSE);
1160 }
1161
1162 eglSurface->swap();
1163
1164 return success(EGL_TRUE);
1165 }
1166
CopyBuffers(EGLDisplay dpy,EGLSurface surface,EGLNativePixmapType target)1167 EGLBoolean EGLAPIENTRY CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
1168 {
1169 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLNativePixmapType target = %p)", dpy, surface, target);
1170
1171 egl::Display *display = egl::Display::get(dpy);
1172 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
1173
1174 RecursiveLockGuard lock(egl::getDisplayLock(display));
1175
1176 if(!validateSurface(display, eglSurface))
1177 {
1178 return EGL_FALSE;
1179 }
1180
1181 UNIMPLEMENTED(); // FIXME
1182
1183 return success(EGL_FALSE);
1184 }
1185
CreateImage(EGLDisplay dpy,EGLContext ctx,EGLenum target,EGLClientBuffer buffer,const EGLAttrib * attrib_list)1186 EGLImage EGLAPIENTRY CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list)
1187 {
1188 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLenum target = 0x%X, buffer = %p, const EGLAttrib *attrib_list = %p)", dpy, ctx, target, buffer, attrib_list);
1189
1190 egl::Display *display = egl::Display::get(dpy);
1191 egl::Context *context = static_cast<egl::Context*>(ctx);
1192
1193 RecursiveLockGuard lock(egl::getDisplayLock(display));
1194
1195 if(!validateDisplay(display))
1196 {
1197 return error(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1198 }
1199
1200 if(context != EGL_NO_CONTEXT && !display->isValidContext(context))
1201 {
1202 return error(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1203 }
1204
1205 EGLenum imagePreserved = EGL_FALSE;
1206 (void)imagePreserved; // currently unused
1207
1208 GLuint textureLevel = 0;
1209 if(attrib_list)
1210 {
1211 for(const EGLAttrib *attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2)
1212 {
1213 if(attribute[0] == EGL_IMAGE_PRESERVED_KHR)
1214 {
1215 imagePreserved = static_cast<EGLenum>(attribute[1]);
1216 }
1217 else if(attribute[0] == EGL_GL_TEXTURE_LEVEL_KHR)
1218 {
1219 textureLevel = static_cast<GLuint>(attribute[1]);
1220 }
1221 else
1222 {
1223 return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR);
1224 }
1225 }
1226 }
1227
1228 #if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD)
1229 if(target == EGL_NATIVE_BUFFER_ANDROID)
1230 {
1231 ANativeWindowBuffer *nativeBuffer = reinterpret_cast<ANativeWindowBuffer*>(buffer);
1232
1233 if(!nativeBuffer || GLPixelFormatFromAndroid(nativeBuffer->format) == GL_NONE)
1234 {
1235 ERR("%s badness unsupported HAL format=%x", __FUNCTION__, nativeBuffer ? nativeBuffer->format : 0);
1236 return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR);
1237 }
1238
1239 Image *image = new AndroidNativeImage(nativeBuffer);
1240 EGLImageKHR eglImage = display->createSharedImage(image);
1241
1242 return success(eglImage);
1243 }
1244 #endif
1245
1246 GLuint name = static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer));
1247
1248 if(name == 0)
1249 {
1250 return error(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1251 }
1252
1253 EGLenum validationResult = context->validateSharedImage(target, name, textureLevel);
1254
1255 if(validationResult != EGL_SUCCESS)
1256 {
1257 return error(validationResult, EGL_NO_IMAGE_KHR);
1258 }
1259
1260 Image *image = context->createSharedImage(target, name, textureLevel);
1261
1262 if(!image)
1263 {
1264 return error(EGL_BAD_MATCH, EGL_NO_IMAGE_KHR);
1265 }
1266
1267 if(image->getDepth() > 1)
1268 {
1269 return error(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1270 }
1271
1272 EGLImage eglImage = display->createSharedImage(image);
1273
1274 return success(eglImage);
1275 }
1276
CreateImageKHR(EGLDisplay dpy,EGLContext ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attrib_list)1277 EGLImageKHR EGLAPIENTRY CreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
1278 {
1279 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLenum target = 0x%X, buffer = %p, const EGLint attrib_list = %p)", dpy, ctx, target, buffer, attrib_list);
1280
1281 EGLAttribs attribs(attrib_list);
1282 return CreateImage(dpy, ctx, target, buffer, &attribs);
1283 }
1284
DestroyImageKHR(EGLDisplay dpy,EGLImageKHR image)1285 EGLBoolean EGLAPIENTRY DestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
1286 {
1287 TRACE("(EGLDisplay dpy = %p, EGLImageKHR image = %p)", dpy, image);
1288
1289 egl::Display *display = egl::Display::get(dpy);
1290
1291 RecursiveLockGuard lock(egl::getDisplayLock(display));
1292
1293 if(!validateDisplay(display))
1294 {
1295 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1296 }
1297
1298 if(!display->destroySharedImage(image))
1299 {
1300 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1301 }
1302
1303 return success(EGL_TRUE);
1304 }
1305
GetPlatformDisplay(EGLenum platform,void * native_display,const EGLAttrib * attrib_list)1306 EGLDisplay EGLAPIENTRY GetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list)
1307 {
1308 TRACE("(EGLenum platform = 0x%X, void *native_display = %p, const EGLAttrib *attrib_list = %p)", platform, native_display, attrib_list);
1309
1310 #if (defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)) && !defined(__ANDROID__)
1311 switch(platform)
1312 {
1313 #if defined(USE_X11)
1314 case EGL_PLATFORM_X11_EXT: break;
1315 #endif
1316 case EGL_PLATFORM_GBM_KHR: break;
1317 default:
1318 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
1319 }
1320
1321 if(platform == EGL_PLATFORM_GBM_KHR)
1322 {
1323 if(native_display != (void*)EGL_DEFAULT_DISPLAY)
1324 {
1325 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); // Unimplemented
1326 }
1327
1328 if(attrib_list && attrib_list[0] != EGL_NONE)
1329 {
1330 return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented
1331 }
1332
1333 return success(HEADLESS_DISPLAY);
1334 }
1335 #if defined(USE_X11)
1336 else if(platform == EGL_PLATFORM_X11_EXT)
1337 {
1338 if(!libX11)
1339 {
1340 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
1341 }
1342
1343 if(native_display != (void*)EGL_DEFAULT_DISPLAY)
1344 {
1345 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); // Unimplemented
1346 }
1347
1348 if(attrib_list && attrib_list[0] != EGL_NONE)
1349 {
1350 return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented
1351 }
1352 }
1353 #endif
1354
1355 return success(PRIMARY_DISPLAY); // We only support the default display
1356 #else
1357 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
1358 #endif
1359 }
1360
GetPlatformDisplayEXT(EGLenum platform,void * native_display,const EGLint * attrib_list)1361 EGLDisplay EGLAPIENTRY GetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list)
1362 {
1363 TRACE("(EGLenum platform = 0x%X, void *native_display = %p, const EGLint *attrib_list = %p)", platform, native_display, attrib_list);
1364
1365 EGLAttribs attribs(attrib_list);
1366 return GetPlatformDisplay(platform, native_display, &attribs);
1367 }
1368
CreateSync(EGLDisplay dpy,EGLenum type,const EGLAttrib * attrib_list)1369 EGLSync EGLAPIENTRY CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list)
1370 {
1371 TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLAttrib *attrib_list=%p)", dpy, type, attrib_list);
1372
1373 egl::Display *display = egl::Display::get(dpy);
1374
1375 RecursiveLockGuard lock(egl::getDisplayLock(display));
1376
1377 if(!validateDisplay(display))
1378 {
1379 return error(EGL_BAD_DISPLAY, EGL_NO_SYNC_KHR);
1380 }
1381
1382 if(type != EGL_SYNC_FENCE_KHR)
1383 {
1384 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
1385 }
1386
1387 if(attrib_list && attrib_list[0] != EGL_NONE)
1388 {
1389 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
1390 }
1391
1392 egl::Context *context = egl::getCurrentContext();
1393
1394 if(!validateContext(display, context))
1395 {
1396 return error(EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
1397 }
1398
1399 EGLSyncKHR sync = display->createSync(context);
1400
1401 return success(sync);
1402 }
1403
CreateSyncKHR(EGLDisplay dpy,EGLenum type,const EGLint * attrib_list)1404 EGLSyncKHR EGLAPIENTRY CreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1405 {
1406 TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLint *attrib_list=%p)", dpy, type, attrib_list);
1407
1408 EGLAttribs attribs(attrib_list);
1409 return CreateSync(dpy, type, &attribs);
1410 }
1411
DestroySyncKHR(EGLDisplay dpy,EGLSyncKHR sync)1412 EGLBoolean EGLAPIENTRY DestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1413 {
1414 TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p)", dpy, sync);
1415
1416 egl::Display *display = egl::Display::get(dpy);
1417 FenceSync *eglSync = static_cast<FenceSync*>(sync);
1418
1419 RecursiveLockGuard lock(egl::getDisplayLock(display));
1420
1421 if(!validateDisplay(display))
1422 {
1423 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1424 }
1425
1426 if(!display->isValidSync(eglSync))
1427 {
1428 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1429 }
1430
1431 display->destroySync(eglSync);
1432
1433 return success(EGL_TRUE);
1434 }
1435
ClientWaitSyncKHR(EGLDisplay dpy,EGLSyncKHR sync,EGLint flags,EGLTimeKHR timeout)1436 EGLint EGLAPIENTRY ClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
1437 {
1438 TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint flags = %x, EGLTimeKHR value = %llx)", dpy, sync, flags, timeout);
1439
1440 egl::Display *display = egl::Display::get(dpy);
1441 FenceSync *eglSync = static_cast<FenceSync*>(sync);
1442
1443 RecursiveLockGuard lock(egl::getDisplayLock(display));
1444
1445 if(!validateDisplay(display))
1446 {
1447 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1448 }
1449
1450 if(!display->isValidSync(eglSync))
1451 {
1452 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1453 }
1454
1455 (void)flags;
1456 (void)timeout;
1457
1458 if(!eglSync->isSignaled())
1459 {
1460 eglSync->wait();
1461 }
1462
1463 return success(EGL_CONDITION_SATISFIED_KHR);
1464 }
1465
GetSyncAttrib(EGLDisplay dpy,EGLSyncKHR sync,EGLint attribute,EGLAttrib * value)1466 EGLBoolean EGLAPIENTRY GetSyncAttrib(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLAttrib *value)
1467 {
1468 TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint attribute = %x, EGLAttrib *value = %p)", dpy, sync, attribute, value);
1469
1470 egl::Display *display = egl::Display::get(dpy);
1471 FenceSync *eglSync = static_cast<FenceSync*>(sync);
1472
1473 RecursiveLockGuard lock(egl::getDisplayLock(display));
1474
1475 if(!validateDisplay(display))
1476 {
1477 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1478 }
1479
1480 if(!display->isValidSync(eglSync))
1481 {
1482 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1483 }
1484
1485 if(!value)
1486 {
1487 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1488 }
1489
1490 switch(attribute)
1491 {
1492 case EGL_SYNC_TYPE_KHR:
1493 *value = EGL_SYNC_FENCE_KHR;
1494 return success(EGL_TRUE);
1495 case EGL_SYNC_STATUS_KHR:
1496 eglSync->wait(); // TODO: Don't block. Just poll based on sw::Query.
1497 *value = eglSync->isSignaled() ? EGL_SIGNALED_KHR : EGL_UNSIGNALED_KHR;
1498 return success(EGL_TRUE);
1499 case EGL_SYNC_CONDITION_KHR:
1500 *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
1501 return success(EGL_TRUE);
1502 default:
1503 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1504 }
1505 }
1506
GetSyncAttribKHR(EGLDisplay dpy,EGLSyncKHR sync,EGLint attribute,EGLint * value)1507 EGLBoolean EGLAPIENTRY GetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
1508 {
1509 EGLAttrib attrib_value;
1510 EGLBoolean result = GetSyncAttrib(dpy, sync, attribute, &attrib_value);
1511 *value = static_cast<EGLint>(attrib_value);
1512 return result;
1513 }
1514
GetProcAddress(const char * procname)1515 __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *procname)
1516 {
1517 TRACE("(const char *procname = \"%s\")", procname);
1518
1519 struct Function
1520 {
1521 const char *name;
1522 __eglMustCastToProperFunctionPointerType address;
1523 };
1524
1525 struct CompareFunctor
1526 {
1527 bool operator()(const Function &a, const Function &b) const
1528 {
1529 return strcmp(a.name, b.name) < 0;
1530 }
1531 };
1532
1533 // This array must be kept sorted with respect to strcmp(), so that binary search works correctly.
1534 // The Unix command "LC_COLLATE=C sort" will generate the correct order.
1535 static const Function eglFunctions[] =
1536 {
1537 #define FUNCTION(name) {#name, (__eglMustCastToProperFunctionPointerType)name}
1538
1539 FUNCTION(eglBindAPI),
1540 FUNCTION(eglBindTexImage),
1541 FUNCTION(eglChooseConfig),
1542 FUNCTION(eglClientWaitSync),
1543 FUNCTION(eglClientWaitSyncKHR),
1544 FUNCTION(eglCopyBuffers),
1545 FUNCTION(eglCreateContext),
1546 FUNCTION(eglCreateImage),
1547 FUNCTION(eglCreateImageKHR),
1548 FUNCTION(eglCreatePbufferFromClientBuffer),
1549 FUNCTION(eglCreatePbufferSurface),
1550 FUNCTION(eglCreatePixmapSurface),
1551 FUNCTION(eglCreatePlatformPixmapSurface),
1552 FUNCTION(eglCreatePlatformPixmapSurfaceEXT),
1553 FUNCTION(eglCreatePlatformWindowSurface),
1554 FUNCTION(eglCreatePlatformWindowSurfaceEXT),
1555 FUNCTION(eglCreateSync),
1556 FUNCTION(eglCreateSyncKHR),
1557 FUNCTION(eglCreateWindowSurface),
1558 FUNCTION(eglDestroyContext),
1559 FUNCTION(eglDestroyImage),
1560 FUNCTION(eglDestroyImageKHR),
1561 FUNCTION(eglDestroySurface),
1562 FUNCTION(eglDestroySync),
1563 FUNCTION(eglDestroySyncKHR),
1564 FUNCTION(eglGetConfigAttrib),
1565 FUNCTION(eglGetConfigs),
1566 FUNCTION(eglGetCurrentContext),
1567 FUNCTION(eglGetCurrentDisplay),
1568 FUNCTION(eglGetCurrentSurface),
1569 FUNCTION(eglGetDisplay),
1570 FUNCTION(eglGetError),
1571 FUNCTION(eglGetPlatformDisplay),
1572 FUNCTION(eglGetPlatformDisplayEXT),
1573 FUNCTION(eglGetProcAddress),
1574 FUNCTION(eglGetSyncAttrib),
1575 FUNCTION(eglGetSyncAttribKHR),
1576 FUNCTION(eglInitialize),
1577 FUNCTION(eglMakeCurrent),
1578 FUNCTION(eglQueryAPI),
1579 FUNCTION(eglQueryContext),
1580 FUNCTION(eglQueryString),
1581 FUNCTION(eglQuerySurface),
1582 FUNCTION(eglReleaseTexImage),
1583 FUNCTION(eglReleaseThread),
1584 FUNCTION(eglSurfaceAttrib),
1585 FUNCTION(eglSwapBuffers),
1586 FUNCTION(eglSwapInterval),
1587 FUNCTION(eglTerminate),
1588 FUNCTION(eglWaitClient),
1589 FUNCTION(eglWaitGL),
1590 FUNCTION(eglWaitNative),
1591 FUNCTION(eglWaitSync),
1592 FUNCTION(eglWaitSyncKHR),
1593
1594 #undef FUNCTION
1595 };
1596
1597 static const size_t numFunctions = sizeof eglFunctions / sizeof(Function);
1598 static const Function *const eglFunctionsEnd = eglFunctions + numFunctions;
1599
1600 Function needle;
1601 needle.name = procname;
1602
1603 if(procname && strncmp("egl", procname, 3) == 0)
1604 {
1605 const Function *result = std::lower_bound(eglFunctions, eglFunctionsEnd, needle, CompareFunctor());
1606 if (result != eglFunctionsEnd && strcmp(procname, result->name) == 0)
1607 {
1608 return success((__eglMustCastToProperFunctionPointerType)result->address);
1609 }
1610 }
1611
1612 if(libGLESv2)
1613 {
1614 __eglMustCastToProperFunctionPointerType proc = libGLESv2->es2GetProcAddress(procname);
1615 if(proc) return success(proc);
1616 }
1617
1618 if(libGLES_CM)
1619 {
1620 __eglMustCastToProperFunctionPointerType proc = libGLES_CM->es1GetProcAddress(procname);
1621 if(proc) return success(proc);
1622 }
1623
1624 return success((__eglMustCastToProperFunctionPointerType)NULL);
1625 }
1626 }
1627