1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "HostConnection.h" 18 #include "ThreadInfo.h" 19 #include "eglDisplay.h" 20 #include "egl_ftable.h" 21 #include <cutils/log.h> 22 #include "gralloc_cb.h" 23 #include "GLClientState.h" 24 #include "GLSharedGroup.h" 25 #include "eglContext.h" 26 #include "ClientAPIExts.h" 27 28 #include "GLEncoder.h" 29 #ifdef WITH_GLES2 30 #include "GL2Encoder.h" 31 #endif 32 33 #include <system/window.h> 34 35 template<typename T> 36 static T setErrorFunc(GLint error, T returnValue) { 37 getEGLThreadInfo()->eglError = error; 38 return returnValue; 39 } 40 41 const char * eglStrError(EGLint err) 42 { 43 switch (err){ 44 case EGL_SUCCESS: return "EGL_SUCCESS"; 45 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; 46 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; 47 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; 48 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; 49 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; 50 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; 51 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; 52 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; 53 case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; 54 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; 55 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; 56 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; 57 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; 58 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; 59 default: return "UNKNOWN"; 60 } 61 } 62 63 #define LOG_EGL_ERRORS 1 64 65 #ifdef LOG_EGL_ERRORS 66 67 #define setErrorReturn(error, retVal) \ 68 { \ 69 ALOGE("tid %d: %s(%d): error 0x%x (%s)", gettid(), __FUNCTION__, __LINE__, error, eglStrError(error)); \ 70 return setErrorFunc(error, retVal); \ 71 } 72 73 #define RETURN_ERROR(ret,err) \ 74 ALOGE("tid %d: %s(%d): error 0x%x (%s)", gettid(), __FUNCTION__, __LINE__, err, eglStrError(err)); \ 75 getEGLThreadInfo()->eglError = err; \ 76 return ret; 77 78 #else //!LOG_EGL_ERRORS 79 80 #define setErrorReturn(error, retVal) return setErrorFunc(error, retVal); 81 82 #define RETURN_ERROR(ret,err) \ 83 getEGLThreadInfo()->eglError = err; \ 84 return ret; 85 86 #endif //LOG_EGL_ERRORS 87 88 #define VALIDATE_CONFIG(cfg,ret) \ 89 if(((int)cfg<0)||((int)cfg>s_display.getNumConfigs())) { \ 90 RETURN_ERROR(ret,EGL_BAD_CONFIG); \ 91 } 92 93 #define VALIDATE_DISPLAY(dpy,ret) \ 94 if ((dpy) != (EGLDisplay)&s_display) { \ 95 RETURN_ERROR(ret, EGL_BAD_DISPLAY); \ 96 } 97 98 #define VALIDATE_DISPLAY_INIT(dpy,ret) \ 99 VALIDATE_DISPLAY(dpy, ret) \ 100 if (!s_display.initialized()) { \ 101 RETURN_ERROR(ret, EGL_NOT_INITIALIZED); \ 102 } 103 104 #define DEFINE_HOST_CONNECTION \ 105 HostConnection *hostCon = HostConnection::get(); \ 106 renderControl_encoder_context_t *rcEnc = (hostCon ? hostCon->rcEncoder() : NULL) 107 108 #define DEFINE_AND_VALIDATE_HOST_CONNECTION(ret) \ 109 HostConnection *hostCon = HostConnection::get(); \ 110 if (!hostCon) { \ 111 ALOGE("egl: Failed to get host connection\n"); \ 112 return ret; \ 113 } \ 114 renderControl_encoder_context_t *rcEnc = hostCon->rcEncoder(); \ 115 if (!rcEnc) { \ 116 ALOGE("egl: Failed to get renderControl encoder context\n"); \ 117 return ret; \ 118 } 119 120 #define VALIDATE_CONTEXT_RETURN(context,ret) \ 121 if (!context) { \ 122 RETURN_ERROR(ret,EGL_BAD_CONTEXT); \ 123 } 124 125 #define VALIDATE_SURFACE_RETURN(surface, ret) \ 126 if (surface != EGL_NO_SURFACE) { \ 127 egl_surface_t* s( static_cast<egl_surface_t*>(surface) ); \ 128 if (s->dpy != (EGLDisplay)&s_display) \ 129 setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE); \ 130 } 131 132 133 EGLContext_t::EGLContext_t(EGLDisplay dpy, EGLConfig config, EGLContext_t* shareCtx) : 134 dpy(dpy), 135 config(config), 136 read(EGL_NO_SURFACE), 137 draw(EGL_NO_SURFACE), 138 shareCtx(shareCtx), 139 rcContext(0), 140 versionString(NULL), 141 vendorString(NULL), 142 rendererString(NULL), 143 extensionString(NULL) 144 { 145 flags = 0; 146 version = 1; 147 clientState = new GLClientState(); 148 if (shareCtx) 149 sharedGroup = shareCtx->getSharedGroup(); 150 else 151 sharedGroup = GLSharedGroupPtr(new GLSharedGroup()); 152 }; 153 154 EGLContext_t::~EGLContext_t() 155 { 156 delete clientState; 157 delete [] versionString; 158 delete [] vendorString; 159 delete [] rendererString; 160 delete [] extensionString; 161 } 162 163 // ---------------------------------------------------------------------------- 164 //egl_surface_t 165 166 //we don't need to handle depth since it's handled when window created on the host 167 168 struct egl_surface_t { 169 170 EGLDisplay dpy; 171 EGLConfig config; 172 173 174 egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType); 175 virtual ~egl_surface_t(); 176 177 virtual void setSwapInterval(int interval) = 0; 178 virtual EGLBoolean swapBuffers() = 0; 179 180 EGLint getSwapBehavior() const; 181 uint32_t getRcSurface() { return rcSurface; } 182 EGLint getSurfaceType() { return surfaceType; } 183 184 EGLint getWidth(){ return width; } 185 EGLint getHeight(){ return height; } 186 void setTextureFormat(EGLint _texFormat) { texFormat = _texFormat; } 187 EGLint getTextureFormat() { return texFormat; } 188 void setTextureTarget(EGLint _texTarget) { texTarget = _texTarget; } 189 EGLint getTextureTarget() { return texTarget; } 190 191 private: 192 // 193 //Surface attributes 194 // 195 EGLint width; 196 EGLint height; 197 EGLint texFormat; 198 EGLint texTarget; 199 200 protected: 201 void setWidth(EGLint w) { width = w; } 202 void setHeight(EGLint h) { height = h; } 203 204 EGLint surfaceType; 205 uint32_t rcSurface; //handle to surface created via remote control 206 }; 207 208 egl_surface_t::egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType) 209 : dpy(dpy), config(config), surfaceType(surfaceType), rcSurface(0) 210 { 211 width = 0; 212 height = 0; 213 texFormat = EGL_NO_TEXTURE; 214 texTarget = EGL_NO_TEXTURE; 215 } 216 217 EGLint egl_surface_t::getSwapBehavior() const { 218 return EGL_BUFFER_PRESERVED; 219 } 220 221 egl_surface_t::~egl_surface_t() 222 { 223 } 224 225 // ---------------------------------------------------------------------------- 226 // egl_window_surface_t 227 228 struct egl_window_surface_t : public egl_surface_t { 229 static egl_window_surface_t* create( 230 EGLDisplay dpy, EGLConfig config, EGLint surfType, 231 ANativeWindow* window); 232 233 virtual ~egl_window_surface_t(); 234 235 virtual void setSwapInterval(int interval); 236 virtual EGLBoolean swapBuffers(); 237 238 private: 239 egl_window_surface_t( 240 EGLDisplay dpy, EGLConfig config, EGLint surfType, 241 ANativeWindow* window); 242 EGLBoolean init(); 243 244 ANativeWindow* nativeWindow; 245 android_native_buffer_t* buffer; 246 }; 247 248 egl_window_surface_t::egl_window_surface_t ( 249 EGLDisplay dpy, EGLConfig config, EGLint surfType, 250 ANativeWindow* window) 251 : egl_surface_t(dpy, config, surfType), 252 nativeWindow(window), 253 buffer(NULL) 254 { 255 // keep a reference on the window 256 nativeWindow->common.incRef(&nativeWindow->common); 257 EGLint w,h; 258 nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &w); 259 setWidth(w); 260 nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &h); 261 setHeight(h); 262 } 263 264 EGLBoolean egl_window_surface_t::init() 265 { 266 if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) { 267 setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE); 268 } 269 nativeWindow->lockBuffer(nativeWindow, buffer); 270 271 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 272 rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config, 273 getWidth(), getHeight()); 274 if (!rcSurface) { 275 ALOGE("rcCreateWindowSurface returned 0"); 276 return EGL_FALSE; 277 } 278 rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, 279 ((cb_handle_t*)(buffer->handle))->hostHandle); 280 281 return EGL_TRUE; 282 } 283 284 egl_window_surface_t* egl_window_surface_t::create( 285 EGLDisplay dpy, EGLConfig config, EGLint surfType, 286 ANativeWindow* window) 287 { 288 egl_window_surface_t* wnd = new egl_window_surface_t( 289 dpy, config, surfType, window); 290 if (wnd && !wnd->init()) { 291 delete wnd; 292 wnd = NULL; 293 } 294 return wnd; 295 } 296 297 egl_window_surface_t::~egl_window_surface_t() { 298 DEFINE_HOST_CONNECTION; 299 if (rcSurface && rcEnc) { 300 rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface); 301 } 302 if (buffer) { 303 nativeWindow->cancelBuffer(nativeWindow, buffer); 304 } 305 nativeWindow->common.decRef(&nativeWindow->common); 306 } 307 308 void egl_window_surface_t::setSwapInterval(int interval) 309 { 310 nativeWindow->setSwapInterval(nativeWindow, interval); 311 } 312 313 EGLBoolean egl_window_surface_t::swapBuffers() 314 { 315 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 316 317 rcEnc->rcFlushWindowColorBuffer(rcEnc, rcSurface); 318 319 nativeWindow->queueBuffer(nativeWindow, buffer); 320 if (nativeWindow->dequeueBuffer(nativeWindow, &buffer)) { 321 buffer = NULL; 322 setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE); 323 } 324 nativeWindow->lockBuffer(nativeWindow, buffer); 325 326 rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, 327 ((cb_handle_t *)(buffer->handle))->hostHandle); 328 329 return EGL_TRUE; 330 } 331 332 // ---------------------------------------------------------------------------- 333 //egl_pbuffer_surface_t 334 335 struct egl_pbuffer_surface_t : public egl_surface_t { 336 static egl_pbuffer_surface_t* create(EGLDisplay dpy, EGLConfig config, 337 EGLint surfType, int32_t w, int32_t h, GLenum pixelFormat); 338 339 virtual ~egl_pbuffer_surface_t(); 340 341 virtual void setSwapInterval(int interval) {} 342 virtual EGLBoolean swapBuffers() { return EGL_TRUE; } 343 344 uint32_t getRcColorBuffer() { return rcColorBuffer; } 345 346 private: 347 egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfType, 348 int32_t w, int32_t h); 349 EGLBoolean init(GLenum format); 350 351 uint32_t rcColorBuffer; 352 }; 353 354 egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config, 355 EGLint surfType, int32_t w, int32_t h) 356 : egl_surface_t(dpy, config, surfType), 357 rcColorBuffer(0) 358 { 359 setWidth(w); 360 setHeight(h); 361 } 362 363 egl_pbuffer_surface_t::~egl_pbuffer_surface_t() 364 { 365 DEFINE_HOST_CONNECTION; 366 if (rcEnc) { 367 if (rcColorBuffer) rcEnc->rcCloseColorBuffer(rcEnc, rcColorBuffer); 368 if (rcSurface) rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface); 369 } 370 } 371 372 EGLBoolean egl_pbuffer_surface_t::init(GLenum pixelFormat) 373 { 374 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 375 376 rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config, 377 getWidth(), getHeight()); 378 if (!rcSurface) { 379 ALOGE("rcCreateWindowSurface returned 0"); 380 return EGL_FALSE; 381 } 382 383 rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(), 384 pixelFormat); 385 if (!rcColorBuffer) { 386 ALOGE("rcCreateColorBuffer returned 0"); 387 return EGL_FALSE; 388 } 389 390 rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, rcColorBuffer); 391 392 return EGL_TRUE; 393 } 394 395 egl_pbuffer_surface_t* egl_pbuffer_surface_t::create(EGLDisplay dpy, 396 EGLConfig config, EGLint surfType, int32_t w, int32_t h, 397 GLenum pixelFormat) 398 { 399 egl_pbuffer_surface_t* pb = new egl_pbuffer_surface_t(dpy, config, surfType, 400 w, h); 401 if (pb && !pb->init(pixelFormat)) { 402 delete pb; 403 pb = NULL; 404 } 405 return pb; 406 } 407 408 static const char *getGLString(int glEnum) 409 { 410 EGLThreadInfo *tInfo = getEGLThreadInfo(); 411 if (!tInfo || !tInfo->currentContext) { 412 return NULL; 413 } 414 415 const char** strPtr = NULL; 416 417 #define GL_VENDOR 0x1F00 418 #define GL_RENDERER 0x1F01 419 #define GL_VERSION 0x1F02 420 #define GL_EXTENSIONS 0x1F03 421 422 switch(glEnum) { 423 case GL_VERSION: 424 strPtr = &tInfo->currentContext->versionString; 425 break; 426 case GL_VENDOR: 427 strPtr = &tInfo->currentContext->vendorString; 428 break; 429 case GL_RENDERER: 430 strPtr = &tInfo->currentContext->rendererString; 431 break; 432 case GL_EXTENSIONS: 433 strPtr = &tInfo->currentContext->extensionString; 434 break; 435 } 436 437 if (!strPtr) { 438 return NULL; 439 } 440 441 if (*strPtr != NULL) { 442 // 443 // string is already cached 444 // 445 return *strPtr; 446 } 447 448 // 449 // first query of that string - need to query host 450 // 451 DEFINE_AND_VALIDATE_HOST_CONNECTION(NULL); 452 char *hostStr = NULL; 453 int n = rcEnc->rcGetGLString(rcEnc, glEnum, NULL, 0); 454 if (n < 0) { 455 hostStr = new char[-n+1]; 456 n = rcEnc->rcGetGLString(rcEnc, glEnum, hostStr, -n); 457 if (n <= 0) { 458 delete [] hostStr; 459 hostStr = NULL; 460 } 461 } 462 463 // 464 // keep the string in the context and return its value 465 // 466 *strPtr = hostStr; 467 return hostStr; 468 } 469 470 // ---------------------------------------------------------------------------- 471 472 // The one and only supported display object. 473 static eglDisplay s_display; 474 475 static EGLClient_eglInterface s_eglIface = { 476 getThreadInfo: getEGLThreadInfo, 477 getGLString: getGLString 478 }; 479 480 #define DBG_FUNC DBG("%s\n", __FUNCTION__) 481 EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) 482 { 483 // 484 // we support only EGL_DEFAULT_DISPLAY. 485 // 486 if (display_id != EGL_DEFAULT_DISPLAY) { 487 return EGL_NO_DISPLAY; 488 } 489 490 return (EGLDisplay)&s_display; 491 } 492 493 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) 494 { 495 VALIDATE_DISPLAY(dpy,EGL_FALSE); 496 497 if (!s_display.initialize(&s_eglIface)) { 498 return EGL_FALSE; 499 } 500 if (major!=NULL) 501 *major = s_display.getVersionMajor(); 502 if (minor!=NULL) 503 *minor = s_display.getVersionMinor(); 504 return EGL_TRUE; 505 } 506 507 EGLBoolean eglTerminate(EGLDisplay dpy) 508 { 509 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 510 511 s_display.terminate(); 512 return EGL_TRUE; 513 } 514 515 EGLint eglGetError() 516 { 517 EGLint error = getEGLThreadInfo()->eglError; 518 getEGLThreadInfo()->eglError = EGL_SUCCESS; 519 return error; 520 } 521 522 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) 523 { 524 // search in EGL function table 525 for (int i=0; i<egl_num_funcs; i++) { 526 if (!strcmp(egl_funcs_by_name[i].name, procname)) { 527 return (__eglMustCastToProperFunctionPointerType)egl_funcs_by_name[i].proc; 528 } 529 } 530 531 // 532 // Make sure display is initialized before searching in client APIs 533 // 534 if (!s_display.initialized()) { 535 if (!s_display.initialize(&s_eglIface)) { 536 return NULL; 537 } 538 } 539 540 // look in gles client api's extensions table 541 return (__eglMustCastToProperFunctionPointerType)ClientAPIExts::getProcAddress(procname); 542 543 // Fail - function not found. 544 return NULL; 545 } 546 547 const char* eglQueryString(EGLDisplay dpy, EGLint name) 548 { 549 VALIDATE_DISPLAY_INIT(dpy, NULL); 550 551 return s_display.queryString(name); 552 } 553 554 EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) 555 { 556 VALIDATE_DISPLAY_INIT(dpy, NULL); 557 558 if(!num_config) { 559 RETURN_ERROR(EGL_FALSE,EGL_BAD_PARAMETER); 560 } 561 562 GLint numConfigs = s_display.getNumConfigs(); 563 if (!configs) { 564 *num_config = numConfigs; 565 return EGL_TRUE; 566 } 567 568 int i=0; 569 for (i=0 ; i<numConfigs && i<config_size ; i++) { 570 *configs++ = (EGLConfig)i; 571 } 572 *num_config = i; 573 return EGL_TRUE; 574 } 575 576 EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) 577 { 578 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 579 580 int attribs_size = 0; 581 if (attrib_list) { 582 const EGLint * attrib_p = attrib_list; 583 while (attrib_p[0] != EGL_NONE) { 584 attribs_size += 2; 585 attrib_p += 2; 586 } 587 attribs_size++; //for the terminating EGL_NONE 588 } 589 590 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 591 *num_config = rcEnc->rcChooseConfig(rcEnc, (EGLint*)attrib_list, attribs_size * sizeof(EGLint), (uint32_t*)configs, config_size); 592 593 return EGL_TRUE; 594 } 595 596 EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) 597 { 598 VALIDATE_DISPLAY_INIT(dpy, NULL); 599 VALIDATE_CONFIG(config, EGL_FALSE); 600 601 if (s_display.getConfigAttrib(config, attribute, value)) 602 { 603 return EGL_TRUE; 604 } 605 else 606 { 607 RETURN_ERROR(EGL_FALSE, EGL_BAD_ATTRIBUTE); 608 } 609 } 610 611 EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) 612 { 613 VALIDATE_DISPLAY_INIT(dpy, NULL); 614 VALIDATE_CONFIG(config, EGL_FALSE); 615 if (win == 0) { 616 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); 617 } 618 619 EGLint surfaceType; 620 if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) return EGL_FALSE; 621 622 if (!(surfaceType & EGL_WINDOW_BIT)) { 623 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); 624 } 625 626 if (static_cast<ANativeWindow*>(win)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) { 627 setErrorReturn(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); 628 } 629 630 egl_surface_t* surface = egl_window_surface_t::create( 631 &s_display, config, surfaceType, static_cast<ANativeWindow*>(win)); 632 if (!surface) { 633 setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE); 634 } 635 636 return surface; 637 } 638 639 EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) 640 { 641 VALIDATE_DISPLAY_INIT(dpy, NULL); 642 VALIDATE_CONFIG(config, EGL_FALSE); 643 644 EGLint surfaceType; 645 if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) return EGL_FALSE; 646 647 if (!(surfaceType & EGL_PBUFFER_BIT)) { 648 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); 649 } 650 651 int32_t w = 0; 652 int32_t h = 0; 653 EGLint texFormat = EGL_NO_TEXTURE; 654 EGLint texTarget = EGL_NO_TEXTURE; 655 while (attrib_list[0]) { 656 switch (attrib_list[0]) { 657 case EGL_WIDTH: 658 w = attrib_list[1]; 659 break; 660 case EGL_HEIGHT: 661 h = attrib_list[1]; 662 break; 663 case EGL_TEXTURE_FORMAT: 664 texFormat = attrib_list[1]; 665 break; 666 case EGL_TEXTURE_TARGET: 667 texTarget = attrib_list[1]; 668 break; 669 default: 670 break; 671 }; 672 attrib_list+=2; 673 } 674 if (((texFormat == EGL_NO_TEXTURE)&&(texTarget != EGL_NO_TEXTURE)) || 675 ((texFormat != EGL_NO_TEXTURE)&&(texTarget == EGL_NO_TEXTURE))) { 676 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); 677 } 678 // TODO: check EGL_TEXTURE_FORMAT - need to support eglBindTexImage 679 680 GLenum pixelFormat; 681 if (s_display.getConfigGLPixelFormat(config, &pixelFormat) == EGL_FALSE) 682 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); 683 684 egl_surface_t* surface = egl_pbuffer_surface_t::create(dpy, config, 685 surfaceType, w, h, pixelFormat); 686 if (!surface) { 687 setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE); 688 } 689 690 //setup attributes 691 surface->setTextureFormat(texFormat); 692 surface->setTextureTarget(texTarget); 693 694 return surface; 695 } 696 697 EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) 698 { 699 //XXX: Pixmap not supported. The host cannot render to a pixmap resource 700 // located on host. In order to support Pixmaps we should either punt 701 // to s/w rendering -or- let the host render to a buffer that will be 702 // copied back to guest at some sync point. None of those methods not 703 // implemented and pixmaps are not used with OpenGL anyway ... 704 return EGL_NO_SURFACE; 705 } 706 707 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface) 708 { 709 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 710 VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE); 711 712 egl_surface_t* surface(static_cast<egl_surface_t*>(eglSurface)); 713 delete surface; 714 715 return EGL_TRUE; 716 } 717 718 EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface eglSurface, EGLint attribute, EGLint *value) 719 { 720 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 721 VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE); 722 723 egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) ); 724 EGLBoolean ret = EGL_TRUE; 725 switch (attribute) { 726 case EGL_CONFIG_ID: 727 ret = s_display.getConfigAttrib(surface->config, EGL_CONFIG_ID, value); 728 break; 729 case EGL_WIDTH: 730 *value = surface->getWidth(); 731 break; 732 case EGL_HEIGHT: 733 *value = surface->getHeight(); 734 break; 735 case EGL_TEXTURE_FORMAT: 736 *value = surface->getTextureFormat(); 737 break; 738 case EGL_TEXTURE_TARGET: 739 *value = surface->getTextureTarget(); 740 break; 741 case EGL_SWAP_BEHAVIOR: 742 *value = surface->getSwapBehavior(); 743 break; 744 case EGL_LARGEST_PBUFFER: 745 // not modified for a window or pixmap surface 746 // and we ignore it when creating a PBuffer surface (default is EGL_FALSE) 747 if (surface->getSurfaceType() & EGL_PBUFFER_BIT) *value = EGL_FALSE; 748 break; 749 //TODO: complete other attributes 750 default: 751 ALOGE("eglQuerySurface %x EGL_BAD_ATTRIBUTE", attribute); 752 ret = setErrorFunc(EGL_BAD_ATTRIBUTE, EGL_FALSE); 753 break; 754 } 755 756 return ret; 757 } 758 759 EGLBoolean eglBindAPI(EGLenum api) 760 { 761 if (api != EGL_OPENGL_ES_API) 762 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 763 return EGL_TRUE; 764 } 765 766 EGLenum eglQueryAPI() 767 { 768 return EGL_OPENGL_ES_API; 769 } 770 771 EGLBoolean eglWaitClient() 772 { 773 return eglWaitGL(); 774 } 775 776 EGLBoolean eglReleaseThread() 777 { 778 EGLThreadInfo *tInfo = getEGLThreadInfo(); 779 if (tInfo && tInfo->currentContext) { 780 return eglMakeCurrent(&s_display, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); 781 } 782 return EGL_TRUE; 783 } 784 785 EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) 786 { 787 //TODO 788 ALOGW("%s not implemented", __FUNCTION__); 789 return 0; 790 } 791 792 EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) 793 { 794 //TODO 795 ALOGW("%s not implemented", __FUNCTION__); 796 return 0; 797 } 798 799 EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface eglSurface, EGLint buffer) 800 { 801 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 802 VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE); 803 if (eglSurface == EGL_NO_SURFACE) { 804 setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); 805 } 806 807 if (buffer != EGL_BACK_BUFFER) { 808 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 809 } 810 811 egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) ); 812 813 if (surface->getTextureFormat() == EGL_NO_TEXTURE) { 814 setErrorReturn(EGL_BAD_MATCH, EGL_FALSE); 815 } 816 817 if (!(surface->getSurfaceType() & EGL_PBUFFER_BIT)) { 818 setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); 819 } 820 821 //It's now safe to cast to pbuffer surface 822 egl_pbuffer_surface_t* pbSurface = (egl_pbuffer_surface_t*)surface; 823 824 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 825 rcEnc->rcBindTexture(rcEnc, pbSurface->getRcColorBuffer()); 826 827 return GL_TRUE; 828 } 829 830 EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) 831 { 832 //TODO 833 ALOGW("%s not implemented", __FUNCTION__); 834 return 0; 835 } 836 837 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) 838 { 839 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 840 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 841 842 EGLContext_t* ctx = getEGLThreadInfo()->currentContext; 843 if (!ctx) { 844 setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE); 845 } 846 if (!ctx->draw) { 847 setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); 848 } 849 egl_surface_t* draw(static_cast<egl_surface_t*>(ctx->draw)); 850 draw->setSwapInterval(interval); 851 852 rcEnc->rcFBSetSwapInterval(rcEnc, interval); //TODO: implement on the host 853 854 return EGL_TRUE; 855 } 856 857 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) 858 { 859 VALIDATE_DISPLAY_INIT(dpy, EGL_NO_CONTEXT); 860 VALIDATE_CONFIG(config, EGL_NO_CONTEXT); 861 862 EGLint version = 1; //default 863 while (attrib_list && attrib_list[0]) { 864 if (attrib_list[0] == EGL_CONTEXT_CLIENT_VERSION) version = attrib_list[1]; 865 attrib_list+=2; 866 } 867 868 uint32_t rcShareCtx = 0; 869 EGLContext_t * shareCtx = NULL; 870 if (share_context) { 871 shareCtx = static_cast<EGLContext_t*>(share_context); 872 rcShareCtx = shareCtx->rcContext; 873 if (shareCtx->dpy != dpy) 874 setErrorReturn(EGL_BAD_MATCH, EGL_NO_CONTEXT); 875 } 876 877 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_NO_CONTEXT); 878 uint32_t rcContext = rcEnc->rcCreateContext(rcEnc, (uint32_t)config, rcShareCtx, version); 879 if (!rcContext) { 880 ALOGE("rcCreateContext returned 0"); 881 setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT); 882 } 883 884 EGLContext_t * context = new EGLContext_t(dpy, config, shareCtx); 885 if (!context) 886 setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT); 887 888 context->version = version; 889 context->rcContext = rcContext; 890 891 892 return context; 893 } 894 895 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) 896 { 897 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 898 VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE); 899 900 EGLContext_t * context = static_cast<EGLContext_t*>(ctx); 901 902 if (getEGLThreadInfo()->currentContext == context) 903 { 904 eglMakeCurrent(dpy, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); 905 } 906 907 if (context->rcContext) { 908 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 909 rcEnc->rcDestroyContext(rcEnc, context->rcContext); 910 context->rcContext = 0; 911 } 912 913 delete context; 914 return EGL_TRUE; 915 } 916 917 EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) 918 { 919 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 920 VALIDATE_SURFACE_RETURN(draw, EGL_FALSE); 921 VALIDATE_SURFACE_RETURN(read, EGL_FALSE); 922 923 if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT)) 924 setErrorReturn(EGL_BAD_MATCH, EGL_FALSE); 925 if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT)) 926 setErrorReturn(EGL_BAD_MATCH, EGL_FALSE); 927 928 EGLContext_t * context = static_cast<EGLContext_t*>(ctx); 929 uint32_t ctxHandle = (context) ? context->rcContext : 0; 930 egl_surface_t * drawSurf = static_cast<egl_surface_t *>(draw); 931 uint32_t drawHandle = (drawSurf) ? drawSurf->getRcSurface() : 0; 932 egl_surface_t * readSurf = static_cast<egl_surface_t *>(read); 933 uint32_t readHandle = (readSurf) ? readSurf->getRcSurface() : 0; 934 935 // 936 // Nothing to do if no binding change has made 937 // 938 EGLThreadInfo *tInfo = getEGLThreadInfo(); 939 if (tInfo->currentContext == context && 940 (context == NULL || 941 (context && context->draw == draw && context->read == read))) { 942 return EGL_TRUE; 943 } 944 945 if (context && (context->flags & EGLContext_t::IS_CURRENT) && (context != tInfo->currentContext)) { 946 //context is current to another thread 947 setErrorReturn(EGL_BAD_ACCESS, EGL_FALSE); 948 } 949 950 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 951 if (rcEnc->rcMakeCurrent(rcEnc, ctxHandle, drawHandle, readHandle) == EGL_FALSE) { 952 ALOGE("rcMakeCurrent returned EGL_FALSE"); 953 setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE); 954 } 955 956 //Now make the local bind 957 if (context) { 958 context->draw = draw; 959 context->read = read; 960 context->flags |= EGLContext_t::IS_CURRENT; 961 //set the client state 962 if (context->version == 2) { 963 hostCon->gl2Encoder()->setClientState(context->getClientState()); 964 hostCon->gl2Encoder()->setSharedGroup(context->getSharedGroup()); 965 } 966 else { 967 hostCon->glEncoder()->setClientState(context->getClientState()); 968 hostCon->glEncoder()->setSharedGroup(context->getSharedGroup()); 969 } 970 } 971 else { 972 //release ClientState & SharedGroup 973 if (tInfo->currentContext->version == 2) { 974 hostCon->gl2Encoder()->setClientState(NULL); 975 hostCon->gl2Encoder()->setSharedGroup(GLSharedGroupPtr(NULL)); 976 } 977 else { 978 hostCon->glEncoder()->setClientState(NULL); 979 hostCon->glEncoder()->setSharedGroup(GLSharedGroupPtr(NULL)); 980 } 981 982 } 983 984 if (tInfo->currentContext) 985 tInfo->currentContext->flags &= ~EGLContext_t::IS_CURRENT; 986 987 //Now make current 988 tInfo->currentContext = context; 989 990 //Check maybe we need to init the encoder, if it's first eglMakeCurrent 991 if (tInfo->currentContext) { 992 if (tInfo->currentContext->version == 2) { 993 if (!hostCon->gl2Encoder()->isInitialized()) { 994 s_display.gles2_iface()->init(); 995 hostCon->gl2Encoder()->setInitialized(); 996 ClientAPIExts::initClientFuncs(s_display.gles2_iface(), 1); 997 } 998 } 999 else { 1000 if (!hostCon->glEncoder()->isInitialized()) { 1001 s_display.gles_iface()->init(); 1002 hostCon->glEncoder()->setInitialized(); 1003 ClientAPIExts::initClientFuncs(s_display.gles_iface(), 0); 1004 } 1005 } 1006 } 1007 1008 return EGL_TRUE; 1009 } 1010 1011 EGLContext eglGetCurrentContext() 1012 { 1013 return getEGLThreadInfo()->currentContext; 1014 } 1015 1016 EGLSurface eglGetCurrentSurface(EGLint readdraw) 1017 { 1018 EGLContext_t * context = getEGLThreadInfo()->currentContext; 1019 if (!context) 1020 return EGL_NO_SURFACE; //not an error 1021 1022 switch (readdraw) { 1023 case EGL_READ: 1024 return context->read; 1025 case EGL_DRAW: 1026 return context->draw; 1027 default: 1028 setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 1029 } 1030 } 1031 1032 EGLDisplay eglGetCurrentDisplay() 1033 { 1034 EGLContext_t * context = getEGLThreadInfo()->currentContext; 1035 if (!context) 1036 return EGL_NO_DISPLAY; //not an error 1037 1038 return context->dpy; 1039 } 1040 1041 EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) 1042 { 1043 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 1044 VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE); 1045 1046 EGLContext_t * context = static_cast<EGLContext_t*>(ctx); 1047 1048 EGLBoolean ret = EGL_TRUE; 1049 switch (attribute) { 1050 case EGL_CONFIG_ID: 1051 ret = s_display.getConfigAttrib(context->config, EGL_CONFIG_ID, value); 1052 break; 1053 case EGL_CONTEXT_CLIENT_TYPE: 1054 *value = EGL_OPENGL_ES_API; 1055 break; 1056 case EGL_CONTEXT_CLIENT_VERSION: 1057 *value = context->version; 1058 break; 1059 case EGL_RENDER_BUFFER: 1060 if (!context->draw) 1061 *value = EGL_NONE; 1062 else 1063 *value = EGL_BACK_BUFFER; //single buffer not supported 1064 break; 1065 default: 1066 ALOGE("eglQueryContext %x EGL_BAD_ATTRIBUTE", attribute); 1067 setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE); 1068 break; 1069 } 1070 1071 return ret; 1072 } 1073 1074 EGLBoolean eglWaitGL() 1075 { 1076 EGLThreadInfo *tInfo = getEGLThreadInfo(); 1077 if (!tInfo || !tInfo->currentContext) { 1078 return EGL_FALSE; 1079 } 1080 1081 if (tInfo->currentContext->version == 2) { 1082 s_display.gles2_iface()->finish(); 1083 } 1084 else { 1085 s_display.gles_iface()->finish(); 1086 } 1087 1088 return EGL_TRUE; 1089 } 1090 1091 EGLBoolean eglWaitNative(EGLint engine) 1092 { 1093 return EGL_TRUE; 1094 } 1095 1096 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface eglSurface) 1097 { 1098 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 1099 if (eglSurface == EGL_NO_SURFACE) 1100 setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); 1101 1102 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 1103 1104 egl_surface_t* d = static_cast<egl_surface_t*>(eglSurface); 1105 if (d->dpy != dpy) 1106 setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE); 1107 1108 // post the surface 1109 d->swapBuffers(); 1110 1111 hostCon->flush(); 1112 return EGL_TRUE; 1113 } 1114 1115 EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) 1116 { 1117 //TODO :later 1118 return 0; 1119 } 1120 1121 EGLBoolean eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list) 1122 { 1123 //TODO later 1124 return 0; 1125 } 1126 1127 EGLBoolean eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface) 1128 { 1129 //TODO later 1130 return 0; 1131 } 1132 1133 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) 1134 { 1135 VALIDATE_DISPLAY_INIT(dpy, EGL_NO_IMAGE_KHR); 1136 if (ctx != EGL_NO_CONTEXT) { 1137 setErrorReturn(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR); 1138 } 1139 if (target != EGL_NATIVE_BUFFER_ANDROID) { 1140 setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); 1141 } 1142 1143 android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer; 1144 1145 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) 1146 setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); 1147 1148 if (native_buffer->common.version != sizeof(android_native_buffer_t)) 1149 setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); 1150 1151 switch (native_buffer->format) { 1152 case HAL_PIXEL_FORMAT_RGBA_8888: 1153 case HAL_PIXEL_FORMAT_RGBX_8888: 1154 case HAL_PIXEL_FORMAT_RGB_888: 1155 case HAL_PIXEL_FORMAT_RGB_565: 1156 case HAL_PIXEL_FORMAT_BGRA_8888: 1157 case HAL_PIXEL_FORMAT_RGBA_5551: 1158 case HAL_PIXEL_FORMAT_RGBA_4444: 1159 break; 1160 default: 1161 setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); 1162 } 1163 1164 native_buffer->common.incRef(&native_buffer->common); 1165 return (EGLImageKHR)native_buffer; 1166 } 1167 1168 EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) 1169 { 1170 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 1171 android_native_buffer_t* native_buffer = (android_native_buffer_t*)img; 1172 1173 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) 1174 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 1175 1176 if (native_buffer->common.version != sizeof(android_native_buffer_t)) 1177 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 1178 1179 native_buffer->common.decRef(&native_buffer->common); 1180 1181 return EGL_TRUE; 1182 } 1183 1184 #define FENCE_SYNC_HANDLE (EGLSyncKHR)0xFE4CE 1185 1186 EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, 1187 const EGLint *attrib_list) 1188 { 1189 // TODO: This implementation could be faster. We should require the host EGL 1190 // to support KHR_fence_sync, or at least pipe the fence command to the host 1191 // and wait for it (probably involving a glFinish on the host) in 1192 // eglClientWaitSyncKHR. 1193 1194 VALIDATE_DISPLAY(dpy, EGL_NO_SYNC_KHR); 1195 1196 if (type != EGL_SYNC_FENCE_KHR || 1197 (attrib_list != NULL && attrib_list[0] != EGL_NONE)) { 1198 setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR); 1199 } 1200 1201 EGLThreadInfo *tInfo = getEGLThreadInfo(); 1202 if (!tInfo || !tInfo->currentContext) { 1203 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SYNC_KHR); 1204 } 1205 1206 if (tInfo->currentContext->version == 2) { 1207 s_display.gles2_iface()->finish(); 1208 } else { 1209 s_display.gles_iface()->finish(); 1210 } 1211 1212 return FENCE_SYNC_HANDLE; 1213 } 1214 1215 EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) 1216 { 1217 if (sync != FENCE_SYNC_HANDLE) { 1218 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 1219 } 1220 1221 return EGL_TRUE; 1222 } 1223 1224 EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, 1225 EGLTimeKHR timeout) 1226 { 1227 if (sync != FENCE_SYNC_HANDLE) { 1228 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 1229 } 1230 1231 return EGL_CONDITION_SATISFIED_KHR; 1232 } 1233 1234 EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, 1235 EGLint attribute, EGLint *value) 1236 { 1237 if (sync != FENCE_SYNC_HANDLE) { 1238 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 1239 } 1240 1241 switch (attribute) { 1242 case EGL_SYNC_TYPE_KHR: 1243 *value = EGL_SYNC_FENCE_KHR; 1244 return EGL_TRUE; 1245 case EGL_SYNC_STATUS_KHR: 1246 *value = EGL_SIGNALED_KHR; 1247 return EGL_TRUE; 1248 case EGL_SYNC_CONDITION_KHR: 1249 *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR; 1250 return EGL_TRUE; 1251 default: 1252 setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE); 1253 } 1254 } 1255