Skip to content
RetrogamingDeep Dive Published Updated 7 min readViews unavailable

Tile-Based Rendering: How 2D Consoles Built Scenes Without a Modern Framebuffer

How tile maps, pattern tables, palettes, sprites, scanlines, and hardware limits produced classic 2D graphics—and what an emulator must reproduce.

Many 2D consoles did not give games a large linear RGB framebuffer. They stored reusable small pixel patterns—tiles—in video memory, then described a scene as maps of tile indexes plus palette and attribute data. Dedicated video hardware fetched those structures as the display scanned from top to bottom.

That arrangement saved memory and bandwidth. A 32×32 map of one-byte tile indexes occupies roughly one kilobyte before attributes, while a full color framebuffer for the same visible area would be much larger. Repeated bricks, letters, terrain, and UI panels reference one pattern many times instead of storing identical pixels at every location.

“Tile-based” here describes classic display hardware that composes backgrounds and objects from patterns. It should not be confused with modern GPUs that divide a framebuffer into internal rendering tiles for cache efficiency; the word is shared, but the programmer-visible models differ.

From pattern bits to colored pixels

A tile pattern usually stores small color indexes, not final RGB values. Bitplanes or packed fields encode each pixel’s palette entry. A separate palette converts that index to the console’s available color representation. The number of bits per pixel determines how many entries a tile can select, while attributes may choose among palette banks.

Bitplane layout matters. In a planar format, bits for one significance level are grouped separately from other planes. Emulators combine the corresponding bits to produce a color index. Endianness, row order, plane offsets, and tile dimensions are platform-specific; interpreting raw pattern memory as a modern bitmap produces scrambled art.

Some systems keep patterns in ROM, others copy them to video RAM, and others let software rewrite them while the game runs. Character animation, water, fire, and text effects can update pattern data without changing every map entry that references it.

Backgrounds and sprites

A background map points to tile patterns and may add palette, priority, or flip bits. Scrolling changes which portion of a larger map is sampled. Sprites use a separate object table with position, tile, palette, and orientation. Hardware combines layers according to platform-specific priority rules.

Map entries vary. On one machine an entry may contain only a tile number, with palette and flip information stored in a coarser attribute table. Another may pack tile index, palette, horizontal and vertical flip, and priority into one word. Multiple background layers can use different sizes, color depths, or map dimensions.

Scrolling is more than moving an already-rendered image. The graphics processor derives coarse tile coordinates and fine pixel offsets, wraps within a name table or map, fetches the next patterns, and shifts pixel data toward the output. Edge behavior, map selection, and when scroll registers latch are observable by software.

Sprites—or objects—come from an object attribute table containing positions and pattern selection plus platform-specific size, palette, priority, and flip controls. Large characters are metasprites assembled by software from several hardware sprites. Collision is generally game logic, though some chips expose sprite/background hit or overflow flags with hardware-specific quirks.

The scanline fetch pipeline

Video hardware has a finite number of memory cycles during each line. It fetches map entries, pattern bits, attributes, sprites, and palettes according to a schedule while pixels are emitted. CPU access may be blocked, delayed, restricted to blanking intervals, or share the bus through arbitration.

On the NES PPU, documented rendering behavior includes background fetch sequences, shift registers, sprite evaluation, and prefetch for following pixels and lines. On the Game Boy, the pixel FIFO and object fetching influence mode timing; drawing time can vary with scrolling and sprites. Those are not interchangeable implementations even though both systems use tiles.

Blanking intervals give software time to update display memory and registers without disrupting active drawing. Vertical blank is the usual window for large map, palette, and sprite-table changes. Horizontal blank or precisely timed active-display writes enable raster effects. Missing the allowed window can produce ignored writes, visible corruption, or timing behavior software intentionally uses.

Constraints became visual style

Palette limits, tiles per scanline, sprite counts, memory bandwidth, and fixed layer counts shaped art and engine design. Developers reused patterns, animated tiles in place, split screens, and changed registers during blanking or active scanout. Hardware drops or hides sprites beyond a per-line limit on some systems. Engines sometimes rotate object priority between frames so different sprites disappear, turning a hard omission into visible flicker; the limit is hardware, while the mitigation is deliberate.

Techniques built from the constraints

Animated tiles replace pattern data for every map location referencing it, making water or machinery inexpensive. Metatiles group several hardware tiles into reusable level-building blocks stored in game code. Metasprites do the same for characters. Compression reduces ROM use, with level data expanded into maps as needed.

Raster splits change scroll, palette, or layer settings at selected lines. A status bar can remain fixed while the playfield scrolls; repeated changes can create wavy water or perspective roads. Parallax can come from multiple background layers moving at different rates or from changing one layer’s scroll across bands of the screen.

Palette animation changes colors without rewriting pattern indexes. Priority bits place selected background tiles before or behind sprites, enabling scenery occlusion. Window layers or masks create HUD panels and transitions. Each technique depends on exact rules for latching, fetching, and combining layers.

The constraints also explain common artifacts. A partially updated map can tear at tile boundaries, palette writes can affect only part of a frame, and object limits can hide pieces of a large character. “Fixing” these universally in an emulator may erase behavior games expect; enhancement options should be labeled separately from hardware-accurate output.

Different consoles expose different contracts

The NES uses pattern tables, name tables, attribute tables, palettes, and a separate object table under a particular PPU timing model. The Game Boy LCD controller combines tile maps, tile data areas, a window, and objects through its own fetcher and FIFO rules. The SNES adds several background modes, color depths, layer priorities, affine Mode 7, color math, windows, and a larger set of object options.

Do not generalize one platform’s “8×8 tiles and four palettes” tutorial into a universal emulator design. Tile dimensions, map addressing, transparency index, palette lookup, sprite evaluation, priority resolution, and bus access all need a per-device specification backed by tests.

Why emulation is timing-sensitive

Rendering only the final tile map once per frame misses mid-frame register writes, sprite overflow flags, raster effects, and bus contention. Accurate emulators model when the graphics processor fetches data and when CPU writes become visible. That is why two screenshots can look identical while one implementation still breaks a game that relies on a precise scanline event.

A fast renderer may batch spans, scanlines, or layers when no observable event can intervene. That can be accurate if it stops at register writes, memory changes, interrupts, and fetch boundaries software can observe. A per-pixel implementation can still be wrong when its ordering or latches differ from hardware. Granularity is an implementation choice; validated behavior is the requirement.

Graphics debugging benefits from separate viewers for pattern tables, maps, palettes, object tables, fetch timing, and final composition. Trace which map entry and pattern produced a pixel, including priority decisions. This turns a wrong screenshot into a specific address, fetch, or ordering error.

Test beyond familiar screenshots

Diagnostic ROMs should exercise fine scrolling, map wrap, edge clipping, sprite limits, overflow and hit flags, priority ties, palette writes, blanking access, DMA, mid-scanline changes, and video-mode transitions. Compare traces and capture with multiple hardware revisions where behavior differs. Commercial games provide integration coverage but may never touch a disputed edge case.

Preserve test binaries, source, expected output, timing notes, content hashes, and hardware capture method. Screenshots retain the final image but not when individual pixels appeared or which status flags software read. A video capture adds timing evidence but still needs context about the console, region, cable, display chain, and capture processing.

Tile systems were economical hardware architectures, not merely a storage format. Preserving their behavior requires code, documentation, test ROMs, and timing evidence—not just extracted art.

Related:

Sources:

Comments