Merge "TouchInputMapper: Fix pointer ID in dispatchPointerMouse"
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 1dc6233..4029957 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -283,11 +283,9 @@
 
 const String16& BBinder::getInterfaceDescriptor() const
 {
-    // This is a local static rather than a global static,
-    // to avoid static initializer ordering issues.
-    static String16 sEmptyDescriptor;
-    ALOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
-    return sEmptyDescriptor;
+    static StaticString16 sBBinder(u"BBinder");
+    ALOGW("Reached BBinder::getInterfaceDescriptor (this=%p). Override?", this);
+    return sBBinder;
 }
 
 // NOLINTNEXTLINE(google-default-arguments)
diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h
index 7574c29..793795e 100644
--- a/libs/binder/binder_module.h
+++ b/libs/binder/binder_module.h
@@ -100,23 +100,4 @@
 #define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32)
 #endif // BINDER_ENABLE_ONEWAY_SPAM_DETECTION
 
-#ifndef BINDER_GET_EXTENDED_ERROR
-/* struct binder_extened_error - extended error information
- * @id:      identifier for the failed operation
- * @command: command as defined by binder_driver_return_protocol
- * @param:   parameter holding a negative errno value
- *
- * Used with BINDER_GET_EXTENDED_ERROR. This extends the error information
- * returned by the driver upon a failed operation. Userspace can pull this
- * data to properly handle specific error scenarios.
- */
-struct binder_extended_error {
-    __u32 id;
-    __u32 command;
-    __s32 param;
-};
-
-#define BINDER_GET_EXTENDED_ERROR _IOWR('b', 17, struct binder_extended_error)
-#endif // BINDER_GET_EXTENDED_ERROR
-
 #endif // _BINDER_MODULE_H_
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index c7ad058..9d9cb6b 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -63,12 +63,13 @@
                         "output buffer not gpu writeable");
 }
 
-std::future<RenderEngineResult> RenderEngine::drawLayers(
-        const DisplaySettings& display, const std::vector<LayerSettings>& layers,
-        const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
-        base::unique_fd&& bufferFence) {
-    const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>();
-    std::future<RenderEngineResult> resultFuture = resultPromise->get_future();
+ftl::Future<FenceResult> RenderEngine::drawLayers(const DisplaySettings& display,
+                                                  const std::vector<LayerSettings>& layers,
+                                                  const std::shared_ptr<ExternalTexture>& buffer,
+                                                  const bool useFramebufferCache,
+                                                  base::unique_fd&& bufferFence) {
+    const auto resultPromise = std::make_shared<std::promise<FenceResult>>();
+    std::future<FenceResult> resultFuture = resultPromise->get_future();
     drawLayersInternal(std::move(resultPromise), display, layers, buffer, useFramebufferCache,
                        std::move(bufferFence));
     return resultFuture;
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index 7bcfff5..739f3fa 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -159,9 +159,10 @@
     };
     auto layers = std::vector<LayerSettings>{layer};
 
-    auto [status, drawFence] =
-            re.drawLayers(display, layers, texture, kUseFrameBufferCache, base::unique_fd()).get();
-    sp<Fence> waitFence = sp<Fence>::make(std::move(drawFence));
+    sp<Fence> waitFence =
+            re.drawLayers(display, layers, texture, kUseFrameBufferCache, base::unique_fd())
+                    .get()
+                    .value();
     waitFence->waitForever(LOG_TAG);
     return texture;
 }
@@ -190,10 +191,10 @@
 
     // This loop starts and stops the timer.
     for (auto _ : benchState) {
-        auto [status, drawFence] = re.drawLayers(display, layers, outputBuffer,
-                                                 kUseFrameBufferCache, base::unique_fd())
-                                           .get();
-        sp<Fence> waitFence = sp<Fence>::make(std::move(drawFence));
+        sp<Fence> waitFence = re.drawLayers(display, layers, outputBuffer, kUseFrameBufferCache,
+                                            base::unique_fd())
+                                      .get()
+                                      .value();
         waitFence->waitForever(LOG_TAG);
     }
 
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 9a5ff54..13f766c 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1081,14 +1081,14 @@
 }
 
 void GLESRenderEngine::drawLayersInternal(
-        const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+        const std::shared_ptr<std::promise<FenceResult>>&& resultPromise,
         const DisplaySettings& display, const std::vector<LayerSettings>& layers,
         const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
         base::unique_fd&& bufferFence) {
     ATRACE_CALL();
     if (layers.empty()) {
         ALOGV("Drawing empty layer stack");
-        resultPromise->set_value({NO_ERROR, base::unique_fd()});
+        resultPromise->set_value(Fence::NO_FENCE);
         return;
     }
 
@@ -1103,7 +1103,7 @@
 
     if (buffer == nullptr) {
         ALOGE("No output buffer provided. Aborting GPU composition.");
-        resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+        resultPromise->set_value(base::unexpected(BAD_VALUE));
         return;
     }
 
@@ -1132,7 +1132,7 @@
             ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
                   buffer->getBuffer()->handle);
             checkErrors();
-            resultPromise->set_value({fbo->getStatus(), base::unique_fd()});
+            resultPromise->set_value(base::unexpected(fbo->getStatus()));
             return;
         }
         setViewportAndProjection(display.physicalDisplay, display.clip);
@@ -1144,7 +1144,7 @@
             ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
                   buffer->getBuffer()->handle);
             checkErrors();
-            resultPromise->set_value({status, base::unique_fd()});
+            resultPromise->set_value(base::unexpected(status));
             return;
         }
     }
@@ -1178,7 +1178,7 @@
                 ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
                       buffer->getBuffer()->handle);
                 checkErrors("Can't render first blur pass");
-                resultPromise->set_value({status, base::unique_fd()});
+                resultPromise->set_value(base::unexpected(status));
                 return;
             }
 
@@ -1201,7 +1201,7 @@
                 ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
                       buffer->getBuffer()->handle);
                 checkErrors("Can't bind native framebuffer");
-                resultPromise->set_value({status, base::unique_fd()});
+                resultPromise->set_value(base::unexpected(status));
                 return;
             }
 
@@ -1210,7 +1210,7 @@
                 ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
                       buffer->getBuffer()->handle);
                 checkErrors("Can't render blur filter");
-                resultPromise->set_value({status, base::unique_fd()});
+                resultPromise->set_value(base::unexpected(status));
                 return;
             }
         }
@@ -1310,7 +1310,7 @@
             checkErrors();
             // Chances are, something illegal happened (either the caller passed
             // us bad parameters, or we messed up our shader generation).
-            resultPromise->set_value({INVALID_OPERATION, std::move(drawFence)});
+            resultPromise->set_value(base::unexpected(INVALID_OPERATION));
             return;
         }
         mLastDrawFence = nullptr;
@@ -1322,8 +1322,7 @@
     mPriorResourcesCleaned = false;
 
     checkErrors();
-    resultPromise->set_value({NO_ERROR, std::move(drawFence)});
-    return;
+    resultPromise->set_value(sp<Fence>::make(std::move(drawFence)));
 }
 
 void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 1d7c2ca..1ee5cba 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -31,6 +31,7 @@
 #include <renderengine/RenderEngine.h>
 #include <renderengine/private/Description.h>
 #include <sys/types.h>
+#include <ui/FenceResult.h>
 #include "GLShadowTexture.h"
 #include "ImageManager.h"
 
@@ -102,7 +103,7 @@
             EXCLUDES(mRenderingMutex);
     void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
     bool canSkipPostRenderCleanup() const override;
-    void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+    void drawLayersInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise,
                             const DisplaySettings& display,
                             const std::vector<LayerSettings>& layers,
                             const std::shared_ptr<ExternalTexture>& buffer,
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 3e7f69c..199392c 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -18,6 +18,7 @@
 #define SF_RENDERENGINE_H_
 
 #include <android-base/unique_fd.h>
+#include <ftl/future.h>
 #include <math/mat4.h>
 #include <renderengine/DisplaySettings.h>
 #include <renderengine/ExternalTexture.h>
@@ -26,6 +27,7 @@
 #include <renderengine/LayerSettings.h>
 #include <stdint.h>
 #include <sys/types.h>
+#include <ui/FenceResult.h>
 #include <ui/GraphicTypes.h>
 #include <ui/Transform.h>
 
@@ -68,7 +70,6 @@
 class Mesh;
 class Texture;
 struct RenderEngineCreationArgs;
-struct RenderEngineResult;
 
 namespace threaded {
 class RenderEngineThreaded;
@@ -158,12 +159,13 @@
     // parameter does nothing.
     // @param bufferFence Fence signalling that the buffer is ready to be drawn
     // to.
-    // @return A future object of RenderEngineResult struct indicating whether
-    // drawing was successful in async mode.
-    virtual std::future<RenderEngineResult> drawLayers(
-            const DisplaySettings& display, const std::vector<LayerSettings>& layers,
-            const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
-            base::unique_fd&& bufferFence);
+    // @return A future object of FenceResult indicating whether drawing was
+    // successful in async mode.
+    virtual ftl::Future<FenceResult> drawLayers(const DisplaySettings& display,
+                                                const std::vector<LayerSettings>& layers,
+                                                const std::shared_ptr<ExternalTexture>& buffer,
+                                                const bool useFramebufferCache,
+                                                base::unique_fd&& bufferFence);
 
     // Clean-up method that should be called on the main thread after the
     // drawFence returned by drawLayers fires. This method will free up
@@ -237,7 +239,7 @@
     const RenderEngineType mRenderEngineType;
 
     virtual void drawLayersInternal(
-            const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+            const std::shared_ptr<std::promise<FenceResult>>&& resultPromise,
             const DisplaySettings& display, const std::vector<LayerSettings>& layers,
             const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
             base::unique_fd&& bufferFence) = 0;
@@ -327,13 +329,6 @@
             RenderEngine::RenderEngineType::SKIA_GL_THREADED;
 };
 
-struct RenderEngineResult {
-    // status indicates if drawing is successful
-    status_t status;
-    // drawFence will fire when the buffer has been drawn to and is ready to be examined.
-    base::unique_fd drawFence;
-};
-
 } // namespace renderengine
 } // namespace android
 
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 248bd65..e3ce85d 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -48,14 +48,13 @@
     MOCK_METHOD0(cleanupPostRender, void());
     MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool());
     MOCK_METHOD5(drawLayers,
-                 std::future<RenderEngineResult>(const DisplaySettings&,
-                                                 const std::vector<LayerSettings>&,
-                                                 const std::shared_ptr<ExternalTexture>&,
-                                                 const bool, base::unique_fd&&));
+                 ftl::Future<FenceResult>(const DisplaySettings&, const std::vector<LayerSettings>&,
+                                          const std::shared_ptr<ExternalTexture>&, const bool,
+                                          base::unique_fd&&));
     MOCK_METHOD6(drawLayersInternal,
-                 void(const std::shared_ptr<std::promise<RenderEngineResult>>&&,
-                      const DisplaySettings&, const std::vector<LayerSettings>&,
-                      const std::shared_ptr<ExternalTexture>&, const bool, base::unique_fd&&));
+                 void(const std::shared_ptr<std::promise<FenceResult>>&&, const DisplaySettings&,
+                      const std::vector<LayerSettings>&, const std::shared_ptr<ExternalTexture>&,
+                      const bool, base::unique_fd&&));
     MOCK_METHOD0(cleanFramebufferCache, void());
     MOCK_METHOD0(getContextPriority, int());
     MOCK_METHOD0(supportsBackgroundBlur, bool());
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index db983a8..b9aa5ac 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -632,7 +632,7 @@
 };
 
 void SkiaRenderEngine::drawLayersInternal(
-        const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+        const std::shared_ptr<std::promise<FenceResult>>&& resultPromise,
         const DisplaySettings& display, const std::vector<LayerSettings>& layers,
         const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
         base::unique_fd&& bufferFence) {
@@ -642,7 +642,7 @@
 
     if (buffer == nullptr) {
         ALOGE("No output buffer provided. Aborting GPU composition.");
-        resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+        resultPromise->set_value(base::unexpected(BAD_VALUE));
         return;
     }
 
@@ -675,7 +675,7 @@
     SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
     if (dstCanvas == nullptr) {
         ALOGE("Cannot acquire canvas from Skia.");
-        resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+        resultPromise->set_value(base::unexpected(BAD_VALUE));
         return;
     }
 
@@ -1126,8 +1126,7 @@
     }
 
     base::unique_fd drawFence = flushAndSubmit(grContext);
-    resultPromise->set_value({NO_ERROR, std::move(drawFence)});
-    return;
+    resultPromise->set_value(sp<Fence>::make(std::move(drawFence)));
 }
 
 size_t SkiaRenderEngine::getMaxTextureSize() const {
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index a5cd278..e7c5b8f 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -135,7 +135,7 @@
     void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
     void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
                     const ShadowSettings& shadowSettings);
-    void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+    void drawLayersInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise,
                             const DisplaySettings& display,
                             const std::vector<LayerSettings>& layers,
                             const std::shared_ptr<ExternalTexture>& buffer,
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index d23063c..9d8b2df 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -528,16 +528,15 @@
 
     void invokeDraw(const renderengine::DisplaySettings& settings,
                     const std::vector<renderengine::LayerSettings>& layers) {
-        std::future<renderengine::RenderEngineResult> result =
+        ftl::Future<FenceResult> future =
                 mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
+        ASSERT_TRUE(future.valid());
 
-        ASSERT_TRUE(result.valid());
-        auto [status, fence] = result.get();
+        auto result = future.get();
+        ASSERT_TRUE(result.ok());
 
-        ASSERT_EQ(NO_ERROR, status);
-        if (fence.ok()) {
-            sync_wait(fence.get(), -1);
-        }
+        auto fence = result.value();
+        fence->waitForever(LOG_TAG);
 
         if (layers.size() > 0 && mGLESRE != nullptr) {
             ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId()));
@@ -1681,13 +1680,13 @@
     layer.geometry.boundaries = fullscreenRect().toFloatRect();
     BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
     layers.push_back(layer);
-    std::future<renderengine::RenderEngineResult> result =
+    ftl::Future<FenceResult> future =
             mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd());
 
-    ASSERT_TRUE(result.valid());
-    auto [status, fence] = result.get();
-    ASSERT_EQ(BAD_VALUE, status);
-    ASSERT_FALSE(fence.ok());
+    ASSERT_TRUE(future.valid());
+    auto result = future.get();
+    ASSERT_FALSE(result.ok());
+    ASSERT_EQ(BAD_VALUE, result.error());
 }
 
 TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
@@ -1712,15 +1711,14 @@
     layer.alpha = 1.0;
     layers.push_back(layer);
 
-    std::future<renderengine::RenderEngineResult> result =
+    ftl::Future<FenceResult> future =
             mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd());
-    ASSERT_TRUE(result.valid());
-    auto [status, fence] = result.get();
+    ASSERT_TRUE(future.valid());
+    auto result = future.get();
 
-    ASSERT_EQ(NO_ERROR, status);
-    if (fence.ok()) {
-        sync_wait(fence.get(), -1);
-    }
+    ASSERT_TRUE(result.ok());
+    auto fence = result.value();
+    fence->waitForever(LOG_TAG);
 
     ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId()));
     expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
@@ -2219,20 +2217,20 @@
     layer.alpha = 1.0;
     layers.push_back(layer);
 
-    std::future<renderengine::RenderEngineResult> resultOne =
+    ftl::Future<FenceResult> futureOne =
             mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
-    ASSERT_TRUE(resultOne.valid());
-    auto [statusOne, fenceOne] = resultOne.get();
-    ASSERT_EQ(NO_ERROR, statusOne);
+    ASSERT_TRUE(futureOne.valid());
+    auto resultOne = futureOne.get();
+    ASSERT_TRUE(resultOne.ok());
+    auto fenceOne = resultOne.value();
 
-    std::future<renderengine::RenderEngineResult> resultTwo =
-            mRE->drawLayers(settings, layers, mBuffer, true, std::move(fenceOne));
-    ASSERT_TRUE(resultTwo.valid());
-    auto [statusTwo, fenceTwo] = resultTwo.get();
-    ASSERT_EQ(NO_ERROR, statusTwo);
-    if (fenceTwo.ok()) {
-        sync_wait(fenceTwo.get(), -1);
-    }
+    ftl::Future<FenceResult> futureTwo =
+            mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(fenceOne->dup()));
+    ASSERT_TRUE(futureTwo.valid());
+    auto resultTwo = futureTwo.get();
+    ASSERT_TRUE(resultTwo.ok());
+    auto fenceTwo = resultTwo.value();
+    fenceTwo->waitForever(LOG_TAG);
 
     // Only cleanup the first time.
     EXPECT_FALSE(mRE->canSkipPostRenderCleanup());
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 909ded3..1a96289 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -183,20 +183,17 @@
     base::unique_fd bufferFence;
 
     EXPECT_CALL(*mRenderEngine, drawLayersInternal)
-            .WillOnce([&](const std::shared_ptr<std::promise<renderengine::RenderEngineResult>>&&
-                                  resultPromise,
+            .WillOnce([&](const std::shared_ptr<std::promise<FenceResult>>&& resultPromise,
                           const renderengine::DisplaySettings&,
                           const std::vector<renderengine::LayerSettings>&,
                           const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                          base::unique_fd&&) -> void {
-                resultPromise->set_value({NO_ERROR, base::unique_fd()});
-            });
+                          base::unique_fd&&) { resultPromise->set_value(Fence::NO_FENCE); });
 
-    std::future<renderengine::RenderEngineResult> result =
+    ftl::Future<FenceResult> future =
             mThreadedRE->drawLayers(settings, layers, buffer, false, std::move(bufferFence));
-    ASSERT_TRUE(result.valid());
-    auto [status, _] = result.get();
-    ASSERT_EQ(NO_ERROR, status);
+    ASSERT_TRUE(future.valid());
+    auto result = future.get();
+    ASSERT_TRUE(result.ok());
 }
 
 } // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 203bb54..b41e843 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -313,21 +313,21 @@
 }
 
 void RenderEngineThreaded::drawLayersInternal(
-        const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+        const std::shared_ptr<std::promise<FenceResult>>&& resultPromise,
         const DisplaySettings& display, const std::vector<LayerSettings>& layers,
         const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
         base::unique_fd&& bufferFence) {
-    resultPromise->set_value({NO_ERROR, base::unique_fd()});
+    resultPromise->set_value(Fence::NO_FENCE);
     return;
 }
 
-std::future<RenderEngineResult> RenderEngineThreaded::drawLayers(
+ftl::Future<FenceResult> RenderEngineThreaded::drawLayers(
         const DisplaySettings& display, const std::vector<LayerSettings>& layers,
         const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
         base::unique_fd&& bufferFence) {
     ATRACE_CALL();
-    const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>();
-    std::future<RenderEngineResult> resultFuture = resultPromise->get_future();
+    const auto resultPromise = std::make_shared<std::promise<FenceResult>>();
+    std::future<FenceResult> resultFuture = resultPromise->get_future();
     int fd = bufferFence.release();
     {
         std::lock_guard lock(mThreadMutex);
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 1340902..bf2ebea 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -56,11 +56,11 @@
     void useProtectedContext(bool useProtectedContext) override;
     void cleanupPostRender() override;
 
-    std::future<RenderEngineResult> drawLayers(const DisplaySettings& display,
-                                               const std::vector<LayerSettings>& layers,
-                                               const std::shared_ptr<ExternalTexture>& buffer,
-                                               const bool useFramebufferCache,
-                                               base::unique_fd&& bufferFence) override;
+    ftl::Future<FenceResult> drawLayers(const DisplaySettings& display,
+                                        const std::vector<LayerSettings>& layers,
+                                        const std::shared_ptr<ExternalTexture>& buffer,
+                                        const bool useFramebufferCache,
+                                        base::unique_fd&& bufferFence) override;
 
     void cleanFramebufferCache() override;
     int getContextPriority() override;
@@ -73,7 +73,7 @@
     void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
     void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
     bool canSkipPostRenderCleanup() const override;
-    void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+    void drawLayersInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise,
                             const DisplaySettings& display,
                             const std::vector<LayerSettings>& layers,
                             const std::shared_ptr<ExternalTexture>& buffer,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h b/libs/ui/include/ui/FenceResult.h
similarity index 60%
rename from services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h
rename to libs/ui/include/ui/FenceResult.h
index 0ce263b..6d63fc9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h
+++ b/libs/ui/include/ui/FenceResult.h
@@ -20,30 +20,14 @@
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
 
-// TODO(b/232535621): Pull this file to <ui/FenceResult.h> so that RenderEngine::drawLayers returns
-// FenceResult rather than RenderEngineResult.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#include <renderengine/RenderEngine.h>
-#pragma clang diagnostic pop
-
 namespace android {
 
 class Fence;
 
 using FenceResult = base::expected<sp<Fence>, status_t>;
 
-// TODO(b/232535621): Prevent base::unexpected(NO_ERROR) from being a valid FenceResult.
 inline status_t fenceStatus(const FenceResult& fenceResult) {
     return fenceResult.ok() ? NO_ERROR : fenceResult.error();
 }
 
-inline FenceResult toFenceResult(renderengine::RenderEngineResult&& result) {
-    if (auto [status, fence] = std::move(result); fence.ok()) {
-        return sp<Fence>::make(std::move(fence));
-    } else {
-        return base::unexpected(status);
-    }
-}
-
 } // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index f93fd99..9753a6c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -20,8 +20,6 @@
 #include <ostream>
 #include <unordered_set>
 
-#include <compositionengine/FenceResult.h>
-
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
@@ -33,6 +31,7 @@
 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
 
 #include <ftl/future.h>
+#include <ui/FenceResult.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 06ae9e9..ea78517 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1330,11 +1330,10 @@
     // over to RenderEngine, in which case this flag can be removed from the drawLayers interface.
     const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay;
 
-    auto fenceResult =
-            toFenceResult(renderEngine
-                                  .drawLayers(clientCompositionDisplay, clientRenderEngineLayers,
-                                              tex, useFramebufferCache, std::move(fd))
-                                  .get());
+    auto fenceResult = renderEngine
+                               .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, tex,
+                                           useFramebufferCache, std::move(fd))
+                               .get();
 
     if (mClientCompositionRequestCache && fenceStatus(fenceResult) != NO_ERROR) {
         // If rendering was not successful, remove the request from the cache.
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 3315767..0731d48 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -273,11 +273,10 @@
 
     constexpr bool kUseFramebufferCache = false;
 
-    auto fenceResult =
-            toFenceResult(renderEngine
-                                  .drawLayers(displaySettings, layerSettings, texture->get(),
-                                              kUseFramebufferCache, std::move(bufferFence))
-                                  .get());
+    auto fenceResult = renderEngine
+                               .drawLayers(displaySettings, layerSettings, texture->get(),
+                                           kUseFramebufferCache, std::move(bufferFence))
+                               .get();
 
     if (fenceStatus(fenceResult) == NO_ERROR) {
         mDrawFence = std::move(fenceResult).value_or(Fence::NO_FENCE);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 163a11c..ace2864 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -39,7 +39,6 @@
 #include "CallOrderStateMachineHelper.h"
 #include "MockHWC2.h"
 #include "RegionMatcher.h"
-#include "TestUtils.h"
 
 namespace android::compositionengine {
 namespace {
@@ -3527,9 +3526,8 @@
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
                                 const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd&&)
-                                    -> std::future<renderengine::RenderEngineResult> {
-                return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
+                return ftl::yield<FenceResult>(Fence::NO_FENCE);
             });
     verify().execute().expectAFenceWasReturned();
 }
@@ -3559,9 +3557,8 @@
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
                                 const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd&&)
-                                    -> std::future<renderengine::RenderEngineResult> {
-                return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
+                return ftl::yield<FenceResult>(Fence::NO_FENCE);
             });
 
     verify().execute().expectAFenceWasReturned();
@@ -3594,9 +3591,8 @@
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
                                 const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd&&)
-                                    -> std::future<renderengine::RenderEngineResult> {
-                return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
+                return ftl::yield<FenceResult>(Fence::NO_FENCE);
             });
 
     verify().execute().expectAFenceWasReturned();
@@ -3622,10 +3618,8 @@
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
     EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
             .Times(2)
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))))
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
 
     verify().execute().expectAFenceWasReturned();
     EXPECT_FALSE(mOutput.mState.reusedClientComposition);
@@ -3653,8 +3647,7 @@
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
     EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
 
     verify().execute().expectAFenceWasReturned();
@@ -3693,9 +3686,8 @@
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
                                 const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd&&)
-                                    -> std::future<renderengine::RenderEngineResult> {
-                return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
+                return ftl::yield<FenceResult>(Fence::NO_FENCE);
             });
 
     verify().execute().expectAFenceWasReturned();
@@ -3726,11 +3718,9 @@
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
     EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r3), _, false, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
 
     verify().execute().expectAFenceWasReturned();
     EXPECT_FALSE(mOutput.mState.reusedClientComposition);
@@ -3807,8 +3797,7 @@
           : public CallOrderStateMachineHelper<TestType, ExpectDisplaySettingsState> {
         auto thenExpectDisplaySettingsUsed(renderengine::DisplaySettings settings) {
             EXPECT_CALL(getInstance()->mRenderEngine, drawLayers(settings, _, _, false, _))
-                    .WillOnce(Return(ByMove(futureOf<renderengine::RenderEngineResult>(
-                            {NO_ERROR, base::unique_fd()}))));
+                    .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
             return nextState<ExecuteState>();
         }
     };
@@ -4061,14 +4050,12 @@
                 .WillRepeatedly(Return());
         EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
         EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
-                .WillRepeatedly(
-                        [&](const renderengine::DisplaySettings&,
-                            const std::vector<renderengine::LayerSettings>&,
-                            const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                            base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
-                            return futureOf<renderengine::RenderEngineResult>(
-                                    {NO_ERROR, base::unique_fd()});
-                        });
+                .WillRepeatedly([&](const renderengine::DisplaySettings&,
+                                    const std::vector<renderengine::LayerSettings>&,
+                                    const std::shared_ptr<renderengine::ExternalTexture>&,
+                                    const bool, base::unique_fd&&) -> ftl::Future<FenceResult> {
+                    return ftl::yield<FenceResult>(Fence::NO_FENCE);
+                });
     }
 
     Layer mLayer1;
@@ -4133,8 +4120,7 @@
     // Must happen after setting the protected content state.
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
 
     base::unique_fd fd;
     std::shared_ptr<renderengine::ExternalTexture> tex;
@@ -4226,8 +4212,7 @@
 
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true));
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
 
     base::unique_fd fd;
     std::shared_ptr<renderengine::ExternalTexture> tex;
@@ -4250,8 +4235,7 @@
         EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace, _))
                 .WillOnce(Return(std::vector<LayerFE::LayerSettings>{}));
         EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
-                .WillOnce(Return(ByMove(futureOf<renderengine::RenderEngineResult>(
-                        {NO_ERROR, base::unique_fd()}))));
+                .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
         EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
         EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
                 .WillRepeatedly(Return(&mLayer.outputLayer));
diff --git a/services/surfaceflinger/CompositionEngine/tests/TestUtils.h b/services/surfaceflinger/CompositionEngine/tests/TestUtils.h
deleted file mode 100644
index c80fde6..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/TestUtils.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2021 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 <future>
-
-namespace android::compositionengine {
-namespace {
-
-template <class T>
-std::future<T> futureOf(T obj) {
-    std::promise<T> resultPromise;
-    std::future<T> resultFuture = resultPromise.get_future();
-    resultPromise.set_value(std::move(obj));
-    return resultFuture;
-}
-} // namespace
-} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 2b938d0..d5d688e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -28,8 +28,6 @@
 #include <utils/Errors.h>
 #include <memory>
 
-#include "tests/TestUtils.h"
-
 namespace android::compositionengine {
 using namespace std::chrono_literals;
 
@@ -353,11 +351,10 @@
     clientComp2.emplace();
     clientComp2->alpha = 0.75f;
 
-    const auto drawLayers =
-            [&](const renderengine::DisplaySettings& displaySettings,
-                const std::vector<renderengine::LayerSettings>& layers,
-                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+    const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
+                                const std::vector<renderengine::LayerSettings>& layers,
+                                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
         EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
         EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
         EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
@@ -365,7 +362,7 @@
         EXPECT_EQ(0.5f, layers[0].alpha);
         EXPECT_EQ(0.75f, layers[1].alpha);
         EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
-        return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+        return ftl::yield<FenceResult>(Fence::NO_FENCE);
     };
 
     EXPECT_CALL(*layerFE1, prepareClientComposition(ClientCompositionTargetSettingsSecureEq(false)))
@@ -403,11 +400,10 @@
     clientComp2.emplace();
     clientComp2->alpha = 0.75f;
 
-    const auto drawLayers =
-            [&](const renderengine::DisplaySettings& displaySettings,
-                const std::vector<renderengine::LayerSettings>& layers,
-                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+    const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
+                                const std::vector<renderengine::LayerSettings>& layers,
+                                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
         EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
         EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
         EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
@@ -416,7 +412,7 @@
         EXPECT_EQ(0.75f, layers[1].alpha);
         EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
 
-        return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+        return ftl::yield<FenceResult>(Fence::NO_FENCE);
     };
 
     EXPECT_CALL(*layerFE1, prepareClientComposition(ClientCompositionTargetSettingsSecureEq(true)))
@@ -454,13 +450,12 @@
 
     mOutputState.displayBrightnessNits = 400.f;
 
-    const auto drawLayers =
-            [&](const renderengine::DisplaySettings& displaySettings,
-                const std::vector<renderengine::LayerSettings>&,
-                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+    const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
+                                const std::vector<renderengine::LayerSettings>&,
+                                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
         EXPECT_EQ(mOutputState.displayBrightnessNits, displaySettings.targetLuminanceNits);
-        return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+        return ftl::yield<FenceResult>(Fence::NO_FENCE);
     };
 
     EXPECT_CALL(*layerFE1,
@@ -505,13 +500,12 @@
 
     mOutputState.displayBrightnessNits = 400.f;
 
-    const auto drawLayers =
-            [&](const renderengine::DisplaySettings& displaySettings,
-                const std::vector<renderengine::LayerSettings>&,
-                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+    const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
+                                const std::vector<renderengine::LayerSettings>&,
+                                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
         EXPECT_EQ(mOutputState.displayBrightnessNits, displaySettings.targetLuminanceNits);
-        return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+        return ftl::yield<FenceResult>(Fence::NO_FENCE);
     };
 
     EXPECT_CALL(*layerFE1,
@@ -555,11 +549,10 @@
 
     mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(2, 3, 10, 5));
 
-    const auto drawLayers =
-            [&](const renderengine::DisplaySettings& displaySettings,
-                const std::vector<renderengine::LayerSettings>& layers,
-                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+    const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
+                                const std::vector<renderengine::LayerSettings>& layers,
+                                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
         EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
         EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
         EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
@@ -568,7 +561,7 @@
         EXPECT_EQ(0.75f, layers[1].alpha);
         EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
 
-        return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+        return ftl::yield<FenceResult>(Fence::NO_FENCE);
     };
 
     EXPECT_CALL(*layerFE1, prepareClientComposition(_)).WillOnce(Return(clientComp1));
@@ -786,11 +779,10 @@
     EXPECT_CALL(*layerFE2, prepareClientComposition(_)).WillOnce(Return(clientComp2));
     EXPECT_CALL(*layerFE3, prepareClientComposition(_)).WillOnce(Return(clientComp3));
 
-    const auto drawLayers =
-            [&](const renderengine::DisplaySettings&,
-                const std::vector<renderengine::LayerSettings>& layers,
-                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+    const auto drawLayers = [&](const renderengine::DisplaySettings&,
+                                const std::vector<renderengine::LayerSettings>& layers,
+                                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
         // If the highlight layer is enabled, it will increase the size by 1.
         // We're interested in the third layer either way.
         EXPECT_GE(layers.size(), 4u);
@@ -810,7 +802,7 @@
             EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha);
         }
 
-        return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+        return ftl::yield<FenceResult>(Fence::NO_FENCE);
     };
 
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
@@ -847,11 +839,10 @@
     EXPECT_CALL(*layerFE2, prepareClientComposition(_)).WillOnce(Return(clientComp2));
     EXPECT_CALL(*layerFE3, prepareClientComposition(_)).WillOnce(Return(clientComp3));
 
-    const auto drawLayers =
-            [&](const renderengine::DisplaySettings&,
-                const std::vector<renderengine::LayerSettings>& layers,
-                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+    const auto drawLayers = [&](const renderengine::DisplaySettings&,
+                                const std::vector<renderengine::LayerSettings>& layers,
+                                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
         // If the highlight layer is enabled, it will increase the size by 1.
         // We're interested in the third layer either way.
         EXPECT_GE(layers.size(), 4u);
@@ -872,7 +863,7 @@
             EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha);
         }
 
-        return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+        return ftl::yield<FenceResult>(Fence::NO_FENCE);
     };
 
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
@@ -999,11 +990,10 @@
                                 BackgroundBlurOnly)))
             .WillOnce(Return(clientComp3));
 
-    const auto drawLayers =
-            [&](const renderengine::DisplaySettings&,
-                const std::vector<renderengine::LayerSettings>& layers,
-                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+    const auto drawLayers = [&](const renderengine::DisplaySettings&,
+                                const std::vector<renderengine::LayerSettings>& layers,
+                                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+                                base::unique_fd&&) -> ftl::Future<FenceResult> {
         // If the highlight layer is enabled, it will increase the size by 1.
         // We're interested in the third layer either way.
         EXPECT_GE(layers.size(), 3u);
@@ -1012,7 +1002,7 @@
         EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings.source.solidColor);
         EXPECT_EQ(0.0f, blurSettings.alpha);
 
-        return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+        return ftl::yield<FenceResult>(Fence::NO_FENCE);
     };
 
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 430a663..86cfee6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -27,8 +27,6 @@
 #include <renderengine/mock/RenderEngine.h>
 #include <chrono>
 
-#include "tests/TestUtils.h"
-
 namespace android::compositionengine {
 using namespace std::chrono_literals;
 using impl::planner::CachedSet;
@@ -171,8 +169,7 @@
 void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) {
     // layers would be flattened but the buffer would not be overridden
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
 
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
@@ -423,8 +420,7 @@
     layerState1->resetFramesSinceBufferUpdate();
 
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -447,8 +443,7 @@
     mTime += 200ms;
 
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -500,8 +495,7 @@
     layerState3->resetFramesSinceBufferUpdate();
 
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -515,8 +509,7 @@
 
     // Layers 1 and 2 will be flattened a new drawFrame would be called for Layer4 and Layer5
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -545,8 +538,7 @@
     layerState3->incrementFramesSinceBufferUpdate();
     mTime += 200ms;
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -601,8 +593,7 @@
 
     // This will render a CachedSet.
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
@@ -666,8 +657,7 @@
 
     // This will render a CachedSet.
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
@@ -739,8 +729,7 @@
     // This will render a CachedSet of layer 0. Though it is just one layer, it satisfies the
     // exception that there would be a hole punch above it.
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
@@ -810,8 +799,7 @@
     // This will render a CachedSet of layer 0. Though it is just one layer, it satisfies the
     // exception that there would be a hole punch above it.
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
@@ -862,8 +850,7 @@
 
     // layers would be flattened but the buffer would not be overridden
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
 
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
@@ -908,8 +895,7 @@
 
     // layers would be flattened but the buffer would not be overridden
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillRepeatedly(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillRepeatedly(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
 
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
@@ -962,8 +948,7 @@
 
     // layers would be flattened but the buffer would not be overridden
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
 
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
@@ -1011,8 +996,7 @@
 
     // layers would be flattened but the buffer would not be overridden
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
 
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
@@ -1054,8 +1038,7 @@
     mTime += 200ms;
     // layers would be flattened but the buffer would not be overridden
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
 
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
@@ -1122,8 +1105,7 @@
     }
 
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     mFlattener->renderCachedSets(mOutputState,
                                  std::chrono::steady_clock::now() -
                                          (kCachedSetRenderDuration + 10ms),
@@ -1159,8 +1141,7 @@
 
     // This will render a CachedSet.
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
@@ -1210,8 +1191,7 @@
 
     // This will render a CachedSet.
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
@@ -1261,8 +1241,7 @@
 
     // This will render a CachedSet.
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
@@ -1315,8 +1294,7 @@
 
     // This will render a CachedSet.
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
@@ -1368,8 +1346,7 @@
 
     // This will render a CachedSet.
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
-            .WillOnce(Return(ByMove(
-                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+            .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
     mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 803eb4f..6426478 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -42,9 +42,9 @@
     DisplayModeIterator modeIt;
     float overallScore;
     struct {
-        float belowThreshold;
-        float aboveThreshold;
-    } fixedRateLayersScore;
+        float modeBelowThreshold;
+        float modeAboveThreshold;
+    } fixedRateBelowThresholdLayersScore;
 };
 
 template <typename Iterator>
@@ -385,7 +385,7 @@
 
         const auto weight = layer.weight;
 
-        for (auto& [modeIt, overallScore, fixedRateScore] : scores) {
+        for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
             const auto& [id, mode] = *modeIt;
             const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup();
 
@@ -451,21 +451,22 @@
                         return false;
                 }
             }(layer.vote);
-            const bool layerAboveThreshold = mConfig.frameRateMultipleThreshold != 0 &&
-                    mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold) &&
+            const bool layerBelowThreshold = mConfig.frameRateMultipleThreshold != 0 &&
                     layer.desiredRefreshRate <
                             Fps::fromValue(mConfig.frameRateMultipleThreshold / 2);
-            if (fixedSourceLayer) {
-                if (layerAboveThreshold) {
+            const bool modeAboveThreshold = layerBelowThreshold &&
+                    mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold);
+            if (fixedSourceLayer && layerBelowThreshold) {
+                if (modeAboveThreshold) {
                     ALOGV("%s gives %s fixed source (above threshold) score of %.4f",
                           formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
                           layerScore);
-                    fixedRateScore.aboveThreshold += weightedLayerScore;
+                    fixedRateBelowThresholdLayersScore.modeAboveThreshold += weightedLayerScore;
                 } else {
                     ALOGV("%s gives %s fixed source (below threshold) score of %.4f",
                           formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
                           layerScore);
-                    fixedRateScore.belowThreshold += weightedLayerScore;
+                    fixedRateBelowThresholdLayersScore.modeBelowThreshold += weightedLayerScore;
                 }
             } else {
                 ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
@@ -476,7 +477,7 @@
     }
 
     // We want to find the best refresh rate without the fixed source layers,
-    // so we could know whether we should add the aboveThreshold scores or not.
+    // so we could know whether we should add the modeAboveThreshold scores or not.
     // If the best refresh rate is already above the threshold, it means that
     // some non-fixed source layers already scored it, so we can just add the score
     // for all fixed source layers, even the ones that are above the threshold.
@@ -500,10 +501,10 @@
     }();
 
     // Now we can add the fixed rate layers score
-    for (auto& [modeIt, overallScore, fixedRateScore] : scores) {
-        overallScore += fixedRateScore.belowThreshold;
+    for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
+        overallScore += fixedRateBelowThresholdLayersScore.modeBelowThreshold;
         if (maxScoreAboveThreshold) {
-            overallScore += fixedRateScore.aboveThreshold;
+            overallScore += fixedRateBelowThresholdLayersScore.modeAboveThreshold;
         }
         ALOGV("%s adjusted overallScore is %.4f", to_string(modeIt->second->getFps()).c_str(),
               overallScore);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e1fcaa0..bdc8406 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -6615,13 +6615,11 @@
     getRenderEngine().useProtectedContext(useProtected);
 
     constexpr bool kUseFramebufferCache = false;
-    auto chain =
-            ftl::Future(getRenderEngine().drawLayers(clientCompositionDisplay,
-                                                     clientRenderEngineLayers, buffer,
-                                                     kUseFramebufferCache, std::move(bufferFence)))
-                    .then(&toFenceResult);
+    const auto future = getRenderEngine()
+                                .drawLayers(clientCompositionDisplay, clientRenderEngineLayers,
+                                            buffer, kUseFramebufferCache, std::move(bufferFence))
+                                .share();
 
-    const auto future = chain.share();
     for (auto* layer : renderedLayers) {
         layer->onLayerDisplayed(future);
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 2b230b3..3101885 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -52,11 +52,11 @@
 #include <utils/Trace.h>
 #include <utils/threads.h>
 
-#include <compositionengine/FenceResult.h>
 #include <compositionengine/OutputColorSetting.h>
 #include <scheduler/Fps.h>
 #include <scheduler/PresentLatencyTracker.h>
 #include <scheduler/Time.h>
+#include <ui/FenceResult.h>
 
 #include "ClientCache.h"
 #include "DisplayDevice.h"
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 59abe33..23ea7a5 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -26,10 +26,10 @@
 
 #include <android-base/thread_annotations.h>
 #include <binder/IBinder.h>
-#include <compositionengine/FenceResult.h>
 #include <ftl/future.h>
 #include <gui/ITransactionCompletedListener.h>
 #include <ui/Fence.h>
+#include <ui/FenceResult.h>
 
 namespace android {
 
diff --git a/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp b/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp
index fb4458a..9162674 100644
--- a/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp
+++ b/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp
@@ -80,14 +80,6 @@
 
 } // namespace
 
-TEST(RefreshRateOverlayTest, enableOverlay) {
-    toggleOverlay(true);
-}
-
-TEST(RefreshRateOverlayTest, disableOverlay) {
-    toggleOverlay(false);
-}
-
 TEST(RefreshRateOverlayTest, enableAndDisableOverlay) {
     toggleOverlay(true);
     toggleOverlay(false);
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 0666561..77625b3 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -351,15 +351,13 @@
                 .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
                                     const std::vector<renderengine::LayerSettings>&,
                                     const std::shared_ptr<renderengine::ExternalTexture>&,
-                                    const bool, base::unique_fd&&)
-                                        -> std::future<renderengine::RenderEngineResult> {
+                                    const bool, base::unique_fd&&) -> std::future<FenceResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.physicalDisplay);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.clip);
-                    return futureOf<renderengine::RenderEngineResult>(
-                            {NO_ERROR, base::unique_fd()});
+                    return futureOf<FenceResult>(Fence::NO_FENCE);
                 });
     }
 
@@ -404,16 +402,14 @@
                 .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
                                     const std::vector<renderengine::LayerSettings>&,
                                     const std::shared_ptr<renderengine::ExternalTexture>&,
-                                    const bool, base::unique_fd&&)
-                                        -> std::future<renderengine::RenderEngineResult> {
+                                    const bool, base::unique_fd&&) -> std::future<FenceResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.physicalDisplay);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.clip);
                     EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace);
-                    return futureOf<renderengine::RenderEngineResult>(
-                            {NO_ERROR, base::unique_fd()});
+                    return futureOf<FenceResult>(Fence::NO_FENCE);
                 });
     }
 
@@ -606,7 +602,7 @@
                 .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
                               const std::vector<renderengine::LayerSettings>& layerSettings,
                               const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                              base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+                              base::unique_fd&&) -> std::future<FenceResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.physicalDisplay);
@@ -614,9 +610,7 @@
                               displaySettings.clip);
                     // screen capture adds an additional color layer as an alpha
                     // prefill, so gtet the back layer.
-                    std::future<renderengine::RenderEngineResult> resultFuture =
-                            futureOf<renderengine::RenderEngineResult>(
-                                    {NO_ERROR, base::unique_fd()});
+                    std::future<FenceResult> resultFuture = futureOf<FenceResult>(Fence::NO_FENCE);
                     if (layerSettings.empty()) {
                         ADD_FAILURE() << "layerSettings was not expected to be empty in "
                                          "setupREBufferCompositionCommonCallExpectations "
@@ -659,7 +653,7 @@
                 .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
                               const std::vector<renderengine::LayerSettings>& layerSettings,
                               const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                              base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+                              base::unique_fd&&) -> std::future<FenceResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.physicalDisplay);
@@ -667,9 +661,7 @@
                               displaySettings.clip);
                     // screen capture adds an additional color layer as an alpha
                     // prefill, so get the back layer.
-                    std::future<renderengine::RenderEngineResult> resultFuture =
-                            futureOf<renderengine::RenderEngineResult>(
-                                    {NO_ERROR, base::unique_fd()});
+                    std::future<FenceResult> resultFuture = futureOf<FenceResult>(Fence::NO_FENCE);
                     if (layerSettings.empty()) {
                         ADD_FAILURE()
                                 << "layerSettings was not expected to be empty in "
@@ -740,7 +732,7 @@
                 .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
                               const std::vector<renderengine::LayerSettings>& layerSettings,
                               const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                              base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+                              base::unique_fd&&) -> std::future<FenceResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.physicalDisplay);
@@ -748,9 +740,7 @@
                               displaySettings.clip);
                     // screen capture adds an additional color layer as an alpha
                     // prefill, so get the back layer.
-                    std::future<renderengine::RenderEngineResult> resultFuture =
-                            futureOf<renderengine::RenderEngineResult>(
-                                    {NO_ERROR, base::unique_fd()});
+                    std::future<FenceResult> resultFuture = futureOf<FenceResult>(Fence::NO_FENCE);
                     if (layerSettings.empty()) {
                         ADD_FAILURE() << "layerSettings was not expected to be empty in "
                                          "setupInsecureREBufferCompositionCommonCallExpectations "
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 1484bcd..188fd58 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -564,9 +564,10 @@
     TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60,
                                        {.frameRateMultipleThreshold = 120});
 
-    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}, {.weight = 1.f}};
     auto& lr1 = layers[0];
     auto& lr2 = layers[1];
+    auto& lr3 = layers[2];
 
     lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitDefault;
@@ -662,6 +663,25 @@
     lr2.vote = LayerVoteType::ExplicitExact;
     lr2.name = "120Hz ExplicitExact";
     EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+    lr1.desiredRefreshRate = 10_Hz;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "30Hz ExplicitExactOrMultiple";
+    lr2.desiredRefreshRate = 120_Hz;
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.name = "120Hz ExplicitExact";
+    EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+    lr1.desiredRefreshRate = 30_Hz;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "30Hz ExplicitExactOrMultiple";
+    lr2.desiredRefreshRate = 30_Hz;
+    lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr2.name = "30Hz ExplicitExactOrMultiple";
+    lr3.vote = LayerVoteType::Heuristic;
+    lr3.desiredRefreshRate = 120_Hz;
+    lr3.name = "120Hz Heuristic";
+    EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {