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