From 3afbfad181fde57223cc4a15ed3402d4f11cc58d Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 9 Mar 2021 16:16:38 -0800 Subject: [PATCH] Add async mode tests for BLAST Add some tests to validate dequeue blocking behavior when the IGBP is configured in async mode. We want to validate that in this mode, with or without blast, the client will not be blocked when dequeuing a buffer. Instead, when the client tries to queue a buffer, the bufferqueue will drop the queued buffer if it exists. In async mode, the bufferqueue in the will have an additional buffer so for blast: one buffer will be acquired and presented, one buffer will be acquired in the queue, and the client will have two buffers left for non blocking dequeue. When queuing a buffer, the BQ in the adapter will drop the last queued buffer if available. Test: atest BufferPresentationTests Bug: 176916466 Change-Id: I6ff45c24d6529cc7cd4169f962eb2ca9cbc09943 --- .../cpp/SurfaceProxy.cpp | 25 ++++++ .../android/test/BufferPresentationTests.kt | 77 +++++++++++++++++++ .../src/com/android/test/SurfaceProxy.kt | 8 +- 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp b/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp index ce226fdce320..926ff4d5793c 100644 --- a/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp +++ b/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp @@ -130,6 +130,9 @@ JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceDequeueBuffer(J return result; } sBuffers[slot] = anb; + if (timeoutMs == 0) { + return android::OK; + } android::sp fence(new android::Fence(fenceFd)); int waitResult = fence->wait(timeoutMs); if (waitResult != android::OK) { @@ -197,6 +200,28 @@ JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceQueueBuffer(JNI return result; } +JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetAsyncMode(JNIEnv* /* env */, + jclass /* clazz */, + jboolean async) { + assert(sAnw); + android::sp surface = static_cast(sAnw); + return surface->setAsyncMode(async); +} + +JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetDequeueTimeout( + JNIEnv* /* env */, jclass /* clazz */, jlong timeoutMs) { + assert(sAnw); + android::sp surface = static_cast(sAnw); + return surface->setDequeueTimeout(timeoutMs); +} + +JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetMaxDequeuedBufferCount( + JNIEnv* /* env */, jclass /* clazz */, jint maxDequeuedBuffers) { + assert(sAnw); + android::sp surface = static_cast(sAnw); + return surface->setMaxDequeuedBufferCount(maxDequeuedBuffers); +} + JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetBufferCount( JNIEnv* /* env */, jclass /* clazz */, jint count) { assert(sAnw); diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt index 7d278dc8acc0..b67dc380efab 100644 --- a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt +++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt @@ -17,6 +17,7 @@ package com.android.test import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat import junit.framework.Assert.assertEquals +import junit.framework.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @@ -93,4 +94,80 @@ class BufferPresentationTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames) } + + @Test + // Leave IGBP in sync mode, try to dequeue and queue as fast as possible. Check that we + // occasionally get timeout errors. + fun testSyncMode_dequeueWithoutBlockingFails() { + val numFrames = 1000L + runOnUiThread { activity -> + assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L)) + var failures = false + for (i in 1..numFrames) { + if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) { + failures = true + break + } + activity.mSurfaceProxy.SurfaceQueueBuffer(0) + } + assertTrue(failures) + } + } + + @Test + // Set IGBP to be in async mode, try to dequeue and queue as fast as possible. Client should be + // able to dequeue and queue buffers without being blocked. + fun testAsyncMode_dequeueWithoutBlocking() { + val numFrames = 1000L + runOnUiThread { activity -> + assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L)) + assertEquals(0, activity.mSurfaceProxy.SurfaceSetAsyncMode(async = true)) + for (i in 1..numFrames) { + assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */)) + activity.mSurfaceProxy.SurfaceQueueBuffer(0) + } + } + } + + @Test + // Disable triple buffering in the system and leave IGBP in sync mode. Check that we + // occasionally get timeout errors. + fun testSyncModeWithDisabledTripleBuffering_dequeueWithoutBlockingFails() { + val numFrames = 1000L + runOnUiThread { activity -> + assertEquals(0, activity.mSurfaceProxy.SurfaceSetMaxDequeuedBufferCount(1)) + assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L)) + var failures = false + for (i in 1..numFrames) { + if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) { + failures = true + break + } + activity.mSurfaceProxy.SurfaceQueueBuffer(0) + } + assertTrue(failures) + } + } + + @Test + // Disable triple buffering in the system and set IGBP to be in async mode. Try to dequeue and + // queue as fast as possible. Without triple buffering, the client does not have an extra buffer + // to dequeue and will not be able to dequeue and queue buffers without being blocked. + fun testAsyncModeWithDisabledTripleBuffering_dequeueWithoutBlockingFails() { + val numFrames = 1000L + runOnUiThread { activity -> + assertEquals(0, activity.mSurfaceProxy.SurfaceSetMaxDequeuedBufferCount(1)) + assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L)) + assertEquals(0, activity.mSurfaceProxy.SurfaceSetAsyncMode(async = true)) + var failures = false + for (i in 1..numFrames) { + if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) { + failures = true + break + } + activity.mSurfaceProxy.SurfaceQueueBuffer(0) + } + assertTrue(failures) + } + } } \ No newline at end of file diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt index cfbd3ac11acb..45a70944204c 100644 --- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt +++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt @@ -54,7 +54,13 @@ class SurfaceProxy { external fun SurfaceSetScalingMode(scalingMode: Int) external fun SurfaceDequeueBuffer(slot: Int, timeoutMs: Int): Int external fun SurfaceCancelBuffer(slot: Int) - external fun SurfaceQueueBuffer(slot: Int, freeSlot: Boolean = true) + external fun SurfaceQueueBuffer(slot: Int, freeSlot: Boolean = true): Int + external fun SurfaceSetAsyncMode(async: Boolean): Int + external fun SurfaceSetDequeueTimeout(timeout: Long): Int + external fun SurfaceQuery(what: Int): Int + external fun SurfaceSetMaxDequeuedBufferCount(maxDequeuedBuffers: Int): Int + + // system/native_window.h functions external fun NativeWindowSetBufferCount(count: Int): Int external fun NativeWindowSetSharedBufferMode(shared: Boolean): Int external fun NativeWindowSetAutoRefresh(autoRefresh: Boolean): Int