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