Merge "Add GL Error logs (temporary)" into jb-mr1-dev
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 923845c..d970a33 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -46,7 +46,8 @@
 	LOCAL_CFLAGS += -DUSE_FENCE_SYNC
 endif
 ifeq ($(TARGET_BOARD_PLATFORM), exynos5)
-	LOCAL_CFLAGS += -DUSE_FENCE_SYNC
+	LOCAL_CFLAGS += -DUSE_NATIVE_FENCE_SYNC
+	LOCAL_CFLAGS += -DUSE_WAIT_SYNC
 endif
 ifneq ($(filter generic%,$(TARGET_DEVICE)),)
     # Emulator build
@@ -57,10 +58,6 @@
 	LOCAL_CFLAGS += -DUSE_NATIVE_FENCE_SYNC
 endif
 
-ifeq ($(TARGET_BOARD_PLATFORM), tegra)
-	LOCAL_CFLAGS += -DALLOW_DEQUEUE_CURRENT_BUFFER
-endif
-
 include $(BUILD_SHARED_LIBRARY)
 
 ifeq (,$(ONE_SHOT_MAKEFILE))
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 8594b84..d408476 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -32,23 +32,6 @@
 #include <gui/SurfaceTexture.h>
 #include <utils/Trace.h>
 
-// This compile option causes SurfaceTexture to return the buffer that is currently
-// attached to the GL texture from dequeueBuffer when no other buffers are
-// available.  It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
-// implicit cross-process synchronization to prevent the buffer from being
-// written to before the buffer has (a) been detached from the GL texture and
-// (b) all GL reads from the buffer have completed.
-
-// During refactoring, do not support dequeuing the current buffer
-#undef ALLOW_DEQUEUE_CURRENT_BUFFER
-
-#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
-#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    true
-#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
-#else
-#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    false
-#endif
-
 // Macros for including the BufferQueue name in log messages
 #define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
 #define ST_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
@@ -325,24 +308,16 @@
                     dequeuedCount++;
                 }
 
-                // this logic used to be if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER)
-                // but dequeuing the current buffer is disabled.
-                if (false) {
-                    // This functionality has been temporarily removed so
-                    // BufferQueue and SurfaceTexture can be refactored into
-                    // separate objects
-                } else {
-                    if (state == BufferSlot::FREE) {
-                        /* We return the oldest of the free buffers to avoid
-                         * stalling the producer if possible.  This is because
-                         * the consumer may still have pending reads of the
-                         * buffers in flight.
-                         */
-                        bool isOlder = mSlots[i].mFrameNumber <
-                                mSlots[found].mFrameNumber;
-                        if (found < 0 || isOlder) {
-                            found = i;
-                        }
+                if (state == BufferSlot::FREE) {
+                    /* We return the oldest of the free buffers to avoid
+                     * stalling the producer if possible.  This is because
+                     * the consumer may still have pending reads of the
+                     * buffers in flight.
+                     */
+                    bool isOlder = mSlots[i].mFrameNumber <
+                            mSlots[found].mFrameNumber;
+                    if (found < 0 || isOlder) {
+                        found = i;
                     }
                 }
             }
diff --git a/libs/gui/CleanSpec.mk b/libs/gui/CleanSpec.mk
index 1713694..c062229 100644
--- a/libs/gui/CleanSpec.mk
+++ b/libs/gui/CleanSpec.mk
@@ -48,3 +48,4 @@
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
 $(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libgui*" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
diff --git a/libs/gui/GuiConfig.cpp b/libs/gui/GuiConfig.cpp
index 0744e4f..bafd21a 100644
--- a/libs/gui/GuiConfig.cpp
+++ b/libs/gui/GuiConfig.cpp
@@ -28,8 +28,8 @@
 #ifdef USE_NATIVE_FENCE_SYNC
             " USE_NATIVE_FENCE_SYNC"
 #endif
-#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
-            " ALLOW_DEQUEUE_CURRENT_BUFFER"
+#ifdef USE_WAIT_SYNC
+            " USE_WAIT_SYNC"
 #endif
             "]";
     configStr.append(config);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 8df1302..57bcd2c 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -63,16 +63,6 @@
 static const bool useWaitSync = false;
 #endif
 
-// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
-// to synchronize access to the buffers.  It will cause dequeueBuffer to stall,
-// waiting for the GL reads for the buffer being dequeued to complete before
-// allowing the buffer to be dequeued.
-#ifdef USE_FENCE_SYNC
-#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
-#error "USE_FENCE_SYNC and ALLOW_DEQUEUE_CURRENT_BUFFER are incompatible"
-#endif
-#endif
-
 // Macros for including the SurfaceTexture name in log messages
 #define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
 #define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index fb93c47..597e5d6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -147,7 +147,7 @@
         // don't need a vsync thread if we have a hardware composer
         needVSyncThread = false;
         // always turn vsync off when we start
-        mHwc->eventControl(mHwc, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
+        eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
 
         // these IDs are always reserved
         for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
@@ -202,7 +202,7 @@
 
 HWComposer::~HWComposer() {
     if (mHwc) {
-        mHwc->eventControl(mHwc, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
+        eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
     }
     if (mVSyncThread != NULL) {
         mVSyncThread->requestExitAndWait();
@@ -443,16 +443,32 @@
     return mDisplayData[disp].connected;
 }
 
-void HWComposer::eventControl(int event, int enabled) {
+void HWComposer::eventControl(int disp, int event, int enabled) {
+    if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) {
+        return;
+    }
     status_t err = NO_ERROR;
-    if (mHwc) {
-        if (!mDebugForceFakeVSync) {
-            err = mHwc->eventControl(mHwc, 0, event, enabled);
-            // error here should not happen -- not sure what we should
-            // do if it does.
-            ALOGE_IF(err, "eventControl(%d, %d) failed %s",
-                    event, enabled, strerror(-err));
+    if (mHwc && !mDebugForceFakeVSync) {
+        // NOTE: we use our own internal lock here because we have to call
+        // into the HWC with the lock held, and we want to make sure
+        // that even if HWC blocks (which it shouldn't), it won't
+        // affect other threads.
+        Mutex::Autolock _l(mEventControlLock);
+        const int32_t eventBit = 1UL << event;
+        const int32_t newValue = enabled ? eventBit : 0;
+        const int32_t oldValue = mDisplayData[disp].events & eventBit;
+        if (newValue != oldValue) {
+            ATRACE_CALL();
+            err = mHwc->eventControl(mHwc, disp, event, enabled);
+            if (!err) {
+                int32_t& events(mDisplayData[disp].events);
+                events = (events & ~eventBit) | newValue;
+            }
         }
+        // error here should not happen -- not sure what we should
+        // do if it does.
+        ALOGE_IF(err, "eventControl(%d, %d) failed %s",
+                event, enabled, strerror(-err));
     }
 
     if (err == NO_ERROR && mVSyncThread != NULL) {
@@ -540,8 +556,13 @@
             // DO NOT reset the handle field to NULL, because it's possible
             // that we have nothing to redraw (eg: eglSwapBuffers() not called)
             // in which case, we should continue to use the same buffer.
+            LOG_FATAL_IF(disp.list == NULL);
             disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
         }
+        if (!disp.connected && disp.list != NULL) {
+            ALOGW("WARNING: disp %d: connected, non-null list, layers=%d",
+                  i, disp.list->numHwLayers);
+        }
         mLists[i] = disp.list;
         if (mLists[i]) {
             if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
@@ -647,16 +668,16 @@
     return (status_t)err;
 }
 
-status_t HWComposer::release(int disp) const {
+status_t HWComposer::release(int disp) {
     LOG_FATAL_IF(disp >= HWC_NUM_DISPLAY_TYPES);
     if (mHwc) {
-        mHwc->eventControl(mHwc, disp, HWC_EVENT_VSYNC, 0);
+        eventControl(disp, HWC_EVENT_VSYNC, 0);
         return (status_t)mHwc->blank(mHwc, disp, 1);
     }
     return NO_ERROR;
 }
 
-status_t HWComposer::acquire(int disp) const {
+status_t HWComposer::acquire(int disp) {
     LOG_FATAL_IF(disp >= HWC_NUM_DISPLAY_TYPES);
     if (mHwc) {
         return (status_t)mHwc->blank(mHwc, disp, 0);
@@ -664,6 +685,17 @@
     return NO_ERROR;
 }
 
+void HWComposer::disconnectDisplay(int disp) {
+    LOG_ALWAYS_FATAL_IF(disp < 0 || disp == HWC_DISPLAY_PRIMARY ||
+                        disp >= HWC_NUM_DISPLAY_TYPES);
+    DisplayData& dd(mDisplayData[disp]);
+    if (dd.list != NULL) {
+        free(dd.list);
+        dd.list = NULL;
+        dd.framebufferTarget = NULL;    // points into dd.list
+    }
+}
+
 int HWComposer::getVisualID() const {
     if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
         // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
@@ -949,8 +981,10 @@
 
 void HWComposer::VSyncThread::setEnabled(bool enabled) {
     Mutex::Autolock _l(mLock);
-    mEnabled = enabled;
-    mCondition.signal();
+    if (mEnabled != enabled) {
+        mEnabled = enabled;
+        mCondition.signal();
+    }
 }
 
 void HWComposer::VSyncThread::onFirstRef() {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 633ca9c..269e147 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -92,10 +92,13 @@
     status_t commit();
 
     // release hardware resources and blank screen
-    status_t release(int disp) const;
+    status_t release(int disp);
 
     // acquire hardware resources and unblank screen
-    status_t acquire(int disp) const;
+    status_t acquire(int disp);
+
+    // reset state when an external, non-virtual display is disconnected
+    void disconnectDisplay(int disp);
 
     // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
     status_t createWorkList(int32_t id, size_t numLayers);
@@ -223,7 +226,7 @@
         EVENT_VSYNC = HWC_EVENT_VSYNC
     };
 
-    void eventControl(int event, int enabled);
+    void eventControl(int disp, int event, int enabled);
 
     // Query display parameters.  Pass in a display index (e.g.
     // HWC_DISPLAY_PRIMARY).
@@ -286,7 +289,7 @@
         DisplayData() : xdpi(0), ydpi(0), refresh(0),
             connected(false), hasFbComp(false), hasOvComp(false),
             capacity(0), list(NULL),
-            framebufferTarget(NULL), fbTargetHandle(NULL) { }
+            framebufferTarget(NULL), fbTargetHandle(NULL), events(0) { }
         ~DisplayData() {
             free(list);
         }
@@ -303,6 +306,8 @@
         hwc_display_contents_1* list;
         hwc_layer_1* framebufferTarget;
         buffer_handle_t fbTargetHandle;
+        // protected by mEventControlLock
+        int32_t events;
     };
 
     sp<SurfaceFlinger>              mFlinger;
@@ -324,6 +329,9 @@
     // protected by mLock
     mutable Mutex mLock;
     mutable nsecs_t mLastHwVSync;
+
+    // thread-safe
+    mutable Mutex mEventControlLock;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 6b7c78b..edb9fa5 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -308,14 +308,14 @@
 void EventThread::enableVSyncLocked() {
     if (!mUseSoftwareVSync) {
         // never enable h/w VSYNC when screen is off
-        mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, true);
+        mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
         mPowerHAL.vsyncHint(true);
     }
     mDebugVsyncEnabled = true;
 }
 
 void EventThread::disableVSyncLocked() {
-    mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, false);
+    mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false);
     mPowerHAL.vsyncHint(false);
     mDebugVsyncEnabled = false;
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a8d20bb..1103175 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -777,8 +777,8 @@
     }
 }
 
-void SurfaceFlinger::eventControl(int event, int enabled) {
-    getHwComposer().eventControl(event, enabled);
+void SurfaceFlinger::eventControl(int disp, int event, int enabled) {
+    getHwComposer().eventControl(disp, event, enabled);
 }
 
 void SurfaceFlinger::onMessageReceived(int32_t what) {
@@ -1123,7 +1123,13 @@
                 if (j < 0) {
                     // in drawing state but not in current state
                     if (!draw[i].isMainDisplay()) {
+                        // Call makeCurrent() on the primary display so we can
+                        // be sure that nothing associated with this display
+                        // is current.
+                        const sp<const DisplayDevice>& hw(getDefaultDisplayDevice());
+                        DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext);
                         mDisplays.removeItem(draw.keyAt(i));
+                        getHwComposer().disconnectDisplay(draw[i].type);
                     } else {
                         ALOGW("trying to remove the main display");
                     }
@@ -1701,8 +1707,12 @@
 
 uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
 {
+    ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token);
+    if (dpyIdx < 0)
+        return 0;
+
     uint32_t flags = 0;
-    DisplayDeviceState& disp(mCurrentState.displays.editValueFor(s.token));
+    DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx));
     if (disp.isValid()) {
         const uint32_t what = s.what;
         if (what & DisplayState::eSurfaceChanged) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8272848..5bb3703 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -123,7 +123,7 @@
 
     // enable/disable h/w composer event
     // TODO: this should be made accessible only to EventThread
-    void eventControl(int event, int enabled);
+    void eventControl(int disp, int event, int enabled);
 
     // called on the main thread by MessageQueue when an internal message
     // is received