איך המעבד ואת האינטראקציה GPU כדי לעבד גרפיקה ממוחשבת?
יחידת העיבוד המרכזית של המחשב (CPU) ומעבד העיבוד הגרפי (GPU) פועלים בכל רגע שבו אתה משתמש במחשב כדי לספק לך ממשק ויזואלי חד וברור. המשך לקרוא כדי להבין טוב יותר כיצד הם פועלים יחד.
תמונה על ידי ססקנל.
מפגש השאלות והתשובות של היום מגיע אלינו באדיבות SuperUser - חלוקה מחודשת של Stack Exchange, קיבוץ קהילתי של אתרי Q & A.
השאלה
קורא הסופר סתיה הציג את השאלה:
כאן ניתן לראות צילום מסך של תוכנית C + + קטנה בשם Triangle.exe עם משולש מסתובב המבוסס על ממשק API של OpenGL.
אמנם יש דוגמה בסיסית מאוד אבל אני חושב שזה ישים על אחרים כרטיסים גרפיים המבצעים.
הייתי רק סקרן ורציתי לדעת את כל התהליך מ לחיצה כפולה על Triangle.exe תחת Windows XP עד שאני יכול לראות את המשולש מסתובבת על הצג. מה קורה, איך מעבד (אשר מטפל הראשון. Exe) ו GPU (אשר סוף סוף פלטי המשולש על המסך) אינטראקציה?
אני מניח מעורב בהצגת המשולש הזה מסתובב בעיקר את החומרה הבאה / תוכנה בין היתר:
חומרה
- HDD
- זיכרון מערכת (RAM)
- מעבד
- זיכרון וידאו
- GPU
- תצוגת LCD
תוכנה
- מערכת הפעלה
- DirectX / OpenGL API
- Nvidia הנהג
מישהו יכול להסביר את התהליך, אולי עם איזשהו תרשים זרימה להמחשה?
זה לא צריך להיות הסבר מורכב המכסה כל צעד ואחד (לנחש כי היה ללכת מעבר להיקף), אבל הסבר ביניים IT יכול לעקוב אחר.
אני די בטוח שאנשים רבים אפילו יקראו לעצמם אנשי IT לא יכלו לתאר את התהליך בצורה נכונה.
התשובה
למרות מספר רב של חברי הקהילה ענה על השאלה, אוליבר זלצבורג הלך קילומטר נוסף וענה זה לא רק עם תגובה מפורטת אבל גרפיקה מלווה מעולה.
תמונה של JasonC, זמין כטפט כאן.
הוא כותב:
החלטתי לכתוב קצת על היבט התכנות וכיצד מרכיבים מדברים זה עם זה. אולי זה ישפוך קצת אור על אזורים מסוימים.
המצגת
מה נדרש כדי לקבל את התמונה היחידה, שאותה פרסמת בשאלה שלך, מצוירת על המסך?
ישנן דרכים רבות לצייר משולש על המסך. לפשטות, נניח שלא נעשה שימוש במאגרי קדקוד. (א חיץ קדקודהוא אזור זיכרון שבו אתה שומר קואורדינטות.) נניח את התוכנית פשוט אמר את הציור עיבוד גרפי על כל קודקוד יחיד (קודקוד הוא רק קואורדינטות בחלל) ברציפות.
אבל, לפני שנוכל לצייר כל דבר, עלינו תחילה להפעיל פיגומים. נראה למה יותר מאוחר:
/ / נקה את המסך ואת עומק המאגר glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); / / אפס את המודל הנוכחי MatView 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 שבו תוכל להתקשר מהתוכנית שלך.
ה- API הזה הוא מה שאנו רואים בשימוש בדוגמה לעיל. בואו ניקח מבט מקרוב.
הפיגומים
לפני שאתה באמת יכול לעשות כל ציור בפועל, תצטרך לבצע להכין. אתה צריך להגדיר את שדה התצוגה שלך (אזור זה יהיה למעשה שניתנו), את נקודת המבט שלך ( מצלמה אל תוך העולם שלך), מה נגד aliasing תוכל להשתמש (כדי להחליק את הקצוות של המשולש שלך) ...
אבל אנחנו לא מסתכלים על כל זה. אנחנו רק נסתכל על הדברים שתצטרך לעשות כל מסגרת. כמו:
ניקוי המסך
הצינור גרפיקה לא הולך לנקות את המסך בשבילך כל מסגרת. יהיה עליך לספר זאת. למה? זו הסיבה לכך:
אם אתה לא לנקות את המסך, אתה פשוט לצייר מעל זה כל מסגרת. בגלל זה אנחנו קוראים glClear
עם הGL_COLOR_BUFFER_BIT
בחר. החלק השני (GL_DEPTH_BUFFER_BIT
) אומר OpenGL כדי לנקות את עומקחיץ. מאגר זה משמש כדי לקבוע אילו פיקסלים נמצאים לפני (או מאחור) פיקסלים אחרים.
טרנספורמציה
מקור תמונה
טרנספורמציה היא החלק שבו אנו לוקחים את כל הקואורדינטות קלט (קודקודים של המשולש שלנו) וליישם מטריקס ModelView שלנו. זוהי המטריצה מסביר איך שלנו מודל (קודקודים) הם מסובבים, scaled, ומתורגם (הועבר).
לאחר מכן, אנו מיישמים את מטריצת הקרנה שלנו. פעולה זו מזיזה את כל הקואורדינטות כך שהן עומדות מול המצלמה שלנו בצורה נכונה.
עכשיו אנחנו הופכים שוב, עם מטריקס Viewport שלנו. אנו עושים זאת כדי לשנות את קנה המידה שלנו מודל לגודל הצג שלנו. עכשיו יש לנו קבוצה של קודקודים כי הם מוכנים להיות שניתנו!
נחזור קצת מאוחר יותר.
ציור
כדי לצייר משולש, אנחנו יכולים פשוט להגיד OpenGL להתחיל חדש רשימה של משולשים על ידי התקשרות glBegin
עם ה GL_TRIANGLES
קבוע.
יש גם צורות אחרות שאתה יכול לצייר. כמו רצועת משולש או מעריץ משולש. אלה הם בעיקר אופטימיזציה, כפי שהם דורשים פחות תקשורת בין המעבד לבין GPU לצייר את אותה כמות של משולשים.
לאחר מכן, אנו יכולים לספק רשימה של קבוצות של 3 הקודקודים אשר אמור לפצות כל משולש. כל משולש משתמש ב- 3 קואורדינטות (כפי שאנו נמצאים בתלת-ממד). בנוסף, אני גם לספק צבע עבור כל קודקוד, על ידי קוראglColor3f
לפני קורא glvertex3f
.
הצל בין 3 הקודקודים (3 הפינות של המשולש) מחושב על ידי OpenGLבאופן אוטומטי. זה יהיה אינטרפולציה צבע על פני כל המצולע.
אינטראקציה
עכשיו, כאשר אתה לוחץ על החלון. היישום רק צריך ללכוד את ההודעה חלון מאותת על לחץ. לאחר מכן תוכל להפעיל כל פעולה בתוכנית שלך אתה רוצה.
זה מקבל גלה יותר קשה ברגע שאתה רוצה להתחיל לתקשר עם הסצנה 3D שלך.
ראשית עליך לדעת בבירור באיזה פיקסל לחץ המשתמש על החלון. לאחר מכן, לוקח את פרספקטיבהבחשבון, אתה יכול לחשב את הכיוון של קרן, מנקודת העכבר לחץ לתוך למקום שלך. לאחר מכן תוכל לחשב אם כל אובייקט בסצנה שלך מצטלב עם הקרן הזאת. עכשיו אתה יודע אם המשתמש לוחץ על אובייקט.
אז, איך אתה עושה את זה לסובב?
טרנספורמציה
אני מודע לשני סוגים של טרנספורמציות המיושמות בדרך כלל:
- מטריצה מבוססת טרנספורמציה
- טרנספורמציה המבוססת על עצם
ההבדל הוא זה עצמות להשפיע על יחיד קודקודים. מטריצות תמיד משפיעות על כל הקודקודים מצוירים באותו אופן. בואו נסתכל על דוגמה.
דוגמא
מוקדם יותר, טעינו שלנו מטריצת הזהות לפני ציור המשולש שלנו. מטריצת הזהות היא אחת שפשוט מספקת ללא שינוי בכלל. אז, מה אני מצייר, מושפע רק מנקודת המבט שלי. אז, המשולש לא יהיה מסובב בכלל.
אם אני רוצה לסובב את זה עכשיו, אני יכול לעשות את המתמטיקה בעצמי (על המעבד) ופשוט להתקשר glvertex3f
עםאחר קואורדינטות (מסובבות). או שאני יכול לתת GPU לעשות את כל העבודה, על ידי קורא glRotatef
לפני ציור:
/ / לסובב את המשולש על ציר Y glototff (כמות, 0.0f, 1.0f, 0.0f);
כמות
הוא, כמובן, רק ערך קבוע. אם אתה רוצה הנפשת, יהיה עליך לעקוב אחר כמות
ולהגדיל את זה כל מסגרת.
אז, רגע, מה קרה לכל הדיבור מטריקס קודם לכן?
בדוגמה פשוטה זו, אנחנו לא צריכים לדאוג מטריצות. אנחנו פשוט קוראים glRotatef
והוא מטפל בכל זה בשבילנו.
glrootate
מייצרת סיבוב שלזווית
מעלות סביב וקטור x y z. המטריצה הנוכחית (SeeglMatrixMode) מוכפלת על ידי מטריצת סיבוב עם המוצר המחליף את המטריצה הנוכחית, כאילו glMMMMrix נקראה עם המטריצה הבאה כטיעון שלה: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 1 - c + c 0 0 0 0 1
טוב, תודה על זה!
סיכום
מה שמתברר הוא שיש הרבה דיבורים ל OpenGL. אבל זה לא אומר אותנו כל דבר. היכן נמצאת התקשורת??
הדבר היחיד ש- OpenGL אומר לנו בדוגמה זו הוא כאשר זה נעשה. כל פעולה תידרש פרק זמן מסוים. פעולה כלשהי לקחת זמן רב, אחרים הם מהירה מאוד.
שליחת קודקוד כדי GPU יהיה כל כך מהר, אני אפילו לא יודע איך לבטא את זה. שליחת אלפי קודקודים מן המעבד ל- GPU, כל מסגרת אחת, היא, קרוב לוודאי, אין בעיה בכלל.
ניקוי המסך יכול לקחת מילישניות או גרוע יותר (יש לזכור, בדרך כלל יש רק כ 16 מילישניות זמן לצייר כל מסגרת), תלוי כמה גדול שלך הוא. כדי לנקות אותו, OpenGL יש לצייר כל פיקסל אחד בצבע שאתה רוצה לנקות, זה יכול להיות מיליוני פיקסלים.
חוץ מזה, אנחנו יכולים די הרבה לשאול רק OpenGL על היכולות של מתאם הגרפיקה שלנו (רזולוציה מקסימלית, מקסימום נגד aliasing, עומק צבע מרבי, ...).
אבל אנחנו יכולים גם למלא מרקם עם פיקסלים שכל אחד מהם יש צבע מסוים. כל פיקסל ובכך מחזיק ערך המרקם הוא "קובץ" ענק מלא נתונים. אנחנו יכולים לטעון את זה לתוך כרטיס המסך (על ידי יצירת חיץ מרקם), ולאחר מכן לטעון Shader, לומר כי Shader להשתמש במרקם שלנו כקלט ולהפעיל כמה חישובים כבדים מאוד על "קובץ".
לאחר מכן אנו יכולים "לעבד" את התוצאה של החישוב שלנו (בצורה של צבעים חדשים) לתוך מרקם חדש.
זה איך אתה יכול לעשות את GPU לעבוד בשבילך בדרכים אחרות. אני מניח ש- CUDA מבצע דומה להיבט הזה, אבל מעולם לא היתה לי הזדמנות לעבוד איתו.
רק מעט נגענו בכל הנושא. 3D גרפיקה תכנות הוא לעזאזל של חיה.
מקור תמונה
יש לך משהו להוסיף להסבר? נשמע את ההערות. רוצה לקרוא תשובות נוספות ממשתמשים אחרים בעלי ידע טכנולוגי מתמצא? בדוק את נושא הדיון המלא כאן.