Edit

kc3-lang/angle/util/EGLWindow.cpp

Branch :

  • Show log

    Commit

  • Author : Michael Spang
    Date : 2019-01-21 18:09:15
    Hash : 229fc83d
    Message : Vulkan: Port renderer to Fuchsia (reland) Add DisplayVk and WindowSurfaceVk subclasses for Fuchsia to the vulkan renderer, as well as an implementation of OSWindow that renders fullscreen for the test suite. Disallow use of the vulkan loader from third_party as Fuchsia uses a fork of the loader and has not sent those changes upstream yet. Add a small wayland-inspired library libfuchsia-egl to provide a type "struct fuchsia_egl_window" to use as EGLNativeWindowType. This type combines a zx_handle_t to an image pipe channel and a surface size. Image pipes can only be used once to create a VkSurfaceKHR. This means we have to recreate the pipe in tests that call eglCreateWindowSurface more than once with a single OSWindow, or the second call will fail. Add a resetNativeWindow() method to accomplish this. Reland disabling -Wextra-semi. BUG=angleproject:2475 TEST=angle_end2end_tests on Fuchsia Change-Id: Ie91715bcd760c6c04d4b8a02a91daa71e32ee30c Reviewed-on: https://chromium-review.googlesource.com/c/1467603 Commit-Queue: Michael Spang <spang@chromium.org> Reviewed-by: Jamie Madill <jmadill@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 "util/EGLWindow.h"
    
    #include <cassert>
    #include <iostream>
    #include <vector>
    
    #include <string.h>
    
    #include "platform/Platform.h"
    #include "util/OSWindow.h"
    #include "util/system_utils.h"
    
    EGLPlatformParameters::EGLPlatformParameters()
        : renderer(EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE),
          majorVersion(EGL_DONT_CARE),
          minorVersion(EGL_DONT_CARE),
          deviceType(EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE),
          presentPath(EGL_DONT_CARE)
    {}
    
    EGLPlatformParameters::EGLPlatformParameters(EGLint renderer)
        : renderer(renderer),
          majorVersion(EGL_DONT_CARE),
          minorVersion(EGL_DONT_CARE),
          deviceType(EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE),
          presentPath(EGL_DONT_CARE)
    {}
    
    EGLPlatformParameters::EGLPlatformParameters(EGLint renderer,
                                                 EGLint majorVersion,
                                                 EGLint minorVersion,
                                                 EGLint deviceType)
        : renderer(renderer),
          majorVersion(majorVersion),
          minorVersion(minorVersion),
          deviceType(deviceType),
          presentPath(EGL_DONT_CARE)
    {}
    
    EGLPlatformParameters::EGLPlatformParameters(EGLint renderer,
                                                 EGLint majorVersion,
                                                 EGLint minorVersion,
                                                 EGLint deviceType,
                                                 EGLint presentPath)
        : renderer(renderer),
          majorVersion(majorVersion),
          minorVersion(minorVersion),
          deviceType(deviceType),
          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);
    }
    
    // GLWindowBase implementation.
    GLWindowBase::GLWindowBase(EGLint glesMajorVersion, EGLint glesMinorVersion)
        : mClientMajorVersion(glesMajorVersion),
          mClientMinorVersion(glesMinorVersion),
          mRedBits(-1),
          mGreenBits(-1),
          mBlueBits(-1),
          mAlphaBits(-1),
          mDepthBits(-1),
          mStencilBits(-1),
          mSwapInterval(-1),
          mPlatformMethods(nullptr)
    {}
    
    GLWindowBase::~GLWindowBase() = default;
    
    // EGLWindow implementation.
    EGLWindow::EGLWindow(EGLint glesMajorVersion,
                         EGLint glesMinorVersion,
                         const EGLPlatformParameters &platform)
        : GLWindowBase(glesMajorVersion, glesMinorVersion),
          mDisplay(EGL_NO_DISPLAY),
          mSurface(EGL_NO_SURFACE),
          mContext(EGL_NO_CONTEXT),
          mEGLMajorVersion(0),
          mEGLMinorVersion(0),
          mPlatform(platform),
          mComponentType(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT),
          mMultisample(false),
          mDebug(false),
          mNoError(false),
          mExtensionsEnabled(),
          mBindGeneratesResource(true),
          mClientArraysEnabled(true),
          mRobustAccess(false),
          mSamples(-1),
          mDebugLayersEnabled(),
          mContextProgramCacheEnabled(),
          mContextVirtualization()
    {}
    
    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, angle::Library *glWindowingLibrary)
    {
        if (!initializeDisplayAndSurface(osWindow, glWindowingLibrary))
            return false;
        return initializeContext();
    }
    
    bool EGLWindow::initializeDisplayAndSurface(OSWindow *osWindow, angle::Library *glWindowingLibrary)
    {
    #if defined(ANGLE_USE_UTIL_LOADER)
        PFNEGLGETPROCADDRESSPROC getProcAddress;
        glWindowingLibrary->getAs("eglGetProcAddress", &getProcAddress);
        if (!getProcAddress)
        {
            return false;
        }
    
        // Likely we will need to use a fallback to Library::getAs on non-ANGLE platforms.
        angle::LoadEGL(getProcAddress);
    #endif  // defined(ANGLE_USE_UTIL_LOADER)
    
        std::vector<EGLAttrib> 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 debug layer settings if requested.
        if (mDebugLayersEnabled.valid())
        {
            displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
            displayAttributes.push_back(mDebugLayersEnabled.value() ? EGL_TRUE : EGL_FALSE);
        }
    
        if (mContextVirtualization.valid())
        {
            displayAttributes.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
            displayAttributes.push_back(mContextVirtualization.value() ? EGL_TRUE : EGL_FALSE);
        }
    
        if (mPlatformMethods)
        {
            static_assert(sizeof(EGLAttrib) == sizeof(mPlatformMethods), "Unexpected pointer size");
            displayAttributes.push_back(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX);
            displayAttributes.push_back(reinterpret_cast<EGLAttrib>(mPlatformMethods));
        }
    
        displayAttributes.push_back(EGL_NONE);
    
        mDisplay = eglGetPlatformDisplay(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,
            EGL_SAMPLES,        (mSamples >= 0) ? mSamples : EGL_DONT_CARE,
        };
    
        // 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))
        {
            std::cout << "Could not find a suitable EGL config!" << std::endl;
            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);
        eglGetConfigAttrib(mDisplay, mConfig, EGL_SAMPLES, &mSamples);
    
        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);
        }
    
        bool hasRobustResourceInit =
            strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
        if (hasRobustResourceInit && mRobustResourceInit.valid())
        {
            surfaceAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
            surfaceAttributes.push_back(mRobustResourceInit.value() ? EGL_TRUE : EGL_FALSE);
        }
    
        surfaceAttributes.push_back(EGL_NONE);
    
        osWindow->resetNativeWindow();
    
        mSurface = eglCreateWindowSurface(mDisplay, mConfig, osWindow->getNativeWindow(),
                                          &surfaceAttributes[0]);
        if (eglGetError() != EGL_SUCCESS || (mSurface == EGL_NO_SURFACE))
        {
            destroyGL();
            return false;
        }
    
    #if defined(ANGLE_USE_UTIL_LOADER)
        angle::LoadGLES(eglGetProcAddress);
    #endif  // defined(ANGLE_USE_UTIL_LOADER)
    
        return true;
    }
    
    EGLContext EGLWindow::createContext(EGLContext share) const
    {
        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)
        {
            return EGL_NO_CONTEXT;
        }
    
        bool hasWebGLCompatibility =
            strstr(displayExtensions, "EGL_ANGLE_create_context_webgl_compatibility") != nullptr;
        if (mWebGLCompatibility.valid() && !hasWebGLCompatibility)
        {
            return EGL_NO_CONTEXT;
        }
    
        bool hasCreateContextExtensionsEnabled =
            strstr(displayExtensions, "EGL_ANGLE_create_context_extensions_enabled") != nullptr;
        if (mExtensionsEnabled.valid() && !hasCreateContextExtensionsEnabled)
        {
            return EGL_NO_CONTEXT;
        }
    
        bool hasRobustness = strstr(displayExtensions, "EGL_EXT_create_context_robustness") != nullptr;
        if (mRobustAccess && !hasRobustness)
        {
            return EGL_NO_CONTEXT;
        }
    
        bool hasBindGeneratesResource =
            strstr(displayExtensions, "EGL_CHROMIUM_create_context_bind_generates_resource") != nullptr;
        if (!mBindGeneratesResource && !hasBindGeneratesResource)
        {
            return EGL_NO_CONTEXT;
        }
    
        bool hasClientArraysExtension =
            strstr(displayExtensions, "EGL_ANGLE_create_context_client_arrays") != nullptr;
        if (!mClientArraysEnabled && !hasClientArraysExtension)
        {
            // Non-default state requested without the extension present
            return EGL_NO_CONTEXT;
        }
    
        bool hasProgramCacheControlExtension =
            strstr(displayExtensions, "EGL_ANGLE_program_cache_control ") != nullptr;
        if (mContextProgramCacheEnabled.valid() && !hasProgramCacheControlExtension)
        {
            return EGL_NO_CONTEXT;
        }
    
        eglBindAPI(EGL_OPENGL_ES_API);
        if (eglGetError() != EGL_SUCCESS)
        {
            return EGL_NO_CONTEXT;
        }
    
        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 (mWebGLCompatibility.valid())
            {
                contextAttributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
                contextAttributes.push_back(mWebGLCompatibility.value() ? EGL_TRUE : EGL_FALSE);
            }
    
            if (mExtensionsEnabled.valid())
            {
                contextAttributes.push_back(EGL_EXTENSIONS_ENABLED_ANGLE);
                contextAttributes.push_back(mExtensionsEnabled.value() ? EGL_TRUE : EGL_FALSE);
            }
    
            if (hasRobustness)
            {
                contextAttributes.push_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
                contextAttributes.push_back(mRobustAccess ? 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 (mContextProgramCacheEnabled.valid())
            {
                contextAttributes.push_back(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE);
                contextAttributes.push_back(mContextProgramCacheEnabled.value() ? EGL_TRUE : EGL_FALSE);
            }
    
            bool hasRobustResourceInit =
                strstr(displayExtensions, "EGL_ANGLE_robust_resource_initialization") != nullptr;
            if (hasRobustResourceInit && mRobustResourceInit.valid())
            {
                contextAttributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
                contextAttributes.push_back(mRobustResourceInit.value() ? EGL_TRUE : EGL_FALSE);
            }
        }
        contextAttributes.push_back(EGL_NONE);
    
        EGLContext context = eglCreateContext(mDisplay, mConfig, nullptr, &contextAttributes[0]);
        if (eglGetError() != EGL_SUCCESS)
        {
            return EGL_NO_CONTEXT;
        }
    
        return context;
    }
    
    bool EGLWindow::initializeContext()
    {
        mContext = createContext(EGL_NO_CONTEXT);
        if (mContext == EGL_NO_CONTEXT)
        {
            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;
    }
    
    void EGLWindow::makeCurrent()
    {
        eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
    }
    
    bool EGLWindow::hasError() const
    {
        return eglGetError() != EGL_SUCCESS;
    }
    
    // static
    bool EGLWindow::ClientExtensionEnabled(const std::string &extName)
    {
        return CheckExtensionExists(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS), extName);
    }
    
    bool CheckExtensionExists(const char *allExtensions, const std::string &extName)
    {
        const std::string paddedExtensions = std::string(" ") + allExtensions + std::string(" ");
        return paddedExtensions.find(std::string(" ") + extName + std::string(" ")) !=
               std::string::npos;
    }
    
    // static
    void GLWindowBase::Delete(GLWindowBase **window)
    {
        delete *window;
        *window = nullptr;
    }
    
    // static
    EGLWindow *EGLWindow::New(EGLint glesMajorVersion,
                              EGLint glesMinorVersion,
                              const EGLPlatformParameters &platform)
    {
        return new EGLWindow(glesMajorVersion, glesMinorVersion, platform);
    }
    
    // static
    void EGLWindow::Delete(EGLWindow **window)
    {
        delete *window;
        *window = nullptr;
    }