• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 #pragma once
15 
16 #include <vulkan/vulkan.h>
17 
18 #include <atomic>
19 #include <functional>
20 #include <memory>
21 #include <unordered_map>
22 #include <unordered_set>
23 #include <vector>
24 
25 #include "DisplayVk.h"
26 #include "base/Lock.h"
27 #include "base/Optional.h"
28 #include "cereal/common/goldfish_vk_private_defs.h"
29 #include "host-common/RenderDoc.h"
30 
31 namespace goldfish_vk {
32 
33 struct VulkanDispatch;
34 
35 // Returns a consistent answer for which memory type index is best for staging
36 // memory. This is not the simplest thing in the world because even if a memory
37 // type index is host visible, that doesn't mean a VkBuffer is allowed to be
38 // associated with it.
39 bool getStagingMemoryTypeIndex(
40     VulkanDispatch* vk,
41     VkDevice device,
42     const VkPhysicalDeviceMemoryProperties* memProps,
43     uint32_t* typeIndex);
44 
45 #ifdef _WIN32
46 typedef void* HANDLE;
47 #endif
48 
49 // External memory objects are HANDLE on Windows and fd's on POSIX systems.
50 #ifdef _WIN32
51 typedef HANDLE VK_EXT_MEMORY_HANDLE;
52 // corresponds to INVALID_HANDLE_VALUE
53 #define VK_EXT_MEMORY_HANDLE_INVALID (VK_EXT_MEMORY_HANDLE)(uintptr_t)(-1)
54 #define VK_EXT_MEMORY_HANDLE_TYPE_BIT VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
55 #else
56 typedef int VK_EXT_MEMORY_HANDLE;
57 #define VK_EXT_MEMORY_HANDLE_INVALID (-1)
58 #define VK_EXT_MEMORY_HANDLE_TYPE_BIT VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT
59 #endif
60 
61 VK_EXT_MEMORY_HANDLE dupExternalMemory(VK_EXT_MEMORY_HANDLE);
62 
63 // Global state that holds a global Vulkan instance along with globally
64 // exported memory allocations + images. This is in order to service things
65 // like AndroidHardwareBuffer/FuchsiaImagePipeHandle. Each such allocation is
66 // associated with a ColorBuffer handle, and depending on host-side support for
67 // GL_EXT_memory_object, also be able to zero-copy render into and readback
68 // with the traditional GL pipeline.
69 struct VkEmulation {
70     // Whether initialization succeeded.
71     bool live = false;
72 
73     // Whether to use deferred command submission.
74     bool useDeferredCommands = false;
75 
76     // Whether to fuse memory requirements getting with resource creation.
77     bool useCreateResourcesWithRequirements = false;
78 
79     // RenderDoc integration for guest VkInstances.
80     std::unique_ptr<emugl::RenderDocWithMultipleVkInstances> guestRenderDoc = nullptr;
81 
82     // Instance and device for creating the system-wide shareable objects.
83     VkInstance instance = VK_NULL_HANDLE;
84     VkPhysicalDevice physdev = VK_NULL_HANDLE;
85     VkDevice device = VK_NULL_HANDLE;
86 
87     // Global, instance and device dispatch tables.
88     VulkanDispatch* gvk = nullptr;
89     VulkanDispatch* ivk = nullptr;
90     VulkanDispatch* dvk = nullptr;
91 
92     bool instanceSupportsExternalMemoryCapabilities = false;
93     PFN_vkGetPhysicalDeviceImageFormatProperties2KHR
94             getImageFormatProperties2Func = nullptr;
95     PFN_vkGetPhysicalDeviceProperties2KHR
96             getPhysicalDeviceProperties2Func = nullptr;
97     PFN_vkGetPhysicalDeviceFeatures2 getPhysicalDeviceFeatures2Func = nullptr;
98 
99     bool instanceSupportsMoltenVK = false;
100     PFN_vkSetMTLTextureMVK setMTLTextureFunc = nullptr;
101     PFN_vkGetMTLTextureMVK getMTLTextureFunc = nullptr;
102 
103     // Queue, command pool, and command buffer
104     // for running commands to sync stuff system-wide.
105     // TODO(b/197362803): Encapsulate host side VkQueue and the lock.
106     VkQueue queue = VK_NULL_HANDLE;
107     std::shared_ptr<android::base::Lock> queueLock = nullptr;
108     uint32_t queueFamilyIndex = 0;
109     VkCommandPool commandPool = VK_NULL_HANDLE;
110     VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
111     VkFence commandBufferFence = VK_NULL_HANDLE;
112 
113     struct ImageSupportInfo {
114         // Input parameters
115         VkFormat format;
116         VkImageType type;
117         VkImageTiling tiling;
118         VkImageUsageFlags usageFlags;
119         VkImageCreateFlags createFlags;
120 
121         // Output parameters
122         bool supported = false;
123         bool supportsExternalMemory = false;
124         bool requiresDedicatedAllocation = false;
125 
126         // Keep the raw output around.
127         VkFormatProperties2 formatProps2;
128         VkImageFormatProperties2 imageFormatProps2;
129         VkExternalImageFormatProperties extFormatProps;
130 
131         // Populated later when device is available.
132         uint32_t memoryTypeBits = 0;
133         bool memoryTypeBitsKnown = false;
134     };
135 
136     std::vector<ImageSupportInfo> imageSupportInfo;
137 
138     struct DeviceSupportInfo {
139         bool hasGraphicsQueueFamily = false;
140         bool hasComputeQueueFamily = false;
141         bool supportsExternalMemory = false;
142         bool supportsIdProperties = false;
143         bool supportsDriverProperties = false;
144         bool hasSamplerYcbcrConversionExtension = false;
145         bool supportsSamplerYcbcrConversion = false;
146         bool glInteropSupported = false;
147 
148         std::vector<VkExtensionProperties> extensions;
149 
150         std::vector<uint32_t> graphicsQueueFamilyIndices;
151         std::vector<uint32_t> computeQueueFamilyIndices;
152 
153         VkPhysicalDeviceProperties physdevProps;
154         VkPhysicalDeviceMemoryProperties memProps;
155         VkPhysicalDeviceIDPropertiesKHR idProps;
156 
157         std::string driverVendor;
158         std::string driverVersion;
159 
160         PFN_vkGetImageMemoryRequirements2KHR getImageMemoryRequirements2Func = nullptr;
161         PFN_vkGetBufferMemoryRequirements2KHR getBufferMemoryRequirements2Func = nullptr;
162 
163 #ifdef _WIN32
164         PFN_vkGetMemoryWin32HandleKHR getMemoryHandleFunc = nullptr;
165 #else
166         PFN_vkGetMemoryFdKHR getMemoryHandleFunc = nullptr;
167 #endif
168     };
169 
170     struct ExternalMemoryInfo {
171         // Input fields
172         VkDeviceSize size;
173         uint32_t typeIndex;
174 
175         // Output fields
176         uint32_t id = 0;
177         VkDeviceMemory memory = VK_NULL_HANDLE;
178         VkDeviceSize actualSize;
179 
180         // host-mapping fields
181         // host virtual address (hva).
182         void* mappedPtr = nullptr;
183         // host virtual address, aligned to 4KB page.
184         void* pageAlignedHva = nullptr;
185         // the offset of |mappedPtr| off its memory page.
186         uint32_t pageOffset = 0u;
187         // the offset set in |vkBindImageMemory| or |vkBindBufferMemory|.
188         uint32_t bindOffset = 0u;
189         // the size of all the pages the mmeory uses.
190         size_t sizeToPage = 0u;
191         // guest physical address.
192         uintptr_t gpa = 0u;
193 
194         VK_EXT_MEMORY_HANDLE exportedHandle =
195             VK_EXT_MEMORY_HANDLE_INVALID;
196         bool actuallyExternal = false;
197     };
198 
199     // 128 mb staging buffer (really, just a few 4K frames or one 4k HDR frame)
200     // ought to be big enough for anybody!
201     static constexpr VkDeviceSize kDefaultStagingBufferSize =
202         128ULL * 1048576ULL;
203 
204     struct StagingBufferInfo {
205         // TODO: Don't actually use this as external memory until host visible
206         // external is supported on all platforms
207         ExternalMemoryInfo memory;
208         VkBuffer buffer = VK_NULL_HANDLE;
209         VkDeviceSize size = kDefaultStagingBufferSize;
210     };
211 
212     enum class VulkanMode {
213         // Default: ColorBuffers can still be used with the existing GL-based
214         // API.  Synchronization with (if it exists) Vulkan images happens on
215         // every one of the GL-based API calls:
216         //
217         // rcReadColorBuffer
218         // rcUpdateColorBuffer
219         // rcBindTexture
220         // rcBindRenderbuffer
221         // rcFlushWindowColorBuffer
222         //
223         // either through explicit CPU copies or implicit in the host driver
224         // if OpenGL interop is supported.
225         //
226         // When images are posted (rcFBPost),
227         // eglSwapBuffers is used, even if that requires a CPU readback.
228 
229         Default = 0,
230 
231         // VulkanOnly: It is assumed that the guest interacts entirely with
232         // the underlying Vulkan image in the guest and does not use the
233         // GL-based API.  This means we can assume those APIs are not called:
234         //
235         // rcReadColorBuffer
236         // rcUpdateColorBuffer
237         // rcBindTexture
238         // rcBindRenderbuffer
239         // rcFlushWindowColorBuffer
240         //
241         // and thus we skip a lot of GL/Vk synchronization.
242         //
243         // When images are posted, eglSwapBuffers is only used if OpenGL
244         // interop is supported. If OpenGL interop is not supported, then we
245         // use a host platform-specific Vulkan swapchain to display the
246         // results.
247 
248         VulkanOnly = 1,
249     };
250     struct ColorBufferInfo {
251         ExternalMemoryInfo memory;
252 
253         uint32_t handle;
254 
255         int frameworkFormat;
256         int frameworkStride;
257 
258         VkExtent3D extent;
259 
260         VkFormat format;
261         VkImageType type;
262         VkImageTiling tiling;
263         VkImageUsageFlags usageFlags;
264         VkImageCreateFlags createFlags;
265 
266         VkSharingMode sharingMode;
267 
268         VkImage image = VK_NULL_HANDLE;
269         VkMemoryRequirements memReqs;
270 
271         VkImageLayout currentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
272 
273         bool glExported = false;
274 
275         VulkanMode vulkanMode = VulkanMode::Default;
276 
277         MTLTextureRef mtlTexture = nullptr;
278         // shared_ptr is required so that ColorBufferInfo::ownedByHost can have
279         // an uninitialized default value that is neither true or false. The
280         // actual value will be set by setupVkColorBuffer when creating
281         // ColorBufferInfo.
282         std::shared_ptr<std::atomic_bool> ownedByHost = nullptr;
283     };
284 
285     struct BufferInfo {
286         ExternalMemoryInfo memory;
287         uint32_t handle;
288 
289         VkDeviceSize size;
290         VkBufferCreateFlags createFlags;
291         VkBufferUsageFlags usageFlags;
292         VkSharingMode sharingMode;
293 
294         VkBuffer buffer = VK_NULL_HANDLE;
295         VkMemoryRequirements memReqs;
296 
297         bool glExported = false;
298         VulkanMode vulkanMode = VulkanMode::Default;
299         MTLBufferRef mtlBuffer = nullptr;
300     };
301 
302     // Track what is supported on whatever device was selected.
303     DeviceSupportInfo deviceInfo;
304 
305     // Track additional vulkan diagnostics
306     uint32_t vulkanInstanceVersion;
307     std::vector<VkExtensionProperties> instanceExtensions;
308 
309     // A single staging buffer to perform most transfers to/from OpenGL on the
310     // host. It is shareable across instances. The memory is shareable but the
311     // buffer is not; other users need to create buffers that
312     // bind to imported versions of the memory.
313     StagingBufferInfo staging;
314 
315     // ColorBuffers are intended to back the guest's shareable images.
316     // For example:
317     // Android: gralloc
318     // Fuchsia: ImagePipeHandle
319     // Linux: dmabuf
320     std::unordered_map<uint32_t, ColorBufferInfo> colorBuffers;
321 
322     // Buffers are intended to back the guest's shareable Vulkan buffers.
323     std::unordered_map<uint32_t, BufferInfo> buffers;
324 
325     // In order to support VK_KHR_external_memory_(fd|win32) we need also to
326     // support the concept of plain external memories that are just memory and
327     // not necessarily images. These are then intended to pass through to the
328     // guest in some way, with 1:1 mapping between guest and host external
329     // memory handles.
330     std::unordered_map<uint32_t, ExternalMemoryInfo> externalMemories;
331 
332     // The host keeps a set of occupied guest memory addresses to avoid a
333     // host memory address mapped to guest twice.
334     std::unordered_set<uint64_t> occupiedGpas;
335 
336     // We can also consider using a single external memory object to back all
337     // host visible allocations in the guest. This would save memory, but we
338     // would also need to automatically add
339     // VkExternalMemory(Image|Buffer)CreateInfo, or if it is already there, OR
340     // it with the handle types on the host.
341     // A rough sketch: Some memories/images/buffers in the guest
342     // are backed by host visible memory:
343     // There is already a virtual memory type for those things in the current
344     // implementation. The guest doesn't know whether the pointer or the
345     // VkDeviceMemory object is backed by host external or non external.
346     // TODO: are all possible buffer / image usages compatible with
347     // external backing?
348     // TODO: try switching to this
349     ExternalMemoryInfo virtualHostVisibleHeap;
350 
351     // Every command buffer in the pool is associated with a VkFence which is
352     // signaled only if the command buffer completes.
353     std::vector<std::tuple<VkCommandBuffer, VkFence>> transferQueueCommandBufferPool;
354 
355     // The implementation for Vulkan native swapchain. Only initialized in initVkEmulationFeatures
356     // if useVulkanNativeSwapchain is set.
357     std::unique_ptr<DisplayVk> displayVk;
358 };
359 
360 VkEmulation* createGlobalVkEmulation(VulkanDispatch* vk);
361 struct VkEmulationFeatures {
362     bool glInteropSupported = false;
363     bool deferredCommands = false;
364     bool createResourceWithRequirements = false;
365     bool useVulkanNativeSwapchain = false;
366     std::unique_ptr<emugl::RenderDocWithMultipleVkInstances> guestRenderDoc = nullptr;
367 };
368 void initVkEmulationFeatures(std::unique_ptr<VkEmulationFeatures>);
369 
370 VkEmulation* getGlobalVkEmulation();
371 void teardownGlobalVkEmulation();
372 
373 bool allocExternalMemory(VulkanDispatch* vk,
374                          VkEmulation::ExternalMemoryInfo* info,
375                          bool actuallyExternal = true,
376                          android::base::Optional<uint64_t> deviceAlignment =
377                                  android::base::kNullopt);
378 void freeExternalMemoryLocked(VulkanDispatch* vk,
379                               VkEmulation::ExternalMemoryInfo* info);
380 
381 bool importExternalMemory(VulkanDispatch* vk,
382                           VkDevice targetDevice,
383                           const VkEmulation::ExternalMemoryInfo* info,
384                           VkDeviceMemory* out);
385 bool importExternalMemoryDedicatedImage(
386     VulkanDispatch* vk,
387     VkDevice targetDevice,
388     const VkEmulation::ExternalMemoryInfo* info,
389     VkImage image,
390     VkDeviceMemory* out);
391 
392 // ColorBuffer operations
393 
394 bool isColorBufferVulkanCompatible(uint32_t colorBufferHandle);
395 
396 std::unique_ptr<VkImageCreateInfo> generateColorBufferVkImageCreateInfo(VkFormat format,
397                                                                         uint32_t width,
398                                                                         uint32_t height,
399                                                                         VkImageTiling tiling);
400 
401 bool setupVkColorBuffer(uint32_t colorBufferHandle,
402                         bool vulkanOnly = false,
403                         uint32_t memoryProperty = 0,
404                         bool* exported = nullptr,
405                         VkDeviceSize* allocSize = nullptr,
406                         uint32_t* typeIndex = nullptr,
407                         void** mappedPtr = nullptr);
408 bool teardownVkColorBuffer(uint32_t colorBufferHandle);
409 VkEmulation::ColorBufferInfo getColorBufferInfo(uint32_t colorBufferHandle);
410 bool updateColorBufferFromVkImage(uint32_t colorBufferHandle);
411 bool updateVkImageFromColorBuffer(uint32_t colorBufferHandle);
412 VK_EXT_MEMORY_HANDLE getColorBufferExtMemoryHandle(uint32_t colorBufferHandle);
413 MTLTextureRef getColorBufferMTLTexture(uint32_t colorBufferHandle);
414 bool setColorBufferVulkanMode(uint32_t colorBufferHandle, uint32_t vulkanMode);
415 int32_t mapGpaToBufferHandle(uint32_t bufferHandle,
416                              uint64_t gpa,
417                              uint64_t size = 0);
418 
419 // Data buffer operations
420 
421 bool setupVkBuffer(uint32_t bufferHandle,
422                    bool vulkanOnly = false,
423                    uint32_t memoryProperty = 0,
424                    bool* exported = nullptr,
425                    VkDeviceSize* allocSize = nullptr,
426                    uint32_t* typeIndex = nullptr);
427 bool teardownVkBuffer(uint32_t bufferHandle);
428 VK_EXT_MEMORY_HANDLE getBufferExtMemoryHandle(uint32_t bufferHandle);
429 
430 VkExternalMemoryHandleTypeFlags
431 transformExternalMemoryHandleTypeFlags_tohost(
432     VkExternalMemoryHandleTypeFlags bits);
433 
434 VkExternalMemoryHandleTypeFlags
435 transformExternalMemoryHandleTypeFlags_fromhost(
436     VkExternalMemoryHandleTypeFlags hostBits,
437     VkExternalMemoryHandleTypeFlags wantedGuestHandleType);
438 
439 VkExternalMemoryProperties
440 transformExternalMemoryProperties_tohost(
441     VkExternalMemoryProperties props);
442 
443 VkExternalMemoryProperties
444 transformExternalMemoryProperties_fromhost(
445     VkExternalMemoryProperties props,
446     VkExternalMemoryHandleTypeFlags wantedGuestHandleType);
447 
448 void acquireColorBuffersForHostComposing(const std::vector<uint32_t>& layerColorBuffers,
449                                          uint32_t renderTargetColorBuffer);
450 
451 void releaseColorBufferFromHostComposing(const std::vector<uint32_t>& colorBufferHandles);
452 
453 void releaseColorBufferFromHostComposingSync(const std::vector<uint32_t>& colorBufferHandles);
454 
455 void setColorBufferCurrentLayout(uint32_t colorBufferHandle, VkImageLayout);
456 
457 } // namespace goldfish_vk
458