blob: 8f005a56f8a7b99208ac8552b7338673c6e8c4c5 [file] [log] [blame]
/*
* 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);
}