blob: fc4ebae387f3f04102e335a262d9f9110f9de4b0 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.cts.hardware;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.hardware.SyncFence;
import android.opengl.EGL14;
import android.opengl.EGL15;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLExt;
import android.opengl.EGLSurface;
import android.opengl.EGLSync;
import android.opengl.GLES20;
public class SyncFenceUtil {
public static SyncFence createUselessFence() {
EGLDisplay eglDisplay = EGL15.EGL_NO_DISPLAY;
EGLConfig eglConfig = null;
EGLSurface eglPbuffer = EGL15.EGL_NO_SURFACE;
EGLContext eglContext = EGL15.EGL_NO_CONTEXT;
int error;
eglDisplay = EGL15.eglGetPlatformDisplay(EGL15.EGL_PLATFORM_ANDROID_KHR,
EGL14.EGL_DEFAULT_DISPLAY,
new long[] {
EGL14.EGL_NONE },
0);
if (eglDisplay == EGL15.EGL_NO_DISPLAY) {
throw new RuntimeException("no EGL display");
}
error = EGL14.eglGetError();
if (error != EGL14.EGL_SUCCESS) {
throw new RuntimeException("eglGetPlatformDisplay failed");
}
int[] major = new int[1];
int[] minor = new int[1];
if (!EGL14.eglInitialize(eglDisplay, major, 0, minor, 0)) {
throw new RuntimeException("error in eglInitialize");
}
error = EGL14.eglGetError();
if (error != EGL14.EGL_SUCCESS) {
throw new RuntimeException("eglInitialize failed");
}
// If we could rely on having EGL_KHR_surfaceless_context and EGL_KHR_context_no_config, we
// wouldn't have to create a config or pbuffer at all.
int[] numConfigs = new int[1];
EGLConfig[] configs = new EGLConfig[1];
if (!EGL14.eglChooseConfig(eglDisplay,
new int[] {
EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT,
EGL14.EGL_NONE},
0, configs, 0, 1, numConfigs, 0)) {
throw new RuntimeException("eglChooseConfig failed");
}
error = EGL14.eglGetError();
if (error != EGL14.EGL_SUCCESS) {
throw new RuntimeException("eglChooseConfig failed");
}
eglConfig = configs[0];
eglPbuffer = EGL14.eglCreatePbufferSurface(eglDisplay, eglConfig,
new int[] {EGL14.EGL_WIDTH, 1, EGL14.EGL_HEIGHT, 1, EGL14.EGL_NONE}, 0);
if (eglPbuffer == EGL15.EGL_NO_SURFACE) {
throw new RuntimeException("eglCreatePbufferSurface failed");
}
error = EGL14.eglGetError();
if (error != EGL14.EGL_SUCCESS) {
throw new RuntimeException("eglCreatePbufferSurface failed");
}
eglContext = EGL14.eglCreateContext(eglDisplay, eglConfig, EGL14.EGL_NO_CONTEXT,
new int[] {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE}, 0);
if (eglContext == EGL15.EGL_NO_CONTEXT) {
throw new RuntimeException("eglCreateContext failed");
}
error = EGL14.eglGetError();
if (error != EGL14.EGL_SUCCESS) {
throw new RuntimeException("eglCreateContext failed");
}
if (!EGL14.eglMakeCurrent(eglDisplay, eglPbuffer, eglPbuffer, eglContext)) {
throw new RuntimeException("eglMakeCurrent failed");
}
error = EGL14.eglGetError();
if (error != EGL14.EGL_SUCCESS) {
throw new RuntimeException("eglMakeCurrent failed");
}
SyncFence nativeFence = null;
String eglExtensions = EGL14.eglQueryString(eglDisplay, EGL14.EGL_EXTENSIONS);
if (eglExtensions.contains("EGL_ANDROID_native_fence_sync")) {
EGLSync sync = EGL15.eglCreateSync(eglDisplay, EGLExt.EGL_SYNC_NATIVE_FENCE_ANDROID,
new long[] {
EGL14.EGL_NONE },
0);
assertNotEquals(sync, EGL15.EGL_NO_SYNC);
assertEquals(EGL14.EGL_SUCCESS, EGL14.eglGetError());
nativeFence = EGLExt.eglDupNativeFenceFDANDROID(eglDisplay, sync);
assertNotNull(nativeFence);
assertEquals(EGL14.EGL_SUCCESS, EGL14.eglGetError());
// If the fence isn't valid, trigger a flush & try again
if (!nativeFence.isValid()) {
GLES20.glFlush();
assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError());
// Have flushed, native fence should be populated
nativeFence = EGLExt.eglDupNativeFenceFDANDROID(eglDisplay, sync);
assertNotNull(nativeFence);
assertTrue(nativeFence.isValid());
assertEquals(EGL14.EGL_SUCCESS, EGL14.eglGetError());
}
assertTrue(EGL15.eglDestroySync(eglDisplay, sync));
}
EGL14.eglTerminate(eglDisplay);
return nativeFence;
}
}