summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/dumpstate/dumpstate.c9
-rw-r--r--include/ui/GraphicBufferAllocator.h1
-rw-r--r--include/utils/Trace.h2
-rw-r--r--libs/gui/BufferQueue.cpp5
-rw-r--r--libs/ui/GraphicBufferAllocator.cpp131
-rw-r--r--libs/utils/Trace.cpp4
-rw-r--r--opengl/libs/EGL/egl.cpp6
-rw-r--r--opengl/specs/EGL_ANDROID_native_fence_sync.txt21
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp7
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.h1
-rw-r--r--services/surfaceflinger/Layer.cpp12
-rw-r--r--services/surfaceflinger/Layer.h4
-rw-r--r--services/surfaceflinger/LayerBase.cpp1
-rw-r--r--services/surfaceflinger/LayerBase.h2
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp69
15 files changed, 220 insertions, 55 deletions
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index f3fcca0..8718bb6 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -188,6 +188,12 @@ static void dumpstate() {
run_command("WIFI NETWORKS", 20,
SU_PATH, "root", "wpa_cli", "list_networks", NULL);
+#ifdef FWDUMP_bcmdhd
+ run_command("DUMP WIFI INTERNAL COUNTERS", 20,
+ SU_PATH, "root", "wlutil", "counters", NULL);
+#endif
+ dump_file("INTERRUPTS (1)", "/proc/interrupts");
+
property_get("dhcp.wlan0.gateway", network, "");
if (network[0])
run_command("PING GATEWAY", 10, SU_PATH, "root", "ping", "-c", "3", "-i", ".5", network, NULL);
@@ -197,12 +203,13 @@ static void dumpstate() {
property_get("dhcp.wlan0.dns2", network, "");
if (network[0])
run_command("PING DNS2", 10, SU_PATH, "root", "ping", "-c", "3", "-i", ".5", network, NULL);
-#ifdef FWDUMP_bcm4329
+#ifdef FWDUMP_bcmdhd
run_command("DUMP WIFI STATUS", 20,
SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
run_command("DUMP WIFI INTERNAL COUNTERS", 20,
SU_PATH, "root", "wlutil", "counters", NULL);
#endif
+ dump_file("INTERRUPTS (2)", "/proc/interrupts");
print_properties();
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
index 0f2a492..6342aac 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/include/ui/GraphicBufferAllocator.h
@@ -87,6 +87,7 @@ private:
static KeyedVector<buffer_handle_t, alloc_rec_t> sAllocList;
friend class Singleton<GraphicBufferAllocator>;
+ friend class BufferLiberatorThread;
GraphicBufferAllocator();
~GraphicBufferAllocator();
diff --git a/include/utils/Trace.h b/include/utils/Trace.h
index 93e2285..41bce00 100644
--- a/include/utils/Trace.h
+++ b/include/utils/Trace.h
@@ -54,6 +54,8 @@
#define ATRACE_TAG_CAMERA (1<<10)
#define ATRACE_TAG_LAST ATRACE_TAG_CAMERA
+#define ATRACE_TAG_NOT_READY (1LL<<63) // Reserved for use during init
+
#define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST)
#ifndef ATRACE_TAG
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 590946a..086e298 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -314,9 +314,8 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
* the consumer may still have pending reads of the
* buffers in flight.
*/
- bool isOlder = mSlots[i].mFrameNumber <
- mSlots[found].mFrameNumber;
- if (found < 0 || isOlder) {
+ if ((found < 0) ||
+ mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
found = i;
}
}
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index c1b246f..2ea5696 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -90,6 +90,105 @@ void GraphicBufferAllocator::dumpToSystemLog()
ALOGD("%s", s.string());
}
+class BufferLiberatorThread : public Thread {
+public:
+
+ static void queueCaptiveBuffer(buffer_handle_t handle) {
+ size_t queueSize;
+ {
+ Mutex::Autolock lock(sMutex);
+ if (sThread == NULL) {
+ sThread = new BufferLiberatorThread;
+ sThread->run("BufferLiberator");
+ }
+
+ sThread->mQueue.push_back(handle);
+ sThread->mQueuedCondition.signal();
+ queueSize = sThread->mQueue.size();
+ }
+ }
+
+ static void waitForLiberation() {
+ Mutex::Autolock lock(sMutex);
+
+ waitForLiberationLocked();
+ }
+
+ static void maybeWaitForLiberation() {
+ Mutex::Autolock lock(sMutex);
+ if (sThread != NULL) {
+ if (sThread->mQueue.size() > 8) {
+ waitForLiberationLocked();
+ }
+ }
+ }
+
+private:
+
+ BufferLiberatorThread() {}
+
+ virtual bool threadLoop() {
+ buffer_handle_t handle;
+ { // Scope for mutex
+ Mutex::Autolock lock(sMutex);
+ while (mQueue.isEmpty()) {
+ mQueuedCondition.wait(sMutex);
+ }
+ handle = mQueue[0];
+ }
+
+ status_t err;
+ GraphicBufferAllocator& gba(GraphicBufferAllocator::get());
+ { // Scope for tracing
+ ATRACE_NAME("gralloc::free");
+ err = gba.mAllocDev->free(gba.mAllocDev, handle);
+ }
+ ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
+
+ if (err == NO_ERROR) {
+ Mutex::Autolock _l(GraphicBufferAllocator::sLock);
+ KeyedVector<buffer_handle_t, GraphicBufferAllocator::alloc_rec_t>&
+ list(GraphicBufferAllocator::sAllocList);
+ list.removeItem(handle);
+ }
+
+ { // Scope for mutex
+ Mutex::Autolock lock(sMutex);
+ mQueue.removeAt(0);
+ mFreedCondition.broadcast();
+ }
+
+ return true;
+ }
+
+ static void waitForLiberationLocked() {
+ if (sThread == NULL) {
+ return;
+ }
+
+ const nsecs_t timeout = 500 * 1000 * 1000;
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t timeToStop = now + timeout;
+ while (!sThread->mQueue.isEmpty() && now < timeToStop) {
+ sThread->mFreedCondition.waitRelative(sMutex, timeToStop - now);
+ now = systemTime(SYSTEM_TIME_MONOTONIC);
+ }
+
+ if (!sThread->mQueue.isEmpty()) {
+ ALOGW("waitForLiberationLocked timed out");
+ }
+ }
+
+ static Mutex sMutex;
+ static sp<BufferLiberatorThread> sThread;
+ Vector<buffer_handle_t> mQueue;
+ Condition mQueuedCondition;
+ Condition mFreedCondition;
+};
+
+Mutex BufferLiberatorThread::sMutex;
+sp<BufferLiberatorThread> BufferLiberatorThread::sThread;
+
status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
int usage, buffer_handle_t* handle, int32_t* stride)
{
@@ -100,7 +199,6 @@ status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat forma
w = h = 1;
// we have a h/w allocator and h/w buffer is requested
- status_t err;
#ifdef EXYNOS4_ENHANCEMENTS
if ((format == 0x101) || (format == 0x105) || (format == 0x107)) {
@@ -111,11 +209,24 @@ status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat forma
}
#endif
+ status_t err;
+
+ // If too many async frees are queued up then wait for some of them to
+ // complete before attempting to allocate more memory. This is exercised
+ // by the android.opengl.cts.GLSurfaceViewTest CTS test.
+ BufferLiberatorThread::maybeWaitForLiberation();
+
err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
+ if (err != NO_ERROR) {
+ ALOGW("WOW! gralloc alloc failed, waiting for pending frees!");
+ BufferLiberatorThread::waitForLiberation();
+ err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
+ }
+
ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
w, h, format, usage, err, strerror(-err));
-
+
if (err == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
@@ -138,21 +249,11 @@ status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat forma
return err;
}
+
status_t GraphicBufferAllocator::free(buffer_handle_t handle)
{
- ATRACE_CALL();
- status_t err;
-
- err = mAllocDev->free(mAllocDev, handle);
-
- ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
- if (err == NO_ERROR) {
- Mutex::Autolock _l(sLock);
- KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
- list.removeItem(handle);
- }
-
- return err;
+ BufferLiberatorThread::queueCaptiveBuffer(handle);
+ return NO_ERROR;
}
// ---------------------------------------------------------------------------
diff --git a/libs/utils/Trace.cpp b/libs/utils/Trace.cpp
index 5cd5731..f5aaea3 100644
--- a/libs/utils/Trace.cpp
+++ b/libs/utils/Trace.cpp
@@ -25,7 +25,7 @@ namespace android {
volatile int32_t Tracer::sIsReady = 0;
int Tracer::sTraceFD = -1;
-uint64_t Tracer::sEnabledTags = 0;
+uint64_t Tracer::sEnabledTags = ATRACE_TAG_NOT_READY;
Mutex Tracer::sMutex;
void Tracer::changeCallback() {
@@ -46,7 +46,7 @@ void Tracer::init() {
sTraceFD = open(traceFileName, O_WRONLY);
if (sTraceFD == -1) {
ALOGE("error opening trace file: %s (%d)", strerror(errno), errno);
- // sEnabledTags remains zero indicating that no tracing can occur
+ sEnabledTags = 0; // no tracing can occur
} else {
loadSystemProperty();
}
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 96e1cba..0d4bed5 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -124,6 +124,12 @@ void initEglTraceLevel() {
void initEglDebugLevel() {
int propertyLevel = 0;
char value[PROPERTY_VALUE_MAX];
+
+ // check system property only on userdebug or eng builds
+ property_get("ro.debuggable", value, "0");
+ if (value[0] == '0')
+ return;
+
property_get("debug.egl.debug_proc", value, "");
if (strlen(value) > 0) {
long pid = getpid();
diff --git a/opengl/specs/EGL_ANDROID_native_fence_sync.txt b/opengl/specs/EGL_ANDROID_native_fence_sync.txt
index 8273be4..ee05b40 100644
--- a/opengl/specs/EGL_ANDROID_native_fence_sync.txt
+++ b/opengl/specs/EGL_ANDROID_native_fence_sync.txt
@@ -100,10 +100,10 @@ Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
EGL_SYNC_TYPE_KHR EGL_SYNC_NATIVE_FENCE_ANDROID
EGL_SYNC_STATUS_KHR EGL_UNSIGNALED_KHR
EGL_SYNC_CONDITION_KHR EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR
- EGL_SYNC_NATIVE_FENCE_FD_ANDROID EGL_NO_NATIVE_FENCE_ANDROID
+ EGL_SYNC_NATIVE_FENCE_FD_ANDROID EGL_NO_NATIVE_FENCE_FD_ANDROID
If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute is not
- EGL_NO_NATIVE_FENCE_ANDROID then the EGL_SYNC_CONDITION_KHR attribute is
+ EGL_NO_NATIVE_FENCE_FD_ANDROID then the EGL_SYNC_CONDITION_KHR attribute is
set to EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID and the EGL_SYNC_STATUS_KHR
attribute is set to reflect the signal status of the native fence object.
Additionally, the EGL implementation assumes ownership of the file
@@ -114,7 +114,7 @@ Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
"When a fence sync object is created or when an EGL native fence sync
object is created with the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute set
- to EGL_NO_NATIVE_FENCE_ANDROID, eglCreateSyncKHR also inserts a fence
+ to EGL_NO_NATIVE_FENCE_FD_ANDROID, eglCreateSyncKHR also inserts a fence
command into the command stream of the bound client API's current context
(i.e., the context returned by eglGetCurrentContext), and associates it
with the newly created sync object.
@@ -157,8 +157,9 @@ Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
empty (containing only EGL_NONE), EGL_NO_SYNC_KHR is returned and an
EGL_BAD_ATTRIBUTE error is generated.
* If <type> is EGL_SYNC_NATIVE_FENCE_ANDROID and <attrib_list> contains
- an attribute other than EGL_SYNC_NATIVE_FENCE_FD_ANDROID, EGL_NO_SYNC_KHR is
- returned and an EGL_BAD_ATTRIBUTE error is generated.
+ an attribute other than EGL_SYNC_NATIVE_FENCE_FD_ANDROID,
+ EGL_NO_SYNC_KHR is returned and an EGL_BAD_ATTRIBUTE error is
+ generated.
* If <type> is not a supported type of sync object,
EGL_NO_SYNC_KHR is returned and an EGL_BAD_ATTRIBUTE error is
generated.
@@ -193,8 +194,8 @@ Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
"If no errors are generated, EGL_TRUE is returned, and <sync> will no
longer be the handle of a valid sync object. Additionally, if <sync> is an
EGL native fence sync object and the EGL_SYNC_NATIVE_FENCE_FD_ANDROID
- attribute is not EGL_NO_NATIVE_FENCE_ANDROID then that file descriptor is
- closed."
+ attribute is not EGL_NO_NATIVE_FENCE_FD_ANDROID then that file descriptor
+ is closed."
Add the following after the last paragraph of Section 3.8.1 (Sync
Objects), added by KHR_fence_sync
@@ -213,11 +214,11 @@ Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
------
* If <sync> is not a valid sync object for <dpy>,
- EGL_NO_NATIVE_FENCE_ANDROID is returned and an EGL_BAD_PARAMETER
+ EGL_NO_NATIVE_FENCE_FD_ANDROID is returned and an EGL_BAD_PARAMETER
error is generated.
* If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute of <sync> is
- EGL_NO_NATIVE_FENCE_ANDROID, EGL_NO_NATIVE_FENCE_ANDROID is returned
- and an EGL_BAD_PARAMETER error is generated.
+ EGL_NO_NATIVE_FENCE_FD_ANDROID, EGL_NO_NATIVE_FENCE_FD_ANDROID is
+ returned and an EGL_BAD_PARAMETER error is generated.
* If <dpy> does not match the display passed to eglCreateSyncKHR
when <sync> was created, the behaviour is undefined."
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 379fb16..3ed8d97 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -1000,6 +1000,9 @@ public:
getLayer()->visibleRegionScreen.numRects = 0;
getLayer()->visibleRegionScreen.rects = NULL;
}
+ virtual void setPerFrameDefaultState() {
+ //getLayer()->compositionType = HWC_FRAMEBUFFER;
+ }
virtual void setSkip(bool skip) {
if (skip) {
getLayer()->flags |= HWC_SKIP_LAYER;
@@ -1073,7 +1076,9 @@ public:
virtual void setAcquireFenceFd(int fenceFd) {
getLayer()->acquireFenceFd = fenceFd;
}
-
+ virtual void setPerFrameDefaultState() {
+ //getLayer()->compositionType = HWC_FRAMEBUFFER;
+ }
virtual void setDefaultState() {
getLayer()->compositionType = HWC_FRAMEBUFFER;
getLayer()->hints = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index a78ffac..7c67407 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -141,6 +141,7 @@ public:
virtual int32_t getCompositionType() const = 0;
virtual uint32_t getHints() const = 0;
virtual int getAndResetReleaseFenceFd() = 0;
+ virtual void setPerFrameDefaultState() = 0;
virtual void setDefaultState() = 0;
virtual void setSkip(bool skip) = 0;
virtual void setBlending(uint32_t blending) = 0;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 064f689..7edbdc5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -110,7 +110,8 @@ void Layer::onFirstRef()
mSurfaceTexture->setDefaultMaxBufferCount(3);
#endif
- updateTransformHint();
+ const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
+ updateTransformHint(hw);
}
Layer::~Layer()
@@ -767,15 +768,12 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const
return usage;
}
-void Layer::updateTransformHint() const {
+void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const {
uint32_t orientation = 0;
if (!mFlinger->mDebugDisableTransformHint) {
- // The transform hint is used to improve performance on the main
- // display -- we can only have a single transform hint, it cannot
+ // The transform hint is used to improve performance, but we can
+ // only have a single transform hint, it cannot
// apply to all displays.
- // This is why we use the default display here. This is not an
- // oversight.
- sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
const Transform& planeTransform(hw->getTransform());
orientation = planeTransform.getOrientation();
if (orientation & Transform::ROT_INVALID) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6f75d8c..c5eb26b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -91,8 +91,8 @@ public:
inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
// Updates the transform hint in our SurfaceTexture to match
- // the current orientation of the default display device.
- virtual void updateTransformHint() const;
+ // the current orientation of the display device.
+ virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const;
protected:
virtual void onFirstRef();
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index db4ef87..9b03c74 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -300,6 +300,7 @@ void LayerBase::setGeometry(
void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer) {
+ layer.setPerFrameDefaultState();
// we have to set the visible region on every frame because
// we currently free it during onLayerDisplayed(), which is called
// after HWComposer::commit() -- every frame.
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 00c4ffe..4d5a5b0 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -246,7 +246,7 @@ public:
* Updates the SurfaceTexture's transform hint, for layers that have
* a SurfaceTexture.
*/
- virtual void updateTransformHint() const { }
+ virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const { }
/** always call base class first */
virtual void dump(String8& result, char* scratch, size_t size) const;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 67b1316..00efd49 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1092,7 +1092,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
if (transactionFlags & eTraversalNeeded) {
for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer = currentLayers[i];
+ const sp<LayerBase>& layer(currentLayers[i]);
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
@@ -1165,18 +1165,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
disp->setProjection(state.orientation,
state.viewport, state.frame);
}
-
- // Walk through all the layers in currentLayers,
- // and update their transform hint.
- //
- // TODO: we could be much more clever about which
- // layers we touch and how often we do these updates
- // (e.g. only touch the layers associated with this
- // display, and only on a rotation).
- for (size_t i = 0; i < count; i++) {
- const sp<LayerBase>& layerBase = currentLayers[i];
- layerBase->updateTransformHint();
- }
}
}
}
@@ -1231,6 +1219,61 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
}
}
+ if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
+ // The transform hint might have changed for some layers
+ // (either because a display has changed, or because a layer
+ // as changed).
+ //
+ // Walk through all the layers in currentLayers,
+ // and update their transform hint.
+ //
+ // If a layer is visible only on a single display, then that
+ // display is used to calculate the hint, otherwise we use the
+ // default display.
+ //
+ // NOTE: we do this here, rather than in rebuildLayerStacks() so that
+ // the hint is set before we acquire a buffer from the surface texture.
+ //
+ // NOTE: layer transactions have taken place already, so we use their
+ // drawing state. However, SurfaceFlinger's own transaction has not
+ // happened yet, so we must use the current state layer list
+ // (soon to become the drawing state list).
+ //
+ sp<const DisplayDevice> disp;
+ uint32_t currentlayerStack = 0;
+ for (size_t i=0; i<count; i++) {
+ // NOTE: we rely on the fact that layers are sorted by
+ // layerStack first (so we don't have to traverse the list
+ // of displays for every layer).
+ const sp<LayerBase>& layerBase(currentLayers[i]);
+ uint32_t layerStack = layerBase->drawingState().layerStack;
+ if (i==0 || currentlayerStack != layerStack) {
+ currentlayerStack = layerStack;
+ // figure out if this layerstack is mirrored
+ // (more than one display) if so, pick the default display,
+ // if not, pick the only display it's on.
+ disp.clear();
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> hw(mDisplays[dpy]);
+ if (hw->getLayerStack() == currentlayerStack) {
+ if (disp == NULL) {
+ disp = hw;
+ } else {
+ disp = getDefaultDisplayDevice();
+ break;
+ }
+ }
+ }
+ }
+ if (disp != NULL) {
+ // presumably this means this layer is using a layerStack
+ // that is not visible on any display
+ layerBase->updateTransformHint(disp);
+ }
+ }
+ }
+
+
/*
* Perform our own transaction if needed
*/