title: OpenGL ES - Too much work on main thread
body: <p>I'm trying to render a 3D cube with different textures on each face (a dice), it works flawlessly when I only render the cube with one of the same image, but the cube doesn't even display and the following is thrown in the android monitor when I try to do the former:</p>
  
  <p>Skipped 36 frames!  The application may be doing too much work on its main thread.</p>
  
  <p>After some research I'm aware that I could run this "heavy processing" in its own thread but I'm lost as to how to go about it. I'm relatively new to OpenGL rendering so I don't know whether my code is super optimal either.</p>
  
  <p>I'm thinking I should run the Dice3D.java in another thread? This is the only class that doesn't extend or implement anything and through a little research I have found the class needs to implement runnable?</p>
  
  <p>Any help in making this work would be great, thanks in advance!</p>
  
  <p>Here are my classes:</p>
  
  <p><strong>OpenGLRenderer.java</strong></p>
  
  <pre><code>public class OpenGLRenderer implements GLSurfaceView.Renderer {
  
      private Context context;
      private Dice3D dice3D;
  
      public OpenGLRenderer(Context context, FrameLayout openGLLayout) {
          this.context = context;
          dice3D = new Dice3D(context);
  
          GLSurfaceView glView = new GLSurfaceView(context);
          glView.setRenderer(this);
  
          //put to welcome layout
          openGLLayout.addView(glView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,   FrameLayout.LayoutParams.MATCH_PARENT));
      }
  
      private float mCubeRotation;
  
      @Override
      public void onSurfaceCreated(GL10 gl, EGLConfig config) {
          gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);  // Set color's clear-value to black
          gl.glClearDepthf(1.0f);            // Set depth's clear-value to farthest
          gl.glEnable(GL10.GL_DEPTH_TEST);   // Enables depth-buffer for hidden surface removal
          gl.glDepthFunc(GL10.GL_LEQUAL);    // The type of depth testing to do
          gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);  // nice perspective view
          gl.glShadeModel(GL10.GL_SMOOTH);   // Enable smooth shading of color
          gl.glDisable(GL10.GL_DITHER);      // Disable dithering for better performance
  
          // Setup Texture, each time the surface is created (NEW)
          dice3D.loadTexture(gl);             // Load images into textures (NEW)
          gl.glEnable(GL10.GL_TEXTURE_2D);  // Enable texture (NEW)
      }
  
      @Override
      public void onDrawFrame(GL10 gl) {
          gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
          gl.glLoadIdentity();
          gl.glTranslatef(0.0f, 0.0f, -6.0f);
          gl.glRotatef(mCubeRotation, 1.0f, 1.0f, 1.0f);
          dice3D.draw(gl);
          mCubeRotation -= 0.15f;
      }
  
      @Override
      public void onSurfaceChanged(GL10 gl, int width, int height) {
          gl.glViewport(0, 0, width, height);
          gl.glMatrixMode(GL10.GL_PROJECTION);
          gl.glLoadIdentity();
          GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 100.0f);
          gl.glViewport(0, 0, width, height);
  
          gl.glMatrixMode(GL10.GL_MODELVIEW);
          gl.glLoadIdentity();
      }
  }
  </code></pre>
  
  <p><strong>Dice3D.java</strong></p>
  
  <pre><code>public class Dice3D {
  
      private FloatBuffer vertexBuffer; // Buffer for vertex-array
      private FloatBuffer texBuffer;    // Buffer for texture-coords-array (NEW)
  
      private int numFaces = 6;
      private int[] imageFileIDs = {  // Image file IDs
              R.drawable.one,
              R.drawable.two,
              R.drawable.three,
              R.drawable.four,
              R.drawable.five,
              R.drawable.six
      };
      private int[] textureIDs = new int[numFaces];
      private Bitmap[] bitmap = new Bitmap[numFaces];
  
      // Constructor - Set up the buffers
      public Dice3D(Context context) {
          // Setup vertex-array buffer. Vertices in float. An float has 4 bytes
          ByteBuffer vbb = ByteBuffer.allocateDirect(12 * 4 * numFaces);
          vbb.order(ByteOrder.nativeOrder()); // Use native byte order
          vertexBuffer = vbb.asFloatBuffer(); // Convert from byte to float
  
          for (int face = 0; face &lt; numFaces; face++) {
              bitmap[face] = BitmapFactory.decodeStream(context.getResources().openRawResource(imageFileIDs[face]));
  
              float[] vertices = { // Vertices for a face
                      -1.0f, -1.0f, 0.0f,  // 0. left-bottom-front
                      1.0f, -1.0f, 0.0f,  // 1. right-bottom-front
                      -1.0f,  1.0f, 0.0f,  // 2. left-top-front
                      1.0f,  1.0f, 0.0f   // 3. right-top-front
              };
              vertexBuffer.put(vertices);  // Populate
          }
          vertexBuffer.position(0);    // Rewind
  
          float[] texCoords = { // Texture coords for the above face (NEW)
                  0.0f, 1.0f,  // A. left-bottom (NEW)
                  1.0f, 1.0f,  // B. right-bottom (NEW)
                  0.0f, 0.0f,  // C. left-top (NEW)
                  1.0f, 0.0f   // D. right-top (NEW)
          };
  
          // Setup texture-coords-array buffer, in float. An float has 4 bytes (NEW)
          ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4 * numFaces);
          tbb.order(ByteOrder.nativeOrder());
          texBuffer = tbb.asFloatBuffer();
          for (int face = 0; face &lt; numFaces; face++) {
              texBuffer.put(texCoords);
          }
          texBuffer.position(0);
      }
  
      // Draw the shape
      public void draw(GL10 gl) {
          gl.glFrontFace(GL10.GL_CCW);    // Front face in counter-clockwise orientation
          gl.glEnable(GL10.GL_CULL_FACE); // Enable cull face
          gl.glCullFace(GL10.GL_BACK);    // Cull the back face (don't display)
  
          gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
          gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
          gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  // Enable texture-coords-array (NEW)
          gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer); // Define texture-coords buffer (NEW)
  
          // front
          gl.glPushMatrix();
          gl.glTranslatef(0.0f, 0.0f, 1.0f);
          gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
          gl.glPopMatrix();
  
          // left
          gl.glPushMatrix();
          gl.glRotatef(270.0f, 0.0f, 1.0f, 0.0f);
          gl.glTranslatef(0.0f, 0.0f, 1.0f);
          gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
          gl.glPopMatrix();
  
          // back
          gl.glPushMatrix();
          gl.glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
          gl.glTranslatef(0.0f, 0.0f, 1.0f);
          gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
          gl.glPopMatrix();
  
          // right
          gl.glPushMatrix();
          gl.glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
          gl.glTranslatef(0.0f, 0.0f, 1.0f);
          gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
          gl.glPopMatrix();
  
          // top
          gl.glPushMatrix();
          gl.glRotatef(270.0f, 1.0f, 0.0f, 0.0f);
          gl.glTranslatef(0.0f, 0.0f, 1.0f);
          gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
          gl.glPopMatrix();
  
          // bottom
          gl.glPushMatrix();
          gl.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
          gl.glTranslatef(0.0f, 0.0f, 1.0f);
          gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
          gl.glPopMatrix();
  
          gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  // Disable texture-coords-array
          gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
          gl.glDisable(GL10.GL_CULL_FACE);
      }
  
      // Load an image into GL texture
      public void loadTexture(GL10 gl) {
          gl.glGenTextures(6, textureIDs, 0); // Generate texture-ID array for 6 IDs
  
          // Generate OpenGL texture images
          for (int face = 0; face &lt; numFaces; face++) {
              gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[face]);
              // Build Texture from loaded bitmap for the currently-bind texture ID
              GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap[face], 0);
              bitmap[face].recycle();
          }
      }
  
  }
  </code></pre>
  
  <p><strong>and finally my activity Welcome.java</strong></p>
  
  <pre><code>public class Welcome extends AppCompatActivity {
  
      LinearLayout l1,l2;
      public Button btnsub;
      Animation uptodown,downtoup;
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          requestWindowFeature(Window.FEATURE_NO_TITLE);
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_welcome);
  
          FrameLayout openGLLayout = (FrameLayout) findViewById(R.id.frameLayout1);
  
          //creates an openGL surface and renders it to the framelayout in the activity layout
          OpenGLRenderer gl3DView = new OpenGLRenderer(this, openGLLayout);
  
  
          btnsub = (Button)findViewById(R.id.buttonsub);
          btnsub.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  Intent test = new Intent(Welcome.this,DiceGame.class);
                  startActivity(test);
              }
          });
          l1 = (LinearLayout) findViewById(R.id.l1);
          l2 = (LinearLayout) findViewById(R.id.l2);
          uptodown = AnimationUtils.loadAnimation(this,R.anim.uptodown);
          downtoup = AnimationUtils.loadAnimation(this,R.anim.downtoup);
          l1.setAnimation(uptodown);
          l2.setAnimation(downtoup);
  
      }
  }
  </code></pre>