Hy,
I'm developing an app on android and I'm in the testing phase and I'm trying it out on different devices. I developed the app on a nexus 7.
When I run it on a arm mali gpu device the rendered textrue starts to blink / lagg like crazy.
I use GLES20.GL_POINTS in the generated texture if I set the point size to 1 it blinks and it looks like there are artifacts in it, and if I set the point size to a bigger number like 10 it "laggs" meaning sometimes it shows a texture from a earlyer rendering.
Any idea what could cause this ?
private void setupRenderToTexture() {
fb = new int[1];
depthRb = new int[1];
renderTex = new int[2];
// generate
GLES20.glGenFramebuffers(1, fb, 0);
GLES20.glGenRenderbuffers(1, depthRb, 0);
GLES20.glGenTextures(1, renderTex, 0);
// create render buffer and bind 16-bit depth buffer
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRb[0]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, texW, texH);
}
This is my render to textue method:
private void createSmokeTexture() {
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[0]);
GLES20.glClearColor(0.48f, 0.48f, 0.48f, 0.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, renderTex[0], 0);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, depthRb[0]);
//background counts
renderscriptSmokeStep_involke();
GLES20.glUseProgram(mProgramSmoke);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramSmoke, "u_MVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramSmoke, "u_Move");
mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramSmoke, "u_Texture");
smokeParticleSizeUniformHandle = GLES20.glGetUniformLocation(mProgramSmoke, "u_PointSize");
maximumDensityHandler = GLES20.glGetUniformLocation(mProgramSmoke, "u_MaximumDensity");
cellDensityHandle = GLES20.glGetAttribLocation(mProgramSmoke, "a_Age");
smokeStartPositionHandle = GLES20.glGetAttribLocation(mProgramSmoke, "a_Position");
Matrix.setIdentityM(mMoveMatrix, 0);
Matrix.translateM(mMoveMatrix, 0, positionX, positionY, 0);
Matrix.multiplyMM(mMoveMatrix, 0, Render.mModelMatrix, 0, mMoveMatrix, 0);
GLES20.glUniform1f(smokeParticleSizeUniformHandle, PARTICLE_SIZE);
GLES20.glUniform1f(maximumDensityHandler, MAXIMUM_DENSITY);
GLES20.glUniform1i(mTextureUniformHandle, 0);
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMoveMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, Render.m2dProjectionMatrix, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, particlePosBuffer);
GLES20.glEnableVertexAttribArray(smokeStartPositionHandle);
GLES20.glVertexAttribPointer(smokeStartPositionHandle, 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glEnableVertexAttribArray(cellDensityHandle);
GLES20.glVertexAttribPointer(cellDensityHandle, 1, GLES20.GL_FLOAT, false, 0, cellDensity);
// Draw the point.
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, NUM_PARTICLES);
}
This gets called on draw:
public void draw(){
createSmokeTexture();
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
setTexture(renderTex[0]);
drawSmokeToScreen();
}
asdas
private void setTexture(int texture) {
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
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, texW, texH, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
}
And after this I draw it to the screen
private void drawSmokeToScreen() {
GLES20.glUseProgram(mProgramHandle);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_Move");
positionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
textureHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, Render.mModelMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, Render.m2dProjectionMatrix, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, fullDrawSurfice.getPositionDataIndex());
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, fullDrawSurfice.getTextureDataIndex());
GLES20.glEnableVertexAttribArray(textureHandle);
GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
}
It looks like there are a couple of problems with the ordering of your calls.
At the start of createSmokeTexture(), there is this code sequence:
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[0]);
GLES20.glClearColor(0.48f, 0.48f, 0.48f, 0.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
GLES20.GL_TEXTURE_2D, renderTex[0], 0);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,
GLES20.GL_RENDERBUFFER, depthRb[0]);
Here, the framebuffer is cleared before it is completely set up by attaching the render targets with the glFramebufferTexture2D() and glFramebufferRenderbuffer() calls. This is most likely only a problem for the first frame, because at least in the code shown here, the render targets are never un-attached again. After that, the calls are just redundant. It would be much better to attach the render targets during setup.
At the end of setTexture():
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, texW, texH, 0,
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
Based on the sequence in draw(), this is called after the FBO rendering completed, and before using the resulting texture to draw to the main framebuffer. However, this glTexImage2D() call basically wipes out the content of the texture that was produced by the FBO rendering.
To fix both of these problems, remove the glFramebufferTexture2D() and glFramebufferRenderbuffer() from the first code sequence, and all but the glActiveTexture() and glBindTexture() calls from setTexture(). All of these should go to setupRenderToTexture() function, which then becomes:
GLES20.glGenTextures(1, renderTex, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, renderTex[0]);
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, texW, texH, 0,
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
// create render buffer and bind 16-bit depth buffer
GLES20.glGenRenderbuffers(1, depthRb, 0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRb[0]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER,
GLES20.GL_DEPTH_COMPONENT16, texW, texH);
GLES20.glGenFramebuffers(1, fb, 0);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
GLES20.GL_TEXTURE_2D, renderTex[0], 0);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,
GLES20.GL_RENDERBUFFER, depthRb[0]);
Related
I am writing an app utilizing CameraX to capture the camera feed, OpenCV to modify the frames and the OpenGL to render them on a GLSurfaceView.
My current approach was to render the original frames from CameraX, construct a pixel buffer, an OpenCV Mat, use glReadPixels to copy the pixel buffer (ByteBuffer) into the Mat, then process it, write the pixel buffer from Mat back to the pixel buffer and then render it onto the texture with glTexSubImage2D.
The problem is, CameraX enables me to access the frame data via GL_TEXTURE_EXTERNAL_OES, which - as per OpenGL's documentation - does not allow for glTexSubImage2D to modify the texture and my current approach, using the code below, does not work and continously throws W/OpenGLRenderer: [SurfaceTexture-1-25873-0] bindTextureImage: clearing GL error: 0x500, which is expected as says the documentation. Is there an alternative way to copy the buffer into GL_TEXTURE_EXTERNAL_OES after OpenCV processing? Another thing I can think of is to copy the texture into GL_TEXTURE_2D and then use glTexSubImage2D, although I have no idea how to do that. Maybe someone knows another approach that would allow me to achieve the goal?
My code:
public void onDrawFrame(GL10 gl) {
GLES20.glClear( GLES20.GL_COLOR_BUFFER_BIT );
if(this.resolutionSet) {
surfaceTexture.updateTexImage();
GLES20.glUseProgram(hProgram);
int ph = GLES20.glGetAttribLocation(hProgram, "vPosition");
int tch = GLES20.glGetAttribLocation(hProgram, "vTexCoord");
int th = GLES20.glGetUniformLocation(hProgram, "sTexture");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, hTex[0]);
GLES20.glUniform1i(th, 0);
GLES20.glVertexAttribPointer(ph, 2, GLES20.GL_FLOAT, false, 4 * 2, pVertex);
GLES20.glVertexAttribPointer(tch, 2, GLES20.GL_FLOAT, false, 4 * 2, pTexCoord);
GLES20.glEnableVertexAttribArray(ph);
GLES20.glEnableVertexAttribArray(tch);
GLES20.glReadPixels(0, 0, this.img.cols(), this.img.rows(), GL_RGBA, GL_UNSIGNED_BYTE, this.imgBuff);
img.put(0, 0, this.imgBuff.array());
Log.d(LOG_TAG, img.toString());
Imgproc.cvtColor(img, img, Imgproc.COLOR_RGBA2BGRA);
Imgproc.cvtColor(img, img, Imgproc.COLOR_BGRA2GRAY);
this.imgBuff.clear();
img.get(0, 0, this.imgBuff.array());
GLES20.glTexImage2D(GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
GLES20.glTexSubImage2D(GL_TEXTURE_EXTERNAL_OES, 0, 0, 0, img.width(), img.height(), GL_RGBA, GL_UNSIGNED_BYTE, this.imgBuff);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
GLES20.glFlush();
}
and the code initializing texture:
hTex = new int[1];
GLES20.glGenTextures ( 1, hTex, 0 );
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, hTex[0]);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
Given you are replacing the entire image and uploading "normal" RGBA data from the application, why does this need to be a GL_TEXTURE_EXTERNAL_OES type at all? Just use a normal GL_TEXTURE_2D.
I have been request texture id and It has been display ,but now i want to update what have been display ,for example
private void initTexture(){
int textureIds[] = new int[1];
// 启用纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glGenTextures(1, textureIds, 0);
// 将绑定纹理(texuture[0]表示指针指向纹理数据的初始位置)
mTextureID = textureIds[0];
}
public void freshTexture(){
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_NEAREST);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D,0,mLayerDrawable.getBitmap(),0);
onFreshView();
}
protected void doDraw() {
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT|GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(163,156,158,255);
mGL20Factory.useProgram();
MatrixState.setInitStack();
MatrixState.transtate(mScreenPosition.getMoveX(mMoveX),mScreenPosition.getMoveY(mMoveY),0);
MatrixState.scale(mScale,mScale,0);
//将最终变换矩阵传入shader程序
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrixMM(), 0);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
GLES20.glVertexAttribPointer(mAttribPosition, 3, GLES20.GL_FLOAT, false, 0, mVerticeBuf);
GLES20.glVertexAttribPointer(mAttribTexCoord, 2, GLES20.GL_FLOAT, false, 0, mTextureCoodBuf);
GLES20.glEnableVertexAttribArray(mAttribPosition);
GLES20.glEnableVertexAttribArray(mAttribTexCoord);
//绑定纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDisableVertexAttribArray(mAttribPosition);
GLES20.glDisableVertexAttribArray(mAttribTexCoord);
}
other way,I use GLUtils.texSubImage2D() method ,but its not used,
I develop video app on Android and use OpenGL for render and filtering video from camera via shaders. One of my shaders use two textures - one is live frame from camera and another is the previous render pass result. So I need to render picture twice - to screen for preview and to separate Texture for next render pass. To achieve it I use Frame Buffer object. Here is my code:
For init frame buffer:
private void initPredrawBuffer() {
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
prevBuffer = new int[1];
GLES20.glGenFramebuffers(1, prevBuffer, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, prevBuffer[0]);
prevTexture = new int[1];
GLES20.glGenTextures(1, prevTexture, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, prevTexture[0]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_NEAREST);
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.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, mFrameWidth, mFrameHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, prevTexture[0], 0);
int[] depthRenderbuffers = new int[1];
GLES20.glGenRenderbuffers(1, depthRenderbuffers, 0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRenderbuffers[0]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, mFrameWidth, mFrameHeight);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, depthRenderbuffers[0]);
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException("Incomplete buffer");
}
}
and for render:
private void draw(boolean offScreen, float[] mvpMatrix, FloatBuffer vertexBuffer, int firstVertex,
int vertexCount, int coordsPerVertex, int vertexStride,
float[] texMatrix, FloatBuffer texBuffer, int textureId, int texStride) {
GlUtil.checkGlError("draw start");
if (offScreen)
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, prevBuffer[0]);
else
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
// Select the program.
GLES20.glUseProgram(firstFrame && firstFrameProgram > 0 ? firstFrameProgram : mProgramHandle);
GlUtil.checkGlError("glUseProgram");
// Set the texture.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
// Copy the model / view / projection matrix over.
GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mvpMatrix, 0);
GlUtil.checkGlError("glUniformMatrix4fv");
// Copy the texture transformation matrix over.
GLES20.glUniformMatrix4fv(muTexMatrixLoc, 1, false, texMatrix, 0);
GlUtil.checkGlError("glUniformMatrix4fv");
// Enable the "aPosition" vertex attribute.
GLES20.glEnableVertexAttribArray(maPositionLoc);
GlUtil.checkGlError("glEnableVertexAttribArray");
// Connect vertexBuffer to "aPosition".
GLES20.glVertexAttribPointer(maPositionLoc, coordsPerVertex,
GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
GlUtil.checkGlError("glVertexAttribPointer");
// Enable the "aTextureCoord" vertex attribute.
GLES20.glEnableVertexAttribArray(maTextureCoordLoc);
GlUtil.checkGlError("glEnableVertexAttribArray");
// Connect texBuffer to "aTextureCoord".
GLES20.glVertexAttribPointer(maTextureCoordLoc, 2,
GLES20.GL_FLOAT, false, texStride, texBuffer);
GlUtil.checkGlError("glVertexAttribPointer");
// Setting Light Trails filter params
if (mProgramType == ProgramType.TEXTURE_LIGHT_TRAILS && !firstFrame) {
GLES20.glUniform1i(muTextureNew, 0);
GlUtil.checkGlError("glUniform1i muTextureNew");
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GlUtil.checkGlError("temp glActiveTexture");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, prevTexture[0]);
GlUtil.checkGlError("temp glBindTexture");
GLES20.glUniform1i(muTexturePrev, 1);
GlUtil.checkGlError("glUniform1i muTexturePrev");
GLES20.glUniform1f(muLightTrailsExposure, lightTrailsKernel[0]);
GlUtil.checkGlError("glUniform1f muLightTrailsExposure");
GLES20.glUniform1f(muLightTrailsEcho, lightTrailsKernel[1]);
GlUtil.checkGlError("glUniform1f muLightTrailsEcho");
GLES20.glUniform1f(muLightTrailsLimit, lightTrailsKernel[2]);
GlUtil.checkGlError("glUniform1f muLightTrailsLimit");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GlUtil.checkGlError("temp glActiveTexture");
}
// Draw the rect.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, firstVertex, vertexCount);
GlUtil.checkGlError("glDrawArrays");
GLES20.glFinish();
}
The problem is that render to frame buffer not working, and glReadPixels always return an empty array. Render to screen works fine.
This is just to share something that took me a long time to figure out. If you don't need your Depthbuffer or don't have a Depth Buffer Attachment Point setup in EGL this might help.
For some reason I couldn't get rendering to texture to work setting the render buffer object RBO to depth buffer: like so
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
juliaTex[0], 0);
rain.checkGlError("glFramebufferTexture2D");
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER,
GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER,
juliaRBO[0]);
rain.checkGlError("glFramebufferRenderbuffer");
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
Causes error status == GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
If I change render buffer storage to GLES20.GL_RGBA4, as opposed to GLES20.DEPTH_COMPONENT16 and change GLES20.GL_DEPTH_ATTACHMENT to GLES20.GL_COLOR_ATTACHMENT0 then the error goes away,
Change this
// create render buffer and bind 16-bit depth buffer
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, juliaRBO[0]);
rain.checkGlError("glBindRenderBuffer");
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.DEPTH_COMPONENT16,
rain.width, rain.height);
to this
// create render buffer and bind 16-bit depth buffer
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, juliaRBO[0]);
rain.checkGlError("glBindRenderBuffer");
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_RGBA4,
rain.width, rain.height);
And the original code to this:
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
juliaTex[0], 0);
rain.checkGlError("glFramebufferTexture2D");
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_RENDERBUFFER,
juliaRBO[0]);
rain.checkGlError("glFramebufferRenderbuffer");
then status == GLES20.GL_FRAMEBUFFER_COMPLETE
But the texture is empty.
here is the call to create storage texture
// bind texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, juliaTex[0]);
// clamp texture to edges
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);
rain.checkGlError("glTexParameter JuliaTex");
// create it
/*
int[] buf = new int[rain.width * rain.height];
juliaTexBuff = ByteBuffer.allocateDirect(buf.length
* rain.FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asIntBuffer();
*/
// generate the textures
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,
rain.width, rain.height, 0, GLES20.GL_RGBA,
GLES20.GL_UNSIGNED_SHORT_4_4_4_4, null);
To get this to work in addition to attaching the render buffer to the color attachment point I swapped the order of the Framebuffer attachments:
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_RENDERBUFFER,
juliaRBO[0]);
rain.checkGlError("glFramebufferRenderbuffer");
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
juliaTex[0], 0);
rain.checkGlError("glFramebufferTexture2D");
So that Texture2D is attached to the Framebuffer color layer after Renderbuffer. I assume the last connection point is the point OpenGL ES uses.
I am rendering to a frame buffer, and then I want to use that as a texture.
I can save the frame buffer to a file using glReadPixels so I am sure that I am rendering OK.
I can bind to fixed texture and render that OK.
But I cannot bind to the frame buffer to render that in place of the fixed texture.
//setup:
private void setupRenderToTexture() {
fb = new int[numberOfBuffers];
depthRb = new int[numberOfBuffers];
renderTex = new int[numberOfBuffers];
texBuffer = new IntBuffer[numberOfBuffers];
// generate
GLES20.glGenFramebuffers(fb.length, fb, 0);
GLES20.glGenRenderbuffers(depthRb.length, depthRb, 0);
GLES20.glGenTextures(renderTex.length, renderTex, 0);
GLErrorHandler.checkGlError("glGenFramebuffers");
for (int i = 0; i < fb.length; i++) {
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[i]);
// generate color texture
GLState.Instance.bindTexture(0, renderTex[i]);
// parameters
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
// GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
// GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
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);
// create it
// create an empty intbuffer first?
int[] fileData = new int[width * height];
texBuffer[i] = IntBuffer.wrap(fileData);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width,
height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,
texBuffer[i]);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
renderTex[i], 0);
// create render buffer and bind 16-bit depth buffer
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRb[i]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER,
GLES20.GL_DEPTH_COMPONENT16, width, height);
GLErrorHandler.checkGlError("glRenderbufferStorage or above");
}
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
}
Use the frame buffer:
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[0]);
Save the frame buffer (for testing):
GLES20.glReadPixels(sourceX, sourceY, width, height, GL10.GL_RGBA,
GL10.GL_UNSIGNED_BYTE, ib);
Then to render to screen:
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[0]);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture); //some simple texture works but:
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, renderTex[0]); //frame buffer texture does not work
All I get is a black screen if I bind to renderTex[0]
You are mis-using the FBO. You have to attach an empty texture so that it can render into it.
See this page