TECH 으로 돌아가기
TECH HACKER NEWS 6분 읽기 26 READS

초고속 디코딩에 올인한 이미지 포맷 'nibnib'이 던지는 질문

초고속 디코딩에 올인한 이미지 포맷 'nibnib'이 던지는 질문
SOURCE IMAGE · HACKER NEWS

임베디드 그래픽스는 늘 극단적인 제약 속에서 작동한다. 라즈베리파이 재단의 RP2350 같은 마이크로컨트롤러에서 DVI 영상을 직접 뽑아내려면 한 픽셀을 처리하는 데 쓸 수 있는 시간이 약 6사이클에 불과하다. 이 정도면 픽셀을 가져오고, 팔레트를 참조하고, 라인 버퍼에 기록하는 것만으로 예산이 거의 소진된다. 여유가 거의 없는 이 환경을 겨냥해 나온 실험적 이미지 포맷이 바로 'nibnib'이다. Rust 생태계에서 그래픽스 작업으로 잘 알려진 개발자 라프 레빈(raphlinus)이 공개한 이 포맷은, 화질이나 압축률보다 '디코딩 속도'를 최우선 설계 목표로 삼았다는 점에서 일반적인 이미지 포맷과 궤를 달리한다.

팔레트에 '색'이 아니라 '차이'를 담는다

nibnib은 이름 그대로 4bpp(픽셀당 4비트)로 동작한다. 핵심 아이디어는 바이트 하나에서 픽셀 두 개를 동시에 복원하는 구조다. 디코더는 마지막으로 복원한 픽셀을 두 배로 복제한 뒤, 입력 스트림에서 바이트 하나를 읽어 팔레트에서 32비트 값을 찾고, 이를 복제해 둔 이전 픽셀에 더한다. 그 결과 RGB 565 형식의 16비트 픽셀 두 개가 한 번에 나온다. 하위 16비트가 왼쪽 픽셀이다. 연산은 이것이 전부이며, 결정론적이고 분기가 거의 없어 좁은 사이클 예산 안에 들어간다.

여기서 눈여겨볼 대목은 팔레트가 절대 색상이 아니라 '델타', 즉 이전 픽셀과의 차이를 저장한다는 점이다. 전통적인 팔레트 이미지는 제한된 색 집합을 직접 인덱싱하기 때문에 부드러운 그라데이션 영역에서 밴딩이 두드러진다. 반면 델타 방식은 완만하게 변하는 영역을 작은 차이값의 누적으로 표현할 수 있어, 같은 비트 예산으로도 소프트한 영역의 품질이 크게 올라간다. 두 픽셀 사이의 델타 크기는 선명함과 노이즈 사이의 트레이드오프를 결정하는데, 이를 작게 유지하면 전체 이미지는 매끄러워지지만 날카로운 경계를 표현하는 능력은 떨어진다.

인코딩과 디코딩의 비대칭

nibnib은 많은 압축 포맷이 그렇듯 '디코딩 과정'으로 정의된다. 즉 인코딩이란 결국 '이 디코더에 넣었을 때 원본과 최대한 비슷하게 복원되는 바이트열'을 탐색하는 문제다. JPEG처럼 DCT 변환이 수학적으로 가역인 경우 인코딩과 디코딩 속도가 대체로 비슷하지만, nibnib의 탐색은 철저히 비대칭적이어서 현재 인코더는 디코더보다 수십~수백 배 느리다. 대신 모든 최적화 부담을 인코더 쪽에 몰아넣어 디코더를 극단적으로 가볍게 유지하는 설계 선택이다.

인코더는 두 축에서 탐색한다. 하나는 팔레트 구성이고, 다른 하나는 코드워드 선택이다. 초기 버전의 팔레트는 0 근처와 최대값을 오버플로 위험 없이 표현하기 위한 작은 델타값의 '큐브'와, 가중 가우시안으로 뽑은 난수 블록으로 구성된다. 큐브 항목이 없으면 심각한 아티팩트가 생긴다고 한다. 코드워드 선택은 Floyd-Steinberg 오차 확산과 유사한데, 다만 보통의 디더링이 한 번에 한 픽셀을 다루는 것과 달리 nibnib은 두 픽셀을 함께 생성한다. 이때 두 픽셀의 차이보다 합에 더 큰 가중치를 둬, 사람의 시각이 저주파 성분에 더 민감하다는 특성을 반영한다.

아직은 실험, 그러나 방향은 분명하다

개발자 스스로 밝히듯 현재 공개된 것은 '동작하는 기본형'에 가깝다. 팔레트가 입력 이미지에 맞춰 적응적으로 선택되지 않는 점, 그리고 탐욕적(greedy) 탐색 탓에 선명한 경계 오른쪽으로 아티팩트가 끌리는 현상 등이 한계로 지적된다. 흥미로운 점은 개선 방향이 대부분 인코더 쪽에 있다는 것이다. 덧셈 단계가 사실상 가역이기 때문에, 디코딩은 좌→우로 유지한 채 인코딩만 우→좌로, 혹은 행마다 방향을 바꾸는 방식으로 돌려 아티팩트를 완화할 수 있다. 적응형 팔레트나 더 깊은 오차 최소화 탐색도 같은 맥락이다. 이런 개선은 모두 인코더를 느리게 하지만 디코더는 그대로여서, 기존 디코더를 탑재한 기기와 호환을 유지할 수 있다.

포맷 자체는 의도적으로 단순하다. 폭과 높이에 각각 2바이트, 이어서 256개의 32비트 팔레트 항목, 그리고 행 데이터가 순서대로 온다. 각 행은 RGB 565 픽셀 두 개로 시작해 (폭-2)/2개의 팔레트 인덱스 바이트가 뒤따르며, 행 스트라이드는 4바이트 배수로 올림한다. 메타데이터는 없고 아카이브 용도도 아니다. 실무자 입장에서 nibnib이 흥미로운 이유는 특정 코덱의 완성도보다, '디코더 예산이 극도로 빠듯한 하드웨어에서는 복잡도를 인코더로 몰아넣고 디코딩을 결정론적 덧셈 한 줄로 만드는 설계가 유효하다'는 점을 구체적으로 보여주기 때문이다. DVI 직접 출력, 저가 MCU 기반 디스플레이, 혹은 팔레트 기반 그래픽을 다루는 프로젝트라면 참고할 가치가 있는 사고방식이다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://github.com/raphlinus/nibnib
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...