← Back · anthropic-design diagram gallery← 返回 · anthropic-design 图示案例库 hardware · the display data path硬件 · 显示通路

One picture.
Ten pieces of hardware.
Zero copies.
一张图片。
十个硬件。
零次拷贝。

What happens between an application drawing a picture and that picture being lit up on a phone screen: which block issues each read, which bus it travels on, what the panel does with it when it arrives — and what every word in that sentence means. Ten figures, one ARM64 phone-class SoC.一个应用画出一张图,到这张图在手机屏幕上亮起来,中间到底发生了什么:哪个模块发出了每一次读、走的是哪根总线、到了屏那边又是怎么点亮的——以及这句话里每个词是什么意思。十张图,一颗 ARM64 手机芯片。

9.89 MiBone frame at 1080×24001080×2400 的一帧
16 KiBthe GPU's on-chip tile bufferGPU 片上的 tile 缓冲
4 bytesthe cost of putting a finished frame on screen把画好的一帧放到屏上的代价
what is checked and what is representative哪些是查过的,哪些是示意

The structure is checked. Which block issues the read, which driver owns the DMA, what the vendor says is inside its own display controller — all of it read out of mainline Linux, tree v7.0-9887-ga43fac2b5813, and every claim of that kind on this page carries a file and a line number. The numbers are a representative configuration chosen so the proportions are honest: bus widths, clock rates and capacities are not copied from any vendor datasheet, and none of them describe a specific product. The argument only depends on the ratio — a frame is megabytes and on-chip memory is kilobytes — and that gap is three orders of magnitude on every chip of this class.结构是查过的。哪个模块发读请求、DMA 归哪个驱动管、厂商自己说它的显示控制器里面有什么——都是从主线 Linux 源码里读出来的,树是 v7.0-9887-ga43fac2b5813,本页每一条这类论断都给了文件名和行号。数字是一种代表性配置,为的是让量级对得上:总线位宽、频率、容量都不是从哪家厂商的手册上抄的,也没有一个是在描述某颗具体芯片。论点只依赖那个比例——一帧是兆字节,片上存储是千字节——这个差距在任何这一类芯片上都是三个数量级。

first · the vocabulary第一步 · 先把词说清

Sixteen words, defined before they are used十六个词,用之前先定义

Every one of these is standard vocabulary in display and graphics work, and every one of them is used later on this page. Two questions each: what it is, and what breaks without it. The mechanism — registers, bit layouts, ordering — is left to the section that owns the concept, because a definition that opens with a register map teaches copying rather than judgement.下面每一个都是显示和图形领域的标准术语,也都会在本页后面用到。每个词答两问:这是什么,以及没有它会怎样。机制细节——寄存器、位布局、生效顺序——留给拥有这个概念的那一节讲,因为一上来就摆寄存器表,读者学到的是照抄而不是判断。

frameframe

One complete copy of everything on screen. On a 1080×2400 panel with four bytes per pixel that is 9.89 MiB of contiguous memory, and there are 60 of them every second.屏幕上所有内容的一份完整拷贝。1080×2400 的屏,每个像素 4 字节,一帧就是 9.89 MiB 一整块连着的内存;一秒钟要有 60 份。

Without it: Without the word you cannot say how big anything is, and the whole argument on this page is an argument about size.没有它会怎样:这是本页所有数字的单位。后面每一句「放不下」「太贵了」都是拿它当尺子量出来的。

framebuffer帧缓冲帧缓冲framebuffer

The range of memory addresses that a frame lives in. It is an address, not a package — nobody ever hands it to anybody.一帧所在的那段内存地址。它是一个地址,不是一个包裹——从头到尾没有谁把它「交」给谁。

Without it: Treat it as a package and every later sentence goes wrong: you start saying the GPU uploads it to the display, which never happens on a phone.没有它会怎样:把它当包裹,后面每句话都会错。「GPU 把帧交给显示控制器」这种说法就是这么来的,而手机上没有这一步。

scanout扫描输出扫描输出scanout

The display controller reading the framebuffer out one line at a time, paced by the panel's pixel clock. It runs 60 times a second and never stops while the screen is on.显示控制器按屏幕的像素时钟,一行一行把帧缓冲读出来。一秒钟 60 遍,屏幕亮着它就没停过。

Without it: Miss one beat and the panel is short one line of pixels. This is the one job on the chip that cannot be rescheduled.没有它会怎样:慢一拍,屏幕就少一行像素。这是整颗芯片上唯一一件不能改期的事。

front buffer前缓冲前缓冲front buffer

Whichever block of memory scanout is reading right now. It is a role, not an address — the same memory is the front buffer this frame and the back buffer the next.此刻正在被扫描输出读的那一块。这是一个角色,不是一个地址——同一块内存,这一帧叫前缓冲,下一帧就叫后缓冲。

back buffer后缓冲后缓冲back buffer

Whichever block the GPU is drawing into right now. At the next vsync the two roles change places.此刻正在被 GPU 画的那一块。下一次 vsync 一到,两个角色就对调。

Without it: With only one block, scanout would be reading the same bytes the GPU is rewriting, and you would see half of the old frame above half of the new one.没有它会怎样:只有一块的话,扫描输出读的正是 GPU 正在改的那些字节,屏幕上会是上半张旧的、下半张新的。

page flip翻页翻页page flip

Writing a different address into the display controller's framebuffer base register. Four bytes. Nothing is copied and neither buffer moves.往显示控制器的帧缓冲基址寄存器里写另一个地址。四个字节。没有任何东西被拷贝,两块缓冲一动不动。

Without it: This is where almost everyone assumes a copy happens. It does not, and that assumption is what makes the rest of the pipeline impossible to reason about.没有它会怎样:几乎所有人都以为这一步发生了拷贝。没有。而这个误解一旦成立,后面整条通路就没法讲清楚了。

tearing撕裂撕裂tearing

What you see when the base address changes while scanout is midway down the screen: the top of one frame sitting above the bottom of another.扫描输出扫到屏幕一半时基址被改掉,屏上就是上半张属于一帧、下半张属于另一帧。

vertical syncvsyncvsyncvertical sync

The gap between finishing one frame and starting the next. Register writes are held and take effect at this instant, not when software issued them.一帧扫完到下一帧开始之间的那段空隙。寄存器的新值被压着,到这一刻才生效,而不是软件写下去的那一刻。

Without it: Without the hold, every flip would land mid-screen and tear.没有它会怎样:没有这个「压着等」,每次翻页都会落在屏幕中间,每次都撕裂。

WHERE EACH WORD LIVES the words in the table above are not all the same kind of word. most of them name a place. four of them name a moment, and mixing the two is what makes this hard to follow. GPU draws it DRAM holds it display controller reads it out MIPI DSI + D-PHY ships it panel lights it tile-based rendering bus master frame framebuffer front buffer back buffer scanout line buffer fetch DMA blending APB · registers AXI · pixels TE signal each of these names a piece of hardware, or a range of addresses inside one. you can point at it. vsync the gap between two frames page flip one register write, at that gap tearing what you see if it lands late underflow what you see if the fetch is late these four are not in any box above. they are things that happen at an instant — which is why looking for them on a block diagram never works.
the map for the table这张表的地图 Half the table is above, half below, and this is where each of those words actually sits. The four along the bottom are the ones worth separating out: vsync, page flip, tearing and underflow are not in any box, because they are moments rather than places. Looking for a moment on a block diagram is a good way to stay confused for a long time.表格上半在这张图前面,下半在后面,而每个词到底落在通路的哪一段,看这张图。最值得单拎出来的是底下那四个:vsync、翻页、撕裂、欠载 不在任何一个盒子里,因为它们是时刻不是地方。在框图上找一个时刻,是能把自己困住很久的一种找法。
line buffer行缓冲行缓冲line buffer

A small on-chip SRAM inside the display controller that holds a handful of lines — sixteen on the hardware cited here, not one frame.显示控制器片上的一小块 SRAM,只存十几行——本页引的这颗是 16 行,不是一帧。

Without it: Without it, a single DRAM read latency would starve the pixel clock and put a visible band across the screen.没有它会怎样:没有它,DDR 一次读延迟就够让像素断流,屏幕上当场出现一道横条。

fetch DMA取数 DMA取数 DMAfetch DMA

The display controller's own read engine. It issues addresses and receives data by itself, with no CPU involvement after setup.显示控制器自己的读引擎。配好之后它自己发地址、自己收数据,CPU 再不参与。

Without it: Without it the CPU would have to move roughly 500 MB every second and do nothing else.没有它会怎样:没有它,CPU 每秒得搬大约 500 MB,然后就干不了别的了。

bus master主设备主设备bus master

Any block that can start a read or a write on the bus by itself. The GPU, the display controller, the camera pipeline and the video codec are all masters; memory is not.任何能自己在总线上发起读写的模块。GPU、显示控制器、摄像头通路、视频编解码都是主设备;内存不是。

Without it: Adding a GPU adds a master, not a destination. That one sentence is the whole shape of this page.没有它会怎样:加一个 GPU,加的是一个主设备,不是一个目的地。这一句话就是整页的形状。

two busesAPB / AXIAPB / AXItwo buses

Two different buses. APB is narrow and slow and carries register writes; AXI is wide and fast and carries pixels. They are physically separate wires.两根不同的总线。APB 又窄又慢,走寄存器;AXI 又宽又快,走像素。它们是物理上分开的两组线。

Without it: On one shared bus a single register write could cut into a pixel burst; scanout has no slack to absorb that.没有它会怎样:合成一根的话,一次寄存器写就可能插进像素突发中间;而扫描输出没有余量能吸收这一下。

tile-based rendering分块渲染分块渲染tile-based rendering

The GPU cuts the screen into 16×16 tiles and finishes one tile entirely inside on-chip memory before writing it out once.GPU 把屏幕切成 16×16 的小格,一格从头到尾在片上算完,算完才往内存写一次。

Without it: Without it every layer of overdraw would be a read and a write of external memory, and on a phone that memory is shared with five other blocks.没有它会怎样:没有它,每一层重叠都要读一次写一次外部内存;而手机上那块内存是跟另外五个模块共用的。

blending / overlay混合混合blending / overlay

Stacking several layers into one image by alpha. On a phone this is a piece of hardware inside the display controller, passed through on the way to the panel.把好几个图层按透明度叠成一张。手机上这是显示控制器里的一块硬件,像素路过时顺手就叠好了。

Without it: If the GPU did it instead, composing would cost one extra full-frame write plus one extra full-frame read — about 1.2 GB/s of pure traffic.没有它会怎样:改由 GPU 来做的话,合成要多写一整帧、多读一整帧——大约每秒 1.2 GB 的纯搬运。

tearing effect signalTETEtearing effect signal

A wire running backwards from the panel's driver chip to the SoC, saying “I have just finished a refresh”.从屏幕的驱动 IC 反向接回芯片的一根线,意思是「我刚扫完一遍」。

Without it: Without it a command-mode panel has no way to know when writing to it is safe.没有它会怎样:没有它,命令模式的屏就无从知道什么时候写才不会撕裂。

underflow欠载欠载underflow

The line buffer running empty while the pixel clock keeps going. The panel receives whatever was on the wires.行缓冲空了,而像素时钟不会等。屏幕收到的就是那一瞬间线上碰巧是什么。

Without it: This is what a bandwidth problem actually looks like from the outside: a band across the screen, not a slow app.没有它会怎样:带宽出问题时,从外面看到的就是这个:屏幕上一道横条,而不是「应用变慢了」。

Figure 01 · the whole journey图 01 · 全程

Ten pieces of hardware, and the frame never enters any of them十个硬件,而这一帧一个都没进去过

Read the two rows against the bar in the middle. Everything above writes into that memory, everything below reads out of it, and no arrow ever goes from one block straight to another. That is the shape of the answer: on a phone, blocks do not hand frames to each other. They take turns touching the same addresses.把上下两行对着中间那条内存看。上面的往里写,下面的往外读,没有一根箭头是从一个模块直接连到另一个模块的。这就是答案的形状:手机上模块之间不传帧,它们只是轮流去碰同一批地址。

ONE FRAME · TEN STOPS ON A PHONE SOC pixels being written pixels being read ①–⑤ · THE WRITE SIDE · the GPU renders one frame into memory shader cores they compute pixels tile buffer 16 KiB on-chip GPU MMU virtual → physical interconnect NoC · arbitration memory ctrl queues + refresh 1 2 3 4 5 GPU · one IP, three parts on-chip AXI 128-bit AXI 128-bit DFI CPU cluster runs the compositor APB 32-bit 4 bytes per frame, to the register at stop ⑧. this is the only thing software does. no pixel travels here. 8.3 MB per frame off-chip · DRAM front buffer the display reads this back buffer the GPU writes this textures source art page tables the GPU's other 6 LPDDR4X · the only place in the system where a whole frame exists back on-chip ⑦–⑩ · THE READ SIDE · the display controller pulls it out again, and never stops fetch DMA reads in scanline order blend + timing composes, makes vsync MIPI DSI packetises D-PHY 4 lanes, serial 7 8 9 display controller · VOP / DPU serial link out of the chip 16 lines only 24-bit RGB packets 10 panel the frame never entered the GPU and never entered the display controller. both of them reached into the same DRAM. every box above is a real block with a driver in mainline Linux. the two that hold no frame are the ones people assume do: the GPU, whose tile buffer is 16 KiB, and the display controller, whose line buffer is 16 lines deep (rockchip_drm_vop2.c:500). One frame · ten stops
phone SoC · every block and every bus手机芯片 · 每个模块,每根总线 Every box is a real block with a driver in mainline Linux, and every link is labelled with its bus type and how many bytes it carries per frame. Note which two boxes hold no frame: the GPU, whose tile buffer is 16 KiB, and the display controller, whose line buffer is sixteen lines. Those are exactly the two everybody assumes are holding one. Stop ⑥ is the memory bar, and it is the only stop in the path that holds a whole frame — ①–⑤ above it all write into it, ⑦–⑩ below it all read out of it. The CPU is off to one side on a 32-bit configuration bus carrying four bytes a frame, and no pixel ever travels on it.每个盒子都是主线 Linux 里有驱动的真实模块,每根线都标了总线类型和每帧走多少字节。留意哪两个盒子里其实一帧都放不下:GPU 的 tile 缓冲是 16 KiB,显示控制器的行缓冲是 16 行——而这两个恰恰是大家都以为「帧在里面」的。CPU 单独挂在一根 32 位配置总线上,每帧四个字节,像素从来不走这条线。停 ⑥ 是那条内存,也是全程唯一装得下一整帧的地方;它上面的 ①—⑤ 都在往里写,下面的 ⑦—⑩ 都在往外读。
Figure 02 · what a frame is图 02 · 一帧是什么

A frame is 9.89 MiB and the largest memory on the chip is 512 KiB一帧是 9.89 MiB,而芯片上最大的一块存储是 512 KiB

This is the constraint everything else is downstream of, so it is worth making it visible rather than asserting it. The right-hand side draws one frame as a ruler and then draws every on-chip memory on that same ruler. The GPU tile buffer comes out one and a half pixels wide.后面所有的设计都是从这一条约束推出来的,所以值得把它画出来而不是说出来。右半边把一帧画成一把尺子,再把片上每一块存储按同一个比例画在下面。GPU 的 tile 缓冲量出来只有一个半像素宽。

WHAT A FRAME IS · AND WHY IT DOES NOT FIT one frame · a full screen of pixels 1080 × 2400 pixels one pixel R G B A 4 bytes nothing here is compressed 1080 × 2400 × 4 = 9.89 MiB, once and there are 60 of them every second THE SAME RULER · one frame, then every on-chip memory drawn to that scale one frame · 9.89 MiB GPU L2 cache 512 KiB — 33 px on this ruler display line buffer 16 lines · 128 KiB — 8 px on this ruler GPU tile buffer 16 KiB — 1 px on this ruler the same three, magnified 12× so they can be seen at all GPU L2 cache display line buffer GPU tile buffer no memory inside the chip is within a hundred times of holding one frame. that is the whole reason the rest of this works the way it does. the largest on-chip memory anywhere in the display path is 53 times too small. on-chip SRAM costs tens of times more silicon area per bit than DRAM, so a chip that could hold a frame would be a chip nobody could afford to buy. the line buffer figure is from rockchip_drm_vop2.c:500 — “a Cluster window has 2048 x 16 line buffer”. sixteen lines, not one frame. A frame · 9.89 MiB, nowhere to put it
the same ruler for all of them同一把尺子量到底 Why not just build a chip with enough SRAM? Because on-chip SRAM costs tens of times more silicon area per bit than DRAM does. A chip holding one frame on-die would be a chip nobody could afford, and it would still hold only one. The 16-line figure is not a simplification: rockchip_drm_vop2.c:500 says in as many words that a Cluster window has a 2048 x 16 line buffer.那为什么不干脆做一颗 SRAM 够大的芯片?因为片上 SRAM 每比特占的硅片面积是 DRAM 的几十倍。能在片内装下一帧的芯片会贵到没人买得起,而且它也只装得下一帧。16 行不是我为了讲故事简化的:rockchip_drm_vop2.c:500 原话就是「a Cluster window has 2048 x 16 line buffer」。
Figure 03 · how the GPU copes图 03 · GPU 怎么办

It never works on a frame. It works on one 16×16 tile at a time它从不处理一帧。它一次只处理一个 16×16 的小格

The previous figure proved the GPU cannot hold a frame. The obvious next question is how it draws one anyway, and the answer is that it never handles a frame at all. The screen is cut into 10 125 tiles of 16 by 16 pixels, and one tile is rasterised, depth-tested and blended to completion inside on-chip memory before a single byte is written out.上一张图证明了 GPU 装不下一帧。那接下来自然要问:它到底怎么把一帧画出来的?答案是它根本不处理一帧。 屏幕被切成 10 125 个 16×16 的小方格,一格的光栅化、深度测试、混合全部在片上做完,做完才往外写一次。

TILING · HOW A GPU DRAWS A FRAME IT CANNOT HOLD the tile buffer holds 16 KiB and a frame is 9.89 MiB. so the GPU never works on a frame. it works on one 16×16 tile at a time, and there are 10 125 of them. the screen, as the GPU sees it done now waiting 10 125 tiles · 16×16 pixels each 1 inside the chip · 16 KiB of tile buffer rasterise which pixels does this triangle touch 2 depth test is it behind something already here 3 blend mix it with what is here 4 all of it on-chip. zero memory traffic so far. once write to DRAM 4 KiB, one burst 5 and only now does this tile exist outside the chip THE ALTERNATIVE · immediate mode, which is what a desktop card does every layer of overdraw is a read-modify-write of external memory. three layers deep, that is six memory accesses per pixel instead of one write. it is the right trade when memory bandwidth is yours alone; on a phone it is shared with five other blocks. tiling is a bandwidth decision, not a compute decision. that is why it shows up on phones first and why the tile buffer is small on purpose: it has to fit in the power and area budget of something in your pocket. the depth and blend work above happens at full rate inside the chip, and DRAM never sees any of it — which is the same shape of answer as the display controller blending layers on the way past. Tiling · 16 KiB at a time
tiling · 16 KiB at a time分块 · 一次 16 KiB This is the largest structural difference between a mobile GPU and a desktop one, and the reason is bandwidth rather than compute. A desktop card renders in immediate mode, where three layers of overdraw cost six external memory accesses per pixel. That is the right trade when the memory bus is yours alone. On a phone it is shared with five other blocks, so avoiding a memory access is worth more than avoiding a multiply. Steps ②, ③ and ④ all happen on-chip; ⑤ is the only one that touches memory, and it is this tile's entire memory cost.这是手机 GPU 和桌面 GPU 之间最大的一处结构差别,而差别的原因是带宽不是算力。桌面显卡用立即模式渲染,三层重叠就是每像素六次外部访存——当内存总线是你一个人的,这个取舍是对的。手机上它是跟另外五个模块共用的,于是省一次访存比省一次乘法值钱。图里 ②③④ 三步全在片上做完,只有 ⑤ 碰了一次内存——这一格的全部访存就是那一次。
Figure 04 · inside the display controller图 04 · 显示控制器内部

Your screen is four images at once, and a piece of silicon adds them up你的屏幕上同时有四张图,把它们加起来的是一块硬件

A phone screen is never one image: a status bar, an application, a video layer and a cursor are all on screen at the same time, each in its own buffer at its own address. Something has to combine them, and the surprising part is where. Not in the GPU, and not through memory.手机屏幕从来不是一张图:状态栏、应用、视频层、光标同时在屏上,各自在自己的缓冲里、各自有自己的地址。总得有谁把它们合起来——意外的是合成发生的地方。不在 GPU 里,也不经过内存。

INSIDE THE DISPLAY CONTROLLER · WHERE COMPOSITING ACTUALLY HAPPENS a phone screen is never one image. it is four, and something has to add them up. the surprise is where that happens: not in the GPU, and not in memory. status bar 1080×90 app window 1080×2100 video decoder output cursor 96×96 other DRAM · four separate buffers, four separate addresses Cluster 0 fetch DMA + 16-line buffer 1 Cluster 1 fetch DMA + 16-line buffer 2 Esmart 0 fetch DMA + 16-line buffer 3 Esmart 1 fetch DMA + 16-line buffer 4 Smart 0 idle not needed here Smart 1 idle not needed here six hardware windows · each one reads memory by itself layer select · 1 from 6 OVERLAY · blends N of the 6 layers alpha, z-order, colour keys this is the compositor, and it is a piece of silicon 7 the alternative GPU composites into a fifth buffer instead +1.2 GB/s of pure memory traffic VIDEO PORT · timing generator makes hsync, vsync and data enable 8 MIPI DSI HDMI eDP LVDS one gets picked the blended result is never written back to memory. it goes straight out of the chip as a pixel stream. structure follows the block diagram the vendor put in the driver itself (rockchip_drm_vop2.c:41–68). the sixteen-line buffer is from line 500 of the same file. this is why a phone can show video under a translucent status bar at 60 Hz without the GPU waking up at all: the layers were never merged into one image, they were added together on the way past.
six windows, one overlay六个窗口,一个混合器 The structure here is not invented: it follows the block diagram the vendor put in the driver itself, rockchip_drm_vop2.c:41-68. Six hardware windows each pull their own layer out of memory with their own fetch DMA, a selector routes any of them to any layer slot, and one overlay block blends them on the way past. The blended result is never written back — it goes straight out of the chip as a pixel stream. That is why a phone can play video under a translucent status bar at 60 Hz without waking the GPU at all.这里的结构不是我编的,照的是厂商自己写进驱动的那张框图:rockchip_drm_vop2.c:41-68。六个硬件窗口各用自己的取数 DMA 从内存里拉自己那一层,选择器可以把任一层送到任一个槽,一个混合器在像素路过时把它们叠好。叠好的结果一个字节都没回内存,直接以像素流的形式出芯片。这就是为什么手机能在半透明状态栏底下以 60 Hz 放视频,而 GPU 全程没醒过。
Figure 05 · front and back图 05 · 前和后

“Front buffer” and “back buffer” are two jobs, not two places「前缓冲」和「后缓冲」是两个岗位,不是两个地方

These two words cause more confusion than anything else in the pipeline, because they sound like locations and they are not. They are roles that two fixed blocks of memory take turns holding. The figure draws the same two rectangles at identical coordinates in all three columns, so the only thing your eye can find changing is which one is which colour.整条通路里最容易把人绕晕的就是这两个词,因为它们听起来像地点,其实不是。它们是两块固定的内存轮流担任的两个岗位。这张图把同样两个矩形在三列里画在完全相同的坐标上,于是眼睛能找到的唯一变化,就是哪一块现在是什么颜色。

FRONT AND BACK ARE ROLES, NOT ADDRESSES display is reading it → we call it the FRONT buffer GPU is writing it → we call it the BACK buffer two blocks of DRAM. their addresses never change. what changes is which one each name is pointing at right now. block A 0x8000_0000 block B 0x8080_0000 frame N BACK buffer being drawn into FRONT buffer being read out 0x8000_0000 frame buffer base address register frame N+1 FRONT buffer being read out BACK buffer being drawn into 0x8080_0000 frame buffer base address register frame N+2 BACK buffer being drawn into FRONT buffer being read out 0x8000_0000 frame buffer base address register vsync vsync ↑ one 32-bit register write. that is the entire page flip. nothing was copied, moved or renamed. one register took a different value, and the two roles changed places. read the three columns across and the two rectangles never move: same x, same y, same address, same size. only their colour alternates. that is what makes the words confusing — “front” and “back” sound like places, and they are not. they are two jobs that two blocks of memory take turns doing. on this hardware the register is VOP2_WIN_YRGB_MST (rockchip_drm_vop2.c:1370), and it takes effect at the next vsync rather than when software writes it — let the address change mid-scan and the panel gets the top of one frame with the bottom of another, which is exactly what tearing is. Front and back · two jobs, taking turns
the roles swap, the memory does not move换的是角色,内存没动 Why two buffers rather than one? With one, scanout would be reading bytes the GPU is rewriting. Why not three? Triple buffering is real and costs another 9.89 MiB to buy the GPU freedom from waiting for a flip, at the price of one more frame of latency. The register here is VOP2_WIN_YRGB_MST (rockchip_drm_vop2.c:1370), and it is held until vsync rather than taking effect when software writes it — let the address change mid-scan and you get tearing by definition.为什么是两块不是一块?一块的话,扫描输出读的正是 GPU 正在改的字节。为什么不是三块?三缓冲是真实存在的,多花 9.89 MiB 换 GPU 不必等翻页,代价是多一帧延迟。这里的寄存器是 VOP2_WIN_YRGB_MSTrockchip_drm_vop2.c:1370),它被压到 vsync 才生效,而不是软件写下去就生效——让地址在扫描中途改掉,撕裂就是定义上的必然。
Figure 06 · out of the chip图 06 · 出芯片

The signal changes form three times, and is stored none of them信号变了三次形态,一次都没被存下来

Everything so far happened inside one piece of silicon. This is where the pixels physically leave it, travel down a flex cable, and get turned back into light. It is also the only stage where the signal's form actually changes: parallel inside the chip, serial on the cable, parallel again inside the panel.到这里为止,一切都发生在同一片硅上。这一步像素真的离开它、走过一根排线、再变回光。这也是整条通路上唯一一处信号形态真的变了的地方:片内是并行的,排线上是串行的,进屏又变回并行。

OUT OF THE CHIP AND INTO THE GLASS this is the one place in the whole path where the signal actually changes form. parallel inside the chip → serial on the cable → parallel again inside the panel. stored nowhere along the way. inside the silicon video port one pixel per clock 1 24 data wires + hsync, vsync, DE parallel MIPI DSI controller one packet per line 2 adds ECC and checksum per packet D-PHY serialiser 3 1.5 Gbit/s per lane lane 0 lane 1 lane 2 lane 3 clock off-chip · down the flex cable the panel · a separate component driver IC deserialises, then drives 4 TE · the panel answers back source driver · 3240 outputs · one whole row at once 5 gate driver 2400 6 the source driver holds one row of colours; the gate driver picks which row gets it. 2400 rows, 60 times a second. the only line in this figure that runs backwards is the one the panel uses to say “I have just finished a refresh”. that line is the tearing effect signal, turned on with the DCS command SET_TEAR_ON, 0x35 (include/video/mipi_display.h:115, issued at drm_mipi_dsi.c:1380). without it a command-mode panel has no way to know when writing is safe. lane count is not fixed by the standard — each panel declares its own (include/drm/drm_mipi_dsi.h:192), and four is simply what a 1080p 60 Hz phone needs.
serialiser, cable, driver IC, glass串行器、排线、驱动 IC、玻璃 The panel is a separate component with its own controller. Its driver IC deserialises the packets and drives 3240 source outputs — one whole row of subpixels at once — while a gate driver selects which of the 2400 rows receives it. One line runs backwards in this figure: the tearing effect signal, enabled with the DCS command SET_TEAR_ON = 0x35 (include/video/mipi_display.h:115, issued at drm_mipi_dsi.c:1380). Lane count is not fixed by the standard; each panel declares its own (include/drm/drm_mipi_dsi.h:192), and four is simply what 1080p at 60 Hz needs. Read ①②③ as the serialising half, ④ as the chip inside the panel that turns the packets back into parallel, and ⑤ and ⑥ as the two drivers that actually address the glass.屏是一个独立的器件,有自己的控制器。它的驱动 IC 把包解成并行,驱动 3240 路源极输出——一次驱动一整行子像素——同时栅极驱动决定 2400 行里哪一行接收它。这张图里只有一根线是朝回走的:TE 信号,用 DCS 命令 SET_TEAR_ON = 0x35 打开(include/video/mipi_display.h:115,发命令的地方在 drm_mipi_dsi.c:1380)。lane 数不是标准定死的,每块屏自己声明(include/drm/drm_mipi_dsi.h:192),四条只是 1080p 60 Hz 需要这么多。顺 ①②③ 看是串行化,④ 是屏里那颗把包解回并行的芯片,⑤⑥ 才是真正去点亮玻璃的两组驱动。
Figure 07 · the price of sharing图 07 · 共用的代价

Sharing one memory removed the copies. It did not remove the queue共用一块内存省掉了拷贝,但没省掉排队

Every figure so far has ended with “and that is why sharing one DRAM is the right design”. It is worth being honest about what it costs, because that cost is where most real display bugs actually live.前面每张图的结论都是「所以共用一块 DDR 是对的设计」。那也该把代价说清楚,因为真实的显示故障大多就住在这个代价里

SIX TENANTS, ONE MEMORY BUS sharing one DRAM removed the copies. what it did not remove is the queue. every block on the chip asks the same memory for bandwidth, and there is not enough for everyone at once. display controller 1.2 GB/s hard real time · cannot be late GPU 2.4 GB/s can drop a frame and catch up camera ISP 0.9 GB/s only while the camera is open video codec 0.7 GB/s only while something is playing CPU cluster 0.6 GB/s bursty, small 6.4 GB/s — everything the DRAM can deliver 5.8 GB/s asked for, 6.4 available. one more tenant and somebody waits. THE MEMORY CONTROLLER DOES NOT SERVE THEM IN THE ORDER THEY ASKED request queue finite depth, reordered deep enough to hide a row miss, no more 1 served by consequence, not by arrival the display port is picked first, every time 2 if the GPU is served late one frame is dropped. the next one catches up. nobody outside the phone can tell. if scanout is served late the 16-line buffer empties and the pixel clock does not wait. a band appears across the screen, in that frame, visibly. the two kinds of lateness differ by an order of magnitude in consequence, so the priorities differ too. this is also the answer to “why did adding a camera preview make the display stutter” — nothing in the display path changed; a sixth tenant moved in.
six requesters, one bus六个主设备,一条总线 The memory controller does not serve requests in arrival order. It serves them by consequence of lateness, and the display port is picked first every time. The reasoning is asymmetric: if the GPU is served late it drops a frame and catches up, and nobody outside the phone can tell. If scanout is served late the 16-line buffer empties, the pixel clock does not wait, and a band appears across the screen in that frame. This is also the answer to “adding a camera preview made the display stutter” — nothing in the display path changed; a sixth tenant moved in.内存控制器不按请求到达的顺序服务,而是按误了会有什么后果排序,显示端口每次都排第一。理由是不对称的:GPU 晚了,掉一帧,下一帧补上,手机外面的人看不出来;扫描输出晚了,16 行的行缓冲会空,而像素时钟不会等,那一帧的屏幕上就出现一道横条。这也是「加了一路摄像头预览之后显示开始抖」的答案——显示通路一点没改,是第六个租户搬进来了。
Figure 08 · the other kind of machine图 08 · 另一种机器

Where the word “upload” actually came from「上传」这个词到底是从哪儿来的

Everything above describes a phone, where the GPU and the display controller share one DRAM. On a desktop machine with a discrete graphics card there really is a second memory across a link, and a copy really does happen. That case is worth drawing because it is where the vocabulary everyone uses came from — and then got applied to hardware where it does not fit.上面说的都是手机,GPU 和显示控制器共用一块 DDR。桌面机插独立显卡的话,隔着一根链路真的有第二块内存,拷贝也真的会发生。这种情况值得画出来,因为大家嘴上那套词汇正是从这儿来的,然后被套到了并不适用的硬件上。

DISCRETE CARD · WHO PULLS FROM WHOM requests go this way data comes back host CPU sets it up, then stops SYSTEM MEMORY other image pinned other pinned + mapped so the card can reach it — the pages never move PCIe · the only wire COPY 48 MiB once the card issues the reads — this is a pull not the CPU pushing bytes out graphics card · its own board copy engine it does this shaders display engine VRAM · a second address space textures 48 MiB fb · back fb · front once a byte is here it never crosses PCIe again to the monitor whoever needs the data issues the reads. that rule did not change — only the number of memories did. 1 2 3 ① the copy engine on the card sends read requests across the link · ② the data comes back and lands in VRAM · ③ and stays there. drawing the link as two opposite lines is what makes “pull” visible; one double-headed arrow would have left it ambiguous, and ambiguous is exactly where the misunderstanding lives. Discrete card · a pull, not a push
discrete card · a pull, not a push独立显卡 · 是拉,不是推 Note who initiates. The requests start on the card, so the copy is a pull: the initiator is the card's own copy engine, not the processor. That is the same rule as on a phone — whoever needs the data issues the reads. Only the number of memories changed. Placement is defined in include/drm/ttm/ttm_placement.h:51, the copy path is amdgpu_move_blit → amdgpu_copy_buffer (amdgpu_ttm.c:383, :2484), and scanout is forced into VRAM at amdgpu_display.c:560.留意是谁发起的。请求起于显卡这边,所以这次拷贝是不是推:发起方是显卡自己的搬运引擎,不是处理器。这跟手机上是同一条规律——谁要数据谁发读请求,变的只是内存的块数。归属定义在 include/drm/ttm/ttm_placement.h:51,拷贝走的是 amdgpu_move_blit → amdgpu_copy_bufferamdgpu_ttm.c:383:2484),扫描输出被强制放在 VRAM,见 amdgpu_display.c:560
when this is the thing you needed to know什么时候用得上

Four moments where this changes what you do next四个时刻,知道这些会改变你下一步怎么做

WHEN IT BREAKS · WHICH STOP TO START AT the same eight figures, read backwards: a symptom, and where on the path it comes from. THE SYMPTOM WHAT IT ACTUALLY IS START HERE DO NOT START HERE tearing the flip landed mid-scan figure 05 when the base register takes effect the panel it received exactly what it was sent a band, or a flash underflow — the line buffer ran dry figure 07 who else is using bandwidth the DSI registers DSI is further down than the fault frozen image, no crash the base address stopped being updated figure 01 the flip path in the display driver the GPU it may be drawing perfectly wrong layer order the overlay's layer selection figure 04 window and layer config what the application drew the last column is worth more than the first three. the usual waste is starting at the end of the path, and the fault is almost never there.
the same figures, read backwards同样这些图,倒着读 A symptom is a report from one specific stop on the path, and knowing which stop is most of the work. The fourth column is worth more than the other three: display debugging is usually wasted at the far end of the path, because the DSI registers are the easiest thing to read and the least likely thing to be wrong.一个症状其实是通路上某一站发来的报告,而判断出是哪一站,这活儿就干完一大半了。第四列比前三列值钱:查显示问题最常见的浪费就是从通路最末端开始查——因为 DSI 寄存器最好读,而它恰恰是最不可能出错的地方。
the screen tears or flashes a band屏幕撕裂,或者闪一道横条
Decide first whether the fetch is falling behind or the panel timing is wrong. A band means underflow, which means bandwidth contention — start at the memory controller's tenants, not at the DSI registers. DSI sits further down the path than the problem does.先判断是取数没跟上,还是面板时序不对。出现横条就是欠载,欠载意味着带宽争用——从内存控制器的租户查起,不要从 DSI 寄存器查起。DSI 在通路上比问题实际所在的位置更靠后。
display started stuttering after a feature landed上了个新功能之后显示开始抖
Ask what new bus master appeared. A camera preview is a sixth tenant on the same 6.4 GB/s, and the display path itself did not change at all. The fix is usually a QoS setting, not a display change.先问多了哪个主设备。摄像头预览就是同一条 6.4 GB/s 上的第六个租户,而显示通路本身一行没改。这类问题的修法通常是调服务质量设置,不是改显示。
someone says “upload the image to the GPU first”有人说「先把图上传到 GPU 再显示」
On this class of chip there is no upload. There is writing to a different address in the same DRAM. The word came from discrete cards, where there really is a second memory across a link — figure 08.在这一类芯片上没有上传这一步,只有「写到同一块 DDR 的另一个地址」。这个词来自独立显卡,那里确实隔着一根链路有第二块内存——见图 08。
you are looking for the DMA registers你在找 DMA 相关的寄存器
They are in the display controller driver. The DSI bridge does not read memory at all — pixels are fed to it. grep -c dma_addr in drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c returns 0.它们在显示控制器驱动里。DSI 桥根本不读内存——像素是别人喂给它的。在 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c 里跑 grep -c dma_addr 得到 0。
what was actually opened到底看了什么

Every structural claim, with the line it came from每一条结构性论断,附出处

Tree v7.0-9887-ga43fac2b5813. Driver names are named because the code was read; the figures stay generic because the principle is general.树是 v7.0-9887-ga43fac2b5813。驱动名写出来是因为代码确实读了;图里保持通用名,因为原理是通用的。

the display controller's internal structure显示控制器的内部结构
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:41-68 — the vendor's own block diagram in the driver header: six windows, six layer selectors, three overlays, three video ports, an output selector.——驱动头部厂商自己画的框图:六个窗口、六个层选择器、三个混合器、三个视频端口、一个输出选择。
the line buffer is 16 lines行缓冲只有 16 行
rockchip_drm_vop2.c:500 — “a Cluster window has 2048 x 16 line buffer”. Not a simplification, and not one frame.——原文「a Cluster window has 2048 x 16 line buffer」。不是我简化的,也不是一帧。
the flip is a register write翻页就是一次寄存器写
rockchip_drm_vop2.c:1370 · vop2_win_write(win, VOP2_WIN_YRGB_MST, yrgb_mst)
the DSI bridge holds no bufferDSI 桥不持有缓冲
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c grep -c dma_addr returns 0. It never issues a read.——grep -c dma_addr 得到 0。它从不发读请求。
the GPU has its own MMU, page tables in DRAMGPU 有自己的 MMU,页表住在内存里
drivers/gpu/drm/panfrost/panfrost_regs.h · panfrost_mmu.c:820
the TE signal and its DCS commandTE 信号和它的 DCS 命令
include/video/mipi_display.h:115 MIPI_DCS_SET_TEAR_ON = 0x35, issued at drm_mipi_dsi.c:1380. Lane count per panel:——MIPI_DCS_SET_TEAR_ON = 0x35,发命令的地方在 drm_mipi_dsi.c:1380。每块屏自己的 lane 数: include/drm/drm_mipi_dsi.h:192
the discrete-card copy path独立显卡的拷贝通路
include/drm/ttm/ttm_placement.h:51 · amdgpu_ttm.c:383 · :2484 · sdma_v5_2.c:2060 · amdgpu_display.c:560
the figures这些图

All ten are templates you can copy十张全都是可以直接抄走的模板

They live in templates/diagrams/ as arm64-display-path.svg, what-is-a-frame.svg, gpu-tile-render.svg, display-controller-inside.svg, buffer-roles.svg, dsi-panel-inside.svg, bus-tenants.svg, display-vocabulary.svg, display-triage.svg and vram-copy-flow.svg, next to thirty-nine more built the same way. All of them follow references/diagram-craft.md and pass the design-review checks. The animated flow lines stop under prefers-reduced-motion.它们在 templates/diagrams/ 下,叫 arm64-display-path.svgwhat-is-a-frame.svggpu-tile-render.svgdisplay-controller-inside.svgbuffer-roles.svgdsi-panel-inside.svgbus-tenants.svgdisplay-vocabulary.svgdisplay-triage.svgvram-copy-flow.svg,旁边还有三十九张同一套画法的图。全部遵循 references/diagram-craft.md,并通过 design-review 的检查。会动的流动线在 prefers-reduced-motion 下会停。

Open the gallery打开图集