TextureRender vs Renderer - very slow performance

Can you tell the average time in milliseconds the test is printing out (without extrapolating it to the fps)? For this test, lower numbers mean less delay, hence faster speed (more fps).

Pbuffer does output white texture and I dont know what is wrong with it and how to fix it.

I have removed all the versions of test and updated the first post to contain the most up-to-date version.

Copy texture: 452

FBO: 7

Probably should standardize on windowed/full screen and resolution, etc. to compare properly.

I have run more testing and found that commenting out the line

EXTFramebufferObject.glGenerateMipmapEXT(GL11.GL_TEXTURE_2D);


in LWJGLTextureRenderer, causes FBO texture renderer to be very fast (almost as fast as CopyToTexture on my machine) and 2.5 times faster than PBuffer!

Is PBufferTextureRenderer capable of generating mipmaps of rendered texture?

PBuffer requires an expensive context switch, so I'm not surprised it would be slower (although 2.5 sounds excessive).  I'm not sure about pbuffer mipmaps…  As for the mipmap generation, perhaps we can simply check the filter settings on the Texture object and only gen the mipmaps if it is a mipmapped texture.

Both copyToTexture and PBufferTexture renderer fail when using a texture with mip-maps enabled. So FBO texture renderer is the only option that supports mipmaps, and its very slow on some systems.



Maybe make mip-map support optional with a warning that it can cause slowdowns on some systems?

I've read that you can get mipmapping from pbuffers by copying the pbuffer contents to a texture that has automatic mipmapping.  So maybe we could support it somehow there as well…

As for the mipmap generation, perhaps we can simply check the filter settings on the Texture object and only gen the mipmaps if it is a mipmapped texture.

If programmers are not aware it can cause slowdowns, they will include mip-mapping and then their software wont be usable on some systems.

I've read that you can get mipmapping from pbuffers by copying the pbuffer contents to a texture that has automatic mipmapping.  So maybe with our forceCopy...

How fast would that work?  :-o Words PBuffer, copying and automatic mipmapping donot inspire much confidence in me.

my results were with this setup:

Resolution: 800x600, windowed

Frequency: 60

Color depth: 32



Mipmapping really should be optional for FBO. quads used for fullscreen effects (bloom) get no benifit from mipmapping at all since they are rendered pixel for pixel.

lex said:

As for the mipmap generation, perhaps we can simply check the filter settings on the Texture object and only gen the mipmaps if it is a mipmapped texture.

If programmers are not aware it can cause slowdowns, they will include mip-mapping and then their software wont be usable on some systems.


Yes, that's an issue but it's an easy way to allow for toggling.  The texture is not something that would be pulled in from the average asset pipeline and we can warn in documentation.  It's also an area that is likely to improve over time as older cards drop out of the market.

lex said:

I've read that you can get mipmapping from pbuffers by copying the pbuffer contents to a texture that has automatic mipmapping.  So maybe with our forceCopy...

How fast would that work?  :-o Words PBuffer, copying and automatic mipmapping donot inspire much confidence in me.


*shrug*  Sometimes you need correctness over high fps.  Again, it is up to the programmer to choose the right targets for his application.  We can set the best defaults internally in jME, but I think it is a disservice to programmers to assume they are better left protected from themselves.

Momoko_Fan said:

Mipmapping really should be optional for FBO. quads used for fullscreen effects (bloom) get no benifit from mipmapping at all since they are rendered pixel for pixel.


Yes. :)

I was looking more at the code in LWJGLTextureRenderer.render(Spatial toDraw, Texture tex, boolean doClear), and found the following.



            LWJGLTextureState.doTextureBind(tex.getTextureId(), 0);

            // Allow mipmapping to work in this fbo.
            EXTFramebufferObject.glGenerateMipmapEXT(GL11.GL_TEXTURE_2D);



According to the specifications, glGenerateMipmapEXT only needs to be called once. And it is called during texture setup. Calling it in render() method really slows down FBO renderer on my system even further:

Here are the test results (the average time as added by renanse) for various configurations of FBO texture renderer:
- No mipmap autogenerationt: around 1.1 millisecond average TPF
- Mipmap autogeneration set in setupTexture(): around 6.5 milliseconds average TPF
- Mipmap autogeneration set in render(): around 12.0 milliseconds average TPF
- Mipmap autogeneration set in both setupTexture() and render(): around 12.5 milliseconds average TPF

Thinking about it, that model is also more efficient, because they donot unbind FBO after rendering every texture. On the other hand texture renderer unbinds FBO and then binds it again after rendering every texture, switching between FBO and no FBO might be alot more expencive than simply switching between different textures buffers.

I have moved glGenerateMipmapEXT call after rendering and FBO deactivation code. My average TPF when using mipmapping with FBO went from 12.0 milliseconds back to 6.0 milliseconds.



Also I have noticed that no mipmap generation is done for render method that takes texture list.



As for deactivating FBO after every texture render, I dont think it amount to any significant performance loss. Sorry for bringing that up, just brainstorming :slight_smile:



    public void render(Spatial toDraw, Texture tex, boolean doClear) {
        if (!isSupported) {
            return;
        }
       
        try {
           
            activate();
           
            if (tex.getRTTSource() == Texture.RTT_SOURCE_DEPTH) {
                // Set textures into FBO
                EXTFramebufferObject.glFramebufferTexture2DEXT(
                        EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
                        EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT,
                        GL11.GL_TEXTURE_2D, tex.getTextureId(), 0);
                GL11.glDrawBuffer(GL11.GL_NONE);
            } else {
                // setup depth RB
                EXTFramebufferObject.glFramebufferRenderbufferEXT(
                        EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
                        EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT,
                        EXTFramebufferObject.GL_RENDERBUFFER_EXT, depthRBID);
   
                // Set textures into FBO
                EXTFramebufferObject.glFramebufferTexture2DEXT(
                        EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
                        EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT,
                        GL11.GL_TEXTURE_2D, tex.getTextureId(), 0);
            }

            // Check FBO complete
            checkFBOComplete();
           
            switchCameraIn(doClear);
           
            // Override parent's last frustum test to avoid accidental incorrect
            // cull
            if (toDraw.getParent() != null)
                toDraw.getParent().setLastFrustumIntersection(
                        Camera.INTERSECTS_FRUSTUM);
            doDraw(toDraw);

            switchCameraOut();
            deactivate();
           
            LWJGLTextureState.doTextureBind(tex.getTextureId(), 0);

            // Allow mipmapping to work in this fbo.
            EXTFramebufferObject.glGenerateMipmapEXT(GL11.GL_TEXTURE_2D);


        } catch (Exception e) {
            logger.logp(Level.SEVERE, this.getClass().toString(),
                    "render(Spatial, Texture, boolean)", "Exception", e);
        }
    }

Good observations!  :)  I've moved things around and set it up in the array version as well…  I've also told it to ignore mipmaps if the texture's mipmap is setup as MM_NONE.  The only boost in speed I got was that it was turning off mipmap generation, but at least it is correct now. :)  I'll get that into the old jme later today.

Ok, that's all in. Just for reference my results on the tests are:

None: 0.300 ms

FBO: 0.565 ms (is 0.815 ms if I don't include the check for mm=none, or iow, if mipmap generation is done)

PBuffer: 0.983 ms

Copy: 1.024 ms

I've checked in the new code from CVS, still getting the old results.

Commenting out the line


EXTFramebufferObject.glGenerateMipmapEXT(GL11.GL_TEXTURE_2D);


in setupTexture() method gives me 10x performance boost on bloom. That line shouldn't matter, but it does... go figure.

I think that the bloom code needs to be modified to create the texture with MM_NONE mipmap mode.

The bloom pass is already using MM_NONE mipmap mode. The problem with my system is that binding an fbo to render to a texture that has mipmap levels causes a significant slowdown.



The render() method was fixed not to generate mipmaps when MM_NONE is used on the texture, however the setupTexture() method was not changed to honor mipmap settings, so mipmpas for the blank texture are generated but never updated. And my system is still performing poorly, because the texture renderer is bound with a texture that has mipmap levels.