I am trying to render the contents of an external texture (which gets its data from android MediaCodec) to a framebuffer with a texture atttachment (first pass) and then using that texture to render to display (second pass)
My overall goal is to do some operation in the shader in the first pass and some more operation in the second pass. But I am getting GL_INVALID_OPERAION in the first pass and hence texture associated with the Framebuffer is not populated.
Below is the summary of the code
OpenGL environment initialization
GLES20.glGenFramebuffers(1,frameBufferHandles,0);
GLES20.glGenBuffers(2, bufferHandles, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferHandles[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, Utils.VERTICES.length * FLOAT_SIZE_BYTES, Utils.getVertexBuffer(), GLES20.GL_DYNAMIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, bufferHandles[1]);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, Utils.INDICES.length * FLOAT_SIZE_BYTES, Utils.getIndicesBuffer(), GLES20.GL_DYNAMIC_DRAW);
GLES20.glGenTextures(2, textureHandles, 0);
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureHandles[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.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,frameBufferHandles[0]);
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[1]);
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.glTexImage2D(GLES20.GL_TEXTURE_2D,0,GLES20.GL_RGBA,width,height,0,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_BYTE,null); //width.height are of that viewport and are initialized properly
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,GLES20.GL_COLOR_ATTACHMENT0,GLES20.GL_TEXTURE_2D,textureHandles[1],0);
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
if(status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
Log.d(TAG,"Frame Buffer Incomplete : " + status);
} else
Log.d(TAG,"Frame Buffer Complete");
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0);
Vertex Shader setup
public static final String DEFAULT_VERTEX_SHADER = "uniform mat4 uMVPMatrix;\n"
+ "uniform mat4 uSTMatrix;\n"
+ "attribute vec4 aPosition;\n"
+ "attribute vec4 aTextureCoord;\n"
+ "varying vec2 vTextureCoord;\n"
+ "void main() {\n"
+ " gl_Position = uMVPMatrix * aPosition;\n"
+ " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n"
+ "}\n";
Fragment shader setup
#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 vTextureCoord;
uniform samplerExternalOES sTexture;
uniform sampler2D sTextureSampler;
uniform float r;
uniform int pass;
void main() {
if(pass == 0) {
gl_FragColor = texture2D(sTexture, vTextureCoord);
//gl_FragColor = vec4(1.0,1.0,0.0,1.0);
}
else if(pass == 1) {
gl_FragColor = texture2D(sTextureSampler, vTextureCoord);
}
}
Vertex Attributes and Index buffer are defined like below
public static float[] VERTICES = {
-1.0f, -1.0f, 0.0f, 0f, 0f,
-1.0f, 1.0f, 0.0f, 0f, 1f,
1.0f, 1.0f, 0.0f, 1f, 1f,
1.0f, -1.0f, 0.0f, 1f, 0f
};
public static int[] INDICES = {
2, 1, 0, 0, 3, 2
};
And finally my draw() function looks like this
protected void draw() {
Matrix.setIdentityM(mvpMatrix, 0);
if(mProgram != -1)
mProgram = createProgram();
int vertexHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
int uvsHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
int texMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix");
int mvpMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
int textureHandle = GLES20.glGetUniformLocation(mProgram, "sTextureSampler");
int pass = GLES20.glGetUniformLocation(mProgram, "pass");
GLES20.glUseProgram(mProgram);
GLES20.glUniformMatrix4fv(texMatrixHandle, 1, false, texMatrix, 0);
GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferHandles[0]);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, bufferHandles[1]);
GLES20.glEnableVertexAttribArray(vertexHandle);
GLES20.glVertexAttribPointer(vertexHandle, 3, GLES20.GL_FLOAT, false, 4 * 5, 0);
GLES20.glEnableVertexAttribArray(uvsHandle);
GLES20.glVertexAttribPointer(uvsHandle, 2, GLES20.GL_FLOAT, false, 4 * 5, 3 * 4);
//Pass 0 - Render to framebuffer , gives GL_INVALID_OPERAION error
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,frameBufferHandles[0]);
GLES20.glUniform1i(pass, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_INT, 0);
//Pass 1 - Render to display
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0);
GLES20.glUniform1i(textureHandle, 2);
GLES20.glUniform1i(pass, 1);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_INT, 0);
}
I am guessing it is related to vTextureCoord, because if I dont use vTextureCoord and render a constant color to the framebuffer during first pass , then I can read it back during the second pass from the texture associated with the framebuffer.
Related
This is part of the MediaExtractor -> MediaCodec (Decoder) -> MediaCodec (Encoder) workflow. More specifically, the part where the texture from the Decoder's output buffer is rendered into the Encoder's input buffer. For that, I've set up the following onDrawFrame() function in the Decoder's output surface:
public void drawFrame(SurfaceTexture st) {
checkGlError("onDrawFrame start");
st.getTransformMatrix(mPrelimSTMatrix);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
drawToFBO();
}
private void drawToFBO() {
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
int mainTextureLoc = GLES20.glGetUniformLocation(prelimShaderProgram, "u_Texture");
checkGlError("glGetMainTextureUniform");
GLES20.glUseProgram(prelimShaderProgram);
checkGlError("glUseProgram");
GLES20.glUniform1i(mainTextureLoc, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
checkGlError("glBindTexture");
onPrelimPreDrawFrame(); //Basically binding the extraneous textures the filter requires
mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(maPrelimPositionHandle, 3, GLES20.GL_FLOAT, false,
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
checkGlError("glVertexAttribPointer maPosition");
GLES20.glEnableVertexAttribArray(maPrelimPositionHandle);
checkGlError("glEnableVertexAttribArray maPositionHandle");
mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
GLES20.glVertexAttribPointer(maPrelimTextureHandle, 3, GLES20.GL_FLOAT, false,
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
checkGlError("glVertexAttribPointer maTextureHandle");
GLES20.glEnableVertexAttribArray(maPrelimTextureHandle);
checkGlError("glEnableVertexAttribArray maTextureHandle");
Matrix.setIdentityM(mPrelimMVPMatrix, 0);
GLES20.glUniformMatrix4fv(muPrelimMVPMatrixHandle, 1, false, mPrelimMVPMatrix, 0);
checkGlError("glmuMVPMatrixHandleSetting");
GLES20.glUniformMatrix4fv(muPrelimSTMatrixHandle, 1, false, mPrelimSTMatrix, 0);
checkGlError("glmuSTMatrixHandleSetting");
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
checkGlError("glDrawArrays");
}
private void createPrelimShader() {
FRAGMENT_SHADER = VideoUtils.getPrelimFragmentShader(context, prelimFilterCode);
prelimShaderProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
if (prelimShaderProgram == 0) {
return;
}
maPrelimPositionHandle = GLES20.glGetAttribLocation(prelimShaderProgram, "aPosition");
checkGlError("glGetAttribLocation aPosition");
if (maPrelimPositionHandle == -1) {
throw new RuntimeException("Could not get attrib location for aPosition");
}
maPrelimTextureHandle = GLES20.glGetAttribLocation(prelimShaderProgram, "aTexCoordinate");
checkGlError("glGetAttribLocation aTexCoordinate");
if (maPrelimTextureHandle == -1) {
throw new RuntimeException("Could not get attrib location for aTexCoordinate");
}
muPrelimMVPMatrixHandle = GLES20.glGetUniformLocation(prelimShaderProgram, "uMVPMatrix");
checkGlError("glGetUniformLocation uMVPMatrix");
if (muPrelimMVPMatrixHandle == -1) {
throw new RuntimeException("Could not get attrib location for uMVPMatrix");
}
muPrelimSTMatrixHandle = GLES20.glGetUniformLocation(prelimShaderProgram, "uSTMatrix");
checkGlError("glGetUniformLocation uSTMatrix");
if (muPrelimSTMatrixHandle == -1) {
throw new RuntimeException("Could not get attrib location for uSTMatrix");
}
filterInputTextureUniform2 = GLES20.glGetUniformLocation(prelimShaderProgram, "inputImageTexture2");
filterInputTextureUniform3 = GLES20.glGetUniformLocation(prelimShaderProgram, "inputImageTexture3");
filterInputTextureUniform4 = GLES20.glGetUniformLocation(prelimShaderProgram, "inputImageTexture4");
filterInputTextureUniform5 = GLES20.glGetUniformLocation(prelimShaderProgram, "inputImageTexture5");
filterInputTextureUniform6 = GLES20.glGetUniformLocation(prelimShaderProgram, "inputImageTexture6");
preloadFilterAssets(VideoUtils.getFilterAssets(prelimFilterCode));
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
checkGlError("glGenFramebuffers");
mTextureID = textures[0];
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_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);
}
The vertex shader looks like this:
uniform mat4 uMVPMatrix;
uniform mat4 uSTMatrix;
attribute vec4 aPosition;
attribute vec4 aTexCoordinate;
varying vec2 v_TexCoordinate;
void main() {
gl_Position = uMVPMatrix * aPosition;
v_TexCoordinate = (uSTMatrix * aTexCoordinate).xy;
}
And the fragment shader looks like this, with one extra input texture:
#extension GL_OES_EGL_image_external : require
precision lowp float;
varying highp vec2 v_TexCoordinate;
uniform samplerExternalOES u_Texture;
uniform sampler2D inputImageTexture2;
uniform float uParamValue1;
void main()
{
vec3 texel = texture2D(u_Texture, v_TexCoordinate).rgb;
vec3 procTexel = vec3(dot(vec3(0.3, 0.6, 0.1), texel));
procTexel = vec3(texture2D(inputImageTexture2, vec2(procTexel.r, .16666)).r);
texel += (procTexel - texel) * uParamValue1;
gl_FragColor = vec4(texel, 1.0);
}
None of the checkGlError() calls returned any exception, but the video renders as if the texture doesn't go through the OpenGL program created in the createPrelimShader() function. It's rendered unfiltered.
On past experience, this is probably caused by something missing in the flow. Is it?
I'm using OpenGL for display YUV420P frames on screen in Android.
With some resolution, my frame looks good, but with big resolution (on the same screen), it still looks like my original frame (with colors and all), but with some green lines hatching it (depending to the orientation, 4 lines, 30 lines?).
Here is an example (an 1080x607 frame):
Is it a alignment problem? A texture binding problem? Here is my code:
private final short[] INDICES_DATA = {0, 1, 2, 0, 2, 3};
private final float[] VERTICES_DATA = new float[] {
-1f, 1f, 0f,
0f, 0f,
-1f, -1f, 0f,
0f, 1f,
1f, -1f, 0f,
1f, 1f,
1f, 1f, 0f,
1f, 0f
};
private final String szVertexShaderCode =
"attribute vec4 aPosition;\n" +
"attribute vec2 aTexCoord;\n" +
"varying vec2 vTexCoord;\n" +
"void main() {\n" +
" gl_Position = aPosition;\n" +
" vTexCoord = aTexCoord;\n" +
"}\n";
private final String szYUV420PFragmentShaderCode =
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n" +
" precision highp float;\n" +
"#else\n" +
" precision mediump float;\n" +
"#endif\n" +
"varying vec2 vTexCoord;\n" +
"uniform sampler2D yTexture;\n" +
"uniform sampler2D uTexture;\n" +
"uniform sampler2D vTexture;\n" +
"void main() {\n" +
" float r, g, b, y, u, v;\n" +
" y = texture2D(yTexture, vTexCoord).r;\n" +
" u = texture2D(uTexture, vTexCoord).r - 0.5;\n" +
" v = texture2D(vTexture, vTexCoord).r - 0.5;\n" +
" r = y + (1.13983 * v);\n" +
" g = y - (0.39465 * u) - (0.58060 * v);\n" +
" b = y + (2.03211 * u);\n" +
" gl_FragColor = vec4(r, g, b, 1.0);\n" +
"}\n";
Function on surface created:
//initShadersAndProgram();
iPositionLoc = GLES20.glGetAttribLocation(iProgram, "aPosition");
iTexCoordLoc = GLES20.glGetAttribLocation(iProgram, "aTexCoord");
// Is this line useful?
GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
iYTexture = GLES20.glGetUniformLocation(iProgram, "yTexture");
int[] yTextureNames = new int[1];
GLES20.glGenTextures(1, yTextureNames, 0);
int iYTextureName = yTextureNames[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iYTextureName);
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.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
iUTexture = GLES20.glGetUniformLocation(iProgram, "uTexture");
int[] uTextureNames = new int[1];
GLES20.glGenTextures(1, uTextureNames, 0);
int iUTextureName = uTextureNames[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iUTextureName);
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.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
iVTexture = GLES20.glGetUniformLocation(iProgram, "vTexture");
int[] vTextureNames = new int[1];
GLES20.glGenTextures(1, vTextureNames, 0);
int iVTextureName = vTextureNames[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iVTextureName);
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.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Function on draw frame:
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(iProgram);
verticesBuffer.position(0);
GLES20.glVertexAttribPointer(iPositionLoc, 3, GLES20.GL_FLOAT, false, 5 * 4, verticesBuffer);
verticesBuffer.position(3);
GLES20.glVertexAttribPointer(iTexCoordLoc, 2, GLES20.GL_FLOAT, false, 5 * 4, verticesBuffer);
GLES20.glEnableVertexAttribArray(iPositionLoc);
GLES20.glEnableVertexAttribArray(iTexCoordLoc);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glUniform1i(iYTexture, 1);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,
0,
GLES20.GL_LUMINANCE,
pixmap.getWidth(),
pixmap.getHeight(),
0,
GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE,
/* buffer Y */);
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glUniform1i(iUTexture, 2);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,
0,
GLES20.GL_LUMINANCE,
pixmap.getWidth() / 2,
pixmap.getHeight() / 2,
0,
GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE,
/* buffer U */);
GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
GLES20.glUniform1i(iVTexture, 3);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,
0,
GLES20.GL_LUMINANCE,
pixmap.getWidth() / 2,
pixmap.getHeight() / 2,
0,
GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE,
/* buffer V */);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, indicesBuffer);
What do I miss?
EDIT: Frames are provided from two different decoders and all works find with an other render process.
EDIT2: I displayed only the Y plane and the result is a grey frame (as expected) but there is no hatch lines!!
I just replaced these lines in my fragment shader to display it:
" r = texture2D(yTexture, vTexCoord).r;\n" +
" g = texture2D(yTexture, vTexCoord).g;\n" +
" b = texture2D(yTexture, vTexCoord).b;\n" +
So problem comes from U/V planes?
I'm encoding a video using this example EncodeAndMuxTest.java. Instead of generate surface frame by GLES20.glScissor(), i'm drawing a texture (by GLES20.glActiveTexture(), GLES20.glBindTexture(), GLES20.glDrawElements()). But the output video always having black screen.
I recogize that the output video only display color in GLES20.glClear() and it doesn't display image texture. I guess that having some problem with texture when using EGL14.eglSwapBuffers but i cann't figure it out.
Please kindly help me solve my problem. Thanks so much!
Update Code use for example
public void testEncodeVideoToMp4() {
// QVGA at 2Mbps
mWidth = 320;
mHeight = 240;
mBitRate = 2000000;
try {
prepareEncoder();
setupTexture(); // insert new function to setup opengles
mInputSurface.makeCurrent();
for (int i = 0; i < NUM_FRAMES; i++) {
drainEncoder(false);
// Generate a new frame of input.
// generateSurfaceFrame(i);
drawTexture(); // insert new function to draw texture
mInputSurface.setPresentationTime(computePresentationTimeNsec(i));
if (VERBOSE)
Log.d(TAG, "sending frame " + i + " to encoder");
mInputSurface.swapBuffers();
}
drainEncoder(true);
} finally {
releaseEncoder();
}
}
setupTexture() function:
public void setupTexture() {
mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertices.put(mVerticesData).position(0);
mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2).order(ByteOrder.nativeOrder()).asShortBuffer();
mIndices.put(mIndicesData).position(0);
String vShaderStr = "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = a_position; \n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
String fShaderStr = "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_baseMap; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = texture2D( s_baseMap, v_texCoord ); \n"
+ "} \n";
// Load the shaders and get a linked program object
mProgramObject = ESShader.loadProgram(vShaderStr, fShaderStr);
// Get the attribute locations
mPositionLoc = GLES20.glGetAttribLocation(mProgramObject, "a_position");
mTexCoordLoc = GLES20.glGetAttribLocation(mProgramObject, "a_texCoord");
// Get the sampler locations
mBaseMapLoc = GLES20.glGetUniformLocation(mProgramObject, "s_baseMap");
// Load the texture
mBaseMapTexId = loadTexture();
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLES20.glViewport(0, 0, 720, 1280);
}
loadTexture() function
private int loadTexture() {
int[] textureId = new int[1];
Bitmap bitmap;
bitmap = BitmapFactory.decodeFile(mFilePath); // please change mFilePath to image file in sdcard
if (bitmap == null) {
return -1;
}
GLES20.glGenTextures(1, textureId, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 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);
bitmap.recycle();
return textureId[0];
}
drawTexture() function:
public void drawTexture() {
GLES20.glClearColor(TEST_R0 / 255.0f, TEST_G0 / 255.0f, TEST_B0 / 255.0f, 1.0f); // green color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Use the program object
GLES20.glUseProgram(mProgramObject);
// Load the vertex position
mVertices.position(0);
GLES20.glVertexAttribPointer(mPositionLoc, 3, GLES20.GL_FLOAT, false, 5 * 4, mVertices);
// Load the texture coordinate
mVertices.position(3);
GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 5 * 4, mVertices);
GLES20.glEnableVertexAttribArray(mPositionLoc);
GLES20.glEnableVertexAttribArray(mTexCoordLoc);
// Bind the base map
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBaseMapTexId);
// Set the base map sampler to texture unit to 0
GLES20.glUniform1i(mBaseMapLoc, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices);
}
Variables use for openGL ES
// Handle to a program object
private int mProgramObject;
// Attribute locations
private int mPositionLoc;
private int mTexCoordLoc;
// Sampler location
private int mBaseMapLoc;
// Texture handle
private int mBaseMapTexId;
// Additional member variables
private FloatBuffer mVertices;
private ShortBuffer mIndices;
private final float[] mVerticesData = { -1f, 1f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-1f, -1f, 0.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
1f, -1f, 0.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
1f, 1f, 0.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
private final short[] mIndicesData = { 0, 1, 2, 0, 2, 3 };
And the video output only display green screen
Brief: when I apply to one fragment shader two textures with two different texture coordinates, I see only first texture. But when I use one texture coordinate for two textures it works fine and I can see both textures.
I work with photo filters and use OpenGL ES 2.0 to make filters. Some filters have an advance texture. First texture is a photo and second is a tracery.
Here is my vertext shader
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
attribute vec4 inputTextureCoordinate2;
varying vec2 textureCoordinate;
varying vec2 textureCoordinate2;
void main() {
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
textureCoordinate2 = inputTextureCoordinate2.xy;
}
Here is my fragment shader
precision mediump float;
uniform sampler2D inputImageTexture1;
uniform sampler2D inputImageTexture2;
varying vec2 textureCoordinate;
varying vec2 textureCoordinate2;
void main() {
mediump vec4 color1 = texture2D(inputImageTexture1, textureCoordinate);
mediump vec4 color2 = texture2D(inputImageTexture2, textureCoordinate2);
mediump vec3 colorResult = mix(color1.rgb, color2.rgb, 0.5);
gl_FragColor = vec4(colorResult, 1.0);
}
In my code I use GLSurfaceView.Render implementation.
Initialization of coordinates:
static final float CUBE[] = {-1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,};
public static final float COORDINATES1[] = {0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,};
public static final float COORDINATES2[] = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,};
...
mGLCubeBuffer = ByteBuffer.allocateDirect(CUBE.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mGLCubeBuffer.put(CUBE).position(0);
mGLTextureCoordinates1 = ByteBuffer.allocateDirect(COORDINATES1.length * 4).order(ByteOrder.nativeOrder())
.asFloatBuffer();
mGLTextureCoordinates1.clear();
mGLTextureCoordinates1.put(COORDINATES1).position(0);
mGLTextureCoordinates2 = ByteBuffer.allocateDirect(COORDINATES2.length * 4).order(ByteOrder.nativeOrder())
.asFloatBuffer();
mGLTextureCoordinates2.clear();
mGLTextureCoordinates1.put(COORDINATES2).position(0);
onSurfaceCreate method:
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0, 0, 0, 1);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glDisable(GLES20.GL_DEPTH_BITS);
String vertexShader = RawResourceReader.readTextFileFromRawResource(mContext, R.raw.test_vertex);
String fragmentShader = RawResourceReader.readTextFileFromRawResource(mContext, R.raw.test_fragment);
mGLProgId = loadProgram(vertexShader, fragmentShader);
mGLAttribPosition = GLES20.glGetAttribLocation(mGLProgId, "position");
mGLAttribTextureCoordinate = GLES20.glGetAttribLocation(mGLProgId, "inputTextureCoordinate");
mGLAttribTextureCoordinate2 = GLES20.glGetAttribLocation(mGLProgId, "inputTextureCoordinate2");
mGLUniformTexture1 = GLES20.glGetUniformLocation(mGLProgId, "inputImageTexture1");
mGLUniformTexture2 = GLES20.glGetUniformLocation(mGLProgId, "inputImageTexture2");
mTexture1 = loadTexture(mContext, R.drawable.photo);
mTexture2 = loadTexture(mContext, R.drawable.formula1);
}
onDrawFrame method:
#Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glUseProgram(mGLProgId);
mGLCubeBuffer.position(0);
GLES20.glVertexAttribPointer(mGLAttribPosition, 2, GLES20.GL_FLOAT, false, 0, mGLCubeBuffer);
GLES20.glEnableVertexAttribArray(mGLAttribPosition);
//set first coordinates
mGLTextureCoordinates1.position(0);
GLES20.glVertexAttribPointer(mGLAttribTextureCoordinate, 2, GLES20.GL_FLOAT, false, 0, mGLTextureCoordinates1);
GLES20.glEnableVertexAttribArray(mGLAttribTextureCoordinate);
//set second coordinates
mGLTextureCoordinates2.position(0);
GLES20.glVertexAttribPointer(mGLAttribTextureCoordinate2, 2, GLES20.GL_FLOAT, false, 0, mGLTextureCoordinates2);
GLES20.glEnableVertexAttribArray(mGLAttribTextureCoordinate2);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture1);
GLES20.glUniform1i(mGLUniformTexture1, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture2);
GLES20.glUniform1i(mGLUniformTexture2, 1);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDisableVertexAttribArray(mGLAttribPosition);
GLES20.glDisableVertexAttribArray(mGLAttribTextureCoordinate);
GLES20.glDisableVertexAttribArray(mGLAttribTextureCoordinate2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
Significant part of loadTexture method:
GLES20.glGenTextures(1, textureHandle, 0);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
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);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_CONSTANT_ALPHA);
GLES20.glEnable(GLES20.GL_BLEND);
// 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();
Note that on iOs it works fine, but there is used some library. I tried to use library jp.co.cyberagent.android.gpuimage but it has a few bugs and doesn't work properly with this problem.
I want to know how solve this problem. It mays be some property which I don't know or something else. I'm new in OpenGL and hope to your help.
You can't use GLUtils.texImage2D() to load alpha textures on Android. This is a common problem that Google really should document better. The problem is that the Bitmap class converts all images into pre-multiplied format, but that does not work with OpenGL ES unless the images are completely opaque. The best solution is to use native code. This article gives more detail on this:
http://software.intel.com/en-us/articles/porting-opengl-games-to-android-on-intel-atom-processors-part-1
I'm trying to get some textures rendered on quads, but the screen turns out empty.
(Open GL 2.0)
I formerly used a static color shader on the quads, and the quads did appear on screen, so the positioning is fine.
UPDATE: Now I can see black textures only...
Here is my code:
Vertex Shader:
uniform mat4 uTMatrix;
uniform mat4 uMVPMatrix;
attribute vec4 vPosition;
attribute vec4 vTex;
attribute vec4 inputTextureCoordinate;
varying vec2 TexCoord0;
void main(){
TexCoord0 = inputTextureCoordinate.xy;
gl_Position = uMVPMatrix * uTMatrix * vPosition;
}
Frag Shader:
varying highp vec2 TexCoord0;
uniform sampler2D colorMap;
void main(){
gl_FragColor = texture2D(colorMap, TexCoord0);
}
onDrawFrame():
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glUseProgram(mProgram);
final float halfw = mWidth / 2f;
final int rowHeight = mRowHeight;
final float r = (float) rowHeight / halfw;
int i = mFirstRow;
final float initial = (float) ((i * rowHeight) - mScroll) / halfw;
Matrix.setIdentityM(mTMatrix, 0);
Matrix.translateM(mTMatrix, 0, 0, -initial, 0);
GLES20.glFrontFace(GLES20.GL_CW);
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
false, 0, mVertBuffer);
GLES20.glEnableVertexAttribArray(maPositionHandle);
GLES20.glVertexAttribPointer(maTexHandle, 3, GLES20.GL_FLOAT,
false, 0, mTexBuffer);
GLES20.glEnableVertexAttribArray(maTexHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
final int l = mLastRow;
for (; i <= l; i++) {
if (\*A check to see if the bitmap is cached*\) {
GLES20.glUniform1i(muTextureHandle, i);
GLES20.glUniformMatrix4fv(muTMatrixHandle, 1, false,
mTMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
Matrix.translateM(mTMatrix, 0, 0, -r, 0);
}
GLES20.glDisableVertexAttribArray(maPositionHandle);
GLES20.glDisableVertexAttribArray(maTexHandle);
loadTexture:
public void loadTexture(GL10 gl, Context c) {
int[] texture = new int[1];
texture[0] = mRow;
GLES20.glDeleteTextures(1, texture, 0);
texture[0] = mRow;
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);
// Create Nearest Filtered Texture
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);
// Different possible texture parameters, e.g.
// GLES20.GL_CLAMP_TO_EDGE
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
Bitmap bitmap = mBitmap;
if (bitmap == null) {
bitmap = mEmptyBitmap;
}
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
}
Additionally there's this one line I'm not sure what it's supposed to do;
if (\*A check to see if the bitmap is cached*\) {
GLES20.glUniform1i(muTextureHandle, i); // ??
...
}
I'm guessing your goal is to update GL_TEXTURE0 constantly though, in which case you should put constant value 0 into muTextureHandle. Or remove this line all together as zero is the default.