vulakn教程--Drawing a Triangle--Set up--Base code

原文地址:vulkan-tutorial

Base code

General structure

上一章通過構建一個窗體來完成VS對Vulkan的配置,並將配置好的工程設置爲模板以備後續的使用。在上一章的最後我們用這個模板創建了一個名爲:Hello Triangle 的新工程,現在讓我們爲這個工程搭建一個框架。


#include <iostream>
#include <stdexcept>
#include <functional>

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

private:
    void initVulkan() {

    }

    void mainLoop() {

    }
};

int main() {
    HelloTriangleApplication app;

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

    return EXIT_SUCCESS;
}

stdexception 引入異常,functional 引入lambda功能。

Resource management

每一個Vulkan對象不再使用後,都需要用一個清理函數來銷燬,就像malloc 分配的內存要用free 銷燬一樣。手動來銷燬每一個對象是一個非常繁雜且容易出錯的任務。我們利用C++的RAII原理來創建一個包裹類,當對象離開有效作用域後自動爲我們銷燬對象。如下,在創建VkInstance前,用類似方法聲明VkInstance對象,並告訴我們的包裹類,銷燬Instance對象的方法是vkDestroyInstance:

VDeleter<VkInstance> instance{vkDestroyInstance};   //VDeleter是我們的包裹類。

然後創建這個Instance:

vkCreateInstance(&instanceCreateInfo, nullptr, &instance);

當Instance離開有效作用域,比如,關閉了應用,VDeleter將自動使用vkDestroyInstance將Instance銷燬。
以下是VDeleter的定義:

template <typename T>
class VDeleter {
public:
    VDeleter() : VDeleter([](T, VkAllocationCallbacks*) {}) {}

    VDeleter(std::function<void(T, VkAllocationCallbacks*)> deletef) {
        this->deleter = [=](T obj) { deletef(obj, nullptr); };
    }

    VDeleter(const VDeleter<VkInstance>& instance, std::function<void(VkInstance, T, VkAllocationCallbacks*)> deletef) {
        this->deleter = [&instance, deletef](T obj) { deletef(instance, obj, nullptr); };
    }

    VDeleter(const VDeleter<VkDevice>& device, std::function<void(VkDevice, T, VkAllocationCallbacks*)> deletef) {
        this->deleter = [&device, deletef](T obj) { deletef(device, obj, nullptr); };
    }

    ~VDeleter() {
        cleanup();
    }

    T* operator &() {
        cleanup();
        return &object;
    }

    operator T() const {
        return object;
    }

private:
    T object{VK_NULL_HANDLE};
    std::function<void(T)> deleter;

    void cleanup() {
        if (object != VK_NULL_HANDLE) {
            deleter(object);
        }
        object = VK_NULL_HANDLE;
    }
};

後續的所有教程都將使用VDeleter來管理我們的對象。

Integrating GLFW

如果你只想離屏渲染(off-screen rendering),不需要創建窗口vulkan一樣可以很好的工作。但是,難道你不覺得在屏幕上顯示一些東西會更酷嗎?首先用如如下語句取代#include <vulkan/vulkan.h>:

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

#define GLFW_INCLUDE_VULKAN告訴glfw 在引入自己的頭文件時也要引入vulkan.h

run裏添加initWindow來創建窗體:

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

private:
    void initWindow() {

    }

初始化:

glfwInit()   ;  

GLFW最初是爲創建OPENGL 的 context設計的,爲了避免它創建OPENGL context,需要設置 :

glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);

允許窗口改變大小會引起其他的問題,後續我們再討論,爲了操作簡單,這裏禁止改變窗口大小:

glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

創建窗體:

const int WIDTH = 800; 
const int HEIGHT = 600; 
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);

第三個參數爲窗口(window)創建一個監視器,最後一個參數和OPENGL 相關。

顯示 ,直到遇到錯誤或關閉窗口:

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

爲了方便你對照和理解,這裏所有代碼:

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

#include <iostream>
#include <stdexcept>
#include <functional>

const int WIDTH = 800;
const int HEIGHT = 600;

template <typename T>
class VDeleter {
public:
    VDeleter() : VDeleter([](T, VkAllocationCallbacks*) {}) {}

    VDeleter(std::function<void(T, VkAllocationCallbacks*)> deletef) {
        this->deleter = [=](T obj) { deletef(obj, nullptr); };
    }

    VDeleter(const VDeleter<VkInstance>& instance, std::function<void(VkInstance, T, VkAllocationCallbacks*)> deletef) {
        this->deleter = [&instance, deletef](T obj) { deletef(instance, obj, nullptr); };
    }

    VDeleter(const VDeleter<VkDevice>& device, std::function<void(VkDevice, T, VkAllocationCallbacks*)> deletef) {
        this->deleter = [&device, deletef](T obj) { deletef(device, obj, nullptr); };
    }

    ~VDeleter() {
        cleanup();
    }

    T* operator &() {
        cleanup();
        return &object;
    }

    operator T() const {
        return object;
    }

private:
    T object{VK_NULL_HANDLE};
    std::function<void(T)> deleter;

    void cleanup() {
        if (object != VK_NULL_HANDLE) {
            deleter(object);
        }
        object = VK_NULL_HANDLE;
    }
};

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

private:
    GLFWwindow* window;

    void initWindow() {
        glfwInit();

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

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

    void initVulkan() {

    }

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

int main() {
    HelloTriangleApplication app;

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

    return EXIT_SUCCESS;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章