1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
//! The lower-level "raw" frame type allowing to draw directly to the window's swapchain image.

use crate::vk;
use crate::vk::command_buffer::pool::standard::StandardCommandPoolBuilder;
use crate::vk::command_buffer::{
    AutoCommandBufferBuilderContextError, BeginRenderPassError, BlitImageError,
    ClearColorImageError, CopyBufferError, CopyBufferImageError, DrawError, DrawIndexedError,
    DynamicState, FillBufferError, UpdateBufferError,
};
use crate::vk::pipeline::input_assembly::Index;
use crate::window;
use crate::window::SwapchainImage;
use std::sync::{Arc, Mutex};

/// Allows the user to draw a single **RawFrame** to the surface of a window.
///
/// The application's **view** function is called each time the application is ready to retrieve a
/// new image that will be displayed to a window. The **RawFrame** type can be thought of as the
/// canvas to which you draw this image.
///
/// ## Under the hood - Vulkan
///
/// There are a couple of main goals for the **RawFrame** type:
///
/// - Allow for maximum flexibility and customisation over the:
///   - Render Pass
///   - Graphics Pipeline
///   - Framebuffer Creation and
///   - Command Buffer
///   to the extent that the user may not interfere with the expected behaviour of the **App**.
/// - Provide reasonable defaults for each step so that it is friendly for new users.
///
/// **Vulkan**
///
/// Nannou uses Vulkan for interacting with the available graphics devices on a machine and for
/// presenting images to the swapchain associated with each window. It does so via the **vulkano**
/// crate, which is exposed publicly from the crate root. **vulkano** aims to be a type-safe,
/// near-zero-cost API around the low-level Vulkan API. As a result **vulkano** tends to be a lot
/// nicer than using the Vulkan API directly where it is the role of the user to maintain all the
/// invariants described within the spec themselves. Due to this higher-level nature, nannou
/// exposes the vulkano API directly in some areas where it is deemed reasonable/safe to do so.
///
/// In order to provide maximum flexibility, nannou allows for fully custom
/// [**RenderPass**](https://docs.rs/vulkano/latest/vulkano/framebuffer/struct.RenderPass.html) and
/// [**GraphicsPipeline**](https://docs.rs/vulkano/latest/vulkano/pipeline/struct.GraphicsPipeline.html)
/// via the **vulkano** API but aims to take care of the surface creation, swapchain tedium and
/// rendering synchronisation behind the scenes.
///
/// ### Render Pass and Swapchain Framebuffers.
///
/// The render pass describes the destination for the output of the graphics pipeline. It is
/// essential that the render pass uses the same pixel format of the window's surface. It also must
/// be initialised with the same logical device with which the surface was initialised.
///
/// For now, it is up to the user to ensure these gaurantees are met. In the future nannou may
/// provide a simplified constructor that implicitly uses the same logical device and format
/// associated with the surface.
///
/// The user can create the framebuffers for the swapchain using this render pass by using the
/// **SwapchainFramebuffers** type. While under the hood there is no distinction between the
/// Framebuffer type used to draw to a swapchain image and any other image, nannou chooses to wrap
/// these framebuffers in a type to ensure the following invariants are met:
///
/// - There must be one framebuffer per swapchain image.
/// - Each framebuffer must be recreated to match the dimensions of the swapchain each time the
///   swapchain requires recreation. This will occur any time the window is resized on desktop or
///   when an app comes in or out of focus on Android, and possibly in many other cases not
///   mentioned here.
/// - It should be impossible to write to these framebuffers outside the **view** function to
///   ensure framebuffer availability.
/// - Each call to **view** must draw to the framebuffer associated with the image that is ready as
///   indicated by the `swapchain::acquire_next_image` function.
///
/// As a result, access to the swapchain framebuffers may feel relatively restrictive. If you
/// require greater flexibility (e.g. control over framebuffer dimensions, the ability to draw to a
/// framebuffer outside the **view** function, etc) then consider creating and writing to another
/// intermediary framebuffer before drawing to the swapchain framebuffers.
///
/// See [the vulkano documenation](https://docs.rs/vulkano/latest/vulkano/framebuffer/index.html)
/// for more details on render passes and framebuffers.
///
/// ### Graphics Pipeline
///
/// The role of the `GraphicsPipeline` is similar to that of the GL "program" but much more
/// detailed and explicit. It allows for describing and chaining together a series of custom
/// shaders.
///
/// For more information on the graphics pipeline and how to create one, see [the vulkano
/// documentation](https://docs.rs/vulkano/latest/vulkano/pipeline/index.html#creating-a-graphics-pipeline).
///
/// ### Command Buffer
///
/// The API for the **Frame** type maps directly onto a vulkano `AutoCommandBufferBuilder` under
/// the hood. This `AutoCommandBufferBuilder` is created using the `primary_one_time_submit`
/// constructor. When returned, the **App** will build the command buffer and submit it to the GPU.
/// Note that certain builder methods are *not* provided in order to avoid unexpected behaviour.
/// E.g. the `build` and submit methods are not provided as it is important that the **App** is
/// able to build the command buffer and synchronise its submission with the swapchain.
///
/// Use the **frame.add_commands()** method to begin chaining together commands. You may call this
/// more than once throughout the duration of the **view** function.
///
/// See [the vulkano
/// documentation](https://docs.rs/vulkano/latest/vulkano/command_buffer/index.html) for more
/// details on how command buffers work in vulkano.
///
/// **Note:** If you find you are unable to do something or that this API is too restrictive,
/// please open an issue about it so that might be able to work out a solution!
pub struct RawFrame {
    // The `AutoCommandBufferBuilder` type used for building the frame's command buffer.
    //
    // An `Option` is used here to allow for taking the builder by `self` as type's builder methods
    // require consuming `self` and returning a new `AutoCommandBufferBuilder` as a result.
    //
    // This `Mutex` is only ever locked for the duration of the addition of a single command.
    command_buffer_builder: Mutex<Option<AutoCommandBufferBuilder>>,
    // The `Id` whose surface the swapchain image is associated with.
    window_id: window::Id,
    // The `nth` frame that has been presented to the window since the start of the application.
    nth: u64,
    // The index associated with the swapchain image.
    swapchain_image_index: usize,
    // The image to which this frame is drawing.
    swapchain_image: Arc<SwapchainImage>,
    // The index of the frame before which this swapchain was created.
    swapchain_frame_created: u64,
    // The queue on which the swapchain image will be drawn.
    queue: Arc<vk::Queue>,
}

/// A builder type that allows chaining together commands for the command buffer that will be used
/// to draw to the swapchain image framebuffer associated with this **RawFrame**.
pub struct AddCommands<'a> {
    frame: &'a RawFrame,
}

// The `AutoCommandBufferBuilder` type used for building the frame's command buffer.
type AutoCommandBufferBuilder = vk::AutoCommandBufferBuilder<StandardCommandPoolBuilder>;

impl RawFrame {
    // Initialise a new empty frame ready for "drawing".
    pub(crate) fn new_empty(
        queue: Arc<vk::Queue>,
        window_id: window::Id,
        nth: u64,
        swapchain_image_index: usize,
        swapchain_image: Arc<SwapchainImage>,
        swapchain_frame_created: u64,
    ) -> Result<Self, vk::OomError> {
        let device = queue.device().clone();
        let cb_builder = AutoCommandBufferBuilder::primary_one_time_submit(device, queue.family())?;
        let command_buffer_builder = Mutex::new(Some(cb_builder));
        let frame = RawFrame {
            command_buffer_builder,
            window_id,
            nth,
            swapchain_image_index,
            swapchain_image,
            swapchain_frame_created,
            queue,
        };
        Ok(frame)
    }

    // Called after the user's `view` function, this consumes the `RawFrame` and returns the inner
    // command buffer builder so that it can be completed.
    pub(crate) fn finish(self) -> AutoCommandBufferBuilder {
        self.command_buffer_builder
            .lock()
            .expect("failed to lock `command_buffer_builder`")
            .take()
            .expect("`command_buffer_builder` was `None`")
    }

    /// Returns whether or not this is the first time this swapchain image has been presented.
    ///
    /// This will be `true` following each occurrence at which the swapchain has been recreated,
    /// which may occur during resize, loop mode switch, etc.
    ///
    /// It is important to call this each frame to determine whether or not framebuffers associated
    /// with the swapchain need to be recreated.
    pub fn swapchain_image_is_new(&self) -> bool {
        // TODO: This is based on the assumption that the images will be acquired starting from
        // index `0` each time the swapchain is recreated. Verify that this is the case.
        (self.nth - self.swapchain_image_index as u64) == self.swapchain_frame_created
    }

    /// Add commands to be executed by the GPU once the **RawFrame** is returned.
    pub fn add_commands(&self) -> AddCommands {
        let frame = self;
        AddCommands { frame }
    }

    /// The `Id` of the window whose vulkan surface is associated with this frame.
    pub fn window_id(&self) -> window::Id {
        self.window_id
    }

    /// The `nth` frame for the associated window since the application started.
    ///
    /// E.g. the first frame yielded will return `0`, the second will return `1`, and so on.
    pub fn nth(&self) -> u64 {
        self.nth
    }

    /// The swapchain image that will be the target for this frame.
    ///
    /// NOTE: You should avoid using the returned `SwapchainImage` outside of the `view` function
    /// as it may become invalid at any moment. The reason we expose the `Arc` is that some of the
    /// vulkano API (including framebuffer creation) requires it to avoid some severe ownsership
    /// issues.
    pub fn swapchain_image(&self) -> &Arc<SwapchainImage> {
        &self.swapchain_image
    }

    /// The index associated with the swapchain image that will be the target for this frame.
    pub fn swapchain_image_index(&self) -> usize {
        self.swapchain_image_index
    }

    /// The queue on which the swapchain image will be drawn.
    pub fn queue(&self) -> &Arc<vk::Queue> {
        &self.queue
    }
}

impl<'a> AddCommands<'a> {
    // Maps a call onto the command buffer builder.
    fn map_cb<F, E>(self, map: F) -> Result<Self, E>
    where
        F: FnOnce(AutoCommandBufferBuilder) -> Result<AutoCommandBufferBuilder, E>,
    {
        {
            let mut guard = self
                .frame
                .command_buffer_builder
                .lock()
                .expect("failed to lock `RawFrame`'s inner command buffer builder");
            let mut builder = guard
                .take()
                .expect("the `RawFrame`'s inner command buffer should always be `Some`");
            builder = map(builder)?;
            *guard = Some(builder);
        }
        Ok(self)
    }

    /// Adds a command that enters a render pass.
    ///
    /// If `secondary` is true, then you will only be able to add secondary command buffers while
    /// you're inside the first subpass of the render pass. If `secondary` is false, you will only
    /// be able to add inline draw commands and not secondary command buffers.
    ///
    /// C must contain exactly one clear value for each attachment in the framebuffer.
    ///
    /// You must call this before you can add draw commands.
    ///
    /// [*Documentation taken from the corresponding vulkano method.*](https://docs.rs/vulkano/latest/vulkano/command_buffer/struct.AutoCommandBufferBuilder.html)
    pub fn begin_render_pass<F, C>(
        self,
        framebuffer: F,
        secondary: bool,
        clear_values: C,
    ) -> Result<Self, BeginRenderPassError>
    where
        F: vk::FramebufferAbstract
            + vk::RenderPassDescClearValues<C>
            + Clone
            + Send
            + Sync
            + 'static,
    {
        self.map_cb(move |cb| cb.begin_render_pass(framebuffer, secondary, clear_values))
    }

    /// Adds a command that jumps to the next subpass of the current render pass.
    pub fn next_subpass(
        self,
        secondary: bool,
    ) -> Result<Self, AutoCommandBufferBuilderContextError> {
        self.map_cb(move |cb| cb.next_subpass(secondary))
    }

    /// Adds a command that ends the current render pass.
    ///
    /// This must be called after you went through all the subpasses and before you can add further
    /// commands.
    pub fn end_render_pass(self) -> Result<Self, AutoCommandBufferBuilderContextError> {
        self.map_cb(move |cb| cb.end_render_pass())
    }

    /// Adds a command that blits an image to another.
    ///
    /// A *blit* is similar to an image copy operation, except that the portion of the image that
    /// is transferred can be resized. You choose an area of the source and an area of the
    /// destination, and the implementation will resize the area of the source so that it matches
    /// the size of the area of the destination before writing it.
    ///
    /// Blit operations have several restrictions:
    ///
    /// - Blit operations are only allowed on queue families that support graphics operations.
    /// - The format of the source and destination images must support blit operations, which
    ///   depends on the Vulkan implementation. Vulkan guarantees that some specific formats must
    ///   always be supported. See tables 52 to 61 of the specifications.
    /// - Only single-sampled images are allowed.
    /// - You can only blit between two images whose formats belong to the same type. The types
    ///   are: floating-point, signed integers, unsigned integers, depth-stencil.
    /// - If you blit between depth, stencil or depth-stencil images, the format of both images
    ///   must match exactly.
    /// - If you blit between depth, stencil or depth-stencil images, only the `Nearest` filter is
    ///   allowed.
    /// - For two-dimensional images, the Z coordinate must be 0 for the top-left offset and 1 for
    ///   the bottom-right offset. Same for the Y coordinate for one-dimensional images.
    /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
    ///
    /// If `layer_count` is greater than 1, the blit will happen between each individual layer as
    /// if they were separate images.
    ///
    /// # Panic
    ///
    /// - Panics if the source or the destination was not created with `device`.
    ///
    /// [*Documentation taken from the corresponding vulkano method.*](https://docs.rs/vulkano/latest/vulkano/command_buffer/struct.AutoCommandBufferBuilder.html)
    pub fn blit_image<S, D>(
        self,
        source: S,
        source_top_left: [i32; 3],
        source_bottom_right: [i32; 3],
        source_base_array_layer: u32,
        source_mip_level: u32,
        destination: D,
        destination_top_left: [i32; 3],
        destination_bottom_right: [i32; 3],
        destination_base_array_layer: u32,
        destination_mip_level: u32,
        layer_count: u32,
        filter: vk::sampler::Filter,
    ) -> Result<Self, BlitImageError>
    where
        S: vk::ImageAccess + Send + Sync + 'static,
        D: vk::ImageAccess + Send + Sync + 'static,
    {
        self.map_cb(move |cb| {
            cb.blit_image(
                source,
                source_top_left,
                source_bottom_right,
                source_base_array_layer,
                source_mip_level,
                destination,
                destination_top_left,
                destination_bottom_right,
                destination_base_array_layer,
                destination_mip_level,
                layer_count,
                filter,
            )
        })
    }

    /// Adds a command that copies an image to another.
    ///
    /// Copy operations have several restrictions:
    ///
    /// - Copy operations are only allowed on queue families that support transfer, graphics, or
    ///   compute operations.
    /// - The number of samples in the source and destination images must be equal.
    /// - The size of the uncompressed element format of the source image must be equal to the
    ///   compressed element format of the destination.
    /// - If you copy between depth, stencil or depth-stencil images, the format of both images
    ///   must match exactly.
    /// - For two-dimensional images, the Z coordinate must be 0 for the image offsets and 1 for
    ///   the extent. Same for the Y coordinate for one-dimensional images.
    /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
    ///
    /// If layer_count is greater than 1, the copy will happen between each individual layer as if
    /// they were separate images.
    ///
    /// # Panic
    ///
    /// - Panics if the source or the destination was not created with device.
    ///
    /// [*Documentation taken from the corresponding vulkano method.*](https://docs.rs/vulkano/latest/vulkano/command_buffer/struct.AutoCommandBufferBuilder.html)
    pub fn copy_image<S, D>(
        self,
        source: S,
        source_offset: [i32; 3],
        source_base_array_layer: u32,
        source_mip_level: u32,
        destination: D,
        destination_offset: [i32; 3],
        destination_base_array_layer: u32,
        destination_mip_level: u32,
        extent: [u32; 3],
        layer_count: u32,
    ) -> Result<Self, ()>
    // TODO: Expose error: https://github.com/vulkano-rs/vulkano/pull/1112
    where
        S: vk::ImageAccess + Send + Sync + 'static,
        D: vk::ImageAccess + Send + Sync + 'static,
    {
        self.map_cb(move |cb| {
            cb.copy_image(
                source,
                source_offset,
                source_base_array_layer,
                source_mip_level,
                destination,
                destination_offset,
                destination_base_array_layer,
                destination_mip_level,
                extent,
                layer_count,
            )
        })
        .map_err(|err| panic!("{}", err))
    }

    /// Adds a command that clears all the layers and mipmap levels of a color image with a
    /// specific value.
    ///
    /// # Panic
    ///
    /// Panics if `color` is not a color value.
    ///
    /// [*Documentation taken from the corresponding vulkano method.*](https://docs.rs/vulkano/latest/vulkano/command_buffer/struct.AutoCommandBufferBuilder.html)
    pub fn clear_color_image<I>(
        self,
        image: I,
        color: vk::ClearValue,
    ) -> Result<Self, ClearColorImageError>
    where
        I: vk::ImageAccess + Send + Sync + 'static,
    {
        self.map_cb(move |cb| cb.clear_color_image(image, color))
    }

    /// Adds a command that clears a color image with a specific value.
    ///
    /// # Panic
    ///
    /// Panics if color is not a color value.
    pub fn clear_color_image_dimensions<I>(
        self,
        image: I,
        first_layer: u32,
        num_layers: u32,
        first_mipmap: u32,
        num_mipmaps: u32,
        color: vk::ClearValue,
    ) -> Result<Self, ClearColorImageError>
    where
        I: vk::ImageAccess + Send + Sync + 'static,
    {
        self.map_cb(move |cb| {
            cb.clear_color_image_dimensions(
                image,
                first_layer,
                num_layers,
                first_mipmap,
                num_mipmaps,
                color,
            )
        })
    }

    /// Adds a command that copies from a buffer to another.
    ///
    /// This command will copy from the source to the destination. If their size is not equal, then
    /// the amount of data copied is equal to the smallest of the two.
    pub fn copy_buffer<S, D, T>(self, source: S, destination: D) -> Result<Self, CopyBufferError>
    where
        S: vk::TypedBufferAccess<Content = T> + Send + Sync + 'static,
        D: vk::TypedBufferAccess<Content = T> + Send + Sync + 'static,
        T: ?Sized,
    {
        self.map_cb(move |cb| cb.copy_buffer(source, destination))
    }

    /// Adds a command that copies from a buffer to an image.
    pub fn copy_buffer_to_image<S, D, Px>(
        self,
        source: S,
        destination: D,
    ) -> Result<Self, CopyBufferImageError>
    where
        S: vk::TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
        D: vk::ImageAccess + Send + Sync + 'static,
        vk::Format: vk::AcceptsPixels<Px>,
    {
        self.map_cb(move |cb| cb.copy_buffer_to_image(source, destination))
    }

    /// Adds a command that copies from a buffer to an image.
    pub fn copy_buffer_to_image_dimensions<S, D, Px>(
        self,
        source: S,
        destination: D,
        offset: [u32; 3],
        size: [u32; 3],
        first_layer: u32,
        num_layers: u32,
        mipmap: u32,
    ) -> Result<Self, CopyBufferImageError>
    where
        S: vk::TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
        D: vk::ImageAccess + Send + Sync + 'static,
        vk::Format: vk::AcceptsPixels<Px>,
    {
        self.map_cb(move |cb| {
            cb.copy_buffer_to_image_dimensions(
                source,
                destination,
                offset,
                size,
                first_layer,
                num_layers,
                mipmap,
            )
        })
    }

    /// Adds a command that copies from an image to a buffer.
    pub fn copy_image_to_buffer<S, D, Px>(
        self,
        source: S,
        destination: D,
    ) -> Result<Self, CopyBufferImageError>
    where
        S: vk::ImageAccess + Send + Sync + 'static,
        D: vk::TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
        vk::Format: vk::AcceptsPixels<Px>,
    {
        self.map_cb(move |cb| cb.copy_image_to_buffer(source, destination))
    }

    /// Adds a command that copies from an image to a buffer.
    pub fn copy_image_to_buffer_dimensions<S, D, Px>(
        self,
        source: S,
        destination: D,
        offset: [u32; 3],
        size: [u32; 3],
        first_layer: u32,
        num_layers: u32,
        mipmap: u32,
    ) -> Result<Self, CopyBufferImageError>
    where
        S: vk::ImageAccess + Send + Sync + 'static,
        D: vk::TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
        vk::Format: vk::AcceptsPixels<Px>,
    {
        self.map_cb(move |cb| {
            cb.copy_image_to_buffer_dimensions(
                source,
                destination,
                offset,
                size,
                first_layer,
                num_layers,
                mipmap,
            )
        })
    }

    /// Draw once, using the vertex_buffer.
    ///
    /// To use only some data in the buffer, wrap it in a `vk::BufferSlice`.
    pub fn draw<V, Gp, S, Pc>(
        self,
        pipeline: Gp,
        dynamic: &DynamicState,
        vertex_buffer: V,
        sets: S,
        constants: Pc,
    ) -> Result<Self, DrawError>
    where
        Gp: vk::GraphicsPipelineAbstract + vk::VertexSource<V> + Send + Sync + 'static + Clone,
        S: vk::DescriptorSetsCollection,
    {
        self.map_cb(move |cb| cb.draw(pipeline, dynamic, vertex_buffer, sets, constants))
    }

    /// Draw once, using the vertex_buffer and the index_buffer.
    ///
    /// To use only some data in a buffer, wrap it in a `vk::BufferSlice`.
    pub fn draw_indexed<V, Gp, S, Pc, Ib, I>(
        self,
        pipeline: Gp,
        dynamic: &DynamicState,
        vertex_buffer: V,
        index_buffer: Ib,
        sets: S,
        constants: Pc,
    ) -> Result<Self, DrawIndexedError>
    where
        Gp: vk::GraphicsPipelineAbstract + vk::VertexSource<V> + Send + Sync + 'static + Clone,
        S: vk::DescriptorSetsCollection,
        Ib: vk::BufferAccess + vk::TypedBufferAccess<Content = [I]> + Send + Sync + 'static,
        I: Index + 'static,
    {
        self.map_cb(move |cb| {
            cb.draw_indexed(
                pipeline,
                dynamic,
                vertex_buffer,
                index_buffer,
                sets,
                constants,
            )
        })
    }

    /// Adds a command that writes the content of a buffer.
    ///
    /// This function is similar to the `memset` function in C. The `data` parameter is a number
    /// that will be repeatedly written through the entire buffer.
    ///
    /// > **Note**: This function is technically safe because buffers can only contain integers or
    /// > floating point numbers, which are always valid whatever their memory representation is.
    /// > But unless your buffer actually contains only 32-bits integers, you are encouraged to use
    /// > this function only for zeroing the content of a buffer by passing `0` for the data.
    pub fn fill_buffer<B>(self, buffer: B, data: u32) -> Result<Self, FillBufferError>
    where
        B: vk::BufferAccess + Send + Sync + 'static,
    {
        self.map_cb(move |cb| cb.fill_buffer(buffer, data))
    }

    /// Adds a command that writes data to a buffer.
    ///
    /// If data is larger than the buffer, only the part of data that fits is written. If the
    /// buffer is larger than data, only the start of the buffer is written.
    pub fn update_buffer<B, D>(self, buffer: B, data: D) -> Result<Self, UpdateBufferError>
    where
        B: vk::TypedBufferAccess<Content = D> + Send + Sync + 'static,
        D: Send + Sync + 'static,
    {
        self.map_cb(move |cb| cb.update_buffer(buffer, data))
    }
}