1 | // 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" |
19 | #include "Surface.hpp" |
20 | #include "Texture.hpp" |
21 | #include "Context.hpp" |
22 | #include "common/Image.hpp" |
23 | #include "common/debug.h" |
24 | #include "Common/Version.h" |
25 | |
26 | #if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD) |
27 | #include <system/window.h> |
28 | #elif defined(USE_X11) |
29 | #include "Main/libX11.hpp" |
30 | #endif |
31 | |
32 | #include <algorithm> |
33 | #include <vector> |
34 | #include <string.h> |
35 | |
36 | namespace egl |
37 | { |
38 | namespace |
39 | { |
40 | sw::RecursiveLock *getDisplayLock(egl::Display *display) { |
41 | if (!display) return nullptr; |
42 | return display->getLock(); |
43 | } |
44 | |
45 | bool validateDisplay(egl::Display *display) |
46 | { |
47 | if(display == EGL_NO_DISPLAY) |
48 | { |
49 | return error(EGL_BAD_DISPLAY, false); |
50 | } |
51 | |
52 | if(!display->isInitialized()) |
53 | { |
54 | return error(EGL_NOT_INITIALIZED, false); |
55 | } |
56 | |
57 | return true; |
58 | } |
59 | |
60 | bool validateConfig(egl::Display *display, EGLConfig config) |
61 | { |
62 | if(!validateDisplay(display)) |
63 | { |
64 | return false; |
65 | } |
66 | |
67 | if(!display->isValidConfig(config)) |
68 | { |
69 | return error(EGL_BAD_CONFIG, false); |
70 | } |
71 | |
72 | return true; |
73 | } |
74 | |
75 | bool validateContext(egl::Display *display, egl::Context *context) |
76 | { |
77 | if(!validateDisplay(display)) |
78 | { |
79 | return false; |
80 | } |
81 | |
82 | if(!display->isValidContext(context)) |
83 | { |
84 | return error(EGL_BAD_CONTEXT, false); |
85 | } |
86 | |
87 | return true; |
88 | } |
89 | |
90 | bool validateSurface(egl::Display *display, egl::Surface *surface) |
91 | { |
92 | if(!validateDisplay(display)) |
93 | { |
94 | return false; |
95 | } |
96 | |
97 | if(!display->isValidSurface(surface)) |
98 | { |
99 | return error(EGL_BAD_SURFACE, false); |
100 | } |
101 | |
102 | return true; |
103 | } |
104 | |
105 | // Class to facilitate conversion from EGLint to EGLAttrib lists. |
106 | class EGLAttribs |
107 | { |
108 | public: |
109 | explicit EGLAttribs(const EGLint *attrib_list) |
110 | { |
111 | if(attrib_list) |
112 | { |
113 | while(*attrib_list != EGL_NONE) |
114 | { |
115 | attrib.push_back(static_cast<EGLAttrib>(*attrib_list)); |
116 | attrib_list++; |
117 | } |
118 | } |
119 | |
120 | attrib.push_back(EGL_NONE); |
121 | } |
122 | |
123 | const EGLAttrib *operator&() const |
124 | { |
125 | return &attrib[0]; |
126 | } |
127 | |
128 | private: |
129 | std::vector<EGLAttrib> attrib; |
130 | }; |
131 | } |
132 | |
133 | EGLint EGLAPIENTRY GetError(void) |
134 | { |
135 | TRACE("()" ); |
136 | |
137 | EGLint error = egl::getCurrentError(); |
138 | |
139 | if(error != EGL_SUCCESS) |
140 | { |
141 | egl::setCurrentError(EGL_SUCCESS); |
142 | } |
143 | |
144 | return error; |
145 | } |
146 | |
147 | EGLDisplay EGLAPIENTRY GetDisplay(EGLNativeDisplayType display_id) |
148 | { |
149 | TRACE("(EGLNativeDisplayType display_id = %p)" , display_id); |
150 | |
151 | if(display_id != EGL_DEFAULT_DISPLAY) |
152 | { |
153 | // FIXME: Check if display_id is the default display |
154 | } |
155 | |
156 | #if defined(__linux__) && !defined(__ANDROID__) |
157 | #if defined(USE_X11) |
158 | if(!libX11) |
159 | #endif // Non X11 linux is headless only |
160 | { |
161 | return success(HEADLESS_DISPLAY); |
162 | } |
163 | #endif |
164 | |
165 | return success(PRIMARY_DISPLAY); // We only support the default display |
166 | } |
167 | |
168 | EGLBoolean EGLAPIENTRY Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor) |
169 | { |
170 | TRACE("(EGLDisplay dpy = %p, EGLint *major = %p, EGLint *minor = %p)" , |
171 | dpy, major, minor); |
172 | |
173 | egl::Display *display = egl::Display::get(dpy); |
174 | |
175 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
176 | |
177 | if(!display) |
178 | { |
179 | return error(EGL_BAD_DISPLAY, EGL_FALSE); |
180 | } |
181 | |
182 | if(!display->initialize()) |
183 | { |
184 | return error(EGL_NOT_INITIALIZED, EGL_FALSE); |
185 | } |
186 | |
187 | if(major) *major = 1; |
188 | if(minor) *minor = 4; |
189 | |
190 | return success(EGL_TRUE); |
191 | } |
192 | |
193 | EGLBoolean EGLAPIENTRY Terminate(EGLDisplay dpy) |
194 | { |
195 | TRACE("(EGLDisplay dpy = %p)" , dpy); |
196 | |
197 | if(dpy == EGL_NO_DISPLAY) |
198 | { |
199 | return error(EGL_BAD_DISPLAY, EGL_FALSE); |
200 | } |
201 | |
202 | egl::Display *display = egl::Display::get(dpy); |
203 | |
204 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
205 | |
206 | display->terminate(); |
207 | |
208 | return success(EGL_TRUE); |
209 | } |
210 | |
211 | const char *EGLAPIENTRY QueryString(EGLDisplay dpy, EGLint name) |
212 | { |
213 | TRACE("(EGLDisplay dpy = %p, EGLint name = %d)" , dpy, name); |
214 | |
215 | if(dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) |
216 | { |
217 | return success( |
218 | "EGL_KHR_client_get_all_proc_addresses " |
219 | #if defined(__linux__) && !defined(__ANDROID__) |
220 | "EGL_KHR_platform_gbm " |
221 | #endif |
222 | #if defined(USE_X11) |
223 | "EGL_KHR_platform_x11 " |
224 | #endif |
225 | "EGL_EXT_client_extensions " |
226 | "EGL_EXT_platform_base" ); |
227 | } |
228 | |
229 | egl::Display *display = egl::Display::get(dpy); |
230 | |
231 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
232 | |
233 | if(!validateDisplay(display)) |
234 | { |
235 | return nullptr; |
236 | } |
237 | |
238 | switch(name) |
239 | { |
240 | case EGL_CLIENT_APIS: |
241 | return success("OpenGL_ES" ); |
242 | case EGL_EXTENSIONS: |
243 | return success("EGL_KHR_create_context " |
244 | "EGL_KHR_get_all_proc_addresses " |
245 | "EGL_KHR_gl_texture_2D_image " |
246 | "EGL_KHR_gl_texture_cubemap_image " |
247 | "EGL_KHR_gl_renderbuffer_image " |
248 | "EGL_KHR_fence_sync " |
249 | "EGL_KHR_image_base " |
250 | "EGL_KHR_surfaceless_context " |
251 | "EGL_ANGLE_iosurface_client_buffer " |
252 | "EGL_ANDROID_framebuffer_target " |
253 | "EGL_ANDROID_recordable" ); |
254 | case EGL_VENDOR: |
255 | return success("Google Inc." ); |
256 | case EGL_VERSION: |
257 | return success("1.4 SwiftShader " VERSION_STRING); |
258 | } |
259 | |
260 | return error(EGL_BAD_PARAMETER, (const char*)nullptr); |
261 | } |
262 | |
263 | EGLBoolean EGLAPIENTRY GetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) |
264 | { |
265 | TRACE("(EGLDisplay dpy = %p, EGLConfig *configs = %p, " |
266 | "EGLint config_size = %d, EGLint *num_config = %p)" , |
267 | dpy, configs, config_size, num_config); |
268 | |
269 | egl::Display *display = egl::Display::get(dpy); |
270 | |
271 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
272 | |
273 | if(!validateDisplay(display)) |
274 | { |
275 | return EGL_FALSE; |
276 | } |
277 | |
278 | if(!num_config) |
279 | { |
280 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
281 | } |
282 | |
283 | const EGLint attribList[] = {EGL_NONE}; |
284 | |
285 | if(!display->getConfigs(configs, attribList, config_size, num_config)) |
286 | { |
287 | return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
288 | } |
289 | |
290 | return success(EGL_TRUE); |
291 | } |
292 | |
293 | EGLBoolean EGLAPIENTRY ChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) |
294 | { |
295 | TRACE("(EGLDisplay dpy = %p, const EGLint *attrib_list = %p, " |
296 | "EGLConfig *configs = %p, EGLint config_size = %d, EGLint *num_config = %p)" , |
297 | dpy, attrib_list, configs, config_size, num_config); |
298 | |
299 | egl::Display *display = egl::Display::get(dpy); |
300 | |
301 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
302 | |
303 | if(!validateDisplay(display)) |
304 | { |
305 | return EGL_FALSE; |
306 | } |
307 | |
308 | if(!num_config) |
309 | { |
310 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
311 | } |
312 | |
313 | const EGLint attribList[] = {EGL_NONE}; |
314 | |
315 | if(!attrib_list) |
316 | { |
317 | attrib_list = attribList; |
318 | } |
319 | |
320 | if(!display->getConfigs(configs, attrib_list, config_size, num_config)) |
321 | { |
322 | return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
323 | } |
324 | |
325 | return success(EGL_TRUE); |
326 | } |
327 | |
328 | EGLBoolean EGLAPIENTRY GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) |
329 | { |
330 | TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLint attribute = %d, EGLint *value = %p)" , |
331 | dpy, config, attribute, value); |
332 | |
333 | egl::Display *display = egl::Display::get(dpy); |
334 | |
335 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
336 | |
337 | if(!validateConfig(display, config)) |
338 | { |
339 | return EGL_FALSE; |
340 | } |
341 | |
342 | if(!display->getConfigAttrib(config, attribute, value)) |
343 | { |
344 | return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
345 | } |
346 | |
347 | return success(EGL_TRUE); |
348 | } |
349 | |
350 | EGLSurface EGLAPIENTRY CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list) |
351 | { |
352 | TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_window = %p, " |
353 | "const EGLint *attrib_list = %p)" , dpy, config, native_window, attrib_list); |
354 | |
355 | egl::Display *display = egl::Display::get(dpy); |
356 | |
357 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
358 | |
359 | if(!validateConfig(display, config)) |
360 | { |
361 | return EGL_NO_SURFACE; |
362 | } |
363 | |
364 | if(!display->isValidWindow((EGLNativeWindowType)native_window)) |
365 | { |
366 | return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); |
367 | } |
368 | |
369 | return display->createWindowSurface((EGLNativeWindowType)native_window, config, attrib_list); |
370 | } |
371 | |
372 | EGLSurface EGLAPIENTRY CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list) |
373 | { |
374 | TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_window = %p, " |
375 | "const EGLint *attrib_list = %p)" , dpy, config, native_window, attrib_list); |
376 | |
377 | EGLAttribs attribs(attrib_list); |
378 | return CreatePlatformWindowSurface(dpy, config, native_window, &attribs); |
379 | } |
380 | |
381 | EGLSurface EGLAPIENTRY CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType window, const EGLint *attrib_list) |
382 | { |
383 | TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativeWindowType window = %p, " |
384 | "const EGLint *attrib_list = %p)" , dpy, config, window, attrib_list); |
385 | |
386 | EGLAttribs attribs(attrib_list); |
387 | return CreatePlatformWindowSurface(dpy, config, (void*)window, &attribs); |
388 | } |
389 | |
390 | EGLSurface EGLAPIENTRY CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) |
391 | { |
392 | TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, const EGLint *attrib_list = %p)" , |
393 | dpy, config, attrib_list); |
394 | |
395 | egl::Display *display = egl::Display::get(dpy); |
396 | |
397 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
398 | |
399 | if(!validateConfig(display, config)) |
400 | { |
401 | return EGL_NO_SURFACE; |
402 | } |
403 | |
404 | return display->createPBufferSurface(config, attrib_list); |
405 | } |
406 | |
407 | EGLSurface EGLAPIENTRY CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list) |
408 | { |
409 | TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_pixmap = %p, " |
410 | "const EGLint *attrib_list = %p)" , dpy, config, native_pixmap, attrib_list); |
411 | |
412 | egl::Display *display = egl::Display::get(dpy); |
413 | |
414 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
415 | |
416 | if(!validateConfig(display, config)) |
417 | { |
418 | return EGL_NO_SURFACE; |
419 | } |
420 | |
421 | UNIMPLEMENTED(); // FIXME |
422 | |
423 | return success(EGL_NO_SURFACE); |
424 | } |
425 | |
426 | EGLSurface EGLAPIENTRY CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list) |
427 | { |
428 | TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_pixmap = %p, " |
429 | "const EGLint *attrib_list = %p)" , dpy, config, native_pixmap, attrib_list); |
430 | |
431 | EGLAttribs attribs(attrib_list); |
432 | return CreatePlatformPixmapSurface(dpy, config, native_pixmap, &attribs); |
433 | } |
434 | |
435 | EGLSurface EGLAPIENTRY CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) |
436 | { |
437 | TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativePixmapType pixmap = %p, " |
438 | "const EGLint *attrib_list = %p)" , dpy, config, pixmap, attrib_list); |
439 | |
440 | EGLAttribs attribs(attrib_list); |
441 | return CreatePlatformPixmapSurface(dpy, config, (void*)pixmap, &attribs); |
442 | } |
443 | |
444 | EGLBoolean EGLAPIENTRY DestroySurface(EGLDisplay dpy, EGLSurface surface) |
445 | { |
446 | TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p)" , dpy, surface); |
447 | |
448 | egl::Display *display = egl::Display::get(dpy); |
449 | egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); |
450 | |
451 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
452 | |
453 | if(!validateSurface(display, eglSurface)) |
454 | { |
455 | return EGL_FALSE; |
456 | } |
457 | |
458 | if(surface == EGL_NO_SURFACE) |
459 | { |
460 | return error(EGL_BAD_SURFACE, EGL_FALSE); |
461 | } |
462 | |
463 | display->destroySurface((egl::Surface*)surface); |
464 | |
465 | return success(EGL_TRUE); |
466 | } |
467 | |
468 | EGLBoolean EGLAPIENTRY QuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) |
469 | { |
470 | TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint attribute = %d, EGLint *value = %p)" , |
471 | dpy, surface, attribute, value); |
472 | |
473 | egl::Display *display = egl::Display::get(dpy); |
474 | egl::Surface *eglSurface = (egl::Surface*)surface; |
475 | |
476 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
477 | |
478 | if(!validateSurface(display, eglSurface)) |
479 | { |
480 | return EGL_FALSE; |
481 | } |
482 | |
483 | if(surface == EGL_NO_SURFACE) |
484 | { |
485 | return error(EGL_BAD_SURFACE, EGL_FALSE); |
486 | } |
487 | |
488 | switch(attribute) |
489 | { |
490 | case EGL_VG_ALPHA_FORMAT: |
491 | *value = EGL_VG_ALPHA_FORMAT_NONPRE; // Default |
492 | break; |
493 | case EGL_VG_COLORSPACE: |
494 | *value = EGL_VG_COLORSPACE_sRGB; // Default |
495 | break; |
496 | case EGL_CONFIG_ID: |
497 | *value = eglSurface->getConfigID(); |
498 | break; |
499 | case EGL_HEIGHT: |
500 | *value = eglSurface->getHeight(); |
501 | break; |
502 | case EGL_HORIZONTAL_RESOLUTION: |
503 | *value = EGL_UNKNOWN; |
504 | break; |
505 | case EGL_LARGEST_PBUFFER: |
506 | if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified. |
507 | { |
508 | *value = eglSurface->getLargestPBuffer(); |
509 | } |
510 | break; |
511 | case EGL_MIPMAP_TEXTURE: |
512 | if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified. |
513 | { |
514 | *value = EGL_FALSE; // UNIMPLEMENTED |
515 | } |
516 | break; |
517 | case EGL_MIPMAP_LEVEL: |
518 | if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified. |
519 | { |
520 | *value = eglSurface->getMipmapLevel(); |
521 | } |
522 | break; |
523 | case EGL_MULTISAMPLE_RESOLVE: |
524 | *value = eglSurface->getMultisampleResolve(); |
525 | break; |
526 | case EGL_PIXEL_ASPECT_RATIO: |
527 | *value = eglSurface->getPixelAspectRatio(); |
528 | break; |
529 | case EGL_RENDER_BUFFER: |
530 | *value = eglSurface->getRenderBuffer(); |
531 | break; |
532 | case EGL_SWAP_BEHAVIOR: |
533 | *value = eglSurface->getSwapBehavior(); |
534 | break; |
535 | case EGL_TEXTURE_FORMAT: |
536 | if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified. |
537 | { |
538 | *value = eglSurface->getTextureFormat(); |
539 | } |
540 | break; |
541 | case EGL_TEXTURE_TARGET: |
542 | if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified. |
543 | { |
544 | *value = eglSurface->getTextureTarget(); |
545 | } |
546 | break; |
547 | case EGL_VERTICAL_RESOLUTION: |
548 | *value = EGL_UNKNOWN; |
549 | break; |
550 | case EGL_WIDTH: |
551 | *value = eglSurface->getWidth(); |
552 | break; |
553 | default: |
554 | return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
555 | } |
556 | |
557 | return success(EGL_TRUE); |
558 | } |
559 | |
560 | EGLBoolean EGLAPIENTRY BindAPI(EGLenum api) |
561 | { |
562 | TRACE("(EGLenum api = 0x%X)" , api); |
563 | |
564 | switch(api) |
565 | { |
566 | case EGL_OPENGL_API: |
567 | case EGL_OPENVG_API: |
568 | return error(EGL_BAD_PARAMETER, EGL_FALSE); // Not supported by this implementation |
569 | case EGL_OPENGL_ES_API: |
570 | break; |
571 | default: |
572 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
573 | } |
574 | |
575 | egl::setCurrentAPI(api); |
576 | |
577 | return success(EGL_TRUE); |
578 | } |
579 | |
580 | EGLenum EGLAPIENTRY QueryAPI(void) |
581 | { |
582 | TRACE("()" ); |
583 | |
584 | EGLenum API = egl::getCurrentAPI(); |
585 | |
586 | return success(API); |
587 | } |
588 | |
589 | EGLBoolean EGLAPIENTRY WaitClient(void) |
590 | { |
591 | TRACE("()" ); |
592 | |
593 | // eglWaitClient is ignored if there is no current EGL rendering context for the current rendering API. |
594 | egl::Context *context = egl::getCurrentContext(); |
595 | |
596 | if(context) |
597 | { |
598 | context->finish(); |
599 | } |
600 | |
601 | return success(EGL_TRUE); |
602 | } |
603 | |
604 | EGLBoolean EGLAPIENTRY ReleaseThread(void) |
605 | { |
606 | TRACE("()" ); |
607 | |
608 | detachThread(); |
609 | |
610 | return EGL_TRUE; // success() is not called here because it would re-allocate thread-local storage. |
611 | } |
612 | |
613 | EGLSurface EGLAPIENTRY CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) |
614 | { |
615 | TRACE("(EGLDisplay dpy = %p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = %p, " |
616 | "EGLConfig config = %p, const EGLint *attrib_list = %p)" , |
617 | dpy, buftype, buffer, config, attrib_list); |
618 | |
619 | switch(buftype) |
620 | { |
621 | case EGL_IOSURFACE_ANGLE: |
622 | { |
623 | egl::Display *display = egl::Display::get(dpy); |
624 | |
625 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
626 | |
627 | if(!validateConfig(display, config)) |
628 | { |
629 | return EGL_NO_SURFACE; |
630 | } |
631 | |
632 | return display->createPBufferSurface(config, attrib_list, buffer); |
633 | } |
634 | case EGL_OPENVG_IMAGE: |
635 | UNIMPLEMENTED(); |
636 | return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); |
637 | default: |
638 | return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); |
639 | }; |
640 | } |
641 | |
642 | EGLBoolean EGLAPIENTRY SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) |
643 | { |
644 | TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint attribute = %d, EGLint value = %d)" , |
645 | dpy, surface, attribute, value); |
646 | |
647 | egl::Display *display = egl::Display::get(dpy); |
648 | egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); |
649 | |
650 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
651 | |
652 | if(!validateSurface(display, eglSurface)) |
653 | { |
654 | return EGL_FALSE; |
655 | } |
656 | |
657 | switch(attribute) |
658 | { |
659 | case EGL_MIPMAP_LEVEL: |
660 | eglSurface->setMipmapLevel(value); |
661 | break; |
662 | case EGL_MULTISAMPLE_RESOLVE: |
663 | switch(value) |
664 | { |
665 | case EGL_MULTISAMPLE_RESOLVE_DEFAULT: |
666 | break; |
667 | case EGL_MULTISAMPLE_RESOLVE_BOX: |
668 | if(!(eglSurface->getSurfaceType() & EGL_MULTISAMPLE_RESOLVE_BOX_BIT)) |
669 | { |
670 | return error(EGL_BAD_MATCH, EGL_FALSE); |
671 | } |
672 | break; |
673 | default: |
674 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
675 | } |
676 | eglSurface->setMultisampleResolve(value); |
677 | break; |
678 | case EGL_SWAP_BEHAVIOR: |
679 | switch(value) |
680 | { |
681 | case EGL_BUFFER_DESTROYED: |
682 | break; |
683 | case EGL_BUFFER_PRESERVED: |
684 | if(!(eglSurface->getSurfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)) |
685 | { |
686 | return error(EGL_BAD_MATCH, EGL_FALSE); |
687 | } |
688 | break; |
689 | default: |
690 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
691 | } |
692 | eglSurface->setSwapBehavior(value); |
693 | break; |
694 | default: |
695 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
696 | } |
697 | |
698 | return success(EGL_TRUE); |
699 | } |
700 | |
701 | EGLBoolean EGLAPIENTRY BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) |
702 | { |
703 | TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint buffer = %d)" , dpy, surface, buffer); |
704 | |
705 | egl::Display *display = egl::Display::get(dpy); |
706 | egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); |
707 | |
708 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
709 | |
710 | if(!validateSurface(display, eglSurface)) |
711 | { |
712 | return EGL_FALSE; |
713 | } |
714 | |
715 | if(buffer != EGL_BACK_BUFFER) |
716 | { |
717 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
718 | } |
719 | |
720 | if(surface == EGL_NO_SURFACE || eglSurface->isWindowSurface()) |
721 | { |
722 | return error(EGL_BAD_SURFACE, EGL_FALSE); |
723 | } |
724 | |
725 | if(eglSurface->getBoundTexture()) |
726 | { |
727 | return error(EGL_BAD_ACCESS, EGL_FALSE); |
728 | } |
729 | |
730 | if(eglSurface->getTextureFormat() == EGL_NO_TEXTURE) |
731 | { |
732 | return error(EGL_BAD_MATCH, EGL_FALSE); |
733 | } |
734 | |
735 | egl::Context *context = egl::getCurrentContext(); |
736 | |
737 | if(context) |
738 | { |
739 | context->bindTexImage(eglSurface); |
740 | } |
741 | |
742 | return success(EGL_TRUE); |
743 | } |
744 | |
745 | EGLBoolean EGLAPIENTRY ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) |
746 | { |
747 | TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint buffer = %d)" , dpy, surface, buffer); |
748 | |
749 | egl::Display *display = egl::Display::get(dpy); |
750 | egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); |
751 | |
752 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
753 | |
754 | if(!validateSurface(display, eglSurface)) |
755 | { |
756 | return EGL_FALSE; |
757 | } |
758 | |
759 | if(buffer != EGL_BACK_BUFFER) |
760 | { |
761 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
762 | } |
763 | |
764 | if(surface == EGL_NO_SURFACE || eglSurface->isWindowSurface()) |
765 | { |
766 | return error(EGL_BAD_SURFACE, EGL_FALSE); |
767 | } |
768 | |
769 | if(eglSurface->getTextureFormat() == EGL_NO_TEXTURE) |
770 | { |
771 | return error(EGL_BAD_MATCH, EGL_FALSE); |
772 | } |
773 | |
774 | egl::Texture *texture = eglSurface->getBoundTexture(); |
775 | |
776 | if(texture) |
777 | { |
778 | texture->releaseTexImage(); |
779 | } |
780 | |
781 | return success(EGL_TRUE); |
782 | } |
783 | |
784 | EGLBoolean EGLAPIENTRY SwapInterval(EGLDisplay dpy, EGLint interval) |
785 | { |
786 | TRACE("(EGLDisplay dpy = %p, EGLint interval = %d)" , dpy, interval); |
787 | |
788 | egl::Display *display = egl::Display::get(dpy); |
789 | egl::Context *context = egl::getCurrentContext(); |
790 | |
791 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
792 | |
793 | if(!validateContext(display, context)) |
794 | { |
795 | return EGL_FALSE; |
796 | } |
797 | |
798 | egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface()); |
799 | |
800 | if(!draw_surface) |
801 | { |
802 | return error(EGL_BAD_SURFACE, EGL_FALSE); |
803 | } |
804 | |
805 | draw_surface->setSwapInterval(interval); |
806 | |
807 | return success(EGL_TRUE); |
808 | } |
809 | |
810 | EGLContext EGLAPIENTRY CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) |
811 | { |
812 | TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLContext share_context = %p, " |
813 | "const EGLint *attrib_list = %p)" , dpy, config, share_context, attrib_list); |
814 | |
815 | EGLint majorVersion = 1; |
816 | EGLint minorVersion = 0; |
817 | |
818 | if(attrib_list) |
819 | { |
820 | for(const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) |
821 | { |
822 | switch(attribute[0]) |
823 | { |
824 | case EGL_CONTEXT_MAJOR_VERSION_KHR: // This token is an alias for EGL_CONTEXT_CLIENT_VERSION |
825 | majorVersion = attribute[1]; |
826 | break; |
827 | case EGL_CONTEXT_MINOR_VERSION_KHR: |
828 | minorVersion = attribute[1]; |
829 | break; |
830 | case EGL_CONTEXT_FLAGS_KHR: |
831 | switch(attribute[1]) |
832 | { |
833 | case EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR: |
834 | // According to the EGL_KHR_create_context spec: |
835 | // "Khronos is still defining the expected and required features of debug contexts, so |
836 | // implementations are currently free to implement "debug contexts" with little or no debug |
837 | // functionality. However, OpenGL and OpenGL ES implementations supporting the GL_KHR_debug |
838 | // extension should enable it when this bit is set." |
839 | break; |
840 | case EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR: |
841 | case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR: |
842 | // These bits are for OpenGL contexts only, not OpenGL ES contexts |
843 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
844 | default: |
845 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
846 | } |
847 | break; |
848 | case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR: |
849 | switch(attribute[1]) |
850 | { |
851 | case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR: |
852 | case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR: |
853 | // These bits are for OpenGL contexts only, not OpenGL ES contexts |
854 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
855 | default: |
856 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
857 | } |
858 | break; |
859 | case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR: |
860 | switch(attribute[1]) |
861 | { |
862 | case EGL_NO_RESET_NOTIFICATION_KHR: |
863 | case EGL_LOSE_CONTEXT_ON_RESET_KHR: |
864 | // These bits are for OpenGL contexts only, not OpenGL ES contexts |
865 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
866 | default: |
867 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
868 | } |
869 | break; |
870 | default: |
871 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
872 | } |
873 | } |
874 | } |
875 | |
876 | switch(majorVersion) |
877 | { |
878 | case 1: |
879 | if(minorVersion != 0 && minorVersion != 1) |
880 | { |
881 | // 1.X: Only OpenGL ES 1.0 and 1.1 contexts are supported |
882 | return error(EGL_BAD_MATCH, EGL_NO_CONTEXT); |
883 | } |
884 | break; |
885 | case 2: |
886 | case 3: |
887 | if(minorVersion != 0) |
888 | { |
889 | // 2.X and 3.X: Only OpenGL ES 2.0 and 3.0 contexts are currently supported |
890 | return error(EGL_BAD_MATCH, EGL_NO_CONTEXT); |
891 | } |
892 | break; |
893 | default: |
894 | return error(EGL_BAD_MATCH, EGL_NO_CONTEXT); |
895 | } |
896 | |
897 | egl::Display *display = egl::Display::get(dpy); |
898 | egl::Context *shareContext = static_cast<egl::Context*>(share_context); |
899 | |
900 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
901 | |
902 | if(!validateConfig(display, config)) |
903 | { |
904 | return EGL_NO_CONTEXT; |
905 | } |
906 | |
907 | // Allow sharing between different context versions >= 2.0, but isolate 1.x |
908 | // contexts from 2.0+. Strict matching between context versions >= 2.0 is |
909 | // confusing for apps to navigate because of version promotion. |
910 | if(shareContext && ((shareContext->getClientVersion() >= 2) ^ (majorVersion >= 2))) |
911 | { |
912 | return error(EGL_BAD_CONTEXT, EGL_NO_CONTEXT); |
913 | } |
914 | |
915 | return display->createContext(config, shareContext, majorVersion); |
916 | } |
917 | |
918 | EGLBoolean EGLAPIENTRY DestroyContext(EGLDisplay dpy, EGLContext ctx) |
919 | { |
920 | TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p)" , dpy, ctx); |
921 | |
922 | egl::Display *display = egl::Display::get(dpy); |
923 | egl::Context *context = static_cast<egl::Context*>(ctx); |
924 | |
925 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
926 | |
927 | if(!validateContext(display, context)) |
928 | { |
929 | return EGL_FALSE; |
930 | } |
931 | |
932 | if(ctx == EGL_NO_CONTEXT) |
933 | { |
934 | return error(EGL_BAD_CONTEXT, EGL_FALSE); |
935 | } |
936 | |
937 | display->destroyContext(context); |
938 | |
939 | return success(EGL_TRUE); |
940 | } |
941 | |
942 | EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) |
943 | { |
944 | TRACE("(EGLDisplay dpy = %p, EGLSurface draw = %p, EGLSurface read = %p, EGLContext ctx = %p)" , |
945 | dpy, draw, read, ctx); |
946 | |
947 | egl::Display *display = egl::Display::get(dpy); |
948 | egl::Context *context = static_cast<egl::Context*>(ctx); |
949 | egl::Surface *drawSurface = static_cast<egl::Surface*>(draw); |
950 | egl::Surface *readSurface = static_cast<egl::Surface*>(read); |
951 | |
952 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
953 | |
954 | if(ctx != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) |
955 | { |
956 | if(!validateDisplay(display)) |
957 | { |
958 | return EGL_FALSE; |
959 | } |
960 | } |
961 | |
962 | if(ctx == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)) |
963 | { |
964 | return error(EGL_BAD_MATCH, EGL_FALSE); |
965 | } |
966 | |
967 | if(ctx != EGL_NO_CONTEXT && !validateContext(display, context)) |
968 | { |
969 | return EGL_FALSE; |
970 | } |
971 | |
972 | if((draw != EGL_NO_SURFACE && !validateSurface(display, drawSurface)) || |
973 | (read != EGL_NO_SURFACE && !validateSurface(display, readSurface))) |
974 | { |
975 | return EGL_FALSE; |
976 | } |
977 | |
978 | if((draw != EGL_NO_SURFACE) ^ (read != EGL_NO_SURFACE)) |
979 | { |
980 | return error(EGL_BAD_MATCH, EGL_FALSE); |
981 | } |
982 | |
983 | if(draw != read) |
984 | { |
985 | UNIMPLEMENTED(); // FIXME |
986 | } |
987 | |
988 | egl::setCurrentDrawSurface(drawSurface); |
989 | egl::setCurrentReadSurface(readSurface); |
990 | egl::setCurrentContext(context); |
991 | |
992 | if(context) |
993 | { |
994 | context->makeCurrent(drawSurface); |
995 | } |
996 | |
997 | return success(EGL_TRUE); |
998 | } |
999 | |
1000 | EGLContext EGLAPIENTRY GetCurrentContext(void) |
1001 | { |
1002 | TRACE("()" ); |
1003 | |
1004 | EGLContext context = egl::getCurrentContext(); |
1005 | |
1006 | return success(context); |
1007 | } |
1008 | |
1009 | EGLSurface EGLAPIENTRY GetCurrentSurface(EGLint readdraw) |
1010 | { |
1011 | TRACE("(EGLint readdraw = %d)" , readdraw); |
1012 | |
1013 | if(readdraw == EGL_READ) |
1014 | { |
1015 | EGLSurface read = egl::getCurrentReadSurface(); |
1016 | return success(read); |
1017 | } |
1018 | else if(readdraw == EGL_DRAW) |
1019 | { |
1020 | EGLSurface draw = egl::getCurrentDrawSurface(); |
1021 | return success(draw); |
1022 | } |
1023 | else |
1024 | { |
1025 | return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); |
1026 | } |
1027 | } |
1028 | |
1029 | EGLDisplay EGLAPIENTRY GetCurrentDisplay(void) |
1030 | { |
1031 | TRACE("()" ); |
1032 | |
1033 | egl::Context *context = egl::getCurrentContext(); |
1034 | |
1035 | if(!context) |
1036 | { |
1037 | return success(EGL_NO_DISPLAY); |
1038 | } |
1039 | |
1040 | egl::Display *display = context->getDisplay(); |
1041 | |
1042 | if(!display) |
1043 | { |
1044 | return error(EGL_BAD_ACCESS, EGL_NO_DISPLAY); |
1045 | } |
1046 | |
1047 | return success(display->getEGLDisplay()); |
1048 | } |
1049 | |
1050 | EGLBoolean EGLAPIENTRY QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) |
1051 | { |
1052 | TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLint attribute = %d, EGLint *value = %p)" , |
1053 | dpy, ctx, attribute, value); |
1054 | |
1055 | egl::Display *display = egl::Display::get(dpy); |
1056 | egl::Context *context = static_cast<egl::Context*>(ctx); |
1057 | |
1058 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
1059 | |
1060 | if(!validateContext(display, context)) |
1061 | { |
1062 | return EGL_FALSE; |
1063 | } |
1064 | |
1065 | switch(attribute) |
1066 | { |
1067 | case EGL_CONFIG_ID: |
1068 | *value = context->getConfigID(); |
1069 | break; |
1070 | case EGL_CONTEXT_CLIENT_TYPE: |
1071 | *value = egl::getCurrentAPI(); |
1072 | break; |
1073 | case EGL_CONTEXT_CLIENT_VERSION: |
1074 | *value = context->getClientVersion(); |
1075 | break; |
1076 | case EGL_RENDER_BUFFER: |
1077 | *value = EGL_BACK_BUFFER; |
1078 | break; |
1079 | default: |
1080 | return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
1081 | } |
1082 | |
1083 | return success(EGL_TRUE); |
1084 | } |
1085 | |
1086 | EGLBoolean EGLAPIENTRY WaitGL(void) |
1087 | { |
1088 | TRACE("()" ); |
1089 | |
1090 | // glWaitGL is ignored if there is no current EGL rendering context for OpenGL ES. |
1091 | egl::Context *context = egl::getCurrentContext(); |
1092 | |
1093 | if(context) |
1094 | { |
1095 | context->finish(); |
1096 | } |
1097 | |
1098 | return success(EGL_TRUE); |
1099 | } |
1100 | |
1101 | EGLBoolean EGLAPIENTRY WaitNative(EGLint engine) |
1102 | { |
1103 | TRACE("(EGLint engine = %d)" , engine); |
1104 | |
1105 | if(engine != EGL_CORE_NATIVE_ENGINE) |
1106 | { |
1107 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
1108 | } |
1109 | |
1110 | // eglWaitNative is ignored if there is no current EGL rendering context. |
1111 | egl::Context *context = egl::getCurrentContext(); |
1112 | |
1113 | if(context) |
1114 | { |
1115 | #if defined(USE_X11) |
1116 | egl::Display *display = context->getDisplay(); |
1117 | |
1118 | if(!display) |
1119 | { |
1120 | return error(EGL_BAD_DISPLAY, EGL_FALSE); |
1121 | } |
1122 | |
1123 | libX11->XSync((::Display*)display->getNativeDisplay(), False); |
1124 | #else |
1125 | UNIMPLEMENTED(); |
1126 | #endif |
1127 | } |
1128 | |
1129 | return success(EGL_TRUE); |
1130 | } |
1131 | |
1132 | EGLBoolean EGLAPIENTRY SwapBuffers(EGLDisplay dpy, EGLSurface surface) |
1133 | { |
1134 | TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p)" , dpy, surface); |
1135 | |
1136 | egl::Display *display = egl::Display::get(dpy); |
1137 | egl::Surface *eglSurface = (egl::Surface*)surface; |
1138 | |
1139 | { |
1140 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
1141 | |
1142 | if(!validateSurface(display, eglSurface)) |
1143 | { |
1144 | return EGL_FALSE; |
1145 | } |
1146 | } |
1147 | |
1148 | if(surface == EGL_NO_SURFACE) |
1149 | { |
1150 | return error(EGL_BAD_SURFACE, EGL_FALSE); |
1151 | } |
1152 | |
1153 | eglSurface->swap(); |
1154 | |
1155 | return success(EGL_TRUE); |
1156 | } |
1157 | |
1158 | EGLBoolean EGLAPIENTRY CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) |
1159 | { |
1160 | TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLNativePixmapType target = %p)" , dpy, surface, target); |
1161 | |
1162 | egl::Display *display = egl::Display::get(dpy); |
1163 | egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); |
1164 | |
1165 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
1166 | |
1167 | if(!validateSurface(display, eglSurface)) |
1168 | { |
1169 | return EGL_FALSE; |
1170 | } |
1171 | |
1172 | UNIMPLEMENTED(); // FIXME |
1173 | |
1174 | return success(EGL_FALSE); |
1175 | } |
1176 | |
1177 | EGLImage EGLAPIENTRY CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list) |
1178 | { |
1179 | TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLenum target = 0x%X, buffer = %p, const EGLAttrib *attrib_list = %p)" , dpy, ctx, target, buffer, attrib_list); |
1180 | |
1181 | egl::Display *display = egl::Display::get(dpy); |
1182 | egl::Context *context = static_cast<egl::Context*>(ctx); |
1183 | |
1184 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
1185 | |
1186 | if(!validateDisplay(display)) |
1187 | { |
1188 | return error(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR); |
1189 | } |
1190 | |
1191 | if(context != EGL_NO_CONTEXT && !display->isValidContext(context)) |
1192 | { |
1193 | return error(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR); |
1194 | } |
1195 | |
1196 | EGLenum imagePreserved = EGL_FALSE; |
1197 | (void)imagePreserved; // currently unused |
1198 | |
1199 | GLuint textureLevel = 0; |
1200 | if(attrib_list) |
1201 | { |
1202 | for(const EGLAttrib *attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) |
1203 | { |
1204 | if(attribute[0] == EGL_IMAGE_PRESERVED_KHR) |
1205 | { |
1206 | imagePreserved = static_cast<EGLenum>(attribute[1]); |
1207 | } |
1208 | else if(attribute[0] == EGL_GL_TEXTURE_LEVEL_KHR) |
1209 | { |
1210 | textureLevel = static_cast<GLuint>(attribute[1]); |
1211 | } |
1212 | else |
1213 | { |
1214 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR); |
1215 | } |
1216 | } |
1217 | } |
1218 | |
1219 | #if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD) |
1220 | if(target == EGL_NATIVE_BUFFER_ANDROID) |
1221 | { |
1222 | ANativeWindowBuffer *nativeBuffer = reinterpret_cast<ANativeWindowBuffer*>(buffer); |
1223 | |
1224 | if(!nativeBuffer || GLPixelFormatFromAndroid(nativeBuffer->format) == GL_NONE) |
1225 | { |
1226 | ERR("%s badness unsupported HAL format=%x" , __FUNCTION__, nativeBuffer ? nativeBuffer->format : 0); |
1227 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR); |
1228 | } |
1229 | |
1230 | Image *image = new AndroidNativeImage(nativeBuffer); |
1231 | EGLImageKHR eglImage = display->createSharedImage(image); |
1232 | |
1233 | return success(eglImage); |
1234 | } |
1235 | #endif |
1236 | |
1237 | GLuint name = static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer)); |
1238 | |
1239 | if(name == 0) |
1240 | { |
1241 | return error(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); |
1242 | } |
1243 | |
1244 | EGLenum validationResult = context->validateSharedImage(target, name, textureLevel); |
1245 | |
1246 | if(validationResult != EGL_SUCCESS) |
1247 | { |
1248 | return error(validationResult, EGL_NO_IMAGE_KHR); |
1249 | } |
1250 | |
1251 | Image *image = context->createSharedImage(target, name, textureLevel); |
1252 | |
1253 | if(!image) |
1254 | { |
1255 | return error(EGL_BAD_MATCH, EGL_NO_IMAGE_KHR); |
1256 | } |
1257 | |
1258 | if(image->getDepth() > 1) |
1259 | { |
1260 | return error(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); |
1261 | } |
1262 | |
1263 | EGLImage eglImage = display->createSharedImage(image); |
1264 | |
1265 | return success(eglImage); |
1266 | } |
1267 | |
1268 | EGLImageKHR EGLAPIENTRY CreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) |
1269 | { |
1270 | TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLenum target = 0x%X, buffer = %p, const EGLint attrib_list = %p)" , dpy, ctx, target, buffer, attrib_list); |
1271 | |
1272 | EGLAttribs attribs(attrib_list); |
1273 | return CreateImage(dpy, ctx, target, buffer, &attribs); |
1274 | } |
1275 | |
1276 | EGLBoolean EGLAPIENTRY DestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) |
1277 | { |
1278 | TRACE("(EGLDisplay dpy = %p, EGLImageKHR image = %p)" , dpy, image); |
1279 | |
1280 | egl::Display *display = egl::Display::get(dpy); |
1281 | |
1282 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
1283 | |
1284 | if(!validateDisplay(display)) |
1285 | { |
1286 | return error(EGL_BAD_DISPLAY, EGL_FALSE); |
1287 | } |
1288 | |
1289 | if(!display->destroySharedImage(image)) |
1290 | { |
1291 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
1292 | } |
1293 | |
1294 | return success(EGL_TRUE); |
1295 | } |
1296 | |
1297 | EGLDisplay EGLAPIENTRY GetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list) |
1298 | { |
1299 | TRACE("(EGLenum platform = 0x%X, void *native_display = %p, const EGLAttrib *attrib_list = %p)" , platform, native_display, attrib_list); |
1300 | |
1301 | #if defined(__linux__) && !defined(__ANDROID__) |
1302 | switch(platform) |
1303 | { |
1304 | #if defined(USE_X11) |
1305 | case EGL_PLATFORM_X11_EXT: break; |
1306 | #endif |
1307 | case EGL_PLATFORM_GBM_KHR: break; |
1308 | default: |
1309 | return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); |
1310 | } |
1311 | |
1312 | if(platform == EGL_PLATFORM_GBM_KHR) |
1313 | { |
1314 | if(native_display != (void*)EGL_DEFAULT_DISPLAY) |
1315 | { |
1316 | return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); // Unimplemented |
1317 | } |
1318 | |
1319 | if(attrib_list && attrib_list[0] != EGL_NONE) |
1320 | { |
1321 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented |
1322 | } |
1323 | |
1324 | return success(HEADLESS_DISPLAY); |
1325 | } |
1326 | #if defined(USE_X11) |
1327 | else if(platform == EGL_PLATFORM_X11_EXT) |
1328 | { |
1329 | if(!libX11) |
1330 | { |
1331 | return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); |
1332 | } |
1333 | |
1334 | if(native_display != (void*)EGL_DEFAULT_DISPLAY) |
1335 | { |
1336 | return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); // Unimplemented |
1337 | } |
1338 | |
1339 | if(attrib_list && attrib_list[0] != EGL_NONE) |
1340 | { |
1341 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented |
1342 | } |
1343 | } |
1344 | #endif |
1345 | |
1346 | return success(PRIMARY_DISPLAY); // We only support the default display |
1347 | #else |
1348 | return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); |
1349 | #endif |
1350 | } |
1351 | |
1352 | EGLDisplay EGLAPIENTRY GetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) |
1353 | { |
1354 | TRACE("(EGLenum platform = 0x%X, void *native_display = %p, const EGLint *attrib_list = %p)" , platform, native_display, attrib_list); |
1355 | |
1356 | EGLAttribs attribs(attrib_list); |
1357 | return GetPlatformDisplay(platform, native_display, &attribs); |
1358 | } |
1359 | |
1360 | EGLSync EGLAPIENTRY CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list) |
1361 | { |
1362 | TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLAttrib *attrib_list=%p)" , dpy, type, attrib_list); |
1363 | |
1364 | egl::Display *display = egl::Display::get(dpy); |
1365 | |
1366 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
1367 | |
1368 | if(!validateDisplay(display)) |
1369 | { |
1370 | return error(EGL_BAD_DISPLAY, EGL_NO_SYNC_KHR); |
1371 | } |
1372 | |
1373 | if(type != EGL_SYNC_FENCE_KHR) |
1374 | { |
1375 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR); |
1376 | } |
1377 | |
1378 | if(attrib_list && attrib_list[0] != EGL_NONE) |
1379 | { |
1380 | return error(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR); |
1381 | } |
1382 | |
1383 | egl::Context *context = egl::getCurrentContext(); |
1384 | |
1385 | if(!validateContext(display, context)) |
1386 | { |
1387 | return error(EGL_BAD_MATCH, EGL_NO_SYNC_KHR); |
1388 | } |
1389 | |
1390 | EGLSyncKHR sync = display->createSync(context); |
1391 | |
1392 | return success(sync); |
1393 | } |
1394 | |
1395 | EGLSyncKHR EGLAPIENTRY CreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) |
1396 | { |
1397 | TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLint *attrib_list=%p)" , dpy, type, attrib_list); |
1398 | |
1399 | EGLAttribs attribs(attrib_list); |
1400 | return CreateSync(dpy, type, &attribs); |
1401 | } |
1402 | |
1403 | EGLBoolean EGLAPIENTRY DestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) |
1404 | { |
1405 | TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p)" , dpy, sync); |
1406 | |
1407 | egl::Display *display = egl::Display::get(dpy); |
1408 | FenceSync *eglSync = static_cast<FenceSync*>(sync); |
1409 | |
1410 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
1411 | |
1412 | if(!validateDisplay(display)) |
1413 | { |
1414 | return error(EGL_BAD_DISPLAY, EGL_FALSE); |
1415 | } |
1416 | |
1417 | if(!display->isValidSync(eglSync)) |
1418 | { |
1419 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
1420 | } |
1421 | |
1422 | display->destroySync(eglSync); |
1423 | |
1424 | return success(EGL_TRUE); |
1425 | } |
1426 | |
1427 | EGLint EGLAPIENTRY ClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) |
1428 | { |
1429 | TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint flags = %x, EGLTimeKHR value = %llx)" , dpy, sync, flags, timeout); |
1430 | |
1431 | egl::Display *display = egl::Display::get(dpy); |
1432 | FenceSync *eglSync = static_cast<FenceSync*>(sync); |
1433 | |
1434 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
1435 | |
1436 | if(!validateDisplay(display)) |
1437 | { |
1438 | return error(EGL_BAD_DISPLAY, EGL_FALSE); |
1439 | } |
1440 | |
1441 | if(!display->isValidSync(eglSync)) |
1442 | { |
1443 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
1444 | } |
1445 | |
1446 | (void)flags; |
1447 | (void)timeout; |
1448 | |
1449 | if(!eglSync->isSignaled()) |
1450 | { |
1451 | eglSync->wait(); |
1452 | } |
1453 | |
1454 | return success(EGL_CONDITION_SATISFIED_KHR); |
1455 | } |
1456 | |
1457 | EGLBoolean EGLAPIENTRY GetSyncAttrib(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLAttrib *value) |
1458 | { |
1459 | TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint attribute = %x, EGLAttrib *value = %p)" , dpy, sync, attribute, value); |
1460 | |
1461 | egl::Display *display = egl::Display::get(dpy); |
1462 | FenceSync *eglSync = static_cast<FenceSync*>(sync); |
1463 | |
1464 | RecursiveLockGuard lock(egl::getDisplayLock(display)); |
1465 | |
1466 | if(!validateDisplay(display)) |
1467 | { |
1468 | return error(EGL_BAD_DISPLAY, EGL_FALSE); |
1469 | } |
1470 | |
1471 | if(!display->isValidSync(eglSync)) |
1472 | { |
1473 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
1474 | } |
1475 | |
1476 | if(!value) |
1477 | { |
1478 | return error(EGL_BAD_PARAMETER, EGL_FALSE); |
1479 | } |
1480 | |
1481 | switch(attribute) |
1482 | { |
1483 | case EGL_SYNC_TYPE_KHR: |
1484 | *value = EGL_SYNC_FENCE_KHR; |
1485 | return success(EGL_TRUE); |
1486 | case EGL_SYNC_STATUS_KHR: |
1487 | eglSync->wait(); // TODO: Don't block. Just poll based on sw::Query. |
1488 | *value = eglSync->isSignaled() ? EGL_SIGNALED_KHR : EGL_UNSIGNALED_KHR; |
1489 | return success(EGL_TRUE); |
1490 | case EGL_SYNC_CONDITION_KHR: |
1491 | *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR; |
1492 | return success(EGL_TRUE); |
1493 | default: |
1494 | return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
1495 | } |
1496 | } |
1497 | |
1498 | EGLBoolean EGLAPIENTRY GetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) |
1499 | { |
1500 | EGLAttrib attrib_value; |
1501 | EGLBoolean result = GetSyncAttrib(dpy, sync, attribute, &attrib_value); |
1502 | *value = static_cast<EGLint>(attrib_value); |
1503 | return result; |
1504 | } |
1505 | |
1506 | __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *procname) |
1507 | { |
1508 | TRACE("(const char *procname = \"%s\")" , procname); |
1509 | |
1510 | struct Function |
1511 | { |
1512 | const char *name; |
1513 | __eglMustCastToProperFunctionPointerType address; |
1514 | }; |
1515 | |
1516 | struct CompareFunctor |
1517 | { |
1518 | bool operator()(const Function &a, const Function &b) const |
1519 | { |
1520 | return strcmp(a.name, b.name) < 0; |
1521 | } |
1522 | }; |
1523 | |
1524 | // This array must be kept sorted with respect to strcmp(), so that binary search works correctly. |
1525 | // The Unix command "LC_COLLATE=C sort" will generate the correct order. |
1526 | static const Function eglFunctions[] = |
1527 | { |
1528 | #define FUNCTION(name) {#name, (__eglMustCastToProperFunctionPointerType)name} |
1529 | |
1530 | FUNCTION(eglBindAPI), |
1531 | FUNCTION(eglBindTexImage), |
1532 | FUNCTION(eglChooseConfig), |
1533 | FUNCTION(eglClientWaitSync), |
1534 | FUNCTION(eglClientWaitSyncKHR), |
1535 | FUNCTION(eglCopyBuffers), |
1536 | FUNCTION(eglCreateContext), |
1537 | FUNCTION(eglCreateImage), |
1538 | FUNCTION(eglCreateImageKHR), |
1539 | FUNCTION(eglCreatePbufferFromClientBuffer), |
1540 | FUNCTION(eglCreatePbufferSurface), |
1541 | FUNCTION(eglCreatePixmapSurface), |
1542 | FUNCTION(eglCreatePlatformPixmapSurface), |
1543 | FUNCTION(eglCreatePlatformPixmapSurfaceEXT), |
1544 | FUNCTION(eglCreatePlatformWindowSurface), |
1545 | FUNCTION(eglCreatePlatformWindowSurfaceEXT), |
1546 | FUNCTION(eglCreateSync), |
1547 | FUNCTION(eglCreateSyncKHR), |
1548 | FUNCTION(eglCreateWindowSurface), |
1549 | FUNCTION(eglDestroyContext), |
1550 | FUNCTION(eglDestroyImage), |
1551 | FUNCTION(eglDestroyImageKHR), |
1552 | FUNCTION(eglDestroySurface), |
1553 | FUNCTION(eglDestroySync), |
1554 | FUNCTION(eglDestroySyncKHR), |
1555 | FUNCTION(eglGetConfigAttrib), |
1556 | FUNCTION(eglGetConfigs), |
1557 | FUNCTION(eglGetCurrentContext), |
1558 | FUNCTION(eglGetCurrentDisplay), |
1559 | FUNCTION(eglGetCurrentSurface), |
1560 | FUNCTION(eglGetDisplay), |
1561 | FUNCTION(eglGetError), |
1562 | FUNCTION(eglGetPlatformDisplay), |
1563 | FUNCTION(eglGetPlatformDisplayEXT), |
1564 | FUNCTION(eglGetProcAddress), |
1565 | FUNCTION(eglGetSyncAttrib), |
1566 | FUNCTION(eglGetSyncAttribKHR), |
1567 | FUNCTION(eglInitialize), |
1568 | FUNCTION(eglMakeCurrent), |
1569 | FUNCTION(eglQueryAPI), |
1570 | FUNCTION(eglQueryContext), |
1571 | FUNCTION(eglQueryString), |
1572 | FUNCTION(eglQuerySurface), |
1573 | FUNCTION(eglReleaseTexImage), |
1574 | FUNCTION(eglReleaseThread), |
1575 | FUNCTION(eglSurfaceAttrib), |
1576 | FUNCTION(eglSwapBuffers), |
1577 | FUNCTION(eglSwapInterval), |
1578 | FUNCTION(eglTerminate), |
1579 | FUNCTION(eglWaitClient), |
1580 | FUNCTION(eglWaitGL), |
1581 | FUNCTION(eglWaitNative), |
1582 | FUNCTION(eglWaitSync), |
1583 | FUNCTION(eglWaitSyncKHR), |
1584 | |
1585 | #undef FUNCTION |
1586 | }; |
1587 | |
1588 | static const size_t numFunctions = sizeof eglFunctions / sizeof(Function); |
1589 | static const Function *const eglFunctionsEnd = eglFunctions + numFunctions; |
1590 | |
1591 | Function needle; |
1592 | needle.name = procname; |
1593 | |
1594 | if(procname && strncmp("egl" , procname, 3) == 0) |
1595 | { |
1596 | const Function *result = std::lower_bound(eglFunctions, eglFunctionsEnd, needle, CompareFunctor()); |
1597 | if (result != eglFunctionsEnd && strcmp(procname, result->name) == 0) |
1598 | { |
1599 | return success((__eglMustCastToProperFunctionPointerType)result->address); |
1600 | } |
1601 | } |
1602 | |
1603 | if(libGLESv2) |
1604 | { |
1605 | __eglMustCastToProperFunctionPointerType proc = libGLESv2->es2GetProcAddress(procname); |
1606 | if(proc) return success(proc); |
1607 | } |
1608 | |
1609 | if(libGLES_CM) |
1610 | { |
1611 | __eglMustCastToProperFunctionPointerType proc = libGLES_CM->es1GetProcAddress(procname); |
1612 | if(proc) return success(proc); |
1613 | } |
1614 | |
1615 | return success((__eglMustCastToProperFunctionPointerType)NULL); |
1616 | } |
1617 | } |
1618 | |