Drawing a triangle/Setup/Base code

目录

General structure

Resource management

Integrating GLFW


General structure

在上一章中,您创建了一个具有所有正确配置的Vulkan项目,并使用示例代码对其进行了测试。在本章中,我们将从以下代码开始:

#include <vulkan/vulkan.h>

#include <iostream>
#include <stdexcept>
#include <cstdlib>

class HelloTriangleApplication {
public:
    void run() {
        initVulkan();
        mainLoop();
        cleanup();
    }

private:
    void initVulkan() {

    }

    void mainLoop() {

    }

    void cleanup() {

    }
};

int main() {
    HelloTriangleApplication app;

    try {
        app.run();
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

我们首先包含了LunarG SDK中的Vulkan标头,它提供了函数、结构和枚举。stdexcept和iostream标头用于报告和传播错误。cstdlib标头提供EXIT_SUCCESS和EXIT_FAILURE宏。

程序本身被封装到一个类中,我们将在其中存储Vulkan对象作为私有类成员,并添加函数来初始化每个对象,这将从initVulkan函数调用。一切准备就绪后,我们进入主循环开始渲染帧。我们将填充mainLoop函数,以包含一个循环,该循环将迭代直到窗口立即关闭。一旦窗口关闭并且mainLoop返回,我们将确保释放清理函数中使用的资源。

如果在执行过程中发生任何类型的致命错误,那么我们将抛出一个std::runtime_error异常和一条描述性消息,该消息将传播回主函数并打印到命令提示符。为了处理各种标准异常类型,我们捕捉了更一般的std::exception。我们将很快处理的一个错误示例是发现某个必需的扩展不受支持。

大致上,本章之后的每一章都将添加一个从initVulkan调用的新函数,以及一个或多个新Vulkan对象到需要在清理结束时释放的私有类成员。

Resource management

就像分配给malloc的每个内存块都需要调用释放一样,我们创建的每个Vulkan对象都需要在不再需要时显式销毁。在C++中,可以使用RAII或<memory>头中提供的智能指针执行自动资源管理。然而,在本教程中,我选择了明确Vulkan对象的分配和释放。毕竟,Vulkan的优势是明确每一个操作以避免错误,所以明确对象的生命周期以了解API的工作原理是很好的。

遵循本教程后,您可以通过编写C++类来实现自动资源管理,这些C++类在构造函数中获取Vulkan对象,并在析构函数中释放它们,或者根据所有权要求,为std::unique_ptr或std::shared_ptr提供自定义删除器。RAII是大型Vulkan项目的推荐模式,但出于学习目的,了解幕后情况总是很好的。

Vulkan对象要么直接使用vkCreateXXX等函数创建,要么通过另一个具有vkAllocateXXX等函数的对象分配。确保某个对象不再在任何地方使用后,您需要使用对应的vkDestroyXXX和vkFreeXXX销毁它。对于不同类型的对象,这些函数的参数通常有所不同,但它们都共享一个参数:pAllocator。这是一个可选参数,允许您为自定义内存分配器指定回调。我们将在教程中忽略此参数,并始终传递nullptr作为参数。

Integrating GLFW

如果你想将Vulkan用于屏幕外渲染,那么它在不创建窗口的情况下工作得非常好,但实际显示一些东西会让你兴奋得多!首先将#include<vulkan/vulkan.h>行替换为

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

这样,GLFW将包含自己的定义并自动加载Vulkan标头。添加initWindow函数,并在其他调用之前从run函数添加对它的调用。我们将使用该函数初始化GLFW并创建一个窗口。

void run() {
    initWindow();
    initVulkan();
    mainLoop();
    cleanup();
}

private:
    void initWindow() {

    }

initWindow中的第一个调用应该是glfwInit(),它初始化GLFW库。因为GLFW最初设计用于创建OpenGL上下文,所以我们需要告诉它不要在后续调用中创建OpenGL上下文:

glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);

因为处理调整大小的窗口需要特别小心,我们稍后将对此进行研究,所以现在使用另一个窗口提示调用禁用它:

glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

现在剩下的就是创建实际的窗口。添加GLFWwindow*窗口;私有类成员,以存储对它的引用,并使用以下命令初始化窗口:

window = glfwCreateWindow(800, 600, "Vulkan", nullptr, nullptr);

前三个参数指定窗口的宽度、高度和标题。第四个参数允许您选择指定要打开窗口的监视器,最后一个参数仅与OpenGL相关。

使用常量而不是硬编码的宽度和高度数字是一个好主意,因为我们将在将来多次引用这些值。我在HelloTriangleApplication类定义上方添加了以下行:

const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;

并将窗口创建调用替换为

window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);

您现在应该有一个initWindow函数,它看起来像这样:

void initWindow() {
    glfwInit();

    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

    window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
}

要保持应用程序运行,直到出现错误或窗口关闭,我们需要向mainLoop函数添加一个事件循环,如下所示:

void mainLoop() {
    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
    }
}

这段代码应该是不言自明的。它循环并检查事件,如按下X按钮,直到用户关闭窗口。这也是我们稍后将调用函数来渲染单个帧的循环。

一旦窗口关闭,我们需要通过销毁它并终止GLFW本身来清理资源。这将是我们的第一个清理代码:

void cleanup() {
    glfwDestroyWindow(window);

    glfwTerminate();
}

当您现在运行程序时,应该会看到一个名为Vulkan的窗口出现,直到关闭窗口终止应用程序。现在我们有了Vulkan应用程序的框架,让我们创建第一个Vulkan对象!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值