This question is regarding exception handling in Vulkan-Hpp (official Vulkan C++ bindings).
I wrote a small application using Vulkan-Hpp without
VULKAN_HPP_NO_EXCEPTIONS
VULKAN_HPP_NO_EXCEPTIONS
VULKAN_HPP_NO_EXCEPTIONS
If exception handling is disabled by definingVULKAN_HPP_NO_EXCEPTIONS
is a struct which contains the returnResultValue<SomeType>::type
value and the error code in the fields result and value.
surface = instance.createWin32SurfaceKHR(surfaceCreateInfo);
vk::ResultValue<vk::SurfaceKHR> surfaceResult = instance.createWin32SurfaceKHR(surfaceCreateInfo);
if (surfaceResult.result == vk::Result::eSuccess) {
surface = surfaceResult.value;
}
VULKAN_HPP_NO_EXCEPTIONS
VULKAN_HPP_NO_EXCEPTIONS
The principle reason exceptions can be disabled is because many game developers for various platforms turn off exception handling at the compiler level. On some platforms, exception handling is flat out not supported. Those platforms still need a reasonable means to deal with errors, and that requires a different API.
Exceptions have been a hotly debated subject in C++ and likely always will be. While C++ programmers will agree that exceptions should only be used in exceptional circumstances, the line between "exceptional circumstances" and "expected behavior" is ultimately in the eye of the beholder.
Personally, I would consider Vulkan errors to be "exceptional circumstances". Device lost and OOM errors are not things you frequently expect to happen. Plus, your response to them will likely be decidedly non-local; code higher up in the call stack will be what actually deals with it.
Furthermore, many of the functions that error are not the functions commonly encountered in performance critical Vulkan code (vkCmd*
, and such). After all, usage errors are supposed to be handled by validation layers and should be impossible at runtime. Errors are usually given for object creation/destruction, and allocations, which are not things you do in the middle of building command buffers.
The erroring function most likely to be found in performance-critical code is vkAllocateDescriptorSets
. And while it can error out, can only do so for memory fragmentation reasons. The standard actually requires this:
Any returned error other than
VK_ERROR_OUT_OF_POOL_MEMORY_KHR
orVK_ERROR_FRAGMENTED_POOL
does not imply its usual meaning: applications should assume that the allocation failed due to fragmentation, and create a new descriptor pool.
Fragmentation is something that you can usually prevent, if you have firm control over your input data. Given such control, you can ensure that you never get errors when allocating from descriptor pools.
vkBegin/EndCommandBuffer
can error, but only for OOM reasons. Which typically means that there's little you can do to recover, so performance is irrelevant.
The commands that give you serious runtime errors that require actions are typically device commands. And you don't issue such commands in the middle of rendering; vkQueueSubmit
is the one exception, and that's at the end of rendering (or beginning; however you want to see it).
This is probably why throwing in VK_HPP is the default.