我如何从这个 jogl 程序中获得更多的每秒帧数? [关闭]

Posted

技术标签:

【中文标题】我如何从这个 jogl 程序中获得更多的每秒帧数? [关闭]【英文标题】:how do i get more frames per second from this jogl program? [closed] 【发布时间】:2012-09-07 20:33:01 【问题描述】:

试图从这个 jogl 程序中获得更多的 fps。理论fps很高,但实际fps很低。 jvisualvm 表示大部分(超过 90%)的时间都花在了 AWTAnimatorImpl.display() 和 GLDrawableHelper.displayImpl() 上。

package stanalone;
import static java.awt.Color.cyan;
import static java.awt.Color.magenta;
import static java.awt.Color.white;
import static java.awt.Color.yellow;
import static java.awt.Color.red;
import static java.lang.Math.PI;
import static java.lang.Math.cos;
import static java.lang.Math.min;
import static java.lang.Math.signum;
import static java.lang.Math.sin;
import static javax.media.opengl.GL.GL_ARRAY_BUFFER;
import static javax.media.opengl.GL.GL_COLOR_BUFFER_BIT;
import static javax.media.opengl.GL.GL_DEPTH_BUFFER_BIT;
import static javax.media.opengl.GL.GL_DEPTH_TEST;
import static javax.media.opengl.GL.GL_FLOAT;
import static javax.media.opengl.GL.GL_FRONT;
import static javax.media.opengl.GL.GL_FRONT_AND_BACK;
import static javax.media.opengl.GL.GL_LEQUAL;
import static javax.media.opengl.GL.GL_MAX_TEXTURE_SIZE;
import static javax.media.opengl.GL.GL_NICEST;
import static javax.media.opengl.GL.GL_POINTS;
import static javax.media.opengl.GL.GL_WRITE_ONLY;
import static javax.media.opengl.GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT;
import static javax.media.opengl.GL2GL3.GL_FILL;
import static javax.media.opengl.fixedfunc.GLLightingFunc.GL_SMOOTH;
import static javax.media.opengl.fixedfunc.GLMatrixFunc.GL_MODELVIEW;
import static javax.media.opengl.fixedfunc.GLMatrixFunc.GL_PROJECTION;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Point2D;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLJPanel;
import javax.media.opengl.fixedfunc.GLLightingFunc;
import javax.media.opengl.fixedfunc.GLPointerFunc;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.util.FPSAnimator;
import com.jogamp.opengl.util.gl2.GLUT;
class Histogram 
    public Histogram() 
        this(10,0,1);
    
    public Histogram(int bins,double low,double high) 
        this.bins=bins;
        bin=new int[bins];
        this.low=low;
        this.high=high;
        range=high-low;
    
    public void add(double[] x) 
        for(int i=0;i<x.length;i++)
            add(x[i]);
    
    public void add(double x) 
        n++;
        sum+=x;
        final double x2=x*x;
        sum2+=x2;
        min=Math.min(min,x);
        max=Math.max(max,x);
        if(x>=high)
            overflows++;
        else if(x<low)
            underflows++;
        else 
            double val=x-low;
            int index=(int)(bins*(val/range));
            bin[index]++;
        
    
    public void clear() 
        for(int i=0;i<bins;i++)
            bin[i]=0;
        overflows=0;
        underflows=0;
        min=Double.MAX_VALUE;
        max=Double.MIN_VALUE;
    
    public int n() 
        return n;
    
    public double low() 
        return low;
    
    public double high() 
        return high;
    
    public double range() 
        return high()-low();
    
    public int bins() 
        return bins;
    
    public double min() 
        return n==0?Double.NaN:min;
    
    public double max() 
        return n==0?Double.NaN:max;
    
    public double sum() 
        return n==0?Double.NaN:sum;
    
    public double mean() 
        return n==0?Double.NaN:sum/n;
    
    public double variance() 
        return n==0?Double.NaN:sum2/n-mean()*mean();
    
    public int bin(int index) 
        if(index<0)
            return underflows;
        else if(index>=bins)
            return overflows;
        else return bin[index];
    
    public double maxDifference() 
        double max=0;
        for(int i=0;i<bins();i++)
            max=Math.max(max,Math.abs(bin(i)-n()/(double)bins())/(n()/(double)bins()));
        return max;
    
    public String toString() 
        final StringBuffer sb=new StringBuffer();
        sb.append((float)min()).append("<=").append((float)mean()).append("<=").append((float)max()).append(" ");
        sb.append(bin(-1)).append(",[");
        for(int i=0;i<bins;i++)
            sb.append(i>0?",":"").append(bin(i));
        sb.append("],").append(bin(bins));
        return sb.toString();
    
    private int[] bin;
    private int n,bins,underflows,overflows;
    private final double low,high,range;
    private double min=Double.MAX_VALUE,max=Double.MIN_VALUE,sum,sum2;

class MyDataObject 
    MyDataObject(Point2D[] points) 
        this(points,white);
    
    MyDataObject(Point2D[] points,Color color) 
        this.points=points;
        this.color=color;
    
    Point2D[] points;
    Color color;
    static Point2D[] randomPoints(Random random,Point2D offset) 
        List<Point2D> l=new LinkedList<Point2D>();
        int n=nPoints/pieces.length;
        for(int j=0;j<n;j++)
            l.add(new Point2D.Double(offset.getX()+random.nextFloat(),offset.getY()+random.nextFloat()));
        return l.toArray(new Point2D[0]);
    
    static MyDataObject[] pieces;
    static Color[] colors=new Color[]cyan,magenta,yellow,white;
    static int nPoints=1000000;

class StandAlone implements GLEventListener 
    StandAlone(GLAutoDrawable drawable) 
        this.drawable=drawable;
        drawable.addGLEventListener(this);
        init();
    
    void init() 
        nVbos=4;
        vertexBufferIndices=new int[nVbos];
        for(int i=0;i<vertexBufferIndices.length;i++)
            vertexBufferIndices[i]=-1;
        numberOFVertices=new int[nVbos];
        // drawAxes=true;
        MyDataObject.pieces=new MyDataObject[nVbos];
        for(int i=0;i<nVbos;i++) 
            Point2D offset=new Point.Double(min(0,signum(cos(PI/4+i*PI/2))),min(0,signum(sin(PI/4+i*PI/2))));
            MyDataObject.pieces[i]=new MyDataObject(MyDataObject.randomPoints(random,offset),MyDataObject.colors[i%MyDataObject.colors.length]);
        
    
    static void setupFrame(Component component) 
        setupFrame(component,defaultFps);
    
    static void setupFrame(Component component,int fps) 
        component.setPreferredSize(new Dimension(displayWidth,displayHeight));
        final FPSAnimator animator=new FPSAnimator((GLAutoDrawable)component,fps,true);
        final JFrame frame=new JFrame();
        frame.getContentPane().add(component);
        frame.addWindowListener(new WindowAdapter() 
            @Override public void windowClosing(WindowEvent e) 
                new Thread() 
                    @Override public void run() 
                        if(animator.isStarted())
                            animator.stop();
                        System.exit(0);
                    
                .start();
            
        );
        frame.setTitle(TITLE);
        frame.pack();
        frame.setVisible(true);
        animator.start();
    
    static void setup() 
        GLProfile glprofile=GLProfile.getDefault();
        GLCapabilities glcapabilities=new GLCapabilities(glprofile);
        GLJPanel panel=new GLJPanel(glcapabilities);
        new StandAlone(panel);
        setupFrame(panel,200);
    
    public static void main(String[] args) 
        SwingUtilities.invokeLater(new Runnable() 
            @Override public void run() 
                setup();
            
        );
    
    private void createVbo(GL2 gl2,int[] n,int index) 
        if(!gl2.isFunctionAvailable("glGenBuffers")||!gl2.isFunctionAvailable("glBindBuffer")||!gl2.isFunctionAvailable("glBufferData")||!gl2.isFunctionAvailable("glDeleteBuffers"))  throw new RuntimeException("Vertex buffer objects not supported."); 
        gl2.glGenBuffers(1,vertexBufferIndices,index);
        // create vertex buffer data store without initial copy
        gl2.glBindBuffer(GL_ARRAY_BUFFER,vertexBufferIndices[index]);
        gl2.glBufferData(GL_ARRAY_BUFFER,n[0]*3*Buffers.SIZEOF_FLOAT*2,null,GL.GL_DYNAMIC_DRAW);
    
    private static void storeVerticesAndColors(FloatBuffer floatbuffer,MyDataObject w) 
        for(Point2D p:w.points) 
            floatbuffer.put((float)p.getX()).put((float)p.getY()).put(0);
            floatbuffer.put((float)(w.color.getRed()/255.));
            floatbuffer.put((float)(w.color.getGreen()/255.));
            floatbuffer.put((float)(w.color.getBlue()/255.));
        
        floatbuffer.rewind();
    
    private void fillVertexBuffer(GL2 gl2,MyDataObject piece,int index) 
        // map the buffer and write vertex and color data directly into it
        gl2.glBindBuffer(GL_ARRAY_BUFFER,vertexBufferIndices[index]);
        ByteBuffer bytebuffer=gl2.glMapBuffer(GL_ARRAY_BUFFER,GL_WRITE_ONLY);
        FloatBuffer floatbuffer=bytebuffer.order(ByteOrder.nativeOrder()).asFloatBuffer();
        storeVerticesAndColors(floatbuffer,piece);
        gl2.glUnmapBuffer(GL_ARRAY_BUFFER);
    
    protected int createAndFillVertexBuffer(GL2 gl2,MyDataObject piece,int index) 
        int[] n=new int[]piece.points.length;
        if(vertexBufferIndices[index]==-1)
            createVbo(gl2,n,index);
        fillVertexBuffer(gl2,piece,index);
        return n[0];
    
    private void renderPiece(GLAutoDrawable drawable,int index) 
        final GL2 gl2=drawable.getGL().getGL2();
        gl2.glColorMaterial(GL_FRONT_AND_BACK,GLLightingFunc.GL_AMBIENT_AND_DIFFUSE);
        gl2.glEnable(GLLightingFunc.GL_COLOR_MATERIAL);
        // draw all objects in vertex buffer
        gl2.glBindBuffer(GL_ARRAY_BUFFER,vertexBufferIndices[index]);
        gl2.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
        gl2.glEnableClientState(GLPointerFunc.GL_COLOR_ARRAY);
        gl2.glVertexPointer(3,GL_FLOAT,6*Buffers.SIZEOF_FLOAT,0);
        gl2.glColorPointer(3,GL_FLOAT,6*Buffers.SIZEOF_FLOAT,3*Buffers.SIZEOF_FLOAT);
        gl2.glPolygonMode(GL_FRONT,GL_FILL);
        gl2.glDrawArrays(GL_POINTS,0,1*numberOFVertices[index]);
        // disable arrays once we're done
        gl2.glBindBuffer(GL_ARRAY_BUFFER,0);
        gl2.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
        gl2.glDisableClientState(GLPointerFunc.GL_COLOR_ARRAY);
        gl2.glDisable(GLLightingFunc.GL_COLOR_MATERIAL);
    
    private void startTimeReporting() 
        t0=System.nanoTime();
        if(frame%reportPeriod==0)
            t0Frame=t0;
        if(frame>1) 
            double dt=(System.nanoTime()-t0Display);
            double millis=dt/1000000.;
            hDisplay.add(millis);
        
    
    void endTimeReporting() 
        double dt=(System.nanoTime()-t0);
        double millis=dt/1000000.;
        hRender.add(millis);
        if(++frame%reportPeriod==0) 
            System.out.println("average render time: "+hRender.mean()+" ms., max fps="+1000./hRender.mean());
            double dtFrames=System.nanoTime()-t0Frame;
            System.out.println("average time between calls to display: "+hDisplay.mean()+" ms., actual fps="+reportPeriod/(dtFrames/1000000.)*1000.);
            hRender.clear();
        
        t0Display=System.nanoTime();
    
    void update() 
        angle+=1;
    
    @Override public void reshape(GLAutoDrawable drawable,int x,int y,int width,int height) 
        System.out.println("super.reshape "+drawable);
        GL2 gl=drawable.getGL().getGL2();
        if(height==0)
            height=1;
        float aspect=(float)width/height;
        gl.glViewport(0,0,width,height);
        gl.glMatrixMode(GL_PROJECTION);
        gl.glLoadIdentity();
        // glu.gluPerspective(45.0,aspect,0.1,100.0);
        gl.glMatrixMode(GL_MODELVIEW);
        gl.glLoadIdentity();
    
    @Override public void init(final GLAutoDrawable drawable) 
        GL2 gl=drawable.getGL().getGL2();
        glu=new GLU();
        glut=new GLUT();
        gl.glClearColor(0.0f,0.0f,0.0f,0.0f);
        gl.glClearDepth(1.0f);
        gl.glEnable(GL_DEPTH_TEST);
        gl.glDepthFunc(GL_LEQUAL);
        gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
        gl.glShadeModel(GL_SMOOTH);
        for(int i=0;i<nVbos;i++)
            numberOFVertices[i]=createAndFillVertexBuffer(drawable.getGL().getGL2(),MyDataObject.pieces[i],i);
    
    @Override public void display(GLAutoDrawable drawable) 
        update();
        if(doTimeReporting)
            startTimeReporting();
        GL2 gl=drawable.getGL().getGL2();
        gl.glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        gl.glLoadIdentity();
        gl.glRotated(angle,0,1,0);
        gl.glColor3d(1,1,1);
        for(int i=0;i<nVbos;i++)
            renderPiece(drawable,i);
        if(doTimeReporting)
            endTimeReporting();
    
    @Override public void dispose(GLAutoDrawable drawable) 
    final GLAutoDrawable drawable;
    double angle;
    int nVbos;
    int[] vertexBufferIndices;
    int[] numberOFVertices;
    Random random=new Random();
    final int reportPeriod=100;
    boolean doTimeReporting=true;
    long t0,t0Frame,t0Display;
    int frame;
    Histogram hRender=new Histogram(10,0,10),hDisplay=new Histogram(10,0,100);
    int fps=defaultFps;
    protected GLU glu;
    protected GLUT glut;
    protected static String TITLE="JOGL 2.0 Setup (GLJPanel)";
    protected static final int displayWidth=1024;
    protected static final int displayHeight=1024;
    protected static final int defaultFps=60;

【问题讨论】:

嗨,Ray,首先切换到现代 OpenGL。其次,像glMapBuffer 这样的调用慢了。 如果我回到那个,我会尝试你的建议。谢谢。 不客气,让我给你一个简短的Hello Triangle 看起来更干净。谢谢 【参考方案1】:

如果在显示代码中使用了大部分处理能力,则可能是您使用了太多顶点或复杂的纹理计算。纹理方面,最好在可能的情况下在初始化时将纹理设置为对象,这样您的程序只需加载一次即可完成。对于顶点,请确保您不会意外复制任何内容,并尝试限制粒子效果,因为处理成本可能非常高。

【讨论】:

我只有 4 个 vbo,每个有 250000 个顶点和颜色,没有纹理。渲染时间约为 0.25 毫秒。为他们所有人。调用显示之间的时间为 37 毫秒。【参考方案2】:

您似乎误解了 OpenGL 的工作原理。正如您目前所做的那样,测量包装 OpenGL 调用所花费的时间几乎没有用处。

当您调用 opengl 命令时,它只是将命令放入处理队列并返回。 draw 对象所花费的实际时间并不是您发出所有绘图调用所花费的时间。

如果调用 display 之间的时间是 37 毫秒,那么这就是 GPU 处理您排队的所有命令所需的时间。

【讨论】:

我有一个带有片上显卡的 i3,所以这可能是个问题。但是 37 毫秒。 1000000 个顶点和颜色对我来说似乎有点慢。

以上是关于我如何从这个 jogl 程序中获得更多的每秒帧数? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何在opencv中计算每秒帧数?

如何将运动物理函数缩放到每秒帧数(在游戏引擎中)?

每秒帧数是啥意思

帧数和每秒帧数是一样的吗?

iOS AVFoundation 如何使用 CMTime 转换每秒相机帧数以创建延时摄影?

在python中获取gif的每秒帧数?