### 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. 更改Mysql 密码的4种方法(转)

    原文:http://www.jb51.net/article/39454.htm 方法1: 用SET PASSWORD命令 首先登录MySQL. 格式:mysql> set password f ...

  2. /bin/sh^M:bad interpreter: No such file or directory

    bash脚本:/bin/sh^M:bad interpreter: No such file or directory   dos2unix 实际上就是把文本文件中面的^M删除 用SHELL 写了一个 ...

  3. ubuntu 16.04.3 安装完成后的一些初始化工作

    虚拟机安装前记得把桥接调好! 1. 重置root密码 sudo passwd, 然后系统会让你输入密码,这时输入的密码就是root用户的密码,su root切用户 2. 设置固定IP,有重启服务功能令 ...

  4. 如何正确对tomcat host进行配置

    今天在对tomcat的host容器(即虚拟主机的配置)进行配置时,发现即使修改了host name的值(默认为localhost),但是仍无法访问web项目的问题(提示域名解析出错).只能使用默认的值 ...

  5. python利用正则表达式提取字符串

    前言 正则表达式的基础知识就不说了,有兴趣的可以点击这里,提取一般分两种情况,一种是提取在文本中提取单个位置的字符串,另一种是提取连续多个位置的字符串.日志分析会遇到这种情况,下面我会分别讲一下对应的 ...

  6. Android 与H5之间的js交互

    之前项目做过一些Android和Html5之间js交互方面的东西,今天有时间就总结一下: 一.为什么要进行js交互: 为了方便原生开发和Html之间数据传递,在静态页面的情况下可以改变原生开发的页面: ...

  7. 从零开始写一个Exporter

    前言 上一篇文章中已经给大家整体的介绍了开源监控系统Prometheus,其中Exporter作为整个系统的Agent端,通过HTTP接口暴露需要监控的数据.那么如何将用户指标通过Exporter的形 ...

  8. 洛谷P2296 寻找道路==codevs3731 寻找道路

    P2296 寻找道路 题目描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点 ...

  9. 【BZOJ3112】[Zjoi2013]防守战线 单纯形法

    [BZOJ3112][Zjoi2013]防守战线 题解:依旧是转化成对偶问题,然后敲板子就行了~ 建完表后发现跟志愿者招募的表正好是相反的,感觉很神奇~ #include <cstdio> ...

  10. 【BZOJ4930】棋盘 拆边费用流

    [BZOJ4930]棋盘 Description 给定一个n×n的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置(x,y),(u,v)能互相攻击当前仅 当满足以下两个条件: 1:x=u或y ...