Merge "Always reset layer acquireFenceFd after commit" into jb-mr1-dev
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 06cd3da..0f5c14a 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -93,6 +93,10 @@
 
     ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY = 0x0000,
 
+    ACONFIGURATION_LAYOUTDIR_ANY  = 0x00,
+    ACONFIGURATION_LAYOUTDIR_LTR  = 0x01,
+    ACONFIGURATION_LAYOUTDIR_RTL  = 0x02,
+
     ACONFIGURATION_MCC = 0x0001,
     ACONFIGURATION_MNC = 0x0002,
     ACONFIGURATION_LOCALE = 0x0004,
@@ -107,6 +111,7 @@
     ACONFIGURATION_SCREEN_LAYOUT = 0x0800,
     ACONFIGURATION_UI_MODE = 0x1000,
     ACONFIGURATION_SMALLEST_SCREEN_SIZE = 0x2000,
+    ACONFIGURATION_LAYOUTDIR = 0x4000,
 };
 
 /**
@@ -331,6 +336,17 @@
 void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value);
 
 /**
+ * Return the configuration's layout direction, or
+ * ACONFIGURATION_LAYOUTDIR_ANY if not set.
+ */
+int32_t AConfiguration_getLayoutDirection(AConfiguration* config);
+
+/**
+ * Set the configuration's layout direction.
+ */
+void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value);
+
+/**
  * Perform a diff between two configurations.  Returns a bit mask of
  * ACONFIGURATION_* constants, each bit set meaning that configuration element
  * is different between them.
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 0a95bb3..3481c6f 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -41,6 +41,10 @@
     enum { INVALID_BUFFER_SLOT = -1 };
     enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE };
 
+    // When in async mode we reserve two slots in order to guarantee that the
+    // producer and consumer can run asynchronously.
+    enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 };
+
     // ConsumerListener is the interface through which the BufferQueue notifies
     // the consumer of events that the consumer may wish to react to.  Because
     // the consumer will generally have a mutex that is locked during calls from
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 8b4025d..ae7c5c2 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -39,9 +39,6 @@
 public:
     DECLARE_META_INTERFACE(SurfaceTexture);
 
-protected:
-    friend class SurfaceTextureClient;
-
     enum {
         BUFFER_NEEDS_REALLOCATION = 0x1,
         RELEASE_ALL_BUFFERS       = 0x2,
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index a143d81..57c72c9 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -121,11 +121,21 @@
             const sp<ISurfaceTexture>& surface);
     static void setDisplayLayerStack(const sp<IBinder>& token,
             uint32_t layerStack);
-    static void setDisplayOrientation(const sp<IBinder>& token,
-            uint32_t orientation);
-    static void setDisplayViewport(const sp<IBinder>& token,
-            const Rect& viewport);
-    static void setDisplayFrame(const sp<IBinder>& token, const Rect& frame);
+
+    /* setDisplayProjection() defines the projection of layer stacks
+     * to a given display.
+     *
+     * - orientation defines the display's orientation.
+     * - layerStackRect defines which area of the window manager coordinate
+     * space will be used.
+     * - displayRect defines where on the display will layerStackRect be
+     * mapped to. displayRect is specified post-orientation, that is
+     * it uses the orientation seen by the end-user.
+     */
+    static void setDisplayProjection(const sp<IBinder>& token,
+            uint32_t orientation,
+            const Rect& layerStackRect,
+            const Rect& displayRect);
 
 private:
     virtual void onFirstRef();
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 65d9eb3..a7eb48c 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -107,11 +107,9 @@
     };
 
     enum {
-        eSurfaceChanged     = 0x01,
-        eLayerStackChanged  = 0x02,
-        eOrientationChanged = 0x04,
-        eViewportChanged    = 0x08,
-        eFrameChanged       = 0x10
+        eSurfaceChanged             = 0x01,
+        eLayerStackChanged          = 0x02,
+        eDisplayProjectionChanged   = 0x04
     };
 
     uint32_t what;
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 4640149..2eee6f5 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -974,6 +974,11 @@
 status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
     ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
+    if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) {
+        ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d",
+                maxAcquiredBuffers);
+        return BAD_VALUE;
+    }
     if (mConnectedApi != NO_CONNECTED_API) {
         return INVALID_OPERATION;
     }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e4922a4..814036e 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -119,9 +119,10 @@
 
     void setDisplaySurface(const sp<IBinder>& token, const sp<ISurfaceTexture>& surface);
     void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
-    void setDisplayOrientation(const sp<IBinder>& token, uint32_t orientation);
-    void setDisplayViewport(const sp<IBinder>& token, const Rect& viewport);
-    void setDisplayFrame(const sp<IBinder>& token, const Rect& frame);
+    void setDisplayProjection(const sp<IBinder>& token,
+            uint32_t orientation,
+            const Rect& layerStackRect,
+            const Rect& displayRect);
 
     static void closeGlobalTransaction(bool synchronous) {
         Composer::getInstance().closeGlobalTransactionImpl(synchronous);
@@ -326,39 +327,19 @@
     s.what |= DisplayState::eLayerStackChanged;
 }
 
-void Composer::setDisplayOrientation(const sp<IBinder>& token,
-        uint32_t orientation) {
+void Composer::setDisplayProjection(const sp<IBinder>& token,
+        uint32_t orientation,
+        const Rect& layerStackRect,
+        const Rect& displayRect) {
     Mutex::Autolock _l(mLock);
     DisplayState& s(getDisplayStateLocked(token));
     s.orientation = orientation;
-    s.what |= DisplayState::eOrientationChanged;
+    s.viewport = layerStackRect;
+    s.frame = displayRect;
+    s.what |= DisplayState::eDisplayProjectionChanged;
     mForceSynchronous = true; // TODO: do we actually still need this?
 }
 
-// FIXME: get rid of this eventually
-status_t Composer::setOrientation(int orientation) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    sp<IBinder> token(sm->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-    Composer::setDisplayOrientation(token, orientation);
-    return NO_ERROR;
-}
-
-void Composer::setDisplayViewport(const sp<IBinder>& token,
-        const Rect& viewport) {
-    Mutex::Autolock _l(mLock);
-    DisplayState& s(getDisplayStateLocked(token));
-    s.viewport = viewport;
-    s.what |= DisplayState::eViewportChanged;
-}
-
-void Composer::setDisplayFrame(const sp<IBinder>& token,
-        const Rect& frame) {
-    Mutex::Autolock _l(mLock);
-    DisplayState& s(getDisplayStateLocked(token));
-    s.frame = frame;
-    s.what |= DisplayState::eFrameChanged;
-}
-
 // ---------------------------------------------------------------------------
 
 SurfaceComposerClient::SurfaceComposerClient()
@@ -520,19 +501,12 @@
     Composer::getInstance().setDisplayLayerStack(token, layerStack);
 }
 
-void SurfaceComposerClient::setDisplayOrientation(const sp<IBinder>& token,
-        uint32_t orientation) {
-    Composer::getInstance().setDisplayOrientation(token, orientation);
-}
-
-void SurfaceComposerClient::setDisplayViewport(const sp<IBinder>& token,
-        const Rect& viewport) {
-    Composer::getInstance().setDisplayViewport(token, viewport);
-}
-
-void SurfaceComposerClient::setDisplayFrame(const sp<IBinder>& token,
-        const Rect& frame) {
-    Composer::getInstance().setDisplayFrame(token, frame);
+void SurfaceComposerClient::setDisplayProjection(const sp<IBinder>& token,
+        uint32_t orientation,
+        const Rect& layerStackRect,
+        const Rect& displayRect) {
+    Composer::getInstance().setDisplayProjection(token, orientation,
+            layerStackRect, displayRect);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
index e8863d3..4a6f74f 100644
--- a/libs/gui/tests/Android.mk
+++ b/libs/gui/tests/Android.mk
@@ -7,6 +7,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := \
+    BufferQueue_test.cpp \
     CpuConsumer_test.cpp \
     SurfaceTextureClient_test.cpp \
     SurfaceTexture_test.cpp \
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
new file mode 100644
index 0000000..817abb4
--- /dev/null
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BufferQueue_test"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/FramebufferNativeWindow.h>
+
+#include <gui/BufferQueue.h>
+
+namespace android {
+
+class BufferQueueTest : public ::testing::Test {
+protected:
+
+    BufferQueueTest() {}
+
+    virtual void SetUp() {
+        const ::testing::TestInfo* const testInfo =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
+                testInfo->name());
+
+        mBQ = new BufferQueue();
+    }
+
+    virtual void TearDown() {
+        mBQ.clear();
+
+        const ::testing::TestInfo* const testInfo =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGV("End test:   %s.%s", testInfo->test_case_name(),
+                testInfo->name());
+    }
+
+    sp<BufferQueue> mBQ;
+};
+
+struct DummyConsumer : public BufferQueue::ConsumerListener {
+    virtual void onFrameAvailable() {}
+    virtual void onBuffersReleased() {}
+};
+
+TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
+    sp<DummyConsumer> dc(new DummyConsumer);
+    mBQ->consumerConnect(dc);
+    ISurfaceTexture::QueueBufferOutput qbo;
+    mBQ->connect(NATIVE_WINDOW_API_CPU, &qbo);
+    mBQ->setBufferCount(4);
+
+    int slot;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buf;
+    ISurfaceTexture::QueueBufferInput qbi(0, Rect(0, 0, 1, 1),
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, fence);
+    BufferQueue::BufferItem item;
+
+    for (int i = 0; i < 2; i++) {
+        ASSERT_EQ(ISurfaceTexture::BUFFER_NEEDS_REALLOCATION,
+                mBQ->dequeueBuffer(&slot, fence, 1, 1, 0,
+                    GRALLOC_USAGE_SW_READ_OFTEN));
+        ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
+        ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
+        ASSERT_EQ(OK, mBQ->acquireBuffer(&item));
+    }
+
+    ASSERT_EQ(ISurfaceTexture::BUFFER_NEEDS_REALLOCATION,
+            mBQ->dequeueBuffer(&slot, fence, 1, 1, 0,
+                GRALLOC_USAGE_SW_READ_OFTEN));
+    ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
+    ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
+
+    // Acquire the third buffer, which should fail.
+    ASSERT_EQ(INVALID_OPERATION, mBQ->acquireBuffer(&item));
+}
+
+TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) {
+    sp<DummyConsumer> dc(new DummyConsumer);
+    mBQ->consumerConnect(dc);
+
+    ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(0));
+    ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(-3));
+    ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(
+            BufferQueue::MAX_MAX_ACQUIRED_BUFFERS+1));
+    ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(100));
+}
+
+TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) {
+    sp<DummyConsumer> dc(new DummyConsumer);
+    mBQ->consumerConnect(dc);
+
+    ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(1));
+    ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(2));
+    ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(
+            BufferQueue::MAX_MAX_ACQUIRED_BUFFERS));
+}
+
+} // namespace android
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 371fb8b..72a36bf 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -339,7 +339,9 @@
     ASSERT_NO_ERROR(err, "queueBuffer error:");
 };
 
-TEST_P(CpuConsumerTest, FromCpuSingle) {
+// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not
+// supported on all devices.
+TEST_P(CpuConsumerTest, DISABLED_FromCpuSingle) {
     status_t err;
     CpuConsumerTestParams params = GetParam();
 
@@ -371,7 +373,9 @@
     mCC->unlockBuffer(b);
 }
 
-TEST_P(CpuConsumerTest, FromCpuManyInQueue) {
+// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not
+// supported on all devices.
+TEST_P(CpuConsumerTest, DISABLED_FromCpuManyInQueue) {
     status_t err;
     CpuConsumerTestParams params = GetParam();
 
@@ -412,7 +416,9 @@
     }
 }
 
-TEST_P(CpuConsumerTest, FromCpuLockMax) {
+// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not
+// supported on all devices.
+TEST_P(CpuConsumerTest, DISABLED_FromCpuLockMax) {
     status_t err;
     CpuConsumerTestParams params = GetParam();
 
diff --git a/opengl/specs/EGL_ANDROID_fence_sync.txt b/opengl/specs/EGL_ANDROID_native_fence_sync.txt
similarity index 64%
rename from opengl/specs/EGL_ANDROID_fence_sync.txt
rename to opengl/specs/EGL_ANDROID_native_fence_sync.txt
index 316ee1c..bd1cdda 100644
--- a/opengl/specs/EGL_ANDROID_fence_sync.txt
+++ b/opengl/specs/EGL_ANDROID_native_fence_sync.txt
@@ -1,10 +1,10 @@
 Name
 
-    ANDROID_fence_sync
+    ANDROID_native_fence_sync
 
 Name Strings
 
-    EGL_ANDROID_fence_sync
+    EGL_ANDROID_native_fence_sync
 
 Contributors
 
@@ -37,10 +37,17 @@
 Overview
 
     This extension enables the creation of EGL fence sync objects that are
-    associated with an Android Sync HAL fence object.  These EGL fence sync
-    objects have nearly identical semantics to those defined by the
-    KHR_fence_sync extension, except that they have an additional attribute
-    storing the file descriptor referring to the native Android fence object.
+    associated with a native synchronization fence object that is referenced
+    using a file descriptor.  These EGL fence sync objects have nearly
+    identical semantics to those defined by the KHR_fence_sync extension,
+    except that they have an additional attribute storing the file descriptor
+    referring to the native fence object.
+
+    This extension assumes the existence of a native fence synchronization
+    object that behaves similarly to an EGL fence sync object.  These native
+    objects must have a signal status like that of an EGLSyncKHR object that
+    indicates whether the fence has ever been signaled.  Once signaled the
+    native object's signal status may not change again.
 
 New Types
 
@@ -48,7 +55,7 @@
 
 New Procedures and Functions
 
-    EGLint eglDupAndroidFenceFDANDROID(
+    EGLint eglDupNativeFenceFDANDROID(
                         EGLDisplay dpy,
                         EGLSyncKHR);
 
@@ -58,72 +65,72 @@
     in <value> when eglGetSyncAttribKHR is called with <attribute>
     EGL_SYNC_TYPE_KHR:
 
-    EGL_SYNC_ANDROID_FENCE_ANDROID          0x3144
+    EGL_SYNC_NATIVE_FENCE_ANDROID          0x3144
 
     Accepted by the <attrib_list> parameter of eglCreateSyncKHR:
 
-    EGL_SYNC_ANDROID_FENCE_FD_ANDROID       0x3145
+    EGL_SYNC_NATIVE_FENCE_FD_ANDROID       0x3145
 
     Accepted by the <attrib_list> parameter of eglCreateSyncKHR, and returned
-    by eglDupAndroidFenceFDANDROID in the event of an error:
+    by eglDupNativeFenceFDANDROID in the event of an error:
 
-    EGL_NO_ANDROID_FENCE_ANDROID            -1
+    EGL_NO_NATIVE_FENCE_ANDROID            -1
 
     Returned in <value> when eglGetSyncAttribKHR is called with <attribute>
     EGL_SYNC_CONDITION_KHR:
 
-    EGL_SYNC_ANDROID_FENCE_SIGNALED_ANDROID 0x3146
+    EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146
 
 Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
 
     Add the following after the sixth paragraph of Section 3.8.1 (Sync
     Objects), added by KHR_fence_sync
 
-    "If <type> is EGL_SYNC_ANDROID_FENCE_ANDROID, an EGL Android fence sync
-    object is created. In this case the EGL_SYNC_ANDROID_FENCE_FD_ANDROID
+    "If <type> is EGL_SYNC_NATIVE_FENCE_ANDROID, an EGL native fence sync
+    object is created. In this case the EGL_SYNC_NATIVE_FENCE_FD_ANDROID
     attribute may optionally be specified. If this attribute is specified, it
-    must be set to either a file descriptor that refers to a native Android
-    fence object or to the value EGL_NO_ANDROID_FENCE_ANDROID.
+    must be set to either a file descriptor that refers to a native fence
+    object or to the value EGL_NO_NATIVE_FENCE_ANDROID.
 
-    The default values for the EGL Android fence sync object attributes are as
+    The default values for the EGL native fence sync object attributes are as
     follows:
 
       Attribute Name                     Initial Attribute Value(s)
       ---------------                    --------------------------
-      EGL_SYNC_TYPE_KHR                  EGL_SYNC_ANDROID_FENCE_ANDROID
+      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_ANDROID_FENCE_FD_ANDROID  EGL_NO_ANDROID_FENCE_ANDROID
+      EGL_SYNC_NATIVE_FENCE_FD_ANDROID   EGL_NO_NATIVE_FENCE_ANDROID
 
-    If the EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute is not
-    EGL_NO_ANDROID_FENCE_ANDROID then the EGL_SYNC_CONDITION_KHR attribute is
-    set to EGL_SYNC_ANDROID_FENCE_SIGNALED_ANDROID and the EGL_SYNC_STATUS_KHR
-    attribute is set to reflect the signal status of the native Android fence
-    object. Additionally, the EGL implementation assumes ownership of the file
+    If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute is not
+    EGL_NO_NATIVE_FENCE_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
     descriptor, so the caller must not use it after calling eglCreateSyncKHR."
 
     Modify Section 3.8.1 (Sync Objects), added by KHR_fence_sync, starting at
     the seventh paragraph
 
-    "When a fence sync object is created or when an EGL Android fence sync
-    object is created with the EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute set
-    to EGL_NO_ANDROID_FENCE_ANDROID, eglCreateSyncKHR also inserts a fence
+    "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
     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.
 
-    After associating the fence command with an EGL Android fence sync object,
+    After associating the fence command with an EGL native fence sync object,
     the next Flush() operation performed by the current client API causes a
-    new native Android fence object to be created, and the
-    EGL_SYNC_ANDROID_FENCE_ANDROID attribute of the EGL Android fence object
-    is set to a file descriptor that refers to the new native Android fence
-    object. This new native Android fence object is signaled when the EGL
-    Android fence sync object is signaled.
+    new native fence object to be created, and the
+    EGL_SYNC_NATIVE_FENCE_ANDROID attribute of the EGL native fence object is
+    set to a file descriptor that refers to the new native fence object. This
+    new native fence object is signaled when the EGL native fence sync object
+    is signaled.
 
     When the condition of the sync object is satisfied by the fence command,
     the sync is signaled by the associated client API context, causing any
-    eglClientWaitSyncKHR commands (see below) blocking on <sync> to unblock. If
-    the sync object is an EGL Android fence sync object then the native Android
+    eglClientWaitSyncKHR commands (see below) blocking on <sync> to unblock.
+    If the sync object is an EGL native fence sync object then the native
     fence object is also signaled when the condition is satisfied. The
     EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR condition is satisfied by completion
     of the fence command corresponding to the sync object and all preceding
@@ -132,9 +139,9 @@
     client API's internal and framebuffer state are fully realized. No other
     state is affected by execution of the fence command.
 
-    The EGL_SYNC_ANDROID_FENCE_SIGNALED_ANDROID condition is satisfied by the
-    signaling of the native Android fence object referred to by the
-    EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute. When this happens any
+    The EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID condition is satisfied by the
+    signaling of the native fence object referred to by the
+    EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute. When this happens any
     eglClientWaitSyncKHR commands blocking on <sync> unblock."
 
     Modify the list of eglCreateSyncKHR errors in Section 3.8.1 (Sync Objects),
@@ -149,22 +156,22 @@
       * If <type> is EGL_SYNC_FENCE_KHR and <attrib_list> is neither NULL nor
         empty (containing only EGL_NONE), EGL_NO_SYNC_KHR is returned and an
         EGL_BAD_ATTRIBUTE error is generated.
-      * If <type> is EGL_SYNC_ANDROID_FENCE_ANDROID and <attrib_list> contains
-        an attribute other than EGL_SYNC_ANDROID_FENCE_FD_ANDROID, EGL_NO_SYNC_KHR is
+      * 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.
       * If <type> is not a supported type of sync object,
         EGL_NO_SYNC_KHR is returned and an EGL_BAD_ATTRIBUTE error is
         generated.
-      * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_ANDROID_FENCE_ANDROID and
+      * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_NATIVE_FENCE_ANDROID and
         no context is current for the bound API (i.e., eglGetCurrentContext
         returns EGL_NO_CONTEXT), EGL_NO_SYNC_KHR is returned and an
         EGL_BAD_MATCH error is generated.
-      * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_ANDROID_FENCE_ANDROID and
+      * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_NATIVE_FENCE_ANDROID and
         <dpy> does not match the EGLDisplay of the currently bound context for
         the currently bound client API (the EGLDisplay returned by
         eglGetCurrentDisplay()) then EGL_NO_SYNC_KHR is returned and an
         EGL_BAD_MATCH error is generated.
-      * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_ANDROID_FENCE_ANDROID and
+      * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_NATIVE_FENCE_ANDROID and
         the currently bound client API does not support the client API
         extension indicating it can place fence commands, then EGL_NO_SYNC_KHR
         is returned and an EGL_BAD_MATCH error is generated."
@@ -177,7 +184,7 @@
     EGL_SYNC_TYPE_KHR                  Type of the sync object    All
     EGL_SYNC_STATUS_KHR                Status of the sync object  All
     EGL_SYNC_CONDITION_KHR             Signaling condition        EGL_SYNC_FENCE_KHR and
-                                                                  EGL_SYNC_ANDROID_FENCE_ANDROID only
+                                                                  EGL_SYNC_NATIVE_FENCE_ANDROID only
     "
 
     Modify the second paragraph description of eglDestroySyncKHR in Section
@@ -185,8 +192,8 @@
 
     "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 Android fence sync object and the EGL_SYNC_ANDROID_FENCE_FD_ANDROID
-    attribute is not EGL_NO_ANDROID_FENCE_ANDROID then that file descriptor is
+    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."
 
     Add the following after the last paragraph of Section 3.8.1 (Sync
@@ -194,51 +201,50 @@
 
     The command
 
-        EGLint eglDupAndroidFenceFDANDROID(
+        EGLint eglDupNativeFenceFDANDROID(
                             EGLdisplay dpy,
                             EGLSyncKHR sync);
 
     duplicates the file descriptor stored in the
-    EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute of an EGL Android fence sync
+    EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute of an EGL native fence sync
     object and returns the new file descriptor.
 
     Errors
     ------
 
       * If <sync> is not a valid sync object for <dpy>,
-        EGL_NO_ANDROID_FENCE_ANDROID is returned and an EGL_BAD_PARAMETER
+        EGL_NO_NATIVE_FENCE_ANDROID is returned and an EGL_BAD_PARAMETER
         error is generated.
-      * If the EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute of <sync> is
-        EGL_NO_ANDROID_FENCE_ANDROID, EGL_NO_ANDROID_FENCE_ANDROID is returned
+      * 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.
       * If <dpy> does not match the display passed to eglCreateSyncKHR
         when <sync> was created, the behaviour is undefined."
 
 Issues
 
-    1. Should EGLSyncKHR objects that wrap Android fence objects use the
+    1. Should EGLSyncKHR objects that wrap native fence objects use the
     EGL_SYNC_FENCE_KHR type?
 
     RESOLVED: A new sync object type will be added.
 
-    We don't want to require all EGL fence sync objects to wrap Android fence
+    We don't want to require all EGL fence sync objects to wrap native fence
     objects, so we need some way to tell the EGL implementation at sync object
-    creation whether the sync object should support querying the Android fence
+    creation whether the sync object should support querying the native fence
     FD attribute. We could do this with either a new sync object type or with a
     boolean attribute. It might be nice to pick up future signaling conditions
     that might be added for fence sync objects, but there may be things that
-    get added that don't make sense in the context of Android fence objects.
+    get added that don't make sense in the context of native fence objects.
 
-    2. Who is responsible for dup'ing the Android fence file descriptors?
+    2. Who is responsible for dup'ing the native fence file descriptors?
 
     RESOLVED: Whenever a file descriptor is passed into or returned from an
     EGL call in this extension, ownership of that file descriptor is
     transfered. The recipient of the file descriptor must close it when it is
     no longer needed, and the provider of the file descriptor must dup it
-    before providing it if they require continued use of the native Android
-    fence.
+    before providing it if they require continued use of the native fence.
 
-    3. Can the EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute be queried?
+    3. Can the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute be queried?
 
     RESOLVED: No.
 
@@ -250,15 +256,21 @@
 
     That said, the attribute is useful both as a way to pass an existing file
     descriptor to eglCreateSyncKHR and as a way to describe the subsequent
-    behavior of EGL Android fence sync objects, so it is left as an attribute
+    behavior of EGL native fence sync objects, so it is left as an attribute
     for which the value cannot be queried.
 
 Revision History
 
+#3 (Jamie Gennis, September 4, 2012)
+    - Reworded the extension to refer to "native fence" objects rather than
+    "Android fence" objects.
+    - Added a paragraph to the overview that describes assumptions about the
+    native fence sync objects.
+
 #2 (Jamie Gennis, July 23, 2012)
     - Changed the file descriptor ownership transferring behavior.
     - Added the eglDupAndroidFenceFDANDROID function.
-    - Removed EGL_SYNC_ANDROID_FENCE_FD_ANDROID from the table of gettable
+    - Removed EGL_SYNC_NATIVE_FENCE_FD_ANDROID from the table of gettable
     attributes.
     - Added language specifying that a native Android fence is created at the
     flush following the creation of an EGL Android fence sync object that is
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 16e5547..01ae1c2 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -38,6 +38,7 @@
 #include "DisplayHardware/FramebufferSurface.h"
 #include "DisplayHardware/HWComposer.h"
 
+#include "clz.h"
 #include "DisplayDevice.h"
 #include "GLExtensions.h"
 #include "SurfaceFlinger.h"
@@ -84,8 +85,8 @@
       mPageFlipCount(),
       mSecureLayerVisible(false),
       mScreenAcquired(false),
-      mOrientation(),
-      mLayerStack(0)
+      mLayerStack(0),
+      mOrientation()
 {
     init(config);
 }
@@ -139,6 +140,8 @@
     mSurface = surface;
     mFormat  = format;
     mPageFlipCount = 0;
+    mViewport.makeInvalid();
+    mFrame.makeInvalid();
 
     // external displays are always considered enabled
     mScreenAcquired = (mType >= DisplayDevice::NUM_DISPLAY_TYPES);
@@ -147,7 +150,7 @@
     mHwcDisplayId = mFlinger->allocateHwcDisplayId(mType);
 
     // initialize the display orientation transform.
-    DisplayDevice::setOrientation(DisplayState::eOrientationDefault);
+    setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
 }
 
 uint32_t DisplayDevice::getPageFlipCount() const {
@@ -192,12 +195,23 @@
     }
 }
 
-void DisplayDevice::makeCurrent(const sp<const DisplayDevice>& hw, EGLContext ctx) {
+EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy,
+        const sp<const DisplayDevice>& hw, EGLContext ctx) {
+    EGLBoolean result = EGL_TRUE;
     EGLSurface sur = eglGetCurrentSurface(EGL_DRAW);
     if (sur != hw->mSurface) {
-        EGLDisplay dpy = eglGetCurrentDisplay();
-        eglMakeCurrent(dpy, hw->mSurface, hw->mSurface, ctx);
+        result = eglMakeCurrent(dpy, hw->mSurface, hw->mSurface, ctx);
+        if (result == EGL_TRUE) {
+            GLsizei w = hw->mDisplayWidth;
+            GLsizei h = hw->mDisplayHeight;
+            glViewport(0, 0, w, h);
+            glMatrixMode(GL_PROJECTION);
+            glLoadIdentity();
+            // put the origin in the left-bottom corner
+            glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h
+        }
     }
+    return result;
 }
 
 // ----------------------------------------------------------------------------
@@ -223,10 +237,10 @@
 
 Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
     Region dirty;
-    const Transform& planeTransform(mGlobalTransform);
     if (repaintEverything) {
         dirty.set(getBounds());
     } else {
+        const Transform& planeTransform(mGlobalTransform);
         dirty = planeTransform.transform(this->dirtyRegion);
         dirty.andSelf(getBounds());
     }
@@ -284,18 +298,62 @@
     return NO_ERROR;
 }
 
-status_t DisplayDevice::setOrientation(int orientation) {
+void DisplayDevice::setProjection(int orientation,
+        const Rect& viewport, const Rect& frame) {
+    mOrientation = orientation;
+    mViewport = viewport;
+    mFrame = frame;
+    updateGeometryTransform();
+}
+
+void DisplayDevice::updateGeometryTransform() {
     int w = mDisplayWidth;
     int h = mDisplayHeight;
+    Transform R, S;
+    if (DisplayDevice::orientationToTransfrom(
+            mOrientation, w, h, &R) == NO_ERROR) {
+        dirtyRegion.set(bounds());
 
-    DisplayDevice::orientationToTransfrom(
-            orientation, w, h, &mGlobalTransform);
-    if (orientation & DisplayState::eOrientationSwapMask) {
-        int tmp = w;
-        w = h;
-        h = tmp;
+        Rect viewport(mViewport);
+        Rect frame(mFrame);
+
+        if (!frame.isValid()) {
+            // the destination frame can be invalid if it has never been set,
+            // in that case we assume the whole display frame.
+            frame = Rect(w, h);
+        }
+
+        if (viewport.isEmpty()) {
+            // viewport can be invalid if it has never been set, in that case
+            // we assume the whole display size.
+            // it's also invalid to have an empty viewport, so we handle that
+            // case in the same way.
+            viewport = Rect(w, h);
+            if (R.getOrientation() & Transform::ROT_90) {
+                // viewport is always specified in the logical orientation
+                // of the display (ie: post-rotation).
+                swap(viewport.right, viewport.bottom);
+            }
+        }
+
+        float src_width  = viewport.width();
+        float src_height = viewport.height();
+        float dst_width  = frame.width();
+        float dst_height = frame.height();
+        if (src_width != src_height || dst_width != dst_height) {
+            float sx = dst_width  / src_width;
+            float sy = dst_height / src_height;
+            S.set(sx, 0, 0, sy);
+        }
+        float src_x = viewport.left;
+        float src_y = viewport.top;
+        float dst_x = frame.left;
+        float dst_y = frame.top;
+        float tx = dst_x - src_x;
+        float ty = dst_y - src_y;
+        S.set(tx, ty);
+
+        // rotate first, followed by scaling
+        mGlobalTransform = S * R;
     }
-    mOrientation = orientation;
-    dirtyRegion.set(bounds());
-    return NO_ERROR;
 }
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index b742b13..8122b9d 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -93,11 +93,14 @@
     bool                    getSecureLayerVisible() const;
     Region                  getDirtyRegion(bool repaintEverything) const;
 
-    status_t                setOrientation(int orientation);
     void                    setLayerStack(uint32_t stack);
+    void                    setProjection(int orientation, const Rect& viewport, const Rect& frame);
 
     int                     getOrientation() const { return mOrientation; }
     const Transform&        getTransform() const { return mGlobalTransform; }
+    const Rect&             getViewport() const { return mViewport; }
+    const Rect&             getFrame() const { return mFrame; }
+
     uint32_t                getLayerStack() const { return mLayerStack; }
     int32_t                 getDisplayType() const { return mType; }
     int32_t                 getHwcDisplayId() const { return mHwcDisplayId; }
@@ -110,7 +113,8 @@
     }
     inline Rect bounds() const { return getBounds(); }
 
-    static void makeCurrent(const sp<const DisplayDevice>& hw, EGLContext ctx);
+    static EGLBoolean makeCurrent(EGLDisplay dpy,
+            const sp<const DisplayDevice>& hw, EGLContext ctx);
 
     /* ------------------------------------------------------------------------
      * blank / unplank management
@@ -170,11 +174,16 @@
     /*
      * Transaction state
      */
-    static status_t orientationToTransfrom(int orientation, int w, int h,
-            Transform* tr);
-    Transform mGlobalTransform;
-    int mOrientation;
+    static status_t orientationToTransfrom(int orientation,
+            int w, int h, Transform* tr);
+
+    void updateGeometryTransform();
+
     uint32_t mLayerStack;
+    int mOrientation;
+    Rect mViewport;
+    Rect mFrame;
+    Transform mGlobalTransform;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index dcda67e..ade9f75 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -140,6 +140,8 @@
     return true;
 }
 
+// This will return when (1) a vsync event has been received, and (2) there was
+// at least one connection interested in receiving it when we started waiting.
 Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
         DisplayEventReceiver::Event* event)
 {
@@ -193,31 +195,54 @@
             // don't report it, and disable VSYNC events
             disableVSyncLocked();
         } else if (!timestamp && waitForVSync) {
+            // we have at least one client, so we want vsync enabled
+            // (TODO: this function is called right after we finish
+            // notifying clients of a vsync, so this call will be made
+            // at the vsync rate, e.g. 60fps.  If we can accurately
+            // track the current state we could avoid making this call
+            // so often.)
             enableVSyncLocked();
         }
 
-        // note: !timestamp implies signalConnections.isEmpty()
+        // note: !timestamp implies signalConnections.isEmpty(), because we
+        // don't populate signalConnections if there's no vsync pending
         if (!timestamp) {
             // wait for something to happen
-            if (CC_UNLIKELY(mUseSoftwareVSync && waitForVSync)) {
-                // h/w vsync cannot be used (screen is off), so we use
-                // a  timeout instead. it doesn't matter how imprecise this
-                // is, we just need to make sure to serve the clients
-                if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
+            if (waitForVSync) {
+                // This is where we spend most of our time, waiting
+                // for vsync events and new client registrations.
+                //
+                // If the screen is off, we can't use h/w vsync, so we
+                // use a 16ms timeout instead.  It doesn't need to be
+                // precise, we just need to keep feeding our clients.
+                //
+                // We don't want to stall if there's a driver bug, so we
+                // use a (long) timeout when waiting for h/w vsync, and
+                // generate fake events when necessary.
+                bool softwareSync = mUseSoftwareVSync;
+                nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
+                if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
+                    if (!softwareSync) {
+                        ALOGW("Timed out waiting for hw vsync; faking it");
+                    }
                     mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
                     mVSyncCount++;
                 }
             } else {
-                // This is where we spend most of our time, waiting
-                // for a vsync events and registered clients
+                // Nobody is interested in vsync, so we just want to sleep.
+                // h/w vsync should be disabled, so this will wait until we
+                // get a new connection, or an existing connection becomes
+                // interested in receiving vsync again.
                 mCondition.wait(mLock);
             }
         }
     } while (signalConnections.isEmpty());
 
     // here we're guaranteed to have a timestamp and some connections to signal
+    // (The connections might have dropped out of mDisplayEventConnections
+    // while we were asleep, but we'll still have strong references to them.)
 
-    // dispatch vsync events to listeners...
+    // fill in vsync event info
     event->header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
     event->header.timestamp = timestamp;
     event->vsync.count = vsyncCount;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f928805..f39de4a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -276,10 +276,10 @@
 
 void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
         HWComposer::HWCLayerInterface& layer) {
-    const sp<GraphicBuffer>& buffer(mActiveBuffer);
+    LayerBaseClient::setPerFrameData(hw, layer);
     // NOTE: buffer can be NULL if the client never drew into this
     // layer yet, or if we ran out of memory
-    layer.setBuffer(buffer);
+    layer.setBuffer(mActiveBuffer);
 }
 
 void Layer::setAcquireFence(const sp<const DisplayDevice>& hw,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ee653f3..08cb345 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -297,8 +297,8 @@
     return ctxt;
 }
 
-void SurfaceFlinger::initializeGL(EGLDisplay display, EGLSurface surface) {
-    EGLBoolean result = eglMakeCurrent(display, surface, surface, mEGLContext);
+void SurfaceFlinger::initializeGL(EGLDisplay display, const sp<DisplayDevice>& hw) {
+    EGLBoolean result = DisplayDevice::makeCurrent(display, hw, mEGLContext);
     if (!result) {
         ALOGE("Couldn't create a working GLES context. check logs. exiting...");
         exit(0);
@@ -314,10 +314,6 @@
             eglQueryString(display, EGL_VERSION),
             eglQueryString(display, EGL_EXTENSIONS));
 
-    EGLint w, h;
-    eglQuerySurface(display, surface, EGL_WIDTH,  &w);
-    eglQuerySurface(display, surface, EGL_HEIGHT, &h);
-
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
 
@@ -344,12 +340,6 @@
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0,
             GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
 
-    glViewport(0, 0, w, h);
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    // put the origin in the left-bottom corner
-    glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h
-
     // print some debugging info
     EGLint r,g,b,a;
     eglGetConfigAttrib(display, mEGLConfig, EGL_RED_SIZE,   &r);
@@ -412,8 +402,7 @@
     mDisplays.add(mDefaultDisplays[DisplayDevice::DISPLAY_PRIMARY], hw);
 
     //  initialize OpenGL ES
-    EGLSurface surface = hw->getEGLSurface();
-    initializeGL(mEGLDisplay, surface);
+    initializeGL(mEGLDisplay, hw);
 
     // start the EventThread
     mEventThread = new EventThread(this);
@@ -863,7 +852,7 @@
         // FIXME: EGL spec says:
         //   "surface must be bound to the calling thread's current context,
         //    for the current rendering API."
-        DisplayDevice::makeCurrent(getDefaultDisplayDevice(), mEGLContext);
+        DisplayDevice::makeCurrent(mEGLDisplay, getDefaultDisplayDevice(), mEGLContext);
         hwc.commit();
     }
 
@@ -983,11 +972,12 @@
                         if (state.layerStack != draw[i].layerStack) {
                             disp->setLayerStack(state.layerStack);
                         }
-                        if (state.orientation != draw[i].orientation ||
-                                state.viewport != draw[i].viewport ||
-                                state.frame != draw[i].frame) {
-                            disp->setOrientation(state.orientation);
-                            // TODO: take viewport and frame into account
+                        if ((state.orientation != draw[i].orientation)
+                                || (state.viewport != draw[i].viewport)
+                                || (state.frame != draw[i].frame))
+                        {
+                            disp->setProjection(state.orientation,
+                                    state.viewport, state.viewport);
                         }
                     }
                 }
@@ -1005,8 +995,8 @@
                         sp<DisplayDevice> disp = new DisplayDevice(this,
                                 state.type, display, stc, 0, mEGLConfig);
                         disp->setLayerStack(state.layerStack);
-                        disp->setOrientation(state.orientation);
-                        // TODO: take viewport and frame into account
+                        disp->setProjection(state.orientation,
+                                state.viewport, state.viewport);
                         mDisplays.add(display, disp);
                     }
                 }
@@ -1037,10 +1027,10 @@
                 // TODO: we could traverse the tree from front to back and
                 //       compute the actual visible region
                 // TODO: we could cache the transformed region
-                Layer::State front(layer->drawingState());
-                Region visibleReg = front.transform.transform(
-                        Region(Rect(front.active.w, front.active.h)));
-                invalidateLayerStack(front.layerStack, visibleReg);
+                const Layer::State& s(layer->drawingState());
+                Region visibleReg = s.transform.transform(
+                        Region(Rect(s.active.w, s.active.h)));
+                invalidateLayerStack(s.layerStack, visibleReg);
             }
         }
     }
@@ -1212,7 +1202,7 @@
     for (size_t i=0 ; i<count ; i++) {
         const sp<LayerBase>& layer(currentLayers[i]);
         const Region dirty(layer->latchBuffer(visibleRegions));
-        Layer::State s(layer->drawingState());
+        const Layer::State& s(layer->drawingState());
         invalidateLayerStack(s.layerStack, dirty);
     }
 
@@ -1280,7 +1270,7 @@
 
     const bool hasGlesComposition = hwc.hasGlesComposition(id) || (cur==end);
     if (hasGlesComposition) {
-        DisplayDevice::makeCurrent(hw, mEGLContext);
+        DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext);
 
         // set the frame buffer
         glMatrixMode(GL_MODELVIEW);
@@ -1506,19 +1496,15 @@
                 flags |= eDisplayTransactionNeeded;
             }
         }
-        if (what & DisplayState::eOrientationChanged) {
+        if (what & DisplayState::eDisplayProjectionChanged) {
             if (disp.orientation != s.orientation) {
                 disp.orientation = s.orientation;
                 flags |= eDisplayTransactionNeeded;
             }
-        }
-        if (what & DisplayState::eFrameChanged) {
             if (disp.frame != s.frame) {
                 disp.frame = s.frame;
                 flags |= eDisplayTransactionNeeded;
             }
-        }
-        if (what & DisplayState::eViewportChanged) {
             if (disp.viewport != s.viewport) {
                 disp.viewport = s.viewport;
                 flags |= eDisplayTransactionNeeded;
@@ -1739,7 +1725,7 @@
     Vector<ComposerState> state;
     Vector<DisplayState> displays;
     DisplayState d;
-    d.what = DisplayState::eOrientationChanged;
+    d.what = DisplayState::eDisplayProjectionChanged;
     d.token = mDefaultDisplays[DisplayDevice::DISPLAY_PRIMARY];
     d.orientation = DisplayState::eOrientationDefault;
     displays.add(d);
@@ -1977,15 +1963,18 @@
         const sp<const DisplayDevice>& hw(mDisplays[dpy]);
         snprintf(buffer, SIZE,
                 "+ DisplayDevice[%u]\n"
-                "   id=%x, layerStack=%u, (%4dx%4d), orient=%2d, tr=%08x, "
-                "flips=%u, secure=%d, numLayers=%u\n",
+                "   id=%x, layerStack=%u, (%4dx%4d), orient=%2d (type=%08x), "
+                "flips=%u, secure=%d, numLayers=%u, v:[%d,%d,%d,%d], f:[%d,%d,%d,%d]\n",
                 dpy,
                 hw->getDisplayType(), hw->getLayerStack(),
                 hw->getWidth(), hw->getHeight(),
                 hw->getOrientation(), hw->getTransform().getType(),
                 hw->getPageFlipCount(),
                 hw->getSecureLayerVisible(),
-                hw->getVisibleLayersSortedByZ().size());
+                hw->getVisibleLayersSortedByZ().size(),
+                hw->getViewport().left, hw->getViewport().top, hw->getViewport().right, hw->getViewport().bottom,
+                hw->getFrame().left, hw->getFrame().top, hw->getFrame().right, hw->getFrame().bottom);
+
         result.append(buffer);
     }
 
@@ -2488,6 +2477,8 @@
 
 SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type)
     : type(type), layerStack(0), orientation(0) {
+    viewport.makeInvalid();
+    frame.makeInvalid();
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9db6b2d..ea03e2d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -320,7 +320,7 @@
         EGLint const* attrs, PixelFormat format, EGLConfig* outConfig);
     static EGLConfig selectEGLConfig(EGLDisplay disp, EGLint visualId);
     static EGLContext createGLContext(EGLDisplay disp, EGLConfig config);
-    void initializeGL(EGLDisplay display, EGLSurface surface);
+    void initializeGL(EGLDisplay display, const sp<DisplayDevice>& hw);
     uint32_t getMaxTextureSize() const;
     uint32_t getMaxViewportDims() const;