图形API学习工程(12):讨论当前工程里同步CPU与GPU的方式

2024-09-06 23:32

本文主要是介绍图形API学习工程(12):讨论当前工程里同步CPU与GPU的方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

工程GIT地址:https://gitee.com/yaksue/yaksue-graphics

简单讨论CPU和GPU间的交互

《DX12龙书》在【4.2 CPU与GPU间的交互】章节中讨论了这个问题,简单来说:
为了最佳性能,CPU和GPU这两种处理器应该尽量同时工作,少“同步”。因为“同步”意味着一种处理器以空闲状态等待另一种处理器,即它破坏了“并行”。

但有时,又不得不进行二者的同步,见《DX12龙书》的【4.2.2 CPU与GPU间的同步】所讨论的问题。

当前工程,在D3D12和Vulkan的版本上有同步CPU与GPU的操作。
(D3D12代码参考DX12官方范例的【D3D12HelloWindow范例】,
Vulkan代码参考Rendering and presentation - Vulkan Tutorial)

我想就当前工程的同步方式进行讨论。但值得注意的是:当前的同步方式是最简单的,但并不是最佳的,详见最后一部分的讨论。

D3D12的方式

目前工程里D3D12方面是使用围栏实现同步。

接口介绍

所用的函数除了D3D12本身定义的之外,还有Windows定义的函数。

CreateEvent函数 (synchapi.h)

CreateEvent 将创建一个event对象,并返回这个event对象的Handle。

WaitForSingleObject函数 (synchapi.h)

调用WaitForSingleObject将使程序等待一个event对象直到它进入一个特定信号的状态(或者直到超过指定时间)。

DWORD WaitForSingleObject(HANDLE hHandle,DWORD  dwMilliseconds
);

参数中hHandle就是event对象的Handle。dwMilliseconds是超时的时间,如果设为INFINITE即表示一直等待。

ID3D12Fence接口 (d3d12.h)

ID3D12Fence代表一个围栏对象,用来同步CPU和GPU。
它的三个成员函数:

ID3D12Fence::GetCompletedValue 可以获取当前围栏对象的值。

ID3D12Fence::SetEventOnCompletion 可以设定当这个围栏对象到达某个值将会触发一个event对象。

HRESULT SetEventOnCompletion(UINT64 Value,HANDLE hEvent
);

参数中Value是围栏对象要到达的值,而hEvent是要触发的event对象的Handle。

ID3D12Fence::Signal 将设定围栏对象为指定的值。(CPU端

ID3D12CommandQueue::Signal方法

ID3D12CommandQueue的Signal方法将在队列执行完成后,在GPU端围栏对象设定为指定的值。

HRESULT Signal(ID3D12Fence *pFence,UINT64      Value
);

参数中pFence围栏对象,而Value则是会被设定的值。

使用

首先,在初始化阶段,创建围栏对象和event对象:

 //创建Fence
Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence));//创建一个event对象
m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);

WaitForPreviousFrame()表示等待这一帧GPU执行,其中内容如下:

首先,NewFenceValue表示应该设置的新的围栏值,它应该和从GetCompletedValue()获得的旧的围栏值不一样,比如+1。

const UINT64 NewFenceValue = m_fence->GetCompletedValue() + 1;

然后,CommandQueue设定:当它完成队列后,围栏将会在GPU端被设定为新的值。

CommandQueue->Signal(m_fence.Get(), NewFenceValue);

围栏自己也设定:当它到达新的值时,将会触发m_fenceEvent这个事件。

m_fence->SetEventOnCompletion(NewFenceValue, m_fenceEvent);

最后,让程序无限地等待m_fenceEvent这个事件。

WaitForSingleObject(m_fenceEvent, INFINITE);

这样,程序便会一直等待直到CommandQueue完成队列。

Vulkan的方式

目前工程里Vulkan方面相对于简单,是在VulkanInterface::Present()中使用了一些等待 设备/队列 进入闲置状态的接口。

接口介绍

vkDeviceWaitIdle:Wait for a device to become idle
vkQueueWaitIdle:Wait for a queue to become idle

使用

vkDeviceWaitIdle(Device);

或者

vkQueueWaitIdle(PresentQueue);

当前的同步方式并不是最佳

在学习过程中所参考的资料,无一不指出:当前的同步方式不是最佳的,而更佳的方式,会在后续学习。
例如:


《DX12龙书》:

这种解决方案并不完美,因为这意味着在等待GPU处理命令的时候,CPU会处于空闲状态,但在第7章以前也只能暂时使用这个简单的方法了。


DX12官方范例的【D3D12HelloWindow范例】:

// WAITING FOR THE FRAME TO COMPLETE BEFORE CONTINUING IS NOT BEST PRACTICE.
// This is code implemented as such for simplicity. The D3D12HelloFrameBuffering
// sample illustrates how to use fences for efficient resource usage and to
// maximize GPU utilization.

Rendering and presentation - Vulkan Tutorial:

The easy way to solve this is to wait for work to finish right after submitting it, for example by using vkQueueWaitIdle
However, we are likely not optimally using the GPU in this way, because the whole graphics pipeline is only used for one frame at a time right now. The stages that the current frame has already progressed through are idle and could already be used for a next frame. We will now extend our application to allow for multiple frames to be in-flight while still bounding the amount of work that piles up.

这篇关于图形API学习工程(12):讨论当前工程里同步CPU与GPU的方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

idea设置快捷键风格方式

《idea设置快捷键风格方式》在IntelliJIDEA中设置快捷键风格,打开IDEA,进入设置页面,选择Keymap,从Keymaps下拉列表中选择或复制想要的快捷键风格,点击Apply和OK即可使... 目录idea设www.chinasem.cn置快捷键风格按照以下步骤进行总结idea设置快捷键pyth

Linux镜像文件制作方式

《Linux镜像文件制作方式》本文介绍了Linux镜像文件制作的过程,包括确定磁盘空间布局、制作空白镜像文件、分区与格式化、复制引导分区和其他分区... 目录1.确定磁盘空间布局2.制作空白镜像文件3.分区与格式化1) 分区2) 格式化4.复制引导分区5.复制其它分区1) 挂载2) 复制bootfs分区3)

SpringBoot返回文件让前端下载的几种方式

《SpringBoot返回文件让前端下载的几种方式》文章介绍了开发中文件下载的两种常见解决方案,并详细描述了通过后端进行下载的原理和步骤,包括一次性读取到内存和分块写入响应输出流两种方法,此外,还提供... 目录01 背景02 一次性读取到内存,通过响应输出流输出到前端02 将文件流通过循环写入到响应输出流

java敏感词过滤的实现方式

《java敏感词过滤的实现方式》文章描述了如何搭建敏感词过滤系统来防御用户生成内容中的违规、广告或恶意言论,包括引入依赖、定义敏感词类、非敏感词类、替换词类和工具类等步骤,并指出资源文件应放在src/... 目录1.引入依赖2.定义自定义敏感词类3.定义自定义非敏感类4.定义自定义替换词类5.最后定义工具类

SpringBoot实现图形验证码的示例代码

《SpringBoot实现图形验证码的示例代码》验证码的实现方式有很多,可以由前端实现,也可以由后端进行实现,也有很多的插件和工具包可以使用,在这里,我们使用Hutool提供的小工具实现,本文介绍Sp... 目录项目创建前端代码实现约定前后端交互接口需求分析接口定义Hutool工具实现服务器端代码引入依赖获

python项目环境切换的几种实现方式

《python项目环境切换的几种实现方式》本文主要介绍了python项目环境切换的几种实现方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 如何在不同python项目中,安装不同的依赖2. 如何切换到不同项目的工作空间3.创建项目

SpringBoot的内嵌和外置tomcat的实现方式

《SpringBoot的内嵌和外置tomcat的实现方式》本文主要介绍了在SpringBoot中定制和修改Servlet容器的配置,包括内嵌式和外置式Servlet容器的配置方法,文中通过示例代码介绍... 目录1.内嵌如何定制和修改Servlet容器的相关配置注册Servlet三大组件Servlet注册详

C# WebAPI的几种返回类型方式

《C#WebAPI的几种返回类型方式》本文主要介绍了C#WebAPI的几种返回类型方式,包括直接返回指定类型、返回IActionResult实例和返回ActionResult,文中通过示例代码介绍的... 目录创建 Controller 和 Model 类在 Action 中返回 指定类型在 Action

SQL 注入攻击(SQL Injection)原理、利用方式与防御策略深度解析

《SQL注入攻击(SQLInjection)原理、利用方式与防御策略深度解析》本文将从SQL注入的基本原理、攻击方式、常见利用手法,到企业级防御方案进行全面讲解,以帮助开发者和安全人员更系统地理解... 目录一、前言二、SQL 注入攻击的基本概念三、SQL 注入常见类型分析1. 基于错误回显的注入(Erro

requests处理token鉴权接口和jsonpath使用方式

《requests处理token鉴权接口和jsonpath使用方式》文章介绍了如何使用requests库进行token鉴权接口的处理,包括登录提取token并保存,还详述了如何使用jsonpath表达... 目录requests处理token鉴权接口和jsonpath使用json数据提取工具总结reques