Add VTS test for clearing buffer slots to Composer HIDL and AIDL

This feature allows SurfaceFlinger to clear buffer slots when buffers
are discarded by SurfaceFlinger clients and will no longer be used,
allowing the graphics memory to be freed immediately.

Bug: 258196272
Test: atest VtsHalGraphicsComposerV2_4TargetTest
Test: atest VtsHalGraphicsComposer3_TargetTest
Change-Id: Ibfbe2078ac419bb8f3880ee3f0512acaad2f5012
This commit is contained in:
Brian Lindahl
2022-12-09 00:32:11 -07:00
parent f7e4b9f044
commit 25e0d09c76
2 changed files with 214 additions and 10 deletions

View File

@@ -666,11 +666,13 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
}
NativeHandleWrapper allocate() {
NativeHandleWrapper allocate() { return allocate(mDisplayWidth, mDisplayHeight); }
NativeHandleWrapper allocate(uint32_t width, uint32_t height) {
uint64_t usage =
static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN |
BufferUsage::COMPOSER_OVERLAY);
return mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage);
return mGralloc->allocate(width, height, 1, PixelFormat::RGBA_8888, usage);
}
void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
@@ -883,6 +885,106 @@ TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER) {
execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_BUFFER with the behavior used for clearing buffer slots.
*/
TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER_multipleTimes) {
// A placeholder buffer used to clear buffer slots
auto clearSlotBuffer = allocate(1u, 1u);
//
// Set the layer buffer to the first buffer
//
auto handle1 = allocate();
ASSERT_NE(nullptr, handle1.get());
IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight};
Layer layer;
ASSERT_NO_FATAL_FAILURE(
layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->selectLayer(layer);
mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
mWriter->setLayerDisplayFrame(displayFrame);
mWriter->setLayerBuffer(0, handle1.get(), -1);
mWriter->setLayerDataspace(Dataspace::UNKNOWN);
mWriter->validateDisplay();
execute();
if (mReader->mCompositionChanges.size() != 0) {
GTEST_SUCCEED() << "Composition change requested, skipping test";
return;
}
ASSERT_EQ(0, mReader->mErrors.size());
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->presentDisplay();
execute();
ASSERT_EQ(0, mReader->mErrors.size());
//
// Set the layer buffer to the second buffer
//
auto handle2 = allocate();
ASSERT_NE(nullptr, handle2.get());
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->selectLayer(layer);
mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
mWriter->setLayerDisplayFrame(displayFrame);
mWriter->setLayerBuffer(1, handle2.get(), -1);
mWriter->setLayerDataspace(Dataspace::UNKNOWN);
mWriter->validateDisplay();
execute();
if (mReader->mCompositionChanges.size() != 0) {
GTEST_SUCCEED() << "Composition change requested, skipping test";
return;
}
ASSERT_EQ(0, mReader->mErrors.size());
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->presentDisplay();
execute();
ASSERT_EQ(0, mReader->mErrors.size());
//
// Set the layer buffer to the third buffer
//
auto handle3 = allocate();
ASSERT_NE(nullptr, handle3.get());
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->selectLayer(layer);
mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
mWriter->setLayerDisplayFrame(displayFrame);
mWriter->setLayerBuffer(2, handle3.get(), -1);
mWriter->setLayerDataspace(Dataspace::UNKNOWN);
mWriter->validateDisplay();
execute();
if (mReader->mCompositionChanges.size() != 0) {
GTEST_SUCCEED() << "Composition change requested, skipping test";
return;
}
ASSERT_EQ(0, mReader->mErrors.size());
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->presentDisplay();
execute();
ASSERT_EQ(0, mReader->mErrors.size());
// Ensure we can clear multiple buffer slots and then restore the active buffer at the end
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->selectLayer(layer);
mWriter->setLayerBuffer(0, clearSlotBuffer.get(), -1);
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->selectLayer(layer);
mWriter->setLayerBuffer(1, clearSlotBuffer.get(), -1);
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->selectLayer(layer);
mWriter->setLayerBuffer(2, nullptr, -1);
mWriter->validateDisplay();
execute();
ASSERT_EQ(0, mReader->mErrors.size());
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->presentDisplay();
execute();
ASSERT_EQ(0, mReader->mErrors.size());
}
/**
* Test IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE.
*/

View File

@@ -1225,17 +1225,21 @@ class GraphicsComposerAidlCommandTest : public GraphicsComposerAidlTest {
});
}
sp<GraphicBuffer> allocate(::android::PixelFormat pixelFormat) {
sp<GraphicBuffer> allocate(uint32_t width, uint32_t height,
::android::PixelFormat pixelFormat) {
return sp<GraphicBuffer>::make(
static_cast<uint32_t>(getPrimaryDisplay().getDisplayWidth()),
static_cast<uint32_t>(getPrimaryDisplay().getDisplayHeight()), pixelFormat,
/*layerCount*/ 1U,
(static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
static_cast<uint64_t>(common::BufferUsage::COMPOSER_OVERLAY)),
width, height, pixelFormat, /*layerCount*/ 1U,
static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
static_cast<uint64_t>(common::BufferUsage::COMPOSER_OVERLAY),
"VtsHalGraphicsComposer3_TargetTest");
}
sp<GraphicBuffer> allocate(::android::PixelFormat pixelFormat) {
return allocate(static_cast<uint32_t>(getPrimaryDisplay().getDisplayWidth()),
static_cast<uint32_t>(getPrimaryDisplay().getDisplayHeight()), pixelFormat);
}
void sendRefreshFrame(const VtsDisplay& display, const VsyncPeriodChangeTimeline* timeline) {
if (timeline != nullptr) {
// Refresh time should be before newVsyncAppliedTimeNanos
@@ -1749,6 +1753,104 @@ TEST_P(GraphicsComposerAidlCommandTest, SetLayerBuffer) {
execute();
}
TEST_P(GraphicsComposerAidlCommandTest, SetLayerBufferSlotsToClear) {
// Older HAL versions use a backwards compatible way of clearing buffer slots
const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
ASSERT_TRUE(versionStatus.isOk());
if (version <= 1) {
GTEST_SUCCEED() << "HAL at version 1 or lower does not have "
"LayerCommand::bufferSlotsToClear.";
return;
}
const auto& [layerStatus, layer] =
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
auto& writer = getWriter(getPrimaryDisplayId());
// setup 3 buffers in the buffer cache, with the last buffer being active
// then emulate the Android platform code that clears all 3 buffer slots
const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
ASSERT_NE(nullptr, buffer1);
const auto handle1 = buffer1->handle;
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle1, /*acquireFence*/ -1);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
ASSERT_NE(nullptr, buffer2);
const auto handle2 = buffer2->handle;
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle2, /*acquireFence*/ -1);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
const auto buffer3 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
ASSERT_NE(nullptr, buffer3);
const auto handle3 = buffer3->handle;
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 2, handle3, /*acquireFence*/ -1);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
// Ensure we can clear all 3 buffer slots, even the active buffer - it is assumed the
// current active buffer's slot will be cleared, but still remain the active buffer and no
// errors will occur.
writer.setLayerBufferSlotsToClear(getPrimaryDisplayId(), layer, {0, 1, 2});
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
}
TEST_P(GraphicsComposerAidlCommandTest, SetLayerBufferMultipleTimes) {
const auto& [layerStatus, layer] =
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
auto& writer = getWriter(getPrimaryDisplayId());
// Setup 3 buffers in the buffer cache, with the last buffer being active. Then, emulate the
// Android platform code that clears all 3 buffer slots by setting all but the active buffer
// slot to a placeholder buffer, and then restoring the active buffer.
// This is used on HALs that don't support setLayerBufferSlotsToClear (version <= 3.1).
const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
ASSERT_NE(nullptr, buffer1);
const auto handle1 = buffer1->handle;
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle1, /*acquireFence*/ -1);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
ASSERT_NE(nullptr, buffer2);
const auto handle2 = buffer2->handle;
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle2, /*acquireFence*/ -1);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
const auto buffer3 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
ASSERT_NE(nullptr, buffer3);
const auto handle3 = buffer3->handle;
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 2, handle3, /*acquireFence*/ -1);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
// Older versions of the HAL clear all but the active buffer slot with a placeholder buffer,
// and then restoring the current active buffer at the end
auto clearSlotBuffer = allocate(1u, 1u, ::android::PIXEL_FORMAT_RGB_888);
ASSERT_NE(nullptr, clearSlotBuffer);
auto clearSlotBufferHandle = clearSlotBuffer->handle;
// clear buffer slots 0 and 1 with new layer commands... and then...
writer.setLayerBufferWithNewCommand(getPrimaryDisplayId(), layer, /* slot */ 0,
clearSlotBufferHandle, /*acquireFence*/ -1);
writer.setLayerBufferWithNewCommand(getPrimaryDisplayId(), layer, /* slot */ 1,
clearSlotBufferHandle, /*acquireFence*/ -1);
// ...reset the layer buffer to the current active buffer slot with a final new command
writer.setLayerBufferWithNewCommand(getPrimaryDisplayId(), layer, /*slot*/ 2, nullptr,
/*acquireFence*/ -1);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
}
TEST_P(GraphicsComposerAidlCommandTest, SetLayerSurfaceDamage) {
const auto& [layerStatus, layer] =
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
@@ -2583,4 +2685,4 @@ int main(int argc, char** argv) {
}
return RUN_ALL_TESTS();
}
}