vulkan tutorial

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <iostream>
#include <stdexcept>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <optional>
#include <set>

const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;
const std::vector<const char*> validationLayers = {
        "VK_LAYER_KHRONOS_validation"
};

const std::vector<const char*> deviceExtensions = {
        VK_KHR_SWAPCHAIN_EXTENSION_NAME
};

#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif

class HelloTriangleApplication {
public:
        void run() {
                initWindow();
                initVulkan();
                mainLoop();
                cleanup();
        }
private:
        bool checkValidationLayerSupport() {
                uint32_t layerCount;
                vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
                std::vector<VkLayerProperties> availableLayers(layerCount);
                vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
                for (const char* layerName : validationLayers) {
                        bool layerFound = false;
                        for (const auto& layerProperties : availableLayers) {
                                if (strcmp(layerName, layerProperties.layerName) == 0) {
                                        layerFound = true;
                                        break;
                                }
                        }
                        if (!layerFound) {
                                return false;
                        }
                }
                return true;
        }
        void initWindow() {
                glfwInit();
                glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
                glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
                window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
        }
        void createInstance() {
                if (enableValidationLayers && !checkValidationLayerSupport()) {
                        throw std::runtime_error("validation layers requested, but not available!");
                }
                VkApplicationInfo appInfo{};
                appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
                appInfo.pApplicationName = "Hello Triangle";
                appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
                appInfo.pEngineName = "No Engine";
                appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
                appInfo.apiVersion = VK_API_VERSION_1_0;
                VkInstanceCreateInfo createInfo{};
                createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
                createInfo.pApplicationInfo = &appInfo;
                uint32_t glfwExtensionCount = 0;
                const char** glfwExtensions;
                glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
                std::cout << "extensions from glfwGetRequiredInstanceExtensions:\n";
                for (int i = 0; i < glfwExtensionCount; ++i) {
                        std::cout << '\t' << glfwExtensions[i] << '\n';
                }
                createInfo.enabledExtensionCount = glfwExtensionCount;
                createInfo.ppEnabledExtensionNames = glfwExtensions;
                if (enableValidationLayers) {
                        createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
                        createInfo.ppEnabledLayerNames = validationLayers.data();
                } else {
                        createInfo.enabledLayerCount = 0;
                }

                VkResult result = vkCreateInstance(&createInfo, nullptr, &instance);
                if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS)
                        {
                                throw std::runtime_error("failed to create instance!");
                }


                uint32_t extensionCount = 0;
                vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
                std::vector<VkExtensionProperties> extensions(extensionCount);
                vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
                int count = 0;
                std::cout << "available extensions:\n";
                for (const auto& extension : extensions) {
                        std::cout << '\t' << extension.extensionName << '\n';
                        for (int i = 0; i < glfwExtensionCount; ++i) {
                                if(!strcmp(glfwExtensions[i], extension.extensionName))
                                {
                                        std::cout << '\t' << glfwExtensions[i] << "************ is supported! "<< '\n';
                                        count++;
                                }
                        }
                }
                if(count != glfwExtensionCount)
                        std::cout << '\t' << "some extension(s) is/are not supported "<< '\n';
        }
        void initVulkan() {
                createInstance();
                createSurface();
                pickPhysicalDevice();
                createLogicalDevice();

        }
        void createSurface() {
                if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
                        throw std::runtime_error("failed to create window surface!");
                }
        }
        void createLogicalDevice() {
                QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
                std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
                std::set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()};
                float queuePriority = 1.0f;
                for (uint32_t queueFamily : uniqueQueueFamilies) {
                        VkDeviceQueueCreateInfo queueCreateInfo{};
                        queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
                        queueCreateInfo.queueFamilyIndex = queueFamily;
                        queueCreateInfo.queueCount = 1;
                        queueCreateInfo.pQueuePriorities = &queuePriority;
                        queueCreateInfos.push_back(queueCreateInfo);
                }

                /*VkDeviceQueueCreateInfo queueCreateInfo{};
                queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
                queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value();
                queueCreateInfo.queueCount = 1;
                float queuePriority = 1.0f;
                queueCreateInfo.pQueuePriorities = &queuePriority;*/

                VkDeviceCreateInfo createInfo{};
                createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
                VkPhysicalDeviceFeatures deviceFeatures{};
                //createInfo.queueCreateInfoCount = 1;
                //createInfo.pQueueCreateInfos = &queueCreateInfo;
                createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
                createInfo.pQueueCreateInfos = queueCreateInfos.data();
                createInfo.pEnabledFeatures = &deviceFeatures;
                //createInfo.enabledExtensionCount = 0;
                createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
                createInfo.ppEnabledExtensionNames = deviceExtensions.data();
                if (enableValidationLayers) {
                        createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
                        createInfo.ppEnabledLayerNames = validationLayers.data();
                } else {
                        createInfo.enabledLayerCount = 0;
                }
                if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
                        throw std::runtime_error("failed to create logical device!");
                }
                vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
                vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
        }
        void pickPhysicalDevice() {
                uint32_t deviceCount = 0;
                vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
                if (deviceCount == 0) {
                        throw std::runtime_error("failed to find GPUs with Vulkan support!");
                }
                std::vector<VkPhysicalDevice> devices(deviceCount);
                vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
                for (const auto& device : devices) {
                                if (isDeviceSuitable(device)) {
                                physicalDevice = device;
                                break;
                        }
                }
                if (physicalDevice == VK_NULL_HANDLE) {
                        throw std::runtime_error("failed to find a suitable GPU!");
                }
        }
        bool isDeviceSuitable(VkPhysicalDevice device) {
                /*VkPhysicalDeviceProperties deviceProperties;
                VkPhysicalDeviceFeatures deviceFeatures;
                vkGetPhysicalDeviceProperties(device, &deviceProperties);
                vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
                return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
                        deviceFeatures.geometryShader;*/
                QueueFamilyIndices indices = findQueueFamilies(device);
                bool extensionsSupported = checkDeviceExtensionSupport(device);
                bool swapChainAdequate = false;
                if (extensionsSupported) {
                        SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
                        swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
                }
                return indices.isComplete() && extensionsSupported && swapChainAdequate;
        }
        bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
                uint32_t extensionCount;
                vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
                std::vector<VkExtensionProperties> availableExtensions(extensionCount);
                vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
                std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
                std::cout << "+++++++++++++++++"<< std::endl;
                for (const auto& extension : deviceExtensions) std::cout << extension << std::endl;
                std::cout << "*****************"<< std::endl;
                for (const auto& extension : availableExtensions) {
                        std::cout << extension.extensionName << std::endl;
                        requiredExtensions.erase(extension.extensionName);
                }
                std::cout << "-----------------" <<std::endl;
                return requiredExtensions.empty();
        }
        struct QueueFamilyIndices {
                std::optional<uint32_t> graphicsFamily;
                std::optional<uint32_t> presentFamily;
                bool isComplete() {
                        return graphicsFamily.has_value()&&
                                presentFamily.has_value();
                }
        };
        QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
                QueueFamilyIndices indices;
                // Logic to find queue family indices to populate struct with
                uint32_t queueFamilyCount = 0;
                vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
                std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
                vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
                int i = 0;
                VkBool32 presentSupport = false;
                for (const auto& queueFamily : queueFamilies) {
                        if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
                                indices.graphicsFamily = i;
                        }
                        vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
                        if (presentSupport) {
                                indices.presentFamily = i;
                        }
                        if (indices.isComplete()) {
                                break;
                        }
                        i++;
                }
                return indices;
        }
        struct SwapChainSupportDetails {
                VkSurfaceCapabilitiesKHR capabilities;
                std::vector<VkSurfaceFormatKHR> formats;
                std::vector<VkPresentModeKHR> presentModes;
        };
        SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
                SwapChainSupportDetails details;
                vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
                uint32_t formatCount;
                vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
                if (formatCount != 0) {
                        details.formats.resize(formatCount);
                        vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
                }

                uint32_t presentModeCount;
                vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
                if (presentModeCount != 0) {
                        details.presentModes.resize(presentModeCount);
                        vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
                }

                return details;
        }
        void mainLoop() {
                while (!glfwWindowShouldClose(window)) {
                        glfwPollEvents();
                }
        }
        void cleanup() {
                vkDestroyDevice(device, nullptr);
                vkDestroySurfaceKHR(instance, surface, nullptr);
                vkDestroyInstance(instance, nullptr);
                glfwDestroyWindow(window);
                glfwTerminate();

        }
//      VkPhysicalDeviceFeatures deviceFeatures{};
private:
        VkQueue presentQueue;
        VkSurfaceKHR surface;
        VkQueue graphicsQueue;
        VkInstance instance;
        GLFWwindow* window;
        VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
        VkDevice device;
};

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

Makefile:

VULKAN_SDK_PATH = /usr
CFLAGS = -std=c++17 -I$(VULKAN_SDK_PATH)/include -g
LDFLAGS = -L$(VULKAN_SDK_PATH)/lib `pkg-config --static --libs glfw3` -lvulkan
VulkanTest: main.cpp
        g++ $(CFLAGS) -o VulkanTest main.cpp $(LDFLAGS)
.PHONY: test clean
test: VulkanTest
        LD_LIBRARY_PATH=$(VULKAN_SDK_PATH)/lib
                VK_LAYER_PATH=$(VULKAN_SDK_PATH)/etc/vulkan/explicit_layer.d
                ./VulkanTest
clean:
        rm -f VulkanTest

Choosing the right settings for the swap chain. page 82

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值