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 "VkDeviceMemory.hpp" 16 #include "VkStringify.hpp" 17 18 #include "System/Debug.hpp" 19 20 #include <zircon/process.h> 21 #include <zircon/syscalls.h> 22 23 namespace zircon { 24 25 class VmoExternalMemory : public vk::DeviceMemory, public vk::ObjectBase<VmoExternalMemory, VkDeviceMemory> 26 { 27 public: 28 // Helper struct which reads the parsed allocation info and 29 // extracts relevant information related to the handle type 30 // supported by this DeviceMemory subclass. 31 struct AllocateInfo 32 { 33 bool importHandle = false; 34 bool exportHandle = false; 35 zx_handle_t handle = ZX_HANDLE_INVALID; 36 37 AllocateInfo() = default; 38 39 // Use the parsed allocation info to initialize a AllocateInfo. AllocateInfozircon::VmoExternalMemory::AllocateInfo40 AllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo) 41 { 42 if(extendedAllocationInfo.importMemoryZirconHandleInfo) 43 { 44 if(extendedAllocationInfo.importMemoryZirconHandleInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA) 45 { 46 UNSUPPORTED("extendedAllocationInfo.importMemoryZirconHandleInfo->handleType"); 47 } 48 importHandle = true; 49 handle = extendedAllocationInfo.importMemoryZirconHandleInfo->handle; 50 } 51 52 if(extendedAllocationInfo.exportMemoryAllocateInfo) 53 { 54 if(extendedAllocationInfo.exportMemoryAllocateInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA) 55 { 56 UNSUPPORTED("extendedAllocationInfo.exportMemoryAllocateInfo->handleTypes"); 57 } 58 exportHandle = true; 59 } 60 } 61 }; 62 63 static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA; 64 supportsAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo & extendedAllocationInfo)65 static bool supportsAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo) 66 { 67 AllocateInfo info(extendedAllocationInfo); 68 return info.importHandle || info.exportHandle; 69 } 70 VmoExternalMemory(const VkMemoryAllocateInfo * pCreateInfo,void * mem,const vk::DeviceMemory::ExtendedAllocationInfo & extendedAllocationInfo,vk::Device * pDevice)71 explicit VmoExternalMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem, const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, vk::Device *pDevice) 72 : vk::DeviceMemory(pCreateInfo, pDevice) 73 , allocateInfo(extendedAllocationInfo) 74 { 75 } 76 ~VmoExternalMemory()77 ~VmoExternalMemory() 78 { 79 closeVmo(); 80 } 81 allocateBuffer()82 VkResult allocateBuffer() override 83 { 84 if(allocateInfo.importHandle) 85 { 86 // NOTE: handle ownership is passed to the VkDeviceMemory. 87 vmoHandle = allocateInfo.handle; 88 } 89 else 90 { 91 ASSERT(allocateInfo.exportHandle); 92 zx_status_t status = zx_vmo_create(allocationSize, 0, &vmoHandle); 93 if(status != ZX_OK) 94 { 95 TRACE("zx_vmo_create() returned %d", status); 96 return VK_ERROR_OUT_OF_DEVICE_MEMORY; 97 } 98 } 99 100 // Now map it directly. 101 zx_vaddr_t addr = 0; 102 zx_status_t status = zx_vmar_map(zx_vmar_root_self(), 103 ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 104 0, // vmar_offset 105 vmoHandle, 106 0, // vmo_offset 107 allocationSize, 108 &addr); 109 if(status != ZX_OK) 110 { 111 TRACE("zx_vmar_map() failed with %d", status); 112 return VK_ERROR_MEMORY_MAP_FAILED; 113 } 114 buffer = reinterpret_cast<void *>(addr); 115 return VK_SUCCESS; 116 } 117 freeBuffer()118 void freeBuffer() override 119 { 120 zx_status_t status = zx_vmar_unmap(zx_vmar_root_self(), 121 reinterpret_cast<zx_vaddr_t>(buffer), 122 allocationSize); 123 if(status != ZX_OK) 124 { 125 TRACE("zx_vmar_unmap() failed with %d", status); 126 } 127 closeVmo(); 128 } 129 getFlagBit() const130 VkExternalMemoryHandleTypeFlagBits getFlagBit() const override 131 { 132 return typeFlagBit; 133 } 134 exportHandle(zx_handle_t * pHandle) const135 VkResult exportHandle(zx_handle_t *pHandle) const override 136 { 137 if(vmoHandle == ZX_HANDLE_INVALID) 138 { 139 return VK_ERROR_INVALID_EXTERNAL_HANDLE; 140 } 141 zx_status_t status = zx_handle_duplicate(vmoHandle, ZX_RIGHT_SAME_RIGHTS, pHandle); 142 if(status != ZX_OK) 143 { 144 TRACE("zx_handle_duplicate() returned %d", status); 145 return VK_ERROR_INVALID_EXTERNAL_HANDLE; 146 } 147 return VK_SUCCESS; 148 } 149 150 private: closeVmo()151 void closeVmo() 152 { 153 if(vmoHandle != ZX_HANDLE_INVALID) 154 { 155 zx_handle_close(vmoHandle); 156 vmoHandle = ZX_HANDLE_INVALID; 157 } 158 } 159 160 zx_handle_t vmoHandle = ZX_HANDLE_INVALID; 161 AllocateInfo allocateInfo; 162 }; 163 164 } // namespace zircon 165