Potential issue in nifty batch rendering

Hi,

After having a look at JmeBatchRenderBackend code I’ve noticed that there’s a potential issue in the clearTextureAtlas method:

  @Override
  public void clearTextureAtlas(final int atlasId) {
      initialData.rewind();
      getTextureAtlas(atlasId).getImage().setData(initialData);
  }

it just overwrites the inner buffer of the texture atlas image with a pre stored green empty bytebuffer created on class initialization.

If you configure your batch to have multiple atlases or you need them because your images doesn’t fit in just one of them because you’re using small sized batch and you define disposeImagesBetweenScreens to true as follows for example:

BatchRenderConfiguration batchConfig = new BatchRenderConfiguration();
batchConfig.atlasWidth = 256;
batchConfig.atlasHeight = 256;
batchConfig.disposeImagesBetweenScreens = true;
batchConfig.initialAtlasCount = 2;
niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay(assetManager, inputManager, audioRenderer, viewport, batchConfig);

All atlases in this batch render backend will use the same byte buffer after the first screen change. And this may lead to weird GUI rendering issues.

My proposal is to remove the pre defined initialData ByteBuffer and just overwrite the data of the ByteBuffer in the image. Something like this could be slower but it’s safer and will avoid the potential issues.

  @Override
  public void clearTextureAtlas(final int atlasId) {
      com.jme3.texture.Image atlasImage=getTextureAtlas(atlasId).getImage();
      ByteBuffer atlasBuffer=atlasImage.getData(0);
      atlasBuffer.rewind();
      for (int i=0; i<atlasImage.getWidth()*atlasImage.getHeight(); i++) {
        atlasBuffer.put((byte) 0x00);
        atlasBuffer.put((byte) 0xff);
        atlasBuffer.put((byte) 0x00);
        atlasBuffer.put((byte) 0xff);
      }
      atlasBuffer.rewind();
      atlasImage.setUpdateNeeded();
      // could use atlasImage.setData(atlasBuffer); instead
  }

This change will also allow to remove the default initialData which as a side effect will avoid having useless memory reserved, for example the default image size 2048*2048 would missuse 16Mb of direct memory for each batched nifty which heppens even if the disposeImagesBetweenScreens is set to false.

1 Like

I remember having an issue with nifty when you recreate the rendering window and I wonder if this bug has something to do with that. At any rate, you could submit a pull request with the nifty git. I don’t think it is under real active development anymore but they still accept pull requests and bug fixes every few months.

@joliver82 Thank you for investigating and reporting on this issue.
@glh3586 I believe the class in question is in JME’s repo, not Nifty’s. But yes, a pull request would be in order.

1 Like

Ahh, you are right. I missed that it was in the JME connection code.

1 Like

Yes, that class is in the jme3-nifty package. I’ll create a PR for this :wink:

@glh3586 honestly I’m not sure if can be related with your issue. For sure creates glitches when changing screens having multiple fonts and bitmaps

1 Like

PR created: Nifty batch fix - memory improvement by joliver82 · Pull Request #1220 · jMonkeyEngine/jmonkeyengine · GitHub

Thanks

1 Like

Hi!

Finally I got some spare time and I’ve been getting deeper into this and I realized that the potential issue is not happening because the buffer is uploaded to the graphics card just once and then it’s overwritten in GL memory using glTexSubImage2D and the buffer itself is not used afterwards at all.

So I’m changing this to a little memory improvement initializing the initialData buffer in the class constructor instead of when creating an atlas or in the same method but just once if not created previousle because currently we’re creating multiple buffers (as much as the atlases required for the nifty screen) and using just one and all other (numAtlas - 1) will be garbage collected later.

In fact, when creating the atlases (in the method createAtlasTextureInternal) we can use the same initial buffer instead of creating a new one for each atlas as the buffer itself is also not being used but for uploading a base to GL and later the atlases will be modified by glTexSubimage

2 Likes