/* * Copyright (C) 2007 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. */ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" //#define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "Layer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DisplayDevice.h" #include "DisplayHardware/HWComposer.h" #include "FrameTimeline.h" #include "FrameTracer/FrameTracer.h" #include "FrontEnd/LayerCreationArgs.h" #include "FrontEnd/LayerHandle.h" #include "Layer.h" #include "LayerProtoHelper.h" #include "SurfaceFlinger.h" #include "TimeStats/TimeStats.h" #include "TransactionCallbackInvoker.h" #include "TunnelModeEnabledReporter.h" #include "Utils/FenceUtils.h" #define DEBUG_RESIZE 0 #define EARLY_RELEASE_ENABLED false namespace android { using namespace std::chrono_literals; namespace { constexpr int kDumpTableRowLength = 159; const ui::Transform kIdentityTransform; TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) { using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; const auto frameRateCompatibility = [frameRate] { switch (frameRate.vote.type) { case Layer::FrameRateCompatibility::Default: return FrameRateCompatibility::Default; case Layer::FrameRateCompatibility::ExactOrMultiple: return FrameRateCompatibility::ExactOrMultiple; default: return FrameRateCompatibility::Undefined; } }(); const auto seamlessness = [frameRate] { switch (frameRate.vote.seamlessness) { case scheduler::Seamlessness::OnlySeamless: return Seamlessness::ShouldBeSeamless; case scheduler::Seamlessness::SeamedAndSeamless: return Seamlessness::NotRequired; default: return Seamlessness::Undefined; } }(); return TimeStats::SetFrameRateVote{.frameRate = frameRate.vote.rate.getValue(), .frameRateCompatibility = frameRateCompatibility, .seamlessness = seamlessness}; } } // namespace using namespace ftl::flag_operators; using base::StringAppendF; using frontend::LayerSnapshot; using frontend::RoundedCornerState; using gui::GameMode; using gui::LayerMetadata; using gui::WindowInfo; using ui::Size; using PresentState = frametimeline::SurfaceFrame::PresentState; Layer::Layer(const surfaceflinger::LayerCreationArgs& args) : sequence(args.sequence), mFlinger(sp::fromExisting(args.flinger)), mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)), mWindowType(static_cast( args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))) { ALOGV("Creating Layer %s", getDebugName()); mDrawingState.crop = {0, 0, -1, -1}; mDrawingState.sequence = 0; mDrawingState.transform.set(0, 0); mDrawingState.frameNumber = 0; mDrawingState.previousFrameNumber = 0; mDrawingState.barrierFrameNumber = 0; mDrawingState.producerId = 0; mDrawingState.barrierProducerId = 0; mDrawingState.bufferTransform = 0; mDrawingState.transformToDisplayInverse = false; mDrawingState.acquireFence = sp::make(-1); mDrawingState.acquireFenceTime = std::make_shared(mDrawingState.acquireFence); mDrawingState.dataspace = ui::Dataspace::V0_SRGB; mDrawingState.metadata = args.metadata; mDrawingState.frameTimelineInfo = {}; mDrawingState.postTime = -1; mDeprecatedFrameTracker.setDisplayRefreshPeriod( args.flinger->mScheduler->getPacesetterVsyncPeriod().ns()); mOwnerUid = args.ownerUid; mOwnerPid = args.ownerPid; mOwnerAppId = mOwnerUid % PER_USER_RANGE; mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; mLayerFEs.emplace_back(frontend::LayerHierarchy::TraversalPath{static_cast(sequence)}, args.flinger->getFactory().createLayerFE(mName, this)); } void Layer::onFirstRef() { mFlinger->onLayerFirstRef(this); } Layer::~Layer() { LOG_ALWAYS_FATAL_IF(std::this_thread::get_id() != mFlinger->mMainThreadId, "Layer destructor called off the main thread."); if (mBufferInfo.mBuffer != nullptr) { callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber, mBufferInfo.mFence); } const int32_t layerId = getSequence(); mFlinger->mTimeStats->onDestroy(layerId); mFlinger->mFrameTracer->onDestroy(layerId); mFlinger->onLayerDestroyed(this); const auto currentTime = std::chrono::steady_clock::now(); if (mBufferInfo.mTimeSinceDataspaceUpdate > std::chrono::steady_clock::time_point::min()) { mFlinger->mLayerEvents.emplace_back(mOwnerUid, getSequence(), mBufferInfo.mDataspace, std::chrono::duration_cast( currentTime - mBufferInfo.mTimeSinceDataspaceUpdate)); } if (mDrawingState.sidebandStream != nullptr) { mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); } if (hasTrustedPresentationListener()) { mFlinger->mNumTrustedPresentationListeners--; updateTrustedPresentationState(nullptr, nullptr, -1 /* time_in_ms */, true /* leaveState*/); } } // --------------------------------------------------------------------------- // set-up // --------------------------------------------------------------------------- sp Layer::getHandle() { Mutex::Autolock _l(mLock); if (mGetHandleCalled) { ALOGE("Get handle called twice" ); return nullptr; } mGetHandleCalled = true; mHandleAlive = true; return sp::make(mFlinger, sp::fromExisting(this)); } // --------------------------------------------------------------------------- // h/w composer set-up // --------------------------------------------------------------------------- // No early returns. void Layer::updateTrustedPresentationState(const DisplayDevice* display, const frontend::LayerSnapshot* snapshot, int64_t time_in_ms, bool leaveState) { if (!hasTrustedPresentationListener()) { return; } const bool lastState = mLastComputedTrustedPresentationState; mLastComputedTrustedPresentationState = false; if (!leaveState) { const auto outputLayer = findOutputLayerForDisplay(display, snapshot->path); if (outputLayer != nullptr) { if (outputLayer->getState().coveredRegionExcludingDisplayOverlays) { Region coveredRegion = *outputLayer->getState().coveredRegionExcludingDisplayOverlays; mLastComputedTrustedPresentationState = computeTrustedPresentationState(snapshot->geomLayerBounds, snapshot->sourceBounds(), coveredRegion, snapshot->transformedBounds, snapshot->alpha, snapshot->geomLayerTransform, mTrustedPresentationThresholds); } else { ALOGE("CoveredRegionExcludingDisplayOverlays was not set for %s. Don't compute " "TrustedPresentationState", getDebugName()); } } } const bool newState = mLastComputedTrustedPresentationState; if (lastState && !newState) { // We were in the trusted presentation state, but now we left it, // emit the callback if needed if (mLastReportedTrustedPresentationState) { mLastReportedTrustedPresentationState = false; mTrustedPresentationListener.invoke(false); } // Reset the timer mEnteredTrustedPresentationStateTime = -1; } else if (!lastState && newState) { // We were not in the trusted presentation state, but we entered it, begin the timer // and make sure this gets called at least once more! mEnteredTrustedPresentationStateTime = time_in_ms; mFlinger->forceFutureUpdate(mTrustedPresentationThresholds.stabilityRequirementMs * 1.5); } // Has the timer elapsed, but we are still in the state? Emit a callback if needed if (!mLastReportedTrustedPresentationState && newState && (time_in_ms - mEnteredTrustedPresentationStateTime > mTrustedPresentationThresholds.stabilityRequirementMs)) { mLastReportedTrustedPresentationState = true; mTrustedPresentationListener.invoke(true); } } /** * See SurfaceComposerClient.h: setTrustedPresentationCallback for discussion * of how the parameters and thresholds are interpreted. The general spirit is * to produce an upper bound on the amount of the buffer which was presented. */ bool Layer::computeTrustedPresentationState(const FloatRect& bounds, const FloatRect& sourceBounds, const Region& coveredRegion, const FloatRect& screenBounds, float alpha, const ui::Transform& effectiveTransform, const TrustedPresentationThresholds& thresholds) { if (alpha < thresholds.minAlpha) { return false; } if (sourceBounds.getWidth() == 0 || sourceBounds.getHeight() == 0) { return false; } if (screenBounds.getWidth() == 0 || screenBounds.getHeight() == 0) { return false; } const float sx = effectiveTransform.dsdx(); const float sy = effectiveTransform.dsdy(); float fractionRendered = std::min(sx * sy, 1.0f); float boundsOverSourceW = bounds.getWidth() / (float)sourceBounds.getWidth(); float boundsOverSourceH = bounds.getHeight() / (float)sourceBounds.getHeight(); fractionRendered *= boundsOverSourceW * boundsOverSourceH; Region tJunctionFreeRegion = Region::createTJunctionFreeRegion(coveredRegion); // Compute the size of all the rects since they may be disconnected. float coveredSize = 0; for (auto rect = tJunctionFreeRegion.begin(); rect < tJunctionFreeRegion.end(); rect++) { float size = rect->width() * rect->height(); coveredSize += size; } fractionRendered *= (1 - (coveredSize / (screenBounds.getWidth() * screenBounds.getHeight()))); if (fractionRendered < thresholds.minFractionRendered) { return false; } return true; } Rect Layer::getCroppedBufferSize(const State& s) const { Rect size = getBufferSize(s); Rect crop = Rect(getCrop(s)); if (!crop.isEmpty() && size.isValid()) { size.intersect(crop, &size); } else if (!crop.isEmpty()) { size = crop; } return size; } const char* Layer::getDebugName() const { return mName.c_str(); } // --------------------------------------------------------------------------- // drawing... // --------------------------------------------------------------------------- aidl::android::hardware::graphics::composer3::Composition Layer::getCompositionType( const DisplayDevice& display) const { const auto outputLayer = findOutputLayerForDisplay(&display); return getCompositionType(outputLayer); } aidl::android::hardware::graphics::composer3::Composition Layer::getCompositionType( const compositionengine::OutputLayer* outputLayer) const { if (outputLayer == nullptr) { return aidl::android::hardware::graphics::composer3::Composition::INVALID; } if (outputLayer->getState().hwc) { return (*outputLayer->getState().hwc).hwcCompositionType; } else { return aidl::android::hardware::graphics::composer3::Composition::CLIENT; } } // ---------------------------------------------------------------------------- // transaction // ---------------------------------------------------------------------------- void Layer::commitTransaction() { // Set the present state for all bufferlessSurfaceFramesTX to Presented. The // bufferSurfaceFrameTX will be presented in latchBuffer. for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) { if (surfaceFrame->getPresentState() != PresentState::Presented) { // With applyPendingStates, we could end up having presented surfaceframes from previous // states surfaceFrame->setPresentState(PresentState::Presented, mLastLatchTime); mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame); } } mDrawingState.bufferlessSurfaceFramesTX.clear(); } void Layer::setTransactionFlags(uint32_t mask) { mTransactionFlags |= mask; } bool Layer::setCrop(const FloatRect& crop) { if (mDrawingState.crop == crop) return false; mDrawingState.sequence++; mDrawingState.crop = crop; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE; }; void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime, gui::GameMode gameMode) { mDrawingState.postTime = postTime; // Check if one of the bufferlessSurfaceFramesTX contains the same vsyncId. This can happen if // there are two transactions with the same token, the first one without a buffer and the // second one with a buffer. We promote the bufferlessSurfaceFrame to a bufferSurfaceFrameTX // in that case. auto it = mDrawingState.bufferlessSurfaceFramesTX.find(info.vsyncId); if (it != mDrawingState.bufferlessSurfaceFramesTX.end()) { // Promote the bufferlessSurfaceFrame to a bufferSurfaceFrameTX mDrawingState.bufferSurfaceFrameTX = it->second; mDrawingState.bufferlessSurfaceFramesTX.erase(it); mDrawingState.bufferSurfaceFrameTX->promoteToBuffer(); mDrawingState.bufferSurfaceFrameTX->setActualQueueTime(postTime); } else { mDrawingState.bufferSurfaceFrameTX = createSurfaceFrameForBuffer(info, postTime, mTransactionName, gameMode); } setFrameTimelineVsyncForSkippedFrames(info, postTime, mTransactionName, gameMode); } void Layer::setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info, nsecs_t postTime, gui::GameMode gameMode) { mDrawingState.frameTimelineInfo = info; mDrawingState.postTime = postTime; setTransactionFlags(eTransactionNeeded); if (const auto& bufferSurfaceFrameTX = mDrawingState.bufferSurfaceFrameTX; bufferSurfaceFrameTX != nullptr) { if (bufferSurfaceFrameTX->getToken() == info.vsyncId) { // BufferSurfaceFrame takes precedence over BufferlessSurfaceFrame. If the same token is // being used for BufferSurfaceFrame, don't create a new one. return; } } // For Transactions without a buffer, we create only one SurfaceFrame per vsyncId. If multiple // transactions use the same vsyncId, we just treat them as one SurfaceFrame (unless they are // targeting different vsyncs). auto it = mDrawingState.bufferlessSurfaceFramesTX.find(info.vsyncId); if (it == mDrawingState.bufferlessSurfaceFramesTX.end()) { auto surfaceFrame = createSurfaceFrameForTransaction(info, postTime, gameMode); mDrawingState.bufferlessSurfaceFramesTX[info.vsyncId] = surfaceFrame; } else { if (it->second->getPresentState() == PresentState::Presented) { // If the SurfaceFrame was already presented, its safe to overwrite it since it must // have been from previous vsync. it->second = createSurfaceFrameForTransaction(info, postTime, gameMode); } } setFrameTimelineVsyncForSkippedFrames(info, postTime, mTransactionName, gameMode); } void Layer::addSurfaceFrameDroppedForBuffer( std::shared_ptr& surfaceFrame, nsecs_t dropTime) { surfaceFrame->setDropTime(dropTime); surfaceFrame->setPresentState(PresentState::Dropped); mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame); } void Layer::addSurfaceFramePresentedForBuffer( std::shared_ptr& surfaceFrame, nsecs_t acquireFenceTime, nsecs_t currentLatchTime) { surfaceFrame->setAcquireFenceTime(acquireFenceTime); surfaceFrame->setPresentState(PresentState::Presented, mLastLatchTime); mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame); updateLastLatchTime(currentLatchTime); } std::shared_ptr Layer::createSurfaceFrameForTransaction( const FrameTimelineInfo& info, nsecs_t postTime, gui::GameMode gameMode) { auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, getSequence(), mName, mTransactionName, /*isBuffer*/ false, gameMode); // Buffer hasn't yet been latched, so use mDrawingState surfaceFrame->setDesiredPresentTime(mDrawingState.desiredPresentTime); surfaceFrame->setActualStartTime(info.startTimeNanos); // For Transactions, the post time is considered to be both queue and acquire fence time. surfaceFrame->setActualQueueTime(postTime); surfaceFrame->setAcquireFenceTime(postTime); const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); if (fps) { surfaceFrame->setRenderRate(*fps); } return surfaceFrame; } std::shared_ptr Layer::createSurfaceFrameForBuffer( const FrameTimelineInfo& info, nsecs_t queueTime, std::string debugName, gui::GameMode gameMode) { auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, getSequence(), mName, debugName, /*isBuffer*/ true, gameMode); // Buffer hasn't yet been latched, so use mDrawingState surfaceFrame->setDesiredPresentTime(mDrawingState.desiredPresentTime); surfaceFrame->setActualStartTime(info.startTimeNanos); // For buffers, acquire fence time will set during latch. surfaceFrame->setActualQueueTime(queueTime); const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); if (fps) { surfaceFrame->setRenderRate(*fps); } return surfaceFrame; } void Layer::setFrameTimelineVsyncForSkippedFrames(const FrameTimelineInfo& info, nsecs_t postTime, std::string debugName, gui::GameMode gameMode) { if (info.skippedFrameVsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { return; } FrameTimelineInfo skippedFrameTimelineInfo = info; skippedFrameTimelineInfo.vsyncId = info.skippedFrameVsyncId; auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(skippedFrameTimelineInfo, mOwnerPid, mOwnerUid, getSequence(), mName, debugName, /*isBuffer*/ false, gameMode); // Buffer hasn't yet been latched, so use mDrawingState surfaceFrame->setDesiredPresentTime(mDrawingState.desiredPresentTime); surfaceFrame->setActualStartTime(skippedFrameTimelineInfo.skippedFrameStartTimeNanos); // For Transactions, the post time is considered to be both queue and acquire fence time. surfaceFrame->setActualQueueTime(postTime); surfaceFrame->setAcquireFenceTime(postTime); const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); if (fps) { surfaceFrame->setRenderRate(*fps); } addSurfaceFrameDroppedForBuffer(surfaceFrame, postTime); } bool Layer::setFrameRateForLayerTree(FrameRate frameRate, const scheduler::LayerProps& layerProps, nsecs_t now) { if (mDrawingState.frameRateForLayerTree == frameRate) { return false; } mDrawingState.frameRateForLayerTree = frameRate; mFlinger->mScheduler ->recordLayerHistory(sequence, layerProps, now, now, scheduler::LayerHistory::LayerUpdateType::SetFrameRate); return true; } Layer::FrameRate Layer::getFrameRateForLayerTree() const { return getDrawingState().frameRateForLayerTree; } // ---------------------------------------------------------------------------- // debugging // ---------------------------------------------------------------------------- void Layer::miniDumpHeader(std::string& result) { result.append(kDumpTableRowLength, '-'); result.append("\n"); result.append(" Layer name\n"); result.append(" Z | "); result.append(" Window Type | "); result.append(" Comp Type | "); result.append(" Transform | "); result.append(" Disp Frame (LTRB) | "); result.append(" Source Crop (LTRB) | "); result.append(" Frame Rate (Explicit) (Seamlessness) [Focused]\n"); result.append(kDumpTableRowLength, '-'); result.append("\n"); } void Layer::miniDump(std::string& result, const frontend::LayerSnapshot& snapshot, const DisplayDevice& display) const { const auto outputLayer = findOutputLayerForDisplay(&display, snapshot.path); if (!outputLayer) { return; } StringAppendF(&result, " %s\n", snapshot.debugName.c_str()); StringAppendF(&result, " %10zu | ", snapshot.globalZ); StringAppendF(&result, " %10d | ", snapshot.layerMetadata.getInt32(gui::METADATA_WINDOW_TYPE, 0)); StringAppendF(&result, "%10s | ", toString(getCompositionType(outputLayer)).c_str()); const auto& outputLayerState = outputLayer->getState(); StringAppendF(&result, "%10s | ", toString(outputLayerState.bufferTransform).c_str()); const Rect& frame = outputLayerState.displayFrame; StringAppendF(&result, "%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom); const FloatRect& crop = outputLayerState.sourceCrop; StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f | ", crop.left, crop.top, crop.right, crop.bottom); const auto frameRate = snapshot.frameRate; std::string frameRateStr; if (frameRate.vote.rate.isValid()) { StringAppendF(&frameRateStr, "%.2f", frameRate.vote.rate.getValue()); } if (frameRate.vote.rate.isValid() || frameRate.vote.type != FrameRateCompatibility::Default) { StringAppendF(&result, "%6s %15s %17s", frameRateStr.c_str(), ftl::enum_string(frameRate.vote.type).c_str(), ftl::enum_string(frameRate.vote.seamlessness).c_str()); } else if (frameRate.category != FrameRateCategory::Default) { StringAppendF(&result, "%6s %15s %17s", frameRateStr.c_str(), (std::string("Cat::") + ftl::enum_string(frameRate.category)).c_str(), ftl::enum_string(frameRate.vote.seamlessness).c_str()); } else { result.append(41, ' '); } const auto focused = isLayerFocusedBasedOnPriority(snapshot.frameRateSelectionPriority); StringAppendF(&result, " [%s]\n", focused ? "*" : " "); result.append(kDumpTableRowLength, '-'); result.append("\n"); } void Layer::dumpFrameStats(std::string& result) const { if (FlagManager::getInstance().deprecate_frame_tracker()) { FrameStats fs = FrameStats(); getFrameStats(&fs); for (auto desired = fs.desiredPresentTimesNano.begin(), actual = fs.actualPresentTimesNano.begin(), ready = fs.frameReadyTimesNano.begin(); desired != fs.desiredPresentTimesNano.end() && actual != fs.actualPresentTimesNano.end() && ready != fs.frameReadyTimesNano.end(); ++desired, ++actual, ++ready) { result.append(std::format("{}\t{}\t{}\n", *desired, *actual, *ready)); } result.push_back('\n'); } else { mDeprecatedFrameTracker.dumpStats(result); } } void Layer::clearFrameStats() { if (FlagManager::getInstance().deprecate_frame_tracker()) { mFrameStatsHistorySize = 0; } else { mDeprecatedFrameTracker.clearStats(); } } void Layer::getFrameStats(FrameStats* outStats) const { if (FlagManager::getInstance().deprecate_frame_tracker()) { if (auto ftl = getTimeline()) { float fps = ftl->get().computeFps({getSequence()}); ftl->get().generateFrameStats(getSequence(), mFrameStatsHistorySize, outStats); outStats->refreshPeriodNano = Fps::fromValue(fps).getPeriodNsecs(); } } else { mDeprecatedFrameTracker.getStats(outStats); } } void Layer::onDisconnect() { const int32_t layerId = getSequence(); mFlinger->mTimeStats->onDestroy(layerId); mFlinger->mFrameTracer->onDestroy(layerId); } void Layer::writeCompositionStateToProto(perfetto::protos::LayerProto* layerProto, ui::LayerStack layerStack) { ftl::FakeGuard guard(mFlinger->mStateLock); // Called from the main thread. ftl::FakeGuard mainThreadGuard(kMainThreadContext); // Only populate for the primary display. if (const auto display = mFlinger->getDisplayFromLayerStack(layerStack)) { const auto compositionType = getCompositionType(*display); layerProto->set_hwc_composition_type( static_cast(compositionType)); LayerProtoHelper::writeToProto(getVisibleRegion(display), [&]() { return layerProto->mutable_visible_region(); }); } } compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( const DisplayDevice* display) const { if (!display) return nullptr; sp layerFE; frontend::LayerHierarchy::TraversalPath path{.id = static_cast(sequence)}; for (auto& [p, layer] : mLayerFEs) { if (p == path) { layerFE = layer; } } if (!layerFE) return nullptr; return display->getCompositionDisplay()->getOutputLayerForLayer(layerFE); } compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( const DisplayDevice* display, const frontend::LayerHierarchy::TraversalPath& path) const { if (!display) return nullptr; sp layerFE; for (auto& [p, layer] : mLayerFEs) { if (p == path) { layerFE = layer; } } if (!layerFE) return nullptr; return display->getCompositionDisplay()->getOutputLayerForLayer(layerFE); } Region Layer::getVisibleRegion(const DisplayDevice* display) const { const auto outputLayer = findOutputLayerForDisplay(display); return outputLayer ? outputLayer->getState().visibleRegion : Region(); } void Layer::callReleaseBufferCallback(const sp& listener, const sp& buffer, uint64_t framenumber, const sp& releaseFence) { if (!listener && !mBufferReleaseChannel) { return; } SFTRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); ReleaseCallbackId callbackId{buffer->getId(), framenumber}; const sp& fence = releaseFence ? releaseFence : Fence::NO_FENCE; uint32_t currentMaxAcquiredBufferCount = mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); if (listener) { listener->onReleaseBuffer(callbackId, fence, currentMaxAcquiredBufferCount); } if (!mBufferReleaseChannel) { return; } status_t status = mBufferReleaseChannel->writeReleaseFence(callbackId, fence, currentMaxAcquiredBufferCount); if (status != OK) { int error = -status; // callReleaseBufferCallback is called during Layer's destructor. In this case, it's // expected to receive connection errors. if (error != EPIPE && error != ECONNRESET) { ALOGD("[%s] writeReleaseFence failed. error %d (%s)", getDebugName(), error, strerror(error)); } } } sp Layer::findCallbackHandle() { // If we are displayed on multiple displays in a single composition cycle then we would // need to do careful tracking to enable the use of the mLastClientCompositionFence. // For example we can only use it if all the displays are client comp, and we need // to merge all the client comp fences. We could do this, but for now we just // disable the optimization when a layer is composed on multiple displays. if (mClearClientCompositionFenceOnLayerDisplayed) { mLastClientCompositionFence = nullptr; } else { mClearClientCompositionFenceOnLayerDisplayed = true; } // The previous release fence notifies the client that SurfaceFlinger is done with the previous // buffer that was presented on this layer. The first transaction that came in this frame that // replaced the previous buffer on this layer needs this release fence, because the fence will // let the client know when that previous buffer is removed from the screen. // // Every other transaction on this layer does not need a release fence because no other // Transactions that were set on this layer this frame are going to have their preceding buffer // removed from the display this frame. // // For example, if we have 3 transactions this frame. The first transaction doesn't contain a // buffer so it doesn't need a previous release fence because the layer still needs the previous // buffer. The second transaction contains a buffer so it needs a previous release fence because // the previous buffer will be released this frame. The third transaction also contains a // buffer. It replaces the buffer in the second transaction. The buffer in the second // transaction will now no longer be presented so it is released immediately and the third // transaction doesn't need a previous release fence. sp ch; for (auto& handle : mDrawingState.callbackHandles) { if (handle->releasePreviousBuffer && mPreviousReleaseBufferEndpoint == handle->listener) { ch = handle; break; } } return ch; } void Layer::prepareReleaseCallbacks(ftl::Future futureFenceResult, ui::LayerStack layerStack) { sp ch = findCallbackHandle(); if (ch != nullptr) { ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; ch->previousReleaseFences.emplace_back(std::move(futureFenceResult)); ch->name = mName; } else { // If we didn't get a release callback yet (e.g. some scenarios when capturing // screenshots asynchronously) then make sure we don't drop the fence. // Older fences for the same layer stack can be dropped when a new fence arrives. // An assumption here is that RenderEngine performs work sequentially, so an // incoming fence will not fire before an existing fence. mAdditionalPreviousReleaseFences.emplace_or_replace(layerStack, std::move(futureFenceResult)); } if (mBufferInfo.mBuffer) { mPreviouslyPresentedLayerStacks.push_back(layerStack); } if (mDrawingState.frameNumber > 0) { mDrawingState.previousFrameNumber = mDrawingState.frameNumber; } } void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { for (const auto& handle : mDrawingState.callbackHandles) { handle->bufferReleaseChannel = mBufferReleaseChannel; handle->transformHint = mTransformHint; handle->dequeueReadyTime = dequeueReadyTime; handle->currentMaxAcquiredBufferCount = mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); SFTRACE_FORMAT_INSTANT("releasePendingBuffer %s - %" PRIu64, getDebugName(), handle->previousReleaseCallbackId.framenumber); } for (auto& handle : mDrawingState.callbackHandles) { if (handle->releasePreviousBuffer && mPreviousReleaseBufferEndpoint == handle->listener) { handle->previousReleaseCallbackId = mPreviousReleaseCallbackId; break; } } mFlinger->getTransactionCallbackInvoker().addCallbackHandles(mDrawingState.callbackHandles); mDrawingState.callbackHandles = {}; } bool Layer::setTransform(uint32_t transform) { if (mDrawingState.bufferTransform == transform) return false; mDrawingState.bufferTransform = transform; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setTransformToDisplayInverse(bool transformToDisplayInverse) { if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false; mDrawingState.sequence++; mDrawingState.transformToDisplayInverse = transformToDisplayInverse; setTransactionFlags(eTransactionNeeded); return true; } void Layer::releasePreviousBuffer() { mReleasePreviousBuffer = true; if (!mBufferInfo.mBuffer || (!mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer) || mDrawingState.frameNumber != mBufferInfo.mFrameNumber)) { // If mDrawingState has a buffer, and we are about to update again // before swapping to drawing state, then the first buffer will be // dropped and we should decrement the pending buffer count and // call any release buffer callbacks if set. callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, mDrawingState.acquireFence); const int32_t layerId = getSequence(); mFlinger->mTimeStats->removeTimeRecord(layerId, mDrawingState.frameNumber); decrementPendingBufferCount(); if (mDrawingState.bufferSurfaceFrameTX != nullptr && mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) { addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX, systemTime()); mDrawingState.bufferSurfaceFrameTX.reset(); } } else if (EARLY_RELEASE_ENABLED && mLastClientCompositionFence != nullptr) { callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, mLastClientCompositionFence); mLastClientCompositionFence = nullptr; } } void Layer::resetDrawingStateBufferInfo() { mDrawingState.producerId = 0; mDrawingState.frameNumber = 0; mDrawingState.previousFrameNumber = 0; mDrawingState.releaseBufferListener = nullptr; mDrawingState.buffer = nullptr; mDrawingState.acquireFence = sp::make(-1); mDrawingState.acquireFenceTime = std::make_unique(mDrawingState.acquireFence); mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFenceTime->getSignalTime(); mDrawingState.releaseBufferEndpoint = nullptr; } bool Layer::setBuffer(std::shared_ptr& buffer, const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const FrameTimelineInfo& info, gui::GameMode gameMode) { SFTRACE_FORMAT("setBuffer %s - hasBuffer=%s", getDebugName(), (buffer ? "true" : "false")); const bool frameNumberChanged = bufferData.flags.test(BufferData::BufferDataChange::frameNumberChanged); const uint64_t frameNumber = frameNumberChanged ? bufferData.frameNumber : mDrawingState.frameNumber + 1; SFTRACE_FORMAT_INSTANT("setBuffer %s - %" PRIu64, getDebugName(), frameNumber); if (mDrawingState.buffer) { releasePreviousBuffer(); } else if (buffer) { // if we are latching a buffer for the first time then clear the mLastLatchTime since // we don't want to incorrectly classify a frame if we miss the desired present time. updateLastLatchTime(0); } mDrawingState.desiredPresentTime = desiredPresentTime; mDrawingState.isAutoTimestamp = isAutoTimestamp; mDrawingState.latchedVsyncId = info.vsyncId; mDrawingState.useVsyncIdForRefreshRateSelection = info.useForRefreshRateSelection; if (!buffer) { resetDrawingStateBufferInfo(); setTransactionFlags(eTransactionNeeded); mDrawingState.bufferSurfaceFrameTX = nullptr; setFrameTimelineVsyncForBufferlessTransaction(info, postTime, gameMode); return true; } else { // release sideband stream if it exists and a non null buffer is being set if (mDrawingState.sidebandStream != nullptr) { setSidebandStream(nullptr, info, postTime, gameMode); } } if ((mDrawingState.producerId > bufferData.producerId) || ((mDrawingState.producerId == bufferData.producerId) && (mDrawingState.frameNumber > frameNumber))) { ALOGE("Out of order buffers detected for %s producedId=%d frameNumber=%" PRIu64 " -> producedId=%d frameNumber=%" PRIu64, getDebugName(), mDrawingState.producerId, mDrawingState.frameNumber, bufferData.producerId, frameNumber); TransactionTraceWriter::getInstance().invoke("out_of_order_buffers_", /*overwrite=*/false); } mDrawingState.producerId = bufferData.producerId; mDrawingState.barrierProducerId = std::max(mDrawingState.producerId, mDrawingState.barrierProducerId); mDrawingState.frameNumber = frameNumber; mDrawingState.barrierFrameNumber = std::max(mDrawingState.frameNumber, mDrawingState.barrierFrameNumber); mDrawingState.releaseBufferListener = bufferData.releaseBufferListener; mDrawingState.buffer = std::move(buffer); mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) ? bufferData.acquireFence : Fence::NO_FENCE; mDrawingState.acquireFenceTime = std::make_unique(mDrawingState.acquireFence); if (mDrawingState.acquireFenceTime->getSignalTime() == Fence::SIGNAL_TIME_PENDING) { // We latched this buffer unsiganled, so we need to pass the acquire fence // on the callback instead of just the acquire time, since it's unknown at // this point. mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFence; } else { mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFenceTime->getSignalTime(); } setTransactionFlags(eTransactionNeeded); const int32_t layerId = getSequence(); mFlinger->mTimeStats->setPostTime(layerId, mDrawingState.frameNumber, getName().c_str(), mOwnerUid, postTime, gameMode); setFrameTimelineVsyncForBufferTransaction(info, postTime, gameMode); if (bufferData.dequeueTime > 0) { const uint64_t bufferId = mDrawingState.buffer->getId(); mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, bufferData.dequeueTime, FrameTracer::FrameEvent::DEQUEUE); mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime, FrameTracer::FrameEvent::QUEUE); } mDrawingState.releaseBufferEndpoint = bufferData.releaseBufferEndpoint; // If the layer had been updated a TextureView, this would make sure the present time could be // same to TextureView update when it's a small dirty, and get the correct heuristic rate. if (mFlinger->mScheduler->supportSmallDirtyDetection(mOwnerAppId)) { if (mDrawingState.useVsyncIdForRefreshRateSelection) { mUsedVsyncIdForRefreshRateSelection = true; } } return true; } void Layer::setDesiredPresentTime(nsecs_t desiredPresentTime, bool isAutoTimestamp) { mDrawingState.desiredPresentTime = desiredPresentTime; mDrawingState.isAutoTimestamp = isAutoTimestamp; } void Layer::recordLayerHistoryBufferUpdate(const scheduler::LayerProps& layerProps, nsecs_t now) { SFTRACE_CALL(); const nsecs_t presentTime = [&] { if (!mDrawingState.isAutoTimestamp) { SFTRACE_FORMAT_INSTANT("desiredPresentTime"); return mDrawingState.desiredPresentTime; } if (mDrawingState.useVsyncIdForRefreshRateSelection) { const auto prediction = mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken( mDrawingState.latchedVsyncId); if (prediction.has_value()) { SFTRACE_FORMAT_INSTANT("predictedPresentTime"); mMaxTimeForUseVsyncId = prediction->presentTime + scheduler::LayerHistory::kMaxPeriodForHistory.count(); return prediction->presentTime; } } if (!mFlinger->mScheduler->supportSmallDirtyDetection(mOwnerAppId)) { return static_cast(0); } // If the layer is not an application and didn't set an explicit rate or desiredPresentTime, // return "0" to tell the layer history that it will use the max refresh rate without // calculating the adaptive rate. if (mWindowType != WindowInfo::Type::APPLICATION && mWindowType != WindowInfo::Type::BASE_APPLICATION) { return static_cast(0); } // Return the valid present time only when the layer potentially updated a TextureView so // LayerHistory could heuristically calculate the rate if the UI is continually updating. if (mUsedVsyncIdForRefreshRateSelection) { const auto prediction = mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken( mDrawingState.latchedVsyncId); if (prediction.has_value()) { if (mMaxTimeForUseVsyncId >= prediction->presentTime) { return prediction->presentTime; } mUsedVsyncIdForRefreshRateSelection = false; } } return static_cast(0); }(); if (SFTRACE_ENABLED() && presentTime > 0) { const auto presentIn = TimePoint::fromNs(presentTime) - TimePoint::now(); SFTRACE_FORMAT_INSTANT("presentIn %s", to_string(presentIn).c_str()); } mFlinger->mScheduler->recordLayerHistory(sequence, layerProps, presentTime, now, scheduler::LayerHistory::LayerUpdateType::Buffer); } void Layer::recordLayerHistoryAnimationTx(const scheduler::LayerProps& layerProps, nsecs_t now) { const nsecs_t presentTime = mDrawingState.isAutoTimestamp ? 0 : mDrawingState.desiredPresentTime; mFlinger->mScheduler->recordLayerHistory(sequence, layerProps, presentTime, now, scheduler::LayerHistory::LayerUpdateType::AnimationTX); } bool Layer::setDataspace(ui::Dataspace dataspace) { if (mDrawingState.dataspace == dataspace) return false; mDrawingState.dataspace = dataspace; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setExtendedRangeBrightness(float currentBufferRatio, float desiredRatio) { if (mDrawingState.currentHdrSdrRatio == currentBufferRatio && mDrawingState.desiredHdrSdrRatio == desiredRatio) return false; mDrawingState.currentHdrSdrRatio = currentBufferRatio; mDrawingState.desiredHdrSdrRatio = desiredRatio; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setDesiredHdrHeadroom(float desiredRatio) { if (mDrawingState.desiredHdrSdrRatio == desiredRatio) return false; mDrawingState.desiredHdrSdrRatio = desiredRatio; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setSidebandStream(const sp& sidebandStream, const FrameTimelineInfo& info, nsecs_t postTime, gui::GameMode gameMode) { if (mDrawingState.sidebandStream == sidebandStream) return false; if (mDrawingState.sidebandStream != nullptr && sidebandStream == nullptr) { mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); } else if (sidebandStream != nullptr) { mFlinger->mTunnelModeEnabledReporter->incrementTunnelModeCount(); } mDrawingState.sidebandStream = sidebandStream; if (sidebandStream != nullptr && mDrawingState.buffer != nullptr) { releasePreviousBuffer(); resetDrawingStateBufferInfo(); mDrawingState.bufferSurfaceFrameTX = nullptr; setFrameTimelineVsyncForBufferlessTransaction(info, postTime, gameMode); } setTransactionFlags(eTransactionNeeded); if (!mSidebandStreamChanged.exchange(true)) { // mSidebandStreamChanged was false mFlinger->onLayerUpdate(); } return true; } bool Layer::setTransactionCompletedListeners(const std::vector>& handles, bool willPresent) { // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return if (handles.empty()) { mReleasePreviousBuffer = false; return false; } std::deque> remainingHandles; for (const auto& handle : handles) { // If this transaction set a buffer on this layer, release its previous buffer handle->releasePreviousBuffer = mReleasePreviousBuffer; // If this layer will be presented in this frame if (willPresent) { // If this transaction set an acquire fence on this layer, set its acquire time handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence; handle->frameNumber = mDrawingState.frameNumber; handle->previousFrameNumber = mDrawingState.previousFrameNumber; if (mPreviousReleaseBufferEndpoint == handle->listener) { // Add fence from previous screenshot now so that it can be dispatched to the // client. for (auto& [_, future] : mAdditionalPreviousReleaseFences) { handle->previousReleaseFences.emplace_back(std::move(future)); } mAdditionalPreviousReleaseFences.clear(); } // Store so latched time and release fence can be set mDrawingState.callbackHandles.push_back(handle); } else { // If this layer will NOT need to be relatched and presented this frame // Queue this handle to be notified below. remainingHandles.push_back(handle); } } if (!remainingHandles.empty()) { // Notify the transaction completed threads these handles are done. These are only the // handles that were not added to the mDrawingState, which will be notified later. mFlinger->getTransactionCallbackInvoker().addCallbackHandles(remainingHandles); } mReleasePreviousBuffer = false; mCallbackHandleAcquireTimeOrFence = -1; return willPresent; } Rect Layer::getBufferSize(const State& /*s*/) const { // for buffer state layers we use the display frame size as the buffer size. if (mBufferInfo.mBuffer == nullptr) { return Rect::INVALID_RECT; } uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { std::swap(bufWidth, bufHeight); } if (getTransformToDisplayInverse()) { uint32_t invTransform = SurfaceFlinger::getActiveDisplayRotationFlags(); if (invTransform & ui::Transform::ROT_90) { std::swap(bufWidth, bufHeight); } } return Rect(0, 0, static_cast(bufWidth), static_cast(bufHeight)); } bool Layer::fenceHasSignaled() const { if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { return true; } const bool fenceSignaled = getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled; if (!fenceSignaled) { mFlinger->mTimeStats->incrementLatchSkipped(getSequence(), TimeStats::LatchSkipReason::LateAcquire); } return fenceSignaled; } void Layer::onPreComposition(nsecs_t refreshStartTime) { for (const auto& handle : mDrawingState.callbackHandles) { handle->refreshStartTime = refreshStartTime; } } bool Layer::latchSidebandStream(bool& recomputeVisibleRegions) { if (mSidebandStreamChanged.exchange(false)) { const State& s(getDrawingState()); // mSidebandStreamChanged was true mSidebandStream = s.sidebandStream; if (mSidebandStream != nullptr) { setTransactionFlags(eTransactionNeeded); mFlinger->setTransactionFlags(eTraversalNeeded); } recomputeVisibleRegions = true; return true; } return false; } void Layer::updateTexImage(nsecs_t latchTime, bool bgColorOnly) { const State& s(getDrawingState()); if (!s.buffer) { if (bgColorOnly || mBufferInfo.mBuffer) { for (auto& handle : mDrawingState.callbackHandles) { handle->latchTime = latchTime; } } return; } for (auto& handle : mDrawingState.callbackHandles) { if (handle->frameNumber == mDrawingState.frameNumber) { handle->latchTime = latchTime; } } const int32_t layerId = getSequence(); const uint64_t bufferId = mDrawingState.buffer->getId(); const uint64_t frameNumber = mDrawingState.frameNumber; const auto acquireFence = std::make_shared(mDrawingState.acquireFence); mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence); mFlinger->mTimeStats->setLatchTime(layerId, frameNumber, latchTime); mFlinger->mFrameTracer->traceFence(layerId, bufferId, frameNumber, acquireFence, FrameTracer::FrameEvent::ACQUIRE_FENCE); mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, latchTime, FrameTracer::FrameEvent::LATCH); auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX; if (bufferSurfaceFrame != nullptr && bufferSurfaceFrame->getPresentState() != PresentState::Presented) { // Update only if the bufferSurfaceFrame wasn't already presented. A Presented // bufferSurfaceFrame could be seen here if a pending state was applied successfully and we // are processing the next state. addSurfaceFramePresentedForBuffer(bufferSurfaceFrame, mDrawingState.acquireFenceTime->getSignalTime(), latchTime); mDrawingState.bufferSurfaceFrameTX.reset(); } std::deque> remainingHandles; mFlinger->getTransactionCallbackInvoker() .addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles); mDrawingState.callbackHandles = remainingHandles; } void Layer::gatherBufferInfo() { mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber}; mPreviousReleaseBufferEndpoint = mBufferInfo.mReleaseBufferEndpoint; if (!mDrawingState.buffer) { mBufferInfo = {}; return; } if ((!mBufferInfo.mBuffer || !mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer))) { decrementPendingBufferCount(); } mBufferInfo.mBuffer = mDrawingState.buffer; mBufferInfo.mReleaseBufferEndpoint = mDrawingState.releaseBufferEndpoint; mBufferInfo.mFence = mDrawingState.acquireFence; mBufferInfo.mFrameNumber = mDrawingState.frameNumber; mBufferInfo.mPixelFormat = !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat(); mBufferInfo.mFrameLatencyNeeded = true; mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime; mBufferInfo.mFenceTime = std::make_shared(mDrawingState.acquireFence); mBufferInfo.mTransform = mDrawingState.bufferTransform; auto lastDataspace = mBufferInfo.mDataspace; mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace); if (mBufferInfo.mBuffer != nullptr) { auto& mapper = GraphicBufferMapper::get(); // TODO: We should measure if it's faster to do a blind write if we're on newer api levels // and don't need to possibly remaps buffers. ui::Dataspace dataspace = ui::Dataspace::UNKNOWN; status_t err = OK; { SFTRACE_NAME("getDataspace"); err = mapper.getDataspace(mBufferInfo.mBuffer->getBuffer()->handle, &dataspace); } if (err != OK || dataspace != mBufferInfo.mDataspace) { { SFTRACE_NAME("setDataspace"); err = mapper.setDataspace(mBufferInfo.mBuffer->getBuffer()->handle, static_cast(mBufferInfo.mDataspace)); } // Some GPU drivers may cache gralloc metadata which means before we composite we need // to upsert RenderEngine's caches. Put in a special workaround to be backwards // compatible with old vendors, with a ticking clock. static const int32_t kVendorVersion = base::GetIntProperty("ro.board.api_level", __ANDROID_API_FUTURE__); if (const auto format = static_cast( mBufferInfo.mBuffer->getPixelFormat()); err == OK && kVendorVersion < __ANDROID_API_U__ && (format == aidl::android::hardware::graphics::common::PixelFormat:: IMPLEMENTATION_DEFINED || format == aidl::android::hardware::graphics::common::PixelFormat::YCBCR_420_888 || format == aidl::android::hardware::graphics::common::PixelFormat::YV12 || format == aidl::android::hardware::graphics::common::PixelFormat::YCBCR_P010)) { mBufferInfo.mBuffer->remapBuffer(); } } } if (lastDataspace != mBufferInfo.mDataspace || mBufferInfo.mTimeSinceDataspaceUpdate == std::chrono::steady_clock::time_point::min()) { mFlinger->mHdrLayerInfoChanged = true; const auto currentTime = std::chrono::steady_clock::now(); if (mBufferInfo.mTimeSinceDataspaceUpdate > std::chrono::steady_clock::time_point::min()) { mFlinger->mLayerEvents .emplace_back(mOwnerUid, getSequence(), lastDataspace, std::chrono::duration_cast( currentTime - mBufferInfo.mTimeSinceDataspaceUpdate)); } mBufferInfo.mTimeSinceDataspaceUpdate = currentTime; } if (mBufferInfo.mDesiredHdrSdrRatio != mDrawingState.desiredHdrSdrRatio) { mBufferInfo.mDesiredHdrSdrRatio = mDrawingState.desiredHdrSdrRatio; mFlinger->mHdrLayerInfoChanged = true; } mBufferInfo.mCrop = computeBufferCrop(mDrawingState); mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse; } Rect Layer::computeBufferCrop(const State& s) { if (s.buffer && !s.bufferCrop.isEmpty()) { Rect bufferCrop; s.buffer->getBounds().intersect(s.bufferCrop, &bufferCrop); return bufferCrop; } else if (s.buffer) { return s.buffer->getBounds(); } else { return s.bufferCrop; } } void Layer::decrementPendingBufferCount() { int32_t pendingBuffers = --mPendingBuffers; tracePendingBufferCount(pendingBuffers); } void Layer::tracePendingBufferCount(int32_t pendingBuffers) { SFTRACE_INT(mBlastTransactionName.c_str(), pendingBuffers); } sp Layer::getCompositionEngineLayerFE( const frontend::LayerHierarchy::TraversalPath& path) { for (auto& [p, layerFE] : mLayerFEs) { if (p == path) { return layerFE; } } auto layerFE = mFlinger->getFactory().createLayerFE(mName, this); mLayerFEs.emplace_back(path, layerFE); return layerFE; } void Layer::onCompositionPresented(const DisplayDevice* display, const std::shared_ptr& glDoneFence, const std::shared_ptr& presentFence, const CompositorTiming& compositorTiming, gui::GameMode gameMode) { // mFrameLatencyNeeded is true when a new frame was latched for the // composition. if (!mBufferInfo.mFrameLatencyNeeded) return; for (const auto& handle : mDrawingState.callbackHandles) { handle->gpuCompositionDoneFence = glDoneFence; handle->compositorTiming = compositorTiming; } // Update mDeprecatedFrameTracker. nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime; mDeprecatedFrameTracker.setDesiredPresentTime(desiredPresentTime); const int32_t layerId = getSequence(); mFlinger->mTimeStats->setDesiredTime(layerId, mCurrentFrameNumber, desiredPresentTime); const auto outputLayer = findOutputLayerForDisplay(display); if (outputLayer && outputLayer->requiresClientComposition()) { nsecs_t clientCompositionTimestamp = outputLayer->getState().clientCompositionTimestamp; mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, clientCompositionTimestamp, FrameTracer::FrameEvent::FALLBACK_COMPOSITION); // Update the SurfaceFrames in the drawing state if (mDrawingState.bufferSurfaceFrameTX) { mDrawingState.bufferSurfaceFrameTX->setGpuComposition(); } for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) { surfaceFrame->setGpuComposition(); } } // The SurfaceFrame's AcquireFence is the same as this. std::shared_ptr frameReadyFence = mBufferInfo.mFenceTime; if (frameReadyFence->isValid()) { mDeprecatedFrameTracker.setFrameReadyFence(std::move(frameReadyFence)); } else { // There was no fence for this frame, so assume that it was ready // to be presented at the desired present time. mDeprecatedFrameTracker.setFrameReadyTime(desiredPresentTime); } if (display) { const auto activeMode = display->refreshRateSelector().getActiveMode(); const Fps refreshRate = activeMode.fps; const std::optional renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); const auto vote = frameRateToSetFrameRateVotePayload(getFrameRateForLayerTree()); if (presentFence->isValid()) { mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, refreshRate, renderRate, vote, gameMode); mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); mDeprecatedFrameTracker.setActualPresentFence(std::shared_ptr(presentFence)); } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId()); displayId && mFlinger->getHwComposer().isConnected(*displayId)) { // The HWC doesn't support present fences, so use the present timestamp instead. const nsecs_t presentTimestamp = mFlinger->getHwComposer().getPresentTimestamp(*displayId); const nsecs_t now = systemTime(CLOCK_MONOTONIC); const nsecs_t vsyncPeriod = mFlinger->getHwComposer() .getDisplayVsyncPeriod(*displayId) .value_opt() .value_or(activeMode.modePtr->getVsyncRate().getPeriodNsecs()); const nsecs_t actualPresentTime = now - ((now - presentTimestamp) % vsyncPeriod); mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, refreshRate, renderRate, vote, gameMode); mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, actualPresentTime, FrameTracer::FrameEvent::PRESENT_FENCE); mDeprecatedFrameTracker.setActualPresentTime(actualPresentTime); } } mFrameStatsHistorySize++; mDeprecatedFrameTracker.advanceFrame(); mBufferInfo.mFrameLatencyNeeded = false; } bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bool bgColorOnly) { SFTRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(), getDrawingState().frameNumber); bool refreshRequired = latchSidebandStream(recomputeVisibleRegions); if (refreshRequired) { return refreshRequired; } // If the head buffer's acquire fence hasn't signaled yet, return and // try again later if (!fenceHasSignaled()) { SFTRACE_NAME("!fenceHasSignaled()"); mFlinger->onLayerUpdate(); return false; } updateTexImage(latchTime, bgColorOnly); // Capture the old state of the layer for comparisons later BufferInfo oldBufferInfo = mBufferInfo; mPreviousFrameNumber = mCurrentFrameNumber; mCurrentFrameNumber = mDrawingState.frameNumber; gatherBufferInfo(); if (mBufferInfo.mBuffer) { // We latched a buffer that will be presented soon. Clear the previously presented layer // stack list. mPreviouslyPresentedLayerStacks.clear(); } if (mDrawingState.buffer == nullptr) { const bool bufferReleased = oldBufferInfo.mBuffer != nullptr; recomputeVisibleRegions = bufferReleased; return bufferReleased; } 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.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) { recomputeVisibleRegions = true; } if (oldBufferInfo.mBuffer != nullptr) { uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); if (bufWidth != oldBufferInfo.mBuffer->getWidth() || bufHeight != oldBufferInfo.mBuffer->getHeight()) { recomputeVisibleRegions = true; } } return true; } bool Layer::getTransformToDisplayInverse() const { return mBufferInfo.mTransformToDisplayInverse; } ui::Dataspace Layer::translateDataspace(ui::Dataspace dataspace) { ui::Dataspace updatedDataspace = dataspace; // translate legacy dataspaces to modern dataspaces switch (dataspace) { // Treat unknown dataspaces as V0_sRGB case ui::Dataspace::UNKNOWN: case ui::Dataspace::SRGB: updatedDataspace = ui::Dataspace::V0_SRGB; break; case ui::Dataspace::SRGB_LINEAR: updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR; break; case ui::Dataspace::JFIF: updatedDataspace = ui::Dataspace::V0_JFIF; break; case ui::Dataspace::BT601_625: updatedDataspace = ui::Dataspace::V0_BT601_625; break; case ui::Dataspace::BT601_525: updatedDataspace = ui::Dataspace::V0_BT601_525; break; case ui::Dataspace::BT709: updatedDataspace = ui::Dataspace::V0_BT709; break; default: break; } return updatedDataspace; } sp Layer::getBuffer() const { return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr; } bool Layer::setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds, TrustedPresentationListener const& listener) { bool hadTrustedPresentationListener = hasTrustedPresentationListener(); mTrustedPresentationListener = listener; mTrustedPresentationThresholds = thresholds; bool haveTrustedPresentationListener = hasTrustedPresentationListener(); if (!hadTrustedPresentationListener && haveTrustedPresentationListener) { mFlinger->mNumTrustedPresentationListeners++; } else if (hadTrustedPresentationListener && !haveTrustedPresentationListener) { mFlinger->mNumTrustedPresentationListeners--; } // Reset trusted presentation states to ensure we start the time again. mEnteredTrustedPresentationStateTime = -1; mLastReportedTrustedPresentationState = false; mLastComputedTrustedPresentationState = false; // If there's a new trusted presentation listener, the code needs to go through the composite // path to ensure it recomutes the current state and invokes the TrustedPresentationListener if // we're already in the requested state. return haveTrustedPresentationListener; } void Layer::setBufferReleaseChannel( const std::shared_ptr& channel) { mBufferReleaseChannel = channel; } void Layer::updateLastLatchTime(nsecs_t latchTime) { mLastLatchTime = latchTime; } void Layer::setIsSmallDirty(frontend::LayerSnapshot* snapshot) { if (!mFlinger->mScheduler->supportSmallDirtyDetection(mOwnerAppId)) { snapshot->isSmallDirty = false; return; } if (mWindowType != WindowInfo::Type::APPLICATION && mWindowType != WindowInfo::Type::BASE_APPLICATION) { snapshot->isSmallDirty = false; return; } Rect bounds = snapshot->surfaceDamage.getBounds(); if (!bounds.isValid()) { snapshot->isSmallDirty = false; return; } // Transform to screen space. bounds = snapshot->localTransform.transform(bounds); // If the damage region is a small dirty, this could give the hint for the layer history that // it could suppress the heuristic rate when calculating. snapshot->isSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId, bounds.getWidth() * bounds.getHeight()); } } // namespace android #if defined(__gl_h_) #error "don't include gl/gl.h in this file" #endif #if defined(__gl2_h_) #error "don't include gl2/gl2.h in this file" #endif // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion"