blob: 51f5309b140a4cfdb170c971ed7cde50064a94ea [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// libEGL.cpp: Implements the exported EGL functions.
16
17#include "main.h"
18#include "Display.h"
Nicolas Capens31c07a32017-06-13 23:44:13 -040019#include "Surface.hpp"
Nicolas Capens0bac2852016-05-07 06:09:58 -040020#include "Texture.hpp"
21#include "Context.hpp"
22#include "common/Image.hpp"
23#include "common/debug.h"
24#include "Common/Version.h"
25
Stephen Whitee6ab01f2019-04-04 14:31:25 -040026#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD)
Nicolas Capens0bac2852016-05-07 06:09:58 -040027#include <system/window.h>
Alexis Hetu20eea3c2018-06-19 14:50:41 -040028#elif defined(USE_X11)
Nicolas Capens0bac2852016-05-07 06:09:58 -040029#include "Main/libX11.hpp"
30#endif
31
Krzysztof Kosińskif919b862018-01-03 23:17:52 +010032#include <algorithm>
Nicolas Capens48908cb2018-01-08 13:07:14 -050033#include <vector>
Nicolas Capens0bac2852016-05-07 06:09:58 -040034#include <string.h>
35
Nicolas Capens48908cb2018-01-08 13:07:14 -050036namespace egl
37{
38namespace
39{
40bool validateDisplay(egl::Display *display)
Nicolas Capens0bac2852016-05-07 06:09:58 -040041{
42 if(display == EGL_NO_DISPLAY)
43 {
44 return error(EGL_BAD_DISPLAY, false);
45 }
46
47 if(!display->isInitialized())
48 {
49 return error(EGL_NOT_INITIALIZED, false);
50 }
51
52 return true;
53}
54
Nicolas Capens48908cb2018-01-08 13:07:14 -050055bool validateConfig(egl::Display *display, EGLConfig config)
Nicolas Capens0bac2852016-05-07 06:09:58 -040056{
57 if(!validateDisplay(display))
58 {
59 return false;
60 }
61
62 if(!display->isValidConfig(config))
63 {
64 return error(EGL_BAD_CONFIG, false);
65 }
66
67 return true;
68}
69
Nicolas Capens48908cb2018-01-08 13:07:14 -050070bool validateContext(egl::Display *display, egl::Context *context)
Nicolas Capens0bac2852016-05-07 06:09:58 -040071{
72 if(!validateDisplay(display))
73 {
74 return false;
75 }
76
77 if(!display->isValidContext(context))
78 {
79 return error(EGL_BAD_CONTEXT, false);
80 }
81
82 return true;
83}
84
Nicolas Capens48908cb2018-01-08 13:07:14 -050085bool validateSurface(egl::Display *display, egl::Surface *surface)
Nicolas Capens0bac2852016-05-07 06:09:58 -040086{
87 if(!validateDisplay(display))
88 {
89 return false;
90 }
91
92 if(!display->isValidSurface(surface))
93 {
94 return error(EGL_BAD_SURFACE, false);
95 }
96
97 return true;
98}
99
Nicolas Capens48908cb2018-01-08 13:07:14 -0500100// Class to facilitate conversion from EGLint to EGLAttrib lists.
101class EGLAttribs
Nicolas Capens0bac2852016-05-07 06:09:58 -0400102{
Nicolas Capens48908cb2018-01-08 13:07:14 -0500103public:
104 explicit EGLAttribs(const EGLint *attrib_list)
105 {
106 if(attrib_list)
107 {
108 while(*attrib_list != EGL_NONE)
109 {
110 attrib.push_back(static_cast<EGLAttrib>(*attrib_list));
111 attrib_list++;
112 }
113 }
114
115 attrib.push_back(EGL_NONE);
116 }
117
Nicolas Capensd7622ff2018-08-07 12:24:10 -0400118 const EGLAttrib *operator&() const
Nicolas Capens48908cb2018-01-08 13:07:14 -0500119 {
120 return &attrib[0];
121 }
122
123private:
124 std::vector<EGLAttrib> attrib;
125};
126}
127
Nicolas Capens0bac2852016-05-07 06:09:58 -0400128EGLint GetError(void)
129{
130 TRACE("()");
131
132 EGLint error = egl::getCurrentError();
133
134 if(error != EGL_SUCCESS)
135 {
136 egl::setCurrentError(EGL_SUCCESS);
137 }
138
139 return error;
140}
141
142EGLDisplay GetDisplay(EGLNativeDisplayType display_id)
143{
144 TRACE("(EGLNativeDisplayType display_id = %p)", display_id);
145
146 if(display_id != EGL_DEFAULT_DISPLAY)
147 {
148 // FIXME: Check if display_id is the default display
149 }
150
151 #if defined(__linux__) && !defined(__ANDROID__)
Alexis Hetu20eea3c2018-06-19 14:50:41 -0400152 #if defined(USE_X11)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400153 if(!libX11)
Alexis Hetu20eea3c2018-06-19 14:50:41 -0400154 #endif // Non X11 linux is headless only
Nicolas Capens0bac2852016-05-07 06:09:58 -0400155 {
156 return success(HEADLESS_DISPLAY);
157 }
158 #endif
159
160 return success(PRIMARY_DISPLAY); // We only support the default display
161}
162
163EGLBoolean Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
164{
165 TRACE("(EGLDisplay dpy = %p, EGLint *major = %p, EGLint *minor = %p)",
166 dpy, major, minor);
167
Alexis Hetu2b6ac182017-05-24 14:06:27 -0400168 egl::Display *display = egl::Display::get(dpy);
169
170 if(!display)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400171 {
172 return error(EGL_BAD_DISPLAY, EGL_FALSE);
173 }
174
Nicolas Capens0bac2852016-05-07 06:09:58 -0400175 if(!display->initialize())
176 {
177 return error(EGL_NOT_INITIALIZED, EGL_FALSE);
178 }
179
180 if(major) *major = 1;
181 if(minor) *minor = 4;
182
183 return success(EGL_TRUE);
184}
185
186EGLBoolean Terminate(EGLDisplay dpy)
187{
188 TRACE("(EGLDisplay dpy = %p)", dpy);
189
190 if(dpy == EGL_NO_DISPLAY)
191 {
192 return error(EGL_BAD_DISPLAY, EGL_FALSE);
193 }
194
195 egl::Display *display = egl::Display::get(dpy);
196
197 display->terminate();
198
199 return success(EGL_TRUE);
200}
201
202const char *QueryString(EGLDisplay dpy, EGLint name)
203{
204 TRACE("(EGLDisplay dpy = %p, EGLint name = %d)", dpy, name);
205
Nicolas Capensdf0be382017-06-05 17:43:46 -0400206 if(dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
207 {
208 return success(
Krzysztof Kosińskif919b862018-01-03 23:17:52 +0100209 "EGL_KHR_client_get_all_proc_addresses "
Nicolas Capensdf0be382017-06-05 17:43:46 -0400210#if defined(__linux__) && !defined(__ANDROID__)
211 "EGL_KHR_platform_gbm "
Alexis Hetu20eea3c2018-06-19 14:50:41 -0400212#endif
213#if defined(USE_X11)
Nicolas Capensdf0be382017-06-05 17:43:46 -0400214 "EGL_KHR_platform_x11 "
Alexis Hetud415ba12017-06-05 10:29:14 -0400215#endif
Nicolas Capensdf0be382017-06-05 17:43:46 -0400216 "EGL_EXT_client_extensions "
217 "EGL_EXT_platform_base");
218 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400219
220 egl::Display *display = egl::Display::get(dpy);
221
222 if(!validateDisplay(display))
223 {
224 return nullptr;
225 }
226
227 switch(name)
228 {
229 case EGL_CLIENT_APIS:
230 return success("OpenGL_ES");
231 case EGL_EXTENSIONS:
Alexis Hetub75bb022016-05-18 11:43:43 -0400232 return success("EGL_KHR_create_context "
Krzysztof Kosińskif919b862018-01-03 23:17:52 +0100233 "EGL_KHR_get_all_proc_addresses "
Alexis Hetub75bb022016-05-18 11:43:43 -0400234 "EGL_KHR_gl_texture_2D_image "
Nicolas Capens0bac2852016-05-07 06:09:58 -0400235 "EGL_KHR_gl_texture_cubemap_image "
236 "EGL_KHR_gl_renderbuffer_image "
237 "EGL_KHR_fence_sync "
238 "EGL_KHR_image_base "
Alexis Hetu5cd502b2018-03-22 08:29:31 -0400239 "EGL_KHR_surfaceless_context "
Alexis Hetuc80eada2018-02-13 15:02:40 -0500240 "EGL_ANGLE_iosurface_client_buffer "
Nicolas Capens0bac2852016-05-07 06:09:58 -0400241 "EGL_ANDROID_framebuffer_target "
242 "EGL_ANDROID_recordable");
243 case EGL_VENDOR:
244 return success("Google Inc.");
245 case EGL_VERSION:
246 return success("1.4 SwiftShader " VERSION_STRING);
247 }
248
249 return error(EGL_BAD_PARAMETER, (const char*)nullptr);
250}
251
252EGLBoolean GetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
253{
254 TRACE("(EGLDisplay dpy = %p, EGLConfig *configs = %p, "
255 "EGLint config_size = %d, EGLint *num_config = %p)",
256 dpy, configs, config_size, num_config);
257
258 egl::Display *display = egl::Display::get(dpy);
259
260 if(!validateDisplay(display))
261 {
262 return EGL_FALSE;
263 }
264
265 if(!num_config)
266 {
267 return error(EGL_BAD_PARAMETER, EGL_FALSE);
268 }
269
270 const EGLint attribList[] = {EGL_NONE};
271
272 if(!display->getConfigs(configs, attribList, config_size, num_config))
273 {
274 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
275 }
276
277 return success(EGL_TRUE);
278}
279
280EGLBoolean ChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
281{
282 TRACE("(EGLDisplay dpy = %p, const EGLint *attrib_list = %p, "
283 "EGLConfig *configs = %p, EGLint config_size = %d, EGLint *num_config = %p)",
284 dpy, attrib_list, configs, config_size, num_config);
285
286 egl::Display *display = egl::Display::get(dpy);
287
288 if(!validateDisplay(display))
289 {
290 return EGL_FALSE;
291 }
292
293 if(!num_config)
294 {
295 return error(EGL_BAD_PARAMETER, EGL_FALSE);
296 }
297
298 const EGLint attribList[] = {EGL_NONE};
299
300 if(!attrib_list)
301 {
302 attrib_list = attribList;
303 }
304
305 if(!display->getConfigs(configs, attrib_list, config_size, num_config))
306 {
307 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
308 }
309
310 return success(EGL_TRUE);
311}
312
313EGLBoolean GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
314{
315 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLint attribute = %d, EGLint *value = %p)",
316 dpy, config, attribute, value);
317
318 egl::Display *display = egl::Display::get(dpy);
319
320 if(!validateConfig(display, config))
321 {
322 return EGL_FALSE;
323 }
324
325 if(!display->getConfigAttrib(config, attribute, value))
326 {
327 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
328 }
329
330 return success(EGL_TRUE);
331}
332
Nicolas Capens48908cb2018-01-08 13:07:14 -0500333EGLSurface CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400334{
Nicolas Capens48908cb2018-01-08 13:07:14 -0500335 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_window = %p, "
336 "const EGLint *attrib_list = %p)", dpy, config, native_window, attrib_list);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400337
338 egl::Display *display = egl::Display::get(dpy);
339
340 if(!validateConfig(display, config))
341 {
342 return EGL_NO_SURFACE;
343 }
344
Nicolas Capens48908cb2018-01-08 13:07:14 -0500345 if(!display->isValidWindow((EGLNativeWindowType)native_window))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400346 {
347 return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
348 }
349
Nicolas Capens48908cb2018-01-08 13:07:14 -0500350 return display->createWindowSurface((EGLNativeWindowType)native_window, config, attrib_list);
351}
352
353EGLSurface CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list)
354{
355 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_window = %p, "
356 "const EGLint *attrib_list = %p)", dpy, config, native_window, attrib_list);
357
358 EGLAttribs attribs(attrib_list);
Nicolas Capensd7622ff2018-08-07 12:24:10 -0400359 return CreatePlatformWindowSurface(dpy, config, native_window, &attribs);
Nicolas Capens48908cb2018-01-08 13:07:14 -0500360}
361
362EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType window, const EGLint *attrib_list)
363{
364 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativeWindowType window = %p, "
365 "const EGLint *attrib_list = %p)", dpy, config, window, attrib_list);
366
367 EGLAttribs attribs(attrib_list);
Nicolas Capensd7622ff2018-08-07 12:24:10 -0400368 return CreatePlatformWindowSurface(dpy, config, (void*)window, &attribs);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400369}
370
371EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
372{
373 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, const EGLint *attrib_list = %p)",
374 dpy, config, attrib_list);
375
376 egl::Display *display = egl::Display::get(dpy);
377
378 if(!validateConfig(display, config))
379 {
380 return EGL_NO_SURFACE;
381 }
382
383 return display->createPBufferSurface(config, attrib_list);
384}
385
Nicolas Capens48908cb2018-01-08 13:07:14 -0500386EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400387{
Nicolas Capens48908cb2018-01-08 13:07:14 -0500388 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_pixmap = %p, "
389 "const EGLint *attrib_list = %p)", dpy, config, native_pixmap, attrib_list);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400390
391 egl::Display *display = egl::Display::get(dpy);
392
393 if(!validateConfig(display, config))
394 {
395 return EGL_NO_SURFACE;
396 }
397
398 UNIMPLEMENTED(); // FIXME
399
400 return success(EGL_NO_SURFACE);
401}
402
Nicolas Capens48908cb2018-01-08 13:07:14 -0500403EGLSurface CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list)
404{
405 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_pixmap = %p, "
406 "const EGLint *attrib_list = %p)", dpy, config, native_pixmap, attrib_list);
407
408 EGLAttribs attribs(attrib_list);
Nicolas Capensd7622ff2018-08-07 12:24:10 -0400409 return CreatePlatformPixmapSurface(dpy, config, native_pixmap, &attribs);
Nicolas Capens48908cb2018-01-08 13:07:14 -0500410}
411
412EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
413{
414 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativePixmapType pixmap = %p, "
415 "const EGLint *attrib_list = %p)", dpy, config, pixmap, attrib_list);
416
417 EGLAttribs attribs(attrib_list);
Nicolas Capensd7622ff2018-08-07 12:24:10 -0400418 return CreatePlatformPixmapSurface(dpy, config, (void*)pixmap, &attribs);
Nicolas Capens48908cb2018-01-08 13:07:14 -0500419}
420
Nicolas Capens0bac2852016-05-07 06:09:58 -0400421EGLBoolean DestroySurface(EGLDisplay dpy, EGLSurface surface)
422{
423 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p)", dpy, surface);
424
425 egl::Display *display = egl::Display::get(dpy);
426 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
427
428 if(!validateSurface(display, eglSurface))
429 {
430 return EGL_FALSE;
431 }
432
433 if(surface == EGL_NO_SURFACE)
434 {
435 return error(EGL_BAD_SURFACE, EGL_FALSE);
436 }
437
438 display->destroySurface((egl::Surface*)surface);
439
440 return success(EGL_TRUE);
441}
442
443EGLBoolean QuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
444{
445 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint attribute = %d, EGLint *value = %p)",
446 dpy, surface, attribute, value);
447
448 egl::Display *display = egl::Display::get(dpy);
449 egl::Surface *eglSurface = (egl::Surface*)surface;
450
451 if(!validateSurface(display, eglSurface))
452 {
453 return EGL_FALSE;
454 }
455
456 if(surface == EGL_NO_SURFACE)
457 {
458 return error(EGL_BAD_SURFACE, EGL_FALSE);
459 }
460
461 switch(attribute)
462 {
463 case EGL_VG_ALPHA_FORMAT:
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400464 *value = EGL_VG_ALPHA_FORMAT_NONPRE; // Default
Nicolas Capens0bac2852016-05-07 06:09:58 -0400465 break;
466 case EGL_VG_COLORSPACE:
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400467 *value = EGL_VG_COLORSPACE_sRGB; // Default
Nicolas Capens0bac2852016-05-07 06:09:58 -0400468 break;
469 case EGL_CONFIG_ID:
470 *value = eglSurface->getConfigID();
471 break;
472 case EGL_HEIGHT:
473 *value = eglSurface->getHeight();
474 break;
475 case EGL_HORIZONTAL_RESOLUTION:
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400476 *value = EGL_UNKNOWN;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400477 break;
478 case EGL_LARGEST_PBUFFER:
479 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
480 {
481 *value = eglSurface->getLargestPBuffer();
482 }
483 break;
484 case EGL_MIPMAP_TEXTURE:
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400485 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
486 {
487 *value = EGL_FALSE; // UNIMPLEMENTED
488 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400489 break;
490 case EGL_MIPMAP_LEVEL:
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400491 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
492 {
493 *value = eglSurface->getMipmapLevel();
494 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400495 break;
496 case EGL_MULTISAMPLE_RESOLVE:
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400497 *value = eglSurface->getMultisampleResolve();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400498 break;
499 case EGL_PIXEL_ASPECT_RATIO:
500 *value = eglSurface->getPixelAspectRatio();
501 break;
502 case EGL_RENDER_BUFFER:
503 *value = eglSurface->getRenderBuffer();
504 break;
505 case EGL_SWAP_BEHAVIOR:
506 *value = eglSurface->getSwapBehavior();
507 break;
508 case EGL_TEXTURE_FORMAT:
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400509 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
510 {
511 *value = eglSurface->getTextureFormat();
512 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400513 break;
514 case EGL_TEXTURE_TARGET:
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400515 if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified.
516 {
517 *value = eglSurface->getTextureTarget();
518 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400519 break;
520 case EGL_VERTICAL_RESOLUTION:
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400521 *value = EGL_UNKNOWN;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400522 break;
523 case EGL_WIDTH:
524 *value = eglSurface->getWidth();
525 break;
526 default:
527 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
528 }
529
530 return success(EGL_TRUE);
531}
532
533EGLBoolean BindAPI(EGLenum api)
534{
535 TRACE("(EGLenum api = 0x%X)", api);
536
537 switch(api)
538 {
539 case EGL_OPENGL_API:
540 case EGL_OPENVG_API:
541 return error(EGL_BAD_PARAMETER, EGL_FALSE); // Not supported by this implementation
542 case EGL_OPENGL_ES_API:
543 break;
544 default:
545 return error(EGL_BAD_PARAMETER, EGL_FALSE);
546 }
547
548 egl::setCurrentAPI(api);
549
550 return success(EGL_TRUE);
551}
552
553EGLenum QueryAPI(void)
554{
555 TRACE("()");
556
557 EGLenum API = egl::getCurrentAPI();
558
559 return success(API);
560}
561
562EGLBoolean WaitClient(void)
563{
564 TRACE("()");
565
Alexis Hetuf3a124f2018-01-15 15:49:42 -0500566 // eglWaitClient is ignored if there is no current EGL rendering context for the current rendering API.
567 egl::Context *context = egl::getCurrentContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400568
Alexis Hetuf3a124f2018-01-15 15:49:42 -0500569 if(context)
570 {
571 context->finish();
572 }
573
574 return success(EGL_TRUE);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400575}
576
577EGLBoolean ReleaseThread(void)
578{
579 TRACE("()");
580
Nicolas Capenscc5c7d92016-06-13 14:35:11 -0400581 detachThread();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400582
Nicolas Capens660eba92017-09-05 14:06:06 -0400583 return EGL_TRUE; // success() is not called here because it would re-allocate thread-local storage.
Nicolas Capens0bac2852016-05-07 06:09:58 -0400584}
585
586EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
587{
588 TRACE("(EGLDisplay dpy = %p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = %p, "
589 "EGLConfig config = %p, const EGLint *attrib_list = %p)",
590 dpy, buftype, buffer, config, attrib_list);
591
Alexis Hetuc80eada2018-02-13 15:02:40 -0500592 switch(buftype)
593 {
594 case EGL_IOSURFACE_ANGLE:
595 {
596 egl::Display *display = egl::Display::get(dpy);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400597
Alexis Hetuc80eada2018-02-13 15:02:40 -0500598 if(!validateConfig(display, config))
599 {
600 return EGL_NO_SURFACE;
601 }
602
603 return display->createPBufferSurface(config, attrib_list, buffer);
604 }
605 case EGL_OPENVG_IMAGE:
606 UNIMPLEMENTED();
607 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
608 default:
609 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
610 };
Nicolas Capens0bac2852016-05-07 06:09:58 -0400611}
612
613EGLBoolean SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
614{
615 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint attribute = %d, EGLint value = %d)",
616 dpy, surface, attribute, value);
617
618 egl::Display *display = egl::Display::get(dpy);
619 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
620
621 if(!validateSurface(display, eglSurface))
622 {
623 return EGL_FALSE;
624 }
625
626 switch(attribute)
627 {
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400628 case EGL_MIPMAP_LEVEL:
629 eglSurface->setMipmapLevel(value);
630 break;
631 case EGL_MULTISAMPLE_RESOLVE:
632 switch(value)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400633 {
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400634 case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
635 break;
636 case EGL_MULTISAMPLE_RESOLVE_BOX:
637 if(!(eglSurface->getSurfaceType() & EGL_MULTISAMPLE_RESOLVE_BOX_BIT))
638 {
639 return error(EGL_BAD_MATCH, EGL_FALSE);
640 }
641 break;
642 default:
643 return error(EGL_BAD_PARAMETER, EGL_FALSE);
644 }
645 eglSurface->setMultisampleResolve(value);
646 break;
647 case EGL_SWAP_BEHAVIOR:
648 switch(value)
649 {
650 case EGL_BUFFER_DESTROYED:
651 break;
652 case EGL_BUFFER_PRESERVED:
Nicolas Capens0bac2852016-05-07 06:09:58 -0400653 if(!(eglSurface->getSurfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
654 {
655 return error(EGL_BAD_MATCH, EGL_FALSE);
656 }
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400657 break;
658 default:
Nicolas Capens0bac2852016-05-07 06:09:58 -0400659 return error(EGL_BAD_PARAMETER, EGL_FALSE);
660 }
661 eglSurface->setSwapBehavior(value);
662 break;
663 default:
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400664 return error(EGL_BAD_PARAMETER, EGL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400665 }
666
667 return success(EGL_TRUE);
668}
669
670EGLBoolean BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
671{
672 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint buffer = %d)", dpy, surface, buffer);
673
674 egl::Display *display = egl::Display::get(dpy);
675 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
676
677 if(!validateSurface(display, eglSurface))
678 {
679 return EGL_FALSE;
680 }
681
682 if(buffer != EGL_BACK_BUFFER)
683 {
684 return error(EGL_BAD_PARAMETER, EGL_FALSE);
685 }
686
687 if(surface == EGL_NO_SURFACE || eglSurface->isWindowSurface())
688 {
689 return error(EGL_BAD_SURFACE, EGL_FALSE);
690 }
691
692 if(eglSurface->getBoundTexture())
693 {
694 return error(EGL_BAD_ACCESS, EGL_FALSE);
695 }
696
697 if(eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
698 {
699 return error(EGL_BAD_MATCH, EGL_FALSE);
700 }
701
702 egl::Context *context = egl::getCurrentContext();
703
704 if(context)
705 {
706 context->bindTexImage(eglSurface);
707 }
708
709 return success(EGL_TRUE);
710}
711
712EGLBoolean ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
713{
714 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint buffer = %d)", dpy, surface, buffer);
715
716 egl::Display *display = egl::Display::get(dpy);
717 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
718
719 if(!validateSurface(display, eglSurface))
720 {
721 return EGL_FALSE;
722 }
723
724 if(buffer != EGL_BACK_BUFFER)
725 {
726 return error(EGL_BAD_PARAMETER, EGL_FALSE);
727 }
728
729 if(surface == EGL_NO_SURFACE || eglSurface->isWindowSurface())
730 {
731 return error(EGL_BAD_SURFACE, EGL_FALSE);
732 }
733
734 if(eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
735 {
736 return error(EGL_BAD_MATCH, EGL_FALSE);
737 }
738
739 egl::Texture *texture = eglSurface->getBoundTexture();
740
741 if(texture)
742 {
743 texture->releaseTexImage();
744 }
745
746 return success(EGL_TRUE);
747}
748
749EGLBoolean SwapInterval(EGLDisplay dpy, EGLint interval)
750{
751 TRACE("(EGLDisplay dpy = %p, EGLint interval = %d)", dpy, interval);
752
753 egl::Display *display = egl::Display::get(dpy);
754 egl::Context *context = egl::getCurrentContext();
755
756 if(!validateContext(display, context))
757 {
758 return EGL_FALSE;
759 }
760
761 egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface());
762
763 if(!draw_surface)
764 {
765 return error(EGL_BAD_SURFACE, EGL_FALSE);
766 }
767
768 draw_surface->setSwapInterval(interval);
769
770 return success(EGL_TRUE);
771}
772
773EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
774{
775 TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLContext share_context = %p, "
776 "const EGLint *attrib_list = %p)", dpy, config, share_context, attrib_list);
777
Alexis Hetub75bb022016-05-18 11:43:43 -0400778 EGLint majorVersion = 1;
779 EGLint minorVersion = 0;
780
Nicolas Capens0bac2852016-05-07 06:09:58 -0400781 if(attrib_list)
782 {
783 for(const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2)
784 {
Alexis Hetub75bb022016-05-18 11:43:43 -0400785 switch(attribute[0])
Nicolas Capens0bac2852016-05-07 06:09:58 -0400786 {
Alexis Hetub75bb022016-05-18 11:43:43 -0400787 case EGL_CONTEXT_MAJOR_VERSION_KHR: // This token is an alias for EGL_CONTEXT_CLIENT_VERSION
788 majorVersion = attribute[1];
789 break;
790 case EGL_CONTEXT_MINOR_VERSION_KHR:
791 minorVersion = attribute[1];
792 break;
793 case EGL_CONTEXT_FLAGS_KHR:
794 switch(attribute[1])
795 {
796 case EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR:
797 // According to the EGL_KHR_create_context spec:
798 // "Khronos is still defining the expected and required features of debug contexts, so
799 // implementations are currently free to implement "debug contexts" with little or no debug
800 // functionality. However, OpenGL and OpenGL ES implementations supporting the GL_KHR_debug
801 // extension should enable it when this bit is set."
802 break;
803 case EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR:
804 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR:
805 // These bits are for OpenGL contexts only, not OpenGL ES contexts
806 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
807 default:
808 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
809 }
810 break;
811 case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
812 switch(attribute[1])
813 {
814 case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR:
815 case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR:
816 // These bits are for OpenGL contexts only, not OpenGL ES contexts
817 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
818 default:
819 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
820 }
821 break;
822 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
823 switch(attribute[1])
824 {
825 case EGL_NO_RESET_NOTIFICATION_KHR:
826 case EGL_LOSE_CONTEXT_ON_RESET_KHR:
827 // These bits are for OpenGL contexts only, not OpenGL ES contexts
828 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
829 default:
830 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
831 }
832 break;
833 default:
Nicolas Capens0bac2852016-05-07 06:09:58 -0400834 return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
835 }
836 }
837 }
838
Alexis Hetub75bb022016-05-18 11:43:43 -0400839 switch(majorVersion)
840 {
841 case 1:
842 if(minorVersion != 0 && minorVersion != 1)
843 {
844 // 1.X: Only OpenGL ES 1.0 and 1.1 contexts are supported
845 return error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
846 }
847 break;
848 case 2:
849 case 3:
850 if(minorVersion != 0)
851 {
852 // 2.X and 3.X: Only OpenGL ES 2.0 and 3.0 contexts are currently supported
853 return error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
854 }
855 break;
856 default:
857 return error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
858 }
859
Nicolas Capens0bac2852016-05-07 06:09:58 -0400860 egl::Display *display = egl::Display::get(dpy);
861 egl::Context *shareContext = static_cast<egl::Context*>(share_context);
862
863 if(!validateConfig(display, config))
864 {
865 return EGL_NO_CONTEXT;
866 }
867
Chris Forbes5fb5e812018-08-30 17:28:59 -0700868 // Allow sharing between different context versions >= 2.0, but isolate 1.x
869 // contexts from 2.0+. Strict matching between context versions >= 2.0 is
870 // confusing for apps to navigate because of version promotion.
871 if(shareContext && ((shareContext->getClientVersion() >= 2) ^ (majorVersion >= 2)))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400872 {
873 return error(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
874 }
875
Alexis Hetub75bb022016-05-18 11:43:43 -0400876 return display->createContext(config, shareContext, majorVersion);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400877}
878
879EGLBoolean DestroyContext(EGLDisplay dpy, EGLContext ctx)
880{
881 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p)", dpy, ctx);
882
883 egl::Display *display = egl::Display::get(dpy);
884 egl::Context *context = static_cast<egl::Context*>(ctx);
885
886 if(!validateContext(display, context))
887 {
888 return EGL_FALSE;
889 }
890
891 if(ctx == EGL_NO_CONTEXT)
892 {
893 return error(EGL_BAD_CONTEXT, EGL_FALSE);
894 }
895
896 display->destroyContext(context);
897
898 return success(EGL_TRUE);
899}
900
901EGLBoolean MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
902{
903 TRACE("(EGLDisplay dpy = %p, EGLSurface draw = %p, EGLSurface read = %p, EGLContext ctx = %p)",
904 dpy, draw, read, ctx);
905
906 egl::Display *display = egl::Display::get(dpy);
907 egl::Context *context = static_cast<egl::Context*>(ctx);
908 egl::Surface *drawSurface = static_cast<egl::Surface*>(draw);
909 egl::Surface *readSurface = static_cast<egl::Surface*>(read);
910
911 if(ctx != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)
912 {
913 if(!validateDisplay(display))
914 {
915 return EGL_FALSE;
916 }
917 }
918
919 if(ctx == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
920 {
921 return error(EGL_BAD_MATCH, EGL_FALSE);
922 }
923
924 if(ctx != EGL_NO_CONTEXT && !validateContext(display, context))
925 {
926 return EGL_FALSE;
927 }
928
929 if((draw != EGL_NO_SURFACE && !validateSurface(display, drawSurface)) ||
930 (read != EGL_NO_SURFACE && !validateSurface(display, readSurface)))
931 {
932 return EGL_FALSE;
933 }
934
Alexis Hetuc80eada2018-02-13 15:02:40 -0500935 if((draw != EGL_NO_SURFACE && drawSurface->hasClientBuffer()) ||
936 (read != EGL_NO_SURFACE && readSurface->hasClientBuffer()))
937 {
938 // Make current is not supported on IOSurface pbuffers.
939 return error(EGL_BAD_SURFACE, EGL_FALSE);
940 }
941
Nicolas Capens0bac2852016-05-07 06:09:58 -0400942 if((draw != EGL_NO_SURFACE) ^ (read != EGL_NO_SURFACE))
943 {
944 return error(EGL_BAD_MATCH, EGL_FALSE);
945 }
946
947 if(draw != read)
948 {
949 UNIMPLEMENTED(); // FIXME
950 }
951
Nicolas Capens0bac2852016-05-07 06:09:58 -0400952 egl::setCurrentDrawSurface(drawSurface);
953 egl::setCurrentReadSurface(readSurface);
954 egl::setCurrentContext(context);
955
956 if(context)
957 {
958 context->makeCurrent(drawSurface);
959 }
960
961 return success(EGL_TRUE);
962}
963
964EGLContext GetCurrentContext(void)
965{
966 TRACE("()");
967
968 EGLContext context = egl::getCurrentContext();
969
970 return success(context);
971}
972
973EGLSurface GetCurrentSurface(EGLint readdraw)
974{
975 TRACE("(EGLint readdraw = %d)", readdraw);
976
977 if(readdraw == EGL_READ)
978 {
979 EGLSurface read = egl::getCurrentReadSurface();
980 return success(read);
981 }
982 else if(readdraw == EGL_DRAW)
983 {
984 EGLSurface draw = egl::getCurrentDrawSurface();
985 return success(draw);
986 }
987 else
988 {
989 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
990 }
991}
992
993EGLDisplay GetCurrentDisplay(void)
994{
995 TRACE("()");
996
Nicolas Capens8aca1df2017-06-15 14:15:30 -0700997 egl::Context *context = egl::getCurrentContext();
998
999 if(!context)
1000 {
1001 return success(EGL_NO_DISPLAY);
1002 }
1003
Nicolas Capense88da312017-07-10 14:26:17 -04001004 egl::Display *display = context->getDisplay();
1005
1006 if(!display)
1007 {
1008 return error(EGL_BAD_ACCESS, EGL_NO_DISPLAY);
1009 }
1010
1011 return success(display->getEGLDisplay());
Nicolas Capens0bac2852016-05-07 06:09:58 -04001012}
1013
1014EGLBoolean QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
1015{
1016 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLint attribute = %d, EGLint *value = %p)",
1017 dpy, ctx, attribute, value);
1018
1019 egl::Display *display = egl::Display::get(dpy);
1020 egl::Context *context = static_cast<egl::Context*>(ctx);
1021
1022 if(!validateContext(display, context))
1023 {
1024 return EGL_FALSE;
1025 }
1026
Nicolas Capensf6a377b2017-05-19 09:31:35 -04001027 switch(attribute)
1028 {
Nicolas Capensdf0be382017-06-05 17:43:46 -04001029 case EGL_CONFIG_ID:
1030 *value = context->getConfigID();
1031 break;
1032 case EGL_CONTEXT_CLIENT_TYPE:
1033 *value = egl::getCurrentAPI();
1034 break;
Nicolas Capensf6a377b2017-05-19 09:31:35 -04001035 case EGL_CONTEXT_CLIENT_VERSION:
1036 *value = context->getClientVersion();
1037 break;
1038 case EGL_RENDER_BUFFER:
Nicolas Capensdf0be382017-06-05 17:43:46 -04001039 *value = EGL_BACK_BUFFER;
Nicolas Capensf6a377b2017-05-19 09:31:35 -04001040 break;
1041 default:
1042 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1043 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001044
Nicolas Capensf6a377b2017-05-19 09:31:35 -04001045 return success(EGL_TRUE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001046}
1047
1048EGLBoolean WaitGL(void)
1049{
1050 TRACE("()");
1051
Alexis Hetuf3a124f2018-01-15 15:49:42 -05001052 // glWaitGL is ignored if there is no current EGL rendering context for OpenGL ES.
1053 egl::Context *context = egl::getCurrentContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001054
Alexis Hetuf3a124f2018-01-15 15:49:42 -05001055 if(context)
1056 {
1057 context->finish();
1058 }
1059
1060 return success(EGL_TRUE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001061}
1062
1063EGLBoolean WaitNative(EGLint engine)
1064{
1065 TRACE("(EGLint engine = %d)", engine);
1066
Alexis Hetuf3a124f2018-01-15 15:49:42 -05001067 if(engine != EGL_CORE_NATIVE_ENGINE)
1068 {
1069 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1070 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001071
Alexis Hetuf3a124f2018-01-15 15:49:42 -05001072 // eglWaitNative is ignored if there is no current EGL rendering context.
1073 egl::Context *context = egl::getCurrentContext();
1074
1075 if(context)
1076 {
Alexis Hetu20eea3c2018-06-19 14:50:41 -04001077 #if defined(USE_X11)
Alexis Hetuf3a124f2018-01-15 15:49:42 -05001078 egl::Display *display = context->getDisplay();
1079
1080 if(!display)
1081 {
1082 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1083 }
1084
1085 libX11->XSync((::Display*)display->getNativeDisplay(), False);
1086 #else
1087 UNIMPLEMENTED();
1088 #endif
1089 }
1090
1091 return success(EGL_TRUE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001092}
1093
1094EGLBoolean SwapBuffers(EGLDisplay dpy, EGLSurface surface)
1095{
1096 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p)", dpy, surface);
1097
1098 egl::Display *display = egl::Display::get(dpy);
1099 egl::Surface *eglSurface = (egl::Surface*)surface;
1100
1101 if(!validateSurface(display, eglSurface))
1102 {
1103 return EGL_FALSE;
1104 }
1105
1106 if(surface == EGL_NO_SURFACE)
1107 {
1108 return error(EGL_BAD_SURFACE, EGL_FALSE);
1109 }
1110
1111 eglSurface->swap();
1112
1113 return success(EGL_TRUE);
1114}
1115
1116EGLBoolean CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
1117{
1118 TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLNativePixmapType target = %p)", dpy, surface, target);
1119
1120 egl::Display *display = egl::Display::get(dpy);
1121 egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
1122
1123 if(!validateSurface(display, eglSurface))
1124 {
1125 return EGL_FALSE;
1126 }
1127
1128 UNIMPLEMENTED(); // FIXME
1129
1130 return success(EGL_FALSE);
1131}
1132
Nicolas Capens48908cb2018-01-08 13:07:14 -05001133EGLImage CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001134{
Nicolas Capens48908cb2018-01-08 13:07:14 -05001135 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLenum target = 0x%X, buffer = %p, const EGLAttrib *attrib_list = %p)", dpy, ctx, target, buffer, attrib_list);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001136
1137 egl::Display *display = egl::Display::get(dpy);
1138 egl::Context *context = static_cast<egl::Context*>(ctx);
1139
1140 if(!validateDisplay(display))
1141 {
1142 return error(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1143 }
1144
1145 if(context != EGL_NO_CONTEXT && !display->isValidContext(context))
1146 {
1147 return error(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1148 }
1149
1150 EGLenum imagePreserved = EGL_FALSE;
Ben Claytonf4b99b62019-02-19 16:50:48 +00001151 (void)imagePreserved; // currently unused
1152
Nicolas Capens0bac2852016-05-07 06:09:58 -04001153 GLuint textureLevel = 0;
1154 if(attrib_list)
1155 {
Nicolas Capens48908cb2018-01-08 13:07:14 -05001156 for(const EGLAttrib *attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001157 {
1158 if(attribute[0] == EGL_IMAGE_PRESERVED_KHR)
1159 {
Nicolas Capens48908cb2018-01-08 13:07:14 -05001160 imagePreserved = static_cast<EGLenum>(attribute[1]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001161 }
1162 else if(attribute[0] == EGL_GL_TEXTURE_LEVEL_KHR)
1163 {
Nicolas Capens48908cb2018-01-08 13:07:14 -05001164 textureLevel = static_cast<GLuint>(attribute[1]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001165 }
1166 else
1167 {
1168 return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR);
1169 }
1170 }
1171 }
1172
Stephen Whitee6ab01f2019-04-04 14:31:25 -04001173 #if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001174 if(target == EGL_NATIVE_BUFFER_ANDROID)
1175 {
1176 ANativeWindowBuffer *nativeBuffer = reinterpret_cast<ANativeWindowBuffer*>(buffer);
1177
1178 if(!nativeBuffer || GLPixelFormatFromAndroid(nativeBuffer->format) == GL_NONE)
1179 {
Alistair Strachanc28d28a2018-03-24 12:24:00 -07001180 ERR("%s badness unsupported HAL format=%x", __FUNCTION__, nativeBuffer ? nativeBuffer->format : 0);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001181 return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR);
1182 }
1183
Nicolas Capens58df2f62016-06-07 14:48:56 -04001184 Image *image = new AndroidNativeImage(nativeBuffer);
1185 EGLImageKHR eglImage = display->createSharedImage(image);
1186
1187 return success(eglImage);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001188 }
1189 #endif
1190
Nicolas Capens3a795c62016-06-30 10:38:12 -04001191 GLuint name = static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer));
Nicolas Capens0bac2852016-05-07 06:09:58 -04001192
1193 if(name == 0)
1194 {
1195 return error(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1196 }
1197
1198 EGLenum validationResult = context->validateSharedImage(target, name, textureLevel);
1199
1200 if(validationResult != EGL_SUCCESS)
1201 {
1202 return error(validationResult, EGL_NO_IMAGE_KHR);
1203 }
1204
Nicolas Capens58df2f62016-06-07 14:48:56 -04001205 Image *image = context->createSharedImage(target, name, textureLevel);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001206
1207 if(!image)
1208 {
1209 return error(EGL_BAD_MATCH, EGL_NO_IMAGE_KHR);
1210 }
1211
1212 if(image->getDepth() > 1)
1213 {
1214 return error(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1215 }
1216
Nicolas Capens48908cb2018-01-08 13:07:14 -05001217 EGLImage eglImage = display->createSharedImage(image);
Nicolas Capens58df2f62016-06-07 14:48:56 -04001218
1219 return success(eglImage);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001220}
1221
Nicolas Capens48908cb2018-01-08 13:07:14 -05001222EGLImageKHR CreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
1223{
1224 TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLenum target = 0x%X, buffer = %p, const EGLint attrib_list = %p)", dpy, ctx, target, buffer, attrib_list);
1225
1226 EGLAttribs attribs(attrib_list);
Nicolas Capensd7622ff2018-08-07 12:24:10 -04001227 return CreateImage(dpy, ctx, target, buffer, &attribs);
Nicolas Capens48908cb2018-01-08 13:07:14 -05001228}
1229
Nicolas Capens0bac2852016-05-07 06:09:58 -04001230EGLBoolean DestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
1231{
1232 TRACE("(EGLDisplay dpy = %p, EGLImageKHR image = %p)", dpy, image);
1233
1234 egl::Display *display = egl::Display::get(dpy);
1235
1236 if(!validateDisplay(display))
1237 {
1238 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1239 }
1240
Nicolas Capens58df2f62016-06-07 14:48:56 -04001241 if(!display->destroySharedImage(image))
Nicolas Capens0bac2852016-05-07 06:09:58 -04001242 {
1243 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1244 }
1245
Nicolas Capens0bac2852016-05-07 06:09:58 -04001246 return success(EGL_TRUE);
1247}
1248
Nicolas Capens48908cb2018-01-08 13:07:14 -05001249EGLDisplay GetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001250{
Nicolas Capens48908cb2018-01-08 13:07:14 -05001251 TRACE("(EGLenum platform = 0x%X, void *native_display = %p, const EGLAttrib *attrib_list = %p)", platform, native_display, attrib_list);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001252
Nicolas Capens0bac2852016-05-07 06:09:58 -04001253 #if defined(__linux__) && !defined(__ANDROID__)
Alexis Hetu1d672442016-06-23 11:24:00 -04001254 switch(platform)
1255 {
Alexis Hetuc47cd432018-08-10 11:48:33 -04001256 #if defined(USE_X11)
1257 case EGL_PLATFORM_X11_EXT: break;
1258 #endif
1259 case EGL_PLATFORM_GBM_KHR: break;
Alexis Hetu1d672442016-06-23 11:24:00 -04001260 default:
1261 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
1262 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001263
Alexis Hetuc47cd432018-08-10 11:48:33 -04001264 if(platform == EGL_PLATFORM_GBM_KHR)
1265 {
1266 if(native_display != (void*)EGL_DEFAULT_DISPLAY)
1267 {
1268 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); // Unimplemented
1269 }
1270
1271 if(attrib_list && attrib_list[0] != EGL_NONE)
1272 {
1273 return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented
1274 }
1275
1276 return success(HEADLESS_DISPLAY);
1277 }
1278 #if defined(USE_X11)
1279 else if(platform == EGL_PLATFORM_X11_EXT)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001280 {
1281 if(!libX11)
1282 {
Nicolas Capensd7622ff2018-08-07 12:24:10 -04001283 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001284 }
1285
Nicolas Capensd7622ff2018-08-07 12:24:10 -04001286 if(native_display != (void*)EGL_DEFAULT_DISPLAY)
1287 {
1288 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); // Unimplemented
1289 }
1290
1291 if(attrib_list && attrib_list[0] != EGL_NONE)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001292 {
1293 return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented
1294 }
1295 }
Alexis Hetuc47cd432018-08-10 11:48:33 -04001296 #endif
Nicolas Capens0bac2852016-05-07 06:09:58 -04001297
Alexis Hetu1d672442016-06-23 11:24:00 -04001298 return success(PRIMARY_DISPLAY); // We only support the default display
1299 #else
1300 return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
1301 #endif
Nicolas Capens0bac2852016-05-07 06:09:58 -04001302}
1303
Nicolas Capens48908cb2018-01-08 13:07:14 -05001304EGLDisplay GetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001305{
Nicolas Capens48908cb2018-01-08 13:07:14 -05001306 TRACE("(EGLenum platform = 0x%X, void *native_display = %p, const EGLint *attrib_list = %p)", platform, native_display, attrib_list);
1307
1308 EGLAttribs attribs(attrib_list);
Nicolas Capensd7622ff2018-08-07 12:24:10 -04001309 return GetPlatformDisplay(platform, native_display, &attribs);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001310}
1311
Nicolas Capens48908cb2018-01-08 13:07:14 -05001312EGLSync CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001313{
Nicolas Capens48908cb2018-01-08 13:07:14 -05001314 TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLAttrib *attrib_list=%p)", dpy, type, attrib_list);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001315
1316 egl::Display *display = egl::Display::get(dpy);
1317
1318 if(!validateDisplay(display))
1319 {
1320 return error(EGL_BAD_DISPLAY, EGL_NO_SYNC_KHR);
1321 }
1322
1323 if(type != EGL_SYNC_FENCE_KHR)
1324 {
1325 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
1326 }
1327
1328 if(attrib_list && attrib_list[0] != EGL_NONE)
1329 {
1330 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
1331 }
1332
1333 egl::Context *context = egl::getCurrentContext();
1334
1335 if(!validateContext(display, context))
1336 {
1337 return error(EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
1338 }
1339
1340 EGLSyncKHR sync = display->createSync(context);
1341
1342 return success(sync);
1343}
1344
Nicolas Capens48908cb2018-01-08 13:07:14 -05001345EGLSyncKHR CreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1346{
1347 TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLint *attrib_list=%p)", dpy, type, attrib_list);
1348
1349 EGLAttribs attribs(attrib_list);
Nicolas Capensd7622ff2018-08-07 12:24:10 -04001350 return CreateSync(dpy, type, &attribs);
Nicolas Capens48908cb2018-01-08 13:07:14 -05001351}
1352
Nicolas Capens0bac2852016-05-07 06:09:58 -04001353EGLBoolean DestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1354{
1355 TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p)", dpy, sync);
1356
1357 egl::Display *display = egl::Display::get(dpy);
1358 FenceSync *eglSync = static_cast<FenceSync*>(sync);
1359
1360 if(!validateDisplay(display))
1361 {
1362 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1363 }
1364
1365 if(!display->isValidSync(eglSync))
1366 {
1367 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1368 }
1369
1370 display->destroySync(eglSync);
1371
1372 return success(EGL_TRUE);
1373}
1374
1375EGLint ClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
1376{
1377 TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint flags = %x, EGLTimeKHR value = %llx)", dpy, sync, flags, timeout);
1378
1379 egl::Display *display = egl::Display::get(dpy);
1380 FenceSync *eglSync = static_cast<FenceSync*>(sync);
1381
1382 if(!validateDisplay(display))
1383 {
1384 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1385 }
1386
1387 if(!display->isValidSync(eglSync))
1388 {
1389 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1390 }
1391
1392 (void)flags;
1393 (void)timeout;
1394
1395 if(!eglSync->isSignaled())
1396 {
1397 eglSync->wait();
1398 }
1399
1400 return success(EGL_CONDITION_SATISFIED_KHR);
1401}
1402
Nicolas Capens48908cb2018-01-08 13:07:14 -05001403EGLBoolean GetSyncAttrib(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLAttrib *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001404{
Nicolas Capens48908cb2018-01-08 13:07:14 -05001405 TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint attribute = %x, EGLAttrib *value = %p)", dpy, sync, attribute, value);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001406
1407 egl::Display *display = egl::Display::get(dpy);
1408 FenceSync *eglSync = static_cast<FenceSync*>(sync);
1409
1410 if(!validateDisplay(display))
1411 {
1412 return error(EGL_BAD_DISPLAY, EGL_FALSE);
1413 }
1414
1415 if(!display->isValidSync(eglSync))
1416 {
1417 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1418 }
1419
Alistair Strachan179c9322019-03-27 17:54:12 +09001420 if(!value)
1421 {
1422 return error(EGL_BAD_PARAMETER, EGL_FALSE);
1423 }
1424
Nicolas Capens0bac2852016-05-07 06:09:58 -04001425 switch(attribute)
1426 {
1427 case EGL_SYNC_TYPE_KHR:
1428 *value = EGL_SYNC_FENCE_KHR;
1429 return success(EGL_TRUE);
1430 case EGL_SYNC_STATUS_KHR:
1431 eglSync->wait(); // TODO: Don't block. Just poll based on sw::Query.
1432 *value = eglSync->isSignaled() ? EGL_SIGNALED_KHR : EGL_UNSIGNALED_KHR;
1433 return success(EGL_TRUE);
1434 case EGL_SYNC_CONDITION_KHR:
1435 *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
1436 return success(EGL_TRUE);
1437 default:
1438 return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1439 }
1440}
1441
Nicolas Capens48908cb2018-01-08 13:07:14 -05001442EGLBoolean GetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
1443{
1444 EGLAttrib attrib_value;
1445 EGLBoolean result = GetSyncAttrib(dpy, sync, attribute, &attrib_value);
1446 *value = static_cast<EGLint>(attrib_value);
1447 return result;
1448}
1449
Nicolas Capens0bac2852016-05-07 06:09:58 -04001450__eglMustCastToProperFunctionPointerType GetProcAddress(const char *procname)
1451{
1452 TRACE("(const char *procname = \"%s\")", procname);
1453
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001454 struct Function
Nicolas Capens0bac2852016-05-07 06:09:58 -04001455 {
1456 const char *name;
1457 __eglMustCastToProperFunctionPointerType address;
1458 };
1459
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001460 struct CompareFunctor
Nicolas Capens0bac2852016-05-07 06:09:58 -04001461 {
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001462 bool operator()(const Function &a, const Function &b) const
1463 {
1464 return strcmp(a.name, b.name) < 0;
1465 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001466 };
1467
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001468 // This array must be kept sorted with respect to strcmp(), so that binary search works correctly.
1469 // The Unix command "LC_COLLATE=C sort" will generate the correct order.
1470 static const Function eglFunctions[] =
Nicolas Capens0bac2852016-05-07 06:09:58 -04001471 {
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001472 #define FUNCTION(name) {#name, (__eglMustCastToProperFunctionPointerType)name}
1473
1474 FUNCTION(eglBindAPI),
1475 FUNCTION(eglBindTexImage),
1476 FUNCTION(eglChooseConfig),
Nicolas Capens48908cb2018-01-08 13:07:14 -05001477 FUNCTION(eglClientWaitSync),
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001478 FUNCTION(eglClientWaitSyncKHR),
1479 FUNCTION(eglCopyBuffers),
1480 FUNCTION(eglCreateContext),
Nicolas Capens48908cb2018-01-08 13:07:14 -05001481 FUNCTION(eglCreateImage),
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001482 FUNCTION(eglCreateImageKHR),
1483 FUNCTION(eglCreatePbufferFromClientBuffer),
1484 FUNCTION(eglCreatePbufferSurface),
1485 FUNCTION(eglCreatePixmapSurface),
Nicolas Capens48908cb2018-01-08 13:07:14 -05001486 FUNCTION(eglCreatePlatformPixmapSurface),
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001487 FUNCTION(eglCreatePlatformPixmapSurfaceEXT),
Nicolas Capens48908cb2018-01-08 13:07:14 -05001488 FUNCTION(eglCreatePlatformWindowSurface),
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001489 FUNCTION(eglCreatePlatformWindowSurfaceEXT),
Nicolas Capens48908cb2018-01-08 13:07:14 -05001490 FUNCTION(eglCreateSync),
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001491 FUNCTION(eglCreateSyncKHR),
1492 FUNCTION(eglCreateWindowSurface),
1493 FUNCTION(eglDestroyContext),
Nicolas Capens48908cb2018-01-08 13:07:14 -05001494 FUNCTION(eglDestroyImage),
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001495 FUNCTION(eglDestroyImageKHR),
1496 FUNCTION(eglDestroySurface),
Nicolas Capens48908cb2018-01-08 13:07:14 -05001497 FUNCTION(eglDestroySync),
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001498 FUNCTION(eglDestroySyncKHR),
1499 FUNCTION(eglGetConfigAttrib),
1500 FUNCTION(eglGetConfigs),
1501 FUNCTION(eglGetCurrentContext),
1502 FUNCTION(eglGetCurrentDisplay),
1503 FUNCTION(eglGetCurrentSurface),
1504 FUNCTION(eglGetDisplay),
1505 FUNCTION(eglGetError),
Nicolas Capens48908cb2018-01-08 13:07:14 -05001506 FUNCTION(eglGetPlatformDisplay),
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001507 FUNCTION(eglGetPlatformDisplayEXT),
1508 FUNCTION(eglGetProcAddress),
Nicolas Capens48908cb2018-01-08 13:07:14 -05001509 FUNCTION(eglGetSyncAttrib),
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001510 FUNCTION(eglGetSyncAttribKHR),
1511 FUNCTION(eglInitialize),
1512 FUNCTION(eglMakeCurrent),
1513 FUNCTION(eglQueryAPI),
1514 FUNCTION(eglQueryContext),
1515 FUNCTION(eglQueryString),
1516 FUNCTION(eglQuerySurface),
1517 FUNCTION(eglReleaseTexImage),
1518 FUNCTION(eglReleaseThread),
1519 FUNCTION(eglSurfaceAttrib),
1520 FUNCTION(eglSwapBuffers),
1521 FUNCTION(eglSwapInterval),
1522 FUNCTION(eglTerminate),
1523 FUNCTION(eglWaitClient),
1524 FUNCTION(eglWaitGL),
1525 FUNCTION(eglWaitNative),
Nicolas Capens48908cb2018-01-08 13:07:14 -05001526 FUNCTION(eglWaitSync),
1527 FUNCTION(eglWaitSyncKHR),
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001528
1529 #undef FUNCTION
1530 };
1531
1532 static const size_t numFunctions = sizeof eglFunctions / sizeof(Function);
1533 static const Function *const eglFunctionsEnd = eglFunctions + numFunctions;
1534
1535 Function needle;
1536 needle.name = procname;
1537
1538 if(procname && strncmp("egl", procname, 3) == 0)
1539 {
1540 const Function *result = std::lower_bound(eglFunctions, eglFunctionsEnd, needle, CompareFunctor());
1541 if (result != eglFunctionsEnd && strcmp(procname, result->name) == 0)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001542 {
Krzysztof Kosińskif919b862018-01-03 23:17:52 +01001543 return success((__eglMustCastToProperFunctionPointerType)result->address);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001544 }
1545 }
1546
1547 if(libGLESv2)
1548 {
1549 __eglMustCastToProperFunctionPointerType proc = libGLESv2->es2GetProcAddress(procname);
1550 if(proc) return success(proc);
1551 }
1552
1553 if(libGLES_CM)
1554 {
1555 __eglMustCastToProperFunctionPointerType proc = libGLES_CM->es1GetProcAddress(procname);
1556 if(proc) return success(proc);
1557 }
1558
1559 return success((__eglMustCastToProperFunctionPointerType)NULL);
1560}
1561}