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 |