SF: Separate out render surface code

This creates a new class for the purpose of holding all the
functionality related to flipping the output display surface.

Test: atest libsurfaceflinger_unittest libcompositionengine_test
Bug: 121291683
Change-Id: I108ccb75f3cd6aa1204487b0aed7c67d9fe1b85f
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index d089bf6..e8b038b 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -68,6 +68,7 @@
         "PixelFormat.cpp",
         "Rect.cpp",
         "Region.cpp",
+        "Size.cpp",
         "Transform.cpp",
         "UiConfig.cpp",
     ],
diff --git a/libs/ui/Size.cpp b/libs/ui/Size.cpp
new file mode 100644
index 0000000..d2996d1
--- /dev/null
+++ b/libs/ui/Size.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#include <ui/Size.h>
+
+namespace android::ui {
+
+const Size Size::INVALID{-1, -1};
+const Size Size::EMPTY{0, 0};
+
+} // namespace android::ui
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index e9da087..1768805 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -24,6 +24,7 @@
 
 #include <ui/FloatRect.h>
 #include <ui/Point.h>
+#include <ui/Size.h>
 
 #include <android/rect.h>
 
@@ -78,6 +79,13 @@
         bottom = static_cast<int32_t>(floatRect.bottom + 0.5f);
     }
 
+    inline explicit Rect(const ui::Size& size) {
+        left = 0;
+        top = 0;
+        right = size.width;
+        bottom = size.height;
+    }
+
     void makeInvalid();
 
     inline void clear() {
@@ -106,6 +114,8 @@
         return bottom - top;
     }
 
+    ui::Size getSize() const { return ui::Size(getWidth(), getHeight()); }
+
     __attribute__((no_sanitize("signed-integer-overflow")))
     inline Rect getBounds() const {
         return Rect(right - left, bottom - top);
diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h
new file mode 100644
index 0000000..c39d8af
--- /dev/null
+++ b/libs/ui/include/ui/Size.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+namespace android {
+namespace ui {
+
+// Forward declare a few things.
+struct Size;
+bool operator==(const Size& lhs, const Size& rhs);
+
+/**
+ * A simple value type representing a two-dimensional size
+ */
+struct Size {
+    int32_t width;
+    int32_t height;
+
+    // Special values
+    static const Size INVALID;
+    static const Size EMPTY;
+
+    // ------------------------------------------------------------------------
+    // Construction
+    // ------------------------------------------------------------------------
+
+    Size() : Size(INVALID) {}
+    template <typename T>
+    Size(T&& w, T&& h)
+          : width(Size::clamp<int32_t, T>(std::forward<T>(w))),
+            height(Size::clamp<int32_t, T>(std::forward<T>(h))) {}
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+
+    int32_t getWidth() const { return width; }
+    int32_t getHeight() const { return height; }
+
+    template <typename T>
+    void setWidth(T&& v) {
+        width = Size::clamp<int32_t, T>(std::forward<T>(v));
+    }
+    template <typename T>
+    void setHeight(T&& v) {
+        height = Size::clamp<int32_t, T>(std::forward<T>(v));
+    }
+
+    // ------------------------------------------------------------------------
+    // Assignment
+    // ------------------------------------------------------------------------
+
+    void set(const Size& size) { *this = size; }
+    template <typename T>
+    void set(T&& w, T&& h) {
+        set(Size(std::forward<T>(w), std::forward<T>(h)));
+    }
+
+    // Sets the value to INVALID
+    void makeInvalid() { set(INVALID); }
+
+    // Sets the value to EMPTY
+    void clear() { set(EMPTY); }
+
+    // ------------------------------------------------------------------------
+    // Semantic checks
+    // ------------------------------------------------------------------------
+
+    // Valid means non-negative width and height
+    bool isValid() const { return width >= 0 && height >= 0; }
+
+    // Empty means zero width and height
+    bool isEmpty() const { return *this == EMPTY; }
+
+    // ------------------------------------------------------------------------
+    // Clamp Helpers
+    // ------------------------------------------------------------------------
+
+    // Note: We use only features available in C++11 here for compatibility with
+    // external targets which include this file directly or indirectly and which
+    // themselves use C++11.
+
+    // C++11 compatible replacement for std::remove_cv_reference_t [C++20]
+    template <typename T>
+    using remove_cv_reference_t =
+            typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+
+    // Takes a value of type FromType, and ensures it can be represented as a value of type ToType,
+    // clamping the input value to the output range if necessary.
+    template <typename ToType, typename FromType>
+    static Size::remove_cv_reference_t<ToType> clamp(
+            typename std::enable_if<
+                    std::numeric_limits<Size::remove_cv_reference_t<ToType>>::is_bounded &&
+                            std::numeric_limits<Size::remove_cv_reference_t<FromType>>::is_bounded,
+                    FromType&&>::type v) {
+        static constexpr auto toHighest = std::numeric_limits<remove_cv_reference_t<ToType>>::max();
+        static constexpr auto toLowest =
+                std::numeric_limits<remove_cv_reference_t<ToType>>::lowest();
+        static constexpr auto fromHighest =
+                std::numeric_limits<remove_cv_reference_t<FromType>>::max();
+        static constexpr auto fromLowest =
+                std::numeric_limits<remove_cv_reference_t<FromType>>::lowest();
+
+        // A clamp is needed if the range of FromType is not a subset of the range of ToType
+        static constexpr bool isClampNeeded = (toLowest > fromLowest) || (toHighest < fromHighest);
+
+        // If a clamp is not needed, the conversion is just a trivial cast.
+        if (!isClampNeeded) {
+            return static_cast<ToType>(v);
+        }
+
+        // Otherwise we leverage implicit conversion to safely compare values of
+        // different types, to ensure we return a value clamped to the range of
+        // ToType.
+        return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast<ToType>(v));
+    }
+};
+
+// ------------------------------------------------------------------------
+// Comparisons
+// ------------------------------------------------------------------------
+
+inline bool operator==(const Size& lhs, const Size& rhs) {
+    return lhs.width == rhs.width && lhs.height == rhs.height;
+}
+
+inline bool operator!=(const Size& lhs, const Size& rhs) {
+    return !operator==(lhs, rhs);
+}
+
+inline bool operator<(const Size& lhs, const Size& rhs) {
+    // Orders by increasing width, then height.
+    if (lhs.width != rhs.width) return lhs.width < rhs.width;
+    return lhs.height < rhs.height;
+}
+
+} // namespace ui
+} // namespace android
diff --git a/libs/ui/include_vndk/ui/Size.h b/libs/ui/include_vndk/ui/Size.h
new file mode 120000
index 0000000..fd2b21b
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Size.h
@@ -0,0 +1 @@
+../../include/ui/Size.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 665469e..373fa4f 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -71,3 +71,10 @@
     ],
     cflags: ["-Wall", "-Werror"],
 }
+
+cc_test {
+    name: "Size_test",
+    shared_libs: ["libui"],
+    srcs: ["Size_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+}
diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp
new file mode 100644
index 0000000..69e1ac8
--- /dev/null
+++ b/libs/ui/tests/Size_test.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2019 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 "SizeTest"
+
+#include <cmath>
+#include <cstdlib>
+
+#include <ui/Size.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace ui {
+
+TEST(SizeTest, BasicConstructionAndEqualityComparison) {
+    Size s(123, 456);
+
+    EXPECT_EQ(123, s.width);
+    EXPECT_EQ(123, s.getWidth());
+
+    EXPECT_EQ(456, s.height);
+    EXPECT_EQ(456, s.getHeight());
+
+    EXPECT_EQ(Size(123, 456), s);
+    EXPECT_NE(Size(456, 123), s);
+}
+
+TEST(SizeTest, BasicLessThanComparison) {
+    EXPECT_TRUE(Size(0, 1) < Size(2, 3));
+    EXPECT_FALSE(Size(2, 3) < Size(0, 1));
+
+    EXPECT_TRUE(Size(0, 3) < Size(2, 1));
+    EXPECT_FALSE(Size(2, 1) < Size(0, 3));
+
+    EXPECT_TRUE(Size(0, 1) < Size(0, 3));
+    EXPECT_FALSE(Size(0, 3) < Size(0, 1));
+
+    EXPECT_FALSE(Size(1, 1) < Size(1, 1));
+}
+
+TEST(SizeTest, ValidAndEmpty) {
+    {
+        Size s;
+        EXPECT_FALSE(s.isValid());
+        EXPECT_FALSE(s.isEmpty());
+    }
+
+    {
+        Size s(-1, -1);
+        EXPECT_FALSE(s.isValid());
+        EXPECT_FALSE(s.isEmpty());
+    }
+
+    {
+        Size s(1, -1000);
+        EXPECT_FALSE(s.isValid());
+        EXPECT_FALSE(s.isEmpty());
+    }
+
+    {
+        Size s(-1000, 1);
+        EXPECT_FALSE(s.isValid());
+        EXPECT_FALSE(s.isEmpty());
+    }
+
+    {
+        Size s(-1000, -1000);
+        EXPECT_FALSE(s.isValid());
+        EXPECT_FALSE(s.isEmpty());
+    }
+
+    {
+        const auto& s = Size::INVALID;
+        EXPECT_FALSE(s.isValid());
+        EXPECT_FALSE(s.isEmpty());
+    }
+
+    {
+        Size s(123, 456);
+        s.makeInvalid();
+        EXPECT_FALSE(s.isValid());
+        EXPECT_FALSE(s.isEmpty());
+    }
+
+    {
+        Size s(0, 0);
+        EXPECT_TRUE(s.isValid());
+        EXPECT_TRUE(s.isEmpty());
+    }
+
+    {
+        const auto& s = Size::EMPTY;
+        EXPECT_TRUE(s.isValid());
+        EXPECT_TRUE(s.isEmpty());
+    }
+
+    {
+        Size s(123, 456);
+        s.clear();
+        EXPECT_TRUE(s.isValid());
+        EXPECT_TRUE(s.isEmpty());
+    }
+
+    {
+        Size s(123, 456);
+        EXPECT_TRUE(s.isValid());
+        EXPECT_FALSE(s.isEmpty());
+    }
+}
+
+TEST(SizeTest, Set) {
+    {
+        Size s;
+        s.setWidth(0);
+        EXPECT_EQ(Size(0, -1), s);
+    }
+
+    {
+        Size s;
+        s.setHeight(0);
+        EXPECT_EQ(Size(-1, 0), s);
+    }
+
+    {
+        Size s;
+        s.set(123, 456);
+        EXPECT_EQ(Size(123, 456), s);
+    }
+}
+
+template <typename T, typename U>
+void ClampTest(T input, U expected) {
+    // The constructor, set(), setWidth() and setHeight() all allow arbitrary
+    // conversions from other numeric types, and implement clamping if necessary.
+
+    EXPECT_EQ(Size(expected, expected), Size(input, input));
+
+    {
+        Size s;
+        s.set(input, input);
+        EXPECT_EQ(Size(expected, expected), s);
+    }
+
+    {
+        Size s;
+        s.setWidth(input);
+        EXPECT_EQ(expected, s.width);
+    }
+
+    {
+        Size s;
+        s.setHeight(input);
+        EXPECT_EQ(expected, s.height);
+    }
+}
+
+TEST(SizeTest, Int8RangeIsNotClamped) {
+    ClampTest(std::numeric_limits<int8_t>::max(), std::numeric_limits<int8_t>::max());
+    ClampTest(int8_t(0), int8_t(0));
+    ClampTest(std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::lowest());
+}
+
+TEST(SizeTest, FloatRangeIsClamped) {
+    ClampTest(std::numeric_limits<float>::max(), std::numeric_limits<int32_t>::max());
+    ClampTest(float(0), int32_t(0));
+    ClampTest(std::numeric_limits<float>::lowest(), std::numeric_limits<int32_t>::lowest());
+}
+
+} // namespace ui
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 64db6ef..6ec0e60 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -16,6 +16,8 @@
         "libgui",
         "liblayers_proto",
         "liblog",
+        "libnativewindow",
+        "libsync",
         "libtimestats_proto",
         "libui",
         "libutils",
@@ -40,6 +42,7 @@
         "src/DumpHelpers.cpp",
         "src/Output.cpp",
         "src/OutputCompositionState.cpp",
+        "src/RenderSurface.cpp",
     ],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
@@ -53,6 +56,7 @@
         "mock/Display.cpp",
         "mock/DisplaySurface.cpp",
         "mock/Output.cpp",
+        "mock/RenderSurface.cpp",
     ],
     static_libs: [
         "libgtest",
@@ -72,6 +76,7 @@
         "tests/DisplayTest.cpp",
         "tests/OutputTest.cpp",
         "tests/MockHWComposer.cpp",
+        "tests/RenderSurfaceTest.cpp",
     ],
     static_libs: [
         "libcompositionengine",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
index 979fdad..9ba6671 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -25,6 +25,8 @@
 
 namespace android::compositionengine {
 
+struct RenderSurfaceCreationArgs;
+
 /**
  * A display is a composition target which may be backed by a hardware composer
  * display device
@@ -43,6 +45,8 @@
     // Releases the use of the HWC display, if any
     virtual void disconnect() = 0;
 
+    virtual void createRenderSurface(RenderSurfaceCreationArgs&&) = 0;
+
 protected:
     ~Display() = default;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 731189f..7814bcb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -26,6 +26,8 @@
 
 namespace android::compositionengine {
 
+class RenderSurface;
+
 namespace impl {
 struct OutputCompositionState;
 } // namespace impl
@@ -47,7 +49,7 @@
     virtual void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
                                const Rect& viewport, const Rect& scissor, bool needsFiltering) = 0;
     // Sets the bounds to use
-    virtual void setBounds(const Rect&) = 0;
+    virtual void setBounds(const ui::Size&) = 0;
 
     // Sets the layer stack filter for this output. If singleLayerStack is true,
     // this output displays just the single layer stack specified by
@@ -70,6 +72,9 @@
     // Sets a debug name for the output
     virtual void setName(const std::string&) = 0;
 
+    // Gets the current render surface for the output
+    virtual RenderSurface* getRenderSurface() const = 0;
+
     using OutputCompositionState = compositionengine::impl::OutputCompositionState;
 
     // Gets the raw composition state data for the output
@@ -92,6 +97,8 @@
 
 protected:
     ~Output() = default;
+
+    virtual void setRenderSurface(std::unique_ptr<RenderSurface> surface) = 0;
 };
 
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
new file mode 100644
index 0000000..dd01b05
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+#include <ui/Fence.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Size.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class GraphicBuffer;
+
+struct CompositionInfo;
+
+namespace compositionengine {
+
+/**
+ * Encapsulates everything for composing to a render surface with RenderEngine
+ */
+class RenderSurface {
+public:
+    virtual ~RenderSurface();
+
+    // Returns true if the render surface is valid. This is meant to be checked
+    // post-construction and prior to use, as not everything is set up by the
+    // constructor.
+    virtual bool isValid() const = 0;
+
+    // Performs one-time initialization of the render surface. This is meant
+    // to be called after the validation check.
+    virtual void initialize() = 0;
+
+    // Returns the bounds of the surface
+    virtual const ui::Size& getSize() const = 0;
+
+    // Gets the latest fence to pass to the HWC to signal that the surface
+    // buffer is done rendering
+    virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
+
+    // Sets the size of the surface
+    virtual void setDisplaySize(const ui::Size&) = 0;
+
+    // Sets the dataspace used for rendering the surface
+    virtual void setBufferDataspace(ui::Dataspace) = 0;
+
+    // Configures the protected rendering on the surface
+    virtual void setProtected(bool useProtected) = 0;
+
+    // Called to signal that rendering has started. 'mustRecompose' should be
+    // true if the entire frame must be recomposed.
+    virtual status_t beginFrame(bool mustRecompose) = 0;
+
+    // Prepares the frame for rendering
+    virtual status_t prepareFrame(std::vector<CompositionInfo>& compositionData) = 0;
+
+    // Allocates a buffer as scratch space for GPU composition
+    virtual sp<GraphicBuffer> dequeueBuffer() = 0;
+
+    // Queues the drawn buffer for consumption by HWC
+    virtual void queueBuffer() = 0;
+
+    // Called after the HWC calls are made to present the display
+    virtual void onPresentDisplayCompleted() = 0;
+
+    // Marks the current buffer has finished, so that it can be presented and
+    // swapped out
+    virtual void finishBuffer() = 0;
+
+    // Called to set the viewport and projection state for rendering into this
+    // surface
+    virtual void setViewportAndProjection() = 0;
+
+    // Called after the surface has been rendering to signal the surface should
+    // be made ready for displaying
+    virtual void flip() = 0;
+
+    // Debugging - Dumps the state of the RenderSurface to a string
+    virtual void dump(std::string& result) const = 0;
+
+    // Debugging - gets the page flip count for the RenderSurface
+    virtual std::uint32_t getPageFlipCount() const = 0;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
new file mode 100644
index 0000000..a1230b3
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <memory>
+
+#include <compositionengine/DisplaySurface.h>
+#include <utils/StrongPointer.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+namespace compositionengine {
+
+class Display;
+
+/**
+ * A parameter object for creating RenderSurface instances
+ */
+struct RenderSurfaceCreationArgs {
+    // The initial width of the surface
+    int32_t displayWidth;
+
+    // The initial height of the surface
+    int32_t displayHeight;
+
+    // The ANativeWindow for the buffer queue for this surface
+    sp<ANativeWindow> nativeWindow;
+
+    // The DisplaySurface for this surface
+    sp<DisplaySurface> displaySurface;
+};
+
+/**
+ * A helper for setting up a RenderSurfaceCreationArgs value in-line.
+ * Prefer this builder over raw structure initialization.
+ *
+ * Instead of:
+ *
+ *   RenderSurfaceCreationArgs{1000, 1000, nativeWindow, displaySurface}
+ *
+ * Prefer:
+ *
+ *  RenderSurfaceCreationArgsBuilder().setDisplayWidth(1000).setDisplayHeight(1000)
+ *      .setNativeWindow(nativeWindow).setDisplaySurface(displaySurface).Build();
+ */
+class RenderSurfaceCreationArgsBuilder {
+public:
+    RenderSurfaceCreationArgs build() { return std::move(mArgs); }
+
+    RenderSurfaceCreationArgsBuilder& setDisplayWidth(int32_t displayWidth) {
+        mArgs.displayWidth = displayWidth;
+        return *this;
+    }
+    RenderSurfaceCreationArgsBuilder& setDisplayHeight(int32_t displayHeight) {
+        mArgs.displayHeight = displayHeight;
+        return *this;
+    }
+    RenderSurfaceCreationArgsBuilder& setNativeWindow(sp<ANativeWindow> nativeWindow) {
+        mArgs.nativeWindow = nativeWindow;
+        return *this;
+    }
+    RenderSurfaceCreationArgsBuilder& setDisplaySurface(sp<DisplaySurface> displaySurface) {
+        mArgs.displaySurface = displaySurface;
+        return *this;
+    }
+
+private:
+    RenderSurfaceCreationArgs mArgs;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 7c38c49..5609382 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -46,6 +46,7 @@
     bool isSecure() const override;
     bool isVirtual() const override;
     void disconnect() override;
+    void createRenderSurface(compositionengine::RenderSurfaceCreationArgs&&) override;
 
 private:
     const bool mIsVirtual;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
index 663010f..782c8d7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
@@ -55,6 +55,7 @@
 void dumpVal(std::string& out, const char* name, const Rect& rect);
 void dumpVal(std::string& out, const char* name, const Region& region);
 void dumpVal(std::string& out, const char* name, const ui::Transform&);
+void dumpVal(std::string& out, const char* name, const ui::Size&);
 
 void dumpVal(std::string& out, const char* name, const mat4& tr);
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 60b94a4..86a1662 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -37,7 +37,7 @@
     void setCompositionEnabled(bool) override;
     void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
                        const Rect& viewport, const Rect& scissor, bool needsFiltering) override;
-    void setBounds(const Rect&) override;
+    void setBounds(const ui::Size&) override;
     void setLayerStackFilter(bool singleLayerStack, uint32_t singleLayerStackId) override;
 
     void setColorTransform(const mat4&) override;
@@ -48,12 +48,18 @@
     const std::string& getName() const override;
     void setName(const std::string&) override;
 
+    compositionengine::RenderSurface* getRenderSurface() const override;
+    void setRenderSurface(std::unique_ptr<compositionengine::RenderSurface>) override;
+
     const OutputCompositionState& getState() const override;
     OutputCompositionState& editState() override;
 
     Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const override;
     bool belongsInOutput(uint32_t) const override;
 
+    // Testing
+    void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
+
 protected:
     const CompositionEngine& getCompositionEngine() const;
     void dumpBase(std::string&) const;
@@ -66,6 +72,8 @@
     std::string mName;
 
     OutputCompositionState mState;
+
+    std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
new file mode 100644
index 0000000..0489310
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <android-base/unique_fd.h>
+#include <compositionengine/RenderSurface.h>
+#include <utils/StrongPointer.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+namespace compositionengine {
+
+class CompositionEngine;
+class Display;
+class DisplaySurface;
+
+struct RenderSurfaceCreationArgs;
+
+namespace impl {
+
+class RenderSurface : public compositionengine::RenderSurface {
+public:
+    RenderSurface(const CompositionEngine&, compositionengine::Display&,
+                  compositionengine::RenderSurfaceCreationArgs&&);
+    ~RenderSurface() override;
+
+    bool isValid() const override;
+    void initialize() override;
+    const ui::Size& getSize() const override;
+
+    const sp<Fence>& getClientTargetAcquireFence() const override;
+    void setBufferDataspace(ui::Dataspace) override;
+    void setDisplaySize(const ui::Size&) override;
+    void setProtected(bool useProtected) override;
+    status_t beginFrame(bool mustRecompose) override;
+    status_t prepareFrame(std::vector<CompositionInfo>& compositionData) override;
+    sp<GraphicBuffer> dequeueBuffer() override;
+    void queueBuffer() override;
+    void onPresentDisplayCompleted() override;
+    void finishBuffer() override;
+    void setViewportAndProjection() override;
+    void flip() override;
+
+    // Debugging
+    void dump(std::string& result) const override;
+    std::uint32_t getPageFlipCount() const override;
+
+    // Testing
+    void setPageFlipCountForTest(std::uint32_t);
+    void setSizeForTest(const ui::Size&);
+    sp<GraphicBuffer>& mutableGraphicBufferForTest();
+    base::unique_fd& mutableBufferReadyForTest();
+
+private:
+    const compositionengine::CompositionEngine& mCompositionEngine;
+    const compositionengine::Display& mDisplay;
+
+    // ANativeWindow being rendered into
+    const sp<ANativeWindow> mNativeWindow;
+    // Current buffer being rendered into
+    sp<GraphicBuffer> mGraphicBuffer;
+    // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
+    // that drawing to the buffer is now complete.
+    base::unique_fd mBufferReady;
+    const sp<DisplaySurface> mDisplaySurface;
+    ui::Size mSize;
+    std::uint32_t mPageFlipCount{0};
+};
+
+std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
+        const compositionengine::CompositionEngine&, compositionengine::Display&,
+        compositionengine::RenderSurfaceCreationArgs&&);
+
+} // namespace impl
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index 22eb8f5..e4adfc5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -17,8 +17,11 @@
 #pragma once
 
 #include <compositionengine/Display.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
 #include <compositionengine/mock/Output.h>
 #include <gmock/gmock.h>
+#include <system/window.h>
 
 #include "DisplayHardware/DisplayIdentification.h"
 
@@ -34,6 +37,8 @@
     MOCK_CONST_METHOD0(isVirtual, bool());
 
     MOCK_METHOD0(disconnect, void());
+
+    MOCK_METHOD1(createRenderSurface, void(RenderSurfaceCreationArgs&&));
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index ccdf804..3f2cc05 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <compositionengine/Output.h>
+#include <compositionengine/RenderSurface.h>
 #include <compositionengine/impl/OutputCompositionState.h>
 #include <gmock/gmock.h>
 
@@ -32,7 +33,7 @@
     MOCK_METHOD1(setCompositionEnabled, void(bool));
     MOCK_METHOD6(setProjection,
                  void(const ui::Transform&, int32_t, const Rect&, const Rect&, const Rect&, bool));
-    MOCK_METHOD1(setBounds, void(const Rect&));
+    MOCK_METHOD1(setBounds, void(const ui::Size&));
     MOCK_METHOD2(setLayerStackFilter, void(bool, uint32_t));
 
     MOCK_METHOD1(setColorTransform, void(const mat4&));
@@ -42,6 +43,9 @@
     MOCK_CONST_METHOD0(getName, const std::string&());
     MOCK_METHOD1(setName, void(const std::string&));
 
+    MOCK_CONST_METHOD0(getRenderSurface, RenderSurface*());
+    MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<RenderSurface>));
+
     MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
     MOCK_METHOD0(editState, OutputCompositionState&());
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
new file mode 100644
index 0000000..2269e57
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <compositionengine/RenderSurface.h>
+#include <gmock/gmock.h>
+#include <ui/GraphicBuffer.h>
+
+#include "LayerBE.h"
+
+namespace android::compositionengine::mock {
+
+class RenderSurface : public compositionengine::RenderSurface {
+public:
+    RenderSurface();
+    ~RenderSurface() override;
+
+    MOCK_CONST_METHOD0(isValid, bool());
+    MOCK_METHOD0(initialize, void());
+    MOCK_CONST_METHOD0(getSize, const ui::Size&());
+    MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
+    MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
+    MOCK_METHOD1(setProtected, void(bool));
+    MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
+    MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
+    MOCK_METHOD1(prepareFrame, status_t(std::vector<CompositionInfo>& compositionData));
+    MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
+    MOCK_METHOD0(queueBuffer, void());
+    MOCK_METHOD0(onPresentDisplayCompleted, void());
+    MOCK_METHOD0(finishBuffer, void());
+    MOCK_METHOD0(setViewportAndProjection, void());
+    MOCK_METHOD0(flip, void());
+    MOCK_CONST_METHOD1(dump, void(std::string& result));
+    MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp
new file mode 100644
index 0000000..fe718d6
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#include <compositionengine/mock/RenderSurface.h>
+
+namespace android::compositionengine::mock {
+
+// Explicit default instantiation is recommended.
+RenderSurface::RenderSurface() = default;
+RenderSurface::~RenderSurface() = default;
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index fb783e7..ae77614 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -17,8 +17,10 @@
 #include <android-base/stringprintf.h>
 #include <compositionengine/CompositionEngine.h>
 #include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
 #include <compositionengine/impl/Display.h>
 #include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/RenderSurface.h>
 
 #include "DisplayHardware/HWComposer.h"
 
@@ -107,4 +109,9 @@
     Output::dumpBase(out);
 }
 
+void Display::createRenderSurface(RenderSurfaceCreationArgs&& args) {
+    setRenderSurface(compositionengine::impl::createRenderSurface(getCompositionEngine(), *this,
+                                                                  std::move(args)));
+}
+
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
index ba86be7..c497013 100644
--- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -79,6 +79,10 @@
     transform.dump(out, name);
 }
 
+void dumpVal(std::string& out, const char* name, const ui::Size& size) {
+    StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height);
+}
+
 void dumpVal(std::string& out, const char* name, const mat4& tr) {
     StringAppendF(&out,
                   "%s=["
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 8b2441f..b74c5c6 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -16,6 +16,7 @@
 
 #include <android-base/stringprintf.h>
 #include <compositionengine/CompositionEngine.h>
+#include <compositionengine/RenderSurface.h>
 #include <compositionengine/impl/Output.h>
 #include <ui/DebugUtils.h>
 
@@ -31,7 +32,7 @@
 }
 
 bool Output::isValid() const {
-    return true;
+    return mRenderSurface && mRenderSurface->isValid();
 }
 
 const std::string& Output::getName() const {
@@ -63,8 +64,11 @@
     dirtyEntireOutput();
 }
 
-void Output::setBounds(const Rect& bounds) {
-    mState.bounds = bounds;
+// TODO(lpique): Rename setSize() once more is moved.
+void Output::setBounds(const ui::Size& size) {
+    mRenderSurface->setDisplaySize(size);
+    // TODO(lpique): Rename mState.size once more is moved.
+    mState.bounds = Rect(mRenderSurface->getSize());
 
     dirtyEntireOutput();
 }
@@ -89,6 +93,8 @@
     mState.dataspace = dataspace;
     mState.renderIntent = renderIntent;
 
+    mRenderSurface->setBufferDataspace(dataspace);
+
     ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
           decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
           renderIntent);
@@ -106,6 +112,27 @@
 
 void Output::dumpBase(std::string& out) const {
     mState.dump(out);
+
+    if (mRenderSurface) {
+        mRenderSurface->dump(out);
+    } else {
+        out.append("    No render surface!\n");
+    }
+}
+
+compositionengine::RenderSurface* Output::getRenderSurface() const {
+    return mRenderSurface.get();
+}
+
+void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
+    mRenderSurface = std::move(surface);
+    mState.bounds = Rect(mRenderSurface->getSize());
+
+    dirtyEntireOutput();
+}
+
+void Output::setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface> surface) {
+    mRenderSurface = std::move(surface);
 }
 
 const OutputCompositionState& Output::getState() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
new file mode 100644
index 0000000..d546fc8
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#include <android-base/stringprintf.h>
+#include <android/native_window.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/RenderSurface.h>
+#include <log/log.h>
+#include <renderengine/RenderEngine.h>
+#include <sync/sync.h>
+#include <system/window.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine {
+
+RenderSurface::~RenderSurface() = default;
+
+namespace impl {
+
+std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
+        const compositionengine::CompositionEngine& compositionEngine,
+        compositionengine::Display& display, compositionengine::RenderSurfaceCreationArgs&& args) {
+    return std::make_unique<RenderSurface>(compositionEngine, display, std::move(args));
+}
+
+RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display& display,
+                             RenderSurfaceCreationArgs&& args)
+      : mCompositionEngine(compositionEngine),
+        mDisplay(display),
+        mNativeWindow(args.nativeWindow),
+        mDisplaySurface(args.displaySurface),
+        mSize(args.displayWidth, args.displayHeight) {}
+
+RenderSurface::~RenderSurface() = default;
+
+bool RenderSurface::isValid() const {
+    return mSize.isValid();
+}
+
+void RenderSurface::initialize() {
+    ANativeWindow* const window = mNativeWindow.get();
+
+    int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+    ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
+    status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
+    ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
+    status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER);
+    ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
+}
+
+const ui::Size& RenderSurface::getSize() const {
+    return mSize;
+}
+
+const sp<Fence>& RenderSurface::getClientTargetAcquireFence() const {
+    return mDisplaySurface->getClientTargetAcquireFence();
+}
+
+void RenderSurface::setDisplaySize(const ui::Size& size) {
+    mDisplaySurface->resizeBuffers(size.width, size.height);
+    mSize = size;
+}
+
+void RenderSurface::setBufferDataspace(ui::Dataspace dataspace) {
+    native_window_set_buffers_data_space(mNativeWindow.get(),
+                                         static_cast<android_dataspace>(dataspace));
+}
+
+void RenderSurface::setProtected(bool useProtected) {
+    uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
+    if (useProtected) {
+        usageFlags |= GRALLOC_USAGE_PROTECTED;
+    }
+    const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
+    ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
+}
+
+status_t RenderSurface::beginFrame(bool mustRecompose) {
+    return mDisplaySurface->beginFrame(mustRecompose);
+}
+
+status_t RenderSurface::prepareFrame(std::vector<CompositionInfo>& compositionData) {
+    auto& hwc = mCompositionEngine.getHwComposer();
+    const auto id = mDisplay.getId();
+    if (id) {
+        status_t error = hwc.prepare(*id, compositionData);
+        if (error != NO_ERROR) {
+            return error;
+        }
+    }
+
+    DisplaySurface::CompositionType compositionType;
+    const bool hasClient = hwc.hasClientComposition(id);
+    const bool hasDevice = hwc.hasDeviceComposition(id);
+    if (hasClient && hasDevice) {
+        compositionType = DisplaySurface::COMPOSITION_MIXED;
+    } else if (hasClient) {
+        compositionType = DisplaySurface::COMPOSITION_GLES;
+    } else if (hasDevice) {
+        compositionType = DisplaySurface::COMPOSITION_HWC;
+    } else {
+        // Nothing to do -- when turning the screen off we get a frame like
+        // this. Call it a HWC frame since we won't be doing any GLES work but
+        // will do a prepare/set cycle.
+        compositionType = DisplaySurface::COMPOSITION_HWC;
+    }
+    return mDisplaySurface->prepareFrame(compositionType);
+}
+
+sp<GraphicBuffer> RenderSurface::dequeueBuffer() {
+    int fd = -1;
+    ANativeWindowBuffer* buffer = nullptr;
+
+    status_t result = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
+
+    if (result != NO_ERROR) {
+        ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
+              mDisplay.getName().c_str(), result);
+        // Return fast here as we can't do much more - any rendering we do
+        // now will just be wrong.
+        return mGraphicBuffer;
+    }
+
+    ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
+             mGraphicBuffer->getNativeBuffer()->handle);
+    mGraphicBuffer = GraphicBuffer::from(buffer);
+
+    // Block until the buffer is ready
+    // TODO(alecmouri): it's perhaps more appropriate to block renderengine so
+    // that the gl driver can block instead.
+    if (fd >= 0) {
+        sync_wait(fd, -1);
+        close(fd);
+    }
+
+    return mGraphicBuffer;
+}
+
+void RenderSurface::queueBuffer() {
+    auto& hwc = mCompositionEngine.getHwComposer();
+    const auto id = mDisplay.getId();
+
+    if (hwc.hasClientComposition(id) || hwc.hasFlipClientTargetRequest(id)) {
+        // hasFlipClientTargetRequest could return true even if we haven't
+        // dequeued a buffer before. Try dequeueing one if we don't have a
+        // buffer ready.
+        if (mGraphicBuffer == nullptr) {
+            ALOGI("Attempting to queue a client composited buffer without one "
+                  "previously dequeued for display [%s]. Attempting to dequeue "
+                  "a scratch buffer now",
+                  mDisplay.getName().c_str());
+            // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
+            // after a successful call to queueBuffer, or if dequeueBuffer has
+            // never been called.
+            dequeueBuffer();
+        }
+
+        if (mGraphicBuffer == nullptr) {
+            ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str());
+        } else {
+            status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(),
+                                                         mGraphicBuffer->getNativeBuffer(),
+                                                         dup(mBufferReady));
+            if (result != NO_ERROR) {
+                ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
+                      result);
+                // We risk blocking on dequeueBuffer if the primary display failed
+                // to queue up its buffer, so crash here.
+                if (!mDisplay.isVirtual()) {
+                    LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
+                } else {
+                    mNativeWindow->cancelBuffer(mNativeWindow.get(),
+                                                mGraphicBuffer->getNativeBuffer(),
+                                                dup(mBufferReady));
+                }
+            }
+
+            mBufferReady.reset();
+            mGraphicBuffer = nullptr;
+        }
+    }
+
+    status_t result = mDisplaySurface->advanceFrame();
+    if (result != NO_ERROR) {
+        ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplay.getName().c_str(), result);
+    }
+}
+
+void RenderSurface::onPresentDisplayCompleted() {
+    mDisplaySurface->onFrameCommitted();
+}
+
+void RenderSurface::setViewportAndProjection() {
+    auto& renderEngine = mCompositionEngine.getRenderEngine();
+    Rect sourceCrop = Rect(mSize);
+    renderEngine.setViewportAndProjection(mSize.width, mSize.height, sourceCrop,
+                                          ui::Transform::ROT_0);
+}
+
+void RenderSurface::finishBuffer() {
+    auto& renderEngine = mCompositionEngine.getRenderEngine();
+    mBufferReady = renderEngine.flush();
+    if (mBufferReady.get() < 0) {
+        renderEngine.finish();
+    }
+}
+
+void RenderSurface::flip() {
+    mPageFlipCount++;
+}
+
+void RenderSurface::dump(std::string& out) const {
+    using android::base::StringAppendF;
+
+    out.append("   Composition RenderSurface State:");
+
+    out.append("\n   ");
+
+    dumpVal(out, "size", mSize);
+    StringAppendF(&out, "ANativeWindow=%p (format %d) ", mNativeWindow.get(),
+                  ANativeWindow_getFormat(mNativeWindow.get()));
+    dumpVal(out, "flips", mPageFlipCount);
+    out.append("\n");
+
+    String8 surfaceDump;
+    mDisplaySurface->dumpAsString(surfaceDump);
+    out.append(surfaceDump);
+}
+
+std::uint32_t RenderSurface::getPageFlipCount() const {
+    return mPageFlipCount;
+}
+
+void RenderSurface::setPageFlipCountForTest(std::uint32_t count) {
+    mPageFlipCount = count;
+}
+
+void RenderSurface::setSizeForTest(const ui::Size& size) {
+    mSize = size;
+}
+
+sp<GraphicBuffer>& RenderSurface::mutableGraphicBufferForTest() {
+    return mGraphicBuffer;
+}
+
+base::unique_fd& RenderSurface::mutableBufferReadyForTest() {
+    return mBufferReady;
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index a04c2aa..589fdc3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -17,15 +17,20 @@
 #include <cmath>
 
 #include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
 #include <compositionengine/impl/Display.h>
 #include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/RenderSurface.h>
 #include <gtest/gtest.h>
+#include <system/window.h>
 
 #include "MockHWComposer.h"
 
 namespace android::compositionengine {
 namespace {
 
+using testing::Return;
 using testing::ReturnRef;
 using testing::StrictMock;
 
@@ -131,6 +136,9 @@
  */
 
 TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) {
+    mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+    mDisplay.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
     EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
 
     // These values are expected to be the initial state.
@@ -147,6 +155,7 @@
     EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
 
     // Otherwise if the values are different, updates happen
+    EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
     EXPECT_CALL(mHwComposer,
                 setActiveColorMode(DEFAULT_DISPLAY_ID, ui::ColorMode::BT2100_PQ,
                                    ui::RenderIntent::TONE_MAP_COLORIMETRIC))
@@ -172,5 +181,15 @@
     EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay.getState().renderIntent);
 }
 
+/* ------------------------------------------------------------------------
+ * Display::createRenderSurface()
+ */
+
+TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) {
+    EXPECT_TRUE(mDisplay.getRenderSurface() == nullptr);
+    mDisplay.createRenderSurface(RenderSurfaceCreationArgs{640, 480, nullptr, nullptr});
+    EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr);
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 0cd0d23..4807445 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -18,6 +18,7 @@
 
 #include <compositionengine/impl/Output.h>
 #include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/RenderSurface.h>
 #include <gtest/gtest.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -28,14 +29,19 @@
 namespace android::compositionengine {
 namespace {
 
+using testing::Return;
 using testing::ReturnRef;
 using testing::StrictMock;
 
 class OutputTest : public testing::Test {
 public:
+    OutputTest() {
+        mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+    }
     ~OutputTest() override = default;
 
     StrictMock<mock::CompositionEngine> mCompositionEngine;
+    mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
     impl::Output mOutput{mCompositionEngine};
 };
 
@@ -43,7 +49,17 @@
  * Basic construction
  */
 
-TEST_F(OutputTest, canInstantiateOutput) {}
+TEST_F(OutputTest, canInstantiateOutput) {
+    // The validation check checks each required component.
+    EXPECT_CALL(*mRenderSurface, isValid()).WillOnce(Return(true));
+
+    EXPECT_TRUE(mOutput.isValid());
+
+    // If we take away the required components, it is no longer valid.
+    mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>());
+
+    EXPECT_FALSE(mOutput.isValid());
+}
 
 /* ------------------------------------------------------------------------
  * Output::setCompositionEnabled()
@@ -109,12 +125,16 @@
  */
 
 TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
-    const Rect displaySize{100, 200};
+    const ui::Size displaySize{100, 200};
+
+    EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
+    EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
+
     mOutput.setBounds(displaySize);
 
-    EXPECT_EQ(displaySize, mOutput.getState().bounds);
+    EXPECT_EQ(Rect(displaySize), mOutput.getState().bounds);
 
-    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
 }
 
 /* ------------------------------------------------------------------------
@@ -159,6 +179,8 @@
  */
 
 TEST_F(OutputTest, setColorModeSetsModeUnlessNoChange) {
+    EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+
     mOutput.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
                          ui::RenderIntent::TONE_MAP_COLORIMETRIC);
 
@@ -168,6 +190,21 @@
 }
 
 /* ------------------------------------------------------------------------
+ * Output::setRenderSurface()
+ */
+
+TEST_F(OutputTest, setRenderSurfaceResetsBounds) {
+    const ui::Size newDisplaySize{640, 480};
+
+    mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+    EXPECT_CALL(*renderSurface, getSize()).WillOnce(ReturnRef(newDisplaySize));
+
+    mOutput.setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
+
+    EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds);
+}
+
+/* ------------------------------------------------------------------------
  * Output::getPhysicalSpaceDirtyRegion()
  */
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
new file mode 100644
index 0000000..13cc663
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#include <cstdarg>
+#include <cstdint>
+
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/RenderSurface.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <system/window.h>
+#include <ui/ANativeObjectBase.h>
+
+#include "MockHWComposer.h"
+
+namespace android::compositionengine {
+namespace {
+
+/* ------------------------------------------------------------------------
+ * MockNativeWindow
+ *
+ * An intentionally simplified Mock which implements a minimal subset of the full
+ * ANativeWindow interface.
+ */
+
+class MockNativeWindow : public ANativeObjectBase<ANativeWindow, MockNativeWindow, RefBase> {
+public:
+    MockNativeWindow() {
+        ANativeWindow::setSwapInterval = &forwardSetSwapInterval;
+        ANativeWindow::dequeueBuffer = &forwardDequeueBuffer;
+        ANativeWindow::cancelBuffer = &forwardCancelBuffer;
+        ANativeWindow::queueBuffer = &forwardQueueBuffer;
+        ANativeWindow::query = &forwardQuery;
+        ANativeWindow::perform = &forwardPerform;
+
+        ANativeWindow::dequeueBuffer_DEPRECATED = &forwardDequeueBufferDeprecated;
+        ANativeWindow::cancelBuffer_DEPRECATED = &forwardCancelBufferDeprecated;
+        ANativeWindow::lockBuffer_DEPRECATED = &forwardLockBufferDeprecated;
+        ANativeWindow::queueBuffer_DEPRECATED = &forwardQueueBufferDeprecated;
+    }
+
+    MOCK_METHOD1(setSwapInterval, int(int));
+    MOCK_METHOD2(dequeueBuffer, int(struct ANativeWindowBuffer**, int*));
+    MOCK_METHOD2(cancelBuffer, int(struct ANativeWindowBuffer*, int));
+    MOCK_METHOD2(queueBuffer, int(struct ANativeWindowBuffer*, int));
+    MOCK_CONST_METHOD2(query, int(int, int*));
+    MOCK_METHOD1(connect, int(int));
+    MOCK_METHOD1(lockBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
+    MOCK_METHOD1(setBuffersFormat, int(PixelFormat));
+    MOCK_METHOD1(setBuffersDataSpace, int(ui::Dataspace));
+    MOCK_METHOD1(setUsage, int(uint64_t));
+
+    static void unexpectedCall(...) { LOG_ALWAYS_FATAL("Unexpected ANativeWindow API call"); }
+
+    static int forwardSetSwapInterval(ANativeWindow* window, int interval) {
+        return getSelf(window)->setSwapInterval(interval);
+    }
+
+    static int forwardDequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
+                                    int* fenceFd) {
+        return getSelf(window)->dequeueBuffer(buffer, fenceFd);
+    }
+
+    static int forwardCancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
+                                   int fenceFd) {
+        return getSelf(window)->cancelBuffer(buffer, fenceFd);
+    }
+
+    static int forwardQueueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+        return getSelf(window)->queueBuffer(buffer, fenceFd);
+    }
+
+    static int forwardQuery(const ANativeWindow* window, int what, int* value) {
+        return getSelf(window)->query(what, value);
+    }
+
+    static int forwardPerform(ANativeWindow* window, int operation, ...) {
+        va_list args;
+        va_start(args, operation);
+        int result = NO_ERROR;
+        switch (operation) {
+            case NATIVE_WINDOW_API_CONNECT: {
+                int api = va_arg(args, int);
+                result = getSelf(window)->connect(api);
+                break;
+            }
+            case NATIVE_WINDOW_SET_BUFFERS_FORMAT: {
+                PixelFormat format = va_arg(args, PixelFormat);
+                result = getSelf(window)->setBuffersFormat(format);
+                break;
+            }
+            case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: {
+                ui::Dataspace dataspace = static_cast<ui::Dataspace>(va_arg(args, int));
+                result = getSelf(window)->setBuffersDataSpace(dataspace);
+                break;
+            }
+            case NATIVE_WINDOW_SET_USAGE: {
+                // Note: Intentionally widens usage from 32 to 64 bits so we
+                // just have one implementation.
+                uint64_t usage = va_arg(args, uint32_t);
+                result = getSelf(window)->setUsage(usage);
+                break;
+            }
+            case NATIVE_WINDOW_SET_USAGE64: {
+                uint64_t usage = va_arg(args, uint64_t);
+                result = getSelf(window)->setUsage(usage);
+                break;
+            }
+            default:
+                LOG_ALWAYS_FATAL("Unexpected operation %d", operation);
+                break;
+        }
+
+        va_end(args);
+        return result;
+    }
+
+    static int forwardDequeueBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer** buffer) {
+        int ignoredFenceFd = -1;
+        return getSelf(window)->dequeueBuffer(buffer, &ignoredFenceFd);
+    }
+
+    static int forwardCancelBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+        return getSelf(window)->cancelBuffer(buffer, -1);
+    }
+
+    static int forwardLockBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+        return getSelf(window)->lockBuffer_DEPRECATED(buffer);
+    }
+
+    static int forwardQueueBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+        return getSelf(window)->queueBuffer(buffer, -1);
+    }
+};
+
+/* ------------------------------------------------------------------------
+ * RenderSurfaceTest
+ */
+
+constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
+constexpr std::optional<DisplayId> DEFAULT_DISPLAY_ID = std::make_optional(DisplayId{123u});
+const std::string DEFAULT_DISPLAY_NAME = "Mock Display";
+
+using testing::_;
+using testing::ByMove;
+using testing::DoAll;
+using testing::Ref;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgPointee;
+using testing::StrictMock;
+
+class RenderSurfaceTest : public testing::Test {
+public:
+    RenderSurfaceTest() {
+        EXPECT_CALL(mDisplay, getId()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_ID));
+        EXPECT_CALL(mDisplay, getName()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_NAME));
+        EXPECT_CALL(mCompositionEngine, getHwComposer).WillRepeatedly(ReturnRef(mHwComposer));
+        EXPECT_CALL(mCompositionEngine, getRenderEngine).WillRepeatedly(ReturnRef(mRenderEngine));
+    }
+    ~RenderSurfaceTest() override = default;
+
+    StrictMock<android::mock::HWComposer> mHwComposer;
+    StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
+    StrictMock<mock::CompositionEngine> mCompositionEngine;
+    StrictMock<mock::Display> mDisplay;
+    sp<MockNativeWindow> mNativeWindow = new StrictMock<MockNativeWindow>();
+    sp<mock::DisplaySurface> mDisplaySurface = new StrictMock<mock::DisplaySurface>();
+    impl::RenderSurface mSurface{mCompositionEngine, mDisplay,
+                                 RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH,
+                                                           DEFAULT_DISPLAY_HEIGHT, mNativeWindow,
+                                                           mDisplaySurface}};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(RenderSurfaceTest, canInstantiate) {
+    EXPECT_TRUE(mSurface.isValid());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::initialize()
+ */
+
+TEST_F(RenderSurfaceTest, initializeConfiguresNativeWindow) {
+    EXPECT_CALL(*mNativeWindow, connect(NATIVE_WINDOW_API_EGL)).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(*mNativeWindow, setBuffersFormat(HAL_PIXEL_FORMAT_RGBA_8888))
+            .WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+
+    mSurface.initialize();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::getSize()
+ */
+
+TEST_F(RenderSurfaceTest, sizeReturnsConstructedSize) {
+    const ui::Size expected{DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT};
+
+    EXPECT_EQ(expected, mSurface.getSize());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::getClientTargetAcquireFence()
+ */
+
+TEST_F(RenderSurfaceTest, getClientTargetAcquireFenceForwardsCall) {
+    sp<Fence> fence = new Fence();
+
+    EXPECT_CALL(*mDisplaySurface, getClientTargetAcquireFence()).WillOnce(ReturnRef(fence));
+
+    EXPECT_EQ(fence.get(), mSurface.getClientTargetAcquireFence().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setDisplaySize()
+ */
+
+TEST_F(RenderSurfaceTest, setDisplaySizeAppliesChange) {
+    EXPECT_CALL(*mDisplaySurface, resizeBuffers(640, 480)).Times(1);
+
+    mSurface.setDisplaySize(ui::Size(640, 480));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setBufferDataspace()
+ */
+
+TEST_F(RenderSurfaceTest, setBufferDataspaceAppliesChange) {
+    EXPECT_CALL(*mNativeWindow, setBuffersDataSpace(ui::Dataspace::DISPLAY_P3))
+            .WillOnce(Return(NO_ERROR));
+
+    mSurface.setBufferDataspace(ui::Dataspace::DISPLAY_P3);
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setProtected()
+ */
+
+TEST_F(RenderSurfaceTest, setProtectedTrueEnablesProtection) {
+    EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
+            .WillOnce(Return(NO_ERROR));
+
+    mSurface.setProtected(true);
+}
+
+TEST_F(RenderSurfaceTest, setProtectedFalseDisablesProtection) {
+    EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+
+    mSurface.setProtected(false);
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::beginFrame()
+ */
+
+TEST_F(RenderSurfaceTest, beginFrameAppliesChange) {
+    EXPECT_CALL(*mDisplaySurface, beginFrame(true)).WillOnce(Return(NO_ERROR));
+
+    EXPECT_EQ(NO_ERROR, mSurface.beginFrame(true));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::prepareFrame()
+ */
+
+TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
+    std::vector<CompositionInfo> data;
+
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data)))
+            .WillOnce(Return(INVALID_OPERATION));
+
+    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
+    std::vector<CompositionInfo> data;
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+
+    EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
+            .WillOnce(Return(INVALID_OPERATION));
+
+    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
+    std::vector<CompositionInfo> data;
+
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+
+    EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
+            .WillOnce(Return(NO_ERROR));
+
+    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
+    std::vector<CompositionInfo> data;
+
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+
+    EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
+            .WillOnce(Return(NO_ERROR));
+
+    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
+    std::vector<CompositionInfo> data;
+
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+
+    EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
+            .WillOnce(Return(NO_ERROR));
+
+    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::dequeueBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) {
+    sp<GraphicBuffer> buffer = new GraphicBuffer();
+
+    EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
+            .WillOnce(
+                    DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
+
+    EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer().get());
+
+    EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::queueBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) {
+    sp<GraphicBuffer> buffer = new GraphicBuffer();
+    mSurface.mutableGraphicBufferForTest() = buffer;
+
+    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+    EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID))
+            .WillOnce(Return(false));
+    EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+    mSurface.queueBuffer();
+
+    EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) {
+    sp<GraphicBuffer> buffer = new GraphicBuffer();
+    mSurface.mutableGraphicBufferForTest() = buffer;
+
+    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+            .WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+    mSurface.queueBuffer();
+
+    EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) {
+    sp<GraphicBuffer> buffer = new GraphicBuffer();
+    mSurface.mutableGraphicBufferForTest() = buffer;
+
+    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+    EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+            .WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+    mSurface.queueBuffer();
+
+    EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
+    sp<GraphicBuffer> buffer = new GraphicBuffer();
+
+    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+    EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
+            .WillOnce(
+                    DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
+    EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+            .WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+    mSurface.queueBuffer();
+
+    EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) {
+    sp<GraphicBuffer> buffer = new GraphicBuffer();
+    mSurface.mutableGraphicBufferForTest() = buffer;
+
+    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+            .WillOnce(Return(INVALID_OPERATION));
+    EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true));
+    EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getNativeBuffer(), -1))
+            .WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+    mSurface.queueBuffer();
+
+    EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::onPresentDisplayCompleted()
+ */
+
+TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) {
+    EXPECT_CALL(*mDisplaySurface, onFrameCommitted()).Times(1);
+
+    mSurface.onPresentDisplayCompleted();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::finishBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, finishBufferJustFlushesRenderEngine) {
+    int fd = dup(1);
+
+    EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(fd))));
+
+    mSurface.finishBuffer();
+
+    EXPECT_EQ(fd, mSurface.mutableBufferReadyForTest().release());
+}
+
+TEST_F(RenderSurfaceTest, finishBufferFlushesAndFinishesRenderEngine) {
+    EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(-2))));
+    EXPECT_CALL(mRenderEngine, finish()).Times(1);
+
+    mSurface.finishBuffer();
+
+    EXPECT_EQ(-2, mSurface.mutableBufferReadyForTest().release());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setViewportAndProjection()
+ */
+
+TEST_F(RenderSurfaceTest, setViewportAndProjectionAppliesChang) {
+    mSurface.setSizeForTest(ui::Size(100, 200));
+
+    EXPECT_CALL(mRenderEngine,
+                setViewportAndProjection(100, 200, Rect(100, 200), ui::Transform::ROT_0))
+            .Times(1);
+
+    mSurface.setViewportAndProjection();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::flip()
+ */
+
+TEST_F(RenderSurfaceTest, flipForwardsSignal) {
+    mSurface.setPageFlipCountForTest(500);
+
+    mSurface.flip();
+
+    EXPECT_EQ(501, mSurface.getPageFlipCount());
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 80004a1..08e5db9 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -34,6 +34,8 @@
 #include <compositionengine/Display.h>
 #include <compositionengine/DisplayCreationArgs.h>
 #include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
 #include <compositionengine/impl/OutputCompositionState.h>
 #include <configstore/Utils.h>
 #include <cutils/properties.h>
@@ -230,10 +232,6 @@
         mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
                 compositionengine::DisplayCreationArgs{args.isSecure, args.isVirtual,
                                                        args.displayId})},
-        mNativeWindow(args.nativeWindow),
-        mGraphicBuffer(nullptr),
-        mDisplaySurface(args.displaySurface),
-        mPageFlipCount(0),
         mIsVirtual(args.isVirtual),
         mOrientation(),
         mActiveConfig(0),
@@ -244,14 +242,20 @@
         mHasDolbyVision(false),
         mSupportedPerFrameMetadata(args.supportedPerFrameMetadata),
         mIsPrimary(args.isPrimary) {
+    mCompositionDisplay->createRenderSurface(
+            compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth(
+                                                                 args.nativeWindow.get()),
+                                                         ANativeWindow_getHeight(
+                                                                 args.nativeWindow.get()),
+                                                         args.nativeWindow, args.displaySurface});
+
     if (!mCompositionDisplay->isValid()) {
         ALOGE("Composition Display did not validate!");
     }
 
-    populateColorModes(args.hwcColorModes);
+    mCompositionDisplay->getRenderSurface()->initialize();
 
-    ALOGE_IF(!mNativeWindow, "No native window was set for display");
-    ALOGE_IF(!mDisplaySurface, "No display surface was set for display");
+    populateColorModes(args.hwcColorModes);
 
     std::vector<Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
     for (Hdr hdrType : types) {
@@ -293,18 +297,6 @@
     }
     mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
 
-    ANativeWindow* const window = mNativeWindow.get();
-
-    int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
-    ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
-    status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
-    ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
-    status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER);
-    ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
-
-    mCompositionDisplay->setBounds(
-            Rect(ANativeWindow_getWidth(window), ANativeWindow_getHeight(window)));
-
     setPowerMode(args.initialPowerMode);
 
     // initialize the display orientation transform.
@@ -334,151 +326,7 @@
 }
 
 uint32_t DisplayDevice::getPageFlipCount() const {
-    return mPageFlipCount;
-}
-
-void DisplayDevice::flip() const
-{
-    mPageFlipCount++;
-}
-
-status_t DisplayDevice::beginFrame(bool mustRecompose) const {
-    return mDisplaySurface->beginFrame(mustRecompose);
-}
-
-status_t DisplayDevice::prepareFrame(HWComposer& hwc,
-        std::vector<CompositionInfo>& compositionData) {
-    const auto id = getId();
-    if (id) {
-        status_t error = hwc.prepare(id.value(), compositionData);
-        if (error != NO_ERROR) {
-            return error;
-        }
-    }
-
-    compositionengine::DisplaySurface::CompositionType compositionType;
-    bool hasClient = hwc.hasClientComposition(id);
-    bool hasDevice = hwc.hasDeviceComposition(id);
-    if (hasClient && hasDevice) {
-        compositionType = compositionengine::DisplaySurface::COMPOSITION_MIXED;
-    } else if (hasClient) {
-        compositionType = compositionengine::DisplaySurface::COMPOSITION_GLES;
-    } else if (hasDevice) {
-        compositionType = compositionengine::DisplaySurface::COMPOSITION_HWC;
-    } else {
-        // Nothing to do -- when turning the screen off we get a frame like
-        // this. Call it a HWC frame since we won't be doing any GLES work but
-        // will do a prepare/set cycle.
-        compositionType = compositionengine::DisplaySurface::COMPOSITION_HWC;
-    }
-    return mDisplaySurface->prepareFrame(compositionType);
-}
-
-void DisplayDevice::setProtected(bool useProtected) {
-    uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
-    if (useProtected) {
-        usageFlags |= GRALLOC_USAGE_PROTECTED;
-    }
-    const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
-    ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
-}
-
-sp<GraphicBuffer> DisplayDevice::dequeueBuffer() {
-    int fd;
-    ANativeWindowBuffer* buffer;
-
-    status_t res = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
-
-    if (res != NO_ERROR) {
-        ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
-              getDisplayName().c_str(), res);
-        // Return fast here as we can't do much more - any rendering we do
-        // now will just be wrong.
-        return mGraphicBuffer;
-    }
-
-    ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
-             mGraphicBuffer->getNativeBuffer()->handle);
-    mGraphicBuffer = GraphicBuffer::from(buffer);
-
-    // Block until the buffer is ready
-    // TODO(alecmouri): it's perhaps more appropriate to block renderengine so
-    // that the gl driver can block instead.
-    if (fd >= 0) {
-        sync_wait(fd, -1);
-        close(fd);
-    }
-
-    return mGraphicBuffer;
-}
-
-void DisplayDevice::queueBuffer(HWComposer& hwc) {
-    const auto id = getId();
-    if (hwc.hasClientComposition(id) || hwc.hasFlipClientTargetRequest(id)) {
-        // hasFlipClientTargetRequest could return true even if we haven't
-        // dequeued a buffer before. Try dequeueing one if we don't have a
-        // buffer ready.
-        if (mGraphicBuffer == nullptr) {
-            ALOGI("Attempting to queue a client composited buffer without one "
-                  "previously dequeued for display [%s]. Attempting to dequeue "
-                  "a scratch buffer now",
-                  mDisplayName.c_str());
-            // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
-            // after a successful call to queueBuffer, or if dequeueBuffer has
-            // never been called.
-            dequeueBuffer();
-        }
-
-        if (mGraphicBuffer == nullptr) {
-            ALOGE("No buffer is ready for display [%s]", mDisplayName.c_str());
-        } else {
-            status_t res = mNativeWindow->queueBuffer(mNativeWindow.get(),
-                                                      mGraphicBuffer->getNativeBuffer(),
-                                                      dup(mBufferReady));
-            if (res != NO_ERROR) {
-                ALOGE("Error when queueing buffer for display [%s]: %d", mDisplayName.c_str(), res);
-                // We risk blocking on dequeueBuffer if the primary display failed
-                // to queue up its buffer, so crash here.
-                if (isPrimary()) {
-                    LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", res);
-                } else {
-                    mNativeWindow->cancelBuffer(mNativeWindow.get(),
-                                                mGraphicBuffer->getNativeBuffer(),
-                                                dup(mBufferReady));
-                }
-            }
-
-            mBufferReady.reset();
-            mGraphicBuffer = nullptr;
-        }
-    }
-
-    status_t result = mDisplaySurface->advanceFrame();
-    if (result != NO_ERROR) {
-        ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplayName.c_str(), result);
-    }
-}
-
-void DisplayDevice::onPresentDisplayCompleted() {
-    mDisplaySurface->onFrameCommitted();
-}
-
-void DisplayDevice::setViewportAndProjection() const {
-    size_t w = getWidth();
-    size_t h = getHeight();
-    Rect sourceCrop(0, 0, w, h);
-    mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, ui::Transform::ROT_0);
-}
-
-void DisplayDevice::finishBuffer() {
-    mBufferReady = mFlinger->getRenderEngine().flush();
-    if (mBufferReady.get() < 0) {
-        mFlinger->getRenderEngine().finish();
-    }
-}
-
-const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
-    return mDisplaySurface->getClientTargetAcquireFence();
+    return mCompositionDisplay->getRenderSurface()->getPageFlipCount();
 }
 
 // ----------------------------------------------------------------------------
@@ -524,11 +372,6 @@
 
 // ----------------------------------------------------------------------------
 
-void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) {
-    ANativeWindow* const window = mNativeWindow.get();
-    native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace));
-}
-
 ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
     return mCompositionDisplay->getState().dataspace;
 }
@@ -566,8 +409,7 @@
 }
 
 void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
-    mDisplaySurface->resizeBuffers(newWidth, newHeight);
-    mCompositionDisplay->setBounds(Rect(newWidth, newHeight));
+    mCompositionDisplay->setBounds(ui::Size(newWidth, newHeight));
 }
 
 void DisplayDevice::setProjection(int orientation,
@@ -665,26 +507,16 @@
 }
 
 void DisplayDevice::dump(std::string& result) const {
-    ANativeWindow* const window = mNativeWindow.get();
     StringAppendF(&result, "+ %s\n", getDebugName().c_str());
 
     result.append("   ");
-    StringAppendF(&result, "ANativeWindow=%p (format %d), ", window,
-                  ANativeWindow_getFormat(window));
-    StringAppendF(&result, "flips=%u, ", getPageFlipCount());
     StringAppendF(&result, "powerMode=%d, ", mPowerMode);
     StringAppendF(&result, "activeConfig=%d, ", mActiveConfig);
     StringAppendF(&result, "numLayers=%zu\n", mVisibleLayersSortedByZ.size());
+    StringAppendF(&result, "wideColorGamut=%d, ", mHasWideColorGamut);
+    StringAppendF(&result, "hdr10plus=%d\n", mHasHdr10Plus);
+    StringAppendF(&result, "hdr10=%d\n", mHasHdr10);
     getCompositionDisplay()->dump(result);
-    auto const surface = static_cast<Surface*>(window);
-    ui::Dataspace dataspace = surface->getBuffersDataSpace();
-    StringAppendF(&result, "   wideColorGamut=%d, hdr10plus =%d, hdr10=%d, dataspace: %s (%d)\n",
-                  mHasWideColorGamut, mHasHdr10Plus, mHasHdr10,
-                  dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
-
-    String8 surfaceDump;
-    mDisplaySurface->dumpAsString(surfaceDump);
-    result.append(surfaceDump.string(), surfaceDump.size());
 }
 
 // Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index c606659..941d61c 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -82,10 +82,6 @@
     // secure surfaces.
     bool isSecure() const;
 
-    // Flip the front and back buffers if the back buffer is "dirty".  Might
-    // be instantaneous, might involve copying the frame buffer around.
-    void flip() const;
-
     int         getWidth() const;
     int         getHeight() const;
     int         getInstallOrientation() const { return mDisplayInstallOrientation; }
@@ -116,11 +112,6 @@
 
     int32_t getSupportedPerFrameMetadata() const { return mSupportedPerFrameMetadata; }
 
-    // We pass in mustRecompose so we can keep VirtualDisplaySurface's state
-    // machine happy without actually queueing a buffer if nothing has changed
-    status_t beginFrame(bool mustRecompose) const;
-    status_t prepareFrame(HWComposer& hwc, std::vector<CompositionInfo>& compositionInfo);
-
     bool hasWideColorGamut() const { return mHasWideColorGamut; }
     // Whether h/w composer has native support for specific HDR type.
     bool hasHDR10PlusSupport() const { return mHasHdr10Plus; }
@@ -147,30 +138,12 @@
                           ui::Dataspace* outDataspace, ui::ColorMode* outMode,
                           ui::RenderIntent* outIntent) const;
 
-    void setProtected(bool useProtected);
-    // Queues the drawn buffer for consumption by HWC.
-    void queueBuffer(HWComposer& hwc);
-    // Allocates a buffer as scratch space for GPU composition
-    sp<GraphicBuffer> dequeueBuffer();
-
-    // called after h/w composer has completed its set() call
-    void onPresentDisplayCompleted();
-
     const Rect& getBounds() const;
     const Rect& bounds() const { return getBounds(); }
 
     void setDisplayName(const std::string& displayName);
     const std::string& getDisplayName() const { return mDisplayName; }
 
-    // Acquires a new buffer for GPU composition.
-    void readyNewBuffer();
-    // Marks the current buffer has finished, so that it can be presented and
-    // swapped out.
-    void finishBuffer();
-    void setViewportAndProjection() const;
-
-    const sp<Fence>& getClientTargetAcquireFence() const;
-
     /* ------------------------------------------------------------------------
      * Display power mode management.
      */
@@ -178,7 +151,6 @@
     void setPowerMode(int mode);
     bool isPoweredOn() const;
 
-    void setCompositionDataSpace(ui::Dataspace dataspace);
     ui::Dataspace getCompositionDataSpace() const;
 
     /* ------------------------------------------------------------------------
@@ -208,18 +180,7 @@
     const int mDisplayInstallOrientation;
     const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
 
-    // ANativeWindow this display is rendering into
-    sp<ANativeWindow> mNativeWindow;
-    // Current buffer that this display can render to.
-    sp<GraphicBuffer> mGraphicBuffer;
-    sp<compositionengine::DisplaySurface> mDisplaySurface;
-    // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
-    // that drawing to the buffer is now complete.
-    base::unique_fd mBufferReady;
-
-    mutable uint32_t mPageFlipCount;
-    std::string     mDisplayName;
-
+    std::string mDisplayName;
     const bool mIsVirtual;
 
     /*
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fb15b24..89129e9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -37,6 +37,7 @@
 
 #include <compositionengine/CompositionEngine.h>
 #include <compositionengine/Display.h>
+#include <compositionengine/RenderSurface.h>
 #include <compositionengine/impl/OutputCompositionState.h>
 #include <dvr/vr_flinger.h>
 #include <gui/BufferQueue.h>
@@ -1042,7 +1043,6 @@
             ALOGW("Attempt to set active color mode %s (%d) for virtual display",
                   decodeColorMode(mode).c_str(), mode);
         } else {
-            display->setCompositionDataSpace(Dataspace::UNKNOWN);
             display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN,
                                                            RenderIntent::COLORIMETRIC);
         }
@@ -1760,7 +1760,6 @@
             Dataspace dataSpace;
             RenderIntent renderIntent;
             pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
-            displayDevice->setCompositionDataSpace(dataSpace);
             display->setColorMode(colorMode, dataSpace, renderIntent);
         }
     }
@@ -1805,7 +1804,7 @@
             auto& engine(getRenderEngine());
             engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1);
 
-            displayDevice->queueBuffer(getHwComposer());
+            display->getRenderSurface()->queueBuffer();
         }
     }
 
@@ -1989,7 +1988,9 @@
 
     if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
         glCompositionDoneFenceTime =
-                std::make_shared<FenceTime>(displayDevice->getClientTargetAcquireFence());
+                std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
+                                                    ->getRenderSurface()
+                                                    ->getClientTargetAcquireFence());
         getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
     } else {
         glCompositionDoneFenceTime = FenceTime::NO_FENCE;
@@ -2340,7 +2341,7 @@
              displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty],
              flagPrefix[wasEmpty]);
 
-    displayDevice->beginFrame(mustRecompose);
+    display->getRenderSurface()->beginFrame(mustRecompose);
 
     if (mustRecompose) {
         display->editState().lastCompositionHadVisibleLayers = !empty;
@@ -2355,9 +2356,8 @@
         return;
     }
 
-    status_t result =
-            displayDevice->prepareFrame(getHwComposer(),
-                                        getBE().mCompositionInfo[displayDevice->getDisplayToken()]);
+    status_t result = display->getRenderSurface()->prepareFrame(
+            getBE().mCompositionInfo[displayDevice->getDisplayToken()]);
     ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
              displayDevice->getDebugName().c_str(), result, strerror(-result));
 }
@@ -2377,7 +2377,7 @@
         doDisplayComposition(displayDevice, dirtyRegion);
 
         display->editState().dirtyRegion.clear();
-        displayDevice->flip();
+        display->getRenderSurface()->flip();
     }
     postFramebuffer(displayDevice);
 }
@@ -2408,7 +2408,7 @@
         if (displayId) {
             getHwComposer().presentAndGetReleaseFences(*displayId);
         }
-        displayDevice->onPresentDisplayCompleted();
+        display->getRenderSurface()->onPresentDisplayCompleted();
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             sp<Fence> releaseFence = Fence::NO_FENCE;
 
@@ -2426,8 +2426,9 @@
             // client target acquire fence when it is available, even though
             // this is suboptimal.
             if (layer->getCompositionType(displayId) == HWC2::Composition::Client) {
-                releaseFence = Fence::merge("LayerRelease", releaseFence,
-                                            displayDevice->getClientTargetAcquireFence());
+                releaseFence =
+                        Fence::merge("LayerRelease", releaseFence,
+                                     display->getRenderSurface()->getClientTargetAcquireFence());
             }
 
             layer->getBE().onLayerDisplayed(releaseFence);
@@ -2581,7 +2582,6 @@
         defaultColorMode = ColorMode::SRGB;
         defaultDataSpace = Dataspace::V0_SRGB;
     }
-    display->setCompositionDataSpace(defaultDataSpace);
     display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace,
                                                    RenderIntent::COLORIMETRIC);
     if (!state.isVirtual()) {
@@ -3256,7 +3256,7 @@
     if (!doComposeSurfaces(displayDevice)) return;
 
     // swap buffers (presentation)
-    displayDevice->queueBuffer(getHwComposer());
+    display->getRenderSurface()->queueBuffer();
 }
 
 bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) {
@@ -3280,7 +3280,7 @@
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
-        sp<GraphicBuffer> buf = displayDevice->dequeueBuffer();
+        sp<GraphicBuffer> buf = display->getRenderSurface()->dequeueBuffer();
 
         if (buf == nullptr) {
             ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
@@ -3319,7 +3319,7 @@
             colorMatrix = mDrawingState.colorMatrix;
         }
 
-        displayDevice->setViewportAndProjection();
+        display->getRenderSurface()->setViewportAndProjection();
 
         // Never touch the framebuffer if we don't have any framebuffer layers
         if (hasDeviceComposition) {
@@ -3413,7 +3413,7 @@
     if (hasClientComposition) {
         getRenderEngine().setColorTransform(mat4());
         getRenderEngine().disableScissor();
-        displayDevice->finishBuffer();
+        display->getRenderSurface()->finishBuffer();
         // Clear out error flags here so that we don't wait until next
         // composition to log.
         getRenderEngine().checkErrors();