1/*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Vulkan test case base classes
22 *//*--------------------------------------------------------------------*/
23
24#include "vktTestCase.hpp"
25
26#include "vkRef.hpp"
27#include "vkRefUtil.hpp"
28#include "vkQueryUtil.hpp"
29#include "vkDeviceUtil.hpp"
30#include "vkMemUtil.hpp"
31#include "vkPlatform.hpp"
32#include "vkDebugReportUtil.hpp"
33
34#include "tcuCommandLine.hpp"
35
36#include "deSTLUtil.hpp"
37#include "deMemory.h"
38
39namespace vkt
40{
41
42// Default device utilities
43
44using std::vector;
45using std::string;
46using namespace vk;
47
48namespace
49{
50
51vector<string> getValidationLayers (const vector<VkLayerProperties>& supportedLayers)
52{
53	static const char*	s_magicLayer		= "VK_LAYER_LUNARG_standard_validation";
54	static const char*	s_defaultLayers[]	=
55	{
56		"VK_LAYER_GOOGLE_threading",
57		"VK_LAYER_LUNARG_parameter_validation",
58		"VK_LAYER_LUNARG_device_limits",
59		"VK_LAYER_LUNARG_object_tracker",
60		"VK_LAYER_LUNARG_image",
61		"VK_LAYER_LUNARG_core_validation",
62		"VK_LAYER_LUNARG_swapchain",
63		"VK_LAYER_GOOGLE_unique_objects"
64	};
65
66	vector<string>		enabledLayers;
67
68	if (isLayerSupported(supportedLayers, RequiredLayer(s_magicLayer)))
69		enabledLayers.push_back(s_magicLayer);
70	else
71	{
72		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_defaultLayers); ++ndx)
73		{
74			if (isLayerSupported(supportedLayers, RequiredLayer(s_defaultLayers[ndx])))
75				enabledLayers.push_back(s_defaultLayers[ndx]);
76		}
77	}
78
79	return enabledLayers;
80}
81
82vector<string> getValidationLayers (const PlatformInterface& vkp)
83{
84	return getValidationLayers(enumerateInstanceLayerProperties(vkp));
85}
86
87vector<string> getValidationLayers (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
88{
89	return getValidationLayers(enumerateDeviceLayerProperties(vki, physicalDevice));
90}
91
92vector<string> filterExtensions(const vector<VkExtensionProperties>& deviceExtensions)
93{
94	vector<string>	enabledExtensions;
95	const char*		extensionGroups[] =
96	{
97		"VK_KHR_",
98		"VK_EXT_",
99		"VK_KHX_"
100	};
101
102	for (size_t deviceExtNdx = 0; deviceExtNdx < deviceExtensions.size(); deviceExtNdx++)
103	{
104		for (int extGroupNdx = 0; extGroupNdx < DE_LENGTH_OF_ARRAY(extensionGroups); extGroupNdx++)
105		{
106			if (deStringBeginsWith(deviceExtensions[deviceExtNdx].extensionName, extensionGroups[extGroupNdx]))
107				enabledExtensions.push_back(deviceExtensions[deviceExtNdx].extensionName);
108		}
109	}
110
111	return enabledExtensions;
112}
113
114Move<VkInstance> createInstance (const PlatformInterface& vkp, const vector<string>& enabledExtensions, const tcu::CommandLine& cmdLine)
115{
116	const bool							isValidationEnabled	= cmdLine.isValidationEnabled();
117	vector<string>						enabledLayers;
118
119	if (isValidationEnabled)
120	{
121		if (!isDebugReportSupported(vkp))
122			TCU_THROW(NotSupportedError, "VK_EXT_debug_report is not supported");
123
124		enabledLayers = getValidationLayers(vkp);
125		if (enabledLayers.empty())
126			TCU_THROW(NotSupportedError, "No validation layers found");
127	}
128
129	return createDefaultInstance(vkp, enabledLayers, enabledExtensions);
130}
131
132static deUint32 findQueueFamilyIndexWithCaps (const InstanceInterface& vkInstance, VkPhysicalDevice physicalDevice, VkQueueFlags requiredCaps)
133{
134	const vector<VkQueueFamilyProperties>	queueProps	= getPhysicalDeviceQueueFamilyProperties(vkInstance, physicalDevice);
135
136	for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
137	{
138		if ((queueProps[queueNdx].queueFlags & requiredCaps) == requiredCaps)
139			return (deUint32)queueNdx;
140	}
141
142	TCU_THROW(NotSupportedError, "No matching queue found");
143}
144
145Move<VkDevice> createDefaultDevice (const InstanceInterface&			vki,
146									VkPhysicalDevice					physicalDevice,
147									deUint32							queueIndex,
148									const VkPhysicalDeviceFeatures2KHR&	enabledFeatures,
149									const vector<string>&				enabledExtensions,
150									const tcu::CommandLine&				cmdLine)
151{
152	VkDeviceQueueCreateInfo		queueInfo;
153	VkDeviceCreateInfo			deviceInfo;
154	vector<string>				enabledLayers;
155	vector<const char*>			layerPtrs;
156	vector<const char*>			extensionPtrs;
157	const float					queuePriority	= 1.0f;
158
159	deMemset(&queueInfo,	0, sizeof(queueInfo));
160	deMemset(&deviceInfo,	0, sizeof(deviceInfo));
161
162	if (cmdLine.isValidationEnabled())
163	{
164		enabledLayers = getValidationLayers(vki, physicalDevice);
165		if (enabledLayers.empty())
166			TCU_THROW(NotSupportedError, "No validation layers found");
167	}
168
169	layerPtrs.resize(enabledLayers.size());
170
171	for (size_t ndx = 0; ndx < enabledLayers.size(); ++ndx)
172		layerPtrs[ndx] = enabledLayers[ndx].c_str();
173
174	extensionPtrs.resize(enabledExtensions.size());
175
176	for (size_t ndx = 0; ndx < enabledExtensions.size(); ++ndx)
177		extensionPtrs[ndx] = enabledExtensions[ndx].c_str();
178
179	// VK_KHR_get_physical_device_propeties2 is used if enabledFeatures.pNext != 0
180
181	queueInfo.sType							= VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
182	queueInfo.pNext							= enabledFeatures.pNext ? &enabledFeatures : DE_NULL;
183	queueInfo.flags							= (VkDeviceQueueCreateFlags)0u;
184	queueInfo.queueFamilyIndex				= queueIndex;
185	queueInfo.queueCount					= 1u;
186	queueInfo.pQueuePriorities				= &queuePriority;
187
188	deviceInfo.sType						= VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
189	deviceInfo.pNext						= DE_NULL;
190	deviceInfo.queueCreateInfoCount			= 1u;
191	deviceInfo.pQueueCreateInfos			= &queueInfo;
192	deviceInfo.enabledExtensionCount		= (deUint32)extensionPtrs.size();
193	deviceInfo.ppEnabledExtensionNames		= (extensionPtrs.empty() ? DE_NULL : &extensionPtrs[0]);
194	deviceInfo.enabledLayerCount			= (deUint32)layerPtrs.size();
195	deviceInfo.ppEnabledLayerNames			= (layerPtrs.empty() ? DE_NULL : &layerPtrs[0]);
196	deviceInfo.pEnabledFeatures				= enabledFeatures.pNext ? DE_NULL : &enabledFeatures.features;
197
198	return createDevice(vki, physicalDevice, &deviceInfo);
199};
200
201bool isPhysicalDeviceFeatures2Supported (const vector<string>& instanceExtensions)
202{
203	return de::contains(instanceExtensions.begin(), instanceExtensions.end(), "VK_KHR_get_physical_device_properties2");
204}
205
206struct DeviceFeatures
207{
208	VkPhysicalDeviceFeatures2KHR						coreFeatures;
209	VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR	samplerYCbCrConversionFeatures;
210
211	DeviceFeatures (const InstanceInterface&	vki,
212					VkPhysicalDevice			physicalDevice,
213					const vector<string>&		instanceExtensions,
214					const vector<string>&		deviceExtensions)
215	{
216		void**	curExtPoint		= &coreFeatures.pNext;
217
218		deMemset(&coreFeatures, 0, sizeof(coreFeatures));
219		deMemset(&samplerYCbCrConversionFeatures, 0, sizeof(samplerYCbCrConversionFeatures));
220
221		coreFeatures.sType						= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
222		samplerYCbCrConversionFeatures.sType	= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR;
223
224		if (isPhysicalDeviceFeatures2Supported(instanceExtensions))
225		{
226			if (de::contains(deviceExtensions.begin(), deviceExtensions.end(), "VK_KHR_sampler_ycbcr_conversion"))
227			{
228				*curExtPoint = &samplerYCbCrConversionFeatures;
229				curExtPoint = &samplerYCbCrConversionFeatures.pNext;
230			}
231
232			vki.getPhysicalDeviceFeatures2KHR(physicalDevice, &coreFeatures);
233		}
234		else
235			coreFeatures.features = getPhysicalDeviceFeatures(vki, physicalDevice);
236
237		// Disable robustness by default, as it has an impact on performance on some HW.
238		coreFeatures.features.robustBufferAccess = false;
239	}
240};
241
242} // anonymous
243
244class DefaultDevice
245{
246public:
247										DefaultDevice					(const PlatformInterface& vkPlatform, const tcu::CommandLine& cmdLine);
248										~DefaultDevice					(void);
249
250	VkInstance							getInstance						(void) const	{ return *m_instance;								}
251	const InstanceInterface&			getInstanceInterface			(void) const	{ return m_instanceInterface;						}
252	const vector<string>&				getInstanceExtensions			(void) const	{ return m_instanceExtensions;						}
253
254	VkPhysicalDevice					getPhysicalDevice				(void) const	{ return m_physicalDevice;							}
255	const VkPhysicalDeviceFeatures&		getDeviceFeatures				(void) const	{ return m_deviceFeatures.coreFeatures.features;	}
256	const VkPhysicalDeviceFeatures2KHR&	getDeviceFeatures2				(void) const	{ return m_deviceFeatures.coreFeatures;				}
257	VkDevice							getDevice						(void) const	{ return *m_device;									}
258	const DeviceInterface&				getDeviceInterface				(void) const	{ return m_deviceInterface;							}
259	const VkPhysicalDeviceProperties&	getDeviceProperties				(void) const	{ return m_deviceProperties;						}
260	const vector<string>&				getDeviceExtensions				(void) const	{ return m_deviceExtensions;						}
261
262	deUint32							getUniversalQueueFamilyIndex	(void) const	{ return m_universalQueueFamilyIndex;				}
263	VkQueue								getUniversalQueue				(void) const;
264
265private:
266	static VkPhysicalDeviceFeatures		filterDefaultDeviceFeatures		(const VkPhysicalDeviceFeatures& deviceFeatures);
267
268	const vector<string>				m_instanceExtensions;
269	const Unique<VkInstance>			m_instance;
270	const InstanceDriver				m_instanceInterface;
271
272	const VkPhysicalDevice				m_physicalDevice;
273
274	const deUint32						m_universalQueueFamilyIndex;
275	const vector<string>				m_deviceExtensions;
276	const DeviceFeatures				m_deviceFeatures;
277	const VkPhysicalDeviceProperties	m_deviceProperties;
278
279	const Unique<VkDevice>				m_device;
280	const DeviceDriver					m_deviceInterface;
281};
282
283DefaultDevice::DefaultDevice (const PlatformInterface& vkPlatform, const tcu::CommandLine& cmdLine)
284	: m_instanceExtensions			(filterExtensions(enumerateInstanceExtensionProperties(vkPlatform, DE_NULL)))
285	, m_instance					(createInstance(vkPlatform, m_instanceExtensions, cmdLine))
286	, m_instanceInterface			(vkPlatform, *m_instance)
287	, m_physicalDevice				(chooseDevice(m_instanceInterface, *m_instance, cmdLine))
288	, m_universalQueueFamilyIndex	(findQueueFamilyIndexWithCaps(m_instanceInterface, m_physicalDevice, VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT))
289	, m_deviceExtensions			(filterExtensions(enumerateDeviceExtensionProperties(m_instanceInterface, m_physicalDevice, DE_NULL)))
290	, m_deviceFeatures				(m_instanceInterface, m_physicalDevice, m_instanceExtensions, m_deviceExtensions)
291	, m_deviceProperties			(getPhysicalDeviceProperties(m_instanceInterface, m_physicalDevice))
292	, m_device						(createDefaultDevice(m_instanceInterface,
293														 m_physicalDevice,
294														 m_universalQueueFamilyIndex,
295														 m_deviceFeatures.coreFeatures,
296														 m_deviceExtensions,
297														 cmdLine))
298	, m_deviceInterface				(m_instanceInterface, *m_device)
299{
300}
301
302DefaultDevice::~DefaultDevice (void)
303{
304}
305
306VkQueue DefaultDevice::getUniversalQueue (void) const
307{
308	return getDeviceQueue(m_deviceInterface, *m_device, m_universalQueueFamilyIndex, 0);
309}
310
311namespace
312{
313
314// Allocator utilities
315
316vk::Allocator* createAllocator (DefaultDevice* device)
317{
318	const VkPhysicalDeviceMemoryProperties memoryProperties = vk::getPhysicalDeviceMemoryProperties(device->getInstanceInterface(), device->getPhysicalDevice());
319
320	// \todo [2015-07-24 jarkko] support allocator selection/configuration from command line (or compile time)
321	return new SimpleAllocator(device->getDeviceInterface(), device->getDevice(), memoryProperties);
322}
323
324} // anonymous
325
326// Context
327
328Context::Context (tcu::TestContext&							testCtx,
329				  const vk::PlatformInterface&				platformInterface,
330				  vk::ProgramCollection<vk::ProgramBinary>&	progCollection)
331	: m_testCtx				(testCtx)
332	, m_platformInterface	(platformInterface)
333	, m_progCollection		(progCollection)
334	, m_device				(new DefaultDevice(m_platformInterface, testCtx.getCommandLine()))
335	, m_allocator			(createAllocator(m_device.get()))
336{
337}
338
339Context::~Context (void)
340{
341}
342
343const vector<string>&					Context::getInstanceExtensions			(void) const { return m_device->getInstanceExtensions();		}
344vk::VkInstance							Context::getInstance					(void) const { return m_device->getInstance();					}
345const vk::InstanceInterface&			Context::getInstanceInterface			(void) const { return m_device->getInstanceInterface();			}
346vk::VkPhysicalDevice					Context::getPhysicalDevice				(void) const { return m_device->getPhysicalDevice();			}
347const vk::VkPhysicalDeviceFeatures&		Context::getDeviceFeatures				(void) const { return m_device->getDeviceFeatures();			}
348const vk::VkPhysicalDeviceFeatures2KHR&	Context::getDeviceFeatures2				(void) const { return m_device->getDeviceFeatures2();			}
349const vk::VkPhysicalDeviceProperties&	Context::getDeviceProperties			(void) const { return m_device->getDeviceProperties();			}
350const vector<string>&					Context::getDeviceExtensions			(void) const { return m_device->getDeviceExtensions();			}
351vk::VkDevice							Context::getDevice						(void) const { return m_device->getDevice();					}
352const vk::DeviceInterface&				Context::getDeviceInterface				(void) const { return m_device->getDeviceInterface();			}
353deUint32								Context::getUniversalQueueFamilyIndex	(void) const { return m_device->getUniversalQueueFamilyIndex();	}
354vk::VkQueue								Context::getUniversalQueue				(void) const { return m_device->getUniversalQueue();			}
355vk::Allocator&							Context::getDefaultAllocator			(void) const { return *m_allocator;								}
356
357// TestCase
358
359void TestCase::initPrograms (SourceCollections&) const
360{
361}
362
363} // vkt
364