1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Display.cpp: Implements the egl::Display class, representing the abstract 16 // display on which graphics are drawn. Implements EGLDisplay. 17 // [EGL 1.4] section 2.1.2 page 3. 18 19 #include "Display.h" 20 21 #include "main.h" 22 #include "libEGL/Surface.hpp" 23 #include "libEGL/Context.hpp" 24 #include "common/Image.hpp" 25 #include "common/debug.h" 26 #include "Common/MutexLock.hpp" 27 28 #ifdef __ANDROID__ 29 #include <system/window.h> 30 #include <sys/ioctl.h> 31 #include <linux/fb.h> 32 #include <fcntl.h> 33 #elif defined(__linux__) 34 #include "Main/libX11.hpp" 35 #elif defined(__APPLE__) 36 #include "OSXUtils.hpp" 37 #include <CoreFoundation/CoreFoundation.h> 38 #include <IOSurface/IOSurface.h> 39 #endif 40 41 #include <algorithm> 42 #include <vector> 43 #include <map> 44 45 namespace egl 46 { 47 48 class DisplayImplementation : public Display 49 { 50 public: 51 DisplayImplementation(EGLDisplay dpy, void *nativeDisplay) : Display(dpy, nativeDisplay) {} 52 ~DisplayImplementation() override {} 53 54 Image *getSharedImage(EGLImageKHR name) override 55 { 56 return Display::getSharedImage(name); 57 } 58 }; 59 60 Display *Display::get(EGLDisplay dpy) 61 { 62 if(dpy != PRIMARY_DISPLAY && dpy != HEADLESS_DISPLAY) // We only support the default display 63 { 64 return nullptr; 65 } 66 67 static void *nativeDisplay = nullptr; 68 69 #if defined(__linux__) && !defined(__ANDROID__) 70 // Even if the application provides a native display handle, we open (and close) our own connection 71 if(!nativeDisplay && dpy != HEADLESS_DISPLAY && libX11 && libX11->XOpenDisplay) 72 { 73 nativeDisplay = libX11->XOpenDisplay(NULL); 74 } 75 #endif 76 77 static DisplayImplementation display(dpy, nativeDisplay); 78 79 return &display; 80 } 81 82 Display::Display(EGLDisplay eglDisplay, void *nativeDisplay) : eglDisplay(eglDisplay), nativeDisplay(nativeDisplay) 83 { 84 mMinSwapInterval = 1; 85 mMaxSwapInterval = 1; 86 } 87 88 Display::~Display() 89 { 90 terminate(); 91 92 #if defined(__linux__) && !defined(__ANDROID__) 93 if(nativeDisplay && libX11->XCloseDisplay) 94 { 95 libX11->XCloseDisplay((::Display*)nativeDisplay); 96 } 97 #endif 98 } 99 100 #if !defined(__i386__) && defined(_M_IX86) 101 #define __i386__ 1 102 #endif 103 104 #if !defined(__x86_64__) && (defined(_M_AMD64) || defined (_M_X64)) 105 #define __x86_64__ 1 106 #endif 107 108 static void cpuid(int registers[4], int info) 109 { 110 #if defined(__i386__) || defined(__x86_64__) 111 #if defined(_WIN32) 112 __cpuid(registers, info); 113 #else 114 __asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info)); 115 #endif 116 #else 117 registers[0] = 0; 118 registers[1] = 0; 119 registers[2] = 0; 120 registers[3] = 0; 121 #endif 122 } 123 124 static bool detectSSE() 125 { 126 int registers[4]; 127 cpuid(registers, 1); 128 return (registers[3] & 0x02000000) != 0; 129 } 130 131 bool Display::initialize() 132 { 133 if(isInitialized()) 134 { 135 return true; 136 } 137 138 #if defined(__i386__) || defined(__x86_64__) 139 if(!detectSSE()) 140 { 141 return false; 142 } 143 #endif 144 145 mMinSwapInterval = 0; 146 mMaxSwapInterval = 4; 147 148 const int samples[] = 149 { 150 0, 151 2, 152 4 153 }; 154 155 const sw::Format renderTargetFormats[] = 156 { 157 // sw::FORMAT_A1R5G5B5, 158 // sw::FORMAT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value. 159 sw::FORMAT_A8R8G8B8, 160 sw::FORMAT_A8B8G8R8, 161 sw::FORMAT_R5G6B5, 162 // sw::FORMAT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format 163 sw::FORMAT_X8R8G8B8, 164 sw::FORMAT_X8B8G8R8 165 }; 166 167 const sw::Format depthStencilFormats[] = 168 { 169 sw::FORMAT_NULL, 170 // sw::FORMAT_D16_LOCKABLE, 171 sw::FORMAT_D32, 172 // sw::FORMAT_D15S1, 173 sw::FORMAT_D24S8, 174 sw::FORMAT_D24X8, 175 // sw::FORMAT_D24X4S4, 176 sw::FORMAT_D16, 177 // sw::FORMAT_D32F_LOCKABLE, 178 // sw::FORMAT_D24FS8 179 }; 180 181 sw::Format currentDisplayFormat = getDisplayFormat(); 182 ConfigSet configSet; 183 184 for(unsigned int samplesIndex = 0; samplesIndex < sizeof(samples) / sizeof(int); samplesIndex++) 185 { 186 for(unsigned int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(sw::Format); formatIndex++) 187 { 188 sw::Format renderTargetFormat = renderTargetFormats[formatIndex]; 189 190 for(unsigned int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(sw::Format); depthStencilIndex++) 191 { 192 sw::Format depthStencilFormat = depthStencilFormats[depthStencilIndex]; 193 194 configSet.add(currentDisplayFormat, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, samples[samplesIndex]); 195 } 196 } 197 } 198 199 // Give the sorted configs a unique ID and store them internally 200 EGLint index = 1; 201 for(ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++) 202 { 203 Config configuration = *config; 204 configuration.mConfigID = index; 205 index++; 206 207 mConfigSet.mSet.insert(configuration); 208 } 209 210 if(!isInitialized()) 211 { 212 terminate(); 213 214 return false; 215 } 216 217 return true; 218 } 219 220 void Display::terminate() 221 { 222 while(!mSurfaceSet.empty()) 223 { 224 destroySurface(*mSurfaceSet.begin()); 225 } 226 227 while(!mContextSet.empty()) 228 { 229 destroyContext(*mContextSet.begin()); 230 } 231 232 while(!mSharedImageNameSpace.empty()) 233 { 234 destroySharedImage(reinterpret_cast<EGLImageKHR>((intptr_t)mSharedImageNameSpace.firstName())); 235 } 236 } 237 238 bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig) 239 { 240 return mConfigSet.getConfigs(configs, attribList, configSize, numConfig); 241 } 242 243 bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) 244 { 245 const egl::Config *configuration = mConfigSet.get(config); 246 247 switch(attribute) 248 { 249 case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break; 250 case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break; 251 case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break; 252 case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break; 253 case EGL_RED_SIZE: *value = configuration->mRedSize; break; 254 case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break; 255 case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break; 256 case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break; 257 case EGL_CONFIG_ID: *value = configuration->mConfigID; break; 258 case EGL_LEVEL: *value = configuration->mLevel; break; 259 case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break; 260 case EGL_NATIVE_VISUAL_ID: *value = configuration->mNativeVisualID; break; 261 case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break; 262 case EGL_SAMPLES: *value = configuration->mSamples; break; 263 case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break; 264 case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break; 265 case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break; 266 case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break; 267 case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break; 268 case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break; 269 case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break; 270 case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break; 271 case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break; 272 case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break; 273 case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break; 274 case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break; 275 case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break; 276 case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break; 277 case EGL_MATCH_NATIVE_PIXMAP: *value = EGL_FALSE; UNIMPLEMENTED(); break; 278 case EGL_CONFORMANT: *value = configuration->mConformant; break; 279 case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break; 280 case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break; 281 case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break; 282 case EGL_RECORDABLE_ANDROID: *value = configuration->mRecordableAndroid; break; 283 case EGL_FRAMEBUFFER_TARGET_ANDROID: *value = configuration->mFramebufferTargetAndroid; break; 284 default: 285 return false; 286 } 287 288 return true; 289 } 290 291 EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList) 292 { 293 const Config *configuration = mConfigSet.get(config); 294 295 if(attribList) 296 { 297 while(*attribList != EGL_NONE) 298 { 299 switch(attribList[0]) 300 { 301 case EGL_RENDER_BUFFER: 302 switch(attribList[1]) 303 { 304 case EGL_BACK_BUFFER: 305 break; 306 case EGL_SINGLE_BUFFER: 307 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported 308 default: 309 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 310 } 311 break; 312 case EGL_VG_COLORSPACE: 313 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 314 case EGL_VG_ALPHA_FORMAT: 315 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 316 default: 317 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 318 } 319 320 attribList += 2; 321 } 322 } 323 324 if(hasExistingWindowSurface(window)) 325 { 326 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); 327 } 328 329 Surface *surface = new WindowSurface(this, configuration, window); 330 331 if(!surface->initialize()) 332 { 333 surface->release(); 334 return EGL_NO_SURFACE; 335 } 336 337 surface->addRef(); 338 mSurfaceSet.insert(surface); 339 340 return success(surface); 341 } 342 343 EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribList, EGLClientBuffer clientBuffer) 344 { 345 EGLint width = -1, height = -1, ioSurfacePlane = -1; 346 EGLenum textureFormat = EGL_NO_TEXTURE; 347 EGLenum textureTarget = EGL_NO_TEXTURE; 348 EGLenum clientBufferFormat = EGL_NO_TEXTURE; 349 EGLenum clientBufferType = EGL_NO_TEXTURE; 350 EGLBoolean largestPBuffer = EGL_FALSE; 351 const Config *configuration = mConfigSet.get(config); 352 353 if(attribList) 354 { 355 while(*attribList != EGL_NONE) 356 { 357 switch(attribList[0]) 358 { 359 case EGL_WIDTH: 360 width = attribList[1]; 361 break; 362 case EGL_HEIGHT: 363 height = attribList[1]; 364 break; 365 case EGL_LARGEST_PBUFFER: 366 largestPBuffer = attribList[1]; 367 break; 368 case EGL_TEXTURE_FORMAT: 369 switch(attribList[1]) 370 { 371 case EGL_NO_TEXTURE: 372 case EGL_TEXTURE_RGB: 373 case EGL_TEXTURE_RGBA: 374 textureFormat = attribList[1]; 375 break; 376 default: 377 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 378 } 379 break; 380 case EGL_TEXTURE_INTERNAL_FORMAT_ANGLE: 381 switch(attribList[1]) 382 { 383 case GL_RED: 384 case GL_R16UI: 385 case GL_RG: 386 case GL_BGRA_EXT: 387 case GL_RGBA: 388 clientBufferFormat = attribList[1]; 389 break; 390 default: 391 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 392 } 393 break; 394 case EGL_TEXTURE_TYPE_ANGLE: 395 switch(attribList[1]) 396 { 397 case GL_UNSIGNED_BYTE: 398 case GL_UNSIGNED_SHORT: 399 case GL_HALF_FLOAT_OES: 400 case GL_HALF_FLOAT: 401 clientBufferType = attribList[1]; 402 break; 403 default: 404 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 405 } 406 break; 407 case EGL_IOSURFACE_PLANE_ANGLE: 408 if(attribList[1] < 0) 409 { 410 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 411 } 412 ioSurfacePlane = attribList[1]; 413 break; 414 case EGL_TEXTURE_TARGET: 415 switch(attribList[1]) 416 { 417 case EGL_NO_TEXTURE: 418 case EGL_TEXTURE_2D: 419 case EGL_TEXTURE_RECTANGLE_ANGLE: 420 textureTarget = attribList[1]; 421 break; 422 default: 423 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 424 } 425 break; 426 case EGL_MIPMAP_TEXTURE: 427 if(attribList[1] != EGL_FALSE) 428 { 429 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 430 } 431 break; 432 case EGL_VG_COLORSPACE: 433 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 434 case EGL_VG_ALPHA_FORMAT: 435 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 436 default: 437 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 438 } 439 440 attribList += 2; 441 } 442 } 443 444 if(width < 0 || height < 0) 445 { 446 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 447 } 448 449 if(width == 0 || height == 0) 450 { 451 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 452 } 453 454 if((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || 455 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) 456 { 457 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 458 } 459 460 if(!(configuration->mSurfaceType & EGL_PBUFFER_BIT)) 461 { 462 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 463 } 464 465 if(clientBuffer) 466 { 467 switch(clientBufferType) 468 { 469 case GL_UNSIGNED_BYTE: 470 switch(clientBufferFormat) 471 { 472 case GL_RED: 473 case GL_RG: 474 case GL_BGRA_EXT: 475 break; 476 case GL_R16UI: 477 case GL_RGBA: 478 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 479 default: 480 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 481 } 482 break; 483 case GL_UNSIGNED_SHORT: 484 switch(clientBufferFormat) 485 { 486 case GL_R16UI: 487 break; 488 case GL_RED: 489 case GL_RG: 490 case GL_BGRA_EXT: 491 case GL_RGBA: 492 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 493 default: 494 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 495 } 496 break; 497 case GL_HALF_FLOAT_OES: 498 case GL_HALF_FLOAT: 499 switch(clientBufferFormat) 500 { 501 case GL_RGBA: 502 break; 503 case GL_RED: 504 case GL_R16UI: 505 case GL_RG: 506 case GL_BGRA_EXT: 507 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 508 default: 509 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 510 } 511 break; 512 default: 513 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 514 } 515 516 if(ioSurfacePlane < 0) 517 { 518 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 519 } 520 521 if(textureFormat != EGL_TEXTURE_RGBA) 522 { 523 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 524 } 525 526 if(textureTarget != EGL_TEXTURE_RECTANGLE_ANGLE) 527 { 528 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 529 } 530 531 #if defined(__APPLE__) 532 IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(clientBuffer); 533 size_t planeCount = IOSurfaceGetPlaneCount(ioSurface); 534 if((static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, ioSurfacePlane)) || 535 (static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, ioSurfacePlane)) || 536 ((planeCount != 0) && static_cast<size_t>(ioSurfacePlane) >= planeCount)) 537 { 538 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 539 } 540 #endif 541 } 542 else 543 { 544 if((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) || 545 ((textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))) 546 { 547 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 548 } 549 } 550 551 Surface *surface = new PBufferSurface(this, configuration, width, height, textureFormat, textureTarget, clientBufferFormat, clientBufferType, largestPBuffer, clientBuffer, ioSurfacePlane); 552 553 if(!surface->initialize()) 554 { 555 surface->release(); 556 return EGL_NO_SURFACE; 557 } 558 559 surface->addRef(); 560 mSurfaceSet.insert(surface); 561 562 return success(surface); 563 } 564 565 EGLContext Display::createContext(EGLConfig configHandle, const egl::Context *shareContext, EGLint clientVersion) 566 { 567 const egl::Config *config = mConfigSet.get(configHandle); 568 egl::Context *context = nullptr; 569 570 if(clientVersion == 1 && config->mRenderableType & EGL_OPENGL_ES_BIT) 571 { 572 if(libGLES_CM) 573 { 574 context = libGLES_CM->es1CreateContext(this, shareContext, config); 575 } 576 } 577 else if((clientVersion == 2 && config->mRenderableType & EGL_OPENGL_ES2_BIT) || 578 (clientVersion == 3 && config->mRenderableType & EGL_OPENGL_ES3_BIT)) 579 { 580 if(libGLESv2) 581 { 582 context = libGLESv2->es2CreateContext(this, shareContext, clientVersion, config); 583 } 584 } 585 else 586 { 587 return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); 588 } 589 590 if(!context) 591 { 592 return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT); 593 } 594 595 context->addRef(); 596 mContextSet.insert(context); 597 598 return success(context); 599 } 600 601 EGLSyncKHR Display::createSync(Context *context) 602 { 603 FenceSync *fenceSync = new egl::FenceSync(context); 604 LockGuard lock(mSyncSetMutex); 605 mSyncSet.insert(fenceSync); 606 return fenceSync; 607 } 608 609 void Display::destroySurface(egl::Surface *surface) 610 { 611 surface->release(); 612 mSurfaceSet.erase(surface); 613 614 if(surface == getCurrentDrawSurface()) 615 { 616 setCurrentDrawSurface(nullptr); 617 } 618 619 if(surface == getCurrentReadSurface()) 620 { 621 setCurrentReadSurface(nullptr); 622 } 623 } 624 625 void Display::destroyContext(egl::Context *context) 626 { 627 context->release(); 628 mContextSet.erase(context); 629 630 if(context == getCurrentContext()) 631 { 632 setCurrentContext(nullptr); 633 setCurrentDrawSurface(nullptr); 634 setCurrentReadSurface(nullptr); 635 } 636 } 637 638 void Display::destroySync(FenceSync *sync) 639 { 640 { 641 LockGuard lock(mSyncSetMutex); 642 mSyncSet.erase(sync); 643 } 644 delete sync; 645 } 646 647 bool Display::isInitialized() const 648 { 649 return mConfigSet.size() > 0; 650 } 651 652 bool Display::isValidConfig(EGLConfig config) 653 { 654 return mConfigSet.get(config) != nullptr; 655 } 656 657 bool Display::isValidContext(egl::Context *context) 658 { 659 return mContextSet.find(context) != mContextSet.end(); 660 } 661 662 bool Display::isValidSurface(egl::Surface *surface) 663 { 664 return mSurfaceSet.find(surface) != mSurfaceSet.end(); 665 } 666 667 bool Display::isValidWindow(EGLNativeWindowType window) 668 { 669 #if defined(_WIN32) 670 return IsWindow(window) == TRUE; 671 #elif defined(__ANDROID__) 672 if(!window) 673 { 674 ALOGE("%s called with window==NULL %s:%d", __FUNCTION__, __FILE__, __LINE__); 675 return false; 676 } 677 if(static_cast<ANativeWindow*>(window)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) 678 { 679 ALOGE("%s called with window==%p bad magic %s:%d", __FUNCTION__, window, __FILE__, __LINE__); 680 return false; 681 } 682 return true; 683 #elif defined(__linux__) 684 if(nativeDisplay) 685 { 686 XWindowAttributes windowAttributes; 687 Status status = libX11->XGetWindowAttributes((::Display*)nativeDisplay, window, &windowAttributes); 688 689 return status != 0; 690 } 691 return false; 692 #elif defined(__APPLE__) 693 return sw::OSX::IsValidWindow(window); 694 #elif defined(__Fuchsia__) 695 // TODO(crbug.com/800951): Integrate with Mozart. 696 return true; 697 #else 698 #error "Display::isValidWindow unimplemented for this platform" 699 return false; 700 #endif 701 } 702 703 bool Display::hasExistingWindowSurface(EGLNativeWindowType window) 704 { 705 for(const auto &surface : mSurfaceSet) 706 { 707 if(surface->isWindowSurface()) 708 { 709 if(surface->getWindowHandle() == window) 710 { 711 return true; 712 } 713 } 714 } 715 716 return false; 717 } 718 719 bool Display::isValidSync(FenceSync *sync) 720 { 721 LockGuard lock(mSyncSetMutex); 722 return mSyncSet.find(sync) != mSyncSet.end(); 723 } 724 725 EGLint Display::getMinSwapInterval() const 726 { 727 return mMinSwapInterval; 728 } 729 730 EGLint Display::getMaxSwapInterval() const 731 { 732 return mMaxSwapInterval; 733 } 734 735 EGLDisplay Display::getEGLDisplay() const 736 { 737 return eglDisplay; 738 } 739 740 void *Display::getNativeDisplay() const 741 { 742 return nativeDisplay; 743 } 744 745 EGLImageKHR Display::createSharedImage(Image *image) 746 { 747 return reinterpret_cast<EGLImageKHR>((intptr_t)mSharedImageNameSpace.allocate(image)); 748 } 749 750 bool Display::destroySharedImage(EGLImageKHR image) 751 { 752 GLuint name = (GLuint)reinterpret_cast<intptr_t>(image); 753 Image *eglImage = mSharedImageNameSpace.find(name); 754 755 if(!eglImage) 756 { 757 return false; 758 } 759 760 eglImage->destroyShared(); 761 mSharedImageNameSpace.remove(name); 762 763 return true; 764 } 765 766 Image *Display::getSharedImage(EGLImageKHR image) 767 { 768 GLuint name = (GLuint)reinterpret_cast<intptr_t>(image); 769 return mSharedImageNameSpace.find(name); 770 } 771 772 sw::Format Display::getDisplayFormat() const 773 { 774 #if defined(_WIN32) 775 HDC deviceContext = GetDC(0); 776 unsigned int bpp = ::GetDeviceCaps(deviceContext, BITSPIXEL); 777 ReleaseDC(0, deviceContext); 778 779 switch(bpp) 780 { 781 case 32: return sw::FORMAT_X8R8G8B8; 782 case 24: return sw::FORMAT_R8G8B8; 783 case 16: return sw::FORMAT_R5G6B5; 784 default: UNREACHABLE(bpp); // Unexpected display mode color depth 785 } 786 #elif defined(__ANDROID__) 787 static const char *const framebuffer[] = 788 { 789 "/dev/graphics/fb0", 790 "/dev/fb0", 791 0 792 }; 793 794 for(int i = 0; framebuffer[i]; i++) 795 { 796 int fd = open(framebuffer[i], O_RDONLY, 0); 797 798 if(fd != -1) 799 { 800 struct fb_var_screeninfo info; 801 int io = ioctl(fd, FBIOGET_VSCREENINFO, &info); 802 close(fd); 803 804 if(io >= 0) 805 { 806 switch(info.bits_per_pixel) 807 { 808 case 16: 809 return sw::FORMAT_R5G6B5; 810 case 32: 811 if(info.red.length == 8 && info.red.offset == 16 && 812 info.green.length == 8 && info.green.offset == 8 && 813 info.blue.length == 8 && info.blue.offset == 0 && 814 info.transp.length == 0) 815 { 816 return sw::FORMAT_X8R8G8B8; 817 } 818 if(info.red.length == 8 && info.red.offset == 0 && 819 info.green.length == 8 && info.green.offset == 8 && 820 info.blue.length == 8 && info.blue.offset == 16 && 821 info.transp.length == 0) 822 { 823 return sw::FORMAT_X8B8G8R8; 824 } 825 if(info.red.length == 8 && info.red.offset == 16 && 826 info.green.length == 8 && info.green.offset == 8 && 827 info.blue.length == 8 && info.blue.offset == 0 && 828 info.transp.length == 8 && info.transp.offset == 24) 829 { 830 return sw::FORMAT_A8R8G8B8; 831 } 832 if(info.red.length == 8 && info.red.offset == 0 && 833 info.green.length == 8 && info.green.offset == 8 && 834 info.blue.length == 8 && info.blue.offset == 16 && 835 info.transp.length == 8 && info.transp.offset == 24) 836 { 837 return sw::FORMAT_A8B8G8R8; 838 } 839 else UNIMPLEMENTED(); 840 default: 841 UNIMPLEMENTED(); 842 } 843 } 844 } 845 } 846 847 // No framebuffer device found, or we're in user space 848 return sw::FORMAT_X8B8G8R8; 849 #elif defined(__linux__) 850 if(nativeDisplay) 851 { 852 Screen *screen = libX11->XDefaultScreenOfDisplay((::Display*)nativeDisplay); 853 unsigned int bpp = libX11->XPlanesOfScreen(screen); 854 855 switch(bpp) 856 { 857 case 32: return sw::FORMAT_X8R8G8B8; 858 case 24: return sw::FORMAT_R8G8B8; 859 case 16: return sw::FORMAT_R5G6B5; 860 default: UNREACHABLE(bpp); // Unexpected display mode color depth 861 } 862 } 863 else 864 { 865 return sw::FORMAT_X8R8G8B8; 866 } 867 #elif defined(__APPLE__) 868 return sw::FORMAT_A8B8G8R8; 869 #elif defined(__Fuchsia__) 870 return sw::FORMAT_A8B8G8R8; 871 #else 872 #error "Display::isValidWindow unimplemented for this platform" 873 #endif 874 875 return sw::FORMAT_X8R8G8B8; 876 } 877 878 } 879