|  | // Copyright 2019 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef SRC_UI_LIB_ESCHER_VK_CHAINED_SEMAPHORE_GENERATOR_H_ | 
|  | #define SRC_UI_LIB_ESCHER_VK_CHAINED_SEMAPHORE_GENERATOR_H_ | 
|  |  | 
|  | #include "src/lib/fxl/memory/weak_ptr.h" | 
|  | #include "src/ui/lib/escher/renderer/semaphore.h" | 
|  |  | 
|  | #include <vulkan/vulkan.hpp> | 
|  |  | 
|  | namespace escher { | 
|  |  | 
|  | // Forward declaration. | 
|  | class ChainedSemaphoreGenerator; | 
|  | using ChainedSemaphoreGeneratorWeakPtr = fxl::WeakPtr<ChainedSemaphoreGenerator>; | 
|  |  | 
|  | // ChainedSemaphoreGenerator is used for generating VkSemaphores for | 
|  | // synchronizing between gfx::Engine, gfx::Screenshotter, and gfx::Snaphshotter. | 
|  | // | 
|  | // Each time the caller calls TakeLastAndCreateNextSemaphore() to get a pair of | 
|  | // VkSemaphore, which it will wait on |semaphore_to_wait| before executing | 
|  | // its command and signal |semaphore_to_signal| after finishing execution. When | 
|  | // the next caller calls this function, the caller will wait on the semaphore | 
|  | // signalled by the previous caller. In this way all components are chained | 
|  | // together and we can ensure the execution sequence of command buffers. | 
|  | // | 
|  | // Therefore, the caller MUST always signal |semaphore_to_signal| in their | 
|  | // command buffer, otherwise the next caller will wait on this semaphore | 
|  | // forever. | 
|  | // | 
|  | // Also, the caller MUST ensure that the submission sequence MUST be of the | 
|  | // same order of the semaphore chain, otherwise it will cause deadlock on most | 
|  | // platforms. | 
|  | // | 
|  | // TODO(fxbug.dev/41980): Add integration tests to test synchronization of gfx Engine, | 
|  | // Screenshotter and Snapshotter as well. | 
|  | // | 
|  | class ChainedSemaphoreGenerator { | 
|  | public: | 
|  | struct SemaphorePair { | 
|  | // The |semaphore_to_wait| was the last semaphore generated by this class. | 
|  | SemaphorePtr semaphore_to_wait; | 
|  | // The |semaphore_to_signal| signal will be waited on by its next caller. | 
|  | SemaphorePtr semaphore_to_signal; | 
|  | }; | 
|  |  | 
|  | ChainedSemaphoreGenerator(vk::Device device); | 
|  |  | 
|  | SemaphorePair TakeLastAndCreateNextSemaphore(bool exportable = false) { | 
|  | return SemaphorePair{.semaphore_to_wait = TakeLastSemaphore(), | 
|  | .semaphore_to_signal = CreateNextSemaphore(exportable)}; | 
|  | } | 
|  |  | 
|  | ChainedSemaphoreGeneratorWeakPtr GetWeakPtr() { return weak_factory_.GetWeakPtr(); } | 
|  |  | 
|  | private: | 
|  | SemaphorePtr CreateNextSemaphore(bool exportable); | 
|  | SemaphorePtr TakeLastSemaphore(); | 
|  |  | 
|  | vk::Device device_; | 
|  | SemaphorePtr last_semaphore_ = nullptr; | 
|  |  | 
|  | fxl::WeakPtrFactory<ChainedSemaphoreGenerator> weak_factory_;  // must be last | 
|  | }; | 
|  |  | 
|  | }  // namespace escher | 
|  |  | 
|  | #endif  // SRC_UI_LIB_ESCHER_VK_CHAINED_SEMAPHORE_GENERATOR_H_ |