一个最基本的多线程3D渲染器方案

news2024/11/15 4:40:44

概括

渲染器仍然是大多数现代视频游戏的主要组件。通常,这些流水线通过 3D 图形应用程序接口(如 DirectX、OpenGL )暴露出来。现代,多核 CPU 已广泛应用于游戏机和个人电脑。为了确保 GPU 能持续不断地处理数据,渲染器必须充分利用这一优势。通常在屏幕上渲染出 3D 图像的工作流程依赖于向GPU 发送的可执行命令队列。

可以采用不同的方法将 CPU 与 GPU 分离。例如,一种常见的技术是使用双缓冲或三缓冲方案,CPU 在第 N 帧创建命令,GPU 在第 N+1 帧消耗命令,如图 1 所示。另外,GPU 也可以在同一帧内消耗 数据,以减少延迟,如图 2 所示。一个潜在的缺点是,在帧的早期可能难以避免 GPU 的一些停滞。另一方面,与双缓冲方法相比,内存占用要小得多,这对于内存有限的嵌入式系统尤为重要。

内存模型

无论渲染队列是如何创建的,渲染器最终都可能受到内存访问速度的限制,尤其是当图形命令是通过单线程生成时。近年来,GPU 处理能力与内存延迟之间的性能差距越来越大,由于系统内存中昂贵的数据访问速度,GPU 的工作变得更加困难,如图 3 所示。一个典型的帧会被细分为多个处理流程,例如渲染阴影贴图、渲染主场景和渲染全屏后处理效果。渲染过程中的工作单元通常被称为批次,由一组渲染状态、着色器和几何元素组成,如下表所示:

//setting up a batch
setRenderStates(...);
bindTextures(...);
setShaders(...);
setShaderConstants(...);
setVertexBuffer(...);
setIndexBuffer(...);
drawCall(...);

设置批次主要包括设置渲染对象所需的各种资源的地址。在创建批次的过程中,渲染代码必须遍历场景图,并有可能访问主内存中不同位置的数据。这将导致大量的缓存缺失。对于(out-of-order)乱序CPU(如 Xbox 360 和 PlayStation 3 游戏机中的 PowerPC 芯片)来说,每次缓存缺失都可能导致处理器停滞数百个周期,从而极大地影响性能。这个问题可以通过(out-of-order)乱序cpu来缓解,因为在以前的指令正在等待数据准备就绪时,可能会执行其他指令。

也许有人会说,可以通过重组数据结构来避免许多缓存命中率低的问题。的确,采用缓存感知或缓存忽略算法[2]会有所帮助,尤其是在场景图管理方面,但遗憾的是,图形库也需要自行访问和处理一些数据。顶点缓冲区和索引缓冲区等大型结构通常存储在 GPU 的本地内存中,因此不会造成问题,但着色器常量和纹理配置等许多类型的渲染状态需要每帧复制到命令缓冲区。因此,需要其他解决方案来克服缓存的限制。

并行的构建渲染队列

为确保在最短时间内创建渲染队列,并最大限度地减少内存带宽限制,我们的解决方案使用多个线程,每个线程负责创建一个渲染命令子集。不过,这只有在 3D 图形库提供这种粒度时才有可能实现。值得庆幸的是,Xbox 360、PlayStation 3 和 DirectX 11 开发人员都能做到这一点。在PlayStation 3 中,单元宽带引擎的协同处理单元(SPU)是纯粹的矢量处理器,擅长几何处理。这意味着它们可以轻松执行图形操作,在必要时帮助 GPU 分担工作。为了并行创建渲染队列,一种常见的模式是让主命令缓冲区引用在次命令缓冲区内创建的渲染队列。这些渲染队列在不同的执行单元上并行创建,如图 4 所示。通常情况下,这些辅助缓冲区会处理帧的一个子集,粒度可以是单个绘制调用,也可以是整个通道。

通过将绘制调用及其图形状态的创建并行分配到多个命令缓冲区,创建渲染队列的整体延迟大大降低,这在使用图 2 所示方案时尤为有用。此外,这还使 渲染器更易于扩展到各种配置的多核架构,并有助于生成现代视频游戏中常见的成千上万次绘制调用。

并行化模型

3D渲染器非常适合并行化,因为每次绘制调用 通常可被视为一个独立的工作单元。如以下代码所示,每个任务都会将一大块数据 与对该数据进行操作的一些逻辑配对,如以下代码所示。

int TaskMain(...)
{
 const int sourceAddr = ...; // source address of data
 const int count = ...; // number of elements
 const int dataSize = count * sizeof(gfxObject);
 // On some platforms like the PS3,
 // you may have to keep the data local to the executing unit
 gfxObject *buffer = (gfxObject *) Allocate(dataSize);
 DmaGet(buffer, sourceAddr, dataSize);
 DmaWait(...); // barrier to wait for the data
 // let's do some work
 for (int i = 0; i < count; ++i)
 {
 buffer[i]->update();
 }
 // On some platforms like the PS3,
 // you may have to store back the data to system memory
 DmaPut(buffer, sourceAddr, dataSize);
 DmaWait(....); // barrier to wait for the data
}

如图 5 所示,这种模式提供了一种高效的并行范式,每个任务都可以排队,并由可用的处理单元处理。这也避免了更标准的多线程方法的一些问题,因为任务提供了更精细的细分,可以更轻松地应对不均衡的计算,而多线程架构可能最终会等待某个特定子系统完成任务。

同步CPU和GPU

在多线程环境中,GPU 和 CPU 的同步处理更为困难,因为多个处理单元可能都想访问相同的数据。为了避免出现任何不一致和竞赛条件,有必要采用诸如互斥或原子等同步原语。通常情况下,GPU 可以报告其在特定内存区域的进度。例如,当 GPU 完成某个特定命令后,它可以将指定值或 “报告 ”写入 CPU 可访问的

在多线程环境中,GPU 和 CPU 的同步处理更为困难,因为多个处理单元可能都想访问相同的数据。为了避免出现任何不一致和竞赛条件,有必要采用诸如互斥或原子等同步原语。通常情况下,GPU 可以报告其在特定内存区域的进度。例如,当 GPU 完成一个特定的命令后,它可以向 CPU 可访问的位置写入一个指定的值或 “报告”,以表示完成。根据架构的不同,CPU 可以轮询报告值或接收某种系统回调。表 1 列出了一些可能的配置。
 

与任何多线程环境一样,需要特别注意避免潜在的竞赛条件或死锁,因为 CPU 和 GPU 都可能以不可预测的时间模式生成和消耗数据。

使用额外的处理资源

在许多游戏中,可用处理单元之间的处理负载并不完全平衡。在这种情况下,值得将通常在主 CPU 上执行的一些操作转移到每帧都可能有空闲时间的其他单元上。例如,密集度较低的图形应用程序可以使用 GPGPU(通用 GPU)代码,利用 CUDA 等技术将物理或人工智能模拟从 CPU 上卸载下来。另一方面,愿意挑战实时 3D 图形极限的游戏可能希望使用空闲的 CPU 内核来执行某些图形操作。如果这些内核恰好提供了一种有趣的 ISA(指令集架构),具有 SIMD 指令,例如 Cell 处理器上的 SPU,那么就有可能卸载 GPU 来执行以下几种操作:

- 几何处理,包括创建地形、树木、贴花或细分表面的程序算法。
- 物理和粒子系统更新。
- 视锥体剔除或遮挡剔除。
- 软件渲染,特别是闭塞查询和后期处理效果。

降低对内存带宽的压力

CPU 和 GPU 的性能都在飞速提升,但内存速度却没有跟上同样的曲线,因此内存带宽成为了一个重要的瓶颈。因此,必须考虑任何有助于最大限度降低对内存系统要求的技术,即使这意味着需要使用更多的 CPU 或 GPU 周期。可以使用的一些技术包括打包着色器输入和输出属性,或在可用的情况下使用 GPU 的细分单元。在 CPU 方面,特殊的几何图形剔除可以避免发送多达 70% 的基元,这些基元最终会被 GPU 丢弃(背向、离屏、零尺寸和退化基元)。另一种技术是在软件中生成一个粗深度缓冲区来执行遮挡查询,而不是依赖 GPU [1],因为后者可能涉及从视频内存中读取数据,而这通常是一条缓慢的路径。

并行执行图形操作

到目前为止,我们已经讨论了一些有助于提高整体性能的技术,但我们还可以更进一步,让不同的处理单元并行工作,以创建一帧的最终图像。现代游戏在一帧内使用多个渲染目标,其中有些目标并不是由 GPU 同时访问的。例如,在 GPU 开始渲染下一帧时,通常可以通过 SPU 等其他处理单元访问后置缓冲区,以执行一些后期处理效果。这样,在保持相同帧频的情况下,最多可以有一整帧的时间来渲染特效,但代价是要增加一帧的延迟(见图 6)。

[1] Johan Andersson."The Intersection of Game Engines and GPUs: Current & Future". Graphics Hardware 2008 .
[2] Sebastien Schertenleib."An Effective Cache-Oblivious Implementation of the ABT Tree". Game Programming Gems 5 , Charles River Media, 2005.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2090447.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

惠中科技RDS自清洁膜层:光伏行业的清洁革命与创新先锋

在当今全球能源转型和光伏产业蓬勃发展的背景下&#xff0c;光伏电站的运营维护面临着诸多挑战&#xff0c;其中灰尘污染问题尤为突出。灰尘的堆积不仅降低了光伏板的透光率&#xff0c;还直接影响了电站的发电效率和经济效益。为了有效解决这一难题&#xff0c;惠中科技凭借其…

C++日期差值问题(2个日期之间差几天)

上面是牛客网给出的题目。 思路 假设第一个输入的日期为2011 12 03&#xff0c;第二个输入的日期为2024 02 29。 这两个日期并不相等&#xff0c;我们可以让日期2011 12 03一直加1&#xff0c;直到等于2024 02 29为止。 在这个过程中&#xff0c;每1一次&#xff0c;就让re…

情感共鸣:数业智能心大陆重塑AI心理交互新纪元

在科技蓬勃发展的今天&#xff0c;人工智能如同一张大网&#xff0c;与我们的生活密切交织&#xff0c;在多个层面深刻影响着每一个人。而数业智能心大陆&#xff0c;作为 “AI 心理健康” 领域的佼佼者&#xff0c;正以其独特的技术和创新理念&#xff0c; 为人工智能与用户的…

企业EMS - 能源管理系统 - 能源管理系统源码-能源在线监测平台-双碳平台源码

一、介绍 企业EMS - 能源管理系统 - 能源管理系统源码-能源在线监测平台-双碳平台源码’ 二、软件架构 二、功能介绍 三、数字大屏展示 四、数据采集原理 五、软件截图

C++ 有向图算法

概念 Breadth-First Search (BFS) 目的: 主要用于遍历或搜索图中的所有顶点。 特点: 从根节点开始&#xff0c;先访问所有与之相邻的节点&#xff0c;然后再一层一层地深入。 应用: 可以用来寻找两节点间的最短路径&#xff08;当边的权重相等时&#xff09;&#xff0c;检测…

笔记:应用Visual Studio Profiler分析CPU使用情况

一、目的&#xff1a;应用Visual Studio Profiler分析CPU使用情况 使用 Visual Studio Profiler 分析 CPU 使用情况可以帮助你识别性能瓶颈&#xff0c;优化代码&#xff0c;提高应用程序的响应速度。 二、实现 以下是如何使用 Visual Studio Profiler 分析 CPU 使用情况的详…

前端问答:如何判断变量是否为数组?

在JavaScript的世界里&#xff0c;判断一个变量的类型是开发者日常工作中不可或缺的一部分&#xff0c;尤其是在处理数组这种关键数据结构时。数组作为一种广泛应用于各种操作的数据结构&#xff0c;无论是简单的数据存储还是复杂的算法实现&#xff0c;都发挥着重要作用。然而…

力扣刷题--762. 二进制表示中质数个计算置位【简单】

题目描述&#x1f357; 给你两个整数 left 和 right &#xff0c;在闭区间 [left, right] 范围内&#xff0c;统计并返回 计算置位位数为质数 的整数个数。 计算置位位数 就是二进制表示中 1 的个数。 例如&#xff0c; 21 的二进制表示 10101 有 3 个计算置位。 示例 1&am…

【JPCS独立出版】2024电驱系统与控制工程国际学术研讨会(EDSCE 2024,10月18-20)

2024电驱系统与控制工程国际学术研讨会&#xff08;EDSCE 2024&#xff09;将于2024年10月18-20日在中国本溪隆重举行。 本次会议将集中讨论电驱系统与控制工程的最新研究成果&#xff0c;旨在建立一个高水平的学术交流平台&#xff0c;以便领域内的专家学者、工程师和技术研发…

【单片机原理及应用】实验: 8位数码显示器

目录 一、实验目的 二、实验内容 三、实验步骤 四、记录与处理 五、思考 六、成果文件提取链接 一、实验目的 学习8位数码管串行扩展原理&#xff0c;掌握74HC595与动态显示编程方法。 二、实验内容 【参照图表】 &#xff08;1&#xff09;创建一个包含80C51固件&#x…

如何选择适合企业的财税自动化解决方案

财税自动化解决方案是现代企业提升财务管理效率、降低运营成本的关键工具。然而&#xff0c;市场上的财税自动化产品琳琅满目&#xff0c;功能各异&#xff0c;企业在选择时常常感到困惑。本文金智维将从中小型的需求出发&#xff0c;帮助企业了解如何选择适合自身的财税自动化…

ASP.NET Core6.0-wwwroot文件夹无法访问解决方法

默认情况下&#xff0c;ASP.NET Core项目中的wwwroot文件夹被视为Web根文件夹。静态文件可以存储在Web根目录下的任何文件夹中&#xff0c;并可以使用该根目录的相对路径进行访问。在ASP.NET应用程序中&#xff0c;可以从应用程序的根文件夹或其下的任何其他文件夹提供静态文件…

数据分析学习之numpy

引言 好久没写帖子了&#xff0c;确实变懒了&#xff0c;在这一个月里学习了爬虫&#xff0c;还有seleium自动化技术初步以及数据分析中的numpy&#xff0c;下一步就要学习pandas,但是欠了太多帖子没写&#xff0c;所以现在来补一下&#xff0c;现在来的是numpy的学习&#xff…

Java面试宝典-java基础07

Java面试宝典-java基础07 61、什么是 java 序列化&#xff1f;什么情况下需要序列化&#xff1f;62、序列化使用场景有哪些&#xff1f;63、使用序列化和反序列化的注意事项64、为什么要使用克隆&#xff1f;如何实现对象克隆&#xff1f;深拷贝和浅拷贝区别是什么&#xff1f;…

计算机网络概述(分组延时、丢失和吞吐量)

目录 分组丢失和延时是怎样发生的&#xff1f; 四种分组延时 节点延时 排队延迟 分组丢失 吞吐量 吞吐量&#xff1a;互联网场景 分组丢失和延时是怎样发生的&#xff1f; 在路由器缓冲区的分组队列 分组到达链路的速率超过了链路输出的能力分组等待排队到队头、被传输…

Ethernet 测试系列(1)-- 物理层测试::IOP Test::Link-up time

车载以太网物理层IOP测试&#xff0c;即互操作性测试&#xff08;Interop- erability Tests&#xff09;&#xff0c;用于验证车载以太网PHY&#xff08;通常也称为收发器&#xff09;的可靠性和检查PHY能否在给定的有限时间内建立稳定的链路;还用于车载以太网PHY的诊断&#x…

ARCGIS 纸质小班XY坐标转电子要素面(2)

本章用于说明未知坐标系情况下如何正确将XY转要素面 背景说明 现有资料&#xff1a;清除大概位置&#xff0c;纸质小班图&#xff0c;图上有横纵坐标&#xff0c;并已知小班XY拐点坐标&#xff0c;但未知坐标系。需要上图 具体操作 大部分操作同这边文章ARCGIS 纸质小班XY…

Vue.js 模板语法详解:插值表达式与指令使用指南

Vue.js 模板语法详解&#xff1a;插值表达式与指令使用指南 引言 简要介绍主题&#xff1a; Vue.js 是一个现代化的 JavaScript 框架&#xff0c;用于构建用户界面。Vue 的模板语法提供了直观且功能强大的工具&#xff0c;用于将数据与 DOM 绑定。本文将深入探讨 Vue.js 的两个…

AI游戏革命!谷歌推出GameNGen,实时生成游戏画面,每秒20帧实时模拟

未来&#xff0c; AI会取代传统游戏引擎吗&#xff1f; 谷歌的研究人员发表论文称&#xff0c;他们创建了一个名为GameNGen的AI神经网络&#xff0c;直接用AI生成了整个《Doom》游戏&#xff01; 最令人惊讶的是&#xff0c;他们并没有使用传统的游戏引擎&#xff0c;而是在单…

基于单片机的浴室防雾镜系统设计

1系统方案设计 浴室防雾镜是一种特殊的镜子&#xff0c;在浴室中使用时不会起雾&#xff0c;通过对其需要展开分析&#xff0c;本设计基于51单片机设计的浴室防雾镜的系统架构如图2.1所示&#xff0c;采用了DS18B20温度传感器和人体红外感应红外传感器进行智能控制&#xff0c…