Skip to content

New readmes #3

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Update README.md
  • Loading branch information
devshgraphicsprogramming authored Oct 12, 2022
commit 288bd46ef0fe6046aa865816988aaf184f90a0ad
109 changes: 52 additions & 57 deletions EmscriptenGLFW/README.md
Original file line number Diff line number Diff line change
@@ -1,94 +1,89 @@
# GPU With C-Sharp Angular WASM
### C++ to WebAssembly using Emscripten
# C++ to WebAssembly using Emscripten

To solve one problem at a time instead of dealing with all of them at once, in this variant of the app we only look into how to get the native app running in the browser.
To solve one problem at a time instead of dealing with all of them at once, in this variant of the app we only look into how to compile the previously native app to WASM and get it running in the browser.

We are going to utilize the fact that Emscripten comes with its own GLFW and GLEW function defintions that are spoofed into JavaScript function calls.
We are going to utilize the fact that Emscripten comes with its own GLFW and GLEW headers in the SDK.

To continously render without making the browser unresponsive, we have to wait inbetween renderloop calls.
The main function changed to something like this
```
int main() {
w = new Window(1280, 720);
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(main_loop, 0, true);
#else
while (w->keepAlive())
w->update();
#endif

}
```
## Findings

Emscriptens function to create the main loop is not much different from using JS' ` window.requestAnimationFrame(main_loop);` recursively.
### Most of the C or C++ function definitions belonging to libraries in Emscripten's SDK are spoofed into JavaScript function calls

`requestAnimationFrame` is apparently the recommended way of creating a render loops, however it seems that in conjunction with webassembly or DWARF debug format it can lead to stack smashing as more and more stack frames are added the longer the app is running.
For example, there's no such thing as OpenGL ES 3.0 on the web, there's only a C header which uses Emscripten's JavaScript-Embedded-in-C macro to call WebGL 2 functions which are only usable from JavaScript.

Rest of the libraries, such as the standard C library, the Standard C++ Library, GLFW, SDL, etc. are bizarre hybrids where certain OS-specific API function calls are replaced with implementations that use JavaScript.

### You cannot use a "main loop"

<br>
If your JS or WASM function does not return within a given timeout, the web-page's responsiveness freezes and you will eventually get a prompt from the browser whether to kill or wait for the script.

# Installation
<br>
Any rendering or similar continuous operation needs to be implemented via callbacks instead of loops.

### Emscripten
### Faux Stack Smashing in Debug

Set up Emscripten as explained in readme in directory above.
Emscriptens function to create the main loop is not much different from enqueueing JavaScript's `window.requestAnimationFrame(main_loop);` recursively.

<br>
Calls to `requestAnimationFrame` from the callaback previously passed to `requestAnimationFrame` is apparently the recommended way of creating a render loops, however it seems that in conjunction with WASM or DWARF debug format it can lead to what appears like stack smashing, as more and more stack frames are seemingly added the longer the app is running.

### CMake
However this is not true stack smashing as `requestAnimationFrame` merely enqueues the callback to be executed when the current one finishes.

Do not use CMake gui if you plan on using Visual Studio 2022 as an IDE. As of now, the custom toolchain passed into CMake gets disregarded if you use the generator `Visual Studio 17 2022` to configure a CMake project, and you use the default C++ compiler instead of `emcc`.
### The Proper way to get Debugging Symbols

Instead, launch VS2022 and use the newly added option to open a CMake project by targetting this CMakeLists.txt
Over the period of 2018-2021 there were many compile options to generate debug info with Emscripten and ways to store and debug it, such as `-gsource-maps`, they should all be consideted outdated even and especially if coming from the Chromium Developer blog. The DWARF debug symbol generation is the only method which is actually understood by Chrome and does not lose your variable names or function names.

![Opening a CMake project in VS2022](../Docs/img4.jpg)
**While using DWARF, you cannot use source maps. -gsource-maps is now obsolete, yet despite that, if present, they will take precedence over the debug info from DWARF, and will end up scrambling names of locals.**

<br>

## Building
When the debug info for a WebAssembly app is stored in DWARF format, it can be either embedded into the .wasm file, or be separated from it. We tried both for this example and for exercise's sake we decided to go with the split DWARF.

In solution explorer on the top click on a button to switch between solutions and available views, then on CMake Target views and right click on EmscriptenGLFW project to bring up a context menu that has an option to build.
Another option is to change the launch target to `EmscriptenGLFW.html`, and then build by pressing `Ctrl + B`
The DWARF format stores an absolute path to the source files on the computer, _which means that its not going to load the sources properly when debugging if the sources move (such as when debugging on another machine to the building one)_. Unfortunately unlike a real IDE, Chrome Dev Tools won't ask you to locate a missing source.

<br>
_We tried to develop a utility for patching the paths for sources in the split DWARF, however we found out that the format is offset based, ergo the length of the path strings cannot be changed. Furthermore the paths get concatenated with directory paths which rules out exchanging paths for shorter paths and padding the remainder of the data with null characters._

-----

# Launching

To properly launch this project, use the provided `run.py` script in the root directory of the repo.
```python run.py ./EmscriptenGLFW/```
One letdown of DWARF is that, unlike source maps, it does not list the source files in the sources tab of chrome debugger.

It starts a local server with its root in the directory of the repository, such that it can also view the contents of `GPU-With-C-Sharp-Angular-WASM/data/` which are obtained by the built example at runtime using wget.
## Modifications Required

To continously render without causing the browser to become unresponsive, we had to change the main function to this:
```cpp
Window* window;
void main_loop()
{
window->update();
}

<br><br><br><br><br>
int main() {
window = new Window(1280, 720);
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(main_loop, 0, true);
#else
while (window->keepAlive())
window->update();
#endif

}
```

# Debugging
## Building

The debug info for this WebAssembly app is stored in DWARF format, that can be either embedded into the .wasm file, or be separated from it.
As long as you have the Emscripten Target VS2022 component installed, the solution should load and work out-of-the-box.

The DWARF format stores an absolute path to the source files on the computer.
The solution only has one project, build it by pressing `Ctrl + B` or straight up `F5` debugging it.

To debug this app, you no longer use VS debugger or GDB, instead you use the chrome debugger.
You can change the targets from Debug to RelWithDebInfo or Release.

While using DWARF, you cannot use source maps. -gsource-maps is now obsolete, yet despite that, if present, they will take precedence over the debug info from DWARF, and will end up scrambling names of locals.
One letdown of DWARF is that, unlike source maps, it does not list the source files in the sources tab of chrome debugger. The source files are still accessible though.
## Debugging

Other than debugging C++, you can now also debug the generated JS glue code that loads the wasm app.
**TL;DR All source-level CPU debugging features you're used to on Native, just work. For a discussion of GPU debugging using Renderdoc see the section in towards the bottom of the top level repository root README.md**

Disassembling the code yields reading from the generated `EmscriptenGLFW.wasm`
To debug this app, you can use either the Chrome Developer Tools Debugger once you run the example in Crhome or you can use the VS2022 debugger, which launches the example in Chrome and connects to the Chrome Developer Tools Debugger remotely.

<br><br><br><br><br>
Other than debugging C++, you can now also debug the generated JS glue code (a few thousand lines of it) that loads the wasm app and implements some of the functions that the Emscripten SDK declares in its C and C++ headers.

Disassembling the code yields reading from the generated `EmscriptenGLFW.wasm`


## Launching outside of the Debugger (TODO: update)

Notes:
-------
To properly launch this project, use the provided `run.py` script in the root directory of the repo.
```python run.py ./EmscriptenGLFW/```

Compiling with -g4 prints a warning that this option is outdated, and to use source maps, which are also outdated, but the latter is not displayed.
Do not use either.
It starts a local server with its root in the directory of the repository, such that it can also view the contents of `GPU-With-C-Sharp-Angular-WASM/data/` which are obtained by the built example at runtime using wget.