Start RenderThread earlier to preload Vulkan/EGL drivers
This CL should fix application startup regression for Vulkan
detected by "Hermetic Startup: EmptyActivity" test.
EGL drivers are loaded in a temp thread to leave more time
in RenderThread for other work. Loading EGL drivers
on the RenderThread may cause a perf regression.
Test: Ran cold-dropcache-test test.
Bug: 122659224
Bug: 123361175
Change-Id: I8ca818e98fac196a41d079be15594caca5cb1bab
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cc419b8..7908637 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3229,8 +3229,9 @@
TAG, "Handling launch of " + r);
// Initialize before creating the activity
- if (!ThreadedRenderer.sRendererDisabled) {
- GraphicsEnvironment.earlyInitEGL();
+ if (!ThreadedRenderer.sRendererDisabled
+ && (r.activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
+ HardwareRenderer.preload();
}
WindowManagerGlobal.initialize();
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index ec6da24..4a14ece 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -25,7 +25,6 @@
import android.content.pm.ResolveInfo;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
-import android.opengl.EGL14;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;
@@ -677,25 +676,6 @@
return true;
}
- /**
- * Start a background thread to initialize EGL.
- *
- * Initializing EGL involves loading and initializing the graphics driver. Some drivers take
- * several 10s of milliseconds to do this, so doing it on-demand when an app tries to render
- * its first frame adds directly to user-visible app launch latency. By starting it earlier
- * on a separate thread, it can usually be finished well before the UI is ready to be drawn.
- *
- * Should only be called after chooseDriver().
- */
- public static void earlyInitEGL() {
- final Thread eglInitThread = new Thread(
- () -> {
- EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
- },
- "EGL Init");
- eglInitThread.start();
- }
-
private static String chooseAbi(ApplicationInfo ai) {
final String isa = VMRuntime.getCurrentInstructionSet();
if (ai.primaryCpuAbi != null &&
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 2aa5cb4..ecc2dd0 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -1029,6 +1029,10 @@
proxy->setForceDark(enable);
}
+static void android_view_ThreadedRenderer_preload(JNIEnv*, jclass) {
+ RenderProxy::preload();
+}
+
// ----------------------------------------------------------------------------
// FrameMetricsObserver
// ----------------------------------------------------------------------------
@@ -1144,6 +1148,7 @@
{ "nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority },
{ "nAllocateBuffers", "(J)V", (void*)android_view_ThreadedRenderer_allocateBuffers },
{ "nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark },
+ { "preload", "()V", (void*)android_view_ThreadedRenderer_preload },
};
static JavaVM* mJvm = nullptr;
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 99d8c1b..b020556 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -1027,6 +1027,18 @@
*/
public static native void disableVsync();
+ /**
+ * Start render thread and initialize EGL or Vulkan.
+ *
+ * Initializing EGL involves loading and initializing the graphics driver. Some drivers take
+ * several 10s of milliseconds to do this, so doing it on-demand when an app tries to render
+ * its first frame adds directly to user-visible app launch latency.
+ *
+ * Should only be called after GraphicsEnvironment.chooseDriver().
+ * @hide
+ */
+ public static native void preload();
+
/** @hide */
protected static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile);
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 720c603..34f76d9 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -381,6 +381,14 @@
});
}
+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();
+ });
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 6e1bfd7..a1a5551 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -131,6 +131,8 @@
ANDROID_API static void disableVsync();
+ ANDROID_API static void preload();
+
static void repackVectorDrawableAtlas();
static void releaseVDAtlasEntries();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index bfae80f..08edd20 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -41,6 +41,7 @@
#include <utils/Condition.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
+#include <thread>
namespace android {
namespace uirenderer {
@@ -175,9 +176,6 @@
mRenderState = new RenderState(*this);
mVkManager = new VulkanManager();
mCacheManager = new CacheManager(mDisplayInfo);
- if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- requireVkContext();
- }
}
void RenderThread::requireGlContext() {
@@ -409,6 +407,17 @@
return gettid() == getInstance().getTid();
}
+void RenderThread::preload() {
+ std::thread eglInitThread([]() {
+ //TODO: don't load EGL drivers for Vulkan, when HW bitmap uploader is refactored.
+ eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ });
+ eglInitThread.detach();
+ if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+ requireVkContext();
+ }
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 419e7c7..329b4b9 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -115,6 +115,8 @@
void requireVkContext();
void destroyRenderingContext();
+ void preload();
+
/**
* isCurrent provides a way to query, if the caller is running on
* the render thread.
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 1e685ab..3b43f12 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -360,7 +360,7 @@
}
}
-sk_sp<GrContext> VulkanManager::createContext(GrContextOptions options) {
+sk_sp<GrContext> VulkanManager::createContext(const GrContextOptions& options) {
auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) {
if (device != VK_NULL_HANDLE) {
return vkGetDeviceProcAddr(device, proc_name);
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 9763686..95c9630 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -150,7 +150,7 @@
// Returned pointers are owned by VulkanManager.
VkFunctorInitParams getVkFunctorInitParams() const;
- sk_sp<GrContext> createContext(GrContextOptions options);
+ sk_sp<GrContext> createContext(const GrContextOptions& options);
private:
// Sets up the VkInstance and VkDevice objects. Also fills out the passed in