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 {
20 constexpr int kColorBits = 24;
21 constexpr int kAlphaBits = 8;
22 constexpr int kDepthBits = 24;
23 constexpr int kStencilBits = 8;
24
GetDefaultPixelFormatDescriptor()25 PIXELFORMATDESCRIPTOR GetDefaultPixelFormatDescriptor()
26 {
27 PIXELFORMATDESCRIPTOR pixelFormatDescriptor = {};
28 pixelFormatDescriptor.nSize = sizeof(pixelFormatDescriptor);
29 pixelFormatDescriptor.nVersion = 1;
30 pixelFormatDescriptor.dwFlags =
31 PFD_DRAW_TO_WINDOW | PFD_GENERIC_ACCELERATED | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
32 pixelFormatDescriptor.iPixelType = PFD_TYPE_RGBA;
33 pixelFormatDescriptor.cColorBits = kColorBits;
34 pixelFormatDescriptor.cAlphaBits = kAlphaBits;
35 pixelFormatDescriptor.cDepthBits = kDepthBits;
36 pixelFormatDescriptor.cStencilBits = kStencilBits;
37 pixelFormatDescriptor.iLayerType = PFD_MAIN_PLANE;
38
39 return pixelFormatDescriptor;
40 }
41
42 PFNWGLGETPROCADDRESSPROC gCurrentWGLGetProcAddress = nullptr;
43 HMODULE gCurrentModule = nullptr;
44
GetProcAddressWithFallback(const char * name)45 GenericProc WINAPI GetProcAddressWithFallback(const char *name)
46 {
47 GenericProc proc = reinterpret_cast<GenericProc>(gCurrentWGLGetProcAddress(name));
48 if (proc)
49 {
50 return proc;
51 }
52
53 return reinterpret_cast<GenericProc>(GetProcAddress(gCurrentModule, name));
54 }
55
HasExtension(const std::vector<std::string> & extensions,const char * ext)56 bool HasExtension(const std::vector<std::string> &extensions, const char *ext)
57 {
58 return std::find(extensions.begin(), extensions.end(), ext) != extensions.end();
59 }
60
DumpLastWindowsError()61 void DumpLastWindowsError()
62 {
63 std::cerr << "Last Windows error code: 0x" << std::hex << GetLastError() << std::endl;
64 }
65
66 // Based on GetDefaultPixelFormatAttributes from wgl_utils.cpp
GetPixelFormatAttributes(const ConfigParameters & configParams)67 std::vector<int> GetPixelFormatAttributes(const ConfigParameters &configParams)
68 {
69 std::vector<int> attribs;
70 attribs.push_back(WGL_DRAW_TO_WINDOW_ARB);
71 attribs.push_back(TRUE);
72
73 attribs.push_back(WGL_ACCELERATION_ARB);
74 attribs.push_back(WGL_FULL_ACCELERATION_ARB);
75
76 attribs.push_back(WGL_SUPPORT_OPENGL_ARB);
77 attribs.push_back(TRUE);
78
79 attribs.push_back(WGL_DOUBLE_BUFFER_ARB);
80 attribs.push_back(TRUE);
81
82 attribs.push_back(WGL_PIXEL_TYPE_ARB);
83 attribs.push_back(WGL_TYPE_RGBA_ARB);
84
85 attribs.push_back(WGL_COLOR_BITS_ARB);
86 attribs.push_back(kColorBits);
87
88 attribs.push_back(WGL_ALPHA_BITS_ARB);
89 attribs.push_back(kAlphaBits);
90
91 attribs.push_back(WGL_DEPTH_BITS_ARB);
92 attribs.push_back(kDepthBits);
93
94 attribs.push_back(WGL_STENCIL_BITS_ARB);
95 attribs.push_back(kStencilBits);
96
97 attribs.push_back(WGL_SWAP_METHOD_ARB);
98 attribs.push_back(WGL_SWAP_UNDEFINED_ARB);
99
100 attribs.push_back(WGL_COLORSPACE_EXT);
101 if (configParams.colorSpace == EGL_COLORSPACE_sRGB)
102 {
103 attribs.push_back(WGL_COLORSPACE_SRGB_EXT);
104 }
105 else
106 {
107 attribs.push_back(WGL_COLORSPACE_LINEAR_EXT);
108 }
109
110 attribs.push_back(0);
111
112 return attribs;
113 }
114
115 } // namespace
116
WGLWindow(EGLenum clientType,int majorVersion,int minorVersion,int profileMask)117 WGLWindow::WGLWindow(EGLenum clientType, int majorVersion, int minorVersion, int profileMask)
118 : GLWindowBase(clientType, majorVersion, minorVersion, profileMask),
119 mDeviceContext(nullptr),
120 mWGLContext(nullptr),
121 mWindow(nullptr)
122 {}
123
~WGLWindow()124 WGLWindow::~WGLWindow() {}
125
126 // Internally initializes GL resources.
initializeGLWithResult(OSWindow * osWindow,angle::Library * glWindowingLibrary,angle::GLESDriverType driverType,const EGLPlatformParameters & platformParams,const ConfigParameters & configParams)127 GLWindowResult WGLWindow::initializeGLWithResult(OSWindow *osWindow,
128 angle::Library *glWindowingLibrary,
129 angle::GLESDriverType driverType,
130 const EGLPlatformParameters &platformParams,
131 const ConfigParameters &configParams)
132 {
133 if (driverType != angle::GLESDriverType::SystemWGL)
134 {
135 std::cerr << "WGLWindow requires angle::GLESDriverType::SystemWGL.\n";
136 return GLWindowResult::Error;
137 }
138
139 glWindowingLibrary->getAs("wglGetProcAddress", &gCurrentWGLGetProcAddress);
140
141 if (!gCurrentWGLGetProcAddress)
142 {
143 std::cerr << "Error loading wglGetProcAddress." << std::endl;
144 return GLWindowResult::Error;
145 }
146
147 gCurrentModule = reinterpret_cast<HMODULE>(glWindowingLibrary->getNative());
148 LoadWGL(GetProcAddressWithFallback);
149
150 mWindow = osWindow->getNativeWindow();
151 mDeviceContext = GetDC(mWindow);
152 const PIXELFORMATDESCRIPTOR pixelFormatDescriptor = GetDefaultPixelFormatDescriptor();
153
154 int pixelFormat = 0;
155
156 if (!_wglChoosePixelFormatARB)
157 {
158 std::cout << "Driver does not expose wglChoosePixelFormatARB." << std::endl;
159 }
160 else
161 {
162 std::vector<int> pixelFormatAttribs = GetPixelFormatAttributes(configParams);
163
164 UINT matchingFormats = 0;
165 _wglChoosePixelFormatARB(mDeviceContext, &pixelFormatAttribs[0], nullptr, 1u, &pixelFormat,
166 &matchingFormats);
167 }
168
169 if (pixelFormat == 0 && configParams.colorSpace != EGL_COLORSPACE_LINEAR)
170 {
171 std::cerr << "Could not find a compatible pixel format for a non-linear color space."
172 << std::endl;
173 return GLWindowResult::NoColorspaceSupport;
174 }
175
176 if (pixelFormat == 0)
177 {
178 pixelFormat = ChoosePixelFormat(mDeviceContext, &pixelFormatDescriptor);
179 }
180
181 if (pixelFormat == 0)
182 {
183 std::cerr << "Could not find a compatible pixel format." << std::endl;
184 DumpLastWindowsError();
185 return GLWindowResult::Error;
186 }
187
188 // According to the Windows docs, it is an error to set a pixel format twice.
189 int currentPixelFormat = GetPixelFormat(mDeviceContext);
190 if (currentPixelFormat != pixelFormat)
191 {
192 if (SetPixelFormat(mDeviceContext, pixelFormat, &pixelFormatDescriptor) != TRUE)
193 {
194 std::cerr << "Failed to set the pixel format." << std::endl;
195 DumpLastWindowsError();
196 return GLWindowResult::Error;
197 }
198 }
199
200 mWGLContext = createContext(configParams, nullptr);
201 if (mWGLContext == nullptr)
202 {
203 return GLWindowResult::Error;
204 }
205
206 if (!makeCurrent())
207 {
208 return GLWindowResult::Error;
209 }
210
211 mPlatform = platformParams;
212 mConfigParams = configParams;
213
214 LoadUtilGLES(GetProcAddressWithFallback);
215 return GLWindowResult::NoError;
216 }
217
initializeGL(OSWindow * osWindow,angle::Library * glWindowingLibrary,angle::GLESDriverType driverType,const EGLPlatformParameters & platformParams,const ConfigParameters & configParams)218 bool WGLWindow::initializeGL(OSWindow *osWindow,
219 angle::Library *glWindowingLibrary,
220 angle::GLESDriverType driverType,
221 const EGLPlatformParameters &platformParams,
222 const ConfigParameters &configParams)
223 {
224 return initializeGLWithResult(osWindow, glWindowingLibrary, driverType, platformParams,
225 configParams) == GLWindowResult::NoError;
226 }
227
createContext(const ConfigParameters & configParams,HGLRC shareContext)228 HGLRC WGLWindow::createContext(const ConfigParameters &configParams, HGLRC shareContext)
229 {
230 HGLRC context = _wglCreateContext(mDeviceContext);
231 if (!context)
232 {
233 std::cerr << "Failed to create a WGL context." << std::endl;
234 return context;
235 }
236
237 if (!makeCurrent(context))
238 {
239 std::cerr << "Failed to make WGL context current." << std::endl;
240 return context;
241 }
242
243 // Reload entry points to capture extensions.
244 LoadWGL(GetProcAddressWithFallback);
245
246 if (!_wglGetExtensionsStringARB)
247 {
248 std::cerr << "Driver does not expose wglGetExtensionsStringARB." << std::endl;
249 return context;
250 }
251
252 const char *extensionsString = _wglGetExtensionsStringARB(mDeviceContext);
253
254 std::vector<std::string> extensions;
255 angle::SplitStringAlongWhitespace(extensionsString, &extensions);
256
257 if (!HasExtension(extensions, "WGL_EXT_create_context_es2_profile"))
258 {
259 std::cerr << "Driver does not expose WGL_EXT_create_context_es2_profile." << std::endl;
260 return context;
261 }
262
263 if (mConfigParams.webGLCompatibility.valid() || mConfigParams.robustResourceInit.valid())
264 {
265 std::cerr << "WGLWindow does not support the requested feature set." << std::endl;
266 return context;
267 }
268
269 // Tear down the context and create another with ES2 compatibility.
270 _wglDeleteContext(context);
271
272 // This could be extended to cover ES1 compatibility and desktop GL profiles.
273 int profileMask = 0;
274 if (mClientType == EGL_OPENGL_ES_API)
275 {
276 profileMask = WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
277 }
278 else
279 {
280 if ((mProfileMask & EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT) != 0)
281 {
282 profileMask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
283 }
284 if ((mProfileMask & EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT) != 0)
285 {
286 profileMask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
287 }
288 }
289
290 const int createAttribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB,
291 mClientMajorVersion,
292 WGL_CONTEXT_MINOR_VERSION_ARB,
293 mClientMinorVersion,
294 WGL_CONTEXT_PROFILE_MASK_ARB,
295 profileMask,
296 0,
297 0};
298
299 context = _wglCreateContextAttribsARB(mDeviceContext, shareContext, createAttribs);
300 if (!context)
301 {
302 std::cerr << "Failed to create an ES2 compatible WGL context." << std::endl;
303 return context;
304 }
305
306 return context;
307 }
308
destroyGL()309 void WGLWindow::destroyGL()
310 {
311 if (mWGLContext)
312 {
313 _wglDeleteContext(mWGLContext);
314 mWGLContext = nullptr;
315 }
316
317 if (mDeviceContext)
318 {
319 ReleaseDC(mWindow, mDeviceContext);
320 mDeviceContext = nullptr;
321 }
322 }
323
isGLInitialized() const324 bool WGLWindow::isGLInitialized() const
325 {
326 return mWGLContext != nullptr;
327 }
328
getCurrentContextGeneric()329 GLWindowContext WGLWindow::getCurrentContextGeneric()
330 {
331 return reinterpret_cast<GLWindowContext>(mWGLContext);
332 }
333
createContextGeneric(GLWindowContext share)334 GLWindowContext WGLWindow::createContextGeneric(GLWindowContext share)
335 {
336 HGLRC shareContext = reinterpret_cast<HGLRC>(share);
337 HGLRC newContext = createContext(mConfigParams, shareContext);
338
339 // createContext() calls makeCurrent(newContext), so we need to restore the current context.
340 if (!makeCurrent())
341 {
342 return nullptr;
343 }
344
345 return reinterpret_cast<GLWindowContext>(newContext);
346 }
347
makeCurrent()348 bool WGLWindow::makeCurrent()
349 {
350 return makeCurrent(mWGLContext);
351 }
352
makeCurrentGeneric(GLWindowContext context)353 bool WGLWindow::makeCurrentGeneric(GLWindowContext context)
354 {
355 HGLRC wglContext = reinterpret_cast<HGLRC>(context);
356 return makeCurrent(wglContext);
357 }
358
makeCurrent(HGLRC context)359 bool WGLWindow::makeCurrent(HGLRC context)
360 {
361 if (_wglMakeCurrent(mDeviceContext, context) == FALSE)
362 {
363 std::cerr << "Error during wglMakeCurrent.\n";
364 return false;
365 }
366
367 return true;
368 }
369
createImage(GLWindowContext context,Enum target,ClientBuffer buffer,const Attrib * attrib_list)370 WGLWindow::Image WGLWindow::createImage(GLWindowContext context,
371 Enum target,
372 ClientBuffer buffer,
373 const Attrib *attrib_list)
374 {
375 std::cerr << "WGLWindow::createImage not implemented.\n";
376 return nullptr;
377 }
378
createImageKHR(GLWindowContext context,Enum target,ClientBuffer buffer,const AttribKHR * attrib_list)379 WGLWindow::Image WGLWindow::createImageKHR(GLWindowContext context,
380 Enum target,
381 ClientBuffer buffer,
382 const AttribKHR *attrib_list)
383 {
384 std::cerr << "WGLWindow::createImageKHR not implemented.\n";
385 return nullptr;
386 }
387
destroyImage(Image image)388 EGLBoolean WGLWindow::destroyImage(Image image)
389 {
390 std::cerr << "WGLWindow::destroyImage not implemented.\n";
391 return EGL_FALSE;
392 }
393
destroyImageKHR(Image image)394 EGLBoolean WGLWindow::destroyImageKHR(Image image)
395 {
396 std::cerr << "WGLWindow::destroyImageKHR not implemented.\n";
397 return EGL_FALSE;
398 }
399
createSync(EGLDisplay dpy,EGLenum type,const EGLAttrib * attrib_list)400 WGLWindow::Sync WGLWindow::createSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list)
401 {
402 return nullptr;
403 }
404
createSyncKHR(EGLDisplay dpy,EGLenum type,const EGLint * attrib_list)405 WGLWindow::Sync WGLWindow::createSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
406 {
407 return nullptr;
408 }
409
destroySync(EGLDisplay dpy,Sync sync)410 EGLBoolean WGLWindow::destroySync(EGLDisplay dpy, Sync sync)
411 {
412 return EGL_FALSE;
413 }
414
destroySyncKHR(EGLDisplay dpy,Sync sync)415 EGLBoolean WGLWindow::destroySyncKHR(EGLDisplay dpy, Sync sync)
416 {
417 return EGL_FALSE;
418 }
419
clientWaitSync(EGLDisplay dpy,Sync sync,EGLint flags,EGLTimeKHR timeout)420 EGLint WGLWindow::clientWaitSync(EGLDisplay dpy, Sync sync, EGLint flags, EGLTimeKHR timeout)
421 {
422 return EGL_FALSE;
423 }
424
clientWaitSyncKHR(EGLDisplay dpy,Sync sync,EGLint flags,EGLTimeKHR timeout)425 EGLint WGLWindow::clientWaitSyncKHR(EGLDisplay dpy, Sync sync, EGLint flags, EGLTimeKHR timeout)
426 {
427 return EGL_FALSE;
428 }
429
getEGLError()430 EGLint WGLWindow::getEGLError()
431 {
432 return EGL_SUCCESS;
433 }
434
getCurrentDisplay()435 WGLWindow::Display WGLWindow::getCurrentDisplay()
436 {
437 return nullptr;
438 }
439
createPbufferSurface(const EGLint * attrib_list)440 WGLWindow::Surface WGLWindow::createPbufferSurface(const EGLint *attrib_list)
441 {
442 std::cerr << "WGLWindow::createPbufferSurface not implemented.\n";
443 return EGL_FALSE;
444 }
445
destroySurface(Surface surface)446 EGLBoolean WGLWindow::destroySurface(Surface surface)
447 {
448 std::cerr << "WGLWindow::destroySurface not implemented.\n";
449 return EGL_FALSE;
450 }
451
bindTexImage(EGLSurface surface,EGLint buffer)452 EGLBoolean WGLWindow::bindTexImage(EGLSurface surface, EGLint buffer)
453 {
454 std::cerr << "WGLWindow::bindTexImage not implemented.\n";
455 return EGL_FALSE;
456 }
457
releaseTexImage(EGLSurface surface,EGLint buffer)458 EGLBoolean WGLWindow::releaseTexImage(EGLSurface surface, EGLint buffer)
459 {
460 std::cerr << "WGLWindow::releaseTexImage not implemented.\n";
461 return EGL_FALSE;
462 }
463
makeCurrent(EGLSurface draw,EGLSurface read,EGLContext context)464 bool WGLWindow::makeCurrent(EGLSurface draw, EGLSurface read, EGLContext context)
465 {
466 std::cerr << "WGLWindow::makeCurrent(draw, read, context) not implemented.\n";
467 return EGL_FALSE;
468 }
469
setSwapInterval(EGLint swapInterval)470 bool WGLWindow::setSwapInterval(EGLint swapInterval)
471 {
472 if (!_wglSwapIntervalEXT || _wglSwapIntervalEXT(swapInterval) == FALSE)
473 {
474 std::cerr << "Error during wglSwapIntervalEXT.\n";
475 return false;
476 }
477 return true;
478 }
479
swap()480 void WGLWindow::swap()
481 {
482 if (SwapBuffers(mDeviceContext) == FALSE)
483 {
484 std::cerr << "Error during SwapBuffers.\n";
485 }
486 }
487
hasError() const488 bool WGLWindow::hasError() const
489 {
490 return GetLastError() != S_OK;
491 }
492
getProcAddress(const char * name)493 GenericProc WGLWindow::getProcAddress(const char *name)
494 {
495 return GetProcAddressWithFallback(name);
496 }
497
498 // static
New(EGLenum clientType,int majorVersion,int minorVersion,int profileMask)499 WGLWindow *WGLWindow::New(EGLenum clientType, int majorVersion, int minorVersion, int profileMask)
500 {
501 return new WGLWindow(clientType, majorVersion, minorVersion, profileMask);
502 }
503
504 // static
Delete(WGLWindow ** window)505 void WGLWindow::Delete(WGLWindow **window)
506 {
507 delete *window;
508 *window = nullptr;
509 }
510