• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 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 // egl_stubs.cpp: Stubs for EGL entry points.
7 //
8 
9 #include "libGLESv2/egl_stubs_autogen.h"
10 
11 #include "common/angle_version_info.h"
12 #include "libANGLE/Context.h"
13 #include "libANGLE/Display.h"
14 #include "libANGLE/EGLSync.h"
15 #include "libANGLE/Surface.h"
16 #include "libANGLE/Thread.h"
17 #include "libANGLE/queryutils.h"
18 #include "libANGLE/validationEGL.h"
19 #include "libGLESv2/global_state.h"
20 #include "libGLESv2/proc_table_egl.h"
21 
22 namespace egl
23 {
24 namespace
25 {
26 
CompareProc(const ProcEntry & a,const char * b)27 bool CompareProc(const ProcEntry &a, const char *b)
28 {
29     return strcmp(a.first, b) < 0;
30 }
31 
ClipConfigs(const std::vector<const Config * > & filteredConfigs,EGLConfig * outputConfigs,EGLint configSize,EGLint * numConfigs)32 void ClipConfigs(const std::vector<const Config *> &filteredConfigs,
33                  EGLConfig *outputConfigs,
34                  EGLint configSize,
35                  EGLint *numConfigs)
36 {
37     EGLint resultSize = static_cast<EGLint>(filteredConfigs.size());
38     if (outputConfigs)
39     {
40         resultSize = std::max(std::min(resultSize, configSize), 0);
41         for (EGLint i = 0; i < resultSize; i++)
42         {
43             outputConfigs[i] = const_cast<Config *>(filteredConfigs[i]);
44         }
45     }
46     *numConfigs = resultSize;
47 }
48 }  // anonymous namespace
49 
BindAPI(Thread * thread,EGLenum api)50 EGLBoolean BindAPI(Thread *thread, EGLenum api)
51 {
52     thread->setAPI(api);
53 
54     thread->setSuccess();
55     return EGL_TRUE;
56 }
57 
BindTexImage(Thread * thread,Display * display,egl::SurfaceID surfaceID,EGLint buffer)58 EGLBoolean BindTexImage(Thread *thread, Display *display, egl::SurfaceID surfaceID, EGLint buffer)
59 {
60     Surface *eglSurface = display->getSurface(surfaceID);
61 
62     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglBindTexImage",
63                          GetDisplayIfValid(display), EGL_FALSE);
64 
65     gl::Context *context = thread->getContext();
66     if (context && !context->isContextLost())
67     {
68         gl::TextureType type =
69             egl_gl::EGLTextureTargetToTextureType(eglSurface->getTextureTarget());
70         gl::Texture *textureObject = context->getTextureByType(type);
71         ANGLE_EGL_TRY_RETURN(thread, eglSurface->bindTexImage(context, textureObject, buffer),
72                              "eglBindTexImage", GetSurfaceIfValid(display, surfaceID), EGL_FALSE);
73     }
74 
75     thread->setSuccess();
76     return EGL_TRUE;
77 }
78 
ChooseConfig(Thread * thread,Display * display,const AttributeMap & attribMap,EGLConfig * configs,EGLint config_size,EGLint * num_config)79 EGLBoolean ChooseConfig(Thread *thread,
80                         Display *display,
81                         const AttributeMap &attribMap,
82                         EGLConfig *configs,
83                         EGLint config_size,
84                         EGLint *num_config)
85 {
86     ClipConfigs(display->chooseConfig(attribMap), configs, config_size, num_config);
87 
88     thread->setSuccess();
89     return EGL_TRUE;
90 }
91 
ClientWaitSync(Thread * thread,Display * display,SyncID syncID,EGLint flags,EGLTime timeout)92 EGLint ClientWaitSync(Thread *thread,
93                       Display *display,
94                       SyncID syncID,
95                       EGLint flags,
96                       EGLTime timeout)
97 {
98     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglClientWaitSync",
99                          GetDisplayIfValid(display), EGL_FALSE);
100     gl::Context *currentContext = thread->getContext();
101     EGLint syncStatus           = EGL_FALSE;
102     Sync *syncObject            = display->getSync(syncID);
103     ANGLE_EGL_TRY_RETURN(
104         thread, syncObject->clientWait(display, currentContext, flags, timeout, &syncStatus),
105         "eglClientWaitSync", GetSyncIfValid(display, syncID), EGL_FALSE);
106 
107     thread->setSuccess();
108     return syncStatus;
109 }
110 
CopyBuffers(Thread * thread,Display * display,egl::SurfaceID surfaceID,EGLNativePixmapType target)111 EGLBoolean CopyBuffers(Thread *thread,
112                        Display *display,
113                        egl::SurfaceID surfaceID,
114                        EGLNativePixmapType target)
115 {
116     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCopyBuffers",
117                          GetDisplayIfValid(display), EGL_FALSE);
118     UNIMPLEMENTED();  // FIXME
119 
120     thread->setSuccess();
121     return 0;
122 }
123 
CreateContext(Thread * thread,Display * display,Config * configuration,gl::ContextID sharedContextID,const AttributeMap & attributes)124 EGLContext CreateContext(Thread *thread,
125                          Display *display,
126                          Config *configuration,
127                          gl::ContextID sharedContextID,
128                          const AttributeMap &attributes)
129 {
130     gl::Context *sharedGLContext = display->getContext(sharedContextID);
131     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateContext",
132                          GetDisplayIfValid(display), EGL_NO_CONTEXT);
133     gl::Context *context = nullptr;
134     ANGLE_EGL_TRY_RETURN(thread,
135                          display->createContext(configuration, sharedGLContext, thread->getAPI(),
136                                                 attributes, &context),
137                          "eglCreateContext", GetDisplayIfValid(display), EGL_NO_CONTEXT);
138 
139     thread->setSuccess();
140     return reinterpret_cast<EGLContext>(static_cast<uintptr_t>(context->id().value));
141 }
142 
CreateImage(Thread * thread,Display * display,gl::ContextID contextID,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attributes)143 EGLImage CreateImage(Thread *thread,
144                      Display *display,
145                      gl::ContextID contextID,
146                      EGLenum target,
147                      EGLClientBuffer buffer,
148                      const AttributeMap &attributes)
149 {
150     gl::Context *context = display->getContext(contextID);
151 
152     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateImage",
153                          GetDisplayIfValid(display), EGL_FALSE);
154 
155     Image *image = nullptr;
156     Error error  = display->createImage(context, target, buffer, attributes, &image);
157     if (error.isError())
158     {
159         thread->setError(error, "eglCreateImage", GetDisplayIfValid(display));
160         return EGL_NO_IMAGE;
161     }
162 
163     thread->setSuccess();
164     return reinterpret_cast<EGLImage>(static_cast<uintptr_t>(image->id().value));
165 }
166 
CreatePbufferFromClientBuffer(Thread * thread,Display * display,EGLenum buftype,EGLClientBuffer buffer,Config * configuration,const AttributeMap & attributes)167 EGLSurface CreatePbufferFromClientBuffer(Thread *thread,
168                                          Display *display,
169                                          EGLenum buftype,
170                                          EGLClientBuffer buffer,
171                                          Config *configuration,
172                                          const AttributeMap &attributes)
173 {
174     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePbufferFromClientBuffer",
175                          GetDisplayIfValid(display), EGL_NO_SURFACE);
176     Surface *surface = nullptr;
177     ANGLE_EGL_TRY_RETURN(thread,
178                          display->createPbufferFromClientBuffer(configuration, buftype, buffer,
179                                                                 attributes, &surface),
180                          "eglCreatePbufferFromClientBuffer", GetDisplayIfValid(display),
181                          EGL_NO_SURFACE);
182 
183     return reinterpret_cast<EGLSurface>(static_cast<uintptr_t>(surface->id().value));
184 }
185 
CreatePbufferSurface(Thread * thread,Display * display,Config * configuration,const AttributeMap & attributes)186 EGLSurface CreatePbufferSurface(Thread *thread,
187                                 Display *display,
188                                 Config *configuration,
189                                 const AttributeMap &attributes)
190 {
191     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePbufferSurface",
192                          GetDisplayIfValid(display), EGL_NO_SURFACE);
193     Surface *surface = nullptr;
194     ANGLE_EGL_TRY_RETURN(thread, display->createPbufferSurface(configuration, attributes, &surface),
195                          "eglCreatePbufferSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
196 
197     return reinterpret_cast<EGLSurface>(static_cast<uintptr_t>(surface->id().value));
198 }
199 
CreatePixmapSurface(Thread * thread,Display * display,Config * configuration,EGLNativePixmapType pixmap,const AttributeMap & attributes)200 EGLSurface CreatePixmapSurface(Thread *thread,
201                                Display *display,
202                                Config *configuration,
203                                EGLNativePixmapType pixmap,
204                                const AttributeMap &attributes)
205 {
206     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePixmapSurface",
207                          GetDisplayIfValid(display), EGL_NO_SURFACE);
208     Surface *surface = nullptr;
209     ANGLE_EGL_TRY_RETURN(thread,
210                          display->createPixmapSurface(configuration, pixmap, attributes, &surface),
211                          "eglCreatePixmapSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
212 
213     thread->setSuccess();
214     return reinterpret_cast<EGLSurface>(static_cast<uintptr_t>(surface->id().value));
215 }
216 
CreatePlatformPixmapSurface(Thread * thread,Display * display,Config * configuration,void * pixmap,const AttributeMap & attributes)217 EGLSurface CreatePlatformPixmapSurface(Thread *thread,
218                                        Display *display,
219                                        Config *configuration,
220                                        void *pixmap,
221                                        const AttributeMap &attributes)
222 {
223     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePlatformPixmapSurface",
224                          GetDisplayIfValid(display), EGL_NO_SURFACE);
225     Surface *surface                 = nullptr;
226     EGLNativePixmapType nativePixmap = reinterpret_cast<EGLNativePixmapType>(pixmap);
227     ANGLE_EGL_TRY_RETURN(
228         thread, display->createPixmapSurface(configuration, nativePixmap, attributes, &surface),
229         "eglCreatePlatformPixmapSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
230 
231     thread->setSuccess();
232     return reinterpret_cast<EGLSurface>(static_cast<uintptr_t>(surface->id().value));
233 }
234 
CreatePlatformWindowSurface(Thread * thread,Display * display,Config * configuration,void * win,const AttributeMap & attributes)235 EGLSurface CreatePlatformWindowSurface(Thread *thread,
236                                        Display *display,
237                                        Config *configuration,
238                                        void *win,
239                                        const AttributeMap &attributes)
240 {
241     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePlatformWindowSurface",
242                          GetDisplayIfValid(display), EGL_NO_SURFACE);
243     Surface *surface                 = nullptr;
244     EGLNativeWindowType nativeWindow = reinterpret_cast<EGLNativeWindowType>(win);
245     ANGLE_EGL_TRY_RETURN(
246         thread, display->createWindowSurface(configuration, nativeWindow, attributes, &surface),
247         "eglCreatePlatformWindowSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
248 
249     return reinterpret_cast<EGLSurface>(static_cast<uintptr_t>(surface->id().value));
250 }
251 
CreateSync(Thread * thread,Display * display,EGLenum type,const AttributeMap & attributes)252 EGLSync CreateSync(Thread *thread, Display *display, EGLenum type, const AttributeMap &attributes)
253 {
254     gl::Context *currentContext = thread->getContext();
255 
256     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateSync",
257                          GetDisplayIfValid(display), EGL_FALSE);
258     Sync *syncObject = nullptr;
259     ANGLE_EGL_TRY_RETURN(thread, display->createSync(currentContext, type, attributes, &syncObject),
260                          "eglCreateSync", GetDisplayIfValid(display), EGL_NO_SYNC);
261 
262     thread->setSuccess();
263     return reinterpret_cast<EGLSync>(static_cast<uintptr_t>(syncObject->id().value));
264 }
265 
CreateWindowSurface(Thread * thread,Display * display,Config * configuration,EGLNativeWindowType win,const AttributeMap & attributes)266 EGLSurface CreateWindowSurface(Thread *thread,
267                                Display *display,
268                                Config *configuration,
269                                EGLNativeWindowType win,
270                                const AttributeMap &attributes)
271 {
272     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateWindowSurface",
273                          GetDisplayIfValid(display), EGL_NO_SURFACE);
274 
275     Surface *surface = nullptr;
276     ANGLE_EGL_TRY_RETURN(thread,
277                          display->createWindowSurface(configuration, win, attributes, &surface),
278                          "eglCreateWindowSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
279 
280     return reinterpret_cast<EGLSurface>(static_cast<uintptr_t>(surface->id().value));
281 }
282 
DestroyContext(Thread * thread,Display * display,gl::ContextID contextID)283 EGLBoolean DestroyContext(Thread *thread, Display *display, gl::ContextID contextID)
284 {
285     gl::Context *context = display->getContext(contextID);
286 
287     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroyContext",
288                          GetDisplayIfValid(display), EGL_FALSE);
289 
290     ScopedSyncCurrentContextFromThread scopedSyncCurrent(thread);
291 
292     ANGLE_EGL_TRY_RETURN(thread, display->destroyContext(thread, context), "eglDestroyContext",
293                          GetContextIfValid(display, contextID), EGL_FALSE);
294     thread->setSuccess();
295     return EGL_TRUE;
296 }
297 
DestroyImage(Thread * thread,Display * display,ImageID imageID)298 EGLBoolean DestroyImage(Thread *thread, Display *display, ImageID imageID)
299 {
300     Image *img = display->getImage(imageID);
301     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroyImage",
302                          GetDisplayIfValid(display), EGL_FALSE);
303     display->destroyImage(img);
304 
305     thread->setSuccess();
306     return EGL_TRUE;
307 }
308 
DestroySurface(Thread * thread,Display * display,egl::SurfaceID surfaceID)309 EGLBoolean DestroySurface(Thread *thread, Display *display, egl::SurfaceID surfaceID)
310 {
311     Surface *eglSurface = display->getSurface(surfaceID);
312 
313     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroySurface",
314                          GetDisplayIfValid(display), EGL_FALSE);
315 
316     ANGLE_EGL_TRY_RETURN(thread, display->destroySurface(eglSurface), "eglDestroySurface",
317                          GetSurfaceIfValid(display, surfaceID), EGL_FALSE);
318 
319     thread->setSuccess();
320     return EGL_TRUE;
321 }
322 
DestroySync(Thread * thread,Display * display,SyncID syncID)323 EGLBoolean DestroySync(Thread *thread, Display *display, SyncID syncID)
324 {
325     Sync *sync = display->getSync(syncID);
326     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroySync",
327                          GetDisplayIfValid(display), EGL_FALSE);
328     display->destroySync(sync);
329 
330     thread->setSuccess();
331     return EGL_TRUE;
332 }
333 
GetConfigAttrib(Thread * thread,Display * display,Config * configuration,EGLint attribute,EGLint * value)334 EGLBoolean GetConfigAttrib(Thread *thread,
335                            Display *display,
336                            Config *configuration,
337                            EGLint attribute,
338                            EGLint *value)
339 {
340     QueryConfigAttrib(configuration, attribute, value);
341 
342     thread->setSuccess();
343     return EGL_TRUE;
344 }
345 
GetConfigs(Thread * thread,Display * display,EGLConfig * configs,EGLint config_size,EGLint * num_config)346 EGLBoolean GetConfigs(Thread *thread,
347                       Display *display,
348                       EGLConfig *configs,
349                       EGLint config_size,
350                       EGLint *num_config)
351 {
352     ClipConfigs(display->getConfigs(AttributeMap()), configs, config_size, num_config);
353 
354     thread->setSuccess();
355     return EGL_TRUE;
356 }
357 
GetCurrentContext(Thread * thread)358 EGLContext GetCurrentContext(Thread *thread)
359 {
360     gl::Context *context = thread->getContext();
361 
362     thread->setSuccess();
363     return reinterpret_cast<EGLContext>(context ? static_cast<uintptr_t>(context->id().value) : 0);
364 }
365 
GetCurrentDisplay(Thread * thread)366 EGLDisplay GetCurrentDisplay(Thread *thread)
367 {
368     thread->setSuccess();
369     if (thread->getContext() != nullptr)
370     {
371         return thread->getContext()->getDisplay();
372     }
373     return EGL_NO_DISPLAY;
374 }
375 
GetCurrentSurface(Thread * thread,EGLint readdraw)376 EGLSurface GetCurrentSurface(Thread *thread, EGLint readdraw)
377 {
378     Surface *surface =
379         (readdraw == EGL_READ) ? thread->getCurrentReadSurface() : thread->getCurrentDrawSurface();
380     thread->setSuccess();
381     if (surface)
382     {
383         return reinterpret_cast<EGLSurface>(static_cast<uintptr_t>(surface->id().value));
384     }
385     else
386     {
387         return EGL_NO_SURFACE;
388     }
389 }
390 
GetDisplay(Thread * thread,EGLNativeDisplayType display_id)391 EGLDisplay GetDisplay(Thread *thread, EGLNativeDisplayType display_id)
392 {
393     return Display::GetDisplayFromNativeDisplay(EGL_PLATFORM_ANGLE_ANGLE, display_id,
394                                                 AttributeMap());
395 }
396 
GetError(Thread * thread)397 EGLint GetError(Thread *thread)
398 {
399     EGLint error = thread->getError();
400     thread->setSuccess();
401     return error;
402 }
403 
GetPlatformDisplay(Thread * thread,EGLenum platform,void * native_display,const AttributeMap & attribMap)404 EGLDisplay GetPlatformDisplay(Thread *thread,
405                               EGLenum platform,
406                               void *native_display,
407                               const AttributeMap &attribMap)
408 {
409     switch (platform)
410     {
411         case EGL_PLATFORM_ANGLE_ANGLE:
412         case EGL_PLATFORM_GBM_KHR:
413         case EGL_PLATFORM_WAYLAND_EXT:
414         {
415             return Display::GetDisplayFromNativeDisplay(
416                 platform, gl::bitCast<EGLNativeDisplayType>(native_display), attribMap);
417         }
418         case EGL_PLATFORM_DEVICE_EXT:
419         {
420             Device *eglDevice = static_cast<Device *>(native_display);
421             return Display::GetDisplayFromDevice(eglDevice, attribMap);
422         }
423         default:
424         {
425             UNREACHABLE();
426             return EGL_NO_DISPLAY;
427         }
428     }
429 }
430 
GetProcAddress(Thread * thread,const char * procname)431 __eglMustCastToProperFunctionPointerType GetProcAddress(Thread *thread, const char *procname)
432 {
433     const ProcEntry *entry =
434         std::lower_bound(&g_procTable[0], &g_procTable[g_numProcs], procname, CompareProc);
435 
436     thread->setSuccess();
437 
438     if (entry == &g_procTable[g_numProcs] || strcmp(entry->first, procname) != 0)
439     {
440         return nullptr;
441     }
442 
443     return entry->second;
444 }
445 
GetSyncAttrib(Thread * thread,Display * display,SyncID syncID,EGLint attribute,EGLAttrib * value)446 EGLBoolean GetSyncAttrib(Thread *thread,
447                          Display *display,
448                          SyncID syncID,
449                          EGLint attribute,
450                          EGLAttrib *value)
451 {
452     EGLint valueExt;
453     ANGLE_EGL_TRY_RETURN(thread, GetSyncAttrib(display, syncID, attribute, &valueExt),
454                          "eglGetSyncAttrib", GetSyncIfValid(display, syncID), EGL_FALSE);
455     *value = valueExt;
456 
457     thread->setSuccess();
458     return EGL_TRUE;
459 }
460 
Initialize(Thread * thread,Display * display,EGLint * major,EGLint * minor)461 EGLBoolean Initialize(Thread *thread, Display *display, EGLint *major, EGLint *minor)
462 {
463     ANGLE_EGL_TRY_RETURN(thread, display->initialize(), "eglInitialize", GetDisplayIfValid(display),
464                          EGL_FALSE);
465 
466     if (major)
467     {
468         *major = kEglMajorVersion;
469     }
470     if (minor)
471     {
472         *minor = kEglMinorVersion;
473     }
474 
475     thread->setSuccess();
476     return EGL_TRUE;
477 }
478 
MakeCurrent(Thread * thread,Display * display,egl::SurfaceID drawSurfaceID,egl::SurfaceID readSurfaceID,gl::ContextID contextID)479 EGLBoolean MakeCurrent(Thread *thread,
480                        Display *display,
481                        egl::SurfaceID drawSurfaceID,
482                        egl::SurfaceID readSurfaceID,
483                        gl::ContextID contextID)
484 {
485     Surface *drawSurface = display->getSurface(drawSurfaceID);
486     Surface *readSurface = display->getSurface(readSurfaceID);
487     gl::Context *context = display->getContext(contextID);
488 
489     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglMakeCurrent",
490                          GetDisplayIfValid(display), EGL_FALSE);
491     ScopedSyncCurrentContextFromThread scopedSyncCurrent(thread);
492 
493     Surface *previousDraw        = thread->getCurrentDrawSurface();
494     Surface *previousRead        = thread->getCurrentReadSurface();
495     gl::Context *previousContext = thread->getContext();
496 
497     // Only call makeCurrent if the context or surfaces have changed.
498     if (previousDraw != drawSurface || previousRead != readSurface || previousContext != context)
499     {
500         ANGLE_EGL_TRY_RETURN(
501             thread,
502             display->makeCurrent(thread, previousContext, drawSurface, readSurface, context),
503             "eglMakeCurrent", GetContextIfValid(display, contextID), EGL_FALSE);
504     }
505 
506     thread->setSuccess();
507     return EGL_TRUE;
508 }
509 
QueryAPI(Thread * thread)510 EGLenum QueryAPI(Thread *thread)
511 {
512     EGLenum API = thread->getAPI();
513 
514     thread->setSuccess();
515     return API;
516 }
517 
QueryContext(Thread * thread,Display * display,gl::ContextID contextID,EGLint attribute,EGLint * value)518 EGLBoolean QueryContext(Thread *thread,
519                         Display *display,
520                         gl::ContextID contextID,
521                         EGLint attribute,
522                         EGLint *value)
523 {
524     gl::Context *context = display->getContext(contextID);
525 
526     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryContext",
527                          GetDisplayIfValid(display), EGL_FALSE);
528     QueryContextAttrib(context, attribute, value);
529 
530     thread->setSuccess();
531     return EGL_TRUE;
532 }
533 
QueryString(Thread * thread,Display * display,EGLint name)534 const char *QueryString(Thread *thread, Display *display, EGLint name)
535 {
536     if (display)
537     {
538         ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryString",
539                              GetDisplayIfValid(display), nullptr);
540     }
541 
542     const char *result = nullptr;
543     switch (name)
544     {
545         case EGL_CLIENT_APIS:
546             result = display->getClientAPIString().c_str();
547             break;
548         case EGL_EXTENSIONS:
549             if (display == EGL_NO_DISPLAY)
550             {
551                 result = Display::GetClientExtensionString().c_str();
552             }
553             else
554             {
555                 result = display->getExtensionString().c_str();
556             }
557             break;
558         case EGL_VENDOR:
559             result = display->getVendorString().c_str();
560             break;
561         case EGL_VERSION:
562         {
563             static const char *sVersionString =
564                 MakeStaticString(std::string("1.5 (ANGLE ") + angle::GetANGLEVersionString() + ")");
565             result = sVersionString;
566             break;
567         }
568         default:
569             UNREACHABLE();
570             break;
571     }
572 
573     thread->setSuccess();
574     return result;
575 }
576 
QuerySurface(Thread * thread,Display * display,egl::SurfaceID surfaceID,EGLint attribute,EGLint * value)577 EGLBoolean QuerySurface(Thread *thread,
578                         Display *display,
579                         egl::SurfaceID surfaceID,
580                         EGLint attribute,
581                         EGLint *value)
582 {
583     Surface *eglSurface = display->getSurface(surfaceID);
584 
585     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQuerySurface",
586                          GetDisplayIfValid(display), EGL_FALSE);
587 
588     // Update GetContextLock_QuerySurface() switch accordingly to take a ContextMutex lock for
589     // attributes that require current Context.
590     const gl::Context *context;
591     switch (attribute)
592     {
593         // EGL_BUFFER_AGE_EXT uses Context, so lock was taken in GetContextLock_QuerySurface().
594         case EGL_BUFFER_AGE_EXT:
595             context = thread->getContext();
596             break;
597         // Other attributes are not using Context, pass nullptr to be explicit about that.
598         default:
599             context = nullptr;
600             break;
601     }
602 
603     ANGLE_EGL_TRY_RETURN(thread, QuerySurfaceAttrib(display, context, eglSurface, attribute, value),
604                          "eglQuerySurface", GetSurfaceIfValid(display, surfaceID), EGL_FALSE);
605 
606     thread->setSuccess();
607     return EGL_TRUE;
608 }
609 
ReleaseTexImage(Thread * thread,Display * display,egl::SurfaceID surfaceID,EGLint buffer)610 EGLBoolean ReleaseTexImage(Thread *thread,
611                            Display *display,
612                            egl::SurfaceID surfaceID,
613                            EGLint buffer)
614 {
615     Surface *eglSurface = display->getSurface(surfaceID);
616 
617     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglReleaseTexImage",
618                          GetDisplayIfValid(display), EGL_FALSE);
619     gl::Context *context = thread->getContext();
620     if (context && !context->isContextLost())
621     {
622         gl::Texture *texture = eglSurface->getBoundTexture();
623 
624         if (texture)
625         {
626             ANGLE_EGL_TRY_RETURN(thread, eglSurface->releaseTexImage(thread->getContext(), buffer),
627                                  "eglReleaseTexImage", GetSurfaceIfValid(display, surfaceID),
628                                  EGL_FALSE);
629         }
630     }
631     thread->setSuccess();
632     return EGL_TRUE;
633 }
634 
ReleaseThread(Thread * thread)635 EGLBoolean ReleaseThread(Thread *thread)
636 {
637     ScopedSyncCurrentContextFromThread scopedSyncCurrent(thread);
638 
639     Surface *previousDraw        = thread->getCurrentDrawSurface();
640     Surface *previousRead        = thread->getCurrentReadSurface();
641     gl::Context *previousContext = thread->getContext();
642     Display *previousDisplay     = thread->getDisplay();
643 
644     if (previousDisplay != EGL_NO_DISPLAY)
645     {
646         ANGLE_EGL_TRY_RETURN(thread, previousDisplay->prepareForCall(), "eglReleaseThread",
647                              GetDisplayIfValid(previousDisplay), EGL_FALSE);
648         // Only call makeCurrent if the context or surfaces have changed.
649         if (previousDraw != EGL_NO_SURFACE || previousRead != EGL_NO_SURFACE ||
650             previousContext != EGL_NO_CONTEXT)
651         {
652             ANGLE_EGL_TRY_RETURN(
653                 thread,
654                 previousDisplay->makeCurrent(thread, previousContext, nullptr, nullptr, nullptr),
655                 "eglReleaseThread", nullptr, EGL_FALSE);
656         }
657         ANGLE_EGL_TRY_RETURN(thread, previousDisplay->releaseThread(), "eglReleaseThread",
658                              GetDisplayIfValid(previousDisplay), EGL_FALSE);
659     }
660 
661     thread->setSuccess();
662     return EGL_TRUE;
663 }
664 
SurfaceAttrib(Thread * thread,Display * display,egl::SurfaceID surfaceID,EGLint attribute,EGLint value)665 EGLBoolean SurfaceAttrib(Thread *thread,
666                          Display *display,
667                          egl::SurfaceID surfaceID,
668                          EGLint attribute,
669                          EGLint value)
670 {
671     Surface *eglSurface = display->getSurface(surfaceID);
672 
673     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSurfaceAttrib",
674                          GetDisplayIfValid(display), EGL_FALSE);
675 
676     ANGLE_EGL_TRY_RETURN(thread, SetSurfaceAttrib(eglSurface, attribute, value), "eglSurfaceAttrib",
677                          GetDisplayIfValid(display), EGL_FALSE);
678 
679     thread->setSuccess();
680     return EGL_TRUE;
681 }
682 
SwapBuffers(Thread * thread,Display * display,egl::SurfaceID surfaceID)683 EGLBoolean SwapBuffers(Thread *thread, Display *display, egl::SurfaceID surfaceID)
684 {
685     Surface *eglSurface = display->getSurface(surfaceID);
686 
687     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapBuffers",
688                          GetDisplayIfValid(display), EGL_FALSE);
689 
690     ANGLE_EGL_TRY_RETURN(thread, eglSurface->swap(thread->getContext()), "eglSwapBuffers",
691                          GetSurfaceIfValid(display, surfaceID), EGL_FALSE);
692 
693     thread->setSuccess();
694     return EGL_TRUE;
695 }
696 
SwapInterval(Thread * thread,Display * display,EGLint interval)697 EGLBoolean SwapInterval(Thread *thread, Display *display, EGLint interval)
698 {
699     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapInterval",
700                          GetDisplayIfValid(display), EGL_FALSE);
701 
702     Surface *drawSurface        = static_cast<Surface *>(thread->getCurrentDrawSurface());
703     const Config *surfaceConfig = drawSurface->getConfig();
704     EGLint clampedInterval      = std::min(std::max(interval, surfaceConfig->minSwapInterval),
705                                            surfaceConfig->maxSwapInterval);
706 
707     drawSurface->setSwapInterval(clampedInterval);
708 
709     thread->setSuccess();
710     return EGL_TRUE;
711 }
712 
Terminate(Thread * thread,Display * display)713 EGLBoolean Terminate(Thread *thread, Display *display)
714 {
715     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglTerminate",
716                          GetDisplayIfValid(display), EGL_FALSE);
717 
718     ScopedSyncCurrentContextFromThread scopedSyncCurrent(thread);
719 
720     ANGLE_EGL_TRY_RETURN(thread, display->terminate(thread, Display::TerminateReason::Api),
721                          "eglTerminate", GetDisplayIfValid(display), EGL_FALSE);
722 
723     thread->setSuccess();
724     return EGL_TRUE;
725 }
726 
WaitClient(Thread * thread)727 EGLBoolean WaitClient(Thread *thread)
728 {
729     Display *display = thread->getDisplay();
730     if (display == nullptr)
731     {
732         // EGL spec says this about eglWaitClient -
733         //    If there is no current context for the current rendering API,
734         //    the function has no effect but still returns EGL_TRUE.
735         return EGL_TRUE;
736     }
737 
738     gl::Context *context = thread->getContext();
739 
740     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitClient",
741                          GetDisplayIfValid(display), EGL_FALSE);
742     ANGLE_EGL_TRY_RETURN(thread, display->waitClient(context), "eglWaitClient",
743                          GetContextIfValid(display, context->id()), EGL_FALSE);
744 
745     thread->setSuccess();
746     return EGL_TRUE;
747 }
748 
WaitGL(Thread * thread)749 EGLBoolean WaitGL(Thread *thread)
750 {
751     Display *display = thread->getDisplay();
752     if (display == nullptr)
753     {
754         // EGL spec says this about eglWaitGL -
755         //    eglWaitGL is ignored if there is no current EGL rendering context for OpenGL ES.
756         return EGL_TRUE;
757     }
758 
759     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitGL", GetDisplayIfValid(display),
760                          EGL_FALSE);
761 
762     // eglWaitGL like calling eglWaitClient with the OpenGL ES API bound. Since we only implement
763     // OpenGL ES we can do the call directly.
764     ANGLE_EGL_TRY_RETURN(thread, display->waitClient(thread->getContext()), "eglWaitGL",
765                          GetDisplayIfValid(display), EGL_FALSE);
766 
767     thread->setSuccess();
768     return EGL_TRUE;
769 }
770 
WaitNative(Thread * thread,EGLint engine)771 EGLBoolean WaitNative(Thread *thread, EGLint engine)
772 {
773     Display *display = thread->getDisplay();
774     if (display == nullptr)
775     {
776         // EGL spec says this about eglWaitNative -
777         //    eglWaitNative is ignored if there is no current EGL rendering context.
778         return EGL_TRUE;
779     }
780 
781     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitNative",
782                          GetDisplayIfValid(display), EGL_FALSE);
783     ANGLE_EGL_TRY_RETURN(thread, display->waitNative(thread->getContext(), engine), "eglWaitNative",
784                          GetThreadIfValid(thread), EGL_FALSE);
785 
786     thread->setSuccess();
787     return EGL_TRUE;
788 }
789 
WaitSync(Thread * thread,Display * display,SyncID syncID,EGLint flags)790 EGLBoolean WaitSync(Thread *thread, Display *display, SyncID syncID, EGLint flags)
791 {
792     ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitSync",
793                          GetDisplayIfValid(display), EGL_FALSE);
794     gl::Context *currentContext = thread->getContext();
795     Sync *syncObject            = display->getSync(syncID);
796     ANGLE_EGL_TRY_RETURN(thread, syncObject->serverWait(display, currentContext, flags),
797                          "eglWaitSync", GetSyncIfValid(display, syncID), EGL_FALSE);
798 
799     thread->setSuccess();
800     return EGL_TRUE;
801 }
802 }  // namespace egl
803