Skip to content

Update vga.js - #1622

Merged
copy merged 2 commits into
copy:masterfrom
Godlance:master
Aug 31, 2026
Merged

Update vga.js#1622
copy merged 2 commits into
copy:masterfrom
Godlance:master

Conversation

@Godlance

@Godlance Godlance commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

fix: prevent image freezes caused by svga_offset

This PR fixes a screen freeze in some svga dependant games.

The SVGA 8bpp fast path in screen_fill_buffer ignores svga_offset, causing permanent display freezes with page-flipped double buffering.

VGAScreen.prototype.screen_fill_buffer's fast path for 8bpp SVGA modes reads the displayed frame starting at byte 0 of svga_memory always, which ignores svga_offset that port1CF_write sets from VBE_DISPI_INDEX_X_OFFSET/VBE_DISPI_INDEX_Y_OFFSET.

This is the standard VBE "Set Display Start" call that real VESA-aware software uses for page-flipped double buffering, it renders the next frame into a back buffer elsewhere in svga_memory and then flips the display-start offset to it instead of copying pixels.

Since this fast path always paints from offset 0, any program that flips the display start away from 0 gets a display that silently freezes on whatever was last drawn at offset 0 while the program keeps rendering correctly into the buffer v86 no longer looks at.

2026-08-21_11-23_1

Given that there is no error, it was really hard to debug from my side.

The existing code already has a comment to this fact:

// XXX: Slow, should be ported to rust, but it doesn't have access to vga256_palette
// XXX: Doesn't take svga_offset into account

This PR fixes the second XXX.

I've tested it with Master of Orion 2 and display freeze is fully resolved.

2026-08-21_11-19

This will help any 90s era game that uses page flipping.

Edit: Formatting.

fix: prevent image freezes caused by svga_offset
@copy

copy commented Aug 27, 2026

Copy link
Copy Markdown
Owner

From your description, it's not clear to me that this game actually uses the wraparound behavior. I have pushed an alternative fix that clamps instead (like the other bpps). Could you test that this fixed the issue?

@Godlance

Godlance commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

From your description, it's not clear to me that this game actually uses the wraparound behavior. I have pushed an alternative fix that clamps instead (like the other bpps). Could you test that this fixed the issue?

Yeah, sorry for taking so long.

I just tested the latest release (132da7b) and it still has the same problem. So, either MoO2 is doing something different altogether or the fix is breaking something else.

If I manage to find more games or other software of another kind that shows a similar behavior, we could find out what's going on. For now, I'll maintain the fix in my setup.

Edit: If I could find a MoO2 demo, I could also put up a website for you to test this behavior, but it seems I can only find full game releases.

I was using a release version of libv86.js instead of compiling one with your changes, sorry. After compiling and testing I can assure that your fix works just as well, thank you!

@copy
copy merged commit 180830d into copy:master Aug 31, 2026
3 checks passed
@copy

copy commented Aug 31, 2026

Copy link
Copy Markdown
Owner

Thanks for diagnosing the issue and testing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants