summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/SurfaceFlinger.cpp
diff options
context:
space:
mode:
author Xin Li <delphij@google.com> 2018-06-08 15:11:57 -0700
committer Xin Li <delphij@google.com> 2018-06-08 15:11:57 -0700
commitf11e2bd016d886a333345dea853ebda23a408d5c (patch)
tree905bd4d25d6ab2b046620ff459777d8dcfa5d7de /services/surfaceflinger/SurfaceFlinger.cpp
parentaabd6b7fa343654cd85b3b2da392e424d037d15a (diff)
parent5c947cdf72270fd1f766b2248d526ebc8c7227f6 (diff)
Merge pi-dev-plus-aosp-without-vendor into stage-aosp-master
Bug: 79597307 Change-Id: I6d6bee71b9424eb478780bbfc06b830eb8ded342
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp2470
1 files changed, 1485 insertions, 985 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ffc61bef7f..87baf8c8a8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -28,8 +28,6 @@
#include <stdatomic.h>
#include <optional>
-#include <EGL/egl.h>
-
#include <cutils/properties.h>
#include <log/log.h>
@@ -63,19 +61,21 @@
#include <private/android_filesystem_config.h>
#include <private/gui/SyncFeatures.h>
+#include "BufferLayer.h"
#include "Client.h"
-#include "clz.h"
+#include "ColorLayer.h"
#include "Colorizer.h"
+#include "ContainerLayer.h"
#include "DdmConnection.h"
-#include "DisplayDevice.h"
#include "DispSync.h"
+#include "DisplayDevice.h"
#include "EventControlThread.h"
#include "EventThread.h"
#include "Layer.h"
#include "LayerVector.h"
-#include "LayerDim.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
+#include "clz.h"
#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/FramebufferSurface.h"
@@ -88,8 +88,12 @@
#include <cutils/compiler.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 <configstore/Utils.h>
+#include <layerproto/LayerProtoParser.h>
+
#define DISPLAY_COUNT 1
/*
@@ -98,12 +102,14 @@
*/
#define DEBUG_SCREENSHOTS false
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-
namespace android {
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
+using ui::ColorMode;
+using ui::Dataspace;
+using ui::Hdr;
+using ui::RenderIntent;
namespace {
class ConditionalLock {
@@ -130,13 +136,13 @@ const String16 sDump("android.permission.DUMP");
// ---------------------------------------------------------------------------
int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
-bool SurfaceFlinger::useContextPriority;
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;
@@ -154,16 +160,63 @@ bool useTrebleTestingOverride() {
return std::string(value) == "true";
}
-SurfaceFlinger::SurfaceFlinger()
- : BnSurfaceComposer(),
+std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
+ switch(displayColorSetting) {
+ case DisplayColorSetting::MANAGED:
+ return std::string("Managed");
+ case DisplayColorSetting::UNMANAGED:
+ return std::string("Unmanaged");
+ case DisplayColorSetting::ENHANCED:
+ return std::string("Enhanced");
+ default:
+ return std::string("Unknown ") +
+ std::to_string(static_cast<int>(displayColorSetting));
+ }
+}
+
+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(); }
+
+ sp<Surface> surface;
+};
+
+} // 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),
- mHwcServiceName(getHwcServiceName()),
- mRenderEngine(nullptr),
mBootTime(systemTime()),
mBuiltinDisplays(),
mVisibleRegionsDirty(false),
@@ -179,20 +232,17 @@ SurfaceFlinger::SurfaceFlinger()
mLastTransactionTime(0),
mBootFinished(false),
mForceFullDamage(false),
- mInterceptor(this),
mPrimaryDispSync("PrimaryDispSync"),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
- mHasColorMatrix(false),
mHasPoweredOff(false),
- mFrameBuckets(),
- mTotalTime(0),
- mLastSwapTime(0),
mNumLayers(0),
mVrFlingerRequestsDisplay(false),
mMainThreadId(std::this_thread::get_id()),
- mComposerSequenceId(0)
-{
+ mCreateBufferQueue(&BufferQueue::createBufferQueue),
+ mCreateNativeWindowSurface(&impl::NativeWindowSurface::create) {}
+
+SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
@@ -204,9 +254,6 @@ SurfaceFlinger::SurfaceFlinger()
hasSyncFramework = getBool< ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::hasSyncFramework>(true);
- useContextPriority = getBool< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::useContextPriority>(false);
-
dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0);
@@ -226,7 +273,27 @@ SurfaceFlinger::SurfaceFlinger()
hasWideColorDisplay =
getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
- mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset);
+ V1_1::DisplayOrientation primaryDisplayOrientation =
+ getDisplayOrientation< V1_1::ISurfaceFlingerConfigs, &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
+ V1_1::DisplayOrientation::ORIENTATION_0);
+
+ switch (primaryDisplayOrientation) {
+ case V1_1::DisplayOrientation::ORIENTATION_90:
+ mPrimaryDisplayOrientation = DisplayState::eOrientation90;
+ break;
+ case V1_1::DisplayOrientation::ORIENTATION_180:
+ mPrimaryDisplayOrientation = DisplayState::eOrientation180;
+ break;
+ case V1_1::DisplayOrientation::ORIENTATION_270:
+ mPrimaryDisplayOrientation = DisplayState::eOrientation270;
+ break;
+ default:
+ mPrimaryDisplayOrientation = DisplayState::eOrientationDefault;
+ break;
+ }
+ ALOGV("Primary Display Orientation is set to %2d.", mPrimaryDisplayOrientation);
+
+ mPrimaryDispSync.init(SurfaceFlinger::hasSyncFramework, SurfaceFlinger::dispSyncPresentTimeOffset);
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
@@ -260,6 +327,16 @@ SurfaceFlinger::SurfaceFlinger()
mLayerTripleBufferingDisabled = atoi(value);
ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
+ const size_t defaultListSize = MAX_LAYERS;
+ auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
+ mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
+
+ property_get("debug.sf.early_phase_offset_ns", value, "0");
+ const int earlyWakeupOffsetOffsetNs = atoi(value);
+ ALOGI_IF(earlyWakeupOffsetOffsetNs != 0, "Enabling separate early offset");
+ mVsyncModulator.setPhaseOffsets(sfVsyncPhaseOffsetNs - earlyWakeupOffsetOffsetNs,
+ sfVsyncPhaseOffsetNs);
+
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -277,14 +354,11 @@ SurfaceFlinger::SurfaceFlinger()
void SurfaceFlinger::onFirstRef()
{
- mEventQueue.init(this);
+ mEventQueue->init(this);
}
SurfaceFlinger::~SurfaceFlinger()
{
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglTerminate(display);
}
void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
@@ -346,7 +420,7 @@ sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
info.displayName = displayName;
mCurrentState.displays.add(token, info);
- mInterceptor.saveDisplayCreation(info);
+ mInterceptor->saveDisplayCreation(info);
return token;
}
@@ -364,7 +438,7 @@ void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) {
ALOGE("destroyDisplay called for non-virtual display");
return;
}
- mInterceptor.saveDisplayDeletion(info.displayId);
+ mInterceptor->saveDisplayDeletion(info.displayId);
mCurrentState.displays.removeItemsAt(idx);
setTransactionFlags(eDisplayTransactionNeeded);
}
@@ -372,7 +446,7 @@ void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) {
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 NULL;
+ return nullptr;
}
return mBuiltinDisplays[id];
}
@@ -414,12 +488,11 @@ void SurfaceFlinger::bootFinished()
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
class MessageDestroyGLTexture : public MessageBase {
- RenderEngine& engine;
+ RE::RenderEngine& engine;
uint32_t texture;
public:
- MessageDestroyGLTexture(RenderEngine& engine, uint32_t texture)
- : engine(engine), texture(texture) {
- }
+ MessageDestroyGLTexture(RE::RenderEngine& engine, uint32_t texture)
+ : engine(engine), texture(texture) {}
virtual bool handler() {
engine.deleteTextures(1, &texture);
return true;
@@ -428,7 +501,7 @@ void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
}
-class DispSyncSource : public VSyncSource, private DispSync::Callback {
+class DispSyncSource final : public VSyncSource, private DispSync::Callback {
public:
DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
const char* name) :
@@ -439,14 +512,13 @@ public:
mVsyncEventLabel(String8::format("VSYNC-%s", name)),
mDispSync(dispSync),
mCallbackMutex(),
- mCallback(),
mVsyncMutex(),
mPhaseOffset(phaseOffset),
mEnabled(false) {}
- virtual ~DispSyncSource() {}
+ ~DispSyncSource() override = default;
- virtual void setVSyncEnabled(bool enable) {
+ void setVSyncEnabled(bool enable) override {
Mutex::Autolock lock(mVsyncMutex);
if (enable) {
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
@@ -468,12 +540,12 @@ public:
mEnabled = enable;
}
- virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+ void setCallback(VSyncSource::Callback* callback) override{
Mutex::Autolock lock(mCallbackMutex);
mCallback = callback;
}
- virtual void setPhaseOffset(nsecs_t phaseOffset) {
+ void setPhaseOffset(nsecs_t phaseOffset) override {
Mutex::Autolock lock(mVsyncMutex);
// Normalize phaseOffset to [0, period)
@@ -491,26 +563,17 @@ public:
return;
}
- // Remove the listener with the old offset
- status_t err = mDispSync->removeEventListener(
- static_cast<DispSync::Callback*>(this));
- if (err != NO_ERROR) {
- ALOGE("error unregistering vsync callback: %s (%d)",
- strerror(-err), err);
- }
-
- // Add a listener with the new offset
- err = mDispSync->addEventListener(mName, mPhaseOffset,
- static_cast<DispSync::Callback*>(this));
+ status_t err = mDispSync->changePhaseOffset(static_cast<DispSync::Callback*>(this),
+ mPhaseOffset);
if (err != NO_ERROR) {
- ALOGE("error registering vsync callback: %s (%d)",
+ ALOGE("error changing vsync offset: %s (%d)",
strerror(-err), err);
}
}
private:
virtual void onDispSyncEvent(nsecs_t when) {
- sp<VSyncSource::Callback> callback;
+ VSyncSource::Callback* callback;
{
Mutex::Autolock lock(mCallbackMutex);
callback = mCallback;
@@ -521,7 +584,7 @@ private:
}
}
- if (callback != NULL) {
+ if (callback != nullptr) {
callback->onVSyncEvent(when);
}
}
@@ -537,35 +600,36 @@ private:
DispSync* mDispSync;
Mutex mCallbackMutex; // Protects the following
- sp<VSyncSource::Callback> mCallback;
+ VSyncSource::Callback* mCallback = nullptr;
Mutex mVsyncMutex; // Protects the following
nsecs_t mPhaseOffset;
bool mEnabled;
};
-class InjectVSyncSource : public VSyncSource {
+class InjectVSyncSource final : public VSyncSource {
public:
- InjectVSyncSource() {}
+ InjectVSyncSource() = default;
+ ~InjectVSyncSource() override = default;
- virtual ~InjectVSyncSource() {}
-
- virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+ void setCallback(VSyncSource::Callback* callback) override {
std::lock_guard<std::mutex> lock(mCallbackMutex);
mCallback = callback;
}
- virtual void onInjectSyncEvent(nsecs_t when) {
+ void onInjectSyncEvent(nsecs_t when) {
std::lock_guard<std::mutex> lock(mCallbackMutex);
- mCallback->onVSyncEvent(when);
+ if (mCallback) {
+ mCallback->onVSyncEvent(when);
+ }
}
- virtual void setVSyncEnabled(bool) {}
- virtual void setPhaseOffset(nsecs_t) {}
+ void setVSyncEnabled(bool) override {}
+ void setPhaseOffset(nsecs_t) override {}
private:
std::mutex mCallbackMutex; // Protects the following
- sp<VSyncSource::Callback> mCallback;
+ VSyncSource::Callback* mCallback = nullptr;
};
// Do not call property_set on main thread which will be blocked by init
@@ -578,53 +642,49 @@ void SurfaceFlinger::init() {
Mutex::Autolock _l(mStateLock);
- // initialize EGL for the default display
- mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(mEGLDisplay, NULL, NULL);
-
// start the EventThread
- sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
- vsyncPhaseOffsetNs, true, "app");
- mEventThread = new EventThread(vsyncSrc, *this, false);
- sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
- sfVsyncPhaseOffsetNs, true, "sf");
- mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
- mEventQueue.setEventThread(mSFEventThread);
-
- // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter
- struct sched_param param = {0};
- param.sched_priority = 2;
- if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
- ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
- }
- if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, &param) != 0) {
- ALOGE("Couldn't set SCHED_FIFO for 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.setEventThread(mSFEventThread.get());
// Get a RenderEngine for the given display / config (can't fail)
- mRenderEngine = RenderEngine::create(mEGLDisplay,
- HAL_PIXEL_FORMAT_RGBA_8888,
- hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0);
-
- // retrieve the EGL context that was selected/created
- mEGLContext = mRenderEngine->getEGLContext();
-
- LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
- "couldn't create EGLContext");
+ 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");
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
"Starting with vr flinger active is not currently supported.");
- mHwc.reset(new HWComposer(mHwcServiceName));
- mHwc->registerCallback(this, mComposerSequenceId);
+ getBE().mHwc.reset(
+ new HWComposer(std::make_unique<Hwc2::impl::Composer>(getBE().mHwcServiceName)));
+ getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
- LOG_ALWAYS_FATAL_IF(!mHwc->isConnected(HWC_DISPLAY_PRIMARY),
- "Registered composer callback but didn't create the default primary "
- "display");
+ 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(mEGLDisplay, mEGLContext);
+ getDefaultDisplayDeviceLocked()->makeCurrent();
if (useVrFlinger) {
auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
@@ -641,15 +701,16 @@ void SurfaceFlinger::init() {
});
postMessageAsync(message);
};
- mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(),
- vrFlingerRequestDisplayCallback);
+ mVrFlinger = dvr::VrFlinger::Create(getBE().mHwc->getComposer(),
+ getBE().mHwc->getHwcDisplayId(HWC_DISPLAY_PRIMARY).value_or(0),
+ vrFlingerRequestDisplayCallback);
if (!mVrFlinger) {
ALOGE("Failed to start vrflinger");
}
}
- mEventControlThread = new EventControlThread(this);
- mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
+ mEventControlThread = std::make_unique<impl::EventControlThread>(
+ [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -657,7 +718,7 @@ void SurfaceFlinger::init() {
// set initial conditions (e.g. unblank default device)
initializeDisplays();
- mRenderEngine->primeCache();
+ getBE().mRenderEngine->primeCache();
// Inform native graphics APIs whether the present timestamp is supported:
if (getHwComposer().hasCapability(
@@ -671,15 +732,24 @@ void SurfaceFlinger::init() {
ALOGE("Run StartPropertySetThread failed!");
}
+ mLegacySrgbSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
+ Dataspace::SRGB_LINEAR);
+
ALOGV("Done initializing");
}
void SurfaceFlinger::readPersistentProperties() {
+ Mutex::Autolock _l(mStateLock);
+
char value[PROPERTY_VALUE_MAX];
property_get("persist.sys.sf.color_saturation", value, "1.0");
- mSaturation = atof(value);
- ALOGV("Saturation is set to %.2f", mSaturation);
+ mGlobalSaturationFactor = atof(value);
+ updateColorMatrixLocked();
+ ALOGV("Saturation is set to %.2f", mGlobalSaturationFactor);
+
+ property_get("persist.sys.sf.native_mode", value, "0");
+ mDisplayColorSetting = static_cast<DisplayColorSetting>(atoi(value));
}
void SurfaceFlinger::startBootAnim() {
@@ -693,11 +763,11 @@ void SurfaceFlinger::startBootAnim() {
}
size_t SurfaceFlinger::getMaxTextureSize() const {
- return mRenderEngine->getMaxTextureSize();
+ return getBE().mRenderEngine->getMaxTextureSize();
}
size_t SurfaceFlinger::getMaxViewportDims() const {
- return mRenderEngine->getMaxViewportDims();
+ return getBE().mRenderEngine->getMaxViewportDims();
}
// ----------------------------------------------------------------------------
@@ -711,7 +781,7 @@ bool SurfaceFlinger::authenticateSurfaceTexture(
bool SurfaceFlinger::authenticateSurfaceTextureLocked(
const sp<IGraphicBufferProducer>& bufferProducer) const {
sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer));
- return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
+ return mGraphicBufferProducerList.count(surfaceTextureBinder.get()) > 0;
}
status_t SurfaceFlinger::getSupportedFrameTimestamps(
@@ -737,7 +807,7 @@ status_t SurfaceFlinger::getSupportedFrameTimestamps(
status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
Vector<DisplayInfo>* configs) {
- if ((configs == NULL) || (display.get() == NULL)) {
+ if (configs == nullptr || display.get() == nullptr) {
return BAD_VALUE;
}
@@ -761,7 +831,7 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
static int getDensityFromProperty(char const* propName) {
char property[PROPERTY_VALUE_MAX];
int density = 0;
- if (property_get(propName, property, NULL) > 0) {
+ if (property_get(propName, property, nullptr) > 0) {
density = atoi(property);
}
return density;
@@ -801,7 +871,7 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
// TODO: this needs to go away (currently needed only by webkit)
sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
- info.orientation = hw->getOrientation();
+ info.orientation = hw ? hw->getOrientation() : 0;
} else {
// TODO: where should this value come from?
static const int TV_DENSITY = 213;
@@ -834,6 +904,11 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
// All non-virtual displays are currently considered secure.
info.secure = true;
+ if (type == DisplayDevice::DISPLAY_PRIMARY &&
+ mPrimaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
+ std::swap(info.w, info.h);
+ }
+
configs->push_back(info);
}
@@ -842,7 +917,7 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */,
DisplayStatInfo* stats) {
- if (stats == NULL) {
+ if (stats == nullptr) {
return BAD_VALUE;
}
@@ -854,13 +929,13 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */,
}
int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
- if (display == NULL) {
- ALOGE("%s : display is NULL", __func__);
+ if (display == nullptr) {
+ ALOGE("%s : display is nullptr", __func__);
return BAD_VALUE;
}
sp<const DisplayDevice> device(getDisplayDevice(display));
- if (device != NULL) {
+ if (device != nullptr) {
return device->getActiveConfig();
}
@@ -905,7 +980,7 @@ status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) {
return true;
}
sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
- if (hw == NULL) {
+ if (hw == nullptr) {
ALOGE("Attempt to set active config = %d for null display %p",
mMode, mDisplay.get());
} else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
@@ -922,7 +997,7 @@ status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) {
return NO_ERROR;
}
status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
- Vector<android_color_mode_t>* outColorModes) {
+ Vector<ColorMode>* outColorModes) {
if ((outColorModes == nullptr) || (display.get() == nullptr)) {
return BAD_VALUE;
}
@@ -943,7 +1018,7 @@ status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
return type;
}
- std::vector<android_color_mode_t> modes;
+ std::vector<ColorMode> modes;
{
ConditionalLock _l(mStateLock,
std::this_thread::get_id() != mMainThreadId);
@@ -955,20 +1030,24 @@ status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
return NO_ERROR;
}
-android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
+ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
sp<const DisplayDevice> device(getDisplayDevice(display));
if (device != nullptr) {
return device->getActiveColorMode();
}
- return static_cast<android_color_mode_t>(BAD_VALUE);
+ return static_cast<ColorMode>(BAD_VALUE);
}
void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
- android_color_mode_t mode) {
+ ColorMode mode, Dataspace dataSpace,
+ RenderIntent renderIntent) {
int32_t type = hw->getDisplayType();
- android_color_mode_t currentMode = hw->getActiveColorMode();
+ ColorMode currentMode = hw->getActiveColorMode();
+ Dataspace currentDataSpace = hw->getCompositionDataSpace();
+ RenderIntent currentRenderIntent = hw->getActiveRenderIntent();
- if (mode == currentMode) {
+ if (mode == currentMode && dataSpace == currentDataSpace &&
+ renderIntent == currentRenderIntent) {
return;
}
@@ -977,29 +1056,33 @@ void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
return;
}
- ALOGD("Set active color mode: %s (%d), type=%d", decodeColorMode(mode).c_str(), mode,
- hw->getDisplayType());
-
hw->setActiveColorMode(mode);
- getHwComposer().setActiveColorMode(type, mode);
+ hw->setCompositionDataSpace(dataSpace);
+ hw->setActiveRenderIntent(renderIntent);
+ getHwComposer().setActiveColorMode(type, mode, renderIntent);
+
+ 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::setActiveColorMode(const sp<IBinder>& display,
- android_color_mode_t colorMode) {
+ ColorMode colorMode) {
class MessageSetActiveColorMode: public MessageBase {
SurfaceFlinger& mFlinger;
sp<IBinder> mDisplay;
- android_color_mode_t mMode;
+ ColorMode mMode;
public:
MessageSetActiveColorMode(SurfaceFlinger& flinger, const sp<IBinder>& disp,
- android_color_mode_t mode) :
+ ColorMode mode) :
mFlinger(flinger), mDisplay(disp) { mMode = mode; }
virtual bool handler() {
- Vector<android_color_mode_t> modes;
+ Vector<ColorMode> modes;
mFlinger.getDisplayColorModes(mDisplay, &modes);
bool exists = std::find(std::begin(modes), std::end(modes), mMode) != std::end(modes);
- if (mMode < 0 || !exists) {
+ 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;
@@ -1012,7 +1095,8 @@ status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
ALOGW("Attempt to set active color mode %s %d for virtual display",
decodeColorMode(mMode).c_str(), mMode);
} else {
- mFlinger.setActiveColorModeInternal(hw, mMode);
+ mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN,
+ RenderIntent::COLORIMETRIC);
}
return true;
}
@@ -1044,40 +1128,51 @@ status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& display,
return BAD_VALUE;
}
- std::unique_ptr<HdrCapabilities> capabilities =
- mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
- if (capabilities) {
- std::swap(*outCapabilities, *capabilities);
- } else {
- 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();
+ *outCapabilities = HdrCapabilities(capabilities.getSupportedHdrTypes(),
+ capabilities.getDesiredMaxLuminance(),
+ capabilities.getDesiredMaxAverageLuminance(),
+ capabilities.getDesiredMinLuminance());
return NO_ERROR;
}
status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
- if (enable == mInjectVSyncs) {
- return NO_ERROR;
- }
+ sp<LambdaMessage> enableVSyncInjections = new LambdaMessage([&]() {
+ Mutex::Autolock _l(mStateLock);
- if (enable) {
- mInjectVSyncs = enable;
- ALOGV("VSync Injections enabled");
- if (mVSyncInjector.get() == nullptr) {
- mVSyncInjector = new InjectVSyncSource();
- mInjectorEventThread = new EventThread(mVSyncInjector, *this, false);
+ if (mInjectVSyncs == enable) {
+ return;
}
- mEventQueue.setEventThread(mInjectorEventThread);
- } else {
+
+ 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());
+ } else {
+ ALOGV("VSync Injections disabled");
+ mEventQueue->setEventThread(mSFEventThread.get());
+ }
+
mInjectVSyncs = enable;
- ALOGV("VSync Injections disabled");
- mEventQueue.setEventThread(mSFEventThread);
- mVSyncInjector.clear();
- }
+ });
+ postMessageSync(enableVSyncInjections);
return NO_ERROR;
}
status_t SurfaceFlinger::injectVSync(nsecs_t when) {
+ Mutex::Autolock _l(mStateLock);
+
if (!mInjectVSyncs) {
ALOGE("VSync Injections not enabled");
return BAD_VALUE;
@@ -1089,7 +1184,8 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) {
return NO_ERROR;
}
-status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const {
+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();
@@ -1130,30 +1226,30 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
// ----------------------------------------------------------------------------
void SurfaceFlinger::waitForEvent() {
- mEventQueue.waitMessage();
+ mEventQueue->waitMessage();
}
void SurfaceFlinger::signalTransaction() {
- mEventQueue.invalidate();
+ mEventQueue->invalidate();
}
void SurfaceFlinger::signalLayerUpdate() {
- mEventQueue.invalidate();
+ mEventQueue->invalidate();
}
void SurfaceFlinger::signalRefresh() {
mRefreshPending = true;
- mEventQueue.refresh();
+ mEventQueue->refresh();
}
status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
nsecs_t reltime, uint32_t /* flags */) {
- return mEventQueue.postMessage(msg, reltime);
+ return mEventQueue->postMessage(msg, reltime);
}
status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
nsecs_t reltime, uint32_t /* flags */) {
- status_t res = mEventQueue.postMessage(msg, reltime);
+ status_t res = mEventQueue->postMessage(msg, reltime);
if (res == NO_ERROR) {
msg->wait();
}
@@ -1187,7 +1283,7 @@ void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
return;
}
- const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
const nsecs_t period = activeConfig->getVsyncPeriod();
mPrimaryDispSync.reset();
@@ -1230,12 +1326,12 @@ 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 != mComposerSequenceId) {
+ if (sequenceId != getBE().mComposerSequenceId) {
return;
}
int32_t type;
- if (!mHwc->onVsync(displayId, timestamp, &type)) {
+ if (!getBE().mHwc->onVsync(displayId, timestamp, &type)) {
return;
}
@@ -1256,21 +1352,17 @@ void SurfaceFlinger::onVsyncReceived(int32_t sequenceId,
}
void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
- std::lock_guard<std::mutex> lock(mCompositorTimingLock);
- *compositorTiming = mCompositorTiming;
+ std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
+ *compositorTiming = getBE().mCompositorTiming;
}
-void SurfaceFlinger::onHotplugReceived(int32_t sequenceId,
- hwc2_display_t display, HWC2::Connection connection,
- bool primaryDisplay) {
- ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s, %s)",
- sequenceId, display,
- connection == HWC2::Connection::Connected ?
- "connected" : "disconnected",
- primaryDisplay ? "primary" : "external");
+void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+ HWC2::Connection connection) {
+ ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s)", sequenceId, display,
+ connection == HWC2::Connection::Connected ? "connected" : "disconnected");
// Ignore events that do not have the right sequenceId.
- if (sequenceId != mComposerSequenceId) {
+ if (sequenceId != getBE().mComposerSequenceId) {
return;
}
@@ -1280,7 +1372,7 @@ void SurfaceFlinger::onHotplugReceived(int32_t sequenceId,
// acquire it here.
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
- mPendingHotplugEvents.emplace_back(HotplugEvent{display, connection, primaryDisplay});
+ mPendingHotplugEvents.emplace_back(HotplugEvent{display, connection});
if (std::this_thread::get_id() == mMainThreadId) {
// Process all pending hot plug events immediately if we are on the main thread.
@@ -1293,10 +1385,10 @@ void SurfaceFlinger::onHotplugReceived(int32_t sequenceId,
void SurfaceFlinger::onRefreshReceived(int sequenceId,
hwc2_display_t /*display*/) {
Mutex::Autolock lock(mStateLock);
- if (sequenceId != mComposerSequenceId) {
+ if (sequenceId != getBE().mComposerSequenceId) {
return;
}
- repaintEverythingLocked();
+ repaintEverything();
}
void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
@@ -1314,7 +1406,7 @@ void SurfaceFlinger::resetDisplayState() {
// mCurrentState and mDrawingState and re-apply all changes when we make the
// transition.
mDrawingState.displays.clear();
- eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ getRenderEngine().resetCurrentSurface();
mDisplays.clear();
}
@@ -1322,11 +1414,11 @@ void SurfaceFlinger::updateVrFlinger() {
if (!mVrFlinger)
return;
bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
- if (vrFlingerRequestsDisplay == mHwc->isUsingVrComposer()) {
+ if (vrFlingerRequestsDisplay == getBE().mHwc->isUsingVrComposer()) {
return;
}
- if (vrFlingerRequestsDisplay && !mHwc->getComposer()->isRemote()) {
+ if (vrFlingerRequestsDisplay && !getBE().mHwc->getComposer()->isRemote()) {
ALOGE("Vr flinger is only supported for remote hardware composer"
" service connections. Ignoring request to transition to vr"
" flinger.");
@@ -1344,13 +1436,13 @@ void SurfaceFlinger::updateVrFlinger() {
}
resetDisplayState();
- mHwc.reset(); // Delete the current instance before creating the new one
- mHwc.reset(new HWComposer(
- vrFlingerRequestsDisplay ? "vr" : mHwcServiceName));
- mHwc->registerCallback(this, ++mComposerSequenceId);
+ 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);
- LOG_ALWAYS_FATAL_IF(!mHwc->getComposer()->isRemote(),
- "Switched to non-remote hardware composer");
+ LOG_ALWAYS_FATAL_IF(!getBE().mHwc->getComposer()->isRemote(),
+ "Switched to non-remote hardware composer");
if (vrFlingerRequestsDisplay) {
mVrFlinger->GrantDisplayOwnership();
@@ -1367,7 +1459,7 @@ void SurfaceFlinger::updateVrFlinger() {
setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true);
// Reset the timing values to account for the period of the swapped in HWC
- const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
@@ -1388,9 +1480,12 @@ void SurfaceFlinger::onMessageReceived(int32_t what) {
(mPreviousPresentFence->getSignalTime() ==
Fence::SIGNAL_TIME_PENDING);
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
- if (mPropagateBackpressure && frameMissed) {
- signalLayerUpdate();
- break;
+ if (frameMissed) {
+ mTimeStats.incrementMissedFrames();
+ if (mPropagateBackpressure) {
+ signalLayerUpdate();
+ break;
+ }
}
// Now that we're going to make it to the handleMessageTransaction()
@@ -1441,17 +1536,20 @@ void SurfaceFlinger::handleMessageRefresh() {
rebuildLayerStacks();
setUpHWComposer();
doDebugFlashRegions();
+ doTracing("handleRefresh");
+ logLayerStats();
doComposition();
postComposition(refreshStartTime);
- mPreviousPresentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
+ mPreviousPresentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
mHadClientComposition = false;
for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
mHadClientComposition = mHadClientComposition ||
- mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
+ getBE().mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
}
+ mVsyncModulator.onRefreshed(mHadClientComposition);
mLayersWithQueuedFrames.clear();
}
@@ -1470,11 +1568,11 @@ void SurfaceFlinger::doDebugFlashRegions()
const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
if (!dirtyRegion.isEmpty()) {
// redraw the whole screen
- doComposeSurfaces(hw, Region(hw->bounds()));
+ doComposeSurfaces(hw);
// and draw the dirty region
const int32_t height = hw->getHeight();
- RenderEngine& engine(getRenderEngine());
+ auto& engine(getRenderEngine());
engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
hw->swapBuffers(getHwComposer());
@@ -1494,9 +1592,38 @@ void SurfaceFlinger::doDebugFlashRegions()
continue;
}
- status_t result = displayDevice->prepareFrame(*mHwc);
- ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
- " %d (%s)", displayId, result, strerror(-result));
+ status_t result = displayDevice->prepareFrame(*getBE().mHwc);
+ ALOGE_IF(result != NO_ERROR,
+ "prepareFrame for display %zd failed:"
+ " %d (%s)",
+ displayId, result, strerror(-result));
+ }
+}
+
+void SurfaceFlinger::doTracing(const char* where) {
+ ATRACE_CALL();
+ ATRACE_NAME(where);
+ if (CC_UNLIKELY(mTracing.isEnabled())) {
+ mTracing.traceLayers(where, dumpProtoInfo(LayerVector::StateSet::Drawing));
+ }
+}
+
+void SurfaceFlinger::logLayerStats() {
+ ATRACE_CALL();
+ if (CC_UNLIKELY(mLayerStats.isEnabled())) {
+ 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;
+ }
+ }
+ if (hwcId < 0) {
+ ALOGE("LayerStats: Hmmm, no primary display?");
+ return;
+ }
+ mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(hwcId));
}
}
@@ -1522,10 +1649,10 @@ void SurfaceFlinger::updateCompositorTiming(
std::shared_ptr<FenceTime>& presentFenceTime) {
// Update queue of past composite+present times and determine the
// most recently known composite to present latency.
- mCompositePresentTimes.push({compositeTime, presentFenceTime});
+ getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime});
nsecs_t compositeToPresentLatency = -1;
- while (!mCompositePresentTimes.empty()) {
- CompositePresentTime& cpt = mCompositePresentTimes.front();
+ while (!getBE().mCompositePresentTimes.empty()) {
+ SurfaceFlingerBE::CompositePresentTime& cpt = getBE().mCompositePresentTimes.front();
// Cached values should have been updated before calling this method,
// which helps avoid duplicate syscalls.
nsecs_t displayTime = cpt.display->getCachedSignalTime();
@@ -1533,12 +1660,12 @@ void SurfaceFlinger::updateCompositorTiming(
break;
}
compositeToPresentLatency = displayTime - cpt.composite;
- mCompositePresentTimes.pop();
+ getBE().mCompositePresentTimes.pop();
}
// Don't let mCompositePresentTimes grow unbounded, just in case.
- while (mCompositePresentTimes.size() > 16) {
- mCompositePresentTimes.pop();
+ while (getBE().mCompositePresentTimes.size() > 16) {
+ getBE().mCompositePresentTimes.pop();
}
setCompositorTimingSnapped(
@@ -1570,10 +1697,10 @@ void SurfaceFlinger::setCompositorTimingSnapped(nsecs_t vsyncPhase,
nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ?
idealLatency + (extraVsyncs * vsyncInterval) : idealLatency;
- std::lock_guard<std::mutex> lock(mCompositorTimingLock);
- mCompositorTiming.deadline = vsyncPhase - idealLatency;
- mCompositorTiming.interval = vsyncInterval;
- mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
+ std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
+ getBE().mCompositorTiming.deadline = vsyncPhase - idealLatency;
+ getBE().mCompositorTiming.interval = vsyncInterval;
+ getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
}
void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
@@ -1590,20 +1717,20 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
// |mStateLock| not needed as we are on the main thread
const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
- mGlCompositionDoneTimeline.updateSignalTimes();
+ getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- if (mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
+ if (hw && getBE().mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
glCompositionDoneFenceTime =
std::make_shared<FenceTime>(hw->getClientTargetAcquireFence());
- mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
+ getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
} else {
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
- mDisplayTimeline.updateSignalTimes();
- sp<Fence> presentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
+ getBE().mDisplayTimeline.updateSignalTimes();
+ sp<Fence> presentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
- mDisplayTimeline.push(presentFenceTime);
+ getBE().mDisplayTimeline.push(presentFenceTime);
nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
@@ -1615,8 +1742,8 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
vsyncPhase, vsyncInterval, refreshStartTime, presentFenceTime);
CompositorTiming compositorTiming;
{
- std::lock_guard<std::mutex> lock(mCompositorTimingLock);
- compositorTiming = mCompositorTiming;
+ std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
+ compositorTiming = getBE().mCompositorTiming;
}
mDrawingState.traverseInZOrder([&](Layer* layer) {
@@ -1637,7 +1764,7 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
}
if (!hasSyncFramework) {
- if (hw->isDisplayOn()) {
+ if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) && hw->isDisplayOn()) {
enableHardwareVsync();
}
}
@@ -1648,17 +1775,23 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
- } else {
+ } else if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
nsecs_t presentTime =
- mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+ getBE().mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
mAnimFrameTracker.setActualPresentTime(presentTime);
}
mAnimFrameTracker.advanceFrame();
}
- if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+ mTimeStats.incrementTotalFrames();
+ if (mHadClientComposition) {
+ mTimeStats.incrementClientCompositionFrames();
+ }
+
+ if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) &&
+ hw->getPowerMode() == HWC_POWER_MODE_OFF) {
return;
}
@@ -1666,16 +1799,16 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
if (mHasPoweredOff) {
mHasPoweredOff = false;
} else {
- nsecs_t elapsedTime = currentTime - mLastSwapTime;
+ nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncInterval);
- if (numPeriods < NUM_BUCKETS - 1) {
- mFrameBuckets[numPeriods] += elapsedTime;
+ if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
+ getBE().mFrameBuckets[numPeriods] += elapsedTime;
} else {
- mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
+ getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] += elapsedTime;
}
- mTotalTime += elapsedTime;
+ getBE().mTotalTime += elapsedTime;
}
- mLastSwapTime = currentTime;
+ getBE().mLastSwapTime = currentTime;
}
void SurfaceFlinger::rebuildLayerStacks() {
@@ -1684,7 +1817,7 @@ void SurfaceFlinger::rebuildLayerStacks() {
// rebuild the visible layer list per screen
if (CC_UNLIKELY(mVisibleRegionsDirty)) {
- ATRACE_CALL();
+ ATRACE_NAME("rebuildLayerStacks VR Dirty");
mVisibleRegionsDirty = false;
invalidateHwcGeometry();
@@ -1745,61 +1878,82 @@ void SurfaceFlinger::rebuildLayerStacks() {
}
}
-mat4 SurfaceFlinger::computeSaturationMatrix() const {
- if (mSaturation == 1.0f) {
- return mat4();
+// Returns a data space that fits all visible layers. The returned data space
+// can only be one of
+// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
+// - Dataspace::DISPLAY_P3
+// 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;
+ *outHdrDataSpace = Dataspace::UNKNOWN;
+
+ for (const auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ switch (layer->getDataSpace()) {
+ case Dataspace::V0_SCRGB:
+ case Dataspace::V0_SCRGB_LINEAR:
+ case Dataspace::DISPLAY_P3:
+ bestDataSpace = Dataspace::DISPLAY_P3;
+ break;
+ case Dataspace::BT2020_PQ:
+ case Dataspace::BT2020_ITU_PQ:
+ *outHdrDataSpace = Dataspace::BT2020_PQ;
+ break;
+ case Dataspace::BT2020_HLG:
+ case Dataspace::BT2020_ITU_HLG:
+ // When there's mixed PQ content and HLG content, we set the HDR
+ // data space to be BT2020_PQ and convert HLG to PQ.
+ if (*outHdrDataSpace == Dataspace::UNKNOWN) {
+ *outHdrDataSpace = Dataspace::BT2020_HLG;
+ }
+ break;
+ default:
+ break;
+ }
}
- // Rec.709 luma coefficients
- float3 luminance{0.213f, 0.715f, 0.072f};
- luminance *= 1.0f - mSaturation;
- return mat4(
- vec4{luminance.r + mSaturation, luminance.r, luminance.r, 0.0f},
- vec4{luminance.g, luminance.g + mSaturation, luminance.g, 0.0f},
- vec4{luminance.b, luminance.b, luminance.b + mSaturation, 0.0f},
- vec4{0.0f, 0.0f, 0.0f, 1.0f}
- );
+ return bestDataSpace;
}
-// pickColorMode translates a given dataspace into the best available color mode.
-// Currently only support sRGB and Display-P3.
-android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) const {
- switch (dataSpace) {
- // treat Unknown as regular SRGB buffer, since that's what the rest of the
- // system expects.
- case HAL_DATASPACE_UNKNOWN:
- case HAL_DATASPACE_SRGB:
- case HAL_DATASPACE_V0_SRGB:
- return HAL_COLOR_MODE_SRGB;
- break;
+// Pick the ColorMode / Dataspace for the display device.
+void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice,
+ ColorMode* outMode, Dataspace* outDataSpace,
+ RenderIntent* outRenderIntent) const {
+ if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {
+ *outMode = ColorMode::NATIVE;
+ *outDataSpace = Dataspace::UNKNOWN;
+ *outRenderIntent = RenderIntent::COLORIMETRIC;
+ return;
+ }
- case HAL_DATASPACE_DISPLAY_P3:
- return HAL_COLOR_MODE_DISPLAY_P3;
- break;
+ Dataspace hdrDataSpace;
+ Dataspace bestDataSpace = getBestDataspace(displayDevice, &hdrDataSpace);
- default:
- // TODO (courtneygo): Do we want to assert an error here?
- ALOGE("No color mode mapping for %s (%#x)", dataspaceDetails(dataSpace).c_str(),
- dataSpace);
- return HAL_COLOR_MODE_SRGB;
- break;
+ // respect hdrDataSpace only when there is no legacy HDR support
+ const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN &&
+ !displayDevice->hasLegacyHdrSupport(hdrDataSpace);
+ if (isHdr) {
+ bestDataSpace = hdrDataSpace;
}
-}
-android_dataspace SurfaceFlinger::bestTargetDataSpace(
- android_dataspace a, android_dataspace b) const {
- // Only support sRGB and Display-P3 right now.
- if (a == HAL_DATASPACE_DISPLAY_P3 || b == HAL_DATASPACE_DISPLAY_P3) {
- return HAL_DATASPACE_DISPLAY_P3;
- }
- if (a == HAL_DATASPACE_V0_SCRGB_LINEAR || b == HAL_DATASPACE_V0_SCRGB_LINEAR) {
- return HAL_DATASPACE_DISPLAY_P3;
- }
- if (a == HAL_DATASPACE_V0_SCRGB || b == HAL_DATASPACE_V0_SCRGB) {
- return HAL_DATASPACE_DISPLAY_P3;
+ RenderIntent intent;
+ switch (mDisplayColorSetting) {
+ case DisplayColorSetting::MANAGED:
+ case DisplayColorSetting::UNMANAGED:
+ intent = isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC;
+ break;
+ case DisplayColorSetting::ENHANCED:
+ intent = isHdr ? RenderIntent::TONE_MAP_ENHANCE : RenderIntent::ENHANCE;
+ break;
+ default: // vendor display color setting
+ intent = static_cast<RenderIntent>(mDisplayColorSetting);
+ break;
}
- return HAL_DATASPACE_V0_SRGB;
+ displayDevice->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
}
void SurfaceFlinger::setUpHWComposer() {
@@ -1807,7 +1961,7 @@ void SurfaceFlinger::setUpHWComposer() {
ALOGV("setUpHWComposer");
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
+ bool dirty = !mDisplays[dpy]->getDirtyRegion(mRepaintEverything).isEmpty();
bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
@@ -1847,7 +2001,7 @@ void SurfaceFlinger::setUpHWComposer() {
for (size_t i = 0; i < currentLayers.size(); i++) {
const auto& layer = currentLayers[i];
if (!layer->hasHwcLayer(hwcId)) {
- if (!layer->createHwcLayer(mHwc.get(), hwcId)) {
+ if (!layer->createHwcLayer(getBE().mHwc.get(), hwcId)) {
layer->forceClientComposition(hwcId);
continue;
}
@@ -1862,9 +2016,6 @@ void SurfaceFlinger::setUpHWComposer() {
}
}
-
- mat4 colorMatrix = mColorMatrix * computeSaturationMatrix() * mDaltonizer();
-
// Set the per-frame data
for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
auto& displayDevice = mDisplays[displayId];
@@ -1873,32 +2024,44 @@ void SurfaceFlinger::setUpHWComposer() {
if (hwcId < 0) {
continue;
}
- if (colorMatrix != mPreviousColorMatrix) {
- status_t result = mHwc->setColorTransform(hwcId, colorMatrix);
+ 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;
+ }
+
layer->setPerFrameData(displayDevice);
}
if (hasWideColorDisplay) {
- android_color_mode newColorMode;
- android_dataspace newDataSpace = HAL_DATASPACE_V0_SRGB;
-
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace);
- ALOGV("layer: %s, dataspace: %s (%#x), newDataSpace: %s (%#x)",
- layer->getName().string(), dataspaceDetails(layer->getDataSpace()).c_str(),
- layer->getDataSpace(), dataspaceDetails(newDataSpace).c_str(), newDataSpace);
- }
- newColorMode = pickColorMode(newDataSpace);
-
- setActiveColorModeInternal(displayDevice, newColorMode);
+ ColorMode colorMode;
+ Dataspace dataSpace;
+ RenderIntent renderIntent;
+ pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
+ setActiveColorModeInternal(displayDevice, colorMode, dataSpace, renderIntent);
}
}
- mPreviousColorMatrix = colorMatrix;
+ mDrawingState.colorMatrixChanged = false;
for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
auto& displayDevice = mDisplays[displayId];
@@ -1906,7 +2069,7 @@ void SurfaceFlinger::setUpHWComposer() {
continue;
}
- status_t result = displayDevice->prepareFrame(*mHwc);
+ status_t result = displayDevice->prepareFrame(*getBE().mHwc);
ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
" %d (%s)", displayId, result, strerror(-result));
}
@@ -1927,8 +2090,7 @@ void SurfaceFlinger::doComposition() {
doDisplayComposition(hw, dirtyRegion);
hw->dirtyRegion.clear();
- hw->flip(hw->swapRegion);
- hw->swapRegion.clear();
+ hw->flip();
}
}
postFramebuffer();
@@ -1949,16 +2111,16 @@ void SurfaceFlinger::postFramebuffer()
}
const auto hwcId = displayDevice->getHwcDisplayId();
if (hwcId >= 0) {
- mHwc->presentAndGetReleaseFences(hwcId);
+ getBE().mHwc->presentAndGetReleaseFences(hwcId);
}
displayDevice->onSwapBuffersCompleted();
- displayDevice->makeCurrent(mEGLDisplay, mEGLContext);
+ displayDevice->makeCurrent();
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
// 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);
- sp<Fence> releaseFence = mHwc->getLayerReleaseFence(hwcId, hwcLayer);
+ sp<Fence> releaseFence = getBE().mHwc->getLayerReleaseFence(hwcId, hwcLayer);
// If the layer was client composited in the previous frame, we
// need to merge with the previous client target acquire fence.
@@ -1977,14 +2139,14 @@ void SurfaceFlinger::postFramebuffer()
// displayDevice->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
if (!displayDevice->getLayersNeedingFences().isEmpty()) {
- sp<Fence> presentFence = mHwc->getPresentFence(hwcId);
+ sp<Fence> presentFence = getBE().mHwc->getPresentFence(hwcId);
for (auto& layer : displayDevice->getLayersNeedingFences()) {
layer->onLayerDisplayed(presentFence);
}
}
if (hwcId >= 0) {
- mHwc->clearReleaseFences(hwcId);
+ getBE().mHwc->clearReleaseFences(hwcId);
}
}
@@ -1992,9 +2154,11 @@ void SurfaceFlinger::postFramebuffer()
mDebugInSwapBuffers = 0;
// |mStateLock| not needed as we are on the main thread
- uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
- if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
- logFrameStats();
+ if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
+ uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
+ if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
+ logFrameStats();
+ }
}
}
@@ -2018,6 +2182,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
+ mVsyncModulator.onTransactionHandled();
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
@@ -2027,37 +2192,65 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
// 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) {
- DisplayDevice::DisplayType displayType = event.isPrimaryDisplay
- ? DisplayDevice::DISPLAY_PRIMARY
- : DisplayDevice::DISPLAY_EXTERNAL;
+ 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;
+ }
- if (mHwc->isUsingVrComposer() && displayType == DisplayDevice::DISPLAY_EXTERNAL) {
+ if (getBE().mHwc->isUsingVrComposer() && displayType == DisplayDevice::DISPLAY_EXTERNAL) {
ALOGE("External displays are not supported by the vr hardware composer.");
continue;
}
- mHwc->onHotplug(event.display, event.connection);
+ getBE().mHwc->onHotplug(event.display, displayType, event.connection);
if (event.connection == HWC2::Connection::Connected) {
- ALOGV("Creating built in display %d", displayType);
- ALOGW_IF(mBuiltinDisplays[displayType], "Overwriting display token for display type %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 (!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);
+ }
} else {
ALOGV("Removing built in display %d", displayType);
ssize_t idx = mCurrentState.displays.indexOfKey(mBuiltinDisplays[displayType]);
if (idx >= 0) {
const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
- mInterceptor.saveDisplayDeletion(info.displayId);
+ mInterceptor->saveDisplayDeletion(info.displayId);
mCurrentState.displays.removeItemsAt(idx);
}
mBuiltinDisplays[displayType].clear();
@@ -2069,6 +2262,91 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() {
mPendingHotplugEvents.clear();
}
+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;
+
+ if (hasWideColorDisplay) {
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
+ for (ColorMode colorMode : modes) {
+ switch (colorMode) {
+ case ColorMode::DISPLAY_P3:
+ case ColorMode::ADOBE_RGB:
+ case ColorMode::DCI_P3:
+ hasWideColorGamut = true;
+ break;
+ default:
+ break;
+ }
+
+ std::vector<RenderIntent> renderIntents = getHwComposer().getRenderIntents(hwcId,
+ colorMode);
+ hwcColorModes.emplace(colorMode, renderIntents);
+ }
+ }
+
+ HdrCapabilities hdrCapabilities;
+ getHwComposer().getHdrCapabilities(hwcId, &hdrCapabilities);
+
+ auto nativeWindowSurface = mCreateNativeWindowSurface(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();
+
+ // 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) {
+ nativeWindow->setSwapInterval(nativeWindow.get(), 0);
+ }
+
+ // virtual displays are always considered enabled
+ auto initialPowerMode = (state.type >= DisplayDevice::DISPLAY_VIRTUAL) ? 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,
+ hasWideColorGamut, hdrCapabilities,
+ getHwComposer().getSupportedPerFrameMetadata(hwcId),
+ hwcColorModes, initialPowerMode);
+
+ if (maxFrameBufferAcquiredBuffers >= 3) {
+ nativeWindowSurface->preallocateBuffers();
+ }
+
+ ColorMode defaultColorMode = ColorMode::NATIVE;
+ Dataspace defaultDataSpace = Dataspace::UNKNOWN;
+ if (hasWideColorGamut) {
+ defaultColorMode = ColorMode::SRGB;
+ defaultDataSpace = Dataspace::SRGB;
+ }
+ setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace,
+ RenderIntent::COLORIMETRIC);
+ if (state.type < DisplayDevice::DISPLAY_VIRTUAL) {
+ hw->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
+ }
+ hw->setLayerStack(state.layerStack);
+ hw->setProjection(state.orientation, state.viewport, state.frame);
+ hw->setDisplayName(state.displayName);
+
+ return hw;
+}
+
void SurfaceFlinger::processDisplayChangesLocked() {
// here we take advantage of Vector's copy-on-write semantics to
// improve performance by skipping the transaction entirely when
@@ -2088,20 +2366,16 @@ void SurfaceFlinger::processDisplayChangesLocked() {
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
if (j < 0) {
// in drawing state but not in current state
- if (!draw[i].isMainDisplay()) {
- // 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());
- defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext);
- sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
- if (hw != NULL) hw->disconnect(getHwComposer());
- if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
- mEventThread->onHotplugReceived(draw[i].type, false);
- mDisplays.removeItem(draw.keyAt(i));
- } else {
- ALOGW("trying to remove the main display");
- }
+ // 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));
} else {
// this display is in both lists. see if something changed.
const DisplayDeviceState& state(curr[j]);
@@ -2114,7 +2388,7 @@ void SurfaceFlinger::processDisplayChangesLocked() {
// from the drawing state, so that it get re-added
// below.
sp<DisplayDevice> hw(getDisplayDeviceLocked(display));
- if (hw != NULL) hw->disconnect(getHwComposer());
+ if (hw != nullptr) hw->disconnect(getHwComposer());
mDisplays.removeItem(display);
mDrawingState.displays.removeItemsAt(i);
dc--;
@@ -2123,7 +2397,7 @@ void SurfaceFlinger::processDisplayChangesLocked() {
}
const sp<DisplayDevice> disp(getDisplayDeviceLocked(display));
- if (disp != NULL) {
+ if (disp != nullptr) {
if (state.layerStack != draw[i].layerStack) {
disp->setLayerStack(state.layerStack);
}
@@ -2149,16 +2423,16 @@ void SurfaceFlinger::processDisplayChangesLocked() {
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
- BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
+ mCreateBufferQueue(&bqProducer, &bqConsumer, false);
int32_t hwcId = -1;
if (state.isVirtualDisplay()) {
// 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 != NULL) {
+ if (state.surface != nullptr) {
// Allow VR composer to use virtual displays.
- if (mUseHwcVirtualDisplays || mHwc->isUsingVrComposer()) {
+ if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) {
int width = 0;
int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
@@ -2168,71 +2442,37 @@ void SurfaceFlinger::processDisplayChangesLocked() {
int intFormat = 0;
status = state.surface->query(NATIVE_WINDOW_FORMAT, &intFormat);
ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
- auto format = static_cast<android_pixel_format_t>(intFormat);
+ auto format = static_cast<ui::PixelFormat>(intFormat);
- mHwc->allocateVirtualDisplay(width, height, &format, &hwcId);
+ getBE().mHwc->allocateVirtualDisplay(width, height, &format, &hwcId);
}
// TODO: Plumb requested format back up to consumer
sp<VirtualDisplaySurface> vds =
- new VirtualDisplaySurface(*mHwc, hwcId, state.surface, bqProducer,
- bqConsumer, state.displayName);
+ new VirtualDisplaySurface(*getBE().mHwc, hwcId, state.surface,
+ bqProducer, bqConsumer,
+ state.displayName);
dispSurface = vds;
producer = vds;
}
} else {
- ALOGE_IF(state.surface != NULL,
+ ALOGE_IF(state.surface != nullptr,
"adding a supported display, but rendering "
"surface is provided (%p), ignoring it",
state.surface.get());
hwcId = state.type;
- dispSurface = new FramebufferSurface(*mHwc, hwcId, bqConsumer);
+ dispSurface = new FramebufferSurface(*getBE().mHwc, hwcId, bqConsumer);
producer = bqProducer;
}
const wp<IBinder>& display(curr.keyAt(i));
-
- if (dispSurface != NULL) {
- bool useWideColorMode = hasWideColorDisplay;
- if (state.isMainDisplay()) {
- bool hasWideColorModes = false;
- std::vector<android_color_mode_t> modes =
- getHwComposer().getColorModes(state.type);
- for (android_color_mode_t colorMode : modes) {
- switch (colorMode) {
- case HAL_COLOR_MODE_DISPLAY_P3:
- case HAL_COLOR_MODE_ADOBE_RGB:
- case HAL_COLOR_MODE_DCI_P3:
- hasWideColorModes = true;
- break;
- default:
- break;
- }
- }
- useWideColorMode = hasWideColorModes && hasWideColorDisplay;
- }
-
- sp<DisplayDevice> hw =
- new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
- dispSurface, producer, mRenderEngine->getEGLConfig(),
- useWideColorMode);
-
- if (state.isMainDisplay()) {
- android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
- if (useWideColorMode) {
- defaultColorMode = HAL_COLOR_MODE_SRGB;
- }
- setActiveColorModeInternal(hw, defaultColorMode);
- hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
- }
-
- hw->setLayerStack(state.layerStack);
- hw->setProjection(state.orientation, state.viewport, state.frame);
- hw->setDisplayName(state.displayName);
- mDisplays.add(display, hw);
+ if (dispSurface != nullptr) {
+ mDisplays.add(display,
+ setupNewDisplayDeviceInternal(display, hwcId, state, dispSurface,
+ producer));
if (!state.isVirtualDisplay()) {
mEventThread->onHotplugReceived(state.type, true);
}
@@ -2276,7 +2516,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
processDisplayHotplugEventsLocked();
}
- if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
+ if (transactionFlags & (eDisplayLayerStackChanged|eDisplayTransactionNeeded)) {
// The transform hint might have changed for some layers
// (either because a display has changed, or because a layer
// as changed).
@@ -2313,16 +2553,17 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
- if (disp == NULL) {
+ if (disp == nullptr) {
disp = std::move(hw);
} else {
- disp = NULL;
+ disp = nullptr;
break;
}
}
}
}
- if (disp == NULL) {
+
+ if (disp == nullptr) {
// NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
// redraw after transform hint changes. See bug 8508397.
@@ -2331,7 +2572,12 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
// screen off/on times.
disp = getDefaultDisplayDeviceLocked();
}
- layer->updateTransformHint(disp);
+
+ // disp can be null if there is no display available at all to get
+ // the transform hint from.
+ if (disp != nullptr) {
+ layer->updateTransformHint(disp);
+ }
first = false;
});
@@ -2402,6 +2648,9 @@ void SurfaceFlinger::commitTransaction()
mAnimCompositionPending = mAnimTransactionPending;
mDrawingState = mCurrentState;
+ // clear the "changed" flags in current state
+ mCurrentState.colorMatrixChanged = false;
+
mDrawingState.traverseInZOrder([](Layer* layer) {
layer->commitChildList();
});
@@ -2481,7 +2730,7 @@ void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displa
// compute the opaque region
const int32_t layerOrientation = tr.getOrientation();
- if (s.alpha == 1.0f && !translucent &&
+ if (layer->getAlpha() == 1.0f && !translucent &&
((layerOrientation & Transform::ROT_INVALID) == false)) {
// the opaque region is the layer's footprint
opaqueRegion = visibleRegion;
@@ -2489,6 +2738,11 @@ void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displa
}
}
+ if (visibleRegion.isEmpty()) {
+ layer->clearVisibilityRegions();
+ return;
+ }
+
// Clip the covered region to the visible region
coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
@@ -2626,90 +2880,73 @@ void SurfaceFlinger::doDisplayComposition(
}
ALOGV("doDisplayComposition");
-
- Region dirtyRegion(inDirtyRegion);
-
- // compute the invalid region
- displayDevice->swapRegion.orSelf(dirtyRegion);
-
- uint32_t flags = displayDevice->getFlags();
- if (flags & DisplayDevice::SWAP_RECTANGLE) {
- // we can redraw only what's dirty, but since SWAP_RECTANGLE only
- // takes a rectangle, we must make sure to update that whole
- // rectangle in that case
- dirtyRegion.set(displayDevice->swapRegion.bounds());
- } else {
- if (flags & DisplayDevice::PARTIAL_UPDATES) {
- // We need to redraw the rectangle that will be updated
- // (pushed to the framebuffer).
- // This is needed because PARTIAL_UPDATES only takes one
- // rectangle instead of a region (see DisplayDevice::flip())
- dirtyRegion.set(displayDevice->swapRegion.bounds());
- } else {
- // we need to redraw everything (the whole screen)
- dirtyRegion.set(displayDevice->bounds());
- displayDevice->swapRegion = dirtyRegion;
- }
- }
-
- if (!doComposeSurfaces(displayDevice, dirtyRegion)) return;
-
- // update the swap region and clear the dirty region
- displayDevice->swapRegion.orSelf(dirtyRegion);
+ if (!doComposeSurfaces(displayDevice)) return;
// swap buffers (presentation)
displayDevice->swapBuffers(getHwComposer());
}
-bool SurfaceFlinger::doComposeSurfaces(
- const sp<const DisplayDevice>& displayDevice, const Region& dirty)
+bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDevice)
{
ALOGV("doComposeSurfaces");
+ const Region bounds(displayDevice->bounds());
+ const DisplayRenderArea renderArea(displayDevice);
const auto hwcId = displayDevice->getHwcDisplayId();
+ const bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
+ ATRACE_INT("hasClientComposition", hasClientComposition);
- mat4 oldColorMatrix;
- const bool applyColorMatrix = !mHwc->hasDeviceComposition(hwcId) &&
- !mHwc->hasCapability(HWC2::Capability::SkipClientColorTransform);
- if (applyColorMatrix) {
- mat4 colorMatrix = mColorMatrix * mDaltonizer();
- oldColorMatrix = getRenderEngine().setupColorTransform(colorMatrix);
- }
+ bool applyColorMatrix = false;
+ bool needsLegacyColorMatrix = false;
+ bool legacyColorMatrixApplied = false;
- bool hasClientComposition = mHwc->hasClientComposition(hwcId);
if (hasClientComposition) {
ALOGV("hasClientComposition");
-#ifdef USE_HWC2
- mRenderEngine->setWideColor(displayDevice->getWideColorSupport());
- mRenderEngine->setColorMode(displayDevice->getActiveColorMode());
-#endif
- if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) {
+ 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);
+
+ applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
+ if (applyColorMatrix) {
+ getRenderEngine().setupColorTransform(mDrawingState.colorMatrix);
+ }
+
+ needsLegacyColorMatrix =
+ (displayDevice->getActiveRenderIntent() >= RenderIntent::ENHANCE &&
+ outputDataspace != Dataspace::UNKNOWN &&
+ outputDataspace != Dataspace::SRGB);
+
+ if (!displayDevice->makeCurrent()) {
ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
displayDevice->getDisplayName().string());
- eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ getRenderEngine().resetCurrentSurface();
// |mStateLock| not needed as we are on the main thread
- if(!getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext)) {
+ if(!getDefaultDisplayDeviceLocked()->makeCurrent()) {
ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
}
return false;
}
// Never touch the framebuffer if we don't have any framebuffer layers
- const bool hasDeviceComposition = mHwc->hasDeviceComposition(hwcId);
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.
- mRenderEngine->clearWithColor(0, 0, 0, 0);
+ getBE().mRenderEngine->clearWithColor(0, 0, 0, 0);
} else {
- // we start with the whole screen area
- const Region bounds(displayDevice->getBounds());
-
- // we remove the scissor part
+ // 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()));
@@ -2717,9 +2954,6 @@ bool SurfaceFlinger::doComposeSurfaces(
// compute the area to clear
Region region(displayDevice->undefinedRegion.merge(letterbox));
- // but limit it to the dirty region
- region.andSelf(dirty);
-
// screen is already cleared here
if (!region.isEmpty()) {
// can happen with SurfaceView
@@ -2740,7 +2974,7 @@ bool SurfaceFlinger::doComposeSurfaces(
// enable scissor for this frame
const uint32_t height = displayDevice->getHeight();
- mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
+ getBE().mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
scissor.getWidth(), scissor.getHeight());
}
}
@@ -2752,66 +2986,68 @@ bool SurfaceFlinger::doComposeSurfaces(
ALOGV("Rendering client layers");
const Transform& displayTransform = displayDevice->getTransform();
- if (hwcId >= 0) {
- // we're using h/w composer
- bool firstLayer = true;
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- const Region clip(dirty.intersect(
- displayTransform.transform(layer->visibleRegion)));
- ALOGV("Layer: %s", layer->getName().string());
- ALOGV(" Composition type: %s",
- to_string(layer->getCompositionType(hwcId)).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: {
- const Layer::State& state(layer->getDrawingState());
- if (layer->getClearClientTarget(hwcId) && !firstLayer &&
- layer->isOpaque(state) && (state.alpha == 1.0f)
- && hasClientComposition) {
- // never clear the very first layer since we're
- // guaranteed the FB is already cleared
- layer->clearWithOpenGL(displayDevice);
- }
- break;
+ bool firstLayer = true;
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ const Region clip(bounds.intersect(
+ displayTransform.transform(layer->visibleRegion)));
+ ALOGV("Layer: %s", layer->getName().string());
+ ALOGV(" Composition type: %s",
+ to_string(layer->getCompositionType(hwcId)).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: {
+ const Layer::State& state(layer->getDrawingState());
+ if (layer->getClearClientTarget(hwcId) && !firstLayer &&
+ layer->isOpaque(state) && (state.color.a == 1.0f)
+ && hasClientComposition) {
+ // never clear the very first layer since we're
+ // guaranteed the FB is already cleared
+ layer->clearWithOpenGL(renderArea);
}
- case HWC2::Composition::Client: {
- layer->draw(displayDevice, clip);
- break;
+ break;
+ }
+ case HWC2::Composition::Client: {
+ // switch color matrices lazily
+ if (layer->isLegacyDataSpace() && needsLegacyColorMatrix) {
+ if (!legacyColorMatrixApplied) {
+ getRenderEngine().setSaturationMatrix(mLegacySrgbSaturationMatrix);
+ legacyColorMatrixApplied = true;
+ }
+ } else if (legacyColorMatrixApplied) {
+ getRenderEngine().setSaturationMatrix(mat4());
+ legacyColorMatrixApplied = false;
}
- default:
- break;
+
+ layer->draw(renderArea, clip);
+ break;
}
- } else {
- ALOGV(" Skipping for empty clip");
- }
- firstLayer = false;
- }
- } else {
- // we're not using h/w composer
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- const Region clip(dirty.intersect(
- displayTransform.transform(layer->visibleRegion)));
- if (!clip.isEmpty()) {
- layer->draw(displayDevice, clip);
+ default:
+ break;
}
+ } else {
+ ALOGV(" Skipping for empty clip");
}
+ firstLayer = false;
}
if (applyColorMatrix) {
- getRenderEngine().setupColorTransform(oldColorMatrix);
+ getRenderEngine().setupColorTransform(mat4());
+ }
+ if (needsLegacyColorMatrix && legacyColorMatrixApplied) {
+ getRenderEngine().setSaturationMatrix(mat4());
}
// disable scissor at the end of the frame
- mRenderEngine->disableScissor();
+ getBE().mRenderEngine->disableScissor();
return true;
}
void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const {
const int32_t height = displayDevice->getHeight();
- RenderEngine& engine(getRenderEngine());
+ auto& engine(getRenderEngine());
engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
}
@@ -2832,14 +3068,21 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
if (parent == nullptr) {
mCurrentState.layersSortedByZ.add(lbc);
} else {
- if (mCurrentState.layersSortedByZ.indexOf(parent) < 0) {
+ if (parent->isPendingRemoval()) {
ALOGE("addClientLayer called with a removed parent");
return NAME_NOT_FOUND;
}
parent->addChild(lbc);
}
- mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+ if (gbc != nullptr) {
+ mGraphicBufferProducerList.insert(IInterface::asBinder(gbc).get());
+ LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() >
+ mMaxGraphicBufferProducerListSize,
+ "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
+ mGraphicBufferProducerList.size(),
+ mMaxGraphicBufferProducerListSize, mNumLayers);
+ }
mLayersAdded = true;
mNumLayers++;
}
@@ -2852,6 +3095,14 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
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;
@@ -2905,15 +3156,43 @@ uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
+ return setTransactionFlags(flags, VSyncModulator::TransactionStart::NORMAL);
+}
+
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
+ VSyncModulator::TransactionStart transactionStart) {
uint32_t old = android_atomic_or(flags, &mTransactionFlags);
+ mVsyncModulator.setTransactionStart(transactionStart);
if ((old & flags)==0) { // wake the server up
signalTransaction();
}
return old;
}
+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
+ // one of our own. A malicious client could give us a nullptr
+ // IInterface, or one of its own or even one of our own but a
+ // different type. All these situations would cause us to crash.
+ if (state.client == nullptr) {
+ return true;
+ }
+
+ sp<IBinder> binder = IInterface::asBinder(state.client);
+ if (binder == nullptr) {
+ return true;
+ }
+
+ if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) == nullptr) {
+ return true;
+ }
+ }
+ return false;
+}
+
void SurfaceFlinger::setTransactionState(
- const Vector<ComposerState>& state,
+ const Vector<ComposerState>& states,
const Vector<DisplayState>& displays,
uint32_t flags)
{
@@ -2921,6 +3200,10 @@ void SurfaceFlinger::setTransactionState(
Mutex::Autolock _l(mStateLock);
uint32_t transactionFlags = 0;
+ if (containsAnyInvalidClientState(states)) {
+ return;
+ }
+
if (flags & eAnimation) {
// For window updates that are part of an animation we must wait for
// previous animation "frames" to be handled.
@@ -2937,31 +3220,20 @@ void SurfaceFlinger::setTransactionState(
}
}
- size_t count = displays.size();
- for (size_t i=0 ; i<count ; i++) {
- const DisplayState& s(displays[i]);
- transactionFlags |= setDisplayStateLocked(s);
+ for (const DisplayState& display : displays) {
+ transactionFlags |= setDisplayStateLocked(display);
}
- count = state.size();
- for (size_t i=0 ; i<count ; i++) {
- const ComposerState& s(state[i]);
- // Here we need to check that the interface we're given is indeed
- // one of our own. A malicious client could give us a NULL
- // IInterface, or one of its own or even one of our own but a
- // different type. All these situations would cause us to crash.
- //
- // NOTE: it would be better to use RTTI as we could directly check
- // that we have a Client*. however, RTTI is disabled in Android.
- if (s.client != NULL) {
- sp<IBinder> binder = IInterface::asBinder(s.client);
- if (binder != NULL) {
- if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) != NULL) {
- sp<Client> client( static_cast<Client *>(s.client.get()) );
- transactionFlags |= setClientStateLocked(client, s.state);
- }
- }
- }
+ for (const ComposerState& state : states) {
+ transactionFlags |= setClientStateLocked(state);
+ }
+
+ // 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).
+ for (const ComposerState& state : states) {
+ setDestroyStateLocked(state);
}
// If a synchronous transaction is explicitly requested without any changes, force a transaction
@@ -2974,12 +3246,15 @@ void SurfaceFlinger::setTransactionState(
}
if (transactionFlags) {
- if (mInterceptor.isEnabled()) {
- mInterceptor.saveTransaction(state, mCurrentState.displays, displays, flags);
+ if (mInterceptor->isEnabled()) {
+ mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags);
}
// this triggers the transaction
- setTransactionFlags(transactionFlags);
+ const auto start = (flags & eEarlyWakeup)
+ ? VSyncModulator::TransactionStart::EARLY
+ : VSyncModulator::TransactionStart::NORMAL;
+ setTransactionFlags(transactionFlags, start);
// if this is a synchronous transaction, wait for it to take effect
// before returning.
@@ -3052,134 +3327,191 @@ uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
return flags;
}
-uint32_t SurfaceFlinger::setClientStateLocked(
- const sp<Client>& client,
- const layer_state_t& s)
-{
- uint32_t flags = 0;
+uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState) {
+ const layer_state_t& s = composerState.state;
+ sp<Client> client(static_cast<Client*>(composerState.client.get()));
+
sp<Layer> layer(client->getLayerUser(s.surface));
- if (layer != 0) {
- const uint32_t what = s.what;
- bool geometryAppliesWithResize =
- what & layer_state_t::eGeometryAppliesWithResize;
- if (what & layer_state_t::ePositionChanged) {
- if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) {
- flags |= eTraversalNeeded;
- }
- }
- if (what & layer_state_t::eLayerChanged) {
- // NOTE: index needs to be calculated before we update the state
- const auto& p = layer->getParent();
- if (p == nullptr) {
- ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
- if (layer->setLayer(s.z) && idx >= 0) {
- mCurrentState.layersSortedByZ.removeAt(idx);
- mCurrentState.layersSortedByZ.add(layer);
- // we need traversal (state changed)
- // AND transaction (list changed)
- flags |= eTransactionNeeded|eTraversalNeeded;
- }
- } else {
- if (p->setChildLayer(layer, s.z)) {
- flags |= eTransactionNeeded|eTraversalNeeded;
- }
- }
+ if (layer == nullptr) {
+ 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;
+ 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) {
+ layer->pushPendingState();
+ }
+
+ if (what & layer_state_t::ePositionChanged) {
+ if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) {
+ flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eRelativeLayerChanged) {
+ }
+ if (what & layer_state_t::eLayerChanged) {
+ // NOTE: index needs to be calculated before we update the state
+ const auto& p = layer->getParent();
+ if (p == nullptr) {
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
- if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) {
+ if (layer->setLayer(s.z) && idx >= 0) {
mCurrentState.layersSortedByZ.removeAt(idx);
mCurrentState.layersSortedByZ.add(layer);
+ // we need traversal (state changed)
+ // AND transaction (list changed)
flags |= eTransactionNeeded|eTraversalNeeded;
}
- }
- if (what & layer_state_t::eSizeChanged) {
- if (layer->setSize(s.w, s.h)) {
- flags |= eTraversalNeeded;
+ } else {
+ if (p->setChildLayer(layer, s.z)) {
+ flags |= eTransactionNeeded|eTraversalNeeded;
}
}
- if (what & layer_state_t::eAlphaChanged) {
- if (layer->setAlpha(s.alpha))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eMatrixChanged) {
- if (layer->setMatrix(s.matrix))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eTransparentRegionChanged) {
- if (layer->setTransparentRegionHint(s.transparentRegion))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eFlagsChanged) {
- if (layer->setFlags(s.flags, s.mask))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eCropChanged) {
- if (layer->setCrop(s.crop, !geometryAppliesWithResize))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eFinalCropChanged) {
- if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eLayerStackChanged) {
+ }
+ if (what & layer_state_t::eRelativeLayerChanged) {
+ // NOTE: index needs to be calculated before we update the state
+ const auto& p = layer->getParent();
+ if (p == nullptr) {
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
- // We only allow setting layer stacks for top level layers,
- // everything else inherits layer stack from its parent.
- if (layer->hasParent()) {
- ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid",
- layer->getName().string());
- } else if (idx < 0) {
- ALOGE("Attempt to set layer stack on layer without parent (%s) that "
- "that also does not appear in the top level layer list. Something"
- " has gone wrong.", layer->getName().string());
- } else if (layer->setLayerStack(s.layerStack)) {
+ if (layer->setRelativeLayer(s.relativeLayerHandle, s.z) && idx >= 0) {
mCurrentState.layersSortedByZ.removeAt(idx);
mCurrentState.layersSortedByZ.add(layer);
// we need traversal (state changed)
// AND transaction (list changed)
flags |= eTransactionNeeded|eTraversalNeeded;
}
- }
- 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 (authenticateSurfaceTextureLocked(gbp)) {
- const auto& otherLayer =
- (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
- layer->deferTransactionUntil(otherLayer, s.frameNumber);
- } else {
- ALOGE("Attempt to defer transaction to to an"
- " unrecognized GraphicBufferProducer");
- }
+ } else {
+ if (p->setChildRelativeLayer(layer, s.relativeLayerHandle, s.z)) {
+ flags |= eTransactionNeeded|eTraversalNeeded;
}
- // 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::eReparentChildren) {
- if (layer->reparentChildren(s.reparentHandle)) {
- flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ if (what & layer_state_t::eSizeChanged) {
+ if (layer->setSize(s.w, s.h)) {
+ flags |= eTraversalNeeded;
+ }
+ }
+ if (what & layer_state_t::eAlphaChanged) {
+ if (layer->setAlpha(s.alpha))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eColorChanged) {
+ if (layer->setColor(s.color))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eMatrixChanged) {
+ if (layer->setMatrix(s.matrix))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eTransparentRegionChanged) {
+ if (layer->setTransparentRegionHint(s.transparentRegion))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eFlagsChanged) {
+ if (layer->setFlags(s.flags, s.mask))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eCropChanged) {
+ if (layer->setCrop(s.crop, !geometryAppliesWithResize))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eFinalCropChanged) {
+ if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eLayerStackChanged) {
+ ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+ // We only allow setting layer stacks for top level layers,
+ // everything else inherits layer stack from its parent.
+ if (layer->hasParent()) {
+ ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid",
+ layer->getName().string());
+ } else if (idx < 0) {
+ ALOGE("Attempt to set layer stack on layer without parent (%s) that "
+ "that also does not appear in the top level layer list. Something"
+ " has gone wrong.", layer->getName().string());
+ } else if (layer->setLayerStack(s.layerStack)) {
+ mCurrentState.layersSortedByZ.removeAt(idx);
+ mCurrentState.layersSortedByZ.add(layer);
+ // we need traversal (state changed)
+ // AND transaction (list changed)
+ 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 (authenticateSurfaceTextureLocked(gbp)) {
+ const auto& otherLayer =
+ (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
+ layer->deferTransactionUntil(otherLayer, s.frameNumber);
+ } else {
+ ALOGE("Attempt to defer transaction to to an"
+ " unrecognized GraphicBufferProducer");
}
}
- if (what & layer_state_t::eDetachChildren) {
- layer->detachChildren();
+ // 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::eReparent) {
+ bool hadParent = layer->hasParent();
+ if (layer->reparent(s.parentHandleForChild)) {
+ if (!hadParent) {
+ mCurrentState.layersSortedByZ.remove(layer);
+ }
+ flags |= eTransactionNeeded|eTraversalNeeded;
}
- if (what & layer_state_t::eOverrideScalingModeChanged) {
- layer->setOverrideScalingMode(s.overrideScalingMode);
- // 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::eReparentChildren) {
+ if (layer->reparentChildren(s.reparentHandle)) {
+ flags |= eTransactionNeeded|eTraversalNeeded;
}
}
+ if (what & layer_state_t::eDetachChildren) {
+ layer->detachChildren();
+ }
+ if (what & layer_state_t::eOverrideScalingModeChanged) {
+ layer->setOverrideScalingMode(s.overrideScalingMode);
+ // We don't trigger a traversal here because if no other state is
+ // changed, we don't want this to cause any more work
+ }
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;
+ }
+
+ if (layer->isPendingRemoval()) {
+ ALOGW("Attempting to destroy on removed layer: %s", layer->getName().string());
+ return;
+ }
+
+ if (state.what & layer_state_t::eDestroySurface) {
+ removeLayerLocked(mStateLock, layer);
+ }
+}
+
status_t SurfaceFlinger::createLayer(
const String8& name,
const sp<Client>& client,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- uint32_t windowType, uint32_t ownerUid, sp<IBinder>* handle,
+ int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent)
{
if (int32_t(w|h) < 0) {
@@ -3196,14 +3528,15 @@ status_t SurfaceFlinger::createLayer(
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal:
- result = createNormalLayer(client,
+ result = createBufferLayer(client,
uniqueName, w, h, flags, format,
handle, gbp, &layer);
+
break;
- case ISurfaceComposerClient::eFXSurfaceDim:
- result = createDimLayer(client,
+ case ISurfaceComposerClient::eFXSurfaceColor:
+ result = createColorLayer(client,
uniqueName, w, h, flags,
- handle, gbp, &layer);
+ handle, &layer);
break;
default:
result = BAD_VALUE;
@@ -3227,7 +3560,7 @@ status_t SurfaceFlinger::createLayer(
if (result != NO_ERROR) {
return result;
}
- mInterceptor.saveSurfaceCreation(layer);
+ mInterceptor->saveSurfaceCreation(layer);
setTransactionFlags(eTransactionNeeded);
return result;
@@ -3257,7 +3590,7 @@ String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
return uniqueName;
}
-status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
+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)
{
@@ -3272,24 +3605,24 @@ status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
break;
}
- *outLayer = new Layer(this, client, name, w, h, flags);
- status_t err = (*outLayer)->setBuffers(w, h, format, flags);
+ sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
+ status_t err = layer->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
- *handle = (*outLayer)->getHandle();
- *gbp = (*outLayer)->getProducer();
+ *handle = layer->getHandle();
+ *gbp = layer->getProducer();
+ *outLayer = layer;
}
- ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
+ ALOGE_IF(err, "createBufferLayer() failed (%s)", strerror(-err));
return err;
}
-status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags,
- sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
+ sp<IBinder>* handle, sp<Layer>* outLayer)
{
- *outLayer = new LayerDim(this, client, name, w, h, flags);
+ *outLayer = new ColorLayer(this, client, name, w, h, flags);
*handle = (*outLayer)->getHandle();
- *gbp = (*outLayer)->getProducer();
return NO_ERROR;
}
@@ -3298,8 +3631,8 @@ status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBind
// called by a client when it wants to remove a Layer
status_t err = NO_ERROR;
sp<Layer> l(client->getLayerUser(handle));
- if (l != NULL) {
- mInterceptor.saveSurfaceDeletion(l);
+ 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));
@@ -3341,7 +3674,7 @@ void SurfaceFlinger::onInitializeDisplays() {
setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL,
/*stateLockHeld*/ false);
- const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
@@ -3381,14 +3714,14 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
return;
}
- if (mInterceptor.isEnabled()) {
+ 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(mCurrentState.displays.valueAt(idx).displayId, mode);
}
if (currentMode == HWC_POWER_MODE_OFF) {
@@ -3403,7 +3736,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
mVisibleRegionsDirty = true;
mHasPoweredOff = true;
- repaintEverythingLocked();
+ repaintEverything();
struct sched_param param = {0};
param.sched_priority = 1;
@@ -3417,7 +3750,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
ALOGW("Couldn't set SCHED_OTHER on display off");
}
- if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ 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
@@ -3431,7 +3765,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
mode == HWC_POWER_MODE_NORMAL) {
// Update display while dozing
getHwComposer().setPowerMode(type, mode);
- if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ 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);
@@ -3448,6 +3783,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
ALOGE("Attempting to set unknown power mode: %d\n", mode);
getHwComposer().setPowerMode(type, mode);
}
+ ALOGD("Finished set power mode=%d, type=%d", mode, hw->getDisplayType());
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
@@ -3461,7 +3797,7 @@ void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
mDisplay(disp) { mMode = mode; }
virtual bool handler() {
sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
- if (hw == NULL) {
+ if (hw == nullptr) {
ALOGE("Attempt to set power mode = %d for null display %p",
mMode, mDisplay.get());
} else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
@@ -3480,13 +3816,14 @@ void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
// ---------------------------------------------------------------------------
-status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
-{
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto)
+ NO_THREAD_SAFETY_ANALYSIS {
String8 result;
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
+
if ((uid != AID_SHELL) &&
!PermissionCache::checkPermission(sDump, pid, uid)) {
result.appendFormat("Permission Denial: "
@@ -3506,6 +3843,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
bool dumpAll = true;
size_t index = 0;
size_t numArgs = args.size();
+
if (numArgs) {
if ((index < numArgs) &&
(args[index] == String16("--list"))) {
@@ -3554,10 +3892,49 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
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;
+ }
+
+ if ((index < numArgs) && (args[index] == String16("--timestats"))) {
+ index++;
+ mTimeStats.parseArgs(asProto, args, index, result);
+ dumpAll = false;
+ }
}
if (dumpAll) {
- dumpAllLocked(args, index, result);
+ if (asProto) {
+ LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
+ result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
+ } else {
+ dumpAllLocked(args, index, result);
+ }
}
if (locked) {
@@ -3585,7 +3962,7 @@ void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index
index++;
}
- const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
const nsecs_t period = activeConfig->getVsyncPeriod();
result.appendFormat("%" PRId64 "\n", period);
@@ -3631,7 +4008,6 @@ void SurfaceFlinger::logFrameStats() {
void SurfaceFlinger::appendSfConfigString(String8& result) const
{
result.append(" [sf");
- result.appendFormat(" HAS_CONTEXT_PRIORITY=%d", useContextPriority);
if (isLayerTripleBufferingDisabled())
result.append(" DISABLE_TRIPLE_BUFFERING");
@@ -3648,24 +4024,24 @@ void SurfaceFlinger::appendSfConfigString(String8& result) const
void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
{
result.appendFormat("Static screen stats:\n");
- for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
- float bucketTimeSec = mFrameBuckets[b] / 1e9;
+ for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) {
+ float bucketTimeSec = getBE().mFrameBuckets[b] / 1e9;
float percent = 100.0f *
- static_cast<float>(mFrameBuckets[b]) / mTotalTime;
+ static_cast<float>(getBE().mFrameBuckets[b]) / getBE().mTotalTime;
result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n",
b + 1, bucketTimeSec, percent);
}
- float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
+ float bucketTimeSec = getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] / 1e9;
float percent = 100.0f *
- static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
+ static_cast<float>(getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1]) / getBE().mTotalTime;
result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n",
- NUM_BUCKETS - 1, bucketTimeSec, percent);
+ SurfaceFlingerBE::NUM_BUCKETS - 1, bucketTimeSec, percent);
}
void SurfaceFlinger::recordBufferingStats(const char* layerName,
std::vector<OccupancyTracker::Segment>&& history) {
- Mutex::Autolock lock(mBufferingStatsMutex);
- auto& stats = mBufferingStats[layerName];
+ Mutex::Autolock lock(getBE().mBufferingStatsMutex);
+ auto& stats = getBE().mBufferingStats[layerName];
for (const auto& segment : history) {
if (!segment.usedThirdBuffer) {
stats.twoBufferTime += segment.totalTime;
@@ -3694,12 +4070,12 @@ void SurfaceFlinger::dumpBufferingStats(String8& result) const {
result.append("Buffering stats:\n");
result.append(" [Layer name] <Active time> <Two buffer> "
"<Double buffered> <Triple buffered>\n");
- Mutex::Autolock lock(mBufferingStatsMutex);
+ Mutex::Autolock lock(getBE().mBufferingStatsMutex);
typedef std::tuple<std::string, float, float, float> BufferTuple;
std::map<float, BufferTuple, std::greater<float>> sorted;
- for (const auto& statsPair : mBufferingStats) {
+ for (const auto& statsPair : getBE().mBufferingStats) {
const char* name = statsPair.first.c_str();
- const BufferingStats& stats = statsPair.second;
+ const SurfaceFlingerBE::BufferingStats& stats = statsPair.second;
if (stats.numSegments == 0) {
continue;
}
@@ -3726,6 +4102,8 @@ void SurfaceFlinger::dumpBufferingStats(String8& result) const {
void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
+ result.appendFormat("DisplayColorSetting: %s\n",
+ decodeDisplayColorSetting(mDisplayColorSetting).c_str());
// TODO: print out if wide-color mode is active or not
@@ -3737,18 +4115,53 @@ void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
}
result.appendFormat("Display %d color modes:\n", hwcId);
- std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(hwcId);
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
for (auto&& mode : modes) {
result.appendFormat(" %s (%d)\n", decodeColorMode(mode).c_str(), mode);
}
- android_color_mode_t currentMode = displayDevice->getActiveColorMode();
+ ColorMode currentMode = displayDevice->getActiveColorMode();
result.appendFormat(" Current color mode: %s (%d)\n",
decodeColorMode(currentMode).c_str(), currentMode);
}
result.append("\n");
}
+LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet) 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);
+ });
+
+ return layersProto;
+}
+
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) 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()));
+
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(hwcId)) {
+ LayerProto* layerProto = layersProto.add_layers();
+ layer->writeToProto(layerProto, hwcId);
+ }
+ });
+
+ return layersProto;
+}
+
void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
String8& result) const
{
@@ -3789,14 +4202,14 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
result.append(SyncFeatures::getInstance().toString());
result.append("\n");
- const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
colorizer.bold(result);
result.append("DispSync configuration: ");
colorizer.reset(result);
- result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
- "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
- vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
+ result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, early sf phase %" PRId64
+ " ns, present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+ vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, mVsyncModulator.getEarlyPhaseOffset(),
dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
result.append("\n");
@@ -3812,10 +4225,14 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
*/
colorizer.bold(result);
result.appendFormat("Visible layers (count = %zu)\n", mNumLayers);
+ result.appendFormat("GraphicBufferProducers: %zu, max %zu\n",
+ mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize);
colorizer.reset(result);
- mCurrentState.traverseInZOrder([&](Layer* layer) {
- result.append(to_string(layer->getLayerDebugInfo()).c_str());
- });
+
+ LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
+ auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+ result.append(LayerProtoParser::layersToString(std::move(layerTree)).c_str());
+ result.append("\n");
/*
* Dump Display state
@@ -3828,6 +4245,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
const sp<const DisplayDevice>& hw(mDisplays[dpy]);
hw->dump(result);
}
+ result.append("\n");
/*
* Dump SurfaceFlinger global state
@@ -3840,18 +4258,13 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
HWComposer& hwc(getHwComposer());
sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
- colorizer.bold(result);
- result.appendFormat("EGL implementation : %s\n",
- eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
- colorizer.reset(result);
- result.appendFormat("%s\n",
- eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
-
- mRenderEngine->dump(result);
+ getBE().mRenderEngine->dump(result);
- hw->undefinedRegion.dump(result, "undefinedRegion");
- result.appendFormat(" orientation=%d, isDisplayOn=%d\n",
- hw->getOrientation(), hw->isDisplayOn());
+ 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"
@@ -3936,7 +4349,7 @@ SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) {
break;
}
}
- if (dpy == NULL) {
+ 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);
@@ -3962,6 +4375,30 @@ bool SurfaceFlinger::startDdmConnection()
return true;
}
+void SurfaceFlinger::updateColorMatrixLocked() {
+ mat4 colorMatrix;
+ if (mGlobalSaturationFactor != 1.0f) {
+ // Rec.709 luma coefficients
+ float3 luminance{0.213f, 0.715f, 0.072f};
+ luminance *= 1.0f - mGlobalSaturationFactor;
+ mat4 saturationMatrix = mat4(
+ vec4{luminance.r + mGlobalSaturationFactor, luminance.r, luminance.r, 0.0f},
+ vec4{luminance.g, luminance.g + mGlobalSaturationFactor, luminance.g, 0.0f},
+ vec4{luminance.b, luminance.b, luminance.b + mGlobalSaturationFactor, 0.0f},
+ vec4{0.0f, 0.0f, 0.0f, 1.0f}
+ );
+ colorMatrix = mClientColorMatrix * saturationMatrix * mDaltonizer();
+ } else {
+ colorMatrix = mClientColorMatrix * mDaltonizer();
+ }
+
+ if (mCurrentState.colorMatrix != colorMatrix) {
+ mCurrentState.colorMatrix = colorMatrix;
+ mCurrentState.colorMatrixChanged = true;
+ setTransactionFlags(eTransactionNeeded);
+ }
+}
+
status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
switch (code) {
case CREATE_CONNECTION:
@@ -3971,6 +4408,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
case GET_ANIMATION_FRAME_STATS:
case SET_POWER_MODE:
case GET_HDR_CAPABILITIES:
+ case ENABLE_VSYNC_INJECTIONS:
+ case INJECT_VSYNC:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
@@ -4007,6 +4446,17 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
}
break;
}
+ case CAPTURE_LAYERS: {
+ 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;
+ }
+ break;
+ }
}
return OK;
}
@@ -4083,6 +4533,7 @@ status_t SurfaceFlinger::onTransact(
return NO_ERROR;
}
case 1014: {
+ Mutex::Autolock _l(mStateLock);
// daltonize
n = data.readInt32();
switch (n % 10) {
@@ -4104,33 +4555,33 @@ status_t SurfaceFlinger::onTransact(
} else {
mDaltonizer.setMode(ColorBlindnessMode::Simulation);
}
- invalidateHwcGeometry();
- repaintEverything();
+
+ updateColorMatrixLocked();
return NO_ERROR;
}
case 1015: {
+ Mutex::Autolock _l(mStateLock);
// apply a color matrix
n = data.readInt32();
if (n) {
// color matrix is sent as a column-major mat4 matrix
for (size_t i = 0 ; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
- mColorMatrix[i][j] = data.readFloat();
+ mClientColorMatrix[i][j] = data.readFloat();
}
}
} else {
- mColorMatrix = mat4();
+ mClientColorMatrix = mat4();
}
// Check that supplied matrix's last row is {0,0,0,1} so we can avoid
// the division by w in the fragment shader
- float4 lastRow(transpose(mColorMatrix)[3]);
+ float4 lastRow(transpose(mClientColorMatrix)[3]);
if (any(greaterThan(abs(lastRow - float4{0, 0, 0, 1}), float4{1e-4f}))) {
ALOGE("The color transform's last row must be (0, 0, 0, 1)");
}
- invalidateHwcGeometry();
- repaintEverything();
+ updateColorMatrixLocked();
return NO_ERROR;
}
// This is an experimental interface
@@ -4159,11 +4610,11 @@ status_t SurfaceFlinger::onTransact(
n = data.readInt32();
if (n) {
ALOGV("Interceptor enabled");
- mInterceptor.enable(mDrawingState.layersSortedByZ, mDrawingState.displays);
+ mInterceptor->enable(mDrawingState.layersSortedByZ, mDrawingState.displays);
}
else{
ALOGV("Interceptor disabled");
- mInterceptor.disable();
+ mInterceptor->disable();
}
return NO_ERROR;
}
@@ -4173,57 +4624,74 @@ status_t SurfaceFlinger::onTransact(
return NO_ERROR;
}
case 1022: { // Set saturation boost
- mSaturation = std::max(0.0f, std::min(data.readFloat(), 2.0f));
+ Mutex::Autolock _l(mStateLock);
+ mGlobalSaturationFactor = std::max(0.0f, std::min(data.readFloat(), 2.0f));
+ updateColorMatrixLocked();
+ return NO_ERROR;
+ }
+ case 1023: { // Set native mode
+ mDisplayColorSetting = static_cast<DisplayColorSetting>(data.readInt32());
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
}
+ case 1024: { // Is wide color gamut rendering/color management supported?
+ reply->writeBool(hasWideColorDisplay);
+ return NO_ERROR;
+ }
+ case 1025: { // Set layer tracing
+ n = data.readInt32();
+ if (n) {
+ ALOGV("LayerTracing enabled");
+ mTracing.enable();
+ doTracing("tracing.enable");
+ reply->writeInt32(NO_ERROR);
+ } else {
+ ALOGV("LayerTracing disabled");
+ status_t err = mTracing.disable();
+ reply->writeInt32(err);
+ }
+ return NO_ERROR;
+ }
+ case 1026: { // Get layer tracing status
+ reply->writeBool(mTracing.isEnabled());
+ return NO_ERROR;
+ }
+ // Is a DisplayColorSetting supported?
+ case 1027: {
+ sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+ if (!hw) {
+ return NAME_NOT_FOUND;
+ }
+
+ DisplayColorSetting setting = static_cast<DisplayColorSetting>(data.readInt32());
+ switch (setting) {
+ case DisplayColorSetting::MANAGED:
+ reply->writeBool(hasWideColorDisplay);
+ break;
+ case DisplayColorSetting::UNMANAGED:
+ reply->writeBool(true);
+ break;
+ case DisplayColorSetting::ENHANCED:
+ reply->writeBool(hw->hasRenderIntent(RenderIntent::ENHANCE));
+ break;
+ default: // vendor display color setting
+ reply->writeBool(hw->hasRenderIntent(static_cast<RenderIntent>(setting)));
+ break;
+ }
+ return NO_ERROR;
+ }
}
}
return err;
}
-void SurfaceFlinger::repaintEverythingLocked() {
+void SurfaceFlinger::repaintEverything() {
android_atomic_or(1, &mRepaintEverything);
signalTransaction();
}
-void SurfaceFlinger::repaintEverything() {
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
- repaintEverythingLocked();
-}
-
-// Checks that the requested width and height are valid and updates them to the display dimensions
-// if they are set to 0
-static status_t updateDimensionsLocked(const sp<const DisplayDevice>& displayDevice,
- Transform::orientation_flags rotation,
- uint32_t* requestedWidth, uint32_t* requestedHeight) {
- // get screen geometry
- uint32_t displayWidth = displayDevice->getWidth();
- uint32_t displayHeight = displayDevice->getHeight();
-
- if (rotation & Transform::ROT_90) {
- std::swap(displayWidth, displayHeight);
- }
-
- if ((*requestedWidth > displayWidth) || (*requestedHeight > displayHeight)) {
- ALOGE("size mismatch (%d, %d) > (%d, %d)",
- *requestedWidth, *requestedHeight, displayWidth, displayHeight);
- return BAD_VALUE;
- }
-
- if (*requestedWidth == 0) {
- *requestedWidth = displayWidth;
- }
- if (*requestedHeight == 0) {
- *requestedHeight = displayHeight;
- }
-
- return NO_ERROR;
-}
-
// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
class WindowDisconnector {
public:
@@ -4237,111 +4705,152 @@ private:
const int mApi;
};
-static status_t getWindowBuffer(ANativeWindow* window, uint32_t requestedWidth,
- uint32_t requestedHeight, bool hasWideColorDisplay,
- bool renderEngineUsesWideColor, ANativeWindowBuffer** outBuffer) {
- const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
-
- int err = 0;
- err = native_window_set_buffers_dimensions(window, requestedWidth, requestedHeight);
- err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
- err |= native_window_set_usage(window, usage);
+status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ int32_t minLayerZ, int32_t maxLayerZ,
+ bool useIdentityTransform,
+ ISurfaceComposer::Rotation rotation) {
+ ATRACE_CALL();
- if (hasWideColorDisplay) {
- err |= native_window_set_buffers_data_space(window,
- renderEngineUsesWideColor
- ? HAL_DATASPACE_DISPLAY_P3
- : HAL_DATASPACE_V0_SRGB);
- }
+ if (CC_UNLIKELY(display == 0)) return BAD_VALUE;
- if (err != NO_ERROR) {
- return BAD_VALUE;
- }
+ const sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
+ if (CC_UNLIKELY(device == 0)) return BAD_VALUE;
- /* TODO: Once we have the sync framework everywhere this can use
- * server-side waits on the fence that dequeueBuffer returns.
- */
- err = native_window_dequeue_buffer_and_wait(window, outBuffer);
- if (err != NO_ERROR) {
- return err;
- }
+ DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation);
- return NO_ERROR;
+ auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
+ device, minLayerZ, maxLayerZ, std::placeholders::_1);
+ return captureScreenCommon(renderArea, traverseLayers, outBuffer, useIdentityTransform);
}
-status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
- const sp<IGraphicBufferProducer>& producer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
+ sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+ float frameScale, bool childrenOnly) {
ATRACE_CALL();
- if (CC_UNLIKELY(display == 0))
- return BAD_VALUE;
+ class LayerRenderArea : public RenderArea {
+ public:
+ LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
+ int32_t reqWidth, int32_t reqHeight, bool childrenOnly)
+ : RenderArea(reqHeight, reqWidth, CaptureFill::CLEAR),
+ mLayer(layer),
+ mCrop(crop),
+ mFlinger(flinger),
+ mChildrenOnly(childrenOnly) {}
+ const Transform& getTransform() const override { return mTransform; }
+ Rect getBounds() const override {
+ const Layer::State& layerState(mLayer->getDrawingState());
+ return Rect(layerState.active.w, layerState.active.h);
+ }
+ 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 false; }
+ Rect getSourceCrop() const override {
+ if (mCrop.isEmpty()) {
+ return getBounds();
+ } else {
+ return mCrop;
+ }
+ }
+ class ReparentForDrawing {
+ public:
+ const sp<Layer>& oldParent;
+ const sp<Layer>& newParent;
- if (CC_UNLIKELY(producer == 0))
- return BAD_VALUE;
+ ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent)
+ : oldParent(oldParent), newParent(newParent) {
+ oldParent->setChildrenDrawingParent(newParent);
+ }
+ ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
+ };
- // if we have secure windows on this display, never allow the screen capture
- // unless the producer interface is local (i.e.: we can take a screenshot for
- // ourselves).
- bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
+ void render(std::function<void()> drawLayers) override {
+ if (!mChildrenOnly) {
+ mTransform = mLayer->getTransform().inverse();
+ drawLayers();
+ } else {
+ Rect bounds = getBounds();
+ screenshotParentLayer =
+ new ContainerLayer(mFlinger, nullptr, String8("Screenshot Parent"),
+ bounds.getWidth(), bounds.getHeight(), 0);
- // Convert to surfaceflinger's internal rotation type.
- Transform::orientation_flags rotationFlags;
- switch (rotation) {
- case ISurfaceComposer::eRotateNone:
- rotationFlags = Transform::ROT_0;
- break;
- case ISurfaceComposer::eRotate90:
- rotationFlags = Transform::ROT_90;
- break;
- case ISurfaceComposer::eRotate180:
- rotationFlags = Transform::ROT_180;
- break;
- case ISurfaceComposer::eRotate270:
- rotationFlags = Transform::ROT_270;
- break;
- default:
- rotationFlags = Transform::ROT_0;
- ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
- break;
- }
+ ReparentForDrawing reparent(mLayer, screenshotParentLayer);
+ drawLayers();
+ }
+ }
- { // Autolock scope
- Mutex::Autolock lock(mStateLock);
- sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display));
- updateDimensionsLocked(displayDevice, rotationFlags, &reqWidth, &reqHeight);
- }
+ private:
+ const sp<Layer> mLayer;
+ const Rect mCrop;
+
+ // 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;
- // create a surface (because we're a producer, and we need to
- // dequeue/queue a buffer)
- sp<Surface> surface = new Surface(producer, false);
+ SurfaceFlinger* mFlinger;
+ const bool mChildrenOnly;
+ };
- // Put the screenshot Surface into async mode so that
- // Layer::headFenceHasSignaled will always return true and we'll latch the
- // first buffer regardless of whether or not its acquire fence has
- // signaled. This is needed to avoid a race condition in the rotation
- // animation. See b/30209608
- surface->setAsyncMode(true);
+ auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
+ auto parent = layerHandle->owner.promote();
- ANativeWindow* window = surface.get();
+ if (parent == nullptr || parent->isPendingRemoval()) {
+ ALOGE("captureLayers called with a removed parent");
+ return NAME_NOT_FOUND;
+ }
- status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
- if (result != NO_ERROR) {
- return result;
+ 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;
}
- WindowDisconnector disconnector(window, NATIVE_WINDOW_API_EGL);
- ANativeWindowBuffer* buffer = nullptr;
- result = getWindowBuffer(window, reqWidth, reqHeight, hasWideColorDisplay,
- getRenderEngine().usesWideColor(), &buffer);
- if (result != NO_ERROR) {
- return result;
+ Rect crop(sourceCrop);
+ if (sourceCrop.width() <= 0) {
+ crop.left = 0;
+ crop.right = parent->getCurrentState().active.w;
+ }
+
+ if (sourceCrop.height() <= 0) {
+ crop.top = 0;
+ crop.bottom = parent->getCurrentState().active.h;
}
+ int32_t reqWidth = crop.width() * frameScale;
+ int32_t reqHeight = crop.height() * frameScale;
+
+ LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, childrenOnly);
+
+ auto traverseLayers = [parent, childrenOnly](const LayerVector::Visitor& visitor) {
+ parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ if (!layer->isVisible()) {
+ return;
+ } else if (childrenOnly && layer == parent.get()) {
+ return;
+ }
+ visitor(layer);
+ });
+ };
+ return captureScreenCommon(renderArea, traverseLayers, outBuffer, false);
+}
+
+status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers,
+ sp<GraphicBuffer>* outBuffer,
+ bool useIdentityTransform) {
+ ATRACE_CALL();
+
+ renderArea.updateDimensions(mPrimaryDisplayOrientation);
+
+ 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");
+
// This mutex protects syncFd and captureResult for communication of the return values from the
// main thread back to this Binder thread
std::mutex captureMutex;
@@ -4350,6 +4859,9 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
int syncFd = -1;
std::optional<status_t> captureResult;
+ const int uid = IPCThreadState::self()->getCallingUid();
+ const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
+
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.
@@ -4365,10 +4877,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
int fd = -1;
{
Mutex::Autolock _l(mStateLock);
- sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
- result = captureScreenImplLocked(device, buffer, sourceCrop, reqWidth, reqHeight,
- minLayerZ, maxLayerZ, useIdentityTransform,
- rotationFlags, isLocalScreenshot, &fd);
+ renderArea.render([&]() {
+ result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
+ useIdentityTransform, forSystem, &fd);
+ });
}
{
@@ -4379,7 +4891,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
}
});
- result = postMessageAsync(message);
+ status_t result = postMessageAsync(message);
if (result == NO_ERROR) {
captureCondition.wait(captureLock, [&]() { return captureResult; });
while (*captureResult == EAGAIN) {
@@ -4394,153 +4906,154 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
}
if (result == NO_ERROR) {
- // queueBuffer takes ownership of syncFd
- result = window->queueBuffer(window, buffer, syncFd);
+ sync_wait(syncFd, -1);
+ close(syncFd);
}
return result;
}
-
-void SurfaceFlinger::renderScreenImplLocked(
- const sp<const DisplayDevice>& hw,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation)
-{
+void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers, bool yswap,
+ bool useIdentityTransform) {
ATRACE_CALL();
- RenderEngine& engine(getRenderEngine());
+
+ auto& engine(getRenderEngine());
// get screen geometry
- const int32_t hw_w = hw->getWidth();
- const int32_t hw_h = hw->getHeight();
- const bool filtering = static_cast<int32_t>(reqWidth) != hw_w ||
- static_cast<int32_t>(reqHeight) != hw_h;
+ const auto raWidth = renderArea.getWidth();
+ const auto raHeight = renderArea.getHeight();
+
+ const auto reqWidth = renderArea.getReqWidth();
+ const auto reqHeight = renderArea.getReqHeight();
+ Rect sourceCrop = renderArea.getSourceCrop();
+
+ bool filtering = false;
+ if (mPrimaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
+ filtering = static_cast<int32_t>(reqWidth) != raHeight ||
+ static_cast<int32_t>(reqHeight) != raWidth;
+ } else {
+ filtering = static_cast<int32_t>(reqWidth) != raWidth ||
+ static_cast<int32_t>(reqHeight) != raHeight;
+ }
// if a default or invalid sourceCrop is passed in, set reasonable values
- if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
- !sourceCrop.isValid()) {
+ if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || !sourceCrop.isValid()) {
sourceCrop.setLeftTop(Point(0, 0));
- sourceCrop.setRightBottom(Point(hw_w, hw_h));
+ sourceCrop.setRightBottom(Point(raWidth, raHeight));
+ } else if (mPrimaryDisplayOrientation != DisplayState::eOrientationDefault) {
+ Transform tr;
+ uint32_t flags = 0x00;
+ switch (mPrimaryDisplayOrientation) {
+ case DisplayState::eOrientation90:
+ flags = Transform::ROT_90;
+ break;
+ case DisplayState::eOrientation180:
+ flags = Transform::ROT_180;
+ break;
+ case DisplayState::eOrientation270:
+ flags = Transform::ROT_270;
+ break;
+ }
+ tr.set(flags, raWidth, raHeight);
+ sourceCrop = tr.transform(sourceCrop);
}
// ensure that sourceCrop is inside screen
if (sourceCrop.left < 0) {
ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
}
- if (sourceCrop.right > hw_w) {
- ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w);
+ if (sourceCrop.right > raWidth) {
+ ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, raWidth);
}
if (sourceCrop.top < 0) {
ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
}
- if (sourceCrop.bottom > hw_h) {
- ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
+ if (sourceCrop.bottom > raHeight) {
+ ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
}
-#ifdef USE_HWC2
- engine.setWideColor(hw->getWideColorSupport());
- engine.setColorMode(hw->getActiveColorMode());
-#endif
+ // assume ColorMode::SRGB / RenderIntent::COLORIMETRIC
+ engine.setOutputDataSpace(Dataspace::SRGB);
+ engine.setDisplayMaxLuminance(DisplayDevice::sDefaultMaxLumiance);
// make sure to clear all GL error flags
engine.checkErrors();
- // set-up our viewport
- engine.setViewportAndProjection(
- reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation);
- engine.disableTexturing();
-
- // redraw the screen entirely...
- engine.clearWithColor(0, 0, 0, 1);
-
- // 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.
- for (const auto& layer : mDrawingState.layersSortedByZ) {
- if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
- continue;
+ Transform::orientation_flags rotation = renderArea.getRotationFlags();
+ if (mPrimaryDisplayOrientation != DisplayState::eOrientationDefault) {
+ // convert hw orientation into flag presentation
+ // here inverse transform needed
+ uint8_t hw_rot_90 = 0x00;
+ uint8_t hw_flip_hv = 0x00;
+ switch (mPrimaryDisplayOrientation) {
+ case DisplayState::eOrientation90:
+ hw_rot_90 = Transform::ROT_90;
+ hw_flip_hv = Transform::ROT_180;
+ break;
+ case DisplayState::eOrientation180:
+ hw_flip_hv = Transform::ROT_180;
+ break;
+ case DisplayState::eOrientation270:
+ hw_rot_90 = Transform::ROT_90;
+ break;
}
- const Layer::State& state(layer->getDrawingState());
- if (state.z < minLayerZ || state.z > maxLayerZ) {
- continue;
+
+ // transform flags operation
+ // 1) flip H V if both have ROT_90 flag
+ // 2) XOR these flags
+ uint8_t rotation_rot_90 = rotation & Transform::ROT_90;
+ uint8_t rotation_flip_hv = rotation & Transform::ROT_180;
+ if (rotation_rot_90 & hw_rot_90) {
+ rotation_flip_hv = (~rotation_flip_hv) & Transform::ROT_180;
}
- layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- if (!layer->isVisible()) {
- return;
- }
- if (filtering) layer->setFiltering(true);
- layer->draw(hw, useIdentityTransform);
- if (filtering) layer->setFiltering(false);
- });
+ rotation = static_cast<Transform::orientation_flags>
+ ((rotation_rot_90 ^ hw_rot_90) | (rotation_flip_hv ^ hw_flip_hv));
}
- hw->setViewportAndProjection();
-}
-
-// A simple RAII class that holds an EGLImage and destroys it either:
-// a) When the destroy() method is called
-// b) When the object goes out of scope
-class ImageHolder {
-public:
- ImageHolder(EGLDisplay display, EGLImageKHR image) : mDisplay(display), mImage(image) {}
- ~ImageHolder() { destroy(); }
+ // set-up our viewport
+ engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, raHeight, yswap,
+ rotation);
+ engine.disableTexturing();
- void destroy() {
- if (mImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mDisplay, mImage);
- mImage = EGL_NO_IMAGE_KHR;
- }
- }
+ const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
+ // redraw the screen entirely...
+ engine.clearWithColor(0, 0, 0, alpha);
-private:
- const EGLDisplay mDisplay;
- EGLImageKHR mImage;
-};
+ traverseLayers([&](Layer* layer) {
+ if (filtering) layer->setFiltering(true);
+ layer->draw(renderArea, useIdentityTransform);
+ if (filtering) layer->setFiltering(false);
+ });
+}
-status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& hw,
- ANativeWindowBuffer* buffer, Rect sourceCrop,
- uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
+status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers,
+ ANativeWindowBuffer* buffer,
bool useIdentityTransform,
- Transform::orientation_flags rotation,
- bool isLocalScreenshot, int* outSyncFd) {
+ bool forSystem,
+ int* outSyncFd) {
ATRACE_CALL();
bool secureLayerIsVisible = false;
- for (const auto& layer : mDrawingState.layersSortedByZ) {
- const Layer::State& state(layer->getDrawingState());
- if (!layer->belongsToDisplay(hw->getLayerStack(), false) ||
- (state.z < minLayerZ || state.z > maxLayerZ)) {
- continue;
- }
- layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) {
- secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() &&
- layer->isSecure());
- });
- }
- if (!isLocalScreenshot && secureLayerIsVisible) {
+ traverseLayers([&](Layer* layer) {
+ secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && layer->isSecure());
+ });
+
+ // We allow the system server to take screenshots of secure layers for
+ // use in situations like the Screen-rotation animation and place
+ // the impetus on WindowManager to not persist them.
+ if (secureLayerIsVisible && !forSystem) {
ALOGW("FB is protected: PERMISSION_DENIED");
return PERMISSION_DENIED;
}
- int syncFd = -1;
- // create an EGLImage from the buffer so we can later
- // turn it into a texture
- EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
- if (image == EGL_NO_IMAGE_KHR) {
- return BAD_VALUE;
- }
-
- // This will automatically destroy the image if we return before calling its destroy method
- ImageHolder imageHolder(mEGLDisplay, image);
-
// this binds the given EGLImage as a framebuffer for the
// duration of this scope.
- RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
- if (imageBond.getStatus() != NO_ERROR) {
- ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
+ RE::BindNativeBufferAsFramebuffer bufferBond(getRenderEngine(), buffer);
+ if (bufferBond.getStatus() != NO_ERROR) {
+ ALOGE("got ANWB binding error while taking screenshot");
return INVALID_OPERATION;
}
@@ -4548,89 +5061,50 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>&
// 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(
- hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
- useIdentityTransform, rotation);
-
- // Attempt to create a sync khr object that can produce a sync point. If that
- // isn't available, create a non-dupable sync object in the fallback path and
- // wait on it directly.
- EGLSyncKHR sync = EGL_NO_SYNC_KHR;
- if (!DEBUG_SCREENSHOTS) {
- sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
- // native fence fd will not be populated until flush() is done.
- getRenderEngine().flush();
- }
-
- if (sync != EGL_NO_SYNC_KHR) {
- // get the sync fd
- syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
- if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
- ALOGW("captureScreen: failed to dup sync khr object");
- syncFd = -1;
- }
- eglDestroySyncKHR(mEGLDisplay, sync);
- } else {
- // fallback path
- sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
- if (sync != EGL_NO_SYNC_KHR) {
- EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
- EGLint eglErr = eglGetError();
- if (result == EGL_TIMEOUT_EXPIRED_KHR) {
- ALOGW("captureScreen: fence wait timed out");
- } else {
- ALOGW_IF(eglErr != EGL_SUCCESS,
- "captureScreen: error waiting on EGL fence: %#x", eglErr);
- }
- eglDestroySyncKHR(mEGLDisplay, sync);
- } else {
- ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
- }
- }
- *outSyncFd = syncFd;
+ 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,
- hw, minLayerZ, maxLayerZ);
+ checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, traverseLayers);
delete [] pixels;
+ } else {
+ base::unique_fd syncFd = getRenderEngine().flush();
+ if (syncFd < 0) {
+ getRenderEngine().finish();
+ }
+ *outSyncFd = syncFd.release();
}
- // destroy our image
- imageHolder.destroy();
-
return NO_ERROR;
}
void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
- const sp<const DisplayDevice>& hw, int32_t minLayerZ, int32_t maxLayerZ) {
+ 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++) {
+ 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 ***\n"
- "requested minz=%d, maxz=%d, layerStack=%d",
- minLayerZ, maxLayerZ, hw->getLayerStack());
+ ALOGE("*** we just took a black screenshot ***");
size_t i = 0;
- for (const auto& layer : mDrawingState.layersSortedByZ) {
+ traverseLayers([&](Layer* layer) {
const Layer::State& state(layer->getDrawingState());
- if (layer->belongsToDisplay(hw->getLayerStack(), false) && state.z >= minLayerZ &&
- state.z <= maxLayerZ) {
- layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- 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, state.alpha);
- i++;
- });
- }
- }
+ 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++;
+ });
}
}
@@ -4644,6 +5118,32 @@ 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,
+ 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.
+ for (const auto& layer : mDrawingState.layersSortedByZ) {
+ if (!layer->belongsToDisplay(hw->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)) {
+ return;
+ }
+ if (!layer->isVisible()) {
+ return;
+ }
+ visitor(layer);
+ });
+ }
+}
+
}; // namespace android