프레임 프로파일링을 사용하여 몇 가지 가능한 버텍스 관련 성능 문제를 진단할 수 있습니다. Commands 창을 사용하여 게임이 특정 프레임에서 실행하는 모든 그리기 호출과 그리기 호출당 그려진 프리미티브 수를 확인할 수 있습니다. 이렇게 하면 단일 프레임에 제출된 총 꼭짓점 수의 근사치를 얻을 수 있습니다.
그림 1. 단일 glDrawElements 호출의 프레임 프로파일링 뷰(2,718개의 삼각형 프리미티브가 그려짐)
꼭짓점 속성 압축
게임이 직면할 수 있는 일반적인 문제 중 하나는 큰 평균 꼭짓점 크기입니다. 평균 꼭짓점 크기가 높은 꼭짓점 수가 많으면 GPU에서 읽을 때 꼭짓점 메모리 읽기 대역폭이 커집니다.
지정된 그리기 호출의 꼭짓점 형식을 관찰하려면 다음 단계를 완료하세요.
관심 있는 그리기 호출을 선택합니다.
이는 장면의 일반적인 그리기 호출, 꼭짓점 수가 많은 그리기 호출, 복잡한 문자 모델의 그리기 호출 또는 기타 유형의 그리기 호출일 수 있습니다.
Pipeline(파이프라인) 창으로 이동하고 입력 어셈블리의 IA를 클릭합니다.
이는 GPU로 들어오는 꼭짓점의 꼭짓점 형식을 정의합니다.
일련의 속성과 형식을 관찰합니다. 예를 들어 R32G32B32_SFLOAT는 3개 구성요소로 이루어진 부호 있는 32비트 부동 소수점입니다.
그림 2. 버텍스 크기가 56바이트가 되는 압축되지 않은 속성이 있는 그리기 호출용 입력 어셈블리
대부분의 경우 꼭짓점 속성은 그려지는 모델의 품질을 최소한으로 저해하면서 압축될 수 있습니다. 특히 다음 사항을 권장합니다.
꼭짓점 위치를 반정밀도 16비트 부동 소수점 수로 압축
UV 텍스처 좌표를 16비트의 부호 없는 정수 ushort로 압축함
쿼터니언을 사용하여 정상, 탄젠트, 이중 정규 벡터를 인코딩하여 탄젠트 공간을 압축합니다.
낮은 정밀도 유형에는 사례별로 다른 기타 속성도 고려될 수 있습니다.
꼭짓점 스트림 분할
꼭짓점 속성 스트림이 적절하게 분할되었는지도 조사할 수 있습니다. 모바일 GPU와 같은 타일식 렌더링 아키텍처에서는 꼭짓점 위치가 먼저 비닝 패스에서 사용되어 각 카드에서 처리되는 프리미티브의 구간을 만듭니다. 꼭짓점 속성이 단일 버퍼에 인터리브 처리되면 꼭짓점 위치만 사용되더라도 모든 꼭짓점 데이터는 비닝을 위해 캐시로 읽힙니다.
꼭짓점 읽기 메모리 대역폭을 줄이고 캐시 효율성을 개선하여 비닝 패스에 소요되는 시간을 줄이려면 꼭짓점 데이터를 두 개의 별도 스트림(꼭짓점 위치용 스트림과 다른 모든 꼭짓점 속성용 스트림)으로 분할해야 합니다.
꼭짓점 속성이 적절히 분할되었는지 조사하려면 다음 단계를 따르세요.
원하는 그리기 호출을 선택하고 그리기 호출 번호를 기록해 둡니다.
이는 장면의 일반적인 그리기 호출, 꼭짓점 수가 많은 그리기 호출, 복잡한 문자 모델의 그리기 호출 또는 기타 유형의 그리기 호출일 수 있습니다.
Pipeline(파이프라인) 창으로 이동하고 입력 어셈블리의 IA를 클릭합니다. 이는 GPU로 들어오는 꼭짓점의 꼭짓점 형식을 정의합니다.
꼭짓점 속성의 결합을 관찰합니다. 일반적으로 결합은 선형적으로 증가할 수 있지만 (0, 1, 2, 3 등) 항상 그런 것은 아닙니다.
꼭짓점 위치는 일반적으로 나열되는 첫 번째 꼭짓점 속성입니다.
State 창에서 LastDrawInfos를 찾아 일치하는 그리기 호출 번호를 펼칩니다. 그런 다음 이 그리기 호출의 BoundVertexBuffers를 펼칩니다.
지정된 그리기 호출 중에 바인딩된 꼭짓점 버퍼를 관찰하고 색인은 이전 꼭짓점 속성 결합과 일치시킵니다.
그리기 호출의 꼭짓점 속성 결합을 확장하고 버퍼를 확장합니다.
꼭짓점 데이터 소스의 기본 메모리를 나타내는 버퍼의 VulkanHandle를 확인합니다. VulkanHandle가 다르면 속성이 다른 기본 버퍼에서 발생한다는 의미입니다. VulkanHandle는 동일하지만 오프셋이 큰 경우(예: 100 초과) 다른 하위 버퍼에서 속성이 계속 발생할 수 있지만 추가 조사가 필요합니다.
그림 3. 그리기 호출을 위한 입력 어셈블리. 오른쪽에 결합 0과 1, 꼭짓점 위치 및 일반의 속성이 단일 기본 버퍼를 공유함을 보여주는 상태 패널
버텍스 스트림 분할과 다양한 게임 엔진에서 이를 해결하는 방법에 관한 자세한 내용은 관련 블로그 게시물을 참고하세요.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 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 vertex formats\n\nYou may diagnose a few possible vertex-related performance problems through the\nuse of frame profiling. Use the **Commands** pane to view all of the draw calls\nyour game performs in a given frame and counts of primitives drawn per draw\ncall. This can give an approximation of the overall number of vertices submitted\nin a single frame.\n**Figure 1.** Frame profiling view for a single `glDrawElements` call, showing 2,718 triangle primitives drawn\n\nVertex attribute compression\n----------------------------\n\nOne common problem your game may face is a large average vertex size. A\nlarge number of vertices submitted with a high average vertex size results in a\nlarge vertex memory read bandwidth when read by the GPU.\n\nTo observe the vertex format for a given draw call, complete the following steps:\n\n1. Select a draw call of interest.\n\n This can be a typical draw call for the scene, a draw call with a large\n number of vertices, a draw call for a complex character model, or some other\n type of draw call.\n2. Navigate to the **Pipeline** pane, and click **IA** for input assembly.\n This defines the vertex format for vertices coming into the GPU.\n\n3. Observe a series of attributes and their formats; for example,\n `R32G32B32_SFLOAT` is a 3-component 32-bit signed float.\n\n**Figure 2.**Input assembly for a draw call, with uncompressed attributes resulting in a vertex size of 56 bytes\n\nFrequently, vertex attributes can be compressed with minimal reduction in the\nquality of the models drawn. In particular, we recommend:\n\n- Compressing vertex position to half-precision 16-bit floats\n- Compressing UV texture coordinates to 16-bit unsigned integer ushorts\n- Compressing the tangent space by encoding normal, tangent, and binormal vectors using quaternions\n\nOther miscellaneous attributes may also be considered for lower-precision types\non a case-by-case basis.\n\nVertex stream splitting\n-----------------------\n\nYou can also investigate whether vertex attribute streams are appropriately\nsplit. On tiled rendering architectures such as mobile GPUs, vertex positions\nare first used in a binning pass to create bins of primitives processed in each\ntile. If vertex attributes are interleaved into a single buffer, all vertex data\nis read into cache for binning, even though only vertex positions are used.\n\nTo reduce vertex read memory bandwidth and improve cache efficiency, and thus\nreduce time spent on the binning pass, vertex data should be split into two\nseparate streams, one for vertex positions, and one for all other vertex\nattributes.\n\nTo investigate whether vertex attributes are appropriately split:\n\n1. Select a draw call of interest, and note the draw call number.\n\n This can be a typical draw call for the scene, a draw call with a large\n number of vertices, a draw call for a complex character model, or some other\n type of draw call.\n2. Navigate to the **Pipeline** pane, and click **IA** for input assembly. This\n defines the vertex format for vertices coming into the GPU.\n\n3. Observe the bindings of your vertex attributes; typically these might\n increase linearly (0, 1, 2, 3, etc.), but this is not always the case.\n Vertex position is typically the first vertex attribute listed.\n\n4. In the **State** pane, find the `LastDrawInfos` and expand the matching draw\n call number. Then, expand the `BoundVertexBuffers` for this draw call.\n\n5. Observe the vertex buffers bound during the given draw call, with indices\n matching the vertex attribute bindings from earlier.\n\n6. Expand the bindings for your draw call's vertex attributes, and expand the\n buffers.\n\n7. Observe the `VulkanHandle` for the buffers, which represent the underlying\n memory that the vertex data sources from. If the `VulkanHandle`s are\n different, this means the attributes originate from different underlying\n buffers. If the `VulkanHandle`s are the same but the offsets are large\n (for example, greater than 100), the attributes may still originate from\n different sub-buffers, but this requires further investigation.\n\n**Figure 3.**Input assembly for a draw call, with the state panel to the right showing that the attributes at binding 0 and 1, vertex position and normal, share a single underlying buffer\n\nFor more detail about vertex stream splitting and how to resolve it on various\ngame engines, see our [blog post](/agi/frame-trace/link-to-Omars-blog-post) on the subject."]]