### double buffer 双缓存

简单说: 当一个缓存被读取的时候,往另一个缓存里写入, 如此交替

#### the pattern
有两个缓存实例,一个是 current buffer, 一个是next buffer 从current buffer读取信息, 往next buffer里写入信息.
swap操作,进行两种buff的身份切换 #### 何时使用
需要增量修改的状态
在修改的过程中需要进行访问
当访问数据的时候,不会发现数据正在被写入
读操作不用等待写的操作完成 #### 注意事项 swap操作比较耗时
必须有两个buffer, 内存消耗变大 #### Sample Code ####一个帧缓存的例子 ```
class Framebuffer
{
public:
Framebuffer() { clear(); } void clear()
{
for (int i = ; 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 = ;
static const int HEIGHT = ; char pixels_[WIDTH * HEIGHT];
}; // 问题版本
class Scene
{
public: // 每一帧执行 void draw()
{
buffer_.clear(); buffer_.draw(, );
buffer_.draw(, );
// 问题! video driver 可以在任何时候读取pixels, 可能会读到非法值
buffer_.draw(, );
buffer_.draw(, );
buffer_.draw(, );
buffer_.draw(, );
} Framebuffer& getBuffer() { return buffer_; } private:
Framebuffer buffer_; void swap()
{
// Just switch the pointers.
Framebuffer* temp = current_; current_ = next_;
next_ = temp;
} }; // 使用double buffer
class Scene
{
public:
Scene()
: current_(&buffers_[]),
next_(&buffers_[])
{} // video driver 只会从 current里获取pixel
void draw()
{
next_->clear(); next_->draw(, );
// ...
next_->draw(, ); swap();
} Framebuffer& getBuffer() { return *current_; } private:
void swap()
{
// Just switch the pointers.
Framebuffer* temp = current_;
current_ = next_;
next_ = temp;
} Framebuffer buffers_[];
Framebuffer* current_;
Framebuffer* next_;
}; ``` ##### Artificial unintelligence ```
class Actor
{
public:
Actor() : slapped_(false) {} virtual ~Actor() {}
virtual void update() = ; void reset() { slapped_ = false; }
void slap() { slapped_ = true; }
bool wasSlapped() { return slapped_; } private:
bool slapped_;
}; // 每一帧都会调用actor的update, ,所有的actor需要同时进行更新
// actor之间可以交互, 例如击打 class Stage
{
public:
void add(Actor* actor, int index)
{
actors_[index] = actor;
} void update()
{
for (int i = ; i < NUM_ACTORS; i++)
{
actors_[i]->update();
actors_[i]->reset();
}
} private:
static const int NUM_ACTORS = ; Actor* actors_[NUM_ACTORS];
}; // 同一时间, 只会有一个actor执行update class Comedian : public Actor
{
public:
void face(Actor* actor) { facing_ = actor; } virtual void update()
{
if (wasSlapped()) facing_->slap();
} private:
Actor* facing_;
}; // 面对某人
harry ------> balay ------> chump
^ |
|
-------------------------------v Stage stage; Comedian* harry = new Comedian();
Comedian* baldy = new Comedian();
Comedian* chump = new Comedian(); harry->face(baldy);
baldy->face(chump);
chump->face(harry); stage.add(harry, );
stage.add(baldy, );
stage.add(chump, ); harry->slap(); stage.update(); // slap
harry ---slap---> balay --slap----> chump
^ |
|
----------------slap---------------v
正确的结果 #如果把三人的执行顺序换一下, 结果将不正确#
stage.add(harry, );
stage.add(baldy, );
stage.add(chump, ); 只有harry slap 了baldy buffered slaps // 把slap用buffer记录下来 class Actor
{
public:
Actor() : currentSlapped_(false) {} virtual ~Actor() {}
virtual void update() = ; void swap()
{
// Swap the buffer.
currentSlapped_ = nextSlapped_; // Clear the new "next" buffer.
nextSlapped_ = false;
} void slap() { nextSlapped_ = true; }
bool wasSlapped() { return currentSlapped_; } private:
bool currentSlapped_;
bool nextSlapped_;
}; void Stage::update()
{
for (int i = ; i < NUM_ACTORS; i++)
{
actors_[i]->update();
} for (int i = ; i < NUM_ACTORS; i++)
{
actors_[i]->swap();
}
} ``` #### buffer swap
swap需要锁住两个buffer, 所需需要尽量的轻量快速
交换指针 引用
.快速
.外部代码不能保存buffer指针
当前的数据,是两帧之前的数据(读current的同时,数据写入了next) buffer之间拷贝数据
如果无法进行swap,可以把next的数据copy到current
如果数量小则没什么问题,如果大则会耗时 ```
当很多对象都有需要swap操作时, 会很慢
下面这个例子,不用swap,而是slap的时候修改了next的值 class Actor
{
public:
static void init() { current_ = ; }
static void swap() { current_ = next(); } void slap() { slapped_[next()] = true; }
bool wasSlapped() { return slapped_[current_]; } private:
static int current_;
static int next() { return - current_; } bool slapped_[];
};
``` #### See also
double buffer 模式在图形编程上应用广泛 You can find the Double Buffer pattern in use in almost every graphics API out there. For example, OpenGL has swapBuffers(), Direct3D has “swap chains”, and Microsoft’s XNA framework swaps the framebuffers within its endDraw() method.

7_DoubleBuffer 游戏编程中的双缓存模式的更多相关文章

  1. 第28月第21天 记事本Unicode 游戏编程中的人工智能技术

    1. Windows平台,有一个最简单的转化方法,就是使用内置的记事本小程序notepad.exe.打开文件后,点击文件菜单中的另存为命令,会跳出一个对话框,在最底部有一个编码的下拉条. 里面有四个选 ...

  2. 游戏编程系列[1]--游戏编程中RPC协议的使用

    RPC(Remote Procedure Call Protocol)--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在 ...

  3. windows游戏编程X86 32位保护模式下的内存管理概述(二)

    本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22448323 作者:jadeshu   邮箱: jades ...

  4. 游戏编程系列[1]--游戏编程中RPC协议的使用[3]--体验

    运行环境,客户端一般编译为.Net 3.5 Unity兼容,服务端因为用了一些库,所以一般为4.0 或往上.同一份代码,建立拥有2个项目.客户端引用: WindNet.Client服务端引用: OpL ...

  5. 游戏编程系列[2]--游戏编程中RPC与OpLog协议的结合--序

    在系列[1]中,我们展示了RPC调用协议的定义以及演示,通过方法定义以及协议约定,进行了协议约定以及调用过程的约定.然而,实际上在游戏中,调用过程之后,需要传输相对多的数据给服务端. 常用场景,客户端 ...

  6. 游戏编程系列[1]--游戏编程中RPC协议的使用[2]--Aop PostSharp篇

    上一篇我们使用了一个通用JSON协议约定来进行达到远程调用的目的.但是从实现上,我们需要不断的在所有的方法上添加拦截,并且判断拦截,然后执行,这就达到了一个比较繁琐的目的. 之前我们尝试过使用代码生成 ...

  7. windows游戏编程X86 32位保护模式下的内存管理概述(一)

    本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22445945 作者:jadeshu   邮箱: jades ...

  8. 如何系统掌握游戏编程中3D图形学相关的基础?

    https://www.zhihu.com/question/27544895 三维几何学基础:三维坐标系统点与矢量矩阵与几何变换四元数与三维旋转

  9. 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D中的顶点缓存和索引缓存

    第12章 Direct3D绘制基础 1. 顶点缓存 计算机所描绘的3D图形是通过多边形网格来构成的,网网格勾勒出轮廓,然后在网格轮廓的表面上贴上相应的图片,这样就构成了一个3D模型.三角形网格是构建物 ...

随机推荐

  1. saltstack内置执行模块useradd

    useradd模块用于命令行管理用户 salt.modules.useradd.add(name, uid=None, gid=None, groups=None, home=None, shell= ...

  2. Centos 安装libreoffice 生成office 报错信息见内容

    个人博客:https://blog.sharedata.info/ 错误信息:/opt/libreoffice5.2/program/soffice.bin: error while loading ...

  3. polynomial time

    https://en.wikipedia.org/wiki/Time_complexity#Polynomial_time An algorithm is said to be of polynomi ...

  4. 浅谈命令查询职责分离(CQRS)模式---转载

    在常用的三层架构中,通常都是通过数据访问层来修改或者查询数据,一般修改和查询使用的是相同的实体.在一些业务逻辑简单的系统中可能没有什么问题,但是随着系统逻辑变得复杂,用户增多,这种设计就会出现一些性能 ...

  5. HDU 4513 吉哥系列故事――完美队形II(Manacher)

    题目链接:cid=70325#problem/V">[kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher V - 吉哥系列故事――完美队形I ...

  6. node.js版本升级

      node有一个模块叫n(这名字可够短的...),是专门用来管理node.js的版本的. 首先安装n模块: npm install -g n 第二步: 升级node.js到最新稳定版 n stabl ...

  7. im协议设计选型【转】

    一.im协议的分层设计所谓“协议”是双方共同遵守的规则,例如:离婚协议,停战协议.协议有语法.语义.时序三要素.(1)语法:即数据与控制信息的结构或格式(2)语义:即需要发出何种控制信息,完成何种动作 ...

  8. CSS选择器(二)

    五.属性选择器. 属性选择器可以根据元素的属性及属性值来选择元素. 简单属性选择 如果希望选择有某个属性的元素,而不论属性值是什么,可以使用简单属性选择器. 例子 1 如果您希望把包含标题(title ...

  9. PAT 天梯赛 L3-013. 非常弹的球 【物理】

    题目链接 https://www.patest.cn/contests/gplt/L3-013 思路 将速度 分解成 竖直方程 和 垂直方向 当 角度为 45° 时 射出的时候 水平方向 最远 所以 ...

  10. c的详细学习(9)结构体与共用体的学习(一)

    C语言提供了另外两种构造类型:结构体与公用体,用来存储若干个类型不同但彼此组成一个集合的数据总体. (1)结构体类型与结构体变量 1.定义 其一般形式为: struct  结构体类型名{ 数据类型1 ...