Android12 HDR相关

以hdr10为例
在nativewindow中,提供native_window_set_buffers_hdr10_plus_metadata接口
在dequeue buffer之后,queue buffer之前调用该接口,将hdr的元数据与该buffer关联起来

/*
 * native_window_set_buffers_hdr10_plus_metadata(..., metadata)
 * All buffers queued after this call will be associated with the
 * HDR10+ dynamic metadata specified.
 *
 * metadata specifies additional dynamic information about the
 * contents of the buffer that may affect how it is displayed.  When
 * it is nullptr, it means no such information is available.  No
 * HDR10+ dynamic emtadata is associated with the buffers by default.
 *
 * Parameter "size" refers to the length of the metadata blob pointed to
 * by parameter "data".  The metadata blob will adhere to the HDR10+ SEI
 * message standard.
 */
static inline int native_window_set_buffers_hdr10_plus_metadata(struct ANativeWindow* window,
                                                           const size_t size,
                                                           const uint8_t* metadata) {
    
    
    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA, size,
                           metadata);
}

那么是如何关联起来的呢,继续往下走
在Surface.cpp中,将hdr元数据保存在input中

void Surface::getQueueBufferInputLocked(android_native_buffer_t* buffer, int fenceFd,
        nsecs_t timestamp, IGraphicBufferProducer::QueueBufferInput* out) {
    
    
    ...
    IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
            static_cast<android_dataspace>(mDataSpace), crop, mScalingMode,
            mTransform ^ mStickyTransform, fence, mStickyTransform,
            mEnableFrameTimestamps);

    // we should send HDR metadata as needed if this becomes a bottleneck
    input.setHdrMetadata(mHdrMetadata);
    ...

那什么时候会走到这个逻辑呢?在Surface::queuebuffer的时候,会走到这里,将元数据保存下来。然后调用GraphicBufferProducer将buffer 入列。此时会将buffer的信息作为BufferItem对象保存在mCore->mQueue中,即GraphicBufferCore中,其中mQueue是一个FIFO的队列。

int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
    
    
   ...
    IGraphicBufferProducer::QueueBufferOutput output;
    IGraphicBufferProducer::QueueBufferInput input;
    getQueueBufferInputLocked(buffer, fenceFd, mTimestamp, &input);
    sp<Fence> fence = input.fence;

    nsecs_t now = systemTime();
    status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
    ...

BufferItem是一个对buffer信息的封装,后面消费者在acquire buffer时拿到的也是一个bufferItem对象。
我们看surfaceflinger中是如何拿到buffer的。
在BufferLayerConsumer.cpp中,在updateTexImage接口中去获取buffer。我们看acquireBufferLocked具体的实现。

status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
                                             bool* autoRefresh, bool* queuedBuffer,
                                             uint64_t maxFrameNumber) {
    
    
  ...
    BufferItem item;

    // Acquire the next buffer.
    // In asynchronous mode the list is guaranteed to be one buffer
    // deep, while in synchronous mode we use the oldest buffer.
    status_t err = acquireBufferLocked(&item, expectedPresentTime, maxFrameNumber);
    if (err != NO_ERROR) {
    
    
        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
    
    
            err = NO_ERROR;
        } else if (err == BufferQueue::PRESENT_LATER) {
    
    
            // return the error, without logging
        } else {
    
    
            BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
        }
        return err;
    }

acquireBufferLocked的具体实现逻辑在ConsumerBase::acquireBufferLocked中,其中mConsumer是
IGraphicBufferConsumer对象,具体的实现在GraphicBufferConsumer中。

status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
        nsecs_t presentWhen, uint64_t maxFrameNumber) {
    
    
    if (mAbandoned) {
    
    
        CB_LOGE("acquireBufferLocked: ConsumerBase is abandoned!");
        return NO_INIT;
    }

    status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
    if (err != NO_ERROR) {
    
    
        return err;
    }

    if (item->mGraphicBuffer != nullptr) {
    
    
        if (mSlots[item->mSlot].mGraphicBuffer != nullptr) {
    
    
            freeBufferLocked(item->mSlot);
        }
        mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
    }

    mSlots[item->mSlot].mFrameNumber = item->mFrameNumber;
    mSlots[item->mSlot].mFence = item->mFence;

    CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64,
            item->mSlot, item->mFrameNumber);

    return OK;
}

然后在GraphicBufferConsumer::acquireBuffer()中获取buffer的信息,即bufferItem。因为hdr的元数据已经保存在bufferitem中,所以当acquirebuffer拿到一块buffer时,hdr元数据信息会同步设置过去。

在获取了bufferitem之后,调用BufferLayerConsumer::updateAndReleaseLocked接口,将hdr数据更新到bufferlayerconsumer的状态中

    ...
 // Update the BufferLayerConsumer state.
    mCurrentTexture = slot;
    mCurrentTextureBuffer = nextTextureBuffer;
    mCurrentCrop = item.mCrop;
    mCurrentTransform = item.mTransform;
    mCurrentScalingMode = item.mScalingMode;
    mCurrentTimestamp = item.mTimestamp;
    mCurrentDataSpace = static_cast<ui::Dataspace>(item.mDataSpace);
    
    mCurrentHdrMetadata = item.mHdrMetadata;
    
    mCurrentFence = item.mFence;
    mCurrentFenceTime = item.mFenceTime;
    mCurrentFrameNumber = item.mFrameNumber;
    mCurrentTransformToDisplayInverse = item.mTransformToDisplayInverse;
    mCurrentSurfaceDamage = item.mSurfaceDamage;
    mCurrentApi = item.mApi;
    ...

继续对mCurrentHdrMetadata 进行追踪,如下接口提供了获取buffer hdr数据的功能

const HdrMetadata& BufferLayerConsumer::getCurrentHdrMetadata() const {
    
    
    BLC_LOGV("getCurrentHdrMetadata");
    Mutex::Autolock lock(mMutex);
    return mCurrentHdrMetadata;
}

该接口在bufferQueueLayer中被调用

void BufferQueueLayer::gatherBufferInfo() {
    
    
    BufferLayer::gatherBufferInfo();

    mBufferInfo.mDesiredPresentTime = mConsumer->getTimestamp();
    mBufferInfo.mFenceTime = mConsumer->getCurrentFenceTime();
    mBufferInfo.mFence = mConsumer->getCurrentFence();
    mBufferInfo.mTransform = mConsumer->getCurrentTransform();
    mBufferInfo.mDataspace = translateDataspace(mConsumer->getCurrentDataSpace());
    mBufferInfo.mCrop = mConsumer->getCurrentCrop();
    mBufferInfo.mScaleMode = mConsumer->getCurrentScalingMode();
    mBufferInfo.mSurfaceDamage = mConsumer->getSurfaceDamage();
    
    mBufferInfo.mHdrMetadata = mConsumer->getCurrentHdrMetadata();
    
    mBufferInfo.mApi = mConsumer->getCurrentApi();
    mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse();
}

继续往下追踪,发现在latchbuffer的时候会调用该接口

bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
                              nsecs_t expectedPresentTime) {
    
    
    ATRACE_CALL();

    bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);

    if (refreshRequired) {
    
    
        return refreshRequired;
    }

    if (!hasReadyFrame()) {
    
    
        return false;
    }

    // if we've already called updateTexImage() without going through
    // a composition step, we have to skip this layer at this point
    // because we cannot call updateTeximage() without a corresponding
    // compositionComplete() call.
    // we'll trigger an update in onPreComposition().
    if (mRefreshPending) {
    
    
        return false;
    }

    // If the head buffer's acquire fence hasn't signaled yet, return and
    // try again later
    if (!fenceHasSignaled()) {
    
    
        ATRACE_NAME("!fenceHasSignaled()");
        mFlinger->signalLayerUpdate();
        return false;
    }

    // Capture the old state of the layer for comparisons later
    const State& s(getDrawingState());
    const bool oldOpacity = isOpaque(s);

    BufferInfo oldBufferInfo = mBufferInfo;

    status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime);
    if (err != NO_ERROR) {
    
    
        return false;
    }

    err = updateActiveBuffer();
    if (err != NO_ERROR) {
    
    
        return false;
    }

    err = updateFrameNumber(latchTime);
    if (err != NO_ERROR) {
    
    
        return false;
    }

    gatherBufferInfo();

    mRefreshPending = true;
    if (oldBufferInfo.mBuffer == nullptr) {
    
    
        // the first time we receive a buffer, we need to trigger a
        // geometry invalidation.
        recomputeVisibleRegions = true;
    }

    if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) ||
        (mBufferInfo.mTransform != oldBufferInfo.mTransform) ||
        (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) ||
        (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) {
    
    
        recomputeVisibleRegions = true;
    }

    if (oldBufferInfo.mBuffer != nullptr) {
    
    
        uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth();
        uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight();
        if (bufWidth != uint32_t(oldBufferInfo.mBuffer->getBuffer()->width) ||
            bufHeight != uint32_t(oldBufferInfo.mBuffer->getBuffer()->height)) {
    
    
            recomputeVisibleRegions = true;
        }
    }

    if (oldOpacity != isOpaque(s)) {
    
    
        recomputeVisibleRegions = true;
    }

    return true;
}

latchbuffer就是在invalidate阶段获取buffer用的。所以也就是说,当获取buffer时,会同时获取hdr metadata,即buffer与metadata是绑定的。
在SurfaceFlinger::handlePageFlip()中,如果layer获取到了buffer,并且满足显示的条件,那么就应该送去合成显示。

for (const auto& layer : mLayersWithQueuedFrames) {
    
    
            if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) {
    
    
                mLayersPendingRefresh.push_back(layer);
            }
            layer->useSurfaceDamage();
            if (layer->isBufferLatched()) {
    
    
                newDataLatched = true;
            }
        }
    }

后面基本不会涉及到与buffer相关的操作,因为buffer的信息已经保存在layer的mBufferInfo中,需要时去取即可。
surfaceflinger中hdr layer还有另外的处理,需要继续研究。

猜你喜欢

转载自blog.csdn.net/weixin_45460140/article/details/122720041