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.h: 7 // A class to process and submit Vulkan command buffers that can be 8 // used in an asynchronous worker thread. 9 // 10 11 #ifndef LIBANGLE_RENDERER_VULKAN_COMMAND_PROCESSOR_H_ 12 #define LIBANGLE_RENDERER_VULKAN_COMMAND_PROCESSOR_H_ 13 14 #include <condition_variable> 15 #include <mutex> 16 #include <queue> 17 #include <thread> 18 19 #include "common/vulkan/vk_headers.h" 20 #include "libANGLE/renderer/vulkan/PersistentCommandPool.h" 21 #include "libANGLE/renderer/vulkan/vk_helpers.h" 22 23 namespace rx 24 { 25 class RendererVk; 26 class CommandProcessor; 27 28 namespace vk 29 { 30 enum class SubmitPolicy 31 { 32 AllowDeferred, 33 EnsureSubmitted, 34 }; 35 36 class FenceRecycler 37 { 38 public: FenceRecycler()39 FenceRecycler() {} ~FenceRecycler()40 ~FenceRecycler() {} 41 void destroy(vk::Context *context); 42 43 angle::Result newSharedFence(vk::Context *context, vk::Shared<vk::Fence> *sharedFenceOut); resetSharedFence(vk::Shared<vk::Fence> * sharedFenceIn)44 inline void resetSharedFence(vk::Shared<vk::Fence> *sharedFenceIn) 45 { 46 std::lock_guard<std::mutex> lock(mMutex); 47 sharedFenceIn->resetAndRecycle(&mRecyler); 48 } 49 50 private: 51 std::mutex mMutex; 52 vk::Recycler<vk::Fence> mRecyler; 53 }; 54 55 enum class CustomTask 56 { 57 Invalid = 0, 58 // Process SecondaryCommandBuffer commands into the primary CommandBuffer. 59 ProcessOutsideRenderPassCommands, 60 ProcessRenderPassCommands, 61 // End the current command buffer and submit commands to the queue 62 FlushAndQueueSubmit, 63 // Submit custom command buffer, excludes some state management 64 OneOffQueueSubmit, 65 // Finish queue commands up to given serial value, process garbage 66 FinishToSerial, 67 // Finish all pending work 68 WaitIdle, 69 // Execute QueuePresent 70 Present, 71 // do cleanup processing on completed commands 72 // TODO: https://issuetracker.google.com/170312581 - should be able to remove 73 // checkCompletedCommands command with fence refactor. 74 CheckCompletedCommands, 75 // Exit the command processor thread 76 Exit, 77 }; 78 79 // CommandProcessorTask interface 80 class CommandProcessorTask 81 { 82 public: CommandProcessorTask()83 CommandProcessorTask() { initTask(); } 84 85 void initTask(); 86 initTask(CustomTask command)87 void initTask(CustomTask command) { mTask = command; } 88 89 void initOutsideRenderPassProcessCommands(bool hasProtectedContent, 90 OutsideRenderPassCommandBufferHelper *commandBuffer); 91 92 void initRenderPassProcessCommands(bool hasProtectedContent, 93 RenderPassCommandBufferHelper *commandBuffer, 94 const RenderPass *renderPass); 95 96 void initPresent(egl::ContextPriority priority, const VkPresentInfoKHR &presentInfo); 97 98 void initFinishToSerial(Serial serial); 99 100 void initWaitIdle(); 101 102 void initFlushAndQueueSubmit(const std::vector<VkSemaphore> &waitSemaphores, 103 const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks, 104 const Semaphore *semaphore, 105 bool hasProtectedContent, 106 egl::ContextPriority priority, 107 SecondaryCommandPools *commandPools, 108 GarbageList &¤tGarbage, 109 SecondaryCommandBufferList &&commandBuffersToReset, 110 Serial submitQueueSerial); 111 112 void initOneOffQueueSubmit(VkCommandBuffer commandBufferHandle, 113 bool hasProtectedContent, 114 egl::ContextPriority priority, 115 const Semaphore *waitSemaphore, 116 VkPipelineStageFlags waitSemaphoreStageMask, 117 const Fence *fence, 118 Serial submitQueueSerial); 119 120 CommandProcessorTask &operator=(CommandProcessorTask &&rhs); 121 CommandProcessorTask(CommandProcessorTask && other)122 CommandProcessorTask(CommandProcessorTask &&other) : CommandProcessorTask() 123 { 124 *this = std::move(other); 125 } 126 setQueueSerial(Serial serial)127 void setQueueSerial(Serial serial) { mSerial = serial; } getQueueSerial()128 Serial getQueueSerial() const { return mSerial; } getTaskCommand()129 CustomTask getTaskCommand() { return mTask; } getWaitSemaphores()130 std::vector<VkSemaphore> &getWaitSemaphores() { return mWaitSemaphores; } getWaitSemaphoreStageMasks()131 std::vector<VkPipelineStageFlags> &getWaitSemaphoreStageMasks() 132 { 133 return mWaitSemaphoreStageMasks; 134 } getSemaphore()135 const Semaphore *getSemaphore() { return mSemaphore; } getGarbage()136 GarbageList &getGarbage() { return mGarbage; } getCommandBuffersToReset()137 SecondaryCommandBufferList &&getCommandBuffersToReset() 138 { 139 return std::move(mCommandBuffersToReset); 140 } getPriority()141 egl::ContextPriority getPriority() const { return mPriority; } hasProtectedContent()142 bool hasProtectedContent() const { return mHasProtectedContent; } getOneOffCommandBufferVk()143 VkCommandBuffer getOneOffCommandBufferVk() const { return mOneOffCommandBufferVk; } getOneOffWaitSemaphore()144 const Semaphore *getOneOffWaitSemaphore() { return mOneOffWaitSemaphore; } getOneOffWaitSemaphoreStageMask()145 VkPipelineStageFlags getOneOffWaitSemaphoreStageMask() { return mOneOffWaitSemaphoreStageMask; } getOneOffFence()146 const Fence *getOneOffFence() { return mOneOffFence; } getPresentInfo()147 const VkPresentInfoKHR &getPresentInfo() const { return mPresentInfo; } getRenderPass()148 const RenderPass *getRenderPass() const { return mRenderPass; } getOutsideRenderPassCommandBuffer()149 OutsideRenderPassCommandBufferHelper *getOutsideRenderPassCommandBuffer() const 150 { 151 return mOutsideRenderPassCommandBuffer; 152 } getRenderPassCommandBuffer()153 RenderPassCommandBufferHelper *getRenderPassCommandBuffer() const 154 { 155 return mRenderPassCommandBuffer; 156 } getCommandPools()157 SecondaryCommandPools *getCommandPools() const { return mCommandPools; } 158 159 private: 160 void copyPresentInfo(const VkPresentInfoKHR &other); 161 162 CustomTask mTask; 163 164 // ProcessCommands 165 OutsideRenderPassCommandBufferHelper *mOutsideRenderPassCommandBuffer; 166 RenderPassCommandBufferHelper *mRenderPassCommandBuffer; 167 const RenderPass *mRenderPass; 168 169 // Flush data 170 std::vector<VkSemaphore> mWaitSemaphores; 171 std::vector<VkPipelineStageFlags> mWaitSemaphoreStageMasks; 172 const Semaphore *mSemaphore; 173 SecondaryCommandPools *mCommandPools; 174 GarbageList mGarbage; 175 SecondaryCommandBufferList mCommandBuffersToReset; 176 177 // FinishToSerial & Flush command data 178 Serial mSerial; 179 180 // Present command data 181 VkPresentInfoKHR mPresentInfo; 182 VkSwapchainKHR mSwapchain; 183 VkSemaphore mWaitSemaphore; 184 uint32_t mImageIndex; 185 // Used by Present if supportsIncrementalPresent is enabled 186 VkPresentRegionKHR mPresentRegion; 187 VkPresentRegionsKHR mPresentRegions; 188 std::vector<VkRectLayerKHR> mRects; 189 190 // Used by OneOffQueueSubmit 191 VkCommandBuffer mOneOffCommandBufferVk; 192 const Semaphore *mOneOffWaitSemaphore; 193 VkPipelineStageFlags mOneOffWaitSemaphoreStageMask; 194 const Fence *mOneOffFence; 195 196 // Flush, Present & QueueWaitIdle data 197 egl::ContextPriority mPriority; 198 bool mHasProtectedContent; 199 }; 200 201 struct CommandBatch final : angle::NonCopyable 202 { 203 CommandBatch(); 204 ~CommandBatch(); 205 CommandBatch(CommandBatch &&other); 206 CommandBatch &operator=(CommandBatch &&other); 207 208 void destroy(VkDevice device); 209 void resetSecondaryCommandBuffers(VkDevice device); 210 211 PrimaryCommandBuffer primaryCommands; 212 // commandPools is for secondary CommandBuffer allocation 213 SecondaryCommandPools *commandPools; 214 SecondaryCommandBufferList commandBuffersToReset; 215 Shared<Fence> fence; 216 Serial serial; 217 bool hasProtectedContent; 218 }; 219 220 class DeviceQueueMap; 221 222 class QueueFamily final : angle::NonCopyable 223 { 224 public: 225 static const uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max(); 226 227 static uint32_t FindIndex(const std::vector<VkQueueFamilyProperties> &queueFamilyProperties, 228 VkQueueFlags flags, 229 int32_t matchNumber, // 0 = first match, 1 = second match ... 230 uint32_t *matchCount); 231 static const uint32_t kQueueCount = static_cast<uint32_t>(egl::ContextPriority::EnumCount); 232 static const float kQueuePriorities[static_cast<uint32_t>(egl::ContextPriority::EnumCount)]; 233 QueueFamily()234 QueueFamily() : mProperties{}, mIndex(kInvalidIndex) {} ~QueueFamily()235 ~QueueFamily() {} 236 237 void initialize(const VkQueueFamilyProperties &queueFamilyProperties, uint32_t index); valid()238 bool valid() const { return (mIndex != kInvalidIndex); } getIndex()239 uint32_t getIndex() const { return mIndex; } getProperties()240 const VkQueueFamilyProperties *getProperties() const { return &mProperties; } isGraphics()241 bool isGraphics() const { return ((mProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) > 0); } isCompute()242 bool isCompute() const { return ((mProperties.queueFlags & VK_QUEUE_COMPUTE_BIT) > 0); } supportsProtected()243 bool supportsProtected() const 244 { 245 return ((mProperties.queueFlags & VK_QUEUE_PROTECTED_BIT) > 0); 246 } getDeviceQueueCount()247 uint32_t getDeviceQueueCount() const { return mProperties.queueCount; } 248 249 DeviceQueueMap initializeQueueMap(VkDevice device, 250 bool makeProtected, 251 uint32_t queueIndex, 252 uint32_t queueCount); 253 254 private: 255 VkQueueFamilyProperties mProperties; 256 uint32_t mIndex; 257 258 void getDeviceQueue(VkDevice device, bool makeProtected, uint32_t queueIndex, VkQueue *queue); 259 }; 260 261 class DeviceQueueMap : public angle::PackedEnumMap<egl::ContextPriority, VkQueue> 262 { 263 friend QueueFamily; 264 265 public: DeviceQueueMap()266 DeviceQueueMap() : mIndex(vk::QueueFamily::kInvalidIndex), mIsProtected(false) {} DeviceQueueMap(uint32_t queueFamilyIndex,bool isProtected)267 DeviceQueueMap(uint32_t queueFamilyIndex, bool isProtected) 268 : mIndex(queueFamilyIndex), mIsProtected(isProtected) 269 {} 270 ~DeviceQueueMap(); 271 DeviceQueueMap &operator=(const DeviceQueueMap &other); 272 valid()273 bool valid() const { return (mIndex != QueueFamily::kInvalidIndex); } getIndex()274 uint32_t getIndex() const { return mIndex; } isProtected()275 bool isProtected() const { return mIsProtected; } 276 egl::ContextPriority getDevicePriority(egl::ContextPriority priority) const; 277 278 private: 279 uint32_t mIndex; 280 bool mIsProtected; 281 angle::PackedEnumMap<egl::ContextPriority, egl::ContextPriority> mPriorities; 282 }; 283 284 class CommandQueueInterface : angle::NonCopyable 285 { 286 public: ~CommandQueueInterface()287 virtual ~CommandQueueInterface() {} 288 289 virtual angle::Result init(Context *context, const DeviceQueueMap &queueMap) = 0; 290 virtual void destroy(Context *context) = 0; 291 292 virtual void handleDeviceLost(RendererVk *renderer) = 0; 293 294 // Wait until the desired serial has been completed. 295 virtual angle::Result finishToSerial(Context *context, 296 Serial finishSerial, 297 uint64_t timeout) = 0; 298 virtual angle::Result waitIdle(Context *context, uint64_t timeout) = 0; 299 virtual Serial reserveSubmitSerial() = 0; 300 virtual angle::Result submitFrame( 301 Context *context, 302 bool hasProtectedContent, 303 egl::ContextPriority priority, 304 const std::vector<VkSemaphore> &waitSemaphores, 305 const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks, 306 const Semaphore *signalSemaphore, 307 GarbageList &¤tGarbage, 308 SecondaryCommandBufferList &&commandBuffersToReset, 309 SecondaryCommandPools *commandPools, 310 Serial submitQueueSerial) = 0; 311 virtual angle::Result queueSubmitOneOff(Context *context, 312 bool hasProtectedContent, 313 egl::ContextPriority contextPriority, 314 VkCommandBuffer commandBufferHandle, 315 const Semaphore *waitSemaphore, 316 VkPipelineStageFlags waitSemaphoreStageMask, 317 const Fence *fence, 318 SubmitPolicy submitPolicy, 319 Serial submitQueueSerial) = 0; 320 virtual VkResult queuePresent(egl::ContextPriority contextPriority, 321 const VkPresentInfoKHR &presentInfo) = 0; 322 323 virtual angle::Result waitForSerialWithUserTimeout(vk::Context *context, 324 Serial serial, 325 uint64_t timeout, 326 VkResult *result) = 0; 327 328 // Check to see which batches have finished completion (forward progress for 329 // the last completed serial, for example for when the application busy waits on a query 330 // result). It would be nice if we didn't have to expose this for QueryVk::getResult. 331 virtual angle::Result checkCompletedCommands(Context *context) = 0; 332 333 virtual angle::Result flushOutsideRPCommands( 334 Context *context, 335 bool hasProtectedContent, 336 OutsideRenderPassCommandBufferHelper **outsideRPCommands) = 0; 337 virtual angle::Result flushRenderPassCommands( 338 Context *context, 339 bool hasProtectedContent, 340 const RenderPass &renderPass, 341 RenderPassCommandBufferHelper **renderPassCommands) = 0; 342 343 // For correct synchronization with external, in particular when asked to signal an external 344 // semaphore, we need to ensure that there are no pending submissions. 345 virtual angle::Result ensureNoPendingWork(Context *context) = 0; 346 347 virtual Serial getLastCompletedQueueSerial() const = 0; 348 virtual bool isBusy() const = 0; 349 }; 350 351 class CommandQueue final : public CommandQueueInterface 352 { 353 public: 354 CommandQueue(); 355 ~CommandQueue() override; 356 357 angle::Result init(Context *context, const DeviceQueueMap &queueMap) override; 358 void destroy(Context *context) override; 359 void clearAllGarbage(RendererVk *renderer); 360 361 void handleDeviceLost(RendererVk *renderer) override; 362 363 angle::Result finishToSerial(Context *context, Serial finishSerial, uint64_t timeout) override; 364 angle::Result waitIdle(Context *context, uint64_t timeout) override; 365 366 Serial reserveSubmitSerial() override; 367 368 angle::Result submitFrame(Context *context, 369 bool hasProtectedContent, 370 egl::ContextPriority priority, 371 const std::vector<VkSemaphore> &waitSemaphores, 372 const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks, 373 const Semaphore *signalSemaphore, 374 GarbageList &¤tGarbage, 375 SecondaryCommandBufferList &&commandBuffersToReset, 376 SecondaryCommandPools *commandPools, 377 Serial submitQueueSerial) override; 378 379 angle::Result queueSubmitOneOff(Context *context, 380 bool hasProtectedContent, 381 egl::ContextPriority contextPriority, 382 VkCommandBuffer commandBufferHandle, 383 const Semaphore *waitSemaphore, 384 VkPipelineStageFlags waitSemaphoreStageMask, 385 const Fence *fence, 386 SubmitPolicy submitPolicy, 387 Serial submitQueueSerial) override; 388 389 VkResult queuePresent(egl::ContextPriority contextPriority, 390 const VkPresentInfoKHR &presentInfo) override; 391 392 angle::Result waitForSerialWithUserTimeout(vk::Context *context, 393 Serial serial, 394 uint64_t timeout, 395 VkResult *result) override; 396 397 angle::Result checkCompletedCommands(Context *context) override; 398 399 angle::Result flushOutsideRPCommands( 400 Context *context, 401 bool hasProtectedContent, 402 OutsideRenderPassCommandBufferHelper **outsideRPCommands) override; 403 angle::Result flushRenderPassCommands( 404 Context *context, 405 bool hasProtectedContent, 406 const RenderPass &renderPass, 407 RenderPassCommandBufferHelper **renderPassCommands) override; 408 ensureNoPendingWork(Context * context)409 angle::Result ensureNoPendingWork(Context *context) override { return angle::Result::Continue; } 410 411 Serial getLastCompletedQueueSerial() const override; 412 bool isBusy() const override; 413 414 angle::Result queueSubmit(Context *context, 415 egl::ContextPriority contextPriority, 416 const VkSubmitInfo &submitInfo, 417 const Fence *fence, 418 Serial submitQueueSerial); 419 getDriverPriority(egl::ContextPriority priority)420 egl::ContextPriority getDriverPriority(egl::ContextPriority priority) 421 { 422 return mQueueMap.getDevicePriority(priority); 423 } getDeviceQueueIndex()424 uint32_t getDeviceQueueIndex() const { return mQueueMap.getIndex(); } 425 getQueue(egl::ContextPriority priority)426 VkQueue getQueue(egl::ContextPriority priority) { return mQueueMap[priority]; } 427 428 private: 429 void releaseToCommandBatch(bool hasProtectedContent, 430 PrimaryCommandBuffer &&commandBuffer, 431 SecondaryCommandPools *commandPools, 432 CommandBatch *batch); 433 angle::Result retireFinishedCommands(Context *context, size_t finishedCount); 434 angle::Result ensurePrimaryCommandBufferValid(Context *context, bool hasProtectedContent); 435 436 bool allInFlightCommandsAreAfterSerial(Serial serial); 437 getCommandBuffer(bool hasProtectedContent)438 PrimaryCommandBuffer &getCommandBuffer(bool hasProtectedContent) 439 { 440 if (hasProtectedContent) 441 { 442 return mProtectedPrimaryCommands; 443 } 444 else 445 { 446 return mPrimaryCommands; 447 } 448 } 449 getCommandPool(bool hasProtectedContent)450 PersistentCommandPool &getCommandPool(bool hasProtectedContent) 451 { 452 if (hasProtectedContent) 453 { 454 return mProtectedPrimaryCommandPool; 455 } 456 else 457 { 458 return mPrimaryCommandPool; 459 } 460 } 461 462 GarbageQueue mGarbageQueue; 463 464 std::vector<CommandBatch> mInFlightCommands; 465 466 // Keeps a free list of reusable primary command buffers. 467 PrimaryCommandBuffer mPrimaryCommands; 468 PersistentCommandPool mPrimaryCommandPool; 469 PrimaryCommandBuffer mProtectedPrimaryCommands; 470 PersistentCommandPool mProtectedPrimaryCommandPool; 471 472 // Queue serial management. 473 AtomicSerialFactory mQueueSerialFactory; 474 Serial mLastCompletedQueueSerial; 475 Serial mLastSubmittedQueueSerial; 476 Serial mCurrentQueueSerial; 477 478 // QueueMap 479 DeviceQueueMap mQueueMap; 480 481 FenceRecycler mFenceRecycler; 482 }; 483 484 // CommandProcessor is used to dispatch work to the GPU when the asyncCommandQueue feature is 485 // enabled. Issuing the |destroy| command will cause the worker thread to clean up it's resources 486 // and shut down. This command is sent when the renderer instance shuts down. Tasks are defined by 487 // the CommandQueue interface. 488 489 class CommandProcessor final : public Context, public CommandQueueInterface 490 { 491 public: 492 CommandProcessor(RendererVk *renderer); 493 ~CommandProcessor() override; 494 getLastPresentResult(VkSwapchainKHR swapchain)495 VkResult getLastPresentResult(VkSwapchainKHR swapchain) 496 { 497 return getLastAndClearPresentResult(swapchain); 498 } 499 500 // vk::Context 501 void handleError(VkResult result, 502 const char *file, 503 const char *function, 504 unsigned int line) override; 505 506 // CommandQueueInterface 507 angle::Result init(Context *context, const DeviceQueueMap &queueMap) override; 508 509 void destroy(Context *context) override; 510 511 void handleDeviceLost(RendererVk *renderer) override; 512 513 angle::Result finishToSerial(Context *context, Serial finishSerial, uint64_t timeout) override; 514 515 angle::Result waitIdle(Context *context, uint64_t timeout) override; 516 517 Serial reserveSubmitSerial() override; 518 519 angle::Result submitFrame(Context *context, 520 bool hasProtectedContent, 521 egl::ContextPriority priority, 522 const std::vector<VkSemaphore> &waitSemaphores, 523 const std::vector<VkPipelineStageFlags> &waitSemaphoreStageMasks, 524 const Semaphore *signalSemaphore, 525 GarbageList &¤tGarbage, 526 SecondaryCommandBufferList &&commandBuffersToReset, 527 SecondaryCommandPools *commandPools, 528 Serial submitQueueSerial) override; 529 530 angle::Result queueSubmitOneOff(Context *context, 531 bool hasProtectedContent, 532 egl::ContextPriority contextPriority, 533 VkCommandBuffer commandBufferHandle, 534 const Semaphore *waitSemaphore, 535 VkPipelineStageFlags waitSemaphoreStageMask, 536 const Fence *fence, 537 SubmitPolicy submitPolicy, 538 Serial submitQueueSerial) override; 539 VkResult queuePresent(egl::ContextPriority contextPriority, 540 const VkPresentInfoKHR &presentInfo) override; 541 542 angle::Result waitForSerialWithUserTimeout(vk::Context *context, 543 Serial serial, 544 uint64_t timeout, 545 VkResult *result) override; 546 547 angle::Result checkCompletedCommands(Context *context) override; 548 549 angle::Result flushOutsideRPCommands( 550 Context *context, 551 bool hasProtectedContent, 552 OutsideRenderPassCommandBufferHelper **outsideRPCommands) override; 553 angle::Result flushRenderPassCommands( 554 Context *context, 555 bool hasProtectedContent, 556 const RenderPass &renderPass, 557 RenderPassCommandBufferHelper **renderPassCommands) override; 558 559 angle::Result ensureNoPendingWork(Context *context) override; 560 561 Serial getLastCompletedQueueSerial() const override; 562 bool isBusy() const override; 563 getDriverPriority(egl::ContextPriority priority)564 egl::ContextPriority getDriverPriority(egl::ContextPriority priority) 565 { 566 return mCommandQueue.getDriverPriority(priority); 567 } getDeviceQueueIndex()568 uint32_t getDeviceQueueIndex() const { return mCommandQueue.getDeviceQueueIndex(); } getQueue(egl::ContextPriority priority)569 VkQueue getQueue(egl::ContextPriority priority) { return mCommandQueue.getQueue(priority); } 570 571 private: hasPendingError()572 bool hasPendingError() const 573 { 574 std::lock_guard<std::mutex> queueLock(mErrorMutex); 575 return !mErrors.empty(); 576 } 577 angle::Result checkAndPopPendingError(Context *errorHandlingContext); 578 579 // Entry point for command processor thread, calls processTasksImpl to do the 580 // work. called by RendererVk::initializeDevice on main thread 581 void processTasks(); 582 583 // Called asynchronously from main thread to queue work that is then processed by the worker 584 // thread 585 void queueCommand(CommandProcessorTask &&task); 586 587 // Command processor thread, called by processTasks. The loop waits for work to 588 // be submitted from a separate thread. 589 angle::Result processTasksImpl(bool *exitThread); 590 591 // Command processor thread, process a task 592 angle::Result processTask(CommandProcessorTask *task); 593 594 VkResult getLastAndClearPresentResult(VkSwapchainKHR swapchain); 595 VkResult present(egl::ContextPriority priority, const VkPresentInfoKHR &presentInfo); 596 597 // Used by main thread to wait for worker thread to complete all outstanding work. 598 angle::Result waitForWorkComplete(Context *context); 599 600 std::queue<CommandProcessorTask> mTasks; 601 mutable std::mutex mWorkerMutex; 602 // Signal worker thread when work is available 603 std::condition_variable mWorkAvailableCondition; 604 // Signal main thread when all work completed 605 mutable std::condition_variable mWorkerIdleCondition; 606 // Track worker thread Idle state for assertion purposes 607 bool mWorkerThreadIdle; 608 CommandQueue mCommandQueue; 609 610 mutable std::mutex mQueueSerialMutex; 611 612 mutable std::mutex mErrorMutex; 613 std::queue<Error> mErrors; 614 615 // Track present info 616 std::mutex mSwapchainStatusMutex; 617 std::condition_variable mSwapchainStatusCondition; 618 std::map<VkSwapchainKHR, VkResult> mSwapchainStatus; 619 620 // Command queue worker thread. 621 std::thread mTaskThread; 622 }; 623 624 // An RAII wrapper for locking and unlocking the command-queue mutex. On destructor, this class 625 // handles device loss, if it has happened. This is because handling device loss affects the 626 // command queue state, so it's deferred until the current scope that's using the command queue 627 // state is finished. 628 class ANGLE_NO_DISCARD ScopedCommandQueueLock final 629 { 630 public: ScopedCommandQueueLock(RendererVk * renderer,std::mutex & lock)631 ScopedCommandQueueLock(RendererVk *renderer, std::mutex &lock) 632 : mRenderer(renderer), mLock(lock) 633 { 634 lock.lock(); 635 } 636 ~ScopedCommandQueueLock(); 637 638 private: 639 RendererVk *mRenderer; 640 std::mutex &mLock; 641 }; 642 643 } // namespace vk 644 645 } // namespace rx 646 647 #endif // LIBANGLE_RENDERER_VULKAN_COMMAND_PROCESSOR_H_ 648