🗒️引擎开发日志1 - Vulkan封装
type
status
date
slug
summary
tags
category
icon
password

技术栈

  • 底层图形API:Vulkan
  • 引擎语言:C++
  • 脚本语言:暂定Lua
  • 引擎的设计模式:主体采用ECS+MVC

Vulkan Base

Context上下文
Swapchain交换链
RenderProcess渲染阶段的Pipline、Layout封装
Renderer渲染器
Shader着色器
CommandMgr命令管理器
Vec2、Vec4、Mat4数学库(暂定先实现这些)
Texture纹理
DescriptorMgr描述符

Manager

ShaderMgr:负责管理Shaders,目前暂时采用哈希表映射
TextureMgr:在原有的TextureMgr基础上增加材质的管理
ModelMgr:管理模型

Descriptor Problem

目前封装存在的最大的问题是不够独立,新的模块需要频繁更改封装好的Vulkan库的代码,需要进一步将公用接口进行隔离。

引入

假设两个Shader,不考虑frag和vert,那么可能会出现以下共用uniform的情况:
 
 
我们会发现,view、projection和worldTime是公用的全局变量,可能多个Shader都会用到它,所以他们的Descriptor应该是只有一个的,而不能每个Shader都拥有一个相同Descriptor的拷贝,不然当项目大了起来对内存来说是致命的。
我们需要引入一个管理这些uniform相关的数据结构。

原有的流程

Context创建Shader模块

这个示例中,首先获取了ShaderMgr,然后创建名字为default的shader,然后设置DescriptorSetLayoutBinding,分别为MVP矩阵和texture:
其中ShaderMgr关于SetDescriptorSetLayoutBinding和CreateDescriptorSetLayout的函数如下:
descriptorSetLayoutBindings是一个键值对,需要提供这个描述符的绑定点名称和所属于的集合。
descriptorSetLayouts是创建后的layout,通过集合名称确定。
notion image
 

RenderPass确定Layout

Renderer阶段获取更新set

理解Descriptor

如下图所示:
notion image
不像OpenGL,Vulkan不能对单独的Uniform或者其他被描述的变量进行Buffer。而是采用集合的设计,将要在Shader使用的Uniform变量的布局被SetLayout指定,通过vk::DescriptorPool 分配出vk::DescriptorSet ,再由这个集合Buffer。这样做的效率比OpenGL高很多。
还是原来的问题,考虑公共UBO,比如viewprojection ,他们在渲染的过程中,只需要绑定一次即可。如果在OpenGL,每切换一个绘制对象就要重新绑定。所以很浪费效率。

Solution

解决方案是分别封装DescriptorPool,DescriptorSetLayout,DescriptorWriter,每个类都会有各自的Builder。

DescriptorSetLayout

该类提供创建vk::DescriptorSetLayout 的相应接口,能够接受多个多个binding。使用的方法如下:
这说明创建了一个全局setlayout,描述了一个binding = 0的uniform对象:
可以设置多个binding,只需要:
描述了:

DescriptorPool

DescriptorWriter

FrameInfo Problem

现在存在一个很大的问题就是FrameInfo的封装可以说是基本没有:
可以看到,不同的RenderSystem,可能会用不同的FrameInfo,我们这样使用会让代码非常的丑,而且很冗余。
目前能想到的解决方案之一就是修改FrameInfo的结构体:
将原来的的set改成了map,就方便集成descriptorSet了。
不过大概率之后会改,因为总会遇到很复杂的情况。

UBO

在vulkan中uniform不能单独buffer到device,需要由descriptor set描述,而descirptor set需要由descriptor pool分配。
基于这个理念,结合之前封装的Descriptor组件,可以封装出一个这样的UBO模板类:
记录第一次做肠镜检查Neural Radiance Fields
Loading...