1 //
2 // Copyright(c) 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // entry_points_egl.cpp : Implements the EGL entry points.
8
9 #include "libGLESv2/entry_points_egl.h"
10
11 #include "common/debug.h"
12 #include "common/version.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Display.h"
15 #include "libANGLE/Surface.h"
16 #include "libANGLE/Texture.h"
17 #include "libANGLE/Thread.h"
18 #include "libANGLE/queryutils.h"
19 #include "libANGLE/validationEGL.h"
20 #include "libGLESv2/global_state.h"
21 #include "libGLESv2/proc_table.h"
22
23 #include <EGL/eglext.h>
24
25 namespace egl
26 {
27
28 namespace
29 {
30
CompareProc(const ProcEntry & a,const char * b)31 bool CompareProc(const ProcEntry &a, const char *b)
32 {
33 return strcmp(a.first, b) < 0;
34 }
35
ClipConfigs(const std::vector<const Config * > & filteredConfigs,EGLConfig * output_configs,EGLint config_size,EGLint * num_config)36 void ClipConfigs(const std::vector<const Config *> &filteredConfigs,
37 EGLConfig *output_configs,
38 EGLint config_size,
39 EGLint *num_config)
40 {
41 EGLint result_size = static_cast<EGLint>(filteredConfigs.size());
42 if (output_configs)
43 {
44 result_size = std::max(std::min(result_size, config_size), 0);
45 for (EGLint i = 0; i < result_size; i++)
46 {
47 output_configs[i] = const_cast<Config *>(filteredConfigs[i]);
48 }
49 }
50 *num_config = result_size;
51 }
52
53 } // anonymous namespace
54
55 // EGL 1.0
GetError(void)56 EGLint EGLAPIENTRY GetError(void)
57 {
58 EVENT("()");
59 Thread *thread = GetCurrentThread();
60
61 EGLint error = thread->getError();
62 thread->setError(NoError());
63 return error;
64 }
65
GetDisplay(EGLNativeDisplayType display_id)66 EGLDisplay EGLAPIENTRY GetDisplay(EGLNativeDisplayType display_id)
67 {
68 EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id);
69
70 return Display::GetDisplayFromNativeDisplay(display_id, AttributeMap());
71 }
72
Initialize(EGLDisplay dpy,EGLint * major,EGLint * minor)73 EGLBoolean EGLAPIENTRY Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
74 {
75 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint *major = 0x%0.8p, EGLint *minor = 0x%0.8p)", dpy,
76 major, minor);
77 Thread *thread = GetCurrentThread();
78
79 Display *display = static_cast<Display *>(dpy);
80 if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
81 {
82 thread->setError(EglBadDisplay());
83 return EGL_FALSE;
84 }
85
86 Error error = display->initialize();
87 if (error.isError())
88 {
89 thread->setError(error);
90 return EGL_FALSE;
91 }
92
93 if (major)
94 *major = 1;
95 if (minor)
96 *minor = 4;
97
98 thread->setError(NoError());
99 return EGL_TRUE;
100 }
101
Terminate(EGLDisplay dpy)102 EGLBoolean EGLAPIENTRY Terminate(EGLDisplay dpy)
103 {
104 EVENT("(EGLDisplay dpy = 0x%0.8p)", dpy);
105 Thread *thread = GetCurrentThread();
106
107 Display *display = static_cast<Display *>(dpy);
108 if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
109 {
110 thread->setError(EglBadDisplay());
111 return EGL_FALSE;
112 }
113
114 if (display->isValidContext(thread->getContext()))
115 {
116 thread->setCurrent(nullptr);
117 }
118
119 Error error = display->terminate();
120 if (error.isError())
121 {
122 thread->setError(error);
123 return EGL_FALSE;
124 }
125
126 thread->setError(NoError());
127 return EGL_TRUE;
128 }
129
QueryString(EGLDisplay dpy,EGLint name)130 const char *EGLAPIENTRY QueryString(EGLDisplay dpy, EGLint name)
131 {
132 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint name = %d)", dpy, name);
133 Thread *thread = GetCurrentThread();
134
135 Display *display = static_cast<Display *>(dpy);
136 if (!(display == EGL_NO_DISPLAY && name == EGL_EXTENSIONS))
137 {
138 Error error = ValidateDisplay(display);
139 if (error.isError())
140 {
141 thread->setError(error);
142 return nullptr;
143 }
144 }
145
146 const char *result;
147 switch (name)
148 {
149 case EGL_CLIENT_APIS:
150 result = "OpenGL_ES";
151 break;
152 case EGL_EXTENSIONS:
153 if (display == EGL_NO_DISPLAY)
154 {
155 result = Display::GetClientExtensionString().c_str();
156 }
157 else
158 {
159 result = display->getExtensionString().c_str();
160 }
161 break;
162 case EGL_VENDOR:
163 result = display->getVendorString().c_str();
164 break;
165 case EGL_VERSION:
166 result = "1.4 (ANGLE " ANGLE_VERSION_STRING ")";
167 break;
168 default:
169 thread->setError(EglBadParameter());
170 return nullptr;
171 }
172
173 thread->setError(NoError());
174 return result;
175 }
176
GetConfigs(EGLDisplay dpy,EGLConfig * configs,EGLint config_size,EGLint * num_config)177 EGLBoolean EGLAPIENTRY GetConfigs(EGLDisplay dpy,
178 EGLConfig *configs,
179 EGLint config_size,
180 EGLint *num_config)
181 {
182 EVENT(
183 "(EGLDisplay dpy = 0x%0.8p, EGLConfig *configs = 0x%0.8p, "
184 "EGLint config_size = %d, EGLint *num_config = 0x%0.8p)",
185 dpy, configs, config_size, num_config);
186 Thread *thread = GetCurrentThread();
187
188 Display *display = static_cast<Display *>(dpy);
189
190 Error error = ValidateGetConfigs(display, config_size, num_config);
191 if (error.isError())
192 {
193 thread->setError(error);
194 return EGL_FALSE;
195 }
196
197 ClipConfigs(display->getConfigs(AttributeMap()), configs, config_size, num_config);
198
199 thread->setError(NoError());
200 return EGL_TRUE;
201 }
202
ChooseConfig(EGLDisplay dpy,const EGLint * attrib_list,EGLConfig * configs,EGLint config_size,EGLint * num_config)203 EGLBoolean EGLAPIENTRY ChooseConfig(EGLDisplay dpy,
204 const EGLint *attrib_list,
205 EGLConfig *configs,
206 EGLint config_size,
207 EGLint *num_config)
208 {
209 EVENT(
210 "(EGLDisplay dpy = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p, "
211 "EGLConfig *configs = 0x%0.8p, EGLint config_size = %d, EGLint *num_config = 0x%0.8p)",
212 dpy, attrib_list, configs, config_size, num_config);
213 Thread *thread = GetCurrentThread();
214
215 Display *display = static_cast<Display *>(dpy);
216 AttributeMap attribMap = AttributeMap::CreateFromIntArray(attrib_list);
217
218 Error error = ValidateChooseConfig(display, attribMap, config_size, num_config);
219 if (error.isError())
220 {
221 thread->setError(error);
222 return EGL_FALSE;
223 }
224
225 ClipConfigs(display->getConfigs(attribMap), configs, config_size, num_config);
226
227 thread->setError(NoError());
228 return EGL_TRUE;
229 }
230
GetConfigAttrib(EGLDisplay dpy,EGLConfig config,EGLint attribute,EGLint * value)231 EGLBoolean EGLAPIENTRY GetConfigAttrib(EGLDisplay dpy,
232 EGLConfig config,
233 EGLint attribute,
234 EGLint *value)
235 {
236 EVENT(
237 "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLint attribute = %d, EGLint "
238 "*value = 0x%0.8p)",
239 dpy, config, attribute, value);
240 Thread *thread = GetCurrentThread();
241
242 Display *display = static_cast<Display *>(dpy);
243 Config *configuration = static_cast<Config *>(config);
244
245 Error error = ValidateGetConfigAttrib(display, configuration, attribute);
246 if (error.isError())
247 {
248 thread->setError(error);
249 return EGL_FALSE;
250 }
251
252 QueryConfigAttrib(configuration, attribute, value);
253
254 thread->setError(NoError());
255 return EGL_TRUE;
256 }
257
CreateWindowSurface(EGLDisplay dpy,EGLConfig config,EGLNativeWindowType win,const EGLint * attrib_list)258 EGLSurface EGLAPIENTRY CreateWindowSurface(EGLDisplay dpy,
259 EGLConfig config,
260 EGLNativeWindowType win,
261 const EGLint *attrib_list)
262 {
263 EVENT(
264 "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativeWindowType win = 0x%0.8p, "
265 "const EGLint *attrib_list = 0x%0.8p)",
266 dpy, config, win, attrib_list);
267 Thread *thread = GetCurrentThread();
268
269 Display *display = static_cast<Display *>(dpy);
270 Config *configuration = static_cast<Config *>(config);
271 AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list);
272
273 Error error = ValidateCreateWindowSurface(display, configuration, win, attributes);
274 if (error.isError())
275 {
276 thread->setError(error);
277 return EGL_NO_SURFACE;
278 }
279
280 egl::Surface *surface = nullptr;
281 error = display->createWindowSurface(configuration, win, attributes, &surface);
282 if (error.isError())
283 {
284 thread->setError(error);
285 return EGL_NO_SURFACE;
286 }
287
288 return static_cast<EGLSurface>(surface);
289 }
290
CreatePbufferSurface(EGLDisplay dpy,EGLConfig config,const EGLint * attrib_list)291 EGLSurface EGLAPIENTRY CreatePbufferSurface(EGLDisplay dpy,
292 EGLConfig config,
293 const EGLint *attrib_list)
294 {
295 EVENT(
296 "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = "
297 "0x%0.8p)",
298 dpy, config, attrib_list);
299 Thread *thread = GetCurrentThread();
300
301 Display *display = static_cast<Display *>(dpy);
302 Config *configuration = static_cast<Config *>(config);
303 AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list);
304
305 Error error = ValidateCreatePbufferSurface(display, configuration, attributes);
306 if (error.isError())
307 {
308 thread->setError(error);
309 return EGL_NO_SURFACE;
310 }
311
312 egl::Surface *surface = nullptr;
313 error = display->createPbufferSurface(configuration, attributes, &surface);
314 if (error.isError())
315 {
316 thread->setError(error);
317 return EGL_NO_SURFACE;
318 }
319
320 return static_cast<EGLSurface>(surface);
321 }
322
CreatePixmapSurface(EGLDisplay dpy,EGLConfig config,EGLNativePixmapType pixmap,const EGLint * attrib_list)323 EGLSurface EGLAPIENTRY CreatePixmapSurface(EGLDisplay dpy,
324 EGLConfig config,
325 EGLNativePixmapType pixmap,
326 const EGLint *attrib_list)
327 {
328 EVENT(
329 "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativePixmapType pixmap = "
330 "0x%0.8p, "
331 "const EGLint *attrib_list = 0x%0.8p)",
332 dpy, config, pixmap, attrib_list);
333 Thread *thread = GetCurrentThread();
334
335 Display *display = static_cast<Display *>(dpy);
336 Config *configuration = static_cast<Config *>(config);
337
338 Error error = ValidateConfig(display, configuration);
339 if (error.isError())
340 {
341 thread->setError(error);
342 return EGL_NO_SURFACE;
343 }
344
345 UNIMPLEMENTED(); // FIXME
346
347 thread->setError(NoError());
348 return EGL_NO_SURFACE;
349 }
350
DestroySurface(EGLDisplay dpy,EGLSurface surface)351 EGLBoolean EGLAPIENTRY DestroySurface(EGLDisplay dpy, EGLSurface surface)
352 {
353 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface);
354 Thread *thread = GetCurrentThread();
355
356 Display *display = static_cast<Display *>(dpy);
357 Surface *eglSurface = static_cast<Surface *>(surface);
358
359 Error error = ValidateSurface(display, eglSurface);
360 if (error.isError())
361 {
362 thread->setError(error);
363 return EGL_FALSE;
364 }
365
366 if (surface == EGL_NO_SURFACE)
367 {
368 thread->setError(EglBadSurface());
369 return EGL_FALSE;
370 }
371
372 error = display->destroySurface(reinterpret_cast<Surface *>(surface));
373 if (error.isError())
374 {
375 thread->setError(error);
376 return EGL_FALSE;
377 }
378
379 thread->setError(NoError());
380 return EGL_TRUE;
381 }
382
QuerySurface(EGLDisplay dpy,EGLSurface surface,EGLint attribute,EGLint * value)383 EGLBoolean EGLAPIENTRY QuerySurface(EGLDisplay dpy,
384 EGLSurface surface,
385 EGLint attribute,
386 EGLint *value)
387 {
388 EVENT(
389 "(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint "
390 "*value = 0x%0.8p)",
391 dpy, surface, attribute, value);
392 Thread *thread = GetCurrentThread();
393
394 const Display *display = static_cast<const Display *>(dpy);
395 const Surface *eglSurface = static_cast<const Surface *>(surface);
396
397 Error error = ValidateQuerySurface(display, eglSurface, attribute, value);
398 if (error.isError())
399 {
400 thread->setError(error);
401 return EGL_FALSE;
402 }
403
404 QuerySurfaceAttrib(eglSurface, attribute, value);
405
406 thread->setError(NoError());
407 return EGL_TRUE;
408 }
409
CreateContext(EGLDisplay dpy,EGLConfig config,EGLContext share_context,const EGLint * attrib_list)410 EGLContext EGLAPIENTRY CreateContext(EGLDisplay dpy,
411 EGLConfig config,
412 EGLContext share_context,
413 const EGLint *attrib_list)
414 {
415 EVENT(
416 "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLContext share_context = "
417 "0x%0.8p, "
418 "const EGLint *attrib_list = 0x%0.8p)",
419 dpy, config, share_context, attrib_list);
420 Thread *thread = GetCurrentThread();
421
422 Display *display = static_cast<Display *>(dpy);
423 Config *configuration = static_cast<Config *>(config);
424 gl::Context *sharedGLContext = static_cast<gl::Context *>(share_context);
425 AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list);
426
427 Error error = ValidateCreateContext(display, configuration, sharedGLContext, attributes);
428 if (error.isError())
429 {
430 thread->setError(error);
431 return EGL_NO_CONTEXT;
432 }
433
434 gl::Context *context = nullptr;
435 error = display->createContext(configuration, sharedGLContext, attributes, &context);
436 if (error.isError())
437 {
438 thread->setError(error);
439 return EGL_NO_CONTEXT;
440 }
441
442 thread->setError(NoError());
443 return static_cast<EGLContext>(context);
444 }
445
DestroyContext(EGLDisplay dpy,EGLContext ctx)446 EGLBoolean EGLAPIENTRY DestroyContext(EGLDisplay dpy, EGLContext ctx)
447 {
448 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx);
449 Thread *thread = GetCurrentThread();
450
451 Display *display = static_cast<Display *>(dpy);
452 gl::Context *context = static_cast<gl::Context *>(ctx);
453
454 Error error = ValidateContext(display, context);
455 if (error.isError())
456 {
457 thread->setError(error);
458 return EGL_FALSE;
459 }
460
461 if (ctx == EGL_NO_CONTEXT)
462 {
463 thread->setError(EglBadContext());
464 return EGL_FALSE;
465 }
466
467 if (context == thread->getContext())
468 {
469 thread->setCurrent(nullptr);
470 }
471
472 error = display->destroyContext(context);
473 if (error.isError())
474 {
475 thread->setError(error);
476 return EGL_FALSE;
477 }
478
479 thread->setError(NoError());
480 return EGL_TRUE;
481 }
482
MakeCurrent(EGLDisplay dpy,EGLSurface draw,EGLSurface read,EGLContext ctx)483 EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
484 {
485 EVENT(
486 "(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, "
487 "EGLContext ctx = 0x%0.8p)",
488 dpy, draw, read, ctx);
489 Thread *thread = GetCurrentThread();
490
491 Display *display = static_cast<Display *>(dpy);
492 gl::Context *context = static_cast<gl::Context *>(ctx);
493
494 Error error = ValidateMakeCurrent(display, draw, read, context);
495 if (error.isError())
496 {
497 thread->setError(error);
498 return EGL_FALSE;
499 }
500
501 Surface *readSurface = static_cast<Surface *>(read);
502 Surface *drawSurface = static_cast<Surface *>(draw);
503 Error makeCurrentError = display->makeCurrent(drawSurface, readSurface, context);
504 if (makeCurrentError.isError())
505 {
506 thread->setError(makeCurrentError);
507 return EGL_FALSE;
508 }
509
510 gl::Context *previousContext = thread->getContext();
511 thread->setCurrent(context);
512
513 // Release the surface from the previously-current context, to allow
514 // destroyed surfaces to delete themselves.
515 if (previousContext != nullptr && context != previousContext)
516 {
517 auto err = previousContext->releaseSurface(display);
518 if (err.isError())
519 {
520 thread->setError(err);
521 return EGL_FALSE;
522 }
523 }
524
525 thread->setError(NoError());
526 return EGL_TRUE;
527 }
528
GetCurrentSurface(EGLint readdraw)529 EGLSurface EGLAPIENTRY GetCurrentSurface(EGLint readdraw)
530 {
531 EVENT("(EGLint readdraw = %d)", readdraw);
532 Thread *thread = GetCurrentThread();
533
534 if (readdraw == EGL_READ)
535 {
536 thread->setError(NoError());
537 return thread->getCurrentReadSurface();
538 }
539 else if (readdraw == EGL_DRAW)
540 {
541 thread->setError(NoError());
542 return thread->getCurrentDrawSurface();
543 }
544 else
545 {
546 thread->setError(EglBadParameter());
547 return EGL_NO_SURFACE;
548 }
549 }
550
GetCurrentDisplay(void)551 EGLDisplay EGLAPIENTRY GetCurrentDisplay(void)
552 {
553 EVENT("()");
554 Thread *thread = GetCurrentThread();
555
556 thread->setError(NoError());
557 if (thread->getContext() != nullptr)
558 {
559 return thread->getContext()->getCurrentDisplay();
560 }
561 return EGL_NO_DISPLAY;
562 }
563
QueryContext(EGLDisplay dpy,EGLContext ctx,EGLint attribute,EGLint * value)564 EGLBoolean EGLAPIENTRY QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
565 {
566 EVENT(
567 "(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value "
568 "= 0x%0.8p)",
569 dpy, ctx, attribute, value);
570 Thread *thread = GetCurrentThread();
571
572 Display *display = static_cast<Display *>(dpy);
573 gl::Context *context = static_cast<gl::Context *>(ctx);
574
575 Error error = ValidateQueryContext(display, context, attribute, value);
576 if (error.isError())
577 {
578 thread->setError(error);
579 return EGL_FALSE;
580 }
581
582 QueryContextAttrib(context, attribute, value);
583
584 thread->setError(NoError());
585 return EGL_TRUE;
586 }
587
WaitGL(void)588 EGLBoolean EGLAPIENTRY WaitGL(void)
589 {
590 EVENT("()");
591 Thread *thread = GetCurrentThread();
592
593 Display *display = thread->getCurrentDisplay();
594
595 Error error = ValidateDisplay(display);
596 if (error.isError())
597 {
598 thread->setError(error);
599 return EGL_FALSE;
600 }
601
602 // eglWaitGL like calling eglWaitClient with the OpenGL ES API bound. Since we only implement
603 // OpenGL ES we can do the call directly.
604 error = display->waitClient(thread->getContext());
605 if (error.isError())
606 {
607 thread->setError(error);
608 return EGL_FALSE;
609 }
610
611 thread->setError(NoError());
612 return EGL_TRUE;
613 }
614
WaitNative(EGLint engine)615 EGLBoolean EGLAPIENTRY WaitNative(EGLint engine)
616 {
617 EVENT("(EGLint engine = %d)", engine);
618 Thread *thread = GetCurrentThread();
619
620 Display *display = thread->getCurrentDisplay();
621
622 Error error = ValidateDisplay(display);
623 if (error.isError())
624 {
625 thread->setError(error);
626 return EGL_FALSE;
627 }
628
629 if (engine != EGL_CORE_NATIVE_ENGINE)
630 {
631 thread->setError(EglBadParameter() << "the 'engine' parameter has an unrecognized value");
632 }
633
634 error = display->waitNative(thread->getContext(), engine);
635 if (error.isError())
636 {
637 thread->setError(error);
638 return EGL_FALSE;
639 }
640
641 thread->setError(NoError());
642 return EGL_TRUE;
643 }
644
SwapBuffers(EGLDisplay dpy,EGLSurface surface)645 EGLBoolean EGLAPIENTRY SwapBuffers(EGLDisplay dpy, EGLSurface surface)
646 {
647 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface);
648 Thread *thread = GetCurrentThread();
649
650 Display *display = static_cast<Display *>(dpy);
651 Surface *eglSurface = (Surface *)surface;
652
653 Error error = ValidateSurface(display, eglSurface);
654 if (error.isError())
655 {
656 thread->setError(error);
657 return EGL_FALSE;
658 }
659
660 if (display->testDeviceLost())
661 {
662 thread->setError(EglContextLost());
663 return EGL_FALSE;
664 }
665
666 if (surface == EGL_NO_SURFACE)
667 {
668 thread->setError(EglBadSurface());
669 return EGL_FALSE;
670 }
671
672 if (!thread->getContext() || thread->getCurrentDrawSurface() != eglSurface)
673 {
674 thread->setError(EglBadSurface());
675 return EGL_FALSE;
676 }
677
678 error = eglSurface->swap(thread->getContext());
679 if (error.isError())
680 {
681 thread->setError(error);
682 return EGL_FALSE;
683 }
684
685 thread->setError(NoError());
686 return EGL_TRUE;
687 }
688
CopyBuffers(EGLDisplay dpy,EGLSurface surface,EGLNativePixmapType target)689 EGLBoolean EGLAPIENTRY CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
690 {
691 EVENT(
692 "(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLNativePixmapType target = "
693 "0x%0.8p)",
694 dpy, surface, target);
695 Thread *thread = GetCurrentThread();
696
697 Display *display = static_cast<Display *>(dpy);
698 Surface *eglSurface = static_cast<Surface *>(surface);
699
700 Error error = ValidateSurface(display, eglSurface);
701 if (error.isError())
702 {
703 thread->setError(error);
704 return EGL_FALSE;
705 }
706
707 if (display->testDeviceLost())
708 {
709 thread->setError(EglContextLost());
710 return EGL_FALSE;
711 }
712
713 UNIMPLEMENTED(); // FIXME
714
715 thread->setError(NoError());
716 return 0;
717 }
718
719 // EGL 1.1
BindTexImage(EGLDisplay dpy,EGLSurface surface,EGLint buffer)720 EGLBoolean EGLAPIENTRY BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
721 {
722 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy,
723 surface, buffer);
724 Thread *thread = GetCurrentThread();
725
726 Display *display = static_cast<Display *>(dpy);
727 Surface *eglSurface = static_cast<Surface *>(surface);
728
729 Error error = ValidateSurface(display, eglSurface);
730 if (error.isError())
731 {
732 thread->setError(error);
733 return EGL_FALSE;
734 }
735
736 if (buffer != EGL_BACK_BUFFER)
737 {
738 thread->setError(EglBadParameter());
739 return EGL_FALSE;
740 }
741
742 if (surface == EGL_NO_SURFACE || eglSurface->getType() == EGL_WINDOW_BIT)
743 {
744 thread->setError(EglBadSurface());
745 return EGL_FALSE;
746 }
747
748 if (eglSurface->getBoundTexture())
749 {
750 thread->setError(EglBadAccess());
751 return EGL_FALSE;
752 }
753
754 if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
755 {
756 thread->setError(EglBadMatch());
757 return EGL_FALSE;
758 }
759
760 gl::Context *context = thread->getContext();
761 if (context)
762 {
763 gl::Texture *textureObject = context->getTargetTexture(GL_TEXTURE_2D);
764 ASSERT(textureObject != nullptr);
765
766 if (textureObject->getImmutableFormat())
767 {
768 thread->setError(EglBadMatch());
769 return EGL_FALSE;
770 }
771
772 error = eglSurface->bindTexImage(context, textureObject, buffer);
773 if (error.isError())
774 {
775 thread->setError(error);
776 return EGL_FALSE;
777 }
778 }
779
780 thread->setError(NoError());
781 return EGL_TRUE;
782 }
783
SurfaceAttrib(EGLDisplay dpy,EGLSurface surface,EGLint attribute,EGLint value)784 EGLBoolean EGLAPIENTRY SurfaceAttrib(EGLDisplay dpy,
785 EGLSurface surface,
786 EGLint attribute,
787 EGLint value)
788 {
789 EVENT(
790 "(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint "
791 "value = %d)",
792 dpy, surface, attribute, value);
793 Thread *thread = GetCurrentThread();
794
795 Display *display = static_cast<Display *>(dpy);
796 Surface *eglSurface = static_cast<Surface *>(surface);
797
798 Error error = ValidateSurfaceAttrib(display, eglSurface, attribute, value);
799 if (error.isError())
800 {
801 thread->setError(error);
802 return EGL_FALSE;
803 }
804
805 SetSurfaceAttrib(eglSurface, attribute, value);
806
807 thread->setError(NoError());
808 return EGL_TRUE;
809 }
810
ReleaseTexImage(EGLDisplay dpy,EGLSurface surface,EGLint buffer)811 EGLBoolean EGLAPIENTRY ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
812 {
813 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy,
814 surface, buffer);
815 Thread *thread = GetCurrentThread();
816
817 Display *display = static_cast<Display *>(dpy);
818 Surface *eglSurface = static_cast<Surface *>(surface);
819
820 Error error = ValidateSurface(display, eglSurface);
821 if (error.isError())
822 {
823 thread->setError(error);
824 return EGL_FALSE;
825 }
826
827 if (buffer != EGL_BACK_BUFFER)
828 {
829 thread->setError(EglBadParameter());
830 return EGL_FALSE;
831 }
832
833 if (surface == EGL_NO_SURFACE || eglSurface->getType() == EGL_WINDOW_BIT)
834 {
835 thread->setError(EglBadSurface());
836 return EGL_FALSE;
837 }
838
839 if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
840 {
841 thread->setError(EglBadMatch());
842 return EGL_FALSE;
843 }
844
845 gl::Texture *texture = eglSurface->getBoundTexture();
846
847 if (texture)
848 {
849 error = eglSurface->releaseTexImage(thread->getContext(), buffer);
850 if (error.isError())
851 {
852 thread->setError(error);
853 return EGL_FALSE;
854 }
855 }
856
857 thread->setError(NoError());
858 return EGL_TRUE;
859 }
860
SwapInterval(EGLDisplay dpy,EGLint interval)861 EGLBoolean EGLAPIENTRY SwapInterval(EGLDisplay dpy, EGLint interval)
862 {
863 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint interval = %d)", dpy, interval);
864 Thread *thread = GetCurrentThread();
865
866 Display *display = static_cast<Display *>(dpy);
867
868 Error error = ValidateDisplay(display);
869 if (error.isError())
870 {
871 thread->setError(error);
872 return EGL_FALSE;
873 }
874
875 Surface *draw_surface = static_cast<Surface *>(thread->getCurrentDrawSurface());
876
877 if (draw_surface == nullptr)
878 {
879 thread->setError(EglBadSurface());
880 return EGL_FALSE;
881 }
882
883 const egl::Config *surfaceConfig = draw_surface->getConfig();
884 EGLint clampedInterval = std::min(std::max(interval, surfaceConfig->minSwapInterval),
885 surfaceConfig->maxSwapInterval);
886
887 draw_surface->setSwapInterval(clampedInterval);
888
889 thread->setError(NoError());
890 return EGL_TRUE;
891 }
892
893 // EGL 1.2
BindAPI(EGLenum api)894 EGLBoolean EGLAPIENTRY BindAPI(EGLenum api)
895 {
896 EVENT("(EGLenum api = 0x%X)", api);
897 Thread *thread = GetCurrentThread();
898
899 switch (api)
900 {
901 case EGL_OPENGL_API:
902 case EGL_OPENVG_API:
903 thread->setError(EglBadParameter());
904 return EGL_FALSE; // Not supported by this implementation
905 case EGL_OPENGL_ES_API:
906 break;
907 default:
908 thread->setError(EglBadParameter());
909 return EGL_FALSE;
910 }
911
912 thread->setAPI(api);
913
914 thread->setError(NoError());
915 return EGL_TRUE;
916 }
917
QueryAPI(void)918 EGLenum EGLAPIENTRY QueryAPI(void)
919 {
920 EVENT("()");
921 Thread *thread = GetCurrentThread();
922
923 EGLenum API = thread->getAPI();
924
925 thread->setError(NoError());
926 return API;
927 }
928
CreatePbufferFromClientBuffer(EGLDisplay dpy,EGLenum buftype,EGLClientBuffer buffer,EGLConfig config,const EGLint * attrib_list)929 EGLSurface EGLAPIENTRY CreatePbufferFromClientBuffer(EGLDisplay dpy,
930 EGLenum buftype,
931 EGLClientBuffer buffer,
932 EGLConfig config,
933 const EGLint *attrib_list)
934 {
935 EVENT(
936 "(EGLDisplay dpy = 0x%0.8p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = 0x%0.8p, "
937 "EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)",
938 dpy, buftype, buffer, config, attrib_list);
939 Thread *thread = GetCurrentThread();
940
941 Display *display = static_cast<Display *>(dpy);
942 Config *configuration = static_cast<Config *>(config);
943 AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list);
944
945 Error error =
946 ValidateCreatePbufferFromClientBuffer(display, buftype, buffer, configuration, attributes);
947 if (error.isError())
948 {
949 thread->setError(error);
950 return EGL_NO_SURFACE;
951 }
952
953 egl::Surface *surface = nullptr;
954 error = display->createPbufferFromClientBuffer(configuration, buftype, buffer, attributes,
955 &surface);
956 if (error.isError())
957 {
958 thread->setError(error);
959 return EGL_NO_SURFACE;
960 }
961
962 return static_cast<EGLSurface>(surface);
963 }
964
ReleaseThread(void)965 EGLBoolean EGLAPIENTRY ReleaseThread(void)
966 {
967 EVENT("()");
968 Thread *thread = GetCurrentThread();
969
970 MakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE);
971
972 thread->setError(NoError());
973 return EGL_TRUE;
974 }
975
WaitClient(void)976 EGLBoolean EGLAPIENTRY WaitClient(void)
977 {
978 EVENT("()");
979 Thread *thread = GetCurrentThread();
980
981 Display *display = thread->getCurrentDisplay();
982
983 Error error = ValidateDisplay(display);
984 if (error.isError())
985 {
986 thread->setError(error);
987 return EGL_FALSE;
988 }
989
990 error = display->waitClient(thread->getContext());
991 if (error.isError())
992 {
993 thread->setError(error);
994 return EGL_FALSE;
995 }
996
997 thread->setError(NoError());
998 return EGL_TRUE;
999 }
1000
1001 // EGL 1.4
GetCurrentContext(void)1002 EGLContext EGLAPIENTRY GetCurrentContext(void)
1003 {
1004 EVENT("()");
1005 Thread *thread = GetCurrentThread();
1006
1007 gl::Context *context = thread->getContext();
1008
1009 thread->setError(NoError());
1010 return static_cast<EGLContext>(context);
1011 }
1012
1013 // EGL 1.5
CreateSync(EGLDisplay dpy,EGLenum type,const EGLAttrib * attrib_list)1014 EGLSync EGLAPIENTRY CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list)
1015 {
1016 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum type = 0x%X, const EGLint* attrib_list = 0x%0.8p)",
1017 dpy, type, attrib_list);
1018 Thread *thread = GetCurrentThread();
1019
1020 UNIMPLEMENTED();
1021 thread->setError(EglBadDisplay() << "eglCreateSync unimplemented.");
1022 return EGL_NO_SYNC;
1023 }
1024
DestroySync(EGLDisplay dpy,EGLSync sync)1025 EGLBoolean EGLAPIENTRY DestroySync(EGLDisplay dpy, EGLSync sync)
1026 {
1027 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p)", dpy, sync);
1028 Thread *thread = GetCurrentThread();
1029
1030 UNIMPLEMENTED();
1031 thread->setError(EglBadDisplay() << "eglDestroySync unimplemented.");
1032 return EGL_FALSE;
1033 }
1034
ClientWaitSync(EGLDisplay dpy,EGLSync sync,EGLint flags,EGLTime timeout)1035 EGLint EGLAPIENTRY ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout)
1036 {
1037 EVENT(
1038 "(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint flags = 0x%X, EGLTime timeout = "
1039 "%d)",
1040 dpy, sync, flags, timeout);
1041 Thread *thread = GetCurrentThread();
1042
1043 UNIMPLEMENTED();
1044 thread->setError(EglBadDisplay() << "eglClientWaitSync unimplemented.");
1045 return 0;
1046 }
1047
GetSyncAttrib(EGLDisplay dpy,EGLSync sync,EGLint attribute,EGLAttrib * value)1048 EGLBoolean EGLAPIENTRY GetSyncAttrib(EGLDisplay dpy,
1049 EGLSync sync,
1050 EGLint attribute,
1051 EGLAttrib *value)
1052 {
1053 EVENT(
1054 "(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint attribute = 0x%X, EGLAttrib "
1055 "*value = 0x%0.8p)",
1056 dpy, sync, attribute, value);
1057 Thread *thread = GetCurrentThread();
1058
1059 UNIMPLEMENTED();
1060 thread->setError(EglBadDisplay() << "eglSyncAttrib unimplemented.");
1061 return EGL_FALSE;
1062 }
1063
CreateImage(EGLDisplay dpy,EGLContext ctx,EGLenum target,EGLClientBuffer buffer,const EGLAttrib * attrib_list)1064 EGLImage EGLAPIENTRY CreateImage(EGLDisplay dpy,
1065 EGLContext ctx,
1066 EGLenum target,
1067 EGLClientBuffer buffer,
1068 const EGLAttrib *attrib_list)
1069 {
1070 EVENT(
1071 "(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLenum target = 0x%X, "
1072 "EGLClientBuffer buffer = 0x%0.8p, const EGLAttrib *attrib_list = 0x%0.8p)",
1073 dpy, ctx, target, buffer, attrib_list);
1074 Thread *thread = GetCurrentThread();
1075
1076 UNIMPLEMENTED();
1077 thread->setError(EglBadDisplay() << "eglCreateImage unimplemented.");
1078 return EGL_NO_IMAGE;
1079 }
1080
DestroyImage(EGLDisplay dpy,EGLImage image)1081 EGLBoolean EGLAPIENTRY DestroyImage(EGLDisplay dpy, EGLImage image)
1082 {
1083 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLImage image = 0x%0.8p)", dpy, image);
1084 Thread *thread = GetCurrentThread();
1085
1086 UNIMPLEMENTED();
1087 thread->setError(EglBadDisplay() << "eglDestroyImage unimplemented.");
1088 return EGL_FALSE;
1089 }
1090
GetPlatformDisplay(EGLenum platform,void * native_display,const EGLAttrib * attrib_list)1091 EGLDisplay EGLAPIENTRY GetPlatformDisplay(EGLenum platform,
1092 void *native_display,
1093 const EGLAttrib *attrib_list)
1094 {
1095 EVENT(
1096 "(EGLenum platform = %d, void* native_display = 0x%0.8p, const EGLint* attrib_list = "
1097 "0x%0.8p)",
1098 platform, native_display, attrib_list);
1099 Thread *thread = GetCurrentThread();
1100
1101 Error err = ValidateGetPlatformDisplay(platform, native_display, attrib_list);
1102 thread->setError(err);
1103 if (err.isError())
1104 {
1105 return EGL_NO_DISPLAY;
1106 }
1107
1108 const auto &attribMap = AttributeMap::CreateFromAttribArray(attrib_list);
1109 if (platform == EGL_PLATFORM_ANGLE_ANGLE)
1110 {
1111 return Display::GetDisplayFromNativeDisplay(
1112 gl::bitCast<EGLNativeDisplayType>(native_display), attribMap);
1113 }
1114 else if (platform == EGL_PLATFORM_DEVICE_EXT)
1115 {
1116 Device *eglDevice = reinterpret_cast<Device *>(native_display);
1117 return Display::GetDisplayFromDevice(eglDevice, attribMap);
1118 }
1119 else
1120 {
1121 UNREACHABLE();
1122 return EGL_NO_DISPLAY;
1123 }
1124 }
1125
CreatePlatformWindowSurface(EGLDisplay dpy,EGLConfig config,void * native_window,const EGLAttrib * attrib_list)1126 EGLSurface EGLAPIENTRY CreatePlatformWindowSurface(EGLDisplay dpy,
1127 EGLConfig config,
1128 void *native_window,
1129 const EGLAttrib *attrib_list)
1130 {
1131 EVENT(
1132 "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, void* native_window = 0x%0.8p, "
1133 "const EGLint* attrib_list = 0x%0.8p)",
1134 dpy, config, native_window, attrib_list);
1135 Thread *thread = GetCurrentThread();
1136
1137 UNIMPLEMENTED();
1138 thread->setError(EglBadDisplay() << "eglCreatePlatformWindowSurface unimplemented.");
1139 return EGL_NO_SURFACE;
1140 }
1141
CreatePlatformPixmapSurface(EGLDisplay dpy,EGLConfig config,void * native_pixmap,const EGLAttrib * attrib_list)1142 EGLSurface EGLAPIENTRY CreatePlatformPixmapSurface(EGLDisplay dpy,
1143 EGLConfig config,
1144 void *native_pixmap,
1145 const EGLAttrib *attrib_list)
1146 {
1147 EVENT(
1148 "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, void* native_pixmap = 0x%0.8p, "
1149 "const EGLint* attrib_list = 0x%0.8p)",
1150 dpy, config, native_pixmap, attrib_list);
1151 Thread *thread = GetCurrentThread();
1152
1153 UNIMPLEMENTED();
1154 thread->setError(EglBadDisplay() << "eglCreatePlatformPixmapSurface unimplemented.");
1155 return EGL_NO_SURFACE;
1156 }
1157
WaitSync(EGLDisplay dpy,EGLSync sync,EGLint flags)1158 EGLBoolean EGLAPIENTRY WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags)
1159 {
1160 EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint flags = 0x%X)", dpy, sync,
1161 flags);
1162 Thread *thread = GetCurrentThread();
1163
1164 UNIMPLEMENTED();
1165 thread->setError(EglBadDisplay() << "eglWaitSync unimplemented.");
1166 return EGL_FALSE;
1167 }
1168
GetProcAddress(const char * procname)1169 __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *procname)
1170 {
1171 EVENT("(const char *procname = \"%s\")", procname);
1172 Thread *thread = GetCurrentThread();
1173
1174 ProcEntry *entry =
1175 std::lower_bound(&g_procTable[0], &g_procTable[g_numProcs], procname, CompareProc);
1176
1177 thread->setError(NoError());
1178
1179 if (entry == &g_procTable[g_numProcs] || strcmp(entry->first, procname) != 0)
1180 {
1181 return nullptr;
1182 }
1183
1184 return entry->second;
1185 }
1186 }
1187