Destroy EGLSurface immediately by focusing a placeholder surface

eglDestroySurface only destroys the surface when it's made not current.
Pass the placeholder surface in FinalShaderProgramWrapper and use it
when destroying eglSurface.

PiperOrigin-RevId: 655139661
This commit is contained in:
dancho 2024-07-23 06:18:09 -07:00 committed by Copybara-Service
parent 9c075b692e
commit 1797359950
2 changed files with 42 additions and 17 deletions

View File

@ -32,8 +32,10 @@ import android.graphics.Bitmap;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.opengl.EGLContext; import android.opengl.EGLContext;
import android.opengl.EGLDisplay; import android.opengl.EGLDisplay;
import android.opengl.EGLSurface;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.opengl.GLES30; import android.opengl.GLES30;
import android.util.Pair;
import android.view.Surface; import android.view.Surface;
import androidx.annotation.GuardedBy; import androidx.annotation.GuardedBy;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
@ -813,7 +815,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
ColorInfo.isTransferHdr(outputColorInfo) ColorInfo.isTransferHdr(outputColorInfo)
? GlUtil.EGL_CONFIG_ATTRIBUTES_RGBA_1010102 ? GlUtil.EGL_CONFIG_ATTRIBUTES_RGBA_1010102
: GlUtil.EGL_CONFIG_ATTRIBUTES_RGBA_8888; : GlUtil.EGL_CONFIG_ATTRIBUTES_RGBA_8888;
EGLContext eglContext = Pair<EGLContext, EGLSurface> eglContextAndPlaceholderSurface =
createFocusedEglContextWithFallback(glObjectsProvider, eglDisplay, configAttributes); createFocusedEglContextWithFallback(glObjectsProvider, eglDisplay, configAttributes);
ColorInfo linearColorInfo = ColorInfo linearColorInfo =
@ -845,7 +847,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
new FinalShaderProgramWrapper( new FinalShaderProgramWrapper(
context, context,
eglDisplay, eglDisplay,
eglContext, eglContextAndPlaceholderSurface.first,
eglContextAndPlaceholderSurface.second,
debugViewProvider, debugViewProvider,
outputColorInfo, outputColorInfo,
videoFrameProcessingTaskExecutor, videoFrameProcessingTaskExecutor,
@ -860,7 +863,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
context, context,
glObjectsProvider, glObjectsProvider,
eglDisplay, eglDisplay,
eglContext, eglContextAndPlaceholderSurface.first,
inputSwitcher, inputSwitcher,
videoFrameProcessingTaskExecutor, videoFrameProcessingTaskExecutor,
listener, listener,
@ -1100,8 +1103,12 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
} }
} }
/** Creates an OpenGL ES 3.0 context if possible, and an OpenGL ES 2.0 context otherwise. */ /**
private static EGLContext createFocusedEglContextWithFallback( * Creates an OpenGL ES 3.0 context if possible, and an OpenGL ES 2.0 context otherwise.
*
* <p>See {@link #createFocusedEglContext}.
*/
private static Pair<EGLContext, EGLSurface> createFocusedEglContextWithFallback(
GlObjectsProvider glObjectsProvider, EGLDisplay eglDisplay, int[] configAttributes) GlObjectsProvider glObjectsProvider, EGLDisplay eglDisplay, int[] configAttributes)
throws GlUtil.GlException { throws GlUtil.GlException {
if (SDK_INT < 29) { if (SDK_INT < 29) {
@ -1121,8 +1128,10 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
/** /**
* Creates an {@link EGLContext} and focus it using a {@linkplain * Creates an {@link EGLContext} and focus it using a {@linkplain
* GlObjectsProvider#createFocusedPlaceholderEglSurface placeholder EGL Surface}. * GlObjectsProvider#createFocusedPlaceholderEglSurface placeholder EGL Surface}.
*
* @return The {@link EGLContext} and a placeholder {@link EGLSurface} as a {@link Pair}.
*/ */
private static EGLContext createFocusedEglContext( private static Pair<EGLContext, EGLSurface> createFocusedEglContext(
GlObjectsProvider glObjectsProvider, GlObjectsProvider glObjectsProvider,
EGLDisplay eglDisplay, EGLDisplay eglDisplay,
int openGlVersion, int openGlVersion,
@ -1133,8 +1142,9 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
// Some OpenGL ES 3.0 contexts returned from createEglContext may throw EGL_BAD_MATCH when being // Some OpenGL ES 3.0 contexts returned from createEglContext may throw EGL_BAD_MATCH when being
// used to createFocusedPlaceHolderEglSurface, despite GL documentation suggesting the contexts, // used to createFocusedPlaceHolderEglSurface, despite GL documentation suggesting the contexts,
// if successfully created, are valid. Check early whether the context is really valid. // if successfully created, are valid. Check early whether the context is really valid.
glObjectsProvider.createFocusedPlaceholderEglSurface(eglContext, eglDisplay); EGLSurface eglSurface =
return eglContext; glObjectsProvider.createFocusedPlaceholderEglSurface(eglContext, eglDisplay);
return Pair.create(eglContext, eglSurface);
} }
private static final class InputStreamInfo { private static final class InputStreamInfo {

View File

@ -83,6 +83,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final List<RgbMatrix> rgbMatrices; private final List<RgbMatrix> rgbMatrices;
private final EGLDisplay eglDisplay; private final EGLDisplay eglDisplay;
private final EGLContext eglContext; private final EGLContext eglContext;
private final EGLSurface placeholderSurface;
private final DebugViewProvider debugViewProvider; private final DebugViewProvider debugViewProvider;
private final ColorInfo outputColorInfo; private final ColorInfo outputColorInfo;
private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor; private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor;
@ -129,6 +130,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
Context context, Context context,
EGLDisplay eglDisplay, EGLDisplay eglDisplay,
EGLContext eglContext, EGLContext eglContext,
EGLSurface placeholderSurface,
DebugViewProvider debugViewProvider, DebugViewProvider debugViewProvider,
ColorInfo outputColorInfo, ColorInfo outputColorInfo,
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor, VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor,
@ -143,6 +145,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
this.rgbMatrices = new ArrayList<>(); this.rgbMatrices = new ArrayList<>();
this.eglDisplay = eglDisplay; this.eglDisplay = eglDisplay;
this.eglContext = eglContext; this.eglContext = eglContext;
this.placeholderSurface = placeholderSurface;
this.debugViewProvider = debugViewProvider; this.debugViewProvider = debugViewProvider;
this.outputColorInfo = outputColorInfo; this.outputColorInfo = outputColorInfo;
this.videoFrameProcessingTaskExecutor = videoFrameProcessingTaskExecutor; this.videoFrameProcessingTaskExecutor = videoFrameProcessingTaskExecutor;
@ -354,16 +357,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// outputEglSurface is a graphics buffer producer for a BufferQueue, and // outputEglSurface is a graphics buffer producer for a BufferQueue, and
// this.outputSurfaceInfo.surface is the associated consumer. The consumer owns the // this.outputSurfaceInfo.surface is the associated consumer. The consumer owns the
// BufferQueue https://source.android.com/docs/core/graphics/arch-bq-gralloc#BufferQueue. // BufferQueue https://source.android.com/docs/core/graphics/arch-bq-gralloc#BufferQueue.
// If the consumer and the BufferQueue are released while the producer is still alive, EGL // If the BufferQueue is released while the producer is still alive, EGL gets stuck trying
// gets stuck trying to dequeue a new buffer from the released BufferQueue. This probably // to dequeue a new buffer from the released BufferQueue. This probably
// happens when the previously queued back buffer is ready for display. // happens when the previously queued back buffer is ready for display.
try { destroyOutputEglSurface();
GlUtil.destroyEglSurface(eglDisplay, outputEglSurface);
} catch (GlUtil.GlException e) {
videoFrameProcessorListenerExecutor.execute(
() -> videoFrameProcessorListener.onError(VideoFrameProcessingException.from(e)));
}
this.outputEglSurface = null;
} }
outputSurfaceInfoChanged = outputSurfaceInfoChanged =
this.outputSurfaceInfo == null this.outputSurfaceInfo == null
@ -374,6 +371,24 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
this.outputSurfaceInfo = outputSurfaceInfo; this.outputSurfaceInfo = outputSurfaceInfo;
} }
private synchronized void destroyOutputEglSurface() {
if (outputEglSurface == null) {
return;
}
try {
// outputEglSurface will be destroyed only if it's not current.
// See EGL docs. Make the placeholder surface current before destroying.
GlUtil.focusEglSurface(
eglDisplay, eglContext, placeholderSurface, /* width= */ 1, /* height= */ 1);
GlUtil.destroyEglSurface(eglDisplay, outputEglSurface);
} catch (GlUtil.GlException e) {
videoFrameProcessorListenerExecutor.execute(
() -> videoFrameProcessorListener.onError(VideoFrameProcessingException.from(e)));
} finally {
this.outputEglSurface = null;
}
}
private synchronized void renderFrame( private synchronized void renderFrame(
GlObjectsProvider glObjectsProvider, GlObjectsProvider glObjectsProvider,
GlTextureInfo inputTexture, GlTextureInfo inputTexture,