Commit 04f0de436841
tarball2 files changed+86-9
@@ -7,10 +7,27 @@ use std::sync::Mutex;
77
/// Fields drop in declaration order, so the allocator frees its memory before88
/// the device is destroyed.99
pub(crate) struct Shared {10
+ /// Staging buffers kept for reuse, see `Staging`.11
+ pub staging_pool: Mutex<Vec<crate::image::Pooled>>,1012
pub allocator: Mutex<Allocator>,1113
pub device: Device,1214
}1315
16
+impl Drop for Shared {17
+ fn drop(&mut self) {18
+ let pool = std::mem::take(19
+ self.staging_pool20
+ .get_mut()21
+ .unwrap_or_else(|e| e.into_inner()),22
+ );23
+ let allocator = self.allocator.get_mut().unwrap_or_else(|e| e.into_inner());24
+ for p in pool {25
+ unsafe { self.device.device.destroy_buffer(p.buffer, None) };26
+ let _ = allocator.free(p.allocation);27
+ }28
+ }29
+}30
+1431
/// Loaders for the extensions that dmabuf import, export and fence export1532
/// need. Absent when the device lacks any of them.1633
pub(crate) struct DmabufExt {@@ -171,6 +188,7 @@ impl Shared {
171188
spare_fences: Mutex::new(Vec::new()),172189
};173190
Ok(Self {191
+ staging_pool: Mutex::new(Vec::new()),174192
allocator: Mutex::new(allocator?),175193
device,176194
})@@ -180,13 +180,31 @@ pub(crate) fn color_range() -> vk::ImageSubresourceRange {
180180
.layer_count(1)181181
}182182
183
-/// A host-visible buffer for uploads and readbacks.183
+/// A host-visible buffer for uploads and readbacks. Dropped ones go back to184
+/// a pool on `Shared` instead of being freed. Allocating and freeing large185
+/// host-visible memory takes a driver lock on NVIDIA that `vkQueueSubmit`186
+/// also waits on, so a staging buffer made per upload on the import worker187
+/// stalled the main thread's submits for 1 to 3 ms.184188
pub(crate) struct Staging {185189
pub shared: Arc<Shared>,186190
pub buffer: vk::Buffer,187191
pub allocation: Option<Allocation>,192
+ size: usize,193
+ usage: vk::BufferUsageFlags,194
+ location: MemoryLocation,188195
}189196
197
+pub(crate) struct Pooled {198
+ pub buffer: vk::Buffer,199
+ pub allocation: Allocation,200
+ size: usize,201
+ usage: vk::BufferUsageFlags,202
+ location: MemoryLocation,203
+}204
+205
+/// Pooled staging memory kept at most, past which dropped buffers are freed.206
+const POOL_BYTES: usize = 96 * 1024 * 1024;207
+190208
impl Staging {191209
pub fn new(192210
shared: &Arc<Shared>,@@ -194,6 +212,26 @@ impl Staging {
194212
usage: vk::BufferUsageFlags,195213
location: MemoryLocation,196214
) -> Result<Self, Error> {215
+ let reused = {216
+ let mut pool = shared217
+ .staging_pool218
+ .lock()219
+ .unwrap_or_else(|e| e.into_inner());220
+ let fits = |p: &Pooled| {221
+ p.usage == usage && p.location == location && p.size >= size && p.size <= size * 2222
+ };223
+ pool.iter().position(fits).map(|i| pool.swap_remove(i))224
+ };225
+ if let Some(p) = reused {226
+ return Ok(Self {227
+ shared: shared.clone(),228
+ buffer: p.buffer,229
+ allocation: Some(p.allocation),230
+ size: p.size,231
+ usage,232
+ location,233
+ });234
+ }197235
let d = &shared.device.device;198236
let buffer = unsafe {199237
d.create_buffer(@@ -227,6 +265,9 @@ impl Staging {
227265
shared: shared.clone(),228266
buffer,229267
allocation: Some(allocation),268
+ size,269
+ usage,270
+ location,230271
})231272
}232273
@@ -247,15 +288,33 @@ impl Staging {
247288
248289
impl Drop for Staging {249290
fn drop(&mut self) {250
- unsafe { self.shared.device.device.destroy_buffer(self.buffer, None) };251
- if let Some(a) = self.allocation.take() {252
- let _ = self253
- .shared254
- .allocator255
- .lock()256
- .unwrap_or_else(|e| e.into_inner())257
- .free(a);291
+ let Some(allocation) = self.allocation.take() else {292
+ return;293
+ };294
+ let mut pool = self295
+ .shared296
+ .staging_pool297
+ .lock()298
+ .unwrap_or_else(|e| e.into_inner());299
+ let pooled: usize = pool.iter().map(|p| p.size).sum();300
+ if pooled + self.size <= POOL_BYTES {301
+ pool.push(Pooled {302
+ buffer: self.buffer,303
+ allocation,304
+ size: self.size,305
+ usage: self.usage,306
+ location: self.location,307
+ });308
+ return;258309
}310
+ drop(pool);311
+ unsafe { self.shared.device.device.destroy_buffer(self.buffer, None) };312
+ let _ = self313
+ .shared314
+ .allocator315
+ .lock()316
+ .unwrap_or_else(|e| e.into_inner())317
+ .free(allocation);259318
}260319
}