ฉันจะโหลดทรัพยากรกราฟิกแบบอะซิงโครนัสได้อย่างไร


9

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

โดยหลักการแล้วฉันสามารถโหลดไฟล์จริงในเธรดแยกต่างหากหรือใช้ async I / O แต่ด้วยวัตถุกราฟิกฉันจะต้องอัปโหลดไปยัง GPU และสามารถทำได้ (ปกติ) บนเธรดหลักเท่านั้น

ฉันสามารถเปลี่ยนลูปเกมของฉันให้มีลักษณะดังนี้:

while true do
    update()
    for each pending resource do
        load resource to gpu
    end
    draw()
end

ในขณะที่มีทรัพยากรโหลดด้ายแยกจากดิสก์เพื่อแรม

อย่างไรก็ตามหากมีทรัพยากรจำนวนมากที่ต้องโหลดสิ่งนี้อาจทำให้ฉันพลาดกำหนดเส้นตายของเฟรม ดังนั้นฉันสามารถเปลี่ยนวงนี้:

while true do
    update()
    if there are pending resources then
        load one resource to gpu
        remove that resource from the pending list
    end
    draw()
end

โหลดทรัพยากรเดียวต่อเฟรมอย่างมีประสิทธิภาพ อย่างไรก็ตามหากมีทรัพยากรขนาดเล็กจำนวนมากที่ต้องโหลดการโหลดทั้งหมดจะใช้เวลาหลายเฟรมและจะมีเวลาที่สูญเปล่า

อย่างดีที่สุดฉันต้องการกำหนดเวลาการโหลดในลักษณะต่อไปนี้:

while true do
    time_start = get_time()
    update()
    while there are pending resources then
        current_time = get_time()
        if (current_time - time_start) + time_to_load(resource) >= 1/60 then
            break
        load one resource to gpu
        remove that resource from the pending list
    end
    draw()
end

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

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

คำตอบ:


7

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

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

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

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

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


นั่นเป็นคำอธิบายที่ดีทีเดียว สิ่งต่าง ๆ มากมายที่ฉันไม่รู้ แต่ทำให้รู้สึกมาก แทนที่จะทดสอบด้วยความเครียดฉันจะวัดค่าโสหุ้ยการสร้างพื้นผิวในรันไทม์เริ่มต้นเบา ๆ และเร่งขึ้นเพื่อพูด 80% ของเวลาดำเนินการที่มีอยู่เพื่อออกจากห้องสำหรับผู้ผิดปกติ
Panda Pajama

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

นอกจากนี้ยังมีการนำเสนอ NVIDIA เกี่ยวกับการโอนพื้นผิวแบบอะซิงโครนัส สิ่งสำคัญที่มันกำลังขับรถกลับบ้านเท่าที่ฉันอ่านคือการใช้พื้นผิวเร็วเกินไปหลังจากที่คุณอัปโหลดมันกำลังจะหยุดทำงาน developer.download.nvidia.com/GTC/PDF/GTC2012/PresentationPDF/ …
John Calsbeek

ฉันไม่ใช่คนขับ dev jockey แต่มันเป็นเรื่องธรรมดาเหรอ? มันไม่มีเหตุผลที่จะนำไดรเวอร์มาใช้ในทางนั้นเพราะการใช้พื้นผิวครั้งแรกมีแนวโน้มที่จะเกิดขึ้นได้ยาก (เช่นในตอนต้นของแต่ละระดับ) แทนที่จะเว้นระยะตามเส้นเวลา
แพนด้า Pajama

@PandaPajama เป็นเรื่องธรรมดาที่แอปพลิเคชั่นจะสร้างพื้นผิวมากกว่า VRAM ที่มีอยู่และเพื่อสร้างพื้นผิวและไม่เคยใช้มันเลย กรณีทั่วไปคือ "สร้างพื้นผิวแล้ววาดฉากที่ใช้พวกเขาทันที" ซึ่งในกรณีที่การขี้เกียจช่วยคนขับรถเพราะมันสามารถคิดได้ว่าพื้นผิวใดที่ใช้จริงและเฟรมแรกนั้นยังคงผูกปมอยู่ดี . แต่ฉันก็ไม่ได้เป็นคนขับ dev เอามันไปด้วยเม็ดเกลือ (และทดสอบ!)
John Calsbeek
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.