@@ -0,0 +1,937 @@
# define GLFW_INCLUDE_VULKAN
# include <GLFW/glfw3.h>
# include <iostream>
# include <stdexcept>
# include <cstdlib>
# include <vector>
# include <optional>
# include <set>
# include <cstdint>
# include <algorithm>
# include <fstream>
// 窗口尺寸
const uint32_t WIDTH = 800 ;
const uint32_t HEIGHT = 600 ;
// 验证层名称(Debug用,发布版本可移除)
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
// 辅助函数:读取着色器文件
static std : : vector < char > readFile ( const std : : string & filename ) {
std : : ifstream file ( filename , std : : ios : : ate | std : : ios : : binary ) ;
if ( ! file . is_open ( ) ) {
throw std : : runtime_error ( " failed to open file! " ) ;
}
size_t fileSize = ( size_t ) file . tellg ( ) ;
std : : vector < char > buffer ( fileSize ) ;
file . seekg ( 0 ) ;
file . read ( buffer . data ( ) , fileSize ) ;
file . close ( ) ;
return buffer ;
}
// 辅助结构:队列族索引
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 HelloTriangleApplication {
public :
void run ( ) {
initWindow ( ) ;
initVulkan ( ) ;
mainLoop ( ) ;
cleanup ( ) ;
}
private :
GLFWwindow * window ;
VkInstance instance ;
VkDebugUtilsMessengerEXT debugMessenger ; // Debug 信使(可选)
VkSurfaceKHR surface ; // 窗口表面
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE ; // 物理设备(GPU)
VkDevice device ; // 逻辑设备
VkQueue graphicsQueue ; // 图形队列
VkQueue presentQueue ; // 呈现队列
VkSwapchainKHR swapChain ; // 交换链
std : : vector < VkImage > swapChainImages ; // 交换链图像
VkFormat swapChainImageFormat ;
VkExtent2D swapChainExtent ;
std : : vector < VkImageView > swapChainImageViews ; // 图像视图
VkRenderPass renderPass ; // 渲染通道
VkPipelineLayout pipelineLayout ; // 管线布局
VkPipeline graphicsPipeline ; // 图形管线
std : : vector < VkFramebuffer > swapChainFramebuffers ; // 帧缓冲区
VkCommandPool commandPool ; // 命令池
VkCommandBuffer commandBuffer ; // 命令缓冲区
VkSemaphore imageAvailableSemaphore ; // 图像可用信号量
VkSemaphore renderFinishedSemaphore ; // 渲染完成信号量
VkFence inFlightFence ; // 栅栏(用于CPU-GPU同步)
void initWindow ( ) {
glfwInit ( ) ; // 初始化GLFW
glfwWindowHint ( GLFW_CLIENT_API , GLFW_NO_API ) ; // 告诉GLFW不要创建OpenGL上下文
glfwWindowHint ( GLFW_RESIZABLE , GLFW_FALSE ) ; // 暂时禁止窗口缩放以避免复杂处理
window = glfwCreateWindow ( WIDTH , HEIGHT , " Vulkan Triangle " , nullptr , nullptr ) ;
}
void initVulkan ( ) {
createInstance ( ) ;
setupDebugMessenger ( ) ;
createSurface ( ) ;
pickPhysicalDevice ( ) ;
createLogicalDevice ( ) ;
createSwapChain ( ) ;
createImageViews ( ) ;
createRenderPass ( ) ;
createGraphicsPipeline ( ) ;
createFramebuffers ( ) ;
createCommandPool ( ) ;
createCommandBuffer ( ) ;
createSyncObjects ( ) ;
}
void mainLoop ( ) {
while ( ! glfwWindowShouldClose ( window ) ) {
glfwPollEvents ( ) ;
drawFrame ( ) ;
}
vkDeviceWaitIdle ( device ) ; // 等待设备空闲,确保所有操作完成后再清理
}
void cleanup ( ) {
// 销毁同步对象
vkDestroySemaphore ( device , renderFinishedSemaphore , nullptr ) ;
vkDestroySemaphore ( device , imageAvailableSemaphore , nullptr ) ;
vkDestroyFence ( device , inFlightFence , nullptr ) ;
// 销毁命令池(会自动销毁其分配的命令缓冲区)
vkDestroyCommandPool ( device , commandPool , nullptr ) ;
// 销毁帧缓冲区
for ( auto framebuffer : swapChainFramebuffers ) {
vkDestroyFramebuffer ( device , framebuffer , nullptr ) ;
}
// 销毁管线
vkDestroyPipeline ( device , graphicsPipeline , nullptr ) ;
// 销毁管线布局
vkDestroyPipelineLayout ( device , pipelineLayout , nullptr ) ;
// 销毁渲染通道
vkDestroyRenderPass ( device , renderPass , nullptr ) ;
// 销毁图像视图
for ( auto imageView : swapChainImageViews ) {
vkDestroyImageView ( device , imageView , nullptr ) ;
}
// 销毁交换链
vkDestroySwapchainKHR ( device , swapChain , nullptr ) ;
// 销毁逻辑设备
vkDestroyDevice ( device , nullptr ) ;
// 销毁表面
vkDestroySurfaceKHR ( instance , surface , nullptr ) ;
// 销毁Debug工具(如果启用)
if ( enableValidationLayers ) {
DestroyDebugUtilsMessengerEXT ( instance , debugMessenger , nullptr ) ;
}
// 销毁Vulkan实例
vkDestroyInstance ( instance , nullptr ) ;
// 销毁窗口
glfwDestroyWindow ( window ) ;
// 终止GLFW
glfwTerminate ( ) ;
}
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 ;
// 获取GLFW所需的扩展并指定
auto extensions = getRequiredExtensions ( ) ;
createInfo . enabledExtensionCount = static_cast < uint32_t > ( extensions . size ( ) ) ;
createInfo . ppEnabledExtensionNames = extensions . data ( ) ;
// 调试信使创建信息(用于Debug输出)
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo { } ;
if ( enableValidationLayers ) {
createInfo . enabledLayerCount = static_cast < uint32_t > ( validationLayers . size ( ) ) ;
createInfo . ppEnabledLayerNames = validationLayers . data ( ) ;
populateDebugMessengerCreateInfo ( debugCreateInfo ) ;
createInfo . pNext = ( VkDebugUtilsMessengerCreateInfoEXT * ) & debugCreateInfo ;
} else {
createInfo . enabledLayerCount = 0 ;
createInfo . pNext = nullptr ;
}
// 创建Vulkan实例
if ( vkCreateInstance ( & createInfo , nullptr , & instance ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to create instance! " ) ;
}
}
void populateDebugMessengerCreateInfo ( VkDebugUtilsMessengerCreateInfoEXT & createInfo ) {
createInfo = { } ;
createInfo . sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT ;
createInfo . messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT ;
createInfo . messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT ;
createInfo . pfnUserCallback = debugCallback ;
}
void setupDebugMessenger ( ) {
if ( ! enableValidationLayers ) return ;
VkDebugUtilsMessengerCreateInfoEXT createInfo ;
populateDebugMessengerCreateInfo ( createInfo ) ;
if ( CreateDebugUtilsMessengerEXT ( instance , & createInfo , nullptr , & debugMessenger ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to set up debug messenger! " ) ;
}
}
void createSurface ( ) {
// 使用GLFW创建窗口表面(跨平台)
if ( glfwCreateWindowSurface ( instance , window , nullptr , & surface ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to create window surface! " ) ;
}
}
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 ( ) ) ;
// 选择第一个满足我们需求的GPU
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! " ) ;
}
}
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 ) ;
}
VkPhysicalDeviceFeatures deviceFeatures { } ;
VkDeviceCreateInfo createInfo { } ;
createInfo . sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO ;
createInfo . queueCreateInfoCount = static_cast < uint32_t > ( queueCreateInfos . size ( ) ) ;
createInfo . pQueueCreateInfos = queueCreateInfos . data ( ) ;
createInfo . pEnabledFeatures = & deviceFeatures ;
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 createSwapChain ( ) {
SwapChainSupportDetails swapChainSupport = querySwapChainSupport ( physicalDevice ) ;
VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat ( swapChainSupport . formats ) ;
VkPresentModeKHR presentMode = chooseSwapPresentMode ( swapChainSupport . presentModes ) ;
VkExtent2D extent = chooseSwapExtent ( swapChainSupport . capabilities ) ;
uint32_t imageCount = swapChainSupport . capabilities . minImageCount + 1 ;
if ( swapChainSupport . capabilities . maxImageCount > 0 & & imageCount > swapChainSupport . capabilities . maxImageCount ) {
imageCount = swapChainSupport . capabilities . maxImageCount ;
}
VkSwapchainCreateInfoKHR createInfo { } ;
createInfo . sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR ;
createInfo . surface = surface ;
createInfo . minImageCount = imageCount ;
createInfo . imageFormat = surfaceFormat . format ;
createInfo . imageColorSpace = surfaceFormat . colorSpace ;
createInfo . imageExtent = extent ;
createInfo . imageArrayLayers = 1 ;
createInfo . imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ;
QueueFamilyIndices indices = findQueueFamilies ( physicalDevice ) ;
uint32_t queueFamilyIndices [ ] = { indices . graphicsFamily . value ( ) , indices . presentFamily . value ( ) } ;
if ( indices . graphicsFamily ! = indices . presentFamily ) {
createInfo . imageSharingMode = VK_SHARING_MODE_CONCURRENT ;
createInfo . queueFamilyIndexCount = 2 ;
createInfo . pQueueFamilyIndices = queueFamilyIndices ;
} else {
createInfo . imageSharingMode = VK_SHARING_MODE_EXCLUSIVE ;
createInfo . queueFamilyIndexCount = 0 ; // Optional
createInfo . pQueueFamilyIndices = nullptr ; // Optional
}
createInfo . preTransform = swapChainSupport . capabilities . currentTransform ;
createInfo . compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR ;
createInfo . presentMode = presentMode ;
createInfo . clipped = VK_TRUE ;
createInfo . oldSwapchain = VK_NULL_HANDLE ;
if ( vkCreateSwapchainKHR ( device , & createInfo , nullptr , & swapChain ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to create swap chain! " ) ;
}
vkGetSwapchainImagesKHR ( device , swapChain , & imageCount , nullptr ) ;
swapChainImages . resize ( imageCount ) ;
vkGetSwapchainImagesKHR ( device , swapChain , & imageCount , swapChainImages . data ( ) ) ;
swapChainImageFormat = surfaceFormat . format ;
swapChainExtent = extent ;
}
void createImageViews ( ) {
swapChainImageViews . resize ( swapChainImages . size ( ) ) ;
for ( size_t i = 0 ; i < swapChainImages . size ( ) ; i + + ) {
VkImageViewCreateInfo createInfo { } ;
createInfo . sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO ;
createInfo . image = swapChainImages [ i ] ;
createInfo . viewType = VkImageViewType : : VK_IMAGE_VIEW_TYPE_2D ;
createInfo . format = swapChainImageFormat ;
createInfo . components . r = VK_COMPONENT_SWIZZLE_IDENTITY ;
createInfo . components . g = VK_COMPONENT_SWIZZLE_IDENTITY ;
createInfo . components . b = VK_COMPONENT_SWIZZLE_IDENTITY ;
createInfo . components . a = VK_COMPONENT_SWIZZLE_IDENTITY ;
createInfo . subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
createInfo . subresourceRange . baseMipLevel = 0 ;
createInfo . subresourceRange . levelCount = 1 ;
createInfo . subresourceRange . baseArrayLayer = 0 ;
createInfo . subresourceRange . layerCount = 1 ;
if ( vkCreateImageView ( device , & createInfo , nullptr , & swapChainImageViews [ i ] ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to create image views! " ) ;
}
}
}
void createRenderPass ( ) {
VkAttachmentDescription colorAttachment { } ;
colorAttachment . format = swapChainImageFormat ;
colorAttachment . samples = VK_SAMPLE_COUNT_1_BIT ;
colorAttachment . loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
colorAttachment . storeOp = VK_ATTACHMENT_STORE_OP_STORE ;
colorAttachment . stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE ;
colorAttachment . stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE ;
colorAttachment . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
colorAttachment . finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ;
VkAttachmentReference colorAttachmentRef { } ;
colorAttachmentRef . attachment = 0 ;
colorAttachmentRef . layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ;
VkSubpassDescription subpass { } ;
subpass . pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS ;
subpass . colorAttachmentCount = 1 ;
subpass . pColorAttachments = & colorAttachmentRef ;
VkSubpassDependency dependency { } ;
dependency . srcSubpass = VK_SUBPASS_EXTERNAL ;
dependency . dstSubpass = 0 ;
dependency . srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ;
dependency . srcAccessMask = 0 ;
dependency . dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ;
dependency . dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT ;
VkRenderPassCreateInfo renderPassInfo { } ;
renderPassInfo . sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO ;
renderPassInfo . attachmentCount = 1 ;
renderPassInfo . pAttachments = & colorAttachment ;
renderPassInfo . subpassCount = 1 ;
renderPassInfo . pSubpasses = & subpass ;
renderPassInfo . dependencyCount = 1 ;
renderPassInfo . pDependencies = & dependency ;
if ( vkCreateRenderPass ( device , & renderPassInfo , nullptr , & renderPass ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to create render pass! " ) ;
}
}
VkShaderModule createShaderModule ( const std : : vector < char > & code ) {
VkShaderModuleCreateInfo createInfo { } ;
createInfo . sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO ;
createInfo . codeSize = code . size ( ) ;
createInfo . pCode = reinterpret_cast < const uint32_t * > ( code . data ( ) ) ;
VkShaderModule shaderModule ;
if ( vkCreateShaderModule ( device , & createInfo , nullptr , & shaderModule ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to create shader module! " ) ;
}
return shaderModule ;
}
void createGraphicsPipeline ( ) {
// 读取着色器代码
auto vertShaderCode = readFile ( " shaders/vert.spv " ) ;
auto fragShaderCode = readFile ( " shaders/frag.spv " ) ;
// 创建着色器模块
VkShaderModule vertShaderModule = createShaderModule ( vertShaderCode ) ;
VkShaderModule fragShaderModule = createShaderModule ( fragShaderCode ) ;
// 顶点着色器阶段创建信息
VkPipelineShaderStageCreateInfo vertShaderStageInfo { } ;
vertShaderStageInfo . sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO ;
vertShaderStageInfo . stage = VK_SHADER_STAGE_VERTEX_BIT ;
vertShaderStageInfo . module = vertShaderModule ;
vertShaderStageInfo . pName = " main " ;
// 片段着色器阶段创建信息
VkPipelineShaderStageCreateInfo fragShaderStageInfo { } ;
fragShaderStageInfo . sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO ;
fragShaderStageInfo . stage = VK_SHADER_STAGE_FRAGMENT_BIT ;
fragShaderStageInfo . module = fragShaderModule ;
fragShaderStageInfo . pName = " main " ;
VkPipelineShaderStageCreateInfo shaderStages [ ] = { vertShaderStageInfo , fragShaderStageInfo } ;
// 顶点输入状态(我们没有顶点缓冲区,在着色器中硬编码顶点)
VkPipelineVertexInputStateCreateInfo vertexInputInfo { } ;
vertexInputInfo . sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STAGE_CREATE_INFO ;
vertexInputInfo . vertexBindingDescriptionCount = 0 ;
vertexInputInfo . pVertexBindingDescriptions = nullptr ; // Optional
vertexInputInfo . vertexAttributeDescriptionCount = 0 ;
vertexInputInfo . pVertexAttributeDescriptions = nullptr ; // Optional
// 输入装配状态(三角形)
VkPipelineInputAssemblyStateCreateInfo inputAssembly { } ;
inputAssembly . sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STAGE_CREATE_INFO ;
inputAssembly . topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ;
inputAssembly . primitiveRestartEnable = VK_FALSE ;
// 视口和裁剪
VkViewport viewport { } ;
viewport . x = 0.0f ;
viewport . y = 0.0f ;
viewport . width = ( float ) swapChainExtent . width ;
viewport . height = ( float ) swapChainExtent . height ;
viewport . minDepth = 0.0f ;
viewport . maxDepth = 1.0f ;
VkRect2D scissor { } ;
scissor . offset = { 0 , 0 } ;
scissor . extent = swapChainExtent ;
VkPipelineViewportStateCreateInfo viewportState { } ;
viewportState . sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO ;
viewportState . viewportCount = 1 ;
viewportState . pViewports = & viewport ;
viewportState . scissorCount = 1 ;
viewportState . pScissors = & scissor ;
// 光栅化器
VkPipelineRasterizationStateCreateInfo rasterizer { } ;
rasterizer . sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STAGE_CREATE_INFO ;
rasterizer . depthClampEnable = VK_FALSE ;
rasterizer . rasterizerDiscardEnable = VK_FALSE ;
rasterizer . polygonMode = VK_POLYGON_MODE_FILL ;
rasterizer . lineWidth = 1.0f ;
rasterizer . cullMode = VK_CULL_MODE_BACK_BIT ;
rasterizer . frontFace = VK_FRONT_FACE_CLOCKWISE ;
rasterizer . depthBiasEnable = VK_FALSE ;
rasterizer . depthBiasConstantFactor = 0.0f ; // Optional
rasterizer . depthBiasClamp = 0.0f ; // Optional
rasterizer . depthBiasSlopeFactor = 0.0f ; // Optional
// 多重采样(禁用)
VkPipelineMultisampleStateCreateInfo multisampling { } ;
multisampling . sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO ;
multisampling . sampleShadingEnable = VK_FALSE ;
multisampling . rasterizationSamples = VK_SAMPLE_COUNT_1_BIT ;
multisampling . minSampleShading = 1.0f ; // Optional
multisampling . pSampleMask = nullptr ; // Optional
multisampling . alphaToCoverageEnable = VK_FALSE ; // Optional
multisampling . alphaToOneEnable = VK_FALSE ; // Optional
// 颜色混合(附件混合状态)
VkPipelineColorBlendAttachmentState colorBlendAttachment { } ;
colorBlendAttachment . colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT ;
colorBlendAttachment . blendEnable = VK_FALSE ;
colorBlendAttachment . srcColorBlendFactor = VK_BLEND_FACTOR_ONE ; // Optional
colorBlendAttachment . dstColorBlendFactor = VK_BLEND_FACTOR_ZERO ; // Optional
colorBlendAttachment . colorBlendOp = VK_BLEND_OP_ADD ; // Optional
colorBlendAttachment . srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE ; // Optional
colorBlendAttachment . dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO ; // Optional
colorBlendAttachment . alphaBlendOp = VK_BLEND_OP_ADD ; // Optional
// 全局颜色混合状态
VkPipelineColorBlendStateCreateInfo colorBlending { } ;
colorBlending . sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO ;
colorBlending . logicOpEnable = VK_FALSE ;
colorBlending . logicOp = VK_LOGIC_OP_COPY ; // Optional
colorBlending . attachmentCount = 1 ;
colorBlending . pAttachments = & colorBlendAttachment ;
colorBlending . blendConstants [ 0 ] = 0.0f ; // Optional
colorBlending . blendConstants [ 1 ] = 0.0f ; // Optional
colorBlending . blendConstants [ 2 ] = 0.0f ; // Optional
colorBlending . blendConstants [ 3 ] = 0.0f ; // Optional
// 管线布局(我们暂时没有uniform变量)
VkPipelineLayoutCreateInfo pipelineLayoutInfo { } ;
pipelineLayoutInfo . sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO ;
pipelineLayoutInfo . setLayoutCount = 0 ; // Optional
pipelineLayoutInfo . pSetLayouts = nullptr ; // Optional
pipelineLayoutInfo . pushConstantRangeCount = 0 ; // Optional
pipelineLayoutInfo . pPushConstantRanges = nullptr ; // Optional
if ( vkCreatePipelineLayout ( device , & pipelineLayoutInfo , nullptr , & pipelineLayout ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to create pipeline layout! " ) ;
}
// 创建图形管线
VkGraphicsPipelineCreateInfo pipelineInfo { } ;
pipelineInfo . sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO ;
pipelineInfo . stageCount = 2 ;
pipelineInfo . pStages = shaderStages ;
pipelineInfo . pVertexInputState = & vertexInputInfo ;
pipelineInfo . pInputAssemblyState = & inputAssembly ;
pipelineInfo . pViewportState = & viewportState ;
pipelineInfo . pRasterizationState = & rasterizer ;
pipelineInfo . pMultisampleState = & multisampling ;
pipelineInfo . pDepthStencilState = nullptr ; // Optional
pipelineInfo . pColorBlendState = & colorBlending ;
pipelineInfo . pDynamicState = nullptr ; // Optional
pipelineInfo . layout = pipelineLayout ;
pipelineInfo . renderPass = renderPass ;
pipelineInfo . subpass = 0 ;
pipelineInfo . basePipelineHandle = VK_NULL_HANDLE ; // Optional
pipelineInfo . basePipelineIndex = - 1 ; // Optional
if ( vkCreateGraphicsPipelines ( device , VK_NULL_HANDLE , 1 , & pipelineInfo , nullptr , & graphicsPipeline ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to create graphics pipeline! " ) ;
}
// 销毁着色器模块(它们已经被编译到管线中,不再需要)
vkDestroyShaderModule ( device , fragShaderModule , nullptr ) ;
vkDestroyShaderModule ( device , vertShaderModule , nullptr ) ;
}
void createFramebuffers ( ) {
swapChainFramebuffers . resize ( swapChainImageViews . size ( ) ) ;
for ( size_t i = 0 ; i < swapChainImageViews . size ( ) ; i + + ) {
VkImageView attachments [ ] = {
swapChainImageViews [ i ]
} ;
VkFramebufferCreateInfo framebufferInfo { } ;
framebufferInfo . sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO ;
framebufferInfo . renderPass = renderPass ;
framebufferInfo . attachmentCount = 1 ;
framebufferInfo . pAttachments = attachments ;
framebufferInfo . width = swapChainExtent . width ;
framebufferInfo . height = swapChainExtent . height ;
framebufferInfo . layers = 1 ;
if ( vkCreateFramebuffer ( device , & framebufferInfo , nullptr , & swapChainFramebuffers [ i ] ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to create framebuffer! " ) ;
}
}
}
void createCommandPool ( ) {
QueueFamilyIndices queueFamilyIndices = findQueueFamilies ( physicalDevice ) ;
VkCommandPoolCreateInfo poolInfo { } ;
poolInfo . sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO ;
poolInfo . flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT ;
poolInfo . queueFamilyIndex = queueFamilyIndices . graphicsFamily . value ( ) ;
if ( vkCreateCommandPool ( device , & poolInfo , nullptr , & commandPool ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to create command pool! " ) ;
}
}
void createCommandBuffer ( ) {
VkCommandBufferAllocateInfo allocInfo { } ;
allocInfo . sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO ;
allocInfo . commandPool = commandPool ;
allocInfo . level = VK_COMMAND_BUFFER_LEVEL_PRIMARY ;
allocInfo . commandBufferCount = 1 ;
if ( vkAllocateCommandBuffers ( device , & allocInfo , & commandBuffer ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to allocate command buffers! " ) ;
}
}
void recordCommandBuffer ( VkCommandBuffer commandBuffer , uint32_t imageIndex ) {
VkCommandBufferBeginInfo beginInfo { } ;
beginInfo . sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO ;
beginInfo . flags = 0 ; // Optional
beginInfo . pInheritanceInfo = nullptr ; // Optional
if ( vkBeginCommandBuffer ( commandBuffer , & beginInfo ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to begin recording command buffer! " ) ;
}
VkRenderPassBeginInfo renderPassInfo { } ;
renderPassInfo . sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO ;
renderPassInfo . renderPass = renderPass ;
renderPassInfo . framebuffer = swapChainFramebuffers [ imageIndex ] ;
renderPassInfo . renderArea . offset = { 0 , 0 } ;
renderPassInfo . renderArea . extent = swapChainExtent ;
VkClearValue clearColor = { { { 0.0f , 0.5f , 0.8f , 1.0f } } } ; // 蓝色清除颜色
renderPassInfo . clearValueCount = 1 ;
renderPassInfo . pClearValues = & clearColor ;
// 开始渲染通道
vkCmdBeginRenderPass ( commandBuffer , & renderPassInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
// 绑定图形管线
vkCmdBindPipeline ( commandBuffer , VK_PIPELINE_BIND_POINT_GRAPHICS , graphicsPipeline ) ;
// 绘制三角形(3个顶点,无顶点缓冲区,在顶点着色器中硬编码)
vkCmdDraw ( commandBuffer , 3 , 1 , 0 , 0 ) ;
// 结束渲染通道
vkCmdEndRenderPass ( commandBuffer ) ;
if ( vkEndCommandBuffer ( commandBuffer ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to record command buffer! " ) ;
}
}
void createSyncObjects ( ) {
VkSemaphoreCreateInfo semaphoreInfo { } ;
semaphoreInfo . sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO ;
VkFenceCreateInfo fenceInfo { } ;
fenceInfo . sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO ;
fenceInfo . flags = VK_FENCE_CREATE_SIGNALED_BIT ; // 初始化为已信号状态,防止第一帧死锁
if ( vkCreateSemaphore ( device , & semaphoreInfo , nullptr , & imageAvailableSemaphore ) ! = VK_SUCCESS | |
vkCreateSemaphore ( device , & semaphoreInfo , nullptr , & renderFinishedSemaphore ) ! = VK_SUCCESS | |
vkCreateFence ( device , & fenceInfo , nullptr , & inFlightFence ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to create synchronization objects for a frame! " ) ;
}
}
void drawFrame ( ) {
// 等待上一帧完成(确保命令缓冲区可用)
vkWaitForFences ( device , 1 , & inFlightFence , VK_TRUE , UINT64_MAX ) ;
vkResetFences ( device , 1 , & inFlightFence ) ;
// 1. 从交换链获取图像
uint32_t imageIndex ;
vkAcquireNextImageKHR ( device , swapChain , UINT64_MAX , imageAvailableSemaphore , VK_NULL_HANDLE , & imageIndex ) ;
// 2. 重置命令缓冲区并录制命令
vkResetCommandBuffer ( commandBuffer , 0 ) ;
recordCommandBuffer ( commandBuffer , imageIndex ) ;
// 3. 提交命令缓冲区
VkSubmitInfo submitInfo { } ;
submitInfo . sType = VK_STRUCTURE_TYPE_SUBMIT_INFO ;
VkSemaphore waitSemaphores [ ] = { imageAvailableSemaphore } ;
VkPipelineStageFlags waitStages [ ] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT } ;
submitInfo . waitSemaphoreCount = 1 ;
submitInfo . pWaitSemaphores = waitSemaphores ;
submitInfo . pWaitDstStageMask = waitStages ;
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & commandBuffer ;
VkSemaphore signalSemaphores [ ] = { renderFinishedSemaphore } ;
submitInfo . signalSemaphoreCount = 1 ;
submitInfo . pSignalSemaphores = signalSemaphores ;
if ( vkQueueSubmit ( graphicsQueue , 1 , & submitInfo , inFlightFence ) ! = VK_SUCCESS ) {
throw std : : runtime_error ( " failed to submit draw command buffer! " ) ;
}
// 4. 呈现图像
VkPresentInfoKHR presentInfo { } ;
presentInfo . sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR ;
presentInfo . waitSemaphoreCount = 1 ;
presentInfo . pWaitSemaphores = signalSemaphores ;
VkSwapchainKHR swapChains [ ] = { swapChain } ;
presentInfo . swapchainCount = 1 ;
presentInfo . pSwapchains = swapChains ;
presentInfo . pImageIndices = & imageIndex ;
presentInfo . pResults = nullptr ; // Optional
vkQueuePresentKHR ( presentQueue , & presentInfo ) ;
}
// --- 辅助函数实现 ---
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 ;
}
std : : vector < const char * > getRequiredExtensions ( ) {
uint32_t glfwExtensionCount = 0 ;
const char * * glfwExtensions ;
glfwExtensions = glfwGetRequiredInstanceExtensions ( & glfwExtensionCount ) ;
std : : vector < const char * > extensions ( glfwExtensions , glfwExtensions + glfwExtensionCount ) ;
if ( enableValidationLayers ) {
extensions . push_back ( VK_EXT_DEBUG_UTILS_EXTENSION_NAME ) ;
}
return extensions ;
}
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback (
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity ,
VkDebugUtilsMessageTypeFlagsEXT messageType ,
const VkDebugUtilsMessengerCallbackDataEXT * pCallbackData ,
void * pUserData ) {
std : : cerr < < " validation layer: " < < pCallbackData - > pMessage < < std : : endl ;
return VK_FALSE ;
}
VkResult CreateDebugUtilsMessengerEXT ( VkInstance instance , const VkDebugUtilsMessengerCreateInfoEXT * pCreateInfo , const VkAllocationCallbacks * pAllocator , VkDebugUtilsMessengerEXT * pDebugMessenger ) {
auto func = ( PFN_vkCreateDebugUtilsMessengerEXT ) vkGetInstanceProcAddr ( instance , " vkCreateDebugUtilsMessengerEXT " ) ;
if ( func ! = nullptr ) {
return func ( instance , pCreateInfo , pAllocator , pDebugMessenger ) ;
} else {
return VK_ERROR_EXTENSION_NOT_PRESENT ;
}
}
void DestroyDebugUtilsMessengerEXT ( VkInstance instance , VkDebugUtilsMessengerEXT debugMessenger , const VkAllocationCallbacks * pAllocator ) {
auto func = ( PFN_vkDestroyDebugUtilsMessengerEXT ) vkGetInstanceProcAddr ( instance , " vkDestroyDebugUtilsMessengerEXT " ) ;
if ( func ! = nullptr ) {
func ( instance , debugMessenger , pAllocator ) ;
}
}
QueueFamilyIndices findQueueFamilies ( VkPhysicalDevice device ) {
QueueFamilyIndices indices ;
uint32_t queueFamilyCount = 0 ;
vkGetPhysicalDeviceQueueFamilyProperties ( device , & queueFamilyCount , nullptr ) ;
std : : vector < VkQueueFamilyProperties > queueFamilies ( queueFamilyCount ) ;
vkGetPhysicalDeviceQueueFamilyProperties ( device , & queueFamilyCount , queueFamilies . data ( ) ) ;
int i = 0 ;
for ( const auto & queueFamily : queueFamilies ) {
if ( queueFamily . queueFlags & VK_QUEUE_GRAPHICS_BIT ) {
indices . graphicsFamily = i ;
}
VkBool32 presentSupport = false ;
vkGetPhysicalDeviceSurfaceSupportKHR ( device , i , surface , & presentSupport ) ;
if ( presentSupport ) {
indices . presentFamily = i ;
}
if ( indices . isComplete ( ) ) {
break ;
}
i + + ;
}
return indices ;
}
bool isDeviceSuitable ( VkPhysicalDevice device ) {
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 ( ) ) ;
for ( const auto & extension : availableExtensions ) {
requiredExtensions . erase ( extension . extensionName ) ;
}
return requiredExtensions . empty ( ) ;
}
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 ;
}
VkSurfaceFormatKHR chooseSwapSurfaceFormat ( const std : : vector < VkSurfaceFormatKHR > & availableFormats ) {
for ( const auto & availableFormat : availableFormats ) {
if ( availableFormat . format = = VK_FORMAT_B8G8R8A8_SRGB & & availableFormat . colorSpace = = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR ) {
return availableFormat ;
}
}
return availableFormats [ 0 ] ;
}
VkPresentModeKHR chooseSwapPresentMode ( const std : : vector < VkPresentModeKHR > & availablePresentModes ) {
for ( const auto & availablePresentMode : availablePresentModes ) {
if ( availablePresentMode = = VK_PRESENT_MODE_MAILBOX_KHR ) {
return availablePresentMode ;
}
}
return VK_PRESENT_MODE_FIFO_KHR ;
}
VkExtent2D chooseSwapExtent ( const VkSurfaceCapabilitiesKHR & capabilities ) {
if ( capabilities . currentExtent . width ! = std : : numeric_limits < uint32_t > : : max ( ) ) {
return capabilities . currentExtent ;
} else {
int width , height ;
glfwGetFramebufferSize ( window , & width , & height ) ;
VkExtent2D actualExtent = {
static_cast < uint32_t > ( width ) ,
static_cast < uint32_t > ( height )
} ;
actualExtent . width = std : : clamp ( actualExtent . width , capabilities . minImageExtent . width , capabilities . maxImageExtent . width ) ;
actualExtent . height = std : : clamp ( actualExtent . height , capabilities . minImageExtent . height , capabilities . maxImageExtent . height ) ;
return actualExtent ;
}
}
} ;
int main ( ) {
HelloTriangleApplication app ;
try {
app . run ( ) ;
} catch ( const std : : exception & e ) {
std : : cerr < < e . what ( ) < < std : : endl ;
return EXIT_FAILURE ;
}
return EXIT_SUCCESS ;
}