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