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

Commit 6dea4048 authored by Brian Lindahl's avatar Brian Lindahl Committed by Android (Google) Code Review
Browse files

Merge changes from topic "am-4493549d7d1a410f880c7c44afed2208" into udc-dev

* changes:
  [conflict] Merge changes from topic "frame-drop-metrics-tm-qpr-dev-plus-aosp" into tm-qpr-dev-plus-aosp am: fd3b822d
  Allow for reschedule-able messages am: 352fec52
parents 2775bd6d 39ef760f
Loading
Loading
Loading
Loading
+137 −281

File changed.

Preview size limit exceeded, changes collapsed.

+13 −40
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <C2Param.h>
#include <C2.h>

#include <gui/FrameTimestamps.h>
#include <gui/IGraphicBufferProducer.h>
#include <hidl/HidlSupport.h>
#include <utils/StrongPointer.h>
@@ -83,13 +84,6 @@ struct IComponent;
struct IComponentStore;
}  // namespace android::hardware::media::c2::V1_2

namespace aidl::android::hardware::media::c2 {
class IComponent;
class IComponentInterface;
class IComponentStore;
class IConfigurable;
}  // namespace aidl::android::hardware::media::c2

namespace android::hardware::media::bufferpool::V2_0 {
struct IClientManager;
}  // namespace android::hardware::media::bufferpool::V2_0
@@ -112,34 +106,7 @@ namespace android {
// declaration of an inner class is not possible.
struct Codec2ConfigurableClient {

    typedef ::android::hardware::media::c2::V1_0::IConfigurable HidlBase;

    struct ImplBase {
        virtual ~ImplBase() = default;

        virtual const C2String& getName() const = 0;

        virtual c2_status_t query(
                const std::vector<C2Param*>& stackParams,
                const std::vector<C2Param::Index> &heapParamIndices,
                c2_blocking_t mayBlock,
                std::vector<std::unique_ptr<C2Param>>* const heapParams) const = 0;

        virtual c2_status_t config(
                const std::vector<C2Param*> &params,
                c2_blocking_t mayBlock,
                std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;

        virtual c2_status_t querySupportedParams(
                std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
                ) const = 0;

        virtual c2_status_t querySupportedValues(
                std::vector<C2FieldSupportedValuesQuery>& fields,
                c2_blocking_t mayBlock) const = 0;
    };

    explicit Codec2ConfigurableClient(const sp<HidlBase> &hidlBase);
    typedef ::android::hardware::media::c2::V1_0::IConfigurable Base;

    const C2String& getName() const;

@@ -161,11 +128,15 @@ struct Codec2ConfigurableClient {
    c2_status_t querySupportedValues(
            std::vector<C2FieldSupportedValuesQuery>& fields,
            c2_blocking_t mayBlock) const;
private:
    struct HidlImpl;
    struct AidlImpl;

    const std::unique_ptr<ImplBase> mImpl;
    // base cannot be null.
    Codec2ConfigurableClient(const sp<Base>& base);

protected:
    sp<Base> mBase;
    C2String mName;

    friend struct Codec2Client;
};

struct Codec2Client : public Codec2ConfigurableClient {
@@ -438,6 +409,9 @@ struct Codec2Client::Component : public Codec2Client::Configurable {
            const QueueBufferInput& input,
            QueueBufferOutput* output);

    // Retrieve frame event history from the output surface.
    void pollForRenderedFrames(FrameEventHistoryDelta* delta);

    // Set max dequeue count for output surface.
    void setOutputSurfaceMaxDequeueCount(int maxDequeueCount);

@@ -538,4 +512,3 @@ protected:
}  // namespace android

#endif  // CODEC2_HIDL_CLIENT_H
+4 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#ifndef CODEC2_HIDL_V1_0_UTILS_OUTPUT_BUFFER_QUEUE
#define CODEC2_HIDL_V1_0_UTILS_OUTPUT_BUFFER_QUEUE

#include <gui/FrameTimestamps.h>
#include <gui/IGraphicBufferProducer.h>
#include <codec2/hidl/1.0/types.h>
#include <codec2/hidl/1.2/types.h>
@@ -50,10 +51,6 @@ struct OutputBufferQueue {
                   int maxDequeueBufferCount,
                   std::shared_ptr<V1_2::SurfaceSyncObj> *syncObj);

    // If there are waiters to allocate from the old surface, wake up and expire
    // them.
    void expireOldWaiters();

    // Stop using the current output surface. Pending buffer opeations will not
    // perform anymore.
    void stop();
@@ -64,6 +61,9 @@ struct OutputBufferQueue {
            const BnGraphicBufferProducer::QueueBufferInput& input,
            BnGraphicBufferProducer::QueueBufferOutput* output);

    // Retrieve frame event history from the output surface.
    void pollForRenderedFrames(FrameEventHistoryDelta* delta);

    // Call holdBufferQueueBlock() on output blocks in the given workList.
    // The OutputBufferQueue will take the ownership of output blocks.
    //
@@ -90,8 +90,6 @@ private:
    std::weak_ptr<_C2BlockPoolData> mPoolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
    std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
    bool mStopped;
    std::mutex mOldMutex;
    std::shared_ptr<C2SurfaceSyncMemory> mOldMem;

    bool registerBuffer(const C2ConstGraphicBlock& block);
};
+7 −18
Original line number Diff line number Diff line
@@ -217,7 +217,6 @@ bool OutputBufferQueue::configure(const sp<IGraphicBufferProducer>& igbp,
    sp<GraphicBuffer> buffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
    std::weak_ptr<_C2BlockPoolData>
            poolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
    std::shared_ptr<C2SurfaceSyncMemory> oldMem;
    {
        std::scoped_lock<std::mutex> l(mMutex);
        bool stopped = mStopped;
@@ -239,7 +238,7 @@ bool OutputBufferQueue::configure(const sp<IGraphicBufferProducer>& igbp,
            }
            return false;
        }
        oldMem = mSyncMem;
        std::shared_ptr<C2SurfaceSyncMemory> oldMem = mSyncMem;
        C2SyncVariables *oldSync = mSyncMem ? mSyncMem->mem() : nullptr;
        if (oldSync) {
            oldSync->lock();
@@ -315,26 +314,11 @@ bool OutputBufferQueue::configure(const sp<IGraphicBufferProducer>& igbp,
            newSync->unlock();
        }
    }
    {
        std::scoped_lock<std::mutex> l(mOldMutex);
        mOldMem = oldMem;
    }
    ALOGD("remote graphic buffer migration %zu/%zu",
          success, tryNum);
    return true;
}

void OutputBufferQueue::expireOldWaiters() {
    std::scoped_lock<std::mutex> l(mOldMutex);
    if (mOldMem) {
        C2SyncVariables *oldSync = mOldMem->mem();
        if (oldSync) {
            oldSync->notifyAll();
        }
        mOldMem.reset();
    }
}

void OutputBufferQueue::stop() {
    std::scoped_lock<std::mutex> l(mMutex);
    mStopped = true;
@@ -492,6 +476,12 @@ status_t OutputBufferQueue::outputBuffer(
    return OK;
}

void OutputBufferQueue::pollForRenderedFrames(FrameEventHistoryDelta* delta) {
    if (mIgbp) {
        mIgbp->getFrameTimestamps(delta);
    }
}

void OutputBufferQueue::holdBufferQueueBlocks(
        const std::list<std::unique_ptr<C2Work>>& workList) {
    forEachBlock(workList,
@@ -516,4 +506,3 @@ void OutputBufferQueue::updateMaxDequeueBufferCount(int maxDequeueBufferCount) {
}  // namespace media
}  // namespace hardware
}  // namespace android
+106 −5
Original line number Diff line number Diff line
@@ -902,7 +902,7 @@ status_t CCodecBufferChannel::renderOutputBuffer(
    }

    // TODO: revisit this after C2Fence implementation.
    android::IGraphicBufferProducer::QueueBufferInput qbi(
    IGraphicBufferProducer::QueueBufferInput qbi(
            timestampNs,
            false, // droppable
            dataSpace,
@@ -966,9 +966,9 @@ status_t CCodecBufferChannel::renderOutputBuffer(
    }
    SetMetadataToGralloc4Handle(dataSpace, hdrStaticInfo, hdrDynamicInfo, block.handle());

    // we don't have dirty regions
    qbi.setSurfaceDamage(Region::INVALID_REGION);
    android::IGraphicBufferProducer::QueueBufferOutput qbo;
    qbi.setSurfaceDamage(Region::INVALID_REGION); // we don't have dirty regions
    qbi.getFrameTimestamps = true; // we need to know when a frame is rendered
    IGraphicBufferProducer::QueueBufferOutput qbo;
    status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo);
    if (result != OK) {
        ALOGI("[%s] queueBuffer failed: %d", mName, result);
@@ -986,11 +986,107 @@ status_t CCodecBufferChannel::renderOutputBuffer(

    int64_t mediaTimeUs = 0;
    (void)buffer->meta()->findInt64("timeUs", &mediaTimeUs);
    mCCodecCallback->onOutputFramesRendered(mediaTimeUs, timestampNs);
    trackReleasedFrame(qbo, mediaTimeUs, timestampNs);
    processRenderedFrames(qbo.frameTimestamps);

    return OK;
}

void CCodecBufferChannel::initializeFrameTrackingFor(ANativeWindow * window) {
    int hasPresentFenceTimes = 0;
    window->query(window, NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &hasPresentFenceTimes);
    mHasPresentFenceTimes = hasPresentFenceTimes == 1;
    if (mHasPresentFenceTimes) {
        ALOGI("Using latch times for frame rendered signals - present fences not supported");
    }
    mTrackedFrames.clear();
}

void CCodecBufferChannel::trackReleasedFrame(const IGraphicBufferProducer::QueueBufferOutput& qbo,
                                             int64_t mediaTimeUs, int64_t desiredRenderTimeNs) {
    // If the render time is earlier than now, then we're suggesting it should be rendered ASAP,
    // so track the frame as if the desired render time is now.
    int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
    if (desiredRenderTimeNs < nowNs) {
        desiredRenderTimeNs = nowNs;
    }
    // We've just queued a frame to the surface, so keep track of it and later check to see if it is
    // actually rendered.
    TrackedFrame frame;
    frame.number = qbo.nextFrameNumber - 1;
    frame.mediaTimeUs = mediaTimeUs;
    frame.desiredRenderTimeNs = desiredRenderTimeNs;
    frame.latchTime = -1;
    frame.presentFence = nullptr;
    mTrackedFrames.push_back(frame);
}

void CCodecBufferChannel::processRenderedFrames(const FrameEventHistoryDelta& deltas) {
    // Grab the latch times and present fences from the frame event deltas
    for (const auto& delta : deltas) {
        for (auto& frame : mTrackedFrames) {
            if (delta.getFrameNumber() == frame.number) {
                delta.getLatchTime(&frame.latchTime);
                delta.getDisplayPresentFence(&frame.presentFence);
            }
        }
    }

    // Scan all frames and check to see if the frames that SHOULD have been rendered by now, have,
    // in fact, been rendered.
    int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
    while (!mTrackedFrames.empty()) {
        TrackedFrame & frame = mTrackedFrames.front();
        // Frames that should have been rendered at least 100ms in the past are checked
        if (frame.desiredRenderTimeNs > nowNs - 100*1000*1000LL) {
            break;
        }

        // If we don't have a render time by now, then consider the frame as dropped
        int64_t renderTimeNs = getRenderTimeNs(frame);
        if (renderTimeNs != -1) {
            mCCodecCallback->onOutputFramesRendered(frame.mediaTimeUs, renderTimeNs);
        }
        mTrackedFrames.pop_front();
    }
}

int64_t CCodecBufferChannel::getRenderTimeNs(const TrackedFrame& frame) {
    // If the device doesn't have accurate present fence times, then use the latch time as a proxy
    if (!mHasPresentFenceTimes) {
        if (frame.latchTime == -1) {
            ALOGD("no latch time for frame %d", (int) frame.number);
            return -1;
        }
        return frame.latchTime;
    }

    if (frame.presentFence == nullptr) {
        ALOGW("no present fence for frame %d", (int) frame.number);
        return -1;
    }

    nsecs_t actualRenderTimeNs = frame.presentFence->getSignalTime();

    if (actualRenderTimeNs == Fence::SIGNAL_TIME_INVALID) {
        ALOGW("invalid signal time for frame %d", (int) frame.number);
        return -1;
    }

    if (actualRenderTimeNs == Fence::SIGNAL_TIME_PENDING) {
        ALOGD("present fence has not fired for frame %d", (int) frame.number);
        return -1;
    }

    return actualRenderTimeNs;
}

void CCodecBufferChannel::pollForRenderedBuffers() {
    FrameEventHistoryDelta delta;
    mComponent->pollForRenderedFrames(&delta);
    processRenderedFrames(delta);
}

status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
    ALOGV("[%s] discardBuffer: %p", mName, buffer.get());
    bool released = false;
@@ -1615,6 +1711,8 @@ void CCodecBufferChannel::reset() {
        Mutexed<Output>::Locked output(mOutput);
        output->buffers.reset();
    }
    // reset the frames that are being tracked for onFrameRendered callbacks
    mTrackedFrames.clear();
}

void CCodecBufferChannel::release() {
@@ -1683,6 +1781,8 @@ void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushe
            output->buffers->flushStash();
        }
    }
    // reset the frames that are being tracked for onFrameRendered callbacks
    mTrackedFrames.clear();
}

void CCodecBufferChannel::onWorkDone(
@@ -2162,6 +2262,7 @@ status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface, bool pus
        Mutexed<OutputSurface>::Locked output(mOutputSurface);
        output->surface = newSurface;
        output->generation = generation;
        initializeFrameTrackingFor(static_cast<ANativeWindow *>(newSurface.get()));
    }

    if (oldSurface && pushBlankBuffer) {
Loading