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