2 * Copyright © 2015 Intel Corporation
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:
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
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
26 #include <xcb/present.h>
30 #include "util/hash_table.h"
32 struct wsi_x11_connection
{
38 struct anv_wsi_interface base
;
40 pthread_mutex_t mutex
;
41 /* Hash table of xcb_connection -> wsi_x11_connection mappings */
42 struct hash_table
*connections
;
45 static struct wsi_x11_connection
*
46 wsi_x11_connection_create(struct anv_instance
*instance
, xcb_connection_t
*conn
)
48 xcb_query_extension_cookie_t dri3_cookie
, pres_cookie
;
49 xcb_query_extension_reply_t
*dri3_reply
, *pres_reply
;
51 struct wsi_x11_connection
*wsi_conn
=
52 anv_alloc(&instance
->alloc
, sizeof(*wsi_conn
), 8,
53 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
);
57 dri3_cookie
= xcb_query_extension(conn
, 4, "DRI3");
58 pres_cookie
= xcb_query_extension(conn
, 7, "PRESENT");
60 dri3_reply
= xcb_query_extension_reply(conn
, dri3_cookie
, NULL
);
61 pres_reply
= xcb_query_extension_reply(conn
, pres_cookie
, NULL
);
62 if (dri3_reply
== NULL
|| pres_reply
== NULL
) {
65 anv_free(&instance
->alloc
, wsi_conn
);
69 wsi_conn
->has_dri3
= dri3_reply
->present
!= 0;
70 wsi_conn
->has_present
= pres_reply
->present
!= 0;
79 wsi_x11_connection_destroy(struct anv_instance
*instance
,
80 struct wsi_x11_connection
*conn
)
82 anv_free(&instance
->alloc
, conn
);
85 static struct wsi_x11_connection
*
86 wsi_x11_get_connection(struct anv_instance
*instance
, xcb_connection_t
*conn
)
89 (struct wsi_x11
*)instance
->wsi
[VK_ICD_WSI_PLATFORM_XCB
];
91 pthread_mutex_lock(&wsi
->mutex
);
93 struct hash_entry
*entry
= _mesa_hash_table_search(wsi
->connections
, conn
);
95 /* We're about to make a bunch of blocking calls. Let's drop the
96 * mutex for now so we don't block up too badly.
98 pthread_mutex_unlock(&wsi
->mutex
);
100 struct wsi_x11_connection
*wsi_conn
=
101 wsi_x11_connection_create(instance
, conn
);
103 pthread_mutex_lock(&wsi
->mutex
);
105 entry
= _mesa_hash_table_search(wsi
->connections
, conn
);
107 /* Oops, someone raced us to it */
108 wsi_x11_connection_destroy(instance
, wsi_conn
);
110 entry
= _mesa_hash_table_insert(wsi
->connections
, conn
, wsi_conn
);
114 pthread_mutex_unlock(&wsi
->mutex
);
119 static const VkSurfaceFormatKHR formats
[] = {
120 { .format
= VK_FORMAT_B8G8R8A8_UNORM
, },
123 static const VkPresentModeKHR present_modes
[] = {
124 VK_PRESENT_MODE_MAILBOX_KHR
,
127 VkBool32
anv_GetPhysicalDeviceXcbPresentationSupportKHR(
128 VkPhysicalDevice physicalDevice
,
129 uint32_t queueFamilyIndex
,
130 xcb_connection_t
* connection
,
131 xcb_visualid_t visual_id
)
133 ANV_FROM_HANDLE(anv_physical_device
, device
, physicalDevice
);
135 struct wsi_x11_connection
*wsi_conn
=
136 wsi_x11_get_connection(device
->instance
, connection
);
138 if (!wsi_conn
->has_dri3
) {
139 fprintf(stderr
, "vulkan: No DRI3 support\n");
143 anv_finishme("Check visuals");
149 x11_surface_get_support(VkIcdSurfaceBase
*icd_surface
,
150 struct anv_physical_device
*device
,
151 uint32_t queueFamilyIndex
,
152 VkBool32
* pSupported
)
154 VkIcdSurfaceXcb
*surface
= (VkIcdSurfaceXcb
*)icd_surface
;
156 struct wsi_x11_connection
*wsi_conn
=
157 wsi_x11_get_connection(device
->instance
, surface
->connection
);
159 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
161 if (!wsi_conn
->has_dri3
) {
162 fprintf(stderr
, "vulkan: No DRI3 support\n");
172 x11_surface_get_capabilities(VkIcdSurfaceBase
*icd_surface
,
173 struct anv_physical_device
*device
,
174 VkSurfaceCapabilitiesKHR
*caps
)
176 VkIcdSurfaceXcb
*surface
= (VkIcdSurfaceXcb
*)icd_surface
;
178 xcb_get_geometry_cookie_t cookie
= xcb_get_geometry(surface
->connection
,
180 xcb_generic_error_t
*err
;
181 xcb_get_geometry_reply_t
*geom
= xcb_get_geometry_reply(surface
->connection
,
184 VkExtent2D extent
= { geom
->width
, geom
->height
};
185 caps
->currentExtent
= extent
;
186 caps
->minImageExtent
= extent
;
187 caps
->maxImageExtent
= extent
;
189 /* This can happen if the client didn't wait for the configure event
190 * to come back from the compositor. In that case, we don't know the
191 * size of the window so we just return valid "I don't know" stuff.
193 caps
->currentExtent
= (VkExtent2D
) { -1, -1 };
194 caps
->minImageExtent
= (VkExtent2D
) { 1, 1 };
195 caps
->maxImageExtent
= (VkExtent2D
) { INT16_MAX
, INT16_MAX
};
200 caps
->minImageCount
= 2;
201 caps
->maxImageCount
= 4;
202 caps
->supportedTransforms
= VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
;
203 caps
->currentTransform
= VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
;
204 caps
->maxImageArrayLayers
= 1;
205 caps
->supportedCompositeAlpha
= VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
;
206 caps
->supportedUsageFlags
=
207 VK_IMAGE_USAGE_TRANSFER_SRC_BIT
|
208 VK_IMAGE_USAGE_SAMPLED_BIT
|
209 VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
210 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
;
216 x11_surface_get_formats(VkIcdSurfaceBase
*surface
,
217 struct anv_physical_device
*device
,
218 uint32_t *pSurfaceFormatCount
,
219 VkSurfaceFormatKHR
*pSurfaceFormats
)
221 if (pSurfaceFormats
== NULL
) {
222 *pSurfaceFormatCount
= ARRAY_SIZE(formats
);
226 assert(*pSurfaceFormatCount
>= ARRAY_SIZE(formats
));
227 typed_memcpy(pSurfaceFormats
, formats
, *pSurfaceFormatCount
);
228 *pSurfaceFormatCount
= ARRAY_SIZE(formats
);
234 x11_surface_get_present_modes(VkIcdSurfaceBase
*surface
,
235 struct anv_physical_device
*device
,
236 uint32_t *pPresentModeCount
,
237 VkPresentModeKHR
*pPresentModes
)
239 if (pPresentModes
== NULL
) {
240 *pPresentModeCount
= ARRAY_SIZE(present_modes
);
244 assert(*pPresentModeCount
>= ARRAY_SIZE(present_modes
));
245 typed_memcpy(pPresentModes
, present_modes
, *pPresentModeCount
);
246 *pPresentModeCount
= ARRAY_SIZE(present_modes
);
252 x11_surface_create_swapchain(VkIcdSurfaceBase
*surface
,
253 struct anv_device
*device
,
254 const VkSwapchainCreateInfoKHR
* pCreateInfo
,
255 const VkAllocationCallbacks
* pAllocator
,
256 struct anv_swapchain
**swapchain
);
258 VkResult
anv_CreateXcbSurfaceKHR(
259 VkInstance _instance
,
260 const VkXcbSurfaceCreateInfoKHR
* pCreateInfo
,
261 const VkAllocationCallbacks
* pAllocator
,
262 VkSurfaceKHR
* pSurface
)
264 ANV_FROM_HANDLE(anv_instance
, instance
, _instance
);
266 assert(pCreateInfo
->sType
== VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR
);
268 VkIcdSurfaceXcb
*surface
;
270 surface
= anv_alloc2(&instance
->alloc
, pAllocator
, sizeof *surface
, 8,
271 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
273 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
275 surface
->connection
= pCreateInfo
->connection
;
276 surface
->window
= pCreateInfo
->window
;
278 *pSurface
= _VkIcdSurfaceBase_to_handle(&surface
->base
);
284 struct anv_image
* image
;
285 struct anv_device_memory
* memory
;
287 xcb_get_geometry_cookie_t geom_cookie
;
291 struct x11_swapchain
{
292 struct anv_swapchain base
;
294 xcb_connection_t
* conn
;
298 uint32_t image_count
;
300 struct x11_image images
[0];
304 x11_get_images(struct anv_swapchain
*anv_chain
,
305 uint32_t* pCount
, VkImage
*pSwapchainImages
)
307 struct x11_swapchain
*chain
= (struct x11_swapchain
*)anv_chain
;
309 if (pSwapchainImages
== NULL
) {
310 *pCount
= chain
->image_count
;
314 assert(chain
->image_count
<= *pCount
);
315 for (uint32_t i
= 0; i
< chain
->image_count
; i
++)
316 pSwapchainImages
[i
] = anv_image_to_handle(chain
->images
[i
].image
);
318 *pCount
= chain
->image_count
;
324 x11_acquire_next_image(struct anv_swapchain
*anv_chain
,
326 VkSemaphore semaphore
,
327 uint32_t *image_index
)
329 struct x11_swapchain
*chain
= (struct x11_swapchain
*)anv_chain
;
330 struct x11_image
*image
= &chain
->images
[chain
->next_image
];
333 xcb_generic_error_t
*err
;
334 xcb_get_geometry_reply_t
*geom
=
335 xcb_get_geometry_reply(chain
->conn
, image
->geom_cookie
, &err
);
338 return vk_error(VK_ERROR_OUT_OF_DATE_KHR
);
341 if (geom
->width
!= chain
->extent
.width
||
342 geom
->height
!= chain
->extent
.height
) {
344 return vk_error(VK_ERROR_OUT_OF_DATE_KHR
);
351 *image_index
= chain
->next_image
;
352 chain
->next_image
= (chain
->next_image
+ 1) % chain
->image_count
;
357 x11_queue_present(struct anv_swapchain
*anv_chain
,
358 struct anv_queue
*queue
,
359 uint32_t image_index
)
361 struct x11_swapchain
*chain
= (struct x11_swapchain
*)anv_chain
;
362 struct x11_image
*image
= &chain
->images
[image_index
];
364 assert(image_index
< chain
->image_count
);
366 xcb_void_cookie_t cookie
;
368 cookie
= xcb_copy_area(chain
->conn
,
375 chain
->extent
.height
);
376 xcb_discard_reply(chain
->conn
, cookie
.sequence
);
378 image
->geom_cookie
= xcb_get_geometry(chain
->conn
, chain
->window
);
381 xcb_flush(chain
->conn
);
387 x11_swapchain_destroy(struct anv_swapchain
*anv_chain
,
388 const VkAllocationCallbacks
*pAllocator
)
390 struct x11_swapchain
*chain
= (struct x11_swapchain
*)anv_chain
;
391 xcb_void_cookie_t cookie
;
393 for (uint32_t i
= 0; i
< chain
->image_count
; i
++) {
394 struct x11_image
*image
= &chain
->images
[i
];
397 xcb_discard_reply(chain
->conn
, image
->geom_cookie
.sequence
);
399 cookie
= xcb_free_pixmap(chain
->conn
, image
->pixmap
);
400 xcb_discard_reply(chain
->conn
, cookie
.sequence
);
402 /* TODO: Delete images and free memory */
405 anv_free(NULL
/* XXX: pAllocator */, chain
);
411 x11_surface_create_swapchain(VkIcdSurfaceBase
*icd_surface
,
412 struct anv_device
*device
,
413 const VkSwapchainCreateInfoKHR
*pCreateInfo
,
414 const VkAllocationCallbacks
* pAllocator
,
415 struct anv_swapchain
**swapchain_out
)
417 VkIcdSurfaceXcb
*surface
= (VkIcdSurfaceXcb
*)icd_surface
;
418 struct x11_swapchain
*chain
;
419 xcb_void_cookie_t cookie
;
422 int num_images
= pCreateInfo
->minImageCount
;
424 assert(pCreateInfo
->sType
== VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
);
426 size_t size
= sizeof(*chain
) + num_images
* sizeof(chain
->images
[0]);
427 chain
= anv_alloc2(&device
->alloc
, pAllocator
, size
, 8,
428 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
430 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
432 chain
->base
.device
= device
;
433 chain
->base
.destroy
= x11_swapchain_destroy
;
434 chain
->base
.get_images
= x11_get_images
;
435 chain
->base
.acquire_next_image
= x11_acquire_next_image
;
436 chain
->base
.queue_present
= x11_queue_present
;
438 chain
->conn
= surface
->connection
;
439 chain
->window
= surface
->window
;
440 chain
->extent
= pCreateInfo
->imageExtent
;
441 chain
->image_count
= num_images
;
442 chain
->next_image
= 0;
444 for (uint32_t i
= 0; i
< chain
->image_count
; i
++) {
445 VkDeviceMemory memory_h
;
447 struct anv_image
*image
;
448 struct anv_surface
*surface
;
449 struct anv_device_memory
*memory
;
451 anv_image_create(anv_device_to_handle(device
),
452 &(struct anv_image_create_info
) {
453 .isl_tiling_flags
= ISL_TILING_X_BIT
,
456 &(VkImageCreateInfo
) {
457 .sType
= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
,
458 .imageType
= VK_IMAGE_TYPE_2D
,
459 .format
= pCreateInfo
->imageFormat
,
461 .width
= pCreateInfo
->imageExtent
.width
,
462 .height
= pCreateInfo
->imageExtent
.height
,
468 /* FIXME: Need a way to use X tiling to allow scanout */
469 .tiling
= VK_IMAGE_TILING_OPTIMAL
,
470 .usage
= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
,
476 image
= anv_image_from_handle(image_h
);
477 assert(anv_format_is_color(image
->format
));
479 surface
= &image
->color_surface
;
481 anv_AllocateMemory(anv_device_to_handle(device
),
482 &(VkMemoryAllocateInfo
) {
483 .sType
= VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
,
484 .allocationSize
= image
->size
,
485 .memoryTypeIndex
= 0,
487 NULL
/* XXX: pAllocator */,
490 memory
= anv_device_memory_from_handle(memory_h
);
492 anv_BindImageMemory(VK_NULL_HANDLE
, anv_image_to_handle(image
),
495 int ret
= anv_gem_set_tiling(device
, memory
->bo
.gem_handle
,
496 surface
->isl
.row_pitch
, I915_TILING_X
);
498 /* FINISHME: Choose a better error. */
499 result
= vk_errorf(VK_ERROR_OUT_OF_DEVICE_MEMORY
,
500 "set_tiling failed: %m");
504 int fd
= anv_gem_handle_to_fd(device
, memory
->bo
.gem_handle
);
506 /* FINISHME: Choose a better error. */
507 result
= vk_errorf(VK_ERROR_OUT_OF_DEVICE_MEMORY
,
508 "handle_to_fd failed: %m");
514 xcb_pixmap_t pixmap
= xcb_generate_id(chain
->conn
);
517 xcb_dri3_pixmap_from_buffer_checked(chain
->conn
,
521 pCreateInfo
->imageExtent
.width
,
522 pCreateInfo
->imageExtent
.height
,
523 surface
->isl
.row_pitch
,
526 chain
->images
[i
].image
= image
;
527 chain
->images
[i
].memory
= memory
;
528 chain
->images
[i
].pixmap
= pixmap
;
529 chain
->images
[i
].busy
= false;
531 xcb_discard_reply(chain
->conn
, cookie
.sequence
);
534 chain
->gc
= xcb_generate_id(chain
->conn
);
536 /* FINISHME: Choose a better error. */
537 result
= vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
541 cookie
= xcb_create_gc(chain
->conn
,
544 XCB_GC_GRAPHICS_EXPOSURES
,
545 (uint32_t []) { 0 });
546 xcb_discard_reply(chain
->conn
, cookie
.sequence
);
548 *swapchain_out
= &chain
->base
;
557 anv_x11_init_wsi(struct anv_instance
*instance
)
562 wsi
= anv_alloc(&instance
->alloc
, sizeof(*wsi
), 8,
563 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
);
565 result
= vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
569 int ret
= pthread_mutex_init(&wsi
->mutex
, NULL
);
572 result
= vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
574 /* FINISHME: Choose a better error. */
575 result
= vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
581 wsi
->connections
= _mesa_hash_table_create(NULL
, _mesa_hash_pointer
,
582 _mesa_key_pointer_equal
);
583 if (!wsi
->connections
) {
584 result
= vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
588 wsi
->base
.get_support
= x11_surface_get_support
;
589 wsi
->base
.get_capabilities
= x11_surface_get_capabilities
;
590 wsi
->base
.get_formats
= x11_surface_get_formats
;
591 wsi
->base
.get_present_modes
= x11_surface_get_present_modes
;
592 wsi
->base
.create_swapchain
= x11_surface_create_swapchain
;
594 instance
->wsi
[VK_ICD_WSI_PLATFORM_XCB
] = &wsi
->base
;
599 pthread_mutex_destroy(&wsi
->mutex
);
601 anv_free(&instance
->alloc
, wsi
);
603 instance
->wsi
[VK_ICD_WSI_PLATFORM_XCB
] = NULL
;
609 anv_x11_finish_wsi(struct anv_instance
*instance
)
611 struct wsi_x11
*wsi
=
612 (struct wsi_x11
*)instance
->wsi
[VK_ICD_WSI_PLATFORM_XCB
];
615 _mesa_hash_table_destroy(wsi
->connections
, NULL
);
617 pthread_mutex_destroy(&wsi
->mutex
);
619 anv_free(&instance
->alloc
, wsi
);