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

In OpenGL backend, attempting to render to a multisampled texture with the usages RENDER_ATTACHMENT | TEXTURE_BINDING fails #6084

Closed
RedMindZ opened this issue Aug 6, 2024 · 5 comments
Labels
api: gles Issues with GLES or WebGL area: validation Issues related to validation, diagnostics, and error handling

Comments

@RedMindZ
Copy link

RedMindZ commented Aug 6, 2024

Description
When creating a multisampled texture with the usages TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING and rendering to it with the OpenGL backend, rendering fails, the screen remains black, and the following errors are logged by wgpu:

[2024-08-06T15:51:22Z ERROR wgpu_hal::gles] GLES: [API/Error] ID 1280 : 
GL_INVALID_ENUM error generated. <target> enum is invalid; expected GL_TEXTURE_2D_MULTISAMPLE or GL_PROXY_TEXTURE_2D_MULTISAMPLE.
[2024-08-06T15:51:22Z ERROR wgpu_hal::gles] GLES: [API/Error] ID 1286 : 
GL_INVALID_FRAMEBUFFER_OPERATION error generated. Operation is not valid because a bound framebuffer is not framebuffer complete.
[2024-08-06T15:51:22Z ERROR wgpu_hal::gles] GLES: [API/Error] ID 1286 : 
GL_INVALID_FRAMEBUFFER_OPERATION error generated. Operation is not valid because a bound framebuffer is not framebuffer complete.

Note that there is no crush, it simply appears that the render pass is aborted.

Repro steps
I have created a simple example here.
The example is based on the hello_triangle example of wgpu.
In the example, we attempt to render the triangle to a multisampled texture in the first render pass, and then perform a second render pass to load pixels from the multisampled texture and output them to the surface texture.
The important lines of main.rs are as follows:

  • Line 19: here we set the backend to OpenGL. The example works fine when changing this to Vulkan or DX12.
  • Lines 89-93: sets the pipeline of the first render pass to use a multisampled texture.
  • Line 107: sets the bindgroup of the texture to use a multisampled texture.
  • Line 153: sets the texture's sample count to 4, turning it into a multisampled texture.
  • Line 156: sets the texture's usages to both RENDER_ATTACHMENT and TEXTURE_BINDING.
  • Lines 215-232: executes the first render pass, rendering the triangle to the texture.
  • Lines 235-254: executes the second render pass, rendering the texture to the output surface.

Expected vs observed behavior
Given that this setup works in Vulkan and DX12, I expected this to work with GL as well.
When changing lines 89-93, 107, 153 to use a single sample instead (aka, a non-multisampled texture), and changing line 14 in blit.wgsl to use texture_2d instead of texture_multisampled_2d this example works fine.

Platform
OS: Window 10
GPU: Nvidia GTX 1080
wgpu: 22.1.0

@Wumpf
Copy link
Member

Wumpf commented Aug 6, 2024

Thank you so much for diving deep and providing a repro case, but I'm pretty certain this is the same as this issue

In GL backend, we can't create an MSAA-enabled texture if it's not a pure render target.

wgpu is lacking the validation & downlevel feature to express this and that's what above linked issue is about

@Wumpf Wumpf closed this as not planned Won't fix, can't repro, duplicate, stale Aug 6, 2024
@Wumpf Wumpf added api: gles Issues with GLES or WebGL area: validation Issues related to validation, diagnostics, and error handling labels Aug 6, 2024
@RedMindZ
Copy link
Author

RedMindZ commented Aug 6, 2024

Thanks for linking that issue, they do seem to be the same.
Is there any workaround currently? I currently see the following options:

  1. Remove the extra usage flags, render to texture, resolve it, and then use the resolved texture. I would like to avoid this solution because it could cause a significant loss of visual quality for my application.
  2. Add an additional special code path for GL in all involved code, where if we are currently running GL, we will create a different texture/bindgroup, and after rendering we will copy the multisampled texture to a different multisampled texture with the appropriate flags, and continue normally from there. The problem here is that I suspect wgpu's validation layer will prohibit copying from a texture that doesn't have the COPY_SRC usage, even though GL allows it. Not to mention the burden of all of this special case code.

Neither of these solutions is particularly appealing to me. Is this limitation simply a shortcoming of wgpu's implementation, in which case I should probably fork it and maintain my own, or is it a fundamental limitation of GL, and I should just find a different rendering technique for my application that does not depend directly on multisampled textures?

@Wumpf
Copy link
Member

Wumpf commented Aug 7, 2024

@RedMindZ I think those are your option pretty much, yes. Not sure if adding COPY_SRC is a problem though.
I haven't investigated this myself but when we add these downlevel features then because it's a limitation of the backend itself. I suspect however that this is a limitation of GLES specifically and these days we're also using desktop OpenGL when possible, so I'm not sure if this limitation is universal. Unfortunately there don't seem to be any notes about this. Definitely worth looking deeper into and documenting.

In general, the OpenGL backend is not WebGPU compliant and not meant to be either. It's more of a fallback solution when all else fails because of either very old driver & hardware (on Apple Metal is always available and elsewhere Vulkan support is very widespread) or for running via WebGL in a browser that doesn't yet implement WebGPU. WebGPU is designed with Vulkan/Metal/DX12 in mind and this won't be the only unsupported thing you're hitting (although most things are now covered well enough by the feature/downlevel-feature system)
Depending on your application's requirements you may want to disable the GL backend altogether.

@Wumpf
Copy link
Member

Wumpf commented Aug 7, 2024

Hmm I searched a little bit and I think there's actually different bug here:
The target for tex_storage_2d_multisample here is never called with the right target - can't seen the code picking anywhere TEXTURE_2D_MULTISAMPLE.

This API is available on OpenGL 4.2 and GLES 3.1 so this should be supported in your case
Another bug in there probably: We assume all storage apis are available in 3.0, but this one is not according to https://docs.gl/es3/glTexStorage2DMultisample
In any case the downlevel feature is still needed for WebGL then which only has multisampled renderbuffers https://registry.khronos.org/webgl/specs/latest/2.0/#3.7.6

Updating the other ticket consequently. Contributions welcome ;)
I still stick with what I wrote earlier though: Expect more issues and consider setting a clear limit of what you want to support for your application. As you can see OpenGL support is very fragmented (this will STILL not work on some OpenGL versions/devices) and there's a minefield of these out there hidden.

@RedMindZ
Copy link
Author

RedMindZ commented Aug 7, 2024

Thank you so much for this gold mine of information!
Initially, I hoped to provide full support for all backends in my app to make it compatible with as many systems as possible, but now I think that I might disable some of the rendering features when running GL, or simply drop support for GL altogether.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: gles Issues with GLES or WebGL area: validation Issues related to validation, diagnostics, and error handling
Projects
Status: Done
Development

No branches or pull requests

2 participants