1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define ATRACE_TAG ATRACE_TAG_VIEW
18
19 #include <GraphicsJNI.h>
20 #include <RootRenderNode.h>
21 #include <TreeInfo.h>
22 #include <android-base/unique_fd.h>
23 #include <android/native_window.h>
24 #include <nativehelper/JNIPlatformHelp.h>
25 #include <renderthread/CanvasContext.h>
26 #include <renderthread/RenderProxy.h>
27 #include <renderthread/RenderThread.h>
28
29 #include "HardwareBufferHelpers.h"
30 #include "JvmErrorReporter.h"
31
32 namespace android {
33
34 using namespace android::uirenderer;
35 using namespace android::uirenderer::renderthread;
36
37 struct {
38 jclass clazz;
39 jmethodID invokeRenderCallback;
40 } gHardwareBufferRendererClassInfo;
41
createRenderCallback(JNIEnv * env,jobject releaseCallback)42 static RenderCallback createRenderCallback(JNIEnv* env, jobject releaseCallback) {
43 if (releaseCallback == nullptr) return nullptr;
44
45 JavaVM* vm = nullptr;
46 LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
47 auto globalCallbackRef =
48 std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(releaseCallback));
49 return [globalCallbackRef](android::base::unique_fd&& fd, int status) {
50 globalCallbackRef->env()->CallStaticVoidMethod(
51 gHardwareBufferRendererClassInfo.clazz,
52 gHardwareBufferRendererClassInfo.invokeRenderCallback, globalCallbackRef->object(),
53 reinterpret_cast<jint>(fd.release()), reinterpret_cast<jint>(status));
54 };
55 }
56
android_graphics_HardwareBufferRenderer_createRootNode(JNIEnv * env,jobject)57 static long android_graphics_HardwareBufferRenderer_createRootNode(JNIEnv* env, jobject) {
58 auto* node = new RootRenderNode(std::make_unique<JvmErrorReporter>(env));
59 node->incStrong(nullptr);
60 node->setName("RootRenderNode");
61 return reinterpret_cast<jlong>(node);
62 }
63
android_graphics_hardwareBufferRenderer_destroyRootNode(JNIEnv *,jobject,jlong renderNodePtr)64 static void android_graphics_hardwareBufferRenderer_destroyRootNode(JNIEnv*, jobject,
65 jlong renderNodePtr) {
66 auto* node = reinterpret_cast<RootRenderNode*>(renderNodePtr);
67 node->destroy();
68 }
69
android_graphics_HardwareBufferRenderer_create(JNIEnv * env,jobject,jobject buffer,jlong renderNodePtr)70 static long android_graphics_HardwareBufferRenderer_create(JNIEnv* env, jobject, jobject buffer,
71 jlong renderNodePtr) {
72 auto* hardwareBuffer = HardwareBufferHelpers::AHardwareBuffer_fromHardwareBuffer(env, buffer);
73 auto* rootRenderNode = reinterpret_cast<RootRenderNode*>(renderNodePtr);
74 ContextFactoryImpl factory(rootRenderNode);
75 auto* proxy = new RenderProxy(false, rootRenderNode, &factory);
76 proxy->setHardwareBuffer(hardwareBuffer);
77 return (jlong)proxy;
78 }
79
HardwareBufferRenderer_destroy(jlong renderProxy)80 static void HardwareBufferRenderer_destroy(jlong renderProxy) {
81 auto* proxy = reinterpret_cast<RenderProxy*>(renderProxy);
82 delete proxy;
83 }
84
createMatrixFromBufferTransform(SkScalar width,SkScalar height,int transform)85 static SkMatrix createMatrixFromBufferTransform(SkScalar width, SkScalar height, int transform) {
86 switch (transform) {
87 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
88 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
89 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
90 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
91 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
92 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
93 default:
94 ALOGE("Invalid transform provided. Transform should be validated from"
95 "the java side. Leveraging identity transform as a fallback");
96 [[fallthrough]];
97 case ANATIVEWINDOW_TRANSFORM_IDENTITY:
98 return SkMatrix::I();
99 }
100 }
101
android_graphics_HardwareBufferRenderer_render(JNIEnv * env,jobject,jlong renderProxy,jint transform,jint width,jint height,jlong colorspacePtr,jobject consumer)102 static int android_graphics_HardwareBufferRenderer_render(JNIEnv* env, jobject, jlong renderProxy,
103 jint transform, jint width, jint height,
104 jlong colorspacePtr, jobject consumer) {
105 auto* proxy = reinterpret_cast<RenderProxy*>(renderProxy);
106 auto skWidth = static_cast<SkScalar>(width);
107 auto skHeight = static_cast<SkScalar>(height);
108 auto matrix = createMatrixFromBufferTransform(skWidth, skHeight, transform);
109 auto colorSpace = GraphicsJNI::getNativeColorSpace(colorspacePtr);
110 proxy->setHardwareBufferRenderParams(HardwareBufferRenderParams(
111 width, height, matrix, colorSpace, createRenderCallback(env, consumer)));
112 nsecs_t vsync = systemTime(SYSTEM_TIME_MONOTONIC);
113 UiFrameInfoBuilder(proxy->frameInfo())
114 .setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID,
115 UiFrameInfoBuilder::UNKNOWN_DEADLINE,
116 UiFrameInfoBuilder::UNKNOWN_FRAME_INTERVAL)
117 .addFlag(FrameInfoFlags::SurfaceCanvas);
118 return proxy->syncAndDrawFrame();
119 }
120
android_graphics_HardwareBufferRenderer_setLightGeometry(JNIEnv *,jobject,jlong renderProxyPtr,jfloat lightX,jfloat lightY,jfloat lightZ,jfloat lightRadius)121 static void android_graphics_HardwareBufferRenderer_setLightGeometry(JNIEnv*, jobject,
122 jlong renderProxyPtr,
123 jfloat lightX, jfloat lightY,
124 jfloat lightZ,
125 jfloat lightRadius) {
126 auto* proxy = reinterpret_cast<RenderProxy*>(renderProxyPtr);
127 proxy->setLightGeometry((Vector3){lightX, lightY, lightZ}, lightRadius);
128 }
129
android_graphics_HardwareBufferRenderer_setLightAlpha(JNIEnv * env,jobject,jlong renderProxyPtr,jfloat ambientShadowAlpha,jfloat spotShadowAlpha)130 static void android_graphics_HardwareBufferRenderer_setLightAlpha(JNIEnv* env, jobject,
131 jlong renderProxyPtr,
132 jfloat ambientShadowAlpha,
133 jfloat spotShadowAlpha) {
134 auto* proxy = reinterpret_cast<RenderProxy*>(renderProxyPtr);
135 proxy->setLightAlpha((uint8_t)(255 * ambientShadowAlpha), (uint8_t)(255 * spotShadowAlpha));
136 }
137
android_graphics_HardwareBufferRenderer_getFinalizer(CRITICAL_JNI_PARAMS)138 static jlong android_graphics_HardwareBufferRenderer_getFinalizer(CRITICAL_JNI_PARAMS) {
139 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&HardwareBufferRenderer_destroy));
140 }
141
142 // ----------------------------------------------------------------------------
143 // JNI Glue
144 // ----------------------------------------------------------------------------
145
146 const char* const kClassPathName = "android/graphics/HardwareBufferRenderer";
147
148 static const JNINativeMethod gMethods[] = {
149 {"nCreateHardwareBufferRenderer", "(Landroid/hardware/HardwareBuffer;J)J",
150 (void*)android_graphics_HardwareBufferRenderer_create},
151 {"nRender", "(JIIIJLjava/util/function/Consumer;)I",
152 (void*)android_graphics_HardwareBufferRenderer_render},
153 {"nCreateRootRenderNode", "()J",
154 (void*)android_graphics_HardwareBufferRenderer_createRootNode},
155 {"nSetLightGeometry", "(JFFFF)V",
156 (void*)android_graphics_HardwareBufferRenderer_setLightGeometry},
157 {"nSetLightAlpha", "(JFF)V", (void*)android_graphics_HardwareBufferRenderer_setLightAlpha},
158 {"nGetFinalizer", "()J", (void*)android_graphics_HardwareBufferRenderer_getFinalizer},
159 {"nDestroyRootRenderNode", "(J)V",
160 (void*)android_graphics_hardwareBufferRenderer_destroyRootNode}};
161
register_android_graphics_HardwareBufferRenderer(JNIEnv * env)162 int register_android_graphics_HardwareBufferRenderer(JNIEnv* env) {
163 jclass hardwareBufferRendererClazz =
164 FindClassOrDie(env, "android/graphics/HardwareBufferRenderer");
165 gHardwareBufferRendererClassInfo.clazz =
166 reinterpret_cast<jclass>(env->NewGlobalRef(hardwareBufferRendererClazz));
167 gHardwareBufferRendererClassInfo.invokeRenderCallback =
168 GetStaticMethodIDOrDie(env, hardwareBufferRendererClazz, "invokeRenderCallback",
169 "(Ljava/util/function/Consumer;II)V");
170 HardwareBufferHelpers::init();
171 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
172 }
173
174 } // namespace android