blob: 4c1b267397e816c8342a73b1e0a26e7a03313880 [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <sys/types.h>
#include <errno.h>
#include <dlfcn.h>
#include <algorithm>
#include <cinttypes>
#include <cmath>
#include <cstdint>
#include <functional>
#include <mutex>
#include <optional>
#include <unordered_map>
#include <cutils/properties.h>
#include <log/log.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/RenderSurface.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <dvr/vr_flinger.h>
#include <gui/BufferQueue.h>
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/IProducerListener.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
#include <input/IInputFlinger.h>
#include <renderengine/RenderEngine.h>
#include <ui/ColorSpace.h>
#include <ui/DebugUtils.h>
#include <ui/DisplayInfo.h>
#include <ui/DisplayStatInfo.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
#include <ui/UiConfig.h>
#include <utils/CallStack.h>
#include <utils/StopWatch.h>
#include <utils/String16.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
#include <utils/misc.h>
#include <private/android_filesystem_config.h>
#include <private/gui/SyncFeatures.h>
#include "BufferLayer.h"
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
#include "Client.h"
#include "ColorLayer.h"
#include "Colorizer.h"
#include "ContainerLayer.h"
#include "DdmConnection.h"
#include "DisplayDevice.h"
#include "Layer.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
#include "NativeWindowSurface.h"
#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
#include "SurfaceInterceptor.h"
#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "Effects/Daltonizer.h"
#include "Scheduler/DispSync.h"
#include "Scheduler/DispSyncSource.h"
#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/InjectVSyncSource.h"
#include "Scheduler/MessageQueue.h"
#include "Scheduler/Scheduler.h"
#include "TimeStats/TimeStats.h"
#include <cutils/compiler.h>
#include "android-base/stringprintf.h"
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
#include <configstore/Utils.h>
#include <layerproto/LayerProtoParser.h>
#include "SurfaceFlingerProperties.h"
namespace android {
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
using namespace android::sysprop;
using base::StringAppendF;
using ui::ColorMode;
using ui::Dataspace;
using ui::DisplayPrimaries;
using ui::Hdr;
using ui::RenderIntent;
namespace {
#pragma clang diagnostic push
#pragma clang diagnostic error "-Wswitch-enum"
bool isWideColorMode(const ColorMode colorMode) {
switch (colorMode) {
case ColorMode::DISPLAY_P3:
case ColorMode::ADOBE_RGB:
case ColorMode::DCI_P3:
case ColorMode::BT2020:
case ColorMode::DISPLAY_BT2020:
case ColorMode::BT2100_PQ:
case ColorMode::BT2100_HLG:
return true;
case ColorMode::NATIVE:
case ColorMode::STANDARD_BT601_625:
case ColorMode::STANDARD_BT601_625_UNADJUSTED:
case ColorMode::STANDARD_BT601_525:
case ColorMode::STANDARD_BT601_525_UNADJUSTED:
case ColorMode::STANDARD_BT709:
case ColorMode::SRGB:
return false;
}
return false;
}
ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
switch (rotation) {
case ISurfaceComposer::eRotateNone:
return ui::Transform::ROT_0;
case ISurfaceComposer::eRotate90:
return ui::Transform::ROT_90;
case ISurfaceComposer::eRotate180:
return ui::Transform::ROT_180;
case ISurfaceComposer::eRotate270:
return ui::Transform::ROT_270;
}
ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
return ui::Transform::ROT_0;
}
#pragma clang diagnostic pop
class ConditionalLock {
public:
ConditionalLock(Mutex& mutex, bool lock) : mMutex(mutex), mLocked(lock) {
if (lock) {
mMutex.lock();
}
}
~ConditionalLock() { if (mLocked) mMutex.unlock(); }
private:
Mutex& mMutex;
bool mLocked;
};
// Currently we only support V0_SRGB and DISPLAY_P3 as composition preference.
bool validateCompositionDataspace(Dataspace dataspace) {
return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
}
} // namespace anonymous
// ---------------------------------------------------------------------------
const String16 sHardwareTest("android.permission.HARDWARE_TEST");
const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
const String16 sDump("android.permission.DUMP");
constexpr float kSrgbRedX = 0.4123f;
constexpr float kSrgbRedY = 0.2126f;
constexpr float kSrgbRedZ = 0.0193f;
constexpr float kSrgbGreenX = 0.3576f;
constexpr float kSrgbGreenY = 0.7152f;
constexpr float kSrgbGreenZ = 0.1192f;
constexpr float kSrgbBlueX = 0.1805f;
constexpr float kSrgbBlueY = 0.0722f;
constexpr float kSrgbBlueZ = 0.9506f;
constexpr float kSrgbWhiteX = 0.9505f;
constexpr float kSrgbWhiteY = 1.0000f;
constexpr float kSrgbWhiteZ = 1.0891f;
// ---------------------------------------------------------------------------
int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
bool SurfaceFlinger::useHwcForRgbToYuv;
uint64_t SurfaceFlinger::maxVirtualDisplaySize;
bool SurfaceFlinger::hasSyncFramework;
bool SurfaceFlinger::useVrFlinger;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
bool SurfaceFlinger::hasWideColorDisplay;
int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
bool SurfaceFlinger::useColorManagement;
bool SurfaceFlinger::useContextPriority;
Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
std::string getHwcServiceName() {
char value[PROPERTY_VALUE_MAX] = {};
property_get("debug.sf.hwc_service_name", value, "default");
ALOGI("Using HWComposer service: '%s'", value);
return std::string(value);
}
bool useTrebleTestingOverride() {
char value[PROPERTY_VALUE_MAX] = {};
property_get("debug.sf.treble_testing_override", value, "false");
ALOGI("Treble testing override: '%s'", value);
return std::string(value) == "true";
}
std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
switch(displayColorSetting) {
case DisplayColorSetting::MANAGED:
return std::string("Managed");
case DisplayColorSetting::UNMANAGED:
return std::string("Unmanaged");
case DisplayColorSetting::ENHANCED:
return std::string("Enhanced");
default:
return std::string("Unknown ") +
std::to_string(static_cast<int>(displayColorSetting));
}
}
SurfaceFlingerBE::SurfaceFlingerBE()
: mHwcServiceName(getHwcServiceName()),
mFrameBuckets(),
mTotalTime(0),
mLastSwapTime(0),
mComposerSequenceId(0) {
}
SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory,
SurfaceFlinger::SkipInitializationTag)
: BnSurfaceComposer(),
mFactory(factory),
mTransactionPending(false),
mAnimTransactionPending(false),
mLayersRemoved(false),
mLayersAdded(false),
mBootTime(systemTime()),
mPhaseOffsets{getFactory().createPhaseOffsets()},
mVisibleRegionsDirty(false),
mGeometryInvalid(false),
mAnimCompositionPending(false),
mBootStage(BootStage::BOOTLOADER),
mDebugRegion(0),
mDebugDDMS(0),
mDebugDisableHWC(0),
mDebugDisableTransformHint(0),
mDebugInTransaction(0),
mLastTransactionTime(0),
mForceFullDamage(false),
mTimeStats(factory.createTimeStats()),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mRefreshStartTime(0),
mHasPoweredOff(false),
mNumLayers(0),
mVrFlingerRequestsDisplay(false),
mMainThreadId(std::this_thread::get_id()),
mCompositionEngine{getFactory().createCompositionEngine()} {}
SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory)
: SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
hasSyncFramework = running_without_sync_framework(true);
dispSyncPresentTimeOffset = present_time_offset_from_vsync_ns(0);
useHwcForRgbToYuv = force_hwc_copy_for_virtual_displays(false);
maxVirtualDisplaySize = max_virtual_display_dimension(0);
// Vr flinger is only enabled on Daydream ready devices.
useVrFlinger = use_vr_flinger(false);
maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
hasWideColorDisplay = has_wide_color_display(false);
useColorManagement = use_color_management(false);
mDefaultCompositionDataspace =
static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB));
mWideColorGamutCompositionDataspace =
static_cast<ui::Dataspace>(wcg_composition_dataspace(Dataspace::V0_SRGB));
defaultCompositionDataspace = mDefaultCompositionDataspace;
wideColorGamutCompositionDataspace = mWideColorGamutCompositionDataspace;
defaultCompositionPixelFormat = static_cast<ui::PixelFormat>(
default_composition_pixel_format(ui::PixelFormat::RGBA_8888));
wideColorGamutCompositionPixelFormat =
static_cast<ui::PixelFormat>(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888));
useContextPriority = use_context_priority(true);
auto tmpPrimaryDisplayOrientation = primary_display_orientation(
SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_0);
switch (tmpPrimaryDisplayOrientation) {
case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_90:
SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation90;
break;
case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_180:
SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation180;
break;
case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_270:
SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation270;
break;
default:
SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
break;
}
ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
mPrimaryDispSync =
getFactory().createDispSync("PrimaryDispSync", SurfaceFlinger::hasSyncFramework,
SurfaceFlinger::dispSyncPresentTimeOffset);
auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
if (surfaceFlingerConfigsServiceV1_2) {
surfaceFlingerConfigsServiceV1_2->getDisplayNativePrimaries(
[&](auto tmpPrimaries) {
memcpy(&mInternalDisplayPrimaries, &tmpPrimaries, sizeof(ui::DisplayPrimaries));
});
} else {
initDefaultDisplayNativePrimaries();
}
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
mGpuToCpuSupported = !atoi(value);
property_get("debug.sf.showupdates", value, "0");
mDebugRegion = atoi(value);
property_get("debug.sf.ddms", value, "0");
mDebugDDMS = atoi(value);
if (mDebugDDMS) {
if (!startDdmConnection()) {
// start failed, and DDMS debugging not enabled
mDebugDDMS = 0;
}
}
ALOGI_IF(mDebugRegion, "showupdates enabled");
ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
property_get("debug.sf.disable_backpressure", value, "0");
mPropagateBackpressure = !atoi(value);
ALOGI_IF(!mPropagateBackpressure, "Disabling backpressure propagation");
property_get("debug.sf.enable_hwc_vds", value, "0");
mUseHwcVirtualDisplays = atoi(value);
ALOGI_IF(mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
property_get("ro.sf.disable_triple_buffer", value, "0");
mLayerTripleBufferingDisabled = atoi(value);
ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
const size_t defaultListSize = MAX_LAYERS;
auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
property_get("debug.sf.use_scheduler", value, "0");
mUseScheduler = atoi(value);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
mVsyncModulator.setPhaseOffsets(early, gl, late);
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
// instead read after the boot animation
if (useTrebleTestingOverride()) {
// Without the override SurfaceFlinger cannot connect to HIDL
// services that are not listed in the manifests. Considered
// deriving the setting from the set service name, but it
// would be brittle if the name that's not 'default' is used
// for production purposes later on.
setenv("TREBLE_TESTING_OVERRIDE", "true", true);
}
}
void SurfaceFlinger::onFirstRef()
{
mEventQueue->init(this);
}
SurfaceFlinger::~SurfaceFlinger()
{
}
void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
{
// the window manager died on us. prepare its eulogy.
// restore initial conditions (default device unblank, etc)
initializeDisplays();
// restart the boot-animation
startBootAnim();
}
static sp<ISurfaceComposerClient> initClient(const sp<Client>& client) {
status_t err = client->initCheck();
if (err == NO_ERROR) {
return client;
}
return nullptr;
}
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
return initClient(new Client(this));
}
sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
bool secure)
{
class DisplayToken : public BBinder {
sp<SurfaceFlinger> flinger;
virtual ~DisplayToken() {
// no more references, this display must be terminated
Mutex::Autolock _l(flinger->mStateLock);
flinger->mCurrentState.displays.removeItem(this);
flinger->setTransactionFlags(eDisplayTransactionNeeded);
}
public:
explicit DisplayToken(const sp<SurfaceFlinger>& flinger)
: flinger(flinger) {
}
};
sp<BBinder> token = new DisplayToken(this);
Mutex::Autolock _l(mStateLock);
// Display ID is assigned when virtual display is allocated by HWC.
DisplayDeviceState state;
state.isSecure = secure;
state.displayName = displayName;
mCurrentState.displays.add(token, state);
mInterceptor->saveDisplayCreation(state);
return token;
}
void SurfaceFlinger::destroyDisplay(const sp<IBinder>& displayToken) {
Mutex::Autolock _l(mStateLock);
ssize_t index = mCurrentState.displays.indexOfKey(displayToken);
if (index < 0) {
ALOGE("destroyDisplay: Invalid display token %p", displayToken.get());
return;
}
const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
if (!state.isVirtual()) {
ALOGE("destroyDisplay called for non-virtual display");
return;
}
mInterceptor->saveDisplayDeletion(state.sequenceId);
mCurrentState.displays.removeItemsAt(index);
setTransactionFlags(eDisplayTransactionNeeded);
}
std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const {
Mutex::Autolock lock(mStateLock);
const auto internalDisplayId = getInternalDisplayIdLocked();
if (!internalDisplayId) {
return {};
}
std::vector<PhysicalDisplayId> displayIds;
displayIds.reserve(mPhysicalDisplayTokens.size());
displayIds.push_back(internalDisplayId->value);
for (const auto& [id, token] : mPhysicalDisplayTokens) {
if (id != *internalDisplayId) {
displayIds.push_back(id.value);
}
}
return displayIds;
}
sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
Mutex::Autolock lock(mStateLock);
return getPhysicalDisplayTokenLocked(DisplayId{displayId});
}
status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const {
if (!outGetColorManagement) {
return BAD_VALUE;
}
*outGetColorManagement = useColorManagement;
return NO_ERROR;
}
HWComposer& SurfaceFlinger::getHwComposer() const {
return mCompositionEngine->getHwComposer();
}
renderengine::RenderEngine& SurfaceFlinger::getRenderEngine() const {
return mCompositionEngine->getRenderEngine();
}
compositionengine::CompositionEngine& SurfaceFlinger::getCompositionEngine() const {
return *mCompositionEngine.get();
}
void SurfaceFlinger::bootFinished()
{
if (mStartPropertySetThread->join() != NO_ERROR) {
ALOGE("Join StartPropertySetThread failed!");
}
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
// wait patiently for the window manager death
const String16 name("window");
sp<IBinder> window(defaultServiceManager()->getService(name));
if (window != 0) {
window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
sp<IBinder> input(defaultServiceManager()->getService(
String16("inputflinger")));
if (input == nullptr) {
ALOGE("Failed to link to input service");
} else {
mInputFlinger = interface_cast<IInputFlinger>(input);
}
if (mVrFlinger) {
mVrFlinger->OnBootFinished();
}
// stop boot animation
// formerly we would just kill the process, but we now ask it to exit so it
// can choose where to stop the animation.
property_set("service.bootanim.exit", "1");
const int LOGTAG_SF_STOP_BOOTANIM = 60110;
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
postMessageAsync(new LambdaMessage([this] {
readPersistentProperties();
mBootStage = BootStage::FINISHED;
}));
}
uint32_t SurfaceFlinger::getNewTexture() {
{
std::lock_guard lock(mTexturePoolMutex);
if (!mTexturePool.empty()) {
uint32_t name = mTexturePool.back();
mTexturePool.pop_back();
ATRACE_INT("TexturePoolSize", mTexturePool.size());
return name;
}
// The pool was too small, so increase it for the future
++mTexturePoolSize;
}
// The pool was empty, so we need to get a new texture name directly using a
// blocking call to the main thread
uint32_t name = 0;
postMessageSync(new LambdaMessage([&]() { getRenderEngine().genTextures(1, &name); }));
return name;
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
postMessageAsync(new LambdaMessage([=] { getRenderEngine().deleteTextures(1, &texture); }));
}
// Do not call property_set on main thread which will be blocked by init
// Use StartPropertySetThread instead.
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset());
Mutex::Autolock _l(mStateLock);
auto resyncCallback = makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
// start the EventThread
if (mUseScheduler) {
mScheduler = getFactory().createScheduler(
[this](bool enabled) { setPrimaryVsyncEnabled(enabled); });
// TODO(b/113612090): Currently we assume that if scheduler is turned on, then the refresh
// rate is 90. Once b/122905403 is completed, this should be updated accordingly.
mPhaseOffsets->setRefreshRateType(
scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
mAppConnectionHandle =
mScheduler->createConnection("appConnection", mPhaseOffsets->getCurrentAppOffset(),
resyncCallback,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
mScheduler->createConnection("sfConnection", mPhaseOffsets->getCurrentSfOffset(),
resyncCallback, [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
mSfConnectionHandle.get());
} else {
mEventThreadSource =
std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
mPhaseOffsets->getCurrentAppOffset(), true, "app");
mEventThread =
std::make_unique<impl::EventThread>(mEventThreadSource.get(),
impl::EventThread::InterceptVSyncsCallback(),
"appEventThread");
mSfEventThreadSource =
std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
mPhaseOffsets->getCurrentSfOffset(), true, "sf");
mSFEventThread =
std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
[this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
},
"sfEventThread");
mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
}
// Get a RenderEngine for the given display / config (can't fail)
int32_t renderEngineFeature = 0;
renderEngineFeature |= (useColorManagement ?
renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0);
renderEngineFeature |= (useContextPriority ?
renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
// TODO(b/77156734): We need to stop casting and use HAL types when possible.
mCompositionEngine->setRenderEngine(
renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
renderEngineFeature));
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
"Starting with vr flinger active is not currently supported.");
mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName));
mCompositionEngine->getHwComposer().registerCallback(this, getBE().mComposerSequenceId);
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
const auto display = getDefaultDisplayDeviceLocked();
LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()),
"Internal display is disconnected.");
if (useVrFlinger) {
auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) {
// This callback is called from the vr flinger dispatch thread. We
// need to call signalTransaction(), which requires holding
// mStateLock when we're not on the main thread. Acquiring
// mStateLock from the vr flinger dispatch thread might trigger a
// deadlock in surface flinger (see b/66916578), so post a message
// to be handled on the main thread instead.
postMessageAsync(new LambdaMessage([=] {
ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
mVrFlingerRequestsDisplay = requestDisplay;
signalTransaction();
}));
};
mVrFlinger = dvr::VrFlinger::Create(getHwComposer().getComposer(),
getHwComposer()
.fromPhysicalDisplayId(*display->getId())
.value_or(0),
vrFlingerRequestDisplayCallback);
if (!mVrFlinger) {
ALOGE("Failed to start vrflinger");
}
}
mEventControlThread = getFactory().createEventControlThread(
[this](bool enabled) { setPrimaryVsyncEnabled(enabled); });
// initialize our drawing state
mDrawingState = mCurrentState;
// set initial conditions (e.g. unblank default device)
initializeDisplays();
getRenderEngine().primeCache();
// Inform native graphics APIs whether the present timestamp is supported:
const bool presentFenceReliable =
!getHwComposer().hasCapability(HWC2::Capability::PresentFenceIsNotReliable);
mStartPropertySetThread = getFactory().createStartPropertySetThread(presentFenceReliable);
if (mStartPropertySetThread->Start() != NO_ERROR) {
ALOGE("Run StartPropertySetThread failed!");
}
if (mUseScheduler) {
mScheduler->setExpiredIdleTimerCallback([this]() {
mPhaseOffsets->setRefreshRateType(
scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
mVsyncModulator.setPhaseOffsets(early, gl, late);
setRefreshRateTo(60.f /* fps */);
});
mScheduler->setResetIdleTimerCallback([this]() {
mPhaseOffsets->setRefreshRateType(
scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
mVsyncModulator.setPhaseOffsets(early, gl, late);
setRefreshRateTo(90.f /* fps */);
});
mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(
getHwComposer().getConfigs(*display->getId()));
}
ALOGV("Done initializing");
}
void SurfaceFlinger::readPersistentProperties() {
Mutex::Autolock _l(mStateLock);
char value[PROPERTY_VALUE_MAX];
property_get("persist.sys.sf.color_saturation", value, "1.0");
mGlobalSaturationFactor = atof(value);
updateColorMatrixLocked();
ALOGV("Saturation is set to %.2f", mGlobalSaturationFactor);
property_get("persist.sys.sf.native_mode", value, "0");
mDisplayColorSetting = static_cast<DisplayColorSetting>(atoi(value));
}
void SurfaceFlinger::startBootAnim() {
// Start boot animation service by setting a property mailbox
// if property setting thread is already running, Start() will be just a NOP
mStartPropertySetThread->Start();
// Wait until property was set
if (mStartPropertySetThread->join() != NO_ERROR) {
ALOGE("Join StartPropertySetThread failed!");
}
}
size_t SurfaceFlinger::getMaxTextureSize() const {
return getRenderEngine().getMaxTextureSize();
}
size_t SurfaceFlinger::getMaxViewportDims() const {
return getRenderEngine().getMaxViewportDims();
}
// ----------------------------------------------------------------------------
bool SurfaceFlinger::authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const {
Mutex::Autolock _l(mStateLock);
return authenticateSurfaceTextureLocked(bufferProducer);
}
bool SurfaceFlinger::authenticateSurfaceTextureLocked(
const sp<IGraphicBufferProducer>& bufferProducer) const {
sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer));
return mGraphicBufferProducerList.count(surfaceTextureBinder.get()) > 0;
}
status_t SurfaceFlinger::getSupportedFrameTimestamps(
std::vector<FrameEvent>* outSupported) const {
*outSupported = {
FrameEvent::REQUESTED_PRESENT,
FrameEvent::ACQUIRE,
FrameEvent::LATCH,
FrameEvent::FIRST_REFRESH_START,
FrameEvent::LAST_REFRESH_START,
FrameEvent::GPU_COMPOSITION_DONE,
FrameEvent::DEQUEUE_READY,
FrameEvent::RELEASE,
};
ConditionalLock _l(mStateLock,
std::this_thread::get_id() != mMainThreadId);
if (!getHwComposer().hasCapability(
HWC2::Capability::PresentFenceIsNotReliable)) {
outSupported->push_back(FrameEvent::DISPLAY_PRESENT);
}
return NO_ERROR;
}
status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken,
Vector<DisplayInfo>* configs) {
if (!displayToken || !configs) {
return BAD_VALUE;
}
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
const auto displayId = getPhysicalDisplayIdLocked(displayToken);
if (!displayId) {
return NAME_NOT_FOUND;
}
// TODO: Not sure if display density should handled by SF any longer
class Density {
static float getDensityFromProperty(char const* propName) {
char property[PROPERTY_VALUE_MAX];
float density = 0.0f;
if (property_get(propName, property, nullptr) > 0) {
density = strtof(property, nullptr);
}
return density;
}
public:
static float getEmuDensity() {
return getDensityFromProperty("qemu.sf.lcd_density"); }
static float getBuildDensity() {
return getDensityFromProperty("ro.sf.lcd_density"); }
};
configs->clear();
for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
DisplayInfo info = DisplayInfo();
float xdpi = hwConfig->getDpiX();
float ydpi = hwConfig->getDpiY();
info.w = hwConfig->getWidth();
info.h = hwConfig->getHeight();
// Default display viewport to display width and height
info.viewportW = info.w;
info.viewportH = info.h;
if (displayId == getInternalDisplayIdLocked()) {
// The density of the device is provided by a build property
float density = Density::getBuildDensity() / 160.0f;
if (density == 0) {
// the build doesn't provide a density -- this is wrong!
// use xdpi instead
ALOGE("ro.sf.lcd_density must be defined as a build property");
density = xdpi / 160.0f;
}
if (Density::getEmuDensity()) {
// if "qemu.sf.lcd_density" is specified, it overrides everything
xdpi = ydpi = density = Density::getEmuDensity();
density /= 160.0f;
}
info.density = density;
// TODO: this needs to go away (currently needed only by webkit)
const auto display = getDefaultDisplayDeviceLocked();
info.orientation = display ? display->getOrientation() : 0;
// This is for screenrecord
const Rect viewport = display->getViewport();
if (viewport.isValid()) {
info.viewportW = uint32_t(viewport.getWidth());
info.viewportH = uint32_t(viewport.getHeight());
}
} else {
// TODO: where should this value come from?
static const int TV_DENSITY = 213;
info.density = TV_DENSITY / 160.0f;
info.orientation = 0;
}
info.xdpi = xdpi;
info.ydpi = ydpi;
info.fps = 1e9 / hwConfig->getVsyncPeriod();
info.appVsyncOffset = mPhaseOffsets->getCurrentAppOffset();
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
// on the screen at time N, you must submit the buffer before
// (N - presentationDeadline).
//
// Normally it's one full refresh period (to give SF a chance to
// latch the buffer), but this can be reduced by configuring a
// DispSync offset. Any additional delays introduced by the hardware
// composer or panel must be accounted for here.
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
info.presentationDeadline =
hwConfig->getVsyncPeriod() - mPhaseOffsets->getCurrentSfOffset() + 1000000;
// All non-virtual displays are currently considered secure.
info.secure = true;
if (displayId == getInternalDisplayIdLocked() &&
primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
std::swap(info.w, info.h);
}
configs->push_back(info);
}
return NO_ERROR;
}
status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* stats) {
if (!stats) {
return BAD_VALUE;
}
if (mUseScheduler) {
mScheduler->getDisplayStatInfo(stats);
} else {
stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
}
return NO_ERROR;
}
int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) {
const auto display = getDisplayDevice(displayToken);
if (!display) {
ALOGE("getActiveConfig: Invalid display token %p", displayToken.get());
return BAD_VALUE;
}
return display->getActiveConfig();
}
status_t SurfaceFlinger::setActiveConfigAsync(const sp<IBinder>& displayToken, int mode) {
ATRACE_NAME("setActiveConfigAsync");
postMessageAsync(new LambdaMessage(
[=]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); }));
return NO_ERROR;
}
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
ATRACE_NAME("setActiveConfigSync");
postMessageSync(new LambdaMessage(
[&]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); }));
return NO_ERROR;
}
void SurfaceFlinger::setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) {
Vector<DisplayInfo> configs;
getDisplayConfigs(displayToken, &configs);
if (mode < 0 || mode >= static_cast<int>(configs.size())) {
ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size());
return;
}
const auto display = getDisplayDevice(displayToken);
if (!display) {
ALOGE("Attempt to set active config %d for invalid display token %p", mode,
displayToken.get());
return;
}
if (display->isVirtual()) {
ALOGW("Attempt to set active config %d for virtual display", mode);
return;
}
int currentDisplayPowerMode = display->getPowerMode();
if (currentDisplayPowerMode != HWC_POWER_MODE_NORMAL) {
// Don't change active config when in AoD.
return;
}
int currentMode = display->getActiveConfig();
if (mode == currentMode) {
// Don't update config if we are already running in the desired mode.
return;
}
if (mUseScheduler) {
mRefreshRateStats->setConfigMode(mode);
}
const auto displayId = display->getId();
LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(mode);
getHwComposer().setActiveConfig(*displayId, mode);
ATRACE_INT("ActiveConfigMode", mode);
resyncToHardwareVsync(true, getVsyncPeriod());
}
status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
Vector<ColorMode>* outColorModes) {
if (!displayToken || !outColorModes) {
return BAD_VALUE;
}
std::vector<ColorMode> modes;
{
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
const auto displayId = getPhysicalDisplayIdLocked(displayToken);
if (!displayId) {
return NAME_NOT_FOUND;
}
modes = getHwComposer().getColorModes(*displayId);
}
outColorModes->clear();
std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
return NO_ERROR;
}
status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayToken,
ui::DisplayPrimaries &primaries) {
if (!displayToken) {
return BAD_VALUE;
}
// Currently we only support this API for a single internal display.
if (getInternalDisplayToken() != displayToken) {
return BAD_VALUE;
}
memcpy(&primaries, &mInternalDisplayPrimaries, sizeof(ui::DisplayPrimaries));
return NO_ERROR;
}
ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) {
if (const auto display = getDisplayDevice(displayToken)) {
return display->getCompositionDisplay()->getState().colorMode;
}
return static_cast<ColorMode>(BAD_VALUE);
}
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
postMessageSync(new LambdaMessage([&] {
Vector<ColorMode> modes;
getDisplayColorModes(displayToken, &modes);
bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes);
if (mode < ColorMode::NATIVE || !exists) {
ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p",
decodeColorMode(mode).c_str(), mode, displayToken.get());
return;
}
const auto display = getDisplayDevice(displayToken);
if (!display) {
ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p",
decodeColorMode(mode).c_str(), mode, displayToken.get());
} else if (display->isVirtual()) {
ALOGW("Attempt to set active color mode %s (%d) for virtual display",
decodeColorMode(mode).c_str(), mode);
} else {
display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN,
RenderIntent::COLORIMETRIC);
}
}));
return NO_ERROR;
}
status_t SurfaceFlinger::clearAnimationFrameStats() {
Mutex::Autolock _l(mStateLock);
mAnimFrameTracker.clearStats();
return NO_ERROR;
}
status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
Mutex::Autolock _l(mStateLock);
mAnimFrameTracker.getStats(outStats);
return NO_ERROR;
}
status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& displayToken,
HdrCapabilities* outCapabilities) const {
Mutex::Autolock _l(mStateLock);
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("getHdrCapabilities: Invalid display token %p", displayToken.get());
return BAD_VALUE;
}
// At this point the DisplayDeivce should already be set up,
// meaning the luminance information is already queried from
// hardware composer and stored properly.
const HdrCapabilities& capabilities = display->getHdrCapabilities();
*outCapabilities = HdrCapabilities(capabilities.getSupportedHdrTypes(),
capabilities.getDesiredMaxLuminance(),
capabilities.getDesiredMaxAverageLuminance(),
capabilities.getDesiredMinLuminance());
return NO_ERROR;
}
status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken,
ui::PixelFormat* outFormat,
ui::Dataspace* outDataspace,
uint8_t* outComponentMask) const {
if (!outFormat || !outDataspace || !outComponentMask) {
return BAD_VALUE;
}
const auto display = getDisplayDevice(displayToken);
if (!display || !display->getId()) {
ALOGE("getDisplayedContentSamplingAttributes: Bad display token: %p", display.get());
return BAD_VALUE;
}
return getHwComposer().getDisplayedContentSamplingAttributes(*display->getId(), outFormat,
outDataspace, outComponentMask);
}
status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken,
bool enable, uint8_t componentMask,
uint64_t maxFrames) const {
const auto display = getDisplayDevice(displayToken);
if (!display || !display->getId()) {
ALOGE("setDisplayContentSamplingEnabled: Bad display token: %p", display.get());
return BAD_VALUE;
}
return getHwComposer().setDisplayContentSamplingEnabled(*display->getId(), enable,
componentMask, maxFrames);
}
status_t SurfaceFlinger::getDisplayedContentSample(const sp<IBinder>& displayToken,
uint64_t maxFrames, uint64_t timestamp,
DisplayedFrameStats* outStats) const {
const auto display = getDisplayDevice(displayToken);
if (!display || !display->getId()) {
ALOGE("getDisplayContentSample: Bad display token: %p", displayToken.get());
return BAD_VALUE;
}
return getHwComposer().getDisplayedContentSample(*display->getId(), maxFrames, timestamp,
outStats);
}
status_t SurfaceFlinger::getProtectedContentSupport(bool* outSupported) const {
if (!outSupported) {
return BAD_VALUE;
}
*outSupported = getRenderEngine().supportsProtectedContent();
return NO_ERROR;
}
status_t SurfaceFlinger::cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
int32_t* outBufferId) {
if (!outBufferId) {
return BAD_VALUE;
}
*outBufferId = mBufferStateLayerCache.add(token, buffer);
return NO_ERROR;
}
status_t SurfaceFlinger::uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) {
mBufferStateLayerCache.release(token, bufferId);
return NO_ERROR;
}
status_t SurfaceFlinger::isWideColorDisplay(const sp<IBinder>& displayToken,
bool* outIsWideColorDisplay) const {
if (!displayToken || !outIsWideColorDisplay) {
return BAD_VALUE;
}
Mutex::Autolock _l(mStateLock);
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
return BAD_VALUE;
}
*outIsWideColorDisplay = display->hasWideColorGamut();
return NO_ERROR;
}
status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
postMessageSync(new LambdaMessage([&] {
Mutex::Autolock _l(mStateLock);
if (mInjectVSyncs == enable) {
return;
}
auto resyncCallback = makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
// TODO(akrulec): Part of the Injector should be refactored, so that it
// can be passed to Scheduler.
if (enable) {
ALOGV("VSync Injections enabled");
if (mVSyncInjector.get() == nullptr) {
mVSyncInjector = std::make_unique<InjectVSyncSource>();
mInjectorEventThread = std::make_unique<
impl::EventThread>(mVSyncInjector.get(),
impl::EventThread::InterceptVSyncsCallback(),
"injEventThread");
}
mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback));
} else {
ALOGV("VSync Injections disabled");
mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
}
mInjectVSyncs = enable;
}));
return NO_ERROR;
}
status_t SurfaceFlinger::injectVSync(nsecs_t when) {
Mutex::Autolock _l(mStateLock);
if (!mInjectVSyncs) {
ALOGE("VSync Injections not enabled");
return BAD_VALUE;
}
if (mInjectVSyncs && mInjectorEventThread.get() != nullptr) {
ALOGV("Injecting VSync inside SurfaceFlinger");
mVSyncInjector->onInjectSyncEvent(when);
}
return NO_ERROR;
}
status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
NO_THREAD_SAFETY_ANALYSIS {
// Try to acquire a lock for 1s, fail gracefully
const status_t err = mStateLock.timedLock(s2ns(1));
const bool locked = (err == NO_ERROR);
if (!locked) {
ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err);
return TIMED_OUT;
}
outLayers->clear();
mCurrentState.traverseInZOrder([&](Layer* layer) {
outLayers->push_back(layer->getLayerDebugInfo());
});
mStateLock.unlock();
return NO_ERROR;
}
status_t SurfaceFlinger::getCompositionPreference(
Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
Dataspace* outWideColorGamutDataspace,
ui::PixelFormat* outWideColorGamutPixelFormat) const {
*outDataspace = mDefaultCompositionDataspace;
*outPixelFormat = defaultCompositionPixelFormat;
*outWideColorGamutDataspace = mWideColorGamutCompositionDataspace;
*outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat;
return NO_ERROR;
}
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource) {
auto resyncCallback = makeResyncCallback([this] {
Mutex::Autolock lock(mStateLock);
return getVsyncPeriod();
});
if (mUseScheduler) {
if (vsyncSource == eVsyncSourceSurfaceFlinger) {
return mScheduler->createDisplayEventConnection(mSfConnectionHandle, resyncCallback);
} else {
return mScheduler->createDisplayEventConnection(mAppConnectionHandle, resyncCallback);
}
} else {
if (vsyncSource == eVsyncSourceSurfaceFlinger) {
return mSFEventThread->createEventConnection(resyncCallback);
} else {
return mEventThread->createEventConnection(resyncCallback);
}
}
}
// ----------------------------------------------------------------------------
void SurfaceFlinger::waitForEvent() {
mEventQueue->waitMessage();
}
void SurfaceFlinger::signalTransaction() {
mEventQueue->invalidate();
}
void SurfaceFlinger::signalLayerUpdate() {
mEventQueue->invalidate();
}
void SurfaceFlinger::signalRefresh() {
mRefreshPending = true;
mEventQueue->refresh();
}
status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
nsecs_t reltime, uint32_t /* flags */) {
return mEventQueue->postMessage(msg, reltime);
}
status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
nsecs_t reltime, uint32_t /* flags */) {
status_t res = mEventQueue->postMessage(msg, reltime);
if (res == NO_ERROR) {
msg->wait();
}
return res;
}
void SurfaceFlinger::run() {
do {
waitForEvent();
} while (true);
}
nsecs_t SurfaceFlinger::getVsyncPeriod() const {
const auto displayId = getInternalDisplayIdLocked();
if (!displayId || !getHwComposer().isConnected(*displayId)) {
return 0;
}
const auto config = getHwComposer().getActiveConfig(*displayId);
return config ? config->getVsyncPeriod() : 0;
}
void SurfaceFlinger::enableHardwareVsync() {
Mutex::Autolock _l(mHWVsyncLock);
if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
mPrimaryDispSync->beginResync();
mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true;
}
}
void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
Mutex::Autolock _l(mHWVsyncLock);
if (makeAvailable) {
mHWVsyncAvailable = true;
// TODO(b/113612090): This is silly, but necessary evil until we turn on the flag for good.
if (mUseScheduler) {
mScheduler->makeHWSyncAvailable(true);
}
} else if (!mHWVsyncAvailable) {
// Hardware vsync is not currently available, so abort the resync
// attempt for now
return;
}
if (period <= 0) {
return;
}
if (mUseScheduler) {
mScheduler->setVsyncPeriod(period);
} else {
mPrimaryDispSync->reset();
mPrimaryDispSync->setPeriod(period);
if (!mPrimaryHWVsyncEnabled) {
mPrimaryDispSync->beginResync();
mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true;
}
}
}
void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
Mutex::Autolock _l(mHWVsyncLock);
if (mPrimaryHWVsyncEnabled) {
mEventControlThread->setVsyncEnabled(false);
mPrimaryDispSync->endResync();
mPrimaryHWVsyncEnabled = false;
}
if (makeUnavailable) {
mHWVsyncAvailable = false;
}
}
void SurfaceFlinger::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
const nsecs_t now = systemTime();
const nsecs_t last = lastResyncTime.exchange(now);
if (now - last > kIgnoreDelay) {
flinger.resyncToHardwareVsync(false, getVsyncPeriod());
}
}
void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
int64_t timestamp) {
ATRACE_NAME("SF onVsync");
Mutex::Autolock lock(mStateLock);
// Ignore any vsyncs from a previous hardware composer.
if (sequenceId != getBE().mComposerSequenceId) {
return;
}
if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) {
return;
}
if (hwcDisplayId != getHwComposer().getInternalHwcDisplayId()) {
// For now, we don't do anything with external display vsyncs.
return;
}
if (mUseScheduler) {
mScheduler->addResyncSample(timestamp);
} else {
bool needsHwVsync = false;
{ // Scope for the lock
Mutex::Autolock _l(mHWVsyncLock);
if (mPrimaryHWVsyncEnabled) {
needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
}
}
if (needsHwVsync) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
}
}
}
void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
*compositorTiming = getBE().mCompositorTiming;
}
// TODO(b/123715322): Fix thread safety.
void SurfaceFlinger::setRefreshRateTo(float newFps) NO_THREAD_SAFETY_ANALYSIS {
const auto display = getDefaultDisplayDeviceLocked();
if (!display || mBootStage != BootStage::FINISHED) {
return;
}
// TODO(b/113612090): There should be a message queue flush here. Because this esentially
// runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better
// manner, once the setActiveConfig is synchronous, and is executed at a known time in a
// refresh cycle.
// Don't do any updating if the current fps is the same as the new one.
const nsecs_t currentVsyncPeriod = getVsyncPeriod();
if (currentVsyncPeriod == 0) {
return;
}
// TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than
// floating numbers.
const float currentFps = 1e9 / currentVsyncPeriod;
if (std::abs(currentFps - newFps) <= 1) {
return;
}
auto configs = getHwComposer().getConfigs(*display->getId());
for (int i = 0; i < configs.size(); i++) {
const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
if (vsyncPeriod == 0) {
continue;
}
const float fps = 1e9 / vsyncPeriod;
// TODO(b/113612090): There should be a better way at determining which config
// has the right refresh rate.
if (std::abs(fps - newFps) <= 1) {
const sp<IBinder> token = display->getDisplayToken().promote();
LOG_ALWAYS_FATAL_IF(token == nullptr);
// This is posted in async function to avoid deadlock when getDisplayDevice
// requires mStateLock.
setActiveConfigAsync(token, i);
ATRACE_INT("FPS", newFps);
}
}
}
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
HWC2::Connection connection) {
ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
connection == HWC2::Connection::Connected ? "connected" : "disconnected");
// Ignore events that do not have the right sequenceId.
if (sequenceId != getBE().mComposerSequenceId) {
return;
}
// Only lock if we're not on the main thread. This function is normally
// called on a hwbinder thread, but for the primary display it's called on
// the main thread with the state lock already held, so don't attempt to
// acquire it here.
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection});
if (std::this_thread::get_id() == mMainThreadId) {
// Process all pending hot plug events immediately if we are on the main thread.
processDisplayHotplugEventsLocked();
}
setTransactionFlags(eDisplayTransactionNeeded);
}
void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDisplayId*/) {
Mutex::Autolock lock(mStateLock);
if (sequenceId != getBE().mComposerSequenceId) {
return;
}
repaintEverythingForHWC();
}
void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) {
ATRACE_CALL();
Mutex::Autolock lock(mStateLock);
if (const auto displayId = getInternalDisplayIdLocked()) {
getHwComposer().setVsyncEnabled(*displayId,
enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
}
}
// Note: it is assumed the caller holds |mStateLock| when this is called
void SurfaceFlinger::resetDisplayState() {
if (mUseScheduler) {
mScheduler->disableHardwareVsync(true);
} else {
disableHardwareVsync(true);
}
// Clear the drawing state so that the logic inside of
// handleTransactionLocked will fire. It will determine the delta between
// mCurrentState and mDrawingState and re-apply all changes when we make the
// transition.
mDrawingState.displays.clear();
mDisplays.clear();
}
void SurfaceFlinger::updateVrFlinger() {
if (!mVrFlinger)
return;
bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
if (vrFlingerRequestsDisplay == getHwComposer().isUsingVrComposer()) {
return;
}
if (vrFlingerRequestsDisplay && !getHwComposer().getComposer()->isRemote()) {
ALOGE("Vr flinger is only supported for remote hardware composer"
" service connections. Ignoring request to transition to vr"
" flinger.");
mVrFlingerRequestsDisplay = false;
return;
}
Mutex::Autolock _l(mStateLock);
sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
LOG_ALWAYS_FATAL_IF(!display);
const int currentDisplayPowerMode = display->getPowerMode();
// This DisplayDevice will no longer be relevant once resetDisplayState() is
// called below. Clear the reference now so we don't accidentally use it
// later.
display.clear();
if (!vrFlingerRequestsDisplay) {
mVrFlinger->SeizeDisplayOwnership();
}
resetDisplayState();
// Delete the current instance before creating the new one
mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mCompositionEngine->setHwComposer(getFactory().createHWComposer(
vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName));
getHwComposer().registerCallback(this, ++getBE().mComposerSequenceId);
LOG_ALWAYS_FATAL_IF(!getHwComposer().getComposer()->isRemote(),
"Switched to non-remote hardware composer");
if (vrFlingerRequestsDisplay) {
mVrFlinger->GrantDisplayOwnership();
}
mVisibleRegionsDirty = true;
invalidateHwcGeometry();
// Re-enable default display.
display = getDefaultDisplayDeviceLocked();
LOG_ALWAYS_FATAL_IF(!display);
setPowerModeInternal(display, currentDisplayPowerMode);
// Reset the timing values to account for the period of the swapped in HWC
const nsecs_t vsyncPeriod = getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
// The present fences returned from vr_hwc are not an accurate
// representation of vsync times.
if (mUseScheduler) {
mScheduler->setIgnorePresentFences(getHwComposer().isUsingVrComposer() ||
!hasSyncFramework);
} else {
mPrimaryDispSync->setIgnorePresentFences(getHwComposer().isUsingVrComposer() ||
!hasSyncFramework);
}
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
setCompositorTimingSnapped(stats, 0);
resyncToHardwareVsync(false, vsyncPeriod);
mRepaintEverything = true;
setTransactionFlags(eDisplayTransactionNeeded);
}
void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
if (mUseScheduler) {
// This call is made each time SF wakes up and creates a new frame.
mScheduler->incrementFrameCounter();
}
bool frameMissed = !mHadClientComposition &&
mPreviousPresentFence != Fence::NO_FENCE &&
(mPreviousPresentFence->getSignalTime() ==
Fence::SIGNAL_TIME_PENDING);
mFrameMissedCount += frameMissed;
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
if (frameMissed) {
mTimeStats->incrementMissedFrames();
if (mPropagateBackpressure) {
signalLayerUpdate();
break;
}
}
// Now that we're going to make it to the handleMessageTransaction()
// call below it's safe to call updateVrFlinger(), which will
// potentially trigger a display handoff.
updateVrFlinger();
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
refreshNeeded |= mRepaintEverything;
if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
// Signal a refresh if a transaction modified the window state,
// a new buffer was latched, or if HWC has requested a full
// repaint
signalRefresh();
}
break;
}
case MessageQueue::REFRESH: {
handleMessageRefresh();
break;
}
}
}
bool SurfaceFlinger::handleMessageTransaction() {
uint32_t transactionFlags = peekTransactionFlags();
// Apply any ready transactions in the queues if there are still transactions that have not been
// applied, wake up during the next vsync period and check again
bool transactionNeeded = false;
if (!flushTransactionQueues()) {
transactionNeeded = true;
}
if (transactionFlags) {
handleTransaction(transactionFlags);
}
if (transactionNeeded) {
setTransactionFlags(eTransactionNeeded);
}
return transactionFlags;
}
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
mRefreshPending = false;
const bool repaintEverything = mRepaintEverything.exchange(false);
preComposition();
rebuildLayerStacks();
calculateWorkingSet();
for (const auto& [token, display] : mDisplays) {
beginFrame(display);
prepareFrame(display);
doDebugFlashRegions(display, repaintEverything);
doComposition(display, repaintEverything);
}
doTracing("handleRefresh");
logLayerStats();
postFrame();
postComposition();
mHadClientComposition = false;
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
const auto displayId = display->getId();
mHadClientComposition =
mHadClientComposition || getHwComposer().hasClientComposition(displayId);
}
// Setup RenderEngine sync fences if native sync is supported.
if (getRenderEngine().useNativeFenceSync()) {
if (mHadClientComposition) {
base::unique_fd flushFence(getRenderEngine().flush());
ALOGE_IF(flushFence < 0, "Failed to flush RenderEngine!");
getBE().flushFence = new Fence(std::move(flushFence));
} else {
// Cleanup for hygiene.
getBE().flushFence = Fence::NO_FENCE;
}
}
mVsyncModulator.onRefreshed(mHadClientComposition);
getBE().mEndOfFrameCompositionInfo = std::move(getBE().mCompositionInfo);
for (const auto& [token, display] : mDisplays) {
for (auto& compositionInfo : getBE().mEndOfFrameCompositionInfo[token]) {
compositionInfo.hwc.hwcLayer = nullptr;
}
}
mLayersWithQueuedFrames.clear();
}
bool SurfaceFlinger::handleMessageInvalidate() {
ATRACE_CALL();
return handlePageFlip();
}
void SurfaceFlinger::calculateWorkingSet() {
ATRACE_CALL();
ALOGV(__FUNCTION__);
// build the h/w work list
if (CC_UNLIKELY(mGeometryInvalid)) {
mGeometryInvalid = false;
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
const auto displayId = display->getId();
if (!displayId) {
continue;
}
const Vector<sp<Layer>>& currentLayers = displayDevice->getVisibleLayersSortedByZ();
for (size_t i = 0; i < currentLayers.size(); i++) {
const auto& layer = currentLayers[i];
if (!layer->hasHwcLayer(*displayId)) {
if (!layer->createHwcLayer(&getHwComposer(), *displayId)) {
layer->forceClientComposition(*displayId);
continue;
}
}
layer->setGeometry(displayDevice, i);
if (mDebugDisableHWC || mDebugRegion) {
layer->forceClientComposition(*displayId);
}
}
}
}
// Set the per-frame data
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
const auto displayId = display->getId();
if (!displayId) {
continue;
}
auto* profile = display->getDisplayColorProfile();
if (mDrawingState.colorMatrixChanged) {
display->setColorTransform(mDrawingState.colorMatrix);
}
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
if (layer->isHdrY410()) {
layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
!profile->hasHDR10Support()) {
layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
!profile->hasHLGSupport()) {
layer->forceClientComposition(*displayId);
}
// TODO(b/111562338) remove when composer 2.3 is shipped.
if (layer->hasColorTransform()) {
layer->forceClientComposition(*displayId);
}
if (layer->getRoundedCornerState().radius > 0.0f) {
layer->forceClientComposition(*displayId);
}
if (layer->getForceClientComposition(*displayId)) {
ALOGV("[%s] Requesting Client composition", layer->getName().string());
layer->setCompositionType(*displayId, HWC2::Composition::Client);
continue;
}
const auto& displayState = display->getState();
layer->setPerFrameData(*displayId, displayState.transform, displayState.viewport,
displayDevice->getSupportedPerFrameMetadata());
}
if (useColorManagement) {
ColorMode colorMode;
Dataspace dataSpace;
RenderIntent renderIntent;
pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
display->setColorMode(colorMode, dataSpace, renderIntent);
}
}
mDrawingState.colorMatrixChanged = false;
for (const auto& [token, display] : mDisplays) {
for (auto& layer : display->getVisibleLayersSortedByZ()) {
const auto displayId = display->getId();
layer->getBE().compositionInfo.compositionType = layer->getCompositionType(displayId);
if (displayId) {
if (!layer->setHwcLayer(*displayId)) {
ALOGV("Need to create HWCLayer for %s", layer->getName().string());
}
layer->getBE().compositionInfo.hwc.displayId = *displayId;
}
getBE().mCompositionInfo[token].push_back(layer->getBE().compositionInfo);
layer->getBE().compositionInfo.hwc.hwcLayer = nullptr;
}
}
}
void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& displayDevice,
bool repaintEverything) {
auto display = displayDevice->getCompositionDisplay();
const auto& displayState = display->getState();
// is debugging enabled
if (CC_LIKELY(!mDebugRegion))
return;
if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
if (!dirtyRegion.isEmpty()) {
base::unique_fd readyFence;
// redraw the whole screen
doComposeSurfaces(displayDevice, dirtyRegion, &readyFence);
display->getRenderSurface()->queueBuffer(std::move(readyFence));
}
}
postFramebuffer(displayDevice);
if (mDebugRegion > 1) {
usleep(mDebugRegion * 1000);
}
prepareFrame(displayDevice);
}
void SurfaceFlinger::doTracing(const char* where) {
ATRACE_CALL();
ATRACE_NAME(where);
if (CC_UNLIKELY(mTracing.isEnabled())) {
mTracing.traceLayers(where, dumpProtoInfo(LayerVector::StateSet::Drawing));
}
}
void SurfaceFlinger::logLayerStats() {
ATRACE_CALL();
if (CC_UNLIKELY(mLayerStats.isEnabled())) {
for (const auto& [token, display] : mDisplays) {
if (display->isPrimary()) {
mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(*display));
return;
}
}
ALOGE("logLayerStats: no primary display");
}
}
void SurfaceFlinger::preComposition()
{
ATRACE_CALL();
ALOGV("preComposition");
mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
bool needExtraInvalidate = false;
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (layer->onPreComposition(mRefreshStartTime)) {
needExtraInvalidate = true;
}
});
if (needExtraInvalidate) {
signalLayerUpdate();
}
}
void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
std::shared_ptr<FenceTime>& presentFenceTime) {
// Update queue of past composite+present times and determine the
// most recently known composite to present latency.
getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime});
nsecs_t compositeToPresentLatency = -1;
while (!getBE().mCompositePresentTimes.empty()) {
SurfaceFlingerBE::CompositePresentTime& cpt = getBE().mCompositePresentTimes.front();
// Cached values should have been updated before calling this method,
// which helps avoid duplicate syscalls.
nsecs_t displayTime = cpt.display->getCachedSignalTime();
if (displayTime == Fence::SIGNAL_TIME_PENDING) {
break;
}
compositeToPresentLatency = displayTime - cpt.composite;
getBE().mCompositePresentTimes.pop();
}
// Don't let mCompositePresentTimes grow unbounded, just in case.
while (getBE().mCompositePresentTimes.size() > 16) {
getBE().mCompositePresentTimes.pop();
}
setCompositorTimingSnapped(stats, compositeToPresentLatency);
}
void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats,
nsecs_t compositeToPresentLatency) {
// Integer division and modulo round toward 0 not -inf, so we need to
// treat negative and positive offsets differently.
nsecs_t idealLatency = (mPhaseOffsets->getCurrentSfOffset() > 0)
? (stats.vsyncPeriod - (mPhaseOffsets->getCurrentSfOffset() % stats.vsyncPeriod))
: ((-mPhaseOffsets->getCurrentSfOffset()) % stats.vsyncPeriod);
// Just in case mPhaseOffsets->getCurrentSfOffset() == -vsyncInterval.
if (idealLatency <= 0) {
idealLatency = stats.vsyncPeriod;
}
// Snap the latency to a value that removes scheduling jitter from the
// composition and present times, which often have >1ms of jitter.
// Reducing jitter is important if an app attempts to extrapolate
// something (such as user input) to an accurate diasplay time.
// Snapping also allows an app to precisely calculate mPhaseOffsets->getCurrentSfOffset()
// with (presentLatency % interval).
nsecs_t bias = stats.vsyncPeriod / 2;
int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
nsecs_t snappedCompositeToPresentLatency =
(extraVsyncs > 0) ? idealLatency + (extraVsyncs * stats.vsyncPeriod) : idealLatency;
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency;
getBE().mCompositorTiming.interval = stats.vsyncPeriod;
getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
}
// debug patch for b/119477596 - add stack guards to catch stack
// corruptions and disable clang optimizations.
// The code below is temporary and planned to be removed once stack
// corruptions are found.
#pragma clang optimize off
class StackGuard {
public:
StackGuard(const char* name, const char* func, int line) {
guarders.reserve(MIN_CAPACITY);
guarders.push_back({this, name, func, line});
validate();
}
~StackGuard() {
for (auto i = guarders.end() - 1; i >= guarders.begin(); --i) {
if (i->guard == this) {
guarders.erase(i);
break;
}
}
}
static void validate() {
for (const auto& guard : guarders) {
if (guard.guard->cookie != COOKIE_VALUE) {
ALOGE("%s:%d: Stack corruption detected at %s", guard.func, guard.line, guard.name);
CallStack stack(LOG_TAG);
abort();
}
}
}
private:
uint64_t cookie = COOKIE_VALUE;
static constexpr uint64_t COOKIE_VALUE = 0xc0febebedeadbeef;
static constexpr size_t MIN_CAPACITY = 16;
struct GuarderElement {
StackGuard* guard;
const char* name;
const char* func;
int line;
};
static std::vector<GuarderElement> guarders;
};
std::vector<StackGuard::GuarderElement> StackGuard::guarders;
#define DEFINE_STACK_GUARD(__n) StackGuard __n##StackGuard(#__n, __FUNCTION__, __LINE__);
#define ASSERT_ON_STACK_GUARD() StackGuard::validate();
void SurfaceFlinger::postComposition()
{
DEFINE_STACK_GUARD(begin);
ATRACE_CALL();
ALOGV("postComposition");
// Release any buffers which were replaced this frame
nsecs_t dequeueReadyTime = systemTime();
DEFINE_STACK_GUARD(dequeueReadyTime);
for (auto& layer : mLayersWithQueuedFrames) {
layer->releasePendingBuffer(dequeueReadyTime);
}
ASSERT_ON_STACK_GUARD();
// |mStateLock| not needed as we are on the main thread
const auto displayDevice = getDefaultDisplayDeviceLocked();
DEFINE_STACK_GUARD(displayDevice);
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
DEFINE_STACK_GUARD(glCompositionDoneFenceTime);
if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
glCompositionDoneFenceTime =
std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
->getRenderSurface()
->getClientTargetAcquireFence());
getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
} else {
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
ASSERT_ON_STACK_GUARD();
getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFence = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId())
: Fence::NO_FENCE;
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
DEFINE_STACK_GUARD(presentFenceTime);
getBE().mDisplayTimeline.push(presentFenceTime);
DisplayStatInfo stats;
DEFINE_STACK_GUARD(stats);
if (mUseScheduler) {
mScheduler->getDisplayStatInfo(&stats);
} else {
stats.vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
stats.vsyncPeriod = mPrimaryDispSync->getPeriod();
}
ASSERT_ON_STACK_GUARD();
// We use the mRefreshStartTime which might be sampled a little later than
// when we started doing work for this frame, but that should be okay
// since updateCompositorTiming has snapping logic.
updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime);
CompositorTiming compositorTiming;
DEFINE_STACK_GUARD(compositorTiming);
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
DEFINE_STACK_GUARD(lock);
compositorTiming = getBE().mCompositorTiming;
ASSERT_ON_STACK_GUARD();
}
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool frameLatched =
layer->onPostComposition(displayDevice->getId(), glCompositionDoneFenceTime,
presentFenceTime, compositorTiming);
DEFINE_STACK_GUARD(frameLatched);
if (frameLatched) {
recordBufferingStats(layer->getName().string(),
layer->getOccupancyHistory(false));
}
ASSERT_ON_STACK_GUARD();
});
if (presentFenceTime->isValid()) {
ASSERT_ON_STACK_GUARD();
if (mUseScheduler) {
mScheduler->addPresentFence(presentFenceTime);
ASSERT_ON_STACK_GUARD();
} else {
if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
}
ASSERT_ON_STACK_GUARD();
}
}
if (!hasSyncFramework) {
if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
displayDevice->isPoweredOn()) {
if (mUseScheduler) {
mScheduler->enableHardwareVsync();
} else {
enableHardwareVsync();
}
}
}
ASSERT_ON_STACK_GUARD();
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
ASSERT_ON_STACK_GUARD();
} else if (displayDevice && getHwComposer().isConnected(*displayDevice->getId())) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
const nsecs_t presentTime =
getHwComposer().getRefreshTimestamp(*displayDevice->getId());
DEFINE_STACK_GUARD(presentTime);
mAnimFrameTracker.setActualPresentTime(presentTime);
ASSERT_ON_STACK_GUARD();
}
mAnimFrameTracker.advanceFrame();
}
ASSERT_ON_STACK_GUARD();
mTimeStats->incrementTotalFrames();
if (mHadClientComposition) {
mTimeStats->incrementClientCompositionFrames();
}
ASSERT_ON_STACK_GUARD();
mTimeStats->setPresentFenceGlobal(presentFenceTime);
ASSERT_ON_STACK_GUARD();
if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
!displayDevice->isPoweredOn()) {
return;
}
nsecs_t currentTime = systemTime();
DEFINE_STACK_GUARD(currentTime);
if (mHasPoweredOff) {
mHasPoweredOff = false;
} else {
nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
DEFINE_STACK_GUARD(elapsedTime);
size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod);
DEFINE_STACK_GUARD(numPeriods);
if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
getBE().mFrameBuckets[numPeriods] += elapsedTime;
} else {
getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] += elapsedTime;
}
getBE().mTotalTime += elapsedTime;
ASSERT_ON_STACK_GUARD();
}
getBE().mLastSwapTime = currentTime;
ASSERT_ON_STACK_GUARD();
{
std::lock_guard lock(mTexturePoolMutex);
DEFINE_STACK_GUARD(lock);
const size_t refillCount = mTexturePoolSize - mTexturePool.size();
DEFINE_STACK_GUARD(refillCount);
if (refillCount > 0) {
const size_t offset = mTexturePool.size();
mTexturePool.resize(mTexturePoolSize);
getRenderEngine().genTextures(refillCount, mTexturePool.data() + offset);
ATRACE_INT("TexturePoolSize", mTexturePool.size());
}
ASSERT_ON_STACK_GUARD();
}
mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
mTransactionCompletedThread.sendCallbacks();
ASSERT_ON_STACK_GUARD();
}
#pragma clang optimize on // b/119477596
void SurfaceFlinger::rebuildLayerStacks() {
ATRACE_CALL();
ALOGV("rebuildLayerStacks");
// We need to clear these out now as these may be holding on to a
// HWC2::Layer reference at the same time as the LayerBE::HWCInfo structure
// also holds a reference. When the set of visible layers is recomputed,
// some layers may be destroyed if the only thing keeping them alive was
// that list of visible layers associated with each display. The layer
// destruction code asserts that the HWC2::Layer is properly destroyed, but
// that doesn't happen if SurfaceFlingerBE::mCompositionInfo keeps it alive.
for (const auto& [token, display] : mDisplays) {
getBE().mCompositionInfo[token].clear();
}
// rebuild the visible layer list per screen
if (CC_UNLIKELY(mVisibleRegionsDirty)) {
ATRACE_NAME("rebuildLayerStacks VR Dirty");
mVisibleRegionsDirty = false;
invalidateHwcGeometry();
for (const auto& pair : mDisplays) {
const auto& displayDevice = pair.second;
auto display = displayDevice->getCompositionDisplay();
const auto& displayState = display->getState();
Region opaqueRegion;
Region dirtyRegion;
Vector<sp<Layer>> layersSortedByZ;
Vector<sp<Layer>> layersNeedingFences;
const ui::Transform& tr = displayState.transform;
const Rect bounds = displayState.bounds;
if (displayState.isEnabled) {
computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool hwcLayerDestroyed = false;
const auto displayId = displayDevice->getId();
if (display->belongsInOutput(layer->getLayerStack(),
layer->getPrimaryDisplayOnly())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
if (!drawRegion.isEmpty()) {
layersSortedByZ.add(layer);
} else {
// Clear out the HWC layer if this layer was
// previously visible, but no longer is
hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
}
} else {
// WM changes display->layerStack upon sleep/awake.
// Here we make sure we delete the HWC layers even if
// WM changed their layer stack.
hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
}
// If a layer is not going to get a release fence because
// it is invisible, but it is also going to release its
// old buffer, add it to the list of layers needing
// fences.
if (hwcLayerDestroyed) {
auto found = std::find(mLayersWithQueuedFrames.cbegin(),
mLayersWithQueuedFrames.cend(), layer);
if (found != mLayersWithQueuedFrames.cend()) {
layersNeedingFences.add(layer);
}
}
});
}
displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
displayDevice->setLayersNeedingFences(layersNeedingFences);
Region undefinedRegion{bounds};
undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
display->editState().undefinedRegion = undefinedRegion;
display->editState().dirtyRegion.orSelf(dirtyRegion);
}
}
}
// Returns a data space that fits all visible layers. The returned data space
// can only be one of
// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
// - Dataspace::DISPLAY_P3
// - Dataspace::DISPLAY_BT2020
// The returned HDR data space is one of
// - Dataspace::UNKNOWN
// - Dataspace::BT2020_HLG
// - Dataspace::BT2020_PQ
Dataspace SurfaceFlinger::getBestDataspace(const sp<const DisplayDevice>& display,
Dataspace* outHdrDataSpace) const {
Dataspace bestDataSpace = Dataspace::V0_SRGB;
*outHdrDataSpace = Dataspace::UNKNOWN;
for (const auto& layer : display->getVisibleLayersSortedByZ()) {
switch (layer->getDataSpace()) {
case Dataspace::V0_SCRGB:
case Dataspace::V0_SCRGB_LINEAR:
case Dataspace::BT2020:
case Dataspace::BT2020_ITU:
case Dataspace::BT2020_LINEAR:
case Dataspace::DISPLAY_BT2020:
bestDataSpace = Dataspace::DISPLAY_BT2020;
break;
case Dataspace::DISPLAY_P3:
bestDataSpace = Dataspace::DISPLAY_P3;
break;
case Dataspace::BT2020_PQ:
case Dataspace::BT2020_ITU_PQ:
*outHdrDataSpace = Dataspace::BT2020_PQ;
break;
case Dataspace::BT2020_HLG:
case Dataspace::BT2020_ITU_HLG:
// When there's mixed PQ content and HLG content, we set the HDR
// data space to be BT2020_PQ and convert HLG to PQ.
if (*outHdrDataSpace == Dataspace::UNKNOWN) {
*outHdrDataSpace = Dataspace::BT2020_HLG;
}
break;
default:
break;
}
}
return bestDataSpace;
}
// Pick the ColorMode / Dataspace for the display device.
void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& display, ColorMode* outMode,
Dataspace* outDataSpace, RenderIntent* outRenderIntent) const {
if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {
*outMode = ColorMode::NATIVE;
*outDataSpace = Dataspace::UNKNOWN;
*outRenderIntent = RenderIntent::COLORIMETRIC;
return;
}
Dataspace hdrDataSpace;
Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace);
auto* profile = display->getCompositionDisplay()->getDisplayColorProfile();
// respect hdrDataSpace only when there is no legacy HDR support
const bool isHdr =
hdrDataSpace != Dataspace::UNKNOWN && !profile->hasLegacyHdrSupport(hdrDataSpace);
if (isHdr) {
bestDataSpace = hdrDataSpace;
}
RenderIntent intent;
switch (mDisplayColorSetting) {
case DisplayColorSetting::MANAGED:
case DisplayColorSetting::UNMANAGED:
intent = isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC;
break;
case DisplayColorSetting::ENHANCED:
intent = isHdr ? RenderIntent::TONE_MAP_ENHANCE : RenderIntent::ENHANCE;
break;
default: // vendor display color setting
intent = static_cast<RenderIntent>(mDisplayColorSetting);
break;
}
profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
}
void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& displayDevice) {
auto display = displayDevice->getCompositionDisplay();
const auto& displayState = display->getState();
bool dirty = !display->getDirtyRegion(false).isEmpty();
bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
// If nothing has changed (!dirty), don't recompose.
// If something changed, but we don't currently have any visible layers,
// and didn't when we last did a composition, then skip it this time.
// The second rule does two things:
// - When all layers are removed from a display, we'll emit one black
// frame, then nothing more until we get new layers.
// - When a display is created with a private layer stack, we won't
// emit any black frames until a layer is added to the layer stack.
bool mustRecompose = dirty && !(empty && wasEmpty);
const char flagPrefix[] = {'-', '+'};
static_cast<void>(flagPrefix);
ALOGV_IF(displayDevice->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
__FUNCTION__, mustRecompose ? "doing" : "skipping",
displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty],
flagPrefix[wasEmpty]);
display->getRenderSurface()->beginFrame(mustRecompose);
if (mustRecompose) {
display->editState().lastCompositionHadVisibleLayers = !empty;
}
}
void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& displayDevice) {
auto display = displayDevice->getCompositionDisplay();
const auto& displayState = display->getState();
if (!displayState.isEnabled) {
return;
}
status_t result = display->getRenderSurface()->prepareFrame(
getBE().mCompositionInfo[displayDevice->getDisplayToken()]);
ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
displayDevice->getDebugName().c_str(), result, strerror(-result));
}
void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool repaintEverything) {
ATRACE_CALL();
ALOGV("doComposition");
auto display = displayDevice->getCompositionDisplay();
const auto& displayState = display->getState();
if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
// repaint the framebuffer (if needed)
doDisplayComposition(displayDevice, dirtyRegion);
display->editState().dirtyRegion.clear();
display->getRenderSurface()->flip();
}
postFramebuffer(displayDevice);
}
void SurfaceFlinger::postFrame()
{
// |mStateLock| not needed as we are on the main thread
const auto display = getDefaultDisplayDeviceLocked();
if (display && getHwComposer().isConnected(*display->getId())) {
uint32_t flipCount = display->getPageFlipCount();
if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
logFrameStats();
}
}
}
void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& displayDevice) {
ATRACE_CALL();
ALOGV("postFramebuffer");
auto display = displayDevice->getCompositionDisplay();
const auto& displayState = display->getState();
const auto displayId = display->getId();
mPostFramebufferTime = systemTime();
if (displayState.isEnabled) {
if (displayId) {
getHwComposer().presentAndGetReleaseFences(*displayId);
}
display->getRenderSurface()->onPresentDisplayCompleted();
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
sp<Fence> releaseFence = Fence::NO_FENCE;
// The layer buffer from the previous frame (if any) is released
// by HWC only when the release fence from this frame (if any) is
// signaled. Always get the release fence from HWC first.
if (displayId && layer->hasHwcLayer(*displayId)) {
releaseFence = getHwComposer().getLayerReleaseFence(*displayId,
layer->getHwcLayer(*displayId));
}
// If the layer was client composited in the previous frame, we
// need to merge with the previous client target acquire fence.
// Since we do not track that, always merge with the current
// client target acquire fence when it is available, even though
// this is suboptimal.
if (layer->getCompositionType(displayId) == HWC2::Composition::Client) {
releaseFence =
Fence::merge("LayerRelease", releaseFence,
display->getRenderSurface()->getClientTargetAcquireFence());
}
layer->getBE().onLayerDisplayed(releaseFence);
}
// We've got a list of layers needing fences, that are disjoint with
// display->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
if (!displayDevice->getLayersNeedingFences().isEmpty()) {
sp<Fence> presentFence =
displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
for (auto& layer : displayDevice->getLayersNeedingFences()) {
layer->getBE().onLayerDisplayed(presentFence);
}
}
if (displayId) {
getHwComposer().clearReleaseFences(*displayId);
}
}
}
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
// here we keep a copy of the drawing state (that is the state that's
// going to be overwritten by handleTransactionLocked()) outside of
// mStateLock so that the side-effects of the State assignment
// don't happen with mStateLock held (which can cause deadlocks).
State drawingState(mDrawingState);
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
mDebugInTransaction = now;
// Here we're guaranteed that some transaction flags are set
// so we can call handleTransactionLocked() unconditionally.
// We call getTransactionFlags(), which will also clear the flags,
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
mVsyncModulator.onTransactionHandled();
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
// here the transaction has been committed
}
void SurfaceFlinger::processDisplayHotplugEventsLocked() {
for (const auto& event : mPendingHotplugEvents) {
const std::optional<DisplayIdentificationInfo> info =
getHwComposer().onHotplug(event.hwcDisplayId, event.connection);
if (!info) {
continue;
}
if (event.connection == HWC2::Connection::Connected) {
if (!mPhysicalDisplayTokens.count(info->id)) {
ALOGV("Creating display %s", to_string(info->id).c_str());
mPhysicalDisplayTokens[info->id] = new BBinder();
DisplayDeviceState state;
state.displayId = info->id;
state.isSecure = true; // All physical displays are currently considered secure.
state.displayName = info->name;
mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
mInterceptor->saveDisplayCreation(state);
}
} else {
ALOGV("Removing display %s", to_string(info->id).c_str());
ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]);
if (index >= 0) {
const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
mInterceptor->saveDisplayDeletion(state.sequenceId);
mCurrentState.displays.removeItemsAt(index);
}
mPhysicalDisplayTokens.erase(info->id);
}
processDisplayChangesLocked();
}
mPendingHotplugEvents.clear();
}
void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle, displayId, connected);
mScheduler->hotplugReceived(mSfConnectionHandle, displayId, connected);
} else {
mEventThread->onHotplugReceived(displayId, connected);
mSFEventThread->onHotplugReceived(displayId, connected);
}
}
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
creationArgs.sequenceId = state.sequenceId;
creationArgs.isVirtual = state.isVirtual();
creationArgs.isSecure = state.isSecure;
creationArgs.displaySurface = dispSurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
creationArgs.isPrimary = isInternalDisplay;
if (useColorManagement && displayId) {
std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
for (ColorMode colorMode : modes) {
if (isWideColorMode(colorMode)) {
creationArgs.hasWideColorGamut = true;
}
std::vector<RenderIntent> renderIntents =
getHwComposer().getRenderIntents(*displayId, colorMode);
creationArgs.hwcColorModes.emplace(colorMode, renderIntents);
}
}
if (displayId) {
getHwComposer().getHdrCapabilities(*displayId, &creationArgs.hdrCapabilities);
creationArgs.supportedPerFrameMetadata =
getHwComposer().getSupportedPerFrameMetadata(*displayId);
}