קל לארגן דפים בעזרת אוספים
אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.
כדי לבדוק את ה-shaders באמצעות AGI Frame Profiler, בוחרים קריאה לציור מאחד ממעברי הרינדור, ועוברים לקטע Vertex Shader או לקטע Fragment Shader בחלונית Pipeline.
כאן תוכלו למצוא נתונים סטטיסטיים שימושיים שמגיעים מניתוח סטטי של קוד ה-shader, וגם את קוד האסמבלי של Standard Portable Intermediate Representation (SPIR-V) שאליו קוד ה-GLSL שלנו עבר קומפילציה. יש גם כרטיסייה להצגת ייצוג של GLSL המקורי (עם שמות שנוצרו על ידי קומפיילר למשתנים, לפונקציות ועוד) שעבר דקומפילציה באמצעות SPIR-V Cross, כדי לספק הקשר נוסף ל-SPIR-V.
ניתוח סטטי
איור 1. כתובית??
אפשר להשתמש בדלפקי ניתוח סטטי כדי לראות פעולות ברמה נמוכה ב-Shader.
הוראות ALU: המספר הזה מייצג את מספר הפעולות של ALU (חיבור, כפל, חילוק ועוד) שמבוצעות בתוך ה-Shader, והוא מהווה אינדיקטור טוב לרמת המורכבות של ה-Shader. מומלץ לנסות למזער את הערך הזה.
אפשר לשנות את מבנה החישובים הנפוצים או לפשט את החישובים שמתבצעים ב-shader כדי להקטין את מספר ההוראות שנדרשות.
הוראות לטקסטורה: המספר הזה מציין כמה פעמים מתבצעת דגימה של טקסטורה בשיידר.
דגימת טקסטורות עלולה להיות יקרה, בהתאם לסוג הטקסטורות שמהן מתבצעת הדגימה. לכן, עיון בהפניות צולבות של קוד ה-Shader עם הטקסטורות המצורפות שנמצאות בקטע Descriptor Sets יכול לספק מידע נוסף על סוגי הטקסטורות שנמצאות בשימוש.
מומלץ להימנע מגישה אקראית כשדוגמים טקסטורות, כי ההתנהגות הזו לא מתאימה לשמירת טקסטורות במטמון.
הוראות הסתעפות: המספר הזה מציין את מספר פעולות ההסתעפות ב-Shader. צמצום ההתפצלות הוא אידיאלי במעבדים מקביליים כמו GPU, ואפילו יכול לעזור לקומפיילר למצוא אופטימיזציות נוספות:
כדי להימנע מהסתעפות לפי ערכים מספריים, אפשר להשתמש בפונקציות כמו min, max ו-clamp.
בדיקת עלות החישוב על פני הסתעפות. מכיוון ששני הנתיבים של הסתעפות מבוצעים בארכיטקטורות רבות, יש הרבה תרחישים שבהם ביצוע החישוב תמיד מהיר יותר מאשר דילוג על החישוב באמצעות הסתעפות.
Temporary Registers: אלה הם רגיסטרים מהירים בתוך הליבה שמשמשים לאחסון התוצאות של פעולות ביניים שנדרשות לחישובים ב-GPU. יש מגבלה על מספר הרגיסטרים שזמינים לחישובים, ולכן המעבד הגרפי צריך להשתמש בזיכרון אחר מחוץ לליבה כדי לאחסן ערכי ביניים, מה שמפחית את הביצועים הכוללים. (ההגבלה הזו משתנה בהתאם לדגם ה-GPU).
מספר הרישומים הזמניים שנעשה בהם שימוש עשוי להיות גבוה מהצפוי אם קומפיילר ה-shader מבצע פעולות כמו ביטול לולאות, ולכן מומלץ להשוות את הערך הזה עם SPIR-V או GLSL שעבר דקומפילציה כדי לראות מה הקוד עושה.
ניתוח קוד של Shader
בודקים את קוד ה-shader שעבר דקומפילציה כדי לראות אם אפשר לבצע שיפורים.
איור 2. כתובית??
דיוק: הדיוק של משתני shader יכול להשפיע על הביצועים של ה-GPU באפליקציה.
מומלץ להשתמש במשתנים עם mediumpדיוק בינוני (16 ביט) בכל מקום שאפשר, כי בדרך כלל הם מהירים יותר וצורכים פחות חשמל מאשר משתנים עם highpדיוק מלא (32 ביט).mediump
אם לא מופיעים מסיפי דיוק בשיידר בהצהרות על משתנים, או בחלק העליון של השיידר עם precision precision-qualifier type, ברירת המחדל היא דיוק מלא (highp). חשוב לבדוק גם את ההצהרות על משתנים.
מומלץ להשתמש ב-mediump גם עבור הפלט של הצללת הקודקודים, מאותן סיבות שמתוארות למעלה. יש לכך גם יתרון של צמצום רוחב הפס של הזיכרון, ואולי גם צמצום השימוש הזמני ברגיסטר שנדרש לביצוע אינטרפולציה.
מאגרי נתונים אחידים: כדאי לשמור על הגודל של מאגרי נתונים אחידים קטן ככל האפשר (תוך שמירה על כללי היישור). כך אפשר לשפר את התאימות של החישובים לשמירה במטמון, ואולי גם לקדם נתונים אחידים לרישומים מהירים יותר בתוך הליבה.
הסרת פלט של Vertex Shader שלא נמצא בשימוש: אם אתם מוצאים פלט של Vertex Shader שלא נמצא בשימוש ב-Fragment Shader, הסירו אותו מה-Shader כדי לפנות רוחב פס של זיכרון ורגיסטרים זמניים.
העברת חישובים מ-Fragment Shader ל-Vertex Shader: אם קוד ה-Fragment Shader מבצע חישובים שלא תלויים במצב שספציפי ל-Fragment המוצלל (או שאפשר לבצע אינטרפולציה בצורה תקינה), מומלץ להעביר אותו ל-Vertex Shader. הסיבה לכך היא שברוב האפליקציות, vertex shader מופעל בתדירות נמוכה בהרבה בהשוואה ל-fragment shader.
דוגמאות התוכן והקוד שבדף הזה כפופות לרישיונות המפורטים בקטע רישיון לתוכן. Java ו-OpenJDK הם סימנים מסחריים או סימנים מסחריים רשומים של חברת Oracle ו/או של השותפים העצמאיים שלה.
עדכון אחרון: 2025-07-27 (שעון UTC).
[null,null,["עדכון אחרון: 2025-07-27 (שעון UTC)."],[],[],null,["# Analyze shader performance\n\nAGI Frame Profiler allows you to investigate your shaders by\nselecting a draw call from one of our render passes, and going through either\nthe **Vertex Shader** section or **Fragment Shader** section of the **Pipeline**\npane.\n\nHere you'll find useful statistics coming from static analysis of the shader\ncode, as well as the [Standard Portable Intermediate Representation](https://en.wikipedia.org/wiki/Standard_Portable_Intermediate_Representation)\n(SPIR-V) assembly that our GLSL has been compiled down to. There's also a tab\nfor viewing a representation of the original GLSL (with compiler generated names for variables, functions, and more) that was decompiled with SPIR-V Cross, to provide additional context for the SPIR-V.\n\nStatic analysis\n---------------\n\n**Figure 1.**Caption??\n\nUse static analysis counters to view low-level operations in the shader.\n\n- **ALU Instructions**: This count shows the number of ALU operations\n (adds, multiplies, divisions, and more) are being executed within the\n shader, and is a good proxy for how complex the shader is. Try to minimize\n this value.\n\n Refactoring common computations or simplify computations done in the\n shader can help reduce the number of instructions needed.\n- **Texture Instructions**: This count shows the number of times texture\n sampling occurs in the shader.\n\n - Texture sampling can be expensive depending on the type of textures being sampled from, so cross-referencing the shader code with the bound textures found in the **Descriptor Sets** section can provide more information on the types of textures being used.\n - Avoid random access when sampling textures, because this behavior is not ideal for texture-caching.\n- **Branch Instructions**: This count shows the number of branch operations\n in the shader. Minimizing branching is ideal on parallelized processors such\n as the GPU, and can even help the compiler find additional optimizations:\n\n - Use functions such as `min`, `max`, and `clamp` to avoid needing to branch on numeric values.\n - Test the cost of computation over branching. Because both paths of a branch are executed in many architectures, there are many scenarios where always doing the computation is faster than skipping over the computation with a branch.\n- **Temporary Registers**: These are fast, on-core registers that are used to\n hold the results of intermediate operations required by computations on the\n GPU. There is a limit to the number of registers available for computations\n before the GPU has to spill over into using other off-core memory to store\n intermediate values, reducing overall performance. (This limit varies\n depending on the GPU model.)\n\n The number of temporary registers used may be higher than expected if the\n shader compiler performs operations such as unrolling loops, so it's good\n to cross-reference this value with the SPIR-V or decompiled GLSL to see what\n the code is doing.\n\n### Shader code analysis\n\nInvestigate the decompiled shader code itself to determine if there any\npotential improvements are possible.\n**Figure 2.**Caption??\n\n- **Precision** : The precision of shader variables can impact the GPU performance of your application.\n - Try using the `mediump` precision modifier on variables wherever possible, since medium precision (`mediump`) 16-bit variables are usually faster and more power efficient than full precision (`highp`) 32-bit variables.\n - If you don't see any precision qualifiers in the shader on variable declarations, or at the top of the shader with a `precision precision-qualifier type`, it defaults to full precision (`highp`). Make sure to look at variable declarations as well.\n - Using `mediump` for vertex shader output is also preferred for the same reasons described above, and also has the benefit of reducing memory bandwidth and potentially temporary register usage needed to do interpolation.\n- **Uniform Buffers** : Try to keep the size of **Uniform Buffers** as small as possible (while maintaining alignment rules). This helps make computations more compatible with caching and potentially allow for uniform data to be promoted to faster on-core registers.\n- **Remove unused Vertex Shader Outputs**: If you find vertex shader outputs\n being unused in the fragment shader, remove them from the shader to free up\n memory bandwidth and temporary registers.\n\n- **Move computation from Fragment Shader to Vertex Shader**: If the fragment\n shader code performs computations that are independent of state specific to\n the fragment being shaded (or can be interpolated properly), moving it to\n the vertex shader is ideal. The reason for this is that in most apps, the\n vertex shader is run much less frequently compared to the fragment shader."]]