앞서 프레임버퍼에 대해서 짧고 간결하게 설명을 하였다. 장점과 단점은 시간이냐 비용이냐의 차이가 된다. 따라서, 간단한 GUI를 자주 개발하는 독자의 경우에는 이러한 라이브러리를 잘 만들어두면 여기저기 써먹을 데가 많을 수 있다. 라이선스 문제도 없으니 말이다. 필자도 예전에 라이브러리로 만들어놨었는데, 쓸일이 없다보니 어딧는지도 모르겠다.
프레임 버퍼 예제1에서는 프레임버퍼 정보를 가져오는 방법과 색상을 프레임버퍼 영역 전체에 색상을 채우는 예제를 통해서 어떻게 프레임버퍼를 사용하는지에 대한 기본 개념을 잡고 가도록 하겠다. 앞서 언급했지만, 프레임버퍼는 하드웨어에서 제공해주는 메모리 공간이고, 해당 공간에 대해서 커널을 통해 접근이 가능하다. 왜냐면, 커널에 해당 장치에 대한 드라이버가 있고, 그 드라이버에서 제공되는 영역을 사용자 영역에서 접근할 수 있도록 해주는 것이 커널이기 때문이다. 따라서 소개에서도 이야기 했든 커널에서 제공되는 헤더를 이용해서 해당 메모리에 접근할 수 있다. 결국 이 말은 리눅스 시스템에 연결되는 하드웨어에 따라서 프레임버퍼의 크기가 다르다는 것을 의미한다.
뿐만아니라, 일부 장치의경우 여러개의 프레임버퍼를 제공하기도 한다. 각각의 프레임버퍼는 영역이 지정되어있어서 서로 오버레이 될 수 있다. 필자가 10년도 더 전에 사용하던 임베디드 시스템 중 어떤 장치의 경우에는 이러한 프레임 영역을 5개를 지원해서, 오버레이용으로 편리하게 프로그래밍을 했었는데, 그 뒤로 사용한 장치들 대부분은 단일 프레임버퍼만 제공해서 이미지버퍼에서 오버레이를 넣어 화면에 뿌리는 방식을 사용해야만 했었다. 따라서, 모든 장치들이 멀티 프레임버퍼를 지원한다고 생각하지 않고 개발하는 것이 유리할 수 있다.
1. 프레임버퍼 테스트
아래의 명령을 이용해서 랜덤으로 생성된 데이터를 프레임버퍼에 집어 넣는다. 그러면 화면에 자글자글한 이미지들이 표시된다. USB 캡쳐 장치를 썼더니 가용한 공간이 없다는 메시지가 나와서 이 예시는 터미널에서 실행 시켰다. linux에서 /dev/urandom은 난수 발생을 해주는 역할을 한다. 그리고 fb0은 frambuffer장치의 첫번째 장치를 의미한다. 따라서, 프레임버퍼 공간을 랜덤한 값으로 채우게 되며, 그 결과 지지지지지지직한 화면을 볼수 있다.
$ cat /dev/urandom > /dev/fb0
실행 결과는 다음과 같다. 이렇게 표시되지 않느다면, 프레임버퍼 스페셜파일( fb0)가 아니라 다른 장치로 설정된 경우일 수 있다. 예전에 특정 장치는 fb1로 설정된 경우도 있었다. 이는 드라이버나 설정등에서 어떻게 해두냐에 따라 다르다. 따라서 ls /dev/fb*로 확인후 fb1, fb2... 로 명령을 수정하여 실행한다. 특별한 경우가 아니라면 출력이 분명 되어야 한다.
2. 프레임버퍼 정보 읽어오기
프레임버퍼를 컨트롤하기 위해서는 시스템에 연결된 장치에서 정보를 가져오는 것 부터 시작된다. 얻어온 정보를 통해서 디스플레이하기 위한 BPP(픽셀당 비트수)를 확인할 수 있고, 전체 프레임버퍼의 크기를 알 수 있다. 아래와 같이 프레임버퍼 구조체를 통해 커널로부터 프레임버퍼의 정보를 얻어올 수 있다.
2.1. 소스작성
소스는 다음과 같이 작성하면된다. 주석 어려운 부분이 없으므로 주석으로 설명을 대체한다.
// File : fb_info.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> // 파일컨트롤 관련 헤더 #include <sys/ioctl.h> // 장치 제어관련 헤더 #include <linux/fb.h> // 프레임버퍼 관련 헤더 #define FBDEV "/dev/fb0" int main(int argc, char** argv) { int fd; // 프레임 버퍼용 파일 디스크립트 // 프레임버퍼 장치 열기 fd = open(FBDEV, O_RDWR); if (fd < 0) { printf("Device %s open error\n",FBDEV); return -1; } // 프레임버퍼의 스크린 정보를 얻어오기 위함 struct fb_var_screeninfo scr_info; // 프레임버퍼 구조체 // // ioctl()을 통해 커널로부터 정보를 얻어옴 if (ioctl(fd, FBIOGET_VSCREENINFO, &scr_info) < 0) { perror("ioctl call error"); close(fd); return -1; } // 가져온 프레임버퍼의 정보를 출력한다. printf("Framebuffer Information:\n"); printf("Resolution: %dx%d\n", scr_info.xres, scr_info.yres); printf("Virtual Resolution: %dx%d\n", scr_info.xres_virtual, scr_info.yres_virtual); printf("Bits Per Pixel: %d\n", scr_info.bits_per_pixel); printf("Red Length: %d, Offset: %d\n", scr_info.red.length, scr_info.red.offset); printf("Green Length: %d, Offset: %d\n", scr_info.green.length, scr_info.green.offset); printf("Blue Length: %d, Offset: %d\n", scr_info.blue.length, scr_info.blue.offset); printf("Transp Length: %d, Offset: %d\n", scr_info.transp.length, scr_info.transp.offset); // 사용이 완료된 프레임버퍼 디스크립트를 닫아준다. close(fd); return 0; } |
2.2. 컴파일 및 테스트
프레임버퍼는 리눅스에서 기본으로 지원하기 때문에 리눅스의 장치관련 헤더파일(ioctl.h와 linuxfb.h)만 추가하면 되므로 별도로 준비 할 것은 없다.
$ gcc -o fb_info fb_info.c
2.3. 실행 결과
실행결과는 다음과 같다. 앞서 설명한것 같은데, 뒷쪽 화면은 라즈베리파이에 연결된 모니터 화면이고, 앞의 터미널 화면은 ssh화면이다. 필자의 작업디렉터리는 ~/works (/home/pi/works)이다.
라즈베리파이 터미널에서 직접 코딩하고 빌드해도 되고, ssh로 실행해서 결과만 모니터에 출력하는 것도 된다. 참고로 결과는 프레임버퍼에 출력되므로, ssh로 접속한 터미널에는 메시지 이외에 아무런 변화가 없는게 정상이다.
프레임 버퍼 정보를 읽어보니, 화면 해상도는 Full HD(1920*1080)이고, 가상 해상도도 동일하다, BPP즉, 픽셀을 표현하는 방법은 16비트를 이용하고 있고, 구조를 보니 RGB 565를 이용함을 알수있다. 맨 마지막의 Transp는 보통 Alpha라고 이야기 하는 분들도 있던데, 여기서는 그냥 투명도라고 생각해주면 되겠다.
위의 결과에 따라 앞으로 컴파일하고 동작시킬 모든 데이터는 16비트로 처리하면 되겠다.
최근댓글