代码之家  ›  专栏  ›  技术社区  ›  Makogan

如何为命令缓冲区正确调用vulkan.hpp构造函数?

  •  0
  • Makogan  · 技术社区  · 7 年前

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

    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}}
    

    对正确设置场地有什么建议吗?

    0 回复  |  直到 7 年前
        1
  •  1
  •   Jherico    7 年前

    你没有包括消息来源和签名 CreateCommandBuffers 从中进行内部调用的函数 CreateCommandBuffersUnique . 但是,假设它返回 std::vector<vk::CommandBuffer>

    vk::UniqueCommandBuffer 实例。但是,您正在通过cb(假设这里是一个 vk::CommandBuffer 和一个 vk::Device UniqueCommandBuffer 此处为构造函数

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

    实际上我不清楚它是如何编译的,除非 有一个 operator ()() . 不管怎样,第二个参数 唯一命令缓冲区 应该是deleter对象。

    所以事实证明 UniqueXXX UniqueHandle<> ,这反过来又源于 UniqueHandleTraits<...> 它专门用于每种类型,以便为其提供默认值 deleter 类型。大部分 唯一手柄<&燃气轮机; 专门化使用 ObjectDestroy<...> 因为大多数对象只需要创建 Device 摧毁他们。然而 UniqueHandleTraits<CommandBuffer> UniqueHandleTraits<DescriptorSet> 专业化使用 PoolFree<...>

    因此,您使用

    vk::UniqueCommandBuffer(cb, device));
    

    含蓄地变成

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

    {} 之后 device 是应该指定池的位置。

    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 ) );
    }
    

    要修复代码,您需要 或者复制它的行为,特别是创建一个 删除程序 对象或lambda,并将其作为第二个参数传递给 唯一命令缓冲区 克托。

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

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

        u_framebuffers.push_back(vk::UniqueFramebuffer(fb, { device, command_pool }));
    
        2
  •  0
  •   Makogan    7 年前

    尽管我更愿意使用与我提供的帧缓冲区示例更接近的方法,但在四处玩的过程中,我发现了一个解决问题的解决方案:

    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)
    {
        vk::CommandBufferAllocateInfo alloc_info(command_pool,
            vk::CommandBufferLevel::ePrimary, framebuffers.size());
        auto[result, u_command_buffers] = device.allocateCommandBuffersUnique(alloc_info);
        if (result != vk::Result::eSuccess)
            Log::RecordLogError("Failed to allocate command buffers!");
    
        auto command_buffers = CreateCommandBuffers(surface, phys_device, device, render_pass,
            graphics_pipeline, command_pool, framebuffers);
    
        for(auto &cb : command_buffers)
        {
            u_command_buffers[&cb - &command_buffers[0]].reset(cb);
        }
    
        return std::move(u_command_buffers);
    }