프레임버퍼 레벨의 소프트웨어 스택에서 위치

Stephen Kyoungwon Kim@Google의 이미지

VNC가 어떻게 동작하는지 이해하려고 노력 중인데 "at framebuffer level"이라는 표현이 있습니다. 이게 소프트웨어 스택 상에서 어디부터 존재하는 개념인가요?

firefox, gedit 같은 응용 프로그램이 화면에 뭔가를 그리려면 아마 1920 * 1600 해상도의 픽셀 버퍼에다 일일이 셋팅을 주는 대신, X server나 그 위의 뭔가에 대고 "(100, 400)부터 300 x 500짜리 사각형을 그려라"라는 요청을 날리는 것으로 알고 있습니다. 그러니까 대부분의 경우에 X application들은 프레임버퍼의 존재를 모르지 않을까 짐작하는데 맞나요?

그런데 마지막까지 내려가면, 모니터 모듈은 아마도 자기랑 하드웨어상으로 연결된, 이를테면, 가상 메모리/물리 메모리 내의 특정 영역에서 각 픽셀을 어떻게 그려야 하는지가 일일이 정의된 정보를 1초에 N번씩 스캔해서 실제로 물리적 모니터에 그릴 것 같습니다. 그러니까 아마도 모니터에 붙은 디바이스 드라이버나 커널 코드는 이 framebuffer에 해당하는 무엇을 알고 있어야 할 것 같구요.

그렇다면 중간에 어느 단계에서 framebuffer 정보가 생성될 텐데, 이걸 framebuffer level이라고 부르는 건가요? 그러면 이건 어딘가요? X server가 그 밑에 어딘가로 정보를 보낼 때, framebuffer를 만드나요? 혹은 X server조차도 framebuffer를 모른 채로 추상 수준이 더 높은 정보를 내려 보내는지요?

익명 사용자의 이미지

> firefox, gedit 같은 응용 프로그램이 화면에 뭔가를 그리려면 아마 1920 * 1600 해상도의 픽셀 버퍼에다 일일이 셋팅을 주는 대신, X server나 그 위의 뭔가에 대고 "(100, 400)부터 300 x 500짜리 사각형을 그려라"라는 요청을 날리는 것으로 알고 있습니다. 그러니까 대부분의 경우에 X application들은 프레임버퍼의 존재를 모르지 않을까 짐작하는데 맞나요?

맞습니다.

> 그런데 마지막까지 내려가면, 모니터 모듈은 아마도 자기랑 하드웨어상으로 연결된, 이를테면, 가상 메모리/물리 메모리 내의 특정 영역에서 각 픽셀을 어떻게 그려야 하는지가 일일이 정의된 정보를 1초에 N번씩 스캔해서 실제로 물리적 모니터에 그릴 것 같습니다. 그러니까 아마도 모니터에 붙은 디바이스 드라이버나 커널 코드는 이 framebuffer에 해당하는 무엇을 알고 있어야 할 것 같구요.

맞습니다.

> 그렇다면 중간에 어느 단계에서 framebuffer 정보가 생성될 텐데, 이걸 framebuffer level이라고 부르는 건가요? 그러면 이건 어딘가요? X server가 그 밑에 어딘가로 정보를 보낼 때, framebuffer를 만드나요? 혹은 X server조차도 framebuffer를 모른 채로 추상 수준이 더 높은 정보를 내려 보내는지요?

프레임버퍼는 그래픽 카드에 내장된 하드웨어입니다.
그걸 다루기 위해 그래픽 드라이버/펌웨어가 존재하는 거고,
그래픽 드리이버/펌웨어에서 제공하는 로우레벨 함수를 api 로 접근하는거죠.
https://en.wikipedia.org/wiki/Graphics_library
여러 그래픽 라이브러리가 있는데 종류가 많고 계층화가 되어 있는 것 같은데 그것까지는 모르겠네요.
소프트웨어에서 말하는 프레임버퍼는 buf[SIZE] 이런 식의 버퍼고 그 데이터를 그래픽 라이브러리를 통하여 드라이버에서 제공하는 로우레벨 api 통하여 하드웨어로 전송될 겁니다.

xorg 서버를 보면 프레임버퍼라는 드라이버가 별도로 존재하고, 그외 다른 그래픽 드라이버도 존재하는데, 그 둘이 동시에 로딩되어 사용되는지는 모르겠네요. 전에 하두 궁금해서 xorg 소스코드를 까봤는데, 지금 기억이 잘 안나는데,
XCreateWindow() 이런 함수들이 있는데, 그 구현에는 xlib 보다 더 낮은 수준의 api 로 구현되어 있던 걸로 기억합니다.
제가 잘못 기억하고 있다면 다른 분께서 알려주시기 바래요.

만약, 어떤 사람이, 신규 그래픽 툴킷을 만들고 싶다면, 로우레벨에서 어떻게 돌아가는지를 알아야 합니다.
하두 궁금해서 gtk 툴킷 소스코드를 까봤는데,
gtk_window_new() 의 소스코드가 x11(xorg) 용 코드랑, wayland 코드랑 다릅니다.
x11 환경에서는 x11(xorg) 백엔드가 사용되어 내부적으로 XCreateWindow() 이런 함수가 작동되며,
wayland 환경에서는 xdg_어쩌구저쩌구... 하는 wayland 프로토콜로 만들어진 함수가 사용되는데,
그 함수는 더 저수준인 그래픽 드라이버에서 제공하는 api 이용하여 구현되어 있습니다.
https://ko.wikipedia.org/wiki/EGL_(API) 참고 바랍니다.
그래픽 회사에서 그래픽 드라이버와 api 구현체를 같이 제공합니다.
결국, 이러한 api 들이 그래픽 카드에 있는 프레임버퍼를 다루겠죠.
제가 잘못 알고 있는 부분이 있다면 알려 주시기 바랍니다. 저도 배우고 싶습니다.

Stephen Kyoungwon Kim@Google의 이미지

덕분에 이러저러한 페이지들에서 high level에서 리눅스의 그래픽 구현을 개관하는 그림/글들을 꽤 여럿 찾았습니다. 많은 도움이 되었습니다.

익명 사용자의 이미지

음... 고수준에서 저수준으로 이동하는 관점에 바라보았는데, 이번에는 저수준에서 고수준으로 이동하는 관점에서 바라보겠습니다.
어떤 사람/법인이 그래픽 카드를 만들었습니다. 그런데 이 하드웨어 자체 단독으로는 써먹을 수가 없습니다.
하드웨어를 작동하기키 위한 펌웨어를 만들어서 하드웨어에 내장시켰습니다. 그 펌웨어에는 각종 IO 처리를 위한 코드가 내장되어 있습니다. 그 펌웨어가 각각의 회사, 각각의 카드마다 제각기 다 다릅니다. 아... 참.. 어찌해야할까요...
100개가 넘는 회사들이 연합하여 기준을 마련합니다. https://en.wikipedia.org/wiki/Khronos_Group
3D 그래픽 다루는 api 는 이걸로, 저걸로 통일하자. 그렇게 여러개가 나오고
2D 그래픽 다루는 api 는 이걸로, 저걸로 통일하자. 그렇게 여러개가 나옵니다.
산업계에서 두루두루 사용될 수 있도록 BSD 같은 라이선스로 api 를 뿌립니다. 사람들이 많이 사용해야 그래픽 카드 많이 팔아서 돈 벌 수 있으니까 당연한 겁니다.
동시에 그래픽 카드 제조사에서는 해당 api 를 구현하여 라이브러리를 만들어서 배포합니다. (구현된 라이브러리에는 초능력을 썼는지, 외계인을 고문했는지, 그래픽 카드에 라이브러리가 어떻게 접근하는지는 제가 알 필요가 없지만, create_surface_new() 이런 함수를 실행하면 내부적으로 그래픽 드라이버에 있는 api(아마도 노출되지 않아서 api 라 부르기가 좀 거시기 함)를 작동시킬 거고 그게 전기 신호로 바뀌어 그래픽 카드에 신호를 보낼 거고, 그 전기 신호를 펌웨어에서 감지하여 하드웨어를 작동/관리/감독하겠죠.)
그래픽 카드사에서 제공해주는 로우레벨 그래픽 라이브러리로,
xlib(x11), GTK wayland backend 이런 걸 만드는거죠.

보시다시피 wayland 환경에서는 xserver 를 거치지 않고 그래픽 api 를 통하여 그래픽 카드를 다룹니다. 그래서 xserver(xorg) 거치는 것보다 원리적으로 속도가 빠르다고 하지만, 실제는....@$#$

gtk --> xlib --> xserver --> 그래픽 카드..
gtk --> wayland backend ---> 그래픽 카드..

xserver 는 client/server 방식으로 이루어져 있습니다.
우리가 X 어플을 실행시키면(xorg 환경에서 GTK 어플을 실행시키면) 그 어플이 xserver(xorg)에 통신을 접속합니다.
X 어플은 XOpenDisplay() 라는 함수를 반드시 사용합니다. 그 함수가 통신으로 xserver(xorg) 에 접속을 하는 함수입니다. xcb 라이브러리에서 동일 기능을 하는 함수는 xcb_connect () 입니다.
xserver(xorg) 가 클라이언트/서버 방식이기 때문에 외부(remote)에서 접속을 받는게 가능하고 화면 정보를 외부(remote)로 쏴주는게 가능합니다. xserver(xorg)에는 이런 기능이 있고,

클라이언트 어플(X 어플, xorg 위에서 실행시킨 GTK 어플 등)은 xserver(xorg)를 무조건 거치게 되어 있습니다. 이 부분에서 원리적으로 속도가 저하된다고 해서 나온게 wayland 방식인데... 현실에서 실제 속도가 wayland 가 xserver(xorg) 방식보다 더 빠르지는 않습니다.(오십보 백보 차이)

그러면 프레임버퍼는 어느 단계(계층) 위치할까요? 이게.. 답변이 쉽지가 않습니다.
한가지 확실한 거는 프레임버퍼는 그래픽 카드에 있습니다.
소프트웨어에서 바라볼 때, 프레임버퍼를 ... 어느 단계(계층, 레벨)에서 사용할지에 따라서... 답변이 애매하네요.

> 그렇다면 중간에 어느 단계에서 framebuffer 정보가 생성될 텐데, 이걸 framebuffer level이라고 부르는 건가요? 그러면 이건 어딘가요? X server가 그 밑에 어딘가로 정보를 보낼 때, framebuffer를 만드나요? 혹은 X server조차도 framebuffer를 모른 채로 추상 수준이 더 높은 정보를 내려 보내는지요?

xserver(xorg) 가 어딘가에 정보를 보낼 때 프레임버퍼를 알 필요가 있을까요. 정보를 어딘가에 보내면 어딘가가 정보를 받아서 그래픽 api, 그래픽 드라이버를 통하여 처리하겠죠. 통신하는 단계에서는 프레임버퍼를 알 필요가 없습니다.
html 도 일종의 화면 정보거든요. 웹 서버에서 html 을 클라이언트에 보내면 웹 브라우저에서 그려주죠.
웹 브라우저든, xserver(xorg) 서버든, 사용자 화면에 그려주는 단계에서는 프레임버퍼에 그래픽 라이브러리 api 를 통하여 접근하겠죠.

Stephen Kyoungwon Kim@Google의 이미지

우선 전체적인 답글 감사드립니다. 많은 도움이 되었습니다.

제가 막혔던 부분은 1차적으로 vnc 서버가 vnc 클라이언트한테 대체 뭐를 넘기느냐는 것이었습니다. X over ssh는 ssh 서버에게 응용 프로그램들이 X 요청을 하면, ssh 클라이언트에 그대로 넘기고, ssh 클라이언트가 클라이언트 단에서 자기가 그 X 응용 프로그램인양 그쪽 X 서버에 요청을 하는 것으로 이해합니다. 이 경우는 ssh 클라이언트 단에도 X 서버가 구현되어 있어야 하고요.

그런데 vnc는 X 유무와 무관하게 동작하니까 X 요청을 vnc 서버가 받아서 그대로 전달하진 않을 것 같습니다. 그런 맥락에서 읽다 보니 at framebuffer level에서 뭔가가 전달된다고 나오는데, 이 부분이 무슨 말인지 잘 이해가 되지 않았습니다.

두 번째로 제 목적은 단순히 vnc 동작을 이해하려는 건 아니고, 상당히 복잡한 소프트웨어 수행 환경 어디엔가 vnc가 구현되어 있는데, 도대체 그게 어디인지 아는 것입니다. 이 환경은 대충 이렇습니다.

A라는 커널 + 시스템 소프트웨어 + 기본 소프트웨어 집합이 있습니다. 그냥 설명 편의를 위해 iOS라고 하죠. 저희는 arm64 머신 위에 구현되어 서비스가 되는 클라우드 컴퓨팅 시스템이 있습니다. 그 IOS 가상 머신을 클라우드를 통해 개발자들에게 제공합니다. 클라우드 인스턴스 안에 버추얼 머신 프로그램(버츄얼 박스나 vmware 비슷한)이 있고 그 안에 iOS 이미지를 올립니다. 문제는 iOS가 하드웨어 위에 돌아갈 때 그 주위에 붙은 디바이스를 클라우드 인스턴스에는 붙일 수 없다는 건데, 그래서 그 하드웨어도 가상화 해서 만들고 그걸 이 iOS 가상머신 인스턴스에 붙입니다.

이렇게 해서 iOS를 가상화해서 버츄얼 머신의 전원을 켜고 머신을 시작하면 VNC로 해당 iOS에 연결할 수 있습니다. 저는 이 VNC 서버/클라이언트를 리팩토링 하고 개선해야 하는 셈인데... 도대체 VNC가 어떻게 동작하는지도 정확히 몰랐을 뿐더러 (그래픽 관련 일은 툴 만들면서 Java GUI 사용해 본 게 전부입니다, 네트웤은 해본 적도 없고요) 어딘가 이 서버 구현이 들어갈 수 있을 것 같은 데가 너무 많더군요. 뭔가 그 버츄얼 머신 자체에서 자기 인스턴스하고 vnc 연결을 해주는 건지, 아니면 완전히 가상화된 iOS 위에 그냥 vnc 서버 앱을 만들어 까는 건지, 그도 아니면 가상의 그래픽/evdev 장치 드라이버에 vnc 서버 코드를 집어넣은 건지도 모르겠더군요.

지금은 두 분 말씀을 종합해 보건데 그냥 iOS 위에 앱을 만들어 까는 거 같고, X 요청을 받으면 그걸 메모리에다 1920 * 1600 (예컨대) 사이즈의 버퍼를 잡고 픽셀을 설정한 다음, 그걸 그냥 vnc 클라이언트로 보내면, vnc 클라이언트는 그걸로 화면을 꽉 채우는 거대한 이미지를 만들어 클라이언트 쪽 X 서버에다 이미지로 그리도록 요구하는 것으로 상상이 되네요.

익명 사용자의 이미지

VN C의 경우 RFB 라는 프로토콜을 사용한다고 합니다.
https://en.wikipedia.org/wiki/RFB_protocol
https://en.wikipedia.org/wiki/Virtual_Network_Computing

Stephen Kyoungwon Kim@Google의 이미지

사실 질문 전에 그 두 페이지를 이미 보았었습니다. 아래와 같은 부분이 있는데, 거기서도 프레임버퍼 레벨이란 말을 사용하고 저는 그래픽이고 네트웤이고 하나도 모르는 입장이라서 질문을 드리게 되었었습니다.
"Because it works at the framebuffer level it is applicable to all windowing systems and applications, including Microsoft Windows, macOS and the X Window System. RFB is the protocol used in Virtual Network Computing (VNC) and its derivatives."

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.