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