1. Overview of Vulkan

1.1 计算机图形软件

图形软件有两个大类:专用软件包(special-purpose packages)和通用编程软件包(general program-
ming packages)。

专用软件包通常提供一种UI设计语言,让用户直接生成想要的图形,不用关心内部实现。这类软件例子是PS、CAD等等。

相反,通用编程软件包提供一个可使用C、C++或Java等高级语言编程的图形函数库。图形函数库中提供几何图元、矩阵变换等操作,提供了间接操作硬件的软件接口,所以这组图形函数又被称为计算机图形应用编程接口(computer-graphics application programming interface,CG API)。OpenGL、Vulkan、DirectX、Metal皆在此列。

1.2 Vulkan多线程的设计理念

Vulkan不仅仅是图形(graphics)API,而是一个面向图形和计算的编程接口(graphics and compute)。支持Vulkan的设备可以是GPU,也可以是DSP或者固定功能的硬件。

Vulkan中的计算模型主要基于并行计算,因此支持多线程Vulkan设计的核心理念之一。

为了较少Vulkan内部因为互斥同步等操作造成的卡顿问题,Vulkan内部默认认为对任何资源的访问不存在多线程竞争,所有的资源同步操作由应用开发者去负责,因为对资源的访问和使用没有人比应用开发者自己更加清楚。Vulkan称之为外部同步(external synchronization)。

因为这个原因,资源管理和线程同步工作成为编写Vulkan程序的最大难点之一。想要让Vulkan多线程正常运行,你需要做大量的工作。当然,换来的是Vulkan有了更加干净的线程模型以及比其它CG API高得多的性能。

1.3. Instances, Devices, and Queues

在正式研究Vulkan多线程之前,有三个重要的基础概念需要了解—Instances, Devices, and Queues。

Instances可以看做是应用的子系统,从逻辑上把Vulkan与应用程序上下文中的其他逻辑隔开。Instances可以看做是Vulkan的上下文,它会跟踪所有状态,从逻辑上把所有支持Vulkan的设备整合在一起。

Devices有两个概念:Physical devices和Logical device。

Physical devices通常代表一个或者多个支持Vulkan的硬件设备,这些设备具有特定功能,可以提供一系列Queues。图形显卡、加速器、DSP等都可以是Vulkan的Physical devices。

Logical device是Physical devices的软件抽象,用于预订一些硬件资源。

Queues可以理解为一个“GPU线程”,它是实现Vulkan多线程的关键元素之一,用于响应应用的请求,大部分时间,应用都在与其交互。

Vulkan功能的层次结构图如下:

2. Queues and Command Buffer

2.1 Queues

Queue代表一个GPU线程,Vulkan设备执行的就是提交到Queues中的工作。物理设备中Queue可能不止一个,每一个Queue都被包含在Queue Families中。

Queue Families是一个有相同功能的Queues的集合,它们的性能水平和对系统资源的访问是相同的,并且在它们之间数据传输工作没有任何成本(同步之外)。

一个物理设备中可以存在多个Queue Families,不同的Queue Families有不同的特性。相同Queue Families中的Queues的功能相同,并且可以并行运行。

按照Queue的能力,可以将其划分为:

  • Graphics(图形)

    • 该系列中的Queues支持图形操作,例如绘制点,线和三角形。
  • Compute(计算)
    • 该系列中的Queues支持诸如computer shader之类的计算操作。
  • Transfer(传输,拷贝)
    • 该系列中的Queues支持传输操作,例如复制缓冲区和图像内容。
  • Sparse binding(稀疏绑定)
    • 该系列中的队列支持用于更新稀疏资源(sparse resource)的内存绑定操作。

2.2 Command Buffer

2.2.1 单线程的性能瓶颈

传统CG API是单线程的,性能的提升只能依赖于CPU主频的提高。能有的优化方案也不外乎主线程和渲染线程分开,或者某些资源的异步加载、离线处理。

但是在实际应用中我们还是经常遇到传统CG API导致的性能瓶颈。

以手机终端为例,CPU主频提升有限,各大芯片厂商开始向多核多线程发展,考虑到功耗温控问题,又不能把CPU频率升的太高,越来越高的刷新率对实时渲染的速度要求越来越苛刻。

Vulkan为了充分发挥CPU多核多线程的作用,引入了command buffer的概念。多个线程可以同时协作,每个CPU线程都可以往自己的command buffer中提交渲染命令,然后统一提交到对应的Queue中,大大提高了CPU的利用率。

2.2.2 Command Buffer的作用

应用在绘制时会提交一系列绘制命令给GPU驱动,但是这些绘制命令不会立刻被执行,而是被简单的添加到Command Buffer的末尾。

在其他CG APIs中,驱动程序在应用不感知的情况下,把API调用翻译成GPU command并储存在command buffer中,最终提交给GPU处理。command buffer的创建和销毁都由驱动负责。

在Vulkan中,你需要自己从Command Buffer Pool中申请command buffer,将想要记录的命令放入command buffer中。

Command Buffer Pool:

2.2.3 Recording command

Command Buffer可以记录(Record)很多命令,比如:设置状态、绘制操作、数据拷贝…

理论上,一个线程可以把Command记录到多个Command Buffer中,多个线程也可以共享同一个Command Buffer,但是一般不鼓励多个线程共享一个Command Buffer。

Vulkan的关键设计原则之一就是做到高效的多线程。想实现这一点,应用程序要注意因为资源竞争导致的多线程彼此阻塞。因此,每个线程最好有一个或者对个Command Buffer,不要尝试共享一个。另外,Command Buffer由Command Buffer Pool分配,应用可以为每一个线程创建一个Command Buffer Pool,让各个工作线程从Command Buffer Pool中分配Command Buffer,无需参与竞争。

2.2.4 Submitting Command Buffers

提交过程使用示意图更加好理解一点。

单线程Command Buffer提交过程

多线程Command Buffer提交过程

整体流程如下

3. Synchronization

3.1 显示同步操作

Vulkan把同步的操作交给了应用(external synchronization),绝大多数的Vulkan命令根本不提供同步,需要应用自己负责。Vulkan给应用提供了同步原语,帮助应用进行同步操作。

Vulkan中主要有四种同步原语(synchronization primitives):

  • Fences

    • 最大颗粒度的同步原语,目的是给CPU端提供一种方法,可以知道GPU或者其他Vulkan Device什么时候把提交的工作全部做完。
    • 如果你熟悉Android显示机制的话,acquire fence或者retire fence就是类似的作用
  • Semaphores
    • 颗粒度比Fences更小一点,通常用于不同Queue之间的数据同步操作
  • Events
    • 颗粒度更小,可以用于Command Buffer之间的同步工作
  • Barriers
    • Vulkan流水线(Pipeline)阶段内用于内存访问管理和资源状态移动的同步机制

下面这张图取自NVIDIA公司Vulkan 多线程讲解的PPT:

3.2 隐藏的执行顺序

Vulkan是显式的API没错,号称是“没有秘密的API”。但是在多线程同步时,还是存在一些潜规则。

以下面这张图为例,同一个Queue中,Command Buffer1 和Command Buffer2 谁先执行?Command Buffer中记录的一堆命令是如何执行的?

Vulkan的执行顺序其实是有一定的潜规则的,在没有同步原语的情况下:

  • Command Buffer中的Command,先记录的先执行
  • 先提交的Command Buffer先执行
  • 同一个Queue中,一起提交的Command Buffer1 和Command Buffer2 按照下标的顺序执行,Command Buffer1 先执行

3.3 Barriers

所有的同步原语中,Barriers使用起来最为困难。Barriers用于显式的控制buffer或者image的访问范围,避免hazards(RaW,WaR,and WaW),保证数据一致性。

Barriers需要开发者了解渲染管线的各个阶段,能清晰的把握管线中每个步骤对资源的读写顺序。

Vulkan中将Pipeline的各个阶段定义为:

  • TOP_OF_PIPE_BIT
  • DRAW_INDIRECT_BIT
  • VERTEX_INPUT_BIT
  • VERTEX_SHADER_BIT
  • TESSELLATION_CONTROL_SHADER_BIT
  • TESSELLATION_EVALUATION_SHADER_BIT
  • GEOMETRY_SHADER_BIT
  • FRAGMENT_SHADER_BIT
  • EARLY_FRAGMENT_TESTS_BIT
  • LATE_FRAGMENT_TESTS_BIT
  • COLOR_ATTACHMENT_OUTPUT_BIT
  • TRANSFER_BIT
  • COMPUTE_SHADER_BIT
  • BOTTOM_OF_PIPE_BIT

对应:

假设我们有个两个渲染管线P1 和 P2,P1会通过Vertex Shader往buffer写入顶点数据,P2需要在Compute Shader中使用这些数据。

如果使用fence去同步,你的流程应该是这样:P1的Command提交后,P2通过fence确保P1的操作已经被全部执行完,再开始工作。

但是这种大颗粒度的同步操作无疑造成了耗时操作:P1的数据在Vertex Shader阶段就已经准备好了,我们为什么要等到它所有操作执行完再开始?P2平白多等待了很长时间,而且在这个期间P2的其他阶段并没有使用到P1的数据,也是可以执行的啊。

Barriers的引入完全解决了这个问题,我们只需要告诉Vulkan,我们在P2的Compute Shader阶段才会等待P1 Vertex Shader里面的数据,其他阶段并不关心,可以同步进行。

使用方法:

参考文档:

  1. Vulkan Overview

  2. Android and Vulkan - GDD China.pdf

  3. Vulkan Programming Guide

  4. Vulkan Cookbook

  5. Learning Vulkan

  6. Vulkan Multi-Threading

  7. Vulkan中的同步机制

  8. Vulkan® 1.1.148 - A Specification

  9. vulkan中的同步和缓存控制之二,barrier和event

  10. vulkan中的同步和缓存控制之一,fence和semaphore

  11. VULKAN BARRIERS EXPLAINED

Vulkan 多线程渲染相关推荐

  1. ios跨线程通知_一种基于Metal、Vulkan多线程渲染能力的渲染架构

    快手Y-tech  原创最新技术干货分享 随着3D渲染场景规模越来越复杂,单线程渲染架构在满足业务性能要求时已经捉襟见肘,因此,多线程渲染显得愈发重要.本文首先介绍了新一代图形渲染接口Metal.Vu ...

  2. 大量数据+同步+多线程_Vulkan 多线程渲染

    1. Overview of Vulkan 1.1 计算机图形软件 图形软件有两个大类:专用软件包(special-purpose packages)和通用编程软件包(general programm ...

  3. Filament 渲染引擎剖析 之 多线程渲染 2

    Filament 渲染一帧流程 Filament 是一款针对多核硬件系统开发的并行渲染引擎,内部通过多线程的合理调度,尤其在android移动平台上针对大小核心架构做了很多优化设计,比如通过设置线程亲 ...

  4. 《图解UE4渲染体系》Part 1 多线程渲染

    上回书<Part 0 引擎基础>说到,我们粗略地知道UE4是以哪些类来管理一个游戏场景里的数据的,但这仅仅是我们开始探索UE4渲染体系的一小步. 本回主要介绍UE4渲染体系中比较宏观顶层的 ...

  5. Cocos Creator 3.1 携多线程渲染架构和 PhysX 物理支持强势登场

    Hi,各位开发者们.v3.0 过后,引擎组就投入了 Cocos Creator 3.1 的开发,终于在今天顺利发布啦. 3.0 版本的推出标志着 Creator 迈向了一个全新的征程,而 Creato ...

  6. CE3和UE3在多线程渲染方面的简单对比

    由于刚刚开始看CE3,对很多细节都还不是很熟,所以下面的有的针对CE3的描述可能是不准确的,在此先表歉意. CE3和UE3都支持多线程渲染,即有一个单独的渲染线程,当然它们都可以通过简单的办法来开关, ...

  7. DirectX12(D3D12)基础教程(六)——多线程渲染

    目录 1.前言 2.为什么要多线程渲染 3.多线程 3.1.什么是线程 3.2.进程的主线程 3.3.线程的入口函数 3.4.创建线程 3.5.CreateThread示例 3.6.C/C++创建线程 ...

  8. 虚幻引擎之多线程渲染机制

    虚幻引擎之多线程渲染机制 文章目录 虚幻引擎之多线程渲染机制 一.前言 二.游戏线程与渲染线程的交互 2.1 ENQUEUE_RENDER_COMMAND宏 2.2 渲染线程 2.3 数据交互 2.3 ...

  9. D3D11和D3D12多线程渲染框架的比较(一)

    1. 前言 D3D12伴随DirectX12自2014年正式发布以来已经近3年多时间了.遗憾的是我最近才有时间仔细研究D3D12接口及编程方面的内容.D3D12给我总体的感觉用一句话来概括就是--D3 ...

  10. Unity3D 海水多线程渲染算法实现

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...

最新文章

  1. jQuery 插件取url参数[jquery.url.js]的使用以及文件下载
  2. linux uvc 支持的设备,摄像头是否支持uvc
  3. java.lang.RuntimeException: Canvas: trying to draw too large(203212800bytes) bitmap.
  4. pandas删除dataframe列
  5. AtCoder - arc100_c Or Plus Max(SOSdp)
  6. python 单行读取文件_python – 在使用for循环读取文件时跳过一行
  7. 2015第29周二AOP
  8. 5分钟了解什么是真正的深度学习
  9. 10 FI配置-财务会计-把会计年度变式分配给公司代码
  10. OpenWrt 学习网址
  11. mysql主从复制及问题解决
  12. 复盘!12 小时清掉 3500 份生财日历
  13. 黄聪:wordpress向mysql字段中保存html代码(使用add_option()方法),然后无法显示出问题...
  14. MySQL – iBatis – 文件存储
  15. springboot进行微信公众号相关开发:(二)获取微信公众号access_token用以微信公众号各功能接口的调用
  16. MAC APP 签名证书查看
  17. excel实现分组计数
  18. 计算机网络共享打不开,电脑系统网络和共享中心打不开怎么办
  19. Python入门——一个沙雕的表情包
  20. monkey脚本执行中如何强行停止

热门文章

  1. Windows Filtering Platform Windows筛选平台
  2. linux网络标志有个问号,只有Linux中的问号
  3. ESP32和LoRa SX1278通讯
  4. 【学习笔记】利用API进行数据采集或获取
  5. 洛谷 P2123 皇后游戏(贪心)
  6. OAF: 怎样创建 DFF
  7. LeetCode第82场双周赛
  8. 红色警戒怎么修改服务器,INI修改全教程【申精】
  9. 最大连续子数组和python_连续子数组的最大和(python)
  10. [脑科学]-卡耐基等成功学或者心灵鸡汤的书籍