Login  Register

Re: vbo - DrawArrays - threading question

Posted by rtayek on Sep 07, 2012; 7:38pm
URL: https://forum.jogamp.org/vbo-DrawArrays-threading-question-tp4026028p4026040.html

hi, trying to update some vbos in another thread. my code (please see below) hangs, when the timer thread tries to do a: FloatBuffer floatbuffer=bytebuffer.order(ByteOrder.nativeOrder()).asFloatBuffer(); after the buffer was mapped.

any pointers will be appreciated.

thanks

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.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 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=1000000/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};
}
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]);
                        System.out.println("offset="+offset);
                }
        }
        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);
                System.out.println("created "+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);
                System.out.println("buffer was mapped");
                FloatBuffer floatbuffer=bytebuffer.order(ByteOrder.nativeOrder()).asFloatBuffer(); // hangs here!
                System.out.println("store");
                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);
        }
        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);
                stpe.scheduleAtFixedRate(new Runnable() {
                        @Override public void run() {
                                int i=n%nVbos;
                                // MyDataObject.pieces[i].color=MyDataObject.colors[random.nextInt(MyDataObject.colors.length)];
                                MyDataObject.pieces[i].color=Color.red;
                                fillVertexBuffer(drawable.getGL().getGL2(),MyDataObject.pieces[i],i);
                                n++;
                        }
                        int n;
                },500,100,TimeUnit.MILLISECONDS);
        }
        @Override public void display(GLAutoDrawable drawable) {
                update();
                GL2 gl=drawable.getGL().getGL2();
                gl.glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
                gl.glLoadIdentity();
                gl.glRotated(2,1,0,0); // rotate a small amount so we can see the z axis
                gl.glRotated(-2,0,1,0); // rotate a small amount so we can see the z axis
                gl.glRotated(angle,0,1,0);
                gl.glColor3d(1,1,1);
                for(int i=0;i<nVbos;i++)
                        renderPiece(drawable,i);
        }
        @Override public void dispose(GLAutoDrawable drawable) {
                System.out.println("super.dispose "+drawable);
        }
        final GLAutoDrawable drawable;
        double angle;
        int nVbos;
        int[] vertexBufferIndices;
        int[] numberOFVertices;
        Random random=new Random();
        final ScheduledThreadPoolExecutor stpe=new ScheduledThreadPoolExecutor(4);
        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;
}