Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web support #94

Merged
merged 16 commits into from
Dec 30, 2022
Merged

Web support #94

merged 16 commits into from
Dec 30, 2022

Conversation

badlogic
Copy link
Contributor

@badlogic badlogic commented Dec 1, 2022

This commit adds web support to minifb through emscripten. See #93

CMake build changes

The CMake build has been modified in the following way:

  • A new set called SrcWeb was added. It contains the web backend (WebMiniFB.c)
  • The emscripten toolchain identifies as UNIX. Sections of the build targeting UNIX had to be modified, e.g. to not add the USE_OPENGL_API option when building for the web.
  • When building for the web, a range of emscripten specific compiler and linker options are added globally to all targets. This simplifies the build of tests, as well as the build of an app created by an end user that add the minifb CMakeLists.txt to their build.
  • When building the tests for the web, a custom target called web_assets is created, which copies all files from tests/web to the output folder. The folder contains .html files which load the generated .js/.wasm files, setup a canvas for rendering, and execute the test app's main() function. It also adds the target as a dependency to the test targets, and sets an additional linker option for each test target. The linker option specifies the module name with which the compiled minifb app can be instantiated in JavaScript.

New backend features and limitations

A new backend was added in src/web/WebMiniFB.c. It can run all tests of minifb, including the multi-window and input tests, both in dekstop and mobile browsers.

The mfb_open_ex() function expects that a HTML canvas element with an id equal to the specified title exists. If no such canvas exists in the DOM, mfb_open_ex() will return an error code.

Keyboard, mouse and touch input are supported. However, only a single touch will be processed, as the minifb API currently does not provide a way to deal with multi-touch. Touche events are thus interpreted as mouse events. The only supported button on the web is the left mouse button.

The web backend is using emscripten's Asyncify feature. It allows to run synchronous native code, like the minifb tests without modification. However, a minifb app on the web must still yield to the browser so DOM events can be processed. A minifb app on the web must thus periodically call mfb_wait_sync(), which will hand control back to the browser for a short time. This "yielding" is implemented using requestAnimationFrame(), so it is vsynched and as high performance as it can be.

The web backend also implements the timer api using performance.now(). Note that this is not a high precision timer and fudges things by 2ms to due to a Spectre mitigation. It is usually good enough for real-time apps.

The web backend blits the buffer passed to mfb_update_ex() to the canvas associated with the window by converting the buffer to an ImageData instance, then calling Context2D.putImageData() to draw the buffer to the canvas. The canvas' backing buffer always has the size of the buffer provided to mfb_update_ex(). If the CSS size of the canvas is different, the browser engine will automatically up or downscale the backing buffer. To keep scaled display as pixel accurate as possible, mfb_open_ex() will set the CSS property image-rendering to pixelated on the canvas.

When blitting the user provided buffer to the canvas via putImageData(), the alpha channel of each pixel will be interpreted and the data will actually be blended with the current canvas backing buffer data. It is thus necessary to always set the alpha channel of pixels in the buffer passed to mfb_update_ex()

The web backend currently does not support mfb_set_viewport().

Test changes

The changes are using the new MFB_ARGB macro instead of MFB_RGB so each pixel receives an alpha value as well.

Building for and running in the browser

To build for the web, specify the emscripten toolchain location:

cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/emsdk/<version>/emscripten/cmake/Modules/Platform/Emscripten.cmake -S . -B build
cmake --build build

The build folder will then contain .js, .wasm, and .html files for each test, as well as a index.html file that links to all the test .html files for faster navigation between tests.

The tests can then be viewed in the browser by serving the contents of the build file via a HTTP server. E.g. using Python:

python3 -m http.server --directory build

Open http://localhost:8000 in the browser to check out the test apps.

Example usage

Here's a simple project that illustrates how to setup the CMake build for a project using minifb:
https://github.com/badlogic/r96/blob/main/CMakeLists.txt

I've also uploaded the minifb tests for web here: Submitted a pull request to minifb for my web backend:
https://marioslab.io/dump/minifb/

@Darky-Lucera
Copy link
Collaborator

I'll try to keep an eye on it over the weekend

@Darky-Lucera
Copy link
Collaborator

Darky-Lucera commented Dec 18, 2022

Hello!

I just tested it on Windows and it seems to work fine. It doesn't seem to work with MSVC but it worked with MinGW (GCC).

cmake .. -G "MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE=c:\Work\emsdk\upstream\emscripten\cmake\Modules\Platform\Emscripten.cmake ..

cmake --build .

python -m http.server --directory .

Tell me when you finish.

@badlogic
Copy link
Contributor Author

I'm done on my end!

@Darky-Lucera
Copy link
Collaborator

Could you please add an option to compile the examples with all their dependencies in one file per example/app. This way the user program does not need a server.

I think is the flag -sSINGLE_FILE.

@badlogic
Copy link
Contributor Author

Done.

@Darky-Lucera Darky-Lucera merged commit db8ffbb into emoon:master Dec 30, 2022
@badlogic
Copy link
Contributor Author

Wow, thank you!

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.

None yet

2 participants