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