blob: 1a9e2e6542111e091e051625a8db22069edbe7e0 [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* 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 Vulkan test case base classes
*//*--------------------------------------------------------------------*/
#include "vktTestCase.hpp"
#include "vktCustomInstancesDevices.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkDeviceUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkPlatform.hpp"
#include "vkDebugReportUtil.hpp"
#include "vkDeviceFeatures.hpp"
#include "vkDeviceProperties.hpp"
#include "tcuCommandLine.hpp"
#include "tcuTestLog.hpp"
#include "deSTLUtil.hpp"
#include "deMemory.h"
#include <set>
namespace vkt
{
// Default device utilities
using std::set;
using std::string;
using std::vector;
using namespace vk;
namespace
{
vector<string> filterExtensions(const vector<VkExtensionProperties> &extensions)
{
vector<string> enabledExtensions;
bool khrBufferDeviceAddress = false;
const char *extensionGroups[] = {
"VK_KHR_",
"VK_EXT_",
"VK_KHX_",
"VK_NV_cooperative_matrix",
"VK_EXT_extended_dynamic_state2",
"VK_NV_ray_tracing",
"VK_NV_inherited_viewport_scissor",
"VK_NV_mesh_shader",
"VK_AMD_mixed_attachment_samples",
"VK_AMD_shader_fragment_mask",
"VK_AMD_buffer_marker",
"VK_AMD_shader_explicit_vertex_parameter",
"VK_AMD_shader_image_load_store_lod",
"VK_AMD_shader_trinary_minmax",
"VK_AMD_texture_gather_bias_lod",
"VK_ANDROID_external_memory_android_hardware_buffer",
"VK_VALVE_mutable_descriptor_type",
};
for (size_t extNdx = 0; extNdx < extensions.size(); extNdx++)
{
if (deStringEqual(extensions[extNdx].extensionName, "VK_KHR_buffer_device_address"))
{
khrBufferDeviceAddress = true;
break;
}
}
for (size_t extNdx = 0; extNdx < extensions.size(); extNdx++)
{
const auto &extName = extensions[extNdx].extensionName;
// Skip enabling VK_KHR_pipeline_library unless needed.
if (deStringEqual(extName, "VK_KHR_pipeline_library"))
continue;
// VK_EXT_buffer_device_address is deprecated and must not be enabled if VK_KHR_buffer_device_address is enabled
if (khrBufferDeviceAddress && deStringEqual(extName, "VK_EXT_buffer_device_address"))
continue;
for (int extGroupNdx = 0; extGroupNdx < DE_LENGTH_OF_ARRAY(extensionGroups); extGroupNdx++)
{
if (deStringBeginsWith(extName, extensionGroups[extGroupNdx]))
enabledExtensions.push_back(extName);
}
}
return enabledExtensions;
}
vector<string> addExtensions(const vector<string> &a, const vector<const char *> &b)
{
vector<string> res(a);
for (vector<const char *>::const_iterator bIter = b.begin(); bIter != b.end(); ++bIter)
{
if (!de::contains(res.begin(), res.end(), string(*bIter)))
res.push_back(string(*bIter));
}
return res;
}
vector<string> removeExtensions(const vector<string> &a, const vector<const char *> &b)
{
vector<string> res;
set<string> removeExts(b.begin(), b.end());
for (vector<string>::const_iterator aIter = a.begin(); aIter != a.end(); ++aIter)
{
if (!de::contains(removeExts, *aIter))
res.push_back(*aIter);
}
return res;
}
vector<string> addCoreInstanceExtensions(const vector<string> &extensions, uint32_t instanceVersion)
{
vector<const char *> coreExtensions;
getCoreInstanceExtensions(instanceVersion, coreExtensions);
return addExtensions(extensions, coreExtensions);
}
vector<string> addCoreDeviceExtensions(const vector<string> &extensions, uint32_t instanceVersion)
{
vector<const char *> coreExtensions;
getCoreDeviceExtensions(instanceVersion, coreExtensions);
return addExtensions(extensions, coreExtensions);
}
uint32_t getTargetInstanceVersion(const PlatformInterface &vkp)
{
uint32_t version = pack(ApiVersion(1, 0, 0));
if (vkp.enumerateInstanceVersion(&version) != VK_SUCCESS)
TCU_THROW(InternalError, "Enumerate instance version error");
return version;
}
std::pair<uint32_t, uint32_t> determineDeviceVersions(const PlatformInterface &vkp, uint32_t apiVersion,
const tcu::CommandLine &cmdLine)
{
Move<VkInstance> preinstance = createDefaultInstance(vkp, apiVersion);
InstanceDriver preinterface(vkp, preinstance.get());
const vector<VkPhysicalDevice> devices = enumeratePhysicalDevices(preinterface, preinstance.get());
uint32_t lowestDeviceVersion = 0xFFFFFFFFu;
for (uint32_t deviceNdx = 0u; deviceNdx < devices.size(); ++deviceNdx)
{
const VkPhysicalDeviceProperties props = getPhysicalDeviceProperties(preinterface, devices[deviceNdx]);
if (props.apiVersion < lowestDeviceVersion)
lowestDeviceVersion = props.apiVersion;
}
const vk::VkPhysicalDevice choosenDevice = chooseDevice(preinterface, *preinstance, cmdLine);
const VkPhysicalDeviceProperties props = getPhysicalDeviceProperties(preinterface, choosenDevice);
const uint32_t choosenDeviceVersion = props.apiVersion;
return std::make_pair(choosenDeviceVersion, lowestDeviceVersion);
}
Move<VkInstance> createInstance(const PlatformInterface &vkp, uint32_t apiVersion,
const vector<string> &enabledExtensions, DebugReportRecorder *recorder)
{
const bool isValidationEnabled = (recorder != nullptr);
vector<const char *> enabledLayers;
// \note Extensions in core are not explicitly enabled even though
// they are in the extension list advertised to tests.
vector<const char *> coreExtensions;
getCoreInstanceExtensions(apiVersion, coreExtensions);
const auto nonCoreExtensions = removeExtensions(enabledExtensions, coreExtensions);
if (isValidationEnabled)
{
if (!isDebugReportSupported(vkp))
TCU_THROW(NotSupportedError, "VK_EXT_debug_report is not supported");
enabledLayers = vkt::getValidationLayers(vkp);
if (enabledLayers.empty())
TCU_THROW(NotSupportedError, "No validation layers found");
}
return createDefaultInstance(vkp, apiVersion, vector<string>(begin(enabledLayers), end(enabledLayers)),
nonCoreExtensions, recorder);
}
static uint32_t findQueueFamilyIndexWithCaps(const InstanceInterface &vkInstance, VkPhysicalDevice physicalDevice,
VkQueueFlags requiredCaps)
{
const vector<VkQueueFamilyProperties> queueProps =
getPhysicalDeviceQueueFamilyProperties(vkInstance, physicalDevice);
for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
{
if ((queueProps[queueNdx].queueFlags & requiredCaps) == requiredCaps)
return (uint32_t)queueNdx;
}
TCU_THROW(NotSupportedError, "No matching queue found");
}
Move<VkDevice> createDefaultDevice(const PlatformInterface &vkp, VkInstance instance, const InstanceInterface &vki,
VkPhysicalDevice physicalDevice, const uint32_t apiVersion, uint32_t queueIndex,
uint32_t sparseQueueIndex, const VkPhysicalDeviceFeatures2 &enabledFeatures,
const vector<string> &enabledExtensions, const tcu::CommandLine &cmdLine)
{
VkDeviceQueueCreateInfo queueInfo[2];
VkDeviceCreateInfo deviceInfo;
vector<const char *> enabledLayers;
vector<const char *> extensionPtrs;
const float queuePriority = 1.0f;
const uint32_t numQueues = (enabledFeatures.features.sparseBinding && (queueIndex != sparseQueueIndex)) ? 2 : 1;
deMemset(&queueInfo, 0, sizeof(queueInfo));
deMemset(&deviceInfo, 0, sizeof(deviceInfo));
if (cmdLine.isValidationEnabled())
{
enabledLayers = vkt::getValidationLayers(vki, physicalDevice);
if (enabledLayers.empty())
TCU_THROW(NotSupportedError, "No validation layers found");
}
// \note Extensions in core are not explicitly enabled even though
// they are in the extension list advertised to tests.
vector<const char *> coreExtensions;
getCoreDeviceExtensions(apiVersion, coreExtensions);
vector<string> nonCoreExtensions(removeExtensions(enabledExtensions, coreExtensions));
extensionPtrs.resize(nonCoreExtensions.size());
for (size_t ndx = 0; ndx < nonCoreExtensions.size(); ++ndx)
extensionPtrs[ndx] = nonCoreExtensions[ndx].c_str();
queueInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueInfo[0].pNext = DE_NULL;
queueInfo[0].flags = (VkDeviceQueueCreateFlags)0u;
queueInfo[0].queueFamilyIndex = queueIndex;
queueInfo[0].queueCount = 1u;
queueInfo[0].pQueuePriorities = &queuePriority;
if (numQueues > 1)
{
queueInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueInfo[1].pNext = DE_NULL;
queueInfo[1].flags = (VkDeviceQueueCreateFlags)0u;
queueInfo[1].queueFamilyIndex = sparseQueueIndex;
queueInfo[1].queueCount = 1u;
queueInfo[1].pQueuePriorities = &queuePriority;
}
// VK_KHR_get_physical_device_properties2 is used if enabledFeatures.pNext != 0
deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceInfo.pNext = enabledFeatures.pNext ? &enabledFeatures : DE_NULL;
deviceInfo.queueCreateInfoCount = numQueues;
deviceInfo.pQueueCreateInfos = queueInfo;
deviceInfo.enabledExtensionCount = (uint32_t)extensionPtrs.size();
deviceInfo.ppEnabledExtensionNames = (extensionPtrs.empty() ? DE_NULL : &extensionPtrs[0]);
deviceInfo.enabledLayerCount = (uint32_t)enabledLayers.size();
deviceInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
deviceInfo.pEnabledFeatures = enabledFeatures.pNext ? DE_NULL : &enabledFeatures.features;
return createDevice(vkp, instance, vki, physicalDevice, &deviceInfo);
}
} // namespace
class DefaultDevice
{
public:
DefaultDevice(const PlatformInterface &vkPlatform, const tcu::CommandLine &cmdLine);
~DefaultDevice(void);
VkInstance getInstance(void) const
{
return *m_instance;
}
const InstanceInterface &getInstanceInterface(void) const
{
return m_instanceInterface;
}
uint32_t getMaximumFrameworkVulkanVersion(void) const
{
return m_maximumFrameworkVulkanVersion;
}
uint32_t getAvailableInstanceVersion(void) const
{
return m_availableInstanceVersion;
}
uint32_t getUsedInstanceVersion(void) const
{
return m_usedInstanceVersion;
}
const vector<string> &getInstanceExtensions(void) const
{
return m_instanceExtensions;
}
VkPhysicalDevice getPhysicalDevice(void) const
{
return m_physicalDevice;
}
uint32_t getDeviceVersion(void) const
{
return m_deviceVersion;
}
bool isDeviceFeatureInitialized(VkStructureType sType) const
{
return m_deviceFeatures.isDeviceFeatureInitialized(sType);
}
const VkPhysicalDeviceFeatures &getDeviceFeatures(void) const
{
return m_deviceFeatures.getCoreFeatures2().features;
}
const VkPhysicalDeviceFeatures2 &getDeviceFeatures2(void) const
{
return m_deviceFeatures.getCoreFeatures2();
}
const VkPhysicalDeviceVulkan11Features &getVulkan11Features(void) const
{
return m_deviceFeatures.getVulkan11Features();
}
const VkPhysicalDeviceVulkan12Features &getVulkan12Features(void) const
{
return m_deviceFeatures.getVulkan12Features();
}
#include "vkDeviceFeaturesForDefaultDeviceDefs.inl"
bool isDevicePropertyInitialized(VkStructureType sType) const
{
return m_deviceProperties.isDevicePropertyInitialized(sType);
}
const VkPhysicalDeviceProperties &getDeviceProperties(void) const
{
return m_deviceProperties.getCoreProperties2().properties;
}
const VkPhysicalDeviceProperties2 &getDeviceProperties2(void) const
{
return m_deviceProperties.getCoreProperties2();
}
const VkPhysicalDeviceVulkan11Properties &getDeviceVulkan11Properties(void) const
{
return m_deviceProperties.getVulkan11Properties();
}
const VkPhysicalDeviceVulkan12Properties &getDeviceVulkan12Properties(void) const
{
return m_deviceProperties.getVulkan12Properties();
}
#include "vkDevicePropertiesForDefaultDeviceDefs.inl"
VkDevice getDevice(void) const
{
return *m_device;
}
const DeviceInterface &getDeviceInterface(void) const
{
return m_deviceInterface;
}
const vector<string> &getDeviceExtensions(void) const
{
return m_deviceExtensions;
}
uint32_t getUsedApiVersion(void) const
{
return m_usedApiVersion;
}
uint32_t getUniversalQueueFamilyIndex(void) const
{
return m_universalQueueFamilyIndex;
}
VkQueue getUniversalQueue(void) const;
uint32_t getSparseQueueFamilyIndex(void) const
{
return m_sparseQueueFamilyIndex;
}
VkQueue getSparseQueue(void) const;
bool hasDebugReportRecorder(void) const
{
return m_debugReportRecorder.get() != nullptr;
}
vk::DebugReportRecorder &getDebugReportRecorder(void) const
{
return *m_debugReportRecorder.get();
}
private:
using DebugReportRecorderPtr = de::UniquePtr<vk::DebugReportRecorder>;
using DebugReportCallbackPtr = vk::Move<VkDebugReportCallbackEXT>;
const uint32_t m_maximumFrameworkVulkanVersion;
const uint32_t m_availableInstanceVersion;
const uint32_t m_usedInstanceVersion;
const std::pair<uint32_t, uint32_t> m_deviceVersions;
const uint32_t m_usedApiVersion;
const DebugReportRecorderPtr m_debugReportRecorder;
const vector<string> m_instanceExtensions;
const Unique<VkInstance> m_instance;
const InstanceDriver m_instanceInterface;
const DebugReportCallbackPtr m_debugReportCallback;
const VkPhysicalDevice m_physicalDevice;
const uint32_t m_deviceVersion;
const vector<string> m_deviceExtensions;
const DeviceFeatures m_deviceFeatures;
const uint32_t m_universalQueueFamilyIndex;
const uint32_t m_sparseQueueFamilyIndex;
const DeviceProperties m_deviceProperties;
const Unique<VkDevice> m_device;
const DeviceDriver m_deviceInterface;
};
namespace
{
uint32_t sanitizeApiVersion(uint32_t v)
{
return VK_MAKE_VERSION(VK_API_VERSION_MAJOR(v), VK_API_VERSION_MINOR(v), 0);
}
de::MovePtr<vk::DebugReportRecorder> createDebugReportRecorder(const vk::PlatformInterface &vkp,
bool printValidationErrors)
{
if (isDebugReportSupported(vkp))
return de::MovePtr<vk::DebugReportRecorder>(new vk::DebugReportRecorder(printValidationErrors));
else
TCU_THROW(NotSupportedError, "VK_EXT_debug_report is not supported");
}
} // namespace
DefaultDevice::DefaultDevice(const PlatformInterface &vkPlatform, const tcu::CommandLine &cmdLine)
: m_maximumFrameworkVulkanVersion(VK_API_MAX_FRAMEWORK_VERSION)
, m_availableInstanceVersion(getTargetInstanceVersion(vkPlatform))
, m_usedInstanceVersion(sanitizeApiVersion(deMinu32(m_availableInstanceVersion, m_maximumFrameworkVulkanVersion)))
, m_deviceVersions(determineDeviceVersions(vkPlatform, m_usedInstanceVersion, cmdLine))
, m_usedApiVersion(sanitizeApiVersion(deMinu32(m_usedInstanceVersion, m_deviceVersions.first)))
, m_debugReportRecorder(cmdLine.isValidationEnabled() ?
createDebugReportRecorder(vkPlatform, cmdLine.printValidationErrors()) :
de::MovePtr<vk::DebugReportRecorder>())
, m_instanceExtensions(addCoreInstanceExtensions(
filterExtensions(enumerateInstanceExtensionProperties(vkPlatform, DE_NULL)), m_usedApiVersion))
, m_instance(createInstance(vkPlatform, m_usedApiVersion, m_instanceExtensions, m_debugReportRecorder.get()))
, m_instanceInterface(vkPlatform, *m_instance)
, m_debugReportCallback(cmdLine.isValidationEnabled() ?
m_debugReportRecorder->createCallback(m_instanceInterface, m_instance.get()) :
DebugReportCallbackPtr())
, m_physicalDevice(chooseDevice(m_instanceInterface, *m_instance, cmdLine))
, m_deviceVersion(getPhysicalDeviceProperties(m_instanceInterface, m_physicalDevice).apiVersion)
, m_deviceExtensions(addCoreDeviceExtensions(
filterExtensions(enumerateDeviceExtensionProperties(m_instanceInterface, m_physicalDevice, DE_NULL)),
m_usedApiVersion))
, m_deviceFeatures(m_instanceInterface, m_usedApiVersion, m_physicalDevice, m_instanceExtensions,
m_deviceExtensions)
, m_universalQueueFamilyIndex(findQueueFamilyIndexWithCaps(m_instanceInterface, m_physicalDevice,
VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT))
, m_sparseQueueFamilyIndex(
m_deviceFeatures.getCoreFeatures2().features.sparseBinding ?
findQueueFamilyIndexWithCaps(m_instanceInterface, m_physicalDevice, VK_QUEUE_SPARSE_BINDING_BIT) :
0)
, m_deviceProperties(m_instanceInterface, m_usedApiVersion, m_physicalDevice, m_instanceExtensions,
m_deviceExtensions)
, m_device(createDefaultDevice(vkPlatform, *m_instance, m_instanceInterface, m_physicalDevice, m_usedApiVersion,
m_universalQueueFamilyIndex, m_sparseQueueFamilyIndex,
m_deviceFeatures.getCoreFeatures2(), m_deviceExtensions, cmdLine))
, m_deviceInterface(vkPlatform, *m_instance, *m_device)
{
DE_ASSERT(m_deviceVersions.first == m_deviceVersion);
}
DefaultDevice::~DefaultDevice(void)
{
}
VkQueue DefaultDevice::getUniversalQueue(void) const
{
return getDeviceQueue(m_deviceInterface, *m_device, m_universalQueueFamilyIndex, 0);
}
VkQueue DefaultDevice::getSparseQueue(void) const
{
if (!m_deviceFeatures.getCoreFeatures2().features.sparseBinding)
TCU_THROW(NotSupportedError, "Sparse binding not supported.");
return getDeviceQueue(m_deviceInterface, *m_device, m_sparseQueueFamilyIndex, 0);
}
namespace
{
// Allocator utilities
vk::Allocator *createAllocator(DefaultDevice *device)
{
const VkPhysicalDeviceMemoryProperties memoryProperties =
vk::getPhysicalDeviceMemoryProperties(device->getInstanceInterface(), device->getPhysicalDevice());
// \todo [2015-07-24 jarkko] support allocator selection/configuration from command line (or compile time)
return new SimpleAllocator(device->getDeviceInterface(), device->getDevice(), memoryProperties);
}
} // namespace
// Context
Context::Context(tcu::TestContext &testCtx, const vk::PlatformInterface &platformInterface,
vk::BinaryCollection &progCollection)
: m_testCtx(testCtx)
, m_platformInterface(platformInterface)
, m_progCollection(progCollection)
, m_device(new DefaultDevice(m_platformInterface, testCtx.getCommandLine()))
, m_allocator(createAllocator(m_device.get()))
, m_resultSetOnValidation(false)
{
}
Context::~Context(void)
{
}
uint32_t Context::getMaximumFrameworkVulkanVersion(void) const
{
return m_device->getMaximumFrameworkVulkanVersion();
}
uint32_t Context::getAvailableInstanceVersion(void) const
{
return m_device->getAvailableInstanceVersion();
}
const vector<string> &Context::getInstanceExtensions(void) const
{
return m_device->getInstanceExtensions();
}
vk::VkInstance Context::getInstance(void) const
{
return m_device->getInstance();
}
const vk::InstanceInterface &Context::getInstanceInterface(void) const
{
return m_device->getInstanceInterface();
}
vk::VkPhysicalDevice Context::getPhysicalDevice(void) const
{
return m_device->getPhysicalDevice();
}
uint32_t Context::getDeviceVersion(void) const
{
return m_device->getDeviceVersion();
}
const vk::VkPhysicalDeviceFeatures &Context::getDeviceFeatures(void) const
{
return m_device->getDeviceFeatures();
}
const vk::VkPhysicalDeviceFeatures2 &Context::getDeviceFeatures2(void) const
{
return m_device->getDeviceFeatures2();
}
const vk::VkPhysicalDeviceVulkan11Features &Context::getDeviceVulkan11Features(void) const
{
return m_device->getVulkan11Features();
}
const vk::VkPhysicalDeviceVulkan12Features &Context::getDeviceVulkan12Features(void) const
{
return m_device->getVulkan12Features();
}
bool Context::isDeviceFunctionalitySupported(const std::string &extension) const
{
// check if extension was promoted to core
uint32_t apiVersion = getUsedApiVersion();
if (isCoreDeviceExtension(apiVersion, extension))
{
if (apiVersion < VK_MAKE_VERSION(1, 2, 0))
{
// Check feature bits in extension-specific structures.
if (extension == "VK_KHR_multiview")
return !!m_device->getMultiviewFeatures().multiview;
if (extension == "VK_KHR_variable_pointers")
return !!m_device->getVariablePointersFeatures().variablePointersStorageBuffer;
if (extension == "VK_KHR_sampler_ycbcr_conversion")
return !!m_device->getSamplerYcbcrConversionFeatures().samplerYcbcrConversion;
if (extension == "VK_KHR_shader_draw_parameters")
return !!m_device->getShaderDrawParametersFeatures().shaderDrawParameters;
}
else
{
// Check feature bits using the new Vulkan 1.2 structures.
const auto &vk11Features = m_device->getVulkan11Features();
if (extension == "VK_KHR_multiview")
return !!vk11Features.multiview;
if (extension == "VK_KHR_variable_pointers")
return !!vk11Features.variablePointersStorageBuffer;
if (extension == "VK_KHR_sampler_ycbcr_conversion")
return !!vk11Features.samplerYcbcrConversion;
if (extension == "VK_KHR_shader_draw_parameters")
return !!vk11Features.shaderDrawParameters;
const auto &vk12Features = m_device->getVulkan12Features();
if (extension == "VK_KHR_timeline_semaphore")
return !!vk12Features.timelineSemaphore;
if (extension == "VK_KHR_buffer_device_address")
return !!vk12Features.bufferDeviceAddress;
if (extension == "VK_EXT_descriptor_indexing")
return !!vk12Features.descriptorIndexing;
if (extension == "VK_KHR_draw_indirect_count")
return !!vk12Features.drawIndirectCount;
if (extension == "VK_KHR_sampler_mirror_clamp_to_edge")
return !!vk12Features.samplerMirrorClampToEdge;
if (extension == "VK_EXT_sampler_filter_minmax")
return !!vk12Features.samplerFilterMinmax;
if (extension == "VK_EXT_shader_viewport_index_layer")
return !!vk12Features.shaderOutputViewportIndex && !!vk12Features.shaderOutputLayer;
}
// No feature flags to check.
return true;
}
// check if extension is on the list of extensions for current device
const auto &extensions = getDeviceExtensions();
if (de::contains(extensions.begin(), extensions.end(), extension))
{
if (extension == "VK_KHR_timeline_semaphore")
return !!getTimelineSemaphoreFeatures().timelineSemaphore;
if (extension == "VK_KHR_synchronization2")
return !!getSynchronization2Features().synchronization2;
if (extension == "VK_EXT_extended_dynamic_state")
return !!getExtendedDynamicStateFeaturesEXT().extendedDynamicState;
if (extension == "VK_EXT_shader_demote_to_helper_invocation")
return !!getShaderDemoteToHelperInvocationFeaturesEXT().shaderDemoteToHelperInvocation;
if (extension == "VK_KHR_workgroup_memory_explicit_layout")
return !!getWorkgroupMemoryExplicitLayoutFeatures().workgroupMemoryExplicitLayout;
return true;
}
return false;
}
bool Context::isInstanceFunctionalitySupported(const std::string &extension) const
{
// NOTE: current implementation uses isInstanceExtensionSupported but
// this will change when some instance extensions will be promoted to the
// core; don't use isInstanceExtensionSupported directly, use this method instead
return isInstanceExtensionSupported(getUsedApiVersion(), getInstanceExtensions(), extension);
}
#include "vkDeviceFeaturesForContextDefs.inl"
const vk::VkPhysicalDeviceProperties &Context::getDeviceProperties(void) const
{
return m_device->getDeviceProperties();
}
const vk::VkPhysicalDeviceProperties2 &Context::getDeviceProperties2(void) const
{
return m_device->getDeviceProperties2();
}
const vk::VkPhysicalDeviceVulkan11Properties &Context::getDeviceVulkan11Properties(void) const
{
return m_device->getDeviceVulkan11Properties();
}
const vk::VkPhysicalDeviceVulkan12Properties &Context::getDeviceVulkan12Properties(void) const
{
return m_device->getDeviceVulkan12Properties();
}
#include "vkDevicePropertiesForContextDefs.inl"
const vector<string> &Context::getDeviceExtensions(void) const
{
return m_device->getDeviceExtensions();
}
vk::VkDevice Context::getDevice(void) const
{
return m_device->getDevice();
}
const vk::DeviceInterface &Context::getDeviceInterface(void) const
{
return m_device->getDeviceInterface();
}
uint32_t Context::getUniversalQueueFamilyIndex(void) const
{
return m_device->getUniversalQueueFamilyIndex();
}
vk::VkQueue Context::getUniversalQueue(void) const
{
return m_device->getUniversalQueue();
}
uint32_t Context::getSparseQueueFamilyIndex(void) const
{
return m_device->getSparseQueueFamilyIndex();
}
vk::VkQueue Context::getSparseQueue(void) const
{
return m_device->getSparseQueue();
}
vk::Allocator &Context::getDefaultAllocator(void) const
{
return *m_allocator;
}
uint32_t Context::getUsedApiVersion(void) const
{
return m_device->getUsedApiVersion();
}
bool Context::contextSupports(const uint32_t majorNum, const uint32_t minorNum, const uint32_t patchNum) const
{
return m_device->getUsedApiVersion() >= VK_MAKE_VERSION(majorNum, minorNum, patchNum);
}
bool Context::contextSupports(const ApiVersion version) const
{
return m_device->getUsedApiVersion() >= pack(version);
}
bool Context::contextSupports(const uint32_t requiredApiVersionBits) const
{
return m_device->getUsedApiVersion() >= requiredApiVersionBits;
}
bool Context::isDeviceFeatureInitialized(vk::VkStructureType sType) const
{
return m_device->isDeviceFeatureInitialized(sType);
}
bool Context::isDevicePropertyInitialized(vk::VkStructureType sType) const
{
return m_device->isDevicePropertyInitialized(sType);
}
bool Context::requireDeviceFunctionality(const std::string &required) const
{
if (!isDeviceFunctionalitySupported(required))
TCU_THROW(NotSupportedError, required + " is not supported");
return true;
}
bool Context::requireInstanceFunctionality(const std::string &required) const
{
if (!isInstanceFunctionalitySupported(required))
TCU_THROW(NotSupportedError, required + " is not supported");
return true;
}
struct DeviceCoreFeaturesTable
{
const char *featureName;
const uint32_t featureArrayIndex;
const uint32_t featureArrayOffset;
};
#define DEVICE_CORE_FEATURE_OFFSET(FEATURE_FIELD_NAME) offsetof(VkPhysicalDeviceFeatures, FEATURE_FIELD_NAME)
#define DEVICE_CORE_FEATURE_ENTRY(BITNAME, FIELDNAME) \
{ \
#FIELDNAME, BITNAME, DEVICE_CORE_FEATURE_OFFSET(FIELDNAME) \
}
const DeviceCoreFeaturesTable deviceCoreFeaturesTable[] = {
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_ROBUST_BUFFER_ACCESS, robustBufferAccess),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_FULL_DRAW_INDEX_UINT32, fullDrawIndexUint32),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY, imageCubeArray),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_INDEPENDENT_BLEND, independentBlend),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_GEOMETRY_SHADER, geometryShader),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_TESSELLATION_SHADER, tessellationShader),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING, sampleRateShading),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_DUAL_SRC_BLEND, dualSrcBlend),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_LOGIC_OP, logicOp),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_MULTI_DRAW_INDIRECT, multiDrawIndirect),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_DRAW_INDIRECT_FIRST_INSTANCE, drawIndirectFirstInstance),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_DEPTH_CLAMP, depthClamp),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_DEPTH_BIAS_CLAMP, depthBiasClamp),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_FILL_MODE_NON_SOLID, fillModeNonSolid),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_DEPTH_BOUNDS, depthBounds),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_WIDE_LINES, wideLines),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_LARGE_POINTS, largePoints),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_ALPHA_TO_ONE, alphaToOne),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_MULTI_VIEWPORT, multiViewport),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SAMPLER_ANISOTROPY, samplerAnisotropy),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_TEXTURE_COMPRESSION_ETC2, textureCompressionETC2),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_TEXTURE_COMPRESSION_ASTC_LDR, textureCompressionASTC_LDR),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_TEXTURE_COMPRESSION_BC, textureCompressionBC),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_OCCLUSION_QUERY_PRECISE, occlusionQueryPrecise),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_PIPELINE_STATISTICS_QUERY, pipelineStatisticsQuery),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS, vertexPipelineStoresAndAtomics),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS, fragmentStoresAndAtomics),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE,
shaderTessellationAndGeometryPointSize),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_IMAGE_GATHER_EXTENDED, shaderImageGatherExtended),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_EXTENDED_FORMATS,
shaderStorageImageExtendedFormats),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_MULTISAMPLE, shaderStorageImageMultisample),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_READ_WITHOUT_FORMAT,
shaderStorageImageReadWithoutFormat),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_WRITE_WITHOUT_FORMAT,
shaderStorageImageWriteWithoutFormat),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING,
shaderUniformBufferArrayDynamicIndexing),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING,
shaderSampledImageArrayDynamicIndexing),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING,
shaderStorageBufferArrayDynamicIndexing),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_STORAGE_IMAGE_ARRAY_DYNAMIC_INDEXING,
shaderStorageImageArrayDynamicIndexing),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_CLIP_DISTANCE, shaderClipDistance),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_CULL_DISTANCE, shaderCullDistance),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_FLOAT64, shaderFloat64),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_INT64, shaderInt64),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_INT16, shaderInt16),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_RESOURCE_RESIDENCY, shaderResourceResidency),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SHADER_RESOURCE_MIN_LOD, shaderResourceMinLod),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SPARSE_BINDING, sparseBinding),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SPARSE_RESIDENCY_BUFFER, sparseResidencyBuffer),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SPARSE_RESIDENCY_IMAGE2D, sparseResidencyImage2D),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SPARSE_RESIDENCY_IMAGE3D, sparseResidencyImage3D),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SPARSE_RESIDENCY2_SAMPLES, sparseResidency2Samples),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SPARSE_RESIDENCY4_SAMPLES, sparseResidency4Samples),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SPARSE_RESIDENCY8_SAMPLES, sparseResidency8Samples),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SPARSE_RESIDENCY16_SAMPLES, sparseResidency16Samples),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_SPARSE_RESIDENCY_ALIASED, sparseResidencyAliased),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_VARIABLE_MULTISAMPLE_RATE, variableMultisampleRate),
DEVICE_CORE_FEATURE_ENTRY(DEVICE_CORE_FEATURE_INHERITED_QUERIES, inheritedQueries),
};
bool Context::requireDeviceCoreFeature(const DeviceCoreFeature requiredFeature)
{
const vk::VkPhysicalDeviceFeatures &featuresAvailable = getDeviceFeatures();
const vk::VkBool32 *featuresAvailableArray = (vk::VkBool32 *)(&featuresAvailable);
const uint32_t requiredFeatureIndex = static_cast<uint32_t>(requiredFeature);
DE_ASSERT(requiredFeatureIndex * sizeof(vk::VkBool32) < sizeof(featuresAvailable));
DE_ASSERT(deviceCoreFeaturesTable[requiredFeatureIndex].featureArrayIndex * sizeof(vk::VkBool32) ==
deviceCoreFeaturesTable[requiredFeatureIndex].featureArrayOffset);
if (featuresAvailableArray[requiredFeatureIndex] == false)
TCU_THROW(NotSupportedError, "Requested core feature is not supported: " +
std::string(deviceCoreFeaturesTable[requiredFeatureIndex].featureName));
return true;
}
static bool isExtendedStorageFormat(VkFormat format)
{
switch (format)
{
case VK_FORMAT_R8G8B8A8_UNORM:
case VK_FORMAT_R8G8B8A8_SNORM:
case VK_FORMAT_R8G8B8A8_UINT:
case VK_FORMAT_R8G8B8A8_SINT:
case VK_FORMAT_R32_UINT:
case VK_FORMAT_R32_SINT:
case VK_FORMAT_R32_SFLOAT:
case VK_FORMAT_R32G32_UINT:
case VK_FORMAT_R32G32_SINT:
case VK_FORMAT_R32G32_SFLOAT:
case VK_FORMAT_R32G32B32A32_UINT:
case VK_FORMAT_R32G32B32A32_SINT:
case VK_FORMAT_R32G32B32A32_SFLOAT:
case VK_FORMAT_R16G16B16A16_UINT:
case VK_FORMAT_R16G16B16A16_SINT:
case VK_FORMAT_R16G16B16A16_SFLOAT:
case VK_FORMAT_R16G16_SFLOAT:
case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
case VK_FORMAT_R16_SFLOAT:
case VK_FORMAT_R16G16B16A16_UNORM:
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
case VK_FORMAT_R16G16_UNORM:
case VK_FORMAT_R8G8_UNORM:
case VK_FORMAT_R16_UNORM:
case VK_FORMAT_R8_UNORM:
case VK_FORMAT_R16G16B16A16_SNORM:
case VK_FORMAT_R16G16_SNORM:
case VK_FORMAT_R8G8_SNORM:
case VK_FORMAT_R16_SNORM:
case VK_FORMAT_R8_SNORM:
case VK_FORMAT_R16G16_SINT:
case VK_FORMAT_R8G8_SINT:
case VK_FORMAT_R16_SINT:
case VK_FORMAT_R8_SINT:
case VK_FORMAT_A2B10G10R10_UINT_PACK32:
case VK_FORMAT_R16G16_UINT:
case VK_FORMAT_R8G8_UINT:
case VK_FORMAT_R16_UINT:
case VK_FORMAT_R8_UINT:
return true;
default:
return false;
}
}
static bool isDepthFormat(VkFormat format)
{
switch (format)
{
case VK_FORMAT_D16_UNORM:
case VK_FORMAT_X8_D24_UNORM_PACK32:
case VK_FORMAT_D32_SFLOAT:
case VK_FORMAT_D16_UNORM_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
return true;
default:
return false;
}
}
vk::VkFormatProperties3KHR Context::getRequiredFormatProperties(const vk::VkFormat &format) const
{
vk::VkFormatProperties3KHR p;
p.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR;
p.pNext = DE_NULL;
vk::VkFormatProperties properties;
getInstanceInterface().getPhysicalDeviceFormatProperties(getPhysicalDevice(), format, &properties);
p.linearTilingFeatures = properties.linearTilingFeatures;
p.optimalTilingFeatures = properties.optimalTilingFeatures;
p.bufferFeatures = properties.bufferFeatures;
const vk::VkPhysicalDeviceFeatures &featuresAvailable = getDeviceFeatures();
if (isExtendedStorageFormat(format) && featuresAvailable.shaderStorageImageReadWithoutFormat)
{
if (p.linearTilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR)
p.linearTilingFeatures |= VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR;
if (p.optimalTilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR)
p.optimalTilingFeatures |= VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR;
}
if (isExtendedStorageFormat(format) && featuresAvailable.shaderStorageImageWriteWithoutFormat)
{
if (p.linearTilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR)
p.linearTilingFeatures |= VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR;
if (p.optimalTilingFeatures & VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR)
p.optimalTilingFeatures |= VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR;
}
if (isDepthFormat(format) && (p.linearTilingFeatures & (VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT_KHR)))
p.linearTilingFeatures |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT_KHR;
if (isDepthFormat(format) && (p.optimalTilingFeatures & (VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT_KHR)))
p.optimalTilingFeatures |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT_KHR;
return p;
}
vk::VkFormatProperties3KHR Context::getFormatProperties(const vk::VkFormat &format) const
{
if (isDeviceFunctionalitySupported(VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME)) // "VK_KHR_format_feature_flags2"
{
vk::VkFormatProperties3KHR p;
p.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR;
p.pNext = DE_NULL;
vk::VkFormatProperties2 properties;
properties.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
properties.pNext = &p;
getInstanceInterface().getPhysicalDeviceFormatProperties2(getPhysicalDevice(), format, &properties);
return p;
}
else
return Context::getRequiredFormatProperties(format);
}
void *Context::getInstanceProcAddr()
{
return (void *)m_platformInterface.getGetInstanceProcAddr();
}
bool Context::isBufferDeviceAddressSupported(void) const
{
return isDeviceFunctionalitySupported("VK_KHR_buffer_device_address") ||
isDeviceFunctionalitySupported("VK_EXT_buffer_device_address");
}
bool Context::hasDebugReportRecorder() const
{
return m_device->hasDebugReportRecorder();
}
vk::DebugReportRecorder &Context::getDebugReportRecorder() const
{
return m_device->getDebugReportRecorder();
}
// TestCase
void TestCase::initPrograms(SourceCollections &) const
{
}
void TestCase::checkSupport(Context &) const
{
}
void TestCase::delayedInit(void)
{
}
void collectAndReportDebugMessages(vk::DebugReportRecorder &debugReportRecorder, Context &context)
{
using DebugMessages = vk::DebugReportRecorder::MessageList;
const DebugMessages &messages = debugReportRecorder.getMessages();
tcu::TestLog &log = context.getTestContext().getLog();
if (messages.size() > 0)
{
const tcu::ScopedLogSection section(log, "DebugMessages", "Debug Messages");
int numErrors = 0;
for (const auto &msg : messages)
{
if (msg.shouldBeLogged())
log << tcu::TestLog::Message << msg << tcu::TestLog::EndMessage;
if (msg.isError())
numErrors += 1;
}
debugReportRecorder.clearMessages();
if (numErrors > 0)
{
string errorMsg = de::toString(numErrors) + " API usage errors found";
context.resultSetOnValidation(true);
context.getTestContext().setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, errorMsg.c_str());
}
}
}
} // namespace vkt