b412a2bab32a4ec0abfd60ef8b5020cc444d48ec
[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 *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 props->minImageCount = 2;
72 props->maxImageCount = 4;
73 props->currentExtent = (VkExtent2D) { -1, -1 };
74 props->minImageExtent = (VkExtent2D) { 1, 1 };
75 props->maxImageExtent = (VkExtent2D) { INT16_MAX, INT16_MAX };
76 props->supportedTransforms = VK_SURFACE_TRANSFORM_NONE_BIT_WSI;
77 props->currentTransform = VK_SURFACE_TRANSFORM_NONE_WSI;
78 props->maxImageArraySize = 1;
79 props->supportedUsageFlags =
80 VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT |
81 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
82
83 return VK_SUCCESS;
84 }
85
86 case VK_SURFACE_INFO_TYPE_FORMATS_WSI:
87 if (pData == NULL) {
88 *pDataSize = sizeof(formats);
89 return VK_SUCCESS;
90 }
91
92 assert(*pDataSize >= sizeof(formats));
93 memcpy(pData, formats, *pDataSize);
94
95 return VK_SUCCESS;
96
97 case VK_SURFACE_INFO_TYPE_PRESENT_MODES_WSI:
98 if (pData == NULL) {
99 *pDataSize = sizeof(present_modes);
100 return VK_SUCCESS;
101 }
102
103 assert(*pDataSize >= sizeof(present_modes));
104 memcpy(pData, present_modes, *pDataSize);
105
106 return VK_SUCCESS;
107 default:
108 return vk_error(VK_ERROR_INVALID_VALUE);
109 }
110 }
111
112 struct x11_swap_chain {
113 struct anv_swap_chain base;
114
115 xcb_connection_t * conn;
116 xcb_window_t window;
117 xcb_gc_t gc;
118 VkExtent2D extent;
119 uint32_t image_count;
120 uint32_t next_image;
121 struct {
122 struct anv_image * image;
123 struct anv_device_memory * memory;
124 xcb_pixmap_t pixmap;
125 } images[0];
126 };
127
128 static VkResult
129 x11_get_swap_chain_info(struct anv_swap_chain *anv_chain,
130 VkSwapChainInfoTypeWSI infoType,
131 size_t* pDataSize, void* pData)
132 {
133 struct x11_swap_chain *chain = (struct x11_swap_chain *)anv_chain;
134 size_t size;
135
136 switch (infoType) {
137 case VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI: {
138 VkSwapChainImagePropertiesWSI *images = pData;
139
140 size = chain->image_count * sizeof(*images);
141
142 if (pData == NULL) {
143 *pDataSize = size;
144 return VK_SUCCESS;
145 }
146
147 assert(size <= *pDataSize);
148 for (uint32_t i = 0; i < chain->image_count; i++)
149 images[i].image = anv_image_to_handle(chain->images[i].image);
150
151 *pDataSize = size;
152
153 return VK_SUCCESS;
154 }
155
156 default:
157 return vk_error(VK_ERROR_INVALID_VALUE);
158 }
159 }
160
161 static VkResult
162 x11_acquire_next_image(struct anv_swap_chain *anv_chain,
163 uint64_t timeout,
164 VkSemaphore semaphore,
165 uint32_t *image_index)
166 {
167 struct x11_swap_chain *chain = (struct x11_swap_chain *)anv_chain;
168
169 anv_finishme("Implement real blocking AcquireNextImage");
170 *image_index = chain->next_image;
171 chain->next_image = (chain->next_image + 1) % chain->image_count;
172 return VK_SUCCESS;
173 }
174
175 static VkResult
176 x11_queue_present(struct anv_swap_chain *anv_chain,
177 struct anv_queue *queue,
178 uint32_t image_index)
179 {
180 struct x11_swap_chain *chain = (struct x11_swap_chain *)anv_chain;
181
182 xcb_void_cookie_t cookie;
183
184 xcb_pixmap_t pixmap = chain->images[image_index].pixmap;
185
186 if (pixmap == XCB_NONE)
187 return vk_error(VK_ERROR_INVALID_VALUE);
188
189 cookie = xcb_copy_area(chain->conn,
190 pixmap,
191 chain->window,
192 chain->gc,
193 0, 0,
194 0, 0,
195 chain->extent.width,
196 chain->extent.height);
197 xcb_discard_reply(chain->conn, cookie.sequence);
198
199 xcb_flush(chain->conn);
200
201 return VK_SUCCESS;
202 }
203
204 static VkResult
205 x11_destroy_swap_chain(struct anv_swap_chain *chain)
206 {
207 anv_device_free(chain->device, chain);
208
209 return VK_SUCCESS;
210 }
211
212 static VkResult
213 x11_create_swap_chain(struct anv_wsi_implementation *impl,
214 struct anv_device *device,
215 const VkSwapChainCreateInfoWSI *pCreateInfo,
216 struct anv_swap_chain **swap_chain_out)
217 {
218 struct x11_swap_chain *chain;
219 xcb_void_cookie_t cookie;
220 VkResult result;
221
222 assert(pCreateInfo->pSurfaceDescription->sType ==
223 VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_WSI);
224 VkSurfaceDescriptionWindowWSI *vk_window =
225 (VkSurfaceDescriptionWindowWSI *)pCreateInfo->pSurfaceDescription;
226 assert(vk_window->platform == VK_PLATFORM_XCB_WSI);
227
228 int num_images = pCreateInfo->minImageCount;
229
230 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI);
231
232 size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
233 chain = anv_device_alloc(device, size, 8,
234 VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
235 if (chain == NULL)
236 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
237
238 chain->base.device = device;
239 chain->base.destroy = x11_destroy_swap_chain;
240 chain->base.get_swap_chain_info = x11_get_swap_chain_info;
241 chain->base.acquire_next_image = x11_acquire_next_image;
242 chain->base.queue_present = x11_queue_present;
243
244 VkPlatformHandleXcbWSI *vk_xcb_handle = vk_window->pPlatformHandle;
245
246 chain->conn = (xcb_connection_t *) vk_xcb_handle->connection;
247 chain->window = (xcb_window_t) (uintptr_t)vk_window->pPlatformWindow;
248 chain->extent = pCreateInfo->imageExtent;
249 chain->image_count = num_images;
250 chain->next_image = 0;
251
252 for (uint32_t i = 0; i < chain->image_count; i++) {
253 VkDeviceMemory memory_h;
254 VkImage image_h;
255 struct anv_image *image;
256 struct anv_surface *surface;
257 struct anv_device_memory *memory;
258
259 anv_image_create(anv_device_to_handle(device),
260 &(struct anv_image_create_info) {
261 .force_tile_mode = true,
262 .tile_mode = XMAJOR,
263 .stride = 0,
264 .vk_info =
265 &(VkImageCreateInfo) {
266 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
267 .imageType = VK_IMAGE_TYPE_2D,
268 .format = pCreateInfo->imageFormat,
269 .extent = {
270 .width = pCreateInfo->imageExtent.width,
271 .height = pCreateInfo->imageExtent.height,
272 .depth = 1
273 },
274 .mipLevels = 1,
275 .arraySize = 1,
276 .samples = 1,
277 /* FIXME: Need a way to use X tiling to allow scanout */
278 .tiling = VK_IMAGE_TILING_OPTIMAL,
279 .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
280 .flags = 0,
281 }},
282 &image_h);
283
284 image = anv_image_from_handle(image_h);
285 assert(anv_format_is_color(image->format));
286
287 surface = &image->color_surface;
288
289 anv_AllocMemory(anv_device_to_handle(device),
290 &(VkMemoryAllocInfo) {
291 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
292 .allocationSize = image->size,
293 .memoryTypeIndex = 0,
294 },
295 &memory_h);
296
297 memory = anv_device_memory_from_handle(memory_h);
298
299 anv_BindImageMemory(VK_NULL_HANDLE, anv_image_to_handle(image),
300 memory_h, 0);
301
302 int ret = anv_gem_set_tiling(device, memory->bo.gem_handle,
303 surface->stride, I915_TILING_X);
304 if (ret) {
305 result = vk_errorf(VK_ERROR_UNKNOWN, "set_tiling failed: %m");
306 goto fail;
307 }
308
309 int fd = anv_gem_handle_to_fd(device, memory->bo.gem_handle);
310 if (fd == -1) {
311 result = vk_errorf(VK_ERROR_UNKNOWN, "handle_to_fd failed: %m");
312 goto fail;
313 }
314
315 uint32_t bpp = 32;
316 uint32_t depth = 24;
317 xcb_pixmap_t pixmap = xcb_generate_id(chain->conn);
318
319 cookie =
320 xcb_dri3_pixmap_from_buffer_checked(chain->conn,
321 pixmap,
322 chain->window,
323 image->size,
324 pCreateInfo->imageExtent.width,
325 pCreateInfo->imageExtent.height,
326 surface->stride,
327 depth, bpp, fd);
328
329 chain->images[i].image = image;
330 chain->images[i].memory = memory;
331 chain->images[i].pixmap = pixmap;
332
333 xcb_discard_reply(chain->conn, cookie.sequence);
334 }
335
336 chain->gc = xcb_generate_id(chain->conn);
337 if (!chain->gc) {
338 result = vk_error(VK_ERROR_UNKNOWN);
339 goto fail;
340 }
341
342 cookie = xcb_create_gc(chain->conn,
343 chain->gc,
344 chain->window,
345 XCB_GC_GRAPHICS_EXPOSURES,
346 (uint32_t []) { 0 });
347 xcb_discard_reply(chain->conn, cookie.sequence);
348
349 *swap_chain_out = &chain->base;
350
351 return VK_SUCCESS;
352
353 fail:
354 return result;
355 }
356
357 VkResult
358 anv_x11_init_wsi(struct anv_instance *instance)
359 {
360 struct anv_wsi_implementation *impl;
361
362 impl = anv_instance_alloc(instance, sizeof(*impl), 8,
363 VK_SYSTEM_ALLOC_TYPE_INTERNAL);
364 if (!impl)
365 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
366
367 impl->get_window_supported = x11_get_window_supported;
368 impl->get_surface_info = x11_get_surface_info;
369 impl->create_swap_chain = x11_create_swap_chain;
370
371 instance->wsi_impl[VK_PLATFORM_XCB_WSI] = impl;
372
373 return VK_SUCCESS;
374 }
375
376 void
377 anv_x11_finish_wsi(struct anv_instance *instance)
378 {
379 anv_instance_free(instance, instance->wsi_impl[VK_PLATFORM_XCB_WSI]);
380 }