• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Valve Corporation.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Auxiliar functions to help create custom devices and instances.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vkRefUtil.hpp"
26 #include "vkQueryUtil.hpp"
27 #include "vkDeviceUtil.hpp"
28 #include "vkDebugReportUtil.hpp"
29 #include "tcuCommandLine.hpp"
30 #include "vktCustomInstancesDevices.hpp"
31 
32 #include <algorithm>
33 #include <memory>
34 #include <set>
35 
36 using std::vector;
37 using std::string;
38 using vk::Move;
39 using vk::VkInstance;
40 using vk::InstanceDriver;
41 using vk::DebugReportRecorder;
42 using vk::VkDebugReportCallbackCreateInfoEXT;
43 using vk::VkDebugReportCallbackEXT;
44 
45 namespace vkt
46 {
47 
48 namespace
49 {
50 
getValidationLayers(const vector<vk::VkLayerProperties> & supportedLayers)51 vector<const char*> getValidationLayers (const vector<vk::VkLayerProperties>& supportedLayers)
52 {
53 	static const char*	s_magicLayer		= "VK_LAYER_KHRONOS_validation";
54 	static const char*	s_defaultLayers[]	=
55 	{
56 		"VK_LAYER_LUNARG_standard_validation",		// Deprecated by at least Vulkan SDK 1.1.121.
57 		"VK_LAYER_GOOGLE_threading",				// Deprecated by at least Vulkan SDK 1.1.121.
58 		"VK_LAYER_LUNARG_parameter_validation",		// Deprecated by at least Vulkan SDK 1.1.121.
59 		"VK_LAYER_LUNARG_device_limits",
60 		"VK_LAYER_LUNARG_object_tracker",			// Deprecated by at least Vulkan SDK 1.1.121.
61 		"VK_LAYER_LUNARG_image",
62 		"VK_LAYER_LUNARG_core_validation",			// Deprecated by at least Vulkan SDK 1.1.121.
63 		"VK_LAYER_LUNARG_swapchain",
64 		"VK_LAYER_GOOGLE_unique_objects"			// Deprecated by at least Vulkan SDK 1.1.121.
65 	};
66 
67 	vector<const char*>	enabledLayers;
68 
69 	if (vk::isLayerSupported(supportedLayers, vk::RequiredLayer(s_magicLayer)))
70 		enabledLayers.push_back(s_magicLayer);
71 	else
72 	{
73 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_defaultLayers); ++ndx)
74 		{
75 			if (isLayerSupported(supportedLayers, vk::RequiredLayer(s_defaultLayers[ndx])))
76 				enabledLayers.push_back(s_defaultLayers[ndx]);
77 		}
78 	}
79 
80 	return enabledLayers;
81 }
82 
83 } // anonymous
84 
85 
getValidationLayers(const vk::PlatformInterface & vkp)86 vector<const char*> getValidationLayers (const vk::PlatformInterface& vkp)
87 {
88 	return getValidationLayers(enumerateInstanceLayerProperties(vkp));
89 }
90 
getValidationLayers(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice)91 vector<const char*> getValidationLayers (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice)
92 {
93 	return getValidationLayers(enumerateDeviceLayerProperties(vki, physicalDevice));
94 }
95 
CustomInstance(Context & context,Move<VkInstance> instance,std::unique_ptr<vk::DebugReportRecorder> & recorder)96 CustomInstance::CustomInstance (Context& context, Move<VkInstance> instance, std::unique_ptr<vk::DebugReportRecorder>& recorder)
97 	: m_context		(&context)
98 	, m_recorder	(recorder.release())
99 	, m_instance	(instance)
100 	, m_driver		(new InstanceDriver(context.getPlatformInterface(), *m_instance))
101 	, m_callback	(m_recorder ? m_recorder->createCallback(*m_driver, *m_instance) : Move<VkDebugReportCallbackEXT>())
102 {
103 }
104 
CustomInstance()105 CustomInstance::CustomInstance ()
106 	: m_context		(nullptr)
107 	, m_recorder	(nullptr)
108 	, m_instance	()
109 	, m_driver		(nullptr)
110 	, m_callback	()
111 {
112 }
113 
CustomInstance(CustomInstance && other)114 CustomInstance::CustomInstance (CustomInstance&& other)
115 	: CustomInstance()
116 {
117 	this->swap(other);
118 }
119 
~CustomInstance()120 CustomInstance::~CustomInstance ()
121 {
122 	collectMessages();
123 }
124 
operator =(CustomInstance && other)125 CustomInstance&	CustomInstance::operator= (CustomInstance&& other)
126 {
127 	CustomInstance destroyer;
128 	destroyer.swap(other);
129 	this->swap(destroyer);
130 	return *this;
131 }
132 
swap(CustomInstance & other)133 void CustomInstance::swap (CustomInstance& other)
134 {
135 	std::swap(m_context, other.m_context);
136 	m_recorder.swap(other.m_recorder);
137 	Move<VkInstance> aux = m_instance; m_instance = other.m_instance; other.m_instance = aux;
138 	m_driver.swap(other.m_driver);
139 	Move<VkDebugReportCallbackEXT> aux2 = m_callback; m_callback = other.m_callback; other.m_callback = aux2;
140 }
141 
operator VkInstance() const142 CustomInstance::operator VkInstance () const
143 {
144 	return *m_instance;
145 }
146 
getDriver() const147 const vk::InstanceDriver& CustomInstance::getDriver() const
148 {
149 	return *m_driver;
150 }
151 
collectMessages()152 void CustomInstance::collectMessages ()
153 {
154 	if (m_recorder)
155 		collectAndReportDebugMessages(*m_recorder, *m_context);
156 }
157 
UncheckedInstance()158 UncheckedInstance::UncheckedInstance ()
159 	: m_context		(nullptr)
160 	, m_recorder	(nullptr)
161 	, m_allocator	(nullptr)
162 	, m_instance	(DE_NULL)
163 	, m_driver		(nullptr)
164 	, m_callback	()
165 {
166 }
167 
UncheckedInstance(Context & context,vk::VkInstance instance,const vk::VkAllocationCallbacks * pAllocator,std::unique_ptr<DebugReportRecorder> & recorder)168 UncheckedInstance::UncheckedInstance (Context& context, vk::VkInstance instance, const vk::VkAllocationCallbacks* pAllocator, std::unique_ptr<DebugReportRecorder>& recorder)
169 	: m_context		(&context)
170 	, m_recorder	(recorder.release())
171 	, m_allocator	(pAllocator)
172 	, m_instance	(instance)
173 	, m_driver		((m_instance != DE_NULL) ? new InstanceDriver(context.getPlatformInterface(), m_instance) : nullptr)
174 	, m_callback	(m_recorder ? m_recorder->createCallback(*m_driver, m_instance) : Move<VkDebugReportCallbackEXT>())
175 {
176 }
177 
~UncheckedInstance()178 UncheckedInstance::~UncheckedInstance ()
179 {
180 	if (m_recorder)
181 		collectAndReportDebugMessages(*m_recorder, *m_context);
182 
183 	if (m_instance != DE_NULL)
184 	{
185 		m_recorder.reset(nullptr);
186 		m_driver->destroyInstance(m_instance, m_allocator);
187 	}
188 }
189 
swap(UncheckedInstance & other)190 void UncheckedInstance::swap (UncheckedInstance& other)
191 {
192 	std::swap(m_context, other.m_context);
193 	m_recorder.swap(other.m_recorder);
194 	std::swap(m_allocator, other.m_allocator);
195 	vk::VkInstance aux = m_instance; m_instance = other.m_instance; other.m_instance = aux;
196 	m_driver.swap(other.m_driver);
197 	Move<VkDebugReportCallbackEXT> aux2 = m_callback; m_callback = other.m_callback; other.m_callback = aux2;
198 }
199 
UncheckedInstance(UncheckedInstance && other)200 UncheckedInstance::UncheckedInstance (UncheckedInstance&& other)
201 	: UncheckedInstance()
202 {
203 	this->swap(other);
204 }
205 
operator =(UncheckedInstance && other)206 UncheckedInstance& UncheckedInstance::operator= (UncheckedInstance&& other)
207 {
208 	UncheckedInstance destroyer;
209 	destroyer.swap(other);
210 	this->swap(destroyer);
211 	return *this;
212 }
213 
operator vk::VkInstance() const214 UncheckedInstance::operator vk::VkInstance () const
215 {
216 	return m_instance;
217 }
operator bool() const218 UncheckedInstance::operator bool () const
219 {
220 	return (m_instance != DE_NULL);
221 }
222 
createCustomInstanceWithExtensions(Context & context,const std::vector<std::string> & extensions,const vk::VkAllocationCallbacks * pAllocator,bool allowLayers)223 CustomInstance createCustomInstanceWithExtensions (Context& context, const std::vector<std::string>& extensions, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
224 {
225 	vector<const char*>	enabledLayers;
226 	vector<string>		enabledLayersStr;
227 	const auto&			cmdLine					= context.getTestContext().getCommandLine();
228 	const bool			validationRequested		= (cmdLine.isValidationEnabled() && allowLayers);
229 	const bool			printValidationErrors	= cmdLine.printValidationErrors();
230 
231 	if (validationRequested)
232 	{
233 		enabledLayers = getValidationLayers(context.getPlatformInterface());
234 		enabledLayersStr = vector<string>(begin(enabledLayers), end(enabledLayers));
235 	}
236 
237 	const bool validationEnabled = !enabledLayers.empty();
238 
239 	// Filter extension list and throw NotSupported if a required extension is not supported.
240 	const deUint32									apiVersion			= context.getUsedApiVersion();
241 	const vk::PlatformInterface&					vkp					= context.getPlatformInterface();
242 	const vector<vk::VkExtensionProperties>			availableExtensions	= vk::enumerateInstanceExtensionProperties(vkp, DE_NULL);
243 	std::set<string>								usedExtensions;
244 
245 	// Get list of available extension names.
246 	vector<string> availableExtensionNames;
247 	for (const auto& ext : availableExtensions)
248 		availableExtensionNames.push_back(ext.extensionName);
249 
250 	// Filter duplicates and remove core extensions.
251 	for (const auto& ext : extensions)
252 	{
253 		if (!vk::isCoreInstanceExtension(apiVersion, ext))
254 			usedExtensions.insert(ext);
255 	}
256 
257 	// Add debug extension if validation is enabled.
258 	if (validationEnabled)
259 		usedExtensions.insert("VK_EXT_debug_report");
260 
261 	// Check extension support.
262 	for (const auto& ext : usedExtensions)
263 	{
264 		if (!vk::isInstanceExtensionSupported(apiVersion, availableExtensionNames, ext))
265 			TCU_THROW(NotSupportedError, ext + " is not supported");
266 	}
267 
268 	std::unique_ptr<DebugReportRecorder> debugReportRecorder;
269 	if (validationEnabled)
270 		debugReportRecorder.reset(new DebugReportRecorder(printValidationErrors));
271 
272 	// Create custom instance.
273 	const vector<string> usedExtensionsVec(begin(usedExtensions), end(usedExtensions));
274 	Move<VkInstance> instance = vk::createDefaultInstance(vkp, apiVersion, enabledLayersStr, usedExtensionsVec, debugReportRecorder.get(), pAllocator);
275 	return CustomInstance(context, instance, debugReportRecorder);
276 }
277 
createCustomInstanceWithExtension(Context & context,const std::string & extension,const vk::VkAllocationCallbacks * pAllocator,bool allowLayers)278 CustomInstance createCustomInstanceWithExtension (Context& context, const std::string& extension, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
279 {
280 	return createCustomInstanceWithExtensions(context, std::vector<std::string>(1, extension), pAllocator, allowLayers);
281 }
282 
createCustomInstanceFromContext(Context & context,const vk::VkAllocationCallbacks * pAllocator,bool allowLayers)283 CustomInstance createCustomInstanceFromContext (Context& context, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
284 {
285 	return createCustomInstanceWithExtensions(context, std::vector<std::string>(), pAllocator, allowLayers);
286 }
287 
288 const char kDebugReportExt[] = "VK_EXT_debug_report";
289 
addDebugReportExt(const vk::PlatformInterface & vkp,const vk::VkInstanceCreateInfo & createInfo)290 vector<const char*> addDebugReportExt(const vk::PlatformInterface& vkp, const vk::VkInstanceCreateInfo& createInfo)
291 {
292 	if (!isDebugReportSupported(vkp))
293 		TCU_THROW(NotSupportedError, "VK_EXT_debug_report is not supported");
294 
295 	vector<const char*> actualExtensions;
296 	if (createInfo.enabledExtensionCount != 0u)
297 	{
298 		for (deUint32 i = 0u; i < createInfo.enabledExtensionCount; ++i)
299 			actualExtensions.push_back(createInfo.ppEnabledExtensionNames[i]);
300 	}
301 
302 	if (std::find_if(begin(actualExtensions), end(actualExtensions), [](const char* name) { return (strcmp(name, kDebugReportExt) == 0); })
303 		== end(actualExtensions))
304 	{
305 		actualExtensions.push_back(kDebugReportExt);
306 	}
307 
308 	return actualExtensions;
309 }
310 
createCustomInstanceFromInfo(Context & context,const vk::VkInstanceCreateInfo * instanceCreateInfo,const vk::VkAllocationCallbacks * pAllocator,bool allowLayers)311 CustomInstance createCustomInstanceFromInfo (Context& context, const vk::VkInstanceCreateInfo* instanceCreateInfo, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
312 {
313 	vector<const char*>						enabledLayers;
314 	vector<const char*>						enabledExtensions;
315 	vk::VkInstanceCreateInfo				createInfo				= *instanceCreateInfo;
316 	const auto&								cmdLine					= context.getTestContext().getCommandLine();
317 	const bool								validationEnabled		= cmdLine.isValidationEnabled();
318 	const bool								printValidationErrors	= cmdLine.printValidationErrors();
319 	const vk::PlatformInterface&			vkp						= context.getPlatformInterface();
320 	std::unique_ptr<DebugReportRecorder>	recorder;
321 	VkDebugReportCallbackCreateInfoEXT		callbackInfo;
322 
323 	if (validationEnabled && allowLayers)
324 	{
325 		// Activate some layers if requested.
326 		if (createInfo.enabledLayerCount == 0u)
327 		{
328 			enabledLayers = getValidationLayers(vkp);
329 			createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
330 			createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
331 		}
332 
333 		// Make sure the debug report extension is enabled when validation is enabled.
334 		enabledExtensions = addDebugReportExt(vkp, createInfo);
335 		createInfo.enabledExtensionCount = static_cast<deUint32>(enabledExtensions.size());
336 		createInfo.ppEnabledExtensionNames = enabledExtensions.data();
337 
338 		recorder.reset(new DebugReportRecorder(printValidationErrors));
339 		callbackInfo		= recorder->makeCreateInfo();
340 		callbackInfo.pNext	= createInfo.pNext;
341 		createInfo.pNext	= &callbackInfo;
342 	}
343 
344 	return CustomInstance(context, vk::createInstance(vkp, &createInfo, pAllocator), recorder);
345 }
346 
createUncheckedInstance(Context & context,const vk::VkInstanceCreateInfo * instanceCreateInfo,const vk::VkAllocationCallbacks * pAllocator,UncheckedInstance * instance,bool allowLayers)347 vk::VkResult createUncheckedInstance (Context& context, const vk::VkInstanceCreateInfo* instanceCreateInfo, const vk::VkAllocationCallbacks* pAllocator, UncheckedInstance* instance, bool allowLayers)
348 {
349 	vector<const char*>						enabledLayers;
350 	vector<const char*>						enabledExtensions;
351 	vk::VkInstanceCreateInfo				createInfo				= *instanceCreateInfo;
352 	const auto&								cmdLine					= context.getTestContext().getCommandLine();
353 	const bool								validationEnabled		= cmdLine.isValidationEnabled();
354 	const bool								printValidationErrors	= cmdLine.printValidationErrors();
355 	const vk::PlatformInterface&			vkp						= context.getPlatformInterface();
356 	const bool								addLayers				= (validationEnabled && allowLayers);
357 	std::unique_ptr<DebugReportRecorder>	recorder;
358 	VkDebugReportCallbackCreateInfoEXT		callbackInfo;
359 
360 	if (addLayers)
361 	{
362 		// Activate some layers if requested.
363 		if (createInfo.enabledLayerCount == 0u)
364 		{
365 			enabledLayers = getValidationLayers(vkp);
366 			createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
367 			createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
368 		}
369 
370 		// Make sure the debug report extension is enabled when validation is enabled.
371 		enabledExtensions = addDebugReportExt(vkp, createInfo);
372 		createInfo.enabledExtensionCount = static_cast<deUint32>(enabledExtensions.size());
373 		createInfo.ppEnabledExtensionNames = enabledExtensions.data();
374 
375 		// Prepare debug report recorder also for instance creation.
376 		recorder.reset(new DebugReportRecorder(printValidationErrors));
377 		callbackInfo		= recorder->makeCreateInfo();
378 		callbackInfo.pNext	= createInfo.pNext;
379 		createInfo.pNext	= &callbackInfo;
380 	}
381 
382 	vk::VkInstance	raw_instance = DE_NULL;
383 	vk::VkResult	result = vkp.createInstance(&createInfo, pAllocator, &raw_instance);
384 
385 	*instance = UncheckedInstance(context, raw_instance, pAllocator, recorder);
386 
387 	return result;
388 }
389 
createCustomDevice(bool validationEnabled,const vk::PlatformInterface & vkp,vk::VkInstance instance,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const vk::VkDeviceCreateInfo * pCreateInfo,const vk::VkAllocationCallbacks * pAllocator)390 vk::Move<vk::VkDevice> createCustomDevice (bool validationEnabled, const vk::PlatformInterface& vkp, vk::VkInstance instance, const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, const vk::VkDeviceCreateInfo* pCreateInfo, const vk::VkAllocationCallbacks* pAllocator)
391 {
392 	vector<const char*>		enabledLayers;
393 	vk::VkDeviceCreateInfo	createInfo		= *pCreateInfo;
394 
395 	if (createInfo.enabledLayerCount == 0u && validationEnabled)
396 	{
397 		enabledLayers = getValidationLayers(vki, physicalDevice);
398 		createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
399 		createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
400 	}
401 
402 	return createDevice(vkp, instance, vki, physicalDevice, &createInfo, pAllocator);
403 }
404 
createUncheckedDevice(bool validationEnabled,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const vk::VkDeviceCreateInfo * pCreateInfo,const vk::VkAllocationCallbacks * pAllocator,vk::VkDevice * pDevice)405 vk::VkResult createUncheckedDevice (bool validationEnabled, const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, const vk::VkDeviceCreateInfo* pCreateInfo, const vk::VkAllocationCallbacks* pAllocator, vk::VkDevice* pDevice)
406 {
407 	vector<const char*>		enabledLayers;
408 	vk::VkDeviceCreateInfo	createInfo		= *pCreateInfo;
409 
410 	if (createInfo.enabledLayerCount == 0u && validationEnabled)
411 	{
412 		enabledLayers = getValidationLayers(vki, physicalDevice);
413 		createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
414 		createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
415 	}
416 
417 	return vki.createDevice(physicalDevice, &createInfo, pAllocator, pDevice);
418 }
419 
420 
421 }
422