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 using DeviceOpWaitable = std::shared_future<void>;
33
IsDone(const DeviceOpWaitable & waitable)34 inline bool IsDone(const DeviceOpWaitable& waitable) {
35 return waitable.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready;
36 }
37
38 enum class DeviceOpStatus { kPending, kDone, kFailure };
39
40 // Helper class to track the completion of host operations for a specific VkDevice.
41 class DeviceOpTracker {
42 public:
43 DeviceOpTracker(VkDevice device, VulkanDispatch* deviceDispatch);
44
45 DeviceOpTracker(const DeviceOpTracker& rhs) = delete;
46 DeviceOpTracker& operator=(const DeviceOpTracker& rhs) = delete;
47
48 DeviceOpTracker(DeviceOpTracker&& rhs) = delete;
49 DeviceOpTracker& operator=(DeviceOpTracker&& rhs) = delete;
50
51 // Transfers ownership of the fence to this helper and marks that the given fence
52 // can be destroyed once the waitable has finished.
53 void AddPendingGarbage(DeviceOpWaitable waitable, VkFence fence);
54
55 // Transfers ownership of the semaphore to this helper and marks that the given
56 // semaphore can be destroyed once the waitable has finished.
57 void AddPendingGarbage(DeviceOpWaitable waitable, VkSemaphore semaphore);
58
59 // Checks for completion of previously submitted waitables and destroys dependent
60 // objects.
61 void PollAndProcessGarbage();
62
63 void OnDestroyDevice();
64
65 private:
66 VkDevice mDevice = VK_NULL_HANDLE;
67 VulkanDispatch* mDeviceDispatch = nullptr;
68
69 friend class DeviceOpBuilder;
70
71 using OpPollingFunction = std::function<DeviceOpStatus()>;
72
73 void AddPendingDeviceOp(OpPollingFunction pollFunction);
74
75 std::mutex mPollFunctionsMutex;
76 std::deque<OpPollingFunction> mPollFunctions;
77
78 struct PendingGarabage {
79 DeviceOpWaitable waitable;
80 std::variant<VkFence, VkSemaphore> obj;
81 std::chrono::time_point<std::chrono::system_clock> timepoint;
82 };
83 std::mutex mPendingGarbageMutex;
84 std::deque<PendingGarabage> mPendingGarbage;
85 };
86
87 class DeviceOpBuilder {
88 public:
89 DeviceOpBuilder(DeviceOpTracker& tracker);
90
91 DeviceOpBuilder(const DeviceOpBuilder& rhs) = delete;
92 DeviceOpBuilder& operator=(const DeviceOpBuilder& rhs) = delete;
93
94 DeviceOpBuilder(DeviceOpBuilder&& rhs) = delete;
95 DeviceOpBuilder& operator=(DeviceOpBuilder&& rhs) = delete;
96
97 ~DeviceOpBuilder();
98
99 // Returns a VkFence that can be used to track resource usage for
100 // host ops if a VkFence is not already readily available. This
101 // DeviceOpBuilder and its underlying DeviceOpTracker maintain
102 // ownership of the VkFence and will destroy it when then host op
103 // has completed.
104 VkFence CreateFenceForOp();
105
106 // Returns a waitable that can be used to check whether a host op
107 // has completed.
108 DeviceOpWaitable OnQueueSubmittedWithFence(VkFence fence);
109
110 private:
111 DeviceOpTracker& mTracker;
112
113 std::optional<VkFence> mCreatedFence;
114 std::optional<VkFence> mSubmittedFence;
115 };
116
117 } // namespace vk
118 } // namespace gfxstream