Commit 0c0dc345 by Jamie Madill Committed by Commit Bot

Vulkan: Defer command buffer submission.

This packs more rendering commands into fewer command buffers. Instead of using a single command buffer per-command, create a buffer and record commands into it until we need to present the frame. More sophisticated management will be necessary in the future when we can do other types of copied and read-back from image data. This also reduces the number of Fences we use for checking if the device is finished with resources. Instead of creating a Fence per-command-buffer, it creates one per-swap. BUG=angleproject:1898 Change-Id: I9c6033bc04289fd8f936c0df914afc51fc434b29 Reviewed-on: https://chromium-review.googlesource.com/445800Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 43915883
...@@ -314,16 +314,14 @@ gl::Error ContextVk::drawArrays(GLenum mode, GLint first, GLsizei count) ...@@ -314,16 +314,14 @@ gl::Error ContextVk::drawArrays(GLenum mode, GLint first, GLsizei count)
} }
} }
vk::CommandBuffer *commandBuffer = mRenderer->getCommandBuffer(); vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mRenderer->getStartedCommandBuffer(&commandBuffer));
ANGLE_TRY(vkFBO->beginRenderPass(device, commandBuffer, queueSerial, state)); ANGLE_TRY(vkFBO->beginRenderPass(device, commandBuffer, queueSerial, state));
commandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mCurrentPipeline); commandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mCurrentPipeline);
commandBuffer->bindVertexBuffers(0, vertexHandles, vertexOffsets); commandBuffer->bindVertexBuffers(0, vertexHandles, vertexOffsets);
commandBuffer->draw(count, 1, first, 0); commandBuffer->draw(count, 1, first, 0);
commandBuffer->endRenderPass(); commandBuffer->endRenderPass();
ANGLE_TRY(commandBuffer->end());
ANGLE_TRY(submitCommands(*commandBuffer));
return gl::NoError(); return gl::NoError();
} }
...@@ -374,12 +372,12 @@ VkDevice ContextVk::getDevice() const ...@@ -374,12 +372,12 @@ VkDevice ContextVk::getDevice() const
return mRenderer->getDevice(); return mRenderer->getDevice();
} }
vk::CommandBuffer *ContextVk::getCommandBuffer() vk::Error ContextVk::getStartedCommandBuffer(vk::CommandBuffer **commandBufferOut)
{ {
return mRenderer->getCommandBuffer(); return mRenderer->getStartedCommandBuffer(commandBufferOut);
} }
vk::Error ContextVk::submitCommands(const vk::CommandBuffer &commandBuffer) vk::Error ContextVk::submitCommands(vk::CommandBuffer *commandBuffer)
{ {
setQueueSerial(mRenderer->getCurrentQueueSerial()); setQueueSerial(mRenderer->getCurrentQueueSerial());
ANGLE_TRY(mRenderer->submitCommandBuffer(commandBuffer)); ANGLE_TRY(mRenderer->submitCommandBuffer(commandBuffer));
......
...@@ -123,8 +123,8 @@ class ContextVk : public ContextImpl, public ResourceVk ...@@ -123,8 +123,8 @@ class ContextVk : public ContextImpl, public ResourceVk
std::vector<PathImpl *> createPaths(GLsizei) override; std::vector<PathImpl *> createPaths(GLsizei) override;
VkDevice getDevice() const; VkDevice getDevice() const;
vk::CommandBuffer *getCommandBuffer(); vk::Error getStartedCommandBuffer(vk::CommandBuffer **commandBufferOut);
vk::Error submitCommands(const vk::CommandBuffer &commandBuffer); vk::Error submitCommands(vk::CommandBuffer *commandBuffer);
RendererVk *getRenderer() { return mRenderer; } RendererVk *getRenderer() { return mRenderer; }
......
...@@ -162,8 +162,8 @@ gl::Error FramebufferVk::clear(ContextImpl *context, GLbitfield mask) ...@@ -162,8 +162,8 @@ gl::Error FramebufferVk::clear(ContextImpl *context, GLbitfield mask)
const auto &size = attachment->getSize(); const auto &size = attachment->getSize();
const gl::Rectangle renderArea(0, 0, size.width, size.height); const gl::Rectangle renderArea(0, 0, size.width, size.height);
vk::CommandBuffer *commandBuffer = contextVk->getCommandBuffer(); vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(commandBuffer->begin(contextVk->getDevice())); ANGLE_TRY(contextVk->getStartedCommandBuffer(&commandBuffer));
for (const auto &colorAttachment : mState.getColorAttachments()) for (const auto &colorAttachment : mState.getColorAttachments())
{ {
...@@ -177,10 +177,6 @@ gl::Error FramebufferVk::clear(ContextImpl *context, GLbitfield mask) ...@@ -177,10 +177,6 @@ gl::Error FramebufferVk::clear(ContextImpl *context, GLbitfield mask)
} }
} }
commandBuffer->end();
ANGLE_TRY(contextVk->submitCommands(*commandBuffer));
return gl::NoError(); return gl::NoError();
} }
...@@ -271,8 +267,9 @@ gl::Error FramebufferVk::readPixels(ContextImpl *context, ...@@ -271,8 +267,9 @@ gl::Error FramebufferVk::readPixels(ContextImpl *context,
ANGLE_TRY(renderer->createStagingImage(TextureDimension::TEX_2D, *renderTarget->format, ANGLE_TRY(renderer->createStagingImage(TextureDimension::TEX_2D, *renderTarget->format,
renderTarget->extents, &stagingImage)); renderTarget->extents, &stagingImage));
vk::CommandBuffer *commandBuffer = contextVk->getCommandBuffer(); vk::CommandBuffer *commandBuffer = nullptr;
commandBuffer->begin(device); ANGLE_TRY(contextVk->getStartedCommandBuffer(&commandBuffer));
stagingImage.getImage().changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, stagingImage.getImage().changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL,
commandBuffer); commandBuffer);
...@@ -288,9 +285,8 @@ gl::Error FramebufferVk::readPixels(ContextImpl *context, ...@@ -288,9 +285,8 @@ gl::Error FramebufferVk::readPixels(ContextImpl *context,
commandBuffer); commandBuffer);
commandBuffer->copySingleImage(*readImage, stagingImage.getImage(), copyRegion, commandBuffer->copySingleImage(*readImage, stagingImage.getImage(), copyRegion,
VK_IMAGE_ASPECT_COLOR_BIT); VK_IMAGE_ASPECT_COLOR_BIT);
commandBuffer->end();
ANGLE_TRY(renderer->submitAndFinishCommandBuffer(*commandBuffer)); ANGLE_TRY(renderer->submitAndFinishCommandBuffer(commandBuffer));
// TODO(jmadill): parameters // TODO(jmadill): parameters
uint8_t *mapPointer = nullptr; uint8_t *mapPointer = nullptr;
...@@ -587,7 +583,6 @@ gl::Error FramebufferVk::beginRenderPass(VkDevice device, ...@@ -587,7 +583,6 @@ gl::Error FramebufferVk::beginRenderPass(VkDevice device,
ANGLE_TRY(mState.getFirstColorAttachment()->getRenderTarget(&renderTarget)); ANGLE_TRY(mState.getFirstColorAttachment()->getRenderTarget(&renderTarget));
renderTarget->image->updateLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); renderTarget->image->updateLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
ANGLE_TRY(commandBuffer->begin(device));
commandBuffer->beginRenderPass(*renderPass, *framebuffer, glState.getViewport(), commandBuffer->beginRenderPass(*renderPass, *framebuffer, glState.getViewport(),
attachmentClearValues); attachmentClearValues);
......
...@@ -104,7 +104,7 @@ RendererVk::RendererVk() ...@@ -104,7 +104,7 @@ RendererVk::RendererVk()
RendererVk::~RendererVk() RendererVk::~RendererVk()
{ {
if (!mInFlightCommands.empty()) if (!mInFlightCommands.empty() || !mInFlightFences.empty() || !mGarbage.empty())
{ {
vk::Error error = finish(); vk::Error error = finish();
if (error.isError()) if (error.isError())
...@@ -571,20 +571,22 @@ const gl::Limitations &RendererVk::getNativeLimitations() const ...@@ -571,20 +571,22 @@ const gl::Limitations &RendererVk::getNativeLimitations() const
return mNativeLimitations; return mNativeLimitations;
} }
vk::CommandBuffer *RendererVk::getCommandBuffer() vk::Error RendererVk::getStartedCommandBuffer(vk::CommandBuffer **commandBufferOut)
{ {
return &mCommandBuffer; ANGLE_TRY(mCommandBuffer.begin(mDevice));
*commandBufferOut = &mCommandBuffer;
return vk::NoError();
} }
vk::Error RendererVk::submitCommandBuffer(const vk::CommandBuffer &commandBuffer) vk::Error RendererVk::submitCommandBuffer(vk::CommandBuffer *commandBuffer)
{ {
ANGLE_TRY(commandBuffer->end());
VkFenceCreateInfo fenceInfo; VkFenceCreateInfo fenceInfo;
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.pNext = nullptr; fenceInfo.pNext = nullptr;
fenceInfo.flags = 0; fenceInfo.flags = 0;
VkCommandBuffer commandBufferHandle = commandBuffer.getHandle();
VkSubmitInfo submitInfo; VkSubmitInfo submitInfo;
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pNext = nullptr; submitInfo.pNext = nullptr;
...@@ -592,7 +594,7 @@ vk::Error RendererVk::submitCommandBuffer(const vk::CommandBuffer &commandBuffer ...@@ -592,7 +594,7 @@ vk::Error RendererVk::submitCommandBuffer(const vk::CommandBuffer &commandBuffer
submitInfo.pWaitSemaphores = nullptr; submitInfo.pWaitSemaphores = nullptr;
submitInfo.pWaitDstStageMask = nullptr; submitInfo.pWaitDstStageMask = nullptr;
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBufferHandle; submitInfo.pCommandBuffers = commandBuffer->ptr();
submitInfo.signalSemaphoreCount = 0; submitInfo.signalSemaphoreCount = 0;
submitInfo.pSignalSemaphores = nullptr; submitInfo.pSignalSemaphores = nullptr;
...@@ -602,7 +604,7 @@ vk::Error RendererVk::submitCommandBuffer(const vk::CommandBuffer &commandBuffer ...@@ -602,7 +604,7 @@ vk::Error RendererVk::submitCommandBuffer(const vk::CommandBuffer &commandBuffer
return vk::NoError(); return vk::NoError();
} }
vk::Error RendererVk::submitAndFinishCommandBuffer(const vk::CommandBuffer &commandBuffer) vk::Error RendererVk::submitAndFinishCommandBuffer(vk::CommandBuffer *commandBuffer)
{ {
ANGLE_TRY(submitCommandBuffer(commandBuffer)); ANGLE_TRY(submitCommandBuffer(commandBuffer));
ANGLE_TRY(finish()); ANGLE_TRY(finish());
...@@ -610,10 +612,12 @@ vk::Error RendererVk::submitAndFinishCommandBuffer(const vk::CommandBuffer &comm ...@@ -610,10 +612,12 @@ vk::Error RendererVk::submitAndFinishCommandBuffer(const vk::CommandBuffer &comm
return vk::NoError(); return vk::NoError();
} }
vk::Error RendererVk::submitCommandsWithSync(const vk::CommandBuffer &commandBuffer, vk::Error RendererVk::submitCommandsWithSync(vk::CommandBuffer *commandBuffer,
const vk::Semaphore &waitSemaphore, const vk::Semaphore &waitSemaphore,
const vk::Semaphore &signalSemaphore) const vk::Semaphore &signalSemaphore)
{ {
ANGLE_TRY(commandBuffer->end());
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
VkSubmitInfo submitInfo; VkSubmitInfo submitInfo;
...@@ -623,12 +627,12 @@ vk::Error RendererVk::submitCommandsWithSync(const vk::CommandBuffer &commandBuf ...@@ -623,12 +627,12 @@ vk::Error RendererVk::submitCommandsWithSync(const vk::CommandBuffer &commandBuf
submitInfo.pWaitSemaphores = waitSemaphore.ptr(); submitInfo.pWaitSemaphores = waitSemaphore.ptr();
submitInfo.pWaitDstStageMask = &waitStageMask; submitInfo.pWaitDstStageMask = &waitStageMask;
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = commandBuffer.ptr(); submitInfo.pCommandBuffers = commandBuffer->ptr();
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphore.ptr(); submitInfo.pSignalSemaphores = signalSemaphore.ptr();
// TODO(jmadill): Investigate how to properly queue command buffer work. // TODO(jmadill): Investigate how to properly queue command buffer work.
ANGLE_TRY(submit(submitInfo)); ANGLE_TRY(submitFrame(submitInfo));
return vk::NoError(); return vk::NoError();
} }
...@@ -637,49 +641,85 @@ vk::Error RendererVk::finish() ...@@ -637,49 +641,85 @@ vk::Error RendererVk::finish()
{ {
ASSERT(mQueue != VK_NULL_HANDLE); ASSERT(mQueue != VK_NULL_HANDLE);
ANGLE_VK_TRY(vkQueueWaitIdle(mQueue)); ANGLE_VK_TRY(vkQueueWaitIdle(mQueue));
checkInFlightCommands(); freeAllInFlightResources();
return vk::NoError(); return vk::NoError();
} }
void RendererVk::freeAllInFlightResources()
{
for (auto &fence : mInFlightFences)
{
fence.destroy(mDevice);
}
mInFlightFences.clear();
for (auto &command : mInFlightCommands)
{
command.destroy(mDevice);
}
mInFlightCommands.clear();
for (auto &garbage : mGarbage)
{
garbage->destroy(mDevice);
}
mGarbage.clear();
}
vk::Error RendererVk::checkInFlightCommands() vk::Error RendererVk::checkInFlightCommands()
{ {
bool anyFinished = false; size_t finishedIndex = 0;
// Check if any in-flight command buffers are finished. // Check if any in-flight command buffers are finished.
for (size_t index = 0; index < mInFlightCommands.size();) for (size_t index = 0; index < mInFlightFences.size(); index++)
{ {
auto *inFlightCommand = &mInFlightCommands[index]; auto *inFlightFence = &mInFlightFences[index];
bool done = false; VkResult result = inFlightFence->get().getStatus(mDevice);
ANGLE_TRY_RESULT(inFlightCommand->finished(mDevice), done); if (result == VK_NOT_READY)
if (done) break;
{ ANGLE_VK_TRY(result);
ASSERT(inFlightCommand->queueSerial() > mLastCompletedQueueSerial); finishedIndex = index + 1;
mLastCompletedQueueSerial = inFlightCommand->queueSerial();
inFlightCommand->destroy(mDevice); // Release the fence handle.
mInFlightCommands.erase(mInFlightCommands.begin() + index); // TODO(jmadill): Re-use fences.
anyFinished = true; inFlightFence->destroy(mDevice);
}
else
{
++index;
}
} }
if (anyFinished) if (finishedIndex == 0)
return vk::NoError();
Serial finishedSerial = mInFlightFences[finishedIndex - 1].queueSerial();
mInFlightFences.erase(mInFlightFences.begin(), mInFlightFences.begin() + finishedIndex);
size_t completedCBIndex = 0;
for (size_t cbIndex = 0; cbIndex < mInFlightCommands.size(); ++cbIndex)
{ {
size_t freeIndex = 0; auto *inFlightCB = &mInFlightCommands[cbIndex];
for (; freeIndex < mGarbage.size(); ++freeIndex) if (inFlightCB->queueSerial() > finishedSerial)
{ break;
if (!mGarbage[freeIndex]->destroyIfComplete(mDevice, mLastCompletedQueueSerial))
break;
}
// Remove the entries from the garbage list - they should be ready to go. completedCBIndex = cbIndex + 1;
if (freeIndex > 0) inFlightCB->destroy(mDevice);
{ }
mGarbage.erase(mGarbage.begin(), mGarbage.begin() + freeIndex);
} if (completedCBIndex == 0)
return vk::NoError();
mInFlightCommands.erase(mInFlightCommands.begin(),
mInFlightCommands.begin() + completedCBIndex);
size_t freeIndex = 0;
for (; freeIndex < mGarbage.size(); ++freeIndex)
{
if (!mGarbage[freeIndex]->destroyIfComplete(mDevice, finishedSerial))
break;
}
// Remove the entries from the garbage list - they should be ready to go.
if (freeIndex > 0)
{
mGarbage.erase(mGarbage.begin(), mGarbage.begin() + freeIndex);
} }
return vk::NoError(); return vk::NoError();
...@@ -687,28 +727,44 @@ vk::Error RendererVk::checkInFlightCommands() ...@@ -687,28 +727,44 @@ vk::Error RendererVk::checkInFlightCommands()
vk::Error RendererVk::submit(const VkSubmitInfo &submitInfo) vk::Error RendererVk::submit(const VkSubmitInfo &submitInfo)
{ {
checkInFlightCommands(); ANGLE_VK_TRY(vkQueueSubmit(mQueue, 1, &submitInfo, VK_NULL_HANDLE));
// Start a Fence to record when this command buffer finishes. // Store this command buffer in the in-flight list.
VkFenceCreateInfo fenceInfo; mInFlightCommands.emplace_back(std::move(mCommandBuffer), mCurrentQueueSerial);
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.pNext = nullptr; // Sanity check.
fenceInfo.flags = 0; ASSERT(mInFlightCommands.size() < 1000u);
// Increment the queue serial. If this fails, we should restart ANGLE.
ANGLE_VK_CHECK(++mCurrentQueueSerial, VK_ERROR_OUT_OF_HOST_MEMORY);
return vk::NoError();
}
vk::Error RendererVk::submitFrame(const VkSubmitInfo &submitInfo)
{
VkFenceCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
vk::Fence fence; vk::Fence fence;
ANGLE_TRY(fence.init(mDevice, fenceInfo)); ANGLE_TRY(fence.init(mDevice, createInfo));
ANGLE_VK_TRY(vkQueueSubmit(mQueue, 1, &submitInfo, fence.getHandle())); ANGLE_VK_TRY(vkQueueSubmit(mQueue, 1, &submitInfo, fence.getHandle()));
// Store this command buffer in the in-flight list. // Store this command buffer in the in-flight list.
mInFlightCommands.emplace_back(vk::FenceAndCommandBuffer(mCurrentQueueSerial, std::move(fence), mInFlightFences.emplace_back(std::move(fence), mCurrentQueueSerial);
std::move(mCommandBuffer))); mInFlightCommands.emplace_back(std::move(mCommandBuffer), mCurrentQueueSerial);
// Sanity check. // Sanity check.
ASSERT(mInFlightCommands.size() < 1000u); ASSERT(mInFlightCommands.size() < 1000u);
// Increment the command buffer serial. If this fails, we need to restart ANGLE. // Increment the queue serial. If this fails, we should restart ANGLE.
ANGLE_VK_CHECK(++mCurrentQueueSerial, VK_ERROR_OUT_OF_HOST_MEMORY); ANGLE_VK_CHECK(++mCurrentQueueSerial, VK_ERROR_OUT_OF_HOST_MEMORY);
ANGLE_TRY(checkInFlightCommands());
return vk::NoError(); return vk::NoError();
} }
......
...@@ -50,10 +50,10 @@ class RendererVk : angle::NonCopyable ...@@ -50,10 +50,10 @@ class RendererVk : angle::NonCopyable
vk::ErrorOrResult<uint32_t> selectPresentQueueForSurface(VkSurfaceKHR surface); vk::ErrorOrResult<uint32_t> selectPresentQueueForSurface(VkSurfaceKHR surface);
// TODO(jmadill): Use ContextImpl for command buffers to enable threaded contexts. // TODO(jmadill): Use ContextImpl for command buffers to enable threaded contexts.
vk::CommandBuffer *getCommandBuffer(); vk::Error getStartedCommandBuffer(vk::CommandBuffer **commandBufferOut);
vk::Error submitCommandBuffer(const vk::CommandBuffer &commandBuffer); vk::Error submitCommandBuffer(vk::CommandBuffer *commandBuffer);
vk::Error submitAndFinishCommandBuffer(const vk::CommandBuffer &commandBuffer); vk::Error submitAndFinishCommandBuffer(vk::CommandBuffer *commandBuffer);
vk::Error submitCommandsWithSync(const vk::CommandBuffer &commandBuffer, vk::Error submitCommandsWithSync(vk::CommandBuffer *commandBuffer,
const vk::Semaphore &waitSemaphore, const vk::Semaphore &waitSemaphore,
const vk::Semaphore &signalSemaphore); const vk::Semaphore &signalSemaphore);
vk::Error finish(); vk::Error finish();
...@@ -99,7 +99,9 @@ class RendererVk : angle::NonCopyable ...@@ -99,7 +99,9 @@ class RendererVk : angle::NonCopyable
gl::Extensions *outExtensions, gl::Extensions *outExtensions,
gl::Limitations *outLimitations) const; gl::Limitations *outLimitations) const;
vk::Error submit(const VkSubmitInfo &submitInfo); vk::Error submit(const VkSubmitInfo &submitInfo);
vk::Error submitFrame(const VkSubmitInfo &submitInfo);
vk::Error checkInFlightCommands(); vk::Error checkInFlightCommands();
void freeAllInFlightResources();
mutable bool mCapsInitialized; mutable bool mCapsInitialized;
mutable gl::Caps mNativeCaps; mutable gl::Caps mNativeCaps;
...@@ -124,7 +126,8 @@ class RendererVk : angle::NonCopyable ...@@ -124,7 +126,8 @@ class RendererVk : angle::NonCopyable
GlslangWrapper *mGlslangWrapper; GlslangWrapper *mGlslangWrapper;
Serial mCurrentQueueSerial; Serial mCurrentQueueSerial;
Serial mLastCompletedQueueSerial; Serial mLastCompletedQueueSerial;
std::vector<vk::FenceAndCommandBuffer> mInFlightCommands; std::vector<vk::CommandBufferAndSerial> mInFlightCommands;
std::vector<vk::FenceAndSerial> mInFlightFences;
std::vector<std::unique_ptr<vk::IGarbageObject>> mGarbage; std::vector<std::unique_ptr<vk::IGarbageObject>> mGarbage;
}; };
......
...@@ -358,8 +358,8 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer) ...@@ -358,8 +358,8 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
ANGLE_VK_TRY(vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, swapchainImages.data())); ANGLE_VK_TRY(vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, swapchainImages.data()));
// CommandBuffer is a singleton in the Renderer. // CommandBuffer is a singleton in the Renderer.
vk::CommandBuffer *commandBuffer = renderer->getCommandBuffer(); vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(commandBuffer->begin(device)); ANGLE_TRY(renderer->getStartedCommandBuffer(&commandBuffer));
VkClearColorValue transparentBlack; VkClearColorValue transparentBlack;
transparentBlack.float32[0] = 0.0f; transparentBlack.float32[0] = 0.0f;
...@@ -404,8 +404,7 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer) ...@@ -404,8 +404,7 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
mSwapchainImageViews[imageIndex].retain(device, std::move(imageView)); mSwapchainImageViews[imageIndex].retain(device, std::move(imageView));
} }
ANGLE_TRY(commandBuffer->end()); ANGLE_TRY(renderer->submitAndFinishCommandBuffer(commandBuffer));
ANGLE_TRY(renderer->submitAndFinishCommandBuffer(*commandBuffer));
ANGLE_TRY(mImageAvailableSemaphore.init(device)); ANGLE_TRY(mImageAvailableSemaphore.init(device));
ANGLE_TRY(mRenderingCompleteSemaphore.init(device)); ANGLE_TRY(mRenderingCompleteSemaphore.init(device));
...@@ -429,17 +428,16 @@ egl::Error WindowSurfaceVk::swap(const DisplayImpl *displayImpl) ...@@ -429,17 +428,16 @@ egl::Error WindowSurfaceVk::swap(const DisplayImpl *displayImpl)
vk::Error WindowSurfaceVk::swapImpl(RendererVk *renderer) vk::Error WindowSurfaceVk::swapImpl(RendererVk *renderer)
{ {
vk::CommandBuffer *currentCB = renderer->getCommandBuffer(); vk::CommandBuffer *currentCB = nullptr;
ANGLE_TRY(renderer->getStartedCommandBuffer(&currentCB));
auto *image = &mSwapchainImages[mCurrentSwapchainImageIndex]; auto *image = &mSwapchainImages[mCurrentSwapchainImageIndex];
currentCB->begin(renderer->getDevice());
image->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, image->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, currentCB); VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, currentCB);
currentCB->end();
ANGLE_TRY(renderer->submitCommandsWithSync(*currentCB, mImageAvailableSemaphore, ANGLE_TRY(renderer->submitCommandsWithSync(currentCB, mImageAvailableSemaphore,
mRenderingCompleteSemaphore)); mRenderingCompleteSemaphore));
VkPresentInfoKHR presentInfo; VkPresentInfoKHR presentInfo;
......
...@@ -238,7 +238,7 @@ Error CommandPool::init(VkDevice device, const VkCommandPoolCreateInfo &createIn ...@@ -238,7 +238,7 @@ Error CommandPool::init(VkDevice device, const VkCommandPoolCreateInfo &createIn
} }
// CommandBuffer implementation. // CommandBuffer implementation.
CommandBuffer::CommandBuffer() : mCommandPool(nullptr) CommandBuffer::CommandBuffer() : mStarted(false), mCommandPool(nullptr)
{ {
} }
...@@ -250,6 +250,11 @@ void CommandBuffer::setCommandPool(CommandPool *commandPool) ...@@ -250,6 +250,11 @@ void CommandBuffer::setCommandPool(CommandPool *commandPool)
Error CommandBuffer::begin(VkDevice device) Error CommandBuffer::begin(VkDevice device)
{ {
if (mStarted)
{
return NoError();
}
if (mHandle == VK_NULL_HANDLE) if (mHandle == VK_NULL_HANDLE)
{ {
VkCommandBufferAllocateInfo commandBufferInfo; VkCommandBufferAllocateInfo commandBufferInfo;
...@@ -266,6 +271,8 @@ Error CommandBuffer::begin(VkDevice device) ...@@ -266,6 +271,8 @@ Error CommandBuffer::begin(VkDevice device)
reset(); reset();
} }
mStarted = true;
VkCommandBufferBeginInfo beginInfo; VkCommandBufferBeginInfo beginInfo;
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.pNext = nullptr; beginInfo.pNext = nullptr;
...@@ -280,6 +287,8 @@ Error CommandBuffer::begin(VkDevice device) ...@@ -280,6 +287,8 @@ Error CommandBuffer::begin(VkDevice device)
Error CommandBuffer::end() Error CommandBuffer::end()
{ {
mStarted = false;
ASSERT(valid()); ASSERT(valid());
ANGLE_VK_TRY(vkEndCommandBuffer(mHandle)); ANGLE_VK_TRY(vkEndCommandBuffer(mHandle));
return NoError(); return NoError();
...@@ -287,6 +296,8 @@ Error CommandBuffer::end() ...@@ -287,6 +296,8 @@ Error CommandBuffer::end()
Error CommandBuffer::reset() Error CommandBuffer::reset()
{ {
mStarted = false;
ASSERT(valid()); ASSERT(valid());
ANGLE_VK_TRY(vkResetCommandBuffer(mHandle, 0)); ANGLE_VK_TRY(vkResetCommandBuffer(mHandle, 0));
return NoError(); return NoError();
...@@ -861,47 +872,6 @@ VkResult Fence::getStatus(VkDevice device) const ...@@ -861,47 +872,6 @@ VkResult Fence::getStatus(VkDevice device) const
return vkGetFenceStatus(device, mHandle); return vkGetFenceStatus(device, mHandle);
} }
// FenceAndCommandBuffer implementation.
FenceAndCommandBuffer::FenceAndCommandBuffer(Serial queueSerial,
Fence &&fence,
CommandBuffer &&commandBuffer)
: mQueueSerial(queueSerial), mFence(std::move(fence)), mCommandBuffer(std::move(commandBuffer))
{
}
FenceAndCommandBuffer::FenceAndCommandBuffer(FenceAndCommandBuffer &&other)
: mQueueSerial(std::move(other.mQueueSerial)),
mFence(std::move(other.mFence)),
mCommandBuffer(std::move(other.mCommandBuffer))
{
}
void FenceAndCommandBuffer::destroy(VkDevice device)
{
mFence.destroy(device);
mCommandBuffer.destroy(device);
}
vk::ErrorOrResult<bool> FenceAndCommandBuffer::finished(VkDevice device) const
{
VkResult result = mFence.getStatus(device);
// Should this be a part of ANGLE_VK_TRY?
if (result == VK_NOT_READY)
{
return false;
}
ANGLE_VK_TRY(result);
return true;
}
FenceAndCommandBuffer &FenceAndCommandBuffer::operator=(FenceAndCommandBuffer &&other)
{
std::swap(mQueueSerial, other.mQueueSerial);
mFence = std::move(other.mFence);
mCommandBuffer = std::move(other.mCommandBuffer);
return *this;
}
} // namespace vk } // namespace vk
Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProps, Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProps,
......
...@@ -209,6 +209,8 @@ class CommandBuffer final : public WrappedObject<CommandBuffer, VkCommandBuffer> ...@@ -209,6 +209,8 @@ class CommandBuffer final : public WrappedObject<CommandBuffer, VkCommandBuffer>
public: public:
CommandBuffer(); CommandBuffer();
bool started() const { return mStarted; }
void destroy(VkDevice device); void destroy(VkDevice device);
using WrappedObject::operator=; using WrappedObject::operator=;
...@@ -246,6 +248,7 @@ class CommandBuffer final : public WrappedObject<CommandBuffer, VkCommandBuffer> ...@@ -246,6 +248,7 @@ class CommandBuffer final : public WrappedObject<CommandBuffer, VkCommandBuffer>
const std::vector<VkDeviceSize> &offsets); const std::vector<VkDeviceSize> &offsets);
private: private:
bool mStarted;
CommandPool *mCommandPool; CommandPool *mCommandPool;
}; };
...@@ -428,28 +431,45 @@ class Fence final : public WrappedObject<Fence, VkFence> ...@@ -428,28 +431,45 @@ class Fence final : public WrappedObject<Fence, VkFence>
VkResult getStatus(VkDevice device) const; VkResult getStatus(VkDevice device) const;
}; };
class FenceAndCommandBuffer final : angle::NonCopyable template <typename ObjT>
class ObjectAndSerial final : angle::NonCopyable
{ {
public: public:
FenceAndCommandBuffer(Serial queueSerial, Fence &&fence, CommandBuffer &&commandBuffer); ObjectAndSerial(ObjT &&object, Serial queueSerial)
FenceAndCommandBuffer(FenceAndCommandBuffer &&other); : mObject(std::move(object)), mQueueSerial(queueSerial)
FenceAndCommandBuffer &operator=(FenceAndCommandBuffer &&other); {
}
void destroy(VkDevice device); ObjectAndSerial(ObjectAndSerial &&other)
vk::ErrorOrResult<bool> finished(VkDevice device) const; : mObject(std::move(other.mObject)), mQueueSerial(std::move(other.mQueueSerial))
{
}
ObjectAndSerial &operator=(ObjectAndSerial &&other)
{
mObject = std::move(other.mObject);
mQueueSerial = std::move(other.mQueueSerial);
return *this;
}
void destroy(VkDevice device) { mObject.destroy(device); }
Serial queueSerial() const { return mQueueSerial; } Serial queueSerial() const { return mQueueSerial; }
const ObjT &get() const { return mObject; }
private: private:
ObjT mObject;
Serial mQueueSerial; Serial mQueueSerial;
Fence mFence;
CommandBuffer mCommandBuffer;
}; };
using CommandBufferAndSerial = ObjectAndSerial<CommandBuffer>;
using FenceAndSerial = ObjectAndSerial<Fence>;
class IGarbageObject : angle::NonCopyable class IGarbageObject : angle::NonCopyable
{ {
public: public:
virtual bool destroyIfComplete(VkDevice device, Serial completedSerial) = 0; virtual bool destroyIfComplete(VkDevice device, Serial completedSerial) = 0;
virtual void destroy(VkDevice device) = 0;
}; };
template <typename T> template <typename T>
...@@ -469,6 +489,8 @@ class GarbageObject final : public IGarbageObject ...@@ -469,6 +489,8 @@ class GarbageObject final : public IGarbageObject
return false; return false;
} }
void destroy(VkDevice device) override { mObject.destroy(device); }
private: private:
Serial mSerial; Serial mSerial;
T mObject; T mObject;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment