都说vulkan是OpenGLnext,相对于OpenGL,vulkan在效率上有着巨量的提升。Vulkan在效率上的提升主要是它天然支持多线程。而且拥有异步数据交换,使用OpenGL时,如果把数据交互放到另一个独立线程中完成,将会引起冲突,这个原因是上传资源和进行绘制时都需要改变上下文,Vulkan则没有这个问题。Vulkan可以并行创建Command Buffer并行绘制,但由于Command Buffer 提交后就都是GPU驱动怎么执行的事了,执行的过程没必要也没可能用多线程加速。 但随之而来的是巨量的代码量的提升,写一个三色三角形需要1500+行的代码,我也不知道我是怎么回事要对这个麻烦的东西产生兴趣,估计不久我就回去继续看OpenGL了…
接下来着重介绍一下VulkanManager类
该类完成了Vulkan图形应用程序所需的各种基础工作(实例创建、销毁以及绘制)。本质上,该类是Vulkan项目的核心管理者。
#ifndef VULKANEXBASE_MYVULKANMANAGER_H
#define VULKANEXBASE_MYVULKANMANAGER_H
#include
#include
#include
#include "../util/DrawableObjectCommon.h"
#include "ShaderQueueSuit_Common.h"
#define FENCE_TIMEOUT 100000000
class MyVulkanManager
{
public:
//窗口辅助结构体
static struct WindowInfo info;
//vulkan绘制的循环标志
static bool loopDrawFlag;
static std::vector<const char *> instanceExtensionNames;//需要使用的实例扩展名称列表
static VkInstance instance;//Vulkan实例
static uint32_t gpuCount;//物理设备数量
static std::vector<VkPhysicalDevice> gpus; //物理设备列表
static uint32_t queueFamilyCount;//物理设备对应的队列家族数量
static std::vector<VkQueueFamilyProperties> queueFamilyprops;//物理设备对应的队列家族属性列表
static uint32_t queueGraphicsFamilyIndex;//支持图形工作的队列家族索引
static VkQueue queueGraphics;//支持图形工作的队列
static uint32_t queuePresentFamilyIndex;//支持显示工作的队列家族索引
static std::vector<const char *> deviceExtensionNames; //所需的设备扩展名称列表
static VkDevice device; //逻辑设备
static VkCommandPool cmdPool;//命令池
static VkCommandBuffer cmdBuffer;//命令缓冲
static VkCommandBufferBeginInfo cmd_buf_info;//命令缓冲启动信息
static VkCommandBuffer cmd_bufs[1]; //供提交执行的命令缓冲数组
static VkSubmitInfo submit_info[1]; //命令缓冲提交执行信息数组
static uint32_t screenWidth;//屏幕宽度
static uint32_t screenHeight;//屏幕高度
static VkSurfaceKHR surface;//KHR表面
static std::vector<VkFormat> formats;//KHR表面支持的格式
static VkSurfaceCapabilitiesKHR surfCapabilities;//表面的能力
static uint32_t presentModeCount;//显示模式数量
static std::vector<VkPresentModeKHR> presentModes;//显示模式列表
static VkExtent2D swapchainExtent;//交换链尺寸
static VkSwapchainKHR swapChain;//交换链
static uint32_t swapchainImageCount;//交换链中的图像数量
static std::vector<VkImage> swapchainImages;//交换链中的图像列表
static std::vector<VkImageView> swapchainImageViews;//交换链对应的的图像视图列表
static VkFormat depthFormat;//深度图像格式
static VkFormatProperties depthFormatProps; //物理设备支持的深度格式属性
static VkImage depthImage;//深度缓冲图像
static VkPhysicalDeviceMemoryProperties memoryroperties;//物理设备内存属性
static VkDeviceMemory memDepth; //深度缓冲图像对应的内存
static VkImageView depthImageView;//深度缓冲图像视图
static VkSemaphore imageAcquiredSemaphore;//渲染目标图像获取完成信号量
static uint32_t currentBuffer;//从交换链中获取的当前渲染用图像对应的缓冲编号
static VkRenderPass renderPass;//渲染通道
static VkClearValue clear_values[2];//渲染通道用清除帧缓冲深度、颜色附件的数据
static VkRenderPassBeginInfo rp_begin;//渲染通道启动信息
static VkFence taskFinishFence;//等待任务完毕的栅栏
static VkPresentInfoKHR present;//呈现信息
static VkFramebuffer* framebuffers;//帧缓冲序列首指针
static ShaderQueueSuit_Common* sqsCL;//着色器管线指针
static DrawableObjectCommonLight* triForDraw;//绘制用三色三角形物体对象指针
//三角形旋转角度
static float xAngle;
static float yAngle;
static float zAngle;
static void init_vulkan_instance();//创建Vulkan实例
static void enumerate_vulkan_phy_devices();//初始化物理设备
static void create_vulkan_devices();//创建逻辑设备
static void create_vulkan_CommandBuffer();//创建命令缓冲
static void create_vulkan_swapChain();//初始化交换链
static void create_vulkan_DepthBuffer();//创建深度缓冲相关
static void create_render_pass();//创建渲染通道
static void init_queue();//获取设备中支持图形工作的队列
static void create_frame_buffer();//创建帧缓冲
static void createDrawableObject();//创建绘制用物体
static void drawObject();//执行场景中的物体绘制
static void doVulkan();//启动线程执行Vulkan任务
static void initPipeline();//初始化管线
static void createFence();//创建栅栏
static void initPresentInfo();//初始化显示信息
static void initMatrix();//初始化矩阵
static void flushUniformBuffer();//将一致变量数据送入缓冲
static void flushTexToDesSet();//将纹理等数据与描述集关联
static void destroyFence();//销毁栅栏
static void destroyPipeline();//销毁管线
static void destroyDrawableObject();//销毁绘制用物体
static void destroy_frame_buffer();//销毁帧缓冲
static void destroy_render_pass();//销毁渲染通道
static void destroy_vulkan_DepthBuffer();//销毁深度缓冲相关
static void destroy_vulkan_swapChain();//销毁交换链
static void destroy_vulkan_CommandBuffer();//销毁命令缓冲
static void destroy_vulkan_devices();//销毁逻辑设备
static void destroy_vulkan_instance();//销毁实例
};
#endif //VULKANEXBASE_MYVULKANMANAGER_H
相当于OpenGL中 glfwInit()方法的效果。
其中包含了加载Vulkan动态库、初始化所需实例的扩展名称列表、构建应用信息结构体struct等关键步骤。
//创建vulkan实例的方法
void MyVulkanManager::init_vulkan_instance()
{
//初始化所需扩展列表,下列两个扩展是Android下做渲染必须要的
instanceExtensionNames.push_back(VK_KHR_SURFACE_EXTENSION_NAME);//此处移植Windows不需更改
instanceExtensionNames.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);//此处移植Windows需要获取VK_KHR_SURFACE_EXTENSION_NAME扩展
//VkApplicationInfo应用信息
VkApplicationInfo app_info = {};//构建应用信息结构体实例
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;//结构体的类型
app_info.pNext = NULL;//自定义数据的指针
app_info.pApplicationName = "HelloVulkan";//应用的名称
app_info.applicationVersion = 1;//应用的版本号
app_info.pEngineName = "HelloVulkan";//应用的引擎名称
app_info.engineVersion = 1;//应用的引擎版本号
app_info.apiVersion = VK_API_VERSION_1_0;//使用的Vulkan图形应用程序API版本
//VkInstanceCreateInfo实例创建信息
VkInstanceCreateInfo inst_info = {};//构建实例创建信息结构体实例
inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;//结构体的类型
inst_info.pNext = NULL;//自定义数据的指针
inst_info.flags = 0;//供将来使用的标志
inst_info.pApplicationInfo = &app_info;//绑定应用信息结构体
inst_info.enabledExtensionCount = instanceExtensionNames.size();//扩展的数量
inst_info.ppEnabledExtensionNames = instanceExtensionNames.data();//扩展名称列表数据
inst_info.enabledLayerCount = 0;//启动的层数量
inst_info.ppEnabledLayerNames = NULL;//启动的层名称列表
VkResult result;//存储运行结果的辅助变量
//创建Vulkan实例
result = vkCreateInstance(&inst_info, NULL, &instance);//创建实例
if (result == VK_SUCCESS)
{
printf("Vulkan实例创建成功!\n");
}
else
{
printf("Vulkan实例创建失败!\n");
}
}
这个比较简单,调用core方法就好
//销毁vulkan实例的方法
void MyVulkanManager::destroy_vulkan_instance()
{
vkDestroyInstance(instance, NULL);
printf("Vulkan实例销毁完毕!\n");
destroy_window(info);
}
这应该是相当于OpenGL里glad初始化方法
这是在创建完实例之后,获取物理设备的数量、内存、list等信息
这里有一个Vulkan编程技巧:先传入空的列表指针,然后在获取后再填充列表
//获取硬件设备的方法(GPU)
void MyVulkanManager::enumerate_vulkan_phy_devices()
{
gpuCount = 0;//存储物理设备数量的变量
VkResult result = vkEnumeratePhysicalDevices(instance, &gpuCount, NULL);//获取物理设备数量
assert(result == VK_SUCCESS);
printf("[Vulkan硬件设备数量为%d个]", gpuCount);
gpus.resize(gpuCount);//设置物理设备列表尺寸
result =vkEnumeratePhysicalDevices(instance, &gpuCount, gpus.data());//填充物理设备列表
assert(result == VK_SUCCESS);
vkGetPhysicalDeviceMemoryProperties(gpus[USED_GPU_INDEX], &memoryroperties);//获取第一物理设备的内存属性
}
这里主要包含了构建命令池的各种实例的方法、信息的set以及命令的分配。
主命令缓冲直接提交给队列执行,子命令缓冲通过所属的主命令缓冲来执行,不能直接提交给队列。
//创建命令缓冲的方法
void MyVulkanManager::create_vulkan_CommandBuffer()
{
VkCommandPoolCreateInfo cmd_pool_info = {};//构建命令池创建信息结构体实例
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; //给定结构体类型
cmd_pool_info.pNext = NULL;//自定义数据的指针
cmd_pool_info.queueFamilyIndex = queueGraphicsFamilyIndex;//绑定所需队列家族索引
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; //执行控制标志
VkResult result = vkCreateCommandPool(device, &cmd_pool_info, NULL, &cmdPool);//创建命令池
assert(result == VK_SUCCESS);//检查命令池创建是否成功
VkCommandBufferAllocateInfo cmdBAI = {};//构建命令缓冲分配信息结构体实例
cmdBAI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;//给定结构体类型
cmdBAI.pNext = NULL;//自定义数据的指针
cmdBAI.commandPool = cmdPool;//指定命令池
cmdBAI.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;//分配的命令缓冲级别
cmdBAI.commandBufferCount = 1;//分配的命令缓冲数量
result = vkAllocateCommandBuffers(device, &cmdBAI, &cmdBuffer);//分配命令缓冲
assert(result == VK_SUCCESS);//检查分配是否成功
cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;//给定结构体类型
cmd_buf_info.pNext = NULL;//自定义数据的指针
cmd_buf_info.flags = 0;//描述使用标志
cmd_buf_info.pInheritanceInfo = NULL;//命令缓冲继承信息
cmd_bufs[0] = cmdBuffer;//要提交到队列执行的命令缓冲数组
VkPipelineStageFlags* pipe_stage_flags = new VkPipelineStageFlags();//目标管线阶段
*pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
submit_info[0].pNext = NULL;//自定义数据的指针
submit_info[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;//给定结构体类型
submit_info[0].pWaitDstStageMask = pipe_stage_flags;//给定目标管线阶段
submit_info[0].commandBufferCount = 1;//命令缓冲数量
submit_info[0].pCommandBuffers = cmd_bufs;//提交的命令缓冲数组
submit_info[0].signalSemaphoreCount = 0;//信号量数量
submit_info[0].pSignalSemaphores = NULL;//信号量数组
}
相对应的我们也要回收命令缓冲,所以需要销毁方法
void MyVulkanManager::destroy_vulkan_CommandBuffer()//销毁命令缓冲的方法
{
//创建要释放的命令缓冲数组
VkCommandBuffer cmdBufferArray[1] = { cmdBuffer };
//释放命令缓冲
vkFreeCommandBuffers
(
device, //所属逻辑设备
cmdPool,//所属命令池
1, //要销毁的命令缓冲数量
cmdBufferArray//要销毁的命令缓冲数组
);
//销毁命令池
vkDestroyCommandPool(device, cmdPool, NULL);
}
交换链(SwapChain)是vulkan中执行呈现工作的重要策略,需要呈现模块的vulkan应用程序都应该初始化所需的交换链。
//创建绘制用swapChain的方法
void MyVulkanManager::create_vulkan_swapChain()
{
//构建KHR表面创建信息结构体实例
VkWin32SurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;//给定结构体类型
createInfo.pNext = nullptr;//自定义数据的指针
createInfo.flags = 0;//供未来使用的标志
createInfo.hwnd = info.window;//给定窗体
//创建KHR表面
VkResult result=vkCreateWin32SurfaceKHR(instance, &createInfo, nullptr, &surface);
assert(result == VK_SUCCESS);
//遍历设备对应的队列家族列表
VkBool32 *pSupportsPresent = (VkBool32 *)malloc(queueFamilyCount * sizeof(VkBool32));
for (uint32_t i = 0; i < queueFamilyCount; i++)
{
vkGetPhysicalDeviceSurfaceSupportKHR(gpus[USED_GPU_INDEX], i, surface, &pSupportsPresent[i]);
printf("队列家族索引=%d %s显示\n", i, (pSupportsPresent[i] == 1 ? "支持" : "不支持"));
}
queueGraphicsFamilyIndex = UINT32_MAX;//支持图形工作的队列家族索引
queuePresentFamilyIndex = UINT32_MAX;//支持显示(呈现)工作的队列家族索引
for (uint32_t i = 0; i <queueFamilyCount; ++i)//遍历设备对应的队列家族列表
{
//如果当前遍历到的队列家族支持Graphis(图形)工作
if ((queueFamilyprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)//若此队列家族支持图形工作
{
//记录支持Graphis(图形)工作的队列家族索引
if (queueGraphicsFamilyIndex == UINT32_MAX) queueGraphicsFamilyIndex = i;
//如果当前遍历到的队列家族支持Present(显示工作)工作
if (pSupportsPresent[i] == VK_TRUE)//如果当前队列家族支持显示工作
{
queueGraphicsFamilyIndex = i;//记录此队列家族索引为支持图形工作的
queuePresentFamilyIndex = i;//记录此队列家族索引为支持显示工作的
printf("队列家族索引=%d 同时支持Graphis(图形)和Present(显示)工作\n", i);
break;
}
}
}
if (queuePresentFamilyIndex == UINT32_MAX)//若没有找到同时支持两项工作的队列家族
{
for (size_t i = 0; i < queueFamilyCount; ++i)//遍历设备对应的队列家族列表
{
if (pSupportsPresent[i] == VK_TRUE)//判断是否支持显示工作
{
queuePresentFamilyIndex = i;//记录此队列家族索引为支持显示工作的
break;
}
}
}
free(pSupportsPresent);//释放存储是否支持呈现工作的布尔值列表
//没有找到支持Graphis(图形)或Present(显示)工作的队列家族
//没有找到支持图形或显示工作的队列家族
if (queueGraphicsFamilyIndex == UINT32_MAX || queuePresentFamilyIndex == UINT32_MAX)
{
printf("没有找到支持Graphis(图形)或Present(显示)工作的队列家族\n");
assert(false);//若没有支持图形或显示操作的队列家族则程序终止
}
uint32_t formatCount;//支持的格式数量
result = vkGetPhysicalDeviceSurfaceFormatsKHR(gpus[0], surface, &formatCount, NULL);//获取支持的格式数量
printf("支持的格式数量为 %d\n", formatCount);
VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));//分配对应数量的空间
formats.resize(formatCount);//调整对应Vector尺寸
result = vkGetPhysicalDeviceSurfaceFormatsKHR(gpus[0], surface, &formatCount, surfFormats);//获取支持的格式信息
for (unsigned int i = 0; i<formatCount; i++) {//记录支持的格式信息
formats[i] = surfFormats[i].format;
printf("[%d]支持的格式为%d\n", i, formats[i]);
}
if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {//特殊情况处理
formats[0] = VK_FORMAT_B8G8R8A8_UNORM;
}
free(surfFormats);
//获取KHR表面的能力
result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gpus[USED_GPU_INDEX], surface, &surfCapabilities);
assert(result == VK_SUCCESS);
//获取支持的显示模式数量
result = vkGetPhysicalDeviceSurfacePresentModesKHR(gpus[USED_GPU_INDEX], surface, &presentModeCount, NULL);
assert(result == VK_SUCCESS);
printf("显示模式数量为%d\n", presentModeCount);
//调整对应Vector尺寸
presentModes.resize(presentModeCount);
//获取支持的显示模式列表
result = vkGetPhysicalDeviceSurfacePresentModesKHR(gpus[USED_GPU_INDEX], surface, &presentModeCount, presentModes.data());
for (unsigned int i = 0; i<presentModeCount; i++)
{
printf("显示模式[%d]编号为%d\n", i, presentModes[i]);
}
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;//确定交换链显示模式
for (size_t i = 0; i < presentModeCount; i++)//遍历显示模式列表
{
//如果也支持VK_PRESENT_MODE_MAILBOX_KHR模式,由于其效率高,便选用
if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
{
swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
break;
}
if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR))
{
//如果没能用上VK_PRESENT_MODE_MAILBOX_KHR模式,但有VK_PRESENT_MODE_IMMEDIATE_KHR模式
//也比VK_PRESENT_MODE_FIFO_KHR模式强,故选用
swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
}
}
//确定surface的宽度、高度
//如果surface能力中的尺寸没有定义(宽度为0xFFFFFFFF表示没定义)
if (surfCapabilities.currentExtent.width == 0xFFFFFFFF)
{
swapchainExtent.width = screenWidth;//设置宽度为窗体宽度
swapchainExtent.height = screenHeight;//设置高度为窗体高度
//宽度设置值限制到最大值与最小值之间
if (swapchainExtent.width < surfCapabilities.minImageExtent.width)
{
swapchainExtent.width = surfCapabilities.minImageExtent.width;
}
else if (swapchainExtent.width > surfCapabilities.maxImageExtent.width)
{
swapchainExtent.width = surfCapabilities.maxImageExtent.width;
}
//高度设置值限制到最大值与最小值之间
if (swapchainExtent.height < surfCapabilities.minImageExtent.height)
{
swapchainExtent.height = surfCapabilities.minImageExtent.height;
}
else if (swapchainExtent.height > surfCapabilities.maxImageExtent.height)
{
swapchainExtent.height = surfCapabilities.maxImageExtent.height;
}
printf("使用自己设置的 宽度 %d 高度 %d\n", swapchainExtent.width, swapchainExtent.height);
}
else
{
//若表面有确定尺寸
swapchainExtent = surfCapabilities.currentExtent;
printf("使用获取的surface能力中的 宽度 %d 高度 %d\n", swapchainExtent.width, swapchainExtent.height);
}
screenWidth = swapchainExtent.width;//记录实际采用的宽度
screenHeight = swapchainExtent.height;//记录实际采用的高度
//期望交换链中的最少图像数量
uint32_t desiredMinNumberOfSwapChainImages = surfCapabilities.minImageCount + 1;
//将数量限制到范围内
if ((surfCapabilities.maxImageCount > 0) && (desiredMinNumberOfSwapChainImages > surfCapabilities.maxImageCount))
{
desiredMinNumberOfSwapChainImages = surfCapabilities.maxImageCount;
}
//KHR表面变换标志
VkSurfaceTransformFlagBitsKHR preTransform;
if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)//若支持所需的变换
{
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
}
else//若不支持变换
{
preTransform = surfCapabilities.currentTransform;
}
VkSwapchainCreateInfoKHR swapchain_ci = {};//构建交换链创建信息结构体实例
swapchain_ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;//结构体类型
swapchain_ci.pNext = NULL;//自定义数据的指针
swapchain_ci.surface = surface;//指定KHR表面
swapchain_ci.minImageCount = desiredMinNumberOfSwapChainImages;//最少图像数量
swapchain_ci.imageFormat = formats[0];//图像格式
swapchain_ci.imageExtent.width = swapchainExtent.width;//交换链图像宽度
swapchain_ci.imageExtent.height = swapchainExtent.height;//交换链图像高度
swapchain_ci.preTransform = preTransform;//指定变换标志
swapchain_ci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;//混合Alpha值
swapchain_ci.imageArrayLayers = 1;//图像数组层数
swapchain_ci.presentMode = swapchainPresentMode;//交换链的显示模式
swapchain_ci.oldSwapchain = VK_NULL_HANDLE;//前导交换链
swapchain_ci.clipped = true;//开启剪裁
swapchain_ci.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;//色彩空间
swapchain_ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;//图像用途
swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; //图像共享模式
swapchain_ci.queueFamilyIndexCount = 0;//队列家族数量
swapchain_ci.pQueueFamilyIndices = NULL;//队列家族索引列表
if (queueGraphicsFamilyIndex != queuePresentFamilyIndex)//若支持图形和显示工作的队列家族不相同
{
swapchain_ci.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
swapchain_ci.queueFamilyIndexCount = 2;//交换链所需的队列家族索引数量为2
uint32_t queueFamilyIndices[2] = { queueGraphicsFamilyIndex,queuePresentFamilyIndex };
swapchain_ci.pQueueFamilyIndices = queueFamilyIndices;//交换链所需的队列家族索引列表
}
result = vkCreateSwapchainKHR(device, &swapchain_ci, NULL, &swapChain);//创建交换链
assert(result == VK_SUCCESS);//检查交换链是否创建成功
//获取交换链中的图像数量
result = vkGetSwapchainImagesKHR(device, swapChain, &swapchainImageCount, NULL);
assert(result == VK_SUCCESS);
printf("[SwapChain中的Image数量为%d]\n", swapchainImageCount);//检查是否获取成功
swapchainImages.resize(swapchainImageCount);//调整图像列表尺寸
//获取交换链中的图像列表
result =vkGetSwapchainImagesKHR(device, swapChain, &swapchainImageCount, swapchainImages.data());
assert(result == VK_SUCCESS);
swapchainImageViews.resize(swapchainImageCount);//调整图像视图列表尺寸
for (uint32_t i = 0; i < swapchainImageCount; i++)//为交换链中的各幅图像创建图像视图
{
VkImageViewCreateInfo color_image_view = {};//构建图像视图创建信息结构体实例
color_image_view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;//设置结构体类型
color_image_view.pNext = NULL;//自定义数据的指针
color_image_view.flags = 0;//供将来使用的标志
color_image_view.image = swapchainImages[i];//对应交换链图像
color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D;//图像视图的类型
color_image_view.format = formats[0];//图像视图格式
color_image_view.components.r = VK_COMPONENT_SWIZZLE_R;//设置R通道调和
color_image_view.components.g = VK_COMPONENT_SWIZZLE_G;//设置G通道调和
color_image_view.components.b = VK_COMPONENT_SWIZZLE_B;//设置B通道调和
color_image_view.components.a = VK_COMPONENT_SWIZZLE_A;//设置A通道调和
color_image_view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;//图像视图使用方面
color_image_view.subresourceRange.baseMipLevel = 0;//基础Mipmap级别
color_image_view.subresourceRange.levelCount = 1;//Mipmap级别的数量
color_image_view.subresourceRange.baseArrayLayer = 0;//基础数组层
color_image_view.subresourceRange.layerCount = 1;//数组层的数量
result = vkCreateImageView(device, &color_image_view, NULL, &swapchainImageViews[i]);//创建图像视图
assert(result == VK_SUCCESS);//检查是否创建成功
}
}
void MyVulkanManager::drawObject()
{
FPSUtil::init();//初始化FPS计算
while (MyVulkanManager::loopDrawFlag)//每循环一次绘制一帧画面
{
FPSUtil::calFPS();//计算FPS
FPSUtil::before();//一帧开始
//获取交换链中的当前帧索引
VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAcquiredSemaphore, VK_NULL_HANDLE, ¤tBuffer);
//为渲染通道设置当前帧缓冲
rp_begin.framebuffer = framebuffers[currentBuffer];
vkResetCommandBuffer(cmdBuffer, 0);//恢复命令缓冲到初始状态
result = vkBeginCommandBuffer(cmdBuffer, &cmd_buf_info);//启动命令缓冲
MyVulkanManager::flushUniformBuffer();//将当前帧相关数据送入一致变量缓冲
MyVulkanManager::flushTexToDesSet();//更新绘制用描述集
vkCmdBeginRenderPass(cmdBuffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);//启动渲染通道
triForDraw->drawSelf(cmdBuffer, sqsCL->pipelineLayout, sqsCL->pipeline, &(sqsCL->descSet[0]));//绘制三色三角形
vkCmdEndRenderPass(cmdBuffer);//结束渲染通道
result = vkEndCommandBuffer(cmdBuffer);//结束命令缓冲
submit_info[0].waitSemaphoreCount = 1;//等待的信号量数量
submit_info[0].pWaitSemaphores = &imageAcquiredSemaphore;//等待的信号量列表
result = vkQueueSubmit(queueGraphics, 1, submit_info, taskFinishFence);//提交命令缓冲
do { //等待渲染完毕
result =vkWaitForFences(device, 1, &taskFinishFence, VK_TRUE, FENCE_TIMEOUT);
} while (result == VK_TIMEOUT);
vkResetFences(device, 1, &taskFinishFence);//重置栅栏
present.pImageIndices = ¤tBuffer;//指定此次呈现的交换链图像索引
result =vkQueuePresentKHR(queueGraphics, &present);//执行呈现
FPSUtil::after(60);//限制FPS不超过指定的值
}
}