Loading tests/SurfaceViewBufferTests/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ android_test { "kotlinx-coroutines-android", "flickerlib", "truth-prebuilt", "cts-wm-util", "CtsSurfaceValidatorLib", ], } Loading @@ -43,6 +45,7 @@ cc_library_shared { ], shared_libs: [ "libutils", "libui", "libgui", "liblog", "libandroid", Loading tests/SurfaceViewBufferTests/AndroidManifest.xml +11 −0 Original line number Diff line number Diff line Loading @@ -23,12 +23,19 @@ <uses-permission android:name="android.permission.DUMP" /> <!-- Enable / Disable sv blast adapter !--> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <!-- Readback virtual display output !--> <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <!-- Save failed test bitmap images !--> <uses-permission android:name="android.Manifest.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="false" android:supportsRtl="true"> <activity android:name=".MainActivity" android:taskAffinity="com.android.test.MainActivity" android:theme="@style/AppTheme" android:configChanges="orientation|screenSize" android:label="SurfaceViewBufferTestApp" android:exported="true"> <intent-filter> Loading @@ -36,6 +43,10 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <service android:name="android.view.cts.surfacevalidator.LocalMediaProjectionService" android:foregroundServiceType="mediaProjection" android:enabled="true"> </service> <uses-library android:name="android.test.runner"/> </application> Loading tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp +124 −3 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ extern "C" { int i = 0; static ANativeWindow* sAnw; static std::map<uint32_t /* slot */, ANativeWindowBuffer*> sBuffers; JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_setSurface(JNIEnv* env, jclass, jobject surfaceObject) { Loading @@ -39,11 +40,14 @@ JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_setSurface(JNIEnv* env assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); surface->enableFrameTimestamps(true); surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false); native_window_set_usage(sAnw, GRALLOC_USAGE_SW_WRITE_OFTEN); native_window_set_buffers_format(sAnw, HAL_PIXEL_FORMAT_RGBA_8888); return 0; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_waitUntilBufferDisplayed( JNIEnv*, jclass, jint jFrameNumber, jint timeoutSec) { JNIEnv*, jclass, jlong jFrameNumber, jint timeoutMs) { using namespace std::chrono_literals; assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); Loading @@ -63,8 +67,8 @@ JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_waitUntilBufferDisplay &outDisplayPresentTime, &outDequeueReadyTime, &outReleaseTime); if (outDisplayPresentTime < 0) { auto end = std::chrono::steady_clock::now(); if (std::chrono::duration_cast<std::chrono::seconds>(end - start).count() > timeoutSec) { if (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() > timeoutMs) { return -1; } } Loading Loading @@ -99,4 +103,121 @@ JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffer assert(sAnw); return ANativeWindow_setBuffersGeometry(sAnw, w, h, format); } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersTransform( JNIEnv* /* env */, jclass /* clazz */, jint transform) { assert(sAnw); return native_window_set_buffers_transform(sAnw, transform); } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetScalingMode(JNIEnv* /* env */, jclass /* clazz */, jint scalingMode) { assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); return surface->setScalingMode(scalingMode); } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceDequeueBuffer(JNIEnv* /* env */, jclass /* clazz */, jint slot, jint timeoutMs) { assert(sAnw); ANativeWindowBuffer* anb; int fenceFd; int result = sAnw->dequeueBuffer(sAnw, &anb, &fenceFd); if (result != android::OK) { return result; } sBuffers[slot] = anb; android::sp<android::Fence> fence(new android::Fence(fenceFd)); int waitResult = fence->wait(timeoutMs); if (waitResult != android::OK) { sAnw->cancelBuffer(sAnw, sBuffers[slot], -1); sBuffers[slot] = nullptr; return waitResult; } return 0; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceCancelBuffer(JNIEnv* /* env */, jclass /* clazz */, jint slot) { assert(sAnw); assert(sBuffers[slot]); int result = sAnw->cancelBuffer(sAnw, sBuffers[slot], -1); sBuffers[slot] = nullptr; return result; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_drawBuffer(JNIEnv* env, jclass /* clazz */, jint slot, jintArray jintArrayColor) { assert(sAnw); assert(sBuffers[slot]); int* color = env->GetIntArrayElements(jintArrayColor, nullptr); ANativeWindowBuffer* buffer = sBuffers[slot]; android::sp<android::GraphicBuffer> graphicBuffer(static_cast<android::GraphicBuffer*>(buffer)); const android::Rect bounds(buffer->width, buffer->height); android::Region newDirtyRegion; newDirtyRegion.set(bounds); void* vaddr; int fenceFd = -1; graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, newDirtyRegion.bounds(), &vaddr, fenceFd); for (int32_t row = 0; row < buffer->height; row++) { uint8_t* dst = static_cast<uint8_t*>(vaddr) + (buffer->stride * row) * 4; for (int32_t column = 0; column < buffer->width; column++) { dst[0] = color[0]; dst[1] = color[1]; dst[2] = color[2]; dst[3] = color[3]; dst += 4; } } graphicBuffer->unlockAsync(&fenceFd); env->ReleaseIntArrayElements(jintArrayColor, color, JNI_ABORT); return 0; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceQueueBuffer(JNIEnv* /* env */, jclass /* clazz */, jint slot, jboolean freeSlot) { assert(sAnw); assert(sBuffers[slot]); int result = sAnw->queueBuffer(sAnw, sBuffers[slot], -1); if (freeSlot) { sBuffers[slot] = nullptr; } return result; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetBufferCount( JNIEnv* /* env */, jclass /* clazz */, jint count) { assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); int result = native_window_set_buffer_count(sAnw, count); return result; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetSharedBufferMode( JNIEnv* /* env */, jclass /* clazz */, jboolean shared) { assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); int result = native_window_set_shared_buffer_mode(sAnw, shared); return result; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetAutoRefresh( JNIEnv* /* env */, jclass /* clazz */, jboolean autoRefresh) { assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); int result = native_window_set_auto_refresh(sAnw, autoRefresh); return result; } } No newline at end of file tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt 0 → 100644 +93 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.test import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat import junit.framework.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @RunWith(Parameterized::class) class BufferPresentationTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) { /** Submit buffers as fast as possible and make sure they are presented on display */ @Test fun testQueueBuffers() { val numFrames = 100L val trace = withTrace { for (i in 1..numFrames) { it.mSurfaceProxy.ANativeWindowLock() it.mSurfaceProxy.ANativeWindowUnlockAndPost() } assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(numFrames, 1000 /* ms */)) } assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames) } @Test fun testSetBufferScalingMode_outOfOrderQueueBuffer() { val trace = withTrace { assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */)) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */)) it.mSurfaceProxy.SurfaceQueueBuffer(1) it.mSurfaceProxy.SurfaceQueueBuffer(0) assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(2, 5000 /* ms */)) } assertThat(trace).hasFrameSequence("SurfaceView", 1..2L) } @Test fun testSetBufferScalingMode_multipleDequeueBuffer() { val numFrames = 20L val trace = withTrace { for (count in 1..(numFrames / 2)) { assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */)) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */)) it.mSurfaceProxy.SurfaceQueueBuffer(0) it.mSurfaceProxy.SurfaceQueueBuffer(1) } assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(numFrames, 5000 /* ms */)) } assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames) } @Test fun testSetBufferCount_queueMaxBufferCountMinusOne() { val numBufferCount = 8 val numFrames = numBufferCount * 5L val trace = withTrace { assertEquals(0, it.mSurfaceProxy.NativeWindowSetBufferCount(numBufferCount + 1)) for (i in 1..numFrames / numBufferCount) { for (bufferSlot in 0..numBufferCount - 1) { assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(bufferSlot, 1000 /* ms */)) } for (bufferSlot in 0..numBufferCount - 1) { it.mSurfaceProxy.SurfaceQueueBuffer(bufferSlot) } } assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(numFrames, 5000 /* ms */)) } assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames) } } No newline at end of file tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt 0 → 100644 +151 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.test import android.graphics.Point import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode import com.android.test.SurfaceViewBufferTestBase.Companion.Transform import junit.framework.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @RunWith(Parameterized::class) class BufferRejectionTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) { @Test fun testSetBuffersGeometry_0x0_rejectsBuffer() { val trace = withTrace { it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, 100, 100, R8G8B8A8_UNORM) it.mSurfaceProxy.ANativeWindowLock() it.mSurfaceProxy.ANativeWindowUnlockAndPost() it.mSurfaceProxy.ANativeWindowLock() it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, 0, 0, R8G8B8A8_UNORM) // Submit buffer one with a different size which should be rejected it.mSurfaceProxy.ANativeWindowUnlockAndPost() // submit a buffer with the default buffer size it.mSurfaceProxy.ANativeWindowLock() it.mSurfaceProxy.ANativeWindowUnlockAndPost() it.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */) } // Verify we reject buffers since scaling mode == NATIVE_WINDOW_SCALING_MODE_FREEZE assertThat(trace).layer("SurfaceView", 2).doesNotExist() // Verify the next buffer is submitted with the correct size assertThat(trace).layer("SurfaceView", 3).also { it.hasBufferSize(defaultBufferSize) // scaling mode is not passed down to the layer for blast if (useBlastAdapter) { it.hasScalingMode(ScalingMode.SCALE_TO_WINDOW.ordinal) } else { it.hasScalingMode(ScalingMode.FREEZE.ordinal) } } } @Test fun testSetBufferScalingMode_freeze() { val bufferSize = Point(300, 200) val trace = withTrace { it.drawFrame() assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0) it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, bufferSize, R8G8B8A8_UNORM) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */)) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */)) // Change buffer size and set scaling mode to freeze it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, Point(0, 0), R8G8B8A8_UNORM) // first dequeued buffer does not have the new size so it should be rejected. it.mSurfaceProxy.SurfaceQueueBuffer(0) it.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW) it.mSurfaceProxy.SurfaceQueueBuffer(1) assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0) } // verify buffer size is reset to default buffer size assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize) assertThat(trace).layer("SurfaceView", 2).doesNotExist() assertThat(trace).layer("SurfaceView", 3).hasBufferSize(bufferSize) } @Test fun testSetBufferScalingMode_freeze_withBufferRotation() { val rotatedBufferSize = Point(defaultBufferSize.y, defaultBufferSize.x) val trace = withTrace { it.drawFrame() assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0) it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, rotatedBufferSize, R8G8B8A8_UNORM) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */)) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */)) // Change buffer size and set scaling mode to freeze it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, Point(0, 0), R8G8B8A8_UNORM) // first dequeued buffer does not have the new size so it should be rejected. it.mSurfaceProxy.SurfaceQueueBuffer(0) // add a buffer transform so the buffer size is correct. it.mSurfaceProxy.ANativeWindowSetBuffersTransform(Transform.ROT_90) it.mSurfaceProxy.SurfaceQueueBuffer(1) assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0) } // verify buffer size is reset to default buffer size assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize) assertThat(trace).layer("SurfaceView", 2).doesNotExist() assertThat(trace).layer("SurfaceView", 3).hasBufferSize(rotatedBufferSize) assertThat(trace).layer("SurfaceView", 3).hasBufferOrientation(Transform.ROT_90.value) } @Test fun testRejectedBuffersAreReleased() { val bufferSize = Point(300, 200) val trace = withTrace { for (count in 0 until 5) { it.drawFrame() assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed((count * 3) + 1L, 500 /* ms */), 0) it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, bufferSize, R8G8B8A8_UNORM) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */)) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */)) // Change buffer size and set scaling mode to freeze it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, Point(0, 0), R8G8B8A8_UNORM) // first dequeued buffer does not have the new size so it should be rejected. it.mSurfaceProxy.SurfaceQueueBuffer(0) it.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW) it.mSurfaceProxy.SurfaceQueueBuffer(1) assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed((count * 3) + 3L, 500 /* ms */), 0) } } for (count in 0 until 5) { assertThat(trace).layer("SurfaceView", (count * 3) + 1L) .hasBufferSize(defaultBufferSize) assertThat(trace).layer("SurfaceView", (count * 3) + 2L) .doesNotExist() assertThat(trace).layer("SurfaceView", (count * 3) + 3L) .hasBufferSize(bufferSize) } } } No newline at end of file Loading
tests/SurfaceViewBufferTests/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ android_test { "kotlinx-coroutines-android", "flickerlib", "truth-prebuilt", "cts-wm-util", "CtsSurfaceValidatorLib", ], } Loading @@ -43,6 +45,7 @@ cc_library_shared { ], shared_libs: [ "libutils", "libui", "libgui", "liblog", "libandroid", Loading
tests/SurfaceViewBufferTests/AndroidManifest.xml +11 −0 Original line number Diff line number Diff line Loading @@ -23,12 +23,19 @@ <uses-permission android:name="android.permission.DUMP" /> <!-- Enable / Disable sv blast adapter !--> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <!-- Readback virtual display output !--> <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <!-- Save failed test bitmap images !--> <uses-permission android:name="android.Manifest.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="false" android:supportsRtl="true"> <activity android:name=".MainActivity" android:taskAffinity="com.android.test.MainActivity" android:theme="@style/AppTheme" android:configChanges="orientation|screenSize" android:label="SurfaceViewBufferTestApp" android:exported="true"> <intent-filter> Loading @@ -36,6 +43,10 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <service android:name="android.view.cts.surfacevalidator.LocalMediaProjectionService" android:foregroundServiceType="mediaProjection" android:enabled="true"> </service> <uses-library android:name="android.test.runner"/> </application> Loading
tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp +124 −3 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ extern "C" { int i = 0; static ANativeWindow* sAnw; static std::map<uint32_t /* slot */, ANativeWindowBuffer*> sBuffers; JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_setSurface(JNIEnv* env, jclass, jobject surfaceObject) { Loading @@ -39,11 +40,14 @@ JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_setSurface(JNIEnv* env assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); surface->enableFrameTimestamps(true); surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false); native_window_set_usage(sAnw, GRALLOC_USAGE_SW_WRITE_OFTEN); native_window_set_buffers_format(sAnw, HAL_PIXEL_FORMAT_RGBA_8888); return 0; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_waitUntilBufferDisplayed( JNIEnv*, jclass, jint jFrameNumber, jint timeoutSec) { JNIEnv*, jclass, jlong jFrameNumber, jint timeoutMs) { using namespace std::chrono_literals; assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); Loading @@ -63,8 +67,8 @@ JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_waitUntilBufferDisplay &outDisplayPresentTime, &outDequeueReadyTime, &outReleaseTime); if (outDisplayPresentTime < 0) { auto end = std::chrono::steady_clock::now(); if (std::chrono::duration_cast<std::chrono::seconds>(end - start).count() > timeoutSec) { if (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() > timeoutMs) { return -1; } } Loading Loading @@ -99,4 +103,121 @@ JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffer assert(sAnw); return ANativeWindow_setBuffersGeometry(sAnw, w, h, format); } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersTransform( JNIEnv* /* env */, jclass /* clazz */, jint transform) { assert(sAnw); return native_window_set_buffers_transform(sAnw, transform); } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetScalingMode(JNIEnv* /* env */, jclass /* clazz */, jint scalingMode) { assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); return surface->setScalingMode(scalingMode); } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceDequeueBuffer(JNIEnv* /* env */, jclass /* clazz */, jint slot, jint timeoutMs) { assert(sAnw); ANativeWindowBuffer* anb; int fenceFd; int result = sAnw->dequeueBuffer(sAnw, &anb, &fenceFd); if (result != android::OK) { return result; } sBuffers[slot] = anb; android::sp<android::Fence> fence(new android::Fence(fenceFd)); int waitResult = fence->wait(timeoutMs); if (waitResult != android::OK) { sAnw->cancelBuffer(sAnw, sBuffers[slot], -1); sBuffers[slot] = nullptr; return waitResult; } return 0; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceCancelBuffer(JNIEnv* /* env */, jclass /* clazz */, jint slot) { assert(sAnw); assert(sBuffers[slot]); int result = sAnw->cancelBuffer(sAnw, sBuffers[slot], -1); sBuffers[slot] = nullptr; return result; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_drawBuffer(JNIEnv* env, jclass /* clazz */, jint slot, jintArray jintArrayColor) { assert(sAnw); assert(sBuffers[slot]); int* color = env->GetIntArrayElements(jintArrayColor, nullptr); ANativeWindowBuffer* buffer = sBuffers[slot]; android::sp<android::GraphicBuffer> graphicBuffer(static_cast<android::GraphicBuffer*>(buffer)); const android::Rect bounds(buffer->width, buffer->height); android::Region newDirtyRegion; newDirtyRegion.set(bounds); void* vaddr; int fenceFd = -1; graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, newDirtyRegion.bounds(), &vaddr, fenceFd); for (int32_t row = 0; row < buffer->height; row++) { uint8_t* dst = static_cast<uint8_t*>(vaddr) + (buffer->stride * row) * 4; for (int32_t column = 0; column < buffer->width; column++) { dst[0] = color[0]; dst[1] = color[1]; dst[2] = color[2]; dst[3] = color[3]; dst += 4; } } graphicBuffer->unlockAsync(&fenceFd); env->ReleaseIntArrayElements(jintArrayColor, color, JNI_ABORT); return 0; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceQueueBuffer(JNIEnv* /* env */, jclass /* clazz */, jint slot, jboolean freeSlot) { assert(sAnw); assert(sBuffers[slot]); int result = sAnw->queueBuffer(sAnw, sBuffers[slot], -1); if (freeSlot) { sBuffers[slot] = nullptr; } return result; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetBufferCount( JNIEnv* /* env */, jclass /* clazz */, jint count) { assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); int result = native_window_set_buffer_count(sAnw, count); return result; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetSharedBufferMode( JNIEnv* /* env */, jclass /* clazz */, jboolean shared) { assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); int result = native_window_set_shared_buffer_mode(sAnw, shared); return result; } JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetAutoRefresh( JNIEnv* /* env */, jclass /* clazz */, jboolean autoRefresh) { assert(sAnw); android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); int result = native_window_set_auto_refresh(sAnw, autoRefresh); return result; } } No newline at end of file
tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt 0 → 100644 +93 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.test import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat import junit.framework.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @RunWith(Parameterized::class) class BufferPresentationTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) { /** Submit buffers as fast as possible and make sure they are presented on display */ @Test fun testQueueBuffers() { val numFrames = 100L val trace = withTrace { for (i in 1..numFrames) { it.mSurfaceProxy.ANativeWindowLock() it.mSurfaceProxy.ANativeWindowUnlockAndPost() } assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(numFrames, 1000 /* ms */)) } assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames) } @Test fun testSetBufferScalingMode_outOfOrderQueueBuffer() { val trace = withTrace { assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */)) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */)) it.mSurfaceProxy.SurfaceQueueBuffer(1) it.mSurfaceProxy.SurfaceQueueBuffer(0) assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(2, 5000 /* ms */)) } assertThat(trace).hasFrameSequence("SurfaceView", 1..2L) } @Test fun testSetBufferScalingMode_multipleDequeueBuffer() { val numFrames = 20L val trace = withTrace { for (count in 1..(numFrames / 2)) { assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */)) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */)) it.mSurfaceProxy.SurfaceQueueBuffer(0) it.mSurfaceProxy.SurfaceQueueBuffer(1) } assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(numFrames, 5000 /* ms */)) } assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames) } @Test fun testSetBufferCount_queueMaxBufferCountMinusOne() { val numBufferCount = 8 val numFrames = numBufferCount * 5L val trace = withTrace { assertEquals(0, it.mSurfaceProxy.NativeWindowSetBufferCount(numBufferCount + 1)) for (i in 1..numFrames / numBufferCount) { for (bufferSlot in 0..numBufferCount - 1) { assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(bufferSlot, 1000 /* ms */)) } for (bufferSlot in 0..numBufferCount - 1) { it.mSurfaceProxy.SurfaceQueueBuffer(bufferSlot) } } assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(numFrames, 5000 /* ms */)) } assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames) } } No newline at end of file
tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt 0 → 100644 +151 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.test import android.graphics.Point import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode import com.android.test.SurfaceViewBufferTestBase.Companion.Transform import junit.framework.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @RunWith(Parameterized::class) class BufferRejectionTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) { @Test fun testSetBuffersGeometry_0x0_rejectsBuffer() { val trace = withTrace { it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, 100, 100, R8G8B8A8_UNORM) it.mSurfaceProxy.ANativeWindowLock() it.mSurfaceProxy.ANativeWindowUnlockAndPost() it.mSurfaceProxy.ANativeWindowLock() it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, 0, 0, R8G8B8A8_UNORM) // Submit buffer one with a different size which should be rejected it.mSurfaceProxy.ANativeWindowUnlockAndPost() // submit a buffer with the default buffer size it.mSurfaceProxy.ANativeWindowLock() it.mSurfaceProxy.ANativeWindowUnlockAndPost() it.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */) } // Verify we reject buffers since scaling mode == NATIVE_WINDOW_SCALING_MODE_FREEZE assertThat(trace).layer("SurfaceView", 2).doesNotExist() // Verify the next buffer is submitted with the correct size assertThat(trace).layer("SurfaceView", 3).also { it.hasBufferSize(defaultBufferSize) // scaling mode is not passed down to the layer for blast if (useBlastAdapter) { it.hasScalingMode(ScalingMode.SCALE_TO_WINDOW.ordinal) } else { it.hasScalingMode(ScalingMode.FREEZE.ordinal) } } } @Test fun testSetBufferScalingMode_freeze() { val bufferSize = Point(300, 200) val trace = withTrace { it.drawFrame() assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0) it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, bufferSize, R8G8B8A8_UNORM) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */)) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */)) // Change buffer size and set scaling mode to freeze it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, Point(0, 0), R8G8B8A8_UNORM) // first dequeued buffer does not have the new size so it should be rejected. it.mSurfaceProxy.SurfaceQueueBuffer(0) it.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW) it.mSurfaceProxy.SurfaceQueueBuffer(1) assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0) } // verify buffer size is reset to default buffer size assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize) assertThat(trace).layer("SurfaceView", 2).doesNotExist() assertThat(trace).layer("SurfaceView", 3).hasBufferSize(bufferSize) } @Test fun testSetBufferScalingMode_freeze_withBufferRotation() { val rotatedBufferSize = Point(defaultBufferSize.y, defaultBufferSize.x) val trace = withTrace { it.drawFrame() assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0) it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, rotatedBufferSize, R8G8B8A8_UNORM) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */)) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */)) // Change buffer size and set scaling mode to freeze it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, Point(0, 0), R8G8B8A8_UNORM) // first dequeued buffer does not have the new size so it should be rejected. it.mSurfaceProxy.SurfaceQueueBuffer(0) // add a buffer transform so the buffer size is correct. it.mSurfaceProxy.ANativeWindowSetBuffersTransform(Transform.ROT_90) it.mSurfaceProxy.SurfaceQueueBuffer(1) assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0) } // verify buffer size is reset to default buffer size assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize) assertThat(trace).layer("SurfaceView", 2).doesNotExist() assertThat(trace).layer("SurfaceView", 3).hasBufferSize(rotatedBufferSize) assertThat(trace).layer("SurfaceView", 3).hasBufferOrientation(Transform.ROT_90.value) } @Test fun testRejectedBuffersAreReleased() { val bufferSize = Point(300, 200) val trace = withTrace { for (count in 0 until 5) { it.drawFrame() assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed((count * 3) + 1L, 500 /* ms */), 0) it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, bufferSize, R8G8B8A8_UNORM) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */)) assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */)) // Change buffer size and set scaling mode to freeze it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, Point(0, 0), R8G8B8A8_UNORM) // first dequeued buffer does not have the new size so it should be rejected. it.mSurfaceProxy.SurfaceQueueBuffer(0) it.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW) it.mSurfaceProxy.SurfaceQueueBuffer(1) assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed((count * 3) + 3L, 500 /* ms */), 0) } } for (count in 0 until 5) { assertThat(trace).layer("SurfaceView", (count * 3) + 1L) .hasBufferSize(defaultBufferSize) assertThat(trace).layer("SurfaceView", (count * 3) + 2L) .doesNotExist() assertThat(trace).layer("SurfaceView", (count * 3) + 3L) .hasBufferSize(bufferSize) } } } No newline at end of file