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