zoukankan      html  css  js  c++  java
  • 7_DoubleBuffer 游戏编程中的双缓存模式

    ### double buffer 双缓存
    
    简单说: 当一个缓存被读取的时候,往另一个缓存里写入, 如此交替
    
    #### the pattern
    有两个缓存实例,一个是 current buffer, 一个是next buffer
    
    从current buffer读取信息, 往next buffer里写入信息.
    swap操作,进行两种buff的身份切换
    
    
    #### 何时使用
    1 需要增量修改的状态
    2 在修改的过程中需要进行访问
    3 当访问数据的时候,不会发现数据正在被写入
    4 读操作不用等待写的操作完成
    
    
    #### 注意事项
    
    1 swap操作比较耗时
    2 必须有两个buffer, 内存消耗变大
    
    
    #### Sample Code
    
    ####一个帧缓存的例子
    
    ```
    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];
    };
    
    
    // 问题版本
    class Scene
    {
    public:
    
      // 每一帧执行
      
      
      void draw()
      {
        buffer_.clear();
    
        buffer_.draw(1, 1);
        buffer_.draw(4, 1);
        // 问题! video driver 可以在任何时候读取pixels, 可能会读到非法值
        buffer_.draw(1, 3);
        buffer_.draw(2, 4);
        buffer_.draw(3, 4);
        buffer_.draw(4, 3);
      }     
      
    
      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_[0]),
        next_(&buffers_[1])
      {}
    
    
      // video driver 只会从 current里获取pixel
      void draw()
      {
        next_->clear();
    
        next_->draw(1, 1);
        // ...
        next_->draw(4, 3);
    
        swap();
      }
    
      Framebuffer& getBuffer() { return *current_; }
    
    private:
      void swap()
      {
        // Just switch the pointers.
        Framebuffer* temp = current_;
        current_ = next_;
        next_ = temp;
      }
    
      Framebuffer  buffers_[2];
      Framebuffer* current_;
      Framebuffer* next_;
    };
    
    ```
    
    ##### Artificial unintelligence
    
    ```
    class Actor
    {
    public:
      Actor() : slapped_(false) {}
    
      virtual ~Actor() {}
      virtual void update() = 0;
    
      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 = 0; i < NUM_ACTORS; i++)
        {
          actors_[i]->update();
          actors_[i]->reset();
        }
      }
    
    private:
      static const int NUM_ACTORS = 3;
    
      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, 0);
    stage.add(baldy, 1);
    stage.add(chump, 2);
    
    harry->slap();
    
    stage.update();
    
    
    // slap
     harry ---slap---> balay --slap----> chump
     ^                                   |
     |
     ----------------slap---------------v
     正确的结果
     
     #如果把三人的执行顺序换一下, 结果将不正确#
    stage.add(harry, 2);
    stage.add(baldy, 1);
    stage.add(chump, 0);
    
    只有harry slap 了baldy
    
    buffered slaps
    
    // 把slap用buffer记录下来
    
    class Actor
    {
    public:
      Actor() : currentSlapped_(false) {}
    
      virtual ~Actor() {}
      virtual void update() = 0;
    
      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 = 0; i < NUM_ACTORS; i++)
      {
        actors_[i]->update();
      }
    
      for (int i = 0; i < NUM_ACTORS; i++)
      {
        actors_[i]->swap();
      }
    }
    
    
    ```
    
    
    #### buffer swap
    swap需要锁住两个buffer, 所需需要尽量的轻量快速
    1 交换指针 引用
        1.快速
        2.外部代码不能保存buffer指针
        3 当前的数据,是两帧之前的数据(读current的同时,数据写入了next)
        
    2 buffer之间拷贝数据
        如果无法进行swap,可以把next的数据copy到current
        如果数量小则没什么问题,如果大则会耗时
        
    
    ```
    当很多对象都有需要swap操作时, 会很慢
    下面这个例子,不用swap,而是slap的时候修改了next的值
    
    class Actor
    {
    public:
      static void init() { current_ = 0; }
      static void swap() { current_ = next(); }
    
      void slap()        { slapped_[next()] = true; }
      bool wasSlapped()  { return slapped_[current_]; }
    
    private:
      static int current_;
      static int next()  { return 1 - current_; }
    
      bool slapped_[2];
    };
    ```
    
    
    #### 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.
  • 相关阅读:
    字符串匹配算法
    C#中窗体的位置和大小
    关于C#值类型,引用类型,值传递,引用传递(转载)
    ArcMap中设置.mxd相对路径
    统计学上的知识
    .NET 数学实现资料(ZZ)
    牛腩新闻系统学习笔记06讲 编写SQLHelper
    DropDownList 控件不能触发SelectedIndexChanged 事件的另一个原因
    牛腩新闻视频 03讲 数据库设计的心得 如何建立外键sql2008的数据库关系图功能
    使用sql server management studio 2008 连接数据库,无法查看数据库,提示 无法为该请求检索数据 错误916
  • 原文地址:https://www.cnblogs.com/lightlfyan/p/4230736.html
Copyright © 2011-2022 走看看