GL: Request OpenGL ES 3.0 context on API 29+, with fallback to 2.0.

Despite GL 3.0 not being required on API 29+, it is experimentally
determined to always be supported on our testing devices, on API 29+.

That said, still fall back to OpenGL 2.0 if 3.0 is not supported,
just in case.

PiperOrigin-RevId: 590569772
This commit is contained in:
huangdarwin 2023-12-13 05:58:48 -08:00 committed by Copybara-Service
parent 2fa5430417
commit a15dfd75be
3 changed files with 78 additions and 21 deletions

View File

@ -366,11 +366,23 @@ public final class GlUtil {
return eglSurface;
}
/**
* Returns the {@link EGL14#EGL_CONTEXT_CLIENT_VERSION} of the current context.
*
* <p>Returns {@code 0} if no {@link EGLContext} {@linkplain #createFocusedPlaceholderEglSurface
* is focused}.
*/
@RequiresApi(17)
public static long getContextMajorVersion() throws GlException {
return Api17.getContextMajorVersion();
}
/**
* Returns a newly created sync object and inserts it into the GL command stream.
*
* <p>Returns {@code 0} if the operation failed or the {@link EGLContext} version is less than
* 3.0.
* <p>Returns {@code 0} if the operation failed, no {@link EGLContext} {@linkplain
* #createFocusedPlaceholderEglSurface is focused}, or the focused {@link EGLContext} version is
* less than 3.0.
*/
@RequiresApi(17)
public static long createGlSyncFence() throws GlException {

View File

@ -19,6 +19,7 @@ import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.common.util.Util.SDK_INT;
import static androidx.media3.effect.DebugTraceUtil.EVENT_VFP_RECEIVE_END_OF_INPUT;
import static androidx.media3.effect.DebugTraceUtil.EVENT_VFP_REGISTER_NEW_INPUT_STREAM;
import static androidx.media3.effect.DebugTraceUtil.EVENT_VFP_SIGNAL_ENDED;
@ -637,18 +638,20 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
ColorInfo.isTransferHdr(outputColorInfo)
? GlUtil.EGL_CONFIG_ATTRIBUTES_RGBA_1010102
: GlUtil.EGL_CONFIG_ATTRIBUTES_RGBA_8888;
int openGlVersion =
ColorInfo.isTransferHdr(inputColorInfo) || ColorInfo.isTransferHdr(outputColorInfo) ? 3 : 2;
EGLContext eglContext =
glObjectsProvider.createEglContext(eglDisplay, openGlVersion, configAttributes);
glObjectsProvider.createFocusedPlaceholderEglSurface(eglContext, eglDisplay);
createFocusedEglContextWithFallback(glObjectsProvider, eglDisplay, configAttributes);
if ((ColorInfo.isTransferHdr(inputColorInfo) || ColorInfo.isTransferHdr(outputColorInfo))
&& GlUtil.getContextMajorVersion() != 3) {
throw new VideoFrameProcessingException(
"OpenGL ES 3.0 context support is required for HDR input or output.");
}
// Not renderFramesAutomatically means outputting to a display surface. HDR display surfaces
// require the BT2020 PQ GL extension.
if (!renderFramesAutomatically && ColorInfo.isTransferHdr(outputColorInfo)) {
// Display hardware supports PQ only.
checkArgument(outputColorInfo.colorTransfer == C.COLOR_TRANSFER_ST2084);
if (Util.SDK_INT < 33 || !GlUtil.isBt2020PqExtensionSupported()) {
if (SDK_INT < 33 || !GlUtil.isBt2020PqExtensionSupported()) {
GlUtil.destroyEglContext(eglDisplay, eglContext);
// On API<33, the system cannot display PQ content correctly regardless of whether BT2020 PQ
// GL extension is supported.
@ -882,6 +885,43 @@ 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(
GlObjectsProvider glObjectsProvider, EGLDisplay eglDisplay, int[] configAttributes)
throws GlUtil.GlException {
if (SDK_INT < 29) {
return createFocusedEglContext(
glObjectsProvider, eglDisplay, /* openGlVersion= */ 2, configAttributes);
}
try {
return createFocusedEglContext(
glObjectsProvider, eglDisplay, /* openGlVersion= */ 3, configAttributes);
} catch (GlUtil.GlException e) {
return createFocusedEglContext(
glObjectsProvider, eglDisplay, /* openGlVersion= */ 2, configAttributes);
}
}
/**
* Creates an {@link EGLContext} and focus it using a {@linkplain
* GlObjectsProvider#createFocusedPlaceholderEglSurface placeholder EGL Surface}.
*/
private static EGLContext createFocusedEglContext(
GlObjectsProvider glObjectsProvider,
EGLDisplay eglDisplay,
int openGlVersion,
int[] configAttributes)
throws GlUtil.GlException {
EGLContext eglContext =
glObjectsProvider.createEglContext(eglDisplay, openGlVersion, configAttributes);
// 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,
// if successfully created, are valid. Check early whether the context is really valid.
glObjectsProvider.createFocusedPlaceholderEglSurface(eglContext, eglDisplay);
return eglContext;
}
private static final class InputStreamInfo {
public final @InputType int inputType;
public final List<Effect> effects;

View File

@ -48,6 +48,7 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -268,13 +269,15 @@ public final class HdrEditingTest {
assertThat(isToneMappingFallbackApplied.get()).isTrue();
assertFileHasColorTransfer(context, exportTestResult.filePath, C.COLOR_TRANSFER_SDR);
} catch (ExportException exception) {
if (exception.getCause() != null
&& (Objects.equals(
exception.getCause().getMessage(),
"Decoding HDR is not supported on this device.")
|| Objects.equals(
exception.getCause().getMessage(), "Device lacks YUV extension support."))) {
return;
if (exception.getCause() != null) {
@Nullable String message = exception.getCause().getMessage();
if (message != null
&& (Objects.equals(message, "Decoding HDR is not supported on this device.")
|| message.contains(
"OpenGL ES 3.0 context support is required for HDR input or output.")
|| Objects.equals(message, "Device lacks YUV extension support."))) {
return;
}
}
throw exception;
}
@ -330,13 +333,15 @@ public final class HdrEditingTest {
assertThat(isToneMappingFallbackApplied.get()).isTrue();
assertFileHasColorTransfer(context, exportTestResult.filePath, C.COLOR_TRANSFER_SDR);
} catch (ExportException exception) {
if (exception.getCause() != null
&& (Objects.equals(
exception.getCause().getMessage(),
"Decoding HDR is not supported on this device.")
|| Objects.equals(
exception.getCause().getMessage(), "Device lacks YUV extension support."))) {
return;
if (exception.getCause() != null) {
@Nullable String message = exception.getCause().getMessage();
if (message != null
&& (Objects.equals(message, "Decoding HDR is not supported on this device.")
|| message.contains(
"OpenGL ES 3.0 context support is required for HDR input or output.")
|| Objects.equals(message, "Device lacks YUV extension support."))) {
return;
}
}
throw exception;
}