1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved. 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 express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "VkStringify.hpp" 16 17 #include "System/Debug.hpp" 18 19 #include <zircon/process.h> 20 #include <zircon/syscalls.h> 21 22 namespace zircon { 23 24 class VmoExternalMemory : public vk::DeviceMemory::ExternalBase 25 { 26 public: 27 // Helper struct to parse the VkMemoryAllocateInfo.pNext chain and 28 // extract relevant information related to the handle type supported 29 // by this DeviceMemory::ExternalBase subclass. 30 struct AllocateInfo 31 { 32 bool importHandle = false; 33 bool exportHandle = false; 34 zx_handle_t handle = ZX_HANDLE_INVALID; 35 36 AllocateInfo() = default; 37 38 // Parse the VkMemoryAllocateInfo->pNext chain to initialize a AllocateInfo. AllocateInfozircon::VmoExternalMemory::AllocateInfo39 AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo) 40 { 41 const auto *extInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext); 42 while(extInfo) 43 { 44 switch(extInfo->sType) 45 { 46 case VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA: 47 { 48 const auto *importInfo = reinterpret_cast<const VkImportMemoryZirconHandleInfoFUCHSIA *>(extInfo); 49 50 if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA) 51 { 52 UNSUPPORTED("importInfo->handleType"); 53 } 54 importHandle = true; 55 handle = importInfo->handle; 56 break; 57 } 58 case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: 59 { 60 const auto *exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(extInfo); 61 62 if(exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA) 63 { 64 UNSUPPORTED("exportInfo->handleTypes"); 65 } 66 exportHandle = true; 67 break; 68 } 69 case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO: 70 // This can safely be ignored, as the Vulkan spec mentions: 71 // "If the pNext chain includes a VkMemoryDedicatedAllocateInfo structure, then that structure 72 // includes a handle of the sole buffer or image resource that the memory *can* be bound to." 73 break; 74 75 default: 76 WARN("VkMemoryAllocateInfo->pNext sType = %s", vk::Stringify(extInfo->sType).c_str()); 77 } 78 extInfo = extInfo->pNext; 79 } 80 } 81 }; 82 83 static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA; 84 supportsAllocateInfo(const VkMemoryAllocateInfo * pAllocateInfo)85 static bool supportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo) 86 { 87 AllocateInfo info(pAllocateInfo); 88 return info.importHandle || info.exportHandle; 89 } 90 VmoExternalMemory(const VkMemoryAllocateInfo * pAllocateInfo)91 explicit VmoExternalMemory(const VkMemoryAllocateInfo *pAllocateInfo) 92 : allocateInfo(pAllocateInfo) 93 { 94 } 95 ~VmoExternalMemory()96 ~VmoExternalMemory() 97 { 98 closeVmo(); 99 } 100 allocate(size_t size,void ** pBuffer)101 VkResult allocate(size_t size, void **pBuffer) override 102 { 103 if(allocateInfo.importHandle) 104 { 105 // NOTE: handle ownership is passed to the VkDeviceMemory. 106 vmoHandle = allocateInfo.handle; 107 } 108 else 109 { 110 ASSERT(allocateInfo.exportHandle); 111 zx_status_t status = zx_vmo_create(size, 0, &vmoHandle); 112 if(status != ZX_OK) 113 { 114 TRACE("zx_vmo_create() returned %d", status); 115 return VK_ERROR_OUT_OF_DEVICE_MEMORY; 116 } 117 } 118 119 // Now map it directly. 120 zx_vaddr_t addr = 0; 121 zx_status_t status = zx_vmar_map(zx_vmar_root_self(), 122 ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 123 0, // vmar_offset 124 vmoHandle, 125 0, // vmo_offset 126 size, 127 &addr); 128 if(status != ZX_OK) 129 { 130 TRACE("zx_vmar_map() failed with %d", status); 131 return VK_ERROR_MEMORY_MAP_FAILED; 132 } 133 *pBuffer = reinterpret_cast<void *>(addr); 134 return VK_SUCCESS; 135 } 136 deallocate(void * buffer,size_t size)137 void deallocate(void *buffer, size_t size) override 138 { 139 zx_status_t status = zx_vmar_unmap(zx_vmar_root_self(), 140 reinterpret_cast<zx_vaddr_t>(buffer), 141 size); 142 if(status != ZX_OK) 143 { 144 TRACE("zx_vmar_unmap() failed with %d", status); 145 } 146 closeVmo(); 147 } 148 getFlagBit() const149 VkExternalMemoryHandleTypeFlagBits getFlagBit() const override 150 { 151 return typeFlagBit; 152 } 153 exportHandle(zx_handle_t * pHandle) const154 VkResult exportHandle(zx_handle_t *pHandle) const override 155 { 156 if(vmoHandle == ZX_HANDLE_INVALID) 157 { 158 return VK_ERROR_INVALID_EXTERNAL_HANDLE; 159 } 160 zx_status_t status = zx_handle_duplicate(vmoHandle, ZX_RIGHT_SAME_RIGHTS, pHandle); 161 if(status != ZX_OK) 162 { 163 TRACE("zx_handle_duplicate() returned %d", status); 164 return VK_ERROR_INVALID_EXTERNAL_HANDLE; 165 } 166 return VK_SUCCESS; 167 } 168 169 private: closeVmo()170 void closeVmo() 171 { 172 if(vmoHandle != ZX_HANDLE_INVALID) 173 { 174 zx_handle_close(vmoHandle); 175 vmoHandle = ZX_HANDLE_INVALID; 176 } 177 } 178 179 zx_handle_t vmoHandle = ZX_HANDLE_INVALID; 180 AllocateInfo allocateInfo; 181 }; 182 183 } // namespace zircon 184