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