267 lines
13 KiB
C++
267 lines
13 KiB
C++
/*
|
|
* Copyright (C) 2015 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-base/thread_annotations.h>
|
|
#include <android/gui/ISurfaceComposer.h>
|
|
#include <gui/Choreographer.h>
|
|
#include <jni.h>
|
|
#include <private/android/choreographer.h>
|
|
#include <utils/Looper.h>
|
|
#include <utils/Timers.h>
|
|
|
|
#include <cinttypes>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <queue>
|
|
#include <thread>
|
|
|
|
#undef LOG_TAG
|
|
#define LOG_TAG "AChoreographer"
|
|
|
|
using namespace android;
|
|
|
|
static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
|
|
return reinterpret_cast<Choreographer*>(choreographer);
|
|
}
|
|
|
|
static inline const Choreographer* AChoreographer_to_Choreographer(
|
|
const AChoreographer* choreographer) {
|
|
return reinterpret_cast<const Choreographer*>(choreographer);
|
|
}
|
|
|
|
static inline const ChoreographerFrameCallbackDataImpl*
|
|
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(
|
|
const AChoreographerFrameCallbackData* data) {
|
|
return reinterpret_cast<const ChoreographerFrameCallbackDataImpl*>(data);
|
|
}
|
|
|
|
// Glue for private C api
|
|
namespace android {
|
|
void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) {
|
|
Choreographer::signalRefreshRateCallbacks(vsyncPeriod);
|
|
}
|
|
|
|
void AChoreographer_initJVM(JNIEnv* env) {
|
|
Choreographer::initJVM(env);
|
|
}
|
|
|
|
AChoreographer* AChoreographer_routeGetInstance() {
|
|
return AChoreographer_getInstance();
|
|
}
|
|
void AChoreographer_routePostFrameCallback(AChoreographer* choreographer,
|
|
AChoreographer_frameCallback callback, void* data) {
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
return AChoreographer_postFrameCallback(choreographer, callback, data);
|
|
#pragma clang diagnostic pop
|
|
}
|
|
void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer,
|
|
AChoreographer_frameCallback callback, void* data,
|
|
long delayMillis) {
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
return AChoreographer_postFrameCallbackDelayed(choreographer, callback, data, delayMillis);
|
|
#pragma clang diagnostic pop
|
|
}
|
|
void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer,
|
|
AChoreographer_frameCallback64 callback, void* data) {
|
|
return AChoreographer_postFrameCallback64(choreographer, callback, data);
|
|
}
|
|
void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer,
|
|
AChoreographer_frameCallback64 callback,
|
|
void* data, uint32_t delayMillis) {
|
|
return AChoreographer_postFrameCallbackDelayed64(choreographer, callback, data, delayMillis);
|
|
}
|
|
void AChoreographer_routePostVsyncCallback(AChoreographer* choreographer,
|
|
AChoreographer_vsyncCallback callback, void* data) {
|
|
return AChoreographer_postVsyncCallback(choreographer, callback, data);
|
|
}
|
|
void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
|
|
AChoreographer_refreshRateCallback callback,
|
|
void* data) {
|
|
return AChoreographer_registerRefreshRateCallback(choreographer, callback, data);
|
|
}
|
|
void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer,
|
|
AChoreographer_refreshRateCallback callback,
|
|
void* data) {
|
|
return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data);
|
|
}
|
|
int64_t AChoreographerFrameCallbackData_routeGetFrameTimeNanos(
|
|
const AChoreographerFrameCallbackData* data) {
|
|
return AChoreographerFrameCallbackData_getFrameTimeNanos(data);
|
|
}
|
|
size_t AChoreographerFrameCallbackData_routeGetFrameTimelinesLength(
|
|
const AChoreographerFrameCallbackData* data) {
|
|
return AChoreographerFrameCallbackData_getFrameTimelinesLength(data);
|
|
}
|
|
size_t AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex(
|
|
const AChoreographerFrameCallbackData* data) {
|
|
return AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(data);
|
|
}
|
|
AVsyncId AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId(
|
|
const AChoreographerFrameCallbackData* data, size_t index) {
|
|
return AChoreographerFrameCallbackData_getFrameTimelineVsyncId(data, index);
|
|
}
|
|
int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentationTimeNanos(
|
|
const AChoreographerFrameCallbackData* data, size_t index) {
|
|
return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(data,
|
|
index);
|
|
}
|
|
int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos(
|
|
const AChoreographerFrameCallbackData* data, size_t index) {
|
|
return AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(data, index);
|
|
}
|
|
|
|
int64_t AChoreographer_getFrameInterval(const AChoreographer* choreographer) {
|
|
return AChoreographer_to_Choreographer(choreographer)->getFrameInterval();
|
|
}
|
|
|
|
int64_t AChoreographer_getStartTimeNanosForVsyncId(AVsyncId vsyncId) {
|
|
return Choreographer::getStartTimeNanosForVsyncId(vsyncId);
|
|
}
|
|
|
|
} // namespace android
|
|
|
|
/* Glue for the NDK interface */
|
|
|
|
static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
|
|
return reinterpret_cast<AChoreographer*>(choreographer);
|
|
}
|
|
|
|
AChoreographer* AChoreographer_getInstance() {
|
|
return Choreographer_to_AChoreographer(Choreographer::getForThread());
|
|
}
|
|
|
|
void AChoreographer_postFrameCallback(AChoreographer* choreographer,
|
|
AChoreographer_frameCallback callback, void* data) {
|
|
AChoreographer_to_Choreographer(choreographer)
|
|
->postFrameCallbackDelayed(callback, nullptr, nullptr, data, 0);
|
|
}
|
|
void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
|
|
AChoreographer_frameCallback callback, void* data,
|
|
long delayMillis) {
|
|
AChoreographer_to_Choreographer(choreographer)
|
|
->postFrameCallbackDelayed(callback, nullptr, nullptr, data, ms2ns(delayMillis));
|
|
}
|
|
void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
|
|
AChoreographer_vsyncCallback callback, void* data) {
|
|
AChoreographer_to_Choreographer(choreographer)
|
|
->postFrameCallbackDelayed(nullptr, nullptr, callback, data, 0);
|
|
}
|
|
void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
|
|
AChoreographer_frameCallback64 callback, void* data) {
|
|
AChoreographer_to_Choreographer(choreographer)
|
|
->postFrameCallbackDelayed(nullptr, callback, nullptr, data, 0);
|
|
}
|
|
void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
|
|
AChoreographer_frameCallback64 callback, void* data,
|
|
uint32_t delayMillis) {
|
|
AChoreographer_to_Choreographer(choreographer)
|
|
->postFrameCallbackDelayed(nullptr, callback, nullptr, data, ms2ns(delayMillis));
|
|
}
|
|
void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
|
|
AChoreographer_refreshRateCallback callback,
|
|
void* data) {
|
|
AChoreographer_to_Choreographer(choreographer)->registerRefreshRateCallback(callback, data);
|
|
}
|
|
void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
|
|
AChoreographer_refreshRateCallback callback,
|
|
void* data) {
|
|
AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback, data);
|
|
}
|
|
|
|
int64_t AChoreographerFrameCallbackData_getFrameTimeNanos(
|
|
const AChoreographerFrameCallbackData* data) {
|
|
const ChoreographerFrameCallbackDataImpl* frameCallbackData =
|
|
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
|
|
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
|
|
"Data is only valid in callback");
|
|
return frameCallbackData->frameTimeNanos;
|
|
}
|
|
size_t AChoreographerFrameCallbackData_getFrameTimelinesLength(
|
|
const AChoreographerFrameCallbackData* data) {
|
|
const ChoreographerFrameCallbackDataImpl* frameCallbackData =
|
|
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
|
|
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
|
|
"Data is only valid in callback");
|
|
return frameCallbackData->vsyncEventData.frameTimelinesLength;
|
|
}
|
|
size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
|
|
const AChoreographerFrameCallbackData* data) {
|
|
const ChoreographerFrameCallbackDataImpl* frameCallbackData =
|
|
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
|
|
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
|
|
"Data is only valid in callback");
|
|
return frameCallbackData->vsyncEventData.preferredFrameTimelineIndex;
|
|
}
|
|
AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
|
|
const AChoreographerFrameCallbackData* data, size_t index) {
|
|
const ChoreographerFrameCallbackDataImpl* frameCallbackData =
|
|
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
|
|
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
|
|
"Data is only valid in callback");
|
|
LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesCapacity, "Index out of bounds");
|
|
return frameCallbackData->vsyncEventData.frameTimelines[index].vsyncId;
|
|
}
|
|
int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
|
|
const AChoreographerFrameCallbackData* data, size_t index) {
|
|
const ChoreographerFrameCallbackDataImpl* frameCallbackData =
|
|
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
|
|
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
|
|
"Data is only valid in callback");
|
|
LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesCapacity, "Index out of bounds");
|
|
return frameCallbackData->vsyncEventData.frameTimelines[index].expectedPresentationTime;
|
|
}
|
|
int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
|
|
const AChoreographerFrameCallbackData* data, size_t index) {
|
|
const ChoreographerFrameCallbackDataImpl* frameCallbackData =
|
|
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
|
|
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
|
|
"Data is only valid in callback");
|
|
LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesCapacity, "Index out of bounds");
|
|
return frameCallbackData->vsyncEventData.frameTimelines[index].deadlineTimestamp;
|
|
}
|
|
|
|
AChoreographer* AChoreographer_create() {
|
|
Choreographer* choreographer = new Choreographer(nullptr);
|
|
status_t result = choreographer->initialize();
|
|
if (result != OK) {
|
|
ALOGW("Failed to initialize");
|
|
return nullptr;
|
|
}
|
|
return Choreographer_to_AChoreographer(choreographer);
|
|
}
|
|
|
|
void AChoreographer_destroy(AChoreographer* choreographer) {
|
|
if (choreographer == nullptr) {
|
|
return;
|
|
}
|
|
|
|
delete AChoreographer_to_Choreographer(choreographer);
|
|
}
|
|
|
|
int AChoreographer_getFd(const AChoreographer* choreographer) {
|
|
return AChoreographer_to_Choreographer(choreographer)->getFd();
|
|
}
|
|
|
|
void AChoreographer_handlePendingEvents(AChoreographer* choreographer, void* data) {
|
|
// Pass dummy fd and events args to handleEvent, since the underlying
|
|
// DisplayEventDispatcher doesn't need them outside of validating that a
|
|
// Looper instance didn't break, but these args circumvent those checks.
|
|
Choreographer* impl = AChoreographer_to_Choreographer(choreographer);
|
|
impl->handleEvent(-1, Looper::EVENT_INPUT, data);
|
|
}
|