Vulkan: Print the VkResult value on device creation failure.

This adds a CheckVkSuccess utility function that adds the VkResult value
to the context lost error message.

Also adds a small fix to dawn_native/Error.h interoperability between
MaybeError and ResultOrError<NonPointer> with tests.

BUG=chromium:917555
BUG=dawn:79

Change-Id: Icc01122d62d83693fc0ea3f26b272f2372fd3087
Reviewed-on: https://dawn-review.googlesource.com/c/3623
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 72858ae..9a8fe4c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -609,6 +609,8 @@
       "src/dawn_native/vulkan/TextureVk.h",
       "src/dawn_native/vulkan/UtilsVulkan.cpp",
       "src/dawn_native/vulkan/UtilsVulkan.h",
+      "src/dawn_native/vulkan/VulkanError.cpp",
+      "src/dawn_native/vulkan/VulkanError.h",
       "src/dawn_native/vulkan/VulkanFunctions.cpp",
       "src/dawn_native/vulkan/VulkanFunctions.h",
       "src/dawn_native/vulkan/VulkanInfo.cpp",
diff --git a/src/dawn_native/Error.h b/src/dawn_native/Error.h
index 23ec325..f76e638 100644
--- a/src/dawn_native/Error.h
+++ b/src/dawn_native/Error.h
@@ -61,7 +61,7 @@
         if (DAWN_UNLIKELY(DAWN_LOCAL_VAR.IsError())) {            \
             ErrorData* error = DAWN_LOCAL_VAR.AcquireError();     \
             AppendBacktrace(error, __FILE__, __func__, __LINE__); \
-            return {error};                                       \
+            return {std::move(error)};                            \
         }                                                         \
     }                                                             \
     for (;;)                                                      \
@@ -75,7 +75,7 @@
         if (DAWN_UNLIKELY(DAWN_LOCAL_VAR.IsError())) {            \
             ErrorData* error = DAWN_LOCAL_VAR.AcquireError();     \
             AppendBacktrace(error, __FILE__, __func__, __LINE__); \
-            return {error};                                       \
+            return {std::move(error)};                            \
         }                                                         \
         VAR = DAWN_LOCAL_VAR.AcquireSuccess();                    \
     }                                                             \
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index 1a33e61..074f334 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -37,6 +37,7 @@
 #include "dawn_native/vulkan/ShaderModuleVk.h"
 #include "dawn_native/vulkan/SwapChainVk.h"
 #include "dawn_native/vulkan/TextureVk.h"
+#include "dawn_native/vulkan/VulkanError.h"
 
 #include <spirv-cross/spirv_cross.hpp>
 
@@ -485,9 +486,8 @@
         createInfo.enabledExtensionCount = static_cast<uint32_t>(extensionsToRequest.size());
         createInfo.ppEnabledExtensionNames = extensionsToRequest.data();
 
-        if (fn.CreateInstance(&createInfo, nullptr, &mInstance) != VK_SUCCESS) {
-            return DAWN_CONTEXT_LOST_ERROR("vkCreateInstance failed");
-        }
+        DAWN_TRY(CheckVkSuccess(fn.CreateInstance(&createInfo, nullptr, &mInstance),
+                                "vkCreateInstance"));
 
         return usedKnobs;
     }
@@ -554,9 +554,8 @@
         createInfo.ppEnabledExtensionNames = extensionsToRequest.data();
         createInfo.pEnabledFeatures = &usedKnobs.features;
 
-        if (fn.CreateDevice(mPhysicalDevice, &createInfo, nullptr, &mVkDevice) != VK_SUCCESS) {
-            return DAWN_CONTEXT_LOST_ERROR("vkCreateDevice failed");
-        }
+        DAWN_TRY(CheckVkSuccess(fn.CreateDevice(mPhysicalDevice, &createInfo, nullptr, &mVkDevice),
+                                "vkCreateDevice"));
 
         return usedKnobs;
     }
@@ -573,12 +572,9 @@
         createInfo.pfnCallback = Device::OnDebugReportCallback;
         createInfo.pUserData = this;
 
-        if (fn.CreateDebugReportCallbackEXT(mInstance, &createInfo, nullptr,
-                                            &mDebugReportCallback) != VK_SUCCESS) {
-            return DAWN_CONTEXT_LOST_ERROR("vkCreateDebugReportCallbackEXT failed");
-        }
-
-        return {};
+        return CheckVkSuccess(
+            fn.CreateDebugReportCallbackEXT(mInstance, &createInfo, nullptr, &mDebugReportCallback),
+            "vkCreateDebugReportcallback");
     }
 
     VKAPI_ATTR VkBool32 VKAPI_CALL
diff --git a/src/dawn_native/vulkan/VulkanError.cpp b/src/dawn_native/vulkan/VulkanError.cpp
new file mode 100644
index 0000000..a01475c
--- /dev/null
+++ b/src/dawn_native/vulkan/VulkanError.cpp
@@ -0,0 +1,73 @@
+// Copyright 2019 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn_native/vulkan/VulkanError.h"
+
+#include <string>
+
+namespace dawn_native { namespace vulkan {
+
+    const char* VkResultAsString(VkResult result) {
+        switch (result) {
+            case VK_SUCCESS:
+                return "VK_SUCCESS";
+            case VK_NOT_READY:
+                return "VK_NOT_READY";
+            case VK_TIMEOUT:
+                return "VK_TIMEOUT";
+            case VK_EVENT_SET:
+                return "VK_EVENT_SET";
+            case VK_EVENT_RESET:
+                return "VK_EVENT_RESET";
+            case VK_INCOMPLETE:
+                return "VK_INCOMPLETE";
+            case VK_ERROR_OUT_OF_HOST_MEMORY:
+                return "VK_ERROR_OUT_OF_HOST_MEMORY";
+            case VK_ERROR_OUT_OF_DEVICE_MEMORY:
+                return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
+            case VK_ERROR_INITIALIZATION_FAILED:
+                return "VK_ERROR_INITIALIZATION_FAILED";
+            case VK_ERROR_DEVICE_LOST:
+                return "VK_ERROR_DEVICE_LOST";
+            case VK_ERROR_MEMORY_MAP_FAILED:
+                return "VK_ERROR_MEMORY_MAP_FAILED";
+            case VK_ERROR_LAYER_NOT_PRESENT:
+                return "VK_ERROR_LAYER_NOT_PRESENT";
+            case VK_ERROR_EXTENSION_NOT_PRESENT:
+                return "VK_ERROR_EXTENSION_NOT_PRESENT";
+            case VK_ERROR_FEATURE_NOT_PRESENT:
+                return "VK_ERROR_FEATURE_NOT_PRESENT";
+            case VK_ERROR_INCOMPATIBLE_DRIVER:
+                return "VK_ERROR_INCOMPATIBLE_DRIVER";
+            case VK_ERROR_TOO_MANY_OBJECTS:
+                return "VK_ERROR_TOO_MANY_OBJECTS";
+            case VK_ERROR_FORMAT_NOT_SUPPORTED:
+                return "VK_ERROR_FORMAT_NOT_SUPPORTED";
+            case VK_ERROR_FRAGMENTED_POOL:
+                return "VK_ERROR_FRAGMENTED_POOL";
+            default:
+                return "<Unknown VkResult>";
+        }
+    }
+
+    MaybeError CheckVkSuccess(VkResult result, const char* context) {
+        if (DAWN_LIKELY(result == VK_SUCCESS)) {
+            return {};
+        }
+
+        std::string message = std::string(context) + " failed with " + VkResultAsString(result);
+        return DAWN_CONTEXT_LOST_ERROR(message);
+    }
+
+}}  // namespace dawn_native::vulkan
diff --git a/src/dawn_native/vulkan/VulkanError.h b/src/dawn_native/vulkan/VulkanError.h
new file mode 100644
index 0000000..3dedece
--- /dev/null
+++ b/src/dawn_native/vulkan/VulkanError.h
@@ -0,0 +1,34 @@
+// Copyright 2019 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef DAWNNATIVE_VULKAN_VULKANERROR_H_
+#define DAWNNATIVE_VULKAN_VULKANERROR_H_
+
+#include "common/vulkan_platform.h"
+#include "dawn_native/Error.h"
+
+namespace dawn_native { namespace vulkan {
+
+    // Returns a string version of the result.
+    const char* VkResultAsString(VkResult result);
+
+    // Returns a success only if result if VK_SUCCESS, an error with the context and stringified
+    // result value instead. Can be used like this:
+    //
+    //   DAWN_TRY(CheckVkSuccess(vkDoSomething, "doing something"));
+    MaybeError CheckVkSuccess(VkResult result, const char* context);
+
+}}  // namespace dawn_native::vulkan
+
+#endif  // DAWNNATIVE_VULKAN_VULKANERROR_H_
diff --git a/src/tests/unittests/ErrorTests.cpp b/src/tests/unittests/ErrorTests.cpp
index a5aec6c..f7d5bc8 100644
--- a/src/tests/unittests/ErrorTests.cpp
+++ b/src/tests/unittests/ErrorTests.cpp
@@ -246,6 +246,29 @@
     delete errorData;
 }
 
+// Check a ResultOrError can be DAWN_TRY_ASSIGNED in a function that returns an Error
+// Version without Result<E*, T*>
+TEST(ErrorTests, TRY_RESULT_ConversionToErrorNonPointer) {
+    auto ReturnError = []() -> ResultOrError<int> {
+        return DAWN_VALIDATION_ERROR(dummyErrorMessage);
+    };
+
+    auto Try = [ReturnError]() -> MaybeError {
+        int result = 0;
+        DAWN_TRY_ASSIGN(result, ReturnError());
+        DAWN_UNUSED(result);
+
+        return {};
+    };
+
+    MaybeError result = Try();
+    ASSERT_TRUE(result.IsError());
+
+    ErrorData* errorData = result.AcquireError();
+    ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
+    delete errorData;
+}
+
 // Check a MaybeError can be DAWN_TRIED in a function that returns an ResultOrError
 // Check DAWN_TRY handles errors correctly.
 TEST(ErrorTests, TRY_ConversionToErrorOrResult) {
@@ -266,4 +289,24 @@
     delete errorData;
 }
 
+// Check a MaybeError can be DAWN_TRIED in a function that returns an ResultOrError
+// Check DAWN_TRY handles errors correctly. Version without Result<E*, T*>
+TEST(ErrorTests, TRY_ConversionToErrorOrResultNonPointer) {
+    auto ReturnError = []() -> MaybeError {
+        return DAWN_VALIDATION_ERROR(dummyErrorMessage);
+    };
+
+    auto Try = [ReturnError]() -> ResultOrError<int>{
+        DAWN_TRY(ReturnError());
+        return 42;
+    };
+
+    ResultOrError<int> result = Try();
+    ASSERT_TRUE(result.IsError());
+
+    ErrorData* errorData = result.AcquireError();
+    ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
+    delete errorData;
+}
+
 }  // anonymous namespace