1 //
2 // Copyright 2018 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 // WGLWindow:
7 //   Implements initializing a WGL rendering context.
8 //
9 
10 #include "util/windows/WGLWindow.h"
11 
12 #include "common/string_utils.h"
13 #include "common/system_utils.h"
14 #include "util/OSWindow.h"
15 
16 #include <iostream>
17 
18 namespace
19 {
GetDefaultPixelFormatDescriptor()20 PIXELFORMATDESCRIPTOR GetDefaultPixelFormatDescriptor()
21 {
22     PIXELFORMATDESCRIPTOR pixelFormatDescriptor = {};
23     pixelFormatDescriptor.nSize                 = sizeof(pixelFormatDescriptor);
24     pixelFormatDescriptor.nVersion              = 1;
25     pixelFormatDescriptor.dwFlags =
26         PFD_DRAW_TO_WINDOW | PFD_GENERIC_ACCELERATED | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
27     pixelFormatDescriptor.iPixelType   = PFD_TYPE_RGBA;
28     pixelFormatDescriptor.cColorBits   = 24;
29     pixelFormatDescriptor.cAlphaBits   = 8;
30     pixelFormatDescriptor.cDepthBits   = 24;
31     pixelFormatDescriptor.cStencilBits = 8;
32     pixelFormatDescriptor.iLayerType   = PFD_MAIN_PLANE;
33 
34     return pixelFormatDescriptor;
35 }
36 
37 PFNWGLGETPROCADDRESSPROC gCurrentWGLGetProcAddress = nullptr;
38 HMODULE gCurrentModule                             = nullptr;
39 
GetProcAddressWithFallback(const char * name)40 angle::GenericProc WINAPI GetProcAddressWithFallback(const char *name)
41 {
42     angle::GenericProc proc = reinterpret_cast<angle::GenericProc>(gCurrentWGLGetProcAddress(name));
43     if (proc)
44     {
45         return proc;
46     }
47 
48     return reinterpret_cast<angle::GenericProc>(GetProcAddress(gCurrentModule, name));
49 }
50 
HasExtension(const std::vector<std::string> & extensions,const char * ext)51 bool HasExtension(const std::vector<std::string> &extensions, const char *ext)
52 {
53     return std::find(extensions.begin(), extensions.end(), ext) != extensions.end();
54 }
55 
DumpLastWindowsError()56 void DumpLastWindowsError()
57 {
58     std::cerr << "Last Windows error code: 0x" << std::hex << GetLastError() << std::endl;
59 }
60 }  // namespace
61 
WGLWindow(int glesMajorVersion,int glesMinorVersion)62 WGLWindow::WGLWindow(int glesMajorVersion, int glesMinorVersion)
63     : GLWindowBase(glesMajorVersion, glesMinorVersion),
64       mDeviceContext(nullptr),
65       mWGLContext(nullptr),
66       mWindow(nullptr)
67 {}
68 
~WGLWindow()69 WGLWindow::~WGLWindow() {}
70 
71 // Internally initializes GL resources.
initializeGL(OSWindow * osWindow,angle::Library * glWindowingLibrary,angle::GLESDriverType driverType,const EGLPlatformParameters & platformParams,const ConfigParameters & configParams)72 bool WGLWindow::initializeGL(OSWindow *osWindow,
73                              angle::Library *glWindowingLibrary,
74                              angle::GLESDriverType driverType,
75                              const EGLPlatformParameters &platformParams,
76                              const ConfigParameters &configParams)
77 {
78     if (driverType != angle::GLESDriverType::SystemWGL)
79     {
80         std::cerr << "WGLWindow requires angle::GLESDriverType::SystemWGL.\n";
81         return false;
82     }
83 
84     glWindowingLibrary->getAs("wglGetProcAddress", &gCurrentWGLGetProcAddress);
85 
86     if (!gCurrentWGLGetProcAddress)
87     {
88         std::cerr << "Error loading wglGetProcAddress." << std::endl;
89         return false;
90     }
91 
92     gCurrentModule = reinterpret_cast<HMODULE>(glWindowingLibrary->getNative());
93     angle::LoadWGL(GetProcAddressWithFallback);
94 
95     mWindow                                           = osWindow->getNativeWindow();
96     mDeviceContext                                    = GetDC(mWindow);
97     const PIXELFORMATDESCRIPTOR pixelFormatDescriptor = GetDefaultPixelFormatDescriptor();
98 
99     int pixelFormat = ChoosePixelFormat(mDeviceContext, &pixelFormatDescriptor);
100     if (pixelFormat == 0)
101     {
102         std::cerr << "Could not find a compatible pixel format." << std::endl;
103         DumpLastWindowsError();
104         return false;
105     }
106 
107     // According to the Windows docs, it is an error to set a pixel format twice.
108     int currentPixelFormat = GetPixelFormat(mDeviceContext);
109     if (currentPixelFormat != pixelFormat)
110     {
111         if (SetPixelFormat(mDeviceContext, pixelFormat, &pixelFormatDescriptor) != TRUE)
112         {
113             std::cerr << "Failed to set the pixel format." << std::endl;
114             DumpLastWindowsError();
115             return false;
116         }
117     }
118 
119     mWGLContext = _wglCreateContext(mDeviceContext);
120     if (!mWGLContext)
121     {
122         std::cerr << "Failed to create a WGL context." << std::endl;
123         return false;
124     }
125 
126     if (!makeCurrent())
127     {
128         return false;
129     }
130 
131     // Reload entry points to capture extensions.
132     angle::LoadWGL(GetProcAddressWithFallback);
133 
134     if (!_wglGetExtensionsStringARB)
135     {
136         std::cerr << "Driver does not expose wglGetExtensionsStringARB." << std::endl;
137         return false;
138     }
139 
140     const char *extensionsString = _wglGetExtensionsStringARB(mDeviceContext);
141 
142     std::vector<std::string> extensions;
143     angle::SplitStringAlongWhitespace(extensionsString, &extensions);
144 
145     if (!HasExtension(extensions, "WGL_EXT_create_context_es2_profile"))
146     {
147         std::cerr << "Driver does not expose WGL_EXT_create_context_es2_profile." << std::endl;
148         return false;
149     }
150 
151     if (configParams.webGLCompatibility.valid() || configParams.robustResourceInit.valid())
152     {
153         std::cerr << "WGLWindow does not support the requested feature set." << std::endl;
154         return false;
155     }
156 
157     // Tear down the context and create another with ES2 compatibility.
158     _wglDeleteContext(mWGLContext);
159 
160     // This could be extended to cover ES1 compatiblity.
161     int kCreateAttribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB,
162                             mClientMajorVersion,
163                             WGL_CONTEXT_MINOR_VERSION_ARB,
164                             mClientMinorVersion,
165                             WGL_CONTEXT_PROFILE_MASK_ARB,
166                             WGL_CONTEXT_ES2_PROFILE_BIT_EXT,
167                             0,
168                             0};
169 
170     mWGLContext = _wglCreateContextAttribsARB(mDeviceContext, nullptr, kCreateAttribs);
171     if (!mWGLContext)
172     {
173         std::cerr << "Failed to create an ES2 compatible WGL context." << std::endl;
174         return false;
175     }
176 
177     if (!makeCurrent())
178     {
179         return false;
180     }
181 
182     mPlatform     = platformParams;
183     mConfigParams = configParams;
184 
185     angle::LoadGLES(GetProcAddressWithFallback);
186     return true;
187 }
188 
destroyGL()189 void WGLWindow::destroyGL()
190 {
191     if (mWGLContext)
192     {
193         _wglDeleteContext(mWGLContext);
194         mWGLContext = nullptr;
195     }
196 
197     if (mDeviceContext)
198     {
199         ReleaseDC(mWindow, mDeviceContext);
200         mDeviceContext = nullptr;
201     }
202 }
203 
isGLInitialized() const204 bool WGLWindow::isGLInitialized() const
205 {
206     return mWGLContext != nullptr;
207 }
208 
makeCurrent()209 bool WGLWindow::makeCurrent()
210 {
211     if (_wglMakeCurrent(mDeviceContext, mWGLContext) == FALSE)
212     {
213         std::cerr << "Error during wglMakeCurrent.\n";
214         return false;
215     }
216 
217     return true;
218 }
219 
setSwapInterval(EGLint swapInterval)220 bool WGLWindow::setSwapInterval(EGLint swapInterval)
221 {
222     if (!_wglSwapIntervalEXT || _wglSwapIntervalEXT(swapInterval) == FALSE)
223     {
224         std::cerr << "Error during wglSwapIntervalEXT.\n";
225         return false;
226     }
227     return true;
228 }
229 
swap()230 void WGLWindow::swap()
231 {
232     if (SwapBuffers(mDeviceContext) == FALSE)
233     {
234         std::cerr << "Error during SwapBuffers.\n";
235     }
236 }
237 
hasError() const238 bool WGLWindow::hasError() const
239 {
240     return GetLastError() != S_OK;
241 }
242 
getProcAddress(const char * name)243 angle::GenericProc WGLWindow::getProcAddress(const char *name)
244 {
245     return GetProcAddressWithFallback(name);
246 }
247 
248 // static
New(int glesMajorVersion,int glesMinorVersion)249 WGLWindow *WGLWindow::New(int glesMajorVersion, int glesMinorVersion)
250 {
251     return new WGLWindow(glesMajorVersion, glesMinorVersion);
252 }
253 
254 // static
Delete(WGLWindow ** window)255 void WGLWindow::Delete(WGLWindow **window)
256 {
257     delete *window;
258     *window = nullptr;
259 }
260