1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
|
/*
* Copyright (C) 2018 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.
*/
#undef LOG_TAG
#define LOG_TAG "BufferQueueLayer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <gui/BufferQueueConsumer.h>
#include <system/window.h>
#include "BufferQueueLayer.h"
#include "LayerRejecter.h"
#include "SurfaceInterceptor.h"
#include "TimeStats/TimeStats.h"
namespace android {
BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {}
BufferQueueLayer::~BufferQueueLayer() {
mConsumer->abandon();
}
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
void BufferQueueLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
mConsumer->setReleaseFence(releaseFence);
}
void BufferQueueLayer::setTransformHint(uint32_t orientation) const {
mConsumer->setTransformHint(orientation);
}
std::vector<OccupancyTracker::Segment> BufferQueueLayer::getOccupancyHistory(bool forceFlush) {
std::vector<OccupancyTracker::Segment> history;
status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
if (result != NO_ERROR) {
ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result);
return {};
}
return history;
}
bool BufferQueueLayer::getTransformToDisplayInverse() const {
return mConsumer->getTransformToDisplayInverse();
}
void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
if (!mConsumer->releasePendingBuffer()) {
return;
}
auto releaseFenceTime = std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
mReleaseTimeline.updateSignalTimes();
mReleaseTimeline.push(releaseFenceTime);
Mutex::Autolock lock(mFrameEventHistoryMutex);
if (mPreviousFrameNumber != 0) {
mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
std::move(releaseFenceTime));
}
}
void BufferQueueLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
mConsumer->setDefaultBufferSize(w, h);
}
int32_t BufferQueueLayer::getQueuedFrameCount() const {
return mQueuedFrames;
}
bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const {
if (getSidebandStreamChanged() || getAutoRefresh()) {
return true;
}
if (!hasFrameUpdate()) {
return false;
}
Mutex::Autolock lock(mQueueItemLock);
const int64_t addedTime = mQueueItems[0].mTimestamp;
// Ignore timestamps more than a second in the future
const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1));
ALOGW_IF(!isPlausible,
"[%s] Timestamp %" PRId64 " seems implausible "
"relative to expectedPresent %" PRId64,
mName.string(), addedTime, expectedPresentTime);
const bool isDue = addedTime < expectedPresentTime;
return isDue || !isPlausible;
}
// -----------------------------------------------------------------------
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
bool BufferQueueLayer::fenceHasSignaled() const {
if (latchUnsignaledBuffers()) {
return true;
}
if (!hasFrameUpdate()) {
return true;
}
Mutex::Autolock lock(mQueueItemLock);
if (mQueueItems[0].mIsDroppable) {
// Even though this buffer's fence may not have signaled yet, it could
// be replaced by another buffer before it has a chance to, which means
// that it's possible to get into a situation where a buffer is never
// able to be latched. To avoid this, grab this buffer anyway.
return true;
}
return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
}
bool BufferQueueLayer::framePresentTimeIsCurrent() const {
if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
return true;
}
Mutex::Autolock lock(mQueueItemLock);
return mQueueItems[0].mTimestamp <= mFlinger->getExpectedPresentTime();
}
nsecs_t BufferQueueLayer::getDesiredPresentTime() {
return mConsumer->getTimestamp();
}
std::shared_ptr<FenceTime> BufferQueueLayer::getCurrentFenceTime() const {
return mConsumer->getCurrentFenceTime();
}
void BufferQueueLayer::getDrawingTransformMatrix(float *matrix) {
return mConsumer->getTransformMatrix(matrix);
}
// NOTE: SurfaceFlinger's definitions of "Current" and "Drawing" do not neatly map to BufferQueue's
// These functions get the fields for the frame that is currently in SurfaceFlinger's Drawing state
// so the functions start with "getDrawing". The data is retrieved from the BufferQueueConsumer's
// current buffer so the consumer functions start with "getCurrent".
//
// This results in the rather confusing functions below.
uint32_t BufferQueueLayer::getDrawingTransform() const {
return mConsumer->getCurrentTransform();
}
ui::Dataspace BufferQueueLayer::getDrawingDataSpace() const {
return mConsumer->getCurrentDataSpace();
}
Rect BufferQueueLayer::getDrawingCrop() const {
return mConsumer->getCurrentCrop();
}
uint32_t BufferQueueLayer::getDrawingScalingMode() const {
return mConsumer->getCurrentScalingMode();
}
Region BufferQueueLayer::getDrawingSurfaceDamage() const {
return mConsumer->getSurfaceDamage();
}
const HdrMetadata& BufferQueueLayer::getDrawingHdrMetadata() const {
return mConsumer->getCurrentHdrMetadata();
}
int BufferQueueLayer::getDrawingApi() const {
return mConsumer->getCurrentApi();
}
PixelFormat BufferQueueLayer::getPixelFormat() const {
return mFormat;
}
uint64_t BufferQueueLayer::getFrameNumber() const {
Mutex::Autolock lock(mQueueItemLock);
uint64_t frameNumber = mQueueItems[0].mFrameNumber;
// The head of the queue will be dropped if there are signaled and timely frames behind it
nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
}
for (int i = 1; i < mQueueItems.size(); i++) {
const bool fenceSignaled =
mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
if (!fenceSignaled) {
break;
}
// We don't drop frames without explicit timestamps
if (mQueueItems[i].mIsAutoTimestamp) {
break;
}
const nsecs_t desiredPresent = mQueueItems[i].mTimestamp;
if (desiredPresent < expectedPresentTime - BufferQueueConsumer::MAX_REASONABLE_NSEC ||
desiredPresent > expectedPresentTime) {
break;
}
frameNumber = mQueueItems[i].mFrameNumber;
}
return frameNumber;
}
bool BufferQueueLayer::getAutoRefresh() const {
return mAutoRefresh;
}
bool BufferQueueLayer::getSidebandStreamChanged() const {
return mSidebandStreamChanged;
}
bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
bool sidebandStreamChanged = true;
if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
// mSidebandStreamChanged was changed to false
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
layerCompositionState.sidebandStream = mConsumer->getSidebandStream();
if (layerCompositionState.sidebandStream != nullptr) {
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
recomputeVisibleRegions = true;
return true;
}
return false;
}
bool BufferQueueLayer::hasFrameUpdate() const {
return mQueuedFrames > 0;
}
void BufferQueueLayer::setFilteringEnabled(bool enabled) {
return mConsumer->setFilteringEnabled(enabled);
}
status_t BufferQueueLayer::bindTextureImage() {
return mConsumer->bindTextureImage();
}
status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) {
// This boolean is used to make sure that SurfaceFlinger's shadow copy
// of the buffer queue isn't modified when the buffer queue is returning
// BufferItem's that weren't actually queued. This can happen in shared
// buffer mode.
bool queuedBuffer = false;
const int32_t layerID = getSequence();
LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
getTransformToDisplayInverse(), mFreezeGeometryUpdates);
nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
}
// updateTexImage() below might drop the some buffers at the head of the queue if there is a
// buffer behind them which is timely to be presented. However this buffer may not be signaled
// yet. The code below makes sure that this wouldn't happen by setting maxFrameNumber to the
// last buffer that was signaled.
uint64_t lastSignaledFrameNumber = mLastFrameNumberReceived;
{
Mutex::Autolock lock(mQueueItemLock);
for (int i = 0; i < mQueueItems.size(); i++) {
bool fenceSignaled =
mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
if (!fenceSignaled) {
break;
}
lastSignaledFrameNumber = mQueueItems[i].mFrameNumber;
}
}
const uint64_t maxFrameNumberToAcquire =
std::min(mLastFrameNumberReceived.load(), lastSignaledFrameNumber);
status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh,
&queuedBuffer, maxFrameNumberToAcquire);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
mFlinger->signalLayerUpdate();
return BAD_VALUE;
} else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) {
// If the buffer has been rejected, remove it from the shadow queue
// and return early
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
mFlinger->mTimeStats->removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
mQueueItems.removeAt(0);
mQueuedFrames--;
}
return BAD_VALUE;
} else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
// This can occur if something goes wrong when trying to create the
// EGLImage for this buffer. If this happens, the buffer has already
// been released, so we need to clean up the queue and bug out
// early.
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
mQueueItems.clear();
mQueuedFrames = 0;
mFlinger->mTimeStats->onDestroy(layerID);
}
// Once we have hit this state, the shadow queue may no longer
// correctly reflect the incoming BufferQueue's contents, so even if
// updateTexImage starts working, the only safe course of action is
// to continue to ignore updates.
mUpdateTexImageFailed = true;
return BAD_VALUE;
}
if (queuedBuffer) {
// Autolock scope
auto currentFrameNumber = mConsumer->getFrameNumber();
Mutex::Autolock lock(mQueueItemLock);
// Remove any stale buffers that have been dropped during
// updateTexImage
while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
mFlinger->mTimeStats->removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
mQueueItems.removeAt(0);
mQueuedFrames--;
}
mFlinger->mTimeStats->setAcquireFence(layerID, currentFrameNumber,
mQueueItems[0].mFenceTime);
mFlinger->mTimeStats->setLatchTime(layerID, currentFrameNumber, latchTime);
mQueueItems.removeAt(0);
}
// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
if ((queuedBuffer && mQueuedFrames.fetch_sub(1) > 1) || mAutoRefresh) {
mFlinger->signalLayerUpdate();
}
return NO_ERROR;
}
status_t BufferQueueLayer::updateActiveBuffer() {
// update the active buffer
mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence);
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
layerCompositionState.buffer = mActiveBuffer;
layerCompositionState.bufferSlot = mActiveBufferSlot;
if (mActiveBuffer == nullptr) {
// this can only happen if the very first buffer was rejected.
return BAD_VALUE;
}
return NO_ERROR;
}
status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) {
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mConsumer->getFrameNumber();
{
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
}
return NO_ERROR;
}
void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
const auto outputLayer = findOutputLayerForDisplay(display);
LOG_FATAL_IF(!outputLayer);
LOG_FATAL_IF(!outputLayer->getState.hwc);
auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
uint32_t hwcSlot = 0;
sp<GraphicBuffer> hwcBuffer;
// INVALID_BUFFER_SLOT is used to identify BufferStateLayers. Default to 0
// for BufferQueueLayers
int slot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot;
(*outputLayer->editState().hwc)
.hwcBufferCache.getHwcBuffer(slot, mActiveBuffer, &hwcSlot, &hwcBuffer);
auto acquireFence = mConsumer->getCurrentFence();
auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), mActiveBuffer->handle,
to_string(error).c_str(), static_cast<int32_t>(error));
}
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
layerCompositionState.bufferSlot = mActiveBufferSlot;
layerCompositionState.buffer = mActiveBuffer;
layerCompositionState.acquireFence = acquireFence;
}
// -----------------------------------------------------------------------
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
// -----------------------------------------------------------------------
void BufferQueueLayer::fakeVsync() {
mRefreshPending = false;
bool ignored = false;
latchBuffer(ignored, systemTime());
usleep(16000);
releasePendingBuffer(systemTime());
}
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
ATRACE_CALL();
// Add this buffer from our internal queue tracker
{ // Autolock scope
if (mFlinger->mUseSmart90ForVideo) {
const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp;
mFlinger->mScheduler->addLayerPresentTimeAndHDR(mSchedulerLayerHandle, presentTime,
item.mHdrMetadata.validTypes != 0);
}
Mutex::Autolock lock(mQueueItemLock);
// Reset the frame number tracker when we receive the first buffer after
// a frame number reset
if (item.mFrameNumber == 1) {
mLastFrameNumberReceived = 0;
}
// Ensure that callbacks are handled in order
while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
if (result != NO_ERROR) {
ALOGE("[%s] Timed out waiting on callback", mName.string());
}
}
mQueueItems.push_back(item);
mQueuedFrames++;
// Wake up any pending callbacks
mLastFrameNumberReceived = item.mFrameNumber;
mQueueItemCondition.broadcast();
}
mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
item.mGraphicBuffer->getHeight(), item.mFrameNumber);
// If this layer is orphaned, then we run a fake vsync pulse so that
// dequeueBuffer doesn't block indefinitely.
if (isRemovedFromCurrentState()) {
fakeVsync();
} else {
mFlinger->signalLayerUpdate();
}
mConsumer->onBufferAvailable(item);
}
void BufferQueueLayer::onFrameReplaced(const BufferItem& item) {
ATRACE_CALL();
{ // Autolock scope
Mutex::Autolock lock(mQueueItemLock);
// Ensure that callbacks are handled in order
while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
if (result != NO_ERROR) {
ALOGE("[%s] Timed out waiting on callback", mName.string());
}
}
if (!hasFrameUpdate()) {
ALOGE("Can't replace a frame on an empty queue");
return;
}
mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
// Wake up any pending callbacks
mLastFrameNumberReceived = item.mFrameNumber;
mQueueItemCondition.broadcast();
}
mConsumer->onBufferAvailable(item);
}
void BufferQueueLayer::onSidebandStreamChanged() {
bool sidebandStreamChanged = false;
if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, true)) {
// mSidebandStreamChanged was changed to true
mFlinger->signalLayerUpdate();
}
}
// -----------------------------------------------------------------------
void BufferQueueLayer::onFirstRef() {
BufferLayer::onFirstRef();
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer, true);
mProducer = new MonitoredProducer(producer, mFlinger, this);
{
// Grab the SF state lock during this since it's the only safe way to access RenderEngine
Mutex::Autolock lock(mFlinger->mStateLock);
mConsumer =
new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this);
}
mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mConsumer->setContentsChangedListener(this);
mConsumer->setName(mName);
// BufferQueueCore::mMaxDequeuedBufferCount is default to 1
if (!mFlinger->isLayerTripleBufferingDisabled()) {
mProducer->setMaxDequeuedBufferCount(2);
}
if (const auto display = mFlinger->getDefaultDisplayDevice()) {
updateTransformHint(display);
}
}
status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) {
uint32_t const maxSurfaceDims =
std::min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
// never allow a surface larger than what our underlying GL implementation
// can handle.
if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) {
ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
return BAD_VALUE;
}
mFormat = format;
setDefaultBufferSize(w, h);
mConsumer->setDefaultBufferFormat(format);
mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
return NO_ERROR;
}
sp<IGraphicBufferProducer> BufferQueueLayer::getProducer() const {
return mProducer;
}
uint32_t BufferQueueLayer::getProducerStickyTransform() const {
int producerStickyTransform = 0;
int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
if (ret != OK) {
ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
strerror(-ret), ret);
return 0;
}
return static_cast<uint32_t>(producerStickyTransform);
}
} // namespace android
|