Check for repeated zx/zy values

These will never escape, so saves
some time in the lake

trick is taken from fractint
This commit is contained in:
Brooke Vibber 2023-02-12 11:37:52 -08:00
parent 839330edb3
commit 0501a364c7

116
mandel.s
View file

@ -21,12 +21,16 @@ count_pixels = $a3 ; u8
total_ms = $a4 ; float48 total_ms = $a4 ; float48
total_pixels = $aa ; float48 total_pixels = $aa ; float48
temp = $b0 ; u16 z_buffer_active = $b0 ; boolean: 1 if we triggered the lake, 0 if not
pixel_ptr = $b2 ; u16 z_buffer_start = $b1 ; u8: index into z_buffer
pixel_color = $b4 ; u8 z_buffer_end = $b2 ; u8: index into z_buffer
pixel_mask = $b5 ; u8 temp = $b4 ; u16
pixel_shift = $b6 ; u8
pixel_offset = $b7 ; u8 pixel_ptr = $b6 ; u16
pixel_color = $b8 ; u8
pixel_mask = $b9 ; u8
pixel_shift = $ba ; u8
pixel_offset = $bb ; u8
; FP registers in zero page ; FP registers in zero page
@ -186,6 +190,15 @@ color_map:
.code .code
z_buffer_len = 16
z_buffer_mask = z_buffer_len - 1
z_buffer:
; the last N zx/zy values
.repeat z_buffer_len
.word 0
.word 0
.endrepeat
.export start .export start
; 2 + 9 * byte cycles ; 2 + 9 * byte cycles
@ -462,12 +475,14 @@ initloop:
sta zx - 1,x sta zx - 1,x
dex dex
bne initloop bne initloop
sta z_buffer_start
sta z_buffer_len
loop: loop:
; iter++ & max-iters break ; iter++ & max-iters break
inc iter inc iter
bne keep_going bne keep_going
rts jmp exit_path
keep_going: keep_going:
.macro quick_exit arg, max .macro quick_exit arg, max
@ -484,7 +499,7 @@ keep_going:
positive: positive:
cmp #((max) << 4) cmp #((max) << 4)
bmi all_done ; 'less than' bmi all_done ; 'less than'
rts jmp exit_path
negative: negative:
cmp #(256 - ((max) << 4)) cmp #(256 - ((max) << 4))
@ -492,7 +507,7 @@ keep_going:
bpl all_done ; 'greater than' bpl all_done ; 'greater than'
nope_out: nope_out:
rts jmp exit_path
first_equal: first_equal:
lda arg lda arg
@ -527,9 +542,90 @@ keep_going:
; if may be in the lake, look for looping output with a small buffer ; if may be in the lake, look for looping output with a small buffer
; as an optimization vs running to max iters ; as an optimization vs running to max iters
lda z_buffer_active
beq skip_z_buffer
ldx z_buffer_start
cpx z_buffer_end
beq z_nothing_to_read
z_buffer_loop:
.macro z_compare arg
.local compare_no_match
lda z_buffer,x
inx
cmp arg
bne compare_no_match
iny
compare_no_match:
.endmacro
.macro z_advance
.local skip_reset_x
cpx #(z_buffer_len * 4)
bmi skip_reset_x
ldx #0
skip_reset_x:
.endmacro
.macro z_store arg
lda arg
sta z_buffer,x
inx
.endmacro
; Compare the previously stored z values
ldy #0
z_compare zx
z_compare zx + 1
z_compare zy
z_compare zy + 1
cpy #4
bne z_no_matches
jmp z_exit
z_no_matches:
z_advance
cpx z_buffer_end
bne z_buffer_loop
z_nothing_to_read:
; Store and expand
z_store zx
z_store zx + 1
z_store zy
z_store zy + 1
z_advance
stx z_buffer_end
; Increment the start roller if necessary (limit size)
lda iter
cmp #(z_buffer_len * 4)
bmi skip_inc_start
lda z_buffer_start
clc
adc #4
tax
z_advance
stx z_buffer_start
skip_inc_start:
skip_z_buffer:
jmp loop jmp loop
peace_out: z_exit:
lda #0
sta iter
exit_path:
ldx #0
lda iter
bne next
inx
next:
stx z_buffer_active
rts rts
.endproc .endproc