Skip to content

Port BlastEm as a Waterbox core#4744

Closed
mr-ke wants to merge 4 commits into
TASEmulators:masterfrom
mr-ke:feature/blastem
Closed

Port BlastEm as a Waterbox core#4744
mr-ke wants to merge 4 commits into
TASEmulators:masterfrom
mr-ke:feature/blastem

Conversation

@mr-ke
Copy link
Copy Markdown

@mr-ke mr-ke commented May 23, 2026

dev build for branch | mr-ke:blastem

Summary

This PR adds BlastEm new core, to BizHawk (together with Genesis-Plus-GX and picodrive (quite old) )

Changes

New Core: BlastEm

  • Added waterbox/blastem/ directory containing the BlastEm core source code
  • Created bizhawk.c with Waterbox integration layer including:
    • Proper audio initialization order to prevent sound cracking
    • Input handling via FrameAdvancePrep
  • Updated waterbox/make-all-cores.sh to include BlastEm in build process

C# Integration

  • src/BizHawk.Emulation.Cores/Consoles/Sega/BlastEM/BlastEM.cs - Main core implementation
  • src/BizHawk.Emulation.Cores/Consoles/Sega/BlastEM/LibBlastEM.cs - Native interop definitions
  • Core registered in CoreNames.cs and Config.cs for Genesis system

Testing

  • Tested with Genesis Test ROM Titan_Overdrive2

Check if completed:

@vadosnaprimer
Copy link
Copy Markdown
Contributor

Amazing job! Tho I'd recommend turning the core itself (the part that got forked) into a submodule. Makes future maintenance much easier. Recently ported cores like UAE and Dosbox-x are good examples.

@CasualPokePlayer
Copy link
Copy Markdown
Member

CasualPokePlayer commented May 23, 2026

The lack of the submodule means it's hard to know what you exactly changed against upstream here for this integration (and how invasive this integration is). Even putting the raw core as the initial commit then adding integration would be much better here.

Immediately I see a change in emulibc which seems wrong on its face and I have no idea why it would ever be needed besides changing upstream to use wbx alloc_* functions which is wholly unneeded (which again means not seeing what got changed).

This integration also doesn't appear to solve one of the main issue I had when I did my initial integration long ago, in that the core's config system is not integrated (granted, I'm not entirely sure how much of a loss this, but this is relevant for the next point...)

Another reason I dropped blastem integration is I questioned the point of a BlastEm core. GPGX is already a highly accurate core and highly performative, and nowadays that is further true with it being up to date with upstream (and easily updatable given best practices were used wrt modifications in the port). Even then it comes to game compatibility, GPGX seemingly trumps BlastEm (and for the right reasons). What does BlastEm offer that GPGX doesn't (and please do not answer "cycle accuracy" as that itself is a buzzword and meaningless overall, if accuracy is a reason then it should be something more concrete like being better for console verification? better compatibility for some games?)

@mr-ke
Copy link
Copy Markdown
Author

mr-ke commented May 23, 2026

The lack of the submodule means it's hard to know what you exactly changed against upstream here for this integration (and how invasive this integration is). Even putting the raw core as the initial commit then adding integration would be much better here.

Immediately I see a change in emulibc which seems wrong on its face and I have no idea why it would ever be needed besides changing upstream to use wbx alloc_* functions which is wholly unneeded (which again means not seeing what got changed).

This integration also doesn't appear to solve the main issue I had when I did my initial integration long ago, in that the core's config system is not integrated (granted, I'm not entirely sure how much of a loss this, but this is relevant for another point...)

Another reason I dropped blastem integration is I questioned the point of a BlastEm core. GPGX is already a highly accurate core and highly performative, and nowadays that is further true with it being up to date with upstream (and easily updatable given best practices were used wrt modifications in the port). Even then it comes to game compatibility, GPGX seemingly trumps BlastEm (and for the right reasons). What does BlastEm offer that GPGX doesn't (and please do not answer "cycle accuracy" as that itself is a buzzword and meaningless overall, if accuracy is a reason then it should be something more concrete like being better for console verification?)

Glad to hear the honest opinion on this new genesis core, the intention I push this PR come from a observation of #4739 and I remebered I've done some work half year before so I share the work here to see if anyone are intrested. I've not had compared BlastEM and Genesis-Plus-GX as I am also aware that Genesis-Plus-GX is the preferred core for genesis so that I also do not intend to change, in the meanwhile this blastem is even after picodrive for genesis prioritization and just intend to provide extra option.
But I personally very like blastEM not only as they claim that they are very cycle precise, also it is the core can run through Titan_Overdrive2 without any obvious visual defects, in the meabwhile I am not blame Genesis-Plus-GX, but seems Genesis-Plus-GX used in bizhawk will have some flaw as example below but blastEM seems without problem and can run through it.

@CasualPokePlayer
Copy link
Copy Markdown
Member

CasualPokePlayer commented May 23, 2026

I should say "don't answer with cycle accuracy or 1 particular demoscene tech ROM that relies on undocumented behavior". That tech demo is not reason itself to add an entire new core. It's only "wrong" due it relying on undocumented behavior no actual game would use. It would be fixed in GPGX at some point potentially (maybe under some config given it has severe performance penalties) but it's at very very very low priority (see ekeeke/Genesis-Plus-GX#220)

@mr-ke
Copy link
Copy Markdown
Author

mr-ke commented May 23, 2026

@CasualPokePlayer
I just would like to hear your opinion straightful that if the further efforts for integration is worth to do, if it is not, then I will close this PR.

@CasualPokePlayer
Copy link
Copy Markdown
Member

I would personally not think it's worth it to actually integrate BlastEm, but if other devs think it's worth it I wouldn't block it.

@mr-ke
Copy link
Copy Markdown
Author

mr-ke commented May 23, 2026

I would personally not think it's worth it to actually integrate BlastEm, but if other devs think it's worth it I wouldn't block it.

Thank you for your honesty... It is also okey I keep it private to use in Bizhawk.

@mr-ke mr-ke closed this May 23, 2026
@YoshiRulz
Copy link
Copy Markdown
Member

It's not clear how you would even set up a submodule, since BlastEm uses Mercurial, not Git. This rando's mirror is the only one on GitHub that's up-to-date.

@YoshiRulz YoshiRulz changed the title Feature/blastem Port BlastEm as a Waterbox core May 23, 2026
@YoshiRulz YoshiRulz added the Core: Future core Core doesn't exist yet or is an early WIP label May 23, 2026
@CasualPokePlayer
Copy link
Copy Markdown
Member

CasualPokePlayer commented May 23, 2026

It's not clear how you would even set up a submodule

mednafen (which is released as source tarballs) would be the example for that.

@vadosnaprimer
Copy link
Copy Markdown
Contributor

pcem was also mercurial initially, so we just converted it to git via some python script. We'd be submoduling our own fork so I don't understand what can be problematic about it. I also don't understand the thumbs down: you turn whatever is unmodified code into original commit and then put all wbx changes on top of it, and then submodule that.

@mr-ke
Copy link
Copy Markdown
Author

mr-ke commented May 24, 2026

pcem was also mercurial initially, so we just converted it to git via some python script. We'd be submoduling our own fork so I don't understand what can be problematic about it. I also don't understand the thumbs down: you turn whatever is unmodified code into original commit and then put all wbx changes on top of it, and then submodule that.

Hi, actually it is feasible to turn it into submodule of blastEM or a blastEM fork anyway, or just use a original source tarball then append a big patch of it. Since I am crystal clear about the details how I make the efforts to make it work under mono thread without block. But it must have someone here have the Initial interest to do that porting.
From my side, the motiviation as below:

  1. I see the performance boost (Even under waterbox layer beneficial with its dynamic recompilation from 68k to x86) in the sametime it still keep quite cycle precision.
  2. I see the compatibility not worse than existing picodrive or Genesis-Plus-GX on some morden genesis rom.
  3. Some one raise this request as well and I do not see it in-rational.

I would not turn it into any debate or argument since it is just originated from my goodwill without breaking existing good stuff.
CC: @CasualPokePlayer @vadosnaprimer @YoshiRulz

@YoshiRulz
Copy link
Copy Markdown
Member

mednafen (which is released as source tarballs) would be the example for that.

pcem was also mercurial initially, so we just converted it to git via some python script. We'd be submoduling our own fork so I don't understand what can be problematic about it. I also don't understand the thumbs down: you turn whatever is unmodified code into original commit and then put all wbx changes on top of it, and then submodule that.

My problem with a setup like TASEmulators/mednafen is that it's almost never updated. And, in forking that way (as opposed to a normal GitHub fork), we create more technical debt for ourselves.
But I don't think those problems are sufficient justification for blocking a core port, only a "smell" or warning of what to avoid. If it's the least-bad option, then by all means, do it so you unblock OP.

@YoshiRulz
Copy link
Copy Markdown
Member

From my side, the motiviation as below:

  1. I see the performance boost (Even under waterbox layer beneficial with its dynamic recompilation from 68k to x86) in the sametime it still keep quite cycle precision.
  2. I see the compatibility not worse than existing picodrive or Genesis-Plus-GX on some morden genesis rom.
  3. Some one raise this request as well and I do not see it in-rational.

I would not turn it into any debate or argument since it is just originated from my goodwill without breaking existing good stuff.

Sorry about the submoduling tangent.
I think it would be good to have both Genesis Plus GX and BlastEm. BlastEm's licence is less ambiguous, and when one core doesn't work, the other can be used. It looks like both are actively being developed, so they can share knowledge directly or indirectly.
Clearly your understanding of "unmanaged" code is enough for you to build cool features like this and librashader. I want you to know that we appreciate your contributions, despite the language barrier. Would you prefer to discuss technical details here in PR review comments, or in a chatroom? All of us can be reached in a public Discord server, invite here.

@vadosnaprimer
Copy link
Copy Markdown
Contributor

My problem with a setup like TASEmulators/mednafen is that it's almost never updated.

How is the setup relevant here if mednafen literally doesn't release that often?
https://github.com/mednafen/mednafen.github.io/tree/master/releases/files

And, in forking that way (as opposed to a normal GitHub fork), we create more technical debt for ourselves.

What exactly are we supposed to fork then?

But I don't think those problems are sufficient justification for blocking a core port, only a "smell" or warning of what to avoid. If it's the least-bad option, then by all means, do it so you unblock OP.

It's not about blocking it entirely, it's a suggestion that makes things much easier to manage later on, an ideal. It's not even hard to do, I can do it myself unless the author feels like doing it on their end.

@nattthebear
Copy link
Copy Markdown
Contributor

While the mednafen setup isn't perfect, it's better than nothing. By keeping two branches, a fake upstream, and then the branch with our changes, we can more easily sync upstream and then reapply our changes with a 3-way merge.

For blastem, some sort of hg->git sync and then maintaining our own separate git branch with mods should work.

@@ -42,7 +42,7 @@ void* alloc_helper(size_t size, const struct __AddressRange* range, unsigned lon
unsigned long pend = (end + 0xfff) & ~0xffful;
if (pstart < pend)
{
if (mmap((void*)pstart, pend - pstart, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_FIXED_NOREPLACE, -1, 0) == MAP_FAILED)
if (mmap((void*)pstart, pend - pstart, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE | MAP_32BIT, -1, 0) == MAP_FAILED)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes absolutely no sense for many reasons.

  • Waterbox doesn't read or respect the MAP_32BIT flag at all.
  • The point of these allocation helpers is to provide a unified way for simple one-time bump allocations. All of the calculations above are to that end: We have a start offset that is in general not page aligned, and then we allocate pages with mmap in a page-aligned way. So for instance, if we allocate 2KiB, and then 6KiB, the first allocation will map 1 4KiB page, and the second will allocate only 1 more 4KiB page, giving the caller the second half of the page from the first call. By turning off MAP_FIXED, these are no longer guaranteed to be contiguous allocations, and the second call will get a pointer that only is guaranteed to point to 2KiB of space, not the 6KiB it needs.
  • The point of these allocation helpers is to provide a way for allocations into special memory pools that are at specific places. By turning off MAP_FIXED, they all go into a general mmap pool, and so in particular alloc_sealed and alloc_invisible no longer allocate what they claim to.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • While PROT_EXEC is an allowed thing, existing callers of these methods don't expect,want, or need it.

If this core has some special allocation requirements, it should just call mmap directly.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • While PROT_EXEC is an allowed thing, existing callers of these methods don't expect,want, or need it.

If this core has some special allocation requirements, it should just call mmap directly.

MAP_32BIT is redundant, MAP_FIXED should also preserved. The only one I indeed need is PROT_EXEC, since blastem use dynamic recompile (68k->x86) that need the memory to exec, if PROT_EXEC is not allow, then it need another alloc wrapper.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upstream would not be calling the wbx alloc_* functions in the first place. There is no need to change upstream to use wbx alloc functions here.

@getCursorsExe
Copy link
Copy Markdown

Currently this core does not respect the SSF2 mapper on loadstate. Loading a savestate on game session with a different ROM bank will cause a crash.

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

Labels

Core: Future core Core doesn't exist yet or is an early WIP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants