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 ¤tContext =
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 ¤tContext =
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