이 페이지에서

임베디드 리눅스용 Qt

임베디드 리눅스 장치용 플랫폼 플러그인

임베디드 리눅스 시스템에서는 EGLFS, VkKhrDisplay, LinuxFB, Wayland 등 여러 플랫폼 플러그인을 사용할 수 있습니다. 이러한 플러그인의 사용 가능 여부는 Qt의 구성 방식에 따라 달라집니다. 이 중 Wayland는 컴포지터의 존재를 필요로 하며, X11이나 Windows와 유사하게 여러 창을 지원하는 완전한 윈도우 시스템을 제공합니다. 나머지 플러그인들은 별도의 윈도우 시스템 없이 작동하므로, Qt 애플리케이션이 렌더링과 출력을 완전히 제어합니다. 이들은 일반적으로 화면당 하나의 전체 화면 Qt "창"을 지원합니다.

EGLFS는 많은 보드에서 기본 플러그인으로 설정되어 있습니다. 적합하지 않은 경우, ` QT_QPA_PLATFORM ` 환경 변수를 사용하여 다른 플러그인을 지정하십시오. 또는 빠른 테스트를 위해 동일한 구문의 ` -platform ` 명령줄 인수를 사용할 수도 있습니다.

참고: Qt 5.0부터 Qt는 더 이상 자체 윈도우 시스템(QWS) 구현을 제공하지 않습니다. 단일 프로세스 사용 사례의 경우 Qt Platform Abstraction이 더 우수한 솔루션이며, 다중 프로세스 사용 사례는 Wayland를 통해 지원됩니다.

임베디드 리눅스 툴체인을 사용하여 크로스 컴파일을 위해 Qt를 구성하는 방법에 대한 개요는 ‘임베디드 리눅스 장치 구성’을 참조하십시오.

EGLFS

EGL은 OpenGL과 네이티브 윈도우 시스템 간의 인터페이스입니다. Qt는 컨텍스트 및 서피스 관리를 위해 EGL을 사용할 수 있지만, 해당 API에는 플랫폼별 특정이 포함되어 있지 않습니다. 화면에 실제로 표시되는 창이 아닐 수도 있는 네이티브 창을 생성하는 작업은 여전히 플랫폼별 방법을 통해 수행되어야 합니다. 이것이 바로 보드 또는 GPU별 조정 코드가 필요한 이유입니다. 일반적으로 이러한 조정 코드는 다음과 같은 형태로 제공됩니다:

  • EGLFS 후크— 플랫폼 플러그인으로 컴파일되는 단일 소스 파일
  • EGL 장치 통합— 동적으로 로드되는 플러그인

EGLFS는 X11이나 Wayland와 같은 실제 윈도우 시스템 없이 EGL 및 OpenGL ES 2.0 위에서 Qt 애플리케이션을 실행하기 위한 플랫폼 플러그인입니다. 이는 GPU를 탑재한 최신 임베디드 리눅스 장치에 권장되는 플러그인입니다.

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는 오류 메시지와 함께 애플리케이션을 종료합니다.

또한, 드래그 앤 드롭( Drag and Drop)과 같이 데스크톱 플랫폼이나 윈도우 시스템이 있는 환경을 위해 설계된 API는 EGLFS에서 지원되지 않습니다.

EGLFS에서 사용하는 환경 변수

필요한 경우, 다음 환경 변수를 사용하여 ` eglfs `를 구성할 수 있습니다:

환경 변수설명
QT_QPA_EGLFS_INTEGRATION컴파일 시 내장된 후크 외에도, 동적으로 로드되는 플러그인을 사용하여 장치 또는 벤더별 맞춤 설정을 제공할 수 있습니다. 이 환경 변수는 특정 플러그인을 강제 적용합니다. 예를 들어, 이 변수를 eglfs_kms로 설정하면 KMS/DRM 백엔드가 사용됩니다. 이 옵션은 장치 메이크스펙(makespec)에 정적 후크나 컴파일된 후크가 지정되지 않은 경우에만 사용할 수 있습니다. 실제로는 기존의 컴파일된 후크가 거의 사용되지 않으며, 현재 거의 모든 백엔드가 플러그인으로 전환되었습니다. 장치 메이크스펙에는 여전히 선택 사항이긴 하지만 관련 있는 EGLFS_DEVICE_INTEGRATION 항목이 포함되어 있습니다. 이는 해당 장치에 대해 선호되는 백엔드의 이름을 나타냅니다. 대상 시스템에 두 개 이상의 플러그인이 존재하는 경우 이 환경 변수를 설정하지 마십시오. 데스크톱 환경에서는 DISPLAY 환경 변수의 유무에 따라 KMS 또는 X11 백엔드가 우선적으로 사용됩니다.

참고: 일부보드에서는 실제 플러그인 대신 none 의 특수한 값이 사용됩니다. 이는 프레임버퍼에서 EGL을 사용하기 위해 특별한 통합이 필요하지 않음을 나타내며, 플러그인을 로드할 필요가 없습니다.

QT_QPA_EGLFS_PHYSICAL_WIDTH 그리고 QT_QPA_EGLFS_PHYSICAL_HEIGHT물리적 화면의 너비와 높이를 밀리미터 단위로 지정합니다. Qt 6부터는 물리적 화면 크기가 논리적 dpi를 결정하는 데 더 이상 사용되지 않는다는 점에 유의하십시오.
QT_QPA_EGLFS_ROTATIONQWidget 기반 애플리케이션에서 소프트웨어 렌더링된 콘텐츠에 적용되는 회전 각도를 지정합니다. 지원되는 값은 180, 90 및 -90입니다. 이 변수는 Qt Quick 을 포함한 OpenGL 기반 창에는 적용되지 않습니다. Qt Quick 애플리케이션은 대신 QML 장면에서 변환을 적용할 수 있습니다. 표준 eglfs 마우스 커서는 애플리케이션 유형에 관계없이 항상 이 값을 반영하여 포인터 이미지를 적절한 위치와 회전 각도로 표시합니다. 그러나 KMS/DRM 백엔드의 하드웨어 커서와 같은 특수 커서 구현은 회전을 지원하지 않을 수 있습니다. 이 설정은 터치 입력을 포함하여 그 외 다른 요소에는 아무런 영향을 미치지 않습니다. 터치 입력 백엔드인 evdevtouch 및 libinput 는 각각 회전을 구성하기 위한 고유한 메커니즘을 가지고 있습니다. 터치 입력 구성에 대한 자세한 내용은 임베디드 리눅스 장치의 입력(Inputs on an Embedded Linux Device)을 참조하십시오.
QT_QPA_EGLFS_FORCEVSYNC이 옵션이 설정되면, ` eglfs `은 `eglSwapBuffers()`가 호출될 때마다 프레임버퍼 장치에 대해 ` FBIO_WAITFORVSYNC `를 요청합니다. 이 변수는 레거시 리눅스 ` 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 bpp 구성을 강제 적용할 수 있는 지름길을 제공합니다.

또한, 다음과 같이 덜 일반적으로 사용되는 변수들도 사용할 수 있습니다:

환경 변수설명
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 출력에 원치 않는 “no”가 표시된다면 다음 명령을 실행하십시오:

./configure -v

명령어를 실행하여 상세 출력을 활성화하면, 각 configure 테스트에 대한 컴파일러 및 링커 호출 내용을 확인할 수 있습니다.

참고: 헤더나 라이브러리가 누락되었다는 오류나, 이해하기 어려운 링커 오류가 발생하는경우 , 이는 대개 sysroot가 불완전하거나 손상되었음을 나타내는 신호이며 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 확장 기능 계열에 의존합니다. 그래픽스 스택 내의 Vulkan 구현체가 이 기능을 반드시 지원하는 것은 아니라는 점에 유의하십시오. 현재 이 플랫폼 플러그인은 Raspberry Pi 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 를 지원합니다. 다만 마우스 커서 렌더링은 구현되어 있지 않습니다. 이는 이 환경에서 하드웨어 커서라는 개념이 존재하지 않으며, EGLFS가 OpenGL에서 수행하는 방식과 마찬가지로 플랫폼 플러그인 내에서 Vulkan을 사용하여 커서를 렌더링하는 것이 여러 가지 이유로 문제가 되기 때문입니다. 따라서 현재로서는 이 플랫폼 플러그인이 마우스 기반 입력에 적합하지 않습니다.

관련 환경 변수는 다음과 같습니다:

  • QT_QPA_DISABLE_INPUT - 키보드/마우스/터치 입력을 비활성화합니다.
  • QT_QPA_NO_LIBINPUT - libinput을 사용할 수 있는 경우에도 evdev 기반 입력 핸들러를 우선적으로 사용합니다.
  • QT_QPA_TSLIB - 레거시 tslib 라이브러리 사용을 요청합니다.

LinuxFB

이 플러그인은 리눅스의 fbdev 서브시스템을 통해 프레임버퍼에 직접 기록합니다. 소프트웨어 렌더링된 콘텐츠만 지원됩니다. 일부 환경에서는 디스플레이 성능이 제한될 수 있음을 유의하십시오. 이 플랫폼 플러그인과 함께 Qt Quick 애플리케이션을 사용하려면, 환경에 ` QT_QUICK_BACKEND=software `를 설정하거나 ` QSGRendererInterface::Software` 매개변수를 사용하여 ` setGraphicsApi()`를 호출함으로써 ` software ` 시나그래프 백엔드를 반드시 사용해야 합니다. ` QWidget ` 애플리케이션이나 표면 유형이 ` QSurface::RasterSurface`인 ` QWindow `는 지원되지만, ` QOpenGLWidget`와 같은 특수 위젯은 포함되지 않습니다.

리눅스 커널에서 fbdev가 더 이상 사용되지 않게 됨에 따라, DRM 덤프 버퍼 지원도 사용할 수 있습니다. 이를 사용하려면 QT_QPA_FB_DRM 환경 변수를 0이 아닌 값으로 설정하십시오. 이 변수가 설정되면, 시스템에서 덤프 버퍼를 지원하는 경우 /dev/fb0 와 같은 레거시 프레임버퍼 장치에는 접근하지 않습니다. 대신 EGLFS의 eglfs_kms 백엔드와 유사하게 DRM API를 통해 렌더링이 설정됩니다. 출력은 더블 버퍼링 및 페이지 플립 처리되어, 소프트웨어 렌더링 콘텐츠에도 적절한 vsync를 제공합니다.

참고: 덤프 버퍼를 사용하는경우 , 물리적 및 논리적 화면 크기와 같은 속성이 모두 자동으로 조회되므로 아래에 설명된 옵션은 적용되지 않습니다.

추가 설정 지정

linuxfb 플러그인을 사용하면 QT_QPA_PLATFORM 환경 변수나 -platform 명령줄 옵션을 통해 추가 설정을 지정할 수 있습니다. 예를 들어, QT_QPA_PLATFORM=linuxfb:fb=/dev/fb1 는 기본값인 fb0 대신 /dev/fb1 프레임버퍼 장치를 사용하도록 지정합니다. 여러 설정을 지정하려면 m 뒤에 콜론(:)을 붙여 구분하십시오.

설정설명
fb=/dev/fbN프레임버퍼 장치를 지정합니다. 다중 디스플레이 환경에서 이 설정을 사용하면 서로 다른 디스플레이에서 애플리케이션을 실행할 수 있습니다. 현재 하나의 Qt 애플리케이션에서 여러 프레임버퍼를 사용하는 방법은 없습니다.
size=<width>x<height>화면 크기를 픽셀 단위로 지정합니다. 플러그인은 프레임버퍼 장치로부터 물리적 및 논리적 디스플레이 크기를 조회하려고 시도합니다. 그러나 이 조회가 항상 정확한 결과를 반환하는 것은 아니므로, 값을 명시적으로 지정해야 할 수도 있습니다.
mmsize=<width>x<height>물리적 너비와 높이를 밀리미터 단위로 지정합니다.
offset=<width>x<height>화면의 왼쪽 상단 모서리 오프셋을 픽셀 단위로 지정합니다. 기본 위치는 (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() 호출을 반드시 수행해야 합니다.

특정 임베디드 장치에서 개발을 시작할 때, 장치와 드라이버의 동작을 확인하고 연결된 디스플레이가 정상적으로 작동하는지 확인해야 하는 경우가 많습니다. 이를 위한 쉬운 방법 중 하나는 hellowindow 예제를 사용하는 것입니다. -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을 통해 마우스 커서를 렌더링하는 방식으로 대체됨; 기본적으로 하드웨어 커서는 더 효율적이므로 활성화되어 있습니다).
  • QOffscreenSurface 를 표준 EGL pbuffer 표면으로 지원합니다(기본적으로 이 기능은 비활성화되어 있으며 대신 gbm 표면이 사용됩니다).
  • VGA 커넥터를 통한 출력은 비활성화되고, HDMI는 1024x768 해상도로 활성화됩니다.

또한, 이러한 구성에서는 libudev 를 통한 장치 검색이 비활성화되며, 대신 지정된 장치가 사용됩니다.

mode 가 정의되지 않은 경우, 시스템의 우선 모드가 선택됩니다. mode 에 허용되는 값은 다음과 같습니다: off, current, preferred, skip, widthxheight, widthxheight@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 ` 뒤에 ` virtualDesktopLayout ` 속성을 추가하고 값으로 ` vertical`을 지정하십시오.

경고: 가상 데스크톱의 모든 화면이 동일한 해상도를 사용하는 것이권장됩니다 . 그렇지 않으면 마우스 커서와 같은 요소가 특정 화면에만 존재하는 영역에 진입할 때 예상치 못한 방식으로 동작할 수 있습니다.

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도 달라지는데, 이는 일부 그래픽 스택 구성 요소가 다중 화면 환경을 인식하지 못하고 첫 번째 화면의 값에만 의존하여 예기치 않은 문제를 일으킬 수 있으므로 권장되지 않습니다.

활성 출력 및 QScreen 인스턴스

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 렌더 루프를 사용하면, 이러한 각 창은 자체 전용 렌더 스레드를 할당받게 됩니다. 이는 스레드를 vsync에 따라 독립적으로 조절할 수 있고 서로 간섭하지 않기 때문에 유용합니다. 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 속성에 크기를 명시해야 한다는 점을 유의하십시오. 또한 vsync 기반의 스로틀링 기능도 지원되지 않습니다.

이 기능이 활성화되면, 애플리케이션은 헤드리스 모드에서 오프스크린 렌더링을 수행하기 위해 일반적으로 두 가지 선택지를 가집니다:

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은 레거시(legacy )와 아토믹(atomic)이라는 두 가지 서로 다른 DRM API와 함께 사용할 수 있습니다. DRM 아토믹 API의 주요 이점은 동일한 렌더 루프 내에서 여러 DRM 플레인 업데이트를 허용한다는 점이며, 반면 레거시 API는 vsync당 하나의 플레인 업데이트만 허용합니다.

Atomic API는 애플리케이션이 모든 업데이트를 동일한 vsync 내에 유지하면서 콘텐츠를 오버레이에 블렌딩해야 할 때 유용합니다. 하지만 아직 모든 기기가 이 API를 지원하는 것은 아니며, 일부 구형 기기에서는 사용할 수 없을 수도 있습니다. KMS 백엔드는 기본적으로 레거시 API를 사용하지만, 환경 변수 ` QT_QPA_EGLFS_KMS_ATOMIC `를 1로 설정하여 DRM Atomic API를 활성화할 수 있습니다.

화면 해상도보다 작은 프레임버퍼를 사용하는 것도 유용할 수 있습니다. 이는 JSON 파일의 size 매개변수를 사용하여 DRM 아토믹에서 가능합니다. 아래 예제는 3840x2160 비디오 모드에서 1280x720 프레임버퍼를 사용합니다:

{
  "device": "/dev/dri/card0",
  "outputs": [
    { "name": "HDMI1", "mode": "3840x2160", "size": "1280x720", "format": "argb8888" }
  ]
}

EGLFS 핫플러그 및 핫리로드

QT_QPA_EGLFS_KMS_CONFIG 을 통해 KMS 구성 파일이 설정된 경우, 참조된 파일은 QFileSystemWatcher 에 의해 모니터링됩니다. 이 파일에 변경 사항이 발생하면 파일이 다시 읽혀지며, 이에 따라 레이아웃 변경, 모드 변경, 화면 켜기/끄기 등의 적절한 업데이트가 이루어집니다.

이와 유사한 방식이지만, 엄격히 선택적 적용 방식인 QT_QPA_EGLFS_HOTPLUG_ENABLED 를 설정하면 QDeviceDiscovery가 KMS 장치를 모니터링하여 화면 연결/삽입 및 분리/제거와 같은 변경 사항을 감지할 수 있습니다.

두 기능은 모두 병행하여 사용할 수 있으며, 실제로도 종종 병행하여 사용됩니다.

핫 플러그 및 핫 리로드로 인해 발생하는 동적 변경을 적절히 처리하려면, 새로 나타나는 화면과 사라지는 화면에 맞춰 창을 생성하고 제거하는 방식으로 대응하는 것이 중요합니다.

예제 코드:

#include <QGuiApplication>
#include <QQuickView>
#include <QQuickItem>
#include <QScreen>
#include <QQmlContext>

QHash<QString, QQuickView*> screenNameToViewMap;

int main(int argc, char* argv[])
{
    QGuiApplication app(argc,argv);
    app.setQuitOnLastWindowClosed(false);

    auto lRemove = [&](QScreen *screen) {
        if (screen->name().compare(QStringLiteral("qt_Headless")) == 0)
            return;

        if (!screenNameToViewMap.contains(screen->name()))
            return;

        QQuickView *view = screenNameToViewMap.take(screen->name());
        delete view;
    };

    auto lAdd = [&](QScreen *screen) {
        if (screen->handle() == nullptr)
            return;

        if (screen->name().compare(QStringLiteral("qt_Headless")) == 0)
            return;

        if (screenNameToViewMap.contains(screen->name()))
            return;

        QQuickView *view = new QQuickView;

        view->setSource(QUrl(QStringLiteral("qrc:/main.qml")));
        view->setScreen(screen);                    // This is not as important as the next line, but good practice
        view->setGeometry(screen->geometry());      // This is vital! Otherwise QWindow::show (/QWindowPrivate::create) will change the screen!
        view->show();

        screenNameToViewMap.insert(screen->name(), view);
    };

    QObject::connect(&app, &QGuiApplication::screenAdded, &app, lAdd, Qt::QueuedConnection);
    QObject::connect(&app, &QGuiApplication::screenRemoved, &app, lRemove);

    for (QScreen *screen : app.screens())
        lAdd(screen);

    return app.exec();
}

위의 예제에서 ` QWindow::setGeometry`와 관련된 줄에 유의하십시오. 이는 창이 의도된 화면에 표시되도록 하는 데 매우 중요합니다!

QML에도 동일한 신호가 존재하므로, QML에서도 동등한 코드를 작성할 수 있습니다.

특히 ` QT_QPA_EGLFS_HOTPLUG_ENABLED `의 경우 코드를 반드시 수정해야 합니다. 일부 화면은 전원이 꺼지면 연결이 끊어진 것처럼 동작하기 때문입니다. 이 기능을 활성화하지 않으면 Qt나 애플리케이션 레벨 코드 모두 연결 끊김에 대한 알림을 받지 못합니다. 이 경우 모든 백엔드 리소스는 대개 그대로 유지되므로, 마치 아무 일도 없었던 것처럼 화면이 다시 나타납니다. QT_QPA_EGLFS_HOTPLUG_ENABLED 를 사용하면, 화면상의 Qt 리소스(예: QScreen, QPlatformScreen, backing-store 등)가 소멸되고, 연결 시(예: 화면을 다시 켤 때) 재 생성됩니다. 따라서 애플리케이션 레벨 리소스(예: QWindow)도 재 생성되어야 합니다.

"qt_Headless"라고 불리는 폴백 화면은 화면이 없는 구성으로의 전환 및 그 반대의 전환을 원활하게 하기 위해 존재합니다. 애플리케이션 수준의 창의 경우, 이 화면은 대부분의 상황에서 무시할 수 있으며 무시해야 합니다.

eglfs_kms_egldevice 백엔드를 사용하는 EGLFS

일반적으로 Tegra 기기에서 사용되는 이 백엔드는 앞서 언급한 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 기반 보드에서는 linuxfb와 유사하게 QT_QPA_EGLFS_FB 환경 변수를 사용하여 대상 프레임버퍼를 지정할 수 있습니다. Raspberry Pi에서는 QT_QPA_EGLFS_DISPMANX_ID 환경 변수를 사용하여 출력할 화면을 지정할 수 있습니다. 이 값은 DISPMANX_ID_ 상수 중 하나에 해당하며, 자세한 내용은 Dispmanx 문서를 참조하십시오. KMS/DRM과 달리 이러한 방식으로는 일반적으로 동일한 애플리케이션에서 여러 화면으로 출력할 수 없다는 점에 유의하십시오. 또는, 사용되는 프레임버퍼를 제어하기 위해 드라이버별 환경 변수나 커널 매개변수를 사용할 수도 있습니다. 임베디드 보드의 문서를 참조하십시오.

비디오 메모리

고정된 용량의 전용 비디오 메모리를 갖춘 시스템의 경우, ` Qt Quick ` 또는 ` QOpenGLWidget`와 같은 클래스를 기반으로 하는 Qt 애플리케이션을 실행하기 전에 각별한 주의가 필요할 수 있습니다. 특히 고해상도(예: 풀 HD) 화면에서 표시될 때, 기본 설정만으로는 이러한 애플리케이션에 충분하지 않을 수 있습니다. 이 경우, 예기치 못한 방식으로 오류가 발생할 수 있습니다. 최소 128 MB의 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 환경 변수가 제공됩니다.

핸들러는 플랫폼 플러그인이 초기화될 때 설치되며, 그 이전에 애플리케이션이 설정해 둔 모든 처리를 대체합니다.

경고: ` SIGINT ` 및 ` SIGTERM `에서 콘솔 상태가 복원된 후, 프로세스는 ` _exit()`을 통해 종료됩니다. ` atexit() ` 핸들러, 정적 소멸자 또는 Qt 종료 코드는 실행되지 않으며, 버퍼링된 데이터는 플러시되지 않습니다. 따라서 ` systemctl stop ` 또는 일반 ` kill `은 애플리케이션을 즉시 종료시킵니다. SIGTERM 에서 상태를 영구적으로 유지해야 하는 애플리케이션은 QT_QPA_NO_SIGNAL_HANDLER 를 설정하고 자체 핸들러를 설치하여 콘솔 상태 복원 작업도 직접 수행해야 합니다.

콘솔 상태는 이러한 경로와 정상 종료 시에만 복원됩니다. SIGSEGV, SIGABRT 또는 std::terminate() 로 인해 프로세스가 종료될 때는 복원되지 않습니다. 가상 터미널을 그래픽 모드로 전환하는 linuxfb의 경우, 비정상적으로 종료된 애플리케이션으로 인해 장치가 재부팅될 때까지 로컬 콘솔이 비어 있고 키보드 입력에 반응하지 않을 수 있습니다. 해당 콘솔이 유일한 로컬 복구 경로인 장치의 경우, 시리얼 콘솔이나 장치를 재부팅하는 워치독과 같은 대안을 마련해야 합니다. ` QT_QPA_PRESERVE_CONSOLE_STATE `를 사용하여 터미널 커서 및 화면 비우기 설정을 그대로 유지하고, linuxfb의 ` nographicsmodeswitch `를 사용하여 그래픽 모드 전환을 건너뛰십시오.

보안 고려 사항

이 페이지에 설명된 플랫폼 플러그인은 윈도우 시스템 없이 실행되므로, 일반적으로 컴포지터나 디스플레이 서버가 담당하는 역할을 대신 수행합니다. 이 섹션에서는 플러그인이 신뢰하는 요소와 장치 제작자가 제어해야 할 사항에 대해 설명합니다. Qt 공유 보안 모델도 참조하십시오.

구성은 신뢰할 수 있는 콘텐츠입니다

임베디드 플랫폼 플러그인의 동작(어떤 디바이스 노드가 열리고, 어떤 디바이스 통합 플러그인이 프로세스에 로드되며, 터치 좌표가 화면에 어떻게 매핑되는지 등)은 환경 변수, KMS/DRM JSON 구성 파일, 그리고 선택 사항인 키맵 및 커서 아틀라스 파일에 의해 결정됩니다. 이 모든 요소는 신뢰할 수 있는 콘텐츠입니다. 즉, 장치 이미지가 빌드될 때 고정되어야 하며, 그 이후에는 장치 제작자가 제어해야 합니다. Qt는 이러한 항목들이 올바른 형식을 갖췄는지 확인하지만, 그 이상의 유효성 검사는 수행하지 않으며, 어떠한 형태로도 장치의 최종 사용자에게 노출되어서는 안 됩니다.

다음 두 항목에 특히 주목해야 합니다:

  • QT_QPA_EGLFS_INTEGRATION 는 로드될 수 있는 플러그인을 제한하지 않습니다. 요청된 백엔드는 후보 목록의 맨 앞으로 이동될 뿐이며, 초기화에 실패하더라도 나머지 백엔드들은 순서대로 시도됩니다. 여러 장치 통합 플러그인이 존재하는 시스템에서는, 배포 시 명시하지 않은 백엔드가 로드되어 하드웨어를 초기화할 수도 있습니다. 장치에 필요한 백엔드만 배포하십시오.
  • 터치 보정 및 회전 설정은 ` QT_QPA_LIBINPUT_TOUCH_MATRIX`, ` evdev ` rotate, ` invertx `, ` inverty ` 매개변수를 통해 설정되든, JSON 구성 파일의 ` touchDevice ` 매핑을 통해 설정되든, 터치 입력의 보고 위치를 결정합니다. 설정이 잘못되면 사용자가 터치한 컨트롤과 다른 컨트롤이 활성화되는데, 이는 인간-기계 인터페이스에서 안전성을 보장하는 특성입니다. 이러한 설정은 현장에서 조정 가능한 항목이 아니라, 장치의 검증된 구성의 일부로 취급해야 합니다.

입력 장치는 필터링되지 않습니다

Qt의 장치 탐색 기능은 찾고 있는 기능 클래스와 일치하는 모든 /dev/input/event* 노드를 열며, libudev 지원이 가능한 경우 애플리케이션 실행 중에 나중에 나타나는 장치도 함께 엽니다. 허용 목록도, 벤더나 제품 필터도 없으며, 예상되는 장치 집합이라는 개념도 없습니다. 허용된 모든 장치에서 발생하는 이벤트는 마치 의도된 장치에서 온 것처럼 애플리케이션에 전달되며, 애플리케이션은 이를 구별할 수 없습니다.

따라서 어떤 장치가 존재하는지, 그리고 누가 해당 장치를 읽을 수 있는지를 제한하는 것은 장치 제작자의 몫이며, 이는 애플리케이션이 아닌 커널, udev 및 파일 시스템 권한 수준에서 이루어집니다. /dev/input/* 를 읽을 권한이 없는 Qt 애플리케이션은 어떠한 입력도 읽지 못합니다. 또한:

  • QT_QPA_EVDEV_MOUSE_PARAMETERS, QT_QPA_EVDEV_KEYBOARD_PARAMETERS 및 QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS 에서 장치 이름을 명시적으로 지정하면 자동 검색 과정을 우회하여 애플리케이션이 사용하는 장치 세트를 고정할 수 있습니다.
  • grab=1 를 전달하면 애플리케이션이 장치에 대한 독점적인 액세스 권한을 얻게 되며, 이는 단일 애플리케이션만 실행되는 장치에서 고려해 볼 만한 사항입니다.
  • disable-zap 를 고려해 보십시오. ‘임베디드 리눅스 장치의 입력’을 참조하십시오.

디스플레이는 신뢰할 수 없는 입력입니다.

디스플레이가 커넥터를 통해 확인하는 EDID 블록은 모니터, 어댑터, KVM 스위치 또는 캡처 장치 등 연결된 장치에 의해 제공되며, 핫플러그 이벤트가 발생할 때마다 다시 구문 분석됩니다. KMS/DRM 백엔드를 사용하는 eglfs에서는, 여기에 포함된 값들이 QScreen::manufacturer(), QScreen::model(), QScreen::serialNumber() 및 보고된 물리적 크기를 통해 애플리케이션에 전달됩니다. 이 값들은 외부 요인의 영향을 받는 것으로 간주하십시오. 식별자로 사용하지 말고, 로그에 기록될 수 있음을 유의하십시오. 물리적 크기는 QT_QPA_EGLFS_PHYSICAL_WIDTH 및 QT_QPA_EGLFS_PHYSICAL_HEIGHT 를 사용하거나 JSON 구성 파일의 출력별로 재정의할 수 있습니다.

런타임 종속성

임베디드 플랫폼 플러그인은 Qt가 아닌 보드 지원 패키지(BSP)나 배포판에서 제공하는 라이브러리를 기반으로 하는 얇은 어댑터이며, 애플리케이션 프로세스 내에서 실행됩니다. 구성에 따라 다음이 포함됩니다:

  • eglfs: EGL 및 백엔드에 따라 GBM, Mesa, GPU 드라이버 또는 벤더별 EGL 구현체; KMS/DRM 백엔드의 경우 libdrm.
  • vkkhrdisplay: Vulkan 로더 및 설치된 Vulkan 드라이버.
  • linuxfb: 커널 fbdev 인터페이스, 또는 ` QT_QPA_FB_DRM `가 설정된 경우 ` libdrm `.
  • 입력: libinput, libudev 및 mtdev; xkbcommon(시스템에서 키맵 데이터를 추가로 읽음); 또는 tslib(자체 구성 파일에 따라 로드되는 필터 모듈이 결정되므로 Qt가 이를 선택하거나 열거할 수 없음).

이를 기기의 소프트웨어 BOM(Bill of Materials)에 포함시키고 최신 상태로 유지하며, 기기가 실제로 사용하는 백엔드만 Qt에 구성하십시오. 새로운 기기의 경우, 구식 tslib 대신 libinput 을 우선적으로 사용하십시오.

글꼴

Qt는 일반적으로 fontconfig 를 사용하여 시스템 글꼴에 대한 액세스를 제공합니다. fontconfig 를 사용할 수 없는 경우, Qt는 QBasicFontDatabase 를 대체로 사용합니다. 이 경우 Qt 애플리케이션은 Qt의 lib/fonts 디렉터리에서 글꼴을 찾습니다. Qt는 미리 렌더링된 글꼴과 트루타입(TrueType) 글꼴을 자동으로 감지합니다. 이 디렉터리는 QT_QPA_FONTDIR 환경 변수를 설정하여 재정의할 수 있습니다.

지원되는 형식에 대한 자세한 내용은 Qt for Embedded Linux 글꼴을 참조하십시오.

참고: Qt는 더 이상 lib/fonts 디렉터리에 글꼴을 포함하지 않습니다. 즉, 필요한 글꼴을 제공하는 것은 플랫폼(시스템 이미지)의 몫입니다.

임베디드 리눅스 장치의 윈도우 시스템용 플랫폼 플러그인

XCB

이것은 일반 데스크톱 리눅스 플랫폼에서 사용되는 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 Quick

QML 및 Qt Quick 에 대한 모범 사례를 따르십시오. 특히 QML CMake API를 포함하는 부분에서 이를 준수하여 qmllint, QML 스크립트 컴파일러 (qmlsc) 및 QML 타입 컴파일러 (qmltc)를 사용할 수 있도록 하십시오. 또한, 선언적 QML을 작성하고 자바스크립트 사용을 최소화하는 것이 좋습니다. 과도한 자바스크립트 사용이 성능에 미치는 영향에 대한 자세한 내용은 QML 성능 고려 사항 및 권장 사항을 참조하십시오.

Canvas QML 유형 대신 이미지/텍스처와 셰이더 효과를 사용하세요

사용자 정의 UI 요소를 그릴 때는 이미지/텍스처와 셰이더 효과를 사용하십시오. QML의 ` Canvas ` 타입은 사용하지 마십시오. 셰이더를 사용하려면 하드웨어 가속(GPU)이 필요합니다.

Qt Quick 대신 다음을 사용하십시오 Qt Widgets

Qt Quick 의 경우, 하드웨어 가속 백엔드와 소프트웨어 렌더링 백엔드 중 어느 쪽이든 사용할 수 있습니다. 복잡한 UI의 경우, 임베디드 대상에서 Qt Widgets 를 사용하는 것은 항상 소프트웨어 백엔드를 사용하게 되므로 권장되지 않습니다.

여기에는 다음과 같은 장단점이 있습니다:

  • QML 엔진과 ` Qt Quick `을 사용하면 초기 오버헤드가 발생합니다.
  • UI가 매우 단순하고 다시 그리기가 드문 경우, QML 대신 위젯을 사용하여 구현할 때 더 빠른 성능을 보일 수 있습니다.
  • UI가 애니메이션, smooth scrolling, scaling, rendering effects 또는 3D 기능을 활용하는 경우, GPU 가속이 필요하므로 Qt Quick 가 필요합니다.

UI 크기에 적합한 해상도를 선택하십시오

해상도가 높을수록 주의가 필요합니다. 720p 이상의 해상도는 성능 저하를 초래할 수 있습니다.

애플리케이션의 루트 요소로 QML Window 유형을 사용하십시오

Window 를 애플리케이션의 루트 요소로 사용하고, 애플리케이션의 배경을 color 로 설정하십시오.

그 이유는 Window 컴포넌트에 버퍼를 지우는 효과가 있는 color 속성이 있기 때문입니다. 전체 화면 Rectangle 을 애플리케이션의 루트 Item 로 사용하여 배경을 렌더링하면 추가적인 드로우 호출이 발생합니다. 일부 RHI 백엔드에서는 이 두 가지가 동일할 수 있지만, glClear 호출과 쿼드 그리기 사이에는 차이가 있습니다. 대부분의 경우, 불투명한 이미지 하나만으로는 성능에 큰 영향을 미치지 않을 수 있지만, 해당 항목의 색상에 알파 값을 사용하면 상당한 성능 저하가 발생할 수 있습니다.

© 2026 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.