// Copyright 2018 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "VkDeviceMemory.hpp" #include "VkDeviceMemoryExternalHost.hpp" #include "VkBuffer.hpp" #include "VkConfig.hpp" #include "VkDevice.hpp" #include "VkImage.hpp" #include "VkMemory.hpp" #include "VkStringify.hpp" #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD // Helper struct which reads the parsed allocation info and // extracts relevant information related to the handle type // supported by this DeviceMemory subclass. struct OpaqueFdAllocateInfo { bool importFd = false; bool exportFd = false; int fd = -1; OpaqueFdAllocateInfo() = default; // Read the parsed allocation info to initialize an OpaqueFdAllocateInfo. OpaqueFdAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo) { if(extendedAllocationInfo.importMemoryFdInfo) { if(extendedAllocationInfo.importMemoryFdInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) { UNSUPPORTED("VkImportMemoryFdInfoKHR::handleType %d", int(extendedAllocationInfo.importMemoryFdInfo->handleType)); } importFd = true; fd = extendedAllocationInfo.importMemoryFdInfo->fd; } if(extendedAllocationInfo.exportMemoryAllocateInfo) { if(extendedAllocationInfo.exportMemoryAllocateInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) { UNSUPPORTED("VkExportMemoryAllocateInfo::handleTypes %d", int(extendedAllocationInfo.exportMemoryAllocateInfo->handleTypes)); } exportFd = true; } } }; # if defined(__APPLE__) # include "VkDeviceMemoryExternalMac.hpp" # elif defined(__linux__) && !defined(__ANDROID__) # include "VkDeviceMemoryExternalLinux.hpp" # else # error "Missing VK_KHR_external_memory_fd implementation for this platform!" # endif #endif #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER # if defined(__ANDROID__) # include "VkDeviceMemoryExternalAndroid.hpp" # else # error "Missing VK_ANDROID_external_memory_android_hardware_buffer implementation for this platform!" # endif #endif #if VK_USE_PLATFORM_FUCHSIA # include "VkDeviceMemoryExternalFuchsia.hpp" #endif namespace vk { VkResult DeviceMemory::Allocate(const VkAllocationCallbacks *pAllocator, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory, Device *device) { *pMemory = VK_NULL_HANDLE; vk::DeviceMemory::ExtendedAllocationInfo extendedAllocationInfo = {}; VkResult result = vk::DeviceMemory::ParseAllocationInfo(pAllocateInfo, &extendedAllocationInfo); if(result != VK_SUCCESS) { return result; } result = Allocate(pAllocator, pAllocateInfo, pMemory, extendedAllocationInfo, device); if(result != VK_SUCCESS) { return result; } // Make sure the memory allocation is done now so that OOM errors can be checked now return vk::Cast(*pMemory)->allocate(); } VkResult DeviceMemory::Allocate(const VkAllocationCallbacks *pAllocator, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory, const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, Device *device) { VkMemoryAllocateInfo allocateInfo = *pAllocateInfo; // Add 15 bytes of padding to ensure that any type of attribute within // buffers and images can be read using 16-byte accesses. if(allocateInfo.allocationSize > UINT64_MAX - 15) { return VK_ERROR_OUT_OF_DEVICE_MEMORY; } allocateInfo.allocationSize += 15; #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER if(AHardwareBufferExternalMemory::SupportsAllocateInfo(extendedAllocationInfo)) { return AHardwareBufferExternalMemory::Create(pAllocator, &allocateInfo, pMemory, extendedAllocationInfo, device); } #endif #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD if(OpaqueFdExternalMemory::SupportsAllocateInfo(extendedAllocationInfo)) { return OpaqueFdExternalMemory::Create(pAllocator, &allocateInfo, pMemory, extendedAllocationInfo, device); } #endif #if VK_USE_PLATFORM_FUCHSIA if(zircon::VmoExternalMemory::supportsAllocateInfo(extendedAllocationInfo)) { return zircon::VmoExternalMemory::Create(pAllocator, &allocateInfo, pMemory, extendedAllocationInfo, device); } #endif if(ExternalMemoryHost::SupportsAllocateInfo(extendedAllocationInfo)) { return ExternalMemoryHost::Create(pAllocator, &allocateInfo, pMemory, extendedAllocationInfo, device); } return vk::DeviceMemoryInternal::Create(pAllocator, &allocateInfo, pMemory, extendedAllocationInfo, device); } DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo *pAllocateInfo, const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, Device *pDevice) : allocationSize(pAllocateInfo->allocationSize) , memoryTypeIndex(pAllocateInfo->memoryTypeIndex) , opaqueCaptureAddress(extendedAllocationInfo.opaqueCaptureAddress) , device(pDevice) { ASSERT(allocationSize); } void DeviceMemory::destroy(const VkAllocationCallbacks *pAllocator) { #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT VkDeviceMemoryReportEventTypeEXT eventType = isImport() ? VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT : VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT; device->emitDeviceMemoryReport(eventType, getMemoryObjectId(), 0 /* size */, VK_OBJECT_TYPE_DEVICE_MEMORY, (uint64_t)(void *)VkDeviceMemory(*this)); #endif // SWIFTSHADER_DEVICE_MEMORY_REPORT if(buffer) { freeBuffer(); buffer = nullptr; } } size_t DeviceMemory::ComputeRequiredAllocationSize(const VkMemoryAllocateInfo *pAllocateInfo) { return 0; } VkResult DeviceMemory::ParseAllocationInfo(const VkMemoryAllocateInfo *pAllocateInfo, DeviceMemory::ExtendedAllocationInfo *extendedAllocationInfo) { const VkBaseInStructure *allocationInfo = reinterpret_cast(pAllocateInfo->pNext); while(allocationInfo) { switch(allocationInfo->sType) { case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO: // This can safely be ignored on most platforms, as the Vulkan spec mentions: // "If the pNext chain includes a VkMemoryDedicatedAllocateInfo structure, then that structure // includes a handle of the sole buffer or image resource that the memory *can* be bound to." #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER extendedAllocationInfo->dedicatedAllocateInfo = reinterpret_cast(allocationInfo); #endif break; case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO: // This extension controls on which physical devices the memory gets allocated. // SwiftShader only has a single physical device, so this extension does nothing in this case. break; #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR: extendedAllocationInfo->importMemoryFdInfo = reinterpret_cast(allocationInfo); if(extendedAllocationInfo->importMemoryFdInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) { UNSUPPORTED("extendedAllocationInfo->importMemoryFdInfo->handleType %u", extendedAllocationInfo->importMemoryFdInfo->handleType); return VK_ERROR_INVALID_EXTERNAL_HANDLE; } break; #endif // SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: extendedAllocationInfo->exportMemoryAllocateInfo = reinterpret_cast(allocationInfo); switch(extendedAllocationInfo->exportMemoryAllocateInfo->handleTypes) { #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: break; #endif #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID: break; #endif #if VK_USE_PLATFORM_FUCHSIA case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA: break; #endif default: UNSUPPORTED("extendedAllocationInfo->exportMemoryAllocateInfo->handleTypes %u", extendedAllocationInfo->exportMemoryAllocateInfo->handleTypes); return VK_ERROR_INVALID_EXTERNAL_HANDLE; } break; #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER case VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID: extendedAllocationInfo->importAndroidHardwareBufferInfo = reinterpret_cast(allocationInfo); break; #endif // SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: extendedAllocationInfo->importMemoryHostPointerInfo = reinterpret_cast(allocationInfo); if((extendedAllocationInfo->importMemoryHostPointerInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT) && (extendedAllocationInfo->importMemoryHostPointerInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT)) { UNSUPPORTED("extendedAllocationInfo->importMemoryHostPointerInfo->handleType %u", extendedAllocationInfo->importMemoryHostPointerInfo->handleType); return VK_ERROR_INVALID_EXTERNAL_HANDLE; } break; #if VK_USE_PLATFORM_FUCHSIA case VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA: extendedAllocationInfo->importMemoryZirconHandleInfo = reinterpret_cast(allocationInfo); if(extendedAllocationInfo->importMemoryZirconHandleInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA) { UNSUPPORTED("extendedAllocationInfo->importMemoryZirconHandleInfo->handleType %u", extendedAllocationInfo->importMemoryZirconHandleInfo->handleType); return VK_ERROR_INVALID_EXTERNAL_HANDLE; } break; #endif // VK_USE_PLATFORM_FUCHSIA case VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO: extendedAllocationInfo->opaqueCaptureAddress = reinterpret_cast(allocationInfo)->opaqueCaptureAddress; break; default: UNSUPPORTED("pAllocateInfo->pNext sType = %s", vk::Stringify(allocationInfo->sType).c_str()); break; } allocationInfo = allocationInfo->pNext; } return VK_SUCCESS; } VkResult DeviceMemory::allocate() { if(allocationSize > MAX_MEMORY_ALLOCATION_SIZE) { #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT device->emitDeviceMemoryReport(VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT, 0 /* memoryObjectId */, allocationSize, VK_OBJECT_TYPE_DEVICE_MEMORY, 0 /* objectHandle */); #endif // SWIFTSHADER_DEVICE_MEMORY_REPORT return VK_ERROR_OUT_OF_DEVICE_MEMORY; } VkResult result = VK_SUCCESS; if(!buffer) { result = allocateBuffer(); } #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT if(result == VK_SUCCESS) { VkDeviceMemoryReportEventTypeEXT eventType = isImport() ? VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT : VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT; device->emitDeviceMemoryReport(eventType, getMemoryObjectId(), allocationSize, VK_OBJECT_TYPE_DEVICE_MEMORY, (uint64_t)(void *)VkDeviceMemory(*this)); } else { device->emitDeviceMemoryReport(VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT, 0 /* memoryObjectId */, allocationSize, VK_OBJECT_TYPE_DEVICE_MEMORY, 0 /* objectHandle */); } #endif // SWIFTSHADER_DEVICE_MEMORY_REPORT return result; } VkResult DeviceMemory::map(VkDeviceSize pOffset, VkDeviceSize pSize, void **ppData) { *ppData = getOffsetPointer(pOffset); return VK_SUCCESS; } VkDeviceSize DeviceMemory::getCommittedMemoryInBytes() const { return allocationSize; } void *DeviceMemory::getOffsetPointer(VkDeviceSize pOffset) const { ASSERT(buffer); return reinterpret_cast(buffer) + pOffset; } uint64_t DeviceMemory::getOpaqueCaptureAddress() const { return (opaqueCaptureAddress != 0) ? opaqueCaptureAddress : static_cast(reinterpret_cast(buffer)); } bool DeviceMemory::checkExternalMemoryHandleType( VkExternalMemoryHandleTypeFlags supportedHandleTypes) const { if(!supportedHandleTypes) { // This image or buffer does not need to be stored on external // memory, so this check should always pass. return true; } VkExternalMemoryHandleTypeFlagBits handle_type_bit = getFlagBit(); if(!handle_type_bit) { // This device memory is not external and can accommodate // any image or buffer as well. return true; } // Return true only if the external memory type is compatible with the // one specified during VkCreate{Image,Buffer}(), through a // VkExternalMemory{Image,Buffer}AllocateInfo struct. return (supportedHandleTypes & handle_type_bit) != 0; } // Allocate the memory according to `allocationSize`. On success return VK_SUCCESS // and sets `buffer`. VkResult DeviceMemory::allocateBuffer() { buffer = vk::allocateDeviceMemory(allocationSize, vk::DEVICE_MEMORY_ALLOCATION_ALIGNMENT); if(!buffer) { return VK_ERROR_OUT_OF_DEVICE_MEMORY; } return VK_SUCCESS; } // Free previously allocated memory at `buffer`. void DeviceMemory::freeBuffer() { vk::freeDeviceMemory(buffer); buffer = nullptr; } // Return the handle type flag bit supported by this implementation. // A value of 0 corresponds to non-external memory. VkExternalMemoryHandleTypeFlagBits DeviceMemory::getFlagBit() const { // Does not support any external memory type at all. static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)0; return typeFlagBit; } #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD VkResult DeviceMemory::exportFd(int *pFd) const { return VK_ERROR_INVALID_EXTERNAL_HANDLE; } #endif #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER VkResult DeviceMemory::exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const { return VK_ERROR_OUT_OF_HOST_MEMORY; } VkResult DeviceMemory::GetAndroidHardwareBufferProperties(VkDevice &ahbDevice, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties) { return AHardwareBufferExternalMemory::GetAndroidHardwareBufferProperties(ahbDevice, buffer, pProperties); } #endif #if VK_USE_PLATFORM_FUCHSIA VkResult DeviceMemory::exportHandle(zx_handle_t *pHandle) const { return VK_ERROR_INVALID_EXTERNAL_HANDLE; } #endif } // namespace vk