-
Notifications
You must be signed in to change notification settings - Fork 486
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
Comments
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). |
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). |
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 |
Thanks so much for the explanation! The solution that you posted seems great. I'll close the issue. |
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. ;) |
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!
The text was updated successfully, but these errors were encountered: