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