Android: рендеринг с SurfaceTexture в FrameBuffer

Я работаю над эффектом, который требует двухпроходного рендеринга (т. е. два отдельных шейдера применяются последовательно). Я использую GLSurfaceView с пользовательским средством визуализации.

Чтобы добиться этого эффекта, я сначала пытаюсь выполнить рендеринг в FrameBuffer, а затем в GL_TEXTURE_2D для отображения в GLSurfaceView.

Соответствующий код в методе OnSurfaceCreated выглядит следующим образом:

        GLES20.glGenTextures(1, this.textureID, 0);
        GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES,this.textureID[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.glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);

        GLES20.glGenTextures(1, textures2D, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures2D[0]);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

        GLES20.glGenFramebuffers(1, fboId, 0);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId[0]);
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textures2D[0], 0);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

Соответствующий код в OnDrawFrame таков:

       synchronized (this) {
            if (this.updateSurface) {
                this.surfaceTexture.updateTexImage();
                this.surfaceTexture.getTransformMatrix(this.stMatrix);
                this.updateSurface = false;
            }
        }

        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId[0]);
        GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, this.textureID[0]);

// apply the first shader

        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures2D[0]);

// apply the second shader

        GLES20.glFinish();

Однако программа аварийно завершает работу из-за ошибки glError 1286, которая, похоже, указывает на недопустимую операцию буфера кадра. Я не уверен, что вызывает эту проблему, хотя я подозреваю, что это может быть связано с тем фактом, что SurfaceTexture связана с текстурой GL_TEXTURE_EXTERNAL_OES, в то время как FrameBuffer выводит текстуру GL_TEXTURE_2D.

Любая помощь или совет будут оценены. Спасибо.


person Michael    schedule 21.02.2016    source источник
comment
Сбой где? Поместите вызовы проверки ошибок после каждой операции GLES и посмотрите, какой именно вызов не работает.   -  person fadden    schedule 21.02.2016
comment
Он аварийно завершает работу при вызове GLES20.glDrawArrays() при применении первого шейдера.   -  person Michael    schedule 21.02.2016
comment
Команда пытается выполнить рендеринг или чтение из кадрового буфера, в то время как текущий связанный кадровый буфер не заполнен (т. е. возвращаемое значение из glCheckFramebufferStatus не равно GL_FRAMEBUFFER_COMPLETE). Ошибочная команда игнорируется и не имеет другого побочного эффекта, кроме установки флага ошибки. Вы звоните glCheckFramebufferStatus()?   -  person fadden    schedule 21.02.2016
comment
glCheckFramebufferStatus() возвращает 0, что, по-видимому, указывает на то, что FrameBuffer не привязан? Я немного смущен, почему, поскольку я, кажется, следую методам, представленным в аналогичных вопросах (например, stackoverflow.com/questions/28137625/)   -  person Michael    schedule 22.02.2016
comment
Есть ряд вещей, которые необходимо сделать, чтобы FBO был завершен; пройдитесь по списку и проверьте их. github.com/google/grafika/ blob/master/src/com/android/grafika/ содержит пример, который работает на Android.   -  person fadden    schedule 22.02.2016
comment
Я рассмотрел такие примеры и некоторые другие. Основное различие между тем, что я делаю, заключается в том, что исходное изображение в моем случае исходит из SurfaceTexture, связанного с GL_TEXTURE_EXTERNAL_OES, а не с GL_TEXTURE_2D. Я не уверен, вызовет ли это проблемы при рендеринге в FrameBuffer или все же можно будет отобразить окончательный результат (GL_TEXTURE_2D) в GLSurfaceView.   -  person Michael    schedule 22.02.2016
comment
Вы не можете использовать внешнюю текстуру в качестве цели FBO, но для этого нет причин. Внешняя текстура не должна иметь отношения к вашей настройке FBO, так как это просто то, что вы сэмплируете во время вашего первого прохода рендеринга.   -  person fadden    schedule 22.02.2016
comment
Я намерен использовать GL_TEXTURE_2D в качестве конечной цели FBO, поэтому я настроил его таким образом в GLES20.glFramebufferTexture2D(). В чем я не уверен, так это в том, как сделать образец FBO из GL_TEXTURE_EXTERNAL_OES для первого прохода рендеринга. Достаточно ли вызвать GLES20.glBindTexture() для текстуры, из которой будет производиться выборка, а затем я просто настроил FBO, как если бы он выполнял выборку из GL_TEXTURE_2D?   -  person Michael    schedule 22.02.2016
comment
Сосредоточьтесь на том, чтобы заставить конвейер вывода работать. Нарисуйте шаблон с несколькими glClear() вызовами и пропустите его через многопроходную систему. Как только это сработает, добавьте внешний источник текстуры.   -  person fadden    schedule 22.02.2016
comment
Кстати, возможно ли вообще выполнить рендеринг в FrameBuffer, прикрепленном к GL_TEXTURE_2D, если источником является GL_TEXTURE_EXTERNAL_OES? Могут ли различия в форматах текстур вызвать конфликт?   -  person Michael    schedule 22.02.2016
comment
Насколько мне известно, нет никакой связи между конфигурацией фреймбуфера и набором операций, которые вам разрешено использовать для его рисования.   -  person fadden    schedule 23.02.2016