summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/BufferStateLayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/BufferStateLayer.cpp')
-rw-r--r--services/surfaceflinger/BufferStateLayer.cpp765
1 files changed, 265 insertions, 500 deletions
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 8bc51dfa5d..790f2ece77 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -17,7 +17,6 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wextra"
//#define LOG_NDEBUG 0
#undef LOG_TAG
@@ -28,37 +27,29 @@
#include <limits>
-#include <FrameTimeline/FrameTimeline.h>
#include <compositionengine/LayerFECompositionState.h>
#include <gui/BufferQueue.h>
#include <private/gui/SyncFeatures.h>
#include <renderengine/Image.h>
-#include "TunnelModeEnabledReporter.h"
#include "EffectLayer.h"
-#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
namespace android {
-using PresentState = frametimeline::SurfaceFrame::PresentState;
-namespace {
-void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
- const sp<GraphicBuffer>& buffer, uint64_t framenumber,
- const sp<Fence>& releaseFence, uint32_t transformHint,
- uint32_t currentMaxAcquiredBufferCount) {
- if (!listener) {
- return;
- }
- listener->onReleaseBuffer({buffer->getId(), framenumber},
- releaseFence ? releaseFence : Fence::NO_FENCE, transformHint,
- currentMaxAcquiredBufferCount);
-}
-} // namespace
+// clang-format off
+const std::array<float, 16> BufferStateLayer::IDENTITY_MATRIX{
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+};
+// clang-format on
BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args)
: BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) {
- mDrawingState.dataspace = ui::Dataspace::V0_SRGB;
+ mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+ mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
}
BufferStateLayer::~BufferStateLayer() {
@@ -67,79 +58,18 @@ BufferStateLayer::~BufferStateLayer() {
// original layer and the clone should be removed at the same time so there shouldn't be any
// issue with the clone layer trying to use the texture.
if (mBufferInfo.mBuffer != nullptr && !isClone()) {
- callReleaseBufferCallback(mDrawingState.releaseBufferListener,
- mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber,
- mBufferInfo.mFence, mTransformHint,
- mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
- mOwnerUid));
+ // Ensure that mBuffer is uncached from RenderEngine here, as
+ // RenderEngine may have been using the buffer as an external texture
+ // after the client uncached the buffer.
+ auto& engine(mFlinger->getRenderEngine());
+ engine.unbindExternalTextureBuffer(mBufferInfo.mBuffer->getId());
}
}
-status_t BufferStateLayer::addReleaseFence(const sp<CallbackHandle>& ch,
- const sp<Fence>& fence) {
- if (ch == nullptr) {
- return OK;
- }
- ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
- if (!ch->previousReleaseFence.get()) {
- ch->previousReleaseFence = fence;
- return OK;
- }
-
- // Below logic is lifted from ConsumerBase.cpp:
- // Check status of fences first because merging is expensive.
- // Merging an invalid fence with any other fence results in an
- // invalid fence.
- auto currentStatus = ch->previousReleaseFence->getStatus();
- if (currentStatus == Fence::Status::Invalid) {
- ALOGE("Existing fence has invalid state, layer: %s", mName.c_str());
- return BAD_VALUE;
- }
-
- auto incomingStatus = fence->getStatus();
- if (incomingStatus == Fence::Status::Invalid) {
- ALOGE("New fence has invalid state, layer: %s", mName.c_str());
- ch->previousReleaseFence = fence;
- return BAD_VALUE;
- }
-
- // If both fences are signaled or both are unsignaled, we need to merge
- // them to get an accurate timestamp.
- if (currentStatus == incomingStatus) {
- char fenceName[32] = {};
- snprintf(fenceName, 32, "%.28s", mName.c_str());
- sp<Fence> mergedFence = Fence::merge(
- fenceName, ch->previousReleaseFence, fence);
- if (!mergedFence.get()) {
- ALOGE("failed to merge release fences, layer: %s", mName.c_str());
- // synchronization is broken, the best we can do is hope fences
- // signal in order so the new fence will act like a union
- ch->previousReleaseFence = fence;
- return BAD_VALUE;
- }
- ch->previousReleaseFence = mergedFence;
- } else if (incomingStatus == Fence::Status::Unsignaled) {
- // If one fence has signaled and the other hasn't, the unsignaled
- // fence will approximately correspond with the correct timestamp.
- // There's a small race if both fences signal at about the same time
- // and their statuses are retrieved with unfortunate timing. However,
- // by this point, they will have both signaled and only the timestamp
- // will be slightly off; any dependencies after this point will
- // already have been met.
- ch->previousReleaseFence = fence;
- }
- // else if (currentStatus == Fence::Status::Unsignaled) is a no-op.
-
- return OK;
-}
-
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
- if (!releaseFence->isValid()) {
- return;
- }
// 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
@@ -156,17 +86,12 @@ void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
// 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<CallbackHandle> ch;
for (auto& handle : mDrawingState.callbackHandles) {
if (handle->releasePreviousBuffer) {
- ch = handle;
+ handle->previousReleaseFence = releaseFence;
break;
}
}
- auto status = addReleaseFence(ch, releaseFence);
- if (status != OK) {
- ALOGE("Failed to add release fence for layer %s", getName().c_str());
- }
mPreviousReleaseFence = releaseFence;
@@ -176,55 +101,14 @@ void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
}
}
-void BufferStateLayer::onSurfaceFrameCreated(
- const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) {
- while (mPendingJankClassifications.size() >= kPendingClassificationMaxSurfaceFrames) {
- // Too many SurfaceFrames pending classification. The front of the deque is probably not
- // tracked by FrameTimeline and will never be presented. This will only result in a memory
- // leak.
- ALOGW("Removing the front of pending jank deque from layer - %s to prevent memory leak",
- mName.c_str());
- std::string miniDump = mPendingJankClassifications.front()->miniDump();
- ALOGD("Head SurfaceFrame mini dump\n%s", miniDump.c_str());
- mPendingJankClassifications.pop_front();
- }
- mPendingJankClassifications.emplace_back(surfaceFrame);
-}
-
void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
for (const auto& handle : mDrawingState.callbackHandles) {
handle->transformHint = mTransformHint;
handle->dequeueReadyTime = dequeueReadyTime;
- handle->currentMaxAcquiredBufferCount =
- mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
- }
-
- // If there are multiple transactions in this frame, set the previous id on the earliest
- // transacton. We don't need to pass in the released buffer id to multiple transactions.
- // The buffer id does not have to correspond to any particular transaction as long as the
- // listening end point is the same but the client expects the first transaction callback that
- // replaces the presented buffer to contain the release fence. This follows the same logic.
- // see BufferStateLayer::onLayerDisplayed.
- for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer) {
- handle->previousReleaseCallbackId = mPreviousReleaseCallbackId;
- break;
- }
- }
-
- std::vector<JankData> jankData;
- jankData.reserve(mPendingJankClassifications.size());
- while (!mPendingJankClassifications.empty()
- && mPendingJankClassifications.front()->getJankType()) {
- std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame =
- mPendingJankClassifications.front();
- mPendingJankClassifications.pop_front();
- jankData.emplace_back(
- JankData(surfaceFrame->getToken(), surfaceFrame->getJankType().value()));
}
- mFlinger->getTransactionCallbackInvoker().finalizePendingCallbackHandles(
- mDrawingState.callbackHandles, jankData);
+ mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
+ mDrawingState.callbackHandles);
mDrawingState.callbackHandles = {};
@@ -247,158 +131,115 @@ void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime
}
}
+bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
+ if (getSidebandStreamChanged() || getAutoRefresh()) {
+ return true;
+ }
+
+ return hasFrameUpdate();
+}
+
bool BufferStateLayer::willPresentCurrentTransaction() const {
// Returns true if the most recent Transaction applied to CurrentState will be presented.
return (getSidebandStreamChanged() || getAutoRefresh() ||
- (mDrawingState.modified &&
- (mDrawingState.buffer != nullptr || mDrawingState.bgColorLayer != nullptr)));
+ (mCurrentState.modified &&
+ (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr))) &&
+ !mLayerDetached;
}
-Rect BufferStateLayer::getCrop(const Layer::State& s) const {
- return s.crop;
+/* TODO: vhau uncomment once deferred transaction migration complete in
+ * WindowManager
+void BufferStateLayer::pushPendingState() {
+ if (!mCurrentState.modified) {
+ return;
+ }
+ mPendingStates.push_back(mCurrentState);
+ ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
}
+*/
-bool BufferStateLayer::setTransform(uint32_t transform) {
- if (mDrawingState.bufferTransform == transform) return false;
- mDrawingState.bufferTransform = transform;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
+bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
+ mCurrentStateModified = mCurrentState.modified;
+ bool stateUpdateAvailable = Layer::applyPendingStates(stateToCommit);
+ mCurrentStateModified = stateUpdateAvailable && mCurrentStateModified;
+ mCurrentState.modified = false;
+ return stateUpdateAvailable;
}
-bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInverse) {
- if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false;
- mDrawingState.sequence++;
- mDrawingState.transformToDisplayInverse = transformToDisplayInverse;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
+// Crop that applies to the window
+Rect BufferStateLayer::getCrop(const Layer::State& /*s*/) const {
+ return Rect::INVALID_RECT;
}
-bool BufferStateLayer::setCrop(const Rect& crop) {
- if (mDrawingState.crop == crop) return false;
- mDrawingState.sequence++;
- mDrawingState.crop = crop;
-
- mDrawingState.modified = true;
+bool BufferStateLayer::setTransform(uint32_t transform) {
+ if (mCurrentState.transform == transform) return false;
+ mCurrentState.transform = transform;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
-bool BufferStateLayer::setBufferCrop(const Rect& bufferCrop) {
- if (mDrawingState.bufferCrop == bufferCrop) return false;
-
- mDrawingState.sequence++;
- mDrawingState.bufferCrop = bufferCrop;
-
- mDrawingState.modified = true;
+bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInverse) {
+ if (mCurrentState.transformToDisplayInverse == transformToDisplayInverse) return false;
+ mCurrentState.sequence++;
+ mCurrentState.transformToDisplayInverse = transformToDisplayInverse;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
-bool BufferStateLayer::setDestinationFrame(const Rect& destinationFrame) {
- if (mDrawingState.destinationFrame == destinationFrame) return false;
-
- mDrawingState.sequence++;
- mDrawingState.destinationFrame = destinationFrame;
+bool BufferStateLayer::setCrop(const Rect& crop) {
+ Rect c = crop;
+ if (c.left < 0) {
+ c.left = 0;
+ }
+ if (c.top < 0) {
+ c.top = 0;
+ }
+ // If the width and/or height are < 0, make it [0, 0, -1, -1] so the equality comparision below
+ // treats all invalid rectangles the same.
+ if (!c.isValid()) {
+ c.makeInvalid();
+ }
- mDrawingState.modified = true;
+ if (mCurrentState.crop == c) return false;
+ mCurrentState.crop = c;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
-static bool assignTransform(ui::Transform* dst, ui::Transform& from) {
- if (*dst == from) {
- return false;
- }
- *dst = from;
- return true;
-}
+bool BufferStateLayer::setFrame(const Rect& frame) {
+ int x = frame.left;
+ int y = frame.top;
+ int w = frame.getWidth();
+ int h = frame.getHeight();
-// Translate destination frame into scale and position. If a destination frame is not set, use the
-// provided scale and position
-bool BufferStateLayer::updateGeometry() {
- if (mDrawingState.destinationFrame.isEmpty()) {
- // If destination frame is not set, use the requested transform set via
- // BufferStateLayer::setPosition and BufferStateLayer::setMatrix.
- return assignTransform(&mDrawingState.transform, mRequestedTransform);
- }
-
- Rect destRect = mDrawingState.destinationFrame;
- int32_t destW = destRect.width();
- int32_t destH = destRect.height();
- if (destRect.left < 0) {
- destRect.left = 0;
- destRect.right = destW;
- }
- if (destRect.top < 0) {
- destRect.top = 0;
- destRect.bottom = destH;
+ if (x < 0) {
+ x = 0;
+ w = frame.right;
}
- if (!mDrawingState.buffer) {
- ui::Transform t;
- t.set(destRect.left, destRect.top);
- return assignTransform(&mDrawingState.transform, t);
+ if (y < 0) {
+ y = 0;
+ h = frame.bottom;
}
- uint32_t bufferWidth = mDrawingState.buffer->getBuffer()->getWidth();
- uint32_t bufferHeight = mDrawingState.buffer->getBuffer()->getHeight();
- // Undo any transformations on the buffer.
- if (mDrawingState.bufferTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
- if (mDrawingState.transformToDisplayInverse) {
- if (invTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
- }
-
- float sx = destW / static_cast<float>(bufferWidth);
- float sy = destH / static_cast<float>(bufferHeight);
- ui::Transform t;
- t.set(sx, 0, 0, sy);
- t.set(destRect.left, destRect.top);
- return assignTransform(&mDrawingState.transform, t);
-}
-
-bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix,
- bool allowNonRectPreservingTransforms) {
- if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy &&
- mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) {
+ if (mCurrentState.active.transform.tx() == x && mCurrentState.active.transform.ty() == y &&
+ mCurrentState.active.w == w && mCurrentState.active.h == h) {
return false;
}
- ui::Transform t;
- t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
-
- if (!allowNonRectPreservingTransforms && !t.preserveRects()) {
- ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER nor "
- "ROTATE_SURFACE_FLINGER ignored");
- return false;
- }
-
- mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
-
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-
- return true;
-}
-
-bool BufferStateLayer::setPosition(float x, float y) {
- if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) {
- return false;
+ if (!frame.isValid()) {
+ x = y = w = h = 0;
}
+ mCurrentState.active.transform.set(x, y);
+ mCurrentState.active.w = w;
+ mCurrentState.active.h = h;
- mRequestedTransform.set(x, y);
-
- mDrawingState.sequence++;
- mDrawingState.modified = true;
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
-
return true;
}
@@ -408,142 +249,87 @@ bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t post
mAcquireTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> acquireFenceTime =
std::make_shared<FenceTime>((acquireFence ? acquireFence : Fence::NO_FENCE));
- NewFrameEventsEntry newTimestamps = {mDrawingState.frameNumber, postedTime, desiredPresentTime,
+ NewFrameEventsEntry newTimestamps = {mCurrentState.frameNumber, postedTime, desiredPresentTime,
acquireFenceTime};
mFrameEventHistory.setProducerWantsEvents();
mFrameEventHistory.addQueue(newTimestamps);
return true;
}
-bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTexture>& buffer,
- const sp<Fence>& acquireFence, nsecs_t postTime,
- nsecs_t desiredPresentTime, bool isAutoTimestamp,
- const client_cache_t& clientCacheId, uint64_t frameNumber,
- std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info,
- const sp<ITransactionCompletedListener>& releaseBufferListener) {
- ATRACE_CALL();
-
- if (mDrawingState.buffer) {
+bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
+ nsecs_t postTime, nsecs_t desiredPresentTime,
+ const client_cache_t& clientCacheId) {
+ if (mCurrentState.buffer) {
mReleasePreviousBuffer = true;
- if (mDrawingState.buffer != 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, mTransformHint,
- mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
- mOwnerUid));
- decrementPendingBufferCount();
- if (mDrawingState.bufferSurfaceFrameTX != nullptr &&
- mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) {
- addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX);
- mDrawingState.bufferSurfaceFrameTX.reset();
- }
- }
}
- mDrawingState.frameNumber = frameNumber;
- mDrawingState.releaseBufferListener = releaseBufferListener;
- mDrawingState.buffer = buffer;
- mDrawingState.clientCacheId = clientCacheId;
- mDrawingState.modified = true;
+ mCurrentState.frameNumber++;
+
+ mCurrentState.buffer = buffer;
+ mCurrentState.clientCacheId = clientCacheId;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
const int32_t layerId = getSequence();
- mFlinger->mTimeStats->setPostTime(layerId, mDrawingState.frameNumber, getName().c_str(),
- mOwnerUid, postTime, getGameMode());
- mDrawingState.desiredPresentTime = desiredPresentTime;
- mDrawingState.isAutoTimestamp = isAutoTimestamp;
-
- const nsecs_t presentTime = [&] {
- if (!isAutoTimestamp) return desiredPresentTime;
+ mFlinger->mTimeStats->setPostTime(layerId, mCurrentState.frameNumber, getName().c_str(),
+ postTime);
+ desiredPresentTime = desiredPresentTime <= 0 ? 0 : desiredPresentTime;
+ mCurrentState.desiredPresentTime = desiredPresentTime;
- const auto prediction =
- mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken(info.vsyncId);
- if (prediction.has_value()) return prediction->presentTime;
-
- return static_cast<nsecs_t>(0);
- }();
- mFlinger->mScheduler->recordLayerHistory(this, presentTime,
+ mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime,
LayerHistory::LayerUpdateType::Buffer);
- addFrameEvent(acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime);
-
- setFrameTimelineVsyncForBufferTransaction(info, postTime);
-
- if (buffer && dequeueTime && *dequeueTime != 0) {
- const uint64_t bufferId = buffer->getBuffer()->getId();
- mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
- mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime,
- FrameTracer::FrameEvent::DEQUEUE);
- mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime,
- FrameTracer::FrameEvent::QUEUE);
- }
-
- mDrawingState.width = mDrawingState.buffer->getBuffer()->getWidth();
- mDrawingState.height = mDrawingState.buffer->getBuffer()->getHeight();
-
+ addFrameEvent(acquireFence, postTime, desiredPresentTime);
return true;
}
bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) {
- mDrawingState.acquireFence = fence;
- mDrawingState.acquireFenceTime = std::make_unique<FenceTime>(fence);
-
// The acquire fences of BufferStateLayers have already signaled before they are set
- mCallbackHandleAcquireTime = mDrawingState.acquireFenceTime->getSignalTime();
+ mCallbackHandleAcquireTime = fence->getSignalTime();
- mDrawingState.modified = true;
+ mCurrentState.acquireFence = fence;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setDataspace(ui::Dataspace dataspace) {
- if (mDrawingState.dataspace == dataspace) return false;
- mDrawingState.dataspace = dataspace;
- mDrawingState.modified = true;
+ if (mCurrentState.dataspace == dataspace) return false;
+ mCurrentState.dataspace = dataspace;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
- if (mDrawingState.hdrMetadata == hdrMetadata) return false;
- mDrawingState.hdrMetadata = hdrMetadata;
- mDrawingState.modified = true;
+ if (mCurrentState.hdrMetadata == hdrMetadata) return false;
+ mCurrentState.hdrMetadata = hdrMetadata;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setSurfaceDamageRegion(const Region& surfaceDamage) {
- mDrawingState.surfaceDamageRegion = surfaceDamage;
- mDrawingState.modified = true;
+ mCurrentState.surfaceDamageRegion = surfaceDamage;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setApi(int32_t api) {
- if (mDrawingState.api == api) return false;
- mDrawingState.api = api;
- mDrawingState.modified = true;
+ if (mCurrentState.api == api) return false;
+ mCurrentState.api = api;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setSidebandStream(const sp<NativeHandle>& sidebandStream) {
- 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;
- mDrawingState.modified = true;
+ if (mCurrentState.sidebandStream == sidebandStream) return false;
+ mCurrentState.sidebandStream = sidebandStream;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
+
if (!mSidebandStreamChanged.exchange(true)) {
// mSidebandStreamChanged was false
mFlinger->signalLayerUpdate();
@@ -569,18 +355,17 @@ bool BufferStateLayer::setTransactionCompletedListeners(
if (willPresent) {
// If this transaction set an acquire fence on this layer, set its acquire time
handle->acquireTime = mCallbackHandleAcquireTime;
- handle->frameNumber = mDrawingState.frameNumber;
// Notify the transaction completed thread that there is a pending latched callback
// handle
- mFlinger->getTransactionCallbackInvoker().registerPendingCallbackHandle(handle);
+ mFlinger->getTransactionCompletedThread().registerPendingCallbackHandle(handle);
// Store so latched time and release fence can be set
- mDrawingState.callbackHandles.push_back(handle);
+ mCurrentState.callbackHandles.push_back(handle);
} else { // If this layer will NOT need to be relatched and presented this frame
// Notify the transaction completed thread this handle is done
- mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle);
+ mFlinger->getTransactionCompletedThread().registerUnpresentedCallbackHandle(handle);
}
}
@@ -590,45 +375,45 @@ bool BufferStateLayer::setTransactionCompletedListeners(
return willPresent;
}
+void BufferStateLayer::forceSendCallbacks() {
+ mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
+ mCurrentState.callbackHandles);
+}
+
bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
- mDrawingState.sequence++;
- mDrawingState.transparentRegionHint = transparent;
- mDrawingState.modified = true;
+ mCurrentState.transparentRegionHint = transparent;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
Rect BufferStateLayer::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->getBuffer()->getWidth();
- uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight();
-
- // Undo any transformations on the buffer and return the result.
- if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
- std::swap(bufWidth, bufHeight);
+ if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) {
+ return Rect(getActiveWidth(s), getActiveHeight(s));
}
- if (getTransformToDisplayInverse()) {
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
- if (invTransform & ui::Transform::ROT_90) {
- std::swap(bufWidth, bufHeight);
+ // if the display frame is not defined, use the parent bounds as the buffer size.
+ const auto& p = mDrawingParent.promote();
+ if (p != nullptr) {
+ Rect parentBounds = Rect(p->getBounds(Region()));
+ if (!parentBounds.isEmpty()) {
+ return parentBounds;
}
}
- return Rect(0, 0, bufWidth, bufHeight);
+ return Rect::INVALID_RECT;
}
FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) const {
- if (mBufferInfo.mBuffer == nullptr) {
- return parentBounds;
+ const State& s(getDrawingState());
+ // for buffer state layers we use the display frame size as the buffer size.
+ if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) {
+ return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s));
}
- return getBufferSize(getDrawingState()).toFloatRect();
+ // if the display frame is not defined, use the parent bounds as the buffer size.
+ return parentBounds;
}
// -----------------------------------------------------------------------
@@ -637,7 +422,7 @@ FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) c
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
bool BufferStateLayer::fenceHasSignaled() const {
- if (SurfaceFlinger::enableLatchUnsignaled) {
+ if (latchUnsignaledBuffers()) {
return true;
}
@@ -656,7 +441,7 @@ bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) co
return true;
}
- return mDrawingState.isAutoTimestamp || mDrawingState.desiredPresentTime <= expectedPresentTime;
+ return mCurrentState.desiredPresentTime <= expectedPresentTime;
}
bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) {
@@ -683,9 +468,9 @@ uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const
* DeferTransactionUntil -> frameNumber = 2
* Random other stuff
* }
- * Now imagine mFrameNumber returned mDrawingState.frameNumber (or mCurrentFrameNumber).
+ * Now imagine getHeadFrameNumber returned mDrawingState.mFrameNumber (or mCurrentFrameNumber).
* Prior to doTransaction SurfaceFlinger will call notifyAvailableFrames, but because we
- * haven't swapped mDrawingState to mDrawingState yet we will think the sync point
+ * haven't swapped mCurrentState to mDrawingState yet we will think the sync point
* is not ready. So we will return false from applyPendingState and not swap
* current state to drawing state. But because we don't swap current state
* to drawing state the number will never update and we will be stuck. This way
@@ -693,20 +478,20 @@ uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const
* to apply.
*/
uint64_t BufferStateLayer::getHeadFrameNumber(nsecs_t /* expectedPresentTime */) const {
- return mDrawingState.frameNumber;
+ return mCurrentState.frameNumber;
}
-void BufferStateLayer::setAutoRefresh(bool autoRefresh) {
- if (!mAutoRefresh.exchange(autoRefresh)) {
- mFlinger->signalLayerUpdate();
- }
+bool BufferStateLayer::getAutoRefresh() const {
+ // TODO(marissaw): support shared buffer mode
+ return false;
}
-bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
- // We need to update the sideband stream if the layer has both a buffer and a sideband stream.
- const bool updateSidebandStream = hasFrameUpdate() && mSidebandStream.get();
+bool BufferStateLayer::getSidebandStreamChanged() const {
+ return mSidebandStreamChanged.load();
+}
- if (mSidebandStreamChanged.exchange(false) || updateSidebandStream) {
+bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+ if (mSidebandStreamChanged.exchange(false)) {
const State& s(getDrawingState());
// mSidebandStreamChanged was true
mSidebandStream = s.sidebandStream;
@@ -723,8 +508,15 @@ bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
}
bool BufferStateLayer::hasFrameUpdate() const {
- const State& c(getDrawingState());
- return (mDrawingStateModified || mDrawingState.modified) && (c.buffer != nullptr || c.bgColorLayer != nullptr);
+ const State& c(getCurrentState());
+ return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
+}
+
+status_t BufferStateLayer::bindTextureImage() {
+ const State& s(getDrawingState());
+ auto& engine(mFlinger->getRenderEngine());
+
+ return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence);
}
status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
@@ -740,42 +532,56 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse
return NO_ERROR;
}
+ const int32_t layerId = getSequence();
+
+ // Reject if the layer is invalid
+ uint32_t bufferWidth = s.buffer->width;
+ uint32_t bufferHeight = s.buffer->height;
+
+ if (s.transform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+
+ if (s.transformToDisplayInverse) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+ }
+
+ if (getEffectiveScalingMode() == NATIVE_WINDOW_SCALING_MODE_FREEZE &&
+ (s.active.w != bufferWidth || s.active.h != bufferHeight)) {
+ ALOGE("[%s] rejecting buffer: "
+ "bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
+ getDebugName(), bufferWidth, bufferHeight, s.active.w, s.active.h);
+ mFlinger->mTimeStats->removeTimeRecord(layerId, mDrawingState.frameNumber);
+ return BAD_VALUE;
+ }
+
for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->frameNumber == mDrawingState.frameNumber) {
- handle->latchTime = latchTime;
+ handle->latchTime = latchTime;
+ handle->frameNumber = mDrawingState.frameNumber;
+ }
+
+ if (!SyncFeatures::getInstance().useNativeFenceSync()) {
+ // Bind the new buffer to the GL texture.
+ //
+ // Older devices require the "implicit" synchronization provided
+ // by glEGLImageTargetTexture2DOES, which this method calls. Newer
+ // devices will either call this in Layer::onDraw, or (if it's not
+ // a GL-composited layer) not at all.
+ status_t err = bindTextureImage();
+ if (err != NO_ERROR) {
+ mFlinger->mTimeStats->onDestroy(layerId);
+ return BAD_VALUE;
}
}
- const int32_t layerId = getSequence();
- const uint64_t bufferId = mDrawingState.buffer->getBuffer()->getId();
- const uint64_t frameNumber = mDrawingState.frameNumber;
- const auto acquireFence = std::make_shared<FenceTime>(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<sp<CallbackHandle>> remainingHandles;
- mFlinger->getTransactionCallbackInvoker()
- .finalizeOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles);
- mDrawingState.callbackHandles = remainingHandles;
-
- mDrawingStateModified = false;
+ mFlinger->mTimeStats->setAcquireFence(layerId, mDrawingState.frameNumber,
+ std::make_shared<FenceTime>(mDrawingState.acquireFence));
+ mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime);
+
+ mCurrentStateModified = false;
return NO_ERROR;
}
@@ -787,14 +593,9 @@ status_t BufferStateLayer::updateActiveBuffer() {
return BAD_VALUE;
}
- if (!mBufferInfo.mBuffer || s.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) {
- decrementPendingBufferCount();
- }
-
- mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber};
+ mPreviousBufferId = getCurrentBufferId();
mBufferInfo.mBuffer = s.buffer;
mBufferInfo.mFence = s.acquireFence;
- mBufferInfo.mFrameNumber = s.frameNumber;
return NO_ERROR;
}
@@ -890,13 +691,9 @@ void BufferStateLayer::gatherBufferInfo() {
mBufferInfo.mDesiredPresentTime = s.desiredPresentTime;
mBufferInfo.mFenceTime = std::make_shared<FenceTime>(s.acquireFence);
mBufferInfo.mFence = s.acquireFence;
- mBufferInfo.mTransform = s.bufferTransform;
- auto lastDataspace = mBufferInfo.mDataspace;
+ mBufferInfo.mTransform = s.transform;
mBufferInfo.mDataspace = translateDataspace(s.dataspace);
- if (lastDataspace != mBufferInfo.mDataspace) {
- mFlinger->mSomeDataspaceChanged = true;
- }
- mBufferInfo.mCrop = computeBufferCrop(s);
+ mBufferInfo.mCrop = computeCrop(s);
mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion;
mBufferInfo.mHdrMetadata = s.hdrMetadata;
@@ -905,20 +702,27 @@ void BufferStateLayer::gatherBufferInfo() {
mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId);
}
-uint32_t BufferStateLayer::getEffectiveScalingMode() const {
- return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
-}
-
-Rect BufferStateLayer::computeBufferCrop(const State& s) {
- if (s.buffer && !s.bufferCrop.isEmpty()) {
- Rect bufferCrop;
- s.buffer->getBuffer()->getBounds().intersect(s.bufferCrop, &bufferCrop);
- return bufferCrop;
+Rect BufferStateLayer::computeCrop(const State& s) {
+ if (s.crop.isEmpty() && s.buffer) {
+ return s.buffer->getBounds();
} else if (s.buffer) {
- return s.buffer->getBuffer()->getBounds();
- } else {
- return s.bufferCrop;
+ Rect crop = s.crop;
+ crop.left = std::max(crop.left, 0);
+ crop.top = std::max(crop.top, 0);
+ uint32_t bufferWidth = s.buffer->getWidth();
+ uint32_t bufferHeight = s.buffer->getHeight();
+ if (bufferHeight <= std::numeric_limits<int32_t>::max() &&
+ bufferWidth <= std::numeric_limits<int32_t>::max()) {
+ crop.right = std::min(crop.right, static_cast<int32_t>(bufferWidth));
+ crop.bottom = std::min(crop.bottom, static_cast<int32_t>(bufferHeight));
+ }
+ if (!crop.isValid()) {
+ // Crop rect is out of bounds, return whole buffer
+ return s.buffer->getBounds();
+ }
+ return crop;
}
+ return s.crop;
}
sp<Layer> BufferStateLayer::createClone() {
@@ -930,72 +734,33 @@ sp<Layer> BufferStateLayer::createClone() {
return layer;
}
-bool BufferStateLayer::bufferNeedsFiltering() const {
- const State& s(getDrawingState());
- if (!s.buffer) {
- return false;
- }
-
- uint32_t bufferWidth = s.buffer->getBuffer()->width;
- uint32_t bufferHeight = s.buffer->getBuffer()->height;
-
- // Undo any transformations on the buffer and return the result.
- if (s.bufferTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
-
- if (s.transformToDisplayInverse) {
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
- if (invTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
+Layer::RoundedCornerState BufferStateLayer::getRoundedCornerState() const {
+ const auto& p = mDrawingParent.promote();
+ if (p != nullptr) {
+ RoundedCornerState parentState = p->getRoundedCornerState();
+ if (parentState.radius > 0) {
+ ui::Transform t = getActiveTransform(getDrawingState());
+ t = t.inverse();
+ parentState.cropRect = t.transform(parentState.cropRect);
+ // The rounded corners shader only accepts 1 corner radius for performance reasons,
+ // but a transform matrix can define horizontal and vertical scales.
+ // Let's take the average between both of them and pass into the shader, practically we
+ // never do this type of transformation on windows anyway.
+ parentState.radius *= (t[0][0] + t[1][1]) / 2.0f;
+ return parentState;
}
}
-
- const Rect layerSize{getBounds()};
- return layerSize.width() != bufferWidth || layerSize.height() != bufferHeight;
-}
-
-void BufferStateLayer::decrementPendingBufferCount() {
- int32_t pendingBuffers = --mPendingBufferTransactions;
- tracePendingBufferCount(pendingBuffers);
-}
-
-void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) {
- ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers);
-}
-
-
-/*
- * We don't want to send the layer's transform to input, but rather the
- * parent's transform. This is because BufferStateLayer's transform is
- * information about how the buffer is placed on screen. The parent's
- * transform makes more sense to send since it's information about how the
- * layer is placed on screen. This transform is used by input to determine
- * how to go from screen space back to window space.
- */
-ui::Transform BufferStateLayer::getInputTransform() const {
- sp<Layer> parent = mDrawingParent.promote();
- if (parent == nullptr) {
- return ui::Transform();
- }
-
- return parent->getTransform();
-}
-
-/**
- * Similar to getInputTransform, we need to update the bounds to include the transform.
- * This is because bounds for BSL doesn't include buffer transform, where the input assumes
- * that's already included.
- */
-Rect BufferStateLayer::getInputBounds() const {
- Rect bufferBounds = getCroppedBufferSize(getDrawingState());
- if (mDrawingState.transform.getType() == ui::Transform::IDENTITY || !bufferBounds.isValid()) {
- return bufferBounds;
- }
- return mDrawingState.transform.transform(bufferBounds);
+ const float radius = getDrawingState().cornerRadius;
+ const State& s(getDrawingState());
+ if (radius <= 0 || (getActiveWidth(s) == UINT32_MAX && getActiveHeight(s) == UINT32_MAX))
+ return RoundedCornerState();
+ return RoundedCornerState(FloatRect(static_cast<float>(s.active.transform.tx()),
+ static_cast<float>(s.active.transform.ty()),
+ static_cast<float>(s.active.transform.tx() + s.active.w),
+ static_cast<float>(s.active.transform.ty() + s.active.h)),
+ radius);
}
-
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
+#pragma clang diagnostic pop // ignored "-Wconversion"