VulkanBenchmarks: add validation layers and load via ICD

In DEBUG builds, enable validation layers: VK_LAYER_KHRONOS_validation
and VK_LAYER_LUNARG_standard_validation. Also register the debug utils
messenger ext callback for when validation layers report a problem. We
can force validation layers in non-DEBUG by defining
ENABLE_VALIDATION_LAYERS to 1.

In order to be able to use validation layers, load the Vulkan driver via
ICD, rather than directly. To load SwiftShader, generate a temp icd.json
file pointing at the driver path, and temporarily set the
VK_ICD_FILENAMES env var to point at it when we load the ICD. This also
allows us to load the native GPU driver by defining LOAD_NATIVE_DRIVER
to 1 (default is 0).

Fixed errors reported by enabling validation layers:
* TriangleSampleTexture had a mismatched binding number for the sampler2D
* Correctly set memoryTypeIndex for allocations instead of 0

Bug: b/176981107
Change-Id: I3c791086acea048b73d3568d6d7a45d8e0100c17
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/52749
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
diff --git a/tests/VulkanBenchmarks/ClearImageBenchmarks.cpp b/tests/VulkanBenchmarks/ClearImageBenchmarks.cpp
index 8852903..72a6db2 100644
--- a/tests/VulkanBenchmarks/ClearImageBenchmarks.cpp
+++ b/tests/VulkanBenchmarks/ClearImageBenchmarks.cpp
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "Util.hpp"
 #include "VulkanTester.hpp"
 #include "benchmark/benchmark.h"
 
 #include <cassert>
-
 class ClearImageBenchmark
 {
 public:
@@ -24,6 +24,7 @@
 	{
 		tester.initialize();
 		auto &device = tester.getDevice();
+		auto &physicalDevice = tester.getPhysicalDevice();
 
 		vk::ImageCreateInfo imageInfo;
 		imageInfo.imageType = vk::ImageType::e2D;
@@ -42,7 +43,7 @@
 
 		vk::MemoryAllocateInfo allocateInfo;
 		allocateInfo.allocationSize = memoryRequirements.size;
-		allocateInfo.memoryTypeIndex = 0;
+		allocateInfo.memoryTypeIndex = Util::getMemoryTypeIndex(physicalDevice, memoryRequirements.memoryTypeBits);
 
 		memory = device.allocateMemory(allocateInfo);
 
diff --git a/tests/VulkanBenchmarks/TriangleBenchmarks.cpp b/tests/VulkanBenchmarks/TriangleBenchmarks.cpp
index 215d3f4..9050010 100644
--- a/tests/VulkanBenchmarks/TriangleBenchmarks.cpp
+++ b/tests/VulkanBenchmarks/TriangleBenchmarks.cpp
@@ -198,7 +198,7 @@
 
 			layout(location = 0) out vec4 outColor;
 
-			layout(binding = 0) uniform sampler2D texSampler;
+			layout(binding = 1) uniform sampler2D texSampler;
 
 			void main()
 			{
@@ -221,9 +221,10 @@
 
 	tester.onUpdateDescriptorSet([](DrawTester &tester, vk::CommandPool &commandPool, vk::DescriptorSet &descriptorSet) {
 		auto &device = tester.getDevice();
+		auto &physicalDevice = tester.getPhysicalDevice();
 		auto &queue = tester.getQueue();
 
-		auto &texture = tester.addImage(device, 16, 16, vk::Format::eR8G8B8A8Unorm).obj;
+		auto &texture = tester.addImage(device, physicalDevice, 16, 16, vk::Format::eR8G8B8A8Unorm).obj;
 
 		// Fill texture with white
 		vk::DeviceSize bufferSize = 16 * 16 * 4;
diff --git a/tests/VulkanWrapper/DrawTester.cpp b/tests/VulkanWrapper/DrawTester.cpp
index 2e2e29e..356c892 100644
--- a/tests/VulkanWrapper/DrawTester.cpp
+++ b/tests/VulkanWrapper/DrawTester.cpp
@@ -193,7 +193,7 @@
 
 	for(size_t i = 0; i < framebuffers.size(); i++)
 	{
-		framebuffers[i].reset(new Framebuffer(device, swapchain->getImageView(i), swapchain->colorFormat, renderPass, swapchain->getExtent(), multisample));
+		framebuffers[i].reset(new Framebuffer(device, physicalDevice, swapchain->getImageView(i), swapchain->colorFormat, renderPass, swapchain->getExtent(), multisample));
 	}
 }
 
@@ -392,10 +392,13 @@
 		}
 
 		// Draw
-		commandBuffers[i].bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
-		VULKAN_HPP_NAMESPACE::DeviceSize offset = 0;
-		commandBuffers[i].bindVertexBuffers(0, 1, &vertices.buffer, &offset);
-		commandBuffers[i].draw(vertices.numVertices, 1, 0, 0);
+		if(vertices.numVertices > 0)
+		{
+			commandBuffers[i].bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
+			VULKAN_HPP_NAMESPACE::DeviceSize offset = 0;
+			commandBuffers[i].bindVertexBuffers(0, 1, &vertices.buffer, &offset);
+			commandBuffers[i].draw(vertices.numVertices, 1, 0, 0);
+		}
 
 		commandBuffers[i].endRenderPass();
 		commandBuffers[i].end();
diff --git a/tests/VulkanWrapper/DrawTester.hpp b/tests/VulkanWrapper/DrawTester.hpp
index 431a6c5..e380ef2 100644
--- a/tests/VulkanWrapper/DrawTester.hpp
+++ b/tests/VulkanWrapper/DrawTester.hpp
@@ -148,7 +148,7 @@
 		std::vector<vk::VertexInputAttributeDescription> inputAttributes;
 		vk::PipelineVertexInputStateCreateInfo inputState;
 
-		uint32_t numVertices;
+		uint32_t numVertices = 0;
 	} vertices;
 
 	vk::DescriptorSetLayout descriptorSetLayout;  // Owning handle
diff --git a/tests/VulkanWrapper/Framebuffer.cpp b/tests/VulkanWrapper/Framebuffer.cpp
index ab62a10..dd9298a 100644
--- a/tests/VulkanWrapper/Framebuffer.cpp
+++ b/tests/VulkanWrapper/Framebuffer.cpp
@@ -14,14 +14,14 @@
 
 #include "Framebuffer.hpp"
 
-Framebuffer::Framebuffer(vk::Device device, vk::ImageView attachment, vk::Format colorFormat, vk::RenderPass renderPass, vk::Extent2D extent, bool multisample)
+Framebuffer::Framebuffer(vk::Device device, vk::PhysicalDevice physicalDevice, vk::ImageView attachment, vk::Format colorFormat, vk::RenderPass renderPass, vk::Extent2D extent, bool multisample)
     : device(device)
 {
 	std::vector<vk::ImageView> attachments(multisample ? 2 : 1);
 
 	if(multisample)
 	{
-		multisampleImage.reset(new Image(device, extent.width, extent.height, colorFormat, vk::SampleCountFlagBits::e4));
+		multisampleImage.reset(new Image(device, physicalDevice, extent.width, extent.height, colorFormat, vk::SampleCountFlagBits::e4));
 
 		// We'll be rendering to attachment location 0
 		attachments[0] = multisampleImage->getImageView();
diff --git a/tests/VulkanWrapper/Framebuffer.hpp b/tests/VulkanWrapper/Framebuffer.hpp
index b3d1620..505eea1 100644
--- a/tests/VulkanWrapper/Framebuffer.hpp
+++ b/tests/VulkanWrapper/Framebuffer.hpp
@@ -21,7 +21,7 @@
 class Framebuffer
 {
 public:
-	Framebuffer(vk::Device device, vk::ImageView attachment, vk::Format colorFormat, vk::RenderPass renderPass, vk::Extent2D extent, bool multisample);
+	Framebuffer(vk::Device device, vk::PhysicalDevice physicalDevice, vk::ImageView attachment, vk::Format colorFormat, vk::RenderPass renderPass, vk::Extent2D extent, bool multisample);
 	~Framebuffer();
 
 	vk::Framebuffer getFramebuffer()
diff --git a/tests/VulkanWrapper/Image.cpp b/tests/VulkanWrapper/Image.cpp
index 0ffc69b..c5cbad6 100644
--- a/tests/VulkanWrapper/Image.cpp
+++ b/tests/VulkanWrapper/Image.cpp
@@ -13,8 +13,9 @@
 // limitations under the License.
 
 #include "Image.hpp"
+#include "Util.hpp"
 
-Image::Image(vk::Device device, uint32_t width, uint32_t height, vk::Format format, vk::SampleCountFlagBits sampleCount /*= vk::SampleCountFlagBits::e1*/)
+Image::Image(vk::Device device, vk::PhysicalDevice physicalDevice, uint32_t width, uint32_t height, vk::Format format, vk::SampleCountFlagBits sampleCount /*= vk::SampleCountFlagBits::e1*/)
     : device(device)
 {
 	vk::ImageCreateInfo imageInfo;
@@ -34,7 +35,7 @@
 
 	vk::MemoryAllocateInfo allocateInfo;
 	allocateInfo.allocationSize = memoryRequirements.size;
-	allocateInfo.memoryTypeIndex = 0;  //getMemoryTypeIndex(memoryRequirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eDeviceLocal);
+	allocateInfo.memoryTypeIndex = Util::getMemoryTypeIndex(physicalDevice, memoryRequirements.memoryTypeBits);
 
 	imageMemory = device.allocateMemory(allocateInfo);
 
diff --git a/tests/VulkanWrapper/Image.hpp b/tests/VulkanWrapper/Image.hpp
index 3526ff2..5bfa863 100644
--- a/tests/VulkanWrapper/Image.hpp
+++ b/tests/VulkanWrapper/Image.hpp
@@ -20,7 +20,7 @@
 class Image
 {
 public:
-	Image(vk::Device device, uint32_t width, uint32_t height, vk::Format format, vk::SampleCountFlagBits sampleCount = vk::SampleCountFlagBits::e1);
+	Image(vk::Device device, vk::PhysicalDevice physicalDevice, uint32_t width, uint32_t height, vk::Format format, vk::SampleCountFlagBits sampleCount = vk::SampleCountFlagBits::e1);
 	~Image();
 
 	vk::Image getImage()
diff --git a/tests/VulkanWrapper/Util.hpp b/tests/VulkanWrapper/Util.hpp
index adfdedb..980c984 100644
--- a/tests/VulkanWrapper/Util.hpp
+++ b/tests/VulkanWrapper/Util.hpp
@@ -22,7 +22,7 @@
 
 namespace Util {
 
-uint32_t getMemoryTypeIndex(vk::PhysicalDevice physicalDevice, uint32_t typeBits, vk::MemoryPropertyFlags properties);
+uint32_t getMemoryTypeIndex(vk::PhysicalDevice physicalDevice, uint32_t typeBits, vk::MemoryPropertyFlags properties = {});
 
 vk::CommandBuffer beginSingleTimeCommands(vk::Device device, vk::CommandPool commandPool);
 
diff --git a/tests/VulkanWrapper/VulkanTester.cpp b/tests/VulkanWrapper/VulkanTester.cpp
index 90f2ca0..e4c05e5 100644
--- a/tests/VulkanWrapper/VulkanTester.cpp
+++ b/tests/VulkanWrapper/VulkanTester.cpp
@@ -13,7 +13,30 @@
 // limitations under the License.
 
 #include "VulkanTester.hpp"
+#include <cstdlib>
+#include <filesystem>
 #include <fstream>
+#include <iostream>
+
+namespace fs = std::filesystem;
+
+// By default, load SwiftShader via loader
+#ifndef LOAD_NATIVE_DRIVER
+#	define LOAD_NATIVE_DRIVER 0
+#endif
+
+#ifndef LOAD_SWIFTSHADER_DIRECTLY
+#	define LOAD_SWIFTSHADER_DIRECTLY 0
+#endif
+
+#if LOAD_NATIVE_DRIVER && LOAD_SWIFTSHADER_DIRECTLY
+#	error Enable only one of LOAD_NATIVE_DRIVER and LOAD_SWIFTSHADER_DIRECTLY
+#endif
+
+// By default, enable validation layers in DEBUG builds
+#if !defined(ENABLE_VALIDATION_LAYERS) && !defined(NDEBUG)
+#	define ENABLE_VALIDATION_LAYERS 1
+#endif
 
 #if defined(_WIN32)
 #	define OS_WINDOWS 1
@@ -33,7 +56,107 @@
 #	error Unimplemented platform
 #endif
 
+// TODO: move to its own header/cpp
+// Wraps a single environment variable, allowing it to be set
+// and automatically restored on destruction.
+class ScopedSetEnvVar
+{
+public:
+	ScopedSetEnvVar(std::string name)
+	    : name(name)
+	{
+		assert(!name.empty());
+	}
+
+	ScopedSetEnvVar(std::string name, std::string value)
+	    : name(name)
+	{
+		set(value);
+	}
+
+	~ScopedSetEnvVar()
+	{
+		restore();
+	}
+
+	void set(std::string value)
+	{
+		restore();
+		if(auto ov = getEnv(name.data()))
+		{
+			oldValue = ov;
+		}
+		putEnv((name + std::string("=") + value).c_str());
+	}
+
+	void restore()
+	{
+		if(!oldValue.empty())
+		{
+			putEnv((name + std::string("=") + oldValue).c_str());
+			oldValue.clear();
+		}
+	}
+
+private:
+	void putEnv(const char *env)
+	{
+		// POSIX putenv needs 'env' to live beyond the call
+		envCopy = env;
+#if OS_WINDOWS
+		[[maybe_unused]] auto r = ::_putenv(envCopy.c_str());
+		assert(r == 0);
+#else
+		[[maybe_unused]] auto r = ::putenv(const_cast<char *>(envCopy.c_str()));
+		assert(r == 0);
+#endif
+	}
+
+	const char *getEnv(const char *name)
+	{
+		return ::getenv(name);
+	}
+
+	std::string name;
+	std::string oldValue;
+	std::string envCopy;
+};
+
+// Generates a temporary icd.json file that sets library_path at the input driverPath,
+// and sets VK_ICD_FILENAMES environment variable to this file, restoring the env var
+// and deleting the temp file on destruction.
+class ScopedSetIcdFilenames
+{
+public:
+	ScopedSetIcdFilenames() = default;
+	ScopedSetIcdFilenames(const char *driverPath)
+	{
+		std::ofstream fout(icdFileName);
+		assert(fout && "Failed to create generated icd file");
+		fout << R"raw({ "file_format_version": "1.0.0", "ICD": { "library_path": ")raw" << driverPath << R"raw(", "api_version": "1.0.5" } } )raw";
+		fout.close();
+
+		setEnvVar.set(icdFileName);
+	}
+
+	~ScopedSetIcdFilenames()
+	{
+		//TODO(b/180494886): fix C++17 filesystem issues on macOS
+#if !OS_MAC
+		if(fs::exists("vk_swiftshader_generated_icd.json"))
+		{
+			fs::remove("vk_swiftshader_generated_icd.json");
+		}
+#endif
+	}
+
+private:
+	static constexpr const char *icdFileName = "vk_swiftshader_generated_icd.json";
+	ScopedSetEnvVar setEnvVar{ "VK_ICD_FILENAMES" };
+};
+
 namespace {
+
 std::vector<const char *> getDriverPaths()
 {
 #if OS_WINDOWS
@@ -91,24 +214,25 @@
 	return f.good();
 }
 
-std::unique_ptr<vk::DynamicLoader> loadDriver()
+std::string findDriverPath()
 {
-	for(auto &p : getDriverPaths())
+	for(auto &path : getDriverPaths())
 	{
-		if(!fileExists(p))
-			continue;
-		return std::make_unique<vk::DynamicLoader>(p);
+		if(fileExists(path))
+			return path;
 	}
 
-#if(OS_MAC || OS_LINUX || OS_ANDROID || OS_FUCHSIA)
+#if(OS_LINUX || OS_ANDROID || OS_FUCHSIA)
 	// On Linux-based OSes, the lib path may be resolved by dlopen
-	for(auto &p : getDriverPaths())
+	for(auto &path : getDriverPaths())
 	{
-		auto lib = dlopen(p, RTLD_LAZY | RTLD_LOCAL);
+		auto lib = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
 		if(lib)
 		{
+			char libPath[2048] = { '\0' };
+			dlinfo(lib, RTLD_DI_ORIGIN, libPath);
 			dlclose(lib);
-			return std::make_unique<vk::DynamicLoader>(p);
+			return std::string{ libPath } + "/" + path;
 		}
 	}
 #endif
@@ -118,10 +242,13 @@
 
 }  // namespace
 
+VulkanTester::VulkanTester() = default;
+
 VulkanTester::~VulkanTester()
 {
 	device.waitIdle();
 	device.destroy(nullptr);
+	if(debugReport) instance.destroy(debugReport);
 	instance.destroy(nullptr);
 }
 
@@ -133,9 +260,75 @@
 	PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl->getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
 	VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
 
-	instance = vk::createInstance({}, nullptr);
+	vk::InstanceCreateInfo instanceCreateInfo;
+	std::vector<const char *> extensionNames
+	{
+		VK_KHR_SURFACE_EXTENSION_NAME,
+#if defined(USE_HEADLESS_SURFACE)
+		    VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME,
+#endif
+#if defined(VK_USE_PLATFORM_WIN32_KHR)
+		    VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
+#endif
+	};
+#if ENABLE_VALIDATION_LAYERS
+	extensionNames.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+#endif
+
+	auto addLayerIfAvailable = [](std::vector<const char *> &layers, const char *layer) {
+		static auto layerProperties = vk::enumerateInstanceLayerProperties();
+		if(std::find_if(layerProperties.begin(), layerProperties.end(), [layer](auto &lp) {
+			   return strcmp(layer, lp.layerName) == 0;
+		   }) != layerProperties.end())
+		{
+			//std::cout << "Enabled layer: " << layer << std::endl;
+			layers.push_back(layer);
+		}
+	};
+
+	std::vector<const char *> layerNames;
+#if ENABLE_VALIDATION_LAYERS
+	addLayerIfAvailable(layerNames, "VK_LAYER_KHRONOS_validation");
+	addLayerIfAvailable(layerNames, "VK_LAYER_LUNARG_standard_validation");
+#endif
+
+	instanceCreateInfo.ppEnabledExtensionNames = extensionNames.data();
+	instanceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(extensionNames.size());
+	instanceCreateInfo.ppEnabledLayerNames = layerNames.data();
+	instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(layerNames.size());
+
+	instance = vk::createInstance(instanceCreateInfo, nullptr);
 	VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
 
+#if ENABLE_VALIDATION_LAYERS
+	if(VULKAN_HPP_DEFAULT_DISPATCHER.vkCreateDebugUtilsMessengerEXT)
+	{
+		vk::DebugUtilsMessengerCreateInfoEXT debugInfo;
+		debugInfo.messageSeverity =
+		    // vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
+		    vk::DebugUtilsMessageSeverityFlagBitsEXT::eError |
+		    vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning;
+
+		debugInfo.messageType = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
+		                        vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
+		                        vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance;
+
+		PFN_vkDebugUtilsMessengerCallbackEXT debugInfoCallback =
+		    [](
+		        VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
+		        VkDebugUtilsMessageTypeFlagsEXT messageTypes,
+		        const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
+		        void *pUserData) -> VkBool32 {
+			//assert(false);
+			std::cerr << "[DebugInfoCallback] " << pCallbackData->pMessage << std::endl;
+			return VK_FALSE;
+		};
+
+		debugInfo.pfnUserCallback = debugInfoCallback;
+		debugReport = instance.createDebugUtilsMessengerEXT(debugInfo);
+	}
+#endif
+
 	std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
 	assert(!physicalDevices.empty());
 	physicalDevice = physicalDevices[0];
@@ -146,11 +339,56 @@
 	queueCreateInfo.queueCount = 1;
 	queueCreateInfo.pQueuePriorities = &defaultQueuePriority;
 
+	std::vector<const char *> deviceExtensions = {
+		VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+	};
+
 	vk::DeviceCreateInfo deviceCreateInfo;
 	deviceCreateInfo.queueCreateInfoCount = 1;
 	deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
+	deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
+	deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
 
 	device = physicalDevice.createDevice(deviceCreateInfo, nullptr);
 
 	queue = device.getQueue(queueFamilyIndex, 0);
 }
+
+std::unique_ptr<vk::DynamicLoader> VulkanTester::loadDriver()
+{
+	if(LOAD_NATIVE_DRIVER)
+	{
+		return std::make_unique<vk::DynamicLoader>();
+	}
+
+	auto driverPath = findDriverPath();
+	assert(!driverPath.empty());
+
+	if(LOAD_SWIFTSHADER_DIRECTLY)
+	{
+		return std::make_unique<vk::DynamicLoader>(driverPath);
+	}
+
+	// Load SwiftShader via loader
+
+	// Set VK_ICD_FILENAMES env var so it gets picked up by the loading of the ICD driver
+	setIcdFilenames = std::make_unique<ScopedSetIcdFilenames>(driverPath.c_str());
+
+	std::unique_ptr<vk::DynamicLoader> dl;
+#ifndef VULKAN_HPP_NO_EXCEPTIONS
+	try
+	{
+		dl = std::make_unique<vk::DynamicLoader>();
+	}
+	catch(std::exception &ex)
+	{
+		std::cerr << "vk::DynamicLoader exception: " << ex.what() << std::endl;
+		std::cerr << "Falling back to loading SwiftShader directly (i.e. no validation layers)" << std::endl;
+		dl = std::make_unique<vk::DynamicLoader>(driverPath);
+	}
+#else
+	dl = std::make_unique<vk::DynamicLoader>();
+#endif
+
+	return dl;
+}
diff --git a/tests/VulkanWrapper/VulkanTester.hpp b/tests/VulkanWrapper/VulkanTester.hpp
index 89b7d05..044bffc 100644
--- a/tests/VulkanWrapper/VulkanTester.hpp
+++ b/tests/VulkanWrapper/VulkanTester.hpp
@@ -20,19 +20,24 @@
 class VulkanTester
 {
 public:
-	VulkanTester() = default;
+	VulkanTester();
 	virtual ~VulkanTester();
 
 	// Call once after construction so that virtual functions may be called during init
 	void initialize();
 
 	const vk::DynamicLoader &dynamicLoader() const { return *dl; }
-	vk::Device &getDevice() { return this->device; }
-	vk::Queue &getQueue() { return this->queue; }
+	vk::PhysicalDevice &getPhysicalDevice() { return physicalDevice; }
+	vk::Device &getDevice() { return device; }
+	vk::Queue &getQueue() { return queue; }
 	uint32_t getQueueFamilyIndex() const { return queueFamilyIndex; }
 
 private:
+	std::unique_ptr<vk::DynamicLoader> loadDriver();
+
+	std::unique_ptr<class ScopedSetIcdFilenames> setIcdFilenames;
 	std::unique_ptr<vk::DynamicLoader> dl;
+	vk::DebugUtilsMessengerEXT debugReport;
 
 protected:
 	const uint32_t queueFamilyIndex = 0;
diff --git a/tests/VulkanWrapper/Window.cpp b/tests/VulkanWrapper/Window.cpp
index 1cfdbe6..ad29cfc 100644
--- a/tests/VulkanWrapper/Window.cpp
+++ b/tests/VulkanWrapper/Window.cpp
@@ -17,6 +17,7 @@
 #if USE_HEADLESS_SURFACE
 
 Window::Window(vk::Instance instance, vk::Extent2D windowSize)
+    : instance(instance)
 {
 	vk::HeadlessSurfaceCreateInfoEXT surfaceCreateInfo;
 	surface = instance.createHeadlessSurfaceEXT(surfaceCreateInfo);
@@ -40,6 +41,7 @@
 #elif defined(_WIN32)
 
 Window::Window(vk::Instance instance, vk::Extent2D windowSize)
+    : instance(instance)
 {
 	windowClass.cbSize = sizeof(WNDCLASSEX);
 	windowClass.style = CS_HREDRAW | CS_VREDRAW;