vk/wsi/x11: Actually block on X so we don't re-use busy buffers
[mesa.git] / src / vulkan / anv_wsi_x11.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 <xcb/xcb.h>
25 #include <xcb/dri3.h>
26 #include <xcb/present.h>
27
28 #include "anv_wsi.h"
29
30 static const VkFormat formats[] = {
31 VK_FORMAT_B5G6R5_UNORM,
32 VK_FORMAT_B8G8R8A8_UNORM,
33 VK_FORMAT_B8G8R8A8_SRGB,
34 };
35
36 static const VkSurfacePresentModePropertiesWSI present_modes[] = {
37 { VK_PRESENT_MODE_MAILBOX_WSI },
38 };
39
40 static VkResult
41 x11_get_window_supported(struct anv_wsi_implementation *impl,
42 struct anv_physical_device *physical_device,
43 const VkSurfaceDescriptionWindowWSI *window,
44 VkBool32 *pSupported)
45 {
46 *pSupported = true;
47 stub_return(VK_SUCCESS);
48 }
49
50 static VkResult
51 x11_get_surface_info(struct anv_wsi_implementation *impl,
52 struct anv_device *device,
53 VkSurfaceDescriptionWindowWSI *vk_window,
54 VkSurfaceInfoTypeWSI infoType,
55 size_t* pDataSize, void* pData)
56 {
57 if (pDataSize == NULL)
58 return vk_error(VK_ERROR_INVALID_POINTER);
59
60 switch (infoType) {
61 case VK_SURFACE_INFO_TYPE_PROPERTIES_WSI: {
62 VkSurfacePropertiesWSI *props = pData;
63
64 if (pData == NULL) {
65 *pDataSize = sizeof(*props);
66 return VK_SUCCESS;
67 }
68
69 assert(*pDataSize >= sizeof(*props));
70
71 VkPlatformHandleXcbWSI *vk_xcb_handle = vk_window->pPlatformHandle;
72 xcb_connection_t *conn = vk_xcb_handle->connection;
73 xcb_window_t win = (xcb_window_t)(uintptr_t)vk_window->pPlatformWindow;
74
75 xcb_get_geometry_cookie_t cookie = xcb_get_geometry(conn, win);
76 xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(conn, cookie,
77 NULL);
78 VkExtent2D extent = { geom->width, geom->height };
79 free(geom);
80
81 props->minImageCount = 2;
82 props->maxImageCount = 4;
83 props->currentExtent = extent;
84 props->minImageExtent = extent;
85 props->maxImageExtent = extent;
86 props->supportedTransforms = VK_SURFACE_TRANSFORM_NONE_BIT_WSI;
87 props->currentTransform = VK_SURFACE_TRANSFORM_NONE_WSI;
88 props->maxImageArraySize = 1;
89 props->supportedUsageFlags =
90 VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT |
91 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
92
93 return VK_SUCCESS;
94 }
95
96 case VK_SURFACE_INFO_TYPE_FORMATS_WSI:
97 if (pData == NULL) {
98 *pDataSize = sizeof(formats);
99 return VK_SUCCESS;
100 }
101
102 assert(*pDataSize >= sizeof(formats));
103 memcpy(pData, formats, *pDataSize);
104
105 return VK_SUCCESS;
106
107 case VK_SURFACE_INFO_TYPE_PRESENT_MODES_WSI:
108 if (pData == NULL) {
109 *pDataSize = sizeof(present_modes);
110 return VK_SUCCESS;
111 }
112
113 assert(*pDataSize >= sizeof(present_modes));
114 memcpy(pData, present_modes, *pDataSize);
115
116 return VK_SUCCESS;
117 default:
118 return vk_error(VK_ERROR_INVALID_VALUE);
119 }
120 }
121
122 struct x11_image {
123 struct anv_image * image;
124 struct anv_device_memory * memory;
125 xcb_pixmap_t pixmap;
126 xcb_get_geometry_cookie_t geom_cookie;
127 bool busy;
128 };
129
130 struct x11_swap_chain {
131 struct anv_swap_chain base;
132
133 xcb_connection_t * conn;
134 xcb_window_t window;
135 xcb_gc_t gc;
136 VkExtent2D extent;
137 uint32_t image_count;
138 uint32_t next_image;
139 struct x11_image images[0];
140 };
141
142 static VkResult
143 x11_get_swap_chain_info(struct anv_swap_chain *anv_chain,
144 VkSwapChainInfoTypeWSI infoType,
145 size_t* pDataSize, void* pData)
146 {
147 struct x11_swap_chain *chain = (struct x11_swap_chain *)anv_chain;
148 size_t size;
149
150 switch (infoType) {
151 case VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI: {
152 VkSwapChainImagePropertiesWSI *images = pData;
153
154 size = chain->image_count * sizeof(*images);
155
156 if (pData == NULL) {
157 *pDataSize = size;
158 return VK_SUCCESS;
159 }
160
161 assert(size <= *pDataSize);
162 for (uint32_t i = 0; i < chain->image_count; i++)
163 images[i].image = anv_image_to_handle(chain->images[i].image);
164
165 *pDataSize = size;
166
167 return VK_SUCCESS;
168 }
169
170 default:
171 return vk_error(VK_ERROR_INVALID_VALUE);
172 }
173 }
174
175 static VkResult
176 x11_acquire_next_image(struct anv_swap_chain *anv_chain,
177 uint64_t timeout,
178 VkSemaphore semaphore,
179 uint32_t *image_index)
180 {
181 struct x11_swap_chain *chain = (struct x11_swap_chain *)anv_chain;
182 struct x11_image *image = &chain->images[chain->next_image];
183
184 if (image->busy) {
185 xcb_get_geometry_reply_t *geom =
186 xcb_get_geometry_reply(chain->conn, image->geom_cookie, NULL);
187 image->busy = false;
188
189 if (geom->width != chain->extent.width ||
190 geom->height != chain->extent.height) {
191 free(geom);
192 return VK_ERROR_OUT_OF_DATE_WSI;
193 }
194 free(geom);
195 }
196
197 *image_index = chain->next_image;
198 chain->next_image = (chain->next_image + 1) % chain->image_count;
199 return VK_SUCCESS;
200 }
201
202 static VkResult
203 x11_queue_present(struct anv_swap_chain *anv_chain,
204 struct anv_queue *queue,
205 uint32_t image_index)
206 {
207 struct x11_swap_chain *chain = (struct x11_swap_chain *)anv_chain;
208 struct x11_image *image = &chain->images[image_index];
209
210 assert(image_index < chain->image_count);
211
212 xcb_void_cookie_t cookie;
213
214 cookie = xcb_copy_area(chain->conn,
215 image->pixmap,
216 chain->window,
217 chain->gc,
218 0, 0,
219 0, 0,
220 chain->extent.width,
221 chain->extent.height);
222 xcb_discard_reply(chain->conn, cookie.sequence);
223
224 image->geom_cookie = xcb_get_geometry(chain->conn, chain->window);
225 image->busy = true;
226
227 xcb_flush(chain->conn);
228
229 return VK_SUCCESS;
230 }
231
232 static VkResult
233 x11_destroy_swap_chain(struct anv_swap_chain *anv_chain)
234 {
235 struct x11_swap_chain *chain = (struct x11_swap_chain *)anv_chain;
236 xcb_void_cookie_t cookie;
237
238 for (uint32_t i = 0; i < chain->image_count; i++) {
239 struct x11_image *image = &chain->images[i];
240
241 if (image->busy)
242 xcb_discard_reply(chain->conn, image->geom_cookie.sequence);
243
244 cookie = xcb_free_pixmap(chain->conn, image->pixmap);
245 xcb_discard_reply(chain->conn, cookie.sequence);
246
247 /* TODO: Delete images and free memory */
248 }
249
250 anv_device_free(chain->base.device, chain);
251
252 return VK_SUCCESS;
253 }
254
255 static VkResult
256 x11_create_swap_chain(struct anv_wsi_implementation *impl,
257 struct anv_device *device,
258 const VkSwapChainCreateInfoWSI *pCreateInfo,
259 struct anv_swap_chain **swap_chain_out)
260 {
261 struct x11_swap_chain *chain;
262 xcb_void_cookie_t cookie;
263 VkResult result;
264
265 assert(pCreateInfo->pSurfaceDescription->sType ==
266 VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_WSI);
267 VkSurfaceDescriptionWindowWSI *vk_window =
268 (VkSurfaceDescriptionWindowWSI *)pCreateInfo->pSurfaceDescription;
269 assert(vk_window->platform == VK_PLATFORM_XCB_WSI);
270
271 int num_images = pCreateInfo->minImageCount;
272
273 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI);
274
275 size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
276 chain = anv_device_alloc(device, size, 8,
277 VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
278 if (chain == NULL)
279 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
280
281 chain->base.device = device;
282 chain->base.destroy = x11_destroy_swap_chain;
283 chain->base.get_swap_chain_info = x11_get_swap_chain_info;
284 chain->base.acquire_next_image = x11_acquire_next_image;
285 chain->base.queue_present = x11_queue_present;
286
287 VkPlatformHandleXcbWSI *vk_xcb_handle = vk_window->pPlatformHandle;
288
289 chain->conn = (xcb_connection_t *) vk_xcb_handle->connection;
290 chain->window = (xcb_window_t) (uintptr_t)vk_window->pPlatformWindow;
291 chain->extent = pCreateInfo->imageExtent;
292 chain->image_count = num_images;
293 chain->next_image = 0;
294
295 for (uint32_t i = 0; i < chain->image_count; i++) {
296 VkDeviceMemory memory_h;
297 VkImage image_h;
298 struct anv_image *image;
299 struct anv_surface *surface;
300 struct anv_device_memory *memory;
301
302 anv_image_create(anv_device_to_handle(device),
303 &(struct anv_image_create_info) {
304 .force_tile_mode = true,
305 .tile_mode = XMAJOR,
306 .stride = 0,
307 .vk_info =
308 &(VkImageCreateInfo) {
309 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
310 .imageType = VK_IMAGE_TYPE_2D,
311 .format = pCreateInfo->imageFormat,
312 .extent = {
313 .width = pCreateInfo->imageExtent.width,
314 .height = pCreateInfo->imageExtent.height,
315 .depth = 1
316 },
317 .mipLevels = 1,
318 .arraySize = 1,
319 .samples = 1,
320 /* FIXME: Need a way to use X tiling to allow scanout */
321 .tiling = VK_IMAGE_TILING_OPTIMAL,
322 .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
323 .flags = 0,
324 }},
325 &image_h);
326
327 image = anv_image_from_handle(image_h);
328 assert(anv_format_is_color(image->format));
329
330 surface = &image->color_surface;
331
332 anv_AllocMemory(anv_device_to_handle(device),
333 &(VkMemoryAllocInfo) {
334 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
335 .allocationSize = image->size,
336 .memoryTypeIndex = 0,
337 },
338 &memory_h);
339
340 memory = anv_device_memory_from_handle(memory_h);
341
342 anv_BindImageMemory(VK_NULL_HANDLE, anv_image_to_handle(image),
343 memory_h, 0);
344
345 int ret = anv_gem_set_tiling(device, memory->bo.gem_handle,
346 surface->stride, I915_TILING_X);
347 if (ret) {
348 result = vk_errorf(VK_ERROR_UNKNOWN, "set_tiling failed: %m");
349 goto fail;
350 }
351
352 int fd = anv_gem_handle_to_fd(device, memory->bo.gem_handle);
353 if (fd == -1) {
354 result = vk_errorf(VK_ERROR_UNKNOWN, "handle_to_fd failed: %m");
355 goto fail;
356 }
357
358 uint32_t bpp = 32;
359 uint32_t depth = 24;
360 xcb_pixmap_t pixmap = xcb_generate_id(chain->conn);
361
362 cookie =
363 xcb_dri3_pixmap_from_buffer_checked(chain->conn,
364 pixmap,
365 chain->window,
366 image->size,
367 pCreateInfo->imageExtent.width,
368 pCreateInfo->imageExtent.height,
369 surface->stride,
370 depth, bpp, fd);
371
372 chain->images[i].image = image;
373 chain->images[i].memory = memory;
374 chain->images[i].pixmap = pixmap;
375 chain->images[i].busy = false;
376
377 xcb_discard_reply(chain->conn, cookie.sequence);
378 }
379
380 chain->gc = xcb_generate_id(chain->conn);
381 if (!chain->gc) {
382 result = vk_error(VK_ERROR_UNKNOWN);
383 goto fail;
384 }
385
386 cookie = xcb_create_gc(chain->conn,
387 chain->gc,
388 chain->window,
389 XCB_GC_GRAPHICS_EXPOSURES,
390 (uint32_t []) { 0 });
391 xcb_discard_reply(chain->conn, cookie.sequence);
392
393 *swap_chain_out = &chain->base;
394
395 return VK_SUCCESS;
396
397 fail:
398 return result;
399 }
400
401 VkResult
402 anv_x11_init_wsi(struct anv_instance *instance)
403 {
404 struct anv_wsi_implementation *impl;
405
406 impl = anv_instance_alloc(instance, sizeof(*impl), 8,
407 VK_SYSTEM_ALLOC_TYPE_INTERNAL);
408 if (!impl)
409 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
410
411 impl->get_window_supported = x11_get_window_supported;
412 impl->get_surface_info = x11_get_surface_info;
413 impl->create_swap_chain = x11_create_swap_chain;
414
415 instance->wsi_impl[VK_PLATFORM_XCB_WSI] = impl;
416
417 return VK_SUCCESS;
418 }
419
420 void
421 anv_x11_finish_wsi(struct anv_instance *instance)
422 {
423 anv_instance_free(instance, instance->wsi_impl[VK_PLATFORM_XCB_WSI]);
424 }