blob: 0f5a6d715d04c6ce90564ad3d69e8a46f59850aa [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 "vkObjTypeImpl.inl"
#include "vkObjUtil.hpp"
#include "vktTestGroupUtil.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>
#include <algorithm>
#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");
}
// Class to wrap singleton devices used by private_data tests
class SingletonDevice
{
Move<VkDevice> createPrivateDataDevice(const Context &context, int idx)
{
const int requestedSlots[NUM_DEVICES][2] =
{
{0, 0},
{1, 0},
{1, 1},
{4, 4},
{1, 100},
};
const float queuePriority = 1.0;
const VkDeviceQueueCreateInfo queues[] =
{
{
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
DE_NULL,
(VkDeviceQueueCreateFlags)0,
context.getUniversalQueueFamilyIndex(),
1u, // queueCount
&queuePriority, // pQueuePriorities
}
};
VkDevicePrivateDataCreateInfoEXT pdci0 =
{
VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // uint32_t privateDataSlotRequestCount;
};
VkDevicePrivateDataCreateInfoEXT pdci1 =
{
VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // uint32_t privateDataSlotRequestCount;
};
void *pNext = DE_NULL;
if (requestedSlots[idx][0])
{
pNext = &pdci0;
pdci0.privateDataSlotRequestCount = requestedSlots[idx][0];
if (requestedSlots[idx][1])
{
pdci0.pNext = &pdci1;
pdci1.privateDataSlotRequestCount = requestedSlots[idx][1];
}
}
VkPhysicalDevicePrivateDataFeaturesEXT privateDataFeatures =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT, // VkStructureType sType;
pNext, // void* pNext;
VK_TRUE, // VkBool32 privateData;
};
pNext = &privateDataFeatures;
const char *extName = "VK_EXT_private_data";
const VkDeviceCreateInfo deviceInfo =
{
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
pNext,
(VkDeviceCreateFlags)0,
DE_LENGTH_OF_ARRAY(queues),
queues,
0u, // enabledLayerNameCount
DE_NULL, // ppEnabledLayerNames
1u, // enabledExtensionNameCount
&extName, // ppEnabledExtensionNames
DE_NULL, // pEnabledFeatures
};
Move<VkDevice> device = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(),
context.getPlatformInterface(), context.getInstance(), context.getInstanceInterface(), context.getPhysicalDevice(), &deviceInfo, DE_NULL);
return device;
}
SingletonDevice (const Context& context, int idx)
: m_logicalDevice (createPrivateDataDevice(context, idx))
{
}
public:
static const int NUM_DEVICES = 5;
static const Unique<vk::VkDevice>& getDevice(const Context& context, int idx)
{
if (!m_singletonDevice[idx])
m_singletonDevice[idx] = SharedPtr<SingletonDevice>(new SingletonDevice(context, idx));
DE_ASSERT(m_singletonDevice[idx]);
return m_singletonDevice[idx]->m_logicalDevice;
}
static void destroy()
{
for (int idx = 0; idx < NUM_DEVICES; ++idx)
m_singletonDevice[idx].clear();
}
private:
const Unique<vk::VkDevice> m_logicalDevice;
static SharedPtr<SingletonDevice> m_singletonDevice[NUM_DEVICES];
};
SharedPtr<SingletonDevice> SingletonDevice::m_singletonDevice[NUM_DEVICES];
template<typename T> static deUint64 HandleToInt(T t) { return t.getInternal(); }
template<typename T> static deUint64 HandleToInt(T *t) { return (deUint64)(deUintptr)(t); }
template<typename Object>
tcu::TestStatus createPrivateDataTest (Context& context, typename Object::Parameters params)
{
if (!context.getPrivateDataFeaturesEXT().privateData)
TCU_THROW(NotSupportedError, "privateData not supported");
for (int d = 0; d < SingletonDevice::NUM_DEVICES; ++d)
{
const Unique<vk::VkDevice>& device = SingletonDevice::getDevice(context, d);
const Environment env (context.getPlatformInterface(),
context.getUsedApiVersion(),
context.getInstanceInterface(),
context.getInstance(),
context.getDeviceInterface(),
*device,
context.getUniversalQueueFamilyIndex(),
context.getBinaryCollection(),
DE_NULL,
4u,
context.getTestContext().getCommandLine());
const typename Object::Resources res (env, params);
const VkPrivateDataSlotCreateInfoEXT createInfo =
{
VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPrivateDataSlotCreateFlagsEXT flags;
};
const int numSlots = 100;
typedef Unique<VkPrivateDataSlotEXT> PrivateDataSlotUp;
typedef SharedPtr<PrivateDataSlotUp> PrivateDataSlotSp;
vector<PrivateDataSlotSp> slots;
// interleave allocating objects and slots
for (int i = 0; i < numSlots / 2; ++i)
{
Move<VkPrivateDataSlotEXT> s = createPrivateDataSlotEXT(env.vkd, *device, &createInfo, DE_NULL);
slots.push_back(PrivateDataSlotSp(new PrivateDataSlotUp(s)));
}
Unique<typename Object::Type> obj0 (Object::create(env, res, params));
Unique<typename Object::Type> obj1 (Object::create(env, res, params));
for (int i = numSlots / 2; i < numSlots; ++i)
{
Move<VkPrivateDataSlotEXT> s = createPrivateDataSlotEXT(env.vkd, *device, &createInfo, DE_NULL);
slots.push_back(PrivateDataSlotSp(new PrivateDataSlotUp(s)));
}
Unique<typename Object::Type> obj2 (Object::create(env, res, params));
Unique<typename Object::Type> obj3 (Object::create(env, res, params));
Unique<typename Object::Type> *objs[4] = { &obj0, &obj1, &obj2, &obj3 };
for (int r = 0; r < 3; ++r)
{
deUint64 data;
// Test private data for the objects
for (int o = 0; o < 4; ++o)
{
auto &obj = *objs[o];
for (int i = 0; i < numSlots; ++i)
{
data = 1234;
env.vkd.getPrivateDataEXT(*device, getObjectType<typename Object::Type>(), HandleToInt(obj.get()), **slots[i], &data);
if (data != 0)
return tcu::TestStatus::fail("Expected initial value of zero");
}
}
for (int o = 0; o < 4; ++o)
{
auto &obj = *objs[o];
for (int i = 0; i < numSlots; ++i)
VK_CHECK(env.vkd.setPrivateDataEXT(*device, getObjectType<typename Object::Type>(), HandleToInt(obj.get()), **slots[i], i*i*i + o*o + 1));
}
for (int o = 0; o < 4; ++o)
{
auto &obj = *objs[o];
for (int i = 0; i < numSlots; ++i)
{
data = 1234;
env.vkd.getPrivateDataEXT(*device, getObjectType<typename Object::Type>(), HandleToInt(obj.get()), **slots[i], &data);
if (data != (deUint64)(i*i*i + o*o + 1))
return tcu::TestStatus::fail("Didn't read back set value");
}
}
// Test private data for the private data objects
for (int o = 0; o < numSlots; ++o)
{
auto &obj = **slots[o];
for (int i = 0; i < numSlots; ++i)
{
data = 1234;
env.vkd.getPrivateDataEXT(*device, VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT, HandleToInt<VkPrivateDataSlotEXT>(obj), **slots[i], &data);
if (data != 0)
return tcu::TestStatus::fail("Expected initial value of zero");
}
}
for (int o = 0; o < numSlots; ++o)
{
auto &obj = **slots[o];
for (int i = 0; i < numSlots; ++i)
VK_CHECK(env.vkd.setPrivateDataEXT(*device, VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT, HandleToInt<VkPrivateDataSlotEXT>(obj), **slots[i], i*i*i + o*o + 1));
}
for (int o = 0; o < numSlots; ++o)
{
auto &obj = **slots[o];
for (int i = 0; i < numSlots; ++i)
{
data = 1234;
env.vkd.getPrivateDataEXT(*device, VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT, HandleToInt<VkPrivateDataSlotEXT>(obj), **slots[i], &data);
if (data != (deUint64)(i*i*i + o*o + 1))
return tcu::TestStatus::fail("Didn't read back set value");
}
}
// Test private data for the device
for (int i = 0; i < numSlots; ++i)
{
data = 1234;
env.vkd.getPrivateDataEXT(*device, VK_OBJECT_TYPE_DEVICE, (deUint64)(deUintptr)(*device), **slots[i], &data);
if (data != 0)
return tcu::TestStatus::fail("Expected initial value of zero for device");
}
for (int i = 0; i < numSlots; ++i)
VK_CHECK(env.vkd.setPrivateDataEXT(*device, VK_OBJECT_TYPE_DEVICE, (deUint64)(deUintptr)(*device), **slots[i], i*i*i + r*r + 1));
for (int i = 0; i < numSlots; ++i)
{
data = 1234;
env.vkd.getPrivateDataEXT(*device, VK_OBJECT_TYPE_DEVICE, (deUint64)(deUintptr)(*device), **slots[i], &data);
if (data != (deUint64)(i*i*i + r*r + 1))
return tcu::TestStatus::fail("Didn't read back set value from device");
}
// Destroy and realloc slots for the next iteration
slots.clear();
for (int i = 0; i < numSlots; ++i)
{
Move<VkPrivateDataSlotEXT> s = createPrivateDataSlotEXT(env.vkd, *device, &createInfo, DE_NULL);
slots.push_back(PrivateDataSlotSp(new PrivateDataSlotUp(s)));
}
}
}
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));