Android OpenGL ES texture TextImage2D error - android

Due to some unfathomable reason, the textures won't load.
Here's the method
public static void loadGLTexture(GL10 gl, Context context){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDensity = 240;// needed so that the image will be 512x512
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.glasstexture, options);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Log.i("GridLoginSquare.loadGLTexture 96", "Bitmap:{w:" + width + " h:" + height + "}");
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
// create nearest filtered texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
// Use Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); //error is on this line
Log.e("GridLoginSquare.loadGLTexture 102", " ERR "+gl.glGetError());
// Clean up
bitmap.recycle();
}
The size of my texture image is 405 x 512
The line Log.e("GridLoginSquare.loadGLTexture 102", " ERR "+gl.glGetError()); gives
me a 1281 error which (after investigating others who had similar problems) means
INVALID_VALUE
The above code is a part of the overall GridLoginSquare class which is here
NOTE This problem had already persisted before BitmapFactory.Options density was included to scale the image. Similarly the texture uv was divided by 405 and 512 when this was included in the gist code.

I have had this problem when I did not put my textures in the drawable-nodpi folder. Try moving your textures into that folder.
Also, OpenGL prefers your textures to have dimensions that are powers of two. I am not sure if this would cause the textures to not appear at all, but you may as well try making your texture images 512x512 or 256x256 just to see.

I had exactly the same error at textImage2D with glGetError returning 0, and WindyB's solution of using images whose width & length are powers of two... DID WORK form me! Thank you very much! :)
This error took place only in Android 2 (exactly Android 2.3.3). In Android 4 it always worked fine (I like to test my Apps in different Android versions).
By the way, I had no need of creating folder 'drawable-nodpi', I have it all stacked in just 'drawable'
In case it helps: At http://developer.android.com/guide/topics/graphics/opengl.html#manifest under 'Declaring OpenGL Requirements' it says that some texture compression formats are not compatible with some devices.. Maybe your problem has something to do with this?

I have my textures on drawable-nodpi folder (which we have to create) and was getting the same error 1281 after call this function: GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
And it was being caused because my textures wasn't at power of 2, so after I fix it (leave it at power of 2), it works fine, only leaving a texture bleeding (when a tiny undesired part of the texture appears on the borders), but this is solved adjusting the values of the uvs coordinates.

Related

OpenGL Texture Size Limits. Providing alternate resources for specific Android devices

Within my Android App, which is an OpenGL ES 2.0 game, I've included 4 sets of graphic resources like so
ldpi
mdpi
hdpi
xhdpi
Now, within my xhdpi folder, the largest asset I have is 2560 x 1838 as I'm targeting large screens here (for example the Google Nexus 10 tablet which gets its resources from the XHDPI folder). Up until now, everything has worked on the devices on which I've tested (Google Nexus 10, Samsung Galaxy S3, S4 & S5, Nexus 4 & 5 etc etc....)
I've recently heard from a user who has encountered problems running this on an HTC One X+ handset (I believe there are other reasons for this besides the one I'm talking about here so I have a separate question open for the other issues).
The thing is, according to: this, the maximum texture size for the this phone is 2048x2048, but then according to this this phone gets its resources from the XHDPI folder.
So, it won't display the textures from this atlas (it's an atlas of backgrounds containing 6 separate backgrounds of 1280*612.
Now I have two options that I am aware of to fix this:
Reduce the size of the backgrounds. Ruled out as this would compromise quality on larger-screen devices (like the nexus 10)
Split into 2 atlases would rather not do this as would like to keep all backgrounds in 1 atlas to optimise loading speed (and just to keep things tidy)
Are there any other options? Am I able to provide, within a sub folder of xhdpi another folder that fits within the 1X+'s limits? And if so, how do I get the device to grab resources from there?
I'm doing this blind as I don't have an 1X+ on which to test this, but from what I've read, I believe having assets larger than 2048 x 2048 is going to cause problems on this device.
This is my code for applying textures:
public static int LoadTexture(GLSurfaceView view, Bitmap imgTex){
//Array for texture
int textures[] = new int[1];
try {
//texture name
GLES20.glGenTextures(1, textures, 0);
//Bind textures
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
//Set parameters for texture
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
//Apply texture
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, imgTex, 0);
//clamp texture
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
} catch (Exception e){
}
//Increase texture count
textureCount++;
//Return texture
return textures[0];
}
If you don't know if a texture load will work, you can do all the same operations, except use GL_PROXY_TEXTURE_2D (or 1D, 3D, etc.) instead of GL_TEXTURE_2D to check to see if the load will work for a given texture size and parameters. OpenGL attempts to perform the load, and and it will set all texture state to 0 if it doesn't work or there is another problem in a texture parameter. Then if the texture load fails (in your case due to the image being too big), have your program load a smaller scaled texture.
EDIT: I use iOS and my gl.h doesn't include GL_PROXY_TEXTURE_* and I can't find any reference in the OpenGL ES3 specification, so I'm not sure this will work for you with OpenGL.
Alternatively, get your max texture size (per dimension, e.g. width, height or depth) and load a suitable image sized using:
glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );
Afterward, check your image to ensure it worked.
GLuint name;
int width = 10000; // really bad width
int height = 512;
GLint size;
glGenTextures( 1, &name );
glBindTexture( GL_TEXTURE_2D, name );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0);
GLenum error = glGetError();
if( error ) {
printf("Failed!");
}
else {
printf("Succeeded!");
}

Common reasons for OpenGL Textures not being rendered

I just heard from a user who says that my (Android OpenGL ES 2.0) app (a game) won't run on his HTC 1X+ handset. All he gets is the music and the banner ad at the top of the screen and nothing else.
Unfortunately I don't have an HTC 1X+ to test this on.
Some notes:
Although my textures are not power of 2, I'm only using GLES20.GL_CLAMP_TO_EDGE
From what I've read, the HTC 1X+ has a max Texture Size of 2048 x 2048 and it gets it's resources from the XHDPI folder (annoyingly), even so, I have only 1 texure that exceeds that size, all other objects displayed on my app's opening page use textures much smaller than this max amount, so something should be displayed.
I'm not using texture compression of any kind
My app runs quite happily on the 15 (aprox) other devices I, and others have tested it on - just the 1x (so far) is giving problems.
Can anyone point out some common issues with OpenGL ES 2.0 that could be causing these textures not to be rendered? Are there any quirks with certain Android versions or devices?
I haven't yet posted any code simply because the app works on most devices, and I'm not sure which parts of the code would be helpful, but if any code is required, please just ask.
Edit - including texture loading code
public static int LoadTexture(GLSurfaceView view, Bitmap imgTex){
//Array for texture
int textures[] = new int[1];
try {
//texture name
GLES20.glGenTextures(1, textures, 0);
//Bind textures
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
//Set parameters for texture
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
//Apply texture
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, imgTex, 0);
//clamp texture
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
} catch (Exception e){
}
//Increase texture count
textureCount++;
//Return texture
return textures[0];
}
Have you checked the sampler properties?
The settings look correct, but why not also specify the GL_TEXTURE_WRAP_S setting? Use GLES20.glTexParameteri for integer values.
What type of bitmap are you using?
Try to force the internal format to GL_RGBA, GL_BGR, GL_RGB
Do you properly unbind or bind to a different texture?
Other texture settings may be causing havoc in other parts of the code..
Do you specify the correct texture unit in your shader?
Print out the shader's sampler attribute position so you know this is correct, and make sure to bind the texture to it explicitly during rendering.

Android opengl texture corruption

I am having problems with texture corruption on Android emulator (it runs fine on most android devices).
The picture above is a reference rendering produced by emulator running Android 4.1 Jelly Bean, everything looks as it should.
The second picture is captured in emulator running Android 1.6. Note the corruption of some of the disabled toolbar buttons (they are rendered with color 1f,1f,1f,0.5f)
The third picture is captured in the same emulator. The difference is that now score is rendered in the upper-right corner. Score is a bitmap font, it's texture is an alpha mask. Everything rendered after the score looses it's texture. Note that the previous screenshot also contained bitmap font rendered the same way (but using different texture).
A similar problem was present on one of the Samsung devices (I don't remember the model). When the floor texture was rendered, everything rendered after that lost texture. The problem did not manifest itself when I either a) did not bind the texture b) did bind the texture, but drew no triangles using it c) recreated the png asset from scratch.
Opengl settings:
gl.glDisable(GL10.GL_LIGHTING);
gl.glDisable(GL10.GL_CULL_FACE);
gl.glDisable(GL10.GL_DEPTH_TEST);
gl.glDisable(GL10.GL_DITHER);
gl.glDepthMask(false);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glBlendFunc(GL10.GL_ONE,GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glShadeModel(GL10.GL_FLAT);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
How textures are loaded:
public void doGLLoading(Engine renderer) {
GL10 gl=renderer.getGl();
int[] ids=new int[1];
gl.glGenTextures(1, ids,0);
id=ids[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, id);
Log.d("SpriteDraw", String.format("Texture %s has format %s",getPath(),bitmap.getConfig().toString()));
buildMipmap(gl, bitmap);
gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER, minFilter);
gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER, magFilter);
gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_WRAP_S, textureWrapS);
gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_WRAP_T, textureWrapT);
}
private void buildMipmap(GL10 gl, Bitmap bitmap) {
int level = 0;
int height = bitmap.getHeight();
int width = bitmap.getWidth();
while (height >= 1 || width >= 1) {
// First of all, generate the texture from our bitmap and set it to
// the according level
//TextureUtils.texImage2D(gl, GL10.GL_TEXTURE_2D, level, -1, bitmap, -1, 0);
GLUtils.texImage2D(GL10.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);
// Clean up
bitmap.recycle();
bitmap = bitmap2;
}
}
Notes: the font is rendered using gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); and GL10.glDrawArrays. The corruption affects not only the 1.6 emulator, but also the 2.x series of android, althought it is not as prominent (the alpha masks are still rendered incorrectly). All assets are correctly loaded as power of two bitmaps.
I suggest using 32bit textures, not grayscale, not "alphamasks" (what's that?)
Check the size of your texture, it should not exceed maximum size ( glGetInteger( GL_MAX_TEXTURE_SIZE ). Also make shure your textures are power of 2. Yes, you mentioned before they are, but if they are in scalable assets (drawable_x_dpi folders), they will be scaled by android. To avoid scaling, put them to "raw" folder.
Just for test, try to disable all filtering, including mipmaps - set GL_TEXTURE_WRAP_S, and GL_TEXTURE_WRAP_T to GL_NEAREST

Handling large bitmaps on Android - int[] larger than max heap size

I'm using very large bitmaps and I store data in a big int[]. The images can be really large and I can't downsample them (I'm getting the bitmaps over the wire and rendering them).
The problem I'm hitting is on very large bitmaps (bitmap size = 64MB), where I try to allocate int array with size 16384000. I'm testing this on Samsung Galaxy SII, which should have enough memory to handle this, but it seems there is a "cap" on heap size. The method Runtime.getRuntime().maxMemory() returns 64MB, so this is the max heap size for this particular device.
The API level is set to 10, so I can't use android:largeHeap attribute suggested elsewhere (and I don't even know if that would help).
Is there any way to allocate more than 64MB? I tried allocating the array in native (using JNI NewIntArray function), but that fails as well. It seems as though it is bound by the same limit as jvm.
I could however allocate memory on the native side using NewDirectByteBuffer, but since this byte buffer is not backed by an array, I can not get access to int[] (using asIntBuffer().array() in java which I need in order to display the image using setPixels or createBitmap. I guess OpenGL would be a way to go, but I have (so far) 0 experience with OpenGL.
Is there a way to somehow access allocated memory as int[] that I am missing?
So, the only way I've found so far is to allocate image using NDK. Furthermore, since Bitmap does not use existing Buffer as pixel "storage" (the method copyPixelsFromBuffer is also bound to memory limits; and judging by the method name, it copies the data anyway).
The solution (I've only prototyped it roughly) is to malloc whatever the size of the image is, and fill it using c/c++ and then use ByteBuffer in Java with OpenGLES.
The current prototype creates a simple plane and applies this image as a texture to it (luckily, OpenGLES methods take Buffer as input, which seems to work as expected). I'm using glTexImage2D to apply this buffer as a texture to a plane. Here is a sample, where mImageData is ByteBuffer allocated (and filled) on the native side.
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
mTextureId = textures[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, 4000, 4096, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, mImageData);
I assume OP already solved this, but if you have a Stream, you can stream the bitmap into a file and read that file using inSampleSize

Android: OpenGL textures too large, can't figure out why

Why do my textures seemingly take up so much space?
My app, which uses opengl heavily, produces the following heap stats* during operation:
Used heap dump 1.8 MB
Number of objects 49,447
Number of classes 2,257
Number of class loaders 4
Number of GC roots 8,551
Format hprof
JVM version
Time 1:08:15 AM GMT+02:00
Date Oct 2, 2011
Identifier size 32-bit
But, when I use the task manager on my phone to look at the ram use of my application it says my app uses 44.42MB. Is there any relationship between heap size use and ram use? I think much of that 42MB must be my open GL textures, but I can't figure out why they take up so much space, because on disk all the files together take only take up 24MB (and they are not all loaded at the same time). And I'm even making many of them smaller by resizing the bitmap prior to texture loading. I also dynamically create some textures, but also destroy those textures after use.
I am using OpenGL 1.0 and Android 2.2, typical code that I use to load a texture looks like this:
static int set_gl_texture(Bitmap bitmap){
bitmap = Bitmap.createScaledBitmap(bitmap, 256, 256, true);
// generate one texture pointer
mGL.glGenTextures(1, mTextures, 0);
mGL.glBindTexture(GL10.GL_TEXTURE_2D, mTextures[0]); // A bound texture is
// an active texture
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0,GL10.GL_RGBA, bitmap, 0);
// create nearest filtered texture
mGL.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_LINEAR); // This is where the scaling algorithms are
mGL.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR); // This is where the scaling algorithms are
mGL.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE);
mGL.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
GL10.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
Log.v("GLSurfaceView", "Loading Texture Finished, Error Codes:"+mGL.glGetError());
return mTextures[0];
}
Code which I use to load bitmaps looks like the following:
public int load_texture(int res_id){
if(mBitmapOpts==null){
mBitmapOpts = new BitmapFactory.Options();
mBitmapOpts.inScaled = false;
}
mBtoLoad = BitmapFactory.decodeResource(MyApplicationObject.getContext().getResources(),res_id, mBitmapOpts);
assert mBtoLoad != null;
return GraphicsOperations.set_gl_texture(mBtoLoad);
}
*hprof file analyzed using mat, same data is generated by eclipse ddms
PNGs are compressed images. In order for OpenGL to use them, the pngs must be decompressed. This decompression will increase the memory size.
You may want to decrease the size of some of the textures somehow. Maybe instead of using 512x512 images, use 256x256 or 128x128. Some textures that you use may not need to be so large since they are going onto a mobile device with a limited screen size.

Categories

Resources