In my live wallpaper I'm drawing 3 textured quads that covers the whole screen. On Nexus One I get 40fps. I'm looking for ways to improving performance.
The quads are blended on top of each other, textures are loaded from RGB_8888 bitmaps. Textures are 1024x1024.
I've got
glDisable(GL_DITHER);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glDisable(GL10.GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Things I've tried, all resulting in the same 40fps:
Reduce texture size to 512x512 and 256x256
Use draw_texture extension
Disable blending
Change texture filtering from GL_LINEAR to GL_NEAREST
Use VBOs (desperate try, since there are just 3 quads...)
Run the drawing code in standalone activity (in case being a live wallpaper somehow affects performance)
If I draw 2 layers instead of 3, fps rises to 45 or so,
then drawing just 1 layer sees fps rise to 55. I guess I'm getting limited by fill rate, since turning off and on the potentially costly features result in the same fps, and the only thing that seems to improve fps is just drawing less...
I'm mulling over the idea of texture compression, but supporting the different compression formats doesn't seem like fun. ETC1 has no alpha channel which I need, and I'm not sure if PVRTC and ATITC can even be used from Java and OpenGL ES 1.0 or 1.1.
I'd be glad to hear ideas on what else to try.
I can give pointer to the current version of wallpaper and screenshots if that's of use.
You probably already thought of this, but just in case you didn't:
calling glClear at the start of your frame probably isn't necessary
you could do the first pass with blending disabled
Also, did you try doing it in 1 pass with a multi-texturing approach?
edit: And another thing: writing to the z-buffer is not needed, so either use a context without z-buffer, or disable depth writing with glDepthMask(GL_FALSE).
glCompressedTexImage2D is available in Java (and NDK), however available compression format depends on GPU.
The AndroidManifest.xml File > supports-gl-texture
PowerVR SGX - Nexus S, Galaxy S/Tab, DROID - PVRTC
Adreno - Nexus One, EVO - ATITC
Tegra2 - Xoom, Atrix - S3TC
If you use these compression format and want to support various Android devices, you must prepare for many compressed textures, but the GPU native compression texture should improve rendering performance.
GPU Profiling and callbacks in OpenGL ES
OpenGL ES, Changing texture format
from RGBA8888 to RGBA4444 will
improve fill rate?
The android opengl framework min3d is able to draw these objects or scenes at a full 60fps.
The framework is opensource and is available for download and use at: http://code.google.com/p/min3d/
I would recommend comparing your code to it to see what you have done wrong/differently in order to improve your performance.
Related
I need to have two ping-pong framebuffers in my OpenGL ES app on Android. I also need them to be of the same size as device screen. Neither depth buffer nor stencil buffer will be attached to them only RGBA8888 color buffer.
I'm planning to use them for adding some Photoshop like blending modes (color burn, overlay, etc.)
Can I afford this on most modern (say above Android 3.0, OpenGL ES 2.0) devices? And if not then Why? And how to determine whenever I can create the prior to their creation?
I think this should be reasonably safe to assume for devices above Android 3.0, I think they should all be running OpenGLES 2.0?
Your bottle necks will be memory (unlikely to run out here though I would have thought) and complexity of whatever you need to ping pong these buffers for. I ported this fluid simulation to Android using OpenGLES 2.0 which relies heavily on ping-ponging frame buffers to perform simulation updates.
I had 6 or so full screen frame buffers on a Samsung Galaxy S4 and Nexus 7 (2012) all of which were created just fine. My problem was that the simulation itself was very complex and these devices just couldn't perform.
I can't imagine memory being an issue for 2 full screen buffers and performance probably will be OK depending on how often you're rendering to them.
Not sure how much this helps as it all depends on your usage.
Can you just check what glFramebufferTexture2D returns when you try to attach it to your FBO in terms of checking if the device can handle it?
I found a 3D graphics framework for Android called Rajawali and I am learning how to use it. I followed the most basic tutorial which is rendering a shpere object with a 1024x512 size jpg image for the texture. It worked fine on Galaxy Nexus, but it didn't work on the Galaxy Player GB70.
When I say it didn't work, I mean that the object appears but the texture is not rendered. Eventually, I changed some parameters that I use for the Rajawali framework when creating textures and got it to work. Here is what I found out.
The cause was coming from where the GL_TEXTURE_MIN_FILTER was being set. Among the following four values
GLES20.GL_LINEAR_MIPMAP_LINEAR
GLES20.GL_NEAREST_MIPMAP_NEAREST
GLES20.GL_LINEAR
GLES20.GL_NEAREST
the texture is only rendered when GL_TEXTURE_MIN_FILTER is not set to a filter using mipmap. So when GL_TEXTURE_MIN_FILTER is set to the last two it works.
Now here is the what I don't understand and am curious about. When I shrink the image which I'm using as the texture to size 512x512 the GL_TEXTURE_MIN_FILTER settings does not matter. All four settings of the min filter works.
So my question is, is there a requirement for the dimensions of the image when using min filter for the texture? Such as am I required to use an image that is square? Can other things such as the wrap style or the the configuration of the mag filter be a problem?
Or does it seem like a OpenGL implementation bug of the device?
Good morning, this a typical example of non-power of 2 textures.
Textures need to be power of 2 in their resolution for a multitude of reasons, this is a very common mistake and it did happen to everybody to fall in this pitfall :) too me too.
The fact that non power of 2 textures work smoothly on some devices/GPU, depends merely to the OpenGL drivers implementation, some GPUs support them clearly, some others don't, I strongly suggest you to go for pow2 textures in order to be able to guarantee the functioning on all the devices.
Last but not least, using non power of 2 textures can lead you to a cathastrophic scenarious in GPU memory utilization since, most of the drivers which accept non-powerof2 textures, need to rescale in memory the textures to the nearest higher power of 2 factor. For instance, having a texture of 520X520 could lead to an actual memory mapping of 1024X1024.
This is something you don't want because in real world "size matters", especially on mobile devices.
You can find a quite good explanation in the OpenGL Gold Book, the OpenGL ES 2.0:
In OpenGL ES 2.0, textures can have non-power-of-two (npot)
dimensions. In other words, the width and height do not need to be a
power of two. However, OpenGL ES 2.0 does have a restriction on the
wrap modes that can be used if the texture dimensions are not power of
two. That is, for npot textures, the wrap mode can only be
GL_CLAMP_TO_EDGE and the minifica- tion filter can only be GL_NEAREST
or GL_LINEAR (in other words, not mip- mapped). The extension
GL_OES_texture_npot relaxes these restrictions and allows wrap modes
of GL_REPEAT and GL_MIRRORED_REPEAT and also allows npot textures to
be mipmapped with the full set of minification filters.
I suggest you to evaluate this book since it does a quite decent coverage to this topic.
I created a movie player based on FFmpeg. It works fine. The decoding is quite fast, on LG P970 (Cortex A8 with Neon) I have an average 70 fps with 640 x 424 resolution video stream including YUV2RGB conversion. However, there is one bottleneck. It is drawing on Canvas.
I use jnigraphics native library to fill picture data into the bitmap in the native side and then I draw this bitmap on Canvas in SurfaceView. It is quite simple and common approach, but the drawing takes 44 ms for bitmap with 640 x 424 resolution which reduces fps to 23 and makes this technique unusable... It takes a lot more then the whole A/V frame decoding!
Is there any method how to draw bitmaps significantly faster? I would prefer to render completely in the native code using OpenGLES 2, but I have read it also could be slow. So what now?...
How can I render bitmaps as fast as possible?
Draw them in GLES1.x. You do not need to use GLES2 as you will have no use, or at least not in the context of your question, for shaders which would be the general primary reason of using GLES2.x. So for simplicity sake, GLES1.x would be ideal. All you need to do is draw the bytebuffer to the screen. On my Galaxy S (Vibrant) this takes about 3ms. The size of the byte[] in my wallpaper is 800x480x3 or 1152000 which is significantly larger than what you are working with.
I believe this guide should point you in the correct direction.
http://qdevarena.blogspot.com/2009/02/how-to-load-texture-in-android-opengl.html
As for the notion of accessing canvas from native code, I would just avoid that altogether and follow an OpenGL implementation by offloading everything to GPU as much as possible.
I recall during the Replica Island presentation during GoogleIO the designer said that using the OpenGL 'draw_texture' extension glDrawTexfOES was the fastest way to blit to the screen, and significantly faster than drawing just regular quads with textures attached (I'm assuming you're using OpenGL).
You can't rotate the texture, but it doesn't sound like you need that.
I am learning to develop games with Android using libgdx, a framework for programming in Android using OpenGL ES and on desktop with Java using LWJGL. The device I am testing on (HTC Hero) quotes a maximum texture size of 1024 and a maximum stack depth of 2. However, when I create textures at this maximum size, they will not load, instead displaying a white square where the texture should be. The textures are this size because they are packed sprite sheets, and it is preferable to keep them at this size. With regards to the stack depth, the device will also show a white square if more than 1 texture is used simultaneously, so it seems as though the maximum values given by OpenGL ES are one step above that of the device's actual performance. Can anybody help me out? Thanks
Actually there are scales for texture in libgdx, like texture must be exponent of 2. so as you said you are running with sprites please go through once how to work with sprites in http://libgdx.googlecode.com/svn/trunk/tests/gdx-tests/src/com/badlogic/gdx/tests/. I hope it works
I find this question to be of value despite of its age.
In current devices going 1024x1024 is pretty much safe. But if it doesn't work on one of yours, go lower. 1 or 4 draw calls won't affect much performant wise.
I have an OpenGL Live wallpaper that works fine on all phones except those with the PowerVR SGX series. This includes almost all Samsung phones and the Motorola Droid series. The wallpaper is nothing but a black screen on the PowerVR GPU phones. I have been racking my brain for a week trying to figure this problem out but have had no luck.
One difference between the different GPUs is their texture compression. Some of the things I have done in that regards is I have changed my texture image to a square of 256x256. Changed it from 8 bit to a 16 bit rgba and even tried indexed.
I have a list of all the extensions that are available with the PowerVR and the ones that are available with the Adreno. It seems that there are quite a few differences in available extensions but I do not know what functions go with what extensions (though I can somewhat guess). Here is a list of the functions that I use:
glLightfv
glMaterialfv
glDepthFunc
glEnableClientState
glViewport
glMatrixMode
glLoadIdentity
gluPerspective
glclearcolor
glclear
glTranslatef
glRotatef
glVertexPointer
glTexCoordPointer
glColor4f
glNormal3f
glDrawArrays
glTexParamterx
I am using Robert Green's GlWallPaperService and have tried this solution at Trying to draw textured triangles on device fails, but the emulator works. Why? . Does anybody have any idea why the PowerVR chips are giving me such a hard time and what I could do about it?
Removing EGL10.EGL_RED_SIZE, EGL10.EGL_GREEN_SIZE, and EGL10.EGL_BLUE_SIZE but leaving EGL10.EGL_DEPTH_SIZE, EGL10.EGL_NONE in the eglChooseConfig worked. I assume that the PowerVR chip processes RGB in a way that makes defining them a problem.
This probably won't help you, but I noticed:
One difference between the different GPUs is their texture compression. Some of the things I have done in that regards is I have changed my texture image to a square of 256x256. Changed it from 8 bit to a 16 bit rgba and even tried indexed.
To my knowledge, no current hardware supports indexed textures. Also, to use texture compression, you need to target a compressed texture format that is specifically supported by the device (which usually entails running a compressor on the host/development platform). SGX supports PVRTC and ETC but whether those are enabled depends on the platform
From my own experience with this GPU, it will offer GLES configurations, that once applied will not work (i.e. the GLES context will not be created). The workaround is to look at the GLSurfaceView code, roll out your own and try out each offered configuration, whether it works for creating a context.