ปัญหาบัฟเฟอร์สองหรือสามแก้ไขในเกมสมัยใหม่อย่างไร


31

ฉันต้องการตรวจสอบว่าการทำความเข้าใจเกี่ยวกับสาเหตุของการใช้การบัฟเฟอร์สองเท่า (หรือสามเท่า) ถูกต้องหรือไม่:

จอภาพที่มีการรีเฟรช 60Hz ของจอภาพ - จอแสดงผล 60 ครั้งต่อวินาที หากจอภาพรีเฟรชจอแสดงผลเขาจะอัปเดตพิกเซลเป็นพิกเซลและบรรทัดสำหรับบรรทัด จอภาพขอค่าสีสำหรับพิกเซลจากหน่วยความจำวิดีโอ

ถ้าตอนนี้ฉันเล่นเกมเกมนี้ก็จัดการหน่วยความจำวิดีโอนี้อยู่ตลอดเวลา

หากเกมนี้ไม่ใช้กลยุทธ์บัฟเฟอร์ (การบัฟเฟอร์สองครั้งเป็นต้น) ปัญหาต่อไปนี้อาจเกิดขึ้นได้:

ตอนนี้จอภาพกำลังรีเฟรชจอภาพ - จอแสดงผลของเขาแล้ว ในขณะนี้จอภาพได้รีเฟรชจอภาพครึ่งแรกแล้ว ในเวลาเดียวกันเกมได้จัดการหน่วยความจำวิดีโอด้วยข้อมูลใหม่ ตอนนี้จอภาพสามารถเข้าถึงจอภาพที่ใช้ในช่วงครึ่งหลังและแสดงข้อมูลที่ถูกจัดการใหม่นี้จากหน่วยความจำวิดีโอ ปัญหาสามารถฉีกขาดหรือริบหรี่

ฉันเข้าใจกรณีของการใช้กลยุทธ์บัฟเฟอร์ถูกต้องหรือไม่? มีเหตุผลอื่นอีกไหม?

คำตอบ:


62

เป้าหมายหลักในการเรนเดอร์คือแต่ละเฟรมที่แสดงบนจอภาพเพื่อนำเสนอภาพเดียวที่เชื่อมโยงกัน มีหลายกลยุทธ์ที่แตกต่างกันซึ่งเป็นหรือถูกนำมาใช้เพื่อให้บรรลุนี้

ในเรื่องต่อไปนี้ฉันพูดถึง "vsync" Vsync เป็นช่วงเวลาที่จอภาพเริ่มวาดภาพหน้าจอใหม่ เป็นจุดที่ "vblank" เริ่มต้นบนหน้าจอ CRT แบบดั้งเดิมที่ซึ่งไลน์การสแกนจะหยุดการวาดและย้ายกลับไปที่ด้านบนของจอภาพชั่วขณะ ช่วงเวลานี้สำคัญมากสำหรับวิธีการหลายวิธีในการเชื่อมโยงกรอบ

"การฉีกขาด" คือสิ่งที่เราเรียกว่าเมื่อหน้าจอแสดงผลจากภาพสองภาพที่แตกต่างกันภายในกรอบเดียว ตัวอย่างเช่นถ้าฉันวาดภาพหน้าจอสองภาพซึ่งตั้งใจจะให้แสดงทีละภาพ แต่จอแสดงผลได้แสดงครึ่งบนของเฟรมหนึ่งและครึ่งล่างของเฟรมสองนั่นคือ "ฉีกขาด" สิ่งนี้เกิดขึ้นเนื่องจากการเปลี่ยนแปลงข้อมูลที่จอภาพกำลังอ่านในขณะที่จอภาพกำลังวาดแทนที่จะเป็นช่วง vblank (ในโปรแกรมที่ทันสมัยมักเกิดขึ้นเนื่องจากผู้ใช้ปิดการใช้งานรอ vsync ในการตั้งค่าไดรเวอร์ของพวกเขา)

ศูนย์บัฟเฟอร์

บนฮาร์ดแวร์ที่เก่าที่สุดมักจะมีหน่วยความจำไม่เพียงพอที่จะเก็บภาพเต็มหน้าจอและดังนั้นแทนที่จะวาดภาพหน้าจอคุณจำเป็นต้องระบุสีสำหรับแต่ละ scanline ทีละรายการขณะที่จอภาพอยู่ในขั้นตอนการวาดเส้นนั้น ตัวอย่างเช่นใน Atari 2600 คุณมีวงจรการเรียนการสอนด้วยเครื่องเพียง 76 รอบเพื่อระบุสีที่เข้าไปในแต่ละพิกเซลของ scanline ก่อนที่โทรทัศน์จะเริ่มวาดเส้นสแกนนั้น จากนั้นคุณมีคำสั่ง 76 รอบเพื่อให้เนื้อหาสำหรับscanline ถัดไปและอื่น ๆ

เดี่ยวบัฟเฟอร์

เมื่อวาดในบริบท "บัฟเฟอร์เดียว" คุณกำลังวาดลงไปใน VRAM ที่จอภาพกำลังอ่านอยู่ ในวิธีการนี้คุณ "แข่งสแกนไลน์" แนวคิดทั่วไปคือว่าเมื่อ scanline เริ่มวาดภาพเนื้อหาเฟรมก่อนหน้าที่ด้านบนของหน้าจอที่คุณวาดเข้า VRAM ที่อยู่เบื้องหลังมัน ดังนั้นขณะที่ scanline กำลังวาดภาพหน้าจอสำหรับเฟรมสุดท้ายคุณจะวาดเฟรมถัดไปด้านหลังสแกนไลน์

โดยทั่วไปแล้วคุณกำลังพยายามวาดภาพเฟรมถัดไปให้เสร็จก่อนที่ไลน์สแกนจะ "วน" คุณโดยการวนไปรอบ ๆ และแซงพิกเซลที่คุณกำลังวาดและไม่เคยล้ำหน้าสแกนไลน์หรือสิ่งใหม่ของคุณ เฟรมอาจวาดลงในสิ่งที่ควรเป็นเฟรมก่อนหน้า

ด้วยเหตุนี้การเรนเดอร์บัฟเฟอร์เดียวจึงทำงานได้เองโดยการวาดเส้นสเกลไลน์จากบนลงล่างและจากซ้ายไปขวา หากคุณวาดในลำดับอื่น ๆ มันอาจเป็นไปได้ว่า scanline จะกลับมาอีกครั้งและมองเห็นภาพ "ถัดไป" ซึ่งคุณยังไม่ได้วาด

โปรดทราบว่าในระบบปฏิบัติการที่ทันสมัยโดยทั่วไปคุณจะไม่เคยมีโอกาสที่จะวาดบัฟเฟอร์เดี่ยวแม้ว่าจะเป็นเรื่องปกติเมื่อสามสิบปีที่แล้วก็ตาม (ตอนนี้ฉันรู้สึกเก่ามากแล้ว - นี่คือสิ่งที่ฉันทำเมื่อฉันเริ่มพัฒนาเกมครั้งแรก)

ดับเบิลบัฟเฟอร์

นี่ง่ายกว่ากลยุทธ์ใด ๆ ที่เคยทำมาก่อนมาก

ในระบบการบัฟเฟอร์สองครั้งเรามีหน่วยความจำเพียงพอที่จะเก็บภาพหน้าจอที่แตกต่างกันสองภาพดังนั้นเราจึงกำหนดหนึ่งในนั้นเป็น "บัฟเฟอร์ด้านหน้า" และอีกหนึ่ง "บัฟเฟอร์หลัง" "front buffer" คือสิ่งที่กำลังแสดงอยู่และ "back buffer" เป็นที่ที่เรากำลังวาด

หลังจากที่เราวาดภาพหน้าจอไปที่บัฟเฟอร์ด้านหลังเสร็จแล้วเราจะรอจนกระทั่ง vsync จากนั้นสลับบัฟเฟอร์ทั้งสอง ด้วยวิธีนี้บัฟเฟอร์ด้านหลังจะกลายเป็นบัฟเฟอร์ด้านหน้าและในทางกลับกันและการสลับทั้งหมดเกิดขึ้นในขณะที่จอภาพไม่ได้วาดอะไรเลย

Triple-บัฟเฟอร์

ปัญหาหนึ่งที่มักเกิดขึ้นกับวิธีการสองบัฟเฟอร์คือหลังจากที่เราวาดไปที่ back buffer เสร็จแล้วเราต้องนั่งรอ vsync ก่อนที่เราจะสามารถแลกเปลี่ยนบัฟเฟอร์และทำงานต่อไป เราอาจทำการคำนวณในช่วงเวลานั้นได้! ยิ่งกว่านั้นตลอดเวลาที่เรารอการสลับระหว่างบัฟเฟอร์รูปภาพในบัฟเฟอร์ด้านหลังนั้นเก่าขึ้นเรื่อย ๆ ซึ่งจะเป็นการเพิ่มความล่าช้าในการรับรู้ของผู้ใช้

ในระบบสามบัฟเฟอร์เราสร้างตัวเราสามบัฟเฟอร์ - หนึ่งบัฟเฟอร์ด้านหน้าและสองบัฟเฟอร์กลับ ความคิดคือสิ่งนี้:

จอภาพกำลังแสดงบัฟเฟอร์ด้านหน้าและเรากำลังวาดลงในบัฟเฟอร์ด้านหลัง # 1 หากเราวาดลงใน back buffer # 1 ก่อนที่มอนิเตอร์จะวาด buffer ด้านหน้าเสร็จแล้วแทนที่จะรอ vsync เราก็เริ่มวาดเฟรมถัดไปทันทีลงใน back buffer # 2 หากเรายังคงเสร็จสิ้นและ vsync ยังไม่มาเราเริ่มวาดกลับไปที่บัฟเฟอร์ด้านหลัง # 1 และอื่น ๆ แนวคิดคือเมื่อ vsync เกิดขึ้นในที่สุดบัฟเฟอร์แบ็คอัพอันใดอันหนึ่งของเราจะเสร็จสมบูรณ์และสามารถสลับอันหนึ่งสำหรับบัฟเฟอร์ด้านหน้าได้

ประโยชน์ของการบัฟเฟอร์สามเท่าคือเราไม่เสียเวลาที่เรารอคอย vsync ในวิธีการบัฟเฟอร์สองครั้งและภาพที่สลับไปยังบัฟเฟอร์ด้านหน้าอาจ "สดชื่น" มากกว่าที่รอ vsync สำหรับ 8ms ด้านล่างของการบัฟเฟอร์สามเท่าคือเราต้องการหน่วยความจำเพิ่มเติมสำหรับการจัดเก็บภาพหน้าจอพิเศษและการใช้งาน CPU / GPU ของเราจะสูงขึ้น (อีกครั้งเนื่องจากเราไม่ช้าลงเพื่อรอ vsync)

โดยทั่วไปแล้วคนขับรถรุ่นใหม่มักจะทำงานสามด้านอย่างโปร่งใสหลังฉาก คุณเขียนรหัสเพื่อทำบัฟเฟอร์สองครั้งและคนขับจะกลับมาควบคุมคุณก่อนและเพียงแค่จัดการแลกเปลี่ยนภายในระหว่างบัฟเฟอร์ด้านหลังจำนวนมากที่ต้องการใช้โดยไม่ต้องใช้รหัสของคุณรู้ตัว

ผู้จำหน่าย GPU ในปัจจุบันแนะนำว่าคุณไม่ควรใช้ตัวคุณเองสามเท่า - ไดรเวอร์จะทำเพื่อคุณโดยอัตโนมัติ


7
นี่เป็นคำตอบที่มีรายละเอียดอย่างไม่น่าเชื่อและอธิบายว่าทำไมหลาย ๆ สิ่งจึงทำในแบบที่พวกเขาทำ (เช่นพื้นที่หน้าจอประสานงานเป็นต้น) ยังตอบคำถามของฉัน "ทำไมไม่บัฟเฟอร์สี่เท่า? Quintuple?" ฉันไม่ทราบว่าการแลกเปลี่ยนบัฟเฟอร์เกิดขึ้นในพื้นหลังซึ่งหมายความว่าบัฟเฟอร์สำรองสองหลังนั้นเป็นค่าสูงสุดที่จำเป็น upvoted
lunchmeat317

จริงๆแล้วมีการบัฟเฟอร์สี่เหลี่ยม นี่เป็นบัฟเฟอร์สองเท่าสำหรับมุมมองภาพสามมิติ swiftless.com/tutorials/opengl/smooth_rotation.html
Narek

@ ไม่ได้รับการอ้างอิงจากลิงก์ของคุณ: "คุณไม่สามารถเปิดใช้งานการบัฟเฟอร์สี่เหลี่ยมจริงในสภาพแวดล้อมกราฟิคคอมพิวเตอร์ได้เนื่องจากไม่มีจุดจริง" การแนะนำว่าการทำบัฟเฟอร์สองครั้งในสองมุมมองที่แตกต่างกันพร้อมกันคือ "การบัฟเฟอร์สี่เหลี่ยม" เป็นเพียงการเล่นคำที่สนุกสนาน ไม่ใช่ของจริง
Trevor Powell

@TrevorPowell การเพิ่มส่วนที่คุณลืมรวมถึง: "ดีโดยทั่วไปการบัฟเฟอร์สี่ชั้นหมายถึงการบัฟเฟอร์สองครั้งในสภาพแวดล้อมสามมิติเช่น: คุณมีจอแสดงผลสองจอโดยทั่วไปสำหรับวัตถุประสงค์ 3 มิติและแต่ละตามีบัฟเฟอร์สองเท่า" ตอนนี้บริบทอาจมีความชัดเจนมากขึ้น
Narek

@ TrevorPowell จุดของคุณชัดเจนโดยสิ้นเชิงว่า มันไม่มีเหตุผลที่จะมีบัฟเฟอร์มากกว่า 3 อันสำหรับบัฟเฟอร์การแสดงผลหนึ่งอัน
Narek
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.