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 "libGLESv2/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 if (attribList) 195 { 196 while (*attribList != EGL_NONE) 197 { 198 switch (attribList[0]) 199 { 200 case EGL_RENDER_BUFFER: 201 switch (attribList[1]) 202 { 203 case EGL_BACK_BUFFER: 204 break; 205 case EGL_SINGLE_BUFFER: 206 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported 207 default: 208 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 209 } 210 break; 211 case EGL_POST_SUB_BUFFER_SUPPORTED_NV: 212 postSubBufferSupported = attribList[1]; 213 break; 214 case EGL_VG_COLORSPACE: 215 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 216 case EGL_VG_ALPHA_FORMAT: 217 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 218 default: 219 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 220 } 221 222 attribList += 2; 223 } 224 } 225 226 if (hasExistingWindowSurface(window)) 227 { 228 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); 229 } 230 231 if (mRenderer->testDeviceLost(false)) 232 { 233 if (!restoreLostDevice()) 234 return EGL_NO_SURFACE; 235 } 236 237 Surface *surface = new Surface(this, configuration, window, postSubBufferSupported); 238 239 if (!surface->initialize()) 240 { 241 delete surface; 242 return EGL_NO_SURFACE; 243 } 244 245 mSurfaceSet.insert(surface); 246 247 return success(surface); 248 } 249 250 EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList) 251 { 252 EGLint width = 0, height = 0; 253 EGLenum textureFormat = EGL_NO_TEXTURE; 254 EGLenum textureTarget = EGL_NO_TEXTURE; 255 const Config *configuration = mConfigSet.get(config); 256 257 if (attribList) 258 { 259 while (*attribList != EGL_NONE) 260 { 261 switch (attribList[0]) 262 { 263 case EGL_WIDTH: 264 width = attribList[1]; 265 break; 266 case EGL_HEIGHT: 267 height = attribList[1]; 268 break; 269 case EGL_LARGEST_PBUFFER: 270 if (attribList[1] != EGL_FALSE) 271 UNIMPLEMENTED(); // FIXME 272 break; 273 case EGL_TEXTURE_FORMAT: 274 switch (attribList[1]) 275 { 276 case EGL_NO_TEXTURE: 277 case EGL_TEXTURE_RGB: 278 case EGL_TEXTURE_RGBA: 279 textureFormat = attribList[1]; 280 break; 281 default: 282 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 283 } 284 break; 285 case EGL_TEXTURE_TARGET: 286 switch (attribList[1]) 287 { 288 case EGL_NO_TEXTURE: 289 case EGL_TEXTURE_2D: 290 textureTarget = attribList[1]; 291 break; 292 default: 293 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 294 } 295 break; 296 case EGL_MIPMAP_TEXTURE: 297 if (attribList[1] != EGL_FALSE) 298 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 299 break; 300 case EGL_VG_COLORSPACE: 301 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 302 case EGL_VG_ALPHA_FORMAT: 303 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 304 default: 305 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 306 } 307 308 attribList += 2; 309 } 310 } 311 312 if (width < 0 || height < 0) 313 { 314 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 315 } 316 317 if (width == 0 || height == 0) 318 { 319 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 320 } 321 322 if (textureFormat != EGL_NO_TEXTURE && !mRenderer->getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height))) 323 { 324 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 325 } 326 327 if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || 328 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) 329 { 330 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 331 } 332 333 if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT)) 334 { 335 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); 336 } 337 338 if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) || 339 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE)) 340 { 341 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); 342 } 343 344 if (mRenderer->testDeviceLost(false)) 345 { 346 if (!restoreLostDevice()) 347 return EGL_NO_SURFACE; 348 } 349 350 Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget); 351 352 if (!surface->initialize()) 353 { 354 delete surface; 355 return EGL_NO_SURFACE; 356 } 357 358 mSurfaceSet.insert(surface); 359 360 return success(surface); 361 } 362 363 EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess) 364 { 365 if (!mRenderer) 366 { 367 return NULL; 368 } 369 else if (mRenderer->testDeviceLost(false)) // Lost device 370 { 371 if (!restoreLostDevice()) 372 return NULL; 373 } 374 375 gl::Context *context = glCreateContext(shareContext, mRenderer, notifyResets, robustAccess); 376 mContextSet.insert(context); 377 378 return context; 379 } 380 381 bool Display::restoreLostDevice() 382 { 383 for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++) 384 { 385 if ((*ctx)->isResetNotificationEnabled()) 386 return false; // If reset notifications have been requested, application must delete all contexts first 387 } 388 389 // Release surface resources to make the Reset() succeed 390 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) 391 { 392 (*surface)->release(); 393 } 394 395 if (!mRenderer->resetDevice()) 396 { 397 return error(EGL_BAD_ALLOC, false); 398 } 399 400 // Restore any surfaces that may have been lost 401 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) 402 { 403 (*surface)->resetSwapChain(); 404 } 405 406 return true; 407 } 408 409 410 void Display::destroySurface(egl::Surface *surface) 411 { 412 delete surface; 413 mSurfaceSet.erase(surface); 414 } 415 416 void Display::destroyContext(gl::Context *context) 417 { 418 glDestroyContext(context); 419 mContextSet.erase(context); 420 } 421 422 void Display::notifyDeviceLost() 423 { 424 for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) 425 { 426 (*context)->markContextLost(); 427 } 428 egl::error(EGL_CONTEXT_LOST); 429 } 430 431 void Display::recreateSwapChains() 432 { 433 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) 434 { 435 (*surface)->getSwapChain()->recreate(); 436 } 437 } 438 439 bool Display::isInitialized() const 440 { 441 return mRenderer != NULL && mConfigSet.size() > 0; 442 } 443 444 bool Display::isValidConfig(EGLConfig config) 445 { 446 return mConfigSet.get(config) != NULL; 447 } 448 449 bool Display::isValidContext(gl::Context *context) 450 { 451 return mContextSet.find(context) != mContextSet.end(); 452 } 453 454 bool Display::isValidSurface(egl::Surface *surface) 455 { 456 return mSurfaceSet.find(surface) != mSurfaceSet.end(); 457 } 458 459 bool Display::hasExistingWindowSurface(HWND window) 460 { 461 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) 462 { 463 if ((*surface)->getWindowHandle() == window) 464 { 465 return true; 466 } 467 } 468 469 return false; 470 } 471 472 void Display::initExtensionString() 473 { 474 HMODULE swiftShader = GetModuleHandle(TEXT("swiftshader_d3d9.dll")); 475 bool shareHandleSupported = mRenderer->getShareHandleSupport(); 476 477 mExtensionString = ""; 478 479 // Multi-vendor (EXT) extensions 480 mExtensionString += "EGL_EXT_create_context_robustness "; 481 482 // ANGLE-specific extensions 483 if (shareHandleSupported) 484 { 485 mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer "; 486 } 487 488 mExtensionString += "EGL_ANGLE_query_surface_pointer "; 489 490 if (swiftShader) 491 { 492 mExtensionString += "EGL_ANGLE_software_display "; 493 } 494 495 if (shareHandleSupported) 496 { 497 mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle "; 498 } 499 500 if (mRenderer->getPostSubBufferSupport()) 501 { 502 mExtensionString += "EGL_NV_post_sub_buffer"; 503 } 504 505 std::string::size_type end = mExtensionString.find_last_not_of(' '); 506 if (end != std::string::npos) 507 { 508 mExtensionString.resize(end+1); 509 } 510 } 511 512 const char *Display::getExtensionString() const 513 { 514 return mExtensionString.c_str(); 515 } 516 517 void Display::initVendorString() 518 { 519 mVendorString = "Google Inc."; 520 521 LUID adapterLuid = {0}; 522 523 if (mRenderer && mRenderer->getLUID(&adapterLuid)) 524 { 525 char adapterLuidString[64]; 526 sprintf_s(adapterLuidString, sizeof(adapterLuidString), " (adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart); 527 528 mVendorString += adapterLuidString; 529 } 530 } 531 532 const char *Display::getVendorString() const 533 { 534 return mVendorString.c_str(); 535 } 536 537 } 538