ไลบรารี Frame Pacing   ส่วนหนึ่งของ Android Game Development Kit

ไลบรารีการเว้นระยะเฟรมของ Android หรือที่เรียกว่า Swappy เป็นส่วนหนึ่งของไลบรารี AGDK ซึ่งจะช่วยให้เกม OpenGL และ Vulkan แสดงผลได้อย่างราบรื่นและเว้นระยะเฟรมได้อย่างถูกต้องใน Android เอกสารนี้จะกำหนดการเว้นระยะเฟรม อธิบาย สถานการณ์ที่จำเป็นต้องใช้การเว้นระยะเฟรม และแสดงวิธีที่ไลบรารีจัดการกับ สถานการณ์เหล่านี้ หากต้องการข้ามไปใช้การเว้นวรรคเฟรมในเกมโดยตรง โปรดดูขั้นตอนถัดไป

ฉากหลัง

การเว้นระยะเฟรมคือการซิงค์ตรรกะของเกมและลูปการแสดงผลกับ ระบบย่อยการแสดงผลของระบบปฏิบัติการและฮาร์ดแวร์การแสดงผลพื้นฐาน ระบบย่อยการแสดงผลของ Android ได้รับการออกแบบมาเพื่อหลีกเลี่ยงอาร์ติแฟกต์ภาพ (ที่เรียกว่าภาพขาด) ซึ่งอาจเกิดขึ้นเมื่อฮาร์ดแวร์จอแสดงผลเปลี่ยนไปใช้เฟรมใหม่กลางคัน ระหว่างการอัปเดต ระบบย่อยการแสดงผลจะทำสิ่งต่อไปนี้เพื่อหลีกเลี่ยงอาร์ติแฟกต์เหล่านี้

  • บัฟเฟอร์เฟรมที่ผ่านมาภายใน
  • ตรวจหาการส่งเฟรมที่ล่าช้า
  • แสดงเฟรมที่ผ่านมาซ้ำเมื่อตรวจพบเฟรมที่ล่าช้า

เกมจะแจ้งให้ SurfaceFlinger ซึ่งเป็น Compositor ภายในระบบย่อยของจอแสดงผลทราบว่าได้ส่งการเรียกวาดทั้งหมดที่จำเป็นสำหรับเฟรมแล้ว (โดยการเรียก eglSwapBuffers หรือ vkQueuePresentKHR) SurfaceFlinger จะส่งสัญญาณความพร้อมใช้งานของเฟรมไปยังฮาร์ดแวร์จอแสดงผลโดยใช้ แลตช์ จากนั้นฮาร์ดแวร์จอแสดงผลจะแสดงเฟรมที่ระบุ ฮาร์ดแวร์จอแสดงผล จะทำงานในอัตราคงที่ เช่น 60 Hz และหากไม่มีเฟรมใหม่เมื่อ ฮาร์ดแวร์ต้องการเฟรมใหม่ ฮาร์ดแวร์จะแสดงเฟรมก่อนหน้าอีกครั้ง

เวลาเฟรมที่ไม่สอดคล้องกันมักเกิดขึ้นเมื่อลูปการแสดงผลของเกมแสดงผลที่ อัตราที่แตกต่างจากฮาร์ดแวร์จอแสดงผลดั้งเดิม หากเกมที่ทำงานที่ 30 FPS พยายามแสดงผลบนอุปกรณ์ที่รองรับ 60 FPS โดยกำเนิด ลูปการแสดงผลของเกม จะไม่ทราบว่าเฟรมที่ซ้ำกันยังคงอยู่บนหน้าจอเป็นเวลา 16 มิลลิวินาทีเพิ่มเติม การขาดการเชื่อมต่อนี้มักทำให้เกิดความไม่สอดคล้องกันอย่างมากในเวลาเฟรม เช่น 49 มิลลิวินาที 16 มิลลิวินาที 33 มิลลิวินาที ฉากที่ซับซ้อนมากเกินไปจะทำให้ปัญหานี้รุนแรงขึ้น เนื่องจากทำให้เกิดเฟรมที่ขาดหายไป

โซลูชันที่ไม่เหมาะสม

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

ส่งเฟรมให้เร็วที่สุดเท่าที่ API การแสดงผลอนุญาต

วิธีนี้จะเชื่อมโยงเกมกับกิจกรรม SurfaceFlinger ที่เปลี่ยนแปลงได้และทำให้เกิด เวลาในการตอบสนองเพิ่มขึ้น 1 เฟรม ไปป์ไลน์การแสดงผลมีคิวของเฟรม โดยปกติจะมีขนาด 2 ซึ่งจะเต็มหากเกมพยายามนำเสนอเฟรมเร็วเกินไป เมื่อไม่มีพื้นที่ในคิวอีกต่อไป การเรียก OpenGL หรือ Vulkan จะบล็อก Game Loop (หรืออย่างน้อยก็ เธรดการแสดงผล) จากนั้นระบบจะบังคับให้เกมรอฮาร์ดแวร์จอแสดงผลเพื่อแสดงเฟรม และแรงดันย้อนกลับนี้จะซิงค์คอมโพเนนต์ทั้ง 2 รายการ สถานการณ์นี้เรียกว่าการยัดบัฟเฟอร์หรือ การยัดคิว กระบวนการแสดงผล ไม่ทราบว่าเกิดอะไรขึ้น ดังนั้นความไม่สอดคล้องของอัตราเฟรมจึงแย่ลง หาก เกมสุ่มตัวอย่างอินพุตก่อนเฟรม เวลาในการตอบสนองของอินพุตจะแย่ลง

ใช้ Android Choreographer ด้วยตัวเอง

นอกจากนี้ เกมยังใช้ Android Choreographer เพื่อการซิงโครไนซ์ด้วย คอมโพเนนต์นี้ ซึ่งพร้อมใช้งานใน Java ตั้งแต่ API 16 และใน C++ ตั้งแต่ API 24 จะส่งสัญญาณปกติที่ ความถี่เดียวกับระบบย่อยของจอแสดงผล แต่ก็ยังมีรายละเอียดปลีกย่อยเกี่ยวกับ เวลาที่ส่งสัญญาณนี้เมื่อเทียบกับ VSYNC ของฮาร์ดแวร์จริง และออฟเซ็ตเหล่านี้จะแตกต่างกันไปตามอุปกรณ์ การแทรกบัฟเฟอร์อาจยังเกิดขึ้นกับเฟรมยาวๆ

ข้อดีของไลบรารีการเว้นระยะเฟรม

ไลบรารี Frame Pacing ใช้ Android Choreographer เพื่อการซิงโครไนซ์และ จัดการความแปรปรวนในการส่งสัญญาณสำหรับคุณ โดยใช้การประทับเวลาการนำเสนอ เพื่อให้มั่นใจว่าเฟรมจะแสดงในเวลาที่เหมาะสม และใช้ Sync Fences เพื่อหลีกเลี่ยงการใส่บัฟเฟอร์ ไลบรารีจะใช้ NDK Choreographer หากมี และ จะกลับไปใช้ Java Choreographer หากไม่มี

ไลบรารีจะจัดการอัตราการรีเฟรชหลายรายการหากอุปกรณ์รองรับ ซึ่งจะช่วยให้เกมมีความยืดหยุ่นมากขึ้นในการนำเสนอเฟรม เช่น สำหรับ อุปกรณ์ที่รองรับอัตราการรีเฟรช 60 Hz และ 90 Hz เกมที่ไม่สามารถ สร้างเฟรมต่อวินาทีได้ 60 เฟรมจะลดลงเหลือ 45 FPS แทนที่จะเป็น 30 FPS เพื่อให้ ยังคงราบรื่น ไลบรารีจะตรวจหาอัตราเฟรมของเกมที่คาดไว้และปรับเวลา การนำเสนอเฟรมโดยอัตโนมัติตามนั้น นอกจากนี้ ไลบรารีการเว้นวรรคเฟรมยังช่วยยืดอายุการใช้งานแบตเตอรี่ด้วย เนื่องจากจะหลีกเลี่ยงการอัปเดตจอแสดงผลที่ไม่จำเป็น เช่น หากเกม แสดงผลที่ 60 FPS แต่จอแสดงผลอัปเดตที่ 120 Hz หน้าจอจะ อัปเดต 2 ครั้งต่อเฟรม ไลบรารีการเว้นระยะเฟรมจะหลีกเลี่ยงปัญหานี้โดยการตั้งค่า อัตราการรีเฟรชเป็นค่าที่อุปกรณ์รองรับซึ่งใกล้เคียงกับอัตรา เฟรมเป้าหมายมากที่สุด

วิธีการทำงาน

ส่วนต่อไปนี้จะแสดงวิธีที่ไลบรารีการเว้นระยะเฟรมจัดการกับเฟรมเกมที่ยาวและสั้นเพื่อให้ได้การเว้นระยะเฟรมที่ถูกต้อง

การเว้นเฟรมที่ถูกต้องที่ 30 Hz

เมื่อแสดงผลที่ 30 Hz ในอุปกรณ์ 60 Hz สถานการณ์ที่เหมาะสมที่สุดใน Android จะ แสดงในรูปที่ 1 SurfaceFlinger จะล็อกบัฟเฟอร์กราฟิกใหม่หากมี (หมายเหตุใน แผนภาพระบุว่า "ไม่มีบัฟเฟอร์" และจะใช้บัฟเฟอร์ก่อนหน้าซ้ำ)

การเว้นระยะเฟรมที่เหมาะสมที่ 30 Hz ในอุปกรณ์ 60 Hz

รูปที่ 1 การเว้นระยะเฟรมที่เหมาะสมที่ 30 Hz ในอุปกรณ์ 60 Hz

เฟรมเกมสั้นๆ ทำให้เกิดอาการกระตุก

ในอุปกรณ์ที่ทันสมัยส่วนใหญ่ เกมเอนจินจะใช้ตัวประสานงานแพลตฟอร์ม เพื่อส่งสัญญาณเวลาเพื่อขับเคลื่อนการส่งเฟรม อย่างไรก็ตาม ยังคงมี ความเป็นไปได้ที่จะเกิดการเว้นระยะเฟรมไม่ดีเนื่องจากเฟรมสั้น ดังที่แสดงในรูปที่ 2 ผู้เล่นจะรับรู้ว่าเฟรมสั้นตามด้วยเฟรมยาวเป็นการกระตุก

เฟรมเกมสั้น

รูปที่ 2 เฟรม C ของเกมที่เล่นสั้นๆ ทำให้เฟรม B แสดงเพียงเฟรมเดียว ตามด้วยเฟรม C หลายเฟรม

ไลบรารีการเว้นระยะเฟรมจะแก้ปัญหานี้โดยใช้การประทับเวลาการนำเสนอ ไลบรารีใช้ส่วนขยายการประทับเวลาการนำเสนอ EGL_ANDROID_presentation_time และ VK_GOOGLE_display_timing เพื่อให้เฟรมไม่แสดงก่อนเวลา ดังที่แสดงในรูปที่ 3

การประทับเวลาการนำเสนอ

รูปที่ 3 เฟรม B ของเกมแสดง 2 ครั้งเพื่อให้แสดงผลได้ราบรื่นขึ้น

เฟรมที่ยาวจะทำให้เกิดการกระตุกและความหน่วง

เมื่อภาระงานการแสดงผลใช้เวลานานกว่าภาระงานของแอปพลิเคชัน ระบบจะเพิ่มเฟรมพิเศษลงในคิว ซึ่งจะทำให้เกิดอาการกระตุกอีกครั้ง และอาจทำให้เกิดเวลาในการตอบสนองเพิ่มขึ้นอีก 1 เฟรมเนื่องจากการแทรกเฟรมลงในบัฟเฟอร์ (ดูรูปที่ 4) ไลบรารีจะช่วยลดอาการภาพกระตุกและลดเวลาในการตอบสนอง

เฟรมการแข่งขันระยะยาว

รูปที่ 4 เฟรม B แบบยาวทำให้เฟรม 2 เฟรม ซึ่งได้แก่เฟรม A และ B มีการเว้นระยะที่ไม่ถูกต้อง

ไลบรารีนี้แก้ปัญหานี้ได้โดยใช้ Sync Fences (EGL_KHR_fence_sync และ VkFence) เพื่อแทรกการรอลงในแอปพลิเคชัน ซึ่งจะช่วยให้ไปป์ไลน์การแสดงผลตามทันได้ แทนที่จะปล่อยให้เกิดแรงดันย้อนกลับ เฟรม A ยังคงแสดงเฟรม พิเศษ แต่ตอนนี้เฟรม B แสดงอย่างถูกต้องแล้ว ดังที่เห็นในรูปที่ 5

เพิ่มการรอลงในเลเยอร์ของแอปพลิเคชัน

รูปที่ 5 เฟรม C และ D รอที่จะแสดง

โหมดการทำงานที่รองรับ

คุณกำหนดค่าไลบรารีการเว้นระยะเฟรมให้ทำงานในโหมดใดโหมดหนึ่งต่อไปนี้ได้

  • ปิดโหมดอัตโนมัติ + ไปป์ไลน์
  • โหมดอัตโนมัติ + ไปป์ไลน์
  • โหมดอัตโนมัติเปิด + โหมดไปป์ไลน์อัตโนมัติ (ไปป์ไลน์/ไม่ใช่ไปป์ไลน์)

คุณสามารถทดลองใช้โหมดอัตโนมัติและโหมดไปป์ไลน์ได้ แต่ต้องเริ่มด้วยการปิดโหมดดังกล่าวและรวมรายการต่อไปนี้หลังจากเริ่มต้น Swappy

  swappyAutoSwapInterval(false);
  swappyAutoPipelineMode(false);
  swappyEnableStats(false);
  swappySwapIntervalNS(1000000000L/yourPreferredFrameRateInHz);

โหมดไปป์ไลน์

โดยปกติแล้ว ไลบรารีจะใช้รูปแบบการไปป์ไลน์เพื่อประสานงานภาระงานของเครื่อง ซึ่งจะแยกภาระงานของ CPU และ GPU ตามขอบเขต VSYNC

โหมดไปป์ไลน์

รูปที่ 6 โหมดไปป์ไลน์

โหมดที่ไม่ใช่ไปป์ไลน์

โดยทั่วไปแล้ว วิธีนี้จะส่งผลให้เวลาในการตอบสนองระหว่างอินพุตกับหน้าจอลดลงและคาดการณ์ได้มากขึ้น ในกรณีที่เกมมีเวลาที่ใช้ในการแสดงผลเฟรมต่ำมาก ปริมาณงานของทั้ง CPU และ GPU อาจพอดีกับช่วงเวลาการสลับเดียว ในกรณีนี้ วิธีการที่ไม่ใช่แบบไปป์ไลน์ จะทำให้เวลาในการตอบสนองของหน้าจออินพุตต่ำกว่า

โหมดที่ไม่ใช่ไปป์ไลน์

รูปที่ 7 โหมดที่ไม่ใช่ไปป์ไลน์

โหมดอัตโนมัติ

เกมส่วนใหญ่ไม่ทราบวิธีเลือกช่วงเวลาการสลับ ซึ่งเป็นระยะเวลาที่แต่ละเฟรมแสดง (เช่น 33.3 มิลลิวินาทีสำหรับ 30 Hz) ในอุปกรณ์บางเครื่อง เกมอาจแสดงผลที่ 60 FPS ขณะที่ในอุปกรณ์อีกเครื่องอาจต้องลดลงไปที่ค่าที่ต่ำกว่า โหมดอัตโนมัติจะวัดเวลา CPU และ GPU เพื่อทำสิ่งต่อไปนี้

  • เลือกช่วงการสลับโดยอัตโนมัติ: เกมที่แสดงผล 30 Hz ในบางฉากและ 60 Hz ในฉากอื่นๆ สามารถอนุญาตให้ไลบรารีปรับช่วงนี้แบบไดนามิกได้
  • ปิดใช้การส่งผ่านข้อมูลแบบไปป์ไลน์สำหรับเฟรมที่เร็วมาก: ให้เวลาในการตอบสนองการป้อนข้อมูลบนหน้าจอที่เหมาะสมที่สุดในทุกกรณี

อัตราการรีเฟรชหลายอัตรา

อุปกรณ์ที่รองรับอัตราการรีเฟรชหลายอัตราจะมีความยืดหยุ่นมากขึ้นในการ เลือกช่วงเวลาการสลับที่ดูราบรื่น

  • ในอุปกรณ์ 60 Hz: 60 FPS / 30 FPS / 20 FPS
  • ในอุปกรณ์ 60 Hz + 90 Hz: 90 FPS / 60 FPS / 45 FPS / 30 FPS
  • ในอุปกรณ์ 60 Hz + 90 Hz + 120 Hz: 120 FPS / 90 FPS / 60 FPS / 45 FPS / 40 FPS / 30 FPS

ไลบรารีจะเลือกอัตราการรีเฟรชที่ตรงกับระยะเวลาการแสดงผลจริงของเฟรมเกมมากที่สุด เพื่อมอบประสบการณ์ด้านภาพที่ดีขึ้น

ดูข้อมูลเพิ่มเติมเกี่ยวกับการเว้นระยะเฟรมที่อัตราการรีเฟรชหลายรายการได้ที่บล็อกโพสต์การแสดงผลที่อัตราการรีเฟรชสูงใน Android

สถิติเฟรม

ไลบรารี Frame Pacing มีสถิติต่อไปนี้เพื่อวัตถุประสงค์ในการแก้ไขข้อบกพร่องและ การสร้างโปรไฟล์

  • ฮิสโทแกรมของจำนวนการรีเฟรชหน้าจอที่เฟรมรอในคิวของ Compositor หลังจากที่การแสดงผลเสร็จสมบูรณ์
  • ฮิสโทแกรมของจำนวนการรีเฟรชหน้าจอที่ผ่านไประหว่างเวลาการนำเสนอที่ขอและเวลาการนำเสนอจริง
  • ฮิสโทแกรมของจำนวนการรีเฟรชหน้าจอที่ผ่านระหว่าง 2 เฟรมติดต่อกัน
  • ฮิสโทแกรมของจำนวนการรีเฟรชหน้าจอที่ผ่านไประหว่างจุดเริ่มต้นของ งาน CPU สำหรับเฟรมนี้กับเวลาปัจจุบันจริง

ขั้นตอนถัดไป

ดูคำแนะนำต่อไปนี้เพื่อผสานรวมไลบรารีการเว้นเฟรมของ Android เข้ากับเกม

แหล่งข้อมูลเพิ่มเติม