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