OpenGL ES 2.0屏幕闪烁

9

我遇到了一个大问题。我正在使用安卓4.0.3系统的Transformer tf101平板电脑。

我的应用程序正在使用自定义OpenGL ES 2.0表面。我用纹理渲染多个平面,这些纹理每秒变化约20次,通过传递字节数组进行更新。然而,在某些情况下,屏幕开始闪烁,并且无法呈现新的纹理。其他UI元素仍然响应并按预期工作。似乎OpenGL上下文忽略所有命令并处于无响应状态。

当发生这种情况时,我的logCat中会显示几行:

08-20 10:31:15.390: D/NvOsDebugPrintf(2898): NvRmChannelSubmit: NvError_IoctlFailed with error code 1

接着是
08-20 10:31:15.390: D/NvOsDebugPrintf(2898): NvRmChannelSubmit failed (err = 13, SyncPointValue = 879005, returning = 0)

其中有一些:

08-20 10:31:15.390: D/NvOsDebugPrintf(2898): NvRmChannelSubmit failed (err = 196623, SyncPointValue = 0)

以下是我创建纹理平面的步骤:

    m_nTextureStorage[0] = 0;

    GLES20.glGenTextures( 1, m_nTextureStorage, 0);
    GLES20.glActiveTexture( GLES20.GL_TEXTURE0 );
    GLES20.glBindTexture( GLES20.GL_TEXTURE_2D, m_nTextureStorage[ 0 ] );

    // Set filtering
    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 );
    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.glEnable(GLES20.GL_TEXTURE_2D);
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
        GLES20.glActiveTexture( GLES20.GL_TEXTURE0 );

        //GLES20.glUniformMatrix4fv(m_HMVPMatrixUniform, 1, false, mvpMatrix, 0); 
        GLES20.glUseProgram( m_nProgramHandle );
        ByteBuffer oDataBuf = ByteBuffer.wrap( m_sTexture );

        m_HTextureUniform = GLES20.glGetUniformLocation( m_nProgramHandle, "uTexture" );
        m_HTextureCoordinate = GLES20.glGetAttribLocation( m_nProgramHandle, "TexCoordinate" );
        GLES20.glUniform1iv( m_HTextureUniform, 2, m_nTextureStorage, 0 );

        // get handle to the vertex shader's vPosition member
        m_nPositionHandle = GLES20.glGetAttribLocation( m_nProgramHandle, "vPosition" );


        // Prepare the triangle data
        GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, 640, 480,
                             0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, oDataBuf );

        // Prepare the triangle data
        GLES20.glVertexAttribPointer( m_nPositionHandle, 3, GLES20.GL_FLOAT, false, 12, m_oVertexBuffer );
        GLES20.glEnableVertexAttribArray( m_nPositionHandle );

        GLES20.glVertexAttribPointer( m_HTextureCoordinate, 2, GLES20.GL_FLOAT, false, 12, m_oTextureBuffer); 
        GLES20.glEnableVertexAttribArray( m_HTextureCoordinate );

        m_nMVPMatrixHandle = GLES20.glGetUniformLocation( m_nProgramHandle, "uMVPMatrix");

        // Apply the projection and view transformation
        GLES20.glUniformMatrix4fv( m_nMVPMatrixHandle, 1, false, mvpMatrix, 0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);

OpenGL渲染器通过传递mvpMatrix调用TexturedPlane的绘制函数。我没有删除任何纹理,因为我读到android系统会自动处理它们。
我认为这可能与GPU内存不足有关,但我不确定,因为我没有找到任何相关的错误信息。
谢谢您的提前帮助!
更新:
Rendermode被设置为RENDER_WHEN_DIRTY。将其更改为RENDERMODE_CONTINUOUSLY后,问题消失了。很奇怪。由于这只是一个解决方法而不是解决方案,我仍然需要求助;)
将Rendermode保持在连续状态下是不可行的,因为这会消耗太多的处理器时间,并且毫无意义,因为只有在生成新纹理时才需要渲染。

m_sTexture是如何生成的? - Maz
动态地创建一个新的 byte[640*480] 数组;这只需要做一次。我对 Java 和 OpenGL 还很陌生。然而,我注意到当闪烁开始时,Surface 会渲染已经传递的最后 3 帧……这说明这些帧仍然存储在 GPU 内存中的某个地方。 - Hafnernuss
更新:看起来当纹理创建过程需要很长时间时,闪烁更容易发生。创建新纹理可能需要一秒钟的时间。如果是这种情况,闪烁会在几秒钟后开始。如果纹理生成时间少于50毫秒,则不会出现闪烁...这是否意味着闪烁是由某种同步问题触发的,因为OpenGL渲染和纹理创建在不同的线程中运行? - Hafnernuss
非常好的观点。不,我不是。我的渲染器能够处理各种“对象”。例如,用于标记区域的平面、十字架等等。这些对象在此渲染线程之外创建。gl调用在构造函数中完成。然而,在OpenGL启动之前没有初始化任何“对象”...但由于我使用可重入锁,我确信只有一个线程正在访问OpenGL,对吗? - Hafnernuss
@nmr,谢谢你的信息,我之前不知道这个。 - Hafnernuss
显示剩余4条评论
2个回答

3

终于找到了解决方案。

每次渲染圆形后调用glFlush(),它就能正常工作。如果我将每个平面渲染到不同的纹理通道上,目前为止它也可以完美地工作。感谢您的帮助。


0

当你调用..:

GLES20.glUniform1iv( m_HTextureUniform, 2, m_nTextureStorage, 0 );

我认为将特定的纹理单元绑定到采样器统一变量。但是你正在传递一个纹理名称/对象/句柄/任何东西(这不是纹理单元)。也许这只是巧合,你只传递0(可能是m_nTextureStorage中的纹理名称),这恰好是正确/期望的值?

或者这可能导致用户空间驱动程序崩溃。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接