• 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 {
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