Vulkan Synchronization 同步

2024-01-09 22:12

本文主要是介绍Vulkan Synchronization 同步,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Vulkan的同步有两个作用,一是控制Command的执行顺序,二是控制缓存的刷新。

Vulkan会保证在同一个Command Queue中的Command按顺序开始执行,但并不会保证谁先执行完成,而且会多个Command同时执行。例如Command1 开执行后会,立即开始执行Command2,两个命令会同时执行,且不保证谁先执行完。

GPU是incoherent caches(缓存不一致),Vulkan也不会保证缓存一致性,所以需要控制缓存的刷新,保证后面执行的Command读取到前面Command的执行结果。

Execution Barriers

VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier(VkCommandBuffer                             commandBuffer,VkPipelineStageFlags                        srcStageMask,VkPipelineStageFlags                        dstStageMask,VkDependencyFlags                           dependencyFlags,uint32_t                                    memoryBarrierCount,const VkMemoryBarrier*                      pMemoryBarriers,uint32_t                                    bufferMemoryBarrierCount,const VkBufferMemoryBarrier*                pBufferMemoryBarriers,uint32_t                                    imageMemoryBarrierCount,const VkImageMemoryBarrier*                 pImageMemoryBarriers);

Execution Barriers是用来控制命令的执行顺序的。函数vkCmdPipelineBarrier设置前3个参数(commandBuffer、srcStageMask、dstStageMask),其他参数设为null或0,就是设置了一个Execution Barriers。

设置Execution Barriers后会将Queue中的所有Command分成两部分,即Execution Barriers之前的Command和Execution Barriers之后的Command。这里的Command不限于当前commanBuffer中的Command,还包括当前commanBuffer提交之前提交的commandBuffer中的Command和提交之后的,也就是说Execution Barriers在queue中是全局。Execution Barriers的作用是:之后的Command执行dstStageMask阶段,需要等待之前Command执行完srcStageMask阶段

例如以下代码:

vkCmdPipelineBarrier(commandBuffer, TRANSFER_BIT, FRAGMENT_SHADER_BIT);
代码之后的命令执行到FRAGMENT_SHADER_BIT时,需要之前所有命令都执行完了TRANSFER_BIT。

Memory Available and Visible 

GPU缓存如下图:

GPU缓存

Vulkan并不会保证缓存一致性,所以单纯的控制执行顺序并不能保证后面执行的Command读取到前面Command的执行结果。因为Command执行后其执行结果会存在L1缓存,并不会立即刷新到L2缓存,所以后面在不同的SM上执行的Command就不能读取到最新的结果。为了保证后面执行的Command读取到前面Command的执行结果,还需要控制缓存的刷新。

Memory Available

当L2缓存中包含了最新的数据时,则当前的Memory是Avilable状态。如果一个Command执行时修改了数据,则对应的Memory是Undefined状态,此时其他命令读取Memory会读到错误的数据。为了让Memory在Command执行完后变成Available状态,需要在Comand后面的vkCmdPipelineBarrier中MemoryBarrier的srcAccessMask设置一个VK_ACCESS_*_WRITE_BIT。这样Command执行完srcStageMask阶段后,会将执行结果更新到L2缓存。

Memory Visible 

当前L1缓存中包含了最新数据,并设置了访问权限时,则当前Memory是Visible状态,也就是当前SM单元可以读取或修改数据。为了让Memory在Command执行完后变成Visible状态,首先需要保证数据为Avilable状态,然后在vkCmdPipelineBarrier中MemoryBarrier的dstAccessMask设置一个VK_ACCESS_*_WRITE_BIT/VK_ACCESS_*_READ_BIT权限。这样Command执行完dstStageMask阶段时,L1会重新刷新,从L2中读取到最新数据。

其他

  1. srcAccessMask不需要设置*READ_BIT标志,srcAccessMask是用来控制L1缓存中的结果写入到L2缓存的,*READ_BIT标志并不会有任何作用。
  2. TOP_OF_PIPE/BOTTOM_OF_PIPE阶段并执行任何Command,这两个阶段srcAccessMask/dstAccessMask只能设置为0。
  3. “making memory available” is all about flushing caches,将最新数据写入L2缓存
  4. “making memory visible” is invalidating caches。无效化缓存,加载最新的数据。

Image Memory Barrier and Layout

typedef struct VkImageMemoryBarrier {VkStructureType            sType;const void*                pNext;VkAccessFlags              srcAccessMask;VkAccessFlags              dstAccessMask;VkImageLayout              oldLayout;VkImageLayout              newLayout;uint32_t                   srcQueueFamilyIndex;uint32_t                   dstQueueFamilyIndex;VkImage                    image;VkImageSubresourceRange    subresourceRange;
} VkImageMemoryBarrier;

Image对象使用前需要设置Layout,因为不同的Layout有不同的用途。例如:纹理用作Frame Buffer时Layout需要是COLOR_ATTACHMENT_OPTIMAL,纹理用作着色器采样时Layout需要是SHADER_READ_ONLY_OPTIMAL。

VkImageMemoryBarrier可以用来转换纹理的Layout,这个转换过程可以看作一次读写,转换时会改变Image Memory的字节格式,会先读取Image然后再写入成新的格式。转换前需要保证Image Memory状态为Available,转换后数据会写入L2缓缓,Image Memory状态自动设置为Available,但不是Visible。

新创建的ImageMemory状态默认是Available和Visible,所以可以直接转换Layout。

Image Alias Memory

使用别名会同时将多个Image绑定到同一块Memory中,所以使用时可能其他Image已修改过Memory导致Memory状态是Undefined,不是Available。所以使用前需要增加一个VkImageMemoryBarrier保证Memory为Available。

例如Image1和Image2都绑定到同块Memory,并且都用于RenderPass渲染,使用时如下:

  • vkCmdPipelineBarrier(image = image1, oldLayout = UNDEFINED, newLayout = COLOR_ATTACHMENT_OPTIMAL, srcStageMask = COLOR_ATTACHMENT_OUTPUT, srcAccessMask = COLOR_ATTACHMENT_WRITE, dstStageMask = COLOR_ATTACHMENT_OUTPUT, dstAccessMask = COLOR_ATTACHMENT_WRITE|READ) // 1
  • vkCmdBeginRenderPass/EndRenderPass
  • vkCmdPipelineBarrier(image = image2,  …) // 与1相同
  • vkCmdBeginRenderPass/EndRenderPass

注:因为RenderPass中可以包含vkCmdPipelineBarrier,所以实际使用时可以不需要写上面两个vkCmdPipelineBarrier,这个两个vkCmdPipelineBarrier可以包含到RenderPass中

Semaphores and Fences

Semaphores和Fences可以用在vkQueueSubmit中进行同步,用于Command Queue,Host,Present中进行同步。

当前Semaphores或Fences激活(signaled)时所有的Memory状态会被设为Available。相当于添加了一个MemoryBarrier,srcStageMask = ALL_COMMANDS_BIT,srcAccessMask = MEMORY_WRITE_BIT。

当前获得(wait)Semaphores或Fences,所有的Memory状态会被设为Visible。

Host Memory

更新数据

当更新了UniformBuffer后,并不需要手动添加Barrier同步更新后的数据,当vkQueueSubmit时会自动同步,会将对应的Memory设置Avaiable和Visible。

如果更新数据在vkQueueSubmit后面则需要手动设置Barrier同步,设置如下:

  • srcStageMask = HOST
  • srcAccessMask = HOST_WRITE_BIT
  • dstStageMask = TRANSFER
  • dstAccessMask = TRANSFER_READ

读取数据

当CPU端需要读取GPU数据时,通常需要使用Fences同步,当获得(wait)Fences时会自动将Memory状态设为Visible,但这个仅限于GPU内部。所以还需要手动添加Barrier用于刷新缓存,设置dstStageMask = PIPELINE_STAGE_HOST和dstAccessMask = ACCESS_HOST_READ_BIT。这样Command执行后会将缓存刷新到CPU内存,CPU就可以读取到最新数据。

总结

Vulkan同步会将Command分成前面的和后面的两个部分,同步主要是用于控制后面的Command执行顺序,以及后面的Command读取到最新的数据。

不同的同步方式:

参考:

Yet another blog explaining Vulkan synchronization – Maister's Graphics Adventures

Vulkan Synchronization

这篇关于Vulkan Synchronization 同步的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/588613

相关文章

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

MySQL主从同步延迟原理及解决方案

概述 MySQL的主从同步是一个很成熟的架构,优点为: ①在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力; ②在从主服务器进行备份,避免备份期间影响主服务器服务; ③当主服务器出现问题时,可以切换到从服务器。 相信大家对于这些好处已经非常了解了,在项目的部署中也采用这种方案。但是MySQL的主从同步一直有从库延迟的问题,那么为什么会有这种问题。这种问题如何解决呢? MyS

使用条件变量实现线程同步:C++实战指南

使用条件变量实现线程同步:C++实战指南 在多线程编程中,线程同步是确保程序正确性和稳定性的关键。条件变量(condition variable)是一种强大的同步原语,用于在线程之间进行协调,避免数据竞争和死锁。本文将详细介绍如何在C++中使用条件变量实现线程同步,并提供完整的代码示例和详细的解释。 什么是条件变量? 条件变量是一种同步机制,允许线程在某个条件满足之前进入等待状态,并在条件满

mysql创建新表,同步数据

import os import argparse import glob import cv2 import numpy as np import onnxruntime import tqdm import pymysql import time import json from datetime import datetime os.environ[“CUDA_VISIBLE_DEVICE

三.海量数据实时分析-FlinkCDC实现Mysql数据同步到Doris

FlinkCDC 同步Mysql到Doris 参考:https://nightlies.apache.org/flink/flink-cdc-docs-release-3.0/zh/docs/get-started/quickstart/mysql-to-doris/ 1.安装Flink 下载 Flink 1.18.0,下载后把压缩包上传到服务器,使用tar -zxvf flink-xxx-

Gerrit与Gitlab同步配置replication其他配置

一、Gerrit与Gitlab同步配置 当配置好gerrit环境后,还需要与现有gitlab库进行同步配置,否则会影响现有开发与打包流程。 1.安装gerrit replication插件 unzip gerrit.warcp WEB-INF/plugins/replication.jar ~/temp/ssh -p 29418 admin@172.19.16.64 gerrit plu

iOS剪贴板同步到Windows剪贴板(无需安装软件的方案)

摘要 剪贴板同步能够提高很多的效率,免去复制、发送、复制、粘贴的步骤,只需要在手机上复制,就可以直接在电脑上 ctrl+v 粘贴,这方面在 Apple 设备中是做的非常好的,Apple 设备之间的剪贴板同步功能(Universal Clipboard)确实非常方便,它可以在 iPhone、iPad 和 Mac 之间无缝传输剪贴板内容,从而大大提高工作效率。 但是,iPhone 如何和 Wind

RISC-V (十)任务同步和锁

并发与同步 并发:指多个控制流同时执行。         多处理器多任务。一般在多处理器架构下内存是共享的。           单处理器多任务,通过调度器,一会调度这个任务,一会调度下个任务。  共享一个处                                理器一个内存。                 单处理器任务+中断: 同步: 是为了保证在并发执行的环境中各个控制流可

【Linux修行路】线程同步——条件变量

目录 ⛳️推荐 前言 一、条件变量 1.1 pthread_cond_init——初始化一个条件变量 pthread_cond_destroy——销毁一个条件变量 1.3 定义一个全局的条件变量 1.4 pthread_cond_wait——等待条件满足 1.5 pthread_cond_signal——唤醒一个等待线程 1.6 pthread_cond_broadcast—