Performance Issue with complex Nifty Screen

Hi Folks,

I started with the ingame gui of my project, everything is in place and working. But i get a framerate drop from 70 fps to 13 fps with the gui active.



Is it me or is there a problem with the Nifty, or my XML-layout?



The following is a testcase for the problem with a blank screen and a screen which is like mine.

The program does nothing special but change between two screens.



On gui screen i get something like 250 - 300 fps

On blank screen I get nearly 4000 fps.



gui.xml

[java]

<?xml version="1.0" encoding="UTF-8"?>

<nifty xmlns="http://nifty-gui.sourceforge.net/nifty-1.3.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://nifty-gui.sourceforge.net/nifty-1.3.xsd http://nifty-gui.sourceforge.net/nifty-1.3.xsd">

<useStyles filename="nifty-default-styles.xml" />

<useControls filename="nifty-default-controls.xml" />



<screen id="clearScreen">

<layer>

</layer>

</screen>

<screen id="mainGame" controller="de.myrdragor.controller.nifty.screencontroller.MainGame">

<layer id="layUnitFrame" childLayout="vertical">

<panel id = "pnlMainFrame" height="80px" width = "640px" align="left" valign="top" childLayout="horizontal">

<panel width="256px" childLayout="vertical">

<panel id = "pnlPlayerCharFrame" height="64px" width = "256px" childLayout="horizontal">

<panel width="64px" height="64px" style="nifty-panel-no-shadow" childLayout="center" padding="5px">

<panel id="imgCharHead" style="nifty-panel-red-no-shadow" width="100%" height="100%" valign="center" align="center"/>

</panel>

<panel width="" height="100%" childLayout="vertical">

<panel width="100%" height="20px" style="nifty-panel-no-shadow" childLayout="center" padding="5px">

<control name="label" text="Name"/>

</panel>

<panel width="100%" height="
" style="nifty-panel-no-shadow" childLayout="horizontal" padding="5px">

<panel childLayout="vertical" width="75%" height="100%">

<panel id="barPlayerHealth" backgroundColor="#ffff"/>

<panel id="barPlayerMana" backgroundColor="#f00f"/>

<panel id="barPlayerKarma" backgroundColor="#0f0f"/>

<panel id="barPlayerEnergy" backgroundColor="#00ff"/>

</panel>

<panel childLayout="vertical" width="" height="100%">

<control id="lblPlayerHealth" width="100%" height="
" name="label" text="100%" />

<control id="lblPlayerMana" width="100%" height="" name="label" text="100%" />

<control id="lblPlayerKarma" width="100%" height="
" name="label" text="100%" />

<control id="lblPlayerEnergy" width="100%" height="" name="label" text="100%" />

</panel>

</panel>

</panel>

</panel>

<panel height="
" childLayout="vertical">

<panel id="barPlayerCast" visible="false"/>

</panel>

</panel>

<panel width="2px"/>

<panel id = "pnlTargetCharFrame" height="80px" width="256px" childLayout="vertical">

<panel width="100%" height="64px" childLayout = "horizontal">

<panel width="" height="64px" childLayout="vertical">

<panel width="100%" height="20px" style="nifty-panel-no-shadow" childLayout="horizontal" padding="5px">

<control name="label" id="lblTargetName" text="Target" color="000f" width="100%" align="center" style="base-font"/>

</panel>

<panel width="100%" height="
" style="nifty-panel-no-shadow" childLayout="horizontal" padding="5px">

<panel childLayout="vertical" width="75%" height="100%">

<panel id="barTargetHealth" name="StatusBar" backgroundColor="#ffff"/>

<panel id="barTargetMana" name="StatusBar" backgroundColor="#f00f"/>

<panel id="barTargetKarma" name="StatusBar" backgroundColor="#0f0f"/>

<panel id="barTargetEnergy" name="StatusBar" backgroundColor="#00ff"/>

</panel>

<panel childLayout="vertical" width="" height="100%">

<control id="lblTargetHealth" width="100%" height="
" name="label" text="100%" />

<control id="lblTargetMana" width="100%" height="" name="label" text="100%" />

<control id="lblTargetKarma" width="100%" height="
" name="label" text="100%" />

<control id="lblTargetEnergy" width="100%" height="" name="label" text="100%" />

</panel>

</panel>

</panel>

<panel width="64px" height="64px" style="nifty-panel-no-shadow" childLayout="center" padding="5px">

<panel id="imgTargetHead" style="nifty-panel-red-no-shadow" width="100%" height="100%" valign="center" align="center"/>

</panel>

</panel>

<panel height="
" childLayout="vertical">

<panel id="barTargetCast" visible="false"/>

</panel>

</panel>

<panel width="2px"/>

<panel id = "pnlTargetOfTargetCharFrame" width="128px" height="64px" childLayout="vertical">

<panel width="100%" height = "50%" childLayout="vertical">

<panel width="100%" height="20px" style="nifty-panel-no-shadow" childLayout="horizontal" padding="5px">

<control name="label" id="lblTargetOfTargetName" text="Target" color="000f" width="100%" align="center" style="base-font"/>

</panel>

<panel width="100%" height="" style="nifty-panel-no-shadow" childLayout="vertical" padding="5px">

<panel id="barTargetOfTargetHealth" backgroundColor="#f00f" />

</panel>

</panel>

<panel height="10px" childLayout="vertical">

<control id="barTargetOfTargetCast" name="StatusBar" visible="false"/>

</panel>

</panel>

<panel width="
"/>

</panel>

</layer>

<layer id="Chat" childLayout="vertical">

<panel height=""/>

<panel id="pnlChatButtons" height="20px" width="300px" align="left" valign="bottom" childLayout="horizontal">

<panel width="
"/>

<control id="ChatButtonSetting" name="button" width="20px" height="20px" label="A" backgroundcolor="#bbb" focusable="false">

</control>

<panel width="1%"/>

<control id="ChatButtonGuild" name="button" width="20px" height="20px" label="G" backgroundcolor="#bbb" focusable="false">

</control>

<panel width="1%"/>

<control id="ChatButtonOfficer" name="button" width="20px" height="20px" label="O" backgroundcolor="#bbb" focusable="false">

</control>

<panel width="1%"/>

<control id="ChatButtonParty" name="button" width="20px" height="20px" label="P" backgroundcolor="#bbb" focusable="false">

</control>

<panel width="1%"/>

<control id="ChatButtonReligion" name="button" width="20px" height="20px" label="R" backgroundcolor="#bbb" focusable="false">

</control>

<panel width="1%"/>

<control id="ChatButtonTown" name="button" width="20px" height="20px" label="T" backgroundcolor="#bbb" focusable="false">

</control>

<panel width=""/>

</panel>

<panel id="pnlChat" height="120px" width="300px" align="left" valign="bottom" childLayout="vertical" backgroundColor="#000a">

<control id="txtChat" name="textfield" width = "100%" height="23px" />

<control id="lbxChat" name="listBox" width = "100%" vertical="optional" horizontal="off" displayItems="6" selectionMode="Disabled">

<text text="Template" backgroundColor="#0000" style="nifty-console-listbox-item" controller="de.lessvoid.nifty.controls.listbox.ListBoxItemController"/>

</control>

</panel>

</layer>

<layer id="Minimap" childLayout="center">

<panel id="minimap" height="150px" width="150px" align="right" valign="top" childLayout="vertical">

<panel width="150px" height="150px" style="nifty-panel-no-shadow" childLayout="center" padding="5px">

<panel id="imgMinimap" width="100%" height="100%" style="nifty-panel-red-no-shadow" childLayout="absolute">

</panel>

</panel>

</panel>

</layer>

<layer id="UIBars" childLayout="center">

<panel childLayout="horizontal" width="100%" height="100px" align="right" valign="bottom">

<panel width="
"/>

<panel childLayout="vertical">

<panel height=""/>

<panel id="SkillBar" align="right" width="400px" height="50px" backgroundColor="#555a" childLayout="horizontal" >

<panel width="50px" height="50px" childLayout="absolute">

<control id="dropSBButton1" name="droppable" width="50px" height="50px" x="0" y="0" align="center" valign="top">

<effect>

<onActive name="border" post="true" color="#222f" border="1px" />

</effect>

</control>

<control id="lblSBB1Binding" name="label" width="20" height="20" x="30" y="30" text="1" color="#bbbf" visibleToMouse="false"/>

</panel>

<panel width="50px" height="50px" childLayout="absolute">

<control id="dropSBButton2" name="droppable" width="50px" height="50px" x="0" y="0" align="center" valign="top">

<effect>

<onActive name="border" post="true" color="#222f" border="1px" />

</effect>

</control>

<control id="lblSBB2Binding" name="label" width="20" height="20" x="30" y="30" text="2" color="#bbbf" visibleToMouse="false"/>

</panel>

<panel width="50px" height="50px" childLayout="absolute">

<control id="dropSBButton3" name="droppable" width="50px" height="50px" x="0" y="0" align="center" valign="top">

<effect>

<onActive name="border" post="true" color="#222f" border="1px" />

</effect>

</control>

<control id="lblSBB3Binding" name="label" width="20" height="20" x="30" y="30" text="3" color="#bbbf" visibleToMouse="false"/>

</panel>

<panel width="50px" height="50px" childLayout="absolute">

<control id="dropSBButton4" name="droppable" width="50px" height="50px" x="0" y="0" align="center" valign="top">

<effect>

<onActive name="border" post="true" color="#222f" border="1px" />

</effect>

</control>

<control id="lblSBB4Binding" name="label" width="20" height="20" x="30" y="30" text="4" color="#bbbf" visibleToMouse="false"/>

</panel>

<panel width="50px" height="50px" childLayout="absolute">

<control id="dropSBButton5" name="droppable" width="50px" height="50px" x="0" y="0" align="center" valign="top">

<effect>

<onActive name="border" post="true" color="#222f" border="1px" />

</effect>

</control>

<control id="lblSBB5Binding" name="label" width="20" height="20" x="30" y="30" text="5" color="#bbbf" visibleToMouse="false"/>

</panel>

<panel width="50px" height="50px" childLayout="absolute">

<control id="dropSBButton6" name="droppable" width="50px" height="50px" x="0" y="0" align="center" valign="top">

<effect>

<onActive name="border" post="true" color="#222f" border="1px" />

</effect>

</control>

<control id="lblSBB6Binding" name="label" width="20" height="20" x="30" y="30" text="6" color="#bbbf" visibleToMouse="false"/>

</panel>

<panel width="50px" height="50px" childLayout="absolute">

<control id="dropSBButton7" name="droppable" width="50px" height="50px" x="0" y="0" align="center" valign="top">

<effect>

<onActive name="border" post="true" color="#222f" border="1px" />

</effect>

</control>

<control id="lblSBB7Binding" name="label" width="20" height="20" x="30" y="30" text="7" color="#bbbf" visibleToMouse="false"/>

</panel>

<panel width="50px" height="50px" childLayout="absolute">

<control id="dropSBButton8" name="droppable" width="50px" height="50px" x="0" y="0" align="center" valign="top">

<effect>

<onActive name="border" post="true" color="#222f" border="1px" />

</effect>

</control>

<control id="lblSBB8Binding" name="label" width="20" height="20" x="30" y="30" text="8" color="#bbbf" visibleToMouse="false"/>

</panel>



</panel>

<panel height="
"/>

</panel>

<panel id="GUICustomizer" style="nifty-panel-no-shadow" width="100px" height="100px" backgroundcolor="#aaa" align="right" childLayout="vertical">

<control padding="0px" id="SkillBar1" name="button" width="20px" height="20px" label="1" backgroundcolor="#bbb" focusable="false">

</control>

<control padding="0px" id="SkillBar2" name="button" width="20px" height="20px" label="2" backgroundcolor="#bbb" focusable="false">

</control>

<control padding="0px" id="SkillBar3" name="button" width="20px" height="20px" label="3" backgroundcolor="#bbb" focusable="false">

</control>

<control padding="0px" id="SkillBar4" name="button" width="20px" height="20px" label="4" backgroundcolor="#bbb" focusable="false">

</control>

</panel>

</panel>

</layer>

</screen>

</nifty>

[/java]



Main.java

[java]

package mygame;



import com.jme3.app.SimpleApplication;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.niftygui.NiftyJmeDisplay;

import com.jme3.renderer.RenderManager;

import de.lessvoid.nifty.Nifty;



/**

  • test
  • @author agares

    */

    public class Main extends SimpleApplication implements ActionListener {



    public static void main(String[] args) {

    Main app = new Main();

    app.start();

    }

    private Nifty nifty;



    @Override

    public void simpleInitApp() {

    NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);



    nifty = niftyDisplay.getNifty();

    guiViewPort.addProcessor(niftyDisplay);



    ClearScreenController csc = new ClearScreenController();

    MainGameController mgc = new MainGameController();

    nifty.registerScreenController(csc,mgc);



    nifty.fromXml("Interface/Gui.xml","mainGame");



    initKeys();

    }



    @Override

    public void simpleUpdate(float tpf) {

    //TODO: add update code

    }



    @Override

    public void simpleRender(RenderManager rm) {

    //TODO: add render code

    }



    private void initKeys() {

    inputManager.addMapping("switchGuiState", new KeyTrigger(KeyInput.KEY_F1));

    inputManager.addListener(this, "switchGuiState");

    }



    public void onAction(String name, boolean isPressed, float tpf) {

    if (isPressed){

    return;

    }



    if (name.equals("switchGuiState")){

    if (nifty.getCurrentScreen().getScreenId().equals("clearScreen")){

    nifty.gotoScreen("mainGame");

    } else {

    nifty.gotoScreen("clearScreen");

    }

    }

    }

    }

    [/java]



    Any ideas?



    Edit: I use the JME3 nightly build

My GUI is way more complex and there is no performance penalty at all. Do you load it or change it by chance in every update or sth.?

At Simple Init the gui is loaded from a xml. No change happens in an update or sth…



In the testcase above you can switch the two screens with the F1 - Key.

thats the only change that happens.

Can’t say that a basic screen without text updates is bringing FPS losses.



My HUD screen has over 800 lines, custom styles and controls, several popups, many many layers, and I can’t say there’s a huge loss.



What’s the specs of the computer you’re running this on?

4000->300fps is nothing to worry about, a blank screen will always render more quickly… also the fps doesn’t give you any real percentages on overhead or headroom really. Some things might take a lot of fps but still leave headroom for other tasks w/o lowering the fps then (cause theres more time).

the code in the upper post is only a testcase to show the difficulties with the gui.

I coded the scenery in my game project with some filters a terrain and an animated 3d character.



at that point i got nearly 70 fps - 100 fps and all is running very smooth and nice.



Now with the gui sample above the framerate is dropping to 13 fps.

This is the reason i posted the above code snippet to get some help with this problem.



@madjack

Can’t say that a basic screen without text updates is bringing FPS losses.
My HUD screen has over 800 lines, custom styles and controls, several popups, many many layers, and I can’t say there’s a huge loss.
What’s the specs of the computer you’re running this on?


My System Spec:
[java]
Intel I7 - 920 X58 @ 2.67 gHz
Cores: 8
HeapSpace: 2728 Mb
OS: Windows 7 (amd64) Service Pack 1
Java: 1.7.0_04 from Oracle Corporation
Adapter: nvd3dumx,nvwgf2umx,nvwgf2umx
Driver Version: 8.17.12.9610
Vendor: NVIDIA Corporation
OpenGL Version: 3.3.0
Renderer: GeForce GTX 295/PCIe/SSE2
GLSL Ver: 3.30 NVIDIA via Cg compiler
Caps : [FrameBuffer, FrameBufferMRT, FrameBufferMultisample, TextureMultisample, OpenGL20, OpenGL21, OpenGL30, OpenGL31, OpenGL32, ARBprogram, GLSL100, GLSL110, GLSL120, GLSL130, GLSL140, GLSL150, VertexTextureFetch, TextureArray, TextureBuffer, FloatTexture, FloatColorBuffer, FloatDepthBuffer, PackedFloatTexture, SharedExponentTexture, PackedFloatColorBuffer, TextureCompressionLATC, NonPowerOfTwoTextures, MeshInstancing, VertexBufferArray, PackedDepthStencilBuffer]
[/java]

@normen
4000->300fps is nothing to worry about, a blank screen will always render more quickly.. also the fps doesn’t give you any real percentages on overhead or headroom really. Some things might take a lot of fps but still leave headroom for other tasks w/o lowering the fps then (cause theres more time).


right, as long as i got more then 25 frames everything schould be fine. But as i wrote before in the real game (not the testcase) it drops from 70 to 13 fps and thats the real problem.

the game has more than 20k lines of code and nearly 400 mb of testassets so pls forgive me that i dont post the code here on the forum :D

if I understand everything in the right way, there should't be such a problem with the nifty gui and maybe this could be a problem with my sdk installation. I'll test this on another computer and let you know if the problem is fixed. Maybe something went wrong with my plugin update or something....

Actually you should target 60fps, the 24 framse is fluent bullshit is not right. With analog films it’s true, since the cameras technically have a motionblur. However computer grafics don’t (unless you have one in the rendering process)

This is noticeable on objects in distances, even if you only change like 2degrees, the object moves instantly several meters.

http://www.highdefdigest.com/blog/james-cameron-48-fps/



Why 60 fps, because that the refresh most monitors use, so you wont have jitters.

(Of course it depends on the game how noticeable this is, a strategy or turn based game works with far less fps than a shooter or race game)

Specs are fine. Not an old crappy laptop (we see that so often), so the slowdown shouldn’t be caused by that hardware.



Although it’s possible this could be caused by the GUI, I would look at the code first and foremost. This is where my money is on.

I ran your test case and i got the same frame rate hit that you mentioned.



Your GUI has a lot of panels, and nifty is rendering around 300 objects when it’s displayed. Add that to your scene objects…that’s a performance killer.

My advice would be to drastically reduce this object count.

for example, over your chat panel you have a “AGOPRT” button bar. That’s 12 quads rendered to screen (one for the back ground and one for the letter of each button). What you could do here is to have one big panel with a background texture drawing the buttons (i guess the letters won’t change so bake them into the texture). from 12 you go to 1 quad.

Then to detect interaction on the panel and know what button has been hit, you can get the mouse coordinates of the click event.

[xml]

<interact onClick=“myMethod()”>

[/xml]

[java]

//Nifty automatically feeds x and y with mouse coordinates

public void myMethod(int x, int y){



Element buttonBar = nifty.getCurrentScreen().findElementByName(“buttonBar”);

//getting the x coordinates inside the button bar to find which button has been clicked

float offsetX = x - buttonBar.getX();

//test offsetX value and dispatch to relevant button action method

}

[/java]



you can apply this to the “Action bar” too, and the “1234” buttons to switch action bars.

As a rule of thumb try to avoid to mutiply panels when you can do one.

What you have to know is that there is one quad for each panel/layer that is not fully transparent (fully transparent are discarded). One text element is one quad (or the label control)

I don’t know about the chat control but i guess it’s a lot of quads, but there is not much you can do there.



Hope that helps

2 Likes

thanks nehon, I will try this aproach.



Edit:

Two additional questions …

Which Nifty version ships with the current nightly build?

Is there a command like nifty.getVersion() or something?

Back from testing. Sry for doubleposting but this information might be interesting for some people.



I’ve tried nehons aproach, everything looks like he says.



It seems there is a difference between the rendering of the Image Modes.



An simple Resize adds one object to the rendering.

An imageMode Resize which declares the parts of the image which will get scaled like:



from the Nifty-Panel Style

[xml]

imageMode=“resize:28,184,28,28,28,184,28,154,28,184,28,58”

[/xml]

adds 9 Objects so be careful to not overload your UI with such calls.



In the example UI posted above I used this method for all UI Panels which should be separated from eachother.



The drawback of this is that if you want a scaleable UI you have to use fixed size Images for each panel which should have a background different to a fixed color.



Don’t use too much

[xml]

<panel style=“nifty-panel”>

</panel>

[/xml]

1 Like
@jstelter2012 said:
Which Nifty version ships with the current nightly build?

Its called "the version that ships with jme" ^^ What exact change are you looking for?

I’m not looking for any special change.

It’s only in my interest.

@jstelter2012 said:
Don't use too much
[xml]
&lt;panel style=&quot;nifty-panel&quot;&gt;
&lt;/panel&gt;
[/xml]


Panels are Nifty's bread and butter. How did you come to the conclusion that the panel tag is evil? I'm very curious about that.

The style=“nifty-panel” tag is the problem, because it uses the mentioned image resize.

with this tag the panel uses 9 objects instead of one. In a “slim” ui this is ok, but in my project i use a UI with 9 Layer 5 windows, 4 popups and some custom components together with buttons and everything sticks to a styled panel. i got an object count over 580 without any rendered 3d data.



thats way too much. as nehon sayed before I take the aproach and design a nice background image for each panel and wrap everything together in a custom style without the image resize. to cut my object count to an healthy level.

1 Like

I guess you could take the style it’s based on and make it “static”, making everything to your particular needs. That way things would be better. That’s what I intend to do down the line. Just not there yet.

of course can you do it that way, but for someone who isn’t beware of the problem which could be upset your whole game, this should be mentioned somewhere.



My first aproach was more the simple way … put some panels whith the nice nifty style in place, and say hey the ui have to do what i want the design i can do another day.



then i run at the problem with the low fps and asking myself wtf what happend now…



the answer is fairly simple i don’t care about design and messed up myself with panels over panels. and Nifty does everything i wanted but slowed down the whole game.



Now after some testing I got the conclusion… don’t take nifty panel styles where a simple image will do the job.



that’s everything i wanted to say in the post above.

Hi folks back from testing now,



I’ve done what nehon suggested.

The whole process shrinked the UI to 31 Objects. The crappy fps value is still in place. I’ve taken two screenshots one with enabled UI, one without.

I don’t know why but the cleanup doesn’t result the slightest performance increase.



The screen without the UI is rendered with 71 fps

http://i.imgur.com/BuIRd.jpg



The screen with enabled UI is rendered with only 12 fps

http://i.imgur.com/YPFN1.jpg



any other suggestions?



I feel a bit helpless atm.

Uhm… That map up right… How does the code for that look?

ok 876 lines of xml is too long for this forum.

mainGame.xml



most of the layers are invisible. they shouldn’t get rendered right?



EDIT:

Things i tested:

Disabling the minimap (first thought of perfomance issues)

Framerate drops from (disabled) 75 to (enabled UI) 20.



Comment everything that isn’t visible in the mainGame UI

Framerate ok with about 60 fps



Reenabling one after another:

Minimap (70 Fps)

Action Bar (58 FPS)

Console (50 FPS)

Layer Hint (44 FPS)

Chat (36 FPS)

Window Layer (12 FPS)



from this i assume that the Window layer is eating most of the performance but why… it isn’t visible.



Could it be that the overload of the different layers with child elements are too time intensive to walk through?

Has anybody an UI with comparable size which is not causing this problem?