• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/vk_renderer.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             std::ostringstream err;
90             err << "Failed to register intermediate OpenGL window class \""
91                 << gl::FmtHex<egl::Display *, char>(display)
92                 << "\":" << gl::FmtErr(HRESULT_CODE(GetLastError()));
93             return egl::Error(EGL_NOT_INITIALIZED, err.str());
94         }
95     }
96 
97     mMockWindow = CreateWindowExW(0, reinterpret_cast<LPCWSTR>(mWindowClass), L"ANGLE Mock Window",
98                                   WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
99                                   CW_USEDEFAULT, nullptr, nullptr, nullptr, nullptr);
100     if (!mMockWindow)
101     {
102         return egl::Error(EGL_NOT_INITIALIZED, "Failed to create mock OpenGL window.");
103     }
104 
105     VkSurfaceKHR surfaceVk;
106     VkWin32SurfaceCreateInfoKHR info = {VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, nullptr, 0,
107                                         GetModuleHandle(nullptr), mMockWindow};
108 
109     VkInstance instance         = mRenderer->getInstance();
110     VkPhysicalDevice physDevice = mRenderer->getPhysicalDevice();
111 
112     if (vkCreateWin32SurfaceKHR(instance, &info, nullptr, &surfaceVk) != VK_SUCCESS)
113     {
114         return egl::Error(EGL_NOT_INITIALIZED, "vkCreateWin32SurfaceKHR failed");
115     }
116     uint32_t surfaceFormatCount;
117 
118     if (vkGetPhysicalDeviceSurfaceFormatsKHR(physDevice, surfaceVk, &surfaceFormatCount, nullptr) !=
119         VK_SUCCESS)
120     {
121         return egl::Error(EGL_NOT_INITIALIZED, "vkGetPhysicalDeviceSurfaceFormatsKHR failed");
122     }
123     mSurfaceFormats.resize(surfaceFormatCount);
124     if (vkGetPhysicalDeviceSurfaceFormatsKHR(physDevice, surfaceVk, &surfaceFormatCount,
125                                              mSurfaceFormats.data()) != VK_SUCCESS)
126     {
127         return egl::Error(EGL_NOT_INITIALIZED, "vkGetPhysicalDeviceSurfaceFormatsKHR (2nd) failed");
128     }
129     vkDestroySurfaceKHR(instance, surfaceVk, nullptr);
130 
131     DestroyWindow(mMockWindow);
132     mMockWindow = nullptr;
133 
134     return egl::NoError();
135 }
136 
generateConfigs()137 egl::ConfigSet DisplayVkWin32::generateConfigs()
138 {
139     const std::array<GLenum, 5> kColorFormats = {GL_RGB565, GL_BGRA8_EXT, GL_BGRX8_ANGLEX,
140                                                  GL_RGB10_A2_EXT, GL_RGBA16F_EXT};
141 
142     std::vector<GLenum> depthStencilFormats(
143         egl_vk::kConfigDepthStencilFormats,
144         egl_vk::kConfigDepthStencilFormats + ArraySize(egl_vk::kConfigDepthStencilFormats));
145 
146     if (getCaps().stencil8)
147     {
148         depthStencilFormats.push_back(GL_STENCIL_INDEX8);
149     }
150     return egl_vk::GenerateConfigs(kColorFormats.data(), kColorFormats.size(),
151                                    depthStencilFormats.data(), depthStencilFormats.size(), this);
152 }
153 
checkConfigSupport(egl::Config * config)154 void DisplayVkWin32::checkConfigSupport(egl::Config *config)
155 {
156     const vk::Format &formatVk = this->getRenderer()->getFormat(config->renderTargetFormat);
157 
158     // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
159     // the surface has no preferred format.  Otherwise, at least one
160     // supported format will be returned.
161     if (mSurfaceFormats.size() == 1u && mSurfaceFormats[0].format == VK_FORMAT_UNDEFINED)
162     {
163         return;
164     }
165 
166     for (const VkSurfaceFormatKHR &surfaceFormat : mSurfaceFormats)
167     {
168         if (surfaceFormat.format == formatVk.getActualRenderableImageVkFormat(this->getRenderer()))
169         {
170             return;
171         }
172     }
173 
174     // No window support for this config.
175     config->surfaceType &= ~EGL_WINDOW_BIT;
176 }
177 
getWSIExtension() const178 const char *DisplayVkWin32::getWSIExtension() const
179 {
180     return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
181 }
182 
IsVulkanWin32DisplayAvailable()183 bool IsVulkanWin32DisplayAvailable()
184 {
185     return true;
186 }
187 
CreateVulkanWin32Display(const egl::DisplayState & state)188 DisplayImpl *CreateVulkanWin32Display(const egl::DisplayState &state)
189 {
190     return new DisplayVkWin32(state);
191 }
192 }  // namespace rx
193