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