월간 보관물: 2014 2월

[WAYLAND] 캐노니컬(우분투) Mir 의 미래

예전에 wayland 와 mir 를 간단히 비교한 글을 올린 적이 있는데, 오늘은 필자가 예상하는 우분투/mir 의 행보에 대해 간단히 정리해보고자 한다. (오픈소스 커뮤니티의 분위기와 기술의 흐름상 필연적인 부분도 있을 것이고, 다분히 필자의 개인적인 의견들도 섞여있기 때문에 가벼운 마음으로 이럴 수도 있겠구나 하는 정도로 읽어주시면 감사하겠습니다.)

우선 우분투가 가져가고자 하는 mir 기반의 소프트웨어 플랫폼의 구조를 간단히 살펴보자.

mir

위의 그림에는 아직 존재하지 않는 부분도 있고 이미 존재하는 부분도 있다. xmir 같은 경우는 작년부터 최적화를 굉장히 열심히 하고 있는 부분이고, wmir(?) 는 필자의 생각에 우분투가 mir 를 끝까지 고집한다면 결국에는 개발할 수 밖에 없을꺼라고 판단되는 부분이다. 일단 간단히 우분투가 mir 를 개발할 수 밖에 없었던 이유를 먼저 생각해보자.

우분투는 기존의 데스크탑 환경에서 일반 사용자들이 리눅스를 쉽게 활용할 수 있도록 큰 기여를 해왔다. 하지만 최근 몇 년 동안 우분투를 스마트폰이나 타블렛, TV 와 같은 다양한 장비에 탑재하기 위해 굉장히 많은 노력을 하고 있다. (이미 UbuntuPhone 은 전세계적으로 두 군데에서 제품을 생산하고 있다고 한다.) 아무래도 회사는 이윤을 추구하는 곳이기 때문에 캐노니컬로써는 당연한 과정이라고 볼 수도 있겠다. 그래서 우분투를 이용하여 상용 제품을 만들려고 하는 캐노니컬의 입장에서는 특히 커스터마이징이 많이 필요한 UX 관련 소프트웨어에 대한 주도권이 절대적으로 필요한 상황이다. 그래서 무리하게 unity 를 개발해왔고, 또한 더 무리를 해서 mir 를 개발하고 있는 것이다. (필자도 이 상황이 충분히 이해가 되는게 wayland 개발자 커뮤니티를 보면 정치적인 부분들이 적지 않게 작용하고 있어서 몇몇 회사의 개발자들의 입김이 굉장히 강하게 작용한다. 그래서 만약에 캐노니컬이 wayland 를 가지고 개발을 진행했더라도 지금과는 또 다른 어려움들이 있었을 것이다. 비슷한 사례로 애플이 웹킷을 주도하고 있는 상황에서 구글과 충돌이 많아지니 결국 구글이 블링크(blink) 라는 이름으로 포크해서 개발을 주도하고 있는 것도 핵심 오픈소스 소프트웨어에 대한 회사의 주도권 싸움이 적지 않은 부분을 차지한다는 걸 알 수 있다.)

또 한가지 우분투가 mir 를 진행할 수 있었던 이유는 일단 당장은 xmir 로 하위 호환성 지원 문제를 해결할 수 있고, 나중에 wayland 가 X 를 완전히 대체하더라도 wmir(?) 같은걸 만들어서 충분히 해결할 수 있기 때문이다. xmir 와 wmir 로 약간의 오버헤드가 생긴다고 하더라도 다른 부분에서 충분히 커스터마이징을 해서 이득을 본다면 전체적으로는 더 좋은 상황이라고 볼 수도 있겠다.

그래서 이와 같은 이유들로 어찌됐던 우분투는 mir 를 개발해서 여러 가지 프로젝트를 진행하고 있다. 이제 간단히 앞으로 우분투가 mir 를 어떻게 활용할지에 대해 살펴보자.

우선 GNOME 과 KDE 가 공식적으로 mir 를 보이콧했기 때문에 GTK+/QT 와 같은 위젯엔진들이 공식적으로 mir 에 포팅되는 일은 없을 것 같다. 하지만 몇몇 기사를 보면 우분투가 내부적으로 이미 QT 를 mir 에 포팅했고, 현재 이를 활용하여 제품을 개발하고 있는 것같다. 하지만 이 작업이 메인라인에 반영될지는 아직 미지수이다. 어찌됐던 현재의 상황을 종합해보면 우분투는 기존 어플리케이션 호환은 xmir 를 이용해서 해결하고 있고, 네이티브 애플리케이션의 개발은 QT on mir 를 이용해서 하고 있는 상황이다.

그리고 필자가 생각하는 한 가지 변수는 우분투가 과연 데스크탑 배포판에서도 끝까지 mir 를 고집할까이다. 현재 상황을 냉정히 생각해보면 데스크탑 배포판은 gnome-shell/mutter/wayland 와 plasma/kwin/wayland 로 가고, 캐노니컬은 unity on mir 를 기반으로 스마트 장치에 탑재할 플랫폼 개발에 전력을 다하는게 더 좋지 않을까싶다. mir 가 데스크탑 환경에서 제대로된 성능을 내기 위해서는 mesa 부터 시작해서 할일이 한 두가지가 아닌데 그걸 다 내부적으로 해결하는건 말이 안되기 때문이다. 그리고 개발보다 더 중요한게 오픈소스에 대한 주도권을 잡는 것인데 mir 와 관련된 많은 오픈소스 프로젝트에 캐노니컬이 필요한만큼 주도권을 확보한다는건 지금 상태를 보면 전혀 불가능한 일이기 때문이다.

어찌됐던 미운털이 단단히 박힌 캐노니컬이 올바른 선택을 해서 (무엇이 올바른 선택인지 모르겠지만) 리눅스를 기반으로 하는 다양한 컴퓨팅 환경이 다같이 발전할 수 있는 계기가 되었으면 좋겠다.

Advertisements

[WAYLAND] wl_signal 와 wl_listener

wayland/weston 소스 코드를 보면 가장 자주 접하게 되는 것이 wl_signal 과 wl_listener 이다. 이름만 봐도 대략 알 수 있듯이, wl_signal 은 특정 이벤트를 생성하는 객체이고, wl_listener 는 특정 이벤트를 받아서 처리하는 (콜백 함수 포인터를 가지고 있는) 객체이다. 사용하는 방법도 간단하고, 실제 동작하는 과정도 굉장히 단순하다.

signal

위의 그림에서 보는 것처럼 wl_signal/wl_listener 와 관련된 대표적인 함수는 딱 두 개이다. 첫 번째 wl_signal_add() 는 wl_listener 를 wl_signal 에 등록하는 일을 하고, 두 번째 wl_signal_emit() 은 wl_signal 에 등록된 wl_listener 를 호출하는 역할을 한다. 그리고 실제 호출하는 방식도 단순히 wl_signal 에서 링크드리스트(wl_list) 형태로 관리하는 wl_listener 를 순회하면서 콜백함수들을 직접 호출하는 방식이다.

이제 주로 어떤 곳에서 활용이 되는지 알아보자. 가장 기본적인 사용 패턴은 객체의 레퍼런스를 관리하는 일이다. 예를 들어, 서페이스(weston_surface) 가 버퍼(weston_buffer) 를 사용 중일 때 해당 버퍼가 클라이언트에 의해 언제든지 해제될 수 있기 때문에 서페이스는 항상 버퍼를 주시해야 한다. 그래서 현재의 weston 에서는 버퍼에 destroy_signal 이라는 이름의 wl_signal 을 생성해놓고, 서페이스에는 buffer_destroy_listener 라는 이름의 wl_listener 를 생성해놓는다. 그리고 서페이스가 버퍼를 참조하면 버퍼의 destroy_signal 에 서페이스의 buffer_destroy_listener 를 등록하고, 만약에 임의의 시점에 버퍼가 제거되면 destroy_signal 을 통해 미리 등록해놓은 콜백을 호출되게 만든다. 이게 wayland/weston 에 수많은 객체들의 레퍼런스를 관리하는 통일된 하나의 방식이다.

그리고 다른 목적으로도 빈번하게 사용되는데 대표적인 예가 focus_signal 이다. 예를 들어, 컴포지터에서 관리되는 마우스 입력 장치에서 새로운 포커스가 등록이 되면, 쉘은 미리 등록해놓은 wl_listener 를 통해 마우스의 포커스가 바뀌었음을 알게 되고 필요한 작업을 처리하게 된다.

사실 간단히 정리하면 wl_signal/wl_listener 는 wayland 가 기본적으로 제공하는 단순한 형태의 옵저버 패턴이라고 보면 된다. 이외에도 wayland 가 제공하는 유용한 것들이 몇 가지 더 있는데 나머지는 다음에 기회되면 설명하도록 하겠다.

[WAYLAND] 입력 장치(마우스/키보드/터치) 포커스 모델

컴포지터의 기본적인 역할은 그 단어의 의미가 말해주듯 여러 이미지(윈도우) 들을 하나의 이미지(화면) 로 합쳐주는 것이다. 이것을 다른 방식으로 표현하면 하나의 출력 장치를 여러 윈도우들이 나누어 쓸 수 있도록 도와준다는 것이다. 그렇다면 입력 장치는? 출력 장치와 마찬가지로 입력 장치를 여러 윈도우들이 나누어 쓸 수 있도록 도와주는 것도 컴포지터의 중요한 역할 중의 하나이다.

현재의 컴포지터들은 하나의 입력 장치를 여러 윈도우들이 나누어 쓸 수 있도록 몇 가지 정책을 정해놓았다. 마우스와 키보드 같은 입력 장치들은 기본적으로 배타적인 장치이기 때문에 이 정책에 따라 어느 한 순간에는 하나의 윈도우만이 해당 입력 장치를 소유하게 된다. 그렇다면 어떤 방식으로 특정 시점에 특정 윈도우가 입력 장치를 선점하고 있다고 결정할까? 여기에 사용되는 대표적인 포커스 모델 세 가지가 있다.

  • click to focus..가장 기본적인 포커스 모델로 윈도우의 내부를 마우스(혹은 터치) 로 클릭하여 포커스를 얻어내는 방식이다.
  • focus follows mouse..흔히 FFM 이라고 하며 현재 마우스 포인터가 위치한 윈도우에게 포커스를 주는 방식이다.
  • sloppy focus..FFM 방식과 유사하지만, 마우스 포인터가 윈도우가 아닌, 바탕화면이나 패널로 옮겨지면 포커스가 바뀌지 않는 방식이다. (즉, 현재 마우스 포인터가 패널에 있다면 포커스는 여전히 마지막으로 포커스됐던 윈도우에 남아있게 된다.)

사실 우리가 일반적으로 사용하는 데스크탑에서 무의식 중에 사용 중인 것들이라서 이해하는데 어려움은 없을 것이다. 하지만 이것들을 wayland/weston 기준으로 좀 더 세분화하고 몇 가지 사항들을 추가해서 설명하도록 하겠다.

첫 번째로 마우스에 대해서 살펴보자. 마우스는 GUI 기반 데스크탑 환경의 대표적인 입력 장치로 상대 좌표 방식을 사용하기 때문에 포인터가 반드시 필요한 장치이다. 현재 대부분의 데스크탑 환경에서 마우스 장치를 위해 사용하고 있는 포커스 모델은 FFM 방식이다. 즉, 마우스 포인터를 따라 마우스에 대한 포커스가 계속 변하고, 마우스 포인터의 모양 또한 현재 포커스된 윈도우에 따라 계속 변하게 된다.

두 번째로 키보드에 대해서 살펴보자. 우리가 현재 사용하고 있는 데스크탑 환경을 살펴보면 직관적으로 알겠지만, 키보드는 대부분 CTF(Click To Focus) 방식을 사용하고 있다. 그래서 특정 윈도우에서 키보드를 사용하고 싶다면 해당 윈도우에서 마우스를 클릭하게 되면 윈도우가 맨 앞으로 나와 활성화되면서 키보드 입력이 가능해지게 된다. (키보드를 FFM 방식으로 설정할 수 있는 데스크탑 환경을 본적이 있는데 굉장히 불편해보였다. CTF 가 익숙해서 그런 것일까 아니면 원래 그런 것일까…?)

세 번째는 터치에 대해서 살펴보자. 당연한 얘기지만 터치는 CTF 방식 밖에 사용할 수 없다. 왜냐하면 마우스와 달리 절대 좌표 방식을 사용하고 있어서 포인터를 사용하지 않기 때문이다. 그리고 사실 생각해보면 터치는 포커스를 유지할 필요도 없다. DND(Drag-aNd-Drop) 을 할 때 그랩(grab) 만 유지해주면 되지 굳이 포커스를 유지하는게 큰 의미가 없기 때문이다.

마지막으로 현재 wayland/weston 에서 새로운 윈도우에서 키보드 포커스를 얻어서 키 입력을 받는 과정에 대해 간단히 정리하도록 하겠다.

  1. 사용자가 마우스 포인터를 새로운 윈도우로 이동한다.
  2. weston 은 마우스 포인터가 위치한 윈도우를 포커스로 등록하고 해당 윈도우를 소유한 클라이언트에게 wl_pointer 인터페이스의 enter 이벤트를 전달한다. (이전 포커스됐던 윈도우를 소유한 클라이언트에게는 wl_pointer 인터페이스의 leave 이벤트를 전달한다.)
  3. 클라이언트는 자신이 사용할 마우스 포인터의 이미지를 wl_pointer 인터페이스의 set_cursor 리퀘스트로 전달한다. (weston 이 마우스 포인터를 바로 변경한다.)
  4. 사용자가 마우스를 클릭한다.
  5. weston 은 현재 마우스에 포커스된 윈도우를 맨 앞으로 활성화시키고, 키보드의 포커스로 등록한다. (그리고 당연히 마우스를 포커스하고 있는 클라이언트에게 wl_pointer 인터페이스의 button 이벤트 또한 전달한다.)
  6. 사용자가 키보드를 누른다.
  7. weston 은 evdev 를 통해 전달받은 키보드 입력을 키보드에 포커스된 윈도우를 소유하고 있는 클라이언트에게 wl_keyboard 인터페이스의 key 이벤트를 이용하여 전달한다.

이게 현재 wayland/weston 에서 마우스와 키보드의 포커스 모델을 이용하여 키 입력을 받아내는 과정이다. UX 는 새로움보다는 익숙함이 우선시되기 때문에 이 과정 자체가 크게 바뀌는 일은 없을것같고, 새로운 입력 장치들이 나오고 그 장치들이 플랫폼 UX 에 활용이 된다면 그 장치의 특징에 맞는 새로운 포커스 모델이 나올 수는 있을것같다.

[WAYLAND] wayland 관련 참여해볼만한 프로젝트 소개

우리가 무언가 새로운 것을 배우고자 할 때 가장 좋은 방법 중에 하나는 일단 부딪쳐서 경험해보는 것입니다. 특히, 소프트웨어 개발자들에게는 직접 해본다는건 그 무엇보다 중요한 일인거같습니다. 그래서 오늘은 현재 활발히 진행 중인 대표적인 wayland 와 관련된 오픈소스 프로젝트들을 간단히 소개드리고자 합니다. 필자는 wayland 를 이용한 컴포지터와 쉘을 개발 중이기 때문에 관련 내용들이 블로그에 많지만, 다양한 클라이언트와 툴킷들도 wayland 를 지원하기 위한 작업들을 한창 진행 중이니 혹시 관심있으신 분들은 참여해보시면 좋은 경험이 될것같습니다.

wayland

# wayland
wayland 는 XML 파일 형식으로 되어있는 wayland 프로토콜을 클라이언트와 서버가 사용할 수 있는 C 코드와 헤더파일로 변환해주는 일과 실제 유닉스 도메인 소켓을 이용하여 메시지를 주고 받을 수 있도록 도와주는 라이브러리입니다. wayland 프로토콜을 이용하는 모든 클라이언트와 서버는 이 라이브러리를 이용하게 됩니다. 주로, wayland 의 창시자인 kristian høgsberg 이 관리하고 작년 중후반부터 안정화가 되어서 현재는 수정이 거의 없는 상태입니다.

# weston compositor
wayland 를 이용한 레퍼런스 컴포지터입니다. 말그대로 여러 서페이스들을 하나의 화면으로 합쳐주는 pixman 과 OpenGL 기반의 렌더링과 입출력 장치 관리 등을 제공합니다. 기능적인 부분과 정책적인 부분들이 많기 때문에 취향에 따라 할 수 있는 일들은 아직 굉장히 많이 남아있는 상태이고, 더군다나 FBDEV, DRM, X11 과 같은 기본적인 백엔드외에 다양한 백엔드들에 대한 지원도 가능하기 때문에 혹시 관심있는 사람은 새로운 백엔드를 개발해서 추가할 수 있는 기회도 있습니다. (하지만 wayland 프로토콜에 대한 검증과 레퍼런스 컴포지터이기 때문에 최적화나 사소한 버그 수정보다는 새로운 기능이나 정책에 대한 검증이 우선시 되고 있어 약간 폐쇠적인 성향이 있습니다.) 그리고 weston compositor 를 이용하여 다양한 쉘을 개발할 수 있도록 플러그인을 제공하고 있습니다.

# weston desktop-shell
weston shell-plugin 을 이용하는 기본적인 데스크탑 환경을 위한 쉘입니다. 이것도 검증을 위한 쉘이기 때문에 현재 디자인이나 이런 부분들은 아무도 신경을 쓰지 않고 있습니다.

# hawaii/orbital shell
weston shell-plugin 을 이용하는 데스크탑 환경을 위한 쉘들입니다. 둘다 QT5 기반이라서 디자인도 상당히 깔끔하고, 특히 hawaii 프로젝트는 상당히 빠른 속도로 개발되고 있는 프로젝트입니다. 새로운 데스크탑 환경을 개발하고 싶거나 관심있으신 분들은 참고하시면 많은 도움이 될 것 같습니다.

# mutter/kwin
리눅스 양대 데스크탑 환경인 gnome 과 kde 의 컴포지터로써 작년부터 꾸준히 wayland 지원 작업을 진행해왔고, 특히 mutter 의 개발자는 wayland/weston 에서도 굉장히 활발하게 활동하고 있고 아주 큰 영향력을 행사하고 있습니다. 하지만 X11 때부터 오랫동안 이어져오던 프로젝트여서 소스가 크고 X11 에 의존적인 부분이 많아서 실질적으로 참여하기 위해서는 어느 정도 준비가 필요할 것 같습니다.

# EFL
주로 스마트 장치에서 사용되고 있는 리눅스 기반의 통합 GUI 환경이고, 주로 삼성의 타이젠에서 사용되고 있고 주요 개발자들이 삼성 소속이기 때문에 약간 폐쇠적일꺼 같습니다. (이건 어디까지나 추측일뿐…) 하지만 그래서 그런지 가장 적극적으로 X11 에 대한 의존성을 제거하고 wayland 로 넘어가고 있는 프로젝트입니다. 소스를 보진 않았지만 wayland 를 위해 컴포지터를 거의 새로 개발했다고 하는 기사를 여러 번 봤기 때문입니다. 아무래도 다양한 데스크탑 환경을 책임지고 있는 mutter/kwin 보다는 빠르게 행동을 취하기 용이해서 그런 것 같습니다.

# xwayland
wayland 에서 X11 호환성을 유지할 수 있도록 도와주는 프로젝트입니다. 현재 weston 에 레퍼런스 구현물이 있고, xserver 측에도 백엔드 작업이 진행 중입니다. 아직 안정화가 필요하고 현재도 다양한 최적화가 진행 중입니다.

# libinput
wayland 를 이용하여 컴포지터와 쉘을 개발할 때 사용할 수 있는 udev/evdev 기반의 입력 장치 처리를 위한 라이브러리입니다. 공식 프로젝트로 인정받은지 얼마되지 않았고, 멀티터치 등 다양한 새로운 기능들이 추가되고 있어 앞으로 많은 작업들이 필요한 프로젝트입니다.

# mesa/DRM/linux kernel DRM driver
데스크탑과 스마트 장치 모두에서 OpenGL 을 이용한 컴포지팅이 일반화되었기 때문에 현재도 그렇고, 앞으로도 다양한 최적화 작업이 진행될 것으로 예상됩니다. 특히, wayland 를 이용한 스마트폰, 스마트TV, 스마트Car 와 같은 장치를 개발하는 회사에서 많은 관심을 가지고 있는 분야이기도 합니다. 하지만 mesa 소스의 난해함과 리눅스 커널 드라이버까지 포함되어있어 진입 장벽이 다른 프로젝트에 비해 상당히 높은 편입니다.

# input-method
wayland 에서 가상 키보드와 같은 input method 를 지원하는 프로젝트도 진행 중입니다. 현재 weston 은 간단한 형태의 가상 키보드를 제공하고 있기 때문에 관심있으신 분은 참고하면 좋을 것 같습니다.

# GTK+/QT
리눅스의 가장 대표적인 툴킷들이기 때문에 작년부터 활발히 wayland 지원 작업을 진행해왔습니다. 하지만 아직 xdg_shell 인터페이스가 안정화되지 않은 문제와 여러 가지 진행 중인 것들이 많이 남아있기 때문에 현재도 활발히 진행되고 있습니다.

# clutter/cogl
OpenGL 기반의 컴포지팅 라이브러리로 여러 어플리케이션에서도 사용 중이지만, 현재 mutter 에서도 사용 중입니다. 그래서 아직 안정화는 안 됐지만 wayland 컴포지터를 개발할 때 편리하게 사용할 수 있는 기능들이 몇 가지 들어가있습니다. 아쉬운 점은 정확한 이유는 모르겠지만 개발자 커뮤니티가 활발하진 않습니다.

# ozone-chrome
wayland 입장에서 가장 중요하고 필요한 일 중의 하나인 브라우저 지원을 해결해줄 수 있는 고마운 프로젝트입니다. ozone 은 크롬이 다양한 환경에서 쉽게 동작할 수 있도록 도와주는 계층이고, ozone 에 wayland 백엔드 지원 작업이 인텔을 중심으로 활발히 진행되고 있습니다. 최근 wayland 위에서 HTML5 기반의 하드웨어 가속을 지원하는 유투브 동영상 재생 데모도 공개되었습니다.

# gstreamer
세계적인 오픈소스 컨설팅 회사인 Collabora 에서도 wayland 에 굉장히 많은 관심을 가지고 참여를 하고 있습니다. 특히, Collabora 가 가장 많은 관심을 가지고 있는 프로젝트가 gstreamer 이기 때문에 wayland 에서도 영상 재생을 원활히 할 수 있는 기능에 대한 기여가 특히 높습니다. wayland 는 데스크탑 환경 뿐 아니라 스마트 환경에서도 활용도가 높기 때문에 위에서 언급했던 OpenGL 을 이용한 컴포지팅 최적화와 더불이 많은 회사들이 관심을 가지고 있는 분야입니다.

이외에도 수많은 프로젝트가 활발히 진행 중입니다. 기존의 X11 환경에서 혹은 프레임버퍼 위에서 동작하던 거의 모든 UI 관련된 프로젝트들이 wayland 로 전환되고 있다고 보면 되기 때문에 앞으로 wayland 의 필요성과 활용도는 점점 더 높아질 것으로 예상됩니다.

[WAYLAND] wl_surface 인터페이스 문서 패치 리뷰

최근 며칠동안 메일링리스트와 IRC 에서 재밌는 논의가 있었습니다. 바로 wl_surface 인터페이스가 제공하는 attach/damage/frame/commit 리퀘스트에 대한 논의였는데요, 문제의 핵심은 이 네 가지 리퀘스트에 대한 명세가 명확하지 않아 클라이언트 개발자들이 혼란스러워한다는 것이고, 그래서 Collabora 에 근무하는 Pekka Paalanen 이 wayland 의 코어 인터페이스 명세 파일인 wayland.xml 에 wl_surface 에 관련된 코멘트를 수정하는 패치를 보냈습니다. (수많은 개발자들이 사용하는 API 를 디자인하는건 정말 너무나 어려운 일인거 같습니다.)

관련된 얘기들 중에 몇 가지만 살펴보도록 하겠습니다.

첫 번째는 클라이언트가 frame callback 을 받는 시점에 대한 부분입니다. 많은 개발자들이 frame callback 을 자신이 업데이트한 내용이 실제 모니터에 나타나는 시점으로 생각하고 있어서 오해가 발생했는데요, 실제 frame callback 의 의미는 클라이언트가 업데이트한 내용을 사용해서 최종 화면을 렌더링했다는 의미입니다. 즉, 렌더링된 프레임버퍼가 준비되고 실제 모니터에 뿌리기 위해 DRM 으로 페이지 플립(page flip) 요청을 보냈다는 의미입니다. (이후, 페이지 플립이 완료되면 DRM 을 통해 weston 으로 이벤트가 날아옵니다. 하지만 이 사실을 따로 클라이언트에게 통보하지는 않습니다.)
(참고로 이건 DRM 백엔드를 사용하는 경우이고, 현재 weston 의 FBDEV 백엔드는 하드웨어 프레임버퍼를 바로 매핑해서 그 위에 렌더링된 결과물을 덮어쓴 뒤 frame callback 이벤트를 보내기 때문에 클라이언트가 frame callback 이벤트를 받았을 때는 이미 모니터가 업데이트된 뒤라고 볼 수 있습니다. 결국, 백엔드 구현 방식에 따라 동작이 다르다는 겁니다.)

두 번째는 damage 리퀘스트의 필요성에 대한 부분입니다. 어떤 클라이언트는 처음에만 attach/damage/frame/commit 리퀘스트를 다 보내고, 그 뒤에는 frame/commit 리퀘스트만 보낸다고 하는데, 이건 문제의 소지가 굉장히 많습니다. 기본적으로 weston 과 같은 컴포지터들은 화면 깜빡임을 최소화하기 위해 전체 화면을 매번 새로 그리지 않고 꼭 필요한 부분만 갱신합니다. 그래서 weston 에게 해당 서페이스의 수정된 부분을 명시하는 damage 리퀘스트를 보내지 않으면 weston 은 다음 컴포지팅을 할 때 해당 서페이스의 수정된 부분을 적절히 반영할 수 없게 됩니다. (상황에 따라 전체를 새로 그리는 경우도 있긴 합니다. 예를 들어, 스크린세이버나 락에서 돌아올 때는 전체 화면이 모두 다시 그려질 필요가 있습니다.)

마지막으로 버퍼(wl_buffer) 와 서페이스(wl_surface) 의 상태(configure) 는 attach 리퀘스트가 없으면 바뀌지 않습니다. 이유는 현재의 weston 은 wl_surface 인터페이스의 commit 리퀘스트에서 서페이스의 상태를 변경하는데, 이 때 새로 attach 된 버퍼가 없으면 상태를 변경하지 않기 때문입니다. 예를 들어, 버퍼의 뷰포트(viewport) 에 새로운 transform 을 적용하거나 서페이스를 전체 화면으로 변경하여도 attach 리퀘스트가 없으면 commit 리퀘스트를 날려도 해당 내용이 반영되지 않는다는 말입니다.

지금까지 살펴본 것처럼 wayland 인터페이스와 이에 대한 설명이 불분명한 부분도 있긴 하지만, 해당 인터페이스를 사용하는 클라이언트 개발자와 컴포지터/쉘 개발자들이 실제로 어떻게 이해하고 개발하느냐가 다르기 때문에 근본적인 해결은 불가능한 것 같습니다.

[WAYLAND] 다중 GPU 지원 (dma-buf/prime)

최근 두 개 이상의 그래픽 카드를 가지고 있는 사용자가 늘어남에 따라 리눅스 환경에서 이를 효과적으로 사용할 수 있는 기술에 대한 관심이 많아지고 있다. 대표적인 기술이 dma-buf 혹은 prime 이라고 하는 기술인데, 오늘은 dma-buf 가 무엇인지와 weston 에서 dma-buf 를 어떻게 활용하는지를 간단히 소개하고자 한다.

지난 DRM 버퍼의 동작 과정에서 설명한 내용을 잘 살펴보면 한 가지 문제가 있다. 만약에 DRM 백엔드를 사용 중인 weston 위에서 클라이언트가 OpenGL 을 사용한다면 어떻게 될까? 그래픽 카드와 드라이버에 따라 상황은 다르지만, 많든 적든 기본적으로 병목 현상은 발생할 것이다. 사실 이 문제는 하나의 그래픽 카드만 가지고 있을 때는 어쩔 수 없는 상황이기 때문에 상관없지만, 두 개 이상의 그래픽 카드를 가지고 있을 때도 하나만을 사용할 수 밖에 없다면 꽤 아쉬운 상황이 된다. 바로 이러한 상황을 해결하기 위해 나온 기술이 dma-buf 라고 하는 기술이다.

이 기술의 목표는 사실 굉장히 단순하다. 하나의 GPU 에 있는 버퍼를 다른 GPU 에 있는 버퍼로 복사해주는 기술이다. 만약에 weston 에서 dma-buf 를 사용한다면 기본 시나리오는 이렇다. 우선 두 개의 GPU0 과 GPU1 이 있다고 가정해보자. 클라이언트는 GPU0 을 이용하여 렌더링을 한다. 그리고 GPU0 의 메모리에 있는 프레임버퍼의 위치를 weston 에게 알려주면, weston 은 GPU0 의 프레임버퍼를 GPU1 로 복사한다. 그리고 weston 은 복사한 프레임버퍼를 텍스쳐로 이용하여 컴포지팅을 위한 렌더링을 한다. 이렇게 되면 클라이언트와 weston 은 GPU 를 하나씩 선점하여 전체 자원을 마음껏 활용할 수 있게 된다. 이 과정을 간략하게 그림으로 표현하면 다음과 같다.

prime

실제 동작 과정은 DRM 버퍼를 이용한 동작 과정과 유사하다. 단지 차이는 client-side mesa 에서 server-side mesa 로 전달하는 프레임버퍼에 대한 핸들인데, 하나의 GPU 만을 사용할 때는 하나의 GPU 내에서만 유효한 핸들(local name) 을 전달하면 되지만, 여러 개의 GPU 를 사용할 때는 전역적으로 유효한 핸들이 필요하다. 현재의 mesa 에서는 이를 해결하기 위해 파일디스크립터를 이용하고 있다. 즉, client-side mesa 에서 프레임버퍼를 생성한 뒤 커널에게 전역 핸들을 요청하면 커널은 해당 프레임버퍼를 지칭하는 struct file 을 생성하여 fd 를 리턴한다. 그리고 이 fd 를 SCM_RIGHTS 을 이용하여 server-side mesa 에 전달하면 동일한 struct file 을 공유하게 되므로 GPU0 에 있는 프레임버퍼에 대한 접근이 가능해진다. 프레임버퍼를 복사한 후의 과정은 일반적인 DRM 버퍼의 동작 과정과 동일하다. 여기까지가 기본적인 weston 이 dma-buf 를 이용하는 방식이다.

사실 이것 외에 해결해야 할 문제들이 아직 많다. 예를 들면, 클라이언트에게 특정 GPU 에 대한 권한을 얼마나 줄 것인지, 그리고 GPU 에서 GPU 로 메모리를 복사할 때 동기화 문제도 아직 해결되지 않은 상태이다. 하지만 머지않아 이러한 문제들이 해결되고 메인라인에 반영될 것으로 기대된다.

[WAYLAND] DRM 버퍼 동작 과정 (OpenGL)

지금까지는 wayland/weston 관련된 모든 내용들을 되도록이면 쉽게 이해할 수 있도록 공유메모리 버퍼를 기준으로 설명하였다. 하지만 실제 wayland/weston 을 사용할 때는 하드웨어 가속을 사용하는 것이 지극히 당연하기 때문에 오늘은 현재 wayland/weston 이 제공하는 OpenGL 기반 DRM 버퍼의 동작 과정을 살펴보도록 하겠다. 사실 공유메모리 버퍼와 DRM 버퍼의 동작 원리는 동일하다. 다만 차이는 공유메모리 버퍼는 CPU 가 관리하는 메모리를 공유하는 것이고, DRM 버퍼는 GPU 가 관리하는 메모리를 공유하는 것일 뿐이다. 하지만 문제는 GPU 의 동작 과정을 이해하기 위해 알아야 하는 소프트웨어 스택이 까다롭다는 점이다. 그래서 우선 wayland/weston 에서 DRM 버퍼 동작 과정을 이해하기 위해 알아야 하는 소프트웨어들의 구조를 살펴보도록 하겠다.

sw

위의 그림은 리눅스 환경에서 OpenGL 을 이용하기 위해 사용하는 주요 소프트웨어들의 구조이다. 일단 가장 눈에 띄는 것은 리눅스 커널에도 인텔 그래픽 카드인 i915 드라이버가 있고, mesa 에도 i915 드라이버가 있다는 것이다. 당연히 둘의 역할이 다른데, 간단히 설명하면 리눅스 커널에 있는 드라이버는 주로 GEM(Graphics Execution Manager) 이라고 하는 GPU 의 메모리를 할당하고 해제하는 역할과 KMS(Kernel-Mode Setting) 를 위해 crtc/encoder/connector 등에 직접적으로 접근하는 역할을 한다. 그리고 mesa 에 있는 드라이버는 GEM 을 통해 할당받은 버퍼에 필요한 내용을 담거나 렌더링을 요청하는 등 실제 OpenGL 의 동작 과정을 관리하는 역할을 한다고 보면 된다. 그리고 DRM 은 mesa 에서 커널에 있는 DRM 드라이버에 접근하기 위해 사용하는 일종의 wrapper 함수들의 집합이라고 보면 된다.

이제 OpenGL 의 기본적인 동작 과정에 대해 살펴보자.

rendering

우선 OpenGL 을 이용하여 무언가를 렌더링하기 위해서는 기본적으로 세 가지의 버퍼가 (이외에도 여러 가지 버퍼가 있지만 생략) 필요하다. 첫 번째 배치버퍼(batch buffer) 는 OpenGL 의 커맨드들을 순서대로 담는 버퍼이고, 두 번째 텍스쳐버퍼(texture buffer) 는 렌더링할 때 사용되는 텍스쳐를 담는 버퍼이고, 마지막 프레임버퍼(framebuffer) 는 렌더링된 결과 화면을 저장하는 버퍼이다. 세 가지 버퍼 모두 역할이 다를뿐이지 동일한 메모리를 사용한다. 이제 기본적인 OpenGL 의 렌더링 과정을 살펴보면, 일단 OpenGL 은 커맨드 기반이기 때문에 폴리곤을 그리거나(glVertex) 폴리곤에 텍스쳐를 붙이거나 광원을 조절하거나 하는 등의 모든 일은 커맨드 형태로 배치버퍼에 순서대로 저장된다. 그리고 텍스쳐버퍼에 필요한 이미지를 저장하는(glTexImage) 등의 렌더링에 필요한 준비 작업이 모두 끝나고 나면 마지막으로 한번에 렌더링 요청을(eglSwapBuffers) 하게 된다. 렌더링하는 과정은 mesa 와 리눅스 커널 드라이버에서 GPU 에게 배치버퍼와 텍스쳐버퍼, 그리고 프레임버퍼의 메모리 주소와 같은 필요한 정보만 GPU 에게 잘 전달해주면 나머지는 GPU 가 알아서 처리해준다. 그리고 렌더링이 완료되면 프레임버퍼에는 최종 결과 화면이 담겨져있게 된다. 하지만 여기서 끝이 아니고, 현재 모니터가 출력하고 있는 화면을 방금 렌더링한 프레임버퍼로 변경해주어야 한다. (그래서 기본적으로 더블버퍼링을 한다) 최종적으로 이 작업까지 모두 끝나고나면 실제 렌더링된 화면이 우리의 모니터에 나타나게 된다.

지금까지 리눅스 환경에서 OpenGL 의 기본적인 동작 과정을 살펴보았다. 이제 본격적으로 wayland/weston 에서 DRM 버퍼를 사용하는 과정에 대해 살펴보도록 하겠다.

rendering

위 그림은 클라이언트가 OpenGL 로 렌더링한 결과 화면을 weston 이 받아서 화면에 그리는 과정을 간략하게 나타낸 것이다. 우선 클라이언트는 현재 mesa 가 제공하는 wayland 를 백엔드로 하는 EGL window/surface 와 OpenGL 을 위한 컨텍스트를 생성하고 필요한 렌더링 준비작업을 수행한다. 그리고 eglSwapBuffers() 함수를 이용하여 실제로 렌더링을 하게 되면 client-side mesa 에서 클라이언트가 요청한 프레임버퍼에 대한 핸들(local name: 리눅스 커널이 제공하는 해당 GPU 내의 메모리 영역을 구분해주는 아이디라고 보면 된다) 을 server-side mesa 로 전달한다. (동일한 mesa 라이브러리에 클라이언트와 weston 이 사용하는 함수가 모두 들어있다.) 그러면 server-side mesa 에서는 전달받은 핸들을 이용하여 클라이언트가 사용 중인 프레임버퍼에 접근할 수 있는 wl_drm_buffer 를 생성한다. (공유메모리 버퍼를 사용할 때는 이와 유사한 일을 wayland 가 처리한다.) 여기까지 완료되면 일단 클라이언트가 사용하는 프레임버퍼에 weston 이 접근할 수 있는 준비는 끝난 것이다. 그리고나서 클라이언트가 렌더링을 하고 나면 최종 이미지가 프레임버퍼에 저장되고, 렌더링이 완료된 버퍼(wl_buffer) 를 원하는 서페이스(wl_surface) 에 attach/damage/commit 하는 과정은 client-side mesa 가 알아서 처리해준다.

위에서 설명한 과정은 클라이언트가 렌더링한 결과 화면을 weston 이 전달받는 과정이고, 이제 weston 에서 (컴포지팅된) 최종 화면을 만들어내는 과정을 살펴보자. 이 과정은 생각보다 단순한데, weston 은 위에서 클라이언트가 렌더링한 결과 화면인 프레임버퍼를 텍스쳐로 사용하여 서페이스(wl_surface) 의 위치와 크기에 맞는 폴리곤을 생성하면 된다. 물론 여러 서페이스가 겹치기 때문에 적절하게 잘려진 폴리곤을 생성하는 과정과 그에 맞는 텍스쳐 좌표를 지정하는 것은 필수이다. 그리고 최종적으로 eglSwapBuffers() 함수를 이용하여 렌더링하면 최종 결과 화면이 생성되고, 이 결과 화면을 실제 모니터에 출력하면 된다. (클라이언트가 사용한 eglSwapBuffers() 함수는 백엔드가 wayland 이기 때문에 위에서 설명한 과정을 거친 것이고, weston 이 사용한 eglSwapBuffers() 함수는 백엔드가 DRM 이기 때문에 클라이언트와는 다른 과정을 거치게 된다.)

지금까지 wayland/weston 에서 DRM 버퍼의 동작 과정을 살펴보았다. 클라이언트와 weston 외에 mesa 가 하는 일이 많고 복잡하기 때문에 당장은 이해하기 어렵겠지만, 일단은 클라이언트가 렌더링한 프레임버퍼를 weston 이 전달받고, 이를 텍스쳐로 사용하여 최종 화면을 렌더링한다는 것 정도만 기억해두면 될것같다.