Commit 6a1fb047 by Jamie Madill Committed by Commit Bot

Vulkan: Align CommandQueue and TaskProcessor.

The intent is to merge these two classes and remove redundant code. Bug: b/172704839 Change-Id: I6eb66d7b4ddea3633b08df99464975cd59773b4e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2524550 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent a428487a
...@@ -21,41 +21,6 @@ constexpr size_t kInFlightCommandsLimit = 100u; ...@@ -21,41 +21,6 @@ constexpr size_t kInFlightCommandsLimit = 100u;
constexpr bool kOutputVmaStatsString = false; constexpr bool kOutputVmaStatsString = false;
void InitializeSubmitInfo(VkSubmitInfo *submitInfo, void InitializeSubmitInfo(VkSubmitInfo *submitInfo,
const PrimaryCommandBuffer &commandBuffer,
const std::vector<VkSemaphore> &waitSemaphores,
std::vector<VkPipelineStageFlags> *waitSemaphoreStageMasks,
const 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();
if (waitSemaphoreStageMasks->size() < waitSemaphores.size())
{
waitSemaphoreStageMasks->resize(waitSemaphores.size(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
}
submitInfo->waitSemaphoreCount = static_cast<uint32_t>(waitSemaphores.size());
submitInfo->pWaitSemaphores = waitSemaphores.data();
submitInfo->pWaitDstStageMask = waitSemaphoreStageMasks->data();
if (signalSemaphore)
{
submitInfo->signalSemaphoreCount = 1;
submitInfo->pSignalSemaphores = signalSemaphore->ptr();
}
else
{
submitInfo->signalSemaphoreCount = 0;
submitInfo->pSignalSemaphores = nullptr;
}
}
// TODO(jmadill): De-duplicate. b/172704839
void InitializeSubmitInfo(VkSubmitInfo *submitInfo,
const vk::PrimaryCommandBuffer &commandBuffer, const vk::PrimaryCommandBuffer &commandBuffer,
const std::vector<VkSemaphore> &waitSemaphores, const std::vector<VkSemaphore> &waitSemaphores,
const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks, const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks,
...@@ -291,6 +256,7 @@ TaskProcessor::~TaskProcessor() = default; ...@@ -291,6 +256,7 @@ TaskProcessor::~TaskProcessor() = default;
void TaskProcessor::destroy(VkDevice device) void TaskProcessor::destroy(VkDevice device)
{ {
mPrimaryCommandBuffer.destroy(device);
mPrimaryCommandPool.destroy(device); mPrimaryCommandPool.destroy(device);
ASSERT(mInFlightCommands.empty() && mGarbageQueue.empty()); ASSERT(mInFlightCommands.empty() && mGarbageQueue.empty());
} }
...@@ -305,21 +271,6 @@ angle::Result TaskProcessor::init(Context *context, std::thread::id threadId) ...@@ -305,21 +271,6 @@ angle::Result TaskProcessor::init(Context *context, std::thread::id threadId)
return angle::Result::Continue; return angle::Result::Continue;
} }
VkResult TaskProcessor::getLastAndClearPresentResult(VkSwapchainKHR swapchain)
{
std::unique_lock<std::mutex> lock(mSwapchainStatusMutex);
if (mSwapchainStatus.find(swapchain) == mSwapchainStatus.end())
{
// Wake when required swapchain status becomes available
mSwapchainStatusCondition.wait(lock, [this, swapchain] {
return mSwapchainStatus.find(swapchain) != mSwapchainStatus.end();
});
}
VkResult result = mSwapchainStatus[swapchain];
mSwapchainStatus.erase(swapchain);
return result;
}
angle::Result TaskProcessor::checkCompletedCommands(Context *context) angle::Result TaskProcessor::checkCompletedCommands(Context *context)
{ {
ANGLE_TRACE_EVENT0("gpu.angle", "TaskProcessor::checkCompletedCommands"); ANGLE_TRACE_EVENT0("gpu.angle", "TaskProcessor::checkCompletedCommands");
...@@ -343,7 +294,7 @@ angle::Result TaskProcessor::checkCompletedCommands(Context *context) ...@@ -343,7 +294,7 @@ angle::Result TaskProcessor::checkCompletedCommands(Context *context)
ANGLE_TRACE_EVENT0("gpu.angle", "command buffer recycling"); ANGLE_TRACE_EVENT0("gpu.angle", "command buffer recycling");
batch.commandPool.destroy(device); batch.commandPool.destroy(device);
ANGLE_TRY(releasePrimaryCommandBuffer(context, std::move(batch.primaryCommands))); ANGLE_TRY(mPrimaryCommandPool.collect(context, std::move(batch.primaryCommands)));
++finishedCount; ++finishedCount;
} }
...@@ -403,21 +354,25 @@ angle::Result TaskProcessor::releaseToCommandBatch(Context *context, ...@@ -403,21 +354,25 @@ angle::Result TaskProcessor::releaseToCommandBatch(Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result TaskProcessor::allocatePrimaryCommandBuffer(Context *context, angle::Result TaskProcessor::ensurePrimaryCommandBufferValid(Context *context)
PrimaryCommandBuffer *commandBufferOut)
{ {
ASSERT(isValidWorkerThread(context)); if (mPrimaryCommandBuffer.valid())
ANGLE_TRACE_EVENT0("gpu.angle", "TaskProcessor::allocatePrimaryCommandBuffer"); {
return mPrimaryCommandPool.allocate(context, commandBufferOut); return angle::Result::Continue;
} }
angle::Result TaskProcessor::releasePrimaryCommandBuffer(Context *context,
PrimaryCommandBuffer &&commandBuffer)
{
ASSERT(isValidWorkerThread(context)); ASSERT(isValidWorkerThread(context));
ANGLE_TRACE_EVENT0("gpu.angle", "TaskProcessor::releasePrimaryCommandBuffer"); ANGLE_TRACE_EVENT0("gpu.angle", "TaskProcessor::ensurePrimaryCommandBufferValid");
ASSERT(mPrimaryCommandPool.valid()); ANGLE_TRY(mPrimaryCommandPool.allocate(context, &mPrimaryCommandBuffer));
return mPrimaryCommandPool.collect(context, std::move(commandBuffer));
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
beginInfo.pInheritanceInfo = nullptr;
ANGLE_VK_TRY(context, mPrimaryCommandBuffer.begin(beginInfo));
return angle::Result::Continue;
} }
void TaskProcessor::handleDeviceLost(Context *context) void TaskProcessor::handleDeviceLost(Context *context)
...@@ -484,42 +439,37 @@ angle::Result TaskProcessor::finishToSerial(Context *context, Serial serial) ...@@ -484,42 +439,37 @@ angle::Result TaskProcessor::finishToSerial(Context *context, Serial serial)
return checkCompletedCommands(context); return checkCompletedCommands(context);
} }
VkResult TaskProcessor::present(VkQueue queue, const VkPresentInfoKHR &presentInfo) angle::Result TaskProcessor::submitFrame(
{ Context *context,
std::lock_guard<std::mutex> lock(mSwapchainStatusMutex); egl::ContextPriority priority,
ANGLE_TRACE_EVENT0("gpu.angle", "vkQueuePresentKHR"); const std::vector<VkSemaphore> &waitSemaphores,
VkResult result = vkQueuePresentKHR(queue, &presentInfo); const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks,
const Semaphore *signalSemaphore,
// Verify that we are presenting one and only one swapchain Shared<Fence> &&sharedFence,
ASSERT(presentInfo.swapchainCount == 1);
ASSERT(presentInfo.pResults == nullptr);
mSwapchainStatus[presentInfo.pSwapchains[0]] = result;
mSwapchainStatusCondition.notify_all();
return result;
}
angle::Result TaskProcessor::submitFrame(Context *context,
VkQueue queue,
const VkSubmitInfo &submitInfo,
const Shared<Fence> &sharedFence,
GarbageList *currentGarbage, GarbageList *currentGarbage,
CommandPool *commandPool, CommandPool *commandPool,
PrimaryCommandBuffer &&commandBuffer,
Serial submitQueueSerial) Serial submitQueueSerial)
{ {
ASSERT(isValidWorkerThread(context)); ASSERT(isValidWorkerThread(context));
ANGLE_TRACE_EVENT0("gpu.angle", "TaskProcessor::submitFrame"); ANGLE_TRACE_EVENT0("gpu.angle", "TaskProcessor::submitFrame");
// Start an empty primary buffer if we have an empty submit.
ANGLE_TRY(ensurePrimaryCommandBufferValid(context));
ANGLE_VK_TRY(context, mPrimaryCommandBuffer.end());
VkSubmitInfo submitInfo = {};
InitializeSubmitInfo(&submitInfo, mPrimaryCommandBuffer, waitSemaphores,
waitSemaphoreStageMasks, signalSemaphore);
VkDevice device = context->getDevice(); VkDevice device = context->getDevice();
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);
batch.serial = submitQueueSerial; batch.serial = submitQueueSerial;
ANGLE_TRY(queueSubmit(context, queue, submitInfo, &batch.fence.get(), batch.serial)); ANGLE_TRY(queueSubmit(context, priority, submitInfo, &batch.fence.get(), batch.serial));
if (!currentGarbage->empty()) if (!currentGarbage->empty())
{ {
...@@ -528,7 +478,8 @@ angle::Result TaskProcessor::submitFrame(Context *context, ...@@ -528,7 +478,8 @@ angle::Result TaskProcessor::submitFrame(Context *context,
// Store the primary CommandBuffer and command pool used for secondary CommandBuffers // Store the primary CommandBuffer and command pool used for secondary CommandBuffers
// in the in-flight list. // in the in-flight list.
ANGLE_TRY(releaseToCommandBatch(context, std::move(commandBuffer), commandPool, &batch)); ANGLE_TRY(
releaseToCommandBatch(context, std::move(mPrimaryCommandBuffer), commandPool, &batch));
mInFlightCommands.emplace_back(scopedBatch.release()); mInFlightCommands.emplace_back(scopedBatch.release());
...@@ -547,28 +498,31 @@ angle::Result TaskProcessor::submitFrame(Context *context, ...@@ -547,28 +498,31 @@ angle::Result TaskProcessor::submitFrame(Context *context,
} }
angle::Result TaskProcessor::queueSubmit(Context *context, angle::Result TaskProcessor::queueSubmit(Context *context,
VkQueue queue, egl::ContextPriority priority,
const VkSubmitInfo &submitInfo, const VkSubmitInfo &submitInfo,
const Fence *fence, const Fence *fence,
Serial submitQueueSerial) Serial submitQueueSerial)
{ {
RendererVk *renderer = context->getRenderer();
ASSERT(isValidWorkerThread(context)); ASSERT(isValidWorkerThread(context));
ANGLE_TRACE_EVENT0("gpu.angle", "TaskProcessor::queueSubmit"); ANGLE_TRACE_EVENT0("gpu.angle", "TaskProcessor::queueSubmit");
ASSERT((context->getRenderer()->getFeatures().asynchronousCommandProcessing.enabled == false) || ASSERT((renderer->getFeatures().asynchronousCommandProcessing.enabled == false) ||
std::this_thread::get_id() == mThreadId); std::this_thread::get_id() == mThreadId);
if (kOutputVmaStatsString) if (kOutputVmaStatsString)
{ {
context->getRenderer()->outputVmaStatString(); renderer->outputVmaStatString();
} }
// Don't need a QueueMutex since all queue accesses are serialized through the worker. // Don't need a QueueMutex since all queue accesses are serialized through the worker.
VkQueue queue = renderer->getVkQueue(priority);
VkFence handle = fence ? fence->getHandle() : VK_NULL_HANDLE; VkFence handle = fence ? fence->getHandle() : VK_NULL_HANDLE;
ANGLE_VK_TRY(context, vkQueueSubmit(queue, 1, &submitInfo, handle)); ANGLE_VK_TRY(context, vkQueueSubmit(queue, 1, &submitInfo, handle));
mLastSubmittedQueueSerial = submitQueueSerial; mLastSubmittedQueueSerial = submitQueueSerial;
// Now that we've submitted work, clean up RendererVk garbage // Now that we've submitted work, clean up RendererVk garbage
return context->getRenderer()->cleanupGarbage(mLastCompletedQueueSerial); return renderer->cleanupGarbage(mLastCompletedQueueSerial);
} }
bool TaskProcessor::isValidWorkerThread(Context *context) const bool TaskProcessor::isValidWorkerThread(Context *context) const
...@@ -584,6 +538,23 @@ Serial TaskProcessor::reserveSubmitSerial() ...@@ -584,6 +538,23 @@ Serial TaskProcessor::reserveSubmitSerial()
return returnSerial; return returnSerial;
} }
angle::Result TaskProcessor::flushOutsideRPCommands(Context *context,
CommandBufferHelper *outsideRPCommands)
{
ANGLE_TRY(ensurePrimaryCommandBufferValid(context));
return outsideRPCommands->flushToPrimary(context->getRenderer()->getFeatures(),
&mPrimaryCommandBuffer, nullptr);
}
angle::Result TaskProcessor::flushRenderPassCommands(Context *context,
const RenderPass &renderPass,
CommandBufferHelper *renderPassCommands)
{
ANGLE_TRY(ensurePrimaryCommandBufferValid(context));
return renderPassCommands->flushToPrimary(context->getRenderer()->getFeatures(),
&mPrimaryCommandBuffer, &renderPass);
}
void CommandProcessor::handleError(VkResult errorCode, void CommandProcessor::handleError(VkResult errorCode,
const char *file, const char *file,
const char *function, const char *function,
...@@ -644,7 +615,7 @@ void CommandProcessor::queueCommand(Context *context, CommandProcessorTask *task ...@@ -644,7 +615,7 @@ void CommandProcessor::queueCommand(Context *context, CommandProcessorTask *task
} }
else else
{ {
angle::Result result = processTask(context, task); angle::Result result = processTask(task);
if (ANGLE_UNLIKELY(IsError(result))) if (ANGLE_UNLIKELY(IsError(result)))
{ {
// TODO: Ignore error, similar to ANGLE_CONTEXT_TRY. // TODO: Ignore error, similar to ANGLE_CONTEXT_TRY.
...@@ -660,13 +631,6 @@ angle::Result CommandProcessor::initTaskProcessor(Context *context) ...@@ -660,13 +631,6 @@ angle::Result CommandProcessor::initTaskProcessor(Context *context)
// Initialization prior to work thread loop // Initialization prior to work thread loop
ANGLE_TRY(mTaskProcessor.init(context, std::this_thread::get_id())); ANGLE_TRY(mTaskProcessor.init(context, std::this_thread::get_id()));
// Allocate and begin primary command buffer // Allocate and begin primary command buffer
ANGLE_TRY(mTaskProcessor.allocatePrimaryCommandBuffer(context, &mPrimaryCommandBuffer));
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
beginInfo.pInheritanceInfo = nullptr;
ANGLE_VK_TRY(context, mPrimaryCommandBuffer.begin(beginInfo));
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -713,7 +677,7 @@ angle::Result CommandProcessor::processTasksImpl(bool *exitThread) ...@@ -713,7 +677,7 @@ angle::Result CommandProcessor::processTasksImpl(bool *exitThread)
mTasks.pop(); mTasks.pop();
lock.unlock(); lock.unlock();
ANGLE_TRY(processTask(this, &task)); ANGLE_TRY(processTask(&task));
if (task.getTaskCommand() == CustomTask::Exit) if (task.getTaskCommand() == CustomTask::Exit)
{ {
...@@ -729,51 +693,34 @@ angle::Result CommandProcessor::processTasksImpl(bool *exitThread) ...@@ -729,51 +693,34 @@ angle::Result CommandProcessor::processTasksImpl(bool *exitThread)
return angle::Result::Stop; return angle::Result::Stop;
} }
angle::Result CommandProcessor::processTask(Context *context, CommandProcessorTask *task) angle::Result CommandProcessor::processTask(CommandProcessorTask *task)
{ {
switch (task->getTaskCommand()) switch (task->getTaskCommand())
{ {
case CustomTask::Exit: case CustomTask::Exit:
{ {
ANGLE_TRY(mTaskProcessor.finishToSerial(context, Serial::Infinite())); ANGLE_TRY(mTaskProcessor.finishToSerial(this, Serial::Infinite()));
// Shutting down so cleanup // Shutting down so cleanup
mTaskProcessor.destroy(mRenderer->getDevice()); mTaskProcessor.destroy(mRenderer->getDevice());
mCommandPool.destroy(mRenderer->getDevice()); mCommandPool.destroy(mRenderer->getDevice());
mPrimaryCommandBuffer.destroy(mRenderer->getDevice());
break; break;
} }
case CustomTask::FlushAndQueueSubmit: case CustomTask::FlushAndQueueSubmit:
{ {
ANGLE_TRACE_EVENT0("gpu.angle", "processTask::FlushAndQueueSubmit"); ANGLE_TRACE_EVENT0("gpu.angle", "processTask::FlushAndQueueSubmit");
// End command buffer // End command buffer
ANGLE_VK_TRY(context, mPrimaryCommandBuffer.end());
// 1. Create submitInfo
VkSubmitInfo submitInfo = {};
InitializeSubmitInfo(&submitInfo, mPrimaryCommandBuffer, task->getWaitSemaphores(),
&task->getWaitSemaphoreStageMasks(), task->getSemaphore());
// 2. Get shared submit fence. It's possible there are other users of this fence that // Get shared submit fence. It's possible there are other users of this fence that
// must wait for the work to be submitted before waiting on the fence. Reset the fence // must wait for the work to be submitted before waiting on the fence. Reset the fence
// immediately so we are sure to get a fresh one next time. // immediately so we are sure to get a fresh one next time.
Shared<Fence> fence; Shared<Fence> fence;
ANGLE_TRY(mRenderer->getNextSubmitFence(&fence, true)); ANGLE_TRY(mRenderer->newSharedFence(this, &fence));
// 3. Call submitFrame() // Call submitFrame()
ANGLE_TRY(mTaskProcessor.submitFrame( ANGLE_TRY(mTaskProcessor.submitFrame(
context, getRenderer()->getVkQueue(task->getPriority()), submitInfo, fence, this, task->getPriority(), task->getWaitSemaphores(),
&task->getGarbage(), &mCommandPool, std::move(mPrimaryCommandBuffer), task->getWaitSemaphoreStageMasks(), task->getSemaphore(), std::move(fence),
task->getQueueSerial())); &task->getGarbage(), &mCommandPool, task->getQueueSerial()));
// 4. Allocate & begin new primary command buffer
ANGLE_TRY(mTaskProcessor.allocatePrimaryCommandBuffer(context, &mPrimaryCommandBuffer));
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
beginInfo.pInheritanceInfo = nullptr;
ANGLE_VK_TRY(context, mPrimaryCommandBuffer.begin(beginInfo));
// Free this local reference
getRenderer()->resetSharedFence(&fence);
ASSERT(task->getGarbage().empty()); ASSERT(task->getGarbage().empty());
break; break;
...@@ -791,21 +738,20 @@ angle::Result CommandProcessor::processTask(Context *context, CommandProcessorTa ...@@ -791,21 +738,20 @@ angle::Result CommandProcessor::processTask(Context *context, CommandProcessorTa
// TODO: https://issuetracker.google.com/issues/170328907 - vkQueueSubmit should be // TODO: https://issuetracker.google.com/issues/170328907 - vkQueueSubmit should be
// owned by TaskProcessor to ensure proper synchronization // owned by TaskProcessor to ensure proper synchronization
ANGLE_TRY(mTaskProcessor.queueSubmit( ANGLE_TRY(mTaskProcessor.queueSubmit(this, task->getPriority(), submitInfo,
context, getRenderer()->getVkQueue(task->getPriority()), submitInfo,
task->getOneOffFence(), task->getQueueSerial())); task->getOneOffFence(), task->getQueueSerial()));
ANGLE_TRY(mTaskProcessor.checkCompletedCommands(context)); ANGLE_TRY(mTaskProcessor.checkCompletedCommands(this));
break; break;
} }
case CustomTask::FinishToSerial: case CustomTask::FinishToSerial:
{ {
ANGLE_TRY(mTaskProcessor.finishToSerial(context, task->getQueueSerial())); ANGLE_TRY(mTaskProcessor.finishToSerial(this, task->getQueueSerial()));
break; break;
} }
case CustomTask::Present: case CustomTask::Present:
{ {
VkResult result = mTaskProcessor.present(getRenderer()->getVkQueue(task->getPriority()), VkResult result =
task->getPresentInfo()); present(getRenderer()->getVkQueue(task->getPriority()), task->getPresentInfo());
if (ANGLE_UNLIKELY(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)) if (ANGLE_UNLIKELY(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR))
{ {
// We get to ignore these as they are not fatal // We get to ignore these as they are not fatal
...@@ -816,15 +762,22 @@ angle::Result CommandProcessor::processTask(Context *context, CommandProcessorTa ...@@ -816,15 +762,22 @@ angle::Result CommandProcessor::processTask(Context *context, CommandProcessorTa
// Don't leave processing loop, don't consider errors from present to be fatal. // Don't leave processing loop, don't consider errors from present to be fatal.
// TODO: https://issuetracker.google.com/issues/170329600 - This needs to improve to // TODO: https://issuetracker.google.com/issues/170329600 - This needs to improve to
// properly parallelize present // properly parallelize present
context->handleError(result, __FILE__, __FUNCTION__, __LINE__); handleError(result, __FILE__, __FUNCTION__, __LINE__);
} }
break; break;
} }
case CustomTask::ProcessCommands: case CustomTask::ProcessCommands:
{ {
ASSERT(!task->getCommandBuffer()->empty()); ASSERT(!task->getCommandBuffer()->empty());
ANGLE_TRY(task->getCommandBuffer()->flushToPrimary( if (task->getRenderPass())
getRenderer()->getFeatures(), &mPrimaryCommandBuffer, task->getRenderPass())); {
ANGLE_TRY(mTaskProcessor.flushRenderPassCommands(this, *task->getRenderPass(),
task->getCommandBuffer()));
}
else
{
ANGLE_TRY(mTaskProcessor.flushOutsideRPCommands(this, task->getCommandBuffer()));
}
ASSERT(task->getCommandBuffer()->empty()); ASSERT(task->getCommandBuffer()->empty());
task->getCommandBuffer()->releaseToContextQueue(task->getContextVk()); task->getCommandBuffer()->releaseToContextQueue(task->getContextVk());
break; break;
...@@ -951,6 +904,37 @@ void CommandProcessor::finishAllWork(Context *context) ...@@ -951,6 +904,37 @@ void CommandProcessor::finishAllWork(Context *context)
finishToSerial(context, Serial::Infinite()); finishToSerial(context, Serial::Infinite());
} }
VkResult CommandProcessor::getLastAndClearPresentResult(VkSwapchainKHR swapchain)
{
std::unique_lock<std::mutex> lock(mSwapchainStatusMutex);
if (mSwapchainStatus.find(swapchain) == mSwapchainStatus.end())
{
// Wake when required swapchain status becomes available
mSwapchainStatusCondition.wait(lock, [this, swapchain] {
return mSwapchainStatus.find(swapchain) != mSwapchainStatus.end();
});
}
VkResult result = mSwapchainStatus[swapchain];
mSwapchainStatus.erase(swapchain);
return result;
}
VkResult CommandProcessor::present(VkQueue queue, const VkPresentInfoKHR &presentInfo)
{
std::lock_guard<std::mutex> lock(mSwapchainStatusMutex);
ANGLE_TRACE_EVENT0("gpu.angle", "vkQueuePresentKHR");
VkResult result = vkQueuePresentKHR(queue, &presentInfo);
// Verify that we are presenting one and only one swapchain
ASSERT(presentInfo.swapchainCount == 1);
ASSERT(presentInfo.pResults == nullptr);
mSwapchainStatus[presentInfo.pSwapchains[0]] = result;
mSwapchainStatusCondition.notify_all();
return result;
}
// CommandQueue implementation. // CommandQueue implementation.
CommandQueue::CommandQueue() : mCurrentQueueSerial(mQueueSerialFactory.generate()) {} CommandQueue::CommandQueue() : mCurrentQueueSerial(mQueueSerialFactory.generate()) {}
...@@ -1021,7 +1005,7 @@ angle::Result CommandQueue::retireFinishedCommands(Context *context, size_t fini ...@@ -1021,7 +1005,7 @@ angle::Result CommandQueue::retireFinishedCommands(Context *context, size_t fini
renderer->resetSharedFence(&batch.fence); renderer->resetSharedFence(&batch.fence);
ANGLE_TRACE_EVENT0("gpu.angle", "command buffer recycling"); ANGLE_TRACE_EVENT0("gpu.angle", "command buffer recycling");
batch.commandPool.destroy(device); batch.commandPool.destroy(device);
ANGLE_TRY(releasePrimaryCommandBuffer(context, std::move(batch.primaryCommands))); ANGLE_TRY(mPrimaryCommandPool.collect(context, std::move(batch.primaryCommands)));
} }
if (finishedCount > 0) if (finishedCount > 0)
...@@ -1093,22 +1077,6 @@ void CommandQueue::clearAllGarbage(RendererVk *renderer) ...@@ -1093,22 +1077,6 @@ void CommandQueue::clearAllGarbage(RendererVk *renderer)
mGarbageQueue.clear(); mGarbageQueue.clear();
} }
angle::Result CommandQueue::allocatePrimaryCommandBuffer(Context *context,
PrimaryCommandBuffer *commandBufferOut)
{
return mPrimaryCommandPool.allocate(context, commandBufferOut);
}
angle::Result CommandQueue::releasePrimaryCommandBuffer(Context *context,
PrimaryCommandBuffer &&commandBuffer)
{
ASSERT(!context->getRenderer()->getFeatures().commandProcessor.enabled);
ASSERT(mPrimaryCommandPool.valid());
ANGLE_TRY(mPrimaryCommandPool.collect(context, std::move(commandBuffer)));
return angle::Result::Continue;
}
void CommandQueue::handleDeviceLost(RendererVk *renderer) void CommandQueue::handleDeviceLost(RendererVk *renderer)
{ {
VkDevice device = renderer->getDevice(); VkDevice device = renderer->getDevice();
...@@ -1294,7 +1262,7 @@ angle::Result CommandQueue::ensurePrimaryCommandBufferValid(Context *context) ...@@ -1294,7 +1262,7 @@ angle::Result CommandQueue::ensurePrimaryCommandBufferValid(Context *context)
return angle::Result::Continue; return angle::Result::Continue;
} }
ANGLE_TRY(allocatePrimaryCommandBuffer(context, &mPrimaryCommands)); ANGLE_TRY(mPrimaryCommandPool.allocate(context, &mPrimaryCommands));
VkCommandBufferBeginInfo beginInfo = {}; VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
......
...@@ -204,7 +204,6 @@ class CommandQueue final : angle::NonCopyable ...@@ -204,7 +204,6 @@ class CommandQueue final : angle::NonCopyable
angle::Result checkCompletedCommands(Context *context); angle::Result checkCompletedCommands(Context *context);
angle::Result flushOutsideRPCommands(Context *context, CommandBufferHelper *outsideRPCommands); angle::Result flushOutsideRPCommands(Context *context, CommandBufferHelper *outsideRPCommands);
angle::Result flushRenderPassCommands(Context *context, angle::Result flushRenderPassCommands(Context *context,
const RenderPass &renderPass, const RenderPass &renderPass,
CommandBufferHelper *renderPassCommands); CommandBufferHelper *renderPassCommands);
...@@ -220,10 +219,6 @@ class CommandQueue final : angle::NonCopyable ...@@ -220,10 +219,6 @@ class CommandQueue final : angle::NonCopyable
CommandBatch *batch); CommandBatch *batch);
angle::Result retireFinishedCommands(Context *context, size_t finishedCount); angle::Result retireFinishedCommands(Context *context, size_t finishedCount);
angle::Result ensurePrimaryCommandBufferValid(Context *context); angle::Result ensurePrimaryCommandBufferValid(Context *context);
angle::Result allocatePrimaryCommandBuffer(Context *context,
PrimaryCommandBuffer *commandBufferOut);
angle::Result releasePrimaryCommandBuffer(Context *context,
PrimaryCommandBuffer &&commandBuffer);
bool allInFlightCommandsAreAfterSerial(Serial serial) const; bool allInFlightCommandsAreAfterSerial(Serial serial) const;
...@@ -250,25 +245,19 @@ class TaskProcessor : angle::NonCopyable ...@@ -250,25 +245,19 @@ class TaskProcessor : angle::NonCopyable
angle::Result init(Context *context, std::thread::id threadId); angle::Result init(Context *context, std::thread::id threadId);
void destroy(VkDevice device); void destroy(VkDevice device);
angle::Result allocatePrimaryCommandBuffer(Context *context,
PrimaryCommandBuffer *commandBufferOut);
angle::Result releasePrimaryCommandBuffer(Context *context,
PrimaryCommandBuffer &&commandBuffer);
angle::Result finishToSerial(Context *context, Serial serial); angle::Result finishToSerial(Context *context, Serial serial);
VkResult present(VkQueue queue, const VkPresentInfoKHR &presentInfo);
angle::Result submitFrame(Context *context, angle::Result submitFrame(Context *context,
VkQueue queue, egl::ContextPriority priority,
const VkSubmitInfo &submitInfo, const std::vector<VkSemaphore> &waitSemaphores,
const Shared<Fence> &sharedFence, const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks,
const Semaphore *signalSemaphore,
Shared<Fence> &&sharedFence,
GarbageList *currentGarbage, GarbageList *currentGarbage,
CommandPool *commandPool, CommandPool *commandPool,
PrimaryCommandBuffer &&commandBuffer,
Serial submitQueueSerial); Serial submitQueueSerial);
angle::Result queueSubmit(Context *context, angle::Result queueSubmit(Context *context,
VkQueue queue, egl::ContextPriority priority,
const VkSubmitInfo &submitInfo, const VkSubmitInfo &submitInfo,
const Fence *fence, const Fence *fence,
Serial submitQueueSerial); Serial submitQueueSerial);
...@@ -277,7 +266,10 @@ class TaskProcessor : angle::NonCopyable ...@@ -277,7 +266,10 @@ class TaskProcessor : angle::NonCopyable
angle::Result checkCompletedCommands(Context *context); angle::Result checkCompletedCommands(Context *context);
VkResult getLastAndClearPresentResult(VkSwapchainKHR swapchain); angle::Result flushOutsideRPCommands(Context *context, CommandBufferHelper *outsideRPCommands);
angle::Result flushRenderPassCommands(Context *context,
const RenderPass &renderPass,
CommandBufferHelper *renderPassCommands);
Serial reserveSubmitSerial(); Serial reserveSubmitSerial();
...@@ -292,11 +284,13 @@ class TaskProcessor : angle::NonCopyable ...@@ -292,11 +284,13 @@ class TaskProcessor : angle::NonCopyable
PrimaryCommandBuffer &&commandBuffer, PrimaryCommandBuffer &&commandBuffer,
CommandPool *commandPool, CommandPool *commandPool,
CommandBatch *batch); CommandBatch *batch);
angle::Result ensurePrimaryCommandBufferValid(Context *context);
GarbageQueue mGarbageQueue; GarbageQueue mGarbageQueue;
std::vector<CommandBatch> mInFlightCommands; std::vector<CommandBatch> mInFlightCommands;
// Keeps a free list of reusable primary command buffers. // Keeps a free list of reusable primary command buffers.
PrimaryCommandBuffer mPrimaryCommandBuffer;
PersistentCommandPool mPrimaryCommandPool; PersistentCommandPool mPrimaryCommandPool;
std::thread::id mThreadId; std::thread::id mThreadId;
...@@ -305,11 +299,6 @@ class TaskProcessor : angle::NonCopyable ...@@ -305,11 +299,6 @@ class TaskProcessor : angle::NonCopyable
Serial mLastCompletedQueueSerial; Serial mLastCompletedQueueSerial;
Serial mLastSubmittedQueueSerial; Serial mLastSubmittedQueueSerial;
Serial mCurrentQueueSerial; 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 // TODO(jmadill): Give this the same API as CommandQueue. b/172704839
...@@ -363,7 +352,7 @@ class CommandProcessor : public Context ...@@ -363,7 +352,7 @@ class CommandProcessor : public Context
VkResult getLastPresentResult(VkSwapchainKHR swapchain) VkResult getLastPresentResult(VkSwapchainKHR swapchain)
{ {
return mTaskProcessor.getLastAndClearPresentResult(swapchain); return getLastAndClearPresentResult(swapchain);
} }
private: private:
...@@ -372,7 +361,10 @@ class CommandProcessor : public Context ...@@ -372,7 +361,10 @@ class CommandProcessor : public Context
angle::Result processTasksImpl(bool *exitThread); angle::Result processTasksImpl(bool *exitThread);
// Command processor thread, process a task // Command processor thread, process a task
angle::Result processTask(Context *context, CommandProcessorTask *task); angle::Result processTask(CommandProcessorTask *task);
VkResult getLastAndClearPresentResult(VkSwapchainKHR swapchain);
VkResult present(VkQueue queue, const VkPresentInfoKHR &presentInfo);
std::queue<CommandProcessorTask> mTasks; std::queue<CommandProcessorTask> mTasks;
mutable std::mutex mWorkerMutex; mutable std::mutex mWorkerMutex;
...@@ -384,13 +376,17 @@ class CommandProcessor : public Context ...@@ -384,13 +376,17 @@ class CommandProcessor : public Context
bool mWorkerThreadIdle; bool mWorkerThreadIdle;
// Command pool to allocate processor thread primary command buffers from // Command pool to allocate processor thread primary command buffers from
CommandPool mCommandPool; CommandPool mCommandPool;
PrimaryCommandBuffer mPrimaryCommandBuffer;
TaskProcessor mTaskProcessor; TaskProcessor mTaskProcessor;
std::mutex mQueueSerialMutex; std::mutex mQueueSerialMutex;
mutable std::mutex mErrorMutex; mutable std::mutex mErrorMutex;
std::queue<Error> mErrors; std::queue<Error> mErrors;
// Track present info
std::mutex mSwapchainStatusMutex;
std::condition_variable mSwapchainStatusCondition;
std::map<VkSwapchainKHR, VkResult> mSwapchainStatus;
}; };
} // namespace vk } // namespace vk
......
...@@ -154,10 +154,10 @@ void SyncHelperNativeFence::releaseToRenderer(RendererVk *renderer) ...@@ -154,10 +154,10 @@ void SyncHelperNativeFence::releaseToRenderer(RendererVk *renderer)
renderer->collectGarbageAndReinit(&mUse, &mFenceWithFd); renderer->collectGarbageAndReinit(&mUse, &mFenceWithFd);
} }
// Note: Having mFenceWithFd hold the FD, so that ownership is with ICD. Meanwhile store a dup // Note: We have mFenceWithFd hold the FD, so that ownership is with ICD. Meanwhile we store a dup
// of FD in SyncHelperNativeFence for further reference, i.e. dup of FD. Any call to clientWait // of FD in SyncHelperNativeFence for further reference, i.e. dup of FD. Any call to clientWait
// or serverWait will ensure the FD or dup of FD goes to application or ICD. At release, above // or serverWait will ensure the FD or dup of FD goes to application or ICD. At release, above
// it's Garbage collected/destroyed. Otherwise can't time when to close(fd); // it's Garbage collected/destroyed. Otherwise we can't time when to close(fd);
angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int inFd) angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int inFd)
{ {
ASSERT(inFd >= kInvalidFenceFd); ASSERT(inFd >= kInvalidFenceFd);
......
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