標籤:
### 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 bufferclass 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執行updateclass 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 了baldybuffered 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 swapswap需要鎖住兩個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 alsodouble 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 遊戲編程中的雙緩衝模式