Loading core/java/android/app/ActivityThread.java +3 −0 Original line number Diff line number Diff line Loading @@ -6403,6 +6403,9 @@ public final class ActivityThread extends ClientTransactionHandler { HardwareRenderer.setDebuggingEnabled(isAppDebuggable || Build.IS_DEBUGGABLE); HardwareRenderer.setPackageName(data.appInfo.packageName); // Pass the current context to HardwareRenderer HardwareRenderer.setContextForInit(getSystemContext()); /** * Initialize the default http proxy in this process for the reasons we set the time zone. */ Loading graphics/java/android/graphics/HardwareRenderer.java +112 −0 Original line number Diff line number Diff line Loading @@ -22,13 +22,17 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.TimeUtils; import android.view.Display; import android.view.Display.Mode; import android.view.IGraphicsStats; import android.view.IGraphicsStatsCallback; import android.view.NativeVectorDrawableAnimator; Loading @@ -42,7 +46,10 @@ import java.io.File; import java.io.FileDescriptor; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Optional; import java.util.concurrent.Executor; import java.util.stream.Stream; import sun.misc.Cleaner; Loading Loading @@ -907,6 +914,7 @@ public class HardwareRenderer { */ public static void setIsolatedProcess(boolean isIsolated) { nSetIsolatedProcess(isIsolated); ProcessInitializer.sInstance.setIsolated(isIsolated); } /** Loading Loading @@ -991,6 +999,17 @@ public class HardwareRenderer { ProcessInitializer.sInstance.setPackageName(packageName); } /** * Gets a context for process initialization * * TODO: Remove this once there is a static method for retrieving an application's context. * * @hide */ public static void setContextForInit(Context context) { ProcessInitializer.sInstance.setContext(context); } private static final class DestroyContextRunnable implements Runnable { private final long mNativeInstance; Loading @@ -1007,8 +1026,34 @@ public class HardwareRenderer { private static class ProcessInitializer { static ProcessInitializer sInstance = new ProcessInitializer(); // Magic values from android/data_space.h private static final int INTERNAL_DATASPACE_SRGB = 142671872; private static final int INTERNAL_DATASPACE_DISPLAY_P3 = 143261696; private static final int INTERNAL_DATASPACE_SCRGB = 411107328; private enum Dataspace { DISPLAY_P3(ColorSpace.Named.DISPLAY_P3, INTERNAL_DATASPACE_DISPLAY_P3), SCRGB(ColorSpace.Named.EXTENDED_SRGB, INTERNAL_DATASPACE_SCRGB), SRGB(ColorSpace.Named.SRGB, INTERNAL_DATASPACE_SRGB); private final ColorSpace.Named mColorSpace; private final int mNativeDataspace; Dataspace(ColorSpace.Named colorSpace, int nativeDataspace) { this.mColorSpace = colorSpace; this.mNativeDataspace = nativeDataspace; } static Optional<Dataspace> find(ColorSpace colorSpace) { return Stream.of(Dataspace.values()) .filter(d -> ColorSpace.get(d.mColorSpace).equals(colorSpace)) .findFirst(); } } private boolean mInitialized = false; private boolean mIsolated = false; private Context mContext; private String mPackageName; private IGraphicsStats mGraphicsStatsService; private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() { Loading @@ -1026,12 +1071,23 @@ public class HardwareRenderer { mPackageName = name; } synchronized void setIsolated(boolean isolated) { if (mInitialized) return; mIsolated = isolated; } synchronized void setContext(Context context) { if (mInitialized) return; mContext = context; } synchronized void init(long renderProxy) { if (mInitialized) return; mInitialized = true; initSched(renderProxy); initGraphicsStats(); initDisplayInfo(); } private void initSched(long renderProxy) { Loading @@ -1056,6 +1112,58 @@ public class HardwareRenderer { } } private void initDisplayInfo() { if (mContext == null) return; // If we're in an isolated sandbox mode then we shouldn't try to communicate with DMS if (mIsolated) { // Defensively clear out the context in case we were passed a context that can leak // if we live longer than it, e.g. an activity context. mContext = null; return; } DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); if (dm == null) { Log.d(LOG_TAG, "Failed to find DisplayManager for display-based configuration"); return; } Display display = dm.getDisplay(Display.DEFAULT_DISPLAY); if (display == null) { Log.d(LOG_TAG, "Failed to find default display for display-based configuration"); return; } Dataspace wideColorDataspace = Optional.ofNullable(display.getPreferredWideGamutColorSpace()) .flatMap(Dataspace::find) // Default to SRGB if the display doesn't support wide color .orElse(Dataspace.SRGB); float maxRefreshRate = (float) Arrays.stream(display.getSupportedModes()) .mapToDouble(Mode::getRefreshRate) .max() .orElseGet(() -> { Log.i(LOG_TAG, "Failed to find the maximum display refresh rate"); // Assume that the max refresh rate is 60hz if we can't find one. return 60.0; }); // Grab the physical screen dimensions from the active display mode // Strictly speaking the screen resolution may not always be constant - it is for // sizing the font cache for the underlying rendering thread. Since it's a // heuristic we don't need to be always 100% correct. Mode activeMode = display.getMode(); nInitDisplayInfo(activeMode.getPhysicalWidth(), activeMode.getPhysicalHeight(), activeMode.getRefreshRate(), maxRefreshRate, wideColorDataspace.mNativeDataspace, display.getAppVsyncOffsetNanos(), display.getPresentationDeadlineNanos()); // Defensively clear out the context mContext = null; } private void rotateBuffer() { nRotateProcessStatsBuffer(); requestBuffer(); Loading Loading @@ -1207,4 +1315,8 @@ public class HardwareRenderer { private static native void nSetForceDark(long nativeProxy, boolean enabled); private static native void nSetDisplayDensityDpi(int densityDpi); private static native void nInitDisplayInfo(int width, int height, float refreshRate, float maxRefreshRate, int wideColorDataspace, long appVsyncOffsetNanos, long presentationDeadlineNanos); } libs/hwui/DeviceInfo.cpp +58 −70 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ #include <DeviceInfo.h> #include <android/hardware_buffer.h> #include <apex/display.h> #include <log/log.h> #include <utils/Errors.h> Loading @@ -34,88 +36,74 @@ DeviceInfo::DeviceInfo() { #else mMaxTextureSize = -1; #endif updateDisplayInfo(); } DeviceInfo::~DeviceInfo() { ADisplay_release(mDisplays); } int DeviceInfo::maxTextureSize() const { LOG_ALWAYS_FATAL_IF(mMaxTextureSize < 0, "MaxTextureSize has not been initialized yet."); return mMaxTextureSize; void DeviceInfo::updateDisplayInfo() { if (Properties::isolatedProcess) { return; } void DeviceInfo::setMaxTextureSize(int maxTextureSize) { DeviceInfo::get()->mMaxTextureSize = maxTextureSize; } ADisplay** displays; int size = ADisplay_acquirePhysicalDisplays(&displays); void DeviceInfo::onRefreshRateChanged(int64_t vsyncPeriod) { mVsyncPeriod = vsyncPeriod; if (size <= 0) { LOG_ALWAYS_FATAL("Failed to acquire physical displays for WCG support!"); } void DeviceInfo::updateDisplayInfo() { if (Properties::isolatedProcess) { for (int i = 0; i < size; ++i) { // Pick the first internal display for querying the display type // In practice this is controlled by a sysprop so it doesn't really // matter which display we use. if (ADisplay_getDisplayType(displays[i]) == DISPLAY_TYPE_INTERNAL) { // We get the dataspace from DisplayManager already. Allocate space // for the result here but we don't actually care about using it. ADataSpace dataspace; AHardwareBuffer_Format pixelFormat; ADisplay_getPreferredWideColorFormat(displays[i], &dataspace, &pixelFormat); if (pixelFormat == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM) { mWideColorType = SkColorType::kN32_SkColorType; } else if (pixelFormat == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT) { mWideColorType = SkColorType::kRGBA_F16_SkColorType; } else { LOG_ALWAYS_FATAL("Unreachable: unsupported pixel format: %d", pixelFormat); } ADisplay_release(displays); return; } if (mCurrentConfig == nullptr) { mDisplaysSize = ADisplay_acquirePhysicalDisplays(&mDisplays); LOG_ALWAYS_FATAL_IF(mDisplays == nullptr || mDisplaysSize <= 0, "Failed to get physical displays: no connected display: %d!", mDisplaysSize); for (size_t i = 0; i < mDisplaysSize; i++) { ADisplayType type = ADisplay_getDisplayType(mDisplays[i]); if (type == ADisplayType::DISPLAY_TYPE_INTERNAL) { mPhysicalDisplayIndex = i; break; } LOG_ALWAYS_FATAL("Failed to find a valid physical display for WCG support!"); } int DeviceInfo::maxTextureSize() const { LOG_ALWAYS_FATAL_IF(mMaxTextureSize < 0, "MaxTextureSize has not been initialized yet."); return mMaxTextureSize; } LOG_ALWAYS_FATAL_IF(mPhysicalDisplayIndex < 0, "Failed to find a connected physical display!"); void DeviceInfo::setMaxTextureSize(int maxTextureSize) { DeviceInfo::get()->mMaxTextureSize = maxTextureSize; } // Since we now just got the primary display for the first time, then // store the primary display metadata here. ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex]; mMaxRefreshRate = ADisplay_getMaxSupportedFps(primaryDisplay); ADataSpace dataspace; AHardwareBuffer_Format format; ADisplay_getPreferredWideColorFormat(primaryDisplay, &dataspace, &format); void DeviceInfo::setWideColorDataspace(ADataSpace dataspace) { switch (dataspace) { case ADATASPACE_DISPLAY_P3: mWideColorSpace = get()->mWideColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); break; case ADATASPACE_SCRGB: mWideColorSpace = SkColorSpace::MakeSRGB(); get()->mWideColorSpace = SkColorSpace::MakeSRGB(); break; case ADATASPACE_SRGB: // when sRGB is returned, it means wide color gamut is not supported. mWideColorSpace = SkColorSpace::MakeSRGB(); get()->mWideColorSpace = SkColorSpace::MakeSRGB(); break; default: LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space."); } switch (format) { case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: mWideColorType = SkColorType::kN32_SkColorType; break; case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: mWideColorType = SkColorType::kRGBA_F16_SkColorType; break; default: LOG_ALWAYS_FATAL("Unreachable: unsupported pixel format."); } } // This method may have been called when the display config changed, so // sync with the current configuration. ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex]; status_t status = ADisplay_getCurrentConfig(primaryDisplay, &mCurrentConfig); LOG_ALWAYS_FATAL_IF(status, "Failed to get display config, error %d", status); mWidth = ADisplayConfig_getWidth(mCurrentConfig); mHeight = ADisplayConfig_getHeight(mCurrentConfig); mVsyncPeriod = static_cast<int64_t>(1000000000 / ADisplayConfig_getFps(mCurrentConfig)); mCompositorOffset = ADisplayConfig_getCompositorOffsetNanos(mCurrentConfig); mAppOffset = ADisplayConfig_getAppVsyncOffsetNanos(mCurrentConfig); void DeviceInfo::onRefreshRateChanged(int64_t vsyncPeriod) { mVsyncPeriod = vsyncPeriod; } std::atomic<float> DeviceInfo::sDensity = 2.0; Loading libs/hwui/DeviceInfo.h +32 −9 Original line number Diff line number Diff line Loading @@ -16,8 +16,10 @@ #ifndef DEVICEINFO_H #define DEVICEINFO_H #include <apex/display.h> #include <SkImageInfo.h> #include <android/data_space.h> #include <mutex> #include "utils/Macros.h" Loading @@ -39,16 +41,34 @@ public: // Gets the density in density-independent pixels static float getDensity() { return sDensity.load(); } static int64_t getVsyncPeriod() { return get()->mVsyncPeriod; } static int64_t getCompositorOffset() { return get()->mCompositorOffset; } static int64_t getAppOffset() { return get()->mAppOffset; } static int64_t getCompositorOffset() { return get()->getCompositorOffsetInternal(); } static int64_t getAppOffset() { return get()->mAppVsyncOffsetNanos; } // Sets the density in density-independent pixels static void setDensity(float density) { sDensity.store(density); } static void setMaxRefreshRate(float refreshRate) { get()->mMaxRefreshRate = refreshRate; } static void setWidth(int32_t width) { get()->mWidth = width; } static void setHeight(int32_t height) { get()->mHeight = height; } static void setRefreshRate(float refreshRate) { get()->mVsyncPeriod = static_cast<int64_t>(1000000000 / refreshRate); } static void setPresentationDeadlineNanos(int64_t deadlineNanos) { get()->mPresentationDeadlineNanos = deadlineNanos; } static void setAppVsyncOffsetNanos(int64_t offsetNanos) { get()->mAppVsyncOffsetNanos = offsetNanos; } static void setWideColorDataspace(ADataSpace dataspace); // this value is only valid after the GPU has been initialized and there is a valid graphics // context or if you are using the HWUI_NULL_GPU int maxTextureSize() const; sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; } SkColorType getWideColorType() const { return mWideColorType; } SkColorType getWideColorType() { static std::once_flag kFlag; // lazily update display info from SF here, so that the call is performed by RenderThread. std::call_once(kFlag, [&, this]() { updateDisplayInfo(); }); return mWideColorType; } // This method should be called whenever the display refresh rate changes. void onRefreshRateChanged(int64_t vsyncPeriod); Loading @@ -57,23 +77,26 @@ private: friend class renderthread::RenderThread; static void setMaxTextureSize(int maxTextureSize); void updateDisplayInfo(); int64_t getCompositorOffsetInternal() const { // Assume that SF takes around a millisecond to latch buffers after // waking up return mVsyncPeriod - (mPresentationDeadlineNanos - 1000000); } DeviceInfo(); ~DeviceInfo(); ~DeviceInfo() = default; int mMaxTextureSize; sk_sp<SkColorSpace> mWideColorSpace = SkColorSpace::MakeSRGB(); SkColorType mWideColorType = SkColorType::kN32_SkColorType; ADisplayConfig* mCurrentConfig = nullptr; ADisplay** mDisplays = nullptr; int mDisplaysSize = 0; int mPhysicalDisplayIndex = -1; float mMaxRefreshRate = 60.0; int32_t mWidth = 1080; int32_t mHeight = 1920; int64_t mVsyncPeriod = 16666666; int64_t mCompositorOffset = 0; int64_t mAppOffset = 0; int64_t mPresentationDeadlineNanos = 0; int64_t mAppVsyncOffsetNanos = 0; // Density is not retrieved from the ADisplay apis, so this may potentially // be called on multiple threads. Loading libs/hwui/jni/android_graphics_HardwareRenderer.cpp +92 −62 Original line number Diff line number Diff line Loading @@ -600,6 +600,21 @@ static void android_view_ThreadedRenderer_setDisplayDensityDpi(JNIEnv*, jclass, DeviceInfo::setDensity(density); } static void android_view_ThreadedRenderer_initDisplayInfo(JNIEnv*, jclass, jint physicalWidth, jint physicalHeight, jfloat refreshRate, jfloat maxRefreshRate, jint wideColorDataspace, jlong appVsyncOffsetNanos, jlong presentationDeadlineNanos) { DeviceInfo::setWidth(physicalWidth); DeviceInfo::setHeight(physicalHeight); DeviceInfo::setRefreshRate(refreshRate); DeviceInfo::setMaxRefreshRate(maxRefreshRate); DeviceInfo::setWideColorDataspace(static_cast<ADataSpace>(wideColorDataspace)); DeviceInfo::setAppVsyncOffsetNanos(appVsyncOffsetNanos); DeviceInfo::setPresentationDeadlineNanos(presentationDeadlineNanos); } // ---------------------------------------------------------------------------- // HardwareRendererObserver // ---------------------------------------------------------------------------- Loading Loading @@ -644,15 +659,19 @@ static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, job const char* const kClassPathName = "android/graphics/HardwareRenderer"; static const JNINativeMethod gMethods[] = { { "nRotateProcessStatsBuffer", "()V", (void*) android_view_ThreadedRenderer_rotateProcessStatsBuffer }, { "nSetProcessStatsBuffer", "(I)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer }, {"nRotateProcessStatsBuffer", "()V", (void*)android_view_ThreadedRenderer_rotateProcessStatsBuffer}, {"nSetProcessStatsBuffer", "(I)V", (void*)android_view_ThreadedRenderer_setProcessStatsBuffer}, {"nGetRenderThreadTid", "(J)I", (void*)android_view_ThreadedRenderer_getRenderThreadTid}, {"nCreateRootRenderNode", "()J", (void*)android_view_ThreadedRenderer_createRootRenderNode}, {"nCreateProxy", "(ZZJ)J", (void*)android_view_ThreadedRenderer_createProxy}, {"nDeleteProxy", "(J)V", (void*)android_view_ThreadedRenderer_deleteProxy}, { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties }, {"nLoadSystemProperties", "(J)Z", (void*)android_view_ThreadedRenderer_loadSystemProperties}, {"nSetName", "(JLjava/lang/String;)V", (void*)android_view_ThreadedRenderer_setName}, { "nSetSurface", "(JLandroid/view/Surface;Z)V", (void*) android_view_ThreadedRenderer_setSurface }, {"nSetSurface", "(JLandroid/view/Surface;Z)V", (void*)android_view_ThreadedRenderer_setSurface}, {"nPause", "(J)Z", (void*)android_view_ThreadedRenderer_pause}, {"nSetStopped", "(JZ)V", (void*)android_view_ThreadedRenderer_setStopped}, {"nSetLightAlpha", "(JFF)V", (void*)android_view_ThreadedRenderer_setLightAlpha}, Loading @@ -661,33 +680,42 @@ static const JNINativeMethod gMethods[] = { {"nSetWideGamut", "(JZ)V", (void*)android_view_ThreadedRenderer_setWideGamut}, {"nSyncAndDrawFrame", "(J[JI)I", (void*)android_view_ThreadedRenderer_syncAndDrawFrame}, {"nDestroy", "(JJ)V", (void*)android_view_ThreadedRenderer_destroy}, { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode }, { "nRegisterVectorDrawableAnimator", "(JJ)V", (void*) android_view_ThreadedRenderer_registerVectorDrawableAnimator }, {"nRegisterAnimatingRenderNode", "(JJ)V", (void*)android_view_ThreadedRenderer_registerAnimatingRenderNode}, {"nRegisterVectorDrawableAnimator", "(JJ)V", (void*)android_view_ThreadedRenderer_registerVectorDrawableAnimator}, {"nInvokeFunctor", "(JZ)V", (void*)android_view_ThreadedRenderer_invokeFunctor}, {"nCreateTextureLayer", "(J)J", (void*)android_view_ThreadedRenderer_createTextureLayer}, {"nBuildLayer", "(JJ)V", (void*)android_view_ThreadedRenderer_buildLayer}, {"nCopyLayerInto", "(JJJ)Z", (void*)android_view_ThreadedRenderer_copyLayerInto}, {"nPushLayerUpdate", "(JJ)V", (void*)android_view_ThreadedRenderer_pushLayerUpdate}, {"nCancelLayerUpdate", "(JJ)V", (void*)android_view_ThreadedRenderer_cancelLayerUpdate}, { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture }, { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources }, {"nDetachSurfaceTexture", "(JJ)V", (void*)android_view_ThreadedRenderer_detachSurfaceTexture}, {"nDestroyHardwareResources", "(J)V", (void*)android_view_ThreadedRenderer_destroyHardwareResources}, {"nTrimMemory", "(I)V", (void*)android_view_ThreadedRenderer_trimMemory}, { "nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) android_view_ThreadedRenderer_overrideProperty }, {"nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V", (void*)android_view_ThreadedRenderer_overrideProperty}, {"nFence", "(J)V", (void*)android_view_ThreadedRenderer_fence}, {"nStopDrawing", "(J)V", (void*)android_view_ThreadedRenderer_stopDrawing}, {"nNotifyFramePending", "(J)V", (void*)android_view_ThreadedRenderer_notifyFramePending}, { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo }, {"nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*)android_view_ThreadedRenderer_dumpProfileInfo}, {"setupShadersDiskCache", "(Ljava/lang/String;Ljava/lang/String;)V", (void*)android_view_ThreadedRenderer_setupShadersDiskCache}, {"nAddRenderNode", "(JJZ)V", (void*)android_view_ThreadedRenderer_addRenderNode}, {"nRemoveRenderNode", "(JJ)V", (void*)android_view_ThreadedRenderer_removeRenderNode}, {"nDrawRenderNode", "(JJ)V", (void*)android_view_ThreadedRendererd_drawRenderNode}, { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds}, { "nSetPictureCaptureCallback", "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V", {"nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds}, {"nSetPictureCaptureCallback", "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V", (void*)android_view_ThreadedRenderer_setPictureCapturedCallbackJNI}, {"nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V", (void*)android_view_ThreadedRenderer_setFrameCallback}, { "nSetFrameCompleteCallback", "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V", {"nSetFrameCompleteCallback", "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V", (void*)android_view_ThreadedRenderer_setFrameCompleteCallback}, {"nAddObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_addObserver}, {"nRemoveObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_removeObserver}, Loading @@ -704,7 +732,9 @@ static const JNINativeMethod gMethods[] = { {"nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority}, {"nAllocateBuffers", "(J)V", (void*)android_view_ThreadedRenderer_allocateBuffers}, {"nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark}, { "nSetDisplayDensityDpi", "(I)V", (void*)android_view_ThreadedRenderer_setDisplayDensityDpi }, {"nSetDisplayDensityDpi", "(I)V", (void*)android_view_ThreadedRenderer_setDisplayDensityDpi}, {"nInitDisplayInfo", "(IIFFIJJ)V", (void*)android_view_ThreadedRenderer_initDisplayInfo}, {"preload", "()V", (void*)android_view_ThreadedRenderer_preload}, }; Loading Loading
core/java/android/app/ActivityThread.java +3 −0 Original line number Diff line number Diff line Loading @@ -6403,6 +6403,9 @@ public final class ActivityThread extends ClientTransactionHandler { HardwareRenderer.setDebuggingEnabled(isAppDebuggable || Build.IS_DEBUGGABLE); HardwareRenderer.setPackageName(data.appInfo.packageName); // Pass the current context to HardwareRenderer HardwareRenderer.setContextForInit(getSystemContext()); /** * Initialize the default http proxy in this process for the reasons we set the time zone. */ Loading
graphics/java/android/graphics/HardwareRenderer.java +112 −0 Original line number Diff line number Diff line Loading @@ -22,13 +22,17 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.TimeUtils; import android.view.Display; import android.view.Display.Mode; import android.view.IGraphicsStats; import android.view.IGraphicsStatsCallback; import android.view.NativeVectorDrawableAnimator; Loading @@ -42,7 +46,10 @@ import java.io.File; import java.io.FileDescriptor; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Optional; import java.util.concurrent.Executor; import java.util.stream.Stream; import sun.misc.Cleaner; Loading Loading @@ -907,6 +914,7 @@ public class HardwareRenderer { */ public static void setIsolatedProcess(boolean isIsolated) { nSetIsolatedProcess(isIsolated); ProcessInitializer.sInstance.setIsolated(isIsolated); } /** Loading Loading @@ -991,6 +999,17 @@ public class HardwareRenderer { ProcessInitializer.sInstance.setPackageName(packageName); } /** * Gets a context for process initialization * * TODO: Remove this once there is a static method for retrieving an application's context. * * @hide */ public static void setContextForInit(Context context) { ProcessInitializer.sInstance.setContext(context); } private static final class DestroyContextRunnable implements Runnable { private final long mNativeInstance; Loading @@ -1007,8 +1026,34 @@ public class HardwareRenderer { private static class ProcessInitializer { static ProcessInitializer sInstance = new ProcessInitializer(); // Magic values from android/data_space.h private static final int INTERNAL_DATASPACE_SRGB = 142671872; private static final int INTERNAL_DATASPACE_DISPLAY_P3 = 143261696; private static final int INTERNAL_DATASPACE_SCRGB = 411107328; private enum Dataspace { DISPLAY_P3(ColorSpace.Named.DISPLAY_P3, INTERNAL_DATASPACE_DISPLAY_P3), SCRGB(ColorSpace.Named.EXTENDED_SRGB, INTERNAL_DATASPACE_SCRGB), SRGB(ColorSpace.Named.SRGB, INTERNAL_DATASPACE_SRGB); private final ColorSpace.Named mColorSpace; private final int mNativeDataspace; Dataspace(ColorSpace.Named colorSpace, int nativeDataspace) { this.mColorSpace = colorSpace; this.mNativeDataspace = nativeDataspace; } static Optional<Dataspace> find(ColorSpace colorSpace) { return Stream.of(Dataspace.values()) .filter(d -> ColorSpace.get(d.mColorSpace).equals(colorSpace)) .findFirst(); } } private boolean mInitialized = false; private boolean mIsolated = false; private Context mContext; private String mPackageName; private IGraphicsStats mGraphicsStatsService; private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() { Loading @@ -1026,12 +1071,23 @@ public class HardwareRenderer { mPackageName = name; } synchronized void setIsolated(boolean isolated) { if (mInitialized) return; mIsolated = isolated; } synchronized void setContext(Context context) { if (mInitialized) return; mContext = context; } synchronized void init(long renderProxy) { if (mInitialized) return; mInitialized = true; initSched(renderProxy); initGraphicsStats(); initDisplayInfo(); } private void initSched(long renderProxy) { Loading @@ -1056,6 +1112,58 @@ public class HardwareRenderer { } } private void initDisplayInfo() { if (mContext == null) return; // If we're in an isolated sandbox mode then we shouldn't try to communicate with DMS if (mIsolated) { // Defensively clear out the context in case we were passed a context that can leak // if we live longer than it, e.g. an activity context. mContext = null; return; } DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); if (dm == null) { Log.d(LOG_TAG, "Failed to find DisplayManager for display-based configuration"); return; } Display display = dm.getDisplay(Display.DEFAULT_DISPLAY); if (display == null) { Log.d(LOG_TAG, "Failed to find default display for display-based configuration"); return; } Dataspace wideColorDataspace = Optional.ofNullable(display.getPreferredWideGamutColorSpace()) .flatMap(Dataspace::find) // Default to SRGB if the display doesn't support wide color .orElse(Dataspace.SRGB); float maxRefreshRate = (float) Arrays.stream(display.getSupportedModes()) .mapToDouble(Mode::getRefreshRate) .max() .orElseGet(() -> { Log.i(LOG_TAG, "Failed to find the maximum display refresh rate"); // Assume that the max refresh rate is 60hz if we can't find one. return 60.0; }); // Grab the physical screen dimensions from the active display mode // Strictly speaking the screen resolution may not always be constant - it is for // sizing the font cache for the underlying rendering thread. Since it's a // heuristic we don't need to be always 100% correct. Mode activeMode = display.getMode(); nInitDisplayInfo(activeMode.getPhysicalWidth(), activeMode.getPhysicalHeight(), activeMode.getRefreshRate(), maxRefreshRate, wideColorDataspace.mNativeDataspace, display.getAppVsyncOffsetNanos(), display.getPresentationDeadlineNanos()); // Defensively clear out the context mContext = null; } private void rotateBuffer() { nRotateProcessStatsBuffer(); requestBuffer(); Loading Loading @@ -1207,4 +1315,8 @@ public class HardwareRenderer { private static native void nSetForceDark(long nativeProxy, boolean enabled); private static native void nSetDisplayDensityDpi(int densityDpi); private static native void nInitDisplayInfo(int width, int height, float refreshRate, float maxRefreshRate, int wideColorDataspace, long appVsyncOffsetNanos, long presentationDeadlineNanos); }
libs/hwui/DeviceInfo.cpp +58 −70 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ #include <DeviceInfo.h> #include <android/hardware_buffer.h> #include <apex/display.h> #include <log/log.h> #include <utils/Errors.h> Loading @@ -34,88 +36,74 @@ DeviceInfo::DeviceInfo() { #else mMaxTextureSize = -1; #endif updateDisplayInfo(); } DeviceInfo::~DeviceInfo() { ADisplay_release(mDisplays); } int DeviceInfo::maxTextureSize() const { LOG_ALWAYS_FATAL_IF(mMaxTextureSize < 0, "MaxTextureSize has not been initialized yet."); return mMaxTextureSize; void DeviceInfo::updateDisplayInfo() { if (Properties::isolatedProcess) { return; } void DeviceInfo::setMaxTextureSize(int maxTextureSize) { DeviceInfo::get()->mMaxTextureSize = maxTextureSize; } ADisplay** displays; int size = ADisplay_acquirePhysicalDisplays(&displays); void DeviceInfo::onRefreshRateChanged(int64_t vsyncPeriod) { mVsyncPeriod = vsyncPeriod; if (size <= 0) { LOG_ALWAYS_FATAL("Failed to acquire physical displays for WCG support!"); } void DeviceInfo::updateDisplayInfo() { if (Properties::isolatedProcess) { for (int i = 0; i < size; ++i) { // Pick the first internal display for querying the display type // In practice this is controlled by a sysprop so it doesn't really // matter which display we use. if (ADisplay_getDisplayType(displays[i]) == DISPLAY_TYPE_INTERNAL) { // We get the dataspace from DisplayManager already. Allocate space // for the result here but we don't actually care about using it. ADataSpace dataspace; AHardwareBuffer_Format pixelFormat; ADisplay_getPreferredWideColorFormat(displays[i], &dataspace, &pixelFormat); if (pixelFormat == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM) { mWideColorType = SkColorType::kN32_SkColorType; } else if (pixelFormat == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT) { mWideColorType = SkColorType::kRGBA_F16_SkColorType; } else { LOG_ALWAYS_FATAL("Unreachable: unsupported pixel format: %d", pixelFormat); } ADisplay_release(displays); return; } if (mCurrentConfig == nullptr) { mDisplaysSize = ADisplay_acquirePhysicalDisplays(&mDisplays); LOG_ALWAYS_FATAL_IF(mDisplays == nullptr || mDisplaysSize <= 0, "Failed to get physical displays: no connected display: %d!", mDisplaysSize); for (size_t i = 0; i < mDisplaysSize; i++) { ADisplayType type = ADisplay_getDisplayType(mDisplays[i]); if (type == ADisplayType::DISPLAY_TYPE_INTERNAL) { mPhysicalDisplayIndex = i; break; } LOG_ALWAYS_FATAL("Failed to find a valid physical display for WCG support!"); } int DeviceInfo::maxTextureSize() const { LOG_ALWAYS_FATAL_IF(mMaxTextureSize < 0, "MaxTextureSize has not been initialized yet."); return mMaxTextureSize; } LOG_ALWAYS_FATAL_IF(mPhysicalDisplayIndex < 0, "Failed to find a connected physical display!"); void DeviceInfo::setMaxTextureSize(int maxTextureSize) { DeviceInfo::get()->mMaxTextureSize = maxTextureSize; } // Since we now just got the primary display for the first time, then // store the primary display metadata here. ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex]; mMaxRefreshRate = ADisplay_getMaxSupportedFps(primaryDisplay); ADataSpace dataspace; AHardwareBuffer_Format format; ADisplay_getPreferredWideColorFormat(primaryDisplay, &dataspace, &format); void DeviceInfo::setWideColorDataspace(ADataSpace dataspace) { switch (dataspace) { case ADATASPACE_DISPLAY_P3: mWideColorSpace = get()->mWideColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); break; case ADATASPACE_SCRGB: mWideColorSpace = SkColorSpace::MakeSRGB(); get()->mWideColorSpace = SkColorSpace::MakeSRGB(); break; case ADATASPACE_SRGB: // when sRGB is returned, it means wide color gamut is not supported. mWideColorSpace = SkColorSpace::MakeSRGB(); get()->mWideColorSpace = SkColorSpace::MakeSRGB(); break; default: LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space."); } switch (format) { case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: mWideColorType = SkColorType::kN32_SkColorType; break; case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: mWideColorType = SkColorType::kRGBA_F16_SkColorType; break; default: LOG_ALWAYS_FATAL("Unreachable: unsupported pixel format."); } } // This method may have been called when the display config changed, so // sync with the current configuration. ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex]; status_t status = ADisplay_getCurrentConfig(primaryDisplay, &mCurrentConfig); LOG_ALWAYS_FATAL_IF(status, "Failed to get display config, error %d", status); mWidth = ADisplayConfig_getWidth(mCurrentConfig); mHeight = ADisplayConfig_getHeight(mCurrentConfig); mVsyncPeriod = static_cast<int64_t>(1000000000 / ADisplayConfig_getFps(mCurrentConfig)); mCompositorOffset = ADisplayConfig_getCompositorOffsetNanos(mCurrentConfig); mAppOffset = ADisplayConfig_getAppVsyncOffsetNanos(mCurrentConfig); void DeviceInfo::onRefreshRateChanged(int64_t vsyncPeriod) { mVsyncPeriod = vsyncPeriod; } std::atomic<float> DeviceInfo::sDensity = 2.0; Loading
libs/hwui/DeviceInfo.h +32 −9 Original line number Diff line number Diff line Loading @@ -16,8 +16,10 @@ #ifndef DEVICEINFO_H #define DEVICEINFO_H #include <apex/display.h> #include <SkImageInfo.h> #include <android/data_space.h> #include <mutex> #include "utils/Macros.h" Loading @@ -39,16 +41,34 @@ public: // Gets the density in density-independent pixels static float getDensity() { return sDensity.load(); } static int64_t getVsyncPeriod() { return get()->mVsyncPeriod; } static int64_t getCompositorOffset() { return get()->mCompositorOffset; } static int64_t getAppOffset() { return get()->mAppOffset; } static int64_t getCompositorOffset() { return get()->getCompositorOffsetInternal(); } static int64_t getAppOffset() { return get()->mAppVsyncOffsetNanos; } // Sets the density in density-independent pixels static void setDensity(float density) { sDensity.store(density); } static void setMaxRefreshRate(float refreshRate) { get()->mMaxRefreshRate = refreshRate; } static void setWidth(int32_t width) { get()->mWidth = width; } static void setHeight(int32_t height) { get()->mHeight = height; } static void setRefreshRate(float refreshRate) { get()->mVsyncPeriod = static_cast<int64_t>(1000000000 / refreshRate); } static void setPresentationDeadlineNanos(int64_t deadlineNanos) { get()->mPresentationDeadlineNanos = deadlineNanos; } static void setAppVsyncOffsetNanos(int64_t offsetNanos) { get()->mAppVsyncOffsetNanos = offsetNanos; } static void setWideColorDataspace(ADataSpace dataspace); // this value is only valid after the GPU has been initialized and there is a valid graphics // context or if you are using the HWUI_NULL_GPU int maxTextureSize() const; sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; } SkColorType getWideColorType() const { return mWideColorType; } SkColorType getWideColorType() { static std::once_flag kFlag; // lazily update display info from SF here, so that the call is performed by RenderThread. std::call_once(kFlag, [&, this]() { updateDisplayInfo(); }); return mWideColorType; } // This method should be called whenever the display refresh rate changes. void onRefreshRateChanged(int64_t vsyncPeriod); Loading @@ -57,23 +77,26 @@ private: friend class renderthread::RenderThread; static void setMaxTextureSize(int maxTextureSize); void updateDisplayInfo(); int64_t getCompositorOffsetInternal() const { // Assume that SF takes around a millisecond to latch buffers after // waking up return mVsyncPeriod - (mPresentationDeadlineNanos - 1000000); } DeviceInfo(); ~DeviceInfo(); ~DeviceInfo() = default; int mMaxTextureSize; sk_sp<SkColorSpace> mWideColorSpace = SkColorSpace::MakeSRGB(); SkColorType mWideColorType = SkColorType::kN32_SkColorType; ADisplayConfig* mCurrentConfig = nullptr; ADisplay** mDisplays = nullptr; int mDisplaysSize = 0; int mPhysicalDisplayIndex = -1; float mMaxRefreshRate = 60.0; int32_t mWidth = 1080; int32_t mHeight = 1920; int64_t mVsyncPeriod = 16666666; int64_t mCompositorOffset = 0; int64_t mAppOffset = 0; int64_t mPresentationDeadlineNanos = 0; int64_t mAppVsyncOffsetNanos = 0; // Density is not retrieved from the ADisplay apis, so this may potentially // be called on multiple threads. Loading
libs/hwui/jni/android_graphics_HardwareRenderer.cpp +92 −62 Original line number Diff line number Diff line Loading @@ -600,6 +600,21 @@ static void android_view_ThreadedRenderer_setDisplayDensityDpi(JNIEnv*, jclass, DeviceInfo::setDensity(density); } static void android_view_ThreadedRenderer_initDisplayInfo(JNIEnv*, jclass, jint physicalWidth, jint physicalHeight, jfloat refreshRate, jfloat maxRefreshRate, jint wideColorDataspace, jlong appVsyncOffsetNanos, jlong presentationDeadlineNanos) { DeviceInfo::setWidth(physicalWidth); DeviceInfo::setHeight(physicalHeight); DeviceInfo::setRefreshRate(refreshRate); DeviceInfo::setMaxRefreshRate(maxRefreshRate); DeviceInfo::setWideColorDataspace(static_cast<ADataSpace>(wideColorDataspace)); DeviceInfo::setAppVsyncOffsetNanos(appVsyncOffsetNanos); DeviceInfo::setPresentationDeadlineNanos(presentationDeadlineNanos); } // ---------------------------------------------------------------------------- // HardwareRendererObserver // ---------------------------------------------------------------------------- Loading Loading @@ -644,15 +659,19 @@ static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, job const char* const kClassPathName = "android/graphics/HardwareRenderer"; static const JNINativeMethod gMethods[] = { { "nRotateProcessStatsBuffer", "()V", (void*) android_view_ThreadedRenderer_rotateProcessStatsBuffer }, { "nSetProcessStatsBuffer", "(I)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer }, {"nRotateProcessStatsBuffer", "()V", (void*)android_view_ThreadedRenderer_rotateProcessStatsBuffer}, {"nSetProcessStatsBuffer", "(I)V", (void*)android_view_ThreadedRenderer_setProcessStatsBuffer}, {"nGetRenderThreadTid", "(J)I", (void*)android_view_ThreadedRenderer_getRenderThreadTid}, {"nCreateRootRenderNode", "()J", (void*)android_view_ThreadedRenderer_createRootRenderNode}, {"nCreateProxy", "(ZZJ)J", (void*)android_view_ThreadedRenderer_createProxy}, {"nDeleteProxy", "(J)V", (void*)android_view_ThreadedRenderer_deleteProxy}, { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties }, {"nLoadSystemProperties", "(J)Z", (void*)android_view_ThreadedRenderer_loadSystemProperties}, {"nSetName", "(JLjava/lang/String;)V", (void*)android_view_ThreadedRenderer_setName}, { "nSetSurface", "(JLandroid/view/Surface;Z)V", (void*) android_view_ThreadedRenderer_setSurface }, {"nSetSurface", "(JLandroid/view/Surface;Z)V", (void*)android_view_ThreadedRenderer_setSurface}, {"nPause", "(J)Z", (void*)android_view_ThreadedRenderer_pause}, {"nSetStopped", "(JZ)V", (void*)android_view_ThreadedRenderer_setStopped}, {"nSetLightAlpha", "(JFF)V", (void*)android_view_ThreadedRenderer_setLightAlpha}, Loading @@ -661,33 +680,42 @@ static const JNINativeMethod gMethods[] = { {"nSetWideGamut", "(JZ)V", (void*)android_view_ThreadedRenderer_setWideGamut}, {"nSyncAndDrawFrame", "(J[JI)I", (void*)android_view_ThreadedRenderer_syncAndDrawFrame}, {"nDestroy", "(JJ)V", (void*)android_view_ThreadedRenderer_destroy}, { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode }, { "nRegisterVectorDrawableAnimator", "(JJ)V", (void*) android_view_ThreadedRenderer_registerVectorDrawableAnimator }, {"nRegisterAnimatingRenderNode", "(JJ)V", (void*)android_view_ThreadedRenderer_registerAnimatingRenderNode}, {"nRegisterVectorDrawableAnimator", "(JJ)V", (void*)android_view_ThreadedRenderer_registerVectorDrawableAnimator}, {"nInvokeFunctor", "(JZ)V", (void*)android_view_ThreadedRenderer_invokeFunctor}, {"nCreateTextureLayer", "(J)J", (void*)android_view_ThreadedRenderer_createTextureLayer}, {"nBuildLayer", "(JJ)V", (void*)android_view_ThreadedRenderer_buildLayer}, {"nCopyLayerInto", "(JJJ)Z", (void*)android_view_ThreadedRenderer_copyLayerInto}, {"nPushLayerUpdate", "(JJ)V", (void*)android_view_ThreadedRenderer_pushLayerUpdate}, {"nCancelLayerUpdate", "(JJ)V", (void*)android_view_ThreadedRenderer_cancelLayerUpdate}, { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture }, { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources }, {"nDetachSurfaceTexture", "(JJ)V", (void*)android_view_ThreadedRenderer_detachSurfaceTexture}, {"nDestroyHardwareResources", "(J)V", (void*)android_view_ThreadedRenderer_destroyHardwareResources}, {"nTrimMemory", "(I)V", (void*)android_view_ThreadedRenderer_trimMemory}, { "nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) android_view_ThreadedRenderer_overrideProperty }, {"nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V", (void*)android_view_ThreadedRenderer_overrideProperty}, {"nFence", "(J)V", (void*)android_view_ThreadedRenderer_fence}, {"nStopDrawing", "(J)V", (void*)android_view_ThreadedRenderer_stopDrawing}, {"nNotifyFramePending", "(J)V", (void*)android_view_ThreadedRenderer_notifyFramePending}, { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo }, {"nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*)android_view_ThreadedRenderer_dumpProfileInfo}, {"setupShadersDiskCache", "(Ljava/lang/String;Ljava/lang/String;)V", (void*)android_view_ThreadedRenderer_setupShadersDiskCache}, {"nAddRenderNode", "(JJZ)V", (void*)android_view_ThreadedRenderer_addRenderNode}, {"nRemoveRenderNode", "(JJ)V", (void*)android_view_ThreadedRenderer_removeRenderNode}, {"nDrawRenderNode", "(JJ)V", (void*)android_view_ThreadedRendererd_drawRenderNode}, { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds}, { "nSetPictureCaptureCallback", "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V", {"nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds}, {"nSetPictureCaptureCallback", "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V", (void*)android_view_ThreadedRenderer_setPictureCapturedCallbackJNI}, {"nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V", (void*)android_view_ThreadedRenderer_setFrameCallback}, { "nSetFrameCompleteCallback", "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V", {"nSetFrameCompleteCallback", "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V", (void*)android_view_ThreadedRenderer_setFrameCompleteCallback}, {"nAddObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_addObserver}, {"nRemoveObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_removeObserver}, Loading @@ -704,7 +732,9 @@ static const JNINativeMethod gMethods[] = { {"nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority}, {"nAllocateBuffers", "(J)V", (void*)android_view_ThreadedRenderer_allocateBuffers}, {"nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark}, { "nSetDisplayDensityDpi", "(I)V", (void*)android_view_ThreadedRenderer_setDisplayDensityDpi }, {"nSetDisplayDensityDpi", "(I)V", (void*)android_view_ThreadedRenderer_setDisplayDensityDpi}, {"nInitDisplayInfo", "(IIFFIJJ)V", (void*)android_view_ThreadedRenderer_initDisplayInfo}, {"preload", "()V", (void*)android_view_ThreadedRenderer_preload}, }; Loading