• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // CommandProcessor.cpp:
7 //    Implements the class methods for CommandProcessor.
8 //
9 
10 #include "libANGLE/renderer/vulkan/CommandProcessor.h"
11 #include "libANGLE/trace.h"
12 
13 namespace rx
14 {
15 
CommandProcessor()16 CommandProcessor::CommandProcessor() : mWorkerThreadIdle(true) {}
17 
queueCommands(const vk::CommandProcessorTask & commands)18 void CommandProcessor::queueCommands(const vk::CommandProcessorTask &commands)
19 {
20     ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::queueCommands");
21     std::lock_guard<std::mutex> queueLock(mWorkerMutex);
22     ASSERT(commands.commandBuffer == nullptr || !commands.commandBuffer->empty());
23     mCommandsQueue.push(commands);
24     mWorkAvailableCondition.notify_one();
25 }
26 
processCommandProcessorTasks()27 angle::Result CommandProcessor::processCommandProcessorTasks()
28 {
29     while (true)
30     {
31         std::unique_lock<std::mutex> lock(mWorkerMutex);
32         mWorkerIdleCondition.notify_one();
33         mWorkerThreadIdle = true;
34         // Only wake if notified and command queue is not empty
35         mWorkAvailableCondition.wait(lock, [this] { return !mCommandsQueue.empty(); });
36         mWorkerThreadIdle             = false;
37         vk::CommandProcessorTask task = mCommandsQueue.front();
38         mCommandsQueue.pop();
39         lock.unlock();
40         // Either both ptrs should be null or non-null
41         ASSERT((task.commandBuffer != nullptr && task.contextVk != nullptr) ||
42                (task.commandBuffer == nullptr && task.contextVk == nullptr));
43         // A work block with null ptrs signals worker thread to exit
44         if (task.commandBuffer == nullptr && task.contextVk == nullptr)
45         {
46             break;
47         }
48 
49         ASSERT(!task.commandBuffer->empty());
50         // TODO: Will need some way to synchronize error reporting between threads
51         ANGLE_TRY(task.commandBuffer->flushToPrimary(task.contextVk, task.primaryCB));
52         ASSERT(task.commandBuffer->empty());
53         task.commandBuffer->releaseToContextQueue(task.contextVk);
54     }
55     return angle::Result::Continue;
56 }
57 
waitForWorkComplete()58 void CommandProcessor::waitForWorkComplete()
59 {
60     ANGLE_TRACE_EVENT0("gpu.angle", "CommandProcessor::waitForWorkerThreadIdle");
61     std::unique_lock<std::mutex> lock(mWorkerMutex);
62     mWorkerIdleCondition.wait(lock,
63                               [this] { return (mCommandsQueue.empty() && mWorkerThreadIdle); });
64     // Worker thread is idle and command queue is empty so good to continue
65     lock.unlock();
66 }
67 
shutdown(std::thread * commandProcessorThread)68 void CommandProcessor::shutdown(std::thread *commandProcessorThread)
69 {
70     waitForWorkComplete();
71     const vk::CommandProcessorTask endTask = vk::kEndCommandProcessorThread;
72     queueCommands(endTask);
73     if (commandProcessorThread->joinable())
74     {
75         commandProcessorThread->join();
76     }
77 }
78 }  // namespace rx
79