* limitations under the License.
*/
+// #define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <stdint.h>
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/StopWatch.h>
+#include <utils/Timers.h>
#include <utils/Trace.h>
#include <private/android_filesystem_config.h>
mRepaintEverything(0),
mRenderEngine(NULL),
mBootTime(systemTime()),
+ mBuiltinDisplays(),
mVisibleRegionsDirty(false),
- mHwWorkListDirty(false),
+ mGeometryInvalid(false),
mAnimCompositionPending(false),
mDebugRegion(0),
mDebugDDMS(0),
mLastTransactionTime(0),
mBootFinished(false),
mForceFullDamage(false),
+ mPrimaryDispSync("PrimaryDispSync"),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mDaltonize(false),
property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
mGpuToCpuSupported = !atoi(value);
+ property_get("debug.sf.drop_missed_frames", value, "0");
+ mDropMissedFrames = atoi(value);
+
property_get("debug.sf.showupdates", value, "0");
mDebugRegion = atoi(value);
sp<BBinder> token = new DisplayToken(this);
Mutex::Autolock _l(mStateLock);
- DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL);
+ DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
info.displayName = displayName;
- info.isSecure = secure;
mCurrentState.displays.add(token, info);
return token;
}
void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) {
+ ALOGV("createBuiltinDisplayLocked(%d)", type);
ALOGW_IF(mBuiltinDisplays[type],
"Overwriting display token for display type %d", type);
mBuiltinDisplays[type] = new BBinder();
- DisplayDeviceState info(type);
// All non-virtual displays are currently considered secure.
- info.isSecure = true;
+ DisplayDeviceState info(type, true);
mCurrentState.displays.add(mBuiltinDisplays[type], info);
}
// formerly we would just kill the process, but we now ask it to exit so it
// can choose where to stop the animation.
property_set("service.bootanim.exit", "1");
+
+ const int LOGTAG_SF_STOP_BOOTANIM = 60110;
+ LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
+ ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
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;
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- Mutex::Autolock _l(mStateLock);
+ { // Autolock scope
+ Mutex::Autolock _l(mStateLock);
- // initialize EGL for the default display
- mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(mEGLDisplay, NULL, NULL);
+ // initialize EGL for the default display
+ mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(mEGLDisplay, NULL, NULL);
- // Initialize the H/W composer object. There may or may not be an
- // actual hardware composer underneath.
- mHwc = new HWComposer(this,
- *static_cast<HWComposer::EventHandler *>(this));
+ // start the EventThread
+ sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
+ vsyncPhaseOffsetNs, true, "app");
+ mEventThread = new EventThread(vsyncSrc, *this);
+ sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
+ sfVsyncPhaseOffsetNs, true, "sf");
+ mSFEventThread = new EventThread(sfVsyncSrc, *this);
+ mEventQueue.setEventThread(mSFEventThread);
- // get a RenderEngine for the given display / config (can't fail)
- mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());
+ // Get a RenderEngine for the given display / config (can't fail)
+ mRenderEngine = RenderEngine::create(mEGLDisplay,
+ HAL_PIXEL_FORMAT_RGBA_8888);
+ }
+
+ // Drop the state lock while we initialize the hardware composer. We drop
+ // the lock because on creation, it will call back into SurfaceFlinger to
+ // initialize the primary display.
+ mHwc = new HWComposer(this);
+ mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
+
+ Mutex::Autolock _l(mStateLock);
// retrieve the EGL context that was selected/created
mEGLContext = mRenderEngine->getEGLContext();
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext");
- // initialize our non-virtual displays
- for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
- DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
- // set-up the displays that are already connected
- if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
- // All non-virtual displays are currently considered secure.
- bool isSecure = true;
- createBuiltinDisplayLocked(type);
- wp<IBinder> token = mBuiltinDisplays[i];
-
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer,
- new GraphicBufferAlloc());
-
- sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
- consumer);
- int32_t hwcId = allocateHwcDisplayId(type);
- sp<DisplayDevice> hw = new DisplayDevice(this,
- type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
- fbs, producer,
- mRenderEngine->getEGLConfig());
- if (i > DisplayDevice::DISPLAY_PRIMARY) {
- // FIXME: currently we don't get blank/unblank requests
- // for displays other than the main display, so we always
- // assume a connected display is unblanked.
- ALOGD("marking display %zu as acquired/unblanked", i);
- hw->setPowerMode(HWC_POWER_MODE_NORMAL);
- }
- mDisplays.add(token, hw);
- }
- }
-
- // make the GLContext current so that we can create textures when creating Layers
- // (which may happens before we render something)
+ // make the GLContext current so that we can create textures when creating
+ // Layers (which may happens before we render something)
getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
- // start the EventThread
- sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
- vsyncPhaseOffsetNs, true, "app");
- mEventThread = new EventThread(vsyncSrc);
- sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
- sfVsyncPhaseOffsetNs, true, "sf");
- mSFEventThread = new EventThread(sfVsyncSrc);
- mEventQueue.setEventThread(mSFEventThread);
-
mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
- // set a fake vsync period if there is no HWComposer
- if (mHwc->initCheck() != NO_ERROR) {
- mPrimaryDispSync.setPeriod(16666667);
- }
-
// initialize our drawing state
mDrawingState = mCurrentState;
// start boot animation
startBootAnim();
-}
-int32_t SurfaceFlinger::allocateHwcDisplayId(DisplayDevice::DisplayType type) {
- return (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) ?
- type : mHwc->allocateDisplayId();
+ ALOGV("Done initializing");
}
void SurfaceFlinger::startBootAnim() {
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();
- const Vector<HWComposer::DisplayConfig>& hwConfigs =
- getHwComposer().getConfigs(type);
- for (size_t c = 0; c < hwConfigs.size(); ++c) {
- const HWComposer::DisplayConfig& hwConfig = hwConfigs[c];
+ for (const auto& hwConfig : getHwComposer().getConfigs(type)) {
DisplayInfo info = DisplayInfo();
- float xdpi = hwConfig.xdpi;
- float ydpi = hwConfig.ydpi;
+ 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.width;
- info.h = hwConfig.height;
info.xdpi = xdpi;
info.ydpi = ydpi;
- info.fps = float(1e9 / hwConfig.refresh);
+ info.fps = 1e9 / hwConfig->getVsyncPeriod();
info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
+ // TODO: Hook this back up
+ info.colorTransform = 0;
+
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
// on the screen at time N, you must submit the buffer before
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
- info.presentationDeadline =
- hwConfig.refresh - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
+ info.presentationDeadline = hwConfig->getVsyncPeriod() -
+ SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
// All non-virtual displays are currently considered secure.
info.secure = true;
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;
}
- const nsecs_t period =
- getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const nsecs_t period = activeConfig->getVsyncPeriod();
mPrimaryDispSync.reset();
mPrimaryDispSync.setPeriod(period);
}
}
-void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
+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;
{ // Scope for the lock
}
}
-void SurfaceFlinger::onHotplugReceived(int type, bool connected) {
- if (mEventThread == NULL) {
- // This is a temporary workaround for b/7145521. A non-null pointer
- // does not mean EventThread has finished initializing, so this
- // is not a correct fix.
- ALOGW("WARNING: EventThread not started, ignoring hotplug");
- return;
- }
+void SurfaceFlinger::onHotplugReceived(int32_t disp, bool connected) {
+ ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false");
+ if (disp == DisplayDevice::DISPLAY_PRIMARY) {
+ Mutex::Autolock lock(mStateLock);
+
+ // All non-virtual displays are currently considered secure.
+ bool isSecure = true;
- if (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+ int32_t type = DisplayDevice::DISPLAY_PRIMARY;
+ createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
+ wp<IBinder> token = mBuiltinDisplays[type];
+
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer,
+ new GraphicBufferAlloc());
+
+ sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc,
+ DisplayDevice::DISPLAY_PRIMARY, consumer);
+ sp<DisplayDevice> hw = new DisplayDevice(this,
+ DisplayDevice::DISPLAY_PRIMARY, disp, isSecure, token, fbs,
+ producer, mRenderEngine->getEGLConfig());
+ mDisplays.add(token, hw);
+ } else {
+ auto type = DisplayDevice::DISPLAY_EXTERNAL;
Mutex::Autolock _l(mStateLock);
if (connected) {
- createBuiltinDisplayLocked((DisplayDevice::DisplayType)type);
+ createBuiltinDisplayLocked(type);
} else {
mCurrentState.displays.removeItem(mBuiltinDisplays[type]);
mBuiltinDisplays[type].clear();
}
}
-void SurfaceFlinger::eventControl(int disp, int event, int enabled) {
+void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
ATRACE_CALL();
- getHwComposer().eventControl(disp, event, enabled);
+ getHwComposer().setVsyncEnabled(disp,
+ enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
}
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();
- preComposition();
- rebuildLayerStacks();
- setUpHWComposer();
- doDebugFlashRegions();
- doComposition();
- postComposition();
+
+#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;
+ bool frameMissed = (expectedPresent == previousExpectedPresent);
+ if (frameMissed != previousFrameMissed) {
+ ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+ }
+ previousFrameMissed = frameMissed;
+
+ if (CC_UNLIKELY(mDropMissedFrames && frameMissed)) {
+ // Latch buffers, but don't send anything to HWC, then signal another
+ // wakeup for the next vsync
+ preComposition();
+ repaintEverything();
+ } else {
+ preComposition();
+ rebuildLayerStacks();
+ setUpHWComposer();
+ doDebugFlashRegions();
+ doComposition();
+ postComposition(refreshStartTime);
+ }
+
+ // Release any buffers which were replaced this frame
+ for (auto& layer : mLayersWithQueuedFrames) {
+ layer->releasePendingBuffer();
+ }
+ mLayersWithQueuedFrames.clear();
+
+ previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0);
}
void SurfaceFlinger::doDebugFlashRegions()
RenderEngine& engine(getRenderEngine());
engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
- hw->compositionComplete();
hw->swapBuffers(getHwComposer());
}
}
usleep(mDebugRegion * 1000);
}
- HWComposer& hwc(getHwComposer());
- if (hwc.initCheck() == NO_ERROR) {
- status_t err = hwc.prepare();
- ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ status_t result = mDisplays[displayId]->prepareFrame(*mHwc);
+ ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
+ " %d (%s)", displayId, result, strerror(-result));
}
}
void SurfaceFlinger::preComposition()
{
+ ATRACE_CALL();
+ ALOGV("preComposition");
+
bool needExtraInvalidate = false;
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
}
}
-void SurfaceFlinger::postComposition()
+#ifdef ENABLE_FENCE_TRACKING
+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
+#else
+void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/)
+#endif
{
+ ATRACE_CALL();
+ ALOGV("postComposition");
+
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
layers[i]->onPostComposition();
}
- const HWComposer& hwc = getHwComposer();
- sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
+ sp<Fence> presentFence = mHwc->getRetireFence(HWC_DISPLAY_PRIMARY);
if (presentFence->isValid()) {
if (mPrimaryDispSync.addPresentFence(presentFence)) {
}
}
+#ifdef ENABLE_FENCE_TRACKING
+ mFenceTracker.addFrame(refreshStartTime, presentFence,
+ hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
+#endif
+
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
} else {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+ nsecs_t presentTime =
+ mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
mAnimFrameTracker.setActualPresentTime(presentTime);
}
mAnimFrameTracker.advanceFrame();
}
void SurfaceFlinger::rebuildLayerStacks() {
+ ATRACE_CALL();
+ ALOGV("rebuildLayerStacks");
+
// rebuild the visible layer list per screen
if (CC_UNLIKELY(mVisibleRegionsDirty)) {
ATRACE_CALL();
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
Region opaqueRegion;
Region dirtyRegion;
- Vector< sp<Layer> > layersSortedByZ;
- const sp<DisplayDevice>& hw(mDisplays[dpy]);
- const Transform& tr(hw->getTransform());
- const Rect bounds(hw->getBounds());
- if (hw->isDisplayOn()) {
+ Vector<sp<Layer>> layersSortedByZ;
+ const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
+ const Transform& tr(displayDevice->getTransform());
+ const Rect bounds(displayDevice->getBounds());
+ if (displayDevice->isDisplayOn()) {
SurfaceFlinger::computeVisibleRegions(layers,
- hw->getLayerStack(), dirtyRegion, opaqueRegion);
+ displayDevice->getLayerStack(), dirtyRegion,
+ opaqueRegion);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(layers[i]);
const Layer::State& s(layer->getDrawingState());
- if (s.layerStack == hw->getLayerStack()) {
+ if (s.layerStack == displayDevice->getLayerStack()) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
if (!drawRegion.isEmpty()) {
layersSortedByZ.add(layer);
+ } else {
+ // Clear out the HWC layer if this layer was
+ // previously visible, but no longer is
+ layer->setHwcLayer(displayDevice->getHwcDisplayId(),
+ nullptr);
}
}
}
}
- hw->setVisibleLayersSortedByZ(layersSortedByZ);
- hw->undefinedRegion.set(bounds);
- hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
- hw->dirtyRegion.orSelf(dirtyRegion);
+ displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
+ displayDevice->undefinedRegion.set(bounds);
+ displayDevice->undefinedRegion.subtractSelf(
+ tr.transform(opaqueRegion));
+ displayDevice->dirtyRegion.orSelf(dirtyRegion);
}
}
}
void SurfaceFlinger::setUpHWComposer() {
+ ATRACE_CALL();
+ ALOGV("setUpHWComposer");
+
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
}
}
- HWComposer& hwc(getHwComposer());
- if (hwc.initCheck() == NO_ERROR) {
- // build the h/w work list
- if (CC_UNLIKELY(mHwWorkListDirty)) {
- mHwWorkListDirty = false;
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- const int32_t id = hw->getHwcDisplayId();
- if (id >= 0) {
- const Vector< sp<Layer> >& currentLayers(
- hw->getVisibleLayersSortedByZ());
- const size_t count = currentLayers.size();
- if (hwc.createWorkList(id, count) == NO_ERROR) {
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
- for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
- const sp<Layer>& layer(currentLayers[i]);
- layer->setGeometry(hw, *cur);
- if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) {
- cur->setSkip(true);
- }
+ // build the h/w work list
+ if (CC_UNLIKELY(mGeometryInvalid)) {
+ mGeometryInvalid = false;
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> displayDevice(mDisplays[dpy]);
+ const auto hwcId = displayDevice->getHwcDisplayId();
+ if (hwcId >= 0) {
+ const Vector<sp<Layer>>& currentLayers(
+ displayDevice->getVisibleLayersSortedByZ());
+ bool foundLayerWithoutHwc = false;
+ for (auto& layer : currentLayers) {
+ if (!layer->hasHwcLayer(hwcId)) {
+ auto hwcLayer = mHwc->createLayer(hwcId);
+ if (hwcLayer) {
+ layer->setHwcLayer(hwcId, std::move(hwcLayer));
+ } else {
+ layer->forceClientComposition(hwcId);
+ foundLayerWithoutHwc = true;
+ continue;
}
}
- }
- }
- }
-
- // set the per-frame data
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- const int32_t id = hw->getHwcDisplayId();
- if (id >= 0) {
- const Vector< sp<Layer> >& currentLayers(
- hw->getVisibleLayersSortedByZ());
- const size_t count = currentLayers.size();
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
- for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
- /*
- * update the per-frame h/w composer data for each layer
- * and build the transparent region of the FB
- */
- const sp<Layer>& layer(currentLayers[i]);
- layer->setPerFrameData(hw, *cur);
- }
- }
- }
- // If possible, attempt to use the cursor overlay on each display.
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- const int32_t id = hw->getHwcDisplayId();
- if (id >= 0) {
- const Vector< sp<Layer> >& currentLayers(
- hw->getVisibleLayersSortedByZ());
- const size_t count = currentLayers.size();
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
- for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
- const sp<Layer>& layer(currentLayers[i]);
- if (layer->isPotentialCursor()) {
- cur->setIsCursorLayerHint();
- break;
+ layer->setGeometry(displayDevice);
+ if (mDebugDisableHWC || mDebugRegion || mDaltonize ||
+ mHasColorMatrix) {
+ layer->forceClientComposition(hwcId);
}
}
}
}
+ }
- status_t err = hwc.prepare();
- ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
-
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- hw->prepareFrame(hwc);
+ // Set the per-frame data
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ auto& displayDevice = mDisplays[displayId];
+ const auto hwcId = displayDevice->getHwcDisplayId();
+ if (hwcId < 0) {
+ continue;
+ }
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ layer->setPerFrameData(displayDevice);
}
}
+
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ status_t result = mDisplays[displayId]->prepareFrame(*mHwc);
+ ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
+ " %d (%s)", displayId, result, strerror(-result));
+ }
}
void SurfaceFlinger::doComposition() {
ATRACE_CALL();
+ ALOGV("doComposition");
+
const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]);
hw->flip(hw->swapRegion);
hw->swapRegion.clear();
}
- // inform the h/w that we're done compositing
- hw->compositionComplete();
}
postFramebuffer();
}
void SurfaceFlinger::postFramebuffer()
{
ATRACE_CALL();
+ ALOGV("postFramebuffer");
const nsecs_t now = systemTime();
mDebugInSwapBuffers = now;
- HWComposer& hwc(getHwComposer());
- if (hwc.initCheck() == NO_ERROR) {
- if (!hwc.supportsFramebufferTarget()) {
- // EGL spec says:
- // "surface must be bound to the calling thread's current context,
- // for the current rendering API."
- getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
- }
- hwc.commit();
- }
-
- // make the default display current because the VirtualDisplayDevice code cannot
- // deal with dequeueBuffer() being called outside of the composition loop; however
- // the code below can call glFlush() which is allowed (and does in some case) call
- // dequeueBuffer().
- getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
-
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ());
- hw->onSwapBuffersCompleted(hwc);
- const size_t count = currentLayers.size();
- int32_t id = hw->getHwcDisplayId();
- if (id >=0 && hwc.initCheck() == NO_ERROR) {
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
- for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
- currentLayers[i]->onLayerDisplayed(hw, &*cur);
- }
- } else {
- for (size_t i = 0; i < count; i++) {
- currentLayers[i]->onLayerDisplayed(hw, NULL);
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ auto& displayDevice = mDisplays[displayId];
+ const auto hwcId = displayDevice->getHwcDisplayId();
+ 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
+ // composition loop; however the code below can call glFlush() which
+ // is allowed to (and does in some case) call dequeueBuffer().
+ displayDevice->makeCurrent(mEGLDisplay, mEGLContext);
+ }
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ sp<Fence> releaseFence = Fence::NO_FENCE;
+ if (layer->getCompositionType(hwcId) == HWC2::Composition::Client) {
+ releaseFence = displayDevice->getClientTargetAcquireFence();
+ } else {
+ auto hwcLayer = layer->getHwcLayer(hwcId);
+ releaseFence = mHwc->getLayerReleaseFence(hwcId, hwcLayer);
}
+ layer->onLayerDisplayed(releaseFence);
+ }
+ if (hwcId >= 0) {
+ mHwc->clearReleaseFences(hwcId);
}
}
const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size();
+ // Notify all layers of available frames
+ for (size_t i = 0; i < count; ++i) {
+ currentLayers[i]->notifyAvailableFrames();
+ }
+
/*
* Traversal of the children
* (perform the transaction for each of them if needed)
BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
new GraphicBufferAlloc());
- int32_t hwcDisplayId = -1;
+ int32_t hwcId = -1;
if (state.isVirtualDisplay()) {
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
NATIVE_WINDOW_HEIGHT, &height);
ALOGE_IF(status != NO_ERROR,
"Unable to query height (%d)", status);
- if (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 ||
- (width <= MAX_VIRTUAL_DISPLAY_DIMENSION &&
- height <= MAX_VIRTUAL_DISPLAY_DIMENSION)) {
- hwcDisplayId = allocateHwcDisplayId(state.type);
- }
+ 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, &format,
+ &hwcId);
+
+ // TODO: Plumb requested format back up to consumer
- sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface(
- *mHwc, hwcDisplayId, state.surface,
- bqProducer, bqConsumer, state.displayName);
+ sp<VirtualDisplaySurface> vds =
+ new VirtualDisplaySurface(*mHwc,
+ hwcId, state.surface, bqProducer,
+ bqConsumer, state.displayName);
dispSurface = vds;
producer = vds;
"adding a supported display, but rendering "
"surface is provided (%p), ignoring it",
state.surface.get());
- hwcDisplayId = allocateHwcDisplayId(state.type);
- // for supported (by hwc) displays we provide our
- // own rendering surface
- dispSurface = new FramebufferSurface(*mHwc, state.type,
- bqConsumer);
- producer = bqProducer;
+ if (state.type == DisplayDevice::DISPLAY_EXTERNAL) {
+ hwcId = DisplayDevice::DISPLAY_EXTERNAL;
+ dispSurface = new FramebufferSurface(*mHwc,
+ DisplayDevice::DISPLAY_EXTERNAL,
+ bqConsumer);
+ producer = bqProducer;
+ } else {
+ ALOGE("Attempted to add non-external non-virtual"
+ " display");
+ }
}
const wp<IBinder>& display(curr.keyAt(i));
if (dispSurface != NULL) {
sp<DisplayDevice> hw = new DisplayDevice(this,
- state.type, hwcDisplayId,
- mHwc->getFormat(hwcDisplayId), state.isSecure,
- display, dispSurface, producer,
+ state.type, hwcId, state.isSecure, display,
+ dispSurface, producer,
mRenderEngine->getEGLConfig());
hw->setLayerStack(state.layerStack);
hw->setProjection(state.orientation,
state.viewport, state.frame);
hw->setDisplayName(state.displayName);
mDisplays.add(display, hw);
- if (state.isVirtualDisplay()) {
- if (hwcDisplayId >= 0) {
- mHwc->setVirtualDisplayProperties(hwcDisplayId,
- hw->getWidth(), hw->getHeight(),
- hw->getFormat());
- }
- } else {
+ if (!state.isVirtualDisplay()) {
mEventThread->onHotplugReceived(state.type, true);
}
}
// compute the actual visible region
// TODO: we could cache the transformed region
const Layer::State& s(layer->getDrawingState());
- Region visibleReg = s.transform.transform(
+ Region visibleReg = s.active.transform.transform(
Region(Rect(s.active.w, s.active.h)));
invalidateLayerStack(s.layerStack, visibleReg);
}
void SurfaceFlinger::updateCursorAsync()
{
- HWComposer& hwc(getHwComposer());
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- const int32_t id = hw->getHwcDisplayId();
- if (id < 0) {
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ auto& displayDevice = mDisplays[displayId];
+ if (displayDevice->getHwcDisplayId() < 0) {
continue;
}
- const Vector< sp<Layer> >& currentLayers(
- hw->getVisibleLayersSortedByZ());
- const size_t count = currentLayers.size();
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
- for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
- if (cur->getCompositionType() != HWC_CURSOR_OVERLAY) {
- continue;
- }
- const sp<Layer>& layer(currentLayers[i]);
- Rect cursorPos = layer->getPosition(hw);
- hwc.setCursorPositionAsync(id, cursorPos);
- break;
+
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ layer->updateCursorPosition(displayDevice);
}
}
}
Region& outDirtyRegion, Region& outOpaqueRegion)
{
ATRACE_CALL();
+ ALOGV("computeVisibleRegions");
Region aboveOpaqueLayers;
Region aboveCoveredLayers;
// handle hidden surfaces by setting the visible region to empty
if (CC_LIKELY(layer->isVisible())) {
const bool translucent = !layer->isOpaque(s);
- Rect bounds(s.transform.transform(layer->computeBounds()));
+ Rect bounds(s.active.transform.transform(layer->computeBounds()));
visibleRegion.set(bounds);
if (!visibleRegion.isEmpty()) {
// Remove the transparent area from the visible region
if (translucent) {
- const Transform tr(s.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();
- }
+ const Transform tr(s.active.transform);
+ 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();
}
}
// compute the opaque region
- const int32_t layerOrientation = s.transform.getOrientation();
- if (s.alpha==255 && !translucent &&
+ const int32_t layerOrientation = s.active.transform.getOrientation();
+ if (s.alpha == 1.0f && !translucent &&
((layerOrientation & Transform::ROT_INVALID) == false)) {
// the opaque region is the layer's footprint
opaqueRegion = visibleRegion;
bool SurfaceFlinger::handlePageFlip()
{
+ ALOGV("handlePageFlip");
+
Region dirtyRegion;
bool visibleRegions = false;
// 3.) Layer 1 is latched.
// Display is now waiting on Layer 1's frame, which is behind layer 0's
// second frame. But layer 0's second frame could be waiting on display.
- Vector<Layer*> layersWithQueuedFrames;
for (size_t i = 0, count = layers.size(); i<count ; i++) {
const sp<Layer>& layer(layers[i]);
if (layer->hasQueuedFrame()) {
frameQueued = true;
if (layer->shouldPresentNow(mPrimaryDispSync)) {
- layersWithQueuedFrames.push_back(layer.get());
+ mLayersWithQueuedFrames.push_back(layer.get());
} else {
layer->useEmptyDamage();
}
layer->useEmptyDamage();
}
}
- for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
- Layer* layer = layersWithQueuedFrames[i];
+ for (auto& layer : mLayersWithQueuedFrames) {
const Region dirty(layer->latchBuffer(visibleRegions));
layer->useSurfaceDamage();
const Layer::State& s(layer->getDrawingState());
// If we will need to wake up at some time in the future to deal with a
// queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.
- if (frameQueued && layersWithQueuedFrames.empty()) {
+ if (frameQueued && mLayersWithQueuedFrames.empty()) {
signalLayerUpdate();
}
// Only continue with the refresh if there is actually new work to do
- return !layersWithQueuedFrames.empty();
+ return !mLayersWithQueuedFrames.empty();
}
void SurfaceFlinger::invalidateHwcGeometry()
{
- mHwWorkListDirty = true;
+ mGeometryInvalid = true;
}
// 2) There is work to be done (the dirty region isn't empty)
bool isHwcDisplay = hw->getHwcDisplayId() >= 0;
if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
+ ALOGV("Skipping display composition");
return;
}
+ ALOGV("doDisplayComposition");
+
Region dirtyRegion(inDirtyRegion);
// compute the invalid region
hw->swapBuffers(getHwComposer());
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
+bool SurfaceFlinger::doComposeSurfaces(
+ const sp<const DisplayDevice>& displayDevice, const Region& dirty)
{
- RenderEngine& engine(getRenderEngine());
- const int32_t id = hw->getHwcDisplayId();
- HWComposer& hwc(getHwComposer());
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
+ ALOGV("doComposeSurfaces");
+
+ const auto hwcId = displayDevice->getHwcDisplayId();
+ bool hasClientComposition = mHwc->hasClientComposition(hwcId);
+ if (hasClientComposition) {
+ ALOGV("hasClientComposition");
- bool hasGlesComposition = hwc.hasGlesComposition(id);
- if (hasGlesComposition) {
- if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) {
+ if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) {
ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
- hw->getDisplayName().string());
+ displayDevice->getDisplayName().string());
eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) {
ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
}
// Never touch the framebuffer if we don't have any framebuffer layers
- const bool hasHwcComposition = hwc.hasHwcComposition(id);
- if (hasHwcComposition) {
+ 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.
- engine.clearWithColor(0, 0, 0, 0);
+ mRenderEngine->clearWithColor(0, 0, 0, 0);
} else {
// we start with the whole screen area
- const Region bounds(hw->getBounds());
+ const Region bounds(displayDevice->getBounds());
// we 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(hw->getScissor()));
+ const Region letterbox(bounds.subtract(displayDevice->getScissor()));
// compute the area to clear
- Region region(hw->undefinedRegion.merge(letterbox));
+ 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
- drawWormhole(hw, region);
+ drawWormhole(displayDevice, region);
}
}
- if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {
+ if (displayDevice->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {
// just to be on the safe side, we don't set the
// scissor on the main display. It should never be needed
// anyways (though in theory it could since the API allows it).
- const Rect& bounds(hw->getBounds());
- const Rect& scissor(hw->getScissor());
+ const Rect& bounds(displayDevice->getBounds());
+ const Rect& scissor(displayDevice->getScissor());
if (scissor != bounds) {
// scissor doesn't match the screen's dimensions, so we
// need to clear everything outside of it and enable
// the GL scissor so we don't draw anything where we shouldn't
// enable scissor for this frame
- const uint32_t height = hw->getHeight();
- engine.setScissor(scissor.left, height - scissor.bottom,
+ const uint32_t height = displayDevice->getHeight();
+ mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
scissor.getWidth(), scissor.getHeight());
}
}
* and then, render the layers targeted at the framebuffer
*/
- const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ());
- const size_t count = layers.size();
- const Transform& tr = hw->getTransform();
- if (cur != end) {
+ ALOGV("Rendering client layers");
+ const Transform& displayTransform = displayDevice->getTransform();
+ if (hwcId >= 0) {
// we're using h/w composer
- for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) {
- const sp<Layer>& layer(layers[i]);
- const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
+ 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 (cur->getCompositionType()) {
- case HWC_CURSOR_OVERLAY:
- case HWC_OVERLAY: {
+ switch (layer->getCompositionType(hwcId)) {
+ case HWC2::Composition::Cursor:
+ case HWC2::Composition::Device:
+ case HWC2::Composition::SolidColor: {
const Layer::State& state(layer->getDrawingState());
- if ((cur->getHints() & HWC_HINT_CLEAR_FB)
- && i
- && layer->isOpaque(state) && (state.alpha == 0xFF)
- && hasGlesComposition) {
+ 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(hw, clip);
+ layer->clearWithOpenGL(displayDevice, clip);
}
break;
}
- case HWC_FRAMEBUFFER: {
- layer->draw(hw, clip);
+ case HWC2::Composition::Client: {
+ layer->draw(displayDevice, clip);
break;
}
- case HWC_FRAMEBUFFER_TARGET: {
- // this should not happen as the iterator shouldn't
- // let us get there.
- ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i);
+ default:
break;
- }
}
+ } else {
+ ALOGV(" Skipping for empty clip");
}
- layer->setAcquireFence(hw, *cur);
+ firstLayer = false;
}
} else {
// we're not using h/w composer
- for (size_t i=0 ; i<count ; ++i) {
- const sp<Layer>& layer(layers[i]);
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
const Region clip(dirty.intersect(
- tr.transform(layer->visibleRegion)));
+ displayTransform.transform(layer->visibleRegion)));
if (!clip.isEmpty()) {
- layer->draw(hw, clip);
+ layer->draw(displayDevice, clip);
}
}
}
// disable scissor at the end of the frame
- engine.disableScissor();
+ mRenderEngine->disableScissor();
return true;
}
}
}
+ // 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
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
- if (layer->setLayer(s.z)) {
+ if (layer->setLayer(s.z) && idx >= 0) {
mCurrentState.layersSortedByZ.removeAt(idx);
mCurrentState.layersSortedByZ.add(layer);
// we need traversal (state changed)
}
}
if (what & layer_state_t::eAlphaChanged) {
- if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+ if (layer->setAlpha(s.alpha))
flags |= eTraversalNeeded;
}
if (what & layer_state_t::eMatrixChanged) {
if (layer->setCrop(s.crop))
flags |= eTraversalNeeded;
}
+ if (what & layer_state_t::eFinalCropChanged) {
+ if (layer->setFinalCrop(s.finalCrop))
+ flags |= eTraversalNeeded;
+ }
if (what & layer_state_t::eLayerStackChanged) {
// NOTE: index needs to be calculated before we update the state
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
- if (layer->setLayerStack(s.layerStack)) {
+ if (layer->setLayerStack(s.layerStack) && idx >= 0) {
mCurrentState.layersSortedByZ.removeAt(idx);
mCurrentState.layersSortedByZ.add(layer);
// we need traversal (state changed)
flags |= eTransactionNeeded|eTraversalNeeded;
}
}
+ if (what & layer_state_t::eDeferTransaction) {
+ layer->deferTransactionUntil(s.handle, s.frameNumber);
+ // 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;
}
setTransactionState(state, displays, 0);
setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);
- const nsecs_t period =
- getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
}
dumpStaticScreenStats(result);
dumpAll = false;
}
+
+#ifdef ENABLE_FENCE_TRACKING
+ if ((index < numArgs) &&
+ (args[index] == String16("--fences"))) {
+ index++;
+ mFenceTracker.dump(&result);
+ dumpAll = false;
+ }
+#endif
}
if (dumpAll) {
index++;
}
- const nsecs_t period =
- getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const nsecs_t period = activeConfig->getVsyncPeriod();
result.appendFormat("%" PRId64 "\n", period);
if (name.isEmpty()) {
result.append(SyncFeatures::getInstance().toString());
result.append("\n");
+ const auto& activeConfig = 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 %d ns (refresh %" PRId64 " ns)",
- vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS,
- mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
+ vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
+ PRESENT_TIME_OFFSET_FROM_VSYNC_NS, activeConfig->getVsyncPeriod());
result.append("\n");
// Dump static screen stats
mLastSwapBufferTime/1000.0,
mLastTransactionTime/1000.0,
mTransactionFlags,
- 1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY),
- hwc.getDpiX(HWC_DISPLAY_PRIMARY),
- hwc.getDpiY(HWC_DISPLAY_PRIMARY),
+ 1e9 / activeConfig->getVsyncPeriod(),
+ activeConfig->getDpiX(),
+ activeConfig->getDpiY(),
!mGpuToCpuSupported);
result.appendFormat(" eglSwapBuffers time: %f us\n",
colorizer.bold(result);
result.append("h/w composer state:\n");
colorizer.reset(result);
- result.appendFormat(" h/w composer %s and %s\n",
- hwc.initCheck()==NO_ERROR ? "present" : "not present",
- (mDebugDisableHWC || mDebugRegion || mDaltonize
- || mHasColorMatrix) ? "disabled" : "enabled");
+ bool hwcDisabled = mDebugDisableHWC || mDebugRegion || mDaltonize ||
+ mHasColorMatrix;
+ result.appendFormat(" h/w composer %s\n",
+ hwcDisabled ? "disabled" : "enabled");
hwc.dump(result);
/*
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();
GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
: impl(impl),
looper(new Looper(true)),
+ result(NO_ERROR),
exitPending(false),
- exitRequested(false)
+ exitRequested(false),
+ code(0),
+ data(NULL),
+ reply(NULL)
{}
// Binder thread
// 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).
- if (!IInterface::asBinder(producer)->localBinder()) {
- Mutex::Autolock _l(mStateLock);
- sp<const DisplayDevice> hw(getDisplayDevice(display));
- if (hw->getSecureLayerVisible()) {
- ALOGW("FB is protected: PERMISSION_DENIED");
- return PERMISSION_DENIED;
- }
- }
+ bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
// Convert to surfaceflinger's internal rotation type.
Transform::orientation_flags rotationFlags;
bool useIdentityTransform;
Transform::orientation_flags rotation;
status_t result;
+ bool isLocalScreenshot;
public:
MessageCaptureScreen(SurfaceFlinger* flinger,
const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation)
+ bool useIdentityTransform,
+ Transform::orientation_flags rotation,
+ bool isLocalScreenshot)
: flinger(flinger), display(display), producer(producer),
sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
useIdentityTransform(useIdentityTransform),
- rotation(rotation),
- result(PERMISSION_DENIED)
+ rotation(rotation), result(PERMISSION_DENIED),
+ isLocalScreenshot(isLocalScreenshot)
{
}
status_t getResult() const {
sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
result = flinger->captureScreenImplLocked(hw, producer,
sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotation);
+ useIdentityTransform, rotation, isLocalScreenshot);
static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
return true;
}
};
- // 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)
sp<MessageBase> msg = new MessageCaptureScreen(this,
display, IGraphicBufferProducer::asInterface( wrapper ),
sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotationFlags);
+ useIdentityTransform, rotationFlags, isLocalScreenshot);
status_t res = postMessageAsync(msg);
if (res == NO_ERROR) {
}
}
- // compositionComplete is needed for older driver
- hw->compositionComplete();
hw->setViewportAndProjection();
}
const sp<IGraphicBufferProducer>& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation)
+ bool useIdentityTransform, Transform::orientation_flags rotation,
+ bool isLocalScreenshot)
{
ATRACE_CALL();
reqWidth = (!reqWidth) ? hw_w : reqWidth;
reqHeight = (!reqHeight) ? hw_h : reqHeight;
+ bool secureLayerIsVisible = false;
+ const LayerVector& layers(mDrawingState.layersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i = 0 ; i < count ; ++i) {
+ const sp<Layer>& layer(layers[i]);
+ const Layer::State& state(layer->getDrawingState());
+ if (state.layerStack == hw->getLayerStack() && state.z >= minLayerZ &&
+ state.z <= maxLayerZ && layer->isVisible() &&
+ layer->isSecure()) {
+ secureLayerIsVisible = true;
+ }
+ }
+
+ if (!isLocalScreenshot && secureLayerIsVisible) {
+ ALOGW("FB is protected: PERMISSION_DENIED");
+ return PERMISSION_DENIED;
+ }
+
// create a surface (because we're a producer, and we need to
// dequeue/queue a buffer)
sp<Surface> sur = new Surface(producer, false);
} else {
ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
result = INVALID_OPERATION;
+ window->cancelBuffer(window, buffer, syncFd);
+ buffer = NULL;
}
// destroy our image
eglDestroyImageKHR(mEGLDisplay, image);
} else {
result = BAD_VALUE;
}
- // queueBuffer takes ownership of syncFd
- result = window->queueBuffer(window, buffer, syncFd);
+ if (buffer) {
+ // queueBuffer takes ownership of syncFd
+ result = window->queueBuffer(window, buffer, syncFd);
+ }
}
} else {
result = BAD_VALUE;
const bool visible = (state.layerStack == hw->getLayerStack())
&& (state.z >= minLayerZ && state.z <= maxLayerZ)
&& (layer->isVisible());
- ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x",
+ ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
visible ? '+' : '-',
i, layer->getName().string(), state.layerStack, state.z,
layer->isVisible(), state.flags, state.alpha);
// ---------------------------------------------------------------------------
SurfaceFlinger::DisplayDeviceState::DisplayDeviceState()
- : type(DisplayDevice::DISPLAY_ID_INVALID), width(0), height(0) {
-}
-
-SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type)
- : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0), width(0), height(0) {
+ : type(DisplayDevice::DISPLAY_ID_INVALID),
+ layerStack(DisplayDevice::NO_LAYER_STACK),
+ orientation(0),
+ width(0),
+ height(0),
+ isSecure(false) {
+}
+
+SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(
+ DisplayDevice::DisplayType type, bool isSecure)
+ : type(type),
+ layerStack(DisplayDevice::NO_LAYER_STACK),
+ orientation(0),
+ width(0),
+ height(0),
+ isSecure(isSecure) {
viewport.makeInvalid();
frame.makeInvalid();
}