2 * Copyright 2017 Jacob Lifshay
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 #ifdef VK_USE_PLATFORM_XCB_KHR
27 #include <sys/types.h>
31 #include <xcb/present.h>
42 #include "util/optional.h"
43 #include "util/circular_queue.h"
49 struct Xcb_wsi::Implementation
51 static constexpr std::size_t max_swapchain_image_count
= 16;
52 static std::uint32_t u32_from_bytes(std::uint8_t b0
,
55 std::uint8_t b3
) noexcept
57 static_assert(sizeof(std::uint8_t) == 1 && sizeof(std::uint32_t) == 4, "");
60 std::uint8_t bytes
[4];
69 template <typename T
= void>
72 void operator()(T
*p
) noexcept
77 typedef std::unique_ptr
<xcb_query_extension_reply_t
, Free_functor
<xcb_query_extension_reply_t
>>
78 Query_extension_reply
;
79 typedef std::unique_ptr
<xcb_get_geometry_reply_t
, Free_functor
<xcb_get_geometry_reply_t
>>
81 typedef std::unique_ptr
<xcb_get_window_attributes_reply_t
,
82 Free_functor
<xcb_get_window_attributes_reply_t
>>
83 Get_window_attributes_reply
;
84 typedef std::unique_ptr
<xcb_query_tree_reply_t
, Free_functor
<xcb_query_tree_reply_t
>>
86 typedef std::unique_ptr
<xcb_shm_query_version_reply_t
,
87 Free_functor
<xcb_shm_query_version_reply_t
>> Shm_query_version_reply
;
88 typedef std::unique_ptr
<xcb_generic_error_t
, Free_functor
<xcb_generic_error_t
>> Generic_error
;
89 template <typename Id_type
,
90 xcb_void_cookie_t (*free_function
)(xcb_connection_t
*connection
, Id_type id
)>
95 xcb_connection_t
*connection
;
98 constexpr Server_object() noexcept
: value(), connection()
101 constexpr Server_object(std::nullptr_t
) noexcept
: value(), connection()
104 constexpr Server_object(Id_type value
, xcb_connection_t
*connection
) noexcept
106 connection(connection
)
110 void swap(Server_object
&other
) noexcept
113 swap(value
, other
.value
);
114 swap(connection
, other
.connection
);
116 Server_object(Server_object
&&rt
) noexcept
: value(), connection()
120 Server_object
&operator=(Server_object rt
) noexcept
125 ~Server_object() noexcept
128 free_function(connection
, value
);
130 Id_type
get() const noexcept
135 typedef Server_object
<xcb_gcontext_t
, &xcb_free_gc
> Gc
;
136 typedef Server_object
<xcb_pixmap_t
, &xcb_free_pixmap
> Pixmap
;
137 typedef Server_object
<xcb_shm_seg_t
, &xcb_shm_detach
> Server_shm_seg
;
138 class Shared_memory_segment
144 constexpr Shared_memory_segment() noexcept
: value(-1)
147 constexpr Shared_memory_segment(std::nullptr_t
) noexcept
: Shared_memory_segment()
150 explicit Shared_memory_segment(int value
) noexcept
: value(value
)
153 static Shared_memory_segment
create(std::size_t size
, int flags
= IPC_CREAT
| 0777)
155 Shared_memory_segment
retval(shmget(IPC_PRIVATE
, size
, flags
));
157 throw std::runtime_error("shmget failed");
160 void swap(Shared_memory_segment
&other
) noexcept
163 swap(value
, other
.value
);
165 Shared_memory_segment(Shared_memory_segment
&&rt
) noexcept
: Shared_memory_segment()
169 Shared_memory_segment
&operator=(Shared_memory_segment rt
) noexcept
174 ~Shared_memory_segment() noexcept
177 shmctl(value
, IPC_RMID
, nullptr);
179 explicit operator bool() const noexcept
183 std::shared_ptr
<void> map()
186 void *memory
= shmat(value
, nullptr, 0);
187 if(memory
== reinterpret_cast<void *>(-1))
188 throw std::runtime_error("shmat failed");
189 return std::shared_ptr
<void>(memory
,
190 [](void *memory
) noexcept
195 int get() const noexcept
200 static xcb_query_extension_cookie_t
query_extension(xcb_connection_t
*connection
,
201 const char *extension_name
) noexcept
203 return xcb_query_extension(connection
, std::strlen(extension_name
), extension_name
);
205 enum class Surface_format_group
209 struct Start_setup_results
219 bool shm_is_supported
;
220 unsigned window_depth
;
221 std::uint32_t image_width
;
222 std::uint32_t image_height
;
223 Surface_format_group surface_format_group
;
224 util::optional
<std::vector
<VkPresentModeKHR
>> present_modes
;
225 VkSurfaceCapabilitiesKHR capabilities
;
226 std::size_t image_pixel_size
;
227 std::size_t scanline_alignment
;
228 xcb_shm_query_version_cookie_t shm_query_version_cookie
;
229 vulkan::Vulkan_image_descriptor image_descriptor
;
230 Start_setup_results(Gc gc
,
231 bool shm_is_supported
,
232 unsigned window_depth
,
233 std::uint32_t image_width
,
234 std::uint32_t image_height
,
235 Surface_format_group surface_format_group
,
236 std::vector
<VkPresentModeKHR
> present_modes
,
237 const VkSurfaceCapabilitiesKHR
&capabilities
,
238 std::size_t image_pixel_size
,
239 std::size_t scanline_alignment
,
240 xcb_shm_query_version_cookie_t shm_query_version_cookie
,
241 const vulkan::Vulkan_image_descriptor
&image_descriptor
) noexcept
242 : status(Status::Success
),
244 shm_is_supported(shm_is_supported
),
245 window_depth(window_depth
),
246 image_width(image_width
),
247 image_height(image_height
),
248 surface_format_group(surface_format_group
),
249 present_modes(std::move(present_modes
)),
250 capabilities(capabilities
),
251 image_pixel_size(image_pixel_size
),
252 scanline_alignment(scanline_alignment
),
253 shm_query_version_cookie(shm_query_version_cookie
),
254 image_descriptor(image_descriptor
)
257 constexpr Start_setup_results(Status status
) noexcept
: status(status
),
263 surface_format_group(),
267 scanline_alignment(),
268 shm_query_version_cookie(),
271 assert(status
!= Status::Success
);
274 static Start_setup_results
start_setup(xcb_connection_t
*connection
,
278 auto mit_shm_cookie
= query_extension(connection
, "MIT-SHM");
279 auto get_geometry_cookie
= xcb_get_geometry(connection
, window
);
280 auto get_window_attributes_cookie
= xcb_get_window_attributes(connection
, window
);
281 auto query_tree_cookie
= xcb_query_tree(connection
, window
);
282 auto gc_id
= xcb_generate_id(connection
);
283 const std::uint32_t gc_params
[1] = {
284 0, // value for XCB_GC_GRAPHICS_EXPOSURES
286 xcb_create_gc(connection
, gc_id
, window
, XCB_GC_GRAPHICS_EXPOSURES
, gc_params
);
287 auto gc
= Gc(gc_id
, connection
);
289 Query_extension_reply(xcb_query_extension_reply(connection
, mit_shm_cookie
, nullptr));
290 bool shm_is_supported
= mit_shm_reply
&& mit_shm_reply
->present
;
291 xcb_shm_query_version_cookie_t shm_query_version_cookie
{};
292 if(shm_is_supported
&& is_full_setup
)
293 shm_query_version_cookie
= xcb_shm_query_version(connection
);
294 auto get_geometry_reply
=
295 Get_geometry_reply(xcb_get_geometry_reply(connection
, get_geometry_cookie
, nullptr));
296 if(!get_geometry_reply
)
297 return Start_setup_results::Status::Bad_surface
;
298 std::uint32_t image_width
= get_geometry_reply
->width
;
299 std::uint32_t image_height
= get_geometry_reply
->height
;
300 auto get_window_attributes_reply
= Get_window_attributes_reply(
301 xcb_get_window_attributes_reply(connection
, get_window_attributes_cookie
, nullptr));
302 if(!get_window_attributes_reply
)
303 return Start_setup_results::Status::Bad_surface
;
304 auto window_visual_id
= get_window_attributes_reply
->visual
;
305 auto query_tree_reply
=
306 Query_tree_reply(xcb_query_tree_reply(connection
, query_tree_cookie
, nullptr));
307 if(!query_tree_reply
)
308 return Start_setup_results::Status::Bad_surface
;
309 auto root_window
= query_tree_reply
->root
;
310 xcb_screen_t
*screen
= nullptr;
311 for(auto iter
= xcb_setup_roots_iterator(xcb_get_setup(connection
)); iter
.rem
;
312 xcb_screen_next(&iter
))
314 if(iter
.data
->root
== root_window
)
321 return Start_setup_results::Status::Bad_surface
;
322 xcb_visualtype_t
*window_visual_type
= nullptr;
323 unsigned window_depth
= 0;
324 for(auto depth_iter
= xcb_screen_allowed_depths_iterator(screen
); depth_iter
.rem
;
325 xcb_depth_next(&depth_iter
))
327 for(auto visual_iter
= xcb_depth_visuals_iterator(depth_iter
.data
); visual_iter
.rem
;
328 xcb_visualtype_next(&visual_iter
))
330 if(visual_iter
.data
->visual_id
== window_visual_id
)
332 window_visual_type
= visual_iter
.data
;
333 window_depth
= depth_iter
.data
->depth
;
337 if(window_visual_type
)
340 if(!window_visual_type
)
341 return Start_setup_results::Status::Bad_surface
;
342 std::uint32_t red_mask
= window_visual_type
->red_mask
;
343 std::uint32_t green_mask
= window_visual_type
->green_mask
;
344 std::uint32_t blue_mask
= window_visual_type
->blue_mask
;
345 std::uint32_t alpha_mask
;
352 alpha_mask
= ~(red_mask
| green_mask
| blue_mask
);
355 return Start_setup_results::Status::No_support
;
357 xcb_format_t
*window_pixmap_format
= nullptr;
358 for(auto iter
= xcb_setup_pixmap_formats_iterator(xcb_get_setup(connection
)); iter
.rem
;
359 xcb_format_next(&iter
))
361 if(iter
.data
->depth
== window_depth
)
363 window_pixmap_format
= iter
.data
;
367 if(!window_pixmap_format
)
368 return Start_setup_results::Status::Bad_surface
;
369 std::size_t image_pixel_size
;
370 switch(window_pixmap_format
->bits_per_pixel
)
373 image_pixel_size
= 3;
376 image_pixel_size
= 4;
379 return Start_setup_results::Status::No_support
;
381 Surface_format_group surface_format_group
;
382 if(red_mask
== u32_from_bytes(0, 0, 0xFF, 0) && green_mask
== u32_from_bytes(0, 0xFF, 0, 0)
383 && blue_mask
== u32_from_bytes(0xFF, 0, 0, 0)
384 && (alpha_mask
== 0 || alpha_mask
== u32_from_bytes(0, 0, 0, 0xFF))
385 && image_pixel_size
== 4)
386 surface_format_group
= Surface_format_group::B8G8R8A8
;
388 return Start_setup_results::Status::No_support
;
389 std::size_t scanline_alignment
= 1;
390 switch(window_pixmap_format
->scanline_pad
)
393 scanline_alignment
= 1;
396 scanline_alignment
= 2;
399 scanline_alignment
= 4;
402 assert(!"invalid pixmap format scanline-pad");
404 std::vector
<VkPresentModeKHR
> present_modes
= {
405 #warning properly implement fifo present mode using X11 Present extension
406 VK_PRESENT_MODE_FIFO_KHR
, VK_PRESENT_MODE_IMMEDIATE_KHR
,
408 VkSurfaceCapabilitiesKHR capabilities
= {
410 .maxImageCount
= max_swapchain_image_count
,
413 .width
= image_width
, .height
= image_height
,
417 .width
= image_width
, .height
= image_height
,
421 .width
= image_width
, .height
= image_height
,
423 .maxImageArrayLayers
= 1,
424 .supportedTransforms
= VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
,
425 .currentTransform
= VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
,
426 .supportedCompositeAlpha
= VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
,
427 .supportedUsageFlags
= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
428 | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT
429 | VK_IMAGE_USAGE_SAMPLED_BIT
430 | VK_IMAGE_USAGE_STORAGE_BIT
431 | VK_IMAGE_USAGE_TRANSFER_DST_BIT
432 | VK_IMAGE_USAGE_TRANSFER_SRC_BIT
,
434 return Start_setup_results(std::move(gc
),
439 surface_format_group
,
444 shm_query_version_cookie
,
445 vulkan::Vulkan_image_descriptor(
450 .width
= image_width
, .height
= image_height
, .depth
= 1,
454 VK_SAMPLE_COUNT_1_BIT
,
455 VK_IMAGE_TILING_OPTIMAL
));
457 struct Swapchain final
: public Vulkan_swapchain
459 enum class Image_owner
472 struct Swapchain_image final
: public vulkan::Vulkan_image
474 Shared_memory_segment shared_memory_segment
;
475 Server_shm_seg server_shm_seg
;
478 xcb_get_geometry_cookie_t get_geometry_cookie
{};
479 Swapchain_image(const vulkan::Vulkan_image_descriptor
&descriptor
,
480 std::shared_ptr
<void> pixels
,
481 Shared_memory_segment shared_memory_segment
,
482 Server_shm_seg server_shm_seg
,
483 Pixmap pixmap
) noexcept
484 : Vulkan_image(descriptor
, std::move(pixels
)),
485 shared_memory_segment(std::move(shared_memory_segment
)),
486 server_shm_seg(std::move(server_shm_seg
)),
487 pixmap(std::move(pixmap
)),
488 owner(Image_owner::Swapchain
)
492 Swapchain_image
&get_image(std::size_t index
) noexcept
494 assert(index
< images
.size());
495 assert(dynamic_cast<Swapchain_image
*>(images
[index
].get()));
496 return *static_cast<Swapchain_image
*>(images
[index
].get());
498 xcb_connection_t
*connection
;
500 bool shm_is_supported
;
502 util::Static_circular_deque
<std::size_t, max_swapchain_image_count
> presenting_image_queue
;
503 std::uint32_t swapchain_width
;
504 std::uint32_t swapchain_height
;
506 unsigned window_depth
;
507 explicit Swapchain(Start_setup_results start_setup_results
,
508 xcb_connection_t
*connection
,
510 const VkSwapchainCreateInfoKHR
&create_info
)
511 : Vulkan_swapchain({}),
512 connection(connection
),
514 shm_is_supported(start_setup_results
.shm_is_supported
),
515 status(Status::Good
),
516 presenting_image_queue(),
517 gc(std::move(start_setup_results
.gc
)),
518 window_depth(start_setup_results
.window_depth
)
520 assert(create_info
.sType
== VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
);
521 #warning formats other than VK_FORMAT_B8G8R8A8_UNORM are unimplemented
522 assert(create_info
.imageFormat
== VK_FORMAT_B8G8R8A8_UNORM
);
523 assert(create_info
.imageColorSpace
== VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
);
524 assert(create_info
.imageArrayLayers
525 <= start_setup_results
.capabilities
.maxImageArrayLayers
);
526 assert(create_info
.imageArrayLayers
!= 0);
527 assert((create_info
.imageUsage
& ~start_setup_results
.capabilities
.supportedUsageFlags
)
529 assert(create_info
.preTransform
== start_setup_results
.capabilities
.currentTransform
);
530 assert((create_info
.compositeAlpha
531 & ~start_setup_results
.capabilities
.supportedCompositeAlpha
)
533 switch(start_setup_results
.status
)
535 case Start_setup_results::Status::Bad_surface
:
536 case Start_setup_results::Status::No_support
:
537 status
= Status::Setup_failed
;
539 case Start_setup_results::Status::Success
:
542 if(start_setup_results
.image_width
!= create_info
.imageExtent
.width
543 || start_setup_results
.image_height
!= create_info
.imageExtent
.height
)
545 status
= Status::Out_of_date
;
547 start_setup_results
.image_descriptor
.format
= create_info
.imageFormat
;
548 swapchain_width
= start_setup_results
.image_width
;
549 swapchain_height
= start_setup_results
.image_height
;
550 const char *warning_message_present_mode_name
= nullptr;
551 switch(create_info
.presentMode
)
553 case VK_PRESENT_MODE_IMMEDIATE_KHR
:
555 case VK_PRESENT_MODE_FIFO_KHR
:
557 static std::atomic_bool
wrote_warning_message(false);
558 if(!wrote_warning_message
.exchange(true, std::memory_order_relaxed
))
559 warning_message_present_mode_name
= "FIFO";
562 case VK_PRESENT_MODE_MAILBOX_KHR
:
564 static std::atomic_bool
wrote_warning_message(false);
565 if(!wrote_warning_message
.exchange(true, std::memory_order_relaxed
))
566 warning_message_present_mode_name
= "MAILBOX";
569 case VK_PRESENT_MODE_FIFO_RELAXED_KHR
:
571 static std::atomic_bool
wrote_warning_message(false);
572 if(!wrote_warning_message
.exchange(true, std::memory_order_relaxed
))
573 warning_message_present_mode_name
= "FIFO_RELAXED";
576 case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR
:
577 case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR
:
578 case VK_PRESENT_MODE_RANGE_SIZE_KHR
:
579 case VK_PRESENT_MODE_MAX_ENUM_KHR
:
580 assert(!"bad present mode");
583 if(warning_message_present_mode_name
)
584 std::cerr
<< warning_message_present_mode_name
585 << " present mode is not implemented; falling back to IMMEDIATE"
587 std::size_t unpadded_scanline_size
=
588 start_setup_results
.image_pixel_size
* start_setup_results
.image_width
;
589 std::size_t padded_scanline_size
=
590 (unpadded_scanline_size
+ start_setup_results
.scanline_alignment
- 1U)
591 & ~(start_setup_results
.scanline_alignment
- 1U);
592 std::size_t image_size
= padded_scanline_size
* start_setup_results
.image_height
;
595 auto shm_query_version_reply
= Shm_query_version_reply(xcb_shm_query_version_reply(
596 connection
, start_setup_results
.shm_query_version_cookie
, nullptr));
597 if(!shm_query_version_reply
|| !shm_query_version_reply
->shared_pixmaps
598 || shm_query_version_reply
->pixmap_format
!= XCB_IMAGE_FORMAT_Z_PIXMAP
)
601 << "shared memory pixmaps are not supported, falling back to using core "
604 shm_is_supported
= false;
607 auto image_count
= std::max
<std::uint32_t>(create_info
.minImageCount
, 2);
610 bool shm_failed
= false;
611 for(std::uint32_t i
= 0; i
< image_count
; i
++)
613 Shared_memory_segment shared_memory_segment
;
614 std::shared_ptr
<void> pixels
;
615 Server_shm_seg server_shm_seg
;
619 shared_memory_segment
= Shared_memory_segment::create(image_size
);
620 pixels
= shared_memory_segment
.map();
621 auto seg_id
= xcb_generate_id(connection
);
622 auto shm_attach_cookie
= xcb_shm_attach_checked(
623 connection
, seg_id
, shared_memory_segment
.get(), false);
625 Generic_error(xcb_request_check(connection
, shm_attach_cookie
));
631 server_shm_seg
= Server_shm_seg(seg_id
, connection
);
632 auto pixmap_id
= xcb_generate_id(connection
);
633 error
= Generic_error(xcb_request_check(
635 xcb_shm_create_pixmap_checked(connection
,
638 start_setup_results
.image_width
,
639 start_setup_results
.image_height
,
640 start_setup_results
.window_depth
,
641 server_shm_seg
.get(),
648 pixmap
= Pixmap(pixmap_id
, connection
);
652 pixels
= std::shared_ptr
<unsigned char>(new unsigned char[image_size
],
653 [](unsigned char *p
) noexcept
659 std::make_unique
<Swapchain_image
>(start_setup_results
.image_descriptor
,
661 std::move(shared_memory_segment
),
662 std::move(server_shm_seg
),
667 std::cerr
<< "using shared memory failed, falling back to using core X protocol"
669 shm_is_supported
= false;
676 virtual VkResult
acquire_next_image(std::uint64_t timeout
,
677 vulkan::Vulkan_semaphore
*semaphore
,
678 vulkan::Vulkan_fence
*fence
,
679 std::uint32_t &returned_image_index
) override
681 #warning figure out how to use timeouts with xcb blocking for X server responses
684 case Status::No_surface
:
685 case Status::Setup_failed
:
686 return VK_ERROR_SURFACE_LOST_KHR
;
687 case Status::Out_of_date
:
688 return VK_ERROR_OUT_OF_DATE_KHR
;
694 for(std::size_t i
= 0; i
< images
.size(); i
++)
696 auto &image
= get_image(i
);
697 if(image
.owner
== Image_owner::Swapchain
)
699 image
.owner
= Image_owner::Application
;
700 returned_image_index
= i
;
708 if(presenting_image_queue
.empty())
710 std::cerr
<< "vkAcquireNextImageKHR called when application has already "
711 "acquired all swapchain images; aborting"
715 assert(shm_is_supported
);
716 std::size_t image_index
= presenting_image_queue
.front();
717 presenting_image_queue
.pop_front();
718 auto &image
= get_image(image_index
);
719 // wait for the presentation request to finish
720 // we use a xcb_get_geometry command after the xcb_copy_area command, so we can wait
721 // on the xcb_get_geometry command since the X server processes commands in order
722 auto get_geometry_reply
= Get_geometry_reply(
723 xcb_get_geometry_reply(connection
, image
.get_geometry_cookie
, nullptr));
724 image
.owner
= Image_owner::Swapchain
;
725 if(!get_geometry_reply
)
727 status
= Status::No_surface
;
728 return VK_ERROR_SURFACE_LOST_KHR
;
730 if(get_geometry_reply
->width
!= swapchain_width
731 || get_geometry_reply
->height
!= swapchain_height
)
733 status
= Status::Out_of_date
;
734 return VK_ERROR_OUT_OF_DATE_KHR
;
736 image
.owner
= Image_owner::Application
;
737 returned_image_index
= image_index
;
745 virtual VkResult
queue_present(std::uint32_t image_index
,
746 vulkan::Vulkan_device::Queue
&queue
) override
748 assert(image_index
< images
.size());
751 case Status::No_surface
:
752 case Status::Setup_failed
:
753 return VK_ERROR_SURFACE_LOST_KHR
;
754 case Status::Out_of_date
:
755 return VK_ERROR_OUT_OF_DATE_KHR
;
759 auto &image
= get_image(image_index
);
760 assert(image
.owner
== Image_owner::Application
);
761 // wait for rendering to catch up
763 vulkan::Vulkan_fence
fence(0);
764 queue
.queue_fence_signal(fence
);
770 xcb_copy_area(connection
,
783 std::size_t image_size
= image
.descriptor
.get_memory_properties().size
;
784 assert(static_cast<std::uint32_t>(image_size
) == image_size
);
785 xcb_put_image(connection
,
786 XCB_IMAGE_FORMAT_Z_PIXMAP
,
796 static_cast<const std::uint8_t *>(image
.memory
.get()));
798 image
.get_geometry_cookie
= xcb_get_geometry(connection
, window
);
799 image
.owner
= Image_owner::Presentation_engine
;
800 presenting_image_queue
.push_back(image_index
);
801 xcb_flush(connection
);
807 VkIcdSurfaceBase
*Xcb_wsi::create_surface(const VkXcbSurfaceCreateInfoKHR
&create_info
) const
809 assert(create_info
.sType
== VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR
);
810 assert(create_info
.flags
== 0);
811 return reinterpret_cast<VkIcdSurfaceBase
*>(new Surface_type
{
814 .platform
= VK_ICD_WSI_PLATFORM_XCB
,
816 .connection
= create_info
.connection
,
817 .window
= create_info
.window
,
821 void Xcb_wsi::destroy_surface(VkIcdSurfaceBase
*surface
) const noexcept
823 delete reinterpret_cast<Surface_type
*>(surface
);
826 VkResult
Xcb_wsi::get_surface_support(VkIcdSurfaceBase
*surface_
, bool &supported
) const
828 auto &surface
= *reinterpret_cast<Surface_type
*>(surface_
);
829 switch(Implementation::start_setup(surface
.connection
, surface
.window
, false).status
)
831 case Implementation::Start_setup_results::Status::Bad_surface
:
832 return VK_ERROR_SURFACE_LOST_KHR
;
833 case Implementation::Start_setup_results::Status::No_support
:
836 case Implementation::Start_setup_results::Status::Success
:
840 assert(!"unreachable");
844 VkResult
Xcb_wsi::get_surface_formats(VkIcdSurfaceBase
*surface_
,
845 std::vector
<VkSurfaceFormatKHR
> &surface_formats
) const
847 auto &surface
= *reinterpret_cast<Surface_type
*>(surface_
);
848 auto start_setup_result
=
849 Implementation::start_setup(surface
.connection
, surface
.window
, false);
850 switch(start_setup_result
.status
)
852 case Implementation::Start_setup_results::Status::Bad_surface
:
853 case Implementation::Start_setup_results::Status::No_support
:
854 return VK_ERROR_SURFACE_LOST_KHR
;
855 case Implementation::Start_setup_results::Status::Success
:
857 surface_formats
.clear();
858 switch(start_setup_result
.surface_format_group
)
860 case Implementation::Surface_format_group::B8G8R8A8
:
864 #warning implement VK_FORMAT_B8G8R8A8_SRGB
867 .format
= VK_FORMAT_B8G8R8A8_SRGB
,
868 .colorSpace
= VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
,
872 .format
= VK_FORMAT_B8G8R8A8_UNORM
,
873 .colorSpace
= VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
,
881 assert(!"unreachable");
885 VkResult
Xcb_wsi::get_present_modes(VkIcdSurfaceBase
*surface_
,
886 std::vector
<VkPresentModeKHR
> &present_modes
) const
888 auto &surface
= *reinterpret_cast<Surface_type
*>(surface_
);
889 auto start_setup_result
=
890 Implementation::start_setup(surface
.connection
, surface
.window
, false);
891 switch(start_setup_result
.status
)
893 case Implementation::Start_setup_results::Status::Bad_surface
:
894 case Implementation::Start_setup_results::Status::No_support
:
895 return VK_ERROR_SURFACE_LOST_KHR
;
896 case Implementation::Start_setup_results::Status::Success
:
897 present_modes
= std::move(start_setup_result
.present_modes
.value());
900 assert(!"unreachable");
904 VkResult
Xcb_wsi::get_surface_capabilities(VkIcdSurfaceBase
*surface_
,
905 VkSurfaceCapabilitiesKHR
&capabilities
) const
907 auto &surface
= *reinterpret_cast<Surface_type
*>(surface_
);
908 auto start_setup_result
=
909 Implementation::start_setup(surface
.connection
, surface
.window
, false);
910 switch(start_setup_result
.status
)
912 case Implementation::Start_setup_results::Status::Bad_surface
:
913 case Implementation::Start_setup_results::Status::No_support
:
914 return VK_ERROR_SURFACE_LOST_KHR
;
915 case Implementation::Start_setup_results::Status::Success
:
916 capabilities
= start_setup_result
.capabilities
;
919 assert(!"unreachable");
923 util::variant
<VkResult
, std::unique_ptr
<Vulkan_swapchain
>> Xcb_wsi::create_swapchain(
924 vulkan::Vulkan_device
&device
, const VkSwapchainCreateInfoKHR
&create_info
) const
926 auto &surface
= *reinterpret_cast<Surface_type
*>(create_info
.surface
);
927 auto swapchain
= std::make_unique
<Implementation::Swapchain
>(
928 Implementation::start_setup(surface
.connection
, surface
.window
, true),
932 switch(swapchain
->status
)
934 case Implementation::Swapchain::Status::Setup_failed
:
935 case Implementation::Swapchain::Status::No_surface
:
936 return VK_ERROR_SURFACE_LOST_KHR
;
937 case Implementation::Swapchain::Status::Good
:
938 case Implementation::Swapchain::Status::Out_of_date
: // we'll return out of date later
939 return std::move(swapchain
);
941 assert(!"unreachable");
945 const Xcb_wsi
&Xcb_wsi::get() noexcept
947 static const Xcb_wsi retval
{};
954 #ifdef VK_USE_PLATFORM_XLIB_KHR
955 #ifndef VK_USE_PLATFORM_XCB_KHR
956 #error can't Xlib WSI interface depends on XCB WSI interface for the implementation
958 #include <X11/Xlib-xcb.h>
964 struct Xlib_wsi::Implementation : public Xcb_wsi::Implementation
966 static VkIcdSurfaceXcb get_xcb_surface(const VkIcdSurfaceXlib &surface) noexcept
968 return VkIcdSurfaceXcb{
969 .base = {.platform = VK_ICD_WSI_PLATFORM_XCB},
970 .connection = XGetXCBConnection(surface.dpy),
971 .window = static_cast<xcb_window_t>(surface.window),
976 VkIcdSurfaceBase *Xlib_wsi::create_surface(const VkXlibSurfaceCreateInfoKHR &create_info) const
978 assert(create_info.sType == VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR);
979 assert(create_info.flags == 0);
980 return reinterpret_cast<VkIcdSurfaceBase *>(new Surface_type{
983 .platform = VK_ICD_WSI_PLATFORM_XLIB,
985 .dpy = create_info.dpy,
986 .window = create_info.window,
990 void Xlib_wsi::destroy_surface(VkIcdSurfaceBase *surface) const noexcept
992 delete reinterpret_cast<Surface_type *>(surface);
995 VkResult Xlib_wsi::get_surface_support(VkIcdSurfaceBase *surface_, bool &supported) const
997 auto &surface = *reinterpret_cast<Surface_type *>(surface_);
998 auto xcb_surface = Implementation::get_xcb_surface(surface);
999 return Xcb_wsi::get().get_surface_support(reinterpret_cast<VkIcdSurfaceBase *>(&xcb_surface),
1003 VkResult Xlib_wsi::get_surface_formats(VkIcdSurfaceBase *surface_,
1004 std::vector<VkSurfaceFormatKHR> &surface_formats) const
1006 auto &surface = *reinterpret_cast<Surface_type *>(surface_);
1007 auto xcb_surface = Implementation::get_xcb_surface(surface);
1008 return Xcb_wsi::get().get_surface_formats(reinterpret_cast<VkIcdSurfaceBase *>(&xcb_surface),
1012 VkResult Xlib_wsi::get_present_modes(VkIcdSurfaceBase *surface_,
1013 std::vector<VkPresentModeKHR> &present_modes) const
1015 auto &surface = *reinterpret_cast<Surface_type *>(surface_);
1016 auto xcb_surface = Implementation::get_xcb_surface(surface);
1017 return Xcb_wsi::get().get_present_modes(reinterpret_cast<VkIcdSurfaceBase *>(&xcb_surface),
1021 VkResult Xlib_wsi::get_surface_capabilities(VkIcdSurfaceBase *surface_,
1022 VkSurfaceCapabilitiesKHR &capabilities) const
1024 auto &surface = *reinterpret_cast<Surface_type *>(surface_);
1025 auto xcb_surface = Implementation::get_xcb_surface(surface);
1026 return Xcb_wsi::get().get_surface_capabilities(
1027 reinterpret_cast<VkIcdSurfaceBase *>(&xcb_surface), capabilities);
1030 util::variant<VkResult, std::unique_ptr<Vulkan_swapchain>> Xlib_wsi::create_swapchain(
1031 vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const
1033 assert(create_info.surface);
1034 auto &surface = *reinterpret_cast<Surface_type *>(create_info.surface);
1035 auto xcb_surface = Implementation::get_xcb_surface(surface);
1036 VkSwapchainCreateInfoKHR xcb_create_info = create_info;
1037 xcb_create_info.surface = reinterpret_cast<VkSurfaceKHR>(&xcb_surface);
1038 return Xcb_wsi::get().create_swapchain(device, xcb_create_info);
1041 const Xlib_wsi &Xlib_wsi::get() noexcept
1043 static const Xlib_wsi retval{};