blob: 253f9d4cb01eae27490343abde498edd55a08e2d [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 Object management tests
*//*--------------------------------------------------------------------*/
#include "vktApiObjectManagementTests.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktCustomInstancesDevices.hpp"
#include "vkDefs.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkPrograms.hpp"
#include "vkTypeUtil.hpp"
#include "vkPlatform.hpp"
#include "vkStrUtil.hpp"
#include "vkAllocationCallbackUtil.hpp"
#include "vkObjUtil.hpp"
#include "tcuVector.hpp"
#include "tcuResultCollector.hpp"
#include "tcuCommandLine.hpp"
#include "tcuTestLog.hpp"
#include "tcuPlatform.hpp"
#include "deUniquePtr.hpp"
#include "deSharedPtr.hpp"
#include "deArrayUtil.hpp"
#include "deSpinBarrier.hpp"
#include "deThread.hpp"
#include "deInt32.h"
#include <limits>
#define VK_DESCRIPTOR_TYPE_LAST (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT + 1)
namespace vkt
{
namespace api
{
namespace
{
using namespace vk;
using de::UniquePtr;
using de::MovePtr;
using de::SharedPtr;
using tcu::IVec3;
using tcu::UVec3;
using tcu::ResultCollector;
using tcu::TestStatus;
using tcu::TestLog;
using std::string;
using std::vector;
typedef SharedPtr<Move<VkPipeline> > VkPipelineSp; // Move so it's possible to disown the handle
typedef SharedPtr<Move<VkDescriptorSet> > VkDescriptorSetSp;
typedef SharedPtr<Move<VkCommandBuffer> > VkCommandBufferSp;
class ThreadGroupThread;
/*--------------------------------------------------------------------*//*!
* \brief Thread group
*
* Thread group manages collection of threads that are expected to be
* launched simultaneously as a group.
*
* Shared barrier is provided for synchronizing execution. Terminating thread
* early either by returning from ThreadGroupThread::runThread() or throwing
* an exception is safe, and other threads will continue execution. The
* thread that has been terminated is simply removed from the synchronization
* group.
*
* TestException-based exceptions are collected and translated into a
* tcu::TestStatus by using tcu::ResultCollector.
*
* Use cases for ThreadGroup include for example testing thread-safety of
* certain API operations by poking API simultaneously from multiple
* threads.
*//*--------------------------------------------------------------------*/
class ThreadGroup
{
public:
ThreadGroup (void);
~ThreadGroup (void);
void add (de::MovePtr<ThreadGroupThread> thread);
TestStatus run (void);
private:
typedef std::vector<de::SharedPtr<ThreadGroupThread> > ThreadVector;
ThreadVector m_threads;
de::SpinBarrier m_barrier;
} DE_WARN_UNUSED_TYPE;
class ThreadGroupThread : private de::Thread
{
public:
ThreadGroupThread (void);
virtual ~ThreadGroupThread (void);
void start (de::SpinBarrier* groupBarrier);
ResultCollector& getResultCollector (void) { return m_resultCollector; }
using de::Thread::join;
protected:
virtual void runThread (void) = 0;
void barrier (void);
private:
ThreadGroupThread (const ThreadGroupThread&);
ThreadGroupThread& operator= (const ThreadGroupThread&);
void run (void);
ResultCollector m_resultCollector;
de::SpinBarrier* m_barrier;
};
// ThreadGroup
ThreadGroup::ThreadGroup (void)
: m_barrier(1)
{
}
ThreadGroup::~ThreadGroup (void)
{
}
void ThreadGroup::add (de::MovePtr<ThreadGroupThread> thread)
{
m_threads.push_back(de::SharedPtr<ThreadGroupThread>(thread.release()));
}
tcu::TestStatus ThreadGroup::run (void)
{
tcu::ResultCollector resultCollector;
m_barrier.reset((int)m_threads.size());
for (ThreadVector::iterator threadIter = m_threads.begin(); threadIter != m_threads.end(); ++threadIter)
(*threadIter)->start(&m_barrier);
for (ThreadVector::iterator threadIter = m_threads.begin(); threadIter != m_threads.end(); ++threadIter)
{
tcu::ResultCollector& threadResult = (*threadIter)->getResultCollector();
(*threadIter)->join();
resultCollector.addResult(threadResult.getResult(), threadResult.getMessage());
}
return tcu::TestStatus(resultCollector.getResult(), resultCollector.getMessage());
}
// ThreadGroupThread
ThreadGroupThread::ThreadGroupThread (void)
: m_barrier(DE_NULL)
{
}
ThreadGroupThread::~ThreadGroupThread (void)
{
}
void ThreadGroupThread::start (de::SpinBarrier* groupBarrier)
{
m_barrier = groupBarrier;
de::Thread::start();
}
void ThreadGroupThread::run (void)
{
try
{
runThread();
}
catch (const tcu::TestException& e)
{
getResultCollector().addResult(e.getTestResult(), e.getMessage());
}
catch (const std::exception& e)
{
getResultCollector().addResult(QP_TEST_RESULT_FAIL, e.what());
}
catch (...)
{
getResultCollector().addResult(QP_TEST_RESULT_FAIL, "Exception");
}
m_barrier->removeThread(de::SpinBarrier::WAIT_MODE_AUTO);
}
inline void ThreadGroupThread::barrier (void)
{
m_barrier->sync(de::SpinBarrier::WAIT_MODE_AUTO);
}
deUint32 getDefaultTestThreadCount (void)
{
return de::clamp(deGetNumAvailableLogicalCores(), 2u, 8u);
}
// Utilities
struct Environment
{
const PlatformInterface& vkp;
deUint32 apiVersion;
const InstanceInterface& instanceInterface;
VkInstance instance;
const DeviceInterface& vkd;
VkDevice device;
deUint32 queueFamilyIndex;
const BinaryCollection& programBinaries;
const VkAllocationCallbacks* allocationCallbacks;
deUint32 maxResourceConsumers; // Maximum number of objects using same Object::Resources concurrently
const tcu::CommandLine& commandLine;
Environment (Context& context, deUint32 maxResourceConsumers_)
: vkp (context.getPlatformInterface())
, apiVersion (context.getUsedApiVersion())
, instanceInterface (context.getInstanceInterface())
, instance (context.getInstance())
, vkd (context.getDeviceInterface())
, device (context.getDevice())
, queueFamilyIndex (context.getUniversalQueueFamilyIndex())
, programBinaries (context.getBinaryCollection())
, allocationCallbacks (DE_NULL)
, maxResourceConsumers (maxResourceConsumers_)
, commandLine (context.getTestContext().getCommandLine())
{
}
Environment (const PlatformInterface& vkp_,
deUint32 apiVersion_,
const InstanceInterface& instanceInterface_,
VkInstance instance_,
const DeviceInterface& vkd_,
VkDevice device_,
deUint32 queueFamilyIndex_,
const BinaryCollection& programBinaries_,
const VkAllocationCallbacks* allocationCallbacks_,
deUint32 maxResourceConsumers_,
const tcu::CommandLine& commandLine_)
: vkp (vkp_)
, apiVersion (apiVersion_)
, instanceInterface (instanceInterface_)
, instance (instance_)
, vkd (vkd_)
, device (device_)
, queueFamilyIndex (queueFamilyIndex_)
, programBinaries (programBinaries_)
, allocationCallbacks (allocationCallbacks_)
, maxResourceConsumers (maxResourceConsumers_)
, commandLine (commandLine_)
{
}
};
template<typename Case>
struct Dependency
{
typename Case::Resources resources;
Unique<typename Case::Type> object;
Dependency (const Environment& env, const typename Case::Parameters& params)
: resources (env, params)
, object (Case::create(env, resources, params))
{}
};
template<typename T>
T roundUpToNextMultiple (T value, T multiple)
{
if (value % multiple == 0)
return value;
else
return value + multiple - (value % multiple);
}
#if defined(DE_DEBUG)
template<typename T>
bool isPowerOfTwo (T value)
{
return ((value & (value - T(1))) == 0);
}
#endif
template<typename T>
T alignToPowerOfTwo (T value, T align)
{
DE_ASSERT(isPowerOfTwo(align));
return (value + align - T(1)) & ~(align - T(1));
}
inline bool hasDeviceExtension (Context& context, const string name)
{
return context.isDeviceFunctionalitySupported(name);
}
VkDeviceSize getPageTableSize (const PlatformMemoryLimits& limits, VkDeviceSize allocationSize)
{
VkDeviceSize totalSize = 0;
for (size_t levelNdx = 0; levelNdx < limits.devicePageTableHierarchyLevels; ++levelNdx)
{
const VkDeviceSize coveredAddressSpaceSize = limits.devicePageSize<<levelNdx;
const VkDeviceSize numPagesNeeded = alignToPowerOfTwo(allocationSize, coveredAddressSpaceSize) / coveredAddressSpaceSize;
totalSize += numPagesNeeded*limits.devicePageTableEntrySize;
}
return totalSize;
}
size_t getCurrentSystemMemoryUsage (const AllocationCallbackRecorder& allocRecoder)
{
const size_t systemAllocationOverhead = sizeof(void*)*2;
AllocationCallbackValidationResults validationResults;
validateAllocationCallbacks(allocRecoder, &validationResults);
TCU_CHECK(validationResults.violations.empty());
return getLiveSystemAllocationTotal(validationResults) + systemAllocationOverhead*validationResults.liveAllocations.size();
}
template<typename Object>
size_t computeSystemMemoryUsage (Context& context, const typename Object::Parameters& params)
{
AllocationCallbackRecorder allocRecorder (getSystemAllocator());
const Environment env (context.getPlatformInterface(),
context.getUsedApiVersion(),
context.getInstanceInterface(),
context.getInstance(),
context.getDeviceInterface(),
context.getDevice(),
context.getUniversalQueueFamilyIndex(),
context.getBinaryCollection(),
allocRecorder.getCallbacks(),
1u,
context.getTestContext().getCommandLine());
const typename Object::Resources res (env, params);
const size_t resourceMemoryUsage = getCurrentSystemMemoryUsage(allocRecorder);
{
Unique<typename Object::Type> obj (Object::create(env, res, params));
const size_t totalMemoryUsage = getCurrentSystemMemoryUsage(allocRecorder);
return totalMemoryUsage - resourceMemoryUsage;
}
}
size_t getSafeObjectCount (const PlatformMemoryLimits& memoryLimits,
size_t objectSystemMemoryUsage,
VkDeviceSize objectDeviceMemoryUsage = 0)
{
const VkDeviceSize roundedUpDeviceMemory = roundUpToNextMultiple(objectDeviceMemoryUsage, memoryLimits.deviceMemoryAllocationGranularity);
if (memoryLimits.totalDeviceLocalMemory > 0 && roundedUpDeviceMemory > 0)
{
if (objectSystemMemoryUsage > 0)
return de::min(memoryLimits.totalSystemMemory / objectSystemMemoryUsage,
(size_t)(memoryLimits.totalDeviceLocalMemory / roundedUpDeviceMemory));
else
return (size_t)(memoryLimits.totalDeviceLocalMemory / roundedUpDeviceMemory);
}
else if (objectSystemMemoryUsage + roundedUpDeviceMemory > 0)
{
DE_ASSERT(roundedUpDeviceMemory <= std::numeric_limits<size_t>::max() - objectSystemMemoryUsage);
return memoryLimits.totalSystemMemory / (objectSystemMemoryUsage + (size_t)roundedUpDeviceMemory);
}
else
{
// Warning: at this point driver has probably not implemented allocation callbacks correctly
return std::numeric_limits<size_t>::max();
}
}
PlatformMemoryLimits getPlatformMemoryLimits (Context& context)
{
PlatformMemoryLimits memoryLimits;
context.getTestContext().getPlatform().getVulkanPlatform().getMemoryLimits(memoryLimits);
return memoryLimits;
}
size_t getSafeObjectCount (Context& context, size_t objectSystemMemoryUsage, VkDeviceSize objectDeviceMemorySize = 0)
{
return getSafeObjectCount(getPlatformMemoryLimits(context), objectSystemMemoryUsage, objectDeviceMemorySize);
}
VkDeviceSize getPageTableSize (Context& context, VkDeviceSize allocationSize)
{
return getPageTableSize(getPlatformMemoryLimits(context), allocationSize);
}
template<typename Object>
deUint32 getSafeObjectCount (Context& context,
const typename Object::Parameters& params,
deUint32 hardCountLimit,
VkDeviceSize deviceMemoryUsage = 0)
{
return (deUint32)de::min((size_t)hardCountLimit,
getSafeObjectCount(context,
computeSystemMemoryUsage<Object>(context, params),
deviceMemoryUsage));
}
// Object definitions
enum
{
MAX_CONCURRENT_INSTANCES = 32,
MAX_CONCURRENT_DEVICES = 32,
MAX_CONCURRENT_SYNC_PRIMITIVES = 100,
MAX_CONCURRENT_PIPELINE_CACHES = 128,
DEFAULT_MAX_CONCURRENT_OBJECTS = 16*1024,
};
struct Instance
{
typedef VkInstance Type;
struct Parameters
{
const vector<string> instanceExtensions;
Parameters (void) {}
Parameters (vector<string>& extensions)
: instanceExtensions (extensions)
{}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<Instance>(context, params, MAX_CONCURRENT_INSTANCES);
}
static Move<VkInstance> create (const Environment& env, const Resources&, const Parameters& params)
{
vector<const char*> extensionNamePtrs;
const vector<VkExtensionProperties> instanceExts = enumerateInstanceExtensionProperties(env.vkp, DE_NULL);
for (const auto& extName : params.instanceExtensions)
{
bool extNotInCore = !isCoreInstanceExtension(env.apiVersion, extName);
if (extNotInCore && !isExtensionSupported(instanceExts.begin(), instanceExts.end(), RequiredExtension(extName)))
TCU_THROW(NotSupportedError, (extName + " is not supported").c_str());
if (extNotInCore)
extensionNamePtrs.push_back(extName.c_str());
}
const VkApplicationInfo appInfo =
{
VK_STRUCTURE_TYPE_APPLICATION_INFO,
DE_NULL,
DE_NULL, // pApplicationName
0u, // applicationVersion
DE_NULL, // pEngineName
0u, // engineVersion
env.apiVersion
};
const VkInstanceCreateInfo instanceInfo =
{
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
DE_NULL,
(VkInstanceCreateFlags)0,
&appInfo,
0u, // enabledLayerNameCount
DE_NULL, // ppEnabledLayerNames
(deUint32)extensionNamePtrs.size(), // enabledExtensionNameCount
extensionNamePtrs.empty() ? DE_NULL : &extensionNamePtrs[0], // ppEnabledExtensionNames
};
return createInstance(env.vkp, &instanceInfo, env.allocationCallbacks);
}
};
struct Device
{
typedef VkDevice Type;
struct Parameters
{
deUint32 deviceIndex;
VkQueueFlags queueFlags;
Parameters (deUint32 deviceIndex_, VkQueueFlags queueFlags_)
: deviceIndex (deviceIndex_)
, queueFlags (queueFlags_)
{}
};
struct Resources
{
Dependency<Instance> instance;
InstanceDriver vki;
VkPhysicalDevice physicalDevice;
deUint32 queueFamilyIndex;
Resources (const Environment& env, const Parameters& params)
: instance (env, Instance::Parameters())
, vki (env.vkp, *instance.object)
, physicalDevice (0)
, queueFamilyIndex (~0u)
{
{
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(vki, *instance.object);
if (physicalDevices.size() <= (size_t)params.deviceIndex)
TCU_THROW(NotSupportedError, "Device not found");
physicalDevice = physicalDevices[params.deviceIndex];
}
{
const vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(vki, physicalDevice);
bool foundMatching = false;
for (size_t curQueueNdx = 0; curQueueNdx < queueProps.size(); curQueueNdx++)
{
if ((queueProps[curQueueNdx].queueFlags & params.queueFlags) == params.queueFlags)
{
queueFamilyIndex = (deUint32)curQueueNdx;
foundMatching = true;
}
}
if (!foundMatching)
TCU_THROW(NotSupportedError, "Matching queue not found");
}
}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<Device>(context, params, MAX_CONCURRENT_DEVICES);
}
static Move<VkDevice> create (const Environment& env, const Resources& res, const Parameters&)
{
const float queuePriority = 1.0;
const VkDeviceQueueCreateInfo queues[] =
{
{
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
DE_NULL,
(VkDeviceQueueCreateFlags)0,
res.queueFamilyIndex,
1u, // queueCount
&queuePriority, // pQueuePriorities
}
};
const VkDeviceCreateInfo deviceInfo =
{
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
DE_NULL,
(VkDeviceCreateFlags)0,
DE_LENGTH_OF_ARRAY(queues),
queues,
0u, // enabledLayerNameCount
DE_NULL, // ppEnabledLayerNames
0u, // enabledExtensionNameCount
DE_NULL, // ppEnabledExtensionNames
DE_NULL, // pEnabledFeatures
};
return createCustomDevice(env.commandLine.isValidationEnabled(), env.vkp, env.instance, res.vki, res.physicalDevice, &deviceInfo, env.allocationCallbacks);
}
};
struct DeviceGroup
{
typedef VkDevice Type;
struct Parameters
{
deUint32 deviceGroupIndex;
deUint32 deviceIndex;
VkQueueFlags queueFlags;
Parameters (deUint32 deviceGroupIndex_, deUint32 deviceIndex_, VkQueueFlags queueFlags_)
: deviceGroupIndex (deviceGroupIndex_)
, deviceIndex (deviceIndex_)
, queueFlags (queueFlags_)
{}
};
struct Resources
{
vector<string> extensions;
Dependency<Instance> instance;
InstanceDriver vki;
vector<VkPhysicalDevice> physicalDevices;
deUint32 physicalDeviceCount;
deUint32 queueFamilyIndex;
Resources (const Environment& env, const Parameters& params)
: extensions (1, "VK_KHR_device_group_creation")
, instance (env, Instance::Parameters(extensions))
, vki (env.vkp, *instance.object)
, physicalDeviceCount (0)
, queueFamilyIndex (~0u)
{
{
const vector<VkPhysicalDeviceGroupProperties> devGroupProperties = enumeratePhysicalDeviceGroups(vki, *instance.object);
if (devGroupProperties.size() <= (size_t)params.deviceGroupIndex)
TCU_THROW(NotSupportedError, "Device Group not found");
physicalDeviceCount = devGroupProperties[params.deviceGroupIndex].physicalDeviceCount;
physicalDevices.resize(physicalDeviceCount);
for (deUint32 physicalDeviceIdx = 0; physicalDeviceIdx < physicalDeviceCount; physicalDeviceIdx++)
physicalDevices[physicalDeviceIdx] = devGroupProperties[params.deviceGroupIndex].physicalDevices[physicalDeviceIdx];
}
{
const vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(vki, physicalDevices[params.deviceIndex]);
bool foundMatching = false;
for (size_t curQueueNdx = 0; curQueueNdx < queueProps.size(); curQueueNdx++)
{
if ((queueProps[curQueueNdx].queueFlags & params.queueFlags) == params.queueFlags)
{
queueFamilyIndex = (deUint32)curQueueNdx;
foundMatching = true;
}
}
if (!foundMatching)
TCU_THROW(NotSupportedError, "Matching queue not found");
}
}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<DeviceGroup>(context, params, MAX_CONCURRENT_DEVICES);
}
static Move<VkDevice> create (const Environment& env, const Resources& res, const Parameters& params)
{
const float queuePriority = 1.0;
const VkDeviceQueueCreateInfo queues[] =
{
{
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
DE_NULL, // pNext
(VkDeviceQueueCreateFlags)0, // flags
res.queueFamilyIndex, // queueFamilyIndex
1u, // queueCount
&queuePriority, // pQueuePriorities
}
};
const VkDeviceGroupDeviceCreateInfo deviceGroupInfo =
{
VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO, //stype
DE_NULL, //pNext
res.physicalDeviceCount, //physicalDeviceCount
res.physicalDevices.data() //physicalDevices
};
const VkDeviceCreateInfo deviceGroupCreateInfo =
{
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
&deviceGroupInfo,
(VkDeviceCreateFlags)0,
DE_LENGTH_OF_ARRAY(queues),
queues,
0u, // enabledLayerNameCount
DE_NULL, // ppEnabledLayerNames
0u, // enabledExtensionNameCount
DE_NULL, // ppEnabledExtensionNames
DE_NULL, // pEnabledFeatures
};
return createCustomDevice(env.commandLine.isValidationEnabled(), env.vkp, env.instance, res.vki, res.physicalDevices[params.deviceIndex], &deviceGroupCreateInfo, env.allocationCallbacks);
}
};
struct DeviceMemory
{
typedef VkDeviceMemory Type;
struct Parameters
{
VkDeviceSize size;
deUint32 memoryTypeIndex;
Parameters (VkDeviceSize size_, deUint32 memoryTypeIndex_)
: size (size_)
, memoryTypeIndex (memoryTypeIndex_)
{
DE_ASSERT(memoryTypeIndex < VK_MAX_MEMORY_TYPES);
}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
const VkDeviceSize deviceMemoryUsage = params.size + getPageTableSize(context, params.size);
return getSafeObjectCount<DeviceMemory>(context,
params,
de::min(context.getDeviceProperties().limits.maxMemoryAllocationCount,
(deUint32)DEFAULT_MAX_CONCURRENT_OBJECTS),
deviceMemoryUsage);
}
static Move<VkDeviceMemory> create (const Environment& env, const Resources&, const Parameters& params)
{
const VkMemoryAllocateInfo allocInfo =
{
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
DE_NULL,
params.size,
params.memoryTypeIndex
};
return allocateMemory(env.vkd, env.device, &allocInfo, env.allocationCallbacks);
}
};
DeviceMemory::Parameters getDeviceMemoryParameters (const VkMemoryRequirements& memReqs)
{
return DeviceMemory::Parameters(memReqs.size, deCtz32(memReqs.memoryTypeBits));
}
DeviceMemory::Parameters getDeviceMemoryParameters (const Environment& env, VkImage image)
{
return getDeviceMemoryParameters(getImageMemoryRequirements(env.vkd, env.device, image));
}
DeviceMemory::Parameters getDeviceMemoryParameters (const Environment& env, VkBuffer image)
{
return getDeviceMemoryParameters(getBufferMemoryRequirements(env.vkd, env.device, image));
}
struct Buffer
{
typedef VkBuffer Type;
struct Parameters
{
VkDeviceSize size;
VkBufferUsageFlags usage;
Parameters (VkDeviceSize size_,
VkBufferUsageFlags usage_)
: size (size_)
, usage (usage_)
{}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
const Environment env (context, 1u);
const Resources res (env, params);
const Unique<VkBuffer> buffer (create(env, res, params));
const VkMemoryRequirements memReqs = getBufferMemoryRequirements(env.vkd, env.device, *buffer);
return getSafeObjectCount<Buffer>(context,
params,
DEFAULT_MAX_CONCURRENT_OBJECTS,
getPageTableSize(context, memReqs.size));
}
static Move<VkBuffer> create (const Environment& env, const Resources&, const Parameters& params)
{
const VkBufferCreateInfo bufferInfo =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
(VkBufferCreateFlags)0,
params.size,
params.usage,
VK_SHARING_MODE_EXCLUSIVE,
1u,
&env.queueFamilyIndex
};
return createBuffer(env.vkd, env.device, &bufferInfo, env.allocationCallbacks);
}
};
struct BufferView
{
typedef VkBufferView Type;
struct Parameters
{
Buffer::Parameters buffer;
VkFormat format;
VkDeviceSize offset;
VkDeviceSize range;
Parameters (const Buffer::Parameters& buffer_,
VkFormat format_,
VkDeviceSize offset_,
VkDeviceSize range_)
: buffer (buffer_)
, format (format_)
, offset (offset_)
, range (range_)
{}
};
struct Resources
{
Dependency<Buffer> buffer;
Dependency<DeviceMemory> memory;
Resources (const Environment& env, const Parameters& params)
: buffer(env, params.buffer)
, memory(env, getDeviceMemoryParameters(env, *buffer.object))
{
VK_CHECK(env.vkd.bindBufferMemory(env.device, *buffer.object, *memory.object, 0));
}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<BufferView>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static Move<VkBufferView> create (const Environment& env, const Resources& res, const Parameters& params)
{
const VkBufferViewCreateInfo bufferViewInfo =
{
VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
DE_NULL,
(VkBufferViewCreateFlags)0,
*res.buffer.object,
params.format,
params.offset,
params.range
};
return createBufferView(env.vkd, env.device, &bufferViewInfo, env.allocationCallbacks);
}
};
struct Image
{
typedef VkImage Type;
struct Parameters
{
VkImageCreateFlags flags;
VkImageType imageType;
VkFormat format;
VkExtent3D extent;
deUint32 mipLevels;
deUint32 arraySize;
VkSampleCountFlagBits samples;
VkImageTiling tiling;
VkImageUsageFlags usage;
VkImageLayout initialLayout;
Parameters (VkImageCreateFlags flags_,
VkImageType imageType_,
VkFormat format_,
VkExtent3D extent_,
deUint32 mipLevels_,
deUint32 arraySize_,
VkSampleCountFlagBits samples_,
VkImageTiling tiling_,
VkImageUsageFlags usage_,
VkImageLayout initialLayout_)
: flags (flags_)
, imageType (imageType_)
, format (format_)
, extent (extent_)
, mipLevels (mipLevels_)
, arraySize (arraySize_)
, samples (samples_)
, tiling (tiling_)
, usage (usage_)
, initialLayout (initialLayout_)
{}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
const Environment env (context, 1u);
const Resources res (env, params);
const Unique<VkImage> image (create(env, res, params));
const VkMemoryRequirements memReqs = getImageMemoryRequirements(env.vkd, env.device, *image);
return getSafeObjectCount<Image>(context,
params,
DEFAULT_MAX_CONCURRENT_OBJECTS,
getPageTableSize(context, memReqs.size));
}
static Move<VkImage> create (const Environment& env, const Resources&, const Parameters& params)
{
const VkImageCreateInfo imageInfo =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
DE_NULL,
params.flags,
params.imageType,
params.format,
params.extent,
params.mipLevels,
params.arraySize,
params.samples,
params.tiling,
params.usage,
VK_SHARING_MODE_EXCLUSIVE, // sharingMode
1u, // queueFamilyIndexCount
&env.queueFamilyIndex, // pQueueFamilyIndices
params.initialLayout
};
return createImage(env.vkd, env.device, &imageInfo, env.allocationCallbacks);
}
};
struct ImageView
{
typedef VkImageView Type;
struct Parameters
{
Image::Parameters image;
VkImageViewType viewType;
VkFormat format;
VkComponentMapping components;
VkImageSubresourceRange subresourceRange;
Parameters (const Image::Parameters& image_,
VkImageViewType viewType_,
VkFormat format_,
VkComponentMapping components_,
VkImageSubresourceRange subresourceRange_)
: image (image_)
, viewType (viewType_)
, format (format_)
, components (components_)
, subresourceRange (subresourceRange_)
{}
};
struct Resources
{
Dependency<Image> image;
Dependency<DeviceMemory> memory;
Resources (const Environment& env, const Parameters& params)
: image (env, params.image)
, memory(env, getDeviceMemoryParameters(env, *image.object))
{
VK_CHECK(env.vkd.bindImageMemory(env.device, *image.object, *memory.object, 0));
}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<ImageView>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static Move<VkImageView> create (const Environment& env, const Resources& res, const Parameters& params)
{
const VkImageViewCreateInfo imageViewInfo =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
DE_NULL,
(VkImageViewCreateFlags)0,
*res.image.object,
params.viewType,
params.format,
params.components,
params.subresourceRange,
};
return createImageView(env.vkd, env.device, &imageViewInfo, env.allocationCallbacks);
}
};
struct Semaphore
{
typedef VkSemaphore Type;
struct Parameters
{
VkSemaphoreCreateFlags flags;
Parameters (VkSemaphoreCreateFlags flags_)
: flags(flags_)
{}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<Semaphore>(context, params, MAX_CONCURRENT_SYNC_PRIMITIVES);
}
static Move<VkSemaphore> create (const Environment& env, const Resources&, const Parameters& params)
{
const VkSemaphoreCreateInfo semaphoreInfo =
{
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
DE_NULL,
params.flags
};
return createSemaphore(env.vkd, env.device, &semaphoreInfo, env.allocationCallbacks);
}
};
struct Fence
{
typedef VkFence Type;
struct Parameters
{
VkFenceCreateFlags flags;
Parameters (VkFenceCreateFlags flags_)
: flags(flags_)
{}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<Fence>(context, params, MAX_CONCURRENT_SYNC_PRIMITIVES);
}
static Move<VkFence> create (const Environment& env, const Resources&, const Parameters& params)
{
const VkFenceCreateInfo fenceInfo =
{
VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
DE_NULL,
params.flags
};
return createFence(env.vkd, env.device, &fenceInfo, env.allocationCallbacks);
}
};
struct Event
{
typedef VkEvent Type;
struct Parameters
{
VkEventCreateFlags flags;
Parameters (VkEventCreateFlags flags_)
: flags(flags_)
{}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<Event>(context, params, MAX_CONCURRENT_SYNC_PRIMITIVES);
}
static Move<VkEvent> create (const Environment& env, const Resources&, const Parameters& params)
{
const VkEventCreateInfo eventInfo =
{
VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,
DE_NULL,
params.flags
};
return createEvent(env.vkd, env.device, &eventInfo, env.allocationCallbacks);
}
};
struct QueryPool
{
typedef VkQueryPool Type;
struct Parameters
{
VkQueryType queryType;
deUint32 entryCount;
VkQueryPipelineStatisticFlags pipelineStatistics;
Parameters (VkQueryType queryType_,
deUint32 entryCount_,
VkQueryPipelineStatisticFlags pipelineStatistics_)
: queryType (queryType_)
, entryCount (entryCount_)
, pipelineStatistics (pipelineStatistics_)
{}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<QueryPool>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static Move<VkQueryPool> create (const Environment& env, const Resources&, const Parameters& params)
{
const VkQueryPoolCreateInfo queryPoolInfo =
{
VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
DE_NULL,
(VkQueryPoolCreateFlags)0,
params.queryType,
params.entryCount,
params.pipelineStatistics
};
return createQueryPool(env.vkd, env.device, &queryPoolInfo, env.allocationCallbacks);
}
};
struct ShaderModule
{
typedef VkShaderModule Type;
struct Parameters
{
VkShaderStageFlagBits shaderStage;
string binaryName;
Parameters (VkShaderStageFlagBits shaderStage_,
const std::string& binaryName_)
: shaderStage (shaderStage_)
, binaryName (binaryName_)
{}
};
struct Resources
{
const ProgramBinary& binary;
Resources (const Environment& env, const Parameters& params)
: binary(env.programBinaries.get(params.binaryName))
{}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<ShaderModule>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static const char* getSource (VkShaderStageFlagBits stage)
{
switch (stage)
{
case VK_SHADER_STAGE_VERTEX_BIT:
return "#version 310 es\n"
"layout(location = 0) in highp vec4 a_position;\n"
"void main () { gl_Position = a_position; }\n";
case VK_SHADER_STAGE_FRAGMENT_BIT:
return "#version 310 es\n"
"layout(location = 0) out mediump vec4 o_color;\n"
"void main () { o_color = vec4(1.0, 0.5, 0.25, 1.0); }";
case VK_SHADER_STAGE_COMPUTE_BIT:
return "#version 310 es\n"
"layout(binding = 0) buffer Input { highp uint dataIn[]; };\n"
"layout(binding = 1) buffer Output { highp uint dataOut[]; };\n"
"void main (void)\n"
"{\n"
" dataOut[gl_GlobalInvocationID.x] = ~dataIn[gl_GlobalInvocationID.x];\n"
"}\n";
default:
DE_FATAL("Not implemented");
return DE_NULL;
}
}
static void initPrograms (SourceCollections& dst, Parameters params)
{
const char* const source = getSource(params.shaderStage);
DE_ASSERT(source);
dst.glslSources.add(params.binaryName)
<< glu::ShaderSource(getGluShaderType(params.shaderStage), source);
}
static Move<VkShaderModule> create (const Environment& env, const Resources& res, const Parameters&)
{
const VkShaderModuleCreateInfo shaderModuleInfo =
{
VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
DE_NULL,
(VkShaderModuleCreateFlags)0,
res.binary.getSize(),
(const deUint32*)res.binary.getBinary(),
};
return createShaderModule(env.vkd, env.device, &shaderModuleInfo, env.allocationCallbacks);
}
};
struct PipelineCache
{
typedef VkPipelineCache Type;
struct Parameters
{
Parameters (void) {}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<PipelineCache>(context, params, MAX_CONCURRENT_PIPELINE_CACHES);
}
static Move<VkPipelineCache> create (const Environment& env, const Resources&, const Parameters&)
{
const VkPipelineCacheCreateInfo pipelineCacheInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
DE_NULL,
(VkPipelineCacheCreateFlags)0u,
0u, // initialDataSize
DE_NULL, // pInitialData
};
return createPipelineCache(env.vkd, env.device, &pipelineCacheInfo, env.allocationCallbacks);
}
};
struct Sampler
{
typedef VkSampler Type;
struct Parameters
{
VkFilter magFilter;
VkFilter minFilter;
VkSamplerMipmapMode mipmapMode;
VkSamplerAddressMode addressModeU;
VkSamplerAddressMode addressModeV;
VkSamplerAddressMode addressModeW;
float mipLodBias;
VkBool32 anisotropyEnable;
float maxAnisotropy;
VkBool32 compareEnable;
VkCompareOp compareOp;
float minLod;
float maxLod;
VkBorderColor borderColor;
VkBool32 unnormalizedCoordinates;
// \todo [2015-09-17 pyry] Other configurations
Parameters (void)
: magFilter (VK_FILTER_NEAREST)
, minFilter (VK_FILTER_NEAREST)
, mipmapMode (VK_SAMPLER_MIPMAP_MODE_NEAREST)
, addressModeU (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE)
, addressModeV (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE)
, addressModeW (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE)
, mipLodBias (0.0f)
, anisotropyEnable (VK_FALSE)
, maxAnisotropy (1.0f)
, compareEnable (VK_FALSE)
, compareOp (VK_COMPARE_OP_ALWAYS)
, minLod (-1000.f)
, maxLod (+1000.f)
, borderColor (VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK)
, unnormalizedCoordinates (VK_FALSE)
{}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<Sampler>(context,
params,
de::min(context.getDeviceProperties().limits.maxSamplerAllocationCount,
(deUint32)DEFAULT_MAX_CONCURRENT_OBJECTS));
}
static Move<VkSampler> create (const Environment& env, const Resources&, const Parameters& params)
{
const VkSamplerCreateInfo samplerInfo =
{
VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
DE_NULL,
(VkSamplerCreateFlags)0,
params.magFilter,
params.minFilter,
params.mipmapMode,
params.addressModeU,
params.addressModeV,
params.addressModeW,
params.mipLodBias,
params.anisotropyEnable,
params.maxAnisotropy,
params.compareEnable,
params.compareOp,
params.minLod,
params.maxLod,
params.borderColor,
params.unnormalizedCoordinates
};
return createSampler(env.vkd, env.device, &samplerInfo, env.allocationCallbacks);
}
};
struct DescriptorSetLayout
{
typedef VkDescriptorSetLayout Type;
struct Parameters
{
struct Binding
{
deUint32 binding;
VkDescriptorType descriptorType;
deUint32 descriptorCount;
VkShaderStageFlags stageFlags;
bool useImmutableSampler;
Binding (deUint32 binding_,
VkDescriptorType descriptorType_,
deUint32 descriptorCount_,
VkShaderStageFlags stageFlags_,
bool useImmutableSampler_)
: binding (binding_)
, descriptorType (descriptorType_)
, descriptorCount (descriptorCount_)
, stageFlags (stageFlags_)
, useImmutableSampler (useImmutableSampler_)
{}
Binding (void) {}
};
vector<Binding> bindings;
Parameters (const vector<Binding>& bindings_)
: bindings(bindings_)
{}
static Parameters empty (void)
{
return Parameters(vector<Binding>());
}
static Parameters single (deUint32 binding,
VkDescriptorType descriptorType,
deUint32 descriptorCount,
VkShaderStageFlags stageFlags,
bool useImmutableSampler = false)
{
vector<Binding> bindings;
bindings.push_back(Binding(binding, descriptorType, descriptorCount, stageFlags, useImmutableSampler));
return Parameters(bindings);
}
};
struct Resources
{
vector<VkDescriptorSetLayoutBinding> bindings;
MovePtr<Dependency<Sampler> > immutableSampler;
vector<VkSampler> immutableSamplersPtr;
Resources (const Environment& env, const Parameters& params)
{
// Create immutable sampler if needed
for (vector<Parameters::Binding>::const_iterator cur = params.bindings.begin(); cur != params.bindings.end(); cur++)
{
if (cur->useImmutableSampler && !immutableSampler)
{
immutableSampler = de::newMovePtr<Dependency<Sampler> >(env, Sampler::Parameters());
if (cur->useImmutableSampler && immutableSamplersPtr.size() < (size_t)cur->descriptorCount)
immutableSamplersPtr.resize(cur->descriptorCount, *immutableSampler->object);
}
}
for (vector<Parameters::Binding>::const_iterator cur = params.bindings.begin(); cur != params.bindings.end(); cur++)
{
const VkDescriptorSetLayoutBinding binding =
{
cur->binding,
cur->descriptorType,
cur->descriptorCount,
cur->stageFlags,
(cur->useImmutableSampler ? &immutableSamplersPtr[0] : DE_NULL)
};
bindings.push_back(binding);
}
}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<DescriptorSetLayout>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static Move<VkDescriptorSetLayout> create (const Environment& env, const Resources& res, const Parameters&)
{
const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
DE_NULL,
(VkDescriptorSetLayoutCreateFlags)0,
(deUint32)res.bindings.size(),
(res.bindings.empty() ? DE_NULL : &res.bindings[0])
};
return createDescriptorSetLayout(env.vkd, env.device, &descriptorSetLayoutInfo, env.allocationCallbacks);
}
};
struct PipelineLayout
{
typedef VkPipelineLayout Type;
struct Parameters
{
vector<DescriptorSetLayout::Parameters> descriptorSetLayouts;
vector<VkPushConstantRange> pushConstantRanges;
Parameters (void) {}
static Parameters empty (void)
{
return Parameters();
}
static Parameters singleDescriptorSet (const DescriptorSetLayout::Parameters& descriptorSetLayout)
{
Parameters params;
params.descriptorSetLayouts.push_back(descriptorSetLayout);
return params;
}
};
struct Resources
{
typedef SharedPtr<Dependency<DescriptorSetLayout> > DescriptorSetLayoutDepSp;
typedef vector<DescriptorSetLayoutDepSp> DescriptorSetLayouts;
DescriptorSetLayouts descriptorSetLayouts;
vector<VkDescriptorSetLayout> pSetLayouts;
Resources (const Environment& env, const Parameters& params)
{
for (vector<DescriptorSetLayout::Parameters>::const_iterator dsParams = params.descriptorSetLayouts.begin();
dsParams != params.descriptorSetLayouts.end();
++dsParams)
{
descriptorSetLayouts.push_back(DescriptorSetLayoutDepSp(new Dependency<DescriptorSetLayout>(env, *dsParams)));
pSetLayouts.push_back(*descriptorSetLayouts.back()->object);
}
}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<PipelineLayout>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static Move<VkPipelineLayout> create (const Environment& env, const Resources& res, const Parameters& params)
{
const VkPipelineLayoutCreateInfo pipelineLayoutInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
DE_NULL,
(VkPipelineLayoutCreateFlags)0,
(deUint32)res.pSetLayouts.size(),
(res.pSetLayouts.empty() ? DE_NULL : &res.pSetLayouts[0]),
(deUint32)params.pushConstantRanges.size(),
(params.pushConstantRanges.empty() ? DE_NULL : &params.pushConstantRanges[0]),
};
return createPipelineLayout(env.vkd, env.device, &pipelineLayoutInfo, env.allocationCallbacks);
}
};
struct RenderPass
{
typedef VkRenderPass Type;
// \todo [2015-09-17 pyry] More interesting configurations
struct Parameters
{
Parameters (void) {}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<RenderPass>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static Move<VkRenderPass> create (const Environment& env, const Resources&, const Parameters&)
{
return makeRenderPass(env.vkd, env.device, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_D16_UNORM,
VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
env.allocationCallbacks);
}
};
struct GraphicsPipeline
{
typedef VkPipeline Type;
// \todo [2015-09-17 pyry] More interesting configurations
struct Parameters
{
Parameters (void) {}
};
struct Resources
{
Dependency<ShaderModule> vertexShader;
Dependency<ShaderModule> fragmentShader;
Dependency<PipelineLayout> layout;
Dependency<RenderPass> renderPass;
Dependency<PipelineCache> pipelineCache;
Resources (const Environment& env, const Parameters&)
: vertexShader (env, ShaderModule::Parameters(VK_SHADER_STAGE_VERTEX_BIT, "vert"))
, fragmentShader (env, ShaderModule::Parameters(VK_SHADER_STAGE_FRAGMENT_BIT, "frag"))
, layout (env, PipelineLayout::Parameters::singleDescriptorSet(
DescriptorSetLayout::Parameters::single(0u, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u, VK_SHADER_STAGE_FRAGMENT_BIT, true)))
, renderPass (env, RenderPass::Parameters())
, pipelineCache (env, PipelineCache::Parameters())
{}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<GraphicsPipeline>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static void initPrograms (SourceCollections& dst, Parameters)
{
ShaderModule::initPrograms(dst, ShaderModule::Parameters(VK_SHADER_STAGE_VERTEX_BIT, "vert"));
ShaderModule::initPrograms(dst, ShaderModule::Parameters(VK_SHADER_STAGE_FRAGMENT_BIT, "frag"));
}
static vector<VkPipelineSp> createMultiple (const Environment& env, const Resources& res, const Parameters&, vector<VkPipeline>* const pOutHandles, VkResult* const pOutResult)
{
DE_ASSERT(pOutResult);
DE_ASSERT(pOutHandles);
DE_ASSERT(pOutHandles->size() != 0);
const VkPipelineShaderStageCreateInfo stages[] =
{
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
DE_NULL,
(VkPipelineShaderStageCreateFlags)0,
VK_SHADER_STAGE_VERTEX_BIT,
*res.vertexShader.object,
"main",
DE_NULL, // pSpecializationInfo
},
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
DE_NULL,
(VkPipelineShaderStageCreateFlags)0,
VK_SHADER_STAGE_FRAGMENT_BIT,
*res.fragmentShader.object,
"main",
DE_NULL, // pSpecializationInfo
}
};
const VkVertexInputBindingDescription vertexBindings[] =
{
{
0u, // binding
16u, // stride
VK_VERTEX_INPUT_RATE_VERTEX
}
};
const VkVertexInputAttributeDescription vertexAttribs[] =
{
{
0u, // location
0u, // binding
VK_FORMAT_R32G32B32A32_SFLOAT,
0u, // offset
}
};
const VkPipelineVertexInputStateCreateInfo vertexInputState =
{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineVertexInputStateCreateFlags)0,
DE_LENGTH_OF_ARRAY(vertexBindings),
vertexBindings,
DE_LENGTH_OF_ARRAY(vertexAttribs),
vertexAttribs
};
const VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
{
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineInputAssemblyStateCreateFlags)0,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
VK_FALSE // primitiveRestartEnable
};
const VkViewport viewport = makeViewport(tcu::UVec2(64));
const VkRect2D scissor = makeRect2D(tcu::UVec2(64));
const VkPipelineViewportStateCreateInfo viewportState =
{
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineViewportStateCreateFlags)0,
1u,
&viewport,
1u,
&scissor,
};
const VkPipelineRasterizationStateCreateInfo rasterState =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineRasterizationStateCreateFlags)0,
VK_FALSE, // depthClampEnable
VK_FALSE, // rasterizerDiscardEnable
VK_POLYGON_MODE_FILL,
VK_CULL_MODE_BACK_BIT,
VK_FRONT_FACE_COUNTER_CLOCKWISE,
VK_FALSE, // depthBiasEnable
0.0f, // depthBiasConstantFactor
0.0f, // depthBiasClamp
0.0f, // depthBiasSlopeFactor
1.0f, // lineWidth
};
const VkPipelineMultisampleStateCreateInfo multisampleState =
{
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineMultisampleStateCreateFlags)0,
VK_SAMPLE_COUNT_1_BIT,
VK_FALSE, // sampleShadingEnable
1.0f, // minSampleShading
DE_NULL, // pSampleMask
VK_FALSE, // alphaToCoverageEnable
VK_FALSE, // alphaToOneEnable
};
const VkPipelineDepthStencilStateCreateInfo depthStencilState =
{
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineDepthStencilStateCreateFlags)0,
VK_TRUE, // depthTestEnable
VK_TRUE, // depthWriteEnable
VK_COMPARE_OP_LESS, // depthCompareOp
VK_FALSE, // depthBoundsTestEnable
VK_FALSE, // stencilTestEnable
{ VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0u, 0u, 0u },
{ VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0u, 0u, 0u },
0.0f, // minDepthBounds
1.0f, // maxDepthBounds
};
const VkPipelineColorBlendAttachmentState colorBlendAttState[]=
{
{
VK_FALSE, // blendEnable
VK_BLEND_FACTOR_ONE,
VK_BLEND_FACTOR_ZERO,
VK_BLEND_OP_ADD,
VK_BLEND_FACTOR_ONE,
VK_BLEND_FACTOR_ZERO,
VK_BLEND_OP_ADD,
VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT
}
};
const VkPipelineColorBlendStateCreateInfo colorBlendState =
{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineColorBlendStateCreateFlags)0,
VK_FALSE, // logicOpEnable
VK_LOGIC_OP_COPY,
DE_LENGTH_OF_ARRAY(colorBlendAttState),
colorBlendAttState,
{ 0.0f, 0.0f, 0.0f, 0.0f } // blendConstants
};
const VkGraphicsPipelineCreateInfo pipelineInfo =
{
VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
DE_NULL,
(VkPipelineCreateFlags)0,
DE_LENGTH_OF_ARRAY(stages),
stages,
&vertexInputState,
&inputAssemblyState,
DE_NULL, // pTessellationState
&viewportState,
&rasterState,
&multisampleState,
&depthStencilState,
&colorBlendState,
(const VkPipelineDynamicStateCreateInfo*)DE_NULL,
*res.layout.object,
*res.renderPass.object,
0u, // subpass
(VkPipeline)0, // basePipelineHandle
0, // basePipelineIndex
};
const deUint32 numPipelines = static_cast<deUint32>(pOutHandles->size());
VkPipeline* const pHandles = &(*pOutHandles)[0];
vector<VkGraphicsPipelineCreateInfo> pipelineInfos (numPipelines, pipelineInfo);
*pOutResult = env.vkd.createGraphicsPipelines(env.device, *res.pipelineCache.object, numPipelines, &pipelineInfos[0], env.allocationCallbacks, pHandles);
vector<VkPipelineSp> pipelines;
// Even if an error is returned, some pipelines may have been created successfully
for (deUint32 i = 0; i < numPipelines; ++i)
{
if (pHandles[i] != DE_NULL)
pipelines.push_back(VkPipelineSp(new Move<VkPipeline>(check<VkPipeline>(pHandles[i]), Deleter<VkPipeline>(env.vkd, env.device, env.allocationCallbacks))));
}
return pipelines;
}
static Move<VkPipeline> create (const Environment& env, const Resources& res, const Parameters&)
{
vector<VkPipeline> handles (1, DE_NULL);
VkResult result = VK_NOT_READY;
vector<VkPipelineSp> scopedHandles = createMultiple(env, res, Parameters(), &handles, &result);
VK_CHECK(result);
return Move<VkPipeline>(check<VkPipeline>(scopedHandles.front()->disown()), Deleter<VkPipeline>(env.vkd, env.device, env.allocationCallbacks));
}
};
struct ComputePipeline
{
typedef VkPipeline Type;
// \todo [2015-09-17 pyry] More interesting configurations
struct Parameters
{
Parameters (void) {}
};
struct Resources
{
Dependency<ShaderModule> shaderModule;
Dependency<PipelineLayout> layout;
Dependency<PipelineCache> pipelineCache;
static DescriptorSetLayout::Parameters getDescriptorSetLayout (void)
{
typedef DescriptorSetLayout::Parameters::Binding Binding;
vector<Binding> bindings;
bindings.push_back(Binding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u, VK_SHADER_STAGE_COMPUTE_BIT, false));
bindings.push_back(Binding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u, VK_SHADER_STAGE_COMPUTE_BIT, false));
return DescriptorSetLayout::Parameters(bindings);
}
Resources (const Environment& env, const Parameters&)
: shaderModule (env, ShaderModule::Parameters(VK_SHADER_STAGE_COMPUTE_BIT, "comp"))
, layout (env, PipelineLayout::Parameters::singleDescriptorSet(getDescriptorSetLayout()))
, pipelineCache (env, PipelineCache::Parameters())
{}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<ComputePipeline>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static void initPrograms (SourceCollections& dst, Parameters)
{
ShaderModule::initPrograms(dst, ShaderModule::Parameters(VK_SHADER_STAGE_COMPUTE_BIT, "comp"));
}
static Move<VkPipeline> create (const Environment& env, const Resources& res, const Parameters&)
{
const VkComputePipelineCreateInfo pipelineInfo =
{
VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
DE_NULL,
(VkPipelineCreateFlags)0,
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
DE_NULL,
(VkPipelineShaderStageCreateFlags)0,
VK_SHADER_STAGE_COMPUTE_BIT,
*res.shaderModule.object,
"main",
DE_NULL // pSpecializationInfo
},
*res.layout.object,
(VkPipeline)0, // basePipelineHandle
0u, // basePipelineIndex
};
return createComputePipeline(env.vkd, env.device, *res.pipelineCache.object, &pipelineInfo, env.allocationCallbacks);
}
static vector<VkPipelineSp> createMultiple (const Environment& env, const Resources& res, const Parameters&, vector<VkPipeline>* const pOutHandles, VkResult* const pOutResult)
{
DE_ASSERT(pOutResult);
DE_ASSERT(pOutHandles);
DE_ASSERT(pOutHandles->size() != 0);
const VkComputePipelineCreateInfo commonPipelineInfo =
{
VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
DE_NULL,
(VkPipelineCreateFlags)0,
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
DE_NULL,
(VkPipelineShaderStageCreateFlags)0,
VK_SHADER_STAGE_COMPUTE_BIT,
*res.shaderModule.object,
"main",
DE_NULL // pSpecializationInfo
},
*res.layout.object,
(VkPipeline)0, // basePipelineHandle
0u, // basePipelineIndex
};
const deUint32 numPipelines = static_cast<deUint32>(pOutHandles->size());
VkPipeline* const pHandles = &(*pOutHandles)[0];
vector<VkComputePipelineCreateInfo> pipelineInfos (numPipelines, commonPipelineInfo);
*pOutResult = env.vkd.createComputePipelines(env.device, *res.pipelineCache.object, numPipelines, &pipelineInfos[0], env.allocationCallbacks, pHandles);
vector<VkPipelineSp> pipelines;
// Even if an error is returned, some pipelines may have been created successfully
for (deUint32 i = 0; i < numPipelines; ++i)
{
if (pHandles[i] != DE_NULL)
pipelines.push_back(VkPipelineSp(new Move<VkPipeline>(check<VkPipeline>(pHandles[i]), Deleter<VkPipeline>(env.vkd, env.device, env.allocationCallbacks))));
}
return pipelines;
}
};
struct DescriptorPool
{
typedef VkDescriptorPool Type;
struct Parameters
{
VkDescriptorPoolCreateFlags flags;
deUint32 maxSets;
vector<VkDescriptorPoolSize> poolSizes;
Parameters (VkDescriptorPoolCreateFlags flags_,
deUint32 maxSets_,
const vector<VkDescriptorPoolSize>& poolSizes_)
: flags (flags_)
, maxSets (maxSets_)
, poolSizes (poolSizes_)
{}
static Parameters singleType (VkDescriptorPoolCreateFlags flags,
deUint32 maxSets,
VkDescriptorType type,
deUint32 count)
{
vector<VkDescriptorPoolSize> poolSizes;
poolSizes.push_back(makeDescriptorPoolSize(type, count));
return Parameters(flags, maxSets, poolSizes);
}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<DescriptorPool>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static Move<VkDescriptorPool> create (const Environment& env, const Resources&, const Parameters& params)
{
const VkDescriptorPoolCreateInfo descriptorPoolInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
DE_NULL,
params.flags,
params.maxSets,
(deUint32)params.poolSizes.size(),
(params.poolSizes.empty() ? DE_NULL : &params.poolSizes[0])
};
return createDescriptorPool(env.vkd, env.device, &descriptorPoolInfo, env.allocationCallbacks);
}
};
struct DescriptorSet
{
typedef VkDescriptorSet Type;
struct Parameters
{
DescriptorSetLayout::Parameters descriptorSetLayout;
Parameters (const DescriptorSetLayout::Parameters& descriptorSetLayout_)
: descriptorSetLayout(descriptorSetLayout_)
{}
};
struct Resources
{
Dependency<DescriptorPool> descriptorPool;
Dependency<DescriptorSetLayout> descriptorSetLayout;
static vector<VkDescriptorPoolSize> computePoolSizes (const DescriptorSetLayout::Parameters& layout, int maxSets)
{
deUint32 countByType[VK_DESCRIPTOR_TYPE_LAST];
vector<VkDescriptorPoolSize> typeCounts;
std::fill(DE_ARRAY_BEGIN(countByType), DE_ARRAY_END(countByType), 0u);
for (vector<DescriptorSetLayout::Parameters::Binding>::const_iterator cur = layout.bindings.begin();
cur != layout.bindings.end();
++cur)
{
DE_ASSERT((deUint32)cur->descriptorType < VK_DESCRIPTOR_TYPE_LAST);
countByType[cur->descriptorType] += cur->descriptorCount * maxSets;
}
for (deUint32 type = 0; type < VK_DESCRIPTOR_TYPE_LAST; ++type)
{
if (countByType[type] > 0)
typeCounts.push_back(makeDescriptorPoolSize((VkDescriptorType)type, countByType[type]));
}
return typeCounts;
}
Resources (const Environment& env, const Parameters& params)
: descriptorPool (env, DescriptorPool::Parameters(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, env.maxResourceConsumers, computePoolSizes(params.descriptorSetLayout, env.maxResourceConsumers)))
, descriptorSetLayout (env, params.descriptorSetLayout)
{
}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<DescriptorSet>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static Move<VkDescriptorSet> create (const Environment& env, const Resources& res, const Parameters&)
{
const VkDescriptorSetAllocateInfo allocateInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
*res.descriptorPool.object,
1u,
&res.descriptorSetLayout.object.get(),
};
return allocateDescriptorSet(env.vkd, env.device, &allocateInfo);
}
static vector<VkDescriptorSetSp> createMultiple (const Environment& env, const Resources& res, const Parameters&, vector<VkDescriptorSet>* const pOutHandles, VkResult* const pOutResult)
{
DE_ASSERT(pOutResult);
DE_ASSERT(pOutHandles);
DE_ASSERT(pOutHandles->size() != 0);
const deUint32 numDescriptorSets = static_cast<deUint32>(pOutHandles->size());
VkDescriptorSet* const pHandles = &(*pOutHandles)[0];
const vector<VkDescriptorSetLayout> descriptorSetLayouts (numDescriptorSets, res.descriptorSetLayout.object.get());
const VkDescriptorSetAllocateInfo allocateInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
*res.descriptorPool.object,
numDescriptorSets,
&descriptorSetLayouts[0],
};
*pOutResult = env.vkd.allocateDescriptorSets(env.device, &allocateInfo, pHandles);
vector<VkDescriptorSetSp> descriptorSets;
if (*pOutResult == VK_SUCCESS)
{
for (deUint32 i = 0; i < numDescriptorSets; ++i)
descriptorSets.push_back(VkDescriptorSetSp(new Move<VkDescriptorSet>(check<VkDescriptorSet>(pHandles[i]), Deleter<VkDescriptorSet>(env.vkd, env.device, *res.descriptorPool.object))));
}
return descriptorSets;
}
};
struct Framebuffer
{
typedef VkFramebuffer Type;
struct Parameters
{
Parameters (void)
{}
};
struct Resources
{
Dependency<ImageView> colorAttachment;
Dependency<ImageView> depthStencilAttachment;
Dependency<RenderPass> renderPass;
Resources (const Environment& env, const Parameters&)
: colorAttachment (env, ImageView::Parameters(Image::Parameters(0u, VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM,
makeExtent3D(256, 256, 1),
1u, 1u,
VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
VK_IMAGE_LAYOUT_UNDEFINED),
VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM,
makeComponentMappingRGBA(),
makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)))
, depthStencilAttachment (env, ImageView::Parameters(Image::Parameters(0u, VK_IMAGE_TYPE_2D, VK_FORMAT_D16_UNORM,
makeExtent3D(256, 256, 1),
1u, 1u,
VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
VK_IMAGE_LAYOUT_UNDEFINED),
VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_D16_UNORM,
makeComponentMappingRGBA(),
makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u)))
, renderPass (env, RenderPass::Parameters())
{}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
// \todo [2016-03-23 pyry] Take into account attachment sizes
return getSafeObjectCount<Framebuffer>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static Move<VkFramebuffer> create (const Environment& env, const Resources& res, const Parameters&)
{
const VkImageView attachments[] =
{
*res.colorAttachment.object,
*res.depthStencilAttachment.object,
};
const VkFramebufferCreateInfo framebufferInfo =
{
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
DE_NULL,
(VkFramebufferCreateFlags)0,
*res.renderPass.object,
(deUint32)DE_LENGTH_OF_ARRAY(attachments),
attachments,
256u, // width
256u, // height
1u // layers
};
return createFramebuffer(env.vkd, env.device, &framebufferInfo, env.allocationCallbacks);
}
};
struct CommandPool
{
typedef VkCommandPool Type;
struct Parameters
{
VkCommandPoolCreateFlags flags;
Parameters (VkCommandPoolCreateFlags flags_)
: flags(flags_)
{}
};
struct Resources
{
Resources (const Environment&, const Parameters&) {}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<CommandPool>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static Move<VkCommandPool> create (const Environment& env, const Resources&, const Parameters& params)
{
const VkCommandPoolCreateInfo cmdPoolInfo =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
DE_NULL,
params.flags,
env.queueFamilyIndex,
};
return createCommandPool(env.vkd, env.device, &cmdPoolInfo, env.allocationCallbacks);
}
};
struct CommandBuffer
{
typedef VkCommandBuffer Type;
struct Parameters
{
CommandPool::Parameters commandPool;
VkCommandBufferLevel level;
Parameters (const CommandPool::Parameters& commandPool_,
VkCommandBufferLevel level_)
: commandPool (commandPool_)
, level (level_)
{}
};
struct Resources
{
Dependency<CommandPool> commandPool;
Resources (const Environment& env, const Parameters& params)
: commandPool(env, params.commandPool)
{}
};
static deUint32 getMaxConcurrent (Context& context, const Parameters& params)
{
return getSafeObjectCount<CommandBuffer>(context, params, DEFAULT_MAX_CONCURRENT_OBJECTS);
}
static Move<VkCommandBuffer> create (const Environment& env, const Resources& res, const Parameters& params)
{
const VkCommandBufferAllocateInfo cmdBufferInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
DE_NULL,
*res.commandPool.object,
params.level,
1, // bufferCount
};
return allocateCommandBuffer(env.vkd, env.device, &cmdBufferInfo);
}
static vector<VkCommandBufferSp> createMultiple (const Environment& env, const Resources& res, const Parameters& params, vector<VkCommandBuffer>* const pOutHandles, VkResult* const pOutResult)
{
DE_ASSERT(pOutResult);
DE_ASSERT(pOutHandles);
DE_ASSERT(pOutHandles->size() != 0);
const deUint32 numCommandBuffers = static_cast<deUint32>(pOutHandles->size());
VkCommandBuffer* const pHandles = &(*pOutHandles)[0];
const VkCommandBufferAllocateInfo cmdBufferInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
DE_NULL,
*res.commandPool.object,
params.level,
numCommandBuffers,
};
*pOutResult = env.vkd.allocateCommandBuffers(env.device, &cmdBufferInfo, pHandles);
vector<VkCommandBufferSp> commandBuffers;
if (*pOutResult == VK_SUCCESS)
{
for (deUint32 i = 0; i < numCommandBuffers; ++i)
commandBuffers.push_back(VkCommandBufferSp(new Move<VkCommandBuffer>(check<VkCommandBuffer>(pHandles[i]), Deleter<VkCommandBuffer>(env.vkd, env.device, *res.commandPool.object))));
}
return commandBuffers;
}
};
// Test cases
template<typename Object>
tcu::TestStatus createSingleTest (Context& context, typename Object::Parameters params)
{
const Environment env (context, 1u);
const typename Object::Resources res (env, params);
{
Unique<typename Object::Type> obj (Object::create(env, res, params));
}
return tcu::TestStatus::pass("Ok");
}
template<typename Object>
tcu::TestStatus createMultipleUniqueResourcesTest (Context& context, typename Object::Parameters params)
{
const Environment env (context, 1u);
const typename Object::Resources res0 (env, params);
const typename Object::Resources res1 (env, params);
const typename Object::Resources res2 (env, params);
const typename Object::Resources res3 (env, params);
{
Unique<typename Object::Type> obj0 (Object::create(env, res0, params));
Unique<typename Object::Type> obj1 (Object::create(env, res1, params));
Unique<typename Object::Type> obj2 (Object::create(env, res2, params));
Unique<typename Object::Type> obj3 (Object::create(env, res3, params));
}
return tcu::TestStatus::pass("Ok");
}
template<typename Object>
tcu::TestStatus createMultipleSharedResourcesTest (Context& context, typename Object::Parameters params)
{
const Environment env (context, 4u);
const typename Object::Resources res (env, params);
{
Unique<typename Object::Type> obj0 (Object::create(env, res, params));
Unique<typename Object::Type> obj1 (Object::create(env, res, params));
Unique<typename Object::Type> obj2 (Object::create(env, res, params));
Unique<typename Object::Type> obj3 (Object::create(env, res, params));
}
return tcu::TestStatus::pass("Ok");
}
template<typename Object>
tcu::TestStatus createMaxConcurrentTest (Context& context, typename Object::Parameters params)
{
typedef Unique<typename Object::Type> UniqueObject;
typedef SharedPtr<UniqueObject> ObjectPtr;
const deUint32 numObjects = Object::getMaxConcurrent(context, params);
const Environment env (context, numObjects);
const typename Object::Resources res (env, params);
vector<ObjectPtr> objects (numObjects);
const deUint32 watchdogInterval = 1024;
context.getTestContext().getLog()
<< TestLog::Message << "Creating " << numObjects << " " << getTypeName<typename Object::Type>() << " objects" << TestLog::EndMessage;
for (deUint32 ndx = 0; ndx < numObjects; ndx++)
{
objects[ndx] = ObjectPtr(new UniqueObject(Object::create(env, res, params)));
if ((ndx > 0) && ((ndx % watchdogInterval) == 0))
context.getTestContext().touchWatchdog();
}
context.getTestContext().touchWatchdog();
objects.clear();
return tcu::TestStatus::pass("Ok");
}
// How many objects to create per thread
template<typename Object> int getCreateCount (void) { return 100; }
// Creating VkDevice and VkInstance can take significantly longer than other object types
template<> int getCreateCount<Instance> (void) { return 20; }
template<> int getCreateCount<Device> (void) { return 20; }
template<> int getCreateCount<DeviceGroup> (void) { return 20; }
template<typename Object>
class CreateThread : public ThreadGroupThread
{
public:
CreateThread (const Environment& env, const typename Object::Resources& resources, const typename Object::Parameters& params)
: m_env (env)
, m_resources (resources)
, m_params (params)
{}
void runThread (void)
{
const int numIters = getCreateCount<Object>();
const int itersBetweenSyncs = numIters / 5;
DE_ASSERT(itersBetweenSyncs > 0);
for (int iterNdx = 0; iterNdx < numIters; iterNdx++)
{
// Sync every Nth iteration to make entering driver at the same time more likely
if ((iterNdx % itersBetweenSyncs) == 0)
barrier();
{
Unique<typename Object::Type> obj (Object::create(m_env, m_resources, m_params));
}
}
}
private:
const Environment& m_env;
const typename Object::Resources& m_resources;
const typename Object::Parameters& m_params;
};
template<typename Object>
tcu::TestStatus multithreadedCreateSharedResourcesTest (Context& context, typename Object::Parameters params)
{
TestLog& log = context.getTestContext().getLog();
const deUint32 numThreads = getDefaultTestThreadCount();
const Environment env (context, numThreads);
const typename Object::Resources res (env, params);
ThreadGroup threads;
log << TestLog::Message << "numThreads = " << numThreads << TestLog::EndMessage;
for (deUint32 ndx = 0; ndx < numThreads; ndx++)
threads.add(MovePtr<ThreadGroupThread>(new CreateThread<Object>(env, res, params)));
return threads.run();
}
template<typename Object>
tcu::TestStatus multithreadedCreatePerThreadResourcesTest (Context& context, typename Object::Parameters params)
{
typedef SharedPtr<typename Object::Resources> ResPtr;
TestLog& log = context.getTestContext().getLog();
const deUint32 numThreads = getDefaultTestThreadCount();
const Environment env (context, 1u);
vector<ResPtr> resources (numThreads);
ThreadGroup threads;
log << TestLog::Message << "numThreads = " << numThreads << TestLog::EndMessage;
for (deUint32 ndx = 0; ndx < numThreads; ndx++)
{
resources[ndx] = ResPtr(new typename Object::Resources(env, params));
threads.add(MovePtr<ThreadGroupThread>(new CreateThread<Object>(env, *resources[ndx], params)));
}
return threads.run();
}
struct EnvClone
{
Device::Resources deviceRes;
Unique<VkDevice> device;
DeviceDriver vkd;
Environment env;
EnvClone (const Environment& parent, const Device::Parameters& deviceParams, deUint32 maxResourceConsumers)
: deviceRes (parent, deviceParams)
, device (Device::create(parent, deviceRes, deviceParams))
, vkd (parent.vkp, parent.instance, *device)
, env (parent.vkp, parent.apiVersion, parent.instanceInterface, parent.instance, vkd, *device, deviceRes.queueFamilyIndex, parent.programBinaries, parent.allocationCallbacks, maxResourceConsumers, parent.commandLine)
{
}
};
Device::Parameters getDefaulDeviceParameters (Context& context)
{
return Device::Parameters(context.getTestContext().getCommandLine().getVKDeviceId()-1u,
VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT);
}
template<typename Object>
tcu::TestStatus multithreadedCreatePerThreadDeviceTest (Context& context, typename Object::Parameters params)
{
typedef SharedPtr<EnvClone> EnvPtr;
typedef SharedPtr<typename Object::Resources> ResPtr;
TestLog& log = context.getTestContext().getLog();
const deUint32 numThreads = getDefaultTestThreadCount();
const Device::Parameters deviceParams = getDefaulDeviceParameters(context);
const Environment sharedEnv (context, numThreads); // For creating Device's
vector<EnvPtr> perThreadEnv (numThreads);
vector<ResPtr> resources (numThreads);
ThreadGroup threads;
log << TestLog::Message << "numThreads = " << numThreads << TestLog::EndMessage;
for (deUint32 ndx = 0; ndx < numThreads; ndx++)
{
perThreadEnv[ndx] = EnvPtr(new EnvClone(sharedEnv, deviceParams, 1u));
resources[ndx] = ResPtr(new typename Object::Resources(perThreadEnv[ndx]->env, params));
threads.add(MovePtr<ThreadGroupThread>(new CreateThread<Object>(perThreadEnv[ndx]->env, *resources[ndx], params)));
}
return threads.run();
}
template<typename Object>
tcu::TestStatus createSingleAllocCallbacksTest (Context& context, typename Object::Parameters params)
{
const deUint32 noCmdScope = (1u << VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)
| (1u << VK_SYSTEM_ALLOCATION_SCOPE_DEVICE)
| (1u << VK_SYSTEM_ALLOCATION_SCOPE_CACHE)
| (1u << VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
// Callbacks used by resources
AllocationCallbackRecorder resCallbacks (getSystemAllocator(), 128);
// Root environment still uses default instance and device, created without callbacks
const Environment rootEnv (context.getPlatformInterface(),
context.getUsedApiVersion(),
context.getInstanceInterface(),
context.getInstance(),
context.getDeviceInterface(),
context.getDevice(),
context.getUniversalQueueFamilyIndex(),
context.getBinaryCollection(),
resCallbacks.getCallbacks(),
1u,
context.getTestContext().getCommandLine());
{
// Test env has instance & device created with callbacks
const EnvClone resEnv (rootEnv, getDefaulDeviceParameters(context), 1u);
const typename Object::Resources res (resEnv.env, params);
// Supply a separate callback recorder just for object construction
AllocationCallbackRecorder objCallbacks(getSystemAllocator(), 128);
const Environment objEnv (resEnv.env.vkp,
resEnv.env.apiVersion,
resEnv.env.instanceInterface,
resEnv.env.instance,
resEnv.env.vkd,
resEnv.env.device,
resEnv.env.queueFamilyIndex,
resEnv.env.programBinaries,
objCallbacks.getCallbacks(),
resEnv.env.maxResourceConsumers,
resEnv.env.commandLine);
{
Unique<typename Object::Type> obj (Object::create(objEnv, res, params));
// Validate that no command-level allocations are live
if (!validateAndLog(context.getTestContext().getLog(), objCallbacks, noCmdScope))
return tcu::TestStatus::fail("Invalid allocation callback");
}
// At this point all allocations made against object callbacks must have been freed
if (!validateAndLog(context.getTestContext().getLog(), objCallbacks, 0u))
return tcu::TestStatus::fail("Invalid allocation callback");
}
if (!validateAndLog(context.getTestContext().getLog(), resCallbacks, 0u))
return tcu::TestStatus::fail("Invalid allocation callback");
return tcu::TestStatus::pass("Ok");
}
template<typename Object> deUint32 getOomIterLimit (void) { return 1024; }
template<> deUint32 getOomIterLimit<Device> (void) { return 20; }
template<> deUint32 getOomIterLimit<DeviceGroup> (void) { return 20; }
template<typename Object>
tcu::TestStatus allocCallbackFailTest (Context& context, typename Object::Parameters params)
{
AllocationCallbackRecorder resCallbacks (getSystemAllocator(), 128);
const Environment rootEnv (context.getPlatformInterface(),
context.getUsedApiVersion(),
context.getInstanceInterface(),
context.getInstance(),
context.getDeviceInterface(),
context.getDevice(),
context.getUniversalQueueFamilyIndex(),
context.getBinaryCollection(),
resCallbacks.getCallbacks(),
1u,
context.getTestContext().getCommandLine());
deUint32 numPassingAllocs = 0;
const deUint32 cmdLineIterCount = (deUint32)context.getTestContext().getCommandLine().getTestIterationCount();
const deUint32 maxTries = cmdLineIterCount != 0 ? cmdLineIterCount : getOomIterLimit<Object>();
{
const EnvClone resEnv (rootEnv, getDefaulDeviceParameters(context), 1u);
const typename Object::Resources res (resEnv.env, params);
// Iterate over test until object allocation succeeds
for (; numPassingAllocs < maxTries; ++numPassingAllocs)
{
DeterministicFailAllocator objAllocator(getSystemAllocator(),
DeterministicFailAllocator::MODE_COUNT_AND_FAIL,
numPassingAllocs);
AllocationCallbackRecorder recorder (objAllocator.getCallbacks(), 128);
const Environment objEnv (resEnv.env.vkp,
resEnv.env.apiVersion,
resEnv.env.instanceInterface,
resEnv.env.instance,
resEnv.env.vkd,
resEnv.env.device,
resEnv.env.queueFamilyIndex,
resEnv.env.programBinaries,
recorder.getCallbacks(),
resEnv.env.maxResourceConsumers,
resEnv.env.commandLine);
bool createOk = false;
context.getTestContext().getLog()
<< TestLog::Message
<< "Trying to create object with " << numPassingAllocs << " allocation" << (numPassingAllocs != 1 ? "s" : "") << " passing"
<< TestLog::EndMessage;
try
{
Unique<typename Object::Type> obj (Object::create(objEnv, res, params));
createOk = true;
}
catch (const vk::OutOfMemoryError& e)
{
if (e.getError() != VK_ERROR_OUT_OF_HOST_MEMORY)
{
context.getTestContext().getLog() << e;
return tcu::TestStatus::fail("Got invalid error code");
}
}
if (!validateAndLog(context.getTestContext().getLog(), recorder, 0u))
return tcu::TestStatus::fail("Invalid allocation callback");
if (createOk)
{
context.getTestContext().getLog()
<< TestLog::Message << "Object construction succeeded! " << TestLog::EndMessage;
break;
}
}
}
if (!validateAndLog(context.getTestContext().getLog(), resCallbacks, 0u))
return tcu::TestStatus::fail("Invalid allocation callback");
if (numPassingAllocs == 0)
return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks not called");
else if (numPassingAllocs == maxTries)
{
context.getTestContext().getLog()
<< TestLog::Message << "WARNING: Maximum iteration count (" << maxTries << ") reached without object construction passing. "
<< "OOM testing incomplete, use --deqp-test-iteration-count= to test with higher limit." << TestLog::EndMessage;
return tcu::TestStatus(QP_TEST_RESULT_PASS, "Max iter count reached");
}
else
return tcu::TestStatus::pass("Ok");
}
// Determine whether an API call sets the invalid handles to NULL (true) or leaves them undefined or not modified (false)
template<typename T> inline bool isNullHandleOnAllocationFailure (Context&) { return false; }
template<> inline bool isNullHandleOnAllocationFailure<VkCommandBuffer> (Context& context) { return hasDeviceExtension(context, "VK_KHR_maintenance1"); }
template<> inline bool isNullHandleOnAllocationFailure<VkDescriptorSet> (Context& context) { return hasDeviceExtension(context, "VK_KHR_maintenance1"); }
template<> inline bool isNullHandleOnAllocationFailure<VkPipeline> (Context&) { return true; }
template<typename T> inline bool isPooledObject (void) { return false; };
template<> inline bool isPooledObject<VkCommandBuffer> (void) { return true; };
template<> inline bool isPooledObject<VkDescriptorSet> (void) { return true; };
template<typename Object>
tcu::TestStatus allocCallbackFailMultipleObjectsTest (Context& context, typename Object::Parameters params)
{
typedef SharedPtr<Move<typename Object::Type> > ObjectTypeSp;
static const deUint32 numObjects = 4;
const bool expectNullHandles = isNullHandleOnAllocationFailure<typename Object::Type>(context);
deUint32 numPassingAllocs = 0;
{
vector<typename Object::Type> handles (numObjects);
VkResult result = VK_NOT_READY;
for (; numPassingAllocs <= numObjects; ++numPassingAllocs)
{
ValidateQueryBits::fillBits(handles.begin(), handles.end()); // fill with garbage
// \note We have to use the same allocator for both resource dependencies and the object under test,
// because pooled objects take memory from the pool.
DeterministicFailAllocator objAllocator(getSystemAllocator(), DeterministicFailAllocator::MODE_DO_NOT_COUNT, 0);
AllocationCallbackRecorder recorder (objAllocator.getCallbacks(), 128);
const Environment objEnv (context.getPlatformInterface(),
context.getUsedApiVersion(),
context.getInstanceInterface(),
context.getInstance(),
context.getDeviceInterface(),
context.getDevice(),
context.getUniversalQueueFamilyIndex(),
context.getBinaryCollection(),
recorder.getCallbacks(),
numObjects,
context.getTestContext().getCommandLine());
context.getTestContext().getLog()
<< TestLog::Message
<< "Trying to create " << numObjects << " objects with " << numPassingAllocs << " allocation" << (numPassingAllocs != 1 ? "s" : "") << " passing"
<< TestLog::EndMessage;
{
const typename Object::Resources res (objEnv, params);
objAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
const vector<ObjectTypeSp> scopedHandles = Object::createMultiple(objEnv, res, params, &handles, &result);
}
if (result == VK_SUCCESS)
{
context.getTestContext().getLog() << TestLog::Message << "Construction of all objects succeeded! " << TestLog::EndMessage;
break;
}
else
{
if (expectNullHandles)
{
for (deUint32 nullNdx = numPassingAllocs; nullNdx < numObjects; ++nullNdx)
{
if (handles[nullNdx] != DE_NULL)
return tcu::TestStatus::fail("Some object handles weren't set to NULL");
}
}
if (result != VK_ERROR_OUT_OF_HOST_MEMORY)
return tcu::TestStatus::fail("Got invalid error code: " + de::toString(getResultName(result)));
if (!validateAndLog(context.getTestContext().getLog(), recorder, 0u))
return tcu::TestStatus::fail("Invalid allocation callback");
}
}
}
if (numPassingAllocs == 0)
{
if (isPooledObject<typename Object::Type>())
return tcu::TestStatus::pass("Not validated: pooled objects didn't seem to use host memory");
else
return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks not called");
}
else
return tcu::TestStatus::pass("Ok");
}
// Utilities for creating groups
template<typename Object>
struct NamedParameters
{
const char* name;
typename Object::Parameters parameters;
};
template<typename Object>
struct CaseDescription
{
typename FunctionInstance1<typename Object::Parameters>::Function function;
const NamedParameters<Object>* paramsBegin;
const NamedParameters<Object>* paramsEnd;
};
#define EMPTY_CASE_DESC(OBJECT) \
{ (FunctionInstance1<OBJECT::Parameters>::Function)DE_NULL, DE_NULL, DE_NULL }
#define CASE_DESC(FUNCTION, CASES) \
{ FUNCTION, DE_ARRAY_BEGIN(CASES), DE_ARRAY_END(CASES) }
struct CaseDescriptions
{
CaseDescription<Instance> instance;
CaseDescription<Device> device;
CaseDescription<DeviceGroup> deviceGroup;
CaseDescription<DeviceMemory> deviceMemory;
CaseDescription<Buffer> buffer;
CaseDescription<BufferView> bufferView;
CaseDescription<Image> image;
CaseDescription<ImageView> imageView;
CaseDescription<Semaphore> semaphore;
CaseDescription<Event> event;
CaseDescription<Fence> fence;
CaseDescription<QueryPool> queryPool;
CaseDescription<ShaderModule> shaderModule;
CaseDescription<PipelineCache> pipelineCache;
CaseDescription<PipelineLayout> pipelineLayout;
CaseDescription<RenderPass> renderPass;
CaseDescription<GraphicsPipeline> graphicsPipeline;
CaseDescription<ComputePipeline> computePipeline;
CaseDescription<DescriptorSetLayout> descriptorSetLayout;
CaseDescription<Sampler> sampler;
CaseDescription<DescriptorPool> descriptorPool;
CaseDescription<DescriptorSet> descriptorSet;
CaseDescription<Framebuffer> framebuffer;
CaseDescription<CommandPool> commandPool;
CaseDescription<CommandBuffer> commandBuffer;
};
template<typename Object>
void addCases (const MovePtr<tcu::TestCaseGroup>& group, const CaseDescription<Object>& cases)
{
for (const NamedParameters<Object>* cur = cases.paramsBegin; cur != cases.paramsEnd; ++cur)
addFunctionCase(group.get(), cur->name, "", cases.function, cur->parameters);
}
template<typename Object>
void addCasesWithProgs (const MovePtr<tcu::TestCaseGroup>& group, const CaseDescription<Object>& cases)
{
for (const NamedParameters<Object>* cur = cases.paramsBegin; cur != cases.paramsEnd; ++cur)
addFunctionCaseWithPrograms(group.get(), cur->name, "", Object::initPrograms, cases.function, cur->parameters);
}
tcu::TestCaseGroup* createGroup (tcu::TestContext& testCtx, const char* name, const char* desc, const CaseDescriptions& cases)
{
MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, name, desc));
addCases (group, cases.instance);
addCases (group, cases.device);
addCases (group, cases.deviceGroup);
addCases (group, cases.deviceMemory);
addCases (group, cases.buffer);
addCases (group, cases.bufferView);
addCases (group, cases.image);
addCases (group, cases.imageView);
addCases (group, cases.semaphore);
addCases (group, cases.event);
addCases (group, cases.fence);
addCases (group, cases.queryPool);
addCases (group, cases.sampler);
addCasesWithProgs (group, cases.shaderModule);
addCases (group, cases.pipelineCache);
addCases (group, cases.pipelineLayout);
addCases (group, cases.renderPass);
addCasesWithProgs (group, cases.graphicsPipeline);
addCasesWithProgs (group, cases.computePipeline);
addCases (group, cases.descriptorSetLayout);
addCases (group, cases.descriptorPool);
addCases (group, cases.descriptorSet);
addCases (group, cases.framebuffer);
addCases (group, cases.commandPool);
addCases (group, cases.commandBuffer);
return group.release();
}
} // anonymous
tcu::TestCaseGroup* createObjectManagementTests (tcu::TestContext& testCtx)
{
MovePtr<tcu::TestCaseGroup> objectMgmtTests (new tcu::TestCaseGroup(testCtx, "object_management", "Object management tests"));
const Image::Parameters img1D (0u, VK_IMAGE_TYPE_1D, VK_FORMAT_R8G8B8A8_UNORM, makeExtent3D(256, 1, 1), 1u, 4u, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_UNDEFINED);
const Image::Parameters img2D (0u, VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, makeExtent3D( 64, 64, 1), 1u, 12u, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_UNDEFINED);
const Image::Parameters imgCube (VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, makeExtent3D( 64, 64, 1), 1u, 12u, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_UNDEFINED);
const Image::Parameters img3D (0u, VK_IMAGE_TYPE_3D, VK_FORMAT_R8G8B8A8_UNORM, makeExtent3D( 64, 64, 4), 1u, 1u, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_UNDEFINED);
const ImageView::Parameters imgView1D (img1D, VK_IMAGE_VIEW_TYPE_1D, img1D.format, makeComponentMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
const ImageView::Parameters imgView1DArr (img1D, VK_IMAGE_VIEW_TYPE_1D_ARRAY, img1D.format, makeComponentMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 4u));
const ImageView::Parameters imgView2D (img2D, VK_IMAGE_VIEW_TYPE_2D, img2D.format, makeComponentMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
const ImageView::Parameters imgView2DArr (img2D, VK_IMAGE_VIEW_TYPE_2D_ARRAY, img2D.format, makeComponentMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 8u));
const ImageView::Parameters imgViewCube (imgCube, VK_IMAGE_VIEW_TYPE_CUBE, img2D.format, makeComponentMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 6u));
const ImageView::Parameters imgViewCubeArr (imgCube, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, img2D.format, makeComponentMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 12u));
const ImageView::Parameters imgView3D (img3D, VK_IMAGE_VIEW_TYPE_3D, img3D.format, makeComponentMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
const DescriptorSetLayout::Parameters singleUboDescLayout = DescriptorSetLayout::Parameters::single(0u, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u, VK_SHADER_STAGE_VERTEX_BIT);
static const NamedParameters<Instance> s_instanceCases[] =
{
{ "instance", Instance::Parameters() },
};
// \note Device index may change - must not be static
const NamedParameters<Device> s_deviceCases[] =
{
{ "device", Device::Parameters(testCtx.getCommandLine().getVKDeviceId()-1u, VK_QUEUE_GRAPHICS_BIT) },
};
const NamedParameters<DeviceGroup> s_deviceGroupCases[] =
{
{ "device_group", DeviceGroup::Parameters(testCtx.getCommandLine().getVKDeviceGroupId() - 1u, testCtx.getCommandLine().getVKDeviceId() - 1u, VK_QUEUE_GRAPHICS_BIT) },
};
static const NamedParameters<DeviceMemory> s_deviceMemCases[] =
{
{ "device_memory_small", DeviceMemory::Parameters(1024, 0u) },
};
static const NamedParameters<Buffer> s_bufferCases[] =
{
{ "buffer_uniform_small", Buffer::Parameters(1024u, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT), },
{ "buffer_uniform_large", Buffer::Parameters(1024u*1024u*16u, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT), },
{ "buffer_storage_small", Buffer::Parameters(1024u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), },
{ "buffer_storage_large", Buffer::Parameters(1024u*1024u*16u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), },
};
static const NamedParameters<BufferView> s_bufferViewCases[] =
{
{ "buffer_view_uniform_r8g8b8a8_unorm", BufferView::Parameters(Buffer::Parameters(8192u, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT), VK_FORMAT_R8G8B8A8_UNORM, 0u, 4096u) },
{ "buffer_view_storage_r8g8b8a8_unorm", BufferView::Parameters(Buffer::Parameters(8192u, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT), VK_FORMAT_R8G8B8A8_UNORM, 0u, 4096u) },
};
static const NamedParameters<Image> s_imageCases[] =