1 //
2 // Copyright 2016 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 // DisplayVkWin32.cpp:
7 // Implements the class methods for DisplayVkWin32.
8 //
9
10 #include "libANGLE/renderer/vulkan/win32/DisplayVkWin32.h"
11 #include "libANGLE/renderer/vulkan/DisplayVk.h"
12 #include "libANGLE/renderer/vulkan/RendererVk.h"
13
14 #include <windows.h>
15
16 #include "common/vulkan/vk_headers.h"
17 #include "libANGLE/renderer/vulkan/vk_caps_utils.h"
18 #include "libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h"
19
20 namespace rx
21 {
22
DisplayVkWin32(const egl::DisplayState & state)23 DisplayVkWin32::DisplayVkWin32(const egl::DisplayState &state)
24 : DisplayVk(state), mWindowClass(NULL), mMockWindow(nullptr)
25 {}
26
~DisplayVkWin32()27 DisplayVkWin32::~DisplayVkWin32() {}
28
terminate()29 void DisplayVkWin32::terminate()
30 {
31 if (mMockWindow)
32 {
33 DestroyWindow(mMockWindow);
34 mMockWindow = nullptr;
35 }
36 if (mWindowClass)
37 {
38 if (!UnregisterClassA(reinterpret_cast<const char *>(mWindowClass),
39 GetModuleHandle(nullptr)))
40 {
41 WARN() << "Failed to unregister ANGLE window class: " << gl::FmtHex(mWindowClass);
42 }
43 mWindowClass = NULL;
44 }
45
46 DisplayVk::terminate();
47 }
48
isValidNativeWindow(EGLNativeWindowType window) const49 bool DisplayVkWin32::isValidNativeWindow(EGLNativeWindowType window) const
50 {
51 return (IsWindow(window) == TRUE);
52 }
53
createWindowSurfaceVk(const egl::SurfaceState & state,EGLNativeWindowType window)54 SurfaceImpl *DisplayVkWin32::createWindowSurfaceVk(const egl::SurfaceState &state,
55 EGLNativeWindowType window)
56 {
57 return new WindowSurfaceVkWin32(state, window);
58 }
59
initialize(egl::Display * display)60 egl::Error DisplayVkWin32::initialize(egl::Display *display)
61 {
62 ANGLE_TRY(DisplayVk::initialize(display));
63
64 HINSTANCE hinstance = GetModuleHandle(nullptr);
65
66 std::wostringstream stream;
67 stream << L"ANGLE DisplayVkWin32 " << gl::FmtHex<egl::Display *, wchar_t>(display)
68 << L" Intermediate Window Class";
69
70 const LPWSTR idcArrow = MAKEINTRESOURCEW(32512);
71 std::wstring className = stream.str();
72 WNDCLASSW wndClass;
73 if (!GetClassInfoW(hinstance, className.c_str(), &wndClass))
74 {
75 WNDCLASSW intermediateClassDesc = {};
76 intermediateClassDesc.style = CS_OWNDC;
77 intermediateClassDesc.lpfnWndProc = DefWindowProcW;
78 intermediateClassDesc.cbClsExtra = 0;
79 intermediateClassDesc.cbWndExtra = 0;
80 intermediateClassDesc.hInstance = GetModuleHandle(nullptr);
81 intermediateClassDesc.hIcon = nullptr;
82 intermediateClassDesc.hCursor = LoadCursorW(nullptr, idcArrow);
83 intermediateClassDesc.hbrBackground = nullptr;
84 intermediateClassDesc.lpszMenuName = nullptr;
85 intermediateClassDesc.lpszClassName = className.c_str();
86 mWindowClass = RegisterClassW(&intermediateClassDesc);
87 if (!mWindowClass)
88 {
89 return egl::EglNotInitialized()
90 << "Failed to register intermediate OpenGL window class \""
91 << gl::FmtHex<egl::Display *, char>(display)
92 << "\":" << gl::FmtErr(HRESULT_CODE(GetLastError()));
93 }
94 }
95
96 mMockWindow = CreateWindowExW(0, reinterpret_cast<LPCWSTR>(mWindowClass), L"ANGLE Mock Window",
97 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
98 CW_USEDEFAULT, nullptr, nullptr, nullptr, nullptr);
99 if (!mMockWindow)
100 {
101 return egl::EglNotInitialized() << "Failed to create mock OpenGL window.";
102 }
103
104 VkSurfaceKHR surfaceVk;
105 VkWin32SurfaceCreateInfoKHR info = {VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, nullptr, 0,
106 GetModuleHandle(nullptr), mMockWindow};
107
108 VkInstance instance = mRenderer->getInstance();
109 VkPhysicalDevice physDevice = mRenderer->getPhysicalDevice();
110
111 if (vkCreateWin32SurfaceKHR(instance, &info, nullptr, &surfaceVk) != VK_SUCCESS)
112 {
113 return egl::EglNotInitialized() << "vkCreateWin32SurfaceKHR failed";
114 }
115 uint32_t surfaceFormatCount;
116
117 if (vkGetPhysicalDeviceSurfaceFormatsKHR(physDevice, surfaceVk, &surfaceFormatCount, nullptr) !=
118 VK_SUCCESS)
119 {
120 return egl::EglNotInitialized() << "vkGetPhysicalDeviceSurfaceFormatsKHR failed";
121 }
122 mSurfaceFormats.resize(surfaceFormatCount);
123 if (vkGetPhysicalDeviceSurfaceFormatsKHR(physDevice, surfaceVk, &surfaceFormatCount,
124 mSurfaceFormats.data()) != VK_SUCCESS)
125 {
126 return egl::EglNotInitialized() << "vkGetPhysicalDeviceSurfaceFormatsKHR (2nd) failed";
127 }
128 vkDestroySurfaceKHR(instance, surfaceVk, nullptr);
129
130 DestroyWindow(mMockWindow);
131 mMockWindow = nullptr;
132
133 return egl::NoError();
134 }
135
generateConfigs()136 egl::ConfigSet DisplayVkWin32::generateConfigs()
137 {
138 const std::array<GLenum, 5> kColorFormats = {GL_RGB565, GL_BGRA8_EXT, GL_BGRX8_ANGLEX,
139 GL_RGB10_A2_EXT, GL_RGBA16F_EXT};
140
141 std::vector<GLenum> depthStencilFormats(
142 egl_vk::kConfigDepthStencilFormats,
143 egl_vk::kConfigDepthStencilFormats + ArraySize(egl_vk::kConfigDepthStencilFormats));
144
145 if (getCaps().stencil8)
146 {
147 depthStencilFormats.push_back(GL_STENCIL_INDEX8);
148 }
149 return egl_vk::GenerateConfigs(kColorFormats.data(), kColorFormats.size(),
150 depthStencilFormats.data(), depthStencilFormats.size(), this);
151 }
152
checkConfigSupport(egl::Config * config)153 void DisplayVkWin32::checkConfigSupport(egl::Config *config)
154 {
155 const vk::Format &formatVk = this->getRenderer()->getFormat(config->renderTargetFormat);
156
157 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
158 // the surface has no preferred format. Otherwise, at least one
159 // supported format will be returned.
160 if (mSurfaceFormats.size() == 1u && mSurfaceFormats[0].format == VK_FORMAT_UNDEFINED)
161 {
162 return;
163 }
164
165 for (const VkSurfaceFormatKHR &surfaceFormat : mSurfaceFormats)
166 {
167 if (surfaceFormat.format == formatVk.getActualRenderableImageVkFormat())
168 {
169 return;
170 }
171 }
172
173 // No window support for this config.
174 config->surfaceType &= ~EGL_WINDOW_BIT;
175 }
176
getWSIExtension() const177 const char *DisplayVkWin32::getWSIExtension() const
178 {
179 return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
180 }
181
IsVulkanWin32DisplayAvailable()182 bool IsVulkanWin32DisplayAvailable()
183 {
184 return true;
185 }
186
CreateVulkanWin32Display(const egl::DisplayState & state)187 DisplayImpl *CreateVulkanWin32Display(const egl::DisplayState &state)
188 {
189 return new DisplayVkWin32(state);
190 }
191 } // namespace rx
192