我一直在更改一些vulkan代码以使用vulkan.hpp结构和方法。

因为我喜欢RAII,所以我使用唯一包装器来不必明确地处理资源管理。

到目前为止,我已经能够为每个包装方法创建2个版本,一个版本创建一个非唯一对象,另一个版本调用第一个,然后从第一个初始化一个唯一的句柄。例:

vector<vk::UniqueFramebuffer> CreateFramebuffersUnique(vk::SurfaceKHR surface,
    vk::PhysicalDevice phys_device, vk::Device device, vk::RenderPass render_pass,
    vector<vk::ImageView> image_views)
{
    auto framebuffers =
        CreateFramebuffers(surface, phys_device, device, render_pass, image_views);
    vector<vk::UniqueFramebuffer> u_framebuffers;
    for(auto &fb : framebuffers)
        u_framebuffers.push_back(vk::UniqueFramebuffer(fb, device));

    return u_framebuffers;
}


上面的方法创建一个帧缓冲区数组,然后在返回它之前将每个帧缓冲区重新初始化为唯一的帧缓冲区。

我尝试对命令缓冲区执行相同的操作:

vector<vk::UniqueCommandBuffer> CreateCommandBuffersUnique(vk::SurfaceKHR &surface,
    vk::PhysicalDevice &phys_device, vk::Device &device, vk::RenderPass &render_pass,
    vk::Pipeline &graphics_pipeline, vk::CommandPool &command_pool,
    vector<vk::Framebuffer> &framebuffers)
{
    auto command_buffers = CreateCommandBuffers(surface, phys_device, device, render_pass,
        graphics_pipeline, command_pool, framebuffers);

    vector<vk::UniqueCommandBuffer> u_command_buffers;
    for(auto &cb : command_buffers)
        u_command_buffers.push_back(vk::UniqueCommandBuffer(cb, device));

    return u_command_buffers;
}


以上从技术上讲是有效的,但是在程序终止时,验证层会在重新分配资源时抱怨错误:

validation layer: vkFreeCommandBuffers: required parameter commandPool specified as VK_NULL_HANDLE
UNASSIGNED-GeneralParameterError-RequiredParameter
4096
validation layer: Invalid CommandPool Object 0x0. The Vulkan spec states: commandPool must be a valid VkCommandPool handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkFreeCommandBuffers-commandPool-parameter)
VUID-vkFreeCommandBuffers-commandPool-parameter


发生这种情况是因为唯一句柄的命令池字段设置不正确:

(gdb) p t_command_buffers[0]
$6 = {<vk::PoolFree<vk::Device, vk::CommandPool, vk::DispatchLoaderStatic>> = {m_owner = {m_device = 0x555555ec14e0}, m_pool = {m_commandPool = 0x0},
    m_dispatch = 0x7fffffffe2f7}, m_value = {m_commandBuffer = 0x555555fe6390}}


我检查了一下,尽管没有commandBuffer.getPool(),但没有setPool()。

有关正确设置字段的任何建议?

最佳答案

您不包括要从内部从CreateCommandBuffers调用的CreateCommandBuffersUnique函数的源代码或签名。但是,假设它返回的类型为std::vector<vk::CommandBuffer>

看来您正在遍历这些并将它们手动包装在vk::UniqueCommandBuffer实例中。但是,您正在传递cb(这里假定为vk::CommandBuffervk::DeviceUniqueCommandBuffer构造函数)

u_command_buffers.push_back(vk::UniqueCommandBuffer(cb, device));


除非vk::Device具有operator ()(),否则我实际上还不清楚如何编译。无论如何,vk::UniqueCommandBuffer的第二个参数应该是一个删除对象。

因此,事实证明,所有UniqueXXX类型都从UniqueHandle<>派生而来,而UniqueHandleTraits<...>又从每种类型专用的deleter中派生出来,以便为其提供默认的UniqueHandleTraits<...>类型。大多数ObjectDestroy<...>专长都使用Device模板,因为大多数对象仅需要其创建的UniqueHandleTraits<CommandBuffer>即可销毁它们。但是,UniqueHandleTraits<DescriptorSet>PoolFree<...>专长使用{}作为其删除器。

因此,您使用

vk::UniqueCommandBuffer(cb, device));


隐含地变成

vk::UniqueCommandBuffer(cb,
    vk::PoolFree<Device, CommandPool,Dispatch> { device, {}, {} }
)


device之后的vk::Device::allocateCommandBuffersUnique是应该指定池的位置。

请参见vk::Device::allocateCommandBuffersUnique中的相应代码

PoolFree<Device,CommandPool,Dispatch> deleter( *this, allocateInfo.commandPool, d );
for ( size_t i=0 ; i<allocateInfo.commandBufferCount ; i++ )
{
  commandBuffers.push_back( UniqueCommandBuffer( buffer[i], deleter ) );
}


要修复代码,您需要使用UniqueCommandBuffer或复制其行为,特别是创建一个deleter对象或lambda并将其作为第二个参数传递给UniqueHandleTraits ctor。

根据我对的检查,看起来您只需更改以下行就可以修复代码:

    u_framebuffers.push_back(vk::UniqueFramebuffer(fb, device));




    u_framebuffers.push_back(vk::UniqueFramebuffer(fb, { device, command_pool }));

关于c++ - 如何正确调用命令缓冲区的vulkan.hpp构造函数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55885882/

10-11 18:28