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

Framebuffer Ping-Ponging #66

Closed
mhalber opened this issue Aug 9, 2018 · 5 comments
Closed

Framebuffer Ping-Ponging #66

mhalber opened this issue Aug 9, 2018 · 5 comments

Comments

@mhalber
Copy link

mhalber commented Aug 9, 2018

Hello,

A common way to implement the gaussian blur in OpenGL/GLSL is to setup ping-ponging framebuffers and apply horizontal and vertical blurs with fixed width kernel repeatedly (ref).

Attempting to implement such setup in sokol seems to be quite tricky. While it is possible to change the input texture by setting .fs_images[i] variable of sg_draw_state object, it seems to be impossible to change the output framebuffer, as it is only set when creating sg_pass object, and setting color attachements. As such I don't really see a way to setup buffer ping-ponging in sokol, other than a) injecting openGL or b) creating and destroying pass object on the fly.

My questions are then - have I missed anything and there is in fact a way to set up the ping-ponging framebuffer? Otherwise, given that buffer ping-ponging is relatively common operation, should it be possible to express that operation in sokol without injecting gl code.

Thanks!

@floooh
Copy link
Owner

floooh commented Aug 9, 2018

You're on the right track. You need 2 textures setup as render targets, and 2 pass objects using those textures as framebuffer. I was considering making pass render targets 'rebindable' similar to the sg_draw_state bind slots but decided against it for now for various implementation detail reasons (for instance on D3D11 the image object would need to own the RenderTargetView or DepthStencilView, not the pass object, or alternatively, the View objects would need to be created on the fly etc etc etc...), none of the solution looked very nice to me.

Also all the validation can happen in sg_create_pass() (e.g. that all render target have the sample multi-sample count, pixel format, size etc...), instead of in sg_begin_pass().

So it would basically look like this:

sg_pass pass[2];
sg_image img[2]
void init() {
    ....
  sg_image_desc img_desc = { .render_target = true, ... };
  for (int i = 0; i < 2; i++) {
    img[i] = sg_make_image(&img_desc);
    pass[i] = sg_make_pass(&(sg_pass_desc) { .color_attachment[0].image = img[i] });
  }
  ...
}

void frame() {
  ....
  // offscreen ping-pong rendering
  sg_begin_pass(pass[frame_count % 2], &pass_action);
  draw_state.fs_image[0] = img[(frame_count + 1) % 2];
  sg_apply_draw_state(&draw_state);
  sg_draw(...);
  sg_end_pass();
  ...
}

(you'd need to handle the first frame as special case though, since the images will have undefined content initially).

@floooh
Copy link
Owner

floooh commented Aug 9, 2018

PS: IMHO the only reason to implement a similar 'rebinding' on an existing pass like in sg_draw_state would be to avoid a combinatorial explosion, if you have many different render-target combinations for MRT rendering. But my thinking was that usually there's much fewer passes happening per frame then draw calls, and the different pass configurations should be fairly 'rigid' The only exception would be if you have hundreds of per-object dynamically rendered textures, but even then one or two pass objects per object isn't too bad, as they should be much more light-weight than for instance the texture(s) used as render target, so creating hundreds of thousands of pass objects shouldn't be too bad (but trying to render hundreds of passes each frame probably isn't a good idea).

@floooh
Copy link
Owner

floooh commented Aug 9, 2018

PPS: here's a ping-pong-rendering sample from Oryol: the basic ideas also translate to sokol-gfx: https://github.com/floooh/oryol/blob/master/code/Samples/InfiniteSpheres/InfiniteSpheres.cc

@mhalber
Copy link
Author

mhalber commented Aug 9, 2018

Thanks so much for the explanation! The solution that you posted seems great. I'll close the issue.

@mhalber mhalber closed this as completed Aug 9, 2018
@tomas
Copy link

tomas commented Jan 3, 2023

Hi @mhalber, I know it's been a while but I was wondering if you managed to get this working and, if possible, if you have a working example to show. I've been trying to get a simple gaussian blur demo to work (draw image to offscreen texture, then perform ping-pong blurring and finally render to screen) but all I get is a black screen. :)

PS: @floooh it would be really great to have something like this in the sokol-samples repo. ;)

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

No branches or pull requests

3 participants