1 // Copyright 2024 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expresso or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 
17 #include <vulkan/vulkan.h>
18 
19 #include <chrono>
20 #include <deque>
21 #include <functional>
22 #include <future>
23 #include <mutex>
24 #include <optional>
25 #include <variant>
26 
27 #include "VulkanDispatch.h"
28 
29 namespace gfxstream {
30 namespace vk {
31 
32 class DeviceOpTracker;
33 using DeviceOpTrackerPtr = std::shared_ptr<DeviceOpTracker>;
34 
35 using DeviceOpWaitable = std::shared_future<void>;
36 
IsDone(const DeviceOpWaitable & waitable)37 inline bool IsDone(const DeviceOpWaitable& waitable) {
38     return waitable.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready;
39 }
40 
41 enum class DeviceOpStatus { kPending, kDone, kFailure };
42 
43 // Helper class to track the completion of host operations for a specific VkDevice.
44 class DeviceOpTracker {
45    public:
46     DeviceOpTracker(VkDevice device, VulkanDispatch* deviceDispatch);
47 
48     DeviceOpTracker(const DeviceOpTracker& rhs) = delete;
49     DeviceOpTracker& operator=(const DeviceOpTracker& rhs) = delete;
50 
51     DeviceOpTracker(DeviceOpTracker&& rhs) = delete;
52     DeviceOpTracker& operator=(DeviceOpTracker&& rhs) = delete;
53 
54     // Transfers ownership of the fence to this helper and marks that the given fence
55     // can be destroyed once the waitable has finished.
56     void AddPendingGarbage(DeviceOpWaitable waitable, VkFence fence);
57 
58     // Transfers ownership of the semaphore to this helper and marks that the given
59     // semaphore can be destroyed once the waitable has finished.
60     void AddPendingGarbage(DeviceOpWaitable waitable, VkSemaphore semaphore);
61 
62     // Checks for completion of previously submitted waitables and sets their state accordingly .
63     // This function is thread-safe
64     void Poll();
65 
66     // Calls Poll(), and also destroys dependent objects accordingly
67     void PollAndProcessGarbage();
68 
69     void OnDestroyDevice();
70 
71    private:
72     VkDevice mDevice = VK_NULL_HANDLE;
73     VulkanDispatch* mDeviceDispatch = nullptr;
74 
75     friend class DeviceOpBuilder;
76 
77     using OpPollingFunction = std::function<DeviceOpStatus()>;
78 
79     void AddPendingDeviceOp(OpPollingFunction pollFunction);
80     struct PollFunction {
81         OpPollingFunction func;
82         std::chrono::time_point<std::chrono::system_clock> timepoint;
83     };
84     std::mutex mPollFunctionsMutex;
85     std::deque<PollFunction> mPollFunctions;
86 
87     struct PendingGarbage {
88         DeviceOpWaitable waitable;
89         std::variant<VkFence, VkSemaphore> obj;
90         std::chrono::time_point<std::chrono::system_clock> timepoint;
91     };
92     std::mutex mPendingGarbageMutex;
93     std::deque<PendingGarbage> mPendingGarbage;
94 };
95 
96 class DeviceOpBuilder {
97    public:
98     DeviceOpBuilder(DeviceOpTracker& tracker);
99 
100     DeviceOpBuilder(const DeviceOpBuilder& rhs) = delete;
101     DeviceOpBuilder& operator=(const DeviceOpBuilder& rhs) = delete;
102 
103     DeviceOpBuilder(DeviceOpBuilder&& rhs) = delete;
104     DeviceOpBuilder& operator=(DeviceOpBuilder&& rhs) = delete;
105 
106     ~DeviceOpBuilder();
107 
108     // Returns a VkFence that can be used to track resource usage for
109     // host ops if a VkFence is not already readily available. This
110     // DeviceOpBuilder and its underlying DeviceOpTracker maintain
111     // ownership of the VkFence and will destroy it when then host op
112     // has completed.
113     VkFence CreateFenceForOp();
114 
115     // Returns a waitable that can be used to check whether a host op
116     // has completed.
117     DeviceOpWaitable OnQueueSubmittedWithFence(VkFence fence);
118 
119    private:
120     DeviceOpTracker& mTracker;
121 
122     std::optional<VkFence> mCreatedFence;
123     std::optional<VkFence> mSubmittedFence;
124 };
125 
126 }  // namespace vk
127 }  // namespace gfxstream