Loading services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,7 @@ filegroup { "FrameTracer/FrameTracer.cpp", "FrameTracker.cpp", "HdrLayerInfoReporter.cpp", "HwcSlotGenerator.cpp", "WindowInfosListenerInvoker.cpp", "Layer.cpp", "LayerProtoHelper.cpp", Loading services/surfaceflinger/BufferStateLayer.cpp +101 −239 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ #include <FrameTimeline/FrameTimeline.h> #include <compositionengine/CompositionEngine.h> #include <compositionengine/LayerFECompositionState.h> #include <gui/BufferQueue.h> #include <private/gui/SyncFeatures.h> #include <renderengine/Image.h> Loading Loading @@ -71,22 +70,64 @@ namespace android { using PresentState = frametimeline::SurfaceFrame::PresentState; using gui::WindowInfo; void BufferStateLayer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, const sp<GraphicBuffer>& buffer, uint64_t framenumber, const sp<Fence>& releaseFence, uint32_t currentMaxAcquiredBufferCount) { if (!listener) { return; namespace { static constexpr float defaultMaxLuminance = 1000.0; constexpr mat4 inverseOrientation(uint32_t transform) { const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); mat4 tr; if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { tr = tr * rot90; } ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); listener->onReleaseBuffer({buffer->getId(), framenumber}, releaseFence ? releaseFence : Fence::NO_FENCE, currentMaxAcquiredBufferCount); if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { tr = tr * flipH; } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { tr = tr * flipV; } return inverse(tr); } namespace { static constexpr float defaultMaxLuminance = 1000.0; bool assignTransform(ui::Transform* dst, ui::Transform& from) { if (*dst == from) { return false; } *dst = from; return true; } TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) { using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; const auto frameRateCompatibility = [frameRate] { switch (frameRate.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.seamlessness) { case scheduler::Seamlessness::OnlySeamless: return Seamlessness::ShouldBeSeamless; case scheduler::Seamlessness::SeamedAndSeamless: return Seamlessness::NotRequired; default: return Seamlessness::Undefined; } }(); return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(), .frameRateCompatibility = frameRateCompatibility, .seamlessness = seamlessness}; } } // namespace BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) Loading @@ -97,7 +138,6 @@ BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) ALOGV("Creating Layer %s", getDebugName()); mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied); mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp; mDrawingState.dataspace = ui::Dataspace::V0_SRGB; Loading Loading @@ -127,6 +167,20 @@ BufferStateLayer::~BufferStateLayer() { mFlinger->mFrameTracer->onDestroy(layerId); } void BufferStateLayer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, const sp<GraphicBuffer>& buffer, uint64_t framenumber, const sp<Fence>& releaseFence, uint32_t currentMaxAcquiredBufferCount) { if (!listener) { return; } ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); listener->onReleaseBuffer({buffer->getId(), framenumber}, releaseFence ? releaseFence : Fence::NO_FENCE, currentMaxAcquiredBufferCount); } // ----------------------------------------------------------------------- // Interface implementation for Layer // ----------------------------------------------------------------------- Loading Loading @@ -239,14 +293,6 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { mDrawingState.callbackHandles = {}; } void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence, const CompositorTiming& compositorTiming) { for (const auto& handle : mDrawingState.callbackHandles) { handle->gpuCompositionDoneFence = glDoneFence; handle->compositorTiming = compositorTiming; } } bool BufferStateLayer::willPresentCurrentTransaction() const { // Returns true if the most recent Transaction applied to CurrentState will be presented. return (getSidebandStreamChanged() || getAutoRefresh() || Loading Loading @@ -307,14 +353,6 @@ bool BufferStateLayer::setDestinationFrame(const Rect& destinationFrame) { return true; } static bool assignTransform(ui::Transform* dst, ui::Transform& from) { if (*dst == from) { return false; } *dst = from; return true; } // Translate destination frame into scale and position. If a destination frame is not set, use the // provided scale and position bool BufferStateLayer::updateGeometry() { Loading Loading @@ -641,14 +679,6 @@ bool BufferStateLayer::fenceHasSignaled() const { return fenceSignaled; } bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const { if (!hasFrameUpdate() || isRemovedFromCurrentState()) { return true; } return mDrawingState.isAutoTimestamp || mDrawingState.desiredPresentTime <= expectedPresentTime; } bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) { for (const auto& handle : mDrawingState.callbackHandles) { handle->refreshStartTime = refreshStartTime; Loading Loading @@ -685,8 +715,7 @@ bool BufferStateLayer::hasFrameUpdate() const { return (mDrawingStateModified || mDrawingState.modified) && (c.buffer != nullptr || c.bgColorLayer != nullptr); } status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime, nsecs_t /*expectedPresentTime*/) { void BufferStateLayer::updateTexImage(nsecs_t latchTime) { const State& s(getDrawingState()); if (!s.buffer) { Loading @@ -695,7 +724,7 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse handle->latchTime = latchTime; } } return NO_ERROR; return; } for (auto& handle : mDrawingState.callbackHandles) { Loading Loading @@ -734,135 +763,36 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse mDrawingState.callbackHandles = remainingHandles; mDrawingStateModified = false; return NO_ERROR; } status_t BufferStateLayer::updateActiveBuffer() { const State& s(getDrawingState()); if (s.buffer == nullptr) { return BAD_VALUE; } if (!mBufferInfo.mBuffer || !s.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) { void BufferStateLayer::gatherBufferInfo() { if (!mBufferInfo.mBuffer || !mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) { decrementPendingBufferCount(); } mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber}; mBufferInfo.mBuffer = s.buffer; mBufferInfo.mFence = s.acquireFence; mBufferInfo.mFrameNumber = s.frameNumber; return NO_ERROR; } status_t BufferStateLayer::updateFrameNumber() { // TODO(marissaw): support frame history events mPreviousFrameNumber = mCurrentFrameNumber; mCurrentFrameNumber = mDrawingState.frameNumber; return NO_ERROR; } void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) { std::lock_guard lock(mMutex); if (!clientCacheId.isValid()) { ALOGE("invalid process, failed to erase buffer"); return; } eraseBufferLocked(clientCacheId); } int BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) { std::lock_guard<std::mutex> lock(mMutex); auto itr = mCachedBuffers.find(clientCacheId); if (itr == mCachedBuffers.end()) { return addCachedBuffer(clientCacheId); } auto& [hwcCacheSlot, counter] = itr->second; counter = mCounter++; return hwcCacheSlot; } int BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex) { if (!clientCacheId.isValid()) { ALOGE("invalid process, returning invalid slot"); return BufferQueue::INVALID_BUFFER_SLOT; } ClientCache::getInstance().registerErasedRecipient(clientCacheId, wp<ErasedRecipient>(this)); int hwcCacheSlot = getFreeHwcCacheSlot(); mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++}; return hwcCacheSlot; } int BufferStateLayer::HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) { if (mFreeHwcCacheSlots.empty()) { evictLeastRecentlyUsed(); } int hwcCacheSlot = mFreeHwcCacheSlots.top(); mFreeHwcCacheSlots.pop(); return hwcCacheSlot; } void BufferStateLayer::HwcSlotGenerator::evictLeastRecentlyUsed() REQUIRES(mMutex) { uint64_t minCounter = UINT_MAX; client_cache_t minClientCacheId = {}; for (const auto& [clientCacheId, slotCounter] : mCachedBuffers) { const auto& [hwcCacheSlot, counter] = slotCounter; if (counter < minCounter) { minCounter = counter; minClientCacheId = clientCacheId; } } eraseBufferLocked(minClientCacheId); ClientCache::getInstance().unregisterErasedRecipient(minClientCacheId, this); } void BufferStateLayer::HwcSlotGenerator::eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex) { auto itr = mCachedBuffers.find(clientCacheId); if (itr == mCachedBuffers.end()) { return; } auto& [hwcCacheSlot, counter] = itr->second; // TODO send to hwc cache and resources mFreeHwcCacheSlots.push(hwcCacheSlot); mCachedBuffers.erase(clientCacheId); } void BufferStateLayer::gatherBufferInfo() { mBufferInfo.mBuffer = mDrawingState.buffer; mBufferInfo.mFence = mDrawingState.acquireFence; mBufferInfo.mFrameNumber = mDrawingState.frameNumber; mBufferInfo.mPixelFormat = !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat(); mBufferInfo.mFrameLatencyNeeded = true; const State& s(getDrawingState()); mBufferInfo.mDesiredPresentTime = s.desiredPresentTime; mBufferInfo.mFenceTime = std::make_shared<FenceTime>(s.acquireFence); mBufferInfo.mFence = s.acquireFence; mBufferInfo.mTransform = s.bufferTransform; mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime; mBufferInfo.mFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence); mBufferInfo.mFence = mDrawingState.acquireFence; mBufferInfo.mTransform = mDrawingState.bufferTransform; auto lastDataspace = mBufferInfo.mDataspace; mBufferInfo.mDataspace = translateDataspace(s.dataspace); mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace); if (lastDataspace != mBufferInfo.mDataspace) { mFlinger->mSomeDataspaceChanged = true; } mBufferInfo.mCrop = computeBufferCrop(s); mBufferInfo.mCrop = computeBufferCrop(mDrawingState); mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion; mBufferInfo.mHdrMetadata = s.hdrMetadata; mBufferInfo.mApi = s.api; mBufferInfo.mTransformToDisplayInverse = s.transformToDisplayInverse; mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId); } uint32_t BufferStateLayer::getEffectiveScalingMode() const { return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; mBufferInfo.mSurfaceDamage = mDrawingState.surfaceDamageRegion; mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata; mBufferInfo.mApi = mDrawingState.api; mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse; mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(mDrawingState.clientCacheId); } Rect BufferStateLayer::computeBufferCrop(const State& s) { Loading Loading @@ -1178,32 +1108,6 @@ bool BufferStateLayer::isVisible() const { (mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr); } bool BufferStateLayer::isFixedSize() const { return true; } bool BufferStateLayer::usesSourceCrop() const { return true; } static constexpr mat4 inverseOrientation(uint32_t transform) { const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); mat4 tr; if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { tr = tr * rot90; } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { tr = tr * flipH; } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { tr = tr * flipV; } return inverse(tr); } std::optional<compositionengine::LayerFE::LayerSettings> BufferStateLayer::prepareClientComposition( compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { ATRACE_CALL(); Loading Loading @@ -1373,38 +1277,6 @@ void BufferStateLayer::preparePerFrameCompositionState() { compositionState->sidebandStreamHasFrame = false; } namespace { TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) { using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; const auto frameRateCompatibility = [frameRate] { switch (frameRate.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.seamlessness) { case scheduler::Seamlessness::OnlySeamless: return Seamlessness::ShouldBeSeamless; case scheduler::Seamlessness::SeamedAndSeamless: return Seamlessness::NotRequired; default: return Seamlessness::Undefined; } }(); return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(), .frameRateCompatibility = frameRateCompatibility, .seamlessness = seamlessness}; } } // namespace void BufferStateLayer::onPostComposition(const DisplayDevice* display, const std::shared_ptr<FenceTime>& glDoneFence, const std::shared_ptr<FenceTime>& presentFence, Loading @@ -1413,8 +1285,10 @@ void BufferStateLayer::onPostComposition(const DisplayDevice* display, // composition. if (!mBufferInfo.mFrameLatencyNeeded) return; // Update mFrameEventHistory. finalizeFrameEventHistory(glDoneFence, compositorTiming); for (const auto& handle : mDrawingState.callbackHandles) { handle->gpuCompositionDoneFence = glDoneFence; handle->compositorTiming = compositorTiming; } // Update mFrameTracker. nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime; Loading Loading @@ -1480,8 +1354,7 @@ void BufferStateLayer::onPostComposition(const DisplayDevice* display, mBufferInfo.mFrameLatencyNeeded = false; } bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) { bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) { ATRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(), getDrawingState().frameNumber); Loading @@ -1499,27 +1372,16 @@ bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchT 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(); if (err != NO_ERROR) { updateTexImage(latchTime); if (mDrawingState.buffer == nullptr) { return false; } // Capture the old state of the layer for comparisons later BufferInfo oldBufferInfo = mBufferInfo; const bool oldOpacity = isOpaque(mDrawingState); mPreviousFrameNumber = mCurrentFrameNumber; mCurrentFrameNumber = mDrawingState.frameNumber; gatherBufferInfo(); if (oldBufferInfo.mBuffer == nullptr) { Loading @@ -1544,7 +1406,7 @@ bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchT } } if (oldOpacity != isOpaque(s)) { if (oldOpacity != isOpaque(mDrawingState)) { recomputeVisibleRegions = true; } Loading Loading @@ -1628,7 +1490,7 @@ bool BufferStateLayer::needsFilteringForScreenshots( void BufferStateLayer::latchAndReleaseBuffer() { if (hasReadyFrame()) { bool ignored = false; latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */); latchBuffer(ignored, systemTime()); } releasePendingBuffer(systemTime()); } Loading services/surfaceflinger/BufferStateLayer.h +4 −65 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include "DisplayHardware/HWComposer.h" #include "FrameTimeline.h" #include "FrameTracker.h" #include "HwcSlotGenerator.h" #include "Layer.h" #include "LayerVector.h" #include "SurfaceFlinger.h" Loading Loading @@ -74,10 +75,7 @@ public: // GRALLOC_USAGE_PROTECTED sense. bool isProtected() const override; // isFixedSize - true if content has a fixed size bool isFixedSize() const override; bool usesSourceCrop() const override; bool usesSourceCrop() const override { return true; } bool isHdrY410() const override; Loading @@ -89,13 +87,9 @@ public: // the visible regions need to be recomputed (this is a fairly heavy // operation, so this should be set only if needed). Typically this is used // to figure out if the content or size of a surface has changed. bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) override; bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override; bool hasReadyFrame() const override; // Returns the current scaling mode uint32_t getEffectiveScalingMode() const override; // Calls latchBuffer if the buffer has a frame queued and then releases the buffer. // This is used if the buffer is just latched and releases to free up the buffer // and will not be shown on screen. Loading @@ -122,14 +116,6 @@ public: void releasePendingBuffer(nsecs_t dequeueReadyTime) override; void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence, const CompositorTiming& compositorTiming) override; // Returns true if the next buffer should be presented at the expected present time, // overridden by BufferStateLayer and BufferQueueLayer for implementation // specific logic bool isBufferDue(nsecs_t /*expectedPresentTime*/) const { return true; } Region getActiveTransparentRegion(const Layer::State& s) const override { return s.transparentRegionHint; } Loading Loading @@ -166,7 +152,6 @@ public: bool updateGeometry() override; bool fenceHasSignaled() const; bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const; bool onPreComposition(nsecs_t) override; // See mPendingBufferTransactions Loading @@ -174,9 +159,6 @@ public: std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() override { return mBlastTransactionName; } // Returns true if the next buffer should be presented at the expected present time bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const override { return true; } protected: void gatherBufferInfo(); void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame); Loading Loading @@ -268,11 +250,7 @@ private: bool hasFrameUpdate() const; status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime); status_t updateActiveBuffer(); status_t updateFrameNumber(); void updateTexImage(nsecs_t latchTime); sp<Layer> createClone() override; Loading Loading @@ -323,45 +301,6 @@ private: // not specify a destination frame. ui::Transform mRequestedTransform; // TODO(marissaw): support sticky transform for LEGACY camera mode class HwcSlotGenerator : public ClientCache::ErasedRecipient { public: HwcSlotGenerator() { for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { mFreeHwcCacheSlots.push(i); } } void bufferErased(const client_cache_t& clientCacheId); int getHwcCacheSlot(const client_cache_t& clientCacheId); private: friend class SlotGenerationTest; int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex); int getFreeHwcCacheSlot() REQUIRES(mMutex); void evictLeastRecentlyUsed() REQUIRES(mMutex); void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex); struct CachedBufferHash { std::size_t operator()(const client_cache_t& clientCacheId) const { return std::hash<uint64_t>{}(clientCacheId.id); } }; std::mutex mMutex; std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>, CachedBufferHash> mCachedBuffers GUARDED_BY(mMutex); std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex); // The cache increments this counter value when a slot is updated or used. // Used to track the least recently-used buffer uint64_t mCounter = 0; }; sp<HwcSlotGenerator> mHwcSlotGenerator; }; Loading services/surfaceflinger/HwcSlotGenerator.cpp 0 → 100644 +104 −0 File added.Preview size limit exceeded, changes collapsed. Show changes services/surfaceflinger/HwcSlotGenerator.h 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 <functional> #include <mutex> #include <stack> #include <unordered_map> #include "ClientCache.h" namespace android { class HwcSlotGenerator : public ClientCache::ErasedRecipient { public: HwcSlotGenerator(); void bufferErased(const client_cache_t& clientCacheId); int getHwcCacheSlot(const client_cache_t& clientCacheId); private: friend class SlotGenerationTest; int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex); int getFreeHwcCacheSlot() REQUIRES(mMutex); void evictLeastRecentlyUsed() REQUIRES(mMutex); void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex); struct CachedBufferHash { std::size_t operator()(const client_cache_t& clientCacheId) const { return std::hash<uint64_t>{}(clientCacheId.id); } }; std::mutex mMutex; std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>, CachedBufferHash> mCachedBuffers GUARDED_BY(mMutex); std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex); // The cache increments this counter value when a slot is updated or used. // Used to track the least recently-used buffer uint64_t mCounter = 0; }; } // namespace android Loading
services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,7 @@ filegroup { "FrameTracer/FrameTracer.cpp", "FrameTracker.cpp", "HdrLayerInfoReporter.cpp", "HwcSlotGenerator.cpp", "WindowInfosListenerInvoker.cpp", "Layer.cpp", "LayerProtoHelper.cpp", Loading
services/surfaceflinger/BufferStateLayer.cpp +101 −239 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ #include <FrameTimeline/FrameTimeline.h> #include <compositionengine/CompositionEngine.h> #include <compositionengine/LayerFECompositionState.h> #include <gui/BufferQueue.h> #include <private/gui/SyncFeatures.h> #include <renderengine/Image.h> Loading Loading @@ -71,22 +70,64 @@ namespace android { using PresentState = frametimeline::SurfaceFrame::PresentState; using gui::WindowInfo; void BufferStateLayer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, const sp<GraphicBuffer>& buffer, uint64_t framenumber, const sp<Fence>& releaseFence, uint32_t currentMaxAcquiredBufferCount) { if (!listener) { return; namespace { static constexpr float defaultMaxLuminance = 1000.0; constexpr mat4 inverseOrientation(uint32_t transform) { const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); mat4 tr; if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { tr = tr * rot90; } ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); listener->onReleaseBuffer({buffer->getId(), framenumber}, releaseFence ? releaseFence : Fence::NO_FENCE, currentMaxAcquiredBufferCount); if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { tr = tr * flipH; } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { tr = tr * flipV; } return inverse(tr); } namespace { static constexpr float defaultMaxLuminance = 1000.0; bool assignTransform(ui::Transform* dst, ui::Transform& from) { if (*dst == from) { return false; } *dst = from; return true; } TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) { using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; const auto frameRateCompatibility = [frameRate] { switch (frameRate.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.seamlessness) { case scheduler::Seamlessness::OnlySeamless: return Seamlessness::ShouldBeSeamless; case scheduler::Seamlessness::SeamedAndSeamless: return Seamlessness::NotRequired; default: return Seamlessness::Undefined; } }(); return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(), .frameRateCompatibility = frameRateCompatibility, .seamlessness = seamlessness}; } } // namespace BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) Loading @@ -97,7 +138,6 @@ BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) ALOGV("Creating Layer %s", getDebugName()); mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied); mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp; mDrawingState.dataspace = ui::Dataspace::V0_SRGB; Loading Loading @@ -127,6 +167,20 @@ BufferStateLayer::~BufferStateLayer() { mFlinger->mFrameTracer->onDestroy(layerId); } void BufferStateLayer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, const sp<GraphicBuffer>& buffer, uint64_t framenumber, const sp<Fence>& releaseFence, uint32_t currentMaxAcquiredBufferCount) { if (!listener) { return; } ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); listener->onReleaseBuffer({buffer->getId(), framenumber}, releaseFence ? releaseFence : Fence::NO_FENCE, currentMaxAcquiredBufferCount); } // ----------------------------------------------------------------------- // Interface implementation for Layer // ----------------------------------------------------------------------- Loading Loading @@ -239,14 +293,6 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { mDrawingState.callbackHandles = {}; } void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence, const CompositorTiming& compositorTiming) { for (const auto& handle : mDrawingState.callbackHandles) { handle->gpuCompositionDoneFence = glDoneFence; handle->compositorTiming = compositorTiming; } } bool BufferStateLayer::willPresentCurrentTransaction() const { // Returns true if the most recent Transaction applied to CurrentState will be presented. return (getSidebandStreamChanged() || getAutoRefresh() || Loading Loading @@ -307,14 +353,6 @@ bool BufferStateLayer::setDestinationFrame(const Rect& destinationFrame) { return true; } static bool assignTransform(ui::Transform* dst, ui::Transform& from) { if (*dst == from) { return false; } *dst = from; return true; } // Translate destination frame into scale and position. If a destination frame is not set, use the // provided scale and position bool BufferStateLayer::updateGeometry() { Loading Loading @@ -641,14 +679,6 @@ bool BufferStateLayer::fenceHasSignaled() const { return fenceSignaled; } bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const { if (!hasFrameUpdate() || isRemovedFromCurrentState()) { return true; } return mDrawingState.isAutoTimestamp || mDrawingState.desiredPresentTime <= expectedPresentTime; } bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) { for (const auto& handle : mDrawingState.callbackHandles) { handle->refreshStartTime = refreshStartTime; Loading Loading @@ -685,8 +715,7 @@ bool BufferStateLayer::hasFrameUpdate() const { return (mDrawingStateModified || mDrawingState.modified) && (c.buffer != nullptr || c.bgColorLayer != nullptr); } status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime, nsecs_t /*expectedPresentTime*/) { void BufferStateLayer::updateTexImage(nsecs_t latchTime) { const State& s(getDrawingState()); if (!s.buffer) { Loading @@ -695,7 +724,7 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse handle->latchTime = latchTime; } } return NO_ERROR; return; } for (auto& handle : mDrawingState.callbackHandles) { Loading Loading @@ -734,135 +763,36 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse mDrawingState.callbackHandles = remainingHandles; mDrawingStateModified = false; return NO_ERROR; } status_t BufferStateLayer::updateActiveBuffer() { const State& s(getDrawingState()); if (s.buffer == nullptr) { return BAD_VALUE; } if (!mBufferInfo.mBuffer || !s.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) { void BufferStateLayer::gatherBufferInfo() { if (!mBufferInfo.mBuffer || !mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) { decrementPendingBufferCount(); } mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber}; mBufferInfo.mBuffer = s.buffer; mBufferInfo.mFence = s.acquireFence; mBufferInfo.mFrameNumber = s.frameNumber; return NO_ERROR; } status_t BufferStateLayer::updateFrameNumber() { // TODO(marissaw): support frame history events mPreviousFrameNumber = mCurrentFrameNumber; mCurrentFrameNumber = mDrawingState.frameNumber; return NO_ERROR; } void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) { std::lock_guard lock(mMutex); if (!clientCacheId.isValid()) { ALOGE("invalid process, failed to erase buffer"); return; } eraseBufferLocked(clientCacheId); } int BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) { std::lock_guard<std::mutex> lock(mMutex); auto itr = mCachedBuffers.find(clientCacheId); if (itr == mCachedBuffers.end()) { return addCachedBuffer(clientCacheId); } auto& [hwcCacheSlot, counter] = itr->second; counter = mCounter++; return hwcCacheSlot; } int BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex) { if (!clientCacheId.isValid()) { ALOGE("invalid process, returning invalid slot"); return BufferQueue::INVALID_BUFFER_SLOT; } ClientCache::getInstance().registerErasedRecipient(clientCacheId, wp<ErasedRecipient>(this)); int hwcCacheSlot = getFreeHwcCacheSlot(); mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++}; return hwcCacheSlot; } int BufferStateLayer::HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) { if (mFreeHwcCacheSlots.empty()) { evictLeastRecentlyUsed(); } int hwcCacheSlot = mFreeHwcCacheSlots.top(); mFreeHwcCacheSlots.pop(); return hwcCacheSlot; } void BufferStateLayer::HwcSlotGenerator::evictLeastRecentlyUsed() REQUIRES(mMutex) { uint64_t minCounter = UINT_MAX; client_cache_t minClientCacheId = {}; for (const auto& [clientCacheId, slotCounter] : mCachedBuffers) { const auto& [hwcCacheSlot, counter] = slotCounter; if (counter < minCounter) { minCounter = counter; minClientCacheId = clientCacheId; } } eraseBufferLocked(minClientCacheId); ClientCache::getInstance().unregisterErasedRecipient(minClientCacheId, this); } void BufferStateLayer::HwcSlotGenerator::eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex) { auto itr = mCachedBuffers.find(clientCacheId); if (itr == mCachedBuffers.end()) { return; } auto& [hwcCacheSlot, counter] = itr->second; // TODO send to hwc cache and resources mFreeHwcCacheSlots.push(hwcCacheSlot); mCachedBuffers.erase(clientCacheId); } void BufferStateLayer::gatherBufferInfo() { mBufferInfo.mBuffer = mDrawingState.buffer; mBufferInfo.mFence = mDrawingState.acquireFence; mBufferInfo.mFrameNumber = mDrawingState.frameNumber; mBufferInfo.mPixelFormat = !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat(); mBufferInfo.mFrameLatencyNeeded = true; const State& s(getDrawingState()); mBufferInfo.mDesiredPresentTime = s.desiredPresentTime; mBufferInfo.mFenceTime = std::make_shared<FenceTime>(s.acquireFence); mBufferInfo.mFence = s.acquireFence; mBufferInfo.mTransform = s.bufferTransform; mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime; mBufferInfo.mFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence); mBufferInfo.mFence = mDrawingState.acquireFence; mBufferInfo.mTransform = mDrawingState.bufferTransform; auto lastDataspace = mBufferInfo.mDataspace; mBufferInfo.mDataspace = translateDataspace(s.dataspace); mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace); if (lastDataspace != mBufferInfo.mDataspace) { mFlinger->mSomeDataspaceChanged = true; } mBufferInfo.mCrop = computeBufferCrop(s); mBufferInfo.mCrop = computeBufferCrop(mDrawingState); mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion; mBufferInfo.mHdrMetadata = s.hdrMetadata; mBufferInfo.mApi = s.api; mBufferInfo.mTransformToDisplayInverse = s.transformToDisplayInverse; mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId); } uint32_t BufferStateLayer::getEffectiveScalingMode() const { return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; mBufferInfo.mSurfaceDamage = mDrawingState.surfaceDamageRegion; mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata; mBufferInfo.mApi = mDrawingState.api; mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse; mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(mDrawingState.clientCacheId); } Rect BufferStateLayer::computeBufferCrop(const State& s) { Loading Loading @@ -1178,32 +1108,6 @@ bool BufferStateLayer::isVisible() const { (mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr); } bool BufferStateLayer::isFixedSize() const { return true; } bool BufferStateLayer::usesSourceCrop() const { return true; } static constexpr mat4 inverseOrientation(uint32_t transform) { const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); mat4 tr; if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { tr = tr * rot90; } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { tr = tr * flipH; } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { tr = tr * flipV; } return inverse(tr); } std::optional<compositionengine::LayerFE::LayerSettings> BufferStateLayer::prepareClientComposition( compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { ATRACE_CALL(); Loading Loading @@ -1373,38 +1277,6 @@ void BufferStateLayer::preparePerFrameCompositionState() { compositionState->sidebandStreamHasFrame = false; } namespace { TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) { using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; const auto frameRateCompatibility = [frameRate] { switch (frameRate.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.seamlessness) { case scheduler::Seamlessness::OnlySeamless: return Seamlessness::ShouldBeSeamless; case scheduler::Seamlessness::SeamedAndSeamless: return Seamlessness::NotRequired; default: return Seamlessness::Undefined; } }(); return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(), .frameRateCompatibility = frameRateCompatibility, .seamlessness = seamlessness}; } } // namespace void BufferStateLayer::onPostComposition(const DisplayDevice* display, const std::shared_ptr<FenceTime>& glDoneFence, const std::shared_ptr<FenceTime>& presentFence, Loading @@ -1413,8 +1285,10 @@ void BufferStateLayer::onPostComposition(const DisplayDevice* display, // composition. if (!mBufferInfo.mFrameLatencyNeeded) return; // Update mFrameEventHistory. finalizeFrameEventHistory(glDoneFence, compositorTiming); for (const auto& handle : mDrawingState.callbackHandles) { handle->gpuCompositionDoneFence = glDoneFence; handle->compositorTiming = compositorTiming; } // Update mFrameTracker. nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime; Loading Loading @@ -1480,8 +1354,7 @@ void BufferStateLayer::onPostComposition(const DisplayDevice* display, mBufferInfo.mFrameLatencyNeeded = false; } bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) { bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) { ATRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(), getDrawingState().frameNumber); Loading @@ -1499,27 +1372,16 @@ bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchT 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(); if (err != NO_ERROR) { updateTexImage(latchTime); if (mDrawingState.buffer == nullptr) { return false; } // Capture the old state of the layer for comparisons later BufferInfo oldBufferInfo = mBufferInfo; const bool oldOpacity = isOpaque(mDrawingState); mPreviousFrameNumber = mCurrentFrameNumber; mCurrentFrameNumber = mDrawingState.frameNumber; gatherBufferInfo(); if (oldBufferInfo.mBuffer == nullptr) { Loading @@ -1544,7 +1406,7 @@ bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchT } } if (oldOpacity != isOpaque(s)) { if (oldOpacity != isOpaque(mDrawingState)) { recomputeVisibleRegions = true; } Loading Loading @@ -1628,7 +1490,7 @@ bool BufferStateLayer::needsFilteringForScreenshots( void BufferStateLayer::latchAndReleaseBuffer() { if (hasReadyFrame()) { bool ignored = false; latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */); latchBuffer(ignored, systemTime()); } releasePendingBuffer(systemTime()); } Loading
services/surfaceflinger/BufferStateLayer.h +4 −65 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include "DisplayHardware/HWComposer.h" #include "FrameTimeline.h" #include "FrameTracker.h" #include "HwcSlotGenerator.h" #include "Layer.h" #include "LayerVector.h" #include "SurfaceFlinger.h" Loading Loading @@ -74,10 +75,7 @@ public: // GRALLOC_USAGE_PROTECTED sense. bool isProtected() const override; // isFixedSize - true if content has a fixed size bool isFixedSize() const override; bool usesSourceCrop() const override; bool usesSourceCrop() const override { return true; } bool isHdrY410() const override; Loading @@ -89,13 +87,9 @@ public: // the visible regions need to be recomputed (this is a fairly heavy // operation, so this should be set only if needed). Typically this is used // to figure out if the content or size of a surface has changed. bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) override; bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override; bool hasReadyFrame() const override; // Returns the current scaling mode uint32_t getEffectiveScalingMode() const override; // Calls latchBuffer if the buffer has a frame queued and then releases the buffer. // This is used if the buffer is just latched and releases to free up the buffer // and will not be shown on screen. Loading @@ -122,14 +116,6 @@ public: void releasePendingBuffer(nsecs_t dequeueReadyTime) override; void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence, const CompositorTiming& compositorTiming) override; // Returns true if the next buffer should be presented at the expected present time, // overridden by BufferStateLayer and BufferQueueLayer for implementation // specific logic bool isBufferDue(nsecs_t /*expectedPresentTime*/) const { return true; } Region getActiveTransparentRegion(const Layer::State& s) const override { return s.transparentRegionHint; } Loading Loading @@ -166,7 +152,6 @@ public: bool updateGeometry() override; bool fenceHasSignaled() const; bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const; bool onPreComposition(nsecs_t) override; // See mPendingBufferTransactions Loading @@ -174,9 +159,6 @@ public: std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() override { return mBlastTransactionName; } // Returns true if the next buffer should be presented at the expected present time bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const override { return true; } protected: void gatherBufferInfo(); void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame); Loading Loading @@ -268,11 +250,7 @@ private: bool hasFrameUpdate() const; status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime); status_t updateActiveBuffer(); status_t updateFrameNumber(); void updateTexImage(nsecs_t latchTime); sp<Layer> createClone() override; Loading Loading @@ -323,45 +301,6 @@ private: // not specify a destination frame. ui::Transform mRequestedTransform; // TODO(marissaw): support sticky transform for LEGACY camera mode class HwcSlotGenerator : public ClientCache::ErasedRecipient { public: HwcSlotGenerator() { for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { mFreeHwcCacheSlots.push(i); } } void bufferErased(const client_cache_t& clientCacheId); int getHwcCacheSlot(const client_cache_t& clientCacheId); private: friend class SlotGenerationTest; int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex); int getFreeHwcCacheSlot() REQUIRES(mMutex); void evictLeastRecentlyUsed() REQUIRES(mMutex); void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex); struct CachedBufferHash { std::size_t operator()(const client_cache_t& clientCacheId) const { return std::hash<uint64_t>{}(clientCacheId.id); } }; std::mutex mMutex; std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>, CachedBufferHash> mCachedBuffers GUARDED_BY(mMutex); std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex); // The cache increments this counter value when a slot is updated or used. // Used to track the least recently-used buffer uint64_t mCounter = 0; }; sp<HwcSlotGenerator> mHwcSlotGenerator; }; Loading
services/surfaceflinger/HwcSlotGenerator.cpp 0 → 100644 +104 −0 File added.Preview size limit exceeded, changes collapsed. Show changes
services/surfaceflinger/HwcSlotGenerator.h 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 <functional> #include <mutex> #include <stack> #include <unordered_map> #include "ClientCache.h" namespace android { class HwcSlotGenerator : public ClientCache::ErasedRecipient { public: HwcSlotGenerator(); void bufferErased(const client_cache_t& clientCacheId); int getHwcCacheSlot(const client_cache_t& clientCacheId); private: friend class SlotGenerationTest; int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex); int getFreeHwcCacheSlot() REQUIRES(mMutex); void evictLeastRecentlyUsed() REQUIRES(mMutex); void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex); struct CachedBufferHash { std::size_t operator()(const client_cache_t& clientCacheId) const { return std::hash<uint64_t>{}(clientCacheId.id); } }; std::mutex mMutex; std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>, CachedBufferHash> mCachedBuffers GUARDED_BY(mMutex); std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex); // The cache increments this counter value when a slot is updated or used. // Used to track the least recently-used buffer uint64_t mCounter = 0; }; } // namespace android