Skip to content
New issue

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

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

Already on GitHub? # to your account

WebGL2 rendering broken: correct transform are not used #9375

Closed
mockersf opened this issue Aug 6, 2023 · 4 comments · Fixed by #9383
Closed

WebGL2 rendering broken: correct transform are not used #9375

mockersf opened this issue Aug 6, 2023 · 4 comments · Fixed by #9383
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior O-WebGL2 Specific to the WebGL2 render API P-High This is particularly urgent, and deserves immediate attention
Milestone

Comments

@mockersf
Copy link
Member

mockersf commented Aug 6, 2023

Bevy version

main since #9254

[Optional] Relevant system information

On WebGL2, all browsers

What you did

Run one of the 3d examples, easily visible on the pbr example

What went wrong

Screenshot 2023-08-05 at 12 53 14
@mockersf mockersf added C-Bug An unexpected or incorrect behavior A-Rendering Drawing game state to the screen O-WebGL2 Specific to the WebGL2 render API labels Aug 6, 2023
@alice-i-cecile alice-i-cecile added the P-High This is particularly urgent, and deserves immediate attention label Aug 6, 2023
@alice-i-cecile alice-i-cecile modified the milestones: 0.11.1, 0.12 Aug 6, 2023
@superdump
Copy link
Contributor

I'll have a look and see if I can find out what's up.

@superdump
Copy link
Contributor

Well, my bad for testing the GpuArrayBuffer stuff on WebGL2 via applying the limits. I thought I’d tested it on web at some point and seen it work.

The problem is that WebGL2 GLSL only supports gl_InstanceID which is the index within the range of instances being drawn. So for example, if you’re drawing instances 10..12 in rust notation, the gl_InstanceID values would be 0..2.

naga and wgpu currently don’t implement any workaround for this shortcoming such that the wgsl instance_index builtin gets translated to plain gl_InstanceID. They would have to provide the base instance via a uniform and polyfill this into the shader.

As we’re doing one draw per instance at the moment, this would mean wgpu+naga would have to provide a new uniform per draw. I don’t know if it would do this via a buffer or using the direct uniform submission that exists in GL. Either way, it adds back at least some if not all of the per-draw binding overhead that GpuArrayBuffer and instance_index were trying to avoid.

One way that it would still be achieved on WebGL2 is when we get to the ‘encode instance index into the upper bits of the index buffer indices’ part of batching.

For now I suppose it’s going to be worth testing whether direct uniform submission by value is faster than rebinding a uniform buffer or updating its dynamic offset to see if it’s worth keeping the approach anyway. And a short term fix will be to basically have WebGL2 one way or another go back to a dynamic offset per MeshUniform. Sad.

@superdump
Copy link
Contributor

Talking with @cwfitzgerald it sounds like when instance_index is properly polyfilled in naga+wgpu then the uniform for the base index would always be pushed regardless of whether we use it or not, so we may as well use it.

@superdump
Copy link
Contributor

And while I was looking into implementing that in wgpu and naga, I noticed that push constants could be used as a workaround for now, as they are translated to uniforms, which is exactly what I would implement anyway. Just that the workaround introduces more ugliness into bevy. :/

github-merge-queue bot pushed a commit that referenced this issue Aug 9, 2023
…n WebGL2 (#9383)

naga and wgpu should polyfill WGSL instance_index functionality where it
is not available in GLSL. Until that is done, we can work around it in
bevy using a push constant which is converted to a uniform by naga and
wgpu.

# Objective

- Fixes #9375 

## Solution

- Use a push constant to pass in the base instance to the shader on
WebGL2 so that base instance + gl_InstanceID is used to correctly
represent the instance index.

## TODO

- [ ] Benchmark vs per-object dynamic offset MeshUniform as this will
now push a uniform value per-draw as well as update the dynamic offset
per-batch.
- [x] Test on DX12 AMD/NVIDIA to check that this PR does not regress any
problems that were observed there. (@Elabajaba @robtfm were testing that
last time - help appreciated. <3 )

---

## Changelog

- Added: `bevy_render::instance_index` shader import which includes a
workaround for the lack of a WGSL `instance_index` polyfill for WebGL2
in naga and wgpu for the time being. It uses a push_constant which gets
converted to a plain uniform by naga and wgpu.

## Migration Guide

Shader code before:

```
struct Vertex {
    @Builtin(instance_index) instance_index: u32,
...
}

@vertex
fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
...

    var model = mesh[vertex_no_morph.instance_index].model;
```

After:

```
#import bevy_render::instance_index

struct Vertex {
    @Builtin(instance_index) instance_index: u32,
...
}

@vertex
fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
...

    var model = mesh[bevy_render::instance_index::get_instance_index(vertex_no_morph.instance_index)].model;
```
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior O-WebGL2 Specific to the WebGL2 render API P-High This is particularly urgent, and deserves immediate attention
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants