media.c2 aidl: Implement IGraphicBufferAllocator

Implement IGraphicBufferAllocator c2aidl interface.

Bug: 254050314
Change-Id: Ib7ad6d91291ce1ea7dcefdebe24d1f217abac44b
diff --git a/media/codec2/hal/client/Android.bp b/media/codec2/hal/client/Android.bp
index 61ec10e..38b3edf 100644
--- a/media/codec2/hal/client/Android.bp
+++ b/media/codec2/hal/client/Android.bp
@@ -23,6 +23,7 @@
     name: "libcodec2_client",
 
     srcs: [
+        "GraphicBufferAllocator.cpp",
         "GraphicsTracker.cpp",
         "client.cpp",
         "output.cpp",
diff --git a/media/codec2/hal/client/GraphicBufferAllocator.cpp b/media/codec2/hal/client/GraphicBufferAllocator.cpp
new file mode 100644
index 0000000..bbef1b5
--- /dev/null
+++ b/media/codec2/hal/client/GraphicBufferAllocator.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/IProducerListener.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <codec2/aidl/GraphicBufferAllocator.h>
+#include <codec2/aidl/GraphicsTracker.h>
+
+namespace aidl::android::hardware::media::c2::implementation {
+
+class OnBufferReleasedListener : public ::android::BnProducerListener {
+private:
+    uint32_t mGeneration;
+    std::weak_ptr<GraphicBufferAllocator> mAllocator;
+public:
+    OnBufferReleasedListener(
+            uint32_t generation,
+            const std::shared_ptr<GraphicBufferAllocator> &allocator)
+            : mGeneration(generation), mAllocator(allocator) {}
+    virtual ~OnBufferReleasedListener() = default;
+    virtual void onBufferReleased() {
+        auto p = mAllocator.lock();
+        if (p) {
+            p->onBufferReleased(mGeneration);
+        }
+    }
+    virtual bool needsReleaseNotify() { return true; }
+};
+
+::ndk::ScopedAStatus GraphicBufferAllocator::allocate(
+        const IGraphicBufferAllocator::Description& in_desc,
+        IGraphicBufferAllocator::Allocation* _aidl_return) {
+    AHardwareBuffer *buf;
+    ::android::sp<::android::Fence> fence;
+    c2_status_t ret = allocate(
+            in_desc.width, in_desc.height, in_desc.format, in_desc.usage,
+            &buf, &fence);
+    if (ret == C2_OK) {
+        _aidl_return->buffer.reset(buf);
+        _aidl_return->fence = ::ndk::ScopedFileDescriptor(fence->dup());
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(ret);
+}
+
+::ndk::ScopedAStatus GraphicBufferAllocator::deallocate(int64_t in_id, bool* _aidl_return) {
+    *_aidl_return = deallocate(in_id, ::android::Fence::NO_FENCE);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus GraphicBufferAllocator::getWaitableFds(
+        IGraphicBufferAllocator::WaitableFds* _aidl_return) {
+    int allocFd;
+    int statusFd;
+    c2_status_t ret = mGraphicsTracker->getWaitableFds(&allocFd, &statusFd);
+    if (ret == C2_OK) {
+        _aidl_return->allocEvent.set(allocFd);
+        _aidl_return->statusEvent.set(statusFd);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(ret);
+}
+
+bool GraphicBufferAllocator::configure(
+        const ::android::sp<IGraphicBufferProducer>& igbp,
+        uint32_t generation,
+        int maxDequeueBufferCount) {
+    c2_status_t ret = C2_OK;
+
+    ret = mGraphicsTracker->configureGraphics(igbp, generation);
+    if (ret != C2_OK) {
+        ALOGE("configuring igbp failed gen #(%d), configuring max dequeue count didn't happen",
+              (unsigned int)generation);
+        return false;
+    }
+
+    ret = mGraphicsTracker->configureMaxDequeueCount(maxDequeueBufferCount);
+    if (ret != C2_OK) {
+        ALOGE("configuring max dequeue count to %d failed", maxDequeueBufferCount);
+        return false;
+    }
+    return true;
+}
+
+void GraphicBufferAllocator::updateMaxDequeueBufferCount(int count) {
+    c2_status_t ret = mGraphicsTracker->configureMaxDequeueCount(count);
+    if (ret != C2_OK) {
+        ALOGE("updating max dequeue buffer count failed %d", ret);
+    }
+}
+
+void GraphicBufferAllocator::reset() {
+    mGraphicsTracker->stop();
+}
+
+const ::android::sp<::android::IProducerListener> GraphicBufferAllocator::createReleaseListener(
+      uint32_t generation) {
+    return new OnBufferReleasedListener(generation, ref<GraphicBufferAllocator>());
+}
+
+void GraphicBufferAllocator::onBufferReleased(uint32_t generation) {
+    mGraphicsTracker->onReleased(generation);
+}
+
+c2_status_t GraphicBufferAllocator::allocate(
+        uint32_t width, uint32_t height, ::android::PixelFormat format, uint64_t usage,
+        AHardwareBuffer **buf, ::android::sp<::android::Fence> *fence) {
+    return mGraphicsTracker->allocate(width, height, format, usage, buf, fence);
+}
+
+bool GraphicBufferAllocator::deallocate(const uint64_t id,
+                                        const ::android::sp<::android::Fence> &fence) {
+    c2_status_t ret = mGraphicsTracker->deallocate(id, fence);
+    if (ret != C2_OK) {
+        ALOGW("deallocate() %llu was not successful %d", (unsigned long long)id, ret);
+        return false;
+    }
+    return true;
+}
+
+c2_status_t GraphicBufferAllocator::displayBuffer(
+        const C2ConstGraphicBlock& block,
+        const IGraphicBufferProducer::QueueBufferInput& input,
+        IGraphicBufferProducer::QueueBufferOutput *output) {
+    return mGraphicsTracker->render(block, input, output);
+}
+
+GraphicBufferAllocator::~GraphicBufferAllocator() {}
+
+std::shared_ptr<GraphicBufferAllocator> GraphicBufferAllocator::CreateGraphicBufferAllocator(
+        int maxDequeueCount) {
+    return ::ndk::SharedRefBase::make<GraphicBufferAllocator>(maxDequeueCount);
+}
+
+GraphicBufferAllocator::GraphicBufferAllocator(int maxDequeueCount)
+        : mGraphicsTracker(GraphicsTracker::CreateGraphicsTracker(maxDequeueCount)) {}
+
+} // namespace aidl::android::hardware::media::c2::implementation
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h b/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
new file mode 100644
index 0000000..f9c8aca
--- /dev/null
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/media/c2/BnGraphicBufferAllocator.h>
+
+#include <android-base/unique_fd.h>
+#include <gui/IGraphicBufferProducer.h>
+
+#include <memory>
+
+#include <C2Buffer.h>
+
+namespace aidl::android::hardware::media::c2::implementation {
+
+// forward declarations
+class GraphicsTracker;
+
+struct GraphicBufferAllocator : public BnGraphicBufferAllocator {
+public:
+    // HAL interfaces
+    ::ndk::ScopedAStatus allocate(const IGraphicBufferAllocator::Description& in_desc,
+                                  IGraphicBufferAllocator::Allocation* _aidl_return) override;
+
+    ::ndk::ScopedAStatus deallocate(int64_t in_id, bool* _aidl_return) override;
+
+    ::ndk::ScopedAStatus getWaitableFds(
+            IGraphicBufferAllocator::WaitableFds* _aidl_return) override;
+
+    /**
+     * Configuring Surface/BufferQueue for the interface.
+     *
+     * Configure Surface, generation # and max dequeueBuffer() count for
+     * allocate interface.
+     *
+     * @param   igbp              Surface where to allocate.
+     * @param   generation        Generation # for allocations.
+     * @param   maxDequeueBufferCount
+     *                            Maximum # of pending allocations.
+     */
+    bool configure(const ::android::sp<::android::IGraphicBufferProducer>& igbp,
+                   uint32_t generation,
+                   int maxDequeueBufferCount);
+
+    /**
+     * Update max dequeue buffer count of BufferQueue.
+     *
+     * BufferQueue does not update this value if count is smaller
+     * than the currently dequeued count.
+     * TODO: better to update the value inside this interface.
+     * for return value inspection from BQ, also for delayed updates.
+     *
+     * @param   count             the new value to update
+     */
+    void updateMaxDequeueBufferCount(int count);
+
+    void reset();
+
+    /**
+     * Create a listener for buffer being released.
+     *
+     * Surface will register this listener and notify whenever the consumer
+     * releases a buffer.
+     *
+     * @param   generation        generation # for the BufferQueue.
+     * @return  IProducerListener can be used when connect# to Surface.
+     */
+    const ::android::sp<::android::IProducerListener> createReleaseListener(
+            uint32_t generation);
+
+    /**
+     * Notifies a buffer being released.
+     *
+     * @param   generation        generation # for the BufferQueue.
+     */
+    void onBufferReleased(uint32_t generation);
+
+    /**
+     * Allocates a buffer.
+     *
+     * @param   width             width of the requested buffer.
+     * @param   height            height of the requested buffer.
+     * @param   format            format of the requested buffer.
+     * @param   usage             usage of the requested buffer.
+     * @param   buf               out param for created buffer.
+     * @param   fence             out param for a pending fence.
+     *
+     * @return  OK                When an allocation was created.
+     *          C2_BAD_STATE      Client is not in the state for allocating
+     *          C2_BLOCKING       operation is blocked. Waitable fds can be
+     *                            used to know when it unblocks.
+     *          C2_CORRUPTED      Failed with a serious reason.
+     */
+    c2_status_t allocate(uint32_t width, uint32_t height,
+                         ::android::PixelFormat format, uint64_t usage,
+                         AHardwareBuffer **buf, ::android::sp<::android::Fence> *fence);
+
+    /**
+     * De-allocate a buffer.
+     *
+     * @param   id                unique id for a buffer.
+     * @param   fence             write fence if it's deallocated due to
+     *                            cancellation of displaying
+     */
+    bool deallocate(const uint64_t id, const ::android::sp<::android::Fence> &fence);
+
+    /**
+     * Display a graphic buffer to BufferQueue.
+     *
+     * @param   block             block to display to Surface.
+     * @param   input             input parameter for displaying.
+     * @param   output            out parameter from Surface.
+     */
+    c2_status_t displayBuffer(
+            const C2ConstGraphicBlock& block,
+            const ::android::IGraphicBufferProducer::QueueBufferInput& input,
+            ::android::IGraphicBufferProducer::QueueBufferOutput *output);
+
+    ~GraphicBufferAllocator();
+
+    /**
+     * Create the interface.
+     *
+     * The interface and codec instance's relationship is 1 to 1.
+     * The interface will be cretaed in the beginning of Codec createion. And
+     * lives until the instance destroyed.
+     *
+     * @param   maxDequeueCount   Initial max allocatable count
+     */
+    static std::shared_ptr<GraphicBufferAllocator> CreateGraphicBufferAllocator(
+            int maxDequeueCount);
+private:
+    GraphicBufferAllocator(int maxDequeueCount);
+
+    std::shared_ptr<GraphicsTracker> mGraphicsTracker;
+
+    friend class ::ndk::SharedRefBase;
+};
+
+} // namespace aidl::android::hardware::media::c2::implementation