Loading libs/gui/Surface.cpp +33 −9 Original line number Diff line number Diff line Loading @@ -741,11 +741,12 @@ status_t Surface::dequeueBuffer(sp<GraphicBuffer>* buffer, sp<Fence>* outFence) 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) { Loading Loading @@ -1195,7 +1196,8 @@ void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence, #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"); Loading Loading @@ -1245,16 +1247,26 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { 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); Loading @@ -1280,12 +1292,13 @@ int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) { 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; Loading @@ -1295,10 +1308,21 @@ int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) { 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; } Loading libs/gui/include/gui/Surface.h +21 −1 Original line number Diff line number Diff line Loading @@ -87,6 +87,15 @@ public: 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. Loading Loading @@ -363,7 +372,12 @@ private: 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); Loading Loading @@ -422,7 +436,8 @@ public: // 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. Loading @@ -443,8 +458,13 @@ public: 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 }; Loading libs/gui/tests/Surface_test.cpp +95 −0 Original line number Diff line number Diff line Loading @@ -2422,6 +2422,101 @@ TEST_F(SurfaceTest, TestRemoteSurfaceDied_Disconnect_CallbackNotCalled) { 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 Loading
libs/gui/Surface.cpp +33 −9 Original line number Diff line number Diff line Loading @@ -741,11 +741,12 @@ status_t Surface::dequeueBuffer(sp<GraphicBuffer>* buffer, sp<Fence>* outFence) 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) { Loading Loading @@ -1195,7 +1196,8 @@ void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence, #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"); Loading Loading @@ -1245,16 +1247,26 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { 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); Loading @@ -1280,12 +1292,13 @@ int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) { 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; Loading @@ -1295,10 +1308,21 @@ int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) { 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; } Loading
libs/gui/include/gui/Surface.h +21 −1 Original line number Diff line number Diff line Loading @@ -87,6 +87,15 @@ public: 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. Loading Loading @@ -363,7 +372,12 @@ private: 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); Loading Loading @@ -422,7 +436,8 @@ public: // 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. Loading @@ -443,8 +458,13 @@ public: 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 }; Loading
libs/gui/tests/Surface_test.cpp +95 −0 Original line number Diff line number Diff line Loading @@ -2422,6 +2422,101 @@ TEST_F(SurfaceTest, TestRemoteSurfaceDied_Disconnect_CallbackNotCalled) { 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