Add a draw sprint feature for reducing flicker

This commit is contained in:
Juhani Krekelä 2018-09-23 12:03:07 +03:00
parent f8de8aa2cf
commit 5504050d56
2 changed files with 68 additions and 5 deletions

View File

@ -34,11 +34,33 @@ Emulation speed
---------------
Instructions are run 500 times a second
Draw sprint
-----------
To reduce sprite flicker, sipsi-8 can run upto two ticks' worth of cycles
after a draw call. This is since chip-8 often does drawing in pairs, where
the first in the pair erases the old sprite and the next one draws it back.
If they happen on different frames, this results in very back flickering.
To avoid an issue of pairing one sprite's draw to other's erase, a sprint
is invalidated if it hits a jump, call, or a return.
Games improved by draw sprint:
* Brix and its descendants
* UFO
Games unaffected by draw sprint:
* Pong and Pong2 (Draws are too far from each other)
* Tetris (Does jumps inbetween)
* Blitz (Does jumps inbetween. If invalidation upon jump is disabled, ends
up pairing wrong draw calls)
Issues
------
* Player sprites tend to flicker. (See e.g. BRIX) Why? Also, this seems to
happen in the haxe-chip-8-emulator too, and lowering the FPS doesn't seem
to help, which suggests something fishy with the programs
* Keyboard can't be changed
* FPS can't be changed
* Interpreter speed can't be changed
* Window size can't be changed
* No error handing on opening a file
Requirements
------------

View File

@ -79,9 +79,14 @@ def step():
global delay_timer, sound_timer
global keys_pressed, waiting_for_keypress, keypress_arrived
# Keep track of whether we did a draw or a jump, for the draw
# sprint feature
did_draw = False
did_jump = False
# Don't execute any code in a waitstate, as it'd only end up
# busylooping
if waiting_for_keypress and not keypress_arrived: return
if waiting_for_keypress and not keypress_arrived: return did_draw, did_jump
high_byte = ram[ip]
ip = (ip + 1) & 0xfff
@ -100,6 +105,7 @@ def step():
# 00EE ret
elif high_byte == 0x00 and low_byte == 0xEE:
ip = stack.pop()
did_jump = True
# 0nnn call_machine
elif high_byte >> 4 == 0:
@ -109,11 +115,13 @@ def step():
# 1nnn jmp nnn
elif high_byte >> 4 == 1:
ip = ((high_byte & 0xf) << 8) | low_byte
did_jump = True
# 2nnn call nnn
elif high_byte >> 4 == 2:
stack.append(ip)
ip = ((high_byte & 0xf) << 8) | low_byte
did_jump = True
# 3xnn skipeq vx, nn
elif high_byte >> 4 == 3:
@ -216,6 +224,7 @@ def step():
elif high_byte >> 4 == 0xB:
ip = ((high_byte & 0xf) << 8) | low_byte
ip = (ip + data_registers[0]) & 0xfff
did_jump = True
# Cxnn maskedrandom vx, nn
elif high_byte >> 4 == 0xC:
@ -242,6 +251,8 @@ def step():
# have yet to find any games that break with it, I'm just
# skipping pixels that fall outside the screen.
did_draw = True
x_start = data_registers[high_byte & 0xf]
y_start = data_registers[low_byte >> 4]
@ -362,6 +373,8 @@ def step():
else:
print('%03x: Unrecognized!' % (ip-2))
return did_draw, did_jump
def tick_timers():
global delay_timer, sound_timer
@ -391,9 +404,37 @@ def advance_interpreter(dt):
tick_timers()
while cpu_cycles_to_go >= 1:
step()
did_draw, _ = step()
cpu_cycles_to_go -= 1
# If we did a draw, run upto two ticks' cycles to reach
# the next draw. Chip-8 draws are often paired, an erase
# and a draw. If we don't hit both in the same frame, it
# will cause flicker.
# Since this will put the number of cycles to go below zero
# if we run out of our own cycles, on average we will run
# the right number of cycles per tick
# Also, to avoid pairing draw half of one pair and erase
# half of another, the sprint is invalidated by a jump, a
# call or a ret
if did_draw:
#sprint_run_out = True#debg
for cycle in range(2*cpu_clock // 60):
did_draw, did_jump = step()
cpu_cycles_to_go -= 1
# Exit as soon as we hit the other draw
if did_draw:
#sprint_run_out = False#debg
#print('Sprint succeeded! %i' % cycle)#debg
break
if did_jump:
#sprint_run_out = False#debg
#print('Sprint failed! (jump) %i' % cycle)#debg
break
#if sprint_run_out: print('Sprint failed! (ran out)')#debg
if frames_to_go >= 1:
# Only draw the latest frame. This means FPS >60 won't work
# but why would you ever want to run chip-8 faster than