使用Vulkan画出第一个三角形

This commit is contained in:
2026-08-31 13:23:09 +08:00
parent b5bd7fa1f5
commit 3a90e8408d
11 changed files with 1308 additions and 6 deletions
+3
View File
@@ -2,4 +2,7 @@
.vs/
cmake-build*/
out/
build/
*.spv
compile_commands.json
+3
View File
@@ -4,3 +4,6 @@
[submodule "Libraries/glfw"]
path = Libraries/glfw
url = https://github.com/glfw/glfw
[submodule "Libraries/spdlog"]
path = Libraries/spdlog
url = https://github.com/gabime/spdlog
+14 -3
View File
@@ -4,11 +4,20 @@ project(VulkanTutorial)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
file(GLOB SOURCE_CODE ./src/*.cpp)
file(GLOB_RECURSE SOURCE_CODE ./src/**.cpp)
add_executable(${PROJECT_NAME}
${SOURCE_CODE}
)
file(GLOB SHADER_CODE ./shaders/*.spv)
file(COPY ${SHADER_CODE} DESTINATION ${CMAKE_BINARY_DIR})
target_include_directories(${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# 1. 查找 Vulkan
find_package(Vulkan REQUIRED)
if(NOT Vulkan_FOUND)
@@ -22,10 +31,12 @@ set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
add_subdirectory(Libraries/glfw) # GLFW
add_subdirectory(Libraries/glm) # GLM
add_subdirectory(Libraries/spdlog)
# 链接依赖
target_link_libraries(${PROJECT_NAME}
PRIVATE
glfw # glfw 的 target 名称(由 add_subdirectory 提供)
Vulkan::Vulkan # 来自 find_package(Vulkan)
glfw
Vulkan::Vulkan
spdlog
)
+1
Submodule Libraries/spdlog added at f5f173a1a5
+9
View File
@@ -0,0 +1,9 @@
#version 450
layout(location = 0) in vec3 fragColor;
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(fragColor, 1.0);
}
+20
View File
@@ -0,0 +1,20 @@
#version 450
layout (location = 0) out vec3 fragColor;
vec2 positions[3] = vec2[](
vec2(0.0,-0.5),
vec2(0.5,0.5),
vec2(-0.5,0.5)
);
vec3 colors[3] = vec3[] (
vec3(1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 0.0, 1.0)
);
void main() {
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
fragColor = colors[gl_VertexIndex];
}
File diff suppressed because it is too large Load Diff
+134
View File
@@ -0,0 +1,134 @@
#ifndef VULKAN_APPLICATION_H
#define VULKAN_APPLICATION_H
#include <string>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <optional>
#include <vector>
#include <vulkan/vk_platform.h>
#include <vulkan/vulkan_core.h>
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
bool IsComplete() {
return graphicsFamily.has_value() && presentFamily.has_value();
}
};
struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};
class Application {
public:
void run();
private:
void InitWindow();
void InitVulkan();
void MainLoop();
void CleanUp();
void CreateInstance();
void SetupDebugMessenger();
void CreateSurface();
void PickPhysicalDevice();
void CreateLogicalDevice();
void CreateSwapChain();
void CreateImageViews();
void CreateRenderPass();
void CreateGraphicsPipeline();
void CreateFramebuffers();
void CreateCommandPool();
void CreateCommandBuffers();
void CleanUpSwapChain();
void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex);
void CreateSyncObjects();
void ReCreateSwapChain();
void DrawFrame();
bool CheckValidationLayerSupport();
bool CheckDeviceExtensionSupport(VkPhysicalDevice device);
bool IsDeviceSuitable(VkPhysicalDevice device);
std::vector<const char *> getRequiredExtensions();
VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR> &availableFormats);
VkPresentModeKHR ChooseSwapPresentMode(const std::vector<VkPresentModeKHR> &availablePresentModes);
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities);
QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice device);
SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice device);
// key callback
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods);
// FramebufferCallback
static void FramebufferCallback(GLFWwindow *window, int width, int height);
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData);
void PopulateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT &createInfo);
static std::vector<char> ReadFile(const std::string &filename);
VkShaderModule CreateShaderModule(const std::vector<char> &code);
private:
GLFWwindow *m_Window = nullptr;
uint32_t m_WIDTH = 800;
uint32_t m_HEIGHT = 600;
VkInstance m_Instance = VK_NULL_HANDLE;
VkDebugUtilsMessengerEXT m_DebugMessager;
VkSurfaceKHR m_Surface;
VkSwapchainKHR m_SwapChain;
std::vector<VkImage> m_SwapChainImages;
VkFormat m_SwapChainImageFormat;
VkExtent2D m_SwapChainExtent;
std::vector<VkImageView> m_SwapChainImageViews;
VkPhysicalDevice m_PhysicalDevice = VK_NULL_HANDLE;
VkDevice m_Device = VK_NULL_HANDLE;
VkQueue m_GraphicsQueue;
VkQueue m_PresentQueue;
VkRenderPass m_RenderPass;
VkPipelineLayout m_PipelineLayout;
VkPipeline m_GraphicsPipeline;
std::vector<VkFramebuffer> m_SwapChainFramebuffers;
VkCommandPool m_CommandPool;
std::vector<VkCommandBuffer> m_CommandBuffers;
std::vector<VkSemaphore> m_ImageAvailableSemaphores;
std::vector<VkSemaphore> m_RenderFinishedSemaphores;
std::vector<VkFence> m_InFlightFences;
bool m_FramebufferResized = false;
const int MAX_FRAMES_IN_FLIGHT = 2;
uint32_t m_CurrrentFrame = 0;
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 enableValidationLayer = false;
#else
const bool enableValidationLayer = true;
#endif
};
#endif
+43
View File
@@ -0,0 +1,43 @@
#include "Log.h"
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <stdexcept>
namespace Log {
static bool IsInited = false;
void Init() {
if (IsInited) {
throw std::runtime_error("spdlog already inited");
}
IsInited = true;
// 控制台彩色 sink (多线程安全)
auto console = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
console->set_pattern("%^[%T.%e] [%l] [%n] %v%$");
// 文件
auto file = std::make_shared<spdlog::sinks::basic_file_sink_mt>("VulkanToturial.log", true);
file->set_pattern("[%Y-%m-%d %T.%e] [%l] [%t] %v");
// 多sink 组合默认 logger
// auto logger = std::make_shared<spdlog::logger>("hello", spdlog::sinks_init_list{console, file});
auto logger = std::make_shared<spdlog::logger>("Application", spdlog::sinks_init_list{console, file});
logger->set_level(spdlog::level::trace);
logger->flush_on(spdlog::level::warn); // warn 及以上立即 flush,避免崩溃丢日志
spdlog::set_default_logger(logger);
}
void Shutdown() {
if (!IsInited) {
throw std::runtime_error("spdlog already shutdown or not init");
}
IsInited = false;
spdlog::shutdown();
}
} // namespace Log
+22
View File
@@ -0,0 +1,22 @@
#ifndef LOG_H
#define LOG_H
#ifndef SPDLOG_ACTIVE_LEVEL
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
#endif
#include <spdlog/spdlog.h>
namespace Log {
void Init();
void Shutdown();
}; // namespace Log
#define LOG_TRACE(...) SPDLOG_TRACE(__VA_ARGS__)
#define LOG_DEBUG(...) SPDLOG_DEBUG(__VA_ARGS__)
#define LOG_INFO(...) SPDLOG_INFO(__VA_ARGS__)
#define LOG_WARN(...) SPDLOG_WARN(__VA_ARGS__)
#define LOG_ERROR(...) SPDLOG_ERROR(__VA_ARGS__)
#define LOG_CRIT(...) SPDLOG_CRITICAL(__VA_ARGS__)
#endif
+18 -3
View File
@@ -2,8 +2,23 @@
// Created by atdunbg on 2026/8/25.
//
#include <iostream>
#include "Application/Application.h"
#include "Log/Log.h"
#include <cstdlib>
#include <exception>
int main(int argc, char** argv) {
std::cout << "Hello World!" << std::endl;
int main(int argc, char **argv) {
Log::Init();
Application app;
try {
app.run();
} catch (const std::exception &e) {
LOG_CRIT("{}", e.what());
Log::Shutdown();
return EXIT_FAILURE;
}
Log::Shutdown();
return EXIT_SUCCESS;
}