Commit ad1f04ba8cb2
tarball2 files changed+108-27
@@ -1,5 +1,28 @@
11
use crate::image::{ImageInner, color_range};22
use ash::vk;3
+use std::sync::Arc;4
+5
+/// Layout changes recorded into a command buffer that has not been submitted.6
+/// Images keep their old layout until `commit`, so a failed submit leaves the7
+/// tracking true to what the GPU has done.8
+#[derive(Default)]9
+pub(crate) struct LayoutLog(Vec<(Arc<ImageInner>, vk::ImageLayout)>);10
+11
+impl LayoutLog {12
+ fn current(&self, image: &Arc<ImageInner>) -> vk::ImageLayout {13
+ self.014
+ .iter()15
+ .rev()16
+ .find(|(i, _)| Arc::ptr_eq(i, image))17
+ .map_or_else(|| image.layout(), |(_, layout)| *layout)18
+ }19
+20
+ pub fn commit(self) {21
+ for (image, layout) in self.0 {22
+ image.set_layout(layout);23
+ }24
+ }25
+}326
427
/// A full barrier between all earlier and later work on the image, optionally528
/// transferring ownership between queue families. Coarse, but correct for@@ -39,8 +62,9 @@ pub(crate) unsafe fn acquire(
3962
d: &ash::Device,4063
cmd: vk::CommandBuffer,4164
family: u32,42
- image: &ImageInner,65
+ image: &Arc<ImageInner>,4366
layout: vk::ImageLayout,67
+ log: &mut LayoutLog,4468
) {4569
if image.external {4670
unsafe {@@ -55,7 +79,7 @@ pub(crate) unsafe fn acquire(
5579
)5680
};5781
} else {58
- let old = image.layout();82
+ let old = log.current(image);5983
if old != layout {6084
unsafe {6185
barrier(@@ -68,7 +92,7 @@ pub(crate) unsafe fn acquire(
6892
vk::QUEUE_FAMILY_IGNORED,6993
)7094
};71
- image.set_layout(layout);95
+ log.0.push((image.clone(), layout));7296
}7397
}7498
}@@ -5,7 +5,7 @@ use shm::stage_rows;
55
use stall::{STALL, StallPhase};66
77
use crate::Error;8
-use crate::barrier::{acquire, release};8
+use crate::barrier::{LayoutLog, acquire, release};99
use crate::device::Shared;1010
use crate::dmabuf::{self, DmabufCaps, RENDER_USAGE, SAMPLE_USAGE, VulkanAllocator};1111
use crate::format::{BYTES_PER_PIXEL, SUPPORTED};@@ -49,6 +49,20 @@ struct Upload {
4949
copy: vk::BufferImageCopy,5050
}5151
52
+impl Upload {53
+ fn bytes(&self) -> usize {54
+ let extent = self.copy.image_extent;55
+ extent.width as usize * extent.height as usize * BYTES_PER_PIXEL56
+ }57
+}58
+59
+/// What a command buffer holds besides its own commands. A failed submit60
+/// takes the uploads back and drops the layouts.61
+struct Recorded {62
+ uploads: Vec<Upload>,63
+ layouts: LayoutLog,64
+}65
+5266
/// Queued staging memory past which uploads are submitted without waiting5367
/// for a frame.5468
const UPLOAD_BATCH_BYTES: usize = 64 * 1024 * 1024;@@ -224,18 +238,31 @@ impl VulkanRenderer {
224238
)?[0]225239
},226240
};227
- unsafe {241
+ let began = unsafe {228242
d.begin_command_buffer(229243
cmd,230244
&vk::CommandBufferBeginInfo::default()231245
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT),232
- )?246
+ )233247
};248
+ if let Err(e) = began {249
+ self.spare_cmds.push(cmd);250
+ return Err(e.into());251
+ }234252
Ok(cmd)235253
}236254
255
+ /// Ends and submits `cmd`. It goes back to the spare list if that fails.256
+ fn end_and_submit(&mut self, cmd: vk::CommandBuffer) -> Result<Arc<FenceInner>, Error> {257
+ let submitted = self.submit_cmd(cmd);258
+ if submitted.is_err() {259
+ self.spare_cmds.push(cmd);260
+ }261
+ submitted262
+ }263
+237264
#[profiling::function]238
- fn end_and_submit(&self, cmd: vk::CommandBuffer) -> Result<Arc<FenceInner>, Error> {265
+ fn submit_cmd(&self, cmd: vk::CommandBuffer) -> Result<Arc<FenceInner>, Error> {239266
let d = &self.shared.device.device;240267
{241268
profiling::scope!("end_command_buffer");@@ -270,28 +297,39 @@ impl VulkanRenderer {
270297
/// go first, so `record` sees their pixels.271298
fn one_shot(272299
&mut self,273
- record: impl FnOnce(&ash::Device, vk::CommandBuffer, u32),300
+ record: impl FnOnce(&ash::Device, vk::CommandBuffer, u32, &mut LayoutLog),274301
) -> Result<(), Error> {275302
let cmd = self.begin()?;276
- let uploads = self.record_uploads(cmd);303
+ let mut recorded = self.record_uploads(cmd);277304
record(278305
&self.shared.device.device,279306
cmd,280307
self.shared.device.queue_family,308
+ &mut recorded.layouts,281309
);282
- let fence = self.finish(cmd, uploads, Vec::new())?;310
+ let fence = self.finish(cmd, recorded, Vec::new())?;283311
Ok(fence.wait()?)284312
}285313
286
- /// Submits `cmd`, which holds `uploads` and works on `keep`, and tracks287
- /// it until its fence signals.314
+ /// Submits `cmd`, which holds `recorded` and works on `keep`, and tracks315
+ /// it until its fence signals. On success the layouts it recorded take316
+ /// effect, on failure the uploads are queued again.288317
fn finish(289318
&mut self,290319
cmd: vk::CommandBuffer,291
- uploads: Vec<Upload>,320
+ recorded: Recorded,292321
mut keep: Vec<Arc<ImageInner>>,293322
) -> Result<Arc<FenceInner>, Error> {294
- let fence = self.end_and_submit(cmd)?;323
+ let Recorded { uploads, layouts } = recorded;324
+ let fence = match self.end_and_submit(cmd) {325
+ Ok(fence) => fence,326
+ Err(e) => {327
+ self.upload_bytes += uploads.iter().map(Upload::bytes).sum::<usize>();328
+ self.uploads.splice(0..0, uploads);329
+ return Err(e);330
+ }331
+ };332
+ layouts.commit();295333
keep.extend(uploads.iter().map(|u| u.image.clone()));296334
self.pending.push(Pending {297335
fence: fence.clone(),@@ -304,17 +342,25 @@ impl VulkanRenderer {
304342
305343
/// Records every queued upload into `cmd` and hands them back to keep306344
/// alive until it finishes.307
- fn record_uploads(&mut self, cmd: vk::CommandBuffer) -> Vec<Upload> {345
+ fn record_uploads(&mut self, cmd: vk::CommandBuffer) -> Recorded {308346
let uploads = std::mem::take(&mut self.uploads);309347
self.upload_bytes = 0;348
+ let mut layouts = LayoutLog::default();310349
if uploads.is_empty() {311
- return uploads;350
+ return Recorded { uploads, layouts };312351
}313352
let d = &self.shared.device.device;314353
let family = self.shared.device.queue_family;315354
unsafe {316355
for u in &uploads {317
- acquire(d, cmd, family, &u.image, vk::ImageLayout::TRANSFER_DST_OPTIMAL);356
+ acquire(357
+ d,358
+ cmd,359
+ family,360
+ &u.image,361
+ vk::ImageLayout::TRANSFER_DST_OPTIMAL,362
+ &mut layouts,363
+ );318364
}319365
for (i, u) in uploads.iter().enumerate() {320366
if uploads[..i].iter().any(|e| Arc::ptr_eq(&e.image, &u.image)) {@@ -343,10 +389,11 @@ impl VulkanRenderer {
343389
family,344390
&u.image,345391
vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,392
+ &mut layouts,346393
);347394
}348395
}349
- uploads396
+ Recorded { uploads, layouts }350397
}351398
352399
/// Submits the queued uploads without waiting for a frame to carry them.@@ -355,8 +402,8 @@ impl VulkanRenderer {
355402
return Ok(());356403
}357404
let cmd = self.begin()?;358
- let uploads = self.record_uploads(cmd);359
- self.finish(cmd, uploads, Vec::new()).map(drop)405
+ let recorded = self.record_uploads(cmd);406
+ self.finish(cmd, recorded, Vec::new()).map(drop)360407
}361408
362409
#[profiling::function]@@ -385,7 +432,7 @@ impl VulkanRenderer {
385432
});386433
}387434
let cmd = self.begin()?;388
- let uploads = self.record_uploads(cmd);435
+ let mut recorded = self.record_uploads(cmd);389436
let d = &self.shared.device.device;390437
let family = self.shared.device.queue_family;391438
let push = &self.shared.device.push_descriptor;@@ -393,7 +440,14 @@ impl VulkanRenderer {
393440
let sampler = self.sampler();394441
unsafe {395442
for t in &sampled {396
- acquire(d, cmd, family, t, vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL);443
+ acquire(444
+ d,445
+ cmd,446
+ family,447
+ t,448
+ vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,449
+ &mut recorded.layouts,450
+ );397451
}398452
acquire(399453
d,@@ -401,6 +455,7 @@ impl VulkanRenderer {
401455
family,402456
&image,403457
vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,458
+ &mut recorded.layouts,404459
);405460
let attachments = [vk::RenderingAttachmentInfo::default()406461
.image_view(image.view)@@ -509,7 +564,7 @@ impl VulkanRenderer {
509564
}510565
}511566
sampled.push(image);512
- let fence = self.finish(cmd, uploads, sampled)?;567
+ let fence = self.finish(cmd, recorded, sampled)?;513568
Ok(SyncPoint::from(VkFence(fence)))514569
}515570
@@ -585,12 +640,13 @@ impl VulkanRenderer {
585640
height: h as u32,586641
depth: 1,587642
});588
- self.uploads.push(Upload {643
+ let upload = Upload {589644
image: image.clone(),590645
staging,591646
copy,592
- });593
- self.upload_bytes += w * h * BYTES_PER_PIXEL;647
+ };648
+ self.upload_bytes += upload.bytes();649
+ self.uploads.push(upload);594650
if self.upload_bytes > UPLOAD_BATCH_BYTES {595651
self.flush_uploads()?;596652
}@@ -636,13 +692,14 @@ impl VulkanRenderer {
636692
});637693
let buffer = staging.buffer;638694
let source = image.clone();639
- self.one_shot(|d, cmd, family| unsafe {695
+ self.one_shot(|d, cmd, family, layouts| unsafe {640696
acquire(641697
d,642698
cmd,643699
family,644700
&source,645701
vk::ImageLayout::TRANSFER_SRC_OPTIMAL,702
+ layouts,646703
);647704
d.cmd_copy_image_to_buffer(648705
cmd,