blob: 1fccb37edfc95fd168873a3417a9cc9d6e8316d0 [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2017 Khronos Group
*
* 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 API Maintenance3 Check test - checks structs and function from VK_KHR_maintenance3
*//*--------------------------------------------------------------------*/
#include "tcuTestLog.hpp"
#include "vkQueryUtil.hpp"
#include "vktApiMaintenance3Check.hpp"
#include "vktTestCase.hpp"
#include <sstream>
#include <limits>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
using namespace vk;
namespace vkt
{
namespace api
{
namespace
{
using ::std::string;
using ::std::vector;
using ::std::map;
using ::std::set;
using ::std::ostringstream;
using ::std::make_pair;
typedef vk::VkPhysicalDeviceProperties DevProp1;
typedef vk::VkPhysicalDeviceProperties2 DevProp2;
typedef vk::VkPhysicalDeviceMaintenance3Properties MaintDevProp3;
typedef vk::VkPhysicalDeviceFeatures2 DevFeat2;
typedef vk::VkPhysicalDeviceInlineUniformBlockFeaturesEXT DevIubFeat;
typedef vk::VkPhysicalDeviceInlineUniformBlockPropertiesEXT DevIubProp;
// These variables are equal to minimal values for maxMemoryAllocationSize and maxPerSetDescriptors
constexpr deUint32 maxMemoryAllocationSize = 1073741824u;
constexpr deUint32 maxDescriptorsInSet = 1024u;
constexpr deUint32 maxReasonableInlineUniformBlocks = 64u;
using TypeSet = set<vk::VkDescriptorType>;
// Structure representing an implementation limit, like maxPerStageDescriptorSamplers. It has a maximum value
// obtained at runtime and a remaining number of descriptors, which starts with the same count and decreases
// as we assign descriptor counts to the different types. A limit is affected by (or itself affects) one or more
// descriptor types. Note a type may be involved in several limits, and a limit may affect several types.
struct Limit
{
Limit(const string& name_, deUint32 maxValue_, const TypeSet& affectedTypes_)
: name(name_), maxValue(maxValue_), remaining(maxValue_), affectedTypes(affectedTypes_)
{}
const string name;
const deUint32 maxValue;
deUint32 remaining;
const TypeSet affectedTypes;
};
// Structure representing how many descriptors have been assigned to the given type. The type is "alive" during
// descriptor count assignment if more descriptors can be added to the type without hitting any limit affected
// by the type. Once at least one of the limits is reached, no more descriptors can be assigned to the type and
// the type is no longer considered "alive".
struct TypeState
{
TypeState(vk::VkDescriptorType type_)
: type(type_), alive(true), count(0u)
{}
const vk::VkDescriptorType type;
bool alive;
deUint32 count;
};
using TypeCounts = map<vk::VkDescriptorType, TypeState>;
using LimitsVector = vector<Limit>;
// Get the subset of alive types from the given map.
TypeSet getAliveTypes (const TypeCounts& typeCounts)
{
TypeSet aliveTypes;
for (const auto& typeCount : typeCounts)
{
if (typeCount.second.alive)
aliveTypes.insert(typeCount.first);
}
return aliveTypes;
}
// Get the subset of alive types for a specific limit, among the set of types affected by the limit.
TypeSet getAliveTypesForLimit (const Limit& limit, const TypeSet& aliveTypes)
{
TypeSet subset;
for (const auto& type : limit.affectedTypes)
{
if (aliveTypes.find(type) != aliveTypes.end())
subset.insert(type);
}
return subset;
}
// Distribute descriptor counts as evenly as possible among the given set of types, taking into account the
// given limits.
void distributeCounts (LimitsVector& limits, TypeCounts& typeCounts)
{
using IncrementsMap = map<vk::VkDescriptorType, deUint32>;
TypeSet aliveTypes;
while ((aliveTypes = getAliveTypes(typeCounts)).size() > 0u)
{
// Calculate the maximum increment per alive descriptor type. This involves iterating over the limits and
// finding out how many more descriptors can be distributed among the affected types that are still alive
// for the limit. For each type, remember the lowest possible increment.
IncrementsMap increments;
for (const auto& type : aliveTypes)
increments[type] = std::numeric_limits<deUint32>::max();
TypeSet aliveTypesForLimit;
for (const auto& limit : limits)
{
if (limit.remaining == 0u)
continue;
aliveTypesForLimit = getAliveTypesForLimit(limit, aliveTypes);
if (aliveTypesForLimit.empty())
continue;
// Distribute remaining count evenly among alive types.
deUint32 maxIncrement = limit.remaining / static_cast<deUint32>(aliveTypesForLimit.size());
if (maxIncrement == 0u)
{
// More types than remaining descriptors. Assign 1 to the first affected types and 0 to the rest.
deUint32 remaining = limit.remaining;
for (const auto& type : aliveTypesForLimit)
{
if (remaining > 0u && increments[type] > 0u)
{
increments[type] = 1u;
--remaining;
}
else
{
increments[type] = 0u;
}
}
}
else
{
// Find the lowest possible increment taking into account all limits.
for (const auto& type : aliveTypesForLimit)
{
if (increments[type] > maxIncrement)
increments[type] = maxIncrement;
}
}
}
// Apply the calculated increments per descriptor type, decreasing the remaining descriptors for each
// limit affected by the type, and switching types to the not-alive state when a limit is hit.
for (const auto& inc : increments)
{
const vk::VkDescriptorType& type = inc.first;
const deUint32& increment = inc.second;
// Increase type count.
auto iter = typeCounts.find(type);
DE_ASSERT(iter != typeCounts.end());
iter->second.count += increment;
for (auto& limit : limits)
{
// Decrease remaining descriptors for affected limits.
if (limit.affectedTypes.find(type) != limit.affectedTypes.end())
{
DE_ASSERT(increment <= limit.remaining);
limit.remaining -= increment;
}
if (limit.remaining == 0u)
{
// Limit hit, switch affected types to not-alive.
for (const auto& affectedType : limit.affectedTypes)
{
auto tc = typeCounts.find(affectedType);
if (tc != typeCounts.end())
tc->second.alive = false;
}
}
}
}
}
}
// Create a limits vector based on runtime limit information for the device.
LimitsVector buildLimitsVector (const DevProp1& prop1, const DevIubProp& iubProp, const MaintDevProp3& maintProp3)
{
static const TypeSet samplerTypes = { vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_DESCRIPTOR_TYPE_SAMPLER };
static const TypeSet sampledImageTypes = { vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER };
static const TypeSet uniformBufferTypes = { vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC };
static const TypeSet storageBufferTypes = { vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC };
static const TypeSet storageImageTypes = { vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER };
static const TypeSet inputAttachmentTypes = { vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT };
static const TypeSet inlineUniformBlockTypes = { vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT };
static const TypeSet dynamicUniformBuffer = { vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC };
static const TypeSet dynamicStorageBuffer = { vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC };
static const TypeSet allTypesButIUB = {
vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
};
static const TypeSet allTypes = {
vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
vk::VK_DESCRIPTOR_TYPE_SAMPLER,
vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT,
};
LimitsVector limits = {
{
"maxPerStageDescriptorSamplers",
prop1.limits.maxPerStageDescriptorSamplers,
samplerTypes
},
{
"maxDescriptorSetSamplers",
prop1.limits.maxDescriptorSetSamplers,
samplerTypes
},
{
"maxPerStageDescriptorSampledImages",
prop1.limits.maxPerStageDescriptorSampledImages,
sampledImageTypes
},
{
"maxDescriptorSetSampledImages",
prop1.limits.maxDescriptorSetSampledImages,
sampledImageTypes
},
{
"maxPerStageDescriptorUniformBuffers",
prop1.limits.maxPerStageDescriptorUniformBuffers,
uniformBufferTypes
},
{
"maxDescriptorSetUniformBuffers",
prop1.limits.maxDescriptorSetUniformBuffers,
uniformBufferTypes
},
{
"maxPerStageDescriptorStorageBuffers",
prop1.limits.maxPerStageDescriptorStorageBuffers,
storageBufferTypes
},
{
"maxDescriptorSetStorageBuffers",
prop1.limits.maxDescriptorSetStorageBuffers,
storageBufferTypes
},
{
"maxPerStageDescriptorStorageImages",
prop1.limits.maxPerStageDescriptorStorageImages,
storageImageTypes
},
{
"maxDescriptorSetStorageImages",
prop1.limits.maxDescriptorSetStorageImages,
storageImageTypes
},
{
"maxPerStageDescriptorInputAttachments",
prop1.limits.maxPerStageDescriptorInputAttachments,
inputAttachmentTypes
},
{
"maxDescriptorSetInputAttachments",
prop1.limits.maxDescriptorSetInputAttachments,
inputAttachmentTypes
},
{
"maxDescriptorSetUniformBuffersDynamic",
prop1.limits.maxDescriptorSetUniformBuffersDynamic,
dynamicUniformBuffer
},
{
"maxDescriptorSetStorageBuffersDynamic",
prop1.limits.maxDescriptorSetStorageBuffersDynamic,
dynamicStorageBuffer
},
{
"maxPerStageDescriptorInlineUniformBlocks",
iubProp.maxPerStageDescriptorInlineUniformBlocks,
inlineUniformBlockTypes
},
{
"maxDescriptorSetInlineUniformBlocks",
iubProp.maxDescriptorSetInlineUniformBlocks,
inlineUniformBlockTypes
},
{
"maxPerStageResources",
prop1.limits.maxPerStageResources,
allTypesButIUB
},
{
"maxPerSetDescriptors",
maintProp3.maxPerSetDescriptors,
allTypes
},
};
return limits;
}
// Create a vector of bindings by constructing the system limits and distributing descriptor counts.
vector<vk::VkDescriptorSetLayoutBinding> calculateBindings(const DevProp1& prop1, const DevIubProp& iubProp, const MaintDevProp3& maintProp3, const vector<vk::VkDescriptorType> &types)
{
LimitsVector limits = buildLimitsVector(prop1, iubProp, maintProp3);
TypeCounts typeCounts;
for (const auto& type : types)
typeCounts.emplace(make_pair(type, TypeState(type)));
distributeCounts(limits, typeCounts);
deUint32 bindingNumber = 0u;
vector<vk::VkDescriptorSetLayoutBinding> bindings;
for (const auto& tc : typeCounts)
{
if (tc.first != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)
{
vk::VkDescriptorSetLayoutBinding b;
b.binding = bindingNumber;
b.descriptorCount = tc.second.count;
b.descriptorType = tc.first;
b.pImmutableSamplers = DE_NULL;
b.stageFlags = vk::VK_SHADER_STAGE_ALL;
bindings.push_back(b);
}
else
{
// Inline uniform blocks are special because descriptorCount represents the size of that block.
// The only way of creating several blocks is by adding more structures to the list instead of creating an array.
size_t firstAdded = bindings.size();
bindings.resize(firstAdded + tc.second.count);
for (deUint32 i = 0u; i < tc.second.count; ++i)
{
vk::VkDescriptorSetLayoutBinding& b = bindings[firstAdded + i];
b.binding = bindingNumber + i;
b.descriptorCount = 4u; // For inline uniform blocks, this must be a multiple of 4 according to the spec.
b.descriptorType = tc.first;
b.pImmutableSamplers = DE_NULL;
b.stageFlags = vk::VK_SHADER_STAGE_ALL;
}
}
bindingNumber += tc.second.count;
}
return bindings;
}
// Get a textual description with descriptor counts per type.
string getBindingsDescription (const vector<VkDescriptorSetLayoutBinding>& bindings)
{
map<vk::VkDescriptorType, deUint32> typeCount;
deUint32 totalCount = 0u;
deUint32 count;
for (const auto& b : bindings)
{
auto iter = typeCount.find(b.descriptorType);
if (iter == typeCount.end())
iter = typeCount.insert(make_pair(b.descriptorType, (deUint32)0)).first;
count = ((b.descriptorType == vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) ? 1u : b.descriptorCount);
iter->second += count;
totalCount += count;
}
deUint32 i = 0;
ostringstream combStr;
combStr << "{ Descriptors: " << totalCount << ", [";
for (const auto& tc : typeCount)
combStr << (i++ ? ", " : " ") << tc.first << ": " << tc.second;
combStr << " ] }";
return combStr.str();
}
class Maintenance3StructTestInstance : public TestInstance
{
public:
Maintenance3StructTestInstance (Context& ctx)
: TestInstance (ctx)
{}
virtual tcu::TestStatus iterate (void)
{
tcu::TestLog& log = m_context.getTestContext().getLog();
// set values to be a bit smaller than required minimum values
MaintDevProp3 maintProp3 =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, //VkStructureType sType;
DE_NULL, //void* pNext;
maxDescriptorsInSet - 1u, //deUint32 maxPerSetDescriptors;
maxMemoryAllocationSize - 1u //VkDeviceSize maxMemoryAllocationSize;
};
DevProp2 prop2;
deMemset(&prop2, 0, sizeof(prop2)); // zero the structure
prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
prop2.pNext = &maintProp3;
m_context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &prop2);
if (maintProp3.maxMemoryAllocationSize < maxMemoryAllocationSize)
return tcu::TestStatus::fail("Fail");
if (maintProp3.maxPerSetDescriptors < maxDescriptorsInSet)
return tcu::TestStatus::fail("Fail");
log << tcu::TestLog::Message << "maxMemoryAllocationSize: " << maintProp3.maxMemoryAllocationSize << tcu::TestLog::EndMessage;
log << tcu::TestLog::Message << "maxPerSetDescriptors: " << maintProp3.maxPerSetDescriptors << tcu::TestLog::EndMessage;
return tcu::TestStatus::pass("Pass");
}
};
class Maintenance3StructTestCase : public TestCase
{
public:
Maintenance3StructTestCase (tcu::TestContext& testCtx)
: TestCase(testCtx, "maintenance3_properties", "tests VkPhysicalDeviceMaintenance3Properties struct")
{}
virtual ~Maintenance3StructTestCase (void)
{}
virtual void checkSupport (Context& ctx) const
{
ctx.requireDeviceFunctionality("VK_KHR_maintenance3");
}
virtual TestInstance* createInstance (Context& ctx) const
{
return new Maintenance3StructTestInstance(ctx);
}
private:
};
class Maintenance3DescriptorTestInstance : public TestInstance
{
public:
Maintenance3DescriptorTestInstance (Context& ctx)
: TestInstance(ctx)
{}
virtual tcu::TestStatus iterate (void)
{
const auto& vki = m_context.getInstanceInterface();
const auto& vkd = m_context.getDeviceInterface();
const auto& physicalDevice = m_context.getPhysicalDevice();
const auto& device = m_context.getDevice();
auto& log = m_context.getTestContext().getLog();
bool iubSupported = false;
if (m_context.isDeviceFunctionalitySupported("VK_EXT_inline_uniform_block"))
{
DevIubFeat iubFeatures =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT,
DE_NULL,
0u,
0u
};
DevFeat2 features2 =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
&iubFeatures,
VkPhysicalDeviceFeatures()
};
vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
iubSupported = (iubFeatures.inlineUniformBlock == VK_TRUE);
}
DevIubProp devIubProp =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT, // VkStructureType sType;
DE_NULL, // void* pNext;
0u, // deUint32 maxInlineUniformBlockSize;
0u, // deUint32 maxPerStageDescriptorInlineUniformBlocks;
0u, // deUint32 maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks;
0u, // deUint32 maxDescriptorSetInlineUniformBlocks;
0u // deUint32 maxDescriptorSetUpdateAfterBindInlineUniformBlocks;
};
MaintDevProp3 maintProp3 =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, //VkStructureType sType;
(iubSupported ? &devIubProp : DE_NULL), //void* pNext;
maxDescriptorsInSet, //deUint32 maxPerSetDescriptors;
maxMemoryAllocationSize //VkDeviceSize maxMemoryAllocationSize;
};
DevProp2 prop2 =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, //VkStructureType sType;
&maintProp3, //void* pNext;
VkPhysicalDeviceProperties() //VkPhysicalDeviceProperties properties;
};
vki.getPhysicalDeviceProperties2(physicalDevice, &prop2);
vector<VkDescriptorType> descriptorTypes = {
VK_DESCRIPTOR_TYPE_SAMPLER,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
};
if (iubSupported)
descriptorTypes.push_back(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT);
// VkDescriptorSetLayoutCreateInfo setup
vk::VkDescriptorSetLayoutCreateInfo pCreateInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, //VkStructureType sType;
DE_NULL, //const void* pNext;
0u, //VkDescriptorSetLayoutCreateFlags flags;
0u, //deUint32 bindingCount;
DE_NULL //const VkDescriptorSetLayoutBinding* pBindings;
};
// VkDescriptorSetLayoutSupport setup
vk::VkDescriptorSetLayoutSupport pSupport =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, //VkStructureType sType;
DE_NULL, //void* pNext;
VK_FALSE //VkBool32 supported;
};
// Check every combination maximizing descriptor counts.
for (size_t combSize = 1; combSize <= descriptorTypes.size(); ++combSize)
{
// Create a vector of selectors with combSize elements set to true.
vector<bool> selectors(descriptorTypes.size(), false);
std::fill(begin(selectors), begin(selectors) + combSize, true);
// Iterate over every permutation of selectors for that combination size.
do
{
vector<vk::VkDescriptorType> types;
for (size_t i = 0; i < selectors.size(); ++i)
{
if (selectors[i])
types.push_back(descriptorTypes[i]);
}
// Due to inline uniform blocks being unable to form arrays and each one of them needing its own
// VkDescriptorSetLayoutBinding structure, we will limit when to test them.
if (std::find(begin(types), end(types), VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) != types.end() &&
devIubProp.maxPerStageDescriptorInlineUniformBlocks > maxReasonableInlineUniformBlocks &&
combSize > 1u && combSize < descriptorTypes.size())
{
continue;
}
vector<vk::VkDescriptorSetLayoutBinding> bindings = calculateBindings(prop2.properties, devIubProp, maintProp3, types);
string description = getBindingsDescription(bindings);
log << tcu::TestLog::Message << "Testing combination: " << description << tcu::TestLog::EndMessage;
pCreateInfo.bindingCount = static_cast<deUint32>(bindings.size());
pCreateInfo.pBindings = bindings.data();
vkd.getDescriptorSetLayoutSupport(device, &pCreateInfo, &pSupport);
if (pSupport.supported == VK_FALSE)
{
ostringstream msg;
msg << "Failed to use the following descriptor type counts: " << description;
return tcu::TestStatus::fail(msg.str());
}
} while (std::prev_permutation(begin(selectors), end(selectors)));
}
return tcu::TestStatus::pass("Pass");
}
};
class Maintenance3DescriptorTestCase : public TestCase
{
public:
Maintenance3DescriptorTestCase (tcu::TestContext& testCtx)
: TestCase(testCtx, "descriptor_set", "tests vkGetDescriptorSetLayoutSupport struct")
{}
virtual ~Maintenance3DescriptorTestCase (void)
{}
virtual void checkSupport (Context& ctx) const
{
ctx.requireDeviceFunctionality("VK_KHR_maintenance3");
}
virtual TestInstance* createInstance (Context& ctx) const
{
return new Maintenance3DescriptorTestInstance(ctx);
}
};
} // anonymous
tcu::TestCaseGroup* createMaintenance3Tests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> main3Tests(new tcu::TestCaseGroup(testCtx, "maintenance3_check", "Maintenance3 Tests"));
main3Tests->addChild(new Maintenance3StructTestCase(testCtx));
main3Tests->addChild(new Maintenance3DescriptorTestCase(testCtx));
return main3Tests.release();
}
} // api
} // vkt