I am building an android opengl es 2.0 application. I am drawing squares in a circle, and with the user's movements left and right I am moving the squares. I am applying textures on the squares and keep getting this error:
2-19 16:08:25.666: E/Adreno200-EGL(8183): eglLockWindowSurface: failed to map the memory
for fd=42 offs=6352896
I think that it has something to do with the textures. For loading the textures I use:
public static int loadTexture(final Context context, Bitmap bmp)
{
final int[] textureHandle = new int[1];
// GLES20.glDeleteTextures(1, textureHandle, 0);
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = bmp;
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
// bitmap.recycle();
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
Note: with bitmap.recycle() the app does not work.
Also I must say that the onDraw() method is always working and the renderer is NOT set to RENDER_WHEN_DIRTY. I assume that I am loading too many textures and not doing anything to the old ones, but I can't solve this problem for several days now. If someone has a solution, please let me know. I will deeply appreciate any advice or feedback. Thank u in advance!!!
Related
I have created a texture like this
public int createTexture(Bitmap bitmap){
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
return textureHandle[0];
}
Now based on the user input I want to update my Texture with the new Bitmap. I tried recalling same function with different Bitmap but its not getting updated. Am I doing something wrong here?
EDIT
I tried as Tommy said in his answer but no use. Let me elaborate how I am using textures.
public void changeFilter(){
//create required bitmap here
if(mTextureDataHandle1==0)
mTextureDataHandle1 =loadTexture(bitmap);
else
updateTexture(mTextureDataHandle1);
}
In onDrawFrame
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, mTextureDataHandle1);
glUniform1i(mTextureUniformHandle1, 1);
That method both creates a new texture and uploads a Bitmap to it. It sounds like you want to do the second thing but not the first? If so then provide the int texture name as a parameter rather than receiving it as a result, and skip straight to the glBindTexure (i.e. omit the glGenTextures, which is what creates the new texture).
E.g.
public int createTexture(Bitmap bitmap){
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
glBindTexture(GLES20.GL_TEXTURE_2D, textureName);
glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
updateTexture(textureHandle[0], bitmap);
return textureHandle[0];
}
public void updateTexture(int textureName, Bitmap bitmap) {
glBindTexture(GLES20.GL_TEXTURE_2D, textureName);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
}
So the bit where you upload a Bitmap is factored out from the bit where you create a texture and set its filtering type; to update an existing texture use the int you got earlier and call directly into updateTexture.
You may simply be not on the OpenGL rendering thread when changing the Bitmap. When you change the Bitmap, save in a boolean that you did so, and then only in the rendering thread call texImage2D.
I tried the techniques in the above responses I got horrible performance. If what you want is to update the texture live as in 60 fps there is a better way. BTW I didn't find documentation on it, I had to pull and pieces together from different sources.
(1) you have to tell OpenGL extensions to use external textures. That is when defining your texture instead of using GLES20.GL_TEXTURE0 you use GLES11Ext.GL_TEXTURE_EXTERNAL_OES
(2) you have to use the classes Surface and SurfaceTexture. (look into consumers and producers for more into. They work like a server/client but instead the architecture is called consumer/producer)
(3) You have to enable an extension on your fragment shader. You can't use sampler2D you have to use samplerExternalOES. To enable the extension you put the following line at the top of your shader code:
#extension GL_OES_EGL_image_external: require
Code snapshot
The above is a snapshot of my code, below is the fragment shader
Fragment shader
I will like to load textures during run time ( so I dont need to load all of the texture)
If I try to load a texture during run time with this function, I get the RunTimeException ( I think that is because the context is already created)
Is any way to do this without having 2 OpenlGL context(I read that this may cause error if the drivers are bad implemented)?
public static int loadTexture(final Context context, final int resourceId)
{
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
I haven't touched OpenGL ES in Java, only C++ but I would have thought this would be perfectly OK - are you trying to create this texture on a different thread to the thread you created the OpenGL context on? Did your OpenGL context creation code succeed?
I'm working on an android application which augment 3D model when image target is detected using vuforia SDK. Nine 3D model are augmented at a same time. I have loaded texture using GLES20.glGenTextures(1, textureHandle, 0) method. So I've called below method for nine times and store the integer value of texture id in integer array.
public static int loadTexture(Bitmap bitmap)
{
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
{
isaugmented1 = false;
android.graphics.Matrix matrix = new android.graphics.Matrix();
bitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap = null;
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
Now I want to delete that all nine texture, so I've called
GLES20.glDeleteTextures(1, temphandler, 0)
method in a loop as mentioned in below code. but as a result only last texture is deleted. I want to delete all texture which are stored.
public void deleteTexture()
{
if(mosaicHandler!=null){
if(mosaicHandler.length>0)
{
Log.e("deleting", "texture");
for(int i = 0; i<mosaicHandler.length;i++)
{
Log.e("deletingTexture", i+"");
int [] temphandler = new int[1];
temphandler[0] = mosaicHandler[i];
GLES20.glDeleteTextures(1, temphandler, 0);
}
}
}
}
Is there any other way to delete texture whose Id is stored in integer array?
To delete multiple textures at once, just follow the opengl api
https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteTextures.xml
I'm trying to load multiple textures in my Applikation. The Problem is that the second texture isnt displayed right.
This is how i get the Handels:
mTextureDataHandle = TextureHelper.loadTexture(mActivityContext, R.drawable.full_texture);
mTextureDataHandleError = TextureHelper.loadTexture(mActivityContext, R.drawable.full_texture_error);
using this Method:
public static int loadTexture(final Context context, final int resourceId)
{
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0 )
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
during the onDrawFrame method I use this to switch between Textures:
if (LessonFourActivity.error) {
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandleError);
GLES20.glUniform1i(mTextureUniformHandle, 1);
} else {
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
GLES20.glUniform1i(mTextureUniformHandle, 0);
}
The texture without the error works fine but when i switch to the error texture it's just black.
Does anyone know an answer to this?
I already found a few answers regarding GL10 but they didnt help me.
I am having problems rendering textures loaded from the assets folder. If I do exactly the same procedure loading the same texture from the resources folder, everything works fine. Also the image from the assets seems to be loading correctly as when I get the width and height property from the bitmap object, these correspond with the dimensions of the file on disk. However attempting to render the texture results in plain black.
// [...]
int [] tmpId = new int[1];
GLES20.glGenTextures(1, tmpId, 0);
int id = tmpId[0];
InputStream in = null;
try {
in = context.getAssets().open(resource);
}
catch (IOException e)
{
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeStream(in);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, id);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
bitmap.recycle();
Am I missing something, are there rules which apply to assets which are different from resources? I can´t seem to figure out why this isn´t working.
The image is 512x512 png format with transparency.
I'm not 100% sure as You didn't present the rest of the code, but basing on what You've shown it seems that You're unbinding the texture, which You want to draw, through glBindTexture call with the last parameter equal 0.