Vulkan: Handle errors on device creation.

This is both something we should strive for for robustness of the
backends and in this case helped debug what the issue was on the
linux-dawn-rel builder that was failing all Vulkan tests.

BUG=dawn:19

Change-Id: Ibe9f5ad76b7766575bb74fe4993625cf82cdf13f
Reviewed-on: https://dawn-review.googlesource.com/c/2702
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/Error.cpp b/src/dawn_native/Error.cpp
index 9467c3a..2e09931 100644
--- a/src/dawn_native/Error.cpp
+++ b/src/dawn_native/Error.cpp
@@ -19,7 +19,7 @@
 namespace dawn_native {
 
     ErrorData* MakeError(ErrorType type,
-                         const char* message,
+                         std::string message,
                          const char* file,
                          const char* function,
                          int line) {
diff --git a/src/dawn_native/Error.h b/src/dawn_native/Error.h
index 7f202f7..23ec325 100644
--- a/src/dawn_native/Error.h
+++ b/src/dawn_native/Error.h
@@ -17,6 +17,8 @@
 
 #include "common/Result.h"
 
+#include <string>
+
 namespace dawn_native {
 
     // This is the content of an error value for MaybeError or ResultOrError, split off to its own
@@ -85,7 +87,7 @@
 
     // Implementation detail of DAWN_MAKE_ERROR
     ErrorData* MakeError(ErrorType type,
-                         const char* message,
+                         std::string message,
                          const char* file,
                          const char* function,
                          int line);
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index 7b1cdd5..6c6d3dc 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -83,66 +83,47 @@
     // Device
 
     Device::Device(const std::vector<const char*>& requiredInstanceExtensions) {
-        if (!mVulkanLib.Open(kVulkanLibName)) {
+        if (ConsumedError(Initialize(requiredInstanceExtensions))) {
             ASSERT(false);
             return;
         }
+    }
+
+    MaybeError Device::Initialize(const std::vector<const char*>& requiredInstanceExtensions) {
+        if (!mVulkanLib.Open(kVulkanLibName)) {
+            return DAWN_CONTEXT_LOST_ERROR(std::string("Couldn't open ") + kVulkanLibName);
+        }
 
         VulkanFunctions* functions = GetMutableFunctions();
+        DAWN_TRY(functions->LoadGlobalProcs(mVulkanLib));
 
-        if (!functions->LoadGlobalProcs(mVulkanLib)) {
-            ASSERT(false);
-            return;
-        }
-
-        if (!GatherGlobalInfo(*this, &mGlobalInfo)) {
-            ASSERT(false);
-            return;
-        }
+        DAWN_TRY_ASSIGN(mGlobalInfo, GatherGlobalInfo(*this));
 
         VulkanGlobalKnobs usedGlobalKnobs = {};
-        if (!CreateInstance(&usedGlobalKnobs, requiredInstanceExtensions)) {
-            ASSERT(false);
-            return;
-        }
+        DAWN_TRY_ASSIGN(usedGlobalKnobs, CreateInstance(requiredInstanceExtensions));
         *static_cast<VulkanGlobalKnobs*>(&mGlobalInfo) = usedGlobalKnobs;
 
-        if (!functions->LoadInstanceProcs(mInstance, usedGlobalKnobs)) {
-            ASSERT(false);
-            return;
-        }
+        DAWN_TRY(functions->LoadInstanceProcs(mInstance, mGlobalInfo));
 
         if (usedGlobalKnobs.debugReport) {
-            if (!RegisterDebugReport()) {
-                ASSERT(false);
-                return;
-            }
+            DAWN_TRY(RegisterDebugReport());
         }
 
         std::vector<VkPhysicalDevice> physicalDevices;
-        if (!GetPhysicalDevices(*this, &physicalDevices) || physicalDevices.empty()) {
-            ASSERT(false);
-            return;
+        DAWN_TRY_ASSIGN(physicalDevices, GetPhysicalDevices(*this));
+        if (physicalDevices.empty()) {
+            return DAWN_CONTEXT_LOST_ERROR("No physical devices");
         }
         // TODO(cwallez@chromium.org): Choose the physical device based on ???
         mPhysicalDevice = physicalDevices[0];
 
-        if (!GatherDeviceInfo(*this, mPhysicalDevice, &mDeviceInfo)) {
-            ASSERT(false);
-            return;
-        }
+        DAWN_TRY_ASSIGN(mDeviceInfo, GatherDeviceInfo(*this, mPhysicalDevice));
 
         VulkanDeviceKnobs usedDeviceKnobs = {};
-        if (!CreateDevice(&usedDeviceKnobs)) {
-            ASSERT(false);
-            return;
-        }
+        DAWN_TRY_ASSIGN(usedDeviceKnobs, CreateDevice());
         *static_cast<VulkanDeviceKnobs*>(&mDeviceInfo) = usedDeviceKnobs;
 
-        if (!functions->LoadDeviceProcs(mVkDevice, usedDeviceKnobs)) {
-            ASSERT(false);
-            return;
-        }
+        DAWN_TRY(functions->LoadDeviceProcs(mVkDevice, mDeviceInfo));
 
         GatherQueueFromDevice();
 
@@ -155,6 +136,8 @@
         mPCIInfo.deviceId = mDeviceInfo.properties.deviceID;
         mPCIInfo.vendorId = mDeviceInfo.properties.vendorID;
         mPCIInfo.name = mDeviceInfo.properties.deviceName;
+
+        return {};
     }
 
     Device::~Device() {
@@ -418,8 +401,10 @@
         mWaitSemaphores.push_back(semaphore);
     }
 
-    bool Device::CreateInstance(VulkanGlobalKnobs* usedKnobs,
-                                const std::vector<const char*>& requiredExtensions) {
+    ResultOrError<VulkanGlobalKnobs> Device::CreateInstance(
+        const std::vector<const char*>& requiredExtensions) {
+        VulkanGlobalKnobs usedKnobs = {};
+
         std::vector<const char*> layersToRequest;
         std::vector<const char*> extensionsToRequest = requiredExtensions;
 
@@ -441,7 +426,7 @@
 #if defined(DAWN_USE_VKTRACE)
         if (mGlobalInfo.vktrace) {
             layersToRequest.push_back(kLayerNameLunargVKTrace);
-            usedKnobs->vktrace = true;
+            usedKnobs.vktrace = true;
         }
 #endif
         // RenderDoc installs a layer at the system level for its capture but we don't want to use
@@ -449,22 +434,22 @@
 #if defined(DAWN_USE_RENDERDOC)
         if (mGlobalInfo.renderDocCapture) {
             layersToRequest.push_back(kLayerNameRenderDocCapture);
-            usedKnobs->renderDocCapture = true;
+            usedKnobs.renderDocCapture = true;
         }
 #endif
 #if defined(DAWN_ENABLE_ASSERTS)
         if (mGlobalInfo.standardValidation) {
             layersToRequest.push_back(kLayerNameLunargStandardValidation);
-            usedKnobs->standardValidation = true;
+            usedKnobs.standardValidation = true;
         }
         if (mGlobalInfo.debugReport) {
             AddExtensionIfNotPresent(&extensionsToRequest, kExtensionNameExtDebugReport);
-            usedKnobs->debugReport = true;
+            usedKnobs.debugReport = true;
         }
 #endif
         if (mGlobalInfo.surface) {
             AddExtensionIfNotPresent(&extensionsToRequest, kExtensionNameKhrSurface);
-            usedKnobs->surface = true;
+            usedKnobs.surface = true;
         }
 
         VkApplicationInfo appInfo;
@@ -487,13 +472,15 @@
         createInfo.ppEnabledExtensionNames = extensionsToRequest.data();
 
         if (fn.CreateInstance(&createInfo, nullptr, &mInstance) != VK_SUCCESS) {
-            return false;
+            return DAWN_CONTEXT_LOST_ERROR("vkCreateInstance failed");
         }
 
-        return true;
+        return usedKnobs;
     }
 
-    bool Device::CreateDevice(VulkanDeviceKnobs* usedKnobs) {
+    ResultOrError<VulkanDeviceKnobs> Device::CreateDevice() {
+        VulkanDeviceKnobs usedKnobs = {};
+
         float zero = 0.0f;
         std::vector<const char*> layersToRequest;
         std::vector<const char*> extensionsToRequest;
@@ -501,13 +488,13 @@
 
         if (mDeviceInfo.swapchain) {
             extensionsToRequest.push_back(kExtensionNameKhrSwapchain);
-            usedKnobs->swapchain = true;
+            usedKnobs.swapchain = true;
         }
 
         // Always require independentBlend because it is a core Dawn feature
-        usedKnobs->features.independentBlend = VK_TRUE;
+        usedKnobs.features.independentBlend = VK_TRUE;
         // Always require imageCubeArray because it is a core Dawn feature
-        usedKnobs->features.imageCubeArray = VK_TRUE;
+        usedKnobs.features.imageCubeArray = VK_TRUE;
 
         // Find a universal queue family
         {
@@ -523,7 +510,7 @@
             }
 
             if (universalQueueFamily == -1) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("No universal queue family");
             }
             mQueueFamily = static_cast<uint32_t>(universalQueueFamily);
         }
@@ -551,20 +538,20 @@
         createInfo.ppEnabledLayerNames = layersToRequest.data();
         createInfo.enabledExtensionCount = static_cast<uint32_t>(extensionsToRequest.size());
         createInfo.ppEnabledExtensionNames = extensionsToRequest.data();
-        createInfo.pEnabledFeatures = &usedKnobs->features;
+        createInfo.pEnabledFeatures = &usedKnobs.features;
 
         if (fn.CreateDevice(mPhysicalDevice, &createInfo, nullptr, &mVkDevice) != VK_SUCCESS) {
-            return false;
+            return DAWN_CONTEXT_LOST_ERROR("vkCreateDevice failed");
         }
 
-        return true;
+        return usedKnobs;
     }
 
     void Device::GatherQueueFromDevice() {
         fn.GetDeviceQueue(mVkDevice, mQueueFamily, 0, &mQueue);
     }
 
-    bool Device::RegisterDebugReport() {
+    MaybeError Device::RegisterDebugReport() {
         VkDebugReportCallbackCreateInfoEXT createInfo;
         createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
         createInfo.pNext = nullptr;
@@ -574,10 +561,10 @@
 
         if (fn.CreateDebugReportCallbackEXT(mInstance, &createInfo, nullptr,
                                             &mDebugReportCallback) != VK_SUCCESS) {
-            return false;
+            return DAWN_CONTEXT_LOST_ERROR("vkCreateDebugReportCallbackEXT failed");
         }
 
-        return true;
+        return {};
     }
 
     VKAPI_ATTR VkBool32 VKAPI_CALL
diff --git a/src/dawn_native/vulkan/DeviceVk.h b/src/dawn_native/vulkan/DeviceVk.h
index 35fd591..ae1f940 100644
--- a/src/dawn_native/vulkan/DeviceVk.h
+++ b/src/dawn_native/vulkan/DeviceVk.h
@@ -97,12 +97,13 @@
             TextureBase* texture,
             const TextureViewDescriptor* descriptor) override;
 
-        bool CreateInstance(VulkanGlobalKnobs* usedKnobs,
-                            const std::vector<const char*>& requiredExtensions);
-        bool CreateDevice(VulkanDeviceKnobs* usedKnobs);
+        MaybeError Initialize(const std::vector<const char*>& requiredInstanceExtensions);
+        ResultOrError<VulkanGlobalKnobs> CreateInstance(
+            const std::vector<const char*>& requiredExtensions);
+        ResultOrError<VulkanDeviceKnobs> CreateDevice();
         void GatherQueueFromDevice();
 
-        bool RegisterDebugReport();
+        MaybeError RegisterDebugReport();
         static VKAPI_ATTR VkBool32 VKAPI_CALL
         OnDebugReportCallback(VkDebugReportFlagsEXT flags,
                               VkDebugReportObjectTypeEXT objectType,
@@ -117,8 +118,8 @@
         // the Device is allowed to mutate them through these private methods.
         VulkanFunctions* GetMutableFunctions();
 
-        VulkanGlobalInfo mGlobalInfo;
-        VulkanDeviceInfo mDeviceInfo;
+        VulkanGlobalInfo mGlobalInfo = {};
+        VulkanDeviceInfo mDeviceInfo = {};
 
         DynamicLib mVulkanLib;
 
diff --git a/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp b/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp
index a49aaff..a1da700 100644
--- a/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp
+++ b/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp
@@ -58,7 +58,7 @@
     }
 
     void NativeSwapChainImpl::Init(dawnWSIContextVulkan* /*context*/) {
-        if (!GatherSurfaceInfo(*mDevice, mSurface, &mInfo)) {
+        if (mDevice->ConsumedError(GatherSurfaceInfo(*mDevice, mSurface, &mInfo))) {
             ASSERT(false);
         }
 
diff --git a/src/dawn_native/vulkan/VulkanFunctions.cpp b/src/dawn_native/vulkan/VulkanFunctions.cpp
index 09f6e51..39f3a19 100644
--- a/src/dawn_native/vulkan/VulkanFunctions.cpp
+++ b/src/dawn_native/vulkan/VulkanFunctions.cpp
@@ -22,29 +22,29 @@
 #define GET_GLOBAL_PROC(name)                                                          \
     name = reinterpret_cast<decltype(name)>(GetInstanceProcAddr(nullptr, "vk" #name)); \
     if (name == nullptr) {                                                             \
-        return false;                                                                  \
+        return DAWN_CONTEXT_LOST_ERROR(std::string("Couldn't get proc vk") + #name);   \
     }
 
-    bool VulkanFunctions::LoadGlobalProcs(const DynamicLib& vulkanLib) {
+    MaybeError VulkanFunctions::LoadGlobalProcs(const DynamicLib& vulkanLib) {
         if (!vulkanLib.GetProc(&GetInstanceProcAddr, "vkGetInstanceProcAddr")) {
-            return false;
+            return DAWN_CONTEXT_LOST_ERROR("Couldn't get vkGetInstanceProcAddr");
         }
 
         GET_GLOBAL_PROC(CreateInstance);
         GET_GLOBAL_PROC(EnumerateInstanceExtensionProperties);
         GET_GLOBAL_PROC(EnumerateInstanceLayerProperties);
 
-        return true;
+        return {};
     }
 
 #define GET_INSTANCE_PROC(name)                                                         \
     name = reinterpret_cast<decltype(name)>(GetInstanceProcAddr(instance, "vk" #name)); \
     if (name == nullptr) {                                                              \
-        return false;                                                                   \
+        return DAWN_CONTEXT_LOST_ERROR(std::string("Couldn't get proc vk") + #name);    \
     }
 
-    bool VulkanFunctions::LoadInstanceProcs(VkInstance instance,
-                                            const VulkanGlobalKnobs& usedKnobs) {
+    MaybeError VulkanFunctions::LoadInstanceProcs(VkInstance instance,
+                                                  const VulkanGlobalKnobs& usedKnobs) {
         // Load this proc first so that we can destroy the instance even if some other
         // GET_INSTANCE_PROC fails
         GET_INSTANCE_PROC(DestroyInstance);
@@ -77,16 +77,17 @@
             GET_INSTANCE_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
         }
 
-        return true;
+        return {};
     }
 
-#define GET_DEVICE_PROC(name)                                                       \
-    name = reinterpret_cast<decltype(name)>(GetDeviceProcAddr(device, "vk" #name)); \
-    if (name == nullptr) {                                                          \
-        return false;                                                               \
+#define GET_DEVICE_PROC(name)                                                        \
+    name = reinterpret_cast<decltype(name)>(GetDeviceProcAddr(device, "vk" #name));  \
+    if (name == nullptr) {                                                           \
+        return DAWN_CONTEXT_LOST_ERROR(std::string("Couldn't get proc vk") + #name); \
     }
 
-    bool VulkanFunctions::LoadDeviceProcs(VkDevice device, const VulkanDeviceKnobs& usedKnobs) {
+    MaybeError VulkanFunctions::LoadDeviceProcs(VkDevice device,
+                                                const VulkanDeviceKnobs& usedKnobs) {
         GET_DEVICE_PROC(AllocateCommandBuffers);
         GET_DEVICE_PROC(AllocateDescriptorSets);
         GET_DEVICE_PROC(AllocateMemory);
@@ -215,7 +216,7 @@
             GET_DEVICE_PROC(QueuePresentKHR);
         }
 
-        return true;
+        return {};
     }
 
 }}  // namespace dawn_native::vulkan
diff --git a/src/dawn_native/vulkan/VulkanFunctions.h b/src/dawn_native/vulkan/VulkanFunctions.h
index a9a6a54..e229cb0 100644
--- a/src/dawn_native/vulkan/VulkanFunctions.h
+++ b/src/dawn_native/vulkan/VulkanFunctions.h
@@ -17,6 +17,8 @@
 
 #include "common/vulkan_platform.h"
 
+#include "dawn_native/Error.h"
+
 class DynamicLib;
 
 namespace dawn_native { namespace vulkan {
@@ -27,9 +29,9 @@
     // Stores the Vulkan entry points. Also loads them from the dynamic library
     // and the vkGet*ProcAddress entry points.
     struct VulkanFunctions {
-        bool LoadGlobalProcs(const DynamicLib& vulkanLib);
-        bool LoadInstanceProcs(VkInstance instance, const VulkanGlobalKnobs& usedGlobals);
-        bool LoadDeviceProcs(VkDevice device, const VulkanDeviceKnobs& usedKnobs);
+        MaybeError LoadGlobalProcs(const DynamicLib& vulkanLib);
+        MaybeError LoadInstanceProcs(VkInstance instance, const VulkanGlobalKnobs& usedGlobals);
+        MaybeError LoadDeviceProcs(VkDevice device, const VulkanDeviceKnobs& usedKnobs);
 
         // ---------- Global procs
 
diff --git a/src/dawn_native/vulkan/VulkanInfo.cpp b/src/dawn_native/vulkan/VulkanInfo.cpp
index d7b4a84..625d7c1 100644
--- a/src/dawn_native/vulkan/VulkanInfo.cpp
+++ b/src/dawn_native/vulkan/VulkanInfo.cpp
@@ -38,7 +38,9 @@
     const char kExtensionNameKhrSurface[] = "VK_KHR_surface";
     const char kExtensionNameKhrSwapchain[] = "VK_KHR_swapchain";
 
-    bool GatherGlobalInfo(const Device& device, VulkanGlobalInfo* info) {
+    ResultOrError<VulkanGlobalInfo> GatherGlobalInfo(const Device& device) {
+        VulkanGlobalInfo info = {};
+
         // Gather the info about the instance layers
         {
             uint32_t count = 0;
@@ -47,24 +49,24 @@
             // incomplete otherwise. This means that both values represent a success.
             // This is the same for all Enumarte functions
             if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkEnumerateInstanceLayerProperties");
             }
 
-            info->layers.resize(count);
-            result = device.fn.EnumerateInstanceLayerProperties(&count, info->layers.data());
+            info.layers.resize(count);
+            result = device.fn.EnumerateInstanceLayerProperties(&count, info.layers.data());
             if (result != VK_SUCCESS) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkEnumerateInstanceLayerProperties");
             }
 
-            for (const auto& layer : info->layers) {
+            for (const auto& layer : info.layers) {
                 if (IsLayerName(layer, kLayerNameLunargStandardValidation)) {
-                    info->standardValidation = true;
+                    info.standardValidation = true;
                 }
                 if (IsLayerName(layer, kLayerNameLunargVKTrace)) {
-                    info->vktrace = true;
+                    info.vktrace = true;
                 }
                 if (IsLayerName(layer, kLayerNameRenderDocCapture)) {
-                    info->renderDocCapture = true;
+                    info.renderDocCapture = true;
                 }
             }
         }
@@ -75,65 +77,66 @@
             VkResult result =
                 device.fn.EnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
             if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkEnumerateInstanceExtensionProperties");
             }
 
-            info->extensions.resize(count);
+            info.extensions.resize(count);
             result = device.fn.EnumerateInstanceExtensionProperties(nullptr, &count,
-                                                                    info->extensions.data());
+                                                                    info.extensions.data());
             if (result != VK_SUCCESS) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkEnumerateInstanceExtensionProperties");
             }
 
-            for (const auto& extension : info->extensions) {
+            for (const auto& extension : info.extensions) {
                 if (IsExtensionName(extension, kExtensionNameExtDebugReport)) {
-                    info->debugReport = true;
+                    info.debugReport = true;
                 }
                 if (IsExtensionName(extension, kExtensionNameKhrSurface)) {
-                    info->surface = true;
+                    info.surface = true;
                 }
             }
         }
 
         // TODO(cwallez@chromium:org): Each layer can expose additional extensions, query them?
 
-        return true;
+        return info;
     }
 
-    bool GetPhysicalDevices(const Device& device, std::vector<VkPhysicalDevice>* physicalDevices) {
+    ResultOrError<std::vector<VkPhysicalDevice>> GetPhysicalDevices(const Device& device) {
         VkInstance instance = device.GetInstance();
 
         uint32_t count = 0;
         VkResult result = device.fn.EnumeratePhysicalDevices(instance, &count, nullptr);
         if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
-            return false;
+            return DAWN_CONTEXT_LOST_ERROR("vkEnumeratePhysicalDevices");
         }
 
-        physicalDevices->resize(count);
-        result = device.fn.EnumeratePhysicalDevices(instance, &count, physicalDevices->data());
+        std::vector<VkPhysicalDevice> physicalDevices(count);
+        result = device.fn.EnumeratePhysicalDevices(instance, &count, physicalDevices.data());
         if (result != VK_SUCCESS) {
-            return false;
+            return DAWN_CONTEXT_LOST_ERROR("vkEnumeratePhysicalDevices");
         }
 
-        return true;
+        return physicalDevices;
     }
 
-    bool GatherDeviceInfo(const Device& device,
-                          VkPhysicalDevice physicalDevice,
-                          VulkanDeviceInfo* info) {
+    ResultOrError<VulkanDeviceInfo> GatherDeviceInfo(const Device& device,
+                                                     VkPhysicalDevice physicalDevice) {
+        VulkanDeviceInfo info = {};
+
         // Gather general info about the device
-        device.fn.GetPhysicalDeviceProperties(physicalDevice, &info->properties);
-        device.fn.GetPhysicalDeviceFeatures(physicalDevice, &info->features);
+        device.fn.GetPhysicalDeviceProperties(physicalDevice, &info.properties);
+        device.fn.GetPhysicalDeviceFeatures(physicalDevice, &info.features);
 
         // Gather info about device memory.
         {
             VkPhysicalDeviceMemoryProperties memory;
             device.fn.GetPhysicalDeviceMemoryProperties(physicalDevice, &memory);
 
-            info->memoryTypes.assign(memory.memoryTypes,
-                                     memory.memoryTypes + memory.memoryTypeCount);
-            info->memoryHeaps.assign(memory.memoryHeaps,
-                                     memory.memoryHeaps + memory.memoryHeapCount);
+            info.memoryTypes.assign(memory.memoryTypes,
+                                    memory.memoryTypes + memory.memoryTypeCount);
+            info.memoryHeaps.assign(memory.memoryHeaps,
+                                    memory.memoryHeaps + memory.memoryHeapCount);
         }
 
         // Gather info about device queue families
@@ -141,9 +144,9 @@
             uint32_t count = 0;
             device.fn.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &count, nullptr);
 
-            info->queueFamilies.resize(count);
+            info.queueFamilies.resize(count);
             device.fn.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &count,
-                                                             info->queueFamilies.data());
+                                                             info.queueFamilies.data());
         }
 
         // Gather the info about the device layers
@@ -152,14 +155,14 @@
             VkResult result =
                 device.fn.EnumerateDeviceLayerProperties(physicalDevice, &count, nullptr);
             if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkEnumerateDeviceLayerProperties");
             }
 
-            info->layers.resize(count);
+            info.layers.resize(count);
             result = device.fn.EnumerateDeviceLayerProperties(physicalDevice, &count,
-                                                              info->layers.data());
+                                                              info.layers.data());
             if (result != VK_SUCCESS) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkEnumerateDeviceLayerProperties");
             }
         }
 
@@ -169,29 +172,31 @@
             VkResult result = device.fn.EnumerateDeviceExtensionProperties(physicalDevice, nullptr,
                                                                            &count, nullptr);
             if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkEnumerateDeviceExtensionProperties");
             }
 
-            info->extensions.resize(count);
+            info.extensions.resize(count);
             result = device.fn.EnumerateDeviceExtensionProperties(physicalDevice, nullptr, &count,
-                                                                  info->extensions.data());
+                                                                  info.extensions.data());
             if (result != VK_SUCCESS) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkEnumerateDeviceExtensionProperties");
             }
 
-            for (const auto& extension : info->extensions) {
+            for (const auto& extension : info.extensions) {
                 if (IsExtensionName(extension, kExtensionNameKhrSwapchain)) {
-                    info->swapchain = true;
+                    info.swapchain = true;
                 }
             }
         }
 
         // TODO(cwallez@chromium.org): gather info about formats
 
-        return true;
+        return info;
     }
 
-    bool GatherSurfaceInfo(const Device& device, VkSurfaceKHR surface, VulkanSurfaceInfo* info) {
+    MaybeError GatherSurfaceInfo(const Device& device,
+                                 VkSurfaceKHR surface,
+                                 VulkanSurfaceInfo* info) {
         VkPhysicalDevice physicalDevice = device.GetPhysicalDevice();
 
         // Get the surface capabilities
@@ -199,7 +204,7 @@
             VkResult result = device.fn.GetPhysicalDeviceSurfaceCapabilitiesKHR(
                 physicalDevice, surface, &info->capabilities);
             if (result != VK_SUCCESS) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
             }
         }
 
@@ -214,7 +219,7 @@
                                                                                surface, &supported);
 
                 if (result != VK_SUCCESS) {
-                    return false;
+                    return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfaceSupportKHR");
                 }
 
                 info->supportedQueueFamilies[i] = (supported == VK_TRUE);
@@ -227,14 +232,14 @@
             VkResult result = device.fn.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface,
                                                                            &count, nullptr);
             if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfaceFormatsKHR");
             }
 
             info->formats.resize(count);
             result = device.fn.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &count,
                                                                   info->formats.data());
             if (result != VK_SUCCESS) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfaceFormatsKHR");
             }
         }
 
@@ -244,18 +249,18 @@
             VkResult result = device.fn.GetPhysicalDeviceSurfacePresentModesKHR(
                 physicalDevice, surface, &count, nullptr);
             if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfacePresentModesKHR");
             }
 
             info->presentModes.resize(count);
             result = device.fn.GetPhysicalDeviceSurfacePresentModesKHR(
                 physicalDevice, surface, &count, info->presentModes.data());
             if (result != VK_SUCCESS) {
-                return false;
+                return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfacePresentModesKHR");
             }
         }
 
-        return true;
+        return {};
     }
 
 }}  // namespace dawn_native::vulkan
diff --git a/src/dawn_native/vulkan/VulkanInfo.h b/src/dawn_native/vulkan/VulkanInfo.h
index b87b666..383ea9b 100644
--- a/src/dawn_native/vulkan/VulkanInfo.h
+++ b/src/dawn_native/vulkan/VulkanInfo.h
@@ -16,6 +16,7 @@
 #define DAWNNATIVE_VULKAN_VULKANINFO_H_
 
 #include "common/vulkan_platform.h"
+#include "dawn_native/Error.h"
 
 #include <vector>
 
@@ -76,13 +77,13 @@
         std::vector<bool> supportedQueueFamilies;
     };
 
-    bool GatherGlobalInfo(const Device& device, VulkanGlobalInfo* info);
-    bool GetPhysicalDevices(const Device& device, std::vector<VkPhysicalDevice>* physicalDevices);
-    bool GatherDeviceInfo(const Device& device,
-                          VkPhysicalDevice physicalDevice,
-                          VulkanDeviceInfo* info);
-    bool GatherSurfaceInfo(const Device& device, VkSurfaceKHR surface, VulkanSurfaceInfo* info);
-
+    ResultOrError<VulkanGlobalInfo> GatherGlobalInfo(const Device& device);
+    ResultOrError<std::vector<VkPhysicalDevice>> GetPhysicalDevices(const Device& device);
+    ResultOrError<VulkanDeviceInfo> GatherDeviceInfo(const Device& device,
+                                                     VkPhysicalDevice physicalDevice);
+    MaybeError GatherSurfaceInfo(const Device& device,
+                                 VkSurfaceKHR surface,
+                                 VulkanSurfaceInfo* info);
 }}  // namespace dawn_native::vulkan
 
 #endif  // DAWNNATIVE_VULKAN_VULKANINFO_H_