blob: 83004bd76ad6d844831ba982adc5e58ba95858bd [file] [log] [blame]
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrVkCommandBuffer_DEFINED
#define GrVkCommandBuffer_DEFINED
#include "include/gpu/vk/GrVkTypes.h"
#include "src/gpu/ganesh/GrManagedResource.h"
#include "src/gpu/ganesh/GrRefCnt.h"
#include "src/gpu/ganesh/vk/GrVkGpu.h"
#include "src/gpu/ganesh/vk/GrVkSemaphore.h"
#include "src/gpu/ganesh/vk/GrVkUtil.h"
class GrVkFramebuffer;
class GrVkImage;
class GrVkPipeline;
class GrVkPipelineState;
class GrVkRenderPass;
class GrVkRenderTarget;
class GrVkCommandBuffer {
public:
virtual ~GrVkCommandBuffer() {}
void invalidateState();
////////////////////////////////////////////////////////////////////////////
// CommandBuffer commands
////////////////////////////////////////////////////////////////////////////
enum BarrierType {
kBufferMemory_BarrierType,
kImageMemory_BarrierType
};
void pipelineBarrier(const GrVkGpu* gpu,
const GrManagedResource* resource,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
bool byRegion,
BarrierType barrierType,
void* barrier);
void bindInputBuffer(GrVkGpu* gpu, uint32_t binding, sk_sp<const GrBuffer> buffer);
void bindIndexBuffer(GrVkGpu* gpu, sk_sp<const GrBuffer> buffer);
void bindPipeline(const GrVkGpu* gpu, sk_sp<const GrVkPipeline> pipeline);
void bindDescriptorSets(const GrVkGpu* gpu,
VkPipelineLayout layout,
uint32_t firstSet,
uint32_t setCount,
const VkDescriptorSet* descriptorSets,
uint32_t dynamicOffsetCount,
const uint32_t* dynamicOffsets);
void pushConstants(const GrVkGpu* gpu, VkPipelineLayout layout,
VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size,
const void* values);
void setViewport(const GrVkGpu* gpu,
uint32_t firstViewport,
uint32_t viewportCount,
const VkViewport* viewports);
void setScissor(const GrVkGpu* gpu,
uint32_t firstScissor,
uint32_t scissorCount,
const VkRect2D* scissors);
void setBlendConstants(const GrVkGpu* gpu, const float blendConstants[4]);
// Commands that only work inside of a render pass
void clearAttachments(const GrVkGpu* gpu,
int numAttachments,
const VkClearAttachment* attachments,
int numRects,
const VkClearRect* clearRects);
void drawIndexed(const GrVkGpu* gpu,
uint32_t indexCount,
uint32_t instanceCount,
uint32_t firstIndex,
int32_t vertexOffset,
uint32_t firstInstance);
void draw(const GrVkGpu* gpu,
uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,
uint32_t firstInstance);
void drawIndirect(const GrVkGpu* gpu,
sk_sp<const GrBuffer> indirectBuffer,
VkDeviceSize offset,
uint32_t drawCount,
uint32_t stride);
void drawIndexedIndirect(const GrVkGpu* gpu,
sk_sp<const GrBuffer> indirectBuffer,
VkDeviceSize offset,
uint32_t drawCount,
uint32_t stride);
// Add ref-counted resource that will be tracked and released when this command buffer finishes
// execution
void addResource(sk_sp<const GrManagedResource> resource) {
SkASSERT(resource);
fTrackedResources.push_back(std::move(resource));
}
void addResource(const GrManagedResource* resource) {
this->addResource(sk_ref_sp(resource));
}
// Add ref-counted resource that will be tracked and released when this command buffer finishes
// execution. When it is released, it will signal that the resource can be recycled for reuse.
void addRecycledResource(gr_rp<const GrRecycledResource> resource) {
SkASSERT(resource);
fTrackedRecycledResources.push_back(std::move(resource));
}
void addRecycledResource(const GrRecycledResource* resource) {
this->addRecycledResource(gr_ref_rp<const GrRecycledResource>(resource));
}
void addGrBuffer(sk_sp<const GrBuffer> buffer) {
fTrackedGpuBuffers.push_back(std::move(buffer));
}
void addGrSurface(sk_sp<const GrSurface> surface) {
fTrackedGpuSurfaces.push_back(std::move(surface));
}
void releaseResources();
void freeGPUData(const GrGpu* gpu, VkCommandPool pool) const;
bool hasWork() const { return fHasWork; }
protected:
GrVkCommandBuffer(VkCommandBuffer cmdBuffer, bool isWrapped = false)
: fIsActive(isWrapped) // All wrapped command buffers start as active
, fCmdBuffer(cmdBuffer)
, fIsWrapped(isWrapped) {
this->invalidateState();
}
bool isWrapped() const { return fIsWrapped; }
void addingWork(const GrVkGpu* gpu);
void submitPipelineBarriers(const GrVkGpu* gpu, bool forSelfDependency = false);
private:
static constexpr int kInitialTrackedResourcesCount = 32;
protected:
template <typename T> using TrackedResourceArray = SkSTArray<kInitialTrackedResourcesCount, T>;
TrackedResourceArray<sk_sp<const GrManagedResource>> fTrackedResources;
TrackedResourceArray<gr_rp<const GrRecycledResource>> fTrackedRecycledResources;
SkSTArray<16, sk_sp<const GrBuffer>> fTrackedGpuBuffers;
SkSTArray<16, gr_cb<const GrSurface>> fTrackedGpuSurfaces;
// Tracks whether we are in the middle of a command buffer begin/end calls and thus can add
// new commands to the buffer;
bool fIsActive;
bool fHasWork = false;
// Stores a pointer to the current active render pass (i.e. begin has been called but not
// end). A nullptr means there is no active render pass. The GrVKCommandBuffer does not own
// the render pass.
const GrVkRenderPass* fActiveRenderPass = nullptr;
VkCommandBuffer fCmdBuffer;
virtual void onReleaseResources() {}
virtual void onFreeGPUData(const GrVkGpu* gpu) const = 0;
static constexpr uint32_t kMaxInputBuffers = 2;
VkBuffer fBoundInputBuffers[kMaxInputBuffers];
VkBuffer fBoundIndexBuffer;
// Cached values used for dynamic state updates
VkViewport fCachedViewport;
VkRect2D fCachedScissor;
float fCachedBlendConstant[4];
// Tracking of memory barriers so that we can submit them all in a batch together.
SkSTArray<1, VkBufferMemoryBarrier> fBufferBarriers;
SkSTArray<2, VkImageMemoryBarrier> fImageBarriers;
bool fBarriersByRegion = false;
VkPipelineStageFlags fSrcStageMask = 0;
VkPipelineStageFlags fDstStageMask = 0;
bool fIsWrapped;
};
class GrVkSecondaryCommandBuffer;
class GrVkPrimaryCommandBuffer : public GrVkCommandBuffer {
public:
~GrVkPrimaryCommandBuffer() override;
static GrVkPrimaryCommandBuffer* Create(GrVkGpu* gpu, VkCommandPool cmdPool);
void begin(GrVkGpu* gpu);
void end(GrVkGpu* gpu, bool abandoningBuffer = false);
// Begins render pass on this command buffer. The framebuffer from GrVkRenderTarget will be used
// in the render pass.
bool beginRenderPass(GrVkGpu* gpu,
const GrVkRenderPass*,
sk_sp<const GrVkFramebuffer>,
const VkClearValue clearValues[],
const GrSurface* target,
const SkIRect& bounds,
bool forSecondaryCB);
void endRenderPass(const GrVkGpu* gpu);
void nexSubpass(GrVkGpu* gpu, bool forSecondaryCB);
// Submits the SecondaryCommandBuffer into this command buffer. It is required that we are
// currently inside a render pass that is compatible with the one used to create the
// SecondaryCommandBuffer.
void executeCommands(const GrVkGpu* gpu,
std::unique_ptr<GrVkSecondaryCommandBuffer> secondaryBuffer);
// Commands that only work outside of a render pass
void clearColorImage(const GrVkGpu* gpu,
GrVkImage* image,
const VkClearColorValue* color,
uint32_t subRangeCount,
const VkImageSubresourceRange* subRanges);
void clearDepthStencilImage(const GrVkGpu* gpu,
GrVkImage* image,
const VkClearDepthStencilValue* color,
uint32_t subRangeCount,
const VkImageSubresourceRange* subRanges);
void copyImage(const GrVkGpu* gpu,
GrVkImage* srcImage,
VkImageLayout srcLayout,
GrVkImage* dstImage,
VkImageLayout dstLayout,
uint32_t copyRegionCount,
const VkImageCopy* copyRegions);
void blitImage(const GrVkGpu* gpu,
const GrManagedResource* srcResource,
VkImage srcImage,
VkImageLayout srcLayout,
const GrManagedResource* dstResource,
VkImage dstImage,
VkImageLayout dstLayout,
uint32_t blitRegionCount,
const VkImageBlit* blitRegions,
VkFilter filter);
void blitImage(const GrVkGpu* gpu,
const GrVkImage& srcImage,
const GrVkImage& dstImage,
uint32_t blitRegionCount,
const VkImageBlit* blitRegions,
VkFilter filter);
void copyImageToBuffer(const GrVkGpu* gpu,
GrVkImage* srcImage,
VkImageLayout srcLayout,
sk_sp<GrGpuBuffer> dstBuffer,
uint32_t copyRegionCount,
const VkBufferImageCopy* copyRegions);
// All uses of copyBufferToImage are done with buffers from our staging manager. The staging
// manager will handle making sure the command buffer refs the buffer. Thus we just pass in the
// raw VkBuffer here and don't worry about refs.
void copyBufferToImage(const GrVkGpu* gpu,
VkBuffer srcBuffer,
GrVkImage* dstImage,
VkImageLayout dstLayout,
uint32_t copyRegionCount,
const VkBufferImageCopy* copyRegions);
void fillBuffer(GrVkGpu* gpu,
sk_sp<GrGpuBuffer>,
VkDeviceSize offset,
VkDeviceSize size,
uint32_t data);
void copyBuffer(GrVkGpu* gpu,
sk_sp<GrGpuBuffer> srcBuffer,
sk_sp<GrGpuBuffer> dstBuffer,
uint32_t regionCount,
const VkBufferCopy* regions);
void updateBuffer(GrVkGpu* gpu,
sk_sp<GrVkBuffer> dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
const void* data);
void resolveImage(GrVkGpu* gpu,
const GrVkImage& srcImage,
const GrVkImage& dstImage,
uint32_t regionCount,
const VkImageResolve* regions);
bool submitToQueue(GrVkGpu* gpu, VkQueue queue,
SkTArray<GrVkSemaphore::Resource*>& signalSemaphores,
SkTArray<GrVkSemaphore::Resource*>& waitSemaphores);
void forceSync(GrVkGpu* gpu);
bool finished(GrVkGpu* gpu);
void addFinishedProc(sk_sp<skgpu::RefCntedCallback> finishedProc);
void callFinishedProcs() {
fFinishedProcs.clear();
}
void recycleSecondaryCommandBuffers(GrVkCommandPool* cmdPool);
private:
explicit GrVkPrimaryCommandBuffer(VkCommandBuffer cmdBuffer)
: INHERITED(cmdBuffer)
, fSubmitFence(VK_NULL_HANDLE) {}
void onFreeGPUData(const GrVkGpu* gpu) const override;
void onReleaseResources() override;
SkTArray<std::unique_ptr<GrVkSecondaryCommandBuffer>, true> fSecondaryCommandBuffers;
VkFence fSubmitFence;
SkTArray<sk_sp<skgpu::RefCntedCallback>> fFinishedProcs;
using INHERITED = GrVkCommandBuffer;
};
class GrVkSecondaryCommandBuffer : public GrVkCommandBuffer {
public:
static GrVkSecondaryCommandBuffer* Create(GrVkGpu* gpu, GrVkCommandPool* cmdPool);
// Used for wrapping an external secondary command buffer.
static GrVkSecondaryCommandBuffer* Create(VkCommandBuffer externalSecondaryCB,
const GrVkRenderPass* externalRenderPass);
void begin(GrVkGpu* gpu, const GrVkFramebuffer* framebuffer,
const GrVkRenderPass* compatibleRenderPass);
void end(GrVkGpu* gpu);
void recycle(GrVkCommandPool* cmdPool);
VkCommandBuffer vkCommandBuffer() { return fCmdBuffer; }
private:
explicit GrVkSecondaryCommandBuffer(VkCommandBuffer cmdBuffer,
const GrVkRenderPass* externalRenderPass)
: INHERITED(cmdBuffer, SkToBool(externalRenderPass)) {
fActiveRenderPass = externalRenderPass;
}
void onFreeGPUData(const GrVkGpu* gpu) const override {}
// Used for accessing fIsActive (on GrVkCommandBuffer)
friend class GrVkPrimaryCommandBuffer;
using INHERITED = GrVkCommandBuffer;
};
#endif