Alright I made an application that uses a FBO to render to a texture and later uses this texture to display it on a quad.
That's the code I am using to initialize the FBO and the texture:
IntBuffer intBuffer = IntBuffer.allocate(1);
GLES20.glGenFramebuffers(1, intBuffer);
fbo = intBuffer.get(0);
GLES20.glGenTextures(1, intBuffer);
tex = intBuffer.get(0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, tex, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
(1. code in onDrawFrame())
The problem is that I don't know where to put the code, so at first I put the code in the onDrawFrame() method. When I do that the texturing works fine and I get the result that I want. But since I am creating a new FBO and texture every frame, after some time The application starts to lag and at the end the emulator crashes.
(2. code in onSurfaceChanged())
After noticing that behaviour I decided to put the code in the onSurfaceChanged() method. This time the application didn't crash but the entire texture is black. I tried to clear the texture or draw a white quad over it but nothing worked. And when I try to get an error from GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) or GLES20.glGetError() it says that everything is fine.
I also tried to put the code in the onDrawFrame() method surrounded with a if-clause so that it's only executed once. The result is also the black texture.
(3. code in onDrawFrame() and onSurfaceChanged())
The last thing I tried was to put the code in both methods. I wanted to reduce the code in the onDrawFrame() method until I find the codeline that makes the texture work fine. But when I started the application the quad flickered, changing from the black texture to the right texture.
There is no problem with the texture displaying since it works with the one method. I also tried to add a depth-buffer to the code but the result is the same. So since I don't need it in my application I commented it out.
Is there anyone who can say what's going on? If someone has a application that works but doesn't know what's the problem with mine it would be nice if that person could upload the project because I didn't find a tutorial that has a android project up for download.
Alright thanks to Rabbid76 for giving me a checklist to find my problem. I tried to use the fbo as a texture. This is the right binding: GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex). In the tutorial I have read the FBO was also bound. I still don't know why it works when I initialize the FBO in the onDrawFrame() method and use it then as texture.
Related
I can't get the texture tied to a SurfaceTexture to display in Unity.
Update 4: Based on the pipeline in update 1 (surface->external texture via surface texture -> fbo -> texture 2d) I know the SurfaceTexture isn't properly converting its surface to a texture. I can get correctly drawn pictures from its surface via pixelcopy and I can confirm my FBO drawing to texture2d pipeline works with some test colors. So the question is, why can't the SurfaceTexture convert its surface to a texture?
I generate a Texture in Java and pass its pointer back to Unity:
public void initGLTexture()
{
Log.d("Unity", "initGLTexture");
int textures[] = new int[1];
GLES20.glGenTextures(1, textures, 0);
mTextureId = textures[0];
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureId);
GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
I create a SurfaceTexture from the id (in Java):
mSurfaceTexture = new SurfaceTexture(mTextureId);
mSurfaceTexture.setDefaultBufferSize(512, 512);
I use a third-party library, GeckoView, to render onto the Surface of the SurfaceTexture. I call the following method from Unity's OnRenderObject() to keep all GL rendering on the same thread:
mSurfaceTexture.updateTexImage();
I know the above code allows proper drawing onto the surface.
I call the following in Unity to load the texture:
_imageTexture2D = Texture2D.CreateExternalTexture(
512,512,TextureFormat.RGBA32,false,true,(IntPtr) mTextureId);
_rawImage.texture = _imageTexture2D;
Why does the RawImage with the texture applied show only this sprite-looking thing, which should be a webpage?
Update 1: So I've been working on the hypothesis of: use Gecko to draw to the Surface, and use a SurfaceTexture to render this surface to a GL_TEXTURE_EXTERNAL_OES. Since I can't display this on Unity (not sure why) I am drawing this texture to a frame buffer and copying the pixels in the framebuffer to a GL_TEXTURE_2D. I am getting a web page in the texture_2d (in the emulator with an imageview and glReadPixels). However, when I import the work into Unity to test if the pipeline is okay thus far I just get a black screen. I CAN get images of the surface via the PixelCopy api.
Here is my FBO overview code - my rendering code comes from grafika's texture2D program:
// bind display buffer
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBufferId);
GlUtil.checkGlError("glbindframebuffer");
// unbind external texture to make sure it's fresh
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
GlUtil.checkGlError("glunbindexternaltex");
// bind source texture (done in drawFrame as well )
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mOffscreenTextureId);
GlUtil.checkGlError("glBindFramebuffer");
// draw to frame buffer
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // again, only really need to
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); // clear pixels outside rect
mFullScreen.drawFrame(mOffscreenTextureId, mIdentityMatrix);
// unbind source texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
GlUtil.checkGlError("glBindTexture2d");
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
GlUtil.checkGlError("glunbindexternaltex");
// make sure we're still bound to fbo
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBufferId);
GlUtil.checkGlError("glBindTexture2d");
// copy pixels from frame buffer to display texture
GLES20.glCopyTexImage2D(GLES20.GL_TEXTURE_2D,0,GLES20.GL_RGBA,0,0,512,512,0);
// read pixels from the display buffer to imageview for debugging
BitmapDisplay.mBitmap = SavePixels(0,0,512,512);
// unbind texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
Here's my player settings > other:
Update 2: Possible pipeline to try: call the draw function of the external texture to FBO (attached to Unity's texture_2d) in C++ via this interface.
Update 3: Calling the Java functions from native code that are responsible for drawing the texture from the SurfaceTexture to the FBO to Unity's texture via the GL.IssuePluginEvent produce a black texture as in the first update. It will show images in the emulator but not in Unity.
I had to do a similar task a couple of months ago and found out that the correct pipeline is creating a texture in Unity, obtaining a native pointer in C and finally updating it in the Java layer.
Please take a look at this sample project, it should give you a different perspective.
https://github.com/robsondepaula/unity-android-native-camera
Regards
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.
I'm using RenderBuffer and OpenGL instead of Canvas and Bitmap on Android Java. However, drawing to a texture takes time. I referred to this question and tried speed improvement (Reduces the call of glEnableVertexAttribArray, glClearColor, glBindFramebuffer), but it's ineffective. Is this limitations of GPU and Android OS?
*This is an extract of the program.
GLES20.glAttachShader(program, vertex);
GLES20.glAttachShader(program, fragment);
GLES20.glLinkProgram(program);
GLES20.glUseProgram(program);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[i]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
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_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, s, s,
0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbs[i]);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textures[i], 0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renders[i]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, s, s);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER,
GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, renders[i]);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbs[i]);
GLES20.glClearColor(fr, fg, fb, fa);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glGetIntegerv(GLES20.GL_FRAMEBUFFER_BINDING, old, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbs[pos]);
GLES20.glViewport(0, 0, ww, hh);
:
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
:
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, old[0]);
GLES20.glViewport(0, 0, scw, sch);
If, as I understand, you use all the code you pasted each time you need to draw something, it's not a surprise that your program is running slow.
OpenGL (wheter ES or not) is based on a "state machine" model: the OpenGL context retains the changes you make to it (using the various glXXX commands), and modify the way OpenGL will react to future commands (most notably to the ones you use for drawing).
This means that when you issue the command:
GLES20.glClearColor(fr, fg, fb, fa);
what you are really doing is set the
GL_COLOR_CLEAR_VALUE
variable inside the state machine to [fr, fg, fb, fa]. From that moment on, GL_COLOR_CLEAR_VALUE is already set to [fr, fg, fb, fa], and every extra call to glClearColor with the same arguments will change nothing in the machine.
OpenGL ES 2.0 glClearColor reference page
Why am I going into this? Because OpenGL state changes are performance critical (and some are more than others): changing the state of the context has a performance hit that often goes beyond a simple variable assignment, as it may require OpenGL to "talk" to the GPU, discard caches and whatnot. It's a necessary evil when done in a setup stage, but frequent changes might have a huge performance hit when done every frame.
Therefore the first thing you should do is to minimize the sheer number of glXXX command per second in your program by creating an initialization method and a drawframe method.
The standard approach is to use the GLSurfaceView.Renderer class
Android GLSurfaceView.Renderer class reference
cram all initialization commands into
public abstract void onSurfaceCreated (GL10 gl, EGLConfig config)
and
public abstract void onSurfaceChanged (GL10 gl, int width, int height)
and put in the method:
public abstract void onDrawFrame (GL10 gl)
the least possible amount of OpenGL commands (just what you need to actually draw stuff)
Leaving the theory aside and going into the specific, here is a list of optimizations I would suggest you to consider:
if you are using a single program, leave the whole:
GLES20.glAttachShader(program, vertex);
GLES20.glAttachShader(program, fragment);
GLES20.glLinkProgram(program);
GLES20.glUseProgram(program);
block in the setup section (and even if you don't, just switch between programs with glUseProgram: you don't have to link it over and over again!). glLinkProgram is likely to have a big performance hit!
texture initialization goes in the setup (on top of the "state change" thing you are actually moving the same very data from CPU memory to GPU memory over and over again, each frame)
framebuffer initialization (with all the renderbuffer creation and binding) goes in setup as well. Besides, why do you need multiple framebuffers anyway? :)
glViewport goes in the onSurfaceChanged method
it seems to me that you are using different framebuffers to draw different objects: I'm not sure of what you are trying to accomplish, but I'd suggest you to change strategy: draw to the whole screen and on the same buffer, unless you have a very good reason to do otherwise.
Last but not least, here is a good book on the topic:
OpenGL ES 2.0 Programming Guide
it's both a good introduction to OpenGL ES 2.0 and a nice introduction to OpenGL in general (I don't get a cut on their sales ;-) )
Hope it helps
I am programming an Android 2d game using opengl es 2.0. After I draw my sprites to the backbuffer I draw lights to a FBO and try to blend it to the back buffer again.
When I draw the FBO to the framebuffer, even trasparent without any color, the framerates drops from 60 to 30 on a Samsung Galaxy w (it has an adreno 205 as gpu). I searched everywhere and tried everything, even if I draw a single sprite on the scene and blend a trasparent FBO texture to the screen the framerate drops. I tried other games with lighting effects on that phone and they run fine, almost every game is fine on that phone, I believe they use the framebuffer as well.
On the Galaxy SII (mali 400 gpu) runs fine, I am quite new to opengl so I believe I am making a mistake somewhere, I share my code.
// Create a framebuffer and renderbuffer
GLES20.glGenFramebuffers(1, fb, offset);
GLES20.glGenRenderbuffers(1, depthRb, offset);
// Create a texture to hold the frame buffer
GLES20.glGenTextures(1, renderTex, offset);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, renderTex[offset]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,
screenWidth, screenHeight, 0,
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,
null);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
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_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
//bind renderbuffer
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRb[offset]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16,
screenWidth, screenHeight);
// bind the framebuffer
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[offset]);
// specify texture as color attachment
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
GLES20.GL_TEXTURE_2D, renderTex[offset], 0);
// specify depth_renderbufer as depth attachment
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,
GLES20.GL_RENDERBUFFER, depthRb[0]);
// Check FBO status.
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
if ( status == GLES20.GL_FRAMEBUFFER_COMPLETE )
{
Log.d("GLGame framebuffer creation", "Framebuffer complete");
}
// set default framebuffer
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
I do this once on surface creation. Not sure if is correct. I keep the texture and framebuffer ids to switch to them when I need.
My drawing code:
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
ShaderProgram program = glgame.getProgram();
//put vertices in the floatbuffer
mTriangleVertices.put(vertices, 0, len);
mTriangleVertices.flip();
GLES20.glVertexAttribPointer(program.POSITION_LOCATION, 2, GLES20.GL_FLOAT, false,
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
//preparing parameter for texture position
mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
GLES20.glEnableVertexAttribArray(program.POSITION_LOCATION);
//preparing parameter for texture coords
GLES20.glVertexAttribPointer(program.TEXTURECOORD_LOCATION, 2, GLES20.GL_FLOAT,
false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES,
mTriangleVertices);
//set projection matrix
GLES20.glEnableVertexAttribArray(program.TEXTURECOORD_LOCATION);
GLES20.glUniformMatrix4fv(program.MATRIX_LOCATION, 1, false, matrix, 0);
//draw triangle with indices to form a rectangle
GLES20.glDrawElements(GLES20.GL_TRIANGLES, numSprites * 6, GLES20.GL_UNSIGNED_SHORT,
indicesbuf);
//clear buffers
mTriangleVertices.clear();
mVertexColors.clear();
Everything is rendered on screen correctly, but the performance are ruined just when I draw the FBO texture.
Thank you very much for your help. I worked very hard on this and didn't find a solution.
According to qualcomm docs, you need to glclear after every glbindframebuffer, this is a problem related to tiled architecture, if you are switching framebuffers, data need to get copied from fastmem to normal memory to save current framebuffer and from slowmem to fast mem to get contents of newly binded frame, in case you are clearing just after glbind no data is copied from slowmem to fastmem and you are saving time, but you need to redesign your render pipeline often, so it will avoid reading data back and forth between slow and fast memory, so try to do glclear after each bind and it should help, you can also use adreno profiler to get additional information about problematic calls, but i doubt it will help with adreno200 i am trying to get two buffers for blur and i am ending with 10fps, bindframebuffer call can take up to 20msec if its not cleared, if it is it should end at 2ms.
I am building a simple live wallpaper for Android. I am uploading the required texture into OpenGL ES 2.0 using the below code. I have loaded all my images into a single file of size 2048x2048. This below code takes about 900 to 1200 ms to load the texture. Is this a normal time or am I doing something wrong to make it slow?
I also try to clear the list of textures in Opengl every time the onSurfaceCreated is called in my renderer. Is this right to be done, or is there a way to simple check if the previously loaded texture is already in memory and if so avoid clearing and reloading? Please let me know your comments on this. Thank you.
Also on screen orientation change the OnSurfaceCreated is called. So the texture upload happens again. This is not a good idea. What is the work around?
public int addTexture(Bitmap texture) {
int bitmapFormat = texture.getConfig() == Config.ARGB_8888 ? GLES20.GL_RGBA : GLES20.GL_RGB;
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
int textureId = textures[0];
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmapFormat, texture, 0);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
return textureId;
}
A few ways you can improve performance.
Do not load the texture every time onSurfaceChanged is called. Initialize your textureId to -1 (in the constructor/surfaceCreated of your renderer) and check at the beginning of onSurfaceChanged if you have a different Id. When you call glGenTextures, you will get a positive number.
Do you need the Mipmaps? That might be the key point of your method here. Try without the line GLES20.glGenerateMipMap(GLES20.GL_TEXTURE_2D);
2048x2048 is huge. Especially for textures. Do you really need that much detail? Maybe 1024x1024 is enough.
Avoid RGB_888, use RGB_565 instead: you'll get almost the same visual quality for half the size.