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 определяет семафоры как нерасширяемые дескрипторы.
Это ведь хорошая идея?
Спасибо за отзыв, Джон.