Skip to content

Commit e7a736d

Browse files
committed
Clean up rendering overview (first pass)
1 parent 2512bdf commit e7a736d

File tree

2 files changed

+40
-45
lines changed

2 files changed

+40
-45
lines changed

src/Rendering.md

+30-45
Original file line numberDiff line numberDiff line change
@@ -17,67 +17,52 @@ The following diagram shows how a Game Boy frame is decomposed:
1717

1818
</figure>
1919

20-
## STAT modes
20+
TODO: high-level description of the above... and implications ("raster effects")
2121

22-
The LCD controller operates on a 2^22 Hz = 4.194 MHz dot clock. An
23-
entire frame is 154 scanlines = 70224 dots = 16.74 ms. On scanlines 0
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
2426
through 143, the PPU cycles through modes 2, 3, and 0 once
2527
every 456 dots. Scanlines 144 through 153 are mode 1.
2628

27-
The following sequence is typical when the display is enabled:
29+
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).
2830

29-
```
30-
Mode 2 2_____2_____2_____2_____2_____2___________________2____
31-
Mode 3 _33____33____33____33____33____33__________________3___
32-
Mode 0 ___000___000___000___000___000___000________________000
33-
Mode 1 ____________________________________11111111111111_____
34-
```
31+
Mode | Action | Duration | Accessible video memory
32+
-----|--------------------------------------------|--------------------------------------|-------------------------
33+
2 | Searching for OBJs which overlap this line | 80 dots | VRAM, CGB palettes
34+
3 | Sending pixels to the LCD | Between 172 and 289 dots, see below | None
35+
0 | Waiting until the end of the scanline | 376 - mode 3's duration | VRAM, OAM, CGB palettes
36+
1 | Waiting until the next frame | 4560 dots (10 scanlines) | VRAM, OAM, CGB palettes
3537

36-
When the PPU is accessing some video-related memory, that memory is inaccessible
37-
to the CPU: writes are ignored, and reads return garbage values (usually $FF).
38+
## Mode 3 length
3839

39-
- During modes 2 and 3, the CPU cannot access [OAM](<#VRAM Sprite Attribute Table (OAM)>) ($FE00-FE9F).
40-
- During mode 3, the CPU cannot access VRAM or [CGB palette data registers](<#LCD Color Palettes (CGB only)>)
41-
($FF69,$FF6B).
40+
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.
41+
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.
4242

43-
Mode | Action | Duration | Accessible video memory
44-
-----|------------------------------------------------------------------|--------------------------------------------------------------------|-------------------------
45-
2 | Searching OAM for OBJs whose Y coordinate overlap this line | 80 dots | VRAM, CGB palettes
46-
3 | Reading OAM and VRAM to generate the picture | 168 to 291 dots, depending on object count | None
47-
0 | Nothing (HBlank) | 85 to 208 dots, depending on previous mode 3 duration | VRAM, OAM, CGB palettes
48-
1 | Nothing (VBlank) | 4560 dots (10 scanlines) | VRAM, OAM, CGB palettes
43+
Three things can cause Mode 3 "penalties":
4944

50-
## Properties of STAT modes
45+
- **Background scrolling**: At the very beginning of Mode 3, rendering is paused for [`SCX`](<#FF42–FF43 — SCY, SCX: Viewport Y position, X position>) % 8 dots while the same number of pixels are discarded from the leftmost tile.
46+
- **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.
47+
- **Objects**: Each object drawn during the scanline (even partially) incurs a 6- to 11-dot penalty ([see below](<#OBJ penalty algorithm>)).
5148

52-
Unlike most game consoles, the Game Boy can pause the dot clock briefly,
53-
making Mode 3 longer and Mode 0 shorter. It routinely takes a 6 to 11 dot
54-
break to fetch an OBJ's tile between background tile pattern fetches.
5549
On DMG and GBC in DMG mode, mid-scanline writes to [`BGP`](<#FF47 — BGP (Non-CGB Mode only): BG palette data>)
5650
allow observing this behavior, as the delay from drawing an OBJ shifts the
5751
write's effect to the left by that many dots.
5852

59-
Three things are known to pause the dot clock:
60-
61-
- Background scrolling: If `SCX % 8` is not zero at the start of the scanline, rendering is paused for that many dots while the shifter discards that many pixels from the leftmost tile.
62-
- Window: An active window pauses for at least 6 dots, as the background fetching mechanism starts over at the left side of the window.
63-
- Objects: Each object usually pauses for `11 - min(5, (x + SCX) % 8)` dots.
64-
Because object fetch waits for background fetch to finish, an object's cost depends on its position relative to the left side of the background tile under it. It's greater if an object is directly aligned over the background tile, less if the object is to the right. If the object's left side is over the window, use `255 - WX` instead of `SCX` in this formula.
53+
### OBJ penalty algorithm
6554

66-
::: warning TO BE VERIFIED
55+
Only the OBJ's leftmost pixel matters here, transparent or not; it is designated as "The Pixel" in the following.
6756

68-
The exact pause duration for window start is
69-
not confirmed; it may have the same background fetch finish delay as
70-
an object. If two objects' left sides are over the same background or
71-
window tile, the second may pause for fewer dots.
57+
1. Determine the tile (background or window) that The Pixel is within. (This is affected by horizontal scrolling and/or the window!)
58+
2. If that tile has **not** been considered by a previous OBJ yet:
59+
1. Count how many of that tile's pixels are to the right of The Pixel.
60+
2. Subtract 3.
61+
3. Incur this many dots of penalty, or zero if negative (from waiting for the BG fetch to finish).
62+
3. Incur a flat, 6-dot penalty (from fetching the OBJ's tile).
7263

73-
:::
64+
**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`.
7465

75-
A hardware quirk in the monochrome Game Boy makes the LCD interrupt
76-
sometimes trigger when writing to STAT (including writing \$00) during
77-
OAM scan, HBlank, VBlank, or LY=LYC. It behaves as if \$FF were
78-
written for one cycle, and then the written value were written the next
79-
cycle. Because the GBC in DMG mode does not have this quirk, two games
80-
that depend on this quirk (Ocean's *Road Rash* and Vic Tokai's *Xerd
81-
no Densetsu*) will not run on a GBC.
66+
TODO: a diagram of some examples would probably help this be much clearer! \>_\<
8267

83-
TODO
68+
[^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.

src/STAT.md

+10
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,13 @@ Bit 2 is set when [LY](<#FF44 — LY: LCD Y coordinate \[read-only\]>) contains
3939
It is constantly updated.
4040

4141
Bits 3-6 select which sources are used for [the STAT interrupt](<#INT $48 — STAT interrupt>).
42+
43+
### Spurious STAT interrupts
44+
45+
A hardware quirk in the monochrome Game Boy makes the LCD interrupt
46+
sometimes trigger when writing to STAT (including writing \$00) during
47+
OAM scan, HBlank, VBlank, or LY=LYC. It behaves as if \$FF were
48+
written for one cycle, and then the written value were written the next
49+
cycle. Because the GBC in DMG mode does not have this quirk, two games
50+
that depend on this quirk (Ocean's *Road Rash* and Vic Tokai's *Xerd
51+
no Densetsu*) will not run on a GBC.

0 commit comments

Comments
 (0)