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