VK_NULL_HANDLE 始终为 0;为什么不是 nullptr?
VK_NULL_HANDLE is always 0; Why not nullptr?
在大多数情况下,您可以将 VK_NULL_HANDLE
分配给 VK_DEFINE_HANDLE(object)
或 VK_DEFINE_NON_DISPATCHABLE_HANDLE(object)
定义的任何句柄,但 std::exchange()
几乎无法设置此值所有案例。
在大多数情况下,我必须调用 std::exchange(m_dispatchableHandle, nullptr)
和 std::exchange(m_nonDispatchableHandle, nullptr)
但是在x86上,由于VK_DEFINE_NON_DISPATCHABLE_HANDLE
的重新定义,nullptr是无效的。我必须将 std::exchange
与 NULL
、0
或(最后)VK_NULL_HANDLE
.
一起使用
我的问题:在遵循 VK_DEFINE_HANDLE
宏模式时,不应该像下面这样定义两个空句柄宏吗?
#define VK_NULL_HANDLE nullptr
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define VK_NON_DISPATCHABLE_NULL_HANDLE nullptr
#else
#define VK_NON_DISPATCHABLE_NULL_HANDLE 0
#endif
如果不出意外,#define VK_NULL_HANDLE nullptr
总体上似乎更实用。
我可能误解了 API 应该如何使用,所以我分享了有问题的代码:一个转移句柄并用 NULL
填充旧对象的移动构造函数或 VK_NULL_HANDLE
。通过仔细管理所有权,可以简单地设计 class 并处理 vkDestroy*
等。阿尔。在它的析构函数中。
class RenderContext
{
public:
RenderContext(VkPhysicalDevice physicalDevice, uint32_t gfxQueueFamilyIdx, uint32_t presentQueueFamilyIdx);
RenderContext(const RenderContext& other) = delete;
RenderContext& operator=(const RenderContext& other) = delete;
RenderContext(RenderContext&& other) noexcept;
RenderContext&& operator=(RenderContext&& other) = delete;
~RenderContext();
private:
VkDevice _device;
VkCommandPool _gCmdPool;
VkCommandPool _pCmdPool;
VkQueue _gQueue;
VkQueue _pQueue;
};
RenderContext::RenderContext(VkPhysicalDevice physicalDevice, uint32_t gfxQueueFamilyIdx, uint32_t presentQueueFamilyIdx) :
_device(VK_NULL_HANDLE),
_gCmdPool(VK_NULL_HANDLE),
_pCmdPool(VK_NULL_HANDLE),
_gQueue(VK_NULL_HANDLE),
_pQueue(VK_NULL_HANDLE)
{
// ...
}
RenderContext::RenderContext(RenderContext&& other) noexcept :
_device(std::exchange(other._device, nullptr)),
_gCmdPool(std::exchange(other._gCmdPool, VK_NULL_HANDLE)),
_pCmdPool(std::exchange(other._pCmdPool, VK_NULL_HANDLE)),
_gQueue(std::exchange(other._gQueue, nullptr)),
_pQueue(std::exchange(other._pQueue, nullptr))
{}
RenderContext::~RenderContext()
{
vkDestroyCommandPool(_device, _pCmdPool, nullptr);
vkDestroyCommandPool(_device, _gCmdPool, nullptr);
vkDestroyDevice(_device, nullptr);
}
C++ 中的模板需要精确的类型,而不仅仅是兼容的类型,才能正确实例化。因此 C 的 NULL
(定义为 0
)可能是个问题。 0
也可能是一个问题,因为它是 int
,而不是 uint64_t
,它是不可分派句柄的 ABI(可以存储在 64 位指针中以获得某种类型安全性C).这在处理来自 C++(或一般)的 C 库时并不新鲜。
其余是作者提出的设计问题和建议,因此不适合 Whosebug。问题跟踪系统可在 https://github.com/KhronosGroup/Vulkan-Docs/issues 获得。从表面上看,你的建议对我来说很有意义。他们可能不想让它普及,但另外,这样做可能是 #ifdef __cplusplus #define VK_NULL_HANDLE nullptr
.
或者,还有 Vulkan-Hpp,它应该向 Vulkan 公开更多 C++ 式绑定。
目前调用模板函数的正确方法是std::exchange(m_nonDispatchableHandle, decltype(m_nonDispatchableHandle)(VK_NULL_HANDLE));
。
In most cases, VK_NULL_HANDLE
can be assigned to any handle defined by VK_DEFINE_HANDLE(object)
or VK_DEFINE_NON_DISPATCHABLE_HANDLE(object)
错了。您可以 摆脱它 因为 C 和 C++ 让您如此。但是Vulkan的规范很明确:
The reserved values VK_NULL_HANDLE
and NULL
can be used in place of valid non-dispatchable handles and dispatchable handles, respectively
也就是说,VK_NULL_HANDLE
仅 用于不可分派的句柄。 C/C++ 语言允许您将 VK_NULL_HANDLE
的值分配给可分派的句柄,这只是语言的一个功能,Vulkan 本身的行为没有定义。
您永远不应该尝试在可分派句柄和不可分派句柄之间 std::exchange
,就像您永远不应该在两种不同类型之间尝试 std::exchange
一样。
在大多数情况下,您可以将 VK_NULL_HANDLE
分配给 VK_DEFINE_HANDLE(object)
或 VK_DEFINE_NON_DISPATCHABLE_HANDLE(object)
定义的任何句柄,但 std::exchange()
几乎无法设置此值所有案例。
在大多数情况下,我必须调用 std::exchange(m_dispatchableHandle, nullptr)
和 std::exchange(m_nonDispatchableHandle, nullptr)
但是在x86上,由于VK_DEFINE_NON_DISPATCHABLE_HANDLE
的重新定义,nullptr是无效的。我必须将 std::exchange
与 NULL
、0
或(最后)VK_NULL_HANDLE
.
我的问题:在遵循 VK_DEFINE_HANDLE
宏模式时,不应该像下面这样定义两个空句柄宏吗?
#define VK_NULL_HANDLE nullptr
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define VK_NON_DISPATCHABLE_NULL_HANDLE nullptr
#else
#define VK_NON_DISPATCHABLE_NULL_HANDLE 0
#endif
如果不出意外,#define VK_NULL_HANDLE nullptr
总体上似乎更实用。
我可能误解了 API 应该如何使用,所以我分享了有问题的代码:一个转移句柄并用 NULL
填充旧对象的移动构造函数或 VK_NULL_HANDLE
。通过仔细管理所有权,可以简单地设计 class 并处理 vkDestroy*
等。阿尔。在它的析构函数中。
class RenderContext
{
public:
RenderContext(VkPhysicalDevice physicalDevice, uint32_t gfxQueueFamilyIdx, uint32_t presentQueueFamilyIdx);
RenderContext(const RenderContext& other) = delete;
RenderContext& operator=(const RenderContext& other) = delete;
RenderContext(RenderContext&& other) noexcept;
RenderContext&& operator=(RenderContext&& other) = delete;
~RenderContext();
private:
VkDevice _device;
VkCommandPool _gCmdPool;
VkCommandPool _pCmdPool;
VkQueue _gQueue;
VkQueue _pQueue;
};
RenderContext::RenderContext(VkPhysicalDevice physicalDevice, uint32_t gfxQueueFamilyIdx, uint32_t presentQueueFamilyIdx) :
_device(VK_NULL_HANDLE),
_gCmdPool(VK_NULL_HANDLE),
_pCmdPool(VK_NULL_HANDLE),
_gQueue(VK_NULL_HANDLE),
_pQueue(VK_NULL_HANDLE)
{
// ...
}
RenderContext::RenderContext(RenderContext&& other) noexcept :
_device(std::exchange(other._device, nullptr)),
_gCmdPool(std::exchange(other._gCmdPool, VK_NULL_HANDLE)),
_pCmdPool(std::exchange(other._pCmdPool, VK_NULL_HANDLE)),
_gQueue(std::exchange(other._gQueue, nullptr)),
_pQueue(std::exchange(other._pQueue, nullptr))
{}
RenderContext::~RenderContext()
{
vkDestroyCommandPool(_device, _pCmdPool, nullptr);
vkDestroyCommandPool(_device, _gCmdPool, nullptr);
vkDestroyDevice(_device, nullptr);
}
C++ 中的模板需要精确的类型,而不仅仅是兼容的类型,才能正确实例化。因此 C 的 NULL
(定义为 0
)可能是个问题。 0
也可能是一个问题,因为它是 int
,而不是 uint64_t
,它是不可分派句柄的 ABI(可以存储在 64 位指针中以获得某种类型安全性C).这在处理来自 C++(或一般)的 C 库时并不新鲜。
其余是作者提出的设计问题和建议,因此不适合 Whosebug。问题跟踪系统可在 https://github.com/KhronosGroup/Vulkan-Docs/issues 获得。从表面上看,你的建议对我来说很有意义。他们可能不想让它普及,但另外,这样做可能是 #ifdef __cplusplus #define VK_NULL_HANDLE nullptr
.
或者,还有 Vulkan-Hpp,它应该向 Vulkan 公开更多 C++ 式绑定。
目前调用模板函数的正确方法是std::exchange(m_nonDispatchableHandle, decltype(m_nonDispatchableHandle)(VK_NULL_HANDLE));
。
In most cases,
VK_NULL_HANDLE
can be assigned to any handle defined byVK_DEFINE_HANDLE(object)
orVK_DEFINE_NON_DISPATCHABLE_HANDLE(object)
错了。您可以 摆脱它 因为 C 和 C++ 让您如此。但是Vulkan的规范很明确:
The reserved values
VK_NULL_HANDLE
andNULL
can be used in place of valid non-dispatchable handles and dispatchable handles, respectively
也就是说,VK_NULL_HANDLE
仅 用于不可分派的句柄。 C/C++ 语言允许您将 VK_NULL_HANDLE
的值分配给可分派的句柄,这只是语言的一个功能,Vulkan 本身的行为没有定义。
您永远不应该尝试在可分派句柄和不可分派句柄之间 std::exchange
,就像您永远不应该在两种不同类型之间尝试 std::exchange
一样。