How to read data from a specific buffer using glreadpixels based on GLES30 on Android

As I understand it, from GLES30 there is no more gl_FragColor buffer (I saw it HERE )

Since I cannot read "Special Variables", how can I read the "output" buffer?

This is my code:

 private static final String FRAGMENT_SHADER = "#version 300 es\n"+ "#extension GL_OES_EGL_image_external_essl3 : require\n" + "precision mediump float;\n" + // highp here doesn't seem to matter "in vec2 vTextureCoord;\n" + "uniform sampler2D sTexture;\n" + "out vec4 fragColor ;\n" + "void main() {\n" + " vec4 tc = texture(sTexture, vTextureCoord);\n" + " fragColor.r = tc.r * 0.3 + tc.g * 0.59 + tc.b * 0.11;\n" + " fragColor.g = tc.r * 0.3 + tc.g * 0.59 + tc.b * 0.11;\n" + " fragColor.b = tc.r * 0.3 + tc.g * 0.59 + tc.b * 0.11;\n" + "}\n"; 

Here I tried to read the data:

  ByteBuffer mPixelBuf = ByteBuffer.allocateDirect(mWidth * mHeight * 4); mPixelBuf.order(ByteOrder.LITTLE_ENDIAN); GLES30.glReadPixels(startX, startY, frameWidth, frameHeight, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, mPixelBuf); 

There are no gl errors in the code.

The output of mPixelBuf only zeros.

How can I make sure fragColor reading?

thanks

Update1- Full texture rendering code:

 package com.MES.YOtm.AnalyzingAdapter; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import android.graphics.SurfaceTexture; import android.opengl.GLES11Ext; import android.opengl.GLES30; import android.opengl.Matrix; import android.util.Log; /** * Code for rendering a texture onto a surface using OpenGL ES 2.0. */ public class STextureRender { private static final String TAG = "Myopengl"; private int zoom; private static final int FLOAT_SIZE_BYTES = 4; private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; private final float[] mTriangleVerticesData = { // X, Y, Z, U, V -1.0f, -1.0f, 0, 0.f, 0.f, 1.0f, -1.0f, 0, 1.f, 0.f, -1.0f, 1.0f, 0, 0.f, 1.f, 1.0f, 1.0f, 0, 1.f, 1.f, }; private FloatBuffer mTriangleVertices; private static final String VERTEX_SHADER = "#version 300 es\n"+ "uniform mat4 uMVPMatrix;\n" + "uniform mat4 uSTMatrix;\n" + "in vec4 aPosition;\n" + "in vec4 aTextureCoord;\n" + "out vec2 vTextureCoord;\n" + "void main() {\n" + " gl_Position = uMVPMatrix * aPosition;\n" + " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" + "}\n"; //Smapler2D private static final String FRAGMENT_SHADER = "#version 300 es\n"+ "#extension GL_OES_EGL_image_external_essl3 : require\n" + "precision mediump float;\n" + // highp here doesn't seem to matter "in vec2 vTextureCoord;\n" + "uniform mediump sampler2D sTexture;\n" + "layout(location = 0) out mediump vec4 fragColor ;\n" + "void main() {\n" + " vec4 tc = texture(sTexture, vTextureCoord);\n" + " fragColor.r = tc.r * 0.3 + tc.g * 0.59 + tc.b * 0.11;\n" + " fragColor.g = tc.r * 0.3 + tc.g * 0.59 + tc.b * 0.11;\n" + " fragColor.b = tc.r * 0.3 + tc.g * 0.59 + tc.b * 0.11;\n" + "}\n"; private float[] mMVPMatrix = new float[16]; private float[] mSTMatrix = new float[16]; private int mProgram; private int mTextureID = -12345; private int muMVPMatrixHandle; private int muSTMatrixHandle; private int maPositionHandle; private int maTextureHandle; public STextureRender(int _zoom) { Log.v("My Error", "Start STextureRender constructor"); try { mTriangleVertices = ByteBuffer.allocateDirect( mTriangleVerticesData.length * FLOAT_SIZE_BYTES) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mTriangleVertices.put(mTriangleVerticesData).position(0); Matrix.setIdentityM(mSTMatrix, 0); zoom = _zoom; } catch(Exception ex) { Log.v("My Error", "STextureRender Error = " + ex.toString()); } Log.v("My Error", "End STextureRender constructor"); } public int getTextureId() { return mTextureID; } /** * Draws the external texture in SurfaceTexture onto the current EGL surface. */ public void drawFrame(SurfaceTexture st, boolean invert) { checkGlError("onDrawFrame start"); try { st.getTransformMatrix(mSTMatrix); if (invert) { mSTMatrix[5] = -mSTMatrix[5]; mSTMatrix[13] = 1.0f - mSTMatrix[13]; } GLES30.glClearColor(0.0f, 1.0f, 0.0f, 1.0f); GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT); GLES30.glUseProgram(mProgram); checkGlError("glUseProgram"); GLES30.glActiveTexture(GLES30.GL_TEXTURE0); GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID); mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); GLES30.glVertexAttribPointer(maPositionHandle, 3, GLES30.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); checkGlError("glVertexAttribPointer maPosition"); GLES30.glEnableVertexAttribArray(maPositionHandle); checkGlError("glEnableVertexAttribArray maPositionHandle"); mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); GLES30.glVertexAttribPointer(maTextureHandle, 2, GLES30.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); checkGlError("glVertexAttribPointer maTextureHandle"); GLES30.glEnableVertexAttribArray(maTextureHandle); checkGlError("glEnableVertexAttribArray maTextureHandle"); Matrix.setIdentityM(mMVPMatrix, 0); GLES30.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0); GLES30.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0); GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4); checkGlError("glDrawArrays"); } catch(Exception ex) { Log.v("My Error", "drawFrame Error = " + ex.toString()); } } /** * Initializes GL state. Call this after the EGL surface has been created and made current. */ public void surfaceCreated() { try { mProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER); if (mProgram == 0) { throw new RuntimeException("failed creating program"); } maPositionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition"); checkGlError("glGetAttribLocation aPosition"); if (maPositionHandle == -1) { throw new RuntimeException("Could not get attrib location for aPosition"); } maTextureHandle = GLES30.glGetAttribLocation(mProgram, "aTextureCoord"); checkGlError("glGetAttribLocation aTextureCoord"); if (maTextureHandle == -1) { throw new RuntimeException("Could not get attrib location for aTextureCoord"); } muMVPMatrixHandle = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix"); checkGlError("glGetUniformLocation uMVPMatrix"); if (muMVPMatrixHandle == -1) { throw new RuntimeException("Could not get attrib location for uMVPMatrix"); } muSTMatrixHandle = GLES30.glGetUniformLocation(mProgram, "uSTMatrix"); checkGlError("glGetUniformLocation uSTMatrix"); if (muSTMatrixHandle == -1) { throw new RuntimeException("Could not get attrib location for uSTMatrix"); } int[] textures = new int[1]; GLES30.glGenTextures(1, textures, 0); mTextureID = textures[0]; GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID); checkGlError("glBindTexture mTextureID"); GLES30.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST); GLES30.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR); GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE); GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE); checkGlError("glTexParameter"); } catch(Exception ex) { Log.v("My Error", "surfaceCreated Error = " + ex.toString()); } } /** * Replaces the fragment shader. Pass in null to reset to default. */ public void changementShader(String fragmentShader) { try { if (fragmentShader == null) { fragmentShader = FRAGMENT_SHADER; } GLES30.glDeleteProgram(mProgram); mProgram = createProgram(VERTEX_SHADER, fragmentShader); if (mProgram == 0) { Log.v("My Error", "failed creating program"); throw new RuntimeException("failed creating program"); } } catch(Exception ex) { Log.v("My Error", " changementShader Error = " + ex.toString()); } } private int loadShader(int shaderType, String source) { try { int shader = GLES30.glCreateShader(shaderType); checkGlError("glCreateShader type=" + shaderType); GLES30.glShaderSource(shader, source); GLES30.glCompileShader(shader); int[] compiled = new int[1]; GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compiled, 0); if (compiled[0] == 0) { Log.e(TAG, "Could not compile shader " + shaderType + ":"); Log.e(TAG, " " + GLES30.glGetShaderInfoLog(shader)); GLES30.glDeleteShader(shader); shader = 0; } return shader; } catch(Exception ex) { Log.v("My Error", "loadShader Error = " + ex.toString()); return 0; } } private int createProgram(String vertexSource, String fragmentSource) { try { int vertexShader = loadShader(GLES30.GL_VERTEX_SHADER, vertexSource); if (vertexShader == 0) { return 0; } int pixelShader = loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentSource); if (pixelShader == 0) { return 0; } int program = GLES30.glCreateProgram(); checkGlError("glCreateProgram"); if (program == 0) { Log.e(TAG, "Could not create program"); } GLES30.glAttachShader(program, vertexShader); checkGlError("glAttachShader"); GLES30.glAttachShader(program, pixelShader); checkGlError("glAttachShader"); GLES30.glLinkProgram(program); int[] linkStatus = new int[1]; GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, linkStatus, 0); if (linkStatus[0] != GLES30.GL_TRUE) { Log.e(TAG, "Could not link program: "); Log.e(TAG, GLES30.glGetProgramInfoLog(program)); GLES30.glDeleteProgram(program); program = 0; } return program; } catch(Exception ex) { Log.v("My Error", "createProgram Error = " + ex.toString()); return 0; } } public void checkGlError(String op) { int error; while ((error = GLES30.glGetError()) != GLES30.GL_NO_ERROR) { Log.e(TAG, op + ": glError " + error); throw new RuntimeException(op + ": glError " + error); } } } 
+6
source share
2 answers

Your shader code has absolutely nothing to do with reading glReadPixels , and it has nothing to do with the names of special variables. It is read from the current associated read framebuffer; those. glReadPixels in ES 3.0 works exactly the same as in ES 2.0.

The only exception is multiple support for target rendering, but in this case it is not relevant.

How can I make sure fragColor is reading?

 glClearColor(some interesting color) glClear(COLOR_BUFFER_BIT) glReadPixels() assert color == some interesting color 
0
source

What I found out is that your call to GLES30.glReadPixels should be done before eglSwapBuffers, because glReadBuffer initially set to GL_BACK in two-buffered configurations according to the glReadBuffer document. As soon as eglSwapBuffers calls glReadPixels it returns nothing to main memory.

0
source

All Articles