หน่วยประมวลผลกลาง (CPU) และหน่วยประมวลผลกราฟิก (GPU) ของคอมพิวเตอร์ของคุณโต้ตอบทุกครั้งที่คุณใช้คอมพิวเตอร์เพื่อมอบอินเทอร์เฟซภาพที่คมชัดและตอบสนอง อ่านเพื่อทำความเข้าใจวิธีการทำงานร่วมกันให้ดีขึ้น
ภาพโดย sskennel .
เซสชันคำถามและคำตอบของวันนี้มาถึงเราโดยได้รับความอนุเคราะห์จาก SuperUser ซึ่งเป็นแผนกย่อยของ Stack Exchange ซึ่งเป็นการรวมกลุ่มเว็บไซต์ถาม & ตอบในชุมชน
คำถาม
ผู้อ่าน SuperUser Sathya ตั้งคำถามว่า:
ที่นี่คุณสามารถดูภาพหน้าจอของโปรแกรม C ++ ขนาดเล็กที่เรียกว่า Triangle.exe พร้อมกับสามเหลี่ยมหมุนตาม OpenGL API
เป็นตัวอย่างพื้นฐานที่ยอมรับได้ แต่ฉันคิดว่าใช้ได้กับการใช้งานกราฟิกการ์ดอื่น ๆ
ฉันแค่อยากรู้และอยากรู้กระบวนการทั้งหมดจากการดับเบิลคลิกที่ Triangle.exe ใน Windows XP จนกระทั่งฉันเห็นสามเหลี่ยมหมุนบนจอภาพ จะเกิดอะไรขึ้น CPU (ซึ่งจัดการกับ. exe ก่อน) และ GPU (ซึ่งสุดท้ายแสดงผลสามเหลี่ยมบนหน้าจอ) จะโต้ตอบได้อย่างไร?
ฉันเดาว่าการแสดงสามเหลี่ยมหมุนนี้ส่วนใหญ่เป็นฮาร์ดแวร์ / ซอฟต์แวร์ต่อไปนี้:
ฮาร์ดแวร์
- HDD
- หน่วยความจำระบบ (RAM)
- ซีพียู
- หน่วยความจำวิดีโอ
- GPU
- จอ LCD
ซอฟต์แวร์
- ระบบปฏิบัติการ
- DirectX / OpenGL API
- ไดรเวอร์ Nvidia
ใครช่วยอธิบายกระบวนการนี้ได้บ้างอาจจะมีผังงานประกอบเพื่อเป็นภาพประกอบ
ไม่ควรเป็นคำอธิบายที่ซับซ้อนครอบคลุมทุกขั้นตอน (เดาว่าเกินขอบเขต) แต่คำอธิบายที่คนไอทีระดับกลางสามารถปฏิบัติตามได้
ฉันค่อนข้างมั่นใจว่ามีคนจำนวนมากที่เรียกตัวเองว่าผู้เชี่ยวชาญด้านไอทีไม่สามารถอธิบายกระบวนการนี้ได้อย่างถูกต้อง
คำตอบ
แม้ว่าสมาชิกในชุมชนหลายคนจะตอบคำถาม แต่ Oliver Salzburg ก็เดินหน้าไปได้ไกลกว่าเดิมและตอบคำถามนี้ไม่เพียง แต่ตอบสนองอย่างละเอียดเท่านั้น แต่ยังมีกราฟิกประกอบที่ยอดเยี่ยมอีกด้วย
ภาพโดย JasonC มีให้เป็นภาพพื้นหลังที่นี่ .
เขาเขียน:
ฉันตัดสินใจที่จะเขียนเกี่ยวกับแง่มุมของการเขียนโปรแกรมและวิธีที่ส่วนประกอบต่างๆพูดคุยกัน บางทีมันอาจจะให้ความกระจ่างในบางพื้นที่
การนำเสนอ
ต้องใช้อะไรบ้างถึงจะมีภาพเดียวที่คุณโพสต์ในคำถามของคุณวาดบนหน้าจอ?
มีหลายวิธีในการวาดสามเหลี่ยมบนหน้าจอ เพื่อความง่ายสมมติว่าไม่มีการใช้บัฟเฟอร์จุดยอด (ก บัฟเฟอร์จุดยอด เป็นพื้นที่ของหน่วยความจำที่คุณเก็บพิกัด) สมมติว่าโปรแกรมเพียงแค่บอกไปป์ไลน์การประมวลผลกราฟิกเกี่ยวกับทุกจุดยอดเดียว (จุดยอดเป็นเพียงพิกัดในอวกาศ) ในแถว
แต่ ก่อนที่เราจะวาดอะไรได้เราต้องวิ่งนั่งร้านก่อน เราจะเห็น ทำไม ภายหลัง:
// ล้างหน้าจอและบัฟเฟอร์ความลึก glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // รีเซ็ตเมทริกซ์ Modelview ปัจจุบัน glMatrixMode (GL_MODELVIEW); glLoadIdentity (); // การวาดโดยใช้สามเหลี่ยม glBegin (GL_TRIANGLES); // สีแดง glColor3f (1.0f, 0.0f, 0.0f); // ด้านบนของสามเหลี่ยม (ด้านหน้า) glVertex3f (0.0f, 1.0f, 0.0f); // สีเขียว glColor3f (0.0f, 1.0f, 0.0f); // ซ้ายของสามเหลี่ยม (ด้านหน้า) glVertex3f (-1.0f, -1.0f, 1.0f); // สีน้ำเงิน glColor3f (0.0f, 0.0f, 1.0f); // ด้านขวาของสามเหลี่ยม (ด้านหน้า) glVertex3f (1.0f, -1.0f, 1.0f); // วาดเสร็จแล้ว glEnd ();
แล้วมันทำอะไร?
เมื่อคุณเขียนโปรแกรมที่ต้องการใช้การ์ดแสดงผลคุณมักจะเลือกอินเทอร์เฟซบางประเภทให้กับไดรเวอร์ อินเทอร์เฟซที่รู้จักกันดีสำหรับไดรเวอร์ ได้แก่ :
- OpenGL
- Direct3D
- มิราเคิล
สำหรับตัวอย่างนี้เราจะใช้ OpenGL ตอนนี้ อินเทอร์เฟซกับไดรเวอร์ คือสิ่งที่ให้เครื่องมือทั้งหมดที่คุณต้องการในการสร้างโปรแกรมของคุณ การพูดคุย ไปยังการ์ดแสดงผล (หรือไดรเวอร์ซึ่งจากนั้น การพูดคุย ไปยังการ์ด)
อินเทอร์เฟซนี้มีไว้เพื่อให้คุณแน่นอน เครื่องมือ . เครื่องมือเหล่านี้มีรูปร่างเป็นไฟล์ ไฟ ซึ่งคุณสามารถโทรได้จากโปรแกรมของคุณ
API นั้นคือสิ่งที่เราเห็นในตัวอย่างด้านบน มาดูรายละเอียดกันดีกว่า
นั่งร้าน
ก่อนที่คุณจะวาดภาพจริงๆได้คุณจะต้องทำไฟล์ ติดตั้ง . คุณต้องกำหนดวิวพอร์ตของคุณ (พื้นที่ที่จะแสดงผลจริง) มุมมองของคุณ (ไฟล์ กล้อง ในโลกของคุณ) คุณจะใช้การลบรอยหยักแบบใด (เพื่อทำให้ขอบสามเหลี่ยมของคุณเรียบขึ้น) ...
แต่เราจะไม่พิจารณาสิ่งนั้น เราจะมาดูสิ่งที่คุณจะต้องทำ ทุกเฟรม . ชอบ:
การล้างหน้าจอ
ไปป์ไลน์กราฟิกจะไม่ล้างหน้าจอให้คุณทุกเฟรม คุณจะต้องบอกมัน ทำไม? นี่คือเหตุผล:
หากคุณไม่ล้างหน้าจอคุณก็ทำได้ง่ายๆ
วาดมากกว่า
ทุกเฟรม นั่นคือเหตุผลที่เราโทรหา
glClear
กับ
GL_COLOR_BUFFER_BIT
ชุด. บิตอื่น ๆ (
GL_DEPTH_BUFFER_BIT
) บอกให้ OpenGL ล้างไฟล์
ความลึก
กันชน. บัฟเฟอร์นี้ใช้เพื่อกำหนดว่าพิกเซลใดอยู่ด้านหน้า (หรือด้านหลัง) พิกเซลอื่น ๆ
การเปลี่ยนแปลง
การแปลงเป็นส่วนที่เราใช้พิกัดอินพุตทั้งหมด (จุดยอดของสามเหลี่ยมของเรา) และใช้เมทริกซ์ ModelView ของเรา นี่คือเมทริกซ์ที่ อธิบาย ของเราอย่างไร แบบ (จุดยอด) ถูกหมุนปรับขนาดและแปล (ย้าย)
ต่อไปเราจะใช้เมทริกซ์การฉายของเรา สิ่งนี้จะย้ายพิกัดทั้งหมดเพื่อให้หันเข้าหากล้องของเราอย่างถูกต้อง
ตอนนี้เราแปลงร่างอีกครั้งด้วยเมทริกซ์วิวพอร์ตของเรา เราทำสิ่งนี้เพื่อปรับขนาดของเรา แบบ ขนาดของจอภาพของเรา ตอนนี้เรามีชุดจุดยอดที่พร้อมแสดงผลแล้ว!
เราจะกลับมาเปลี่ยนแปลงในภายหลัง
การวาดภาพ
ในการวาดสามเหลี่ยมเราสามารถบอกให้ OpenGL เริ่มต้นใหม่ได้
รายการสามเหลี่ยม
โทร
glBegin
กับ
GL_TRIANGLES
คงที่
นอกจากนี้ยังมีรูปแบบอื่น ๆ ที่คุณสามารถวาดได้ ชอบ
แถบสามเหลี่ยม
หรือก
พัดลมสามเหลี่ยม
. สิ่งเหล่านี้เป็นการเพิ่มประสิทธิภาพเป็นหลักเนื่องจากต้องการการสื่อสารระหว่าง CPU และ GPU น้อยลงเพื่อวาดสามเหลี่ยมจำนวนเท่ากัน
หลังจากนั้นเราสามารถจัดเตรียมรายการของจุดยอด 3 จุดซึ่งควรประกอบเป็นสามเหลี่ยมแต่ละอัน ทุกสามเหลี่ยมใช้พิกัด 3 พิกัด (เหมือนที่เราอยู่ในอวกาศ 3 มิติ) นอกจากนี้ฉันยังมีไฟล์
สี
สำหรับแต่ละจุดยอดโดยการโทร
glColor3f
ก่อน
โทร
glVertex3f
.
เฉดสีระหว่างจุดยอด 3 จุด (มุมทั้ง 3 ของสามเหลี่ยม) คำนวณโดย OpenGL โดยอัตโนมัติ . มันจะสอดแทรกสีให้ทั่วทั้งใบหน้าของรูปหลายเหลี่ยม
ปฏิสัมพันธ์
ตอนนี้เมื่อคุณคลิกหน้าต่าง แอปพลิเคชันจะต้องจับไฟล์ ข้อความหน้าต่าง ที่ส่งสัญญาณการคลิก จากนั้นคุณสามารถดำเนินการใด ๆ ในโปรแกรมของคุณที่คุณต้องการ
สิ่งนี้จะได้รับ มาก ยากขึ้นเมื่อคุณต้องการเริ่มโต้ตอบกับฉาก 3 มิติของคุณ
ก่อนอื่นคุณต้องทราบอย่างชัดเจนว่าผู้ใช้คลิกหน้าต่างใดพิกเซลใด จากนั้นรับไฟล์ มุมมอง คุณสามารถคำนวณทิศทางของรังสีได้จากจุดที่คลิกเมาส์เข้าไปในฉากของคุณ จากนั้นคุณสามารถคำนวณว่ามีวัตถุใดในฉากของคุณหรือไม่ ตัดกัน ด้วยรังสีนั้น . ตอนนี้คุณทราบแล้วว่าผู้ใช้คลิกวัตถุหรือไม่
แล้วคุณจะทำให้มันหมุนได้อย่างไร?
การเปลี่ยนแปลง
ฉันตระหนักถึงการเปลี่ยนแปลงสองประเภทที่ใช้โดยทั่วไป:
- การแปลงตามเมทริกซ์
- การเปลี่ยนแปลงตามกระดูก
ความแตกต่างก็คือ กระดูก มีผลต่อความโสด จุดยอด . เมทริกซ์จะส่งผลต่อจุดยอดที่วาดในลักษณะเดียวกันเสมอ ลองดูตัวอย่าง
ตัวอย่าง
ก่อนหน้านี้เราโหลดไฟล์ เมทริกซ์เอกลักษณ์ ก่อนวาดสามเหลี่ยมของเรา เมทริกซ์เอกลักษณ์เป็นเมทริกซ์ที่ให้ ไม่มีการเปลี่ยนแปลง เลย. ดังนั้นสิ่งที่ฉันวาดจะได้รับผลกระทบจากมุมมองของฉันเท่านั้น ดังนั้นสามเหลี่ยมจะไม่หมุนเลย
ถ้าฉันต้องการหมุนตอนนี้ฉันสามารถคำนวณด้วยตัวเอง (บน CPU) และเรียกง่ายๆ
glVertex3f
ด้วย
อื่น ๆ
พิกัด (ที่หมุน) หรือฉันสามารถปล่อยให้ GPU ทำงานทั้งหมดได้โดยการโทร
glRotatef
ก่อนวาด:
// หมุนสามเหลี่ยมบนแกน Y glRotatef (จำนวน 0.0f, 1.0f, 0.0f);
จำนวน
แน่นอนว่าเป็นเพียงค่าคงที่ ถ้าคุณต้องการ
เคลื่อนไหว
คุณจะต้องติดตาม
จำนวน
และเพิ่มทุกเฟรม
เดี๋ยวก่อนเกิดอะไรขึ้นกับเมทริกซ์ทั้งหมดก่อนหน้านี้?
ในตัวอย่างง่ายๆนี้เราไม่จำเป็นต้องสนใจเรื่องเมทริกซ์ เราก็โทร
glRotatef
และดูแลทุกอย่างให้เรา
glRotateก่อให้เกิดการหมุนของมุมองศารอบเวกเตอร์ x y z เมทริกซ์ปัจจุบัน (ดู glMatrixMode ) คูณด้วยเมทริกซ์การหมุนโดยให้ผลิตภัณฑ์แทนที่เมทริกซ์ปัจจุบันราวกับว่า glMultMatrix ถูกเรียกด้วยเมทริกซ์ต่อไปนี้เป็นอาร์กิวเมนต์: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
ขอบคุณสำหรับสิ่งนั้น!
สรุป
สิ่งที่เห็นได้ชัดคือมีการพูดคุยมากมาย ถึง OpenGL แต่มันไม่ได้บอก เรา อะไรก็ได้ การสื่อสารอยู่ที่ไหน?
สิ่งเดียวที่ OpenGL บอกเราในตัวอย่างนี้คือ เมื่อเสร็จสิ้น . การดำเนินการทุกครั้งจะใช้เวลาช่วงหนึ่ง การดำเนินการบางอย่างใช้เวลานานอย่างไม่น่าเชื่อบางอย่างก็รวดเร็วอย่างไม่น่าเชื่อ
ส่งจุดยอด ถึง GPU จะเร็วมากฉันไม่รู้ด้วยซ้ำว่าจะแสดงออกอย่างไร การส่งจุดยอดหลายพันจุดจาก CPU ไปยัง GPU ในทุกๆเฟรมนั้นเป็นไปได้มากว่าไม่มีปัญหาเลย
การล้างหน้าจอ อาจใช้เวลาหนึ่งมิลลิวินาทีหรือแย่กว่านั้น (โปรดทราบว่าโดยปกติคุณมีเวลาเพียง 16 มิลลิวินาทีในการวาดแต่ละเฟรม) ขึ้นอยู่กับว่าวิวพอร์ตของคุณมีขนาดใหญ่เพียงใด เพื่อให้ชัดเจน OpenGL จะต้องวาดทุก ๆ พิกเซลในสีที่คุณต้องการล้างซึ่งอาจเป็นล้านพิกเซล
นอกเหนือจากนั้นเราสามารถถาม OpenGL เกี่ยวกับความสามารถของกราฟิกอะแดปเตอร์ของเราเท่านั้น (ความละเอียดสูงสุด, การลบรอยหยักสูงสุด, ความลึกของสีสูงสุด, ... )
แต่เรายังสามารถเติมพื้นผิวด้วยพิกเซลที่แต่ละพิกเซลมีสีเฉพาะได้ แต่ละพิกเซลจึงมีค่าและพื้นผิวเป็น "ไฟล์" ขนาดยักษ์ที่เต็มไปด้วยข้อมูล เราสามารถโหลดสิ่งนั้นลงในกราฟิกการ์ด (โดยการสร้างบัฟเฟอร์พื้นผิว) จากนั้นโหลดไฟล์ เงา บอกให้ shader ใช้พื้นผิวของเราเป็นอินพุตและเรียกใช้การคำนวณที่หนักมากใน "ไฟล์"
จากนั้นเราสามารถ "แสดงผล" ผลลัพธ์ของการคำนวณ (ในรูปแบบของสีใหม่) ให้เป็นพื้นผิวใหม่ได้
นั่นคือวิธีที่คุณสามารถทำให้ GPU ทำงานแทนคุณด้วยวิธีอื่น ๆ ฉันถือว่า CUDA ทำงานคล้ายกับด้านนั้น แต่ฉันไม่เคยมีโอกาสทำงานกับมัน
เราสัมผัสเรื่องทั้งหมดเพียงเล็กน้อยจริงๆ การเขียนโปรแกรมกราฟิก 3 มิติเป็นนรกของสัตว์ร้าย
มีสิ่งที่จะเพิ่มคำอธิบาย? ปิดเสียงในความคิดเห็น ต้องการอ่านคำตอบเพิ่มเติมจากผู้ใช้ Stack Exchange ที่เชี่ยวชาญด้านเทคโนโลยีคนอื่น ๆ หรือไม่? ดูกระทู้สนทนาฉบับเต็มได้ที่นี่ .