1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 /*
23  * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
24  * SDL_x11vulkan.c.
25  */
26 
27 #include "../../SDL_internal.h"
28 
29 #if SDL_VIDEO_VULKAN && SDL_VIDEO_DRIVER_WAYLAND
30 
31 #include "SDL_waylandvideo.h"
32 #include "SDL_waylandwindow.h"
33 #include "SDL_assert.h"
34 
35 #include "SDL_loadso.h"
36 #include "SDL_waylandvulkan.h"
37 #include "SDL_syswm.h"
38 
Wayland_Vulkan_LoadLibrary(_THIS,const char * path)39 int Wayland_Vulkan_LoadLibrary(_THIS, const char *path)
40 {
41     VkExtensionProperties *extensions = NULL;
42     Uint32 i, extensionCount = 0;
43     SDL_bool hasSurfaceExtension = SDL_FALSE;
44     SDL_bool hasWaylandSurfaceExtension = SDL_FALSE;
45     PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
46     if(_this->vulkan_config.loader_handle)
47         return SDL_SetError("Vulkan already loaded");
48 
49     /* Load the Vulkan loader library */
50     if(!path)
51         path = SDL_getenv("SDL_VULKAN_LIBRARY");
52     if(!path)
53         path = "libvulkan.so.1";
54     _this->vulkan_config.loader_handle = SDL_LoadObject(path);
55     if(!_this->vulkan_config.loader_handle)
56         return -1;
57     SDL_strlcpy(_this->vulkan_config.loader_path, path,
58                 SDL_arraysize(_this->vulkan_config.loader_path));
59     vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
60         _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
61     if(!vkGetInstanceProcAddr)
62         goto fail;
63     _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr;
64     _this->vulkan_config.vkEnumerateInstanceExtensionProperties =
65         (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)(
66             VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
67     if(!_this->vulkan_config.vkEnumerateInstanceExtensionProperties)
68         goto fail;
69     extensions = SDL_Vulkan_CreateInstanceExtensionsList(
70         (PFN_vkEnumerateInstanceExtensionProperties)
71             _this->vulkan_config.vkEnumerateInstanceExtensionProperties,
72         &extensionCount);
73     if(!extensions)
74         goto fail;
75     for(i = 0; i < extensionCount; i++)
76     {
77         if(SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0)
78             hasSurfaceExtension = SDL_TRUE;
79         else if(SDL_strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0)
80             hasWaylandSurfaceExtension = SDL_TRUE;
81     }
82     SDL_free(extensions);
83     if(!hasSurfaceExtension)
84     {
85         SDL_SetError("Installed Vulkan doesn't implement the "
86                      VK_KHR_SURFACE_EXTENSION_NAME " extension");
87         goto fail;
88     }
89     else if(!hasWaylandSurfaceExtension)
90     {
91         SDL_SetError("Installed Vulkan doesn't implement the "
92                      VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "extension");
93         goto fail;
94     }
95     return 0;
96 
97 fail:
98     SDL_UnloadObject(_this->vulkan_config.loader_handle);
99     _this->vulkan_config.loader_handle = NULL;
100     return -1;
101 }
102 
Wayland_Vulkan_UnloadLibrary(_THIS)103 void Wayland_Vulkan_UnloadLibrary(_THIS)
104 {
105     if(_this->vulkan_config.loader_handle)
106     {
107         SDL_UnloadObject(_this->vulkan_config.loader_handle);
108         _this->vulkan_config.loader_handle = NULL;
109     }
110 }
111 
Wayland_Vulkan_GetInstanceExtensions(_THIS,SDL_Window * window,unsigned * count,const char ** names)112 SDL_bool Wayland_Vulkan_GetInstanceExtensions(_THIS,
113                                           SDL_Window *window,
114                                           unsigned *count,
115                                           const char **names)
116 {
117     static const char *const extensionsForWayland[] = {
118         VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
119     };
120     if(!_this->vulkan_config.loader_handle)
121     {
122         SDL_SetError("Vulkan is not loaded");
123         return SDL_FALSE;
124     }
125     return SDL_Vulkan_GetInstanceExtensions_Helper(
126             count, names, SDL_arraysize(extensionsForWayland),
127             extensionsForWayland);
128 }
129 
Wayland_Vulkan_GetDrawableSize(_THIS,SDL_Window * window,int * w,int * h)130 void Wayland_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h)
131 {
132     SDL_WindowData *data;
133     if (window->driverdata) {
134         data = (SDL_WindowData *) window->driverdata;
135 
136         if (w) {
137             *w = window->w * data->scale_factor;
138         }
139 
140         if (h) {
141             *h = window->h * data->scale_factor;
142         }
143     }
144 }
145 
Wayland_Vulkan_CreateSurface(_THIS,SDL_Window * window,VkInstance instance,VkSurfaceKHR * surface)146 SDL_bool Wayland_Vulkan_CreateSurface(_THIS,
147                                   SDL_Window *window,
148                                   VkInstance instance,
149                                   VkSurfaceKHR *surface)
150 {
151     SDL_WindowData *windowData = (SDL_WindowData *)window->driverdata;
152     PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
153         (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
154     PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR =
155         (PFN_vkCreateWaylandSurfaceKHR)vkGetInstanceProcAddr(
156                                             instance,
157                                             "vkCreateWaylandSurfaceKHR");
158     VkWaylandSurfaceCreateInfoKHR createInfo;
159     VkResult result;
160 
161     if(!_this->vulkan_config.loader_handle)
162     {
163         SDL_SetError("Vulkan is not loaded");
164         return SDL_FALSE;
165     }
166 
167     if(!vkCreateWaylandSurfaceKHR)
168     {
169         SDL_SetError(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
170                      " extension is not enabled in the Vulkan instance.");
171         return SDL_FALSE;
172     }
173     SDL_zero(createInfo);
174     createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
175     createInfo.pNext = NULL;
176     createInfo.flags = 0;
177     createInfo.display = windowData->waylandData->display;
178     createInfo.surface =  windowData->surface;
179     result = vkCreateWaylandSurfaceKHR(instance, &createInfo,
180                                        NULL, surface);
181     if(result != VK_SUCCESS)
182     {
183         SDL_SetError("vkCreateWaylandSurfaceKHR failed: %s",
184                      SDL_Vulkan_GetResultString(result));
185         return SDL_FALSE;
186     }
187     return SDL_TRUE;
188 }
189 
190 #endif
191 
192 /* vim: set ts=4 sw=4 expandtab: */
193