ใช้เวลานานแค่ไหนสำหรับ OpenGL ในการอัพเดทหน้าจอจริง?


9

ฉันมีแอปทดสอบ OpenGL แบบง่าย ๆ ใน C ซึ่งดึงดูดสิ่งต่าง ๆ เพื่อตอบสนองต่อการป้อนข้อมูลสำคัญ (Mesa 8.0.4, ลองกับ Mesa-EGL และกับ GLFW, Ubuntu 12.04LTS บนพีซีที่ใช้ NVIDIA GTX650) การดึงค่อนข้างง่าย / เร็ว (หมุนประเภทของสิ่งของ) รหัสการทดสอบของฉันไม่ได้ จำกัด จำนวนการจงใจอย่างรอบคอบ แต่อย่างใดมันมีลักษณะดังนี้:

while (true)
{
    draw();
    swap_buffers();
}

ฉันหมดเวลาอย่างระมัดระวังและฉันพบว่าเวลาจากการโทรครั้งเดียวeglSwapBuffers()(หรือglfwSwapBuffersสิ่งเดียวกัน) ต่อไปคือ ~ 16.6 มิลลิวินาที เวลาจากหลังจากการโทรถึงeglSwapBuffers()ก่อนการโทรครั้งถัดไปจะน้อยกว่านั้นเล็กน้อยถึงแม้ว่าสิ่งที่ถูกวาดจะง่ายมาก เวลาที่การแลกเปลี่ยนบัฟเฟอร์ใช้เวลาน้อยกว่า 1 มิลลิวินาที

อย่างไรก็ตามเวลาจากแอปเปลี่ยนสิ่งที่มันวาดในการตอบสนองต่อการกดปุ่มเพื่อการเปลี่ยนแปลงที่เกิดขึ้นจริงบนหน้าจอคือ> 150ms (ประมาณ 8-9 เฟรมมูลค่า) วัดจากการบันทึกกล้องของหน้าจอและคีย์บอร์ดที่ 60fps

ดังนั้นคำถาม:

  1. การดึงบัฟเฟอร์ระหว่างการโทรเพื่อสลับบัฟเฟอร์อยู่ที่ไหนและแสดงขึ้นบนหน้าจอจริงหรือไม่ ทำไมความล่าช้า? ดูเหมือนว่าแอพจะวาดภาพหลายเฟรมก่อนหน้าจอตลอดเวลา

  2. แอปพลิเคชัน OpenGL สามารถทำอะไรได้บ้างเพื่อทำให้วาดหน้าจอได้ทันที (เช่น: ไม่มีการบัฟเฟอร์เพียงบล็อกจนกว่าการวาดจะเสร็จสมบูรณ์ฉันไม่ต้องการปริมาณงานสูงฉันต้องใช้เวลาในการตอบสนองต่ำ)

  3. แอปพลิเคชันสามารถทำอะไรเพื่อให้การจับสลากทันทีเกิดขึ้นเร็วที่สุดเท่าที่จะทำได้

  4. แอปพลิเคชันจะรู้ได้อย่างไรว่าสิ่งที่อยู่บนหน้าจอจริงในขณะนี้? (หรือนานแค่ไหน / กี่เฟรมที่ล่าช้าบัฟเฟอร์ปัจจุบันคืออะไร?)


คุณสามารถแยกเวลาที่แป้นพิมพ์ใช้เพื่อแจ้งให้แอปพลิเคชันของคุณทราบถึงเวลาที่ใช้ในการแสดงผลจริงหรือไม่?
ThorinII

@ThorinII: จุดยุติธรรม ฉันสามารถตั้งค่าบางสิ่งที่แฮ็คโดยใช้ LED บนพอร์ตขนาน ฯลฯ เพื่อรับการบ่งชี้ว่าเมื่อใดที่แอพได้รับการกดปุ่ม ถึงกระนั้นมันก็แค่ fgetc (stdin) มันจะช้าแค่ไหน? : /
อเล็กซ์ฉัน

ฉันอยู่ภายใต้ความประทับใจที่ใช้ glFlush เพื่อทำให้ล้างคำสั่งทั้งหมดทันที
Programmdude

1
@AlexI ตรวจสอบเรื่องนี้gamedev.stackexchange.com/questions/66543/...อาจช่วยให้คุณ
concept3d

1
@ concept3d: ใช่มันตอบโดยทั่วไปแค่คิดว่าคุณต้องการตัวแทนพิเศษ :) เห็นได้ชัดว่าฉันต้องรอวันที่จะได้รับรางวัลแม้ว่า
อเล็กซ์ฉัน

คำตอบ:


6

ฟังก์ชัน API การวาดใด ๆ ที่เรียกจาก CPU จะถูกส่งไปยังบัฟเฟอร์วงแหวนคำสั่ง GPU ที่จะดำเนินการในภายหลังโดย GPU ซึ่งหมายความว่าฟังก์ชั่น OpenGL ส่วนใหญ่เป็นฟังก์ชั่นที่ไม่ปิดกั้น ดังนั้น CPU และ GPU จะทำงานพร้อมกัน

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

และทราบว่ามีความแตกต่างระหว่างและglFlushglFinish

glFlush: ระบุว่าคำสั่งทั้งหมดที่เคยส่งไปยัง GL ต้องดำเนินการให้เสร็จภายในเวลาที่กำหนด

glFinish: บังคับให้คำสั่ง GL ก่อนหน้าทั้งหมดเสร็จสมบูรณ์ เสร็จสิ้นจะไม่ส่งคืนจนกว่าจะมีผลกระทบทั้งหมดจากคำสั่งที่ออกใช้ก่อนหน้านี้ในสถานะไคลเอนต์และเซิร์ฟเวอร์ของ GL และเฟรมบัฟเฟอร์นั้นรับรู้อย่างสมบูรณ์ "

glXSwapBuffersดำเนินการ glFlush โดยปริยายก่อนที่จะส่งคืน คำสั่ง OpenGL ที่ตามมาอาจถูกเรียกใช้ทันทีหลังจากเรียก glXSwapBuffers แต่จะไม่ดำเนินการจนกว่าการแลกเปลี่ยนบัฟเฟอร์จะเสร็จสมบูรณ์

เวลาเฟรมที่แท้จริงมักจะถูกกำหนดโดยหนึ่งในสอง CPU / GPU ที่ใช้เวลามากขึ้นในการทำงานให้เสร็จสมบูรณ์


สิ่งนี้มีประโยชน์มาก การแก้ไขที่เป็นไปได้บางอย่าง: opengl.org/sdk/docs/man2/xhtml/glXSwapBuffers.xml "glXSwapBuffers ดำเนินการ glFlush โดยปริยายก่อนที่จะส่งคืน" ดูเหมือนว่านี่ไม่ได้ทำ glFinish มากนัก สิ่งที่อยู่ในนั้นเมื่อแลกเปลี่ยนบัฟเฟอร์ส่งกลับ
อเล็กซ์ฉัน

... นอกจากนี้ฉันคิดว่าจุดที่น่าสนใจที่สุดคือแอปพลิเคชันทดสอบที่เรียบง่ายของฉันคือ CPU ไม่ จำกัด GPU - ไม่ได้ทำงานอะไรมากมายที่นี่ อัตราการรีเฟรช ??) และเวลาในการตอบสนองสูง (เนื่องจากบัฟเฟอร์คำสั่งคุณอธิบายส่วนนั้นค่อนข้างดี)
อเล็กซ์ฉัน

@AlexI both low framerate (exactly same as monitor refresh rate??ไม่เว้นแต่คุณจะใช้ VSync อย่างชัดเจน
concept3d

@AlexI ฉันต้องการชี้ให้เห็นว่าเวลาของเฟรมนั้นแตกต่างจาก FPS ใช้เวลาของเฟรมในการทำโปรไฟล์แอปพลิเคชันของคุณเพราะมันเป็นเส้นตรง FPS ในทางตรงกันข้ามเป็นการวัดที่ไม่ดีซึ่งไม่ได้เป็นเชิงเส้น
concept3d

ฉันไม่ได้ใช้ vsync อย่างชัดเจน ฉันไม่ได้ทำอะไรเพื่อเปลี่ยนการตั้งค่า vsync defauls ฉันไม่รู้ด้วยซ้ำว่าจะเปลี่ยนที่ใดใน OpenGL ฉันเพิ่งได้รับ 60fps (ภายในไม่กี่เปอร์เซ็นต์)
อเล็กซ์ฉัน

4

OpenGL ไม่เคยอัปเดตหน้าจอทางเทคนิค

มี API ระบบหน้าต่างที่แยกจาก GL (เช่น GLX, WGL, CGL, EGL) ที่ทำสิ่งนี้ บัฟเฟอร์การแลกเปลี่ยนโดยใช้ API เหล่านี้โดยทั่วไปเรียกใช้โดยนัยglFlush (...)แต่ในการใช้งานบางอย่าง (เช่น GDI rasterizer บน Windows) มันทำงานเต็มรูปแบบglFinish (...):

 

    * ทางด้านซ้ายเป็น ICD (ฮาร์ดแวร์) SwapBuffers (...)ผ่านเส้นทาง ทางด้านขวาเส้นทาง GDI (ซอฟต์แวร์)

หากคุณเปิดใช้งาน VSYNC และ double-buffering ดังนั้นคำสั่งใด ๆ ที่จะแก้ไขบัฟเฟอร์ด้านหลังก่อนที่การแลกเปลี่ยนที่ค้างอยู่จะต้องหยุดจนกว่าการแลกเปลี่ยน มีความลึกที่ จำกัด ในคิวคำสั่งดังนั้นในที่สุดคำสั่งนี้จะทำให้เกิดปัญหาการจราจรติดขัดในไปป์ไลน์ นี่อาจหมายความว่าแทนที่จะบล็อกSwapBuffers (...)แอปพลิเคชันของคุณจริง ๆ แล้วจะปิดกั้นคำสั่ง GL ที่ไม่เกี่ยวข้องจนกว่า VBLANK จะหมุนไปรอบ ๆ สิ่งที่ควรทำคือจำนวนบัฟเฟอร์ด้านหลังในห่วงโซ่การแลกเปลี่ยนของคุณ

ตราบใดที่บัฟเฟอร์ด้านหลังทั้งหมดเต็มเฟรมที่เสร็จแล้วและยังไม่ได้ย้ายไปข้างหน้าบัฟเฟอร์แลกเปลี่ยนจะทำให้เกิดการบล็อกโดยปริยาย น่าเศร้าที่ไม่มีวิธีใดที่จะควบคุมจำนวนบัฟเฟอร์สำรองที่ใช้โดย API ระบบหน้าต่าง GL ส่วนใหญ่อย่างชัดเจน (นอกเหนือจาก0บัฟเฟอร์เดียวหรือ1บัฟเฟอร์สองครั้ง) คนขับมีอิสระในการใช้บัฟเฟอร์สำรอง2 อันหากต้องการ (การบัฟเฟอร์สามเท่า) แต่คุณไม่สามารถร้องขอสิ่งนี้ได้ในระดับแอปพลิเคชันโดยใช้อย่าง GLX หรือ WGL


Andon: ข้อมูลดีขอบคุณ ฉันคิดว่าสิ่งที่ฉันเห็นคือการบัฟเฟอร์สองส่วน แต่: "พยายามแก้ไขบัฟเฟอร์ด้านหลังก่อนที่การสลับจะเกิดขึ้นต้องปิดกั้น" - ทำไม ดูเหมือนทุกอย่างจะได้รับการส่งไปยังบัฟเฟอร์คำสั่งรวมทั้งการแลกเปลี่ยน :)
อเล็กซ์ผม

"ควบคุมจำนวนบัฟเฟอร์สำรองอย่างชัดเจนที่ใช้โดย API ระบบหน้าต่าง GL ส่วนใหญ่ (นอกเหนือจาก 0 บัฟเฟอร์เดียวหรือ 1 บัฟเฟอร์สองครั้ง)" - วิธีควบคุมบัฟเฟอร์เดี่ยว / คู่หนึ่งรายการอย่างไร
อเล็กซ์ฉัน

@AlexI: ฉันชี้แจงภาษาด้วยความเคารพว่าทำไมคำสั่งสามารถนำไปสู่การปิดกั้น ใน API อื่น ๆ มีแนวคิดที่เรียกว่า render-ahead ซึ่งเป็นความลึกของคิวคำสั่งอย่างมีประสิทธิภาพ สำหรับการควบคุมบัฟเฟอร์เดี่ยว / คู่ที่ควบคุมโดยรูปแบบพิกเซลที่คุณเลือกเมื่อคุณสร้างบริบทการแสดงผลของคุณ ใน WGL คุณสามารถเลือกแบบเดี่ยวหรือสองครั้ง แต่หากคุณเลือกสองครั้งที่บัฟเฟอร์ไดรเวอร์อาจสร้างบัฟเฟอร์ด้านหลัง 2 อัน (ซึ่งการบัฟเฟอร์สองครั้งจะกลายเป็นบัฟเฟอร์สามเท่า) หากผู้ใช้ตั้งค่าไดรเวอร์ให้ทำเช่นนี้
Andon M. Coleman

คุณไม่ต้องการแสดงเฟรมมากเกินไปเพราะขณะนี้จะลดการบล็อก แต่ยังเพิ่มความล่าช้า วิธีที่ดีที่สุดในการลดความหน่วงแฝงคือการเรียกใช้glFinish (...)ทันทีหลังจากการแลกเปลี่ยนบัฟเฟอร์ นี่จะเป็นการล้างคิวคำสั่ง แต่ก็หมายความว่า GPU และ CPU จะได้รับการซิงโครไนซ์ (ซึ่งไม่ดีถ้าคุณต้องการให้ GPU ทำงานตลอดเวลา)
Andon M. Coleman

1

ฉันถือว่าคุณคุ้นเคยกับการทดสอบนี้หรือไม่

โดยพื้นฐานแล้ว John Carmack กำลังทำสิ่งที่คล้ายกันโดยบันทึกหน้าจอและพิกเซลเวลาที่ส่งไปยังหน้าจอ เขาพบว่าเวลาแฝงจำนวนมากมาจากหน้าจอ ปัจจัยอื่น ๆ ได้แก่ ความล่าช้าในการป้อนข้อมูลจากแป้นพิมพ์ไดรเวอร์วิดีโอและหรือการดำเนินการของโปรแกรมเอง

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