1use alloc::sync::Arc;
42use alloc::vec;
43use alloc::vec::Vec;
44use core::cell::{Cell, RefCell};
45use core::ffi::c_void;
46use core::sync::atomic::{AtomicU64, Ordering};
47
48use rt::sync::SpinLock;
49
50use crate::vk_dev::{Device, Garbage, Shared};
51use crate::vk_ffi as vk;
52use crate::vk_inst::Adapter;
53use crate::*;
54
55const DRM_FORMAT_MOD_INVALID: u64 = 0x00FF_FFFF_FFFF_FFFF;
56const FORMAT_FEATURE_TRANSFER_SRC_BIT: u32 = 0x4000;
57const F_DUPFD_CLOEXEC: usize = 1030;
58const POLLOUT: u16 = 4;
59const IMAGES_DEFAULT: u32 = 3;
61const GPU_LOOK_US: u64 = 1_000;
63const WAIT_US: u64 = 10_000_000;
64
65fn candidates(srgb: bool) -> [(u32, u32, Format); 4] {
67 let (bgra, bf, rgba, rf) = if srgb {
68 (vk::FORMAT_B8G8R8A8_SRGB, Format::Bgra8Srgb, vk::FORMAT_R8G8B8A8_SRGB, Format::Rgba8Srgb)
69 } else {
70 (vk::FORMAT_B8G8R8A8_UNORM, Format::Bgra8Unorm, vk::FORMAT_R8G8B8A8_UNORM, Format::Rgba8Unorm)
71 };
72 [(0x3432_5258, bgra, bf), (0x3432_4258, rgba, rf), (0x3432_5241, bgra, bf), (0x3432_4241, rgba, rf)]
73}
74
75static RETIRED: SpinLock<Vec<(i32, u32)>> = SpinLock::new(Vec::new());
77
78fn free_retired() {
79 let list = core::mem::take(&mut *RETIRED.lock());
80 for (w, h) in list {
81 plat::gpu_buf_free(w, h);
82 }
83}
84
85fn fd_close(fd: i32) {
86 unsafe { rt::os::syscall3(rt::os::SYS_CLOSE, fd as usize, 0, 0) };
88}
89
90pub(crate) struct SurfShared {
91 pub window: i32,
92 caps: plat::GpuCaps,
93 size: AtomicU64,
94}
95
96#[derive(Clone)]
98pub struct Surface(pub(crate) Arc<SurfShared>);
99
100impl Surface {
101 pub fn new(instance: &Instance, window: i32) -> Result<Surface> {
103 let nw = plat::win_gpu_child(window).ok_or(GpuError::Unsupported("the display takes no GPU buffers"))?;
104 Surface::native(instance, nw, window)
105 }
106
107 pub fn native(_instance: &Instance, nw: plat::NativeWindow, window: i32) -> Result<Surface> {
109 let (w, h) = nw.size;
110 Ok(Surface(Arc::new(SurfShared { window, caps: nw.caps, size: AtomicU64::new(pack(w, h)) })))
111 }
112
113 pub fn track_size(&self) {
115 let (w, h) = plat::win_size(self.0.window);
116 self.0.size.store(pack(w, h), Ordering::Relaxed);
117 free_retired();
118 }
119
120 fn size(&self) -> (u32, u32) {
121 let v = self.0.size.load(Ordering::Relaxed);
122 ((v >> 32) as u32, v as u32)
123 }
124}
125
126fn pack(w: i32, h: i32) -> u64 {
127 (w.max(0) as u64) << 32 | h.max(0) as u64
128}
129
130#[must_use]
132pub struct Frame {
133 image: u32,
134 generation: u32,
135 size: (u32, u32),
136}
137
138#[must_use]
140pub enum TryAcquire {
141 Frame(Frame),
142 NotReady,
144 Stale,
146 NoArea,
148}
149
150impl Frame {
151 pub fn index(&self) -> u32 {
153 self.image
154 }
155 pub fn size(&self) -> (u32, u32) {
156 self.size
157 }
158}
159
160struct Img {
161 tex: Texture,
162 image: vk::Handle,
163 mem: vk::Handle,
164 fd: i32, buf: u32, offset: u32,
167 stride: u32,
168}
169
170pub struct Swapchain {
172 sh: Arc<Shared>,
173 surf: Surface,
174 desc: SwapchainDesc,
175 format: Format,
176 vk_format: u32,
177 fourcc: u32,
178 mods: Vec<u64>,
179 modifier: u64,
180 mode: PresentMode,
181 extent: (u32, u32),
182 images: Vec<Img>,
183 generation: u32,
184 next: Cell<u32>,
185 stale: Cell<bool>,
186 outstanding: Cell<bool>,
187 fly: RefCell<Option<(u32, u64, Option<Vec<[i32; 4]>>)>>,
189 dmg: RefCell<Vec<[i32; 4]>>,
190 dmg_full: Cell<bool>,
191 dmg_known: Cell<bool>,
192 waiting: Cell<bool>,
194 first: Cell<bool>,
197}
198
199fn present_mode_of(m: PresentMode) -> PresentMode {
200 match m {
203 PresentMode::Fifo => PresentMode::Fifo,
204 _ => PresentMode::Mailbox,
205 }
206}
207
208fn device_modifiers(a: &crate::vk_inst::InstShared, pd: vk::PhysicalDevice, format: u32, features: u32) -> Vec<u64> {
210 let Some(get) = a.f.get_physical_device_format_properties2 else { return Vec::new() };
211 let mut list: vk::DrmFormatModifierPropertiesListEXT = vk::Zero::zero();
212 list.s_type = vk::STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
213 let mut fp: vk::FormatProperties2 = vk::Zero::zero();
214 fp.s_type = vk::STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
215 fp.p_next = &mut list as *mut _ as *mut c_void;
216 unsafe { get(pd, format, &mut fp) };
218 let mut v: Vec<vk::DrmFormatModifierPropertiesEXT> = vec![vk::Zero::zero(); list.count as usize];
219 list.p_properties = v.as_mut_ptr();
220 fp.p_next = &mut list as *mut _ as *mut c_void;
221 unsafe { get(pd, format, &mut fp) };
223 v.truncate(list.count as usize);
224 v.iter().filter(|m| m.plane_count == 1 && m.tiling_features & features == features).map(|m| m.modifier).collect()
225}
226
227fn exportable(a: &crate::vk_inst::InstShared, pd: vk::PhysicalDevice, format: u32, usage: u32, modifier: u64) -> bool {
229 let Some(get) = a.f.get_physical_device_image_format_properties2 else { return false };
230 let dm = vk::PhysicalDeviceImageDrmFormatModifierInfoEXT {
231 s_type: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
232 modifier,
233 sharing_mode: vk::SHARING_MODE_EXCLUSIVE,
234 ..vk::Zero::zero()
235 };
236 let ei = vk::PhysicalDeviceExternalImageFormatInfo {
237 s_type: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
238 p_next: &dm as *const _ as *const c_void,
239 handle_type: vk::EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
240 };
241 let info = vk::PhysicalDeviceImageFormatInfo2 {
242 s_type: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
243 p_next: &ei as *const _ as *const c_void,
244 format,
245 image_type: vk::IMAGE_TYPE_2D,
246 tiling: vk::IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
247 usage,
248 flags: 0,
249 };
250 let mut ep: vk::ExternalImageFormatProperties = vk::Zero::zero();
251 ep.s_type = vk::STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
252 let mut p: vk::ImageFormatProperties2 = vk::Zero::zero();
253 p.s_type = vk::STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
254 p.p_next = &mut ep as *mut _ as *mut c_void;
255 let r = unsafe { get(pd, &info, &mut p) };
257 r == vk::SUCCESS && ep.external_memory_properties.external_memory_features & vk::EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT != 0
258}
259
260fn image_usage(copy_src: bool) -> (u32, u32) {
261 let mut usage = vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
262 let mut features = vk::FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
263 if copy_src {
264 usage |= vk::IMAGE_USAGE_TRANSFER_SRC_BIT;
265 features |= FORMAT_FEATURE_TRANSFER_SRC_BIT;
266 }
267 (usage, features)
268}
269
270fn pick_format(a: &crate::vk_inst::InstShared, pd: vk::PhysicalDevice, caps: &plat::GpuCaps, srgb: bool, copy_src: bool)
272 -> Option<(u32, u32, Format, Vec<u64>)> {
273 let (usage, features) = image_usage(copy_src);
274 for (fourcc, vf, ff) in candidates(srgb) {
275 if !caps.formats.iter().any(|e| e.0 == fourcc && e.1 != DRM_FORMAT_MOD_INVALID) {
276 continue;
277 }
278 let mods: Vec<u64> = device_modifiers(a, pd, vf, features)
279 .into_iter()
280 .filter(|&m| caps.formats.contains(&(fourcc, m)) && exportable(a, pd, vf, usage, m))
281 .collect();
282 if !mods.is_empty() {
283 return Some((fourcc, vf, ff, mods));
284 }
285 }
286 None
287}
288
289fn same_device(adapter: &Adapter, caps: &plat::GpuCaps) -> bool {
291 let (Some(d), true) = (caps.device, adapter.exts.physical_drm) else { return true };
292 let major = ((d >> 32) & 0xFFFF_F000 | (d >> 8) & 0xFFF) as i64;
293 let minor = ((d >> 12) & 0xFFFF_FF00 | d & 0xFF) as i64;
294 let mut drm: vk::PhysicalDeviceDrmPropertiesEXT = vk::Zero::zero();
295 drm.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT;
296 let mut p2: vk::PhysicalDeviceProperties2 = vk::Zero::zero();
297 p2.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
298 p2.p_next = &mut drm as *mut _ as *mut c_void;
299 unsafe { (adapter.inst.f.get_physical_device_properties2)(adapter.pd, &mut p2) };
301 (drm.has_primary != 0 && (drm.primary_major, drm.primary_minor) == (major, minor))
302 || (drm.has_render != 0 && (drm.render_major, drm.render_minor) == (major, minor))
303}
304
305pub(crate) fn can_present(adapter: &Adapter, surface: &Surface) -> bool {
307 adapter.exts.dmabuf
308 && adapter.info.kind != AdapterKind::Cpu
309 && same_device(adapter, &surface.0.caps)
310 && pick_format(&adapter.inst, adapter.pd, &surface.0.caps, false, false).is_some()
311}
312
313impl Device {
314 pub fn create_swapchain(&self, surface: &Surface, desc: &SwapchainDesc) -> Result<Swapchain> {
315 let sh = &self.sh;
316 sh.check()?;
317 if !sh.features.swapchain {
318 return Err(GpuError::Unsupported("images for a window (VK_EXT_image_drm_format_modifier, not on a CPU adapter)"));
319 }
320 let (fourcc, vk_format, format, mods) = pick_format(&sh.inst, sh.pd, &surface.0.caps, desc.srgb, desc.copy_src)
321 .ok_or(GpuError::Unsupported("a format the display and the device share"))?;
322 let mut d = *desc;
323 d.frames_in_flight = d.frames_in_flight.clamp(1, 3);
324 match plat::env("jfgui_GPU_PRESENT").as_deref() {
325 Some("fifo") => d.present = PresentMode::Fifo,
326 Some("mailbox") => d.present = PresentMode::Mailbox,
327 Some("immediate") => d.present = PresentMode::Immediate,
328 _ => {}
329 }
330 let mut sc = Swapchain {
331 sh: sh.clone(),
332 surf: surface.clone(),
333 desc: d,
334 format,
335 vk_format,
336 fourcc,
337 mods,
338 modifier: 0,
339 mode: present_mode_of(d.present),
340 extent: (0, 0),
341 images: Vec::new(),
342 generation: 0,
343 next: Cell::new(0),
344 stale: Cell::new(false),
345 outstanding: Cell::new(false),
346 fly: RefCell::new(None),
347 dmg: RefCell::new(Vec::new()),
348 dmg_full: Cell::new(false),
349 dmg_known: Cell::new(false),
350 waiting: Cell::new(false),
351 first: Cell::new(false),
352 };
353 sc.build()?;
354 Ok(sc)
355 }
356}
357
358impl Swapchain {
359 fn release(&mut self) {
361 let window = self.surf.0.window;
362 for m in self.images.drain(..) {
363 if m.buf != 0 {
364 RETIRED.lock().push((window, m.buf));
365 }
366 fd_close(m.fd);
367 drop(m.tex);
368 self.sh.defer(Garbage::Image(m.image, None));
369 self.sh.defer(Garbage::Memory(m.mem));
370 }
371 *self.fly.borrow_mut() = None;
372 }
373
374 fn make_image(&self, w: u32, h: u32, mods: &[u64]) -> Result<(Img, u64)> {
376 let sh = self.sh.clone();
377 let (Some(get_mod), Some(get_layout), Some(get_fd)) =
378 (sh.f.get_image_drm_format_modifier_properties_ext, sh.f.get_image_subresource_layout, sh.f.get_memory_fd_khr)
379 else {
380 return Err(GpuError::Unsupported("VK_EXT_image_drm_format_modifier"));
381 };
382 let (usage, _) = image_usage(self.desc.copy_src);
383 let list = vk::ImageDrmFormatModifierListCreateInfoEXT {
384 s_type: vk::STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT,
385 p_next: core::ptr::null(),
386 count: mods.len() as u32,
387 p_modifiers: mods.as_ptr(),
388 };
389 let ext = vk::ExternalMemoryImageCreateInfo {
390 s_type: vk::STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
391 p_next: &list as *const _ as *const c_void,
392 handle_types: vk::EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
393 };
394 let ii = vk::ImageCreateInfo {
395 s_type: vk::STRUCTURE_TYPE_IMAGE_CREATE_INFO,
396 p_next: &ext as *const _ as *const c_void,
397 image_type: vk::IMAGE_TYPE_2D,
398 format: self.vk_format,
399 extent: vk::Extent3D { width: w, height: h, depth: 1 },
400 mip_levels: 1,
401 array_layers: 1,
402 samples: vk::SAMPLE_COUNT_1_BIT,
403 tiling: vk::IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
404 usage,
405 sharing_mode: vk::SHARING_MODE_EXCLUSIVE,
406 initial_layout: vk::IMAGE_LAYOUT_UNDEFINED,
407 ..vk::Zero::zero()
408 };
409 let mut image = 0;
410 sh.vk(unsafe { (sh.f.create_image)(sh.dev, &ii, core::ptr::null(), &mut image) })?;
412 let mut mem = 0;
413 let mut fd = -1;
414 let made = (|| {
415 let mut mp: vk::ImageDrmFormatModifierPropertiesEXT = vk::Zero::zero();
416 mp.s_type = vk::STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT;
417 sh.vk(unsafe { get_mod(sh.dev, image, &mut mp) })?;
419 let mut req: vk::MemoryRequirements = vk::Zero::zero();
420 unsafe { (sh.f.get_image_memory_requirements)(sh.dev, image, &mut req) };
422 let mut props: vk::PhysicalDeviceMemoryProperties = vk::Zero::zero();
423 unsafe { (sh.inst.f.get_physical_device_memory_properties)(sh.pd, &mut props) };
425 let n = props.memory_type_count.min(32);
426 let ty = (0..n)
427 .find(|&k| req.memory_type_bits & 1 << k != 0 && props.memory_types[k as usize].property_flags & vk::MEMORY_PROPERTY_DEVICE_LOCAL_BIT != 0)
428 .or_else(|| (0..n).find(|&k| req.memory_type_bits & 1 << k != 0))
429 .ok_or(GpuError::Unsupported("memory for an exported image"))?;
430 let ded = vk::MemoryDedicatedAllocateInfo {
431 s_type: vk::STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
432 image,
433 ..vk::Zero::zero()
434 };
435 let exp = vk::ExportMemoryAllocateInfo {
436 s_type: vk::STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
437 p_next: &ded as *const _ as *const c_void,
438 handle_types: vk::EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
439 };
440 let ai = vk::MemoryAllocateInfo {
441 s_type: vk::STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
442 p_next: &exp as *const _ as *const c_void,
443 allocation_size: req.size,
444 memory_type_index: ty,
445 };
446 sh.vk(unsafe { (sh.f.allocate_memory)(sh.dev, &ai, core::ptr::null(), &mut mem) })?;
448 sh.vk(unsafe { (sh.f.bind_image_memory)(sh.dev, image, mem, 0) })?;
450 let gi = vk::MemoryGetFdInfoKHR {
451 s_type: vk::STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
452 p_next: core::ptr::null(),
453 memory: mem,
454 handle_type: vk::EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
455 };
456 sh.vk(unsafe { get_fd(sh.dev, &gi, &mut fd) })?;
458 let sub = vk::ImageSubresource { aspect_mask: vk::IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT, mip_level: 0, array_layer: 0 };
459 let mut lay: vk::SubresourceLayout = vk::Zero::zero();
460 unsafe { get_layout(sh.dev, image, &sub, &mut lay) };
462 let mut tu = TextureUsage::COLOR_TARGET;
463 if self.desc.copy_src {
464 tu = tu | TextureUsage::COPY_SRC;
465 }
466 let tex = crate::vk_res::wrap_image(&sh, image, TextureDesc::d2(w, h, self.format, tu))?;
467 Ok((tex, mp.modifier, lay.offset as u32, lay.row_pitch as u32))
468 })();
469 match made {
470 Ok((tex, modifier, offset, stride)) => Ok((Img { tex, image, mem, fd, buf: 0, offset, stride }, modifier)),
471 Err(e) => {
472 if fd >= 0 {
473 fd_close(fd);
474 }
475 sh.defer(Garbage::Image(image, None));
476 if mem != 0 {
477 sh.defer(Garbage::Memory(mem));
478 }
479 Err(e)
480 }
481 }
482 }
483
484 fn build(&mut self) -> Result<()> {
486 self.release();
487 let (w, h) = self.surf.size();
488 self.stale.set(false);
489 self.outstanding.set(false);
490 self.extent = (0, 0);
491 if w == 0 || h == 0 {
492 return Ok(());
493 }
494 let n = if self.desc.min_images != 0 { self.desc.min_images } else { IMAGES_DEFAULT }.clamp(2, 8);
495 let mut mods = self.mods.clone();
496 for _ in 0..n {
497 let (img, m) = self.make_image(w, h, &mods)?;
498 mods = vec![m];
500 self.modifier = m;
501 self.images.push(img);
502 }
503 self.extent = (w, h);
504 self.generation = self.generation.wrapping_add(1);
505 self.dmg_full.set(true);
506 Ok(())
507 }
508
509 pub fn rebuild(&mut self) -> Result<()> {
511 self.sh.check()?;
512 self.build()
513 }
514
515 fn register(&mut self) -> Result<()> {
517 let (w, h) = self.extent;
518 for k in 0..self.images.len() {
519 if self.images[k].buf != 0 {
520 continue;
521 }
522 let dup = unsafe { rt::os::syscall3(rt::os::SYS_FCNTL, self.images[k].fd as usize, F_DUPFD_CLOEXEC, 3) };
524 if dup < 0 {
525 return Err(GpuError::Unsupported("no descriptor for a buffer"));
526 }
527 let m = &self.images[k];
528 let d = plat::GpuBufDesc {
529 w: w as i32,
530 h: h as i32,
531 fourcc: self.fourcc,
532 modifier: self.modifier,
533 planes: vec![plat::GpuPlane { fd: dup as i32, offset: m.offset, stride: m.stride }],
534 };
535 let buf = plat::gpu_buf_new(self.surf.0.window, &d);
536 if buf == 0 {
537 return Err(GpuError::Unsupported("the display refuses the buffer"));
538 }
539 self.images[k].buf = buf;
540 }
541 Ok(())
542 }
543
544 fn unread(fd: i32) -> bool {
546 #[repr(C)]
547 struct PollFd {
548 fd: i32,
549 events: u16,
550 revents: u16,
551 }
552 let mut p = PollFd { fd, events: POLLOUT, revents: 0 };
553 let r = unsafe { rt::os::poll(&mut p as *mut PollFd as usize, 1, 0) };
555 r == 1
556 }
557
558 pub fn flush(&self) -> Result<bool> {
560 free_retired();
561 let Some(&(k, v, _)) = self.fly.borrow().as_ref() else { return Ok(false) };
562 if v > self.sh.refresh() {
563 self.sh.check()?;
564 return Ok(true);
565 }
566 let Some((_, _, rects)) = self.fly.borrow_mut().take() else { return Ok(false) };
567 if let Some(m) = self.images.get(k as usize) {
568 plat::gpu_show(self.surf.0.window, m.buf, rects.as_deref());
569 }
570 Ok(false)
571 }
572
573 pub fn busy(&self) -> bool {
575 self.fly.borrow().is_some()
576 }
577
578 pub fn next_look(&self, retry: u64) -> u64 {
582 if self.busy() {
583 return plat::time_us() + GPU_LOOK_US;
584 }
585 if !self.waiting.get() {
586 return retry;
587 }
588 let w = self.surf.0.window;
589 if plat::gpu_can_show(w) && self.images.iter().any(|m| plat::gpu_buf_state(w, m.buf) == plat::GPU_BUF_FREE) {
590 return retry;
591 }
592 plat::gpu_next_look(w)
593 }
594
595 pub fn prepare(&mut self) -> Result<bool> {
597 self.register()?;
598 let w = self.surf.0.window;
599 for m in &self.images {
600 match plat::gpu_buf_state(w, m.buf) {
601 plat::GPU_BUF_FAILED => return Err(GpuError::Unsupported("the display refuses the buffer")),
602 plat::GPU_BUF_PENDING => return Ok(false),
603 _ => {}
604 }
605 }
606 self.first.set(true);
607 Ok(true)
608 }
609
610 pub fn damage(&self, rects: Option<&[[i32; 4]]>) {
612 self.dmg_known.set(true);
613 match rects {
614 Some(r) => self.dmg.borrow_mut().extend_from_slice(r),
615 None => self.dmg_full.set(true),
616 }
617 }
618
619 pub fn try_acquire(&mut self) -> Result<TryAcquire> {
621 self.sh.check()?;
622 free_retired();
623 let window = self.surf.0.window;
624 if plat::win_state(window) & plat::WST_MINIMIZED != 0 {
625 return Ok(TryAcquire::NoArea);
626 }
627 let (ww, wh) = plat::win_size(window);
628 let size = (ww.max(0) as u32, wh.max(0) as u32);
629 if self.stale.get() || self.outstanding.get() || self.images.is_empty() || size != self.extent {
630 self.stale.set(true);
631 return Ok(TryAcquire::Stale);
632 }
633 self.register()?;
634 self.waiting.set(true);
635 if self.flush()? || (!self.first.get() && !plat::gpu_can_show(window)) {
636 return Ok(TryAcquire::NotReady);
637 }
638 let n = self.images.len() as u32;
639 let first = self.next.get();
640 for j in 0..n {
641 let k = (first + j) % n;
642 let m = &self.images[k as usize];
643 match plat::gpu_buf_state(window, m.buf) {
644 plat::GPU_BUF_FAILED => return Err(GpuError::Unsupported("the display refuses the buffer")),
645 plat::GPU_BUF_FREE if Self::unread(m.fd) => {
646 self.next.set((k + 1) % n);
647 self.outstanding.set(true);
648 self.waiting.set(false);
649 self.first.set(false);
650 return Ok(TryAcquire::Frame(Frame { image: k, generation: self.generation, size: self.extent }));
651 }
652 _ => {}
653 }
654 }
655 Ok(TryAcquire::NotReady)
656 }
657
658 pub fn acquire(&mut self) -> Result<Option<Frame>> {
661 self.sh.check()?;
662 let window = self.surf.0.window;
663 if plat::win_state(window) & plat::WST_MINIMIZED != 0 {
664 return Ok(None);
665 }
666 if self.outstanding.get() {
667 self.stale.set(true); }
669 let dl = plat::time_us() + WAIT_US;
670 loop {
671 self.surf.track_size();
672 let (w, h) = self.surf.size();
673 if w == 0 || h == 0 {
674 return Ok(None);
675 }
676 if self.stale.get() || self.images.is_empty() || (w, h) != self.extent {
677 self.build()?;
678 }
679 match self.try_acquire()? {
680 TryAcquire::Frame(f) => return Ok(Some(f)),
681 TryAcquire::NoArea => return Ok(None),
682 TryAcquire::Stale => {}
683 TryAcquire::NotReady => {
684 let now = plat::time_us();
685 if now >= dl {
686 return Err(GpuError::Timeout);
687 }
688 plat::gpu_wait(self.next_look(now).min(now + 2_000));
689 }
690 }
691 }
692 }
693
694 pub fn view(&self, frame: &Frame) -> &TextureView {
696 self.images[frame.image as usize].tex.view()
697 }
698
699 pub fn texture(&self, frame: &Frame) -> &Texture {
701 &self.images[frame.image as usize].tex
702 }
703
704 fn ownership(&self, image: vk::Handle, acquire: bool) -> Result<crate::vk_dev::Slot> {
706 let sh = &self.sh;
707 let foreign = if sh.queue_foreign { vk::QUEUE_FAMILY_FOREIGN_EXT } else { vk::QUEUE_FAMILY_EXTERNAL };
708 let slot = sh.take_slot()?;
709 let range = vk::ImageSubresourceRange { aspect_mask: vk::IMAGE_ASPECT_COLOR_BIT, base_mip_level: 0, level_count: 1, base_array_layer: 0, layer_count: 1 };
710 let b = vk::ImageMemoryBarrier {
711 s_type: vk::STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
712 src_access_mask: if acquire { 0 } else { vk::ACCESS_COLOR_ATTACHMENT_WRITE_BIT | vk::ACCESS_TRANSFER_READ_BIT },
713 dst_access_mask: 0,
714 old_layout: if acquire { vk::IMAGE_LAYOUT_UNDEFINED } else { vk::IMAGE_LAYOUT_GENERAL },
715 new_layout: vk::IMAGE_LAYOUT_GENERAL,
716 src_queue_family_index: if acquire { foreign } else { sh.family },
717 dst_queue_family_index: if acquire { sh.family } else { foreign },
718 image,
719 subresource_range: range,
720 ..vk::Zero::zero()
721 };
722 let (ss, ds) = if acquire {
723 (vk::PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)
724 } else {
725 (vk::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | vk::PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT)
726 };
727 unsafe { (sh.f.cmd_pipeline_barrier)(slot.cb, ss, ds, 0, 0, core::ptr::null(), 0, core::ptr::null(), 1, &b) };
729 if let Err(e) = sh.vk(unsafe { (sh.f.end_command_buffer)(slot.cb) }) {
731 sh.give_slot(slot);
732 return Err(e);
733 }
734 Ok(slot)
735 }
736
737 pub fn present<'a, I: IntoIterator<Item = CommandBuffer<'a>>>(&self, frame: Frame, cmds: I) -> Result<SubmitId> {
740 let sh = &self.sh;
741 let mut slots = Vec::new();
742 for c in cmds {
743 slots.push(c.into_slot());
744 }
745 if frame.generation != self.generation || !self.outstanding.get() || self.images.is_empty() {
746 for s in slots {
747 sh.give_slot(s);
748 }
749 return Err(GpuError::Invalid("present: a frame of an older swapchain"));
750 }
751 let image = self.images[frame.image as usize].image;
752 let first = match self.ownership(image, true) {
753 Ok(s) => s,
754 Err(e) => {
755 for s in slots {
756 sh.give_slot(s);
757 }
758 return Err(e);
759 }
760 };
761 let last = match self.ownership(image, false) {
762 Ok(s) => s,
763 Err(e) => {
764 sh.give_slot(first);
765 for s in slots {
766 sh.give_slot(s);
767 }
768 return Err(e);
769 }
770 };
771 slots.insert(0, first);
772 slots.push(last);
773 let cbs: Vec<vk::CommandBuffer> = slots.iter().map(|s| s.cb).collect();
774 let value = sh.submit(&cbs, slots, None, None)?;
775 self.outstanding.set(false);
776 let rects = if self.dmg_known.get() && !self.dmg_full.replace(false) {
777 Some(core::mem::take(&mut *self.dmg.borrow_mut()))
778 } else {
779 self.dmg.borrow_mut().clear();
780 None
781 };
782 *self.fly.borrow_mut() = Some((frame.image, value, rects));
783 self.flush()?;
784 Ok(SubmitId(value))
785 }
786
787 pub fn resize(&mut self) {
789 self.stale.set(true);
790 }
791
792 pub fn set_present_mode(&mut self, m: PresentMode) {
794 self.desc.present = m;
795 self.mode = present_mode_of(m);
796 }
797
798 pub fn present_mode(&self) -> PresentMode {
799 self.mode
800 }
801 pub fn format(&self) -> Format {
802 self.format
803 }
804 pub fn size(&self) -> (u32, u32) {
806 self.extent
807 }
808 pub fn image_count(&self) -> usize {
809 self.images.len()
810 }
811 pub fn drm_format(&self) -> (u32, u64) {
813 (self.fourcc, self.modifier)
814 }
815}
816
817impl Drop for Swapchain {
818 fn drop(&mut self) {
819 self.release();
820 }
821}