Vulkan API — урок 13. Поверхность окна

Итак, новый урок Vulkan API самоучитель будет открывать небольшую главу под названием Presentation, в которой поговорим о поверхности окна, swap chain и отображении картинки.

Поверхность окна

Поскольку Vulkan – платформонезависсимое API, оно не контактирует с оконной системой непосредственно. Для создания связи между Vulkan’ом и оконной системой для вывода результата на экран, нам необходимо использовать расширения WSI (Window System Integration). В этой главе мы обсудим первое расширение VK_KHR_surface. Оно предоставляет объект VkSurfaceKHR, который представляет собой абстрактный тип поверхности для представления изображения. Поверхность в нашей программе будет работать поверх окна, уже открытого при помощи GLFW.

Расширение VK_KHR_surface – это расширение уровная instance и мы уже активировали его, т.к. око включено в список, возвращаемый glfwGetRequiredInstanceExtensions. Этот список так же возвращает некоторые другие WSI расширения, которые мы будем использовать в ближайших уроках.

Поверхность окна должна быть создана сразу после создания instance, т.к. оно может повлиять на выбор физического устройства. Причина, по которой мы заговорили об этом только сейчас в том, что поверхность окна является частью большой темы целей визуализации и презентации, и базовые настройки её лишь больше запутаю и загромоздят. Следует так же отметить, что поверхность окна является полностью опциональным компонентов в Vulkan’е, который может быть выключен для закадрового рендеринга. Вам не нужно создавать невидимое окно или по иному изощряться, как в том же OpenGL.

Создание поверхности окна

Начнем с добавления нового члена класса сразу после callback’а дебага. Поверхность уничтожается при помощи вызова vkDestroySurfaceKHR.

VDeleter<VkSurfaceKHR> surface{instance, vkDestroySurfaceKHR};

Не смотря на то, что объект VkSurfaceKHR и его использование платформонезависимы, его создание никак не связано с деталями оконной системы. К примеру, необходимы HWND и HMODULE элементы в Windows. Поэтому существует дополнительное, специфичные для каждой платформы, расширение, которое в Windows зовется VK_KHR_win32_surface, и также автоматически включено в glfwGetRequiredInstanceExtensions.

Далее я продемонстрирую как это платформо-зависимое расширение может быть использования поверхности в Windows, но мы не будем использовать ничего подобного в будущем, и вы не увидите этого в листинге, заместо этого мы все так же будем использовать GLFW.

Потому что поверхность окна это объект Vulkan’a, понадобится заполнить структуру (куда же мы без них та) VkWin32SurfaceCreateInfoKHR. Она содержит два важных параметра: hwnd and hinstance. Это два дескриптора на окно и на процесс:

VkWin32SurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
createInfo.hwnd = glfwGetWin32Window(window);
createInfo.hinstance = GetModuleHandle(nullptr);

Функция glfwGetWin32Window используется для получения HWND из объекта окна GLFW. Вызов GetModuleHandle возвращает дескриптор HINSTANCE текущего процесса.

После этого поверхность может быть создана при помощи  vkCreateWin32SurfaceKHR, который должен быть загружен снова. Кроме этого вызов тривиален и включает в себя параметр для instance, детали создания поверхности, пользовательский аллокатор и переменную для хранения дескриптора поверхности.

auto CreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR");

if (!CreateWin32SurfaceKHR || CreateWin32SurfaceKHR(instance, &createInfo,
   nullptr, surface.replace()) != VK_SUCCESS) {
    throw std::runtime_error("failed to create window surface!");
}

Процесс аналогичен и в других платформах, как например в Линухе, где vkCreateXcbSurfaceKHR принимает XCB соединение и окно как детали для X11.

Функция glfwCreateWindowSurface выполняет именно эти операции для каждой из платформ. Теперь интегрируем её в программу. Добавим вызов функции createSurface в initVulkan сразу после создания instance и setupDebugCallback.

void initVulkan() {
    createInstance();
    setupDebugCallback();
    createSurface();
    pickPhysicalDevice();
    createLogicalDevice();
}

void createSurface() {

}

Вызов GLFW принимает простые параметры, а не структуру (сам удивился):

void createSurface() {
    if (glfwCreateWindowSurface(instance, window, nullptr, surface.replace()) != VK_SUCCESS) {
        throw std::runtime_error("failed to create window surface!");
    }
}

Параметры –  VkInstance, GLFW указатель окна, модифицированный аллокатор и указатель на переменную VkSurfaceKHR.

Main Admin

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *