mLastTransactionTime(0),
mBootFinished(false),
mForceFullDamage(false),
+ mPrimaryDispSync("PrimaryDispSync"),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mDaltonize(false),
class DispSyncSource : public VSyncSource, private DispSync::Callback {
public:
DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
- const char* label) :
+ const char* name) :
+ mName(name),
mValue(0),
mTraceVsync(traceVsync),
- mVsyncOnLabel(String8::format("VsyncOn-%s", label)),
- mVsyncEventLabel(String8::format("VSYNC-%s", label)),
+ mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
+ mVsyncEventLabel(String8::format("VSYNC-%s", name)),
mDispSync(dispSync),
mCallbackMutex(),
mCallback(),
virtual void setVSyncEnabled(bool enable) {
Mutex::Autolock lock(mVsyncMutex);
if (enable) {
- status_t err = mDispSync->addEventListener(mPhaseOffset,
+ status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
static_cast<DispSync::Callback*>(this));
if (err != NO_ERROR) {
ALOGE("error registering vsync callback: %s (%d)",
}
// Add a listener with the new offset
- err = mDispSync->addEventListener(mPhaseOffset,
+ err = mDispSync->addEventListener(mName, mPhaseOffset,
static_cast<DispSync::Callback*>(this));
if (err != NO_ERROR) {
ALOGE("error registering vsync callback: %s (%d)",
}
}
+ const char* const mName;
+
int mValue;
const bool mTraceVsync;
// start the EventThread
sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
vsyncPhaseOffsetNs, true, "app");
- mEventThread = new EventThread(vsyncSrc);
+ mEventThread = new EventThread(vsyncSrc, *this);
sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
sfVsyncPhaseOffsetNs, true, "sf");
- mSFEventThread = new EventThread(sfVsyncSrc);
+ mSFEventThread = new EventThread(sfVsyncSrc, *this);
mEventQueue.setEventThread(mSFEventThread);
// Get a RenderEngine for the given display / config (can't fail)
public:
static int getEmuDensity() {
return getDensityFromProperty("qemu.sf.lcd_density"); }
- static int getBuildDensity() {
- return getDensityFromProperty("ro.sf.lcd_density"); }
+ static int getBuildDensity(const DisplayInfo& info) {
+ static int density = getDensityFromProperty("ro.sf.lcd_density");
+#if defined(__i386__) || defined(__x86_64__)
+ if (density == 0) {
+ uint32_t area = info.w * info.h;
+ if (area <= 800 * 480) {
+ density = 120;
+ } else if (area <= 1024 * 600) {
+ density = 130;
+ } else if (area < 1024 * 768) {
+ density = 140;
+ } else if (area < 1920 * 1080) {
+ density = 160;
+ } else {
+ density = 240;
+ }
+ ALOGI("auto set density to %d", density);
+ }
+#endif
+ return density;
+ }
};
configs->clear();
float xdpi = hwConfig->getDpiX();
float ydpi = hwConfig->getDpiY();
+ info.w = hwConfig->getWidth();
+ info.h = hwConfig->getHeight();
if (type == DisplayDevice::DISPLAY_PRIMARY) {
// The density of the device is provided by a build property
- float density = Density::getBuildDensity() / 160.0f;
+ float density = Density::getBuildDensity(info) / 160.0f;
if (density == 0) {
// the build doesn't provide a density -- this is wrong!
// use xdpi instead
info.orientation = 0;
}
- info.w = hwConfig->getWidth();
- info.h = hwConfig->getHeight();
info.xdpi = xdpi;
info.ydpi = ydpi;
info.fps = 1e9 / hwConfig->getVsyncPeriod();
return NO_ERROR;
}
+status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& display,
+ HdrCapabilities* outCapabilities) const {
+ Mutex::Autolock _l(mStateLock);
+
+ sp<const DisplayDevice> displayDevice(getDisplayDevice(display));
+ if (displayDevice == nullptr) {
+ ALOGE("getHdrCapabilities: Invalid display %p", displayDevice.get());
+ return BAD_VALUE;
+ }
+
+ std::unique_ptr<HdrCapabilities> capabilities =
+ mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
+ if (capabilities) {
+ std::swap(*outCapabilities, *capabilities);
+ } else {
+ return BAD_VALUE;
+ }
+
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
mEventQueue.waitMessage();
}
+#ifdef CONSOLE_MANAGER
+void SurfaceFlinger::screenReleased(const sp<IBinder>& display) {
+ // this may be called by a signal handler, we can't do too much in here
+ setPowerMode(display, HWC_POWER_MODE_OFF);
+ signalLayerUpdate();
+}
+
+void SurfaceFlinger::screenAcquired(const sp<IBinder>& display) {
+ // this may be called by a signal handler, we can't do too much in here
+ setPowerMode(display, HWC_POWER_MODE_NORMAL);
+ signalLayerUpdate();
+}
+#endif
+
void SurfaceFlinger::signalTransaction() {
mEventQueue.invalidate();
}
if (makeAvailable) {
mHWVsyncAvailable = true;
} else if (!mHWVsyncAvailable) {
- ALOGE("resyncToHardwareVsync called when HW vsync unavailable");
+ // Hardware vsync is not currently available, so abort the resync
+ // attempt for now
return;
}
}
}
+void SurfaceFlinger::resyncWithRateLimit() {
+ static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
+ if (systemTime() - mLastSwapTime > kIgnoreDelay) {
+ resyncToHardwareVsync(false);
+ }
+}
+
void SurfaceFlinger::onVSyncReceived(int32_t type, nsecs_t timestamp) {
bool needsHwVsync = false;
void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL();
switch (what) {
- case MessageQueue::TRANSACTION: {
- handleMessageTransaction();
- break;
- }
case MessageQueue::INVALIDATE: {
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
+#ifdef ENABLE_FENCE_TRACKING
nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+#else
+ nsecs_t refreshStartTime = 0;
+#endif
static nsecs_t previousExpectedPresent = 0;
nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
static bool previousFrameMissed = false;
}
}
+#ifdef ENABLE_FENCE_TRACKING
void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
+#else
+void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/)
+#endif
{
ATRACE_CALL();
ALOGV("postComposition");
}
}
+#ifdef ENABLE_FENCE_TRACKING
mFenceTracker.addFrame(refreshStartTime, presentFence,
hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
+#endif
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
if (hwcId >= 0) {
mHwc->commit(hwcId);
}
+ displayDevice->onSwapBuffersCompleted();
if (displayId == 0) {
// Make the default display current because the VirtualDisplayDevice
// code cannot deal with dequeueBuffer() being called outside of the
// is allowed to (and does in some case) call dequeueBuffer().
displayDevice->makeCurrent(mEGLDisplay, mEGLContext);
}
- displayDevice->onSwapBuffersCompleted();
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
sp<Fence> releaseFence = Fence::NO_FENCE;
if (layer->getCompositionType(hwcId) == HWC2::Composition::Client) {
NATIVE_WINDOW_HEIGHT, &height);
ALOGE_IF(status != NO_ERROR,
"Unable to query height (%d)", status);
+ 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);
- mHwc->allocateVirtualDisplay(width, height,
+ mHwc->allocateVirtualDisplay(width, height, &format,
&hwcId);
+ // TODO: Plumb requested format back up to consumer
+
sp<VirtualDisplaySurface> vds =
new VirtualDisplaySurface(*mHwc,
hwcId, state.surface, bqProducer,
// Remove the transparent area from the visible region
if (translucent) {
const Transform tr(s.active.transform);
- if (tr.transformed()) {
- if (tr.preserveRects()) {
- // transform the transparent region
- transparentRegion = tr.transform(s.activeTransparentRegion);
- } else {
- // transformation too complex, can't do the
- // transparent region optimization.
- transparentRegion.clear();
- }
+ if (tr.preserveRects()) {
+ // transform the transparent region
+ transparentRegion = tr.transform(s.activeTransparentRegion);
} else {
- transparentRegion = s.activeTransparentRegion;
+ // transformation too complex, can't do the
+ // transparent region optimization.
+ transparentRegion.clear();
}
}
}
}
+ // If a synchronous transaction is explicitly requested without any changes,
+ // force a transaction anyway. This can be used as a flush mechanism for
+ // previous async transactions.
+ if (transactionFlags == 0 && (flags & eSynchronous)) {
+ transactionFlags = eTransactionNeeded;
+ }
+
if (transactionFlags) {
// this triggers the transaction
setTransactionFlags(transactionFlags);
sp<Layer> layer(client->getLayerUser(s.surface));
if (layer != 0) {
const uint32_t what = s.what;
+ bool positionAppliesWithResize =
+ what & layer_state_t::ePositionAppliesWithResize;
if (what & layer_state_t::ePositionChanged) {
- if (layer->setPosition(s.x, s.y))
+ if (layer->setPosition(s.x, s.y, !positionAppliesWithResize)) {
flags |= eTraversalNeeded;
+ }
}
if (what & layer_state_t::eLayerChanged) {
// NOTE: index needs to be calculated before we update the state
// 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::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;
}
dumpAll = false;
}
+#ifdef ENABLE_FENCE_TRACKING
if ((index < numArgs) &&
(args[index] == String16("--fences"))) {
index++;
mFenceTracker.dump(&result);
dumpAll = false;
}
+#endif
}
if (dumpAll) {
case CLEAR_ANIMATION_FRAME_STATS:
case GET_ANIMATION_FRAME_STATS:
case SET_POWER_MODE:
+ case GET_HDR_CAPABILITIES:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
}
};
- // make sure to process transactions before screenshots -- a transaction
- // might already be pending but scheduled for VSYNC; this guarantees we
- // will handle it before the screenshot. When VSYNC finally arrives
- // the scheduled transaction will be a no-op. If no transactions are
- // scheduled at this time, this will end-up being a no-op as well.
- mEventQueue.invalidateTransactionNow();
-
// this creates a "fake" BBinder which will serve as a "fake" remote
// binder to receive the marshaled calls and forward them to the
// real remote (a BpGraphicBufferProducer)