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 #include "volk.h"
16
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), mDummyWindow(nullptr)
25 {}
26
~DisplayVkWin32()27 DisplayVkWin32::~DisplayVkWin32() {}
28
terminate()29 void DisplayVkWin32::terminate()
30 {
31 if (mDummyWindow)
32 {
33 DestroyWindow(mDummyWindow);
34 mDummyWindow = 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::ostringstream stream;
67 stream << "ANGLE DisplayVkWin32 " << gl::FmtHex(display) << " Intermediate Window Class";
68
69 const LPSTR idcArrow = MAKEINTRESOURCEA(32512);
70 std::string className = stream.str();
71 WNDCLASSA wndClass;
72 if (!GetClassInfoA(hinstance, className.c_str(), &wndClass))
73 {
74 WNDCLASSA intermediateClassDesc = {};
75 intermediateClassDesc.style = CS_OWNDC;
76 intermediateClassDesc.lpfnWndProc = DefWindowProcA;
77 intermediateClassDesc.cbClsExtra = 0;
78 intermediateClassDesc.cbWndExtra = 0;
79 intermediateClassDesc.hInstance = GetModuleHandle(nullptr);
80 intermediateClassDesc.hIcon = nullptr;
81 intermediateClassDesc.hCursor = LoadCursorA(nullptr, idcArrow);
82 intermediateClassDesc.hbrBackground = 0;
83 intermediateClassDesc.lpszMenuName = nullptr;
84 intermediateClassDesc.lpszClassName = className.c_str();
85 mWindowClass = RegisterClassA(&intermediateClassDesc);
86 if (!mWindowClass)
87 {
88 return egl::EglNotInitialized()
89 << "Failed to register intermediate OpenGL window class \"" << className.c_str()
90 << "\":" << gl::FmtErr(HRESULT_CODE(GetLastError()));
91 }
92 }
93
94 mDummyWindow =
95 CreateWindowExA(0, reinterpret_cast<const char *>(mWindowClass), "ANGLE Dummy Window",
96 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
97 CW_USEDEFAULT, nullptr, nullptr, nullptr, nullptr);
98 if (!mDummyWindow)
99 {
100 return egl::EglNotInitialized() << "Failed to create dummy OpenGL window.";
101 }
102
103 VkSurfaceKHR surfaceVk;
104 VkWin32SurfaceCreateInfoKHR info = {VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, nullptr, 0,
105 GetModuleHandle(nullptr), mDummyWindow};
106
107 VkInstance instance = mRenderer->getInstance();
108 VkPhysicalDevice physDevice = mRenderer->getPhysicalDevice();
109
110 if (vkCreateWin32SurfaceKHR(instance, &info, nullptr, &surfaceVk) != VK_SUCCESS)
111 {
112 return egl::EglNotInitialized() << "vkCreateWin32SurfaceKHR failed";
113 }
114 uint32_t surfaceFormatCount;
115
116 if (vkGetPhysicalDeviceSurfaceFormatsKHR(physDevice, surfaceVk, &surfaceFormatCount, nullptr) !=
117 VK_SUCCESS)
118 {
119 return egl::EglNotInitialized() << "vkGetPhysicalDeviceSurfaceFormatsKHR failed";
120 }
121 mSurfaceFormats.resize(surfaceFormatCount);
122 if (vkGetPhysicalDeviceSurfaceFormatsKHR(physDevice, surfaceVk, &surfaceFormatCount,
123 mSurfaceFormats.data()) != VK_SUCCESS)
124 {
125 return egl::EglNotInitialized() << "vkGetPhysicalDeviceSurfaceFormatsKHR (2nd) failed";
126 }
127 vkDestroySurfaceKHR(instance, surfaceVk, nullptr);
128
129 DestroyWindow(mDummyWindow);
130 mDummyWindow = nullptr;
131
132 return egl::NoError();
133 }
134
generateConfigs()135 egl::ConfigSet DisplayVkWin32::generateConfigs()
136 {
137 constexpr GLenum kColorFormats[] = {GL_RGB565, GL_BGRA8_EXT, GL_BGRX8_ANGLEX, GL_RGB10_A2_EXT,
138 GL_RGBA16F_EXT};
139 return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, this);
140 }
141
checkConfigSupport(egl::Config * config)142 bool DisplayVkWin32::checkConfigSupport(egl::Config *config)
143 {
144 const vk::Format &formatVk = this->getRenderer()->getFormat(config->renderTargetFormat);
145 VkFormat nativeFormat = formatVk.vkImageFormat;
146
147 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
148 // the surface has no preferred format. Otherwise, at least one
149 // supported format will be returned.
150 if (mSurfaceFormats.size() == 1u && mSurfaceFormats[0].format == VK_FORMAT_UNDEFINED)
151 {
152 return true;
153 }
154
155 for (const VkSurfaceFormatKHR &surfaceFormat : mSurfaceFormats)
156 {
157 if (surfaceFormat.format == nativeFormat)
158 {
159 return true;
160 }
161 }
162
163 return false;
164 }
165
getWSIExtension() const166 const char *DisplayVkWin32::getWSIExtension() const
167 {
168 return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
169 }
170
IsVulkanWin32DisplayAvailable()171 bool IsVulkanWin32DisplayAvailable()
172 {
173 return true;
174 }
175
CreateVulkanWin32Display(const egl::DisplayState & state)176 DisplayImpl *CreateVulkanWin32Display(const egl::DisplayState &state)
177 {
178 return new DisplayVkWin32(state);
179 }
180 } // namespace rx
181