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