Merge "Surface: Add a SurfaceQueueOutput struct for replaced buffers" into main
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 76d74fe..66e7ddd 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -741,11 +741,12 @@
return res;
}
-status_t Surface::queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd) {
+status_t Surface::queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd,
+ SurfaceQueueBufferOutput* output) {
if (buffer == nullptr) {
return BAD_VALUE;
}
- return queueBuffer(buffer.get(), fd ? fd->get() : -1);
+ return queueBuffer(buffer.get(), fd ? fd->get() : -1, output);
}
status_t Surface::detachBuffer(const sp<GraphicBuffer>& buffer) {
@@ -1195,7 +1196,8 @@
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
-int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
+int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd,
+ SurfaceQueueBufferOutput* surfaceOutput) {
ATRACE_CALL();
ALOGV("Surface::queueBuffer");
@@ -1245,16 +1247,26 @@
onBufferQueuedLocked(slot, fence, output);
}
+ if (surfaceOutput != nullptr) {
+ *surfaceOutput = {.bufferReplaced = output.bufferReplaced};
+ }
+
return err;
}
-int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers,
+ std::vector<SurfaceQueueBufferOutput>* queueBufferOutputs)
+#else
+int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers)
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+{
ATRACE_CALL();
ALOGV("Surface::queueBuffers");
size_t numBuffers = buffers.size();
- std::vector<IGraphicBufferProducer::QueueBufferInput> queueBufferInputs(numBuffers);
- std::vector<IGraphicBufferProducer::QueueBufferOutput> queueBufferOutputs;
+ std::vector<IGraphicBufferProducer::QueueBufferInput> igbpQueueBufferInputs(numBuffers);
+ std::vector<IGraphicBufferProducer::QueueBufferOutput> igbpQueueBufferOutputs;
std::vector<int> bufferSlots(numBuffers, -1);
std::vector<sp<Fence>> bufferFences(numBuffers);
@@ -1280,12 +1292,13 @@
IGraphicBufferProducer::QueueBufferInput input;
getQueueBufferInputLocked(buffers[batchIdx].buffer, buffers[batchIdx].fenceFd,
buffers[batchIdx].timestamp, &input);
+ input.slot = i;
bufferFences[batchIdx] = input.fence;
- queueBufferInputs[batchIdx] = input;
+ igbpQueueBufferInputs[batchIdx] = input;
}
}
nsecs_t now = systemTime();
- err = mGraphicBufferProducer->queueBuffers(queueBufferInputs, &queueBufferOutputs);
+ err = mGraphicBufferProducer->queueBuffers(igbpQueueBufferInputs, &igbpQueueBufferOutputs);
{
Mutex::Autolock lock(mMutex);
mLastQueueDuration = systemTime() - now;
@@ -1295,10 +1308,21 @@
for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) {
onBufferQueuedLocked(bufferSlots[batchIdx], bufferFences[batchIdx],
- queueBufferOutputs[batchIdx]);
+ igbpQueueBufferOutputs[batchIdx]);
}
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ if (queueBufferOutputs != nullptr) {
+ queueBufferOutputs->clear();
+ queueBufferOutputs->resize(numBuffers);
+ for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) {
+ (*queueBufferOutputs)[batchIdx].bufferReplaced =
+ igbpQueueBufferOutputs[batchIdx].bufferReplaced;
+ }
+ }
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
return err;
}
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 5ea81c4..e74f9ad 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -87,6 +87,15 @@
virtual void onBufferDetached(int /*slot*/) override {}
};
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+// Contains additional data from the queueBuffer operation.
+struct SurfaceQueueBufferOutput {
+ // True if this queueBuffer caused a buffer to be replaced in the queue
+ // (and therefore not will not be acquired)
+ bool bufferReplaced = false;
+};
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
/*
* An implementation of ANativeWindow that feeds graphics buffers into a
* BufferQueue.
@@ -363,7 +372,12 @@
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd,
+ SurfaceQueueBufferOutput* surfaceOutput = nullptr);
+#else
virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
virtual int perform(int operation, va_list args);
virtual int setSwapInterval(int interval);
@@ -422,7 +436,8 @@
// Queues a buffer, with an optional fd fence that captures pending work on the buffer. This
// buffer must have been returned by dequeueBuffer or associated with this Surface via an
// attachBuffer operation.
- status_t queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd = Fence::NO_FENCE);
+ status_t queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd = Fence::NO_FENCE,
+ SurfaceQueueBufferOutput* output = nullptr);
// Detaches this buffer, dissociating it from this Surface. This buffer must have been returned
// by queueBuffer or associated with this Surface via an attachBuffer operation.
@@ -443,8 +458,13 @@
int fenceFd = -1;
nsecs_t timestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
};
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ virtual int queueBuffers(const std::vector<BatchQueuedBuffer>& buffers,
+ std::vector<SurfaceQueueBufferOutput>* queueBufferOutputs = nullptr);
+#else
virtual int queueBuffers(
const std::vector<BatchQueuedBuffer>& buffers);
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
protected:
enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 0c3859e..88893b6 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -2422,6 +2422,101 @@
std::future_status status = watcherDiedFuture.wait_for(std::chrono::seconds(1));
EXPECT_EQ(std::future_status::timeout, status);
}
+
+TEST_F(SurfaceTest, QueueBufferOutput_TracksReplacements) {
+ sp<BufferItemConsumer> consumer = sp<BufferItemConsumer>::make(GRALLOC_USAGE_SW_READ_OFTEN);
+ ASSERT_EQ(OK, consumer->setMaxBufferCount(3));
+ ASSERT_EQ(OK, consumer->setMaxAcquiredBufferCount(1));
+
+ sp<Surface> surface = consumer->getSurface();
+ sp<StubSurfaceListener> listener = sp<StubSurfaceListener>::make();
+
+ // Async mode sets up an extra buffer so the surface can queue it without waiting.
+ ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(1));
+ ASSERT_EQ(OK, surface->setAsyncMode(true));
+ ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener));
+
+ sp<GraphicBuffer> buffer;
+ sp<Fence> fence;
+ SurfaceQueueBufferOutput output;
+ BufferItem item;
+
+ // We can queue directly, without an output arg.
+ EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence));
+ EXPECT_EQ(OK, surface->queueBuffer(buffer, fence));
+ EXPECT_EQ(OK, consumer->acquireBuffer(&item, 0));
+ EXPECT_EQ(OK, consumer->releaseBuffer(item));
+
+ // We can queue with an output arg, and that we don't expect to see a replacement.
+ EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence));
+ EXPECT_EQ(OK, surface->queueBuffer(buffer, fence, &output));
+ EXPECT_FALSE(output.bufferReplaced);
+
+ // We expect see a replacement when we queue a second buffer in async mode, and the consumer
+ // hasn't acquired the first one yet.
+ EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence));
+ EXPECT_EQ(OK, surface->queueBuffer(buffer, fence, &output));
+ EXPECT_TRUE(output.bufferReplaced);
+}
+
+TEST_F(SurfaceTest, QueueBufferOutput_TracksReplacements_Plural) {
+ sp<BufferItemConsumer> consumer = sp<BufferItemConsumer>::make(GRALLOC_USAGE_SW_READ_OFTEN);
+ ASSERT_EQ(OK, consumer->setMaxBufferCount(4));
+ ASSERT_EQ(OK, consumer->setMaxAcquiredBufferCount(1));
+
+ sp<Surface> surface = consumer->getSurface();
+ consumer->setName(String8("TRPTest"));
+ sp<StubSurfaceListener> listener = sp<StubSurfaceListener>::make();
+
+ // Async mode sets up an extra buffer so the surface can queue it without waiting.
+ ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(2));
+ ASSERT_EQ(OK, surface->setAsyncMode(true));
+ ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener));
+
+ // dequeueBuffers requires a vector of a certain size:
+ std::vector<Surface::BatchBuffer> buffers(2);
+ std::vector<Surface::BatchQueuedBuffer> queuedBuffers;
+ std::vector<SurfaceQueueBufferOutput> outputs;
+ BufferItem item;
+
+ auto moveBuffersToQueuedBuffers = [&]() {
+ EXPECT_EQ(2u, buffers.size());
+ EXPECT_NE(nullptr, buffers[0].buffer);
+ EXPECT_NE(nullptr, buffers[1].buffer);
+
+ queuedBuffers.clear();
+ for (auto& buffer : buffers) {
+ auto& queuedBuffer = queuedBuffers.emplace_back();
+ queuedBuffer.buffer = buffer.buffer;
+ queuedBuffer.fenceFd = buffer.fenceFd;
+ queuedBuffer.timestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+ }
+ buffers = {{}, {}};
+ };
+
+ // We can queue directly, without an output arg.
+ EXPECT_EQ(OK, surface->dequeueBuffers(&buffers));
+ moveBuffersToQueuedBuffers();
+ EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers));
+ EXPECT_EQ(OK, consumer->acquireBuffer(&item, 0));
+ EXPECT_EQ(OK, consumer->releaseBuffer(item));
+
+ // We can queue with an output arg. Only the second one should be replaced.
+ EXPECT_EQ(OK, surface->dequeueBuffers(&buffers));
+ moveBuffersToQueuedBuffers();
+ EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers, &outputs));
+ EXPECT_EQ(2u, outputs.size());
+ EXPECT_FALSE(outputs[0].bufferReplaced);
+ EXPECT_TRUE(outputs[1].bufferReplaced);
+
+ // Since we haven't acquired anything, both queued buffers will replace the original one.
+ EXPECT_EQ(OK, surface->dequeueBuffers(&buffers));
+ moveBuffersToQueuedBuffers();
+ EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers, &outputs));
+ EXPECT_EQ(2u, outputs.size());
+ EXPECT_TRUE(outputs[0].bufferReplaced);
+ EXPECT_TRUE(outputs[1].bufferReplaced);
+}
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
} // namespace android