Skip to content
RetrogamingDeep Dive Published Updated 8 min readViews unavailable

SNES Mode 7: Affine Transforms, Pivot Registers, and Raster Effects

Understand SNES Mode 7 fixed-point transforms, center offsets, map-boundary behavior, mosaic, and why per-line effects need raster-aware emulation.

Mode 7 is often described as “the SNES rotation mode,” which is memorable but incomplete. The picture is generated by mapping screen coordinates back into a background tilemap through a programmable affine transform. The hardware does not rotate a finished framebuffer, and the transform is not an arbitrary modern GPU shader. It is a set of fixed-point registers, tile data, offsets, flip and boundary controls, and scanline-time interactions with the PPU. A faithful emulator needs to model those inputs as state, not bake a single rotated image once per frame.

The PPU source code of Snes9x is useful as an executable implementation reference, while the SNES technical references describe the register interface. Emulator code is not a substitute for a hardware specification: it documents what that implementation does and may include compatibility behavior for known software. When a detail is uncertain, distinguish measured or documented register behavior from a renderer optimization.

The background is a source texture, not a rotated screen

In Mode 7, BG1 uses a 128-by-128 tile map whose 8-by-8 pixel tiles form a 1024-by-1024 texel space. The mode has a distinctive layout and color depth compared with ordinary SNES tile modes. For each visible screen coordinate, the PPU computes a location in that source map and fetches the corresponding texel. As the scanout moves one output pixel to the right, the transform advances by one matrix column; advancing a line uses the other column. This inverse mapping is why the visual result looks like rotating or scaling a plane.

The registers $211B through $211E provide matrix coefficients conventionally named A, B, C, and D. Each is represented as a signed fixed-point value with an 8-bit fractional part. In the simplest identity-like mapping, the horizontal increment maps one screen pixel to one source texel horizontally, and the vertical increment maps one screen line to one source texel vertically. Larger coefficient magnitudes zoom out in source space; smaller magnitudes enlarge the sampled region. Combining coefficients produces rotation and shear.

Do not confuse transform units with display scaling. A value that changes which source texel is sampled is not equivalent to changing the host window size. A modern shader that rotates the already rendered screen cannot reproduce Mode 7’s source-map boundary behavior, per-line register updates, PPU priority, or color math.

Centering and scrolling are separate operations

The center registers $211F and $2120 establish a pivot for the affine transform. The Mode 7 horizontal and vertical offset ports share the normal scroll-write mechanism but are used as the source-space offset terms. The effective mapping combines the output coordinate, scroll offset, center, and matrix, then adds the pivot back. Changing the center therefore changes where a rotation or scale is anchored; changing the offset translates the viewed region.

An implementation should keep the signed register values and the write-latch behavior separate from derived coordinates. Mode 7’s matrix and center values are assembled from byte writes through PPU ports. If an emulator stores only a precomputed floating-point matrix, it risks losing the exact sign-extension or high/low-byte semantics needed when a game updates one byte during active display.

The conceptual form is:

screen_relative = screen_position + mode7_scroll - mode7_center
source_position = matrix_8_8 * screen_relative + mode7_center
sample = fetch_mode7_texel(source_position)

This is a description, not code for the PPU’s full integer arithmetic. Real register width, signed interpretation, intermediate precision, wrap rules, and the timing at which writes take effect belong to the hardware model. A floating-point expression is excellent for explaining the geometry and insufficient for validating every pixel.

Boundary handling is part of the effect

The Mode 7 selection register $211A controls horizontal/vertical flip and behavior outside the tilemap boundary. Depending on configuration, out-of-range samples can become transparent, repeat the map, or use tile-zero behavior. These options create recognizable effects: a plane may wrap seamlessly, reveal transparency beyond its edge, or fill with a selected border source. Treating every source coordinate as modulo 1024 produces visible errors in scenes that depend on the other boundary modes.

The mode also has an extended-background capability. In the appropriate configuration, BG2 derives an additional priority/background contribution from Mode 7 map data rather than becoming a second independent affine plane. This is not simply “two Mode 7 layers.” A renderer that draws BG2 as another complete transformed copy can produce incorrect priority and color results. The precise interpretation should be checked against the PPU’s Mode 7 configuration and the selected color/priority path.

As with other SNES backgrounds, the final pixel is not merely the texel. Main/sub-screen designation, windows, object priority, color math, brightness, and forced blanking participate in the output. When investigating a missing road or horizon, first establish whether the sample coordinate is wrong, whether the fetched color is transparent, or whether another layer wins during composition.

Mosaic and line-by-line updates

The mosaic register $2106 chooses a block size and selects which background layers are affected. Mosaic changes the sampling granularity; it does not rewrite tile data. A renderer must preserve the relationship between the mosaic origin, current line, and sampled pixel. Recomputing a coarse result only from the final image can shift block boundaries when a game changes registers during a frame.

HDMA can update Mode 7 registers on a scanline schedule to create perspective floors, slopes, and warping. The transform may be constant in X and vary by Y, giving a sequence of affine mappings that approximates a perspective projection. This technique is still subject to PPU register-write timing: a table entry is not automatically applied at the mathematically ideal start of a line, and scroll/matrix writes have specific port semantics. The right test is to compare a trace of the register values at each line with the rendered source coordinates.

Use separate names for CPU writes, HDMA transfers, the PPU’s latched register state, and renderer snapshots. This helps locate errors such as a matrix update applied one line early, a stale center coordinate, or a mosaic value captured at frame start instead of at the relevant raster event.

Emulator implementation choices

There are at least three plausible renderer architectures:

  1. A line renderer computes all Mode 7 pixels from a snapshot of registers at line start.
  2. A raster-event renderer divides a line into spans when writes occur during active display.
  3. A dot-oriented renderer evaluates state at individual output positions.

Each approach has different speed and accuracy costs. A line renderer can be adequate when supported software writes only during known blanking intervals. It is not automatically correct for mid-line writes. A span renderer must define the exact pixel boundary affected by each register write. A dot renderer gives the clearest event model but may be too expensive without careful optimization. Snes9x’s PPU and graphics implementation illustrate how a mature emulator tracks Mode 7 state and related raster output; use it as a comparison, not as proof that every optimization applies to another core.

For fixed-point arithmetic, use sufficiently wide signed intermediates and add explicit tests for negative coordinates and overflow. Avoid relying on implementation-defined right shifts of negative signed integers in portable C or C++. Define the arithmetic shift/wrap behavior that the emulator intends to model. Test sign bits in matrix and center writes independently; bugs often look correct for the default positive identity matrix and fail only when a game rotates past a quadrant boundary.

A reproducible test matrix

For every supported PPU profile, test:

  • Identity mapping, then positive and negative horizontal/vertical scale.
  • Rotation around a nonzero center, followed by offset changes that translate without changing the pivot.
  • All outside-boundary modes, including negative source coordinates and values beyond the map on both axes.
  • Horizontal/vertical flip combinations and their interaction with boundary selection.
  • Mode 7 extended background and priority against sprites and another active layer.
  • Mosaic size changes, including a change during active display.
  • HDMA-driven per-line matrix or offset updates, with the update list and expected line numbers recorded.
  • Savestate capture while a partial line or raster event is pending, if the renderer supports such a state boundary.

Keep an unfiltered native-resolution capture for comparison. Integer scaling, CRT shaders, aspect correction, and host bilinear filtering can hide a one-pixel source-coordinate error. When hardware capture is not available, compare against multiple independent emulator implementations and label that result as cross-emulator evidence rather than physical-console verification.

Acceptance criteria

The Mode 7 subsystem is in good shape when the same register trace produces the same source-coordinate sequence across deterministic runs, all map-edge modes are independently tested, and per-line effects do not depend on the host refresh rate. A renderer may use floating point internally if it proves pixel-compatible for the tested behavior, but fixed-point register semantics and PPU event order must remain explicit at its boundary.

Mode 7’s enduring lesson is architectural: the effect belongs to the hardware’s address-generation pipeline. It is not a post-processing filter. Treat the map, matrix, pivot, boundary selector, mosaic, and raster schedule as a coherent PPU feature, and the familiar racing-game horizon becomes a predictable data path rather than a collection of visual hacks.

Related:

Sources:

Comments