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