ซีพียูและ 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 คนอื่นหรือไม่ ลองอ่านหัวข้อสนทนาเต็มได้ที่นี่.