월간 보관물: 2013 11월

[WAYLAND] 4. 입력 장치

이번 시간에는 키보드, 마우스와 같은 입력 장치들이 어떻게 다루어지는지를 살펴보고자 한다. 우선 입력 장치를 다루기 전에 seat 이라는 개념에 대해 간단히 설명하도록 하겠다. seat 은 한국어로 번역하면 자리/좌석을 의미한다. 즉 한 명의 사용자가 자리에 앉아서 사용할 수 있는 장치들의 묶음을 보통 하나의 seat 이라고 보면 된다. 예를 들어 우리가 일반적으로 사용하는 키보드와 마우스, 그리고 모니터가 각각 하나씩 있으면 하나의 seat 이 완성이 되는 것이다. 그래서 일반적인 사용자들은 “seat0” 만을 사용한다(보통은 키보드, 마우스 모니터가 하나씩 있기 때문에). 하지만 마치 하나의 서버에 여러 개의 터미널을 접속해서 사용하는 것처럼 하나의 본체에 여러 개의 키보드, 마우스 그리고 모니터를 연결해서 사용하는 경우도 있을 수 있다. 이럴 경우에는 윈도우 매니저가 multi-seat 환경을 지원해야만 여러 명의 사용자가 동시에 혹은 각각 윈도우 환경을 사용할 수 있다. multi-seat 자체만으로도 여러 가지 이슈들이 많기 때문에 자세한 이야기는 따로 하도록 하겠다(이를 위해 우리가 전통적으로 알고 있는 virtual terminal 과 최근 많은 이슈화가 되고 있는 systemd/logind 에 대해 조만간 자세히 다루도록 하겠다.)

우선 wayland/weston 환경에서 입력 장치를 사용하기 위해서는 일단 udev 를 이용하여 현재 사용 가능한 입력 장치들을 활성화 한다. 이때 기본적으로 “seat0” 를 사용하지만 옵션으로 다른 seat 을 사용할 수 있다(현재의 weston 은 기본적으로 하나의 컴포지터 인스턴스에서 하나의 seat 만 사용할 수 있다. 즉, 여러 개의 seat 을 사용하기 위해서는 독립적인 컴포지터 인스턴스를 필요한 만큼 동작시켜야 한다.) 그리고 활성화된 입력 장치들은 evdev 를 이용하여 이벤트를 전달받을 수 있도록 준비하여 클라이언트가 요청하면 바로 사용할 수 있도록 준비를 마무리한다.

weston 이 초기화를 끝낸 후, 클라이언트가 실행되면 weston 은 wl_registry 인터페이스를 이용하여 클라이언트에게 wl_seat 인터페이스를 등록하도록 요청하고, 클라이언트가 wl_seat 인터페이스를 등록하고 나면 weston 은 클라이언트에게 현재 사용가능한 입력 장치들에 대한 정보를 capabilities 이벤트를 이용하여 전달한다. 만약 현재 하나의 키보드와 하나의 마우스가 사용가능하다면 클라이언트는 capabilities 이벤트 핸들러에서 이 사실을 알 수 있고, 바로 키보드와 마우스를 사용하기 위해 각각 wl_keyboard 인터페이스와 wl_pointer 인터페이스를 등록한다. 그리고나서 해당 클라이언트가 키보드와 마우스에 포커싱이 되면 해당 입력 장치에서 발생한 이벤트들을 wl_keyboard, wl_pointer 인터페이스를 통해 전달받게 된다. 아래의 그림은 wayland/weston 에서 입력 장치가 동작하는 전체적인 과정을 간단히 그림으로 표현한 것이다.

seat

위의 그림을 보면서 간단히 요약하면, weston 에서 udev 로 현재의 seat (기본적으로 “seat0”) 에 해당하는 입력 장치들을 evdev 를 이용하여 사용가능하도록 준비한다. 그리고 클라이언트에게 사용가능한 입력 장치들에 대한 정보를 wl_seat 인터페이스의 capabilities 이벤트로 전달하고, 클라이언트는 필요한 입력 장치들을 사용하기 위해 wl_keyboard, wl_pointer 혹은 wl_touch 인터페이스를 연결한다. 여기까지가 wayland/weston 환경에서 입력 장치가 동작하는 과정이다.

Advertisements

[RTRT] 레이트레이싱 기법 소개

3D 컴퓨터 그래픽 기술의 기본적인 목적은 3D 공간을 특정 시점(카메라)에서 바라봤을 때의 2D 영상을 만들어내는 것이다. 여기에는 크게 두 가지 방식이 있다. 첫 번째 레스터라이징 기법은 단순히 3D 공간을 카메라 시점에서 바라봤을 때 앞에 있는 물체를(가까이 있는 물체의 표면을) 출력하는 기법이고, 두 번째 레이트레이싱 기법은 우리가 실세계에서 눈으로 사물을 바라보는 과정(광원에서 광자들이 튀어나와 사물에 충돌 후 반사되어 눈으로 들어오는 과정)을 컴퓨터로 재현하는 기법이다. 아래 왼쪽 그림은 레스터라이징 기법의 결과물이고, 오른쪽 그림은 레이트레이싱 기법의 결과물이다.

rasray

왼쪽 그림(레스터라이징 기법)을 보면 반사/투과 및 명암 차이가 전혀 나타나지 않는다. 이는 실사와는 거리가 멀지만 속도가 빠르기 때문에 3D 게임같은 실시간 응용에서 널리 사용되고 있다. 오른쪽 그림(레이트레이싱 기법)은 보는 것처럼 자연스러운 명암 표현으로 실사와 유사한 느낌이 든다. 하지만 엄청난 양의 연산이 필요하기 때문에 지금까지는 영화 CG 제작과 같은 오프라인 환경에서 주로 사용되어 왔다. 아래 그림은 두 가지 기법의 동작 과정을 간단히 표현한 것이다.

ras0ray0

왼쪽의 레스터라이징 기법은 위에서 설명한 것처럼 카메라 시점에서 투사면으로 발사된 광선이 처음 충돌하는 표면에서 색을 바로 결정한다. 반면에 오른쪽의 레이트레이싱 기법은 광선의 이동 경로를 추적하여 색을 결정하게 된다. 위에서 한 가지 특이한 점은 실세계에서는 광원에서 광자들이 출발하여 물체에 충돌 후 우리의 눈으로 들어오지만 레이트레이싱 기법은 반대로, 카메라에서 화면 방향으로 광선이 출발한다. 이는 광원에서 나오는 광자들의 양이 너무 많고, 그 중에서 실제로 카메라로 들어오는 양은 미미하기 때문에 효과적인 렌더링을 위해 카메라로 들어오는 광자들만을 계산하기 위해서이다. 하지만 포톤 매핑과 같은 기법들은 광원에서 나온 광자들을 표면에 저장하여 렌더링에 사용하기도 한다. 마지막으로 빛의 이동 경로를 추적하는 과정을 통해 최종 색 값을 결정하기 위해서는 아래의 Rendering Equation 이라고 부르는 모델링 기법을 사용한다[1].

rendering equation

위의 식은 화면의 특정 위치에서 특정 방향으로 반사되는 빛의 양을 계산하기 위한 것이다. 오른쪽의 적분은 해당 위치에서 법선 벡터 방향의 반구(hemisphere)로 들어오는 모든 빛의 양을 더한 것이다. 결국 다양한 레이트레이싱 기법들은 위의 적분을 얼마나 효과적으로 풀어낼 것이냐에 대한 것이다. 패스트레이싱과 포톤 매핑같이 몬테카를로 기법을 이용하는 확률 기반의 레이트레이싱 기법은 멀티 샘플링 방식으로 위의 식을 풀기 때문에 충분히 샘플링하지 않을 경우에는 노이즈가 심한 이미지가 만들어진다[2]. 그리고 향후 유명 게임 엔진들에서 실시간 전역 조명을 위해 적용될 것으로 보이는 Voxel Cone Tracing 은 Sparse Voxel Octree 기반으로 위의 적분식을 5~6 개 정도의 Cone 을 합산하는 방식으로 대체한다[3].

지금까지는 레이트레이싱이라는 기술이 여러 가지 제약사항으로 인해 굉장히 제한된 환경에서만 사용되었지만, 앞으로는 하드웨어/소프트웨어 기술의 발전으로 다양한 온/오프라인 환경에서 널리 사용될 것으로 기대된다.

[참고자료]

1. J. T. Kajiya, “The Rendering Equation”, ACM SIGGRAPH Volume 20, Number 4, 1986.
2. C. Wynn, “An Introduction to BRDF-Based Lighting”, NVIDIA Corporation.
3. C. Crassin, “Interactive Indirect Illumination Using Voxel Cone Tracing”, ACM SIGGRAPH Volume 30, Number 7, 2011.

[NEMOSHELL] 터미널 & 시그널 처리

오늘 NEMOSHELL 에서 실행한 터미널에서 어플리케이션을 실행하고 나서 CTRL+C (SIGINT) 가 먹지 않는 버그를 발견했다. 일반적인 단일 어플리케이션을 개발하고 있는 상황이라면 바로 시그널 처리에 문제가 있다는걸 알았겠지만, 윈도우 매니저와 쉘을 개발하고 있는 중이기 때문에 처음에는 키보드 입력 값이 터미널 쪽으로 전달되는 과정에서 문제가 있는지 알고 삽질하다가 결국 엉뚱한 곳에서 문제를 해결하였다.

우선 일반적인 그래픽 기반의 터미널이 동작하는 과정을 간단히 설명하도록 하겠다.

terminal

위의 그림은 WAYLAND/WESTON 기반의 그래픽 기반 터미널이 동작하는 과정을 간단히 표현한 것이다. 일단 간단히 실행 준비 과정부터 살펴보면, 사용자가 터미널을 실행하면 터미널은 /bin/bash 의 표준 입출력을 파이프로 연결한 다음 실행한다. 이렇게 되면 터미널에서 파이프를 이용하여 /bin/bash 에 커맨드를 전달하고, 그 출력값을 간단히 받아올 수 있다. (즉, 실질적인 커맨드 기반 쉘의 기능은 /bin/bash 를 그대로 활용하는 것이다.)
그리고 전체 동작 과정은 다음과 같다. 터미널이 포커싱되어 있는 상태에서 키보드를 누르면 먼저 WESTON 이 EVDEV 를 통해 입력값을 받아오고, 터미널에게 wl_keyboard 인터페이스를 이용하여 값을 전달한다. 그리고 터미널에서는 키보드 상태와 전달값을 이용하여 필요한 입력값을 파이프를 통해 /bin/bash 에 전달한다. 그리고 /bin/bash 가 이를 처리하고 출력값이 있다면 반대로 파이프를 이용하여 출력값을 터미널로 전달한다. 마지막으로 터미널은 이 값을 그래픽 엔진(여기서는 CAIRO 벡터 엔진)을 이용하여 그린 다음, wl_surface 인터페이스를 통해 WESTON 에게 전달하면, WESTON 은 이를 그래픽 장치에 반영하게 된다.
위에 간단히 설명한 과정이 일반적인 그래픽 기반의 터미널이 동작하는 과정이다. 그리고 마지막으로 CTRL+C 가 전달되는 과정은 터미널에서 /bin/bash 에게 CTRL+C 에 해당하는 ASCII 코드 값인 0x03 을 전달하면 /bin/bash 가 foreground 로 동작 중인 어플리케이션에게 SIGINT 를 전달하여 어플리케이션은 실행을 종료하거나 등록된 핸들러를 실행하게 된다.

즉, 위에서 설명한 것처럼 CTRL+C 를 키보드로 눌러도 어플리케이션이 반응하지 못할 이유는 너무나도 많다. 다행히 이것저것 디버깅을 하다가 결국 어플리케이션이 SIGINT 를 블로킹하고 있다는 사실을 알아냈다. 알고 보니, /bin/bash 와 터미널도 모두 SIGINT 를 블로킹하고 있었다. 이유는, 당연히(!!!) 나의 실수로 NEMOSHELL 에서 터미널을 실행할 때 시그널을 초기화해주는 걸 깜빡한 거였다. 그래서 부모의 시그널 설정을 그대로 상속받아서 SIGINT 가 블로킹되어있었던 것이다. 이거 때문에 오후를 그냥 날리다니…ㅠㅠ 그래도 덕분에 겸사겸사 이것저것 살펴봤으니 불행 중 다행이다;;