summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/SurfaceFlinger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp2246
1 files changed, 1511 insertions, 735 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cf1d3bd32a..c56dc83412 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -24,6 +24,7 @@
#include "SurfaceFlinger.h"
+#include <aidl/android/hardware/power/Boost.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -34,7 +35,6 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
-#include <android/hardware/power/Boost.h>
#include <android/native_window.h>
#include <android/os/IInputFlinger.h>
#include <binder/IPCThreadState.h>
@@ -68,6 +68,7 @@
#include <gui/LayerMetadata.h>
#include <gui/LayerState.h>
#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
#include <gui/TraceUtils.h>
#include <hidl/ServiceManagement.h>
#include <layerproto/LayerProtoParser.h>
@@ -91,18 +92,18 @@
#include <ui/LayerStack.h>
#include <ui/PixelFormat.h>
#include <ui/StaticDisplayInfo.h>
+#include <unistd.h>
#include <utils/StopWatch.h>
#include <utils/String16.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/misc.h>
-
-#include <unistd.h>
#include <algorithm>
#include <cerrno>
#include <cinttypes>
#include <cmath>
#include <cstdint>
+#include <filesystem>
#include <functional>
#include <memory>
#include <mutex>
@@ -112,7 +113,9 @@
#include <unordered_map>
#include <vector>
+#include <common/FlagManager.h>
#include <gui/LayerStatePermissions.h>
+#include <gui/SchedulingPolicy.h>
#include <ui/DisplayIdentification.h>
#include "BackgroundExecutor.h"
#include "Client.h"
@@ -127,13 +130,13 @@
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "DisplayRenderArea.h"
#include "Effects/Daltonizer.h"
-#include "FlagManager.h"
#include "FpsReporter.h"
#include "FrameTimeline/FrameTimeline.h"
#include "FrameTracer/FrameTracer.h"
#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/LayerHandle.h"
#include "FrontEnd/LayerLifecycleManager.h"
+#include "FrontEnd/LayerLog.h"
#include "FrontEnd/LayerSnapshot.h"
#include "HdrLayerInfoReporter.h"
#include "Layer.h"
@@ -169,7 +172,6 @@
#define DOES_CONTAIN_BORDER false
namespace android {
-
using namespace std::chrono_literals;
using namespace std::string_literals;
using namespace std::string_view_literals;
@@ -260,7 +262,7 @@ bool getKernelIdleTimerSyspropConfig(DisplayId displayId) {
bool isAbove4k30(const ui::DisplayMode& outMode) {
using fps_approx_ops::operator>;
- Fps refreshRate = Fps::fromValue(outMode.refreshRate);
+ Fps refreshRate = Fps::fromValue(outMode.peakRefreshRate);
return outMode.resolution.getWidth() >= FOUR_K_WIDTH &&
outMode.resolution.getHeight() >= FOUR_K_HEIGHT && refreshRate > 30_Hz;
}
@@ -303,6 +305,66 @@ uint32_t getLayerIdFromSurfaceControl(sp<SurfaceControl> surfaceControl) {
return LayerHandle::getLayerId(surfaceControl->getHandle());
}
+/**
+ * Returns true if the file at path exists and is newer than duration.
+ */
+bool fileNewerThan(const std::string& path, std::chrono::minutes duration) {
+ using Clock = std::filesystem::file_time_type::clock;
+ std::error_code error;
+ std::filesystem::file_time_type updateTime = std::filesystem::last_write_time(path, error);
+ if (error) {
+ return false;
+ }
+ return duration > (Clock::now() - updateTime);
+}
+
+bool isFrameIntervalOnCadence(TimePoint expectedPresentTime, TimePoint lastExpectedPresentTimestamp,
+ Fps lastFrameInterval, Period timeout, Duration threshold) {
+ if (lastFrameInterval.getPeriodNsecs() == 0) {
+ return false;
+ }
+
+ const auto expectedPresentTimeDeltaNs =
+ expectedPresentTime.ns() - lastExpectedPresentTimestamp.ns();
+
+ if (expectedPresentTimeDeltaNs > timeout.ns()) {
+ return false;
+ }
+
+ const auto expectedPresentPeriods = static_cast<nsecs_t>(
+ std::round(static_cast<float>(expectedPresentTimeDeltaNs) /
+ static_cast<float>(lastFrameInterval.getPeriodNsecs())));
+ const auto calculatedPeriodsOutNs = lastFrameInterval.getPeriodNsecs() * expectedPresentPeriods;
+ const auto calculatedExpectedPresentTimeNs =
+ lastExpectedPresentTimestamp.ns() + calculatedPeriodsOutNs;
+ const auto presentTimeDelta =
+ std::abs(expectedPresentTime.ns() - calculatedExpectedPresentTimeNs);
+ return presentTimeDelta < threshold.ns();
+}
+
+bool isExpectedPresentWithinTimeout(TimePoint expectedPresentTime,
+ TimePoint lastExpectedPresentTimestamp,
+ std::optional<Period> timeoutOpt, Duration threshold) {
+ if (!timeoutOpt) {
+ // Always within timeout if timeoutOpt is absent and don't send hint
+ // for the timeout
+ return true;
+ }
+
+ if (timeoutOpt->ns() == 0) {
+ // Always outside timeout if timeoutOpt is 0 and always send
+ // the hint for the timeout.
+ return false;
+ }
+
+ if (expectedPresentTime.ns() < lastExpectedPresentTimestamp.ns() + timeoutOpt->ns()) {
+ return true;
+ }
+
+ // Check if within the threshold as it can be just outside the timeout
+ return std::abs(expectedPresentTime.ns() -
+ (lastExpectedPresentTimestamp.ns() + timeoutOpt->ns())) < threshold.ns();
+}
} // namespace anonymous
// ---------------------------------------------------------------------------
@@ -319,13 +381,12 @@ const String16 sWakeupSurfaceFlinger("android.permission.WAKEUP_SURFACE_FLINGER"
const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
-static const int MAX_TRACING_MEMORY = 1024 * 1024 * 1024; // 1GB
-
// ---------------------------------------------------------------------------
int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
bool SurfaceFlinger::useHwcForRgbToYuv;
bool SurfaceFlinger::hasSyncFramework;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
+int64_t SurfaceFlinger::minAcquiredBuffers = 1;
uint32_t SurfaceFlinger::maxGraphicsWidth;
uint32_t SurfaceFlinger::maxGraphicsHeight;
bool SurfaceFlinger::useContextPriority;
@@ -377,6 +438,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
+ ATRACE_CALL();
ALOGI("SurfaceFlinger is starting");
hasSyncFramework = running_without_sync_framework(true);
@@ -386,6 +448,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI
useHwcForRgbToYuv = force_hwc_copy_for_virtual_displays(false);
maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
+ minAcquiredBuffers =
+ SurfaceFlingerProperties::min_acquired_buffers().value_or(minAcquiredBuffers);
maxGraphicsWidth = std::max(max_graphics_width(0), 0);
maxGraphicsHeight = std::max(max_graphics_height(0), 0);
@@ -402,9 +466,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI
wideColorGamutCompositionPixelFormat =
static_cast<ui::PixelFormat>(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888));
- mColorSpaceAgnosticDataspace =
- static_cast<ui::Dataspace>(color_space_agnostic_dataspace(Dataspace::UNKNOWN));
-
mLayerCachingEnabled = [] {
const bool enable =
android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false);
@@ -481,12 +542,13 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI
if (!mIsUserBuild && base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, true)) {
mTransactionTracing.emplace();
+ mLayerTracing.setTransactionTracing(*mTransactionTracing);
}
mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false);
mLayerLifecycleManagerEnabled =
- base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false);
+ base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true);
mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled ||
base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false);
}
@@ -496,10 +558,6 @@ LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
return LatchUnsignaledConfig::AutoSingleLayer;
}
- if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) {
- return LatchUnsignaledConfig::Always;
- }
-
return LatchUnsignaledConfig::Disabled;
}
@@ -554,6 +612,9 @@ sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, bool secur
// Display ID is assigned when virtual display is allocated by HWC.
DisplayDeviceState state;
state.isSecure = secure;
+ // Set display as protected when marked as secure to ensure no behavior change
+ // TODO (b/314820005): separate as a different arg when creating the display.
+ state.isProtected = secure;
state.displayName = displayName;
state.requestedRefreshRate = Fps::fromValue(requestedRefreshRate);
mCurrentState.displays.add(token, state);
@@ -650,14 +711,6 @@ sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId)
return getPhysicalDisplayTokenLocked(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();
}
@@ -676,6 +729,7 @@ void SurfaceFlinger::bootFinished() {
return;
}
mBootFinished = true;
+ FlagManager::getMutableInstance().markBootCompleted();
if (mStartPropertySetThread->join() != NO_ERROR) {
ALOGE("Join StartPropertySetThread failed!");
}
@@ -689,11 +743,11 @@ void SurfaceFlinger::bootFinished() {
mFrameTracer->initialize();
mFrameTimeline->onBootFinished();
- getRenderEngine().setEnableTracing(mFlagManager.use_skia_tracing());
+ getRenderEngine().setEnableTracing(FlagManager::getInstance().use_skia_tracing());
// wait patiently for the window manager death
const String16 name("window");
- mWindowManager = defaultServiceManager()->getService(name);
+ mWindowManager = defaultServiceManager()->waitForService(name);
if (mWindowManager != 0) {
mWindowManager->linkToDeath(sp<IBinder::DeathRecipient>::fromExisting(this));
}
@@ -707,7 +761,7 @@ void SurfaceFlinger::bootFinished() {
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- sp<IBinder> input(defaultServiceManager()->getService(String16("inputflinger")));
+ sp<IBinder> input(defaultServiceManager()->waitForService(String16("inputflinger")));
static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(kMainThreadContext) {
if (input == nullptr) {
@@ -717,10 +771,12 @@ void SurfaceFlinger::bootFinished() {
}
readPersistentProperties();
- mPowerAdvisor->onBootFinished();
- const bool hintSessionEnabled = mFlagManager.use_adpf_cpu_hint();
+ const bool hintSessionEnabled = FlagManager::getInstance().use_adpf_cpu_hint();
mPowerAdvisor->enablePowerHintSession(hintSessionEnabled);
const bool hintSessionUsed = mPowerAdvisor->usePowerHintSession();
+ // Ordering is important here, as onBootFinished signals to PowerAdvisor that concurrency
+ // is safe because its variables are initialized.
+ mPowerAdvisor->onBootFinished();
ALOGD("Power hint is %s",
hintSessionUsed ? "supported" : (hintSessionEnabled ? "unsupported" : "disabled"));
if (hintSessionUsed) {
@@ -730,7 +786,7 @@ void SurfaceFlinger::bootFinished() {
if (renderEngineTid.has_value()) {
tidList.emplace_back(*renderEngineTid);
}
- if (!mPowerAdvisor->startPowerHintSession(tidList)) {
+ if (!mPowerAdvisor->startPowerHintSession(std::move(tidList))) {
ALOGW("Cannot start power hint session");
}
}
@@ -744,52 +800,12 @@ void SurfaceFlinger::bootFinished() {
}));
}
-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
- auto genTextures = [this] {
- uint32_t name = 0;
- getRenderEngine().genTextures(1, &name);
- return name;
- };
- if (std::this_thread::get_id() == mMainThreadId) {
- return genTextures();
- } else {
- return mScheduler->schedule(genTextures).get();
- }
-}
-
-void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
- std::lock_guard lock(mTexturePoolMutex);
- // We don't change the pool size, so the fix-up logic in postComposition will decide whether
- // to actually delete this or not based on mTexturePoolSize
- mTexturePool.push_back(texture);
- ATRACE_INT("TexturePoolSize", mTexturePool.size());
-}
-
static std::optional<renderengine::RenderEngine::RenderEngineType>
chooseRenderEngineTypeViaSysProp() {
char prop[PROPERTY_VALUE_MAX];
- property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "");
+ property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "skiaglthreaded");
- if (strcmp(prop, "gles") == 0) {
- return renderengine::RenderEngine::RenderEngineType::GLES;
- } else if (strcmp(prop, "threaded") == 0) {
- return renderengine::RenderEngine::RenderEngineType::THREADED;
- } else if (strcmp(prop, "skiagl") == 0) {
+ if (strcmp(prop, "skiagl") == 0) {
return renderengine::RenderEngine::RenderEngineType::SKIA_GL;
} else if (strcmp(prop, "skiaglthreaded") == 0) {
return renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED;
@@ -806,6 +822,7 @@ chooseRenderEngineTypeViaSysProp() {
// Do not call property_set on main thread which will be blocked by init
// Use StartPropertySetThread instead.
void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
+ ATRACE_CALL();
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
addTransactionReadyFilters();
@@ -817,7 +834,6 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
auto builder = renderengine::RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int32_t>(defaultCompositionPixelFormat))
.setImageCacheSize(maxFrameBufferAcquiredBuffers)
- .setUseColorManagerment(useColorManagement)
.setEnableProtectedContext(enable_protected_contents(false))
.setPrecacheToneMapperShaderOnly(false)
.setSupportsBackgroundBlur(mSupportsBlur)
@@ -877,6 +893,17 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
initScheduler(display);
dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
+ mLayerTracing.setTakeLayersSnapshotProtoFunction([&](uint32_t traceFlags) {
+ auto snapshot = perfetto::protos::LayersSnapshotProto{};
+ mScheduler
+ ->schedule([&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) {
+ snapshot = takeLayersSnapshotProto(traceFlags, TimePoint::now(),
+ mLastCommittedVsyncId, true);
+ })
+ .wait();
+ return snapshot;
+ });
+
// Commit secondary display(s).
processDisplayChangesLocked();
@@ -890,14 +917,14 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
mPowerAdvisor->init();
- char primeShaderCache[PROPERTY_VALUE_MAX];
- property_get("service.sf.prime_shader_cache", primeShaderCache, "1");
- if (atoi(primeShaderCache)) {
+ if (base::GetBoolProperty("service.sf.prime_shader_cache"s, true)) {
if (setSchedFifo(false) != NO_ERROR) {
ALOGW("Can't set SCHED_OTHER for primeCache");
}
- mRenderEnginePrimeCacheFuture = getRenderEngine().primeCache();
+ bool shouldPrimeUltraHDR =
+ base::GetBoolProperty("ro.surface_flinger.prime_shader_cache.ultrahdr"s, false);
+ mRenderEnginePrimeCacheFuture = getRenderEngine().primeCache(shouldPrimeUltraHDR);
if (setSchedFifo(true) != NO_ERROR) {
ALOGW("Can't set SCHED_FIFO after primeCache");
@@ -914,30 +941,32 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
ALOGE("Run StartPropertySetThread failed!");
}
- if (mTransactionTracing) {
- TransactionTraceWriter::getInstance().setWriterFunction([&](const std::string& prefix,
- bool overwrite) {
- auto writeFn = [&]() {
- const std::string filename =
- TransactionTracing::DIR_NAME + prefix + TransactionTracing::FILE_NAME;
- if (overwrite && access(filename.c_str(), F_OK) == 0) {
- ALOGD("TransactionTraceWriter: file=%s already exists", filename.c_str());
- return;
- }
- mTransactionTracing->flush();
- mTransactionTracing->writeToFile(filename);
- };
- if (std::this_thread::get_id() == mMainThreadId) {
- writeFn();
- } else {
- mScheduler->schedule(writeFn).get();
- }
- });
- }
-
+ initTransactionTraceWriter();
ALOGV("Done initializing");
}
+void SurfaceFlinger::initTransactionTraceWriter() {
+ if (!mTransactionTracing) {
+ return;
+ }
+ TransactionTraceWriter::getInstance().setWriterFunction(
+ [&](const std::string& filename, bool overwrite) {
+ auto writeFn = [&]() {
+ if (!overwrite && fileNewerThan(filename, std::chrono::minutes{10})) {
+ ALOGD("TransactionTraceWriter: file=%s already exists", filename.c_str());
+ return;
+ }
+ mTransactionTracing->flush();
+ mTransactionTracing->writeToFile(filename);
+ };
+ if (std::this_thread::get_id() == mMainThreadId) {
+ writeFn();
+ } else {
+ mScheduler->schedule(writeFn).get();
+ }
+ });
+}
+
void SurfaceFlinger::readPersistentProperties() {
Mutex::Autolock _l(mStateLock);
@@ -1069,11 +1098,12 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info
outMode.xDpi = xDpi;
outMode.yDpi = yDpi;
- const nsecs_t period = mode->getVsyncPeriod();
- outMode.refreshRate = Fps::fromPeriodNsecs(period).getValue();
+ const auto peakFps = mode->getPeakFps();
+ outMode.peakRefreshRate = peakFps.getValue();
+ outMode.vsyncRate = mode->getVsyncRate().getValue();
- const auto vsyncConfigSet =
- mVsyncConfiguration->getConfigsForRefreshRate(Fps::fromValue(outMode.refreshRate));
+ const auto vsyncConfigSet = mVsyncConfiguration->getConfigsForRefreshRate(
+ Fps::fromValue(outMode.peakRefreshRate));
outMode.appVsyncOffset = vsyncConfigSet.late.appOffset;
outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
outMode.group = mode->getGroup();
@@ -1090,7 +1120,7 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
- outMode.presentationDeadline = period - outMode.sfVsyncOffset + 1000000;
+ outMode.presentationDeadline = peakFps.getPeriodNsecs() - outMode.sfVsyncOffset + 1000000;
excludeDolbyVisionIf4k30Present(display->getHdrCapabilities().getSupportedHdrTypes(),
outMode);
info->supportedDisplayModes.push_back(outMode);
@@ -1199,7 +1229,7 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& displayToken,
return NO_ERROR;
}
-void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request, bool force) {
+void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& request, bool force) {
const auto displayId = request.mode.modePtr->getPhysicalDisplayId();
ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str());
@@ -1212,10 +1242,9 @@ void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request,
const auto mode = request.mode;
const bool emitEvent = request.emitEvent;
- switch (display->setDesiredActiveMode(DisplayDevice::ActiveModeInfo(std::move(request)),
- force)) {
- case DisplayDevice::DesiredActiveModeAction::InitiateDisplayModeSwitch:
- // Set the render rate as setDesiredActiveMode updated it.
+ switch (display->setDesiredMode(std::move(request), force)) {
+ case DisplayDevice::DesiredModeAction::InitiateDisplayModeSwitch:
+ // DisplayDevice::setDesiredMode updated the render rate, so inform Scheduler.
mScheduler->setRenderRate(displayId,
display->refreshRateSelector().getActiveMode().fps);
@@ -1225,7 +1254,7 @@ void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request,
// Start receiving vsync samples now, so that we can detect a period
// switch.
mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */,
- mode.modePtr->getFps());
+ mode.modePtr.get());
// As we called to set period, we will call to onRefreshRateChangeCompleted once
// VsyncController model is locked.
@@ -1237,7 +1266,7 @@ void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request,
mScheduler->setModeChangePending(true);
break;
- case DisplayDevice::DesiredActiveModeAction::InitiateRenderRateSwitch:
+ case DisplayDevice::DesiredModeAction::InitiateRenderRateSwitch:
mScheduler->setRenderRate(displayId, mode.fps);
if (displayId == mActiveDisplayId) {
@@ -1249,13 +1278,13 @@ void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request,
dispatchDisplayModeChangeEvent(displayId, mode);
}
break;
- case DisplayDevice::DesiredActiveModeAction::None:
+ case DisplayDevice::DesiredModeAction::None:
break;
}
}
status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<display::DisplayToken>& displayToken,
- DisplayModeId modeId) {
+ DisplayModeId modeId, Fps minFps, Fps maxFps) {
ATRACE_CALL();
if (!displayToken) {
@@ -1279,7 +1308,7 @@ status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<display::DisplayToke
const auto& snapshot = snapshotRef.get();
const auto fpsOpt = snapshot.displayModes().get(modeId).transform(
- [](const DisplayModePtr& mode) { return mode->getFps(); });
+ [](const DisplayModePtr& mode) { return mode->getPeakFps(); });
if (!fpsOpt) {
ALOGE("%s: Invalid mode %d for display %s", whence, modeId.value(),
@@ -1288,13 +1317,15 @@ status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<display::DisplayToke
}
const Fps fps = *fpsOpt;
+ const FpsRange physical = {fps, fps};
+ const FpsRange render = {minFps.isValid() ? minFps : fps, maxFps.isValid() ? maxFps : fps};
+ const FpsRanges ranges = {physical, render};
// Keep the old switching type.
const bool allowGroupSwitching =
display->refreshRateSelector().getCurrentPolicy().allowGroupSwitching;
- const scheduler::RefreshRateSelector::DisplayManagerPolicy policy{modeId,
- {fps, fps},
+ const scheduler::RefreshRateSelector::DisplayManagerPolicy policy{modeId, ranges, ranges,
allowGroupSwitching};
return setDesiredDisplayModeSpecsInternal(display, policy);
@@ -1307,28 +1338,28 @@ void SurfaceFlinger::finalizeDisplayModeChange(DisplayDevice& display) {
const auto displayId = display.getPhysicalId();
ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str());
- const auto upcomingModeInfo = display.getUpcomingActiveMode();
- if (!upcomingModeInfo.modeOpt) {
+ const auto pendingModeOpt = display.getPendingMode();
+ if (!pendingModeOpt) {
// There is no pending mode change. This can happen if the active
// display changed and the mode change happened on a different display.
return;
}
- if (display.getActiveMode().modePtr->getResolution() !=
- upcomingModeInfo.modeOpt->modePtr->getResolution()) {
+ const auto& activeMode = pendingModeOpt->mode;
+
+ if (display.getActiveMode().modePtr->getResolution() != activeMode.modePtr->getResolution()) {
auto& state = mCurrentState.displays.editValueFor(display.getDisplayToken());
// We need to generate new sequenceId in order to recreate the display (and this
// way the framebuffer).
state.sequenceId = DisplayDeviceState{}.sequenceId;
- state.physical->activeMode = upcomingModeInfo.modeOpt->modePtr.get();
+ state.physical->activeMode = activeMode.modePtr.get();
processDisplayChangesLocked();
// processDisplayChangesLocked will update all necessary components so we're done here.
return;
}
- const auto& activeMode = *upcomingModeInfo.modeOpt;
- display.finalizeModeChange(activeMode.modePtr->getId(), activeMode.modePtr->getFps(),
+ display.finalizeModeChange(activeMode.modePtr->getId(), activeMode.modePtr->getVsyncRate(),
activeMode.fps);
if (displayId == mActiveDisplayId) {
@@ -1336,27 +1367,29 @@ void SurfaceFlinger::finalizeDisplayModeChange(DisplayDevice& display) {
updatePhaseConfiguration(activeMode.fps);
}
- if (upcomingModeInfo.event != scheduler::DisplayModeEvent::None) {
+ if (pendingModeOpt->emitEvent) {
dispatchDisplayModeChangeEvent(displayId, activeMode);
}
}
-void SurfaceFlinger::clearDesiredActiveModeState(const sp<DisplayDevice>& display) {
- display->clearDesiredActiveModeState();
+void SurfaceFlinger::dropModeRequest(const sp<DisplayDevice>& display) {
+ display->clearDesiredMode();
if (display->getPhysicalId() == mActiveDisplayId) {
// TODO(b/255635711): Check for pending mode changes on other displays.
mScheduler->setModeChangePending(false);
}
}
-void SurfaceFlinger::desiredActiveModeChangeDone(const sp<DisplayDevice>& display) {
- const auto desiredActiveMode = display->getDesiredActiveMode();
- const auto& modeOpt = desiredActiveMode->modeOpt;
- const auto displayId = modeOpt->modePtr->getPhysicalDisplayId();
- const auto displayFps = modeOpt->modePtr->getFps();
- const auto renderFps = modeOpt->fps;
- clearDesiredActiveModeState(display);
- mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */, displayFps);
+void SurfaceFlinger::applyActiveMode(const sp<DisplayDevice>& display) {
+ const auto activeModeOpt = display->getDesiredMode();
+ auto activeModePtr = activeModeOpt->mode.modePtr;
+ const auto displayId = activeModePtr->getPhysicalDisplayId();
+ const auto renderFps = activeModeOpt->mode.fps;
+
+ dropModeRequest(display);
+
+ constexpr bool kAllowToEnable = true;
+ mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, std::move(activeModePtr).take());
mScheduler->setRenderRate(displayId, renderFps);
if (displayId == mActiveDisplayId) {
@@ -1373,45 +1406,40 @@ void SurfaceFlinger::initiateDisplayModeChanges() {
const auto display = getDisplayDeviceLocked(id);
if (!display) continue;
- // Store the local variable to release the lock.
- const auto desiredActiveMode = display->getDesiredActiveMode();
- if (!desiredActiveMode) {
- // No desired active mode pending to be applied.
+ auto desiredModeOpt = display->getDesiredMode();
+ if (!desiredModeOpt) {
continue;
}
if (!shouldApplyRefreshRateSelectorPolicy(*display)) {
- clearDesiredActiveModeState(display);
+ dropModeRequest(display);
continue;
}
- const auto desiredModeId = desiredActiveMode->modeOpt->modePtr->getId();
+ const auto desiredModeId = desiredModeOpt->mode.modePtr->getId();
const auto displayModePtrOpt = physical.snapshot().displayModes().get(desiredModeId);
if (!displayModePtrOpt) {
ALOGW("Desired display mode is no longer supported. Mode ID = %d",
desiredModeId.value());
- clearDesiredActiveModeState(display);
+ dropModeRequest(display);
continue;
}
ALOGV("%s changing active mode to %d(%s) for display %s", __func__, desiredModeId.value(),
- to_string(displayModePtrOpt->get()->getFps()).c_str(),
+ to_string(displayModePtrOpt->get()->getVsyncRate()).c_str(),
to_string(display->getId()).c_str());
- if (display->getActiveMode() == desiredActiveMode->modeOpt) {
- // we are already in the requested mode, there is nothing left to do
- desiredActiveModeChangeDone(display);
+ if (display->getActiveMode() == desiredModeOpt->mode) {
+ applyActiveMode(display);
continue;
}
// Desired active mode was set, it is different than the mode currently in use, however
// allowed modes might have changed by the time we process the refresh.
// Make sure the desired mode is still allowed
- const auto displayModeAllowed =
- display->refreshRateSelector().isModeAllowed(*desiredActiveMode->modeOpt);
- if (!displayModeAllowed) {
- clearDesiredActiveModeState(display);
+ if (!display->refreshRateSelector().isModeAllowed(desiredModeOpt->mode)) {
+ dropModeRequest(display);
continue;
}
@@ -1421,13 +1449,7 @@ void SurfaceFlinger::initiateDisplayModeChanges() {
constraints.seamlessRequired = false;
hal::VsyncPeriodChangeTimeline outTimeline;
- const auto status =
- display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline);
-
- if (status != NO_ERROR) {
- // initiateModeChange may fail if a hotplug event is just about
- // to be sent. We just log the error in this case.
- ALOGW("initiateModeChange failed: %d", status);
+ if (!display->initiateModeChange(std::move(*desiredModeOpt), constraints, outTimeline)) {
continue;
}
@@ -1448,9 +1470,9 @@ void SurfaceFlinger::initiateDisplayModeChanges() {
const auto display = getDisplayDeviceLocked(*displayToUpdateImmediately);
finalizeDisplayModeChange(*display);
- const auto desiredActiveMode = display->getDesiredActiveMode();
- if (desiredActiveMode && display->getActiveMode() == desiredActiveMode->modeOpt) {
- desiredActiveModeChangeDone(display);
+ const auto desiredModeOpt = display->getDesiredMode();
+ if (desiredModeOpt && display->getActiveMode() == desiredModeOpt->mode) {
+ applyActiveMode(display);
}
}
}
@@ -1523,7 +1545,7 @@ status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ui:
}
display->getCompositionDisplay()->setColorProfile(
- {mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN});
+ {mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC});
return NO_ERROR;
});
@@ -1943,10 +1965,28 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken,
float currentDimmingRatio =
compositionDisplay->editState().sdrWhitePointNits /
compositionDisplay->editState().displayBrightnessNits;
- compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits,
- brightness.displayBrightnessNits);
+ static constexpr float kDimmingThreshold = 0.02f;
+ if (brightness.sdrWhitePointNits == 0.f ||
+ abs(brightness.sdrWhitePointNits - brightness.displayBrightnessNits) /
+ brightness.sdrWhitePointNits >=
+ kDimmingThreshold) {
+ // to optimize, skip brightness setter if the brightness difference ratio
+ // is lower than threshold
+ compositionDisplay
+ ->setDisplayBrightness(brightness.sdrWhitePointNits,
+ brightness.displayBrightnessNits);
+ } else {
+ compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits,
+ brightness.sdrWhitePointNits);
+ }
+
FTL_FAKE_GUARD(kMainThreadContext,
display->stageBrightness(brightness.displayBrightness));
+ float currentHdrSdrRatio =
+ compositionDisplay->editState().displayBrightnessNits /
+ compositionDisplay->editState().sdrWhitePointNits;
+ FTL_FAKE_GUARD(kMainThreadContext,
+ display->updateHdrSdrRatioOverlayRatio(currentHdrSdrRatio));
if (brightness.sdrWhitePointNits / brightness.displayBrightnessNits !=
currentDimmingRatio) {
@@ -2018,7 +2058,7 @@ status_t SurfaceFlinger::removeHdrLayerInfoListener(
}
status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) {
- using hardware::power::Boost;
+ using aidl::android::hardware::power::Boost;
Boost powerBoost = static_cast<Boost>(boostId);
if (powerBoost == Boost::INTERACTION) {
@@ -2090,6 +2130,17 @@ nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const {
void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp,
std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
+ if (FlagManager::getInstance().connected_display()) {
+ // use ~0 instead of -1 as AidlComposerHal.cpp passes the param as unsigned int32
+ if (mIsHotplugErrViaNegVsync && timestamp < 0 && vsyncPeriod.has_value() &&
+ vsyncPeriod.value() == ~0) {
+ int hotplugErrorCode = static_cast<int32_t>(-timestamp);
+ ALOGD("SurfaceFlinger got hotplugErrorCode=%d", hotplugErrorCode);
+ mScheduler->onHotplugConnectionError(mAppConnectionHandle, hotplugErrorCode);
+ return;
+ }
+ }
+
ATRACE_NAME(vsyncPeriod
? ftl::Concat(__func__, ' ', hwcDisplayId, ' ', *vsyncPeriod, "ns").c_str()
: ftl::Concat(__func__, ' ', hwcDisplayId).c_str());
@@ -2103,15 +2154,28 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t
}
}
-void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
- hal::Connection connection) {
- {
- std::lock_guard<std::mutex> lock(mHotplugMutex);
- mPendingHotplugEvents.push_back(HotplugEvent{hwcDisplayId, connection});
+void SurfaceFlinger::onComposerHalHotplugEvent(hal::HWDisplayId hwcDisplayId,
+ DisplayHotplugEvent event) {
+ if (event == DisplayHotplugEvent::CONNECTED || event == DisplayHotplugEvent::DISCONNECTED) {
+ hal::Connection connection = (event == DisplayHotplugEvent::CONNECTED)
+ ? hal::Connection::CONNECTED
+ : hal::Connection::DISCONNECTED;
+ {
+ std::lock_guard<std::mutex> lock(mHotplugMutex);
+ mPendingHotplugEvents.push_back(HotplugEvent{hwcDisplayId, connection});
+ }
+
+ if (mScheduler) {
+ mScheduler->scheduleConfigure();
+ }
+
+ return;
}
- if (mScheduler) {
- mScheduler->scheduleConfigure();
+ if (FlagManager::getInstance().hotplug2()) {
+ ALOGD("SurfaceFlinger got hotplug event=%d", static_cast<int32_t>(event));
+ // TODO(b/311403559): use enum type instead of int
+ mScheduler->onHotplugConnectionError(mAppConnectionHandle, static_cast<int32_t>(event));
}
}
@@ -2143,19 +2207,16 @@ void SurfaceFlinger::onComposerHalVsyncIdle(hal::HWDisplayId) {
void SurfaceFlinger::onRefreshRateChangedDebug(const RefreshRateChangedDebugData& data) {
ATRACE_CALL();
if (const auto displayId = getHwComposer().toPhysicalDisplayId(data.display); displayId) {
- const Fps fps = Fps::fromPeriodNsecs(data.vsyncPeriodNanos);
- ATRACE_FORMAT("%s Fps %d", __func__, fps.getIntValue());
+ const char* const whence = __func__;
static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
- {
- {
- const auto display = getDisplayDeviceLocked(*displayId);
- FTL_FAKE_GUARD(kMainThreadContext,
- display->updateRefreshRateOverlayRate(fps,
- display->getActiveMode()
- .fps,
- /* setByHwc */ true));
- }
- }
+ const Fps fps = Fps::fromPeriodNsecs(getHwComposer().getComposer()->isVrrSupported()
+ ? data.refreshPeriodNanos
+ : data.vsyncPeriodNanos);
+ ATRACE_FORMAT("%s Fps %d", whence, fps.getIntValue());
+ const auto display = getDisplayDeviceLocked(*displayId);
+ FTL_FAKE_GUARD(kMainThreadContext,
+ display->updateRefreshRateOverlayRate(fps, display->getActiveMode().fps,
+ /* setByHwc */ true));
}));
}
}
@@ -2167,12 +2228,22 @@ void SurfaceFlinger::configure() {
}
}
-bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, frontend::Update& update,
- bool transactionsFlushed,
+bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, nsecs_t frameTimeNs,
+ bool flushTransactions,
bool& outTransactionsAreEmpty) {
ATRACE_CALL();
+ frontend::Update update;
+ if (flushTransactions) {
+ update = flushLifecycleUpdates();
+ if (mTransactionTracing) {
+ mTransactionTracing->addCommittedTransactions(ftl::to_underlying(vsyncId), frameTimeNs,
+ update, mFrontEndDisplayInfos,
+ mFrontEndDisplayInfosChanged);
+ }
+ }
+
bool needsTraversal = false;
- if (transactionsFlushed) {
+ if (flushTransactions) {
needsTraversal |= commitMirrorDisplays(vsyncId);
needsTraversal |= commitCreatedLayers(vsyncId, update.layerCreatedStates);
needsTraversal |= applyTransactions(update.transactions, vsyncId);
@@ -2188,44 +2259,111 @@ bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, frontend::Updat
return mustComposite;
}
-void SurfaceFlinger::updateLayerHistory(const frontend::LayerSnapshot& snapshot) {
- using Changes = frontend::RequestedLayerState::Changes;
- if (snapshot.path.isClone() ||
- !snapshot.changes.any(Changes::FrameRate | Changes::Buffer | Changes::Animation)) {
- return;
- }
+void SurfaceFlinger::updateLayerHistory(nsecs_t now) {
+ for (const auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) {
+ using Changes = frontend::RequestedLayerState::Changes;
+ if (snapshot->path.isClone()) {
+ continue;
+ }
- const auto layerProps = scheduler::LayerProps{
- .visible = snapshot.isVisible,
- .bounds = snapshot.geomLayerBounds,
- .transform = snapshot.geomLayerTransform,
- .setFrameRateVote = snapshot.frameRate,
- .frameRateSelectionPriority = snapshot.frameRateSelectionPriority,
- };
+ const bool updateSmallDirty = FlagManager::getInstance().enable_small_area_detection() &&
+ ((snapshot->clientChanges & layer_state_t::eSurfaceDamageRegionChanged) ||
+ snapshot->changes.any(Changes::Geometry));
- auto it = mLegacyLayers.find(snapshot.sequence);
- LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s",
- snapshot.getDebugString().c_str());
+ const bool hasChanges =
+ snapshot->changes.any(Changes::FrameRate | Changes::Buffer | Changes::Animation |
+ Changes::Geometry | Changes::Visibility) ||
+ (snapshot->clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) !=
+ 0;
- if (snapshot.changes.test(Changes::Animation)) {
- it->second->recordLayerHistoryAnimationTx(layerProps);
- }
+ if (!updateSmallDirty && !hasChanges) {
+ continue;
+ }
- if (snapshot.changes.test(Changes::FrameRate)) {
- it->second->setFrameRateForLayerTree(snapshot.frameRate, layerProps);
- }
+ auto it = mLegacyLayers.find(snapshot->sequence);
+ LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mLegacyLayers.end(),
+ "Couldn't find layer object for %s",
+ snapshot->getDebugString().c_str());
+
+ if (updateSmallDirty) {
+ // Update small dirty flag while surface damage region or geometry changed
+ it->second->setIsSmallDirty(snapshot.get());
+ }
- if (snapshot.changes.test(Changes::Buffer)) {
- it->second->recordLayerHistoryBufferUpdate(layerProps);
+ if (!hasChanges) {
+ continue;
+ }
+
+ const auto layerProps = scheduler::LayerProps{
+ .visible = snapshot->isVisible,
+ .bounds = snapshot->geomLayerBounds,
+ .transform = snapshot->geomLayerTransform,
+ .setFrameRateVote = snapshot->frameRate,
+ .frameRateSelectionPriority = snapshot->frameRateSelectionPriority,
+ .isSmallDirty = snapshot->isSmallDirty,
+ .isFrontBuffered = snapshot->isFrontBuffered(),
+ };
+
+ if (snapshot->changes.any(Changes::Geometry | Changes::Visibility)) {
+ mScheduler->setLayerProperties(snapshot->sequence, layerProps);
+ }
+
+ if (snapshot->clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) {
+ mScheduler->setDefaultFrameRateCompatibility(snapshot->sequence,
+ snapshot->defaultFrameRateCompatibility);
+ }
+
+ if (snapshot->changes.test(Changes::Animation)) {
+ it->second->recordLayerHistoryAnimationTx(layerProps, now);
+ }
+
+ if (snapshot->changes.test(Changes::FrameRate)) {
+ it->second->setFrameRateForLayerTree(snapshot->frameRate, layerProps, now);
+ }
+
+ if (snapshot->changes.test(Changes::Buffer)) {
+ it->second->recordLayerHistoryBufferUpdate(layerProps, now);
+ }
}
}
-bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& update,
- bool transactionsFlushed, bool& outTransactionsAreEmpty) {
+bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs,
+ bool flushTransactions, bool& outTransactionsAreEmpty) {
using Changes = frontend::RequestedLayerState::Changes;
ATRACE_CALL();
- {
+ frontend::Update update;
+ if (flushTransactions) {
+ ATRACE_NAME("TransactionHandler:flushTransactions");
+ // Locking:
+ // 1. to prevent onHandleDestroyed from being called while the state lock is held,
+ // we must keep a copy of the transactions (specifically the composer
+ // states) around outside the scope of the lock.
+ // 2. Transactions and created layers do not share a lock. To prevent applying
+ // transactions with layers still in the createdLayer queue, collect the transactions
+ // before committing the created layers.
+ // 3. Transactions can only be flushed after adding layers, since the layer can be a newly
+ // created one
+ mTransactionHandler.collectTransactions();
+ {
+ // TODO(b/238781169) lockless queue this and keep order.
+ std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
+ update.layerCreatedStates = std::move(mCreatedLayers);
+ mCreatedLayers.clear();
+ update.newLayers = std::move(mNewLayers);
+ mNewLayers.clear();
+ update.layerCreationArgs = std::move(mNewLayerArgs);
+ mNewLayerArgs.clear();
+ update.destroyedHandles = std::move(mDestroyedHandles);
+ mDestroyedHandles.clear();
+ }
+
mLayerLifecycleManager.addLayers(std::move(update.newLayers));
+ update.transactions = mTransactionHandler.flushTransactions();
+ if (mTransactionTracing) {
+ mTransactionTracing->addCommittedTransactions(ftl::to_underlying(vsyncId), frameTimeNs,
+ update, mFrontEndDisplayInfos,
+ mFrontEndDisplayInfosChanged);
+ }
mLayerLifecycleManager.applyTransactions(update.transactions);
mLayerLifecycleManager.onHandlesDestroyed(update.destroyedHandles);
for (auto& legacyLayer : update.layerCreatedStates) {
@@ -2234,11 +2372,11 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& upd
mLegacyLayers[layer->sequence] = layer;
}
}
- }
- if (mLayerLifecycleManager.getGlobalChanges().test(Changes::Hierarchy)) {
- ATRACE_NAME("LayerHierarchyBuilder:update");
- mLayerHierarchyBuilder.update(mLayerLifecycleManager.getLayers(),
- mLayerLifecycleManager.getDestroyedLayers());
+ if (mLayerLifecycleManager.getGlobalChanges().test(Changes::Hierarchy)) {
+ ATRACE_NAME("LayerHierarchyBuilder:update");
+ mLayerHierarchyBuilder.update(mLayerLifecycleManager.getLayers(),
+ mLayerLifecycleManager.getDestroyedLayers());
+ }
}
bool mustComposite = false;
@@ -2256,7 +2394,9 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& upd
.forceFullDamage = mForceFullDamage,
.supportedLayerGenericMetadata =
getHwComposer().getSupportedLayerGenericMetadata(),
- .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap()};
+ .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap(),
+ .skipRoundCornersWhenProtected =
+ !getRenderEngine().supportsProtectedContent()};
mLayerSnapshotBuilder.update(args);
}
@@ -2265,16 +2405,22 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& upd
mUpdateInputInfo = true;
}
if (mLayerLifecycleManager.getGlobalChanges().any(Changes::VisibleRegion | Changes::Hierarchy |
- Changes::Visibility)) {
+ Changes::Visibility | Changes::Geometry)) {
mVisibleRegionsDirty = true;
}
+ if (mLayerLifecycleManager.getGlobalChanges().any(Changes::Hierarchy | Changes::FrameRate)) {
+ // The frame rate of attached choreographers can only change as a result of a
+ // FrameRate change (including when Hierarchy changes).
+ mUpdateAttachedChoreographer = true;
+ }
outTransactionsAreEmpty = mLayerLifecycleManager.getGlobalChanges().get() == 0;
mustComposite |= mLayerLifecycleManager.getGlobalChanges().get() != 0;
bool newDataLatched = false;
if (!mLegacyFrontEndEnabled) {
ATRACE_NAME("DisplayCallbackAndStatsUpdates");
- applyTransactions(update.transactions, vsyncId);
+ mustComposite |= applyTransactions(update.transactions, vsyncId);
+ traverseLegacyLayers([&](Layer* layer) { layer->commitTransaction(); });
const nsecs_t latchTime = systemTime();
bool unused = false;
@@ -2288,30 +2434,44 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& upd
mLegacyLayers[bgColorLayer->sequence] = bgColorLayer;
}
const bool willReleaseBufferOnLatch = layer->willReleaseBufferOnLatch();
- if (!layer->hasReadyFrame() && !willReleaseBufferOnLatch) continue;
auto it = mLegacyLayers.find(layer->id);
- LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s",
- layer->getDebugString().c_str());
+ LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mLegacyLayers.end(),
+ "Couldnt find layer object for %s",
+ layer->getDebugString().c_str());
+ if (!layer->hasReadyFrame() && !willReleaseBufferOnLatch) {
+ if (!it->second->hasBuffer()) {
+ // The last latch time is used to classify a missed frame as buffer stuffing
+ // instead of a missed frame. This is used to identify scenarios where we
+ // could not latch a buffer or apply a transaction due to backpressure.
+ // We only update the latch time for buffer less layers here, the latch time
+ // is updated for buffer layers when the buffer is latched.
+ it->second->updateLastLatchTime(latchTime);
+ }
+ continue;
+ }
+
const bool bgColorOnly =
!layer->externalTexture && (layer->bgColorLayerId != UNASSIGNED_LAYER_ID);
if (willReleaseBufferOnLatch) {
mLayersWithBuffersRemoved.emplace(it->second);
}
it->second->latchBufferImpl(unused, latchTime, bgColorOnly);
+ newDataLatched = true;
+
mLayersWithQueuedFrames.emplace(it->second);
+ mLayersIdsWithQueuedFrames.emplace(it->second->sequence);
}
- for (auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) {
- updateLayerHistory(*snapshot);
- if (!snapshot->hasReadyFrame) continue;
- newDataLatched = true;
- if (!snapshot->isVisible) break;
-
+ updateLayerHistory(latchTime);
+ mLayerSnapshotBuilder.forEachVisibleSnapshot([&](const frontend::LayerSnapshot& snapshot) {
+ if (mLayersIdsWithQueuedFrames.find(snapshot.path.id) ==
+ mLayersIdsWithQueuedFrames.end())
+ return;
Region visibleReg;
- visibleReg.set(snapshot->transformedBoundsWithoutTransparentRegion);
- invalidateLayerStack(snapshot->outputFilter, visibleReg);
- }
+ visibleReg.set(snapshot.transformedBoundsWithoutTransparentRegion);
+ invalidateLayerStack(snapshot.outputFilter, visibleReg);
+ });
for (auto& destroyedLayer : mLayerLifecycleManager.getDestroyedLayers()) {
mLegacyLayers.erase(destroyedLayer->id);
@@ -2322,8 +2482,6 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& upd
mLayerLifecycleManager.commitChanges();
}
- commitTransactions();
-
// enter boot animation on first buffer latch
if (CC_UNLIKELY(mBootStage == BootStage::BOOTLOADER && newDataLatched)) {
ALOGI("Enter boot animation");
@@ -2331,6 +2489,10 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& upd
}
}
mustComposite |= (getTransactionFlags() & ~eTransactionFlushNeeded) || newDataLatched;
+ if (mustComposite && !mLegacyFrontEndEnabled) {
+ commitTransactions();
+ }
+
return mustComposite;
}
@@ -2345,11 +2507,6 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId,
mTimeStats->incrementMissedFrames();
}
- if (mTracingEnabledChanged) {
- mLayerTracingEnabled = mLayerTracing.isEnabled();
- mTracingEnabledChanged = false;
- }
-
// If a mode set is pending and the fence hasn't fired yet, wait for the next commit.
if (std::any_of(frameTargets.begin(), frameTargets.end(),
[this](const auto& pair) FTL_FAKE_GUARD(mStateLock)
@@ -2384,6 +2541,10 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId,
if (pacesetterFrameTarget.isFramePending()) {
if (mBackpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) {
+ if (FlagManager::getInstance().vrr_config()) {
+ mScheduler->getVsyncSchedule()->getTracker().onFrameMissed(
+ pacesetterFrameTarget.expectedPresentTime());
+ }
scheduleCommit(FrameHint::kNone);
return false;
}
@@ -2414,10 +2575,10 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId,
mPowerAdvisor->updateTargetWorkDuration(idealVsyncPeriod);
}
- if (mRefreshRateOverlaySpinner) {
+ if (mRefreshRateOverlaySpinner || mHdrSdrRatioOverlay) {
Mutex::Autolock lock(mStateLock);
if (const auto display = getDefaultDisplayDeviceLocked()) {
- display->animateRefreshRateOverlay();
+ display->animateOverlay();
}
}
@@ -2426,28 +2587,20 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId,
{
mFrameTimeline->setSfWakeUp(ftl::to_underlying(vsyncId),
pacesetterFrameTarget.frameBeginTime().ns(),
- Fps::fromPeriodNsecs(vsyncPeriod.ns()));
+ Fps::fromPeriodNsecs(vsyncPeriod.ns()),
+ mScheduler->getPacesetterRefreshRate());
const bool flushTransactions = clearTransactionFlags(eTransactionFlushNeeded);
- frontend::Update updates;
- if (flushTransactions) {
- updates = flushLifecycleUpdates();
- if (mTransactionTracing) {
- mTransactionTracing
- ->addCommittedTransactions(ftl::to_underlying(vsyncId),
- pacesetterFrameTarget.frameBeginTime().ns(),
- updates, mFrontEndDisplayInfos,
- mFrontEndDisplayInfosChanged);
- }
- }
bool transactionsAreEmpty;
if (mLegacyFrontEndEnabled) {
- mustComposite |= updateLayerSnapshotsLegacy(vsyncId, updates, flushTransactions,
- transactionsAreEmpty);
+ mustComposite |=
+ updateLayerSnapshotsLegacy(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(),
+ flushTransactions, transactionsAreEmpty);
}
if (mLayerLifecycleManagerEnabled) {
mustComposite |=
- updateLayerSnapshots(vsyncId, updates, flushTransactions, transactionsAreEmpty);
+ updateLayerSnapshots(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(),
+ flushTransactions, transactionsAreEmpty);
}
if (transactionFlushNeeded()) {
@@ -2470,18 +2623,24 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId,
// Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer>
// and may eventually call to ~Layer() if it holds the last reference
{
+ bool updateAttachedChoreographer = mUpdateAttachedChoreographer;
+ mUpdateAttachedChoreographer = false;
+
Mutex::Autolock lock(mStateLock);
- mScheduler->chooseRefreshRateForContent();
+ mScheduler->chooseRefreshRateForContent(mLayerLifecycleManagerEnabled
+ ? &mLayerHierarchyBuilder.getHierarchy()
+ : nullptr,
+ updateAttachedChoreographer);
initiateDisplayModeChanges();
}
updateCursorAsync();
- updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime());
-
- if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
- // This will block and tracing should only be enabled for debugging.
- addToLayerTracing(mVisibleRegionsDirty, pacesetterFrameTarget.frameBeginTime(), vsyncId);
+ if (!mustComposite) {
+ updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime());
}
+ doActiveLayersTracingIfNeeded(false, mVisibleRegionsDirty,
+ pacesetterFrameTarget.frameBeginTime(), vsyncId);
+
mLastCommittedVsyncId = vsyncId;
persistDisplayBrightness(mustComposite);
@@ -2558,10 +2717,7 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
refreshArgs.layersWithQueuedFrames.push_back(layerFE);
}
- refreshArgs.outputColorSetting = useColorManagement
- ? mDisplayColorSetting
- : compositionengine::OutputColorSetting::kUnmanaged;
- refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace;
+ refreshArgs.outputColorSetting = mDisplayColorSetting;
refreshArgs.forceOutputColorMode = mForceColorMode;
refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
@@ -2580,22 +2736,36 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay);
}
- const Period vsyncPeriod = mScheduler->getVsyncSchedule()->period();
+ const Period minFramePeriod = mScheduler->getVsyncSchedule()->minFramePeriod();
if (!getHwComposer().getComposer()->isSupported(
Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
- pacesetterTarget.wouldPresentEarly(vsyncPeriod)) {
+ pacesetterTarget.wouldPresentEarly(minFramePeriod)) {
const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
// TODO(b/255601557): Calculate and pass per-display values for each FrameTarget.
refreshArgs.earliestPresentTime =
- pacesetterTarget.previousFrameVsyncTime(vsyncPeriod) - hwcMinWorkDuration;
+ pacesetterTarget.previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
}
+ const TimePoint expectedPresentTime = pacesetterTarget.expectedPresentTime();
+ // TODO(b/255601557) Update frameInterval per display
+ refreshArgs.frameInterval = mScheduler->getNextFrameInterval(pacesetterId, expectedPresentTime);
refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
- refreshArgs.expectedPresentTime = pacesetterTarget.expectedPresentTime().ns();
+ refreshArgs.expectedPresentTime = expectedPresentTime.ns();
refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
-
+ {
+ auto& notifyExpectedPresentData = mNotifyExpectedPresentMap[pacesetterId];
+ auto lastExpectedPresentTimestamp = TimePoint::fromNs(
+ notifyExpectedPresentData.lastExpectedPresentTimestamp.load().ns());
+ if (expectedPresentTime > lastExpectedPresentTimestamp) {
+ // If the values are not same, then hint is sent with newer value.
+ // And because composition always follows the notifyExpectedPresentIfRequired, we can
+ // skip updating the lastExpectedPresentTimestamp in this case.
+ notifyExpectedPresentData.lastExpectedPresentTimestamp
+ .compare_exchange_weak(lastExpectedPresentTimestamp, expectedPresentTime);
+ }
+ }
// Store the present time just before calling to the composition engine so we could notify
// the scheduler.
const auto presentTime = systemTime();
@@ -2603,6 +2773,28 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
constexpr bool kCursorOnly = false;
const auto layers = moveSnapshotsToCompositionArgs(refreshArgs, kCursorOnly);
+ if (mLayerLifecycleManagerEnabled && !mVisibleRegionsDirty) {
+ for (const auto& [token, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
+ auto compositionDisplay = display->getCompositionDisplay();
+ if (!compositionDisplay->getState().isEnabled) continue;
+ for (auto outputLayer : compositionDisplay->getOutputLayersOrderedByZ()) {
+ if (outputLayer->getLayerFE().getCompositionState() == nullptr) {
+ // This is unexpected but instead of crashing, capture traces to disk
+ // and recover gracefully by forcing CE to rebuild layer stack.
+ ALOGE("Output layer %s for display %s %" PRIu64 " has a null "
+ "snapshot. Forcing mVisibleRegionsDirty",
+ outputLayer->getLayerFE().getDebugName(),
+ compositionDisplay->getName().c_str(), compositionDisplay->getId().value);
+
+ TransactionTraceWriter::getInstance().invoke(__func__, /* overwrite= */ false);
+ mVisibleRegionsDirty = true;
+ refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
+ refreshArgs.updatingGeometryThisFrame = mVisibleRegionsDirty;
+ }
+ }
+ }
+ }
+
mCompositionEngine->present(refreshArgs);
moveSnapshotsFromCompositionArgs(refreshArgs, layers);
@@ -2633,11 +2825,11 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
mPowerAdvisor->reportActualWorkDuration();
}
- if (mScheduler->onPostComposition(presentTime)) {
+ if (mScheduler->onCompositionPresented(presentTime)) {
scheduleComposite(FrameHint::kNone);
}
- postComposition(pacesetterId, frameTargeters, presentTime);
+ onCompositionPresented(pacesetterId, frameTargeters, presentTime);
const bool hadGpuComposited =
multiDisplayUnion(mCompositionCoverage).test(CompositionCoverage::Gpu);
@@ -2683,10 +2875,11 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
mScheduler->modulateVsync({}, &VsyncModulator::onDisplayRefresh, hasGpuUseOrReuse);
mLayersWithQueuedFrames.clear();
- if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
- // This will block and should only be used for debugging.
- addToLayerTracing(mVisibleRegionsDirty, pacesetterTarget.frameBeginTime(), vsyncId);
- }
+ mLayersIdsWithQueuedFrames.clear();
+ doActiveLayersTracingIfNeeded(true, mVisibleRegionsDirty, pacesetterTarget.frameBeginTime(),
+ vsyncId);
+
+ updateInputFlinger(vsyncId, pacesetterTarget.frameBeginTime());
if (mVisibleRegionsDirty) mHdrLayerInfoChanged = true;
mVisibleRegionsDirty = false;
@@ -2793,11 +2986,10 @@ ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId,
return ui::ROTATION_0;
}
-void SurfaceFlinger::postComposition(PhysicalDisplayId pacesetterId,
- const scheduler::FrameTargeters& frameTargeters,
- nsecs_t presentStartTime) {
+void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId,
+ const scheduler::FrameTargeters& frameTargeters,
+ nsecs_t presentStartTime) {
ATRACE_CALL();
- ALOGV(__func__);
ui::PhysicalDisplayMap<PhysicalDisplayId, std::shared_ptr<FenceTime>> presentFences;
ui::PhysicalDisplayMap<PhysicalDisplayId, const sp<Fence>> gpuCompositionDoneFences;
@@ -2889,8 +3081,9 @@ void SurfaceFlinger::postComposition(PhysicalDisplayId pacesetterId,
mLayersWithBuffersRemoved.clear();
for (const auto& layer: mLayersWithQueuedFrames) {
- layer->onPostComposition(pacesetterDisplay.get(), pacesetterGpuCompositionDoneFenceTime,
- pacesetterPresentFenceTime, compositorTiming);
+ layer->onCompositionPresented(pacesetterDisplay.get(),
+ pacesetterGpuCompositionDoneFenceTime,
+ pacesetterPresentFenceTime, compositorTiming);
layer->releasePendingBuffer(presentTime.ns());
}
@@ -2922,31 +3115,55 @@ void SurfaceFlinger::postComposition(PhysicalDisplayId pacesetterId,
for (auto& [compositionDisplay, listener] : hdrInfoListeners) {
HdrLayerInfoReporter::HdrLayerInfo info;
int32_t maxArea = 0;
- mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
- const auto layerFe = layer->getCompositionEngineLayerFE();
- const frontend::LayerSnapshot& snapshot = *layer->getLayerSnapshot();
- if (snapshot.isVisible &&
- compositionDisplay->includesLayer(snapshot.outputFilter)) {
- if (isHdrLayer(snapshot)) {
- const auto* outputLayer =
- compositionDisplay->getOutputLayerForLayer(layerFe);
- if (outputLayer) {
- const float desiredHdrSdrRatio = snapshot.desiredHdrSdrRatio <= 1.f
- ? std::numeric_limits<float>::infinity()
- : snapshot.desiredHdrSdrRatio;
- info.mergeDesiredRatio(desiredHdrSdrRatio);
- info.numberOfHdrLayers++;
- const auto displayFrame = outputLayer->getState().displayFrame;
- const int32_t area = displayFrame.width() * displayFrame.height();
- if (area > maxArea) {
- maxArea = area;
- info.maxW = displayFrame.width();
- info.maxH = displayFrame.height();
+ auto updateInfoFn =
+ [&](const std::shared_ptr<compositionengine::Display>& compositionDisplay,
+ const frontend::LayerSnapshot& snapshot, const sp<LayerFE>& layerFe) {
+ if (snapshot.isVisible &&
+ compositionDisplay->includesLayer(snapshot.outputFilter)) {
+ if (isHdrLayer(snapshot)) {
+ const auto* outputLayer =
+ compositionDisplay->getOutputLayerForLayer(layerFe);
+ if (outputLayer) {
+ const float desiredHdrSdrRatio =
+ snapshot.desiredHdrSdrRatio <= 1.f
+ ? std::numeric_limits<float>::infinity()
+ : snapshot.desiredHdrSdrRatio;
+ info.mergeDesiredRatio(desiredHdrSdrRatio);
+ info.numberOfHdrLayers++;
+ const auto displayFrame = outputLayer->getState().displayFrame;
+ const int32_t area =
+ displayFrame.width() * displayFrame.height();
+ if (area > maxArea) {
+ maxArea = area;
+ info.maxW = displayFrame.width();
+ info.maxH = displayFrame.height();
+ }
+ }
}
}
- }
- }
- });
+ };
+
+ if (mLayerLifecycleManagerEnabled) {
+ mLayerSnapshotBuilder.forEachVisibleSnapshot(
+ [&, compositionDisplay = compositionDisplay](
+ std::unique_ptr<frontend::LayerSnapshot>& snapshot) {
+ auto it = mLegacyLayers.find(snapshot->sequence);
+ LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mLegacyLayers.end(),
+ "Couldnt find layer object for %s",
+ snapshot->getDebugString().c_str());
+ auto& legacyLayer = it->second;
+ sp<LayerFE> layerFe =
+ legacyLayer->getCompositionEngineLayerFE(snapshot->path);
+
+ updateInfoFn(compositionDisplay, *snapshot, layerFe);
+ });
+ } else {
+ mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
+ const auto layerFe = layer->getCompositionEngineLayerFE();
+ const frontend::LayerSnapshot& snapshot = *layer->getLayerSnapshot();
+ updateInfoFn(compositionDisplay, snapshot, layerFe);
+ });
+ }
listener->dispatchHdrLayerInfo(info);
}
}
@@ -2978,10 +3195,6 @@ void SurfaceFlinger::postComposition(PhysicalDisplayId pacesetterId,
}
}
- const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle);
- const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle);
- mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections);
-
if (hasPacesetterDisplay && !pacesetterDisplay->isPoweredOn()) {
getRenderEngine().cleanupPostRender();
return;
@@ -2990,23 +3203,6 @@ void SurfaceFlinger::postComposition(PhysicalDisplayId pacesetterId,
// Cleanup any outstanding resources due to rendering a prior frame.
getRenderEngine().cleanupPostRender();
- {
- std::lock_guard lock(mTexturePoolMutex);
- if (mTexturePool.size() < mTexturePoolSize) {
- const size_t refillCount = mTexturePoolSize - mTexturePool.size();
- const size_t offset = mTexturePool.size();
- mTexturePool.resize(mTexturePoolSize);
- getRenderEngine().genTextures(refillCount, mTexturePool.data() + offset);
- ATRACE_INT("TexturePoolSize", mTexturePool.size());
- } else if (mTexturePool.size() > mTexturePoolSize) {
- const size_t deleteCount = mTexturePool.size() - mTexturePoolSize;
- const size_t offset = mTexturePoolSize;
- getRenderEngine().deleteTextures(deleteCount, mTexturePool.data() + offset);
- mTexturePool.resize(mTexturePoolSize);
- ATRACE_INT("TexturePoolSize", mTexturePool.size());
- }
- }
-
if (mNumTrustedPresentationListeners > 0) {
// We avoid any reverse traversal upwards so this shouldn't be too expensive
traverseLegacyLayers([&](Layer* layer) {
@@ -3097,7 +3293,9 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes(
int attempt = 0;
constexpr int kMaxAttempts = 3;
do {
- hwcModes = getHwComposer().getModes(displayId);
+ hwcModes = getHwComposer().getModes(displayId,
+ scheduler::RefreshRateSelector::kMinSupportedFrameRate
+ .getPeriodNsecs());
activeModeHwcId = getHwComposer().getActiveMode(displayId);
const auto isActiveMode = [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) {
@@ -3139,6 +3337,7 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes(
.setPhysicalDisplayId(displayId)
.setResolution({hwcMode.width, hwcMode.height})
.setVsyncPeriod(hwcMode.vsyncPeriod)
+ .setVrrConfig(hwcMode.vrrConfig)
.setDpiX(hwcMode.dpiX)
.setDpiY(hwcMode.dpiY)
.setGroup(hwcMode.configGroup)
@@ -3244,6 +3443,7 @@ const char* SurfaceFlinger::processHotplug(PhysicalDisplayId displayId,
.hwcDisplayId = hwcDisplayId,
.activeMode = std::move(activeMode)};
state.isSecure = true; // All physical displays are currently considered secure.
+ state.isProtected = true;
state.displayName = std::move(info.name);
mCurrentState.displays.add(token, state);
@@ -3275,6 +3475,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
displayToken, compositionDisplay);
creationArgs.sequenceId = state.sequenceId;
creationArgs.isSecure = state.isSecure;
+ creationArgs.isProtected = state.isProtected;
creationArgs.displaySurface = displaySurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
@@ -3308,18 +3509,16 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
creationArgs.isPrimary = physical->id == getPrimaryDisplayIdLocked();
- if (useColorManagement) {
- mPhysicalDisplays.get(physical->id)
- .transform(&PhysicalDisplay::snapshotRef)
- .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) {
- for (const auto mode : snapshot.colorModes()) {
- creationArgs.hasWideColorGamut |= ui::isWideColorMode(mode);
- creationArgs.hwcColorModes
- .emplace(mode,
- getHwComposer().getRenderIntents(physical->id, mode));
- }
- }));
- }
+ mPhysicalDisplays.get(physical->id)
+ .transform(&PhysicalDisplay::snapshotRef)
+ .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) {
+ for (const auto mode : snapshot.colorModes()) {
+ creationArgs.hasWideColorGamut |= ui::isWideColorMode(mode);
+ creationArgs.hwcColorModes
+ .emplace(mode,
+ getHwComposer().getRenderIntents(physical->id, mode));
+ }
+ }));
}
if (const auto id = HalDisplayId::tryCast(compositionDisplay->getId())) {
@@ -3360,12 +3559,11 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
}
display->getCompositionDisplay()->setColorProfile(
compositionengine::Output::ColorProfile{defaultColorMode, defaultDataSpace,
- RenderIntent::COLORIMETRIC,
- Dataspace::UNKNOWN});
+ RenderIntent::COLORIMETRIC});
if (const auto& physical = state.physical) {
const auto& mode = *physical->activeMode;
- display->setActiveMode(mode.getId(), mode.getFps(), mode.getFps());
+ display->setActiveMode(mode.getId(), mode.getVsyncRate(), mode.getVsyncRate());
}
display->setLayerFilter(makeLayerFilterForDisplay(display->getId(), state.layerStack));
@@ -3409,6 +3607,7 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
builder.setPixels(resolution);
builder.setIsSecure(state.isSecure);
+ builder.setIsProtected(state.isProtected);
builder.setPowerAdvisor(mPowerAdvisor.get());
builder.setName(state.displayName);
auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
@@ -3505,8 +3704,6 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
// Recreate the DisplayDevice if the surface or sequence ID changed.
if (currentBinder != drawingBinder || currentState.sequenceId != drawingState.sequenceId) {
- getRenderEngine().cleanFramebufferCache();
-
if (const auto display = getDisplayDeviceLocked(displayToken)) {
display->disconnect();
if (display->isVirtual()) {
@@ -3683,7 +3880,6 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) {
// first frame before the display is available, we rely
// on WMS and DMS to provide the right information
// so the client can calculate the hint.
- ALOGV("Skipping reporting transform hint update for %s", layer->getDebugName());
layer->skipReportingTransformHint();
} else {
layer->updateTransformHint(hintDisplay->getTransformHint());
@@ -3891,7 +4087,7 @@ void SurfaceFlinger::requestDisplayModes(std::vector<display::DisplayModeRequest
}
if (display->refreshRateSelector().isModeAllowed(request.mode)) {
- setDesiredActiveMode(std::move(request));
+ setDesiredMode(std::move(request));
} else {
ALOGV("%s: Mode %d is disallowed for display %s", __func__, modePtr->getId().value(),
to_string(displayId).c_str());
@@ -3912,6 +4108,77 @@ void SurfaceFlinger::notifyCpuLoadUp() {
mPowerAdvisor->notifyCpuLoadUp();
}
+void SurfaceFlinger::onChoreographerAttached() {
+ ATRACE_CALL();
+ if (mLayerLifecycleManagerEnabled) {
+ mUpdateAttachedChoreographer = true;
+ scheduleCommit(FrameHint::kNone);
+ }
+}
+
+void SurfaceFlinger::onVsyncGenerated(TimePoint expectedPresentTime,
+ ftl::NonNull<DisplayModePtr> modePtr, Fps renderRate) {
+ const auto vsyncPeriod = modePtr->getVsyncRate().getPeriod();
+ const auto timeoutOpt = [&]() -> std::optional<Period> {
+ const auto vrrConfig = modePtr->getVrrConfig();
+ if (!vrrConfig) return std::nullopt;
+
+ const auto notifyExpectedPresentConfig =
+ modePtr->getVrrConfig()->notifyExpectedPresentConfig;
+ if (!notifyExpectedPresentConfig) return std::nullopt;
+ return Period::fromNs(notifyExpectedPresentConfig->notifyExpectedPresentTimeoutNs);
+ }();
+
+ notifyExpectedPresentIfRequired(modePtr->getPhysicalDisplayId(), vsyncPeriod,
+ expectedPresentTime, renderRate, timeoutOpt);
+}
+
+void SurfaceFlinger::notifyExpectedPresentIfRequired(PhysicalDisplayId displayId,
+ Period vsyncPeriod,
+ TimePoint expectedPresentTime,
+ Fps frameInterval,
+ std::optional<Period> timeoutOpt) {
+ {
+ auto& data = mNotifyExpectedPresentMap[displayId];
+ const auto lastExpectedPresentTimestamp = data.lastExpectedPresentTimestamp.load();
+ const auto lastFrameInterval = data.lastFrameInterval;
+ data.lastFrameInterval = frameInterval;
+ const auto threshold = Duration::fromNs(vsyncPeriod.ns() / 2);
+
+ const constexpr nsecs_t kOneSecondNs =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
+ const auto timeout = Period::fromNs(timeoutOpt && timeoutOpt->ns() > 0 ? timeoutOpt->ns()
+ : kOneSecondNs);
+ const bool frameIntervalIsOnCadence =
+ isFrameIntervalOnCadence(expectedPresentTime, lastExpectedPresentTimestamp,
+ lastFrameInterval, timeout, threshold);
+
+ const bool expectedPresentWithinTimeout =
+ isExpectedPresentWithinTimeout(expectedPresentTime, lastExpectedPresentTimestamp,
+ timeoutOpt, threshold);
+
+ using fps_approx_ops::operator!=;
+ if (frameIntervalIsOnCadence && frameInterval != lastFrameInterval) {
+ data.lastExpectedPresentTimestamp = expectedPresentTime;
+ }
+
+ if (expectedPresentWithinTimeout && frameIntervalIsOnCadence) {
+ return;
+ }
+ data.lastExpectedPresentTimestamp = expectedPresentTime;
+ }
+
+ const char* const whence = __func__;
+ static_cast<void>(mScheduler->schedule([=, this]() FTL_FAKE_GUARD(kMainThreadContext) {
+ const auto status = getHwComposer().notifyExpectedPresent(displayId, expectedPresentTime,
+ frameInterval);
+ if (status != NO_ERROR) {
+ ALOGE("%s failed to notifyExpectedPresentHint for display %" PRId64, whence,
+ displayId.value);
+ }
+ }));
+}
+
void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
using namespace scheduler;
@@ -3926,9 +4193,12 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
FeatureFlags features;
- if (sysprop::use_content_detection_for_refresh_rate(false)) {
+ const auto defaultContentDetectionValue =
+ FlagManager::getInstance().enable_fro_dependent_features() &&
+ sysprop::enable_frame_rate_override(true);
+ if (sysprop::use_content_detection_for_refresh_rate(defaultContentDetectionValue)) {
features |= Feature::kContentDetection;
- if (base::GetBoolProperty("debug.sf.enable_small_dirty_detection"s, false)) {
+ if (FlagManager::getInstance().enable_small_area_detection()) {
features |= Feature::kSmallDirtyContentDetection;
}
}
@@ -3950,8 +4220,12 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
mScheduler = std::make_unique<Scheduler>(static_cast<ICompositor&>(*this),
static_cast<ISchedulerCallback&>(*this), features,
- std::move(modulatorPtr));
+ std::move(modulatorPtr),
+ static_cast<IVsyncTrackerCallback&>(*this));
mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
+ if (FlagManager::getInstance().vrr_config()) {
+ mScheduler->setRenderRate(display->getPhysicalId(), activeMode.fps);
+ }
mScheduler->startTimers();
const auto configs = mVsyncConfiguration->getCurrentConfigs();
@@ -3974,6 +4248,9 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
sp<RegionSamplingThread>::make(*this,
RegionSamplingThread::EnvironmentTimingTunables());
mFpsReporter = sp<FpsReporter>::make(*mFrameTimeline, *this);
+
+ mIsHotplugErrViaNegVsync =
+ base::GetBoolProperty("debug.sf.hwc_hotplug_error_via_neg_vsync"s, false);
}
void SurfaceFlinger::updatePhaseConfiguration(Fps refreshRate) {
@@ -4298,18 +4575,16 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelin
return TransactionReadiness::Ready;
}
-TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck(
+TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheckLegacy(
const TransactionHandler::TransactionFlushState& flushState) {
using TransactionReadiness = TransactionHandler::TransactionReadiness;
auto ready = TransactionReadiness::Ready;
- flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const layer_state_t& s,
- const std::shared_ptr<
- renderengine::
- ExternalTexture>&
- externalTexture)
- -> bool {
- sp<Layer> layer = LayerHandle::getLayer(s.surface);
+ flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const ResolvedComposerState&
+ resolvedState) -> bool {
+ sp<Layer> layer = LayerHandle::getLayer(resolvedState.state.surface);
+
const auto& transaction = *flushState.transaction;
+ const auto& s = resolvedState.state;
// check for barrier frames
if (s.bufferData->hasBarrier) {
// The current producerId is already a newer producer than the buffer that has a
@@ -4317,7 +4592,7 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC
// don't wait on the barrier since we know that's stale information.
if (layer->getDrawingState().barrierProducerId > s.bufferData->producerId) {
layer->callReleaseBufferCallback(s.bufferData->releaseBufferListener,
- externalTexture->getBuffer(),
+ resolvedState.externalTexture->getBuffer(),
s.bufferData->frameNumber,
s.bufferData->acquireFence);
// Delete the entire state at this point and not just release the buffer because
@@ -4354,18 +4629,17 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC
return TraverseBuffersReturnValues::STOP_TRAVERSAL;
}
- // ignore the acquire fence if LatchUnsignaledConfig::Always is set.
- const bool checkAcquireFence = enableLatchUnsignaledConfig != LatchUnsignaledConfig::Always;
const bool acquireFenceAvailable = s.bufferData &&
s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
s.bufferData->acquireFence;
- const bool fenceSignaled = !checkAcquireFence || !acquireFenceAvailable ||
+ const bool fenceSignaled = !acquireFenceAvailable ||
s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled;
if (!fenceSignaled) {
// check fence status
- const bool allowLatchUnsignaled =
- shouldLatchUnsignaled(layer, s, transaction.states.size(),
- flushState.firstTransaction);
+ const bool allowLatchUnsignaled = shouldLatchUnsignaled(s, transaction.states.size(),
+ flushState.firstTransaction) &&
+ layer->isSimpleBufferUpdate(s);
+
if (allowLatchUnsignaled) {
ATRACE_FORMAT("fence unsignaled try allowLatchUnsignaled %s",
layer->getDebugName());
@@ -4394,15 +4668,121 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC
return ready;
}
+TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck(
+ const TransactionHandler::TransactionFlushState& flushState) {
+ using TransactionReadiness = TransactionHandler::TransactionReadiness;
+ auto ready = TransactionReadiness::Ready;
+ flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const ResolvedComposerState&
+ resolvedState) -> bool {
+ const frontend::RequestedLayerState* layer =
+ mLayerLifecycleManager.getLayerFromId(resolvedState.layerId);
+ const auto& transaction = *flushState.transaction;
+ const auto& s = resolvedState.state;
+ // check for barrier frames
+ if (s.bufferData->hasBarrier) {
+ // The current producerId is already a newer producer than the buffer that has a
+ // barrier. This means the incoming buffer is older and we can release it here. We
+ // don't wait on the barrier since we know that's stale information.
+ if (layer->barrierProducerId > s.bufferData->producerId) {
+ if (s.bufferData->releaseBufferListener) {
+ uint32_t currentMaxAcquiredBufferCount =
+ getMaxAcquiredBufferCountForCurrentRefreshRate(layer->ownerUid.val());
+ ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64,
+ layer->name.c_str(), s.bufferData->frameNumber);
+ s.bufferData->releaseBufferListener
+ ->onReleaseBuffer({resolvedState.externalTexture->getBuffer()->getId(),
+ s.bufferData->frameNumber},
+ s.bufferData->acquireFence
+ ? s.bufferData->acquireFence
+ : Fence::NO_FENCE,
+ currentMaxAcquiredBufferCount);
+ }
+
+ // Delete the entire state at this point and not just release the buffer because
+ // everything associated with the Layer in this Transaction is now out of date.
+ ATRACE_FORMAT("DeleteStaleBuffer %s barrierProducerId:%d > %d", layer->name.c_str(),
+ layer->barrierProducerId, s.bufferData->producerId);
+ return TraverseBuffersReturnValues::DELETE_AND_CONTINUE_TRAVERSAL;
+ }
+
+ if (layer->barrierFrameNumber < s.bufferData->barrierFrameNumber) {
+ const bool willApplyBarrierFrame =
+ flushState.bufferLayersReadyToPresent.contains(s.surface.get()) &&
+ ((flushState.bufferLayersReadyToPresent.get(s.surface.get()) >=
+ s.bufferData->barrierFrameNumber));
+ if (!willApplyBarrierFrame) {
+ ATRACE_FORMAT("NotReadyBarrier %s barrierFrameNumber:%" PRId64 " > %" PRId64,
+ layer->name.c_str(), layer->barrierFrameNumber,
+ s.bufferData->barrierFrameNumber);
+ ready = TransactionReadiness::NotReadyBarrier;
+ return TraverseBuffersReturnValues::STOP_TRAVERSAL;
+ }
+ }
+ }
+
+ // If backpressure is enabled and we already have a buffer to commit, keep
+ // the transaction in the queue.
+ const bool hasPendingBuffer =
+ flushState.bufferLayersReadyToPresent.contains(s.surface.get());
+ if (layer->backpressureEnabled() && hasPendingBuffer && transaction.isAutoTimestamp) {
+ ATRACE_FORMAT("hasPendingBuffer %s", layer->name.c_str());
+ ready = TransactionReadiness::NotReady;
+ return TraverseBuffersReturnValues::STOP_TRAVERSAL;
+ }
+
+ const bool acquireFenceAvailable = s.bufferData &&
+ s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
+ s.bufferData->acquireFence;
+ const bool fenceSignaled = !acquireFenceAvailable ||
+ s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled;
+ if (!fenceSignaled) {
+ // check fence status
+ const bool allowLatchUnsignaled = shouldLatchUnsignaled(s, transaction.states.size(),
+ flushState.firstTransaction) &&
+ layer->isSimpleBufferUpdate(s);
+ if (allowLatchUnsignaled) {
+ ATRACE_FORMAT("fence unsignaled try allowLatchUnsignaled %s", layer->name.c_str());
+ ready = TransactionReadiness::NotReadyUnsignaled;
+ } else {
+ ready = TransactionReadiness::NotReady;
+ auto& listener = s.bufferData->releaseBufferListener;
+ if (listener &&
+ (flushState.queueProcessTime - transaction.postTime) >
+ std::chrono::nanoseconds(4s).count()) {
+ mTransactionHandler
+ .onTransactionQueueStalled(transaction.id,
+ {.pid = layer->ownerPid.val(),
+ .layerId = layer->id,
+ .layerName = layer->name,
+ .bufferId = s.bufferData->getId(),
+ .frameNumber = s.bufferData->frameNumber});
+ }
+ ATRACE_FORMAT("fence unsignaled %s", layer->name.c_str());
+ return TraverseBuffersReturnValues::STOP_TRAVERSAL;
+ }
+ }
+ return TraverseBuffersReturnValues::CONTINUE_TRAVERSAL;
+ });
+ return ready;
+}
+
void SurfaceFlinger::addTransactionReadyFilters() {
mTransactionHandler.addTransactionReadyFilter(
std::bind(&SurfaceFlinger::transactionReadyTimelineCheck, this, std::placeholders::_1));
- mTransactionHandler.addTransactionReadyFilter(
- std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this, std::placeholders::_1));
+ if (mLayerLifecycleManagerEnabled) {
+ mTransactionHandler.addTransactionReadyFilter(
+ std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this,
+ std::placeholders::_1));
+ } else {
+ mTransactionHandler.addTransactionReadyFilter(
+ std::bind(&SurfaceFlinger::transactionReadyBufferCheckLegacy, this,
+ std::placeholders::_1));
+ }
}
// For tests only
bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) {
+ mTransactionHandler.collectTransactions();
std::vector<TransactionState> transactions = mTransactionHandler.flushTransactions();
return applyTransactions(transactions, vsyncId);
}
@@ -4449,24 +4829,19 @@ bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId
return false;
}
- const Duration earlyLatchVsyncThreshold = mScheduler->getVsyncSchedule()->period() / 2;
+ const Duration earlyLatchVsyncThreshold = mScheduler->getVsyncSchedule()->minFramePeriod() / 2;
return predictedPresentTime >= expectedPresentTime &&
predictedPresentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
}
-bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state,
- size_t numStates, bool firstTransaction) const {
+bool SurfaceFlinger::shouldLatchUnsignaled(const layer_state_t& state, size_t numStates,
+ bool firstTransaction) const {
if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
ATRACE_FORMAT_INSTANT("%s: false (LatchUnsignaledConfig::Disabled)", __func__);
return false;
}
- if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) {
- ATRACE_FORMAT_INSTANT("%s: true (LatchUnsignaledConfig::Always)", __func__);
- return true;
- }
-
// We only want to latch unsignaled when a single layer is updated in this
// transaction (i.e. not a blast sync transaction).
if (numStates != 1) {
@@ -4493,7 +4868,7 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_s
}
}
- return layer->isSimpleBufferUpdate(state);
+ return true;
}
status_t SurfaceFlinger::setTransactionState(
@@ -4635,7 +5010,7 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin
for (const auto& listener : listenerCallbacks) {
mTransactionCallbackInvoker.addEmptyTransaction(listener);
}
-
+ nsecs_t now = systemTime();
uint32_t clientStateFlags = 0;
for (auto& resolvedState : states) {
if (mLegacyFrontEndEnabled) {
@@ -4656,8 +5031,9 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin
.transform = layer->getTransform(),
.setFrameRateVote = layer->getFrameRateForLayerTree(),
.frameRateSelectionPriority = layer->getFrameRateSelectionPriority(),
+ .isFrontBuffered = layer->isFrontBuffered(),
};
- layer->recordLayerHistoryAnimationTx(layerProps);
+ layer->recordLayerHistoryAnimationTx(layerProps, now);
}
}
}
@@ -4971,7 +5347,8 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime
if (layer->setApi(s.api)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eSidebandStreamChanged) {
- if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
+ if (layer->setSidebandStream(s.sidebandStream, frameTimelineInfo, postTime))
+ flags |= eTraversalNeeded;
}
if (what & layer_state_t::eInputInfoChanged) {
layer->setInputInfo(*s.windowInfoHandle->getInfo());
@@ -5021,9 +5398,23 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime
const auto strategy =
Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy);
- if (layer->setFrameRate(
- Layer::FrameRate(Fps::fromValue(s.frameRate), compatibility, strategy))) {
- flags |= eTraversalNeeded;
+ if (layer->setFrameRate(Layer::FrameRate::FrameRateVote(Fps::fromValue(s.frameRate),
+ compatibility, strategy))) {
+ flags |= eTraversalNeeded;
+ }
+ }
+ if (what & layer_state_t::eFrameRateCategoryChanged) {
+ const FrameRateCategory category = Layer::FrameRate::convertCategory(s.frameRateCategory);
+ if (layer->setFrameRateCategory(category, s.frameRateCategorySmoothSwitchOnly)) {
+ flags |= eTraversalNeeded;
+ }
+ }
+ if (what & layer_state_t::eFrameRateSelectionStrategyChanged) {
+ const scheduler::LayerInfo::FrameRateSelectionStrategy strategy =
+ scheduler::LayerInfo::convertFrameRateSelectionStrategy(
+ s.frameRateSelectionStrategy);
+ if (layer->setFrameRateSelectionStrategy(strategy)) {
+ flags |= eTraversalNeeded;
}
}
if (what & layer_state_t::eFixedTransformHintChanged) {
@@ -5205,11 +5596,27 @@ uint32_t SurfaceFlinger::updateLayerCallbacksAndStats(const FrameTimelineInfo& f
// TODO(b/238781169) remove after screenshot refactor, currently screenshots
// requires to read drawing state from binder thread. So we need to fix that
// before removing this.
+ if (what & layer_state_t::eBufferTransformChanged) {
+ if (layer->setTransform(s.bufferTransform)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eTransformToDisplayInverseChanged) {
+ if (layer->setTransformToDisplayInverse(s.transformToDisplayInverse))
+ flags |= eTraversalNeeded;
+ }
if (what & layer_state_t::eCropChanged) {
if (layer->setCrop(s.crop)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eSidebandStreamChanged) {
- if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
+ if (layer->setSidebandStream(s.sidebandStream, frameTimelineInfo, postTime))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eDataspaceChanged) {
+ if (layer->setDataspace(s.dataspace)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eExtendedRangeBrightnessChanged) {
+ if (layer->setExtendedRangeBrightness(s.currentHdrSdrRatio, s.desiredHdrSdrRatio)) {
+ flags |= eTraversalNeeded;
+ }
}
if (what & layer_state_t::eBufferChanged) {
std::optional<ui::Transform::RotationFlags> transformHint = std::nullopt;
@@ -5385,7 +5792,6 @@ status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, gui::CreateSurface
status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* handle,
sp<Layer>* outLayer) {
- args.textureName = getNewTexture();
*outLayer = getFactory().createBufferStateLayer(args);
*handle = (*outLayer)->getHandle();
return NO_ERROR;
@@ -5407,7 +5813,7 @@ void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) {
void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer, uint32_t layerId) {
{
std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
- mDestroyedHandles.emplace_back(layerId);
+ mDestroyedHandles.emplace_back(layerId, layer->getDebugName());
}
mTransactionHandler.onLayerDestroyed(layerId);
@@ -5492,7 +5898,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal:
display->setPowerMode(mode);
- const auto refreshRate = display->refreshRateSelector().getActiveMode().modePtr->getFps();
+ const auto activeMode = display->refreshRateSelector().getActiveMode().modePtr;
if (!currentModeOpt || *currentModeOpt == hal::PowerMode::OFF) {
// Turn on the display
@@ -5521,22 +5927,25 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal:
}
getHwComposer().setPowerMode(displayId, mode);
- if (displayId == mActiveDisplayId && mode != hal::PowerMode::DOZE_SUSPEND) {
+ if (mode != hal::PowerMode::DOZE_SUSPEND &&
+ (displayId == mActiveDisplayId || FlagManager::getInstance().multithreaded_present())) {
const bool enable =
mScheduler->getVsyncSchedule(displayId)->getPendingHardwareVsyncState();
requestHardwareVsync(displayId, enable);
- mScheduler->enableSyntheticVsync(false);
+ if (displayId == mActiveDisplayId) {
+ mScheduler->enableSyntheticVsync(false);
+ }
constexpr bool kAllowToEnable = true;
- mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, refreshRate);
+ mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, activeMode.get());
}
mVisibleRegionsDirty = true;
scheduleComposite(FrameHint::kActive);
} else if (mode == hal::PowerMode::OFF) {
+ const bool currentModeNotDozeSuspend = (*currentModeOpt != hal::PowerMode::DOZE_SUSPEND);
// Turn off the display
-
if (displayId == mActiveDisplayId) {
if (const auto display = getActivatableDisplay()) {
onActiveDisplayChangedLocked(activeDisplay.get(), *display);
@@ -5550,14 +5959,24 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal:
strerror(errno));
}
- if (*currentModeOpt != hal::PowerMode::DOZE_SUSPEND) {
- mScheduler->disableHardwareVsync(displayId, true);
+ if (currentModeNotDozeSuspend) {
+ if (!FlagManager::getInstance().multithreaded_present()) {
+ mScheduler->disableHardwareVsync(displayId, true);
+ }
mScheduler->enableSyntheticVsync();
}
}
}
+ if (currentModeNotDozeSuspend && FlagManager::getInstance().multithreaded_present()) {
+ constexpr bool kDisallow = true;
+ mScheduler->disableHardwareVsync(displayId, kDisallow);
+ }
- // Disable VSYNC before turning off the display.
+ // We must disable VSYNC *before* turning off the display. The call to
+ // disableHardwareVsync, above, schedules a task to turn it off after
+ // this method returns. But by that point, the display is OFF, so the
+ // call just updates the pending state, without actually disabling
+ // VSYNC.
requestHardwareVsync(displayId, false);
getHwComposer().setPowerMode(displayId, mode);
@@ -5566,17 +5985,24 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal:
} else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
// Update display while dozing
getHwComposer().setPowerMode(displayId, mode);
- if (displayId == mActiveDisplayId && *currentModeOpt == hal::PowerMode::DOZE_SUSPEND) {
- ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON.");
- mVisibleRegionsDirty = true;
- scheduleRepaint();
- mScheduler->enableSyntheticVsync(false);
- mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */, refreshRate);
+ if (*currentModeOpt == hal::PowerMode::DOZE_SUSPEND &&
+ (displayId == mActiveDisplayId || FlagManager::getInstance().multithreaded_present())) {
+ if (displayId == mActiveDisplayId) {
+ ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON.");
+ mVisibleRegionsDirty = true;
+ scheduleRepaint();
+ mScheduler->enableSyntheticVsync(false);
+ }
+ constexpr bool kAllowToEnable = true;
+ mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, activeMode.get());
}
} else if (mode == hal::PowerMode::DOZE_SUSPEND) {
// Leave display going to doze
+ if (displayId == mActiveDisplayId || FlagManager::getInstance().multithreaded_present()) {
+ constexpr bool kDisallow = true;
+ mScheduler->disableHardwareVsync(displayId, kDisallow);
+ }
if (displayId == mActiveDisplayId) {
- mScheduler->disableHardwareVsync(displayId, true);
mScheduler->enableSyntheticVsync();
}
getHwComposer().setPowerMode(displayId, mode);
@@ -5623,81 +6049,60 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) {
!PermissionCache::checkPermission(sDump, pid, uid)) {
StringAppendF(&result, "Permission Denial: can't dump SurfaceFlinger from pid=%d, uid=%d\n",
pid, uid);
- } else {
- static const std::unordered_map<std::string, Dumper> dumpers = {
- {"--comp-displays"s, dumper(&SurfaceFlinger::dumpCompositionDisplays)},
- {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
- {"--displays"s, dumper(&SurfaceFlinger::dumpDisplays)},
- {"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)},
- {"--events"s, dumper(&SurfaceFlinger::dumpEvents)},
- {"--frametimeline"s, argsDumper(&SurfaceFlinger::dumpFrameTimeline)},
- {"--hwclayers"s, dumper(&SurfaceFlinger::dumpHwcLayersMinidumpLocked)},
- {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
- {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
- {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)},
- {"--planner"s, argsDumper(&SurfaceFlinger::dumpPlannerInfo)},
- {"--scheduler"s, dumper(&SurfaceFlinger::dumpScheduler)},
- {"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
- {"--vsync"s, dumper(&SurfaceFlinger::dumpVsync)},
- {"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
- };
-
- const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
-
- // Traversal of drawing state must happen on the main thread.
- // Otherwise, SortedVector may have shared ownership during concurrent
- // traversals, which can result in use-after-frees.
- std::string compositionLayers;
- mScheduler
- ->schedule([&] {
- StringAppendF(&compositionLayers, "Composition layers\n");
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- auto* compositionState = layer->getCompositionState();
- if (!compositionState || !compositionState->isVisible) return;
-
- android::base::StringAppendF(&compositionLayers, "* Layer %p (%s)\n", layer,
- layer->getDebugName() ? layer->getDebugName()
- : "<unknown>");
- compositionState->dump(compositionLayers);
- });
- })
- .get();
-
- bool dumpLayers = true;
- {
- TimedLock lock(mStateLock, s2ns(1), __func__);
- if (!lock.locked()) {
- StringAppendF(&result, "Dumping without lock after timeout: %s (%d)\n",
- strerror(-lock.status), lock.status);
- }
+ write(fd, result.c_str(), result.size());
+ return NO_ERROR;
+ }
- if (const auto it = dumpers.find(flag); it != dumpers.end()) {
- (it->second)(args, asProto, result);
- dumpLayers = false;
- } else if (!asProto) {
- dumpAllLocked(args, compositionLayers, result);
- }
- }
+ if (asProto && args.empty()) {
+ perfetto::protos::LayersTraceFileProto traceFileProto =
+ mLayerTracing.createTraceFileProto();
+ perfetto::protos::LayersSnapshotProto* layersTrace = traceFileProto.add_entry();
+ perfetto::protos::LayersProto layersProto = dumpProtoFromMainThread();
+ layersTrace->mutable_layers()->Swap(&layersProto);
+ auto displayProtos = dumpDisplayProto();
+ layersTrace->mutable_displays()->Swap(&displayProtos);
+ result.append(traceFileProto.SerializeAsString());
+ write(fd, result.c_str(), result.size());
+ return NO_ERROR;
+ }
- if (dumpLayers) {
- LayersTraceFileProto traceFileProto = mLayerTracing.createTraceFileProto();
- LayersTraceProto* layersTrace = traceFileProto.add_entry();
- LayersProto layersProto = dumpProtoFromMainThread();
- layersTrace->mutable_layers()->Swap(&layersProto);
- auto displayProtos = dumpDisplayProto();
- layersTrace->mutable_displays()->Swap(&displayProtos);
+ static const std::unordered_map<std::string, Dumper> dumpers = {
+ {"--comp-displays"s, dumper(&SurfaceFlinger::dumpCompositionDisplays)},
+ {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
+ {"--displays"s, dumper(&SurfaceFlinger::dumpDisplays)},
+ {"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)},
+ {"--events"s, dumper(&SurfaceFlinger::dumpEvents)},
+ {"--frametimeline"s, argsDumper(&SurfaceFlinger::dumpFrameTimeline)},
+ {"--frontend"s, mainThreadDumper(&SurfaceFlinger::dumpFrontEnd)},
+ {"--hdrinfo"s, dumper(&SurfaceFlinger::dumpHdrInfo)},
+ {"--hwclayers"s, mainThreadDumper(&SurfaceFlinger::dumpHwcLayersMinidump)},
+ {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
+ {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
+ {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)},
+ {"--planner"s, argsDumper(&SurfaceFlinger::dumpPlannerInfo)},
+ {"--scheduler"s, dumper(&SurfaceFlinger::dumpScheduler)},
+ {"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
+ {"--vsync"s, dumper(&SurfaceFlinger::dumpVsync)},
+ {"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
+ };
- if (asProto) {
- result.append(traceFileProto.SerializeAsString());
- } else {
- // Dump info that we need to access from the main thread
- const auto layerTree = LayerProtoParser::generateLayerTree(layersTrace->layers());
- result.append(LayerProtoParser::layerTreeToString(layerTree));
- result.append("\n");
- dumpOffscreenLayers(result);
- }
- }
+ const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
+ if (const auto it = dumpers.find(flag); it != dumpers.end()) {
+ (it->second)(args, asProto, result);
+ write(fd, result.c_str(), result.size());
+ return NO_ERROR;
}
+
+ // Traversal of drawing state must happen on the main thread.
+ // Otherwise, SortedVector may have shared ownership during concurrent
+ // traversals, which can result in use-after-frees.
+ std::string compositionLayers;
+ mScheduler
+ ->schedule([&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) {
+ dumpVisibleFrontEnd(compositionLayers);
+ })
+ .get();
+ dumpAll(args, compositionLayers, result);
write(fd, result.c_str(), result.size());
return NO_ERROR;
}
@@ -5880,7 +6285,6 @@ void SurfaceFlinger::dumpRawDisplayIdentificationData(const DumpArgs& args,
void SurfaceFlinger::dumpWideColorInfo(std::string& result) const {
StringAppendF(&result, "Device supports wide color: %d\n", mSupportsWideColor);
- StringAppendF(&result, "Device uses color management: %d\n", useColorManagement);
StringAppendF(&result, "DisplayColorSetting: %s\n",
decodeDisplayColorSetting(mDisplayColorSetting).c_str());
@@ -5901,7 +6305,93 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const {
result.append("\n");
}
-LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
+void SurfaceFlinger::dumpHdrInfo(std::string& result) const {
+ for (const auto& [displayId, listener] : mHdrLayerInfoListeners) {
+ StringAppendF(&result, "HDR events for display %" PRIu64 "\n", displayId.value);
+ listener->dump(result);
+ result.append("\n");
+ }
+}
+
+void SurfaceFlinger::dumpFrontEnd(std::string& result) {
+ std::ostringstream out;
+ out << "\nComposition list\n";
+ ui::LayerStack lastPrintedLayerStackHeader = ui::INVALID_LAYER_STACK;
+ for (const auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) {
+ if (lastPrintedLayerStackHeader != snapshot->outputFilter.layerStack) {
+ lastPrintedLayerStackHeader = snapshot->outputFilter.layerStack;
+ out << "LayerStack=" << lastPrintedLayerStackHeader.id << "\n";
+ }
+ out << " " << *snapshot << "\n";
+ }
+
+ out << "\nInput list\n";
+ lastPrintedLayerStackHeader = ui::INVALID_LAYER_STACK;
+ mLayerSnapshotBuilder.forEachInputSnapshot([&](const frontend::LayerSnapshot& snapshot) {
+ if (lastPrintedLayerStackHeader != snapshot.outputFilter.layerStack) {
+ lastPrintedLayerStackHeader = snapshot.outputFilter.layerStack;
+ out << "LayerStack=" << lastPrintedLayerStackHeader.id << "\n";
+ }
+ out << " " << snapshot << "\n";
+ });
+
+ out << "\nLayer Hierarchy\n"
+ << mLayerHierarchyBuilder.getHierarchy().dump() << "\nOffscreen Hierarchy\n"
+ << mLayerHierarchyBuilder.getOffscreenHierarchy().dump() << "\n\n";
+ result.append(out.str());
+}
+
+void SurfaceFlinger::dumpVisibleFrontEnd(std::string& result) {
+ if (!mLayerLifecycleManagerEnabled) {
+ StringAppendF(&result, "Composition layers\n");
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ auto* compositionState = layer->getCompositionState();
+ if (!compositionState || !compositionState->isVisible) return;
+ android::base::StringAppendF(&result, "* Layer %p (%s)\n", layer,
+ layer->getDebugName() ? layer->getDebugName()
+ : "<unknown>");
+ compositionState->dump(result);
+ });
+
+ StringAppendF(&result, "Offscreen Layers\n");
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ offscreenLayer->traverse(LayerVector::StateSet::Drawing,
+ [&](Layer* layer) { layer->dumpOffscreenDebugInfo(result); });
+ }
+ } else {
+ std::ostringstream out;
+ out << "\nComposition list\n";
+ ui::LayerStack lastPrintedLayerStackHeader = ui::INVALID_LAYER_STACK;
+ mLayerSnapshotBuilder.forEachVisibleSnapshot(
+ [&](std::unique_ptr<frontend::LayerSnapshot>& snapshot) {
+ if (snapshot->hasSomethingToDraw()) {
+ if (lastPrintedLayerStackHeader != snapshot->outputFilter.layerStack) {
+ lastPrintedLayerStackHeader = snapshot->outputFilter.layerStack;
+ out << "LayerStack=" << lastPrintedLayerStackHeader.id << "\n";
+ }
+ out << " " << *snapshot << "\n";
+ }
+ });
+
+ out << "\nInput list\n";
+ lastPrintedLayerStackHeader = ui::INVALID_LAYER_STACK;
+ mLayerSnapshotBuilder.forEachInputSnapshot([&](const frontend::LayerSnapshot& snapshot) {
+ if (lastPrintedLayerStackHeader != snapshot.outputFilter.layerStack) {
+ lastPrintedLayerStackHeader = snapshot.outputFilter.layerStack;
+ out << "LayerStack=" << lastPrintedLayerStackHeader.id << "\n";
+ }
+ out << " " << snapshot << "\n";
+ });
+
+ out << "\nLayer Hierarchy\n"
+ << mLayerHierarchyBuilder.getHierarchy() << "\nOffscreen Hierarchy\n"
+ << mLayerHierarchyBuilder.getOffscreenHierarchy() << "\n\n";
+ result = out.str();
+ dumpHwcLayersMinidump(result);
+ }
+}
+
+perfetto::protos::LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
std::unordered_set<uint64_t> stackIdsToSkip;
// Determine if virtual layers display should be skipped
@@ -5914,7 +6404,7 @@ LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
}
if (mLegacyFrontEndEnabled) {
- LayersProto layersProto;
+ perfetto::protos::LayersProto layersProto;
for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
if (stackIdsToSkip.find(layer->getLayerStack().id) != stackIdsToSkip.end()) {
continue;
@@ -5929,13 +6419,21 @@ LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
.generate(mLayerHierarchyBuilder.getHierarchy());
}
-google::protobuf::RepeatedPtrField<DisplayProto> SurfaceFlinger::dumpDisplayProto() const {
- google::protobuf::RepeatedPtrField<DisplayProto> displays;
+google::protobuf::RepeatedPtrField<perfetto::protos::DisplayProto>
+SurfaceFlinger::dumpDisplayProto() const {
+ google::protobuf::RepeatedPtrField<perfetto::protos::DisplayProto> displays;
for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
- DisplayProto* displayProto = displays.Add();
+ perfetto::protos::DisplayProto* displayProto = displays.Add();
displayProto->set_id(display->getId().value);
displayProto->set_name(display->getDisplayName());
displayProto->set_layer_stack(display->getLayerStack().id);
+
+ if (!display->isVirtual()) {
+ const auto dpi = display->refreshRateSelector().getActiveMode().modePtr->getDpi();
+ displayProto->set_dpi_x(dpi.x);
+ displayProto->set_dpi_y(dpi.y);
+ }
+
LayerProtoHelper::writeSizeToProto(display->getWidth(), display->getHeight(),
[&]() { return displayProto->mutable_size(); });
LayerProtoHelper::writeToProto(display->getLayerStackSpaceRect(), [&]() {
@@ -5952,10 +6450,11 @@ void SurfaceFlinger::dumpHwc(std::string& result) const {
getHwComposer().dump(result);
}
-void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags) const {
+void SurfaceFlinger::dumpOffscreenLayersProto(perfetto::protos::LayersProto& layersProto,
+ uint32_t traceFlags) const {
// Add a fake invisible root layer to the proto output and parent all the offscreen layers to
// it.
- LayerProto* rootProto = layersProto.add_layers();
+ perfetto::protos::LayerProto* rootProto = layersProto.add_layers();
const int32_t offscreenRootLayerId = INT32_MAX - 2;
rootProto->set_id(offscreenRootLayerId);
rootProto->set_name("Offscreen Root");
@@ -5966,12 +6465,12 @@ void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t
rootProto->add_children(offscreenLayer->sequence);
// Add layer
- LayerProto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags);
+ auto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags);
layerProto->set_parent(offscreenRootLayerId);
}
}
-LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
+perfetto::protos::LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
return mScheduler->schedule([=] { return dumpDrawingStateProto(traceFlags); }).get();
}
@@ -5989,8 +6488,8 @@ void SurfaceFlinger::dumpOffscreenLayers(std::string& result) {
result.append(future.get());
}
-void SurfaceFlinger::dumpHwcLayersMinidumpLocked(std::string& result) const {
- for (const auto& [token, display] : mDisplays) {
+void SurfaceFlinger::dumpHwcLayersMinidumpLockedLegacy(std::string& result) const {
+ for (const auto& [token, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
const auto displayId = HalDisplayId::tryCast(display->getId());
if (!displayId) {
continue;
@@ -6001,13 +6500,49 @@ void SurfaceFlinger::dumpHwcLayersMinidumpLocked(std::string& result) const {
Layer::miniDumpHeader(result);
const DisplayDevice& ref = *display;
- mDrawingState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, ref); });
+ mDrawingState.traverseInZOrder([&](Layer* layer) { layer->miniDumpLegacy(result, ref); });
result.append("\n");
}
}
-void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& compositionLayers,
- std::string& result) const {
+void SurfaceFlinger::dumpHwcLayersMinidump(std::string& result) const {
+ if (!mLayerLifecycleManagerEnabled) {
+ return dumpHwcLayersMinidumpLockedLegacy(result);
+ }
+ for (const auto& [token, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
+ const auto displayId = HalDisplayId::tryCast(display->getId());
+ if (!displayId) {
+ continue;
+ }
+
+ StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(),
+ displayId == mActiveDisplayId ? "active" : "inactive");
+ Layer::miniDumpHeader(result);
+
+ const DisplayDevice& ref = *display;
+ mLayerSnapshotBuilder.forEachVisibleSnapshot([&](const frontend::LayerSnapshot& snapshot) {
+ if (!snapshot.hasSomethingToDraw() ||
+ ref.getLayerStack() != snapshot.outputFilter.layerStack) {
+ return;
+ }
+ auto it = mLegacyLayers.find(snapshot.sequence);
+ LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mLegacyLayers.end(),
+ "Couldnt find layer object for %s",
+ snapshot.getDebugString().c_str());
+ it->second->miniDump(result, snapshot, ref);
+ });
+ result.append("\n");
+ }
+}
+
+void SurfaceFlinger::dumpAll(const DumpArgs& args, const std::string& compositionLayers,
+ std::string& result) const {
+ TimedLock lock(mStateLock, s2ns(1), __func__);
+ if (!lock.locked()) {
+ StringAppendF(&result, "Dumping without lock after timeout: %s (%d)\n",
+ strerror(-lock.status), lock.status);
+ }
+
const bool colorize = !args.empty() && args[0] == String16("--color");
Colorizer colorizer(colorize);
@@ -6032,6 +6567,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp
result.append("\nWide-Color information:\n");
dumpWideColorInfo(result);
+ dumpHdrInfo(result);
+
colorizer.bold(result);
result.append("Sync configuration: ");
colorizer.reset(result);
@@ -6050,7 +6587,10 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp
* Dump the visible layer list
*/
colorizer.bold(result);
- StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers.load());
+ StringAppendF(&result, "SurfaceFlinger New Frontend Enabled:%s\n",
+ mLayerLifecycleManagerEnabled ? "true" : "false");
+ StringAppendF(&result, "Active Layers - layers with client handles (count = %zu)\n",
+ mNumLayers.load());
colorizer.reset(result);
result.append(compositionLayers);
@@ -6090,7 +6630,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp
std::string fps, xDpi, yDpi;
if (const auto activeModePtr =
display->refreshRateSelector().getActiveMode().modePtr.get()) {
- fps = to_string(activeModePtr->getFps());
+ fps = to_string(activeModePtr->getVsyncRate());
const auto dpi = activeModePtr->getDpi();
xDpi = base::StringPrintf("%.2f", dpi.x);
@@ -6109,11 +6649,6 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp
StringAppendF(&result, " transaction time: %f us\n", inTransactionDuration / 1000.0);
- /*
- * Tracing state
- */
- mLayerTracing.dump(result);
-
result.append("\nTransaction tracing: ");
if (mTransactionTracing) {
result.append("enabled\n");
@@ -6123,7 +6658,9 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp
}
result.push_back('\n');
- dumpHwcLayersMinidumpLocked(result);
+ if (mLegacyFrontEndEnabled) {
+ dumpHwcLayersMinidumpLockedLegacy(result);
+ }
{
DumpArgs plannerArgs;
@@ -6151,7 +6688,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp
/*
* Dump flag/property manager state
*/
- mFlagManager.dump(result);
+ FlagManager::getInstance().dump(result);
result.append(mTimeStats->miniDump());
result.append("\n");
@@ -6219,6 +6756,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
case GET_ACTIVE_DISPLAY_MODE:
case GET_DISPLAY_COLOR_MODES:
case GET_DISPLAY_MODES:
+ case GET_SCHEDULING_POLICY:
// Calling setTransactionState is safe, because you need to have been
// granted a reference to Client* and Handle* to do anything with it.
case SET_TRANSACTION_STATE: {
@@ -6300,9 +6838,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1042 are currently used for backdoors. The code
+ // Numbers from 1000 to 1045 are currently used for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1042) {
+ if (code >= 1000 && code <= 1045) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -6335,28 +6873,20 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
case 1001:
return NAME_NOT_FOUND;
case 1002: // Toggle flashing on surface damage.
- if (const int delay = data.readInt32(); delay > 0) {
- mDebugFlashDelay = delay;
- } else {
- mDebugFlashDelay = mDebugFlashDelay ? 0 : 1;
- }
- scheduleRepaint();
+ sfdo_setDebugFlash(data.readInt32());
return NO_ERROR;
case 1004: // Force composite ahead of next VSYNC.
case 1006:
- scheduleComposite(FrameHint::kActive);
+ sfdo_scheduleComposite();
return NO_ERROR;
case 1005: { // Force commit ahead of next VSYNC.
- Mutex::Autolock lock(mStateLock);
- setTransactionFlags(eTransactionNeeded | eDisplayTransactionNeeded |
- eTraversalNeeded);
+ sfdo_scheduleCommit();
return NO_ERROR;
}
case 1007: // Unused.
return NAME_NOT_FOUND;
case 1008: // Toggle forced GPU composition.
- mDebugDisableHWC = data.readInt32() != 0;
- scheduleRepaint();
+ sfdo_forceClientComposition(data.readInt32() != 0);
return NO_ERROR;
case 1009: // Toggle use of transform hint.
mDebugDisableTransformHint = data.readInt32() != 0;
@@ -6470,42 +7000,13 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
case 1024: {
return NAME_NOT_FOUND;
}
- case 1025: { // Set layer tracing
- n = data.readInt32();
- bool tracingEnabledChanged;
- if (n == 1) {
- int64_t fixedStartingTime = data.readInt64();
- ALOGD("LayerTracing enabled");
- tracingEnabledChanged = mLayerTracing.enable();
- if (tracingEnabledChanged) {
- const TimePoint startingTime = fixedStartingTime
- ? TimePoint::fromNs(fixedStartingTime)
- : TimePoint::now();
-
- mScheduler
- ->schedule([this, startingTime]() FTL_FAKE_GUARD(
- mStateLock) FTL_FAKE_GUARD(kMainThreadContext) {
- constexpr bool kVisibleRegionDirty = true;
- addToLayerTracing(kVisibleRegionDirty, startingTime,
- mLastCommittedVsyncId);
- })
- .wait();
- }
- } else if (n == 2) {
- std::string filename = std::string(data.readCString());
- ALOGD("LayerTracing disabled. Trace wrote to %s", filename.c_str());
- tracingEnabledChanged = mLayerTracing.disable(filename.c_str());
- } else {
- ALOGD("LayerTracing disabled");
- tracingEnabledChanged = mLayerTracing.disable();
- }
- mTracingEnabledChanged = tracingEnabledChanged;
- reply->writeInt32(NO_ERROR);
- return NO_ERROR;
+ // Deprecated, use perfetto to start/stop the layer tracing
+ case 1025: {
+ return NAME_NOT_FOUND;
}
- case 1026: { // Get layer tracing status
- reply->writeBool(mLayerTracing.isEnabled());
- return NO_ERROR;
+ // Deprecated, execute "adb shell perfetto --query" to see the ongoing tracing sessions
+ case 1026: {
+ return NAME_NOT_FOUND;
}
// Is a DisplayColorSetting supported?
case 1027: {
@@ -6517,8 +7018,6 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
DisplayColorSetting setting = static_cast<DisplayColorSetting>(data.readInt32());
switch (setting) {
case DisplayColorSetting::kManaged:
- reply->writeBool(useColorManagement);
- break;
case DisplayColorSetting::kUnmanaged:
reply->writeBool(true);
break;
@@ -6535,23 +7034,14 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
case 1028: { // Unused.
return NAME_NOT_FOUND;
}
- // Set buffer size for SF tracing (value in KB)
+ // Deprecated, use perfetto to set the active layer tracing buffer size
case 1029: {
- n = data.readInt32();
- if (n <= 0 || n > MAX_TRACING_MEMORY) {
- ALOGW("Invalid buffer size: %d KB", n);
- reply->writeInt32(BAD_VALUE);
- return BAD_VALUE;
- }
-
- ALOGD("Updating trace buffer to %d KB", n);
- mLayerTracing.setBufferSize(n * 1024);
- reply->writeInt32(NO_ERROR);
- return NO_ERROR;
+ return NAME_NOT_FOUND;
}
// Is device color managed?
case 1030: {
- reply->writeBool(useColorManagement);
+ // ColorDisplayManager stil calls this
+ reply->writeBool(true);
return NO_ERROR;
}
// Override default composition data space
@@ -6586,31 +7076,27 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
}
return NO_ERROR;
}
- // Set trace flags
+ // Deprecated, use perfetto to set layer trace flags
case 1033: {
- n = data.readUint32();
- ALOGD("Updating trace flags to 0x%x", n);
- mLayerTracing.setTraceFlags(n);
- reply->writeInt32(NO_ERROR);
- return NO_ERROR;
+ return NAME_NOT_FOUND;
}
case 1034: {
- auto future = mScheduler->schedule(
- [&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) {
- switch (n = data.readInt32()) {
- case 0:
- case 1:
- enableRefreshRateOverlay(static_cast<bool>(n));
- break;
- default:
- reply->writeBool(isRefreshRateOverlayEnabled());
- }
- });
-
- future.wait();
+ n = data.readInt32();
+ if (n == 0 || n == 1) {
+ sfdo_enableRefreshRateOverlay(static_cast<bool>(n));
+ } else {
+ Mutex::Autolock lock(mStateLock);
+ reply->writeBool(isRefreshRateOverlayEnabled());
+ }
return NO_ERROR;
}
case 1035: {
+ // Parameters:
+ // - (required) i32 mode id.
+ // - (optional) i64 display id. Using default display if not provided.
+ // - (optional) f min render rate. Using mode's fps is not provided.
+ // - (optional) f max render rate. Using mode's fps is not provided.
+
const int modeId = data.readInt32();
const auto display = [&]() -> sp<IBinder> {
@@ -6627,8 +7113,21 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
return nullptr;
}();
+ const auto getFps = [&] {
+ float value;
+ if (data.readFloat(&value) == NO_ERROR) {
+ return Fps::fromValue(value);
+ }
+
+ return Fps();
+ };
+
+ const auto minFps = getFps();
+ const auto maxFps = getFps();
+
mDebugDisplayModeSetByBackdoor = false;
- const status_t result = setActiveModeFromBackdoor(display, DisplayModeId{modeId});
+ const status_t result =
+ setActiveModeFromBackdoor(display, DisplayModeId{modeId}, minFps, maxFps);
mDebugDisplayModeSetByBackdoor = result == NO_ERROR;
return result;
}
@@ -6674,7 +7173,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
const hal::HWDisplayId hwcId =
(Mutex::Autolock(mStateLock), getHwComposer().getPrimaryHwcDisplayId());
- onComposerHalHotplug(hwcId, hal::Connection::CONNECTED);
+ onComposerHalHotplugEvent(hwcId, DisplayHotplugEvent::CONNECTED);
return NO_ERROR;
}
// Modify the max number of display frames stored within FrameTimeline
@@ -6739,11 +7238,14 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
}
case 1041: { // Transaction tracing
if (mTransactionTracing) {
- if (data.readInt32()) {
+ int arg = data.readInt32();
+ if (arg == -1) {
+ mScheduler->schedule([&]() { mTransactionTracing.reset(); }).get();
+ } else if (arg > 0) {
// Transaction tracing is always running but allow the user to temporarily
// increase the buffer when actively debugging.
mTransactionTracing->setBufferSize(
- TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE);
+ TransactionTracing::LEGACY_ACTIVE_TRACING_BUFFER_SIZE);
} else {
TransactionTraceWriter::getInstance().invoke("", /* overwrite= */ true);
mTransactionTracing->setBufferSize(
@@ -6753,16 +7255,131 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
reply->writeInt32(NO_ERROR);
return NO_ERROR;
}
- case 1042: { // Write layers trace or transaction trace to file
+ case 1042: { // Write transaction trace to file
if (mTransactionTracing) {
mTransactionTracing->writeToFile();
}
- if (mLayerTracingEnabled) {
- mLayerTracing.writeToFile();
- }
reply->writeInt32(NO_ERROR);
return NO_ERROR;
}
+ // hdr sdr ratio overlay
+ case 1043: {
+ auto future = mScheduler->schedule(
+ [&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) {
+ n = data.readInt32();
+ mHdrSdrRatioOverlay = n != 0;
+ switch (n) {
+ case 0:
+ case 1:
+ enableHdrSdrRatioOverlay(mHdrSdrRatioOverlay);
+ break;
+ default:
+ reply->writeBool(isHdrSdrRatioOverlayEnabled());
+ }
+ });
+ future.wait();
+ return NO_ERROR;
+ }
+
+ case 1044: { // Enable/Disable mirroring from one display to another
+ /*
+ * Mirror one display onto another.
+ * Ensure the source and destination displays are on.
+ * Commands:
+ * 0: Mirror one display to another
+ * 1: Disable mirroring to a previously mirrored display
+ * 2: Disable mirroring on previously mirrored displays
+ *
+ * Ex:
+ * Get the display ids:
+ * adb shell dumpsys SurfaceFlinger --display-id
+ * Mirror first display to the second:
+ * adb shell service call SurfaceFlinger 1044 i64 0 i64 4619827677550801152 i64
+ * 4619827677550801153
+ * Stop mirroring:
+ * adb shell service call SurfaceFlinger 1044 i64 1
+ */
+
+ int64_t arg0 = data.readInt64();
+
+ switch (arg0) {
+ case 0: {
+ // Mirror arg1 to arg2
+ int64_t arg1 = data.readInt64();
+ int64_t arg2 = data.readInt64();
+ // Enable mirroring for one display
+ const auto display1id = DisplayId::fromValue(arg1);
+ auto mirrorRoot = SurfaceComposerClient::getDefault()->mirrorDisplay(
+ display1id.value());
+ auto id2 = DisplayId::fromValue<PhysicalDisplayId>(arg2);
+ const auto token2 = getPhysicalDisplayToken(*id2);
+ ui::LayerStack layerStack;
+ {
+ Mutex::Autolock lock(mStateLock);
+ sp<DisplayDevice> display = getDisplayDeviceLocked(token2);
+ layerStack = display->getLayerStack();
+ }
+ SurfaceComposerClient::Transaction t;
+ t.setDisplayLayerStack(token2, layerStack);
+ t.setLayer(mirrorRoot, INT_MAX); // Top-most layer
+ t.setLayerStack(mirrorRoot, layerStack);
+ t.apply();
+
+ mMirrorMapForDebug.emplace_or_replace(arg2, mirrorRoot);
+ break;
+ }
+
+ case 1: {
+ // Disable mirroring for arg1
+ int64_t arg1 = data.readInt64();
+ mMirrorMapForDebug.erase(arg1);
+ break;
+ }
+
+ case 2: {
+ // Disable mirroring for all displays
+ mMirrorMapForDebug.clear();
+ break;
+ }
+
+ default:
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+ }
+ // Inject jank
+ // First argument is a float that describes the fraction of frame duration to jank by.
+ // Second argument is a delay in ms for triggering the jank. This is useful for working
+ // with tools that steal the adb connection. This argument is optional.
+ case 1045: {
+ if (FlagManager::getInstance().vrr_config()) {
+ float jankAmount = data.readFloat();
+ int32_t jankDelayMs = 0;
+ if (data.readInt32(&jankDelayMs) != NO_ERROR) {
+ jankDelayMs = 0;
+ }
+
+ const auto jankDelayDuration = Duration(std::chrono::milliseconds(jankDelayMs));
+
+ const bool jankAmountValid = jankAmount > 0.0 && jankAmount < 100.0;
+
+ if (!jankAmountValid) {
+ ALOGD("Ignoring invalid jank amount: %f", jankAmount);
+ reply->writeInt32(BAD_VALUE);
+ return BAD_VALUE;
+ }
+
+ (void)mScheduler->scheduleDelayed(
+ [&, jankAmount]() FTL_FAKE_GUARD(kMainThreadContext) {
+ mScheduler->injectPacesetterDelay(jankAmount);
+ scheduleComposite(FrameHint::kActive);
+ },
+ jankDelayDuration.ns());
+ reply->writeInt32(NO_ERROR);
+ return NO_ERROR;
+ }
+ return err;
+ }
}
}
return err;
@@ -6783,15 +7400,14 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) {
}
if (!display->isRefreshRateOverlayEnabled()) return;
- const auto desiredActiveMode = display->getDesiredActiveMode();
- const std::optional<DisplayModeId> desiredModeId = desiredActiveMode
- ? std::make_optional(desiredActiveMode->modeOpt->modePtr->getId())
-
- : std::nullopt;
+ const auto desiredModeIdOpt =
+ display->getDesiredMode().transform([](const display::DisplayModeRequest& request) {
+ return request.mode.modePtr->getId();
+ });
const bool timerExpired = mKernelIdleTimerEnabled && expired;
- if (display->onKernelTimerChanged(desiredModeId, timerExpired)) {
+ if (display->onKernelTimerChanged(desiredModeIdOpt, timerExpired)) {
mScheduler->scheduleFrame();
}
}));
@@ -7004,16 +7620,33 @@ ui::Dataspace pickBestDataspace(ui::Dataspace requestedDataspace, const DisplayD
} // namespace
-status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
- const sp<IScreenCaptureListener>& captureListener) {
+static void invokeScreenCaptureError(const status_t status,
+ const sp<IScreenCaptureListener>& captureListener) {
+ ScreenCaptureResults captureResults;
+ captureResults.fenceResult = base::unexpected(status);
+ captureListener->onScreenCaptureCompleted(captureResults);
+}
+
+void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
+ const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
status_t validate = validateScreenshotPermissions(args);
if (validate != OK) {
- return validate;
+ invokeScreenCaptureError(validate, captureListener);
+ return;
+ }
+
+ if (!args.displayToken) {
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
}
- if (!args.displayToken) return BAD_VALUE;
+ if (args.captureSecureLayers && !hasCaptureBlackoutContentPermission()) {
+ ALOGE("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT");
+ invokeScreenCaptureError(PERMISSION_DENIED, captureListener);
+ return;
+ }
wp<const DisplayDevice> displayWeak;
ui::LayerStack layerStack;
@@ -7022,7 +7655,10 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
{
Mutex::Autolock lock(mStateLock);
sp<DisplayDevice> display = getDisplayDeviceLocked(args.displayToken);
- if (!display) return NAME_NOT_FOUND;
+ if (!display) {
+ invokeScreenCaptureError(NAME_NOT_FOUND, captureListener);
+ return;
+ }
displayWeak = display;
layerStack = display->getLayerStack();
@@ -7037,15 +7673,15 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
excludeLayerIds.emplace(excludeLayer);
} else {
ALOGW("Invalid layer handle passed as excludeLayer to captureDisplay");
- return NAME_NOT_FOUND;
+ invokeScreenCaptureError(NAME_NOT_FOUND, captureListener);
+ return;
}
}
}
RenderAreaFuture renderAreaFuture = ftl::defer([=] {
return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize, args.dataspace,
- args.useIdentityTransform, args.hintForSeamlessTransition,
- args.captureSecureLayers);
+ args.hintForSeamlessTransition, args.captureSecureLayers);
});
GetLayerSnapshotsFunction getLayerSnapshots;
@@ -7060,14 +7696,12 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
getLayerSnapshots = RenderArea::fromTraverseLayersLambda(traverseLayers);
}
- auto future = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize,
- args.pixelFormat, args.allowProtected, args.grayscale,
- captureListener);
- return fenceStatus(future.get());
+ captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize, args.pixelFormat,
+ args.allowProtected, args.grayscale, captureListener);
}
-status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
- const sp<IScreenCaptureListener>& captureListener) {
+void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args,
+ const sp<IScreenCaptureListener>& captureListener) {
ui::LayerStack layerStack;
wp<const DisplayDevice> displayWeak;
ui::Size size;
@@ -7076,7 +7710,8 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
const auto display = getDisplayDeviceLocked(displayId);
if (!display) {
- return NAME_NOT_FOUND;
+ invokeScreenCaptureError(NAME_NOT_FOUND, captureListener);
+ return;
}
displayWeak = display;
@@ -7084,10 +7719,22 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
size = display->getLayerStackSpaceRect().getSize();
}
+ size.width *= args.frameScaleX;
+ size.height *= args.frameScaleY;
+
+ // We could query a real value for this but it'll be a long, long time until we support
+ // displays that need upwards of 1GB per buffer so...
+ constexpr auto kMaxTextureSize = 16384;
+ if (size.width <= 0 || size.height <= 0 || size.width >= kMaxTextureSize ||
+ size.height >= kMaxTextureSize) {
+ ALOGE("capture display resolved to invalid size %d x %d", size.width, size.height);
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
+ }
+
RenderAreaFuture renderAreaFuture = ftl::defer([=] {
- return DisplayRenderArea::create(displayWeak, Rect(), size, ui::Dataspace::UNKNOWN,
- false /* useIdentityTransform */,
- false /* hintForSeamlessTransition */,
+ return DisplayRenderArea::create(displayWeak, Rect(), size, args.dataspace,
+ args.hintForSeamlessTransition,
false /* captureSecureLayers */);
});
@@ -7104,25 +7751,25 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
if (captureListener == nullptr) {
ALOGE("capture screen must provide a capture listener callback");
- return BAD_VALUE;
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
}
constexpr bool kAllowProtected = false;
constexpr bool kGrayscale = false;
- auto future = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, size,
- ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale,
- captureListener);
- return fenceStatus(future.get());
+ captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, size, args.pixelFormat,
+ kAllowProtected, kGrayscale, captureListener);
}
-status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
- const sp<IScreenCaptureListener>& captureListener) {
+void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
+ const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
status_t validate = validateScreenshotPermissions(args);
if (validate != OK) {
- return validate;
+ invokeScreenCaptureError(validate, captureListener);
+ return;
}
ui::Size reqSize;
@@ -7131,8 +7778,11 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
std::unordered_set<uint32_t> excludeLayerIds;
ui::Dataspace dataspace = args.dataspace;
- // Call this before holding mStateLock to avoid any deadlocking.
- bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
+ if (args.captureSecureLayers && !hasCaptureBlackoutContentPermission()) {
+ ALOGE("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT");
+ invokeScreenCaptureError(PERMISSION_DENIED, captureListener);
+ return;
+ }
{
Mutex::Autolock lock(mStateLock);
@@ -7140,13 +7790,8 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
parent = LayerHandle::getLayer(args.layerHandle);
if (parent == nullptr) {
ALOGE("captureLayers called with an invalid or removed parent");
- return NAME_NOT_FOUND;
- }
-
- if (!canCaptureBlackoutContent &&
- parent->getDrawingState().flags & layer_state_t::eLayerSecure) {
- ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
- return PERMISSION_DENIED;
+ invokeScreenCaptureError(NAME_NOT_FOUND, captureListener);
+ return;
}
Rect parentSourceBounds = parent->getCroppedBufferSize(parent->getDrawingState());
@@ -7163,7 +7808,8 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
if (crop.isEmpty() || args.frameScaleX <= 0.0f || args.frameScaleY <= 0.0f) {
// Error out if the layer has no source bounds (i.e. they are boundless) and a source
// crop was not specified, or an invalid frame scale was provided.
- return BAD_VALUE;
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
}
reqSize = ui::Size(crop.width() * args.frameScaleX, crop.height() * args.frameScaleY);
@@ -7173,7 +7819,8 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
excludeLayerIds.emplace(excludeLayer);
} else {
ALOGW("Invalid layer handle passed as excludeLayer to captureLayers");
- return NAME_NOT_FOUND;
+ invokeScreenCaptureError(NAME_NOT_FOUND, captureListener);
+ return;
}
}
} // mStateLock
@@ -7181,7 +7828,8 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
// really small crop or frameScale
if (reqSize.width <= 0 || reqSize.height <= 0) {
ALOGW("Failed to captureLayes: crop or scale too small");
- return BAD_VALUE;
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
}
bool childrenOnly = args.childrenOnly;
@@ -7245,26 +7893,27 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
if (captureListener == nullptr) {
ALOGE("capture screen must provide a capture listener callback");
- return BAD_VALUE;
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
}
- auto future = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize,
- args.pixelFormat, args.allowProtected, args.grayscale,
- captureListener);
- return fenceStatus(future.get());
+ captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize, args.pixelFormat,
+ args.allowProtected, args.grayscale, captureListener);
}
-ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
- RenderAreaFuture renderAreaFuture, GetLayerSnapshotsFunction getLayerSnapshots,
- ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale,
- const sp<IScreenCaptureListener>& captureListener) {
+void SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
+ GetLayerSnapshotsFunction getLayerSnapshots,
+ ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
+ bool allowProtected, bool grayscale,
+ const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) {
ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32
") that exceeds render target size limit.",
bufferSize.getWidth(), bufferSize.getHeight());
- return ftl::yield<FenceResult>(base::unexpected(BAD_VALUE)).share();
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
}
// Loop over all visible layers to see whether there's any protected layer. A protected layer is
@@ -7287,12 +7936,11 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
})
.get();
}
-
+ const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected;
const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_TEXTURE |
- (hasProtectedLayer && allowProtected && supportsProtected
- ? GRALLOC_USAGE_PROTECTED
- : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ (isProtected ? GRALLOC_USAGE_PROTECTED
+ : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
sp<GraphicBuffer> buffer =
getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
static_cast<android_pixel_format>(reqPixelFormat),
@@ -7304,24 +7952,25 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
// Otherwise an irreponsible process may cause an SF crash by allocating
// too much.
ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus);
- return ftl::yield<FenceResult>(base::unexpected(bufferStatus)).share();
+ invokeScreenCaptureError(bufferStatus, captureListener);
+ return;
}
const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
renderengine::impl::ExternalTexture>(buffer, getRenderEngine(),
renderengine::impl::ExternalTexture::Usage::
WRITEABLE);
- return captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, texture,
- false /* regionSampling */, grayscale, captureListener);
+ auto fence = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, texture,
+ false /* regionSampling */, grayscale, isProtected,
+ captureListener);
+ fence.get();
}
ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
RenderAreaFuture renderAreaFuture, GetLayerSnapshotsFunction getLayerSnapshots,
const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
- bool grayscale, const sp<IScreenCaptureListener>& captureListener) {
+ bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
- bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
-
auto future = mScheduler->schedule(
[=, renderAreaFuture = std::move(renderAreaFuture)]() FTL_FAKE_GUARD(
kMainThreadContext) mutable -> ftl::SharedFuture<FenceResult> {
@@ -7338,9 +7987,9 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
ftl::SharedFuture<FenceResult> renderFuture;
renderArea->render([&]() FTL_FAKE_GUARD(kMainThreadContext) {
- renderFuture = renderScreenImpl(renderArea, getLayerSnapshots, buffer,
- canCaptureBlackoutContent, regionSampling,
- grayscale, captureResults);
+ renderFuture =
+ renderScreenImpl(renderArea, getLayerSnapshots, buffer, regionSampling,
+ grayscale, isProtected, captureResults);
});
if (captureListener) {
@@ -7367,9 +8016,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
std::shared_ptr<const RenderArea> renderArea, GetLayerSnapshotsFunction getLayerSnapshots,
- const std::shared_ptr<renderengine::ExternalTexture>& buffer,
- bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
- ScreenCaptureResults& captureResults) {
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
+ bool grayscale, bool isProtected, ScreenCaptureResults& captureResults) {
ATRACE_CALL();
auto layers = getLayerSnapshots();
@@ -7384,14 +8032,6 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
layerFE->mSnapshot->geomLayerTransform.inverse();
}
- // We allow the system server to take screenshots of secure layers for
- // use in situations like the Screen-rotation animation and place
- // the impetus on WindowManager to not persist them.
- if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) {
- ALOGW("FB is protected: PERMISSION_DENIED");
- return ftl::yield<FenceResult>(base::unexpected(PERMISSION_DENIED)).share();
- }
-
auto capturedBuffer = buffer;
auto requestedDataspace = renderArea->getReqDataSpace();
@@ -7426,7 +8066,10 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
renderArea->getHintForSeamlessTransition());
sdrWhitePointNits = state.sdrWhitePointNits;
- if (!captureResults.capturedHdrLayers) {
+ // TODO(b/298219334): Clean this up once we verify this doesn't break anything
+ static constexpr bool kScreenshotsDontDim = true;
+
+ if (kScreenshotsDontDim && !captureResults.capturedHdrLayers) {
displayBrightnessNits = sdrWhitePointNits;
} else {
displayBrightnessNits = state.displayBrightnessNits;
@@ -7469,9 +8112,9 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
};
auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace,
- sdrWhitePointNits, displayBrightnessNits, grayscale, layerFEs = copyLayerFEs(),
- layerStack, regionSampling, renderArea = std::move(renderArea),
- renderIntent]() -> FenceResult {
+ sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected,
+ layerFEs = copyLayerFEs(), layerStack, regionSampling,
+ renderArea = std::move(renderArea), renderIntent]() -> FenceResult {
std::unique_ptr<compositionengine::CompositionEngine> compositionEngine =
mFactory.createCompositionEngine();
compositionEngine->setRenderEngine(mRenderEngine.get());
@@ -7505,7 +8148,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
.regionSampling = regionSampling,
.treat170mAsSrgb = mTreat170mAsSrgb,
.dimInGammaSpaceForEnhancedScreenshots =
- dimInGammaSpaceForEnhancedScreenshots});
+ dimInGammaSpaceForEnhancedScreenshots,
+ .isProtected = isProtected});
const float colorSaturation = grayscale ? 0 : 1;
compositionengine::CompositionRefreshArgs refreshArgs{
@@ -7530,7 +8174,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
const bool renderEngineIsThreaded = [&]() {
using Type = renderengine::RenderEngine::RenderEngineType;
const auto type = mRenderEngine->getRenderEngineType();
- return type == Type::THREADED || type == Type::SKIA_GL_THREADED;
+ return type == Type::SKIA_GL_THREADED;
}();
auto presentFuture = renderEngineIsThreaded ? ftl::defer(std::move(present)).share()
: ftl::yield(present()).share();
@@ -7622,7 +8266,7 @@ ftl::Optional<scheduler::FrameRateMode> SurfaceFlinger::getPreferredDisplayMode(
return snapshot.displayModes().get(defaultModeId);
})
.transform([](const DisplayModePtr& modePtr) {
- return scheduler::FrameRateMode{modePtr->getFps(), ftl::as_non_null(modePtr)};
+ return scheduler::FrameRateMode{modePtr->getPeakFps(), ftl::as_non_null(modePtr)};
});
}
@@ -7701,15 +8345,22 @@ status_t SurfaceFlinger::applyRefreshRateSelectorPolicy(
auto preferredMode = std::move(*preferredModeOpt);
const auto preferredModeId = preferredMode.modePtr->getId();
+ const Fps preferredFps = preferredMode.fps;
ALOGV("Switching to Scheduler preferred mode %d (%s)", preferredModeId.value(),
- to_string(preferredMode.fps).c_str());
+ to_string(preferredFps).c_str());
if (!selector.isModeAllowed(preferredMode)) {
ALOGE("%s: Preferred mode %d is disallowed", __func__, preferredModeId.value());
return INVALID_OPERATION;
}
- setDesiredActiveMode({std::move(preferredMode), .emitEvent = true}, force);
+ setDesiredMode({std::move(preferredMode), .emitEvent = true}, force);
+
+ // Update the frameRateOverride list as the display render rate might have changed
+ if (mScheduler->updateFrameRateOverrides(scheduler::GlobalSignals{}, preferredFps)) {
+ triggerOnFrameRateOverridesChanged();
+ }
+
return NO_ERROR;
}
@@ -7810,6 +8461,7 @@ void SurfaceFlinger::onLayerDestroyed(Layer* layer) {
if (mTransactionTracing) {
mTransactionTracing->onLayerRemoved(layer->getSequence());
}
+ mScheduler->onLayerDestroyed(layer);
}
void SurfaceFlinger::onLayerUpdate() {
@@ -7862,32 +8514,41 @@ const std::unordered_map<std::string, uint32_t>& SurfaceFlinger::getGenericLayer
return genericLayerMetadataKeyMap;
}
-status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) {
+status_t SurfaceFlinger::setGameModeFrameRateOverride(uid_t uid, float frameRate) {
PhysicalDisplayId displayId = [&]() {
Mutex::Autolock lock(mStateLock);
return getDefaultDisplayDeviceLocked()->getPhysicalId();
}();
- mScheduler->setGameModeRefreshRateForUid(FrameRateOverride{static_cast<uid_t>(uid), frameRate});
+ mScheduler->setGameModeFrameRateForUid(FrameRateOverride{static_cast<uid_t>(uid), frameRate});
mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
return NO_ERROR;
}
+status_t SurfaceFlinger::setGameDefaultFrameRateOverride(uid_t uid, float frameRate) {
+ if (FlagManager::getInstance().game_default_frame_rate()) {
+ mScheduler->setGameDefaultFrameRateForUid(
+ FrameRateOverride{static_cast<uid_t>(uid), frameRate});
+ }
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::updateSmallAreaDetection(
- std::vector<std::pair<uid_t, float>>& uidThresholdMappings) {
- mScheduler->updateSmallAreaDetection(uidThresholdMappings);
+ std::vector<std::pair<int32_t, float>>& appIdThresholdMappings) {
+ mScheduler->updateSmallAreaDetection(appIdThresholdMappings);
return NO_ERROR;
}
-status_t SurfaceFlinger::setSmallAreaDetectionThreshold(uid_t uid, float threshold) {
- mScheduler->setSmallAreaDetectionThreshold(uid, threshold);
+status_t SurfaceFlinger::setSmallAreaDetectionThreshold(int32_t appId, float threshold) {
+ mScheduler->setSmallAreaDetectionThreshold(appId, threshold);
return NO_ERROR;
}
void SurfaceFlinger::enableRefreshRateOverlay(bool enable) {
bool setByHwc = getHwComposer().hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG);
for (const auto& [id, display] : mPhysicalDisplays) {
- if (display.snapshot().connectionType() == ui::DisplayConnectionType::Internal) {
+ if (display.snapshot().connectionType() == ui::DisplayConnectionType::Internal ||
+ FlagManager::getInstance().refresh_rate_overlay_on_external_display()) {
if (const auto device = getDisplayDeviceLocked(id)) {
const auto enableOverlay = [&](const bool setByHwc) FTL_FAKE_GUARD(
kMainThreadContext) {
@@ -7909,6 +8570,16 @@ void SurfaceFlinger::enableRefreshRateOverlay(bool enable) {
}
}
+void SurfaceFlinger::enableHdrSdrRatioOverlay(bool enable) {
+ for (const auto& [id, display] : mPhysicalDisplays) {
+ if (display.snapshot().connectionType() == ui::DisplayConnectionType::Internal) {
+ if (const auto device = getDisplayDeviceLocked(id)) {
+ device->enableHdrSdrRatioOverlay(enable);
+ }
+ }
+ }
+}
+
int SurfaceFlinger::getGpuContextPriority() {
return getRenderEngine().getContextPriority();
}
@@ -7919,7 +8590,7 @@ int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate,
if (presentLatency.count() % refreshRate.getPeriodNsecs()) {
pipelineDepth++;
}
- return std::max(1ll, pipelineDepth - 1);
+ return std::max(minAcquiredBuffers, static_cast<int64_t>(pipelineDepth - 1));
}
status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
@@ -8011,15 +8682,6 @@ void SurfaceFlinger::sample() {
void SurfaceFlinger::onActiveDisplaySizeChanged(const DisplayDevice& activeDisplay) {
mScheduler->onActiveDisplayAreaChanged(activeDisplay.getWidth() * activeDisplay.getHeight());
getRenderEngine().onActiveDisplaySizeChanged(activeDisplay.getSize());
-
- // Notify layers to update small dirty flag.
- if (mScheduler->supportSmallDirtyDetection()) {
- mCurrentState.traverse([&](Layer* layer) {
- if (layer->getLayerStack() == activeDisplay.getLayerStack()) {
- layer->setIsSmallDirty();
- }
- });
- }
}
sp<DisplayDevice> SurfaceFlinger::getActivatableDisplay() const {
@@ -8040,7 +8702,7 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveD
const DisplayDevice& activeDisplay) {
ATRACE_CALL();
- // For the first display activated during boot, there is no need to force setDesiredActiveMode,
+ // For the first display activated during boot, there is no need to force setDesiredMode,
// because DM is about to send its policy via setDesiredDisplayModeSpecs.
bool forceApplyPolicy = false;
@@ -8064,9 +8726,9 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveD
sActiveDisplayRotationFlags = ui::Transform::toRotationFlags(activeDisplay.getOrientation());
// The policy of the new active/pacesetter display may have changed while it was inactive. In
- // that case, its preferred mode has not been propagated to HWC (via setDesiredActiveMode). In
- // either case, the Scheduler's cachedModeChangedParams must be initialized to the newly active
- // mode, and the kernel idle timer of the newly active display must be toggled.
+ // that case, its preferred mode has not been propagated to HWC (via setDesiredMode). In either
+ // case, the Scheduler's cachedModeChangedParams must be initialized to the newly active mode,
+ // and the kernel idle timer of the newly active display must be toggled.
applyRefreshRateSelectorPolicy(mActiveDisplayId, activeDisplay.refreshRateSelector(),
forceApplyPolicy);
}
@@ -8263,9 +8925,9 @@ std::vector<std::pair<Layer*, LayerFE*>> SurfaceFlinger::moveSnapshotsToComposit
}
auto it = mLegacyLayers.find(snapshot->sequence);
- LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(),
- "Couldnt find layer object for %s",
- snapshot->getDebugString().c_str());
+ LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mLegacyLayers.end(),
+ "Couldnt find layer object for %s",
+ snapshot->getDebugString().c_str());
auto& legacyLayer = it->second;
sp<LayerFE> layerFE = legacyLayer->getCompositionEngineLayerFE(snapshot->path);
snapshot->fps = getLayerFramerate(currentTime, snapshot->sequence);
@@ -8334,9 +8996,9 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots(
}
auto it = mLegacyLayers.find(snapshot->sequence);
- LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(),
- "Couldnt find layer object for %s",
- snapshot->getDebugString().c_str());
+ LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mLegacyLayers.end(),
+ "Couldnt find layer object for %s",
+ snapshot->getDebugString().c_str());
Layer* legacyLayer = (it == mLegacyLayers.end()) ? nullptr : it->second.get();
sp<LayerFE> layerFE = getFactory().createLayerFE(snapshot->name);
layerFE->mSnapshot = std::make_unique<frontend::LayerSnapshot>(*snapshot);
@@ -8371,7 +9033,9 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots(std::optional<ui::LayerStack> la
.excludeLayerIds = std::move(excludeLayerIds),
.supportedLayerGenericMetadata =
getHwComposer().getSupportedLayerGenericMetadata(),
- .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap()};
+ .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap(),
+ .skipRoundCornersWhenProtected =
+ !getRenderEngine().supportsProtectedContent()};
mLayerSnapshotBuilder.update(args);
auto getLayerSnapshotsFn =
@@ -8406,7 +9070,13 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots(uint32_t rootLayerId, uint32_t u
.excludeLayerIds = std::move(excludeLayerIds),
.supportedLayerGenericMetadata =
getHwComposer().getSupportedLayerGenericMetadata(),
- .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap()};
+ .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap(),
+ .skipRoundCornersWhenProtected =
+ !getRenderEngine().supportsProtectedContent()};
+ // The layer may not exist if it was just created and a screenshot was requested immediately
+ // after. In this case, the hierarchy will be empty so we will not render any layers.
+ args.rootSnapshot.isSecure = mLayerLifecycleManager.getLayerFromId(rootLayerId) &&
+ mLayerLifecycleManager.isLayerSecure(rootLayerId);
mLayerSnapshotBuilder.update(args);
auto getLayerSnapshotsFn =
@@ -8430,6 +9100,7 @@ frontend::Update SurfaceFlinger::flushLifecycleUpdates() {
// 2. Transactions and created layers do not share a lock. To prevent applying
// transactions with layers still in the createdLayer queue, flush the transactions
// before committing the created layers.
+ mTransactionHandler.collectTransactions();
update.transactions = mTransactionHandler.flushTransactions();
{
// TODO(b/238781169) lockless queue this and keep order.
@@ -8446,19 +9117,82 @@ frontend::Update SurfaceFlinger::flushLifecycleUpdates() {
return update;
}
-void SurfaceFlinger::addToLayerTracing(bool visibleRegionDirty, TimePoint time, VsyncId vsyncId) {
- const uint32_t tracingFlags = mLayerTracing.getFlags();
- LayersProto layers(dumpDrawingStateProto(tracingFlags));
- if (tracingFlags & LayerTracing::TRACE_EXTRA) {
+void SurfaceFlinger::doActiveLayersTracingIfNeeded(bool isCompositionComputed,
+ bool visibleRegionDirty, TimePoint time,
+ VsyncId vsyncId) {
+ if (!mLayerTracing.isActiveTracingStarted()) {
+ return;
+ }
+ if (isCompositionComputed !=
+ mLayerTracing.isActiveTracingFlagSet(LayerTracing::Flag::TRACE_COMPOSITION)) {
+ return;
+ }
+ if (!visibleRegionDirty &&
+ !mLayerTracing.isActiveTracingFlagSet(LayerTracing::Flag::TRACE_BUFFERS)) {
+ return;
+ }
+ auto snapshot = takeLayersSnapshotProto(mLayerTracing.getActiveTracingFlags(), time, vsyncId,
+ visibleRegionDirty);
+ mLayerTracing.addProtoSnapshotToOstream(std::move(snapshot), LayerTracing::Mode::MODE_ACTIVE);
+}
+
+perfetto::protos::LayersSnapshotProto SurfaceFlinger::takeLayersSnapshotProto(
+ uint32_t traceFlags, TimePoint time, VsyncId vsyncId, bool visibleRegionDirty) {
+ ATRACE_CALL();
+ perfetto::protos::LayersSnapshotProto snapshot;
+ snapshot.set_elapsed_realtime_nanos(time.ns());
+ snapshot.set_vsync_id(ftl::to_underlying(vsyncId));
+ snapshot.set_where(visibleRegionDirty ? "visibleRegionsDirty" : "bufferLatched");
+ snapshot.set_excludes_composition_state((traceFlags & LayerTracing::Flag::TRACE_COMPOSITION) ==
+ 0);
+
+ auto layers = dumpDrawingStateProto(traceFlags);
+ if (traceFlags & LayerTracing::Flag::TRACE_EXTRA) {
dumpOffscreenLayersProto(layers);
}
- std::string hwcDump;
- if (tracingFlags & LayerTracing::TRACE_HWC) {
+ *snapshot.mutable_layers() = std::move(layers);
+
+ if (traceFlags & LayerTracing::Flag::TRACE_HWC) {
+ std::string hwcDump;
dumpHwc(hwcDump);
+ snapshot.set_hwc_blob(std::move(hwcDump));
+ }
+
+ *snapshot.mutable_displays() = dumpDisplayProto();
+
+ return snapshot;
+}
+
+// sfdo functions
+
+void SurfaceFlinger::sfdo_enableRefreshRateOverlay(bool active) {
+ auto future = mScheduler->schedule(
+ [&]() FTL_FAKE_GUARD(mStateLock)
+ FTL_FAKE_GUARD(kMainThreadContext) { enableRefreshRateOverlay(active); });
+ future.wait();
+}
+
+void SurfaceFlinger::sfdo_setDebugFlash(int delay) {
+ if (delay > 0) {
+ mDebugFlashDelay = delay;
+ } else {
+ mDebugFlashDelay = mDebugFlashDelay ? 0 : 1;
}
- auto displays = dumpDisplayProto();
- mLayerTracing.notify(visibleRegionDirty, time.ns(), ftl::to_underlying(vsyncId), &layers,
- std::move(hwcDump), &displays);
+ scheduleRepaint();
+}
+
+void SurfaceFlinger::sfdo_scheduleComposite() {
+ scheduleComposite(SurfaceFlinger::FrameHint::kActive);
+}
+
+void SurfaceFlinger::sfdo_scheduleCommit() {
+ Mutex::Autolock lock(mStateLock);
+ setTransactionFlags(eTransactionNeeded | eDisplayTransactionNeeded | eTraversalNeeded);
+}
+
+void SurfaceFlinger::sfdo_forceClientComposition(bool enabled) {
+ mDebugDisableHWC = enabled;
+ scheduleRepaint();
}
// gui::ISurfaceComposer
@@ -8490,6 +9224,10 @@ binder::Status SurfaceComposerAIDL::createConnection(sp<gui::ISurfaceComposerCli
const sp<Client> client = sp<Client>::make(mFlinger);
if (client->initCheck() == NO_ERROR) {
*outClient = client;
+ if (FlagManager::getInstance().misc1()) {
+ const int policy = SCHED_FIFO;
+ client->setMinSchedulerPolicy(policy, sched_get_priority_min(policy));
+ }
return binder::Status::ok();
} else {
*outClient = nullptr;
@@ -8643,7 +9381,8 @@ void SurfaceComposerAIDL::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo&
outMode.resolution.height = mode.resolution.height;
outMode.xDpi = mode.xDpi;
outMode.yDpi = mode.yDpi;
- outMode.refreshRate = mode.refreshRate;
+ outMode.peakRefreshRate = mode.peakRefreshRate;
+ outMode.vsyncRate = mode.vsyncRate;
outMode.appVsyncOffset = mode.appVsyncOffset;
outMode.sfVsyncOffset = mode.sfVsyncOffset;
outMode.presentationDeadline = mode.presentationDeadline;
@@ -8813,28 +9552,29 @@ binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& displa
binder::Status SurfaceComposerAIDL::captureDisplay(
const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
- status_t status = mFlinger->captureDisplay(args, captureListener);
- return binderStatusFromStatusT(status);
+ mFlinger->captureDisplay(args, captureListener);
+ return binderStatusFromStatusT(NO_ERROR);
}
binder::Status SurfaceComposerAIDL::captureDisplayById(
- int64_t displayId, const sp<IScreenCaptureListener>& captureListener) {
- status_t status;
+ int64_t displayId, const CaptureArgs& args,
+ const sp<IScreenCaptureListener>& captureListener) {
+ // status_t status;
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) {
std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId));
- status = mFlinger->captureDisplay(*id, captureListener);
+ mFlinger->captureDisplay(*id, args, captureListener);
} else {
- status = PERMISSION_DENIED;
+ invokeScreenCaptureError(PERMISSION_DENIED, captureListener);
}
- return binderStatusFromStatusT(status);
+ return binderStatusFromStatusT(NO_ERROR);
}
binder::Status SurfaceComposerAIDL::captureLayers(
const LayerCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
- status_t status = mFlinger->captureLayers(args, captureListener);
- return binderStatusFromStatusT(status);
+ mFlinger->captureLayers(args, captureListener);
+ return binderStatusFromStatusT(NO_ERROR);
}
binder::Status SurfaceComposerAIDL::overrideHdrTypes(const sp<IBinder>& display,
@@ -8881,11 +9621,6 @@ binder::Status SurfaceComposerAIDL::getLayerDebugInfo(std::vector<gui::LayerDebu
return binderStatusFromStatusT(status);
}
-binder::Status SurfaceComposerAIDL::getColorManagement(bool* outGetColorManagement) {
- status_t status = mFlinger->getColorManagement(outGetColorManagement);
- return binderStatusFromStatusT(status);
-}
-
binder::Status SurfaceComposerAIDL::getCompositionPreference(gui::CompositionPreference* outPref) {
ui::Dataspace dataspace;
ui::PixelFormat pixelFormat;
@@ -9147,30 +9882,67 @@ binder::Status SurfaceComposerAIDL::getDisplayDecorationSupport(
return binder::Status::ok();
}
-binder::Status SurfaceComposerAIDL::setOverrideFrameRate(int32_t uid, float frameRate) {
+binder::Status SurfaceComposerAIDL::setGameModeFrameRateOverride(int32_t uid, float frameRate) {
status_t status;
const int c_uid = IPCThreadState::self()->getCallingUid();
if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) {
- status = mFlinger->setOverrideFrameRate(uid, frameRate);
+ status = mFlinger->setGameModeFrameRateOverride(uid, frameRate);
} else {
- ALOGE("setOverrideFrameRate() permission denied for uid: %d", c_uid);
+ ALOGE("setGameModeFrameRateOverride() permission denied for uid: %d", c_uid);
status = PERMISSION_DENIED;
}
return binderStatusFromStatusT(status);
}
-binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vector<int32_t>& uids,
+binder::Status SurfaceComposerAIDL::setGameDefaultFrameRateOverride(int32_t uid, float frameRate) {
+ status_t status;
+ const int c_uid = IPCThreadState::self()->getCallingUid();
+ if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) {
+ status = mFlinger->setGameDefaultFrameRateOverride(uid, frameRate);
+ } else {
+ ALOGE("setGameDefaultFrameRateOverride() permission denied for uid: %d", c_uid);
+ status = PERMISSION_DENIED;
+ }
+ return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::enableRefreshRateOverlay(bool active) {
+ mFlinger->sfdo_enableRefreshRateOverlay(active);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setDebugFlash(int delay) {
+ mFlinger->sfdo_setDebugFlash(delay);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::scheduleComposite() {
+ mFlinger->sfdo_scheduleComposite();
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::scheduleCommit() {
+ mFlinger->sfdo_scheduleCommit();
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::forceClientComposition(bool enabled) {
+ mFlinger->sfdo_forceClientComposition(enabled);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vector<int32_t>& appIds,
const std::vector<float>& thresholds) {
status_t status;
const int c_uid = IPCThreadState::self()->getCallingUid();
if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) {
- if (uids.size() != thresholds.size()) return binderStatusFromStatusT(BAD_VALUE);
+ if (appIds.size() != thresholds.size()) return binderStatusFromStatusT(BAD_VALUE);
- std::vector<std::pair<uid_t, float>> mappings;
- const size_t size = uids.size();
+ std::vector<std::pair<int32_t, float>> mappings;
+ const size_t size = appIds.size();
mappings.reserve(size);
for (int i = 0; i < size; i++) {
- auto row = std::make_pair(static_cast<uid_t>(uids[i]), thresholds[i]);
+ auto row = std::make_pair(appIds[i], thresholds[i]);
mappings.push_back(row);
}
status = mFlinger->updateSmallAreaDetection(mappings);
@@ -9181,11 +9953,11 @@ binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vector<i
return binderStatusFromStatusT(status);
}
-binder::Status SurfaceComposerAIDL::setSmallAreaDetectionThreshold(int32_t uid, float threshold) {
+binder::Status SurfaceComposerAIDL::setSmallAreaDetectionThreshold(int32_t appId, float threshold) {
status_t status;
const int c_uid = IPCThreadState::self()->getCallingUid();
if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) {
- status = mFlinger->setSmallAreaDetectionThreshold(uid, threshold);
+ status = mFlinger->setSmallAreaDetectionThreshold(appId, threshold);
} else {
ALOGE("setSmallAreaDetectionThreshold() permission denied for uid: %d", c_uid);
status = PERMISSION_DENIED;
@@ -9256,6 +10028,10 @@ binder::Status SurfaceComposerAIDL::getStalledTransactionInfo(
return binderStatusFromStatusT(status);
}
+binder::Status SurfaceComposerAIDL::getSchedulingPolicy(gui::SchedulingPolicy* outPolicy) {
+ return gui::getSchedulingPolicy(outPolicy);
+}
+
status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) {
if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
IPCThreadState* ipc = IPCThreadState::self();