pex-gl / pex-context

Modern WebGL state wrapper for PEX: allocate GPU resources (textures, buffers), setup state pipelines and passes, and combine them into commands.
http://pex-gl.github.io/pex-context/
MIT License
160 stars 12 forks source link

Multisampled framebuffer support #115

Open vorg opened 2 years ago

vorg commented 2 years ago

Is available in WebGL 2

Example usage renderbufferStorageMultisample + blitframebuffer: https://stackoverflow.com/a/55976760/1527470

vorg commented 2 years ago

Question about pex-context syntax though : is it fbo.blit(anotherFbo) or ctx.blit(fbo1, fbo2) We don’t really have resource class methods, there some but hidden like _dispose and you still do ctx.dispose(texture)

e.g. webgpu

const encoder = device.createCommandEncoder();
encoder.copyBufferToBuffer(srcBuffer, 0, dstBuffer, 0, 4);

Which would suggest ctx.blit(fbo1, fbo2) syntax.

But the thing is we don’t expose fbos…we just have passes...so maybe it’s actually

ctx.pass({
   color: [ colorTexture ],
   numSamples: 16 //auto allocate render buffer matching texture size, blit and resolve on pass end
}}

A bit automagic but it’s not like we blit fbos left and right outside of this single usecase ever.

Or even better:

ctx.pass({
   //auto allocate render buffer matching texture size, blit and resolve on pass end
   color: [ { texture: colorTexture, numSamples: 16 } ]
}}
vorg commented 2 years ago

Live example here https://codesandbox.io/s/webgl-multi-sampled-mrt-fbos-1vhkif

vorg commented 2 years ago

https://github.com/mrdoob/three.js/issues/23300#issuecomment-1100666026

Some notes (I'll repeat the obvious for the sake of being on the same page): • as mentioned above, multi-sampling for data textures is prone to error although invaluable for anything used to render to screen (i.e. your usual PBR result in slot 0, vertex colors or ids in slot 1 for selective post-processing) • all attachments (color or depth, etc.) of a multi-sampled FBO must be multi-sampled with the same number of samples • attachments of a multi-sampled FBO like renderBuffers or textures cannot be read from directly, they must be downsampled via blitFramebuffer before use. This includes methods like readPixels • blitFramebuffer can only copy one color attachment between FBOs at a time (one to all of another -- see issue 12 https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_framebuffer_blit.txt). This is an implementation detail, but worth noting as I did in my demo

CodyJasonBennett commented 2 years ago

Spotted this from the three issue tracker.

If you need a more complete example as far as reviews made in three, see this gist which forgoes temporary FBO attachments when blitting and instead disassembles/reconstructs attachments https://gist.github.com/CodyJasonBennett/edbc4372d3c9a921ebc3e46cb5899ba8. This is less clean, but much more memory efficient.

Regarding the API, blit can copy any frame buffer -- whether that be user-created or native to the underlying canvas implementation. There might be a consideration for how one would copy to/from the canvas with this API. This is useful for where you might want to sample depth from a forward pass, often done in hybrid/forward+ rendering setups.

A constraint in WebGPU is that the mesh pipeline would also be multi-sampled, so this would not be isolated to the render passes. I'm not very familiar with Pex's internals, but this can be tricky to deal with from a design perspective.

vorg commented 2 years ago

There is also in issue the blitFramebuffer can copy only one renderbuffer at the time although (manually) fixable. That's another vote for hiding complexity inside pex-context pass()

To do multiple ones, you need to do a Blit for each buffer, changing your READ_BUFFER for each buffer you want to blit, and select the corresponding draw buffer of the draw framebuffer. (source)