Vulkan SDK for Android 1.1.1 Mali Developer Center
wayland.cpp
1 /* Copyright (c) 2016-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #define VK_USE_PLATFORM_WAYLAND_KHR
22 #include "wayland.hpp"
23 #include <fcntl.h>
24 #include <string.h>
25 #include <sys/poll.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 
30 using namespace std;
31 
32 namespace MaliSDK
33 {
34 Platform &Platform::get()
35 {
36  // Not initialized until first call to Platform::get().
37  // Initialization is thread-safe.
38  static WaylandPlatform singleton;
39  return singleton;
40 }
41 
42 VkSurfaceKHR WaylandPlatform::createSurface()
43 {
44  if (FAILED(initWindow()))
45  return VK_NULL_HANDLE;
46 
47  VkSurfaceKHR surface;
48  PFN_vkCreateWaylandSurfaceKHR fpCreateWaylandSurfaceKHR;
49  if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateWaylandSurfaceKHR", fpCreateWaylandSurfaceKHR))
50  return VK_NULL_HANDLE;
51 
52  VkWaylandSurfaceCreateInfoKHR info = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR };
53  info.display = waylandData.dpy;
54  info.surface = waylandData.surf;
55 
56  VK_CHECK(fpCreateWaylandSurfaceKHR(instance, &info, nullptr, &surface));
57  return surface;
58 }
59 
60 WaylandPlatform::WaylandPlatform()
61 {
62  memset(&waylandData, 0, sizeof(waylandData));
63  waylandData.fd = -1;
64 }
65 
66 // Wayland callbacks
67 static void registryHandleGlobal(void *data, wl_registry *reg, uint32_t id, const char *interface, uint32_t)
68 {
69  WaylandData *waylandData = static_cast<WaylandData *>(data);
70  if (!strcmp(interface, "wl_compositor"))
71  waylandData->compositor = static_cast<wl_compositor *>(wl_registry_bind(reg, id, &wl_compositor_interface, 1));
72  else if (!strcmp(interface, "wl_shell"))
73  waylandData->shell = static_cast<wl_shell *>(wl_registry_bind(reg, id, &wl_shell_interface, 1));
74 }
75 
76 static void registryHandleGlobalRemove(void *, wl_registry *, uint32_t)
77 {
78 }
79 
80 static const wl_registry_listener registryListener = {
81  registryHandleGlobal, registryHandleGlobalRemove,
82 };
83 
84 static void shellSurfaceHandlePing(void *, wl_shell_surface *shellSurface, uint32_t serial)
85 {
86  wl_shell_surface_pong(shellSurface, serial);
87 }
88 
89 static void shellSurfaceHandlePopupDone(void *, wl_shell_surface *)
90 {
91 }
92 
93 static void shellSurfaceHandleConfigure(void *, wl_shell_surface *, uint32_t, int32_t width, int32_t height)
94 {
95  LOGI("Wayland: Surface size: %d x %d.\n", width, height);
96 }
97 
98 static const wl_shell_surface_listener shellSurfaceListener = {
99  shellSurfaceHandlePing, shellSurfaceHandleConfigure, shellSurfaceHandlePopupDone,
100 };
101 
102 Platform::Status WaylandPlatform::getWindowStatus()
103 {
104  return waylandData.status;
105 }
106 
107 void WaylandPlatform::flushWaylandFd()
108 {
109  pollfd fd = { 0 };
110  wl_display_dispatch_pending(waylandData.dpy);
111  wl_display_flush(waylandData.dpy);
112 
113  fd.fd = waylandData.fd;
114  fd.events = POLLIN | POLLOUT | POLLERR | POLLHUP;
115 
116  if (poll(&fd, 1, 0) > 0)
117  {
118  if (fd.revents & (POLLERR | POLLHUP))
119  {
120  close(waylandData.fd);
121  waylandData.fd = -1;
122  waylandData.status = STATUS_TEARDOWN;
123  }
124 
125  if (fd.revents & POLLIN)
126  wl_display_dispatch(waylandData.dpy);
127  if (fd.revents & POLLOUT)
128  wl_display_flush(waylandData.dpy);
129  }
130 }
131 
132 Result WaylandPlatform::initialize()
133 {
134  waylandData.dpy = wl_display_connect(nullptr);
135  if (!waylandData.dpy)
136  return RESULT_ERROR_IO;
137 
138  waylandData.registry = wl_display_get_registry(waylandData.dpy);
139  wl_registry_add_listener(waylandData.registry, &registryListener, &waylandData);
140  wl_display_roundtrip(waylandData.dpy);
141 
142  if (!waylandData.compositor || !waylandData.shell)
143  return RESULT_ERROR_GENERIC;
144 
145  waylandData.fd = wl_display_get_fd(waylandData.dpy);
146  if (waylandData.fd < 0)
147  return RESULT_ERROR_IO;
148 
149  waylandData.status = STATUS_RUNNING;
150 
151  return WSIPlatform::initialize();
152 }
153 
154 Platform::SwapchainDimensions WaylandPlatform::getPreferredSwapchain()
155 {
156  SwapchainDimensions chain = { 1280, 720, VK_FORMAT_B8G8R8A8_UNORM };
157  return chain;
158 }
159 
160 Result WaylandPlatform::initWindow()
161 {
162  waylandData.surf = wl_compositor_create_surface(waylandData.compositor);
163  waylandData.shellSurf = wl_shell_get_shell_surface(waylandData.shell, waylandData.surf);
164 
165  if (!waylandData.surf || !waylandData.shellSurf)
166  return RESULT_ERROR_GENERIC;
167 
168  wl_shell_surface_add_listener(waylandData.shellSurf, &shellSurfaceListener, &waylandData);
169  wl_shell_surface_set_toplevel(waylandData.shellSurf);
170  wl_shell_surface_set_class(waylandData.shellSurf, "Mali SDK");
171  wl_shell_surface_set_title(waylandData.shellSurf, "Mali SDK");
172 
173  flushWaylandFd();
174  return RESULT_SUCCESS;
175 }
176 
177 Result WaylandPlatform::createWindow(const SwapchainDimensions &swapchain)
178 {
179  if (!waylandData.dpy)
180  return RESULT_ERROR_GENERIC;
181 
182  return initVulkan(swapchain, { "VK_KHR_surface", "VK_KHR_wayland_surface" }, { "VK_KHR_swapchain" });
183 }
184 
185 void WaylandPlatform::terminate()
186 {
187  // Tear down WSI resources before we destroy Wayland.
188  WSIPlatform::terminate();
189 
190  if (waylandData.dpy)
191  {
192  if (waylandData.fd >= 0)
193  close(waylandData.fd);
194 
195  if (waylandData.shellSurf)
196  wl_shell_surface_destroy(waylandData.shellSurf);
197  if (waylandData.surf)
198  wl_surface_destroy(waylandData.surf);
199  if (waylandData.compositor)
200  wl_compositor_destroy(waylandData.compositor);
201  if (waylandData.registry)
202  wl_registry_destroy(waylandData.registry);
203  if (waylandData.dpy)
204  wl_display_disconnect(waylandData.dpy);
205 
206  waylandData.dpy = nullptr;
207  }
208 }
209 
210 WaylandPlatform::~WaylandPlatform()
211 {
212  terminate();
213 }
214 
215 Result WaylandPlatform::presentImage(unsigned index)
216 {
217  Result res = WSIPlatform::presentImage(index);
218  flushWaylandFd();
219  return res;
220 }
221 }
Describes the size and format of the swapchain.
Definition: platform.hpp:54
Status
Describes the status of the application lifecycle.
Definition: platform.hpp:65