diff --git a/BUILD.gn b/BUILD.gn index 72858aedec..9a8fe4c72f 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -609,6 +609,8 @@ source_set("libdawn_native_sources") { "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 23ec3258e3..f76e6382e9 100644 --- a/src/dawn_native/Error.h +++ b/src/dawn_native/Error.h @@ -61,7 +61,7 @@ namespace dawn_native { 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 @@ namespace dawn_native { 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 1a33e612c2..074f334d61 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 @@ -485,9 +486,8 @@ namespace dawn_native { namespace vulkan { createInfo.enabledExtensionCount = static_cast(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 @@ namespace dawn_native { namespace vulkan { 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 @@ namespace dawn_native { namespace vulkan { 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 0000000000..a01475c23f --- /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 + +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 ""; + } + } + + 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 0000000000..3dedece1ad --- /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 a5aec6ce21..f7d5bc82ea 100644 --- a/src/tests/unittests/ErrorTests.cpp +++ b/src/tests/unittests/ErrorTests.cpp @@ -246,6 +246,29 @@ TEST(ErrorTests, TRY_RESULT_ConversionToError) { delete errorData; } +// Check a ResultOrError can be DAWN_TRY_ASSIGNED in a function that returns an Error +// Version without Result +TEST(ErrorTests, TRY_RESULT_ConversionToErrorNonPointer) { + auto ReturnError = []() -> ResultOrError { + 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 @@ TEST(ErrorTests, TRY_ConversionToErrorOrResult) { 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 +TEST(ErrorTests, TRY_ConversionToErrorOrResultNonPointer) { + auto ReturnError = []() -> MaybeError { + return DAWN_VALIDATION_ERROR(dummyErrorMessage); + }; + + auto Try = [ReturnError]() -> ResultOrError{ + DAWN_TRY(ReturnError()); + return 42; + }; + + ResultOrError result = Try(); + ASSERT_TRUE(result.IsError()); + + ErrorData* errorData = result.AcquireError(); + ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); + delete errorData; +} + } // anonymous namespace