Merge changes from topic "rootless_debug_gles_20181015"

* changes:
  Call down the chain for eglGetError
  Move platform entries init earlier
  Revert "Revert "Rootless Debug for GLES""
  Revert "Revert "Split platform functions from entrypoints""
  Revert "Revert "Rename eglApi.cpp to egl_platform_entries.cpp""
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 24b1986..7b35409 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -144,6 +144,9 @@
         "libhardware_headers",
         "libui_headers",
     ],
+
+    // TODO(b/117568153): Temporarily opt out using libcrt.
+    no_libcrt: true,
 }
 
 cc_library_headers {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 57fc17f..0b73be0 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -256,18 +256,17 @@
 
 // --- InputReaderConfiguration ---
 
-bool InputReaderConfiguration::getDisplayViewport(ViewportType viewportType,
-        const std::string& uniqueDisplayId, DisplayViewport* outViewport) const {
+std::optional<DisplayViewport> InputReaderConfiguration::getDisplayViewport(
+        ViewportType viewportType, const std::string& uniqueDisplayId) const {
     for (const DisplayViewport& currentViewport : mDisplays) {
         if (currentViewport.type == viewportType) {
             if (uniqueDisplayId.empty() ||
                     (!uniqueDisplayId.empty() && uniqueDisplayId == currentViewport.uniqueId)) {
-                *outViewport = currentViewport;
-                return true;
+                return std::make_optional(currentViewport);
             }
         }
     }
-    return false;
+    return std::nullopt;
 }
 
 void InputReaderConfiguration::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
@@ -2249,7 +2248,6 @@
     dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
 }
 
-
 void KeyboardInputMapper::configure(nsecs_t when,
         const InputReaderConfiguration* config, uint32_t changes) {
     InputMapper::configure(when, config, changes);
@@ -2261,9 +2259,7 @@
 
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
         if (mParameters.orientationAware) {
-            DisplayViewport dvp;
-            config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &dvp);
-            mViewport = dvp;
+            mViewport = config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
         }
     }
 }
@@ -2672,9 +2668,10 @@
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
         mOrientation = DISPLAY_ORIENTATION_0;
         if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
-            DisplayViewport v;
-            if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &v)) {
-                mOrientation = v.orientation;
+            std::optional<DisplayViewport> internalViewport =
+                    config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
+            if (internalViewport) {
+                mOrientation = internalViewport->orientation;
             }
         }
         bumpGeneration();
@@ -2987,9 +2984,10 @@
         mRotaryEncoderScrollAccumulator.configure(getDevice());
     }
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-        DisplayViewport v;
-        if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &v)) {
-            mOrientation = v.orientation;
+        std::optional<DisplayViewport> internalViewport =
+                config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
+        if (internalViewport) {
+            mOrientation = internalViewport->orientation;
         } else {
             mOrientation = DISPLAY_ORIENTATION_0;
         }
@@ -3502,7 +3500,9 @@
             viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;
         }
 
-        if (!mConfig.getDisplayViewport(viewportTypeToUse, uniqueDisplayId, &newViewport)) {
+        std::optional<DisplayViewport> viewportToUse =
+                mConfig.getDisplayViewport(viewportTypeToUse, uniqueDisplayId);
+        if (!viewportToUse) {
             ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
                     "display.  The device will be inoperable until the display size "
                     "becomes available.",
@@ -3510,6 +3510,7 @@
             mDeviceMode = DEVICE_MODE_DISABLED;
             return;
         }
+        newViewport = *viewportToUse;
     } else {
         newViewport.setNonDisplayViewport(rawWidth, rawHeight);
     }
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 74668b7..3410bc9 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -202,8 +202,8 @@
             pointerGestureZoomSpeedRatio(0.3f),
             showTouches(false) { }
 
-    bool getDisplayViewport(ViewportType viewportType, const std::string& uniqueDisplayId,
-            DisplayViewport* outViewport) const;
+    std::optional<DisplayViewport> getDisplayViewport(ViewportType viewportType,
+            const std::string& uniqueDisplayId) const;
     void setDisplayViewports(const std::vector<DisplayViewport>& viewports);
 
 
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 517e639..a1cd71c 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -10,6 +10,7 @@
     cflags: [
         "-Wall",
         "-Werror",
+        "-Wextra",
         "-Wno-unused-parameter",
     ],
     shared_libs: [
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index b70ee09..707f3c5 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -33,7 +33,7 @@
 static const int32_t VIRTUAL_DISPLAY_ID = 1;
 static const int32_t VIRTUAL_DISPLAY_WIDTH = 400;
 static const int32_t VIRTUAL_DISPLAY_HEIGHT = 500;
-static const char* VIRTUAL_DISPLAY_UNIQUE_ID = "Vr-display-unique-ID";
+static const char* VIRTUAL_DISPLAY_UNIQUE_ID = "virtual:1";
 
 // Error tolerance for floating point assertions.
 static const float EPSILON = 0.001f;
@@ -142,21 +142,21 @@
     FakeInputReaderPolicy() {
     }
 
-    void setDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
-            const std::string& uniqueId) {
+    virtual void clearViewports() {
         mViewports.clear();
-        // Set the size of both the internal and external display at the same time.
-        mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
-                ViewportType::VIEWPORT_INTERNAL));
-        mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
-                ViewportType::VIEWPORT_EXTERNAL));
         mConfig.setDisplayViewports(mViewports);
     }
 
-    void setVirtualDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
+    std::optional<DisplayViewport> getDisplayViewport(ViewportType viewportType,
             const std::string& uniqueId) {
-        mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
-                ViewportType::VIEWPORT_VIRTUAL));
+        return mConfig.getDisplayViewport(viewportType, uniqueId);
+    }
+
+    void addDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
+            const std::string& uniqueId, ViewportType viewportType) {
+        const DisplayViewport viewport = createDisplayViewport(displayId, width, height,
+                orientation, uniqueId, viewportType);
+        mViewports.push_back(viewport);
         mConfig.setDisplayViewports(mViewports);
     }
 
@@ -1080,6 +1080,146 @@
     friend class InputReaderTest;
 };
 
+// --- InputReaderPolicyTest ---
+class InputReaderPolicyTest : public testing::Test {
+    protected:
+    sp<FakeInputReaderPolicy> mFakePolicy;
+
+    virtual void SetUp() {
+        mFakePolicy = new FakeInputReaderPolicy();
+    }
+    virtual void TearDown() {
+        mFakePolicy.clear();
+    }
+};
+
+/**
+ * Check that empty set of viewports is an acceptable configuration.
+ * Also try to get internal viewport two different ways - by type and by uniqueId.
+ *
+ * There will be confusion if two viewports with empty uniqueId and identical type are present.
+ * Such configuration is not currently allowed.
+ */
+TEST_F(InputReaderPolicyTest, Viewports_GetCleared) {
+    const std::string uniqueId = "local:0";
+
+    // We didn't add any viewports yet, so there shouldn't be any.
+    std::optional<DisplayViewport> internalViewport =
+            mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, uniqueId);
+    ASSERT_FALSE(internalViewport);
+
+    // Add an internal viewport, then clear it
+    mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+            DISPLAY_ORIENTATION_0, uniqueId, ViewportType::VIEWPORT_INTERNAL);
+
+    // Check matching by uniqueId
+    internalViewport = mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, uniqueId);
+    ASSERT_TRUE(internalViewport);
+
+    // Check matching by viewport type
+    internalViewport = mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
+    ASSERT_TRUE(internalViewport);
+
+    mFakePolicy->clearViewports();
+    // Make sure nothing is found after clear
+    internalViewport = mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, uniqueId);
+    ASSERT_FALSE(internalViewport);
+    internalViewport = mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
+    ASSERT_FALSE(internalViewport);
+}
+
+TEST_F(InputReaderPolicyTest, Viewports_GetByType) {
+    const std::string internalUniqueId = "local:0";
+    const std::string externalUniqueId = "local:1";
+    const std::string virtualUniqueId1 = "virtual:2";
+    const std::string virtualUniqueId2 = "virtual:3";
+    constexpr int32_t virtualDisplayId1 = 2;
+    constexpr int32_t virtualDisplayId2 = 3;
+
+    // Add an internal viewport
+    mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+            DISPLAY_ORIENTATION_0, internalUniqueId, ViewportType::VIEWPORT_INTERNAL);
+    // Add an external viewport
+    mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+            DISPLAY_ORIENTATION_0, externalUniqueId, ViewportType::VIEWPORT_EXTERNAL);
+    // Add an virtual viewport
+    mFakePolicy->addDisplayViewport(virtualDisplayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+            DISPLAY_ORIENTATION_0, virtualUniqueId1, ViewportType::VIEWPORT_VIRTUAL);
+    // Add another virtual viewport
+    mFakePolicy->addDisplayViewport(virtualDisplayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+            DISPLAY_ORIENTATION_0, virtualUniqueId2, ViewportType::VIEWPORT_VIRTUAL);
+
+    // Check matching by type for internal
+    std::optional<DisplayViewport> internalViewport =
+            mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
+    ASSERT_TRUE(internalViewport);
+    ASSERT_EQ(internalUniqueId, internalViewport->uniqueId);
+
+    // Check matching by type for external
+    std::optional<DisplayViewport> externalViewport =
+            mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_EXTERNAL, "");
+    ASSERT_TRUE(externalViewport);
+    ASSERT_EQ(externalUniqueId, externalViewport->uniqueId);
+
+    // Check matching by uniqueId for virtual viewport #1
+    std::optional<DisplayViewport> virtualViewport1 =
+            mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_VIRTUAL, virtualUniqueId1);
+    ASSERT_TRUE(virtualViewport1);
+    ASSERT_EQ(virtualUniqueId1, virtualViewport1->uniqueId);
+    ASSERT_EQ(virtualDisplayId1, virtualViewport1->displayId);
+
+    // Check matching by uniqueId for virtual viewport #2
+    std::optional<DisplayViewport> virtualViewport2 =
+            mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_VIRTUAL, virtualUniqueId2);
+    ASSERT_TRUE(virtualViewport2);
+    ASSERT_EQ(virtualUniqueId2, virtualViewport2->uniqueId);
+    ASSERT_EQ(virtualDisplayId2, virtualViewport2->displayId);
+}
+
+
+/**
+ * We can have 2 viewports of the same kind. We can distinguish them by uniqueId, and confirm
+ * that lookup works by checking display id.
+ * Check that 2 viewports of each kind is possible, for all existing viewport types.
+ */
+TEST_F(InputReaderPolicyTest, Viewports_TwoOfSameType) {
+    const std::string uniqueId1 = "uniqueId1";
+    const std::string uniqueId2 = "uniqueId2";
+    constexpr int32_t displayId1 = 2;
+    constexpr int32_t displayId2 = 3;
+
+    std::vector<ViewportType> types = {ViewportType::VIEWPORT_INTERNAL,
+            ViewportType::VIEWPORT_EXTERNAL, ViewportType::VIEWPORT_VIRTUAL};
+    for (const ViewportType& type : types) {
+        mFakePolicy->clearViewports();
+        // Add a viewport
+        mFakePolicy->addDisplayViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+            DISPLAY_ORIENTATION_0, uniqueId1, type);
+        // Add another viewport
+        mFakePolicy->addDisplayViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+            DISPLAY_ORIENTATION_0, uniqueId2, type);
+
+        // Check that correct display viewport was returned by comparing the display IDs.
+        std::optional<DisplayViewport> viewport1 = mFakePolicy->getDisplayViewport(type, uniqueId1);
+        ASSERT_TRUE(viewport1);
+        ASSERT_EQ(displayId1, viewport1->displayId);
+        ASSERT_EQ(type, viewport1->type);
+
+        std::optional<DisplayViewport> viewport2 = mFakePolicy->getDisplayViewport(type, uniqueId2);
+        ASSERT_TRUE(viewport2);
+        ASSERT_EQ(displayId2, viewport2->displayId);
+        ASSERT_EQ(type, viewport2->type);
+
+        // When there are multiple viewports of the same kind, and uniqueId is not specified
+        // in the call to getDisplayViewport, then that situation is not supported.
+        // The viewports can be stored in any order, so we cannot rely on the order, since that
+        // is just implementation detail.
+        // However, we can check that it still returns *a* viewport, we just cannot assert
+        // which one specifically is returned.
+        std::optional<DisplayViewport> someViewport = mFakePolicy->getDisplayViewport(type, "");
+        ASSERT_TRUE(someViewport);
+    }
+}
 
 // --- InputReaderTest ---
 
@@ -1603,15 +1743,14 @@
     }
 
     void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
-            int32_t orientation) {
-        mFakePolicy->setDisplayViewport(displayId, width, height, orientation, "");
+            int32_t orientation, const std::string& uniqueId, ViewportType viewportType) {
+        mFakePolicy->addDisplayViewport(
+                displayId, width, height, orientation, uniqueId, viewportType);
         configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
     }
 
-    void setVirtualDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
-            int32_t orientation, const std::string& uniqueId) {
-        mFakePolicy->setVirtualDisplayViewport(displayId, width, height, orientation, uniqueId);
-        configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    void clearViewports() {
+        mFakePolicy->clearViewports();
     }
 
     static void process(InputMapper* mapper, nsecs_t when, int32_t deviceId, int32_t type,
@@ -1715,12 +1854,24 @@
 
 class KeyboardInputMapperTest : public InputMapperTest {
 protected:
+    const std::string UNIQUE_ID = "local:0";
+
+    void prepareDisplay(int32_t orientation);
+
     void testDPadKeyRotation(KeyboardInputMapper* mapper,
             int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode);
 };
 
+/* Similar to setDisplayInfoAndReconfigure, but pre-populates all parameters except for the
+ * orientation.
+ */
+void KeyboardInputMapperTest::prepareDisplay(int32_t orientation) {
+    setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+            orientation, UNIQUE_ID, ViewportType::VIEWPORT_INTERNAL);
+}
+
 void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper,
-        int32_t originalScanCode, int32_t, int32_t rotatedKeyCode) {
+        int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode) {
     NotifyKeyArgs args;
 
     process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, 1);
@@ -1908,9 +2059,7 @@
             AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
     addMapperAndConfigure(mapper);
 
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_90);
+    prepareDisplay(DISPLAY_ORIENTATION_90);
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
             KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1932,9 +2081,7 @@
     addConfigurationProperty("keyboard.orientationAware", "1");
     addMapperAndConfigure(mapper);
 
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_0);
+    prepareDisplay(DISPLAY_ORIENTATION_0);
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
             KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1944,9 +2091,8 @@
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
             KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT));
 
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_90);
+    clearViewports();
+    prepareDisplay(DISPLAY_ORIENTATION_90);
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
             KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT));
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1956,9 +2102,8 @@
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
             KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN));
 
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_180);
+    clearViewports();
+    prepareDisplay(DISPLAY_ORIENTATION_180);
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
             KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN));
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1968,9 +2113,8 @@
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
             KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT));
 
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_270);
+    clearViewports();
+    prepareDisplay(DISPLAY_ORIENTATION_270);
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
             KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT));
     ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1983,19 +2127,16 @@
     // Special case: if orientation changes while key is down, we still emit the same keycode
     // in the key up as we did in the key down.
     NotifyKeyArgs args;
-
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_270);
+    clearViewports();
+    prepareDisplay(DISPLAY_ORIENTATION_270);
     process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
     ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
     ASSERT_EQ(KEY_UP, args.scanCode);
     ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode);
 
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_180);
+    clearViewports();
+    prepareDisplay(DISPLAY_ORIENTATION_180);
     process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
     ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
@@ -2020,8 +2161,7 @@
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
     ASSERT_EQ(ADISPLAY_ID_NONE, args.displayId);
 
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+    prepareDisplay(DISPLAY_ORIENTATION_0);
     process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
     process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
@@ -2043,8 +2183,8 @@
     // Display id should be ADISPLAY_ID_NONE without any display configuration.
     // ^--- already checked by the previous test
 
-    setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+    setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0,
+            UNIQUE_ID, ViewportType::VIEWPORT_INTERNAL);
     process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
     process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
@@ -2052,8 +2192,9 @@
     ASSERT_EQ(DISPLAY_ID, args.displayId);
 
     constexpr int32_t newDisplayId = 2;
-    setDisplayInfoAndReconfigure(newDisplayId,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+    clearViewports();
+    setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0,
+            UNIQUE_ID, ViewportType::VIEWPORT_INTERNAL);
     process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
     process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
@@ -2484,9 +2625,12 @@
     addConfigurationProperty("cursor.mode", "navigation");
     addMapperAndConfigure(mapper);
 
+    const std::string uniqueId = "local:0";
+    const ViewportType viewportType = ViewportType::VIEWPORT_INTERNAL;
+
     setDisplayInfoAndReconfigure(DISPLAY_ID,
             DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_90);
+            DISPLAY_ORIENTATION_90, uniqueId, viewportType);
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0,  1));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1,  1,  1));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  0,  1,  0));
@@ -2503,8 +2647,11 @@
     addConfigurationProperty("cursor.orientationAware", "1");
     addMapperAndConfigure(mapper);
 
+    const std::string uniqueId = "local:0";
+    const ViewportType viewportType = ViewportType::VIEWPORT_INTERNAL;
+
     setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0, uniqueId, viewportType);
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0,  1));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1,  1,  1));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  0,  1,  0));
@@ -2515,7 +2662,7 @@
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1, -1,  1));
 
     setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90);
+            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90, uniqueId, viewportType);
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  1,  0));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1,  1, -1));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  0,  0, -1));
@@ -2526,7 +2673,7 @@
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1,  1,  1));
 
     setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180);
+            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180, uniqueId, viewportType);
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0, -1));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1, -1, -1));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  0, -1,  0));
@@ -2537,7 +2684,7 @@
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1,  1, -1));
 
     setDisplayInfoAndReconfigure(DISPLAY_ID,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270);
+            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270, uniqueId, viewportType);
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1, -1,  0));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1, -1,  1));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  0,  0,  1));
@@ -2982,6 +3129,8 @@
 
     static const VirtualKeyDefinition VIRTUAL_KEYS[2];
 
+    const std::string UNIQUE_ID = "local:0";
+
     enum Axes {
         POSITION = 1 << 0,
         TOUCH = 1 << 1,
@@ -3050,12 +3199,14 @@
 };
 
 void TouchInputMapperTest::prepareDisplay(int32_t orientation) {
-    setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation);
+    setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation,
+            UNIQUE_ID, ViewportType::VIEWPORT_INTERNAL);
 }
 
 void TouchInputMapperTest::prepareVirtualDisplay(int32_t orientation) {
-    setVirtualDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH,
-        VIRTUAL_DISPLAY_HEIGHT, orientation, VIRTUAL_DISPLAY_UNIQUE_ID);
+    setDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH,
+        VIRTUAL_DISPLAY_HEIGHT, orientation,
+        VIRTUAL_DISPLAY_UNIQUE_ID, ViewportType::VIEWPORT_VIRTUAL);
 }
 
 void TouchInputMapperTest::prepareVirtualKeys() {
@@ -3784,6 +3935,7 @@
     NotifyMotionArgs args;
 
     // Rotation 0.
+    clearViewports();
     prepareDisplay(DISPLAY_ORIENTATION_0);
     processDown(mapper, toRawX(50), toRawY(75));
     processSync(mapper);
@@ -3797,6 +3949,7 @@
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
 
     // Rotation 90.
+    clearViewports();
     prepareDisplay(DISPLAY_ORIENTATION_90);
     processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50));
     processSync(mapper);
@@ -3810,6 +3963,7 @@
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
 
     // Rotation 180.
+    clearViewports();
     prepareDisplay(DISPLAY_ORIENTATION_180);
     processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN);
     processSync(mapper);
@@ -3823,6 +3977,7 @@
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
 
     // Rotation 270.
+    clearViewports();
     prepareDisplay(DISPLAY_ORIENTATION_270);
     processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN);
     processSync(mapper);
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index a294793..d000d85 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -138,7 +138,7 @@
 
     virtual void setFilteringEnabled(bool enabled) = 0;
 
-    virtual status_t bindTextureImage() const = 0;
+    virtual status_t bindTextureImage() = 0;
     virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
                                     const sp<Fence>& flushFence) = 0;
 
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 8c8915c..6826050 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -111,12 +111,6 @@
         return NO_INIT;
     }
 
-    // Make sure RenderEngine is current
-    if (!mRE.isCurrent()) {
-        BLC_LOGE("updateTexImage: RenderEngine is not current");
-        return INVALID_OPERATION;
-    }
-
     BufferItem item;
 
     // Acquire the next buffer.
@@ -185,8 +179,7 @@
         return;
     }
 
-    auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer
-                                            : mCurrentTextureImage->graphicBuffer();
+    auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer : mCurrentTextureBuffer;
     auto err = addReleaseFence(slot, buffer, fence);
     if (err != OK) {
         BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
@@ -222,10 +215,9 @@
     }
 
     // If item->mGraphicBuffer is not null, this buffer has not been acquired
-    // before, so any prior EglImage created is using a stale buffer. This
-    // replaces any old EglImage with a new one (using the new buffer).
+    // before.
     if (item->mGraphicBuffer != nullptr) {
-        mImages[item->mSlot] = new Image(item->mGraphicBuffer, mRE);
+        mImages[item->mSlot] = nullptr;
     }
 
     return NO_ERROR;
@@ -252,19 +244,18 @@
     }
 
     BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
-             mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : 0,
-             slot, mSlots[slot].mGraphicBuffer->handle);
+             mCurrentTextureBuffer != nullptr ? mCurrentTextureBuffer->handle : 0, slot,
+             mSlots[slot].mGraphicBuffer->handle);
 
     // Hang onto the pointer so that it isn't freed in the call to
     // releaseBufferLocked() if we're in shared buffer mode and both buffers are
     // the same.
-    sp<Image> nextTextureImage = mImages[slot];
+    sp<GraphicBuffer> nextTextureBuffer = mSlots[slot].mGraphicBuffer;
 
     // release old buffer
     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
         if (pendingRelease == nullptr) {
-            status_t status =
-                    releaseBufferLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer());
+            status_t status = releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer);
             if (status < NO_ERROR) {
                 BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
                          status);
@@ -273,14 +264,15 @@
             }
         } else {
             pendingRelease->currentTexture = mCurrentTexture;
-            pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
+            pendingRelease->graphicBuffer = mCurrentTextureBuffer;
             pendingRelease->isPending = true;
         }
     }
 
     // Update the BufferLayerConsumer state.
     mCurrentTexture = slot;
-    mCurrentTextureImage = nextTextureImage;
+    mCurrentTextureBuffer = nextTextureBuffer;
+    mCurrentTextureImageFreed = nullptr;
     mCurrentCrop = item.mCrop;
     mCurrentTransform = item.mTransform;
     mCurrentScalingMode = item.mScalingMode;
@@ -301,22 +293,46 @@
 
 status_t BufferLayerConsumer::bindTextureImageLocked() {
     ATRACE_CALL();
+
     mRE.checkErrors();
 
-    if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) {
+    // It is possible for the current slot's buffer to be freed before a new one
+    // is bound. In that scenario we still want to bind the image.
+    if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureBuffer == nullptr) {
         BLC_LOGE("bindTextureImage: no currently-bound texture");
         mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
         return NO_INIT;
     }
 
-    status_t err = mCurrentTextureImage->createIfNeeded();
-    if (err != NO_ERROR) {
-        BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
-        mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
-        return UNKNOWN_ERROR;
+    renderengine::Image* imageToRender;
+
+    // mCurrentTextureImageFreed is non-null iff mCurrentTexture ==
+    // BufferQueue::INVALID_BUFFER_SLOT, so we can omit that check.
+    if (mCurrentTextureImageFreed) {
+        imageToRender = mCurrentTextureImageFreed.get();
+    } else if (mImages[mCurrentTexture]) {
+        imageToRender = mImages[mCurrentTexture].get();
+    } else {
+        std::unique_ptr<renderengine::Image> image = mRE.createImage();
+        bool success = image->setNativeWindowBuffer(mCurrentTextureBuffer->getNativeBuffer(),
+                                                    mCurrentTextureBuffer->getUsage() &
+                                                            GRALLOC_USAGE_PROTECTED);
+        if (!success) {
+            BLC_LOGE("bindTextureImage: Failed to create image. size=%ux%u st=%u usage=%#" PRIx64
+                     " fmt=%d",
+                     mCurrentTextureBuffer->getWidth(), mCurrentTextureBuffer->getHeight(),
+                     mCurrentTextureBuffer->getStride(), mCurrentTextureBuffer->getUsage(),
+                     mCurrentTextureBuffer->getPixelFormat());
+            BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
+            mRE.bindExternalTextureImage(mTexName, *image);
+            return UNKNOWN_ERROR;
+        }
+        imageToRender = image.get();
+        // Cache the image here so that we can reuse it.
+        mImages[mCurrentTexture] = std::move(image);
     }
 
-    mRE.bindExternalTextureImage(mTexName, mCurrentTextureImage->image());
+    mRE.bindExternalTextureImage(mTexName, *imageToRender);
 
     // Wait for the new buffer to be ready.
     return doFenceWaitLocked();
@@ -333,8 +349,7 @@
                 return UNKNOWN_ERROR;
             }
             status_t err =
-                    addReleaseFenceLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
-                                          releaseFence);
+                    addReleaseFenceLocked(mCurrentTexture, mCurrentTextureBuffer, releaseFence);
             if (err != OK) {
                 BLC_LOGE("syncForReleaseLocked: error adding release fence: "
                          "%s (%d)",
@@ -361,24 +376,22 @@
     bool needsRecompute = mFilteringEnabled != enabled;
     mFilteringEnabled = enabled;
 
-    if (needsRecompute && mCurrentTextureImage == nullptr) {
-        BLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == nullptr");
+    if (needsRecompute && mCurrentTextureBuffer == nullptr) {
+        BLC_LOGD("setFilteringEnabled called with mCurrentTextureBuffer == nullptr");
     }
 
-    if (needsRecompute && mCurrentTextureImage != nullptr) {
+    if (needsRecompute && mCurrentTextureBuffer != nullptr) {
         computeCurrentTransformMatrixLocked();
     }
 }
 
 void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
     BLC_LOGV("computeCurrentTransformMatrixLocked");
-    sp<GraphicBuffer> buf =
-            (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
-    if (buf == nullptr) {
+    if (mCurrentTextureBuffer == nullptr) {
         BLC_LOGD("computeCurrentTransformMatrixLocked: "
-                 "mCurrentTextureImage is nullptr");
+                 "mCurrentTextureBuffer is nullptr");
     }
-    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop,
+    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, mCurrentTextureBuffer, mCurrentCrop,
                                        mCurrentTransform, mFilteringEnabled);
 }
 
@@ -427,7 +440,7 @@
         *outSlot = mCurrentTexture;
     }
 
-    return (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
+    return mCurrentTextureBuffer;
 }
 
 Rect BufferLayerConsumer::getCurrentCrop() const {
@@ -458,11 +471,6 @@
 }
 
 status_t BufferLayerConsumer::doFenceWaitLocked() const {
-    if (!mRE.isCurrent()) {
-        BLC_LOGE("doFenceWait: RenderEngine is not current");
-        return INVALID_OPERATION;
-    }
-
     if (mCurrentFence->isValid()) {
         if (mRE.useWaitSync()) {
             base::unique_fd fenceFd(mCurrentFence->dup());
@@ -490,8 +498,10 @@
     BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
     if (slotIndex == mCurrentTexture) {
         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
+        mCurrentTextureImageFreed = std::move(mImages[slotIndex]);
+    } else {
+        mImages[slotIndex] = nullptr;
     }
-    mImages[slotIndex].clear();
     ConsumerBase::freeBufferLocked(slotIndex);
 }
 
@@ -530,7 +540,7 @@
 
 void BufferLayerConsumer::abandonLocked() {
     BLC_LOGV("abandonLocked");
-    mCurrentTextureImage.clear();
+    mCurrentTextureBuffer.clear();
     ConsumerBase::abandonLocked();
 }
 
@@ -548,29 +558,4 @@
     ConsumerBase::dumpLocked(result, prefix);
 }
 
-BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer,
-                                  renderengine::RenderEngine& engine)
-      : mGraphicBuffer(graphicBuffer),
-        mImage{engine.createImage()},
-        mCreated(false),
-        mCropWidth(0),
-        mCropHeight(0) {}
-
-BufferLayerConsumer::Image::~Image() = default;
-
-status_t BufferLayerConsumer::Image::createIfNeeded() {
-    if (mCreated) return OK;
-
-    mCreated = mImage->setNativeWindowBuffer(mGraphicBuffer->getNativeBuffer(),
-                                             mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
-    if (!mCreated) {
-        const sp<GraphicBuffer>& buffer = mGraphicBuffer;
-        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
-              buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
-              buffer->getPixelFormat());
-    }
-
-    return mCreated ? OK : UNKNOWN_ERROR;
-}
-
 }; // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index e174680..ea46245 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -185,8 +185,7 @@
     // specific info in addition to the ConsumerBase behavior.
     virtual void dumpLocked(String8& result, const char* prefix) const;
 
-    // acquireBufferLocked overrides the ConsumerBase method to update the
-    // mImages array in addition to the ConsumerBase behavior.
+    // See ConsumerBase::acquireBufferLocked
     virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
                                          uint64_t maxFrameNumber = 0) override;
 
@@ -210,53 +209,14 @@
                                     PendingRelease* pendingRelease = nullptr,
                                     const sp<Fence>& releaseFence = Fence::NO_FENCE);
 
-    // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.  Uses
-    // mCurrentTexture if it's set, mCurrentTextureImage if not.  If the
-    // bind succeeds, this calls doFenceWait.
+    // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.
+    // If the bind succeeds, this calls doFenceWait.
     status_t bindTextureImageLocked();
 
 private:
-    // Image is a utility class for tracking and creating renderengine::Images. There
-    // is primarily just one image per slot, but there is also special cases:
-    //  - After freeBuffer, we must still keep the current image/buffer
-    // Reference counting renderengine::Images lets us handle all these cases easily while
-    // also only creating new renderengine::Images from buffers when required.
-    class Image : public LightRefBase<Image> {
-    public:
-        Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine);
-
-        Image(const Image& rhs) = delete;
-        Image& operator=(const Image& rhs) = delete;
-
-        // createIfNeeded creates an renderengine::Image if we haven't created one yet.
-        status_t createIfNeeded();
-
-        const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
-        const native_handle* graphicBufferHandle() {
-            return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
-        }
-
-        const renderengine::Image& image() const { return *mImage; }
-
-    private:
-        // Only allow instantiation using ref counting.
-        friend class LightRefBase<Image>;
-        virtual ~Image();
-
-        // mGraphicBuffer is the buffer that was used to create this image.
-        sp<GraphicBuffer> mGraphicBuffer;
-
-        // mImage is the image created from mGraphicBuffer.
-        std::unique_ptr<renderengine::Image> mImage;
-        bool mCreated;
-        int32_t mCropWidth;
-        int32_t mCropHeight;
-    };
-
     // freeBufferLocked frees up the given buffer slot. If the slot has been
     // initialized this will release the reference to the GraphicBuffer in
-    // that slot and destroy the renderengine::Image in that slot.  Otherwise it has no
-    // effect.
+    // that slot.  Otherwise it has no effect.
     //
     // This method must be called with mMutex locked.
     virtual void freeBufferLocked(int slotIndex);
@@ -290,10 +250,10 @@
     // consume buffers as hardware textures.
     static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
 
-    // mCurrentTextureImage is the Image/buffer of the current texture. It's
+    // mCurrentTextureImage is the buffer containing the current texture. It's
     // possible that this buffer is not associated with any buffer slot, so we
     // must track it separately in order to support the getCurrentBuffer method.
-    sp<Image> mCurrentTextureImage;
+    sp<GraphicBuffer> mCurrentTextureBuffer;
 
     // mCurrentCrop is the crop rectangle that applies to the current texture.
     // It gets set each time updateTexImage is called.
@@ -363,15 +323,6 @@
 
     wp<ContentsChangedListener> mContentsChangedListener;
 
-    // mImages stores the buffers that have been allocated by the BufferQueue
-    // for each buffer slot.  It is initialized to null pointers, and gets
-    // filled in with the result of BufferQueue::acquire when the
-    // client dequeues a buffer from a
-    // slot that has not yet been used. The buffer allocated to a slot will also
-    // be replaced if the requested buffer usage or geometry differs from that
-    // of the buffer allocated to a slot.
-    sp<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
-
     // mCurrentTexture is the buffer slot index of the buffer that is currently
     // bound to the RenderEngine texture. It is initialized to INVALID_BUFFER_SLOT,
     // indicating that no buffer slot is currently bound to the texture. Note,
@@ -380,6 +331,17 @@
     // reset mCurrentTexture to INVALID_BUFFER_SLOT.
     int mCurrentTexture;
 
+    // Cached image used for rendering the current texture through GPU
+    // composition, which contains the cached image after freeBufferLocked is
+    // called on the current buffer. Whenever latchBuffer is called, this is
+    // expected to be cleared. Then, if bindTexImage is called before the next
+    // buffer is acquired, then this image is bound.
+    std::unique_ptr<renderengine::Image> mCurrentTextureImageFreed;
+
+    // Cached images used for rendering the current texture through GPU
+    // composition.
+    std::unique_ptr<renderengine::Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
+
     // A release that is pending on the receipt of a new release fence from
     // presentDisplay
     PendingRelease mPendingRelease;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 06e8a98..e75fbdf 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -216,7 +216,7 @@
     return mConsumer->setFilteringEnabled(enabled);
 }
 
-status_t BufferQueueLayer::bindTextureImage() const {
+status_t BufferQueueLayer::bindTextureImage() {
     return mConsumer->bindTextureImage();
 }
 
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index c239a00..abe0bc7 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -89,7 +89,7 @@
 
     void setFilteringEnabled(bool enabled) override;
 
-    status_t bindTextureImage() const override;
+    status_t bindTextureImage() override;
     status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
                             const sp<Fence>& releaseFence) override;
 
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index c817fb0..e52b35a 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -323,22 +323,14 @@
                                        mCurrentTransform, enabled);
 }
 
-status_t BufferStateLayer::bindTextureImage() const {
+status_t BufferStateLayer::bindTextureImage() {
     const State& s(getDrawingState());
     auto& engine(mFlinger->getRenderEngine());
 
-    if (!engine.isCurrent()) {
-        ALOGE("RenderEngine is not current");
-        return INVALID_OPERATION;
-    }
-
     engine.checkErrors();
 
-    if (!mTextureImage) {
-        ALOGE("no currently-bound texture");
-        engine.bindExternalTextureImage(mTextureName, *engine.createImage());
-        return NO_INIT;
-    }
+    // TODO(marissaw): once buffers are cached, don't create a new image everytime
+    mTextureImage = engine.createImage();
 
     bool created =
             mTextureImage->setNativeWindowBuffer(s.buffer->getNativeBuffer(),
@@ -385,16 +377,6 @@
         return NO_ERROR;
     }
 
-    auto& engine(mFlinger->getRenderEngine());
-    if (!engine.isCurrent()) {
-        ALOGE("RenderEngine is not current");
-        return INVALID_OPERATION;
-    }
-    engine.checkErrors();
-
-    // TODO(marissaw): once buffers are cached, don't create a new image everytime
-    mTextureImage = engine.createImage();
-
     // Reject if the layer is invalid
     uint32_t bufferWidth = s.buffer->width;
     uint32_t bufferHeight = s.buffer->height;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index b134fc5..0c6eaf5 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -114,7 +114,7 @@
 
     void setFilteringEnabled(bool enabled) override;
 
-    status_t bindTextureImage() const override;
+    status_t bindTextureImage() override;
     status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
                             const sp<Fence>& releaseFence) override;
 
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 7b79fbd..4e403b7 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -474,10 +474,7 @@
         enqueueBuffer(test, layer);
         Mock::VerifyAndClear(test->mMessageQueue);
 
-        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
         EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
-        EXPECT_CALL(*test->mRenderEngine, createImage())
-                .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
         bool ignoredRecomputeVisibleRegions;
         layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, Fence::NO_FENCE);
         Mock::VerifyAndClear(test->mRenderEngine);
@@ -574,6 +571,9 @@
                                              LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
                 .Times(1);
 
+        EXPECT_CALL(*test->mRenderEngine, createImage())
+                .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
+        EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, _)).WillOnce(Return(true));
         EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
         EXPECT_CALL(*test->mRenderEngine, setupLayerTexturing(_)).Times(1);
         EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
@@ -669,6 +669,9 @@
     static constexpr uint32_t LAYER_FLAGS = ISurfaceComposerClient::eSecure;
 
     static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mRenderEngine, createImage())
+                .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
+        EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, _)).WillOnce(Return(true));
         EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
         EXPECT_CALL(*test->mRenderEngine, setupLayerBlackedOut()).Times(1);
 
diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp
index 7fbe315..78d6694 100644
--- a/vulkan/vkjson/Android.bp
+++ b/vulkan/vkjson/Android.bp
@@ -7,6 +7,7 @@
     cflags: [
         "-Wall",
         "-Werror",
+        "-Wimplicit-fallthrough",
     ],
     cppflags: [
         "-Wno-sign-compare",
@@ -32,6 +33,7 @@
     cflags: [
         "-Wall",
         "-Werror",
+        "-Wimplicit-fallthrough",
     ],
     cppflags: [
         "-Wno-sign-compare",
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index f841862..57668a8 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -791,6 +791,7 @@
                          &device->external_fence_properties) &&
           visitor->Visit("externalSemaphoreProperties",
                          &device->external_semaphore_properties);
+      FALLTHROUGH_INTENDED;
     case VK_API_VERSION_1_0:
       ret &= visitor->Visit("properties", &device->properties) &&
              visitor->Visit("features", &device->features) &&
@@ -817,6 +818,7 @@
   switch (instance->api_version ^ VK_VERSION_PATCH(instance->api_version)) {
     case VK_API_VERSION_1_1:
       ret &= visitor->Visit("deviceGroups", &instance->device_groups);
+      FALLTHROUGH_INTENDED;
     case VK_API_VERSION_1_0:
       ret &= visitor->Visit("layers", &instance->layers) &&
              visitor->Visit("extensions", &instance->extensions) &&
diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h
index 3373f19..450fb24 100644
--- a/vulkan/vkjson/vkjson.h
+++ b/vulkan/vkjson/vkjson.h
@@ -41,6 +41,12 @@
 #define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)
 #endif
 
+/*
+ * Annotation to tell clang that we intend to fall through from one case to
+ * another in a switch. Sourced from android-base/macros.h.
+ */
+#define FALLTHROUGH_INTENDED [[clang::fallthrough]]
+
 struct VkJsonLayer {
   VkLayerProperties properties;
   std::vector<VkExtensionProperties> extensions;