| /* |
| * Copyright (C) 2019 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. |
| */ |
| |
| #include "android_graphics_HardwareRendererObserver.h" |
| |
| #include "graphics_jni_helpers.h" |
| #include "nativehelper/jni_macros.h" |
| |
| #include <array> |
| |
| namespace android { |
| |
| struct { |
| jclass clazz; |
| jmethodID callback; |
| } gHardwareRendererObserverClassInfo; |
| |
| 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; |
| } |
| |
| HardwareRendererObserver::HardwareRendererObserver(JavaVM* vm, jobject observer, |
| bool waitForPresentTime) |
| : uirenderer::FrameMetricsObserver(waitForPresentTime), mVm(vm) { |
| mObserver = getenv(mVm)->NewGlobalRef(observer); |
| LOG_ALWAYS_FATAL_IF(mObserver == nullptr, "unable to create frame stats observer reference"); |
| } |
| |
| HardwareRendererObserver::~HardwareRendererObserver() { |
| JNIEnv* env = getenv(mVm); |
| env->DeleteGlobalRef(mObserver); |
| } |
| |
| bool HardwareRendererObserver::getNextBuffer(JNIEnv* env, jlongArray metrics, int* dropCount) { |
| jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(metrics)); |
| LOG_ALWAYS_FATAL_IF(bufferSize != HardwareRendererObserver::kBufferSize, |
| "Mismatched Java/Native FrameMetrics data format."); |
| |
| FrameMetricsNotification& elem = mRingBuffer[mNextInQueue]; |
| if (elem.hasData.load()) { |
| env->SetLongArrayRegion(metrics, 0, kBufferSize, elem.buffer); |
| *dropCount = elem.dropCount; |
| mNextInQueue = (mNextInQueue + 1) % kRingSize; |
| elem.hasData = false; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| void HardwareRendererObserver::notify(const int64_t* stats) { |
| if (!mKeepListening) return; |
| |
| FrameMetricsNotification& elem = mRingBuffer[mNextFree]; |
| |
| if (!elem.hasData.load()) { |
| memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0])); |
| |
| elem.dropCount = mDroppedReports; |
| mDroppedReports = 0; |
| mNextFree = (mNextFree + 1) % kRingSize; |
| elem.hasData = true; |
| |
| JNIEnv* env = getenv(mVm); |
| mKeepListening = env->CallStaticBooleanMethod(gHardwareRendererObserverClassInfo.clazz, |
| gHardwareRendererObserverClassInfo.callback, |
| mObserver); |
| } else { |
| mDroppedReports++; |
| } |
| } |
| |
| static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env, |
| jobject /*clazz*/, |
| jobject weakRefThis, |
| jboolean waitForPresentTime) { |
| JavaVM* vm = nullptr; |
| if (env->GetJavaVM(&vm) != JNI_OK) { |
| LOG_ALWAYS_FATAL("Unable to get Java VM"); |
| return 0; |
| } |
| |
| HardwareRendererObserver* observer = |
| new HardwareRendererObserver(vm, weakRefThis, waitForPresentTime); |
| return reinterpret_cast<jlong>(observer); |
| } |
| |
| static jint android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv* env, jobject, |
| jlong observerPtr, |
| jlongArray metrics) { |
| HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr); |
| int dropCount = 0; |
| if (observer->getNextBuffer(env, metrics, &dropCount)) { |
| return dropCount; |
| } else { |
| return -1; |
| } |
| } |
| |
| static const std::array gMethods = { |
| MAKE_JNI_NATIVE_METHOD("nCreateObserver", "(Ljava/lang/ref/WeakReference;Z)J", |
| android_graphics_HardwareRendererObserver_createObserver), |
| MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I", |
| android_graphics_HardwareRendererObserver_getNextBuffer), |
| }; |
| |
| int register_android_graphics_HardwareRendererObserver(JNIEnv* env) { |
| |
| jclass observerClass = FindClassOrDie(env, "android/graphics/HardwareRendererObserver"); |
| gHardwareRendererObserverClassInfo.clazz = |
| reinterpret_cast<jclass>(env->NewGlobalRef(observerClass)); |
| gHardwareRendererObserverClassInfo.callback = GetStaticMethodIDOrDie( |
| env, observerClass, "invokeDataAvailable", "(Ljava/lang/ref/WeakReference;)Z"); |
| |
| return RegisterMethodsOrDie(env, "android/graphics/HardwareRendererObserver", |
| gMethods.data(), gMethods.size()); |
| |
| } |
| |
| } // namespace android |