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