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

Use Gaussian approximation for backbuffer mipmaps in GL Compatibility renderer #78168

Merged
merged 1 commit into from
Jul 12, 2023

Conversation

clayjohn
Copy link
Member

Fixes: #72823

When I first wrote the GLES3 renderer I used the pure linear mipmap approach to maximize speed. At that time, mipmaps were always generated when reading from the backbuffer. Now, users can choose whether to generate mipmaps or not. So users that need to prioritize speed can choose not to generate mipmaps at all and users that need mipmaps can get high-quality mipmaps.

I used the same gaussian approximation that is used in the mobile renderer as it is significantly faster on mobile devices than the two-pass gaussian used in the Forward+ renderer. The results aren't quite as soft, but they are still quite good.

I have tagged this for 4.2 as it changes visuals and decreases performance. I don't want to disturb teams that are already working around the current visuals/relying on the current performance.

If the reduced performance is a problem, we can consider adding a project setting to bring the older pure linear blur back. In my testing it looks like the new approach is nearly 50% more expensive than the old one (this is a testament to how fast the old approach was, the new approach is still very efficient for what it is).

Base image used for testing
Screenshot from 2023-06-12 15-05-21

Comparison of the different renderers at mip level 4.0

GL Compatibility renderer before this PR
Screenshot from 2023-06-12 13-02-18

GL Compatibility renderer after this PR (and Mobile renderer)
Screenshot from 2023-06-12 13-30-48

Forward+ renderer
Screenshot from 2023-06-12 13-31-09

@clayjohn clayjohn added this to the 4.2 milestone Jun 13, 2023
@clayjohn clayjohn requested a review from a team as a code owner June 13, 2023 05:02
@Zireael07
Copy link
Contributor

My vote is having a switch for linear blur. GLES 3 is going to be used mostly on mobile, where performance is already at a premium

@clayjohn
Copy link
Member Author

My vote is having a switch for linear blur. GLES 3 is going to be used mostly on mobile, where performance is already at a premium

Just for clarification, do you know of a situation where the pure linear mipmaps would be acceptable quality-wise? I would prefer to only add a project setting that we know is needed by users. In other words, I don't like to speculate and add settings until I know that users need them.

@Zireael07
Copy link
Contributor

I used Compatibility renderer and never noticed the quality of mipmaps bothering me, and from the looks of the pic it's definitely acceptable to me for a low-poly game that needs some performance, not 10 fps (being a racer will do that)

@clayjohn
Copy link
Member Author

I used Compatibility renderer and never noticed the quality of mipmaps bothering me, and from the looks of the pic it's definitely acceptable to me for a low-poly game that needs some performance, not 10 fps (being a racer will do that)

Is your game 3D? This PR doesn't impact 3D. It is specifically for when you use SCREEN_TEXTURE with mipmaps in a 2D project.

@Zireael07
Copy link
Contributor

Ah, good point (mine is 3D). Tbh if it's 2d, then the reduction in quality shouldn't matter for most projects either (but I can't speak personally)

@lawnjelly
Copy link
Member

lawnjelly commented Jun 13, 2023

Looks fine to me.

As an aside I must admit I'm slightly out of the loop on framebuffers, but what's the etiquette for creating / destroying them per frame versus reusing them? I'm sure I've seen this create / destroy pattern quite a few times, is this something everybody does and ok performance wise?

GameTechDev/IntroductionToVulkan#20
https://stackoverflow.com/questions/44541600/re-create-fbo-frame-buffer-object-each-frame
https://community.khronos.org/t/re-create-fbo-frame-buffer-object-each-frame/75892

(Maybe it's cheaper in this PR as it is reusing the framebuffer texture? Not sure, just wanted to check.)

@clayjohn
Copy link
Member Author

@lawnjelly The "weight" in the framebuffer comes from validating its connection to the attachments. The actual creation and destruction of a framebuffer in OpenGL is trivial. The biggest cost comes from switching FBOs which requires re-validating all the current state. Ultimately whether you pre-allocate one FBO per layer, or create one FBO and change the attachment as needed you end up paying the same cost (I.e. re-validating).

In my testing, this approach is slightly faster than pre-allocating FBOs on older hardware (particularly on my old/low end integrated GPU) and the same speed as pre-allocating on newer hardware.

Overall, I am indifferent between the two approaches and went with this one as it requires less resource tracking.

@SirTodd
Copy link

SirTodd commented Jun 15, 2023

I do use a lot of blur on my android game, and users complain a lot about the pixelation of images.
This would be such a welcome change since the game does not use too much GPU.

@djrain
Copy link

djrain commented Jun 15, 2023

I just did some testing of the blur effect on several devices using the Forward+ renderer. Just one layer of fullscreen blur starts to cripple a Google Pixel 4 XL (2019, this is the newest android we have).

However, Apple devices seem to handle this with ease. On a 2nd gen iPhone SE (that's the low-end iPhone from 2020), it took a whopping 10 consecutive layers of blur (that's including 10 BackBufferCopy nodes in viewport mode) to get the FPS to even dip below 60. Even at 14(!) layers, it was running better than the Pixel 4 at just a couple layers. Also tested on iPhone 14 Pro Max, with similar results.

I'm hoping this phone is not representative of most Androids, if so that is a shockingly sad performance... But anyhow, if iOS is that solid, maybe it makes sense to give all the renderers an option for the highest-quality blur? I would probably enable it on those devices for our game since it does look considerably better. It would also be relevant for anyone releasing on desktop using the compatibility or mobile renderers.

@clayjohn
Copy link
Member Author

@djrain Please note this PR doesn't change the Forward+ renderer at all. The results you are seeing come from the fact that iOS devices have pretty good compute shader support while Android devices (until very recently) have very poor compute shader support. The Google device should have much better performance using either the Mobile or GL Compatibility backends.

@djrain
Copy link

djrain commented Jun 15, 2023

@clayjohn Ah, interesting! Yeah, I realize this is for compatibility only - I just wanted to suggest the possibility of allowing the two pass blur in all renderers (if that's even an option here.)

From our results, the android blur performance is somewhat better in mobile mode, but there it still struggles with even the one approximate blur, and is still pretty far from the iPhone performance (whether you're saying that's expected, I'm not sure). In any case, this would open back up compatibility mode as an option for our project, so thanks for this :)

@clayjohn
Copy link
Member Author

@clayjohn Ah, interesting! Yeah, I realize this is for compatibility only - I just wanted to suggest the possibility of allowing the two pass blur in all renderers (if that's even an option here.)

Fair enough, it is an interesting idea as it does look way nicer.

By any chance did you compare performance of the mobile version between Android and iOS. I imagine that Android would get closer to iOS performance on that backend (compared to using Forward+), but if iOS is still ahead by the same margin then my theory may be wrong

@YuriSizov YuriSizov merged commit a33b548 into godotengine:master Jul 12, 2023
@YuriSizov
Copy link
Contributor

Thanks!

@clayjohn clayjohn deleted the GLES3-gaussian-rt branch July 12, 2023 16:18
@Anutrix
Copy link
Contributor

Anutrix commented Jul 17, 2023

Can someone provide a sample/demo so that we can test it on our phones?

@djrain
Copy link

djrain commented Aug 18, 2023

By any chance did you compare performance of the mobile version between Android and iOS.

Sorry for late reply - I'm afraid the results are pretty much the same for Mobile renderer. With 14 layers of blur, iPhone SE gets 60 fps, Pixel 4 XL 14 fps.

And practically speaking, it's bad enough that we can't use any blur in our game on this phone, unless I run it in a viewport at 1/4 the resolution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

OpenGL: textureLod() is blocky due to using linear mipmaps instead of Gaussian
7 participants