Skip to content

Commit b0093fb

Browse files
committed
Clean up rendering overview (second pass)
1 parent e7a736d commit b0093fb

File tree

1 file changed

+23
-19
lines changed

1 file changed

+23
-19
lines changed

src/Rendering.md

+23-19
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,46 @@
11
# Rendering overview
22

3-
::: tip TERMINOLOGY
3+
## Terminology
44

5-
All references to a "dot" are meant as dots (one 4 MiHz time unit).
6-
Dots remain the same regardless of whether the CPU is in [double speed](<#FF4D — KEY1 (CGB Mode only): Prepare speed switch>).
5+
The entire frame is not drawn atomically; instead, the image is drawn by the **<abbr>PPU</abbr>** (Pixel-Processing Unit) progressively, **directly to the screen**.
6+
A frame consists of 154 **scanlines**; during the first 144, the screen is drawn top to bottom, left to right.
7+
8+
The main implication of this rendering process is the existence of **raster effects**: modifying some rendering parameters in the middle of rendering.
9+
The most famous raster effect is modifying the [scrolling registers](<#LCD Position and Scrolling>) between scanlines to create a ["wavy" effect](https://gbdev.io/guides/deadcscroll#effects).
10+
11+
A "**dot**" = one 2<sup>22</sup> Hz (≅ 4.194 MHz) time unit.
12+
Dots remain the same regardless of whether the CPU is in [double speed](<#FF4D — KEY1 (CGB Mode only): Prepare speed switch>), so there are 4 dots per single-speed CPU cycle, and 2 per double-speed CPU cycle.
13+
14+
::: tip
15+
16+
Note that a frame is not exactly one 60<sup>th</sup> of a second: the Game Boy runs slightly slower than 60 Hz, as one frame takes ~16.74 ms instead of ~16.67 (the error is 0.45%).
717

818
:::
919

10-
<figure><figcaption>
20+
## PPU modes
1121

12-
The following diagram shows how a Game Boy frame is decomposed:
22+
<figure><figcaption>
1323

24+
During a frame, the Game Boy's PPU cycles between four modes as follows:
1425
</figcaption>
1526

1627
{{#include imgs/ppu_modes_timing.svg:2:}}
1728

1829
</figure>
1930

20-
TODO: high-level description of the above... and implications ("raster effects")
21-
22-
## PPU modes
23-
24-
The PPU operates on a 2<sup>22</sup> Hz = 4.194 MHz clock, called the "dot clock".
25-
An entire frame is 154 scanlines = 70224 dots = 16.74 ms. On scanlines 0
26-
through 143, the PPU cycles through modes 2, 3, and 0 once
27-
every 456 dots. Scanlines 144 through 153 are mode 1.
28-
2931
While the PPU is accessing some video-related memory, [that memory is inaccessible to the CPU](<#Accessing VRAM and OAM>) (writes are ignored, and reads return garbage values, usually $FF).
3032

3133
Mode | Action | Duration | Accessible video memory
32-
-----|--------------------------------------------|--------------------------------------|-------------------------
34+
----:|--------------------------------------------|--------------------------------------|-------------------------
3335
2 | Searching for OBJs which overlap this line | 80 dots | VRAM, CGB palettes
3436
3 | Sending pixels to the LCD | Between 172 and 289 dots, see below | None
3537
0 | Waiting until the end of the scanline | 376 - mode 3's duration | VRAM, OAM, CGB palettes
3638
1 | Waiting until the next frame | 4560 dots (10 scanlines) | VRAM, OAM, CGB palettes
3739

3840
## Mode 3 length
3941

42+
During Mode 3, by default the PPU outputs one pixel to the screen per dot; the screen is 160 pixels wide, so the minimum Mode 3 length is 160 + 12[^first12] = 172 dots.
43+
4044
Unlike most game consoles, the Game Boy does not always output pixels steadily[^crt]: some features cause the rendering process to stall for a couple dots.
4145
Any extra time spent stalling *lengthens* Mode 3; but since scanlines last for a fixed number of dots, Mode 0 is therefore shortened by that same amount of time.
4246

@@ -46,9 +50,7 @@ Three things can cause Mode 3 "penalties":
4650
- **Window**: After the last non-window pixel is emitted, a 6-dot penalty is incurred while the BG fetcher is being set up for the window.
4751
- **Objects**: Each object drawn during the scanline (even partially) incurs a 6- to 11-dot penalty ([see below](<#OBJ penalty algorithm>)).
4852

49-
On DMG and GBC in DMG mode, mid-scanline writes to [`BGP`](<#FF47 — BGP (Non-CGB Mode only): BG palette data>)
50-
allow observing this behavior, as the delay from drawing an OBJ shifts the
51-
write's effect to the left by that many dots.
53+
On DMG and GBC in DMG mode, mid-scanline writes to [`BGP`](<#FF47 — BGP (Non-CGB Mode only): BG palette data>) allow observing this behavior precisely, as any delay shifts the write's effect to the left by that many dots.
5254

5355
### OBJ penalty algorithm
5456

@@ -63,6 +65,8 @@ Only the OBJ's leftmost pixel matters here, transparent or not; it is designated
6365

6466
**Exception**: an OBJ with an OAM X position of 0 (thus, completely off the left side of the screen) always incurs a 11-cycle penalty, regardless of `SCX`.
6567

66-
TODO: a diagram of some examples would probably help this be much clearer! \>_\<
68+
TODO: a diagram of some examples would probably help this be much clearer!
69+
70+
[^first12]: The 12 extra cycles come from two tile fetches at the beginning of Mode 3. One is the first tile in the scanline (the one that gets shifted by `SCX` % 8 pixels), the other is simply discarded.
6771

6872
[^crt]: The Game Boy can afford to "take pauses", because it writes to a LCD it fully controls; by contrast, home consoles like the NES or SNES are on a schedule imposed by the screen they are hooked up to. Taking pauses arguably simplified the PPU's design while allowing greater flexibility to game developers.

0 commit comments

Comments
 (0)