I have a problem with the rendering to texture in my Android based game (OpenGl ES2.0). I wasn't aware of the issue as on most devices this problem doesn't exists and everything is drawn just fine.
Regarding the screenshot attached below, the red bar on the left is drawn on the main framebuffer and because of that it is properly displayed. Everything else is rendered on off-screen texture which is then rendered on the main framebuffer.
I'm attaching the screenshot made on Samsung Galaxy Y S5360 (I'm not aware if this issue occur on other devices) as well as the code responsible for off-screen framebuffer/texture creation:
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[i]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_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_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebuffer[i]);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, texture[i], 0);
if(GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) != GLES20.GL_FRAMEBUFFER_COMPLETE) {
// ...
If I'm not mistaken, Samsung Galaxy Y S5360 has only OpenGL ES-CM 1.1 See http://geekprison.com/2163-samsung-galaxy-y-s5360-pricespecification-announced-for-india/
Related
When i render the cameraTexture to a low resolution SurfaceView, it looks pixelated.
Seems i need to generate mipmap for the camera texture, but it doesn't work this way.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glGenTextures(1, glTextures, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, glTextures[0]);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
mInputSurfaceTexture = new SurfaceTexture(inputTexture);
mInputSurfaceTexture.setDefaultBufferSize(CCamera.SIZE.getWidth(), CCamera.SIZE.getHeight());
mInputSurfaceTexture.setOnFrameAvailableListener(new CameraFrameListener(), mGLHandler);
mInputSurface = new Surface(mInputSurfaceTexture);
# feed mInputSurface to camera service.
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
surfaceTexture.updateTexImage();
GLES20.glGenerateMipmap(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
//GLES11Ext.glGenerateMipmapOES(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
}
BTW, that is the different of :
GLES11Ext.glGenerateMipmapOES
GLES20.glGenerateMipmap
You can't, at least not directly.
Implement an offscreen pass that converts the YUV to RGB to write an RGB image, and then mipmap that. If you know you only need the low resolution version, that YUV to RGB pass could also implement the initial 2:1 downsample to minimize the memory bandwidth overheads.
I've four types of texture.png for one 3d.obj file. How to change texture.png after 3d.obj was placed in the surface, like color changing functionality for ARCORE?
Does anyone have any idea?
You can change the texture of the object. Assuming you are looking at the hello_ar_java sample, you can add a method to ObjectRenderer:
public void setTextureOnGLThread(Bitmap textureBitmap) {
// Bind the texture name already allocated.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
// Set the filtering for handling different sizes to render.
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
// Copy the bitmap contents into the texture buffer.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, textureBitmap, 0);
// Generate the mip map for the different sizes.
GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
// Unbind the texture.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
You need to call this from the GL thread, for example from onDrawFrame().
I have a texture, bound to GL_TEXTURE_EXTERNAL_OES target
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
How can rebind it to GL_TEXTURE_2D target?
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); provides error
You can't. The texture target is a fundamental part of the texture object. If you have an external texture, you cannot treat it like a GL_TEXTURE_2D. At all.
This means if you want to bind it, you must bind it as a GL_TEXTURE_EXTERNAL_OES texture. If you want to use it in a sampler, that sampler must be of type samplerExternalOES rather than sampler2D (and your shader must enable the appropriate extension). And so forth.
I am displaying a video on a GLSurfaceView with a custom renderer that requires that multiple shaders be applied in succession. Currently, it is working successfully with one shader, though I am not sure how to extend the rendering pipeline to apply multiple shaders in succession.
I know that there are some examples concerning applying multiple shaders (using FrameBuffers and RenderBuffers), but I have not found any that deal with an image passed in through a SurfaceTexture.
There is a specific concern I would like to address:
A SurfaceTexture must be bound to a GL_TEXTURE_EXTERNAL_OES texture. On the other hand, a FrameBuffer cannot be bound to a GL_TEXTURE_EXTERNAL_OES texture (typically a GL_TEXTURE_2D is used), so is it even possible to use a FrameBuffer for a multi-pass render when the input texture is of a different format than the output? If not, what are the other options for performing a multi-pass render?
Below is some relevant code in the onSurfaceCreated function of the renderer I am trying to extend to perform multiple passes::
GLES20.glGenTextures(1, this.textureID, 0);
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, this.textureID[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(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_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
this.surfaceTexture = new SurfaceTexture(this.textureID[0]);
Below is some relevant code in the onDrawFrame function of that renderer:
synchronized (this) {
if (this.updateSurface) {
this.surfaceTexture.updateTexImage();
this.surfaceTexture.getTransformMatrix(this.stMatrix);
this.updateSurface = false;
}
}
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, this.textureID[0]);
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
//apply shader here and call glDrawArrays() at end
One way to approach this would be to use a SurfaceHolder rather than a SurfaceTexture.
From there, you can then get the Surface being held by the SurfaceHolder.
Then you can get the underlying Canvas being drawn to.
Note: Per this answer, you will need to use setBitmap(Bitmap canvas_bitmap) to specify the Bitmap being drawn into.
All the texture setup and parameter stuff will still need to be done basically the way you showed in you question.
GLES20.glGenTextures(1, this.textureID, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.textureID[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(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_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
Then dump the bitmap into a texture using:
GLUtils.texImage2D( GLES20.GL_TEXTURE_2D, 0, canvas_bitmap, 0 );
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.