• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 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 
7 // DisplayWGL.h: WGL implementation of egl::Display
8 
9 #include "libANGLE/renderer/gl/wgl/DisplayWGL.h"
10 
11 #include "common/debug.h"
12 #include "common/system_utils.h"
13 #include "libANGLE/Config.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/Display.h"
16 #include "libANGLE/Surface.h"
17 #include "libANGLE/renderer/gl/ContextGL.h"
18 #include "libANGLE/renderer/gl/RendererGL.h"
19 #include "libANGLE/renderer/gl/renderergl_utils.h"
20 #include "libANGLE/renderer/gl/wgl/ContextWGL.h"
21 #include "libANGLE/renderer/gl/wgl/D3DTextureSurfaceWGL.h"
22 #include "libANGLE/renderer/gl/wgl/DXGISwapChainWindowSurfaceWGL.h"
23 #include "libANGLE/renderer/gl/wgl/FunctionsWGL.h"
24 #include "libANGLE/renderer/gl/wgl/PbufferSurfaceWGL.h"
25 #include "libANGLE/renderer/gl/wgl/RendererWGL.h"
26 #include "libANGLE/renderer/gl/wgl/WindowSurfaceWGL.h"
27 #include "libANGLE/renderer/gl/wgl/wgl_utils.h"
28 #include "platform/PlatformMethods.h"
29 
30 #include <EGL/eglext.h>
31 #include <sstream>
32 #include <string>
33 
34 namespace rx
35 {
36 
37 namespace
38 {
39 
GetErrorMessage()40 std::string GetErrorMessage()
41 {
42     DWORD errorCode     = GetLastError();
43     LPSTR messageBuffer = nullptr;
44     size_t size         = FormatMessageA(
45         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
46         NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
47     std::string message(messageBuffer, size);
48     if (size == 0)
49     {
50         std::ostringstream stream;
51         stream << "Failed to get the error message for '" << errorCode << "' due to the error '"
52                << GetLastError() << "'";
53         message = stream.str();
54     }
55     if (messageBuffer != nullptr)
56     {
57         LocalFree(messageBuffer);
58     }
59     return message;
60 }
61 
62 }  // anonymous namespace
63 
64 class FunctionsGLWindows : public FunctionsGL
65 {
66   public:
FunctionsGLWindows(HMODULE openGLModule,PFNWGLGETPROCADDRESSPROC getProcAddressWGL)67     FunctionsGLWindows(HMODULE openGLModule, PFNWGLGETPROCADDRESSPROC getProcAddressWGL)
68         : mOpenGLModule(openGLModule), mGetProcAddressWGL(getProcAddressWGL)
69     {
70         ASSERT(mOpenGLModule);
71         ASSERT(mGetProcAddressWGL);
72     }
73 
~FunctionsGLWindows()74     ~FunctionsGLWindows() override {}
75 
76   private:
loadProcAddress(const std::string & function) const77     void *loadProcAddress(const std::string &function) const override
78     {
79         void *proc = reinterpret_cast<void *>(mGetProcAddressWGL(function.c_str()));
80         if (!proc)
81         {
82             proc = reinterpret_cast<void *>(GetProcAddress(mOpenGLModule, function.c_str()));
83         }
84         return proc;
85     }
86 
87     HMODULE mOpenGLModule;
88     PFNWGLGETPROCADDRESSPROC mGetProcAddressWGL;
89 };
90 
DisplayWGL(const egl::DisplayState & state)91 DisplayWGL::DisplayWGL(const egl::DisplayState &state)
92     : DisplayGL(state),
93       mRenderer(nullptr),
94       mCurrentNativeContexts(),
95       mOpenGLModule(nullptr),
96       mFunctionsWGL(nullptr),
97       mHasWGLCreateContextRobustness(false),
98       mHasRobustness(false),
99       mWindowClass(0),
100       mWindow(nullptr),
101       mDeviceContext(nullptr),
102       mPixelFormat(0),
103       mUseDXGISwapChains(false),
104       mHasDXInterop(false),
105       mDxgiModule(nullptr),
106       mD3d11Module(nullptr),
107       mD3D11DeviceHandle(nullptr),
108       mD3D11Device(nullptr),
109       mD3D11Device1(nullptr)
110 {}
111 
~DisplayWGL()112 DisplayWGL::~DisplayWGL() {}
113 
initialize(egl::Display * display)114 egl::Error DisplayWGL::initialize(egl::Display *display)
115 {
116     egl::Error error = initializeImpl(display);
117     if (error.isError())
118     {
119         destroy();
120         return error;
121     }
122 
123     return DisplayGL::initialize(display);
124 }
125 
initializeImpl(egl::Display * display)126 egl::Error DisplayWGL::initializeImpl(egl::Display *display)
127 {
128     mDisplayAttributes = display->getAttributeMap();
129 
130     mOpenGLModule = LoadLibraryExA("opengl32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
131     if (!mOpenGLModule)
132     {
133         return egl::Error(EGL_NOT_INITIALIZED, "Failed to load OpenGL library.");
134     }
135 
136     mFunctionsWGL = new FunctionsWGL();
137     mFunctionsWGL->initialize(mOpenGLModule, nullptr);
138 
139     // WGL can't grab extensions until it creates a context because it needs to load the driver's
140     // DLLs first. Create a stub context to load the driver and determine which GL versions are
141     // available.
142 
143     // Work around compile error from not defining "UNICODE" while Chromium does
144     const LPWSTR idcArrow = MAKEINTRESOURCEW(32512);
145 
146     std::wostringstream stream;
147     stream << L"ANGLE DisplayWGL " << gl::FmtHex<egl::Display *, wchar_t>(display)
148            << L" Intermediate Window Class";
149     std::wstring className = stream.str();
150 
151     WNDCLASSW intermediateClassDesc     = {};
152     intermediateClassDesc.style         = CS_OWNDC;
153     intermediateClassDesc.lpfnWndProc   = DefWindowProcW;
154     intermediateClassDesc.cbClsExtra    = 0;
155     intermediateClassDesc.cbWndExtra    = 0;
156     intermediateClassDesc.hInstance     = GetModuleHandle(nullptr);
157     intermediateClassDesc.hIcon         = nullptr;
158     intermediateClassDesc.hCursor       = LoadCursorW(nullptr, idcArrow);
159     intermediateClassDesc.hbrBackground = nullptr;
160     intermediateClassDesc.lpszMenuName  = nullptr;
161     intermediateClassDesc.lpszClassName = className.c_str();
162     mWindowClass                        = RegisterClassW(&intermediateClassDesc);
163     if (!mWindowClass)
164     {
165         std::ostringstream err;
166         err << "Failed to register intermediate OpenGL window class \""
167             << gl::FmtHex<egl::Display *, char>(display)
168             << "\":" << gl::FmtErr(HRESULT_CODE(GetLastError()));
169         return egl::Error(EGL_NOT_INITIALIZED, err.str());
170     }
171 
172     HWND placeholderWindow =
173         CreateWindowExW(0, reinterpret_cast<LPCWSTR>(mWindowClass), L"ANGLE Placeholder Window",
174                         WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
175                         CW_USEDEFAULT, nullptr, nullptr, nullptr, nullptr);
176     if (!placeholderWindow)
177     {
178         return egl::Error(EGL_NOT_INITIALIZED, "Failed to create placeholder OpenGL window.");
179     }
180 
181     HDC placeholderDeviceContext = GetDC(placeholderWindow);
182     if (!placeholderDeviceContext)
183     {
184         return egl::Error(EGL_NOT_INITIALIZED,
185                           "Failed to get the device context of the placeholder OpenGL window.");
186     }
187 
188     const PIXELFORMATDESCRIPTOR pixelFormatDescriptor = wgl::GetDefaultPixelFormatDescriptor();
189 
190     int placeholderPixelFormat =
191         ChoosePixelFormat(placeholderDeviceContext, &pixelFormatDescriptor);
192     if (placeholderPixelFormat == 0)
193     {
194         return egl::Error(
195             EGL_NOT_INITIALIZED,
196             "Could not find a compatible pixel format for the placeholder OpenGL window.");
197     }
198 
199     if (!SetPixelFormat(placeholderDeviceContext, placeholderPixelFormat, &pixelFormatDescriptor))
200     {
201         return egl::Error(EGL_NOT_INITIALIZED,
202                           "Failed to set the pixel format on the intermediate OpenGL window.");
203     }
204 
205     HGLRC placeholderWGLContext = mFunctionsWGL->createContext(placeholderDeviceContext);
206     if (!placeholderDeviceContext)
207     {
208         return egl::Error(EGL_NOT_INITIALIZED,
209                           "Failed to create a WGL context for the placeholder OpenGL window.");
210     }
211 
212     if (!mFunctionsWGL->makeCurrent(placeholderDeviceContext, placeholderWGLContext))
213     {
214         return egl::Error(EGL_NOT_INITIALIZED,
215                           "Failed to make the placeholder WGL context current.");
216     }
217 
218     // Reinitialize the wgl functions to grab the extensions
219     mFunctionsWGL->initialize(mOpenGLModule, placeholderDeviceContext);
220 
221     mHasWGLCreateContextRobustness =
222         mFunctionsWGL->hasExtension("WGL_ARB_create_context_robustness");
223 
224     // Destroy the placeholder window and context
225     mFunctionsWGL->makeCurrent(placeholderDeviceContext, nullptr);
226     mFunctionsWGL->deleteContext(placeholderWGLContext);
227     ReleaseDC(placeholderWindow, placeholderDeviceContext);
228     DestroyWindow(placeholderWindow);
229 
230     const egl::AttributeMap &displayAttributes = display->getAttributeMap();
231     EGLint requestedDisplayType                = static_cast<EGLint>(displayAttributes.get(
232         EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE));
233     if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE &&
234         !mFunctionsWGL->hasExtension("WGL_EXT_create_context_es2_profile") &&
235         !mFunctionsWGL->hasExtension("WGL_EXT_create_context_es_profile"))
236     {
237         return egl::Error(EGL_NOT_INITIALIZED,
238                           "Cannot create an OpenGL ES platform on Windows without "
239                           "the WGL_EXT_create_context_es(2)_profile extension.");
240     }
241 
242     // Create the real intermediate context and windows
243     mWindow = CreateWindowExA(0, reinterpret_cast<const char *>(mWindowClass),
244                               "ANGLE Intermediate Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
245                               CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr,
246                               nullptr, nullptr);
247     if (!mWindow)
248     {
249         return egl::Error(EGL_NOT_INITIALIZED, "Failed to create intermediate OpenGL window.");
250     }
251 
252     mDeviceContext = GetDC(mWindow);
253     if (!mDeviceContext)
254     {
255         return egl::Error(EGL_NOT_INITIALIZED,
256                           "Failed to get the device context of the intermediate OpenGL window.");
257     }
258 
259     if (mFunctionsWGL->choosePixelFormatARB)
260     {
261         std::vector<int> attribs = wgl::GetDefaultPixelFormatAttributes(false);
262 
263         UINT matchingFormats = 0;
264         mFunctionsWGL->choosePixelFormatARB(mDeviceContext, &attribs[0], nullptr, 1u, &mPixelFormat,
265                                             &matchingFormats);
266     }
267 
268     if (mPixelFormat == 0)
269     {
270         mPixelFormat = ChoosePixelFormat(mDeviceContext, &pixelFormatDescriptor);
271     }
272 
273     if (mPixelFormat == 0)
274     {
275         return egl::Error(
276             EGL_NOT_INITIALIZED,
277             "Could not find a compatible pixel format for the intermediate OpenGL window.");
278     }
279 
280     if (!SetPixelFormat(mDeviceContext, mPixelFormat, &pixelFormatDescriptor))
281     {
282         return egl::Error(EGL_NOT_INITIALIZED,
283                           "Failed to set the pixel format on the intermediate OpenGL window.");
284     }
285 
286     ANGLE_TRY(createRenderer(&mRenderer));
287     const FunctionsGL *functionsGL = mRenderer->getFunctions();
288 
289     mHasRobustness = functionsGL->getGraphicsResetStatus != nullptr;
290     if (mHasWGLCreateContextRobustness != mHasRobustness)
291     {
292         WARN() << "WGL_ARB_create_context_robustness exists but unable to create a context with "
293                   "robustness.";
294     }
295 
296     // Intel OpenGL ES drivers are not currently supported due to bugs in the driver and ANGLE
297     VendorID vendor = GetVendorID(functionsGL);
298     if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE && IsIntel(vendor))
299     {
300         return egl::Error(EGL_NOT_INITIALIZED, "Intel OpenGL ES drivers are not supported.");
301     }
302 
303     // Create DXGI swap chains for windows that come from other processes.  Windows is unable to
304     // SetPixelFormat on windows from other processes when a sandbox is enabled.
305     HDC nativeDisplay = display->getNativeDisplayId();
306     HWND nativeWindow = WindowFromDC(nativeDisplay);
307     if (nativeWindow != nullptr)
308     {
309         DWORD currentProcessId = GetCurrentProcessId();
310         DWORD windowProcessId;
311         GetWindowThreadProcessId(nativeWindow, &windowProcessId);
312 
313         // AMD drivers advertise the WGL_NV_DX_interop and WGL_NV_DX_interop2 extensions but fail
314         mUseDXGISwapChains = !IsAMD(vendor) && (currentProcessId != windowProcessId);
315     }
316     else
317     {
318         mUseDXGISwapChains = false;
319     }
320 
321     mHasDXInterop = mFunctionsWGL->hasExtension("WGL_NV_DX_interop2");
322 
323     if (mUseDXGISwapChains)
324     {
325         if (mHasDXInterop)
326         {
327             ANGLE_TRY(initializeD3DDevice());
328         }
329         else
330         {
331             // Want to use DXGI swap chains but WGL_NV_DX_interop2 is not present, fail
332             // initialization
333             return egl::Error(EGL_NOT_INITIALIZED,
334                               "WGL_NV_DX_interop2 is required but not present.");
335         }
336     }
337 
338     const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
339     if (maxVersion < gl::Version(2, 0))
340     {
341         return egl::Error(EGL_NOT_INITIALIZED, "OpenGL ES 2.0 is not supportable.");
342     }
343 
344     return egl::NoError();
345 }
346 
terminate()347 void DisplayWGL::terminate()
348 {
349     DisplayGL::terminate();
350     destroy();
351 }
352 
destroy()353 void DisplayWGL::destroy()
354 {
355     releaseD3DDevice(mD3D11DeviceHandle);
356 
357     mRenderer.reset();
358 
359     if (mFunctionsWGL)
360     {
361         if (mDeviceContext)
362         {
363             mFunctionsWGL->makeCurrent(mDeviceContext, nullptr);
364         }
365     }
366     mCurrentNativeContexts.clear();
367 
368     SafeDelete(mFunctionsWGL);
369 
370     if (mDeviceContext)
371     {
372         ReleaseDC(mWindow, mDeviceContext);
373         mDeviceContext = nullptr;
374     }
375 
376     if (mWindow)
377     {
378         DestroyWindow(mWindow);
379         mWindow = nullptr;
380     }
381 
382     if (mWindowClass)
383     {
384         if (!UnregisterClassA(reinterpret_cast<const char *>(mWindowClass),
385                               GetModuleHandle(nullptr)))
386         {
387             WARN() << "Failed to unregister OpenGL window class: " << gl::FmtHex(mWindowClass);
388         }
389         mWindowClass = NULL;
390     }
391 
392     if (mOpenGLModule)
393     {
394         FreeLibrary(mOpenGLModule);
395         mOpenGLModule = nullptr;
396     }
397 
398     SafeRelease(mD3D11Device);
399     SafeRelease(mD3D11Device1);
400 
401     if (mDxgiModule)
402     {
403         FreeLibrary(mDxgiModule);
404         mDxgiModule = nullptr;
405     }
406 
407     if (mD3d11Module)
408     {
409         FreeLibrary(mD3d11Module);
410         mD3d11Module = nullptr;
411     }
412 
413     ASSERT(mRegisteredD3DDevices.empty());
414 }
415 
createWindowSurface(const egl::SurfaceState & state,EGLNativeWindowType window,const egl::AttributeMap & attribs)416 SurfaceImpl *DisplayWGL::createWindowSurface(const egl::SurfaceState &state,
417                                              EGLNativeWindowType window,
418                                              const egl::AttributeMap &attribs)
419 {
420     EGLint orientation = static_cast<EGLint>(attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0));
421     // TODO(crbug.com/540829, anglebug.com/42266638) other orientations
422     // are still unsupported, so allow fallback instead of crashing
423     // later in eglCreateWindowSurface
424     if (mUseDXGISwapChains && orientation == EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE)
425     {
426         egl::Error error = initializeD3DDevice();
427         if (error.isError())
428         {
429             return nullptr;
430         }
431 
432         return new DXGISwapChainWindowSurfaceWGL(
433             state, mRenderer->getStateManager(), window, mD3D11Device, mD3D11DeviceHandle,
434             mDeviceContext, mRenderer->getFunctions(), mFunctionsWGL, orientation);
435     }
436     else
437     {
438         return new WindowSurfaceWGL(state, window, mPixelFormat, mFunctionsWGL, orientation);
439     }
440 }
441 
createPbufferSurface(const egl::SurfaceState & state,const egl::AttributeMap & attribs)442 SurfaceImpl *DisplayWGL::createPbufferSurface(const egl::SurfaceState &state,
443                                               const egl::AttributeMap &attribs)
444 {
445     EGLint width          = static_cast<EGLint>(attribs.get(EGL_WIDTH, 0));
446     EGLint height         = static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0));
447     bool largest          = (attribs.get(EGL_LARGEST_PBUFFER, EGL_FALSE) == EGL_TRUE);
448     EGLenum textureFormat = static_cast<EGLenum>(attribs.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE));
449     EGLenum textureTarget = static_cast<EGLenum>(attribs.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE));
450 
451     return new PbufferSurfaceWGL(state, width, height, textureFormat, textureTarget, largest,
452                                  mPixelFormat, mDeviceContext, mFunctionsWGL);
453 }
454 
createPbufferFromClientBuffer(const egl::SurfaceState & state,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)455 SurfaceImpl *DisplayWGL::createPbufferFromClientBuffer(const egl::SurfaceState &state,
456                                                        EGLenum buftype,
457                                                        EGLClientBuffer clientBuffer,
458                                                        const egl::AttributeMap &attribs)
459 {
460     egl::Error error = initializeD3DDevice();
461     if (error.isError())
462     {
463         return nullptr;
464     }
465 
466     return new D3DTextureSurfaceWGL(state, mRenderer->getStateManager(), buftype, clientBuffer,
467                                     this, mDeviceContext, mD3D11Device, mD3D11Device1,
468                                     mRenderer->getFunctions(), mFunctionsWGL);
469 }
470 
createPixmapSurface(const egl::SurfaceState & state,NativePixmapType nativePixmap,const egl::AttributeMap & attribs)471 SurfaceImpl *DisplayWGL::createPixmapSurface(const egl::SurfaceState &state,
472                                              NativePixmapType nativePixmap,
473                                              const egl::AttributeMap &attribs)
474 {
475     UNIMPLEMENTED();
476     return nullptr;
477 }
478 
createContext(const gl::State & state,gl::ErrorSet * errorSet,const egl::Config * configuration,const gl::Context * shareContext,const egl::AttributeMap & attribs)479 rx::ContextImpl *DisplayWGL::createContext(const gl::State &state,
480                                            gl::ErrorSet *errorSet,
481                                            const egl::Config *configuration,
482                                            const gl::Context *shareContext,
483                                            const egl::AttributeMap &attribs)
484 {
485     return new ContextWGL(state, errorSet, mRenderer);
486 }
487 
generateConfigs()488 egl::ConfigSet DisplayWGL::generateConfigs()
489 {
490     egl::ConfigSet configs;
491 
492     int minSwapInterval = 1;
493     int maxSwapInterval = 1;
494     if (mFunctionsWGL->swapIntervalEXT)
495     {
496         // No defined maximum swap interval in WGL_EXT_swap_control, use a reasonable number
497         minSwapInterval = 0;
498         maxSwapInterval = 8;
499     }
500 
501     const gl::Version &maxVersion = getMaxSupportedESVersion();
502     ASSERT(maxVersion >= gl::Version(2, 0));
503     bool supportsES3 = maxVersion >= gl::Version(3, 0);
504 
505     PIXELFORMATDESCRIPTOR pixelFormatDescriptor;
506     DescribePixelFormat(mDeviceContext, mPixelFormat, sizeof(pixelFormatDescriptor),
507                         &pixelFormatDescriptor);
508 
509     auto getAttrib = [this](int attrib) {
510         return wgl::QueryWGLFormatAttrib(mDeviceContext, mPixelFormat, attrib, mFunctionsWGL);
511     };
512 
513     const EGLint optimalSurfaceOrientation =
514         mUseDXGISwapChains ? EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE : 0;
515 
516     egl::Config config;
517     config.renderTargetFormat = GL_RGBA8;  // TODO: use the bit counts to determine the format
518     config.depthStencilFormat =
519         GL_DEPTH24_STENCIL8;  // TODO: use the bit counts to determine the format
520     config.bufferSize        = pixelFormatDescriptor.cColorBits;
521     config.redSize           = pixelFormatDescriptor.cRedBits;
522     config.greenSize         = pixelFormatDescriptor.cGreenBits;
523     config.blueSize          = pixelFormatDescriptor.cBlueBits;
524     config.luminanceSize     = 0;
525     config.alphaSize         = pixelFormatDescriptor.cAlphaBits;
526     config.alphaMaskSize     = 0;
527     config.bindToTextureRGB  = (getAttrib(WGL_BIND_TO_TEXTURE_RGB_ARB) == TRUE);
528     config.bindToTextureRGBA = (getAttrib(WGL_BIND_TO_TEXTURE_RGBA_ARB) == TRUE);
529     config.colorBufferType   = EGL_RGB_BUFFER;
530     config.configCaveat      = EGL_NONE;
531     config.conformant        = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0);
532     config.depthSize         = pixelFormatDescriptor.cDepthBits;
533     config.level             = 0;
534     config.matchNativePixmap = EGL_NONE;
535     config.maxPBufferWidth   = getAttrib(WGL_MAX_PBUFFER_WIDTH_ARB);
536     config.maxPBufferHeight  = getAttrib(WGL_MAX_PBUFFER_HEIGHT_ARB);
537     config.maxPBufferPixels  = getAttrib(WGL_MAX_PBUFFER_PIXELS_ARB);
538     config.maxSwapInterval   = maxSwapInterval;
539     config.minSwapInterval   = minSwapInterval;
540     config.nativeRenderable  = EGL_TRUE;  // Direct rendering
541     config.nativeVisualID    = 0;
542     config.nativeVisualType  = EGL_NONE;
543     config.renderableType    = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0);
544     config.sampleBuffers     = 0;  // FIXME: enumerate multi-sampling
545     config.samples           = 0;
546     config.stencilSize       = pixelFormatDescriptor.cStencilBits;
547     config.surfaceType =
548         ((pixelFormatDescriptor.dwFlags & PFD_DRAW_TO_WINDOW) ? EGL_WINDOW_BIT : 0) |
549         ((getAttrib(WGL_DRAW_TO_PBUFFER_ARB) == TRUE) ? EGL_PBUFFER_BIT : 0) |
550         ((getAttrib(WGL_SWAP_METHOD_ARB) == WGL_SWAP_COPY_ARB) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT
551                                                                : 0);
552     config.optimalOrientation = optimalSurfaceOrientation;
553     config.colorComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
554 
555     config.transparentType       = EGL_NONE;
556     config.transparentRedValue   = 0;
557     config.transparentGreenValue = 0;
558     config.transparentBlueValue  = 0;
559 
560     configs.add(config);
561 
562     return configs;
563 }
564 
testDeviceLost()565 bool DisplayWGL::testDeviceLost()
566 {
567     return false;
568 }
569 
restoreLostDevice(const egl::Display * display)570 egl::Error DisplayWGL::restoreLostDevice(const egl::Display *display)
571 {
572     return egl::Error(EGL_BAD_DISPLAY);
573 }
574 
isValidNativeWindow(EGLNativeWindowType window) const575 bool DisplayWGL::isValidNativeWindow(EGLNativeWindowType window) const
576 {
577     return (IsWindow(window) == TRUE);
578 }
579 
validateClientBuffer(const egl::Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const580 egl::Error DisplayWGL::validateClientBuffer(const egl::Config *configuration,
581                                             EGLenum buftype,
582                                             EGLClientBuffer clientBuffer,
583                                             const egl::AttributeMap &attribs) const
584 {
585     switch (buftype)
586     {
587         case EGL_D3D_TEXTURE_ANGLE:
588         case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
589             ANGLE_TRY(const_cast<DisplayWGL *>(this)->initializeD3DDevice());
590             return D3DTextureSurfaceWGL::ValidateD3DTextureClientBuffer(
591                 buftype, clientBuffer, mD3D11Device, mD3D11Device1);
592 
593         default:
594             return DisplayGL::validateClientBuffer(configuration, buftype, clientBuffer, attribs);
595     }
596 }
597 
initializeD3DDevice()598 egl::Error DisplayWGL::initializeD3DDevice()
599 {
600     if (mD3D11Device != nullptr)
601     {
602         return egl::NoError();
603     }
604 
605     mDxgiModule = LoadLibrary(TEXT("dxgi.dll"));
606     if (!mDxgiModule)
607     {
608         return egl::Error(EGL_NOT_INITIALIZED, "Failed to load DXGI library.");
609     }
610 
611     mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
612     if (!mD3d11Module)
613     {
614         return egl::Error(EGL_NOT_INITIALIZED, "Failed to load d3d11 library.");
615     }
616 
617     PFN_D3D11_CREATE_DEVICE d3d11CreateDevice = nullptr;
618     d3d11CreateDevice                         = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(
619         GetProcAddress(mD3d11Module, "D3D11CreateDevice"));
620     if (d3d11CreateDevice == nullptr)
621     {
622         return egl::Error(EGL_NOT_INITIALIZED, "Could not retrieve D3D11CreateDevice address.");
623     }
624 
625     HRESULT result = d3d11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0,
626                                        D3D11_SDK_VERSION, &mD3D11Device, nullptr, nullptr);
627     if (FAILED(result))
628     {
629         std::ostringstream err;
630         err << "Could not create D3D11 device, " << gl::FmtHR(result);
631         return egl::Error(EGL_NOT_INITIALIZED, err.str());
632     }
633 
634     mD3D11Device->QueryInterface(__uuidof(ID3D11Device1),
635                                  reinterpret_cast<void **>(&mD3D11Device1));
636 
637     return registerD3DDevice(mD3D11Device, &mD3D11DeviceHandle);
638 }
639 
generateExtensions(egl::DisplayExtensions * outExtensions) const640 void DisplayWGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
641 {
642     // Only enable the surface orientation  and post sub buffer for DXGI swap chain surfaces, they
643     // prefer to swap with inverted Y.
644     outExtensions->postSubBuffer      = mUseDXGISwapChains;
645     outExtensions->surfaceOrientation = mUseDXGISwapChains;
646 
647     outExtensions->createContextRobustness = mHasRobustness;
648 
649     outExtensions->d3dTextureClientBuffer         = mHasDXInterop;
650     outExtensions->d3dShareHandleClientBuffer     = mHasDXInterop;
651     outExtensions->surfaceD3DTexture2DShareHandle = true;
652     outExtensions->querySurfacePointer            = true;
653     outExtensions->keyedMutex                     = true;
654 
655     // Contexts are virtualized so textures and semaphores can be shared globally
656     outExtensions->displayTextureShareGroup   = true;
657     outExtensions->displaySemaphoreShareGroup = true;
658 
659     outExtensions->surfacelessContext = true;
660 
661     DisplayGL::generateExtensions(outExtensions);
662 }
663 
generateCaps(egl::Caps * outCaps) const664 void DisplayWGL::generateCaps(egl::Caps *outCaps) const
665 {
666     outCaps->textureNPOT = true;
667 }
668 
makeCurrentSurfaceless(gl::Context * context)669 egl::Error DisplayWGL::makeCurrentSurfaceless(gl::Context *context)
670 {
671     // Nothing to do because WGL always uses the same context and the previous surface can be left
672     // current.
673     return egl::NoError();
674 }
675 
waitClient(const gl::Context * context)676 egl::Error DisplayWGL::waitClient(const gl::Context *context)
677 {
678     // Unimplemented as this is not needed for WGL
679     return egl::NoError();
680 }
681 
waitNative(const gl::Context * context,EGLint engine)682 egl::Error DisplayWGL::waitNative(const gl::Context *context, EGLint engine)
683 {
684     // Unimplemented as this is not needed for WGL
685     return egl::NoError();
686 }
687 
makeCurrent(egl::Display * display,egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)688 egl::Error DisplayWGL::makeCurrent(egl::Display *display,
689                                    egl::Surface *drawSurface,
690                                    egl::Surface *readSurface,
691                                    gl::Context *context)
692 {
693     CurrentNativeContext &currentContext =
694         mCurrentNativeContexts[angle::GetCurrentThreadUniqueId()];
695 
696     HDC newDC = mDeviceContext;
697     if (drawSurface)
698     {
699         SurfaceWGL *drawSurfaceWGL = GetImplAs<SurfaceWGL>(drawSurface);
700         newDC                      = drawSurfaceWGL->getDC();
701     }
702 
703     HGLRC newContext = currentContext.glrc;
704     if (context)
705     {
706         ContextWGL *contextWGL = GetImplAs<ContextWGL>(context);
707         newContext             = contextWGL->getContext();
708     }
709     else if (!mUseDXGISwapChains)
710     {
711         newContext = 0;
712     }
713 
714     if (newDC != currentContext.dc || newContext != currentContext.glrc)
715     {
716         ASSERT(newDC != 0);
717 
718         if (!mFunctionsWGL->makeCurrent(newDC, newContext))
719         {
720             // TODO(geofflang): What error type here?
721             return egl::Error(EGL_CONTEXT_LOST, "Failed to make the WGL context current.");
722         }
723         currentContext.dc   = newDC;
724         currentContext.glrc = newContext;
725     }
726 
727     return DisplayGL::makeCurrent(display, drawSurface, readSurface, context);
728 }
729 
registerD3DDevice(IUnknown * device,HANDLE * outHandle)730 egl::Error DisplayWGL::registerD3DDevice(IUnknown *device, HANDLE *outHandle)
731 {
732     ASSERT(device != nullptr);
733     ASSERT(outHandle != nullptr);
734 
735     auto iter = mRegisteredD3DDevices.find(device);
736     if (iter != mRegisteredD3DDevices.end())
737     {
738         iter->second.refCount++;
739         *outHandle = iter->second.handle;
740         return egl::NoError();
741     }
742 
743     HANDLE handle = mFunctionsWGL->dxOpenDeviceNV(device);
744     if (!handle)
745     {
746         return egl::Error(EGL_BAD_PARAMETER, "Failed to open D3D device.");
747     }
748 
749     device->AddRef();
750 
751     D3DObjectHandle newDeviceInfo;
752     newDeviceInfo.handle          = handle;
753     newDeviceInfo.refCount        = 1;
754     mRegisteredD3DDevices[device] = newDeviceInfo;
755 
756     *outHandle = handle;
757     return egl::NoError();
758 }
759 
releaseD3DDevice(HANDLE deviceHandle)760 void DisplayWGL::releaseD3DDevice(HANDLE deviceHandle)
761 {
762     for (auto iter = mRegisteredD3DDevices.begin(); iter != mRegisteredD3DDevices.end(); iter++)
763     {
764         if (iter->second.handle == deviceHandle)
765         {
766             iter->second.refCount--;
767             if (iter->second.refCount == 0)
768             {
769                 mFunctionsWGL->dxCloseDeviceNV(iter->second.handle);
770                 iter->first->Release();
771                 mRegisteredD3DDevices.erase(iter);
772                 break;
773             }
774         }
775     }
776 }
777 
getMaxSupportedESVersion() const778 gl::Version DisplayWGL::getMaxSupportedESVersion() const
779 {
780     return mRenderer->getMaxSupportedESVersion();
781 }
782 
destroyNativeContext(HGLRC context)783 void DisplayWGL::destroyNativeContext(HGLRC context)
784 {
785     mFunctionsWGL->deleteContext(context);
786 }
787 
initializeContextAttribs(const egl::AttributeMap & eglAttributes) const788 HGLRC DisplayWGL::initializeContextAttribs(const egl::AttributeMap &eglAttributes) const
789 {
790     EGLint requestedDisplayType = static_cast<EGLint>(
791         eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE));
792 
793     // Create a context of the requested version, if any.
794     gl::Version requestedVersion(static_cast<EGLint>(eglAttributes.get(
795                                      EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE)),
796                                  static_cast<EGLint>(eglAttributes.get(
797                                      EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE)));
798     if (static_cast<EGLint>(requestedVersion.major) != EGL_DONT_CARE &&
799         static_cast<EGLint>(requestedVersion.minor) != EGL_DONT_CARE)
800     {
801         int profileMask = 0;
802         if (requestedDisplayType != EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE &&
803             requestedVersion >= gl::Version(3, 2))
804         {
805             profileMask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
806         }
807         return createContextAttribs(requestedVersion, profileMask);
808     }
809 
810     // Try all the GL version in order as a workaround for Mesa context creation where the driver
811     // doesn't automatically return the highest version available.
812     for (const auto &info : GenerateContextCreationToTry(requestedDisplayType, false))
813     {
814         int profileFlag = 0;
815         if (info.type == ContextCreationTry::Type::DESKTOP_CORE)
816         {
817             profileFlag |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
818         }
819         else if (info.type == ContextCreationTry::Type::ES)
820         {
821             profileFlag |= WGL_CONTEXT_ES_PROFILE_BIT_EXT;
822         }
823 
824         HGLRC context = createContextAttribs(info.version, profileFlag);
825         if (context != nullptr)
826         {
827             return context;
828         }
829     }
830 
831     return nullptr;
832 }
833 
createContextAttribs(const gl::Version & version,int profileMask) const834 HGLRC DisplayWGL::createContextAttribs(const gl::Version &version, int profileMask) const
835 {
836     std::vector<int> attribs;
837 
838     if (mHasWGLCreateContextRobustness)
839     {
840         attribs.push_back(WGL_CONTEXT_FLAGS_ARB);
841         attribs.push_back(WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB);
842         attribs.push_back(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
843         attribs.push_back(WGL_LOSE_CONTEXT_ON_RESET_ARB);
844     }
845 
846     attribs.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB);
847     attribs.push_back(version.major);
848 
849     attribs.push_back(WGL_CONTEXT_MINOR_VERSION_ARB);
850     attribs.push_back(version.minor);
851 
852     if (profileMask != 0)
853     {
854         attribs.push_back(WGL_CONTEXT_PROFILE_MASK_ARB);
855         attribs.push_back(profileMask);
856     }
857 
858     attribs.push_back(0);
859     attribs.push_back(0);
860     return mFunctionsWGL->createContextAttribsARB(mDeviceContext, nullptr, &attribs[0]);
861 }
862 
createRenderer(std::shared_ptr<RendererWGL> * outRenderer)863 egl::Error DisplayWGL::createRenderer(std::shared_ptr<RendererWGL> *outRenderer)
864 {
865     HGLRC context = nullptr;
866 
867     if (mFunctionsWGL->createContextAttribsARB)
868     {
869         context = initializeContextAttribs(mDisplayAttributes);
870     }
871 
872     // If wglCreateContextAttribsARB is unavailable or failed, try the standard wglCreateContext
873     if (!context)
874     {
875         // Don't have control over GL versions
876         context = mFunctionsWGL->createContext(mDeviceContext);
877     }
878 
879     if (!context)
880     {
881         std::ostringstream err;
882         err << "Failed to create a WGL context for the intermediate OpenGL window."
883             << GetErrorMessage();
884         return egl::Error(EGL_NOT_INITIALIZED, err.str());
885     }
886 
887     if (!mFunctionsWGL->makeCurrent(mDeviceContext, context))
888     {
889         return egl::Error(EGL_NOT_INITIALIZED,
890                           "Failed to make the intermediate WGL context current.");
891     }
892     CurrentNativeContext &currentContext =
893         mCurrentNativeContexts[angle::GetCurrentThreadUniqueId()];
894     currentContext.dc   = mDeviceContext;
895     currentContext.glrc = context;
896 
897     std::unique_ptr<FunctionsGL> functionsGL(
898         new FunctionsGLWindows(mOpenGLModule, mFunctionsWGL->getProcAddress));
899     functionsGL->initialize(mDisplayAttributes);
900 
901     outRenderer->reset(new RendererWGL(std::move(functionsGL), mDisplayAttributes, this, context));
902 
903     return egl::NoError();
904 }
905 
initializeFrontendFeatures(angle::FrontendFeatures * features) const906 void DisplayWGL::initializeFrontendFeatures(angle::FrontendFeatures *features) const
907 {
908     mRenderer->initializeFrontendFeatures(features);
909 }
910 
populateFeatureList(angle::FeatureList * features)911 void DisplayWGL::populateFeatureList(angle::FeatureList *features)
912 {
913     mRenderer->getFeatures().populateFeatureList(features);
914 }
915 
getRenderer() const916 RendererGL *DisplayWGL::getRenderer() const
917 {
918     return reinterpret_cast<RendererGL *>(mRenderer.get());
919 }
920 
921 }  // namespace rx
922