summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jim Shargo <jshargo@google.com> 2025-02-20 20:26:24 +0000
committer Jim Shargo <jshargo@google.com> 2025-03-14 15:04:33 +0000
commit729f721ae6ac3eb3e0c45b67f6c5f43c06065a22 (patch)
tree2bc5eef2cca69cfc6cb6308ff0d8a37a417197c1
parent835688b9f7ccc6128918bba64014346b4f93ff20 (diff)
Surface: Add 'isBufferOwned' call
Camera's StreamSplitter keeps track of buffers and won't attach them if they're already owned. This allows us to keep that behavior as we move over from IGBP to surfaces. Ideally, I think, IGBPs should fail to attach the same buffer multiple times. Even if not, this call should probably be to the IGBP instead of the Surface for more accuracy. But this replicates the old behavior. Bug: 340933206 Flag: com.android.graphics.libgui.flags.wb_stream_splitter Test: new test Change-Id: Idbb200202012c9eae2668616dcff277c925c3907
-rw-r--r--libs/gui/Surface.cpp34
-rw-r--r--libs/gui/include/gui/Surface.h3
-rw-r--r--libs/gui/tests/Surface_test.cpp53
3 files changed, 88 insertions, 2 deletions
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 63dcfbcb9b..83c6b57289 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -2230,17 +2230,47 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
return NO_ERROR;
}
+int Surface::isBufferOwned(const sp<GraphicBuffer>& buffer, bool* outIsOwned) const {
+ ATRACE_CALL();
+
+ if (buffer == nullptr) {
+ ALOGE("%s: Bad input, buffer was null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ if (outIsOwned == nullptr) {
+ ALOGE("%s: Bad input, output was null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mMutex);
+
+ int slot = this->getSlotFromBufferLocked(buffer->getNativeBuffer());
+ if (slot == BAD_VALUE) {
+ ALOGV("%s: Buffer %" PRIu64 " is not owned", __FUNCTION__, buffer->getId());
+ *outIsOwned = false;
+ return NO_ERROR;
+ } else if (slot < 0) {
+ ALOGV("%s: Buffer %" PRIu64 " look up failed (%d)", __FUNCTION__, buffer->getId(), slot);
+ *outIsOwned = false;
+ return slot;
+ }
+
+ *outIsOwned = true;
+ return NO_ERROR;
+}
+
int Surface::attachBuffer(ANativeWindowBuffer* buffer)
{
ATRACE_CALL();
- ALOGV("Surface::attachBuffer");
+ sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer));
+
+ ALOGV("Surface::attachBuffer bufferId=%" PRIu64, graphicBuffer->getId());
Mutex::Autolock lock(mMutex);
if (mReportRemovedBuffers) {
mRemovedBuffers.clear();
}
- sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer));
uint32_t priorGeneration = graphicBuffer->mGenerationNumber;
graphicBuffer->mGenerationNumber = mGenerationNumber;
int32_t attachedSlot = -1;
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 755674d9e6..3cfbed11bf 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -442,6 +442,9 @@ public:
status_t detachBuffer(const sp<GraphicBuffer>& buffer);
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ // Sets outIsOwned to true if the given buffer is currently known to be owned by this Surface.
+ status_t isBufferOwned(const sp<GraphicBuffer>& buffer, bool* outIsOwned) const;
+
// Batch version of dequeueBuffer, cancelBuffer and queueBuffer
// Note that these batched operations are not supported when shared buffer mode is being used.
struct BatchBuffer {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index e7690e2530..538829ed7e 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -2653,4 +2653,57 @@ TEST_F(SurfaceTest, UnlimitedSlots_BatchOperations) {
EXPECT_EQ(128u, outputs.size());
}
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
+
+TEST_F(SurfaceTest, isBufferOwned) {
+ const int TEST_USAGE_FLAGS = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
+ auto [bufferItemConsumer, surface] = BufferItemConsumer::create(TEST_USAGE_FLAGS);
+
+ sp<SurfaceListener> listener = sp<StubSurfaceListener>::make();
+ ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener));
+
+ sp<GraphicBuffer> surfaceAttachableBuffer =
+ sp<GraphicBuffer>::make(10, 10, PIXEL_FORMAT_RGBA_8888, 1, TEST_USAGE_FLAGS);
+
+ //
+ // Attaching a buffer makes it owned.
+ //
+
+ bool isOwned;
+ EXPECT_EQ(OK, surface->isBufferOwned(surfaceAttachableBuffer, &isOwned));
+ EXPECT_FALSE(isOwned);
+
+ EXPECT_EQ(OK, surface->attachBuffer(surfaceAttachableBuffer.get()));
+ EXPECT_EQ(OK, surface->isBufferOwned(surfaceAttachableBuffer, &isOwned));
+ EXPECT_TRUE(isOwned);
+
+ //
+ // A dequeued buffer is always owned.
+ //
+
+ sp<GraphicBuffer> buffer;
+ sp<Fence> fence;
+ EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence));
+ EXPECT_EQ(OK, surface->isBufferOwned(buffer, &isOwned));
+ EXPECT_TRUE(isOwned);
+
+ //
+ // A detached buffer is no longer owned.
+ //
+
+ EXPECT_EQ(OK, surface->detachBuffer(buffer));
+ EXPECT_EQ(OK, surface->isBufferOwned(buffer, &isOwned));
+ EXPECT_FALSE(isOwned);
+
+ //
+ // It's not currently possible to verify whether or not a consumer has attached a buffer until
+ // it shows up on the Surface.
+ //
+
+ sp<GraphicBuffer> consumerAttachableBuffer =
+ sp<GraphicBuffer>::make(10, 10, PIXEL_FORMAT_RGBA_8888, 1, TEST_USAGE_FLAGS);
+
+ ASSERT_EQ(OK, bufferItemConsumer->attachBuffer(consumerAttachableBuffer));
+ EXPECT_EQ(OK, surface->isBufferOwned(consumerAttachableBuffer, &isOwned));
+ EXPECT_FALSE(isOwned);
+}
} // namespace android