Live data from Hacker News

Theseus: Translating Win32 to WASM

neugierig.org

21–30 of 31 posts

Re: Theseus: Translating Win32 to WASM

#21
post #19

Seems like Theseus is not using OffscreenCanvas yet. Should be a good fit for something that runs off the main thread. Graphics can be rendered from a background worker thread directly to the screen without the involvement of the browser main thread at all. https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCa...

[post author] I looked into this API but wasn't sure how to make good use of it. I may have misunderstood, maybe you could help! The doc you linked has two forms of use, sync and async. For sync: it seems the idea is for the worker to render into an OffscreenCanvas, then postMessage an ImageBitmap created with transferToImageBitmap from worker to main thread for drawing. It seems like it would need to allocate a new…

I think after you call transferControlToOffscreen() and transfer the OffscreenCanvas to the worker, then the worker can control the size of the canvas with the width and height properties of the OffscreenCanvas. I'm not sure how this interacts with layout though.

IIRC the transferToImageBitmap path is efficient and doesn't necessarily copy anything. The APIs are designed to allow the ImageBitmap you get to be a reference to the GPU texture that is the backbuffer of the canvas, not a copy. When you transfer it to the main thread you are supposed to draw it using an ImageBitmapRenderingContext, which doesn't need to do an extra blit. It's just directly composited with the rest of the page, all staying on the GPU. In theory if it's a full screen canvas with no DOM on top the browser could even skip compositing entirely though I don't know if that's implemented anywhere.

Of course there are probably a lot of ways to fall off the fast path. And I guess you are doing software rendering for GDI so you're not starting out with pixels on the GPU in the first place. I'm not sure what the best path is for you but I think you can probably benefit from OffscreenCanvas in some way.

Re: Theseus: Translating Win32 to WASM

#22
post #20

There is also Retrotick. https://retrotick.com/ It simulates x86 (win32 and win16) and implements Windows APIs in javascript and renders window frames with DOM and contents with canvas (e.g. GDI translates to browser canvas operations). A lot of programs run already but a lot of APIs are not yet implemented. I successfullt spent a few days extending it to run a Click & Create based game from my childhood.

The author actually talks about this in an earlier post[0]

[0]: https://neugierig.org/software/blog/2026/04/theseus.html

Re: Theseus: Translating Win32 to WASM

#23

I am unfamiliar with this project and only skimmed this post but if this uses Rust for the main binary blob it should be possible to have the main thread blob shared with the other threads even with the blocking. The blog post cites the concern that malloc could block, however when Rust's standard library is compiled with support for atomics enabled the Rust allocator's locking implementation busy loops instead of wa…

People in the WebAssembly standards group are recently considering relaxing the limitation that the main thread can't use atomic.wait: https://github.com/WebAssembly/threads/issues/177#issuecomme...

Re: Theseus: Translating Win32 to WASM

#24
post #23

I am unfamiliar with this project and only skimmed this post but if this uses Rust for the main binary blob it should be possible to have the main thread blob shared with the other threads even with the blocking. The blog post cites the concern that malloc could block, however when Rust's standard library is compiled with support for atomics enabled the Rust allocator's locking implementation busy loops instead of wa…

People in the WebAssembly standards group are recently considering relaxing the limitation that the main thread can't use atomic.wait: https://github.com/WebAssembly/threads/issues/177#issuecomme...

Wow, thanks for the link, that is perfect timing! I submitted my post and my own feedback on the discussion: https://github.com/WebAssembly/shared-everything-threads/dis...

Re: Theseus: Translating Win32 to WASM

#25
post #19

Earlier quoted context omitted.

[post author] I looked into this API but wasn't sure how to make good use of it. I may have misunderstood, maybe you could help! The doc you linked has two forms of use, sync and async. For sync: it seems the idea is for the worker to render into an OffscreenCanvas, then postMessage an ImageBitmap created with transferToImageBitmap from worker to main thread for drawing. It seems like it would need to allocate a new…

I think after you call transferControlToOffscreen() and transfer the OffscreenCanvas to the worker, then the worker can control the size of the canvas with the width and height properties of the OffscreenCanvas. I'm not sure how this interacts with layout though. IIRC the transferToImageBitmap path is efficient and doesn't necessarily copy anything. The APIs are designed to allow the ImageBitmap you get to be a refer…

Thanks a lot for this, I will put it on my list to investigate.

I've gone in circles a few times with how to think about image buffer management because I also support DirectDraw, which is designed to be backed by accelerated graphics, with operations like scaling bitblit. (Currently the Theseus implementation uses a shared "Surface" type as the backing store for both GDI Windows and DirectX Surfaces.)

It's a bit complicated by a few things. (1) DirectX surfaces can be "locked" to access as pixel buffers, so any accelerated surface indirection I guess would need to be able to copy pixels back down into emulator memory. Which I guess I could just implement. (2) There's a bunch of different modes for operations like bitblit like setting a color key for transparency that I can't implement with the canvas API, so I think I'd need to use GL shaders if I want acceleration, not just canvas.

Re: Theseus: Translating Win32 to WASM

#26

I miss the days when this would just have been named win2wasm. These branded projects become difficult to remember when everything has a random non-mnemonic name.

This is my second emulator, and in my first I picked a name more like that and regretted it. A thing I now appreciate about emulators is that it's common to increase scope -- like this one already supports non-wasm output, and I am tinkering with adding support for DOS executables as well, which means the name 'win2wasm' would already become obsolete!

Re: Theseus: Translating Win32 to WASM

#27
post #17

I am unfamiliar with this project and only skimmed this post but if this uses Rust for the main binary blob it should be possible to have the main thread blob shared with the other threads even with the blocking. The blog post cites the concern that malloc could block, however when Rust's standard library is compiled with support for atomics enabled the Rust allocator's locking implementation busy loops instead of wa…

Gosh, I think that means even when your code is wholly running on workers (where you would be able to use the atomic wait mentioned in the comment), it still will busy loop, doesn't it? At least it's within the allocator and not in the general implementation of Mutex... I think?

Yes that first sentence is correct and that's an unfortunate side effect. The Rust ecosystem eventually needs to evolve its multithreaded Wasm approach. Atomics are still only supported on Nightly Rust but it's been that way for 7+ years now.

And yes you're right again it's only in the allocator.

Re: Theseus: Translating Win32 to WASM

#28

If you’re poking around WASM consider falling down the Component Model rabbit hole: https://github.com/WebAssembly/component-model/blob/main/des... Threading is actively being worked on right now (to be released in 0.3.x, soon), and some changes just made their way into LLVM as well: https://github.com/llvm/llvm-project/pull/175800

Iirc the async stuff in the component model isn’t actual threads but rather green threads, but correct me if I’m wrong

That’s right — I’m assuming you mean OS threads when you write “actual threads”.

Stackless Coroutines are currently supported for p3, stackful coroutines AKA “virtual threads” are coming (which I assume is what you mean by green threads), and “actual threads” as in OS threads are not currently a goal for the ABI AFAIK —- would you mind explaining some uses you were thinking of?

Re: Theseus: Translating Win32 to WASM

#29

Earlier quoted context omitted.

Iirc the async stuff in the component model isn’t actual threads but rather green threads, but correct me if I’m wrong

That’s right — I’m assuming you mean OS threads when you write “actual threads”. Stackless Coroutines are currently supported for p3, stackful coroutines AKA “virtual threads” are coming (which I assume is what you mean by green threads), and “actual threads” as in OS threads are not currently a goal for the ABI AFAIK —- would you mind explaining some uses you were thinking of?

So if you are writing a WASM component model, and you were hoping to use Web Workers/SharedArrayBuffer, how would that work?

Do the virtual threads map on top of the Web Workers? Or are the Web Workers themselves green threads?

I was assuming Web Workers are OS threads

Re: Theseus: Translating Win32 to WASM

#30

Earlier quoted context omitted.

That’s right — I’m assuming you mean OS threads when you write “actual threads”. Stackless Coroutines are currently supported for p3, stackful coroutines AKA “virtual threads” are coming (which I assume is what you mean by green threads), and “actual threads” as in OS threads are not currently a goal for the ABI AFAIK —- would you mind explaining some uses you were thinking of?

So if you are writing a WASM component model, and you were hoping to use Web Workers/SharedArrayBuffer, how would that work? Do the virtual threads map on top of the Web Workers? Or are the Web Workers themselves green threads? I was assuming Web Workers are OS threads

That’s a great question and something we’re going to have to figure out going forward on the JS side.

What I can say now is that the first version will probably be single threaded stack switching coroutines, and the model that seems to fit most naturally in my head is virtual threads mapping to some worker thread n in a premade pool.

Post reply on HN