فهرست منبع

* Added glGetError() checks after every GL call (its ugly, I know, but it helps with debugging). Added option to disable it with constant on RendererUtil.ENABLE_ERROR_CHECKING.
* Set lastFb in OGLESShaderRenderer when context is reset, this is needed otherwise the state tracker would not work correctly.
* Fix issue with Mesh.Mode.Hybrid that wasn't rendering triangle fans correctly (was rendering them as triangle strips instead).
* Remove call to glPointSize in OGLESShaderRenderer (it would most likely crash anyway, since GLES10 calls can't be used in a GLES20 context)
* TestCustomMesh now uses shorts instead of ints for the index buffer. 32-bit indices are not supported on Android and are slower on Desktop, don't use them if you can avoid it.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10525 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

sha..RD 12 سال پیش
والد
کامیت
27bf244729

+ 152 - 25
engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java

@@ -121,13 +121,6 @@ public class OGLESShaderRenderer implements Renderer {
         nameBuf.rewind();
     }
 
-    private void checkGLError() {
-        int error;
-        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
-            throw new RendererException("OpenGL Error " + error);
-        }
-    }
-
     public Statistics getStatistics() {
         return statistics;
     }
@@ -330,6 +323,9 @@ public class OGLESShaderRenderer implements Renderer {
         // Allocate buffer for compressed formats.
         IntBuffer compressedFormats = BufferUtils.createIntBuffer(numCompressedFormats);
         GLES20.glGetIntegerv(GLES20.GL_COMPRESSED_TEXTURE_FORMATS, compressedFormats);
+        
+        // Check for errors after all glGet calls.
+        RendererUtil.checkGLError();
 
         // Print compressed formats.
         for (int i = 0; i < numCompressedFormats; i++) {
@@ -337,9 +333,10 @@ public class OGLESShaderRenderer implements Renderer {
         }
 
         TextureUtil.loadTextureFeatures(extensions);
-
+        
         applyRenderState(RenderState.DEFAULT);
         GLES20.glDisable(GLES20.GL_DITHER);
+        RendererUtil.checkGLError();
 
         useVBO = false;
 
@@ -363,7 +360,7 @@ public class OGLESShaderRenderer implements Renderer {
         objManager.resetObjects();
         statistics.clearMemory();
         boundShader = null;
-//        lastFb = null;
+        lastFb = null;
         context.reset();
     }
 
@@ -383,6 +380,7 @@ public class OGLESShaderRenderer implements Renderer {
     \*********************************************************************/
     public void setDepthRange(float start, float end) {
         GLES20.glDepthRangef(start, end);
+        RendererUtil.checkGLError();
     }
 
     public void clearBuffers(boolean color, boolean depth, boolean stencil) {
@@ -398,11 +396,13 @@ public class OGLESShaderRenderer implements Renderer {
         }
         if (bits != 0) {
             GLES20.glClear(bits);
+            RendererUtil.checkGLError();
         }
     }
 
     public void setBackgroundColor(ColorRGBA color) {
         GLES20.glClearColor(color.r, color.g, color.b, color.a);
+        RendererUtil.checkGLError();
     }
 
     public void applyRenderState(RenderState state) {
@@ -418,24 +418,30 @@ public class OGLESShaderRenderer implements Renderer {
         if (state.isDepthTest() && !context.depthTestEnabled) {
             GLES20.glEnable(GLES20.GL_DEPTH_TEST);
             GLES20.glDepthFunc(GLES20.GL_LEQUAL);
+            RendererUtil.checkGLError();
             context.depthTestEnabled = true;
         } else if (!state.isDepthTest() && context.depthTestEnabled) {
             GLES20.glDisable(GLES20.GL_DEPTH_TEST);
+            RendererUtil.checkGLError();
             context.depthTestEnabled = false;
         }
 
         if (state.isDepthWrite() && !context.depthWriteEnabled) {
             GLES20.glDepthMask(true);
+            RendererUtil.checkGLError();
             context.depthWriteEnabled = true;
         } else if (!state.isDepthWrite() && context.depthWriteEnabled) {
             GLES20.glDepthMask(false);
+            RendererUtil.checkGLError();
             context.depthWriteEnabled = false;
         }
         if (state.isColorWrite() && !context.colorWriteEnabled) {
             GLES20.glColorMask(true, true, true, true);
+            RendererUtil.checkGLError();
             context.colorWriteEnabled = true;
         } else if (!state.isColorWrite() && context.colorWriteEnabled) {
             GLES20.glColorMask(false, false, false, false);
+            RendererUtil.checkGLError();
             context.colorWriteEnabled = false;
         }
 //        if (state.isPointSprite() && !context.pointSprite) {
@@ -452,6 +458,8 @@ public class OGLESShaderRenderer implements Renderer {
                 GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
                 GLES20.glPolygonOffset(state.getPolyOffsetFactor(),
                         state.getPolyOffsetUnits());
+                RendererUtil.checkGLError();
+                
                 context.polyOffsetEnabled = true;
                 context.polyOffsetFactor = state.getPolyOffsetFactor();
                 context.polyOffsetUnits = state.getPolyOffsetUnits();
@@ -460,6 +468,8 @@ public class OGLESShaderRenderer implements Renderer {
                         || state.getPolyOffsetUnits() != context.polyOffsetUnits) {
                     GLES20.glPolygonOffset(state.getPolyOffsetFactor(),
                             state.getPolyOffsetUnits());
+                    RendererUtil.checkGLError();
+                    
                     context.polyOffsetFactor = state.getPolyOffsetFactor();
                     context.polyOffsetUnits = state.getPolyOffsetUnits();
                 }
@@ -467,6 +477,8 @@ public class OGLESShaderRenderer implements Renderer {
         } else {
             if (context.polyOffsetEnabled) {
                 GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL);
+                RendererUtil.checkGLError();
+                
                 context.polyOffsetEnabled = false;
                 context.polyOffsetFactor = 0;
                 context.polyOffsetUnits = 0;
@@ -475,8 +487,10 @@ public class OGLESShaderRenderer implements Renderer {
         if (state.getFaceCullMode() != context.cullMode) {
             if (state.getFaceCullMode() == RenderState.FaceCullMode.Off) {
                 GLES20.glDisable(GLES20.GL_CULL_FACE);
+                RendererUtil.checkGLError();
             } else {
                 GLES20.glEnable(GLES20.GL_CULL_FACE);
+                RendererUtil.checkGLError();
             }
 
             switch (state.getFaceCullMode()) {
@@ -484,12 +498,15 @@ public class OGLESShaderRenderer implements Renderer {
                     break;
                 case Back:
                     GLES20.glCullFace(GLES20.GL_BACK);
+                    RendererUtil.checkGLError();
                     break;
                 case Front:
                     GLES20.glCullFace(GLES20.GL_FRONT);
+                    RendererUtil.checkGLError();
                     break;
                 case FrontAndBack:
                     GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK);
+                    RendererUtil.checkGLError();
                     break;
                 default:
                     throw new UnsupportedOperationException("Unrecognized face cull mode: "
@@ -502,6 +519,7 @@ public class OGLESShaderRenderer implements Renderer {
         if (state.getBlendMode() != context.blendMode) {
             if (state.getBlendMode() == RenderState.BlendMode.Off) {
                 GLES20.glDisable(GLES20.GL_BLEND);
+                RendererUtil.checkGLError();
             } else {
                 GLES20.glEnable(GLES20.GL_BLEND);
                 switch (state.getBlendMode()) {
@@ -532,6 +550,7 @@ public class OGLESShaderRenderer implements Renderer {
                         throw new UnsupportedOperationException("Unrecognized blend mode: "
                                 + state.getBlendMode());
                 }
+                RendererUtil.checkGLError();
             }
             context.blendMode = state.getBlendMode();
         }
@@ -543,6 +562,8 @@ public class OGLESShaderRenderer implements Renderer {
     public void setViewPort(int x, int y, int w, int h) {
         if (x != vpX || vpY != y || vpW != w || vpH != h) {
             GLES20.glViewport(x, y, w, h);
+            RendererUtil.checkGLError();
+            
             vpX = x;
             vpY = y;
             vpW = w;
@@ -553,10 +574,12 @@ public class OGLESShaderRenderer implements Renderer {
     public void setClipRect(int x, int y, int width, int height) {
         if (!context.clipRectEnabled) {
             GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
+            RendererUtil.checkGLError();
             context.clipRectEnabled = true;
         }
         if (clipX != x || clipY != y || clipW != width || clipH != height) {
             GLES20.glScissor(x, y, width, height);
+            RendererUtil.checkGLError();
             clipX = x;
             clipY = y;
             clipW = width;
@@ -567,6 +590,7 @@ public class OGLESShaderRenderer implements Renderer {
     public void clearClipRect() {
         if (context.clipRectEnabled) {
             GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
+            RendererUtil.checkGLError();
             context.clipRectEnabled = false;
 
             clipX = 0;
@@ -577,10 +601,8 @@ public class OGLESShaderRenderer implements Renderer {
     }
 
     public void onFrame() {
-        int error = GLES20.glGetError();
-        if (error != GLES20.GL_NO_ERROR){
-            throw new RendererException("OpenGL Error " + error + ". Enable error checking for more info.");
-        }
+        RendererUtil.checkGLErrorForced();
+
         objManager.deleteUnused(this);
     }
 
@@ -598,6 +620,8 @@ public class OGLESShaderRenderer implements Renderer {
         stringBuf.append(uniform.getName()).append('\0');
         updateNameBuffer();
         int loc = GLES20.glGetUniformLocation(shader.getId(), uniform.getName());
+        RendererUtil.checkGLError();
+        
         if (loc < 0) {
             uniform.setLocation(-1);
             // uniform is not declared in shader
@@ -610,6 +634,8 @@ public class OGLESShaderRenderer implements Renderer {
         int shaderId = shader.getId();
         if (context.boundShaderProgram != shaderId) {
             GLES20.glUseProgram(shaderId);
+            RendererUtil.checkGLError();
+            
             statistics.onShaderUse(shader, true);
             boundShader = shader;
             context.boundShaderProgram = shaderId;
@@ -626,6 +652,8 @@ public class OGLESShaderRenderer implements Renderer {
 
         if (context.boundShaderProgram != shaderId) {
             GLES20.glUseProgram(shaderId);
+            RendererUtil.checkGLError();
+            
             statistics.onShaderUse(shader, true);
             boundShader = shader;
             context.boundShaderProgram = shaderId;
@@ -730,6 +758,7 @@ public class OGLESShaderRenderer implements Renderer {
             default:
                 throw new UnsupportedOperationException("Unsupported uniform type: " + uniform.getVarType());
         }
+        RendererUtil.checkGLError();
     }
 
     protected void updateShaderUniforms(Shader shader) {
@@ -775,6 +804,8 @@ public class OGLESShaderRenderer implements Renderer {
         if (id == -1) {
             // Create id
             id = GLES20.glCreateShader(convertShaderType(source.getType()));
+            RendererUtil.checkGLError();
+            
             if (id <= 0) {
                 throw new RendererException("Invalid ID received when trying to create shader.");
             }
@@ -821,7 +852,10 @@ public class OGLESShaderRenderer implements Renderer {
 //        System.out.println("precision "+precision[0]);
 
         GLES20.glCompileShader(id);
+        RendererUtil.checkGLError();
+        
         GLES20.glGetShaderiv(id, GLES20.GL_COMPILE_STATUS, intBuf1);
+        RendererUtil.checkGLError();
 
         boolean compiledOK = intBuf1.get(0) == GLES20.GL_TRUE;
         String infoLog = null;
@@ -830,7 +864,7 @@ public class OGLESShaderRenderer implements Renderer {
             // even if compile succeeded, check
             // log for warnings
             GLES20.glGetShaderiv(id, GLES20.GL_INFO_LOG_LENGTH, intBuf1);
-            checkGLError();
+            RendererUtil.checkGLError();
             infoLog = GLES20.glGetShaderInfoLog(id);
         }
 
@@ -858,6 +892,7 @@ public class OGLESShaderRenderer implements Renderer {
         if (id == -1) {
             // create program
             id = GLES20.glCreateProgram();
+            RendererUtil.checkGLError();
 
             if (id <= 0) {
                 throw new RendererException("Invalid ID received when trying to create shader program.");
@@ -871,23 +906,30 @@ public class OGLESShaderRenderer implements Renderer {
             if (source.isUpdateNeeded()) {
                 updateShaderSourceData(source);
             }
+            
             GLES20.glAttachShader(id, source.getId());
+            RendererUtil.checkGLError();
         }
 
         // link shaders to program
         GLES20.glLinkProgram(id);
+        RendererUtil.checkGLError();
+        
         GLES20.glGetProgramiv(id, GLES20.GL_LINK_STATUS, intBuf1);
+        RendererUtil.checkGLError();
 
         boolean linkOK = intBuf1.get(0) == GLES20.GL_TRUE;
         String infoLog = null;
 
         if (VALIDATE_SHADER || !linkOK) {
             GLES20.glGetProgramiv(id, GLES20.GL_INFO_LOG_LENGTH, intBuf1);
+            RendererUtil.checkGLError();
 
             int length = intBuf1.get(0);
             if (length > 3) {
                 // get infos
                 infoLog = GLES20.glGetProgramInfoLog(id);
+                RendererUtil.checkGLError();
             }
         }
 
@@ -940,7 +982,10 @@ public class OGLESShaderRenderer implements Renderer {
         }
 
         source.clearUpdateNeeded();
+        
         GLES20.glDeleteShader(source.getId());
+        RendererUtil.checkGLError();
+        
         source.resetObject();
     }
 
@@ -953,11 +998,15 @@ public class OGLESShaderRenderer implements Renderer {
         for (ShaderSource source : shader.getSources()) {
             if (source.getId() != -1) {
                 GLES20.glDetachShader(shader.getId(), source.getId());
+                RendererUtil.checkGLError();
+                
                 deleteShaderSource(source);
             }
         }
 
         GLES20.glDeleteProgram(shader.getId());
+        RendererUtil.checkGLError();
+        
         statistics.onDeleteShader();
         shader.resetObject();
     }
@@ -1161,12 +1210,16 @@ public class OGLESShaderRenderer implements Renderer {
         int id = rb.getId();
         if (id == -1) {
             GLES20.glGenRenderbuffers(1, intBuf1);
+            RendererUtil.checkGLError();
+            
             id = intBuf1.get(0);
             rb.setId(id);
         }
 
         if (context.boundRB != id) {
             GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, id);
+            RendererUtil.checkGLError();
+            
             context.boundRB = id;
         }
 
@@ -1198,6 +1251,8 @@ public class OGLESShaderRenderer implements Renderer {
                     imageFormat.renderBufferStorageFormat,
                     fb.getWidth(),
                     fb.getHeight());
+            
+            RendererUtil.checkGLError();
         }
     }
 
@@ -1229,6 +1284,8 @@ public class OGLESShaderRenderer implements Renderer {
                 convertTextureType(tex.getType()),
                 image.getId(),
                 0);
+        
+        RendererUtil.checkGLError();
     }
 
     public void updateFrameBufferAttachment(FrameBuffer fb, RenderBuffer rb) {
@@ -1246,6 +1303,8 @@ public class OGLESShaderRenderer implements Renderer {
                     convertAttachmentSlot(rb.getSlot()),
                     GLES20.GL_RENDERBUFFER,
                     rb.getId());
+            
+            RendererUtil.checkGLError();
         }
     }
 
@@ -1255,6 +1314,8 @@ public class OGLESShaderRenderer implements Renderer {
             intBuf1.clear();
             // create FBO
             GLES20.glGenFramebuffers(1, intBuf1);
+            RendererUtil.checkGLError();
+            
             id = intBuf1.get(0);
             fb.setId(id);
             objManager.registerForCleanup(fb);
@@ -1264,6 +1325,8 @@ public class OGLESShaderRenderer implements Renderer {
 
         if (context.boundFBO != id) {
             GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, id);
+            RendererUtil.checkGLError();
+            
             // binding an FBO automatically sets draw buf to GL_COLOR_ATTACHMENT0
             context.boundDrawBuf = 0;
             context.boundFBO = id;
@@ -1309,6 +1372,7 @@ public class OGLESShaderRenderer implements Renderer {
 //                    int textureType = convertTextureType(tex.getType(), tex.getImage().getMultiSamples(), rb.getFace());
                     int textureType = convertTextureType(tex.getType());
                     GLES20.glGenerateMipmap(textureType);
+                    RendererUtil.checkGLError();
                 }
             }
         }
@@ -1317,6 +1381,8 @@ public class OGLESShaderRenderer implements Renderer {
             // unbind any fbos
             if (context.boundFBO != 0) {
                 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
+                RendererUtil.checkGLError();
+                
                 statistics.onFrameBufferUse(null, true);
 
                 context.boundFBO = 0;
@@ -1347,6 +1413,8 @@ public class OGLESShaderRenderer implements Renderer {
 
             if (context.boundFBO != fb.getId()) {
                 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb.getId());
+                RendererUtil.checkGLError();
+                
                 statistics.onFrameBufferUse(fb, true);
 
                 // update viewport to reflect framebuffer's resolution
@@ -1395,6 +1463,8 @@ public class OGLESShaderRenderer implements Renderer {
                     // select this draw buffer
                     if (context.boundDrawBuf != rb.getSlot()) {
                         GLES20.glActiveTexture(convertAttachmentSlot(rb.getSlot()));
+                        RendererUtil.checkGLError();
+                        
                         context.boundDrawBuf = rb.getSlot();
                     }
                 }
@@ -1427,6 +1497,8 @@ public class OGLESShaderRenderer implements Renderer {
             setFrameBuffer(fb);
             if (context.boundReadBuf != rb.getSlot()) {
                 GLES20.glActiveTexture(convertAttachmentSlot(rb.getSlot()));
+                RendererUtil.checkGLError();
+                
                 context.boundReadBuf = rb.getSlot();
             }
         } else {
@@ -1434,17 +1506,21 @@ public class OGLESShaderRenderer implements Renderer {
         }
 
         GLES20.glReadPixels(vpX, vpY, vpW, vpH, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, byteBuf);
+        RendererUtil.checkGLError();
     }
 
     private void deleteRenderBuffer(FrameBuffer fb, RenderBuffer rb) {
         intBuf1.put(0, rb.getId());
         GLES20.glDeleteRenderbuffers(1, intBuf1);
+        RendererUtil.checkGLError();
     }
 
     public void deleteFrameBuffer(FrameBuffer fb) {
         if (fb.getId() != -1) {
             if (context.boundFBO == fb.getId()) {
                 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
+                RendererUtil.checkGLError();
+                
                 context.boundFBO = 0;
             }
 
@@ -1457,6 +1533,8 @@ public class OGLESShaderRenderer implements Renderer {
 
             intBuf1.put(0, fb.getId());
             GLES20.glDeleteFramebuffers(1, intBuf1);
+            RendererUtil.checkGLError();
+            
             fb.resetObject();
 
             statistics.onDeleteFrameBuffer();
@@ -1539,6 +1617,7 @@ public class OGLESShaderRenderer implements Renderer {
 
         GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MIN_FILTER, minFilter);
         GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MAG_FILTER, magFilter);
+        RendererUtil.checkGLError();
 
         /*
         if (tex.getAnisotropicFilter() > 1){
@@ -1565,6 +1644,8 @@ public class OGLESShaderRenderer implements Renderer {
                 // fall down here is intentional..
 //          case OneDimensional:
                 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S)));
+                
+                RendererUtil.checkGLError();
                 break;
             default:
                 throw new UnsupportedOperationException("Unknown texture type: " + tex.getType());
@@ -1594,6 +1675,8 @@ public class OGLESShaderRenderer implements Renderer {
         if (texId == -1) {
             // create texture
             GLES20.glGenTextures(1, intBuf1);
+            RendererUtil.checkGLError();
+            
             texId = intBuf1.get(0);
             img.setId(texId);
             objManager.registerForCleanup(img);
@@ -1606,10 +1689,14 @@ public class OGLESShaderRenderer implements Renderer {
         if (context.boundTextures[0] != img) {
             if (context.boundTextureUnit != 0) {
                 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+                RendererUtil.checkGLError();
+                
                 context.boundTextureUnit = 0;
             }
 
             GLES20.glBindTexture(target, texId);
+            RendererUtil.checkGLError();
+            
             context.boundTextures[0] = img;
         }
 
@@ -1697,6 +1784,8 @@ public class OGLESShaderRenderer implements Renderer {
             }
 
             GLES20.glBindTexture(type, texId);
+            RendererUtil.checkGLError();
+            
             textures[unit] = image;
 
             statistics.onTextureUse(tex.getImage(), true);
@@ -1734,6 +1823,8 @@ public class OGLESShaderRenderer implements Renderer {
             intBuf1.position(0).limit(1);
 
             GLES20.glDeleteTextures(1, intBuf1);
+            RendererUtil.checkGLError();
+            
             image.resetObject();
 
             statistics.onDeleteTexture();
@@ -1791,6 +1882,8 @@ public class OGLESShaderRenderer implements Renderer {
         if (bufId == -1) {
             // create buffer
             GLES20.glGenBuffers(1, intBuf1);
+            RendererUtil.checkGLError();
+            
             bufId = intBuf1.get(0);
             vb.setId(bufId);
             objManager.registerForCleanup(vb);
@@ -1804,12 +1897,16 @@ public class OGLESShaderRenderer implements Renderer {
             target = GLES20.GL_ELEMENT_ARRAY_BUFFER;
             if (context.boundElementArrayVBO != bufId) {
                 GLES20.glBindBuffer(target, bufId);
+                RendererUtil.checkGLError();
+                
                 context.boundElementArrayVBO = bufId;
             }
         } else {
             target = GLES20.GL_ARRAY_BUFFER;
             if (context.boundArrayVBO != bufId) {
                 GLES20.glBindBuffer(target, bufId);
+                RendererUtil.checkGLError();
+                
                 context.boundArrayVBO = bufId;
             }
         }
@@ -1825,21 +1922,21 @@ public class OGLESShaderRenderer implements Renderer {
                 case Byte:
                 case UnsignedByte:
                     GLES20.glBufferData(target, size, (ByteBuffer) vb.getData(), usage);
+                    RendererUtil.checkGLError();
                     break;
-              //case Half:
                 case Short:
                 case UnsignedShort:
                     GLES20.glBufferData(target, size, (ShortBuffer) vb.getData(), usage);
+                    RendererUtil.checkGLError();
                     break;
                 case Int:
                 case UnsignedInt:
                     GLES20.glBufferData(target, size, (IntBuffer) vb.getData(), usage);
+                    RendererUtil.checkGLError();
                     break;
                 case Float:
                     GLES20.glBufferData(target, size, (FloatBuffer) vb.getData(), usage);
-                    break;
-                case Double:
-                    GLES20.glBufferData(target, size, (DoubleBuffer) vb.getData(), usage);
+                    RendererUtil.checkGLError();
                     break;
                 default:
                     throw new RuntimeException("Unknown buffer format.");
@@ -1851,20 +1948,21 @@ public class OGLESShaderRenderer implements Renderer {
                 case Byte:
                 case UnsignedByte:
                     GLES20.glBufferSubData(target, 0, size, (ByteBuffer) vb.getData());
+                    RendererUtil.checkGLError();
                     break;
                 case Short:
                 case UnsignedShort:
                     GLES20.glBufferSubData(target, 0, size, (ShortBuffer) vb.getData());
+                    RendererUtil.checkGLError();
                     break;
                 case Int:
                 case UnsignedInt:
                     GLES20.glBufferSubData(target, 0, size, (IntBuffer) vb.getData());
+                    RendererUtil.checkGLError();
                     break;
                 case Float:
                     GLES20.glBufferSubData(target, 0, size, (FloatBuffer) vb.getData());
-                    break;
-                case Double:
-                    GLES20.glBufferSubData(target, 0, size, (DoubleBuffer) vb.getData());
+                    RendererUtil.checkGLError();
                     break;
                 default:
                     throw new RuntimeException("Unknown buffer format.");
@@ -1881,6 +1979,8 @@ public class OGLESShaderRenderer implements Renderer {
             intBuf1.position(0).limit(1);
 
             GLES20.glDeleteBuffers(1, intBuf1);
+            RendererUtil.checkGLError();
+            
             vb.resetObject();
         }
     }
@@ -1891,6 +1991,8 @@ public class OGLESShaderRenderer implements Renderer {
             int idx = attribList.oldList[i];
 
             GLES20.glDisableVertexAttribArray(idx);
+            RendererUtil.checkGLError();
+            
             context.boundAttribs[idx] = null;
         }
         context.attribIndexList.copyNewToOld();
@@ -1920,6 +2022,7 @@ public class OGLESShaderRenderer implements Renderer {
 
                 String attributeName = "in" + vb.getBufferType().name();
                 loc = GLES20.glGetAttribLocation(programId, attributeName);
+                RendererUtil.checkGLError();
 
                 // not really the name of it in the shader (inPosition\0) but
                 // the internal name of the enum (Position).
@@ -1934,6 +2037,7 @@ public class OGLESShaderRenderer implements Renderer {
             VertexBuffer[] attribs = context.boundAttribs;
             if (!context.attribIndexList.moveToNew(loc)) {
                 GLES20.glEnableVertexAttribArray(loc);
+                RendererUtil.checkGLError();
                 //System.out.println("Enabled ATTRIB IDX: "+loc);
             }
             if (attribs[loc] != vb) {
@@ -1946,8 +2050,9 @@ public class OGLESShaderRenderer implements Renderer {
                 }
 
                 if (context.boundArrayVBO != bufId) {
-
                     GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufId);
+                    RendererUtil.checkGLError();
+                    
                     context.boundArrayVBO = bufId;
                 }
 
@@ -1959,6 +2064,8 @@ public class OGLESShaderRenderer implements Renderer {
                                     vb.isNormalized(),
                                     vb.getStride(),
                                     0);
+                
+                RendererUtil.checkGLError();
 
                 attribs[loc] = vb;
             }
@@ -1977,6 +2084,7 @@ public class OGLESShaderRenderer implements Renderer {
         vertCount, count);
         }else{*/
         GLES20.glDrawArrays(convertElementMode(mode), 0, vertCount);
+        RendererUtil.checkGLError();
         /*
         }*/
     }
@@ -1994,11 +2102,13 @@ public class OGLESShaderRenderer implements Renderer {
         assert bufId != -1;
 
         if (bufId == -1) {
-            logger.warning("invalid buffer id!");
+            throw new RendererException("Invalid buffer ID");
         }
 
         if (context.boundElementArrayVBO != bufId) {
             GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, bufId);
+            RendererUtil.checkGLError();
+            
             context.boundElementArrayVBO = bufId;
         }
 
@@ -2044,6 +2154,7 @@ public class OGLESShaderRenderer implements Renderer {
                 } else {
                     indexBuf.getData().position(curOffset);
                     GLES20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData());
+                    RendererUtil.checkGLError();
                     /*
                     glDrawRangeElements(elMode,
                     0,
@@ -2074,6 +2185,7 @@ public class OGLESShaderRenderer implements Renderer {
                         indexBuf.getData().limit(),
                         convertVertexBufferFormat(indexBuf.getFormat()),
                         0);
+                RendererUtil.checkGLError();
             }
         }
     }
@@ -2180,6 +2292,7 @@ public class OGLESShaderRenderer implements Renderer {
             drawTriangleList_Array(indices, mesh, count);
         } else {
             GLES20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount());
+            RendererUtil.checkGLError();
         }
         clearVertexAttribs();
         clearTextureUnits();
@@ -2219,18 +2332,23 @@ public class OGLESShaderRenderer implements Renderer {
         } else {
 //            throw new UnsupportedOperationException("Cannot render without index buffer");
             GLES20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount());
+            RendererUtil.checkGLError();
         }
         clearVertexAttribs();
         clearTextureUnits();
     }
 
     public void renderMesh(Mesh mesh, int lod, int count) {
+        /*
+         * NOTE: not supported in OpenGL ES 2.0.
         if (context.pointSize != mesh.getPointSize()) {
             GLES10.glPointSize(mesh.getPointSize());
             context.pointSize = mesh.getPointSize();
         }
+        */ 
         if (context.lineWidth != mesh.getLineWidth()) {
             GLES20.glLineWidth(mesh.getLineWidth());
+            RendererUtil.checkGLError();
             context.lineWidth = mesh.getLineWidth();
         }
 
@@ -2281,12 +2399,13 @@ public class OGLESShaderRenderer implements Renderer {
                 if (i == stripStart) {
                     elMode = convertElementMode(Mode.TriangleStrip);
                 } else if (i == fanStart) {
-                    elMode = convertElementMode(Mode.TriangleStrip);
+                    elMode = convertElementMode(Mode.TriangleFan);
                 }
                 int elementLength = elementLengths[i];
 
                 indexBuf.getData().position(curOffset);
                 GLES20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData());
+                RendererUtil.checkGLError();
 
                 curOffset += elementLength * elSize;
             }
@@ -2296,6 +2415,7 @@ public class OGLESShaderRenderer implements Renderer {
                     indexBuf.getData().limit(),
                     convertVertexBufferFormat(indexBuf.getFormat()),
                     indexBuf.getData());
+            RendererUtil.checkGLError();
         }
     }
 
@@ -2323,6 +2443,8 @@ public class OGLESShaderRenderer implements Renderer {
                 String attributeName = "in" + vb.getBufferType().name();
 
                 loc = GLES20.glGetAttribLocation(programId, attributeName);
+                RendererUtil.checkGLError();
+                
                 if (loc < 0) {
                     attrib.setLocation(-1);
                     return; // not available in shader.
@@ -2345,8 +2467,11 @@ public class OGLESShaderRenderer implements Renderer {
                         vb.isNormalized(),
                         vb.getStride(),
                         avb.getData());
+                
+                RendererUtil.checkGLError();
 
                 GLES20.glEnableVertexAttribArray(loc);
+                RendererUtil.checkGLError();
 
                 attribs[loc] = vb;
             } // if (attribs[loc] != vb)
@@ -2366,8 +2491,10 @@ public class OGLESShaderRenderer implements Renderer {
     public void setAlphaToCoverage(boolean value) {
         if (value) {
             GLES20.glEnable(GLES20.GL_SAMPLE_ALPHA_TO_COVERAGE);
+            RendererUtil.checkGLError();
         } else {
             GLES20.glDisable(GLES20.GL_SAMPLE_ALPHA_TO_COVERAGE);
+            RendererUtil.checkGLError();
         }
     }
 
@@ -2375,6 +2502,6 @@ public class OGLESShaderRenderer implements Renderer {
     public void invalidateState() {
         context.reset();
         boundShader = null;
-//        lastFb = null;
+        lastFb = null;
     }
 }

+ 53 - 0
engine/src/android/com/jme3/renderer/android/RendererUtil.java

@@ -0,0 +1,53 @@
+package com.jme3.renderer.android;
+
+import android.opengl.GLES20;
+import android.opengl.GLU;
+import com.jme3.renderer.RendererException;
+
+/**
+ * Utility class used by the {@link OGLESShaderRenderer renderer} and sister classes.
+ * 
+ * @author Kirill Vainer
+ */
+public class RendererUtil {
+    
+    /**
+     * When set to true, every OpenGL call will check for errors and throw
+     * an exception if there is one, if false, no error checking is performed.
+     */
+    public static boolean ENABLE_ERROR_CHECKING = true;
+    
+    /**
+     * Checks for an OpenGL error and throws a {@link RendererException}
+     * if there is one. Ignores the value of {@link RendererUtil#ENABLE_ERROR_CHECKING}.
+     */
+    public static void checkGLErrorForced() {
+        int error = GLES20.glGetError();
+        if (error != 0) {
+            String message = GLU.gluErrorString(error);
+            if (message == null) {
+                throw new RendererException("An unknown OpenGL error has occurred.");
+            } else {
+                throw new RendererException("An OpenGL error has occurred: " + message);
+            }
+        }
+    }
+    
+    /**
+     * Checks for an OpenGL error and throws a {@link RendererException}
+     * if there is one. Does nothing if {@link RendererUtil#ENABLE_ERROR_CHECKING}
+     * is set to <code>false</code>.
+     */
+    public static void checkGLError() {
+        if (!ENABLE_ERROR_CHECKING) return;
+        int error = GLES20.glGetError();
+        if (error != 0) {
+            String message = GLU.gluErrorString(error);
+            if (message == null) {
+                throw new RendererException("An unknown OpenGL error has occurred.");
+            } else {
+                throw new RendererException("An OpenGL error has occurred: " + message);
+            }
+        }
+    }
+}

+ 11 - 16
engine/src/android/com/jme3/renderer/android/TextureUtil.java

@@ -103,10 +103,10 @@ public class TextureUtil {
             logger.log(Level.FINEST, " - Uploading bitmap directly. Cannot compress as alpha present.");
             if (subTexture) {
                 GLUtils.texSubImage2D(target, level, x, y, bitmap);
-                checkGLError();
+                RendererUtil.checkGLError();
             } else {
                 GLUtils.texImage2D(target, level, bitmap, 0);
-                checkGLError();
+                RendererUtil.checkGLError();
             }
         } else {
             // Convert to RGB565
@@ -150,7 +150,8 @@ public class TextureUtil {
                             ETC1.ETC1_RGB8_OES,
                             etc1tex.getData().capacity(),
                             etc1tex.getData());
-                    checkGLError();
+                    
+                    RendererUtil.checkGLError();
                 } else {
                     GLES20.glCompressedTexImage2D(target,
                             level,
@@ -160,7 +161,8 @@ public class TextureUtil {
                             0,
                             etc1tex.getData().capacity(),
                             etc1tex.getData());
-                    checkGLError();
+                    
+                    RendererUtil.checkGLError();
                 }
 
 //                ETC1Util.loadTexture(target, level, 0, GLES20.GL_RGB,
@@ -208,17 +210,17 @@ public class TextureUtil {
                 if (subTexture) {
                     System.err.println("x : " + x + " y :" + y + " , " + bitmap.getWidth() + "/" + bitmap.getHeight());
                     GLUtils.texSubImage2D(target, 0, x, y, bitmap);
-                    checkGLError();
+                    RendererUtil.checkGLError();
                 } else {
                     GLUtils.texImage2D(target, 0, bitmap, 0);
-                    checkGLError();
+                    RendererUtil.checkGLError();
                 }
 
                 if (needMips) {
                     // No pregenerated mips available,
                     // generate from base level if required
                     GLES20.glGenerateMipmap(target);
-                    checkGLError();
+                    RendererUtil.checkGLError();
                 }
             }
         }
@@ -485,13 +487,6 @@ public class TextureUtil {
         }
     }
 
-    private static void checkGLError() {
-        int error;
-        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
-            throw new RendererException("OpenGL Error " + error);
-        }
-    }
-
     /**
      * Update the texture currently bound to target at with data from the given
      * Image at position x and y. The parameter index is used as the zoffset in
@@ -564,10 +559,10 @@ public class TextureUtil {
 
             if (imageFormat.compress && data != null) {
                 GLES20.glCompressedTexSubImage2D(target, i, x, y, mipWidth, mipHeight, imageFormat.format, data.remaining(), data);
-                checkGLError();
+                RendererUtil.checkGLError();
             } else {
                 GLES20.glTexSubImage2D(target, i, x, y, mipWidth, mipHeight, imageFormat.format, imageFormat.dataType, data);
-                checkGLError();
+                RendererUtil.checkGLError();
             }
 
             pos += mipSizes[i];

+ 1 - 1
engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java

@@ -2256,7 +2256,7 @@ public class LwjglRenderer implements Renderer {
                 if (i == stripStart) {
                     elMode = convertElementMode(Mode.TriangleStrip);
                 } else if (i == fanStart) {
-                    elMode = convertElementMode(Mode.TriangleStrip);
+                    elMode = convertElementMode(Mode.TriangleFan);
                 }
                 int elementLength = elementLengths[i];
 

+ 2 - 2
engine/src/test/jme3test/model/shape/TestCustomMesh.java

@@ -75,12 +75,12 @@ public class TestCustomMesh extends SimpleApplication {
         texCoord[3] = new Vector2f(1,1);
 
         // Indexes. We define the order in which mesh should be constructed
-        int [] indexes = {2,0,1,1,3,2};
+        short[] indexes = {2, 0, 1, 1, 3, 2};
 
         // Setting buffers
         m.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
         m.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoord));
-        m.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(indexes));
+        m.setBuffer(Type.Index, 1, BufferUtils.createShortBuffer(indexes));
         m.updateBound();
 
         // *************************************************************************