| // |
| // 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 |
| { |
| 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 = 24; |
| pixelFormatDescriptor.cAlphaBits = 8; |
| pixelFormatDescriptor.cDepthBits = 24; |
| pixelFormatDescriptor.cStencilBits = 8; |
| 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; |
| } |
| } // namespace |
| |
| WGLWindow::WGLWindow(int glesMajorVersion, int glesMinorVersion) |
| : GLWindowBase(glesMajorVersion, glesMinorVersion), |
| mDeviceContext(nullptr), |
| mWGLContext(nullptr), |
| mWindow(nullptr) |
| {} |
| |
| WGLWindow::~WGLWindow() {} |
| |
| // Internally initializes GL resources. |
| bool WGLWindow::initializeGL(OSWindow *osWindow, |
| angle::Library *glWindowingLibrary, |
| const EGLPlatformParameters &platformParams, |
| const ConfigParameters &configParams) |
| { |
| glWindowingLibrary->getAs("wglGetProcAddress", &gCurrentWGLGetProcAddress); |
| |
| if (!gCurrentWGLGetProcAddress) |
| { |
| std::cerr << "Error loading wglGetProcAddress." << std::endl; |
| return false; |
| } |
| |
| gCurrentModule = reinterpret_cast<HMODULE>(glWindowingLibrary->getNative()); |
| angle::LoadWGL(GetProcAddressWithFallback); |
| |
| mWindow = osWindow->getNativeWindow(); |
| mDeviceContext = GetDC(mWindow); |
| const PIXELFORMATDESCRIPTOR pixelFormatDescriptor = GetDefaultPixelFormatDescriptor(); |
| |
| int pixelFormat = ChoosePixelFormat(mDeviceContext, &pixelFormatDescriptor); |
| if (pixelFormat == 0) |
| { |
| std::cerr << "Could not find a compatible pixel format." << std::endl; |
| DumpLastWindowsError(); |
| return false; |
| } |
| |
| // 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 false; |
| } |
| } |
| |
| mWGLContext = _wglCreateContext(mDeviceContext); |
| if (!mWGLContext) |
| { |
| std::cerr << "Failed to create a WGL context." << std::endl; |
| return false; |
| } |
| |
| if (!makeCurrent()) |
| { |
| return false; |
| } |
| |
| // Reload entry points to capture extensions. |
| angle::LoadWGL(GetProcAddressWithFallback); |
| |
| if (!_wglGetExtensionsStringARB) |
| { |
| std::cerr << "Driver does not expose wglGetExtensionsStringARB." << std::endl; |
| return false; |
| } |
| |
| 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 false; |
| } |
| |
| if (configParams.webGLCompatibility.valid() || configParams.robustResourceInit.valid()) |
| { |
| std::cerr << "WGLWindow does not support the requested feature set." << std::endl; |
| return false; |
| } |
| |
| // Tear down the context and create another with ES2 compatibility. |
| _wglDeleteContext(mWGLContext); |
| |
| // 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}; |
| |
| mWGLContext = _wglCreateContextAttribsARB(mDeviceContext, nullptr, kCreateAttribs); |
| if (!mWGLContext) |
| { |
| std::cerr << "Failed to create an ES2 compatible WGL context." << std::endl; |
| return false; |
| } |
| |
| if (!makeCurrent()) |
| { |
| return false; |
| } |
| |
| mPlatform = platformParams; |
| mConfigParams = configParams; |
| |
| angle::LoadGLES(GetProcAddressWithFallback); |
| return true; |
| } |
| |
| void WGLWindow::destroyGL() |
| { |
| if (mWGLContext) |
| { |
| _wglDeleteContext(mWGLContext); |
| mWGLContext = nullptr; |
| } |
| |
| if (mDeviceContext) |
| { |
| ReleaseDC(mWindow, mDeviceContext); |
| mDeviceContext = nullptr; |
| } |
| } |
| |
| bool WGLWindow::isGLInitialized() const |
| { |
| return mWGLContext != nullptr; |
| } |
| |
| bool WGLWindow::makeCurrent() |
| { |
| if (_wglMakeCurrent(mDeviceContext, mWGLContext) == 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; |
| } |
| |
| // static |
| WGLWindow *WGLWindow::New(int glesMajorVersion, int glesMinorVersion) |
| { |
| return new WGLWindow(glesMajorVersion, glesMinorVersion); |
| } |
| |
| // static |
| void WGLWindow::Delete(WGLWindow **window) |
| { |
| delete *window; |
| *window = nullptr; |
| } |