CommandBufferVk.h#

The CommandBuffer class, arguably the busiest class in Vulkan, containing most functionality.

Includes#

  • PVRVk/ComputePipelineVk.h

  • PVRVk/DescriptorSetVk.h

  • PVRVk/DeviceVk.h

  • PVRVk/EventVk.h

  • PVRVk/FramebufferVk.h

  • PVRVk/GraphicsPipelineVk.h

  • PVRVk/MemoryBarrierVk.h

  • PVRVk/RaytracingPipelineVk.h

  • PVRVk/RenderPassVk.h

Included By#

Namespaces#

Classes#

Source Code#

#pragma once
#include "PVRVk/DeviceVk.h"
#include "PVRVk/DescriptorSetVk.h"
#include "PVRVk/GraphicsPipelineVk.h"
#include "PVRVk/ComputePipelineVk.h"
#include "PVRVk/RaytracingPipelineVk.h"
#include "PVRVk/MemoryBarrierVk.h"
#include "PVRVk/EventVk.h"
#include "PVRVk/FramebufferVk.h"
#include "PVRVk/RenderPassVk.h"

namespace pvrvk {
namespace impl {
class CommandBufferBase_ : public PVRVkDeviceObjectBase<VkCommandBuffer, ObjectType::e_COMMAND_BUFFER>, public DeviceObjectDebugUtils<CommandBufferBase_>
{
protected:
    class make_shared_enabler
    {
    protected:
        make_shared_enabler() = default;
        friend class CommandBufferBase_;
    };

    static CommandBufferBase constructShared(const DeviceWeakPtr& device, CommandPool& pool, VkCommandBuffer myHandle)
    {
        return std::make_shared<CommandBufferBase_>(make_shared_enabler{}, device, pool, myHandle);
    }

    std::vector<std::shared_ptr<void> > _objectReferences;

    CommandPool _pool;

    bool _isRecording;

    bool _VKSynchronization2IsSupported;

public:
    DECLARE_NO_COPY_SEMANTICS(CommandBufferBase_)
    CommandBufferBase_(make_shared_enabler, const DeviceWeakPtr& device, CommandPool pool, VkCommandBuffer myHandle)
        : PVRVkDeviceObjectBase(device, myHandle), DeviceObjectDebugUtils(), _pool(pool), _isRecording(false), _VKSynchronization2IsSupported(false)
    {}

    virtual ~CommandBufferBase_();

    void begin(const CommandBufferUsageFlags flags = CommandBufferUsageFlags(0));

    void end();

    void beginDebugUtilsLabel(const pvrvk::DebugUtilsLabel& labelInfo)
    {
        VkDebugUtilsLabelEXT vkLabelInfo = {};
        vkLabelInfo.sType = static_cast<VkStructureType>(StructureType::e_DEBUG_UTILS_LABEL_EXT);
        // The color to use for the marked region
        vkLabelInfo.color[0] = labelInfo.getR();
        vkLabelInfo.color[1] = labelInfo.getG();
        vkLabelInfo.color[2] = labelInfo.getB();
        vkLabelInfo.color[3] = labelInfo.getA();
        // The label name to give to the marked region
        vkLabelInfo.pLabelName = labelInfo.getLabelName().c_str();
        getDevice()->getPhysicalDevice()->getInstance()->getVkBindings().vkCmdBeginDebugUtilsLabelEXT(getVkHandle(), &vkLabelInfo);
    }

    void endDebugUtilsLabel() { getDevice()->getPhysicalDevice()->getInstance()->getVkBindings().vkCmdEndDebugUtilsLabelEXT(getVkHandle()); }

    void insertDebugUtilsLabel(const pvrvk::DebugUtilsLabel& labelInfo)
    {
        VkDebugUtilsLabelEXT vkLabelInfo = {};
        vkLabelInfo.sType = static_cast<VkStructureType>(StructureType::e_DEBUG_UTILS_LABEL_EXT);
        // The color to use for the marked region
        vkLabelInfo.color[0] = labelInfo.getR();
        vkLabelInfo.color[1] = labelInfo.getG();
        vkLabelInfo.color[2] = labelInfo.getB();
        vkLabelInfo.color[3] = labelInfo.getA();
        // The label name to give to the marked region
        vkLabelInfo.pLabelName = labelInfo.getLabelName().c_str();
        getDevice()->getPhysicalDevice()->getInstance()->getVkBindings().vkCmdInsertDebugUtilsLabelEXT(getVkHandle(), &vkLabelInfo);
    }

    void debugMarkerBeginEXT(pvrvk::DebugMarkerMarkerInfo& markerInfo)
    {
        VkDebugMarkerMarkerInfoEXT vkMarkerInfo = {};
        vkMarkerInfo.sType = static_cast<VkStructureType>(StructureType::e_DEBUG_MARKER_MARKER_INFO_EXT);
        // The color to use for the marked region
        vkMarkerInfo.color[0] = markerInfo.getR();
        vkMarkerInfo.color[1] = markerInfo.getG();
        vkMarkerInfo.color[2] = markerInfo.getB();
        vkMarkerInfo.color[3] = markerInfo.getA();
        // The name to give to the marked region
        vkMarkerInfo.pMarkerName = markerInfo.getMarkerName().c_str();
        getDevice()->getVkBindings().vkCmdDebugMarkerBeginEXT(getVkHandle(), &vkMarkerInfo);
    }

    void debugMarkerEndEXT() { getDevice()->getVkBindings().vkCmdDebugMarkerEndEXT(getVkHandle()); }

    void debugMarkerInsertEXT(pvrvk::DebugMarkerMarkerInfo& markerInfo)
    {
        VkDebugMarkerMarkerInfoEXT vkMarkerInfo = {};
        vkMarkerInfo.sType = static_cast<VkStructureType>(StructureType::e_DEBUG_MARKER_MARKER_INFO_EXT);
        // The color to use for the marked region
        vkMarkerInfo.color[0] = markerInfo.getR();
        vkMarkerInfo.color[1] = markerInfo.getG();
        vkMarkerInfo.color[2] = markerInfo.getB();
        vkMarkerInfo.color[3] = markerInfo.getA();
        // The name to give to the marked region
        vkMarkerInfo.pMarkerName = markerInfo.getMarkerName().c_str();
        getDevice()->getVkBindings().vkCmdDebugMarkerInsertEXT(getVkHandle(), &vkMarkerInfo);
    }

    void resetQueryPool(QueryPool& queryPool, uint32_t firstQuery, uint32_t queryCount);

    void resetQueryPool(QueryPool& queryPool, uint32_t queryIndex);

    void beginQuery(QueryPool& queryPool, uint32_t queryIndex, QueryControlFlags flags = QueryControlFlags(0));

    void endQuery(QueryPool& queryPool, uint32_t queryIndex);

    void copyQueryPoolResults(QueryPool& queryPool, uint32_t firstQuery, uint32_t queryCount, Buffer& dstBuffer, VkDeviceSize offset, VkDeviceSize stride, QueryResultFlags flags);

    void writeTimestamp(QueryPool& queryPool, uint32_t queryIndex, PipelineStageFlags pipelineStage);

    bool isRecording() { return _isRecording; }

    void bindPipeline(const GraphicsPipeline& pipeline)
    {
        _objectReferences.emplace_back(pipeline);
        getDevice()->getVkBindings().vkCmdBindPipeline(getVkHandle(), static_cast<VkPipelineBindPoint>(PipelineBindPoint::e_GRAPHICS), pipeline->getVkHandle());
    }

    void bindPipeline(ComputePipeline& pipeline)
    {
        _objectReferences.emplace_back(pipeline);
        getDevice()->getVkBindings().vkCmdBindPipeline(getVkHandle(), static_cast<VkPipelineBindPoint>(PipelineBindPoint::e_COMPUTE), pipeline->getVkHandle());
    }

    void bindPipeline(RaytracingPipeline& pipeline)
    {
        _objectReferences.emplace_back(pipeline);
        getDevice()->getVkBindings().vkCmdBindPipeline(getVkHandle(), static_cast<VkPipelineBindPoint>(PipelineBindPoint::e_RAY_TRACING_KHR), pipeline->getVkHandle());
    }

    void bindDescriptorSets(PipelineBindPoint bindingPoint, const PipelineLayout& pipelineLayout, uint32_t firstSet, const DescriptorSet* sets, uint32_t numDescriptorSets,
        const uint32_t* dynamicOffsets = nullptr, uint32_t numDynamicOffsets = 0);

    void bindDescriptorSet(PipelineBindPoint bindingPoint, const PipelineLayout& pipelineLayout, uint32_t firstSet, const DescriptorSet set,
        const uint32_t* dynamicOffsets = nullptr, uint32_t numDynamicOffsets = 0)
    {
        bindDescriptorSets(bindingPoint, pipelineLayout, firstSet, &set, 1, dynamicOffsets, numDynamicOffsets);
    }

    void bindVertexBuffers(const Buffer* buffers, uint32_t firstBinding, uint16_t bindingCount, const uint32_t* offsets = nullptr)
    {
        VkBuffer native_buffers[static_cast<uint32_t>(FrameworkCaps::MaxVertexBindings)] = { VK_NULL_HANDLE };
        for (uint32_t i = 0; i < bindingCount; ++i)
        {
            _objectReferences.emplace_back(buffers[i]);
            native_buffers[i] = buffers[i]->getVkHandle();
        }

        getDevice()->getVkBindings().vkCmdBindVertexBuffers(getVkHandle(), firstBinding, bindingCount, native_buffers, (VkDeviceSize*)offsets);
    }

    void bindVertexBuffer(const Buffer& buffer, uint32_t offset, uint16_t bindingIndex)
    {
        _objectReferences.emplace_back(buffer);
        VkDeviceSize offs = offset;
        getDevice()->getVkBindings().vkCmdBindVertexBuffers(getVkHandle(), bindingIndex, !!buffer, (buffer ? &buffer->getVkHandle() : NULL), &offs);
    }

    void bindVertexBuffer(Buffer const* buffers, uint32_t* offsets, uint16_t numBuffers, uint16_t startBinding, uint16_t numBindings);

    void bindIndexBuffer(const Buffer& buffer, uint32_t offset, IndexType indexType)
    {
        _objectReferences.emplace_back(buffer);
        getDevice()->getVkBindings().vkCmdBindIndexBuffer(getVkHandle(), buffer->getVkHandle(), offset, static_cast<VkIndexType>(indexType));
    }

    void pipelineBarrier(PipelineStageFlags srcStage, PipelineStageFlags dstStage, const MemoryBarrierSet& barriers, bool dependencyByRegion = true);

    void pipelineBarrier2(const MemoryBarrierSet2& barriers, bool dependencyByRegion = true);

    void waitForEvent(const Event& event, PipelineStageFlags srcStage, PipelineStageFlags dstStage, const MemoryBarrierSet& barriers);

    void waitForEvents(const Event* events, uint32_t numEvents, PipelineStageFlags srcStage, PipelineStageFlags dstStage, const MemoryBarrierSet& barriers);

    void setEvent(Event& event, PipelineStageFlags pipelineStageFlags = PipelineStageFlags::e_ALL_COMMANDS_BIT)
    {
        _objectReferences.emplace_back(event);
        getDevice()->getVkBindings().vkCmdSetEvent(getVkHandle(), event->getVkHandle(), static_cast<VkPipelineStageFlags>(pipelineStageFlags));
    }

    void resetEvent(Event& event, PipelineStageFlags pipelineStageFlags = PipelineStageFlags::e_ALL_COMMANDS_BIT)
    {
        getDevice()->getVkBindings().vkCmdResetEvent(getVkHandle(), event->getVkHandle(), static_cast<VkPipelineStageFlags>(pipelineStageFlags));
    }

    void reset(CommandBufferResetFlags resetFlags = CommandBufferResetFlags::e_NONE)
    {
        _objectReferences.clear();

        getDevice()->getVkBindings().vkResetCommandBuffer(getVkHandle(), static_cast<VkCommandBufferResetFlagBits>(resetFlags));
    }

    void copyImage(const Image& srcImage, const Image& dstImage, ImageLayout srcImageLayout, ImageLayout dstImageLayout, uint32_t numRegions, const ImageCopy* regions);

    void copyImageToBuffer(const Image& srcImage, ImageLayout srcImageLayout, Buffer& dstBuffer, const BufferImageCopy* regions, uint32_t numRegions);

    void copyBuffer(const Buffer& srcBuffer, const Buffer& dstBuffer, uint32_t numRegions, const BufferCopy* regions);

    void copyBufferToImage(const Buffer& buffer, const Image& image, ImageLayout dstImageLayout, uint32_t regionsCount, const BufferImageCopy* regions);

    void fillBuffer(const Buffer& dstBuffer, uint32_t dstOffset, uint32_t data, uint64_t size = VK_WHOLE_SIZE);

    void setViewport(const Viewport& viewport);

    void clearAttachments(const uint32_t numAttachments, const ClearAttachment* clearAttachments, uint32_t numRectangles, const ClearRect* clearRectangles);

    void clearAttachment(const ClearAttachment& clearAttachment, const ClearRect& clearRectangle) { clearAttachments(1, &clearAttachment, 1, &clearRectangle); }

    void draw(uint32_t firstVertex, uint32_t numVertices, uint32_t firstInstance = 0, uint32_t numInstances = 1);

    void drawIndexed(uint32_t firstIndex, uint32_t numIndices, int32_t vertexOffset = 0, uint32_t firstInstance = 0, uint32_t numInstances = 1);

    void drawIndirect(const Buffer& buffer, uint32_t offset, uint32_t count, uint32_t stride);

    void drawIndexedIndirect(const Buffer& buffer, uint32_t offset, uint32_t count, uint32_t stride);

    void dispatch(uint32_t numGroupX, uint32_t numGroupY, uint32_t numGroupZ);

    void dispatchIndirect(Buffer& buffer, uint32_t offset);

    void clearColorImage(const ImageView& image, const ClearColorValue& clearColor, ImageLayout currentLayout, const uint32_t baseMipLevel = 0, const uint32_t numLevels = 1,
        const uint32_t baseArrayLayer = 0, const uint32_t numLayers = 1);

    void clearColorImage(const ImageView& image, const ClearColorValue& clearColor, ImageLayout currentLayout, const uint32_t* baseMipLevels, const uint32_t* numLevels,
        const uint32_t* baseArrayLayers, const uint32_t* numLayers, uint32_t numRanges);

    void clearDepthStencilImage(const Image& image, float clearDepth, uint32_t clearStencil, const uint32_t baseMipLevel, const uint32_t numLevels, const uint32_t baseArrayLayer,
        const uint32_t numLayers, ImageLayout layout);

    void clearDepthStencilImage(const Image& image, float clearDepth, uint32_t clearStencil, const uint32_t* baseMipLevels, const uint32_t* numLevels,
        const uint32_t* baseArrayLayers, const uint32_t* numLayers, uint32_t numRanges, ImageLayout layout);

    void clearStencilImage(const Image& image, uint32_t clearStencil, const uint32_t baseMipLevel, const uint32_t numLevels, const uint32_t baseArrayLayer,
        const uint32_t numLayers, ImageLayout layout);

    void clearStencilImage(const Image& image, uint32_t clearStencil, const uint32_t* baseMipLevels, const uint32_t* numLevels, const uint32_t* baseArrayLayers,
        const uint32_t* numLayers, uint32_t numRanges, ImageLayout layout);

    void clearDepthImage(
        const Image& image, float clearDepth, const uint32_t baseMipLevel, const uint32_t numLevels, const uint32_t baseArrayLayer, const uint32_t numLayers, ImageLayout layout);

    void clearDepthImage(const Image& image, float clearDepth, const uint32_t* baseMipLevels, const uint32_t* numLevels, const uint32_t* baseArrayLayers, const uint32_t* numLayers,
        uint32_t numRanges, ImageLayout layout);

    void setScissor(uint32_t firstScissor, uint32_t numScissors, const Rect2D* scissors);

    void setDepthBounds(float min, float max);

    void setStencilWriteMask(StencilFaceFlags face, uint32_t writeMask);

    void setStencilReference(StencilFaceFlags face, uint32_t reference);

    void setStencilCompareMask(StencilFaceFlags face, uint32_t compareMask);

    void setDepthBias(float constantFactor, float clamp, float slopeFactor);

    void setBlendConstants(float rgba[4]);

    void setLineWidth(float lineWidth);

    void blitImage(const Image& srcImage, const Image& dstImage, const ImageBlit* regions, uint32_t numRegions, Filter filter, ImageLayout srcLayout, ImageLayout dstLayout);

    void resolveImage(const Image& srcImage, const Image& dstImage, const ImageResolve* regions, uint32_t numRegions, ImageLayout srcLayout, ImageLayout dstLayout);

    void updateBuffer(const Buffer& buffer, const void* data, uint32_t offset, uint32_t length);

    void pushConstants(const PipelineLayout& pipelineLayout, ShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* data);

    void bindTransformFeedbackBuffers(pvrvk::Buffer buffer, VkDeviceSize offset, VkDeviceSize size = VK_WHOLE_SIZE);

    void bindTransformFeedbackBuffers(uint32_t firstBinding, uint32_t bindingCount, const pvrvk::Buffer* buffers, const VkDeviceSize* offsets, const VkDeviceSize* sizes = nullptr);

    void beginTransformFeedback(
        uint32_t firstCounterBuffer, uint32_t numCounterBuffers, const pvrvk::Buffer* counterBuffers = nullptr, const VkDeviceSize* counterBufferOffsets = nullptr);

    void beginTransformFeedback(pvrvk::Buffer counterBuffer, VkDeviceSize counterBufferOffset = 0);

    void endTransformFeedback(uint32_t firstCounterBuffer, uint32_t numCounterBuffers, const pvrvk::Buffer* counterBuffers = nullptr, const VkDeviceSize* counterBufferOffsets = nullptr);

    void endTransformFeedback(pvrvk::Buffer counterBuffer, VkDeviceSize counterBufferOffset = 0);

    void beginQueryIndexed(QueryPool& queryPool, uint32_t queryIndex, QueryControlFlags flags = QueryControlFlags(0), uint32_t index = 0);

    void endQueryIndexed(QueryPool& queryPool, uint32_t queryIndex, uint32_t index = 0);

    void drawIndirectByteCount(
        uint32_t instanceCount, uint32_t firstInstance, pvrvk::Buffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride);

    const CommandPool getCommandPool() const { return _pool; }

    void setFragmentShadingRate(Extent2D fragmentSize, FragmentShadingRateCombinerOpKHR combinerOpPipelinePrimitive, FragmentShadingRateCombinerOpKHR combinerOpResultAttachment);

    void traceRays(pvrvk::StridedDeviceAddressRegionKHR& raygenTable, pvrvk::StridedDeviceAddressRegionKHR& missTable, pvrvk::StridedDeviceAddressRegionKHR& hitTable,
        pvrvk::StridedDeviceAddressRegionKHR& callableTable, int width, int height, int depth)
    {
        VkStridedDeviceAddressRegionKHR raygen = VkStridedDeviceAddressRegionKHR{ raygenTable.getDeviceAddress(), raygenTable.getStride(), raygenTable.getSize() };
        VkStridedDeviceAddressRegionKHR miss = VkStridedDeviceAddressRegionKHR{ missTable.getDeviceAddress(), missTable.getStride(), missTable.getSize() };
        VkStridedDeviceAddressRegionKHR hit = VkStridedDeviceAddressRegionKHR{ hitTable.getDeviceAddress(), hitTable.getStride(), hitTable.getSize() };
        VkStridedDeviceAddressRegionKHR callable = VkStridedDeviceAddressRegionKHR{ callableTable.getDeviceAddress(), callableTable.getStride(), callableTable.getSize() };
        getDevice()->getVkBindings().vkCmdTraceRaysKHR(getVkHandle(), &raygen, &miss, &hit, &callable, width, height, depth);
    }

    void setVKSynchronization2IsSupported(bool value)
    {
        _VKSynchronization2IsSupported = value;
    }
};

class CommandBuffer_ : public CommandBufferBase_
{
protected:
    friend class CommandPool_;

    class make_shared_enabler : public CommandBufferBase_::make_shared_enabler
    {
    protected:
        make_shared_enabler() : CommandBufferBase_::make_shared_enabler() {}
        friend CommandBuffer_;
    };

    static CommandBuffer constructShared(const DeviceWeakPtr& device, CommandPool pool, VkCommandBuffer myHandle)
    {
        return std::make_shared<CommandBuffer_>(make_shared_enabler{}, device, pool, myHandle);
    }

#ifdef DEBUG
    pvrvk::Framebuffer _currentlyBoundFramebuffer;
    uint32_t _currentSubpass;
#endif

public:
    DECLARE_NO_COPY_SEMANTICS(CommandBuffer_)

    CommandBuffer_(make_shared_enabler, const DeviceWeakPtr& device, CommandPool pool, VkCommandBuffer myHandle)
        : CommandBufferBase_(make_shared_enabler{}, device, pool, myHandle)
#ifdef DEBUG
          ,
          _currentSubpass(static_cast<uint32_t>(-1))
#endif
    {}

    virtual ~CommandBuffer_()
    {
#ifdef DEBUG
        _currentlyBoundFramebuffer.reset();
#endif
    }

    void executeCommands(const SecondaryCommandBuffer& secondaryCmdBuffer);

    void executeCommands(const SecondaryCommandBuffer* secondaryCmdBuffers, uint32_t numCommandBuffers);

    void beginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, const Rect2D& renderArea, bool inlineFirstSubpass = false,
        const ClearValue* clearValues = nullptr, uint32_t numClearValues = 0);

    void beginRenderPass(const Framebuffer& framebuffer, const Rect2D& renderArea, bool inlineFirstSubpass = false, const ClearValue* clearValues = nullptr, uint32_t numClearValues = 0);

    void beginRenderPass(const Framebuffer& framebuffer, bool inlineFirstSubpass = false, const ClearValue* clearValues = nullptr, uint32_t numClearValues = 0);

    void endRenderPass()
    {
        getDevice()->getVkBindings().vkCmdEndRenderPass(getVkHandle());

#ifdef DEBUG
        auto& currentRenderPass = _currentlyBoundFramebuffer->getCreateInfo().getRenderPass();
        assert(currentRenderPass->getCreateInfo().getNumAttachmentDescription() == _currentlyBoundFramebuffer->getNumAttachments());

        for (uint32_t i = 0; i < _currentlyBoundFramebuffer->getNumAttachments(); ++i)
        { _currentlyBoundFramebuffer->getAttachment(i)->getImage()->setImageLayout(currentRenderPass->getCreateInfo().getAttachmentDescription(i).getFinalLayout()); }

        _currentlyBoundFramebuffer.reset();
        _currentSubpass = static_cast<uint32_t>(-1);
#endif
    }

#ifdef DEBUG
    void updatePerSubpassImageLayouts()
    {
        auto& currentRenderPass = _currentlyBoundFramebuffer->getCreateInfo().getRenderPass();

        for (uint8_t i = 0; i < currentRenderPass->getCreateInfo().getSubpass(_currentSubpass).getNumInputAttachmentReference(); ++i)
        {
            const AttachmentReference& attachmentReference = currentRenderPass->getCreateInfo().getSubpass(_currentSubpass).getInputAttachmentReference(i);
            _currentlyBoundFramebuffer->getCreateInfo().getAttachment(attachmentReference.getAttachment())->getImage()->setImageLayout(attachmentReference.getLayout());
        }

        for (uint8_t i = 0; i < currentRenderPass->getCreateInfo().getSubpass(_currentSubpass).getNumColorAttachmentReference(); ++i)
        {
            const AttachmentReference& attachmentReference = currentRenderPass->getCreateInfo().getSubpass(_currentSubpass).getColorAttachmentReference(i);
            _currentlyBoundFramebuffer->getCreateInfo().getAttachment(attachmentReference.getAttachment())->getImage()->setImageLayout(attachmentReference.getLayout());
        }

        for (uint8_t i = 0; i < currentRenderPass->getCreateInfo().getSubpass(_currentSubpass).getNumResolveAttachmentReference(); ++i)
        {
            const AttachmentReference& attachmentReference = currentRenderPass->getCreateInfo().getSubpass(_currentSubpass).getResolveAttachmentReference(i);
            _currentlyBoundFramebuffer->getCreateInfo().getAttachment(attachmentReference.getAttachment())->getImage()->setImageLayout(attachmentReference.getLayout());
        }
    }
#endif

    void nextSubpass(SubpassContents contents)
    {
        getDevice()->getVkBindings().vkCmdNextSubpass(getVkHandle(), static_cast<VkSubpassContents>(contents));

#ifdef DEBUG
        _currentSubpass++;
        updatePerSubpassImageLayouts();
#endif
    }
};

class SecondaryCommandBuffer_ : public CommandBufferBase_
{
protected:
    friend class CommandPool_;

    class make_shared_enabler : public CommandBufferBase_::make_shared_enabler
    {
    protected:
        make_shared_enabler() : CommandBufferBase_::make_shared_enabler() {}
        friend SecondaryCommandBuffer_;
    };

    static SecondaryCommandBuffer constructShared(const DeviceWeakPtr& device, CommandPool pool, VkCommandBuffer myHandle)
    {
        return std::make_shared<SecondaryCommandBuffer_>(make_shared_enabler{}, device, pool, myHandle);
    }

public:
    DECLARE_NO_COPY_SEMANTICS(SecondaryCommandBuffer_)


    SecondaryCommandBuffer_(make_shared_enabler, const DeviceWeakPtr& device, CommandPool pool, VkCommandBuffer myHandle)
        : CommandBufferBase_(make_shared_enabler{}, device, pool, myHandle)
    {}

    using CommandBufferBase_::begin;

    void begin(const RenderPass& renderpass, uint32_t subpass = 0, const CommandBufferUsageFlags flags = CommandBufferUsageFlags::e_RENDER_PASS_CONTINUE_BIT);

    void begin(const Framebuffer& framebuffer, uint32_t subpass = 0, const CommandBufferUsageFlags flags = CommandBufferUsageFlags::e_RENDER_PASS_CONTINUE_BIT);
};
} // namespace impl
} // namespace pvrvk