mirror of
https://github.com/imjasonh/nescript
synced 2026-07-08 08:55:38 +00:00
Codegen: skip OAM clear loop in handlers that don't draw
The OAM clear at frame-handler entry is only needed if the handler actually modifies OAM — handlers that never call \`draw\` don't need to reset the shadow buffer at all, since the previous handler's contents are still correct (or the startup zero-fill still applies). Adds a \`function_draws_sprites\` helper that walks the IR ops once and emits the clear loop only when at least one \`DrawSprite\` exists. Handlers like a title screen that doesn't render sprites pay zero cycles for the OAM clear now. https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
This commit is contained in:
parent
28cb739840
commit
629e596ec7
1 changed files with 19 additions and 6 deletions
|
|
@ -356,12 +356,15 @@ impl<'a> IrCodeGen<'a> {
|
|||
|
||||
self.emit_label(&format!("__ir_fn_{}", func.name));
|
||||
|
||||
// At the start of every frame handler, clear the OAM shadow
|
||||
// buffer so stale sprites from the previous frame (or from a
|
||||
// different state's handler) don't linger on screen. We set
|
||||
// the Y position byte of every OAM entry to $FE (off-screen).
|
||||
// The actual drawing code overwrites the slots it needs.
|
||||
if self.in_frame_handler {
|
||||
// At the start of a frame handler that actually draws
|
||||
// sprites, clear the OAM shadow buffer so stale sprites from
|
||||
// the previous frame (or from a different state's handler)
|
||||
// don't linger on screen. We set the Y position byte of every
|
||||
// OAM entry to $FE (off-screen) and the `draw` code
|
||||
// overwrites the slots it needs. Handlers that never call
|
||||
// `draw` skip the clear entirely — the NMI handler's DMA
|
||||
// copies whatever's in $0200 unchanged.
|
||||
if self.in_frame_handler && function_draws_sprites(func) {
|
||||
let clear_loop = format!("__ir_oam_clear_{}", func.name);
|
||||
self.emit(LDX, AM::Immediate(0));
|
||||
self.emit(LDA, AM::Immediate(0xFE));
|
||||
|
|
@ -800,6 +803,16 @@ fn substitute_asm_vars<F: Fn(&str) -> Option<u16>>(body: &str, resolver: F) -> S
|
|||
out
|
||||
}
|
||||
|
||||
/// True if the given IR function contains at least one
|
||||
/// `DrawSprite` op. Used by the frame-handler OAM clear to skip
|
||||
/// the clear loop when a handler doesn't actually draw anything.
|
||||
fn function_draws_sprites(func: &IrFunction) -> bool {
|
||||
func.blocks
|
||||
.iter()
|
||||
.flat_map(|b| &b.ops)
|
||||
.any(|op| matches!(op, IrOp::DrawSprite { .. }))
|
||||
}
|
||||
|
||||
/// Scan the IR functions for all scanline handlers (named
|
||||
/// `{state}_scanline_{line}`) and return them in IR function order.
|
||||
fn collect_scanline_handlers(ir: &IrProgram) -> Vec<(String, u8)> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue