Eliminate recents upload jank

Bug: 30342017

Upload recents thumbnails in the
dead gaps between frames instead of
at the start of a frame. This eliminates
jank caused by the large texture
upload.

Change-Id: I507cd286d199109c7a9a1511d68ba5ab5d28069f
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 06a24b2..fb1c896 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -22,9 +22,11 @@
 #include "Readback.h"
 #include "Rect.h"
 #include "renderthread/CanvasContext.h"
+#include "renderthread/EglManager.h"
 #include "renderthread/RenderTask.h"
 #include "renderthread/RenderThread.h"
 #include "utils/Macros.h"
+#include "utils/TimeUtils.h"
 
 namespace android {
 namespace uirenderer {
@@ -44,6 +46,8 @@
     typedef struct { \
         a1; a2; a3; a4; a5; a6; a7; a8; \
     } ARGS(name); \
+    static_assert(std::is_trivially_destructible<ARGS(name)>::value, \
+            "Error, ARGS must be trivially destructible!"); \
     static void* Bridge_ ## name(ARGS(name)* args)
 
 #define SETUP_TASK(method) \
@@ -636,6 +640,41 @@
             reinterpret_cast<intptr_t>( staticPostAndWait(task) ));
 }
 
+CREATE_BRIDGE2(prepareToDraw, RenderThread* thread, SkBitmap* bitmap) {
+    if (Caches::hasInstance() && args->thread->eglManager().hasEglContext()) {
+        ATRACE_NAME("Bitmap#prepareToDraw task");
+        Caches::getInstance().textureCache.prefetch(args->bitmap);
+    }
+    delete args->bitmap;
+    args->bitmap = nullptr;
+    return nullptr;
+}
+
+void RenderProxy::prepareToDraw(const SkBitmap& bitmap) {
+    // If we haven't spun up a hardware accelerated window yet, there's no
+    // point in precaching these bitmaps as it can't impact jank.
+    // We also don't know if we even will spin up a hardware-accelerated
+    // window or not.
+    if (!RenderThread::hasInstance()) return;
+    RenderThread* renderThread = &RenderThread::getInstance();
+    SETUP_TASK(prepareToDraw);
+    args->thread = renderThread;
+    args->bitmap = new SkBitmap(bitmap);
+    nsecs_t lastVsync = renderThread->timeLord().latestVsync();
+    nsecs_t estimatedNextVsync = lastVsync + renderThread->timeLord().frameIntervalNanos();
+    nsecs_t timeToNextVsync = estimatedNextVsync - systemTime(CLOCK_MONOTONIC);
+    // We expect the UI thread to take 4ms and for RT to be active from VSYNC+4ms to
+    // VSYNC+12ms or so, so aim for the gap during which RT is expected to
+    // be idle
+    // TODO: Make this concept a first-class supported thing? RT could use
+    // knowledge of pending draws to better schedule this task
+    if (timeToNextVsync > -6_ms && timeToNextVsync < 1_ms) {
+        renderThread->queueAt(task, estimatedNextVsync + 8_ms);
+    } else {
+        renderThread->queue(task);
+    }
+}
+
 void RenderProxy::post(RenderTask* task) {
     mRenderThread.queue(task);
 }