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()16CommandProcessor::CommandProcessor() : mWorkerThreadIdle(true) {} 17 queueCommands(const vk::CommandProcessorTask & commands)18void 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()27angle::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()58void 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)68void 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