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