사전 vblank
개념

vblank

gabury1고친 사람 github-actions[bot]

vblank 은 모니터가 화면 한 장을 다 칠하고 다음 장을 칠하기 전에 잠깐 쉬는 시간입니다. 이 시간에는 화면의 어느 줄도 새로 칠해지지 않습니다. 그래서 다음 그림은 이때 바꿔 끼웁니다. 그러면 그림이 바뀌는 도중이 보는 사람 눈에 드러나지 않습니다. 그래픽 드라이버와 게임 같은 프로그램은 화면을 바꾸는 일을 이 틈에 맞춰 합니다.

쉽고 빠른 이해

vblank 은 모니터가 화면을 한 번 다 칠한 뒤 맨 위로 돌아가는 동안의 짧은 쉼입니다. 1초에 화면을 60번 새로 칠하는 모니터라면 이 쉼도 1초에 60번 찾아옵니다.

이 쉼이 없으면 그림을 바꿀 안전한 때가 없습니다. 모니터가 화면 중간을 칠하는 도중에 그림이 바뀌면 위쪽은 앞 장면, 아래쪽은 새 장면이 섞여 보입니다.

어떻게 쓰는가:

  1. 모니터로 그림을 보내는 장치가 쉼이 시작됐다고 컴퓨터에 알립니다
  2. 드라이버가 미리 그려 둔 다음 그림으로 화면을 바꿔 끼웁니다
  3. 쉼이 끝나면 모니터는 맨 윗줄부터 새 그림을 칠합니다

대가는 박자에 묶인다는 것입니다. 쉼이 짧아서 그 안에 할 수 있는 일은 바꿔 끼우기 정도입니다. 그림이 조금만 늦게 준비돼도 다음 쉼까지 한 박자를 기다립니다.

화면을 칠하지 않는 서버 코드는 vblank 과 만날 일이 거의 없습니다.

상세

줄넘기를 두 사람이 돌리고 있습니다. 가운데로 뛰어들려는 사람은 줄이 발밑을 지나 머리 위로 올라간 틈을 노립니다. 아무 때나 뛰어들면 줄에 걸립니다.

vblank 은 화면에서 그 틈에 해당하는 시간입니다. 뛰어드는 사람은 화면 그림을 바꾸려는 프로그램입니다. 돌아가는 줄은 화면을 칠하는 순서입니다.

영어 이름은 vertical blanking interval 입니다. 우리말로는 수직 귀선 구간이라고 부릅니다. VBI(Vertical Blanking Interval)로 줄여 적기도 합니다.

이 절은 모니터가 화면을 칠하는 순서에서 출발합니다. 그 순서 안에서 이 틈이 어떻게 생기는지, 이 틈에 무엇을 하는지, 프로그램이 이 틈을 어떻게 알아채는지를 차례로 봅니다.

모니터가 화면을 칠하는 순서

모니터는 화면 전체를 한꺼번에 바꾸지 않습니다. 맨 윗줄부터 한 줄씩 아래로 내려가며 칠합니다. 한 줄 안에서는 왼쪽에서 오른쪽으로 갑니다.

모니터가 1초에 화면 전체를 몇 번 새로 칠하는지를 주사율이라고 합니다. 단위는 Hz(hertz, 헤르츠)입니다. 60 Hz 모니터는 화면 한 장을 칠하는 데 60분의 1초를 씁니다.

칠할 색은 프레임버퍼에서 옵니다. 프레임버퍼는 화면의 픽셀마다 색 값을 하나씩 담아 둔 메모리입니다. 프로그램이 그린 그림은 이 메모리에 놓여야 화면에 나옵니다.

프레임버퍼를 한 줄씩 읽어 모니터로 보내는 장치가 디스플레이 컨트롤러입니다. 대개 GPU(Graphics Processing Unit, 그래픽 처리 장치) 안에 들어 있습니다.

디스플레이 컨트롤러가 프레임버퍼를 읽어 모니터로 보내는 일을 스캔아웃이라고 부릅니다. 모니터는 스캔아웃으로 들어온 순서대로 칠합니다.

줄 끝의 쉼과 화면 끝의 쉼

스캔아웃은 끊김 없이 이어지지 않습니다. 한 줄을 다 보내면 다음 줄로 넘어가기 전에 짧게 쉽니다. 이 쉼을 hblank(horizontal blanking, 수평 귀선 구간)라고 합니다.

마지막 줄까지 다 보내면 맨 윗줄로 돌아가기 전에 더 길게 쉽니다. 이 쉼이 vblank 입니다. 줄 여러 개를 보낼 만큼의 시간이 아무것도 칠하지 않고 지나갑니다.

아래 그림은 한 장을 칠하는 동안 스캔아웃이 오가는 상태입니다.

stateDiagram-v2
    state "한 줄을 칠한다" as draw
    state "hblank · 줄 끝의 쉼" as hb
    state "vblank · 화면 끝의 쉼" as vb
    [*] --> draw
    draw --> hb: 한 줄을 다 보냄
    hb --> draw: 아직 줄이 남음
    hb --> vb: 마지막 줄이었음
    vb --> draw: 맨 윗줄로 돌아감

그림에서 hblank 은 한 장에 줄 수만큼 찾아옵니다. vblank 은 한 장에 한 번 찾아옵니다. 화면 한 장을 남김없이 바꿀 수 있는 틈은 vblank 뿐입니다. hblank 에 그림을 바꾸면 바로 다음 줄부터 새 그림이 나갑니다. 그러면 한 화면 안에서 위아래가 갈립니다.

이름에 남은 브라운관

「귀선」과 「blanking」이라는 이름은 CRT(Cathode Ray Tube, 음극선관) 모니터에서 왔습니다. 흔히 브라운관이라고 부르던 모니터입니다. CRT 는 전자빔으로 화면 안쪽의 형광 물질을 때려 빛을 냅니다. 빔이 윗줄부터 한 줄씩 훑어 내려가며 화면을 칠합니다.

마지막 줄을 칠한 빔은 화면 오른쪽 아래에서 왼쪽 위로 되돌아가야 합니다. 「귀선」은 이렇게 빔이 되돌아가는 일을 가리킵니다. 되돌아가는 데는 시간이 걸립니다. 그동안 빔을 켜 두면 화면에 대각선이 그어집니다.

그래서 되돌아가는 동안 빔을 끕니다. 화면을 비운다는 뜻의 blanking 이 여기서 나왔습니다. 위로 되돌아가는 쪽은 vertical(수직)입니다. 줄 끝에서 왼쪽으로 되돌아가는 쪽은 horizontal(수평)입니다.

LCD(Liquid Crystal Display, 액정 디스플레이) 같은 요즘 모니터에는 되돌아갈 빔이 없습니다. 그래도 모니터로 가는 신호는 지금도 한 줄씩, 한 장씩 나갑니다. 장과 장 사이에는 쉼이 들어갑니다. 소프트웨어는 이 쉼을 화면을 바꾸는 박자로 씁니다.

vblank 에 하는 일

이 틈의 쓰임은 하나로 모입니다. 화면을 바꾸는 일을 보는 사람 눈에 안 띄게 끝내는 것입니다. 대표적인 일은 둘입니다.

첫째는 보여 줄 프레임버퍼를 바꿔 끼우는 일입니다. 프레임버퍼를 두 개 둡니다. 모니터가 하나를 읽는 동안 다른 하나에 다음 그림을 그립니다. 이 방식을 더블 버퍼링이라고 합니다.

모니터가 읽는 버퍼를 프런트 버퍼, 프로그램이 그리는 버퍼를 백 버퍼라고 부릅니다. 백 버퍼에 그림을 다 그리면 둘의 역할을 맞바꿉니다.

이 맞바꿈을 페이지 플립이라고 부릅니다. 페이지 플립은 메모리 내용을 복사하지 않습니다. 디스플레이 컨트롤러가 읽기 시작할 메모리 주소만 바꿉니다. 그래서 짧은 vblank 안에 넉넉히 끝납니다.

이 맞바꿈을 스캔아웃 도중에 하면 화면 위쪽은 옛 버퍼에서, 아래쪽은 새 버퍼에서 읽힙니다. 한 화면이 가로로 찢겨 보이는 이 결함을 티어링이라고 합니다. vblank 에 맞바꾸면 다음 장은 처음부터 끝까지 한 버퍼에서 읽힙니다.

둘째는 화면 설정을 바꾸는 일입니다. 해상도와 주사율을 정하는 일을 모드 설정이라고 합니다. 이런 설정도 칠하는 도중에 바뀌면 한 장이 깨져 보입니다. 그래서 드라이버는 대개 새 설정을 vblank 에 맞춰 적용합니다.

그림을 새로 그리는 일은 이 틈에 하지 않습니다. vblank 은 한 장 시간의 작은 몫이라 그리기에는 너무 짧습니다. 그림은 백 버퍼에 미리 그려 둡니다. 틈에는 바꿔 끼우기만 합니다.

프로그램이 vblank 을 알아채는 방법

프로그램은 모니터를 들여다보지 않습니다. 대신 디스플레이 컨트롤러가 vblank 이 시작될 때마다 인터럽트를 냅니다. 인터럽트는 장치가 처리할 일이 생겼다고 프로세서에 알리는 신호입니다.

그래픽 드라이버는 이 인터럽트를 받아 vblank 이벤트로 바꿔 프로그램에 전합니다. 이벤트에는 대개 몇 번째 vblank 인지 세는 번호와 그 시각이 붙습니다. 프로그램은 번호를 보고 그림이 늦어 vblank 을 놓쳤는지 알아챕니다(아래 「vblank 을 놓칠 때」). 시각을 보고 다음 그림을 언제 낼지 셈합니다.

아래 그림은 프로그램이 다음 vblank 에 페이지 플립을 해 달라고 맡기고 결과를 받는 흐름입니다.

sequenceDiagram
    participant 프로그램
    participant 드라이버
    participant 컨트롤러 as 디스플레이 컨트롤러
    프로그램->>드라이버: 다음 vblank 에 이 버퍼로 바꿔 달라
    Note over 프로그램: 입력 처리 같은 다른 일을 한다
    컨트롤러->>드라이버: 인터럽트 · vblank 시작
    드라이버->>컨트롤러: 읽을 주소를 새 버퍼로 바꾼다
    드라이버-->>프로그램: vblank 이벤트 · 바꿨다

그림에서 프로그램은 맡긴 뒤 바꿈을 지켜보지 않습니다. 바꾸는 순간을 고르는 일은 드라이버와 디스플레이 컨트롤러가 맡습니다. 프로그램은 바꿨다는 이벤트를 받은 뒤에야 옛 프런트 버퍼에 다음 그림을 그립니다.

백엔드 코드로 치면 비동기 요청과 닮았습니다. 요청을 걸어 둔 채 다른 일을 합니다. 완료 이벤트가 오면 다음 단계로 넘어갑니다. 게임이나 화면을 합치는 프로그램은 이 이벤트를 기다리는 이벤트 루프로 도는 일이 많습니다.

vblank 을 놓칠 때

그림이 vblank 전에 준비되지 않으면 그 틈은 그냥 지나갑니다. 모니터는 앞 그림을 한 번 더 칠합니다. 새 그림은 다음 vblank 까지 기다립니다.

60 Hz 모니터에서 한 번 놓치면 그 그림은 60분의 1초 늦게 나옵니다. 놓치는 일이 띄엄띄엄 생기면 화면이 바뀌는 간격이 고르지 않습니다. 그러면 움직임이 툭툭 끊겨 보입니다. 이 끊김을 스터터링이라고 합니다.

그림을 바꾸는 때를 언제나 vblank 에 맞추는 설정을 수직 동기화라고 합니다. vblank 은 시간의 한 구간입니다. 수직 동기화는 그 구간에만 바꾸겠다는 선택입니다. 수직 동기화를 끄면 티어링을 감수하는 대신 그림이 준비되는 대로 바로 나갑니다.

틈을 늘이는 가변 주사율

보통 모니터는 vblank 의 길이가 정해져 있어서 박자가 일정합니다. 가변 주사율 모니터는 다릅니다. 다음 그림이 아직 안 왔으면 vblank 을 늘여 가며 기다립니다.

그림이 도착하면 그때 vblank 을 끝내고 새 장을 칠하기 시작합니다. 모니터가 프로그램의 박자를 따라오는 셈입니다. 그래서 그림이 조금 늦어도 다음 박자까지 한 번을 다 기다릴 일이 줄어듭니다. 늘일 수 있는 길이에는 모니터마다 한도가 있습니다.

vblank 을 다루는 코드

서버 코드는 모니터를 칠하지 않으니 vblank 과 만날 일이 거의 없습니다. 이미지를 만들어 파일로 내는 일도 마찬가지입니다. vblank 을 직접 다루는 쪽은 그래픽 드라이버, 여러 창을 한 화면으로 합치는 컴포지터, 그리고 게임 엔진입니다.

웹 프런트엔드는 간접으로 닿습니다. 브라우저의 requestAnimationFrame은 화면을 다음에 새로 그리기 직전에 콜백을 부릅니다. 브라우저가 화면을 새로 그리는 박자는 모니터의 박자를 따릅니다. 그래서 이 콜백도 대개 vblank 박자로 불립니다.

관련 항목

vblank 이 끼어 있는 화면 출력 장치와 신호

모니터 · 디스플레이 컨트롤러 · 스캔아웃 · 프레임버퍼 · 주사율 · 해상도 · 픽셀 · GPU · CRT · LCD

vblank 과 함께 화면 타이밍을 이루는 신호

hblank · 수직 동기 신호 · 수평 동기 신호 · 디스플레이 타이밍 · 픽셀 클록

vblank 에 맞춰 화면을 바꾸는 기법

수직 동기화 · 더블 버퍼링 · 트리플 버퍼링 · 프런트 버퍼 · 백 버퍼 · 페이지 플립 · 버퍼 스왑 · 가변 주사율 · 모드 설정

vblank 을 어기거나 놓치면 생기는 화면 결함

티어링 · 스터터링 · 입력 지연 · 프레임 드롭

vblank 을 받아 쓰는 소프트웨어 계층

그래픽 드라이버 · 다이렉트 렌더링 매니저 · 컴포지터 · 게임 엔진 · 게임 루프 · requestAnimationFrame · 그래픽스

vblank 을 프로그램에 알리는 수단

인터럽트 · 이벤트 루프 · 비동기 · 펜싱

다른 이름: vertical blanking · vertical blanking interval · VBI · V-blank · 수직 귀선 구간 · 수직 공백 구간 · 수직 블랭킹