Android 上出现意外的 GLES 1282 错误

Unexpected GLES 1282 error on Android

到目前为止,我使用了不同的着色器并在播放视频时将它们应用于自定义 VideoSurfaceView。直到今天我想添加伽玛效果时一切正常:

public class GammaEffect implements ShaderInterface {
/**
 * Initialize Effect
 */
public GammaEffect() {
}

@Override
public String getShader(GLSurfaceView mGlSurfaceView) {

    String shader = "#extension GL_OES_EGL_image_external : require\n"
            +"precision mediump float;\n"

            +"varying vec2 textureCoordinate;\n"
            +"uniform sampler2D inputImageTexture;\n"
            +"uniform float gamma;\n"

            +"void main() {\n"

            +"vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n"
            +"gl_FragColor = vec4(pow(textureColor.rgb, vec3(gamma)), textureColor.w);\n"

            +"}\n";


    return shader;
   }
}

在自定义 VideoSurface 上 class :

public class VideoSurfaceView extends GLSurfaceView {
private static final String TAG = "VideoSurfaceView";
private VideoRender mRenderer;
private MediaPlayer mMediaPlayer = null;
private static VideoSurfaceView mSurfaceView;
private Context mContext;
private static ShaderInterface effect;

public VideoSurfaceView(Context context) {
    super(context);
    mContext = context;
    setEGLContextClientVersion(2);
    mRenderer = new VideoRender(mContext);
    setRenderer(mRenderer);
    mSurfaceView = this;
}

public VideoSurfaceView(Context context, AttributeSet attrs) {
    super(context, attrs);
    mContext = context;
    setEGLContextClientVersion(2);
    mRenderer = new VideoRender(mContext);
    setRenderer(mRenderer);
    mSurfaceView = this;
}

/**
 * initializes media player and the effect that is going to be applied on
 * video. The video is played automatically so you dont need to call play.
 *
 * @param mediaPlayer  instance of {@link MediaPlayer}
 * @param shaderEffect any effect that implements {@link ShaderInterface}
 */
public void init(MediaPlayer mediaPlayer, ShaderInterface shaderEffect) {
    if (mediaPlayer == null)
        Toast.makeText(mContext, "Set MediaPlayer before continuing",
                Toast.LENGTH_LONG).show();
    else
        mMediaPlayer = mediaPlayer;
    if (shaderEffect == null)
        effect = new NoEffect();
    else
        effect = shaderEffect;
}

@Override
public void onResume() {
    if (mMediaPlayer == null) {
        Log.e(TAG, "Call init() before Continuing");
        return;
    }
    queueEvent(new Runnable() {
        @Override
        public void run() {
            mRenderer.setMediaPlayer(mMediaPlayer);
        }
    });

    super.onResume();
}

private static class VideoRender implements Renderer,
        SurfaceTexture.OnFrameAvailableListener {
    private static String TAG = "VideoRender";

    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 final String mVertexShader = "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";
    private float[] mMVPMatrix = new float[16];
    private float[] mSTMatrix = new float[16];

    private int mProgram;
    private int mTextureID[] = new int[2];
    private int muMVPMatrixHandle;
    private int muSTMatrixHandle;
    private int maPositionHandle;
    private int maTextureHandle;

    private SurfaceTexture mSurface;
    private boolean updateSurface = false;

    private static int GL_TEXTURE_EXTERNAL_OES = 0x8D65;

    private MediaPlayer mMediaPlayer;

    public VideoRender(Context context) {
        mTriangleVertices = ByteBuffer
                .allocateDirect(
                        mTriangleVerticesData.length * FLOAT_SIZE_BYTES)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        mTriangleVertices.put(mTriangleVerticesData).position(0);

        Matrix.setIdentityM(mSTMatrix, 0);
    }

    public void setMediaPlayer(MediaPlayer player) {
        mMediaPlayer = player;
    }

    @Override
    public void onDrawFrame(GL10 glUnused) {
        synchronized (this) {
            if (updateSurface) {
                mSurface.updateTexImage();
                mSurface.getTransformMatrix(mSTMatrix);
                updateSurface = false;
            }
        }
        mProgram = createProgram(mVertexShader,
                effect.getShader(mSurfaceView));
        GLES20.glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT
                | GLES20.GL_COLOR_BUFFER_BIT);

        GLES20.glUseProgram(mProgram);
        checkGlError("glUseProgram");

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID[0]);

        mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
        GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
                false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES,
                mTriangleVertices);
        checkGlError("glVertexAttribPointer maPosition");
        GLES20.glEnableVertexAttribArray(maPositionHandle);
        checkGlError("glEnableVertexAttribArray maPositionHandle");

        mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
        GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT,
                false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES,
                mTriangleVertices);
        checkGlError("glVertexAttribPointer maTextureHandle");
        GLES20.glEnableVertexAttribArray(maTextureHandle);
        checkGlError("glEnableVertexAttribArray maTextureHandle");

        Matrix.setIdentityM(mMVPMatrix, 0);
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix,
                0);
        GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        checkGlError("glDrawArrays");
        GLES20.glFinish();

    }

    @Override
    public void onSurfaceChanged(GL10 glUnused, int width, int height) {

    }

    @Override
    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {

        mProgram = createProgram(mVertexShader,
                effect.getShader(mSurfaceView));
        if (mProgram == 0) {
            return;
        }
        maPositionHandle = GLES20
                .glGetAttribLocation(mProgram, "aPosition");
        checkGlError("glGetAttribLocation aPosition");
        if (maPositionHandle == -1) {
            throw new RuntimeException(
                    "Could not get attrib location for aPosition");
        }
        maTextureHandle = GLES20.glGetAttribLocation(mProgram,
                "aTextureCoord");
        checkGlError("glGetAttribLocation aTextureCoord");
        if (maTextureHandle == -1) {
            throw new RuntimeException(
                    "Could not get attrib location for aTextureCoord");
        }

        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram,
                "uMVPMatrix");
        checkGlError("glGetUniformLocation uMVPMatrix");
        if (muMVPMatrixHandle == -1) {
            throw new RuntimeException(
                    "Could not get attrib location for uMVPMatrix");
        }

        muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram,
                "uSTMatrix");
        checkGlError("glGetUniformLocation uSTMatrix");
        if (muSTMatrixHandle == -1) {
            throw new RuntimeException(
                    "Could not get attrib location for uSTMatrix");
        }

        // int[] textures = new int[1];
        GLES20.glGenTextures(2, mTextureID, 0);
        // GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID[0]);

        // mTextureID = textures[0];
        GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID[0]);
        checkGlError("glBindTexture mTextureID");

        // GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES,
        // GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        // GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES,
        // GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        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);

        /*
         * Create the SurfaceTexture that will feed this textureID, and pass
         * it to the MediaPlayer
         */
        mSurface = new SurfaceTexture(mTextureID[0]);
        mSurface.setOnFrameAvailableListener(this);

        Surface surface = new Surface(mSurface);
        mMediaPlayer.setSurface(surface);
        mMediaPlayer.setScreenOnWhilePlaying(true);
        surface.release();

        try {
            mMediaPlayer.prepare();
        } catch (IOException t) {
            Log.e(TAG, "media player prepare failed");
        }

        synchronized (this) {
            updateSurface = false;
        }

        mMediaPlayer.start();
    }

    @Override
    synchronized public void onFrameAvailable(SurfaceTexture surface) {
        updateSurface = true;
    }

    private int loadShader(int shaderType, String source) {
        int shader = GLES20.glCreateShader(shaderType);
        if (shader != 0) {
            GLES20.glShaderSource(shader, source);
            GLES20.glCompileShader(shader);
            int[] compiled = new int[1];
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS,
                    compiled, 0);
            if (compiled[0] == 0) {
                Log.e(TAG, "Could not compile shader " + shaderType + ":");
                Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }

    private int createProgram(String vertexSource, String fragmentSource) {
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) {
            return 0;
        }
        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
                fragmentSource);
        if (pixelShader == 0) {
            return 0;
        }

        int program = GLES20.glCreateProgram();
        if (program != 0) {
            GLES20.glAttachShader(program, vertexShader);
            checkGlError("glAttachShader");
            GLES20.glAttachShader(program, pixelShader);
            checkGlError("glAttachShader");
            GLES20.glLinkProgram(program);
            int[] linkStatus = new int[1];
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS,
                    linkStatus, 0);
            if (linkStatus[0] != GLES20.GL_TRUE) {
                Log.e(TAG, "Could not link program: ");
                Log.e(TAG, GLES20.glGetProgramInfoLog(program));
                GLES20.glDeleteProgram(program);
                program = 0;
            }
        }
        return program;
    }

    private void checkGlError(String op) {
        int error;
        if ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e(TAG, op + ": glError " + error);
            throw new RuntimeException(op + ": glError " + error);
        }
    }

  } // End of class VideoRender.

} // End of class VideoSurfaceView.

"checkGLError" 方法 returns 1282。这是它第一次这样做,我不明白为什么。

我在 Stack 上搜索了答案,但没有找到适合这种情况的答案。您能否就应该更改的内容发表您的意见?

我认为问题出在您设置 UV 数据的位置:

GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT,
                             false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES,
                             mTriangleVertices);

你没有 3 个 UV 值,你有 2 个,所以你 运行 超出了数组的末尾。在正常的原生 C OpenGL ES 中,这可能会出现段错误; Java 允许对数组进行边界检查意味着您会抛出错误。

问题在于 Gamma 着色器的创建方式。在没有编译器的情况下编辑 C 代码有点棘手,我不得不进行一些更改和代码的最终版本:

public class GammaEffect implements ShaderInterface {
/**
 * Initialize Effect
 */
public GammaEffect() {
}

@Override
public String getShader(GLSurfaceView mGlSurfaceView) {

    String shader = "#extension GL_OES_EGL_image_external : require\n"

            +"precision mediump float;\n"
            +"uniform samplerExternalOES sTexture;\n"
            +"varying vec2 vTextureCoord;\n"
            +"float gamma;\n"

            +"void main() {\n"

            +"gamma = 2.0;\n"

    +"vec4 color = texture2D(sTexture, vTextureCoord);\n"
            +"gl_FragColor = vec4(pow(color.rgb, vec3(gamma)), color.a);\n"

            +"}\n";

return shader;

    }
}

很有魅力。希望对想学习GLSL的程序员有所帮助!