summaryrefslogtreecommitdiffstats
path: root/services/surfaceflinger
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger')
-rw-r--r--services/surfaceflinger/DispSync.cpp46
-rw-r--r--services/surfaceflinger/DispSync.h3
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp4
-rw-r--r--services/surfaceflinger/DisplayDevice.h4
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplaySurface.h4
-rw-r--r--services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp2
-rw-r--r--services/surfaceflinger/DisplayHardware/FramebufferSurface.h2
-rw-r--r--services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp35
-rw-r--r--services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h4
-rw-r--r--services/surfaceflinger/Layer.cpp22
-rw-r--r--services/surfaceflinger/Layer.h7
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp28
-rw-r--r--services/surfaceflinger/main_surfaceflinger.cpp2
13 files changed, 126 insertions, 37 deletions
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 602f20a..95839b7 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -20,6 +20,7 @@
#define __STDC_LIMIT_MACROS
#include <math.h>
+#include <inttypes.h>
#include <cutils/log.h>
@@ -487,4 +488,49 @@ void DispSync::resetErrorLocked() {
}
}
+void DispSync::dump(String8& result) const {
+ Mutex::Autolock lock(mMutex);
+ result.appendFormat("mPeriod: %"PRId64" ns\n", mPeriod);
+ result.appendFormat("mPhase: %"PRId64" ns\n", mPhase);
+ result.appendFormat("mError: %"PRId64" ns (sqrt: %.1f)\n",
+ mError, sqrt(mError));
+ result.appendFormat("mNumResyncSamplesSincePresent: %d (max %d)\n",
+ mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
+ result.appendFormat("mNumResyncSamples: %d (max %d)\n",
+ mNumResyncSamples, MAX_RESYNC_SAMPLES);
+
+ result.appendFormat("mResyncSamples:\n");
+ nsecs_t previous = -1;
+ for (size_t i = 0; i < mNumResyncSamples; i++) {
+ size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
+ nsecs_t sampleTime = mResyncSamples[idx];
+ if (i == 0) {
+ result.appendFormat(" %"PRId64"\n", sampleTime);
+ } else {
+ result.appendFormat(" %"PRId64" (+%"PRId64")\n",
+ sampleTime, sampleTime - previous);
+ }
+ previous = sampleTime;
+ }
+
+ result.appendFormat("mPresentFences / mPresentTimes [%d]:\n",
+ NUM_PRESENT_SAMPLES);
+ previous = 0;
+ for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
+ size_t idx = (i + mPresentSampleOffset) % NUM_PRESENT_SAMPLES;
+ bool signaled = mPresentFences[idx] == NULL;
+ nsecs_t presentTime = mPresentTimes[idx];
+ if (!signaled) {
+ result.appendFormat(" [unsignaled fence]\n");
+ } else if (previous == 0) {
+ result.appendFormat(" %"PRId64"\n", presentTime);
+ } else {
+ result.appendFormat(" %"PRId64" (+%"PRId64" / %.3f)\n",
+ presentTime, presentTime - previous,
+ (presentTime - previous) / (double) mPeriod);
+ }
+ previous = presentTime;
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index c4280aa..19eb3e5 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -99,6 +99,9 @@ public:
// DispSync object.
status_t removeEventListener(const sp<Callback>& callback);
+ // dump appends human-readable debug info to the result string.
+ void dump(String8& result) const;
+
private:
void updateModelLocked();
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a1430b9..f9034a6 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -199,8 +199,8 @@ void DisplayDevice::flip(const Region& dirty) const
mPageFlipCount++;
}
-status_t DisplayDevice::beginFrame() const {
- return mDisplaySurface->beginFrame();
+status_t DisplayDevice::beginFrame(bool mustRecompose) const {
+ return mDisplaySurface->beginFrame(mustRecompose);
}
status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 01a9d2e..f750c6c 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -124,7 +124,9 @@ public:
int32_t getHwcDisplayId() const { return mHwcDisplayId; }
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
- status_t beginFrame() const;
+ // We pass in mustRecompose so we can keep VirtualDisplaySurface's state
+ // machine happy without actually queueing a buffer if nothing has changed
+ status_t beginFrame(bool mustRecompose) const;
status_t prepareFrame(const HWComposer& hwc) const;
void swapBuffers(HWComposer& hwc) const;
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index 48bf3f2..1db3eb8 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -33,7 +33,9 @@ public:
// beginFrame is called at the beginning of the composition loop, before
// the configuration is known. The DisplaySurface should do anything it
// needs to do to enable HWComposer to decide how to compose the frame.
- virtual status_t beginFrame() = 0;
+ // We pass in mustRecompose so we can keep VirtualDisplaySurface's state
+ // machine happy without actually queueing a buffer if nothing has changed.
+ virtual status_t beginFrame(bool mustRecompose) = 0;
// prepareFrame is called after the composition configuration is known but
// before composition takes place. The DisplaySurface can use the
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 7d4b196..086ccf8 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -68,7 +68,7 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp,
mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
}
-status_t FramebufferSurface::beginFrame() {
+status_t FramebufferSurface::beginFrame(bool mustRecompose) {
return NO_ERROR;
}
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 1d67446..ba72ce3 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -39,7 +39,7 @@ class FramebufferSurface : public ConsumerBase,
public:
FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer);
- virtual status_t beginFrame();
+ virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType);
virtual status_t compositionComplete();
virtual status_t advanceFrame();
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index d7fef8c..a1820ab 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -56,7 +56,8 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
mProducerSlotSource(0),
mDbgState(DBG_STATE_IDLE),
- mDbgLastCompositionType(COMPOSITION_UNKNOWN)
+ mDbgLastCompositionType(COMPOSITION_UNKNOWN),
+ mMustRecompose(false)
{
mSource[SOURCE_SINK] = sink;
mSource[SOURCE_SCRATCH] = bq;
@@ -92,10 +93,12 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
VirtualDisplaySurface::~VirtualDisplaySurface() {
}
-status_t VirtualDisplaySurface::beginFrame() {
+status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) {
if (mDisplayId < 0)
return NO_ERROR;
+ mMustRecompose = mustRecompose;
+
VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
"Unexpected beginFrame() in %s state", dbgStateStr());
mDbgState = DBG_STATE_BEGUN;
@@ -228,16 +231,24 @@ void VirtualDisplaySurface::onFrameCommitted() {
QueueBufferOutput qbo;
sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId);
VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
- status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
- QueueBufferInput(
- systemTime(), false /* isAutoTimestamp */,
- Rect(mSinkBufferWidth, mSinkBufferHeight),
- NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */,
- true /* async*/,
- outFence),
- &qbo);
- if (result == NO_ERROR) {
- updateQueueBufferOutput(qbo);
+ if (mMustRecompose) {
+ status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
+ QueueBufferInput(
+ systemTime(), false /* isAutoTimestamp */,
+ Rect(mSinkBufferWidth, mSinkBufferHeight),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */,
+ true /* async*/,
+ outFence),
+ &qbo);
+ if (result == NO_ERROR) {
+ updateQueueBufferOutput(qbo);
+ }
+ } else {
+ // If the surface hadn't actually been updated, then we only went
+ // through the motions of updating the display to keep our state
+ // machine happy. We cancel the buffer to avoid triggering another
+ // re-composition and causing an infinite loop.
+ mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence);
}
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 1e85ac4..6899904 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -79,7 +79,7 @@ public:
//
// DisplaySurface interface
//
- virtual status_t beginFrame();
+ virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType);
virtual status_t compositionComplete();
virtual status_t advanceFrame();
@@ -222,6 +222,8 @@ private:
const char* dbgStateStr() const;
static const char* dbgSourceStr(Source s);
+
+ bool mMustRecompose;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 61af51f..fcc9d78 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -64,7 +64,6 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
mName("unnamed"),
mDebug(false),
mFormat(PIXEL_FORMAT_NONE),
- mOpaqueLayer(true),
mTransactionFlags(0),
mQueuedFrames(0),
mCurrentTransform(0),
@@ -86,7 +85,9 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
uint32_t layerFlags = 0;
if (flags & ISurfaceComposerClient::eHidden)
- layerFlags = layer_state_t::eLayerHidden;
+ layerFlags |= layer_state_t::eLayerHidden;
+ if (flags & ISurfaceComposerClient::eOpaque)
+ layerFlags |= layer_state_t::eLayerOpaque;
if (flags & ISurfaceComposerClient::eNonPremultiplied)
mPremultipliedAlpha = false;
@@ -189,7 +190,6 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false;
mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
- mOpaqueLayer = (flags & ISurfaceComposerClient::eOpaque);
mCurrentOpacity = getOpacityForFormat(format);
mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
@@ -352,7 +352,7 @@ void Layer::setGeometry(
// this gives us only the "orientation" component of the transform
const State& s(getDrawingState());
- if (!isOpaque() || s.alpha != 0xFF) {
+ if (!isOpaque(s) || s.alpha != 0xFF) {
layer.setBlending(mPremultipliedAlpha ?
HWC_BLENDING_PREMULT :
HWC_BLENDING_COVERAGE);
@@ -596,7 +596,7 @@ void Layer::drawWithOpenGL(
texCoords[3] = vec2(right, 1.0f - top);
RenderEngine& engine(mFlinger->getRenderEngine());
- engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(), s.alpha);
+ engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), s.alpha);
engine.drawMesh(mMesh);
engine.disableBlending();
}
@@ -656,7 +656,7 @@ void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh) const
}
}
-bool Layer::isOpaque() const
+bool Layer::isOpaque(const Layer::State& s) const
{
// if we don't have a buffer yet, we're translucent regardless of the
// layer's opaque flag.
@@ -666,7 +666,7 @@ bool Layer::isOpaque() const
// if the layer has the opaque flag, then we're always opaque,
// otherwise we use the current buffer's format.
- return mOpaqueLayer || mCurrentOpacity;
+ return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
}
bool Layer::isProtected() const
@@ -954,7 +954,8 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
}
// Capture the old state of the layer for comparisons later
- const bool oldOpacity = isOpaque();
+ const State& s(getDrawingState());
+ const bool oldOpacity = isOpaque(s);
sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
@@ -1122,12 +1123,11 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
}
mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
- if (oldOpacity != isOpaque()) {
+ if (oldOpacity != isOpaque(s)) {
recomputeVisibleRegions = true;
}
// FIXME: postedRegion should be dirty & bounds
- const Layer::State& s(getDrawingState());
Region dirtyRegion(Rect(s.active.w, s.active.h));
// transform the dirty region to window-manager space
@@ -1188,7 +1188,7 @@ void Layer::dump(String8& result, Colorizer& colorizer) const
s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
s.active.crop.left, s.active.crop.top,
s.active.crop.right, s.active.crop.bottom,
- isOpaque(), contentDirty,
+ isOpaque(s), contentDirty,
s.alpha, s.flags,
s.transform[0][0], s.transform[0][1],
s.transform[1][0], s.transform[1][1],
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ef4a7e9..ea65ded 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -149,8 +149,12 @@ public:
/*
* isOpaque - true if this surface is opaque
+ *
+ * This takes into account the buffer format (i.e. whether or not the
+ * pixel format includes an alpha channel) and the "opaque" flag set
+ * on the layer. It does not examine the current plane alpha value.
*/
- virtual bool isOpaque() const;
+ virtual bool isOpaque(const Layer::State& s) const;
/*
* isSecure - true if this surface is secure, that is if it prevents
@@ -335,7 +339,6 @@ private:
String8 mName;
mutable bool mDebug;
PixelFormat mFormat;
- bool mOpaqueLayer;
// these are protected by an external lock
State mCurrentState;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 943ed02..94bef9a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -882,7 +882,9 @@ void SurfaceFlinger::rebuildLayerStacks() {
void SurfaceFlinger::setUpHWComposer() {
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- mDisplays[dpy]->beginFrame();
+ bool mustRecompose =
+ !(mDisplays[dpy]->getDirtyRegion(false).isEmpty());
+ mDisplays[dpy]->beginFrame(mustRecompose);
}
HWComposer& hwc(getHwComposer());
@@ -1380,7 +1382,7 @@ void SurfaceFlinger::computeVisibleRegions(
// handle hidden surfaces by setting the visible region to empty
if (CC_LIKELY(layer->isVisible())) {
- const bool translucent = !layer->isOpaque();
+ const bool translucent = !layer->isOpaque(s);
Rect bounds(s.transform.transform(layer->computeBounds()));
visibleRegion.set(bounds);
if (!visibleRegion.isEmpty()) {
@@ -1500,6 +1502,15 @@ void SurfaceFlinger::invalidateHwcGeometry()
void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
const Region& inDirtyRegion)
{
+ // We only need to actually compose the display if:
+ // 1) It is being handled by hardware composer, which may need this to
+ // keep its virtual display state machine in sync, or
+ // 2) There is work to be done (the dirty region isn't empty)
+ bool isHwcDisplay = hw->getHwcDisplayId() >= 0;
+ if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
+ return;
+ }
+
Region dirtyRegion(inDirtyRegion);
// compute the invalid region
@@ -1625,7 +1636,7 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const
const Layer::State& state(layer->getDrawingState());
if ((cur->getHints() & HWC_HINT_CLEAR_FB)
&& i
- && layer->isOpaque() && (state.alpha == 0xFF)
+ && layer->isOpaque(state) && (state.alpha == 0xFF)
&& hasGlesComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
@@ -1869,7 +1880,9 @@ uint32_t SurfaceFlinger::setClientStateLocked(
if (layer->setTransparentRegionHint(s.transparentRegion))
flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eVisibilityChanged) {
+ if ((what & layer_state_t::eVisibilityChanged) ||
+ (what & layer_state_t::eOpacityChanged)) {
+ // TODO: should we just use an eFlagsChanged for this?
if (layer->setFlags(s.flags, s.mask))
flags |= eTraversalNeeded;
}
@@ -2189,6 +2202,13 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
clearStatsLocked(args, index, result);
dumpAll = false;
}
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--dispsync"))) {
+ index++;
+ mPrimaryDispSync.dump(result);
+ dumpAll = false;
+ }
}
if (dumpAll) {
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index b161480..90e3f7d 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -27,7 +27,7 @@
using namespace android;
-int main(int argc, char** argv) {
+int main(int, char**) {
// When SF is launched in its own process, limit the number of
// binder threads to 4.
ProcessState::self()->setThreadPoolMaxThreadCount(4);