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