Commit 0966f3f8 by Michael Spang Committed by Commit Bot

Vulkan: Remove flush semaphore chain

This avoids using an unbounded number of semaphores in between calls to swapbuffers. Using two semaphores should be sufficient to synchronize swaps. In addition, fix tracking of VkPipelineStageFlags by creating a 2nd vector parallel to the semaphores vector. The last fix assumed there could only be 2 wait semaphores, but that bound only applied to signal semaphores. After this change, there can only be one signal semaphore, but there's still no bound to wait semaphores. Bug: angleproject:3637 Change-Id: I7fbba67fa4bbdf62b9e9d530a924acd5236705d3 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1688435 Commit-Queue: Michael Spang <spang@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent 0c83813f
......@@ -76,30 +76,34 @@ constexpr size_t kInFlightCommandsLimit = 100u;
// Initially dumping the command graphs is disabled.
constexpr bool kEnableCommandGraphDiagnostics = false;
constexpr VkPipelineStageFlags kSubmitInfoWaitDstStageMask[] = {
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
};
void InitializeSubmitInfo(VkSubmitInfo *submitInfo,
const vk::PrimaryCommandBuffer &commandBuffer,
const std::vector<VkSemaphore> &waitSemaphores,
const SignalSemaphoreVector &signalSemaphores)
std::vector<VkPipelineStageFlags> *waitSemaphoreStageMasks,
const vk::Semaphore *signalSemaphore)
{
// Verify that the submitInfo has been zero'd out.
ASSERT(submitInfo->signalSemaphoreCount == 0);
submitInfo->sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo->commandBufferCount = commandBuffer.valid() ? 1 : 0;
submitInfo->pCommandBuffers = commandBuffer.ptr();
static_assert(std::extent<decltype(kSubmitInfoWaitDstStageMask)>::value ==
std::decay_t<decltype(signalSemaphores)>::max_size(),
"Wrong size for waitStageMask");
if (waitSemaphoreStageMasks->size() < waitSemaphores.size())
{
waitSemaphoreStageMasks->resize(waitSemaphores.size(),
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
}
submitInfo->waitSemaphoreCount = waitSemaphores.size();
submitInfo->pWaitSemaphores = waitSemaphores.data();
submitInfo->pWaitDstStageMask = kSubmitInfoWaitDstStageMask;
submitInfo->pWaitDstStageMask = waitSemaphoreStageMasks->data();
submitInfo->signalSemaphoreCount = signalSemaphores.size();
submitInfo->pSignalSemaphores = signalSemaphores.data();
if (signalSemaphore)
{
submitInfo->signalSemaphoreCount = 1;
submitInfo->pSignalSemaphores = signalSemaphore->ptr();
}
}
uint32_t GetCoverageSampleCount(const gl::State &glState, FramebufferVk *drawFramebuffer)
......@@ -359,7 +363,7 @@ angle::Result ContextVk::waitSemaphore(const gl::Context *context,
const GLuint *textures,
const GLenum *srcLayouts)
{
mWaitSemaphores.push_back(vk::GetImpl(semaphore)->getHandle());
addWaitSemaphore(vk::GetImpl(semaphore)->getHandle());
if (numBufferBarriers != 0)
{
......@@ -396,7 +400,7 @@ angle::Result ContextVk::signalSemaphore(const gl::Context *context,
UNIMPLEMENTED();
}
return flushImpl(semaphore);
return flushImpl(vk::GetImpl(semaphore)->ptr());
}
angle::Result ContextVk::setupDraw(const gl::Context *context,
......@@ -933,7 +937,8 @@ angle::Result ContextVk::synchronizeCpuGpuTime()
// Submit the command buffer
VkSubmitInfo submitInfo = {};
InitializeSubmitInfo(&submitInfo, commandBatch.get(), {}, {});
InitializeSubmitInfo(&submitInfo, commandBatch.get(), {}, &mWaitSemaphoreStageMasks,
nullptr);
ANGLE_TRY(submitFrame(submitInfo, std::move(commandBuffer)));
......@@ -2126,9 +2131,9 @@ const gl::ActiveTextureArray<TextureVk *> &ContextVk::getActiveTextures() const
return mActiveTextures;
}
angle::Result ContextVk::flushImpl(const gl::Semaphore *clientSignalSemaphore)
angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore)
{
if (mCommandGraph.empty() && !clientSignalSemaphore && mWaitSemaphores.empty())
if (mCommandGraph.empty() && !signalSemaphore && mWaitSemaphores.empty())
{
return angle::Result::Continue;
}
......@@ -2141,16 +2146,11 @@ angle::Result ContextVk::flushImpl(const gl::Semaphore *clientSignalSemaphore)
ANGLE_TRY(flushCommandGraph(&commandBatch.get()));
}
SignalSemaphoreVector signalSemaphores;
ANGLE_TRY(generateSurfaceSemaphores(&signalSemaphores));
if (clientSignalSemaphore)
{
signalSemaphores.push_back(vk::GetImpl(clientSignalSemaphore)->getHandle());
}
waitForSwapchainImageIfNecessary();
VkSubmitInfo submitInfo = {};
InitializeSubmitInfo(&submitInfo, commandBatch.get(), mWaitSemaphores, signalSemaphores);
InitializeSubmitInfo(&submitInfo, commandBatch.get(), mWaitSemaphores,
&mWaitSemaphoreStageMasks, signalSemaphore);
ANGLE_TRY(submitFrame(submitInfo, commandBatch.release()));
......@@ -2187,6 +2187,11 @@ angle::Result ContextVk::finishImpl()
return angle::Result::Continue;
}
void ContextVk::addWaitSemaphore(VkSemaphore semaphore)
{
mWaitSemaphores.push_back(semaphore);
}
const vk::CommandPool &ContextVk::getCommandPool() const
{
return mCommandPool;
......@@ -2475,21 +2480,17 @@ angle::Result ContextVk::updateDefaultAttribute(size_t attribIndex)
return angle::Result::Continue;
}
angle::Result ContextVk::generateSurfaceSemaphores(SignalSemaphoreVector *signalSemaphores)
void ContextVk::waitForSwapchainImageIfNecessary()
{
if (mCurrentWindowSurface)
{
const vk::Semaphore *waitSemaphore = nullptr;
const vk::Semaphore *signalSemaphore = nullptr;
ANGLE_TRY(mCurrentWindowSurface->generateSemaphoresForFlush(this, &waitSemaphore,
&signalSemaphore));
mWaitSemaphores.push_back(waitSemaphore->getHandle());
ASSERT(signalSemaphores->empty());
signalSemaphores->push_back(signalSemaphore->getHandle());
vk::Semaphore waitSemaphore = mCurrentWindowSurface->getAcquireImageSemaphore();
if (waitSemaphore.valid())
{
addWaitSemaphore(waitSemaphore.getHandle());
releaseObject(getCurrentQueueSerial(), &waitSemaphore);
}
}
return angle::Result::Continue;
}
vk::DescriptorSetLayoutDesc ContextVk::getDriverUniformsDescriptorSetDesc() const
......
......@@ -241,9 +241,11 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
mLastIndexBufferOffset = reinterpret_cast<const void *>(angle::DirtyPointer);
}
angle::Result flushImpl(const gl::Semaphore *semaphore);
angle::Result flushImpl(const vk::Semaphore *semaphore);
angle::Result finishImpl();
void addWaitSemaphore(VkSemaphore semaphore);
const vk::CommandPool &getCommandPool() const;
Serial getCurrentQueueSerial() const { return mCurrentQueueSerial; }
......@@ -414,7 +416,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
void handleDeviceLost();
angle::Result generateSurfaceSemaphores(SignalSemaphoreVector *signalSemaphores);
void waitForSwapchainImageIfNecessary();
vk::PipelineHelper *mCurrentPipeline;
gl::PrimitiveMode mCurrentDrawMode;
......@@ -588,6 +590,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
// Semaphores that must be waited on in the next submission.
std::vector<VkSemaphore> mWaitSemaphores;
std::vector<VkPipelineStageFlags> mWaitSemaphoreStageMasks;
// Hold information from the last gpu clock sync for future gpu-to-cpu timestamp conversions.
struct GpuClockSyncInfo
......
......@@ -27,6 +27,8 @@ class SemaphoreVk : public SemaphoreImpl
VkSemaphore getHandle() const { return mSemaphore.getHandle(); }
const vk::Semaphore *ptr() const { return &mSemaphore; }
private:
angle::Result importOpaqueFd(gl::Context *context, GLint fd);
......
......@@ -331,18 +331,6 @@ WindowSurfaceVk::SwapchainImage::SwapchainImage(SwapchainImage &&other)
{}
WindowSurfaceVk::SwapHistory::SwapHistory() = default;
WindowSurfaceVk::SwapHistory::SwapHistory(SwapHistory &&other)
{
*this = std::move(other);
}
WindowSurfaceVk::SwapHistory &WindowSurfaceVk::SwapHistory::operator=(SwapHistory &&other)
{
std::swap(sharedFence, other.sharedFence);
std::swap(semaphores, other.semaphores);
std::swap(swapchain, other.swapchain);
return *this;
}
WindowSurfaceVk::SwapHistory::~SwapHistory() = default;
......@@ -355,12 +343,7 @@ void WindowSurfaceVk::SwapHistory::destroy(VkDevice device)
}
sharedFence.reset(device);
for (vk::Semaphore &semaphore : semaphores)
{
semaphore.destroy(device);
}
semaphores.clear();
presentImageSemaphore.destroy(device);
}
angle::Result WindowSurfaceVk::SwapHistory::waitFence(ContextVk *contextVk)
......@@ -431,11 +414,7 @@ void WindowSurfaceVk::destroy(const egl::Display *display)
mSurface = VK_NULL_HANDLE;
}
for (vk::Semaphore &flushSemaphore : mFlushSemaphoreChain)
{
flushSemaphore.destroy(device);
}
mFlushSemaphoreChain.clear();
mAcquireImageSemaphore.destroy(device);
}
egl::Error WindowSurfaceVk::initialize(const egl::Display *display)
......@@ -917,16 +896,14 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
}
image.image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::Present, swapCommands);
ANGLE_TRY(contextVk->flushImpl(nullptr));
ANGLE_VK_TRY(contextVk, swap.presentImageSemaphore.init(contextVk->getDevice()));
// The semaphore chain must at least have the semaphore returned by vkAquireImage in it. It will
// likely have more based on how much work was flushed this frame.
ASSERT(!mFlushSemaphoreChain.empty());
ANGLE_TRY(contextVk->flushImpl(&swap.presentImageSemaphore));
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = mFlushSemaphoreChain.back().ptr();
presentInfo.pWaitSemaphores = swap.presentImageSemaphore.ptr();
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &mSwapchain;
presentInfo.pImageIndices = &mCurrentSwapchainImageIndex;
......@@ -966,7 +943,7 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
// Update the swap history for this presentation
swap.sharedFence = contextVk->getLastSubmittedFence();
swap.semaphores = std::move(mFlushSemaphoreChain);
ASSERT(!mAcquireImageSemaphore.valid());
++mCurrentSwapHistoryIndex;
mCurrentSwapHistoryIndex =
......@@ -1032,25 +1009,23 @@ VkResult WindowSurfaceVk::nextSwapchainImage(vk::Context *context)
{
VkDevice device = context->getDevice();
vk::Scoped<vk::Semaphore> aquireImageSemaphore(device);
VkResult result = aquireImageSemaphore.get().init(device);
vk::Scoped<vk::Semaphore> acquireImageSemaphore(device);
VkResult result = acquireImageSemaphore.get().init(device);
if (ANGLE_UNLIKELY(result != VK_SUCCESS))
{
return result;
}
result = vkAcquireNextImageKHR(device, mSwapchain, UINT64_MAX,
aquireImageSemaphore.get().getHandle(), VK_NULL_HANDLE,
acquireImageSemaphore.get().getHandle(), VK_NULL_HANDLE,
&mCurrentSwapchainImageIndex);
if (ANGLE_UNLIKELY(result != VK_SUCCESS))
{
return result;
}
// After presenting, the flush semaphore chain is cleared. The semaphore returned by
// vkAcquireNextImage will start a new chain.
ASSERT(mFlushSemaphoreChain.empty());
mFlushSemaphoreChain.push_back(aquireImageSemaphore.release());
// The semaphore will be waited on in the next flush.
mAcquireImageSemaphore = acquireImageSemaphore.release();
SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex];
......@@ -1217,23 +1192,9 @@ angle::Result WindowSurfaceVk::getCurrentFramebuffer(vk::Context *context,
return angle::Result::Continue;
}
angle::Result WindowSurfaceVk::generateSemaphoresForFlush(vk::Context *context,
const vk::Semaphore **outWaitSemaphore,
const vk::Semaphore **outSignalSempahore)
vk::Semaphore WindowSurfaceVk::getAcquireImageSemaphore()
{
// The flush semaphore chain should always start with a semaphore in it, created by the
// vkAquireImage call. This semaphore must be waited on before any rendering to the swap chain
// image can occur.
ASSERT(!mFlushSemaphoreChain.empty());
vk::Semaphore nextSemaphore;
ANGLE_VK_TRY(context, nextSemaphore.init(context->getDevice()));
mFlushSemaphoreChain.push_back(std::move(nextSemaphore));
*outWaitSemaphore = &mFlushSemaphoreChain[mFlushSemaphoreChain.size() - 2];
*outSignalSempahore = &mFlushSemaphoreChain[mFlushSemaphoreChain.size() - 1];
return angle::Result::Continue;
return std::move(mAcquireImageSemaphore);
}
angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context,
......
......@@ -142,9 +142,7 @@ class WindowSurfaceVk : public SurfaceVk
const vk::RenderPass &compatibleRenderPass,
vk::Framebuffer **framebufferOut);
angle::Result generateSemaphoresForFlush(vk::Context *context,
const vk::Semaphore **outWaitSemaphore,
const vk::Semaphore **outSignalSempahore);
vk::Semaphore getAcquireImageSemaphore();
protected:
EGLNativeWindowType mNativeWindowType;
......@@ -202,24 +200,7 @@ class WindowSurfaceVk : public SurfaceVk
};
std::vector<SwapchainImage> mSwapchainImages;
// Each time vkPresent is called, a wait semaphore is needed to know when the work to render the
// frame is done. For ANGLE to know when that is, it needs to add a signal semaphore to each
// flush. Conversely, before being able to use a swap chain image, ANGLE needs to wait on the
// semaphore returned by vkAcquireNextImage.
//
// We build a chain of semaphores starting with the semaphore returned by vkAcquireNextImageKHR
// and ending with the semaphore provided to vkPresent. Each time generateSemaphoresForFlush is
// called, a new semaphore is created and appended to mFlushSemaphoreChain. The second last
// semaphore is used as a wait semaphore and the last one is used as a signal semaphore for the
// flush.
//
// The semaphore chain is cleared after every call to present and a new one is started once
// vkAquireImage is called.
//
// We don't need a semaphore chain for offscreen surfaces or surfaceless rendering because the
// results cannot affect the images in a swap chain.
std::vector<vk::Semaphore> mFlushSemaphoreChain;
vk::Semaphore mAcquireImageSemaphore;
// A circular buffer that stores the serial of the renderer on every swap. The CPU is
// throttled by waiting for the 2nd previous serial to finish. Old swapchains are scheduled to
......@@ -227,8 +208,8 @@ class WindowSurfaceVk : public SurfaceVk
struct SwapHistory : angle::NonCopyable
{
SwapHistory();
SwapHistory(SwapHistory &&other);
SwapHistory &operator=(SwapHistory &&other);
SwapHistory(SwapHistory &&other) = delete;
SwapHistory &operator=(SwapHistory &&other) = delete;
~SwapHistory();
void destroy(VkDevice device);
......@@ -238,7 +219,8 @@ class WindowSurfaceVk : public SurfaceVk
// Fence associated with the last submitted work to render to this swapchain image.
vk::Shared<vk::Fence> sharedFence;
std::vector<vk::Semaphore> semaphores;
vk::Semaphore presentImageSemaphore;
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
};
static constexpr size_t kSwapHistorySize = 2;
......
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