Merge "Support render-ahead in vulkan" into qt-dev
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 9b1f259..9998854 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -17,8 +17,8 @@
 #include "Properties.h"
 #include "Debug.h"
 #include "DeviceInfo.h"
-#include "SkTraceEventCommon.h"
 #include "HWUIProperties.sysprop.h"
+#include "SkTraceEventCommon.h"
 
 #include <algorithm>
 #include <cstdlib>
@@ -67,7 +67,7 @@
 bool Properties::isolatedProcess = false;
 
 int Properties::contextPriority = 0;
-int Properties::defaultRenderAhead = 0;
+uint32_t Properties::defaultRenderAhead = 0;
 
 static int property_get_int(const char* key, int defaultValue) {
     char buf[PROPERTY_VALUE_MAX] = {
@@ -130,12 +130,9 @@
 
     enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, true);
 
-    defaultRenderAhead = std::max(0, std::min(2, property_get_int(PROPERTY_RENDERAHEAD,
-            render_ahead().value_or(0))));
-
-    if (defaultRenderAhead && sRenderPipelineType == RenderPipelineType::SkiaVulkan) {
-        ALOGW("hwui.render_ahead of %d ignored because pipeline is skiavk", defaultRenderAhead);
-    }
+    defaultRenderAhead =
+            std::max(0u, std::min(2u, static_cast<uint32_t>(property_get_int(
+                                              PROPERTY_RENDERAHEAD, render_ahead().value_or(0)))));
 
     return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw);
 }
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 3e91c63..3105e58 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -253,7 +253,7 @@
 
     ANDROID_API static int contextPriority;
 
-    static int defaultRenderAhead;
+    static uint32_t defaultRenderAhead;
 
 private:
     static ProfileType sProfileType;
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 8508274..66aa8c2 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "ShaderCache.h"
+#include <GrContext.h>
 #include <log/log.h>
 #include <openssl/sha.h>
 #include <algorithm>
@@ -23,7 +24,6 @@
 #include "FileBlobCache.h"
 #include "Properties.h"
 #include "utils/TraceUtils.h"
-#include <GrContext.h>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 570e895..9248ead 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -101,7 +101,7 @@
 
     SkiaPipeline::updateLighting(lightGeometry, lightInfo);
     renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
-            SkMatrix::I());
+                SkMatrix::I());
     layerUpdateQueue->clear();
 
     // Draw visual debugging features
@@ -156,8 +156,23 @@
     }
 }
 
+static void setBufferCount(ANativeWindow* window, uint32_t extraBuffers) {
+    int query_value;
+    int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
+    if (err != 0 || query_value < 0) {
+        ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
+        return;
+    }
+    auto min_undequeued_buffers = static_cast<uint32_t>(query_value);
+
+    int bufferCount = min_undequeued_buffers + 2 + extraBuffers;
+    ALOGD("Setting buffer count to %d, min_undequeued %u, extraBuffers %u",
+            bufferCount, min_undequeued_buffers, extraBuffers);
+    native_window_set_buffer_count(window, bufferCount);
+}
+
 bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
-                                    ColorMode colorMode) {
+                                    ColorMode colorMode, uint32_t extraBuffers) {
     if (mEglSurface != EGL_NO_SURFACE) {
         mEglManager.destroySurface(mEglSurface);
         mEglSurface = EGL_NO_SURFACE;
@@ -177,6 +192,7 @@
     if (mEglSurface != EGL_NO_SURFACE) {
         const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
         mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
+        setBufferCount(surface, extraBuffers);
         return true;
     }
 
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 6692922..3fe0f92 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -44,7 +44,7 @@
                      FrameInfo* currentFrameInfo, bool* requireSwap) override;
     DeferredLayerUpdater* createTextureLayer() override;
     bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
-                    renderthread::ColorMode colorMode) override;
+                    renderthread::ColorMode colorMode, uint32_t extraBuffers) override;
     void onStop() override;
     bool isSurfaceReady() override;
     bool isContextReady() override;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 721a115..ccc1701 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -250,8 +250,9 @@
         }
         if (mCaptureSequence > 0 || mPictureCapturedCallback) {
             mRecorder.reset(new SkPictureRecorder());
-            SkCanvas* pictureCanvas = mRecorder->beginRecording(surface->width(), surface->height(), nullptr,
-                                                                SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
+            SkCanvas* pictureCanvas =
+                    mRecorder->beginRecording(surface->width(), surface->height(), nullptr,
+                                              SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
             mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
             mNwayCanvas->addCanvas(surface->getCanvas());
             mNwayCanvas->addCanvas(pictureCanvas);
@@ -276,8 +277,7 @@
                 if (1 == mCaptureSequence) {
                     savePictureAsync(data, mCapturedFile);
                 } else {
-                    savePictureAsync(data,
-                            mCapturedFile + "_" + std::to_string(mCaptureSequence));
+                    savePictureAsync(data, mCapturedFile + "_" + std::to_string(mCaptureSequence));
                 }
                 mCaptureSequence--;
             }
@@ -327,7 +327,7 @@
     auto& props = node.properties();
     return Rect(props.getLeft(), props.getTop(), props.getRight(), props.getBottom());
 }
-}
+}  // namespace
 
 void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
                                    const std::vector<sp<RenderNode>>& nodes, bool opaque,
@@ -464,10 +464,20 @@
 // (3) Requires RGBA colors (instead of BGRA).
 static const uint32_t kOverdrawColors[2][6] = {
         {
-                0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f,
+                0x00000000,
+                0x00000000,
+                0x2f2f0000,
+                0x2f002f00,
+                0x3f00003f,
+                0x7f00007f,
         },
         {
-                0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f,
+                0x00000000,
+                0x00000000,
+                0x2f2f0000,
+                0x4f004f4f,
+                0x5f50335f,
+                0x7f00007f,
         },
 };
 
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index d945635..5a47a29 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -142,8 +142,7 @@
 void SkiaRecordingCanvas::drawWebViewFunctor(int functor) {
     FunctorDrawable* functorDrawable;
     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
-        functorDrawable =
-                mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, asSkCanvas());
+        functorDrawable = mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, asSkCanvas());
     } else {
         functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, asSkCanvas());
     }
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index edde6d3..e8cb219 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -18,12 +18,12 @@
 
 #include "DeferredLayerUpdater.h"
 #include "Readback.h"
+#include "ShaderCache.h"
 #include "SkiaPipeline.h"
 #include "SkiaProfileRenderer.h"
 #include "VkInteropFunctorDrawable.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/Frame.h"
-#include "ShaderCache.h"
 
 #include <SkSurface.h>
 #include <SkTypes.h>
@@ -70,8 +70,8 @@
         return false;
     }
     SkiaPipeline::updateLighting(lightGeometry, lightInfo);
-    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
-            backBuffer, mVkSurface->getCurrentPreTransform());
+    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer,
+                mVkSurface->getCurrentPreTransform());
     ShaderCache::get().onVkFrameFlushed(mRenderThread.getGrContext());
     layerUpdateQueue->clear();
 
@@ -116,7 +116,7 @@
 void SkiaVulkanPipeline::onStop() {}
 
 bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
-                                    ColorMode colorMode) {
+                                    ColorMode colorMode, uint32_t extraBuffers) {
     if (mVkSurface) {
         mVkManager.destroySurface(mVkSurface);
         mVkSurface = nullptr;
@@ -125,8 +125,9 @@
     setSurfaceColorProperties(colorMode);
     if (surface) {
         mRenderThread.requireVkContext();
-        mVkSurface = mVkManager.createSurface(surface, colorMode, mSurfaceColorSpace,
-                                              mSurfaceColorType, mRenderThread.getGrContext());
+        mVkSurface =
+                mVkManager.createSurface(surface, colorMode, mSurfaceColorSpace, mSurfaceColorType,
+                                         mRenderThread.getGrContext(), extraBuffers);
     }
 
     return mVkSurface != nullptr;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 77a7ab1..3173478 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -43,7 +43,7 @@
                      FrameInfo* currentFrameInfo, bool* requireSwap) override;
     DeferredLayerUpdater* createTextureLayer() override;
     bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
-                    renderthread::ColorMode colorMode) override;
+                    renderthread::ColorMode colorMode, uint32_t extraBuffers) override;
     void onStop() override;
     bool isSurfaceReady() override;
     bool isContextReady() override;
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 1b9e53b..1127926 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -17,16 +17,16 @@
 #include "VkFunctorDrawable.h"
 #include <private/hwui/DrawVkInfo.h>
 
-#include "renderthread/VulkanManager.h"
-#include "renderthread/RenderThread.h"
-#include <SkAndroidFrameworkUtils.h>
 #include <GrBackendDrawableInfo.h>
+#include <SkAndroidFrameworkUtils.h>
 #include <SkImage.h>
 #include <utils/Color.h>
 #include <utils/Trace.h>
 #include <utils/TraceUtils.h>
 #include <vk/GrVkTypes.h>
 #include <thread>
+#include "renderthread/RenderThread.h"
+#include "renderthread/VulkanManager.h"
 #include "thread/ThreadBase.h"
 #include "utils/TimeUtils.h"
 
@@ -64,13 +64,13 @@
 
     SkMatrix44 mat4(mMatrix);
     VkFunctorDrawParams params{
-      .width = mImageInfo.width(),
-      .height = mImageInfo.height(),
-      .color_space_ptr = mImageInfo.colorSpace(),
-      .clip_left = mClip.fLeft,
-      .clip_top = mClip.fTop,
-      .clip_right = mClip.fRight,
-      .clip_bottom = mClip.fBottom,
+            .width = mImageInfo.width(),
+            .height = mImageInfo.height(),
+            .color_space_ptr = mImageInfo.colorSpace(),
+            .clip_left = mClip.fLeft,
+            .clip_top = mClip.fTop,
+            .clip_right = mClip.fRight,
+            .clip_bottom = mClip.fBottom,
     };
     mat4.asColMajorf(&params.transform[0]);
     params.secondary_command_buffer = vulkan_info.fSecondaryCommandBuffer;
@@ -87,8 +87,7 @@
     vulkan_info.fDrawBounds->extent.height = mClip.fBottom - mClip.fTop;
 }
 
-VkFunctorDrawable::~VkFunctorDrawable() {
-}
+VkFunctorDrawable::~VkFunctorDrawable() {}
 
 void VkFunctorDrawable::onDraw(SkCanvas* canvas) {
     // "canvas" is either SkNWayCanvas created by SkiaPipeline::tryCapture (SKP capture use case) or
@@ -106,9 +105,8 @@
         SkCanvas* gpuCanvas = SkAndroidFrameworkUtils::getBaseWrappedCanvas(canvas);
         // Enforce "canvas" must be an AlphaFilterCanvas. For GPU canvas, the call should come from
         // onSnapGpuDrawHandler.
-        LOG_ALWAYS_FATAL_IF(
-                gpuCanvas == canvas,
-                "VkFunctorDrawable::onDraw() should not be called with a GPU canvas!");
+        LOG_ALWAYS_FATAL_IF(gpuCanvas == canvas,
+                            "VkFunctorDrawable::onDraw() should not be called with a GPU canvas!");
 
         // This will invoke onSnapGpuDrawHandler and regular draw flow.
         gpuCanvas->drawDrawable(this);
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 8b02c11..a31081c 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -21,17 +21,16 @@
 #include "RenderThread.h"
 #include "pipeline/skia/ShaderCache.h"
 #include "pipeline/skia/SkiaMemoryTracer.h"
-#include "Properties.h"
 #include "renderstate/RenderState.h"
 #include "thread/CommonPool.h"
 
 #include <GrContextOptions.h>
 #include <SkExecutor.h>
 #include <SkGraphics.h>
+#include <SkMathPriv.h>
 #include <gui/Surface.h>
 #include <math.h>
 #include <set>
-#include <SkMathPriv.h>
 
 namespace android {
 namespace uirenderer {
@@ -79,14 +78,13 @@
 
 class CommonPoolExecutor : public SkExecutor {
 public:
-    virtual void add(std::function<void(void)> func) override {
-        CommonPool::post(std::move(func));
-    }
+    virtual void add(std::function<void(void)> func) override { CommonPool::post(std::move(func)); }
 };
 
 static CommonPoolExecutor sDefaultExecutor;
 
-void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, ssize_t size) {
+void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity,
+                                    ssize_t size) {
     contextOptions->fAllowPathMaskCaching = true;
 
     // This sets the maximum size for a single texture atlas in the GPU font cache.  If necessary,
@@ -180,7 +178,8 @@
         }
 
         const char* layerType = Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL
-                ? "GlLayer" : "VkLayer";
+                                        ? "GlLayer"
+                                        : "VkLayer";
         size_t layerMemoryTotal = 0;
         for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin();
              it != renderState->mActiveLayers.end(); it++) {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4808d68..1b3bd30 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -17,6 +17,7 @@
 #include "CanvasContext.h"
 #include <GpuMemoryTracker.h>
 
+#include "../Properties.h"
 #include "AnimationContext.h"
 #include "EglManager.h"
 #include "Frame.h"
@@ -31,7 +32,6 @@
 #include "utils/GLUtils.h"
 #include "utils/TimeUtils.h"
 #include "utils/TraceUtils.h"
-#include "../Properties.h"
 
 #include <cutils/properties.h>
 #include <private/hwui/DrawGlInfo.h>
@@ -153,7 +153,8 @@
     }
 
     ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
-    bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode);
+    bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode,
+                                                  mRenderAheadDepth);
 
     mFrameNumber = -1;
 
@@ -298,7 +299,7 @@
 
     mAnimationContext->startFrame(info.mode);
     mRenderPipeline->onPrepareTree();
-    for (const sp<RenderNode> &node : mRenderNodes) {
+    for (const sp<RenderNode>& node : mRenderNodes) {
         // Only the primary target node will be drawn full - all other nodes would get drawn in
         // real time mode. In case of a window, the primary node is the window content and the other
         // node(s) are non client / filler nodes.
@@ -322,7 +323,7 @@
 
     if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) {
         nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
-        SwapHistory &lastSwap = mSwapHistory.back();
+        SwapHistory& lastSwap = mSwapHistory.back();
         nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
         // The slight fudge-factor is to deal with cases where
         // the vsync was estimated due to being slow handling the signal.
@@ -405,8 +406,7 @@
     SkRect dirty;
     mDamageAccumulator.finish(&dirty);
 
-    if (dirty.isEmpty() && Properties::skipEmptyFrames
-            && !surfaceRequiresRedraw()) {
+    if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) {
         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
         return;
     }
@@ -416,21 +416,21 @@
     Frame frame = mRenderPipeline->getFrame();
 
     SkRect windowDirty = computeDirtyRect(frame, &dirty);
+    if (mRenderAheadDepth) {
+        auto presentTime =
+                mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
+                (mRenderThread.timeLord().frameIntervalNanos() * (mRenderAheadDepth + 1));
+        native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
+    }
 
     bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
-                                      mContentDrawBounds, mOpaque, mLightInfo,
-                                      mRenderNodes, &(profiler()));
+                                      mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes,
+                                      &(profiler()));
 
     int64_t frameCompleteNr = mFrameCompleteCallbacks.size() ? getFrameNumber() : -1;
 
     waitOnFences();
 
-    if (mRenderAheadDepth) {
-        auto presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
-                (mRenderThread.timeLord().frameIntervalNanos() * (mRenderAheadDepth + 1));
-        native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
-    }
-
     bool requireSwap = false;
     bool didSwap =
             mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);
@@ -645,21 +645,13 @@
 }
 
 void CanvasContext::applyRenderAheadSettings() {
-    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
-        // TODO: Fix SkiaVulkan's assumptions on buffer counts. And SIGBUS crashes.
-        mRenderAheadDepth = 0;
-        return;
-    }
-    if (mNativeSurface) {
-        native_window_set_buffer_count(mNativeSurface.get(), 3 + mRenderAheadDepth);
-        if (!mRenderAheadDepth) {
-            native_window_set_buffers_timestamp(mNativeSurface.get(), NATIVE_WINDOW_TIMESTAMP_AUTO);
-        }
+    if (mNativeSurface && !mRenderAheadDepth) {
+        native_window_set_buffers_timestamp(mNativeSurface.get(), NATIVE_WINDOW_TIMESTAMP_AUTO);
     }
 }
 
-void CanvasContext::setRenderAheadDepth(int renderAhead) {
-    if (renderAhead < 0 || renderAhead > 2 || renderAhead == mRenderAheadDepth) {
+void CanvasContext::setRenderAheadDepth(uint32_t renderAhead) {
+    if (renderAhead > 2 || renderAhead == mRenderAheadDepth || mNativeSurface) {
         return;
     }
     mRenderAheadDepth = renderAhead;
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 4a3119a..0bd080d 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -17,15 +17,15 @@
 #pragma once
 
 #include "DamageAccumulator.h"
-#include "Lighting.h"
 #include "FrameInfo.h"
 #include "FrameInfoVisualizer.h"
 #include "FrameMetricsReporter.h"
 #include "IContextFactory.h"
 #include "IRenderPipeline.h"
 #include "LayerUpdateQueue.h"
-#include "RenderNode.h"
+#include "Lighting.h"
 #include "ReliableSurface.h"
+#include "RenderNode.h"
 #include "renderthread/RenderTask.h"
 #include "renderthread/RenderThread.h"
 
@@ -37,10 +37,10 @@
 #include <utils/Functor.h>
 
 #include <functional>
+#include <future>
 #include <set>
 #include <string>
 #include <vector>
-#include <future>
 
 namespace android {
 namespace uirenderer {
@@ -187,9 +187,7 @@
         mRenderPipeline->setPictureCapturedCallback(callback);
     }
 
-    void setForceDark(bool enable) {
-        mUseForceDark = enable;
-    }
+    void setForceDark(bool enable) { mUseForceDark = enable; }
 
     bool useForceDark() {
         // The force-dark override has the highest priority, followed by the disable setting
@@ -204,7 +202,8 @@
         return mUseForceDark;
     }
 
-    void setRenderAheadDepth(int renderAhead);
+    // Must be called before setSurface
+    void setRenderAheadDepth(uint32_t renderAhead);
 
 private:
     CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
@@ -238,7 +237,7 @@
     // painted onto its surface.
     bool mIsDirty = false;
     SwapBehavior mSwapBehavior = SwapBehavior::kSwap_default;
-    int mRenderAheadDepth = 0;
+    uint32_t mRenderAheadDepth = 0;
     struct SwapHistory {
         SkRect damage;
         nsecs_t vsyncTime;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 51eeab7..91dc3bc 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -109,9 +109,8 @@
 
     // Even if we aren't drawing this vsync pulse the next frame number will still be accurate
     if (CC_UNLIKELY(callback)) {
-        context->enqueueFrameWork([callback, frameNr = context->getFrameNumber()]() {
-            callback(frameNr);
-        });
+        context->enqueueFrameWork(
+                [callback, frameNr = context->getFrameNumber()]() { callback(frameNr); });
     }
 
     if (CC_LIKELY(canDrawThisFrame)) {
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 2cc3f36..1d55334 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -29,10 +29,10 @@
 #include <EGL/eglext.h>
 #include <GLES/gl.h>
 
+#include <gui/Surface.h>
+#include <system/window.h>
 #include <string>
 #include <vector>
-#include <system/window.h>
-#include <gui/Surface.h>
 
 #define GLES_VERSION 2
 
@@ -171,8 +171,7 @@
                         EGL_NONE};
     EGLConfig config = EGL_NO_CONFIG_KHR;
     EGLint numConfigs = 1;
-    if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) ||
-        numConfigs != 1) {
+    if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) {
         return EGL_NO_CONFIG_KHR;
     }
     return config;
@@ -203,8 +202,7 @@
                         EGL_NONE};
     EGLConfig config = EGL_NO_CONFIG_KHR;
     EGLint numConfigs = 1;
-    if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) ||
-        numConfigs != 1) {
+    if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) {
         return EGL_NO_CONFIG_KHR;
     }
     return config;
@@ -262,7 +260,7 @@
         mEglConfigWideGamut = loadFP16Config(mEglDisplay, mSwapBehavior);
         if (mEglConfigWideGamut == EGL_NO_CONFIG_KHR) {
             ALOGE("Device claims wide gamut support, cannot find matching config, error = %s",
-                    eglErrorString());
+                  eglErrorString());
             EglExtensions.pixelFormatFloat = false;
         }
     } else if (wideColorType == SkColorType::kN32_SkColorType) {
@@ -350,7 +348,7 @@
     EGLSurface surface = eglCreateWindowSurface(
             mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs);
     if (surface == EGL_NO_SURFACE) {
-        return Error<EGLint> { eglGetError() };
+        return Error<EGLint>{eglGetError()};
     }
 
     if (mSwapBehavior != SwapBehavior::Preserved) {
@@ -525,12 +523,8 @@
             ALOGE("EglManager::fenceWait: error dup'ing fence fd: %d", errno);
             return -errno;
         }
-        EGLint attribs[] = {
-            EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
-            EGL_NONE
-        };
-        EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay,
-                EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+        EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
+        EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
         if (sync == EGL_NO_SYNC_KHR) {
             close(fenceFd);
             ALOGE("EglManager::fenceWait: error creating EGL fence: %#x", eglGetError());
@@ -559,18 +553,16 @@
 }
 
 status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence,
-        sp<Fence>& nativeFence) {
+                                        sp<Fence>& nativeFence) {
     if (!hasEglContext()) {
         ALOGE("EglManager::createReleaseFence: EGLDisplay not initialized");
         return INVALID_OPERATION;
     }
 
     if (SyncFeatures::getInstance().useNativeFenceSync()) {
-        EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay,
-                EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+        EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
         if (sync == EGL_NO_SYNC_KHR) {
-            ALOGE("EglManager::createReleaseFence: error creating EGL fence: %#x",
-                    eglGetError());
+            ALOGE("EglManager::createReleaseFence: error creating EGL fence: %#x", eglGetError());
             return UNKNOWN_ERROR;
         }
         glFlush();
@@ -578,7 +570,8 @@
         eglDestroySyncKHR(mEglDisplay, sync);
         if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
             ALOGE("EglManager::createReleaseFence: error dup'ing native fence "
-                    "fd: %#x", eglGetError());
+                  "fd: %#x",
+                  eglGetError());
             return UNKNOWN_ERROR;
         }
         nativeFence = new Fence(fenceFd);
@@ -592,7 +585,7 @@
             EGLint result = eglClientWaitSyncKHR(mEglDisplay, *eglFence, 0, 1000000000);
             if (result == EGL_FALSE) {
                 ALOGE("EglManager::createReleaseFence: error waiting for previous fence: %#x",
-                        eglGetError());
+                      eglGetError());
                 return UNKNOWN_ERROR;
             } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
                 ALOGE("EglManager::createReleaseFence: timeout waiting for previous fence");
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 0502eb8..3b81014 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -66,8 +66,8 @@
     virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
                              FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
     virtual DeferredLayerUpdater* createTextureLayer() = 0;
-    virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior,
-                            ColorMode colorMode) = 0;
+    virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode,
+                            uint32_t extraBuffers) = 0;
     virtual void onStop() = 0;
     virtual bool isSurfaceReady() = 0;
     virtual bool isContextReady() = 0;
diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp
index 6f2b9df..b9410c2 100644
--- a/libs/hwui/renderthread/ReliableSurface.cpp
+++ b/libs/hwui/renderthread/ReliableSurface.cpp
@@ -34,13 +34,13 @@
     // Make warnings happy
     SurfaceExposer() = delete;
 
-    using Surface::setBufferCount;
-    using Surface::setSwapInterval;
-    using Surface::dequeueBuffer;
-    using Surface::queueBuffer;
     using Surface::cancelBuffer;
+    using Surface::dequeueBuffer;
     using Surface::lockBuffer_DEPRECATED;
     using Surface::perform;
+    using Surface::queueBuffer;
+    using Surface::setBufferCount;
+    using Surface::setSwapInterval;
 };
 
 #define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__)
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index b58bab1..1a1b9da 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -84,7 +84,7 @@
 
 void RenderProxy::setSurface(const sp<Surface>& surface) {
     mRenderThread.queue().post(
-            [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
+            [this, surf = surface]() mutable { mContext->setSurface(std::move(surf)); });
 }
 
 void RenderProxy::allocateBuffers() {
@@ -251,7 +251,7 @@
 
 void RenderProxy::setProcessStatsBuffer(int fd) {
     auto& rt = RenderThread::getInstance();
-    rt.queue().post([&rt, fd = dup(fd) ]() {
+    rt.queue().post([&rt, fd = dup(fd)]() {
         rt.globalProfileData().switchStorageToAshmem(fd);
         close(fd);
     });
@@ -285,7 +285,7 @@
 void RenderProxy::setPictureCapturedCallback(
         const std::function<void(sk_sp<SkPicture>&&)>& callback) {
     mRenderThread.queue().post(
-            [ this, cb = callback ]() { mContext->setPictureCapturedCallback(cb); });
+            [this, cb = callback]() { mContext->setPictureCapturedCallback(cb); });
 }
 
 void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) {
@@ -297,13 +297,13 @@
 }
 
 void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
-    mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() {
+    mRenderThread.queue().post([this, observer = sp{observerPtr}]() {
         mContext->addFrameMetricsObserver(observer.get());
     });
 }
 
 void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
-    mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() {
+    mRenderThread.queue().post([this, observer = sp{observerPtr}]() {
         mContext->removeFrameMetricsObserver(observer.get());
     });
 }
@@ -313,9 +313,8 @@
 }
 
 void RenderProxy::setRenderAheadDepth(int renderAhead) {
-    mRenderThread.queue().post([ context = mContext, renderAhead ] {
-        context->setRenderAheadDepth(renderAhead);
-    });
+    mRenderThread.queue().post(
+            [context = mContext, renderAhead] { context->setRenderAheadDepth(renderAhead); });
 }
 
 int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
@@ -393,9 +392,7 @@
 void RenderProxy::preload() {
     // Create RenderThread object and start the thread. Then preload Vulkan/EGL driver.
     auto& thread = RenderThread::getInstance();
-    thread.queue().post([&thread]() {
-        thread.preload();
-    });
+    thread.queue().post([&thread]() { thread.preload(); });
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index b76e49c..eca7d88 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -16,6 +16,7 @@
 
 #include "RenderThread.h"
 
+#include "../HardwareBitmapUploader.h"
 #include "CanvasContext.h"
 #include "DeviceInfo.h"
 #include "EglManager.h"
@@ -29,7 +30,6 @@
 #include "utils/FatVector.h"
 #include "utils/TimeUtils.h"
 #include "utils/TraceUtils.h"
-#include "../HardwareBitmapUploader.h"
 
 #ifdef HWUI_GLES_WRAP_ENABLED
 #include "debug/GlesDriver.h"
@@ -410,9 +410,7 @@
 void RenderThread::preload() {
     // EGL driver is always preloaded only if HWUI renders with GL.
     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
-        std::thread eglInitThread([]() {
-            eglGetDisplay(EGL_DEFAULT_DISPLAY);
-        });
+        std::thread eglInitThread([]() { eglGetDisplay(EGL_DEFAULT_DISPLAY); });
         eglInitThread.detach();
     } else {
         requireVkContext();
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 5f43b48..6bb26fd 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -22,8 +22,8 @@
 #include "../JankTracker.h"
 #include "CacheManager.h"
 #include "TimeLord.h"
-#include "thread/ThreadBase.h"
 #include "WebViewFunctorManager.h"
+#include "thread/ThreadBase.h"
 #include "utils/TimeUtils.h"
 
 #include <GrContext.h>
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 4011329..5edf330 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -29,7 +29,6 @@
 #include <GrBackendSurface.h>
 #include <GrContext.h>
 #include <GrTypes.h>
-#include <GrTypes.h>
 #include <vk/GrVkExtensions.h>
 #include <vk/GrVkTypes.h>
 
@@ -43,7 +42,7 @@
     // so we can get access to the pNext for the next struct.
     struct CommonVulkanHeader {
         VkStructureType sType;
-        void*           pNext;
+        void* pNext;
     };
 
     void* pNext = features.pNext;
@@ -94,13 +93,13 @@
     VkResult err;
 
     constexpr VkApplicationInfo app_info = {
-        VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
-        nullptr,                            // pNext
-        "android framework",                // pApplicationName
-        0,                                  // applicationVersion
-        "android framework",                // pEngineName
-        0,                                  // engineVerison
-        mAPIVersion,                        // apiVersion
+            VK_STRUCTURE_TYPE_APPLICATION_INFO,  // sType
+            nullptr,                             // pNext
+            "android framework",                 // pApplicationName
+            0,                                   // applicationVersion
+            "android framework",                 // pEngineName
+            0,                                   // engineVerison
+            mAPIVersion,                         // apiVersion
     };
 
     {
@@ -128,14 +127,14 @@
     }
 
     const VkInstanceCreateInfo instance_create = {
-        VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,    // sType
-        nullptr,                                   // pNext
-        0,                                         // flags
-        &app_info,                                 // pApplicationInfo
-        0,                                         // enabledLayerNameCount
-        nullptr,                                   // ppEnabledLayerNames
-        (uint32_t) mInstanceExtensions.size(),     // enabledExtensionNameCount
-        mInstanceExtensions.data(),                // ppEnabledExtensionNames
+            VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,  // sType
+            nullptr,                                 // pNext
+            0,                                       // flags
+            &app_info,                               // pApplicationInfo
+            0,                                       // enabledLayerNameCount
+            nullptr,                                 // ppEnabledLayerNames
+            (uint32_t)mInstanceExtensions.size(),    // enabledExtensionNameCount
+            mInstanceExtensions.data(),              // ppEnabledExtensionNames
     };
 
     GET_PROC(CreateInstance);
@@ -200,11 +199,11 @@
     {
         uint32_t extensionCount = 0;
         err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount,
-                nullptr);
+                                                  nullptr);
         LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err);
         mDeviceExtensionsOwner.resize(extensionCount);
         err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount,
-                mDeviceExtensionsOwner.data());
+                                                  mDeviceExtensionsOwner.data());
         LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err);
         bool hasKHRSwapchainExtension = false;
         for (const VkExtensionProperties& extension : mDeviceExtensionsOwner) {
@@ -216,7 +215,7 @@
         LOG_ALWAYS_FATAL_IF(!hasKHRSwapchainExtension);
     }
 
-    auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) {
+    auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
         if (device != VK_NULL_HANDLE) {
             return vkGetDeviceProcAddr(device, proc_name);
         }
@@ -224,7 +223,8 @@
     };
 
     grExtensions.init(getProc, mInstance, mPhysicalDevice, mInstanceExtensions.size(),
-            mInstanceExtensions.data(), mDeviceExtensions.size(), mDeviceExtensions.data());
+                      mInstanceExtensions.data(), mDeviceExtensions.size(),
+                      mDeviceExtensions.data());
 
     LOG_ALWAYS_FATAL_IF(!grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1));
 
@@ -237,7 +237,7 @@
 
     if (grExtensions.hasExtension(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, 2)) {
         VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT* blend;
-        blend = (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT*) malloc(
+        blend = (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT*)malloc(
                 sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT));
         LOG_ALWAYS_FATAL_IF(!blend);
         blend->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT;
@@ -247,7 +247,7 @@
     }
 
     VkPhysicalDeviceSamplerYcbcrConversionFeatures* ycbcrFeature;
-    ycbcrFeature = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*) malloc(
+    ycbcrFeature = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*)malloc(
             sizeof(VkPhysicalDeviceSamplerYcbcrConversionFeatures));
     LOG_ALWAYS_FATAL_IF(!ycbcrFeature);
     ycbcrFeature->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
@@ -261,17 +261,17 @@
     // and we can't depend on it on all platforms
     features.features.robustBufferAccess = VK_FALSE;
 
-    float queuePriorities[1] = { 0.0 };
+    float queuePriorities[1] = {0.0};
 
     void* queueNextPtr = nullptr;
 
     VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo;
 
-    if (Properties::contextPriority != 0
-            && grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
+    if (Properties::contextPriority != 0 &&
+        grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
         memset(&queuePriorityCreateInfo, 0, sizeof(VkDeviceQueueGlobalPriorityCreateInfoEXT));
         queuePriorityCreateInfo.sType =
-            VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT;
+                VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT;
         queuePriorityCreateInfo.pNext = nullptr;
         switch (Properties::contextPriority) {
             case EGL_CONTEXT_PRIORITY_LOW_IMG:
@@ -285,41 +285,40 @@
                 break;
             default:
                 LOG_ALWAYS_FATAL("Unsupported context priority");
-         }
-         queueNextPtr = &queuePriorityCreateInfo;
+        }
+        queueNextPtr = &queuePriorityCreateInfo;
     }
 
     const VkDeviceQueueCreateInfo queueInfo[2] = {
-        {
-            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
-            queueNextPtr,                               // pNext
-            0,                                          // VkDeviceQueueCreateFlags
-            mGraphicsQueueIndex,                        // queueFamilyIndex
-            1,                                          // queueCount
-            queuePriorities,                            // pQueuePriorities
-        },
-        {
-            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
-            queueNextPtr,                               // pNext
-            0,                                          // VkDeviceQueueCreateFlags
-            mPresentQueueIndex,                         // queueFamilyIndex
-            1,                                          // queueCount
-            queuePriorities,                            // pQueuePriorities
-        }
-    };
+            {
+                    VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,  // sType
+                    queueNextPtr,                                // pNext
+                    0,                                           // VkDeviceQueueCreateFlags
+                    mGraphicsQueueIndex,                         // queueFamilyIndex
+                    1,                                           // queueCount
+                    queuePriorities,                             // pQueuePriorities
+            },
+            {
+                    VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,  // sType
+                    queueNextPtr,                                // pNext
+                    0,                                           // VkDeviceQueueCreateFlags
+                    mPresentQueueIndex,                          // queueFamilyIndex
+                    1,                                           // queueCount
+                    queuePriorities,                             // pQueuePriorities
+            }};
     uint32_t queueInfoCount = (mPresentQueueIndex != mGraphicsQueueIndex) ? 2 : 1;
 
     const VkDeviceCreateInfo deviceInfo = {
-        VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,    // sType
-        &features,                               // pNext
-        0,                                       // VkDeviceCreateFlags
-        queueInfoCount,                          // queueCreateInfoCount
-        queueInfo,                               // pQueueCreateInfos
-        0,                                       // layerCount
-        nullptr,                                 // ppEnabledLayerNames
-        (uint32_t) mDeviceExtensions.size(),     // extensionCount
-        mDeviceExtensions.data(),                // ppEnabledExtensionNames
-        nullptr,                                 // ppEnabledFeatures
+            VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,  // sType
+            &features,                             // pNext
+            0,                                     // VkDeviceCreateFlags
+            queueInfoCount,                        // queueCreateInfoCount
+            queueInfo,                             // pQueueCreateInfos
+            0,                                     // layerCount
+            nullptr,                               // ppEnabledLayerNames
+            (uint32_t)mDeviceExtensions.size(),    // extensionCount
+            mDeviceExtensions.data(),              // ppEnabledExtensionNames
+            nullptr,                               // ppEnabledFeatures
     };
 
     LOG_ALWAYS_FATAL_IF(mCreateDevice(mPhysicalDevice, &deviceInfo, nullptr, &mDevice));
@@ -371,8 +370,8 @@
         // this needs to be on the render queue
         commandPoolInfo.queueFamilyIndex = mGraphicsQueueIndex;
         commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
-        SkDEBUGCODE(VkResult res =) mCreateCommandPool(mDevice, &commandPoolInfo, nullptr,
-                &mCommandPool);
+        SkDEBUGCODE(VkResult res =)
+                mCreateCommandPool(mDevice, &commandPoolInfo, nullptr, &mCommandPool);
         SkASSERT(VK_SUCCESS == res);
     }
     LOG_ALWAYS_FATAL_IF(mCommandPool == VK_NULL_HANDLE);
@@ -391,7 +390,7 @@
 }
 
 sk_sp<GrContext> VulkanManager::createContext(const GrContextOptions& options) {
-    auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) {
+    auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
         if (device != VK_NULL_HANDLE) {
             return vkGetDeviceProcAddr(device, proc_name);
         }
@@ -431,7 +430,6 @@
 }
 
 Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) {
-
     VulkanSurface::NativeBufferInfo* bufferInfo = surface->dequeueNativeBuffer();
 
     if (bufferInfo == nullptr) {
@@ -480,7 +478,7 @@
                 bufferInfo->skSurface->wait(1, &backendSemaphore);
                 // The following flush blocks the GPU immediately instead of waiting for other
                 // drawing ops. It seems dequeue_fence is not respected otherwise.
-                //TODO: remove the flush after finding why backendSemaphore is not working.
+                // TODO: remove the flush after finding why backendSemaphore is not working.
                 bufferInfo->skSurface->flush();
             }
         }
@@ -557,15 +555,15 @@
 
 VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode,
                                             sk_sp<SkColorSpace> surfaceColorSpace,
-                                            SkColorType surfaceColorType,
-                                            GrContext* grContext) {
+                                            SkColorType surfaceColorType, GrContext* grContext,
+                                            uint32_t extraBuffers) {
     LOG_ALWAYS_FATAL_IF(!hasVkContext(), "Not initialized");
     if (!window) {
         return nullptr;
     }
 
     return VulkanSurface::Create(window, colorMode, surfaceColorType, surfaceColorSpace, grContext,
-                                  *this);
+                                 *this, extraBuffers);
 }
 
 bool VulkanManager::setupDummyCommandBuffer() {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index a7a43cc..1a3a0e4 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -18,16 +18,16 @@
 #define VULKANMANAGER_H
 
 #if !defined(VK_USE_PLATFORM_ANDROID_KHR)
-#  define VK_USE_PLATFORM_ANDROID_KHR
+#define VK_USE_PLATFORM_ANDROID_KHR
 #endif
 #include <vulkan/vulkan.h>
 
 #include <GrContextOptions.h>
-#include <vk/GrVkExtensions.h>
 #include <SkSurface.h>
 #include <ui/Fence.h>
 #include <utils/StrongPointer.h>
 #include <vk/GrVkBackendContext.h>
+#include <vk/GrVkExtensions.h>
 #include "Frame.h"
 #include "IRenderPipeline.h"
 #include "VulkanSurface.h"
@@ -59,8 +59,8 @@
     // Create and destroy functions for wrapping an ANativeWindow in a VulkanSurface
     VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode,
                                  sk_sp<SkColorSpace> surfaceColorSpace,
-                                 SkColorType surfaceColorType,
-                                 GrContext* grContext);
+                                 SkColorType surfaceColorType, GrContext* grContext,
+                                 uint32_t extraBuffers);
     void destroySurface(VulkanSurface* surface);
 
     Frame dequeueNextBuffer(VulkanSurface* surface);
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index be78b69..32815fe 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -16,12 +16,12 @@
 
 #include "VulkanSurface.h"
 
-#include <algorithm>
 #include <SkSurface.h>
+#include <algorithm>
 
 #include "VulkanManager.h"
-#include "utils/TraceUtils.h"
 #include "utils/Color.h"
+#include "utils/TraceUtils.h"
 
 namespace android {
 namespace uirenderer {
@@ -31,10 +31,9 @@
     // For now, only support pure rotations, not flip or flip-and-rotate, until we have
     // more time to test them and build sample code. As far as I know we never actually
     // use anything besides pure rotations anyway.
-    return transform == 0
-        || transform == NATIVE_WINDOW_TRANSFORM_ROT_90
-        || transform == NATIVE_WINDOW_TRANSFORM_ROT_180
-        || transform == NATIVE_WINDOW_TRANSFORM_ROT_270;
+    return transform == 0 || transform == NATIVE_WINDOW_TRANSFORM_ROT_90 ||
+           transform == NATIVE_WINDOW_TRANSFORM_ROT_180 ||
+           transform == NATIVE_WINDOW_TRANSFORM_ROT_270;
 }
 
 static int InvertTransform(int transform) {
@@ -85,16 +84,16 @@
 }
 
 void VulkanSurface::ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize,
-                                                   const SkISize& maxSize) {
+                                                  const SkISize& maxSize) {
     SkISize& windowSize = windowInfo->size;
 
     // clamp width & height to handle currentExtent of -1 and  protect us from broken hints
-    if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width()
-        || windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) {
+    if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width() ||
+        windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) {
         int width = std::min(maxSize.width(), std::max(minSize.width(), windowSize.width()));
         int height = std::min(maxSize.height(), std::max(minSize.height(), windowSize.height()));
-        ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]",
-              windowSize.width(), windowSize.height(), width, height);
+        ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]", windowSize.width(),
+              windowSize.height(), width, height);
         windowSize.set(width, height);
     }
 
@@ -145,12 +144,8 @@
 public:
     VkSurfaceAutoDeleter(VkInstance instance, VkSurfaceKHR surface,
                          PFN_vkDestroySurfaceKHR destroySurfaceKHR)
-            : mInstance(instance)
-            , mSurface(surface)
-            , mDestroySurfaceKHR(destroySurfaceKHR) {}
-    ~VkSurfaceAutoDeleter() {
-        destroy();
-    }
+            : mInstance(instance), mSurface(surface), mDestroySurfaceKHR(destroySurfaceKHR) {}
+    ~VkSurfaceAutoDeleter() { destroy(); }
 
     void destroy() {
         if (mSurface != VK_NULL_HANDLE) {
@@ -166,9 +161,9 @@
 };
 
 VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
-                                       SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
-                                       GrContext* grContext, const VulkanManager& vkManager) {
-
+                                     SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
+                                     GrContext* grContext, const VulkanManager& vkManager,
+                                     uint32_t extraBuffers) {
     VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
     memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
     surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
@@ -188,10 +183,11 @@
                                           vkManager.mDestroySurfaceKHR);
 
     SkDEBUGCODE(VkBool32 supported; res = vkManager.mGetPhysicalDeviceSurfaceSupportKHR(
-            vkManager.mPhysicalDevice, vkManager.mPresentQueueIndex, vkSurface, &supported);
-    // All physical devices and queue families on Android must be capable of
-    // presentation with any native window.
-    SkASSERT(VK_SUCCESS == res && supported););
+                                            vkManager.mPhysicalDevice, vkManager.mPresentQueueIndex,
+                                            vkSurface, &supported);
+                // All physical devices and queue families on Android must be capable of
+                // presentation with any native window.
+                SkASSERT(VK_SUCCESS == res && supported););
 
     // check for capabilities
     VkSurfaceCapabilitiesKHR caps;
@@ -225,14 +221,13 @@
     int query_value;
     int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
     if (err != 0 || query_value < 0) {
-        ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
-              query_value);
+        ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
         return nullptr;
     }
     auto min_undequeued_buffers = static_cast<uint32_t>(query_value);
 
-    windowInfo.bufferCount = min_undequeued_buffers
-            + std::max(VulkanSurface::sTargetBufferCount, caps.minImageCount);
+    windowInfo.bufferCount = min_undequeued_buffers +
+                             std::max(sTargetBufferCount + extraBuffers, caps.minImageCount);
     if (caps.maxImageCount > 0 && windowInfo.bufferCount > caps.maxImageCount) {
         // Application must settle for fewer images than desired:
         windowInfo.bufferCount = caps.maxImageCount;
@@ -241,8 +236,7 @@
     // Currently Skia requires the images to be color attachments and support all transfer
     // operations.
     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
-                                   VK_IMAGE_USAGE_SAMPLED_BIT |
-                                   VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+                                   VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
                                    VK_IMAGE_USAGE_TRANSFER_DST_BIT;
     LOG_ALWAYS_FATAL_IF((caps.supportedUsageFlags & usageFlags) != usageFlags);
 
@@ -336,7 +330,8 @@
     err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
     if (err != 0) {
         ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
-              "failed: %s (%d)", windowInfo.dataspace, strerror(-err), err);
+              "failed: %s (%d)",
+              windowInfo.dataspace, strerror(-err), err);
         return false;
     }
 
@@ -344,7 +339,8 @@
     err = native_window_set_buffers_dimensions(window, size.width(), size.height());
     if (err != 0) {
         ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_dimensions(%d,%d) "
-              "failed: %s (%d)", size.width(), size.height(), strerror(-err), err);
+              "failed: %s (%d)",
+              size.width(), size.height(), strerror(-err), err);
         return false;
     }
 
@@ -357,7 +353,8 @@
     err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
     if (err != 0) {
         ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
-              "failed: %s (%d)", windowInfo.transform, strerror(-err), err);
+              "failed: %s (%d)",
+              windowInfo.transform, strerror(-err), err);
         return false;
     }
 
@@ -366,7 +363,8 @@
     err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
     if (err != 0) {
         ALOGE("VulkanSurface::UpdateWindow() native_window_set_scaling_mode(SCALE_TO_WINDOW) "
-              "failed: %s (%d)", strerror(-err), err);
+              "failed: %s (%d)",
+              strerror(-err), err);
         return false;
     }
 
@@ -388,12 +386,12 @@
 }
 
 VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
-                               SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext)
+                             SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext)
         : mNativeWindow(window)
         , mWindowInfo(windowInfo)
         , mGrContext(grContext)
         , mMinWindowSize(minWindowSize)
-        , mMaxWindowSize(maxWindowSize) { }
+        , mMaxWindowSize(maxWindowSize) {}
 
 VulkanSurface::~VulkanSurface() {
     releaseBuffers();
@@ -436,8 +434,7 @@
     // value at the end of the function if everything dequeued correctly.
     mCurrentBufferInfo = nullptr;
 
-
-    //check if the native window has been resized or rotated and update accordingly
+    // check if the native window has been resized or rotated and update accordingly
     SkISize newSize = SkISize::MakeEmpty();
     int transformHint = 0;
     mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &newSize.fWidth);
@@ -457,8 +454,8 @@
                                                        newWindowInfo.actualSize.height());
             if (err != 0) {
                 ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
-                      newWindowInfo.actualSize.width(),
-                      newWindowInfo.actualSize.height(), strerror(-err), err);
+                      newWindowInfo.actualSize.width(), newWindowInfo.actualSize.height(),
+                      strerror(-err), err);
                 return nullptr;
             }
             // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
@@ -469,7 +466,7 @@
 
         if (newWindowInfo.transform != mWindowInfo.transform) {
             err = native_window_set_buffers_transform(mNativeWindow.get(),
-                    InvertTransform(newWindowInfo.transform));
+                                                      InvertTransform(newWindowInfo.transform));
             if (err != 0) {
                 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
                       newWindowInfo.transform, strerror(-err), err);
@@ -512,11 +509,9 @@
     VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
 
     if (bufferInfo->skSurface.get() == nullptr) {
-        bufferInfo->skSurface =
-                SkSurface::MakeFromAHardwareBuffer(mGrContext,
-                        ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
-                        kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace),
-                        nullptr);
+        bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer(
+                mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
+                kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace), nullptr);
         if (bufferInfo->skSurface.get() == nullptr) {
             ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
             mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index 305483f..b7af596 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -19,8 +19,8 @@
 #include <system/window.h>
 #include <vulkan/vulkan.h>
 
-#include <SkSize.h>
 #include <SkRefCnt.h>
+#include <SkSize.h>
 
 #include "IRenderPipeline.h"
 
@@ -34,12 +34,9 @@
 
 class VulkanSurface {
 public:
-    static VulkanSurface* Create(ANativeWindow* window,
-                                  ColorMode colorMode,
-                                  SkColorType colorType,
-                                  sk_sp<SkColorSpace> colorSpace,
-                                  GrContext* grContext,
-                                  const VulkanManager& vkManager);
+    static VulkanSurface* Create(ANativeWindow* window, ColorMode colorMode, SkColorType colorType,
+                                 sk_sp<SkColorSpace> colorSpace, GrContext* grContext,
+                                 const VulkanManager& vkManager, uint32_t extraBuffers);
     ~VulkanSurface();
 
     sk_sp<SkSurface> getCurrentSkSurface() {
@@ -104,15 +101,10 @@
         SkMatrix preTransform;
     };
 
-    VulkanSurface(ANativeWindow* window,
-                  const WindowInfo& windowInfo,
-                  SkISize minWindowSize,
-                  SkISize maxWindowSize,
-                  GrContext* grContext);
-    static bool UpdateWindow(ANativeWindow* window,
-                             const WindowInfo& windowInfo);
-    static void ComputeWindowSizeAndTransform(WindowInfo* windowInfo,
-                                              const SkISize& minSize,
+    VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, SkISize minWindowSize,
+                  SkISize maxWindowSize, GrContext* grContext);
+    static bool UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo);
+    static void ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize,
                                               const SkISize& maxSize);
     void releaseBuffers();
 
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index e86cf42..a671bda 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -31,6 +31,9 @@
 #include "renderthread/CanvasContext.h"
 #include "tests/common/TestUtils.h"
 
+#include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
+
 using namespace android;
 using namespace android::uirenderer;
 using namespace android::uirenderer::renderthread;
@@ -421,10 +424,20 @@
     EXPECT_EQ(1, surface->canvas()->mDrawCounter);
 }
 
+static sp<Surface> createDummySurface() {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    producer->setMaxDequeuedBufferCount(1);
+    producer->setAsyncMode(true);
+    return new Surface(producer);
+}
+
 RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) {
+    auto surface = createDummySurface();
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
     EXPECT_FALSE(pipeline->isSurfaceReady());
-    EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::SRGB));
+    EXPECT_TRUE(pipeline->setSurface(surface.get(), SwapBehavior::kSwap_default, ColorMode::SRGB, 0));
     EXPECT_TRUE(pipeline->isSurfaceReady());
     renderThread.destroyRenderingContext();
     EXPECT_FALSE(pipeline->isSurfaceReady());