《游戏编程模式》学习笔记(八)双缓冲模式 Sequencing Patterns

双缓冲模式的意图

双缓冲模式,使用序列操作来模拟瞬间或者同时发生的事情

具体定义

双缓冲模式定义缓冲类封装了缓冲:一段可改变的状态。 这个缓冲被增量地修改,但我们想要外部的代码将修改视为单一的原子操作。 为了实现这点,类保存了两个缓冲的实例:下一缓冲和当前缓冲。
当信息从缓冲区中读取,它总是读取当前的缓冲区。 当信息需要写到缓存,它总是在下一缓冲区上操作。 当改变完成后,一个交换操作会立刻将当前缓冲区和下一缓冲区交换, 这样新缓冲区就是公共可见的了。旧的缓冲区成为下一个重用的缓冲区。

举个例子

接触过渲染系统的同学应该知道,图形渲染的任务就是将指定颜色的像素存储到一个缓冲区中,缓冲区中有一个二维的数组, GPU负责读取这个数组,根据数组中的颜色信息,将图像绘制在屏幕上。我们可以这样定义这个缓冲区:

class Framebuffer
{
public:Framebuffer() { clear(); }void clear(){for (int i = 0; i < WIDTH * HEIGHT; i++){pixels_[i] = WHITE;}}void draw(int x, int y){pixels_[(WIDTH * y) + x] = BLACK;}const char* getPixels(){return pixels_;}private:static const int WIDTH = 160;static const int HEIGHT = 120;char pixels_[WIDTH * HEIGHT];
};

其中pixels就是我们说的二维数组,GPU会频繁调用函数,将缓冲区中的数据(通常是颜色信息)输送到屏幕上。
我们将整个缓冲区封装在Scene类中。渲染某物需要做的是在这块缓冲区上调用一系列draw()。

class Scene
{
public:void draw(){buffer_.clear();buffer_.draw(1, 1);buffer_.draw(4, 1);buffer_.draw(1, 3);buffer_.draw(2, 4);buffer_.draw(3, 4);buffer_.draw(4, 3);}Framebuffer& getBuffer() { return buffer_; }private:Framebuffer buffer_;
};

当draw()绘制完毕后,GPU就可以调用getBuffer()将数组中的颜色信息读取出来,然后在屏幕上绘制对应的信息了。
问题在于,我们的GPU会在固定的渲染帧频率期间调用 getBuffer()方法,读取pixel中的数据。如果我们绘制的任务比较重,那么就有可能出现draw()还没结束,GPU就迫不及待读取了,这就会造成画面错误。
当上面的情况发生时,用户就会看到脸的眼睛,但是这一帧中嘴却消失了。 下一帧,又可能在某些别的地方发生冲突。最终结果是糟糕的闪烁图形。
我们会用双缓冲模式修复这点:

class Scene
{
public:Scene(): current_(&buffers_[0]),next_(&buffers_[1]){}void draw(){next_->clear();next_->draw(1, 1);// ...next_->draw(4, 3);swap();}Framebuffer& getBuffer() { return *current_; }private:void swap(){// 只需交换指针Framebuffer* temp = current_;current_ = next_;next_ = temp;}Framebuffer  buffers_[2];Framebuffer* current_;Framebuffer* next_;
};

现在scene中有两个缓冲区,next_是我们正在绘制的数组。Current_是已经准备就绪,CPU可以访问到的数组。每次绘制完毕,我们只要交换一下两个数组的指针就好了。在需要时,GPU读取current_获取数据绘制图像。因为GPU不会接触到正在施工的数据,所以可以保证每次都是正确的图像。

一些要点

  1. Swap本身也需要时间,我们必须要保证swap的操作是原子的,也就是说,在这个过程中,没有人可以接触到这两个缓冲区的任何数据,这样才能保证双缓冲模式正确运行。
    双缓冲需要保存两个缓冲区,这可能是个问题,你得看看自己的内存够不够用。
  2. 原文里还用扇耳光游戏说明了双缓冲模式在别的地方的运用,这里没有做相关笔记。大体上来说,双缓冲模式保证了这个游戏所有人对于巴掌的反应都在下一帧才生效,这让它们在同一帧中更新的顺序不该对结果有影响。

使用场合

  • 我们需要维护一些被增量修改的状态。
  • 在修改到一半的时候,状态可能会被外部请求。
  • 我们想要防止请求状态的外部代码知道内部的工作方式。
  • 我们想要随时可以读取状态,而且不想等着修改完成。

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

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

相关文章

Programming abstractions in C阅读笔记:p127-p129

《Programming Abstractions In C》学习第51天&#xff0c;p127-p129&#xff0c;总结如下&#xff1a; 一、技术总结 1. string library 掌握常用函数如strlen&#xff0c;strcpy用法。 2.buffer overflow(缓冲区溢出) (1)什么是buffer? p129&#xff0c;Arrays that a…

死锁的典型情况、产生的必要条件和解决方案

前言 死锁&#xff1a;多个线程同时被阻塞&#xff0c;他们中的一个或全部都在等待某个资源被释放。由于线程被无限期地阻塞&#xff0c;因此程序不可能正常终止。 目录 前言 一、死锁的三种典型情况 &#xff08;一&#xff09;一个线程一把锁 &#xff08;二&#xff09;…

==和===的区别(经典面试题,你不知道的细节)

全等运算符 又叫全等运算符&#xff0c;结果会返回一个布尔值&#xff0c;在数据类型相同的情况下&#xff0c;会比较值&#xff0c;值相同才返回true "1" 1 // false NaN NaN // false undefined undefined // true相等运算符 相等运算符在比较两个变量是否相…

分布式锁解决方案

分布式锁解决方案 背景解决方案redisson 分布式锁 实战zookeeper 分布式锁 实战结论代码地址背景 由于分布式或者集群部署项目时,在某些业务场景下需保证资源的原子性、一致性和互斥性。 如果把房子比作资源,通俗的来讲,我无论在那个城市生活,这个房子我先租的,再没有退房…

dolphinscheduler的僵尸任务清理和清理一直在运行的任务状态

dolphinscheduler的僵尸任务清理 界面操作不了的 只能去数据库更改状态或则删除掉 原因&#xff1a;海豚调度中有几百条僵尸任务&#xff0c; 界面怎么也删不掉&#xff0c;想从数据库中删除&#xff0c;开始查找从数据库删除的办法。 参考以下脚本&#xff0c;结合我库中僵尸…

缓存的设计方式

问题情况&#xff1a; 当有大量的请求到内部系统时&#xff0c;若每一个请求都需要我们操作数据库&#xff0c;例如查询操作&#xff0c;那么对于那种数据基本不怎么变动的数据来说&#xff0c;每一次都去数据库里面查询&#xff0c;是很消耗我们的性能 尤其是对于在海量数据…

抖音火山引擎推出免费域名DNS和公共DNS服务

抖音旗下的云计算服务火山引擎最近推出了"TrafficRoute DNS 套件"服务&#xff0c;其中包括两款产品&#xff0c;对软希网来说非常有用。 1.域名DNS&#xff1a; 这是一个用于网站域名的DNS服务&#xff0c;可以加速域名解析速度&#xff0c;从而提升网站的速度。如…

回归预测 | MATLAB实现GA-RF遗传算法优化随机森林算法多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现GA-RF遗传算法优化随机森林算法多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现GA-RF遗传算法优化随机森林算法多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本介绍程…

mysql的登录与退出

mysql是c/s架构&#xff0c;意味着同时要有客户端和服务端 1 找到客户端。mysql.exe的安装目录 打开命令行 2 输入对应的服务器的ip&#xff0c;如果是本地&#xff0c;就是Localhost&#xff0c;如果是远程服务器&#xff0c;那就输入对应ip/域名。并且指定mysql监听的端口 …

机器视觉之特征匹配

特征匹配是计算机视觉中的一个重要任务&#xff0c;它用于寻找两幅或多幅图像中相对应的特征点&#xff0c;从而识别、跟踪或配准对象。下面是一个使用C和OpenCV进行特征匹配的简单示例&#xff0c;使用SIFT特征检测和FLANN匹配器&#xff08;快速最近邻搜索&#xff09;&#…

混合面试题

索引在单表中建议不要创建的数量超过6个&#xff0c;在大的字段上不要建立索引例如书的目录不要以文章的一个长句子为目录索引 mybatis是半自动的&#xff0c;是JDBC的浅封装&#xff0c;以sql语句的工作量换取了程序执行的高灵活性。 foreach标签&#xff1a;用于循环语句&a…

做一个蛋糕店小程序需要哪些步骤?

对于一些不懂技术的新手来说&#xff0c;创建蛋糕店小程序可能会感到有些困惑。但是&#xff0c;有了乔拓云平台的帮助&#xff0c;你可以轻松地创建自己的蛋糕店小程序。下面&#xff0c;我将为大家详细介绍一下具体的操作步骤。 首先&#xff0c;登录乔拓云平台并进入后台管理…

Mysql报错 mysqladmin flush-hosts

出现这个的原因是错误连接达到数据库设置的最大值。 此时需要释放重置连接最大值。 进入mysql使用命令 flush-hosts;环境说明&#xff1a; 内网测试服务器192.168.18.251 为WEB服务器&#xff0c;安装了mysql; 内网音视频转码服务器192.168.18.253安装了转码工具&#xff0…

Java“牵手”根据关键词搜索(分类搜索)义乌购商品列表页面数据获取方法,义乌购API实现批量商品数据抓取示例

义乌购商城是一个网上批发购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取义乌购商品列表和商品详情页面数据&#xff0c;您可以通过开放平台的接口或者直接访问义乌购商城的网页来获取商品详情信息。以下是两种常用方法…

网络安全---Ring3下动态链接库.so函数劫持

一、动态链接库劫持原理 1.1、原理 Unix操作系统中&#xff0c;程序运行时会按照一定的规则顺序去查找依赖的动态链接库&#xff0c;当查找到指定的so文件时&#xff0c;动态链接器(/lib/ld-linux.so.X)会将程序所依赖的共享对象进行装载和初始化&#xff0c;而为什么可以使用…

[软件工具]精灵标注助手目标检测数据集格式转VOC或者yolo

有时候我们拿到一个数据集发现是xml文件格式如下&#xff1a; <?xml version"1.0" ?> <doc><path>C:\Users\Administrator\Desktop\test\000000000074.jpg</path><outputs><object><item><name>dog</name>…

7个改变玩法规则的ChatGPT应用场景

ChatGPT因各种原因受到了广泛关注&#xff1a;ChatGPT可以充当各种改善生活改进工作的小助手&#xff0c;如内容写手、客户支持、语言翻译、编码专家等等。只需在你的聊天内容中添加适当的提示&#xff0c;人工智能将为你提供各项支持。[1] 1.ChatGPT作为内容写手 通过AI的帮助…

基于java SpringBoot CRM客户关系管理系统设计

当今计算机技术和信息管理技术的迅速发展和广泛应用&#xff0c;为管理相关理论的应用提供了广阔的平台。IT技术和DBT技术&#xff08;数据库技术&#xff09;基于《客户信息管理系统》设计的客户信息管理系统正在逐步发展成为管理模式发展的新趋势&#xff0c;企业建立客户信息…

常用的数据可视化工具有哪些?要操作简单的

随着数据量的剧增&#xff0c;对分析效率和数据信息传递都带来了不小的挑战&#xff0c;于是数据可视化工具应运而生&#xff0c;通过直观形象的图表来展现、传递数据信息&#xff0c;提高数据分析报表的易读性。那么&#xff0c;常用的操作简单数据可视化工具有哪些&#xff1…

java八股文面试[JVM]——JVM内存结构

参考&#xff1a; JVM学习笔记&#xff08;一&#xff09;_卷心菜不卷Iris的博客-CSDN博客 JVM是运行在操作系统之上的&#xff0c;它与硬件没有直接的交互 JVM内存结构&#xff1a; 方法区&#xff1a;存储已被虚拟机加载的类元数据信息(元空间) 堆&#xff1a;存放对象实…