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