Qt5의 구조와 Integration
Qt5 Framework는 비GUI 적인 기능을 포함하는 Core와 플랫폼 윈도우 추상 레이어인 QPA 를 기반으로 Widget 및 그래픽 요소를 포함하는 Qt GUI구조를 이룬다. 여기서 QPA(Qt Platform Abstraction)는 플랫폼 기본 윈도우 시스템의 추상 레이어로써 플러그인 형태로 구현되며 Qt Application 시작 시 동적으로 로드된다.
기본으로 제공되는 주요 플러그인들이 있으며 다음과 같다.
-
linuxfb: Linux Framebuffer
-
EGLFS: OpenGL / OpenGL ES 를 위한 EGL 플랫폼 인터페이스.
-
DirectFB: 가속 렌더링 지원 기능을 갖춘 경량 윈도우 시스템.
-
X11/XCB: 전통적 리눅스 X 윈도우 시스템을 위한 것으로 XCB library를 사용.
-
Wayland: OpenGL/ES 를 사용하는 경량의 리눅스 윈도우 시스템.
이 중 EGLFS는 EGL 인터페이스를 사용하여 하나의 전체화면크기 창을 생성하는 것으로 GPU를 포함하고 OpenGL ES를 지원하는 임베디드 리눅스 장치에서 멀티 윈도우 및 응용프로그램이 필요 없는 요구사항에서 적합하다. EGLFS에는 몇 가지 기본으로 제공되는 포트가 있는데 다음과 같다.
-
KMS (GBM): Kernel Mode Setting (DRM) with Mesa's Generic Buffer Management
-
KMS (EGLDevice): Kernel Mode Setting with NVidia's EGLDevice
-
viv, viv_wl: Vivante's framebuffer API
-
brcm: Broadcom's framebuffer API for Raspberry PI
-
mali: Framebuffer API for Mali chips
OpenGL ES 2.0, 3.0 및 EGL을 지원하는경우 기본으로 제공되는 EGLFS를 사용하거나 따로 개발할 수 있다. 아래의 다이어그램은 EGLFS의 QEglFSVivIntegrationPlugin 을 구현하는 클래스 관계를 나타낸 것이다. 플랫폼 서페이스 생성에 대한 공통적인 인터페이스 사용을 위해 추상 클래스를 서브클래싱하여 플러그인을 구현한다.
아래의 리스트는 QEglFSVivIntegration 클래스 구현의 일부분이다. 플러그인은 EGL/eglvivante.h 를 포함하고 EGL인터페이스를 통해 초기화, 표면을 생성, 삭제등을 구현한다.
#include <EGL/eglvivante.h>
…
void QEglFSVivIntegration::platformInit()
{
QEglFSDeviceIntegration::platformInit();
int width, height;
...
#ifdef Q_OS_INTEGRITY
VivanteInit();
mNativeDisplay = fbGetDisplay();
#else
mNativeDisplay = static_cast<EGLNativeDisplayType>(fbGetDisplayByIndex(framebufferIndex()));
#endif
fbGetDisplayGeometry(mNativeDisplay, &width, &height);
mScreenSize.setHeight(height);
mScreenSize.setWidth(width);
}
...
EGLNativeWindowType QEglFSVivIntegration::createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format)
{
...
EGLNativeWindowType eglWindow = static_cast<EGLNativeWindowType>(fbCreateWindow(mNativeDisplay, 0, 0, size.width(), size.height()));
return eglWindow;
}
void QEglFSVivIntegration::destroyNativeWindow(EGLNativeWindowType window)
{
fbDestroyWindow(window);
}
시스템 전체 범위로 확대하여 구조를 파악할 필요가 있다. 아래의 그림은 임베디드 리눅스에서 프레임버퍼 장치를 기반으로 Qt Framework의 EGLFS와 OpenGL ES / EGL을 사용하는 그래픽 스택이다.
OpenGL ES / EGL이 어떻게 사용되고 또 그 흐름을 간단하게 설명하면 다음과 같다.
-
먼저 Qt 는 Application이 실행될 때 QPA 플러그인으로 EGLFS를 사용하여 EGL Surface를 생성한다.
-
응용프로그램에서QOpenGLWidget 또는 QML을 사용하는 GUI는 OpenGL ES를 통해 H/W가속이 먼저 이뤄진다.
-
그밖에 PaintEngine으로 그려진 그 외의 그래픽 요소들(QWidget)을 텍스처로 만들고 그것들을 QPA 플러그인(EGLFS)에서 최종 합성한다.
-
GPU결과는 EGL 인터페이스를 통해 리눅스 프레임버퍼장치의 DMA 버퍼에 쓰고 DMA컨트롤러에 의해 Display컨트롤러로 보낸다.