Commit e6a302a0 by Jamie Madill Committed by Commit Bot

Vulkan: Move vk::CommandQueue to RendererVk.

This consolidates most of the command processor vs queue logic in one place. It also has a number of incidental changes related to fences: - syncs now do not store a shared fence. instead they call command apis to wait for a particular serial with a timeout. this is not yet fully implemented in CommandProcessor. - surface swap history stores a serial instead of a fence. because the RendererVk class stores the command batches, we no longer have to do messy things with ContextVk. - it is no longer possible to ask for a wait on a serial that isn't in the command queue. Also adds mutex synchronization around the RendererVk methods. Bug: angleproject:5217 Bug: b/172704839 Change-Id: I5faf0e24bb6ede79a927ab149b80bfa8baca4620 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2524548 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent aead51e3
...@@ -114,7 +114,7 @@ void CommandProcessorTask::initTask() ...@@ -114,7 +114,7 @@ void CommandProcessorTask::initTask()
// CommandProcessorTask implementation // CommandProcessorTask implementation
void CommandProcessorTask::initProcessCommands(ContextVk *contextVk, void CommandProcessorTask::initProcessCommands(ContextVk *contextVk,
CommandBufferHelper *commandBuffer, CommandBufferHelper *commandBuffer,
RenderPass *renderPass) const RenderPass *renderPass)
{ {
mTask = CustomTask::ProcessCommands; mTask = CustomTask::ProcessCommands;
mContextVk = contextVk; mContextVk = contextVk;
...@@ -562,19 +562,6 @@ angle::Result TaskProcessor::submitFrame(Context *context, ...@@ -562,19 +562,6 @@ angle::Result TaskProcessor::submitFrame(Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
Shared<Fence> TaskProcessor::getLastSubmittedFenceWithLock(VkDevice device) const
{
Shared<Fence> fence;
std::lock_guard<std::mutex> inFlightLock(mInFlightCommandsMutex);
if (!mInFlightCommands.empty())
{
fence.copy(device, mInFlightCommands.back().fence);
}
return fence;
}
angle::Result TaskProcessor::queueSubmit(Context *context, angle::Result TaskProcessor::queueSubmit(Context *context,
VkQueue queue, VkQueue queue,
const VkSubmitInfo &submitInfo, const VkSubmitInfo &submitInfo,
...@@ -926,21 +913,6 @@ void CommandProcessor::shutdown(std::thread *commandProcessorThread) ...@@ -926,21 +913,6 @@ void CommandProcessor::shutdown(std::thread *commandProcessorThread)
} }
} }
// Return the fence for the last submit. This may mean waiting on the worker to process tasks to
// actually get to the last submit
Shared<Fence> CommandProcessor::getLastSubmittedFence(const Context *context) const
{
ANGLE_TRACE_EVENT0("gpu.angle", "CommandProcessor::getLastSubmittedFence");
std::unique_lock<std::mutex> lock(mWorkerMutex);
if (context->getRenderer()->getFeatures().asynchronousCommandProcessing.enabled)
{
mWorkerIdleCondition.wait(lock, [this] { return (mTasks.empty() && mWorkerThreadIdle); });
}
// Worker thread is idle and command queue is empty so good to continue
return mTaskProcessor.getLastSubmittedFenceWithLock(getDevice());
}
Serial CommandProcessor::getLastSubmittedSerial() Serial CommandProcessor::getLastSubmittedSerial()
{ {
std::lock_guard<std::mutex> lock(mCommandProcessorQueueSerialMutex); std::lock_guard<std::mutex> lock(mCommandProcessorQueueSerialMutex);
...@@ -1165,9 +1137,9 @@ void CommandQueue::handleDeviceLost(RendererVk *renderer) ...@@ -1165,9 +1137,9 @@ void CommandQueue::handleDeviceLost(RendererVk *renderer)
mInFlightCommands.clear(); mInFlightCommands.clear();
} }
bool CommandQueue::hasInFlightCommands() const bool CommandQueue::allInFlightCommandsAreAfterSerial(Serial serial) const
{ {
return !mInFlightCommands.empty(); return mInFlightCommands.empty() || mInFlightCommands[0].serial > serial;
} }
angle::Result CommandQueue::finishToSerial(Context *context, Serial finishSerial, uint64_t timeout) angle::Result CommandQueue::finishToSerial(Context *context, Serial finishSerial, uint64_t timeout)
...@@ -1186,15 +1158,7 @@ angle::Result CommandQueue::finishToSerial(Context *context, Serial finishSerial ...@@ -1186,15 +1158,7 @@ angle::Result CommandQueue::finishToSerial(Context *context, Serial finishSerial
size_t finishedCount = 0; size_t finishedCount = 0;
while (finishedCount < mInFlightCommands.size() && while (finishedCount < mInFlightCommands.size() &&
mInFlightCommands[finishedCount].serial < finishSerial) mInFlightCommands[finishedCount].serial <= finishSerial)
{
finishedCount++;
}
// This heuristic attempts to increase chances of success for shared resource scenarios.
// Ultimately as long as fences are managed by ContextVk there are edge case bugs here.
// TODO: http://anglebug.com/5217: fix this bug by moving it submit into RendererVk.
if (finishedCount < mInFlightCommands.size())
{ {
finishedCount++; finishedCount++;
} }
...@@ -1213,7 +1177,10 @@ angle::Result CommandQueue::finishToSerial(Context *context, Serial finishSerial ...@@ -1213,7 +1177,10 @@ angle::Result CommandQueue::finishToSerial(Context *context, Serial finishSerial
ANGLE_VK_TRY(context, status); ANGLE_VK_TRY(context, status);
// Clean up finished batches. // Clean up finished batches.
return retireFinishedCommands(context, finishedCount); ANGLE_TRY(retireFinishedCommands(context, finishedCount));
ASSERT(allInFlightCommandsAreAfterSerial(finishSerial));
return angle::Result::Continue;
} }
angle::Result CommandQueue::submitFrame( angle::Result CommandQueue::submitFrame(
...@@ -1222,9 +1189,9 @@ angle::Result CommandQueue::submitFrame( ...@@ -1222,9 +1189,9 @@ angle::Result CommandQueue::submitFrame(
const std::vector<VkSemaphore> &waitSemaphores, const std::vector<VkSemaphore> &waitSemaphores,
const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks, const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks,
const Semaphore *signalSemaphore, const Semaphore *signalSemaphore,
const Shared<Fence> &sharedFence, Shared<Fence> &&sharedFence,
ResourceUseList *resourceList, ResourceUseList &&resourceList,
GarbageList *currentGarbage, GarbageList &&currentGarbage,
CommandPool *commandPool) CommandPool *commandPool)
{ {
// Start an empty primary buffer if we have an empty submit. // Start an empty primary buffer if we have an empty submit.
...@@ -1243,14 +1210,14 @@ angle::Result CommandQueue::submitFrame( ...@@ -1243,14 +1210,14 @@ angle::Result CommandQueue::submitFrame(
DeviceScoped<CommandBatch> scopedBatch(device); DeviceScoped<CommandBatch> scopedBatch(device);
CommandBatch &batch = scopedBatch.get(); CommandBatch &batch = scopedBatch.get();
batch.fence.copy(device, sharedFence); batch.fence = std::move(sharedFence);
ANGLE_TRY(renderer->queueSubmit(context, priority, submitInfo, resourceList, &batch.fence.get(), ANGLE_TRY(renderer->queueSubmit(context, priority, submitInfo, std::move(resourceList),
&batch.serial)); &batch.fence.get(), &batch.serial));
if (!currentGarbage->empty()) if (!currentGarbage.empty())
{ {
mGarbageQueue.emplace_back(std::move(*currentGarbage), batch.serial); mGarbageQueue.emplace_back(std::move(currentGarbage), batch.serial);
} }
// Store the primary CommandBuffer and command pool used for secondary CommandBuffers // Store the primary CommandBuffer and command pool used for secondary CommandBuffers
...@@ -1272,17 +1239,52 @@ angle::Result CommandQueue::submitFrame( ...@@ -1272,17 +1239,52 @@ angle::Result CommandQueue::submitFrame(
return angle::Result::Continue; return angle::Result::Continue;
} }
Shared<Fence> CommandQueue::getLastSubmittedFence(const Context *context) const angle::Result CommandQueue::waitForSerialWithUserTimeout(vk::Context *context,
Serial serial,
uint64_t timeout,
VkResult *result)
{ {
ASSERT(!context->getRenderer()->getFeatures().commandProcessor.enabled); // No in-flight work. This indicates the serial is already complete.
if (mInFlightCommands.empty())
{
*result = VK_SUCCESS;
return angle::Result::Continue;
}
Shared<Fence> fence; // Serial is already complete.
if (!mInFlightCommands.empty()) if (serial < mInFlightCommands[0].serial)
{ {
fence.copy(context->getDevice(), mInFlightCommands.back().fence); *result = VK_SUCCESS;
return angle::Result::Continue;
} }
return fence; size_t batchIndex = 0;
while (batchIndex != mInFlightCommands.size() && mInFlightCommands[batchIndex].serial < serial)
{
batchIndex++;
}
// Serial is not yet submitted. This is undefined behaviour, so we can do anything.
if (batchIndex >= mInFlightCommands.size())
{
WARN() << "Waiting on an unsubmitted serial.";
*result = VK_TIMEOUT;
return angle::Result::Continue;
}
ASSERT(serial == mInFlightCommands[batchIndex].serial);
vk::Fence &fence = mInFlightCommands[batchIndex].fence.get();
ASSERT(fence.valid());
*result = fence.wait(context->getDevice(), timeout);
// Don't trigger an error on timeout.
if (*result != VK_TIMEOUT)
{
ANGLE_VK_TRY(context, *result);
}
return angle::Result::Continue;
} }
angle::Result CommandQueue::ensurePrimaryCommandBufferValid(Context *context) angle::Result CommandQueue::ensurePrimaryCommandBufferValid(Context *context)
......
...@@ -65,7 +65,7 @@ class CommandProcessorTask ...@@ -65,7 +65,7 @@ class CommandProcessorTask
void initProcessCommands(ContextVk *contextVk, void initProcessCommands(ContextVk *contextVk,
CommandBufferHelper *commandBuffer, CommandBufferHelper *commandBuffer,
RenderPass *renderPass); const RenderPass *renderPass);
void initPresent(egl::ContextPriority priority, VkPresentInfoKHR &presentInfo); void initPresent(egl::ContextPriority priority, VkPresentInfoKHR &presentInfo);
...@@ -104,7 +104,7 @@ class CommandProcessorTask ...@@ -104,7 +104,7 @@ class CommandProcessorTask
const VkCommandBuffer &getOneOffCommandBufferVk() const { return mOneOffCommandBufferVk; } const VkCommandBuffer &getOneOffCommandBufferVk() const { return mOneOffCommandBufferVk; }
const Fence *getOneOffFence() { return mOneOffFence; } const Fence *getOneOffFence() { return mOneOffFence; }
const VkPresentInfoKHR &getPresentInfo() const { return mPresentInfo; } const VkPresentInfoKHR &getPresentInfo() const { return mPresentInfo; }
RenderPass *getRenderPass() const { return mRenderPass; } const RenderPass *getRenderPass() const { return mRenderPass; }
CommandBufferHelper *getCommandBuffer() const { return mCommandBuffer; } CommandBufferHelper *getCommandBuffer() const { return mCommandBuffer; }
ContextVk *getContextVk() const { return mContextVk; } ContextVk *getContextVk() const { return mContextVk; }
...@@ -115,7 +115,7 @@ class CommandProcessorTask ...@@ -115,7 +115,7 @@ class CommandProcessorTask
// ProcessCommands // ProcessCommands
ContextVk *mContextVk; ContextVk *mContextVk;
RenderPass *mRenderPass; const RenderPass *mRenderPass;
CommandBufferHelper *mCommandBuffer; CommandBufferHelper *mCommandBuffer;
// Flush data // Flush data
...@@ -172,8 +172,6 @@ class CommandQueue final : angle::NonCopyable ...@@ -172,8 +172,6 @@ class CommandQueue final : angle::NonCopyable
void destroy(VkDevice device); void destroy(VkDevice device);
void handleDeviceLost(RendererVk *renderer); void handleDeviceLost(RendererVk *renderer);
bool hasInFlightCommands() const;
void clearAllGarbage(RendererVk *renderer); void clearAllGarbage(RendererVk *renderer);
angle::Result finishToSerial(Context *context, Serial finishSerial, uint64_t timeout); angle::Result finishToSerial(Context *context, Serial finishSerial, uint64_t timeout);
...@@ -183,12 +181,15 @@ class CommandQueue final : angle::NonCopyable ...@@ -183,12 +181,15 @@ class CommandQueue final : angle::NonCopyable
const std::vector<VkSemaphore> &waitSemaphores, const std::vector<VkSemaphore> &waitSemaphores,
const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks, const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks,
const Semaphore *signalSemaphore, const Semaphore *signalSemaphore,
const Shared<Fence> &sharedFence, Shared<Fence> &&sharedFence,
ResourceUseList *resourceList, ResourceUseList &&resourceList,
GarbageList *currentGarbage, GarbageList &&currentGarbage,
CommandPool *commandPool); CommandPool *commandPool);
Shared<Fence> getLastSubmittedFence(const Context *context) const; angle::Result waitForSerialWithUserTimeout(vk::Context *context,
Serial serial,
uint64_t timeout,
VkResult *result);
// Check to see which batches have finished completion (forward progress for // Check to see which batches have finished completion (forward progress for
// mLastCompletedQueueSerial, for example for when the application busy waits on a query // mLastCompletedQueueSerial, for example for when the application busy waits on a query
...@@ -213,6 +214,8 @@ class CommandQueue final : angle::NonCopyable ...@@ -213,6 +214,8 @@ class CommandQueue final : angle::NonCopyable
angle::Result releasePrimaryCommandBuffer(Context *context, angle::Result releasePrimaryCommandBuffer(Context *context,
PrimaryCommandBuffer &&commandBuffer); PrimaryCommandBuffer &&commandBuffer);
bool allInFlightCommandsAreAfterSerial(Serial serial) const;
GarbageQueue mGarbageQueue; GarbageQueue mGarbageQueue;
std::vector<CommandBatch> mInFlightCommands; std::vector<CommandBatch> mInFlightCommands;
...@@ -252,8 +255,6 @@ class TaskProcessor : angle::NonCopyable ...@@ -252,8 +255,6 @@ class TaskProcessor : angle::NonCopyable
const VkSubmitInfo &submitInfo, const VkSubmitInfo &submitInfo,
const Fence *fence); const Fence *fence);
Shared<Fence> getLastSubmittedFenceWithLock(VkDevice device) const;
void handleDeviceLost(Context *context); void handleDeviceLost(Context *context);
// Called by CommandProcessor to process any completed work // Called by CommandProcessor to process any completed work
...@@ -320,7 +321,6 @@ class CommandProcessor : public Context ...@@ -320,7 +321,6 @@ class CommandProcessor : public Context
// Wait until desired serial has been processed. // Wait until desired serial has been processed.
void finishToSerial(Context *context, Serial serial); void finishToSerial(Context *context, Serial serial);
Shared<Fence> getLastSubmittedFence(const Context *context) const;
void handleDeviceLost(); void handleDeviceLost();
bool hasPendingError() const bool hasPendingError() const
......
...@@ -507,14 +507,11 @@ void ContextVk::onDestroy(const gl::Context *context) ...@@ -507,14 +507,11 @@ void ContextVk::onDestroy(const gl::Context *context)
ASSERT(mCurrentGarbage.empty()); ASSERT(mCurrentGarbage.empty());
mCommandQueue.destroy(device);
mRenderer->releaseSharedResources(&mResourceUseList); mRenderer->releaseSharedResources(&mResourceUseList);
mUtils.destroy(mRenderer); mUtils.destroy(mRenderer);
mRenderPassCache.destroy(device); mRenderPassCache.destroy(device);
mSubmitFence.reset(device);
mShaderLibrary.destroy(device); mShaderLibrary.destroy(device);
mGpuEventQueryPool.destroy(device); mGpuEventQueryPool.destroy(device);
mCommandPool.destroy(device); mCommandPool.destroy(device);
...@@ -600,8 +597,6 @@ angle::Result ContextVk::initialize() ...@@ -600,8 +597,6 @@ angle::Result ContextVk::initialize()
buffer.init(mRenderer, kVertexBufferUsage, 1, kDefaultBufferSize, true); buffer.init(mRenderer, kVertexBufferUsage, 1, kDefaultBufferSize, true);
} }
ANGLE_TRY(mCommandQueue.init(this));
#if ANGLE_ENABLE_VULKAN_GPU_TRACE_EVENTS #if ANGLE_ENABLE_VULKAN_GPU_TRACE_EVENTS
angle::PlatformMethods *platform = ANGLEPlatformCurrent(); angle::PlatformMethods *platform = ANGLEPlatformCurrent();
ASSERT(platform); ASSERT(platform);
...@@ -1500,24 +1495,6 @@ void ContextVk::addOverlayUsedBuffersCount(vk::CommandBufferHelper *commandBuffe ...@@ -1500,24 +1495,6 @@ void ContextVk::addOverlayUsedBuffersCount(vk::CommandBufferHelper *commandBuffe
} }
} }
void ContextVk::commandProcessorSyncErrors()
{
while (mRenderer->hasPendingError())
{
vk::Error error = mRenderer->getAndClearPendingError();
if (error.mErrorCode != VK_SUCCESS)
{
handleError(error.mErrorCode, error.mFile, error.mFunction, error.mLine);
}
}
}
void ContextVk::commandProcessorSyncErrorsAndQueueCommand(vk::CommandProcessorTask *command)
{
commandProcessorSyncErrors();
mRenderer->queueCommand(this, command);
}
angle::Result ContextVk::submitFrame(const vk::Semaphore *signalSemaphore) angle::Result ContextVk::submitFrame(const vk::Semaphore *signalSemaphore)
{ {
if (mCurrentWindowSurface) if (mCurrentWindowSurface)
...@@ -1536,27 +1513,9 @@ angle::Result ContextVk::submitFrame(const vk::Semaphore *signalSemaphore) ...@@ -1536,27 +1513,9 @@ angle::Result ContextVk::submitFrame(const vk::Semaphore *signalSemaphore)
dumpCommandStreamDiagnostics(); dumpCommandStreamDiagnostics();
} }
if (mRenderer->getFeatures().commandProcessor.enabled) ANGLE_TRY(mRenderer->submitFrame(
{ this, mContextPriority, std::move(mWaitSemaphores), std::move(mWaitSemaphoreStageMasks),
vk::CommandProcessorTask flushAndQueueSubmit; signalSemaphore, std::move(mResourceUseList), std::move(mCurrentGarbage), &mCommandPool));
flushAndQueueSubmit.initFlushAndQueueSubmit(
std::move(mWaitSemaphores), std::move(mWaitSemaphoreStageMasks), signalSemaphore,
mContextPriority, std::move(mCurrentGarbage), std::move(mResourceUseList));
commandProcessorSyncErrorsAndQueueCommand(&flushAndQueueSubmit);
}
else
{
ANGLE_TRY(ensureSubmitFenceInitialized());
ANGLE_TRY(mCommandQueue.submitFrame(this, mContextPriority, mWaitSemaphores,
mWaitSemaphoreStageMasks, signalSemaphore, mSubmitFence,
&mResourceUseList, &mCurrentGarbage, &mCommandPool));
// Make sure a new fence is created for the next submission.
mRenderer->resetSharedFence(&mSubmitFence);
mWaitSemaphores.clear();
mWaitSemaphoreStageMasks.clear();
}
onRenderPassFinished(); onRenderPassFinished();
mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits; mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits;
...@@ -1885,31 +1844,14 @@ void ContextVk::clearAllGarbage() ...@@ -1885,31 +1844,14 @@ void ContextVk::clearAllGarbage()
garbage.destroy(mRenderer); garbage.destroy(mRenderer);
} }
mCurrentGarbage.clear(); mCurrentGarbage.clear();
if (mRenderer->getFeatures().commandProcessor.enabled) mRenderer->clearAllGarbage(this);
{
// Issue command to CommandProcessor to ensure all work is complete, which will return any
// garbage items as well.
mRenderer->finishAllWork(this);
}
else
{
mCommandQueue.clearAllGarbage(mRenderer);
}
} }
void ContextVk::handleDeviceLost() void ContextVk::handleDeviceLost()
{ {
mOutsideRenderPassCommands->reset(); mOutsideRenderPassCommands->reset();
mRenderPassCommands->reset(); mRenderPassCommands->reset();
mRenderer->handleDeviceLost();
if (mRenderer->getFeatures().commandProcessor.enabled)
{
mRenderer->handleDeviceLost();
}
else
{
mCommandQueue.handleDeviceLost(mRenderer);
}
clearAllGarbage(); clearAllGarbage();
mRenderer->notifyDeviceLost(); mRenderer->notifyDeviceLost();
...@@ -4136,16 +4078,7 @@ angle::Result ContextVk::finishImpl() ...@@ -4136,16 +4078,7 @@ angle::Result ContextVk::finishImpl()
ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::finishImpl"); ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::finishImpl");
ANGLE_TRY(flushImpl(nullptr)); ANGLE_TRY(flushImpl(nullptr));
ANGLE_TRY(mRenderer->finish(this));
if (mRenderer->getFeatures().commandProcessor.enabled)
{
ANGLE_TRY(finishToSerial(getLastSubmittedQueueSerial()));
}
else
{
ANGLE_TRY(finishToSerial(getLastSubmittedQueueSerial()));
ASSERT(!mCommandQueue.hasInFlightCommands());
}
clearAllGarbage(); clearAllGarbage();
...@@ -4186,26 +4119,12 @@ bool ContextVk::isSerialInUse(Serial serial) const ...@@ -4186,26 +4119,12 @@ bool ContextVk::isSerialInUse(Serial serial) const
angle::Result ContextVk::checkCompletedCommands() angle::Result ContextVk::checkCompletedCommands()
{ {
if (mRenderer->getFeatures().commandProcessor.enabled) return mRenderer->checkCompletedCommands(this);
{
// TODO: https://issuetracker.google.com/169788986 - would be better if we could just wait
// for the work we need but that requires QueryHelper to use the actual serial for the
// query.
mRenderer->checkCompletedCommands(this);
return angle::Result::Continue;
}
return mCommandQueue.checkCompletedCommands(this);
} }
angle::Result ContextVk::finishToSerial(Serial serial) angle::Result ContextVk::finishToSerial(Serial serial)
{ {
if (mRenderer->getFeatures().commandProcessor.enabled) return mRenderer->finishToSerial(this, serial);
{
mRenderer->finishToSerial(this, serial);
return angle::Result::Continue;
}
return mCommandQueue.finishToSerial(this, serial, mRenderer->getMaxFenceWaitTimeNs());
} }
angle::Result ContextVk::getCompatibleRenderPass(const vk::RenderPassDesc &desc, angle::Result ContextVk::getCompatibleRenderPass(const vk::RenderPassDesc &desc,
...@@ -4223,35 +4142,6 @@ angle::Result ContextVk::getRenderPassWithOps(const vk::RenderPassDesc &desc, ...@@ -4223,35 +4142,6 @@ angle::Result ContextVk::getRenderPassWithOps(const vk::RenderPassDesc &desc,
return mRenderPassCache.getRenderPassWithOps(this, desc, ops, renderPassOut); return mRenderPassCache.getRenderPassWithOps(this, desc, ops, renderPassOut);
} }
angle::Result ContextVk::ensureSubmitFenceInitialized()
{
if (mSubmitFence.isReferenced())
{
return angle::Result::Continue;
}
return mRenderer->newSharedFence(this, &mSubmitFence);
}
angle::Result ContextVk::getNextSubmitFence(vk::Shared<vk::Fence> *sharedFenceOut)
{
ASSERT(!getRenderer()->getFeatures().commandProcessor.enabled);
ANGLE_TRY(ensureSubmitFenceInitialized());
ASSERT(!sharedFenceOut->isReferenced());
sharedFenceOut->copy(getDevice(), mSubmitFence);
return angle::Result::Continue;
}
vk::Shared<vk::Fence> ContextVk::getLastSubmittedFence() const
{
if (mRenderer->getFeatures().commandProcessor.enabled)
{
return mRenderer->getLastSubmittedFence(this);
}
return mCommandQueue.getLastSubmittedFence(this);
}
angle::Result ContextVk::getTimestamp(uint64_t *timestampOut) angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
{ {
// The intent of this function is to query the timestamp without stalling the GPU. // The intent of this function is to query the timestamp without stalling the GPU.
...@@ -4646,19 +4536,13 @@ angle::Result ContextVk::flushCommandsAndEndRenderPass() ...@@ -4646,19 +4536,13 @@ angle::Result ContextVk::flushCommandsAndEndRenderPass()
ANGLE_TRY(getRenderPassWithOps(mRenderPassCommands->getRenderPassDesc(), ANGLE_TRY(getRenderPassWithOps(mRenderPassCommands->getRenderPassDesc(),
mRenderPassCommands->getAttachmentOps(), &renderPass)); mRenderPassCommands->getAttachmentOps(), &renderPass));
if (mRenderer->getFeatures().commandProcessor.enabled) ANGLE_TRY(mRenderer->flushRenderPassCommands(this, *renderPass, &mRenderPassCommands));
// TODO(jmadill): Manage in RendererVk. b/172678125
if (getFeatures().commandProcessor.enabled)
{ {
mRenderPassCommands->markClosed();
vk::CommandProcessorTask flushToPrimary;
flushToPrimary.initProcessCommands(this, mRenderPassCommands, renderPass);
ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::flushInsideRenderPassCommands");
commandProcessorSyncErrorsAndQueueCommand(&flushToPrimary);
getNextAvailableCommandBuffer(&mRenderPassCommands, true); getNextAvailableCommandBuffer(&mRenderPassCommands, true);
} }
else
{
ANGLE_TRY(mCommandQueue.flushRenderPassCommands(this, *renderPass, mRenderPassCommands));
}
if (mGpuEventsEnabled) if (mGpuEventsEnabled)
{ {
...@@ -4791,19 +4675,14 @@ angle::Result ContextVk::flushOutsideRenderPassCommands() ...@@ -4791,19 +4675,14 @@ angle::Result ContextVk::flushOutsideRenderPassCommands()
mOutsideRenderPassCommands->addCommandDiagnostics(this); mOutsideRenderPassCommands->addCommandDiagnostics(this);
} }
if (mRenderer->getFeatures().commandProcessor.enabled) ANGLE_TRY(mRenderer->flushOutsideRPCommands(this, &mOutsideRenderPassCommands));
// TODO(jmadill): Manage in RendererVk. b/172678125
if (getFeatures().commandProcessor.enabled)
{ {
mOutsideRenderPassCommands->markClosed();
vk::CommandProcessorTask flushToPrimary;
flushToPrimary.initProcessCommands(this, mOutsideRenderPassCommands, nullptr);
ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::flushOutsideRenderPassCommands");
commandProcessorSyncErrorsAndQueueCommand(&flushToPrimary);
getNextAvailableCommandBuffer(&mOutsideRenderPassCommands, false); getNextAvailableCommandBuffer(&mOutsideRenderPassCommands, false);
} }
else
{
ANGLE_TRY(mCommandQueue.flushOutsideRPCommands(this, mOutsideRenderPassCommands));
}
mPerfCounters.flushedOutsideRenderPassCommandBuffers++; mPerfCounters.flushedOutsideRenderPassCommandBuffers++;
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -386,10 +386,6 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -386,10 +386,6 @@ class ContextVk : public ContextImpl, public vk::Context
const vk::AttachmentOpsArray &ops, const vk::AttachmentOpsArray &ops,
vk::RenderPass **renderPassOut); vk::RenderPass **renderPassOut);
// Get (or allocate) the fence that will be signaled on next submission.
angle::Result getNextSubmitFence(vk::Shared<vk::Fence> *sharedFenceOut);
vk::Shared<vk::Fence> getLastSubmittedFence() const;
vk::ShaderLibrary &getShaderLibrary() { return mShaderLibrary; } vk::ShaderLibrary &getShaderLibrary() { return mShaderLibrary; }
UtilsVk &getUtils() { return mUtils; } UtilsVk &getUtils() { return mUtils; }
...@@ -522,6 +518,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -522,6 +518,7 @@ class ContextVk : public ContextImpl, public vk::Context
vk::CommandBuffer &getOutsideRenderPassCommandBuffer() vk::CommandBuffer &getOutsideRenderPassCommandBuffer()
{ {
ASSERT(!mOutsideRenderPassCommands->hasRenderPass());
return mOutsideRenderPassCommands->getCommandBuffer(); return mOutsideRenderPassCommands->getCommandBuffer();
} }
...@@ -595,10 +592,6 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -595,10 +592,6 @@ class ContextVk : public ContextImpl, public vk::Context
void updateOverlayOnPresent(); void updateOverlayOnPresent();
void addOverlayUsedBuffersCount(vk::CommandBufferHelper *commandBuffer); void addOverlayUsedBuffersCount(vk::CommandBufferHelper *commandBuffer);
// Sync any errors from the command processor
void commandProcessorSyncErrors();
// Sync any error from worker thread and queue up next command for processing
void commandProcessorSyncErrorsAndQueueCommand(vk::CommandProcessorTask *command);
// When worker thread completes, it releases command buffers back to context queue // When worker thread completes, it releases command buffers back to context queue
void recycleCommandBuffer(vk::CommandBufferHelper *commandBuffer); void recycleCommandBuffer(vk::CommandBufferHelper *commandBuffer);
...@@ -884,7 +877,6 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -884,7 +877,6 @@ class ContextVk : public ContextImpl, public vk::Context
bool shouldEmulateSeamfulCubeMapSampling() const; bool shouldEmulateSeamfulCubeMapSampling() const;
bool shouldUseOldRewriteStructSamplers() const; bool shouldUseOldRewriteStructSamplers() const;
void clearAllGarbage(); void clearAllGarbage();
angle::Result ensureSubmitFenceInitialized();
bool hasRecordedCommands(); bool hasRecordedCommands();
void dumpCommandStreamDiagnostics(); void dumpCommandStreamDiagnostics();
angle::Result flushOutsideRenderPassCommands(); angle::Result flushOutsideRenderPassCommands();
...@@ -1035,20 +1027,10 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -1035,20 +1027,10 @@ class ContextVk : public ContextImpl, public vk::Context
// We use a single pool for recording commands. We also keep a free list for pool recycling. // We use a single pool for recording commands. We also keep a free list for pool recycling.
vk::CommandPool mCommandPool; vk::CommandPool mCommandPool;
// TODO: This can be killed once threading is enabled https://issuetracker.google.com/153666475
vk::CommandQueue mCommandQueue;
vk::GarbageList mCurrentGarbage; vk::GarbageList mCurrentGarbage;
RenderPassCache mRenderPassCache; RenderPassCache mRenderPassCache;
// mSubmitFence is the fence that's going to be signaled at the next submission. This is used
// to support SyncVk objects, which may outlive the context (as EGLSync objects).
//
// TODO(geofflang): this is in preparation for moving RendererVk functionality to ContextVk, and
// is otherwise unnecessary as the SyncVk objects don't actually outlive the renderer currently.
// http://anglebug.com/2701
vk::Shared<vk::Fence> mSubmitFence;
// We have a queue of CommandBufferHelpers (CBHs) that is drawn from for the two active command // We have a queue of CommandBufferHelpers (CBHs) that is drawn from for the two active command
// buffers in the main thread. The two active command buffers are the inside and outside // buffers in the main thread. The two active command buffers are the inside and outside
// RenderPass command buffers. // RenderPass command buffers.
......
...@@ -511,6 +511,7 @@ void RendererVk::onDestroy() ...@@ -511,6 +511,7 @@ void RendererVk::onDestroy()
// Shutdown worker thread // Shutdown worker thread
mCommandProcessor.shutdown(&mCommandProcessorThread); mCommandProcessor.shutdown(&mCommandProcessorThread);
} }
mCommandQueue.destroy(mDevice);
// Force all commands to finish by flushing all queues. // Force all commands to finish by flushing all queues.
for (VkQueue queue : mQueues) for (VkQueue queue : mQueues)
...@@ -929,6 +930,10 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk, ...@@ -929,6 +930,10 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
ANGLE_TRY(mCommandProcessor.initTaskProcessor(displayVk)); ANGLE_TRY(mCommandProcessor.initTaskProcessor(displayVk));
} }
} }
else
{
ANGLE_TRY(mCommandQueue.init(displayVk));
}
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -2240,7 +2245,7 @@ void RendererVk::outputVmaStatString() ...@@ -2240,7 +2245,7 @@ void RendererVk::outputVmaStatString()
angle::Result RendererVk::queueSubmit(vk::Context *context, angle::Result RendererVk::queueSubmit(vk::Context *context,
egl::ContextPriority priority, egl::ContextPriority priority,
const VkSubmitInfo &submitInfo, const VkSubmitInfo &submitInfo,
vk::ResourceUseList *resourceList, vk::ResourceUseList &&resourceUseList,
const vk::Fence *fence, const vk::Fence *fence,
Serial *serialOut) Serial *serialOut)
{ {
...@@ -2257,10 +2262,8 @@ angle::Result RendererVk::queueSubmit(vk::Context *context, ...@@ -2257,10 +2262,8 @@ angle::Result RendererVk::queueSubmit(vk::Context *context,
VkFence handle = fence ? fence->getHandle() : VK_NULL_HANDLE; VkFence handle = fence ? fence->getHandle() : VK_NULL_HANDLE;
ANGLE_VK_TRY(context, vkQueueSubmit(mQueues[priority], 1, &submitInfo, handle)); ANGLE_VK_TRY(context, vkQueueSubmit(mQueues[priority], 1, &submitInfo, handle));
if (resourceList) resourceUseList.releaseResourceUsesAndUpdateSerials(mCurrentQueueSerial);
{
resourceList->releaseResourceUsesAndUpdateSerials(mCurrentQueueSerial);
}
*serialOut = mCurrentQueueSerial; *serialOut = mCurrentQueueSerial;
mLastSubmittedQueueSerial = mCurrentQueueSerial; mLastSubmittedQueueSerial = mCurrentQueueSerial;
mCurrentQueueSerial = mQueueSerialFactory.generate(); mCurrentQueueSerial = mQueueSerialFactory.generate();
...@@ -2294,13 +2297,13 @@ angle::Result RendererVk::queueSubmitOneOff(vk::Context *context, ...@@ -2294,13 +2297,13 @@ angle::Result RendererVk::queueSubmitOneOff(vk::Context *context,
} }
else else
{ {
VkSubmitInfo submitInfo = {}; VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = primary.ptr(); submitInfo.pCommandBuffers = primary.ptr();
ANGLE_TRY(queueSubmit(context, priority, submitInfo, nullptr, fence, serialOut)); ANGLE_TRY(
queueSubmit(context, priority, submitInfo, vk::ResourceUseList(), fence, serialOut));
} }
mPendingOneOffCommands.push_back({*serialOut, std::move(primary)}); mPendingOneOffCommands.push_back({*serialOut, std::move(primary)});
...@@ -2586,4 +2589,188 @@ angle::Result RendererVk::getCommandBufferOneOff(vk::Context *context, ...@@ -2586,4 +2589,188 @@ angle::Result RendererVk::getCommandBufferOneOff(vk::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
void RendererVk::commandProcessorSyncErrors(vk::Context *context)
{
while (hasPendingError())
{
vk::Error error = getAndClearPendingError();
if (error.mErrorCode != VK_SUCCESS)
{
context->handleError(error.mErrorCode, error.mFile, error.mFunction, error.mLine);
}
}
}
void RendererVk::commandProcessorSyncErrorsAndQueueCommand(vk::Context *context,
vk::CommandProcessorTask *command)
{
commandProcessorSyncErrors(context);
queueCommand(context, command);
}
angle::Result RendererVk::submitFrame(vk::Context *context,
egl::ContextPriority contextPriority,
std::vector<VkSemaphore> &&waitSemaphores,
std::vector<VkPipelineStageFlags> &&waitSemaphoreStageMasks,
const vk::Semaphore *signalSemaphore,
vk::ResourceUseList &&resourceUseList,
vk::GarbageList &&currentGarbage,
vk::CommandPool *commandPool)
{
if (mFeatures.commandProcessor.enabled)
{
vk::CommandProcessorTask flushAndQueueSubmit;
flushAndQueueSubmit.initFlushAndQueueSubmit(
std::move(waitSemaphores), std::move(waitSemaphoreStageMasks), signalSemaphore,
contextPriority, std::move(currentGarbage), std::move(resourceUseList));
commandProcessorSyncErrorsAndQueueCommand(context, &flushAndQueueSubmit);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
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));
waitSemaphores.clear();
waitSemaphoreStageMasks.clear();
}
return angle::Result::Continue;
}
void RendererVk::clearAllGarbage(vk::Context *context)
{
if (mFeatures.commandProcessor.enabled)
{
// Issue command to CommandProcessor to ensure all work is complete, which will return any
// garbage items as well.
finishAllWork(context);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
mCommandQueue.clearAllGarbage(this);
}
}
void RendererVk::handleDeviceLost()
{
if (mFeatures.commandProcessor.enabled)
{
mCommandProcessor.handleDeviceLost();
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
mCommandQueue.handleDeviceLost(this);
}
}
angle::Result RendererVk::finishToSerial(vk::Context *context, Serial serial)
{
if (mFeatures.commandProcessor.enabled)
{
mCommandProcessor.finishToSerial(context, serial);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
ANGLE_TRY(mCommandQueue.finishToSerial(context, serial, getMaxFenceWaitTimeNs()));
}
return angle::Result::Continue;
}
angle::Result RendererVk::waitForSerialWithUserTimeout(vk::Context *context,
Serial serial,
uint64_t timeout,
VkResult *result)
{
ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::waitForSerialWithUserTimeout");
if (mFeatures.commandProcessor.enabled)
{
// TODO: https://issuetracker.google.com/170312581 - Wait with timeout.
mCommandProcessor.finishToSerial(context, serial);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
ANGLE_TRY(mCommandQueue.waitForSerialWithUserTimeout(context, serial, timeout, result));
}
return angle::Result::Continue;
}
angle::Result RendererVk::finish(vk::Context *context)
{
ANGLE_TRY(finishToSerial(context, mLastSubmittedQueueSerial));
return angle::Result::Continue;
}
angle::Result RendererVk::checkCompletedCommands(vk::Context *context)
{
if (mFeatures.commandProcessor.enabled)
{
// TODO: https://issuetracker.google.com/169788986 - would be better if we could just wait
// for the work we need but that requires QueryHelper to use the actual serial for the
// query.
mCommandProcessor.checkCompletedCommands(context);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
ANGLE_TRY(mCommandQueue.checkCompletedCommands(context));
}
return angle::Result::Continue;
}
angle::Result RendererVk::flushRenderPassCommands(ContextVk *contextVk,
const vk::RenderPass &renderPass,
vk::CommandBufferHelper **renderPassCommands)
{
ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::flushRenderPassCommands");
if (mFeatures.commandProcessor.enabled)
{
(*renderPassCommands)->markClosed();
vk::CommandProcessorTask flushToPrimary;
flushToPrimary.initProcessCommands(contextVk, *renderPassCommands, &renderPass);
commandProcessorSyncErrorsAndQueueCommand(contextVk, &flushToPrimary);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
ANGLE_TRY(
mCommandQueue.flushRenderPassCommands(contextVk, renderPass, *renderPassCommands));
}
return angle::Result::Continue;
}
angle::Result RendererVk::flushOutsideRPCommands(ContextVk *contextVk,
vk::CommandBufferHelper **outsideRPCommands)
{
ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::flushOutsideRPCommands");
if (mFeatures.commandProcessor.enabled)
{
(*outsideRPCommands)->markClosed();
vk::CommandProcessorTask flushToPrimary;
flushToPrimary.initProcessCommands(contextVk, *outsideRPCommands, nullptr);
commandProcessorSyncErrorsAndQueueCommand(contextVk, &flushToPrimary);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
ANGLE_TRY(mCommandQueue.flushOutsideRPCommands(contextVk, *outsideRPCommands));
}
return angle::Result::Continue;
}
} // namespace rx } // namespace rx
...@@ -175,7 +175,7 @@ class RendererVk : angle::NonCopyable ...@@ -175,7 +175,7 @@ class RendererVk : angle::NonCopyable
angle::Result queueSubmit(vk::Context *context, angle::Result queueSubmit(vk::Context *context,
egl::ContextPriority priority, egl::ContextPriority priority,
const VkSubmitInfo &submitInfo, const VkSubmitInfo &submitInfo,
vk::ResourceUseList *resourceList, vk::ResourceUseList &&resourceList,
const vk::Fence *fence, const vk::Fence *fence,
Serial *serialOut); Serial *serialOut);
angle::Result queueWaitIdle(vk::Context *context, egl::ContextPriority priority); angle::Result queueWaitIdle(vk::Context *context, egl::ContextPriority priority);
...@@ -230,12 +230,6 @@ class RendererVk : angle::NonCopyable ...@@ -230,12 +230,6 @@ class RendererVk : angle::NonCopyable
} }
} }
vk::Shared<vk::Fence> getLastSubmittedFence(const vk::Context *context) const
{
return mCommandProcessor.getLastSubmittedFence(context);
}
void handleDeviceLost() { mCommandProcessor.handleDeviceLost(); }
angle::Result getPipelineCache(vk::PipelineCache **pipelineCache); angle::Result getPipelineCache(vk::PipelineCache **pipelineCache);
void onNewGraphicsPipeline() void onNewGraphicsPipeline()
{ {
...@@ -298,16 +292,6 @@ class RendererVk : angle::NonCopyable ...@@ -298,16 +292,6 @@ class RendererVk : angle::NonCopyable
mCommandProcessor.waitForWorkComplete(context); mCommandProcessor.waitForWorkComplete(context);
} }
void finishToSerial(vk::Context *context, Serial serial)
{
mCommandProcessor.finishToSerial(context, serial);
}
void checkCompletedCommands(vk::Context *context)
{
mCommandProcessor.checkCompletedCommands(context);
}
void finishAllWork(vk::Context *context) { mCommandProcessor.finishAllWork(context); } void finishAllWork(vk::Context *context) { mCommandProcessor.finishAllWork(context); }
VkQueue getVkQueue(egl::ContextPriority priority) const { return mQueues[priority]; } VkQueue getVkQueue(egl::ContextPriority priority) const { return mQueues[priority]; }
...@@ -321,6 +305,32 @@ class RendererVk : angle::NonCopyable ...@@ -321,6 +305,32 @@ class RendererVk : angle::NonCopyable
angle::Result cleanupGarbage(bool block); angle::Result cleanupGarbage(bool block);
angle::Result submitFrame(vk::Context *context,
egl::ContextPriority contextPriority,
std::vector<VkSemaphore> &&waitSemaphores,
std::vector<VkPipelineStageFlags> &&waitSemaphoreStageMasks,
const vk::Semaphore *signalSemaphore,
vk::ResourceUseList &&resourceUseList,
vk::GarbageList &&currentGarbage,
vk::CommandPool *commandPool);
void clearAllGarbage(vk::Context *context);
void handleDeviceLost();
angle::Result finishToSerial(vk::Context *context, Serial serial);
angle::Result waitForSerialWithUserTimeout(vk::Context *context,
Serial serial,
uint64_t timeout,
VkResult *result);
angle::Result finish(vk::Context *context);
angle::Result checkCompletedCommands(vk::Context *context);
// TODO(jmadill): Use vk::Context instead of ContextVk. b/172704839
angle::Result flushRenderPassCommands(ContextVk *contextVk,
const vk::RenderPass &renderPass,
vk::CommandBufferHelper **renderPassCommands);
angle::Result flushOutsideRPCommands(ContextVk *contextVk,
vk::CommandBufferHelper **outsideRPCommands);
private: private:
angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex); angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex);
void ensureCapsInitialized() const; void ensureCapsInitialized() const;
...@@ -340,6 +350,12 @@ class RendererVk : angle::NonCopyable ...@@ -340,6 +350,12 @@ class RendererVk : angle::NonCopyable
template <VkFormatFeatureFlags VkFormatProperties::*features> template <VkFormatFeatureFlags VkFormatProperties::*features>
bool hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits) const; bool hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits) const;
// Sync any errors from the command processor
void commandProcessorSyncErrors(vk::Context *context);
// Sync any error from worker thread and queue up next command for processing
void commandProcessorSyncErrorsAndQueueCommand(vk::Context *context,
vk::CommandProcessorTask *command);
egl::Display *mDisplay; egl::Display *mDisplay;
mutable bool mCapsInitialized; mutable bool mCapsInitialized;
...@@ -434,6 +450,9 @@ class RendererVk : angle::NonCopyable ...@@ -434,6 +450,9 @@ class RendererVk : angle::NonCopyable
}; };
std::deque<PendingOneOffCommands> mPendingOneOffCommands; std::deque<PendingOneOffCommands> mPendingOneOffCommands;
std::mutex mCommandQueueMutex;
vk::CommandQueue mCommandQueue;
// Command Processor Thread // Command Processor Thread
vk::CommandProcessor mCommandProcessor; vk::CommandProcessor mCommandProcessor;
std::thread mCommandProcessorThread; std::thread mCommandProcessorThread;
......
...@@ -482,25 +482,6 @@ SwapchainImage::SwapchainImage(SwapchainImage &&other) ...@@ -482,25 +482,6 @@ SwapchainImage::SwapchainImage(SwapchainImage &&other)
presentHistory(std::move(other.presentHistory)), presentHistory(std::move(other.presentHistory)),
currentPresentHistoryIndex(other.currentPresentHistoryIndex) currentPresentHistoryIndex(other.currentPresentHistoryIndex)
{} {}
SwapHistory::SwapHistory() = default;
SwapHistory::~SwapHistory() = default;
void SwapHistory::destroy(RendererVk *renderer)
{
renderer->resetSharedFence(&sharedFence);
}
angle::Result SwapHistory::waitFence(ContextVk *contextVk)
{
ASSERT(sharedFence.isReferenced());
// TODO: https://issuetracker.google.com/170312581 - This wait needs to be synchronized with
// worker thread
ANGLE_VK_TRY(contextVk, sharedFence.get().wait(contextVk->getDevice(),
std::numeric_limits<uint64_t>::max()));
return angle::Result::Continue;
}
} // namespace impl } // namespace impl
using namespace impl; using namespace impl;
...@@ -550,11 +531,6 @@ void WindowSurfaceVk::destroy(const egl::Display *display) ...@@ -550,11 +531,6 @@ void WindowSurfaceVk::destroy(const egl::Display *display)
destroySwapChainImages(displayVk); destroySwapChainImages(displayVk);
for (SwapHistory &swap : mSwapHistory)
{
swap.destroy(renderer);
}
if (mSwapchain) if (mSwapchain)
{ {
vkDestroySwapchainKHR(device, mSwapchain, nullptr); vkDestroySwapchainKHR(device, mSwapchain, nullptr);
...@@ -1296,16 +1272,10 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk, ...@@ -1296,16 +1272,10 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
// Throttle the submissions to avoid getting too far ahead of the GPU. // Throttle the submissions to avoid getting too far ahead of the GPU.
SwapHistory &swap = mSwapHistory[mCurrentSwapHistoryIndex]; Serial *swapSerial = &mSwapHistory[mCurrentSwapHistoryIndex];
{ {
ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::present: Throttle CPU"); ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::present: Throttle CPU");
if (swap.sharedFence.isReferenced()) ANGLE_TRY(renderer->finishToSerial(contextVk, *swapSerial));
{
// TODO: https://issuetracker.google.com/170312581 - This wait needs to be sure to
// happen after work has submitted
ANGLE_TRY(swap.waitFence(contextVk));
swap.destroy(renderer);
}
} }
SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex]; SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex];
...@@ -1425,10 +1395,8 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk, ...@@ -1425,10 +1395,8 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
presentInfo.pNext = &presentRegions; presentInfo.pNext = &presentRegions;
} }
// Update the swap history for this presentation // TODO(jmadill): Fix potential serial race. b/172704839
// TODO: https://issuetracker.google.com/issues/170312581 - this will force us to flush worker *swapSerial = renderer->getLastSubmittedQueueSerial();
// queue to get the fence.
swap.sharedFence = contextVk->getLastSubmittedFence();
ASSERT(!mAcquireImageSemaphore.valid()); ASSERT(!mAcquireImageSemaphore.valid());
++mCurrentSwapHistoryIndex; ++mCurrentSwapHistoryIndex;
......
...@@ -117,21 +117,6 @@ class OffscreenSurfaceVk : public SurfaceVk ...@@ -117,21 +117,6 @@ class OffscreenSurfaceVk : public SurfaceVk
// Data structures used in WindowSurfaceVk // Data structures used in WindowSurfaceVk
namespace impl namespace impl
{ {
// The submission fence of the context used to throttle the CPU.
struct SwapHistory : angle::NonCopyable
{
SwapHistory();
SwapHistory(SwapHistory &&other) = delete;
SwapHistory &operator=(SwapHistory &&other) = delete;
~SwapHistory();
void destroy(RendererVk *renderer);
angle::Result waitFence(ContextVk *contextVk);
// Fence associated with the last submitted work to render to this swapchain image.
vk::Shared<vk::Fence> sharedFence;
};
static constexpr size_t kSwapHistorySize = 2; static constexpr size_t kSwapHistorySize = 2;
// Old swapchain and associated present semaphores that need to be scheduled for destruction when // Old swapchain and associated present semaphores that need to be scheduled for destruction when
...@@ -317,9 +302,9 @@ class WindowSurfaceVk : public SurfaceVk ...@@ -317,9 +302,9 @@ class WindowSurfaceVk : public SurfaceVk
VkSurfaceTransformFlagBitsKHR mEmulatedPreTransform; VkSurfaceTransformFlagBitsKHR mEmulatedPreTransform;
VkCompositeAlphaFlagBitsKHR mCompositeAlpha; VkCompositeAlphaFlagBitsKHR mCompositeAlpha;
// A circular buffer that stores the submission fence of the context on every swap. The CPU is // A circular buffer that stores the serial of the submission fence of the context on every
// throttled by waiting for the 2nd previous serial to finish. // swap. The CPU is throttled by waiting for the 2nd previous serial to finish.
std::array<impl::SwapHistory, impl::kSwapHistorySize> mSwapHistory; std::array<Serial, impl::kSwapHistorySize> mSwapHistory;
size_t mCurrentSwapHistoryIndex; size_t mCurrentSwapHistoryIndex;
// The previous swapchain which needs to be scheduled for destruction when appropriate. This // The previous swapchain which needs to be scheduled for destruction when appropriate. This
......
...@@ -39,7 +39,6 @@ void SyncHelper::releaseToRenderer(RendererVk *renderer) ...@@ -39,7 +39,6 @@ void SyncHelper::releaseToRenderer(RendererVk *renderer)
ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelper::releaseToRenderer"); ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelper::releaseToRenderer");
renderer->waitForCommandProcessorIdle(nullptr); renderer->waitForCommandProcessorIdle(nullptr);
} }
mFence.reset(renderer->getDevice());
} }
angle::Result SyncHelper::initialize(ContextVk *contextVk) angle::Result SyncHelper::initialize(ContextVk *contextVk)
...@@ -55,20 +54,6 @@ angle::Result SyncHelper::initialize(ContextVk *contextVk) ...@@ -55,20 +54,6 @@ angle::Result SyncHelper::initialize(ContextVk *contextVk)
DeviceScoped<Event> event(device); DeviceScoped<Event> event(device);
ANGLE_VK_TRY(contextVk, event.get().init(device, eventCreateInfo)); ANGLE_VK_TRY(contextVk, event.get().init(device, eventCreateInfo));
// TODO: https://issuetracker.google.com/170312581 - For now wait for worker thread to finish
// then get next fence from renderer
if (contextVk->getRenderer()->getFeatures().commandProcessor.enabled)
{
if (contextVk->getRenderer()->getFeatures().asynchronousCommandProcessing.enabled)
{
contextVk->getRenderer()->waitForCommandProcessorIdle(contextVk);
}
ANGLE_TRY(contextVk->getRenderer()->getNextSubmitFence(&mFence, false));
}
else
{
ANGLE_TRY(contextVk->getNextSubmitFence(&mFence));
}
mEvent = event.release(); mEvent = event.release();
...@@ -110,19 +95,18 @@ angle::Result SyncHelper::clientWait(Context *context, ...@@ -110,19 +95,18 @@ angle::Result SyncHelper::clientWait(Context *context,
ANGLE_TRY(contextVk->flushImpl(nullptr)); ANGLE_TRY(contextVk->flushImpl(nullptr));
} }
// TODO: https://issuetracker.google.com/170312581 - If we are using worker need to wait for the // Undefined behaviour. Early exit.
// commands to be issued before waiting on the fence. if (usedInRecordedCommands())
if (renderer->getFeatures().asynchronousCommandProcessing.enabled)
{ {
ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelper::clientWait"); WARN() << "Waiting on a sync that is not flushed";
renderer->waitForCommandProcessorIdle(contextVk); *outResult = VK_TIMEOUT;
return angle::Result::Continue;
} }
// Wait on the fence that's expected to be signaled on the first vkQueueSubmit after ASSERT(mUse.getSerial().valid());
// `initialize` was called. The first fence is the fence created to signal this sync.
ASSERT(mFence.get().valid()); VkResult status = VK_SUCCESS;
// TODO: https://issuetracker.google.com/170312581 - Wait could be command to worker ANGLE_TRY(renderer->waitForSerialWithUserTimeout(context, mUse.getSerial(), timeout, &status));
VkResult status = mFence.get().wait(renderer->getDevice(), timeout);
// Check for errors, but don't consider timeout as such. // Check for errors, but don't consider timeout as such.
if (status != VK_TIMEOUT) if (status != VK_TIMEOUT)
...@@ -238,7 +222,7 @@ angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int ...@@ -238,7 +222,7 @@ angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
ANGLE_TRY(renderer->queueSubmit(contextVk, contextVk->getPriority(), submitInfo, ANGLE_TRY(renderer->queueSubmit(contextVk, contextVk->getPriority(), submitInfo,
nullptr, &fence.get(), &serialOut)); vk::ResourceUseList(), &fence.get(), &serialOut));
} }
VkFenceGetFdInfoKHR fenceGetFdInfo = {}; VkFenceGetFdInfoKHR fenceGetFdInfo = {};
......
...@@ -55,9 +55,6 @@ class SyncHelper : public vk::Resource ...@@ -55,9 +55,6 @@ class SyncHelper : public vk::Resource
// The vkEvent that's signaled on `init` and can be waited on in `serverWait`, or queried with // The vkEvent that's signaled on `init` and can be waited on in `serverWait`, or queried with
// `getStatus`. // `getStatus`.
Event mEvent; Event mEvent;
// The fence is signaled once the CB including the `init` signal is executed.
// `clientWait` waits on this fence.
Shared<Fence> mFence;
}; };
// Implementation of sync types: EGLSync(EGL_SYNC_ANDROID_NATIVE_FENCE_ANDROID). // Implementation of sync types: EGLSync(EGL_SYNC_ANDROID_NATIVE_FENCE_ANDROID).
......
...@@ -1105,6 +1105,8 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1105,6 +1105,8 @@ class CommandBufferHelper : angle::NonCopyable
const RenderPassDesc &getRenderPassDesc() const { return mRenderPassDesc; } const RenderPassDesc &getRenderPassDesc() const { return mRenderPassDesc; }
const AttachmentOpsArray &getAttachmentOps() const { return mAttachmentOps; } const AttachmentOpsArray &getAttachmentOps() const { return mAttachmentOps; }
bool hasRenderPass() const { return mIsRenderPassCommandBuffer; }
private: private:
bool onDepthStencilAccess(ResourceAccess access, bool onDepthStencilAccess(ResourceAccess access,
uint32_t *cmdCountInvalidated, uint32_t *cmdCountInvalidated,
......
...@@ -515,9 +515,10 @@ bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters ...@@ -515,9 +515,10 @@ bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters
switch (param.getRenderer()) switch (param.getRenderer())
{ {
case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
// Note that system info collection depends on Vulkan support.
return true; return true;
case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
// http://issuetracker.google.com/173004081
return !IsIntel() || param.eglParameters.asyncCommandQueueFeatureVulkan != EGL_TRUE;
default: default:
return false; return false;
} }
......
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