FrameBuffer initialization

Started by Wojtek, March 15, 2010, 08:21:53 PM

Previous topic - Next topic

Wojtek

Hello,

I would like to ask some questions related to FrameBuffer hardware mode initialization process.

My code for that is

buffer = new FrameBuffer(currentWidth, currentHeight, FrameBuffer.SAMPLINGMODE_GL_AA_4X);
canvas = buffer.enableGLCanvasRenderer();
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);

where currentWidth and currentHeight are dimensions of panel where canvas is displayed.

Well, first of all I am getting following errors in logs:

Java version is: 1.6.0_17
-> support for BufferedImage
Version helper for 1.5+ initialized!
-> using BufferedImage
Software renderer (OpenGL mode) initialized
Using LWJGL's AWTGLCanvas
Can't find desired videomode (1232 x 555 x 32) - searching for alternatives
Can't find alternative videomode (1232 x 555 x 32) - trying something else
[ Mon Mar 15 19:58:05 CET 2010 ] - ERROR: Can't find any suitable videomode!
[ Mon Mar 15 19:58:05 CET 2010 ] - ERROR: Can't set videomode - try different settings!
Software renderer disposed

I have read in docs that width and height must match to the one of available VideoModes for hardware mode, however when I ignore it, the game is running fine and the canvas content is displayed correctly - it fills to the panel content.
My question is how it is working in that case and what is the consequence of ignoring those error messages?

The other thing is that I do not see any difference between SAMPLINGMODE_NORMAL, SAMPLINGMODE_GL_AA_2X and SAMPLINGMODE_GL_AA_4X mode. Is there anything else that I have to do to enable it?
The logs about graphics card are:

Driver is: vga/6.0.6001.18000 on NVIDIA Corporation / GeForce 9650M GT/PCI/SSE2
GL_ARB_texture_env_combine supported and used!
FBO supported and used!
OpenGL renderer initialized (using 4 texture stages)


There is an screenshot of my ship, and I am assuming the AA is not working because I see sharp shapes of ship and station:



Thanks,
Wojtek

EgonOlsen

Interesting...this seems like a flaw when creating the AWTGLRenderer. Actually, it's not needed that the dimensions match those of a real video mode, but the init-method still queries the native modes. Which is actually fine, but if none fits, it shouldn't act like it does. Try this version instead to see if this is any better: http://www.jpct.net/download/beta/jpct.jar

It hopefully fixes both problems.

Wojtek

Works much better now - there is no error messages and I see AA working.
Thanks a lot!

Wojtek

Wojtek

#3
Hello,

I am wondering if it is possible to force full initialization of AWTGLCanvas during construction FrameBuffer in mentioned code.

What happens now is that the game main window is displayed and when I show a JPanel that contains AWTGLCanvas for a first time, game freezes for some time before it shows something. I am using JTabbedPane so the canvases that I am using are not visible from the begining.
Now, I am using compiled objects (at least main ones), and noticed also a bunch of following messages:

Using LWJGL's AWTGLCanvas
Software renderer disposed
Waiting for renderer to initialize...0
Waiting for renderer to initialize...1
Waiting for renderer to initialize...2
[...]
Waiting for renderer to initialize...48
Waiting for renderer to initialize...49
Subobject of object 15129/object15131 compiled using 670 vertices in 1ms!


My question is if it is possible to force full initialization of renderers/canvases and make that before the main window is displayed (lets say in constructor of window or in some method that will be called before setVisible())?
The other question is how to avoid such messages?

Thanks,
Wojtek

EgonOlsen

No, you can't initialize it when creating the FrameBuffer, because it has to happen in the awt event dispatch thread. This is what the object compiler has to wait for. To make it happen, it calls repaint() on the canvas and waits 50ms for this to happen. It does this 50 times, which is what you see in your log. However, it should acuatually never need this 50*50ms and IF it does, i would expect it to crash afterwards, because it's obviously not initialized...this is strange. Can you post more of the log?

Wojtek

There is a bigger log:

Java version is: 1.6.0_17
-> support for BufferedImage
Version helper for 1.5+ initialized!
-> using BufferedImage
Software renderer (OpenGL mode) initialized
Using LWJGL's AWTGLCanvas
Software renderer disposed
[6 times]

Driver is: vga/6.0.6001.18000 on NVIDIA Corporation / GeForce 9650M GT/PCI/SSE2
GL_ARB_texture_env_combine supported and used!
FBO supported and used!
OpenGL renderer initialized (using 4 texture stages)
[3 times]

Software renderer disposed
Software renderer disposed
Software renderer disposed
Adding Lightsource: 1
Adding Lightsource: 2
Visibility lists disposed!
Java version is: 1.6.0_17
-> support for BufferedImage
Version helper for 1.5+ initialized!
-> using BufferedImage
Software renderer (OpenGL mode) initialized
Using LWJGL's AWTGLCanvas
Software renderer disposed
Waiting for renderer to initialize...0
[...]
Waiting for renderer to initialize...49
Subobject of object 15153/object15155 compiled using 612 vertices in 6ms!
Subobject of object 15153/object15155 compiled using 2 vertices in 0ms!
Object 15153/object15155 compiled to 2 subobjects in 2518ms!
Waiting for renderer to initialize...0
[...]
Waiting for renderer to initialize...49
Subobject of object 15154/object15156 compiled using 512 vertices in 1ms!
Object 15154/object15156 compiled to 1 subobjects in 2511ms!
Waiting for renderer to initialize...0
[...]
Waiting for renderer to initialize...49
Subobject of object 15177/object15179 compiled using 512 vertices in 1ms!
Object 15177/object15179 compiled to 1 subobjects in 2508ms!
Waiting for renderer to initialize...0
[...]
Waiting for renderer to initialize...49
Subobject of object 15200/object15202 compiled using 24 vertices in 0ms!
Object 15200/object15202 compiled to 1 subobjects in 2502ms!
Waiting for renderer to initialize...0
[...]
Waiting for renderer to initialize...49
Subobject of object 15201/object15203 compiled using 24 vertices in 0ms!
Object 15201/object15203 compiled to 1 subobjects in 2500ms!
Driver is: vga/6.0.6001.18000 on NVIDIA Corporation / GeForce 9650M GT/PCI/SSE2
GL_ARB_texture_env_combine supported and used!
FBO supported and used!
OpenGL renderer initialized (using 4 texture stages)
Compiled 6 display lists!
Software renderer disposed


Currently I have 3 panels where I am displaying 3d views, however I see much more initializations. I think it is because of layout dimensions calculation/change (I am creating a new FrameBuffer with new dimensions when container is resized) - the main view is extended to fit the screen for example, however I think I can improve that.

QuoteNo, you can't initialize it when creating the FrameBuffer, because it has to happen in the awt event dispatch thread.
How about running that initialization from a method invoked in a awt event dispatch thread before displaying window?

QuoteThis is what the object compiler has to wait for. To make it happen, it calls repaint() on the canvas and waits 50ms for this to happen.

Hmm, it may happen then because I am calling world.renderScene(buffer); from awt event dispatch thread (a timer callback), so the compiler may wait for the same thread it is working in.

Thanks,
Wojtek

EgonOlsen

Additionally, initialization has to happen in the paintGL-method of the renderer, so there's no way to do this beforehand, even if you are already in the EDT. However, it may be sufficient to skip the wait if we are already in the EDT. I've updated the jar in link a few posts ealier with a version that does this (hopefully).

BTW: Are you actually using the same objects multiple times in different views? I don't think that this will work if you are using display lists (what you do, juding from the log), because they are bound to the gl context which should be different in multiple canvas'. Or does it work anyway? I 'm just asking because i never really tried this...and hoped that nobody never will, so that i would never have to care about this case... ;)

EgonOlsen

Looking at the code again, it might work with multiple contexts, because it tries to revert to normal vertex arrays in that case (which are somewhat slower, but not bound to the context). However, the current version might spam the log in that case. I've modified the jar again to prevent this (if it actually is a problem in your case).

Wojtek

QuoteAdditionally, initialization has to happen in the paintGL-method of the renderer, so there's no way to do this beforehand, even if you are already in the EDT. However, it may be sufficient to skip the wait if we are already in the EDT. I've updated the jar in link a few posts ealier with a version that does this (hopefully).
Ok, I understand. In the meantime I have reduced the amount of reinitialization of the FrameBuffers on resize event, so now each canvas is initialzied only once. Additionally I noticed that the problem with waiting was related to the fact, that I was adding a new object to world (and run compile() on it) and reinitializing a FB in the same time (both operations were a result of the same event). Now I ensured that the canvas size is not changed in that time and now it seems to work ok.

Regarding to the link, I am not sure which one I should used - one from main page, or perhaps http://www.jpct.net/download/beta/jpct.jar.

QuoteBTW: Are you actually using the same objects multiple times in different views? I don't think that this will work if you are using display lists (what you do, juding from the log), because they are bound to the gl context which should be different in multiple canvas'. Or does it work anyway? I 'm just asking because i never really tried this...and hoped that nobody never will, so that i would never have to care about this case...
Quote
Looking at the code again, it might work with multiple contexts, because it tries to revert to normal vertex arrays in that case (which are somewhat slower, but not bound to the context). However, the current version might spam the log in that case. I've modified the jar again to prevent this (if it actually is a problem in your case).

My code is working in that way, that I am loading first all models, run build() and compile() and put them to "factory".
Next I am creating 3 views (with different FB, worlds, canvases etc).
When I want do display some objects, I run following method:

public Object3D createObject()
{
    Object3D result = object.cloneObject(); //it is the model
    result.compile();
    return result;
}

and adding object to specific world.
Is that a wrong concept?

I am not sharing objects between worlds, however I have noticed that sometimes (not all times) I receive exceptions like:

Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: java.lang.NullPointerException
at com.threed.jpct.AWTJPCTCanvas.paintGL(Unknown Source)
at org.lwjgl.opengl.AWTGLCanvas.paint(AWTGLCanvas.java:288)
at org.lwjgl.opengl.AWTGLCanvas.update(AWTGLCanvas.java:317)
at sun.awt.RepaintArea.updateComponent(Unknown Source)
at sun.awt.RepaintArea.paint(Unknown Source)
at sun.awt.windows.WComponentPeer.handleEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Caused by: java.lang.NullPointerException
at com.threed.jpct.CompiledInstance.render(Unknown Source)
at com.threed.jpct.AWTGLRenderer.drawVertexArray(Unknown Source)
... 15 more



I am wondering also how to use shareCompiledData() and compileAndStrip() for my models - I was not able to do that without problems so far so I am not using it yet.

Thanks,
Wojtek

EgonOlsen

This one: http://www.jpct.net/download/beta/jpct.jar.

If you are using different worlds with different objects, all is fine because each object carries it's own set opf display lists bound to the specific context in which it is used. About the excpetion...might be a problem with multiple threads working on the objects. jPCT isn't thread safe, so if you modify the world for example, make sure that you aren't doing this while some rendering takes places. There are three ways to accomplish that:


  • Do it in the EDT on your own
  • Do it in the EDT by implementing an IPaintListener and execute your code in one of the methods that it offers (prefered to the solution above)
  • Do it in some other thread of your choice, but synchronize it with FrameBuffer.getLock()

I'm not sure what the problem with sharing and stripping might be in your case. Any exceptions or something? In case of sharing, make sure that you are sharing with objects that live in the same context, i.e. not with the blue print object from your factory, because that will cause this object to be compiled using the gl context of the first objects that shares data with it...and all others will try to reuse it and that will work only if you are in the same context.


Wojtek

QuoteThis one: http://www.jpct.net/download/beta/jpct.jar.
Thanks :)

QuoteAbout the excpetion...might be a problem with multiple threads working on the objects.
Hmm, the thread that sets the new Object3D to the world is called AWT-EventQueue-0 (this is a handler method for click on grid's row). The thread where an exception is thrown is also called the same, but eclipse debugger shows that this is another thread. I do not know AWT/swing much so I cannot say why I have multiple threads for that (perhaps because eclipse stopped threads that thrown an exception so AWT created another one?)... But I will try to investigate it a little bit more...

QuoteI'm not sure what the problem with sharing and stripping might be in your case. Any exceptions or something? In case of sharing, make sure that you are sharing with objects that live in the same context, i.e. not with the blue print object from your factory, because that will cause this object to be compiled using the gl context of the first objects that shares data with it...and all others will try to reuse it and that will work only if you are in the same context.
Oh ok, so this must occur because I am using one blueprint as a clone source for objects that belongs to different contexts.
The exception that I am getting when I do the sharing and stripping is:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
Additional visibility list (2) created with size: 10000
at com.threed.jpct.CompiledInstance.fill(Unknown Source)
at com.threed.jpct.Object3DCompiler.compile(Unknown Source)
at com.threed.jpct.VersionHelper5.compile(Unknown Source)
at com.threed.jpct.World.renderScene(Unknown Source)
at game.ui.swing.components.jpct.JPCTPanel.renderContent(JPCTPanel.java:128)
at game.ui.swing.components.jpct.ShipFlightPanel.processBackground(ShipFlightPanel.java:157)
at game.ui.swing.views.gameWindow.FlightView.updateView(FlightView.java:74)
at game.ui.swing.views.GameWindowView.updateViews(GameWindowView.java:396)
at game.ui.swing.views.GameWindowView.access$4(GameWindowView.java:387)
at game.ui.swing.views.GameWindowView$6$1.run(GameWindowView.java:378)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

I will have to do a little bit bigger change to solve that, but anyway now it is working because I do not use those methods...

Thanks for help!
Wojtek

EgonOlsen

Sounds a bit twisted with all those AWT event queues...however, the null pointer in rendering is caused by another thread than the rendering thread manipulating the world almost always. You can find references to it in various posts and cleaning that thread intermix always cured the problem. I don't know why you have multiple event queues (AWT can do this...we used that at work some time ago until it bit us badly... ;D), but maybe that's the reason. If you are doing your adding and removing in the IPaintListener's method, you should be save.

I don't know about this sharing/stripping thing....if you could provide me a simple test case, i would be grateful.

Wojtek

Hello,

I am sorry that I haven't written for so long - I have not had time to look at it and prepare example.
Well the problem with NullPointer seems to be that what you have said in some posts earlier ie. to not share objects between different FrameBuffers:


import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;

public class Test2 extends JFrame implements Runnable
{
    private static final long serialVersionUID = -1203822572518219468L;
    private World world;
    private FrameBuffer buffer;
    private Canvas canvas;
    private boolean initialized = false;
    private FrameBuffer buffer2;
    private Canvas canvas2;
    private World world2;
    private boolean alive = true;

    public static void main(String[] args)
    {
new Test2();
    }

    public Test2()
    {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
init();
pack();
setVisible(true);
    }

    private static World createWorld()
    {
World w = new World();
w.setAmbientLight(100, 100, 100);
w.getCamera().setPosition(new SimpleVector(200, 0, 0));
w.getCamera().lookAt(SimpleVector.ORIGIN);
return w;
    }

    public void init()
    {
world = createWorld();
world2 = createWorld();

Object3D BLUEPRINT = Primitives.getPyramide(10);
Object3D o1 = BLUEPRINT.cloneObject();
o1.compileAndStrip();
world.addObject(o1);
Object3D o2 = BLUEPRINT.cloneObject();
o2.compileAndStrip();
world2.addObject(o2);

buffer = createBuffer();
buffer2 = createBuffer();

add(canvas = buffer.enableGLCanvasRenderer(), BorderLayout.LINE_START);
add(canvas2 = buffer2.enableGLCanvasRenderer(), BorderLayout.LINE_END);
initialized = true;
new Thread(this).start();
    }

    private static FrameBuffer createBuffer()
    {
FrameBuffer buffer = new FrameBuffer(300, 300,
FrameBuffer.SAMPLINGMODE_GL_AA_4X);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
return buffer;
    }

    @Override
    public void run()
    {

while (alive)
{
    this.repaint();
    try
    {
Thread.sleep(1000);
    }
    catch (InterruptedException e)
    {
    }
}
alive = false;

    }

    private static void paint(FrameBuffer buffer, World world, Canvas canvas)
    {
buffer.clear(Color.BLACK);
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
canvas.repaint();
    }

    @Override
    public void paint(Graphics g)
    {
if (!initialized)
    return;
paint(buffer, world, canvas);
paint(buffer2, world2, canvas2);
    }
}


Everything is fine if o2 is added to first world. If it is added to world2, the mentioned exception is thrown.

Thanks,
Wojtek