以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还有另外的处理,需要继续研究。