]> git.tdb.fi Git - libs/gl.git/commitdiff
Add a wrapper class for recording Vulkan commands
authorMikko Rasa <tdb@tdb.fi>
Sat, 19 Mar 2022 08:51:40 +0000 (10:51 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sat, 19 Mar 2022 08:51:40 +0000 (10:51 +0200)
This makes the command syntax shorter by storing the command buffer
handle in the wrapper.

14 files changed:
source/backends/vulkan/buffer_backend.cpp
source/backends/vulkan/commands_backend.cpp
source/backends/vulkan/pipelinestate_backend.cpp
source/backends/vulkan/pipelinestate_backend.h
source/backends/vulkan/synchronizer.cpp
source/backends/vulkan/synchronizer.h
source/backends/vulkan/texture1d_backend.cpp
source/backends/vulkan/texture2d_backend.cpp
source/backends/vulkan/texture3d_backend.cpp
source/backends/vulkan/texture_backend.cpp
source/backends/vulkan/texturecube_backend.cpp
source/backends/vulkan/transferqueue.cpp
source/backends/vulkan/transferqueue.h
source/backends/vulkan/vulkan.h

index c3dcb8e12c5ccbb1fb21d9abc0b76862a65cad16..bde76beaf8119b5985203b593117b0b799a2311b 100644 (file)
@@ -121,14 +121,12 @@ void Buffer::AsyncTransfer::allocate()
                        [&buf, off, sz](){
                                buf.device.get_synchronizer().write_buffer(buf.handle, off, sz);
                        },
-                       [&buf, off, sz](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
-                               const VulkanFunctions &vk = buf.device.get_functions();
-
+                       [&buf, off, sz](const VulkanCommandRecorder &vkCmd, VkBuffer staging_buf, size_t src_off){
                                VkBufferCopy region = { };
                                region.srcOffset = src_off;
                                region.dstOffset = off;
                                region.size = sz;
-                               vk.CmdCopyBuffer(cmd_buf, staging_buf, buf.handle, 1, &region);
+                               vkCmd.CopyBuffer(staging_buf, buf.handle, 1, &region);
                        });
        }
 }
index 13acd8a38495baa6091afe43beb1a07ae0af7216..2698d43173a819bcf153ee2488e1502f1979707a 100644 (file)
@@ -149,21 +149,22 @@ void VulkanCommands::begin_render_pass(bool clear, const ClearValue *clear_value
 void VulkanCommands::end_render_pass()
 {
        const VulkanFunctions &vk = device.get_functions();
+       VulkanCommandRecorder vkCmd(vk, pass_buffer);
 
        vk.EndCommandBuffer(pass_buffer);
 
-       device.get_transfer_queue().dispatch_transfers(primary_buffer);
+       device.get_transfer_queue().dispatch_transfers(vkCmd);
 
        Synchronizer &sync = device.get_synchronizer();
        sync.reset();
        if(!fb_is_swapchain)
                framebuffer->prepare_image_layouts(discard_fb_contents);
-       sync.barrier(primary_buffer);
+       sync.barrier(vkCmd);
 
        const VkRenderPassBeginInfo &begin_info = *reinterpret_cast<const VkRenderPassBeginInfo *>(pass_begin_info.data());
-       vk.CmdBeginRenderPass(primary_buffer, begin_info, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
-       vk.CmdExecuteCommands(primary_buffer, 1, &pass_buffer);
-       vk.CmdEndRenderPass(primary_buffer);
+       vkCmd.BeginRenderPass(begin_info, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
+       vkCmd.ExecuteCommands(1, &pass_buffer);
+       vkCmd.EndRenderPass();
 
        framebuffer = 0;
        viewport = Rect::max();
@@ -253,15 +254,16 @@ void VulkanCommands::draw_instanced(const Batch &batch, unsigned count)
                throw invalid_operation("VulkanCommands::draw_instanced");
 
        const VulkanFunctions &vk = device.get_functions();
+       VulkanCommandRecorder vkCmd(vk, pass_buffer);
 
        if(!framebuffer)
                 begin_render_pass(false, 0);
 
        pipeline_state->refresh();
-       pipeline_state->apply(pass_buffer, last_pipeline, frame_index, fb_is_swapchain);
+       pipeline_state->apply(vkCmd, last_pipeline, frame_index, fb_is_swapchain);
        last_pipeline = pipeline_state;
        unsigned first_index = batch.get_offset()/batch.get_index_size();
-       vk.CmdDrawIndexed(pass_buffer, batch.size(), count, first_index, 0, 0);
+       vkCmd.DrawIndexed(batch.size(), count, first_index, 0, 0);
 }
 
 void VulkanCommands::resolve_multisample(Framebuffer &)
index d14bc00c6539bb3c9509fab26abf4610cd151d1f..7deae24c9b09b59ada978489feb1bdfd6b1637a9 100644 (file)
@@ -386,10 +386,9 @@ unsigned VulkanPipelineState::fill_descriptor_writes(unsigned index, unsigned fr
        return n_writes;
 }
 
-void VulkanPipelineState::apply(VkCommandBuffer command_buffer, const VulkanPipelineState *last, unsigned frame, bool negative_viewport) const
+void VulkanPipelineState::apply(const VulkanCommandRecorder &vkCmd, const VulkanPipelineState *last, unsigned frame, bool negative_viewport) const
 {
        const PipelineState &self = *static_cast<const PipelineState *>(this);
-       const VulkanFunctions &vk = device.get_functions();
 
        if(!last)
        {
@@ -424,14 +423,14 @@ void VulkanPipelineState::apply(VkCommandBuffer command_buffer, const VulkanPipe
        }
 
        if(unapplied&PipelineState::SHPROG)
-               vk.CmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, handle);
+               vkCmd.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, handle);
 
        if(unapplied&PipelineState::VERTEX_SETUP)
                if(const VertexSetup *vs = self.vertex_setup)
                {
-                       vk.CmdBindVertexBuffers(command_buffer, 0, vs->n_bindings, vs->buffers, vs->offsets);
+                       vkCmd.BindVertexBuffers(0, vs->n_bindings, vs->buffers, vs->offsets);
                        VkIndexType index_type = static_cast<VkIndexType>(get_vulkan_index_type(vs->get_index_type()));
-                       vk.CmdBindIndexBuffer(command_buffer, vs->get_index_buffer()->handle, 0, index_type);
+                       vkCmd.BindIndexBuffer(vs->get_index_buffer()->handle, 0, index_type);
                }
 
        if(!self.uniform_blocks.empty())
@@ -440,7 +439,7 @@ void VulkanPipelineState::apply(VkCommandBuffer command_buffer, const VulkanPipe
                if(first_block.used && first_block.binding==ReflectData::PUSH_CONSTANT)
                {
                        const UniformBlock &pc_block = *first_block.block;
-                       vk.CmdPushConstants(command_buffer, self.shprog->layout_handle, self.shprog->stage_flags,
+                       vkCmd.PushConstants(self.shprog->layout_handle, self.shprog->stage_flags,
                                pc_block.get_offset(), pc_block.get_data_size(), pc_block.get_data_pointer());
                }
        }
@@ -453,7 +452,7 @@ void VulkanPipelineState::apply(VkCommandBuffer command_buffer, const VulkanPipe
                        descriptor_set_handles.push_back(device.get_descriptor_pool().get_descriptor_set(
                                self.descriptor_set_slots[i], self, i, frame));
 
-               vk.CmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, self.shprog->layout_handle,
+               vkCmd.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, self.shprog->layout_handle,
                        first_changed_desc_set, descriptor_set_handles.size(), descriptor_set_handles.data(), 0, 0);
        }
 
@@ -476,7 +475,7 @@ void VulkanPipelineState::apply(VkCommandBuffer command_buffer, const VulkanPipe
                        }
                        viewport.minDepth = 0.0f;
                        viewport.maxDepth = 1.0f;
-                       vk.CmdSetViewport(command_buffer, 0, 1, &viewport);
+                       vkCmd.SetViewport(0, 1, &viewport);
                }
 
                if(unapplied&PipelineState::SCISSOR)
@@ -487,7 +486,7 @@ void VulkanPipelineState::apply(VkCommandBuffer command_buffer, const VulkanPipe
                        scissor.offset.y = scissor_rect.bottom;
                        scissor.extent.width = scissor_rect.width;
                        scissor.extent.height = scissor_rect.height;
-                       vk.CmdSetScissor(command_buffer, 0, 1, &scissor);
+                       vkCmd.SetScissor(0, 1, &scissor);
                }
        }
 
index d033fbb8591897309cd4e7c106a204600cd19063..892d8b3a12a127cc20d64b445a0a56bb07f601b1 100644 (file)
@@ -8,6 +8,7 @@ namespace Msp {
 namespace GL {
 
 class Device;
+class VulkanCommandRecorder;
 
 class VulkanPipelineState: public NonCopyable
 {
@@ -38,7 +39,7 @@ protected:
        VkDescriptorSetLayout get_descriptor_set_layout(unsigned) const;
        unsigned fill_descriptor_writes(unsigned, unsigned, std::vector<char> &) const;
 
-       void apply(VkCommandBuffer, const VulkanPipelineState *, unsigned, bool) const;
+       void apply(const VulkanCommandRecorder &, const VulkanPipelineState *, unsigned, bool) const;
 };
 
 using PipelineStateBackend = VulkanPipelineState;
index 9995f248c89d06503dc00a507b2748e08f3cb964..28488fd0d28ad81188fe882b7e2c81ede29ebc59 100644 (file)
@@ -121,10 +121,8 @@ void Synchronizer::reset()
                i.pending_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 }
 
-void Synchronizer::barrier(VkCommandBuffer command_buffer)
+void Synchronizer::barrier(const VulkanCommandRecorder &vkCmd)
 {
-       const VulkanFunctions &vk = device.get_functions();
-
        if(buffer_accesses.empty() && image_accesses.empty())
                return;
 
@@ -201,7 +199,7 @@ void Synchronizer::barrier(VkCommandBuffer command_buffer)
        if(!dst_stage)
                dst_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
 
-       vk.CmdPipelineBarrier(command_buffer, src_stage, dst_stage, 0, 0, 0,
+       vkCmd.PipelineBarrier(src_stage, dst_stage, 0, 0, 0,
                buffer_barriers.size(), buffer_barriers.data(), image_barriers.size(), image_barriers.data());
 
        for(auto i=buffer_accesses.begin(); i!=buffer_accesses.end(); )
index 077274f8200a0fd1fad5417dcde7d92ba9995b4e..32a4d9793e303125a76e841aff368276ab791541 100644 (file)
@@ -8,6 +8,8 @@
 namespace Msp {
 namespace GL {
 
+class VulkanCommandRecorder;
+
 class Synchronizer
 {
 private:
@@ -40,7 +42,7 @@ public:
        void split_image_mipmap(VkImage, unsigned, unsigned);
        void change_image_layout(VkImage, unsigned, int, unsigned, bool);
        void reset();
-       void barrier(VkCommandBuffer);
+       void barrier(const VulkanCommandRecorder &);
 
 private:
        bool is_write_layout(unsigned);
index 539060da3f13b54d2dc3e4966ac4ac9fad9075a4..59ef60d010c1bb8a310fee19dcb1fc85312a37b1 100644 (file)
@@ -34,9 +34,7 @@ void VulkanTexture1D::sub_image(unsigned level, int x, unsigned wd, const void *
                [this, level, discard](){
                        change_layout(level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
                },
-               [this, level, x, wd](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
-                       const VulkanFunctions &vk = device.get_functions();
-
+               [this, level, x, wd](const VulkanCommandRecorder &vkCmd, VkBuffer staging_buf, size_t src_off){
                        VkBufferImageCopy region = { };
                        region.bufferOffset = src_off;
                        region.imageSubresource.aspectMask = get_vulkan_aspect(get_components(storage_fmt));
@@ -45,7 +43,7 @@ void VulkanTexture1D::sub_image(unsigned level, int x, unsigned wd, const void *
                        region.imageSubresource.layerCount = 1;
                        region.imageOffset = { x, 0, 0 };
                        region.imageExtent = { wd, 1, 1 };
-                       vk.CmdCopyBufferToImage(cmd_buf, staging_buf, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
+                       vkCmd.CopyBufferToImage(staging_buf, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
                });
 
        stage_pixels(staging, data, wd);
index 1ab49b888a63a5eeeebb7cc626ebc21d9a243050..d1bb74f55415c8f916577c36c5f2a1f237e29129 100644 (file)
@@ -69,9 +69,7 @@ void *VulkanTexture2D::AsyncTransfer::allocate()
                [&tex, level, discard](){
                        tex.change_layout(level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
                },
-               [&tex, level, x, y, wd, ht](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
-                       const VulkanFunctions &vk = tex.device.get_functions();
-
+               [&tex, level, x, y, wd, ht](const VulkanCommandRecorder &vkCmd, VkBuffer staging_buf, size_t src_off){
                        VkBufferImageCopy region = { };
                        region.bufferOffset = src_off;
                        region.imageSubresource.aspectMask = get_vulkan_aspect(get_components(tex.storage_fmt));
@@ -80,7 +78,7 @@ void *VulkanTexture2D::AsyncTransfer::allocate()
                        region.imageSubresource.layerCount = 1;
                        region.imageOffset = { x, y, 0 };
                        region.imageExtent = { wd, ht, 1 };
-                       vk.CmdCopyBufferToImage(cmd_buf, staging_buf, tex.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
+                       vkCmd.CopyBufferToImage(staging_buf, tex.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
                });
 }
 
index 67adb8d130e610173895d84acfd1d69a2c90ff5e..d2180556bce4ae645eb491ea517fa533c6509fb0 100644 (file)
@@ -40,9 +40,7 @@ void VulkanTexture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd
                [this, level, discard](){
                        change_layout(level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
                },
-               [this, level, x, y, z, wd, ht, dp](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
-                       const VulkanFunctions &vk = device.get_functions();
-
+               [this, level, x, y, z, wd, ht, dp](const VulkanCommandRecorder &vkCmd, VkBuffer staging_buf, size_t src_off){
                        VkBufferImageCopy region = { };
                        region.bufferOffset = src_off;
                        region.imageSubresource.aspectMask = get_vulkan_aspect(get_components(storage_fmt));
@@ -51,7 +49,7 @@ void VulkanTexture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd
                        region.imageSubresource.layerCount = (is_array() ? dp : 1);
                        region.imageOffset = { x, y, (is_array() ? 0 : z) };
                        region.imageExtent = { wd, ht, (is_array() ? 1 : dp) };
-                       vk.CmdCopyBufferToImage(cmd_buf, staging_buf, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
+                       vkCmd.CopyBufferToImage(staging_buf, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
                });
 
        stage_pixels(staging, data, wd*ht*dp);
index bf2692172c922295c835012ccc0637ab2d909aa8..5b73749884892aad06f69589648e4bad16b663aa 100644 (file)
@@ -146,9 +146,8 @@ void VulkanTexture::generate_mipmap()
                                change_layout(i, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false);
                                change_layout(i+1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
                        },
-                       [this, i](VkCommandBuffer cmd_buf, VkBuffer, size_t){
+                       [this, i](const VulkanCommandRecorder &vkCmd, VkBuffer, size_t){
                                const Texture &self = *static_cast<const Texture *>(this);
-                               const VulkanFunctions &vk = device.get_functions();
 
                                VkImageBlit region = { };
                                region.srcSubresource.aspectMask = get_vulkan_aspect(get_components(self.storage_fmt));
@@ -160,7 +159,7 @@ void VulkanTexture::generate_mipmap()
 
                                fill_mipmap_blit(i, &region);
 
-                               vk.CmdBlitImage(cmd_buf, handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                               vkCmd.BlitImage(handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                                        1, &region, VK_FILTER_LINEAR);
                        });
        }
index a92247d56746ed22426cf90a2e26867b718e3b35..f0b941bfbe14e32d9e222db6e80cf0f940d5835a 100644 (file)
@@ -37,9 +37,7 @@ void VulkanTextureCube::sub_image(unsigned face, unsigned level, int x, int y, u
                [this, level, discard](){
                        change_layout(level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
                },
-               [this, face, level, x, y, wd, ht](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
-                       const VulkanFunctions &vk = device.get_functions();
-
+               [this, face, level, x, y, wd, ht](const VulkanCommandRecorder &vkCmd, VkBuffer staging_buf, size_t src_off){
                        VkBufferImageCopy region = { };
                        region.bufferOffset = src_off;
                        region.imageSubresource.aspectMask = get_vulkan_aspect(get_components(storage_fmt));
@@ -48,7 +46,7 @@ void VulkanTextureCube::sub_image(unsigned face, unsigned level, int x, int y, u
                        region.imageSubresource.layerCount = 1;
                        region.imageOffset = { x, y, 0 };
                        region.imageExtent = { wd, ht, 1 };
-                       vk.CmdCopyBufferToImage(cmd_buf, staging_buf, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
+                       vkCmd.CopyBufferToImage(staging_buf, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
                });
 
        stage_pixels(staging, data, wd*ht);
index f6f3c6f5079f2c2a01812348616d8b1fb83ef367..5419245b3ac793dc1bc2936e7826e124b31d0df5 100644 (file)
@@ -78,7 +78,7 @@ TransferQueue::PendingTransfer &TransferQueue::insert_transfer(PendingTransfer &
        return *j;
 }
 
-void TransferQueue::dispatch_transfers(VkCommandBuffer command_buffer)
+void TransferQueue::dispatch_transfers(const VulkanCommandRecorder &vkCmd)
 {
        if(transfers.empty())
                return;
@@ -90,12 +90,12 @@ void TransferQueue::dispatch_transfers(VkCommandBuffer command_buffer)
                for(; (j!=transfers.end() && j->order==i->order); ++j)
                        j->synchronize();
 
-               device.get_synchronizer().barrier(command_buffer);
+               device.get_synchronizer().barrier(vkCmd);
 
                for(; i!=j; ++i)
                {
                        VkBuffer buffer = (i->buffer_index>=0 ? buffers[i->buffer_index].buffer : 0);
-                       i->transfer(command_buffer, buffer, i->offset);
+                       i->transfer(vkCmd, buffer, i->offset);
                        if(i->buffer_index>=0)
                                buffers[i->buffer_index].last_frame = current_frame;
                }
index e78137fc4067701fc9a2168ffc6f5e673392e0cd..536edbd8782830f1352444e2c5f38419653523f4 100644 (file)
@@ -10,6 +10,7 @@ namespace GL {
 
 class Buffer;
 class Device;
+class VulkanCommandRecorder;
 
 class TransferQueue
 {
@@ -39,7 +40,7 @@ private:
                std::size_t size = 0;
                void *staging_address = 0;
                std::function<void()> synchronize;
-               std::function<void(VkCommandBuffer, VkBuffer, std::size_t)> transfer;
+               std::function<void(const VulkanCommandRecorder &, VkBuffer, std::size_t)> transfer;
        };
 
        Device &device;
@@ -68,7 +69,7 @@ private:
        PendingTransfer &insert_transfer(PendingTransfer &&);
 
 public:
-       void dispatch_transfers(VkCommandBuffer);
+       void dispatch_transfers(const VulkanCommandRecorder &);
 };
 
 template<typename S, typename T>
index c41813fa8a588f4f822942b92eba72c859f913b9..d77e2cc424e852852adb7ac31e75eeb7b6d3569c 100644 (file)
@@ -417,6 +417,61 @@ public:
        { return { vkSetDebugUtilsObjectName(device, &rNameInfo), "vkSetDebugUtilsObjectName" }; }
 };
 
+class VulkanCommandRecorder
+{
+private:
+       const VulkanFunctions &vk;
+       VkCommandBuffer commandBuffer;
+
+public:
+       VulkanCommandRecorder(const VulkanFunctions &v, VkCommandBuffer b): vk(v), commandBuffer(b) { }
+
+       void ExecuteCommands(std::uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) const
+       { vk.CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers); }
+
+       void PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) const
+       { vk.CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); }
+
+       void BeginRenderPass(const VkRenderPassBeginInfo &rRenderPassBegin, VkSubpassContents contents) const
+       { vk.CmdBeginRenderPass(commandBuffer, rRenderPassBegin, contents); }
+
+       void EndRenderPass() const
+       { vk.CmdEndRenderPass(commandBuffer); }
+
+       void BindPipeline(VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) const
+       { vk.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline); }
+
+       void BindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, std::uint32_t firstSet, std::uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets, std::uint32_t dynamicOffsetCount, const std::uint32_t *pDynamicOffsets) const
+       { vk.CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); }
+
+       void PushConstants(VkPipelineLayout layout, VkShaderStageFlags stageFlags, std::uint32_t offset, std::uint32_t size, const void *pValues) const
+       { vk.CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues); }
+
+       void CopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, std::uint32_t regionCount, const VkBufferCopy *pRegions) const
+       { vk.CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); }
+
+       void CopyBufferToImage(VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, std::uint32_t regionCount, const VkBufferImageCopy *pRegions) const
+       { vk.CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions); }
+
+       void BlitImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) const
+       { vk.CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter); }
+
+       void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) const
+       { vk.CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType); }
+
+       void DrawIndexed(std::uint32_t indexCount, std::uint32_t instanceCount, std::uint32_t firstIndex, std::int32_t vertexOffset, std::uint32_t firstInstance) const
+       { vk.CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); }
+
+       void BindVertexBuffers(std::uint32_t firstBinding, std::uint32_t bindingCount, const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) const
+       { vk.CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); }
+
+       void SetViewport(std::uint32_t firstViewport, std::uint32_t viewportCount, const VkViewport *pViewports) const
+       { vk.CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports); }
+
+       void SetScissor(std::uint32_t firstScissor, std::uint32_t scissorCount, const VkRect2D *pScissors) const
+       { vk.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors); }
+};
+
 } // namespace GL
 } // namespace Msp