AGI 프레임 프로파일러를 사용하면 렌더링 패스 중 하나에서 그리기 호출을 선택하고 파이프라인 창의 Vertex Shader 섹션 또는 Fragment Shader 섹션을 통해 셰이더를 조사할 수 있습니다.
여기에서는 셰이더 코드의 정적 분석과 GLSL로 컴파일된 Standard Portable Intermediate Representation(SPIR-V) 어셈블리에서 가져온 유용한 통계를 확인할 수 있습니다. SPIR-V Cross로 디컴파일된 원본 GLSL의 표현 (컴파일러에서 생성된 변수, 함수 등의 이름 포함)을 볼 수 있는 탭도 있어 SPIR-V에 관한 추가 컨텍스트를 제공합니다.
정적 분석
그림 1. 설명??
정적 분석 카운터를 사용하여 셰이더의 하위 수준 작업을 봅니다.
ALU 명령: 이 수는 셰이더 내에서 실행되는 ALU 연산(더하기, 곱하기, 나눗셈 등)의 수를 나타내며 셰이더의 복잡성을 나타내는 좋은 프록시입니다. 이 값을 최소화해 보세요.
일반적인 계산을 리팩터링하거나 셰이더에서 실행되는 계산을 단순화하면 필요한 명령 수를 줄이는 데 도움이 될 수 있습니다.
텍스처 안내: 이 수는 셰이더에서 텍스처 샘플링이 발생하는 횟수를 보여줍니다.
텍스처 샘플링은 샘플링되는 텍스처 유형에 따라 비용이 많이 들 수 있으므로 셰이더 코드를 설명자 세트 섹션에 있는 바인드 텍스처와 교차 참조하면 사용 중인 텍스처 유형에 관한 자세한 정보를 제공할 수 있습니다.
텍스처를 샘플링할 때 무작위 액세스를 피합니다. 이 동작은 텍스처 캐싱에 적합하지 않기 때문입니다.
브랜치 안내: 이 수는 셰이더의 브랜치 작업 수를 보여줍니다. GPU와 같은 병렬화된 프로세서에서 분기를 최소화하는 것이 이상적이며 컴파일러가 추가 최적화를 찾는 데 도움이 될 수도 있습니다.
숫자 값을 분기할 필요가 없도록 min, max, clamp과 같은 함수를 사용합니다.
분기를 통한 계산 비용을 테스트합니다. 브랜치의 두 경로는 모두 많은 아키텍처에서 실행되므로 항상 계산을 실행하는 것이 브랜치를 사용한 계산을 건너뛰는 것보다 더 빠른 시나리오가 많습니다.
임시 레지스터: GPU에서의 계산에 필요한 중간 작업의 결과를 저장하는 데 사용되는 빠른 온코어 레지스터입니다. GPU가 다른 오프코어 메모리를 사용하여 중간 값을 저장하도록 스필오버하기 전에 계산에 사용할 수 있는 레지스터 수에 제한이 있으므로 전반적인 성능이 저하됩니다. (이 한도는 GPU 모델에 따라 다릅니다.)
셰이더 컴파일러가 언롤링 루프와 같은 작업을 실행하는 경우 사용되는 임시 레지스터의 수가 예상보다 많을 수 있으므로 이 값을 SPIR-V 또는 디컴파일된 GLSL과 교차 참조하여 코드가 실행하는 작업을 확인하는 것이 좋습니다.
셰이더 코드 분석
디컴파일된 셰이더 코드 자체를 조사하여 가능한 개선 사항이 있는지 확인합니다.
그림 2. 설명??
정밀도: 셰이더 변수의 정밀도는 애플리케이션의 GPU 성능에 영향을 줄 수 있습니다.
가능한 경우 변수에 mediump 정밀도 수정자를 사용해 보세요. 중간 정밀도 (mediump) 16비트 변수는 일반적으로 전체 정밀도 (highp) 32비트 변수보다 빠르고 전력 효율성이 높기 때문입니다.
변수 선언 시 셰이더 또는 precision precision-qualifier type가 있는 셰이더 상단에 정밀도 한정자가 표시되지 않으면 기본값은 전체 정밀도(highp)입니다. 변수 선언도 확인해야 합니다.
위에서 설명한 것과 같은 이유로 꼭짓점 셰이더 출력에 mediump를 사용하는 것이 좋으며, 메모리 대역폭과 보간을 실행하는 데 필요한 임시 레지스터 사용량을 줄일 수 있는 이점도 있습니다.
균일 버퍼: 정렬 규칙은 유지하면서 균일 버퍼의 크기를 가능한 한 작게 유지합니다. 이렇게 하면 계산과 캐싱의 호환성이 향상되고 균일한 데이터를 더 빠른 온코어 레지스터로 승격할 수 있습니다.
사용하지 않는 Vertex 셰이더 출력 삭제: 프래그먼트 셰이더에서 사용되지 않는 꼭짓점 셰이더 출력이 있으면 셰이더에서 삭제하여 메모리 대역폭과 임시 레지스터의 여유 공간을 확보합니다.
프래그먼트 셰이더에서 Vertex 셰이더로 계산 이동: 프래그먼트 셰이더 코드가 음영 처리되는 (또는 제대로 보간할 수 있는) 프래그먼트와 무관한 상태와 무관한 계산을 실행하는 경우 꼭짓점 셰이더로 이동하는 것이 좋습니다. 그 이유는 대부분의 앱에서 꼭짓점 셰이더가 프래그먼트 셰이더에 비해 훨씬 덜 실행되기 때문입니다.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-07-27(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 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."]]