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

Updated WebGPU #11067

Merged
merged 15 commits into from May 15, 2020
Merged

Updated WebGPU #11067

merged 15 commits into from May 15, 2020

Conversation

Tandaradei
Copy link
Contributor

@Tandaradei Tandaradei commented May 2, 2020

WIP
Related issue: #11007

  • Updated webgpu.h from webgpu-native (with changes like adding Reference/Release methods)
    • There some parts (functions on Adapter, Instance, Surface etc) that I just added as a comment, because I wasn't sure how they should be implemented. For example I haven't found anything on Surface/Instance in the specification.
  • Manually updated WebGPU part of struct_info.json (couldn't figure out how to use the generator)
  • Updated library_webgpu.js
    • Renamed all binding/bindings to entry/entries in wgpuDeviceCreateBindGroupLayout and wgpuDeviceCreateBindGroup
    • Added functions for QuerySet
    • Renamed all two part 64bit integers from <name>_l/<name>_h to <name>_low/<name>_high to match defineI64Param and receiveI64ParamAsI32s
    • Added size parameter to setIndexBuffer and setVertexBuffer
    • Changed default/required PresentMode from VSync to Fifo

I tested the changes with my pet project (https://github.com/Tandaradei/webgpu-wasm/tree/new-webgpu-version) which works fine in Chrome Canary 84.0.4133.0, but doesn't work in Firefox Nightly 77.0a1 (TypeError: buffer.mapWriteAsync is not a function,_wgpuBufferMapWriteAsync).
The project isn't using all the features from WebGPU so I'm not sure if everything works (for example the new QuerySet).

@welcome
Copy link

welcome bot commented May 2, 2020

Thank you for submitting a pull request! If this is your first PR, make sure to add yourself to AUTHORS.

@kainino0x kainino0x self-requested a review May 2, 2020 20:33
@juj
Copy link
Collaborator

juj commented May 4, 2020

Hey, really cool to notice you are writing a bachelor's thesis about WebGPU @Tandaradei!

I have been trying to find a good stretch of time from other fronts to jump in to reviewing WebGPU as well. There are some hot questions we are pondering here at Unity:

  1. What will the code size difference be between a WebGL 2-enabled renderer vs a WebGPU-enabled renderer? The API is a bit verbose in comparison to WebGL 2, making me wonder how it will translate to delivery size, especially on really small renderers.
  2. Operating the WebGL 2 API is JavaScript garbage free at rendering time, meaning that calling the API functions will not cause temporary JS garbage units to be generated (in the hot paths/per-frame loop). JS GCs that stemmed from produced WebGL 1 garbage caused annoying stuttering with Unreal Engine 3 and 4 back in the day. Looking at the current library_webgpu.js implementation we have, there are a lot of places where it trashes. I wonder if those places will all be either cold, or if Emscripten layer will then be able to pool up all the JS objects to avoid trashing, so that WebGPU execution will also be garbage free at rendering time.
  3. What will the main thread JS CPU utilization % be like for WebGPU vs WebGL 2?
  4. What will the overall system Watts consumption be like for WebGPU vs WebGL 2?
  5. How well does WebGPU execute in practice on avoiding general per-frame stalling/stuttering (due to shader compilation/texture/buffer upload delays etc. that WebGL 2 had)?

Perhaps some of those perspectives may be interesting for your research as well :) If you end up producing data points, would be curious to read!

Great work with getting on top of WebGPU with Emscripten!

@kainino0x : on the note of point 5 above: is there any machinery to query if one is getting WebGPU-on-top-of-Vulkan vs WebGPU-on-top-of-GLES2/3 in a browser? I'd imagine e.g. shader compilation performance (and performance overrall..) will still be quite bad if browser needs to fall back to a GLES backend?

@Tandaradei
Copy link
Contributor Author

Hey @juj,

I will be completely honest with you, I have no answer for any of your questions.
I like graphics programming and wanted to my bachelor thesis on something related to it. I have never done a GPU renderer before and have never even come close to WebGL, so I'm far from expert or even proficient on any of this topics. I started with the practical part of the thesis with implementing a (very simple) renderer to get a feeling for WebGPU and now I will slowly transition to the theoretical part.
I will take your points as inputs for my research but don't expect too much, I don't think my research will be as deep and detailed as you need it to be.

Does somebody know why there are 3 checks failing? From the error messages it seems like something WASM/SIMD related, but I have no idea what caused this to fail or how to fix it.

@sbc100
Copy link
Collaborator

sbc100 commented May 4, 2020

There was some recent SIMD failures due to opcode renumbering that are not related to this PR.

I think just re-basing your change to origin/master (past #11058) should help

@kainino0x
Copy link
Collaborator

@kainino0x : on the note of point 5 above: is there any machinery to query if one is getting WebGPU-on-top-of-Vulkan vs WebGPU-on-top-of-GLES2/3 in a browser? I'd imagine e.g. shader compilation performance (and performance overrall..) will still be quite bad if browser needs to fall back to a GLES backend?

By default WebGPU will most likely always be on Vulkan/D3D12/Metal (it is right now). If there ends up being a GL backend it will probably require an explicit "compatibility profile" flag.

2. Looking at the current library_webgpu.js implementation we have, there are a lot of places where it trashes. I wonder if those places will all be either cold, or if Emscripten layer will then be able to pool up all the JS objects to avoid trashing, so that WebGPU execution will also be garbage free at rendering time.

This is an improvement I've been thinking about for the long term. Right now most of the garbage-heavy entry points are relatively cold, but we still have the inherent garbage from the API of bind group creation and command encoder / pass / command buffer creation, so I'd like the group to finish discussing that topic first (e.g. gpuweb/gpuweb#214).

@kainino0x
Copy link
Collaborator

Re-merged master into your branch because somehow the diff was including commits from master.

Copy link
Collaborator

@kainino0x kainino0x left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM.
It would be ideal if we could include at least one more change: the refactor of WGPUShaderModuleDescriptor. Without this it won't be possible for an app to build the same code against both Dawn and Emscripten. (There may be other issues I'm missing, but this is the most noticeable.)

system/include/webgpu/webgpu.h Outdated Show resolved Hide resolved
src/library_webgpu.js Show resolved Hide resolved
src/library_webgpu.js Outdated Show resolved Hide resolved
src/library_webgpu.js Outdated Show resolved Hide resolved
src/library_webgpu.js Outdated Show resolved Hide resolved
src/struct_info.json Outdated Show resolved Hide resolved
src/library_webgpu.js Outdated Show resolved Hide resolved
src/library_webgpu.js Outdated Show resolved Hide resolved
- Changed 'const * nextInChain' to 'chain' for chained descriptors
- Removed unnecessary structs/enums for web
- Changed wgpuDeviceGetDefaultQueue so it returns the same queue
     when called multiple times with the same device
- Changed makeCheckDescriptor to also work with 'chain' member (hacky)
src/library_webgpu.js Outdated Show resolved Hide resolved
src/library_webgpu.js Outdated Show resolved Hide resolved
Copy link
Collaborator

@kainino0x kainino0x left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the revisions!

src/library_webgpu.js Show resolved Hide resolved
@kainino0x
Copy link
Collaborator

It would be ideal if we could include at least one more change: the refactor of WGPUShaderModuleDescriptor. Without this it won't be possible for an app to build the same code against both Dawn and Emscripten. (There may be other issues I'm missing, but this is the most noticeable.)

I'd still like to resolve this one before merging (I could take care of it if needed).

@Tandaradei
Copy link
Contributor Author

It would be ideal if we could include at least one more change: the refactor of WGPUShaderModuleDescriptor. Without this it won't be possible for an app to build the same code against both Dawn and Emscripten. (There may be other issues I'm missing, but this is the most noticeable.)

I'd still like to resolve this one before merging (I could take care of it if needed).

So no more code/codeSize in WGPUShaderModuleDescriptor? And it chains to a specific (SPIRV/WGSL) shader module descriptor? Like the surface descriptors?

What has to be done to finish this up? :)

PS: Why is there no size member in WGPUShaderModuleWGSLDescriptor ?

@kainino0x
Copy link
Collaborator

So no more code/codeSize in WGPUShaderModuleDescriptor? And it chains to a specific (SPIRV/WGSL) shader module descriptor? Like the surface descriptors?

Yup, exactly. Sorry, I should point to an example.
https://cs.chromium.org/chromium/src/third_party/dawn/src/utils/WGPUHelpers.cpp?l=54&rcl=94efed23e7fb262bfcadb0dace5a873a7abfdb07

What has to be done to finish this up? :)

  • Remove code/codeSize from WGPUShaderModuleDescriptor in header and struct_info
  • Deconstruct the SPIRV chained object in wgpuDeviceCreateShaderModule
  • Optionally also support the WGSL chained object

PS: Why is there no size member in WGPUShaderModuleWGSLDescriptor ?

WGSL is text so it's passed as a null-terminated string.

@Tandaradei
Copy link
Contributor Author

Yup, exactly. Sorry, I should point to an example.
https://cs.chromium.org/chromium/src/third_party/dawn/src/utils/WGPUHelpers.cpp?l=54&rcl=94efed23e7fb262bfcadb0dace5a873a7abfdb07

In your linked example, shouldn't there be a ChainedStruct wrapped around the pointer to the SPIRV descriptor?
In my understanding it should look like this (C instead of C++):

WGPUShaderModuleSPIRVDescriptor sm_desc = {
  .codeSize = spv_source_size / sizeof(uint32_t),
  .code = (const uint32_t*)spv_source_data
};
WGPUShaderModuleDescriptor sm_wrapper = {
  .nextInChain = &(WGPUChainedStruct){
    .next = (WGPUChainedStruct const*)&sm_desc,
    .sType = WGPUSType_ShaderModuleSPIRVDescriptor
  },
};
WGPUShaderModule module = wgpuDeviceCreateShaderModule(device, &sm_wrapper);

@kainino0x
Copy link
Collaborator

It's not exactly like your C code. Sorry, that example used the C++ wrapper so it's not exactly the same. Here's another example which I forgot about:
https://cs.chromium.org/chromium/src/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc?l=21&rcl=a47ddf858f207179e5a179b73c4042d690e76823
Hopefully this is more helpful.

Copy link
Collaborator

@kainino0x kainino0x left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(tiny formatting nits, will apply them myself)

src/library_webgpu.js Outdated Show resolved Hide resolved
src/library_webgpu.js Outdated Show resolved Hide resolved
@kainino0x
Copy link
Collaborator

Since I don't have any good test cases for this, let me see if I can find someone to try this out on their codebase to make sure everything seems working before landing :)

@@ -559,7 +584,6 @@ var LibraryWebGPU = {
var desc = {
"label": undefined,
"size": WebGPU.makeExtent3D(descriptor + {{{ C_STRUCTS.WGPUTextureDescriptor.size }}}),
"arrayLayerCount": {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureDescriptor.arrayLayerCount) }}},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be removed for now, it isn't part of the PSA we sent, and it breaks the possibility to have applications that target both Dawn and emscripten at the same time. It was found by @hugoam.

@@ -1909,7 +1925,6 @@
"usage",
"dimension",
"size",
"arrayLayerCount",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@hugoam
Copy link
Contributor

hugoam commented May 10, 2020

To be discussed with @kainino0x and @Kangz
But eventually, if Emscripten wants to stay compatible with Dawn's headers (which is necessary to be compatible with webgpu_cpp so-far provided only by Dawn), I isolated the necessary fixes that must be applied to this PR: hugoam@d549969
This reverts almost all the occlusion query work. Unfortunately we can't keep it if we want to use Dawn's header, since it doesn't exist there yet. We can't either keep it in library_webgpu.js because the library compiler tries to compile it against non-existing structs (commented out for now in struct_info.json because they don't exist in Dawn's webgpu.h)

Aside from that, and with those fixes, the PR works as expected
My personal advice would be: keep the occlusion query work in a separate branch until Dawn implements it, and add it only then. It seems unlikely that any other implementer would have occlusion queries before Dawn anyway ?

@Kangz also mentioned the possibility of integrating webgpu_cpp.cpp back into Emscripten, as was done in a previous iteration. This would at least ensure that an Emscripten app can be compiled against WebGPU C++ API without this kind of incompatibility issues arising.

@juj
Copy link
Collaborator

juj commented May 10, 2020

My personal advice would be: keep the occlusion query work in a separate branch until Dawn implements it, and add it only then.

Is this a case where the spec headers already define upcoming work (occlusion queries have already been added to the spec and headers?), but Dawn hasn't just implemented them? Do we expect that the content in the headers will stay the same?

If so, then let's not delete valid work that has already been taken, but instead can add comments to webgpu.h and library_webgpu.js along the lines of // note: no backend implementation available, not yet tested. That way once Dawn does add them, there is no need to take action to add the support, but can just remove the comments once someone gets around to verifying the code paths.

If on the other hand that is work that is not likely to stay the same, then dropping it sounds viable?

@hugoam
Copy link
Contributor

hugoam commented May 10, 2020

The problem is that there currently exists no other webgpu_cpp implementation than the one in Dawn. So the only way Emscripten slightly supports an application written against a C++ API of WebGPU, as it does not provide its own, is by sticking to Dawn's version of the webgpu.h header. (which is what Emscripten own header is, historically, until that PR) Even though writing that wrapper is a simple task that can be largely automated, Dawn is the only one to provide one for now.

If this PR is merged as-is, my application will not be able support WebGPU through Emscripten anymore, because it is built against the C++ API. Some potential ways to solve this:

  • one option is for Emscripten to provide a version of webgpu_cpp that works with the webgpu.h from webgpu-native (which would allow you to keep the Occlusion Query work, but has a cost)
  • another option is to stick to Dawn's version of webgpu.h, which prevents the Occlusion Query work to go in as well

(Note that the library that I ported plans to use the C API at some point, but work needs to be done, and it won't be ready before a while)

@juj
Copy link
Collaborator

juj commented May 11, 2020

Hmm, if I understood the situation correctly, it does seem like the best way forward would be to include webgpu_cpp into this repository that'd match webgpu.h, having API dependencies to external code does seem awkward.

Even though writing that wrapper is a simple task that can be largely automated, Dawn is the only one to provide one for now.

Do you know if Dawn autogenerates its webgpu_cpp wrapper? Or is it all currently hand-maintained?

@Kangz
Copy link
Contributor

Kangz commented May 11, 2020

Do you know if Dawn autogenerates its webgpu_cpp wrapper? Or is it all currently hand-maintained?

All of webgpu.h, webgpu_cpp.h, webgpu_cpp.cpp and parts of library_webgpu.js and struct_info.json are autogenerated from these templates and dawn.json. We have a patch to apply to generate "upstream" webgpu-native/webgpu-header's webgpu.h and maybe @kainino0x has a patch to apply to generate the emscripten parts.

@hugoam
Copy link
Contributor

hugoam commented May 11, 2020

Would it by thinkable to add some fields in dawn.json so that both webgpu-native and dawn's flavor can be generated from the same file, instead of patching it ?
e.g "visibility": "dawn" and "visibility": "webgpu-native" for fields, classes and functions that belong exclusively (or temporarily) to one or another ?
I could even try that approach on my local copy and submit a cl, maybe, if you think it's a valid approach

Practical example (bindings and binding count are only visible in Dawn for backwards compatibility, but aren't in webgpu-native):

    "bind group layout descriptor": {
        "category": "structure",
        "extensible": true,
        "members": [
            {"name": "label", /*...*/},
            {"name": "binding count", "visibility": "dawn", /*...*/},
            {"name": "bindings", "visibility": "dawn", /*...*/},
            {"name": "entry count",  /*...*/},
            {"name": "entries", /*...*/}
        ]
    },

@Kangz
Copy link
Contributor

Kangz commented May 11, 2020

I'm not too keen on adding conditionals to dawn.json like this. Instead webgpu-native should probably have its own copy of the generator. When WebGPUv1 is out, there will be less issues like this with backwards incompatible changes.

@kainino0x
Copy link
Collaborator

Thanks for the patch Hugo, I'm going to make some tweaks to it and push it to this branch. I think we'll be ready to merge then. (I may not be able to get this done today, we'll see.)

@Kangz
Copy link
Contributor

Kangz commented May 11, 2020

Ah, @hugoam added back some things so webgpu_cpp.cpp compiles. That explains the question about having Dawn support visibilities in dawn.json. We need to figure out the exact details, but maybe we could have best effort annotations that make it generate a webgpu_cpp that matches the current emscripten. (that would only be needed until WebGPU v1, and maybe while working on WIP extensions).

@kainino0x
Copy link
Collaborator

Ohh I see. I guess we should just exactly match Dawn here for the moment then.

@kainino0x
Copy link
Collaborator

kainino0x commented May 11, 2020

@hugoam I merged your changes and added an extra commit on top. Could you review and verify my changes? 5f83f1f

@kainino0x
Copy link
Collaborator

kainino0x commented May 11, 2020

Sorry, realized that change wouldn't compile with webgpu_cpp.cpp (I ctrl-f'd wrong the first time).

f494f63 now.

@kainino0x
Copy link
Collaborator

BTW I think we should put webgpu_cpp in both webgpu-headers and Emscripten eventually, but we'll do that later.

Copy link
Contributor

@hugoam hugoam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fixes ! Unfortunately although it should compile, I'm expecting it to fail at runtime because of this the missing fields in struct_info.json (see below)

src/struct_info.json Show resolved Hide resolved
@kainino0x
Copy link
Collaborator

The list of members in struct_info is not enough to compute the offsets (it doesn't know the types). I think how this works is it calls offsetof in C and saves the result. So I'm pretty sure this still would work.

@hugoam
Copy link
Contributor

hugoam commented May 11, 2020

Ahhh, I must have conflated some of the errors I faced when trying to get this to work with an overly naive explanation of how Emscripten works then ! I suppose it's all good in that case

@kainino0x kainino0x merged commit 9010921 into emscripten-core:master May 15, 2020
@hugoam
Copy link
Contributor

hugoam commented May 15, 2020

Now Dawn has just removed the deprecated fields. But we'll do a follow-up PR I suppose 😄

@kainino0x
Copy link
Collaborator

Yup, we knew we would need another PR here :)

I wanted to get this landed as we're about to start removing the deprecated fields from Blink as well, so they won't be exposed to JS anymore, and this patch is needed for Emscripten'd content to work on Chrome.

@hugoam
Copy link
Contributor

hugoam commented May 15, 2020

Just tried building bgfx examples with Emscripten@master and it works as expected 😄
(the up to date links are at bkaradzic/bgfx#2023)

@kainino0x
Copy link
Collaborator

Awesome!

@Tandaradei Tandaradei deleted the fix/update-webgpu branch May 16, 2020 10:18
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

6 participants