【问题标题】:GlUniform1i results in an error with uniform and bitmap textureGlUniform1i 导致统一和位图纹理错误
【发布时间】:2015-07-02 09:24:06
【问题描述】:

我在Android 上使用OpenGL ES 2.0 为视频添加效果。在我添加另一个纹理之前一切正常。

我尝试过的:

  • 使用 Texture2D 而不是外部 (EOS) -> 不可能用于外部源(视频文件)
  • 在使用检查 GPU 是否支持非 2 的 pow 的方法后将纹理更改为 2 的幂 -> 无变化
  • 按 GLES20 方法的时间顺序播放 -> 执行行为没有明显变化
  • 使用不同索引逻辑的绑定纹理 -> 无变化

还没试过:

  • 使用另一种位图格式,但加载位图的 GLUtils 方法应该能够处理该格式
  • 使用“传统”方法从位图加载纹理(GLES 而不是 GLUtils)
  • 使用像素数组而不是位图。

但在这一点上,我只想放弃位图并将包含我的像素的统一缓冲区发送到着色器...

创建表面后,我会这样做:

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.");
}

我还加载了我的纹理:

_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);

仍然在 Surface Created 事件中,我通过上传位图来添加纹理

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();

然后在 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);`

我不断收到此错误,然后在 OnDraw 中设置我的位图纹理统一。

[Adreno200-ES20] <__load_uniform_float:539>: GL_INVALID_OPERATION

我得到的两个错误是:

[SurfaceTexture] [unnamed-22096-0] updateTexImage: clearing GL error: 0x502
[Adreno200-ES20] <__load_uniform_int:305>: GL_INVALID_OPERATION

顶点看起来像这样:

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;
}

片段看起来像这样:

#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;
}

除了“帮助!”我不知道该说什么,因为我可能已经尝试按照 100 多个教程来修复这个 GL_INVALID_OPERATION 错误。 在将 OES 外部源(电影文件)与位图纹理混合时,我所做的任何尝试都没有产生任何彩色像素。

[编辑]

好的。在上面的代码中,我将 _glProgram 设置为正确创建的程序 ID,然后在使用该程序之前,我说:“_glProgram 是否等于正确创建的程序 id?如果是,那么不要来这里致电useProgram。”所以我从来没有使用过正确的程序。所以现在没有一个 OpenGL 错误,但屏幕是黑色的,就像零一样。这是个好消息。我知道我的位图纹理中的像素是正确的。 (随机编码了一个三角算法,碰巧形成了可爱的波尔卡四孔按钮。)所以我正在修改我的 OpenGL ES 代码。

[编辑 2]

我觉得我遇到了this 问题。

【问题讨论】:

    标签: android opengl-es-2.0


    【解决方案1】:

    您的代码中有一个非常明显的问题。在这个调用序列中:

    GLES20.GlGenTextures(1, textures, 0);
    _texture2Id = textures[0];
    
    GLUtils.TexImage2D(GLES20.GlTexture2d, 0, source, 0);
    source.Recycle ();
    
    GLES20.GlBindTexture(GLES20.GlTexture2d, _texture2Id);
    

    你需要在调用GLUtils.texImage2D()之前绑定纹理。该方法会将纹理数据加载到当前绑定的纹理中。正确的顺序是:

    GLES20.GlGenTextures(1, textures, 0);
    _texture2Id = textures[0];
    GLES20.GlBindTexture(GLES20.GlTexture2d, _texture2Id);
    
    GLUtils.TexImage2D(GLES20.GlTexture2d, 0, source, 0);
    source.Recycle ();
    

    不过,这并不能解释来自 glUniform1i() 调用的错误。由于以下原因,它可能会给出GL_INVALID_OPERATION 错误:

    1. 未绑定任何程序。
    2. 该位置对于当前绑定的程序无效。
    3. 用于调用的类型/大小与着色器中制服的类型/大小不匹配。

    我们可能可以排除选项1,或者至少您应该能够快速检查您刚刚绑定的程序是否有效。

    这会留下位置无效或制服位置错误的选项。除非我在您发布的相对冗长的代码中遗漏了某些内容,否则唯一合乎逻辑的解释是用于检索着色器位置的程序与您在 onDraw() 中绑定用于设置制服的程序不同。

    我注意到您正在使用某种着色器缓存来重用着色器。虽然这看起来相当简单,但我会加倍(以及三倍和四倍)检查它是否真的按预期工作。比较设置过程中使用的程序 id 与准备绘图时使用的统一位置。并确保没有着色器被破坏和重新创建。并且一切都发生在同一个线程/上下文中。

    【讨论】:

    • 谢谢。是的,程序id 从一开始就一直保持第一个,直到 ondraw 时刻。不幸的是,GlUniform1i 在反复试验中上下移动,但没有成功。根据您的提示,我将在运行时记录每个元素的 id,以检查在整个过程中是否有任何内容被处理和替换。如果没有机会,我将切换到 Buffer 对象。我不做真正密集的纹理混合。我只需要为一些过滤算法传递查找纹理,这可能适合一到四个 64kb 块。
    • 只是为了诊断,我也会尝试在有问题的glUniform() 调用之前立即放置一个glGetUniformLocation(),看看你是否仍然得到相同的统一位置。再加上glGetError() 的慷慨帮助,也许可以试试glValidateProgram()
    • 我修复了错误。 (请参阅编辑 - 错误的分配和条件阻止调用 useProgram。)将其重命名为 LoadAndUseProgram,并设置 _glProgram - in - 现在的条件。 :) 现在没有报错了,但是黑屏,只有OES贴图的版本就不是这样了(来源是MediaPlayer)。
    • 奇怪的是,当仅集成该代码以添加来自位图的第二个纹理时,我的两个纹理在着色器代码中不可用。硬编码值,如使用 texel 偏移,会生成正确的图像(例如渐变)。所以要么我用无效值覆盖这两个纹理,要么崩溃了,但不是渲染本身。顺便说一句 GlValidateProgram 有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-02
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多