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