Commit 84fce18c by Jamie Madill Committed by Commit Bot

Vulkan: Give CommandQueue an abstract interface.

This gives CommandQueue and CommandProcessor the exact same interface. This also moves the worker thread to be owned by CommandProcessor. Bug: b/172704839 Change-Id: Ife439bcf52d923e01a6a2166e0caaffce14fd086 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2537235 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 59bddcfb
......@@ -59,6 +59,7 @@ bool CommandsHaveValidOrdering(const std::vector<vk::CommandBatch> &commands)
}
} // namespace
// CommandProcessorTask implementation
void CommandProcessorTask::initTask()
{
mTask = CustomTask::Invalid;
......@@ -75,7 +76,6 @@ void CommandProcessorTask::initTask()
mOneOffCommandBufferVk = VK_NULL_HANDLE;
}
// CommandProcessorTask implementation
void CommandProcessorTask::initProcessCommands(CommandBufferHelper *commandBuffer,
const RenderPass *renderPass)
{
......@@ -165,29 +165,29 @@ void CommandProcessorTask::initFinishToSerial(Serial serial)
}
void CommandProcessorTask::initFlushAndQueueSubmit(
std::vector<VkSemaphore> &&waitSemaphores,
std::vector<VkPipelineStageFlags> &&waitSemaphoreStageMasks,
const std::vector<VkSemaphore> &waitSemaphores,
const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks,
const Semaphore *semaphore,
egl::ContextPriority priority,
GarbageList &&currentGarbage,
Serial submitQueueSerial)
{
mTask = CustomTask::FlushAndQueueSubmit;
mWaitSemaphores = std::move(waitSemaphores);
mWaitSemaphoreStageMasks = std::move(waitSemaphoreStageMasks);
mWaitSemaphores = waitSemaphores;
mWaitSemaphoreStageMasks = waitSemaphoreStageMasks;
mSemaphore = semaphore;
mGarbage = std::move(currentGarbage);
mPriority = priority;
mSerial = submitQueueSerial;
}
void CommandProcessorTask::initOneOffQueueSubmit(VkCommandBuffer oneOffCommandBufferVk,
void CommandProcessorTask::initOneOffQueueSubmit(VkCommandBuffer commandBufferHandle,
egl::ContextPriority priority,
const Fence *fence,
Serial submitQueueSerial)
{
mTask = CustomTask::OneOffQueueSubmit;
mOneOffCommandBufferVk = oneOffCommandBufferVk;
mOneOffCommandBufferVk = commandBufferHandle;
mOneOffFence = fence;
mPriority = priority;
mSerial = submitQueueSerial;
......@@ -200,17 +200,17 @@ CommandProcessorTask &CommandProcessorTask::operator=(CommandProcessorTask &&rhs
return *this;
}
mRenderPass = rhs.mRenderPass;
mCommandBuffer = rhs.mCommandBuffer;
std::swap(mRenderPass, rhs.mRenderPass);
std::swap(mCommandBuffer, rhs.mCommandBuffer);
std::swap(mTask, rhs.mTask);
std::swap(mWaitSemaphores, rhs.mWaitSemaphores);
std::swap(mWaitSemaphoreStageMasks, rhs.mWaitSemaphoreStageMasks);
mSemaphore = rhs.mSemaphore;
mOneOffFence = rhs.mOneOffFence;
std::swap(mSemaphore, rhs.mSemaphore);
std::swap(mOneOffFence, rhs.mOneOffFence);
std::swap(mGarbage, rhs.mGarbage);
std::swap(mSerial, rhs.mSerial);
std::swap(mPriority, rhs.mPriority);
mOneOffCommandBufferVk = rhs.mOneOffCommandBufferVk;
std::swap(mOneOffCommandBufferVk, rhs.mOneOffCommandBufferVk);
copyPresentInfo(rhs.mPresentInfo);
......@@ -261,7 +261,7 @@ void CommandProcessor::handleError(VkResult errorCode,
if (errorCode == VK_ERROR_DEVICE_LOST)
{
WARN() << errorStream.str();
handleDeviceLost();
handleDeviceLost(mRenderer);
}
std::lock_guard<std::mutex> queueLock(mErrorMutex);
......@@ -281,39 +281,35 @@ CommandProcessor::CommandProcessor(RendererVk *renderer)
CommandProcessor::~CommandProcessor() = default;
Error CommandProcessor::getAndClearPendingError()
angle::Result CommandProcessor::checkAndPopPendingError(Context *errorHandlingContext)
{
std::lock_guard<std::mutex> queueLock(mErrorMutex);
Error tmpError({VK_SUCCESS, nullptr, nullptr, 0});
if (!mErrors.empty())
if (mErrors.empty())
{
return angle::Result::Continue;
}
else
{
tmpError = mErrors.front();
Error err = mErrors.front();
mErrors.pop();
errorHandlingContext->handleError(err.errorCode, err.file, err.function, err.line);
return angle::Result::Stop;
}
return tmpError;
}
void CommandProcessor::queueCommand(Context *context, CommandProcessorTask *task)
void CommandProcessor::queueCommand(CommandProcessorTask &&task)
{
ANGLE_TRACE_EVENT0("gpu.angle", "CommandProcessor::queueCommand");
// Grab the worker mutex so that we put things on the queue in the same order as we give out
// serials.
std::lock_guard<std::mutex> queueLock(mWorkerMutex);
mTasks.emplace(std::move(*task));
mTasks.emplace(std::move(task));
mWorkAvailableCondition.notify_one();
}
void CommandProcessor::processTasks(const DeviceQueueMap &queueMap)
{
angle::Result initResult = mCommandQueue.init(this, queueMap);
if (initResult == angle::Result::Stop)
{
// TODO: https://issuetracker.google.com/issues/170311829 - error handling
UNREACHABLE();
return;
}
while (true)
{
bool exitThread = false;
......@@ -376,7 +372,7 @@ angle::Result CommandProcessor::processTask(CommandProcessorTask *task)
ANGLE_TRY(mCommandQueue.finishToSerial(this, Serial::Infinite(),
mRenderer->getMaxFenceWaitTimeNs()));
// Shutting down so cleanup
mCommandQueue.destroy(mRenderer);
mCommandQueue.destroy(this);
mCommandPool.destroy(mRenderer->getDevice());
break;
}
......@@ -403,18 +399,10 @@ angle::Result CommandProcessor::processTask(CommandProcessorTask *task)
case CustomTask::OneOffQueueSubmit:
{
ANGLE_TRACE_EVENT0("gpu.angle", "processTask::OneOffQueueSubmit");
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
if (task->getOneOffCommandBufferVk() != VK_NULL_HANDLE)
{
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &task->getOneOffCommandBufferVk();
}
// TODO: https://issuetracker.google.com/issues/170328907 - vkQueueSubmit should be
// owned by TaskProcessor to ensure proper synchronization
ANGLE_TRY(mCommandQueue.queueSubmit(this, task->getPriority(), submitInfo,
task->getOneOffFence(), task->getQueueSerial()));
ANGLE_TRY(mCommandQueue.queueSubmitOneOff(
this, task->getPriority(), task->getOneOffCommandBufferVk(), task->getOneOffFence(),
task->getQueueSerial()));
ANGLE_TRY(mCommandQueue.checkCompletedCommands(this));
break;
}
......@@ -444,14 +432,16 @@ angle::Result CommandProcessor::processTask(CommandProcessorTask *task)
case CustomTask::ProcessCommands:
{
ASSERT(!task->getCommandBuffer()->empty());
CommandBufferHelper *commandBuffer = task->getCommandBuffer();
if (task->getRenderPass())
{
ANGLE_TRY(mCommandQueue.flushRenderPassCommands(this, *task->getRenderPass(),
task->getCommandBuffer()));
&commandBuffer));
}
else
{
ANGLE_TRY(mCommandQueue.flushOutsideRPCommands(this, task->getCommandBuffer()));
ANGLE_TRY(mCommandQueue.flushOutsideRPCommands(this, &commandBuffer));
}
ASSERT(task->getCommandBuffer()->empty());
mRenderer->recycleCommandBufferHelper(task->getCommandBuffer());
......@@ -470,64 +460,67 @@ angle::Result CommandProcessor::processTask(CommandProcessorTask *task)
return angle::Result::Continue;
}
void CommandProcessor::checkCompletedCommands(Context *context)
angle::Result CommandProcessor::checkCompletedCommands(Context *context)
{
ANGLE_TRY(checkAndPopPendingError(context));
CommandProcessorTask checkCompletedTask;
checkCompletedTask.initTask(CustomTask::CheckCompletedCommands);
queueCommand(this, &checkCompletedTask);
queueCommand(std::move(checkCompletedTask));
return angle::Result::Continue;
}
void CommandProcessor::waitForWorkComplete(Context *context)
angle::Result CommandProcessor::waitForWorkComplete(Context *context)
{
ANGLE_TRACE_EVENT0("gpu.angle", "CommandProcessor::waitForWorkComplete");
std::unique_lock<std::mutex> lock(mWorkerMutex);
mWorkerIdleCondition.wait(lock, [this] { return (mTasks.empty() && mWorkerThreadIdle); });
// Worker thread is idle and command queue is empty so good to continue
if (!context)
{
return;
}
// Sync any errors to the context
bool shouldStop = hasPendingError();
while (hasPendingError())
{
Error workerError = getAndClearPendingError();
if (workerError.mErrorCode != VK_SUCCESS)
{
context->handleError(workerError.mErrorCode, workerError.mFile, workerError.mFunction,
workerError.mLine);
}
(void)checkAndPopPendingError(context);
}
return shouldStop ? angle::Result::Stop : angle::Result::Continue;
}
// TODO: https://issuetracker.google.com/170311829 - Add vk::Context so that queueCommand has
// someplace to send errors.
void CommandProcessor::shutdown(std::thread *commandProcessorThread)
angle::Result CommandProcessor::init(Context *context, const DeviceQueueMap &queueMap)
{
ANGLE_TRY(mCommandQueue.init(context, queueMap));
mTaskThread = std::thread(&CommandProcessor::processTasks, this, queueMap);
return angle::Result::Continue;
}
void CommandProcessor::destroy(Context *context)
{
CommandProcessorTask endTask;
endTask.initTask(CustomTask::Exit);
queueCommand(this, &endTask);
waitForWorkComplete(nullptr);
if (commandProcessorThread->joinable())
queueCommand(std::move(endTask));
(void)waitForWorkComplete(context);
if (mTaskThread.joinable())
{
commandProcessorThread->join();
mTaskThread.join();
}
}
Serial CommandProcessor::getLastCompletedQueueSerial()
Serial CommandProcessor::getLastCompletedQueueSerial() const
{
std::lock_guard<std::mutex> lock(mQueueSerialMutex);
return mCommandQueue.getLastCompletedQueueSerial();
}
Serial CommandProcessor::getLastSubmittedQueueSerial()
Serial CommandProcessor::getLastSubmittedQueueSerial() const
{
std::lock_guard<std::mutex> lock(mQueueSerialMutex);
return mCommandQueue.getLastSubmittedQueueSerial();
}
Serial CommandProcessor::getCurrentQueueSerial()
Serial CommandProcessor::getCurrentQueueSerial() const
{
std::lock_guard<std::mutex> lock(mQueueSerialMutex);
return mCommandQueue.getCurrentQueueSerial();
......@@ -540,33 +533,36 @@ Serial CommandProcessor::reserveSubmitSerial()
}
// Wait until all commands up to and including serial have been processed
void CommandProcessor::finishToSerial(Context *context, Serial serial)
angle::Result CommandProcessor::finishToSerial(Context *context, Serial serial, uint64_t timeout)
{
ANGLE_TRACE_EVENT0("gpu.angle", "CommandProcessor::finishToSerial");
CommandProcessorTask finishToSerial;
finishToSerial.initFinishToSerial(serial);
queueCommand(context, &finishToSerial);
ANGLE_TRY(checkAndPopPendingError(context));
CommandProcessorTask task;
task.initFinishToSerial(serial);
queueCommand(std::move(task));
// Wait until the worker is idle. At that point we know that the finishToSerial command has
// completed executing, including any associated state cleanup.
waitForWorkComplete(context);
return waitForWorkComplete(context);
}
void CommandProcessor::handleDeviceLost()
void CommandProcessor::handleDeviceLost(RendererVk *renderer)
{
ANGLE_TRACE_EVENT0("gpu.angle", "CommandProcessor::handleDeviceLost");
std::unique_lock<std::mutex> lock(mWorkerMutex);
mWorkerIdleCondition.wait(lock, [this] { return (mTasks.empty() && mWorkerThreadIdle); });
// Worker thread is idle and command queue is empty so good to continue
mCommandQueue.handleDeviceLost(mRenderer);
mCommandQueue.handleDeviceLost(renderer);
}
void CommandProcessor::finishAllWork(Context *context)
angle::Result CommandProcessor::finishAllWork(Context *context)
{
ANGLE_TRACE_EVENT0("gpu.angle", "CommandProcessor::finishAllWork");
// Wait for GPU work to finish
finishToSerial(context, Serial::Infinite());
return finishToSerial(context, Serial::Infinite(), mRenderer->getMaxFenceWaitTimeNs());
}
VkResult CommandProcessor::getLastAndClearPresentResult(VkSwapchainKHR swapchain)
......@@ -601,12 +597,103 @@ VkResult CommandProcessor::present(egl::ContextPriority priority,
return result;
}
angle::Result CommandProcessor::submitFrame(
Context *context,
egl::ContextPriority priority,
const std::vector<VkSemaphore> &waitSemaphores,
const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks,
const Semaphore *signalSemaphore,
Shared<Fence> &&sharedFence,
GarbageList &&currentGarbage,
CommandPool *commandPool,
Serial submitQueueSerial)
{
ANGLE_TRY(checkAndPopPendingError(context));
CommandProcessorTask task;
task.initFlushAndQueueSubmit(waitSemaphores, waitSemaphoreStageMasks, signalSemaphore, priority,
std::move(currentGarbage), submitQueueSerial);
queueCommand(std::move(task));
return angle::Result::Continue;
}
angle::Result CommandProcessor::queueSubmitOneOff(Context *context,
egl::ContextPriority contextPriority,
VkCommandBuffer commandBufferHandle,
const Fence *fence,
Serial submitQueueSerial)
{
ANGLE_TRY(checkAndPopPendingError(context));
CommandProcessorTask task;
task.initOneOffQueueSubmit(commandBufferHandle, contextPriority, fence, submitQueueSerial);
queueCommand(std::move(task));
return angle::Result::Continue;
}
VkResult CommandProcessor::queuePresent(egl::ContextPriority contextPriority,
const VkPresentInfoKHR &presentInfo)
{
CommandProcessorTask task;
task.initPresent(contextPriority, presentInfo);
ANGLE_TRACE_EVENT0("gpu.angle", "CommandProcessor::queuePresent");
queueCommand(std::move(task));
// Always return success, when we call acquireNextImage we'll check the return code. This
// allows the app to continue working until we really need to know the return code from
// present.
return VK_SUCCESS;
}
angle::Result CommandProcessor::waitForSerialWithUserTimeout(vk::Context *context,
Serial serial,
uint64_t timeout,
VkResult *result)
{
// If finishToSerial times out we generate an error. Therefore we a large timeout.
// TODO: https://issuetracker.google.com/170312581 - Wait with timeout.
return finishToSerial(context, serial, mRenderer->getMaxFenceWaitTimeNs());
}
angle::Result CommandProcessor::flushOutsideRPCommands(Context *context,
CommandBufferHelper **outsideRPCommands)
{
ANGLE_TRY(checkAndPopPendingError(context));
(*outsideRPCommands)->markClosed();
CommandProcessorTask task;
task.initProcessCommands(*outsideRPCommands, nullptr);
queueCommand(std::move(task));
*outsideRPCommands = mRenderer->getCommandBufferHelper(false);
return angle::Result::Continue;
}
angle::Result CommandProcessor::flushRenderPassCommands(Context *context,
const RenderPass &renderPass,
CommandBufferHelper **renderPassCommands)
{
ANGLE_TRY(checkAndPopPendingError(context));
(*renderPassCommands)->markClosed();
CommandProcessorTask task;
task.initProcessCommands(*renderPassCommands, &renderPass);
queueCommand(std::move(task));
*renderPassCommands = mRenderer->getCommandBufferHelper(true);
return angle::Result::Continue;
}
// CommandQueue implementation.
CommandQueue::CommandQueue() : mCurrentQueueSerial(mQueueSerialFactory.generate()) {}
CommandQueue::~CommandQueue() = default;
void CommandQueue::destroy(RendererVk *renderer)
void CommandQueue::destroy(Context *context)
{
// Force all commands to finish by flushing all queues.
for (VkQueue queue : mQueues)
......@@ -617,8 +704,10 @@ void CommandQueue::destroy(RendererVk *renderer)
}
}
RendererVk *renderer = context->getRenderer();
mLastCompletedQueueSerial = Serial::Infinite();
clearAllGarbage(renderer);
(void)clearAllGarbage(renderer);
mPrimaryCommands.destroy(renderer->getDevice());
mPrimaryCommandPool.destroy(renderer->getDevice());
......@@ -952,20 +1041,38 @@ angle::Result CommandQueue::ensurePrimaryCommandBufferValid(Context *context)
}
angle::Result CommandQueue::flushOutsideRPCommands(Context *context,
CommandBufferHelper *outsideRPCommands)
CommandBufferHelper **outsideRPCommands)
{
ANGLE_TRY(ensurePrimaryCommandBufferValid(context));
return outsideRPCommands->flushToPrimary(context->getRenderer()->getFeatures(),
&mPrimaryCommands, nullptr);
return (*outsideRPCommands)
->flushToPrimary(context->getRenderer()->getFeatures(), &mPrimaryCommands, nullptr);
}
angle::Result CommandQueue::flushRenderPassCommands(Context *context,
const RenderPass &renderPass,
CommandBufferHelper *renderPassCommands)
CommandBufferHelper **renderPassCommands)
{
ANGLE_TRY(ensurePrimaryCommandBufferValid(context));
return renderPassCommands->flushToPrimary(context->getRenderer()->getFeatures(),
&mPrimaryCommands, &renderPass);
return (*renderPassCommands)
->flushToPrimary(context->getRenderer()->getFeatures(), &mPrimaryCommands, &renderPass);
}
angle::Result CommandQueue::queueSubmitOneOff(Context *context,
egl::ContextPriority contextPriority,
VkCommandBuffer commandBufferHandle,
const Fence *fence,
Serial submitQueueSerial)
{
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
if (commandBufferHandle != VK_NULL_HANDLE)
{
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBufferHandle;
}
return queueSubmit(context, contextPriority, submitInfo, fence, submitQueueSerial);
}
angle::Result CommandQueue::queueSubmit(Context *context,
......@@ -996,5 +1103,20 @@ VkResult CommandQueue::queuePresent(egl::ContextPriority contextPriority,
{
return vkQueuePresentKHR(mQueues[contextPriority], &presentInfo);
}
Serial CommandQueue::getLastSubmittedQueueSerial() const
{
return mLastSubmittedQueueSerial;
}
Serial CommandQueue::getLastCompletedQueueSerial() const
{
return mLastCompletedQueueSerial;
}
Serial CommandQueue::getCurrentQueueSerial() const
{
return mCurrentQueueSerial;
}
} // namespace vk
} // namespace rx
......@@ -27,13 +27,7 @@ class CommandProcessor;
namespace vk
{
// CommandProcessor is used to dispatch work to the GPU when commandProcessor feature is true.
// If asynchronousCommandProcessing is enabled the work will be queued and handled by a worker
// thread asynchronous to the context. Issuing the CustomTask::Exit command will cause the worker
// thread to clean up it's resources and shut down. This command is sent when the renderer instance
// shuts down. Custom tasks are:
enum CustomTask
enum class CustomTask
{
Invalid = 0,
// Process SecondaryCommandBuffer commands into the primary CommandBuffer.
......@@ -54,6 +48,7 @@ enum CustomTask
Exit,
};
// CommandProcessorTask interface
class CommandProcessorTask
{
public:
......@@ -69,14 +64,14 @@ class CommandProcessorTask
void initFinishToSerial(Serial serial);
void initFlushAndQueueSubmit(std::vector<VkSemaphore> &&waitSemaphores,
std::vector<VkPipelineStageFlags> &&waitSemaphoreStageMasks,
void initFlushAndQueueSubmit(const std::vector<VkSemaphore> &waitSemaphores,
const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks,
const Semaphore *semaphore,
egl::ContextPriority priority,
GarbageList &&currentGarbage,
Serial submitQueueSerial);
void initOneOffQueueSubmit(VkCommandBuffer oneOffCommandBufferVk,
void initOneOffQueueSubmit(VkCommandBuffer commandBufferHandle,
egl::ContextPriority priority,
const Fence *fence,
Serial submitQueueSerial);
......@@ -99,7 +94,7 @@ class CommandProcessorTask
const Semaphore *getSemaphore() { return mSemaphore; }
GarbageList &getGarbage() { return mGarbage; }
egl::ContextPriority getPriority() const { return mPriority; }
const VkCommandBuffer &getOneOffCommandBufferVk() const { return mOneOffCommandBufferVk; }
VkCommandBuffer getOneOffCommandBufferVk() const { return mOneOffCommandBufferVk; }
const Fence *getOneOffFence() { return mOneOffFence; }
const VkPresentInfoKHR &getPresentInfo() const { return mPresentInfo; }
const RenderPass *getRenderPass() const { return mRenderPass; }
......@@ -159,21 +154,75 @@ struct CommandBatch final : angle::NonCopyable
using DeviceQueueMap = angle::PackedEnumMap<egl::ContextPriority, VkQueue>;
class CommandQueue final : angle::NonCopyable
class CommandQueueInterface : angle::NonCopyable
{
public:
CommandQueue();
~CommandQueue();
virtual ~CommandQueueInterface() {}
virtual angle::Result init(Context *context, const DeviceQueueMap &queueMap) = 0;
virtual void destroy(Context *context) = 0;
virtual void handleDeviceLost(RendererVk *renderer) = 0;
// Wait until the desired serial has been completed.
virtual angle::Result finishToSerial(Context *context,
Serial finishSerial,
uint64_t timeout) = 0;
virtual Serial reserveSubmitSerial() = 0;
virtual angle::Result submitFrame(
Context *context,
egl::ContextPriority priority,
const std::vector<VkSemaphore> &waitSemaphores,
const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks,
const Semaphore *signalSemaphore,
Shared<Fence> &&sharedFence,
GarbageList &&currentGarbage,
CommandPool *commandPool,
Serial submitQueueSerial) = 0;
virtual angle::Result queueSubmitOneOff(Context *context,
egl::ContextPriority contextPriority,
VkCommandBuffer commandBufferHandle,
const Fence *fence,
Serial submitQueueSerial) = 0;
virtual VkResult queuePresent(egl::ContextPriority contextPriority,
const VkPresentInfoKHR &presentInfo) = 0;
virtual angle::Result waitForSerialWithUserTimeout(vk::Context *context,
Serial serial,
uint64_t timeout,
VkResult *result) = 0;
angle::Result init(Context *context, const DeviceQueueMap &queueMap);
void destroy(RendererVk *renderer);
void handleDeviceLost(RendererVk *renderer);
// Check to see which batches have finished completion (forward progress for
// the last completed serial, for example for when the application busy waits on a query
// result). It would be nice if we didn't have to expose this for QueryVk::getResult.
virtual angle::Result checkCompletedCommands(Context *context) = 0;
virtual angle::Result flushOutsideRPCommands(Context *context,
CommandBufferHelper **outsideRPCommands) = 0;
virtual angle::Result flushRenderPassCommands(Context *context,
const RenderPass &renderPass,
CommandBufferHelper **renderPassCommands) = 0;
virtual Serial getLastSubmittedQueueSerial() const = 0;
virtual Serial getLastCompletedQueueSerial() const = 0;
virtual Serial getCurrentQueueSerial() const = 0;
};
class CommandQueue final : public CommandQueueInterface
{
public:
CommandQueue();
~CommandQueue() override;
angle::Result init(Context *context, const DeviceQueueMap &queueMap) override;
void destroy(Context *context) override;
void clearAllGarbage(RendererVk *renderer);
angle::Result finishToSerial(Context *context, Serial finishSerial, uint64_t timeout);
void handleDeviceLost(RendererVk *renderer) override;
angle::Result finishToSerial(Context *context, Serial finishSerial, uint64_t timeout) override;
Serial reserveSubmitSerial();
Serial reserveSubmitSerial() override;
angle::Result submitFrame(Context *context,
egl::ContextPriority priority,
......@@ -183,34 +232,39 @@ class CommandQueue final : angle::NonCopyable
Shared<Fence> &&sharedFence,
GarbageList &&currentGarbage,
CommandPool *commandPool,
Serial submitQueueSerial);
Serial submitQueueSerial) override;
angle::Result queueSubmitOneOff(Context *context,
egl::ContextPriority contextPriority,
VkCommandBuffer commandBufferHandle,
const Fence *fence,
Serial submitQueueSerial) override;
angle::Result queueSubmit(Context *context,
egl::ContextPriority contextPriority,
const VkSubmitInfo &submitInfo,
const Fence *fence,
Serial submitQueueSerial);
VkResult queuePresent(egl::ContextPriority contextPriority,
const VkPresentInfoKHR &presentInfo);
const VkPresentInfoKHR &presentInfo) override;
angle::Result waitForSerialWithUserTimeout(vk::Context *context,
Serial serial,
uint64_t timeout,
VkResult *result);
VkResult *result) override;
// Check to see which batches have finished completion (forward progress for
// mLastCompletedQueueSerial, for example for when the application busy waits on a query
// result). It would be nice if we didn't have to expose this for QuerygetResult.
angle::Result checkCompletedCommands(Context *context);
angle::Result checkCompletedCommands(Context *context) override;
angle::Result flushOutsideRPCommands(Context *context, CommandBufferHelper *outsideRPCommands);
angle::Result flushOutsideRPCommands(Context *context,
CommandBufferHelper **outsideRPCommands) override;
angle::Result flushRenderPassCommands(Context *context,
const RenderPass &renderPass,
CommandBufferHelper *renderPassCommands);
CommandBufferHelper **renderPassCommands) override;
ANGLE_INLINE Serial getLastSubmittedQueueSerial() const { return mLastSubmittedQueueSerial; }
ANGLE_INLINE Serial getLastCompletedQueueSerial() const { return mLastCompletedQueueSerial; }
ANGLE_INLINE Serial getCurrentQueueSerial() const { return mCurrentQueueSerial; }
Serial getLastSubmittedQueueSerial() const override;
Serial getLastCompletedQueueSerial() const override;
Serial getCurrentQueueSerial() const override;
angle::Result queueSubmit(Context *context,
egl::ContextPriority contextPriority,
const VkSubmitInfo &submitInfo,
const Fence *fence,
Serial submitQueueSerial);
private:
angle::Result releaseToCommandBatch(Context *context,
......@@ -239,59 +293,95 @@ class CommandQueue final : angle::NonCopyable
DeviceQueueMap mQueues;
};
// TODO(jmadill): Give this the same API as CommandQueue. b/172704839
class CommandProcessor : public Context
// CommandProcessor is used to dispatch work to the GPU when the asyncCommandQueue feature is
// enabled. Issuing the |destroy| command will cause the worker thread to clean up it's resources
// and shut down. This command is sent when the renderer instance shuts down. Tasks are defined by
// the CommandQueue interface.
class CommandProcessor : public Context, public CommandQueueInterface
{
public:
CommandProcessor(RendererVk *renderer);
~CommandProcessor() override;
// Used by main thread to wait for worker thread to complete all outstanding work.
// TODO(jmadill): Make private. b/172704839
angle::Result waitForWorkComplete(Context *context);
angle::Result finishAllWork(Context *context);
VkResult getLastPresentResult(VkSwapchainKHR swapchain)
{
return getLastAndClearPresentResult(swapchain);
}
// vk::Context
void handleError(VkResult result,
const char *file,
const char *function,
unsigned int line) override;
// Entry point for command processor thread, calls processTasksImpl to do the
// work. called by Rendererinitialization on main thread
void processTasks(const DeviceQueueMap &queueMap);
// CommandQueueInterface
angle::Result init(Context *context, const DeviceQueueMap &queueMap) override;
// Called asynchronously from main thread to queue work that is then processed by the worker
// thread
void queueCommand(Context *context, CommandProcessorTask *task);
void destroy(Context *context) override;
void checkCompletedCommands(Context *context);
void handleDeviceLost(RendererVk *renderer) override;
// Used by main thread to wait for worker thread to complete all outstanding work.
void waitForWorkComplete(Context *context);
angle::Result finishToSerial(Context *context, Serial finishSerial, uint64_t timeout) override;
Serial getLastCompletedQueueSerial();
Serial getLastSubmittedQueueSerial();
Serial getCurrentQueueSerial();
Serial reserveSubmitSerial();
Serial reserveSubmitSerial() override;
// Wait until desired serial has been processed.
void finishToSerial(Context *context, Serial serial);
angle::Result submitFrame(Context *context,
egl::ContextPriority priority,
const std::vector<VkSemaphore> &waitSemaphores,
const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks,
const Semaphore *signalSemaphore,
Shared<Fence> &&sharedFence,
GarbageList &&currentGarbage,
CommandPool *commandPool,
Serial submitQueueSerial) override;
angle::Result queueSubmitOneOff(Context *context,
egl::ContextPriority contextPriority,
VkCommandBuffer commandBufferHandle,
const Fence *fence,
Serial submitQueueSerial) override;
VkResult queuePresent(egl::ContextPriority contextPriority,
const VkPresentInfoKHR &presentInfo) override;
angle::Result waitForSerialWithUserTimeout(vk::Context *context,
Serial serial,
uint64_t timeout,
VkResult *result) override;
void handleDeviceLost();
angle::Result checkCompletedCommands(Context *context) override;
angle::Result flushOutsideRPCommands(Context *context,
CommandBufferHelper **outsideRPCommands) override;
angle::Result flushRenderPassCommands(Context *context,
const RenderPass &renderPass,
CommandBufferHelper **renderPassCommands) override;
Serial getLastSubmittedQueueSerial() const override;
Serial getLastCompletedQueueSerial() const override;
Serial getCurrentQueueSerial() const override;
private:
bool hasPendingError() const
{
std::lock_guard<std::mutex> queueLock(mErrorMutex);
return !mErrors.empty();
}
Error getAndClearPendingError();
// Stop the command processor thread
void shutdown(std::thread *commandProcessorThread);
angle::Result checkAndPopPendingError(Context *errorHandlingContext);
void finishAllWork(Context *context);
// Entry point for command processor thread, calls processTasksImpl to do the
// work. called by RendererVk::initializeDevice on main thread
void processTasks(const DeviceQueueMap &queueMap);
VkResult getLastPresentResult(VkSwapchainKHR swapchain)
{
return getLastAndClearPresentResult(swapchain);
}
// Called asynchronously from main thread to queue work that is then processed by the worker
// thread
void queueCommand(CommandProcessorTask &&task);
private:
// Command processor thread, called by processTasks. The loop waits for work to
// be submitted from a separate thread.
angle::Result processTasksImpl(bool *exitThread);
......@@ -314,7 +404,7 @@ class CommandProcessor : public Context
CommandPool mCommandPool;
CommandQueue mCommandQueue;
std::mutex mQueueSerialMutex;
mutable std::mutex mQueueSerialMutex;
mutable std::mutex mErrorMutex;
std::queue<Error> mErrors;
......@@ -323,6 +413,9 @@ class CommandProcessor : public Context
std::mutex mSwapchainStatusMutex;
std::condition_variable mSwapchainStatusCondition;
std::map<VkSwapchainKHR, VkResult> mSwapchainStatus;
// Command queue worker thread.
std::thread mTaskThread;
};
} // namespace vk
......
......@@ -527,9 +527,6 @@ void ContextVk::onDestroy(const gl::Context *context)
mShaderLibrary.destroy(device);
mGpuEventQueryPool.destroy(device);
mCommandPool.destroy(device);
// This will clean up any outstanding buffer allocations
(void)mRenderer->clearAllGarbage(this);
}
angle::Result ContextVk::getIncompleteTexture(const gl::Context *context,
......@@ -1842,13 +1839,12 @@ void ContextVk::flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpuT
void ContextVk::clearAllGarbage()
{
ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::finishAllWork");
ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::clearAllGarbage");
for (vk::GarbageObject &garbage : mCurrentGarbage)
{
garbage.destroy(mRenderer);
}
mCurrentGarbage.clear();
mRenderer->clearAllGarbage(this);
}
void ContextVk::handleDeviceLost()
......@@ -3035,7 +3031,7 @@ angle::Result ContextVk::onUnMakeCurrent(const gl::Context *context)
if (mRenderer->getFeatures().asyncCommandQueue.enabled)
{
ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::onUnMakeCurrent");
mRenderer->finishAllWork(this);
ANGLE_TRY(mRenderer->finishAllWork(this));
}
mCurrentWindowSurface = nullptr;
return angle::Result::Continue;
......
......@@ -260,10 +260,10 @@ void DisplayVk::handleError(VkResult result,
{
ASSERT(result != VK_SUCCESS);
mSavedError.mErrorCode = result;
mSavedError.mFile = file;
mSavedError.mFunction = function;
mSavedError.mLine = line;
mSavedError.errorCode = result;
mSavedError.file = file;
mSavedError.function = function;
mSavedError.line = line;
if (result == VK_ERROR_DEVICE_LOST)
{
......@@ -277,10 +277,9 @@ void DisplayVk::handleError(VkResult result,
egl::Error DisplayVk::getEGLError(EGLint errorCode)
{
std::stringstream errorStream;
errorStream << "Internal Vulkan error (" << mSavedError.mErrorCode
<< "): " << VulkanResultString(mSavedError.mErrorCode) << ", in "
<< mSavedError.mFile << ", " << mSavedError.mFunction << ":" << mSavedError.mLine
<< ".";
errorStream << "Internal Vulkan error (" << mSavedError.errorCode
<< "): " << VulkanResultString(mSavedError.errorCode) << ", in " << mSavedError.file
<< ", " << mSavedError.function << ":" << mSavedError.line << ".";
std::string errorString = errorStream.str();
return egl::Error(errorCode, 0, std::move(errorString));
......
......@@ -190,7 +190,7 @@ angle::Result QueryVk::getResult(const gl::Context *context, bool wait)
if (renderer->getFeatures().asyncCommandQueue.enabled)
{
// TODO: https://issuetracker.google.com/170312581 - For now just stalling here
renderer->waitForCommandProcessorIdle(contextVk);
ANGLE_TRY(renderer->waitForCommandProcessorIdle(contextVk));
}
ASSERT(!mQueryHelperTimeElapsedBegin.hasPendingWork(contextVk));
......
......@@ -511,15 +511,16 @@ void RendererVk::releaseSharedResources(vk::ResourceUseList *resourceList)
void RendererVk::onDestroy(vk::Context *context)
{
if (mFeatures.asyncCommandQueue.enabled)
{
// Shutdown worker thread
mCommandProcessor.shutdown(&mCommandProcessorThread);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
mCommandQueue.destroy(this);
if (mFeatures.asyncCommandQueue.enabled)
{
mCommandProcessor.destroy(context);
}
else
{
mCommandQueue.destroy(context);
}
}
// Assigns an infinite "last completed" serial to force garbage to delete.
......@@ -1495,9 +1496,7 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
if (mFeatures.asyncCommandQueue.enabled)
{
mCommandProcessorThread =
std::thread(&vk::CommandProcessor::processTasks, &mCommandProcessor, queueMap);
waitForCommandProcessorIdle(displayVk);
ANGLE_TRY(mCommandProcessor.init(displayVk, queueMap));
}
else
{
......@@ -2237,37 +2236,21 @@ angle::Result RendererVk::queueSubmitOneOff(vk::Context *context,
Serial *serialOut)
{
ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::queueSubmitOneOff");
Serial submitQueueSerial;
std::lock_guard<std::mutex> commandQueueLock(mCommandQueueMutex);
Serial submitQueueSerial;
if (mFeatures.asyncCommandQueue.enabled)
{
std::lock_guard<std::mutex> commandQueueLock(mCommandQueueMutex);
submitQueueSerial = mCommandProcessor.reserveSubmitSerial();
vk::CommandProcessorTask oneOffQueueSubmit;
oneOffQueueSubmit.initOneOffQueueSubmit(primary.getHandle(), priority, fence,
submitQueueSerial);
queueCommand(context, &oneOffQueueSubmit);
// TODO: https://issuetracker.google.com/170312581 - should go away with improved fence
// management
waitForCommandProcessorIdle(context);
ANGLE_TRY(mCommandProcessor.queueSubmitOneOff(context, priority, primary.getHandle(), fence,
submitQueueSerial));
}
else
{
std::lock_guard<std::mutex> commandQueueLock(mCommandQueueMutex);
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
if (primary.valid())
{
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = primary.ptr();
}
submitQueueSerial = mCommandQueue.reserveSubmitSerial();
ANGLE_TRY(
mCommandQueue.queueSubmit(context, priority, submitInfo, fence, submitQueueSerial));
ANGLE_TRY(mCommandQueue.queueSubmitOneOff(context, priority, primary.getHandle(), fence,
submitQueueSerial));
}
*serialOut = submitQueueSerial;
......@@ -2497,25 +2480,6 @@ angle::Result RendererVk::getCommandBufferOneOff(vk::Context *context,
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,
......@@ -2525,78 +2489,61 @@ angle::Result RendererVk::submitFrame(vk::Context *context,
vk::GarbageList &&currentGarbage,
vk::CommandPool *commandPool)
{
std::lock_guard<std::mutex> commandQueueLock(mCommandQueueMutex);
vk::Shared<vk::Fence> submitFence;
ANGLE_TRY(newSharedFence(context, &submitFence));
Serial submitQueueSerial;
if (mFeatures.asyncCommandQueue.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), submitQueueSerial);
commandProcessorSyncErrorsAndQueueCommand(context, &flushAndQueueSubmit);
ANGLE_TRY(mCommandProcessor.submitFrame(
context, contextPriority, waitSemaphores, waitSemaphoreStageMasks, signalSemaphore,
std::move(submitFence), std::move(currentGarbage), commandPool, submitQueueSerial));
}
else
{
std::lock_guard<std::mutex> commandQueueLock(mCommandQueueMutex);
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(currentGarbage), commandPool, submitQueueSerial));
waitSemaphores.clear();
waitSemaphoreStageMasks.clear();
}
waitSemaphores.clear();
waitSemaphoreStageMasks.clear();
resourceUseList.releaseResourceUsesAndUpdateSerials(submitQueueSerial);
return angle::Result::Continue;
}
void RendererVk::clearAllGarbage(vk::Context *context)
{
if (mFeatures.asyncCommandQueue.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()
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
if (mFeatures.asyncCommandQueue.enabled)
{
mCommandProcessor.handleDeviceLost();
mCommandProcessor.handleDeviceLost(this);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
mCommandQueue.handleDeviceLost(this);
}
}
angle::Result RendererVk::finishToSerial(vk::Context *context, Serial serial)
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
if (mFeatures.asyncCommandQueue.enabled)
{
mCommandProcessor.finishToSerial(context, serial);
ANGLE_TRY(mCommandProcessor.finishToSerial(context, serial, getMaxFenceWaitTimeNs()));
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
ANGLE_TRY(mCommandQueue.finishToSerial(context, serial, getMaxFenceWaitTimeNs()));
}
......@@ -2609,14 +2556,14 @@ angle::Result RendererVk::waitForSerialWithUserTimeout(vk::Context *context,
VkResult *result)
{
ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::waitForSerialWithUserTimeout");
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
if (mFeatures.asyncCommandQueue.enabled)
{
// TODO: https://issuetracker.google.com/170312581 - Wait with timeout.
mCommandProcessor.finishToSerial(context, serial);
ANGLE_TRY(mCommandProcessor.waitForSerialWithUserTimeout(context, serial, timeout, result));
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
ANGLE_TRY(mCommandQueue.waitForSerialWithUserTimeout(context, serial, timeout, result));
}
......@@ -2630,16 +2577,16 @@ angle::Result RendererVk::finish(vk::Context *context)
angle::Result RendererVk::checkCompletedCommands(vk::Context *context)
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
// 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.
if (mFeatures.asyncCommandQueue.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);
ANGLE_TRY(mCommandProcessor.checkCompletedCommands(context));
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
ANGLE_TRY(mCommandQueue.checkCompletedCommands(context));
}
......@@ -2651,18 +2598,16 @@ angle::Result RendererVk::flushRenderPassCommands(vk::Context *context,
vk::CommandBufferHelper **renderPassCommands)
{
ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::flushRenderPassCommands");
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
if (mFeatures.asyncCommandQueue.enabled)
{
(*renderPassCommands)->markClosed();
vk::CommandProcessorTask flushToPrimary;
flushToPrimary.initProcessCommands(*renderPassCommands, &renderPass);
commandProcessorSyncErrorsAndQueueCommand(context, &flushToPrimary);
*renderPassCommands = getCommandBufferHelper(true);
ANGLE_TRY(
mCommandProcessor.flushRenderPassCommands(context, renderPass, renderPassCommands));
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
ANGLE_TRY(mCommandQueue.flushRenderPassCommands(context, renderPass, *renderPassCommands));
ANGLE_TRY(mCommandQueue.flushRenderPassCommands(context, renderPass, renderPassCommands));
}
return angle::Result::Continue;
......@@ -2672,18 +2617,15 @@ angle::Result RendererVk::flushOutsideRPCommands(vk::Context *context,
vk::CommandBufferHelper **outsideRPCommands)
{
ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::flushOutsideRPCommands");
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
if (mFeatures.asyncCommandQueue.enabled)
{
(*outsideRPCommands)->markClosed();
vk::CommandProcessorTask flushToPrimary;
flushToPrimary.initProcessCommands(*outsideRPCommands, nullptr);
commandProcessorSyncErrorsAndQueueCommand(context, &flushToPrimary);
*outsideRPCommands = getCommandBufferHelper(false);
ANGLE_TRY(mCommandProcessor.flushOutsideRPCommands(context, outsideRPCommands));
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
ANGLE_TRY(mCommandQueue.flushOutsideRPCommands(context, *outsideRPCommands));
ANGLE_TRY(mCommandQueue.flushOutsideRPCommands(context, outsideRPCommands));
}
return angle::Result::Continue;
......@@ -2693,22 +2635,15 @@ VkResult RendererVk::queuePresent(vk::Context *context,
egl::ContextPriority priority,
const VkPresentInfoKHR &presentInfo)
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
VkResult result = VK_SUCCESS;
if (mFeatures.asyncCommandQueue.enabled)
{
vk::CommandProcessorTask present;
present.initPresent(priority, presentInfo);
ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::present");
queueCommand(context, &present);
// Always return success, when we call acquireNextImage we'll check the return code. This
// allows the app to continue working until we really need to know the return code from
// present.
result = mCommandProcessor.queuePresent(priority, presentInfo);
}
else
{
std::lock_guard<std::mutex> lock(mCommandQueueMutex);
result = mCommandQueue.queuePresent(priority, presentInfo);
}
......
......@@ -281,21 +281,20 @@ class RendererVk : angle::NonCopyable
SamplerYcbcrConversionCache &getYuvConversionCache() { return mYuvConversionCache; }
vk::ActiveHandleCounter &getActiveHandleCounts() { return mActiveHandleCounts; }
// Queue commands to worker thread for processing
void queueCommand(vk::Context *context, vk::CommandProcessorTask *command)
// TODO(jmadill): Remove. b/172704839
angle::Result waitForCommandProcessorIdle(vk::Context *context)
{
mCommandProcessor.queueCommand(context, command);
ASSERT(getFeatures().asyncCommandQueue.enabled);
return mCommandProcessor.waitForWorkComplete(context);
}
bool hasPendingError() const { return mCommandProcessor.hasPendingError(); }
vk::Error getAndClearPendingError() { return mCommandProcessor.getAndClearPendingError(); }
void waitForCommandProcessorIdle(vk::Context *context)
// TODO(jmadill): Remove. b/172704839
angle::Result finishAllWork(vk::Context *context)
{
ASSERT(getFeatures().asyncCommandQueue.enabled);
mCommandProcessor.waitForWorkComplete(context);
return mCommandProcessor.finishAllWork(context);
}
void finishAllWork(vk::Context *context) { mCommandProcessor.finishAllWork(context); }
bool getEnableValidationLayers() const { return mEnableValidationLayers; }
vk::ResourceSerialFactory &getResourceSerialFactory() { return mResourceSerialFactory; }
......@@ -315,7 +314,6 @@ class RendererVk : angle::NonCopyable
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,
......@@ -357,12 +355,6 @@ class RendererVk : angle::NonCopyable
template <VkFormatFeatureFlags VkFormatProperties::*features>
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;
mutable bool mCapsInitialized;
......@@ -456,9 +448,8 @@ class RendererVk : angle::NonCopyable
std::mutex mCommandBufferHelperFreeListMutex;
std::vector<vk::CommandBufferHelper *> mCommandBufferHelperFreeList;
// Command Processor Thread
// Async Command Queue
vk::CommandProcessor mCommandProcessor;
std::thread mCommandProcessorThread;
// mNextSubmitFence 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).
vk::Shared<vk::Fence> mNextSubmitFence;
......
......@@ -37,7 +37,7 @@ void SyncHelper::releaseToRenderer(RendererVk *renderer)
if (renderer->getFeatures().asyncCommandQueue.enabled)
{
ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelper::releaseToRenderer");
renderer->waitForCommandProcessorIdle(nullptr);
(void)renderer->waitForCommandProcessorIdle(nullptr);
}
}
......@@ -272,7 +272,7 @@ angle::Result SyncHelperNativeFence::clientWait(Context *context,
if (contextVk->getRenderer()->getFeatures().asyncCommandQueue.enabled)
{
ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelperNativeFence::clientWait");
contextVk->getRenderer()->waitForCommandProcessorIdle(contextVk);
ANGLE_TRY(contextVk->getRenderer()->waitForCommandProcessorIdle(contextVk));
}
// Wait for mFenceWithFd to be signaled.
......
......@@ -156,10 +156,10 @@ void AddToPNextChain(VulkanStruct1 *chainStart, VulkanStruct2 *ptr)
struct Error
{
VkResult mErrorCode;
const char *mFile;
const char *mFunction;
unsigned int mLine;
VkResult errorCode;
const char *file;
const char *function;
uint32_t line;
};
// Abstracts error handling. Implemented by both ContextVk for GL and DisplayVk for EGL errors.
......
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