I'm using OpenGL ES 2.0
on Android
to add effects to a video. Everything works fine until I add another texture.
What I've tried:
- Using a Texture2D instead of external (EOS) -> Impossible for an external source (video file)
- Changed texture to a power of two after using the method that checks if the GPU supports non pow of 2 -> No change
- Played with the chronological order of GLES20 methods -> No visible change in execution behaviour
- Binded textures using different index logic -> No change
Not tried yet:
- Using another bitmap format, but the GLUtils method to load bitmap is supposed to handle the format
- Using the 'legacy' method to load a texture from a bitmap (GLES instead of GLUtils)
- Using a array of pixels instead of a bitmap.
But at this point I would just surrender about bitmap and send an Uniform Buffer containing my pixels to the shader...
When my surface is created I do this:
var vertexShader = _videoView.Filtering.Shaders.Item1;
var fragmentShader = _videoView.Filtering.Shaders.Item2;
var progExists = glPrograms.ContainsKey (vertexShader + fragmentShader);
if (!progExists) {
var prog = createProgram (vertexShader, fragmentShader);
glPrograms.Add (vertexShader + fragmentShader, prog);
}
_glProgram = glPrograms [vertexShader + fragmentShader];
if (_glProgram == 0) {
// Should compile with default shaders from GlFilter.
throw new System.Exception ("Can't create GL Program. There is something wrong with EGL on this device.");
}
I also load my textures:
_aPositionHandle = GLES20.GlGetAttribLocation(_glProgram, "aPosition");
checkGlError("glGetAttribLocation aPosition");
if (_aPositionHandle == -1) {
throw new RuntimeException(
"Could not get attrib location for aPosition");
}
_aTextureCoord = GLES20.GlGetAttribLocation(_glProgram,
"aTextureCoord");
checkGlError("glGetAttribLocation aTextureCoord");
if (_aTextureCoord == -1) {
throw new RuntimeException (
"Could not get attrib location for aTextureCoord");
}
_uMVPMatrixHandle = GLES20.GlGetUniformLocation(_glProgram,
"uMVPMatrix");
checkGlError("glGetUniformLocation uMVPMatrix");
if (_uMVPMatrixHandle == -1) {
throw new RuntimeException(
"Could not get attrib location for uMVPMatrix");
}
_uSTMatrixHandle = GLES20.GlGetUniformLocation(_glProgram,
"uSTMatrix");
checkGlError("glGetUniformLocation uSTMatrix");
if (_uSTMatrixHandle == -1) {
throw new RuntimeException(
"Could not get attrib location for uSTMatrix");
}
_texelWidthOffsetUniform = GLES20.GlGetUniformLocation(_glProgram,
"texelWidthOffset");
checkGlError("glGetUniformLocation texelWidthOffset");
if (_texelWidthOffsetUniform == -1) {
throw new RuntimeException(
"Could not get attrib location for texelWidthOffset");
}
_texelHeightOffsetUniform = GLES20.GlGetUniformLocation(_glProgram,
"texelHeightOffset");
checkGlError("glGetUniformLocation texelHeightOffset");
if (_texelHeightOffsetUniform == -1) {
throw new RuntimeException(
"Could not get attrib location for texelHeightOffset");
}
_sTexture2Uniform = GLES20.GlGetUniformLocation(_glProgram,
"sTexture2");
checkGlError("glGetUniformLocation sTexture2Uniform");
if (_sTexture2Uniform == -1) {
throw new RuntimeException(
"Could not get attrib location for sTexture2");
}
int[] textures = new int[1];
GLES20.GlGenTextures(1, textures, 0);
_textureID = textures[0];
GLES20.GlBindTexture(GL_TEXTURE_EXTERNAL_OES, _textureID);
checkGlError("glBindTexture _textureID");
GLES20.GlTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GlTextureMinFilter, GLES20.GlNearest);
GLES20.GlTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GlTextureMagFilter, GLES20.GlLinear);
Still in Surface Created event, I add a texture by uploading a Bitmap
source = Bitmap.CreateBitmap(256, 256, Bitmap.Config.Argb8888);
source.EraseColor(Color.Pink.ToArgb());
for (int x = 0; x < 256; x++)
for (int y = 0; y < 256; y++) {
var cof = (int)(System.Math.Cos ((double)x / (double)256) * 255);
var sif = (int)(System.Math.Sin ((double)y / (double)256) * 255);
var p = (double)x / (double)256 * 360d;
var q = (double)y / (double)256 * 360d;
var c = (int)(((System.Math.Sin (p * q) / 2d) + 0.5d) * 255d);
source.SetPixel (x, y, Color.Argb (255, c, (c + cof) / 2, (c + sif) / 2));
}
int[] textures = new int[1];
GLES20.GlGenTextures(1, textures, 0);
_texture2Id = textures[0];
GLUtils.TexImage2D(GLES20.GlTexture2d, 0, source, 0);
source.Recycle ();
GLES20.GlBindTexture(GLES20.GlTexture2d, _texture2Id);
GLES20.GlTexParameterf(GLES20.GlTexture2d, GLES20.GlTextureWrapS, GLES20.GlClampToEdge);
GLES20.GlTexParameterf(GLES20.GlTexture2d, GLES20.GlTextureWrapT, GLES20.GlClampToEdge);
GLES20.GlTexParameterf(GLES20.GlTexture2d, GLES20.GlTextureMagFilter, GLES20.GlLinear);
GLES20.GlTexParameterf(GLES20.GlTexture2d, GLES20.GlTextureMinFilter, GLES20.GlLinear);
_surfaceTexture = new SurfaceTexture(_textureID);
_surfaceTexture.FrameAvailable += _surfaceTexture_FrameAvailable;
_mediaPlayer = new MediaPlayer();
Then in OnDraw:
var fragment = _videoView.Filtering.Shaders.Item2;
var vertex = _videoView.Filtering.Shaders.Item1;
var progExists = glPrograms.ContainsKey (vertex + fragment);
if (!progExists) {
var prog = createProgram (vertex, fragment);
glPrograms.Add (vertex + fragment, prog);
}
var progToUse = glPrograms [vertex + fragment];
GLES20.GlClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLES20.GlClear(GLES20.GlColorBufferBit);
lock (syncLock) {
_surfaceTexture.UpdateTexImage ();
_surfaceTexture.GetTransformMatrix (_STMatrix);
updateSurface = false;
}
GLES20.GlViewport(0, 0, _surfaceWidth, _surfaceHeight);
if (progToUse != _glProgram) {
GLES20.GlUseProgram (progToUse);
}
_glProgram = progToUse;
GLES20.GlUniform1i(_sTexture2Uniform, 1);
GLES20.GlActiveTexture (GLES20.GlTexture0);
GLES20.GlBindTexture (GL_TEXTURE_EXTERNAL_OES, _textureID);
GLES20.GlActiveTexture (GLES20.GlTexture1);
GLES20.GlBindTexture (GLES20.GlTexture2d, _texture2Id);
_triangleVertices.Position (TRIANGLE_VERTICES_DATA_POS_OFFSET);
GLES20.GlVertexAttribPointer (_aPositionHandle, 3, GLES20.GlFloat, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, _triangleVertices);
GLES20.GlEnableVertexAttribArray (_aPositionHandle);
_textureVertices.Position (TRIANGLE_VERTICES_DATA_UV_OFFSET);
GLES20.GlVertexAttribPointer (_aTextureCoord, 2, GLES20.GlFloat, false, TEXTURE_VERTICES_DATA_STRIDE_BYTES, _textureVertices);
GLES20.GlEnableVertexAttribArray (_aTextureCoord);
Android.Opengl.Matrix.SetIdentityM (_MVPMatrix, 0);
GLES20.GlUniformMatrix4fv (_uMVPMatrixHandle, 1, false, _MVPMatrix, 0);
GLES20.GlUniformMatrix4fv (_uSTMatrixHandle, 1, false, _STMatrix, 0);
GLES20.GlDrawArrays(GLES20.GlTriangleStrip, 0, 4);
The problem is when I hit this line `GLES20.GlUniform1i(_sTexture2Uniform, 1);`
I keep getting this error then setting my bitmap texture uniform in OnDraw.
[Adreno200-ES20] <__load_uniform_float:539>: GL_INVALID_OPERATION
The two errors I get are:
[SurfaceTexture] [unnamed-22096-0] updateTexImage: clearing GL error: 0x502
[Adreno200-ES20] <__load_uniform_int:305>: GL_INVALID_OPERATION
Vertex looks like it:
uniform mat4 uMVPMatrix;
uniform mat4 uSTMatrix;
uniform highp float texelWidthOffset;
uniform highp float texelHeightOffset;
attribute vec4 aPosition;
attribute vec4 aTextureCoord;
varying vec2 vTextureCoord;
void main() {
highp float useTX = texelWidthOffset;
highp float useTY = texelHeightOffset;
gl_Position = uMVPMatrix * aPosition;
vTextureCoord = (uSTMatrix * aTextureCoord).xy;
}
Fragment looks like it:
#version 150
#extension GL_OES_EGL_image_external : require
precision mediump float;
uniform sampler2D sTexture2;
uniform samplerExternalOES sTexture;
varying vec2 vTextureCoord;
varying float texelWidthOffset;
varying float texelHeightOffset;
void main() {
highp float useTX = texelWidthOffset;
highp float useTY = texelHeightOffset;
lowp vec4 inputColor0 = texture2D(sTexture,vTextureCoord);
lowp vec4 someColor = mix(inputColor0, texture2D(sTexture2,vTextureCoord), useTY);
lowp vec4 outputColor0 = mix(inputColor0, texture2D(sTexture,vTextureCoord), useTX);
gl_FragColor=outputColor0;
}
I don't know what to say except "Help!", since I've maybe tried to follow 100+ tutorials to fix this GL_INVALID_OPERATION
error.
None of the attempts I've made ever result in any colored pixel when mixing OES external source (a movie file) with a bitmap texture.
[EDIT]
Ok. In the code above I was setting _glProgram to the proper created program id, then before using the program, I was saying: "Is _glProgram
equals to the proper created program id
? If yes, then don't come here to call useProgram
." So I was never using the proper program. So there is not a single OpenGL error now, but the screen is black like in zero. This is a good news. I know the pixels from my bitmap texture are correct. (Coded an a trigo algo randomly, happened to form cute polka four holes buttons.) So I'm revising my OpenGL ES code.
[EDIT 2]
I feel like I'm stuck with this problem.