Coder Social home page Coder Social logo

kiljorn1109 / macemu Goto Github PK

View Code? Open in Web Editor NEW

This project forked from jsdf/macemu

0.0 0.0 0.0 55.33 MB

Basilisk II Classic Macintosh emulator ported to the browser

Home Page: https://jamesfriend.com.au/projects/basiliskii/BasiliskII-worker.html

Shell 0.49% JavaScript 0.56% C++ 63.03% Perl 0.02% C 24.89% Objective-C 0.70% Assembly 1.87% Objective-C++ 2.54% Makefile 1.03% HTML 1.07% M4 3.79% Roff 0.01%

macemu's Introduction

Basilisk II classic Macintosh emulator in the browser. Try it out

Screenshot of Basilisk II in the browser

How this works

Basically, the emulator code is compiled with Emscripten and run in a Web Worker. Communication with the main thread happens by reading and writing SharedArrayBuffers shared between the main browser thread and the worker, which allows the emulator code to run without ever yielding. This allows the simulation to be more smooth than if we had to regularly yield the browser event loop, and also simplifies the porting work in some ways.

The original emulator codebase makes use of SDL (a cross-platform set of video/audio/input APIs), and Emscripten provides an implementation of SDL, but it doesn't work when the code is running in a web worker, so I've hacked the emulator's video output code to write to the SharedArrayBuffer instead of calling SDL APIs. You can see in video_sdl.cpp where the EM_ASM_ macro is used to call this JS function to copy the contents of the video framebuffer to a SharedArrayBuffer. This shared memory is read from the main thread here and output onto a Canvas. I experimented with locking the video surface when reading and writing, but this hurt performance due to lock contention. However, we don't really need it. Even if the UI thread reads a frame from the video framebuffer while it is currently in the middle of being written to from the emulator worker, it's not really noticable, because in the shared memory the new frame contents is just being written directly over the old one at the same position, so visually it just presents as a bit of 'tearing' (showing part of the old frame, part of the new frame). We could improve on this by using a circular queue of framebuffers for alternating frames (multiple buffering), which would allow locking (with less contention), but in practice this is okay.

Mouse and keyboard input are communicated via another SharedArrayBuffer here in the UI thread JS, then read in the worker thread JS here, when requested from the C code here. I also had to add a mapping to convert JS keycodes to ADB (Apple) keycodes.

The implementation of audio uses a queue of buffers in shared memory, which each have a flag signifying whether they are full and ready to be consumed by the UI thread, or empty and ready to be written by the emulator thread. The emulator thread will ensure that there are several buffers of audio queued up, to avoid gaps in playback in the case of a slowdown. When the emulator is built natively, audio has a dedicated thread to avoid slowness on the emulator thread affecting playback, but to make things simpler I've just hacked in a call to output audio directly into the emulator's main loop here. This could be improved by using Emscripten's pthreads support to spawn a separate audio thread. The audio buffer is passed to JS here and copied into a SharedArrayBuffer here. The audio read in the UI thread here and output using the Web Audio API.

In future this implementation could be improved by moving all of the shared memory communication to C code by leveraging Emscripten's pthreads support. In this scenario the emulator code would start up, spawn a thread to run the emulator main loop, and then yield back to the browser. Instead of creating SharedArrayBuffers to communicate video, audio, and input, Emscripten's pthreads mode makes the entire C heap memory space a SharedArrayBuffer, with each spawned thread running in a web worker. The JS would simply read and write values on the C heap. This would also unblock using threads in the emulator code (currently not easy due to Chrome's lack of support for web workers spawning other web workers).

build instructions

See the NOTES file

macemu's People

Contributors

asvitkine avatar jsdf avatar vasi avatar amade avatar kallisti5 avatar clehner avatar charlesjs avatar dougg3 avatar landonf avatar rickyzhang82 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.