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 #ifdef _WIN32
20 #include <malloc.h>
21 #endif
22 
23 #include <stdlib.h>
24 
25 #include <optional>
26 #include <set>
27 #include <string>
28 #include <unordered_map>
29 
30 #include "DebugUtilsHelper.h"
31 #include "DeviceOpTracker.h"
32 #include "Handle.h"
33 #include "VkEmulatedPhysicalDeviceMemory.h"
34 #include "aemu/base/files/Stream.h"
35 #include "aemu/base/memory/SharedMemory.h"
36 #include "aemu/base/synchronization/ConditionVariable.h"
37 #include "aemu/base/synchronization/Lock.h"
38 #include "common/goldfish_vk_deepcopy.h"
39 #include "vulkan/VkAndroidNativeBuffer.h"
40 #include "vulkan/VkFormatUtils.h"
41 #include "vulkan/emulated_textures/CompressedImageInfo.h"
42 
43 namespace gfxstream {
44 namespace vk {
45 
46 template <class TDispatch>
47 class ExternalFencePool {
48    public:
ExternalFencePool(TDispatch * dispatch,VkDevice device)49     ExternalFencePool(TDispatch* dispatch, VkDevice device)
50         : m_vk(dispatch), mDevice(device), mMaxSize(5) {}
51 
~ExternalFencePool()52     ~ExternalFencePool() {
53         if (!mPool.empty()) {
54             GFXSTREAM_ABORT(emugl::FatalError(emugl::ABORT_REASON_OTHER))
55                 << "External fence pool for device " << static_cast<void*>(mDevice)
56                 << " destroyed but " << mPool.size() << " fences still not destroyed.";
57         }
58     }
59 
add(VkFence fence)60     void add(VkFence fence) {
61         android::base::AutoLock lock(mLock);
62         mPool.push_back(fence);
63         if (mPool.size() > mMaxSize) {
64             INFO("External fence pool for %p has increased to size %d", mDevice, mPool.size());
65             mMaxSize = mPool.size();
66         }
67     }
68 
pop(const VkFenceCreateInfo * pCreateInfo)69     VkFence pop(const VkFenceCreateInfo* pCreateInfo) {
70         VkFence fence = VK_NULL_HANDLE;
71         {
72             android::base::AutoLock lock(mLock);
73             auto it = std::find_if(mPool.begin(), mPool.end(), [this](const VkFence& fence) {
74                 VkResult status = m_vk->vkGetFenceStatus(mDevice, fence);
75                 if (status != VK_SUCCESS) {
76                     if (status != VK_NOT_READY) {
77                         VK_CHECK(status);
78                     }
79 
80                     // Status is valid, but fence is not yet signaled
81                     return false;
82                 }
83                 return true;
84             });
85             if (it == mPool.end()) {
86                 return VK_NULL_HANDLE;
87             }
88 
89             fence = *it;
90             mPool.erase(it);
91         }
92 
93         if (!(pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT)) {
94             VK_CHECK(m_vk->vkResetFences(mDevice, 1, &fence));
95         }
96 
97         return fence;
98     }
99 
popAll()100     std::vector<VkFence> popAll() {
101         android::base::AutoLock lock(mLock);
102         std::vector<VkFence> popped = mPool;
103         mPool.clear();
104         return popped;
105     }
106 
107    private:
108     TDispatch* m_vk;
109     VkDevice mDevice;
110     android::base::Lock mLock;
111     std::vector<VkFence> mPool;
112     int mMaxSize;
113 };
114 
115 class PrivateMemory {
116 public:
PrivateMemory(size_t alignment,size_t size)117     PrivateMemory(size_t alignment, size_t size) {
118 #ifdef _WIN32
119         mAddr = _aligned_malloc(size, alignment);
120 #else
121         mAddr = aligned_alloc(alignment, size);
122 #endif
123     }
~PrivateMemory()124     ~PrivateMemory() {
125         if (mAddr) {
126 #ifdef _WIN32
127             _aligned_free(mAddr);
128 #else
129             free(mAddr);
130 #endif
131             mAddr = nullptr;
132         }
133     }
getAddr()134     void* getAddr() {
135         return mAddr;
136     }
137 private:
138     void* mAddr{nullptr};
139 };
140 
141 // We always map the whole size on host.
142 // This makes it much easier to implement
143 // the memory map API.
144 struct MemoryInfo {
145     // This indicates whether the VkDecoderGlobalState needs to clean up
146     // and unmap the mapped memory; only the owner of the mapped memory
147     // should call unmap.
148     bool needUnmap = false;
149     // When ptr is null, it means the VkDeviceMemory object
150     // was not allocated with the HOST_VISIBLE property.
151     void* ptr = nullptr;
152     VkDeviceSize size;
153     // GLDirectMem info
154     bool directMapped = false;
155     bool virtioGpuMapped = false;
156     uint32_t caching = 0;
157     uint64_t guestPhysAddr = 0;
158     void* pageAlignedHva = nullptr;
159     uint64_t sizeToPage = 0;
160     uint64_t hostmemId = 0;
161     VkDevice device = VK_NULL_HANDLE;
162     uint32_t memoryIndex = 0;
163     // Set if the memory is backed by shared memory.
164     std::optional<android::base::SharedMemory> sharedMemory;
165 
166     std::shared_ptr<PrivateMemory> privateMemory;
167     // virtio-gpu blobs
168     uint64_t blobId = 0;
169 
170     // Buffer, provided via vkAllocateMemory().
171     std::optional<HandleType> boundBuffer;
172     // ColorBuffer, provided via vkAllocateMemory().
173     std::optional<HandleType> boundColorBuffer;
174 };
175 
176 struct InstanceInfo {
177     std::vector<std::string> enabledExtensionNames;
178     uint32_t apiVersion = VK_MAKE_VERSION(1, 0, 0);
179     VkInstance boxed = nullptr;
180     bool isAngle = false;
181     std::string applicationName;
182     std::string engineName;
183 };
184 
185 struct PhysicalDeviceInfo {
186     VkInstance instance = VK_NULL_HANDLE;
187     VkPhysicalDeviceProperties props;
188     std::unique_ptr<EmulatedPhysicalDeviceMemoryProperties> memoryPropertiesHelper;
189     std::vector<VkQueueFamilyProperties> queueFamilyProperties;
190     VkPhysicalDevice boxed = nullptr;
191 
192     // Indicates that if the graphics queue family properties are overridden for
193     // this physical device to include a virtual queue.
194     bool hasVirtualGraphicsQueues = false;
195 };
196 
197 struct ExternalFenceInfo {
198     VkExternalSemaphoreHandleTypeFlagBits supportedBinarySemaphoreHandleTypes;
199     VkExternalFenceHandleTypeFlagBits supportedFenceHandleTypes;
200 };
201 
202 struct DeviceInfo {
203     std::unordered_map<uint32_t, std::vector<VkQueue>> queues;
204     std::vector<std::string> enabledExtensionNames;
205     bool emulateTextureEtc2 = false;
206     bool emulateTextureAstc = false;
207     bool useAstcCpuDecompression = false;
208 
209     ExternalFenceInfo externalFenceInfo;
210     VkPhysicalDevice physicalDevice;
211     VkDevice boxed = nullptr;
212     DebugUtilsHelper debugUtilsHelper = DebugUtilsHelper::withUtilsDisabled();
213     std::unique_ptr<ExternalFencePool<VulkanDispatch>> externalFencePool = nullptr;
214     std::set<VkFormat> imageFormats = {};  // image formats used on this device
215     std::unique_ptr<GpuDecompressionPipelineManager> decompPipelines = nullptr;
216     DeviceOpTrackerPtr deviceOpTracker = nullptr;
217     std::optional<uint32_t> virtioGpuContextId;
218 
219     // True if this is a compressed image that needs to be decompressed on the GPU (with our
220     // compute shader)
needGpuDecompressionDeviceInfo221     bool needGpuDecompression(const CompressedImageInfo& cmpInfo) {
222         return ((cmpInfo.isEtc2() && emulateTextureEtc2) ||
223                 (cmpInfo.isAstc() && emulateTextureAstc && !useAstcCpuDecompression));
224     }
needEmulatedDecompressionDeviceInfo225     bool needEmulatedDecompression(const CompressedImageInfo& cmpInfo) {
226         return ((cmpInfo.isEtc2() && emulateTextureEtc2) ||
227                 (cmpInfo.isAstc() && emulateTextureAstc));
228     }
needEmulatedDecompressionDeviceInfo229     bool needEmulatedDecompression(VkFormat format) {
230         return (gfxstream::vk::isEtc2(format) && emulateTextureEtc2) ||
231                (gfxstream::vk::isAstc(format) && emulateTextureAstc);
232     }
233 };
234 
235 struct QueueInfo {
236     std::shared_ptr<android::base::Lock> physicalQueueLock;
237     VkDevice device;
238     uint32_t queueFamilyIndex;
239     VkQueue boxed = nullptr;
240 
241     // In order to create a virtual queue handle, we use an offset to the physical
242     // queue handle value. This assumes the new generated virtual handle value will
243     // be unique and won't be generated by the actual GPU. This is expected to be
244     // true since most implementations will use a pointer for the handle value and
245     // they will be at least 4-byte aligned. Using a small value allows us to check
246     // if a given 'unboxed' queue handle value is virtual and convert into the actual
247     // physical one easily, without locking for mQueueInfo.
248     static const uint64_t kVirtualQueueBit = 0x1;
249 };
250 
251 struct BufferInfo {
252     VkDevice device;
253     VkBufferUsageFlags usage;
254     VkDeviceMemory memory = 0;
255     VkDeviceSize memoryOffset = 0;
256     VkDeviceSize size;
257     std::shared_ptr<bool> alive{new bool(true)};
258 };
259 
260 struct ImageInfo {
261     VkDevice device;
262     VkImageCreateInfo imageCreateInfoShallow;
263     std::unique_ptr<AndroidNativeBufferInfo> anbInfo;
264     CompressedImageInfo cmpInfo;
265     // ColorBuffer, provided via vkAllocateMemory().
266     std::optional<HandleType> boundColorBuffer;
267     // TODO: might need to use an array of layouts to represent each sub resource
268     VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
269     VkDeviceMemory memory = VK_NULL_HANDLE;
270 };
271 
272 struct ImageViewInfo {
273     VkDevice device;
274     bool needEmulatedAlpha = false;
275 
276     // Color buffer, provided via vkAllocateMemory().
277     std::optional<HandleType> boundColorBuffer;
278     std::shared_ptr<bool> alive{new bool(true)};
279 };
280 
281 struct SamplerInfo {
282     VkDevice device;
283     bool needEmulatedAlpha = false;
284     VkSamplerCreateInfo createInfo = {};
285     VkSampler emulatedborderSampler = VK_NULL_HANDLE;
286     android::base::BumpPool pool = android::base::BumpPool(256);
287     SamplerInfo() = default;
288     SamplerInfo& operator=(const SamplerInfo& other) {
289         deepcopy_VkSamplerCreateInfo(&pool, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
290                                      &other.createInfo, &createInfo);
291         device = other.device;
292         needEmulatedAlpha = other.needEmulatedAlpha;
293         emulatedborderSampler = other.emulatedborderSampler;
294         return *this;
295     }
SamplerInfoSamplerInfo296     SamplerInfo(const SamplerInfo& other) { *this = other; }
297     SamplerInfo(SamplerInfo&& other) = delete;
298     SamplerInfo& operator=(SamplerInfo&& other) = delete;
299     std::shared_ptr<bool> alive{new bool(true)};
300 };
301 
302 struct FenceInfo {
303     VkDevice device = VK_NULL_HANDLE;
304     VkFence boxed = VK_NULL_HANDLE;
305     VulkanDispatch* vk = nullptr;
306 
307     android::base::StaticLock lock;
308     android::base::ConditionVariable cv;
309 
310     enum class State {
311         kWaitable,
312         kNotWaitable,
313         kWaiting,
314     };
315     State state = State::kNotWaitable;
316 
317     bool external = false;
318 
319     // If this fence was used in an additional host operation that must be waited
320     // upon before destruction (e.g. as part of a vkAcquireImageANDROID() call),
321     // the waitable that tracking that host operation.
322     std::optional<DeviceOpWaitable> latestUse;
323 };
324 
325 struct SemaphoreInfo {
326     VkDevice device;
327     int externalHandleId = 0;
328     VK_EXT_SYNC_HANDLE externalHandle = VK_EXT_SYNC_HANDLE_INVALID;
329     // If this fence was used in an additional host operation that must be waited
330     // upon before destruction (e.g. as part of a vkAcquireImageANDROID() call),
331     // the waitable that tracking that host operation.
332     std::optional<DeviceOpWaitable> latestUse;
333 };
334 struct DescriptorSetLayoutInfo {
335     VkDevice device = 0;
336     VkDescriptorSetLayout boxed = 0;
337     VkDescriptorSetLayoutCreateInfo createInfo;
338     std::vector<VkDescriptorSetLayoutBinding> bindings;
339 };
340 
341 struct DescriptorPoolInfo {
342     VkDevice device = 0;
343     VkDescriptorPool boxed = 0;
344     struct PoolState {
345         VkDescriptorType type;
346         uint32_t descriptorCount;
347         uint32_t used;
348     };
349 
350     VkDescriptorPoolCreateInfo createInfo;
351     uint32_t maxSets;
352     uint32_t usedSets;
353     std::vector<PoolState> pools;
354 
355     std::unordered_map<VkDescriptorSet, VkDescriptorSet> allocedSetsToBoxed;
356     std::vector<uint64_t> poolIds;
357 };
358 
359 struct DescriptorSetInfo {
360     enum DescriptorWriteType {
361         Empty = 0,
362         ImageInfo = 1,
363         BufferInfo = 2,
364         BufferView = 3,
365         InlineUniformBlock = 4,
366         AccelerationStructure = 5,
367     };
368 
369     struct DescriptorWrite {
370         VkDescriptorType descriptorType;
371         DescriptorWriteType writeType = DescriptorWriteType::Empty;
372         uint32_t dstArrayElement;  // Only used for inlineUniformBlock and accelerationStructure.
373 
374         union {
375             VkDescriptorImageInfo imageInfo;
376             VkDescriptorBufferInfo bufferInfo;
377             VkBufferView bufferView;
378             VkWriteDescriptorSetInlineUniformBlockEXT inlineUniformBlock;
379             VkWriteDescriptorSetAccelerationStructureKHR accelerationStructure;
380         };
381 
382         std::vector<uint8_t> inlineUniformBlockBuffer;
383         // Weak pointer(s) to detect if all objects on dependency chain are alive.
384         std::vector<std::weak_ptr<bool>> alives;
385         std::optional<HandleType> boundColorBuffer;
386     };
387 
388     VkDescriptorPool pool;
389     VkDescriptorSetLayout unboxedLayout = 0;
390     std::vector<std::vector<DescriptorWrite>> allWrites;
391     std::vector<VkDescriptorSetLayoutBinding> bindings;
392 };
393 
394 struct ShaderModuleInfo {
395     VkDevice device;
396 };
397 
398 struct PipelineCacheInfo {
399     VkDevice device;
400 };
401 
402 struct PipelineInfo {
403     VkDevice device;
404 };
405 
406 struct RenderPassInfo {
407     VkDevice device;
408 };
409 
410 struct FramebufferInfo {
411     VkDevice device;
412     std::vector<HandleType> attachedColorBuffers;
413 };
414 
415 typedef std::function<void()> PreprocessFunc;
416 struct CommandBufferInfo {
417     std::vector<PreprocessFunc> preprocessFuncs = {};
418     std::vector<VkCommandBuffer> subCmds = {};
419     VkDevice device = VK_NULL_HANDLE;
420     VkCommandPool cmdPool = VK_NULL_HANDLE;
421     VkCommandBuffer boxed = VK_NULL_HANDLE;
422     DebugUtilsHelper debugUtilsHelper = DebugUtilsHelper::withUtilsDisabled();
423 
424     // Most recently bound compute pipeline and descriptor sets. We save it here so that we can
425     // restore it after doing emulated texture decompression.
426     VkPipeline computePipeline = VK_NULL_HANDLE;
427     uint32_t firstSet = 0;
428     VkPipelineLayout descriptorLayout = VK_NULL_HANDLE;
429     std::vector<VkDescriptorSet> currentDescriptorSets;
430     std::unordered_set<VkDescriptorSet> allDescriptorSets;
431     std::vector<uint32_t> dynamicOffsets;
432     std::unordered_set<HandleType> acquiredColorBuffers;
433     std::unordered_set<HandleType> releasedColorBuffers;
434     std::unordered_map<HandleType, VkImageLayout> cbLayouts;
435     std::unordered_map<VkImage, VkImageLayout> imageLayouts;
436     std::unordered_set<HandleType> imageBarrierColorBuffers;
437 
resetCommandBufferInfo438     void reset() {
439         preprocessFuncs.clear();
440         subCmds.clear();
441         computePipeline = VK_NULL_HANDLE;
442         firstSet = 0;
443         descriptorLayout = VK_NULL_HANDLE;
444         currentDescriptorSets.clear();
445         allDescriptorSets.clear();
446         dynamicOffsets.clear();
447         acquiredColorBuffers.clear();
448         releasedColorBuffers.clear();
449         cbLayouts.clear();
450         imageLayouts.clear();
451     }
452 };
453 
454 struct CommandPoolInfo {
455     VkDevice device = VK_NULL_HANDLE;
456     VkCommandPool boxed = VK_NULL_HANDLE;
457     std::unordered_set<VkCommandBuffer> cmdBuffers = {};
458 };
459 
460 struct InstanceObjects {
461     std::unordered_map<VkInstance, InstanceInfo>::node_type instance;
462     std::unordered_map<VkPhysicalDevice, PhysicalDeviceInfo> physicalDevices;
463     struct DeviceObjects {
464         std::unordered_map<VkDevice, DeviceInfo>::node_type device;
465 
466         std::unordered_map<VkBuffer, BufferInfo> buffers;
467         std::unordered_map<VkCommandBuffer, CommandBufferInfo> commandBuffers;
468         std::unordered_map<VkCommandPool, CommandPoolInfo> commandPools;
469         std::unordered_map<VkDescriptorPool, DescriptorPoolInfo> descriptorPools;
470         std::unordered_map<VkDescriptorSet, DescriptorSetInfo> descriptorSets;
471         std::unordered_map<VkDescriptorSetLayout, DescriptorSetLayoutInfo> descriptorSetLayouts;
472         std::unordered_map<VkDeviceMemory, MemoryInfo> memories;
473         std::unordered_map<VkFence, FenceInfo> fences;
474         std::unordered_map<VkFramebuffer, FramebufferInfo> framebuffers;
475         std::unordered_map<VkImage, ImageInfo> images;
476         std::unordered_map<VkImageView, ImageViewInfo> imageViews;
477         std::unordered_map<VkPipeline, PipelineInfo> pipelines;
478         std::unordered_map<VkPipelineCache, PipelineCacheInfo> pipelineCaches;
479         std::unordered_map<VkQueue, QueueInfo> queues;
480         std::unordered_map<VkRenderPass, RenderPassInfo> renderPasses;
481         std::unordered_map<VkSampler, SamplerInfo> samplers;
482         std::unordered_map<VkSemaphore, SemaphoreInfo> semaphores;
483         std::unordered_map<VkShaderModule, ShaderModuleInfo> shaderModules;
484     };
485     std::vector<DeviceObjects> devices;
486 };
487 
488 }  // namespace vk
489 }  // namespace gfxstream
490