Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (739)
Games in Android Showcase (224)
games submitted by our members
Games in WIP (820)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Render-Time Benchmarking Problem - display() bug?  (Read 1925 times)
0 Members and 1 Guest are viewing this topic.
Offline lamster

Senior Newbie





« Posted 2003-09-20 17:59:00 »

I was under the impression that I could tell how long it'd take to render something by wrapping an appropriate subsection of the display(GLDrawable) function with time-checks and noting the elapsed time:
Ex.
before = hires.getTime()
gl.glBegin( GL.GL_QUADS )....gl.glEnd()
elapsed = hires.getTime()-before

While this method seems to capture _some_ of the time required to perform a particular render, I've recently noticed another associated time that is, in some cases, many times more important (say 400x for large shapes) and requires more careful benchmarking.  The time I refer to is the delay between successive display(GLDrawable) calls by an Animator which, as far as I can tell, is calling display in a pretty tight loop.

For example, when drawing 200 620x460 white quads to the screen on my p4/radeon.mobility.9000, the 'direct', timer-wrapped elapsed time is about 00.14ms, while the time between successive display calls jumps to around 63.52ms.  I'm sure that the successive call delay is directly related to the quad rendering because cutting the number-to-render in half also halves the successive display wait, and forgoing renders altogether brings successive display wait to a (healthy?) baseline of about 1.8ms.

I'm sure I must misunderstand something fundamental about how the OGL framebuffer gets swapped onscreen, or else this latency is the result of some enormous performance-destroying bug.

Please straighten me out Smiley

Example program to illustrate what I'm talking about:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
/* Demonstrates the (strange?) pauses between display(GLDrawable) calls
 * managed by an Animator when large amounts of area are filled during each
 * display call.  On my p4/mobility radeon 9000, high-res timing indicates
 * that the time _between_ display() calls is over 400x the time spent
 * within a particular display() function call when several hundred large
 * white quads are drawn to the screen each display() (63.52ms vs 00.14ms).
 ********************************************************************************/


import java.awt.*;
import java.awt.event.*;
import sun.misc.Perf;
import net.java.games.jogl.*;

public final class DDelay extends Frame implements GLEventListener, KeyListener
{
      private GraphicsDevice gd;
      private DisplayMode dm;

      // JOGL:
      private GLCanvas canvas;
      private Animator animator;

      public static void main( String[] args )
      {
            boolean openFullScreen = args.length >= 1 && args[0].equals("y");
            System.out.println( "open fullscreen = "+openFullScreen );
            DDelay test = new DDelay( openFullScreen );
            test.show();
      }

      public DDelay( boolean fs )
      {
            super( "Strange Delay Between display(GLDrawable) Calls" );

            GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas( new GLCapabilities() );
            canvas.addGLEventListener( this );
            add( canvas );
            animator = new Animator( canvas );

            addKeyListener( this );
            addWindowListener( new WindowAdapter(){public void windowClosing( WindowEvent e ){close();System.exit( 0 );}});

            gd = getGraphicsConfiguration().getDevice();
            dm = new DisplayMode( 640, 480, gd.getDisplayMode().getBitDepth(), gd.getDisplayMode().getRefreshRate() );

            fs = fs && ( dm != null && gd.isFullScreenSupported() );

            setIgnoreRepaint( true );
            setResizable( false );

            setUndecorated( fs );
            if( fs )
            {
                  gd.setFullScreenWindow( this );
                  gd.setDisplayMode( dm );
            }
            else
            {
                  pack();
                  Insets insets = getInsets();
                  int w = 640+insets.left+insets.right;
                  int h = 480+insets.top+insets.bottom;
                  setSize( w, h );
                  Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
                  setLocation( (screenSize.width-w)/2, (screenSize.height-h)/2 );
                  show();
            }

            animator.start();
      }

      // GLEventListener:
      public void init( GLDrawable drawable )
      {
            GL gl = drawable.getGL();
            gl.glEnable( GL.GL_DEPTH_TEST );
            gl.glEnable( GL.GL_CULL_FACE );
            drawable.addKeyListener( this );
      }
      public void reshape( GLDrawable drawable, int x, int y, int width, int height )
      {
            GL gl = drawable.getGL();
            GLU glu = drawable.getGLU();
            gl.glViewport( 0, 0, width, height );
            gl.glMatrixMode( GL.GL_PROJECTION );
            gl.glLoadIdentity();
            // java-style display coordinates, (0,0) is top left
            glu.gluOrtho2D( 0, 640, 480, 0 );
            gl.glMatrixMode( GL.GL_MODELVIEW );
      }
      public void displayChanged( GLDrawable arg0, boolean arg1, boolean arg2 ) {}

      public void display( GLDrawable drawable )
      {
            // begin display, record time for future printing
            double startDisplay = Timer.getTime();
            double betweenDisplays = startDisplay - endDisplay;

            GL gl = drawable.getGL();
            gl.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_ACCUM_BUFFER_BIT );
            gl.glColor3f( 1.0f, 1.0f, 1.0f );

            // draw a simple quad occupying most of the screen, 200 times (one on top of the next)
            for( int i = 0; i < 200; i++ )
            {
                  gl.glBegin( GL.GL_QUADS );
                        gl.glVertex2i( 10, 470 );
                        gl.glVertex2i( 630, 470 );
                        gl.glVertex2i( 630, 10 );
                        gl.glVertex2i( 10, 10 );
                  gl.glEnd();
            }

            // Every second, print how much time was spent drawing the quads, and how much time was spent between display() calls:
            if( lastPrint == 0 )
                  lastPrint = Timer.getTime();
            else if( startDisplay - lastPrint > PRINT_DELAY )
            {
                  System.out.println( "Between display()'s for "+printFormat.format(betweenDisplays) + " milliseconds" );
                  System.out.println( "Rendering display() for "+printFormat.format(lastRenderTime) + " milliseconds" );
                  System.out.println( "--------------------------------------------" );
                  lastPrint = startDisplay;
            }

            // end display, record time for future printing
            endDisplay = Timer.getTime();
            lastRenderTime = endDisplay - startDisplay;
      }

      private final static java.text.NumberFormat printFormat = java.text.NumberFormat.getNumberInstance();
      static
      {
            printFormat.setMinimumIntegerDigits(3);printFormat.setMinimumIntegerDigits(3);printFormat.setMinimumFractionDigits(3);printFormat.setMaximumFractionDigits(3);
      }
      private final static double PRINT_DELAY = 1000;
      private double lastPrint;
      private double lastRenderTime;
      private double endDisplay;

      // KeyListener:
      public final void keyTyped( KeyEvent e ){}
      public final void keyPressed( KeyEvent e )
      {
            if( e.getKeyCode() == KeyEvent.VK_ESCAPE )
            {
                  close();
                  System.exit( 0 );
            }
      }
      public final void keyReleased( KeyEvent e ){}
     
      public final void close(){      animator.stop(); }
}

final class Timer
{
      static Perf hiResTimer;
      static double freq;
     
      static
      {
            hiResTimer = Perf.getPerf();
            freq = hiResTimer.highResFrequency();
      }
     
      public static double getTime()
      {
            return hiResTimer.highResCounter() * 1000.0 / freq;
      }
}


And some example output:
[size=1]
Between display()'s for 127.347 milliseconds
Rendering display() for 000.142 milliseconds
--------------------------------------------
Between display()'s for 063.521 milliseconds
Rendering display() for 000.115 milliseconds
--------------------------------------------
[/size]
Oh yeah, every once in a while the generally consistent between-display time will spike by a factor of ~2.  And enabling DEPTH_TEST seemed to reduce between-display delay by about 40%.

Also, any advice on how to measure actual, total render time an operation ends up consuming, short of isolating the operation in its own test program and measuring successive display wait, would be nice.  Online OGL FAQs of apparent repute seem to indicate the sort of direct benchmarking I've tried would work..Sad
Offline pepijnve

Junior Devvie




Java games rock!


« Reply #1 - Posted 2003-09-20 20:44:20 »

Calling glBegin, glVertex, glEnd and measuring how long this takes doesn't necessarily measure how long it takes for all the work related to these operations to be completed. The driver might be buffering these commands internally. So this test only measures how long it takes to send data to the driver. The only guaranteed way to wait until everything has been completed is to call glFinish. Maybe if you add a glFinish call just after glEnd the two times will match better. Measuring like this however still doesn't take the buffer swap into account (if you're using double buffering).
Offline lamster

Senior Newbie





« Reply #2 - Posted 2003-09-21 06:02:18 »

Thanks! glFinish() is exactly what I needed.

Somehow every time I scanned the GL reference function list my mind skipped glFinish and fixated on glFlush, which, of course, wasn't helpful at all.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 
Ecumene (61 views)
2017-09-30 02:57:34

theagentd (82 views)
2017-09-26 18:23:31

cybrmynd (189 views)
2017-08-02 12:28:51

cybrmynd (189 views)
2017-08-02 12:19:43

cybrmynd (194 views)
2017-08-02 12:18:09

Sralse (206 views)
2017-07-25 17:13:48

Archive (770 views)
2017-04-27 17:45:51

buddyBro (904 views)
2017-04-05 03:38:00

CopyableCougar4 (1454 views)
2017-03-24 15:39:42

theagentd (1333 views)
2017-03-24 15:32:08
List of Learning Resources
by elect
2017-03-13 14:05:44

List of Learning Resources
by elect
2017-03-13 14:04:45

SF/X Libraries
by philfrei
2017-03-02 08:45:19

SF/X Libraries
by philfrei
2017-03-02 08:44:05

SF/X Libraries
by SkyAphid
2017-03-02 06:38:56

SF/X Libraries
by SkyAphid
2017-03-02 06:38:32

SF/X Libraries
by SkyAphid
2017-03-02 06:38:05

SF/X Libraries
by SkyAphid
2017-03-02 06:37:51
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!