| /* |
| * Copyright 2015 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "GrVkCommandBuffer.h" |
| |
| #include "GrVkFramebuffer.h" |
| #include "GrVkImageView.h" |
| #include "GrVkRenderPass.h" |
| #include "GrVkRenderTarget.h" |
| #include "GrVkProgram.h" |
| #include "GrVkTransferBuffer.h" |
| #include "GrVkUtil.h" |
| |
| GrVkCommandBuffer* GrVkCommandBuffer::Create(const GrVkGpu* gpu, VkCommandPool cmdPool) { |
| const VkCommandBufferAllocateInfo cmdInfo = { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType |
| NULL, // pNext |
| cmdPool, // commandPool |
| VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level |
| 1 // bufferCount |
| }; |
| |
| VkCommandBuffer cmdBuffer; |
| VkResult err = GR_VK_CALL(gpu->vkInterface(), AllocateCommandBuffers(gpu->device(), |
| &cmdInfo, |
| &cmdBuffer)); |
| if (err) { |
| return nullptr; |
| } |
| return new GrVkCommandBuffer(cmdBuffer); |
| } |
| |
| GrVkCommandBuffer::~GrVkCommandBuffer() { |
| // Should have ended any render pass we're in the middle of |
| SkASSERT(!fActiveRenderPass); |
| } |
| |
| void GrVkCommandBuffer::invalidateState() { |
| fBoundVertexBuffer = 0; |
| fBoundVertexBufferIsValid = false; |
| fBoundIndexBuffer = 0; |
| fBoundIndexBufferIsValid = false; |
| } |
| |
| void GrVkCommandBuffer::freeGPUData(const GrVkGpu* gpu) const { |
| SkASSERT(!fIsActive); |
| SkASSERT(!fActiveRenderPass); |
| for (int i = 0; i < fTrackedResources.count(); ++i) { |
| fTrackedResources[i]->unref(gpu); |
| } |
| |
| // Destroy the fence, if any |
| if (VK_NULL_HANDLE != fSubmitFence) { |
| GR_VK_CALL(gpu->vkInterface(), DestroyFence(gpu->device(), fSubmitFence, nullptr)); |
| } |
| |
| GR_VK_CALL(gpu->vkInterface(), FreeCommandBuffers(gpu->device(), gpu->cmdPool(), |
| 1, &fCmdBuffer)); |
| } |
| |
| void GrVkCommandBuffer::abandonSubResources() const { |
| for (int i = 0; i < fTrackedResources.count(); ++i) { |
| fTrackedResources[i]->unrefAndAbandon(); |
| } |
| } |
| |
| void GrVkCommandBuffer::begin(const GrVkGpu* gpu) { |
| SkASSERT(!fIsActive); |
| VkCommandBufferBeginInfo cmdBufferBeginInfo; |
| memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo)); |
| cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
| cmdBufferBeginInfo.pNext = nullptr; |
| cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
| cmdBufferBeginInfo.pInheritanceInfo = nullptr; |
| |
| GR_VK_CALL_ERRCHECK(gpu->vkInterface(), BeginCommandBuffer(fCmdBuffer, |
| &cmdBufferBeginInfo)); |
| fIsActive = true; |
| } |
| |
| void GrVkCommandBuffer::end(const GrVkGpu* gpu) { |
| SkASSERT(fIsActive); |
| SkASSERT(!fActiveRenderPass); |
| GR_VK_CALL_ERRCHECK(gpu->vkInterface(), EndCommandBuffer(fCmdBuffer)); |
| this->invalidateState(); |
| fIsActive = false; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| void GrVkCommandBuffer::beginRenderPass(const GrVkGpu* gpu, |
| const GrVkRenderPass* renderPass, |
| const GrVkRenderTarget& target) { |
| SkASSERT(fIsActive); |
| SkASSERT(!fActiveRenderPass); |
| VkRenderPassBeginInfo beginInfo; |
| VkSubpassContents contents; |
| renderPass->getBeginInfo(target, &beginInfo, &contents); |
| GR_VK_CALL(gpu->vkInterface(), CmdBeginRenderPass(fCmdBuffer, &beginInfo, contents)); |
| fActiveRenderPass = renderPass; |
| this->addResource(renderPass); |
| target.addResources(*this); |
| } |
| |
| void GrVkCommandBuffer::endRenderPass(const GrVkGpu* gpu) { |
| SkASSERT(fIsActive); |
| SkASSERT(fActiveRenderPass); |
| GR_VK_CALL(gpu->vkInterface(), CmdEndRenderPass(fCmdBuffer)); |
| fActiveRenderPass = nullptr; |
| } |
| |
| void GrVkCommandBuffer::submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync) { |
| SkASSERT(!fIsActive); |
| |
| VkResult err; |
| VkFenceCreateInfo fenceInfo; |
| memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo)); |
| fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; |
| err = GR_VK_CALL(gpu->vkInterface(), CreateFence(gpu->device(), &fenceInfo, nullptr, |
| &fSubmitFence)); |
| SkASSERT(!err); |
| |
| VkSubmitInfo submitInfo; |
| memset(&submitInfo, 0, sizeof(VkSubmitInfo)); |
| submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submitInfo.pNext = nullptr; |
| submitInfo.waitSemaphoreCount = 0; |
| submitInfo.pWaitSemaphores = nullptr; |
| submitInfo.commandBufferCount = 1; |
| submitInfo.pCommandBuffers = &fCmdBuffer; |
| submitInfo.signalSemaphoreCount = 0; |
| submitInfo.pSignalSemaphores = nullptr; |
| GR_VK_CALL_ERRCHECK(gpu->vkInterface(), QueueSubmit(queue, 1, &submitInfo, fSubmitFence)); |
| |
| if (GrVkGpu::kForce_SyncQueue == sync) { |
| err = GR_VK_CALL(gpu->vkInterface(), |
| WaitForFences(gpu->device(), 1, &fSubmitFence, true, UINT64_MAX)); |
| if (VK_TIMEOUT == err) { |
| SkDebugf("Fence failed to signal: %d\n", err); |
| SkFAIL("failing"); |
| } |
| SkASSERT(!err); |
| |
| // Destroy the fence |
| GR_VK_CALL(gpu->vkInterface(), DestroyFence(gpu->device(), fSubmitFence, nullptr)); |
| fSubmitFence = VK_NULL_HANDLE; |
| } |
| } |
| |
| bool GrVkCommandBuffer::finished(const GrVkGpu* gpu) const { |
| if (VK_NULL_HANDLE == fSubmitFence) { |
| return true; |
| } |
| |
| VkResult err = GR_VK_CALL(gpu->vkInterface(), GetFenceStatus(gpu->device(), fSubmitFence)); |
| switch (err) { |
| case VK_SUCCESS: |
| return true; |
| |
| case VK_NOT_READY: |
| return false; |
| |
| default: |
| SkDebugf("Error getting fence status: %d\n", err); |
| SkFAIL("failing"); |
| break; |
| } |
| |
| return false; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // CommandBuffer commands |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| void GrVkCommandBuffer::pipelineBarrier(const GrVkGpu* gpu, |
| VkPipelineStageFlags srcStageMask, |
| VkPipelineStageFlags dstStageMask, |
| bool byRegion, |
| BarrierType barrierType, |
| void* barrier) const { |
| SkASSERT(fIsActive); |
| VkDependencyFlags dependencyFlags = byRegion ? VK_DEPENDENCY_BY_REGION_BIT : 0; |
| |
| switch (barrierType) { |
| case kMemory_BarrierType: { |
| const VkMemoryBarrier* barrierPtr = reinterpret_cast<VkMemoryBarrier*>(barrier); |
| GR_VK_CALL(gpu->vkInterface(), CmdPipelineBarrier(fCmdBuffer, srcStageMask, |
| dstStageMask, dependencyFlags, |
| 1, barrierPtr, |
| 0, nullptr, |
| 0, nullptr)); |
| break; |
| } |
| |
| case kBufferMemory_BarrierType: { |
| const VkBufferMemoryBarrier* barrierPtr = |
| reinterpret_cast<VkBufferMemoryBarrier*>(barrier); |
| GR_VK_CALL(gpu->vkInterface(), CmdPipelineBarrier(fCmdBuffer, srcStageMask, |
| dstStageMask, dependencyFlags, |
| 0, nullptr, |
| 1, barrierPtr, |
| 0, nullptr)); |
| break; |
| } |
| |
| case kImageMemory_BarrierType: { |
| const VkImageMemoryBarrier* barrierPtr = |
| reinterpret_cast<VkImageMemoryBarrier*>(barrier); |
| GR_VK_CALL(gpu->vkInterface(), CmdPipelineBarrier(fCmdBuffer, srcStageMask, |
| dstStageMask, dependencyFlags, |
| 0, nullptr, |
| 0, nullptr, |
| 1, barrierPtr)); |
| break; |
| } |
| } |
| |
| } |
| |
| void GrVkCommandBuffer::copyImage(const GrVkGpu* gpu, |
| GrVkImage* srcImage, |
| VkImageLayout srcLayout, |
| GrVkImage* dstImage, |
| VkImageLayout dstLayout, |
| uint32_t copyRegionCount, |
| const VkImageCopy* copyRegions) { |
| SkASSERT(fIsActive); |
| SkASSERT(!fActiveRenderPass); |
| this->addResource(srcImage->resource()); |
| this->addResource(dstImage->resource()); |
| GR_VK_CALL(gpu->vkInterface(), CmdCopyImage(fCmdBuffer, |
| srcImage->textureImage(), |
| srcLayout, |
| dstImage->textureImage(), |
| dstLayout, |
| copyRegionCount, |
| copyRegions)); |
| } |
| |
| void GrVkCommandBuffer::copyImageToBuffer(const GrVkGpu* gpu, |
| GrVkImage* srcImage, |
| VkImageLayout srcLayout, |
| GrVkTransferBuffer* dstBuffer, |
| uint32_t copyRegionCount, |
| const VkBufferImageCopy* copyRegions) { |
| SkASSERT(fIsActive); |
| SkASSERT(!fActiveRenderPass); |
| this->addResource(srcImage->resource()); |
| this->addResource(dstBuffer->resource()); |
| GR_VK_CALL(gpu->vkInterface(), CmdCopyImageToBuffer(fCmdBuffer, |
| srcImage->textureImage(), |
| srcLayout, |
| dstBuffer->buffer(), |
| copyRegionCount, |
| copyRegions)); |
| } |
| |
| void GrVkCommandBuffer::copyBufferToImage(const GrVkGpu* gpu, |
| GrVkTransferBuffer* srcBuffer, |
| GrVkImage* dstImage, |
| VkImageLayout dstLayout, |
| uint32_t copyRegionCount, |
| const VkBufferImageCopy* copyRegions) { |
| SkASSERT(fIsActive); |
| SkASSERT(!fActiveRenderPass); |
| this->addResource(srcBuffer->resource()); |
| this->addResource(dstImage->resource()); |
| GR_VK_CALL(gpu->vkInterface(), CmdCopyBufferToImage(fCmdBuffer, |
| srcBuffer->buffer(), |
| dstImage->textureImage(), |
| dstLayout, |
| copyRegionCount, |
| copyRegions)); |
| } |
| |
| void GrVkCommandBuffer::clearColorImage(const GrVkGpu* gpu, |
| GrVkImage* image, |
| const VkClearColorValue* color, |
| uint32_t subRangeCount, |
| const VkImageSubresourceRange* subRanges) { |
| SkASSERT(fIsActive); |
| SkASSERT(!fActiveRenderPass); |
| this->addResource(image->resource()); |
| GR_VK_CALL(gpu->vkInterface(), CmdClearColorImage(fCmdBuffer, |
| image->textureImage(), |
| image->currentLayout(), |
| color, |
| subRangeCount, |
| subRanges)); |
| } |
| |
| void GrVkCommandBuffer::clearDepthStencilImage(const GrVkGpu* gpu, |
| GrVkImage* image, |
| const VkClearDepthStencilValue* color, |
| uint32_t subRangeCount, |
| const VkImageSubresourceRange* subRanges) { |
| SkASSERT(fIsActive); |
| SkASSERT(!fActiveRenderPass); |
| this->addResource(image->resource()); |
| GR_VK_CALL(gpu->vkInterface(), CmdClearDepthStencilImage(fCmdBuffer, |
| image->textureImage(), |
| image->currentLayout(), |
| color, |
| subRangeCount, |
| subRanges)); |
| } |
| |
| void GrVkCommandBuffer::clearAttachments(const GrVkGpu* gpu, |
| int numAttachments, |
| const VkClearAttachment* attachments, |
| int numRects, |
| const VkClearRect* clearRects) const { |
| SkASSERT(fIsActive); |
| SkASSERT(fActiveRenderPass); |
| SkASSERT(numAttachments > 0); |
| SkASSERT(numRects > 0); |
| #ifdef SK_DEBUG |
| for (int i = 0; i < numAttachments; ++i) { |
| if (attachments[i].aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) { |
| uint32_t testIndex; |
| SkAssertResult(fActiveRenderPass->colorAttachmentIndex(&testIndex)); |
| SkASSERT(testIndex == attachments[i].colorAttachment); |
| } |
| } |
| #endif |
| GR_VK_CALL(gpu->vkInterface(), CmdClearAttachments(fCmdBuffer, |
| numAttachments, |
| attachments, |
| numRects, |
| clearRects)); |
| } |
| |
| void GrVkCommandBuffer::bindDescriptorSets(const GrVkGpu* gpu, |
| GrVkProgram* program, |
| VkPipelineLayout layout, |
| uint32_t firstSet, |
| uint32_t setCount, |
| const VkDescriptorSet* descriptorSets, |
| uint32_t dynamicOffsetCount, |
| const uint32_t* dynamicOffsets) { |
| SkASSERT(fIsActive); |
| GR_VK_CALL(gpu->vkInterface(), CmdBindDescriptorSets(fCmdBuffer, |
| VK_PIPELINE_BIND_POINT_GRAPHICS, |
| layout, |
| firstSet, |
| setCount, |
| descriptorSets, |
| dynamicOffsetCount, |
| dynamicOffsets)); |
| program->addUniformResources(*this); |
| } |
| |
| void GrVkCommandBuffer::drawIndexed(const GrVkGpu* gpu, |
| uint32_t indexCount, |
| uint32_t instanceCount, |
| uint32_t firstIndex, |
| int32_t vertexOffset, |
| uint32_t firstInstance) const { |
| SkASSERT(fIsActive); |
| SkASSERT(fActiveRenderPass); |
| GR_VK_CALL(gpu->vkInterface(), CmdDrawIndexed(fCmdBuffer, |
| indexCount, |
| instanceCount, |
| firstIndex, |
| vertexOffset, |
| firstInstance)); |
| } |
| |
| void GrVkCommandBuffer::draw(const GrVkGpu* gpu, |
| uint32_t vertexCount, |
| uint32_t instanceCount, |
| uint32_t firstVertex, |
| uint32_t firstInstance) const { |
| SkASSERT(fIsActive); |
| SkASSERT(fActiveRenderPass); |
| GR_VK_CALL(gpu->vkInterface(), CmdDraw(fCmdBuffer, |
| vertexCount, |
| instanceCount, |
| firstVertex, |
| firstInstance)); |
| } |