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