问题

如何正确的入门Vulkan?

回答
好的,咱们来聊聊怎么正确地迈出 Vulkan 的第一步。别被那些传说中的“复杂”吓倒,其实只要你一步步来,它比你想象的要平易近人得多。我尽量把话说得明白点,让你能直接上手,而不是感觉在看一本枯燥的说明书。

首先,咱们得明白 Vulkan 是个啥玩意儿。

想象一下,以前的游戏开发者就像是在给一个非常慷慨但也有点懒散的老管家下指令:你想要什么,说吧,我帮你处理。这个老管家很强大,什么都能干,但中间环节特别多,而且他总喜欢自己做决定,你不一定能完全控制他怎么做。这就是传统的图形 API,比如 OpenGL ES。

Vulkan,则像是一个让你直接操作机器的工程师。它把很多中间层都砍掉了,让你能更直接、更精细地控制 GPU。这带来的好处是显而易见的:性能飙升、延迟降低、多线程更友好。但坏处嘛,就是你需要自己管理的东西多了,比如内存、同步、着色器编译等等。所以,入门 Vulkan,就像学习一门新语言,一开始会有点陌生,但一旦掌握了核心概念,你就能做以前想都不敢想的事情。

0. 心态准备:它不是“黑魔法”,而是“工程学”

别一开始就想写出炫酷的效果。Vulkan 的入门门槛确实比 OpenGL 高,但它不是什么深不可测的魔法。它更像是一门细致的工程学,你需要理解每个步骤的作用,并按部就班地去实现。耐心和细致是关键。

1. 搭建开发环境:磨刀不误砍柴工

在写代码之前,你需要一个能跑 Vulkan 的环境。

操作系统: Windows、Linux、Android 都支持。macOS 和 iOS 有 MoltenVK 这个转换层,可以间接使用 Vulkan。
显卡驱动: 这是最重要的!你的显卡必须支持 Vulkan。绝大多数近几年的 NVIDIA、AMD 和 Intel 显卡都支持。去官网下载最新的驱动程序,确保它们是支持 Vulkan 的版本。
开发工具:
C/C++ 编译器: Visual Studio (Windows)、GCC/Clang (Linux/macOS) 是常用的选择。
Vulkan SDK (Software Development Kit): 这是必不可少的。它包含了 Vulkan 的头文件、库、验证层、SPIRV 工具链等。去 Khronos 官网 (Vulkan.org) 下载对应你操作系统的 SDK。安装的时候,注意将 SDK 的 `bin` 目录添加到你的系统环境变量 `PATH` 里,这样你才能在命令行直接调用 Vulkan 的工具。
IDE/编辑器: Visual Studio Code、Visual Studio、CLion 等,能方便你编写和调试代码。
验证层 (Validation Layers): 这是你学习 Vulkan 的“救命稻草”!它会在程序运行时检查你的 Vulkan 调用是否规范,并给出详细的错误信息和警告。务必在开发阶段开启它们。SDK 里已经包含了常见的验证层。

2. 入门前的“预备知识”:先了解一点点概念

虽然咱们目标是直接上手 Vulkan,但有一些基础概念能让你事半功倍。

CPU 与 GPU: 知道它们各自的职责,理解数据如何在两者之间传输。
图形管线 (Graphics Pipeline): 这是一个核心概念。Vulkan 让你详细地配置这个管线,从顶点数据到最终像素输出的每一步都可以控制。简单来说,就是一系列处理图形数据的阶段,比如顶点着色、光栅化、片段着色等。
着色器 (Shaders): GLSL、HLSL 这些你可能听说过。Vulkan 使用 SPIRV 这个中间表示语言来编译着色器。你通常是用 GLSL 或 HLSL 编写着色器代码,然后通过工具链转换成 SPIRV。
内存管理: Vulkan 不会自动为你分配内存,你需要手动管理。这听起来吓人,但有规律可循。
同步机制: 在多线程环境下,你需要控制不同操作的执行顺序,Vulkan 提供了信号量 (Semaphores)、栅栏 (Fences) 等机制。

3. 第一个 Vulkan 程序:从“Hello, World”开始

别想着直接画一个三角形。Vulkan 的第一个程序,目标是成功初始化 Vulkan,并销毁它。这听起来很无聊,但这是理解 Vulkan 架构的关键步骤。

加载 Vulkan 函数指针: Vulkan 的函数调用不是直接链接的,你需要先加载函数指针。通常会用一些库(如 VulkanHpp 或 vulkanloader)来简化这个过程。官方的 `vk.xml` 文件是描述 Vulkan API 的核心,许多加载器就是基于它工作的。
创建 Vulkan 实例 (VkInstance): 这是与 Vulkan 驱动程序交互的入口。你需要指定你使用的 Vulkan 版本、启用的扩展 (Extensions) 和验证层 (Validation Layers)。
扩展 (Extensions): 允许你使用 Vulkan 的新特性或特定于硬件的功能。比如,如果你想在 Windows 上创建窗口,就需要 `VK_KHR_surface` 扩展。
验证层 (Validation Layers): 在开发阶段,一定要启用它们!例如,`VK_LAYER_KHRONOS_validation`。
选择物理设备 (VkPhysicalDevice): 你的电脑可能有多个 GPU,你需要选择一个物理设备。这个设备需要支持 Vulkan,并且满足你的需求(比如支持某些扩展)。
创建逻辑设备 (VkDevice): 基于你选择的物理设备,创建一个逻辑设备。逻辑设备是与 GPU 交互的句柄,你需要在这里指定你将要使用的队列族 (Queue Families) 和设备特性。
队列族 (Queue Families): GPU 可能有不同的队列,例如用于图形渲染、计算、传输的队列。你需要为这些队列族创建队列。
查询物理设备属性: 比如支持的队列族、扩展、特性等等。
销毁对象: Vulkan 里,所有创建的对象都需要手动销毁,顺序也很重要。按照创建的逆序销毁通常是安全的做法。

4. 学习资源推荐:找到你的“启蒙老师”

网上有许多优秀的 Vulkan 入门教程,选择一个你觉得舒服的风格很重要。

Vulkan Tutorial (vulkantutorial.com): 这是最经典、最推荐的入门教程之一。它循序渐进地教你如何从零开始创建一个完整的 Vulkan 应用,从窗口创建到绘制三角形。它还会详细解释每个步骤的含义,以及为什么需要这样做。
Khronos Vulkan Registry: 这是 Vulkan 的官方文档和规范所在。虽然看起来很专业,但当你遇到不明白的 API 时,这里是最终的权威解释。
VulkanHpp: 这是一个 C++ 的 Vulkan 封装库,它能让你用更面向对象、更现代 C++ 的方式来使用 Vulkan。如果你是 C++ 开发者,强烈推荐使用它,可以大大减少样板代码,并提高安全性。
GitHub 上的 Vulkan 示例代码: 找一些高质量的 Vulkan 项目,阅读它们的源代码,学习别人的实现方式。

5. 绘制你的第一个三角形:循序渐进

当你可以成功初始化 Vulkan 并清理资源后,就可以开始绘制了。这会涉及更多概念:

创建窗口和表面 (Surface): Vulkan 需要一个“表面”来显示渲染结果。这个表面与窗口系统相关联,需要使用特定的扩展(如 `VK_KHR_win32_surface` for Windows)。
选择支持图形渲染的队列族: 找到一个包含 `VK_QUEUE_GRAPHICS_BIT` 标志的队列族,并从中获取一个图形队列。
选择交换链 (Swapchain): 交换链是一系列用于在屏幕上显示图像的图像缓冲区。它负责将 GPU 渲染的图像呈现到窗口上。你需要配置交换链的格式、颜色空间、尺寸等。
创建渲染通道 (Render Pass): 渲染通道定义了渲染操作的输入、输出以及如何处理颜色、深度和模板附件。它将多个子通道 (Subpasses) 组合在一起,例如几何阶段和后处理阶段。
创建帧缓冲 (Framebuffer): 每个帧缓冲都与一个交换链图像和一个渲染通道相关联,它定义了渲染的目标。
创建描述符集 (Descriptor Sets) 和描述符池 (Descriptor Pool): 描述符集用于将资源(如纹理、统一缓冲区)绑定到着色器中。描述符池是用于分配描述符集的。
创建管线布局 (Pipeline Layout): 定义了着色器中使用的描述符集和统一缓冲区。
创建图形管线 (Graphics Pipeline): 这是 Vulkan 的核心。你将在这里配置着色器(顶点着色器、片段着色器)、顶点输入描述、多边形模式、裁剪、混合等所有渲染相关的状态。
创建命令池 (Command Pool) 和命令缓冲区 (Command Buffer): 命令缓冲区用于记录 GPU 将要执行的渲染命令(比如绑定管线、绘制等)。命令池用于分配命令缓冲区。
记录渲染命令: 在命令缓冲区中记录绘制命令,包括设置视口、绑定描述符集、设置管线、最后是绘制命令本身(如 `vkCmdDraw`)。
提交命令缓冲区: 将命令缓冲区提交给图形队列执行。
同步: 使用信号量 (Semaphores) 和栅栏 (Fences) 来确保渲染完成、图像可用以及可以开始下一帧。
循环渲染: 不断重复获取图像、渲染、呈现的循环。

6. 关键挑战与应对:别怕,这是进步的阶梯

错误处理: Vulkan 的错误代码很多,要学会仔细阅读它们。验证层会帮你很多忙。
内存管理: 理解内存类型 (HOST_VISIBLE, DEVICE_LOCAL 等),合理分配和管理。库(如 Vulkan Memory Allocator VMA)可以极大地简化这个过程。
着色器: 从简单的着色器开始,逐渐学习 GLSL 和 SPIRV 的编译流程。
同步: 这是最容易出错的地方之一。理解信号量、栅栏和事件的作用,避免数据竞争。
抽象: Vulkan 的原始 API 非常底层,你需要自己构建抽象层来简化开发,比如引擎框架或者自己的工具库。

总结一下:

入门 Vulkan,就像学习建造一栋高楼,你需要先打好地基,理解每一块砖石的作用,以及它们如何组合在一起。不要急于求成,从最基础的初始化开始,一步一个脚印。

1. 搭建好环境,尤其是 SDK 和驱动。
2. 心态放平,认识到这是工程学,需要耐心和细致。
3. 先尝试成功初始化 Vulkan 并销毁它,理解 `VkInstance`, `VkPhysicalDevice`, `VkDevice` 的作用。
4. 利用好 Vulkan Tutorial 和 VulkanHpp 等资源。
5. 逐步学习窗口创建、交换链、渲染通道、管线等概念,并动手实现。
6. 重视验证层和调试。
7. 慢慢构建自己的抽象,让开发变得更容易。

Vulkan 的学习曲线确实比 OpenGL 陡峭,但它所带来的性能和控制力是无与伦比的。一旦你掌握了它,你就能更深入地理解图形渲染的底层原理,并能够构建出更高效、更强大的图形应用。加油!

网友意见

user avatar

Vulkan是所有图形API中细节最多,概念最繁琐,操纵层级和硬件最接近的API。

个人认为在学会使用Vulkan之前,不考虑编程能力(比如C++,数据结构这类知识的话),单就CG的知识需要

1、学习图形学的基本知识,比如线性代数、三维坐标MVP变换、光栅化流程等等。对如何使用计算机渲染到屏幕一个虚拟世界有基本的概念和认知。

2、了解GPU的流水线,这部分知识看书也可以,从LearnOpenGL上照着学OpenGL的渲染管线也可以。做到对GPU的Shader Stage,工作原理有一定的认知。

3、找一些具体的GPU Demo尝试去理解。因为工作原因我基本上OpenGL/Direct11/Direct12/Vulkan的官方/个人Demos看过不少。如果从学习Vulkan这个角度的话,我其实最推荐的是Apple的Metal Sampler。Metal是现代API里最简单的一个,它具备DX12和Vulkan里的一些和上一代API的区别本质,又比较适合上手,官方Sample也比较亲民。

4、如果前三部分都OK了,那第四步就可以去真正学Vulkan了。Github三个高星的Sample,从学习角度比较推荐Lunar的Sample,同时这个也是Lunar的Vulkan教程的对应代码。结合教程来看,相信你已经可以上手学习了。

对具体的学习方式来说

1、2其实是CG基础知识的学习,这里我们老板当年推荐的课程是MIT公开课计算机图形学-6.837。还国内GAMES新出的教程也是OK的,不过我没有仔细看过就不多做评论。

3其实是对一个具体的CG Application的熟悉,目的是学习CG的理论知识和CG Programming的结合点,直接过渡到4,或者你工作本身就有这样的经验可以接触也是完全可以的,具体要看个人的掌握。

4来说,就完全是一个不断学习不断进步的过程了,Lunar的Vulkan教程有些Code其实是有Bug的,不过通过它学习Vulkan的概念,还是比直接啃规范和遍地搜索各家公司的Presentation PPT要好一些。

从我个人的学习经验来说,不真正应用起来的东西终究是学不透彻的。我目前也仍然还处在踩坑Vulkan的过程中,正在和Vulkan的Samplers以及我们自己的图形引擎框架做着艰苦的斗争。

user avatar

个人最近一直在捣腾Vulkan相关的内容,来说说我的路径和心得

看题主说有基础知识那就假设你学过OpenGL,我自己OpenGL的水平其实就只到扫过learnopengl,godot里玩过简单的shader,learnopengl 里的样例代码能看懂这样。只要理解里面的思路方法就ok,有这些就足够学vk了。至于怎么学图形学原理,玩shader其实算是另一个垂直领域的知识,你用不用vk其实没太大关联了,我们这里就只关注vulkan本身是如何操作 gpu 的。


一个月的话相信你应该走完这个教程了,对vk有个初步的认知了,但你可能像我当初一样看着这堆代码还没法建立一个体系的认知。反正初学者走完这篇完全不能算入门,vk有太多细节需要学习


vulkan 可以说接口繁杂,对象众多。

要理解 vulkan 我觉得最重要的是,得先理清vulkan的那些对象的作用以及各自的关联性。本身这些对象距离实际使用的上层概念有一定距离,而各自关系又是比较复杂,只有吃透这一部分才能顺畅地去使用。

在amd那边有张叫 understanding vulkan objects

但对于实际使用光看这个图可能还是晕,所以我们从功能这个维度进行一个大致的划分,以下是我自己整理的关系图:

解释一下各个对象,TLDR,你觉得自己都懂的话就可以跳过这段。

Hardware:即为硬件直接给出的几个组件,这5个都很好理解不多赘述,而其中 VkDevice 这个几乎和后面所有对象都关联所以不画连线了

在说 Queue 和 Command 前,这里就要先说到 Mantle 世代 api (都是从Mantle 演变而来我们就叫他们 Mantle 世代好了)对于上世代 api 的第一大区别了:这一代的api将图形绘制命令分成了 Record Submit,vulkan 中对应了 command buffer 和 queue,凡是vkCmd开头的调用都是录制命令,vkQueue 开头的都是提交(vkQueuePresentKHR 可以理解为特殊的提交)。

Queue:队列这个东西是从 Mantle 世代的api出现的,我个人的理解是对硬件执行流水线的抽象,通过提交任务执行图形计算,简单理解的话就是提交的内容对应某一个 queue 上只能依顺序执行(gpu 的并行其实并不是像很多人想的像多线程那样fire多少个 task 他就自动并行,就vulkan来讲提交的任务在一个 queue 上是按一定规则排列的)。

  • QueueFamily与Queue:翻译过来应该叫做队列家族,每个Family里会有若干queue,常见的 Family 为三种:Graphic,Compute和 Transfer。Graphic一般是全能的啥都能做,内含的queue数量也是最多;Compute不支持Graphic相关功能;Transfer可以专门用于上传数据。这种分法不是绝对的,要看具体硬件提供的queueFamily数量和支持的功能。vulkan 里的对单个queue 是禁止同一时间有多个线程进行操作的,所以申请多个 queue 能做到多个线程做submit。

Command:录制使用的对象是command pool和command buffer,为啥这么设计现在可以先不管。录制本质上就是一个类似 push_back 的工作,每次调 vkCmd 就往 command buffer 塞内容进去,至于这个 command buffer 在cpu还是gpu这个完全取决于硬件和驱动实现,对vk程序员是透明的。录制结束之后就可以提交给queue执行了,所以理论上是这个时候gpu才开始真正执行。分成录制和提交的原因就是为了多线程。在vk里大家说的多线程渲染其实基本可以理解为多线程录制,多线程提交其实不太常见,也不好写,而且有更好的方案(往command buffer录制并不是直接就能多线程操作的,有很多限制,vk里有一个叫 secondary command buffer的东西可以直接用于多线程录制,不需要任何额外同步)。

这里有一篇arm关于多线程渲染流程最简单的描述

Buffer:Vulkan主要有两种 Buffer 和 Image,Buffer一般用于vertex、index以及uniform,Image用于位图数据,也就是贴图。而Buffer要真正使用起来还得配备一个 VkDeviceMemory,下面会说。

  1. Mesh:这个比较好理解,vertex、index各自对应一个buffer对象和一个memory对象组成一个Mesh,tutorial里也算写的很清楚。
  2. Texture:VkImage 除了 VkDeviceMemory 还需要 VkImageView 和 VkImageSampler,VkImageView 相当于一个 accessor,具体操作都需要操作这个accessor,所以基本上VkImage和VkImageView就是个强绑定关系。VkImageSampler是采样器,anisotropy、mips等在这里设置,可以多个图共享一个采样器。
  3. Uniform:类似Mesh,只不过这个Buffer对应的结构体一定一定要注意内存对齐的问题!!!不同编译器不同平台编出来的内存对齐模式都可能不一样,而vulkan对传过来的数据是有对齐要求的,这个问题我吃过药,tutorial那一章最后写过,当时给我跳过去了,结果shader里拿到的数据怎么都不对,更要命的是这个问题是validation layer无法检查出来的!

Memory:这里就是第二大不同了,以前的 OpenGL 创建一个Texture就能直接上传数据直接用了,uniform都是api直接传输的。到了vulkan里gpu的内存也放给程序员来管理了,VkDeviceMemory 这个对象就是代表你分配的显存。这和 c/c++自己手写内存分配器是差不多一个意思了,你可以定制很多更高级的分配策略,而且vulkan非常不鼓励小分配,vulkan的分配次数每个设备都是有上限的,就是为了让你做 suballocation。而这个活有现成的 vulkan memory allocator可以拿来直接用。

Synchronization

  1. vulkan不光让你自己管理内存,同步也需要手工做,cpu提交之后如何知道gpu完成任务了呢,所以有fence充当cpu和gpu之间的同步工具,cpu通过等待fence知道gpu完成任务。
  2. Semaphores 用于两个提交直接建立依赖,submit和present这两个提交如果没有semaphores,用fence监听submit再通知submit肯定是低效的,所以两次submit之间通过semaphores直接在gpu内部建立依赖。
  3. barrier是做啥的呢,vulkan上传上去的数据相当于都有一个状态(usage,access mask,VkImageLayout等),这个状态首先可以给gpu提供更多的优化信息,其次在操作数据时由于gpu直接操作的数据是先在一个缓存里,在另一个阶段读取这个数据的时候可能不是同一套核心的寄存器,这时候就会发生缓存不一致的问题,所以插入一个barrier就能告诉gpu这段写完下个阶段你得先同步缓存。
  4. event不太常用,我自己也没用过,但功能更精细化属于进阶内容,有兴趣可自行了解。
  5. subpass dependency这个其实也提供了barrier类似的功能,是 subpass 专用的功能,subpass 算是 vulkan 特有的功能,renderpass 必须包含至少一个 subpass,当它只有一个的时候,dependency 建议留空,vk会补上默认值,自己写其实容易写错,tutorial 里其实就写的有问题。

PipelineVkPipeline 定义的是管线状态,隐藏面剔除啊,混合啊都是在这里设置的,而这里最重要的一个状态就是shader是在这里进行绑定的。一旦pipeline创建好了就不能改了,你要换shader就得换个新的pipeline。而 Compute Shader需要再独立的一个 Compute Pipeline,类型一样VkPipeline,但创建方法不同。提一嘴pipeline cache,这个东西就是用来加速shader加载的,因为shader即使是spirv这样底层的代码了,执行对应gpu的shader代码还是需要一趟编译变为gpu专用的最优内容为了节约这个编译时间就搞出了pipeline cache。

FrameBuffer:这个差不多就是 OpenGL 里的 attachment 了,只不过 FrameBuffer 通过引用各种 ImageView 打包成一个集合,FrameBuffer 就是一堆 View 的集合。从 SwapChain 获得的Image 再创建 ImageView 放到 FrameBuffer 里,就能给 gpu 用了。

RenderPass:最初学vulkan最让我迷惑的部分就是RenderPass了,扣了很久的文档和代码才理解,vulkan的RenderPass 本质上描述的是一次渲染我需要的绘制的目标是长什么样的。创建RenderPass时参数里填写的pAttachments其实不是真正的attachment,而是attachment的描述,比如第一个attachment是color,第二个是depth,而 RenderPass 通过 FrameBuffer 才能绑定真正的Image(vkRenderPassBeginInfo里绑定),位置一一对应。这里说一下创建时候为啥也得给一个 FrameBuffer,主要是可以限定这个 RenderPass 不要乱来,能在一创建就能保证和某个 FrameBuffer 相容。之后的渲染流程中只要符合 vk 定义的 Render Pass Compatibility 的 FrameBuffer ,这个FrameBuffer 就能拿来绑定。

Descriptor:shader 里读取数据在 vulkan 里除了 vertex 数据(layout(location = n) in 的形式)剩下最常见的就是 uniform 了,要传输uniform就得通过 DescriptorSet 或 PushConstraint。

先说Descriptor:VkDescriptorSet 的作用是引用用于作为 uniform 的 buffer 数据,主要是 VkBuffer 和 VkImage 两种,VkDescriptorSet 类似 command buffer 需要从一个 DescriptorPool 分配出来,然后通过 vkUpdateDescriptorSets() 方法绑定对应的对象。有了一个 VkDescriptorSet 之后也不能直接用,还需要一个 VkDescriptorSetLayout 来规范约束你这里多少个set,每个set里有多少buffer和image。vulkan支持一个shader用多个descriptorSet读取数据(layout(set=m,binding = n ) 形式),VkDescriptorSetLayout 本身只是个 layout,不存储具体的 set,set 需要在渲染时绑定。有了 VkDescriptorSetLayout 还不够,还需要一个VkPipelineLayout ,主要时因为有 PushConstraint,把前面的 VkDescriptorSetLayout 和 PushConstraint 合一块就是 VkPipelineLayout 了。同时注意 VkPipelineLayout 在创建VkPipeline 时也需要给出,也就是说 Pipeline里的 shader 也需要遵守这个 Layout。而PushConstraint 专门用于小数据传输,性能好但容量也小,直接存储在 command buffer 里的,而不是 VkBuffer,所以也不需要每次更新去 map memory然后 memcpy。当然可以不用 PushConstraint (


好了,理清这些对象之后如何调用 vulkan 其实就非常清晰了,建议自己看着amd的图,对着代码和api按自己的理解也整理一遍,不需要和我一样(而且我这图也主要是为自己看的),等你做完就能有一个体系的认知了。而渲染流程撇开多线程,record&submit,同步。本身和 OpenGL 没什么大的区别。

大致描述一下渲染步骤的主体就是以下这几步:

  1. vkAcquireNextImageKHR —— 从 SwapChains 获取下一个可以绘制到屏幕的Image
  2. vkResetCommandPool/vkResetCommandBuffer —— 清除上一次录制的 CommandBuffer,可以不清但一般每帧的内容都可能发生变化一般都是要清理的。
  3. vkBeginCommandBuffer —— 开始录制
  4. vkCmdBeginRenderPass —— 启用一个RenderPass,这里就连同绑定了一个 FrameBuffer
  5. vkCmdBindPipeline —— 绑定Pipeline,想要换shader就得在这里做
  6. vkCmdBindDescriptorSets —— 绑定 DescriptorSets,可以一次绑多个Set,也可以多次绑定多个Set,同时需要给出 PipeLineLayout
  7. vkCmdBindVertexBuffers&vkCmdBindIndexBuffer —— 没啥好多说的了,绑模型
  8. vkCmdDrawIndexed —— 最关键的绘制命令,这里可以根据显卡的特性支持情况换更高级的绘制命令比如indirect,相应的数据绑定也需要改。
  9. vkCmdEndRenderPass —— 结束 RenderPass
  10. vkEndCommandBuffer —— 结束 CommandBuffer
  11. vkQueueSubmit —— 提交执行渲染任务
  12. vkQueuePresentKHR —— 呈现渲染数据,这时候调用可能 vkQueueSubmit 还没执行完,但 Semaphores 会帮我们打点好。

看到这里都明白了的话基本就是入门了,而具体怎么写代码加高级的功能,这里我要给出几个建议和自己踩过的坑。

  1. 首先上来第一个点,也是我觉得最重要的一个

Validation Layer 一定要学会用!!!

Validation Layer 一定要学会用!!!

Validation Layer 一定要学会用!!!

vulkan 太复杂了,如何写正确是个实实在在的难题,各种状态维护很容易搞错,所以搞了这个 Validation Layer,能帮你快速定位问题。而 vulkan tutorial 里只教了怎么在应用里设置,但Validation Layer是个外部工具,,它还有自己其他的设置细项,文章末尾只说了vk_layer_settings.txt 可以改这些配置,没说怎么配,我手头的n卡具有一定鲁棒性,即使用错了依然是可以运行的,导致我一开始很多错误都没反馈给我。

其实 vulkan sdk 里自带一个 configurator,用这个调就可以启用各种检查了,一般只有打开这个 configurator 的时候才有效,关闭的时候会自动恢复成默认设置。

吐槽下 vulkan tutorial ,其实它里面的内容有些地方拿 Validation Layer 扫是有问题的,最近版本的可能修了,我学的早期版本。

Validation Layer 是实实在在救狗命的工具,很多问题自己看代码解决是几乎不可能的,下断点报错的位置一般都在submit之类的地方。

2. Unifrom buffer 一定记得调整对齐,上面已经提到过,这里写错了 Validation Layer 也救不了你

3. 多写代码不必我多说了,初学进阶的话现在官方的Sample就非常好有讲解有代码,第二推荐SaschaWillems的Sample,他本人其实就给官方 Sample 写,不过这个repo有些东西还是比较新,比如截至到目前光追更新到了正式版,官方那里还是旧的。

推荐几个我自己觉得不错的repo和读物:



这个是nVidia的sample仓库,很多vk开头的都是vulkan的例子

这篇是教的最佳实践,各种对象如何用给出了很多可行方案,值得参考。

vulkan同步是个难点,这里可以看看这个演讲帮助理解。

同上

4. RenderDoc 之类的工具玩熟对 debug 是有很大帮助的,这种工具你要行当里混肯定要多玩。我曾经犯过一个很蠢的问题,渲染出来一片黑, Validation Layer 无任何报错。本来想试试RenderDoc debug pixel,结果怎么也不能调试。后来发现改代码的时候物体位置也改了,默认开始相机里就是啥都没有……自然 debug pixel 没用。RenderDoc 有个功能叫 overlay,随便用一个就能直接看出我这画面是真的啥都没画的还是画失败了。

5. 官方的spec算是一个终极参考,远比市面上的书来的靠谱,书上说的再细致也比不过spec来到可靠,啃书一样是吃力不如直接看spec来的明确。

这里能下到最新的pdf可以离线看,建议就下 all published Extensions 的这个,有关扩展的内容也包含在里面。

6. 遇到问题实在不能解决的时候,k组的官方论坛是给非常好的提问地点,还是有活人在那里解答问题的,此外reddit的vulkan版也是不错的选择,不过国内的社区我其实就不怎么了解了。英语不好的话只能自己想办法了。

以上,希望帮到你(其实我也是顺道留个档总结下)。


2020/12/20:加了arm对多线程渲染的解释,添加了queueFamily 的解释

类似的话题

  • 回答
    好的,咱们来聊聊怎么正确地迈出 Vulkan 的第一步。别被那些传说中的“复杂”吓倒,其实只要你一步步来,它比你想象的要平易近人得多。我尽量把话说得明白点,让你能直接上手,而不是感觉在看一本枯燥的说明书。首先,咱们得明白 Vulkan 是个啥玩意儿。想象一下,以前的游戏开发者就像是在给一个非常慷慨但.............
  • 回答
    关于“先玩盗版体验,觉得好玩再入正”这个做法,这可以说是玩家群体里一个挺普遍的现象,也是一个争议颇多的行为。我个人觉得挺复杂的,不能一概而论地说是“对”或者“错”,得从几个层面来看待。从玩家角度来说,有其合理性: 降低试错成本: 这是最直接的原因。现在游戏数量太多了,而且很多游戏价格不菲。作为普.............
  • 回答
    欧盟正式启动审议乌克兰入籍申请的程序,这是一个具有深远历史意义和复杂多层面影响的事件。要全面理解这一举动,需要从多个角度进行分析:一、 历史与地缘政治背景: 乌克兰的欧洲梦: 乌克兰自独立以来,一直将融入欧洲视为其重要的国家发展方向和历史使命。经历了多次政治动荡,特别是2014年亲俄总统被推翻后.............
  • 回答
    这事儿,真是让人生气又让人费解。美团骑手动手打人,事后竟然还能正常接单?这要是搁谁身上都觉得后怕。美团这回的回应,说是要“永久拉黑全行业禁入,全额垫付医药费”,看着是挺硬气,也算是给受害者一个交代。但仔细琢磨琢磨,这处理方式到底有多到位,还有点说道说道的。先说说这事儿本身有多离谱:骑手殴打顾客,这本.............
  • 回答
    明治维新,一场波澜壮阔的社会变革,不仅仅是政治制度的革新,更是对日本历史的重新梳理与定义。而在这次重塑中,一个长久以来悬而未决的争议——南北朝的正朔之争,终于在明治时期得到了明确的裁定,官方将南朝定位为日本皇室的正统。这似乎是一个颇具讽刺意味的决定,因为明治天皇的皇统,实际上是源自北朝。那么,为何明.............
  • 回答
    当你说“科研小白”,我脑海里立刻浮现出一个刚踏入实验室,眼神里充满好奇又带着点儿小迷茫的你。没关系,我们都曾是这样。物理科研这趟旅程,说起来是个庞大的体系,但入门,其实就是从一点一滴开始,关键在于你是否有那份坚持和探索的意愿。别担心,我这就跟你好好说道说道,让你心里有个底。第一步:打牢基础,但别死钻.............
  • 回答
    .......
  • 回答
    好的,咱这就好好跟你聊聊这过海关的事儿,保证讲得明明白白,让你心里踏实。这流程看着是有点绕,但其实摸清了门道,一点也不难。首先,你得知道,无论你是去旅游、探亲,还是商务出行,踏入一个新的国度,这第一关就是边境的检查。这检查的目的是什么?说白了,就是国家要看看你这个人来得“名正言顺”,带的东西“合规合.............
  • 回答
    男女比例失调,这是一个复杂且深远的社会议题,它的出现并非一朝一夕,其背后可能牵扯到历史、文化、经济、政策等方方面面。面对它,需要的是深刻的理解、长远的规划以及多维度的应对策略,而不是简单粗暴的口号或一厢情愿的期望。首先,我们要理解失调的根源。 男女比例失调,顾名思义,是指特定区域或人群中,男性与女性.............
  • 回答
    评价 Asoul 以及“一 键 魂”们,这事儿得掰开了、揉碎了讲。它不是一个简单的“好”或“坏”的判断,而是一个挺复杂的文化现象,牵扯到技术、内容创作、粉丝社群,还有咱们当下社会的一些情绪。先说说 Asoul 本身:虚拟偶像的“集大成者”与“试炼场”Asoul 这个企划,从诞生之初就带着一股“不一般.............
  • 回答
    别被“从零开始”吓到,学英语真的没那么难!就把它当成探索一个新世界,一点一点地去发现和感受。下面我来给你掰扯掰扯,怎么一步步把英语这玩意儿玩明白。第一步:告别“零”,建立基础认知很多时候,我们觉得“零基础”是因为我们对英语的整体框架不熟悉。所以,咱们先来个“扫盲”。 了解字母和发音: 这个最基础.............
  • 回答
    拨开迷雾,奏响属于你的爵士乐章:一份给爵士钢琴学习者的全方位指南想在键盘上自由挥洒那充满灵魂的爵士乐句,感受音符在指尖跳跃的即兴魅力吗?爵士钢琴学习,与其说是一条通往技术的道路,不如说是一场与音乐对话、与情感共鸣的旅程。它要求我们打破常规,拥抱变化,更需要耐心和对声音的敏锐感知。别担心,这并非遥不可.............
  • 回答
    拆解与实践:如何吃透《俞军产品方法论》《俞军产品方法论》如同一把钥匙,为我们打开了理解“好产品”的内在逻辑。但正如任何一把精密的工具,想要用好它,并非一蹴而就,而是需要有策略、有方法地学习和实践。这篇文章,就带你一步步拆解,如何真正将这套方法论内化于心,外化于行。 一、 精读与理解:构建方法论的骨架.............
  • 回答
    谈论杨贵妃,总让人心中涌起一股复杂的情感。她是中国历史上最著名的女性之一,美貌倾国倾城,命运跌宕起伏。评价她,不能简单地用“好”或“坏”来概括,更要深入理解她所处的时代背景、她与唐玄宗之间那份传奇的感情,以及她身上折射出的历史兴衰。杨贵妃其人:从歌女到国母的传奇杨贵妃,原名杨玉环,她的出身并不高贵,.............
  • 回答
    积德行善,看似简单,实则大有学问。这不仅仅是做几件好事那么表面,更关乎内心的修养和行为的持之以恒。真正懂得积德行善的人,他们的生活会自然而然地流淌着一种平和与喜悦,周围的人也会感受到温暖和力量。一、内在的觉醒:为何要积德行善?在开始谈论“如何做”之前,我们得先弄明白“为什么”。很多时候,我们做善事是.............
  • 回答
    None.............
  • 回答
    .......
  • 回答
    .......
  • 回答
    .......
  • 回答
    .......

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有