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 "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