Edit

kc3-lang/angle/util/windows/WGLWindow.cpp

Branch :

  • Show log

    Commit

  • Author : Lubosz Sarnecki
    Date : 2021-09-10 13:56:28
    Hash : e024635d
    Message : ANGLEPerfTest: Skip tests when missing color space support. Make tests where a non-linear colorspace was requested on platforms that do not support EGL_KHR_gl_colorspace non-fatal. Add a initializeGLWithResult function to GLWindowBase, returning a new GLWindowResult enum and wrap it in EGLWindow and WGLWindow. Bug: angleproject:6366 Change-Id: Ib57327c4d988d82064272f229f8ad59287541623 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3151833 Commit-Queue: Lubosz Sarnecki <lubosz.sarnecki@collabora.com> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Cody Northrop <cnorthrop@google.com>

  • util/windows/WGLWindow.cpp
  • //
    // Copyright 2018 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.
    //
    // WGLWindow:
    //   Implements initializing a WGL rendering context.
    //
    
    #include "util/windows/WGLWindow.h"
    
    #include "common/string_utils.h"
    #include "common/system_utils.h"
    #include "util/OSWindow.h"
    
    #include <iostream>
    
    namespace
    {
    constexpr int kColorBits   = 24;
    constexpr int kAlphaBits   = 8;
    constexpr int kDepthBits   = 24;
    constexpr int kStencilBits = 8;
    
    PIXELFORMATDESCRIPTOR GetDefaultPixelFormatDescriptor()
    {
        PIXELFORMATDESCRIPTOR pixelFormatDescriptor = {};
        pixelFormatDescriptor.nSize                 = sizeof(pixelFormatDescriptor);
        pixelFormatDescriptor.nVersion              = 1;
        pixelFormatDescriptor.dwFlags =
            PFD_DRAW_TO_WINDOW | PFD_GENERIC_ACCELERATED | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
        pixelFormatDescriptor.iPixelType   = PFD_TYPE_RGBA;
        pixelFormatDescriptor.cColorBits   = kColorBits;
        pixelFormatDescriptor.cAlphaBits   = kAlphaBits;
        pixelFormatDescriptor.cDepthBits   = kDepthBits;
        pixelFormatDescriptor.cStencilBits = kStencilBits;
        pixelFormatDescriptor.iLayerType   = PFD_MAIN_PLANE;
    
        return pixelFormatDescriptor;
    }
    
    PFNWGLGETPROCADDRESSPROC gCurrentWGLGetProcAddress = nullptr;
    HMODULE gCurrentModule                             = nullptr;
    
    angle::GenericProc WINAPI GetProcAddressWithFallback(const char *name)
    {
        angle::GenericProc proc = reinterpret_cast<angle::GenericProc>(gCurrentWGLGetProcAddress(name));
        if (proc)
        {
            return proc;
        }
    
        return reinterpret_cast<angle::GenericProc>(GetProcAddress(gCurrentModule, name));
    }
    
    bool HasExtension(const std::vector<std::string> &extensions, const char *ext)
    {
        return std::find(extensions.begin(), extensions.end(), ext) != extensions.end();
    }
    
    void DumpLastWindowsError()
    {
        std::cerr << "Last Windows error code: 0x" << std::hex << GetLastError() << std::endl;
    }
    
    // Based on GetDefaultPixelFormatAttributes from wgl_utils.cpp
    std::vector<int> GetPixelFormatAttributes(const ConfigParameters &configParams)
    {
        std::vector<int> attribs;
        attribs.push_back(WGL_DRAW_TO_WINDOW_ARB);
        attribs.push_back(TRUE);
    
        attribs.push_back(WGL_ACCELERATION_ARB);
        attribs.push_back(WGL_FULL_ACCELERATION_ARB);
    
        attribs.push_back(WGL_SUPPORT_OPENGL_ARB);
        attribs.push_back(TRUE);
    
        attribs.push_back(WGL_DOUBLE_BUFFER_ARB);
        attribs.push_back(TRUE);
    
        attribs.push_back(WGL_PIXEL_TYPE_ARB);
        attribs.push_back(WGL_TYPE_RGBA_ARB);
    
        attribs.push_back(WGL_COLOR_BITS_ARB);
        attribs.push_back(kColorBits);
    
        attribs.push_back(WGL_ALPHA_BITS_ARB);
        attribs.push_back(kAlphaBits);
    
        attribs.push_back(WGL_DEPTH_BITS_ARB);
        attribs.push_back(kDepthBits);
    
        attribs.push_back(WGL_STENCIL_BITS_ARB);
        attribs.push_back(kStencilBits);
    
        attribs.push_back(WGL_SWAP_METHOD_ARB);
        attribs.push_back(WGL_SWAP_UNDEFINED_ARB);
    
        attribs.push_back(WGL_COLORSPACE_EXT);
        if (configParams.colorSpace == EGL_COLORSPACE_sRGB)
        {
            attribs.push_back(WGL_COLORSPACE_SRGB_EXT);
        }
        else
        {
            attribs.push_back(WGL_COLORSPACE_LINEAR_EXT);
        }
    
        attribs.push_back(0);
    
        return attribs;
    }
    
    }  // namespace
    
    WGLWindow::WGLWindow(int glesMajorVersion, int glesMinorVersion)
        : GLWindowBase(glesMajorVersion, glesMinorVersion),
          mDeviceContext(nullptr),
          mWGLContext(nullptr),
          mWindow(nullptr)
    {}
    
    WGLWindow::~WGLWindow() {}
    
    // Internally initializes GL resources.
    GLWindowResult WGLWindow::initializeGLWithResult(OSWindow *osWindow,
                                                     angle::Library *glWindowingLibrary,
                                                     angle::GLESDriverType driverType,
                                                     const EGLPlatformParameters &platformParams,
                                                     const ConfigParameters &configParams)
    {
        if (driverType != angle::GLESDriverType::SystemWGL)
        {
            std::cerr << "WGLWindow requires angle::GLESDriverType::SystemWGL.\n";
            return GLWindowResult::Error;
        }
    
        glWindowingLibrary->getAs("wglGetProcAddress", &gCurrentWGLGetProcAddress);
    
        if (!gCurrentWGLGetProcAddress)
        {
            std::cerr << "Error loading wglGetProcAddress." << std::endl;
            return GLWindowResult::Error;
        }
    
        gCurrentModule = reinterpret_cast<HMODULE>(glWindowingLibrary->getNative());
        angle::LoadWGL(GetProcAddressWithFallback);
    
        mWindow                                           = osWindow->getNativeWindow();
        mDeviceContext                                    = GetDC(mWindow);
        const PIXELFORMATDESCRIPTOR pixelFormatDescriptor = GetDefaultPixelFormatDescriptor();
    
        int pixelFormat = 0;
    
        if (!_wglChoosePixelFormatARB)
        {
            std::cout << "Driver does not expose wglChoosePixelFormatARB." << std::endl;
        }
        else
        {
            std::vector<int> pixelFormatAttribs = GetPixelFormatAttributes(configParams);
    
            UINT matchingFormats = 0;
            _wglChoosePixelFormatARB(mDeviceContext, &pixelFormatAttribs[0], nullptr, 1u, &pixelFormat,
                                     &matchingFormats);
        }
    
        if (pixelFormat == 0 && configParams.colorSpace != EGL_COLORSPACE_LINEAR)
        {
            std::cerr << "Could not find a compatible pixel format for a non-linear color space."
                      << std::endl;
            return GLWindowResult::NoColorspaceSupport;
        }
    
        if (pixelFormat == 0)
        {
            pixelFormat = ChoosePixelFormat(mDeviceContext, &pixelFormatDescriptor);
        }
    
        if (pixelFormat == 0)
        {
            std::cerr << "Could not find a compatible pixel format." << std::endl;
            DumpLastWindowsError();
            return GLWindowResult::Error;
        }
    
        // According to the Windows docs, it is an error to set a pixel format twice.
        int currentPixelFormat = GetPixelFormat(mDeviceContext);
        if (currentPixelFormat != pixelFormat)
        {
            if (SetPixelFormat(mDeviceContext, pixelFormat, &pixelFormatDescriptor) != TRUE)
            {
                std::cerr << "Failed to set the pixel format." << std::endl;
                DumpLastWindowsError();
                return GLWindowResult::Error;
            }
        }
    
        mWGLContext = createContext(configParams, nullptr);
        if (mWGLContext == nullptr)
        {
            return GLWindowResult::Error;
        }
    
        if (!makeCurrent())
        {
            return GLWindowResult::Error;
        }
    
        mPlatform     = platformParams;
        mConfigParams = configParams;
    
        angle::LoadGLES(GetProcAddressWithFallback);
        return GLWindowResult::NoError;
    }
    
    bool WGLWindow::initializeGL(OSWindow *osWindow,
                                 angle::Library *glWindowingLibrary,
                                 angle::GLESDriverType driverType,
                                 const EGLPlatformParameters &platformParams,
                                 const ConfigParameters &configParams)
    {
        return initializeGLWithResult(osWindow, glWindowingLibrary, driverType, platformParams,
                                      configParams) == GLWindowResult::NoError;
    }
    
    HGLRC WGLWindow::createContext(const ConfigParameters &configParams, HGLRC shareContext)
    {
        HGLRC context = _wglCreateContext(mDeviceContext);
        if (!context)
        {
            std::cerr << "Failed to create a WGL context." << std::endl;
            return context;
        }
    
        if (!makeCurrent(context))
        {
            std::cerr << "Failed to make WGL context current." << std::endl;
            return context;
        }
    
        // Reload entry points to capture extensions.
        angle::LoadWGL(GetProcAddressWithFallback);
    
        if (!_wglGetExtensionsStringARB)
        {
            std::cerr << "Driver does not expose wglGetExtensionsStringARB." << std::endl;
            return context;
        }
    
        const char *extensionsString = _wglGetExtensionsStringARB(mDeviceContext);
    
        std::vector<std::string> extensions;
        angle::SplitStringAlongWhitespace(extensionsString, &extensions);
    
        if (!HasExtension(extensions, "WGL_EXT_create_context_es2_profile"))
        {
            std::cerr << "Driver does not expose WGL_EXT_create_context_es2_profile." << std::endl;
            return context;
        }
    
        if (mConfigParams.webGLCompatibility.valid() || mConfigParams.robustResourceInit.valid())
        {
            std::cerr << "WGLWindow does not support the requested feature set." << std::endl;
            return context;
        }
    
        // Tear down the context and create another with ES2 compatibility.
        _wglDeleteContext(context);
    
        // This could be extended to cover ES1 compatiblity.
        int kCreateAttribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB,
                                mClientMajorVersion,
                                WGL_CONTEXT_MINOR_VERSION_ARB,
                                mClientMinorVersion,
                                WGL_CONTEXT_PROFILE_MASK_ARB,
                                WGL_CONTEXT_ES2_PROFILE_BIT_EXT,
                                0,
                                0};
    
        context = _wglCreateContextAttribsARB(mDeviceContext, shareContext, kCreateAttribs);
        if (!context)
        {
            std::cerr << "Failed to create an ES2 compatible WGL context." << std::endl;
            return context;
        }
    
        return context;
    }
    
    void WGLWindow::destroyGL()
    {
        if (mWGLContext)
        {
            _wglDeleteContext(mWGLContext);
            mWGLContext = nullptr;
        }
    
        if (mDeviceContext)
        {
            ReleaseDC(mWindow, mDeviceContext);
            mDeviceContext = nullptr;
        }
    }
    
    bool WGLWindow::isGLInitialized() const
    {
        return mWGLContext != nullptr;
    }
    
    GLWindowContext WGLWindow::getCurrentContextGeneric()
    {
        return reinterpret_cast<GLWindowContext>(mWGLContext);
    }
    
    GLWindowContext WGLWindow::createContextGeneric(GLWindowContext share)
    {
        HGLRC shareContext = reinterpret_cast<HGLRC>(share);
        HGLRC newContext   = createContext(mConfigParams, shareContext);
    
        // createContext() calls makeCurrent(newContext), so we need to restore the current context.
        if (!makeCurrent())
        {
            return nullptr;
        }
    
        return reinterpret_cast<GLWindowContext>(newContext);
    }
    
    bool WGLWindow::makeCurrent()
    {
        return makeCurrent(mWGLContext);
    }
    
    bool WGLWindow::makeCurrentGeneric(GLWindowContext context)
    {
        HGLRC wglContext = reinterpret_cast<HGLRC>(context);
        return makeCurrent(wglContext);
    }
    
    bool WGLWindow::makeCurrent(HGLRC context)
    {
        if (_wglMakeCurrent(mDeviceContext, context) == FALSE)
        {
            std::cerr << "Error during wglMakeCurrent.\n";
            return false;
        }
    
        return true;
    }
    
    bool WGLWindow::setSwapInterval(EGLint swapInterval)
    {
        if (!_wglSwapIntervalEXT || _wglSwapIntervalEXT(swapInterval) == FALSE)
        {
            std::cerr << "Error during wglSwapIntervalEXT.\n";
            return false;
        }
        return true;
    }
    
    void WGLWindow::swap()
    {
        if (SwapBuffers(mDeviceContext) == FALSE)
        {
            std::cerr << "Error during SwapBuffers.\n";
        }
    }
    
    bool WGLWindow::hasError() const
    {
        return GetLastError() != S_OK;
    }
    
    angle::GenericProc WGLWindow::getProcAddress(const char *name)
    {
        return GetProcAddressWithFallback(name);
    }
    
    // static
    WGLWindow *WGLWindow::New(int glesMajorVersion, int glesMinorVersion)
    {
        return new WGLWindow(glesMajorVersion, glesMinorVersion);
    }
    
    // static
    void WGLWindow::Delete(WGLWindow **window)
    {
        delete *window;
        *window = nullptr;
    }