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