1use alloc::sync::Arc;
58use alloc::vec::Vec;
59use core::ffi::c_void;
60use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
61
62use rt::sync::SpinLock;
63
64use crate::vk_ffi as vk;
65use crate::vk_inst::{Adapter, InstShared, err};
66use crate::vk_mem::{Alloc, Allocator};
67use crate::{AdapterInfo, DataLayout, DeviceDesc, DeviceOptions, Features, GpuError, Layout, Level, Limits, MemoryKind, Pod, Result,
68 SubmitId, TextureRegion};
69
70pub(crate) enum Garbage {
72 Buffer(vk::Handle, Alloc),
73 Image(vk::Handle, Option<Alloc>),
74 View(vk::Handle),
75 Sampler(vk::Handle),
76 Shader(vk::Handle),
77 SetLayout(vk::Handle),
78 PipeLayout(vk::Handle),
79 Pipeline(vk::Handle),
80 Set(vk::Handle, vk::Handle),
81 Pool(vk::Handle),
82 Query(vk::Handle),
83 #[cfg_attr(jfgui_glibc, allow(dead_code))] Semaphore(vk::Handle),
85 #[cfg_attr(jfgui_glibc, allow(dead_code))]
86 Swapchain(vk::Handle),
87 #[cfg_attr(not(jfgui_glibc), allow(dead_code))] Memory(vk::Handle),
89}
90
91pub(crate) struct Slot {
93 pub pool: vk::Handle,
94 pub cb: vk::CommandBuffer,
95 pub compute: bool,
96}
97
98pub(crate) const COMPUTE_ID: u64 = 1 << 63;
100
101pub(crate) struct Lane {
103 pub queue: vk::Queue,
104 pub family: u32,
105 pub timeline: vk::Handle,
106 pub ts_bits: u32,
107 submitted: AtomicU64,
108 completed: AtomicU64,
109 qlock: SpinLock<()>,
110}
111
112struct Chunk {
114 buf: vk::Handle,
115 a: Alloc,
116 used: u64, }
118
119struct Upload {
122 slot: Slot,
123 retired: Vec<Chunk>,
124}
125
126#[derive(Default)]
128struct Ring {
129 cur: Option<Chunk>, cur_value: u64, cur_open: bool, busy: Vec<(u64, Chunk)>, free: Vec<Chunk>,
134 big_at: u64, big_size: u64, }
137
138pub(crate) struct State {
139 pub mem: Allocator,
140 garbage: Vec<(u64, u64, Garbage)>,
142 free: Vec<Slot>,
143 cfree: Vec<Slot>,
145 busy: Vec<(u64, Slot)>,
147 pools: Vec<vk::Handle>, upload: Option<Upload>,
149 ring: Ring,
150}
151
152const CHUNK: u64 = 256 << 10;
154const BIG_KEEP_RATIO: u64 = 8;
156const CHUNKS_FREE: usize = 2;
158const BIG_KEEP_US: u64 = 1_000_000;
160
161pub(crate) struct Shared {
162 pub inst: Arc<InstShared>,
163 pub pd: vk::PhysicalDevice,
164 pub dev: vk::Device,
165 pub f: vk::DeviceFns,
166 pub queue: vk::Queue,
167 pub family: u32,
168 pub timeline: vk::Handle,
169 pub info: AdapterInfo,
170 pub features: Features,
171 pub limits: Limits,
172 pub level: Level,
173 pub raw: vk::PhysicalDeviceLimits,
174 pub ts_mask: u64,
175 #[cfg_attr(jfgui_glibc, allow(dead_code))] pub swapchain: bool,
177 #[cfg_attr(not(jfgui_glibc), allow(dead_code))]
179 pub queue_foreign: bool,
180 pub ts_base: AtomicU64,
182 pub host_query_reset: bool,
184 pub maintenance4: bool,
186 pub lane: Option<Lane>,
188 lost: AtomicBool,
189 submitted: AtomicU64,
190 completed: AtomicU64,
191 qlock: SpinLock<()>,
192 pub st: SpinLock<State>,
193}
194
195#[derive(Clone)]
197pub struct Device {
198 pub(crate) sh: Arc<Shared>,
199 queue: Queue,
200 compute: Option<ComputeQueue>,
201}
202
203#[derive(Clone)]
207pub struct ComputeQueue {
208 pub(crate) sh: Arc<Shared>,
209}
210
211#[derive(Clone)]
213pub struct Queue {
214 pub(crate) sh: Arc<Shared>,
215}
216
217const E10: &[usize] = &[
219 vk::F10_FULL_DRAW_INDEX_UINT32,
220 vk::F10_IMAGE_CUBE_ARRAY,
221 vk::F10_INDEPENDENT_BLEND,
222 vk::F10_GEOMETRY_SHADER,
223 vk::F10_SAMPLE_RATE_SHADING,
224 vk::F10_DUAL_SRC_BLEND,
225 vk::F10_MULTI_DRAW_INDIRECT,
226 vk::F10_DRAW_INDIRECT_FIRST_INSTANCE,
227 vk::F10_DEPTH_CLAMP,
228 vk::F10_FILL_MODE_NON_SOLID,
229 vk::F10_SAMPLER_ANISOTROPY,
230 vk::F10_TEXTURE_COMPRESSION_BC,
231 vk::F10_VERTEX_PIPELINE_STORES_AND_ATOMICS,
232 vk::F10_FRAGMENT_STORES_AND_ATOMICS,
233 vk::F10_SHADER_STORAGE_IMAGE_EXTENDED_FORMATS,
234 vk::F10_SHADER_STORAGE_IMAGE_READ_WITHOUT_FORMAT,
235 vk::F10_SHADER_STORAGE_IMAGE_WRITE_WITHOUT_FORMAT,
236 vk::F10_SHADER_UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING,
237 vk::F10_SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING,
238 vk::F10_SHADER_STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING,
239 vk::F10_SHADER_STORAGE_IMAGE_ARRAY_DYNAMIC_INDEXING,
240 vk::F10_SHADER_CLIP_DISTANCE,
241 vk::F10_SHADER_FLOAT64,
242 vk::F10_SHADER_INT64,
243 vk::F10_SHADER_INT16,
244];
245const E11: &[usize] = &[
246 vk::F11_STORAGE_BUFFER_16BIT_ACCESS,
247 vk::F11_UNIFORM_AND_STORAGE_BUFFER_16BIT_ACCESS,
248 vk::F11_STORAGE_PUSH_CONSTANT16,
249 vk::F11_SHADER_DRAW_PARAMETERS,
250];
251const E12: &[usize] = &[
252 vk::F12_STORAGE_BUFFER_8BIT_ACCESS,
253 vk::F12_SHADER_FLOAT16,
254 vk::F12_SHADER_INT8,
255 vk::F12_SCALAR_BLOCK_LAYOUT,
256 vk::F12_UNIFORM_BUFFER_STANDARD_LAYOUT,
257 vk::F12_SHADER_SUBGROUP_EXTENDED_TYPES,
258 vk::F12_HOST_QUERY_RESET,
259 vk::F12_TIMELINE_SEMAPHORE,
260 vk::F12_BUFFER_DEVICE_ADDRESS,
261 vk::F12_VULKAN_MEMORY_MODEL,
262 vk::F12_VULKAN_MEMORY_MODEL_DEVICE_SCOPE,
263];
264const E12_VOLL: &[usize] = &[
265 vk::F12_DRAW_INDIRECT_COUNT,
266 vk::F12_DESCRIPTOR_INDEXING,
267 vk::F12_SHADER_SAMPLED_IMAGE_ARRAY_NON_UNIFORM_INDEXING,
268 vk::F12_SHADER_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
269 vk::F12_SHADER_STORAGE_IMAGE_ARRAY_NON_UNIFORM_INDEXING,
270 vk::F12_DESCRIPTOR_BINDING_SAMPLED_IMAGE_UPDATE_AFTER_BIND,
271 vk::F12_DESCRIPTOR_BINDING_STORAGE_IMAGE_UPDATE_AFTER_BIND,
272 vk::F12_DESCRIPTOR_BINDING_STORAGE_BUFFER_UPDATE_AFTER_BIND,
273 vk::F12_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING,
274 vk::F12_DESCRIPTOR_BINDING_PARTIALLY_BOUND,
275 vk::F12_RUNTIME_DESCRIPTOR_ARRAY,
276];
277const E13: &[usize] = &[
278 vk::F13_SHADER_DEMOTE_TO_HELPER_INVOCATION,
279 vk::F13_SUBGROUP_SIZE_CONTROL,
280 vk::F13_SYNCHRONIZATION2,
281 vk::F13_DYNAMIC_RENDERING,
282 vk::F13_MAINTENANCE4,
283];
284
285fn pick<const N: usize>(have: &[u32; N], want: &[usize]) -> [u32; N] {
286 let mut out = [0u32; N];
287 for &i in want {
288 out[i] = have[i];
289 }
290 out
291}
292
293impl Adapter {
294 pub fn create_device(&self, desc: &DeviceDesc) -> Result<Device> {
296 self.create_device_with(desc, &DeviceOptions::DEFAULT)
297 }
298
299 pub fn create_device_with(&self, desc: &DeviceDesc, opts: &DeviceOptions) -> Result<Device> {
302 if let Some(why) = self.info.missing {
303 return Err(GpuError::Unsupported(why));
304 }
305 let inst = &self.inst;
306 let level = if self.voll && desc.max_level == Level::Voll { Level::Voll } else { Level::Basis };
307 let voll = level == Level::Voll;
308 let v12 = self.api >= vk::API_VERSION_1_2;
309 let v13 = self.api >= vk::API_VERSION_1_3;
310 let mut e10 = pick(&self.f10, E10);
311 if !voll {
312 e10[vk::F10_MULTI_DRAW_INDIRECT] = 0;
313 }
314 let e11 = pick(&self.f11, E11);
315 let mut e12 = pick(&self.f12, E12);
316 if e12[vk::F12_VULKAN_MEMORY_MODEL_DEVICE_SCOPE] == 0 {
319 e12[vk::F12_VULKAN_MEMORY_MODEL] = 0;
320 }
321 if voll {
322 for &i in E12_VOLL {
323 e12[i] = self.f12[i];
324 }
325 }
326 let e13 = pick(&self.f13, E13);
327 let mut f13: vk::PhysicalDeviceVulkan13Features = vk::Zero::zero();
328 f13.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
329 f13.f = e13;
330 let mut f12: vk::PhysicalDeviceVulkan12Features = vk::Zero::zero();
331 f12.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
332 f12.f = e12;
333 let mut f11: vk::PhysicalDeviceVulkan11Features = vk::Zero::zero();
334 f11.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
335 f11.f = e11;
336 let mut dynr: vk::PhysicalDeviceOneFeature = vk::Zero::zero();
337 dynr.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
338 dynr.f = 1;
339 let mut tl: vk::PhysicalDeviceOneFeature = vk::Zero::zero();
340 tl.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES;
341 tl.f = 1;
342 let mut f2: vk::PhysicalDeviceFeatures2 = vk::Zero::zero();
343 f2.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
344 f2.f = e10;
345 let mut names: Vec<*const u8> = Vec::new();
346 if v12 {
348 if v13 {
349 f12.p_next = &mut f13 as *mut _ as *mut c_void;
350 } else {
351 f12.p_next = &mut dynr as *mut _ as *mut c_void;
352 names.push(b"VK_KHR_dynamic_rendering\0".as_ptr());
353 }
354 f11.p_next = &mut f12 as *mut _ as *mut c_void;
355 f2.p_next = &mut f11 as *mut _ as *mut c_void;
356 } else {
357 tl.p_next = &mut dynr as *mut _ as *mut c_void;
359 f2.p_next = &mut tl as *mut _ as *mut c_void;
360 names.push(b"VK_KHR_timeline_semaphore\0".as_ptr());
361 names.push(b"VK_KHR_create_renderpass2\0".as_ptr());
362 names.push(b"VK_KHR_depth_stencil_resolve\0".as_ptr());
363 names.push(b"VK_KHR_dynamic_rendering\0".as_ptr());
364 }
365 let swapchain = self.exts.swapchain;
366 if swapchain {
367 names.push(b"VK_KHR_swapchain\0".as_ptr());
368 }
369 let dmabuf = self.exts.dmabuf;
370 if dmabuf {
371 names.push(b"VK_KHR_external_memory_fd\0".as_ptr());
372 names.push(b"VK_EXT_external_memory_dma_buf\0".as_ptr());
373 names.push(b"VK_EXT_image_drm_format_modifier\0".as_ptr());
374 if !v12 {
375 names.push(b"VK_KHR_image_format_list\0".as_ptr());
376 }
377 }
378 let queue_foreign = dmabuf && self.exts.queue_foreign;
379 if queue_foreign {
380 names.push(b"VK_EXT_queue_family_foreign\0".as_ptr());
381 }
382 let prio = 1.0f32;
383 let qi = vk::DeviceQueueCreateInfo {
384 s_type: vk::STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
385 queue_family_index: self.family,
386 queue_count: 1,
387 p_queue_priorities: &prio,
388 ..vk::Zero::zero()
389 };
390 let off = plat::env("jfgui_GPU_COMPUTE").is_some_and(|v| v == "0" || v.eq_ignore_ascii_case("off"));
392 let cfam = self.compute_family.filter(|_| opts.compute_queue && !off);
393 let qis = [qi, vk::DeviceQueueCreateInfo { queue_family_index: cfam.map_or(0, |c| c.0), ..qi }];
394 let info = vk::DeviceCreateInfo {
395 s_type: vk::STRUCTURE_TYPE_DEVICE_CREATE_INFO,
396 p_next: &f2 as *const _ as *const c_void,
397 queue_create_info_count: 1 + cfam.is_some() as u32,
398 p_queue_create_infos: qis.as_ptr(),
399 enabled_extension_count: names.len() as u32,
400 pp_enabled_extension_names: names.as_ptr(),
401 ..vk::Zero::zero()
402 };
403 let mut dev: vk::Device = 0;
404 let r = unsafe { (inst.f.create_device)(self.pd, &info, core::ptr::null(), &mut dev) };
406 if r != vk::SUCCESS {
407 return Err(err(r));
408 }
409 let gdpa = inst.f.get_device_proc_addr;
410 let f = match vk::DeviceFns::load(&|n| unsafe { gdpa(dev, n.as_ptr()) }) {
412 Ok(f) => f,
413 Err(name) => {
414 let d = unsafe { gdpa(dev, b"vkDestroyDevice\0".as_ptr()) };
416 if d != 0 {
417 unsafe {
419 core::mem::transmute::<usize, unsafe extern "system" fn(vk::Device, *const c_void)>(d)(
420 dev,
421 core::ptr::null(),
422 )
423 };
424 }
425 return Err(GpuError::Unsupported(name));
426 }
427 };
428 let mut queue: vk::Queue = 0;
429 unsafe { (f.get_device_queue)(dev, self.family, 0, &mut queue) };
431 let ti = vk::SemaphoreTypeCreateInfo {
432 s_type: vk::STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
433 semaphore_type: vk::SEMAPHORE_TYPE_TIMELINE,
434 initial_value: 0,
435 ..vk::Zero::zero()
436 };
437 let si = vk::SemaphoreCreateInfo {
438 s_type: vk::STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
439 p_next: &ti as *const _ as *const c_void,
440 flags: 0,
441 };
442 let mut timeline = 0;
443 let r = unsafe { (f.create_semaphore)(dev, &si, core::ptr::null(), &mut timeline) };
445 if r != vk::SUCCESS {
446 unsafe { (f.destroy_device)(dev, core::ptr::null()) };
448 return Err(err(r));
449 }
450 let mut lane = None;
451 if let Some((family, ts_bits)) = cfam {
452 let mut cq: vk::Queue = 0;
453 let mut ct = 0;
454 let r = unsafe {
456 (f.get_device_queue)(dev, family, 0, &mut cq);
457 (f.create_semaphore)(dev, &si, core::ptr::null(), &mut ct)
458 };
459 if r != vk::SUCCESS {
460 unsafe {
462 (f.destroy_semaphore)(dev, timeline, core::ptr::null());
463 (f.destroy_device)(dev, core::ptr::null());
464 }
465 return Err(err(r));
466 }
467 lane = Some(Lane { queue: cq, family, timeline: ct, ts_bits, submitted: AtomicU64::new(0), completed: AtomicU64::new(0), qlock: SpinLock::new(()) });
468 }
469 let mut features = self.features;
470 if !voll {
471 features.bindless = false;
472 features.draw_indirect_count = false;
473 features.multi_draw_indirect = false;
474 }
475 let mut limits = self.limits;
476 if !voll {
477 limits.max_bindless_textures = 0;
478 limits.max_bindless_samplers = 0;
479 limits.max_bindless_buffers = 0;
480 limits.max_bindless_storage_textures = 0;
481 }
482 let ts_mask = match self.ts_bits {
483 0 => 0,
484 64.. => !0,
485 b => (1u64 << b) - 1,
486 };
487 let sh = Arc::new(Shared {
488 inst: inst.clone(),
489 pd: self.pd,
490 dev,
491 f,
492 queue,
493 family: self.family,
494 timeline,
495 info: self.info.clone(),
496 features,
497 limits,
498 level,
499 raw: self.raw,
500 ts_mask,
501 swapchain,
502 queue_foreign,
503 ts_base: AtomicU64::new(0),
504 host_query_reset: v12 && e12[vk::F12_HOST_QUERY_RESET] != 0,
505 maintenance4: v13 && e13[vk::F13_MAINTENANCE4] != 0,
506 lane,
507 lost: AtomicBool::new(false),
508 submitted: AtomicU64::new(0),
509 completed: AtomicU64::new(0),
510 qlock: SpinLock::new(()),
511 st: SpinLock::new(State {
512 mem: Allocator::new(self.mem),
513 garbage: Vec::new(),
514 free: Vec::new(),
515 cfree: Vec::new(),
516 busy: Vec::new(),
517 pools: Vec::new(),
518 upload: None,
519 ring: Ring::default(),
520 }),
521 });
522 let compute = sh.lane.as_ref().map(|_| ComputeQueue { sh: sh.clone() });
523 Ok(Device { queue: Queue { sh: sh.clone() }, compute, sh })
524 }
525}
526
527impl Shared {
528 #[inline]
530 pub fn check(&self) -> Result<()> {
531 if self.lost.load(Ordering::Relaxed) { Err(GpuError::DeviceLost) } else { Ok(()) }
532 }
533
534 pub fn vk(&self, r: vk::VkResult) -> Result<()> {
536 if r == vk::SUCCESS {
537 return Ok(());
538 }
539 if r == vk::ERROR_DEVICE_LOST {
540 self.lost.store(true, Ordering::Relaxed);
541 }
542 Err(err(r))
543 }
544
545 #[cfg_attr(jfgui_glibc, allow(dead_code))]
547 pub fn with_queue<R>(&self, f: impl FnOnce(vk::Queue) -> R) -> R {
548 let _q = self.qlock.lock();
549 f(self.queue)
550 }
551
552 #[cfg_attr(jfgui_glibc, allow(dead_code))]
555 pub fn queue_idle(&self) -> Result<()> {
556 let (r, v) = self.with_queue(|q| (unsafe { (self.f.queue_wait_idle)(q) }, self.submitted()));
559 self.vk(r)?;
560 self.completed.fetch_max(v, Ordering::AcqRel);
561 let mut st = self.st.lock();
562 self.collect(&mut st);
563 Ok(())
564 }
565
566 pub fn mark_lost(&self) {
567 self.lost.store(true, Ordering::Relaxed);
568 }
569
570 pub fn submitted(&self) -> u64 {
571 self.submitted.load(Ordering::Acquire)
572 }
573
574 fn lane_submitted(&self) -> u64 {
576 self.lane.as_ref().map_or(0, |l| l.submitted.load(Ordering::Acquire))
577 }
578
579 fn lane_refresh(&self) -> u64 {
581 let Some(l) = &self.lane else { return 0 };
582 let done = l.completed.load(Ordering::Acquire);
584 if l.submitted.load(Ordering::Acquire) <= done {
585 return done;
586 }
587 let mut v = 0u64;
588 let r = unsafe { (self.f.get_semaphore_counter_value)(self.dev, l.timeline, &mut v) };
590 if r != vk::SUCCESS {
591 if r == vk::ERROR_DEVICE_LOST {
592 self.lost.store(true, Ordering::Relaxed);
593 }
594 return l.completed.load(Ordering::Acquire);
595 }
596 l.completed.fetch_max(v, Ordering::AcqRel);
597 v
598 }
599
600 pub fn refresh(&self) -> u64 {
602 let mut v = 0u64;
603 let r = unsafe { (self.f.get_semaphore_counter_value)(self.dev, self.timeline, &mut v) };
605 if r != vk::SUCCESS {
606 if r == vk::ERROR_DEVICE_LOST {
607 self.lost.store(true, Ordering::Relaxed);
608 }
609 return self.completed.load(Ordering::Acquire);
610 }
611 self.completed.fetch_max(v, Ordering::AcqRel);
612 v
613 }
614
615 pub fn defer(&self, g: Garbage) {
620 let mut st = self.st.lock();
621 let named = st.upload.is_some() && matches!(g, Garbage::Buffer(..) | Garbage::Image(..));
622 let v = self.submitted() + named as u64;
623 let vc = self.lane_submitted();
625 let lane_done = self.lane.as_ref().is_none_or(|l| vc <= l.completed.load(Ordering::Acquire));
626 if (v <= self.completed.load(Ordering::Acquire) && lane_done) || self.lost.load(Ordering::Relaxed) {
627 self.destroy(&mut st, g);
628 } else {
629 st.garbage.push((v, vc, g));
630 }
631 }
632
633 fn destroy(&self, st: &mut State, g: Garbage) {
634 let (f, d, n) = (&self.f, self.dev, core::ptr::null());
635 unsafe {
638 match g {
639 Garbage::Buffer(h, a) => {
640 (f.destroy_buffer)(d, h, n);
641 st.mem.free(f, d, &a);
642 }
643 Garbage::Image(h, a) => {
644 (f.destroy_image)(d, h, n);
645 if let Some(a) = a {
646 st.mem.free(f, d, &a);
647 }
648 }
649 Garbage::View(h) => (f.destroy_image_view)(d, h, n),
650 Garbage::Sampler(h) => (f.destroy_sampler)(d, h, n),
651 Garbage::Shader(h) => (f.destroy_shader_module)(d, h, n),
652 Garbage::SetLayout(h) => (f.destroy_descriptor_set_layout)(d, h, n),
653 Garbage::PipeLayout(h) => (f.destroy_pipeline_layout)(d, h, n),
654 Garbage::Pipeline(h) => (f.destroy_pipeline)(d, h, n),
655 Garbage::Set(pool, set) => {
656 (f.free_descriptor_sets)(d, pool, 1, &set);
657 }
658 Garbage::Pool(h) => (f.destroy_descriptor_pool)(d, h, n),
659 Garbage::Query(h) => (f.destroy_query_pool)(d, h, n),
660 Garbage::Semaphore(h) => (f.destroy_semaphore)(d, h, n),
661 Garbage::Swapchain(h) => {
662 if let Some(ds) = f.destroy_swapchain_khr {
663 ds(d, h, n);
664 }
665 }
666 Garbage::Memory(h) => (f.free_memory)(d, h, n),
667 }
668 }
669 }
670
671 fn collect(&self, st: &mut State) {
673 if st.garbage.is_empty() && st.busy.is_empty() && st.ring.busy.is_empty() && st.ring.free.is_empty() {
674 return;
675 }
676 let lost = self.lost.load(Ordering::Relaxed);
677 let done = if lost { u64::MAX } else { self.refresh() };
678 let done_c = if lost { u64::MAX } else { self.lane_refresh() };
679 let mut i = 0;
680 while i < st.ring.busy.len() {
681 if st.ring.busy[i].0 <= done {
682 let (_, mut c) = st.ring.busy.swap_remove(i);
683 c.used = 0;
684 st.ring.free.push(c);
685 } else {
686 i += 1;
687 }
688 }
689 self.ring_trim(st);
690 let mut i = 0;
691 while i < st.busy.len() {
692 let v = st.busy[i].0;
693 let finished = if v & COMPUTE_ID != 0 { v & !COMPUTE_ID <= done_c } else { v <= done };
694 if finished {
695 let (_, s) = st.busy.swap_remove(i);
696 unsafe { (self.f.reset_command_pool)(self.dev, s.pool, 0) };
698 if s.compute { st.cfree.push(s) } else { st.free.push(s) }
699 } else {
700 i += 1;
701 }
702 }
703 let mut i = 0;
704 while i < st.garbage.len() {
705 if st.garbage[i].0 <= done && st.garbage[i].1 <= done_c {
706 let (_, _, g) = st.garbage.swap_remove(i);
707 self.destroy(st, g);
708 } else {
709 i += 1;
710 }
711 }
712 }
713
714 #[cfg_attr(not(jfgui_glibc), allow(dead_code))] pub fn take_slot(&self) -> Result<Slot> {
717 self.take_slot_for(false)
718 }
719
720 pub fn take_slot_for(&self, compute: bool) -> Result<Slot> {
722 self.check()?;
723 if compute && self.lane.is_none() {
724 return Err(GpuError::Unsupported("a compute queue"));
725 }
726 let slot = {
727 let mut st = self.st.lock();
728 let empty = if compute { st.cfree.is_empty() } else { st.free.is_empty() };
729 if empty {
730 self.collect(&mut st);
731 }
732 if compute { st.cfree.pop() } else { st.free.pop() }
733 };
734 let slot = match slot {
735 Some(s) => s,
736 None => self.new_slot(compute)?,
737 };
738 let bi = vk::CommandBufferBeginInfo {
739 s_type: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
740 flags: vk::COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
741 ..vk::Zero::zero()
742 };
743 let r = unsafe { (self.f.begin_command_buffer)(slot.cb, &bi) };
745 if let Err(e) = self.vk(r) {
746 self.give_slot(slot);
747 return Err(e);
748 }
749 Ok(slot)
750 }
751
752 fn new_slot(&self, compute: bool) -> Result<Slot> {
753 let family = match (&self.lane, compute) {
754 (Some(l), true) => l.family,
755 _ => self.family,
756 };
757 let pi = vk::CommandPoolCreateInfo {
758 s_type: vk::STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
759 flags: vk::COMMAND_POOL_CREATE_TRANSIENT_BIT,
760 queue_family_index: family,
761 ..vk::Zero::zero()
762 };
763 let mut pool = 0;
764 self.vk(unsafe { (self.f.create_command_pool)(self.dev, &pi, core::ptr::null(), &mut pool) })?;
766 let ai = vk::CommandBufferAllocateInfo {
767 s_type: vk::STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
768 command_pool: pool,
769 level: vk::COMMAND_BUFFER_LEVEL_PRIMARY,
770 command_buffer_count: 1,
771 ..vk::Zero::zero()
772 };
773 let mut cb = 0;
774 let r = unsafe { (self.f.allocate_command_buffers)(self.dev, &ai, &mut cb) };
776 if let Err(e) = self.vk(r) {
777 unsafe { (self.f.destroy_command_pool)(self.dev, pool, core::ptr::null()) };
779 return Err(e);
780 }
781 Ok(Slot { pool, cb, compute })
782 }
783
784 pub fn give_slot(&self, s: Slot) {
786 unsafe { (self.f.reset_command_pool)(self.dev, s.pool, 0) };
788 let mut st = self.st.lock();
789 if s.compute { st.cfree.push(s) } else { st.free.push(s) }
790 }
791
792 pub fn sharing(&self) -> Option<[u32; 2]> {
794 self.lane.as_ref().map(|l| [self.family, l.family])
795 }
796
797 fn ring_trim(&self, st: &mut State) {
802 let now = plat::time_us();
803 let keep_big = now.saturating_sub(st.ring.big_at) < BIG_KEEP_US;
804 let largest = st.ring.free.iter().map(|c| c.a.size).max().unwrap_or(0);
805 let mut small = 0;
806 let mut i = 0;
807 while i < st.ring.free.len() {
808 let size = st.ring.free[i].a.size;
809 let keep = if size >= CHUNK * 2 {
810 keep_big && size == largest && size <= st.ring.big_size.saturating_mul(BIG_KEEP_RATIO).max(CHUNK * 2)
811 } else {
812 small += 1;
813 small <= CHUNKS_FREE
814 };
815 if keep {
816 i += 1;
817 } else {
818 let c = st.ring.free.swap_remove(i);
819 self.destroy(st, Garbage::Buffer(c.buf, c.a));
820 }
821 }
822 }
823
824 fn ring_chunk(&self, st: &mut State, size: u64) -> Result<Chunk> {
827 let top = if size == CHUNK { CHUNK * 2 } else { u64::MAX };
828 let best = st.ring.free.iter().enumerate().filter(|(_, c)| c.a.size >= size && c.a.size < top).min_by_key(|(_, c)| c.a.size).map(|(i, _)| i);
829 if let Some(i) = best {
830 return Ok(st.ring.free.swap_remove(i));
831 }
832 let (buf, a) = self.raw_buffer(st, size, vk::BUFFER_USAGE_TRANSFER_SRC_BIT, MemoryKind::Upload)?;
833 Ok(Chunk { buf, a, used: 0 })
834 }
835
836 pub fn upload_cb(&self, st: &mut State) -> Result<vk::CommandBuffer> {
838 self.stage(st, 0)?;
839 Ok(st.upload.as_ref().map_or(0, |u| u.slot.cb))
840 }
841
842 fn stage(&self, st: &mut State, n: u64) -> Result<(vk::Handle, u64, usize)> {
845 if st.upload.is_none() {
846 let slot = match st.free.pop() {
848 Some(s) => s,
849 None => self.new_slot(false)?,
850 };
851 let bi = vk::CommandBufferBeginInfo {
852 s_type: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
853 flags: vk::COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
854 ..vk::Zero::zero()
855 };
856 let r = unsafe { (self.f.begin_command_buffer)(slot.cb, &bi) };
858 if let Err(e) = self.vk(r) {
859 st.free.push(slot);
860 return Err(e);
861 }
862 st.upload = Some(Upload { slot, retired: Vec::new() });
863 }
864 if n == 0 {
865 return Ok((0, 0, 0));
866 }
867 if n > CHUNK / 2 {
868 st.ring.big_at = plat::time_us();
870 st.ring.big_size = n;
871 let size = (n + 0xFFFF) & !0xFFFF;
872 let mut c = self.ring_chunk(st, size.max(CHUNK * 2))?;
873 c.used = n;
874 let (buf, ptr) = (c.buf, c.a.ptr);
875 st.upload.as_mut().unwrap_or_else(|| unreachable!()).retired.push(c);
876 return Ok((buf, 0, ptr));
877 }
878 let room = st.ring.cur.as_ref().is_some_and(|c| c.used + n <= c.a.size);
879 if !room {
880 if let Some(c) = st.ring.cur.take() {
881 if st.ring.cur_open {
882 st.upload.as_mut().unwrap_or_else(|| unreachable!()).retired.push(c);
883 } else {
884 let v = st.ring.cur_value;
885 st.ring.busy.push((v, c));
886 }
887 }
888 let c = self.ring_chunk(st, CHUNK)?;
889 st.ring.cur = Some(c);
890 st.ring.cur_open = false;
891 }
892 st.ring.cur_open = true;
893 let c = st.ring.cur.as_mut().unwrap_or_else(|| unreachable!());
894 let off = c.used;
895 c.used = (off + n + 15) & !15;
896 Ok((c.buf, off, c.a.ptr + off as usize))
897 }
898
899 pub fn raw_buffer(&self, st: &mut State, size: u64, usage: u32, kind: MemoryKind) -> Result<(vk::Handle, Alloc)> {
901 let fams = self.sharing();
903 let bi = vk::BufferCreateInfo {
904 s_type: vk::STRUCTURE_TYPE_BUFFER_CREATE_INFO,
905 size,
906 usage,
907 sharing_mode: if fams.is_some() { vk::SHARING_MODE_CONCURRENT } else { vk::SHARING_MODE_EXCLUSIVE },
908 queue_family_index_count: if fams.is_some() { 2 } else { 0 },
909 p_queue_family_indices: fams.as_ref().map_or(core::ptr::null(), |f| f.as_ptr()),
910 ..vk::Zero::zero()
911 };
912 let mut buf = 0;
913 self.vk(unsafe { (self.f.create_buffer)(self.dev, &bi, core::ptr::null(), &mut buf) })?;
915 let mut req: vk::MemoryRequirements = vk::Zero::zero();
916 unsafe { (self.f.get_buffer_memory_requirements)(self.dev, buf, &mut req) };
918 let a = match st.mem.alloc(&self.f, self.dev, &req, kind, true) {
919 Ok(a) => a,
920 Err(e) => {
921 unsafe { (self.f.destroy_buffer)(self.dev, buf, core::ptr::null()) };
923 return Err(e);
924 }
925 };
926 let r = unsafe { (self.f.bind_buffer_memory)(self.dev, buf, a.mem, a.offset) };
928 if let Err(e) = self.vk(r) {
929 unsafe { (self.f.destroy_buffer)(self.dev, buf, core::ptr::null()) };
931 st.mem.free(&self.f, self.dev, &a);
932 return Err(e);
933 }
934 Ok((buf, a))
935 }
936
937 pub fn submit(&self, cbs: &[vk::CommandBuffer], slots: Vec<Slot>, wait: Option<(vk::Handle, u32)>,
940 signal: Option<vk::Handle>) -> Result<u64> {
941 self.submit_on(false, cbs, slots, wait, &[], signal)
942 }
943
944 fn wait_of(&self, id: u64) -> Result<(vk::Handle, u64)> {
946 if id & COMPUTE_ID == 0 {
947 return if id <= self.submitted() { Ok((self.timeline, id)) } else { Err(GpuError::Invalid("submit_after: a submission not made yet")) };
948 }
949 match &self.lane {
950 Some(l) if id & !COMPUTE_ID <= l.submitted.load(Ordering::Acquire) => Ok((l.timeline, id & !COMPUTE_ID)),
951 Some(_) => Err(GpuError::Invalid("submit_after: a submission not made yet")),
952 None => Err(GpuError::Invalid("submit_after: an id of a compute queue the device does not have")),
953 }
954 }
955
956 pub fn submit_on(&self, compute: bool, cbs: &[vk::CommandBuffer], slots: Vec<Slot>, wait: Option<(vk::Handle, u32)>, after: &[u64],
961 signal: Option<vk::Handle>) -> Result<u64> {
962 let mut slots = slots;
963 let fine = self.check().and_then(|_| {
964 if slots.iter().any(|s| s.compute != compute) {
965 return Err(GpuError::Invalid("submit: a command buffer of the other queue's family (Device::encoder / ComputeQueue::encoder)"));
966 }
967 if compute && (self.lane.is_none() || wait.is_some() || signal.is_some()) {
968 return Err(GpuError::Invalid("submit: no compute queue, or a semaphore on it"));
969 }
970 Ok(())
971 });
972 let mut waits: Vec<(vk::Handle, u64)> = Vec::with_capacity(after.len() + 1);
973 let fine = fine.and_then(|_| {
974 for &id in after {
975 waits.push(self.wait_of(id)?);
976 }
977 Ok(())
978 });
979 if let Err(e) = fine {
980 for s in slots {
981 self.give_slot(s);
982 }
983 return Err(e);
984 }
985 if compute {
986 return self.submit_lane(cbs, slots, waits);
987 }
988 let up = self.st.lock().upload.take();
989 let mut all: Vec<vk::CommandBuffer> = Vec::with_capacity(cbs.len() + 1);
990 let mut chunks: Vec<Chunk> = Vec::new();
991 let uploads = up.is_some();
992 if let Some(u) = up {
993 let mb = vk::MemoryBarrier {
994 s_type: vk::STRUCTURE_TYPE_MEMORY_BARRIER,
995 src_access_mask: vk::ACCESS_TRANSFER_WRITE_BIT,
996 dst_access_mask: vk::ACCESS_MEMORY_READ_BIT | vk::ACCESS_MEMORY_WRITE_BIT,
997 ..vk::Zero::zero()
998 };
999 unsafe {
1001 (self.f.cmd_pipeline_barrier)(u.slot.cb, vk::PIPELINE_STAGE_TRANSFER_BIT,
1002 vk::PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &mb, 0, core::ptr::null(), 0, core::ptr::null());
1003 }
1004 let r = unsafe { (self.f.end_command_buffer)(u.slot.cb) };
1006 all.push(u.slot.cb);
1007 slots.push(u.slot);
1008 chunks = u.retired;
1009 if let Err(e) = self.vk(r) {
1010 self.fail_submit(slots, chunks);
1011 return Err(e);
1012 }
1013 }
1014 all.extend_from_slice(cbs);
1015 let mut ws: Vec<vk::Handle> = Vec::with_capacity(waits.len() + 1);
1017 let mut wv: Vec<u64> = Vec::with_capacity(waits.len() + 1);
1018 let mut wst: Vec<u32> = Vec::with_capacity(waits.len() + 1);
1019 if let Some((s, st)) = wait {
1020 ws.push(s);
1021 wv.push(0);
1022 wst.push(st);
1023 }
1024 for &(s, v) in &waits {
1025 ws.push(s);
1026 wv.push(v);
1027 wst.push(vk::PIPELINE_STAGE_ALL_COMMANDS_BIT);
1028 }
1029 let q = self.qlock.lock();
1030 let value = self.submitted.load(Ordering::Relaxed) + 1;
1031 let sems = [self.timeline, signal.unwrap_or(0)];
1032 let values = [value, 0];
1033 let nsig = 1 + signal.is_some() as u32;
1034 let tsi = vk::TimelineSemaphoreSubmitInfo {
1035 s_type: vk::STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
1036 wait_semaphore_value_count: wv.len() as u32,
1037 p_wait_semaphore_values: wv.as_ptr(),
1038 signal_semaphore_value_count: nsig,
1039 p_signal_semaphore_values: values.as_ptr(),
1040 ..vk::Zero::zero()
1041 };
1042 let si = vk::SubmitInfo {
1043 s_type: vk::STRUCTURE_TYPE_SUBMIT_INFO,
1044 p_next: &tsi as *const _ as *const c_void,
1045 wait_semaphore_count: ws.len() as u32,
1046 p_wait_semaphores: ws.as_ptr(),
1047 p_wait_dst_stage_mask: wst.as_ptr(),
1048 command_buffer_count: all.len() as u32,
1049 p_command_buffers: all.as_ptr(),
1050 signal_semaphore_count: nsig,
1051 p_signal_semaphores: sems.as_ptr(),
1052 };
1053 let r = unsafe { (self.f.queue_submit)(self.queue, 1, &si, 0) };
1055 if r == vk::SUCCESS {
1056 self.submitted.store(value, Ordering::Release);
1057 }
1058 drop(q);
1059 if let Err(e) = self.vk(r) {
1060 self.fail_submit(slots, chunks);
1061 return Err(e);
1062 }
1063 let mut st = self.st.lock();
1064 for s in slots {
1065 st.busy.push((value, s));
1066 }
1067 for c in chunks {
1068 st.ring.busy.push((value, c));
1069 }
1070 if uploads && st.ring.cur_open {
1071 st.ring.cur_value = value;
1072 st.ring.cur_open = false;
1073 }
1074 self.collect(&mut st);
1075 Ok(value)
1076 }
1077
1078 fn submit_lane(&self, cbs: &[vk::CommandBuffer], slots: Vec<Slot>, mut waits: Vec<(vk::Handle, u64)>) -> Result<u64> {
1081 let Some(l) = &self.lane else { return Err(GpuError::Invalid("no compute queue")) };
1082 if self.st.lock().upload.is_some() {
1083 match self.submit_on(false, &[], Vec::new(), None, &[], None) {
1084 Ok(v) => waits.push((self.timeline, v)),
1085 Err(e) => {
1086 for s in slots {
1087 self.give_slot(s);
1088 }
1089 return Err(e);
1090 }
1091 }
1092 }
1093 let wv: Vec<u64> = waits.iter().map(|w| w.1).collect();
1094 let ws: Vec<vk::Handle> = waits.iter().map(|w| w.0).collect();
1095 let wst: Vec<u32> = ws.iter().map(|_| vk::PIPELINE_STAGE_ALL_COMMANDS_BIT).collect();
1096 let q = l.qlock.lock();
1097 let value = l.submitted.load(Ordering::Relaxed) + 1;
1098 let tsi = vk::TimelineSemaphoreSubmitInfo {
1099 s_type: vk::STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
1100 wait_semaphore_value_count: wv.len() as u32,
1101 p_wait_semaphore_values: wv.as_ptr(),
1102 signal_semaphore_value_count: 1,
1103 p_signal_semaphore_values: &value,
1104 ..vk::Zero::zero()
1105 };
1106 let si = vk::SubmitInfo {
1107 s_type: vk::STRUCTURE_TYPE_SUBMIT_INFO,
1108 p_next: &tsi as *const _ as *const c_void,
1109 wait_semaphore_count: ws.len() as u32,
1110 p_wait_semaphores: ws.as_ptr(),
1111 p_wait_dst_stage_mask: wst.as_ptr(),
1112 command_buffer_count: cbs.len() as u32,
1113 p_command_buffers: cbs.as_ptr(),
1114 signal_semaphore_count: 1,
1115 p_signal_semaphores: &l.timeline,
1116 };
1117 let r = unsafe { (self.f.queue_submit)(l.queue, 1, &si, 0) };
1119 if r == vk::SUCCESS {
1120 l.submitted.store(value, Ordering::Release);
1121 }
1122 drop(q);
1123 if let Err(e) = self.vk(r) {
1124 for s in slots {
1125 self.give_slot(s);
1126 }
1127 return Err(e);
1128 }
1129 let mut st = self.st.lock();
1130 for s in slots {
1131 st.busy.push((value | COMPUTE_ID, s));
1132 }
1133 self.collect(&mut st);
1134 Ok(value | COMPUTE_ID)
1135 }
1136
1137 pub fn wait_id(&self, id: u64, timeout_ns: u64) -> Result<bool> {
1139 if id & COMPUTE_ID == 0 {
1140 return self.wait_value(id, timeout_ns);
1141 }
1142 self.check()?;
1143 let Some(l) = &self.lane else { return Err(GpuError::Invalid("wait: an id of a compute queue the device does not have")) };
1144 let v = id & !COMPUTE_ID;
1145 if v <= l.completed.load(Ordering::Acquire) {
1146 return Ok(true);
1147 }
1148 if v > l.submitted.load(Ordering::Acquire) {
1149 return Err(GpuError::Invalid("wait: not submitted yet"));
1150 }
1151 let wi = vk::SemaphoreWaitInfo {
1152 s_type: vk::STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
1153 semaphore_count: 1,
1154 p_semaphores: &l.timeline,
1155 p_values: &v,
1156 ..vk::Zero::zero()
1157 };
1158 let r = unsafe { (self.f.wait_semaphores)(self.dev, &wi, timeout_ns) };
1160 if r == vk::TIMEOUT {
1161 return Ok(false);
1162 }
1163 self.vk(r)?;
1164 l.completed.fetch_max(v, Ordering::AcqRel);
1165 let mut st = self.st.lock();
1166 self.collect(&mut st);
1167 Ok(true)
1168 }
1169
1170 fn fail_submit(&self, slots: Vec<Slot>, chunks: Vec<Chunk>) {
1171 for s in slots {
1172 self.give_slot(s);
1173 }
1174 let mut st = self.st.lock();
1175 st.ring.cur_open = false; for c in chunks {
1177 self.destroy(&mut st, Garbage::Buffer(c.buf, c.a));
1178 }
1179 }
1180
1181 pub fn wait_value(&self, v: u64, timeout_ns: u64) -> Result<bool> {
1183 self.check()?;
1184 if v <= self.completed.load(Ordering::Acquire) {
1185 return Ok(true);
1186 }
1187 if v > self.submitted() {
1188 return Err(GpuError::Invalid("wait: not submitted yet"));
1189 }
1190 let wi = vk::SemaphoreWaitInfo {
1191 s_type: vk::STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
1192 semaphore_count: 1,
1193 p_semaphores: &self.timeline,
1194 p_values: &v,
1195 ..vk::Zero::zero()
1196 };
1197 let r = unsafe { (self.f.wait_semaphores)(self.dev, &wi, timeout_ns) };
1199 if r == vk::TIMEOUT {
1200 return Ok(false);
1201 }
1202 self.vk(r)?;
1203 self.completed.fetch_max(v, Ordering::AcqRel);
1204 let mut st = self.st.lock();
1205 self.collect(&mut st);
1206 Ok(true)
1207 }
1208
1209 pub fn alloc_set(&self, layout: vk::Handle, needs: &[vk::DescriptorPoolSize]) -> Result<(vk::Handle, vk::Handle)> {
1211 let mut st = self.st.lock();
1212 let alloc = |pool: vk::Handle| {
1213 let ai = vk::DescriptorSetAllocateInfo {
1214 s_type: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1215 descriptor_pool: pool,
1216 descriptor_set_count: 1,
1217 p_set_layouts: &layout,
1218 ..vk::Zero::zero()
1219 };
1220 let mut set = 0;
1221 let r = unsafe { (self.f.allocate_descriptor_sets)(self.dev, &ai, &mut set) };
1223 (r, set)
1224 };
1225 for &pool in st.pools.iter().rev() {
1226 let (r, set) = alloc(pool);
1227 if r == vk::SUCCESS {
1228 return Ok((pool, set));
1229 }
1230 if r != vk::ERROR_OUT_OF_POOL_MEMORY && r != vk::ERROR_FRAGMENTED_POOL {
1231 self.vk(r)?;
1232 }
1233 }
1234 let mut sizes: Vec<vk::DescriptorPoolSize> = [
1236 (vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER, 256),
1237 (vk::DESCRIPTOR_TYPE_STORAGE_BUFFER, 512),
1238 (vk::DESCRIPTOR_TYPE_SAMPLED_IMAGE, 512),
1239 (vk::DESCRIPTOR_TYPE_STORAGE_IMAGE, 128),
1240 (vk::DESCRIPTOR_TYPE_SAMPLER, 256),
1241 ]
1242 .iter()
1243 .map(|&(t, n)| vk::DescriptorPoolSize { type_: t, descriptor_count: n })
1244 .collect();
1245 for s in sizes.iter_mut() {
1246 let need: u32 = needs.iter().filter(|x| x.type_ == s.type_).map(|x| x.descriptor_count).sum();
1247 s.descriptor_count = s.descriptor_count.max(need.saturating_mul(64));
1248 }
1249 let pi = vk::DescriptorPoolCreateInfo {
1250 s_type: vk::STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1251 flags: vk::DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
1252 max_sets: 256,
1253 pool_size_count: sizes.len() as u32,
1254 p_pool_sizes: sizes.as_ptr(),
1255 ..vk::Zero::zero()
1256 };
1257 let mut pool = 0;
1258 self.vk(unsafe { (self.f.create_descriptor_pool)(self.dev, &pi, core::ptr::null(), &mut pool) })?;
1260 st.pools.push(pool);
1261 let (r, set) = alloc(pool);
1262 self.vk(r)?;
1263 Ok((pool, set))
1264 }
1265}
1266
1267impl Drop for Shared {
1268 fn drop(&mut self) {
1269 let (f, d, n) = (&self.f, self.dev, core::ptr::null());
1270 unsafe {
1273 (f.device_wait_idle)(d);
1274 let mut st = self.st.lock();
1275 if let Some(u) = st.upload.take() {
1276 for c in u.retired {
1277 st.garbage.push((0, 0, Garbage::Buffer(c.buf, c.a)));
1278 }
1279 st.free.push(u.slot);
1280 }
1281 let ring = core::mem::take(&mut st.ring);
1282 for c in ring.cur.into_iter().chain(ring.free).chain(ring.busy.into_iter().map(|(_, c)| c)) {
1283 st.garbage.push((0, 0, Garbage::Buffer(c.buf, c.a)));
1284 }
1285 let garbage = core::mem::take(&mut st.garbage);
1286 for (_, _, g) in garbage {
1287 self.destroy(&mut st, g);
1288 }
1289 for (_, s) in core::mem::take(&mut st.busy) {
1290 st.free.push(s);
1291 }
1292 let cfree = core::mem::take(&mut st.cfree);
1293 for s in st.free.drain(..).chain(cfree) {
1294 (f.destroy_command_pool)(d, s.pool, n);
1295 }
1296 for p in st.pools.drain(..) {
1297 (f.destroy_descriptor_pool)(d, p, n);
1298 }
1299 st.mem.destroy_all(f, d);
1300 (f.destroy_semaphore)(d, self.timeline, n);
1301 if let Some(l) = &self.lane {
1302 (f.destroy_semaphore)(d, l.timeline, n);
1303 }
1304 drop(st);
1305 (f.destroy_device)(d, n);
1306 }
1307 }
1308}
1309
1310impl Device {
1311 pub fn queue(&self) -> &Queue {
1312 &self.queue
1313 }
1314 pub fn compute_queue(&self) -> Option<&ComputeQueue> {
1318 self.compute.as_ref()
1319 }
1320 pub fn info(&self) -> &AdapterInfo {
1321 &self.sh.info
1322 }
1323 pub fn features(&self) -> &Features {
1325 &self.sh.features
1326 }
1327 pub fn limits(&self) -> &Limits {
1328 &self.sh.limits
1329 }
1330 pub fn level(&self) -> Level {
1331 self.sh.level
1332 }
1333 pub fn is_lost(&self) -> bool {
1335 self.sh.check().is_err()
1336 }
1337 pub fn test_lose(&self) {
1341 let _ = self.wait_idle();
1342 self.sh.mark_lost();
1343 }
1344 pub fn validating(&self) -> bool {
1346 self.sh.inst.validate
1347 }
1348 pub fn poll(&self) -> Result<()> {
1350 self.sh.check()?;
1351 let mut st = self.sh.st.lock();
1352 self.sh.collect(&mut st);
1353 drop(st);
1354 self.sh.check()
1355 }
1356 pub fn wait(&self, id: SubmitId, timeout_ns: u64) -> Result<bool> {
1358 self.sh.wait_id(id.0, timeout_ns)
1359 }
1360 pub fn wait_idle(&self) -> Result<()> {
1362 let v = self.sh.submitted();
1363 let vc = self.sh.lane_submitted();
1364 if self.sh.wait_value(v, 10_000_000_000)? && (vc == 0 || self.sh.wait_id(vc | COMPUTE_ID, 10_000_000_000)?) { Ok(()) } else { Err(GpuError::Timeout) }
1365 }
1366 pub fn completed(&self) -> SubmitId {
1368 SubmitId(self.sh.refresh())
1369 }
1370 pub fn is_done(&self, id: SubmitId) -> bool {
1372 if id.0 & COMPUTE_ID != 0 {
1373 return self.sh.lane_refresh() >= id.0 & !COMPUTE_ID;
1374 }
1375 self.sh.refresh() >= id.0
1376 }
1377 pub fn memory_reserved(&self) -> u64 {
1379 self.sh.st.lock().mem.reserved
1380 }
1381}
1382
1383impl Queue {
1384 pub fn submit<'a, I: IntoIterator<Item = crate::CommandBuffer<'a>>>(&self, cmds: I) -> Result<SubmitId> {
1386 let mut cbs = Vec::new();
1387 let mut slots = Vec::new();
1388 for c in cmds {
1389 let s = c.into_slot();
1390 cbs.push(s.cb);
1391 slots.push(s);
1392 }
1393 self.sh.submit(&cbs, slots, None, None).map(SubmitId)
1394 }
1395
1396 pub fn submit_after<'a, I: IntoIterator<Item = crate::CommandBuffer<'a>>>(&self, wait: &[SubmitId], cmds: I) -> Result<SubmitId> {
1399 let (cbs, slots) = split_cmds(cmds);
1400 let after: Vec<u64> = wait.iter().map(|w| w.0).collect();
1401 self.sh.submit_on(false, &cbs, slots, None, &after, None).map(SubmitId)
1402 }
1403
1404 pub fn flush(&self) -> Result<SubmitId> {
1406 self.sh.submit(&[], Vec::new(), None, None).map(SubmitId)
1407 }
1408
1409 pub fn write_buffer<T: Pod>(&self, buf: &crate::Buffer, offset: u64, data: &[T]) -> Result<()> {
1411 let bytes = crate::bytes_of(data);
1412 let n = bytes.len() as u64;
1413 if offset.checked_add(n).is_none_or(|e| e > buf.size()) {
1414 return Err(GpuError::Invalid("write_buffer: range outside the buffer"));
1415 }
1416 if n == 0 {
1417 return Ok(());
1418 }
1419 let sh = &self.sh;
1420 sh.check()?;
1421 let mut st = sh.st.lock();
1422 let (sbuf, soff, ptr) = sh.stage(&mut st, n)?;
1423 let cb = st.upload.as_ref().map_or(0, |u| u.slot.cb);
1424 unsafe {
1427 core::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr as *mut u8, bytes.len());
1428 let region = vk::BufferCopy { src_offset: soff, dst_offset: offset, size: n };
1429 (sh.f.cmd_copy_buffer)(cb, sbuf, buf.handle(), 1, ®ion);
1430 }
1431 Ok(())
1432 }
1433
1434 pub fn write_texture(&self, dst: &TextureRegion, data: &[u8], layout: DataLayout, before: Layout,
1437 after: Layout) -> Result<()> {
1438 let t = dst.texture;
1439 let copy = crate::vk_res::copy_region(dst, &layout, data.len() as u64)?;
1440 let need = copy.1;
1441 let sh = &self.sh;
1442 sh.check()?;
1443 let mut st = sh.st.lock();
1444 let (sbuf, soff, ptr) = sh.stage(&mut st, need)?;
1445 let cb = st.upload.as_ref().map_or(0, |u| u.slot.cb);
1446 let mut region = copy.0;
1447 region.buffer_offset = soff;
1448 let range = crate::vk_res::subresources(t, dst.mip, 1, dst.base_layer, dst.layers);
1449 unsafe {
1452 core::ptr::copy_nonoverlapping(data.as_ptr().add(layout.offset as usize), ptr as *mut u8, need as usize);
1453 crate::vk_cmd::image_barrier(&sh.f, cb, t.image(), range, before, Layout::CopyDst);
1454 (sh.f.cmd_copy_buffer_to_image)(cb, sbuf, t.image(), vk::IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
1455 crate::vk_cmd::image_barrier(&sh.f, cb, t.image(), range, Layout::CopyDst, after);
1456 }
1457 Ok(())
1458 }
1459
1460 pub fn write_texture_rects(&self, t: &crate::Texture, rects: &[[i32; 4]], data: &[u8], stride: u32, before: Layout,
1465 after: Layout) -> Result<()> {
1466 let f = t.format();
1467 let bb = f.block_bytes() as u64;
1468 if f.is_compressed() || f.is_depth() || t.depth() != 1 {
1469 return Err(GpuError::Invalid("write_texture_rects: an uncompressed 2D colour texture"));
1470 }
1471 let (tw, th) = (t.width() as i32, t.height() as i32);
1472 if (stride as u64) < tw as u64 * bb || (data.len() as u64) < stride as u64 * th as u64 {
1473 return Err(GpuError::Invalid("write_texture_rects: data smaller than the texture"));
1474 }
1475 self.write_texture_rects_at(t, rects, (0, 0), data, stride, before, after)
1476 }
1477
1478 #[allow(clippy::too_many_arguments)]
1482 pub fn write_texture_rects_at(&self, t: &crate::Texture, rects: &[[i32; 4]], origin: (i32, i32), data: &[u8], stride: u32, before: Layout,
1483 after: Layout) -> Result<()> {
1484 let f = t.format();
1485 let bb = f.block_bytes() as u64;
1486 if f.is_compressed() || f.is_depth() || t.depth() != 1 {
1487 return Err(GpuError::Invalid("write_texture_rects: an uncompressed 2D colour texture"));
1488 }
1489 let (tw, th) = (t.width() as i32, t.height() as i32);
1490 if stride == 0 {
1491 return Err(GpuError::Invalid("write_texture_rects: stride 0"));
1492 }
1493 let (iw, ih) = ((stride as u64 / bb).min(i32::MAX as u64) as i64, (data.len() as u64 / stride as u64).min(i32::MAX as u64) as i64);
1495 let mut regions: Vec<vk::BufferImageCopy> = Vec::with_capacity(rects.len());
1496 let mut total = 0u64;
1497 let sub = crate::vk_res::subresources(t, 0, 1, 0, 1);
1498 let (ox, oy) = (origin.0 as i64, origin.1 as i64);
1499 for r in rects {
1500 let x0 = (r[0] as i64 - ox).max(0).max(-ox);
1502 let y0 = (r[1] as i64 - oy).max(0).max(-oy);
1503 let x1 = (r[0] as i64 + r[2] as i64 - ox).min(tw as i64).min(iw - ox);
1504 let y1 = (r[1] as i64 + r[3] as i64 - oy).min(th as i64).min(ih - oy);
1505 if x1 <= x0 || y1 <= y0 {
1506 continue;
1507 }
1508 let (x0, y0, x1, y1) = (x0 as i32, y0 as i32, x1 as i32, y1 as i32);
1509 let (w, h) = ((x1 - x0) as u32, (y1 - y0) as u32);
1510 regions.push(vk::BufferImageCopy {
1511 buffer_offset: total,
1512 buffer_row_length: w,
1513 buffer_image_height: h,
1514 image_subresource: vk::ImageSubresourceLayers { aspect_mask: sub.aspect_mask, mip_level: 0, base_array_layer: 0, layer_count: 1 },
1515 image_offset: vk::Offset3D { x: x0, y: y0, z: 0 },
1516 image_extent: vk::Extent3D { width: w, height: h, depth: 1 },
1517 });
1518 total += w as u64 * h as u64 * bb;
1519 }
1520 if regions.is_empty() {
1521 return Ok(());
1522 }
1523 let sh = &self.sh;
1524 sh.check()?;
1525 let mut st = sh.st.lock();
1526 let (sbuf, soff, ptr) = sh.stage(&mut st, total)?;
1527 let cb = st.upload.as_ref().map_or(0, |u| u.slot.cb);
1528 for g in regions.iter_mut() {
1529 let (x, y) = ((g.image_offset.x as i64 + ox) as usize, (g.image_offset.y as i64 + oy) as usize);
1530 let (w, h) = (g.image_extent.width as usize, g.image_extent.height as usize);
1531 let row = w * bb as usize;
1532 let mut dst = ptr + g.buffer_offset as usize;
1533 for yy in y..y + h {
1534 let from = yy * stride as usize + x * bb as usize;
1535 unsafe { core::ptr::copy_nonoverlapping(data.as_ptr().add(from), dst as *mut u8, row) };
1538 dst += row;
1539 }
1540 g.buffer_offset += soff;
1541 }
1542 unsafe {
1545 crate::vk_cmd::image_barrier(&sh.f, cb, t.image(), sub, before, Layout::CopyDst);
1546 (sh.f.cmd_copy_buffer_to_image)(cb, sbuf, t.image(), vk::IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regions.len() as u32, regions.as_ptr());
1547 crate::vk_cmd::image_barrier(&sh.f, cb, t.image(), sub, Layout::CopyDst, after);
1548 }
1549 Ok(())
1550 }
1551
1552 pub fn read_buffer<T: Pod>(&self, buf: &crate::Buffer, offset: u64, out: &mut [T]) -> Result<()> {
1555 let n = core::mem::size_of_val(out) as u64;
1556 if offset.checked_add(n).is_none_or(|e| e > buf.size()) {
1557 return Err(GpuError::Invalid("read_buffer: range outside the buffer"));
1558 }
1559 if buf.memory() == MemoryKind::Readback {
1560 let id = self.flush()?;
1561 self.sh.wait_value(id.0, u64::MAX)?;
1562 return buf.read(offset, out);
1563 }
1564 let dev = Device { sh: self.sh.clone(), queue: self.clone(), compute: None };
1565 let rb = dev.create_buffer(&crate::BufferDesc { size: n.max(4), usage: crate::BufferUsage::NONE, memory: MemoryKind::Readback })?;
1566 let mut enc = dev.encoder()?;
1567 enc.copy_buffer(buf, offset, &rb, 0, n);
1568 let id = self.submit([enc.finish()?])?;
1569 if !self.sh.wait_value(id.0, 10_000_000_000)? {
1570 return Err(GpuError::Timeout);
1571 }
1572 rb.read(0, out)
1573 }
1574}
1575
1576fn split_cmds<'a, I: IntoIterator<Item = crate::CommandBuffer<'a>>>(cmds: I) -> (Vec<vk::CommandBuffer>, Vec<Slot>) {
1578 let mut cbs = Vec::new();
1579 let mut slots = Vec::new();
1580 for c in cmds {
1581 let s = c.into_slot();
1582 cbs.push(s.cb);
1583 slots.push(s);
1584 }
1585 (cbs, slots)
1586}
1587
1588impl ComputeQueue {
1589 pub fn encoder(&self) -> Result<crate::CommandEncoder<'_>> {
1592 crate::vk_cmd::CommandEncoder::of(&self.sh, true)
1593 }
1594
1595 pub fn submit<'a, I: IntoIterator<Item = crate::CommandBuffer<'a>>>(&self, cmds: I) -> Result<SubmitId> {
1598 self.submit_after(&[], cmds)
1599 }
1600
1601 pub fn submit_after<'a, I: IntoIterator<Item = crate::CommandBuffer<'a>>>(&self, wait: &[SubmitId], cmds: I) -> Result<SubmitId> {
1604 let (cbs, slots) = split_cmds(cmds);
1605 let after: Vec<u64> = wait.iter().map(|w| w.0).collect();
1606 self.sh.submit_on(true, &cbs, slots, None, &after, None).map(SubmitId)
1607 }
1608}