1use alloc::sync::Arc;
47use alloc::vec::Vec;
48use core::ffi::c_void;
49use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
50
51use rt::sync::SpinLock;
52
53use crate::vk_ffi as vk;
54use crate::vk_inst::{Adapter, InstShared, err};
55use crate::vk_mem::{Alloc, Allocator};
56use crate::{AdapterInfo, DataLayout, DeviceDesc, Features, GpuError, Layout, Level, Limits, MemoryKind, Pod, Result,
57 SubmitId, TextureRegion};
58
59pub(crate) enum Garbage {
61 Buffer(vk::Handle, Alloc),
62 Image(vk::Handle, Option<Alloc>),
63 View(vk::Handle),
64 Sampler(vk::Handle),
65 Shader(vk::Handle),
66 SetLayout(vk::Handle),
67 PipeLayout(vk::Handle),
68 Pipeline(vk::Handle),
69 Set(vk::Handle, vk::Handle),
70 Pool(vk::Handle),
71 Query(vk::Handle),
72 #[cfg_attr(jfgui_glibc, allow(dead_code))] Semaphore(vk::Handle),
74 #[cfg_attr(jfgui_glibc, allow(dead_code))]
75 Swapchain(vk::Handle),
76 #[cfg_attr(not(jfgui_glibc), allow(dead_code))] Memory(vk::Handle),
78}
79
80pub(crate) struct Slot {
82 pub pool: vk::Handle,
83 pub cb: vk::CommandBuffer,
84}
85
86struct Chunk {
88 buf: vk::Handle,
89 a: Alloc,
90 used: u64, }
92
93struct Upload {
96 slot: Slot,
97 retired: Vec<Chunk>,
98}
99
100#[derive(Default)]
102struct Ring {
103 cur: Option<Chunk>, cur_value: u64, cur_open: bool, busy: Vec<(u64, Chunk)>, free: Vec<Chunk>,
108 big_at: u64, big_size: u64, }
111
112pub(crate) struct State {
113 pub mem: Allocator,
114 garbage: Vec<(u64, Garbage)>,
115 free: Vec<Slot>,
116 busy: Vec<(u64, Slot)>,
117 pools: Vec<vk::Handle>, upload: Option<Upload>,
119 ring: Ring,
120}
121
122const CHUNK: u64 = 256 << 10;
124const BIG_KEEP_RATIO: u64 = 8;
126const CHUNKS_FREE: usize = 2;
128const BIG_KEEP_US: u64 = 1_000_000;
130
131pub(crate) struct Shared {
132 pub inst: Arc<InstShared>,
133 pub pd: vk::PhysicalDevice,
134 pub dev: vk::Device,
135 pub f: vk::DeviceFns,
136 pub queue: vk::Queue,
137 pub family: u32,
138 pub timeline: vk::Handle,
139 pub info: AdapterInfo,
140 pub features: Features,
141 pub limits: Limits,
142 pub level: Level,
143 pub raw: vk::PhysicalDeviceLimits,
144 pub ts_mask: u64,
145 #[cfg_attr(jfgui_glibc, allow(dead_code))] pub swapchain: bool,
147 #[cfg_attr(not(jfgui_glibc), allow(dead_code))]
149 pub queue_foreign: bool,
150 pub ts_base: AtomicU64,
152 pub host_query_reset: bool,
154 pub maintenance4: bool,
156 lost: AtomicBool,
157 submitted: AtomicU64,
158 completed: AtomicU64,
159 qlock: SpinLock<()>,
160 pub st: SpinLock<State>,
161}
162
163#[derive(Clone)]
165pub struct Device {
166 pub(crate) sh: Arc<Shared>,
167 queue: Queue,
168}
169
170#[derive(Clone)]
172pub struct Queue {
173 pub(crate) sh: Arc<Shared>,
174}
175
176const E10: &[usize] = &[
178 vk::F10_FULL_DRAW_INDEX_UINT32,
179 vk::F10_IMAGE_CUBE_ARRAY,
180 vk::F10_INDEPENDENT_BLEND,
181 vk::F10_GEOMETRY_SHADER,
182 vk::F10_SAMPLE_RATE_SHADING,
183 vk::F10_DUAL_SRC_BLEND,
184 vk::F10_MULTI_DRAW_INDIRECT,
185 vk::F10_DRAW_INDIRECT_FIRST_INSTANCE,
186 vk::F10_DEPTH_CLAMP,
187 vk::F10_FILL_MODE_NON_SOLID,
188 vk::F10_SAMPLER_ANISOTROPY,
189 vk::F10_TEXTURE_COMPRESSION_BC,
190 vk::F10_VERTEX_PIPELINE_STORES_AND_ATOMICS,
191 vk::F10_FRAGMENT_STORES_AND_ATOMICS,
192 vk::F10_SHADER_STORAGE_IMAGE_EXTENDED_FORMATS,
193 vk::F10_SHADER_STORAGE_IMAGE_READ_WITHOUT_FORMAT,
194 vk::F10_SHADER_STORAGE_IMAGE_WRITE_WITHOUT_FORMAT,
195 vk::F10_SHADER_UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING,
196 vk::F10_SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING,
197 vk::F10_SHADER_STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING,
198 vk::F10_SHADER_STORAGE_IMAGE_ARRAY_DYNAMIC_INDEXING,
199 vk::F10_SHADER_CLIP_DISTANCE,
200 vk::F10_SHADER_FLOAT64,
201 vk::F10_SHADER_INT64,
202 vk::F10_SHADER_INT16,
203];
204const E11: &[usize] = &[
205 vk::F11_STORAGE_BUFFER_16BIT_ACCESS,
206 vk::F11_UNIFORM_AND_STORAGE_BUFFER_16BIT_ACCESS,
207 vk::F11_STORAGE_PUSH_CONSTANT16,
208 vk::F11_SHADER_DRAW_PARAMETERS,
209];
210const E12: &[usize] = &[
211 vk::F12_STORAGE_BUFFER_8BIT_ACCESS,
212 vk::F12_SHADER_FLOAT16,
213 vk::F12_SHADER_INT8,
214 vk::F12_SCALAR_BLOCK_LAYOUT,
215 vk::F12_UNIFORM_BUFFER_STANDARD_LAYOUT,
216 vk::F12_SHADER_SUBGROUP_EXTENDED_TYPES,
217 vk::F12_HOST_QUERY_RESET,
218 vk::F12_TIMELINE_SEMAPHORE,
219 vk::F12_BUFFER_DEVICE_ADDRESS,
220 vk::F12_VULKAN_MEMORY_MODEL,
221 vk::F12_VULKAN_MEMORY_MODEL_DEVICE_SCOPE,
222];
223const E12_VOLL: &[usize] = &[
224 vk::F12_DRAW_INDIRECT_COUNT,
225 vk::F12_DESCRIPTOR_INDEXING,
226 vk::F12_SHADER_SAMPLED_IMAGE_ARRAY_NON_UNIFORM_INDEXING,
227 vk::F12_SHADER_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
228 vk::F12_SHADER_STORAGE_IMAGE_ARRAY_NON_UNIFORM_INDEXING,
229 vk::F12_DESCRIPTOR_BINDING_SAMPLED_IMAGE_UPDATE_AFTER_BIND,
230 vk::F12_DESCRIPTOR_BINDING_STORAGE_IMAGE_UPDATE_AFTER_BIND,
231 vk::F12_DESCRIPTOR_BINDING_STORAGE_BUFFER_UPDATE_AFTER_BIND,
232 vk::F12_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING,
233 vk::F12_DESCRIPTOR_BINDING_PARTIALLY_BOUND,
234 vk::F12_RUNTIME_DESCRIPTOR_ARRAY,
235];
236const E13: &[usize] = &[
237 vk::F13_SHADER_DEMOTE_TO_HELPER_INVOCATION,
238 vk::F13_SUBGROUP_SIZE_CONTROL,
239 vk::F13_SYNCHRONIZATION2,
240 vk::F13_DYNAMIC_RENDERING,
241 vk::F13_MAINTENANCE4,
242];
243
244fn pick<const N: usize>(have: &[u32; N], want: &[usize]) -> [u32; N] {
245 let mut out = [0u32; N];
246 for &i in want {
247 out[i] = have[i];
248 }
249 out
250}
251
252impl Adapter {
253 pub fn create_device(&self, desc: &DeviceDesc) -> Result<Device> {
255 if let Some(why) = self.info.missing {
256 return Err(GpuError::Unsupported(why));
257 }
258 let inst = &self.inst;
259 let level = if self.voll && desc.max_level == Level::Voll { Level::Voll } else { Level::Basis };
260 let voll = level == Level::Voll;
261 let v12 = self.api >= vk::API_VERSION_1_2;
262 let v13 = self.api >= vk::API_VERSION_1_3;
263 let mut e10 = pick(&self.f10, E10);
264 if !voll {
265 e10[vk::F10_MULTI_DRAW_INDIRECT] = 0;
266 }
267 let e11 = pick(&self.f11, E11);
268 let mut e12 = pick(&self.f12, E12);
269 if e12[vk::F12_VULKAN_MEMORY_MODEL_DEVICE_SCOPE] == 0 {
272 e12[vk::F12_VULKAN_MEMORY_MODEL] = 0;
273 }
274 if voll {
275 for &i in E12_VOLL {
276 e12[i] = self.f12[i];
277 }
278 }
279 let e13 = pick(&self.f13, E13);
280 let mut f13: vk::PhysicalDeviceVulkan13Features = vk::Zero::zero();
281 f13.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
282 f13.f = e13;
283 let mut f12: vk::PhysicalDeviceVulkan12Features = vk::Zero::zero();
284 f12.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
285 f12.f = e12;
286 let mut f11: vk::PhysicalDeviceVulkan11Features = vk::Zero::zero();
287 f11.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
288 f11.f = e11;
289 let mut dynr: vk::PhysicalDeviceOneFeature = vk::Zero::zero();
290 dynr.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
291 dynr.f = 1;
292 let mut tl: vk::PhysicalDeviceOneFeature = vk::Zero::zero();
293 tl.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES;
294 tl.f = 1;
295 let mut f2: vk::PhysicalDeviceFeatures2 = vk::Zero::zero();
296 f2.s_type = vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
297 f2.f = e10;
298 let mut names: Vec<*const u8> = Vec::new();
299 if v12 {
301 if v13 {
302 f12.p_next = &mut f13 as *mut _ as *mut c_void;
303 } else {
304 f12.p_next = &mut dynr as *mut _ as *mut c_void;
305 names.push(b"VK_KHR_dynamic_rendering\0".as_ptr());
306 }
307 f11.p_next = &mut f12 as *mut _ as *mut c_void;
308 f2.p_next = &mut f11 as *mut _ as *mut c_void;
309 } else {
310 tl.p_next = &mut dynr as *mut _ as *mut c_void;
312 f2.p_next = &mut tl as *mut _ as *mut c_void;
313 names.push(b"VK_KHR_timeline_semaphore\0".as_ptr());
314 names.push(b"VK_KHR_create_renderpass2\0".as_ptr());
315 names.push(b"VK_KHR_depth_stencil_resolve\0".as_ptr());
316 names.push(b"VK_KHR_dynamic_rendering\0".as_ptr());
317 }
318 let swapchain = self.exts.swapchain;
319 if swapchain {
320 names.push(b"VK_KHR_swapchain\0".as_ptr());
321 }
322 let dmabuf = self.exts.dmabuf;
323 if dmabuf {
324 names.push(b"VK_KHR_external_memory_fd\0".as_ptr());
325 names.push(b"VK_EXT_external_memory_dma_buf\0".as_ptr());
326 names.push(b"VK_EXT_image_drm_format_modifier\0".as_ptr());
327 if !v12 {
328 names.push(b"VK_KHR_image_format_list\0".as_ptr());
329 }
330 }
331 let queue_foreign = dmabuf && self.exts.queue_foreign;
332 if queue_foreign {
333 names.push(b"VK_EXT_queue_family_foreign\0".as_ptr());
334 }
335 let prio = 1.0f32;
336 let qi = vk::DeviceQueueCreateInfo {
337 s_type: vk::STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
338 queue_family_index: self.family,
339 queue_count: 1,
340 p_queue_priorities: &prio,
341 ..vk::Zero::zero()
342 };
343 let info = vk::DeviceCreateInfo {
344 s_type: vk::STRUCTURE_TYPE_DEVICE_CREATE_INFO,
345 p_next: &f2 as *const _ as *const c_void,
346 queue_create_info_count: 1,
347 p_queue_create_infos: &qi,
348 enabled_extension_count: names.len() as u32,
349 pp_enabled_extension_names: names.as_ptr(),
350 ..vk::Zero::zero()
351 };
352 let mut dev: vk::Device = 0;
353 let r = unsafe { (inst.f.create_device)(self.pd, &info, core::ptr::null(), &mut dev) };
355 if r != vk::SUCCESS {
356 return Err(err(r));
357 }
358 let gdpa = inst.f.get_device_proc_addr;
359 let f = match vk::DeviceFns::load(&|n| unsafe { gdpa(dev, n.as_ptr()) }) {
361 Ok(f) => f,
362 Err(name) => {
363 let d = unsafe { gdpa(dev, b"vkDestroyDevice\0".as_ptr()) };
365 if d != 0 {
366 unsafe {
368 core::mem::transmute::<usize, unsafe extern "system" fn(vk::Device, *const c_void)>(d)(
369 dev,
370 core::ptr::null(),
371 )
372 };
373 }
374 return Err(GpuError::Unsupported(name));
375 }
376 };
377 let mut queue: vk::Queue = 0;
378 unsafe { (f.get_device_queue)(dev, self.family, 0, &mut queue) };
380 let ti = vk::SemaphoreTypeCreateInfo {
381 s_type: vk::STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
382 semaphore_type: vk::SEMAPHORE_TYPE_TIMELINE,
383 initial_value: 0,
384 ..vk::Zero::zero()
385 };
386 let si = vk::SemaphoreCreateInfo {
387 s_type: vk::STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
388 p_next: &ti as *const _ as *const c_void,
389 flags: 0,
390 };
391 let mut timeline = 0;
392 let r = unsafe { (f.create_semaphore)(dev, &si, core::ptr::null(), &mut timeline) };
394 if r != vk::SUCCESS {
395 unsafe { (f.destroy_device)(dev, core::ptr::null()) };
397 return Err(err(r));
398 }
399 let mut features = self.features;
400 if !voll {
401 features.bindless = false;
402 features.draw_indirect_count = false;
403 features.multi_draw_indirect = false;
404 }
405 let mut limits = self.limits;
406 if !voll {
407 limits.max_bindless_textures = 0;
408 limits.max_bindless_samplers = 0;
409 limits.max_bindless_buffers = 0;
410 limits.max_bindless_storage_textures = 0;
411 }
412 let ts_mask = match self.ts_bits {
413 0 => 0,
414 64.. => !0,
415 b => (1u64 << b) - 1,
416 };
417 let sh = Arc::new(Shared {
418 inst: inst.clone(),
419 pd: self.pd,
420 dev,
421 f,
422 queue,
423 family: self.family,
424 timeline,
425 info: self.info.clone(),
426 features,
427 limits,
428 level,
429 raw: self.raw,
430 ts_mask,
431 swapchain,
432 queue_foreign,
433 ts_base: AtomicU64::new(0),
434 host_query_reset: v12 && e12[vk::F12_HOST_QUERY_RESET] != 0,
435 maintenance4: v13 && e13[vk::F13_MAINTENANCE4] != 0,
436 lost: AtomicBool::new(false),
437 submitted: AtomicU64::new(0),
438 completed: AtomicU64::new(0),
439 qlock: SpinLock::new(()),
440 st: SpinLock::new(State {
441 mem: Allocator::new(self.mem),
442 garbage: Vec::new(),
443 free: Vec::new(),
444 busy: Vec::new(),
445 pools: Vec::new(),
446 upload: None,
447 ring: Ring::default(),
448 }),
449 });
450 Ok(Device { queue: Queue { sh: sh.clone() }, sh })
451 }
452}
453
454impl Shared {
455 #[inline]
457 pub fn check(&self) -> Result<()> {
458 if self.lost.load(Ordering::Relaxed) { Err(GpuError::DeviceLost) } else { Ok(()) }
459 }
460
461 pub fn vk(&self, r: vk::VkResult) -> Result<()> {
463 if r == vk::SUCCESS {
464 return Ok(());
465 }
466 if r == vk::ERROR_DEVICE_LOST {
467 self.lost.store(true, Ordering::Relaxed);
468 }
469 Err(err(r))
470 }
471
472 #[cfg_attr(jfgui_glibc, allow(dead_code))]
474 pub fn with_queue<R>(&self, f: impl FnOnce(vk::Queue) -> R) -> R {
475 let _q = self.qlock.lock();
476 f(self.queue)
477 }
478
479 #[cfg_attr(jfgui_glibc, allow(dead_code))]
482 pub fn queue_idle(&self) -> Result<()> {
483 let (r, v) = self.with_queue(|q| (unsafe { (self.f.queue_wait_idle)(q) }, self.submitted()));
486 self.vk(r)?;
487 self.completed.fetch_max(v, Ordering::AcqRel);
488 let mut st = self.st.lock();
489 self.collect(&mut st);
490 Ok(())
491 }
492
493 pub fn mark_lost(&self) {
494 self.lost.store(true, Ordering::Relaxed);
495 }
496
497 pub fn submitted(&self) -> u64 {
498 self.submitted.load(Ordering::Acquire)
499 }
500
501 pub fn refresh(&self) -> u64 {
503 let mut v = 0u64;
504 let r = unsafe { (self.f.get_semaphore_counter_value)(self.dev, self.timeline, &mut v) };
506 if r != vk::SUCCESS {
507 if r == vk::ERROR_DEVICE_LOST {
508 self.lost.store(true, Ordering::Relaxed);
509 }
510 return self.completed.load(Ordering::Acquire);
511 }
512 self.completed.fetch_max(v, Ordering::AcqRel);
513 v
514 }
515
516 pub fn defer(&self, g: Garbage) {
521 let mut st = self.st.lock();
522 let named = st.upload.is_some() && matches!(g, Garbage::Buffer(..) | Garbage::Image(..));
523 let v = self.submitted() + named as u64;
524 if v <= self.completed.load(Ordering::Acquire) || self.lost.load(Ordering::Relaxed) {
525 self.destroy(&mut st, g);
526 } else {
527 st.garbage.push((v, g));
528 }
529 }
530
531 fn destroy(&self, st: &mut State, g: Garbage) {
532 let (f, d, n) = (&self.f, self.dev, core::ptr::null());
533 unsafe {
536 match g {
537 Garbage::Buffer(h, a) => {
538 (f.destroy_buffer)(d, h, n);
539 st.mem.free(f, d, &a);
540 }
541 Garbage::Image(h, a) => {
542 (f.destroy_image)(d, h, n);
543 if let Some(a) = a {
544 st.mem.free(f, d, &a);
545 }
546 }
547 Garbage::View(h) => (f.destroy_image_view)(d, h, n),
548 Garbage::Sampler(h) => (f.destroy_sampler)(d, h, n),
549 Garbage::Shader(h) => (f.destroy_shader_module)(d, h, n),
550 Garbage::SetLayout(h) => (f.destroy_descriptor_set_layout)(d, h, n),
551 Garbage::PipeLayout(h) => (f.destroy_pipeline_layout)(d, h, n),
552 Garbage::Pipeline(h) => (f.destroy_pipeline)(d, h, n),
553 Garbage::Set(pool, set) => {
554 (f.free_descriptor_sets)(d, pool, 1, &set);
555 }
556 Garbage::Pool(h) => (f.destroy_descriptor_pool)(d, h, n),
557 Garbage::Query(h) => (f.destroy_query_pool)(d, h, n),
558 Garbage::Semaphore(h) => (f.destroy_semaphore)(d, h, n),
559 Garbage::Swapchain(h) => {
560 if let Some(ds) = f.destroy_swapchain_khr {
561 ds(d, h, n);
562 }
563 }
564 Garbage::Memory(h) => (f.free_memory)(d, h, n),
565 }
566 }
567 }
568
569 fn collect(&self, st: &mut State) {
571 if st.garbage.is_empty() && st.busy.is_empty() && st.ring.busy.is_empty() && st.ring.free.is_empty() {
572 return;
573 }
574 let done = if self.lost.load(Ordering::Relaxed) { u64::MAX } else { self.refresh() };
575 let mut i = 0;
576 while i < st.ring.busy.len() {
577 if st.ring.busy[i].0 <= done {
578 let (_, mut c) = st.ring.busy.swap_remove(i);
579 c.used = 0;
580 st.ring.free.push(c);
581 } else {
582 i += 1;
583 }
584 }
585 self.ring_trim(st);
586 let mut i = 0;
587 while i < st.busy.len() {
588 if st.busy[i].0 <= done {
589 let (_, s) = st.busy.swap_remove(i);
590 unsafe { (self.f.reset_command_pool)(self.dev, s.pool, 0) };
592 st.free.push(s);
593 } else {
594 i += 1;
595 }
596 }
597 let mut i = 0;
598 while i < st.garbage.len() {
599 if st.garbage[i].0 <= done {
600 let (_, g) = st.garbage.swap_remove(i);
601 self.destroy(st, g);
602 } else {
603 i += 1;
604 }
605 }
606 }
607
608 pub fn take_slot(&self) -> Result<Slot> {
610 self.check()?;
611 let slot = {
612 let mut st = self.st.lock();
613 if st.free.is_empty() {
614 self.collect(&mut st);
615 }
616 st.free.pop()
617 };
618 let slot = match slot {
619 Some(s) => s,
620 None => self.new_slot()?,
621 };
622 let bi = vk::CommandBufferBeginInfo {
623 s_type: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
624 flags: vk::COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
625 ..vk::Zero::zero()
626 };
627 let r = unsafe { (self.f.begin_command_buffer)(slot.cb, &bi) };
629 if let Err(e) = self.vk(r) {
630 self.give_slot(slot);
631 return Err(e);
632 }
633 Ok(slot)
634 }
635
636 fn new_slot(&self) -> Result<Slot> {
637 let pi = vk::CommandPoolCreateInfo {
638 s_type: vk::STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
639 flags: vk::COMMAND_POOL_CREATE_TRANSIENT_BIT,
640 queue_family_index: self.family,
641 ..vk::Zero::zero()
642 };
643 let mut pool = 0;
644 self.vk(unsafe { (self.f.create_command_pool)(self.dev, &pi, core::ptr::null(), &mut pool) })?;
646 let ai = vk::CommandBufferAllocateInfo {
647 s_type: vk::STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
648 command_pool: pool,
649 level: vk::COMMAND_BUFFER_LEVEL_PRIMARY,
650 command_buffer_count: 1,
651 ..vk::Zero::zero()
652 };
653 let mut cb = 0;
654 let r = unsafe { (self.f.allocate_command_buffers)(self.dev, &ai, &mut cb) };
656 if let Err(e) = self.vk(r) {
657 unsafe { (self.f.destroy_command_pool)(self.dev, pool, core::ptr::null()) };
659 return Err(e);
660 }
661 Ok(Slot { pool, cb })
662 }
663
664 pub fn give_slot(&self, s: Slot) {
666 unsafe { (self.f.reset_command_pool)(self.dev, s.pool, 0) };
668 self.st.lock().free.push(s);
669 }
670
671 fn ring_trim(&self, st: &mut State) {
676 let now = plat::time_us();
677 let keep_big = now.saturating_sub(st.ring.big_at) < BIG_KEEP_US;
678 let largest = st.ring.free.iter().map(|c| c.a.size).max().unwrap_or(0);
679 let mut small = 0;
680 let mut i = 0;
681 while i < st.ring.free.len() {
682 let size = st.ring.free[i].a.size;
683 let keep = if size >= CHUNK * 2 {
684 keep_big && size == largest && size <= st.ring.big_size.saturating_mul(BIG_KEEP_RATIO).max(CHUNK * 2)
685 } else {
686 small += 1;
687 small <= CHUNKS_FREE
688 };
689 if keep {
690 i += 1;
691 } else {
692 let c = st.ring.free.swap_remove(i);
693 self.destroy(st, Garbage::Buffer(c.buf, c.a));
694 }
695 }
696 }
697
698 fn ring_chunk(&self, st: &mut State, size: u64) -> Result<Chunk> {
701 let top = if size == CHUNK { CHUNK * 2 } else { u64::MAX };
702 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);
703 if let Some(i) = best {
704 return Ok(st.ring.free.swap_remove(i));
705 }
706 let (buf, a) = self.raw_buffer(st, size, vk::BUFFER_USAGE_TRANSFER_SRC_BIT, MemoryKind::Upload)?;
707 Ok(Chunk { buf, a, used: 0 })
708 }
709
710 pub fn upload_cb(&self, st: &mut State) -> Result<vk::CommandBuffer> {
712 self.stage(st, 0)?;
713 Ok(st.upload.as_ref().map_or(0, |u| u.slot.cb))
714 }
715
716 fn stage(&self, st: &mut State, n: u64) -> Result<(vk::Handle, u64, usize)> {
719 if st.upload.is_none() {
720 let slot = match st.free.pop() {
722 Some(s) => s,
723 None => self.new_slot()?,
724 };
725 let bi = vk::CommandBufferBeginInfo {
726 s_type: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
727 flags: vk::COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
728 ..vk::Zero::zero()
729 };
730 let r = unsafe { (self.f.begin_command_buffer)(slot.cb, &bi) };
732 if let Err(e) = self.vk(r) {
733 st.free.push(slot);
734 return Err(e);
735 }
736 st.upload = Some(Upload { slot, retired: Vec::new() });
737 }
738 if n == 0 {
739 return Ok((0, 0, 0));
740 }
741 if n > CHUNK / 2 {
742 st.ring.big_at = plat::time_us();
744 st.ring.big_size = n;
745 let size = (n + 0xFFFF) & !0xFFFF;
746 let mut c = self.ring_chunk(st, size.max(CHUNK * 2))?;
747 c.used = n;
748 let (buf, ptr) = (c.buf, c.a.ptr);
749 st.upload.as_mut().unwrap_or_else(|| unreachable!()).retired.push(c);
750 return Ok((buf, 0, ptr));
751 }
752 let room = st.ring.cur.as_ref().is_some_and(|c| c.used + n <= c.a.size);
753 if !room {
754 if let Some(c) = st.ring.cur.take() {
755 if st.ring.cur_open {
756 st.upload.as_mut().unwrap_or_else(|| unreachable!()).retired.push(c);
757 } else {
758 let v = st.ring.cur_value;
759 st.ring.busy.push((v, c));
760 }
761 }
762 let c = self.ring_chunk(st, CHUNK)?;
763 st.ring.cur = Some(c);
764 st.ring.cur_open = false;
765 }
766 st.ring.cur_open = true;
767 let c = st.ring.cur.as_mut().unwrap_or_else(|| unreachable!());
768 let off = c.used;
769 c.used = (off + n + 15) & !15;
770 Ok((c.buf, off, c.a.ptr + off as usize))
771 }
772
773 pub fn raw_buffer(&self, st: &mut State, size: u64, usage: u32, kind: MemoryKind) -> Result<(vk::Handle, Alloc)> {
775 let bi = vk::BufferCreateInfo {
776 s_type: vk::STRUCTURE_TYPE_BUFFER_CREATE_INFO,
777 size,
778 usage,
779 sharing_mode: vk::SHARING_MODE_EXCLUSIVE,
780 ..vk::Zero::zero()
781 };
782 let mut buf = 0;
783 self.vk(unsafe { (self.f.create_buffer)(self.dev, &bi, core::ptr::null(), &mut buf) })?;
785 let mut req: vk::MemoryRequirements = vk::Zero::zero();
786 unsafe { (self.f.get_buffer_memory_requirements)(self.dev, buf, &mut req) };
788 let a = match st.mem.alloc(&self.f, self.dev, &req, kind, true) {
789 Ok(a) => a,
790 Err(e) => {
791 unsafe { (self.f.destroy_buffer)(self.dev, buf, core::ptr::null()) };
793 return Err(e);
794 }
795 };
796 let r = unsafe { (self.f.bind_buffer_memory)(self.dev, buf, a.mem, a.offset) };
798 if let Err(e) = self.vk(r) {
799 unsafe { (self.f.destroy_buffer)(self.dev, buf, core::ptr::null()) };
801 st.mem.free(&self.f, self.dev, &a);
802 return Err(e);
803 }
804 Ok((buf, a))
805 }
806
807 pub fn submit(&self, cbs: &[vk::CommandBuffer], slots: Vec<Slot>, wait: Option<(vk::Handle, u32)>,
810 signal: Option<vk::Handle>) -> Result<u64> {
811 let mut slots = slots;
812 if let Err(e) = self.check() {
813 for s in slots {
814 self.give_slot(s);
815 }
816 return Err(e);
817 }
818 let up = self.st.lock().upload.take();
819 let mut all: Vec<vk::CommandBuffer> = Vec::with_capacity(cbs.len() + 1);
820 let mut chunks: Vec<Chunk> = Vec::new();
821 let uploads = up.is_some();
822 if let Some(u) = up {
823 let mb = vk::MemoryBarrier {
824 s_type: vk::STRUCTURE_TYPE_MEMORY_BARRIER,
825 src_access_mask: vk::ACCESS_TRANSFER_WRITE_BIT,
826 dst_access_mask: vk::ACCESS_MEMORY_READ_BIT | vk::ACCESS_MEMORY_WRITE_BIT,
827 ..vk::Zero::zero()
828 };
829 unsafe {
831 (self.f.cmd_pipeline_barrier)(u.slot.cb, vk::PIPELINE_STAGE_TRANSFER_BIT,
832 vk::PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &mb, 0, core::ptr::null(), 0, core::ptr::null());
833 }
834 let r = unsafe { (self.f.end_command_buffer)(u.slot.cb) };
836 all.push(u.slot.cb);
837 slots.push(u.slot);
838 chunks = u.retired;
839 if let Err(e) = self.vk(r) {
840 self.fail_submit(slots, chunks);
841 return Err(e);
842 }
843 }
844 all.extend_from_slice(cbs);
845 let q = self.qlock.lock();
846 let value = self.submitted.load(Ordering::Relaxed) + 1;
847 let sems = [self.timeline, signal.unwrap_or(0)];
848 let values = [value, 0];
849 let nsig = 1 + signal.is_some() as u32;
850 let tsi = vk::TimelineSemaphoreSubmitInfo {
851 s_type: vk::STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
852 signal_semaphore_value_count: nsig,
853 p_signal_semaphore_values: values.as_ptr(),
854 ..vk::Zero::zero()
855 };
856 let (ws, wst) = wait.map_or(([0u64], [0u32]), |(s, st)| ([s], [st]));
857 let si = vk::SubmitInfo {
858 s_type: vk::STRUCTURE_TYPE_SUBMIT_INFO,
859 p_next: &tsi as *const _ as *const c_void,
860 wait_semaphore_count: wait.is_some() as u32,
861 p_wait_semaphores: ws.as_ptr(),
862 p_wait_dst_stage_mask: wst.as_ptr(),
863 command_buffer_count: all.len() as u32,
864 p_command_buffers: all.as_ptr(),
865 signal_semaphore_count: nsig,
866 p_signal_semaphores: sems.as_ptr(),
867 };
868 let r = unsafe { (self.f.queue_submit)(self.queue, 1, &si, 0) };
870 if r == vk::SUCCESS {
871 self.submitted.store(value, Ordering::Release);
872 }
873 drop(q);
874 if let Err(e) = self.vk(r) {
875 self.fail_submit(slots, chunks);
876 return Err(e);
877 }
878 let mut st = self.st.lock();
879 for s in slots {
880 st.busy.push((value, s));
881 }
882 for c in chunks {
883 st.ring.busy.push((value, c));
884 }
885 if uploads && st.ring.cur_open {
886 st.ring.cur_value = value;
887 st.ring.cur_open = false;
888 }
889 self.collect(&mut st);
890 Ok(value)
891 }
892
893 fn fail_submit(&self, slots: Vec<Slot>, chunks: Vec<Chunk>) {
894 for s in slots {
895 self.give_slot(s);
896 }
897 let mut st = self.st.lock();
898 st.ring.cur_open = false; for c in chunks {
900 self.destroy(&mut st, Garbage::Buffer(c.buf, c.a));
901 }
902 }
903
904 pub fn wait_value(&self, v: u64, timeout_ns: u64) -> Result<bool> {
906 self.check()?;
907 if v <= self.completed.load(Ordering::Acquire) {
908 return Ok(true);
909 }
910 if v > self.submitted() {
911 return Err(GpuError::Invalid("wait: not submitted yet"));
912 }
913 let wi = vk::SemaphoreWaitInfo {
914 s_type: vk::STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
915 semaphore_count: 1,
916 p_semaphores: &self.timeline,
917 p_values: &v,
918 ..vk::Zero::zero()
919 };
920 let r = unsafe { (self.f.wait_semaphores)(self.dev, &wi, timeout_ns) };
922 if r == vk::TIMEOUT {
923 return Ok(false);
924 }
925 self.vk(r)?;
926 self.completed.fetch_max(v, Ordering::AcqRel);
927 let mut st = self.st.lock();
928 self.collect(&mut st);
929 Ok(true)
930 }
931
932 pub fn alloc_set(&self, layout: vk::Handle, needs: &[vk::DescriptorPoolSize]) -> Result<(vk::Handle, vk::Handle)> {
934 let mut st = self.st.lock();
935 let alloc = |pool: vk::Handle| {
936 let ai = vk::DescriptorSetAllocateInfo {
937 s_type: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
938 descriptor_pool: pool,
939 descriptor_set_count: 1,
940 p_set_layouts: &layout,
941 ..vk::Zero::zero()
942 };
943 let mut set = 0;
944 let r = unsafe { (self.f.allocate_descriptor_sets)(self.dev, &ai, &mut set) };
946 (r, set)
947 };
948 for &pool in st.pools.iter().rev() {
949 let (r, set) = alloc(pool);
950 if r == vk::SUCCESS {
951 return Ok((pool, set));
952 }
953 if r != vk::ERROR_OUT_OF_POOL_MEMORY && r != vk::ERROR_FRAGMENTED_POOL {
954 self.vk(r)?;
955 }
956 }
957 let mut sizes: Vec<vk::DescriptorPoolSize> = [
959 (vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER, 256),
960 (vk::DESCRIPTOR_TYPE_STORAGE_BUFFER, 512),
961 (vk::DESCRIPTOR_TYPE_SAMPLED_IMAGE, 512),
962 (vk::DESCRIPTOR_TYPE_STORAGE_IMAGE, 128),
963 (vk::DESCRIPTOR_TYPE_SAMPLER, 256),
964 ]
965 .iter()
966 .map(|&(t, n)| vk::DescriptorPoolSize { type_: t, descriptor_count: n })
967 .collect();
968 for s in sizes.iter_mut() {
969 let need: u32 = needs.iter().filter(|x| x.type_ == s.type_).map(|x| x.descriptor_count).sum();
970 s.descriptor_count = s.descriptor_count.max(need.saturating_mul(64));
971 }
972 let pi = vk::DescriptorPoolCreateInfo {
973 s_type: vk::STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
974 flags: vk::DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
975 max_sets: 256,
976 pool_size_count: sizes.len() as u32,
977 p_pool_sizes: sizes.as_ptr(),
978 ..vk::Zero::zero()
979 };
980 let mut pool = 0;
981 self.vk(unsafe { (self.f.create_descriptor_pool)(self.dev, &pi, core::ptr::null(), &mut pool) })?;
983 st.pools.push(pool);
984 let (r, set) = alloc(pool);
985 self.vk(r)?;
986 Ok((pool, set))
987 }
988}
989
990impl Drop for Shared {
991 fn drop(&mut self) {
992 let (f, d, n) = (&self.f, self.dev, core::ptr::null());
993 unsafe {
996 (f.device_wait_idle)(d);
997 let mut st = self.st.lock();
998 if let Some(u) = st.upload.take() {
999 for c in u.retired {
1000 st.garbage.push((0, Garbage::Buffer(c.buf, c.a)));
1001 }
1002 st.free.push(u.slot);
1003 }
1004 let ring = core::mem::take(&mut st.ring);
1005 for c in ring.cur.into_iter().chain(ring.free).chain(ring.busy.into_iter().map(|(_, c)| c)) {
1006 st.garbage.push((0, Garbage::Buffer(c.buf, c.a)));
1007 }
1008 let garbage = core::mem::take(&mut st.garbage);
1009 for (_, g) in garbage {
1010 self.destroy(&mut st, g);
1011 }
1012 for (_, s) in core::mem::take(&mut st.busy) {
1013 st.free.push(s);
1014 }
1015 for s in st.free.drain(..) {
1016 (f.destroy_command_pool)(d, s.pool, n);
1017 }
1018 for p in st.pools.drain(..) {
1019 (f.destroy_descriptor_pool)(d, p, n);
1020 }
1021 st.mem.destroy_all(f, d);
1022 (f.destroy_semaphore)(d, self.timeline, n);
1023 drop(st);
1024 (f.destroy_device)(d, n);
1025 }
1026 }
1027}
1028
1029impl Device {
1030 pub fn queue(&self) -> &Queue {
1031 &self.queue
1032 }
1033 pub fn info(&self) -> &AdapterInfo {
1034 &self.sh.info
1035 }
1036 pub fn features(&self) -> &Features {
1038 &self.sh.features
1039 }
1040 pub fn limits(&self) -> &Limits {
1041 &self.sh.limits
1042 }
1043 pub fn level(&self) -> Level {
1044 self.sh.level
1045 }
1046 pub fn is_lost(&self) -> bool {
1048 self.sh.check().is_err()
1049 }
1050 pub fn test_lose(&self) {
1054 let _ = self.wait_idle();
1055 self.sh.mark_lost();
1056 }
1057 pub fn validating(&self) -> bool {
1059 self.sh.inst.validate
1060 }
1061 pub fn poll(&self) -> Result<()> {
1063 self.sh.check()?;
1064 let mut st = self.sh.st.lock();
1065 self.sh.collect(&mut st);
1066 drop(st);
1067 self.sh.check()
1068 }
1069 pub fn wait(&self, id: SubmitId, timeout_ns: u64) -> Result<bool> {
1071 self.sh.wait_value(id.0, timeout_ns)
1072 }
1073 pub fn wait_idle(&self) -> Result<()> {
1075 let v = self.sh.submitted();
1076 if self.sh.wait_value(v, 10_000_000_000)? { Ok(()) } else { Err(GpuError::Timeout) }
1077 }
1078 pub fn completed(&self) -> SubmitId {
1080 SubmitId(self.sh.refresh())
1081 }
1082 pub fn is_done(&self, id: SubmitId) -> bool {
1084 self.sh.refresh() >= id.0
1085 }
1086 pub fn memory_reserved(&self) -> u64 {
1088 self.sh.st.lock().mem.reserved
1089 }
1090}
1091
1092impl Queue {
1093 pub fn submit<'a, I: IntoIterator<Item = crate::CommandBuffer<'a>>>(&self, cmds: I) -> Result<SubmitId> {
1095 let mut cbs = Vec::new();
1096 let mut slots = Vec::new();
1097 for c in cmds {
1098 let s = c.into_slot();
1099 cbs.push(s.cb);
1100 slots.push(s);
1101 }
1102 self.sh.submit(&cbs, slots, None, None).map(SubmitId)
1103 }
1104
1105 pub fn flush(&self) -> Result<SubmitId> {
1107 self.sh.submit(&[], Vec::new(), None, None).map(SubmitId)
1108 }
1109
1110 pub fn write_buffer<T: Pod>(&self, buf: &crate::Buffer, offset: u64, data: &[T]) -> Result<()> {
1112 let bytes = crate::bytes_of(data);
1113 let n = bytes.len() as u64;
1114 if offset.checked_add(n).is_none_or(|e| e > buf.size()) {
1115 return Err(GpuError::Invalid("write_buffer: range outside the buffer"));
1116 }
1117 if n == 0 {
1118 return Ok(());
1119 }
1120 let sh = &self.sh;
1121 sh.check()?;
1122 let mut st = sh.st.lock();
1123 let (sbuf, soff, ptr) = sh.stage(&mut st, n)?;
1124 let cb = st.upload.as_ref().map_or(0, |u| u.slot.cb);
1125 unsafe {
1128 core::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr as *mut u8, bytes.len());
1129 let region = vk::BufferCopy { src_offset: soff, dst_offset: offset, size: n };
1130 (sh.f.cmd_copy_buffer)(cb, sbuf, buf.handle(), 1, ®ion);
1131 }
1132 Ok(())
1133 }
1134
1135 pub fn write_texture(&self, dst: &TextureRegion, data: &[u8], layout: DataLayout, before: Layout,
1138 after: Layout) -> Result<()> {
1139 let t = dst.texture;
1140 let copy = crate::vk_res::copy_region(dst, &layout, data.len() as u64)?;
1141 let need = copy.1;
1142 let sh = &self.sh;
1143 sh.check()?;
1144 let mut st = sh.st.lock();
1145 let (sbuf, soff, ptr) = sh.stage(&mut st, need)?;
1146 let cb = st.upload.as_ref().map_or(0, |u| u.slot.cb);
1147 let mut region = copy.0;
1148 region.buffer_offset = soff;
1149 let range = crate::vk_res::subresources(t, dst.mip, 1, dst.base_layer, dst.layers);
1150 unsafe {
1153 core::ptr::copy_nonoverlapping(data.as_ptr().add(layout.offset as usize), ptr as *mut u8, need as usize);
1154 crate::vk_cmd::image_barrier(&sh.f, cb, t.image(), range, before, Layout::CopyDst);
1155 (sh.f.cmd_copy_buffer_to_image)(cb, sbuf, t.image(), vk::IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
1156 crate::vk_cmd::image_barrier(&sh.f, cb, t.image(), range, Layout::CopyDst, after);
1157 }
1158 Ok(())
1159 }
1160
1161 pub fn write_texture_rects(&self, t: &crate::Texture, rects: &[[i32; 4]], data: &[u8], stride: u32, before: Layout,
1166 after: Layout) -> Result<()> {
1167 let f = t.format();
1168 let bb = f.block_bytes() as u64;
1169 if f.is_compressed() || f.is_depth() || t.depth() != 1 {
1170 return Err(GpuError::Invalid("write_texture_rects: an uncompressed 2D colour texture"));
1171 }
1172 let (tw, th) = (t.width() as i32, t.height() as i32);
1173 if (stride as u64) < tw as u64 * bb || (data.len() as u64) < stride as u64 * th as u64 {
1174 return Err(GpuError::Invalid("write_texture_rects: data smaller than the texture"));
1175 }
1176 self.write_texture_rects_at(t, rects, (0, 0), data, stride, before, after)
1177 }
1178
1179 #[allow(clippy::too_many_arguments)]
1183 pub fn write_texture_rects_at(&self, t: &crate::Texture, rects: &[[i32; 4]], origin: (i32, i32), data: &[u8], stride: u32, before: Layout,
1184 after: Layout) -> Result<()> {
1185 let f = t.format();
1186 let bb = f.block_bytes() as u64;
1187 if f.is_compressed() || f.is_depth() || t.depth() != 1 {
1188 return Err(GpuError::Invalid("write_texture_rects: an uncompressed 2D colour texture"));
1189 }
1190 let (tw, th) = (t.width() as i32, t.height() as i32);
1191 if stride == 0 {
1192 return Err(GpuError::Invalid("write_texture_rects: stride 0"));
1193 }
1194 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);
1196 let mut regions: Vec<vk::BufferImageCopy> = Vec::with_capacity(rects.len());
1197 let mut total = 0u64;
1198 let sub = crate::vk_res::subresources(t, 0, 1, 0, 1);
1199 let (ox, oy) = (origin.0 as i64, origin.1 as i64);
1200 for r in rects {
1201 let x0 = (r[0] as i64 - ox).max(0).max(-ox);
1203 let y0 = (r[1] as i64 - oy).max(0).max(-oy);
1204 let x1 = (r[0] as i64 + r[2] as i64 - ox).min(tw as i64).min(iw - ox);
1205 let y1 = (r[1] as i64 + r[3] as i64 - oy).min(th as i64).min(ih - oy);
1206 if x1 <= x0 || y1 <= y0 {
1207 continue;
1208 }
1209 let (x0, y0, x1, y1) = (x0 as i32, y0 as i32, x1 as i32, y1 as i32);
1210 let (w, h) = ((x1 - x0) as u32, (y1 - y0) as u32);
1211 regions.push(vk::BufferImageCopy {
1212 buffer_offset: total,
1213 buffer_row_length: w,
1214 buffer_image_height: h,
1215 image_subresource: vk::ImageSubresourceLayers { aspect_mask: sub.aspect_mask, mip_level: 0, base_array_layer: 0, layer_count: 1 },
1216 image_offset: vk::Offset3D { x: x0, y: y0, z: 0 },
1217 image_extent: vk::Extent3D { width: w, height: h, depth: 1 },
1218 });
1219 total += w as u64 * h as u64 * bb;
1220 }
1221 if regions.is_empty() {
1222 return Ok(());
1223 }
1224 let sh = &self.sh;
1225 sh.check()?;
1226 let mut st = sh.st.lock();
1227 let (sbuf, soff, ptr) = sh.stage(&mut st, total)?;
1228 let cb = st.upload.as_ref().map_or(0, |u| u.slot.cb);
1229 for g in regions.iter_mut() {
1230 let (x, y) = ((g.image_offset.x as i64 + ox) as usize, (g.image_offset.y as i64 + oy) as usize);
1231 let (w, h) = (g.image_extent.width as usize, g.image_extent.height as usize);
1232 let row = w * bb as usize;
1233 let mut dst = ptr + g.buffer_offset as usize;
1234 for yy in y..y + h {
1235 let from = yy * stride as usize + x * bb as usize;
1236 unsafe { core::ptr::copy_nonoverlapping(data.as_ptr().add(from), dst as *mut u8, row) };
1239 dst += row;
1240 }
1241 g.buffer_offset += soff;
1242 }
1243 unsafe {
1246 crate::vk_cmd::image_barrier(&sh.f, cb, t.image(), sub, before, Layout::CopyDst);
1247 (sh.f.cmd_copy_buffer_to_image)(cb, sbuf, t.image(), vk::IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regions.len() as u32, regions.as_ptr());
1248 crate::vk_cmd::image_barrier(&sh.f, cb, t.image(), sub, Layout::CopyDst, after);
1249 }
1250 Ok(())
1251 }
1252
1253 pub fn read_buffer<T: Pod>(&self, buf: &crate::Buffer, offset: u64, out: &mut [T]) -> Result<()> {
1256 let n = core::mem::size_of_val(out) as u64;
1257 if offset.checked_add(n).is_none_or(|e| e > buf.size()) {
1258 return Err(GpuError::Invalid("read_buffer: range outside the buffer"));
1259 }
1260 if buf.memory() == MemoryKind::Readback {
1261 let id = self.flush()?;
1262 self.sh.wait_value(id.0, u64::MAX)?;
1263 return buf.read(offset, out);
1264 }
1265 let dev = Device { sh: self.sh.clone(), queue: self.clone() };
1266 let rb = dev.create_buffer(&crate::BufferDesc { size: n.max(4), usage: crate::BufferUsage::NONE, memory: MemoryKind::Readback })?;
1267 let mut enc = dev.encoder()?;
1268 enc.copy_buffer(buf, offset, &rb, 0, n);
1269 let id = self.submit([enc.finish()?])?;
1270 if !self.sh.wait_value(id.0, 10_000_000_000)? {
1271 return Err(GpuError::Timeout);
1272 }
1273 rb.read(0, out)
1274 }
1275}