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::Error(EGL_NOT_INITIALIZED, "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 std::ostringstream err;
166 err << "Failed to register intermediate OpenGL window class \""
167 << gl::FmtHex<egl::Display *, char>(display)
168 << "\":" << gl::FmtErr(HRESULT_CODE(GetLastError()));
169 return egl::Error(EGL_NOT_INITIALIZED, err.str());
170 }
171
172 HWND placeholderWindow =
173 CreateWindowExW(0, reinterpret_cast<LPCWSTR>(mWindowClass), L"ANGLE Placeholder Window",
174 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
175 CW_USEDEFAULT, nullptr, nullptr, nullptr, nullptr);
176 if (!placeholderWindow)
177 {
178 return egl::Error(EGL_NOT_INITIALIZED, "Failed to create placeholder OpenGL window.");
179 }
180
181 HDC placeholderDeviceContext = GetDC(placeholderWindow);
182 if (!placeholderDeviceContext)
183 {
184 return egl::Error(EGL_NOT_INITIALIZED,
185 "Failed to get the device context of the placeholder OpenGL window.");
186 }
187
188 const PIXELFORMATDESCRIPTOR pixelFormatDescriptor = wgl::GetDefaultPixelFormatDescriptor();
189
190 int placeholderPixelFormat =
191 ChoosePixelFormat(placeholderDeviceContext, &pixelFormatDescriptor);
192 if (placeholderPixelFormat == 0)
193 {
194 return egl::Error(
195 EGL_NOT_INITIALIZED,
196 "Could not find a compatible pixel format for the placeholder OpenGL window.");
197 }
198
199 if (!SetPixelFormat(placeholderDeviceContext, placeholderPixelFormat, &pixelFormatDescriptor))
200 {
201 return egl::Error(EGL_NOT_INITIALIZED,
202 "Failed to set the pixel format on the intermediate OpenGL window.");
203 }
204
205 HGLRC placeholderWGLContext = mFunctionsWGL->createContext(placeholderDeviceContext);
206 if (!placeholderDeviceContext)
207 {
208 return egl::Error(EGL_NOT_INITIALIZED,
209 "Failed to create a WGL context for the placeholder OpenGL window.");
210 }
211
212 if (!mFunctionsWGL->makeCurrent(placeholderDeviceContext, placeholderWGLContext))
213 {
214 return egl::Error(EGL_NOT_INITIALIZED,
215 "Failed to make the placeholder WGL context current.");
216 }
217
218 // Reinitialize the wgl functions to grab the extensions
219 mFunctionsWGL->initialize(mOpenGLModule, placeholderDeviceContext);
220
221 mHasWGLCreateContextRobustness =
222 mFunctionsWGL->hasExtension("WGL_ARB_create_context_robustness");
223
224 // Destroy the placeholder window and context
225 mFunctionsWGL->makeCurrent(placeholderDeviceContext, nullptr);
226 mFunctionsWGL->deleteContext(placeholderWGLContext);
227 ReleaseDC(placeholderWindow, placeholderDeviceContext);
228 DestroyWindow(placeholderWindow);
229
230 const egl::AttributeMap &displayAttributes = display->getAttributeMap();
231 EGLint requestedDisplayType = static_cast<EGLint>(displayAttributes.get(
232 EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE));
233 if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE &&
234 !mFunctionsWGL->hasExtension("WGL_EXT_create_context_es2_profile") &&
235 !mFunctionsWGL->hasExtension("WGL_EXT_create_context_es_profile"))
236 {
237 return egl::Error(EGL_NOT_INITIALIZED,
238 "Cannot create an OpenGL ES platform on Windows without "
239 "the WGL_EXT_create_context_es(2)_profile extension.");
240 }
241
242 // Create the real intermediate context and windows
243 mWindow = CreateWindowExA(0, reinterpret_cast<const char *>(mWindowClass),
244 "ANGLE Intermediate Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
245 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr,
246 nullptr, nullptr);
247 if (!mWindow)
248 {
249 return egl::Error(EGL_NOT_INITIALIZED, "Failed to create intermediate OpenGL window.");
250 }
251
252 mDeviceContext = GetDC(mWindow);
253 if (!mDeviceContext)
254 {
255 return egl::Error(EGL_NOT_INITIALIZED,
256 "Failed to get the device context of the intermediate OpenGL window.");
257 }
258
259 if (mFunctionsWGL->choosePixelFormatARB)
260 {
261 std::vector<int> attribs = wgl::GetDefaultPixelFormatAttributes(false);
262
263 UINT matchingFormats = 0;
264 mFunctionsWGL->choosePixelFormatARB(mDeviceContext, &attribs[0], nullptr, 1u, &mPixelFormat,
265 &matchingFormats);
266 }
267
268 if (mPixelFormat == 0)
269 {
270 mPixelFormat = ChoosePixelFormat(mDeviceContext, &pixelFormatDescriptor);
271 }
272
273 if (mPixelFormat == 0)
274 {
275 return egl::Error(
276 EGL_NOT_INITIALIZED,
277 "Could not find a compatible pixel format for the intermediate OpenGL window.");
278 }
279
280 if (!SetPixelFormat(mDeviceContext, mPixelFormat, &pixelFormatDescriptor))
281 {
282 return egl::Error(EGL_NOT_INITIALIZED,
283 "Failed to set the pixel format on the intermediate OpenGL window.");
284 }
285
286 ANGLE_TRY(createRenderer(&mRenderer));
287 const FunctionsGL *functionsGL = mRenderer->getFunctions();
288
289 mHasRobustness = functionsGL->getGraphicsResetStatus != nullptr;
290 if (mHasWGLCreateContextRobustness != mHasRobustness)
291 {
292 WARN() << "WGL_ARB_create_context_robustness exists but unable to create a context with "
293 "robustness.";
294 }
295
296 // Intel OpenGL ES drivers are not currently supported due to bugs in the driver and ANGLE
297 VendorID vendor = GetVendorID(functionsGL);
298 if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE && IsIntel(vendor))
299 {
300 return egl::Error(EGL_NOT_INITIALIZED, "Intel OpenGL ES drivers are not supported.");
301 }
302
303 // Create DXGI swap chains for windows that come from other processes. Windows is unable to
304 // SetPixelFormat on windows from other processes when a sandbox is enabled.
305 HDC nativeDisplay = display->getNativeDisplayId();
306 HWND nativeWindow = WindowFromDC(nativeDisplay);
307 if (nativeWindow != nullptr)
308 {
309 DWORD currentProcessId = GetCurrentProcessId();
310 DWORD windowProcessId;
311 GetWindowThreadProcessId(nativeWindow, &windowProcessId);
312
313 // AMD drivers advertise the WGL_NV_DX_interop and WGL_NV_DX_interop2 extensions but fail
314 mUseDXGISwapChains = !IsAMD(vendor) && (currentProcessId != windowProcessId);
315 }
316 else
317 {
318 mUseDXGISwapChains = false;
319 }
320
321 mHasDXInterop = mFunctionsWGL->hasExtension("WGL_NV_DX_interop2");
322
323 if (mUseDXGISwapChains)
324 {
325 if (mHasDXInterop)
326 {
327 ANGLE_TRY(initializeD3DDevice());
328 }
329 else
330 {
331 // Want to use DXGI swap chains but WGL_NV_DX_interop2 is not present, fail
332 // initialization
333 return egl::Error(EGL_NOT_INITIALIZED,
334 "WGL_NV_DX_interop2 is required but not present.");
335 }
336 }
337
338 const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
339 if (maxVersion < gl::Version(2, 0))
340 {
341 return egl::Error(EGL_NOT_INITIALIZED, "OpenGL ES 2.0 is not supportable.");
342 }
343
344 return egl::NoError();
345 }
346
terminate()347 void DisplayWGL::terminate()
348 {
349 DisplayGL::terminate();
350 destroy();
351 }
352
destroy()353 void DisplayWGL::destroy()
354 {
355 releaseD3DDevice(mD3D11DeviceHandle);
356
357 mRenderer.reset();
358
359 if (mFunctionsWGL)
360 {
361 if (mDeviceContext)
362 {
363 mFunctionsWGL->makeCurrent(mDeviceContext, nullptr);
364 }
365 }
366 mCurrentNativeContexts.clear();
367
368 SafeDelete(mFunctionsWGL);
369
370 if (mDeviceContext)
371 {
372 ReleaseDC(mWindow, mDeviceContext);
373 mDeviceContext = nullptr;
374 }
375
376 if (mWindow)
377 {
378 DestroyWindow(mWindow);
379 mWindow = nullptr;
380 }
381
382 if (mWindowClass)
383 {
384 if (!UnregisterClassA(reinterpret_cast<const char *>(mWindowClass),
385 GetModuleHandle(nullptr)))
386 {
387 WARN() << "Failed to unregister OpenGL window class: " << gl::FmtHex(mWindowClass);
388 }
389 mWindowClass = NULL;
390 }
391
392 if (mOpenGLModule)
393 {
394 FreeLibrary(mOpenGLModule);
395 mOpenGLModule = nullptr;
396 }
397
398 SafeRelease(mD3D11Device);
399 SafeRelease(mD3D11Device1);
400
401 if (mDxgiModule)
402 {
403 FreeLibrary(mDxgiModule);
404 mDxgiModule = nullptr;
405 }
406
407 if (mD3d11Module)
408 {
409 FreeLibrary(mD3d11Module);
410 mD3d11Module = nullptr;
411 }
412
413 ASSERT(mRegisteredD3DDevices.empty());
414 }
415
createWindowSurface(const egl::SurfaceState & state,EGLNativeWindowType window,const egl::AttributeMap & attribs)416 SurfaceImpl *DisplayWGL::createWindowSurface(const egl::SurfaceState &state,
417 EGLNativeWindowType window,
418 const egl::AttributeMap &attribs)
419 {
420 EGLint orientation = static_cast<EGLint>(attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0));
421 // TODO(crbug.com/540829, anglebug.com/42266638) other orientations
422 // are still unsupported, so allow fallback instead of crashing
423 // later in eglCreateWindowSurface
424 if (mUseDXGISwapChains && orientation == EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE)
425 {
426 egl::Error error = initializeD3DDevice();
427 if (error.isError())
428 {
429 return nullptr;
430 }
431
432 return new DXGISwapChainWindowSurfaceWGL(
433 state, mRenderer->getStateManager(), window, mD3D11Device, mD3D11DeviceHandle,
434 mDeviceContext, mRenderer->getFunctions(), mFunctionsWGL, orientation);
435 }
436 else
437 {
438 return new WindowSurfaceWGL(state, window, mPixelFormat, mFunctionsWGL, orientation);
439 }
440 }
441
createPbufferSurface(const egl::SurfaceState & state,const egl::AttributeMap & attribs)442 SurfaceImpl *DisplayWGL::createPbufferSurface(const egl::SurfaceState &state,
443 const egl::AttributeMap &attribs)
444 {
445 EGLint width = static_cast<EGLint>(attribs.get(EGL_WIDTH, 0));
446 EGLint height = static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0));
447 bool largest = (attribs.get(EGL_LARGEST_PBUFFER, EGL_FALSE) == EGL_TRUE);
448 EGLenum textureFormat = static_cast<EGLenum>(attribs.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE));
449 EGLenum textureTarget = static_cast<EGLenum>(attribs.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE));
450
451 return new PbufferSurfaceWGL(state, width, height, textureFormat, textureTarget, largest,
452 mPixelFormat, mDeviceContext, mFunctionsWGL);
453 }
454
createPbufferFromClientBuffer(const egl::SurfaceState & state,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)455 SurfaceImpl *DisplayWGL::createPbufferFromClientBuffer(const egl::SurfaceState &state,
456 EGLenum buftype,
457 EGLClientBuffer clientBuffer,
458 const egl::AttributeMap &attribs)
459 {
460 egl::Error error = initializeD3DDevice();
461 if (error.isError())
462 {
463 return nullptr;
464 }
465
466 return new D3DTextureSurfaceWGL(state, mRenderer->getStateManager(), buftype, clientBuffer,
467 this, mDeviceContext, mD3D11Device, mD3D11Device1,
468 mRenderer->getFunctions(), mFunctionsWGL);
469 }
470
createPixmapSurface(const egl::SurfaceState & state,NativePixmapType nativePixmap,const egl::AttributeMap & attribs)471 SurfaceImpl *DisplayWGL::createPixmapSurface(const egl::SurfaceState &state,
472 NativePixmapType nativePixmap,
473 const egl::AttributeMap &attribs)
474 {
475 UNIMPLEMENTED();
476 return nullptr;
477 }
478
createContext(const gl::State & state,gl::ErrorSet * errorSet,const egl::Config * configuration,const gl::Context * shareContext,const egl::AttributeMap & attribs)479 rx::ContextImpl *DisplayWGL::createContext(const gl::State &state,
480 gl::ErrorSet *errorSet,
481 const egl::Config *configuration,
482 const gl::Context *shareContext,
483 const egl::AttributeMap &attribs)
484 {
485 return new ContextWGL(state, errorSet, mRenderer);
486 }
487
generateConfigs()488 egl::ConfigSet DisplayWGL::generateConfigs()
489 {
490 egl::ConfigSet configs;
491
492 int minSwapInterval = 1;
493 int maxSwapInterval = 1;
494 if (mFunctionsWGL->swapIntervalEXT)
495 {
496 // No defined maximum swap interval in WGL_EXT_swap_control, use a reasonable number
497 minSwapInterval = 0;
498 maxSwapInterval = 8;
499 }
500
501 const gl::Version &maxVersion = getMaxSupportedESVersion();
502 ASSERT(maxVersion >= gl::Version(2, 0));
503 bool supportsES3 = maxVersion >= gl::Version(3, 0);
504
505 PIXELFORMATDESCRIPTOR pixelFormatDescriptor;
506 DescribePixelFormat(mDeviceContext, mPixelFormat, sizeof(pixelFormatDescriptor),
507 &pixelFormatDescriptor);
508
509 auto getAttrib = [this](int attrib) {
510 return wgl::QueryWGLFormatAttrib(mDeviceContext, mPixelFormat, attrib, mFunctionsWGL);
511 };
512
513 const EGLint optimalSurfaceOrientation =
514 mUseDXGISwapChains ? EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE : 0;
515
516 egl::Config config;
517 config.renderTargetFormat = GL_RGBA8; // TODO: use the bit counts to determine the format
518 config.depthStencilFormat =
519 GL_DEPTH24_STENCIL8; // TODO: use the bit counts to determine the format
520 config.bufferSize = pixelFormatDescriptor.cColorBits;
521 config.redSize = pixelFormatDescriptor.cRedBits;
522 config.greenSize = pixelFormatDescriptor.cGreenBits;
523 config.blueSize = pixelFormatDescriptor.cBlueBits;
524 config.luminanceSize = 0;
525 config.alphaSize = pixelFormatDescriptor.cAlphaBits;
526 config.alphaMaskSize = 0;
527 config.bindToTextureRGB = (getAttrib(WGL_BIND_TO_TEXTURE_RGB_ARB) == TRUE);
528 config.bindToTextureRGBA = (getAttrib(WGL_BIND_TO_TEXTURE_RGBA_ARB) == TRUE);
529 config.colorBufferType = EGL_RGB_BUFFER;
530 config.configCaveat = EGL_NONE;
531 config.conformant = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0);
532 config.depthSize = pixelFormatDescriptor.cDepthBits;
533 config.level = 0;
534 config.matchNativePixmap = EGL_NONE;
535 config.maxPBufferWidth = getAttrib(WGL_MAX_PBUFFER_WIDTH_ARB);
536 config.maxPBufferHeight = getAttrib(WGL_MAX_PBUFFER_HEIGHT_ARB);
537 config.maxPBufferPixels = getAttrib(WGL_MAX_PBUFFER_PIXELS_ARB);
538 config.maxSwapInterval = maxSwapInterval;
539 config.minSwapInterval = minSwapInterval;
540 config.nativeRenderable = EGL_TRUE; // Direct rendering
541 config.nativeVisualID = 0;
542 config.nativeVisualType = EGL_NONE;
543 config.renderableType = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0);
544 config.sampleBuffers = 0; // FIXME: enumerate multi-sampling
545 config.samples = 0;
546 config.stencilSize = pixelFormatDescriptor.cStencilBits;
547 config.surfaceType =
548 ((pixelFormatDescriptor.dwFlags & PFD_DRAW_TO_WINDOW) ? EGL_WINDOW_BIT : 0) |
549 ((getAttrib(WGL_DRAW_TO_PBUFFER_ARB) == TRUE) ? EGL_PBUFFER_BIT : 0) |
550 ((getAttrib(WGL_SWAP_METHOD_ARB) == WGL_SWAP_COPY_ARB) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT
551 : 0);
552 config.optimalOrientation = optimalSurfaceOrientation;
553 config.colorComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
554
555 config.transparentType = EGL_NONE;
556 config.transparentRedValue = 0;
557 config.transparentGreenValue = 0;
558 config.transparentBlueValue = 0;
559
560 configs.add(config);
561
562 return configs;
563 }
564
testDeviceLost()565 bool DisplayWGL::testDeviceLost()
566 {
567 return false;
568 }
569
restoreLostDevice(const egl::Display * display)570 egl::Error DisplayWGL::restoreLostDevice(const egl::Display *display)
571 {
572 return egl::Error(EGL_BAD_DISPLAY);
573 }
574
isValidNativeWindow(EGLNativeWindowType window) const575 bool DisplayWGL::isValidNativeWindow(EGLNativeWindowType window) const
576 {
577 return (IsWindow(window) == TRUE);
578 }
579
validateClientBuffer(const egl::Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const580 egl::Error DisplayWGL::validateClientBuffer(const egl::Config *configuration,
581 EGLenum buftype,
582 EGLClientBuffer clientBuffer,
583 const egl::AttributeMap &attribs) const
584 {
585 switch (buftype)
586 {
587 case EGL_D3D_TEXTURE_ANGLE:
588 case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
589 ANGLE_TRY(const_cast<DisplayWGL *>(this)->initializeD3DDevice());
590 return D3DTextureSurfaceWGL::ValidateD3DTextureClientBuffer(
591 buftype, clientBuffer, mD3D11Device, mD3D11Device1);
592
593 default:
594 return DisplayGL::validateClientBuffer(configuration, buftype, clientBuffer, attribs);
595 }
596 }
597
initializeD3DDevice()598 egl::Error DisplayWGL::initializeD3DDevice()
599 {
600 if (mD3D11Device != nullptr)
601 {
602 return egl::NoError();
603 }
604
605 mDxgiModule = LoadLibrary(TEXT("dxgi.dll"));
606 if (!mDxgiModule)
607 {
608 return egl::Error(EGL_NOT_INITIALIZED, "Failed to load DXGI library.");
609 }
610
611 mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
612 if (!mD3d11Module)
613 {
614 return egl::Error(EGL_NOT_INITIALIZED, "Failed to load d3d11 library.");
615 }
616
617 PFN_D3D11_CREATE_DEVICE d3d11CreateDevice = nullptr;
618 d3d11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(
619 GetProcAddress(mD3d11Module, "D3D11CreateDevice"));
620 if (d3d11CreateDevice == nullptr)
621 {
622 return egl::Error(EGL_NOT_INITIALIZED, "Could not retrieve D3D11CreateDevice address.");
623 }
624
625 HRESULT result = d3d11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0,
626 D3D11_SDK_VERSION, &mD3D11Device, nullptr, nullptr);
627 if (FAILED(result))
628 {
629 std::ostringstream err;
630 err << "Could not create D3D11 device, " << gl::FmtHR(result);
631 return egl::Error(EGL_NOT_INITIALIZED, err.str());
632 }
633
634 mD3D11Device->QueryInterface(__uuidof(ID3D11Device1),
635 reinterpret_cast<void **>(&mD3D11Device1));
636
637 return registerD3DDevice(mD3D11Device, &mD3D11DeviceHandle);
638 }
639
generateExtensions(egl::DisplayExtensions * outExtensions) const640 void DisplayWGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
641 {
642 // Only enable the surface orientation and post sub buffer for DXGI swap chain surfaces, they
643 // prefer to swap with inverted Y.
644 outExtensions->postSubBuffer = mUseDXGISwapChains;
645 outExtensions->surfaceOrientation = mUseDXGISwapChains;
646
647 outExtensions->createContextRobustness = mHasRobustness;
648
649 outExtensions->d3dTextureClientBuffer = mHasDXInterop;
650 outExtensions->d3dShareHandleClientBuffer = mHasDXInterop;
651 outExtensions->surfaceD3DTexture2DShareHandle = true;
652 outExtensions->querySurfacePointer = true;
653 outExtensions->keyedMutex = true;
654
655 // Contexts are virtualized so textures and semaphores can be shared globally
656 outExtensions->displayTextureShareGroup = true;
657 outExtensions->displaySemaphoreShareGroup = true;
658
659 outExtensions->surfacelessContext = true;
660
661 DisplayGL::generateExtensions(outExtensions);
662 }
663
generateCaps(egl::Caps * outCaps) const664 void DisplayWGL::generateCaps(egl::Caps *outCaps) const
665 {
666 outCaps->textureNPOT = true;
667 }
668
makeCurrentSurfaceless(gl::Context * context)669 egl::Error DisplayWGL::makeCurrentSurfaceless(gl::Context *context)
670 {
671 // Nothing to do because WGL always uses the same context and the previous surface can be left
672 // current.
673 return egl::NoError();
674 }
675
waitClient(const gl::Context * context)676 egl::Error DisplayWGL::waitClient(const gl::Context *context)
677 {
678 // Unimplemented as this is not needed for WGL
679 return egl::NoError();
680 }
681
waitNative(const gl::Context * context,EGLint engine)682 egl::Error DisplayWGL::waitNative(const gl::Context *context, EGLint engine)
683 {
684 // Unimplemented as this is not needed for WGL
685 return egl::NoError();
686 }
687
makeCurrent(egl::Display * display,egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)688 egl::Error DisplayWGL::makeCurrent(egl::Display *display,
689 egl::Surface *drawSurface,
690 egl::Surface *readSurface,
691 gl::Context *context)
692 {
693 CurrentNativeContext ¤tContext =
694 mCurrentNativeContexts[angle::GetCurrentThreadUniqueId()];
695
696 HDC newDC = mDeviceContext;
697 if (drawSurface)
698 {
699 SurfaceWGL *drawSurfaceWGL = GetImplAs<SurfaceWGL>(drawSurface);
700 newDC = drawSurfaceWGL->getDC();
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::Error(EGL_CONTEXT_LOST, "Failed to make the WGL context current.");
722 }
723 currentContext.dc = newDC;
724 currentContext.glrc = newContext;
725 }
726
727 return DisplayGL::makeCurrent(display, 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::Error(EGL_BAD_PARAMETER, "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) const788 HGLRC DisplayWGL::initializeContextAttribs(const egl::AttributeMap &eglAttributes) const
789 {
790 EGLint requestedDisplayType = static_cast<EGLint>(
791 eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE));
792
793 // Create a context of the requested version, if any.
794 gl::Version requestedVersion(static_cast<EGLint>(eglAttributes.get(
795 EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE)),
796 static_cast<EGLint>(eglAttributes.get(
797 EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE)));
798 if (static_cast<EGLint>(requestedVersion.major) != EGL_DONT_CARE &&
799 static_cast<EGLint>(requestedVersion.minor) != EGL_DONT_CARE)
800 {
801 int profileMask = 0;
802 if (requestedDisplayType != EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE &&
803 requestedVersion >= gl::Version(3, 2))
804 {
805 profileMask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
806 }
807 return createContextAttribs(requestedVersion, profileMask);
808 }
809
810 // Try all the GL version in order as a workaround for Mesa context creation where the driver
811 // doesn't automatically return the highest version available.
812 for (const auto &info : GenerateContextCreationToTry(requestedDisplayType, false))
813 {
814 int profileFlag = 0;
815 if (info.type == ContextCreationTry::Type::DESKTOP_CORE)
816 {
817 profileFlag |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
818 }
819 else if (info.type == ContextCreationTry::Type::ES)
820 {
821 profileFlag |= WGL_CONTEXT_ES_PROFILE_BIT_EXT;
822 }
823
824 HGLRC context = createContextAttribs(info.version, profileFlag);
825 if (context != nullptr)
826 {
827 return context;
828 }
829 }
830
831 return nullptr;
832 }
833
createContextAttribs(const gl::Version & version,int profileMask) const834 HGLRC DisplayWGL::createContextAttribs(const gl::Version &version, int profileMask) const
835 {
836 std::vector<int> attribs;
837
838 if (mHasWGLCreateContextRobustness)
839 {
840 attribs.push_back(WGL_CONTEXT_FLAGS_ARB);
841 attribs.push_back(WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB);
842 attribs.push_back(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
843 attribs.push_back(WGL_LOSE_CONTEXT_ON_RESET_ARB);
844 }
845
846 attribs.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB);
847 attribs.push_back(version.major);
848
849 attribs.push_back(WGL_CONTEXT_MINOR_VERSION_ARB);
850 attribs.push_back(version.minor);
851
852 if (profileMask != 0)
853 {
854 attribs.push_back(WGL_CONTEXT_PROFILE_MASK_ARB);
855 attribs.push_back(profileMask);
856 }
857
858 attribs.push_back(0);
859 attribs.push_back(0);
860 return mFunctionsWGL->createContextAttribsARB(mDeviceContext, nullptr, &attribs[0]);
861 }
862
createRenderer(std::shared_ptr<RendererWGL> * outRenderer)863 egl::Error DisplayWGL::createRenderer(std::shared_ptr<RendererWGL> *outRenderer)
864 {
865 HGLRC context = nullptr;
866
867 if (mFunctionsWGL->createContextAttribsARB)
868 {
869 context = initializeContextAttribs(mDisplayAttributes);
870 }
871
872 // If wglCreateContextAttribsARB is unavailable or failed, try the standard wglCreateContext
873 if (!context)
874 {
875 // Don't have control over GL versions
876 context = mFunctionsWGL->createContext(mDeviceContext);
877 }
878
879 if (!context)
880 {
881 std::ostringstream err;
882 err << "Failed to create a WGL context for the intermediate OpenGL window."
883 << GetErrorMessage();
884 return egl::Error(EGL_NOT_INITIALIZED, err.str());
885 }
886
887 if (!mFunctionsWGL->makeCurrent(mDeviceContext, context))
888 {
889 return egl::Error(EGL_NOT_INITIALIZED,
890 "Failed to make the intermediate WGL context current.");
891 }
892 CurrentNativeContext ¤tContext =
893 mCurrentNativeContexts[angle::GetCurrentThreadUniqueId()];
894 currentContext.dc = mDeviceContext;
895 currentContext.glrc = context;
896
897 std::unique_ptr<FunctionsGL> functionsGL(
898 new FunctionsGLWindows(mOpenGLModule, mFunctionsWGL->getProcAddress));
899 functionsGL->initialize(mDisplayAttributes);
900
901 outRenderer->reset(new RendererWGL(std::move(functionsGL), mDisplayAttributes, this, context));
902
903 return egl::NoError();
904 }
905
initializeFrontendFeatures(angle::FrontendFeatures * features) const906 void DisplayWGL::initializeFrontendFeatures(angle::FrontendFeatures *features) const
907 {
908 mRenderer->initializeFrontendFeatures(features);
909 }
910
populateFeatureList(angle::FeatureList * features)911 void DisplayWGL::populateFeatureList(angle::FeatureList *features)
912 {
913 mRenderer->getFeatures().populateFeatureList(features);
914 }
915
getRenderer() const916 RendererGL *DisplayWGL::getRenderer() const
917 {
918 return reinterpret_cast<RendererGL *>(mRenderer.get());
919 }
920
921 } // namespace rx
922