vulkan/wsi: Implement prime in a completely generic way
[mesa.git] / src / intel / vulkan / anv_wsi.c
1 /*
2 * Copyright © 2015 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "anv_private.h"
25 #include "wsi_common.h"
26 #include "vk_format_info.h"
27 #include "vk_util.h"
28
29 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
30 #define WSI_CB(x) .x = anv_##x
31 static const struct wsi_callbacks wsi_cbs = {
32 WSI_CB(GetPhysicalDeviceFormatProperties),
33 };
34 #endif
35
36 static PFN_vkVoidFunction
37 anv_wsi_proc_addr(VkPhysicalDevice physicalDevice, const char *pName)
38 {
39 ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice);
40 return anv_lookup_entrypoint(&physical_device->info, pName);
41 }
42
43 static uint32_t
44 anv_wsi_queue_get_family_index(VkQueue queue)
45 {
46 return 0;
47 }
48
49 VkResult
50 anv_init_wsi(struct anv_physical_device *physical_device)
51 {
52 VkResult result;
53
54 wsi_device_init(&physical_device->wsi_device,
55 anv_physical_device_to_handle(physical_device),
56 anv_wsi_proc_addr);
57
58 physical_device->wsi_device.queue_get_family_index =
59 anv_wsi_queue_get_family_index;
60
61 #ifdef VK_USE_PLATFORM_XCB_KHR
62 result = wsi_x11_init_wsi(&physical_device->wsi_device, &physical_device->instance->alloc);
63 if (result != VK_SUCCESS)
64 return result;
65 #endif
66
67 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
68 result = wsi_wl_init_wsi(&physical_device->wsi_device, &physical_device->instance->alloc,
69 anv_physical_device_to_handle(physical_device),
70 &wsi_cbs);
71 if (result != VK_SUCCESS) {
72 #ifdef VK_USE_PLATFORM_XCB_KHR
73 wsi_x11_finish_wsi(&physical_device->wsi_device, &physical_device->instance->alloc);
74 #endif
75 return result;
76 }
77 #endif
78
79 return VK_SUCCESS;
80 }
81
82 void
83 anv_finish_wsi(struct anv_physical_device *physical_device)
84 {
85 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
86 wsi_wl_finish_wsi(&physical_device->wsi_device, &physical_device->instance->alloc);
87 #endif
88 #ifdef VK_USE_PLATFORM_XCB_KHR
89 wsi_x11_finish_wsi(&physical_device->wsi_device, &physical_device->instance->alloc);
90 #endif
91 }
92
93 void anv_DestroySurfaceKHR(
94 VkInstance _instance,
95 VkSurfaceKHR _surface,
96 const VkAllocationCallbacks* pAllocator)
97 {
98 ANV_FROM_HANDLE(anv_instance, instance, _instance);
99 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
100
101 if (!surface)
102 return;
103
104 vk_free2(&instance->alloc, pAllocator, surface);
105 }
106
107 VkResult anv_GetPhysicalDeviceSurfaceSupportKHR(
108 VkPhysicalDevice physicalDevice,
109 uint32_t queueFamilyIndex,
110 VkSurfaceKHR _surface,
111 VkBool32* pSupported)
112 {
113 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
114 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
115 struct wsi_interface *iface = device->wsi_device.wsi[surface->platform];
116
117 return iface->get_support(surface, &device->wsi_device,
118 &device->instance->alloc,
119 queueFamilyIndex, device->local_fd, false, pSupported);
120 }
121
122 VkResult anv_GetPhysicalDeviceSurfaceCapabilitiesKHR(
123 VkPhysicalDevice physicalDevice,
124 VkSurfaceKHR _surface,
125 VkSurfaceCapabilitiesKHR* pSurfaceCapabilities)
126 {
127 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
128 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
129 struct wsi_interface *iface = device->wsi_device.wsi[surface->platform];
130
131 return iface->get_capabilities(surface, pSurfaceCapabilities);
132 }
133
134 VkResult anv_GetPhysicalDeviceSurfaceCapabilities2KHR(
135 VkPhysicalDevice physicalDevice,
136 const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
137 VkSurfaceCapabilities2KHR* pSurfaceCapabilities)
138 {
139 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
140 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
141 struct wsi_interface *iface = device->wsi_device.wsi[surface->platform];
142
143 return iface->get_capabilities2(surface, pSurfaceInfo->pNext,
144 pSurfaceCapabilities);
145 }
146
147 VkResult anv_GetPhysicalDeviceSurfaceFormatsKHR(
148 VkPhysicalDevice physicalDevice,
149 VkSurfaceKHR _surface,
150 uint32_t* pSurfaceFormatCount,
151 VkSurfaceFormatKHR* pSurfaceFormats)
152 {
153 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
154 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
155 struct wsi_interface *iface = device->wsi_device.wsi[surface->platform];
156
157 return iface->get_formats(surface, &device->wsi_device, pSurfaceFormatCount,
158 pSurfaceFormats);
159 }
160
161 VkResult anv_GetPhysicalDeviceSurfaceFormats2KHR(
162 VkPhysicalDevice physicalDevice,
163 const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
164 uint32_t* pSurfaceFormatCount,
165 VkSurfaceFormat2KHR* pSurfaceFormats)
166 {
167 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
168 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
169 struct wsi_interface *iface = device->wsi_device.wsi[surface->platform];
170
171 return iface->get_formats2(surface, &device->wsi_device, pSurfaceInfo->pNext,
172 pSurfaceFormatCount, pSurfaceFormats);
173 }
174
175 VkResult anv_GetPhysicalDeviceSurfacePresentModesKHR(
176 VkPhysicalDevice physicalDevice,
177 VkSurfaceKHR _surface,
178 uint32_t* pPresentModeCount,
179 VkPresentModeKHR* pPresentModes)
180 {
181 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
182 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
183 struct wsi_interface *iface = device->wsi_device.wsi[surface->platform];
184
185 return iface->get_present_modes(surface, pPresentModeCount,
186 pPresentModes);
187 }
188
189
190 static VkResult
191 anv_wsi_image_create(VkDevice device_h,
192 const VkSwapchainCreateInfoKHR *pCreateInfo,
193 const VkAllocationCallbacks* pAllocator,
194 struct wsi_image *wsi_image)
195 {
196 struct anv_device *device = anv_device_from_handle(device_h);
197 VkImage image_h;
198 struct anv_image *image;
199
200 VkResult result;
201 result = anv_image_create(anv_device_to_handle(device),
202 &(struct anv_image_create_info) {
203 .isl_tiling_flags = ISL_TILING_X_BIT,
204 .stride = 0,
205 .vk_info =
206 &(VkImageCreateInfo) {
207 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
208 .imageType = VK_IMAGE_TYPE_2D,
209 .format = pCreateInfo->imageFormat,
210 .extent = {
211 .width = pCreateInfo->imageExtent.width,
212 .height = pCreateInfo->imageExtent.height,
213 .depth = 1
214 },
215 .mipLevels = 1,
216 .arrayLayers = 1,
217 .samples = 1,
218 /* FIXME: Need a way to use X tiling to allow scanout */
219 .tiling = VK_IMAGE_TILING_OPTIMAL,
220 .usage = (pCreateInfo->imageUsage |
221 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT),
222 .flags = 0,
223 }},
224 NULL,
225 &image_h);
226 if (result != VK_SUCCESS)
227 return result;
228
229 image = anv_image_from_handle(image_h);
230 assert(vk_format_is_color(image->vk_format));
231
232 VkDeviceMemory memory_h;
233 struct anv_device_memory *memory;
234 result = anv_AllocateMemory(anv_device_to_handle(device),
235 &(VkMemoryAllocateInfo) {
236 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
237 .allocationSize = image->size,
238 .memoryTypeIndex = 0,
239 },
240 NULL /* XXX: pAllocator */,
241 &memory_h);
242 if (result != VK_SUCCESS)
243 goto fail_create_image;
244
245 memory = anv_device_memory_from_handle(memory_h);
246
247 /* We need to set the WRITE flag on window system buffers so that GEM will
248 * know we're writing to them and synchronize uses on other rings (eg if
249 * the display server uses the blitter ring).
250 */
251 memory->bo->flags &= ~EXEC_OBJECT_ASYNC;
252 memory->bo->flags |= EXEC_OBJECT_WRITE;
253
254 anv_BindImageMemory(device_h, image_h, memory_h, 0);
255 assert(image->planes[0].offset == 0);
256
257 struct anv_surface *surface = &image->planes[0].surface;
258 assert(surface->isl.tiling == ISL_TILING_X);
259
260 int ret = anv_gem_set_tiling(device, memory->bo->gem_handle,
261 surface->isl.row_pitch, I915_TILING_X);
262 if (ret) {
263 /* FINISHME: Choose a better error. */
264 result = vk_errorf(device->instance, device,
265 VK_ERROR_OUT_OF_DEVICE_MEMORY,
266 "set_tiling failed: %m");
267 goto fail_alloc_memory;
268 }
269
270 int fd = anv_gem_handle_to_fd(device, memory->bo->gem_handle);
271 if (fd == -1) {
272 /* FINISHME: Choose a better error. */
273 result = vk_errorf(device->instance, device,
274 VK_ERROR_OUT_OF_DEVICE_MEMORY,
275 "handle_to_fd failed: %m");
276 goto fail_alloc_memory;
277 }
278
279 wsi_image->image = image_h;
280 wsi_image->memory = memory_h;
281 wsi_image->fd = fd;
282 wsi_image->size = image->size;
283 wsi_image->offset = 0;
284 wsi_image->row_pitch = surface->isl.row_pitch;
285 return VK_SUCCESS;
286 fail_alloc_memory:
287 anv_FreeMemory(device_h, memory_h, pAllocator);
288
289 fail_create_image:
290 anv_DestroyImage(device_h, image_h, pAllocator);
291 return result;
292 }
293
294 static void
295 anv_wsi_image_free(VkDevice device,
296 const VkAllocationCallbacks* pAllocator,
297 struct wsi_image *wsi_image)
298 {
299 anv_DestroyImage(device, wsi_image->image, pAllocator);
300
301 anv_FreeMemory(device, wsi_image->memory, pAllocator);
302 }
303
304 static const struct wsi_image_fns anv_wsi_image_fns = {
305 .create_wsi_image = anv_wsi_image_create,
306 .free_wsi_image = anv_wsi_image_free,
307 };
308
309 VkResult anv_CreateSwapchainKHR(
310 VkDevice _device,
311 const VkSwapchainCreateInfoKHR* pCreateInfo,
312 const VkAllocationCallbacks* pAllocator,
313 VkSwapchainKHR* pSwapchain)
314 {
315 ANV_FROM_HANDLE(anv_device, device, _device);
316 ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface);
317 struct wsi_interface *iface =
318 device->instance->physicalDevice.wsi_device.wsi[surface->platform];
319 struct wsi_swapchain *swapchain;
320 const VkAllocationCallbacks *alloc;
321
322 if (pAllocator)
323 alloc = pAllocator;
324 else
325 alloc = &device->alloc;
326 VkResult result = iface->create_swapchain(surface, _device,
327 &device->instance->physicalDevice.wsi_device,
328 device->instance->physicalDevice.local_fd,
329 pCreateInfo,
330 alloc, &anv_wsi_image_fns,
331 &swapchain);
332 if (result != VK_SUCCESS)
333 return result;
334
335 swapchain->alloc = *alloc;
336
337 for (unsigned i = 0; i < ARRAY_SIZE(swapchain->fences); i++)
338 swapchain->fences[i] = VK_NULL_HANDLE;
339
340 *pSwapchain = wsi_swapchain_to_handle(swapchain);
341
342 return VK_SUCCESS;
343 }
344
345 void anv_DestroySwapchainKHR(
346 VkDevice _device,
347 VkSwapchainKHR _swapchain,
348 const VkAllocationCallbacks* pAllocator)
349 {
350 ANV_FROM_HANDLE(anv_device, device, _device);
351 ANV_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
352 const VkAllocationCallbacks *alloc;
353
354 if (!swapchain)
355 return;
356
357 if (pAllocator)
358 alloc = pAllocator;
359 else
360 alloc = &device->alloc;
361 for (unsigned i = 0; i < ARRAY_SIZE(swapchain->fences); i++) {
362 if (swapchain->fences[i] != VK_NULL_HANDLE)
363 anv_DestroyFence(_device, swapchain->fences[i], pAllocator);
364 }
365
366 swapchain->destroy(swapchain, alloc);
367 }
368
369 VkResult anv_GetSwapchainImagesKHR(
370 VkDevice device,
371 VkSwapchainKHR _swapchain,
372 uint32_t* pSwapchainImageCount,
373 VkImage* pSwapchainImages)
374 {
375 ANV_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
376
377 return swapchain->get_images(swapchain, pSwapchainImageCount,
378 pSwapchainImages);
379 }
380
381 VkResult anv_AcquireNextImageKHR(
382 VkDevice _device,
383 VkSwapchainKHR _swapchain,
384 uint64_t timeout,
385 VkSemaphore semaphore,
386 VkFence _fence,
387 uint32_t* pImageIndex)
388 {
389 ANV_FROM_HANDLE(anv_device, device, _device);
390 ANV_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
391 ANV_FROM_HANDLE(anv_fence, fence, _fence);
392
393 VkResult result = swapchain->acquire_next_image(swapchain, timeout,
394 semaphore, pImageIndex);
395
396 /* Thanks to implicit sync, the image is ready immediately. However, we
397 * should wait for the current GPU state to finish.
398 */
399 if (fence)
400 anv_QueueSubmit(anv_queue_to_handle(&device->queue), 0, NULL, _fence);
401
402 return result;
403 }
404
405 VkResult anv_QueuePresentKHR(
406 VkQueue _queue,
407 const VkPresentInfoKHR* pPresentInfo)
408 {
409 ANV_FROM_HANDLE(anv_queue, queue, _queue);
410 VkResult result = VK_SUCCESS;
411
412 const VkPresentRegionsKHR *regions =
413 vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR);
414
415 for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
416 ANV_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]);
417 VkResult item_result;
418
419 const VkPresentRegionKHR *region = NULL;
420 if (regions && regions->pRegions)
421 region = &regions->pRegions[i];
422
423 assert(anv_device_from_handle(swapchain->device) == queue->device);
424
425 if (swapchain->fences[0] == VK_NULL_HANDLE) {
426 item_result = anv_CreateFence(anv_device_to_handle(queue->device),
427 &(VkFenceCreateInfo) {
428 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
429 .flags = 0,
430 }, &swapchain->alloc, &swapchain->fences[0]);
431 if (pPresentInfo->pResults != NULL)
432 pPresentInfo->pResults[i] = item_result;
433 result = result == VK_SUCCESS ? item_result : result;
434 if (item_result != VK_SUCCESS)
435 continue;
436 } else {
437 anv_ResetFences(anv_device_to_handle(queue->device),
438 1, &swapchain->fences[0]);
439 }
440
441 anv_QueueSubmit(_queue, 0, NULL, swapchain->fences[0]);
442
443 item_result = swapchain->queue_present(swapchain,
444 _queue,
445 pPresentInfo->waitSemaphoreCount,
446 pPresentInfo->pWaitSemaphores,
447 pPresentInfo->pImageIndices[i],
448 region);
449 /* TODO: What if one of them returns OUT_OF_DATE? */
450 if (pPresentInfo->pResults != NULL)
451 pPresentInfo->pResults[i] = item_result;
452 result = result == VK_SUCCESS ? item_result : result;
453 if (item_result != VK_SUCCESS)
454 continue;
455
456 VkFence last = swapchain->fences[2];
457 swapchain->fences[2] = swapchain->fences[1];
458 swapchain->fences[1] = swapchain->fences[0];
459 swapchain->fences[0] = last;
460
461 if (last != VK_NULL_HANDLE) {
462 anv_WaitForFences(anv_device_to_handle(queue->device),
463 1, &last, true, 1);
464 }
465 }
466
467 return VK_SUCCESS;
468 }