C++ 在同步管理器类的std::unordered_映射中存储vksemaphore是一种不好的做法吗?

C++ 在同步管理器类的std::unordered_映射中存储vksemaphore是一种不好的做法吗?,c++,vulkan,synchronisation,C++,Vulkan,Synchronisation,Vulkan API要求您使用同步渲染。例如,在渲染帧时,我们必须等待,直到可以从交换链获取下一幅图像。我们还必须发出信号,表示可以开始呈现渲染图像。每个人都在讨论这个问题 信号灯在初始化期间创建,在关机期间销毁。在我能找到的任何示例代码(Sascha Willems,官方Khronos示例…)中,VkSemaphore都存储为renderer类中的类成员。我想知道是否可以通过创建VulkanSamphoreManager类来抽象问题,该类将由renderer类继承。简言之,此类将信号量存储在无

Vulkan API要求您使用同步渲染。例如,在渲染帧时,我们必须等待,直到可以从交换链获取下一幅图像。我们还必须发出信号,表示可以开始呈现渲染图像。每个人都在讨论这个问题

信号灯在初始化期间创建,在关机期间销毁。在我能找到的任何示例代码(Sascha Willems,官方Khronos示例…)中,VkSemaphore都存储为renderer类中的类成员。我想知道是否可以通过创建VulkanSamphoreManager类来抽象问题,该类将由renderer类继承。简言之,此类将信号量存储在无序的_映射中,其中std::string(我给信号量的名称)作为键:

//@class VulkanSynchronizationManager
///@brief创建和销毁Vulkan围栏和信号灯。
///这些对于多线程渲染和异步代码的同步是必不可少的!
///@note Fences主要用于将应用程序本身与渲染操作同步,
///而信号量用于在命令队列内或命令队列之间同步操作。
类同步管理器
{
私人:
//我们的应用程序需要的信号量。
std::无序映射信号量;
公众:
VulkanSynchronizationManager()
{}
~vulkanSynchronizationManager()
{}
受保护的:
///@brief检查具有此名称的信号量是否已存在。
///@param semaphore\u name信号灯的名称。
///@如果具有此名称的Vulkan信号量已存在,则返回True,否则返回false。
bool信号量是否存在(const std::string&semaphore\u name)const
{
std::无序映射::常量迭代器信号量\查找=信号量.find(信号量\名称);
if(semaphore\u lookup==semaphores.end())
{
返回true;
}
返回false;
}
///@brief创建一个新的Vulkan信号量。
///@param semaphore\u name信号量的唯一名称。
const std::可选VulkanSynchronizationManager::创建信号量(const VkDevice和vulkan_设备,const std::string和信号量_name)const
{
//首先检查具有此名称的Vulkan信号量是否已经存在!
if(信号量是否存在(信号量名称))
{
//错误处理。。。
返回std::nullopt;
}
VkSemaphoreCreateInfo信号量_create_info={};
//到目前为止,这一结构还没有什么可填补的。
//这在将来可能会改变!
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSemaphoreCreateInfo.html
信号量\创建\信息.sType=VK \结构\类型\信号量\创建\信息;
信号量_create_info.pNext=nullptr;
信号量_create_info.flags=0;
//将创建的新Vulkan信号量。
VkSemaphore新信号量;
VkResult result=vkCreateSemaphore(vulkan\u设备和信号量\u创建\u信息、nullptr和新信号量);
if(VK_SUCCESS!=结果)
{
vulkan_错误检查(结果);
返回std::nullopt;
}
//这不起作用,请参见下文。
插入({semaphore\u name,new\u semaphore});
返回新的_信号量;
}
///@brief按名称获取某个信号量。
///@param semaphore\u name信号灯的名称。
///@返回获取的信号量(如果存在),否则返回std::nullopt。
const std::可选的get_信号量(const std::string&semaphore_name)const
{
如果(!信号量是否存在(信号量名称))
{
//错误处理。。。
返回std::nullopt;
}
//返回请求的信号量。
返回信号量.at(信号量名称);
}
///@brief销毁所有现有信号量。
无效关机信号量(常量VkDevice和vulkan_设备)
{
//为无序映射创建迭代器。
std::无序映射::常量迭代器sephaore\u迭代器=信号量。begin();
//在无序的地图上迭代。
while(sephare_迭代器!=信号量.end())
{
//破坏信号灯。
vkDestroySemaphore(vulkan_设备,sepahore_迭代器->秒,nullptr);
//转到下一个信号灯。
sephaore_迭代器++;
}
//清除无序的地图!
信号量;
}
};
这个类绑定了所有现有的信号量,并提供create和get方法。它还负责在应用程序关闭期间销毁所有信号量

但是有一个问题:我们无法将新的VkSemaphore插入无序的_映射,因为Vulkan定义信号量是不可分发的句柄

这到底是个好主意吗


感谢您的反馈,John。

我发现了问题:通过将create_信号量声明为“const”成员函数,我无法修改无序的_映射

谢谢你的建议!因为这个类比旧的方法要大得多,所以我会重新考虑它。

任何名为“经理”的东西都可能构成问题,而不是解决方案。话虽如此,你的问题是什么还不太清楚。任何类型都可以复制,也可以不复制。如果它不可复制,则不能通过值单独传递或返回它,也不能用
std::optional
包装。但是,您可以将其包装在自己的(不可复制)类中,并使用容器的
emplace
创建一个。
/// @class VulkanSynchronisationManager
/// @brief Creates and destroys Vulkan fences and semaphores.
/// Those are essential for the synchronisation of multithreaded rendering and asynchronous code in general!
/// @note Fences are mainly designed to synchronize your application itself with rendering operation,
/// whereas semaphores are used to synchronize operations within or across command queues.
class VulkanSynchronisationManager
{
    private:

        // The semaphores that our application needs.
        std::unordered_map<std::string, VkSemaphore> semaphores;


    public:

        VulkanSynchronisationManager()
        {}

        ~VulkanSynchronisationManager()
        {}

    protected:

        /// @brief Checks if a semaphore with this name already exists.
        /// @param semaphore_name The name of the semaphore.
        /// @return True if a Vulkan semaphore with this name already exists, false otherwise.
        bool does_semaphore_exist(const std::string&semaphore_name) const
        {
            std::unordered_map<std::string, VkSemaphore>::const_iterator semaphore_lookup = semaphores.find(semaphore_name);

            if(semaphore_lookup == semaphores.end())
            {
                return true;
            }

            return false;
        }

        /// @brief Creates a new Vulkan semaphore.
        /// @param semaphore_name The unique name of the semaphore.
        const std::optional<VkSemaphore> VulkanSynchronisationManager::create_semaphore(const VkDevice& vulkan_device, const std::string& semaphore_name) const
        {
            // First check if a Vulkan semaphore with this name already exists!
            if(does_semaphore_exist(semaphore_name))
            {
                // Error handling...
                return std::nullopt;
            }

            VkSemaphoreCreateInfo semaphore_create_info = {};

            // So far, there is nothing to fill into this structure.
            // This may change in the future!
            // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSemaphoreCreateInfo.html
            semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
            semaphore_create_info.pNext = nullptr;
            semaphore_create_info.flags = 0;

            // The new Vulkan semaphore which will be created.
            VkSemaphore new_semaphore;

            VkResult result = vkCreateSemaphore(vulkan_device, &semaphore_create_info, nullptr, &new_semaphore);
            if(VK_SUCCESS != result)
            {
                vulkan_error_check(result);
                return std::nullopt;
            }

            // THIS does not work, see following text.
            semaphores.insert({semaphore_name, new_semaphore});

            return new_semaphore;
        }


        /// @brief Gets a certain semaphore by name.
        /// @param semaphore_name The name of the semaphore.
        /// @return The acquired semaphore (if existent), std::nullopt otherwise.
        const std::optional<VkSemaphore> get_semaphore(const std::string& semaphore_name) const
        {
            if(!does_semaphore_exist(semaphore_name))
            {
                // Error handling...
                return std::nullopt;
            }

            // Return the requested semaphore.
            return semaphores.at(semaphore_name);
        }


        /// @brief Destroys all existing semaphores.
        void shutdown_semaphores(const VkDevice& vulkan_device)
        {
            // Create an iterator for the unordered map.
            std::unordered_map<std::string, VkSemaphore>::const_iterator sepahore_iterator = semaphores.begin();

            // Iterate over the unordered map.
            while(sepahore_iterator != semaphores.end())
            {
                // Destroy the semaphore.
                vkDestroySemaphore(vulkan_device, sepahore_iterator->second, nullptr);

                // Move on to the next Semaphore.
                sepahore_iterator++;
            }

            // Clear the unordered map!
            semaphores.clear();
        }

};