From c34189dfe5b0c41a2f3182c890987118b50623ab Mon Sep 17 00:00:00 2001 From: "Sha..rd" Date: Sun, 20 May 2012 22:11:59 +0000 Subject: [PATCH] * Removed all "verbose logging" parts of OGLESShaderRenderer, as it made the code hard to read. This sort of logging functionality should be done in a "GL Wrapper" sort of class instead. * The AndroidImageInfo.notifyBitmapUploaded() method is now called at the end of the upload as expected * Huge overhaul of TextureUtil. It automatically compresses textures to ETC1 if selected by user. In addition, it will use hardware mipmap generation if possible, and fallback to software if not (e.g. for compressed textures) * Add support for DXT1 format (usually supported on NVIDIA Tegra devices). The BrightSky.dds skybox now works on Android if the device supports it. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9410 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../renderer/android/OGLESShaderRenderer.java | 758 ++---------------- .../jme3/renderer/android/TextureUtil.java | 258 +++++- 2 files changed, 271 insertions(+), 745 deletions(-) diff --git a/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java b/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java index f754c9e69..56996878c 100644 --- a/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java +++ b/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java @@ -78,46 +78,33 @@ public class OGLESShaderRenderer implements Renderer { private final EnumSet caps = EnumSet.noneOf(Caps.class); // current state private Shader boundShader; - private int initialDrawBuf, initialReadBuf; +// private int initialDrawBuf, initialReadBuf; private int glslVer; private int vertexTextureUnits; private int fragTextureUnits; private int vertexUniforms; private int fragUniforms; private int vertexAttribs; - private int maxFBOSamples; - private int maxFBOAttachs; - private int maxMRTFBOAttachs; - private int maxRBSize; +// private int maxFBOSamples; +// private int maxFBOAttachs; +// private int maxMRTFBOAttachs; +// private int maxRBSize; private int maxTexSize; private int maxCubeTexSize; private int maxVertCount; private int maxTriCount; private boolean tdc; - private FrameBuffer lastFb = null; +// private FrameBuffer lastFb = null; private final Statistics statistics = new Statistics(); private int vpX, vpY, vpW, vpH; private int clipX, clipY, clipW, clipH; //private final GL10 gl; private boolean powerVr = false; - private boolean powerOf2 = false; - private boolean verboseLogging = false; private boolean useVBO = false; - private boolean checkErrors = true; public OGLESShaderRenderer() { } - public void setUseVA(boolean value) { - logger.log(Level.INFO, "use_VBO [{0}] -> [{1}]", new Object[]{useVBO, !value}); - useVBO = !value; - } - - public void setVerboseLogging(boolean value) { - logger.log(Level.INFO, "verboseLogging [{0}] -> [{1}]", new Object[]{verboseLogging, value}); - verboseLogging = value; - } - protected void updateNameBuffer() { int len = stringBuf.length(); @@ -131,18 +118,12 @@ public class OGLESShaderRenderer implements Renderer { } private void checkGLError() { - if (!checkErrors) return; int error; while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { throw new RendererException("OpenGL Error " + error); } } - private boolean log(String message) { - logger.info(message); - return true; - } - public Statistics getStatistics() { return statistics; } @@ -152,7 +133,6 @@ public class OGLESShaderRenderer implements Renderer { } public void initialize() { - logger.log(Level.INFO, "Vendor: {0}", GLES20.glGetString(GLES20.GL_VENDOR)); logger.log(Level.INFO, "Renderer: {0}", GLES20.glGetString(GLES20.GL_RENDERER)); logger.log(Level.INFO, "Version: {0}", GLES20.glGetString(GLES20.GL_VERSION)); @@ -194,7 +174,7 @@ public class OGLESShaderRenderer implements Renderer { } if (!caps.contains(Caps.GLSL100)) { - logger.info("Force-adding GLSL100 support, since OpenGL2 is supported."); + logger.warning("Force-adding GLSL100 support, since OpenGL2 is supported."); caps.add(Caps.GLSL100); } @@ -208,38 +188,36 @@ public class OGLESShaderRenderer implements Renderer { GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_IMAGE_UNITS, intBuf16); fragTextureUnits = intBuf16.get(0); logger.log(Level.INFO, "Texture Units: {0}", fragTextureUnits); - /* - GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_UNIFORM_COMPONENTS, intBuf16); - vertexUniforms = intBuf16.get(0); + + // Multiply vector count by 4 to get float count. + GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_UNIFORM_VECTORS, intBuf16); + vertexUniforms = intBuf16.get(0) * 4; logger.log(Level.FINER, "Vertex Uniforms: {0}", vertexUniforms); - GLES20.glGetIntegerv(GLES20.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16); - fragUniforms = intBuf16.get(0); + GLES20.glGetIntegerv(GLES20.GL_MAX_FRAGMENT_UNIFORM_VECTORS, intBuf16); + fragUniforms = intBuf16.get(0) * 4; logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms); - */ - + + GLES20.glGetIntegerv(GLES20.GL_MAX_VARYING_VECTORS, intBuf16); + int varyingFloats = intBuf16.get(0) * 4; + logger.log(Level.FINER, "Varying Floats: {0}", varyingFloats); + GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_ATTRIBS, intBuf16); vertexAttribs = intBuf16.get(0); logger.log(Level.INFO, "Vertex Attributes: {0}", vertexAttribs); - /* - GLES20.glGetIntegerv(GLES20.GL_MAX_VARYING_FLOATS, intBuf16); - int varyingFloats = intBuf16.get(0); - logger.log(Level.FINER, "Varying Floats: {0}", varyingFloats); - */ - GLES20.glGetIntegerv(GLES20.GL_SUBPIXEL_BITS, intBuf16); int subpixelBits = intBuf16.get(0); logger.log(Level.INFO, "Subpixel Bits: {0}", subpixelBits); - /* - GLES20.glGetIntegerv(GLES20.GL_MAX_ELEMENTS_VERTICES, intBuf16); - maxVertCount = intBuf16.get(0); - logger.log(Level.FINER, "Preferred Batch Vertex Count: {0}", maxVertCount); - GLES20.glGetIntegerv(GLES20.GL_MAX_ELEMENTS_INDICES, intBuf16); - maxTriCount = intBuf16.get(0); - logger.log(Level.FINER, "Preferred Batch Index Count: {0}", maxTriCount); - */ +// GLES10.glGetIntegerv(GLES10.GL_MAX_ELEMENTS_VERTICES, intBuf16); +// maxVertCount = intBuf16.get(0); +// logger.log(Level.FINER, "Preferred Batch Vertex Count: {0}", maxVertCount); +// +// GLES10.glGetIntegerv(GLES10.GL_MAX_ELEMENTS_INDICES, intBuf16); +// maxTriCount = intBuf16.get(0); +// logger.log(Level.FINER, "Preferred Batch Index Count: {0}", maxTriCount); + GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, intBuf16); maxTexSize = intBuf16.get(0); logger.log(Level.INFO, "Maximum Texture Resolution: {0}", maxTexSize); @@ -248,7 +226,6 @@ public class OGLESShaderRenderer implements Renderer { maxCubeTexSize = intBuf16.get(0); logger.log(Level.INFO, "Maximum CubeMap Resolution: {0}", maxCubeTexSize); - /* if (ctxCaps.GL_ARB_color_buffer_float){ // XXX: Require both 16 and 32 bit float support for FloatColorBuffer. @@ -264,9 +241,6 @@ public class OGLESShaderRenderer implements Renderer { if (ctxCaps.GL_ARB_draw_instanced) caps.add(Caps.MeshInstancing); - if (ctxCaps.GL_ARB_fragment_program) - caps.add(Caps.ARBprogram); - if (ctxCaps.GL_ARB_texture_buffer_object) caps.add(Caps.TextureBuffer); @@ -276,18 +250,6 @@ public class OGLESShaderRenderer implements Renderer { } } - if (ctxCaps.GL_ARB_vertex_array_object) - caps.add(Caps.VertexBufferArray); - - boolean latc = ctxCaps.GL_EXT_texture_compression_latc; - boolean atdc = ctxCaps.GL_ATI_texture_compression_3dc; - if (latc || atdc){ - caps.add(Caps.TextureCompressionLATC); - if (atdc && !latc){ - tdc = true; - } - } - if (ctxCaps.GL_EXT_packed_float){ caps.add(Caps.PackedFloatColorBuffer); if (ctxCaps.GL_ARB_half_float_pixel){ @@ -351,22 +313,21 @@ public class OGLESShaderRenderer implements Renderer { logger.log(Level.INFO, "Compressed Texture Formats: {0}", intBuf16.get(i)); } - if (extensions.contains("GL_OES_texture_npot")) { - powerOf2 = true; - } - + TextureUtil.loadTextureFeatures(extensions); + applyRenderState(RenderState.DEFAULT); GLES20.glDisable(GLES20.GL_DITHER); - checkGLError(); - useVBO = false; // NOTE: SDK_INT is only available since 1.6, // but for jME3 it doesn't matter since android versions 1.5 and below // are not supported. if (Build.VERSION.SDK_INT >= 9){ + logger.log(Level.INFO, "Force-enabling VBO (Android 2.3 or higher)"); useVBO = true; + } else { + useVBO = false; } logger.log(Level.INFO, "Caps: {0}", caps); @@ -379,7 +340,7 @@ public class OGLESShaderRenderer implements Renderer { objManager.resetObjects(); statistics.clearMemory(); boundShader = null; - lastFb = null; +// lastFb = null; context.reset(); } @@ -398,12 +359,7 @@ public class OGLESShaderRenderer implements Renderer { |* Render State *| \*********************************************************************/ public void setDepthRange(float start, float end) { - - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glDepthRangef({0}, {1})", new Object[]{start, end}); - } GLES20.glDepthRangef(start, end); - checkGLError(); } public void clearBuffers(boolean color, boolean depth, boolean stencil) { @@ -418,20 +374,12 @@ public class OGLESShaderRenderer implements Renderer { bits |= GLES20.GL_STENCIL_BUFFER_BIT; } if (bits != 0) { - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glClear(color={0}, depth={1}, stencil={2})", new Object[]{color, depth, stencil}); - } GLES20.glClear(bits); - checkGLError(); } } public void setBackgroundColor(ColorRGBA color) { - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glClearColor({0}, {1}, {2}, {3})", new Object[]{color.r, color.g, color.b, color.a}); - } GLES20.glClearColor(color.r, color.g, color.b, color.a); - checkGLError(); } public void applyRenderState(RenderState state) { @@ -445,23 +393,11 @@ public class OGLESShaderRenderer implements Renderer { } */ if (state.isDepthTest() && !context.depthTestEnabled) { - if (verboseLogging) { - logger.info("GLES20.glEnable(GLES20.GL_DEPTH_TEST)"); - } GLES20.glEnable(GLES20.GL_DEPTH_TEST); - checkGLError(); - if (verboseLogging) { - logger.info("GLES20.glDepthFunc(GLES20.GL_LEQUAL)"); - } GLES20.glDepthFunc(GLES20.GL_LEQUAL); - checkGLError(); context.depthTestEnabled = true; } else if (!state.isDepthTest() && context.depthTestEnabled) { - if (verboseLogging) { - logger.info("GLES20.glDisable(GLES20.GL_DEPTH_TEST)"); - } GLES20.glDisable(GLES20.GL_DEPTH_TEST); - checkGLError(); context.depthTestEnabled = false; } if (state.isAlphaTest() && !context.alphaTestEnabled) { @@ -473,33 +409,17 @@ public class OGLESShaderRenderer implements Renderer { context.alphaTestEnabled = false; } if (state.isDepthWrite() && !context.depthWriteEnabled) { - if (verboseLogging) { - logger.info("GLES20.glDepthMask(true)"); - } GLES20.glDepthMask(true); - checkGLError(); context.depthWriteEnabled = true; } else if (!state.isDepthWrite() && context.depthWriteEnabled) { - if (verboseLogging) { - logger.info("GLES20.glDepthMask(false)"); - } GLES20.glDepthMask(false); - checkGLError(); context.depthWriteEnabled = false; } if (state.isColorWrite() && !context.colorWriteEnabled) { - if (verboseLogging) { - logger.info("GLES20.glColorMask(true, true, true, true)"); - } GLES20.glColorMask(true, true, true, true); - checkGLError(); context.colorWriteEnabled = true; } else if (!state.isColorWrite() && context.colorWriteEnabled) { - if (verboseLogging) { - logger.info("GLES20.glColorMask(false, false, false, false)"); - } GLES20.glColorMask(false, false, false, false); - checkGLError(); context.colorWriteEnabled = false; } if (state.isPointSprite() && !context.pointSprite) { @@ -513,40 +433,24 @@ public class OGLESShaderRenderer implements Renderer { if (state.isPolyOffset()) { if (!context.polyOffsetEnabled) { - if (verboseLogging) { - logger.info("GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL)"); - } GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL); - checkGLError(); - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glPolygonOffset({0}, {1})", new Object[]{state.getPolyOffsetFactor(), state.getPolyOffsetUnits()}); - } GLES20.glPolygonOffset(state.getPolyOffsetFactor(), state.getPolyOffsetUnits()); - checkGLError(); context.polyOffsetEnabled = true; context.polyOffsetFactor = state.getPolyOffsetFactor(); context.polyOffsetUnits = state.getPolyOffsetUnits(); } else { if (state.getPolyOffsetFactor() != context.polyOffsetFactor || state.getPolyOffsetUnits() != context.polyOffsetUnits) { - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glPolygonOffset({0}, {1})", new Object[]{state.getPolyOffsetFactor(), state.getPolyOffsetUnits()}); - } GLES20.glPolygonOffset(state.getPolyOffsetFactor(), state.getPolyOffsetUnits()); - checkGLError(); context.polyOffsetFactor = state.getPolyOffsetFactor(); context.polyOffsetUnits = state.getPolyOffsetUnits(); } } } else { if (context.polyOffsetEnabled) { - if (verboseLogging) { - logger.info("GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL)"); - } GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL); - checkGLError(); context.polyOffsetEnabled = false; context.polyOffsetFactor = 0; context.polyOffsetUnits = 0; @@ -554,38 +458,21 @@ public class OGLESShaderRenderer implements Renderer { } if (state.getFaceCullMode() != context.cullMode) { if (state.getFaceCullMode() == RenderState.FaceCullMode.Off) { - if (verboseLogging) { - logger.info("GLES20.glDisable(GLES20.GL_CULL_FACE)"); - } GLES20.glDisable(GLES20.GL_CULL_FACE); } else { - if (verboseLogging) { - logger.info("GLES20.glEnable(GLES20.GL_CULL_FACE)"); - } GLES20.glEnable(GLES20.GL_CULL_FACE); } - checkGLError(); - switch (state.getFaceCullMode()) { case Off: break; case Back: - if (verboseLogging) { - logger.info("GLES20.glCullFace(GLES20.GL_BACK)"); - } GLES20.glCullFace(GLES20.GL_BACK); break; case Front: - if (verboseLogging) { - logger.info("GLES20.glCullFace(GLES20.GL_FRONT)"); - } GLES20.glCullFace(GLES20.GL_FRONT); break; case FrontAndBack: - if (verboseLogging) { - logger.info("GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK)"); - } GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK); break; default: @@ -593,65 +480,36 @@ public class OGLESShaderRenderer implements Renderer { + state.getFaceCullMode()); } - checkGLError(); - context.cullMode = state.getFaceCullMode(); } if (state.getBlendMode() != context.blendMode) { if (state.getBlendMode() == RenderState.BlendMode.Off) { - if (verboseLogging) { - logger.info("GLES20.glDisable(GLES20.GL_BLEND)"); - } GLES20.glDisable(GLES20.GL_BLEND); } else { - if (verboseLogging) { - logger.info("GLES20.glEnable(GLES20.GL_BLEND)"); - } GLES20.glEnable(GLES20.GL_BLEND); switch (state.getBlendMode()) { case Off: break; case Additive: - if (verboseLogging) { - logger.info("GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE)"); - } GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE); break; case AlphaAdditive: - if (verboseLogging) { - logger.info("GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE)"); - } GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE); break; case Color: - if (verboseLogging) { - logger.info("GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_COLOR)"); - } GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_COLOR); break; case Alpha: - if (verboseLogging) { - logger.info("GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA)"); - } GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); break; case PremultAlpha: - if (verboseLogging) { - logger.info("GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA)"); - } GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA); break; case Modulate: - if (verboseLogging) { - logger.info("GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_ZERO)"); - } GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_ZERO); break; case ModulateX2: - if (verboseLogging) { - logger.info("GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_SRC_COLOR)"); - } GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_SRC_COLOR); break; default: @@ -659,9 +517,6 @@ public class OGLESShaderRenderer implements Renderer { + state.getBlendMode()); } } - - checkGLError(); - context.blendMode = state.getBlendMode(); } } @@ -671,11 +526,7 @@ 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) { - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glViewport({0}, {1}, {2}, {3})", new Object[]{x, y, w, h}); - } GLES20.glViewport(x, y, w, h); - checkGLError(); vpX = x; vpY = y; vpW = w; @@ -685,33 +536,21 @@ public class OGLESShaderRenderer implements Renderer { public void setClipRect(int x, int y, int width, int height) { if (!context.clipRectEnabled) { - if (verboseLogging) { - logger.info("GLES20.glEnable(GLES20.GL_SCISSOR_TEST)"); - } GLES20.glEnable(GLES20.GL_SCISSOR_TEST); - checkGLError(); context.clipRectEnabled = true; } if (clipX != x || clipY != y || clipW != width || clipH != height) { - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glScissor({0}, {1}, {2}, {3})", new Object[]{x, y, width, height}); - } GLES20.glScissor(x, y, width, height); clipX = x; clipY = y; clipW = width; clipH = height; - checkGLError(); } } public void clearClipRect() { if (context.clipRectEnabled) { - if (verboseLogging) { - logger.info("GLES20.glDisable(GLES20.GL_SCISSOR_TEST)"); - } GLES20.glDisable(GLES20.GL_SCISSOR_TEST); - checkGLError(); context.clipRectEnabled = false; clipX = 0; @@ -722,14 +561,11 @@ public class OGLESShaderRenderer implements Renderer { } public void onFrame() { - if (!checkErrors){ - int error = GLES20.glGetError(); - if (error != GLES20.GL_NO_ERROR){ - throw new RendererException("OpenGL Error " + error + ". Enable error checking for more info."); - } + int error = GLES20.glGetError(); + if (error != GLES20.GL_NO_ERROR){ + throw new RendererException("OpenGL Error " + error + ". Enable error checking for more info."); } objManager.deleteUnused(this); -// statistics.clearFrame(); } public void setWorldMatrix(Matrix4f worldMatrix) { @@ -745,17 +581,10 @@ public class OGLESShaderRenderer implements Renderer { stringBuf.setLength(0); stringBuf.append(uniform.getName()).append('\0'); updateNameBuffer(); - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glGetUniformLocation({0}, {1})", new Object[]{shader.getId(), uniform.getName()}); - } int loc = GLES20.glGetUniformLocation(shader.getId(), uniform.getName()); - checkGLError(); if (loc < 0) { uniform.setLocation(-1); // uniform is not declared in shader - if (verboseLogging) { - logger.log(Level.WARNING, "Uniform [{0}] is not declared in shader.", uniform.getName()); - } } else { uniform.setLocation(loc); } @@ -768,11 +597,7 @@ public class OGLESShaderRenderer implements Renderer { assert shader.getId() > 0; if (context.boundShaderProgram != shaderId) { - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glUseProgram({0})", shaderId); - } GLES20.glUseProgram(shaderId); - checkGLError(); statistics.onShaderUse(shader, true); boundShader = shader; context.boundShaderProgram = shaderId; @@ -782,9 +607,6 @@ public class OGLESShaderRenderer implements Renderer { int loc = uniform.getLocation(); if (loc == -1) { - if (verboseLogging) { - logger.log(Level.WARNING, "no location for uniform [{0}]", uniform.getName()); - } return; } @@ -793,11 +615,6 @@ public class OGLESShaderRenderer implements Renderer { updateUniformLocation(shader, uniform); if (uniform.getLocation() == -1) { // not declared, ignore - - if (verboseLogging) { - logger.log(Level.WARNING, "not declared uniform: [{0}]", uniform.getName()); - } - uniform.clearUpdateNeeded(); return; } @@ -815,30 +632,18 @@ public class OGLESShaderRenderer implements Renderer { FloatBuffer fb; switch (uniform.getVarType()) { case Float: - if (verboseLogging) { - logger.info("GLES20.glUniform1f set Float. " + uniform.getName()); - } Float f = (Float) uniform.getValue(); GLES20.glUniform1f(loc, f.floatValue()); break; case Vector2: - if (verboseLogging) { - logger.info("GLES20.glUniform2f set Vector2. " + uniform.getName()); - } Vector2f v2 = (Vector2f) uniform.getValue(); GLES20.glUniform2f(loc, v2.getX(), v2.getY()); break; case Vector3: - if (verboseLogging) { - logger.info("GLES20.glUniform3f set Vector3. " + uniform.getName()); - } Vector3f v3 = (Vector3f) uniform.getValue(); GLES20.glUniform3f(loc, v3.getX(), v3.getY(), v3.getZ()); break; case Vector4: - if (verboseLogging) { - logger.info("GLES20.glUniform4f set Vector4." + uniform.getName()); - } Object val = uniform.getValue(); if (val instanceof ColorRGBA) { ColorRGBA c = (ColorRGBA) val; @@ -849,74 +654,46 @@ public class OGLESShaderRenderer implements Renderer { } break; case Boolean: - if (verboseLogging) { - logger.info("GLES20.glUniform1i set Boolean." + uniform.getName()); - } Boolean b = (Boolean) uniform.getValue(); GLES20.glUniform1i(loc, b.booleanValue() ? GLES20.GL_TRUE : GLES20.GL_FALSE); break; case Matrix3: - if (verboseLogging) { - logger.info("GLES20.glUniformMatrix3fv set Matrix3." + uniform.getName()); - } fb = (FloatBuffer) uniform.getValue(); assert fb.remaining() == 9; GLES20.glUniformMatrix3fv(loc, 1, false, fb); break; case Matrix4: - if (verboseLogging) { - logger.info("GLES20.glUniformMatrix4fv set Matrix4." + uniform.getName()); - } fb = (FloatBuffer) uniform.getValue(); assert fb.remaining() == 16; GLES20.glUniformMatrix4fv(loc, 1, false, fb); break; case FloatArray: - if (verboseLogging) { - logger.info("GLES20.glUniform1fv set FloatArray." + uniform.getName()); - } fb = (FloatBuffer) uniform.getValue(); GLES20.glUniform1fv(loc, fb.capacity(), fb); break; case Vector2Array: - if (verboseLogging) { - logger.info("GLES20.glUniform2fv set Vector2Array." + uniform.getName()); - } fb = (FloatBuffer) uniform.getValue(); GLES20.glUniform2fv(loc, fb.capacity() / 2, fb); break; case Vector3Array: - if (verboseLogging) { - logger.info("GLES20.glUniform3fv set Vector3Array." + uniform.getName()); - } fb = (FloatBuffer) uniform.getValue(); GLES20.glUniform3fv(loc, fb.capacity() / 3, fb); break; case Vector4Array: - if (verboseLogging) { - logger.info("GLES20.glUniform4fv set Vector4Array." + uniform.getName()); - } fb = (FloatBuffer) uniform.getValue(); GLES20.glUniform4fv(loc, fb.capacity() / 4, fb); break; case Matrix4Array: - if (verboseLogging) { - logger.info("GLES20.glUniform4fv set Matrix4Array." + uniform.getName()); - } fb = (FloatBuffer) uniform.getValue(); GLES20.glUniformMatrix4fv(loc, fb.capacity() / 16, false, fb); break; case Int: - if (verboseLogging) { - logger.info("GLES20.glUniform1i set Int." + uniform.getName()); - } Integer i = (Integer) uniform.getValue(); GLES20.glUniform1i(loc, i.intValue()); break; default: throw new UnsupportedOperationException("Unsupported uniform type: " + uniform.getVarType()); } - checkGLError(); } protected void updateShaderUniforms(Shader shader) { @@ -963,15 +740,10 @@ public class OGLESShaderRenderer implements Renderer { int id = source.getId(); if (id == -1) { // create id - if (verboseLogging) { - logger.info("GLES20.glCreateShader(" + source.getType() + ")"); - } id = GLES20.glCreateShader(convertShaderType(source.getType())); - checkGLError(); if (id <= 0) { throw new RendererException("Invalid ID received when trying to create shader."); } - source.setId(id); } @@ -989,10 +761,6 @@ public class OGLESShaderRenderer implements Renderer { codeBuf.put(sourceCodeData); codeBuf.flip(); - if (verboseLogging) { - logger.info("GLES20.glShaderSource(" + id + ")"); - } - if (powerVr && source.getType() == ShaderType.Vertex) { // XXX: This is to fix a bug in old PowerVR, remove // when no longer applicable. @@ -1007,40 +775,18 @@ public class OGLESShaderRenderer implements Renderer { + source.getSource()); } - checkGLError(); - - if (verboseLogging) { - logger.info("GLES20.glCompileShader(" + id + ")"); - } - GLES20.glCompileShader(id); - - checkGLError(); - - if (verboseLogging) { - logger.info("GLES20.glGetShaderiv(" + id + ", GLES20.GL_COMPILE_STATUS)"); - } - GLES20.glGetShaderiv(id, GLES20.GL_COMPILE_STATUS, intBuf1); - checkGLError(); - boolean compiledOK = intBuf1.get(0) == GLES20.GL_TRUE; String infoLog = null; if (VALIDATE_SHADER || !compiledOK) { // even if compile succeeded, check // log for warnings - if (verboseLogging) { - logger.info("GLES20.glGetShaderiv()"); - } GLES20.glGetShaderiv(id, GLES20.GL_INFO_LOG_LENGTH, intBuf1); checkGLError(); - if (verboseLogging) { - logger.info("GLES20.glGetShaderInfoLog(" + id + ")"); - } infoLog = GLES20.glGetShaderInfoLog(id); - logger.severe("Errooooooooooot(" + id + ")"); } if (compiledOK) { @@ -1065,11 +811,7 @@ public class OGLESShaderRenderer implements Renderer { if (!compiledOK) { // make sure to dispose id cause all program's // shaders will be cleared later. - if (verboseLogging) { - logger.info("GLES20.glDeleteShader(" + id + ")"); - } GLES20.glDeleteShader(id); - checkGLError(); } else { // register for cleanup since the ID is usable objManager.registerForCleanup(source); @@ -1081,11 +823,6 @@ public class OGLESShaderRenderer implements Renderer { boolean needRegister = false; if (id == -1) { // create program - - if (verboseLogging) { - logger.info("GLES20.glCreateProgram()"); - } - id = GLES20.glCreateProgram(); if (id <= 0) { @@ -1108,45 +845,22 @@ public class OGLESShaderRenderer implements Renderer { shader.clearUpdateNeeded(); return; } - if (verboseLogging) { - logger.info("GLES20.glAttachShader(" + id + ", " + source.getId() + ")"); - } - GLES20.glAttachShader(id, source.getId()); } // link shaders to program - if (verboseLogging) { - logger.info("GLES20.glLinkProgram(" + id + ")"); - } - GLES20.glLinkProgram(id); - - - if (verboseLogging) { - logger.info("GLES20.glGetProgramiv(" + id + ")"); - } - GLES20.glGetProgramiv(id, GLES20.GL_LINK_STATUS, intBuf1); boolean linkOK = intBuf1.get(0) == GLES20.GL_TRUE; String infoLog = null; if (VALIDATE_SHADER || !linkOK) { - if (verboseLogging) { - logger.info("GLES20.glGetProgramiv(" + id + ", GLES20.GL_INFO_LOG_LENGTH, buffer)"); - } - GLES20.glGetProgramiv(id, GLES20.GL_INFO_LOG_LENGTH, intBuf1); int length = intBuf1.get(0); if (length > 3) { // get infos - - if (verboseLogging) { - logger.info("GLES20.glGetProgramInfoLog(" + id + ")"); - } - infoLog = GLES20.glGetProgramInfoLog(id); } } @@ -1184,17 +898,8 @@ public class OGLESShaderRenderer implements Renderer { } public void setShader(Shader shader) { - if (verboseLogging) { - logger.info("setShader(" + shader + ")"); - } - if (shader == null) { if (context.boundShaderProgram > 0) { - - if (verboseLogging) { - logger.info("GLES20.glUseProgram(0)"); - } - GLES20.glUseProgram(0); statistics.onShaderUse(null, true); @@ -1208,7 +913,6 @@ public class OGLESShaderRenderer implements Renderer { // NOTE: might want to check if any of the // sources need an update? - if (!shader.isUsable()) { logger.warning("shader is not usable."); return; @@ -1221,20 +925,10 @@ public class OGLESShaderRenderer implements Renderer { if (VALIDATE_SHADER) { // check if shader can be used // with current state - if (verboseLogging) { - logger.info("GLES20.glValidateProgram(" + shader.getId() + ")"); - } - GLES20.glValidateProgram(shader.getId()); - - if (verboseLogging) { - logger.info("GLES20.glGetProgramiv(" + shader.getId() + ", GLES20.GL_VALIDATE_STATUS, buffer)"); - } - GLES20.glGetProgramiv(shader.getId(), GLES20.GL_VALIDATE_STATUS, intBuf1); boolean validateOK = intBuf1.get(0) == GLES20.GL_TRUE; - if (validateOK) { logger.fine("shader validate success"); } else { @@ -1242,10 +936,6 @@ public class OGLESShaderRenderer implements Renderer { } } - if (verboseLogging) { - logger.info("GLES20.glUseProgram(" + shader.getId() + ")"); - } - GLES20.glUseProgram(shader.getId()); statistics.onShaderUse(shader, true); @@ -1265,10 +955,6 @@ public class OGLESShaderRenderer implements Renderer { source.setUsable(false); source.clearUpdateNeeded(); - if (verboseLogging) { - logger.info("GLES20.glDeleteShader(" + source.getId() + ")"); - } - GLES20.glDeleteShader(source.getId()); source.resetObject(); } @@ -1280,11 +966,6 @@ public class OGLESShaderRenderer implements Renderer { } for (ShaderSource source : shader.getSources()) { if (source.getId() != -1) { - - if (verboseLogging) { - logger.info("GLES20.glDetachShader(" + shader.getId() + ", " + source.getId() + ")"); - } - GLES20.glDetachShader(shader.getId(), source.getId()); // the next part is done by the GLObjectManager automatically // glDeleteShader(source.getId()); @@ -1294,10 +975,6 @@ public class OGLESShaderRenderer implements Renderer { // if needed. shader.resetSources(); - if (verboseLogging) { - logger.info("GLES20.glDeleteProgram(" + shader.getId() + ")"); - } - GLES20.glDeleteProgram(shader.getId()); statistics.onDeleteShader(); @@ -1541,9 +1218,6 @@ public class OGLESShaderRenderer implements Renderer { } public void setFrameBuffer(FrameBuffer fb) { - if (verboseLogging) { - logger.warning("setFrameBuffer is not supported."); - } } /* public void setFrameBuffer(FrameBuffer fb) { @@ -1784,18 +1458,9 @@ public class OGLESShaderRenderer implements Renderer { int minFilter = convertMinFilter(tex.getMinFilter()); int magFilter = convertMagFilter(tex.getMagFilter()); - if (verboseLogging) { - logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MIN_FILTER, " + minFilter + ")"); - } - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MIN_FILTER, minFilter); - - if (verboseLogging) { - logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MAG_FILTER, " + magFilter + ")"); - } - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MAG_FILTER, magFilter); - + /* if (tex.getAnisotropicFilter() > 1){ @@ -1816,20 +1481,10 @@ public class OGLESShaderRenderer implements Renderer { //GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R))); case TwoDimensional: case TwoDimensionalArray: - - if (verboseLogging) { - logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_T, " + convertWrapMode(tex.getWrap(WrapAxis.T))); - } - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, convertWrapMode(tex.getWrap(WrapAxis.T))); // fall down here is intentional.. // case OneDimensional: - - if (verboseLogging) { - logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_S, " + convertWrapMode(tex.getWrap(WrapAxis.S))); - } - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S))); break; default: @@ -1854,16 +1509,12 @@ public class OGLESShaderRenderer implements Renderer { * updateTexImageData activates and binds the texture * @param img * @param type - * @param mips + * @param needMips */ - public void updateTexImageData(Image img, Texture.Type type, boolean mips) { + public void updateTexImageData(Image img, Texture.Type type, boolean needMips) { int texId = img.getId(); if (texId == -1) { // create texture - if (verboseLogging) { - logger.info("GLES20.glGenTexture(1, buffer)"); - } - GLES20.glGenTextures(1, intBuf1); texId = intBuf1.get(0); img.setId(texId); @@ -1876,23 +1527,14 @@ public class OGLESShaderRenderer implements Renderer { int target = convertTextureType(type); if (context.boundTextures[0] != img) { if (context.boundTextureUnit != 0) { - if (verboseLogging) { - logger.info("GLES20.glActiveTexture(GLES20.GL_TEXTURE0)"); - } - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); context.boundTextureUnit = 0; } - if (verboseLogging) { - logger.info("GLES20.glBindTexture(" + target + ", " + texId + ")"); - } - GLES20.glBindTexture(target, texId); context.boundTextures[0] = img; } - if (target == GLES20.GL_TEXTURE_CUBE_MAP) { // Upload a cube map / sky box @SuppressWarnings("unchecked") @@ -1904,34 +1546,25 @@ public class OGLESShaderRenderer implements Renderer { + "Cubemap textures must contain 6 data units."); } for (int i = 0; i < 6; i++) { - TextureUtil.uploadTextureBitmap(GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, bmps.get(i).getBitmap(), false, powerOf2); + TextureUtil.uploadTextureBitmap(GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, bmps.get(i).getBitmap(), needMips); + bmps.get(i).notifyBitmapUploaded(); } } else { // Standard jme3 image data List data = img.getData(); if (data.size() != 6) { - logger.log(Level.WARNING, "Invalid texture: {0}\n" - + "Cubemap textures must contain 6 data units.", img); - return; + throw new UnsupportedOperationException("Invalid texture: " + img + + "Cubemap textures must contain 6 data units."); } for (int i = 0; i < 6; i++) { - TextureUtil.uploadTexture(img, GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, tdc, false, powerOf2); + TextureUtil.uploadTextureAny(img, GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, needMips); } } } else { - TextureUtil.uploadTexture(img, target, 0, 0, tdc, false, powerOf2); - - if (verboseLogging) { - logger.info("GLES20.glTexParameteri(" + target + "GLES11.GL_GENERATE_MIMAP, GLES20.GL_TRUE)"); - } - - if (!img.hasMipmaps() && mips) { - // No pregenerated mips available, - // generate from base level if required - if (verboseLogging) { - logger.info("GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D)"); - } - GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D); + TextureUtil.uploadTextureAny(img, target, 0, needMips); + if (img.getEfficentData() instanceof AndroidImageInfo) { + AndroidImageInfo info = (AndroidImageInfo) img.getEfficentData(); + info.notifyBitmapUploaded(); } } @@ -1941,19 +1574,6 @@ public class OGLESShaderRenderer implements Renderer { public void setTexture(int unit, Texture tex) { Image image = tex.getImage(); if (image.isUpdateNeeded()) { - /* - Bitmap bmp = (Bitmap)image.getEfficentData(); - if (bmp != null) - { - // Check if the bitmap got recycled, can happen after wakeup/restart - if ( bmp.isRecycled() ) - { - // We need to reload the bitmap - Texture textureReloaded = JmeSystem.newAssetManager().loadTexture((TextureKey)tex.getKey()); - image.setEfficentData( textureReloaded.getImage().getEfficentData()); - } - } - */ updateTexImageData(image, tex.getType(), tex.getMinFilter().usesMipMapLevels()); } @@ -1977,17 +1597,10 @@ public class OGLESShaderRenderer implements Renderer { if (textures[unit] != image) { if (context.boundTextureUnit != unit) { - if (verboseLogging) { - logger.info("GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + " + unit + ")"); - } GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + unit); context.boundTextureUnit = unit; } - if (verboseLogging) { - logger.info("GLES20.glBindTexture(" + type + ", " + texId + ")"); - } - GLES20.glBindTexture(type, texId); textures[unit] = image; @@ -2020,10 +1633,6 @@ public class OGLESShaderRenderer implements Renderer { intBuf1.put(0, texId); intBuf1.position(0).limit(1); - if (verboseLogging) { - logger.info("GLES20.glDeleteTexture(1, buffer)"); - } - GLES20.glDeleteTextures(1, intBuf1); image.resetObject(); @@ -2077,20 +1686,10 @@ public class OGLESShaderRenderer implements Renderer { } public void updateBufferData(VertexBuffer vb) { - - if (verboseLogging) { - logger.info("updateBufferData(" + vb + ")"); - } - int bufId = vb.getId(); boolean created = false; if (bufId == -1) { // create buffer - - if (verboseLogging) { - logger.info("GLES20.glGenBuffers(" + 1 + ", buffer)"); - } - GLES20.glGenBuffers(1, intBuf1); bufId = intBuf1.get(0); vb.setId(bufId); @@ -2103,33 +1702,13 @@ public class OGLESShaderRenderer implements Renderer { int target; if (vb.getBufferType() == VertexBuffer.Type.Index) { target = GLES20.GL_ELEMENT_ARRAY_BUFFER; - - if (verboseLogging) { - logger.info("vb.getBufferType() == VertexBuffer.Type.Index"); - } - if (context.boundElementArrayVBO != bufId) { - - if (verboseLogging) { - logger.info("GLES20.glBindBuffer(" + target + ", " + bufId + ")"); - } - GLES20.glBindBuffer(target, bufId); context.boundElementArrayVBO = bufId; } } else { - if (verboseLogging) { - logger.info("vb.getBufferType() != VertexBuffer.Type.Index"); - } - target = GLES20.GL_ARRAY_BUFFER; - if (context.boundArrayVBO != bufId) { - - if (verboseLogging) { - logger.info("GLES20.glBindBuffer(" + target + ", " + bufId + ")"); - } - GLES20.glBindBuffer(target, bufId); context.boundArrayVBO = bufId; } @@ -2145,44 +1724,21 @@ public class OGLESShaderRenderer implements Renderer { switch (vb.getFormat()) { case Byte: case UnsignedByte: - - if (verboseLogging) { - logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); - } - GLES20.glBufferData(target, size, (ByteBuffer) vb.getData(), usage); break; - // case Half: + //case Half: case Short: case UnsignedShort: - - if (verboseLogging) { - logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); - } - GLES20.glBufferData(target, size, (ShortBuffer) vb.getData(), usage); break; case Int: case UnsignedInt: - - if (verboseLogging) { - logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); - } - GLES20.glBufferData(target, size, (IntBuffer) vb.getData(), usage); break; case Float: - if (verboseLogging) { - logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); - } - GLES20.glBufferData(target, size, (FloatBuffer) vb.getData(), usage); break; case Double: - if (verboseLogging) { - logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); - } - GLES20.glBufferData(target, size, (DoubleBuffer) vb.getData(), usage); break; default: @@ -2194,87 +1750,26 @@ public class OGLESShaderRenderer implements Renderer { switch (vb.getFormat()) { case Byte: case UnsignedByte: - if (verboseLogging) { - logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); - } - GLES20.glBufferSubData(target, 0, size, (ByteBuffer) vb.getData()); break; case Short: case UnsignedShort: - if (verboseLogging) { - logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); - } - GLES20.glBufferSubData(target, 0, size, (ShortBuffer) vb.getData()); break; case Int: case UnsignedInt: - if (verboseLogging) { - logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); - } - GLES20.glBufferSubData(target, 0, size, (IntBuffer) vb.getData()); break; case Float: - if (verboseLogging) { - logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); - } - GLES20.glBufferSubData(target, 0, size, (FloatBuffer) vb.getData()); break; case Double: - if (verboseLogging) { - logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); - } - GLES20.glBufferSubData(target, 0, size, (DoubleBuffer) vb.getData()); break; default: throw new RuntimeException("Unknown buffer format."); } } -// }else{ -// if (created || vb.hasDataSizeChanged()){ -// glBufferData(target, vb.getData().capacity() * vb.getFormat().getComponentSize(), usage); -// } -// -// ByteBuffer buf = glMapBuffer(target, -// GL_WRITE_ONLY, -// vb.getMappedData()); -// -// if (buf != vb.getMappedData()){ -// buf = buf.order(ByteOrder.nativeOrder()); -// vb.setMappedData(buf); -// } -// -// buf.clear(); -// -// switch (vb.getFormat()){ -// case Byte: -// case UnsignedByte: -// buf.put( (ByteBuffer) vb.getData() ); -// break; -// case Short: -// case UnsignedShort: -// buf.asShortBuffer().put( (ShortBuffer) vb.getData() ); -// break; -// case Int: -// case UnsignedInt: -// buf.asIntBuffer().put( (IntBuffer) vb.getData() ); -// break; -// case Float: -// buf.asFloatBuffer().put( (FloatBuffer) vb.getData() ); -// break; -// case Double: -// break; -// default: -// throw new RuntimeException("Unknown buffer format."); -// } -// -// glUnmapBuffer(target); -// } - vb.clearUpdateNeeded(); } @@ -2284,10 +1779,7 @@ public class OGLESShaderRenderer implements Renderer { // delete buffer intBuf1.put(0, bufId); intBuf1.position(0).limit(1); - if (verboseLogging) { - logger.info("GLES20.glDeleteBuffers(1, buffer)"); - } - + GLES20.glDeleteBuffers(1, intBuf1); vb.resetObject(); } @@ -2298,10 +1790,6 @@ public class OGLESShaderRenderer implements Renderer { for (int i = 0; i < attribList.oldLen; i++) { int idx = attribList.oldList[i]; - if (verboseLogging) { - logger.info("GLES20.glDisableVertexAttribArray(" + idx + ")"); - } - GLES20.glDisableVertexAttribArray(idx); context.boundAttribs[idx] = null; } @@ -2309,10 +1797,6 @@ public class OGLESShaderRenderer implements Renderer { } public void setVertexAttrib(VertexBuffer vb, VertexBuffer idb) { - if (verboseLogging) { - logger.info("setVertexAttrib(" + vb + ", " + idb + ")"); - } - if (vb.getBufferType() == VertexBuffer.Type.Index) { throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); } @@ -2326,11 +1810,6 @@ public class OGLESShaderRenderer implements Renderer { Attribute attrib = boundShader.getAttribute(vb.getBufferType()); int loc = attrib.getLocation(); if (loc == -1) { - - if (verboseLogging) { - logger.warning("location is invalid for attrib: [" + vb.getBufferType().name() + "]"); - } - return; // not defined } @@ -2340,22 +1819,12 @@ public class OGLESShaderRenderer implements Renderer { // updateNameBuffer(); String attributeName = "in" + vb.getBufferType().name(); - - if (verboseLogging) { - logger.info("GLES20.glGetAttribLocation(" + programId + ", " + attributeName + ")"); - } - loc = GLES20.glGetAttribLocation(programId, attributeName); // not really the name of it in the shader (inPosition\0) but // the internal name of the enum (Position). if (loc < 0) { attrib.setLocation(-1); - - if (verboseLogging) { - logger.warning("attribute is invalid in shader: [" + vb.getBufferType().name() + "]"); - } - return; // not available in shader. } else { attrib.setLocation(loc); @@ -2364,10 +1833,6 @@ public class OGLESShaderRenderer implements Renderer { VertexBuffer[] attribs = context.boundAttribs; if (!context.attribIndexList.moveToNew(loc)) { - if (verboseLogging) { - logger.info("GLES20.glEnableVertexAttribArray(" + loc + ")"); - } - GLES20.glEnableVertexAttribArray(loc); //System.out.println("Enabled ATTRIB IDX: "+loc); } @@ -2381,25 +1846,13 @@ public class OGLESShaderRenderer implements Renderer { } if (context.boundArrayVBO != bufId) { - if (verboseLogging) { - logger.info("GLES20.glBindBuffer(" + GLES20.GL_ARRAY_BUFFER + ", " + bufId + ")"); - } + GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufId); context.boundArrayVBO = bufId; } vb.getData().clear(); - if (verboseLogging) { - logger.info("GLES20.glVertexAttribPointer(" - + "location=" + loc + ", " - + "numComponents=" + vb.getNumComponents() + ", " - + "format=" + vb.getFormat() + ", " - + "isNormalized=" + vb.isNormalized() + ", " - + "stride=" + vb.getStride() + ", " - + "data.capacity=" + vb.getData().capacity() + ")"); - } - Android22Workaround.glVertexAttribPointer(loc, vb.getNumComponents(), convertFormat(vb.getFormat()), @@ -2423,29 +1876,17 @@ public class OGLESShaderRenderer implements Renderer { ARBDrawInstanced.glDrawArraysInstancedARB(convertElementMode(mode), 0, vertCount, count); }else{*/ - if (verboseLogging) { - logger.info("GLES20.glDrawArrays(" + vertCount + ")"); - } - GLES20.glDrawArrays(convertElementMode(mode), 0, vertCount); /* }*/ } public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) { - - if (verboseLogging) { - logger.info("drawTriangleList(" + count + ")"); - } - if (indexBuf.getBufferType() != VertexBuffer.Type.Index) { throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); } if (indexBuf.isUpdateNeeded()) { - if (verboseLogging) { - logger.info("updateBufferData for indexBuf."); - } updateBufferData(indexBuf); } @@ -2457,10 +1898,6 @@ public class OGLESShaderRenderer implements Renderer { } if (context.boundElementArrayVBO != bufId) { - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, {0})", bufId); - } - GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, bufId); context.boundElementArrayVBO = bufId; } @@ -2469,7 +1906,6 @@ public class OGLESShaderRenderer implements Renderer { boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); Buffer indexData = indexBuf.getData(); - if (mesh.getMode() == Mode.Hybrid) { int[] modeStart = mesh.getModeStart(); int[] elementLengths = mesh.getElementLengths(); @@ -2501,10 +1937,6 @@ public class OGLESShaderRenderer implements Renderer { */ } else { indexBuf.getData().position(curOffset); - if (verboseLogging) { - logger.log(Level.INFO, "glDrawElements(): {0}, {1}", new Object[]{elementLength, curOffset}); - } - GLES20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData()); /* glDrawRangeElements(elMode, @@ -2531,11 +1963,6 @@ public class OGLESShaderRenderer implements Renderer { */ } else { indexData.clear(); - - if (verboseLogging) { - logger.log(Level.INFO, "glDrawElements(), indexBuf.capacity ({0}), vertCount ({1})", new Object[]{indexBuf.getData().capacity(), vertCount}); - } - GLES20.glDrawElements( convertElementMode(mesh.getMode()), indexBuf.getData().capacity(), @@ -2618,10 +2045,6 @@ public class OGLESShaderRenderer implements Renderer { * @param count */ private void renderMeshVertexArray(Mesh mesh, int lod, int count) { - if (verboseLogging) { - logger.info("renderMeshVertexArray"); - } - // IntMap buffers = mesh.getBuffers(); for (VertexBuffer vb : mesh.getBufferList().getArray()){ @@ -2650,11 +2073,6 @@ public class OGLESShaderRenderer implements Renderer { if (indices != null) { drawTriangleList_Array(indices, mesh, count); } else { - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glDrawArrays({0}, {1}, {2})", - new Object[]{mesh.getMode(), 0, mesh.getVertexCount()}); - } - GLES20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount()); } clearVertexAttribs(); @@ -2662,12 +2080,7 @@ public class OGLESShaderRenderer implements Renderer { } private void renderMeshDefault(Mesh mesh, int lod, int count) { - if (verboseLogging) { - logger.log(Level.INFO, "renderMeshDefault({0}, {1}, {2})", - new Object[]{mesh, lod, count}); - } VertexBuffer indices = null; - VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); if (interleavedData != null && interleavedData.isUpdateNeeded()) { updateBufferData(interleavedData); @@ -2699,11 +2112,6 @@ public class OGLESShaderRenderer implements Renderer { drawTriangleList(indices, mesh, count); } else { // throw new UnsupportedOperationException("Cannot render without index buffer"); - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glDrawArrays({0}, 0, {1})", - new Object[]{convertElementMode(mesh.getMode()), mesh.getVertexCount()}); - } - GLES20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount()); } clearVertexAttribs(); @@ -2712,20 +2120,10 @@ public class OGLESShaderRenderer implements Renderer { public void renderMesh(Mesh mesh, int lod, int count) { if (context.pointSize != mesh.getPointSize()) { - - if (verboseLogging) { - logger.log(Level.INFO, "GLES10.glPointSize({0})", mesh.getPointSize()); - } - GLES10.glPointSize(mesh.getPointSize()); context.pointSize = mesh.getPointSize(); } if (context.lineWidth != mesh.getLineWidth()) { - - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glLineWidth({0})", mesh.getLineWidth()); - } - GLES20.glLineWidth(mesh.getLineWidth()); context.lineWidth = mesh.getLineWidth(); } @@ -2736,20 +2134,10 @@ public class OGLESShaderRenderer implements Renderer { // }else{ if (useVBO) { - if (verboseLogging) { - logger.info("RENDERING A MESH USING VertexBufferObject"); - } - renderMeshDefault(mesh, lod, count); } else { - if (verboseLogging) { - logger.info("RENDERING A MESH USING VertexArray"); - } - renderMeshVertexArray(mesh, lod, count); } - -// } } /** @@ -2759,10 +2147,6 @@ public class OGLESShaderRenderer implements Renderer { * @param count */ public void drawTriangleList_Array(VertexBuffer indexBuf, Mesh mesh, int count) { - if (verboseLogging) { - logger.log(Level.INFO, "drawTriangleList_Array(Count = {0})", count); - } - if (indexBuf.getBufferType() != VertexBuffer.Type.Index) { throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); } @@ -2796,19 +2180,11 @@ public class OGLESShaderRenderer implements Renderer { int elementLength = elementLengths[i]; indexBuf.getData().position(curOffset); - if (verboseLogging) { - logger.log(Level.INFO, "glDrawElements(): {0}, {1}", new Object[]{elementLength, curOffset}); - } - GLES20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData()); curOffset += elementLength * elSize; } } else { - if (verboseLogging) { - logger.log(Level.INFO, "glDrawElements(), indexBuf.capacity ({0}), vertCount ({1})", new Object[]{indexBuf.getData().capacity(), vertCount}); - } - GLES20.glDrawElements( convertElementMode(mesh.getMode()), indexBuf.getData().capacity(), @@ -2823,10 +2199,6 @@ public class OGLESShaderRenderer implements Renderer { * @param idb */ public void setVertexAttrib_Array(VertexBuffer vb, VertexBuffer idb) { - if (verboseLogging) { - logger.log(Level.INFO, "setVertexAttrib_Array({0}, {1})", new Object[]{vb, idb}); - } - if (vb.getBufferType() == VertexBuffer.Type.Index) { throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); } @@ -2840,23 +2212,13 @@ public class OGLESShaderRenderer implements Renderer { int loc = attrib.getLocation(); if (loc == -1) { //throw new IllegalArgumentException("Location is invalid for attrib: [" + vb.getBufferType().name() + "]"); - if (verboseLogging) { - logger.log(Level.WARNING, "attribute is invalid in shader: [{0}]", vb.getBufferType().name()); - } return; } else if (loc == -2) { String attributeName = "in" + vb.getBufferType().name(); - if (verboseLogging) { - logger.log(Level.INFO, "GLES20.glGetAttribLocation({0}, {1})", new Object[]{programId, attributeName}); - } - loc = GLES20.glGetAttribLocation(programId, attributeName); if (loc < 0) { attrib.setLocation(-1); - if (verboseLogging) { - logger.log(Level.WARNING, "attribute is invalid in shader: [{0}]", vb.getBufferType().name()); - } return; // not available in shader. } else { attrib.setLocation(loc); @@ -2870,23 +2232,6 @@ public class OGLESShaderRenderer implements Renderer { avb.getData().clear(); avb.getData().position(vb.getOffset()); - if (verboseLogging) { - logger.log(Level.INFO, - "GLES20.glVertexAttribPointer(" + - "location={0}, " + - "numComponents={1}, " + - "format={2}, " + - "isNormalized={3}, " + - "stride={4}, " + - "data.capacity={5})", - new Object[]{loc, vb.getNumComponents(), - vb.getFormat(), - vb.isNormalized(), - vb.getStride(), - avb.getData().capacity()}); - } - - // Upload attribute data GLES20.glVertexAttribPointer(loc, vb.getNumComponents(), @@ -2894,7 +2239,6 @@ public class OGLESShaderRenderer implements Renderer { vb.isNormalized(), vb.getStride(), avb.getData()); - checkGLError(); GLES20.glEnableVertexAttribArray(loc); @@ -2925,6 +2269,6 @@ public class OGLESShaderRenderer implements Renderer { public void invalidateState() { context.reset(); boundShader = null; - lastFb = null; +// lastFb = null; } } diff --git a/engine/src/android/com/jme3/renderer/android/TextureUtil.java b/engine/src/android/com/jme3/renderer/android/TextureUtil.java index 4137f37e0..855b9a1d8 100644 --- a/engine/src/android/com/jme3/renderer/android/TextureUtil.java +++ b/engine/src/android/com/jme3/renderer/android/TextureUtil.java @@ -1,82 +1,239 @@ package com.jme3.renderer.android; import android.graphics.Bitmap; +import android.opengl.ETC1; +import android.opengl.ETC1Util.ETC1Texture; import android.opengl.GLES20; import android.opengl.GLUtils; import com.jme3.asset.AndroidImageInfo; import com.jme3.math.FastMath; +import com.jme3.renderer.RendererException; import com.jme3.texture.Image; +import com.jme3.texture.Image.Format; +import com.jme3.util.BufferUtils; import java.nio.ByteBuffer; -import javax.microedition.khronos.opengles.GL10; +import java.util.logging.Level; +import java.util.logging.Logger; public class TextureUtil { - private static void buildMipmap(Bitmap bitmap) { + private static final Logger logger = Logger.getLogger(TextureUtil.class.getName()); + + private static boolean ENABLE_COMPRESSION = true; + private static boolean NPOT = false; + private static boolean ETC1support = false; + private static boolean DXT1 = false; + private static boolean DEPTH24 = false; + + public static void loadTextureFeatures(String extensionString) { + ETC1support = extensionString.contains("GL_OES_compressed_ETC1_RGB8_texture"); + DEPTH24 = extensionString.contains("GL_OES_depth24"); + NPOT = extensionString.contains("GL_OES_texture_npot") || extensionString.contains("GL_NV_texture_npot_2D_mipmap"); + DXT1 = extensionString.contains("GL_EXT_texture_compression_dxt1"); + logger.log(Level.FINE, "Supports ETC1? {0}", ETC1support); + logger.log(Level.FINE, "Supports DEPTH24? {0}", DEPTH24); + logger.log(Level.FINE, "Supports NPOT? {0}", NPOT); + logger.log(Level.FINE, "Supports DXT1? {0}", DXT1); + } + + private static void buildMipmap(Bitmap bitmap, boolean compress) { int level = 0; int height = bitmap.getHeight(); int width = bitmap.getWidth(); + + logger.log(Level.FINEST, " - Generating mipmaps for bitmap using SOFTWARE"); + GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); + while (height >= 1 || width >= 1) { //First of all, generate the texture from our bitmap and set it to the according level - GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bitmap, 0); + if (compress) { + logger.log(Level.FINEST, " - Uploading LOD level {0} ({1}x{2}) with compression.", new Object[]{level, width, height}); + uploadBitmapAsCompressed(GLES20.GL_TEXTURE_2D, level, bitmap); + } else { + logger.log(Level.FINEST, " - Uploading LOD level {0} ({1}x{2}) directly.", new Object[]{level, width, height}); + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, level, bitmap, 0); + } if (height == 1 || width == 1) { break; } //Increase the mipmap level - level++; - height /= 2; width /= 2; Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true); - bitmap.recycle(); + // Recycle any bitmaps created as a result of scaling the bitmap. + // Do not recycle the original image (mipmap level 0) + if (level != 0){ + bitmap.recycle(); + } + bitmap = bitmap2; + + level++; } } + private static void uploadBitmapAsCompressed(int target, int level, Bitmap bitmap) { + if (bitmap.hasAlpha()) { + logger.log(Level.FINEST, " - Uploading bitmap directly. Cannot compress as alpha present."); + GLUtils.texImage2D(target, level, bitmap, 0); + } else { + // Convert to RGB565 + int bytesPerPixel = 2; + Bitmap rgb565 = bitmap.copy(Bitmap.Config.RGB_565, true); + + // Put texture data into ByteBuffer + ByteBuffer inputImage = BufferUtils.createByteBuffer(bitmap.getRowBytes() * bitmap.getHeight()); + rgb565.copyPixelsToBuffer(inputImage); + inputImage.position(0); + + // Delete the copied RGB565 image + rgb565.recycle(); + + // Encode the image into the output bytebuffer + int encodedImageSize = ETC1.getEncodedDataSize(bitmap.getWidth(), bitmap.getHeight()); + ByteBuffer compressedImage = BufferUtils.createByteBuffer(encodedImageSize); + ETC1.encodeImage(inputImage, bitmap.getWidth(), + bitmap.getHeight(), + bytesPerPixel, + bytesPerPixel * bitmap.getWidth(), + compressedImage); + + // Delete the input image buffer + BufferUtils.destroyDirectBuffer(inputImage); + + // Create an ETC1Texture from the compressed image data + ETC1Texture etc1tex = new ETC1Texture(bitmap.getWidth(), bitmap.getHeight(), compressedImage); + + // Upload the ETC1Texture + if (bytesPerPixel == 2) { + int oldSize = (bitmap.getRowBytes() * bitmap.getHeight()); + int newSize = compressedImage.capacity(); + logger.log(Level.FINEST, " - Uploading compressed image to GL, oldSize = {0}, newSize = {1}, ratio = {2}", new Object[]{oldSize, newSize, (float)oldSize/newSize}); + GLES20.glCompressedTexImage2D(target, + level, + ETC1.ETC1_RGB8_OES, + bitmap.getWidth(), + bitmap.getHeight(), + 0, + etc1tex.getData().capacity(), + etc1tex.getData()); + +// ETC1Util.loadTexture(target, level, 0, GLES20.GL_RGB, +// GLES20.GL_UNSIGNED_SHORT_5_6_5, etc1Texture); +// } else if (bytesPerPixel == 3) { +// ETC1Util.loadTexture(target, level, 0, GLES20.GL_RGB, +// GLES20.GL_UNSIGNED_BYTE, etc1Texture); + } + + BufferUtils.destroyDirectBuffer(compressedImage); + } + } + /** * uploadTextureBitmap uploads a native android bitmap */ - public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean generateMips, boolean powerOf2) { - if (!powerOf2) { - // Power of 2 images are not supported by this GPU. + public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean needMips) { + boolean recycleBitmap = false; + if (!NPOT || needMips) { + // Power of 2 images are not supported by this GPU. + // OR + // Mipmaps were requested to be used. + // Currently OGLES does not support NPOT textures with mipmaps. int width = bitmap.getWidth(); int height = bitmap.getHeight(); // If the image is not power of 2, rescale it if (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height)) { - // scale to power of two, then recycle the old image. + // Scale to power of two. width = FastMath.nearestPowerOfTwo(width); height = FastMath.nearestPowerOfTwo(height); + + logger.log(Level.WARNING, " - Image is not POT, so scaling it to new resolution: {0}x{1}", new Object[]{width, height}); Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true); - bitmap.recycle(); bitmap = bitmap2; + + // Flag to indicate that bitmap + // should be recycled at the end. + recycleBitmap = true; } } - if (generateMips) { - buildMipmap(bitmap); + boolean willCompress = ENABLE_COMPRESSION && ETC1support && !bitmap.hasAlpha(); + if (needMips && willCompress) { + // Image is compressed and mipmaps are desired, generate them + // using software. + buildMipmap(bitmap, willCompress); + } else { + if (willCompress) { + // Image is compressed but mipmaps are not desired, upload directly. + logger.log(Level.FINEST, " - Uploading compressed bitmap. Mipmaps are not generated."); + uploadBitmapAsCompressed(target, 0, bitmap); + } else { + // Image is not compressed, mipmaps may or may not be desired. + logger.log(Level.FINEST, " - Uploading bitmap directly.{0}", + (needMips ? + " Mipmaps will be generated in HARDWARE" : + " Mipmaps are not generated.")); + GLUtils.texImage2D(target, 0, bitmap, 0); + if (needMips) { + // No pregenerated mips available, + // generate from base level if required + GLES20.glGenerateMipmap(target); + } + } + } + + if (recycleBitmap) { + bitmap.recycle(); + } + } + + public static void uploadTextureAny(Image img, int target, int index, boolean needMips) { + if (img.getEfficentData() instanceof AndroidImageInfo){ + logger.log(Level.FINEST, " === Uploading image {0}. Using BITMAP PATH === ", img); + // If image was loaded from asset manager, use fast path + AndroidImageInfo imageInfo = (AndroidImageInfo) img.getEfficentData(); + uploadTextureBitmap(target, imageInfo.getBitmap(), needMips); } else { - GLUtils.texImage2D(target, 0, bitmap, 0); - //bitmap.recycle(); + logger.log(Level.FINEST, " === Uploading image {0}. Using BUFFER PATH === ", img); + boolean wantGeneratedMips = needMips && !img.hasMipmaps(); + if (wantGeneratedMips && img.getFormat().isCompressed()) { + logger.log(Level.WARNING, "Generating mipmaps is only" + + " supported for Bitmap based or non-compressed images!"); + } + + // Upload using slower path + logger.log(Level.FINEST, " - Uploading bitmap directly.{0}", + (wantGeneratedMips ? + " Mipmaps will be generated in HARDWARE" : + " Mipmaps are not generated.")); + uploadTexture(img, target, index); + + // Image was uploaded using slower path, since it is not compressed, + // then compress it + if (wantGeneratedMips) { + // No pregenerated mips available, + // generate from base level if required + GLES20.glGenerateMipmap(target); + } } } + + private static void unsupportedFormat(Format fmt) { + throw new UnsupportedOperationException("The image format '" + fmt + "' is unsupported by the video hardware."); + } - public static void uploadTexture(Image img, + private static void uploadTexture(Image img, int target, - int index, - int border, - boolean tdc, - boolean generateMips, - boolean powerOf2){ + int index){ if (img.getEfficentData() instanceof AndroidImageInfo){ - // If image was loaded from asset manager, use fast path - AndroidImageInfo imageInfo = (AndroidImageInfo) img.getEfficentData(); - uploadTextureBitmap(target, imageInfo.getBitmap(), generateMips, powerOf2); - return; + throw new RendererException("This image uses efficient data. " + + "Use uploadTextureBitmap instead."); } // Otherwise upload image directly. @@ -92,7 +249,16 @@ public class TextureUtil { int width = img.getWidth(); int height = img.getHeight(); int depth = img.getDepth(); - + + if (!NPOT) { + // Check if texture is POT + if (!FastMath.isPowerOfTwo(width) || width != height) { + throw new RendererException("Non-power-of-2 textures " + + "are not supported by the video hardware " + + "and no scaling path available for image: " + img); + } + } + boolean compress = false; int format = -1; int dataType = -1; @@ -150,6 +316,22 @@ public class TextureUtil { format = GLES20.GL_DEPTH_COMPONENT; dataType = GLES20.GL_UNSIGNED_BYTE; break; + case DXT1: + if (!DXT1) { + unsupportedFormat(fmt); + } + format = 0x83F0; + dataType = GLES20.GL_UNSIGNED_BYTE; + compress = true; + break; + case DXT1A: + if (!DXT1) { + unsupportedFormat(fmt); + } + format = 0x83F1; + dataType = GLES20.GL_UNSIGNED_BYTE; + compress = true; + break; default: throw new UnsupportedOperationException("Unrecognized format: " + fmt); } @@ -170,18 +352,18 @@ public class TextureUtil { // XXX: might want to change that when support // of more than paletted compressions is added.. /// NOTE: Doesn't support mipmaps - if (compress){ - data.clear(); - GLES20.glCompressedTexImage2D(target, - 1 - mipSizes.length, - format, - width, - height, - 0, - data.capacity(), - data); - return; - } +// if (compress){ +// data.clear(); +// GLES20.glCompressedTexImage2D(target, +// 1 - mipSizes.length, +// format, +// width, +// height, +// 0, +// data.capacity(), +// data); +// return; +// } for (int i = 0; i < mipSizes.length; i++){ int mipWidth = Math.max(1, width >> i);