• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 The Khronos Group Inc.
3  * Copyright (c) 2021 Valve Corporation
4  * Copyright (c) 2021 LunarG, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and/or associated documentation files (the "Materials"), to
8  * deal in the Materials without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Materials, and to permit persons to whom the Materials are
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice(s) and this permission notice shall be included in
14  * all copies or substantial portions of the Materials.
15  *
16  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  *
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23  * USE OR OTHER DEALINGS IN THE MATERIALS.
24  *
25  * Author: Charles Giessen <charles@lunarg.com>
26  */
27 
28 /*
29  * The test_environment is what combines the icd, layer, and shim library into a single object that
30  * test fixtures can create and use. Responsible for loading the libraries and establishing the
31  * channels for tests to talk with the icd's and layers.
32  */
33 #pragma once
34 
35 // Must include gtest first to guard against Xlib colliding due to redefinitions of "None" and "Bool"
36 
37 #ifdef _MSC_VER
38 #pragma warning(push)
39 /*
40     MSVC warnings 4251 and 4275 have to do with potential dll-interface mismatch
41     between library (gtest) and users. Since we build the gtest library
42     as part of the test build we know that the dll-interface will match and
43     can disable these warnings.
44  */
45 #pragma warning(disable : 4251)
46 #pragma warning(disable : 4275)
47 #endif
48 
49 // GTest and Xlib collide due to redefinitions of "None" and "Bool"
50 #ifdef VK_USE_PLATFORM_XLIB_KHR
51 #pragma push_macro("None")
52 #pragma push_macro("Bool")
53 #undef None
54 #undef Bool
55 #endif
56 
57 #ifdef _WIN32
58 #ifndef NOMINMAX
59 #define NOMINMAX
60 #endif
61 #endif
62 
63 // Use the NDK's header on Android
64 #include "gtest/gtest.h"
65 
66 #include "test_util.h"
67 
68 #include "shim/shim.h"
69 
70 #include "icd/physical_device.h"
71 #include "icd/test_icd.h"
72 
73 #include "layer/test_layer.h"
74 
75 // handle checking
76 template <typename T>
handle_assert_has_value(T const & handle)77 void handle_assert_has_value(T const& handle) {
78     ASSERT_TRUE(handle != VK_NULL_HANDLE);
79 }
80 template <typename T>
handle_assert_null(T const & handle)81 void handle_assert_null(T const& handle) {
82     ASSERT_TRUE(handle == VK_NULL_HANDLE);
83 }
84 template <typename T>
handle_assert_has_values(std::vector<T> const & handles)85 void handle_assert_has_values(std::vector<T> const& handles) {
86     for (auto const& handle : handles) {
87         ASSERT_TRUE(handle != VK_NULL_HANDLE);
88     }
89 }
90 template <typename T>
handle_assert_no_values(std::vector<T> const & handles)91 void handle_assert_no_values(std::vector<T> const& handles) {
92     for (auto const& handle : handles) {
93         ASSERT_TRUE(handle == VK_NULL_HANDLE);
94     }
95 }
96 template <typename T>
handle_assert_no_values(size_t length,T handles[])97 void handle_assert_no_values(size_t length, T handles[]) {
98     for (size_t i = 0; i < length; i++) {
99         ASSERT_TRUE(handles[i] == VK_NULL_HANDLE);
100     }
101 }
102 template <typename T>
handle_assert_equal(T const & left,T const & right)103 void handle_assert_equal(T const& left, T const& right) {
104     ASSERT_EQ(left, right);
105 }
106 template <typename T>
handle_assert_equal(std::vector<T> const & left,std::vector<T> const & right)107 void handle_assert_equal(std::vector<T> const& left, std::vector<T> const& right) {
108     ASSERT_EQ(left.size(), right.size());
109     for (size_t i = 0; i < left.size(); i++) {
110         ASSERT_EQ(left[i], right[i]);
111     }
112 }
113 template <typename T>
handle_assert_equal(size_t count,T left[],T right[])114 void handle_assert_equal(size_t count, T left[], T right[]) {
115     for (size_t i = 0; i < count; i++) {
116         ASSERT_EQ(left[i], right[i]);
117     }
118 }
119 
120 // InstWrapper & DeviceWrapper - used to make creating instances & devices easier test writing
121 struct InstWrapper {
122     InstWrapper(VulkanFunctions& functions, VkAllocationCallbacks* callbacks = nullptr) noexcept;
123     InstWrapper(VulkanFunctions& functions, VkInstance inst, VkAllocationCallbacks* callbacks = nullptr) noexcept;
124     ~InstWrapper() noexcept;
125 
126     // Move-nly object
127     InstWrapper(InstWrapper const&) = delete;
128     InstWrapper& operator=(InstWrapper const&) = delete;
129     InstWrapper(InstWrapper&& other) noexcept;
130     InstWrapper& operator=(InstWrapper&&) noexcept;
131 
132     // Construct this VkInstance using googletest to assert if it succeeded
133     void CheckCreate(VkResult result_to_check = VK_SUCCESS);
134 
135     // Convenience
VkInstanceInstWrapper136     operator VkInstance() { return inst; }
137     VulkanFunctions* operator->() { return functions; }
138 
loadInstWrapper139     FromVoidStarFunc load(const char* func_name) { return FromVoidStarFunc(functions->vkGetInstanceProcAddr(inst, func_name)); }
140 
141     // Enumerate physical devices using googletest to assert if it succeeded
142     std::vector<VkPhysicalDevice> GetPhysDevs(VkResult result_to_check = VK_SUCCESS);  // query all physical devices
143     std::vector<VkPhysicalDevice> GetPhysDevs(uint32_t phys_dev_count,
144                                               VkResult result_to_check = VK_SUCCESS);  // query only phys_dev_count devices
145     // Enumerate a single physical device using googletest to assert if it succeeded
146     VkPhysicalDevice GetPhysDev(VkResult result_to_check = VK_SUCCESS);
147 
148     VulkanFunctions* functions = nullptr;
149     VkInstance inst = VK_NULL_HANDLE;
150     VkAllocationCallbacks* callbacks = nullptr;
151     InstanceCreateInfo create_info{};
152 };
153 
154 std::vector<VkExtensionProperties> EnumerateDeviceExtensions(InstWrapper const& inst, VkPhysicalDevice physical_device);
155 
156 struct DeviceWrapper {
157     DeviceWrapper(InstWrapper& inst_wrapper, VkAllocationCallbacks* callbacks = nullptr) noexcept;
158     DeviceWrapper(VulkanFunctions& functions, VkDevice device, VkAllocationCallbacks* callbacks = nullptr) noexcept;
159     ~DeviceWrapper() noexcept;
160 
161     // Move-only object
162     DeviceWrapper(DeviceWrapper const&) = delete;
163     DeviceWrapper& operator=(DeviceWrapper const&) = delete;
164     DeviceWrapper(DeviceWrapper&&) noexcept;
165     DeviceWrapper& operator=(DeviceWrapper&&) noexcept;
166 
167     // Construct this VkDevice using googletest to assert if it succeeded
168     void CheckCreate(VkPhysicalDevice physical_device, VkResult result_to_check = VK_SUCCESS);
169 
170     // Convenience
VkDeviceDeviceWrapper171     operator VkDevice() { return dev; }
VkDeviceDeviceWrapper172     operator VkDevice() const { return dev; }
173     VulkanFunctions* operator->() { return functions; }
174 
loadDeviceWrapper175     FromVoidStarFunc load(const char* func_name) { return FromVoidStarFunc(functions->vkGetDeviceProcAddr(dev, func_name)); }
176 
177     VulkanFunctions* functions = nullptr;
178     VkDevice dev = VK_NULL_HANDLE;
179     VkAllocationCallbacks* callbacks = nullptr;
180     DeviceCreateInfo create_info{};
181 };
182 
183 struct DebugUtilsLogger {
DebugUtilsMessengerLoggerCallbackDebugUtilsLogger184     static VkBool32 VKAPI_PTR DebugUtilsMessengerLoggerCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
185                                                                 VkDebugUtilsMessageTypeFlagsEXT messageTypes,
186                                                                 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
187                                                                 void* pUserData) {
188         DebugUtilsLogger* debug = reinterpret_cast<DebugUtilsLogger*>(pUserData);
189         debug->returned_output += pCallbackData->pMessage;
190         debug->returned_output += '\n';
191         return VK_FALSE;
192     }
193     DebugUtilsLogger(VkDebugUtilsMessageSeverityFlagsEXT severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
194                                                                     VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
195                                                                     VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
196                                                                     VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
197         returned_output.reserve(4096);  // output can be very noisy, reserving should help prevent many small allocations
198         create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
199         create_info.pNext = nullptr;
200         create_info.messageSeverity = severity;
201         create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
202                                   VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
203         create_info.pfnUserCallback = DebugUtilsMessengerLoggerCallback;
204         create_info.pUserData = this;
205     }
206 
207     // Immoveable object
208     DebugUtilsLogger(DebugUtilsLogger const&) = delete;
209     DebugUtilsLogger& operator=(DebugUtilsLogger const&) = delete;
210     DebugUtilsLogger(DebugUtilsLogger&&) = delete;
211     DebugUtilsLogger& operator=(DebugUtilsLogger&&) = delete;
212     // Find a string in the log output
findDebugUtilsLogger213     bool find(std::string const& search_text) const { return returned_output.find(search_text) != std::string::npos; }
214     // Clear the log
clearDebugUtilsLogger215     void clear() { returned_output.clear(); }
getDebugUtilsLogger216     VkDebugUtilsMessengerCreateInfoEXT* get() noexcept { return &create_info; }
217     VkDebugUtilsMessengerCreateInfoEXT create_info{};
218     std::string returned_output;
219 };
220 
221 struct DebugUtilsWrapper {
DebugUtilsWrapperDebugUtilsWrapper222     DebugUtilsWrapper() noexcept {}
223     DebugUtilsWrapper(InstWrapper& inst_wrapper,
224                       VkDebugUtilsMessageSeverityFlagsEXT severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
225                                                                      VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
226                       VkAllocationCallbacks* callbacks = nullptr)
loggerDebugUtilsWrapper227         : logger(severity), inst(inst_wrapper.inst), callbacks(callbacks) {
228         vkCreateDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(
229             inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkCreateDebugUtilsMessengerEXT"));
230         vkDestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(
231             inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkDestroyDebugUtilsMessengerEXT"));
232     };
~DebugUtilsWrapperDebugUtilsWrapper233     ~DebugUtilsWrapper() noexcept {
234         if (messenger) {
235             vkDestroyDebugUtilsMessengerEXT(inst, messenger, callbacks);
236         }
237     }
238     // Immoveable object
239     DebugUtilsWrapper(DebugUtilsWrapper const&) = delete;
240     DebugUtilsWrapper& operator=(DebugUtilsWrapper const&) = delete;
241     DebugUtilsWrapper(DebugUtilsWrapper&&) = delete;
242     DebugUtilsWrapper& operator=(DebugUtilsWrapper&&) = delete;
243 
findDebugUtilsWrapper244     bool find(std::string const& search_text) { return logger.find(search_text); }
getDebugUtilsWrapper245     VkDebugUtilsMessengerCreateInfoEXT* get() noexcept { return logger.get(); }
246 
247     DebugUtilsLogger logger;
248     VkInstance inst = VK_NULL_HANDLE;
249     VkAllocationCallbacks* callbacks = nullptr;
250     PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
251     PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
252     VkDebugUtilsMessengerEXT messenger = VK_NULL_HANDLE;
253 };
254 
255 VkResult CreateDebugUtilsMessenger(DebugUtilsWrapper& debug_utils);
256 
257 // Helper that adds the debug utils extension name and sets the pNext chain up
258 // NOTE: Ignores existing pNext chains
259 void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsLogger& logger);
260 void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsWrapper& wrapper);
261 
262 struct FrameworkEnvironment;  // forward declaration
263 
264 struct PlatformShimWrapper {
265     PlatformShimWrapper(std::vector<fs::FolderManager>* folders, bool enable_log) noexcept;
266     ~PlatformShimWrapper() noexcept;
267     PlatformShimWrapper(PlatformShimWrapper const&) = delete;
268     PlatformShimWrapper& operator=(PlatformShimWrapper const&) = delete;
269 
270     // Convenience
271     PlatformShim* operator->() { return platform_shim; }
272 
273     LibraryWrapper shim_library;
274     PlatformShim* platform_shim;
275 };
276 
277 struct TestICDHandle {
278     TestICDHandle() noexcept;
279     TestICDHandle(fs::path const& icd_path) noexcept;
280     TestICD& reset_icd() noexcept;
281     TestICD& get_test_icd() noexcept;
282     fs::path get_icd_full_path() noexcept;
283     fs::path get_icd_manifest_path() noexcept;
284 
285     // Must use statically
286     LibraryWrapper icd_library;
287     GetTestICDFunc proc_addr_get_test_icd = nullptr;
288     GetNewTestICDFunc proc_addr_reset_icd = nullptr;
289     fs::path manifest_path;
290 };
291 struct TestLayerHandle {
292     TestLayerHandle() noexcept;
293     TestLayerHandle(fs::path const& layer_path) noexcept;
294     TestLayer& reset_layer() noexcept;
295     TestLayer& get_test_layer() noexcept;
296     fs::path get_layer_full_path() noexcept;
297     fs::path get_layer_manifest_path() noexcept;
298 
299     // Must use statically
300     LibraryWrapper layer_library;
301     GetTestLayerFunc proc_addr_get_test_layer = nullptr;
302     GetNewTestLayerFunc proc_addr_reset_layer = nullptr;
303     fs::path manifest_path;
304 };
305 
306 enum class ManifestDiscoveryType {
307     generic,              // put the manifest in the regular locations
308     none,                 // don't add to regular locations - eg D3DKMT
309     env_var,              // use the corresponding env-var for it
310     add_env_var,          // use the corresponding add-env-var for it
311     override_folder,      // add to a special folder for the override layer to use
312     windows_app_package,  // let the app package search find it
313 };
314 
315 struct TestICDDetails {
TestICDDetailsTestICDDetails316     TestICDDetails(ManifestICD icd_manifest) noexcept : icd_manifest(icd_manifest) {}
317     TestICDDetails(fs::path icd_path, uint32_t api_version = VK_API_VERSION_1_0) noexcept {
318         icd_manifest.set_lib_path(icd_path.str()).set_api_version(api_version);
319     }
320     BUILDER_VALUE(TestICDDetails, ManifestICD, icd_manifest, {});
321     BUILDER_VALUE(TestICDDetails, std::string, json_name, "test_icd");
322     BUILDER_VALUE(TestICDDetails, ManifestDiscoveryType, discovery_type, ManifestDiscoveryType::generic);
323     BUILDER_VALUE(TestICDDetails, bool, is_fake, false);
324 };
325 
326 struct TestLayerDetails {
TestLayerDetailsTestLayerDetails327     TestLayerDetails(ManifestLayer layer_manifest, const std::string& json_name) noexcept
328         : layer_manifest(layer_manifest), json_name(json_name) {}
329     BUILDER_VALUE(TestLayerDetails, ManifestLayer, layer_manifest, {});
330     BUILDER_VALUE(TestLayerDetails, std::string, json_name, "test_layer");
331     BUILDER_VALUE(TestLayerDetails, ManifestDiscoveryType, discovery_type, ManifestDiscoveryType::generic);
332     BUILDER_VALUE(TestLayerDetails, bool, is_fake, false);
333 };
334 
335 enum class ManifestLocation {
336     null = 0,
337     driver = 1,
338     driver_env_var = 2,
339     explicit_layer = 3,
340     explicit_layer_env_var = 4,
341     explicit_layer_add_env_var = 5,
342     implicit_layer = 6,
343     override_layer = 7,
344     windows_app_package = 8,
345 };
346 
347 struct FrameworkEnvironment {
348     FrameworkEnvironment() noexcept;  // default is to enable VK_LOADER_DEBUG=all
349     FrameworkEnvironment(bool enable_log) noexcept;
350 
351     void add_icd(TestICDDetails icd_details) noexcept;
352     void add_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
353     void add_implicit_layer(TestLayerDetails layer_details) noexcept;
354     void add_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
355     void add_explicit_layer(TestLayerDetails layer_details) noexcept;
356     void add_fake_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
357     void add_fake_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
358 
359     TestICD& get_test_icd(size_t index = 0) noexcept;
360     TestICD& reset_icd(size_t index = 0) noexcept;
361     fs::path get_test_icd_path(size_t index = 0) noexcept;
362     fs::path get_icd_manifest_path(size_t index = 0) noexcept;
363 
364     TestLayer& get_test_layer(size_t index = 0) noexcept;
365     TestLayer& reset_layer(size_t index = 0) noexcept;
366     fs::path get_test_layer_path(size_t index = 0) noexcept;
367     fs::path get_layer_manifest_path(size_t index = 0) noexcept;
368 
369     fs::FolderManager& get_folder(ManifestLocation location) noexcept;
370 
371     PlatformShimWrapper platform_shim;
372     std::vector<fs::FolderManager> folders;
373 
374     DebugUtilsLogger debug_log;
375     VulkanFunctions vulkan_functions;
376 
377     std::vector<TestICDHandle> icds;
378     std::vector<TestLayerHandle> layers;
379 
380     std::string env_var_vk_icd_filenames;
381     std::string add_env_var_vk_icd_filenames;
382 
383     std::string env_var_vk_layer_paths;
384     std::string add_env_var_vk_layer_paths;
385 
386    private:
387     void add_layer_impl(TestLayerDetails layer_details, ManifestCategory category);
388 };
389 
390 // The following helpers setup an icd with the required extensions and setting to use with WSI
391 // By default they use whatever the set VK_USE_PLATFORM_XXX macros define
392 void setup_WSI_in_ICD(TestICD& icd);
393 void setup_WSI_in_create_instance(InstWrapper& inst);
394 // api_selection: optionally provide a VK_USE_PLATFORM_XXX string to select which API to create a surface with
395 // Note: MUST provide api_selection on platforms with multiple viable API's, such as linux and MacOS
396 VkSurfaceKHR create_surface(InstWrapper& inst, const char* api_selection = nullptr);
397