blob: 54eec2945e337db1b052dc6d35e352d04bf88c1a [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan CTS Framework
* --------------------
*
* Copyright (c) 2015 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.
*
*//*!
* \file
* \brief Null (dummy) Vulkan implementation.
*//*--------------------------------------------------------------------*/
#include "vkNullDriver.hpp"
#include "vkPlatform.hpp"
#include "vkImageUtil.hpp"
#include "vkQueryUtil.hpp"
#include "tcuFunctionLibrary.hpp"
#include "deMemory.h"
#if (DE_OS == DE_OS_ANDROID) && defined(__ANDROID_API_O__) && \
(DE_ANDROID_API >= __ANDROID_API_O__ /* __ANDROID_API_O__ */)
#define USE_ANDROID_O_HARDWARE_BUFFER
#endif
#if defined(USE_ANDROID_O_HARDWARE_BUFFER)
#include <android/hardware_buffer.h>
#endif
#include <stdexcept>
#include <algorithm>
namespace vk
{
namespace
{
using std::vector;
// Memory management
template <typename T>
void *allocateSystemMem(const VkAllocationCallbacks *pAllocator, VkSystemAllocationScope scope)
{
void *ptr = pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(T), sizeof(void *), scope);
if (!ptr)
throw std::bad_alloc();
return ptr;
}
void freeSystemMem(const VkAllocationCallbacks *pAllocator, void *mem)
{
pAllocator->pfnFree(pAllocator->pUserData, mem);
}
template <typename Object, typename Handle, typename Parent, typename CreateInfo>
Handle allocateHandle(Parent parent, const CreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator)
{
Object *obj = DE_NULL;
if (pAllocator)
{
void *mem = allocateSystemMem<Object>(pAllocator, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
try
{
obj = new (mem) Object(parent, pCreateInfo);
DE_ASSERT(obj == mem);
}
catch (...)
{
pAllocator->pfnFree(pAllocator->pUserData, mem);
throw;
}
}
else
obj = new Object(parent, pCreateInfo);
return reinterpret_cast<Handle>(obj);
}
template <typename Object, typename Handle, typename CreateInfo>
Handle allocateHandle(const CreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator)
{
Object *obj = DE_NULL;
if (pAllocator)
{
void *mem = allocateSystemMem<Object>(pAllocator, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
try
{
obj = new (mem) Object(pCreateInfo);
DE_ASSERT(obj == mem);
}
catch (...)
{
pAllocator->pfnFree(pAllocator->pUserData, mem);
throw;
}
}
else
obj = new Object(pCreateInfo);
return reinterpret_cast<Handle>(obj);
}
template <typename Object, typename Handle, typename Parent>
Handle allocateHandle(Parent parent, const VkAllocationCallbacks *pAllocator)
{
Object *obj = DE_NULL;
if (pAllocator)
{
void *mem = allocateSystemMem<Object>(pAllocator, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
try
{
obj = new (mem) Object(parent);
DE_ASSERT(obj == mem);
}
catch (...)
{
pAllocator->pfnFree(pAllocator->pUserData, mem);
throw;
}
}
else
obj = new Object(parent);
return reinterpret_cast<Handle>(obj);
}
template <typename Object, typename Handle>
void freeHandle(Handle handle, const VkAllocationCallbacks *pAllocator)
{
Object *obj = reinterpret_cast<Object *>(handle);
if (pAllocator)
{
obj->~Object();
freeSystemMem(pAllocator, reinterpret_cast<void *>(obj));
}
else
delete obj;
}
template <typename Object, typename BaseObject, typename Handle, typename Parent, typename CreateInfo>
Handle allocateNonDispHandle(Parent parent, const CreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator)
{
Object *const obj = allocateHandle<Object, Object *>(parent, pCreateInfo, pAllocator);
return Handle((uint64_t)(uintptr_t) static_cast<BaseObject *>(obj));
}
template <typename Object, typename Handle, typename Parent, typename CreateInfo>
Handle allocateNonDispHandle(Parent parent, const CreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator)
{
return allocateNonDispHandle<Object, Object, Handle, Parent, CreateInfo>(parent, pCreateInfo, pAllocator);
}
template <typename Object, typename Handle, typename Parent>
Handle allocateNonDispHandle(Parent parent, const VkAllocationCallbacks *pAllocator)
{
Object *const obj = allocateHandle<Object, Object *>(parent, pAllocator);
return Handle((uint64_t)(uintptr_t)obj);
}
template <typename Object, typename Handle>
void freeNonDispHandle(Handle handle, const VkAllocationCallbacks *pAllocator)
{
freeHandle<Object>(reinterpret_cast<Object *>((uintptr_t)handle.getInternal()), pAllocator);
}
// Object definitions
#define VK_NULL_RETURN(STMT) \
do \
{ \
try \
{ \
STMT; \
return VK_SUCCESS; \
} \
catch (const std::bad_alloc &) \
{ \
return VK_ERROR_OUT_OF_HOST_MEMORY; \
} \
catch (VkResult res) \
{ \
return res; \
} \
} while (false)
// \todo [2015-07-14 pyry] Check FUNC type by checkedCastToPtr<T>() or similar
#define VK_NULL_FUNC_ENTRY(NAME, FUNC) \
{ \
#NAME, (deFunctionPtr)FUNC \
} // NOLINT(FUNC)
#define VK_NULL_DEFINE_DEVICE_OBJ(NAME) \
struct NAME \
{ \
NAME(VkDevice, const Vk##NAME##CreateInfo *) \
{ \
} \
}
VK_NULL_DEFINE_DEVICE_OBJ(Fence);
VK_NULL_DEFINE_DEVICE_OBJ(Semaphore);
VK_NULL_DEFINE_DEVICE_OBJ(Event);
VK_NULL_DEFINE_DEVICE_OBJ(QueryPool);
VK_NULL_DEFINE_DEVICE_OBJ(BufferView);
VK_NULL_DEFINE_DEVICE_OBJ(ImageView);
#ifndef CTS_USES_VULKANSC
VK_NULL_DEFINE_DEVICE_OBJ(ShaderModule);
#endif // CTS_USES_VULKANSC
VK_NULL_DEFINE_DEVICE_OBJ(PipelineCache);
VK_NULL_DEFINE_DEVICE_OBJ(PipelineLayout);
VK_NULL_DEFINE_DEVICE_OBJ(DescriptorSetLayout);
VK_NULL_DEFINE_DEVICE_OBJ(Sampler);
VK_NULL_DEFINE_DEVICE_OBJ(Framebuffer);
class Instance
{
public:
Instance(const VkInstanceCreateInfo *instanceInfo);
~Instance(void)
{
}
PFN_vkVoidFunction getProcAddr(const char *name) const
{
return (PFN_vkVoidFunction)m_functions.getFunction(name);
}
private:
const tcu::StaticFunctionLibrary m_functions;
};
class SurfaceKHR
{
public:
#ifndef CTS_USES_VULKANSC
SurfaceKHR(VkInstance, const VkXlibSurfaceCreateInfoKHR *)
{
}
SurfaceKHR(VkInstance, const VkXcbSurfaceCreateInfoKHR *)
{
}
SurfaceKHR(VkInstance, const VkWaylandSurfaceCreateInfoKHR *)
{
}
SurfaceKHR(VkInstance, const VkAndroidSurfaceCreateInfoKHR *)
{
}
SurfaceKHR(VkInstance, const VkWin32SurfaceCreateInfoKHR *)
{
}
#endif // CTS_USES_VULKANSC
SurfaceKHR(VkInstance, const VkDisplaySurfaceCreateInfoKHR *)
{
}
#ifndef CTS_USES_VULKANSC
SurfaceKHR(VkInstance, const VkViSurfaceCreateInfoNN *)
{
}
SurfaceKHR(VkInstance, const VkIOSSurfaceCreateInfoMVK *)
{
}
SurfaceKHR(VkInstance, const VkMacOSSurfaceCreateInfoMVK *)
{
}
SurfaceKHR(VkInstance, const VkImagePipeSurfaceCreateInfoFUCHSIA *)
{
}
#endif // CTS_USES_VULKANSC
SurfaceKHR(VkInstance, const VkHeadlessSurfaceCreateInfoEXT *)
{
}
#ifndef CTS_USES_VULKANSC
SurfaceKHR(VkInstance, const VkStreamDescriptorSurfaceCreateInfoGGP *)
{
}
SurfaceKHR(VkInstance, const VkMetalSurfaceCreateInfoEXT *)
{
}
#endif // CTS_USES_VULKANSC
~SurfaceKHR(void)
{
}
};
class DisplayModeKHR
{
public:
DisplayModeKHR(VkDisplayKHR, const VkDisplayModeCreateInfoKHR *)
{
}
~DisplayModeKHR(void)
{
}
};
#ifndef CTS_USES_VULKANSC
class DebugReportCallbackEXT
{
public:
DebugReportCallbackEXT(VkInstance, const VkDebugReportCallbackCreateInfoEXT *)
{
}
~DebugReportCallbackEXT(void)
{
}
};
class CuModuleNVX
{
public:
CuModuleNVX(VkDevice, const VkCuModuleCreateInfoNVX *)
{
}
~CuModuleNVX(void)
{
}
};
class CuFunctionNVX
{
public:
CuFunctionNVX(VkDevice, const VkCuFunctionCreateInfoNVX *)
{
}
~CuFunctionNVX(void)
{
}
};
#endif // CTS_USES_VULKANSC
class Device
{
public:
Device(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *deviceInfo);
~Device(void)
{
}
PFN_vkVoidFunction getProcAddr(const char *name) const
{
return (PFN_vkVoidFunction)m_functions.getFunction(name);
}
private:
const tcu::StaticFunctionLibrary m_functions;
};
class Pipeline
{
public:
Pipeline(VkDevice, const VkGraphicsPipelineCreateInfo *)
{
}
Pipeline(VkDevice, const VkComputePipelineCreateInfo *)
{
}
#ifndef CTS_USES_VULKANSC
Pipeline(VkDevice, const VkRayTracingPipelineCreateInfoNV *)
{
}
Pipeline(VkDevice, const VkRayTracingPipelineCreateInfoKHR *)
{
}
#endif // CTS_USES_VULKANSC
};
class RenderPass
{
public:
RenderPass(VkDevice, const VkRenderPassCreateInfo *)
{
}
RenderPass(VkDevice, const VkRenderPassCreateInfo2 *)
{
}
};
class SwapchainKHR
{
public:
SwapchainKHR(VkDevice, const VkSwapchainCreateInfoKHR *)
{
}
~SwapchainKHR(void)
{
}
};
class SamplerYcbcrConversion
{
public:
SamplerYcbcrConversion(VkDevice, const VkSamplerYcbcrConversionCreateInfo *)
{
}
};
class Buffer
{
public:
Buffer(VkDevice, const VkBufferCreateInfo *pCreateInfo) : m_size(pCreateInfo->size)
{
}
VkDeviceSize getSize(void) const
{
return m_size;
}
private:
const VkDeviceSize m_size;
};
VkExternalMemoryHandleTypeFlags getExternalTypesHandle(const VkImageCreateInfo *pCreateInfo)
{
const VkExternalMemoryImageCreateInfo *const externalInfo =
findStructure<VkExternalMemoryImageCreateInfo>(pCreateInfo->pNext);
return externalInfo ? externalInfo->handleTypes : 0u;
}
class Image
{
public:
Image(VkDevice, const VkImageCreateInfo *pCreateInfo)
: m_imageType(pCreateInfo->imageType)
, m_format(pCreateInfo->format)
, m_extent(pCreateInfo->extent)
, m_arrayLayers(pCreateInfo->arrayLayers)
, m_samples(pCreateInfo->samples)
, m_usage(pCreateInfo->usage)
, m_flags(pCreateInfo->flags)
, m_externalHandleTypes(getExternalTypesHandle(pCreateInfo))
{
}
VkImageType getImageType(void) const
{
return m_imageType;
}
VkFormat getFormat(void) const
{
return m_format;
}
VkExtent3D getExtent(void) const
{
return m_extent;
}
uint32_t getArrayLayers(void) const
{
return m_arrayLayers;
}
VkSampleCountFlagBits getSamples(void) const
{
return m_samples;
}
VkImageUsageFlags getUsage(void) const
{
return m_usage;
}
VkImageCreateFlags getFlags(void) const
{
return m_flags;
}
VkExternalMemoryHandleTypeFlags getExternalHandleTypes(void) const
{
return m_externalHandleTypes;
}
private:
const VkImageType m_imageType;
const VkFormat m_format;
const VkExtent3D m_extent;
const uint32_t m_arrayLayers;
const VkSampleCountFlagBits m_samples;
const VkImageUsageFlags m_usage;
const VkImageCreateFlags m_flags;
const VkExternalMemoryHandleTypeFlags m_externalHandleTypes;
};
void *allocateHeap(const VkMemoryAllocateInfo *pAllocInfo)
{
// \todo [2015-12-03 pyry] Alignment requirements?
// \todo [2015-12-03 pyry] Empty allocations okay?
if (pAllocInfo->allocationSize > 0)
{
void *const heapPtr = deMalloc((size_t)pAllocInfo->allocationSize);
if (!heapPtr)
throw std::bad_alloc();
return heapPtr;
}
else
return DE_NULL;
}
void freeHeap(void *ptr)
{
deFree(ptr);
}
class DeviceMemory
{
public:
virtual ~DeviceMemory(void)
{
}
virtual void *map(void) = 0;
virtual void unmap(void) = 0;
};
class PrivateDeviceMemory : public DeviceMemory
{
public:
PrivateDeviceMemory(VkDevice, const VkMemoryAllocateInfo *pAllocInfo) : m_memory(allocateHeap(pAllocInfo))
{
// \todo [2016-08-03 pyry] In some cases leaving data unintialized would help valgrind analysis,
// but currently it mostly hinders it.
if (m_memory)
deMemset(m_memory, 0xcd, (size_t)pAllocInfo->allocationSize);
}
virtual ~PrivateDeviceMemory(void)
{
freeHeap(m_memory);
}
virtual void *map(void) /*override*/
{
return m_memory;
}
virtual void unmap(void) /*override*/
{
}
private:
void *const m_memory;
};
#ifndef CTS_USES_VULKANSC
#if defined(USE_ANDROID_O_HARDWARE_BUFFER)
AHardwareBuffer *findOrCreateHwBuffer(const VkMemoryAllocateInfo *pAllocInfo)
{
const VkExportMemoryAllocateInfo *const exportInfo = findStructure<VkExportMemoryAllocateInfo>(pAllocInfo->pNext);
const VkImportAndroidHardwareBufferInfoANDROID *const importInfo =
findStructure<VkImportAndroidHardwareBufferInfoANDROID>(pAllocInfo->pNext);
const VkMemoryDedicatedAllocateInfo *const dedicatedInfo =
findStructure<VkMemoryDedicatedAllocateInfo>(pAllocInfo->pNext);
const Image *const image = dedicatedInfo && !!dedicatedInfo->image ?
reinterpret_cast<const Image *>(dedicatedInfo->image.getInternal()) :
DE_NULL;
AHardwareBuffer *hwbuffer = DE_NULL;
// Import and export aren't mutually exclusive; we can have both simultaneously.
DE_ASSERT((importInfo && importInfo->buffer.internal) ||
(exportInfo &&
(exportInfo->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) != 0));
if (importInfo && importInfo->buffer.internal)
{
hwbuffer = (AHardwareBuffer *)importInfo->buffer.internal;
AHardwareBuffer_acquire(hwbuffer);
}
else if (exportInfo &&
(exportInfo->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) != 0)
{
AHardwareBuffer_Desc hwbufferDesc;
deMemset(&hwbufferDesc, 0, sizeof(hwbufferDesc));
if (image)
{
hwbufferDesc.width = image->getExtent().width;
hwbufferDesc.height = image->getExtent().height;
hwbufferDesc.layers = image->getArrayLayers();
switch (image->getFormat())
{
case VK_FORMAT_R8G8B8A8_UNORM:
hwbufferDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
break;
case VK_FORMAT_R8G8B8_UNORM:
hwbufferDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
break;
case VK_FORMAT_R5G6B5_UNORM_PACK16:
hwbufferDesc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
break;
case VK_FORMAT_R16G16B16A16_SFLOAT:
hwbufferDesc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
break;
case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
hwbufferDesc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
break;
default:
DE_FATAL("Unsupported image format for Android hardware buffer export");
break;
}
if ((image->getUsage() & VK_IMAGE_USAGE_SAMPLED_BIT) != 0)
hwbufferDesc.usage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
if ((image->getUsage() & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0)
hwbufferDesc.usage |= AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
// if ((image->getFlags() & VK_IMAGE_CREATE_PROTECTED_BIT) != 0)
// hwbufferDesc.usage |= AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
// Make sure we have at least one AHB GPU usage, even if the image doesn't have any
// Vulkan usages with corresponding to AHB GPU usages.
if ((image->getUsage() & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) == 0)
hwbufferDesc.usage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
}
else
{
hwbufferDesc.width = static_cast<uint32_t>(pAllocInfo->allocationSize);
hwbufferDesc.height = 1, hwbufferDesc.layers = 1, hwbufferDesc.format = AHARDWAREBUFFER_FORMAT_BLOB,
hwbufferDesc.usage = AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER;
}
AHardwareBuffer_allocate(&hwbufferDesc, &hwbuffer);
}
return hwbuffer;
}
class ExternalDeviceMemoryAndroid : public DeviceMemory
{
public:
ExternalDeviceMemoryAndroid(VkDevice, const VkMemoryAllocateInfo *pAllocInfo)
: m_hwbuffer(findOrCreateHwBuffer(pAllocInfo))
{
}
virtual ~ExternalDeviceMemoryAndroid(void)
{
if (m_hwbuffer)
AHardwareBuffer_release(m_hwbuffer);
}
virtual void *map(void) /*override*/
{
void *p;
AHardwareBuffer_lock(m_hwbuffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
-1, NULL, &p);
return p;
}
virtual void unmap(void) /*override*/
{
AHardwareBuffer_unlock(m_hwbuffer, NULL);
}
AHardwareBuffer *getHwBuffer(void)
{
return m_hwbuffer;
}
private:
AHardwareBuffer *const m_hwbuffer;
};
#endif // defined(USE_ANDROID_O_HARDWARE_BUFFER)
class IndirectCommandsLayoutNV
{
public:
IndirectCommandsLayoutNV(VkDevice, const VkIndirectCommandsLayoutCreateInfoNV *)
{
}
};
class AccelerationStructureNV
{
public:
AccelerationStructureNV(VkDevice, const VkAccelerationStructureCreateInfoNV *)
{
}
};
class AccelerationStructureKHR
{
public:
AccelerationStructureKHR(VkDevice, const VkAccelerationStructureCreateInfoKHR *)
{
}
};
#endif // CTS_USES_VULKANSC
class DebugUtilsMessengerEXT
{
public:
DebugUtilsMessengerEXT(VkInstance, const VkDebugUtilsMessengerCreateInfoEXT *)
{
}
};
class DeferredOperationKHR
{
public:
DeferredOperationKHR(VkDevice)
{
}
};
#ifndef CTS_USES_VULKANSC
class VideoSessionKHR
{
public:
VideoSessionKHR(VkDevice, const VkVideoSessionCreateInfoKHR *)
{
}
};
class VideoSessionParametersKHR
{
public:
VideoSessionParametersKHR(VkDevice, const VkVideoSessionParametersCreateInfoKHR *)
{
}
};
class ValidationCacheEXT
{
public:
ValidationCacheEXT(VkDevice, const VkValidationCacheCreateInfoEXT *)
{
}
};
#endif // CTS_USES_VULKANSC
class CommandBuffer
{
public:
CommandBuffer(VkDevice, VkCommandPool, VkCommandBufferLevel)
{
}
};
#ifndef CTS_USES_VULKANSC
class DescriptorUpdateTemplate
{
public:
DescriptorUpdateTemplate(VkDevice, const VkDescriptorUpdateTemplateCreateInfo *)
{
}
};
class PrivateDataSlotEXT
{
public:
PrivateDataSlotEXT(VkDevice, const VkPrivateDataSlotCreateInfoEXT *)
{
}
};
#endif // CTS_USES_VULKANSC
class CommandPool
{
public:
CommandPool(VkDevice device, const VkCommandPoolCreateInfo *) : m_device(device)
{
}
#ifndef CTS_USES_VULKANSC
~CommandPool(void);
#endif // CTS_USES_VULKANSC
VkCommandBuffer allocate(VkCommandBufferLevel level);
void free(VkCommandBuffer buffer);
private:
const VkDevice m_device;
vector<CommandBuffer *> m_buffers;
};
#ifndef CTS_USES_VULKANSC
CommandPool::~CommandPool(void)
{
for (size_t ndx = 0; ndx < m_buffers.size(); ++ndx)
delete m_buffers[ndx];
}
#endif // CTS_USES_VULKANSC
VkCommandBuffer CommandPool::allocate(VkCommandBufferLevel level)
{
CommandBuffer *const impl = new CommandBuffer(m_device, VkCommandPool(reinterpret_cast<uintptr_t>(this)), level);
try
{
m_buffers.push_back(impl);
}
catch (...)
{
delete impl;
throw;
}
return reinterpret_cast<VkCommandBuffer>(impl);
}
void CommandPool::free(VkCommandBuffer buffer)
{
CommandBuffer *const impl = reinterpret_cast<CommandBuffer *>(buffer);
for (size_t ndx = 0; ndx < m_buffers.size(); ++ndx)
{
if (m_buffers[ndx] == impl)
{
std::swap(m_buffers[ndx], m_buffers.back());
m_buffers.pop_back();
delete impl;
return;
}
}
DE_FATAL("VkCommandBuffer not owned by VkCommandPool");
}
class DescriptorSet
{
public:
DescriptorSet(VkDevice, VkDescriptorPool, VkDescriptorSetLayout)
{
}
};
class DescriptorPool
{
public:
DescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo)
: m_device(device)
, m_flags(pCreateInfo->flags)
{
}
~DescriptorPool(void)
{
reset();
}
VkDescriptorSet allocate(VkDescriptorSetLayout setLayout);
void free(VkDescriptorSet set);
void reset(void);
private:
const VkDevice m_device;
const VkDescriptorPoolCreateFlags m_flags;
vector<DescriptorSet *> m_managedSets;
};
VkDescriptorSet DescriptorPool::allocate(VkDescriptorSetLayout setLayout)
{
DescriptorSet *const impl =
new DescriptorSet(m_device, VkDescriptorPool(reinterpret_cast<uintptr_t>(this)), setLayout);
try
{
m_managedSets.push_back(impl);
}
catch (...)
{
delete impl;
throw;
}
return VkDescriptorSet(reinterpret_cast<uintptr_t>(impl));
}
void DescriptorPool::free(VkDescriptorSet set)
{
DescriptorSet *const impl = reinterpret_cast<DescriptorSet *>((uintptr_t)set.getInternal());
DE_ASSERT(m_flags & VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT);
DE_UNREF(m_flags);
for (size_t ndx = 0; ndx < m_managedSets.size(); ++ndx)
{
if (m_managedSets[ndx] == impl)
{
std::swap(m_managedSets[ndx], m_managedSets.back());
m_managedSets.pop_back();
delete impl;
return;
}
}
DE_FATAL("VkDescriptorSet not owned by VkDescriptorPool");
}
void DescriptorPool::reset(void)
{
for (size_t ndx = 0; ndx < m_managedSets.size(); ++ndx)
delete m_managedSets[ndx];
m_managedSets.clear();
}
// API implementation
extern "C"
{
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL getDeviceProcAddr(VkDevice device, const char *pName)
{
return reinterpret_cast<Device *>(device)->getProcAddr(pName);
}
VKAPI_ATTR VkResult VKAPI_CALL createGraphicsPipelines(VkDevice device, VkPipelineCache, uint32_t count,
const VkGraphicsPipelineCreateInfo *pCreateInfos,
const VkAllocationCallbacks *pAllocator,
VkPipeline *pPipelines)
{
uint32_t allocNdx;
try
{
for (allocNdx = 0; allocNdx < count; allocNdx++)
pPipelines[allocNdx] =
allocateNonDispHandle<Pipeline, VkPipeline>(device, pCreateInfos + allocNdx, pAllocator);
return VK_SUCCESS;
}
catch (const std::bad_alloc &)
{
for (uint32_t freeNdx = 0; freeNdx < allocNdx; freeNdx++)
freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
catch (VkResult err)
{
for (uint32_t freeNdx = 0; freeNdx < allocNdx; freeNdx++)
freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
return err;
}
}
VKAPI_ATTR VkResult VKAPI_CALL createComputePipelines(VkDevice device, VkPipelineCache, uint32_t count,
const VkComputePipelineCreateInfo *pCreateInfos,
const VkAllocationCallbacks *pAllocator,
VkPipeline *pPipelines)
{
uint32_t allocNdx;
try
{
for (allocNdx = 0; allocNdx < count; allocNdx++)
pPipelines[allocNdx] =
allocateNonDispHandle<Pipeline, VkPipeline>(device, pCreateInfos + allocNdx, pAllocator);
return VK_SUCCESS;
}
catch (const std::bad_alloc &)
{
for (uint32_t freeNdx = 0; freeNdx < allocNdx; freeNdx++)
freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
catch (VkResult err)
{
for (uint32_t freeNdx = 0; freeNdx < allocNdx; freeNdx++)
freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
return err;
}
}
#ifndef CTS_USES_VULKANSC
VKAPI_ATTR VkResult VKAPI_CALL createRayTracingPipelinesNV(VkDevice device, VkPipelineCache, uint32_t count,
const VkRayTracingPipelineCreateInfoKHR *pCreateInfos,
const VkAllocationCallbacks *pAllocator,
VkPipeline *pPipelines)
{
uint32_t allocNdx;
try
{
for (allocNdx = 0; allocNdx < count; allocNdx++)
pPipelines[allocNdx] =
allocateNonDispHandle<Pipeline, VkPipeline>(device, pCreateInfos + allocNdx, pAllocator);
return VK_SUCCESS;
}
catch (const std::bad_alloc &)
{
for (uint32_t freeNdx = 0; freeNdx < allocNdx; freeNdx++)
freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
catch (VkResult err)
{
for (uint32_t freeNdx = 0; freeNdx < allocNdx; freeNdx++)
freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
return err;
}
}
VKAPI_ATTR VkResult VKAPI_CALL createRayTracingPipelinesKHR(VkDevice device, VkPipelineCache, uint32_t count,
const VkRayTracingPipelineCreateInfoKHR *pCreateInfos,
const VkAllocationCallbacks *pAllocator,
VkPipeline *pPipelines)
{
uint32_t allocNdx;
try
{
for (allocNdx = 0; allocNdx < count; allocNdx++)
pPipelines[allocNdx] =
allocateNonDispHandle<Pipeline, VkPipeline>(device, pCreateInfos + allocNdx, pAllocator);
return VK_SUCCESS;
}
catch (const std::bad_alloc &)
{
for (uint32_t freeNdx = 0; freeNdx < allocNdx; freeNdx++)
freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
catch (VkResult err)
{
for (uint32_t freeNdx = 0; freeNdx < allocNdx; freeNdx++)
freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
return err;
}
}
#endif // CTS_USES_VULKANSC
VKAPI_ATTR VkResult VKAPI_CALL enumeratePhysicalDevices(VkInstance, uint32_t *pPhysicalDeviceCount,
VkPhysicalDevice *pDevices)
{
if (pDevices && *pPhysicalDeviceCount >= 1u)
*pDevices = reinterpret_cast<VkPhysicalDevice>((void *)(uintptr_t)1u);
*pPhysicalDeviceCount = 1;
return VK_SUCCESS;
}
VkResult enumerateExtensions(uint32_t numExtensions, const VkExtensionProperties *extensions,
uint32_t *pPropertyCount, VkExtensionProperties *pProperties)
{
const uint32_t dstSize = pPropertyCount ? *pPropertyCount : 0;
if (pPropertyCount)
*pPropertyCount = numExtensions;
if (pProperties)
{
for (uint32_t ndx = 0; ndx < de::min(numExtensions, dstSize); ++ndx)
pProperties[ndx] = extensions[ndx];
if (dstSize < numExtensions)
return VK_INCOMPLETE;
}
return VK_SUCCESS;
}
VKAPI_ATTR VkResult VKAPI_CALL enumerateInstanceExtensionProperties(const char *pLayerName,
uint32_t *pPropertyCount,
VkExtensionProperties *pProperties)
{
static const VkExtensionProperties s_extensions[] = {
{"VK_KHR_get_physical_device_properties2", 1u},
{"VK_KHR_external_memory_capabilities", 1u},
};
if (!pLayerName)
return enumerateExtensions((uint32_t)DE_LENGTH_OF_ARRAY(s_extensions), s_extensions, pPropertyCount,
pProperties);
else
return enumerateExtensions(0, DE_NULL, pPropertyCount, pProperties);
}
VKAPI_ATTR VkResult VKAPI_CALL enumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
const char *pLayerName, uint32_t *pPropertyCount,
VkExtensionProperties *pProperties)
{
DE_UNREF(physicalDevice);
static const VkExtensionProperties s_extensions[] = {
{"VK_KHR_bind_memory2", 1u},
{"VK_KHR_external_memory", 1u},
{"VK_KHR_get_memory_requirements2", 1u},
{"VK_KHR_maintenance1", 1u},
{"VK_KHR_sampler_ycbcr_conversion", 1u},
#if defined(USE_ANDROID_O_HARDWARE_BUFFER)
{"VK_ANDROID_external_memory_android_hardware_buffer", 1u},
#endif
};
if (!pLayerName)
return enumerateExtensions((uint32_t)DE_LENGTH_OF_ARRAY(s_extensions), s_extensions, pPropertyCount,
pProperties);
else
return enumerateExtensions(0, DE_NULL, pPropertyCount, pProperties);
}
VKAPI_ATTR void VKAPI_CALL getPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
VkPhysicalDeviceFeatures *pFeatures)
{
DE_UNREF(physicalDevice);
// Enable all features allow as many tests to run as possible
pFeatures->robustBufferAccess = VK_TRUE;
pFeatures->fullDrawIndexUint32 = VK_TRUE;
pFeatures->imageCubeArray = VK_TRUE;
pFeatures->independentBlend = VK_TRUE;
pFeatures->geometryShader = VK_TRUE;
pFeatures->tessellationShader = VK_TRUE;
pFeatures->sampleRateShading = VK_TRUE;
pFeatures->dualSrcBlend = VK_TRUE;
pFeatures->logicOp = VK_TRUE;
pFeatures->multiDrawIndirect = VK_TRUE;
pFeatures->drawIndirectFirstInstance = VK_TRUE;
pFeatures->depthClamp = VK_TRUE;
pFeatures->depthBiasClamp = VK_TRUE;
pFeatures->fillModeNonSolid = VK_TRUE;
pFeatures->depthBounds = VK_TRUE;
pFeatures->wideLines = VK_TRUE;
pFeatures->largePoints = VK_TRUE;
pFeatures->alphaToOne = VK_TRUE;
pFeatures->multiViewport = VK_TRUE;
pFeatures->samplerAnisotropy = VK_TRUE;
pFeatures->textureCompressionETC2 = VK_TRUE;
pFeatures->textureCompressionASTC_LDR = VK_TRUE;
pFeatures->textureCompressionBC = VK_TRUE;
pFeatures->occlusionQueryPrecise = VK_TRUE;
pFeatures->pipelineStatisticsQuery = VK_TRUE;
pFeatures->vertexPipelineStoresAndAtomics = VK_TRUE;
pFeatures->fragmentStoresAndAtomics = VK_TRUE;
pFeatures->shaderTessellationAndGeometryPointSize = VK_TRUE;
pFeatures->shaderImageGatherExtended = VK_TRUE;
pFeatures->shaderStorageImageExtendedFormats = VK_TRUE;
pFeatures->shaderStorageImageMultisample = VK_TRUE;
pFeatures->shaderStorageImageReadWithoutFormat = VK_TRUE;
pFeatures->shaderStorageImageWriteWithoutFormat = VK_TRUE;
pFeatures->shaderUniformBufferArrayDynamicIndexing = VK_TRUE;
pFeatures->shaderSampledImageArrayDynamicIndexing = VK_TRUE;
pFeatures->shaderStorageBufferArrayDynamicIndexing = VK_TRUE;
pFeatures->shaderStorageImageArrayDynamicIndexing = VK_TRUE;
pFeatures->shaderClipDistance = VK_TRUE;
pFeatures->shaderCullDistance = VK_TRUE;
pFeatures->shaderFloat64 = VK_TRUE;
pFeatures->shaderInt64 = VK_TRUE;
pFeatures->shaderInt16 = VK_TRUE;
pFeatures->shaderResourceResidency = VK_TRUE;
pFeatures->shaderResourceMinLod = VK_TRUE;
pFeatures->sparseBinding = VK_TRUE;
pFeatures->sparseResidencyBuffer = VK_TRUE;
pFeatures->sparseResidencyImage2D = VK_TRUE;
pFeatures->sparseResidencyImage3D = VK_TRUE;
pFeatures->sparseResidency2Samples = VK_TRUE;
pFeatures->sparseResidency4Samples = VK_TRUE;
pFeatures->sparseResidency8Samples = VK_TRUE;
pFeatures->sparseResidency16Samples = VK_TRUE;
pFeatures->sparseResidencyAliased = VK_TRUE;
pFeatures->variableMultisampleRate = VK_TRUE;
pFeatures->inheritedQueries = VK_TRUE;
}
VKAPI_ATTR void VKAPI_CALL getPhysicalDeviceProperties(VkPhysicalDevice, VkPhysicalDeviceProperties *props)
{
deMemset(props, 0, sizeof(VkPhysicalDeviceProperties));
props->apiVersion = VK_API_VERSION_1_1;
props->driverVersion = 1u;
props->deviceType = VK_PHYSICAL_DEVICE_TYPE_OTHER;
deMemcpy(props->deviceName, "null", 5);
// Spec minmax
props->limits.maxImageDimension1D = 4096;
props->limits.maxImageDimension2D = 4096;
props->limits.maxImageDimension3D = 256;
props->limits.maxImageDimensionCube = 4096;
props->limits.maxImageArrayLayers = 256;
props->limits.maxTexelBufferElements = 65536;
props->limits.maxUniformBufferRange = 16384;
props->limits.maxStorageBufferRange = 1u << 27;
props->limits.maxPushConstantsSize = 128;
props->limits.maxMemoryAllocationCount = 4096;
props->limits.maxSamplerAllocationCount = 4000;
props->limits.bufferImageGranularity = 131072;
props->limits.sparseAddressSpaceSize = 1u << 31;
props->limits.maxBoundDescriptorSets = 4;
props->limits.maxPerStageDescriptorSamplers = 16;
props->limits.maxPerStageDescriptorUniformBuffers = 12;
props->limits.maxPerStageDescriptorStorageBuffers = 4;
props->limits.maxPerStageDescriptorSampledImages = 16;
props->limits.maxPerStageDescriptorStorageImages = 4;
props->limits.maxPerStageDescriptorInputAttachments = 4;
props->limits.maxPerStageResources = 128;
props->limits.maxDescriptorSetSamplers = 96;
props->limits.maxDescriptorSetUniformBuffers = 72;
props->limits.maxDescriptorSetUniformBuffersDynamic = 8;
props->limits.maxDescriptorSetStorageBuffers = 24;
props->limits.maxDescriptorSetStorageBuffersDynamic = 4;
props->limits.maxDescriptorSetSampledImages = 96;
props->limits.maxDescriptorSetStorageImages = 24;
props->limits.maxDescriptorSetInputAttachments = 4;
props->limits.maxVertexInputAttributes = 16;
props->limits.maxVertexInputBindings = 16;
props->limits.maxVertexInputAttributeOffset = 2047;
props->limits.maxVertexInputBindingStride = 2048;
props->limits.maxVertexOutputComponents = 64;
props->limits.maxTessellationGenerationLevel = 64;
props->limits.maxTessellationPatchSize = 32;
props->limits.maxTessellationControlPerVertexInputComponents = 64;
props->limits.maxTessellationControlPerVertexOutputComponents = 64;
props->limits.maxTessellationControlPerPatchOutputComponents = 120;
props->limits.maxTessellationControlTotalOutputComponents = 2048;
props->limits.maxTessellationEvaluationInputComponents = 64;
props->limits.maxTessellationEvaluationOutputComponents = 64;
props->limits.maxGeometryShaderInvocations = 32;
props->limits.maxGeometryInputComponents = 64;
props->limits.maxGeometryOutputComponents = 64;
props->limits.maxGeometryOutputVertices = 256;
props->limits.maxGeometryTotalOutputComponents = 1024;
props->limits.maxFragmentInputComponents = 64;
props->limits.maxFragmentOutputAttachments = 4;
props->limits.maxFragmentDualSrcAttachments = 1;
props->limits.maxFragmentCombinedOutputResources = 4;
props->limits.maxComputeSharedMemorySize = 16384;
props->limits.maxComputeWorkGroupCount[0] = 65535;
props->limits.maxComputeWorkGroupCount[1] = 65535;
props->limits.maxComputeWorkGroupCount[2] = 65535;
props->limits.maxComputeWorkGroupInvocations = 128;
props->limits.maxComputeWorkGroupSize[0] = 128;
props->limits.maxComputeWorkGroupSize[1] = 128;
props->limits.maxComputeWorkGroupSize[2] = 128;
props->limits.subPixelPrecisionBits = 4;
props->limits.subTexelPrecisionBits = 4;
props->limits.mipmapPrecisionBits = 4;
props->limits.maxDrawIndexedIndexValue = 0xffffffffu;
props->limits.maxDrawIndirectCount = (1u << 16) - 1u;
props->limits.maxSamplerLodBias = 2.0f;
props->limits.maxSamplerAnisotropy = 16.0f;
props->limits.maxViewports = 16;
props->limits.maxViewportDimensions[0] = 4096;
props->limits.maxViewportDimensions[1] = 4096;
props->limits.viewportBoundsRange[0] = -8192.f;
props->limits.viewportBoundsRange[1] = 8191.f;
props->limits.viewportSubPixelBits = 0;
props->limits.minMemoryMapAlignment = 64;
props->limits.minTexelBufferOffsetAlignment = 256;
props->limits.minUniformBufferOffsetAlignment = 256;
props->limits.minStorageBufferOffsetAlignment = 256;
props->limits.minTexelOffset = -8;
props->limits.maxTexelOffset = 7;
props->limits.minTexelGatherOffset = -8;
props->limits.maxTexelGatherOffset = 7;
props->limits.minInterpolationOffset = -0.5f;
props->limits.maxInterpolationOffset = 0.5f; // -1ulp
props->limits.subPixelInterpolationOffsetBits = 4;
props->limits.maxFramebufferWidth = 4096;
props->limits.maxFramebufferHeight = 4096;
props->limits.maxFramebufferLayers = 256;
props->limits.framebufferColorSampleCounts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
props->limits.framebufferDepthSampleCounts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
props->limits.framebufferStencilSampleCounts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
props->limits.framebufferNoAttachmentsSampleCounts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
props->limits.maxColorAttachments = 4;
props->limits.sampledImageColorSampleCounts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
props->limits.sampledImageIntegerSampleCounts = VK_SAMPLE_COUNT_1_BIT;
props->limits.sampledImageDepthSampleCounts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
props->limits.sampledImageStencilSampleCounts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
props->limits.storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
props->limits.maxSampleMaskWords = 1;
props->limits.timestampComputeAndGraphics = VK_TRUE;
props->limits.timestampPeriod = 1.0f;
props->limits.maxClipDistances = 8;
props->limits.maxCullDistances = 8;
props->limits.maxCombinedClipAndCullDistances = 8;
props->limits.discreteQueuePriorities = 2;
props->limits.pointSizeRange[0] = 1.0f;
props->limits.pointSizeRange[1] = 64.0f; // -1ulp
props->limits.lineWidthRange[0] = 1.0f;
props->limits.lineWidthRange[1] = 8.0f; // -1ulp
props->limits.pointSizeGranularity = 1.0f;
props->limits.lineWidthGranularity = 1.0f;
props->limits.strictLines = 0;
props->limits.standardSampleLocations = VK_TRUE;
props->limits.optimalBufferCopyOffsetAlignment = 256;
props->limits.optimalBufferCopyRowPitchAlignment = 256;
props->limits.nonCoherentAtomSize = 128;
}
VKAPI_ATTR void VKAPI_CALL getPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice, uint32_t *count,
VkQueueFamilyProperties *props)
{
if (props && *count >= 1u)
{
deMemset(props, 0, sizeof(VkQueueFamilyProperties));
props->queueCount = 4u;
props->queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
props->timestampValidBits = 64;
}
*count = 1u;
}
VKAPI_ATTR void VKAPI_CALL getPhysicalDeviceMemoryProperties(VkPhysicalDevice,
VkPhysicalDeviceMemoryProperties *props)
{
deMemset(props, 0, sizeof(VkPhysicalDeviceMemoryProperties));
props->memoryTypeCount = 1u;
props->memoryTypes[0].heapIndex = 0u;
props->memoryTypes[0].propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
props->memoryHeapCount = 1u;
props->memoryHeaps[0].size = 1ull << 31;
props->memoryHeaps[0].flags = 0u;
}
VKAPI_ATTR void VKAPI_CALL getPhysicalDeviceFormatProperties(VkPhysicalDevice, VkFormat format,
VkFormatProperties *pFormatProperties)
{
const VkFormatFeatureFlags allFeatures =
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT | VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT |
VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT |
VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT |
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT | VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT |
VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT |
VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT |
VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT |
VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT |
VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT;
pFormatProperties->linearTilingFeatures = allFeatures;
pFormatProperties->optimalTilingFeatures = allFeatures;
pFormatProperties->bufferFeatures = allFeatures;
if (isYCbCrFormat(format) && getPlaneCount(format) > 1)
pFormatProperties->optimalTilingFeatures |= VK_FORMAT_FEATURE_DISJOINT_BIT;
}
VKAPI_ATTR VkResult VKAPI_CALL getPhysicalDeviceImageFormatProperties(
VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling,
VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties *pImageFormatProperties)
{
DE_UNREF(physicalDevice);
DE_UNREF(format);
DE_UNREF(type);
DE_UNREF(tiling);
DE_UNREF(usage);
DE_UNREF(flags);
pImageFormatProperties->maxArrayLayers = 8;
pImageFormatProperties->maxExtent.width = 4096;
pImageFormatProperties->maxExtent.height = 4096;
pImageFormatProperties->maxExtent.depth = 4096;
pImageFormatProperties->maxMipLevels = deLog2Ceil32(4096) + 1;
pImageFormatProperties->maxResourceSize = 64u * 1024u * 1024u;
pImageFormatProperties->sampleCounts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
return VK_SUCCESS;
}
VKAPI_ATTR void VKAPI_CALL getDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex,
VkQueue *pQueue)
{
DE_UNREF(device);
DE_UNREF(queueFamilyIndex);
if (pQueue)
*pQueue = reinterpret_cast<VkQueue>((uint64_t)queueIndex + 1);
}
VKAPI_ATTR void VKAPI_CALL getBufferMemoryRequirements(VkDevice, VkBuffer bufferHandle,
VkMemoryRequirements *requirements)
{
const Buffer *buffer = reinterpret_cast<const Buffer *>(bufferHandle.getInternal());
requirements->memoryTypeBits = 1u;
requirements->size = buffer->getSize();
requirements->alignment = (VkDeviceSize)1u;
}
VkDeviceSize getPackedImageDataSize(VkFormat format, VkExtent3D extent, VkSampleCountFlagBits samples)
{
return (VkDeviceSize)getPixelSize(mapVkFormat(format)) * (VkDeviceSize)extent.width *
(VkDeviceSize)extent.height * (VkDeviceSize)extent.depth * (VkDeviceSize)samples;
}
VkDeviceSize getCompressedImageDataSize(VkFormat format, VkExtent3D extent)
{
try
{
const tcu::CompressedTexFormat tcuFormat = mapVkCompressedFormat(format);
const size_t blockSize = tcu::getBlockSize(tcuFormat);
const tcu::IVec3 blockPixelSize = tcu::getBlockPixelSize(tcuFormat);
const int numBlocksX = deDivRoundUp32((int)extent.width, blockPixelSize.x());
const int numBlocksY = deDivRoundUp32((int)extent.height, blockPixelSize.y());
const int numBlocksZ = deDivRoundUp32((int)extent.depth, blockPixelSize.z());
return blockSize * numBlocksX * numBlocksY * numBlocksZ;
}
catch (...)
{
return 0; // Unsupported compressed format
}
}
VkDeviceSize getYCbCrImageDataSize(VkFormat format, VkExtent3D extent)
{
const PlanarFormatDescription desc = getPlanarFormatDescription(format);
VkDeviceSize totalSize = 0;
DE_ASSERT(extent.depth == 1);
for (uint32_t planeNdx = 0; planeNdx < desc.numPlanes; ++planeNdx)
{
const uint32_t elementSize = desc.planes[planeNdx].elementSizeBytes;
totalSize = (VkDeviceSize)deAlign64((int64_t)totalSize, elementSize);
totalSize += getPlaneSizeInBytes(desc, extent, planeNdx, 0, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
}
return totalSize;
}
VKAPI_ATTR void VKAPI_CALL getImageMemoryRequirements(VkDevice, VkImage imageHandle,
VkMemoryRequirements *requirements)
{
const Image *image = reinterpret_cast<const Image *>(imageHandle.getInternal());
requirements->memoryTypeBits = 1u;
requirements->alignment = 16u;
if (isCompressedFormat(image->getFormat()))
requirements->size = getCompressedImageDataSize(image->getFormat(), image->getExtent());
else if (isYCbCrFormat(image->getFormat()))
requirements->size = getYCbCrImageDataSize(image->getFormat(), image->getExtent());
else
requirements->size = getPackedImageDataSize(image->getFormat(), image->getExtent(), image->getSamples());
}
VKAPI_ATTR VkResult VKAPI_CALL allocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory)
{
#ifndef CTS_USES_VULKANSC
const VkExportMemoryAllocateInfo *const exportInfo =
findStructure<VkExportMemoryAllocateInfo>(pAllocateInfo->pNext);
const VkImportAndroidHardwareBufferInfoANDROID *const importInfo =
findStructure<VkImportAndroidHardwareBufferInfoANDROID>(pAllocateInfo->pNext);
if ((exportInfo &&
(exportInfo->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) != 0) ||
(importInfo && importInfo->buffer.internal))
{
#if defined(USE_ANDROID_O_HARDWARE_BUFFER)
VK_NULL_RETURN((*pMemory = allocateNonDispHandle<ExternalDeviceMemoryAndroid, DeviceMemory, VkDeviceMemory>(
device, pAllocateInfo, pAllocator)));
#else
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
#endif
}
else
{
VK_NULL_RETURN((*pMemory = allocateNonDispHandle<PrivateDeviceMemory, DeviceMemory, VkDeviceMemory>(
device, pAllocateInfo, pAllocator)));
}
#else // CTS_USES_VULKANSC
VK_NULL_RETURN((*pMemory = allocateNonDispHandle<PrivateDeviceMemory, DeviceMemory, VkDeviceMemory>(
device, pAllocateInfo, pAllocator)));
#endif // CTS_USES_VULKANSC
}
VKAPI_ATTR VkResult VKAPI_CALL mapMemory(VkDevice, VkDeviceMemory memHandle, VkDeviceSize offset, VkDeviceSize size,
VkMemoryMapFlags flags, void **ppData)
{
DeviceMemory *const memory = reinterpret_cast<DeviceMemory *>(memHandle.getInternal());
DE_UNREF(size);
DE_UNREF(flags);
*ppData = (uint8_t *)memory->map() + offset;
return VK_SUCCESS;
}
VKAPI_ATTR void VKAPI_CALL unmapMemory(VkDevice device, VkDeviceMemory memHandle)
{
DeviceMemory *const memory = reinterpret_cast<DeviceMemory *>(memHandle.getInternal());
DE_UNREF(device);
memory->unmap();
}
#ifndef CTS_USES_VULKANSC
VKAPI_ATTR VkResult VKAPI_CALL
getMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo,
pt::AndroidHardwareBufferPtr *pBuffer)
{
DE_UNREF(device);
#if defined(USE_ANDROID_O_HARDWARE_BUFFER)
DeviceMemory *const memory = reinterpret_cast<ExternalDeviceMemoryAndroid *>(pInfo->memory.getInternal());
ExternalDeviceMemoryAndroid *const androidMemory = static_cast<ExternalDeviceMemoryAndroid *>(memory);
AHardwareBuffer *hwbuffer = androidMemory->getHwBuffer();
AHardwareBuffer_acquire(hwbuffer);
pBuffer->internal = hwbuffer;
#else
DE_UNREF(pInfo);
DE_UNREF(pBuffer);
#endif
return VK_SUCCESS;
}
#endif // CTS_USES_VULKANSC
VKAPI_ATTR VkResult VKAPI_CALL allocateDescriptorSets(VkDevice, const VkDescriptorSetAllocateInfo *pAllocateInfo,
VkDescriptorSet *pDescriptorSets)
{
DescriptorPool *const poolImpl =
reinterpret_cast<DescriptorPool *>((uintptr_t)pAllocateInfo->descriptorPool.getInternal());
for (uint32_t ndx = 0; ndx < pAllocateInfo->descriptorSetCount; ++ndx)
{
try
{
pDescriptorSets[ndx] = poolImpl->allocate(pAllocateInfo->pSetLayouts[ndx]);
}
catch (const std::bad_alloc &)
{
for (uint32_t freeNdx = 0; freeNdx < ndx; freeNdx++)
delete reinterpret_cast<DescriptorSet *>((uintptr_t)pDescriptorSets[freeNdx].getInternal());
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
catch (VkResult res)
{
for (uint32_t freeNdx = 0; freeNdx < ndx; freeNdx++)
delete reinterpret_cast<DescriptorSet *>((uintptr_t)pDescriptorSets[freeNdx].getInternal());
return res;
}
}
return VK_SUCCESS;
}
VKAPI_ATTR void VKAPI_CALL freeDescriptorSets(VkDevice, VkDescriptorPool descriptorPool, uint32_t count,
const VkDescriptorSet *pDescriptorSets)
{
DescriptorPool *const poolImpl = reinterpret_cast<DescriptorPool *>((uintptr_t)descriptorPool.getInternal());
for (uint32_t ndx = 0; ndx < count; ++ndx)
poolImpl->free(pDescriptorSets[ndx]);
}
VKAPI_ATTR VkResult VKAPI_CALL resetDescriptorPool(VkDevice, VkDescriptorPool descriptorPool,
VkDescriptorPoolResetFlags)
{
DescriptorPool *const poolImpl = reinterpret_cast<DescriptorPool *>((uintptr_t)descriptorPool.getInternal());
poolImpl->reset();
return VK_SUCCESS;
}
VKAPI_ATTR VkResult VKAPI_CALL allocateCommandBuffers(VkDevice device,
const VkCommandBufferAllocateInfo *pAllocateInfo,
VkCommandBuffer *pCommandBuffers)
{
DE_UNREF(device);
if (pAllocateInfo && pCommandBuffers)
{
CommandPool *const poolImpl =
reinterpret_cast<CommandPool *>((uintptr_t)pAllocateInfo->commandPool.getInternal());
for (uint32_t ndx = 0; ndx < pAllocateInfo->commandBufferCount; ++ndx)
pCommandBuffers[ndx] = poolImpl->allocate(pAllocateInfo->level);
}
return VK_SUCCESS;
}
VKAPI_ATTR void VKAPI_CALL freeCommandBuffers(VkDevice device, VkCommandPool commandPool,
uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers)
{
CommandPool *const poolImpl = reinterpret_cast<CommandPool *>((uintptr_t)commandPool.getInternal());
DE_UNREF(device);
for (uint32_t ndx = 0; ndx < commandBufferCount; ++ndx)
poolImpl->free(pCommandBuffers[ndx]);
}
VKAPI_ATTR VkResult VKAPI_CALL createDisplayModeKHR(VkPhysicalDevice, VkDisplayKHR display,
const VkDisplayModeCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkDisplayModeKHR *pMode)
{
DE_UNREF(pAllocator);
VK_NULL_RETURN(
(*pMode = allocateNonDispHandle<DisplayModeKHR, VkDisplayModeKHR>(display, pCreateInfo, pAllocator)));
}
VKAPI_ATTR VkResult VKAPI_CALL createSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
const VkSwapchainCreateInfoKHR *pCreateInfos,
const VkAllocationCallbacks *pAllocator,
VkSwapchainKHR *pSwapchains)
{
for (uint32_t ndx = 0; ndx < swapchainCount; ++ndx)
{
pSwapchains[ndx] =
allocateNonDispHandle<SwapchainKHR, VkSwapchainKHR>(device, pCreateInfos + ndx, pAllocator);
}
return VK_SUCCESS;
}
VKAPI_ATTR void VKAPI_CALL getPhysicalDeviceExternalBufferPropertiesKHR(
VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
VkExternalBufferProperties *pExternalBufferProperties)
{
DE_UNREF(physicalDevice);
DE_UNREF(pExternalBufferInfo);
pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = 0;
pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes = 0;
pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes = 0;
#ifndef CTS_USES_VULKANSC
if (pExternalBufferInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
{
pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures =
VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
}
#endif // CTS_USES_VULKANSC
}
VKAPI_ATTR VkResult VKAPI_CALL getPhysicalDeviceImageFormatProperties2KHR(
VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
VkImageFormatProperties2 *pImageFormatProperties)
{
#ifndef CTS_USES_VULKANSC
const VkPhysicalDeviceExternalImageFormatInfo *const externalInfo =
findStructure<VkPhysicalDeviceExternalImageFormatInfo>(pImageFormatInfo->pNext);
VkExternalImageFormatProperties *const externalProperties =
findStructure<VkExternalImageFormatProperties>(pImageFormatProperties->pNext);
VkResult result;
result = getPhysicalDeviceImageFormatProperties(
physicalDevice, pImageFormatInfo->format, pImageFormatInfo->type, pImageFormatInfo->tiling,
pImageFormatInfo->usage, pImageFormatInfo->flags, &pImageFormatProperties->imageFormatProperties);
if (result != VK_SUCCESS)
return result;
if (externalInfo && externalInfo->handleType != 0)
{
if (externalInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
return VK_ERROR_FORMAT_NOT_SUPPORTED;
if (!(pImageFormatInfo->format == VK_FORMAT_R8G8B8A8_UNORM ||
pImageFormatInfo->format == VK_FORMAT_R8G8B8_UNORM ||
pImageFormatInfo->format == VK_FORMAT_R5G6B5_UNORM_PACK16 ||
pImageFormatInfo->format == VK_FORMAT_R16G16B16A16_SFLOAT ||
pImageFormatInfo->format == VK_FORMAT_A2R10G10B10_UNORM_PACK32))
{
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
if (pImageFormatInfo->type != VK_IMAGE_TYPE_2D)
return VK_ERROR_FORMAT_NOT_SUPPORTED;
if ((pImageFormatInfo->usage & ~(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) != 0)
{
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
if ((pImageFormatInfo->flags & ~(VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
/*| VK_IMAGE_CREATE_PROTECTED_BIT*/
/*| VK_IMAGE_CREATE_EXTENDED_USAGE_BIT*/)) != 0)
{
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
if (externalProperties)
{
externalProperties->externalMemoryProperties.externalMemoryFeatures =
VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
externalProperties->externalMemoryProperties.exportFromImportedHandleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
externalProperties->externalMemoryProperties.compatibleHandleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
}
}
return VK_SUCCESS;
#else // CTS_USES_VULKANSC
return getPhysicalDeviceImageFormatProperties(
physicalDevice, pImageFormatInfo->format, pImageFormatInfo->type, pImageFormatInfo->tiling,
pImageFormatInfo->usage, pImageFormatInfo->flags, &pImageFormatProperties->imageFormatProperties);
#endif // CTS_USES_VULKANSC
}
// \note getInstanceProcAddr is a little bit special:
// vkNullDriverImpl.inl needs it to define s_platformFunctions but
// getInstanceProcAddr() implementation needs other entry points from
// vkNullDriverImpl.inl.
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL getInstanceProcAddr(VkInstance instance, const char *pName);
#include "vkNullDriverImpl.inl"
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL getInstanceProcAddr(VkInstance instance, const char *pName)
{
if (instance)
{
return reinterpret_cast<Instance *>(instance)->getProcAddr(pName);
}
else
{
const std::string name = pName;
if (name == "vkCreateInstance")
return (PFN_vkVoidFunction)createInstance;
else if (name == "vkEnumerateInstanceExtensionProperties")
return (PFN_vkVoidFunction)enumerateInstanceExtensionProperties;
else if (name == "vkEnumerateInstanceLayerProperties")
return (PFN_vkVoidFunction)enumerateInstanceLayerProperties;
else
return (PFN_vkVoidFunction)DE_NULL;
}
}
} // extern "C"
Instance::Instance(const VkInstanceCreateInfo *)
: m_functions(s_instanceFunctions, DE_LENGTH_OF_ARRAY(s_instanceFunctions))
{
}
Device::Device(VkPhysicalDevice, const VkDeviceCreateInfo *)
: m_functions(s_deviceFunctions, DE_LENGTH_OF_ARRAY(s_deviceFunctions))
{
}
class NullDriverLibrary : public Library
{
public:
NullDriverLibrary(void)
: m_library(s_platformFunctions, DE_LENGTH_OF_ARRAY(s_platformFunctions))
, m_driver(m_library)
{
}
const PlatformInterface &getPlatformInterface(void) const
{
return m_driver;
}
const tcu::FunctionLibrary &getFunctionLibrary(void) const
{
return m_library;
}
private:
const tcu::StaticFunctionLibrary m_library;
const PlatformDriver m_driver;
};
} // namespace
Library *createNullDriver(void)
{
return new NullDriverLibrary();
}
} // namespace vk