diff options
-rw-r--r-- | cmds/dumpstate/dumpstate.c | 9 | ||||
-rw-r--r-- | include/ui/GraphicBufferAllocator.h | 1 | ||||
-rw-r--r-- | include/utils/Trace.h | 2 | ||||
-rw-r--r-- | libs/gui/BufferQueue.cpp | 5 | ||||
-rw-r--r-- | libs/ui/GraphicBufferAllocator.cpp | 131 | ||||
-rw-r--r-- | libs/utils/Trace.cpp | 4 | ||||
-rw-r--r-- | opengl/libs/EGL/egl.cpp | 6 | ||||
-rw-r--r-- | opengl/specs/EGL_ANDROID_native_fence_sync.txt | 21 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/HWComposer.cpp | 7 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/HWComposer.h | 1 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.cpp | 12 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.h | 4 | ||||
-rw-r--r-- | services/surfaceflinger/LayerBase.cpp | 1 | ||||
-rw-r--r-- | services/surfaceflinger/LayerBase.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 69 |
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 */ |