|
1 |
| -# Rendering Overview |
| 1 | +# Rendering overview |
2 | 2 |
|
3 |
| -The Game Boy outputs graphics to a 160×144 pixel LCD, using a quite complex |
4 |
| -mechanism to facilitate rendering. |
| 3 | +## Terminology |
5 | 4 |
|
6 |
| -::: warning Terminology |
| 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 | 7 |
|
8 |
| -Sprites/graphics terminology can vary a lot among different platforms, consoles, |
9 |
| -users and communities. You may be familiar with slightly different definitions. |
10 |
| -Keep also in mind that some definitions refer to lower (hardware) tools |
11 |
| -and some others to higher abstractions concepts. |
| 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%). |
12 | 17 |
|
13 | 18 | :::
|
14 | 19 |
|
15 |
| -## Tiles |
| 20 | +## PPU modes |
16 | 21 |
|
17 |
| -Similarly to other retro systems, pixels are not manipulated |
18 |
| -individually, as this would be expensive CPU-wise. Instead, pixels are grouped |
19 |
| -in 8×8 squares, called _tiles_ (or sometimes "patterns" or "characters"), often considered as |
20 |
| -the base unit in Game Boy graphics. |
| 22 | +<figure><figcaption> |
21 | 23 |
|
22 |
| -A tile does not encode color information. Instead, a tile assigns a |
23 |
| -_color ID_ to each of its pixels, ranging from 0 to 3. For this reason, |
24 |
| -Game Boy graphics are also called _2bpp_ (2 bits per pixel). When a tile is used |
25 |
| -in the Background or Window, these color IDs are associated with a _palette_. When |
26 |
| -a tile is used in an object, the IDs 1 to 3 are associated with a palette, but |
27 |
| -ID 0 means transparent. |
| 24 | +During a frame, the Game Boy's PPU cycles between four modes as follows: |
28 | 25 |
|
29 |
| -## Palettes |
| 26 | +</figcaption> |
30 | 27 |
|
31 |
| -A palette consists of an array of colors, 4 in the Game Boy's case. |
32 |
| -Palettes are stored differently in monochrome and color versions of the console. |
| 28 | +{{#include imgs/ppu_modes_timing.svg:2:}} |
33 | 29 |
|
34 |
| -Modifying palettes enables graphical effects such as quickly flashing some graphics (damage, |
35 |
| -invulnerability, thunderstorm, etc.), fading the screen, "palette swaps", and more. |
| 30 | +</figure> |
36 | 31 |
|
37 |
| -## Layers |
| 32 | +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). |
38 | 33 |
|
39 |
| -The Game Boy has three "layers", from back to front: the Background, the Window, |
40 |
| -and the Objects. Some features and behaviors break this abstraction, |
41 |
| -but it works for the most part. |
| 34 | +Mode | Action | Duration | Accessible video memory |
| 35 | +----:|--------------------------------------------|--------------------------------------|------------------------- |
| 36 | + 2 | Searching for OBJs which overlap this line | 80 dots | VRAM, CGB palettes |
| 37 | + 3 | Sending pixels to the LCD | Between 172 and 289 dots, see below | None |
| 38 | + 0 | Waiting until the end of the scanline | 376 - mode 3's duration | VRAM, OAM, CGB palettes |
| 39 | + 1 | Waiting until the next frame | 4560 dots (10 scanlines) | VRAM, OAM, CGB palettes |
42 | 40 |
|
43 |
| -### Background |
| 41 | +## Mode 3 length |
44 | 42 |
|
45 |
| -The background is composed of a _tilemap_. A tilemap is a |
46 |
| -large grid of tiles. However, tiles aren't directly written to tilemaps, |
47 |
| -they merely contain references to the tiles. |
48 |
| -This makes reusing tiles very cheap, both in CPU time and in |
49 |
| -required memory space, and it is the main mechanism that helps work around the |
50 |
| -paltry 8 KiB of video RAM. |
| 43 | +During Mode 3, by default the PPU outputs one pixel to the screen per dot, from left to right; the screen is 160 pixels wide, so the minimum Mode 3 length is 160 + 12[^first12] = 172 dots. |
51 | 44 |
|
52 |
| -The background can be made to scroll as a whole, writing to two |
53 |
| -hardware registers. This makes scrolling very cheap. |
| 45 | +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. |
| 46 | +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. |
54 | 47 |
|
55 |
| -### Window |
| 48 | +Three things can cause Mode 3 "penalties": |
56 | 49 |
|
57 |
| -The window is sort of a second background layer on top of the background. |
58 |
| -It is fairly limited: it has no transparency, it's always a |
59 |
| -rectangle and only the position of the top-left pixel can be controlled. |
| 50 | +- **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. |
| 51 | +- **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. |
| 52 | +- **Objects**: Each object drawn during the scanline (even partially) incurs a 6- to 11-dot penalty ([see below](<#OBJ penalty algorithm>)). |
60 | 53 |
|
61 |
| -Possible usage include a fixed status bar in an otherwise scrolling game (e.g. |
62 |
| -_Super Mario Land 2_). |
| 54 | +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. |
63 | 55 |
|
64 |
| -### Objects |
| 56 | +### OBJ penalty algorithm |
65 | 57 |
|
66 |
| -The background layer is useful for elements scrolling as a whole, but |
67 |
| -it's impractical for objects that need to move separately, such as the player. |
| 58 | +Only the OBJ's leftmost pixel matters here, transparent or not; it is designated as "The Pixel" in the following. |
68 | 59 |
|
69 |
| -The _objects_ layer is designed to fill this gap: _objects_ are made of 1 or 2 stacked tiles (8×8 or 8×16 pixels) |
70 |
| -and can be displayed anywhere on the screen. |
| 60 | +1. Determine the tile (background or window) that The Pixel is within. (This is affected by horizontal scrolling and/or the window!) |
| 61 | +2. If that tile has **not** been considered by a previous OBJ yet[^order]: |
| 62 | + 1. Count how many of that tile's pixels are strictly to the right of The Pixel. |
| 63 | + 2. Subtract 2. |
| 64 | + 3. Incur this many dots of penalty, or zero if negative (from waiting for the BG fetch to finish). |
| 65 | +3. Incur a flat, 6-dot penalty (from fetching the OBJ's tile). |
71 | 66 |
|
72 |
| -::: tip NOTE |
| 67 | +**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`. |
73 | 68 |
|
74 |
| -Several objects can be combined (they can be called _metasprites_) to draw |
75 |
| -a larger graphical element, usually called "sprite". Originally, the term "sprites" |
76 |
| -referred to fixed-sized objects composited together, by hardware, with a background. |
77 |
| -Use of the term has since become more general. |
78 | 69 |
|
79 |
| -::: |
| 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. |
80 | 71 |
|
81 |
| -To summarise: |
| 72 | +[^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. |
82 | 73 |
|
83 |
| -- **Tile**, an 8×8-pixel chunk of graphics. |
84 |
| -- **Object**, an entry in object attribute memory, composed of 1 or 2 |
85 |
| - tiles. Can be moved independently of the background. |
| 74 | +[^order]: Since pixels are emitted from left to right, OBJs overlapping the scanline are considered from [leftmost](<#Byte 1 — X Position>) to rightmost, with ties broken by their index / OAM address (lowest first). |
0 commit comments