1 // 2 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // Display.cpp: Implements the egl::Display class, representing the abstract 8 // display on which graphics are drawn. Implements EGLDisplay. 9 // [EGL 1.4] section 2.1.2 page 3. 10 11 #include "libEGL/Display.h" 12 13 #include <algorithm> 14 #include <map> 15 #include <vector> 16 17 #include "common/debug.h" 18 #include "common/mathutil.h" 19 #include "libGLESv2/main.h" 20 #include "libGLESv2/Context.h" 21 #include "libGLESv2/renderer/SwapChain.h" 22 23 #include "libEGL/main.h" 24 #include "libEGL/Surface.h" 25 26 namespace egl 27 { 28 namespace 29 { 30 typedef std::map<EGLNativeDisplayType, Display*> DisplayMap; 31 DisplayMap displays; 32 } 33 34 egl::Display *Display::getDisplay(EGLNativeDisplayType displayId) 35 { 36 if (displays.find(displayId) != displays.end()) 37 { 38 return displays[displayId]; 39 } 40 41 // FIXME: Check if displayId is a valid display device context 42 43 egl::Display *display = new egl::Display(displayId, (HDC)displayId); 44 45 displays[displayId] = display; 46 return display; 47 } 48 49 Display::Display(EGLNativeDisplayType displayId, HDC deviceContext) : mDc(deviceContext) 50 { 51 mDisplayId = displayId; 52 mRenderer = NULL; 53 } 54 55 Display::~Display() 56 { 57 terminate(); 58 59 DisplayMap::iterator thisDisplay = displays.find(mDisplayId); 60 61 if (thisDisplay != displays.end()) 62 { 63 displays.erase(thisDisplay); 64 } 65 } 66 67 bool Display::initialize() 68 { 69 if (isInitialized()) 70 { 71 return true; 72 } 73 74 mRenderer = glCreateRenderer(this, mDc, mDisplayId); 75 76 if (!mRenderer) 77 { 78 terminate(); 79 return error(EGL_NOT_INITIALIZED, false); 80 } 81 82 EGLint minSwapInterval = mRenderer->getMinSwapInterval(); 83 EGLint maxSwapInterval = mRenderer->getMaxSwapInterval(); 84 EGLint maxTextureWidth = mRenderer->getMaxTextureWidth(); 85 EGLint maxTextureHeight = mRenderer->getMaxTextureHeight(); 86 87 rx::ConfigDesc *descList; 88 int numConfigs = mRenderer->generateConfigs(&descList); 89 ConfigSet configSet; 90 91 for (int i = 0; i < numConfigs; ++i) 92 configSet.add(descList[i], minSwapInterval, maxSwapInterval, 93 maxTextureWidth, maxTextureHeight); 94 95 // Give the sorted configs a unique ID and store them internally 96 EGLint index = 1; 97 for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++) 98 { 99 Config configuration = *config; 100 configuration.mConfigID = index; 101 index++; 102 103 mConfigSet.mSet.insert(configuration); 104 } 105 106 mRenderer->deleteConfigs(descList); 107 descList = NULL; 108 109 if (!isInitialized()) 110 { 111 terminate(); 112 return false; 113 } 114 115 initExtensionString(); 116 initVendorString(); 117 118 return true; 119 } 120 121 void Display::terminate() 122 { 123 while (!mSurfaceSet.empty()) 124 { 125 destroySurface(*mSurfaceSet.begin()); 126 } 127 128 while (!mContextSet.empty()) 129 { 130 destroyContext(*mContextSet.begin()); 131 } 132 133 glDestroyRenderer(mRenderer); 134 mRenderer = NULL; 135 } 136 137 bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig) 138 { 139 return mConfigSet.getConfigs(configs, attribList, configSize, numConfig); 140 } 141 142 bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) 143 { 144 const egl::Config *configuration = mConfigSet.get(config); 145 146 switch (attribute) 147 { 148 case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break; 149 case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break; 150 case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break; 151 case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break; 152 case EGL_RED_SIZE: *value = configuration->mRedSize; break; 153 case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break; 154 case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break; 155 case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break; 156 case EGL_CONFIG_ID: *value = configuration->mConfigID; break; 157 case EGL_LEVEL: *value = configuration->mLevel; break; 158 case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break; 159 case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break; 160 case EGL_SAMPLES: *value = configuration->mSamples; break; 161 case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break; 162 case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break; 163 case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break; 164 case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break; 165 case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break; 166 case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break; 167 case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break; 168 case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break; 169 case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break; 170 case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break; 171 case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break; 172 case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break; 173 case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break; 174 case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break; 175 case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break; 176 case EGL_CONFORMANT: *value = configuration->mConformant; break; 177 case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break; 178 case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break; 179 case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break; 180 default: 181 return false; 182 } 183 184 return true; 185 } 186 187 188 189 EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList) 190 { 191 const Config *configuration = mConfigSet.get(config); 192 EGLint postSubBufferSupported = EGL_FALSE; 193 194 EGLint width = 0; 195 EGLint height = 0; 196 EGLint fixedSize = EGL_FALSE; 197 198 if (attribList) 199 { 200 while (*attribList != EGL_NONE) 201 { 202 switch (attribList[0]) 203 { 204 case EGL_RENDER_BUFFER: 205 switch (attribList[1]) 206 { 207 case EGL_BACK_BUFFER: 208 break; 209 case EGL_SINGLE_BUFFER: 210 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported 211 default: 212 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 213 } 214 break; 215 case EGL_POST_SUB_BUFFER_SUPPORTED_NV: 216 postSubBufferSupported = attribList[1]; 217 break; 218 case EGL_WIDTH: 219 width = attribList[1]; 220 break; 221 case EGL_HEIGHT: 222 height = attribList[1]; 223 break; 224 case EGL_FIXED_SIZE_ANGLE: 225 fixedSize = attribList[1]; 226 break; 227 case EGL_VG_COLORSPACE: 228 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 229 case EGL_VG_ALPHA_FORMAT: 230 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 231 default: 232 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 233 } 234 235 attribList += 2; 236 } 237 } 238 239 if (width < 0 || height < 0) 240 { 241 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 242 } 243 244 if (!fixedSize) 245 { 246 width = -1; 247 height = -1; 248 } 249 250 if (hasExistingWindowSurface(window)) 251 { 252 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); 253 } 254 255 if (mRenderer->testDeviceLost(false)) 256 { 257 if (!restoreLostDevice()) 258 return EGL_NO_SURFACE; 259 } 260 261 Surface *surface = new Surface(this, configuration, window, fixedSize, width, height, postSubBufferSupported); 262 263 if (!surface->initialize()) 264 { 265 delete surface; 266 return EGL_NO_SURFACE; 267 } 268 269 mSurfaceSet.insert(surface); 270 271 return success(surface); 272 } 273 274 EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList) 275 { 276 EGLint width = 0, height = 0; 277 EGLenum textureFormat = EGL_NO_TEXTURE; 278 EGLenum textureTarget = EGL_NO_TEXTURE; 279 const Config *configuration = mConfigSet.get(config); 280 281 if (attribList) 282 { 283 while (*attribList != EGL_NONE) 284 { 285 switch (attribList[0]) 286 { 287 case EGL_WIDTH: 288 width = attribList[1]; 289 break; 290 case EGL_HEIGHT: 291 height = attribList[1]; 292 break; 293 case EGL_LARGEST_PBUFFER: 294 if (attribList[1] != EGL_FALSE) 295 UNIMPLEMENTED(); // FIXME 296 break; 297 case EGL_TEXTURE_FORMAT: 298 switch (attribList[1]) 299 { 300 case EGL_NO_TEXTURE: 301 case EGL_TEXTURE_RGB: 302 case EGL_TEXTURE_RGBA: 303 textureFormat = attribList[1]; 304 break; 305 default: 306 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 307 } 308 break; 309 case EGL_TEXTURE_TARGET: 310 switch (attribList[1]) 311 { 312 case EGL_NO_TEXTURE: 313 case EGL_TEXTURE_2D: 314 textureTarget = attribList[1]; 315 break; 316 default: 317 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 318 } 319 break; 320 case EGL_MIPMAP_TEXTURE: 321 if (attribList[1] != EGL_FALSE) 322 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 323 break; 324 case EGL_VG_COLORSPACE: 325 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 326 case EGL_VG_ALPHA_FORMAT: 327 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 328 default: 329 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 330 } 331 332 attribList += 2; 333 } 334 } 335 336 if (width < 0 || height < 0) 337 { 338 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 339 } 340 341 if (width == 0 || height == 0) 342 { 343 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 344 } 345 346 if (textureFormat != EGL_NO_TEXTURE && !mRenderer->getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height))) 347 { 348 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 349 } 350 351 if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || 352 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) 353 { 354 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 355 } 356 357 if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT)) 358 { 359 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 360 } 361 362 if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) || 363 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE)) 364 { 365 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 366 } 367 368 if (mRenderer->testDeviceLost(false)) 369 { 370 if (!restoreLostDevice()) 371 return EGL_NO_SURFACE; 372 } 373 374 Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget); 375 376 if (!surface->initialize()) 377 { 378 delete surface; 379 return EGL_NO_SURFACE; 380 } 381 382 mSurfaceSet.insert(surface); 383 384 return success(surface); 385 } 386 387 EGLContext Display::createContext(EGLConfig configHandle, EGLint clientVersion, const gl::Context *shareContext, bool notifyResets, bool robustAccess) 388 { 389 if (!mRenderer) 390 { 391 return EGL_NO_CONTEXT; 392 } 393 else if (mRenderer->testDeviceLost(false)) // Lost device 394 { 395 if (!restoreLostDevice()) 396 { 397 return error(EGL_CONTEXT_LOST, EGL_NO_CONTEXT); 398 } 399 } 400 401 if (clientVersion > 2 && mRenderer->getMajorShaderModel() < 4) 402 { 403 return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); 404 } 405 406 gl::Context *context = glCreateContext(clientVersion, shareContext, mRenderer, notifyResets, robustAccess); 407 mContextSet.insert(context); 408 409 return success(context); 410 } 411 412 bool Display::restoreLostDevice() 413 { 414 for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++) 415 { 416 if ((*ctx)->isResetNotificationEnabled()) 417 return false; // If reset notifications have been requested, application must delete all contexts first 418 } 419 420 // Release surface resources to make the Reset() succeed 421 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) 422 { 423 (*surface)->release(); 424 } 425 426 if (!mRenderer->resetDevice()) 427 { 428 return error(EGL_BAD_ALLOC, false); 429 } 430 431 // Restore any surfaces that may have been lost 432 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) 433 { 434 (*surface)->resetSwapChain(); 435 } 436 437 return true; 438 } 439 440 441 void Display::destroySurface(egl::Surface *surface) 442 { 443 delete surface; 444 mSurfaceSet.erase(surface); 445 } 446 447 void Display::destroyContext(gl::Context *context) 448 { 449 glDestroyContext(context); 450 mContextSet.erase(context); 451 } 452 453 void Display::notifyDeviceLost() 454 { 455 for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) 456 { 457 (*context)->markContextLost(); 458 } 459 egl::error(EGL_CONTEXT_LOST); 460 } 461 462 void Display::recreateSwapChains() 463 { 464 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) 465 { 466 (*surface)->getSwapChain()->recreate(); 467 } 468 } 469 470 bool Display::isInitialized() const 471 { 472 return mRenderer != NULL && mConfigSet.size() > 0; 473 } 474 475 bool Display::isValidConfig(EGLConfig config) 476 { 477 return mConfigSet.get(config) != NULL; 478 } 479 480 bool Display::isValidContext(gl::Context *context) 481 { 482 return mContextSet.find(context) != mContextSet.end(); 483 } 484 485 bool Display::isValidSurface(egl::Surface *surface) 486 { 487 return mSurfaceSet.find(surface) != mSurfaceSet.end(); 488 } 489 490 bool Display::hasExistingWindowSurface(HWND window) 491 { 492 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) 493 { 494 if ((*surface)->getWindowHandle() == window) 495 { 496 return true; 497 } 498 } 499 500 return false; 501 } 502 503 void Display::initExtensionString() 504 { 505 bool shareHandleSupported = mRenderer->getShareHandleSupport(); 506 507 mExtensionString = ""; 508 509 // Multi-vendor (EXT) extensions 510 mExtensionString += "EGL_EXT_create_context_robustness "; 511 512 // ANGLE-specific extensions 513 if (shareHandleSupported) 514 { 515 mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer "; 516 } 517 518 mExtensionString += "EGL_ANGLE_query_surface_pointer "; 519 520 mExtensionString += "EGL_ANGLE_window_fixed_size "; 521 522 if (shareHandleSupported) 523 { 524 mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle "; 525 } 526 527 if (mRenderer->getPostSubBufferSupport()) 528 { 529 mExtensionString += "EGL_NV_post_sub_buffer "; 530 } 531 532 // TODO: complete support for the EGL_KHR_create_context extension 533 mExtensionString += "EGL_KHR_create_context "; 534 535 std::string::size_type end = mExtensionString.find_last_not_of(' '); 536 if (end != std::string::npos) 537 { 538 mExtensionString.resize(end+1); 539 } 540 } 541 542 const char *Display::getExtensionString() const 543 { 544 return mExtensionString.c_str(); 545 } 546 547 void Display::initVendorString() 548 { 549 mVendorString = "Google Inc."; 550 551 LUID adapterLuid = {0}; 552 553 if (mRenderer && mRenderer->getLUID(&adapterLuid)) 554 { 555 char adapterLuidString[64]; 556 sprintf_s(adapterLuidString, sizeof(adapterLuidString), " (adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart); 557 558 mVendorString += adapterLuidString; 559 } 560 } 561 562 const char *Display::getVendorString() const 563 { 564 return mVendorString.c_str(); 565 } 566 567 } 568