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