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 return false;
81 }
82
83 glWindowingLibrary->getAs("wglGetProcAddress", &gCurrentWGLGetProcAddress);
84
85 if (!gCurrentWGLGetProcAddress)
86 {
87 std::cerr << "Error loading wglGetProcAddress." << std::endl;
88 return false;
89 }
90
91 gCurrentModule = reinterpret_cast<HMODULE>(glWindowingLibrary->getNative());
92 angle::LoadWGL(GetProcAddressWithFallback);
93
94 mWindow = osWindow->getNativeWindow();
95 mDeviceContext = GetDC(mWindow);
96 const PIXELFORMATDESCRIPTOR pixelFormatDescriptor = GetDefaultPixelFormatDescriptor();
97
98 int pixelFormat = ChoosePixelFormat(mDeviceContext, &pixelFormatDescriptor);
99 if (pixelFormat == 0)
100 {
101 std::cerr << "Could not find a compatible pixel format." << std::endl;
102 DumpLastWindowsError();
103 return false;
104 }
105
106 // According to the Windows docs, it is an error to set a pixel format twice.
107 int currentPixelFormat = GetPixelFormat(mDeviceContext);
108 if (currentPixelFormat != pixelFormat)
109 {
110 if (SetPixelFormat(mDeviceContext, pixelFormat, &pixelFormatDescriptor) != TRUE)
111 {
112 std::cerr << "Failed to set the pixel format." << std::endl;
113 DumpLastWindowsError();
114 return false;
115 }
116 }
117
118 mWGLContext = _wglCreateContext(mDeviceContext);
119 if (!mWGLContext)
120 {
121 std::cerr << "Failed to create a WGL context." << std::endl;
122 return false;
123 }
124
125 if (!makeCurrent())
126 {
127 return false;
128 }
129
130 // Reload entry points to capture extensions.
131 angle::LoadWGL(GetProcAddressWithFallback);
132
133 if (!_wglGetExtensionsStringARB)
134 {
135 std::cerr << "Driver does not expose wglGetExtensionsStringARB." << std::endl;
136 return false;
137 }
138
139 const char *extensionsString = _wglGetExtensionsStringARB(mDeviceContext);
140
141 std::vector<std::string> extensions;
142 angle::SplitStringAlongWhitespace(extensionsString, &extensions);
143
144 if (!HasExtension(extensions, "WGL_EXT_create_context_es2_profile"))
145 {
146 std::cerr << "Driver does not expose WGL_EXT_create_context_es2_profile." << std::endl;
147 return false;
148 }
149
150 if (configParams.webGLCompatibility.valid() || configParams.robustResourceInit.valid())
151 {
152 std::cerr << "WGLWindow does not support the requested feature set." << std::endl;
153 return false;
154 }
155
156 // Tear down the context and create another with ES2 compatibility.
157 _wglDeleteContext(mWGLContext);
158
159 // This could be extended to cover ES1 compatiblity.
160 int kCreateAttribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB,
161 mClientMajorVersion,
162 WGL_CONTEXT_MINOR_VERSION_ARB,
163 mClientMinorVersion,
164 WGL_CONTEXT_PROFILE_MASK_ARB,
165 WGL_CONTEXT_ES2_PROFILE_BIT_EXT,
166 0,
167 0};
168
169 mWGLContext = _wglCreateContextAttribsARB(mDeviceContext, nullptr, kCreateAttribs);
170 if (!mWGLContext)
171 {
172 std::cerr << "Failed to create an ES2 compatible WGL context." << std::endl;
173 return false;
174 }
175
176 if (!makeCurrent())
177 {
178 return false;
179 }
180
181 mPlatform = platformParams;
182 mConfigParams = configParams;
183
184 angle::LoadGLES(GetProcAddressWithFallback);
185 return true;
186 }
187
destroyGL()188 void WGLWindow::destroyGL()
189 {
190 if (mWGLContext)
191 {
192 _wglDeleteContext(mWGLContext);
193 mWGLContext = nullptr;
194 }
195
196 if (mDeviceContext)
197 {
198 ReleaseDC(mWindow, mDeviceContext);
199 mDeviceContext = nullptr;
200 }
201 }
202
isGLInitialized() const203 bool WGLWindow::isGLInitialized() const
204 {
205 return mWGLContext != nullptr;
206 }
207
makeCurrent()208 bool WGLWindow::makeCurrent()
209 {
210 if (_wglMakeCurrent(mDeviceContext, mWGLContext) == FALSE)
211 {
212 std::cerr << "Error during wglMakeCurrent.\n";
213 return false;
214 }
215
216 return true;
217 }
218
setSwapInterval(EGLint swapInterval)219 bool WGLWindow::setSwapInterval(EGLint swapInterval)
220 {
221 if (!_wglSwapIntervalEXT || _wglSwapIntervalEXT(swapInterval) == FALSE)
222 {
223 std::cerr << "Error during wglSwapIntervalEXT.\n";
224 return false;
225 }
226 return true;
227 }
228
swap()229 void WGLWindow::swap()
230 {
231 if (SwapBuffers(mDeviceContext) == FALSE)
232 {
233 std::cerr << "Error during SwapBuffers.\n";
234 }
235 }
236
hasError() const237 bool WGLWindow::hasError() const
238 {
239 return GetLastError() != S_OK;
240 }
241
242 // static
New(int glesMajorVersion,int glesMinorVersion)243 WGLWindow *WGLWindow::New(int glesMajorVersion, int glesMinorVersion)
244 {
245 return new WGLWindow(glesMajorVersion, glesMinorVersion);
246 }
247
248 // static
Delete(WGLWindow ** window)249 void WGLWindow::Delete(WGLWindow **window)
250 {
251 delete *window;
252 *window = nullptr;
253 }
254