使用Vulkan画出第一个三角形
This commit is contained in:
@@ -2,4 +2,7 @@
|
||||
.vs/
|
||||
cmake-build*/
|
||||
out/
|
||||
build/
|
||||
*.spv
|
||||
compile_commands.json
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
)
|
||||
|
||||
Submodule
+1
Submodule Libraries/spdlog added at f5f173a1a5
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user