1 /*
2 * Copyright (C) 2019 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 #include "android_graphics_HardwareRendererObserver.h"
18
19 #include <array>
20
21 #include "FrameInfo.h"
22 #include "graphics_jni_helpers.h"
23 #include "nativehelper/jni_macros.h"
24
25 namespace android {
26
27 struct {
28 jclass clazz;
29 jmethodID callback;
30 } gHardwareRendererObserverClassInfo;
31
getenv(JavaVM * vm)32 static JNIEnv* getenv(JavaVM* vm) {
33 JNIEnv* env;
34 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
35 LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
36 }
37 return env;
38 }
39
HardwareRendererObserver(JavaVM * vm,jobject observer,bool waitForPresentTime)40 HardwareRendererObserver::HardwareRendererObserver(JavaVM* vm, jobject observer,
41 bool waitForPresentTime)
42 : uirenderer::FrameMetricsObserver(waitForPresentTime), mVm(vm) {
43 mObserver = getenv(mVm)->NewGlobalRef(observer);
44 LOG_ALWAYS_FATAL_IF(mObserver == nullptr, "unable to create frame stats observer reference");
45 }
46
~HardwareRendererObserver()47 HardwareRendererObserver::~HardwareRendererObserver() {
48 JNIEnv* env = getenv(mVm);
49 env->DeleteGlobalRef(mObserver);
50 }
51
getNextBuffer(JNIEnv * env,jlongArray metrics,int * dropCount)52 bool HardwareRendererObserver::getNextBuffer(JNIEnv* env, jlongArray metrics, int* dropCount) {
53 jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(metrics));
54 LOG_ALWAYS_FATAL_IF(bufferSize != HardwareRendererObserver::kBufferSize,
55 "Mismatched Java/Native FrameMetrics data format.");
56
57 FrameMetricsNotification& elem = mRingBuffer[mNextInQueue];
58 if (elem.hasData.load()) {
59 env->SetLongArrayRegion(metrics, 0, kBufferSize, elem.buffer);
60 *dropCount = elem.dropCount;
61 mNextInQueue = (mNextInQueue + 1) % kRingSize;
62 elem.hasData = false;
63 return true;
64 }
65
66 return false;
67 }
68
notify(const uirenderer::FrameInfoBuffer & stats)69 void HardwareRendererObserver::notify(const uirenderer::FrameInfoBuffer& stats) {
70 if (!mKeepListening) return;
71
72 FrameMetricsNotification& elem = mRingBuffer[mNextFree];
73
74 if (!elem.hasData.load()) {
75 memcpy(elem.buffer, stats.data(), kBufferSize * sizeof(stats[0]));
76
77 elem.dropCount = mDroppedReports;
78 mDroppedReports = 0;
79 mNextFree = (mNextFree + 1) % kRingSize;
80 elem.hasData = true;
81
82 JNIEnv* env = getenv(mVm);
83 mKeepListening = env->CallStaticBooleanMethod(gHardwareRendererObserverClassInfo.clazz,
84 gHardwareRendererObserverClassInfo.callback,
85 mObserver);
86 } else {
87 mDroppedReports++;
88 }
89 }
90
android_graphics_HardwareRendererObserver_createObserver(JNIEnv * env,jobject,jobject weakRefThis,jboolean waitForPresentTime)91 static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env,
92 jobject /*clazz*/,
93 jobject weakRefThis,
94 jboolean waitForPresentTime) {
95 JavaVM* vm = nullptr;
96 if (env->GetJavaVM(&vm) != JNI_OK) {
97 LOG_ALWAYS_FATAL("Unable to get Java VM");
98 return 0;
99 }
100
101 HardwareRendererObserver* observer =
102 new HardwareRendererObserver(vm, weakRefThis, waitForPresentTime);
103 return reinterpret_cast<jlong>(observer);
104 }
105
android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv * env,jobject,jlong observerPtr,jlongArray metrics)106 static jint android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv* env, jobject,
107 jlong observerPtr,
108 jlongArray metrics) {
109 HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
110 int dropCount = 0;
111 if (observer->getNextBuffer(env, metrics, &dropCount)) {
112 return dropCount;
113 } else {
114 return -1;
115 }
116 }
117
118 static const std::array gMethods = {
119 MAKE_JNI_NATIVE_METHOD("nCreateObserver", "(Ljava/lang/ref/WeakReference;Z)J",
120 android_graphics_HardwareRendererObserver_createObserver),
121 MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I",
122 android_graphics_HardwareRendererObserver_getNextBuffer),
123 };
124
register_android_graphics_HardwareRendererObserver(JNIEnv * env)125 int register_android_graphics_HardwareRendererObserver(JNIEnv* env) {
126
127 jclass observerClass = FindClassOrDie(env, "android/graphics/HardwareRendererObserver");
128 gHardwareRendererObserverClassInfo.clazz =
129 reinterpret_cast<jclass>(env->NewGlobalRef(observerClass));
130 gHardwareRendererObserverClassInfo.callback = GetStaticMethodIDOrDie(
131 env, observerClass, "invokeDataAvailable", "(Ljava/lang/ref/WeakReference;)Z");
132
133 return RegisterMethodsOrDie(env, "android/graphics/HardwareRendererObserver",
134 gMethods.data(), gMethods.size());
135
136 }
137
138 } // namespace android