I have an application which views zoomable images using OPENGLES2.0, and want to render large textures - 1920x2560 and larger - and get GL_INVALID_VALUE errors when trying to load them.
How do I go about doing this?
Mobile devices often cannot support textures bigger than 2048 pixels (width or height).
IOS devices such as IPAD for instance cannot support textures bigger than 2048x2048.
I have found the same limit on most of the Android devices where I have tested my PATRIA 3D engine hence I can only advice you to stay under this limit.
I suggest you to read carefully this official OpenGL document
http://www.opengl.org/resources/faq/technical/texture.htm
In particular point:
21.130 What's the maximum size texture map my device will render hardware accelerated?
Related
I would like to know if there is any kind of limitation on the texture size that can be used in any Android Opengl Es 2.0 projects. I understand that having a huge texture of size 4096x4096 is a bit meaning less as it is rendered on a small screen. But What if the requirement is to switch between many textures at run time? And If I want to have a texture atlas to do a quick single upload instead of multiple smaller texture upload. Please let me know your ideas in this regards.
Also I am sure there has to be a limitation on the size of image that can be processed by a device, as the memory on the device is limited. But I would like to know if it is resolution based or is it size based. I mean if a device has a limitation of 1024x1024 image size can it handle a compressed texture of size 2048x2048 that would be of same size approx as uncompressed 1024x1024.
Also please let me know on an general basis usually how much the limitation on texture size or resolution normal devices running android 2.2 and above would be.
Also please let me know if there are any best practices when handling high resolution images in opengles 2.0 to get best performance in both load time and also run time.
There is a hardware limitation on the texture sizes. To manually look them up, you can go to a site such as glbenchmark.com (Here displaying details about google galaxy nexus).
To automatically find the maximum size from your code, you can use something like:
int[] max = new int[1];
gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, max, 0); //put the maximum texture size in the array.
(For GL10, but the same method exists for GLES20)
When it comes to the processing or editing of an image you usually use an instance of Bitmap when working in android. This holds the uncompressed values of your image and is thus resolution dependant. However, it is recommended that you use compressed textures for your openGL applications as this improves the memory-use efficiency (note that you cannot modify these compressed textures).
From the previous link:
Texture compression can significantly increase the performance of your
OpenGL application by reducing memory requirements and making more
efficient use of memory bandwidth. The Android framework provides
support for the ETC1 compression format as a standard feature [...]
You should take a look at this document which contains many good practices and hints about texture loading and usage. The author explicitly writes:
Best practice: Use ETC for texture compression.
Best practice: Make sure your geometry and texture resolutions are
appropriate for the size they're displayed at. Don't use a 1k x 1k
texture for something that's at most 500 pixels wide on screen. The
same for geometry.
I use SurfaceView for my 2D Android game which I have almost completed. It's based on JBox2D. It is perfectly running on Samsung Galaxy S2, its FPS is 60. It is also running smoothly on HTC Explorer, its FPS is about 54. I thought that if my game was working well in these relatively old devices, it would be working better in the newer ones. But I was wrong! I saw yesterday the FPS value of my game on Galaxy Note 4 is varied between 22 and 45 depending on the number of game objects.
After investigating on this issue in Google and StackOverflow, I deduced that the new devices like Galaxy Note 4 which has higher resolutions (1440 x 2560) could not handle with their large images whereas the little ones can handle with their own smaller images (Galaxy s2:480 x 800, HTC Explorer:320 x 480). Yes, the new devices are surely faster than the older ones, but I think their huge resolutions of the newer devices are the reason of the slowness on the SurfaceView. Of course, this is valid under SurfaceView conditions. If I used OpenGL for my game, it would not be a problem for the new devices having high resolutions.
My bitmaps are designed for 800 x 1280 devices. According to the different device resolutions, my game rescales the images when they are loaded at the beginning of the each level by using createScaledBitmap.
I couldn't transform my game from SurfaceView to OpenGL platform because my game is about to finish and I didn't have enough knowledge about OpenGL.
What should I do?
I believe you have correctly identified the problem: newer devices have pixel counts like you'd find on a 27" monitor (2560x1440), because the manufacturers are chasing screen resolution like they do camera megapixels. The result is that rendering a full screen takes longer, especially when you're doing it in software. Faster CPUs and increased bus bandwidth can help, but full-screen software rendering is problematic.
The solution for Android is to make the Surface smaller, and let the hardware scale it up as it's being scanned out. This is significantly easier (and more efficient) than scaling up each individual item. You do this with the SurfaceHolder#setFixedSize() method. For example, for a 2560x1440 display, you could set the Surface size to 1280x720, and only render a quarter of the pixels. The display performs the pixel doubling (with bilinear filtering).
You can find a blog post here, and can see this in action in Grafika's "hardware scaler exerciser" activity (youtube demo video).
The various examples use GLES -- which also benefits from having fewer pixels to fill -- but applies to Canvas rendering as well.
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 would like to know if there is any kind of limitation on the texture size that can be used in any Android Opengl Es 2.0 projects. I understand that having a huge texture of size 4096x4096 is a bit meaning less as it is rendered on a small screen. But What if the requirement is to switch between many textures at run time? And If I want to have a texture atlas to do a quick single upload instead of multiple smaller texture upload. Please let me know your ideas in this regards.
Also I am sure there has to be a limitation on the size of image that can be processed by a device, as the memory on the device is limited. But I would like to know if it is resolution based or is it size based. I mean if a device has a limitation of 1024x1024 image size can it handle a compressed texture of size 2048x2048 that would be of same size approx as uncompressed 1024x1024.
Also please let me know on an general basis usually how much the limitation on texture size or resolution normal devices running android 2.2 and above would be.
Also please let me know if there are any best practices when handling high resolution images in opengles 2.0 to get best performance in both load time and also run time.
There is a hardware limitation on the texture sizes. To manually look them up, you can go to a site such as glbenchmark.com (Here displaying details about google galaxy nexus).
To automatically find the maximum size from your code, you can use something like:
int[] max = new int[1];
gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, max, 0); //put the maximum texture size in the array.
(For GL10, but the same method exists for GLES20)
When it comes to the processing or editing of an image you usually use an instance of Bitmap when working in android. This holds the uncompressed values of your image and is thus resolution dependant. However, it is recommended that you use compressed textures for your openGL applications as this improves the memory-use efficiency (note that you cannot modify these compressed textures).
From the previous link:
Texture compression can significantly increase the performance of your
OpenGL application by reducing memory requirements and making more
efficient use of memory bandwidth. The Android framework provides
support for the ETC1 compression format as a standard feature [...]
You should take a look at this document which contains many good practices and hints about texture loading and usage. The author explicitly writes:
Best practice: Use ETC for texture compression.
Best practice: Make sure your geometry and texture resolutions are
appropriate for the size they're displayed at. Don't use a 1k x 1k
texture for something that's at most 500 pixels wide on screen. The
same for geometry.
I'm trying to develop an app that uses opengl on android, and ideally make it run on any phone as old as the original droid (or at least any phone that has OpenGL ES 2.0 support). Currently, I'm using a 2048x2048 ETC1 texture compression. It works fine on the Droid X I'm testing it on, but I currently don't have an original droid to test it on, and I can't find much data on this topic either. I know the G1 didn't do well with textures bigger than 512x512, and the droid seems to do fine with images as large as 1024x1024, but what about 2048x2048? (Again, etc1 compression, so it's about 2 MB large). Also, because ETC1 doesn't support alpha, I would like to load up another ETC1 texture to support an alpha channel. Is this a pipe dream?
Basically, I would like to know how much space I have to load texture data in android phones no older than the original droid, at least without the whole thing slowing down drastically.
You can query the MAX_TEXTURE_SIZE to get the maximum texture size, or you can look up your phone on http://glbenchmark.com (you can find the Droid info here). The G1 did not support GLES 2.0, AFAIK.
Loading up several textures should definitly work, especially when they are not more than 2 MB each. But you will of course be restricted by the size of the memory available.
Also, to have optimal performance you should mipmap your textures. Since you are using ETC, this must be done offline.
For a guide to how to use ETC1 with alpha, see here.