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