added buffer and image memory binding
[kazan.git] / vulkan-driver / src / xcb_swapchain.rs
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
3 use api;
4 use handle::Handle;
5 use image::{ImageMultisampleCount, ImageProperties, SupportedTilings, Tiling};
6 use libc;
7 use std::borrow::Cow;
8 use std::mem;
9 use std::ops::{Deref, DerefMut};
10 use std::os::raw::c_char;
11 use std::ptr::null_mut;
12 use std::ptr::NonNull;
13 use swapchain::{SurfaceImplementation, SurfacePlatform, Swapchain};
14 use xcb;
15
16 #[derive(Debug)]
17 pub struct XcbSwapchain {}
18
19 impl Swapchain for XcbSwapchain {}
20
21 struct ReplyObject<T>(NonNull<T>);
22
23 impl<T> ReplyObject<T> {
24 unsafe fn from(v: *mut T) -> Option<Self> {
25 NonNull::new(v).map(ReplyObject)
26 }
27 }
28
29 impl<T> Deref for ReplyObject<T> {
30 type Target = T;
31 fn deref(&self) -> &T {
32 unsafe { self.0.as_ref() }
33 }
34 }
35
36 impl<T> DerefMut for ReplyObject<T> {
37 fn deref_mut(&mut self) -> &mut T {
38 unsafe { self.0.as_mut() }
39 }
40 }
41
42 impl<T> Drop for ReplyObject<T> {
43 fn drop(&mut self) {
44 unsafe {
45 libc::free(self.0.as_ptr() as *mut libc::c_void);
46 }
47 }
48 }
49
50 struct ServerObject<Id: 'static + Copy> {
51 id: Id,
52 connection: *mut xcb::ffi::xcb_connection_t,
53 free_fn: unsafe extern "C" fn(connection: *mut xcb::ffi::xcb_connection_t, id: Id)
54 -> xcb::ffi::xcb_void_cookie_t,
55 }
56
57 impl<Id: 'static + Copy> ServerObject<Id> {
58 fn get(&self) -> Id {
59 self.id
60 }
61 }
62
63 impl<Id: 'static + Copy> Drop for ServerObject<Id> {
64 fn drop(&mut self) {
65 unsafe {
66 (self.free_fn)(self.connection, self.id);
67 }
68 }
69 }
70
71 type Gc = ServerObject<xcb::ffi::xcb_gcontext_t>;
72
73 unsafe fn create_gc(
74 id: xcb::ffi::xcb_gcontext_t,
75 connection: *mut xcb::ffi::xcb_connection_t,
76 ) -> Gc {
77 ServerObject {
78 id,
79 connection,
80 free_fn: xcb::ffi::xcb_free_gc,
81 }
82 }
83
84 type Pixmap = ServerObject<xcb::ffi::xcb_pixmap_t>;
85
86 unsafe fn create_pixmap(
87 id: xcb::ffi::xcb_pixmap_t,
88 connection: *mut xcb::ffi::xcb_connection_t,
89 ) -> Pixmap {
90 ServerObject {
91 id,
92 connection,
93 free_fn: xcb::ffi::xcb_free_pixmap,
94 }
95 }
96
97 type ShmSeg = ServerObject<xcb::ffi::shm::xcb_shm_seg_t>;
98
99 unsafe fn create_shm_seg(
100 id: xcb::ffi::shm::xcb_shm_seg_t,
101 connection: *mut xcb::ffi::xcb_connection_t,
102 ) -> ShmSeg {
103 ServerObject {
104 id,
105 connection,
106 free_fn: xcb::ffi::shm::xcb_shm_detach,
107 }
108 }
109
110 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
111 enum SurfaceFormatGroup {
112 R8G8B8A8,
113 B8G8R8A8,
114 }
115
116 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
117 enum SwapchainSetupError {
118 BadSurface,
119 NoSupport,
120 }
121
122 unsafe fn query_extension(
123 connection: *mut xcb::ffi::xcb_connection_t,
124 extension_name: &str,
125 ) -> xcb::ffi::xcb_query_extension_cookie_t {
126 let len = extension_name.len() as u16;
127 assert_eq!(len as usize, extension_name.len());
128 xcb::ffi::xcb_query_extension(connection, len, extension_name.as_ptr() as *const c_char)
129 }
130
131 pub const MAX_SWAPCHAIN_IMAGE_COUNT: u32 = 16;
132
133 struct SwapchainSetupFirstStage {
134 gc: Gc,
135 shm_supported: bool,
136 window_depth: u8,
137 surface_format_group: SurfaceFormatGroup,
138 present_modes: &'static [api::VkPresentModeKHR],
139 capabilities: api::VkSurfaceCapabilitiesKHR,
140 shared_present_capabilities: Option<api::VkSharedPresentSurfaceCapabilitiesKHR>,
141 image_pixel_size: usize,
142 scanline_alignment: usize,
143 shm_version: Option<xcb::ffi::shm::xcb_shm_query_version_cookie_t>,
144 image_properties: ImageProperties,
145 }
146
147 impl SwapchainSetupFirstStage {
148 unsafe fn new(
149 connection: *mut xcb::ffi::xcb_connection_t,
150 window: xcb::ffi::xcb_window_t,
151 is_full_setup: bool,
152 ) -> Result<Self, SwapchainSetupError> {
153 let has_mit_shm = query_extension(connection, "MIT-SHM");
154 let geometry = xcb::ffi::xcb_get_geometry(connection, window);
155 let window_attributes = xcb::ffi::xcb_get_window_attributes(connection, window);
156 let tree = xcb::ffi::xcb_query_tree(connection, window);
157 let gc = xcb::ffi::xcb_generate_id(connection);
158 xcb::ffi::xcb_create_gc(
159 connection,
160 gc,
161 window,
162 xcb::ffi::XCB_GC_GRAPHICS_EXPOSURES,
163 [0].as_ptr(),
164 );
165 let gc = create_gc(gc, connection);
166 let has_mit_shm = ReplyObject::from(xcb::ffi::xcb_query_extension_reply(
167 connection,
168 has_mit_shm,
169 null_mut(),
170 ));
171 let shm_supported = has_mit_shm.map(|v| v.present != 0).unwrap_or(false);
172 let shm_version = if is_full_setup && shm_supported {
173 Some(xcb::ffi::shm::xcb_shm_query_version(connection))
174 } else {
175 None
176 };
177 let geometry = ReplyObject::from(xcb::ffi::xcb_get_geometry_reply(
178 connection,
179 geometry,
180 null_mut(),
181 ))
182 .ok_or(SwapchainSetupError::BadSurface)?;
183 let image_extent = api::VkExtent2D {
184 width: geometry.width as u32,
185 height: geometry.height as u32,
186 };
187 mem::drop(geometry);
188 let window_attributes = ReplyObject::from(xcb::ffi::xcb_get_window_attributes_reply(
189 connection,
190 window_attributes,
191 null_mut(),
192 ))
193 .ok_or(SwapchainSetupError::BadSurface)?;
194 let window_visual_id = window_attributes.visual;
195 mem::drop(window_attributes);
196 let tree = ReplyObject::from(xcb::ffi::xcb_query_tree_reply(connection, tree, null_mut()))
197 .ok_or(SwapchainSetupError::BadSurface)?;
198 let root_window = tree.root;
199 mem::drop(tree);
200 let mut screen = None;
201 let mut roots_iter =
202 xcb::ffi::xcb_setup_roots_iterator(xcb::ffi::xcb_get_setup(connection));
203 while roots_iter.rem != 0 {
204 if (*roots_iter.data).root == root_window {
205 screen = Some(roots_iter.data);
206 break;
207 }
208 xcb::ffi::xcb_screen_next(&mut roots_iter);
209 }
210 let screen = screen.ok_or(SwapchainSetupError::BadSurface)?;
211 let mut window_visual_type_and_depth = None;
212 let mut depth_iter = xcb::ffi::xcb_screen_allowed_depths_iterator(screen);
213 while depth_iter.rem != 0 {
214 let mut visual_iter = xcb::ffi::xcb_depth_visuals_iterator(depth_iter.data);
215 while visual_iter.rem != 0 {
216 if (*visual_iter.data).visual_id == window_visual_id {
217 window_visual_type_and_depth =
218 Some((visual_iter.data, (*depth_iter.data).depth));
219 break;
220 }
221 xcb::ffi::xcb_visualtype_next(&mut visual_iter);
222 }
223 if window_visual_type_and_depth.is_some() {
224 break;
225 }
226 xcb::ffi::xcb_depth_next(&mut depth_iter);
227 }
228 let (window_visual_type, window_depth) =
229 window_visual_type_and_depth.ok_or(SwapchainSetupError::BadSurface)?;
230 let ref window_visual_type = *window_visual_type;
231 let red_mask = window_visual_type.red_mask;
232 let green_mask = window_visual_type.green_mask;
233 let blue_mask = window_visual_type.blue_mask;
234 let alpha_mask = match window_depth {
235 24 => 0,
236 32 => !(red_mask | green_mask | blue_mask),
237 _ => return Err(SwapchainSetupError::NoSupport),
238 };
239 let mut window_pixmap_format = None;
240 let mut formats_iter =
241 xcb::ffi::xcb_setup_pixmap_formats_iterator(xcb::ffi::xcb_get_setup(connection));
242 while formats_iter.rem != 0 {
243 if (*formats_iter.data).depth == window_depth {
244 window_pixmap_format = Some(formats_iter.data);
245 break;
246 }
247 xcb::ffi::xcb_format_next(&mut formats_iter);
248 }
249 let ref window_pixmap_format =
250 *(window_pixmap_format.ok_or(SwapchainSetupError::BadSurface)?);
251 let image_pixel_size = match window_pixmap_format.bits_per_pixel {
252 24 => 3,
253 32 => 4,
254 _ => return Err(SwapchainSetupError::NoSupport),
255 };
256 fn u32_from_bytes(v: [u8; 4]) -> u32 {
257 unsafe { mem::transmute(v) }
258 }
259 let surface_format_group = match (
260 u32_from_bytes([0xFF, 0, 0, 0]),
261 u32_from_bytes([0, 0xFF, 0, 0]),
262 u32_from_bytes([0, 0, 0xFF, 0]),
263 u32_from_bytes([0, 0, 0, 0xFF]),
264 ) {
265 (r, g, b, a)
266 if r == red_mask
267 && g == green_mask
268 && b == blue_mask
269 && (alpha_mask == 0 || a == alpha_mask) =>
270 {
271 SurfaceFormatGroup::R8G8B8A8
272 }
273 (b, g, r, a)
274 if r == red_mask
275 && g == green_mask
276 && b == blue_mask
277 && (alpha_mask == 0 || a == alpha_mask) =>
278 {
279 SurfaceFormatGroup::B8G8R8A8
280 }
281 _ => return Err(SwapchainSetupError::NoSupport),
282 };
283 let scanline_alignment = match window_pixmap_format.scanline_pad {
284 8 => 1,
285 16 => 2,
286 32 => 4,
287 _ => unreachable!("invalid pixmap format scanline_pad"),
288 };
289 const PRESENT_MODES: &'static [api::VkPresentModeKHR] = &[
290 api::VK_PRESENT_MODE_FIFO_KHR, // FIXME: properly implement FIFO present mode using X11 Present extension
291 api::VK_PRESENT_MODE_IMMEDIATE_KHR,
292 ];
293 Ok(Self {
294 gc,
295 shm_supported,
296 window_depth,
297 surface_format_group,
298 present_modes: PRESENT_MODES,
299 capabilities: api::VkSurfaceCapabilitiesKHR {
300 minImageCount: 2,
301 maxImageCount: MAX_SWAPCHAIN_IMAGE_COUNT,
302 currentExtent: image_extent,
303 minImageExtent: image_extent,
304 maxImageExtent: image_extent,
305 maxImageArrayLayers: 1,
306 supportedTransforms: api::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
307 currentTransform: api::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
308 supportedCompositeAlpha: api::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
309 supportedUsageFlags: api::VK_IMAGE_USAGE_TRANSFER_SRC_BIT
310 | api::VK_IMAGE_USAGE_TRANSFER_DST_BIT
311 | api::VK_IMAGE_USAGE_SAMPLED_BIT
312 | api::VK_IMAGE_USAGE_STORAGE_BIT
313 | api::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
314 | api::VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
315 },
316 shared_present_capabilities: None,
317 image_pixel_size,
318 scanline_alignment,
319 shm_version,
320 image_properties: ImageProperties {
321 supported_tilings: SupportedTilings::Any,
322 format: api::VK_FORMAT_UNDEFINED,
323 extents: api::VkExtent3D {
324 width: image_extent.width,
325 height: image_extent.height,
326 depth: 1,
327 },
328 array_layers: 1,
329 mip_levels: 1,
330 multisample_count: ImageMultisampleCount::Count1,
331 swapchain_present_tiling: Some(Tiling::Linear),
332 },
333 })
334 }
335 }
336
337 impl XcbSwapchain {
338 unsafe fn new(
339 create_info: &api::VkSwapchainCreateInfoKHR,
340 device_group_create_info: Option<&api::VkDeviceGroupSwapchainCreateInfoKHR>,
341 ) -> Result<Self, api::VkResult> {
342 unimplemented!()
343 }
344 }
345
346 #[derive(Debug)]
347 pub struct XcbSurfaceImplementation;
348
349 impl XcbSurfaceImplementation {
350 unsafe fn get_surface(&self, surface: api::VkSurfaceKHR) -> &api::VkIcdSurfaceXcb {
351 let surface = surface.get().unwrap().as_ptr();
352 assert_eq!((*surface).platform, api::VK_ICD_WSI_PLATFORM_XCB);
353 &*(surface as *const api::VkIcdSurfaceXcb)
354 }
355 }
356
357 impl SurfaceImplementation for XcbSurfaceImplementation {
358 fn get_platform(&self) -> SurfacePlatform {
359 SurfacePlatform::VK_ICD_WSI_PLATFORM_XCB
360 }
361 unsafe fn get_surface_formats(
362 &self,
363 surface: api::VkSurfaceKHR,
364 ) -> Result<Cow<'static, [api::VkSurfaceFormatKHR]>, api::VkResult> {
365 let surface = &self.get_surface(surface);
366 let first_stage = SwapchainSetupFirstStage::new(surface.connection, surface.window, false)
367 .map_err(|v| match v {
368 SwapchainSetupError::BadSurface | SwapchainSetupError::NoSupport => {
369 api::VK_ERROR_SURFACE_LOST_KHR
370 }
371 })?;
372 match first_stage.surface_format_group {
373 SurfaceFormatGroup::B8G8R8A8 => {
374 const SURFACE_FORMATS: &'static [api::VkSurfaceFormatKHR] = &[
375 api::VkSurfaceFormatKHR {
376 format: api::VK_FORMAT_B8G8R8A8_SRGB,
377 colorSpace: api::VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
378 },
379 api::VkSurfaceFormatKHR {
380 format: api::VK_FORMAT_B8G8R8A8_UNORM,
381 colorSpace: api::VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
382 },
383 ];
384 Ok(Cow::Borrowed(SURFACE_FORMATS))
385 }
386 SurfaceFormatGroup::R8G8B8A8 => {
387 const SURFACE_FORMATS: &'static [api::VkSurfaceFormatKHR] = &[
388 api::VkSurfaceFormatKHR {
389 format: api::VK_FORMAT_R8G8B8A8_SRGB,
390 colorSpace: api::VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
391 },
392 api::VkSurfaceFormatKHR {
393 format: api::VK_FORMAT_R8G8B8A8_UNORM,
394 colorSpace: api::VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
395 },
396 ];
397 Ok(Cow::Borrowed(SURFACE_FORMATS))
398 }
399 }
400 }
401 unsafe fn get_present_modes(
402 &self,
403 surface: api::VkSurfaceKHR,
404 ) -> Result<Cow<'static, [api::VkPresentModeKHR]>, api::VkResult> {
405 let surface = &self.get_surface(surface);
406 let first_stage = SwapchainSetupFirstStage::new(surface.connection, surface.window, false)
407 .map_err(|v| match v {
408 SwapchainSetupError::BadSurface | SwapchainSetupError::NoSupport => {
409 api::VK_ERROR_SURFACE_LOST_KHR
410 }
411 })?;
412 Ok(Cow::Borrowed(first_stage.present_modes))
413 }
414 unsafe fn get_capabilities(
415 &self,
416 surface: api::VkSurfaceKHR,
417 ) -> Result<api::VkSurfaceCapabilitiesKHR, api::VkResult> {
418 let surface = &self.get_surface(surface);
419 let first_stage = SwapchainSetupFirstStage::new(surface.connection, surface.window, false)
420 .map_err(|v| match v {
421 SwapchainSetupError::BadSurface | SwapchainSetupError::NoSupport => {
422 api::VK_ERROR_SURFACE_LOST_KHR
423 }
424 })?;
425 Ok(first_stage.capabilities)
426 }
427 unsafe fn build(
428 &self,
429 create_info: &api::VkSwapchainCreateInfoKHR,
430 device_group_create_info: Option<&api::VkDeviceGroupSwapchainCreateInfoKHR>,
431 ) -> Result<Box<Swapchain>, api::VkResult> {
432 Ok(Box::new(XcbSwapchain::new(
433 create_info,
434 device_group_create_info,
435 )?))
436 }
437 unsafe fn destroy_surface(&self, surface: NonNull<api::VkIcdSurfaceBase>) {
438 Box::from_raw(surface.as_ptr() as *mut api::VkIcdSurfaceXcb);
439 }
440 fn duplicate(&self) -> Box<dyn SurfaceImplementation> {
441 Box::new(Self {})
442 }
443 }