Edit

kc3-lang/angle/util/EGLWindow.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2017-03-07 17:24:06
    Hash : e08a1d36
    Message : Plumb robust resource init extensions. This also cleans up a few minor glitches in the extension texts, and renames the EGL extension for consistency. It incidentally fixes a bug in our EGL init where we were checking the wrong client versions for KHR_create_context. It also implements a new feature for tests which allow them to defer Context creation until the test body. This allows tests to check for EGL extension available before trying to create a context with certain extensions. BUG=angleproject:1635 Change-Id: I9311991332c357e36214082b16f2a4a57bfa8865 Reviewed-on: https://chromium-review.googlesource.com/450920 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org>

  • util/EGLWindow.cpp
  • //
    // Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    #include <string.h>
    #include <cassert>
    #include <vector>
    
    #include "EGLWindow.h"
    #include "OSWindow.h"
    #include "common/debug.h"
    
    EGLPlatformParameters::EGLPlatformParameters()
        : renderer(EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE),
          majorVersion(EGL_DONT_CARE),
          minorVersion(EGL_DONT_CARE),
          deviceType(EGL_DONT_CARE),
          presentPath(EGL_DONT_CARE)
    {
    }
    
    EGLPlatformParameters::EGLPlatformParameters(EGLint renderer)
        : renderer(renderer),
          majorVersion(EGL_DONT_CARE),
          minorVersion(EGL_DONT_CARE),
          deviceType(EGL_DONT_CARE),
          presentPath(EGL_DONT_CARE)
    {
        if (renderer == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE ||
            renderer == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
        {
            deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
        }
    }
    
    EGLPlatformParameters::EGLPlatformParameters(EGLint renderer,
                                                 EGLint majorVersion,
                                                 EGLint minorVersion,
                                                 EGLint useWarp)
        : renderer(renderer),
          majorVersion(majorVersion),
          minorVersion(minorVersion),
          deviceType(useWarp),
          presentPath(EGL_DONT_CARE)
    {
    }
    
    EGLPlatformParameters::EGLPlatformParameters(EGLint renderer,
                                                 EGLint majorVersion,
                                                 EGLint minorVersion,
                                                 EGLint useWarp,
                                                 EGLint presentPath)
        : renderer(renderer),
          majorVersion(majorVersion),
          minorVersion(minorVersion),
          deviceType(useWarp),
          presentPath(presentPath)
    {
    }
    
    bool operator<(const EGLPlatformParameters &a, const EGLPlatformParameters &b)
    {
        if (a.renderer != b.renderer)
        {
            return a.renderer < b.renderer;
        }
    
        if (a.majorVersion != b.majorVersion)
        {
            return a.majorVersion < b.majorVersion;
        }
    
        if (a.minorVersion != b.minorVersion)
        {
            return a.minorVersion < b.minorVersion;
        }
    
        if (a.deviceType != b.deviceType)
        {
            return a.deviceType < b.deviceType;
        }
    
        return a.presentPath < b.presentPath;
    }
    
    bool operator==(const EGLPlatformParameters &a, const EGLPlatformParameters &b)
    {
        return (a.renderer == b.renderer) && (a.majorVersion == b.majorVersion) &&
               (a.minorVersion == b.minorVersion) && (a.deviceType == b.deviceType) &&
               (a.presentPath == b.presentPath);
    }
    
    EGLWindow::EGLWindow(EGLint glesMajorVersion,
                         EGLint glesMinorVersion,
                         const EGLPlatformParameters &platform)
        : mDisplay(EGL_NO_DISPLAY),
          mSurface(EGL_NO_SURFACE),
          mContext(EGL_NO_CONTEXT),
          mClientMajorVersion(glesMajorVersion),
          mClientMinorVersion(glesMinorVersion),
          mEGLMajorVersion(0),
          mEGLMinorVersion(0),
          mPlatform(platform),
          mRedBits(-1),
          mGreenBits(-1),
          mBlueBits(-1),
          mAlphaBits(-1),
          mDepthBits(-1),
          mStencilBits(-1),
          mComponentType(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT),
          mMultisample(false),
          mDebug(false),
          mNoError(false),
          mWebGLCompatibility(false),
          mBindGeneratesResource(true),
          mClientArraysEnabled(true),
          mRobustResourceInit(false),
          mSwapInterval(-1)
    {
    }
    
    EGLWindow::~EGLWindow()
    {
        destroyGL();
    }
    
    void EGLWindow::swap()
    {
        eglSwapBuffers(mDisplay, mSurface);
    }
    
    EGLConfig EGLWindow::getConfig() const
    {
        return mConfig;
    }
    
    EGLDisplay EGLWindow::getDisplay() const
    {
        return mDisplay;
    }
    
    EGLSurface EGLWindow::getSurface() const
    {
        return mSurface;
    }
    
    EGLContext EGLWindow::getContext() const
    {
        return mContext;
    }
    
    bool EGLWindow::initializeGL(OSWindow *osWindow)
    {
        if (!initializeDisplayAndSurface(osWindow))
            return false;
        return initializeContext();
    }
    
    bool EGLWindow::initializeDisplayAndSurface(OSWindow *osWindow)
    {
        PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
        if (!eglGetPlatformDisplayEXT)
        {
            return false;
        }
    
        std::vector<EGLint> displayAttributes;
        displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
        displayAttributes.push_back(mPlatform.renderer);
        displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
        displayAttributes.push_back(mPlatform.majorVersion);
        displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
        displayAttributes.push_back(mPlatform.minorVersion);
    
        if (mPlatform.deviceType != EGL_DONT_CARE)
        {
            displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
            displayAttributes.push_back(mPlatform.deviceType);
        }
    
        if (mPlatform.presentPath != EGL_DONT_CARE)
        {
            const char *extensionString =
                static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS));
            if (strstr(extensionString, "EGL_ANGLE_experimental_present_path") == nullptr)
            {
                destroyGL();
                return false;
            }
    
            displayAttributes.push_back(EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE);
            displayAttributes.push_back(mPlatform.presentPath);
        }
    
        // Set vulkan validation layer settings if requested.
        if (mVulkanLayersEnabled.valid())
        {
            displayAttributes.push_back(EGL_PLATFORM_ANGLE_ENABLE_VALIDATION_LAYER_ANGLE);
            displayAttributes.push_back(mVulkanLayersEnabled.value() ? EGL_TRUE : EGL_FALSE);
        }
    
        displayAttributes.push_back(EGL_NONE);
    
        mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
                                            reinterpret_cast<void *>(osWindow->getNativeDisplay()),
                                            &displayAttributes[0]);
        if (mDisplay == EGL_NO_DISPLAY)
        {
            destroyGL();
            return false;
        }
    
        if (eglInitialize(mDisplay, &mEGLMajorVersion, &mEGLMinorVersion) == EGL_FALSE)
        {
            destroyGL();
            return false;
        }
    
        const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
    
        std::vector<EGLint> configAttributes = {
            EGL_RED_SIZE,       (mRedBits >= 0) ? mRedBits : EGL_DONT_CARE,
            EGL_GREEN_SIZE,     (mGreenBits >= 0) ? mGreenBits : EGL_DONT_CARE,
            EGL_BLUE_SIZE,      (mBlueBits >= 0) ? mBlueBits : EGL_DONT_CARE,
            EGL_ALPHA_SIZE,     (mAlphaBits >= 0) ? mAlphaBits : EGL_DONT_CARE,
            EGL_DEPTH_SIZE,     (mDepthBits >= 0) ? mDepthBits : EGL_DONT_CARE,
            EGL_STENCIL_SIZE,   (mStencilBits >= 0) ? mStencilBits : EGL_DONT_CARE,
            EGL_SAMPLE_BUFFERS, mMultisample ? 1 : 0,
        };
    
        // Add dynamic attributes
        bool hasPixelFormatFloat = strstr(displayExtensions, "EGL_EXT_pixel_format_float") != nullptr;
        if (!hasPixelFormatFloat && mComponentType != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT)
        {
            destroyGL();
            return false;
        }
        if (hasPixelFormatFloat)
        {
            configAttributes.push_back(EGL_COLOR_COMPONENT_TYPE_EXT);
            configAttributes.push_back(mComponentType);
        }
    
        // Finish the attribute list
        configAttributes.push_back(EGL_NONE);
    
        if (!FindEGLConfig(mDisplay, configAttributes.data(), &mConfig))
        {
            destroyGL();
            return false;
        }
    
        eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &mRedBits);
        eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &mGreenBits);
        eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &mBlueBits);
        eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &mAlphaBits);
        eglGetConfigAttrib(mDisplay, mConfig, EGL_DEPTH_SIZE, &mDepthBits);
        eglGetConfigAttrib(mDisplay, mConfig, EGL_STENCIL_SIZE, &mStencilBits);
    
        std::vector<EGLint> surfaceAttributes;
        if (strstr(displayExtensions, "EGL_NV_post_sub_buffer") != nullptr)
        {
            surfaceAttributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
            surfaceAttributes.push_back(EGL_TRUE);
        }
    
        surfaceAttributes.push_back(EGL_NONE);
    
        mSurface = eglCreateWindowSurface(mDisplay, mConfig, osWindow->getNativeWindow(), &surfaceAttributes[0]);
        if (eglGetError() != EGL_SUCCESS)
        {
            destroyGL();
            return false;
        }
        ASSERT(mSurface != EGL_NO_SURFACE);
        return true;
    }
    
    bool EGLWindow::initializeContext()
    {
        const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
    
        // EGL_KHR_create_context is required to request a ES3+ context.
        bool hasKHRCreateContext = strstr(displayExtensions, "EGL_KHR_create_context") != nullptr;
        if (mClientMajorVersion > 2 && !(mEGLMajorVersion > 1 || mEGLMinorVersion >= 5) &&
            !hasKHRCreateContext)
        {
            destroyGL();
            return false;
        }
    
        bool hasWebGLCompatibility =
            strstr(displayExtensions, "EGL_ANGLE_create_context_webgl_compatibility") != nullptr;
        if (mWebGLCompatibility && !hasWebGLCompatibility)
        {
            destroyGL();
            return false;
        }
    
        bool hasBindGeneratesResource =
            strstr(displayExtensions, "EGL_CHROMIUM_create_context_bind_generates_resource") != nullptr;
        if (!mBindGeneratesResource && !hasBindGeneratesResource)
        {
            destroyGL();
            return false;
        }
    
        bool hasClientArraysExtension =
            strstr(displayExtensions, "EGL_ANGLE_create_context_client_arrays") != nullptr;
        if (!mClientArraysEnabled && !hasClientArraysExtension)
        {
            // Non-default state requested without the extension present
            destroyGL();
            return false;
        }
    
        bool hasRobustResourceInit =
            strstr(displayExtensions, "EGL_ANGLE_create_context_robust_resource_initialization") !=
            nullptr;
        if (mRobustResourceInit && !hasRobustResourceInit)
        {
            // Non-default state requested without the extension present
            destroyGL();
            return false;
        }
    
        eglBindAPI(EGL_OPENGL_ES_API);
        if (eglGetError() != EGL_SUCCESS)
        {
            destroyGL();
            return false;
        }
    
        std::vector<EGLint> contextAttributes;
        if (hasKHRCreateContext)
        {
            contextAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
            contextAttributes.push_back(mClientMajorVersion);
    
            contextAttributes.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
            contextAttributes.push_back(mClientMinorVersion);
    
            contextAttributes.push_back(EGL_CONTEXT_OPENGL_DEBUG);
            contextAttributes.push_back(mDebug ? EGL_TRUE : EGL_FALSE);
    
            // TODO(jmadill): Check for the extension string.
            // bool hasKHRCreateContextNoError = strstr(displayExtensions,
            // "EGL_KHR_create_context_no_error") != nullptr;
    
            contextAttributes.push_back(EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
            contextAttributes.push_back(mNoError ? EGL_TRUE : EGL_FALSE);
    
            if (hasWebGLCompatibility)
            {
                contextAttributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
                contextAttributes.push_back(mWebGLCompatibility ? EGL_TRUE : EGL_FALSE);
            }
    
            if (hasBindGeneratesResource)
            {
                contextAttributes.push_back(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM);
                contextAttributes.push_back(mBindGeneratesResource ? EGL_TRUE : EGL_FALSE);
            }
    
            if (hasClientArraysExtension)
            {
                contextAttributes.push_back(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE);
                contextAttributes.push_back(mClientArraysEnabled ? EGL_TRUE : EGL_FALSE);
            }
    
            if (hasRobustResourceInit)
            {
                contextAttributes.push_back(EGL_CONTEXT_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
                contextAttributes.push_back(mRobustResourceInit ? EGL_TRUE : EGL_FALSE);
            }
        }
        contextAttributes.push_back(EGL_NONE);
    
        mContext = eglCreateContext(mDisplay, mConfig, nullptr, &contextAttributes[0]);
        if (eglGetError() != EGL_SUCCESS)
        {
            destroyGL();
            return false;
        }
    
        eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
        if (eglGetError() != EGL_SUCCESS)
        {
            destroyGL();
            return false;
        }
    
        if (mSwapInterval != -1)
        {
            eglSwapInterval(mDisplay, mSwapInterval);
        }
    
        return true;
    }
    
    void EGLWindow::destroyGL()
    {
        if (mSurface != EGL_NO_SURFACE)
        {
            assert(mDisplay != EGL_NO_DISPLAY);
            eglDestroySurface(mDisplay, mSurface);
            mSurface = EGL_NO_SURFACE;
        }
    
        if (mContext != EGL_NO_CONTEXT)
        {
            assert(mDisplay != EGL_NO_DISPLAY);
            eglDestroyContext(mDisplay, mContext);
            mContext = EGL_NO_CONTEXT;
        }
    
        if (mDisplay != EGL_NO_DISPLAY)
        {
            eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
            eglTerminate(mDisplay);
            mDisplay = EGL_NO_DISPLAY;
        }
    }
    
    bool EGLWindow::isGLInitialized() const
    {
        return mSurface != EGL_NO_SURFACE &&
               mContext != EGL_NO_CONTEXT &&
               mDisplay != EGL_NO_DISPLAY;
    }
    
    // Find an EGLConfig that is an exact match for the specified attributes. EGL_FALSE is returned if
    // the EGLConfig is found.  This indicates that the EGLConfig is not supported.
    EGLBoolean EGLWindow::FindEGLConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *config)
    {
        EGLint numConfigs = 0;
        eglGetConfigs(dpy, nullptr, 0, &numConfigs);
        std::vector<EGLConfig> allConfigs(numConfigs);
        eglGetConfigs(dpy, allConfigs.data(), static_cast<EGLint>(allConfigs.size()), &numConfigs);
    
        for (size_t i = 0; i < allConfigs.size(); i++)
        {
            bool matchFound = true;
            for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
            {
                if (curAttrib[1] == EGL_DONT_CARE)
                {
                    continue;
                }
    
                EGLint actualValue = EGL_DONT_CARE;
                eglGetConfigAttrib(dpy, allConfigs[i], curAttrib[0], &actualValue);
                if (curAttrib[1] != actualValue)
                {
                    matchFound = false;
                    break;
                }
            }
    
            if (matchFound)
            {
                *config = allConfigs[i];
                return EGL_TRUE;
            }
        }
    
        return EGL_FALSE;
    }