1 /* X11DRV Vulkan implementation
3 * Copyright 2017 Roderick Colenbrander
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 /* NOTE: If making changes here, consider whether they should be reflected in
21 * the other drivers. */
34 #define WIN32_NO_STATUS
38 #include "wine/debug.h"
41 #define VK_NO_PROTOTYPES
44 #include "wine/vulkan.h"
45 #include "wine/vulkan_driver.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(vulkan
);
49 #ifdef SONAME_LIBVULKAN
51 static pthread_mutex_t vulkan_mutex
;
53 #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000
55 static struct list surface_list
= LIST_INIT( surface_list
);
57 struct wine_vk_surface
62 VkSurfaceKHR host_surface
;
67 typedef struct VkXlibSurfaceCreateInfoKHR
69 VkStructureType sType
;
71 VkXlibSurfaceCreateFlagsKHR flags
;
74 } VkXlibSurfaceCreateInfoKHR
;
76 static VkResult (*pvkCreateXlibSurfaceKHR
)(VkInstance
, const VkXlibSurfaceCreateInfoKHR
*, const VkAllocationCallbacks
*, VkSurfaceKHR
*);
77 static void (*pvkDestroySurfaceKHR
)(VkInstance
, VkSurfaceKHR
, const VkAllocationCallbacks
*);
78 static VkBool32 (*pvkGetPhysicalDeviceXlibPresentationSupportKHR
)(VkPhysicalDevice
, uint32_t, Display
*, VisualID
);
80 static const struct vulkan_funcs vulkan_funcs
;
82 static inline struct wine_vk_surface
*surface_from_handle(VkSurfaceKHR handle
)
84 return (struct wine_vk_surface
*)(uintptr_t)handle
;
87 static void wine_vk_surface_release( struct wine_vk_surface
*surface
)
89 if (InterlockedDecrement(&surface
->ref
))
92 if (surface
->entry
.next
)
94 pthread_mutex_lock(&vulkan_mutex
);
95 list_remove(&surface
->entry
);
96 pthread_mutex_unlock(&vulkan_mutex
);
99 destroy_client_window( surface
->hwnd
, surface
->window
);
103 void destroy_vk_surface( HWND hwnd
)
105 struct wine_vk_surface
*surface
, *next
;
107 pthread_mutex_lock( &vulkan_mutex
);
108 LIST_FOR_EACH_ENTRY_SAFE( surface
, next
, &surface_list
, struct wine_vk_surface
, entry
)
110 if (surface
->hwnd
!= hwnd
) continue;
111 surface
->hwnd_thread_id
= 0;
112 surface
->hwnd
= NULL
;
114 pthread_mutex_unlock( &vulkan_mutex
);
117 void vulkan_thread_detach(void)
119 struct wine_vk_surface
*surface
, *next
;
120 DWORD thread_id
= GetCurrentThreadId();
122 pthread_mutex_lock(&vulkan_mutex
);
123 LIST_FOR_EACH_ENTRY_SAFE(surface
, next
, &surface_list
, struct wine_vk_surface
, entry
)
125 if (surface
->hwnd_thread_id
!= thread_id
)
128 TRACE("Detaching surface %p, hwnd %p.\n", surface
, surface
->hwnd
);
129 XReparentWindow(gdi_display
, surface
->window
, get_dummy_parent(), 0, 0);
130 XSync(gdi_display
, False
);
132 pthread_mutex_unlock(&vulkan_mutex
);
135 static VkResult
X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance
,
136 const VkWin32SurfaceCreateInfoKHR
*create_info
,
137 const VkAllocationCallbacks
*allocator
, VkSurfaceKHR
*surface
)
140 VkXlibSurfaceCreateInfoKHR create_info_host
;
141 struct wine_vk_surface
*x11_surface
;
143 TRACE("%p %p %p %p\n", instance
, create_info
, allocator
, surface
);
146 FIXME("Support for allocation callbacks not implemented yet\n");
148 /* TODO: support child window rendering. */
149 if (NtUserGetAncestor( create_info
->hwnd
, GA_PARENT
) != NtUserGetDesktopWindow())
151 FIXME("Application requires child window rendering, which is not implemented yet!\n");
152 return VK_ERROR_INCOMPATIBLE_DRIVER
;
155 x11_surface
= calloc(1, sizeof(*x11_surface
));
157 return VK_ERROR_OUT_OF_HOST_MEMORY
;
159 x11_surface
->ref
= 1;
160 x11_surface
->hwnd
= create_info
->hwnd
;
161 x11_surface
->window
= create_client_window( create_info
->hwnd
, &default_visual
, default_colormap
);
162 x11_surface
->hwnd_thread_id
= NtUserGetWindowThread( x11_surface
->hwnd
, NULL
);
164 if (!x11_surface
->window
)
166 ERR("Failed to allocate client window for hwnd=%p\n", create_info
->hwnd
);
168 /* VK_KHR_win32_surface only allows out of host and device memory as errors. */
170 return VK_ERROR_OUT_OF_HOST_MEMORY
;
173 create_info_host
.sType
= VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR
;
174 create_info_host
.pNext
= NULL
;
175 create_info_host
.flags
= 0; /* reserved */
176 create_info_host
.dpy
= gdi_display
;
177 create_info_host
.window
= x11_surface
->window
;
179 res
= pvkCreateXlibSurfaceKHR( instance
, &create_info_host
, NULL
/* allocator */, &x11_surface
->host_surface
);
180 if (res
!= VK_SUCCESS
)
182 ERR("Failed to create Xlib surface, res=%d\n", res
);
183 destroy_client_window( x11_surface
->hwnd
, x11_surface
->window
);
188 pthread_mutex_lock(&vulkan_mutex
);
189 list_add_tail(&surface_list
, &x11_surface
->entry
);
190 pthread_mutex_unlock(&vulkan_mutex
);
192 *surface
= (uintptr_t)x11_surface
;
194 TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*surface
));
198 static void X11DRV_vkDestroySurfaceKHR(VkInstance instance
, VkSurfaceKHR surface
,
199 const VkAllocationCallbacks
*allocator
)
201 struct wine_vk_surface
*x11_surface
= surface_from_handle(surface
);
203 TRACE("%p 0x%s %p\n", instance
, wine_dbgstr_longlong(surface
), allocator
);
206 FIXME("Support for allocation callbacks not implemented yet\n");
208 pvkDestroySurfaceKHR( instance
, x11_surface
->host_surface
, NULL
/* allocator */ );
209 wine_vk_surface_release(x11_surface
);
212 static VkBool32
X11DRV_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev
,
215 TRACE("%p %u\n", phys_dev
, index
);
217 return pvkGetPhysicalDeviceXlibPresentationSupportKHR(phys_dev
, index
, gdi_display
,
218 default_visual
.visual
->visualid
);
221 static const char *X11DRV_get_host_surface_extension(void)
223 return "VK_KHR_xlib_surface";
226 static VkSurfaceKHR
X11DRV_wine_get_host_surface( VkSurfaceKHR surface
)
228 struct wine_vk_surface
*x11_surface
= surface_from_handle(surface
);
230 TRACE("0x%s\n", wine_dbgstr_longlong(surface
));
232 return x11_surface
->host_surface
;
235 static void X11DRV_vulkan_surface_presented(HWND hwnd
, VkResult result
)
239 static const struct vulkan_funcs vulkan_funcs
=
241 X11DRV_vkCreateWin32SurfaceKHR
,
242 X11DRV_vkDestroySurfaceKHR
,
245 X11DRV_vkGetPhysicalDeviceWin32PresentationSupportKHR
,
248 X11DRV_get_host_surface_extension
,
249 X11DRV_wine_get_host_surface
,
250 X11DRV_vulkan_surface_presented
,
253 UINT
X11DRV_VulkanInit( UINT version
, void *vulkan_handle
, struct vulkan_funcs
*driver_funcs
)
255 if (version
!= WINE_VULKAN_DRIVER_VERSION
)
257 ERR( "version mismatch, win32u wants %u but driver has %u\n", version
, WINE_VULKAN_DRIVER_VERSION
);
258 return STATUS_INVALID_PARAMETER
;
261 init_recursive_mutex( &vulkan_mutex
);
263 #define LOAD_FUNCPTR( f ) if (!(p##f = dlsym( vulkan_handle, #f ))) return STATUS_PROCEDURE_NOT_FOUND;
264 LOAD_FUNCPTR( vkCreateXlibSurfaceKHR
);
265 LOAD_FUNCPTR( vkDestroySurfaceKHR
);
266 LOAD_FUNCPTR( vkGetPhysicalDeviceXlibPresentationSupportKHR
);
269 *driver_funcs
= vulkan_funcs
;
270 return STATUS_SUCCESS
;
273 #else /* No vulkan */
275 UINT
X11DRV_VulkanInit( UINT version
, void *vulkan_handle
, struct vulkan_funcs
*driver_funcs
)
277 ERR( "Wine was built without Vulkan support.\n" );
278 return STATUS_NOT_IMPLEMENTED
;
281 void destroy_vk_surface( HWND hwnd
)
285 void vulkan_thread_detach(void)
289 #endif /* SONAME_LIBVULKAN */