Плохо ли хранить VkSemaphores в std :: unordered_map в классе менеджера синхронизации? - PullRequest
0 голосов
/ 16 февраля 2020

Vulkan API требует, чтобы вы синхронизировали рендеринг, используя VkSemaphores . Например, при рендеринге кадра нам нужно подождать, пока следующее изображение не будет получено из цепочки обмена. Мы также должны дать сигнал, что представление визуализированного изображения может начаться. Это обсуждается в каждом учебном пособии по Vulkan .

Семафоры создаются во время инициализации и уничтожаются при завершении работы. В любом примере кода, который я мог найти (Саша Виллемс, официальные примеры Khronos ..), VkSemaphore хранятся как член класса в классе рендерера. Мне было интересно, смогу ли я абстрагировать проблему, создав класс VulkanSemaphoreManager, который будет унаследован классом рендерера. Короче говоря, этот класс хранит семафоры в unordered_map с ключом std :: string (имя, которое я дал семафору):

/// @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();
        }

};

Этот класс связывает все существующие семафоры и предлагает методы create и get. Он также отвечает за уничтожение всех семафоров во время завершения работы приложения.

Но есть проблема : мы не можем вставить новый VkSemaphore в unordered_map, потому что Vulkan определяет семафоры как нерасширяемые дескрипторы.

Это ведь хорошая идея?

Спасибо за отзыв, Джон.

1 Ответ

0 голосов
/ 16 февраля 2020

Я обнаружил проблему: объявив create_semaphore как "const" функцию-член, я не смог изменить unordered_map.

Хотя спасибо за совет! Поскольку этот класс намного больше, чем старый, я переосмыслил его.

...