Home | History | Annotate | Download | only in libEGL
      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