ข้อมูลเกี่ยวกับการเรนเดอร์แบตช์กราฟิกประสิทธิภาพ ฯลฯ + XNA


12

ฉันรู้ว่าชื่อค่อนข้างคลุมเครือ แต่ก็ยากที่จะอธิบายสิ่งที่ฉันกำลังมองหา แต่ที่นี่ไป

เมื่อพูดถึงการเรนเดอร์ CPU ประสิทธิภาพส่วนใหญ่ง่ายต่อการประมาณและตรงไปตรงมา แต่เมื่อพูดถึง GPU เนื่องจากขาดข้อมูลพื้นฐานทางเทคนิค ฉันใช้ XNA ดังนั้นมันคงจะดีถ้าทฤษฎีนั้นเกี่ยวข้องกับเรื่องนั้น

ดังนั้นสิ่งที่ฉันอยากรู้จริง ๆ คืออะไรจะเกิดขึ้นเมื่อใดและที่ไหน (CPU / GPU) เมื่อคุณทำการวาดเฉพาะ ชุดคืออะไร? เอฟเฟกต์การคาดการณ์และอื่น ๆ มีอิทธิพลอย่างไร ข้อมูลยังคงอยู่ในกราฟิกการ์ดหรือถูกถ่ายโอนในทุกขั้นตอนหรือไม่ เมื่อมีการพูดถึงแบนด์วิดธ์คุณกำลังพูดถึงแบนด์วิดธ์ภายในการ์ดกราฟิกหรือไปป์ไลน์จาก CPU ไปยัง GPU หรือไม่?
หมายเหตุ:ฉันไม่ได้กำลังมองหาข้อมูลเกี่ยวกับวิธีการวาดเกิดขึ้นนั่นคือธุรกิจของ GPU ฉันสนใจค่าใช้จ่ายทั้งหมดที่อยู่ก่อนหน้านั้น

ฉันต้องการที่จะเข้าใจสิ่งที่เกิดขึ้นเมื่อฉันทำการกระทำ X เพื่อปรับสถาปัตยกรรมและการปฏิบัติของฉันให้เป็นแบบนั้น

บทความใด ๆ (อาจมีตัวอย่างโค้ด) ข้อมูลลิงค์บทช่วยสอนที่ให้ข้อมูลเชิงลึกมากขึ้นเกี่ยวกับวิธีการเขียนเกมที่ดีขึ้นได้รับการชื่นชมอย่างมาก ขอบคุณ :)


2
แม้ว่านี่จะเป็น XNA เดิม แต่ฉันได้เพิ่มแท็ก DirectX เนื่องจากเป็นเทคโนโลยีพื้นฐาน - อาจช่วยให้คุณได้รับคำตอบที่ดีขึ้น ลองดูคำตอบนี้ซึ่งอาจทำให้คุณเป็นจุดเริ่มต้นที่ดี
Andrew Russell

@AndrewRussell ขอบคุณมาก :) ฉันได้อ่านบทความต่าง ๆ ในหัวข้อรวมถึงบทความนั้นแล้ว แต่มันไม่ได้ครอบคลุมทุกสิ่งที่ฉันอยากรู้
Aidiakapi

คำตอบ:


20

ฉันชอบคิดถึงประสิทธิภาพในแง่ของ " ขีด จำกัด " มันเป็นวิธีที่สะดวกในการกำหนดแนวความคิดที่ค่อนข้างซับซ้อนเชื่อมต่อระบบ เมื่อคุณมีปัญหาด้านประสิทธิภาพคุณถามคำถาม: "ฉันกำลังกดปุ่มขีด จำกัด อะไร" (หรือ: "ฉันมี CPU / GPU ผูกไว้หรือไม่")

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

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

(ในขณะที่ฉันกำลังทำภาพรวมกว้าง ๆ เกี่ยวกับประสิทธิภาพของ XNA ฉันจะชี้ให้เห็นว่าการจัดสรรประเภทการอ้างอิง ( classไม่ใช่struct) ในขณะที่ราคาถูกปกติสามารถเรียกใช้ตัวเก็บรวบรวมขยะซึ่งจะเผาวงจรจำนวนมากโดยเฉพาะใน Xbox 360 . ดูที่นี่สำหรับรายละเอียด)

ทางด้านGPUฉันจะเริ่มโดยชี้ไปที่โพสต์บล็อกที่ยอดเยี่ยมซึ่งมีรายละเอียดมากมาย หากคุณต้องการรายละเอียดระดับบ้าบนไปป์ไลน์อ่านชุดของบล็อกโพสต์นี้ ( นี่คือวิธีที่ง่ายกว่า )

หากต้องการวางไว้ที่นี่เพียงบางส่วนของขนาดใหญ่คือ: " ขีด จำกัด การเติม " (จำนวนพิกเซลที่คุณสามารถเขียนลงใน backbuffer - บ่อยแค่ไหนที่คุณสามารถถอนเงินเกินจำนวนได้) " ขีด จำกัด shader " (ซับซ้อน shader ของคุณและ คุณสามารถส่งผ่านข้อมูลได้มากเพียงใด, " ขีด จำกัด การดึงข้อมูลพื้นผิว / พื้นผิวแบนด์วิดท์ " (จำนวนข้อมูลพื้นผิวที่คุณสามารถเข้าถึงได้)

และตอนนี้เรามาถึงตัวใหญ่ - ซึ่งเป็นสิ่งที่คุณถามจริง ๆ - ที่ CPU และ GPU ต้องโต้ตอบ (ผ่าน API และไดร์เวอร์ต่างๆ) มี " ขีด จำกัด แบตช์ " และ " แบนด์วิดธ์ " อย่างหลวม ๆ (โปรดทราบว่าส่วนหนึ่งของซีรีส์ที่ฉันพูดถึงไปก่อนหน้านี้มีรายละเอียดมากมาย)

แต่โดยทั่วไปชุด ( ตามที่คุณทราบแล้ว ) จะเกิดขึ้นทุกครั้งที่คุณเรียกใช้GraphicsDevice.Draw*ฟังก์ชันใดฟังก์ชันหนึ่ง (หรือส่วนหนึ่งของ XNA เช่นSpriteBatchนี้ทำเพื่อคุณ) ในขณะที่คุณไม่ต้องสงสัยเลยว่าคุณได้อ่านแล้วคุณจะได้รับไม่กี่พัน*ต่อเฟรม นี่เป็นขีด จำกัด ของ CPU - ดังนั้นจึงแข่งขันกับการใช้งาน CPU อื่น ๆ ของคุณ โดยพื้นฐานแล้วคนขับบรรจุหีบห่อทุกอย่างเกี่ยวกับสิ่งที่คุณบอกให้วาดและส่งไปยัง GPU

แล้วมีแบนด์วิดธ์ของ GPU นี่คือข้อมูลดิบที่คุณสามารถถ่ายโอนได้ที่นั่น ซึ่งรวมถึงข้อมูลสถานะทั้งหมดที่ไปพร้อมกับแบทช์ - ทุกอย่างจากการตั้งค่าสถานะการแสดงผลและค่าคงที่ / พารามิเตอร์ shader (ซึ่งรวมถึงสิ่งต่าง ๆ เช่นเมทริกซ์โลก / มุมมอง / โครงการ) ไปจนถึงจุดยอดเมื่อใช้DrawUser*ฟังก์ชัน นอกจากนี้ยังรวมถึงการโทรไปยังSetDataและGetDataบนพื้นผิวบัฟเฟอร์จุดสุดยอด ฯลฯ

ณ จุดนี้ฉันควรจะพูดว่าสิ่งที่คุณสามารถโทรหาSetData(พื้นผิว, จุดสุดยอดและดัชนีบัฟเฟอร์, ฯลฯ ) รวมทั้งEffects - ยังคงอยู่ในหน่วยความจำ GPU มันไม่ได้ถูกส่งไปยัง GPU อีกครั้งอย่างต่อเนื่อง คำสั่ง draw ที่อ้างอิงว่าข้อมูลนั้นจะถูกส่งไปพร้อมกับตัวชี้ไปยังข้อมูลนั้น

(เช่น: คุณสามารถส่งคำสั่งวาดจากเธรดหลักเท่านั้น แต่คุณสามารถทำได้SetDataบนเธรดใด ๆ )

XNA มีความซับซ้อนค่อนข้างสิ่งที่มีการแสดงผลการเรียนของรัฐ ( BlendState, DepthStencilStateฯลฯ ) ข้อมูลสถานะนี้จะถูกส่งต่อการเรียกการดึง (ในแต่ละชุด) ฉันไม่แน่ใจ 100% แต่ฉันรู้สึกว่ามันถูกส่งไปอย่างเกียจคร้าน (มันแค่ส่งการเปลี่ยนแปลงที่ระบุว่า) ไม่ว่าจะด้วยวิธีใดการเปลี่ยนแปลงสถานะจะมีราคาถูกจนถึงจุดว่างซึ่งสัมพันธ์กับต้นทุนของชุดการผลิต

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

ทั้งสองกรณีที่ต้องระวังคือการโทรหาGetDataสิ่งที่มีพลวัต - โดยเฉพาะอย่างยิ่งในสิ่งRenderTarget2Dที่ GPU อาจจะเขียนถึง สิ่งนี้แย่มากสำหรับประสิทธิภาพ - อย่าทำ

อีกกรณีหนึ่งกำลังเรียกSetDataใช้บัฟเฟอร์จุดสุดยอด / ดัชนี หากคุณต้องการทำสิ่งนี้บ่อยให้ใช้DynamicVertexBuffer(ด้วยDynamicIndexBuffer) สิ่งเหล่านี้ทำให้ GPU รู้ว่าพวกมันจะเปลี่ยนบ่อยๆและทำเวทย์มนตร์บัฟเฟอร์ภายในเพื่อหลีกเลี่ยงการสะบัดท่อ

(โปรดทราบว่าบัฟเฟอร์แบบไดนามิกเร็วกว่าDrawUser*วิธีการ - แต่ต้องจัดสรรล่วงหน้าตามขนาดสูงสุดที่ต้องการ)

... และนั่นคือทุกสิ่งที่ฉันรู้เกี่ยวกับประสิทธิภาพของ XNA :)


ขอบคุณมาก! นี่คือว่าสิ่งที่ผมต้องการและหวังสำหรับ :)
Aidiakapi

1
ไม่กี่ร้อยแบทช์ต่อเฟรมฟังดูเป็นแง่ร้ายมากเกินไป กฎง่ายๆที่ฉันเคยได้ยินคือ 2K ถึง 3K สำหรับแต่ละเฟรม บางเกมเป็นที่รู้จักกันดีว่าสามารถเพิ่มได้ถึง 10K บนเครื่อง PC แต่ฉันคิดว่าต้องใช้ความระมัดระวังเป็นอย่างมาก
นาธานรีด

ค่อนข้างถูก ตัวเลข "สองสามร้อย" มาจากกระดาษ "batch batch batch" - ซึ่งแสดงรายการ "25k batches / s @ 100% ของ CPU 1GHz" แต่ตอนนี้กระดาษแผ่นนั้นมีอายุกว่าทศวรรษแล้วและไดรเวอร์และซีพียูก็ดีขึ้นอย่างมากตั้งแต่นั้นมา ฉันจะอัปเดตนี้ (และคนอื่น ๆ ) เพื่ออ่าน "ไม่กี่พัน"
Andrew Russell
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.