blob: 2e60d6cac3a23e789d9711f52263981b1d6904d0 [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2016 Google Inc.
*
* 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.
*
* \brief Vulkan external memory utilities
*//*--------------------------------------------------------------------*/
#include "vktExternalMemoryUtil.hpp"
#include "vkQueryUtil.hpp"
#if (DE_OS == DE_OS_ANDROID) || (DE_OS == DE_OS_UNIX)
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/socket.h>
#endif
#if (DE_OS == DE_OS_WIN32)
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
#if (DE_OS == DE_OS_ANDROID)
# include <sys/system_properties.h>
#endif
#if (DE_OS == DE_OS_ANDROID) && defined(__ANDROID_API_O__) && (DE_ANDROID_API >= __ANDROID_API_O__)
# include <android/hardware_buffer.h>
# include "deDynamicLibrary.hpp"
# define BUILT_WITH_ANDROID_HARDWARE_BUFFER 1
#endif
namespace vkt
{
namespace ExternalMemoryUtil
{
namespace
{
} // anonymous
NativeHandle::NativeHandle (void)
: m_fd (-1)
, m_win32HandleType (WIN32HANDLETYPE_LAST)
, m_win32Handle (DE_NULL)
, m_androidHardwareBuffer (DE_NULL)
, m_hostPtr (DE_NULL)
{
}
NativeHandle::NativeHandle (const NativeHandle& other)
: m_fd (-1)
, m_win32HandleType (WIN32HANDLETYPE_LAST)
, m_win32Handle (DE_NULL)
, m_androidHardwareBuffer (DE_NULL)
, m_hostPtr (DE_NULL)
{
if (other.m_fd >= 0)
{
#if (DE_OS == DE_OS_ANDROID) || (DE_OS == DE_OS_UNIX)
DE_ASSERT(!other.m_win32Handle.internal);
DE_ASSERT(!other.m_androidHardwareBuffer.internal);
m_fd = dup(other.m_fd);
TCU_CHECK(m_fd >= 0);
#else
DE_FATAL("Platform doesn't support file descriptors");
#endif
}
else if (other.m_win32Handle.internal)
{
#if (DE_OS == DE_OS_WIN32)
m_win32HandleType = other.m_win32HandleType;
switch (other.m_win32HandleType)
{
case WIN32HANDLETYPE_NT:
{
DE_ASSERT(other.m_fd == -1);
DE_ASSERT(!other.m_androidHardwareBuffer.internal);
const HANDLE process = ::GetCurrentProcess();
::DuplicateHandle(process, other.m_win32Handle.internal, process, &m_win32Handle.internal, 0, TRUE, DUPLICATE_SAME_ACCESS);
break;
}
case WIN32HANDLETYPE_KMT:
{
m_win32Handle = other.m_win32Handle;
break;
}
default:
DE_FATAL("Unknown win32 handle type");
}
#else
DE_FATAL("Platform doesn't support win32 handles");
#endif
}
else if (other.m_androidHardwareBuffer.internal)
{
DE_ASSERT(other.m_fd == -1);
DE_ASSERT(!other.m_win32Handle.internal);
m_androidHardwareBuffer = other.m_androidHardwareBuffer;
if (AndroidHardwareBufferExternalApi* ahbApi = AndroidHardwareBufferExternalApi::getInstance())
ahbApi->acquire(m_androidHardwareBuffer);
else
DE_FATAL("Platform doesn't support Android Hardware Buffer handles");
}
else
DE_FATAL("Native handle can't be duplicated");
}
NativeHandle::NativeHandle (int fd)
: m_fd (fd)
, m_win32HandleType (WIN32HANDLETYPE_LAST)
, m_win32Handle (DE_NULL)
, m_androidHardwareBuffer (DE_NULL)
, m_hostPtr (DE_NULL)
{
}
NativeHandle::NativeHandle (Win32HandleType handleType, vk::pt::Win32Handle handle)
: m_fd (-1)
, m_win32HandleType (handleType)
, m_win32Handle (handle)
, m_androidHardwareBuffer (DE_NULL)
, m_hostPtr (DE_NULL)
{
}
NativeHandle::NativeHandle (vk::pt::AndroidHardwareBufferPtr buffer)
: m_fd (-1)
, m_win32HandleType (WIN32HANDLETYPE_LAST)
, m_win32Handle (DE_NULL)
, m_androidHardwareBuffer (buffer)
, m_hostPtr (DE_NULL)
{
}
NativeHandle::~NativeHandle (void)
{
reset();
}
void NativeHandle::reset (void)
{
if (m_fd >= 0)
{
#if (DE_OS == DE_OS_ANDROID) || (DE_OS == DE_OS_UNIX)
DE_ASSERT(!m_win32Handle.internal);
DE_ASSERT(!m_androidHardwareBuffer.internal);
::close(m_fd);
#else
DE_FATAL("Platform doesn't support file descriptors");
#endif
}
if (m_win32Handle.internal)
{
#if (DE_OS == DE_OS_WIN32)
switch (m_win32HandleType)
{
case WIN32HANDLETYPE_NT:
DE_ASSERT(m_fd == -1);
DE_ASSERT(!m_androidHardwareBuffer.internal);
::CloseHandle((HANDLE)m_win32Handle.internal);
break;
case WIN32HANDLETYPE_KMT:
break;
default:
DE_FATAL("Unknown win32 handle type");
}
#else
DE_FATAL("Platform doesn't support win32 handles");
#endif
}
if (m_androidHardwareBuffer.internal)
{
DE_ASSERT(m_fd == -1);
DE_ASSERT(!m_win32Handle.internal);
if (AndroidHardwareBufferExternalApi* ahbApi = AndroidHardwareBufferExternalApi::getInstance())
ahbApi->release(m_androidHardwareBuffer);
else
DE_FATAL("Platform doesn't support Android Hardware Buffer handles");
}
m_fd = -1;
m_win32Handle = vk::pt::Win32Handle(DE_NULL);
m_win32HandleType = WIN32HANDLETYPE_LAST;
m_androidHardwareBuffer = vk::pt::AndroidHardwareBufferPtr(DE_NULL);
m_hostPtr = DE_NULL;
}
NativeHandle& NativeHandle::operator= (int fd)
{
reset();
m_fd = fd;
return *this;
}
NativeHandle& NativeHandle::operator= (vk::pt::AndroidHardwareBufferPtr buffer)
{
reset();
m_androidHardwareBuffer = buffer;
return *this;
}
void NativeHandle::setWin32Handle (Win32HandleType type, vk::pt::Win32Handle handle)
{
reset();
m_win32HandleType = type;
m_win32Handle = handle;
}
void NativeHandle::setHostPtr(void* hostPtr)
{
reset();
m_hostPtr = hostPtr;
}
void NativeHandle::disown (void)
{
m_fd = -1;
m_win32Handle = vk::pt::Win32Handle(DE_NULL);
m_androidHardwareBuffer = vk::pt::AndroidHardwareBufferPtr(DE_NULL);
m_hostPtr = DE_NULL;
}
vk::pt::Win32Handle NativeHandle::getWin32Handle (void) const
{
DE_ASSERT(m_fd == -1);
DE_ASSERT(!m_androidHardwareBuffer.internal);
DE_ASSERT(m_hostPtr == DE_NULL);
return m_win32Handle;
}
int NativeHandle::getFd (void) const
{
DE_ASSERT(!m_win32Handle.internal);
DE_ASSERT(!m_androidHardwareBuffer.internal);
DE_ASSERT(m_hostPtr == DE_NULL);
return m_fd;
}
vk::pt::AndroidHardwareBufferPtr NativeHandle::getAndroidHardwareBuffer (void) const
{
DE_ASSERT(m_fd == -1);
DE_ASSERT(!m_win32Handle.internal);
DE_ASSERT(m_hostPtr == DE_NULL);
return m_androidHardwareBuffer;
}
void* NativeHandle::getHostPtr(void) const
{
DE_ASSERT(m_fd == -1);
DE_ASSERT(!m_win32Handle.internal);
return m_hostPtr;
}
const char* externalSemaphoreTypeToName (vk::VkExternalSemaphoreHandleTypeFlagBits type)
{
switch (type)
{
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
return "opaque_fd";
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
return "opaque_win32";
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
return "opaque_win32_kmt";
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT:
return "d3d12_fenc";
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
return "sync_fd";
default:
DE_FATAL("Unknown external semaphore type");
return DE_NULL;
}
}
const char* externalFenceTypeToName (vk::VkExternalFenceHandleTypeFlagBits type)
{
switch (type)
{
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
return "opaque_fd";
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
return "opaque_win32";
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
return "opaque_win32_kmt";
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
return "sync_fd";
default:
DE_FATAL("Unknown external fence type");
return DE_NULL;
}
}
const char* externalMemoryTypeToName (vk::VkExternalMemoryHandleTypeFlagBits type)
{
switch (type)
{
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
return "opaque_fd";
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
return "opaque_win32";
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
return "opaque_win32_kmt";
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT:
return "d3d11_texture";
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT:
return "d3d11_texture_kmt";
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
return "d3d12_heap";
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
return "d3d12_resource";
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID:
return "android_hardware_buffer";
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT:
return "dma_buf";
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT:
return "host_allocation";
default:
DE_FATAL("Unknown external memory type");
return DE_NULL;
}
}
bool isSupportedPermanence (vk::VkExternalSemaphoreHandleTypeFlagBits type,
Permanence permanence)
{
switch (type)
{
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
return permanence == PERMANENCE_PERMANENT || permanence == PERMANENCE_TEMPORARY;
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
return permanence == PERMANENCE_PERMANENT || permanence == PERMANENCE_TEMPORARY;
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
return permanence == PERMANENCE_TEMPORARY;
default:
DE_FATAL("Unknown external semaphore type");
return false;
}
}
Transference getHandelTypeTransferences (vk::VkExternalSemaphoreHandleTypeFlagBits type)
{
switch (type)
{
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
return TRANSFERENCE_REFERENCE;
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
return TRANSFERENCE_REFERENCE;
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
return TRANSFERENCE_COPY;
default:
DE_FATAL("Unknown external semaphore type");
return TRANSFERENCE_REFERENCE;
}
}
bool isSupportedPermanence (vk::VkExternalFenceHandleTypeFlagBits type,
Permanence permanence)
{
switch (type)
{
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
return permanence == PERMANENCE_PERMANENT || permanence == PERMANENCE_TEMPORARY;
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
return permanence == PERMANENCE_PERMANENT || permanence == PERMANENCE_TEMPORARY;
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
return permanence == PERMANENCE_TEMPORARY;
default:
DE_FATAL("Unknown external fence type");
return false;
}
}
Transference getHandelTypeTransferences (vk::VkExternalFenceHandleTypeFlagBits type)
{
switch (type)
{
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
return TRANSFERENCE_REFERENCE;
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
return TRANSFERENCE_REFERENCE;
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
return TRANSFERENCE_COPY;
default:
DE_FATAL("Unknown external fence type");
return TRANSFERENCE_REFERENCE;
}
}
int getMemoryFd (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkDeviceMemory memory,
vk::VkExternalMemoryHandleTypeFlagBits externalType)
{
const vk::VkMemoryGetFdInfoKHR info =
{
vk::VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
DE_NULL,
memory,
externalType
};
int fd = -1;
VK_CHECK(vkd.getMemoryFdKHR(device, &info, &fd));
TCU_CHECK(fd >= 0);
return fd;
}
void getMemoryNative (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkDeviceMemory memory,
vk::VkExternalMemoryHandleTypeFlagBits externalType,
NativeHandle& nativeHandle)
{
if (externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT
|| externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)
{
const vk::VkMemoryGetFdInfoKHR info =
{
vk::VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
DE_NULL,
memory,
externalType
};
int fd = -1;
VK_CHECK(vkd.getMemoryFdKHR(device, &info, &fd));
TCU_CHECK(fd >= 0);
nativeHandle = fd;
}
else if (externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
|| externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT)
{
const vk::VkMemoryGetWin32HandleInfoKHR info =
{
vk::VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
DE_NULL,
memory,
externalType
};
vk::pt::Win32Handle handle (DE_NULL);
VK_CHECK(vkd.getMemoryWin32HandleKHR(device, &info, &handle));
switch (externalType)
{
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
nativeHandle.setWin32Handle(NativeHandle::WIN32HANDLETYPE_NT, handle);
break;
case vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
nativeHandle.setWin32Handle(NativeHandle::WIN32HANDLETYPE_KMT, handle);
break;
default:
DE_FATAL("Unknown external memory handle type");
}
}
else if (externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
{
if (!AndroidHardwareBufferExternalApi::getInstance())
{
TCU_THROW(NotSupportedError, "Platform doesn't support Android Hardware Buffer handles");
}
const vk::VkMemoryGetAndroidHardwareBufferInfoANDROID info =
{
vk::VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
DE_NULL,
memory,
};
vk::pt::AndroidHardwareBufferPtr ahb (DE_NULL);
VK_CHECK(vkd.getMemoryAndroidHardwareBufferANDROID(device, &info, &ahb));
TCU_CHECK(ahb.internal);
nativeHandle = ahb;
}
else
DE_FATAL("Unknown external memory handle type");
}
vk::Move<vk::VkFence> createExportableFence (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkExternalFenceHandleTypeFlagBits externalType)
{
const vk::VkExportFenceCreateInfo exportCreateInfo =
{
vk::VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO,
DE_NULL,
(vk::VkExternalFenceHandleTypeFlags)externalType
};
const vk::VkFenceCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
&exportCreateInfo,
0u
};
return vk::createFence(vkd, device, &createInfo);
}
int getFenceFd (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkFence fence,
vk::VkExternalFenceHandleTypeFlagBits externalType)
{
const vk::VkFenceGetFdInfoKHR info =
{
vk::VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR,
DE_NULL,
fence,
externalType
};
int fd = -1;
VK_CHECK(vkd.getFenceFdKHR(device, &info, &fd));
TCU_CHECK(fd >= 0);
return fd;
}
void getFenceNative (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkFence fence,
vk::VkExternalFenceHandleTypeFlagBits externalType,
NativeHandle& nativeHandle,
bool expectFenceUnsignaled)
{
if (externalType == vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT
|| externalType == vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT)
{
const vk::VkFenceGetFdInfoKHR info =
{
vk::VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR,
DE_NULL,
fence,
externalType
};
int fd = -1;
VK_CHECK(vkd.getFenceFdKHR(device, &info, &fd));
if (externalType == vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT)
{
TCU_CHECK(!expectFenceUnsignaled || (fd >= 0));
}
else
{
TCU_CHECK(fd >= 0);
}
nativeHandle = fd;
}
else if (externalType == vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT
|| externalType == vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT)
{
const vk::VkFenceGetWin32HandleInfoKHR info =
{
vk::VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR,
DE_NULL,
fence,
externalType
};
vk::pt::Win32Handle handle (DE_NULL);
VK_CHECK(vkd.getFenceWin32HandleKHR(device, &info, &handle));
switch (externalType)
{
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
nativeHandle.setWin32Handle(NativeHandle::WIN32HANDLETYPE_NT, handle);
break;
case vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
nativeHandle.setWin32Handle(NativeHandle::WIN32HANDLETYPE_KMT, handle);
break;
default:
DE_FATAL("Unknow external memory handle type");
}
}
else
DE_FATAL("Unknow external fence handle type");
}
void importFence (const vk::DeviceInterface& vkd,
const vk::VkDevice device,
const vk::VkFence fence,
vk::VkExternalFenceHandleTypeFlagBits externalType,
NativeHandle& handle,
vk::VkFenceImportFlags flags)
{
if (externalType == vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT
|| externalType == vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT)
{
const vk::VkImportFenceFdInfoKHR importInfo =
{
vk::VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR,
DE_NULL,
fence,
flags,
externalType,
handle.getFd()
};
VK_CHECK(vkd.importFenceFdKHR(device, &importInfo));
handle.disown();
}
else if (externalType == vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT
|| externalType == vk::VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT)
{
const vk::VkImportFenceWin32HandleInfoKHR importInfo =
{
vk::VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR,
DE_NULL,
fence,
flags,
externalType,
handle.getWin32Handle(),
(vk::pt::Win32LPCWSTR)DE_NULL
};
VK_CHECK(vkd.importFenceWin32HandleKHR(device, &importInfo));
// \note Importing a fence payload from Windows handles does not transfer ownership of the handle to the Vulkan implementation,
// so we do not disown the handle until after all use has complete.
}
else
DE_FATAL("Unknown fence external handle type");
}
vk::Move<vk::VkFence> createAndImportFence (const vk::DeviceInterface& vkd,
const vk::VkDevice device,
vk::VkExternalFenceHandleTypeFlagBits externalType,
NativeHandle& handle,
vk::VkFenceImportFlags flags)
{
vk::Move<vk::VkFence> fence (createFence(vkd, device));
importFence(vkd, device, *fence, externalType, handle, flags);
return fence;
}
vk::Move<vk::VkSemaphore> createExportableSemaphore (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkExternalSemaphoreHandleTypeFlagBits externalType)
{
const vk::VkExportSemaphoreCreateInfo exportCreateInfo =
{
vk::VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
DE_NULL,
(vk::VkExternalSemaphoreHandleTypeFlags)externalType
};
const vk::VkSemaphoreCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
&exportCreateInfo,
0u
};
return vk::createSemaphore(vkd, device, &createInfo);
}
vk::Move<vk::VkSemaphore> createExportableSemaphoreType (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkSemaphoreType semaphoreType,
vk::VkExternalSemaphoreHandleTypeFlagBits externalType)
{
const vk::VkSemaphoreTypeCreateInfo semaphoreTypeCreateInfo =
{
vk::VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
DE_NULL,
semaphoreType,
0,
};
const vk::VkExportSemaphoreCreateInfo exportCreateInfo =
{
vk::VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
&semaphoreTypeCreateInfo,
(vk::VkExternalSemaphoreHandleTypeFlags)externalType
};
const vk::VkSemaphoreCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
&exportCreateInfo,
0u
};
return vk::createSemaphore(vkd, device, &createInfo);
}
int getSemaphoreFd (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkSemaphore semaphore,
vk::VkExternalSemaphoreHandleTypeFlagBits externalType)
{
const vk::VkSemaphoreGetFdInfoKHR info =
{
vk::VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
DE_NULL,
semaphore,
externalType
};
int fd = -1;
VK_CHECK(vkd.getSemaphoreFdKHR(device, &info, &fd));
TCU_CHECK(fd >= 0);
return fd;
}
void getSemaphoreNative (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkSemaphore semaphore,
vk::VkExternalSemaphoreHandleTypeFlagBits externalType,
NativeHandle& nativeHandle)
{
if (externalType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT
|| externalType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT)
{
const vk::VkSemaphoreGetFdInfoKHR info =
{
vk::VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
DE_NULL,
semaphore,
externalType
};
int fd = -1;
VK_CHECK(vkd.getSemaphoreFdKHR(device, &info, &fd));
TCU_CHECK(fd >= 0);
nativeHandle = fd;
}
else if (externalType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
|| externalType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT)
{
const vk::VkSemaphoreGetWin32HandleInfoKHR info =
{
vk::VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR,
DE_NULL,
semaphore,
externalType
};
vk::pt::Win32Handle handle (DE_NULL);
VK_CHECK(vkd.getSemaphoreWin32HandleKHR(device, &info, &handle));
switch (externalType)
{
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
nativeHandle.setWin32Handle(NativeHandle::WIN32HANDLETYPE_NT, handle);
break;
case vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
nativeHandle.setWin32Handle(NativeHandle::WIN32HANDLETYPE_KMT, handle);
break;
default:
DE_FATAL("Unknow external memory handle type");
}
}
else
DE_FATAL("Unknow external semaphore handle type");
}
void importSemaphore (const vk::DeviceInterface& vkd,
const vk::VkDevice device,
const vk::VkSemaphore semaphore,
vk::VkExternalSemaphoreHandleTypeFlagBits externalType,
NativeHandle& handle,
vk::VkSemaphoreImportFlags flags)
{
if (externalType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT
|| externalType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT)
{
const vk::VkImportSemaphoreFdInfoKHR importInfo =
{
vk::VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
DE_NULL,
semaphore,
flags,
externalType,
handle.getFd()
};
VK_CHECK(vkd.importSemaphoreFdKHR(device, &importInfo));
handle.disown();
}
else if (externalType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
|| externalType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT)
{
const vk::VkImportSemaphoreWin32HandleInfoKHR importInfo =
{
vk::VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR,
DE_NULL,
semaphore,
flags,
externalType,
handle.getWin32Handle(),
(vk::pt::Win32LPCWSTR)DE_NULL
};
VK_CHECK(vkd.importSemaphoreWin32HandleKHR(device, &importInfo));
// \note Importing a semaphore payload from Windows handles does not transfer ownership of the handle to the Vulkan implementation,
// so we do not disown the handle until after all use has complete.
}
else
DE_FATAL("Unknown semaphore external handle type");
}
vk::Move<vk::VkSemaphore> createAndImportSemaphore (const vk::DeviceInterface& vkd,
const vk::VkDevice device,
vk::VkExternalSemaphoreHandleTypeFlagBits externalType,
NativeHandle& handle,
vk::VkSemaphoreImportFlags flags)
{
vk::Move<vk::VkSemaphore> semaphore (createSemaphore(vkd, device));
importSemaphore(vkd, device, *semaphore, externalType, handle, flags);
return semaphore;
}
deUint32 chooseMemoryType(deUint32 bits)
{
if (bits == 0)
return 0;
for (deUint32 memoryTypeIndex = 0; (1u << memoryTypeIndex) <= bits; memoryTypeIndex++)
{
if ((bits & (1u << memoryTypeIndex)) != 0)
return memoryTypeIndex;
}
DE_FATAL("No supported memory types");
return -1;
}
deUint32 chooseHostVisibleMemoryType (deUint32 bits, const vk::VkPhysicalDeviceMemoryProperties properties)
{
DE_ASSERT(bits != 0);
for (deUint32 memoryTypeIndex = 0; (1u << memoryTypeIndex) <= bits; memoryTypeIndex++)
{
if (((bits & (1u << memoryTypeIndex)) != 0) &&
((properties.memoryTypes[memoryTypeIndex].propertyFlags & vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0))
return memoryTypeIndex;
}
TCU_THROW(NotSupportedError, "No supported memory type found");
return -1;
}
vk::VkMemoryRequirements getImageMemoryRequirements (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkImage image,
vk::VkExternalMemoryHandleTypeFlagBits externalType)
{
if (externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
{
return { 0u, 0u, 0u };
}
else
{
return vk::getImageMemoryRequirements(vkd, device, image);
}
}
vk::Move<vk::VkDeviceMemory> allocateExportableMemory (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkDeviceSize allocationSize,
deUint32 memoryTypeIndex,
vk::VkExternalMemoryHandleTypeFlagBits externalType,
vk::VkBuffer buffer)
{
const vk::VkMemoryDedicatedAllocateInfo dedicatedInfo =
{
vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
DE_NULL,
(vk::VkImage)0,
buffer
};
const vk::VkExportMemoryAllocateInfo exportInfo =
{
vk::VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
!!buffer ? &dedicatedInfo : DE_NULL,
(vk::VkExternalMemoryHandleTypeFlags)externalType
};
const vk::VkMemoryAllocateInfo info =
{
vk::VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
&exportInfo,
allocationSize,
memoryTypeIndex
};
return vk::allocateMemory(vkd, device, &info);
}
vk::Move<vk::VkDeviceMemory> allocateExportableMemory (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkDeviceSize allocationSize,
deUint32 memoryTypeIndex,
vk::VkExternalMemoryHandleTypeFlagBits externalType,
vk::VkImage image)
{
const vk::VkMemoryDedicatedAllocateInfo dedicatedInfo =
{
vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
DE_NULL,
image,
(vk::VkBuffer)0
};
const vk::VkExportMemoryAllocateInfo exportInfo =
{
vk::VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
!!image ? &dedicatedInfo : DE_NULL,
(vk::VkExternalMemoryHandleTypeFlags)externalType
};
const vk::VkMemoryAllocateInfo info =
{
vk::VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
&exportInfo,
allocationSize,
memoryTypeIndex
};
return vk::allocateMemory(vkd, device, &info);
}
static vk::Move<vk::VkDeviceMemory> importMemory (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkBuffer buffer,
vk::VkImage image,
const vk::VkMemoryRequirements& requirements,
vk::VkExternalMemoryHandleTypeFlagBits externalType,
deUint32 memoryTypeIndex,
NativeHandle& handle)
{
const bool isDedicated = !!buffer || !!image;
DE_ASSERT(!buffer || !image);
if (externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT
|| externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)
{
const vk::VkImportMemoryFdInfoKHR importInfo =
{
vk::VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
DE_NULL,
externalType,
handle.getFd()
};
const vk::VkMemoryDedicatedAllocateInfo dedicatedInfo =
{
vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
&importInfo,
image,
buffer,
};
const vk::VkMemoryAllocateInfo info =
{
vk::VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
(isDedicated ? (const void*)&dedicatedInfo : (const void*)&importInfo),
requirements.size,
(memoryTypeIndex == ~0U) ? chooseMemoryType(requirements.memoryTypeBits) : memoryTypeIndex
};
vk::Move<vk::VkDeviceMemory> memory (vk::allocateMemory(vkd, device, &info));
handle.disown();
return memory;
}
else if (externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
|| externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT)
{
const vk::VkImportMemoryWin32HandleInfoKHR importInfo =
{
vk::VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
DE_NULL,
externalType,
handle.getWin32Handle(),
(vk::pt::Win32LPCWSTR)DE_NULL
};
const vk::VkMemoryDedicatedAllocateInfo dedicatedInfo =
{
vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
&importInfo,
image,
buffer,
};
const vk::VkMemoryAllocateInfo info =
{
vk::VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
(isDedicated ? (const void*)&dedicatedInfo : (const void*)&importInfo),
requirements.size,
(memoryTypeIndex == ~0U) ? chooseMemoryType(requirements.memoryTypeBits) : memoryTypeIndex
};
vk::Move<vk::VkDeviceMemory> memory (vk::allocateMemory(vkd, device, &info));
// The handle's owned reference must also be released. Do not discard the handle below.
if (externalType != vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
handle.disown();
return memory;
}
else if (externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
{
AndroidHardwareBufferExternalApi* ahbApi = AndroidHardwareBufferExternalApi::getInstance();
if (!ahbApi)
{
TCU_THROW(NotSupportedError, "Platform doesn't support Android Hardware Buffer handles");
}
deUint32 ahbFormat = 0;
ahbApi->describe(handle.getAndroidHardwareBuffer(), DE_NULL, DE_NULL, DE_NULL, &ahbFormat, DE_NULL, DE_NULL);
DE_ASSERT(ahbApi->ahbFormatIsBlob(ahbFormat) || image != 0);
vk::VkAndroidHardwareBufferPropertiesANDROID ahbProperties =
{
vk::VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
DE_NULL,
0u,
0u
};
VK_CHECK(vkd.getAndroidHardwareBufferPropertiesANDROID(device, handle.getAndroidHardwareBuffer(), &ahbProperties));
vk::VkImportAndroidHardwareBufferInfoANDROID importInfo =
{
vk::VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
DE_NULL,
handle.getAndroidHardwareBuffer()
};
const vk::VkMemoryDedicatedAllocateInfo dedicatedInfo =
{
vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
&importInfo,
image,
buffer,
};
const vk::VkMemoryAllocateInfo info =
{
vk::VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
(isDedicated ? (const void*)&dedicatedInfo : (const void*)&importInfo),
ahbProperties.allocationSize,
(memoryTypeIndex == ~0U) ? chooseMemoryType(ahbProperties.memoryTypeBits) : memoryTypeIndex
};
vk::Move<vk::VkDeviceMemory> memory (vk::allocateMemory(vkd, device, &info));
return memory;
}
else if (externalType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT)
{
DE_ASSERT(memoryTypeIndex != ~0U);
const vk::VkImportMemoryHostPointerInfoEXT importInfo =
{
vk::VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
DE_NULL,
externalType,
handle.getHostPtr()
};
const vk::VkMemoryDedicatedAllocateInfo dedicatedInfo =
{
vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
&importInfo,
image,
buffer,
};
const vk::VkMemoryAllocateInfo info =
{
vk::VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
(isDedicated ? (const void*)&dedicatedInfo : (const void*)&importInfo),
requirements.size,
memoryTypeIndex
};
vk::Move<vk::VkDeviceMemory> memory (vk::allocateMemory(vkd, device, &info));
return memory;
}
else
{
DE_FATAL("Unknown external memory type");
return vk::Move<vk::VkDeviceMemory>();
}
}
vk::Move<vk::VkDeviceMemory> importMemory (const vk::DeviceInterface& vkd,
vk::VkDevice device,
const vk::VkMemoryRequirements& requirements,
vk::VkExternalMemoryHandleTypeFlagBits externalType,
deUint32 memoryTypeIndex,
NativeHandle& handle)
{
return importMemory(vkd, device, (vk::VkBuffer)0, (vk::VkImage)0, requirements, externalType, memoryTypeIndex, handle);
}
vk::Move<vk::VkDeviceMemory> importDedicatedMemory (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkBuffer buffer,
const vk::VkMemoryRequirements& requirements,
vk::VkExternalMemoryHandleTypeFlagBits externalType,
deUint32 memoryTypeIndex,
NativeHandle& handle)
{
return importMemory(vkd, device, buffer, (vk::VkImage)0, requirements, externalType, memoryTypeIndex, handle);
}
vk::Move<vk::VkDeviceMemory> importDedicatedMemory (const vk::DeviceInterface& vkd,
vk::VkDevice device,
vk::VkImage image,
const vk::VkMemoryRequirements& requirements,
vk::VkExternalMemoryHandleTypeFlagBits externalType,
deUint32 memoryTypeIndex,
NativeHandle& handle)
{
return importMemory(vkd, device, (vk::VkBuffer)0, image, requirements, externalType, memoryTypeIndex, handle);
}
vk::Move<vk::VkBuffer> createExternalBuffer (const vk::DeviceInterface& vkd,
vk::VkDevice device,
deUint32 queueFamilyIndex,
vk::VkExternalMemoryHandleTypeFlagBits externalType,
vk::VkDeviceSize size,
vk::VkBufferCreateFlags createFlags,
vk::VkBufferUsageFlags usageFlags)
{
const vk::VkExternalMemoryBufferCreateInfo externalCreateInfo =
{
vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
DE_NULL,
(vk::VkExternalMemoryHandleTypeFlags)externalType
};
const vk::VkBufferCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
&externalCreateInfo,
createFlags,
size,
usageFlags,
vk::VK_SHARING_MODE_EXCLUSIVE,
1u,
&queueFamilyIndex
};
return vk::createBuffer(vkd, device, &createInfo);
}
vk::Move<vk::VkImage> createExternalImage (const vk::DeviceInterface& vkd,
vk::VkDevice device,
deUint32 queueFamilyIndex,
vk::VkExternalMemoryHandleTypeFlagBits externalType,
vk::VkFormat format,
deUint32 width,
deUint32 height,
vk::VkImageTiling tiling,
vk::VkImageCreateFlags createFlags,
vk::VkImageUsageFlags usageFlags,
deUint32 mipLevels,
deUint32 arrayLayers)
{
if (createFlags & vk::VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT && arrayLayers < 6u)
arrayLayers = 6u;
const vk::VkExternalMemoryImageCreateInfo externalCreateInfo =
{
vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
DE_NULL,
(vk::VkExternalMemoryHandleTypeFlags)externalType
};
const vk::VkImageCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
&externalCreateInfo,
createFlags,
vk::VK_IMAGE_TYPE_2D,
format,
{ width, height, 1u, },
mipLevels,
arrayLayers,
vk::VK_SAMPLE_COUNT_1_BIT,
tiling,
usageFlags,
vk::VK_SHARING_MODE_EXCLUSIVE,
1,
&queueFamilyIndex,
vk::VK_IMAGE_LAYOUT_UNDEFINED
};
return vk::createImage(vkd, device, &createInfo);
}
#if (DE_OS == DE_OS_ANDROID)
# if defined(__ANDROID_API_P__) && (DE_ANDROID_API >= __ANDROID_API_P__)
# define BUILT_WITH_ANDROID_P_HARDWARE_BUFFER 1
# endif
static deInt32 androidGetSdkVersion()
{
static deInt32 sdkVersion = -1;
if (sdkVersion < 0)
{
char value[128] = {0};
__system_property_get("ro.build.version.sdk", value);
sdkVersion = static_cast<deInt32>(strtol(value, DE_NULL, 10));
printf("SDK Version is %d\n", sdkVersion);
}
return sdkVersion;
}
static deInt32 checkAnbApiBuild()
{
deInt32 sdkVersion = androidGetSdkVersion();
#if !defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER)
// When testing AHB on Android-O and newer the CTS must be compiled against API26 or newer.
DE_TEST_ASSERT(!(sdkVersion >= 26)); /* __ANDROID_API_O__ */
#endif // !defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER)
#if !defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER)
// When testing AHB on Android-P and newer the CTS must be compiled against API28 or newer.
DE_TEST_ASSERT(!(sdkVersion >= 28)); /*__ANDROID_API_P__ */
#endif // !defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER)
return sdkVersion;
}
bool AndroidHardwareBufferExternalApi::supportsAhb()
{
return (checkAnbApiBuild() >= __ANDROID_API_O__);
}
bool AndroidHardwareBufferExternalApi::supportsCubeMap()
{
return (checkAnbApiBuild() >= 28);
}
AndroidHardwareBufferExternalApi::AndroidHardwareBufferExternalApi()
{
deInt32 sdkVersion = checkAnbApiBuild();
if(sdkVersion >= __ANDROID_API_O__)
{
#if defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER)
if (!loadAhbDynamicApis(sdkVersion))
{
// Couldn't load Android AHB system APIs.
DE_TEST_ASSERT(false);
}
#else
// Invalid Android AHB APIs configuration. Please check the instructions on how to build NDK for Android.
DE_TEST_ASSERT(false);
#endif // defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER)
}
}
AndroidHardwareBufferExternalApi::~AndroidHardwareBufferExternalApi()
{
}
#if defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER)
typedef int (*pfn_system_property_get)(const char *, char *);
typedef int (*pfnAHardwareBuffer_allocate)(const AHardwareBuffer_Desc* desc, AHardwareBuffer** outBuffer);
typedef void (*pfnAHardwareBuffer_describe)(const AHardwareBuffer* buffer, AHardwareBuffer_Desc* outDesc);
typedef void (*pfnAHardwareBuffer_acquire)(AHardwareBuffer* buffer);
typedef void (*pfnAHardwareBuffer_release)(AHardwareBuffer* buffer);
struct AhbFunctions
{
pfnAHardwareBuffer_allocate allocate;
pfnAHardwareBuffer_describe describe;
pfnAHardwareBuffer_acquire acquire;
pfnAHardwareBuffer_release release;
};
static AhbFunctions ahbFunctions;
static bool ahbFunctionsLoaded(AhbFunctions* pAhbFunctions)
{
static bool ahbApiLoaded = false;
if (ahbApiLoaded ||
((pAhbFunctions->allocate != DE_NULL) &&
(pAhbFunctions->describe != DE_NULL) &&
(pAhbFunctions->acquire != DE_NULL) &&
(pAhbFunctions->release != DE_NULL)))
{
ahbApiLoaded = true;
return true;
}
return false;
}
bool AndroidHardwareBufferExternalApi::loadAhbDynamicApis(deInt32 sdkVersion)
{
if(sdkVersion >= __ANDROID_API_O__)
{
if (!ahbFunctionsLoaded(&ahbFunctions))
{
static de::DynamicLibrary libnativewindow("libnativewindow.so");
ahbFunctions.allocate = reinterpret_cast<pfnAHardwareBuffer_allocate>(libnativewindow.getFunction("AHardwareBuffer_allocate"));
ahbFunctions.describe = reinterpret_cast<pfnAHardwareBuffer_describe>(libnativewindow.getFunction("AHardwareBuffer_describe"));
ahbFunctions.acquire = reinterpret_cast<pfnAHardwareBuffer_acquire>(libnativewindow.getFunction("AHardwareBuffer_acquire"));
ahbFunctions.release = reinterpret_cast<pfnAHardwareBuffer_release>(libnativewindow.getFunction("AHardwareBuffer_release"));
return ahbFunctionsLoaded(&ahbFunctions);
}
else
{
return true;
}
}
return false;
}
class AndroidHardwareBufferExternalApi26 : public AndroidHardwareBufferExternalApi
{
public:
virtual vk::pt::AndroidHardwareBufferPtr allocate(deUint32 width, deUint32 height, deUint32 layers, deUint32 format, deUint64 usage);
virtual void acquire(vk::pt::AndroidHardwareBufferPtr buffer);
virtual void release(vk::pt::AndroidHardwareBufferPtr buffer);
virtual void describe(const vk::pt::AndroidHardwareBufferPtr buffer,
deUint32* width,
deUint32* height,
deUint32* layers,
deUint32* format,
deUint64* usage,
deUint32* stride);
virtual deUint64 vkUsageToAhbUsage(vk::VkImageUsageFlagBits vkFlag);
virtual deUint64 vkCreateToAhbUsage(vk::VkImageCreateFlagBits vkFlag);
virtual deUint32 vkFormatToAhbFormat(vk::VkFormat vkFormat);
virtual deUint64 mustSupportAhbUsageFlags();
virtual bool ahbFormatIsBlob(deUint32 ahbFormat) { return (ahbFormat == AHARDWAREBUFFER_FORMAT_BLOB); };
AndroidHardwareBufferExternalApi26() : AndroidHardwareBufferExternalApi() {};
virtual ~AndroidHardwareBufferExternalApi26() {};
private:
// Stop the compiler generating methods of copy the object
AndroidHardwareBufferExternalApi26(AndroidHardwareBufferExternalApi26 const& copy); // Not Implemented
AndroidHardwareBufferExternalApi26& operator=(AndroidHardwareBufferExternalApi26 const& copy); // Not Implemented
};
vk::pt::AndroidHardwareBufferPtr AndroidHardwareBufferExternalApi26::allocate( deUint32 width,
deUint32 height,
deUint32 layers,
deUint32 format,
deUint64 usage)
{
AHardwareBuffer_Desc hbufferdesc = {
width,
height,
layers, // number of images
format,
usage,
0u, // Stride in pixels, ignored for AHardwareBuffer_allocate()
0u, // Initialize to zero, reserved for future use
0u // Initialize to zero, reserved for future use
};
AHardwareBuffer* hbuffer = DE_NULL;
ahbFunctions.allocate(&hbufferdesc, &hbuffer);
return vk::pt::AndroidHardwareBufferPtr(hbuffer);
}
void AndroidHardwareBufferExternalApi26::acquire(vk::pt::AndroidHardwareBufferPtr buffer)
{
ahbFunctions.acquire(static_cast<AHardwareBuffer*>(buffer.internal));
}
void AndroidHardwareBufferExternalApi26::release(vk::pt::AndroidHardwareBufferPtr buffer)
{
ahbFunctions.release(static_cast<AHardwareBuffer*>(buffer.internal));
}
void AndroidHardwareBufferExternalApi26::describe( const vk::pt::AndroidHardwareBufferPtr buffer,
deUint32* width,
deUint32* height,
deUint32* layers,
deUint32* format,
deUint64* usage,
deUint32* stride)
{
AHardwareBuffer_Desc desc;
ahbFunctions.describe(static_cast<const AHardwareBuffer*>(buffer.internal), &desc);
if (width) *width = desc.width;
if (height) *height = desc.height;
if (layers) *layers = desc.layers;
if (format) *format = desc.format;
if (usage) *usage = desc.usage;
if (stride) *stride = desc.stride;
}
deUint64 AndroidHardwareBufferExternalApi26::vkUsageToAhbUsage(vk::VkImageUsageFlagBits vkFlags)
{
switch(vkFlags)
{
case vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT:
case vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT:
// No AHB equivalent.
return 0u;
case vk::VK_IMAGE_USAGE_SAMPLED_BIT:
return AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
case vk::VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT:
return AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
case vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT:
case vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT:
// Alias of AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER which is defined in later Android API versions.
return AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
default:
return 0u;
}
}
deUint64 AndroidHardwareBufferExternalApi26::vkCreateToAhbUsage(vk::VkImageCreateFlagBits vkFlags)
{
switch(vkFlags)
{
case vk::VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT:
case vk::VK_IMAGE_CREATE_EXTENDED_USAGE_BIT:
// No AHB equivalent.
return 0u;
case vk::VK_IMAGE_CREATE_PROTECTED_BIT:
return AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
default:
return 0u;
}
}
deUint32 AndroidHardwareBufferExternalApi26::vkFormatToAhbFormat(vk::VkFormat vkFormat)
{
switch(vkFormat)
{
case vk::VK_FORMAT_R8G8B8A8_UNORM:
return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
case vk::VK_FORMAT_R8G8B8_UNORM:
return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
case vk::VK_FORMAT_R16G16B16A16_SFLOAT:
return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
default:
return 0u;
}
}
deUint64 AndroidHardwareBufferExternalApi26::mustSupportAhbUsageFlags()
{
return (AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT);
}
#if defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER)
class AndroidHardwareBufferExternalApi28 : public AndroidHardwareBufferExternalApi26
{
public:
virtual deUint64 vkCreateToAhbUsage(vk::VkImageCreateFlagBits vkFlag);
virtual deUint32 vkFormatToAhbFormat(vk::VkFormat vkFormat);
virtual deUint64 mustSupportAhbUsageFlags();
AndroidHardwareBufferExternalApi28() : AndroidHardwareBufferExternalApi26() {};
virtual ~AndroidHardwareBufferExternalApi28() {};
private:
// Stop the compiler generating methods of copy the object
AndroidHardwareBufferExternalApi28(AndroidHardwareBufferExternalApi28 const& copy); // Not Implemented
AndroidHardwareBufferExternalApi28& operator=(AndroidHardwareBufferExternalApi28 const& copy); // Not Implemented
};
deUint64 AndroidHardwareBufferExternalApi28::vkCreateToAhbUsage(vk::VkImageCreateFlagBits vkFlags)
{
switch(vkFlags)
{
case vk::VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT:
return AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP;
default:
return AndroidHardwareBufferExternalApi26::vkCreateToAhbUsage(vkFlags);
}
}
deUint32 AndroidHardwareBufferExternalApi28::vkFormatToAhbFormat(vk::VkFormat vkFormat)
{
switch(vkFormat)
{
case vk::VK_FORMAT_D16_UNORM:
return AHARDWAREBUFFER_FORMAT_D16_UNORM;
case vk::VK_FORMAT_X8_D24_UNORM_PACK32:
return AHARDWAREBUFFER_FORMAT_D24_UNORM;
case vk::VK_FORMAT_D24_UNORM_S8_UINT:
return AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT;
case vk::VK_FORMAT_D32_SFLOAT:
return AHARDWAREBUFFER_FORMAT_D32_FLOAT;
case vk::VK_FORMAT_D32_SFLOAT_S8_UINT:
return AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT;
case vk::VK_FORMAT_S8_UINT:
return AHARDWAREBUFFER_FORMAT_S8_UINT;
default:
return AndroidHardwareBufferExternalApi26::vkFormatToAhbFormat(vkFormat);
}
}
deUint64 AndroidHardwareBufferExternalApi28::mustSupportAhbUsageFlags()
{
return AndroidHardwareBufferExternalApi26::mustSupportAhbUsageFlags() | AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP | AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE;
}
#endif // defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER)
#endif // defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER)
#endif // (DE_OS == DE_OS_ANDROID)
AndroidHardwareBufferExternalApi* AndroidHardwareBufferExternalApi::getInstance()
{
#if (DE_OS == DE_OS_ANDROID)
deInt32 sdkVersion = checkAnbApiBuild();
#if defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER)
# if defined(__ANDROID_API_P__) && (DE_ANDROID_API >= __ANDROID_API_P__)
if (sdkVersion >= __ANDROID_API_P__ )
{
static AndroidHardwareBufferExternalApi28 api28Instance;
return &api28Instance;
}
# endif
# if defined(__ANDROID_API_O__) && (DE_ANDROID_API >= __ANDROID_API_O__)
if (sdkVersion >= __ANDROID_API_O__ )
{
static AndroidHardwareBufferExternalApi26 api26Instance;
return &api26Instance;
}
# endif
#endif // defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER)
DE_UNREF(sdkVersion);
#endif // DE_OS == DE_OS_ANDROID
return DE_NULL;
}
vk::VkPhysicalDeviceExternalMemoryHostPropertiesEXT getPhysicalDeviceExternalMemoryHostProperties(const vk::InstanceInterface& vki,
vk::VkPhysicalDevice physicalDevice)
{
vk::VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalProps =
{
vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT,
DE_NULL,
0u,
};
vk::VkPhysicalDeviceProperties2 props2;
deMemset(&props2, 0, sizeof(props2));
props2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
props2.pNext = &externalProps;
vki.getPhysicalDeviceProperties2(physicalDevice, &props2);
return externalProps;
}
} // ExternalMemoryUtil
} // vkt