[HN Gopher] WebAssembly from Scratch: From FizzBuzz to DooM
___________________________________________________________________
WebAssembly from Scratch: From FizzBuzz to DooM
Author : popitter
Score : 388 points
Date : 2021-07-14 12:00 UTC (11 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| iGu35 wrote:
| https://www.google.com
| Jnr wrote:
| Interesting that Firefox by default did not render the fizzbuzz
| demo correctly by default. I had to click the canvas icon next to
| address bar and allow the canvas usage. And it did not show a
| prompt either. It just looked broken by default.
|
| Screenshot from Firefox vs Chrome https://i.imgur.com/Af8nTim.png
| dimes wrote:
| You probably have resist fingerprinting turned on
| Jnr wrote:
| Most likely. I don't remember all the settings that I have
| turned on at some point. :)
| fouc wrote:
| FF 89 worked fine here (mac), either your FF version is old or
| it's some sort of FF/linux issue ?
| smichel17 wrote:
| ...Good! The "prompt" permission model is fundamentally broken,
| because all it does is train you to click through the prompt.
|
| The "click the blocking button and turn it off" model is much
| better. It still trains you to turn off blocking when something
| is broken. However, crucially, that's _only when it 's broken_.
| When it's not broken, you just use the site, instead of
| habitually clicking through the permission prompt that's just
| harvesting data, not actually needed to function.
|
| And yes, malicious sites can of course display themselves as
| falsely broken until you grant the permissions. But this makes
| them more annoying to use, granting a UX edge to the honest
| sites which don't request unnecessary permissions. In other
| words, the incentives of sites and users are more aligned.
| singularity2001 wrote:
| >>> all it does is train you to click through the prompt.
|
| no, if I want extra functionality, I click it, otherwise I
| ignore it. (random page wants my location? nah)
|
| modular blocking prompts were broken, optional prompts are
| fine
| milliams wrote:
| I found this video https://www.youtube.com/watch?v=r-A78RgMhZU "A
| Talk Near the Future of Python (a.k.a., Dave live-codes a
| WebAssembly Interpreter)" to be a brilliant introduction to WASM
| as well as writing interpreters in general. I'm a relative novice
| in the subject and it was pitched right at my level.
| Quekid5 wrote:
| Dave Beazley is a truly amazing presenter. Another favorite of
| his of mine is his epic tale of how he ended up demolishing an
| opposing side's case in a civil lawsuit... by sheer luck of
| having a Python interpreter avaialable. For for you viewing
| pleasure:
| https://www.youtube.com/watch?v=RZ4Sn-Y7AP8
| jnwatson wrote:
| My first question I thought of before reading this was how to
| actually display characters out of it.
|
| Quite a mess, IMHO. (Not that I'm blaming the author).
| innocenat wrote:
| This is common for lower-level API though. Displaying a single
| cube in modern OpenGL or Vulkan is also surprisingly a mess.
| abledon wrote:
| another tutorial added to my bookmarks I will struggle to get
| around to :)
| sharikone wrote:
| Just a point for the first chapters: you are not required to run
| your own local server (even if things push in that direction)
|
| You can include the wasm as an ArrayBuffer or as a base64 encoded
| string and hardcode it in the javascript. Now it will run even in
| a static html.
| jjice wrote:
| It's incredible how far the web has come. I remember the first
| time I saw a browser GameBoy emulator and I was amazed. Maybe I
| should port my GB emulator to WASM...
| sigg3 wrote:
| > It's incredible how far the web has come.
|
| I agree and disagree. It seems like no one is questioning why
| we need to use legacy web browsers in between all the code
| we're executing locally.
|
| It's like a new iteration of old tech like lisp machines,
| which started out as specific purpose only to grow into
| complete environments (afaik).
|
| In this regard, we haven't come far, it's just the syntax
| that has changed.
| lisper wrote:
| In the case of WASM, even the syntax hasn't changed, it has
| just come full-circle back to S-expressions.
| paulgb wrote:
| For one thing, I'm unlikely to download a native copy of
| Doom to run on my own machine from a strange website. The
| ability to run cross-platform code that uses my GPU in a
| secure sandbox is pretty neat to me.
| [deleted]
| recursivedoubts wrote:
| I can't tell if the lack of strings and DOM API interop in web
| assembly is on purpose or not.
|
| If it is on purpose, what an absolutely diabolical way to ensure
| javascript language dominance in the browser: give people a way
| to port their language to the browser, but make it incredibly
| difficult to do anything.
| Deukhoofd wrote:
| The lack of strings makes sense, as many different languages
| and standard libraries have their own implementations of it,
| that can behave slightly differently. It now puts the
| implementation of the string to the compilers/linkers, as is
| generally the case for assembly as well.
|
| The lack of a DOM API is something I sorely miss as well. It's
| currently possible (and not that hard, you can just interact
| with JS), but comes with such performance overhead that you
| lose the entire benefit of WASM.
| HideousKojima wrote:
| It's also _still_ missing proper garbage collection, meaning
| languages like C# have to include basically the entire runtime
| if you compile to WebAssembly. This is a major part of why
| Blazor apps in .NET 5 are ~2MB for a simple "Hello World"
| (closer to 8MB if you use the AOT compilation options in the
| .NET 6 preview).
| pjmlp wrote:
| My Intel CPU also doesn't have a GC, so that is how it is.
| Deukhoofd wrote:
| Why would WASM have garbage collection? It's an assembly
| target, not a runtime. What if languages would want different
| memory management strategies?
|
| I know it's an existing proposal for WASM, but it feels so
| massively out of scope. If the issue is having to include
| runtimes in the WASM binary it might be more useful to think
| about how we could serve runtimes in a more efficient way.
| staticassertion wrote:
| I feel the same way. I find it very odd that GC is
| something that WASM ever intends to think about. If
| shipping your entire runtime sucks, find a smaller runtime?
| steveklabnik wrote:
| Think of it more of "integration with a host
| environment's runtime" than a "adding a runtime to wasm
| directly."
|
| (At least, that's what it used to be; I haven't been
| involved in WebAssembly for a long time.)
| pjmlp wrote:
| The problem is that each runtime has different GC
| requirements, so at best it will mean WASM GC semantics
| will be the underlying JS GC semantics, probably not what
| you want for a D or .NET GC, for example.
| steveklabnik wrote:
| I would assume that there's Microsoft folks involved to
| make sure it works out satisfactory given their
| investment in Blazor, but yes, it's always a possibility
| that an API is bad. I don't know what their level of
| interest is in embedding wasm inside C# is.
| pjmlp wrote:
| That was just an example, there are a plethora from GC
| algorithms to chose from, which of them needs to be fine
| tuned for the specific runtime it is to be applied, if
| performance is of any concern to the language
| implementers.
| titzer wrote:
| I have worked on a number of runtimes and it is not
| generally the case that a GC needs to be "tuned" for a
| runtime, rather that a GC co-evolves with a runtime and
| features or misfeatures of the runtime determine the path
| of least resistance for developing more advanced GC
| algorithms. The interplay tends to involve a lot of
| technical debt if the separation is poor from the outset.
| But regardless, it's rare that a runtime develops more
| than a couple GC algorithms unless it has a very long
| lifetime or is explicitly designed to allow swappable
| GCs, like Jikes RVM with Mmtk.
|
| GC performance depends more on the program than the
| language.
|
| But regardless, the hardest parts of getting to advanced
| GCs, such as concurrent and parallel algorithms are
| usually very deep assumptions of single-threadedness and
| uninterruptibility that are debt in the runtime. It
| usually doesn't help that most runtimes are written in
| C/C++ and suffer that environment's complete
| uncooperativeness[1] in finding and manipulating roots.
|
| [1] To the point of seeming hostility. It's been how many
| years and LLVM still fights against supporting stack
| maps?
| titzer wrote:
| No one has ever articulated the details of what they mean
| by these runtimes having different GC requirements.
| JavaScript garbage collection has no "semantics"--it is
| entirely invisible to applications. Even WeakMap and
| WeakSet do not expose garbage collection details because
| they are not iterable.
|
| The memory profile of JavaScript applications tends to
| look a lot like the memory profile of typical Java
| applications. It tends to be a law of large numbers.
|
| Now if you want to talk about details of how we implement
| runtimes that do have observable GC details, like weak
| callbacks, Java's zoo of reference types, etc, then let's
| do that, because Wasm GC will eventually need to have
| low-level mechanisms to support those.
|
| But if we're talking about a Wasm engine GC's ability to
| allocate, trace, move (or not!) little blocks of memory
| around, then I don't see any fundamental stumbling blocks
| to making that mechanism efficient and universal.
| staticassertion wrote:
| Yeah, could be interesting. I guess it works for the JVM?
| I feel like people will still want to use their own
| runtimes but idk
| flohofwoe wrote:
| What type of strings though? Exposing Javascript string objects
| in WASM doesn't make much sense if the code is expecting C
| strings for instance. Same for other languages, those all have
| their own incompatible internal representations for strings.
| The only somewhat interop-friendly string type is a zero-
| terminated bag of bytes, usually UTF-8 encoded (aka C strings),
| but that's a different string representation than Javascript
| uses.
|
| The Emscripten SDK offers helper functions to marshal high
| level data types like Javascript strings to UTF-8 encoded C
| strings on the WASM heap and back to JS, so it's not that bad.
|
| DOM access can be achieved with helper libraries which call out
| into JS. And since any sort of DOM manipulation is extremely
| slow anyway there's not much of a performance difference even
| with the overhead of calling out from WASM into JS (which
| actually is quite fast nowadays).
| mamcx wrote:
| >What type of strings though?
|
| The good one!
|
| UTf-8, NOT null terminated, pascal like.
|
| ie: what rust have:
|
| https://doc.rust-lang.org/std/string/struct.String.html
|
| REPEAT the mistakes of C (and considering the security angle!
| in a browser!) must be a big no.
| flohofwoe wrote:
| This would still require conversion from and to Javascript
| strings, and doesn't help with any language compiled to
| WASM that isn't Rust. And it probably wouldn't even help
| Rust because such a native WASM string type would
| presumably live outside the WASM heap (because if the
| string data would be on the WASM heap, there's no need for
| a native string type).
| mamcx wrote:
| Any complex structure past int/floats requiere
| conversion. Heck, even floats and ints (for example:
| oCalm and anybody with more/less bits than JS).
|
| So, given this is a fact, the best course of action is
| chosen the most safe alternative.
|
| And for everyone else? Well an array of bits ant let the
| host/callers that are the only that know their own stuff
| deal with it.
|
| INCLUDING Js.
| pjmlp wrote:
| Unfortunely that is not what WASM designers decided when
| they went without memory tagging for linear memory
| segments.
|
| So you get all the fun to corrupt linear memory C style.
| flohofwoe wrote:
| I think if you're afraid of memory corruption inside the
| WASM heap, it's better to use Rust instead of C or C++.
| WASM's job is to prevent code inside the sandbox from
| escaping the sandbox, not to prevent memory corruption
| inside the sandbox.
| pjmlp wrote:
| > I think if you're afraid of memory corruption inside
| the WASM heap, it's better to use Rust instead of C or
| C++.
|
| Agreed, but as consumer from WASM modules that isn't your
| option to make.
|
| > WASM's job is to prevent code inside the sandbox from
| escaping the sandbox, not to prevent memory corruption
| inside the sandbox.
|
| That is not better than a typical OS process, just it
| happens to be randomly downloaded into my computer.
| skitter wrote:
| Afaik for the WebAssembly MVP, the goal was to have a simple,
| efficient compile target - therefore only integers and floats.
| To make wasm more useful & easier to integrate, the plan calls
| for interface types[0], which allow both accessing complex (JS)
| objects and calling browser APIs.
|
| [0] https://github.com/WebAssembly/interface-
| types/blob/master/p...
| recursivedoubts wrote:
| interesting, thank you
| runnerup wrote:
| thank you
| franz899 wrote:
| WebAssembly's purpose was never to replace JavaScript but only
| to speed up certain parts of a website/app.
| recursivedoubts wrote:
| that's not how I remember it:
|
| https://brendaneich.com/2015/06/from-asm-js-to-webassembly/
|
| edit: from the linked article, in case it isn't clear, an HN
| comment by eich:
|
| _" Sure, in userland many languages compile to assembly.
| Hmm, where have I heard that word lately?"_[1]
|
| [1] - https://news.ycombinator.com/item?id=9554914
| pjmlp wrote:
| That was the original message used to sell WebAssembly,
| however when the real goal is to replace ActiveX, Flash,
| Silverlight and PNaCL it was obvious that it would grew
| beyond that.
| TazeTSchnitzel wrote:
| The difficulty is inherent; C, C++ and so on live in a very
| different world to JavaScript. Whether or not WebAssembly had
| direct interaction with JavaScript objects at launch or not,
| writing bridging code would still be tedious.
|
| But there's no reason you must write this yourself. Others have
| done the hard work for you and written libraries.
| vitiral wrote:
| This is exactly the kind of tutorial I've been waiting for for
| years. The way blocks and breaks work is especially non-intuitive
| if you are used to either assembly or regular languages, and you
| START with it. Good work, really loving this tutorial!
| jgrahamc wrote:
| If you'd like to try (multiplayer) Doom in WASM there's
| https://silentspacemarine.com/
| Mizza wrote:
| If anybody wants to play some Deathmatch:
| https://silentspacemarine.com/dbee695faaa29aefe9a14d5798689e...
| pjmlp wrote:
| An old port for PNaCL is available here, https://doom.pdox.net.
| devwastaken wrote:
| Very nice. I like these tutorials showing the nuts and bolts of
| wasm and C without just throwing it at emscripten toolchain.
|
| I'm curious if there's perf differences between canvas and webgl
| canvas. This project uses just canvas, but iirc passing frames to
| be rendered by webgl is faster. Perhaps I'm wrong in this
| context.
|
| I also don't see threading in here. Makes sense for a demo, but
| if this were to be used performantly you'd have to throw it all
| in a webworker so it doesn't block the main thread. This is one
| point of contention with wasm because it's not straightforward to
| render to a canvas/webgl on the main thread from a worker thread.
| OffscreenCanvas is one workaround but not supported by FF or
| safari.
| pjmlp wrote:
| Pity that WebAssembly Studio development seems to have stalled.
|
| https://webassembly.studio/
|
| It is the easiest way to get into WASM.
|
| Threading requires sending custom headers by the way.
| dQw4w9WgXcQ wrote:
| Any thoughts on how you could revive it?
| pjmlp wrote:
| By having someone to pay me a proper salary. I don't do
| charity.
| pjc50 wrote:
| Given that
|
| > Doom has a global variable screens[0] which is a byte array
| of SCREENWIDTH*SCREENHEIGHT, i.e. 320x200 with the current
| screen contents.
|
| It would seem to me that the right approach would be to hoist
| out Doom's main loop so you just have a renderFrame() function,
| then put something on the main browser thread to "blit" the
| image into the canvas itself.
| dividuum wrote:
| As you wrote "the right approach would be", I'll add: That's
| exactly what the code does.
| throw_m239339 wrote:
| Seems to me the original rendering pipeline wasn't GPU based.
| The author is just dumping whatever the game renders in a
| canvas element, there is no need for webgl for that.
|
| Also Canvas is getting some GPU acceleration in some browsers:
|
| https://developers.google.com/web/updates/2012/07/Taking-adv...
| djhworld wrote:
| There's also the problem of getting keyboard input in and out
| of the web worker in a performant manner.
|
| I tried this a few years ago with a Gameboy emulator I had
| ported from Go to webassembly and used web workers to run the
| emulator in.
|
| Getting the keyboard input in, in a performant way was a real
| struggle using postMessage, although I'll admit I'm not the
| best at web programming so someone more skilled might have been
| able to do it better
| [deleted]
| sitkack wrote:
| Why this arch over having the UI run in the main thread and
| sending events _into_ the wasm worker?
| asiachick wrote:
| You could pass it via a SharedArrayBuffer
| plopz wrote:
| From what I found on MDN "a side effect to the block in one
| agent will eventually become visible in the other agent",
| what does the word eventually mean there, what's going on
| under the hood?
| hoten wrote:
| Could I buy the author some headphones, I'd really like to see
| how they would port audio :)
|
| note on controls: 'ctrl' is a bad choice because ctrl + up/down
| on mac map to window management shortcuts, making the game
| unplayable.
| innocenat wrote:
| While I think this is nice, the tutorial is almost entirely
| unreadable on mobile.
| leeoniya wrote:
| sorry if the answer is to read the whole series (i only read part
| 4), but is there a comparison of this hand-optimized route vs
| what emscripten outputs (in terms of binary size an browser
| perf)?
|
| i assume a proper emscripten comparison would also need to strip
| networking & audio output.
| Mizza wrote:
| I love seeing this kind of tutorial, that isn't just a step-by-
| step guide, but also an exploration of the thought process and
| trial-and-error that goes on in crafting each step, so thanks for
| sharing.
|
| Looks like a lot of the work on the Doom port
| (https://github.com/diekmann/wasm-fizzbuzz/tree/main/doom) is
| about getting common functions from the C standard library to
| work in WASM. Surely this seems like a good opportunity for a new
| Free Software initiative - something optimized, properly
| licensed/credited and easy for everybody to use?
| AlecMurphy wrote:
| Nice read! I ported DOOM to TempleOS about a week ago.
|
| https://git.checksum.fail/alec/chocolate-doom
| bilg21 wrote:
| Doing the gods work, or the devil's work. I'm a little confused
| here.
| xcambar wrote:
| Jumping from FizzBuzz to Doom is quite the leap!
|
| It reminded me of the meme "howbro draw an owl": 1. Draw 2
| circles 2. Draw the rest of the f**ing owl
___________________________________________________________________
(page generated 2021-07-14 23:00 UTC)