Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bad6c068 authored by Jim Shargo's avatar Jim Shargo
Browse files

Surface: Add a SurfaceQueueOutput struct for replaced buffers

With IGBPs, this is provided back to clients via an output object, which
Surface doesn't currently provide.

This lets us notify clients when this happens.

BYPASS_IGBP_IGBC_API_REASON=warren buffers

Bug: 340933794
Flag: com.android.graphics.libgui.flags.wb_platform_api_improvements
Test: new SurfaceTest tests
Change-Id: I2ec5a0598988fdfcfe7356a14be0f99a206ef6a8
parent 5e243ddd
Loading
Loading
Loading
Loading
+33 −9
Original line number Original line Diff line number Diff line
@@ -741,11 +741,12 @@ status_t Surface::dequeueBuffer(sp<GraphicBuffer>* buffer, sp<Fence>* outFence)
    return res;
    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) {
    if (buffer == nullptr) {
        return BAD_VALUE;
        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) {
status_t Surface::detachBuffer(const sp<GraphicBuffer>& buffer) {
@@ -1195,7 +1196,8 @@ void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence,


#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
#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();
    ATRACE_CALL();
    ALOGV("Surface::queueBuffer");
    ALOGV("Surface::queueBuffer");


@@ -1245,16 +1247,26 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
        onBufferQueuedLocked(slot, fence, output);
        onBufferQueuedLocked(slot, fence, output);
    }
    }


    if (surfaceOutput != nullptr) {
        *surfaceOutput = {.bufferReplaced = output.bufferReplaced};
    }

    return err;
    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();
    ATRACE_CALL();
    ALOGV("Surface::queueBuffers");
    ALOGV("Surface::queueBuffers");


    size_t numBuffers = buffers.size();
    size_t numBuffers = buffers.size();
    std::vector<IGraphicBufferProducer::QueueBufferInput> queueBufferInputs(numBuffers);
    std::vector<IGraphicBufferProducer::QueueBufferInput> igbpQueueBufferInputs(numBuffers);
    std::vector<IGraphicBufferProducer::QueueBufferOutput> queueBufferOutputs;
    std::vector<IGraphicBufferProducer::QueueBufferOutput> igbpQueueBufferOutputs;
    std::vector<int> bufferSlots(numBuffers, -1);
    std::vector<int> bufferSlots(numBuffers, -1);
    std::vector<sp<Fence>> bufferFences(numBuffers);
    std::vector<sp<Fence>> bufferFences(numBuffers);


@@ -1280,12 +1292,13 @@ int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) {
            IGraphicBufferProducer::QueueBufferInput input;
            IGraphicBufferProducer::QueueBufferInput input;
            getQueueBufferInputLocked(buffers[batchIdx].buffer, buffers[batchIdx].fenceFd,
            getQueueBufferInputLocked(buffers[batchIdx].buffer, buffers[batchIdx].fenceFd,
                                      buffers[batchIdx].timestamp, &input);
                                      buffers[batchIdx].timestamp, &input);
            input.slot = i;
            bufferFences[batchIdx] = input.fence;
            bufferFences[batchIdx] = input.fence;
            queueBufferInputs[batchIdx] = input;
            igbpQueueBufferInputs[batchIdx] = input;
        }
        }
    }
    }
    nsecs_t now = systemTime();
    nsecs_t now = systemTime();
    err = mGraphicBufferProducer->queueBuffers(queueBufferInputs, &queueBufferOutputs);
    err = mGraphicBufferProducer->queueBuffers(igbpQueueBufferInputs, &igbpQueueBufferOutputs);
    {
    {
        Mutex::Autolock lock(mMutex);
        Mutex::Autolock lock(mMutex);
        mLastQueueDuration = systemTime() - now;
        mLastQueueDuration = systemTime() - now;
@@ -1295,10 +1308,21 @@ int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) {


        for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) {
        for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) {
            onBufferQueuedLocked(bufferSlots[batchIdx], bufferFences[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;
    return err;
}
}


+21 −1
Original line number Original line Diff line number Diff line
@@ -87,6 +87,15 @@ public:
    virtual void onBufferDetached(int /*slot*/) override {}
    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
 * An implementation of ANativeWindow that feeds graphics buffers into a
 * BufferQueue.
 * BufferQueue.
@@ -363,7 +372,12 @@ private:
protected:
protected:
    virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
    virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
    virtual int cancelBuffer(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);
    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 perform(int operation, va_list args);
    virtual int setSwapInterval(int interval);
    virtual int setSwapInterval(int interval);


@@ -422,7 +436,8 @@ public:
    // Queues a buffer, with an optional fd fence that captures pending work on the buffer. This
    // 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
    // buffer must have been returned by dequeueBuffer or associated with this Surface via an
    // attachBuffer operation.
    // 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
    // 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.
    // by queueBuffer or associated with this Surface via an attachBuffer operation.
@@ -443,8 +458,13 @@ public:
        int fenceFd = -1;
        int fenceFd = -1;
        nsecs_t timestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
        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(
    virtual int queueBuffers(
            const std::vector<BatchQueuedBuffer>& buffers);
            const std::vector<BatchQueuedBuffer>& buffers);
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)


protected:
protected:
    enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
    enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
+95 −0
Original line number Original line Diff line number Diff line
@@ -2422,6 +2422,101 @@ TEST_F(SurfaceTest, TestRemoteSurfaceDied_Disconnect_CallbackNotCalled) {
    std::future_status status = watcherDiedFuture.wait_for(std::chrono::seconds(1));
    std::future_status status = watcherDiedFuture.wait_for(std::chrono::seconds(1));
    EXPECT_EQ(std::future_status::timeout, status);
    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)
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)


} // namespace android
} // namespace android