Eliminate recents upload jank
am: 4387190d8e
Change-Id: I40fd49a61dde974c4215c4ccf9676f84cb3f43a7
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ public:
|
||||
ANDROID_API long getDroppedFrameReportCount();
|
||||
|
||||
ANDROID_API static int copySurfaceInto(sp<Surface>& surface, SkBitmap* bitmap);
|
||||
ANDROID_API static void prepareToDraw(const SkBitmap& bitmap);
|
||||
|
||||
private:
|
||||
RenderThread& mRenderThread;
|
||||
|
||||
@@ -200,6 +200,10 @@ class BackgroundTaskLoader implements Runnable {
|
||||
|
||||
if (cachedThumbnailData.thumbnail == null) {
|
||||
cachedThumbnailData.thumbnail = mDefaultThumbnail;
|
||||
} else {
|
||||
// Kick off an early upload of the bitmap to GL so
|
||||
// that this won't jank the first frame it's drawn in.
|
||||
cachedThumbnailData.thumbnail.prepareToDraw();
|
||||
}
|
||||
|
||||
// When svelte, we trim the memory to just the visible thumbnails when
|
||||
|
||||
@@ -164,6 +164,7 @@ public class TaskViewThumbnail extends View {
|
||||
/** Sets the thumbnail to a given bitmap. */
|
||||
void setThumbnail(Bitmap bm, ActivityManager.TaskThumbnailInfo thumbnailInfo) {
|
||||
if (bm != null) {
|
||||
bm.prepareToDraw();
|
||||
mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
||||
mDrawPaint.setShader(mBitmapShader);
|
||||
mThumbnailRect.set(0, 0, bm.getWidth(), bm.getHeight());
|
||||
|
||||
Reference in New Issue
Block a user