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