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