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_DEPRECATED(nativeWindow, &buffer) != NO_ERROR) { 267 setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE); 268 } 269 270 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 271 rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config, 272 getWidth(), getHeight()); 273 if (!rcSurface) { 274 ALOGE("rcCreateWindowSurface returned 0"); 275 return EGL_FALSE; 276 } 277 rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, 278 ((cb_handle_t*)(buffer->handle))->hostHandle); 279 280 return EGL_TRUE; 281 } 282 283 egl_window_surface_t* egl_window_surface_t::create( 284 EGLDisplay dpy, EGLConfig config, EGLint surfType, 285 ANativeWindow* window) 286 { 287 egl_window_surface_t* wnd = new egl_window_surface_t( 288 dpy, config, surfType, window); 289 if (wnd && !wnd->init()) { 290 delete wnd; 291 wnd = NULL; 292 } 293 return wnd; 294 } 295 296 egl_window_surface_t::~egl_window_surface_t() { 297 DEFINE_HOST_CONNECTION; 298 if (rcSurface && rcEnc) { 299 rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface); 300 } 301 if (buffer) { 302 nativeWindow->cancelBuffer_DEPRECATED(nativeWindow, buffer); 303 } 304 nativeWindow->common.decRef(&nativeWindow->common); 305 } 306 307 void egl_window_surface_t::setSwapInterval(int interval) 308 { 309 nativeWindow->setSwapInterval(nativeWindow, interval); 310 } 311 312 EGLBoolean egl_window_surface_t::swapBuffers() 313 { 314 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 315 316 rcEnc->rcFlushWindowColorBuffer(rcEnc, rcSurface); 317 318 nativeWindow->queueBuffer_DEPRECATED(nativeWindow, buffer); 319 if (nativeWindow->dequeueBuffer_DEPRECATED(nativeWindow, &buffer)) { 320 buffer = NULL; 321 setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE); 322 } 323 324 rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, 325 ((cb_handle_t *)(buffer->handle))->hostHandle); 326 327 return EGL_TRUE; 328 } 329 330 // ---------------------------------------------------------------------------- 331 //egl_pbuffer_surface_t 332 333 struct egl_pbuffer_surface_t : public egl_surface_t { 334 static egl_pbuffer_surface_t* create(EGLDisplay dpy, EGLConfig config, 335 EGLint surfType, int32_t w, int32_t h, GLenum pixelFormat); 336 337 virtual ~egl_pbuffer_surface_t(); 338 339 virtual void setSwapInterval(int interval) {} 340 virtual EGLBoolean swapBuffers() { return EGL_TRUE; } 341 342 uint32_t getRcColorBuffer() { return rcColorBuffer; } 343 344 private: 345 egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfType, 346 int32_t w, int32_t h); 347 EGLBoolean init(GLenum format); 348 349 uint32_t rcColorBuffer; 350 }; 351 352 egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config, 353 EGLint surfType, int32_t w, int32_t h) 354 : egl_surface_t(dpy, config, surfType), 355 rcColorBuffer(0) 356 { 357 setWidth(w); 358 setHeight(h); 359 } 360 361 egl_pbuffer_surface_t::~egl_pbuffer_surface_t() 362 { 363 DEFINE_HOST_CONNECTION; 364 if (rcEnc) { 365 if (rcColorBuffer) rcEnc->rcCloseColorBuffer(rcEnc, rcColorBuffer); 366 if (rcSurface) rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface); 367 } 368 } 369 370 EGLBoolean egl_pbuffer_surface_t::init(GLenum pixelFormat) 371 { 372 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 373 374 rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config, 375 getWidth(), getHeight()); 376 if (!rcSurface) { 377 ALOGE("rcCreateWindowSurface returned 0"); 378 return EGL_FALSE; 379 } 380 381 rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(), 382 pixelFormat); 383 if (!rcColorBuffer) { 384 ALOGE("rcCreateColorBuffer returned 0"); 385 return EGL_FALSE; 386 } 387 388 rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, rcColorBuffer); 389 390 return EGL_TRUE; 391 } 392 393 egl_pbuffer_surface_t* egl_pbuffer_surface_t::create(EGLDisplay dpy, 394 EGLConfig config, EGLint surfType, int32_t w, int32_t h, 395 GLenum pixelFormat) 396 { 397 egl_pbuffer_surface_t* pb = new egl_pbuffer_surface_t(dpy, config, surfType, 398 w, h); 399 if (pb && !pb->init(pixelFormat)) { 400 delete pb; 401 pb = NULL; 402 } 403 return pb; 404 } 405 406 static const char *getGLString(int glEnum) 407 { 408 EGLThreadInfo *tInfo = getEGLThreadInfo(); 409 if (!tInfo || !tInfo->currentContext) { 410 return NULL; 411 } 412 413 const char** strPtr = NULL; 414 415 #define GL_VENDOR 0x1F00 416 #define GL_RENDERER 0x1F01 417 #define GL_VERSION 0x1F02 418 #define GL_EXTENSIONS 0x1F03 419 420 switch(glEnum) { 421 case GL_VERSION: 422 strPtr = &tInfo->currentContext->versionString; 423 break; 424 case GL_VENDOR: 425 strPtr = &tInfo->currentContext->vendorString; 426 break; 427 case GL_RENDERER: 428 strPtr = &tInfo->currentContext->rendererString; 429 break; 430 case GL_EXTENSIONS: 431 strPtr = &tInfo->currentContext->extensionString; 432 break; 433 } 434 435 if (!strPtr) { 436 return NULL; 437 } 438 439 if (*strPtr != NULL) { 440 // 441 // string is already cached 442 // 443 return *strPtr; 444 } 445 446 // 447 // first query of that string - need to query host 448 // 449 DEFINE_AND_VALIDATE_HOST_CONNECTION(NULL); 450 char *hostStr = NULL; 451 int n = rcEnc->rcGetGLString(rcEnc, glEnum, NULL, 0); 452 if (n < 0) { 453 hostStr = new char[-n+1]; 454 n = rcEnc->rcGetGLString(rcEnc, glEnum, hostStr, -n); 455 if (n <= 0) { 456 delete [] hostStr; 457 hostStr = NULL; 458 } 459 } 460 461 // 462 // keep the string in the context and return its value 463 // 464 *strPtr = hostStr; 465 return hostStr; 466 } 467 468 // ---------------------------------------------------------------------------- 469 470 // The one and only supported display object. 471 static eglDisplay s_display; 472 473 static EGLClient_eglInterface s_eglIface = { 474 getThreadInfo: getEGLThreadInfo, 475 getGLString: getGLString 476 }; 477 478 #define DBG_FUNC DBG("%s\n", __FUNCTION__) 479 EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) 480 { 481 // 482 // we support only EGL_DEFAULT_DISPLAY. 483 // 484 if (display_id != EGL_DEFAULT_DISPLAY) { 485 return EGL_NO_DISPLAY; 486 } 487 488 return (EGLDisplay)&s_display; 489 } 490 491 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) 492 { 493 VALIDATE_DISPLAY(dpy,EGL_FALSE); 494 495 if (!s_display.initialize(&s_eglIface)) { 496 return EGL_FALSE; 497 } 498 if (major!=NULL) 499 *major = s_display.getVersionMajor(); 500 if (minor!=NULL) 501 *minor = s_display.getVersionMinor(); 502 return EGL_TRUE; 503 } 504 505 EGLBoolean eglTerminate(EGLDisplay dpy) 506 { 507 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 508 509 s_display.terminate(); 510 return EGL_TRUE; 511 } 512 513 EGLint eglGetError() 514 { 515 EGLint error = getEGLThreadInfo()->eglError; 516 getEGLThreadInfo()->eglError = EGL_SUCCESS; 517 return error; 518 } 519 520 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) 521 { 522 // search in EGL function table 523 for (int i=0; i<egl_num_funcs; i++) { 524 if (!strcmp(egl_funcs_by_name[i].name, procname)) { 525 return (__eglMustCastToProperFunctionPointerType)egl_funcs_by_name[i].proc; 526 } 527 } 528 529 // 530 // Make sure display is initialized before searching in client APIs 531 // 532 if (!s_display.initialized()) { 533 if (!s_display.initialize(&s_eglIface)) { 534 return NULL; 535 } 536 } 537 538 // look in gles client api's extensions table 539 return (__eglMustCastToProperFunctionPointerType)ClientAPIExts::getProcAddress(procname); 540 541 // Fail - function not found. 542 return NULL; 543 } 544 545 const char* eglQueryString(EGLDisplay dpy, EGLint name) 546 { 547 VALIDATE_DISPLAY_INIT(dpy, NULL); 548 549 return s_display.queryString(name); 550 } 551 552 EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) 553 { 554 VALIDATE_DISPLAY_INIT(dpy, NULL); 555 556 if(!num_config) { 557 RETURN_ERROR(EGL_FALSE,EGL_BAD_PARAMETER); 558 } 559 560 GLint numConfigs = s_display.getNumConfigs(); 561 if (!configs) { 562 *num_config = numConfigs; 563 return EGL_TRUE; 564 } 565 566 int i=0; 567 for (i=0 ; i<numConfigs && i<config_size ; i++) { 568 *configs++ = (EGLConfig)i; 569 } 570 *num_config = i; 571 return EGL_TRUE; 572 } 573 574 EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) 575 { 576 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 577 578 int attribs_size = 0; 579 if (attrib_list) { 580 const EGLint * attrib_p = attrib_list; 581 while (attrib_p[0] != EGL_NONE) { 582 attribs_size += 2; 583 attrib_p += 2; 584 } 585 attribs_size++; //for the terminating EGL_NONE 586 } 587 588 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 589 *num_config = rcEnc->rcChooseConfig(rcEnc, (EGLint*)attrib_list, attribs_size * sizeof(EGLint), (uint32_t*)configs, config_size); 590 591 return EGL_TRUE; 592 } 593 594 EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) 595 { 596 VALIDATE_DISPLAY_INIT(dpy, NULL); 597 VALIDATE_CONFIG(config, EGL_FALSE); 598 599 if (s_display.getConfigAttrib(config, attribute, value)) 600 { 601 return EGL_TRUE; 602 } 603 else 604 { 605 RETURN_ERROR(EGL_FALSE, EGL_BAD_ATTRIBUTE); 606 } 607 } 608 609 EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) 610 { 611 VALIDATE_DISPLAY_INIT(dpy, NULL); 612 VALIDATE_CONFIG(config, EGL_FALSE); 613 if (win == 0) { 614 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); 615 } 616 617 EGLint surfaceType; 618 if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) return EGL_FALSE; 619 620 if (!(surfaceType & EGL_WINDOW_BIT)) { 621 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); 622 } 623 624 if (static_cast<ANativeWindow*>(win)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) { 625 setErrorReturn(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); 626 } 627 628 egl_surface_t* surface = egl_window_surface_t::create( 629 &s_display, config, surfaceType, static_cast<ANativeWindow*>(win)); 630 if (!surface) { 631 setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE); 632 } 633 634 return surface; 635 } 636 637 EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) 638 { 639 VALIDATE_DISPLAY_INIT(dpy, NULL); 640 VALIDATE_CONFIG(config, EGL_FALSE); 641 642 EGLint surfaceType; 643 if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) return EGL_FALSE; 644 645 if (!(surfaceType & EGL_PBUFFER_BIT)) { 646 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); 647 } 648 649 int32_t w = 0; 650 int32_t h = 0; 651 EGLint texFormat = EGL_NO_TEXTURE; 652 EGLint texTarget = EGL_NO_TEXTURE; 653 while (attrib_list[0]) { 654 switch (attrib_list[0]) { 655 case EGL_WIDTH: 656 w = attrib_list[1]; 657 break; 658 case EGL_HEIGHT: 659 h = attrib_list[1]; 660 break; 661 case EGL_TEXTURE_FORMAT: 662 texFormat = attrib_list[1]; 663 break; 664 case EGL_TEXTURE_TARGET: 665 texTarget = attrib_list[1]; 666 break; 667 default: 668 break; 669 }; 670 attrib_list+=2; 671 } 672 if (((texFormat == EGL_NO_TEXTURE)&&(texTarget != EGL_NO_TEXTURE)) || 673 ((texFormat != EGL_NO_TEXTURE)&&(texTarget == EGL_NO_TEXTURE))) { 674 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); 675 } 676 // TODO: check EGL_TEXTURE_FORMAT - need to support eglBindTexImage 677 678 GLenum pixelFormat; 679 if (s_display.getConfigGLPixelFormat(config, &pixelFormat) == EGL_FALSE) 680 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); 681 682 egl_surface_t* surface = egl_pbuffer_surface_t::create(dpy, config, 683 surfaceType, w, h, pixelFormat); 684 if (!surface) { 685 setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE); 686 } 687 688 //setup attributes 689 surface->setTextureFormat(texFormat); 690 surface->setTextureTarget(texTarget); 691 692 return surface; 693 } 694 695 EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) 696 { 697 //XXX: Pixmap not supported. The host cannot render to a pixmap resource 698 // located on host. In order to support Pixmaps we should either punt 699 // to s/w rendering -or- let the host render to a buffer that will be 700 // copied back to guest at some sync point. None of those methods not 701 // implemented and pixmaps are not used with OpenGL anyway ... 702 return EGL_NO_SURFACE; 703 } 704 705 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface) 706 { 707 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 708 VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE); 709 710 egl_surface_t* surface(static_cast<egl_surface_t*>(eglSurface)); 711 delete surface; 712 713 return EGL_TRUE; 714 } 715 716 EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface eglSurface, EGLint attribute, EGLint *value) 717 { 718 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 719 VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE); 720 721 egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) ); 722 EGLBoolean ret = EGL_TRUE; 723 switch (attribute) { 724 case EGL_CONFIG_ID: 725 ret = s_display.getConfigAttrib(surface->config, EGL_CONFIG_ID, value); 726 break; 727 case EGL_WIDTH: 728 *value = surface->getWidth(); 729 break; 730 case EGL_HEIGHT: 731 *value = surface->getHeight(); 732 break; 733 case EGL_TEXTURE_FORMAT: 734 *value = surface->getTextureFormat(); 735 break; 736 case EGL_TEXTURE_TARGET: 737 *value = surface->getTextureTarget(); 738 break; 739 case EGL_SWAP_BEHAVIOR: 740 *value = surface->getSwapBehavior(); 741 break; 742 case EGL_LARGEST_PBUFFER: 743 // not modified for a window or pixmap surface 744 // and we ignore it when creating a PBuffer surface (default is EGL_FALSE) 745 if (surface->getSurfaceType() & EGL_PBUFFER_BIT) *value = EGL_FALSE; 746 break; 747 //TODO: complete other attributes 748 default: 749 ALOGE("eglQuerySurface %x EGL_BAD_ATTRIBUTE", attribute); 750 ret = setErrorFunc(EGL_BAD_ATTRIBUTE, EGL_FALSE); 751 break; 752 } 753 754 return ret; 755 } 756 757 EGLBoolean eglBindAPI(EGLenum api) 758 { 759 if (api != EGL_OPENGL_ES_API) 760 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 761 return EGL_TRUE; 762 } 763 764 EGLenum eglQueryAPI() 765 { 766 return EGL_OPENGL_ES_API; 767 } 768 769 EGLBoolean eglWaitClient() 770 { 771 return eglWaitGL(); 772 } 773 774 EGLBoolean eglReleaseThread() 775 { 776 EGLThreadInfo *tInfo = getEGLThreadInfo(); 777 if (tInfo && tInfo->currentContext) { 778 return eglMakeCurrent(&s_display, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); 779 } 780 return EGL_TRUE; 781 } 782 783 EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) 784 { 785 //TODO 786 ALOGW("%s not implemented", __FUNCTION__); 787 return 0; 788 } 789 790 EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) 791 { 792 //TODO 793 ALOGW("%s not implemented", __FUNCTION__); 794 return 0; 795 } 796 797 EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface eglSurface, EGLint buffer) 798 { 799 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 800 VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE); 801 if (eglSurface == EGL_NO_SURFACE) { 802 setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); 803 } 804 805 if (buffer != EGL_BACK_BUFFER) { 806 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 807 } 808 809 egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) ); 810 811 if (surface->getTextureFormat() == EGL_NO_TEXTURE) { 812 setErrorReturn(EGL_BAD_MATCH, EGL_FALSE); 813 } 814 815 if (!(surface->getSurfaceType() & EGL_PBUFFER_BIT)) { 816 setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); 817 } 818 819 //It's now safe to cast to pbuffer surface 820 egl_pbuffer_surface_t* pbSurface = (egl_pbuffer_surface_t*)surface; 821 822 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 823 rcEnc->rcBindTexture(rcEnc, pbSurface->getRcColorBuffer()); 824 825 return GL_TRUE; 826 } 827 828 EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) 829 { 830 //TODO 831 ALOGW("%s not implemented", __FUNCTION__); 832 return 0; 833 } 834 835 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) 836 { 837 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 838 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 839 840 EGLContext_t* ctx = getEGLThreadInfo()->currentContext; 841 if (!ctx) { 842 setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE); 843 } 844 if (!ctx->draw) { 845 setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); 846 } 847 egl_surface_t* draw(static_cast<egl_surface_t*>(ctx->draw)); 848 draw->setSwapInterval(interval); 849 850 rcEnc->rcFBSetSwapInterval(rcEnc, interval); //TODO: implement on the host 851 852 return EGL_TRUE; 853 } 854 855 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) 856 { 857 VALIDATE_DISPLAY_INIT(dpy, EGL_NO_CONTEXT); 858 VALIDATE_CONFIG(config, EGL_NO_CONTEXT); 859 860 EGLint version = 1; //default 861 while (attrib_list && attrib_list[0]) { 862 if (attrib_list[0] == EGL_CONTEXT_CLIENT_VERSION) version = attrib_list[1]; 863 attrib_list+=2; 864 } 865 866 uint32_t rcShareCtx = 0; 867 EGLContext_t * shareCtx = NULL; 868 if (share_context) { 869 shareCtx = static_cast<EGLContext_t*>(share_context); 870 rcShareCtx = shareCtx->rcContext; 871 if (shareCtx->dpy != dpy) 872 setErrorReturn(EGL_BAD_MATCH, EGL_NO_CONTEXT); 873 } 874 875 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_NO_CONTEXT); 876 uint32_t rcContext = rcEnc->rcCreateContext(rcEnc, (uint32_t)config, rcShareCtx, version); 877 if (!rcContext) { 878 ALOGE("rcCreateContext returned 0"); 879 setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT); 880 } 881 882 EGLContext_t * context = new EGLContext_t(dpy, config, shareCtx); 883 if (!context) 884 setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT); 885 886 context->version = version; 887 context->rcContext = rcContext; 888 889 890 return context; 891 } 892 893 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) 894 { 895 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 896 VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE); 897 898 EGLContext_t * context = static_cast<EGLContext_t*>(ctx); 899 900 if (getEGLThreadInfo()->currentContext == context) 901 { 902 eglMakeCurrent(dpy, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); 903 } 904 905 if (context->rcContext) { 906 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 907 rcEnc->rcDestroyContext(rcEnc, context->rcContext); 908 context->rcContext = 0; 909 } 910 911 delete context; 912 return EGL_TRUE; 913 } 914 915 EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) 916 { 917 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 918 VALIDATE_SURFACE_RETURN(draw, EGL_FALSE); 919 VALIDATE_SURFACE_RETURN(read, EGL_FALSE); 920 921 if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT)) 922 setErrorReturn(EGL_BAD_MATCH, EGL_FALSE); 923 if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT)) 924 setErrorReturn(EGL_BAD_MATCH, EGL_FALSE); 925 926 EGLContext_t * context = static_cast<EGLContext_t*>(ctx); 927 uint32_t ctxHandle = (context) ? context->rcContext : 0; 928 egl_surface_t * drawSurf = static_cast<egl_surface_t *>(draw); 929 uint32_t drawHandle = (drawSurf) ? drawSurf->getRcSurface() : 0; 930 egl_surface_t * readSurf = static_cast<egl_surface_t *>(read); 931 uint32_t readHandle = (readSurf) ? readSurf->getRcSurface() : 0; 932 933 // 934 // Nothing to do if no binding change has made 935 // 936 EGLThreadInfo *tInfo = getEGLThreadInfo(); 937 if (tInfo->currentContext == context && 938 (context == NULL || 939 (context && context->draw == draw && context->read == read))) { 940 return EGL_TRUE; 941 } 942 943 if (context && (context->flags & EGLContext_t::IS_CURRENT) && (context != tInfo->currentContext)) { 944 //context is current to another thread 945 setErrorReturn(EGL_BAD_ACCESS, EGL_FALSE); 946 } 947 948 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 949 if (rcEnc->rcMakeCurrent(rcEnc, ctxHandle, drawHandle, readHandle) == EGL_FALSE) { 950 ALOGE("rcMakeCurrent returned EGL_FALSE"); 951 setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE); 952 } 953 954 //Now make the local bind 955 if (context) { 956 context->draw = draw; 957 context->read = read; 958 context->flags |= EGLContext_t::IS_CURRENT; 959 //set the client state 960 if (context->version == 2) { 961 hostCon->gl2Encoder()->setClientState(context->getClientState()); 962 hostCon->gl2Encoder()->setSharedGroup(context->getSharedGroup()); 963 } 964 else { 965 hostCon->glEncoder()->setClientState(context->getClientState()); 966 hostCon->glEncoder()->setSharedGroup(context->getSharedGroup()); 967 } 968 } 969 else { 970 //release ClientState & SharedGroup 971 if (tInfo->currentContext->version == 2) { 972 hostCon->gl2Encoder()->setClientState(NULL); 973 hostCon->gl2Encoder()->setSharedGroup(GLSharedGroupPtr(NULL)); 974 } 975 else { 976 hostCon->glEncoder()->setClientState(NULL); 977 hostCon->glEncoder()->setSharedGroup(GLSharedGroupPtr(NULL)); 978 } 979 980 } 981 982 if (tInfo->currentContext) 983 tInfo->currentContext->flags &= ~EGLContext_t::IS_CURRENT; 984 985 //Now make current 986 tInfo->currentContext = context; 987 988 //Check maybe we need to init the encoder, if it's first eglMakeCurrent 989 if (tInfo->currentContext) { 990 if (tInfo->currentContext->version == 2) { 991 if (!hostCon->gl2Encoder()->isInitialized()) { 992 s_display.gles2_iface()->init(); 993 hostCon->gl2Encoder()->setInitialized(); 994 ClientAPIExts::initClientFuncs(s_display.gles2_iface(), 1); 995 } 996 } 997 else { 998 if (!hostCon->glEncoder()->isInitialized()) { 999 s_display.gles_iface()->init(); 1000 hostCon->glEncoder()->setInitialized(); 1001 ClientAPIExts::initClientFuncs(s_display.gles_iface(), 0); 1002 } 1003 } 1004 } 1005 1006 return EGL_TRUE; 1007 } 1008 1009 EGLContext eglGetCurrentContext() 1010 { 1011 return getEGLThreadInfo()->currentContext; 1012 } 1013 1014 EGLSurface eglGetCurrentSurface(EGLint readdraw) 1015 { 1016 EGLContext_t * context = getEGLThreadInfo()->currentContext; 1017 if (!context) 1018 return EGL_NO_SURFACE; //not an error 1019 1020 switch (readdraw) { 1021 case EGL_READ: 1022 return context->read; 1023 case EGL_DRAW: 1024 return context->draw; 1025 default: 1026 setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 1027 } 1028 } 1029 1030 EGLDisplay eglGetCurrentDisplay() 1031 { 1032 EGLContext_t * context = getEGLThreadInfo()->currentContext; 1033 if (!context) 1034 return EGL_NO_DISPLAY; //not an error 1035 1036 return context->dpy; 1037 } 1038 1039 EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) 1040 { 1041 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 1042 VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE); 1043 1044 EGLContext_t * context = static_cast<EGLContext_t*>(ctx); 1045 1046 EGLBoolean ret = EGL_TRUE; 1047 switch (attribute) { 1048 case EGL_CONFIG_ID: 1049 ret = s_display.getConfigAttrib(context->config, EGL_CONFIG_ID, value); 1050 break; 1051 case EGL_CONTEXT_CLIENT_TYPE: 1052 *value = EGL_OPENGL_ES_API; 1053 break; 1054 case EGL_CONTEXT_CLIENT_VERSION: 1055 *value = context->version; 1056 break; 1057 case EGL_RENDER_BUFFER: 1058 if (!context->draw) 1059 *value = EGL_NONE; 1060 else 1061 *value = EGL_BACK_BUFFER; //single buffer not supported 1062 break; 1063 default: 1064 ALOGE("eglQueryContext %x EGL_BAD_ATTRIBUTE", attribute); 1065 setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE); 1066 break; 1067 } 1068 1069 return ret; 1070 } 1071 1072 EGLBoolean eglWaitGL() 1073 { 1074 EGLThreadInfo *tInfo = getEGLThreadInfo(); 1075 if (!tInfo || !tInfo->currentContext) { 1076 return EGL_FALSE; 1077 } 1078 1079 if (tInfo->currentContext->version == 2) { 1080 s_display.gles2_iface()->finish(); 1081 } 1082 else { 1083 s_display.gles_iface()->finish(); 1084 } 1085 1086 return EGL_TRUE; 1087 } 1088 1089 EGLBoolean eglWaitNative(EGLint engine) 1090 { 1091 return EGL_TRUE; 1092 } 1093 1094 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface eglSurface) 1095 { 1096 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 1097 if (eglSurface == EGL_NO_SURFACE) 1098 setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); 1099 1100 DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); 1101 1102 egl_surface_t* d = static_cast<egl_surface_t*>(eglSurface); 1103 if (d->dpy != dpy) 1104 setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE); 1105 1106 // post the surface 1107 d->swapBuffers(); 1108 1109 hostCon->flush(); 1110 return EGL_TRUE; 1111 } 1112 1113 EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) 1114 { 1115 //TODO :later 1116 return 0; 1117 } 1118 1119 EGLBoolean eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list) 1120 { 1121 //TODO later 1122 return 0; 1123 } 1124 1125 EGLBoolean eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface) 1126 { 1127 //TODO later 1128 return 0; 1129 } 1130 1131 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) 1132 { 1133 VALIDATE_DISPLAY_INIT(dpy, EGL_NO_IMAGE_KHR); 1134 if (ctx != EGL_NO_CONTEXT) { 1135 setErrorReturn(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR); 1136 } 1137 if (target != EGL_NATIVE_BUFFER_ANDROID) { 1138 setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); 1139 } 1140 1141 android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer; 1142 1143 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) 1144 setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); 1145 1146 if (native_buffer->common.version != sizeof(android_native_buffer_t)) 1147 setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); 1148 1149 cb_handle_t *cb = (cb_handle_t *)(native_buffer->handle); 1150 1151 switch (cb->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 break; 1158 default: 1159 setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); 1160 } 1161 1162 native_buffer->common.incRef(&native_buffer->common); 1163 return (EGLImageKHR)native_buffer; 1164 } 1165 1166 EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) 1167 { 1168 VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); 1169 android_native_buffer_t* native_buffer = (android_native_buffer_t*)img; 1170 1171 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) 1172 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 1173 1174 if (native_buffer->common.version != sizeof(android_native_buffer_t)) 1175 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 1176 1177 native_buffer->common.decRef(&native_buffer->common); 1178 1179 return EGL_TRUE; 1180 } 1181 1182 #define FENCE_SYNC_HANDLE (EGLSyncKHR)0xFE4CE 1183 1184 EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, 1185 const EGLint *attrib_list) 1186 { 1187 // TODO: This implementation could be faster. We should require the host EGL 1188 // to support KHR_fence_sync, or at least pipe the fence command to the host 1189 // and wait for it (probably involving a glFinish on the host) in 1190 // eglClientWaitSyncKHR. 1191 1192 VALIDATE_DISPLAY(dpy, EGL_NO_SYNC_KHR); 1193 1194 if (type != EGL_SYNC_FENCE_KHR || 1195 (attrib_list != NULL && attrib_list[0] != EGL_NONE)) { 1196 setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR); 1197 } 1198 1199 EGLThreadInfo *tInfo = getEGLThreadInfo(); 1200 if (!tInfo || !tInfo->currentContext) { 1201 setErrorReturn(EGL_BAD_MATCH, EGL_NO_SYNC_KHR); 1202 } 1203 1204 if (tInfo->currentContext->version == 2) { 1205 s_display.gles2_iface()->finish(); 1206 } else { 1207 s_display.gles_iface()->finish(); 1208 } 1209 1210 return FENCE_SYNC_HANDLE; 1211 } 1212 1213 EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) 1214 { 1215 if (sync != FENCE_SYNC_HANDLE) { 1216 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 1217 } 1218 1219 return EGL_TRUE; 1220 } 1221 1222 EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, 1223 EGLTimeKHR timeout) 1224 { 1225 if (sync != FENCE_SYNC_HANDLE) { 1226 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 1227 } 1228 1229 return EGL_CONDITION_SATISFIED_KHR; 1230 } 1231 1232 EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, 1233 EGLint attribute, EGLint *value) 1234 { 1235 if (sync != FENCE_SYNC_HANDLE) { 1236 setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); 1237 } 1238 1239 switch (attribute) { 1240 case EGL_SYNC_TYPE_KHR: 1241 *value = EGL_SYNC_FENCE_KHR; 1242 return EGL_TRUE; 1243 case EGL_SYNC_STATUS_KHR: 1244 *value = EGL_SIGNALED_KHR; 1245 return EGL_TRUE; 1246 case EGL_SYNC_CONDITION_KHR: 1247 *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR; 1248 return EGL_TRUE; 1249 default: 1250 setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE); 1251 } 1252 } 1253