Skip to content

Repository files navigation

P96CTS -- P96 driver Conformance Test Suite

P96CTS

Validates the rendering primitives of P96 RTG card drivers as well as the graphics.library accelerated rendering routines.

Each testcase renders a scene and compares it pixel by pixel against a golden reference which was generated by P96's software rasterizer.

Runs are non-interactive and the exit code reflects the result, so the suite works as an automated check -- including under an emulator with no display.

It also runs on AROS, on which it falls back to cybergraphics.library and graphics.library instead of Picasso96API.library.

Running

Run all tests for a particular monitor and video mode (WxHxD):

p96cts Z3660 640x480x8

Output looks like:

p96cts 0.12 (30.7.2026) by Bernie Innocenti
testing Z3660 640x480x8 clut, scene 320x200
PASS DrawLine-solid
PASS DrawLine-pattern
FAIL DrawLine-complement      4 of 64000 pixels differ
       at 247, 72 golden  89, got 166
       at  73,128 golden 202, got  53
       ... and 2 more
       captured output/Z3660/320x200x8/DrawLine-complement.fail.png
       wrote difference to output/Z3660/320x200x8/DrawLine-complement.diff.png

A palette run also works on native AGA screens, whose bitmaps are planar rather than chunky, which puts graphics.library's own rendering up against the same reference:

p96cts PAL 320x256x8

Reference images live in golden/WxHxD/. A failing test writes two images to output/<monitor>/WxHxD/:

  • <test>.fail.png, what the run actually rendered, and
  • <test>.diff.png, the differing pixels in red over the golden dimmed to gray.

To generate all golden images for a particular scene size and depth, run:

p96cts softrast 320x200x8 CAPTURE

Arguments

MONITOR and MODE are positional and both required for a run, so the usual invocation is p96cts <monitor> <WxHxD>.

Argument Meaning
MONITOR Board to render on; softrast for the software rasterizer
MODE Screen mode as WxHxD
TEST/K One testcase as <group>-<test>; all of them by default
CAPTURE/S Write the reference instead of comparing against it
SCENE/K Region rendered and compared, as WxH (default 320x200)
GOLDENDIR/K Reference directory (default golden/<scene>x<depth>)
OUTDIR/K Output directory (default output/<monitor>/<scene>x<depth>)
THRESHOLD/K/N Tolerate up to this many differing pixels
LISTMODES/S Dump the display database and exit
LISTTESTS/S List the testcase names TEST accepts and exit
HELP/S Print this table and exit; -h and --help work too

Test Results

The tables below are from emulators. If you have access to an Amiga with an RTG board, please run the suite and open an issue to share your results.

Amiberry

scene PAL uaegfx CyberVision ZZ9000
DrawLine-solid
DrawLine-pattern
DrawLine-jam2
DrawLine-inversvid
DrawLine-complement
RectFill-drawmodes
RectFill-edges
RectFill-invert
ClipBlit-overlap
ClipBlit-disjoint
BltTemplate-offsets
BltTemplate-sizes
BltTemplate-drawmodes
BltTemplate-masks
BltPattern-drawmodes
BltPattern-mask
BltPattern-phase
BltBitMap-minterms
BltBitMap-offsets
BltBitMap-sizes
BltBitMap-planemask
BltBitMap-stencil
BltBitMap-shallow
ScrollRaster-directions
ScrollRaster-drawmodes
ScrollRaster-backfill - - - -
ScrollRaster-amounts

A ❌ links to the bug it found. A - is untested.

Notes:

  • uaegfx drops the source plane mask in BlitPlanar2Direct, so BltBitMap-planemask fails at 24 bits and passes at 8 (amiberry#2235). Fixed in WinUAE, so the column turns green once Amiberry picks that up.

Copperline

scene PAL Z3660
DrawLine-solid
DrawLine-pattern
DrawLine-jam2
DrawLine-inversvid
DrawLine-complement
RectFill-drawmodes
RectFill-edges
RectFill-invert
ClipBlit-overlap
ClipBlit-disjoint
BltTemplate-offsets
BltTemplate-sizes
BltTemplate-drawmodes
BltTemplate-masks
BltPattern-drawmodes
BltPattern-mask
BltPattern-phase
BltBitMap-minterms
BltBitMap-offsets
BltBitMap-sizes
BltBitMap-planemask
BltBitMap-stencil
BltBitMap-shallow
ScrollRaster-directions
ScrollRaster-drawmodes
ScrollRaster-backfill
ScrollRaster-amounts

Notes:

  • The Z3660 column needs a Z3660.card built from git: it depends on Z3660#18 and Z3660#19, merged after the last release.
  • Z3660#19 leaves COMPLEMENT lines to Picasso96, as the ZZ9000 driver already does. struct Line carries no FRST_DOT, so an accelerated COMPLEMENT line cannot tell a fresh Draw() from one continuing at a vertex, and inverting a shared vertex twice restores it.
  • Z3660#18 uploads the one template line a patterned blit reads. P96 sends the JAM2 | COMPLEMENT tiles as a template blit whose Template->BytesPerRow is 0, so sizing the upload as BytesPerRow * h copies nothing and leaves the board to blit whatever the previous operation left in the template buffer. Why P96 passes a zero stride here is unexplained.

Coverage

What each group reaches. The P96 hook is what a card driver has to get right; a Default implementation in P96's shared code stands in for any hook a driver leaves out, so a missing hook still renders.

group graphics.library P96 hook
DrawLine Move(), Draw() DrawLine
RectFill RectFill() FillRect, InvertRect
ClipBlit ClipBlit() BlitRect
BltTemplate BltTemplate() BlitTemplate
BltPattern BltPattern() BlitPattern
BltBitMap BltBitMap(), BltMaskBitMapRastPort() BlitRectNoMaskComplete
ScrollRaster ScrollRaster(), ScrollRasterBF() BlitRect, FillRect

BltBitMap also reaches BlitPlanar2Chunky and BlitPlanar2Direct, which nothing else here does: a planar source bitmap goes through the first on a CLUT screen and the second on a truecolor one.

Hooks with no coverage: WriteYUVRect, ScrollPlanar, UpdatePlanar. AROS calls none of them (see the TODO in p96gfx_rtg.h), so scenes for these would only exercise AmigaOS.

TODO

  • EraseRect(): its no-layer path fills through RectFill(); no font state to set up.
  • Text(): renders through BlitTemplate; wants a write-mask sweep.
  • ClearEOL(), ClearScreen(): clear to pen 0, or BPen in JAM2. A golden pins one font's metrics.
  • SetRast(), Flood(), AreaEnd(), DrawCircle(), DrawEllipse(): uncovered.
  • WritePixelArray() / ReadPixelArray() family: uncovered.
  • BltMaskBitMapRastPort(): reached only incidentally, via BltBitMap-stencil.
  • BltBitMapRastPort(): uncovered.
  • A caller-level group needs a font with identical metrics under AmigaOS and AROS.

Building

The default include path is where the amiga-gcc toolchain ships the P96 headers, so a containerised build takes no arguments:

make docker-build

With a toolchain that does not bundle them, point at an unpacked P96Develop.lha:

make CC=/path/to/bin/m68k-amigaos-gcc \
     P96INC=/path/to/Picasso96Develop/Include

Images are read and written with zlib and libpng, which are committed under third_party/ already built for this target, so nothing needs fetching or cross-building first. They rarely need rebuilding, but when they do, the same container runs their build script:

make docker-thirdparty

The archives are reproducible, so a rebuild can be checked byte for byte against the committed ones. third_party/README.md has the upstream versions, checksums, and why both are built -noixemul.

Adding testcases

A testcase renders a complete scene, clearing it first, and must keep all drawing inside the bitmap: the RastPort has no Layer, so graphics.library does not clip it and drawing outside corrupts memory.

Scenes should be built so that a wrong driver cannot pass by accident. Drawing solid lines in one pen, for instance, cannot detect a pixel written twice -- it takes a mode like COMPLEMENT, where writing twice is not the same as writing once, and a figure whose lines actually cross.

About

P96CTS -- Conformance Test Suite for Amiga P96 card drivers

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages