• 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.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 &&currentGarbage,
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 &&currentGarbage,
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 &&currentGarbage,
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 &&currentGarbage,
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