diff options
| author | eunhhu <[email protected]> | 2026-09-27 13:02:41 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-27 13:02:41 +0100 |
| commit | ba76d3810713bb67569114e9458416df0f78687a (patch) | |
| tree | 357c5285b72626ff7f77d0339ccc0e6d2cc66b7d /docs/design | |
| parent | 2acf27f665f8a926d244efa58f6ef2c92d65e8c4 (diff) | |
| download | vega-ba76d3810713bb67569114e9458416df0f78687a.tar.gz vega-ba76d3810713bb67569114e9458416df0f78687a.zip | |
Draw symbols on the GPU from the point table as it is
OpenGL ES 3.1: the file's points go up as one storage buffer, each symbol
gets 16 row bands listing the curves they reach (cut by integer division of
doubled coordinates, so CPU and shader agree), and every pixel of a symbol's
box sums the exact area of its bands' curves, as vega_coverage does.
vega-symbols gpu draws every symbol against the CPU reference and times
1080p pages.
On the Pi 5's V3D it matches the reference (mean 0.001-0.1 levels, worst
4) but takes 142-757 ms a page, 83% of it in the area function. A sorting
network in registers made it 2.3x faster yet computes wrong rows in the
fragment stage with this driver, while the same code is exact in a compute
shader; so drawing each glyph size once into an atlas by compute comes next.
Diffstat (limited to 'docs/design')
| -rw-r--r-- | docs/design/002-symbol-format.md | 27 |
1 files changed, 26 insertions, 1 deletions
diff --git a/docs/design/002-symbol-format.md b/docs/design/002-symbol-format.md index 362798b..d25d996 100644 --- a/docs/design/002-symbol-format.md +++ b/docs/design/002-symbol-format.md @@ -92,11 +92,36 @@ em² 대비 평균 2.6e-5, 최악 1.5e-4 차이다. SVG는 Adwaita 기호 아이 처음 계획은 12바이트 곡선 레코드(1판)였다. 윤곽에 닿는 비용은 더 쌌지만(119 ns) 폰트의 2.1–6.6배 크기였고, 여는 비용이 곡선 수에 비례했다. "초경량"이라는 목표에 맞지 않아서 점 사슬로 바꿨다. +## GPU (Raspberry Pi 5 V3D 7.1, OpenGL ES 3.1, Mesa 26.2.2) + +`src/symbols-gl.c`는 파일의 점 표를 그대로 저장 버퍼 하나로 올리고, 심볼의 상자를 덮는 사각형(인스턴스 하나)의 픽셀마다 +`vega_coverage`와 같은 계산을 한다. 올릴 때 심볼마다 가로 띠 16개를 만들어 띠마다 걸치는 곡선(을 시작하는 점의 번호)을 적는다. +픽셀은 제 행이 걸친 띠의 곡선만 읽고, 여러 띠에 걸친 곡선은 첫 띠에서만 센다. 띠 소속은 두 배 좌표의 정수 나눗셈이라 CPU와 +셰이더가 같게 가른다. 넓이는 행을 벗어난 곡선을 거르지 않고 왼쪽 곡선도 dy로 세야 하므로 띠는 가로로만 자른다. + +`vega-symbols gpu`로 잰 것(표면 없는 EGL 문맥, 8비트 빨강 대상): + +| | 12px | 16px | 32px | 64px | +|---|---|---|---|---| +| CPU 참조와 평균 차이 / 최악 | 0.095 / 3 | 0.096 / 4 | 0.001 / 1 | 0.001 / 1 | +| 1920×1080 한 쪽(글리프 수) | 19,779 | 11,029 | 2,698 | 647 | +| 한 쪽 그리기 | 757 ms | 525 ms | 249 ms | 142 ms | + +맞게 그리지만 매 프레임 직접 그리기에는 수십 배 느리다. 넓이 함수를 사소한 식으로 바꾸면 16px 쪽이 91 ms라서 시간의 83%가 +넓이 계산이다. 셰이더의 교차점 배열(`float ts[10]`, 동적 첨자와 삽입 정렬)을 레지스터 안의 정렬망(vec4 min/max)으로 바꾸면 +2.3배 빨라지지만(229 ms), 이 드라이버에서 프래그먼트 셰이더로 컴파일하면 몇몇 행 전체가 틀린 값을 낸다(최악 255). 같은 함수를 +계산 셰이더에서 돌리면 무작위 곡선 백만 개에서 CPU와 5.7e-6 안에서 같고, 프래그먼트의 `main` 전체를 계산 셰이더로 옮겨도 틀린 +픽셀이 없다. 그래서 프래그먼트 쪽은 정렬망 없이 두었다. + +다음: 크기마다 글리프를 한 번 계산 셰이더로 아틀라스에 그리고(여기서는 정렬망이 맞다), 글은 아틀라스를 읽는 사각형으로 그린다. +UI의 글은 크기가 몇 가지뿐이므로 거의 모든 프레임이 텍스처 읽기다. 크기가 계속 바뀌는 경우(확대 애니메이션)만 직접 그리기를 쓴다. + ## 도구 `vega-symbols build [--font 폰트 --codes 0x20-0x7e,…] [--svg 번호=아이콘.svg …] [--units N] -o 심볼.vsym`: FreeType으로 글리프 윤곽을 단위 그대로(`FT_LOAD_NO_SCALE`) 읽고(단위는 글꼴 단위의 두 배에서 시작해 줄인다. 아이콘만이면 4,096), SVG는 `path`의 `d`를 읽어 viewBox(없으면 width·height)의 높이를 em으로 맞춘다. 호(`A`)는 4분의 1 바퀴 이하의 3차 곡선으로, 3차 곡선은 2차 곡선으로 나눈다. 칠해진 경로만 받는다. 변환, 불투명도, evenodd, 획, 경로 밖의 도형을 쓰는 아이콘은 이름을 대고 거부한다(빠뜨리고 그리면 틀린 그림이 된다). 해석은 여기서 한 번이다. -`compare`(FreeType과 픽셀 차이, 여는 시간, 윤곽 하나에 닿는 시간), `info`(심볼마다 점·곡선 수, 경계, 넓이), `render`(PGM)는 +`compare`(FreeType과 픽셀 차이, 여는 시간, 윤곽 하나에 닿는 시간), `info`(심볼마다 점·곡선 수, 경계, 넓이), `render`(PGM), +`gpu`(GPU와 CPU 참조의 차이, 한 쪽 그리는 시간)는 검증과 측정용이다. `tests/check.py`의 10번이 이것들로 형식을 지킨다. |
