mirror of
https://github.com/Pecusx/libretro-atari800.git
synced 2026-05-20 22:33:22 +02:00
111 lines
4.0 KiB
Plaintext
111 lines
4.0 KiB
Plaintext
DIRTY SPANS TECHNIQUE
|
|
|
|
Please note: this is just an idea.
|
|
|
|
I'll explain it in pseudo-code:
|
|
|
|
/* in antic.c: */
|
|
|
|
int dirty_left[ATARI_HEIGHT];
|
|
int dirty_right[ATARI_HEIGHT];
|
|
|
|
static void draw_antic_*()
|
|
{
|
|
int x;
|
|
for (x = left_margin; x < right_margin; x++) {
|
|
UBYTE new_pixel = generate_pixel(x);
|
|
if (new_pixel != scrn_ptr[x]) {
|
|
dirty_left[ypos - 8] = x;
|
|
x = right_margin;
|
|
do {
|
|
x--;
|
|
new_pixel = generate_pixel(x);
|
|
} while (new_pixel == scrn_ptr[x]);
|
|
dirty_right[ypos - 8] = x + 1;
|
|
for (x = dirty_left[ypos - 8]; x < dirty_right[ypos - 8]; x++) {
|
|
scrn_ptr[x] = generate_pixel(x);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
/* no pixels changed in this line */
|
|
dirty_left[ypos - 8] = dirty_right[ypos - 8] = 0;
|
|
}
|
|
|
|
/* Note: (ypos - 8) is because ypos ranges from 8 to 247
|
|
for the visible scanlines */
|
|
|
|
|
|
/* port-specific Atari_DisplayScreen(): */
|
|
|
|
void Atari_DisplayScreen(UBYTE *screen)
|
|
{
|
|
int y;
|
|
for (y = 0; y < ATARI_HEIGHT; y++) {
|
|
/* copy pixels dirty_left[y] <= x < dirty_right[y]
|
|
from screen[] to the real screen */
|
|
blit_pixels(screen, dirty_left[y], dirty_right[y], y);
|
|
}
|
|
}
|
|
|
|
Now some less formal explanation:
|
|
|
|
The idea is to update only parts of scanlines that changed since last frame.
|
|
We update one continuous sequence of pixels ("span") per scanline.
|
|
dirty_left[y] and dirty_right[y] are the boundaries of the span in scanline y.
|
|
In each scanline, we search for a first pixel that is different
|
|
from the previous frame. If we don't find one, then the whole scanline
|
|
is not dirty, which we mark with:
|
|
dirty_left[y] = dirty_right[y] = 0;
|
|
If we find left-most pixel that differs from the previous frame,
|
|
we save its x coordinate in dirty_left[y]. Then we search starting
|
|
from the right side for a pixel that changed since last frame. We know we'll
|
|
find one. We save (x + 1) in dirty_right[y]. Now we normally generate pixels
|
|
between dirty_left[y] and dirty_right[y].
|
|
|
|
The display routine doesn't need any additional comments, I think.
|
|
|
|
Compared to the current approach (always display whole Atari screen),
|
|
the DIRTY SPANS technique adds almost zero overhead in the worst case.
|
|
In the best case we avoid screen updates completely.
|
|
On average, we update just the areas that changed.
|
|
|
|
There's one case when DIRTY SPANS perform worse than DIRTY RECT:
|
|
if left and right sides of screen are changing while the center of screen
|
|
remains static. This is however extremely rare (actually, I cannot recall
|
|
any real Atari program that does such things).
|
|
|
|
Compared to DIRTY RECT, DIRTY SPANS has nearly zero overhead in ANTIC code:
|
|
while searching for boundaries there are comparisons but no writes
|
|
to the screen; generating the changed part of the scanlines operates
|
|
as fast as without DIRTY techniques.
|
|
|
|
Displaying pixels is much faster: we immediately know which pixels to update,
|
|
without stepping through 8K screen_dirty[]. It is also better for hardware
|
|
architectures where continuous writes to the video memory are faster
|
|
then random writes.
|
|
|
|
It is possible to combine DIRTY SPANS with DIRTY RECT: in the first pass,
|
|
find span boundaries using DIRTY SPANS. Then, in the display loop,
|
|
update only the pixels that changed (compare current pixels to a backup copy
|
|
of the screen).
|
|
|
|
DIRTY SPANS should be straightforward to implement on most platforms:
|
|
all we need is displaying 1-pixel-high bitmaps.
|
|
|
|
The ANTIC code is what gets more complicated with DIRTY SPANS.
|
|
Basically, we have to split each function that generates an Atari graphics
|
|
mode into 3 parts:
|
|
1. Find dirty_left (similar to normal code, but compare instead of write
|
|
pixels).
|
|
2. Find dirty_right (likewise, but *right-to-left*; it should be possible
|
|
to implement it without a speed penalty).
|
|
3. Write pixels (same as the current code).
|
|
This probably means more and more macros (antic.c is already full of them).
|
|
|
|
As noted at the beginning of this document, these are all plans
|
|
for the future.
|
|
|
|
Piotr Fusik
|
|
2005-09-09
|