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 "tcuCommandLine.hpp"
29 #include "vktCustomInstancesDevices.hpp"
30
31 #include <algorithm>
32
33 using std::vector;
34 using std::string;
35 using vk::Move;
36 using vk::VkInstance;
37 using vk::InstanceDriver;
38 using vk::DebugReportRecorder;
39
40 namespace vkt
41 {
42
43 namespace
44 {
45
getValidationLayers(const vector<vk::VkLayerProperties> & supportedLayers)46 vector<const char*> getValidationLayers (const vector<vk::VkLayerProperties>& supportedLayers)
47 {
48 static const char* s_magicLayer = "VK_LAYER_KHRONOS_validation";
49 static const char* s_defaultLayers[] =
50 {
51 "VK_LAYER_LUNARG_standard_validation", // Deprecated by at least Vulkan SDK 1.1.121.
52 "VK_LAYER_GOOGLE_threading", // Deprecated by at least Vulkan SDK 1.1.121.
53 "VK_LAYER_LUNARG_parameter_validation", // Deprecated by at least Vulkan SDK 1.1.121.
54 "VK_LAYER_LUNARG_device_limits",
55 "VK_LAYER_LUNARG_object_tracker", // Deprecated by at least Vulkan SDK 1.1.121.
56 "VK_LAYER_LUNARG_image",
57 "VK_LAYER_LUNARG_core_validation", // Deprecated by at least Vulkan SDK 1.1.121.
58 "VK_LAYER_LUNARG_swapchain",
59 "VK_LAYER_GOOGLE_unique_objects" // Deprecated by at least Vulkan SDK 1.1.121.
60 };
61
62 vector<const char*> enabledLayers;
63
64 if (vk::isLayerSupported(supportedLayers, vk::RequiredLayer(s_magicLayer)))
65 enabledLayers.push_back(s_magicLayer);
66 else
67 {
68 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_defaultLayers); ++ndx)
69 {
70 if (isLayerSupported(supportedLayers, vk::RequiredLayer(s_defaultLayers[ndx])))
71 enabledLayers.push_back(s_defaultLayers[ndx]);
72 }
73 }
74
75 return enabledLayers;
76 }
77
78 } // anonymous
79
80
getValidationLayers(const vk::PlatformInterface & vkp)81 vector<const char*> getValidationLayers (const vk::PlatformInterface& vkp)
82 {
83 return getValidationLayers(enumerateInstanceLayerProperties(vkp));
84 }
85
getValidationLayers(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice)86 vector<const char*> getValidationLayers (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice)
87 {
88 return getValidationLayers(enumerateDeviceLayerProperties(vki, physicalDevice));
89 }
90
CustomInstance(Context & context,Move<VkInstance> instance,bool enableDebugReportRecorder,bool printValidationErrors)91 CustomInstance::CustomInstance (Context& context, Move<VkInstance> instance, bool enableDebugReportRecorder, bool printValidationErrors)
92 : m_context (&context)
93 , m_instance (instance)
94 , m_driver (new InstanceDriver(context.getPlatformInterface(), *m_instance))
95 , m_recorder (enableDebugReportRecorder ? (new DebugReportRecorder(*m_driver, *m_instance, printValidationErrors)) : nullptr)
96 {
97 }
98
CustomInstance()99 CustomInstance::CustomInstance ()
100 : m_context (nullptr)
101 , m_instance ()
102 , m_driver (nullptr)
103 , m_recorder (nullptr)
104 {
105 }
106
CustomInstance(CustomInstance && other)107 CustomInstance::CustomInstance (CustomInstance&& other)
108 : CustomInstance()
109 {
110 this->swap(other);
111 }
112
~CustomInstance()113 CustomInstance::~CustomInstance ()
114 {
115 collectMessages();
116 }
117
operator =(CustomInstance && other)118 CustomInstance& CustomInstance::operator= (CustomInstance&& other)
119 {
120 CustomInstance destroyer;
121 destroyer.swap(other);
122 this->swap(destroyer);
123 return *this;
124 }
125
swap(CustomInstance & other)126 void CustomInstance::swap (CustomInstance& other)
127 {
128 std::swap(m_context, other.m_context);
129 Move<VkInstance> aux = m_instance; m_instance = other.m_instance; other.m_instance = aux;
130 m_driver.swap(other.m_driver);
131 m_recorder.swap(other.m_recorder);
132 }
133
operator VkInstance() const134 CustomInstance::operator VkInstance () const
135 {
136 return *m_instance;
137 }
138
getDriver() const139 const vk::InstanceDriver& CustomInstance::getDriver() const
140 {
141 return *m_driver;
142 }
143
collectMessages()144 void CustomInstance::collectMessages ()
145 {
146 if (m_recorder)
147 collectAndReportDebugMessages(*m_recorder, *m_context);
148 }
149
UncheckedInstance()150 UncheckedInstance::UncheckedInstance ()
151 : m_context (nullptr)
152 , m_allocator (nullptr)
153 , m_instance (DE_NULL)
154 , m_driver (nullptr)
155 , m_recorder (nullptr)
156 {
157 }
158
UncheckedInstance(Context & context,vk::VkInstance instance,const vk::VkAllocationCallbacks * pAllocator,bool enableDebugReportRecorder,bool printValidationErrors)159 UncheckedInstance::UncheckedInstance (Context& context, vk::VkInstance instance, const vk::VkAllocationCallbacks* pAllocator, bool enableDebugReportRecorder, bool printValidationErrors)
160 : m_context (&context)
161 , m_allocator (pAllocator)
162 , m_instance (instance)
163 , m_driver ((m_instance != DE_NULL) ? new InstanceDriver(context.getPlatformInterface(), m_instance) : nullptr)
164 , m_recorder ((enableDebugReportRecorder && m_instance != DE_NULL) ? (new DebugReportRecorder(*m_driver, m_instance, printValidationErrors)) : nullptr)
165 {
166 }
167
~UncheckedInstance()168 UncheckedInstance::~UncheckedInstance ()
169 {
170 if (m_recorder)
171 collectAndReportDebugMessages(*m_recorder, *m_context);
172
173 if (m_instance != DE_NULL)
174 {
175 m_recorder.reset(nullptr);
176 m_driver->destroyInstance(m_instance, m_allocator);
177 }
178 }
179
swap(UncheckedInstance & other)180 void UncheckedInstance::swap (UncheckedInstance& other)
181 {
182 std::swap(m_context, other.m_context);
183 std::swap(m_allocator, other.m_allocator);
184 vk::VkInstance aux = m_instance; m_instance = other.m_instance; other.m_instance = aux;
185 m_driver.swap(other.m_driver);
186 m_recorder.swap(other.m_recorder);
187 }
188
UncheckedInstance(UncheckedInstance && other)189 UncheckedInstance::UncheckedInstance (UncheckedInstance&& other)
190 : UncheckedInstance()
191 {
192 this->swap(other);
193 }
194
operator =(UncheckedInstance && other)195 UncheckedInstance& UncheckedInstance::operator= (UncheckedInstance&& other)
196 {
197 UncheckedInstance destroyer;
198 destroyer.swap(other);
199 this->swap(destroyer);
200 return *this;
201 }
202
operator vk::VkInstance() const203 UncheckedInstance::operator vk::VkInstance () const
204 {
205 return m_instance;
206 }
operator bool() const207 UncheckedInstance::operator bool () const
208 {
209 return (m_instance != DE_NULL);
210 }
211
createCustomInstanceWithExtensions(Context & context,const std::vector<std::string> & extensions,const vk::VkAllocationCallbacks * pAllocator,bool allowLayers)212 CustomInstance createCustomInstanceWithExtensions (Context& context, const std::vector<std::string>& extensions, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
213 {
214 vector<const char*> enabledLayers;
215 vector<string> enabledLayersStr;
216 const auto& cmdLine = context.getTestContext().getCommandLine();
217 const bool validationEnabled = (cmdLine.isValidationEnabled() && allowLayers);
218 const bool printValidationErrors = cmdLine.printValidationErrors();
219
220 if (validationEnabled)
221 {
222 enabledLayers = getValidationLayers(context.getPlatformInterface());
223 enabledLayersStr = vector<string>(begin(enabledLayers), end(enabledLayers));
224 }
225
226 // Filter extension list and throw NotSupported if a required extension is not supported.
227 const deUint32 apiVersion = context.getUsedApiVersion();
228 const vk::PlatformInterface& vkp = context.getPlatformInterface();
229 const std::vector<vk::VkExtensionProperties> availableExtensions = vk::enumerateInstanceExtensionProperties(vkp, DE_NULL);
230 vector<string> extensionPtrs;
231
232 vector<string> availableExtensionNames;
233 for (const auto& ext : availableExtensions)
234 availableExtensionNames.push_back(ext.extensionName);
235
236 for (const auto& ext : extensions)
237 {
238 if (!vk::isInstanceExtensionSupported(apiVersion, availableExtensionNames, ext))
239 TCU_THROW(NotSupportedError, ext + " is not supported");
240
241 if (!vk::isCoreInstanceExtension(apiVersion, ext))
242 extensionPtrs.push_back(ext);
243 }
244
245 Move<VkInstance> instance = vk::createDefaultInstance(vkp, apiVersion, enabledLayersStr, extensionPtrs, pAllocator);
246 return CustomInstance(context, instance, validationEnabled, printValidationErrors);
247 }
248
createCustomInstanceWithExtension(Context & context,const std::string & extension,const vk::VkAllocationCallbacks * pAllocator,bool allowLayers)249 CustomInstance createCustomInstanceWithExtension (Context& context, const std::string& extension, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
250 {
251 return createCustomInstanceWithExtensions(context, std::vector<std::string>(1, extension), pAllocator, allowLayers);
252 }
253
createCustomInstanceFromContext(Context & context,const vk::VkAllocationCallbacks * pAllocator,bool allowLayers)254 CustomInstance createCustomInstanceFromContext (Context& context, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
255 {
256 return createCustomInstanceWithExtensions(context, std::vector<std::string>(), pAllocator, allowLayers);
257 }
258
259 const char kDebugReportExt[] = "VK_EXT_debug_report";
260
addDebugReportExt(const vk::PlatformInterface & vkp,const vk::VkInstanceCreateInfo & createInfo)261 vector<const char*> addDebugReportExt(const vk::PlatformInterface& vkp, const vk::VkInstanceCreateInfo& createInfo)
262 {
263 if (!isDebugReportSupported(vkp))
264 TCU_THROW(NotSupportedError, "VK_EXT_debug_report is not supported");
265
266 vector<const char*> actualExtensions;
267 if (createInfo.enabledExtensionCount != 0u)
268 {
269 for (deUint32 i = 0u; i < createInfo.enabledExtensionCount; ++i)
270 actualExtensions.push_back(createInfo.ppEnabledExtensionNames[i]);
271 }
272
273 if (std::find_if(begin(actualExtensions), end(actualExtensions), [](const char* name) { return (strcmp(name, kDebugReportExt) == 0); })
274 == end(actualExtensions))
275 {
276 actualExtensions.push_back(kDebugReportExt);
277 }
278
279 return actualExtensions;
280 }
281
createCustomInstanceFromInfo(Context & context,const vk::VkInstanceCreateInfo * instanceCreateInfo,const vk::VkAllocationCallbacks * pAllocator,bool allowLayers)282 CustomInstance createCustomInstanceFromInfo (Context& context, const vk::VkInstanceCreateInfo* instanceCreateInfo, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
283 {
284 vector<const char*> enabledLayers;
285 vector<const char*> enabledExtensions;
286 vk::VkInstanceCreateInfo createInfo = *instanceCreateInfo;
287 const auto& cmdLine = context.getTestContext().getCommandLine();
288 const bool validationEnabled = cmdLine.isValidationEnabled();
289 const bool printValidationErrors = cmdLine.printValidationErrors();
290 const vk::PlatformInterface& vkp = context.getPlatformInterface();
291
292 if (validationEnabled && allowLayers)
293 {
294 // Activate some layers if requested.
295 if (createInfo.enabledLayerCount == 0u)
296 {
297 enabledLayers = getValidationLayers(vkp);
298 createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
299 createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
300 }
301
302 // Make sure the debug report extension is enabled when validation is enabled.
303 enabledExtensions = addDebugReportExt(vkp, createInfo);
304 createInfo.enabledExtensionCount = static_cast<deUint32>(enabledExtensions.size());
305 createInfo.ppEnabledExtensionNames = enabledExtensions.data();
306 }
307
308 return CustomInstance(context, vk::createInstance(vkp, &createInfo, pAllocator), validationEnabled, printValidationErrors);
309 }
310
createUncheckedInstance(Context & context,const vk::VkInstanceCreateInfo * instanceCreateInfo,const vk::VkAllocationCallbacks * pAllocator,UncheckedInstance * instance,bool allowLayers)311 vk::VkResult createUncheckedInstance (Context& context, const vk::VkInstanceCreateInfo* instanceCreateInfo, const vk::VkAllocationCallbacks* pAllocator, UncheckedInstance* instance, 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 const bool addLayers = (validationEnabled && allowLayers);
321
322 if (addLayers)
323 {
324 // Activate some layers if requested.
325 if (createInfo.enabledLayerCount == 0u)
326 {
327 enabledLayers = getValidationLayers(vkp);
328 createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
329 createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
330 }
331
332 // Make sure the debug report extension is enabled when validation is enabled.
333 enabledExtensions = addDebugReportExt(vkp, createInfo);
334 createInfo.enabledExtensionCount = static_cast<deUint32>(enabledExtensions.size());
335 createInfo.ppEnabledExtensionNames = enabledExtensions.data();
336 }
337
338 vk::VkInstance raw_instance = DE_NULL;
339 vk::VkResult result = vkp.createInstance(&createInfo, pAllocator, &raw_instance);
340
341 *instance = UncheckedInstance(context, raw_instance, pAllocator, addLayers, printValidationErrors);
342
343 return result;
344 }
345
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)346 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)
347 {
348 vector<const char*> enabledLayers;
349 vk::VkDeviceCreateInfo createInfo = *pCreateInfo;
350
351 if (createInfo.enabledLayerCount == 0u && validationEnabled)
352 {
353 enabledLayers = getValidationLayers(vki, physicalDevice);
354 createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
355 createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
356 }
357
358 return createDevice(vkp, instance, vki, physicalDevice, &createInfo, pAllocator);
359 }
360
createUncheckedDevice(bool validationEnabled,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const vk::VkDeviceCreateInfo * pCreateInfo,const vk::VkAllocationCallbacks * pAllocator,vk::VkDevice * pDevice)361 vk::VkResult createUncheckedDevice (bool validationEnabled, const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, const vk::VkDeviceCreateInfo* pCreateInfo, const vk::VkAllocationCallbacks* pAllocator, vk::VkDevice* pDevice)
362 {
363 vector<const char*> enabledLayers;
364 vk::VkDeviceCreateInfo createInfo = *pCreateInfo;
365
366 if (createInfo.enabledLayerCount == 0u && validationEnabled)
367 {
368 enabledLayers = getValidationLayers(vki, physicalDevice);
369 createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
370 createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
371 }
372
373 return vki.createDevice(physicalDevice, &createInfo, pAllocator, pDevice);
374 }
375
376
377 }
378