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