임베디드 리눅스용 Qt
임베디드 Linux 디바이스용 플랫폼 플러그인
임베디드 Linux 시스템에서 사용할 수 있는 플랫폼 플러그인은 여러 가지가 있습니다: EGLFS, VkKhrDisplay, LinuxFB, 또는 Wayland. 이러한 플러그인의 사용 가능 여부는 Qt의 구성 방식에 따라 다릅니다. 이 중 Wayland는 컴포저가 있어야 하며, X11이나 Windows와 유사하게 다중 창을 지원하는 전체 창 시스템을 제공합니다. 나머지는 윈도우 시스템 없이 작동하며, 이는 Qt 애플리케이션이 렌더링과 출력을 완전히 제어한다는 의미입니다. 이들은 일반적으로 화면당 하나의 전체 화면 Qt "창"을 지원합니다.
EGLFS는 많은 보드의 기본 플러그인입니다. 적합하지 않은 경우 QT_QPA_PLATFORM
환경 변수를 사용하여 다른 플러그인을 요청하세요. 또는 빠른 테스트를 위해 동일한 구문으로 -platform
명령줄 인수를 사용하세요.
참고: Qt 5.0부터 Qt는 더 이상 자체 창 시스템(QWS)을 구현하지 않습니다. 단일 프로세스 사용 사례의 경우 Qt 플랫폼 추상화가 우수한 솔루션이며, 다중 프로세스 사용 사례는 Wayland를 통해 지원됩니다.
임베디드 리눅스 툴체인을 사용하여 크로스 컴파일을 위한 Qt 구성에 대한 개요는 임베디드 리눅스 디바이스 구성을 참조하십시오.
EGLFS
EGL은 OpenGL과 네이티브 윈도우 시스템 사이의 인터페이스입니다. Qt는 컨텍스트와 서피스 관리를 위해 EGL을 사용할 수 있지만, API에는 플랫폼에 특화된 기능이 없습니다. 화면에 실제 창이 아닐 수도 있는 네이티브 창을 생성하려면 여전히 플랫폼별 수단을 사용해야 합니다. 그렇기 때문에 보드 또는 GPU별 적응 코드가 필요합니다. 일반적으로 이러한 적응 코드는 다음과 같이 제공됩니다:
- EGLFS 후크 - 플랫폼 플러그인으로 컴파일된 단일 소스 파일
- EGL 장치 통합 - 동적으로 로드되는 플러그인
EGLFS는 X11이나 Wayland와 같은 실제 윈도우 시스템 없이 EGL 및 OpenGL ES 2.0 위에서 Qt 애플리케이션을 실행하기 위한 플랫폼 플러그인입니다. GPU가 포함된 최신 임베디드 Linux 장치에 권장되는 플러그인입니다.
Qt Quick 및 기본 OpenGL 애플리케이션 외에도 EGLFS는 QWidget 과 같은 소프트웨어 렌더링 창도 지원합니다. QWidget 의 경우 위젯의 콘텐츠는 CPU를 사용하여 이미지로 렌더링된 다음 텍스처로 업로드되고 플러그인에 의해 합성됩니다.
EGLFS는 첫 번째 최상위 창( QWidget 또는 QQuickView )이 전체 화면이 되도록 강제합니다. 이 창은 다른 모든 최상위 위젯이 합성되는 루트 위젯 창으로 선택되기도 합니다. 예를 들어 대화 상자, 팝업 메뉴 또는 콤보 상자가 여기에 해당합니다. 이 동작이 필요한 이유는 EGLFS에는 항상 정확히 하나의 기본 창과 하나의 EGL 창 표면이 있으며, 이들은 먼저 생성된 위젯 또는 창에 속하기 때문입니다. 이 접근 방식은 애플리케이션의 수명 동안 존재하는 기본 창이 있고 다른 모든 위젯이 최상위 수준이 아니거나 기본 창이 표시된 후에 생성되는 경우 잘 작동합니다.
OpenGL 기반 창에는 추가적인 제한 사항이 있습니다. EGLFS는 OpenGL 기반 QWindow, QQuickView 또는 QOpenGLWidget 와 같은 단일 전체 화면 GL 창(Qt 5.3부터)만 지원합니다. 추가 OpenGL 창을 열거나 이러한 창을 QWidget 기반 콘텐츠와 혼합하는 것은 지원되지 않으며, Qt는 오류 메시지와 함께 어플리케이션을 종료합니다.
또한 데스크톱 플랫폼이나 드래그 앤 드롭과 같은 윈도우 시스템이 있는 환경을 위해 설계된 API는 EGLFS에서 지원되지 않습니다.
EGLFS에서 사용하는 환경 변수
필요한 경우 다음 환경 변수를 사용하여 eglfs
을 구성할 수 있습니다:
환경 변수 | 설명 |
---|---|
QT_QPA_EGLFS_INTEGRATION | 컴파일된 후크 외에도 동적으로 로드된 플러그인을 사용하여 장치 또는 공급업체별 적응을 제공할 수도 있습니다. 이 환경 변수는 특정 플러그인을 적용합니다. 예를 들어, eglfs_kms로 설정하면 KMS/DRM 백엔드를 사용합니다. 이는 디바이스 메이크스펙에 정적 또는 컴파일된 훅이 지정되지 않은 경우에만 사용할 수 있는 옵션입니다. 실제로 기존의 컴파일된 후크는 거의 사용되지 않으며, 거의 모든 백엔드는 이제 플러그인으로 마이그레이션됩니다. 장치 메이크스펙에는 여전히 선택 사항이지만 관련성이 있는 EGLFS_DEVICE_INTEGRATION 항목(특정 장치에 대해 선호하는 백엔드의 이름)이 포함되어 있습니다. 대상 시스템에 플러그인이 두 개 이상 있는 경우에는 이 환경 변수를 설정하지 마세요. 데스크톱 환경에서는 DISPLAY 환경 변수의 존재 여부에 따라 KMS 또는 X11 백엔드의 우선순위가 정해집니다.참고: 일부 보드에서는 실제 플러그인 대신 |
QT_QPA_EGLFS_PHYSICAL_WIDTH 및 QT_QPA_EGLFS_PHYSICAL_HEIGHT | 실제 화면의 너비와 높이를 밀리미터 단위로 지정합니다. Qt 6부터 물리적 화면 크기는 더 이상 논리적 dpi를 결정하는 데 사용되지 않습니다. |
QT_QPA_EGLFS_ROTATION | QWidget 기반 애플리케이션에서 소프트웨어 렌더링 콘텐츠에 적용되는 회전을 지정합니다. 지원되는 값은 180, 90, -90입니다. 이 변수는 Qt Quick 를 포함한 OpenGL 기반 창에는 적용되지 않습니다. Qt Quick 애플리케이션은 대신 QML 장면에서 변환을 적용할 수 있습니다. 표준 eglfs 마우스 커서는 애플리케이션 유형에 관계없이 항상 적절한 위치 및 회전된 포인터 이미지와 함께 값을 고려합니다. 그러나 KMS/DRM 백엔드의 하드웨어 커서와 같은 특수 커서 구현은 회전을 지원하지 않을 수 있습니다. |
QT_QPA_EGLFS_FORCEVSYNC | 이 변수를 설정하면 eglfs 은 eglSwapBuffers()를 호출할 때마다 프레임버퍼 장치에 FBIO_WAITFORVSYNC 을 요청합니다. 이 변수는 레거시 Linux fbdev 서브시스템에 의존하는 백엔드에만 해당됩니다. 일반적으로 기본 스왑 간격이 1인 경우, Qt는 eglSwapBuffers() 호출이 vsync를 처리한다고 가정합니다; 그렇지 않은 경우(예: 드라이버 버그 등으로 인해) QT_QPA_EGLFS_FORCEVSYNC 을 0이 아닌 값으로 설정해 보십시오. |
QT_QPA_EGLFS_FORCE888 | 설정하면 eglfs 에서 새 컨텍스트, 창 또는 오프스크린 표면을 만들 때 빨간색, 초록색, 파란색 채널 크기가 무시됩니다. 대신 플러그인은 채널당 8비트로 구성을 요청합니다. 이는 픽셀당 32비트 또는 24비트 미만의 구성(예: 5-6-5 또는 4-4-4)이 밴딩 효과 등으로 인해 이상적이지 않다는 것을 알면서도 기본적으로 선택되는 디바이스에서 유용할 수 있습니다. 이 변수는 애플리케이션 코드를 변경하는 대신 24비트 또는 32비트 구성을 강제로 적용하는 지름길을 제공합니다. |
또한 다음과 같이 덜 일반적으로 사용되는 변수를 사용할 수 있습니다:
환경 변수 | 설명 |
---|---|
QT_QPA_EGLFS_FB | 프레임버퍼 장치를 재정의합니다. 기본값은 /dev/fb0 입니다. 대부분의 임베디드 플랫폼에서는 프레임버퍼가 디스플레이 크기와 같은 설정을 쿼리하는 데만 사용되므로 이 변수는 크게 관련이 없습니다. 그러나 특정 장치에서 이 변수는 LinuxFB의 fb 매개변수와 유사하게 여러 디스플레이 설정에서 사용할 디스플레이를 지정할 수 있는 기능을 제공합니다. |
QT_QPA_EGLFS_WIDTH 및 QT_QPA_EGLFS_HEIGHT | 화면의 너비와 높이를 픽셀 단위로 포함합니다. eglfs 은 프레임버퍼 장치 /dev/fb0에서 치수를 확인하려고 시도하지만 항상 작동하는 것은 아닙니다. 크기를 수동으로 지정해야 할 수도 있습니다. |
QT_QPA_EGLFS_DEPTH | 화면의 색 농도를 재정의합니다. 프레임버퍼 디바이스 /dev/fb0을 사용할 수 없거나 쿼리가 성공하지 못하는 플랫폼에서는 기본값 32 이 사용됩니다. 이러한 기본값을 재정의하려면 이 변수를 사용합니다.참고: 이 변수는 QScreen 에서 보고하는 색 농도 값에만 영향을 줍니다. 이 변수는 EGL 구성 및 OpenGL 렌더링에 사용되는 색 농도와는 관련이 없습니다. |
QT_QPA_EGLFS_SWAPINTERVAL | 기본적으로 1 의 스왑 간격이 요청됩니다. 이 변수를 사용하면 디스플레이의 수직 새로 고침과 동기화할 수 있습니다. 이 변수를 사용하여 스왑 간격의 값을 재정의할 수 있습니다. 예를 들어 0을 전달하면 스왑 시 차단이 비활성화되어 동기화 없이 최대한 빠르게 실행됩니다. |
QT_QPA_EGLFS_DEBUG | 설정하면 디버그 출력에 일부 디버깅 정보가 인쇄됩니다. 예를 들어, 새 컨텍스트를 생성하는 동안 QSurfaceFormat 입력과 선택한 EGL 구성의 속성이 인쇄됩니다. Qt Quick 의 QSG_INFO 변수와 함께 사용하면 EGL 구성과 관련된 문제를 해결하는 데 유용한 정보를 얻을 수 있습니다. |
로깅
QT_QPA_EGLFS_DEBUG
, eglfs
은 Qt의 최신 범주화된 로깅 시스템도 지원합니다. 다음과 같은 로깅 범주를 사용할 수 있습니다:
qt.qpa.egldeviceintegration
- 동적으로 로드된 백엔드에 대한 로깅을 활성화합니다. 이 카테고리를 사용하여 어떤 백엔드가 사용 중인지 확인할 수 있습니다.qt.qpa.input
-evdev
및libinput
입력 핸들러 모두에서 디버그 출력을 활성화합니다. 이 카테고리를 사용하여 지정된 입력 장치가 인식되고 열렸는지 확인하세요.qt.qpa.eglfs.kms
- KMS/DRM 백엔드에서 자세한 로깅을 사용 설정합니다.
configure
을 실행한 후 출력을 검사하세요. 이 방법은 필요한 EGLFS 백엔드, libudev 또는 libinput이 활성화되어 있는지 여부를 가장 쉽고 빠르게 확인할 수 있는 방법입니다. 간단히 말해, configure
출력에 원치 않는 "아니오"가 있으면 실행하세요:
./configure -v
를 실행하여 상세 출력을 켜면 각 구성 테스트에 대한 컴파일러 및 링커 호출을 볼 수 있습니다.
참고: 누락된 헤더, 라이브러리 또는 암호로 보이는 링커 실패에 대한 오류가 발생하는 경우, 이는 종종 불완전하거나 손상된 시스템 루트의 신호이며 Qt와는 관련이 없습니다.
예를 들어, Broadcom 독점 그래픽 드라이버로 Raspberry Pi를 타겟팅하는 경우 출력에 다음과 같은 내용이 포함되어야 합니다:
QPA backends: EGLFS ................................ yes EGLFS details: EGLFS i.Mx6 ........................ no EGLFS i.Mx6 Wayland ................ no EGLFS EGLDevice .................... no EGLFS GBM .......................... no EGLFS Mali ......................... no EGLFS Raspberry Pi ................. yes EGL on X11 ......................... no
그렇지 않은 경우 나머지 Qt가 성공적으로 컴파일되더라도 라즈베리 파이 전용 백엔드가 없으면 가속 그래픽이 작동하지 않으므로 빌드를 더 이상 진행하지 않는 것이 좋습니다.
VkKhrDisplay
EGLFS는 OpenGL(ES)만 지원하지만, VkKhrDisplay는 Vulkan API로 렌더링을 지원하는 실험적인 플랫폼 플러그인입니다. 디스플레이를 열거하고 렌더링을 설정하기 위해 VK_KHR_display 확장 제품군에 의존합니다. 그래픽 스택 내의 벌칸 구현이 이 기능을 지원한다는 것은 전제되지 않는다는 점에 유의하세요. 현재 이 플랫폼 플러그인은 라즈베리 파이 4에서 실행되는 Mesa 및 V3DV로 검증 및 테스트되었습니다.
이 플랫폼 플러그인은 OpenGL 또는 소프트웨어 렌더링을 지원하지 않습니다. 따라서 QWidget 기반 사용자 인터페이스를 표시하려고 시도하면 실패합니다. 지원되는 유일한 QWindow 표면 유형은 QSurface::VulkanSurface 입니다. Qt Quick 애플리케이션의 경우 이는 QQuickWindow 또는 QQuickView 을 생성하기 전에 환경에서 QSG_RHI_BACKEND=vulkan
을 설정하거나 QQuickWindow::setGraphicsApi(QSGRendererInterface::Vulkan)을 호출하여 Vulkan 기반 렌더링을 적용해야 함을 의미합니다.
이 플랫폼 플러그인을 사용하려면 -platform vkkhrdisplay
로 애플리케이션을 실행하거나 QT_QPA_PLATFORM
을 vkkhrdisplay
로 설정하세요. 이 플러그인은 Qt가 Vulkan을 지원하도록 구성된 경우에만 빌드됩니다.
고급 EGLFS 스타일 구성(예: JSON 구성 파일) 또는 동일한 애플리케이션에서 여러 화면으로 출력하는 기능은 현재 구현되지 않습니다. 그러나 애플리케이션은 환경 변수를 통해 사용할 화면을 선택할 수 있습니다.
인덱스 값을 확인하려면 플러그인에서 디버그 출력에 출력되는 로그를 확인하세요. 대부분의 경우 플러그인이 적절한 화면과 모드를 선택하기 위해서는 로그 검사가 필수적이므로 현재 이러한 로그는 분류되지 않은 상태입니다( qDebug)로 출력됩니다.
QT_VK_DISPLAY_INDEX
- 설정하면 지정된 인덱스가 있는 디스플레이가 사용됩니다.QT_VK_MODE_INDEX
- 설정되면 지정된 인덱스가 있는 모드가 사용됩니다.QT_VK_PHYSICAL_DEVICE_INDEX
- 설정하면 지정된 인덱스의 Vulkan 물리적 장치가 사용됩니다. 대부분의 경우 임베디드에서는 관련이 없습니다. 이 변수는 나머지 Qt 그래픽 스택에서도 사용된다는 점에 유의하세요.
입력(키보드, 마우스, 터치) 처리는 EGLFS와 유사하며 evdev
, libinput
, tslib
를 지원합니다. 그러나 마우스 커서 렌더링은 구현되어 있지 않습니다. 이는 이 환경에는 하드웨어 커서라는 개념이 없기 때문이며, 플랫폼 플러그인 내에서 Vulkan으로 커서를 렌더링하는 것은 EGLFS가 OpenGL에서 하는 것과 유사하게 여러 가지 이유로 문제가 있습니다. 따라서 이 플랫폼 플러그인은 현재로서는 마우스 기반 입력에 적합하지 않습니다.
관련 환경 변수는 다음과 같습니다:
QT_QPA_DISABLE_INPUT
- 키보드/마우스/터치 입력을 비활성화합니다.QT_QPA_NO_LIBINPUT
- libinput을 사용할 수 있는 경우에도 evdev 기반 입력 핸들러를 선호합니다.QT_QPA_TSLIB
- 레거시 tslib 라이브러리를 사용하여 요청합니다.
LinuxFB
이 플러그인은 Linux의 fbdev 하위 시스템을 통해 프레임버퍼에 직접 씁니다. 소프트웨어 렌더링 콘텐츠만 지원됩니다. 일부 설정에서는 디스플레이 성능이 제한될 수 있습니다. software
이 플랫폼 플러그인에서 Qt Quick 애플리케이션을 사용하려면 환경에서 QT_QUICK_BACKEND=software
을 설정하거나 setGraphicsApi()를 호출하여 QSGRendererInterface::Software 시나리오 그래프 백엔드를 사용해야 합니다. QWidget 애플리케이션 또는 QWindow 표면 유형이 QSurface::RasterSurface 인 애플리케이션은 지원되지만 QOpenGLWidget 과 같은 특수 위젯은 포함되지 않습니다.
Linux 커널에서 fbdev가 더 이상 사용되지 않으므로 DRM 덤 버퍼 지원도 사용할 수 있습니다. 이를 사용하려면 QT_QPA_FB_DRM
환경 변수를 0이 아닌 값으로 설정하세요. 이 변수를 설정하면 시스템에서 덤 버퍼가 지원되는 경우 /dev/fb0
같은 레거시 프레임버퍼 장치에 액세스하지 않습니다. 대신, 렌더링은 EGLFS의 eglfs_kms
백엔드와 유사한 DRM API를 통해 설정됩니다. 출력은 이중 버퍼링 및 페이지 플립이 적용되어 소프트웨어 렌더링 콘텐츠에 대해서도 적절한 동기화 기능을 제공합니다.
참고: 덤 버퍼가 사용 중인 경우 물리적 및 논리적 화면 크기와 같은 속성이 모두 자동으로 쿼리되므로 아래에 설명된 옵션 중 어느 것도 적용되지 않습니다.
추가 설정 지정하기
linuxfb
플러그인을 사용하면 QT_QPA_PLATFORM
환경 변수 또는 -platform
명령줄 옵션을 통해 추가 설정을 지정할 수 있습니다. 예를 들어 QT_QPA_PLATFORM=linuxfb:fb=/dev/fb1
은 기본값 fb0
대신 프레임버퍼 장치 /dev/fb1
를 사용하도록 지정합니다. 여러 설정을 지정하려면 mw를 콜론(:)으로 구분하세요.
설정 | 설명 |
---|---|
fb=/dev/fbN | 프레임버퍼 장치를 지정합니다. 다중 디스플레이 설정에서 이 설정을 사용하면 여러 디스플레이에서 애플리케이션을 실행할 수 있습니다. 현재 하나의 Qt 응용 프로그램에서 여러 프레임 버퍼를 사용할 수 있는 방법은 없습니다. |
size= <폭>x <높이> | 화면 크기를 픽셀 단위로 지정합니다. 플러그인은 프레임버퍼 장치에서 물리적 및 논리적 디스플레이 치수를 쿼리하려고 시도합니다. 그러나 이 쿼리가 항상 적절한 결과를 가져오는 것은 아니므로 값을 명시적으로 지정해야 할 수도 있습니다. |
mmsize= <폭>x <높이> | 물리적 너비와 높이를 밀리미터 단위로 지정합니다. |
offset= <폭>x <높이 | 화면의 왼쪽 상단 모서리 오프셋을 픽셀 단위로 지정합니다. 기본 위치는 (0, 0) 입니다. |
nographicsmodeswitch | 가상 터미널을 그래픽 모드로 전환하지 않도록 지정합니다(KD_GRAPHICS ). 일반적으로 그래픽 모드를 활성화하면 커서 깜박임 및 화면 공백이 비활성화됩니다. 그러나 이 매개 변수를 설정하면 이 두 기능도 건너뜁니다. |
tty=/dev/ttyN | 가상 콘솔을 재정의합니다. nographicsmodeswitch 이 설정되지 않은 경우에만 사용됩니다. |
Qt 5.9부터 창 크기 조정 정책과 관련하여 EGLFS와 LinuxFB의 동작이 동기화되었습니다: 첫 번째 최상위 창은 두 플랫폼 플러그인 모두에서 전체 화면을 강제로 덮도록 합니다. 이를 원하지 않는 경우 QT_QPA_FB_FORCE_FULLSCREEN
환경 변수를 0
으로 설정하여 이전 Qt 버전의 동작을 복원하세요.
출력 표시
단일 Qt 애플리케이션에서 하나 이상의 디스플레이를 대상으로 하는 지원 수준은 플랫폼 플러그인마다 다릅니다. 지원은 종종 장치와 그래픽 스택에 따라 달라집니다.
eglfs_kms 백엔드를 사용하는 EGLFS
KMS/DRM 백엔드가 사용 중일 때 EGLFS는 QGuiApplication::screens()에서 사용 가능한 모든 화면을 보고합니다. 애플리케이션은 QWindow::setScreen()를 통해 다른 창으로 다른 화면을 타겟팅할 수 있습니다.
참고: 화면당 하나의 전체 화면 창 제한은 여전히 적용됩니다. QWindow 을 표시한 후 화면을 변경하는 것도 지원되지 않습니다. 따라서 임베디드 애플리케이션은 QWindow::show()을 호출하기 전에 필요한 모든 QWindow::setScreen() 호출을 수행해야 합니다.
특정 임베디드 디바이스에서 개발을 시작할 때 디바이스 및 드라이버의 동작과 연결된 디스플레이가 정상적으로 작동하는지 확인해야 하는 경우가 많습니다. 한 가지 쉬운 방법은 헬로우윈도우 예제를 사용하는 것입니다. -platform eglfs --multiscreen --timeout
인수를 사용하여 실행하면 연결된 각 화면에 몇 초 동안 회전하는 Qt 로고가 표시됩니다.
사용자 지정 구성
KMS/DRM 백엔드는 JSON 파일을 통한 사용자 지정 구성도 지원합니다. 이를 활성화하려면 QT_QPA_EGLFS_KMS_CONFIG
환경 변수를 파일 이름으로 설정하세요. Qt 리소스 시스템을 통해 이 파일을 애플리케이션에 임베드할 수도 있습니다.
이러한 구성 옵션의 대부분은 버퍼 관리 기술(GBM 또는 EGLStreams)에 관계없이 모든 KMS/DRM 기반 백엔드에 적용됩니다.
다음은 구성 예시입니다:
{ "device": "/dev/dri/card1", "hwcursor": false, "pbuffers": true, "outputs": [ { "name": "VGA1", "mode": "off" }, { "name": "HDMI1", "mode": "1024x768" } ] }
여기서는 지정된 장치를 다음과 같이 구성합니다:
- 하드웨어 커서를 사용하지 않습니다(OpenGL을 통한 마우스 커서 렌더링으로 되돌아갑니다. 기본적으로 하드웨어 커서가 더 효율적이기 때문에 활성화되어 있습니다).
- 표준 EGL p버퍼 표면으로 QOffscreenSurface (기본적으로 비활성화되어 있으며 대신 gbm 표면이 사용됨)을 지원합니다.
- VGA 커넥터의 출력은 비활성화된 반면, HDMI는 1024x768의 해상도로 활성화됩니다.
또한 이러한 구성에서는 libudev
을 통한 장치 검색도 비활성화되며, 대신 지정된 장치가 사용됩니다.
mode
을 정의하지 않으면 시스템에서 선호하는 모드가 선택됩니다. mode
에 허용되는 값은 다음과 같습니다: off
, current
, preferred
, skip
, 너비x
높이, 너비x
높이@
vrefresh 또는 모델라인 문자열입니다.
current
을 지정하면 현재 모드와 일치하는 해상도의 모드가 선택됩니다. 모드 설정은 원하는 모드가 실제로 활성 모드와 다른 경우에만 수행되므로( QT_QPA_EGLFS_ALWAYS_SET_MODE
환경 변수를 통해 강제하지 않는 한), 이 값은 현재 모드와 Qt가 건드리지 않은 평면의 모든 콘텐츠를 유지하는 데 유용합니다.
skip
는 출력용 커넥터를 마치 연결이 끊어진 것처럼 무시합니다. off
는 비슷하지만 모드를 변경하고 디스플레이를 끕니다.
기본 동작
기본적으로 DRM 계층에서 보고하는 모든 화면은 하나의 큰 가상 데스크톱으로 취급됩니다. 마우스 커서 구현은 이를 고려하여 예상대로 화면을 가로질러 이동합니다. 권장되지는 않지만 구성에서 separateScreens
을 false
으로 설정하여 가상 데스크톱을 비활성화할 수 있습니다.
기본적으로 가상 데스크톱은 시스템에서 보고한 커넥터 순서에 따라 왼쪽에서 오른쪽으로 형성됩니다. 이를 변경하려면 virtualIndex
을 0부터 시작하는 값으로 설정하세요.
예를 들어, 다음 구성은 기본 해상도를 사용하지만 가상 데스크톱의 왼쪽이 HDMI 포트에 연결된 화면이고 오른쪽이 DisplayPort에 연결된 화면이 되도록 합니다:
{ "device": "drm-nvdc", "outputs": [ { "name": "HDMI1", "virtualIndex": 0 }, { "name": "DP1", "virtualIndex": 1 } ] }
배열의 요소 순서는 중요하지 않습니다. 지정되지 않은 가상 인덱스가 있는 출력은 다른 출력 뒤에 배치되며, DRM 커넥터 목록의 원래 순서는 그대로 유지됩니다.
수직 데스크톱 공간을 만들려면(즉, 왼쪽에서 오른쪽이 아닌 위에서 아래로 쌓아 올리려면) device
뒤에 vertical
값을 사용하여 virtualDesktopLayout
속성을 추가합니다.
경고: 가상 데스크톱의 모든 화면에서 동일한 해상도를 사용하는 것이 좋습니다. 그렇지 않으면 마우스 커서 같은 요소가 특정 화면에만 존재하는 영역에 들어갈 때 예기치 않은 방식으로 작동할 수 있습니다.
virtualIndex
으로 충분하지 않은 경우 virtualPos
속성을 사용하여 해당 화면의 왼쪽 상단 위치를 명시적으로 지정할 수 있습니다. 앞의 예를 들어 HDMI1의 해상도가 1080p라고 가정하면 다음 코드 스니펫은 첫 번째 화면 아래에 두 번째 HDMI 기반 화면을 배치합니다:
{ ... "outputs": [ ... { "name": "HDMI2", "virtualPos": "0, 1080" } ] }
참고: 마우스 지원이 필요한 경우에는 이러한 구성을 피하세요. 비선형 레이아웃에서는 마우스 커서의 동작이 예기치 않게 발생할 수 있습니다. 터치해도 문제가 없어야 합니다.
자동 물리적 화면 크기 쿼리
경우에 따라 DRM을 통한 물리적 화면 크기 자동 쿼리가 실패할 수 있습니다. 일반적으로 QT_QPA_EGLFS_PHYSICAL_WIDTH
및 QT_QPA_EGLFS_PHYSICAL_HEIGHT
환경 변수를 사용하여 누락된 값을 제공합니다. 하지만 여러 개의 화면이 있는 경우 이 방법은 더 이상 적합하지 않습니다. 대신 outputs
목록의 physicalWidth
및 physicalHeight
속성을 사용하여 밀리미터 단위로 크기를 지정하세요.
참고: 물리적 크기가 다르면 일부 그래픽 스택 구성 요소가 여러 화면을 인식하지 못하고 첫 번째 화면의 값에만 의존하여 예기치 않은 문제가 발생할 수 있으므로 논리적 DPI를 다르게 지정하는 것은 권장하지 않습니다.
활성 출력 및 Q스크린 인스턴스
outputs
배열의 각 활성 출력은 QGuiApplication::screens()에서 보고된 QScreen 인스턴스 하나에 해당합니다. 기본적으로 QGuiApplication::primaryScreen()가 보고하는 기본 화면은 가장 먼저 등록된 화면입니다. virtualIndex
을 사용하지 않는 경우 이는 DRM 커넥터 순서에 따라 결정된다는 의미입니다. 이를 재정의하려면 outputs
목록에서 원하는 항목의 primary
속성을 true
로 설정하세요.
예를 들어, 시스템이 HDMI를 먼저 보고하는 경우에도 VGA 출력에 해당하는 화면이 기본 화면이 되도록 하려면 다음과 같이 하세요:
{ "device": "/dev/dri/card0", "outputs": [ { "name": "HDMI1" }, { "name": "VGA1", "mode": "1280x720", "primary": true }, { "name": "LVDS1", "mode": "off" } ] }
문제 해결을 위해 KMS/DRM 백엔드에서 디버그 로그를 활성화하는 것이 유용할 수 있습니다. 이렇게 하려면 qt.qpa.eglfs.kms
범주화된 로깅 규칙을 활성화하세요.
참고: 임베디드 환경에서는 가상 데스크톱이 전체 창 시스템과 비교하여 더 제한적입니다. 여러 화면이 겹치는 창, 전체 화면이 아닌 창, 화면 간 창 이동은 피해야 하며 예상대로 작동하지 않을 수 있습니다.
일반적인 사용 사례
다중 화면 설정의 가장 일반적이고 가장 잘 지원되는 사용 사례는 각 화면에 대해 전용 QQuickWindow 또는 QQuickView 을 여는 것입니다. Qt Quick 시나리오의 기본 threaded
렌더 루프를 사용하면 이러한 각 창에 전용 렌더 스레드가 생깁니다. 이는 스레드를 동기화에 따라 독립적으로 스로틀할 수 있고 서로 간섭하지 않기 때문에 좋습니다. basic
루프를 사용하면 문제가 발생하여 애니메이션이 저하될 수 있습니다.
예를 들어 연결된 모든 화면을 검색하고 각 화면에 대해 QQuickView 을 생성하는 작업은 다음과 같이 수행할 수 있습니다:
int main(int argc, char **argv) { QGuiApplication app(argc, argv); QVector<QQuickView *> views; for (QScreen *screen : app.screens()) { QQuickView *view = new QQuickView; view->setScreen(screen); view->setResizeMode(QQuickView::SizeRootObjectToView); view->setSource(QUrl("qrc:/main.qml")); QObject::connect(view->engine(), &QQmlEngine::quit, qGuiApp, &QCoreApplication::quit); views.append(view); view->showFullScreen(); } int result = app.exec(); qDeleteAll(views); return result; }
고급 eglfs_kms 기능
복제(미러링)
화면 복제(미러링)가 지원됩니다. 이는 clones
속성을 통해 활성화할 수 있습니다:
{ "device": "/dev/dri/card0", "outputs": [ { "name": "HDMI1", "mode": "1920x1080" }, { "name": "DP1", "mode": "1920x1080", "clones": "HDMI1" } ] }
이 경우 DisplayPort를 통해 연결된 디스플레이의 콘텐츠는 HDMI 디스플레이의 콘텐츠와 동일합니다. 이는 양쪽에서 동일한 버퍼를 스캔하여 보장됩니다.
그러나 이 기능은 해상도가 동일하고 허용되는 버퍼 형식에 비호환성이 없으며 애플리케이션이 복제 대상과 연결된 QScreen 에 출력이 없는 경우에만 작동할 수 있습니다. 실제로 후자는 문제의 QScreen (예제에서는 DP1)과 연결된 QWindow 에서 QOpenGLContext::swapBuffers() 작업을 수행하지 않아야 함을 의미합니다. 이를 보장하는 것은 구성과 애플리케이션에 달려 있습니다.
DRM 렌더링을 사용한 헤드리스 모드
DRM 렌더 노드를 통한 헤드리스 모드가 지원됩니다. 이 모드를 사용하면 DRM 마스터 권한 없이도 GPU 컴퓨팅(OpenGL 컴퓨팅 셰이더, OpenCL) 또는 오프스크린 OpenGL 렌더링을 수행할 수 있습니다. 이 모드에서는 이미 화면에 출력되는 다른 프로세스가 있는 경우에도 애플리케이션이 작동할 수 있습니다.
헤드리스 모드에서는 수행할 수 없는 작업이 많기 때문에 device
를 /dev/dri/card0
에서 /dev/dri/renderD128
로 전환하는 것만으로는 의미가 없습니다. 따라서 예를 들어 headless
속성과 결합해야 합니다:
{ "device": "/dev/dri/renderD128", "headless": "1024x768" }
창 크기는 여전히 가상의 화면 크기에 맞게 조정되므로 headless
속성에 크기를 지정해야 한다는 점에 유의하세요. 또한 비동기 동기화 기반 스로틀링이 없습니다.
이 기능을 활성화하면 애플리케이션에서 헤드리스 모드에서 오프스크린 렌더링을 수행할 수 있는 두 가지 일반적인 선택지가 있습니다:
QOpenGLWindow 서브클래스와 같이 윈도우의 기본 프레임버퍼(실제로는 gbm_surface
)를 대상으로 하는 일반 윈도우를 사용합니다:
MyOpenGLWindow w; w.show(); // will not actually show up on screen w.grabFramebuffer().save("output.png");
또는 추가 FBO를 사용하는 일반적인 오프스크린 접근 방식:
QOffscreenSurface s; s.setFormat(ctx.format()); s.create(); ctx.makeCurrent(&s); QOpenGLFramebufferObject fbo(1024, 768); fbo.bind(); ctx.functions()->glClearColor(1, 0, 0, 1); ctx.functions()->glClear(GL_COLOR_BUFFER_BIT); fbo.toImage().save("output.png"); ctx.doneCurrent();
DRM API 선택
KMS/DRM은 레거시 및 아토믹이라는 두 가지 다른 DRM API와 함께 사용할 수 있습니다. DRM 원자 API의 주요 이점은 동일한 렌더루프 내에서 여러 DRM 플레인 업데이트를 허용하는 반면, 레거시 API는 동기화할 때마다 하나의 플레인을 업데이트해야 한다는 것입니다.
아토믹 API는 애플리케이션에서 모든 업데이트를 동일한 동기화 내에서 유지하면서 콘텐츠를 오버레이에 블렌딩해야 할 때 유용합니다. 아직 모든 디바이스가 이 API를 지원하는 것은 아니며 일부 구형 디바이스에서는 사용할 수 없습니다. KMS 백엔드는 기본적으로 레거시 API를 사용하지만 QT_QPA_EGLFS_KMS_ATOMIC
환경 변수를 1로 설정하여 DRM 원자 API를 활성화할 수 있습니다.
화면 해상도보다 작은 프레임버퍼를 사용하는 것도 유용할 수 있습니다. 이는 JSON 파일에서 size
파라미터를 사용하여 DRM 원자에서 가능합니다. 아래 예시는 3840x2160 비디오 모드에서 1280x720 프레임버퍼를 사용합니다:
{ "device": "/dev/dri/card0", "outputs": [ { "name": "HDMI1", "mode": "3840x2160", "size": "1280x720", "format": "argb8888" } ] }
eglfs_kms_egldevice 백엔드가 있는 EGLFS
일반적으로 테그라 디바이스에서 사용되는 이 백엔드는 위에서 언급한 KMS/DRM 백엔드와 유사하지만, GBM 대신 EGLDevice 및 EGLStream 확장에 의존한다는 점이 다릅니다.
이 접근 방식에 대한 기술적 세부 사항은 이 프레젠테이션을 확인하세요.
Qt 5.7부터 이 백엔드는 내부 구현의 많은 부분을 GBM 기반 백엔드와 공유합니다. 즉, 다중 화면과 QT_QPA_EGLFS_KMS_CONFIG
을 통한 고급 구성이 지원됩니다. 그러나 hwcursor
및 pbuffers
같은 일부 설정은 적용되지 않습니다.
기본적으로 백엔드는 각 출력의 기본 평면에 대해 올바른 EGL 레이어를 자동으로 선택합니다. 필요한 경우 QT_QPA_EGLFS_LAYER_INDEX
환경 변수를 원하는 계층의 인덱스로 설정하여 이 설정을 재정의할 수 있습니다. 이 접근 방식은 현재 다중 출력을 지원하지 않으므로 단일 화면이 있는 시스템에서만 사용해야 합니다. 사용 가능한 레이어를 확인하고 잠재적인 시작 문제를 디버깅하려면 로깅 카테고리 qt.qpa.eglfs.kms
를 활성화하세요.
경우에 따라 화면에 원하는 해상도가 이미 설정되어 있다고 표시되는 경우에도 애플리케이션 시작 시 비디오 모드 설정을 수행해야 할 수 있습니다. 이는 일반적으로 최적화되어 있지만 화면이 계속 꺼져 있으면 환경 변수 QT_QPA_EGLFS_ALWAYS_SET_MODE
를 0이 아닌 값으로 설정하고 애플리케이션을 다시 실행해 보세요.
백엔드에서 사용하는 EGLStream 객체의 동작을 구성하려면 QT_QPA_EGLFS_STREAM_FIFO_LENGTH
환경 변수를 사용합니다. 여기서는 대상 시스템에서 KHR_stream_fifo
을 지원한다고 가정합니다. 기본적으로 스트림은 메일박스 모드에서 작동합니다. FIFO 모드로 전환하려면 1 이상의 값을 설정합니다. 이 값은 스트림이 보유할 수 있는 최대 프레임 수를 지정합니다.
일부 시스템에서는 사전 정의된 커넥터를 통해 특정 오버레이 플레인을 타겟팅해야 할 수도 있습니다. QT_QPA_EGLFS_LAYER_INDEX
을 통해 레이어 인덱스를 강제 지정하는 것만으로는 플레인 구성을 수행하지 않으므로 그 자체로는 적합하지 않습니다. 대신 이러한 특수한 시나리오에서는 QT_QPA_EGLFS_KMS_CONNECTOR_INDEX
및 QT_QPA_EGLFS_KMS_PLANE_INDEX
환경 변수를 사용하세요. 이 변수를 설정하면 지정된 커넥터와 플레인만 사용되며 다른 모든 출력은 무시됩니다. 백엔드에서 원하는 평면에 해당하는 EGL 레이어를 선택하고 평면을 구성하는 작업을 처리합니다.
KMS/DRM의 여러 화면이 있는 시스템에서의 터치 입력
터치 이벤트가 올바른 가상 화면으로 라우팅되어야 하고 터치스크린과 디스플레이 출력 간의 올바른 매핑이 필요하기 때문에 멀티 디스플레이 시스템에서 터치스크린은 추가적인 고려 사항이 필요합니다.
매핑은 QT_QPA_EGLFS_KMS_CONFIG
에 지정되고 이전 섹션에서 설명한 JSON 구성 파일을 통해 수행됩니다. outputs
배열의 요소에 touchDevice
속성이 있으면 해당 값은 장치 노드로 처리되고 터치 장치는 해당 디스플레이 출력과 연결됩니다.
예를 들어 터치스크린의 디바이스 노드가 /dev/input/event5이고 HDMI를 통해 보조 화면으로 연결된 모니터에 통합된 터치스크린이라고 가정하면 다음 구성을 사용하면 올바른 터치(및 합성 마우스) 이벤트 변환이 보장됩니다:
{ "device": "drm-nvdc", "outputs": [ { "name": "HDMI1", "touchDevice": "/dev/input/event5", "virtualIndex": 1 }, { "name": "DP1", "virtualIndex": 0 } ] }
참고: 확실하지 않은 경우 애플리케이션을 시작하기 전에 환경 변수 QT_LOGGING_RULES=qt.qpa.*=true
를 설정하여 그래픽 및 입력 하위 시스템 모두에서 로깅을 활성화하세요. 이렇게 하면 올바른 입력 장치 노드를 식별하는 데 도움이 되며, 그렇지 않으면 디버깅하기 어려운 출력 구성 문제를 발견할 수 있습니다.
참고: Qt 5.14부터 위의 방법은 evdevtouch 및 libinput 백엔드에서만 지원됩니다. 다른 변형은 계속해서 기본 화면으로 이벤트를 라우팅합니다. 여러 입력 백엔드를 사용할 수 있는 시스템에서 evdevtouch를 강제로 사용하려면 환경 변수 QT_QPA_EGLFS_NO_LIBINPUT
를 1
로 설정하세요.
다른 백엔드를 사용하는 EGLFS
일반적으로 공급업체의 EGL 구현을 통해 프레임버퍼 또는 컴포지션 API를 직접 타겟팅하는 것을 기반으로 하는 다른 백엔드는 일반적으로 다중 디스플레이에 대한 지원이 제한적이거나 전혀 제공되지 않습니다. Vivante GPU가 탑재된 i.MX6 기반 보드에서는 QT_QPA_EGLFS_FB
환경 변수를 사용하여 linuxfb와 유사하게 타겟팅할 프레임버퍼를 지정할 수 있습니다. 라즈베리 파이에서는 QT_QPA_EGLFS_DISPMANX_ID
환경 변수를 사용하여 출력할 화면을 지정할 수 있습니다. 이 값은 DISPMANX_ID_
상수 중 하나에 해당하며, Dispmanx 설명서를 참조하세요. 이러한 접근 방식은 KMS/DRM과 달리 일반적으로 동일한 애플리케이션에서 여러 화면으로 출력을 허용하지 않는다는 점에 유의하세요. 또는 드라이버별 환경 변수 또는 커널 매개변수를 사용하여 사용되는 프레임버퍼를 제어할 수도 있습니다. 임베디드 보드의 설명서를 참조하세요.
비디오 메모리
전용 비디오 메모리가 고정되어 있는 시스템에서는 Qt Quick 또는 QOpenGLWidget 과 같은 클래스에 기반한 Qt 애플리케이션을 실행하기 전에 각별한 주의가 필요할 수 있습니다. 특히 이러한 애플리케이션이 고해상도(예: 풀 HD) 화면에 표시되는 경우 기본 설정이 충분하지 않을 수 있습니다. 이 경우 예기치 않은 방식으로 실패하기 시작할 수 있습니다. 최소 128MB의 GPU 메모리가 있는지 확인하는 것이 좋습니다. GPU를 위해 예약된 메모리가 고정되어 있지 않은 시스템의 경우에는 문제가 되지 않습니다.
linuxfb
fb
플러그인 매개변수를 사용하여 사용할 프레임버퍼 장치를 지정합니다.
유닉스 신호 처리기
콘솔 지향 플랫폼 플러그인인 eglfs 및 linuxfb는 기본적으로 인터럽트(SIGINT
), 일시 중단 및 계속(SIGTSTP
, SIGCONT
) 및 종료(SIGTERM
)를 캡처하기 위해 신호 처리기를 설치합니다. 이렇게 하면 kill
, Ctrl+C
또는 Ctrl+Z
로 인해 애플리케이션이 종료되거나 일시 중단될 때 키보드, 터미널 커서 및 기타 그래픽 상태를 복원할 수 있습니다(키보드를 통한 종료 또는 일시 중단은 위의 입력 섹션에 설명된 대로 QT_QPA_ENABLE_TERMINAL_KEYBOARD
이 설정된 경우에만 가능하지만). 그러나 경우에 따라 SIGINT
을 캡처하는 것은 원격 디버깅과 충돌할 수 있으므로 바람직하지 않을 수 있습니다. 따라서 모든 내장 신호 처리를 옵트아웃할 수 있는 환경 변수 QT_QPA_NO_SIGNAL_HANDLER
가 제공됩니다.
폰트
Qt는 일반적으로 fontconfig
를 사용하여 시스템 폰트에 대한 액세스를 제공합니다. fontconfig
을 사용할 수 없는 경우, Qt는 QBasicFontDatabase
을 사용합니다. 이 경우, Qt 어플리케이션은 Qt의 lib/fonts
디렉토리에서 폰트를 찾습니다. Qt는 미리 렌더링된 글꼴과 트루타입 글꼴을 자동으로 감지합니다. 이 디렉터리는 QT_QPA_FONTDIR
환경 변수를 설정하여 재정의할 수 있습니다.
지원되는 포맷에 대한 자세한 내용은 임베디드 리눅스 폰트용 Qt를 참조하십시오.
참고: Qt는 더 이상 lib/fonts
디렉터리에 글꼴을 제공하지 않습니다. 즉, 필요한 글꼴을 제공하는 것은 플랫폼(시스템 이미지)에 달려 있습니다.
임베디드 Linux 디바이스의 윈도우 시스템용 플랫폼 플러그인
XCB
일반 데스크톱 Linux 플랫폼에서 사용되는 X11 플러그인입니다. 일부 임베디드 환경에서는 X 및 xcb에 필요한 개발 파일을 제공하는 이 플러그인이 일반 PC 데스크톱에서와 마찬가지로 작동합니다.
참고: 일부 기기에서는 EGL 구현이 Xlib와 호환되지 않기 때문에 X에서 EGL 및 OpenGL을 지원하지 않습니다. 이 경우 XCB 플러그인은 EGL 지원 없이 빌드되므로 Qt Quick 2 또는 기타 OpenGL 기반 애플리케이션이 이 플랫폼 플러그인에서 작동하지 않습니다. 그러나 소프트웨어 렌더링 애플리케이션(예: QWidget 기반)을 실행하는 데는 계속 사용할 수 있습니다.
일반적으로 임베디드 디바이스에서 XCB를 사용하는 것은 바람직하지 않습니다. eglfs와 같은 플러그인이 더 나은 성능과 하드웨어 가속을 제공할 가능성이 높습니다.
Wayland
Wayland는 경량 윈도우 시스템, 더 정확하게는 클라이언트가 디스플레이 서버와 통신하기 위한 프로토콜입니다.
Qt Wayland는 Qt 애플리케이션이 Wayland Compositor에 연결할 수 있는 wayland
플랫폼 플러그인을 제공합니다.
자세한 내용은 Wayland와 Qt를 참조하십시오.
성능 향상 가이드라인
가능하면 하드웨어 렌더링 사용
애플리케이션에 성능이 중요한 경우, 소프트웨어 렌더링에 의존하는 Qt 모듈( Qt Charts. 대신 가능하면 하드웨어 렌더링에 의존하는 모듈을 선호하십시오.
다음 모범 사례를 따르세요. Qt Quick
QML 모범 사례 및 Qt Quick, 특히 QML CMake API 포함과 관련하여 qmllint, QML 스크립트 컴파일러 (qmlsc) 및 QML 유형 컴파일러 (qmltc)를 사용할 수 있도록 하세요. 또한 선언적 QML을 작성하고 자바스크립트를 최소화하는 것이 좋습니다. 과도한 자바스크립트 사용이 성능에 미치는 영향에 대한 자세한 내용은 QML 성능 고려 사항 및 제안을 참조하세요.
캔버스 QML 유형 대신 이미지/텍스처 및 셰이더 효과 사용
사용자 지정 UI 요소를 그리려면 이미지/텍스처 및 셰이더 효과를 사용하세요. QML Canvas 유형을 사용하지 마세요. 셰이더에는 하드웨어 가속(GPU)이 필요합니다.
대신 Qt Quick 을 사용하세요. Qt Widgets
Qt Quick 을 사용하면 하드웨어 가속 또는 소프트웨어 렌더링 백엔드를 사용할 수 있습니다. 복잡한 울스의 경우 임베디드 대상에 Qt Widgets 을 사용하는 것은 항상 소프트웨어 백엔드를 사용하므로 권장되지 않습니다.
여기에는 장단점이 있습니다:
- QML 엔진과 Qt Quick 을 사용하면 초기 오버헤드가 발생합니다.
- UI가 매우 단순하고 다시 칠하는 일이 거의 없는 경우 QML 대신 위젯을 사용하여 구현하면 성능이 더 빨라질 수 있습니다.
- UI에 애니메이션, smooth scrolling, scaling, rendering effects, 또는 3D를 사용하는 경우 GPU 가속이 필요하므로 Qt Quick 을 사용해야 합니다.
UI 크기에 적합한 해상도 선택
해상도가 높을수록 주의해야 합니다. 720p 이상의 해상도는 성능이 저하될 수 있습니다.
애플리케이션의 루트 요소로 QML 창 유형 사용
애플리케이션의 배경이 color 인 애플리케이션의 루트 요소로 Window 를 사용하세요.
그 이유는 창 컴포넌트에는 버퍼를 지우는 효과가 있는 색상 속성이 있기 때문입니다. 전체 화면 Rectangle 을 애플리케이션의 루트 Item 로 사용하여 배경을 렌더링하면 추가 드로우 호출이 발생합니다. 일부 RHI 백엔드의 경우 이는 동일할 수 있지만 glClear 호출과 쿼드 그리기에는 차이가 있습니다. 대부분의 경우 불투명한 단일 이미지는 성능에 큰 영향을 미치지 않지만 해당 항목의 색상에 알파 값을 사용하는 경우 성능에 상당한 영향을 미칠 수 있습니다.
관련 주제
© 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.