Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4387190d authored by John Reck's avatar John Reck
Browse files

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
parent fbd93027
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include "CreateJavaOutputStreamAdaptor.h"
#include <Caches.h>
#include <hwui/Paint.h>
#include <renderthread/RenderProxy.h>

#include "core_jni_helpers.h"

@@ -1361,6 +1362,14 @@ static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) {
    return reinterpret_cast<jlong>(pixelRef);
}

static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
    LocalScopedBitmap bitmapHandle(bitmapPtr);
    if (!bitmapHandle.valid()) return;
    SkBitmap bitmap;
    bitmapHandle->getSkBitmap(&bitmap);
    android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmap);
}

///////////////////////////////////////////////////////////////////////////////

static const JNINativeMethod gBitmapMethods[] = {
@@ -1404,6 +1413,7 @@ static const JNINativeMethod gBitmapMethods[] = {
                                            (void*)Bitmap_copyPixelsFromBuffer },
    {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
    {   "nativeRefPixelRef",        "(J)J", (void*)Bitmap_refPixelRef },
    {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
};

int register_android_graphics_Bitmap(JNIEnv* env)
+4 −3
Original line number Diff line number Diff line
@@ -1667,10 +1667,10 @@ public final class Bitmap implements Parcelable {
     * and therefore is harmless.
     */
    public void prepareToDraw() {
        // TODO: Consider having this start an async upload?
        // With inPurgeable no-op'd there's currently no use for this
        // method, but it could have interesting future uses.
        checkRecycled("Can't prepareToDraw on a recycled bitmap!");
        // Kick off an update/upload of the bitmap outside of the normal
        // draw path.
        nativePrepareToDraw(mNativePtr);
    }

    /**
@@ -1741,4 +1741,5 @@ public final class Bitmap implements Parcelable {
    private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
    private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
    private static native long nativeRefPixelRef(long nativeBitmap);
    private static native void nativePrepareToDraw(long nativeBitmap);
}
+4 −0
Original line number Diff line number Diff line
@@ -167,6 +167,10 @@ bool TextureCache::prefetchAndMarkInUse(void* ownerToken, const SkBitmap* bitmap
    return texture;
}

bool TextureCache::prefetch(const SkBitmap* bitmap) {
    return getCachedTexture(bitmap, AtlasUsageType::Use);
}

Texture* TextureCache::get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType) {
    Texture* texture = getCachedTexture(bitmap, atlasUsageType);

+7 −0
Original line number Diff line number Diff line
@@ -77,6 +77,13 @@ public:
     */
    bool prefetchAndMarkInUse(void* ownerToken, const SkBitmap* bitmap);

    /**
     * Attempts to precache the SkBitmap. Returns true if a Texture was successfully
     * acquired for the bitmap, false otherwise. Does not mark the Texture
     * as in use and won't update currently in-use Textures.
     */
    bool prefetch(const SkBitmap* bitmap);

    /**
     * Returns the texture associated with the specified bitmap from either within the cache, or
     * the AssetAtlas. If the texture cannot be found in the cache, a new texture is generated.
+39 −0
Original line number Diff line number Diff line
@@ -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 @@ namespace renderthread {
    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 @@ int RenderProxy::copySurfaceInto(sp<Surface>& surface, SkBitmap* bitmap) {
            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);
}
Loading