Commit 65ee5168 by Jamie Madill Committed by Commit Bot

Vulkan: Align submit and serial management code.

This progresses the goal of merging TaskProcessor and CommandQueue. Moving the serial management out of RendererVk allows these classes to have finer control over when thread synchronization locks happen. Note: device lost handling seems untested currently. Bug: b/172704839 Change-Id: I0cc61e1ffe41aad0b898d4146c8dbd08a2cebd3c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2525140 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com>
parent 453a113a
......@@ -76,11 +76,12 @@ class CommandProcessorTask
const Semaphore *semaphore,
egl::ContextPriority priority,
GarbageList &&currentGarbage,
ResourceUseList &&currentResources);
Serial submitQueueSerial);
void initOneOffQueueSubmit(VkCommandBuffer oneOffCommandBufferVk,
egl::ContextPriority priority,
const Fence *fence);
const Fence *fence,
Serial submitQueueSerial);
CommandProcessorTask &operator=(CommandProcessorTask &&rhs);
......@@ -91,7 +92,6 @@ class CommandProcessorTask
void setQueueSerial(Serial serial) { mSerial = serial; }
Serial getQueueSerial() const { return mSerial; }
ResourceUseList &getResourceUseList() { return mResourceUseList; }
CustomTask getTaskCommand() { return mTask; }
std::vector<VkSemaphore> &getWaitSemaphores() { return mWaitSemaphores; }
std::vector<VkPipelineStageFlags> &getWaitSemaphoreStageMasks()
......@@ -123,7 +123,6 @@ class CommandProcessorTask
std::vector<VkPipelineStageFlags> mWaitSemaphoreStageMasks;
const Semaphore *mSemaphore;
GarbageList mGarbage;
ResourceUseList mResourceUseList;
// FinishToSerial & Flush command data
Serial mSerial;
......@@ -169,22 +168,30 @@ class CommandQueue final : angle::NonCopyable
~CommandQueue();
angle::Result init(Context *context);
void destroy(VkDevice device);
void destroy(RendererVk *renderer);
void handleDeviceLost(RendererVk *renderer);
void clearAllGarbage(RendererVk *renderer);
angle::Result finishToSerial(Context *context, Serial finishSerial, uint64_t timeout);
Serial reserveSubmitSerial();
angle::Result submitFrame(Context *context,
egl::ContextPriority priority,
const std::vector<VkSemaphore> &waitSemaphores,
const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks,
const Semaphore *signalSemaphore,
Shared<Fence> &&sharedFence,
ResourceUseList &&resourceList,
GarbageList &&currentGarbage,
CommandPool *commandPool);
CommandPool *commandPool,
Serial submitQueueSerial);
angle::Result queueSubmit(Context *context,
egl::ContextPriority contextPriority,
const VkSubmitInfo &submitInfo,
const Fence *fence,
Serial submitQueueSerial);
angle::Result waitForSerialWithUserTimeout(vk::Context *context,
Serial serial,
......@@ -202,6 +209,10 @@ class CommandQueue final : angle::NonCopyable
const RenderPass &renderPass,
CommandBufferHelper *renderPassCommands);
ANGLE_INLINE Serial getLastSubmittedQueueSerial() const { return mLastSubmittedQueueSerial; }
ANGLE_INLINE Serial getLastCompletedQueueSerial() const { return mLastCompletedQueueSerial; }
ANGLE_INLINE Serial getCurrentQueueSerial() const { return mCurrentQueueSerial; }
private:
angle::Result releaseToCommandBatch(Context *context,
PrimaryCommandBuffer &&commandBuffer,
......@@ -222,6 +233,12 @@ class CommandQueue final : angle::NonCopyable
// Keeps a free list of reusable primary command buffers.
PrimaryCommandBuffer mPrimaryCommands;
PersistentCommandPool mPrimaryCommandPool;
// Queue serial management.
AtomicSerialFactory mQueueSerialFactory;
Serial mLastCompletedQueueSerial;
Serial mLastSubmittedQueueSerial;
Serial mCurrentQueueSerial;
};
class TaskProcessor : angle::NonCopyable
......@@ -249,11 +266,12 @@ class TaskProcessor : angle::NonCopyable
GarbageList *currentGarbage,
CommandPool *commandPool,
PrimaryCommandBuffer &&commandBuffer,
const Serial &queueSerial);
Serial submitQueueSerial);
angle::Result queueSubmit(Context *context,
VkQueue queue,
const VkSubmitInfo &submitInfo,
const Fence *fence);
const Fence *fence,
Serial submitQueueSerial);
void handleDeviceLost(Context *context);
......@@ -261,6 +279,12 @@ class TaskProcessor : angle::NonCopyable
VkResult getLastAndClearPresentResult(VkSwapchainKHR swapchain);
Serial reserveSubmitSerial();
ANGLE_INLINE Serial getLastSubmittedQueueSerial() const { return mLastSubmittedQueueSerial; }
ANGLE_INLINE Serial getLastCompletedQueueSerial() const { return mLastCompletedQueueSerial; }
ANGLE_INLINE Serial getCurrentQueueSerial() const { return mCurrentQueueSerial; }
private:
bool isValidWorkerThread(Context *context) const;
......@@ -276,12 +300,19 @@ class TaskProcessor : angle::NonCopyable
PersistentCommandPool mPrimaryCommandPool;
std::thread::id mThreadId;
// Queue serial management.
AtomicSerialFactory mQueueSerialFactory;
Serial mLastCompletedQueueSerial;
Serial mLastSubmittedQueueSerial;
Serial mCurrentQueueSerial;
// Track present info
std::mutex mSwapchainStatusMutex;
std::condition_variable mSwapchainStatusCondition;
std::map<VkSwapchainKHR, VkResult> mSwapchainStatus;
};
// TODO(jmadill): Give this the same API as CommandQueue. b/172704839
class CommandProcessor : public Context
{
public:
......@@ -307,8 +338,11 @@ class CommandProcessor : public Context
// Used by main thread to wait for worker thread to complete all outstanding work.
void waitForWorkComplete(Context *context);
Serial getLastCompletedQueueSerial();
Serial getLastSubmittedQueueSerial();
Serial getCurrentQueueSerial();
Serial getLastSubmittedSerial();
Serial reserveSubmitSerial();
// Wait until desired serial has been processed.
void finishToSerial(Context *context, Serial serial);
......@@ -353,10 +387,7 @@ class CommandProcessor : public Context
PrimaryCommandBuffer mPrimaryCommandBuffer;
TaskProcessor mTaskProcessor;
AtomicSerialFactory mQueueSerialFactory;
std::mutex mCommandProcessorQueueSerialMutex;
Serial mCommandProcessorLastSubmittedSerial;
Serial mCommandProcessorCurrentQueueSerial;
std::mutex mQueueSerialMutex;
mutable std::mutex mErrorMutex;
std::queue<Error> mErrors;
......
......@@ -517,7 +517,7 @@ void ContextVk::onDestroy(const gl::Context *context)
mCommandPool.destroy(device);
// This will clean up any outstanding buffer allocations
(void)mRenderer->cleanupGarbage(false);
(void)mRenderer->clearAllGarbage(this);
}
angle::Result ContextVk::getIncompleteTexture(const gl::Context *context,
......
......@@ -47,7 +47,7 @@ void DisplayVk::terminate()
mRenderer->reloadVolkIfNeeded();
ASSERT(mRenderer);
mRenderer->onDestroy();
mRenderer->onDestroy(this);
}
egl::Error DisplayVk::makeCurrent(egl::Display * /*display*/,
......
......@@ -64,8 +64,6 @@ constexpr uint32_t kPipelineCacheVkUpdatePeriod = 60;
// version of Vulkan.
constexpr uint32_t kPreferredVulkanAPIVersion = VK_API_VERSION_1_1;
constexpr bool kOutputVmaStatsString = false;
angle::vk::ICD ChooseICDFromAttribs(const egl::AttributeMap &attribs)
{
#if !defined(ANGLE_PLATFORM_ANDROID)
......@@ -465,8 +463,6 @@ RendererVk::RendererVk()
mMinImportedHostPointerAlignment(1),
mDefaultUniformBufferSize(kPreferredDefaultUniformBufferSize),
mDevice(VK_NULL_HANDLE),
mLastCompletedQueueSerial(mQueueSerialFactory.generate()),
mCurrentQueueSerial(mQueueSerialFactory.generate()),
mDeviceLost(false),
mPipelineCacheVkUpdateTimeout(kPipelineCacheVkUpdatePeriod),
mPipelineCacheDirty(false),
......@@ -504,15 +500,8 @@ void RendererVk::releaseSharedResources(vk::ResourceUseList *resourceList)
resourceList->releaseResourceUses();
}
void RendererVk::onDestroy()
void RendererVk::onDestroy(vk::Context *context)
{
if (getFeatures().commandProcessor.enabled)
{
// Shutdown worker thread
mCommandProcessor.shutdown(&mCommandProcessorThread);
}
mCommandQueue.destroy(mDevice);
// Force all commands to finish by flushing all queues.
for (VkQueue queue : mQueues)
{
......@@ -522,13 +511,19 @@ void RendererVk::onDestroy()
}
}
// Then assign an infinite "last completed" serial to force garbage to delete.
if (getFeatures().commandProcessor.enabled)
{
std::lock_guard<std::mutex> lock(mQueueSerialMutex);
mLastCompletedQueueSerial = Serial::Infinite();
// Shutdown worker thread
mCommandProcessor.shutdown(&mCommandProcessorThread);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
mCommandQueue.destroy(this);
}
(void)cleanupGarbage(true);
// Assigns an infinite "last completed" serial to force garbage to delete.
(void)cleanupGarbage(Serial::Infinite());
ASSERT(!hasSharedGarbage());
for (PendingOneOffCommands &pending : mPendingOneOffCommands)
......@@ -588,10 +583,6 @@ void RendererVk::onDestroy()
void RendererVk::notifyDeviceLost()
{
{
std::lock_guard<std::mutex> lock(mQueueSerialMutex);
mLastCompletedQueueSerial = getLastSubmittedQueueSerial();
}
mDeviceLost = true;
mDisplay->notifyDeviceLost();
}
......@@ -2242,38 +2233,6 @@ void RendererVk::outputVmaStatString()
mAllocator.freeStatsString(statsString);
}
angle::Result RendererVk::queueSubmit(vk::Context *context,
egl::ContextPriority priority,
const VkSubmitInfo &submitInfo,
vk::ResourceUseList &&resourceUseList,
const vk::Fence *fence,
Serial *serialOut)
{
if (kOutputVmaStatsString)
{
outputVmaStatString();
}
ASSERT(!getFeatures().commandProcessor.enabled);
{
std::lock_guard<decltype(mQueueMutex)> lock(mQueueMutex);
std::lock_guard<std::mutex> serialLock(mQueueSerialMutex);
VkFence handle = fence ? fence->getHandle() : VK_NULL_HANDLE;
ANGLE_VK_TRY(context, vkQueueSubmit(mQueues[priority], 1, &submitInfo, handle));
resourceUseList.releaseResourceUsesAndUpdateSerials(mCurrentQueueSerial);
*serialOut = mCurrentQueueSerial;
mLastSubmittedQueueSerial = mCurrentQueueSerial;
mCurrentQueueSerial = mQueueSerialFactory.generate();
}
ANGLE_TRY(cleanupGarbage(false));
return angle::Result::Continue;
}
angle::Result RendererVk::queueSubmitOneOff(vk::Context *context,
vk::PrimaryCommandBuffer &&primary,
egl::ContextPriority priority,
......@@ -2282,10 +2241,16 @@ angle::Result RendererVk::queueSubmitOneOff(vk::Context *context,
{
ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::queueSubmitOneOff");
Serial submitQueueSerial;
if (getFeatures().commandProcessor.enabled)
{
std::lock_guard<std::mutex> commandQueueLock(mCommandQueueMutex);
submitQueueSerial = mCommandProcessor.reserveSubmitSerial();
vk::CommandProcessorTask oneOffQueueSubmit;
oneOffQueueSubmit.initOneOffQueueSubmit(primary.getHandle(), priority, fence);
oneOffQueueSubmit.initOneOffQueueSubmit(primary.getHandle(), priority, fence,
submitQueueSerial);
queueCommand(context, &oneOffQueueSubmit);
// TODO: https://issuetracker.google.com/170312581 - should go away with improved fence
// management
......@@ -2293,20 +2258,32 @@ angle::Result RendererVk::queueSubmitOneOff(vk::Context *context,
{
waitForCommandProcessorIdle(context);
}
*serialOut = getLastSubmittedQueueSerial();
}
else
{
std::lock_guard<std::mutex> commandQueueLock(mCommandQueueMutex);
std::lock_guard<std::mutex> queueLock(mQueueMutex);
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
if (primary.valid())
{
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = primary.ptr();
}
submitQueueSerial = mCommandQueue.reserveSubmitSerial();
ANGLE_TRY(
queueSubmit(context, priority, submitInfo, vk::ResourceUseList(), fence, serialOut));
mCommandQueue.queueSubmit(context, priority, submitInfo, fence, submitQueueSerial));
}
*serialOut = submitQueueSerial;
if (primary.valid())
{
mPendingOneOffCommands.push_back({*serialOut, std::move(primary)});
}
return angle::Result::Continue;
}
......@@ -2414,9 +2391,8 @@ bool RendererVk::hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlag
return IsMaskFlagSet(getFormatFeatureBits<features>(format, featureBits), featureBits);
}
angle::Result RendererVk::cleanupGarbage(bool block)
angle::Result RendererVk::cleanupGarbage(Serial lastCompletedQueueSerial)
{
Serial lastCompletedQueueSerial = getLastCompletedQueueSerial();
std::lock_guard<std::mutex> lock(mGarbageMutex);
for (auto garbageIter = mSharedGarbage.begin(); garbageIter != mSharedGarbage.end();)
......@@ -2457,15 +2433,6 @@ uint64_t RendererVk::getMaxFenceWaitTimeNs() const
return kMaxFenceWaitTimeNs;
}
void RendererVk::onCompletedSerial(Serial serial)
{
std::lock_guard<std::mutex> lock(mQueueSerialMutex);
if (serial > mLastCompletedQueueSerial)
{
mLastCompletedQueueSerial = serial;
}
}
void RendererVk::setGlobalDebugAnnotator()
{
// If the vkCmd*DebugUtilsLabelEXT functions exist, and if the kEnableDebugMarkersVarName
......@@ -2581,29 +2548,39 @@ angle::Result RendererVk::submitFrame(vk::Context *context,
vk::GarbageList &&currentGarbage,
vk::CommandPool *commandPool)
{
Serial submitQueueSerial;
if (mFeatures.commandProcessor.enabled)
{
std::lock_guard<std::mutex> commandQueueLock(mCommandQueueMutex);
submitQueueSerial = mCommandProcessor.reserveSubmitSerial();
vk::CommandProcessorTask flushAndQueueSubmit;
flushAndQueueSubmit.initFlushAndQueueSubmit(
std::move(waitSemaphores), std::move(waitSemaphoreStageMasks), signalSemaphore,
contextPriority, std::move(currentGarbage), std::move(resourceUseList));
contextPriority, std::move(currentGarbage), submitQueueSerial);
commandProcessorSyncErrorsAndQueueCommand(context, &flushAndQueueSubmit);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
std::lock_guard<std::mutex> commandQueueLock(mCommandQueueMutex);
std::lock_guard<std::mutex> queueLock(mQueueMutex);
submitQueueSerial = mCommandQueue.reserveSubmitSerial();
vk::Shared<vk::Fence> submitFence;
ANGLE_TRY(newSharedFence(context, &submitFence));
ANGLE_TRY(mCommandQueue.submitFrame(context, contextPriority, waitSemaphores,
waitSemaphoreStageMasks, signalSemaphore,
std::move(submitFence), std::move(resourceUseList),
std::move(currentGarbage), commandPool));
ANGLE_TRY(mCommandQueue.submitFrame(
context, contextPriority, waitSemaphores, waitSemaphoreStageMasks, signalSemaphore,
std::move(submitFence), std::move(currentGarbage), commandPool, submitQueueSerial));
waitSemaphores.clear();
waitSemaphoreStageMasks.clear();
}
resourceUseList.releaseResourceUsesAndUpdateSerials(submitQueueSerial);
return angle::Result::Continue;
}
......@@ -2672,8 +2649,7 @@ angle::Result RendererVk::waitForSerialWithUserTimeout(vk::Context *context,
angle::Result RendererVk::finish(vk::Context *context)
{
ANGLE_TRY(finishToSerial(context, mLastSubmittedQueueSerial));
return angle::Result::Continue;
return finishToSerial(context, getLastSubmittedQueueSerial());
}
angle::Result RendererVk::checkCompletedCommands(vk::Context *context)
......
......@@ -83,7 +83,7 @@ class RendererVk : angle::NonCopyable
const char *wsiLayer);
// Reload volk vk* function ptrs if needed for an already initialized RendererVk
void reloadVolkIfNeeded() const;
void onDestroy();
void onDestroy(vk::Context *context);
void notifyDeviceLost();
bool isDeviceLost() const;
......@@ -172,12 +172,6 @@ class RendererVk : angle::NonCopyable
}
// Queue submit that originates from the main thread
angle::Result queueSubmit(vk::Context *context,
egl::ContextPriority priority,
const VkSubmitInfo &submitInfo,
vk::ResourceUseList &&resourceList,
const vk::Fence *fence,
Serial *serialOut);
VkResult queuePresent(egl::ContextPriority priority, const VkPresentInfoKHR &presentInfo);
// This command buffer should be submitted immediately via queueSubmitOneOff.
......@@ -246,25 +240,38 @@ class RendererVk : angle::NonCopyable
{
return mCommandProcessor.getCurrentQueueSerial();
}
std::lock_guard<std::mutex> lock(mQueueSerialMutex);
return mCurrentQueueSerial;
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
return mCommandQueue.getCurrentQueueSerial();
}
}
ANGLE_INLINE Serial getLastSubmittedQueueSerial()
{
if (getFeatures().commandProcessor.enabled)
{
return mCommandProcessor.getLastSubmittedSerial();
return mCommandProcessor.getLastSubmittedQueueSerial();
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
return mCommandQueue.getLastSubmittedQueueSerial();
}
std::lock_guard<std::mutex> lock(mQueueSerialMutex);
return mLastSubmittedQueueSerial;
}
ANGLE_INLINE Serial getLastCompletedQueueSerial()
{
std::lock_guard<std::mutex> lock(mQueueSerialMutex);
return mLastCompletedQueueSerial;
if (mFeatures.commandProcessor.enabled)
{
return mCommandProcessor.getLastCompletedQueueSerial();
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
return mCommandQueue.getLastCompletedQueueSerial();
}
}
void onCompletedSerial(Serial serial);
VkResult getLastPresentResult(VkSwapchainKHR swapchain)
{
......@@ -301,7 +308,7 @@ class RendererVk : angle::NonCopyable
void outputVmaStatString();
angle::Result cleanupGarbage(bool block);
angle::Result cleanupGarbage(Serial lastCompletedQueueSerial);
angle::Result submitFrame(vk::Context *context,
egl::ContextPriority contextPriority,
......@@ -396,14 +403,8 @@ class RendererVk : angle::NonCopyable
VkDeviceSize mMinImportedHostPointerAlignment;
uint32_t mDefaultUniformBufferSize;
VkDevice mDevice;
AtomicSerialFactory mQueueSerialFactory;
AtomicSerialFactory mShaderSerialFactory;
std::mutex mQueueSerialMutex;
Serial mLastCompletedQueueSerial;
Serial mLastSubmittedQueueSerial;
Serial mCurrentQueueSerial;
bool mDeviceLost;
std::mutex mFenceRecyclerMutex;
......
......@@ -202,28 +202,9 @@ angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int
retain(&contextVk->getResourceUseList());
if (renderer->getFeatures().commandProcessor.enabled)
{
CommandProcessorTask oneOffQueueSubmit;
oneOffQueueSubmit.initOneOffQueueSubmit(VK_NULL_HANDLE, contextVk->getPriority(),
&fence.get());
renderer->queueCommand(contextVk, &oneOffQueueSubmit);
// TODO: https://issuetracker.google.com/170312581 - wait for now
if (renderer->getFeatures().asynchronousCommandProcessing.enabled)
{
ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelperNativeFence::initializeWithFd");
renderer->waitForCommandProcessorIdle(contextVk);
}
}
else
{
Serial serialOut;
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
ANGLE_TRY(renderer->queueSubmit(contextVk, contextVk->getPriority(), submitInfo,
vk::ResourceUseList(), &fence.get(), &serialOut));
}
ANGLE_TRY(renderer->queueSubmitOneOff(contextVk, vk::PrimaryCommandBuffer(),
contextVk->getPriority(), &fence.get(), &serialOut));
VkFenceGetFdInfoKHR fenceGetFdInfo = {};
fenceGetFdInfo.sType = VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR;
......
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