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.cpp5190
1 files changed, 3047 insertions, 2143 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5324470a76..ad0ac6b2ef 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -14,19 +14,21 @@
* limitations under the License.
*/
-// #define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <stdint.h>
#include <sys/types.h>
-#include <algorithm>
#include <errno.h>
-#include <math.h>
-#include <mutex>
#include <dlfcn.h>
-#include <inttypes.h>
-#include <stdatomic.h>
+
+#include <algorithm>
+#include <cinttypes>
+#include <cmath>
+#include <cstdint>
+#include <functional>
+#include <mutex>
#include <optional>
+#include <unordered_map>
#include <cutils/properties.h>
#include <log/log.h>
@@ -35,80 +37,99 @@
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <dvr/vr_flinger.h>
-
-#include <ui/ColorSpace.h>
-#include <ui/DebugUtils.h>
-#include <ui/DisplayInfo.h>
-#include <ui/DisplayStatInfo.h>
-
#include <gui/BufferQueue.h>
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
+#include <gui/IProducerListener.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
-
+#include <input/IInputFlinger.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/ColorSpace.h>
+#include <ui/DebugUtils.h>
+#include <ui/DisplayInfo.h>
+#include <ui/DisplayStatInfo.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
#include <ui/UiConfig.h>
-
-#include <utils/misc.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
#include <utils/StopWatch.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
+#include <utils/misc.h>
#include <private/android_filesystem_config.h>
#include <private/gui/SyncFeatures.h>
#include "BufferLayer.h"
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
#include "Client.h"
#include "ColorLayer.h"
#include "Colorizer.h"
#include "ContainerLayer.h"
-#include "DispSync.h"
#include "DisplayDevice.h"
-#include "EventControlThread.h"
-#include "EventThread.h"
#include "Layer.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
+#include "NativeWindowSurface.h"
+#include "RefreshRateOverlay.h"
+#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
-#include "Transform.h"
-#include "clz.h"
+#include "SurfaceInterceptor.h"
#include "DisplayHardware/ComposerHal.h"
+#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
-
#include "Effects/Daltonizer.h"
+#include "RegionSamplingThread.h"
+#include "Scheduler/DispSync.h"
+#include "Scheduler/DispSyncSource.h"
+#include "Scheduler/EventControlThread.h"
+#include "Scheduler/EventThread.h"
+#include "Scheduler/InjectVSyncSource.h"
+#include "Scheduler/MessageQueue.h"
+#include "Scheduler/PhaseOffsets.h"
+#include "Scheduler/Scheduler.h"
+#include "TimeStats/TimeStats.h"
-#include "RenderEngine/RenderEngine.h"
#include <cutils/compiler.h>
+#include "android-base/stringprintf.h"
+
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
+#include <android/hardware/power/1.0/IPower.h>
#include <configstore/Utils.h>
#include <layerproto/LayerProtoParser.h>
-
-#define DISPLAY_COUNT 1
-
-/*
- * DEBUG_SCREENSHOTS: set to true to check that screenshots are not all
- * black pixels.
- */
-#define DEBUG_SCREENSHOTS false
+#include "SurfaceFlingerProperties.h"
namespace android {
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
+using namespace android::sysprop;
+
+using android::hardware::power::V1_0::PowerHint;
+using base::StringAppendF;
using ui::ColorMode;
using ui::Dataspace;
+using ui::DisplayPrimaries;
using ui::Hdr;
using ui::RenderIntent;
@@ -117,19 +138,63 @@ namespace {
#pragma clang diagnostic push
#pragma clang diagnostic error "-Wswitch-enum"
-Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
+bool isWideColorMode(const ColorMode colorMode) {
+ switch (colorMode) {
+ case ColorMode::DISPLAY_P3:
+ case ColorMode::ADOBE_RGB:
+ case ColorMode::DCI_P3:
+ case ColorMode::BT2020:
+ case ColorMode::DISPLAY_BT2020:
+ case ColorMode::BT2100_PQ:
+ case ColorMode::BT2100_HLG:
+ return true;
+ case ColorMode::NATIVE:
+ case ColorMode::STANDARD_BT601_625:
+ case ColorMode::STANDARD_BT601_625_UNADJUSTED:
+ case ColorMode::STANDARD_BT601_525:
+ case ColorMode::STANDARD_BT601_525_UNADJUSTED:
+ case ColorMode::STANDARD_BT709:
+ case ColorMode::SRGB:
+ return false;
+ }
+ return false;
+}
+
+bool isHdrColorMode(const ColorMode colorMode) {
+ switch (colorMode) {
+ case ColorMode::BT2100_PQ:
+ case ColorMode::BT2100_HLG:
+ return true;
+ case ColorMode::DISPLAY_P3:
+ case ColorMode::ADOBE_RGB:
+ case ColorMode::DCI_P3:
+ case ColorMode::BT2020:
+ case ColorMode::DISPLAY_BT2020:
+ case ColorMode::NATIVE:
+ case ColorMode::STANDARD_BT601_625:
+ case ColorMode::STANDARD_BT601_625_UNADJUSTED:
+ case ColorMode::STANDARD_BT601_525:
+ case ColorMode::STANDARD_BT601_525_UNADJUSTED:
+ case ColorMode::STANDARD_BT709:
+ case ColorMode::SRGB:
+ return false;
+ }
+ return false;
+}
+
+ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
switch (rotation) {
case ISurfaceComposer::eRotateNone:
- return Transform::ROT_0;
+ return ui::Transform::ROT_0;
case ISurfaceComposer::eRotate90:
- return Transform::ROT_90;
+ return ui::Transform::ROT_90;
case ISurfaceComposer::eRotate180:
- return Transform::ROT_180;
+ return ui::Transform::ROT_180;
case ISurfaceComposer::eRotate270:
- return Transform::ROT_270;
+ return ui::Transform::ROT_270;
}
ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
- return Transform::ROT_0;
+ return ui::Transform::ROT_0;
}
#pragma clang diagnostic pop
@@ -146,6 +211,12 @@ private:
Mutex& mMutex;
bool mLocked;
};
+
+// Currently we only support V0_SRGB and DISPLAY_P3 as composition preference.
+bool validateCompositionDataspace(Dataspace dataspace) {
+ return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
+}
+
} // namespace anonymous
// ---------------------------------------------------------------------------
@@ -156,17 +227,20 @@ const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
const String16 sDump("android.permission.DUMP");
// ---------------------------------------------------------------------------
-int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
-int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
bool SurfaceFlinger::useHwcForRgbToYuv;
uint64_t SurfaceFlinger::maxVirtualDisplaySize;
bool SurfaceFlinger::hasSyncFramework;
bool SurfaceFlinger::useVrFlinger;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
-// TODO(courtneygo): Rename hasWideColorDisplay to clarify its actual meaning.
bool SurfaceFlinger::hasWideColorDisplay;
int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
+bool SurfaceFlinger::useColorManagement;
+bool SurfaceFlinger::useContextPriority;
+Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
+Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
std::string getHwcServiceName() {
char value[PROPERTY_VALUE_MAX] = {};
@@ -196,116 +270,59 @@ std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
}
}
-NativeWindowSurface::~NativeWindowSurface() = default;
-
-namespace impl {
-
-class NativeWindowSurface final : public android::NativeWindowSurface {
-public:
- static std::unique_ptr<android::NativeWindowSurface> create(
- const sp<IGraphicBufferProducer>& producer) {
- return std::make_unique<NativeWindowSurface>(producer);
- }
-
- explicit NativeWindowSurface(const sp<IGraphicBufferProducer>& producer)
- : surface(new Surface(producer, false)) {}
-
- ~NativeWindowSurface() override = default;
-
-private:
- sp<ANativeWindow> getNativeWindow() const override { return surface; }
-
- void preallocateBuffers() override { surface->allocateBuffers(); }
+SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {}
- sp<Surface> surface;
-};
+SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
+ : mFactory(factory),
+ mPhaseOffsets(mFactory.createPhaseOffsets()),
+ mInterceptor(mFactory.createSurfaceInterceptor(this)),
+ mTimeStats(mFactory.createTimeStats()),
+ mEventQueue(mFactory.createMessageQueue()),
+ mCompositionEngine(mFactory.createCompositionEngine()) {}
-} // namespace impl
-
-SurfaceFlingerBE::SurfaceFlingerBE()
- : mHwcServiceName(getHwcServiceName()),
- mRenderEngine(nullptr),
- mFrameBuckets(),
- mTotalTime(0),
- mLastSwapTime(0),
- mComposerSequenceId(0) {
-}
-
-SurfaceFlinger::SurfaceFlinger(SurfaceFlinger::SkipInitializationTag)
- : BnSurfaceComposer(),
- mTransactionFlags(0),
- mTransactionPending(false),
- mAnimTransactionPending(false),
- mLayersRemoved(false),
- mLayersAdded(false),
- mRepaintEverything(0),
- mBootTime(systemTime()),
- mBuiltinDisplays(),
- mVisibleRegionsDirty(false),
- mGeometryInvalid(false),
- mAnimCompositionPending(false),
- mBootStage(BootStage::BOOTLOADER),
- mDebugRegion(0),
- mDebugDisableHWC(0),
- mDebugDisableTransformHint(0),
- mDebugInSwapBuffers(0),
- mLastSwapBufferTime(0),
- mDebugInTransaction(0),
- mLastTransactionTime(0),
- mForceFullDamage(false),
- mPrimaryDispSync("PrimaryDispSync"),
- mPrimaryHWVsyncEnabled(false),
- mHWVsyncAvailable(false),
- mHasPoweredOff(false),
- mNumLayers(0),
- mVrFlingerRequestsDisplay(false),
- mMainThreadId(std::this_thread::get_id()),
- mCreateBufferQueue(&BufferQueue::createBufferQueue),
- mCreateNativeWindowSurface(&impl::NativeWindowSurface::create) {}
-
-SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
+SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
- vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
+ hasSyncFramework = running_without_sync_framework(true);
- sfVsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000);
+ dispSyncPresentTimeOffset = present_time_offset_from_vsync_ns(0);
- hasSyncFramework = getBool< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::hasSyncFramework>(true);
+ useHwcForRgbToYuv = force_hwc_copy_for_virtual_displays(false);
- dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0);
+ maxVirtualDisplaySize = max_virtual_display_dimension(0);
- useHwcForRgbToYuv = getBool< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::useHwcForRGBtoYUV>(false);
+ // Vr flinger is only enabled on Daydream ready devices.
+ useVrFlinger = use_vr_flinger(false);
- maxVirtualDisplaySize = getUInt64<ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::maxVirtualDisplaySize>(0);
+ maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
- // Vr flinger is only enabled on Daydream ready devices.
- useVrFlinger = getBool< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::useVrFlinger>(false);
+ hasWideColorDisplay = has_wide_color_display(false);
- maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
+ useColorManagement = use_color_management(false);
- hasWideColorDisplay =
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+ mDefaultCompositionDataspace =
+ static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB));
+ mWideColorGamutCompositionDataspace = static_cast<ui::Dataspace>(wcg_composition_dataspace(
+ hasWideColorDisplay ? Dataspace::DISPLAY_P3 : Dataspace::V0_SRGB));
+ defaultCompositionDataspace = mDefaultCompositionDataspace;
+ wideColorGamutCompositionDataspace = mWideColorGamutCompositionDataspace;
+ defaultCompositionPixelFormat = static_cast<ui::PixelFormat>(
+ default_composition_pixel_format(ui::PixelFormat::RGBA_8888));
+ wideColorGamutCompositionPixelFormat =
+ static_cast<ui::PixelFormat>(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888));
- V1_1::DisplayOrientation primaryDisplayOrientation =
- getDisplayOrientation< V1_1::ISurfaceFlingerConfigs, &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
- V1_1::DisplayOrientation::ORIENTATION_0);
+ useContextPriority = use_context_priority(true);
- switch (primaryDisplayOrientation) {
- case V1_1::DisplayOrientation::ORIENTATION_90:
+ auto tmpPrimaryDisplayOrientation = primary_display_orientation(
+ SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_0);
+ switch (tmpPrimaryDisplayOrientation) {
+ case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_90:
SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation90;
break;
- case V1_1::DisplayOrientation::ORIENTATION_180:
+ case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_180:
SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation180;
break;
- case V1_1::DisplayOrientation::ORIENTATION_270:
+ case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_270:
SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation270;
break;
default:
@@ -314,7 +331,7 @@ SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
}
ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
- mPrimaryDispSync.init(SurfaceFlinger::hasSyncFramework, SurfaceFlinger::dispSyncPresentTimeOffset);
+ mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries();
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
@@ -336,11 +353,16 @@ SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
mPropagateBackpressure = !atoi(value);
ALOGI_IF(!mPropagateBackpressure, "Disabling backpressure propagation");
+ property_get("debug.sf.enable_gl_backpressure", value, "0");
+ mPropagateBackpressureClientComposition = atoi(value);
+ ALOGI_IF(mPropagateBackpressureClientComposition,
+ "Enabling backpressure propagation for Client Composition");
+
property_get("debug.sf.enable_hwc_vds", value, "0");
mUseHwcVirtualDisplays = atoi(value);
- ALOGI_IF(!mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
+ ALOGI_IF(mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
- property_get("ro.sf.disable_triple_buffer", value, "1");
+ property_get("ro.sf.disable_triple_buffer", value, "0");
mLayerTripleBufferingDisabled = atoi(value);
ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
@@ -348,26 +370,19 @@ SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
- property_get("debug.sf.early_phase_offset_ns", value, "-1");
- const int earlySfOffsetNs = atoi(value);
-
- property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
- const int earlyGlSfOffsetNs = atoi(value);
+ mUseSmart90ForVideo = use_smart_90_for_video(false);
+ property_get("debug.sf.use_smart_90_for_video", value, "0");
- property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
- const int earlyAppOffsetNs = atoi(value);
+ int int_value = atoi(value);
+ if (int_value) {
+ mUseSmart90ForVideo = true;
+ }
- property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
- const int earlyGlAppOffsetNs = atoi(value);
+ property_get("debug.sf.luma_sampling", value, "1");
+ mLumaSampling = atoi(value);
- const VSyncModulator::Offsets earlyOffsets =
- {earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
- const VSyncModulator::Offsets earlyGlOffsets =
- {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
- mVsyncModulator.setPhaseOffsets(earlyOffsets, earlyGlOffsets,
- {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs});
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
@@ -389,9 +404,7 @@ void SurfaceFlinger::onFirstRef()
mEventQueue->init(this);
}
-SurfaceFlinger::~SurfaceFlinger()
-{
-}
+SurfaceFlinger::~SurfaceFlinger() = default;
void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
{
@@ -416,19 +429,6 @@ sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
return initClient(new Client(this));
}
-sp<ISurfaceComposerClient> SurfaceFlinger::createScopedConnection(
- const sp<IGraphicBufferProducer>& gbp) {
- if (authenticateSurfaceTexture(gbp) == false) {
- return nullptr;
- }
- const auto& layer = (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
- if (layer == nullptr) {
- return nullptr;
- }
-
- return initClient(new Client(this, layer));
-}
-
sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
bool secure)
{
@@ -449,38 +449,78 @@ sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
sp<BBinder> token = new DisplayToken(this);
Mutex::Autolock _l(mStateLock);
- DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
- info.displayName = displayName;
- mCurrentState.displays.add(token, info);
- mInterceptor->saveDisplayCreation(info);
+ // Display ID is assigned when virtual display is allocated by HWC.
+ DisplayDeviceState state;
+ state.isSecure = secure;
+ state.displayName = displayName;
+ mCurrentState.displays.add(token, state);
+ mInterceptor->saveDisplayCreation(state);
return token;
}
-void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) {
+void SurfaceFlinger::destroyDisplay(const sp<IBinder>& displayToken) {
Mutex::Autolock _l(mStateLock);
- ssize_t idx = mCurrentState.displays.indexOfKey(display);
- if (idx < 0) {
- ALOGW("destroyDisplay: invalid display token");
+ ssize_t index = mCurrentState.displays.indexOfKey(displayToken);
+ if (index < 0) {
+ ALOGE("destroyDisplay: Invalid display token %p", displayToken.get());
return;
}
- const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
- if (!info.isVirtualDisplay()) {
+ const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
+ if (!state.isVirtual()) {
ALOGE("destroyDisplay called for non-virtual display");
return;
}
- mInterceptor->saveDisplayDeletion(info.displayId);
- mCurrentState.displays.removeItemsAt(idx);
+ mInterceptor->saveDisplayDeletion(state.sequenceId);
+ mCurrentState.displays.removeItemsAt(index);
setTransactionFlags(eDisplayTransactionNeeded);
}
-sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
- if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
- ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
- return nullptr;
+std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const {
+ Mutex::Autolock lock(mStateLock);
+
+ const auto internalDisplayId = getInternalDisplayIdLocked();
+ if (!internalDisplayId) {
+ return {};
}
- return mBuiltinDisplays[id];
+
+ std::vector<PhysicalDisplayId> displayIds;
+ displayIds.reserve(mPhysicalDisplayTokens.size());
+ displayIds.push_back(internalDisplayId->value);
+
+ for (const auto& [id, token] : mPhysicalDisplayTokens) {
+ if (id != *internalDisplayId) {
+ displayIds.push_back(id.value);
+ }
+ }
+
+ return displayIds;
+}
+
+sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
+ Mutex::Autolock lock(mStateLock);
+ return getPhysicalDisplayTokenLocked(DisplayId{displayId});
+}
+
+status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const {
+ if (!outGetColorManagement) {
+ return BAD_VALUE;
+ }
+ *outGetColorManagement = useColorManagement;
+ return NO_ERROR;
+}
+
+HWComposer& SurfaceFlinger::getHwComposer() const {
+ return mCompositionEngine->getHwComposer();
+}
+
+renderengine::RenderEngine& SurfaceFlinger::getRenderEngine() const {
+ return mCompositionEngine->getRenderEngine();
+}
+
+compositionengine::CompositionEngine& SurfaceFlinger::getCompositionEngine() const {
+ return *mCompositionEngine.get();
}
void SurfaceFlinger::bootFinished()
@@ -498,6 +538,13 @@ void SurfaceFlinger::bootFinished()
if (mWindowManager != 0) {
mWindowManager->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
+ sp<IBinder> input(defaultServiceManager()->getService(
+ String16("inputflinger")));
+ if (input == nullptr) {
+ ALOGE("Failed to link to input service");
+ } else {
+ mInputFlinger = interface_cast<IInputFlinger>(input);
+ }
if (mVrFlinger) {
mVrFlinger->OnBootFinished();
@@ -512,11 +559,20 @@ void SurfaceFlinger::bootFinished()
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- sp<LambdaMessage> readProperties = new LambdaMessage([&]() {
+ postMessageAsync(new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS {
readPersistentProperties();
mBootStage = BootStage::FINISHED;
- });
- postMessageAsync(readProperties);
+
+ // set the refresh rate according to the policy
+ const auto& performanceRefreshRate =
+ mRefreshRateConfigs.getRefreshRate(RefreshRateType::PERFORMANCE);
+
+ if (performanceRefreshRate && isDisplayConfigAllowed(performanceRefreshRate->configId)) {
+ setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None);
+ } else {
+ setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None);
+ }
+ }));
}
uint32_t SurfaceFlinger::getNewTexture() {
@@ -541,268 +597,127 @@ uint32_t SurfaceFlinger::getNewTexture() {
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
- class MessageDestroyGLTexture : public MessageBase {
- RE::RenderEngine& engine;
- uint32_t texture;
- public:
- MessageDestroyGLTexture(RE::RenderEngine& engine, uint32_t texture)
- : engine(engine), texture(texture) {}
- virtual bool handler() {
- engine.deleteTextures(1, &texture);
- return true;
- }
- };
- postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), 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());
}
-class DispSyncSource final : public VSyncSource, private DispSync::Callback {
-public:
- DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
- const char* name) :
- mName(name),
- mValue(0),
- mTraceVsync(traceVsync),
- mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
- mVsyncEventLabel(String8::format("VSYNC-%s", name)),
- mDispSync(dispSync),
- mCallbackMutex(),
- mVsyncMutex(),
- mPhaseOffset(phaseOffset),
- mEnabled(false) {}
-
- ~DispSyncSource() override = default;
-
- void setVSyncEnabled(bool enable) override {
- Mutex::Autolock lock(mVsyncMutex);
- if (enable) {
- status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
- static_cast<DispSync::Callback*>(this));
- if (err != NO_ERROR) {
- ALOGE("error registering vsync callback: %s (%d)",
- strerror(-err), err);
- }
- //ATRACE_INT(mVsyncOnLabel.string(), 1);
- } else {
- status_t err = mDispSync->removeEventListener(
- static_cast<DispSync::Callback*>(this));
- if (err != NO_ERROR) {
- ALOGE("error unregistering vsync callback: %s (%d)",
- strerror(-err), err);
- }
- //ATRACE_INT(mVsyncOnLabel.string(), 0);
- }
- mEnabled = enable;
- }
-
- void setCallback(VSyncSource::Callback* callback) override{
- Mutex::Autolock lock(mCallbackMutex);
- mCallback = callback;
- }
-
- void setPhaseOffset(nsecs_t phaseOffset) override {
- Mutex::Autolock lock(mVsyncMutex);
-
- // Normalize phaseOffset to [0, period)
- auto period = mDispSync->getPeriod();
- phaseOffset %= period;
- if (phaseOffset < 0) {
- // If we're here, then phaseOffset is in (-period, 0). After this
- // operation, it will be in (0, period)
- phaseOffset += period;
- }
- mPhaseOffset = phaseOffset;
-
- // If we're not enabled, we don't need to mess with the listeners
- if (!mEnabled) {
- return;
- }
-
- status_t err = mDispSync->changePhaseOffset(static_cast<DispSync::Callback*>(this),
- mPhaseOffset);
- if (err != NO_ERROR) {
- ALOGE("error changing vsync offset: %s (%d)",
- strerror(-err), err);
- }
- }
-
-private:
- virtual void onDispSyncEvent(nsecs_t when) {
- VSyncSource::Callback* callback;
- {
- Mutex::Autolock lock(mCallbackMutex);
- callback = mCallback;
-
- if (mTraceVsync) {
- mValue = (mValue + 1) % 2;
- ATRACE_INT(mVsyncEventLabel.string(), mValue);
- }
- }
-
- if (callback != nullptr) {
- callback->onVSyncEvent(when);
- }
- }
-
- const char* const mName;
-
- int mValue;
-
- const bool mTraceVsync;
- const String8 mVsyncOnLabel;
- const String8 mVsyncEventLabel;
-
- DispSync* mDispSync;
-
- Mutex mCallbackMutex; // Protects the following
- VSyncSource::Callback* mCallback = nullptr;
-
- Mutex mVsyncMutex; // Protects the following
- nsecs_t mPhaseOffset;
- bool mEnabled;
-};
-
-class InjectVSyncSource final : public VSyncSource {
-public:
- InjectVSyncSource() = default;
- ~InjectVSyncSource() override = default;
-
- void setCallback(VSyncSource::Callback* callback) override {
- std::lock_guard<std::mutex> lock(mCallbackMutex);
- mCallback = callback;
- }
-
- void onInjectSyncEvent(nsecs_t when) {
- std::lock_guard<std::mutex> lock(mCallbackMutex);
- if (mCallback) {
- mCallback->onVSyncEvent(when);
- }
- }
-
- void setVSyncEnabled(bool) override {}
- void setPhaseOffset(nsecs_t) override {}
-
-private:
- std::mutex mCallbackMutex; // Protects the following
- VSyncSource::Callback* mCallback = nullptr;
-};
-
// Do not call property_set on main thread which will be blocked by init
// Use StartPropertySetThread instead.
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
+ ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset());
Mutex::Autolock _l(mStateLock);
-
// start the EventThread
- mEventThreadSource =
- std::make_unique<DispSyncSource>(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs,
- true, "app");
- mEventThread = std::make_unique<impl::EventThread>(mEventThreadSource.get(),
- [this]() { resyncWithRateLimit(); },
- impl::EventThread::InterceptVSyncsCallback(),
- "appEventThread");
- mSfEventThreadSource =
- std::make_unique<DispSyncSource>(&mPrimaryDispSync,
- SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
-
- mSFEventThread =
- std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
- [this]() { resyncWithRateLimit(); },
- [this](nsecs_t timestamp) {
- mInterceptor->saveVSyncEvent(timestamp);
- },
- "sfEventThread");
- mEventQueue->setEventThread(mSFEventThread.get());
- mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
+ mScheduler =
+ getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
+ mRefreshRateConfigs);
+ auto resyncCallback =
+ mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
+
+ mAppConnectionHandle =
+ mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
+ resyncCallback,
+ impl::EventThread::InterceptVSyncsCallback());
+ mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
+ resyncCallback, [this](nsecs_t timestamp) {
+ mInterceptor->saveVSyncEvent(timestamp);
+ });
+
+ mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
+ mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
+ mSfConnectionHandle.get());
+
+ mRegionSamplingThread =
+ new RegionSamplingThread(*this, *mScheduler,
+ RegionSamplingThread::EnvironmentTimingTunables());
// Get a RenderEngine for the given display / config (can't fail)
- getBE().mRenderEngine =
- RE::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
- hasWideColorDisplay
- ? RE::RenderEngine::WIDE_COLOR_SUPPORT
- : 0);
- LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
+ int32_t renderEngineFeature = 0;
+ renderEngineFeature |= (useColorManagement ?
+ renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0);
+ renderEngineFeature |= (useContextPriority ?
+ renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
+ renderEngineFeature |=
+ (enable_protected_contents(false) ? renderengine::RenderEngine::ENABLE_PROTECTED_CONTEXT
+ : 0);
+
+ // TODO(b/77156734): We need to stop casting and use HAL types when possible.
+ // Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display.
+ mCompositionEngine->setRenderEngine(
+ renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
+ renderEngineFeature, maxFrameBufferAcquiredBuffers));
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
"Starting with vr flinger active is not currently supported.");
- getBE().mHwc.reset(
- new HWComposer(std::make_unique<Hwc2::impl::Composer>(getBE().mHwcServiceName)));
- getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
+ mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName));
+ mCompositionEngine->getHwComposer().registerCallback(this, getBE().mComposerSequenceId);
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
- LOG_ALWAYS_FATAL_IF(!getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY),
- "Registered composer callback but didn't create the default primary display");
-
- // make the default display GLContext current so that we can create textures
- // when creating Layers (which may happens before we render something)
- getDefaultDisplayDeviceLocked()->makeCurrent();
+ const auto display = getDefaultDisplayDeviceLocked();
+ LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
+ LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()),
+ "Internal display is disconnected.");
if (useVrFlinger) {
- auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
+ auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) {
// This callback is called from the vr flinger dispatch thread. We
// need to call signalTransaction(), which requires holding
// mStateLock when we're not on the main thread. Acquiring
// mStateLock from the vr flinger dispatch thread might trigger a
// deadlock in surface flinger (see b/66916578), so post a message
// to be handled on the main thread instead.
- sp<LambdaMessage> message = new LambdaMessage([=]() {
+ postMessageAsync(new LambdaMessage([=] {
ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
mVrFlingerRequestsDisplay = requestDisplay;
signalTransaction();
- });
- postMessageAsync(message);
+ }));
};
- mVrFlinger = dvr::VrFlinger::Create(getBE().mHwc->getComposer(),
- getBE().mHwc->getHwcDisplayId(HWC_DISPLAY_PRIMARY).value_or(0),
- vrFlingerRequestDisplayCallback);
+ mVrFlinger = dvr::VrFlinger::Create(getHwComposer().getComposer(),
+ getHwComposer()
+ .fromPhysicalDisplayId(*display->getId())
+ .value_or(0),
+ vrFlingerRequestDisplayCallback);
if (!mVrFlinger) {
ALOGE("Failed to start vrflinger");
}
}
- mEventControlThread = std::make_unique<impl::EventControlThread>(
- [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
-
// initialize our drawing state
mDrawingState = mCurrentState;
// set initial conditions (e.g. unblank default device)
initializeDisplays();
- getBE().mRenderEngine->primeCache();
+ getRenderEngine().primeCache();
// Inform native graphics APIs whether the present timestamp is supported:
- if (getHwComposer().hasCapability(
- HWC2::Capability::PresentFenceIsNotReliable)) {
- mStartPropertySetThread = new StartPropertySetThread(false);
- } else {
- mStartPropertySetThread = new StartPropertySetThread(true);
- }
+
+ const bool presentFenceReliable =
+ !getHwComposer().hasCapability(HWC2::Capability::PresentFenceIsNotReliable);
+ mStartPropertySetThread = getFactory().createStartPropertySetThread(presentFenceReliable);
if (mStartPropertySetThread->Start() != NO_ERROR) {
ALOGE("Run StartPropertySetThread failed!");
}
- // This is a hack. Per definition of getDataspaceSaturationMatrix, the returned matrix
- // is used to saturate legacy sRGB content. However, to make sure the same color under
- // Display P3 will be saturated to the same color, we intentionally break the API spec
- // and apply this saturation matrix on Display P3 content. Unless the risk of applying
- // such saturation matrix on Display P3 is understood fully, the API should always return
- // identify matrix.
- mEnhancedSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
- Dataspace::SRGB_LINEAR);
+ mScheduler->setChangeRefreshRateCallback(
+ [this](RefreshRateType type, Scheduler::ConfigEvent event) {
+ Mutex::Autolock lock(mStateLock);
+ setRefreshRateTo(type, event);
+ });
+ mScheduler->setGetVsyncPeriodCallback([this] {
+ Mutex::Autolock lock(mStateLock);
+ return getVsyncPeriod();
+ });
- // we will apply this on Display P3.
- if (mEnhancedSaturationMatrix != mat4()) {
- ColorSpace srgb(ColorSpace::sRGB());
- ColorSpace displayP3(ColorSpace::DisplayP3());
- mat4 srgbToP3 = mat4(ColorSpaceConnector(srgb, displayP3).getTransform());
- mat4 p3ToSrgb = mat4(ColorSpaceConnector(displayP3, srgb).getTransform());
- mEnhancedSaturationMatrix = srgbToP3 * mEnhancedSaturationMatrix * p3ToSrgb;
- }
+ mRefreshRateConfigs.populate(getHwComposer().getConfigs(*display->getId()));
+ mRefreshRateStats.setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId()));
ALOGV("Done initializing");
}
@@ -819,6 +734,9 @@ void SurfaceFlinger::readPersistentProperties() {
property_get("persist.sys.sf.native_mode", value, "0");
mDisplayColorSetting = static_cast<DisplayColorSetting>(atoi(value));
+
+ property_get("persist.sys.sf.color_mode", value, "0");
+ mForceColorMode = static_cast<ColorMode>(atoi(value));
}
void SurfaceFlinger::startBootAnim() {
@@ -832,11 +750,11 @@ void SurfaceFlinger::startBootAnim() {
}
size_t SurfaceFlinger::getMaxTextureSize() const {
- return getBE().mRenderEngine->getMaxTextureSize();
+ return getRenderEngine().getMaxTextureSize();
}
size_t SurfaceFlinger::getMaxViewportDims() const {
- return getBE().mRenderEngine->getMaxViewportDims();
+ return getRenderEngine().getMaxViewportDims();
}
// ----------------------------------------------------------------------------
@@ -874,55 +792,51 @@ status_t SurfaceFlinger::getSupportedFrameTimestamps(
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
- Vector<DisplayInfo>* configs) {
- if (configs == nullptr || display.get() == nullptr) {
+status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken,
+ Vector<DisplayInfo>* configs) {
+ if (!displayToken || !configs) {
return BAD_VALUE;
}
- if (!display.get())
- return NAME_NOT_FOUND;
-
- int32_t type = NAME_NOT_FOUND;
- for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
- if (display == mBuiltinDisplays[i]) {
- type = i;
- break;
- }
- }
+ Mutex::Autolock lock(mStateLock);
- if (type < 0) {
- return type;
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
}
// TODO: Not sure if display density should handled by SF any longer
class Density {
- static int getDensityFromProperty(char const* propName) {
+ static float getDensityFromProperty(char const* propName) {
char property[PROPERTY_VALUE_MAX];
- int density = 0;
+ float density = 0.0f;
if (property_get(propName, property, nullptr) > 0) {
- density = atoi(property);
+ density = strtof(property, nullptr);
}
return density;
}
public:
- static int getEmuDensity() {
+ static float getEmuDensity() {
return getDensityFromProperty("qemu.sf.lcd_density"); }
- static int getBuildDensity() {
+ static float getBuildDensity() {
return getDensityFromProperty("ro.sf.lcd_density"); }
};
configs->clear();
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
- for (const auto& hwConfig : getHwComposer().getConfigs(type)) {
+ for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
DisplayInfo info = DisplayInfo();
float xdpi = hwConfig->getDpiX();
float ydpi = hwConfig->getDpiY();
- if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ info.w = hwConfig->getWidth();
+ info.h = hwConfig->getHeight();
+ // Default display viewport to display width and height
+ info.viewportW = info.w;
+ info.viewportH = info.h;
+
+ if (displayId == getInternalDisplayIdLocked()) {
// The density of the device is provided by a build property
float density = Density::getBuildDensity() / 160.0f;
if (density == 0) {
@@ -939,8 +853,15 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
info.density = density;
// TODO: this needs to go away (currently needed only by webkit)
- sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
- info.orientation = hw ? hw->getOrientation() : 0;
+ const auto display = getDefaultDisplayDeviceLocked();
+ info.orientation = display ? display->getOrientation() : 0;
+
+ // This is for screenrecord
+ const Rect viewport = display->getViewport();
+ if (viewport.isValid()) {
+ info.viewportW = uint32_t(viewport.getWidth());
+ info.viewportH = uint32_t(viewport.getHeight());
+ }
} else {
// TODO: where should this value come from?
static const int TV_DENSITY = 213;
@@ -948,12 +869,12 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
info.orientation = 0;
}
- info.w = hwConfig->getWidth();
- info.h = hwConfig->getHeight();
info.xdpi = xdpi;
info.ydpi = ydpi;
info.fps = 1e9 / hwConfig->getVsyncPeriod();
- info.appVsyncOffset = vsyncPhaseOffsetNs;
+ const auto refreshRateType = mRefreshRateConfigs.getRefreshRateType(hwConfig->getId());
+ const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(refreshRateType);
+ info.appVsyncOffset = offset.late.app;
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
@@ -967,13 +888,12 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
- info.presentationDeadline = hwConfig->getVsyncPeriod() -
- sfVsyncPhaseOffsetNs + 1000000;
+ info.presentationDeadline = hwConfig->getVsyncPeriod() - offset.late.sf + 1000000;
// All non-virtual displays are currently considered secure.
info.secure = true;
- if (type == DisplayDevice::DISPLAY_PRIMARY &&
+ if (displayId == getInternalDisplayIdLocked() &&
primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
std::swap(info.w, info.h);
}
@@ -984,209 +904,229 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */,
- DisplayStatInfo* stats) {
- if (stats == nullptr) {
+status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* stats) {
+ if (!stats) {
return BAD_VALUE;
}
- // FIXME for now we always return stats for the primary display
- memset(stats, 0, sizeof(*stats));
- stats->vsyncTime = mPrimaryDispSync.computeNextRefresh(0);
- stats->vsyncPeriod = mPrimaryDispSync.getPeriod();
+ mScheduler->getDisplayStatInfo(stats);
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
- if (outViewport == nullptr || display.get() == nullptr) {
+int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) {
+ const auto display = getDisplayDevice(displayToken);
+ if (!display) {
+ ALOGE("getActiveConfig: Invalid display token %p", displayToken.get());
return BAD_VALUE;
}
- sp<const DisplayDevice> device(getDisplayDevice(display));
- if (device == nullptr) {
- return BAD_VALUE;
- }
+ return display->getActiveConfig();
+}
- *outViewport = device->getViewport();
+void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
+ ATRACE_CALL();
- return NO_ERROR;
-}
+ // Don't check against the current mode yet. Worst case we set the desired
+ // config twice. However event generation config might have changed so we need to update it
+ // accordingly
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event;
+ mDesiredActiveConfig = info;
+ mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;
-int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
- if (display == nullptr) {
- ALOGE("%s : display is nullptr", __func__);
- return BAD_VALUE;
+ if (!mDesiredActiveConfigChanged) {
+ // This will trigger HWC refresh without resetting the idle timer.
+ repaintEverythingForHWC();
+ // Start receiving vsync samples now, so that we can detect a period
+ // switch.
+ mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+ mPhaseOffsets->setRefreshRateType(info.type);
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.onRefreshRateChangeInitiated();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
}
+ mDesiredActiveConfigChanged = true;
+ ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
- sp<const DisplayDevice> device(getDisplayDevice(display));
- if (device != nullptr) {
- return device->getActiveConfig();
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
}
+}
- return BAD_VALUE;
+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
+ ATRACE_CALL();
+
+ std::vector<int32_t> allowedConfig;
+ allowedConfig.push_back(mode);
+
+ return setAllowedDisplayConfigs(displayToken, allowedConfig);
}
-void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode) {
- ALOGD("Set active config mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
- this);
- int32_t type = hw->getDisplayType();
- int currentMode = hw->getActiveConfig();
+void SurfaceFlinger::setActiveConfigInternal() {
+ ATRACE_CALL();
- if (mode == currentMode) {
- ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display) {
return;
}
- if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
- ALOGW("Trying to set config for virtual display");
- return;
- }
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ mRefreshRateStats.setConfigMode(mUpcomingActiveConfig.configId);
+
+ display->setActiveConfig(mUpcomingActiveConfig.configId);
- hw->setActiveConfig(mode);
- getHwComposer().setActiveConfig(type, mode);
+ mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+ mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
+ ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
+
+ if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
+ mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
+ mUpcomingActiveConfig.configId);
+ }
}
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) {
- class MessageSetActiveConfig: public MessageBase {
- SurfaceFlinger& mFlinger;
- sp<IBinder> mDisplay;
- int mMode;
- public:
- MessageSetActiveConfig(SurfaceFlinger& flinger, const sp<IBinder>& disp,
- int mode) :
- mFlinger(flinger), mDisplay(disp) { mMode = mode; }
- virtual bool handler() {
- Vector<DisplayInfo> configs;
- mFlinger.getDisplayConfigs(mDisplay, &configs);
- if (mMode < 0 || mMode >= static_cast<int>(configs.size())) {
- ALOGE("Attempt to set active config = %d for display with %zu configs",
- mMode, configs.size());
- return true;
- }
- sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
- if (hw == nullptr) {
- ALOGE("Attempt to set active config = %d for null display %p",
- mMode, mDisplay.get());
- } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
- ALOGW("Attempt to set active config = %d for virtual display",
- mMode);
- } else {
- mFlinger.setActiveConfigInternal(hw, mMode);
- }
+bool SurfaceFlinger::performSetActiveConfig() {
+ ATRACE_CALL();
+ if (mCheckPendingFence) {
+ if (previousFrameMissed()) {
+ // fence has not signaled yet. wait for the next invalidate
+ mEventQueue->invalidate();
return true;
}
- };
- sp<MessageBase> msg = new MessageSetActiveConfig(*this, display, mode);
- postMessageSync(msg);
- return NO_ERROR;
-}
-status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
- Vector<ColorMode>* outColorModes) {
- if ((outColorModes == nullptr) || (display.get() == nullptr)) {
- return BAD_VALUE;
- }
- if (!display.get()) {
- return NAME_NOT_FOUND;
+ // We received the present fence from the HWC, so we assume it successfully updated
+ // the config, hence we update SF.
+ mCheckPendingFence = false;
+ setActiveConfigInternal();
}
- int32_t type = NAME_NOT_FOUND;
- for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
- if (display == mBuiltinDisplays[i]) {
- type = i;
- break;
+ // Store the local variable to release the lock.
+ ActiveConfigInfo desiredActiveConfig;
+ {
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ if (!mDesiredActiveConfigChanged) {
+ return false;
}
+ desiredActiveConfig = mDesiredActiveConfig;
}
- if (type < 0) {
- return type;
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display || display->getActiveConfig() == desiredActiveConfig.configId) {
+ // display is not valid or we are already in the requested mode
+ // on both cases there is nothing left to do
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
+ mDesiredActiveConfigChanged = false;
+ ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+ return false;
}
- std::vector<ColorMode> modes;
- {
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
- modes = getHwComposer().getColorModes(type);
+ // Desired active config was set, it is different than the config currently in use, however
+ // allowed configs might have change by the time we process the refresh.
+ // Make sure the desired config is still allowed
+ if (!isDisplayConfigAllowed(desiredActiveConfig.configId)) {
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
+ mDesiredActiveConfig.configId = display->getActiveConfig();
+ mDesiredActiveConfigChanged = false;
+ ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+ return false;
}
- outColorModes->clear();
- std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
+ mUpcomingActiveConfig = desiredActiveConfig;
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
- return NO_ERROR;
+ ATRACE_INT("ActiveConfigModeHWC", mUpcomingActiveConfig.configId);
+ getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId);
+
+ // we need to submit an empty frame to HWC to start the process
+ mCheckPendingFence = true;
+ mEventQueue->invalidate();
+ return false;
}
-ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
- sp<const DisplayDevice> device(getDisplayDevice(display));
- if (device != nullptr) {
- return device->getActiveColorMode();
+status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
+ Vector<ColorMode>* outColorModes) {
+ if (!displayToken || !outColorModes) {
+ return BAD_VALUE;
}
- return static_cast<ColorMode>(BAD_VALUE);
-}
-void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
- ColorMode mode, Dataspace dataSpace,
- RenderIntent renderIntent) {
- int32_t type = hw->getDisplayType();
- ColorMode currentMode = hw->getActiveColorMode();
- Dataspace currentDataSpace = hw->getCompositionDataSpace();
- RenderIntent currentRenderIntent = hw->getActiveRenderIntent();
+ std::vector<ColorMode> modes;
+ bool isInternalDisplay = false;
+ {
+ ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
- if (mode == currentMode && dataSpace == currentDataSpace &&
- renderIntent == currentRenderIntent) {
- return;
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
+ }
+
+ modes = getHwComposer().getColorModes(*displayId);
+ isInternalDisplay = displayId == getInternalDisplayIdLocked();
}
+ outColorModes->clear();
- if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
- ALOGW("Trying to set config for virtual display");
- return;
+ // If it's built-in display and the configuration claims it's not wide color capable,
+ // filter out all wide color modes. The typical reason why this happens is that the
+ // hardware is not good enough to support GPU composition of wide color, and thus the
+ // OEMs choose to disable this capability.
+ if (isInternalDisplay && !hasWideColorDisplay) {
+ std::remove_copy_if(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes),
+ isWideColorMode);
+ } else {
+ std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
}
- hw->setActiveColorMode(mode);
- hw->setCompositionDataSpace(dataSpace);
- hw->setActiveRenderIntent(renderIntent);
- getHwComposer().setActiveColorMode(type, mode, renderIntent);
+ return NO_ERROR;
+}
- ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), type=%d",
- decodeColorMode(mode).c_str(), mode,
- decodeRenderIntent(renderIntent).c_str(), renderIntent,
- hw->getDisplayType());
+status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayToken,
+ ui::DisplayPrimaries &primaries) {
+ if (!displayToken) {
+ return BAD_VALUE;
+ }
+
+ // Currently we only support this API for a single internal display.
+ if (getInternalDisplayToken() != displayToken) {
+ return BAD_VALUE;
+ }
+
+ memcpy(&primaries, &mInternalDisplayPrimaries, sizeof(ui::DisplayPrimaries));
+ return NO_ERROR;
}
+ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) {
+ if (const auto display = getDisplayDevice(displayToken)) {
+ return display->getCompositionDisplay()->getState().colorMode;
+ }
+ return static_cast<ColorMode>(BAD_VALUE);
+}
-status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
- ColorMode colorMode) {
- class MessageSetActiveColorMode: public MessageBase {
- SurfaceFlinger& mFlinger;
- sp<IBinder> mDisplay;
- ColorMode mMode;
- public:
- MessageSetActiveColorMode(SurfaceFlinger& flinger, const sp<IBinder>& disp,
- ColorMode mode) :
- mFlinger(flinger), mDisplay(disp) { mMode = mode; }
- virtual bool handler() {
- Vector<ColorMode> modes;
- mFlinger.getDisplayColorModes(mDisplay, &modes);
- bool exists = std::find(std::begin(modes), std::end(modes), mMode) != std::end(modes);
- if (mMode < ColorMode::NATIVE || !exists) {
- ALOGE("Attempt to set invalid active color mode %s (%d) for display %p",
- decodeColorMode(mMode).c_str(), mMode, mDisplay.get());
- return true;
- }
- sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
- if (hw == nullptr) {
- ALOGE("Attempt to set active color mode %s (%d) for null display %p",
- decodeColorMode(mMode).c_str(), mMode, mDisplay.get());
- } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
- ALOGW("Attempt to set active color mode %s %d for virtual display",
- decodeColorMode(mMode).c_str(), mMode);
- } else {
- mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC);
- }
- return true;
+status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
+ postMessageSync(new LambdaMessage([&] {
+ Vector<ColorMode> modes;
+ getDisplayColorModes(displayToken, &modes);
+ bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes);
+ if (mode < ColorMode::NATIVE || !exists) {
+ ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p",
+ decodeColorMode(mode).c_str(), mode, displayToken.get());
+ return;
}
- };
- sp<MessageBase> msg = new MessageSetActiveColorMode(*this, display, colorMode);
- postMessageSync(msg);
+ const auto display = getDisplayDevice(displayToken);
+ if (!display) {
+ ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p",
+ decodeColorMode(mode).c_str(), mode, displayToken.get());
+ } else if (display->isVirtual()) {
+ ALOGW("Attempt to set active color mode %s (%d) for virtual display",
+ decodeColorMode(mode).c_str(), mode);
+ } else {
+ display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN,
+ RenderIntent::COLORIMETRIC);
+ }
+ }));
+
return NO_ERROR;
}
@@ -1202,20 +1142,20 @@ status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
return NO_ERROR;
}
-status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& display,
- HdrCapabilities* outCapabilities) const {
+status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& displayToken,
+ HdrCapabilities* outCapabilities) const {
Mutex::Autolock _l(mStateLock);
- sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display));
- if (displayDevice == nullptr) {
- ALOGE("getHdrCapabilities: Invalid display %p", displayDevice.get());
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ ALOGE("getHdrCapabilities: Invalid display token %p", displayToken.get());
return BAD_VALUE;
}
// At this point the DisplayDeivce should already be set up,
// meaning the luminance information is already queried from
// hardware composer and stored properly.
- const HdrCapabilities& capabilities = displayDevice->getHdrCapabilities();
+ const HdrCapabilities& capabilities = display->getHdrCapabilities();
*outCapabilities = HdrCapabilities(capabilities.getSupportedHdrTypes(),
capabilities.getDesiredMaxLuminance(),
capabilities.getDesiredMaxAverageLuminance(),
@@ -1224,33 +1164,109 @@ status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& display,
return NO_ERROR;
}
+status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken,
+ ui::PixelFormat* outFormat,
+ ui::Dataspace* outDataspace,
+ uint8_t* outComponentMask) const {
+ if (!outFormat || !outDataspace || !outComponentMask) {
+ return BAD_VALUE;
+ }
+ const auto display = getDisplayDevice(displayToken);
+ if (!display || !display->getId()) {
+ ALOGE("getDisplayedContentSamplingAttributes: Bad display token: %p", display.get());
+ return BAD_VALUE;
+ }
+ return getHwComposer().getDisplayedContentSamplingAttributes(*display->getId(), outFormat,
+ outDataspace, outComponentMask);
+}
+
+status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken,
+ bool enable, uint8_t componentMask,
+ uint64_t maxFrames) const {
+ const auto display = getDisplayDevice(displayToken);
+ if (!display || !display->getId()) {
+ ALOGE("setDisplayContentSamplingEnabled: Bad display token: %p", display.get());
+ return BAD_VALUE;
+ }
+
+ return getHwComposer().setDisplayContentSamplingEnabled(*display->getId(), enable,
+ componentMask, maxFrames);
+}
+
+status_t SurfaceFlinger::getDisplayedContentSample(const sp<IBinder>& displayToken,
+ uint64_t maxFrames, uint64_t timestamp,
+ DisplayedFrameStats* outStats) const {
+ const auto display = getDisplayDevice(displayToken);
+ if (!display || !display->getId()) {
+ ALOGE("getDisplayContentSample: Bad display token: %p", displayToken.get());
+ return BAD_VALUE;
+ }
+
+ return getHwComposer().getDisplayedContentSample(*display->getId(), maxFrames, timestamp,
+ outStats);
+}
+
+status_t SurfaceFlinger::getProtectedContentSupport(bool* outSupported) const {
+ if (!outSupported) {
+ return BAD_VALUE;
+ }
+ *outSupported = getRenderEngine().supportsProtectedContent();
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::isWideColorDisplay(const sp<IBinder>& displayToken,
+ bool* outIsWideColorDisplay) const {
+ if (!displayToken || !outIsWideColorDisplay) {
+ return BAD_VALUE;
+ }
+ Mutex::Autolock _l(mStateLock);
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ return BAD_VALUE;
+ }
+
+ // Use hasWideColorDisplay to override built-in display.
+ const auto displayId = display->getId();
+ if (displayId && displayId == getInternalDisplayIdLocked()) {
+ *outIsWideColorDisplay = hasWideColorDisplay;
+ return NO_ERROR;
+ }
+ *outIsWideColorDisplay = display->hasWideColorGamut();
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
- sp<LambdaMessage> enableVSyncInjections = new LambdaMessage([&]() {
+ postMessageSync(new LambdaMessage([&] {
Mutex::Autolock _l(mStateLock);
if (mInjectVSyncs == enable) {
return;
}
+ auto resyncCallback =
+ mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
+
+ // TODO(b/128863962): Part of the Injector should be refactored, so that it
+ // can be passed to Scheduler.
if (enable) {
ALOGV("VSync Injections enabled");
if (mVSyncInjector.get() == nullptr) {
mVSyncInjector = std::make_unique<InjectVSyncSource>();
mInjectorEventThread = std::make_unique<
impl::EventThread>(mVSyncInjector.get(),
- [this]() { resyncWithRateLimit(); },
impl::EventThread::InterceptVSyncsCallback(),
"injEventThread");
}
- mEventQueue->setEventThread(mInjectorEventThread.get());
+ mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback));
} else {
ALOGV("VSync Injections disabled");
- mEventQueue->setEventThread(mSFEventThread.get());
+ mEventQueue->setEventThread(mScheduler->getEventThread(mSfConnectionHandle),
+ std::move(resyncCallback));
}
mInjectVSyncs = enable;
- });
- postMessageSync(enableVSyncInjections);
+ }));
+
return NO_ERROR;
}
@@ -1270,15 +1286,6 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) {
status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
NO_THREAD_SAFETY_ANALYSIS {
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- if ((uid != AID_SHELL) &&
- !PermissionCache::checkPermission(sDump, pid, uid)) {
- ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
-
// Try to acquire a lock for 1s, fail gracefully
const status_t err = mStateLock.timedLock(s2ns(1));
const bool locked = (err == NO_ERROR);
@@ -1296,15 +1303,84 @@ status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayer
return NO_ERROR;
}
+status_t SurfaceFlinger::getCompositionPreference(
+ Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
+ Dataspace* outWideColorGamutDataspace,
+ ui::PixelFormat* outWideColorGamutPixelFormat) const {
+ *outDataspace = mDefaultCompositionDataspace;
+ *outPixelFormat = defaultCompositionPixelFormat;
+ *outWideColorGamutDataspace = mWideColorGamutCompositionDataspace;
+ *outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat;
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::addRegionSamplingListener(const Rect& samplingArea,
+ const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener) {
+ if (!listener || samplingArea == Rect::INVALID_RECT) {
+ return BAD_VALUE;
+ }
+ mRegionSamplingThread->addListener(samplingArea, stopLayerHandle, listener);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) {
+ if (!listener) {
+ return BAD_VALUE;
+ }
+ mRegionSamplingThread->removeListener(listener);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) const {
+ if (!displayToken || !outSupport) {
+ return BAD_VALUE;
+ }
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
+ }
+ *outSupport =
+ getHwComposer().hasDisplayCapability(displayId, HWC2::DisplayCapability::Brightness);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken,
+ float brightness) const {
+ if (!displayToken) {
+ return BAD_VALUE;
+ }
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
+ }
+ return getHwComposer().setDisplayBrightness(*displayId, brightness);
+}
+
+status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) {
+ PowerHint powerHint = static_cast<PowerHint>(hintId);
+
+ if (powerHint == PowerHint::INTERACTION) {
+ mScheduler->notifyTouchEvent();
+ }
+
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource) {
- if (vsyncSource == eVsyncSourceSurfaceFlinger) {
- return mSFEventThread->createEventConnection();
- } else {
- return mEventThread->createEventConnection();
- }
+ auto resyncCallback = mScheduler->makeResyncCallback([this] {
+ Mutex::Autolock lock(mStateLock);
+ return getVsyncPeriod();
+ });
+
+ const auto& handle =
+ vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
+
+ return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback));
}
// ----------------------------------------------------------------------------
@@ -1314,10 +1390,12 @@ void SurfaceFlinger::waitForEvent() {
}
void SurfaceFlinger::signalTransaction() {
+ mScheduler->resetIdleTimer();
mEventQueue->invalidate();
}
void SurfaceFlinger::signalLayerUpdate() {
+ mScheduler->resetIdleTimer();
mEventQueue->invalidate();
}
@@ -1346,103 +1424,78 @@ void SurfaceFlinger::run() {
} while (true);
}
-void SurfaceFlinger::enableHardwareVsync() {
- Mutex::Autolock _l(mHWVsyncLock);
- if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
- mPrimaryDispSync.beginResync();
- //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
- mEventControlThread->setVsyncEnabled(true);
- mPrimaryHWVsyncEnabled = true;
+nsecs_t SurfaceFlinger::getVsyncPeriod() const {
+ const auto displayId = getInternalDisplayIdLocked();
+ if (!displayId || !getHwComposer().isConnected(*displayId)) {
+ return 0;
}
+
+ const auto config = getHwComposer().getActiveConfig(*displayId);
+ return config ? config->getVsyncPeriod() : 0;
}
-void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
- Mutex::Autolock _l(mHWVsyncLock);
+void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
+ int64_t timestamp) {
+ ATRACE_NAME("SF onVsync");
- if (makeAvailable) {
- mHWVsyncAvailable = true;
- } else if (!mHWVsyncAvailable) {
- // Hardware vsync is not currently available, so abort the resync
- // attempt for now
+ Mutex::Autolock lock(mStateLock);
+ // Ignore any vsyncs from a previous hardware composer.
+ if (sequenceId != getBE().mComposerSequenceId) {
return;
}
- const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
- const nsecs_t period = activeConfig->getVsyncPeriod();
-
- mPrimaryDispSync.reset();
- mPrimaryDispSync.setPeriod(period);
-
- if (!mPrimaryHWVsyncEnabled) {
- mPrimaryDispSync.beginResync();
- //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
- mEventControlThread->setVsyncEnabled(true);
- mPrimaryHWVsyncEnabled = true;
+ if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) {
+ return;
}
-}
-void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
- Mutex::Autolock _l(mHWVsyncLock);
- if (mPrimaryHWVsyncEnabled) {
- //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false);
- mEventControlThread->setVsyncEnabled(false);
- mPrimaryDispSync.endResync();
- mPrimaryHWVsyncEnabled = false;
+ if (hwcDisplayId != getHwComposer().getInternalHwcDisplayId()) {
+ // For now, we don't do anything with external display vsyncs.
+ return;
}
- if (makeUnavailable) {
- mHWVsyncAvailable = false;
+
+ bool periodChanged = false;
+ mScheduler->addResyncSample(timestamp, &periodChanged);
+ if (periodChanged) {
+ mVsyncModulator.onRefreshRateChangeDetected();
}
}
-void SurfaceFlinger::resyncWithRateLimit() {
- static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
+void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
+ std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
+ *compositorTiming = getBE().mCompositorTiming;
+}
- // No explicit locking is needed here since EventThread holds a lock while calling this method
- static nsecs_t sLastResyncAttempted = 0;
- const nsecs_t now = systemTime();
- if (now - sLastResyncAttempted > kIgnoreDelay) {
- resyncToHardwareVsync(false);
- }
- sLastResyncAttempted = now;
+bool SurfaceFlinger::isDisplayConfigAllowed(int32_t configId) {
+ return mAllowedDisplayConfigs.empty() || mAllowedDisplayConfigs.count(configId);
}
-void SurfaceFlinger::onVsyncReceived(int32_t sequenceId,
- hwc2_display_t displayId, int64_t timestamp) {
- Mutex::Autolock lock(mStateLock);
- // Ignore any vsyncs from a previous hardware composer.
- if (sequenceId != getBE().mComposerSequenceId) {
+void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::ConfigEvent event) {
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display || mBootStage != BootStage::FINISHED) {
return;
}
+ ATRACE_CALL();
- int32_t type;
- if (!getBE().mHwc->onVsync(displayId, timestamp, &type)) {
+ // Don't do any updating if the current fps is the same as the new one.
+ const auto& refreshRateConfig = mRefreshRateConfigs.getRefreshRate(refreshRate);
+ if (!refreshRateConfig) {
+ ALOGV("Skipping refresh rate change request for unsupported rate.");
return;
}
- bool needsHwVsync = false;
-
- { // Scope for the lock
- Mutex::Autolock _l(mHWVsyncLock);
- if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) {
- needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
- }
- }
+ const int desiredConfigId = refreshRateConfig->configId;
- if (needsHwVsync) {
- enableHardwareVsync();
- } else {
- disableHardwareVsync(false);
+ if (!isDisplayConfigAllowed(desiredConfigId)) {
+ ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId);
+ return;
}
-}
-void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
- std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
- *compositorTiming = getBE().mCompositorTiming;
+ setDesiredActiveConfig({refreshRate, desiredConfigId, event});
}
-void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
HWC2::Connection connection) {
- ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s)", sequenceId, display,
+ ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
connection == HWC2::Connection::Connected ? "connected" : "disconnected");
// Ignore events that do not have the right sequenceId.
@@ -1456,7 +1509,7 @@ void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t displa
// acquire it here.
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
- mPendingHotplugEvents.emplace_back(HotplugEvent{display, connection});
+ mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection});
if (std::this_thread::get_id() == mMainThreadId) {
// Process all pending hot plug events immediately if we are on the main thread.
@@ -1466,43 +1519,44 @@ void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t displa
setTransactionFlags(eDisplayTransactionNeeded);
}
-void SurfaceFlinger::onRefreshReceived(int sequenceId,
- hwc2_display_t /*display*/) {
+void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDisplayId*/) {
Mutex::Autolock lock(mStateLock);
if (sequenceId != getBE().mComposerSequenceId) {
return;
}
- repaintEverything();
+ repaintEverythingForHWC();
}
-void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
+void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) {
ATRACE_CALL();
Mutex::Autolock lock(mStateLock);
- getHwComposer().setVsyncEnabled(disp,
- enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+ if (const auto displayId = getInternalDisplayIdLocked()) {
+ getHwComposer().setVsyncEnabled(*displayId,
+ enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+ }
}
// Note: it is assumed the caller holds |mStateLock| when this is called
void SurfaceFlinger::resetDisplayState() {
- disableHardwareVsync(true);
+ mScheduler->disableHardwareVsync(true);
// Clear the drawing state so that the logic inside of
// handleTransactionLocked will fire. It will determine the delta between
// mCurrentState and mDrawingState and re-apply all changes when we make the
// transition.
mDrawingState.displays.clear();
- getRenderEngine().resetCurrentSurface();
mDisplays.clear();
}
void SurfaceFlinger::updateVrFlinger() {
+ ATRACE_CALL();
if (!mVrFlinger)
return;
bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
- if (vrFlingerRequestsDisplay == getBE().mHwc->isUsingVrComposer()) {
+ if (vrFlingerRequestsDisplay == getHwComposer().isUsingVrComposer()) {
return;
}
- if (vrFlingerRequestsDisplay && !getBE().mHwc->getComposer()->isRemote()) {
+ if (vrFlingerRequestsDisplay && !getHwComposer().getComposer()->isRemote()) {
ALOGE("Vr flinger is only supported for remote hardware composer"
" service connections. Ignoring request to transition to vr"
" flinger.");
@@ -1512,61 +1566,118 @@ void SurfaceFlinger::updateVrFlinger() {
Mutex::Autolock _l(mStateLock);
- int currentDisplayPowerMode = getDisplayDeviceLocked(
- mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])->getPowerMode();
+ sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
+ LOG_ALWAYS_FATAL_IF(!display);
+
+ const int currentDisplayPowerMode = display->getPowerMode();
+
+ // Clear out all the output layers from the composition engine for all
+ // displays before destroying the hardware composer interface. This ensures
+ // any HWC layers are destroyed through that interface before it becomes
+ // invalid.
+ for (const auto& [token, displayDevice] : mDisplays) {
+ displayDevice->getCompositionDisplay()->setOutputLayersOrderedByZ(
+ compositionengine::Output::OutputLayers());
+ }
+
+ // This DisplayDevice will no longer be relevant once resetDisplayState() is
+ // called below. Clear the reference now so we don't accidentally use it
+ // later.
+ display.clear();
if (!vrFlingerRequestsDisplay) {
mVrFlinger->SeizeDisplayOwnership();
}
resetDisplayState();
- getBE().mHwc.reset(); // Delete the current instance before creating the new one
- getBE().mHwc.reset(new HWComposer(std::make_unique<Hwc2::impl::Composer>(
- vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName)));
- getBE().mHwc->registerCallback(this, ++getBE().mComposerSequenceId);
+ // Delete the current instance before creating the new one
+ mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
+ mCompositionEngine->setHwComposer(getFactory().createHWComposer(
+ vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName));
+ getHwComposer().registerCallback(this, ++getBE().mComposerSequenceId);
- LOG_ALWAYS_FATAL_IF(!getBE().mHwc->getComposer()->isRemote(),
+ LOG_ALWAYS_FATAL_IF(!getHwComposer().getComposer()->isRemote(),
"Switched to non-remote hardware composer");
if (vrFlingerRequestsDisplay) {
mVrFlinger->GrantDisplayOwnership();
- } else {
- enableHardwareVsync();
}
mVisibleRegionsDirty = true;
invalidateHwcGeometry();
// Re-enable default display.
- sp<DisplayDevice> hw(getDisplayDeviceLocked(
- mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
- setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true);
+ display = getDefaultDisplayDeviceLocked();
+ LOG_ALWAYS_FATAL_IF(!display);
+ setPowerModeInternal(display, currentDisplayPowerMode);
// Reset the timing values to account for the period of the swapped in HWC
- const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
- const nsecs_t period = activeConfig->getVsyncPeriod();
- mAnimFrameTracker.setDisplayRefreshPeriod(period);
+ const nsecs_t vsyncPeriod = getVsyncPeriod();
+ mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
+
+ // The present fences returned from vr_hwc are not an accurate
+ // representation of vsync times.
+ mScheduler->setIgnorePresentFences(getHwComposer().isUsingVrComposer() || !hasSyncFramework);
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
- setCompositorTimingSnapped(0, period, 0);
+ DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
+ setCompositorTimingSnapped(stats, 0);
- android_atomic_or(1, &mRepaintEverything);
+ mScheduler->resyncToHardwareVsync(false, vsyncPeriod);
+
+ mRepaintEverything = true;
setTransactionFlags(eDisplayTransactionNeeded);
}
-void SurfaceFlinger::onMessageReceived(int32_t what) {
+bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS {
+ // We are storing the last 2 present fences. If sf's phase offset is to be
+ // woken up before the actual vsync but targeting the next vsync, we need to check
+ // fence N-2
+ const sp<Fence>& fence =
+ mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
+ ? mPreviousPresentFences[0]
+ : mPreviousPresentFences[1];
+
+ return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled);
+}
+
+void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
- bool frameMissed = !mHadClientComposition &&
- mPreviousPresentFence != Fence::NO_FENCE &&
- (mPreviousPresentFence->getSignalTime() ==
- Fence::SIGNAL_TIME_PENDING);
+ bool frameMissed = previousFrameMissed();
+ bool hwcFrameMissed = mHadDeviceComposition && frameMissed;
+ bool gpuFrameMissed = mHadClientComposition && frameMissed;
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+ ATRACE_INT("HwcFrameMissed", static_cast<int>(hwcFrameMissed));
+ ATRACE_INT("GpuFrameMissed", static_cast<int>(gpuFrameMissed));
if (frameMissed) {
- mTimeStats.incrementMissedFrames();
- if (mPropagateBackpressure) {
+ mFrameMissedCount++;
+ mTimeStats->incrementMissedFrames();
+ }
+
+ if (hwcFrameMissed) {
+ mHwcFrameMissedCount++;
+ }
+
+ if (gpuFrameMissed) {
+ mGpuFrameMissedCount++;
+ }
+
+ if (mUseSmart90ForVideo) {
+ // This call is made each time SF wakes up and creates a new frame. It is part
+ // of video detection feature.
+ mScheduler->updateFpsBasedOnContent();
+ }
+
+ if (performSetActiveConfig()) {
+ break;
+ }
+
+ if (frameMissed && mPropagateBackpressure) {
+ if ((hwcFrameMissed && !gpuFrameMissed) ||
+ mPropagateBackpressureClientComposition) {
signalLayerUpdate();
break;
}
@@ -1579,6 +1690,10 @@ void SurfaceFlinger::onMessageReceived(int32_t what) {
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
+
+ updateCursorAsync();
+ updateInputFlinger();
+
refreshNeeded |= mRepaintEverything;
if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
// Signal a refresh if a transaction modified the window state,
@@ -1596,17 +1711,25 @@ void SurfaceFlinger::onMessageReceived(int32_t what) {
}
bool SurfaceFlinger::handleMessageTransaction() {
+ ATRACE_CALL();
uint32_t transactionFlags = peekTransactionFlags();
- if (transactionFlags) {
- handleTransaction(transactionFlags);
- return true;
+
+ bool flushedATransaction = flushTransactionQueues();
+
+ bool runHandleTransaction = transactionFlags &&
+ ((transactionFlags != eTransactionFlushNeeded) || flushedATransaction);
+
+ if (runHandleTransaction) {
+ handleTransaction(eTransactionMask);
+ } else {
+ getTransactionFlags(eTransactionFlushNeeded);
}
- return false;
-}
-bool SurfaceFlinger::handleMessageInvalidate() {
- ATRACE_CALL();
- return handlePageFlip();
+ if (transactionFlushNeeded()) {
+ setTransactionFlags(eTransactionFlushNeeded);
+ }
+
+ return runHandleTransaction;
}
void SurfaceFlinger::handleMessageRefresh() {
@@ -1614,111 +1737,213 @@ void SurfaceFlinger::handleMessageRefresh() {
mRefreshPending = false;
- nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
-
- preComposition(refreshStartTime);
+ const bool repaintEverything = mRepaintEverything.exchange(false);
+ preComposition();
rebuildLayerStacks();
- setUpHWComposer();
- doDebugFlashRegions();
- doTracing("handleRefresh");
+ calculateWorkingSet();
+ for (const auto& [token, display] : mDisplays) {
+ beginFrame(display);
+ prepareFrame(display);
+ doDebugFlashRegions(display, repaintEverything);
+ doComposition(display, repaintEverything);
+ }
+
logLayerStats();
- doComposition();
- postComposition(refreshStartTime);
- mPreviousPresentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
+ postFrame();
+ postComposition();
mHadClientComposition = false;
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
- mHadClientComposition = mHadClientComposition ||
- getBE().mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
+ mHadDeviceComposition = false;
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto displayId = display->getId();
+ mHadClientComposition =
+ mHadClientComposition || getHwComposer().hasClientComposition(displayId);
+ mHadDeviceComposition =
+ mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId);
}
+
mVsyncModulator.onRefreshed(mHadClientComposition);
mLayersWithQueuedFrames.clear();
}
-void SurfaceFlinger::doDebugFlashRegions()
-{
- // is debugging enabled
- if (CC_LIKELY(!mDebugRegion))
- return;
- const bool repaintEverything = mRepaintEverything;
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- const sp<DisplayDevice>& hw(mDisplays[dpy]);
- if (hw->isDisplayOn()) {
- // transform the dirty region into this screen's coordinate space
- const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
- if (!dirtyRegion.isEmpty()) {
- // redraw the whole screen
- doComposeSurfaces(hw);
-
- // and draw the dirty region
- const int32_t height = hw->getHeight();
- auto& engine(getRenderEngine());
- engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
-
- hw->swapBuffers(getHwComposer());
- }
+bool SurfaceFlinger::handleMessageInvalidate() {
+ ATRACE_CALL();
+ bool refreshNeeded = handlePageFlip();
+
+ if (mVisibleRegionsDirty) {
+ computeLayerBounds();
+ if (mTracingEnabled) {
+ mTracing.notify("visibleRegionsDirty");
}
}
- postFramebuffer();
+ for (auto& layer : mLayersPendingRefresh) {
+ Region visibleReg;
+ visibleReg.set(layer->getScreenBounds());
+ invalidateLayerStack(layer, visibleReg);
+ }
+ mLayersPendingRefresh.clear();
+ return refreshNeeded;
+}
- if (mDebugRegion > 1) {
- usleep(mDebugRegion * 1000);
+void SurfaceFlinger::calculateWorkingSet() {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ // build the h/w work list
+ if (CC_UNLIKELY(mGeometryInvalid)) {
+ mGeometryInvalid = false;
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+
+ uint32_t zOrder = 0;
+
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ auto& compositionState = layer->editState();
+ compositionState.forceClientComposition = false;
+ if (!compositionState.hwc || mDebugDisableHWC || mDebugRegion) {
+ compositionState.forceClientComposition = true;
+ }
+
+ // The output Z order is set here based on a simple counter.
+ compositionState.z = zOrder++;
+
+ // Update the display independent composition state. This goes
+ // to the general composition layer state structure.
+ // TODO: Do this once per compositionengine::CompositionLayer.
+ layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
+ true);
+
+ // Recalculate the geometry state of the output layer.
+ layer->updateCompositionState(true);
+
+ // Write the updated geometry state to the HWC
+ layer->writeStateToHWC(true);
+ }
+ }
}
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- auto& displayDevice = mDisplays[displayId];
- if (!displayDevice->isDisplayOn()) {
+ // Set the per-frame data
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto displayId = display->getId();
+ if (!displayId) {
continue;
}
+ auto* profile = display->getDisplayColorProfile();
+
+ if (mDrawingState.colorMatrixChanged) {
+ display->setColorTransform(mDrawingState.colorMatrix);
+ }
+ Dataspace targetDataspace = Dataspace::UNKNOWN;
+ if (useColorManagement) {
+ ColorMode colorMode;
+ RenderIntent renderIntent;
+ pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);
+ display->setColorMode(colorMode, targetDataspace, renderIntent);
+ }
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ if (layer->isHdrY410()) {
+ layer->forceClientComposition(displayDevice);
+ } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
+ layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
+ !profile->hasHDR10Support()) {
+ layer->forceClientComposition(displayDevice);
+ } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
+ layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
+ !profile->hasHLGSupport()) {
+ layer->forceClientComposition(displayDevice);
+ }
+
+ if (layer->getRoundedCornerState().radius > 0.0f) {
+ layer->forceClientComposition(displayDevice);
+ }
+
+ if (layer->getForceClientComposition(displayDevice)) {
+ ALOGV("[%s] Requesting Client composition", layer->getName().string());
+ layer->setCompositionType(displayDevice,
+ Hwc2::IComposerClient::Composition::CLIENT);
+ continue;
+ }
+
+ const auto& displayState = display->getState();
+ layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
+ displayDevice->getSupportedPerFrameMetadata(),
+ isHdrColorMode(displayState.colorMode) ? Dataspace::UNKNOWN
+ : targetDataspace);
+ }
+ }
- status_t result = displayDevice->prepareFrame(*getBE().mHwc);
- ALOGE_IF(result != NO_ERROR,
- "prepareFrame for display %zd failed:"
- " %d (%s)",
- displayId, result, strerror(-result));
+ mDrawingState.colorMatrixChanged = false;
+
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ auto& layerState = layer->getCompositionLayer()->editState().frontEnd;
+ layerState.compositionType = static_cast<Hwc2::IComposerClient::Composition>(
+ layer->getCompositionType(displayDevice));
+ }
}
}
-void SurfaceFlinger::doTracing(const char* where) {
- ATRACE_CALL();
- ATRACE_NAME(where);
- if (CC_UNLIKELY(mTracing.isEnabled())) {
- mTracing.traceLayers(where, dumpProtoInfo(LayerVector::StateSet::Drawing));
+void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& displayDevice,
+ bool repaintEverything) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
+ // is debugging enabled
+ if (CC_LIKELY(!mDebugRegion))
+ return;
+
+ if (displayState.isEnabled) {
+ // transform the dirty region into this screen's coordinate space
+ const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
+ if (!dirtyRegion.isEmpty()) {
+ base::unique_fd readyFence;
+ // redraw the whole screen
+ doComposeSurfaces(displayDevice, dirtyRegion, &readyFence);
+
+ display->getRenderSurface()->queueBuffer(std::move(readyFence));
+ }
+ }
+
+ postFramebuffer(displayDevice);
+
+ if (mDebugRegion > 1) {
+ usleep(mDebugRegion * 1000);
}
+
+ prepareFrame(displayDevice);
}
void SurfaceFlinger::logLayerStats() {
ATRACE_CALL();
if (CC_UNLIKELY(mLayerStats.isEnabled())) {
- int32_t hwcId = -1;
- for (size_t dpy = 0; dpy < mDisplays.size(); ++dpy) {
- const sp<const DisplayDevice>& displayDevice(mDisplays[dpy]);
- if (displayDevice->isPrimary()) {
- hwcId = displayDevice->getHwcDisplayId();
- break;
+ for (const auto& [token, display] : mDisplays) {
+ if (display->isPrimary()) {
+ mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(display));
+ return;
}
}
- if (hwcId < 0) {
- ALOGE("LayerStats: Hmmm, no primary display?");
- return;
- }
- mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(hwcId));
+
+ ALOGE("logLayerStats: no primary display");
}
}
-void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
+void SurfaceFlinger::preComposition()
{
ATRACE_CALL();
ALOGV("preComposition");
+ mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
bool needExtraInvalidate = false;
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (layer->onPreComposition(refreshStartTime)) {
+ if (layer->onPreComposition(mRefreshStartTime)) {
needExtraInvalidate = true;
}
});
@@ -1728,9 +1953,8 @@ void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
}
}
-void SurfaceFlinger::updateCompositorTiming(
- nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
- std::shared_ptr<FenceTime>& presentFenceTime) {
+void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
+ std::shared_ptr<FenceTime>& presentFenceTime) {
// Update queue of past composite+present times and determine the
// most recently known composite to present latency.
getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime});
@@ -1752,42 +1976,40 @@ void SurfaceFlinger::updateCompositorTiming(
getBE().mCompositePresentTimes.pop();
}
- setCompositorTimingSnapped(
- vsyncPhase, vsyncInterval, compositeToPresentLatency);
+ setCompositorTimingSnapped(stats, compositeToPresentLatency);
}
-void SurfaceFlinger::setCompositorTimingSnapped(nsecs_t vsyncPhase,
- nsecs_t vsyncInterval, nsecs_t compositeToPresentLatency) {
+void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats,
+ nsecs_t compositeToPresentLatency) {
// Integer division and modulo round toward 0 not -inf, so we need to
// treat negative and positive offsets differently.
- nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0) ?
- (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) :
- ((-sfVsyncPhaseOffsetNs) % vsyncInterval);
+ nsecs_t idealLatency = (mPhaseOffsets->getCurrentSfOffset() > 0)
+ ? (stats.vsyncPeriod - (mPhaseOffsets->getCurrentSfOffset() % stats.vsyncPeriod))
+ : ((-mPhaseOffsets->getCurrentSfOffset()) % stats.vsyncPeriod);
- // Just in case sfVsyncPhaseOffsetNs == -vsyncInterval.
+ // Just in case mPhaseOffsets->getCurrentSfOffset() == -vsyncInterval.
if (idealLatency <= 0) {
- idealLatency = vsyncInterval;
+ idealLatency = stats.vsyncPeriod;
}
// Snap the latency to a value that removes scheduling jitter from the
// composition and present times, which often have >1ms of jitter.
// Reducing jitter is important if an app attempts to extrapolate
// something (such as user input) to an accurate diasplay time.
- // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
+ // Snapping also allows an app to precisely calculate mPhaseOffsets->getCurrentSfOffset()
// with (presentLatency % interval).
- nsecs_t bias = vsyncInterval / 2;
- int64_t extraVsyncs =
- (compositeToPresentLatency - idealLatency + bias) / vsyncInterval;
- nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ?
- idealLatency + (extraVsyncs * vsyncInterval) : idealLatency;
+ nsecs_t bias = stats.vsyncPeriod / 2;
+ int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
+ nsecs_t snappedCompositeToPresentLatency =
+ (extraVsyncs > 0) ? idealLatency + (extraVsyncs * stats.vsyncPeriod) : idealLatency;
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
- getBE().mCompositorTiming.deadline = vsyncPhase - idealLatency;
- getBE().mCompositorTiming.interval = vsyncInterval;
+ getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency;
+ getBE().mCompositorTiming.interval = stats.vsyncPeriod;
getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
}
-void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
+void SurfaceFlinger::postComposition()
{
ATRACE_CALL();
ALOGV("postComposition");
@@ -1799,31 +2021,35 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
}
// |mStateLock| not needed as we are on the main thread
- const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
+ const auto displayDevice = getDefaultDisplayDeviceLocked();
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- if (hw && getBE().mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
+ if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
glCompositionDoneFenceTime =
- std::make_shared<FenceTime>(hw->getClientTargetAcquireFence());
+ std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
+ ->getRenderSurface()
+ ->getClientTargetAcquireFence());
getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
} else {
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
getBE().mDisplayTimeline.updateSignalTimes();
- sp<Fence> presentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
- auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
+ mPreviousPresentFences[1] = mPreviousPresentFences[0];
+ mPreviousPresentFences[0] = displayDevice
+ ? getHwComposer().getPresentFence(*displayDevice->getId())
+ : Fence::NO_FENCE;
+ auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]);
getBE().mDisplayTimeline.push(presentFenceTime);
- nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
- nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
+ DisplayStatInfo stats;
+ mScheduler->getDisplayStatInfo(&stats);
- // We use the refreshStartTime which might be sampled a little later than
+ // We use the mRefreshStartTime which might be sampled a little later than
// when we started doing work for this frame, but that should be okay
// since updateCompositorTiming has snapping logic.
- updateCompositorTiming(
- vsyncPhase, vsyncInterval, refreshStartTime, presentFenceTime);
+ updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime);
CompositorTiming compositorTiming;
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -1831,8 +2057,9 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
}
mDrawingState.traverseInZOrder([&](Layer* layer) {
- bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
- presentFenceTime, compositorTiming);
+ bool frameLatched =
+ layer->onPostComposition(displayDevice->getId(), glCompositionDoneFenceTime,
+ presentFenceTime, compositorTiming);
if (frameLatched) {
recordBufferingStats(layer->getName().string(),
layer->getOccupancyHistory(false));
@@ -1840,16 +2067,13 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
});
if (presentFenceTime->isValid()) {
- if (mPrimaryDispSync.addPresentFence(presentFenceTime)) {
- enableHardwareVsync();
- } else {
- disableHardwareVsync(false);
- }
+ mScheduler->addPresentFence(presentFenceTime);
}
if (!hasSyncFramework) {
- if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) && hw->isDisplayOn()) {
- enableHardwareVsync();
+ if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
+ displayDevice->isPoweredOn()) {
+ mScheduler->enableHardwareVsync();
}
}
@@ -1859,23 +2083,25 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
- } else if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
+ } else if (displayDevice && getHwComposer().isConnected(*displayDevice->getId())) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- nsecs_t presentTime =
- getBE().mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+ const nsecs_t presentTime =
+ getHwComposer().getRefreshTimestamp(*displayDevice->getId());
mAnimFrameTracker.setActualPresentTime(presentTime);
}
mAnimFrameTracker.advanceFrame();
}
- mTimeStats.incrementTotalFrames();
+ mTimeStats->incrementTotalFrames();
if (mHadClientComposition) {
- mTimeStats.incrementClientCompositionFrames();
+ mTimeStats->incrementClientCompositionFrames();
}
- if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) &&
- hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+ mTimeStats->setPresentFenceGlobal(presentFenceTime);
+
+ if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
+ !displayDevice->isPoweredOn()) {
return;
}
@@ -1884,7 +2110,7 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
mHasPoweredOff = false;
} else {
nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
- size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncInterval);
+ size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod);
if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
getBE().mFrameBuckets[numPeriods] += elapsedTime;
} else {
@@ -1896,12 +2122,53 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
{
std::lock_guard lock(mTexturePoolMutex);
- const size_t refillCount = mTexturePoolSize - mTexturePool.size();
- if (refillCount > 0) {
+ 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());
+ }
+ }
+
+ mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]);
+
+ // Lock the mStateLock in case SurfaceFlinger is in the middle of applying a transaction.
+ // If we do not lock here, a callback could be sent without all of its SurfaceControls and
+ // metrics.
+ {
+ Mutex::Autolock _l(mStateLock);
+ mTransactionCompletedThread.sendCallbacks();
+ }
+
+ if (mLumaSampling && mRegionSamplingThread) {
+ mRegionSamplingThread->notifyNewContent();
+ }
+
+ // Even though ATRACE_INT64 already checks if tracing is enabled, it doesn't prevent the
+ // side-effect of getTotalSize(), so we check that again here
+ if (ATRACE_ENABLED()) {
+ ATRACE_INT64("Total Buffer Size", GraphicBufferAllocator::get().getTotalSize());
+ }
+}
+
+void SurfaceFlinger::computeLayerBounds() {
+ for (const auto& pair : mDisplays) {
+ const auto& displayDevice = pair.second;
+ const auto display = displayDevice->getCompositionDisplay();
+ for (const auto& layer : mDrawingState.layersSortedByZ) {
+ // only consider the layers on the given layer stack
+ if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+ continue;
+ }
+
+ layer->computeBounds(displayDevice->getViewport().toFloatRect(), ui::Transform());
}
}
}
@@ -1916,59 +2183,78 @@ void SurfaceFlinger::rebuildLayerStacks() {
mVisibleRegionsDirty = false;
invalidateHwcGeometry();
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ for (const auto& pair : mDisplays) {
+ const auto& displayDevice = pair.second;
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
Region opaqueRegion;
Region dirtyRegion;
- Vector<sp<Layer>> layersSortedByZ;
+ compositionengine::Output::OutputLayers layersSortedByZ;
+ Vector<sp<Layer>> deprecated_layersSortedByZ;
Vector<sp<Layer>> layersNeedingFences;
- const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
- const Transform& tr(displayDevice->getTransform());
- const Rect bounds(displayDevice->getBounds());
- if (displayDevice->isDisplayOn()) {
+ const ui::Transform& tr = displayState.transform;
+ const Rect bounds = displayState.bounds;
+ if (displayState.isEnabled) {
computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
mDrawingState.traverseInZOrder([&](Layer* layer) {
- bool hwcLayerDestroyed = false;
- if (layer->belongsToDisplay(displayDevice->getLayerStack(),
- displayDevice->isPrimary())) {
+ auto compositionLayer = layer->getCompositionLayer();
+ if (compositionLayer == nullptr) {
+ return;
+ }
+
+ const auto displayId = displayDevice->getId();
+ sp<compositionengine::LayerFE> layerFE = compositionLayer->getLayerFE();
+ LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr);
+
+ bool needsOutputLayer = false;
+
+ if (display->belongsInOutput(layer->getLayerStack(),
+ layer->getPrimaryDisplayOnly())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
if (!drawRegion.isEmpty()) {
- layersSortedByZ.add(layer);
- } else {
- // Clear out the HWC layer if this layer was
- // previously visible, but no longer is
- hwcLayerDestroyed = layer->destroyHwcLayer(
- displayDevice->getHwcDisplayId());
+ needsOutputLayer = true;
}
- } else {
- // WM changes displayDevice->layerStack upon sleep/awake.
- // Here we make sure we delete the HWC layers even if
- // WM changed their layer stack.
- hwcLayerDestroyed = layer->destroyHwcLayer(
- displayDevice->getHwcDisplayId());
}
- // If a layer is not going to get a release fence because
- // it is invisible, but it is also going to release its
- // old buffer, add it to the list of layers needing
- // fences.
- if (hwcLayerDestroyed) {
- auto found = std::find(mLayersWithQueuedFrames.cbegin(),
- mLayersWithQueuedFrames.cend(), layer);
- if (found != mLayersWithQueuedFrames.cend()) {
+ if (needsOutputLayer) {
+ layersSortedByZ.emplace_back(
+ display->getOrCreateOutputLayer(displayId, compositionLayer,
+ layerFE));
+ deprecated_layersSortedByZ.add(layer);
+
+ auto& outputLayerState = layersSortedByZ.back()->editState();
+ outputLayerState.visibleRegion =
+ tr.transform(layer->visibleRegion.intersect(displayState.viewport));
+ } else if (displayId) {
+ // For layers that are being removed from a HWC display,
+ // and that have queued frames, add them to a a list of
+ // released layers so we can properly set a fence.
+ bool hasExistingOutputLayer =
+ display->getOutputLayerForLayer(compositionLayer.get()) != nullptr;
+ bool hasQueuedFrames = std::find(mLayersWithQueuedFrames.cbegin(),
+ mLayersWithQueuedFrames.cend(),
+ layer) != mLayersWithQueuedFrames.cend();
+
+ if (hasExistingOutputLayer && hasQueuedFrames) {
layersNeedingFences.add(layer);
}
}
});
}
- displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
+
+ display->setOutputLayersOrderedByZ(std::move(layersSortedByZ));
+
+ displayDevice->setVisibleLayersSortedByZ(deprecated_layersSortedByZ);
displayDevice->setLayersNeedingFences(layersNeedingFences);
- displayDevice->undefinedRegion.set(bounds);
- displayDevice->undefinedRegion.subtractSelf(
- tr.transform(opaqueRegion));
- displayDevice->dirtyRegion.orSelf(dirtyRegion);
+
+ Region undefinedRegion{bounds};
+ undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
+
+ display->editState().undefinedRegion = undefinedRegion;
+ display->editState().dirtyRegion.orSelf(dirtyRegion);
}
}
}
@@ -1977,28 +2263,39 @@ void SurfaceFlinger::rebuildLayerStacks() {
// can only be one of
// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
// - Dataspace::DISPLAY_P3
+// - Dataspace::DISPLAY_BT2020
// The returned HDR data space is one of
// - Dataspace::UNKNOWN
// - Dataspace::BT2020_HLG
// - Dataspace::BT2020_PQ
-Dataspace SurfaceFlinger::getBestDataspace(
- const sp<const DisplayDevice>& displayDevice, Dataspace* outHdrDataSpace) const {
- Dataspace bestDataSpace = Dataspace::SRGB;
+Dataspace SurfaceFlinger::getBestDataspace(const sp<DisplayDevice>& display,
+ Dataspace* outHdrDataSpace,
+ bool* outIsHdrClientComposition) const {
+ Dataspace bestDataSpace = Dataspace::V0_SRGB;
*outHdrDataSpace = Dataspace::UNKNOWN;
- for (const auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ for (const auto& layer : display->getVisibleLayersSortedByZ()) {
switch (layer->getDataSpace()) {
case Dataspace::V0_SCRGB:
case Dataspace::V0_SCRGB_LINEAR:
+ case Dataspace::BT2020:
+ case Dataspace::BT2020_ITU:
+ case Dataspace::BT2020_LINEAR:
+ case Dataspace::DISPLAY_BT2020:
+ bestDataSpace = Dataspace::DISPLAY_BT2020;
+ break;
case Dataspace::DISPLAY_P3:
bestDataSpace = Dataspace::DISPLAY_P3;
break;
case Dataspace::BT2020_PQ:
case Dataspace::BT2020_ITU_PQ:
+ bestDataSpace = Dataspace::DISPLAY_P3;
*outHdrDataSpace = Dataspace::BT2020_PQ;
+ *outIsHdrClientComposition = layer->getForceClientComposition(display);
break;
case Dataspace::BT2020_HLG:
case Dataspace::BT2020_ITU_HLG:
+ bestDataSpace = Dataspace::DISPLAY_P3;
// When there's mixed PQ content and HLG content, we set the HDR
// data space to be BT2020_PQ and convert HLG to PQ.
if (*outHdrDataSpace == Dataspace::UNKNOWN) {
@@ -2014,9 +2311,8 @@ Dataspace SurfaceFlinger::getBestDataspace(
}
// Pick the ColorMode / Dataspace for the display device.
-void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice,
- ColorMode* outMode, Dataspace* outDataSpace,
- RenderIntent* outRenderIntent) const {
+void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& display, ColorMode* outMode,
+ Dataspace* outDataSpace, RenderIntent* outRenderIntent) const {
if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {
*outMode = ColorMode::NATIVE;
*outDataSpace = Dataspace::UNKNOWN;
@@ -2025,11 +2321,25 @@ void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice,
}
Dataspace hdrDataSpace;
- Dataspace bestDataSpace = getBestDataspace(displayDevice, &hdrDataSpace);
+ bool isHdrClientComposition = false;
+ Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace, &isHdrClientComposition);
+
+ auto* profile = display->getCompositionDisplay()->getDisplayColorProfile();
+
+ switch (mForceColorMode) {
+ case ColorMode::SRGB:
+ bestDataSpace = Dataspace::V0_SRGB;
+ break;
+ case ColorMode::DISPLAY_P3:
+ bestDataSpace = Dataspace::DISPLAY_P3;
+ break;
+ default:
+ break;
+ }
// respect hdrDataSpace only when there is no legacy HDR support
const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN &&
- !displayDevice->hasLegacyHdrSupport(hdrDataSpace);
+ !profile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition;
if (isHdr) {
bestDataSpace = hdrDataSpace;
}
@@ -2048,177 +2358,112 @@ void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice,
break;
}
- displayDevice->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
+ profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
}
-void SurfaceFlinger::setUpHWComposer() {
- ATRACE_CALL();
- ALOGV("setUpHWComposer");
+void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& displayDevice) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- bool dirty = !mDisplays[dpy]->getDirtyRegion(mRepaintEverything).isEmpty();
- bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
- bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
+ bool dirty = !display->getDirtyRegion(false).isEmpty();
+ bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
+ bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
- // If nothing has changed (!dirty), don't recompose.
- // If something changed, but we don't currently have any visible layers,
- // and didn't when we last did a composition, then skip it this time.
- // The second rule does two things:
- // - When all layers are removed from a display, we'll emit one black
- // frame, then nothing more until we get new layers.
- // - When a display is created with a private layer stack, we won't
- // emit any black frames until a layer is added to the layer stack.
- bool mustRecompose = dirty && !(empty && wasEmpty);
+ // If nothing has changed (!dirty), don't recompose.
+ // If something changed, but we don't currently have any visible layers,
+ // and didn't when we last did a composition, then skip it this time.
+ // The second rule does two things:
+ // - When all layers are removed from a display, we'll emit one black
+ // frame, then nothing more until we get new layers.
+ // - When a display is created with a private layer stack, we won't
+ // emit any black frames until a layer is added to the layer stack.
+ bool mustRecompose = dirty && !(empty && wasEmpty);
- ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
- "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy,
- mustRecompose ? "doing" : "skipping",
- dirty ? "+" : "-",
- empty ? "+" : "-",
- wasEmpty ? "+" : "-");
+ const char flagPrefix[] = {'-', '+'};
+ static_cast<void>(flagPrefix);
+ ALOGV_IF(displayDevice->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
+ __FUNCTION__, mustRecompose ? "doing" : "skipping",
+ displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty],
+ flagPrefix[wasEmpty]);
- mDisplays[dpy]->beginFrame(mustRecompose);
+ display->getRenderSurface()->beginFrame(mustRecompose);
- if (mustRecompose) {
- mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
- }
+ if (mustRecompose) {
+ display->editState().lastCompositionHadVisibleLayers = !empty;
}
+}
- // build the h/w work list
- if (CC_UNLIKELY(mGeometryInvalid)) {
- mGeometryInvalid = false;
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> displayDevice(mDisplays[dpy]);
- const auto hwcId = displayDevice->getHwcDisplayId();
- if (hwcId >= 0) {
- const Vector<sp<Layer>>& currentLayers(
- displayDevice->getVisibleLayersSortedByZ());
- for (size_t i = 0; i < currentLayers.size(); i++) {
- const auto& layer = currentLayers[i];
- if (!layer->hasHwcLayer(hwcId)) {
- if (!layer->createHwcLayer(getBE().mHwc.get(), hwcId)) {
- layer->forceClientComposition(hwcId);
- continue;
- }
- }
+void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& displayDevice) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
- layer->setGeometry(displayDevice, i);
- if (mDebugDisableHWC || mDebugRegion) {
- layer->forceClientComposition(hwcId);
- }
- }
- }
- }
+ if (!displayState.isEnabled) {
+ return;
}
- // Set the per-frame data
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- auto& displayDevice = mDisplays[displayId];
- const auto hwcId = displayDevice->getHwcDisplayId();
-
- if (hwcId < 0) {
- continue;
- }
- if (mDrawingState.colorMatrixChanged) {
- displayDevice->setColorTransform(mDrawingState.colorMatrix);
- status_t result = getBE().mHwc->setColorTransform(hwcId, mDrawingState.colorMatrix);
- ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
- "display %zd: %d", displayId, result);
- }
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- if (layer->isHdrY410()) {
- layer->forceClientComposition(hwcId);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
- !displayDevice->hasHDR10Support()) {
- layer->forceClientComposition(hwcId);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
- !displayDevice->hasHLGSupport()) {
- layer->forceClientComposition(hwcId);
- }
-
- if (layer->getForceClientComposition(hwcId)) {
- ALOGV("[%s] Requesting Client composition", layer->getName().string());
- layer->setCompositionType(hwcId, HWC2::Composition::Client);
- continue;
- }
+ status_t result = display->getRenderSurface()->prepareFrame();
+ ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
+ displayDevice->getDebugName().c_str(), result, strerror(-result));
+}
- layer->setPerFrameData(displayDevice);
- }
+void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool repaintEverything) {
+ ATRACE_CALL();
+ ALOGV("doComposition");
- if (hasWideColorDisplay) {
- ColorMode colorMode;
- Dataspace dataSpace;
- RenderIntent renderIntent;
- pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
- setActiveColorModeInternal(displayDevice, colorMode, dataSpace, renderIntent);
- }
- }
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
- mDrawingState.colorMatrixChanged = false;
+ if (displayState.isEnabled) {
+ // transform the dirty region into this screen's coordinate space
+ const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- auto& displayDevice = mDisplays[displayId];
- if (!displayDevice->isDisplayOn()) {
- continue;
- }
+ // repaint the framebuffer (if needed)
+ doDisplayComposition(displayDevice, dirtyRegion);
- status_t result = displayDevice->prepareFrame(*getBE().mHwc);
- ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
- " %d (%s)", displayId, result, strerror(-result));
+ display->editState().dirtyRegion.clear();
+ display->getRenderSurface()->flip();
}
+ postFramebuffer(displayDevice);
}
-void SurfaceFlinger::doComposition() {
- ATRACE_CALL();
- ALOGV("doComposition");
-
- const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- const sp<DisplayDevice>& hw(mDisplays[dpy]);
- if (hw->isDisplayOn()) {
- // transform the dirty region into this screen's coordinate space
- const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
-
- // repaint the framebuffer (if needed)
- doDisplayComposition(hw, dirtyRegion);
-
- hw->dirtyRegion.clear();
- hw->flip();
+void SurfaceFlinger::postFrame()
+{
+ // |mStateLock| not needed as we are on the main thread
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (display && getHwComposer().isConnected(*display->getId())) {
+ uint32_t flipCount = display->getPageFlipCount();
+ if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
+ logFrameStats();
}
}
- postFramebuffer();
}
-void SurfaceFlinger::postFramebuffer()
-{
+void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& displayDevice) {
ATRACE_CALL();
ALOGV("postFramebuffer");
- const nsecs_t now = systemTime();
- mDebugInSwapBuffers = now;
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+ const auto displayId = display->getId();
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- auto& displayDevice = mDisplays[displayId];
- if (!displayDevice->isDisplayOn()) {
- continue;
- }
- const auto hwcId = displayDevice->getHwcDisplayId();
- if (hwcId >= 0) {
- getBE().mHwc->presentAndGetReleaseFences(hwcId);
+ if (displayState.isEnabled) {
+ if (displayId) {
+ getHwComposer().presentAndGetReleaseFences(*displayId);
}
- displayDevice->onSwapBuffersCompleted();
- displayDevice->makeCurrent();
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ display->getRenderSurface()->onPresentDisplayCompleted();
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
sp<Fence> releaseFence = Fence::NO_FENCE;
+ bool usedClientComposition = true;
// The layer buffer from the previous frame (if any) is released
// by HWC only when the release fence from this frame (if any) is
// signaled. Always get the release fence from HWC first.
- auto hwcLayer = layer->getHwcLayer(hwcId);
- if (hwcId >= 0) {
- releaseFence = getBE().mHwc->getLayerReleaseFence(hwcId, hwcLayer);
+ if (layer->getState().hwc) {
+ const auto& hwcState = *layer->getState().hwc;
+ releaseFence =
+ getHwComposer().getLayerReleaseFence(*displayId, hwcState.hwcLayer.get());
+ usedClientComposition =
+ hwcState.hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
}
// If the layer was client composited in the previous frame, we
@@ -2226,37 +2471,28 @@ void SurfaceFlinger::postFramebuffer()
// Since we do not track that, always merge with the current
// client target acquire fence when it is available, even though
// this is suboptimal.
- if (layer->getCompositionType(hwcId) == HWC2::Composition::Client) {
- releaseFence = Fence::merge("LayerRelease", releaseFence,
- displayDevice->getClientTargetAcquireFence());
+ if (usedClientComposition) {
+ releaseFence =
+ Fence::merge("LayerRelease", releaseFence,
+ display->getRenderSurface()->getClientTargetAcquireFence());
}
- layer->onLayerDisplayed(releaseFence);
+ layer->getLayerFE().onLayerDisplayed(releaseFence);
}
// We've got a list of layers needing fences, that are disjoint with
- // displayDevice->getVisibleLayersSortedByZ. The best we can do is to
+ // display->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
if (!displayDevice->getLayersNeedingFences().isEmpty()) {
- sp<Fence> presentFence = getBE().mHwc->getPresentFence(hwcId);
+ sp<Fence> presentFence =
+ displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
for (auto& layer : displayDevice->getLayersNeedingFences()) {
- layer->onLayerDisplayed(presentFence);
+ layer->getCompositionLayer()->getLayerFE()->onLayerDisplayed(presentFence);
}
}
- if (hwcId >= 0) {
- getBE().mHwc->clearReleaseFences(hwcId);
- }
- }
-
- mLastSwapBufferTime = systemTime() - now;
- mDebugInSwapBuffers = 0;
-
- // |mStateLock| not needed as we are on the main thread
- if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
- uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
- if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
- logFrameStats();
+ if (displayId) {
+ getHwComposer().clearReleaseFences(*displayId);
}
}
}
@@ -2272,8 +2508,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
State drawingState(mDrawingState);
Mutex::Autolock _l(mStateLock);
- const nsecs_t now = systemTime();
- mDebugInTransaction = now;
+ mDebugInTransaction = systemTime();
// Here we're guaranteed that some transaction flags are set
// so we can call handleTransactionLocked() unconditionally.
@@ -2285,74 +2520,41 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
- mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
// here the transaction has been committed
}
-DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t display,
- HWC2::Connection connection) const {
- // Figure out whether the event is for the primary display or an
- // external display by matching the Hwc display id against one for a
- // connected display. If we did not find a match, we then check what
- // displays are not already connected to determine the type. If we don't
- // have a connected primary display, we assume the new display is meant to
- // be the primary display, and then if we don't have an external display,
- // we assume it is that.
- const auto primaryDisplayId =
- getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
- const auto externalDisplayId =
- getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_EXTERNAL);
- if (primaryDisplayId && primaryDisplayId == display) {
- return DisplayDevice::DISPLAY_PRIMARY;
- } else if (externalDisplayId && externalDisplayId == display) {
- return DisplayDevice::DISPLAY_EXTERNAL;
- } else if (connection == HWC2::Connection::Connected && !primaryDisplayId) {
- return DisplayDevice::DISPLAY_PRIMARY;
- } else if (connection == HWC2::Connection::Connected && !externalDisplayId) {
- return DisplayDevice::DISPLAY_EXTERNAL;
- }
-
- return DisplayDevice::DISPLAY_ID_INVALID;
-}
-
void SurfaceFlinger::processDisplayHotplugEventsLocked() {
for (const auto& event : mPendingHotplugEvents) {
- auto displayType = determineDisplayType(event.display, event.connection);
- if (displayType == DisplayDevice::DISPLAY_ID_INVALID) {
- ALOGW("Unable to determine the display type for display %" PRIu64, event.display);
- continue;
- }
+ const std::optional<DisplayIdentificationInfo> info =
+ getHwComposer().onHotplug(event.hwcDisplayId, event.connection);
- if (getBE().mHwc->isUsingVrComposer() && displayType == DisplayDevice::DISPLAY_EXTERNAL) {
- ALOGE("External displays are not supported by the vr hardware composer.");
+ if (!info) {
continue;
}
- getBE().mHwc->onHotplug(event.display, displayType, event.connection);
-
if (event.connection == HWC2::Connection::Connected) {
- if (!mBuiltinDisplays[displayType].get()) {
- ALOGV("Creating built in display %d", displayType);
- mBuiltinDisplays[displayType] = new BBinder();
- // All non-virtual displays are currently considered secure.
- DisplayDeviceState info(displayType, true);
- info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
- "Built-in Screen" : "External Screen";
- mCurrentState.displays.add(mBuiltinDisplays[displayType], info);
- mInterceptor->saveDisplayCreation(info);
+ if (!mPhysicalDisplayTokens.count(info->id)) {
+ ALOGV("Creating display %s", to_string(info->id).c_str());
+ mPhysicalDisplayTokens[info->id] = new BBinder();
+ DisplayDeviceState state;
+ state.displayId = info->id;
+ state.isSecure = true; // All physical displays are currently considered secure.
+ state.displayName = info->name;
+ mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
+ mInterceptor->saveDisplayCreation(state);
}
} else {
- ALOGV("Removing built in display %d", displayType);
+ ALOGV("Removing display %s", to_string(info->id).c_str());
- ssize_t idx = mCurrentState.displays.indexOfKey(mBuiltinDisplays[displayType]);
- if (idx >= 0) {
- const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
- mInterceptor->saveDisplayDeletion(info.displayId);
- mCurrentState.displays.removeItemsAt(idx);
+ ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]);
+ if (index >= 0) {
+ const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
+ mInterceptor->saveDisplayDeletion(state.sequenceId);
+ mCurrentState.displays.removeItemsAt(index);
}
- mBuiltinDisplays[displayType].clear();
+ mPhysicalDisplayTokens.erase(info->id);
}
processDisplayChangesLocked();
@@ -2361,74 +2563,63 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() {
mPendingHotplugEvents.clear();
}
+void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
+ mScheduler->hotplugReceived(mAppConnectionHandle, displayId, connected);
+ mScheduler->hotplugReceived(mSfConnectionHandle, displayId, connected);
+}
+
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
- const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state,
- const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
- bool hasWideColorGamut = false;
- std::unordered_map<ColorMode, std::vector<RenderIntent>> hwcColorModes;
- HdrCapabilities hdrCapabilities;
- int32_t supportedPerFrameMetadata = 0;
-
- if (hasWideColorDisplay && hwcId >= 0) {
- std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
+ const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
+ const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface,
+ const sp<IGraphicBufferProducer>& producer) {
+ DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
+ creationArgs.sequenceId = state.sequenceId;
+ creationArgs.isVirtual = state.isVirtual();
+ creationArgs.isSecure = state.isSecure;
+ creationArgs.displaySurface = dispSurface;
+ creationArgs.hasWideColorGamut = false;
+ creationArgs.supportedPerFrameMetadata = 0;
+
+ const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
+ creationArgs.isPrimary = isInternalDisplay;
+
+ if (useColorManagement && displayId) {
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
for (ColorMode colorMode : modes) {
- switch (colorMode) {
- case ColorMode::DISPLAY_P3:
- case ColorMode::ADOBE_RGB:
- case ColorMode::DCI_P3:
- hasWideColorGamut = true;
- break;
- default:
- break;
+ if (isWideColorMode(colorMode)) {
+ creationArgs.hasWideColorGamut = true;
}
- std::vector<RenderIntent> renderIntents = getHwComposer().getRenderIntents(hwcId,
- colorMode);
- hwcColorModes.emplace(colorMode, renderIntents);
+ std::vector<RenderIntent> renderIntents =
+ getHwComposer().getRenderIntents(*displayId, colorMode);
+ creationArgs.hwcColorModes.emplace(colorMode, renderIntents);
}
}
- if (hwcId >= 0) {
- getHwComposer().getHdrCapabilities(hwcId, &hdrCapabilities);
- supportedPerFrameMetadata = getHwComposer().getSupportedPerFrameMetadata(hwcId);
+ if (displayId) {
+ getHwComposer().getHdrCapabilities(*displayId, &creationArgs.hdrCapabilities);
+ creationArgs.supportedPerFrameMetadata =
+ getHwComposer().getSupportedPerFrameMetadata(*displayId);
}
- auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
+ auto nativeWindowSurface = getFactory().createNativeWindowSurface(producer);
auto nativeWindow = nativeWindowSurface->getNativeWindow();
-
- /*
- * Create our display's surface
- */
- std::unique_ptr<RE::Surface> renderSurface = getRenderEngine().createSurface();
- renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY);
- renderSurface->setAsync(state.type >= DisplayDevice::DISPLAY_VIRTUAL);
- renderSurface->setNativeWindow(nativeWindow.get());
- const int displayWidth = renderSurface->queryWidth();
- const int displayHeight = renderSurface->queryHeight();
+ creationArgs.nativeWindow = nativeWindow;
// Make sure that composition can never be stalled by a virtual display
// consumer that isn't processing buffers fast enough. We have to do this
- // in two places:
- // * Here, in case the display is composed entirely by HWC.
- // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
- // window's swap interval in eglMakeCurrent, so they'll override the
- // interval we set here.
- if (state.type >= DisplayDevice::DISPLAY_VIRTUAL) {
+ // here, in case the display is composed entirely by HWC.
+ if (state.isVirtual()) {
nativeWindow->setSwapInterval(nativeWindow.get(), 0);
}
- const int displayInstallOrientation = state.type == DisplayDevice::DISPLAY_PRIMARY ?
- primaryDisplayOrientation : DisplayState::eOrientationDefault;
+ creationArgs.displayInstallOrientation =
+ isInternalDisplay ? primaryDisplayOrientation : DisplayState::eOrientationDefault;
// virtual displays are always considered enabled
- auto initialPowerMode = (state.type >= DisplayDevice::DISPLAY_VIRTUAL) ? HWC_POWER_MODE_NORMAL
- : HWC_POWER_MODE_OFF;
+ creationArgs.initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
- sp<DisplayDevice> hw =
- new DisplayDevice(this, state.type, hwcId, state.isSecure, display, nativeWindow,
- dispSurface, std::move(renderSurface), displayWidth, displayHeight,
- displayInstallOrientation, hasWideColorGamut, hdrCapabilities,
- supportedPerFrameMetadata, hwcColorModes, initialPowerMode);
+ sp<DisplayDevice> display = getFactory().createDisplayDevice(std::move(creationArgs));
if (maxFrameBufferAcquiredBuffers >= 3) {
nativeWindowSurface->preallocateBuffers();
@@ -2436,20 +2627,22 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
ColorMode defaultColorMode = ColorMode::NATIVE;
Dataspace defaultDataSpace = Dataspace::UNKNOWN;
- if (hasWideColorGamut) {
+ if (display->hasWideColorGamut()) {
defaultColorMode = ColorMode::SRGB;
- defaultDataSpace = Dataspace::SRGB;
+ defaultDataSpace = Dataspace::V0_SRGB;
}
- setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace,
- RenderIntent::COLORIMETRIC);
- if (state.type < DisplayDevice::DISPLAY_VIRTUAL) {
- hw->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
+ display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace,
+ RenderIntent::COLORIMETRIC);
+ if (!state.isVirtual()) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
}
- hw->setLayerStack(state.layerStack);
- hw->setProjection(state.orientation, state.viewport, state.frame);
- hw->setDisplayName(state.displayName);
- return hw;
+ display->setLayerStack(state.layerStack);
+ display->setProjection(state.orientation, state.viewport, state.frame);
+ display->setDisplayName(state.displayName);
+
+ return display;
}
void SurfaceFlinger::processDisplayChangesLocked() {
@@ -2471,20 +2664,22 @@ void SurfaceFlinger::processDisplayChangesLocked() {
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
if (j < 0) {
// in drawing state but not in current state
- // Call makeCurrent() on the primary display so we can
- // be sure that nothing associated with this display
- // is current.
- const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
- if (defaultDisplay != nullptr) defaultDisplay->makeCurrent();
- sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
- if (hw != nullptr) hw->disconnect(getHwComposer());
- if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
- mEventThread->onHotplugReceived(draw[i].type, false);
- mDisplays.removeItem(draw.keyAt(i));
+ if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
+ // Save display ID before disconnecting.
+ const auto displayId = display->getId();
+ display->disconnect();
+
+ if (!display->isVirtual()) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ dispatchDisplayHotplugEvent(displayId->value, false);
+ }
+ }
+
+ mDisplays.erase(draw.keyAt(i));
} else {
// this display is in both lists. see if something changed.
const DisplayDeviceState& state(curr[j]);
- const wp<IBinder>& display(curr.keyAt(j));
+ const wp<IBinder>& displayToken = curr.keyAt(j);
const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
if (state_binder != draw_binder) {
@@ -2492,26 +2687,26 @@ void SurfaceFlinger::processDisplayChangesLocked() {
// recreating the DisplayDevice, so we just remove it
// from the drawing state, so that it get re-added
// below.
- sp<DisplayDevice> hw(getDisplayDeviceLocked(display));
- if (hw != nullptr) hw->disconnect(getHwComposer());
- mDisplays.removeItem(display);
+ if (const auto display = getDisplayDeviceLocked(displayToken)) {
+ display->disconnect();
+ }
+ mDisplays.erase(displayToken);
mDrawingState.displays.removeItemsAt(i);
dc--;
// at this point we must loop to the next item
continue;
}
- const sp<DisplayDevice> disp(getDisplayDeviceLocked(display));
- if (disp != nullptr) {
+ if (const auto display = getDisplayDeviceLocked(displayToken)) {
if (state.layerStack != draw[i].layerStack) {
- disp->setLayerStack(state.layerStack);
+ display->setLayerStack(state.layerStack);
}
if ((state.orientation != draw[i].orientation) ||
(state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) {
- disp->setProjection(state.orientation, state.viewport, state.frame);
+ display->setProjection(state.orientation, state.viewport, state.frame);
}
if (state.width != draw[i].width || state.height != draw[i].height) {
- disp->setDisplaySize(state.width, state.height);
+ display->setDisplaySize(state.width, state.height);
}
}
}
@@ -2524,20 +2719,20 @@ void SurfaceFlinger::processDisplayChangesLocked() {
if (draw.indexOfKey(curr.keyAt(i)) < 0) {
const DisplayDeviceState& state(curr[i]);
- sp<DisplaySurface> dispSurface;
+ sp<compositionengine::DisplaySurface> dispSurface;
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
- mCreateBufferQueue(&bqProducer, &bqConsumer, false);
+ getFactory().createBufferQueue(&bqProducer, &bqConsumer, false);
- int32_t hwcId = -1;
- if (state.isVirtualDisplay()) {
+ std::optional<DisplayId> displayId;
+ if (state.isVirtual()) {
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
// etc.) but no internal state (i.e. a DisplayDevice).
if (state.surface != nullptr) {
// Allow VR composer to use virtual displays.
- if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) {
+ if (mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer()) {
int width = 0;
int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
@@ -2549,13 +2744,14 @@ void SurfaceFlinger::processDisplayChangesLocked() {
ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
auto format = static_cast<ui::PixelFormat>(intFormat);
- getBE().mHwc->allocateVirtualDisplay(width, height, &format, &hwcId);
+ displayId =
+ getHwComposer().allocateVirtualDisplay(width, height, &format);
}
// TODO: Plumb requested format back up to consumer
sp<VirtualDisplaySurface> vds =
- new VirtualDisplaySurface(*getBE().mHwc, hwcId, state.surface,
+ new VirtualDisplaySurface(getHwComposer(), displayId, state.surface,
bqProducer, bqConsumer,
state.displayName);
@@ -2568,18 +2764,20 @@ void SurfaceFlinger::processDisplayChangesLocked() {
"surface is provided (%p), ignoring it",
state.surface.get());
- hwcId = state.type;
- dispSurface = new FramebufferSurface(*getBE().mHwc, hwcId, bqConsumer);
+ displayId = state.displayId;
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
producer = bqProducer;
}
- const wp<IBinder>& display(curr.keyAt(i));
+ const wp<IBinder>& displayToken = curr.keyAt(i);
if (dispSurface != nullptr) {
- mDisplays.add(display,
- setupNewDisplayDeviceInternal(display, hwcId, state, dispSurface,
- producer));
- if (!state.isVirtualDisplay()) {
- mEventThread->onHotplugReceived(state.type, true);
+ mDisplays.emplace(displayToken,
+ setupNewDisplayDeviceInternal(displayToken, displayId, state,
+ dispSurface, producer));
+ if (!state.isVirtual()) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ dispatchDisplayHotplugEvent(displayId->value, true);
}
}
}
@@ -2601,7 +2799,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
* (perform the transaction for each of them if needed)
*/
- if (transactionFlags & eTraversalNeeded) {
+ if ((transactionFlags & eTraversalNeeded) || mTraversalNeededMainThread) {
mCurrentState.traverseInZOrder([&](Layer* layer) {
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) return;
@@ -2609,7 +2807,12 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
const uint32_t flags = layer->doTransaction(0);
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
+
+ if (flags & Layer::eInputInfoChanged) {
+ mInputInfoChanged = true;
+ }
});
+ mTraversalNeededMainThread = false;
}
/*
@@ -2641,7 +2844,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
// happened yet, so we must use the current state layer list
// (soon to become the drawing state list).
//
- sp<const DisplayDevice> disp;
+ sp<const DisplayDevice> hintDisplay;
uint32_t currentlayerStack = 0;
bool first = true;
mCurrentState.traverseInZOrder([&](Layer* layer) {
@@ -2654,34 +2857,35 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
// figure out if this layerstack is mirrored
// (more than one display) if so, pick the default display,
// if not, pick the only display it's on.
- disp.clear();
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
- if (disp == nullptr) {
- disp = std::move(hw);
- } else {
- disp = nullptr;
+ hintDisplay = nullptr;
+ for (const auto& [token, display] : mDisplays) {
+ if (display->getCompositionDisplay()
+ ->belongsInOutput(layer->getLayerStack(),
+ layer->getPrimaryDisplayOnly())) {
+ if (hintDisplay) {
+ hintDisplay = nullptr;
break;
+ } else {
+ hintDisplay = display;
}
}
}
}
- if (disp == nullptr) {
+ if (!hintDisplay) {
// NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
// redraw after transform hint changes. See bug 8508397.
// could be null when this layer is using a layerStack
// that is not visible on any display. Also can occur at
// screen off/on times.
- disp = getDefaultDisplayDeviceLocked();
+ hintDisplay = getDefaultDisplayDeviceLocked();
}
- // disp can be null if there is no display available at all to get
+ // could be null if there is no display available at all to get
// the transform hint from.
- if (disp != nullptr) {
- layer->updateTransformHint(disp);
+ if (hintDisplay) {
+ layer->updateTransformHint(hintDisplay);
}
first = false;
@@ -2707,35 +2911,90 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (mLayersPendingRemoval.indexOf(layer) >= 0) {
// this layer is not visible anymore
- // TODO: we could traverse the tree from front to back and
- // compute the actual visible region
- // TODO: we could cache the transformed region
Region visibleReg;
- visibleReg.set(layer->computeScreenBounds());
+ visibleReg.set(layer->getScreenBounds());
invalidateLayerStack(layer, visibleReg);
}
});
}
+ commitInputWindowCommands();
commitTransaction();
+}
+
+void SurfaceFlinger::updateInputFlinger() {
+ ATRACE_CALL();
+ if (!mInputFlinger) {
+ return;
+ }
- updateCursorAsync();
+ if (mVisibleRegionsDirty || mInputInfoChanged) {
+ mInputInfoChanged = false;
+ updateInputWindowInfo();
+ } else if (mInputWindowCommands.syncInputWindows) {
+ // If the caller requested to sync input windows, but there are no
+ // changes to input windows, notify immediately.
+ setInputWindowsFinished();
+ }
+
+ executeInputWindowCommands();
+}
+
+void SurfaceFlinger::updateInputWindowInfo() {
+ std::vector<InputWindowInfo> inputHandles;
+
+ mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
+ if (layer->hasInput()) {
+ // When calculating the screen bounds we ignore the transparent region since it may
+ // result in an unwanted offset.
+ inputHandles.push_back(layer->fillInputInfo());
+ }
+ });
+
+ mInputFlinger->setInputWindows(inputHandles,
+ mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
+ : nullptr);
+}
+
+void SurfaceFlinger::commitInputWindowCommands() {
+ mInputWindowCommands = mPendingInputWindowCommands;
+ mPendingInputWindowCommands.clear();
+}
+
+void SurfaceFlinger::executeInputWindowCommands() {
+ for (const auto& transferTouchFocusCommand : mInputWindowCommands.transferTouchFocusCommands) {
+ if (transferTouchFocusCommand.fromToken != nullptr &&
+ transferTouchFocusCommand.toToken != nullptr &&
+ transferTouchFocusCommand.fromToken != transferTouchFocusCommand.toToken) {
+ mInputFlinger->transferTouchFocus(transferTouchFocusCommand.fromToken,
+ transferTouchFocusCommand.toToken);
+ }
+ }
+
+ mInputWindowCommands.clear();
}
void SurfaceFlinger::updateCursorAsync()
{
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- auto& displayDevice = mDisplays[displayId];
- if (displayDevice->getHwcDisplayId() < 0) {
+ for (const auto& [token, display] : mDisplays) {
+ if (!display->getId()) {
continue;
}
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- layer->updateCursorPosition(displayDevice);
+ for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ layer->updateCursorPosition(display);
}
}
}
+void SurfaceFlinger::latchAndReleaseBuffer(const sp<Layer>& layer) {
+ if (layer->hasReadyFrame()) {
+ bool ignored = false;
+ layer->latchBuffer(ignored, systemTime());
+ }
+ layer->releasePendingBuffer(systemTime());
+}
+
void SurfaceFlinger::commitTransaction()
{
if (!mLayersPendingRemoval.isEmpty()) {
@@ -2743,7 +3002,18 @@ void SurfaceFlinger::commitTransaction()
for (const auto& l : mLayersPendingRemoval) {
recordBufferingStats(l->getName().string(),
l->getOccupancyHistory(true));
- l->onRemoved();
+
+ // Ensure any buffers set to display on any children are released.
+ if (l->isRemovedFromCurrentState()) {
+ latchAndReleaseBuffer(l);
+ }
+
+ // If the layer has been removed and has no parent, then it will not be reachable
+ // when traversing layers on screen. Add the layer to the offscreenLayers set to
+ // ensure we can copy its current to drawing state.
+ if (!l->getParent()) {
+ mOffscreenLayers.emplace(l.get());
+ }
}
mLayersPendingRemoval.clear();
}
@@ -2752,24 +3022,68 @@ void SurfaceFlinger::commitTransaction()
// we composite should be considered an animation as well.
mAnimCompositionPending = mAnimTransactionPending;
- mDrawingState = mCurrentState;
- // clear the "changed" flags in current state
- mCurrentState.colorMatrixChanged = false;
+ withTracingLock([&]() {
+ mDrawingState = mCurrentState;
+ // clear the "changed" flags in current state
+ mCurrentState.colorMatrixChanged = false;
+
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ layer->commitChildList();
+
+ // If the layer can be reached when traversing mDrawingState, then the layer is no
+ // longer offscreen. Remove the layer from the offscreenLayer set.
+ if (mOffscreenLayers.count(layer)) {
+ mOffscreenLayers.erase(layer);
+ }
+ });
- mDrawingState.traverseInZOrder([](Layer* layer) {
- layer->commitChildList();
+ commitOffscreenLayers();
});
+
mTransactionPending = false;
mAnimTransactionPending = false;
mTransactionCV.broadcast();
}
+void SurfaceFlinger::withTracingLock(std::function<void()> lockedOperation) {
+ if (mTracingEnabledChanged) {
+ mTracingEnabled = mTracing.isEnabled();
+ mTracingEnabledChanged = false;
+ }
+
+ // Synchronize with Tracing thread
+ std::unique_lock<std::mutex> lock;
+ if (mTracingEnabled) {
+ lock = std::unique_lock<std::mutex>(mDrawingStateLock);
+ }
+
+ lockedOperation();
+
+ // Synchronize with Tracing thread
+ if (mTracingEnabled) {
+ lock.unlock();
+ }
+}
+
+void SurfaceFlinger::commitOffscreenLayers() {
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [](Layer* layer) {
+ uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
+ if (!trFlags) return;
+
+ layer->doTransaction(0);
+ layer->commitChildList();
+ });
+ }
+}
+
void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
- Region& outDirtyRegion, Region& outOpaqueRegion)
-{
+ Region& outDirtyRegion, Region& outOpaqueRegion) {
ATRACE_CALL();
ALOGV("computeVisibleRegions");
+ auto display = displayDevice->getCompositionDisplay();
+
Region aboveOpaqueLayers;
Region aboveCoveredLayers;
Region dirty;
@@ -2781,8 +3095,9 @@ void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displa
const Layer::State& s(layer->getDrawingState());
// only consider the layers on the given layer stack
- if (!layer->belongsToDisplay(displayDevice->getLayerStack(), displayDevice->isPrimary()))
+ if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
return;
+ }
/*
* opaqueRegion: area of a surface that is fully opaque.
@@ -2817,15 +3132,16 @@ void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displa
// handle hidden surfaces by setting the visible region to empty
if (CC_LIKELY(layer->isVisible())) {
const bool translucent = !layer->isOpaque(s);
- Rect bounds(layer->computeScreenBounds());
+ Rect bounds(layer->getScreenBounds());
+
visibleRegion.set(bounds);
- Transform tr = layer->getTransform();
+ ui::Transform tr = layer->getTransform();
if (!visibleRegion.isEmpty()) {
// Remove the transparent area from the visible region
if (translucent) {
if (tr.preserveRects()) {
// transform the transparent region
- transparentRegion = tr.transform(s.activeTransparentRegion);
+ transparentRegion = tr.transform(layer->getActiveTransparentRegion(s));
} else {
// transformation too complex, can't do the
// transparent region optimization.
@@ -2836,7 +3152,8 @@ void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displa
// compute the opaque region
const int32_t layerOrientation = tr.getOrientation();
if (layer->getAlpha() == 1.0f && !translucent &&
- ((layerOrientation & Transform::ROT_INVALID) == false)) {
+ layer->getRoundedCornerState().radius == 0.0f &&
+ ((layerOrientation & ui::Transform::ROT_INVALID) == false)) {
// the opaque region is the layer's footprint
opaqueRegion = visibleRegion;
}
@@ -2902,16 +3219,17 @@ void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displa
}
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- const sp<DisplayDevice>& hw(mDisplays[dpy]);
- if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
- hw->dirtyRegion.orSelf(dirty);
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ if (display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+ display->editState().dirtyRegion.orSelf(dirty);
}
}
}
bool SurfaceFlinger::handlePageFlip()
{
+ ATRACE_CALL();
ALOGV("handlePageFlip");
nsecs_t latchTime = systemTime();
@@ -2930,11 +3248,14 @@ bool SurfaceFlinger::handlePageFlip()
// Display is now waiting on Layer 1's frame, which is behind layer 0's
// second frame. But layer 0's second frame could be waiting on display.
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (layer->hasQueuedFrame()) {
+ if (layer->hasReadyFrame()) {
frameQueued = true;
- if (layer->shouldPresentNow(mPrimaryDispSync)) {
+ nsecs_t expectedPresentTime;
+ expectedPresentTime = mScheduler->expectedPresentTime();
+ if (layer->shouldPresentNow(expectedPresentTime)) {
mLayersWithQueuedFrames.push_back(layer);
} else {
+ ATRACE_NAME("!layer->shouldPresentNow()");
layer->useEmptyDamage();
}
} else {
@@ -2942,12 +3263,19 @@ bool SurfaceFlinger::handlePageFlip()
}
});
- for (auto& layer : mLayersWithQueuedFrames) {
- const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
- layer->useSurfaceDamage();
- invalidateLayerStack(layer, dirty);
- if (layer->isBufferLatched()) {
- newDataLatched = true;
+ if (!mLayersWithQueuedFrames.empty()) {
+ // mStateLock is needed for latchBuffer as LayerRejecter::reject()
+ // writes to Layer current state. See also b/119481871
+ Mutex::Autolock lock(mStateLock);
+
+ for (auto& layer : mLayersWithQueuedFrames) {
+ if (layer->latchBuffer(visibleRegions, latchTime)) {
+ mLayersPendingRefresh.push_back(layer);
+ }
+ layer->useSurfaceDamage();
+ if (layer->isBufferLatched()) {
+ newDataLatched = true;
+ }
}
}
@@ -2975,121 +3303,104 @@ void SurfaceFlinger::invalidateHwcGeometry()
mGeometryInvalid = true;
}
-
-void SurfaceFlinger::doDisplayComposition(
- const sp<const DisplayDevice>& displayDevice,
- const Region& inDirtyRegion)
-{
+void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& displayDevice,
+ const Region& inDirtyRegion) {
+ auto display = displayDevice->getCompositionDisplay();
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty)
- bool isHwcDisplay = displayDevice->getHwcDisplayId() >= 0;
- if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
+ if (!displayDevice->getId() && inDirtyRegion.isEmpty()) {
ALOGV("Skipping display composition");
return;
}
ALOGV("doDisplayComposition");
- if (!doComposeSurfaces(displayDevice)) return;
+ base::unique_fd readyFence;
+ if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return;
// swap buffers (presentation)
- displayDevice->swapBuffers(getHwComposer());
+ display->getRenderSurface()->queueBuffer(std::move(readyFence));
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDevice)
-{
+bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice,
+ const Region& debugRegion, base::unique_fd* readyFence) {
+ ATRACE_CALL();
ALOGV("doComposeSurfaces");
- const Region bounds(displayDevice->bounds());
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+ const auto displayId = display->getId();
+ auto& renderEngine = getRenderEngine();
+ const bool supportProtectedContent = renderEngine.supportsProtectedContent();
+
+ const Region bounds(displayState.bounds);
const DisplayRenderArea renderArea(displayDevice);
- const auto hwcId = displayDevice->getHwcDisplayId();
- const bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
+ const bool hasClientComposition = getHwComposer().hasClientComposition(displayId);
ATRACE_INT("hasClientComposition", hasClientComposition);
bool applyColorMatrix = false;
- bool needsEnhancedColorMatrix = false;
+
+ renderengine::DisplaySettings clientCompositionDisplay;
+ std::vector<renderengine::LayerSettings> clientCompositionLayers;
+ sp<GraphicBuffer> buf;
+ base::unique_fd fd;
if (hasClientComposition) {
ALOGV("hasClientComposition");
- Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (displayDevice->hasWideColorGamut()) {
- outputDataspace = displayDevice->getCompositionDataSpace();
- }
- getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
- getBE().mRenderEngine->setDisplayMaxLuminance(
- displayDevice->getHdrCapabilities().getDesiredMaxLuminance());
-
- const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId);
- const bool skipClientColorTransform = getBE().mHwc->hasCapability(
- HWC2::Capability::SkipClientColorTransform);
-
- mat4 colorMatrix;
- applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
- if (applyColorMatrix) {
- colorMatrix = mDrawingState.colorMatrix;
- }
-
- // The current enhanced saturation matrix is designed to enhance Display P3,
- // thus we only apply this matrix when the render intent is not colorimetric
- // and the output color space is Display P3.
- needsEnhancedColorMatrix =
- (displayDevice->getActiveRenderIntent() >= RenderIntent::ENHANCE &&
- outputDataspace == Dataspace::DISPLAY_P3);
- if (needsEnhancedColorMatrix) {
- colorMatrix *= mEnhancedSaturationMatrix;
+ if (displayDevice->isPrimary() && supportProtectedContent) {
+ bool needsProtected = false;
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ // If the layer is a protected layer, mark protected context is needed.
+ if (layer->isProtected()) {
+ needsProtected = true;
+ break;
+ }
+ }
+ if (needsProtected != renderEngine.isProtected()) {
+ renderEngine.useProtectedContext(needsProtected);
+ }
+ if (needsProtected != display->getRenderSurface()->isProtected() &&
+ needsProtected == renderEngine.isProtected()) {
+ display->getRenderSurface()->setProtected(needsProtected);
+ }
}
- getRenderEngine().setupColorTransform(colorMatrix);
-
- if (!displayDevice->makeCurrent()) {
- ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
- displayDevice->getDisplayName().string());
- getRenderEngine().resetCurrentSurface();
+ buf = display->getRenderSurface()->dequeueBuffer(&fd);
- // |mStateLock| not needed as we are on the main thread
- if(!getDefaultDisplayDeviceLocked()->makeCurrent()) {
- ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
- }
+ if (buf == nullptr) {
+ ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
+ "client composition for this frame",
+ displayDevice->getDisplayName().c_str());
return false;
}
- // Never touch the framebuffer if we don't have any framebuffer layers
- if (hasDeviceComposition) {
- // when using overlays, we assume a fully transparent framebuffer
- // NOTE: we could reduce how much we need to clear, for instance
- // remove where there are opaque FB layers. however, on some
- // GPUs doing a "clean slate" clear might be more efficient.
- // We'll revisit later if needed.
- getBE().mRenderEngine->clearWithColor(0, 0, 0, 0);
- } else {
- // we start with the whole screen area and remove the scissor part
- // we're left with the letterbox region
- // (common case is that letterbox ends-up being empty)
- const Region letterbox(bounds.subtract(displayDevice->getScissor()));
-
- // compute the area to clear
- Region region(displayDevice->undefinedRegion.merge(letterbox));
-
- // screen is already cleared here
- if (!region.isEmpty()) {
- // can happen with SurfaceView
- drawWormhole(displayDevice, region);
- }
+ clientCompositionDisplay.physicalDisplay = displayState.scissor;
+ clientCompositionDisplay.clip = displayState.scissor;
+ const ui::Transform& displayTransform = displayState.transform;
+ clientCompositionDisplay.globalTransform = displayTransform.asMatrix4();
+ clientCompositionDisplay.orientation = displayState.orientation;
+
+ const auto* profile = display->getDisplayColorProfile();
+ Dataspace outputDataspace = Dataspace::UNKNOWN;
+ if (profile->hasWideColorGamut()) {
+ outputDataspace = displayState.dataspace;
}
+ clientCompositionDisplay.outputDataspace = outputDataspace;
+ clientCompositionDisplay.maxLuminance =
+ profile->getHdrCapabilities().getDesiredMaxLuminance();
- const Rect& bounds(displayDevice->getBounds());
- const Rect& scissor(displayDevice->getScissor());
- if (scissor != bounds) {
- // scissor doesn't match the screen's dimensions, so we
- // need to clear everything outside of it and enable
- // the GL scissor so we don't draw anything where we shouldn't
+ const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId);
+ const bool skipClientColorTransform =
+ getHwComposer()
+ .hasDisplayCapability(displayId,
+ HWC2::DisplayCapability::SkipClientColorTransform);
- // enable scissor for this frame
- const uint32_t height = displayDevice->getHeight();
- getBE().mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
- scissor.getWidth(), scissor.getHeight());
+ // Compute the global color transform matrix.
+ applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
+ if (applyColorMatrix) {
+ clientCompositionDisplay.colorTransform = displayState.colorTransformMat;
}
}
@@ -3098,32 +3409,50 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDev
*/
ALOGV("Rendering client layers");
- const Transform& displayTransform = displayDevice->getTransform();
bool firstLayer = true;
+ Region clearRegion = Region::INVALID_REGION;
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- const Region clip(bounds.intersect(
- displayTransform.transform(layer->visibleRegion)));
+ const Region viewportRegion(displayState.viewport);
+ const Region clip(viewportRegion.intersect(layer->visibleRegion));
ALOGV("Layer: %s", layer->getName().string());
- ALOGV(" Composition type: %s",
- to_string(layer->getCompositionType(hwcId)).c_str());
+ ALOGV(" Composition type: %s", toString(layer->getCompositionType(displayDevice)).c_str());
if (!clip.isEmpty()) {
- switch (layer->getCompositionType(hwcId)) {
- case HWC2::Composition::Cursor:
- case HWC2::Composition::Device:
- case HWC2::Composition::Sideband:
- case HWC2::Composition::SolidColor: {
+ switch (layer->getCompositionType(displayDevice)) {
+ case Hwc2::IComposerClient::Composition::CURSOR:
+ case Hwc2::IComposerClient::Composition::DEVICE:
+ case Hwc2::IComposerClient::Composition::SIDEBAND:
+ case Hwc2::IComposerClient::Composition::SOLID_COLOR: {
+ LOG_ALWAYS_FATAL_IF(!displayId);
const Layer::State& state(layer->getDrawingState());
- if (layer->getClearClientTarget(hwcId) && !firstLayer &&
- layer->isOpaque(state) && (state.color.a == 1.0f)
- && hasClientComposition) {
+ if (layer->getClearClientTarget(displayDevice) && !firstLayer &&
+ layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
+ layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
- layer->clearWithOpenGL(renderArea);
+ renderengine::LayerSettings layerSettings;
+ Region dummyRegion;
+ bool prepared =
+ layer->prepareClientLayer(renderArea, clip, dummyRegion,
+ supportProtectedContent, layerSettings);
+
+ if (prepared) {
+ layerSettings.source.buffer.buffer = nullptr;
+ layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
+ layerSettings.alpha = half(0.0);
+ layerSettings.disableBlending = true;
+ clientCompositionLayers.push_back(layerSettings);
+ }
}
break;
}
- case HWC2::Composition::Client: {
- layer->draw(renderArea, clip);
+ case Hwc2::IComposerClient::Composition::CLIENT: {
+ renderengine::LayerSettings layerSettings;
+ bool prepared =
+ layer->prepareClientLayer(renderArea, clip, clearRegion,
+ supportProtectedContent, layerSettings);
+ if (prepared) {
+ clientCompositionLayers.push_back(layerSettings);
+ }
break;
}
default:
@@ -3135,42 +3464,79 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDev
firstLayer = false;
}
- if (applyColorMatrix || needsEnhancedColorMatrix) {
- getRenderEngine().setupColorTransform(mat4());
+ // Perform some cleanup steps if we used client composition.
+ if (hasClientComposition) {
+ clientCompositionDisplay.clearRegion = clearRegion;
+
+ // We boost GPU frequency here because there will be color spaces conversion
+ // and it's expensive. We boost the GPU frequency so that GPU composition can
+ // finish in time. We must reset GPU frequency afterwards, because high frequency
+ // consumes extra battery.
+ const bool expensiveRenderingExpected =
+ clientCompositionDisplay.outputDataspace == Dataspace::DISPLAY_P3;
+ if (expensiveRenderingExpected && displayId) {
+ mPowerAdvisor.setExpensiveRenderingExpected(*displayId, true);
+ }
+ if (!debugRegion.isEmpty()) {
+ Region::const_iterator it = debugRegion.begin();
+ Region::const_iterator end = debugRegion.end();
+ while (it != end) {
+ const Rect& rect = *it++;
+ renderengine::LayerSettings layerSettings;
+ layerSettings.source.buffer.buffer = nullptr;
+ layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
+ layerSettings.geometry.boundaries = rect.toFloatRect();
+ layerSettings.alpha = half(1.0);
+ clientCompositionLayers.push_back(layerSettings);
+ }
+ }
+ renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
+ buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
+ readyFence);
+ } else if (displayId) {
+ mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
}
-
- // disable scissor at the end of the frame
- getBE().mRenderEngine->disableScissor();
return true;
}
-void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const {
- const int32_t height = displayDevice->getHeight();
+void SurfaceFlinger::drawWormhole(const Region& region) const {
auto& engine(getRenderEngine());
- engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
+ engine.fillRegionWithColor(region, 0, 0, 0, 0);
}
-status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
- const sp<IBinder>& handle,
- const sp<IGraphicBufferProducer>& gbc,
- const sp<Layer>& lbc,
- const sp<Layer>& parent)
-{
+status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
+ const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
+ const sp<IBinder>& parentHandle,
+ const sp<Layer>& parentLayer, bool addToCurrentState) {
// add this layer to the current state list
{
Mutex::Autolock _l(mStateLock);
+ sp<Layer> parent;
+ if (parentHandle != nullptr) {
+ parent = fromHandle(parentHandle);
+ if (parent == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+ } else {
+ parent = parentLayer;
+ }
+
if (mNumLayers >= MAX_LAYERS) {
ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers,
MAX_LAYERS);
return NO_MEMORY;
}
- if (parent == nullptr) {
+
+ mLayersByLocalBinderToken.emplace(handle->localBinder(), lbc);
+
+ if (parent == nullptr && addToCurrentState) {
mCurrentState.layersSortedByZ.add(lbc);
+ } else if (parent == nullptr) {
+ lbc->onRemovedFromCurrentState();
+ } else if (parent->isRemovedFromCurrentState()) {
+ parent->addChild(lbc);
+ lbc->onRemovedFromCurrentState();
} else {
- if (parent->isPendingRemoval()) {
- ALOGE("addClientLayer called with a removed parent");
- return NAME_NOT_FOUND;
- }
parent->addChild(lbc);
}
@@ -3183,7 +3549,6 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
mMaxGraphicBufferProducerListSize, mNumLayers);
}
mLayersAdded = true;
- mNumLayers++;
}
// attach this layer to the client
@@ -3192,75 +3557,21 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) {
- Mutex::Autolock _l(mStateLock);
- return removeLayerLocked(mStateLock, layer, topLevelOnly);
-}
-
-status_t SurfaceFlinger::removeLayerLocked(const Mutex&, const sp<Layer>& layer,
- bool topLevelOnly) {
- if (layer->isPendingRemoval()) {
- return NO_ERROR;
- }
-
- const auto& p = layer->getParent();
- ssize_t index;
- if (p != nullptr) {
- if (topLevelOnly) {
- return NO_ERROR;
- }
-
- sp<Layer> ancestor = p;
- while (ancestor->getParent() != nullptr) {
- ancestor = ancestor->getParent();
- }
- if (mCurrentState.layersSortedByZ.indexOf(ancestor) < 0) {
- ALOGE("removeLayer called with a layer whose parent has been removed");
- return NAME_NOT_FOUND;
- }
-
- index = p->removeChild(layer);
- } else {
- index = mCurrentState.layersSortedByZ.remove(layer);
- }
-
- // As a matter of normal operation, the LayerCleaner will produce a second
- // attempt to remove the surface. The Layer will be kept alive in mDrawingState
- // so we will succeed in promoting it, but it's already been removed
- // from mCurrentState. As long as we can find it in mDrawingState we have no problem
- // otherwise something has gone wrong and we are leaking the layer.
- if (index < 0 && mDrawingState.layersSortedByZ.indexOf(layer) < 0) {
- ALOGE("Failed to find layer (%s) in layer parent (%s).",
- layer->getName().string(),
- (p != nullptr) ? p->getName().string() : "no-parent");
- return BAD_VALUE;
- } else if (index < 0) {
- return NO_ERROR;
- }
-
- layer->onRemovedFromCurrentState();
- mLayersPendingRemoval.add(layer);
- mLayersRemoved = true;
- mNumLayers -= 1 + layer->getChildrenCount();
- setTransactionFlags(eTransactionNeeded);
- return NO_ERROR;
-}
-
uint32_t SurfaceFlinger::peekTransactionFlags() {
- return android_atomic_release_load(&mTransactionFlags);
+ return mTransactionFlags;
}
uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
- return android_atomic_and(~flags, &mTransactionFlags) & flags;
+ return mTransactionFlags.fetch_and(~flags) & flags;
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
- return setTransactionFlags(flags, VSyncModulator::TransactionStart::NORMAL);
+ return setTransactionFlags(flags, Scheduler::TransactionStart::NORMAL);
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
- VSyncModulator::TransactionStart transactionStart) {
- uint32_t old = android_atomic_or(flags, &mTransactionFlags);
+ Scheduler::TransactionStart transactionStart) {
+ uint32_t old = mTransactionFlags.fetch_or(flags);
mVsyncModulator.setTransactionStart(transactionStart);
if ((old & flags)==0) { // wake the server up
signalTransaction();
@@ -3268,6 +3579,51 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
return old;
}
+bool SurfaceFlinger::flushTransactionQueues() {
+ // to prevent onHandleDestroyed from being called while the lock is held,
+ // we must keep a copy of the transactions (specifically the composer
+ // states) around outside the scope of the lock
+ std::vector<const TransactionState> transactions;
+ bool flushedATransaction = false;
+ {
+ Mutex::Autolock _l(mStateLock);
+
+ auto it = mTransactionQueues.begin();
+ while (it != mTransactionQueues.end()) {
+ auto& [applyToken, transactionQueue] = *it;
+
+ while (!transactionQueue.empty()) {
+ const auto& transaction = transactionQueue.front();
+ if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime,
+ transaction.states)) {
+ setTransactionFlags(eTransactionFlushNeeded);
+ break;
+ }
+ transactions.push_back(transaction);
+ applyTransactionState(transaction.states, transaction.displays, transaction.flags,
+ mPendingInputWindowCommands, transaction.desiredPresentTime,
+ transaction.buffer, transaction.callback,
+ transaction.postTime, transaction.privileged,
+ /*isMainThread*/ true);
+ transactionQueue.pop();
+ flushedATransaction = true;
+ }
+
+ if (transactionQueue.empty()) {
+ it = mTransactionQueues.erase(it);
+ mTransactionCV.broadcast();
+ } else {
+ it = std::next(it, 1);
+ }
+ }
+ }
+ return flushedATransaction;
+}
+
+bool SurfaceFlinger::transactionFlushNeeded() {
+ return !mTransactionQueues.empty();
+}
+
bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& states) {
for (const ComposerState& state : states) {
// Here we need to check that the interface we're given is indeed
@@ -3290,23 +3646,90 @@ bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>&
return false;
}
-void SurfaceFlinger::setTransactionState(
- const Vector<ComposerState>& states,
- const Vector<DisplayState>& displays,
- uint32_t flags)
-{
+bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ const Vector<ComposerState>& states) {
+ nsecs_t expectedPresentTime = mScheduler->expectedPresentTime();
+ // Do not present if the desiredPresentTime has not passed unless it is more than one second
+ // in the future. We ignore timestamps more than 1 second in the future for stability reasons.
+ if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime &&
+ desiredPresentTime < expectedPresentTime + s2ns(1)) {
+ return false;
+ }
+
+ for (const ComposerState& state : states) {
+ const layer_state_t& s = state.state;
+ if (!(s.what & layer_state_t::eAcquireFenceChanged)) {
+ continue;
+ }
+ if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& states,
+ const Vector<DisplayState>& displays, uint32_t flags,
+ const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime,
+ const client_cache_t& uncacheBuffer,
+ const std::vector<ListenerCallbacks>& listenerCallbacks) {
ATRACE_CALL();
+
+ const int64_t postTime = systemTime();
+
+ bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess();
+
Mutex::Autolock _l(mStateLock);
- uint32_t transactionFlags = 0;
if (containsAnyInvalidClientState(states)) {
return;
}
+ // If its TransactionQueue already has a pending TransactionState or if it is pending
+ auto itr = mTransactionQueues.find(applyToken);
+ // if this is an animation frame, wait until prior animation frame has
+ // been applied by SF
+ if (flags & eAnimation) {
+ while (itr != mTransactionQueues.end()) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ ALOGW_IF(err == TIMED_OUT,
+ "setTransactionState timed out "
+ "waiting for animation frame to apply");
+ break;
+ }
+ itr = mTransactionQueues.find(applyToken);
+ }
+ }
+ if (itr != mTransactionQueues.end() ||
+ !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
+ mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
+ uncacheBuffer, listenerCallbacks, postTime,
+ privileged);
+ setTransactionFlags(eTransactionFlushNeeded);
+ return;
+ }
+
+ applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
+ uncacheBuffer, listenerCallbacks, postTime, privileged);
+}
+
+void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states,
+ const Vector<DisplayState>& displays, uint32_t flags,
+ const InputWindowCommands& inputWindowCommands,
+ const int64_t desiredPresentTime,
+ const client_cache_t& uncacheBuffer,
+ const std::vector<ListenerCallbacks>& listenerCallbacks,
+ const int64_t postTime, bool privileged,
+ bool isMainThread) {
+ uint32_t transactionFlags = 0;
+
if (flags & eAnimation) {
// For window updates that are part of an animation we must wait for
// previous animation "frames" to be handled.
- while (mAnimTransactionPending) {
+ while (!isMainThread && mAnimTransactionPending) {
status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
if (CC_UNLIKELY(err != NO_ERROR)) {
// just in case something goes wrong in SF, return to the
@@ -3323,16 +3746,32 @@ void SurfaceFlinger::setTransactionState(
transactionFlags |= setDisplayStateLocked(display);
}
- for (const ComposerState& state : states) {
- transactionFlags |= setClientStateLocked(state);
+ // In case the client has sent a Transaction that should receive callbacks but without any
+ // SurfaceControls that should be included in the callback, send the listener and callbackIds
+ // to the callback thread so it can send an empty callback
+ if (!listenerCallbacks.empty()) {
+ mTransactionCompletedThread.run();
+ }
+ for (const auto& [listener, callbackIds] : listenerCallbacks) {
+ mTransactionCompletedThread.addCallback(listener, callbackIds);
}
- // Iterate through all layers again to determine if any need to be destroyed. Marking layers
- // as destroyed should only occur after setting all other states. This is to allow for a
- // child re-parent to happen before marking its original parent as destroyed (which would
- // then mark the child as destroyed).
+ uint32_t clientStateFlags = 0;
for (const ComposerState& state : states) {
- setDestroyStateLocked(state);
+ clientStateFlags |= setClientStateLocked(state, desiredPresentTime, listenerCallbacks,
+ postTime, privileged);
+ }
+
+ // If the state doesn't require a traversal and there are callbacks, send them now
+ if (!(clientStateFlags & eTraversalNeeded) && !listenerCallbacks.empty()) {
+ mTransactionCompletedThread.sendCallbacks();
+ }
+ transactionFlags |= clientStateFlags;
+
+ transactionFlags |= addInputWindowCommands(inputWindowCommands);
+
+ if (uncacheBuffer.isValid()) {
+ ClientCache::getInstance().erase(uncacheBuffer);
}
// If a synchronous transaction is explicitly requested without any changes, force a transaction
@@ -3344,15 +3783,21 @@ void SurfaceFlinger::setTransactionState(
transactionFlags = eTransactionNeeded;
}
+ // If we are on the main thread, we are about to preform a traversal. Clear the traversal bit
+ // so we don't have to wake up again next frame to preform an uneeded traversal.
+ if (isMainThread && (transactionFlags & eTraversalNeeded)) {
+ transactionFlags = transactionFlags & (~eTraversalNeeded);
+ mTraversalNeededMainThread = true;
+ }
+
if (transactionFlags) {
if (mInterceptor->isEnabled()) {
mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags);
}
// this triggers the transaction
- const auto start = (flags & eEarlyWakeup)
- ? VSyncModulator::TransactionStart::EARLY
- : VSyncModulator::TransactionStart::NORMAL;
+ const auto start = (flags & eEarlyWakeup) ? Scheduler::TransactionStart::EARLY
+ : Scheduler::TransactionStart::NORMAL;
setTransactionFlags(transactionFlags, start);
// if this is a synchronous transaction, wait for it to take effect
@@ -3363,82 +3808,91 @@ void SurfaceFlinger::setTransactionState(
if (flags & eAnimation) {
mAnimTransactionPending = true;
}
- while (mTransactionPending) {
+ if (mPendingInputWindowCommands.syncInputWindows) {
+ mPendingSyncInputWindows = true;
+ }
+
+ // applyTransactionState can be called by either the main SF thread or by
+ // another process through setTransactionState. While a given process may wish
+ // to wait on synchronous transactions, the main SF thread should never
+ // be blocked. Therefore, we only wait if isMainThread is false.
+ while (!isMainThread && (mTransactionPending || mPendingSyncInputWindows)) {
status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
if (CC_UNLIKELY(err != NO_ERROR)) {
// just in case something goes wrong in SF, return to the
// called after a few seconds.
ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
mTransactionPending = false;
+ mPendingSyncInputWindows = false;
break;
}
}
}
}
-uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
-{
- ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token);
- if (dpyIdx < 0)
- return 0;
+uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) {
+ const ssize_t index = mCurrentState.displays.indexOfKey(s.token);
+ if (index < 0) return 0;
uint32_t flags = 0;
- DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx));
- if (disp.isValid()) {
- const uint32_t what = s.what;
- if (what & DisplayState::eSurfaceChanged) {
- if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) {
- disp.surface = s.surface;
- flags |= eDisplayTransactionNeeded;
- }
+ DisplayDeviceState& state = mCurrentState.displays.editValueAt(index);
+
+ const uint32_t what = s.what;
+ if (what & DisplayState::eSurfaceChanged) {
+ if (IInterface::asBinder(state.surface) != IInterface::asBinder(s.surface)) {
+ state.surface = s.surface;
+ flags |= eDisplayTransactionNeeded;
}
- if (what & DisplayState::eLayerStackChanged) {
- if (disp.layerStack != s.layerStack) {
- disp.layerStack = s.layerStack;
- flags |= eDisplayTransactionNeeded;
- }
+ }
+ if (what & DisplayState::eLayerStackChanged) {
+ if (state.layerStack != s.layerStack) {
+ state.layerStack = s.layerStack;
+ flags |= eDisplayTransactionNeeded;
}
- if (what & DisplayState::eDisplayProjectionChanged) {
- if (disp.orientation != s.orientation) {
- disp.orientation = s.orientation;
- flags |= eDisplayTransactionNeeded;
- }
- if (disp.frame != s.frame) {
- disp.frame = s.frame;
- flags |= eDisplayTransactionNeeded;
- }
- if (disp.viewport != s.viewport) {
- disp.viewport = s.viewport;
- flags |= eDisplayTransactionNeeded;
- }
+ }
+ if (what & DisplayState::eDisplayProjectionChanged) {
+ if (state.orientation != s.orientation) {
+ state.orientation = s.orientation;
+ flags |= eDisplayTransactionNeeded;
}
- if (what & DisplayState::eDisplaySizeChanged) {
- if (disp.width != s.width) {
- disp.width = s.width;
- flags |= eDisplayTransactionNeeded;
- }
- if (disp.height != s.height) {
- disp.height = s.height;
- flags |= eDisplayTransactionNeeded;
- }
+ if (state.frame != s.frame) {
+ state.frame = s.frame;
+ flags |= eDisplayTransactionNeeded;
+ }
+ if (state.viewport != s.viewport) {
+ state.viewport = s.viewport;
+ flags |= eDisplayTransactionNeeded;
}
}
+ if (what & DisplayState::eDisplaySizeChanged) {
+ if (state.width != s.width) {
+ state.width = s.width;
+ flags |= eDisplayTransactionNeeded;
+ }
+ if (state.height != s.height) {
+ state.height = s.height;
+ flags |= eDisplayTransactionNeeded;
+ }
+ }
+
return flags;
}
-bool callingThreadHasUnscopedSurfaceFlingerAccess() {
+bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess() {
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
-
if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
- !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
+ !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
return false;
}
return true;
}
-uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState) {
+uint32_t SurfaceFlinger::setClientStateLocked(
+ const ComposerState& composerState, int64_t desiredPresentTime,
+ const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime,
+ bool privileged) {
const layer_state_t& s = composerState.state;
sp<Client> client(static_cast<Client*>(composerState.client.get()));
@@ -3447,20 +3901,15 @@ uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState
return 0;
}
- if (layer->isPendingRemoval()) {
- ALOGW("Attempting to set client state on removed layer: %s", layer->getName().string());
- return 0;
- }
-
uint32_t flags = 0;
- const uint32_t what = s.what;
+ const uint64_t what = s.what;
bool geometryAppliesWithResize =
what & layer_state_t::eGeometryAppliesWithResize;
// If we are deferring transaction, make sure to push the pending state, as otherwise the
// pending state will also be deferred.
- if (what & layer_state_t::eDeferTransaction) {
+ if (what & layer_state_t::eDeferTransaction_legacy) {
layer->pushPendingState();
}
@@ -3518,6 +3967,16 @@ uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState
if (layer->setColor(s.color))
flags |= eTraversalNeeded;
}
+ if (what & layer_state_t::eColorTransformChanged) {
+ if (layer->setColorTransform(s.colorTransform)) {
+ flags |= eTraversalNeeded;
+ }
+ }
+ if (what & layer_state_t::eBackgroundColorChanged) {
+ if (layer->setBackgroundColor(s.color, s.bgColorAlpha, s.bgColorDataspace)) {
+ flags |= eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eMatrixChanged) {
// TODO: b/109894387
//
@@ -3534,7 +3993,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState
// of cropped areas, we need to prevent non-root clients without permission ACCESS_SURFACE_FLINGER
// (a.k.a. everyone except WindowManager and tests) from setting non rectangle preserving
// transformations.
- if (layer->setMatrix(s.matrix, callingThreadHasUnscopedSurfaceFlingerAccess()))
+ if (layer->setMatrix(s.matrix, privileged))
flags |= eTraversalNeeded;
}
if (what & layer_state_t::eTransparentRegionChanged) {
@@ -3545,12 +4004,12 @@ uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState
if (layer->setFlags(s.flags, s.mask))
flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eCropChanged) {
- if (layer->setCrop(s.crop, !geometryAppliesWithResize))
+ if (what & layer_state_t::eCropChanged_legacy) {
+ if (layer->setCrop_legacy(s.crop_legacy, !geometryAppliesWithResize))
flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eFinalCropChanged) {
- if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
+ if (what & layer_state_t::eCornerRadiusChanged) {
+ if (layer->setCornerRadius(s.cornerRadius))
flags |= eTraversalNeeded;
}
if (what & layer_state_t::eLayerStackChanged) {
@@ -3572,15 +4031,15 @@ uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState
flags |= eTransactionNeeded|eTraversalNeeded|eDisplayLayerStackChanged;
}
}
- if (what & layer_state_t::eDeferTransaction) {
- if (s.barrierHandle != nullptr) {
- layer->deferTransactionUntil(s.barrierHandle, s.frameNumber);
- } else if (s.barrierGbp != nullptr) {
- const sp<IGraphicBufferProducer>& gbp = s.barrierGbp;
+ if (what & layer_state_t::eDeferTransaction_legacy) {
+ if (s.barrierHandle_legacy != nullptr) {
+ layer->deferTransactionUntil_legacy(s.barrierHandle_legacy, s.frameNumber_legacy);
+ } else if (s.barrierGbp_legacy != nullptr) {
+ const sp<IGraphicBufferProducer>& gbp = s.barrierGbp_legacy;
if (authenticateSurfaceTextureLocked(gbp)) {
const auto& otherLayer =
(static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
- layer->deferTransactionUntil(otherLayer, s.frameNumber);
+ layer->deferTransactionUntil_legacy(otherLayer, s.frameNumber_legacy);
} else {
ALOGE("Attempt to defer transaction to to an"
" unrecognized GraphicBufferProducer");
@@ -3611,63 +4070,159 @@ uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
+ if (what & layer_state_t::eTransformChanged) {
+ if (layer->setTransform(s.transform)) 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::eFrameChanged) {
+ if (layer->setFrame(s.frame)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eAcquireFenceChanged) {
+ if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eDataspaceChanged) {
+ if (layer->setDataspace(s.dataspace)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eHdrMetadataChanged) {
+ if (layer->setHdrMetadata(s.hdrMetadata)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eSurfaceDamageRegionChanged) {
+ if (layer->setSurfaceDamageRegion(s.surfaceDamageRegion)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eApiChanged) {
+ if (layer->setApi(s.api)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eSidebandStreamChanged) {
+ if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eInputInfoChanged) {
+ if (privileged) {
+ layer->setInputInfo(s.inputInfo);
+ flags |= eTraversalNeeded;
+ } else {
+ ALOGE("Attempt to update InputWindowInfo without permission ACCESS_SURFACE_FLINGER");
+ }
+ }
+ if (what & layer_state_t::eMetadataChanged) {
+ if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eColorSpaceAgnosticChanged) {
+ if (layer->setColorSpaceAgnostic(s.colorSpaceAgnostic)) {
+ flags |= eTraversalNeeded;
+ }
+ }
+ std::vector<sp<CallbackHandle>> callbackHandles;
+ if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!listenerCallbacks.empty())) {
+ for (const auto& [listener, callbackIds] : listenerCallbacks) {
+ callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
+ }
+ }
+ bool bufferChanged = what & layer_state_t::eBufferChanged;
+ bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
+ sp<GraphicBuffer> buffer;
+ if (bufferChanged && cacheIdChanged) {
+ ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
+ buffer = s.buffer;
+ } else if (cacheIdChanged) {
+ buffer = ClientCache::getInstance().get(s.cachedBuffer);
+ } else if (bufferChanged) {
+ buffer = s.buffer;
+ }
+ if (buffer) {
+ if (layer->setBuffer(buffer, postTime, desiredPresentTime, s.cachedBuffer)) {
+ flags |= eTraversalNeeded;
+ }
+ }
+ if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
+ // Do not put anything that updates layer state or modifies flags after
+ // setTransactionCompletedListener
return flags;
}
-void SurfaceFlinger::setDestroyStateLocked(const ComposerState& composerState) {
- const layer_state_t& state = composerState.state;
- sp<Client> client(static_cast<Client*>(composerState.client.get()));
-
- sp<Layer> layer(client->getLayerUser(state.surface));
- if (layer == nullptr) {
- return;
+uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
+ uint32_t flags = 0;
+ if (!inputWindowCommands.transferTouchFocusCommands.empty()) {
+ flags |= eTraversalNeeded;
}
- if (layer->isPendingRemoval()) {
- ALOGW("Attempting to destroy on removed layer: %s", layer->getName().string());
- return;
+ if (inputWindowCommands.syncInputWindows) {
+ flags |= eTraversalNeeded;
}
- if (state.what & layer_state_t::eDestroySurface) {
- removeLayerLocked(mStateLock, layer);
- }
+ mPendingInputWindowCommands.merge(inputWindowCommands);
+ return flags;
}
-status_t SurfaceFlinger::createLayer(
- const String8& name,
- const sp<Client>& client,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent)
-{
+status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
+ uint32_t h, PixelFormat format, uint32_t flags,
+ LayerMetadata metadata, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp,
+ const sp<IBinder>& parentHandle,
+ const sp<Layer>& parentLayer) {
if (int32_t(w|h) < 0) {
ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
int(w), int(h));
return BAD_VALUE;
}
+ ALOG_ASSERT(parentLayer == nullptr || parentHandle == nullptr,
+ "Expected only one of parentLayer or parentHandle to be non-null. "
+ "Programmer error?");
+
status_t result = NO_ERROR;
sp<Layer> layer;
String8 uniqueName = getUniqueLayerName(name);
+ bool primaryDisplayOnly = false;
+
+ // window type is WINDOW_TYPE_DONT_SCREENSHOT from SurfaceControl.java
+ // TODO b/64227542
+ if (metadata.has(METADATA_WINDOW_TYPE)) {
+ int32_t windowType = metadata.getInt32(METADATA_WINDOW_TYPE, 0);
+ if (windowType == 441731) {
+ metadata.setInt32(METADATA_WINDOW_TYPE, InputWindowInfo::TYPE_NAVIGATION_BAR_PANEL);
+ primaryDisplayOnly = true;
+ }
+ }
+
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
- case ISurfaceComposerClient::eFXSurfaceNormal:
- result = createBufferLayer(client,
- uniqueName, w, h, flags, format,
- handle, gbp, &layer);
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ result = createBufferQueueLayer(client, uniqueName, w, h, flags, std::move(metadata),
+ format, handle, gbp, &layer);
break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ result = createBufferStateLayer(client, uniqueName, w, h, flags, std::move(metadata),
+ handle, &layer);
+ break;
case ISurfaceComposerClient::eFXSurfaceColor:
- result = createColorLayer(client,
- uniqueName, w, h, flags,
- handle, &layer);
+ // check if buffer size is set for color layer.
+ if (w > 0 || h > 0) {
+ ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)",
+ int(w), int(h));
+ return BAD_VALUE;
+ }
+
+ result = createColorLayer(client, uniqueName, w, h, flags, std::move(metadata), handle,
+ &layer);
break;
case ISurfaceComposerClient::eFXSurfaceContainer:
- result = createContainerLayer(client,
- uniqueName, w, h, flags,
- handle, &layer);
+ // check if buffer size is set for container layer.
+ if (w > 0 || h > 0) {
+ ALOGE("createLayer() failed, w or h cannot be set for container layer (w=%d, h=%d)",
+ int(w), int(h));
+ return BAD_VALUE;
+ }
+ result = createContainerLayer(client, uniqueName, w, h, flags, std::move(metadata),
+ handle, &layer);
break;
default:
result = BAD_VALUE;
@@ -3678,16 +4233,13 @@ status_t SurfaceFlinger::createLayer(
return result;
}
- // window type is WINDOW_TYPE_DONT_SCREENSHOT from SurfaceControl.java
- // TODO b/64227542
- if (windowType == 441731) {
- windowType = 2024; // TYPE_NAVIGATION_BAR_PANEL
+ if (primaryDisplayOnly) {
layer->setPrimaryDisplayOnly();
}
- layer->setInfo(windowType, ownerUid);
-
- result = addClientLayer(client, *handle, *gbp, layer, *parent);
+ bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess();
+ result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer,
+ addToCurrentState);
if (result != NO_ERROR) {
return result;
}
@@ -3719,15 +4271,18 @@ String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
});
}
- ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
+ ALOGV_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(),
+ uniqueName.c_str());
return uniqueName;
}
-status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client,
- const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
- sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
-{
+status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags,
+ LayerMetadata metadata, PixelFormat& format,
+ sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp,
+ sp<Layer>* outLayer) {
// initialize the surfaces
switch (format) {
case PIXEL_FORMAT_TRANSPARENT:
@@ -3739,74 +4294,97 @@ status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client,
break;
}
- sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
- status_t err = layer->setBuffers(w, h, format, flags);
+ sp<BufferQueueLayer> layer = getFactory().createBufferQueueLayer(
+ LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata)));
+ status_t err = layer->setDefaultBufferProperties(w, h, format);
if (err == NO_ERROR) {
*handle = layer->getHandle();
*gbp = layer->getProducer();
*outLayer = layer;
}
- ALOGE_IF(err, "createBufferLayer() failed (%s)", strerror(-err));
+ ALOGE_IF(err, "createBufferQueueLayer() failed (%s)", strerror(-err));
return err;
}
-status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
- const String8& name, uint32_t w, uint32_t h, uint32_t flags,
- sp<IBinder>* handle, sp<Layer>* outLayer)
-{
- *outLayer = new ColorLayer(this, client, name, w, h, flags);
+status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags,
+ LayerMetadata metadata, sp<IBinder>* handle,
+ sp<Layer>* outLayer) {
+ sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(
+ LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata)));
+ *handle = layer->getHandle();
+ *outLayer = layer;
+
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::createColorLayer(const sp<Client>& client, const String8& name, uint32_t w,
+ uint32_t h, uint32_t flags, LayerMetadata metadata,
+ sp<IBinder>* handle, sp<Layer>* outLayer) {
+ *outLayer = getFactory().createColorLayer(
+ LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata)));
*handle = (*outLayer)->getHandle();
return NO_ERROR;
}
-status_t SurfaceFlinger::createContainerLayer(const sp<Client>& client,
- const String8& name, uint32_t w, uint32_t h, uint32_t flags,
- sp<IBinder>* handle, sp<Layer>* outLayer)
-{
- *outLayer = new ContainerLayer(this, client, name, w, h, flags);
+status_t SurfaceFlinger::createContainerLayer(const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags,
+ LayerMetadata metadata, sp<IBinder>* handle,
+ sp<Layer>* outLayer) {
+ *outLayer = getFactory().createContainerLayer(
+ LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata)));
*handle = (*outLayer)->getHandle();
return NO_ERROR;
}
-status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle)
-{
- // called by a client when it wants to remove a Layer
- status_t err = NO_ERROR;
- sp<Layer> l(client->getLayerUser(handle));
- if (l != nullptr) {
- mInterceptor->saveSurfaceDeletion(l);
- err = removeLayer(l);
- ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
- "error removing layer=%p (%s)", l.get(), strerror(-err));
- }
- return err;
+void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) {
+ mLayersPendingRemoval.add(layer);
+ mLayersRemoved = true;
+ setTransactionFlags(eTransactionNeeded);
}
-status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
+void SurfaceFlinger::onHandleDestroyed(sp<Layer>& layer)
{
- // called by ~LayerCleaner() when all references to the IBinder (handle)
- // are gone
- sp<Layer> l = layer.promote();
- if (l == nullptr) {
- // The layer has already been removed, carry on
- return NO_ERROR;
+ Mutex::Autolock lock(mStateLock);
+ // If a layer has a parent, we allow it to out-live it's handle
+ // with the idea that the parent holds a reference and will eventually
+ // be cleaned up. However no one cleans up the top-level so we do so
+ // here.
+ if (layer->getParent() == nullptr) {
+ mCurrentState.layersSortedByZ.remove(layer);
+ }
+ markLayerPendingRemovalLocked(layer);
+
+ auto it = mLayersByLocalBinderToken.begin();
+ while (it != mLayersByLocalBinderToken.end()) {
+ if (it->second == layer) {
+ it = mLayersByLocalBinderToken.erase(it);
+ } else {
+ it++;
+ }
}
- // If we have a parent, then we can continue to live as long as it does.
- return removeLayer(l, true);
+
+ layer.clear();
}
// ---------------------------------------------------------------------------
void SurfaceFlinger::onInitializeDisplays() {
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display) return;
+
+ const sp<IBinder> token = display->getDisplayToken().promote();
+ LOG_ALWAYS_FATAL_IF(token == nullptr);
+
// reset screen orientation and use primary layer stack
Vector<ComposerState> state;
Vector<DisplayState> displays;
DisplayState d;
d.what = DisplayState::eDisplayProjectionChanged |
DisplayState::eLayerStackChanged;
- d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
+ d.token = token;
d.layerStack = 0;
d.orientation = DisplayState::eOrientationDefault;
d.frame.makeInvalid();
@@ -3814,68 +4392,53 @@ void SurfaceFlinger::onInitializeDisplays() {
d.width = 0;
d.height = 0;
displays.add(d);
- setTransactionState(state, displays, 0);
- setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL,
- /*stateLockHeld*/ false);
+ setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, {});
+
+ setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
- const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
- const nsecs_t period = activeConfig->getVsyncPeriod();
- mAnimFrameTracker.setDisplayRefreshPeriod(period);
+ const nsecs_t vsyncPeriod = getVsyncPeriod();
+ mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
- setCompositorTimingSnapped(0, period, 0);
+ DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
+ setCompositorTimingSnapped(stats, 0);
}
void SurfaceFlinger::initializeDisplays() {
- class MessageScreenInitialized : public MessageBase {
- SurfaceFlinger* flinger;
- public:
- explicit MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
- virtual bool handler() {
- flinger->onInitializeDisplays();
- return true;
- }
- };
- sp<MessageBase> msg = new MessageScreenInitialized(this);
- postMessageAsync(msg); // we may be called from main thread, use async message
+ // Async since we may be called from the main thread.
+ postMessageAsync(
+ new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
}
-void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
- int mode, bool stateLockHeld) {
- ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
- this);
- int32_t type = hw->getDisplayType();
- int currentMode = hw->getPowerMode();
-
- if (mode == currentMode) {
+void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
+ if (display->isVirtual()) {
+ ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
return;
}
- hw->setPowerMode(mode);
- if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
- ALOGW("Trying to set power mode for virtual display");
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
+
+ ALOGD("Setting power mode %d on display %s", mode, to_string(*displayId).c_str());
+
+ int currentMode = display->getPowerMode();
+ if (mode == currentMode) {
return;
}
+ display->setPowerMode(mode);
+
if (mInterceptor->isEnabled()) {
- ConditionalLock lock(mStateLock, !stateLockHeld);
- ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken());
- if (idx < 0) {
- ALOGW("Surface Interceptor SavePowerMode: invalid display token");
- return;
- }
- mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode);
+ mInterceptor->savePowerModeUpdate(display->getSequenceId(), mode);
}
if (currentMode == HWC_POWER_MODE_OFF) {
// Turn on the display
- getHwComposer().setPowerMode(type, mode);
- if (type == DisplayDevice::DISPLAY_PRIMARY &&
- mode != HWC_POWER_MODE_DOZE_SUSPEND) {
- // FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenAcquired();
- resyncToHardwareVsync(true);
+ getHwComposer().setPowerMode(*displayId, mode);
+ if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
+ mScheduler->onScreenAcquired(mAppConnectionHandle);
+ mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
}
mVisibleRegionsDirty = true;
@@ -3894,75 +4457,61 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
ALOGW("Couldn't set SCHED_OTHER on display off");
}
- if (type == DisplayDevice::DISPLAY_PRIMARY &&
- currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
- disableHardwareVsync(true); // also cancels any in-progress resync
-
- // FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenReleased();
+ if (display->isPrimary() && currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
+ mScheduler->disableHardwareVsync(true);
+ mScheduler->onScreenReleased(mAppConnectionHandle);
}
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
mVisibleRegionsDirty = true;
// from this point on, SF will stop drawing on this display
} else if (mode == HWC_POWER_MODE_DOZE ||
mode == HWC_POWER_MODE_NORMAL) {
// Update display while dozing
- getHwComposer().setPowerMode(type, mode);
- if (type == DisplayDevice::DISPLAY_PRIMARY &&
- currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
- // FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenAcquired();
- resyncToHardwareVsync(true);
+ getHwComposer().setPowerMode(*displayId, mode);
+ if (display->isPrimary() && currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
+ mScheduler->onScreenAcquired(mAppConnectionHandle);
+ mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
}
} else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
// Leave display going to doze
- if (type == DisplayDevice::DISPLAY_PRIMARY) {
- disableHardwareVsync(true); // also cancels any in-progress resync
- // FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenReleased();
+ if (display->isPrimary()) {
+ mScheduler->disableHardwareVsync(true);
+ mScheduler->onScreenReleased(mAppConnectionHandle);
}
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
} else {
ALOGE("Attempting to set unknown power mode: %d\n", mode);
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
}
- ALOGD("Finished set power mode=%d, type=%d", mode, hw->getDisplayType());
+
+ if (display->isPrimary()) {
+ mTimeStats->setPowerMode(mode);
+ mRefreshRateStats.setPowerMode(mode);
+ }
+
+ ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str());
}
-void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
- class MessageSetPowerMode: public MessageBase {
- SurfaceFlinger& mFlinger;
- sp<IBinder> mDisplay;
- int mMode;
- public:
- MessageSetPowerMode(SurfaceFlinger& flinger,
- const sp<IBinder>& disp, int mode) : mFlinger(flinger),
- mDisplay(disp) { mMode = mode; }
- virtual bool handler() {
- sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
- if (hw == nullptr) {
- ALOGE("Attempt to set power mode = %d for null display %p",
- mMode, mDisplay.get());
- } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
- ALOGW("Attempt to set power mode = %d for virtual display",
- mMode);
- } else {
- mFlinger.setPowerModeInternal(
- hw, mMode, /*stateLockHeld*/ false);
- }
- return true;
+void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
+ postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
+ const auto display = getDisplayDevice(displayToken);
+ if (!display) {
+ ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
+ displayToken.get());
+ } else if (display->isVirtual()) {
+ ALOGW("Attempt to set power mode %d for virtual display", mode);
+ } else {
+ setPowerModeInternal(display, mode);
}
- };
- sp<MessageBase> msg = new MessageSetPowerMode(*this, display, mode);
- postMessageSync(msg);
+ }));
}
// ---------------------------------------------------------------------------
-status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto)
- NO_THREAD_SAFETY_ANALYSIS {
- String8 result;
+status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args,
+ bool asProto) NO_THREAD_SAFETY_ANALYSIS {
+ std::string result;
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
@@ -3970,8 +4519,8 @@ status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asPro
if ((uid != AID_SHELL) &&
!PermissionCache::checkPermission(sDump, pid, uid)) {
- result.appendFormat("Permission Denial: "
- "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+ StringAppendF(&result, "Permission Denial: can't dump SurfaceFlinger from pid=%d, uid=%d\n",
+ pid, uid);
} else {
// Try to get the main lock, but give up after one second
// (this would indicate SF is stuck, but we want to be able to
@@ -3979,105 +4528,43 @@ status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asPro
status_t err = mStateLock.timedLock(s2ns(1));
bool locked = (err == NO_ERROR);
if (!locked) {
- result.appendFormat(
- "SurfaceFlinger appears to be unresponsive (%s [%d]), "
- "dumping anyways (no locks held)\n", strerror(-err), err);
- }
-
- bool dumpAll = true;
- size_t index = 0;
- size_t numArgs = args.size();
-
- if (numArgs) {
- if ((index < numArgs) &&
- (args[index] == String16("--list"))) {
- index++;
- listLayersLocked(args, index, result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--latency"))) {
- index++;
- dumpStatsLocked(args, index, result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--latency-clear"))) {
- index++;
- clearStatsLocked(args, index, result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--dispsync"))) {
- index++;
- mPrimaryDispSync.dump(result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--static-screen"))) {
- index++;
- dumpStaticScreenStats(result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--frame-events"))) {
- index++;
- dumpFrameEventsLocked(result);
- dumpAll = false;
- }
-
- if ((index < numArgs) && (args[index] == String16("--wide-color"))) {
- index++;
- dumpWideColorInfo(result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--enable-layer-stats"))) {
- index++;
- mLayerStats.enable();
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--disable-layer-stats"))) {
- index++;
- mLayerStats.disable();
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--clear-layer-stats"))) {
- index++;
- mLayerStats.clear();
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--dump-layer-stats"))) {
- index++;
- mLayerStats.dump(result);
- dumpAll = false;
- }
+ StringAppendF(&result,
+ "SurfaceFlinger appears to be unresponsive (%s [%d]), dumping anyways "
+ "(no locks held)\n",
+ strerror(-err), err);
+ }
+
+ using namespace std::string_literals;
+
+ static const std::unordered_map<std::string, Dumper> dumpers = {
+ {"--clear-layer-stats"s, dumper([this](std::string&) { mLayerStats.clear(); })},
+ {"--disable-layer-stats"s, dumper([this](std::string&) { mLayerStats.disable(); })},
+ {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
+ {"--dispsync"s, dumper([this](std::string& s) {
+ mScheduler->dumpPrimaryDispSync(s);
+ })},
+ {"--dump-layer-stats"s, dumper([this](std::string& s) { mLayerStats.dump(s); })},
+ {"--enable-layer-stats"s, dumper([this](std::string&) { mLayerStats.enable(); })},
+ {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
+ {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
+ {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
+ {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)},
+ {"--static-screen"s, dumper(&SurfaceFlinger::dumpStaticScreenStats)},
+ {"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
+ {"--vsync"s, dumper(&SurfaceFlinger::dumpVSync)},
+ {"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
+ };
- if ((index < numArgs) && (args[index] == String16("--timestats"))) {
- index++;
- mTimeStats.parseArgs(asProto, args, index, result);
- dumpAll = false;
- }
- }
+ const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
- if (dumpAll) {
+ if (const auto it = dumpers.find(flag); it != dumpers.end()) {
+ (it->second)(args, asProto, result);
+ } else {
if (asProto) {
LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
} else {
- dumpAllLocked(args, index, result);
+ dumpAllLocked(args, result);
}
}
@@ -4085,53 +4572,41 @@ status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asPro
mStateLock.unlock();
}
}
- write(fd, result.string(), result.size());
+ write(fd, result.c_str(), result.size());
return NO_ERROR;
}
-void SurfaceFlinger::listLayersLocked(const Vector<String16>& /* args */,
- size_t& /* index */, String8& result) const
-{
- mCurrentState.traverseInZOrder([&](Layer* layer) {
- result.appendFormat("%s\n", layer->getName().string());
- });
+status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) {
+ if (asProto && mTracing.isEnabled()) {
+ mTracing.writeToFileAsync();
+ }
+
+ return doDump(fd, DumpArgs(), asProto);
}
-void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index,
- String8& result) const
-{
- String8 name;
- if (index < args.size()) {
- name = String8(args[index]);
- index++;
- }
+void SurfaceFlinger::listLayersLocked(std::string& result) const {
+ mCurrentState.traverseInZOrder(
+ [&](Layer* layer) { StringAppendF(&result, "%s\n", layer->getName().string()); });
+}
- const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
- const nsecs_t period = activeConfig->getVsyncPeriod();
- result.appendFormat("%" PRId64 "\n", period);
+void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) const {
+ StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriod());
- if (name.isEmpty()) {
- mAnimFrameTracker.dumpStats(result);
- } else {
+ if (args.size() > 1) {
+ const auto name = String8(args[1]);
mCurrentState.traverseInZOrder([&](Layer* layer) {
if (name == layer->getName()) {
layer->dumpFrameStats(result);
}
});
+ } else {
+ mAnimFrameTracker.dumpStats(result);
}
}
-void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index,
- String8& /* result */)
-{
- String8 name;
- if (index < args.size()) {
- name = String8(args[index]);
- index++;
- }
-
+void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) {
mCurrentState.traverseInZOrder([&](Layer* layer) {
- if (name.isEmpty() || (name == layer->getName())) {
+ if (args.size() < 2 || String8(args[1]) == layer->getName()) {
layer->clearFrameStats();
}
});
@@ -4139,6 +4614,10 @@ void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& inde
mAnimFrameTracker.clearStats();
}
+void SurfaceFlinger::dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const {
+ mTimeStats->parseArgs(asProto, args, result);
+}
+
// This should only be called from the main thread. Otherwise it would need
// the lock and should use mCurrentState rather than mDrawingState.
void SurfaceFlinger::logFrameStats() {
@@ -4149,37 +4628,46 @@ void SurfaceFlinger::logFrameStats() {
mAnimFrameTracker.logAndResetStats(String8("<win-anim>"));
}
-void SurfaceFlinger::appendSfConfigString(String8& result) const
-{
+void SurfaceFlinger::appendSfConfigString(std::string& result) const {
result.append(" [sf");
if (isLayerTripleBufferingDisabled())
result.append(" DISABLE_TRIPLE_BUFFERING");
- result.appendFormat(" PRESENT_TIME_OFFSET=%" PRId64 , dispSyncPresentTimeOffset);
- result.appendFormat(" FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
- result.appendFormat(" MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
- result.appendFormat(" RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
- result.appendFormat(" NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
- maxFrameBufferAcquiredBuffers);
+ StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset);
+ StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
+ StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
+ StringAppendF(&result, " RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
+ StringAppendF(&result, " NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
+ maxFrameBufferAcquiredBuffers);
result.append("]");
}
-void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
-{
- result.appendFormat("Static screen stats:\n");
+void SurfaceFlinger::dumpVSync(std::string& result) const {
+ mPhaseOffsets->dump(result);
+ StringAppendF(&result,
+ " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
+ dispSyncPresentTimeOffset, getVsyncPeriod());
+
+ StringAppendF(&result, "Scheduler enabled.");
+ StringAppendF(&result, "+ Smart 90 for video detection: %s\n\n",
+ mUseSmart90ForVideo ? "on" : "off");
+ mScheduler->dump(mAppConnectionHandle, result);
+}
+
+void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
+ result.append("Static screen stats:\n");
for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) {
float bucketTimeSec = getBE().mFrameBuckets[b] / 1e9;
float percent = 100.0f *
static_cast<float>(getBE().mFrameBuckets[b]) / getBE().mTotalTime;
- result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n",
- b + 1, bucketTimeSec, percent);
+ StringAppendF(&result, " < %zd frames: %.3f s (%.1f%%)\n", b + 1, bucketTimeSec, percent);
}
float bucketTimeSec = getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] / 1e9;
float percent = 100.0f *
static_cast<float>(getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1]) / getBE().mTotalTime;
- result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n",
- SurfaceFlingerBE::NUM_BUCKETS - 1, bucketTimeSec, percent);
+ StringAppendF(&result, " %zd+ frames: %.3f s (%.1f%%)\n", SurfaceFlingerBE::NUM_BUCKETS - 1,
+ bucketTimeSec, percent);
}
void SurfaceFlinger::recordBufferingStats(const char* layerName,
@@ -4200,8 +4688,8 @@ void SurfaceFlinger::recordBufferingStats(const char* layerName,
}
}
-void SurfaceFlinger::dumpFrameEventsLocked(String8& result) {
- result.appendFormat("Layer frame timestamps:\n");
+void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) {
+ result.append("Layer frame timestamps:\n");
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
const size_t count = currentLayers.size();
@@ -4210,7 +4698,7 @@ void SurfaceFlinger::dumpFrameEventsLocked(String8& result) {
}
}
-void SurfaceFlinger::dumpBufferingStats(String8& result) const {
+void SurfaceFlinger::dumpBufferingStats(std::string& result) const {
result.append("Buffering stats:\n");
result.append(" [Layer name] <Active time> <Two buffer> "
"<Double buffered> <Triple buffered>\n");
@@ -4236,93 +4724,132 @@ void SurfaceFlinger::dumpBufferingStats(String8& result) const {
for (const auto& sortedPair : sorted) {
float activeTime = sortedPair.first;
const BufferTuple& values = sortedPair.second;
- result.appendFormat(" [%s] %.2f %.3f %.3f %.3f\n",
- std::get<0>(values).c_str(), activeTime,
- std::get<1>(values), std::get<2>(values),
- std::get<3>(values));
+ StringAppendF(&result, " [%s] %.2f %.3f %.3f %.3f\n", std::get<0>(values).c_str(),
+ activeTime, std::get<1>(values), std::get<2>(values), std::get<3>(values));
}
result.append("\n");
}
-void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
- result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
- result.appendFormat("DisplayColorSetting: %s\n",
- decodeDisplayColorSetting(mDisplayColorSetting).c_str());
+void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
+ for (const auto& [token, display] : mDisplays) {
+ const auto displayId = display->getId();
+ if (!displayId) {
+ continue;
+ }
+ const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
+ if (!hwcDisplayId) {
+ continue;
+ }
+
+ StringAppendF(&result,
+ "Display %s (HWC display %" PRIu64 "): ", to_string(*displayId).c_str(),
+ *hwcDisplayId);
+ uint8_t port;
+ DisplayIdentificationData data;
+ if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
+ result.append("no identification data\n");
+ continue;
+ }
+
+ if (!isEdid(data)) {
+ result.append("unknown identification data: ");
+ for (uint8_t byte : data) {
+ StringAppendF(&result, "%x ", byte);
+ }
+ result.append("\n");
+ continue;
+ }
+
+ const auto edid = parseEdid(data);
+ if (!edid) {
+ result.append("invalid EDID: ");
+ for (uint8_t byte : data) {
+ StringAppendF(&result, "%x ", byte);
+ }
+ result.append("\n");
+ continue;
+ }
+
+ StringAppendF(&result, "port=%u pnpId=%s displayName=\"", port, edid->pnpId.data());
+ result.append(edid->displayName.data(), edid->displayName.length());
+ result.append("\"\n");
+ }
+}
+
+void SurfaceFlinger::dumpWideColorInfo(std::string& result) const {
+ StringAppendF(&result, "Device has wide color built-in display: %d\n", hasWideColorDisplay);
+ StringAppendF(&result, "Device uses color management: %d\n", useColorManagement);
+ StringAppendF(&result, "DisplayColorSetting: %s\n",
+ decodeDisplayColorSetting(mDisplayColorSetting).c_str());
// TODO: print out if wide-color mode is active or not
- for (size_t d = 0; d < mDisplays.size(); d++) {
- const sp<const DisplayDevice>& displayDevice(mDisplays[d]);
- int32_t hwcId = displayDevice->getHwcDisplayId();
- if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
+ for (const auto& [token, display] : mDisplays) {
+ const auto displayId = display->getId();
+ if (!displayId) {
continue;
}
- result.appendFormat("Display %d color modes:\n", hwcId);
- std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
+ StringAppendF(&result, "Display %s color modes:\n", to_string(*displayId).c_str());
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
for (auto&& mode : modes) {
- result.appendFormat(" %s (%d)\n", decodeColorMode(mode).c_str(), mode);
+ StringAppendF(&result, " %s (%d)\n", decodeColorMode(mode).c_str(), mode);
}
- ColorMode currentMode = displayDevice->getActiveColorMode();
- result.appendFormat(" Current color mode: %s (%d)\n",
- decodeColorMode(currentMode).c_str(), currentMode);
+ ColorMode currentMode = display->getCompositionDisplay()->getState().colorMode;
+ StringAppendF(&result, " Current color mode: %s (%d)\n",
+ decodeColorMode(currentMode).c_str(), currentMode);
}
result.append("\n");
}
-LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet) const {
+LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet,
+ uint32_t traceFlags) const {
LayersProto layersProto;
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
const State& state = useDrawing ? mDrawingState : mCurrentState;
state.traverseInZOrder([&](Layer* layer) {
LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProto(layerProto, stateSet);
+ layer->writeToProto(layerProto, stateSet, traceFlags);
});
return layersProto;
}
-LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) const {
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(
+ const sp<DisplayDevice>& displayDevice) const {
LayersProto layersProto;
- const sp<DisplayDevice>& displayDevice(mDisplays[hwcId]);
SizeProto* resolution = layersProto.mutable_resolution();
resolution->set_w(displayDevice->getWidth());
resolution->set_h(displayDevice->getHeight());
- layersProto.set_color_mode(decodeColorMode(displayDevice->getActiveColorMode()));
- layersProto.set_color_transform(decodeColorTransform(displayDevice->getColorTransform()));
- layersProto.set_global_transform(
- static_cast<int32_t>(displayDevice->getOrientationTransform()));
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
+ layersProto.set_color_mode(decodeColorMode(displayState.colorMode));
+ layersProto.set_color_transform(decodeColorTransform(displayState.colorTransform));
+ layersProto.set_global_transform(displayState.orientation);
+ const auto displayId = displayDevice->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(hwcId)) {
+ if (!layer->visibleRegion.isEmpty() && !display->getOutputLayersOrderedByZ().empty()) {
LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProto(layerProto, hwcId);
+ layer->writeToProto(layerProto, displayDevice);
}
});
return layersProto;
}
-void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
- String8& result) const
-{
- bool colorize = false;
- if (index < args.size()
- && (args[index] == String16("--color"))) {
- colorize = true;
- index++;
- }
-
+void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
+ const bool colorize = !args.empty() && args[0] == String16("--color");
Colorizer colorizer(colorize);
// figure out if we're stuck somewhere
const nsecs_t now = systemTime();
- const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
const nsecs_t inTransaction(mDebugInTransaction);
- nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
/*
@@ -4337,6 +4864,9 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
appendGuiConfigString(result);
result.append("\n");
+ result.append("\nDisplay identification data:\n");
+ dumpDisplayIdentificationData(result);
+
result.append("\nWide-Color information:\n");
dumpWideColorInfo(result);
@@ -4344,63 +4874,56 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
result.append("Sync configuration: ");
colorizer.reset(result);
result.append(SyncFeatures::getInstance().toString());
- result.append("\n");
-
- const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ result.append("\n\n");
colorizer.bold(result);
- result.append("DispSync configuration: ");
+ result.append("VSYNC configuration:\n");
colorizer.reset(result);
- const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
- const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
- result.appendFormat(
- "app phase %" PRId64 " ns, "
- "sf phase %" PRId64 " ns, "
- "early app phase %" PRId64 " ns, "
- "early sf phase %" PRId64 " ns, "
- "early app gl phase %" PRId64 " ns, "
- "early sf gl phase %" PRId64 " ns, "
- "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
- vsyncPhaseOffsetNs,
- sfVsyncPhaseOffsetNs,
- appEarlyOffset,
- sfEarlyOffset,
- appEarlyGlOffset,
- sfEarlyOffset,
- dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+ dumpVSync(result);
result.append("\n");
- // Dump static screen stats
- result.append("\n");
dumpStaticScreenStats(result);
result.append("\n");
+ StringAppendF(&result, "Total missed frame count: %u\n", mFrameMissedCount.load());
+ StringAppendF(&result, "HWC missed frame count: %u\n", mHwcFrameMissedCount.load());
+ StringAppendF(&result, "GPU missed frame count: %u\n\n", mGpuFrameMissedCount.load());
+
dumpBufferingStats(result);
/*
* Dump the visible layer list
*/
colorizer.bold(result);
- result.appendFormat("Visible layers (count = %zu)\n", mNumLayers);
- result.appendFormat("GraphicBufferProducers: %zu, max %zu\n",
- mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize);
+ StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers);
+ StringAppendF(&result, "GraphicBufferProducers: %zu, max %zu\n",
+ mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize);
colorizer.reset(result);
- LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
- auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
- result.append(LayerProtoParser::layersToString(std::move(layerTree)).c_str());
- result.append("\n");
+ {
+ LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
+ auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+ result.append(LayerProtoParser::layerTreeToString(layerTree));
+ result.append("\n");
+ }
+
+ {
+ StringAppendF(&result, "Composition layers\n");
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ auto compositionLayer = layer->getCompositionLayer();
+ if (compositionLayer) compositionLayer->dump(result);
+ });
+ }
/*
* Dump Display state
*/
colorizer.bold(result);
- result.appendFormat("Displays (%zu entries)\n", mDisplays.size());
+ StringAppendF(&result, "Displays (%zu entries)\n", mDisplays.size());
colorizer.reset(result);
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- const sp<const DisplayDevice>& hw(mDisplays[dpy]);
- hw->dump(result);
+ for (const auto& [token, display] : mDisplays) {
+ display->dump(result);
}
result.append("\n");
@@ -4412,44 +4935,31 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
result.append("SurfaceFlinger global state:\n");
colorizer.reset(result);
- HWComposer& hwc(getHwComposer());
- sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
-
- getBE().mRenderEngine->dump(result);
-
- if (hw) {
- hw->undefinedRegion.dump(result, "undefinedRegion");
- result.appendFormat(" orientation=%d, isDisplayOn=%d\n",
- hw->getOrientation(), hw->isDisplayOn());
- }
- result.appendFormat(
- " last eglSwapBuffers() time: %f us\n"
- " last transaction time : %f us\n"
- " transaction-flags : %08x\n"
- " refresh-rate : %f fps\n"
- " x-dpi : %f\n"
- " y-dpi : %f\n"
- " gpu_to_cpu_unsupported : %d\n"
- ,
- mLastSwapBufferTime/1000.0,
- mLastTransactionTime/1000.0,
- mTransactionFlags,
- 1e9 / activeConfig->getVsyncPeriod(),
- activeConfig->getDpiX(),
- activeConfig->getDpiY(),
- !mGpuToCpuSupported);
-
- result.appendFormat(" eglSwapBuffers time: %f us\n",
- inSwapBuffersDuration/1000.0);
-
- result.appendFormat(" transaction time: %f us\n",
- inTransactionDuration/1000.0);
+ getRenderEngine().dump(result);
- /*
- * VSYNC state
- */
- mEventThread->dump(result);
- result.append("\n");
+ if (const auto display = getDefaultDisplayDeviceLocked()) {
+ display->getCompositionDisplay()->getState().undefinedRegion.dump(result,
+ "undefinedRegion");
+ StringAppendF(&result, " orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
+ display->isPoweredOn());
+ }
+ StringAppendF(&result,
+ " transaction-flags : %08x\n"
+ " gpu_to_cpu_unsupported : %d\n",
+ mTransactionFlags.load(), !mGpuToCpuSupported);
+
+ if (const auto displayId = getInternalDisplayIdLocked();
+ displayId && getHwComposer().isConnected(*displayId)) {
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+ StringAppendF(&result,
+ " refresh-rate : %f fps\n"
+ " x-dpi : %f\n"
+ " y-dpi : %f\n",
+ 1e9 / activeConfig->getVsyncPeriod(), activeConfig->getDpiX(),
+ activeConfig->getDpiY());
+ }
+
+ StringAppendF(&result, " transaction time: %f us\n", inTransactionDuration / 1000.0);
/*
* Tracing state
@@ -4460,18 +4970,17 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
/*
* HWC layer minidump
*/
- for (size_t d = 0; d < mDisplays.size(); d++) {
- const sp<const DisplayDevice>& displayDevice(mDisplays[d]);
- int32_t hwcId = displayDevice->getHwcDisplayId();
- if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
+ for (const auto& [token, display] : mDisplays) {
+ const auto displayId = display->getId();
+ if (!displayId) {
continue;
}
- result.appendFormat("Display %d HWC layers:\n", hwcId);
+ StringAppendF(&result, "Display %s HWC layers:\n", to_string(*displayId).c_str());
Layer::miniDumpHeader(result);
- mCurrentState.traverseInZOrder([&](Layer* layer) {
- layer->miniDump(result, hwcId);
- });
+ const sp<DisplayDevice> displayDevice = display;
+ mCurrentState.traverseInZOrder(
+ [&](Layer* layer) { layer->miniDump(result, displayDevice); });
result.append("\n");
}
@@ -4482,9 +4991,8 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
result.append("h/w composer state:\n");
colorizer.reset(result);
bool hwcDisabled = mDebugDisableHWC || mDebugRegion;
- result.appendFormat(" h/w composer %s\n",
- hwcDisabled ? "disabled" : "enabled");
- hwc.dump(result);
+ StringAppendF(&result, " h/w composer %s\n", hwcDisabled ? "disabled" : "enabled");
+ getHwComposer().dump(result);
/*
* Dump gralloc state
@@ -4497,27 +5005,33 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
*/
if (mVrFlingerRequestsDisplay && mVrFlinger) {
result.append("VrFlinger state:\n");
- result.append(mVrFlinger->Dump().c_str());
+ result.append(mVrFlinger->Dump());
result.append("\n");
}
+
+ /**
+ * Scheduler dump state.
+ */
+ result.append("\nScheduler state:\n");
+ result.append(mScheduler->doDump() + "\n");
+ StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off");
+ result.append(mRefreshRateStats.doDump() + "\n");
+
+ result.append(mTimeStats->miniDump());
+ result.append("\n");
}
-const Vector< sp<Layer> >&
-SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) {
+const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
// Note: mStateLock is held here
- wp<IBinder> dpy;
- for (size_t i=0 ; i<mDisplays.size() ; i++) {
- if (mDisplays.valueAt(i)->getHwcDisplayId() == id) {
- dpy = mDisplays.keyAt(i);
- break;
+ for (const auto& [token, display] : mDisplays) {
+ if (display->getId() == displayId) {
+ return getDisplayDeviceLocked(token)->getVisibleLayersSortedByZ();
}
}
- if (dpy == nullptr) {
- ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id);
- // Just use the primary display so we have something to return
- dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY);
- }
- return getDisplayDeviceLocked(dpy)->getVisibleLayersSortedByZ();
+
+ ALOGE("%s: Invalid display %s", __FUNCTION__, to_string(displayId).c_str());
+ static const Vector<sp<Layer>> empty;
+ return empty;
}
void SurfaceFlinger::updateColorMatrixLocked() {
@@ -4545,68 +5059,125 @@ void SurfaceFlinger::updateColorMatrixLocked() {
}
status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
- switch (code) {
- case CREATE_CONNECTION:
- case CREATE_DISPLAY:
+#pragma clang diagnostic push
+#pragma clang diagnostic error "-Wswitch-enum"
+ switch (static_cast<ISurfaceComposerTag>(code)) {
+ // These methods should at minimum make sure that the client requested
+ // access to SF.
case BOOT_FINISHED:
case CLEAR_ANIMATION_FRAME_STATS:
+ case CREATE_DISPLAY:
+ case DESTROY_DISPLAY:
+ case ENABLE_VSYNC_INJECTIONS:
case GET_ANIMATION_FRAME_STATS:
- case SET_POWER_MODE:
case GET_HDR_CAPABILITIES:
- case ENABLE_VSYNC_INJECTIONS:
+ case SET_ACTIVE_CONFIG:
+ case SET_ALLOWED_DISPLAY_CONFIGS:
+ case GET_ALLOWED_DISPLAY_CONFIGS:
+ case SET_ACTIVE_COLOR_MODE:
case INJECT_VSYNC:
- {
- // codes that require permission check
+ case SET_POWER_MODE:
+ case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
+ case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
+ case GET_DISPLAYED_CONTENT_SAMPLE:
+ case NOTIFY_POWER_HINT: {
if (!callingThreadHasUnscopedSurfaceFlingerAccess()) {
IPCThreadState* ipc = IPCThreadState::self();
ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d",
ipc->getCallingPid(), ipc->getCallingUid());
return PERMISSION_DENIED;
}
- break;
+ return OK;
}
- /*
- * Calling setTransactionState is safe, because you need to have been
- * granted a reference to Client* and Handle* to do anything with it.
- *
- * Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
- */
+ case GET_LAYER_DEBUG_INFO: {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) {
+ ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ return OK;
+ }
+ // Used by apps to hook Choreographer to SurfaceFlinger.
+ case CREATE_DISPLAY_EVENT_CONNECTION:
+ // The following calls are currently used by clients that do not
+ // request necessary permissions. However, they do not expose any secret
+ // information, so it is OK to pass them.
+ case AUTHENTICATE_SURFACE:
+ case GET_ACTIVE_COLOR_MODE:
+ case GET_ACTIVE_CONFIG:
+ case GET_PHYSICAL_DISPLAY_IDS:
+ case GET_PHYSICAL_DISPLAY_TOKEN:
+ case GET_DISPLAY_COLOR_MODES:
+ case GET_DISPLAY_NATIVE_PRIMARIES:
+ case GET_DISPLAY_CONFIGS:
+ case GET_DISPLAY_STATS:
+ case GET_SUPPORTED_FRAME_TIMESTAMPS:
+ // 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:
- case CREATE_SCOPED_CONNECTION:
- {
+ case CREATE_CONNECTION:
+ case GET_COLOR_MANAGEMENT:
+ case GET_COMPOSITION_PREFERENCE:
+ case GET_PROTECTED_CONTENT_SUPPORT:
+ case IS_WIDE_COLOR_DISPLAY:
+ case GET_DISPLAY_BRIGHTNESS_SUPPORT:
+ case SET_DISPLAY_BRIGHTNESS: {
return OK;
}
+ case CAPTURE_LAYERS:
case CAPTURE_SCREEN:
- {
+ case ADD_REGION_SAMPLING_LISTENER:
+ case REMOVE_REGION_SAMPLING_LISTENER: {
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
if ((uid != AID_GRAPHICS) &&
- !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
+ !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
}
- break;
+ return OK;
}
- case CAPTURE_LAYERS: {
+ // The following codes are deprecated and should never be allowed to access SF.
+ case CONNECT_DISPLAY_UNUSED:
+ case CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED: {
+ ALOGE("Attempting to access SurfaceFlinger with unused code: %u", code);
+ return PERMISSION_DENIED;
+ }
+ case CAPTURE_SCREEN_BY_ID: {
IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
- if ((uid != AID_GRAPHICS) &&
- !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
- ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
+ if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) {
+ return OK;
}
- break;
+ return PERMISSION_DENIED;
}
}
- return OK;
+
+ // These codes are used for the IBinder protocol to either interrogate the recipient
+ // side of the transaction for its canonical interface descriptor or to dump its state.
+ // We let them pass by default.
+ if (code == IBinder::INTERFACE_TRANSACTION || code == IBinder::DUMP_TRANSACTION ||
+ code == IBinder::PING_TRANSACTION || code == IBinder::SHELL_COMMAND_TRANSACTION ||
+ code == IBinder::SYSPROPS_TRANSACTION) {
+ return OK;
+ }
+ // Numbers from 1000 to 1034 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 <= 1035) {
+ ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
+ return OK;
+ }
+ ALOGE("Permission Denial: SurfaceFlinger did not recognize request code: %u", code);
+ return PERMISSION_DENIED;
+#pragma clang diagnostic pop
}
-status_t SurfaceFlinger::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
+status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
status_t credentialCheck = CheckTransactCodeCredentials(code);
if (credentialCheck != OK) {
return credentialCheck;
@@ -4653,13 +5224,13 @@ status_t SurfaceFlinger::onTransact(
}
case 1008: // toggle use of hw composer
n = data.readInt32();
- mDebugDisableHWC = n ? 1 : 0;
+ mDebugDisableHWC = n != 0;
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
case 1009: // toggle use of transform hint
n = data.readInt32();
- mDebugDisableTransformHint = n ? 1 : 0;
+ mDebugDisableTransformHint = n != 0;
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
@@ -4671,8 +5242,12 @@ status_t SurfaceFlinger::onTransact(
reply->writeInt32(mDebugDisableHWC);
return NO_ERROR;
case 1013: {
- sp<const DisplayDevice> hw(getDefaultDisplayDevice());
- reply->writeInt32(hw->getPageFlipCount());
+ const auto display = getDefaultDisplayDevice();
+ if (!display) {
+ return NAME_NOT_FOUND;
+ }
+
+ reply->writeInt32(display->getPageFlipCount());
return NO_ERROR;
}
case 1014: {
@@ -4731,22 +5306,23 @@ status_t SurfaceFlinger::onTransact(
// Needs to be shifted to proper binder interface when we productize
case 1016: {
n = data.readInt32();
- mPrimaryDispSync.setRefreshSkipCount(n);
+ // TODO(b/113612090): Evaluate if this can be removed.
+ mScheduler->setRefreshSkipCount(n);
return NO_ERROR;
}
case 1017: {
n = data.readInt32();
- mForceFullDamage = static_cast<bool>(n);
+ mForceFullDamage = n != 0;
return NO_ERROR;
}
case 1018: { // Modify Choreographer's phase offset
n = data.readInt32();
- mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ mScheduler->setPhaseOffset(mAppConnectionHandle, static_cast<nsecs_t>(n));
return NO_ERROR;
}
case 1019: { // Modify SurfaceFlinger's phase offset
n = data.readInt32();
- mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ mScheduler->setPhaseOffset(mSfConnectionHandle, static_cast<nsecs_t>(n));
return NO_ERROR;
}
case 1020: { // Layer updates interceptor
@@ -4779,21 +5355,32 @@ status_t SurfaceFlinger::onTransact(
repaintEverything();
return NO_ERROR;
}
- case 1024: { // Is wide color gamut rendering/color management supported?
- reply->writeBool(hasWideColorDisplay);
- return NO_ERROR;
+ // Deprecate, use 1030 to check whether the device is color managed.
+ case 1024: {
+ return NAME_NOT_FOUND;
}
case 1025: { // Set layer tracing
n = data.readInt32();
if (n) {
ALOGD("LayerTracing enabled");
+ Mutex::Autolock lock(mStateLock);
+ mTracingEnabledChanged = true;
mTracing.enable();
- doTracing("tracing.enable");
reply->writeInt32(NO_ERROR);
} else {
ALOGD("LayerTracing disabled");
- status_t err = mTracing.disable();
- reply->writeInt32(err);
+ bool writeFile = false;
+ {
+ Mutex::Autolock lock(mStateLock);
+ mTracingEnabledChanged = true;
+ writeFile = mTracing.disable();
+ }
+
+ if (writeFile) {
+ reply->writeInt32(mTracing.writeToFile());
+ } else {
+ reply->writeInt32(NO_ERROR);
+ }
}
return NO_ERROR;
}
@@ -4803,38 +5390,138 @@ status_t SurfaceFlinger::onTransact(
}
// Is a DisplayColorSetting supported?
case 1027: {
- sp<const DisplayDevice> hw(getDefaultDisplayDevice());
- if (!hw) {
+ const auto display = getDefaultDisplayDevice();
+ if (!display) {
return NAME_NOT_FOUND;
}
DisplayColorSetting setting = static_cast<DisplayColorSetting>(data.readInt32());
switch (setting) {
case DisplayColorSetting::MANAGED:
- reply->writeBool(hasWideColorDisplay);
+ reply->writeBool(useColorManagement);
break;
case DisplayColorSetting::UNMANAGED:
reply->writeBool(true);
break;
case DisplayColorSetting::ENHANCED:
- reply->writeBool(hw->hasRenderIntent(RenderIntent::ENHANCE));
+ reply->writeBool(display->hasRenderIntent(RenderIntent::ENHANCE));
break;
default: // vendor display color setting
- reply->writeBool(hw->hasRenderIntent(static_cast<RenderIntent>(setting)));
+ reply->writeBool(
+ display->hasRenderIntent(static_cast<RenderIntent>(setting)));
break;
}
return NO_ERROR;
}
+ // Is VrFlinger active?
+ case 1028: {
+ Mutex::Autolock _l(mStateLock);
+ reply->writeBool(getHwComposer().isUsingVrComposer());
+ return NO_ERROR;
+ }
+ // Set buffer size for SF tracing (value in KB)
+ 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);
+ mTracing.setBufferSize(n * 1024);
+ reply->writeInt32(NO_ERROR);
+ return NO_ERROR;
+ }
+ // Is device color managed?
+ case 1030: {
+ reply->writeBool(useColorManagement);
+ return NO_ERROR;
+ }
+ // Override default composition data space
+ // adb shell service call SurfaceFlinger 1031 i32 1 DATASPACE_NUMBER DATASPACE_NUMBER \
+ // && adb shell stop zygote && adb shell start zygote
+ // to restore: adb shell service call SurfaceFlinger 1031 i32 0 && \
+ // adb shell stop zygote && adb shell start zygote
+ case 1031: {
+ Mutex::Autolock _l(mStateLock);
+ n = data.readInt32();
+ if (n) {
+ n = data.readInt32();
+ if (n) {
+ Dataspace dataspace = static_cast<Dataspace>(n);
+ if (!validateCompositionDataspace(dataspace)) {
+ return BAD_VALUE;
+ }
+ mDefaultCompositionDataspace = dataspace;
+ }
+ n = data.readInt32();
+ if (n) {
+ Dataspace dataspace = static_cast<Dataspace>(n);
+ if (!validateCompositionDataspace(dataspace)) {
+ return BAD_VALUE;
+ }
+ mWideColorGamutCompositionDataspace = dataspace;
+ }
+ } else {
+ // restore composition data space.
+ mDefaultCompositionDataspace = defaultCompositionDataspace;
+ mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace;
+ }
+ return NO_ERROR;
+ }
+ // Set trace flags
+ case 1033: {
+ n = data.readUint32();
+ ALOGD("Updating trace flags to 0x%x", n);
+ mTracing.setTraceFlags(n);
+ reply->writeInt32(NO_ERROR);
+ return NO_ERROR;
+ }
+ case 1034: {
+ // TODO(b/129297325): expose this via developer menu option
+ n = data.readInt32();
+ if (n && !mRefreshRateOverlay) {
+ RefreshRateType type;
+ {
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ type = mDesiredActiveConfig.type;
+ }
+ mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
+ mRefreshRateOverlay->changeRefreshRate(type);
+ } else if (!n) {
+ mRefreshRateOverlay.reset();
+ }
+ return NO_ERROR;
+ }
+ case 1035: {
+ n = data.readInt32();
+ mDebugDisplayConfigSetByBackdoor = false;
+ if (n >= 0) {
+ const auto displayToken = getInternalDisplayToken();
+ status_t result = setAllowedDisplayConfigs(displayToken, {n});
+ if (result != NO_ERROR) {
+ return result;
+ }
+ mDebugDisplayConfigSetByBackdoor = true;
+ }
+ return NO_ERROR;
+ }
}
}
return err;
}
void SurfaceFlinger::repaintEverything() {
- android_atomic_or(1, &mRepaintEverything);
+ mRepaintEverything = true;
signalTransaction();
}
+void SurfaceFlinger::repaintEverythingForHWC() {
+ mRepaintEverything = true;
+ mEventQueue->invalidate();
+}
+
// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
class WindowDisconnector {
public:
@@ -4848,66 +5535,141 @@ private:
const int mApi;
};
-status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
- bool& outCapturedSecureLayers, Rect sourceCrop,
- uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
- int32_t maxLayerZ, bool useIdentityTransform,
+status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken,
+ sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers,
+ const Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight,
+ bool useIdentityTransform,
ISurfaceComposer::Rotation rotation,
bool captureSecureLayers) {
ATRACE_CALL();
- if (CC_UNLIKELY(display == 0)) return BAD_VALUE;
+ if (!displayToken) return BAD_VALUE;
auto renderAreaRotation = fromSurfaceComposerRotation(rotation);
- sp<DisplayDevice> device;
+ sp<DisplayDevice> display;
{
Mutex::Autolock _l(mStateLock);
- device = getDisplayDeviceLocked(display);
- if (!device) return BAD_VALUE;
+ display = getDisplayDeviceLocked(displayToken);
+ if (!display) return BAD_VALUE;
// set the requested width/height to the logical display viewport size
// by default
if (reqWidth == 0 || reqHeight == 0) {
- reqWidth = uint32_t(device->getViewport().width());
- reqHeight = uint32_t(device->getViewport().height());
+ reqWidth = uint32_t(display->getViewport().width());
+ reqHeight = uint32_t(display->getViewport().height());
}
}
- DisplayRenderArea renderArea(device, sourceCrop, reqWidth, reqHeight, renderAreaRotation,
- captureSecureLayers);
+ DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace,
+ renderAreaRotation, captureSecureLayers);
- auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
- device, minLayerZ, maxLayerZ, std::placeholders::_1);
- return captureScreenCommon(renderArea, traverseLayers, outBuffer, useIdentityTransform,
- outCapturedSecureLayers);
+ auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
+ std::placeholders::_1);
+ return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat,
+ useIdentityTransform, outCapturedSecureLayers);
}
-status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
- sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
- float frameScale, bool childrenOnly) {
+static Dataspace pickDataspaceFromColorMode(const ColorMode colorMode) {
+ switch (colorMode) {
+ case ColorMode::DISPLAY_P3:
+ case ColorMode::BT2100_PQ:
+ case ColorMode::BT2100_HLG:
+ case ColorMode::DISPLAY_BT2020:
+ return Dataspace::DISPLAY_P3;
+ default:
+ return Dataspace::V0_SRGB;
+ }
+}
+
+const sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) {
+ const sp<IBinder> displayToken = getPhysicalDisplayTokenLocked(DisplayId{displayOrLayerStack});
+ if (displayToken) {
+ return getDisplayDeviceLocked(displayToken);
+ }
+ // Couldn't find display by displayId. Try to get display by layerStack since virtual displays
+ // may not have a displayId.
+ for (const auto& [token, display] : mDisplays) {
+ if (display->getLayerStack() == displayOrLayerStack) {
+ return display;
+ }
+ }
+ return nullptr;
+}
+
+status_t SurfaceFlinger::captureScreen(uint64_t displayOrLayerStack, Dataspace* outDataspace,
+ sp<GraphicBuffer>* outBuffer) {
+ sp<DisplayDevice> display;
+ uint32_t width;
+ uint32_t height;
+ ui::Transform::orientation_flags captureOrientation;
+ {
+ Mutex::Autolock _l(mStateLock);
+ display = getDisplayByIdOrLayerStack(displayOrLayerStack);
+ if (!display) {
+ return BAD_VALUE;
+ }
+
+ width = uint32_t(display->getViewport().width());
+ height = uint32_t(display->getViewport().height());
+
+ captureOrientation = fromSurfaceComposerRotation(
+ static_cast<ISurfaceComposer::Rotation>(display->getOrientation()));
+ if (captureOrientation == ui::Transform::orientation_flags::ROT_90) {
+ captureOrientation = ui::Transform::orientation_flags::ROT_270;
+ } else if (captureOrientation == ui::Transform::orientation_flags::ROT_270) {
+ captureOrientation = ui::Transform::orientation_flags::ROT_90;
+ }
+ *outDataspace =
+ pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode);
+ }
+
+ DisplayRenderArea renderArea(display, Rect(), width, height, *outDataspace, captureOrientation,
+ false /* captureSecureLayers */);
+
+ auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
+ std::placeholders::_1);
+ bool ignored = false;
+ return captureScreenCommon(renderArea, traverseLayers, outBuffer, ui::PixelFormat::RGBA_8888,
+ false /* useIdentityTransform */,
+ ignored /* outCapturedSecureLayers */);
+}
+
+status_t SurfaceFlinger::captureLayers(
+ const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
+ const Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
+ const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& excludeHandles,
+ float frameScale, bool childrenOnly) {
ATRACE_CALL();
class LayerRenderArea : public RenderArea {
public:
LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
- int32_t reqWidth, int32_t reqHeight, bool childrenOnly)
- : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR),
+ int32_t reqWidth, int32_t reqHeight, Dataspace reqDataSpace,
+ bool childrenOnly)
+ : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR, reqDataSpace),
mLayer(layer),
mCrop(crop),
mNeedsFiltering(false),
mFlinger(flinger),
mChildrenOnly(childrenOnly) {}
- const Transform& getTransform() const override { return mTransform; }
+ const ui::Transform& getTransform() const override { return mTransform; }
Rect getBounds() const override {
const Layer::State& layerState(mLayer->getDrawingState());
- return Rect(layerState.active.w, layerState.active.h);
+ return mLayer->getBufferSize(layerState);
+ }
+ int getHeight() const override {
+ return mLayer->getBufferSize(mLayer->getDrawingState()).getHeight();
+ }
+ int getWidth() const override {
+ return mLayer->getBufferSize(mLayer->getDrawingState()).getWidth();
}
- int getHeight() const override { return mLayer->getDrawingState().active.h; }
- int getWidth() const override { return mLayer->getDrawingState().active.w; }
bool isSecure() const override { return false; }
bool needsFiltering() const override { return mNeedsFiltering; }
+ const sp<const DisplayDevice> getDisplayDevice() const override { return nullptr; }
Rect getSourceCrop() const override {
if (mCrop.isEmpty()) {
return getBounds();
@@ -4920,8 +5682,11 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
const sp<Layer>& oldParent;
const sp<Layer>& newParent;
- ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent)
+ ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent,
+ const Rect& drawingBounds)
: oldParent(oldParent), newParent(newParent) {
+ // Compute and cache the bounds for the new parent layer.
+ newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform());
oldParent->setChildrenDrawingParent(newParent);
}
~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
@@ -4938,11 +5703,12 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
drawLayers();
} else {
Rect bounds = getBounds();
- screenshotParentLayer =
- new ContainerLayer(mFlinger, nullptr, String8("Screenshot Parent"),
- bounds.getWidth(), bounds.getHeight(), 0);
+ screenshotParentLayer = mFlinger->getFactory().createContainerLayer(
+ LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
+ bounds.getWidth(), bounds.getHeight(), 0,
+ LayerMetadata()));
- ReparentForDrawing reparent(mLayer, screenshotParentLayer);
+ ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
drawLayers();
}
}
@@ -4954,41 +5720,57 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
// In the "childrenOnly" case we reparent the children to a screenshot
// layer which has no properties set and which does not draw.
sp<ContainerLayer> screenshotParentLayer;
- Transform mTransform;
+ ui::Transform mTransform;
bool mNeedsFiltering;
SurfaceFlinger* mFlinger;
const bool mChildrenOnly;
};
- auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
- auto parent = layerHandle->owner.promote();
+ int reqWidth = 0;
+ int reqHeight = 0;
+ sp<Layer> parent;
+ Rect crop(sourceCrop);
+ std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers;
- if (parent == nullptr || parent->isPendingRemoval()) {
- ALOGE("captureLayers called with a removed parent");
- return NAME_NOT_FOUND;
- }
+ {
+ Mutex::Autolock _l(mStateLock);
- const int uid = IPCThreadState::self()->getCallingUid();
- const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
- if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
- ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
- return PERMISSION_DENIED;
- }
+ parent = fromHandle(layerHandleBinder);
+ if (parent == nullptr || parent->isRemovedFromCurrentState()) {
+ ALOGE("captureLayers called with an invalid or removed parent");
+ return NAME_NOT_FOUND;
+ }
- Rect crop(sourceCrop);
- if (sourceCrop.width() <= 0) {
- crop.left = 0;
- crop.right = parent->getCurrentState().active.w;
- }
+ const int uid = IPCThreadState::self()->getCallingUid();
+ const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
+ if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
+ ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
+ return PERMISSION_DENIED;
+ }
- if (sourceCrop.height() <= 0) {
- crop.top = 0;
- crop.bottom = parent->getCurrentState().active.h;
- }
+ if (sourceCrop.width() <= 0) {
+ crop.left = 0;
+ crop.right = parent->getBufferSize(parent->getCurrentState()).getWidth();
+ }
+
+ if (sourceCrop.height() <= 0) {
+ crop.top = 0;
+ crop.bottom = parent->getBufferSize(parent->getCurrentState()).getHeight();
+ }
+ reqWidth = crop.width() * frameScale;
+ reqHeight = crop.height() * frameScale;
- int32_t reqWidth = crop.width() * frameScale;
- int32_t reqHeight = crop.height() * frameScale;
+ for (const auto& handle : excludeHandles) {
+ sp<Layer> excludeLayer = fromHandle(handle);
+ if (excludeLayer != nullptr) {
+ excludeLayers.emplace(excludeLayer);
+ } else {
+ ALOGW("Invalid layer handle passed as excludeLayer to captureLayers");
+ return NAME_NOT_FOUND;
+ }
+ }
+ } // mStateLock
// really small crop or frameScale
if (reqWidth <= 0) {
@@ -4998,35 +5780,58 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
reqHeight = 1;
}
- LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, childrenOnly);
-
- auto traverseLayers = [parent, childrenOnly](const LayerVector::Visitor& visitor) {
+ LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, reqDataspace, childrenOnly);
+ auto traverseLayers = [parent, childrenOnly,
+ &excludeLayers](const LayerVector::Visitor& visitor) {
parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
if (!layer->isVisible()) {
return;
} else if (childrenOnly && layer == parent.get()) {
return;
}
+
+ sp<Layer> p = layer;
+ while (p != nullptr) {
+ if (excludeLayers.count(p) != 0) {
+ return;
+ }
+ p = p->getParent();
+ }
+
visitor(layer);
});
};
+
bool outCapturedSecureLayers = false;
- return captureScreenCommon(renderArea, traverseLayers, outBuffer, false,
+ return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false,
outCapturedSecureLayers);
}
status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
sp<GraphicBuffer>* outBuffer,
+ const ui::PixelFormat reqPixelFormat,
bool useIdentityTransform,
bool& outCapturedSecureLayers) {
ATRACE_CALL();
+ // TODO(b/116112787) Make buffer usage a parameter.
const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
- *outBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
- HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
+ *outBuffer =
+ getFactory().createGraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
+ static_cast<android_pixel_format>(reqPixelFormat), 1,
+ usage, "screenshot");
+ return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform,
+ outCapturedSecureLayers);
+}
+
+status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers,
+ const sp<GraphicBuffer>& buffer,
+ bool useIdentityTransform,
+ bool& outCapturedSecureLayers) {
// This mutex protects syncFd and captureResult for communication of the return values from the
// main thread back to this Binder thread
std::mutex captureMutex;
@@ -5038,7 +5843,7 @@ status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
const int uid = IPCThreadState::self()->getCallingUid();
const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
- sp<LambdaMessage> message = new LambdaMessage([&]() {
+ sp<LambdaMessage> message = new LambdaMessage([&] {
// If there is a refresh pending, bug out early and tell the binder thread to try again
// after the refresh.
if (mRefreshPending) {
@@ -5053,8 +5858,8 @@ status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
int fd = -1;
{
Mutex::Autolock _l(mStateLock);
- renderArea.render([&]() {
- result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
+ renderArea.render([&] {
+ result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
useIdentityTransform, forSystem, &fd,
outCapturedSecureLayers);
});
@@ -5070,14 +5875,14 @@ status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
status_t result = postMessageAsync(message);
if (result == NO_ERROR) {
- captureCondition.wait(captureLock, [&]() { return captureResult; });
+ captureCondition.wait(captureLock, [&] { return captureResult; });
while (*captureResult == EAGAIN) {
captureResult.reset();
result = postMessageAsync(message);
if (result != NO_ERROR) {
return result;
}
- captureCondition.wait(captureLock, [&]() { return captureResult; });
+ captureCondition.wait(captureLock, [&] { return captureResult; });
}
result = *captureResult;
}
@@ -5091,39 +5896,106 @@ status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
}
void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
- TraverseLayersFunction traverseLayers, bool yswap,
- bool useIdentityTransform) {
+ TraverseLayersFunction traverseLayers,
+ ANativeWindowBuffer* buffer, bool useIdentityTransform,
+ int* outSyncFd) {
ATRACE_CALL();
- auto& engine(getRenderEngine());
-
- // get screen geometry
- const auto raHeight = renderArea.getHeight();
-
const auto reqWidth = renderArea.getReqWidth();
const auto reqHeight = renderArea.getReqHeight();
- const auto sourceCrop = renderArea.getSourceCrop();
const auto rotation = renderArea.getRotationFlags();
+ const auto transform = renderArea.getTransform();
+ const auto sourceCrop = renderArea.getSourceCrop();
- // assume ColorMode::SRGB / RenderIntent::COLORIMETRIC
- engine.setOutputDataSpace(Dataspace::SRGB);
- engine.setDisplayMaxLuminance(DisplayDevice::sDefaultMaxLumiance);
-
- // make sure to clear all GL error flags
- engine.checkErrors();
+ renderengine::DisplaySettings clientCompositionDisplay;
+ std::vector<renderengine::LayerSettings> clientCompositionLayers;
+
+ // assume that bounds are never offset, and that they are the same as the
+ // buffer bounds.
+ clientCompositionDisplay.physicalDisplay = Rect(reqWidth, reqHeight);
+ clientCompositionDisplay.clip = sourceCrop;
+ clientCompositionDisplay.globalTransform = transform.asMatrix4();
+
+ // Now take into account the rotation flag. We append a transform that
+ // rotates the layer stack about the origin, then translate by buffer
+ // boundaries to be in the right quadrant.
+ mat4 rotMatrix;
+ int displacementX = 0;
+ int displacementY = 0;
+ float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
+ switch (rotation) {
+ case ui::Transform::ROT_90:
+ rotMatrix = mat4::rotate(rot90InRadians, vec3(0, 0, 1));
+ displacementX = renderArea.getBounds().getHeight();
+ break;
+ case ui::Transform::ROT_180:
+ rotMatrix = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1));
+ displacementY = renderArea.getBounds().getWidth();
+ displacementX = renderArea.getBounds().getHeight();
+ break;
+ case ui::Transform::ROT_270:
+ rotMatrix = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1));
+ displacementY = renderArea.getBounds().getWidth();
+ break;
+ default:
+ break;
+ }
- // set-up our viewport
- engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, raHeight, yswap,
- rotation);
- engine.disableTexturing();
+ // We need to transform the clipping window into the right spot.
+ // First, rotate the clipping rectangle by the rotation hint to get the
+ // right orientation
+ const vec4 clipTL = vec4(sourceCrop.left, sourceCrop.top, 0, 1);
+ const vec4 clipBR = vec4(sourceCrop.right, sourceCrop.bottom, 0, 1);
+ const vec4 rotClipTL = rotMatrix * clipTL;
+ const vec4 rotClipBR = rotMatrix * clipBR;
+ const int newClipLeft = std::min(rotClipTL[0], rotClipBR[0]);
+ const int newClipTop = std::min(rotClipTL[1], rotClipBR[1]);
+ const int newClipRight = std::max(rotClipTL[0], rotClipBR[0]);
+ const int newClipBottom = std::max(rotClipTL[1], rotClipBR[1]);
+
+ // Now reposition the clipping rectangle with the displacement vector
+ // computed above.
+ const mat4 displacementMat = mat4::translate(vec4(displacementX, displacementY, 0, 1));
+ clientCompositionDisplay.clip =
+ Rect(newClipLeft + displacementX, newClipTop + displacementY,
+ newClipRight + displacementX, newClipBottom + displacementY);
+
+ mat4 clipTransform = displacementMat * rotMatrix;
+ clientCompositionDisplay.globalTransform =
+ clipTransform * clientCompositionDisplay.globalTransform;
+
+ clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace();
+ clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance;
const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
- // redraw the screen entirely...
- engine.clearWithColor(0, 0, 0, alpha);
+ renderengine::LayerSettings fillLayer;
+ fillLayer.source.buffer.buffer = nullptr;
+ fillLayer.source.solidColor = half3(0.0, 0.0, 0.0);
+ fillLayer.geometry.boundaries = FloatRect(0.0, 0.0, 1.0, 1.0);
+ fillLayer.alpha = half(alpha);
+ clientCompositionLayers.push_back(fillLayer);
+
+ Region clearRegion = Region::INVALID_REGION;
traverseLayers([&](Layer* layer) {
- layer->draw(renderArea, useIdentityTransform);
+ renderengine::LayerSettings layerSettings;
+ bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
+ false, layerSettings);
+ if (prepared) {
+ clientCompositionLayers.push_back(layerSettings);
+ }
});
+
+ clientCompositionDisplay.clearRegion = clearRegion;
+ // Use an empty fence for the buffer fence, since we just created the buffer so
+ // there is no need for synchronization with the GPU.
+ base::unique_fd bufferFence;
+ base::unique_fd drawFence;
+ getRenderEngine().useProtectedContext(false);
+ getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
+ /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
+
+ *outSyncFd = drawFence.release();
}
status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
@@ -5145,64 +6017,15 @@ status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
ALOGW("FB is protected: PERMISSION_DENIED");
return PERMISSION_DENIED;
}
-
- // this binds the given EGLImage as a framebuffer for the
- // duration of this scope.
- RE::BindNativeBufferAsFramebuffer bufferBond(getRenderEngine(), buffer);
- if (bufferBond.getStatus() != NO_ERROR) {
- ALOGE("got ANWB binding error while taking screenshot");
- return INVALID_OPERATION;
- }
-
- // this will in fact render into our dequeued buffer
- // via an FBO, which means we didn't have to create
- // an EGLSurface and therefore we're not
- // dependent on the context's EGLConfig.
- renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform);
-
- if (DEBUG_SCREENSHOTS) {
- getRenderEngine().finish();
- *outSyncFd = -1;
-
- const auto reqWidth = renderArea.getReqWidth();
- const auto reqHeight = renderArea.getReqHeight();
-
- uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
- getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
- checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, traverseLayers);
- delete [] pixels;
- } else {
- base::unique_fd syncFd = getRenderEngine().flush();
- if (syncFd < 0) {
- getRenderEngine().finish();
- }
- *outSyncFd = syncFd.release();
- }
-
+ renderScreenImplLocked(renderArea, traverseLayers, buffer, useIdentityTransform, outSyncFd);
return NO_ERROR;
}
-void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
- TraverseLayersFunction traverseLayers) {
- if (DEBUG_SCREENSHOTS) {
- for (size_t y = 0; y < h; y++) {
- uint32_t const* p = (uint32_t const*)vaddr + y * s;
- for (size_t x = 0; x < w; x++) {
- if (p[x] != 0xFF000000) return;
- }
- }
- ALOGE("*** we just took a black screenshot ***");
+void SurfaceFlinger::setInputWindowsFinished() {
+ Mutex::Autolock _l(mStateLock);
- size_t i = 0;
- traverseLayers([&](Layer* layer) {
- const Layer::State& state(layer->getDrawingState());
- ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
- layer->isVisible() ? '+' : '-', i, layer->getName().string(),
- layer->getLayerStack(), state.z, layer->isVisible(), state.flags,
- static_cast<float>(state.color.a));
- i++;
- });
- }
+ mPendingSyncInputWindows = false;
+ mTransactionCV.broadcast();
}
// ---------------------------------------------------------------------------
@@ -5215,22 +6038,17 @@ void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor&
layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
}
-void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw, int32_t minLayerZ,
- int32_t maxLayerZ,
+void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& display,
const LayerVector::Visitor& visitor) {
// We loop through the first level of layers without traversing,
- // as we need to interpret min/max layer Z in the top level Z space.
+ // as we need to determine which layers belong to the requested display.
for (const auto& layer : mDrawingState.layersSortedByZ) {
- if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+ if (!layer->belongsToDisplay(display->getLayerStack(), false)) {
continue;
}
- const Layer::State& state(layer->getDrawingState());
// relative layers are traversed in Layer::traverseInZOrder
- if (state.zOrderRelativeOf != nullptr || state.z < minLayerZ || state.z > maxLayerZ) {
- continue;
- }
layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+ if (!layer->belongsToDisplay(display->getLayerStack(), false)) {
return;
}
if (!layer->isVisible()) {
@@ -5241,8 +6059,94 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw,
}
}
-}; // namespace android
+void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
+ const std::vector<int32_t>& allowedConfigs) {
+ if (!display->isPrimary()) {
+ return;
+ }
+
+ ALOGV("Updating allowed configs");
+ mAllowedDisplayConfigs = DisplayConfigs(allowedConfigs.begin(), allowedConfigs.end());
+
+ // Set the highest allowed config by iterating backwards on available refresh rates
+ const auto& refreshRates = mRefreshRateConfigs.getRefreshRates();
+ for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
+ if (iter->second && isDisplayConfigAllowed(iter->second->configId)) {
+ ALOGV("switching to config %d", iter->second->configId);
+ setDesiredActiveConfig(
+ {iter->first, iter->second->configId, Scheduler::ConfigEvent::Changed});
+ break;
+ }
+ }
+}
+
+status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+ const std::vector<int32_t>& allowedConfigs) {
+ ATRACE_CALL();
+
+ if (!displayToken || allowedConfigs.empty()) {
+ return BAD_VALUE;
+ }
+
+ if (mDebugDisplayConfigSetByBackdoor) {
+ // ignore this request as config is overridden by backdoor
+ return NO_ERROR;
+ }
+
+ postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ ALOGE("Attempt to set allowed display configs for invalid display token %p",
+ displayToken.get());
+ } else if (display->isVirtual()) {
+ ALOGW("Attempt to set allowed display configs for virtual display");
+ } else {
+ setAllowedDisplayConfigsInternal(display, allowedConfigs);
+ }
+ }));
+
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+ std::vector<int32_t>* outAllowedConfigs) {
+ ATRACE_CALL();
+
+ if (!displayToken || !outAllowedConfigs) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mStateLock);
+
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ return NAME_NOT_FOUND;
+ }
+
+ if (display->isPrimary()) {
+ outAllowedConfigs->assign(mAllowedDisplayConfigs.begin(), mAllowedDisplayConfigs.end());
+ }
+
+ return NO_ERROR;
+}
+
+void SurfaceFlinger::SetInputWindowsListener::onSetInputWindowsFinished() {
+ mFlinger->setInputWindowsFinished();
+}
+
+sp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
+ BBinder *b = handle->localBinder();
+ if (b == nullptr) {
+ return nullptr;
+ }
+ auto it = mLayersByLocalBinderToken.find(b);
+ if (it != mLayersByLocalBinderToken.end()) {
+ return it->second.promote();
+ }
+ return nullptr;
+}
+} // namespace android
#if defined(__gl_h_)
#error "don't include gl/gl.h in this file"