Commit 359bc80a by David 'Digit' Turner Committed by David Turner

[vulkan] Implement VK_KHR_external_memory_fd for Linux and Android.

This extension allows one to import/export device memory buffers through shared memory region file descriptors. This also adds checks to ensure that binding a buffer or image to an external device memory works only if VkCreate{Buffer,Image} was called with a VkExternalMemory{Buffer,Image}CreateInfo struct with compatible handle types. Test: dEQP-VK.api.external.memory.opaque_fd* Bug: b/140419396 Change-Id: I5d249685896ae0764bc9d5c635cc3799323db453 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/35152 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarDavid Turner <digit@google.com>
parent 88632cac
......@@ -91,6 +91,7 @@ swiftshader_source_set("swiftshader_libvulkan_headers") {
]
if (is_linux || is_android) {
sources += [
"VkDeviceMemoryExternalLinux.hpp",
"VkSemaphoreExternalLinux.hpp",
]
} else if (is_fuchsia) {
......
......@@ -31,6 +31,16 @@ Buffer::Buffer(const VkBufferCreateInfo* pCreateInfo, void* mem) :
queueFamilyIndices = reinterpret_cast<uint32_t*>(mem);
memcpy(queueFamilyIndices, pCreateInfo->pQueueFamilyIndices, sizeof(uint32_t) * queueFamilyIndexCount);
}
const auto* nextInfo = reinterpret_cast<const VkBaseInStructure*>(pCreateInfo->pNext);
for (; nextInfo != nullptr; nextInfo = nextInfo->pNext)
{
if (nextInfo->sType == VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO)
{
const auto* externalInfo = reinterpret_cast<const VkExternalMemoryBufferCreateInfo*>(nextInfo);
supportedExternalMemoryHandleTypes = externalInfo->handleTypes;
}
}
}
void Buffer::destroy(const VkAllocationCallbacks* pAllocator)
......@@ -68,6 +78,11 @@ const VkMemoryRequirements Buffer::getMemoryRequirements() const
return memoryRequirements;
}
bool Buffer::canBindToMemory(DeviceMemory* pDeviceMemory) const
{
return pDeviceMemory->checkExternalMemoryHandleType(supportedExternalMemoryHandleTypes);
}
void Buffer::bind(DeviceMemory* pDeviceMemory, VkDeviceSize pMemoryOffset)
{
memory = pDeviceMemory->getOffsetPointer(pMemoryOffset);
......
......@@ -40,6 +40,7 @@ public:
void* getOffsetPointer(VkDeviceSize offset) const;
inline VkDeviceSize getSize() const { return size; }
uint8_t* end() const;
bool canBindToMemory(DeviceMemory* pDeviceMemory) const;
private:
void* memory = nullptr;
......@@ -49,6 +50,8 @@ private:
VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE;
uint32_t queueFamilyIndexCount = 0;
uint32_t* queueFamilyIndices = nullptr;
VkExternalMemoryHandleTypeFlags supportedExternalMemoryHandleTypes = (VkExternalMemoryHandleTypeFlags)0;
};
static inline Buffer* Cast(VkBuffer object)
......
......@@ -85,6 +85,7 @@ constexpr int SUBPIXEL_PRECISION_MASK = 0xFFFFFFFF >> (32 - SUBPIXEL_PRECISION_B
}
#if VK_USE_PLATFORM_XLIB_KHR || VK_USE_PLATFORM_ANDROID_KHR
#define SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD 1
#define SWIFTSHADER_EXTERNAL_SEMAPHORE_LINUX_MEMFD 1
#endif
......
......@@ -19,36 +19,164 @@
namespace vk
{
DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo* pCreateInfo, void* mem) :
size(pCreateInfo->allocationSize), memoryTypeIndex(pCreateInfo->memoryTypeIndex)
// Base abstract interface for a device memory implementation.
class DeviceMemory::ExternalBase
{
ASSERT(size);
public:
virtual ~ExternalBase() = default;
// Allocate the memory according to |size|. On success return VK_SUCCESS
// and sets |*pBuffer|.
virtual VkResult allocate(size_t size, void** pBuffer) = 0;
// Deallocate previously allocated memory at |buffer|.
virtual void deallocate(void* buffer, size_t size) = 0;
// Return the handle type flag bit supported by this implementation.
// A value of 0 corresponds to non-external memory.
virtual VkExternalMemoryHandleTypeFlagBits getFlagBit() const = 0;
#if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD
virtual VkResult exportFd(int* pFd) const
{
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
#endif
protected:
ExternalBase() = default;
};
// Small class describing a given DeviceMemory::ExternalBase derived class.
// |typeFlagBit| corresponds to the external memory handle type.
// |instanceSize| is the size of each class instance in bytes.
// |instanceInit| is a function pointer used to initialize an instance inplace
// according to a |pAllocateInfo| parameter.
class ExternalMemoryTraits
{
public:
VkExternalMemoryHandleTypeFlagBits typeFlagBit;
size_t instanceSize;
void (*instanceInit)(void* external, const VkMemoryAllocateInfo* pAllocateInfo);
};
// Template function that parses a |pAllocateInfo.pNext| chain to verify that
// it asks for the creation or import of a memory type managed by implementation
// class T. On success, return true and sets |pTraits| accordingly. Otherwise
// return false.
template <typename T>
static bool parseCreateInfo(const VkMemoryAllocateInfo* pAllocateInfo,
ExternalMemoryTraits* pTraits)
{
if (T::supportsAllocateInfo(pAllocateInfo))
{
pTraits->typeFlagBit = T::typeFlagBit;
pTraits->instanceSize = sizeof(T);
pTraits->instanceInit = [](void* external,
const VkMemoryAllocateInfo* pAllocateInfo) {
new (external) T(pAllocateInfo);
};
return true;
}
return false;
}
void DeviceMemory::destroy(const VkAllocationCallbacks* pAllocator)
// DeviceMemory::ExternalBase implementation that uses host memory.
// Not really external, but makes everything simpler.
class DeviceMemoryHostExternalBase : public DeviceMemory::ExternalBase
{
vk::deallocate(buffer, DEVICE_MEMORY);
public:
// Does not support any external memory type at all.
static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)0;
// Always return true as is used as a fallback in findTraits() below.
static bool supportsAllocateInfo(const VkMemoryAllocateInfo* pAllocateInfo)
{
return true;
}
DeviceMemoryHostExternalBase(const VkMemoryAllocateInfo* pAllocateInfo) {}
VkResult allocate(size_t size, void** pBuffer) override
{
void* buffer = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY);
if (!buffer)
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
*pBuffer = buffer;
return VK_SUCCESS;
}
void deallocate(void* buffer, size_t size) override
{
vk::deallocate(buffer, DEVICE_MEMORY);
}
VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
{
return typeFlagBit;
}
};
} // namespace vk
#if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD
#include "VkDeviceMemoryExternalLinux.hpp"
#endif
namespace vk
{
static void findTraits(const VkMemoryAllocateInfo* pAllocateInfo,
ExternalMemoryTraits* pTraits)
{
#if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD
if (parseCreateInfo<LinuxMemfdExternalMemory>(pAllocateInfo, pTraits))
{
return;
}
#endif
parseCreateInfo<DeviceMemoryHostExternalBase>(pAllocateInfo, pTraits);
}
size_t DeviceMemory::ComputeRequiredAllocationSize(const VkMemoryAllocateInfo* pCreateInfo)
DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo* pAllocateInfo, void* mem) :
size(pAllocateInfo->allocationSize), memoryTypeIndex(pAllocateInfo->memoryTypeIndex),
external(reinterpret_cast<ExternalBase *>(mem))
{
// buffer is "GPU memory", so we use device memory for it
return 0;
ASSERT(size);
ExternalMemoryTraits traits;
findTraits(pAllocateInfo, &traits);
traits.instanceInit(external, pAllocateInfo);
}
VkResult DeviceMemory::allocate()
void DeviceMemory::destroy(const VkAllocationCallbacks* pAllocator)
{
if(!buffer)
if (buffer)
{
buffer = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY);
external->deallocate(buffer, size);
buffer = nullptr;
}
external->~ExternalBase(); // Call virtual destructor in place.
vk::deallocate(external, pAllocator);
}
size_t DeviceMemory::ComputeRequiredAllocationSize(const VkMemoryAllocateInfo* pAllocateInfo)
{
ExternalMemoryTraits traits;
findTraits(pAllocateInfo, &traits);
return traits.instanceSize;
}
if(!buffer)
VkResult DeviceMemory::allocate()
{
VkResult result = VK_SUCCESS;
if (!buffer)
{
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
result = external->allocate(size, &buffer);
}
return VK_SUCCESS;
return result;
}
VkResult DeviceMemory::map(VkDeviceSize pOffset, VkDeviceSize pSize, void** ppData)
......@@ -70,4 +198,33 @@ void* DeviceMemory::getOffsetPointer(VkDeviceSize pOffset) const
return reinterpret_cast<char*>(buffer) + pOffset;
}
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 = external->getFlagBit();
if (!handle_type_bit)
{
// This device memory is not external and can accomodate
// 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;
}
#if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD
VkResult DeviceMemory::exportFd(int* pFd) const
{
return external->exportFd(pFd);
}
#endif
} // namespace vk
......@@ -15,6 +15,7 @@
#ifndef VK_DEVICE_MEMORY_HPP_
#define VK_DEVICE_MEMORY_HPP_
#include "VkConfig.h"
#include "VkObject.hpp"
namespace vk
......@@ -27,6 +28,10 @@ public:
static size_t ComputeRequiredAllocationSize(const VkMemoryAllocateInfo* pCreateInfo);
#if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD
VkResult exportFd(int* pFd) const;
#endif
void destroy(const VkAllocationCallbacks* pAllocator);
VkResult allocate();
VkResult map(VkDeviceSize offset, VkDeviceSize size, void** ppData);
......@@ -34,10 +39,20 @@ public:
void* getOffsetPointer(VkDeviceSize pOffset) const;
uint32_t getMemoryTypeIndex() const { return memoryTypeIndex; }
// If this is external memory, return true iff its handle type matches the bitmask
// provided by |supportedExternalHandleTypes|. Otherwise, always return true.
bool checkExternalMemoryHandleType(
VkExternalMemoryHandleTypeFlags supportedExternalMemoryHandleType) const;
// Internal implementation class for external memory. Platform-specific.
class ExternalBase;
private:
void* buffer = nullptr;
VkDeviceSize size = 0;
uint32_t memoryTypeIndex = 0;
void* buffer = nullptr;
VkDeviceSize size = 0;
uint32_t memoryTypeIndex = 0;
ExternalBase* external = nullptr;
};
static inline DeviceMemory* Cast(VkDeviceMemory object)
......
// Copyright 2019 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 "VkDebug.hpp"
#include "System/Linux/MemFd.hpp"
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
class LinuxMemfdExternalMemory : public vk::DeviceMemory::ExternalBase
{
public:
// Helper struct to parse the VkMemoryAllocateInfo.pNext chain and
// extract relevant information related to the handle type supported
// by this DeviceMemory;:ExternalBase subclass.
struct AllocateInfo
{
bool importFd = false;
bool exportFd = false;
int fd = -1;
AllocateInfo() = default;
// Parse the VkMemoryAllocateInfo.pNext chain to initialize an AllocateInfo.
AllocateInfo(const VkMemoryAllocateInfo* pAllocateInfo)
{
const auto* createInfo = reinterpret_cast<const VkBaseInStructure*>(pAllocateInfo->pNext);
while (createInfo)
{
switch (createInfo->sType)
{
case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:
{
const auto* importInfo = reinterpret_cast<const VkImportMemoryFdInfoKHR*>(createInfo);
if (importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
{
UNIMPLEMENTED("importInfo->handleType");
}
importFd = true;
fd = importInfo->fd;
}
break;
case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
{
const auto* exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo*>(createInfo);
if (exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
{
UNIMPLEMENTED("exportInfo->handleTypes");
}
exportFd = true;
}
break;
default:
;
}
createInfo = createInfo->pNext;
}
}
};
static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
static bool supportsAllocateInfo(const VkMemoryAllocateInfo* pAllocateInfo)
{
AllocateInfo info(pAllocateInfo);
return info.importFd || info.exportFd;
}
explicit LinuxMemfdExternalMemory(const VkMemoryAllocateInfo* pAllocateInfo)
: allocateInfo(pAllocateInfo)
{
}
~LinuxMemfdExternalMemory()
{
memfd.close();
}
VkResult allocate(size_t size, void** pBuffer) override
{
if (allocateInfo.importFd)
{
memfd.importFd(allocateInfo.fd);
if (!memfd.isValid())
{
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
}
else
{
ASSERT(allocateInfo.exportFd);
static int counter = 0;
char name[40];
snprintf(name, sizeof(name), "SwiftShader.Memory.%d", ++counter);
if (!memfd.allocate(name, size))
{
TRACE("memfd.allocate() returned %s", strerror(errno));
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
}
}
void* addr = memfd.mapReadWrite(0, size);
if (!addr)
{
return VK_ERROR_MEMORY_MAP_FAILED;
}
*pBuffer = addr;
return VK_SUCCESS;
}
void deallocate(void* buffer, size_t size) override
{
memfd.unmap(buffer, size);
}
VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
{
return typeFlagBit;
}
VkResult exportFd(int* pFd) const override
{
int fd = memfd.exportFd();
if (fd < 0)
{
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
*pFd = fd;
return VK_SUCCESS;
}
private:
LinuxMemFd memfd;
AllocateInfo allocateInfo;
};
......@@ -361,6 +361,17 @@ static const std::vector<std::pair<const char*, std::unordered_map<std::string,
}
},
#endif
#if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD
// VK_KHR_external_memory_fd
{
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
{
MAKE_VULKAN_DEVICE_ENTRY(vkGetMemoryFdKHR),
MAKE_VULKAN_DEVICE_ENTRY(vkGetMemoryFdPropertiesKHR),
}
},
#endif
};
#undef MAKE_VULKAN_DEVICE_ENTRY
......
......@@ -75,6 +75,16 @@ Image::Image(const VkImageCreateInfo* pCreateInfo, void* mem, Device *device) :
compressedImageCreateInfo.format = format.getDecompressedFormat();
decompressedImage = new (mem) Image(&compressedImageCreateInfo, nullptr, device);
}
const auto* nextInfo = reinterpret_cast<const VkBaseInStructure*>(pCreateInfo->pNext);
for (; nextInfo != nullptr; nextInfo = nextInfo->pNext)
{
if (nextInfo->sType == VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO)
{
const auto* externalInfo = reinterpret_cast<const VkExternalMemoryImageCreateInfo*>(nextInfo);
supportedExternalMemoryHandleTypes = externalInfo->handleTypes;
}
}
}
void Image::destroy(const VkAllocationCallbacks* pAllocator)
......@@ -100,6 +110,11 @@ const VkMemoryRequirements Image::getMemoryRequirements() const
return memoryRequirements;
}
bool Image::canBindToMemory(DeviceMemory* pDeviceMemory) const
{
return pDeviceMemory->checkExternalMemoryHandleType(supportedExternalMemoryHandleTypes);
}
void Image::bind(DeviceMemory* pDeviceMemory, VkDeviceSize pMemoryOffset)
{
deviceMemory = pDeviceMemory;
......
......@@ -81,6 +81,7 @@ public:
bool is3DSlice() const;
uint8_t* end() const;
VkDeviceSize getLayerSize(VkImageAspectFlagBits aspect) const;
bool canBindToMemory(DeviceMemory* pDeviceMemory) const;
void prepareForSampling(const VkImageSubresourceRange& subresourceRange);
const Image* getSampledImage(const vk::Format& imageViewFormat) const;
......@@ -125,6 +126,8 @@ private:
#ifdef __ANDROID__
BackingMemory backingMemory = {};
#endif
VkExternalMemoryHandleTypeFlags supportedExternalMemoryHandleTypes = (VkExternalMemoryHandleTypeFlags)0;
};
static inline Image* Cast(VkImage object)
......@@ -134,4 +137,4 @@ static inline Image* Cast(VkImage object)
} // namespace vk
#endif // VK_IMAGE_HPP_
\ No newline at end of file
#endif // VK_IMAGE_HPP_
......@@ -23,6 +23,22 @@
namespace vk
{
static void setExternalMemoryProperties(VkExternalMemoryHandleTypeFlagBits handleType, VkExternalMemoryProperties* properties)
{
#if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD
if (handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
{
properties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
properties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
properties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
return;
}
#endif
properties->compatibleHandleTypes = 0;
properties->exportFromImportedHandleTypes = 0;
properties->externalMemoryFeatures = 0;
}
PhysicalDevice::PhysicalDevice(const void*, void* mem)
{
}
......@@ -339,9 +355,7 @@ void PhysicalDevice::getProperties(VkPhysicalDeviceSubgroupProperties* propertie
void PhysicalDevice::getProperties(const VkExternalMemoryHandleTypeFlagBits* handleType, VkExternalImageFormatProperties* properties) const
{
properties->externalMemoryProperties.compatibleHandleTypes = 0;
properties->externalMemoryProperties.exportFromImportedHandleTypes = 0;
properties->externalMemoryProperties.externalMemoryFeatures = 0;
setExternalMemoryProperties(*handleType, &properties->externalMemoryProperties);
}
void PhysicalDevice::getProperties(VkSamplerYcbcrConversionImageFormatProperties* properties) const
......@@ -358,9 +372,7 @@ void PhysicalDevice::getProperties(VkPhysicalDevicePresentationPropertiesANDROID
void PhysicalDevice::getProperties(const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) const
{
pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes = 0;
pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes = 0;
pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = 0;
setExternalMemoryProperties(pExternalBufferInfo->handleType, &pExternalBufferProperties->externalMemoryProperties);
}
void PhysicalDevice::getProperties(const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) const
......
......@@ -250,6 +250,9 @@ static const VkExtensionProperties deviceExtensionProperties[] =
#if SWIFTSHADER_EXTERNAL_SEMAPHORE_LINUX_MEMFD
{ VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION },
#endif
#if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD
{ VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION },
#endif
#if SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT
{ VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME, VK_FUCHSIA_EXTERNAL_SEMAPHORE_SPEC_VERSION },
#endif
......@@ -796,8 +799,30 @@ VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(VkDevice device, const VkMemoryA
// 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_LINUX_MEMFD
case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:
{
auto* importInfo = reinterpret_cast<const VkImportMemoryFdInfoKHR *>(allocationInfo);
if (importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
{
UNSUPPORTED("importInfo->handleType %u", importInfo->handleType);
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
break;
}
case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
{
auto* exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(allocationInfo);
if (exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
{
UNSUPPORTED("exportInfo->handleTypes %u", exportInfo->handleTypes);
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
break;
}
#endif
default:
UNIMPLEMENTED("allocationInfo->sType");
UNIMPLEMENTED("allocationInfo->sType %u", allocationInfo->sType);
break;
}
......@@ -829,6 +854,46 @@ VKAPI_ATTR void VKAPI_CALL vkFreeMemory(VkDevice device, VkDeviceMemory memory,
vk::destroy(memory, pAllocator);
}
#if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD
VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHR(VkDevice device, const VkMemoryGetFdInfoKHR* getFdInfo, int* pFd)
{
TRACE("(VkDevice device = %p, const VkMemoryGetFdInfoKHR* getFdInfo = %p, int* pFd = %p",
device, getFdInfo, pFd);
if (getFdInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
{
UNSUPPORTED("pGetFdInfo->handleType %u", getFdInfo->handleType);
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
return vk::Cast(getFdInfo->memory)->exportFd(pFd);
}
VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHR(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties)
{
TRACE("(VkDevice device = %p, VkExternalMemoryHandleTypeFlagBits handleType = %x, int fd = %d, VkMemoryFdPropertiesKHR* pMemoryFdProperties = %p)",
device, handleType, fd, pMemoryFdProperties);
if (handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
{
UNSUPPORTED("handleType %u", handleType);
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
if (fd < 0)
{
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
const VkPhysicalDeviceMemoryProperties& memoryProperties =
vk::Cast(device)->getPhysicalDevice()->getMemoryProperties();
// All SwiftShader memory types support this!
pMemoryFdProperties->memoryTypeBits = (1U << memoryProperties.memoryTypeCount) - 1U;
return VK_SUCCESS;
}
#endif // SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD
VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData)
{
TRACE("(VkDevice device = %p, VkDeviceMemory memory = %p, VkDeviceSize offset = %d, VkDeviceSize size = %d, VkMemoryMapFlags flags = %d, void** ppData = %p)",
......@@ -886,8 +951,12 @@ VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory(VkDevice device, VkBuffer buff
TRACE("(VkDevice device = %p, VkBuffer buffer = %p, VkDeviceMemory memory = %p, VkDeviceSize memoryOffset = %d)",
device, static_cast<void*>(buffer), static_cast<void*>(memory), int(memoryOffset));
if (!vk::Cast(buffer)->canBindToMemory(vk::Cast(memory)))
{
UNSUPPORTED("vkBindBufferMemory with invalid external memory");
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
vk::Cast(buffer)->bind(vk::Cast(memory), memoryOffset);
return VK_SUCCESS;
}
......@@ -896,8 +965,12 @@ VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(VkDevice device, VkImage image,
TRACE("(VkDevice device = %p, VkImage image = %p, VkDeviceMemory memory = %p, VkDeviceSize memoryOffset = %d)",
device, static_cast<void*>(image), static_cast<void*>(memory), int(memoryOffset));
if (!vk::Cast(image)->canBindToMemory(vk::Cast(memory)))
{
UNSUPPORTED("vkBindImageMemory with invalid external memory");
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
vk::Cast(image)->bind(vk::Cast(memory), memoryOffset);
return VK_SUCCESS;
}
......@@ -1158,9 +1231,18 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(VkDevice device, const VkBufferCre
TRACE("(VkDevice device = %p, const VkBufferCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkBuffer* pBuffer = %p)",
device, pCreateInfo, pAllocator, pBuffer);
if(pCreateInfo->pNext)
auto* nextInfo = reinterpret_cast<const VkBaseInStructure*>(pCreateInfo->pNext);
while (nextInfo)
{
UNIMPLEMENTED("pCreateInfo->pNext");
switch (nextInfo->sType)
{
case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO:
// Do nothing. Should be handled by vk::Buffer::Create().
break;
default:
UNIMPLEMENTED("pCreateInfo->pNext sType=0x%X", nextInfo->sType);
}
nextInfo = nextInfo->pNext;
}
return vk::Buffer::Create(pAllocator, pCreateInfo, pBuffer);
......@@ -1227,6 +1309,9 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(VkDevice device, const VkImageCreat
}
break;
#endif
case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO:
// Do nothing. Should be handled by vk::Image::Create()
break;
case VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR:
/* Do nothing. We don't actually need the swapchain handle yet; we'll do all the work in vkBindImageMemory2. */
break;
......@@ -1279,8 +1364,6 @@ VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const
TRACE("(VkDevice device = %p, VkImage image = %p, const VkAllocationCallbacks* pAllocator = %p)",
device, static_cast<void*>(image), pAllocator);
vk::destroy(image, pAllocator);
#ifdef __ANDROID__
vk::Image* img = vk::Cast(image);
if(img && img->hasExternalMemory())
......@@ -1288,6 +1371,8 @@ VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const
vk::destroy(img->getExternalMemory(), pAllocator);
}
#endif
vk::destroy(image, pAllocator);
}
VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout)
......@@ -2249,6 +2334,15 @@ VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2(VkDevice device, uint32_t bin
UNIMPLEMENTED("pBindInfos[%d].pNext", i);
}
if (!vk::Cast(pBindInfos[i].buffer)->canBindToMemory(vk::Cast(pBindInfos[i].memory)))
{
UNSUPPORTED("vkBindBufferMemory2 with invalid external memory");
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
}
for (uint32_t i = 0; i < bindInfoCount; i++)
{
vk::Cast(pBindInfos[i].buffer)->bind(vk::Cast(pBindInfos[i].memory), pBindInfos[i].memoryOffset);
}
......@@ -2262,6 +2356,15 @@ VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2(VkDevice device, uint32_t bind
for(uint32_t i = 0; i < bindInfoCount; i++)
{
if (!vk::Cast(pBindInfos[i].image)->canBindToMemory(vk::Cast(pBindInfos[i].memory)))
{
UNSUPPORTED("vkBindImageMemory2 with invalid external memory");
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
}
}
for(uint32_t i = 0; i < bindInfoCount; i++)
{
vk::DeviceMemory *memory = vk::Cast(pBindInfos[i].memory);
VkDeviceSize offset = pBindInfos[i].memoryOffset;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment