2

I am basically trying to do something with the default frame buffer pixmap. I wish to blur it when somebody pauses the game . My problem is that even if I am using a separate thread for the whole blur operation, the method ScreenUtils.getFrameBufferPixmap has to be called on the rendering thread. But this method takes atleast 1 second to return even on nexus 5. Calling the method on my blur processing thread is not possible as there is no gl context available on any other thread other than rendering thread .

Is there any solution for eliminating the stall

Rahul Verma
  • 2,140
  • 3
  • 21
  • 31

2 Answers2

0

What you're trying to do: take a screenshot, modify it on the CPU and upload it back to the GPU. There are 3 problems with this approach. 1.Grabbing pixels, takes a lot of time. 2.Blurring can be successfully executed independentely for each pixel so there is no point doing it on CPU. GPU can do it in a blink of an eye. 3. Uploading the texture back still takes some time.

The correct approach is: instead of rendering everything to the screen render it to the offscreen texture. (See offscreen rendering tutorials) Next, draw this texture on a quad of the size of your screen, but while drawing, use a blur shader. There is a number of example blur shaders available. It should basically sample the surroundings of the target pixel and render it's average.

Elvithari
  • 834
  • 1
  • 8
  • 13
  • You are not getting my point . I do not want real time blurring as I am just going to show a still static background while game is paused . Plus I want to generate a lerp blur (the effect used in ios plus described here :https://github.com/mattdesl/lwjgl-basics/wiki/Lerp-Blur-Brief . – Rahul Verma Aug 28 '14 at 07:51
  • @Rahul Verma: I am getting your point. My point is: grabbing output pixels is too slow to run smoothly. If you insist, try using other methods to read them but it's gonna be slow anyway. You don't want real-time blurring? Great! Do what I've said just once, when the pause is pressed. Record the blurred texture at GPU and use it as a static image when the pause is active. No more blur needs to be applied. If you want a blur to be stronger over some time you can still do it easily using this approach. And it will be lightning fast. – Elvithari Aug 28 '14 at 08:09
  • Your seem to be right , In fact for the blur strengthening issue over time , I could use mix() bw actual pixel and blurred pixel and progressively increase the weight of blur pixel to full. But there is short coming you see , Blurring in software (java code) could have been easily carried out asynchronously . Undoubtedly blurring with a Shader is going to be lightening fast but is it sure its not going to lag on older devices (less powerful gpus)? Anyways its definitely going to be less laggy than pulling pixels value off GPU . – Rahul Verma Aug 28 '14 at 10:57
  • The blurring operation itself should be executed rather seamlessly. I don't know how well less powerful GPUs handle multiple passes but as you've said less powerfull GPUs won't perform better downloading/uploading pixels. I believe that this approach is worth a shot. It should be significantly faster than doing it in a separate thread on the CPU. – Elvithari Aug 28 '14 at 11:02
0

In the source for ScreenUtils.java you can see that getFrameBufferPixmap is basically a wrapper around OpenGL's glReadPixels. There isn't too much you can do to improve the Java or Libgdx wrapper. This is not the direction OpenGL is optimized for (its good at pushing data up to the GPU, not pulling data off).

You might be better off re-rendering your current screen to a (smaller, off-screen) FrameBuffer, and then pulling that down. You could use the GPU to do the blurring this way, too.

I believe the screen's format (e.g., not RGBA8888) may have an impact on the read performance.

This isn't Libgdx-specific, so any tips or suggestions for OpenGL in general like Making glReadPixel() run faster should apply.

Community
  • 1
  • 1
P.T.
  • 24,557
  • 7
  • 64
  • 95