Qt Quick 씬 그래프 기본 렌더러
이 문서에서는 기본 씬 그래프 렌더러의 내부 작동 방식을 설명하여 성능과 기능 측면에서 최적의 방식으로 렌더러를 사용하는 코드를 작성할 수 있도록 합니다.
좋은 성능을 얻기 위해 렌더러의 내부를 이해할 필요는 없습니다. 하지만 씬 그래프와 통합하거나 그래픽 칩에서 최대 효율을 끌어낼 수 없는 이유를 파악하는 데 도움이 될 수 있습니다.
참고: 모든 프레임이 고유하고 모든 것이 처음부터 업로드되는 경우에도 기본 렌더러가 잘 작동합니다.
QML 씬의 Qt Quick 항목은 QSGNode 인스턴스의 트리를 채웁니다. 일단 생성되면 이 트리는 특정 프레임이 렌더링되는 방식에 대한 완전한 설명입니다. 여기에는 Qt Quick 항목에 대한 참조가 전혀 포함되어 있지 않으며 대부분의 플랫폼에서 별도의 스레드에서 처리 및 렌더링됩니다. 렌더러는 QSGNode 트리를 탐색하고 QSGGeometryNode 에 정의된 지오메트리와 QSGMaterial 에 정의된 셰이더 상태를 사용하여 그래픽 상태를 업데이트하고 그리기 호출을 생성하는 장면 그래프의 자체 포함 부분입니다.
필요한 경우 렌더러는 내부 씬 그래프 백엔드 API를 사용하여 완전히 교체할 수 있습니다. 이는 비표준 하드웨어 기능을 활용하고자 하는 플랫폼 공급업체에게 주로 흥미로운 기능입니다. 대부분의 사용 사례에서는 기본 렌더러로 충분합니다.
기본 렌더러는 렌더링을 최적화하기 위한 두 가지 주요 전략에 중점을 둡니다: 그리기 호출의 일괄 처리와 GPU의 지오메트리 유지입니다.
일괄 처리
QPainter, Cairo 또는 Context2D 와 같은 기존 2D API는 프레임당 수천 개의 개별 드로우 호출을 처리하도록 작성된 반면, OpenGL 및 기타 하드웨어 가속 API는 드로우 호출 수가 매우 적고 상태 변경이 최소화될 때 가장 성능이 좋습니다.
참고: 다음 섹션에서는 OpenGL
을 예로 사용했지만, 다른 그래픽 API에도 동일한 개념이 적용됩니다.
다음 사용 사례를 고려해 보세요:
이 목록을 그리는 가장 간단한 방법은 셀 단위로 그리는 것입니다. 먼저 배경을 그립니다. 이것은 특정 색상의 직사각형입니다. OpenGL 용어로는 단색 채우기를 수행할 셰이더 프로그램을 선택하고, 채우기 색상을 설정하고, x 및 y 오프셋을 포함하는 변환 행렬을 설정한 다음 예를 들어 glDrawArrays
을 사용하여 직사각형을 구성하는 두 개의 삼각형을 그리는 것을 의미합니다. 다음에 아이콘이 그려집니다. OpenGL 용어로는 텍스처를 그릴 셰이더 프로그램을 선택하고, 사용할 활성 텍스처를 선택하고, 변환 행렬을 설정하고, 알파 블렌딩을 활성화한 다음 glDrawArrays
을 사용하여 아이콘의 경계 사각형을 구성하는 두 개의 삼각형을 그리는 것을 의미합니다. 셀 사이의 텍스트와 구분선도 비슷한 패턴을 따릅니다. 이 과정은 목록의 모든 셀에 대해 반복되므로 목록이 길어지면 OpenGL 상태 변경 및 그리기 호출로 인한 오버헤드가 하드웨어 가속 API를 사용할 때 얻을 수 있는 이점보다 훨씬 더 커집니다.
각 프리미티브가 큰 경우 이 오버헤드는 무시할 수 있지만 일반적인 UI의 경우 작은 항목이 많아 상당한 오버헤드가 발생합니다.
기본 씬 그래프 렌더러는 이러한 제한 내에서 작동하며, 시각적 결과는 그대로 유지하면서 개별 프리미티브를 일괄 병합하려고 시도합니다. 그 결과 OpenGL 상태 변경이 적고 드로우 호출이 최소화되어 최적의 성능을 얻을 수 있습니다.
불투명 프리미티브
렌더러는 불투명 프리미티브와 알파 블렌딩이 필요한 프리미티브를 구분합니다. 렌더러는 OpenGL의 Z 버퍼를 사용하고 각 프리미티브에 고유한 z 위치를 부여함으로써 화면에서의 위치와 겹치는 다른 요소에 관계없이 불투명 프리미티브의 순서를 자유롭게 변경할 수 있습니다. 렌더러는 각 프리미티브의 머티리얼 상태를 확인하여 불투명 배치를 생성합니다. Qt Quick 핵심 항목 세트에서 불투명 색상의 사각형 항목과 JPEG 또는 BMP와 같은 완전 불투명 이미지가 여기에 포함됩니다.
불투명 프리미티브를 사용하면 특히 모바일 및 임베디드 GPU에서 비용이 많이 드는 GL_BLEND
을 활성화할 필요가 없다는 점도 불투명 프리미티브를 사용하면 얻을 수 있는 또 다른 이점입니다.
불투명 프리미티브는 glDepthMask
및 GL_DEPTH_TEST
을 활성화한 상태에서 앞뒤로 렌더링됩니다. 내부적으로 초기 z 검사를 수행하는 GPU에서 이는 가려진 픽셀이나 픽셀 블록에 대해 조각 셰이더를 실행할 필요가 없음을 의미합니다. 렌더러는 여전히 이러한 노드를 고려해야 하며 버텍스 셰이더는 여전히 이러한 프리미티브의 모든 버텍스에 대해 실행되므로 애플리케이션에서 무언가가 완전히 가려진 것을 알고 있는 경우 Item::visible 또는 Item::opacity 을 사용하여 명시적으로 숨기는 것이 가장 좋은 방법이라는 점에 유의하세요.
참고: Item::z 는 형제 항목에 대한 항목의 스택 순서를 제어하는 데 사용됩니다. 렌더러 및 OpenGL의 Z 버퍼와는 직접적인 관련이 없습니다.
알파 블렌디드 프리미티브
불투명 프리미티브가 그려지면 렌더러는 glDepthMask
을 비활성화하고 GL_BLEND
을 활성화한 후 모든 알파 블렌드 프리미티브를 백투프론트 방식으로 렌더링합니다.
알파 블렌딩된 프리미티브를 일괄 처리하려면 겹치는 요소를 올바른 순서로 렌더링해야 알파 블렌딩이 올바르게 보이므로 렌더러에서 조금 더 많은 노력이 필요합니다. Z 버퍼에만 의존하는 것만으로는 충분하지 않습니다. 렌더러는 모든 알파 블렌딩된 프리미티브에 대한 패스를 수행하고 머티리얼 상태와 더불어 바운딩된 직사각형을 살펴 어떤 요소를 일괄 처리할 수 있고 어떤 요소를 처리할 수 없는지 파악합니다.
가장 왼쪽의 경우, 텍스트가 앞에 겹쳐진 배경과만 겹치기 때문에 파란색 배경은 한 호출에서, 두 텍스트 요소는 다른 호출에서 그릴 수 있습니다. 가장 오른쪽의 경우 '항목 4'의 배경이 '항목 3'의 텍스트와 겹치므로 이 경우 배경과 텍스트를 각각 별도의 호출을 사용하여 그려야 합니다.
알파 프리미티브는 불투명 노드와 인터리빙되며 사용 가능한 경우 초기 z를 트리거할 수 있지만 Item::visible 를 false로 설정하는 것이 항상 더 빠릅니다.
3D 프리미티브와 혼합
씬 그래프는 의사 3D 및 적절한 3D 프리미티브를 지원할 수 있습니다. 예를 들어 ShaderEffect 을 사용하여 "페이지 컬" 효과를 구현하거나 QSGGeometry 및 커스텀 머티리얼을 사용하여 범프맵 원환을 구현할 수 있습니다. 이 과정에서 기본 렌더러가 이미 뎁스 버퍼를 사용하고 있다는 점을 고려해야 합니다.
렌더러는 모델 뷰 및 투영 행렬이 적용된 후 QSGMaterialShader::vertexShader()에서 반환된 버텍스 셰이더를 수정하고 버텍스의 z 값을 압축한 다음 z에 작은 변환을 추가하여 올바른 z 위치에 배치합니다.
압축은 z 값이 0에서 1 범위 내에 있다고 가정합니다.
텍스처 아틀라스
활성 텍스처는 고유한 OpenGL 상태이므로 서로 다른 OpenGL 텍스처를 사용하는 여러 프리미티브를 일괄 처리할 수 없습니다. 이러한 이유로 Qt Quick 씬 그래프에서는 여러 개의 QSGTexture 인스턴스를 큰 텍스처의 작은 하위 영역, 즉 텍스처 아틀라스로 할당할 수 있습니다.
텍스처 아틀라스의 가장 큰 장점은 여러 개의 QSGTexture 인스턴스가 이제 동일한 OpenGL 텍스처 인스턴스를 참조한다는 것입니다. 따라서 이미지 항목, BorderImage 항목, ShaderEffect 항목과 같은 텍스처 그리기 호출을 일괄 처리할 수 있으며, 텍스처를 사용하는 QSGSimpleTextureNode 및 커스텀 QSGGeometryNode와 같은 C++ 유형도 가능합니다.
참고: 큰 텍스처는 텍스처 아틀라스에 들어가지 않습니다.
아틀라스 기반 텍스처는 QQuickWindow::createTextureFromImage()에 QQuickWindow::TextureCanUseAtlas 을 전달하여 만듭니다.
참고: 아틀라스 기반 텍스처에는 0에서 1 사이의 텍스처 좌표가 없습니다. QSGTexture::normalizedTextureSubRect ()를 사용하여 아틀라스 텍스처 좌표를 가져옵니다.
씬 그래프는 휴리스틱을 사용하여 아틀라스의 크기와 아틀라스에 입력할 크기 임계값을 파악합니다. 다른 값이 필요한 경우 환경 변수 QSG_ATLAS_WIDTH=[width]
, QSG_ATLAS_HEIGHT=[height]
및 QSG_ATLAS_SIZE_LIMIT=[size]
를 사용하여 재정의할 수 있습니다. 이러한 값을 변경하는 것은 대부분 플랫폼 공급업체에서 흥미로워할 것입니다.
배치 루트
기본 렌더러는 호환 가능한 프리미티브를 배치로 병합하는 것 외에도 매 프레임마다 GPU로 전송해야 하는 데이터의 양을 최소화하려고 노력합니다. 기본 렌더러는 함께 속한 하위 트리를 식별하고 이를 별도의 배치에 넣으려고 시도합니다. 배치가 식별되면 버텍스 버퍼 오브젝트를 사용하여 병합, 업로드 및 GPU 메모리에 저장됩니다.
트랜스폼 노드
각 Qt Quick 아이템은 씬 그래프 트리에 QSGTransformNode 을 삽입하여 x, y, 스케일 또는 회전을 관리합니다. 이 트랜스폼 노드 아래에 자식 항목이 채워집니다. 기본 렌더러는 프레임 간에 트랜스폼 노드의 상태를 추적하고 하위 트리를 살펴 트랜스폼 노드가 배치 세트의 루트가 될 수 있는 후보인지 여부를 결정합니다. 프레임 간에 변경되고 상당히 복잡한 하위 트리를 가진 트랜스폼 노드는 배치 루트가 될 수 있습니다.
배치 루트의 하위 트리에 있는 QSGGeometryNode는 CPU에서 루트를 기준으로 미리 변환됩니다. 그런 다음 GPU에 업로드되어 유지됩니다. 트랜스폼이 변경되면 렌더러는 각 개별 항목이 아닌 루트의 매트릭스만 업데이트하면 되므로 목록 및 그리드 스크롤이 매우 빨라집니다. 연속된 프레임의 경우 노드를 추가하거나 제거하지 않는 한 목록 렌더링은 사실상 무료입니다. 새로운 콘텐츠가 하위 트리에 들어오면 이를 가져오는 배치가 다시 빌드되지만 여전히 비교적 빠릅니다. 그리드나 목록을 패닝할 때 노드가 추가되거나 제거된 프레임마다 일반적으로 변경되지 않는 프레임이 여러 개 있습니다.
트랜스폼 노드를 배치 루트로 식별하면 렌더러가 트리에서 변경되지 않은 부분을 유지할 수 있다는 또 다른 이점이 있습니다. 예를 들어 UI가 목록과 버튼 행으로 구성되어 있다고 가정해 보겠습니다. 목록이 스크롤되고 델리게이트가 추가 및 제거될 때 나머지 UI인 버튼 행은 변경되지 않으며 이미 GPU에 저장된 지오메트리를 사용하여 그릴 수 있습니다.
트랜스폼 노드가 배치 루트가 되기 위한 노드 및 버텍스 임계값은 환경 변수 QSG_RENDERER_BATCH_NODE_THRESHOLD=[count]
및 QSG_RENDERER_BATCH_VERTEX_THRESHOLD=[count]
을 사용하여 재정의할 수 있습니다. 이 플래그를 재정의하는 것은 대부분 플랫폼 공급업체에 유용합니다.
참고: 배치 루트 아래에는 머티리얼 상태 및 지오메트리 유형의 고유한 세트마다 하나의 배치가 생성됩니다.
클리핑
Item::clip 을 true로 설정하면 지오메트리에 직사각형이 포함된 QSGClipNode 이 생성됩니다. 기본 렌더러는 OpenGL에서 시소링을 사용하여 이 클립을 적용합니다. 항목이 90도가 아닌 각도로 회전하는 경우 OpenGL의 스텐실 버퍼가 사용됩니다. Qt Quick 항목은 QML을 통해 직사각형만 클립으로 설정할 수 있지만 씬 그래프 API와 기본 렌더러는 모든 모양을 클립에 사용할 수 있습니다.
하위 트리에 클립을 적용할 때 해당 하위 트리는 고유한 OpenGL 상태로 렌더링되어야 합니다. 즉, Item::clip 이 참이면 해당 항목의 일괄 처리는 해당 하위 항목으로 제한됩니다. ListView 또는 GridView 과 같이 자식이 많거나 TextArea 과 같이 복잡한 자식이 있는 경우에는 괜찮습니다. 그러나 작은 항목에 클립온을 사용하면 일괄 처리를 방지할 수 있으므로 주의해야 합니다. 여기에는 버튼 레이블, 텍스트 필드, 목록 델리게이트 및 표 셀이 포함됩니다. 불투명한 항목이 플릭커블(또는 항목 보기)의 주변 영역을 덮도록 UI를 배열하고 그렇지 않으면 창 가장자리에 의존하여 다른 모든 항목을 스크랩하는 방식으로 플릭커블을 스크랩하는 것을 피할 수 있습니다.
Item::clip 을 true
으로 설정하면 QQuickItem::ItemIsViewport 플래그도 설정되며, QQuickItem::ItemObservesViewport 플래그가 있는 하위 항목은 뷰포트를 사용하여 대략적인 사전 클리핑 단계를 수행할 수 있습니다(예: Text 은 뷰포트 외부에 있는 텍스트 줄을 생략합니다). 씬 그래프 노드를 생략하거나 vertices 을 제한하는 것은 최적화이며, 이는 QML에서 Item::clip 을 설정하는 대신 C++에서 flags 을 설정하여 달성할 수 있습니다.
사용자 지정 항목에서 QQuickItem::updatePaintNode()를 구현할 때 넓은 지오메트리 영역에 많은 디테일을 렌더링할 수 있는 경우 그래픽을 뷰포트에 제한하는 것이 효율적인지 고려해야 하며, 그렇다면 ItemObservesViewport 플래그를 설정하고 QQuickItem::clipRect()에서 현재 노출된 영역을 읽을 수 있습니다. 그 결과 updatePaintNode()가 더 자주(일반적으로 뷰포트에서 콘텐츠가 움직일 때마다 프레임당 한 번) 호출됩니다.
버텍스 버퍼
각 배치는 버텍스 버퍼 오브젝트(VBO)를 사용하여 GPU에 데이터를 저장합니다. 이 버텍스 버퍼는 프레임 간에 유지되며, 버텍스 버퍼가 나타내는 씬 그래프의 일부가 변경되면 업데이트됩니다.
기본적으로 렌더러는 GL_STATIC_DRAW
를 사용하여 VBO에 데이터를 업로드합니다. 환경 변수 QSG_RENDERER_BUFFER_STRATEGY=[strategy]
를 설정하여 다른 업로드 전략을 선택할 수 있습니다. 유효한 값은 stream
와 dynamic
입니다. 이 값을 변경하는 것은 주로 플랫폼 공급업체에 유용합니다.
앤티앨리어싱
씬 그래프는 두 가지 유형의 앤티앨리어싱을 지원합니다. 기본적으로 직사각형 및 이미지와 같은 프리미티브는 프리미티브의 가장자리를 따라 더 많은 버텍스를 추가하여 가장자리가 투명하게 페이드되도록 앤티앨리어싱을 적용합니다. 이 방법을 버텍스 앤티앨리어싱이라고 합니다. 사용자가 멀티샘플링된 OpenGL 컨텍스트를 요청하는 경우 QQuickWindow::setFormat()를 사용하여 0
보다 큰 샘플로 QSurfaceFormat 을 설정하면 씬 그래프가 멀티샘플 기반 앤티앨리어싱(MSAA)을 선호하게 됩니다. 두 기술은 렌더링이 내부적으로 발생하는 방식에 영향을 미치며 서로 다른 제한이 있습니다.
환경 변수 QSG_ANTIALIASING_METHOD
를 vertex
또는 msaa
로 설정하여 사용되는 앤티앨리어싱 방법을 재정의할 수도 있습니다.
버텍스 앤티앨리어싱은 두 가장자리가 수학적으로 동일한 경우에도 인접한 프리미티브의 가장자리 사이에 이음새를 생성할 수 있습니다. 멀티샘플 안티앨리어싱은 그렇지 않습니다.
버텍스 앤티앨리어싱
버텍스 앤티앨리어싱은 Item::antialiasing 프로퍼티를 사용하여 항목별로 활성화 및 비활성화할 수 있습니다. 기본 하드웨어가 지원하는 것과 관계없이 작동하며, 일반적으로 렌더링되는 프리미티브와 프레임버퍼 오브젝트로 캡처된 프리미티브(예: ShaderEffectSource 유형 사용)에 대해 더 높은 품질의 안티앨리어싱을 생성합니다.
버텍스 앤티앨리어싱 사용의 단점은 앤티앨리어싱이 활성화된 각 프리미티브를 블렌딩해야 한다는 것입니다. 일괄 처리 측면에서 이는 렌더러가 프리미티브가 일괄 처리될 수 있는지 여부를 파악하기 위해 더 많은 작업을 수행해야 하며 씬의 다른 요소와 겹치기 때문에 일괄 처리량이 줄어들어 성능에 영향을 미칠 수 있다는 것을 의미합니다.
저사양 하드웨어에서는 블렌딩 비용이 상당히 높을 수 있으므로 화면의 대부분을 차지하는 이미지나 둥근 사각형의 경우 이러한 프리미티브 내부에 필요한 블렌딩 양이 많으면 전체 프리미티브를 블렌딩해야 하므로 성능이 크게 저하될 수 있습니다.
멀티샘플 앤티앨리어싱
멀티샘플 앤티앨리어싱은 하드웨어가 프리미티브의 픽셀당 커버리지 값을 계산하는 하드웨어 기능입니다. 일부 하드웨어는 매우 낮은 비용으로 멀티샘플링이 가능한 반면, 다른 하드웨어는 프레임 렌더링에 더 많은 메모리와 GPU 주기가 필요할 수 있습니다.
멀티샘플 앤티앨리어싱을 사용하면 둥근 사각형이나 이미지 요소와 같은 많은 프리미티브에 앤티앨리어싱을 적용해도 씬 그래프에서 여전히 불투명할 수 있습니다. 즉, 렌더러가 배치를 생성할 때 작업이 더 쉬워지고 오버드로를 피하기 위해 얼리-Z에 의존할 수 있습니다.
멀티샘플 앤티앨리어싱을 사용하는 경우 프레임버퍼 객체로 렌더링된 콘텐츠는 프레임버퍼의 멀티샘플링을 지원하기 위해 추가 확장이 필요합니다. 일반적으로 GL_EXT_framebuffer_multisample
및 GL_EXT_framebuffer_blit
입니다. 대부분의 데스크톱 칩에는 이러한 확장 기능이 있지만 임베디드 칩에는 덜 일반적입니다. 하드웨어에서 프레임버퍼 멀티샘플링을 사용할 수 없는 경우 프레임버퍼 객체로 렌더링된 콘텐츠는 안티앨리어싱이 적용되지 않으며, 여기에는 ShaderEffectSource.
성능
서두에서 언급했듯이 렌더러의 세부 사항을 이해해야만 좋은 성능을 얻을 수 있는 것은 아닙니다. 일반적인 사용 사례에 최적화하도록 작성되었으며 거의 모든 상황에서 성능이 매우 우수합니다.
- 좋은 성능은 지오메트리를 가능한 한 적게 반복해서 업로드하는 효과적인 일괄 처리에서 비롯됩니다. 환경 변수
QSG_RENDERER_DEBUG=render
를 설정하면 렌더러는 배치가 얼마나 잘 진행되는지, 사용된 배치의 수, 유지되는 배치와 불투명한 배치에 대한 통계를 출력합니다. 최적의 성능을 위해 노력할 때는 업로드는 정말 필요할 때만 이루어져야 하며, 배치는 10개 미만이어야 하고, 그 중 최소 3~4개는 불투명해야 합니다. - 기본 렌더러는 CPU 측 뷰포트 클리핑이나 오클루전 감지를 수행하지 않습니다. 표시되지 않아야 하는 항목은 표시되지 않아야 합니다. 그려서는 안 되는 항목은
Item::visible: false
을 사용하세요. 이러한 로직을 추가하지 않는 가장 큰 이유는 추가 비용이 발생하여 제대로 작동하도록 신경 쓴 애플리케이션이 손상될 수 있기 때문입니다. - 텍스처 아틀라스가 사용되었는지 확인하세요. 이미지와 BorderImage 항목은 이미지가 너무 크지 않은 한 텍스처 아틀라스를 사용합니다. C++로 만든 텍스처의 경우 QQuickWindow::createTexture()를 호출할 때 QQuickWindow::TextureCanUseAtlas 을 전달합니다. 환경 변수
QSG_ATLAS_OVERLAY
를 설정하면 모든 아틀라스 텍스처가 애플리케이션에서 쉽게 식별할 수 있도록 색상이 지정됩니다. - 가능하면 불투명 프리미티브를 사용합니다. 불투명 프리미티브는 렌더러에서 처리하는 속도가 빠르고 GPU에서 그리는 속도가 빠릅니다. 예를 들어 PNG 파일은 각 픽셀이 완전히 불투명하더라도 알파 채널이 있는 경우가 많습니다. JPG 파일은 항상 불투명합니다. QQuickImageProvider 에 이미지를 제공하거나 QQuickWindow::createTextureFromImage()로 이미지를 만들 때는 가능하면 이미지에 QImage::Format_RGB32 를 사용하세요.
- 위 그림과 같이 겹치는 복합 항목은 일괄 처리할 수 없다는 점에 유의하세요.
- 클리핑하면 일괄 처리가 중단됩니다. 항목 단위, 표 셀 내부, 항목 델리게이트 등에서는 절대로 사용하지 마세요. 텍스트 클리핑 대신 엘리딩을 사용하세요. 이미지를 잘라내는 대신 잘린 이미지를 반환하는 QQuickImageProvider 을 만듭니다.
- 일괄 처리는 16비트 인덱스에 대해서만 작동합니다. 모든 기본 제공 항목은 16비트 인덱스를 사용하지만 사용자 정의 지오메트리는 32비트 인덱스도 자유롭게 사용할 수 있습니다.
- 일부 머티리얼 플래그는 일괄 처리를 방지하며, 가장 제한적인 것은 QSGMaterial::RequiresFullMatrix 으로 모든 일괄 처리를 방지합니다.
- 단색 배경을 사용하는 애플리케이션은 최상위 직사각형 항목을 사용하는 대신 QQuickWindow::setColor()를 사용하여 설정해야 합니다. QQuickWindow::setColor()는
glClear()
로의 호출에 사용되며, 이는 잠재적으로 더 빠릅니다. - 밉맵 이미지 항목은 글로벌 아틀라스에 배치되지 않으며 일괄 처리되지 않습니다.
- 프레임버퍼 객체(FBO) 읽기백과 관련된 OpenGL 드라이버의 버그로 인해 렌더링된 글리프가 손상될 수 있습니다.
QML_USE_GLYPHCACHE_WORKAROUND
환경 변수를 설정하면 Qt는 RAM에 글리프의 추가 복사본을 유지합니다. 즉, 이전에 그려지지 않은 글리프를 그릴 때 Qt가 CPU를 통해 추가 복사본에 액세스하기 때문에 성능이 약간 저하됩니다. 또한 글리프 캐시가 두 배의 메모리를 사용한다는 의미이기도 합니다. 품질에는 영향을 미치지 않습니다.
애플리케이션의 성능이 저하된다면 실제로 렌더링이 병목 현상인지 확인하세요. 프로파일러를 사용하세요! 환경 변수 QSG_RENDER_TIMING=1
는 문제가 있는 위치를 정확히 파악하는 데 유용한 여러 가지 유용한 타이밍 매개변수를 출력합니다.
시각화
씬 그래프의 기본 렌더러의 다양한 측면을 시각화하려면 QSG_VISUALIZE
환경 변수를 아래 각 섹션에 설명된 값 중 하나로 설정할 수 있습니다. 다음 QML 코드를 사용하여 일부 변수의 출력 예시를 제공합니다:
import QtQuick 2.2 Rectangle { width: 200 height: 140 ListView { id: clippedList x: 20 y: 20 width: 70 height: 100 clip: true model: ["Item A", "Item B", "Item C", "Item D"] delegate: Rectangle { color: "lightblue" width: parent.width height: 25 Text { text: modelData anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } } ListView { id: clippedDelegateList x: clippedList.x + clippedList.width + 20 y: 20 width: 70 height: 100 clip: true model: ["Item A", "Item B", "Item C", "Item D"] delegate: Rectangle { color: "lightblue" width: parent.width height: 25 clip: true Text { text: modelData anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } } }
왼쪽의 ListView 의 경우 clip 속성을 true
로 설정했습니다. 오른쪽의 ListView 의 경우 각 델리게이트의 clip 속성을 true
로 설정하여 일괄 처리에 대한 클리핑의 효과를 설명합니다.
원본
참고: 시각화된 요소는 클리핑을 고려하지 않으며 렌더링 순서는 임의로 지정할 수 있습니다.
배치 시각화하기
QSG_VISUALIZE
을 batches
으로 설정하면 렌더러에서 배치를 시각화합니다. 병합된 배치는 단색으로 그려지고 병합되지 않은 배치는 대각선 패턴으로 그려집니다. 고유한 색상이 적을수록 일괄 처리가 잘 이루어집니다. 병합되지 않은 배치는 개별 노드가 많으면 좋지 않습니다.
QSG_VISUALIZE=batches
클리핑 시각화하기
QSG_VISUALIZE
을 clip
으로 설정하면 장면 위에 빨간색 영역이 그려져 클리핑을 나타냅니다. Qt Quick 항목은 기본적으로 클리핑되지 않으므로 일반적으로 클리핑이 시각화되지 않습니다.
QSG_VISUALIZE=clip
변경 사항 시각화
QSG_VISUALIZE
을 changes
으로 설정하면 렌더러의 변경 사항이 시각화됩니다. 시나리오 그래프의 변경 사항은 임의의 색상으로 깜박이는 오버레이로 시각화됩니다. 프리미티브의 변경 사항은 단색으로 시각화되며, 매트릭스 또는 불투명도 변경과 같은 조상의 변경 사항은 패턴으로 시각화됩니다.
오버드로 시각화하기
QSG_VISUALIZE
을 overdraw
으로 설정하면 렌더러에서 오버드로가 시각화됩니다. 모든 항목을 3D로 시각화하여 오버드로를 강조합니다. 이 모드는 뷰포트 외부의 지오메트리를 어느 정도 감지하는 데에도 사용할 수 있습니다. 불투명 항목은 녹색 색조로 렌더링되고 반투명 항목은 빨간색 색조로 렌더링됩니다. 뷰포트의 경계 상자는 파란색으로 렌더링됩니다. 불투명 콘텐츠는 시나리오 그래프가 처리하기 쉽고 일반적으로 렌더링 속도가 빠릅니다.
위 코드의 루트 사각형은 창도 흰색이므로 불필요하므로 이 경우 직사각형을 그리는 것은 리소스 낭비입니다. 이를 아이템으로 변경하면 약간의 성능 향상을 얻을 수 있습니다.
QSG_VISUALIZE=overdraw
Qt 렌더링 하드웨어 인터페이스를 통한 렌더링
Qt 6.0 이상부터는 기본 적응은 항상 그래픽 추상화 레이어인 Qt 렌더링 하드웨어 인터페이스(RHI)를 통해 렌더링합니다. Qt GUI 모듈에서 제공합니다. 즉, Qt 5와 달리 씬 그래프에서 직접 OpenGL을 호출하지 않습니다. 그 대신 RHI API를 사용하여 리소스 및 그리기 명령을 기록한 다음 명령 스트림을 OpenGL, Vulkan, Metal 또는 Direct 3D 호출로 변환합니다. 셰이더 처리도 셰이더 코드를 한 번 작성하고 SPIR-V로 컴파일한 다음 다양한 그래픽 API에 적합한 언어로 번역하는 방식으로 통합됩니다.
동작을 제어하기 위해 다음 환경 변수를 사용할 수 있습니다:
환경 변수 | 가능한 값 | 설명 |
---|---|---|
QSG_RHI_BACKEND | vulkan , metal , opengl , d3d11 , d3d12 | 특정 RHI 백엔드를 요청합니다. 기본적으로 타겟 그래픽 API는 이 변수나 동등한 C++ API로 재정의하지 않는 한 플랫폼에 따라 선택됩니다. 기본값은 현재 Windows의 경우 Direct3D 11, macOS의 경우 Metal, 그 외의 경우 OpenGL입니다. |
QSG_INFO | 1 | OpenGL 기반 렌더링 경로와 마찬가지로 이 변수를 설정하면 Qt Quick 씬 그래프를 초기화할 때 시스템 정보를 인쇄할 수 있습니다. 이는 문제 해결에 매우 유용할 수 있습니다. |
QSG_RHI_DEBUG_LAYER | 1 | 해당되는 경우(Vulkan, Direct3D) 그래픽 장치 또는 인스턴스 오브젝트에서 그래픽 API 구현의 디버그 또는 유효성 검사 레이어(사용 가능한 경우)를 활성화합니다. macOS의 Metal의 경우 환경 변수 METAL_DEVICE_WRAPPER_TYPE=1 를 대신 설정합니다. |
QSG_RHI_PREFER_SOFTWARE_RENDERER | 1 | 소프트웨어 기반 래스터화를 사용하는 어댑터 또는 물리적 디바이스를 선택하도록 요청합니다. 기본 API가 어댑터 열거를 지원하는 경우에만 적용되며(예: Direct3D 또는 Vulkan), 그렇지 않은 경우 무시됩니다. |
항상 지정된 단일 그래픽 API로 실행하려는 애플리케이션은 C++를 통해서도 이를 요청할 수 있습니다. 예를 들어, QQuickWindow 을 구성하기 전에 main() 초반에 다음 호출을 수행하면 Vulkan을 강제로 사용합니다(그렇지 않으면 실패합니다):
QQuickWindow::setGraphicsApi(QSGRendererInterface::Vulkan);
QSGRendererInterface::GraphicsApi 을 참조하세요. 열거형 값 OpenGL
, Vulkan
, Metal
, Direct3D11
, Direct3D12
은 QSG_RHI_BACKEND
을 동등한 문자열 키로 설정하여 실행하는 것과 사실상 동일합니다.
모든 QRhi 백엔드는 QSG_RHI_PREFER_SOFTWARE_RENDERER
또는 QT_D3D_ADAPTER_INDEX
또는 QT_VK_PHYSICAL_DEVICE_INDEX
과 같은 백엔드 전용 변수로 재정의하지 않는 한 시스템 기본 GPU 어댑터 또는 물리적 장치를 선택합니다. 현재로서는 더 이상의 어댑터 구성 기능이 제공되지 않습니다.
Qt 6.5부터는 이전에는 환경 변수로만 노출되었던 설정 중 일부를 QQuickGraphicsConfiguration 에서 C++ API로 사용할 수 있습니다. 예를 들어 QSG_RHI_DEBUG_LAYER
을 설정하는 것과 setDebugLayer(true)를 호출하는 것은 동일합니다.
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.