OXYGENHUB

video: keep the bitmap layer's settings in registers across the line 39d98c9da02a

render_layer_line_bitmap() writes layer_line[] a byte at a time, and C
lets a byte store alias anything, so the compiler had to load every
field of the layer's properties, and reg_layer's palette offset, again
for every pixel through the pointer into the global array. It also
worked out x % tilew, a division by a run-time value, for every pixel.
It now works from a local copy of the properties (whose address does
not escape, so no store can touch it), reads the palette offset once,
and counts x % tilew up and wraps it. The values are the same.

The busy workload (BASIC drawing LINEs on the 320x240 bitmap layer)
spent about 41% of narvi's run time rendering. Measured with the
emulator stepping 600 frames, real-time mode, SDL dummy drivers, CPU
seconds per emulated second; both builds aligned the same way
(-falign-functions=64 -falign-loops=16 -falign-jumps=16), because
without that this change moved unrelated hot code and swung the idle
figure by 7% on this core on its own:

    narvi  busy  1.794 -> 1.737  (56% -> 58% of a real X16)
    narvi  idle  2.012 -> 2.022  (unchanged; no bitmap layer there)
    x86    busy  0.530 -> 0.422  (median of 3)

The determinism check matches on x86 and riscv64.
Author
Andy McCall @andymccall <[email protected]>
via
agent agent:claude@andymccall <[email protected]> · keyless, under your grant for changes,refs,seal · key 7f1108192b02
When
· 2026-10-21 02:23 UTC
Signature
◈ sealed by agent:claude@andymccall
Hash
39d98c9da02ad9fc397ccdc29d897c2337c04d23457efd8b673305c75274a15b
Depends on
03a3459e6372
Depended on by
35bd422c9032
In bookmarks
main riscv-1
Edits
4 atoms, 0 tree operations, 1 file

Browse the tree at this change

modified src/video.c +11 −7
…
971 unchanged lines
972 972
static void
973 973
render_layer_line_bitmap(uint8_t layer, uint16_t y)
974 974
{
975 -
	const struct video_layer_properties *props = &prev_layer_properties[1][layer];
975 +
	// A copy, not a pointer: layer_line[] is written a byte at a time, and a
976 +
	// byte store may alias anything, so through a pointer into the global
977 +
	// array every field would be loaded again for every pixel.
978 +
	const struct video_layer_properties props_copy = prev_layer_properties[1][layer];
979 +
	const struct video_layer_properties *props = &props_copy;
976 980
//	const struct video_layer_properties *props0 = &prev_layer_properties[0][layer];
977 981
978 982
	int yy = y % props->tileh;
979 983
	// additional bytes to reach the correct line of the tile
980 984
	uint32_t y_add = (yy * props->tilew * props->bits_per_pixel) >> 3;
985 +
986 +
	// extract all information from the map
987 +
	const uint8_t palette_offset = reg_layer[layer][4] & 0xf;
981 988
982 989
	// Render tile line.
983 -
	for (int x = 0; x < SCREEN_WIDTH; x++) {
984 -
		int xx = x % props->tilew;
985 -
986 -
		// extract all information from the map
987 -
		uint8_t palette_offset = reg_layer[layer][4] & 0xf;
988 -
990 +
	// xx is x % tilew, counted up and wrapped rather than divided per pixel.
991 +
	int xx = 0;
992 +
	for (int x = 0; x < SCREEN_WIDTH; x++, xx = xx + 1 == props->tilew ? 0 : xx + 1) {
989 993
		// additional bytes to reach the correct column of the tile
990 994
		uint16_t x_add = (xx * props->bits_per_pixel) >> 3;
991 995
		uint32_t tile_offset = y_add + x_add;
…
1466 unchanged lines