• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 angle::GenericProc WINAPI GetProcAddressWithFallback(const char *name)
46 {
47     angle::GenericProc proc = reinterpret_cast<angle::GenericProc>(gCurrentWGLGetProcAddress(name));
48     if (proc)
49     {
50         return proc;
51     }
52 
53     return reinterpret_cast<angle::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(int glesMajorVersion,int glesMinorVersion)117 WGLWindow::WGLWindow(int glesMajorVersion, int glesMinorVersion)
118     : GLWindowBase(glesMajorVersion, glesMinorVersion),
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     angle::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     angle::LoadGLES(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     angle::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 compatiblity.
273     int kCreateAttribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB,
274                             mClientMajorVersion,
275                             WGL_CONTEXT_MINOR_VERSION_ARB,
276                             mClientMinorVersion,
277                             WGL_CONTEXT_PROFILE_MASK_ARB,
278                             WGL_CONTEXT_ES2_PROFILE_BIT_EXT,
279                             0,
280                             0};
281 
282     context = _wglCreateContextAttribsARB(mDeviceContext, shareContext, kCreateAttribs);
283     if (!context)
284     {
285         std::cerr << "Failed to create an ES2 compatible WGL context." << std::endl;
286         return context;
287     }
288 
289     return context;
290 }
291 
destroyGL()292 void WGLWindow::destroyGL()
293 {
294     if (mWGLContext)
295     {
296         _wglDeleteContext(mWGLContext);
297         mWGLContext = nullptr;
298     }
299 
300     if (mDeviceContext)
301     {
302         ReleaseDC(mWindow, mDeviceContext);
303         mDeviceContext = nullptr;
304     }
305 }
306 
isGLInitialized() const307 bool WGLWindow::isGLInitialized() const
308 {
309     return mWGLContext != nullptr;
310 }
311 
getCurrentContextGeneric()312 GLWindowContext WGLWindow::getCurrentContextGeneric()
313 {
314     return reinterpret_cast<GLWindowContext>(mWGLContext);
315 }
316 
createContextGeneric(GLWindowContext share)317 GLWindowContext WGLWindow::createContextGeneric(GLWindowContext share)
318 {
319     HGLRC shareContext = reinterpret_cast<HGLRC>(share);
320     HGLRC newContext   = createContext(mConfigParams, shareContext);
321 
322     // createContext() calls makeCurrent(newContext), so we need to restore the current context.
323     if (!makeCurrent())
324     {
325         return nullptr;
326     }
327 
328     return reinterpret_cast<GLWindowContext>(newContext);
329 }
330 
makeCurrent()331 bool WGLWindow::makeCurrent()
332 {
333     return makeCurrent(mWGLContext);
334 }
335 
makeCurrentGeneric(GLWindowContext context)336 bool WGLWindow::makeCurrentGeneric(GLWindowContext context)
337 {
338     HGLRC wglContext = reinterpret_cast<HGLRC>(context);
339     return makeCurrent(wglContext);
340 }
341 
makeCurrent(HGLRC context)342 bool WGLWindow::makeCurrent(HGLRC context)
343 {
344     if (_wglMakeCurrent(mDeviceContext, context) == FALSE)
345     {
346         std::cerr << "Error during wglMakeCurrent.\n";
347         return false;
348     }
349 
350     return true;
351 }
352 
setSwapInterval(EGLint swapInterval)353 bool WGLWindow::setSwapInterval(EGLint swapInterval)
354 {
355     if (!_wglSwapIntervalEXT || _wglSwapIntervalEXT(swapInterval) == FALSE)
356     {
357         std::cerr << "Error during wglSwapIntervalEXT.\n";
358         return false;
359     }
360     return true;
361 }
362 
swap()363 void WGLWindow::swap()
364 {
365     if (SwapBuffers(mDeviceContext) == FALSE)
366     {
367         std::cerr << "Error during SwapBuffers.\n";
368     }
369 }
370 
hasError() const371 bool WGLWindow::hasError() const
372 {
373     return GetLastError() != S_OK;
374 }
375 
getProcAddress(const char * name)376 angle::GenericProc WGLWindow::getProcAddress(const char *name)
377 {
378     return GetProcAddressWithFallback(name);
379 }
380 
381 // static
New(int glesMajorVersion,int glesMinorVersion)382 WGLWindow *WGLWindow::New(int glesMajorVersion, int glesMinorVersion)
383 {
384     return new WGLWindow(glesMajorVersion, glesMinorVersion);
385 }
386 
387 // static
Delete(WGLWindow ** window)388 void WGLWindow::Delete(WGLWindow **window)
389 {
390     delete *window;
391     *window = nullptr;
392 }
393