blob: e43c50fc4ac44bdeaeb546002cc86fd6a614f920 [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.
*/
#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::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));
}