โฮมเพจ » ทำอย่างไร » ซีพียูและ GPU ทำปฏิกิริยากับคอมพิวเตอร์กราฟิกได้อย่างไร?

    ซีพียูและ GPU ทำปฏิกิริยากับคอมพิวเตอร์กราฟิกได้อย่างไร?

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

    ภาพถ่ายโดย sskennel.

    เซสชั่นคำถามและคำตอบในวันนี้มาถึงเราด้วยความอนุเคราะห์จาก SuperUser ซึ่งเป็นแผนกย่อยของ Exchange Exchange ซึ่งเป็นกลุ่มไดรฟ์ชุมชนของเว็บไซต์ถาม - ตอบ.

    คำถาม

    ผู้อ่าน SuperUser Sathya โพสต์คำถาม:

    ที่นี่คุณสามารถดูภาพหน้าจอของโปรแกรม C ++ ขนาดเล็กที่ชื่อว่า Triangle.exe พร้อมกับรูปสามเหลี่ยมหมุนได้ตาม OpenGL API.

    เป็นตัวอย่างที่ธรรมดามาก แต่ฉันคิดว่ามันใช้ได้กับการใช้งานกราฟิกการ์ดอื่น ๆ.

    ฉันแค่อยากรู้อยากเห็นและต้องการทราบกระบวนการทั้งหมดจากการดับเบิลคลิกที่ Triangle.exe ใน Windows XP จนกว่าฉันจะเห็นรูปสามเหลี่ยมหมุนบนหน้าจอ จะเกิดอะไรขึ้นซีพียู (ซึ่งจัดการกับ. exe) และ GPU อย่างไร (ซึ่งในที่สุดก็ส่งสัญญาณสามเหลี่ยมบนหน้าจอ) โต้ตอบ?

    ฉันเดาว่าเกี่ยวข้องกับการแสดงสามเหลี่ยมหมุนนี้ส่วนใหญ่เป็นฮาร์ดแวร์ / ซอฟต์แวร์ต่อไปนี้ในหมู่คนอื่น ๆ :

    ฮาร์ดแวร์

    • HDD
    • หน่วยความจำระบบ (RAM)
    • ซีพียู
    • หน่วยความจำวิดีโอ
    • GPU
    • จอแสดงผล LCD

    ซอฟต์แวร์

    • ระบบปฏิบัติการ
    • DirectX / OpenGL API
    • ไดรเวอร์ Nvidia

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

    ไม่ควรเป็นคำอธิบายที่ซับซ้อนที่ครอบคลุมทุกขั้นตอน (คาดเดาว่าจะเกินขอบเขต) แต่คำอธิบายที่คนไอทีระดับกลางสามารถติดตามได้.

    ฉันค่อนข้างมั่นใจว่าผู้คนมากมายที่จะเรียกตัวเองว่าผู้เชี่ยวชาญด้านไอทีไม่สามารถอธิบายกระบวนการนี้ได้อย่างถูกต้อง.

    คำตอบ

    แม้ว่าสมาชิกชุมชนหลายคนจะตอบคำถามนี้ แต่ Oliver Salzburg ก็ตอบโจทย์นี้ได้อย่างยอดเยี่ยมและไม่เพียง แต่ตอบสนองอย่างละเอียดเท่านั้น.

    ภาพโดย JasonC สามารถใช้ได้เป็นภาพพื้นหลังที่นี่.

    เขาเขียน:

    ฉันตัดสินใจที่จะเขียนเล็กน้อยเกี่ยวกับแง่มุมการเขียนโปรแกรมและองค์ประกอบที่พูดคุยกัน บางทีมันจะส่องแสงในบางพื้นที่.

    การนำเสนอ

    สิ่งที่ต้องมีแม้กระทั่งภาพเดียวนั้นที่คุณโพสต์ไว้ในคำถามของคุณวาดบนหน้าจอ?

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

    แต่, ก่อนที่เราจะวาดอะไรได้เราต้องเริ่มนั่งร้านก่อน เราจะเห็น ทำไม ใหม่กว่า:

    // ล้างหน้าจอและบัฟเฟอร์ความลึก glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // รีเซ็ตเมทริกซ์ Modelview ปัจจุบัน glMatrixMode (GL_MODELVIEW); glLoadIdentity (); // การวาดโดยใช้ Triangles glBegin (GL_TRIANGLES); // Red glColor3f (1.0f, 0.0f, 0.0f); // ด้านบนของสามเหลี่ยม (ด้านหน้า) glVertex3f (0.0f, 1.0f, 0.0f); // Green glColor3f (0.0f, 1.0f, 0.0f); // ด้านซ้ายของรูปสามเหลี่ยม (ด้านหน้า) glVertex3f (-1.0f, -1.0f, 1.0f); // Blue glColor3f (0.0f, 0.0f, 1.0f); // ด้านขวาของรูปสามเหลี่ยม (ด้านหน้า) glVertex3f (1.0f, -1.0f, 1.0f); // วาดเสร็จ glEnd ();

    ดังนั้นสิ่งที่ทำ?

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

    • OpenGL
    • Direct3D
    • CUDA

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

    อินเทอร์เฟซนี้ถูกผูกไว้เพื่อให้คุณแน่ใจ เครื่องมือ. เครื่องมือเหล่านี้มีรูปแบบของ API ที่คุณสามารถโทรได้จากโปรแกรมของคุณ.

    API นั้นคือสิ่งที่เราเห็นว่ามีการใช้งานในตัวอย่างด้านบน ลองมาดูอย่างใกล้ชิด.

    นั่งร้าน

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

    แต่เราจะไม่มองสิ่งนั้น เราจะดูสิ่งที่คุณต้องทำ ทุกเฟรม. ชอบ:

    การล้างหน้าจอ

    ไปป์ไลน์กราฟิกจะไม่ล้างหน้าจอสำหรับคุณทุกเฟรม คุณจะต้องบอกมัน ทำไม? นี่คือเหตุผล:

    หากคุณไม่ได้ล้างหน้าจอคุณเพียงแค่ วาดมากกว่า มันทุกเฟรม นั่นเป็นเหตุผลที่เราเรียก glClear กับGL_COLOR_BUFFER_BIT ชุด อีกเล็กน้อย (GL_DEPTH_BUFFER_BIT) บอกให้ OpenGL ล้างค่า ความลึกกันชน. บัฟเฟอร์นี้ใช้เพื่อกำหนดว่าพิกเซลใดที่อยู่ข้างหน้า (หรือหลัง) พิกเซลอื่น ๆ.

    การแปลง


    แหล่งที่มาของภาพ

    การแปลงเป็นส่วนที่เรารับพิกัดอินพุตทั้งหมด (จุดยอดของสามเหลี่ยม) และใช้เมทริกซ์ ModelView ของเรา นี่คือเมทริกซ์ที่ อธิบาย อย่างไรของเรา แบบ (จุดยอด) ถูกหมุนปรับขนาดและแปล (ย้าย).

    ต่อไปเราใช้เมทริกซ์การฉายของเรา นี่เป็นการย้ายพิกัดทั้งหมดเพื่อให้พวกเขาหันหน้าเข้าหากล้องของเราอย่างถูกต้อง.

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

    เราจะกลับมาเปลี่ยนแปลงอีกในภายหลัง.

    การวาดภาพ

    ในการวาดรูปสามเหลี่ยมเราสามารถบอก OpenGL ให้เริ่มใหม่ รายชื่อสามเหลี่ยม โดยการโทร glBegin กับ GL_TRIANGLES คงที่.
    นอกจากนี้ยังมีรูปแบบอื่น ๆ ที่คุณสามารถวาด เหมือนแถบสามเหลี่ยมหรือพัดลมสามเหลี่ยม สิ่งเหล่านี้เป็นการปรับให้เหมาะสมที่สุดเนื่องจากต้องการการสื่อสารที่น้อยกว่าระหว่าง CPU และ GPU เพื่อดึงสามเหลี่ยมจำนวนเท่ากัน.

    หลังจากนั้นเราสามารถให้รายการชุดของ 3 จุดยอดที่ควรประกอบเป็นสามเหลี่ยมแต่ละอัน สามเหลี่ยมทุกอันใช้ 3 พิกัด (เนื่องจากเราอยู่ในพื้นที่ 3D) นอกจากนี้ฉันยังให้ สี สำหรับแต่ละจุดสุดยอดโดยการโทรglColor3f ก่อน การเรียกร้อง glVertex3f.

    OpenGL จะคำนวณเฉดสีระหว่างจุดยอดทั้ง 3 (มุมทั้ง 3 ของสามเหลี่ยม)อัตโนมัติ. มันจะแก้ไขสีให้ทั่วใบหน้าของรูปหลายเหลี่ยม.

    ปฏิสัมพันธ์

    ตอนนี้เมื่อคุณคลิกที่หน้าต่าง แอปพลิเคชันมีเพียงการจับข้อความหน้าต่างที่ส่งสัญญาณการคลิก จากนั้นคุณสามารถเรียกใช้การกระทำใด ๆ ในโปรแกรมที่คุณต้องการ.

    สิ่งนี้ได้รับ จำนวนมาก ยากขึ้นเมื่อคุณต้องการเริ่มปฏิสัมพันธ์กับฉาก 3 มิติของคุณ.

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

    ดังนั้นคุณจะทำให้มันหมุนได้อย่างไร?

    การแปลง

    ฉันตระหนักถึงการแปลงสองประเภทที่ใช้โดยทั่วไป:

    • การแปลงแบบเมทริกซ์
    • การเปลี่ยนแปลงของกระดูก

    ความแตกต่างก็คือ อัฐิ ส่งผลกระทบเดียว จุด. เมทริกซ์จะมีผลต่อจุดยอดที่วาดในลักษณะเดียวกันเสมอ ลองดูตัวอย่าง.

    ตัวอย่าง

    ก่อนหน้านี้เราโหลดของเรา เมทริกซ์เอกลักษณ์ ก่อนวาดสามเหลี่ยมของเรา เมทริกซ์เอกลักษณ์เป็นสิ่งที่ให้ ไม่มีการเปลี่ยนแปลง เลย ดังนั้นสิ่งที่ฉันวาดได้รับผลกระทบจากมุมมองของฉันเท่านั้น ดังนั้นสามเหลี่ยมจะไม่หมุนเลย.

    ถ้าฉันต้องการหมุนมันตอนนี้ฉันก็สามารถทำคณิตศาสตร์ด้วยตัวเอง (บน CPU) และก็เรียก glVertex3f กับอื่น ๆ พิกัด (ที่หมุน) หรือฉันจะปล่อยให้ GPU ทำทุกอย่างได้ด้วยการโทร glRotatefก่อนที่จะวาด:

    // หมุนสามเหลี่ยมบนแกน Y glRotatef (จำนวน, 0.0f, 1.0f, 0.0f); 

    จำนวน แน่นอนว่าเป็นเพียงค่าคงที่ ถ้าคุณต้องการ มีชีวิต, คุณจะต้องติดตาม จำนวนและเพิ่มมันทุกเฟรม.

    ดังนั้นรอสิ่งที่เกิดขึ้นกับเมทริกซ์พูดคุยก่อนหน้านี้ทั้งหมด?

    ในตัวอย่างง่ายๆนี้เราไม่ต้องสนใจเมทริกซ์ เราเพียงแค่โทร glRotatef และดูแลทุกอย่างสำหรับเรา.

    glRotate สร้างการหมุนของ มุม องศารอบเวกเตอร์ x y z เมทริกซ์ปัจจุบัน (seeglMatrixMode) ถูกคูณด้วยเมทริกซ์การหมุนด้วยผลิตภัณฑ์ที่แทนที่เมทริกซ์ปัจจุบันเนื่องจาก ifglMultMatrix ถูกเรียกด้วยเมทริกซ์ต่อไปนี้เป็นอาร์กิวเมนต์:

    x 2 ⁡ 1 - c + cx ⁢ y ⁡ 1 - c - z ⁢ sx ⁢ z ⁡ 1 - c + y ⁢ s 0 y ⁢ x ⁡ 1 - c + z ⁢ sy 2 ⁡ 1 - c + cy ⁢ z ⁡ 1 - c - x ⁢ s 0 x ⁢ z ⁡ 1 - c - y ⁢ sy ⁢ z ⁡ 1 - c + x ⁢ sz 2 ⁡ 1 - c + c 0 0 0 0 1 1

    ขอบคุณมากสำหรับสิ่งนั้น!

    ข้อสรุป

    สิ่งที่ชัดเจนคือมีการพูดคุยกันมากมาย ไปยัง OpenGL แต่มันไม่ได้บอก เรา สิ่งใด การสื่อสารอยู่ที่ไหน?

    สิ่งเดียวที่ OpenGL บอกเราในตัวอย่างนี้คือ เมื่อเสร็จแล้ว. ทุกการดำเนินการจะใช้เวลาพอสมควร การดำเนินการบางอย่างใช้เวลานานอย่างไม่น่าเชื่อการดำเนินการบางอย่างรวดเร็วอย่างเหลือเชื่อ.

    การส่งจุดสุดยอด สำหรับ GPU จะเร็วมากฉันไม่รู้ด้วยซ้ำว่าจะแสดงออกยังไง การส่งจุดยอดเยี่ยมนับพันจาก CPU ไปยัง GPU ในทุก ๆ เฟรมจะมากที่สุดโดยไม่มีปัญหา.

    การล้างหน้าจอ อาจใช้เวลาหนึ่งมิลลิวินาทีหรือแย่กว่านั้น (โปรดทราบว่าโดยปกติคุณจะมีเวลาประมาณ 16 มิลลิวินาทีในการวาดแต่ละเฟรม) ขึ้นอยู่กับวิวพอร์ตของคุณที่มีขนาดใหญ่ เพื่อล้างมัน OpenGL จะต้องวาดทุกพิกเซลในสีที่คุณต้องการลบนั่นอาจเป็นล้านพิกเซล.

    นอกเหนือจากนั้นเราสามารถถาม OpenGL เกี่ยวกับความสามารถของกราฟิกการ์ดของเราได้ (ความละเอียดสูงสุดการลบรอยหยักสูงสุดความลึกสีสูงสุด ... ).

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

    จากนั้นเราสามารถ "แสดงผล" ผลลัพธ์ของการคำนวณของเรา (ในรูปแบบของสีใหม่) ลงในพื้นผิวใหม่.

    นั่นเป็นวิธีที่คุณสามารถทำให้ GPU ใช้งานได้ในวิธีอื่น ฉันถือว่า CUDA ทำงานคล้ายกับด้านนั้น แต่ฉันไม่เคยมีโอกาสได้ทำงานกับมัน.

    พวกเราสัมผัสวัตถุทั้งหมดเพียงเล็กน้อยเท่านั้น การเขียนโปรแกรมกราฟิก 3D เป็นนรกของสัตว์ร้าย.


    แหล่งที่มาของภาพ


    มีสิ่งที่จะเพิ่มคำอธิบายหรือไม่ ปิดเสียงในความคิดเห็น ต้องการอ่านคำตอบเพิ่มเติมจากผู้ใช้ Stack Exchange คนอื่นหรือไม่ ลองอ่านหัวข้อสนทนาเต็มได้ที่นี่.