Loading core/jni/android/graphics/Bitmap.cpp +10 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "CreateJavaOutputStreamAdaptor.h" #include <Caches.h> #include <hwui/Paint.h> #include <renderthread/RenderProxy.h> #include "core_jni_helpers.h" Loading Loading @@ -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[] = { Loading Loading @@ -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) Loading graphics/java/android/graphics/Bitmap.java +4 −3 Original line number Diff line number Diff line Loading @@ -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); } /** Loading Loading @@ -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); } libs/hwui/TextureCache.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -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); Loading libs/hwui/TextureCache.h +7 −0 Original line number Diff line number Diff line Loading @@ -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. Loading libs/hwui/renderthread/RenderProxy.cpp +39 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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) \ Loading Loading @@ -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 Loading
core/jni/android/graphics/Bitmap.cpp +10 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "CreateJavaOutputStreamAdaptor.h" #include <Caches.h> #include <hwui/Paint.h> #include <renderthread/RenderProxy.h> #include "core_jni_helpers.h" Loading Loading @@ -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[] = { Loading Loading @@ -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) Loading
graphics/java/android/graphics/Bitmap.java +4 −3 Original line number Diff line number Diff line Loading @@ -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); } /** Loading Loading @@ -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); }
libs/hwui/TextureCache.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
libs/hwui/TextureCache.h +7 −0 Original line number Diff line number Diff line Loading @@ -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. Loading
libs/hwui/renderthread/RenderProxy.cpp +39 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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) \ Loading Loading @@ -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