summaryrefslogtreecommitdiff
path: root/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
diff options
context:
space:
mode:
authorDerek Sollenberger <djsollen@google.com>2020-02-21 11:43:02 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-02-21 11:43:02 +0000
commit76e7430baead21c67fd4c81a36774a6461d2fb99 (patch)
tree239a62b59c57b4b95d8e82943bf9a48e84439819 /libs/hwui/jni/android_graphics_HardwareRenderer.cpp
parent1ab8e44c06ca05806a81c6737cb3f6e316d8d25a (diff)
parent2173ea286afff6766043227de0bc2d82d9595f77 (diff)
Merge changes from topic "HWUI_JNI"
* changes: Export symbols for the newly exposed APEX/internal headers Remove dependence on libandroid_runtime from Bitmap.cpp Update Region.cpp to use AParcel NDK APIs Cleanup header and build targets for libhwui clients. Remove dependencies on headers outside UI module Cleanup LOG_TAG when bundled in HWUI Move android.graphics JNI & APEX files into HWUI
Diffstat (limited to 'libs/hwui/jni/android_graphics_HardwareRenderer.cpp')
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp745
1 files changed, 745 insertions, 0 deletions
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
new file mode 100644
index 000000000000..49c7fcd468e1
--- /dev/null
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -0,0 +1,745 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "ThreadedRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
+
+#include <FrameInfo.h>
+#include <GraphicsJNI.h>
+#include <Picture.h>
+#include <Properties.h>
+#include <RootRenderNode.h>
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <media/NdkImage.h>
+#include <media/NdkImageReader.h>
+#include <nativehelper/JNIHelp.h>
+#include <pipeline/skia/ShaderCache.h>
+#include <private/EGL/cache.h>
+#include <renderthread/CanvasContext.h>
+#include <renderthread/RenderProxy.h>
+#include <renderthread/RenderTask.h>
+#include <renderthread/RenderThread.h>
+#include <utils/Color.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+#include <utils/TraceUtils.h>
+
+#include <algorithm>
+#include <atomic>
+
+#include "android_graphics_HardwareRendererObserver.h"
+
+namespace android {
+
+using namespace android::uirenderer;
+using namespace android::uirenderer::renderthread;
+
+struct {
+ jclass clazz;
+ jmethodID invokePictureCapturedCallback;
+} gHardwareRenderer;
+
+struct {
+ jmethodID onFrameDraw;
+} gFrameDrawingCallback;
+
+struct {
+ jmethodID onFrameComplete;
+} gFrameCompleteCallback;
+
+static JNIEnv* getenv(JavaVM* vm) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
+ }
+ return env;
+}
+
+typedef ANativeWindow* (*ANW_fromSurface)(JNIEnv* env, jobject surface);
+ANW_fromSurface fromSurface;
+
+class JvmErrorReporter : public ErrorHandler {
+public:
+ JvmErrorReporter(JNIEnv* env) {
+ env->GetJavaVM(&mVm);
+ }
+
+ virtual void onError(const std::string& message) override {
+ JNIEnv* env = getenv(mVm);
+ jniThrowException(env, "java/lang/IllegalStateException", message.c_str());
+ }
+private:
+ JavaVM* mVm;
+};
+
+class FrameCompleteWrapper : public LightRefBase<FrameCompleteWrapper> {
+public:
+ explicit FrameCompleteWrapper(JNIEnv* env, jobject jobject) {
+ env->GetJavaVM(&mVm);
+ mObject = env->NewGlobalRef(jobject);
+ LOG_ALWAYS_FATAL_IF(!mObject, "Failed to make global ref");
+ }
+
+ ~FrameCompleteWrapper() {
+ releaseObject();
+ }
+
+ void onFrameComplete(int64_t frameNr) {
+ if (mObject) {
+ ATRACE_FORMAT("frameComplete %" PRId64, frameNr);
+ getenv(mVm)->CallVoidMethod(mObject, gFrameCompleteCallback.onFrameComplete, frameNr);
+ releaseObject();
+ }
+ }
+
+private:
+ JavaVM* mVm;
+ jobject mObject;
+
+ void releaseObject() {
+ if (mObject) {
+ getenv(mVm)->DeleteGlobalRef(mObject);
+ mObject = nullptr;
+ }
+ }
+};
+
+static void android_view_ThreadedRenderer_rotateProcessStatsBuffer(JNIEnv* env, jobject clazz) {
+ RenderProxy::rotateProcessStatsBuffer();
+}
+
+static void android_view_ThreadedRenderer_setProcessStatsBuffer(JNIEnv* env, jobject clazz,
+ jint fd) {
+ RenderProxy::setProcessStatsBuffer(fd);
+}
+
+static jint android_view_ThreadedRenderer_getRenderThreadTid(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ return proxy->getRenderThreadTid();
+}
+
+static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
+ RootRenderNode* node = new RootRenderNode(std::make_unique<JvmErrorReporter>(env));
+ node->incStrong(0);
+ node->setName("RootRenderNode");
+ return reinterpret_cast<jlong>(node);
+}
+
+static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
+ jboolean translucent, jboolean isWideGamut, jlong rootRenderNodePtr) {
+ RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
+ ContextFactoryImpl factory(rootRenderNode);
+ RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory);
+ proxy->setWideGamut(isWideGamut);
+ return (jlong) proxy;
+}
+
+static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ delete proxy;
+}
+
+static jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ return proxy->loadSystemProperties();
+}
+
+static void android_view_ThreadedRenderer_setName(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jstring jname) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ const char* name = env->GetStringUTFChars(jname, NULL);
+ proxy->setName(name);
+ env->ReleaseStringUTFChars(jname, name);
+}
+
+static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jobject jsurface, jboolean discardBuffer) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ ANativeWindow* window = nullptr;
+ if (jsurface) {
+ window = fromSurface(env, jsurface);
+ }
+ bool enableTimeout = true;
+ if (discardBuffer) {
+ // Currently only Surface#lockHardwareCanvas takes this path
+ enableTimeout = false;
+ proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
+ }
+ proxy->setSurface(window, enableTimeout);
+ ANativeWindow_release(window);
+}
+
+static jboolean android_view_ThreadedRenderer_pause(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ return proxy->pause();
+}
+
+static void android_view_ThreadedRenderer_setStopped(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jboolean stopped) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setStopped(stopped);
+}
+
+static void android_view_ThreadedRenderer_setLightAlpha(JNIEnv* env, jobject clazz, jlong proxyPtr,
+ jfloat ambientShadowAlpha, jfloat spotShadowAlpha) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setLightAlpha((uint8_t) (255 * ambientShadowAlpha), (uint8_t) (255 * spotShadowAlpha));
+}
+
+static void android_view_ThreadedRenderer_setLightGeometry(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setLightGeometry((Vector3){lightX, lightY, lightZ}, lightRadius);
+}
+
+static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jboolean opaque) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setOpaque(opaque);
+}
+
+static void android_view_ThreadedRenderer_setWideGamut(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jboolean wideGamut) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setWideGamut(wideGamut);
+}
+
+static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
+ LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
+ "Mismatched size expectations, given %d expected %d",
+ frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
+ return proxy->syncAndDrawFrame();
+}
+
+static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong rootNodePtr) {
+ RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
+ rootRenderNode->destroy();
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->destroy();
+}
+
+static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* env, jobject clazz,
+ jlong rootNodePtr, jlong animatingNodePtr) {
+ RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
+ RenderNode* animatingNode = reinterpret_cast<RenderNode*>(animatingNodePtr);
+ rootRenderNode->attachAnimatingNode(animatingNode);
+}
+
+static void android_view_ThreadedRenderer_registerVectorDrawableAnimator(JNIEnv* env, jobject clazz,
+ jlong rootNodePtr, jlong animatorPtr) {
+ RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
+ PropertyValuesAnimatorSet* animator = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr);
+ rootRenderNode->addVectorDrawableAnimator(animator);
+}
+
+static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
+ jlong functorPtr, jboolean waitForCompletion) {
+ Functor* functor = reinterpret_cast<Functor*>(functorPtr);
+ RenderProxy::invokeFunctor(functor, waitForCompletion);
+}
+
+static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = proxy->createTextureLayer();
+ return reinterpret_cast<jlong>(layer);
+}
+
+static void android_view_ThreadedRenderer_buildLayer(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong nodePtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ RenderNode* node = reinterpret_cast<RenderNode*>(nodePtr);
+ proxy->buildLayer(node);
+}
+
+static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+ SkBitmap bitmap;
+ bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
+ return proxy->copyLayerInto(layer, bitmap);
+}
+
+static void android_view_ThreadedRenderer_pushLayerUpdate(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong layerPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+ proxy->pushLayerUpdate(layer);
+}
+
+static void android_view_ThreadedRenderer_cancelLayerUpdate(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong layerPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+ proxy->cancelLayerUpdate(layer);
+}
+
+static void android_view_ThreadedRenderer_detachSurfaceTexture(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong layerPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+ proxy->detachSurfaceTexture(layer);
+}
+
+static void android_view_ThreadedRenderer_destroyHardwareResources(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->destroyHardwareResources();
+}
+
+static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
+ jint level) {
+ RenderProxy::trimMemory(level);
+}
+
+static void android_view_ThreadedRenderer_overrideProperty(JNIEnv* env, jobject clazz,
+ jstring name, jstring value) {
+ const char* nameCharArray = env->GetStringUTFChars(name, NULL);
+ const char* valueCharArray = env->GetStringUTFChars(value, NULL);
+ RenderProxy::overrideProperty(nameCharArray, valueCharArray);
+ env->ReleaseStringUTFChars(name, nameCharArray);
+ env->ReleaseStringUTFChars(name, valueCharArray);
+}
+
+static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->fence();
+}
+
+static void android_view_ThreadedRenderer_stopDrawing(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->stopDrawing();
+}
+
+static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->notifyFramePending();
+}
+
+static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jobject javaFileDescriptor, jint dumpFlags) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
+ proxy->dumpProfileInfo(fd, dumpFlags);
+}
+
+static void android_view_ThreadedRenderer_addRenderNode(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong renderNodePtr, jboolean placeFront) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ proxy->addRenderNode(renderNode, placeFront);
+}
+
+static void android_view_ThreadedRenderer_removeRenderNode(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong renderNodePtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ proxy->removeRenderNode(renderNode);
+}
+
+static void android_view_ThreadedRendererd_drawRenderNode(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong renderNodePtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ proxy->drawRenderNode(renderNode);
+}
+
+static void android_view_ThreadedRenderer_setContentDrawBounds(JNIEnv* env,
+ jobject clazz, jlong proxyPtr, jint left, jint top, jint right, jint bottom) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setContentDrawBounds(left, top, right, bottom);
+}
+
+class JGlobalRefHolder {
+public:
+ JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {}
+
+ virtual ~JGlobalRefHolder() {
+ getenv(mVm)->DeleteGlobalRef(mObject);
+ mObject = nullptr;
+ }
+
+ jobject object() { return mObject; }
+ JavaVM* vm() { return mVm; }
+
+private:
+ JGlobalRefHolder(const JGlobalRefHolder&) = delete;
+ void operator=(const JGlobalRefHolder&) = delete;
+
+ JavaVM* mVm;
+ jobject mObject;
+};
+
+static void android_view_ThreadedRenderer_setPictureCapturedCallbackJNI(JNIEnv* env,
+ jobject clazz, jlong proxyPtr, jobject pictureCallback) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ if (!pictureCallback) {
+ proxy->setPictureCapturedCallback(nullptr);
+ } else {
+ JavaVM* vm = nullptr;
+ LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
+ auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm,
+ env->NewGlobalRef(pictureCallback));
+ proxy->setPictureCapturedCallback([globalCallbackRef](sk_sp<SkPicture>&& picture) {
+ JNIEnv* env = getenv(globalCallbackRef->vm());
+ Picture* wrapper = new Picture{std::move(picture)};
+ env->CallStaticVoidMethod(gHardwareRenderer.clazz,
+ gHardwareRenderer.invokePictureCapturedCallback,
+ static_cast<jlong>(reinterpret_cast<intptr_t>(wrapper)),
+ globalCallbackRef->object());
+ });
+ }
+}
+
+static void android_view_ThreadedRenderer_setFrameCallback(JNIEnv* env,
+ jobject clazz, jlong proxyPtr, jobject frameCallback) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ if (!frameCallback) {
+ proxy->setFrameCallback(nullptr);
+ } else {
+ JavaVM* vm = nullptr;
+ LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
+ auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm,
+ env->NewGlobalRef(frameCallback));
+ proxy->setFrameCallback([globalCallbackRef](int64_t frameNr) {
+ JNIEnv* env = getenv(globalCallbackRef->vm());
+ env->CallVoidMethod(globalCallbackRef->object(), gFrameDrawingCallback.onFrameDraw,
+ static_cast<jlong>(frameNr));
+ });
+ }
+}
+
+static void android_view_ThreadedRenderer_setFrameCompleteCallback(JNIEnv* env,
+ jobject clazz, jlong proxyPtr, jobject callback) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ if (!callback) {
+ proxy->setFrameCompleteCallback(nullptr);
+ } else {
+ sp<FrameCompleteWrapper> wrapper = new FrameCompleteWrapper{env, callback};
+ proxy->setFrameCompleteCallback([wrapper](int64_t frameNr) {
+ wrapper->onFrameComplete(frameNr);
+ });
+ }
+}
+
+static jint android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env,
+ jobject clazz, jobject jsurface, jint left, jint top,
+ jint right, jint bottom, jlong bitmapPtr) {
+ SkBitmap bitmap;
+ bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
+ ANativeWindow* window = fromSurface(env, jsurface);
+ jint result = RenderProxy::copySurfaceInto(window, left, top, right, bottom, &bitmap);
+ ANativeWindow_release(window);
+ return result;
+}
+
+class ContextFactory : public IContextFactory {
+public:
+ virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
+ return new AnimationContext(clock);
+ }
+};
+
+static jobject android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr, jint jwidth, jint jheight) {
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ if (jwidth <= 0 || jheight <= 0) {
+ ALOGW("Invalid width %d or height %d", jwidth, jheight);
+ return nullptr;
+ }
+
+ uint32_t width = jwidth;
+ uint32_t height = jheight;
+
+ // Create an ImageReader wired up to a BufferItemConsumer
+ AImageReader* rawReader;
+ media_status_t result =
+ AImageReader_newWithUsage(width, height, AIMAGE_FORMAT_RGBA_8888,
+ AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, 2, &rawReader);
+ std::unique_ptr<AImageReader, decltype(&AImageReader_delete)> reader(rawReader,
+ AImageReader_delete);
+
+ if (result != AMEDIA_OK) {
+ ALOGW("Error creating image reader!");
+ return nullptr;
+ }
+
+ // Note that ownership of this window is maintained by AImageReader, so we
+ // shouldn't need to wrap around a smart pointer.
+ ANativeWindow* window;
+ result = AImageReader_getWindow(rawReader, &window);
+
+ if (result != AMEDIA_OK) {
+ ALOGW("Error retrieving the native window!");
+ return nullptr;
+ }
+
+ // Render into the surface
+ {
+ ContextFactory factory;
+ RenderProxy proxy{true, renderNode, &factory};
+ proxy.setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
+ proxy.setSurface(window);
+ // Shadows can't be used via this interface, so just set the light source
+ // to all 0s.
+ proxy.setLightAlpha(0, 0);
+ proxy.setLightGeometry((Vector3){0, 0, 0}, 0);
+ nsecs_t vsync = systemTime(SYSTEM_TIME_MONOTONIC);
+ UiFrameInfoBuilder(proxy.frameInfo())
+ .setVsync(vsync, vsync)
+ .addFlag(FrameInfoFlags::SurfaceCanvas);
+ proxy.syncAndDrawFrame();
+ }
+
+ AImage* rawImage;
+ result = AImageReader_acquireNextImage(rawReader, &rawImage);
+ std::unique_ptr<AImage, decltype(&AImage_delete)> image(rawImage, AImage_delete);
+ if (result != AMEDIA_OK) {
+ ALOGW("Error reading image: %d!", result);
+ return nullptr;
+ }
+
+ AHardwareBuffer* buffer;
+ result = AImage_getHardwareBuffer(rawImage, &buffer);
+
+ AHardwareBuffer_Desc desc;
+ AHardwareBuffer_describe(buffer, &desc);
+
+ if (desc.width != width || desc.height != height) {
+ ALOGW("AHardwareBuffer size mismatch, got %dx%d expected %dx%d", desc.width, desc.height,
+ width, height);
+ // Continue I guess?
+ }
+
+ sk_sp<SkColorSpace> cs = uirenderer::DataSpaceToColorSpace(
+ static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(window)));
+ if (cs == nullptr) {
+ // nullptr is treated as SRGB in Skia, thus explicitly use SRGB in order to make sure
+ // the returned bitmap has a color space.
+ cs = SkColorSpace::MakeSRGB();
+ }
+ sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, cs);
+ return bitmap::createBitmap(env, bitmap.release(),
+ android::bitmap::kBitmapCreateFlag_Premultiplied);
+}
+
+static void android_view_ThreadedRenderer_disableVsync(JNIEnv*, jclass) {
+ RenderProxy::disableVsync();
+}
+
+static void android_view_ThreadedRenderer_setHighContrastText(JNIEnv*, jclass, jboolean enable) {
+ Properties::enableHighContrastText = enable;
+}
+
+static void android_view_ThreadedRenderer_hackySetRTAnimationsEnabled(JNIEnv*, jclass,
+ jboolean enable) {
+ Properties::enableRTAnimations = enable;
+}
+
+static void android_view_ThreadedRenderer_setDebuggingEnabled(JNIEnv*, jclass, jboolean enable) {
+ Properties::debuggingEnabled = enable;
+}
+
+static void android_view_ThreadedRenderer_setIsolatedProcess(JNIEnv*, jclass, jboolean isolated) {
+ Properties::isolatedProcess = isolated;
+}
+
+static void android_view_ThreadedRenderer_setContextPriority(JNIEnv*, jclass,
+ jint contextPriority) {
+ Properties::contextPriority = contextPriority;
+}
+
+static void android_view_ThreadedRenderer_allocateBuffers(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->allocateBuffers();
+}
+
+static void android_view_ThreadedRenderer_setForceDark(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jboolean enable) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setForceDark(enable);
+}
+
+static void android_view_ThreadedRenderer_preload(JNIEnv*, jclass) {
+ RenderProxy::preload();
+}
+
+// ----------------------------------------------------------------------------
+// HardwareRendererObserver
+// ----------------------------------------------------------------------------
+
+static void android_view_ThreadedRenderer_addObserver(JNIEnv* env, jclass clazz,
+ jlong proxyPtr, jlong observerPtr) {
+ HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
+ renderthread::RenderProxy* renderProxy =
+ reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
+
+ renderProxy->addFrameMetricsObserver(observer);
+}
+
+static void android_view_ThreadedRenderer_removeObserver(JNIEnv* env, jclass clazz,
+ jlong proxyPtr, jlong observerPtr) {
+ HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
+ renderthread::RenderProxy* renderProxy =
+ reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
+
+ renderProxy->removeFrameMetricsObserver(observer);
+}
+
+// ----------------------------------------------------------------------------
+// Shaders
+// ----------------------------------------------------------------------------
+
+static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
+ jstring diskCachePath, jstring skiaDiskCachePath) {
+ const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
+ android::egl_set_cache_filename(cacheArray);
+ env->ReleaseStringUTFChars(diskCachePath, cacheArray);
+
+ const char* skiaCacheArray = env->GetStringUTFChars(skiaDiskCachePath, NULL);
+ uirenderer::skiapipeline::ShaderCache::get().setFilename(skiaCacheArray);
+ env->ReleaseStringUTFChars(skiaDiskCachePath, skiaCacheArray);
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+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 },
+ { "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 },
+ { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
+ { "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 },
+ { "nSetLightGeometry", "(JFFFF)V", (void*) android_view_ThreadedRenderer_setLightGeometry },
+ { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
+ { "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 },
+ { "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 },
+ { "nTrimMemory", "(I)V", (void*) android_view_ThreadedRenderer_trimMemory },
+ { "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 },
+ { "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",
+ (void*) android_view_ThreadedRenderer_setPictureCapturedCallbackJNI },
+ { "nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V",
+ (void*)android_view_ThreadedRenderer_setFrameCallback},
+ { "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 },
+ { "nCopySurfaceInto", "(Landroid/view/Surface;IIIIJ)I",
+ (void*)android_view_ThreadedRenderer_copySurfaceInto },
+ { "nCreateHardwareBitmap", "(JII)Landroid/graphics/Bitmap;",
+ (void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode },
+ { "disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync },
+ { "nSetHighContrastText", "(Z)V", (void*)android_view_ThreadedRenderer_setHighContrastText },
+ { "nHackySetRTAnimationsEnabled", "(Z)V",
+ (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled },
+ { "nSetDebuggingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDebuggingEnabled },
+ { "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess },
+ { "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;
+
+static void attachRenderThreadToJvm(const char* name) {
+ LOG_ALWAYS_FATAL_IF(!mJvm, "No jvm but we set the hook??");
+
+ JavaVMAttachArgs args;
+ args.version = JNI_VERSION_1_4;
+ args.name = name;
+ args.group = NULL;
+ JNIEnv* env;
+ mJvm->AttachCurrentThreadAsDaemon(&env, (void*) &args);
+}
+
+int register_android_view_ThreadedRenderer(JNIEnv* env) {
+ env->GetJavaVM(&mJvm);
+ RenderThread::setOnStartHook(&attachRenderThreadToJvm);
+
+ jclass hardwareRenderer = FindClassOrDie(env,
+ "android/graphics/HardwareRenderer");
+ gHardwareRenderer.clazz = reinterpret_cast<jclass>(env->NewGlobalRef(hardwareRenderer));
+ gHardwareRenderer.invokePictureCapturedCallback = GetStaticMethodIDOrDie(env, hardwareRenderer,
+ "invokePictureCapturedCallback",
+ "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V");
+
+ jclass frameCallbackClass = FindClassOrDie(env,
+ "android/graphics/HardwareRenderer$FrameDrawingCallback");
+ gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,
+ "onFrameDraw", "(J)V");
+
+ jclass frameCompleteClass = FindClassOrDie(env,
+ "android/graphics/HardwareRenderer$FrameCompleteCallback");
+ gFrameCompleteCallback.onFrameComplete = GetMethodIDOrDie(env, frameCompleteClass,
+ "onFrameComplete", "(J)V");
+
+ void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
+ fromSurface = (ANW_fromSurface)dlsym(handle_, "ANativeWindow_fromSurface");
+ LOG_ALWAYS_FATAL_IF(fromSurface == nullptr,
+ "Failed to find required symbol ANativeWindow_fromSurface!");
+
+ return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+}; // namespace android