Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion nativelib/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ set(SOURCE_FILES
usb_ddk_poller.cpp
native_render.cpp
presentation_scheduler.cpp
presentation_diagnostics.cpp
rolling_frame_rate.cpp
gl_post_processor.cpp
sdl_gamecontrollerdb.cpp
Expand Down
146 changes: 5 additions & 141 deletions nativelib/src/main/cpp/native_render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,13 @@
*/

#include "native_render.h"
#include <algorithm>
#include <cstring>
#include <dlfcn.h>
#include <time.h>

#undef LOG_TAG
#define LOG_TAG "NativeRender"

namespace {
constexpr int64_t kNanosecondsPerMillisecond = 1000000LL;
constexpr int64_t kVsyncSampleIntervalNs = 250 * kNanosecondsPerMillisecond;
constexpr int64_t kHostPacedStatsLogIntervalFrames = 600;

std::atomic<uint64_t> g_vsyncSampleGeneration{0};
std::atomic<int64_t> g_observedVsyncTimestampNs{0};
std::atomic<int64_t> g_observedVsyncPeriodNs{0};
std::atomic<int64_t> g_vsyncSampleRequestFailures{0};

void OnVSyncSample(long long timestamp, void* data) {
const uint64_t generation = static_cast<uint64_t>(
reinterpret_cast<uintptr_t>(data));
if (generation == g_vsyncSampleGeneration.load(std::memory_order_acquire)) {
g_observedVsyncTimestampNs.store(
static_cast<int64_t>(timestamp), std::memory_order_release);
}
}
} // namespace

// RenderOutputBufferAtTime 是 API 12+ 的函数,旧设备或不完整运行时可能不存在
// 通过 dlsym 动态加载,避免硬依赖
typedef OH_AVErrCode (*PFN_RenderOutputBufferAtTime)(OH_AVCodec*, uint32_t, int64_t);
Expand Down Expand Up @@ -169,12 +148,6 @@ void NativeRender::InitNativeVSync() {
const char* name = "moonlight_render";
nativeVSync_ = OH_NativeVSync_Create(name, strlen(name));
if (nativeVSync_ != nullptr) {
nativeVsyncGeneration_ =
g_vsyncSampleGeneration.fetch_add(1, std::memory_order_acq_rel) + 1;
g_observedVsyncTimestampNs.store(0, std::memory_order_release);
g_observedVsyncPeriodNs.store(0, std::memory_order_release);
g_vsyncSampleRequestFailures.store(0, std::memory_order_relaxed);
lastVsyncSampleRequestNs_.store(0, std::memory_order_relaxed);
OH_LOG_INFO(LOG_APP, "NativeVSync created successfully");
} else {
OH_LOG_WARN(LOG_APP, "Failed to create NativeVSync");
Expand All @@ -187,10 +160,6 @@ void NativeRender::ReleaseNativeVSync() {
return;
}

g_vsyncSampleGeneration.fetch_add(1, std::memory_order_acq_rel);
nativeVsyncGeneration_ = 0;
g_observedVsyncTimestampNs.store(0, std::memory_order_release);
g_observedVsyncPeriodNs.store(0, std::memory_order_release);
OH_NativeVSync_Destroy(nativeVSync_);
nativeVSync_ = nullptr;
OH_LOG_INFO(LOG_APP, "NativeVSync destroyed");
Expand Down Expand Up @@ -249,7 +218,7 @@ void NativeRender::SetVsyncEnabled(bool enable) {
bool wasEnabled = vsyncEnabled_.exchange(enable);
if (wasEnabled != enable) {
{
std::unique_lock<std::mutex> lock(presentationMutex_);
std::lock_guard<std::mutex> lock(presentationMutex_);
ResetPresentationClockLocked();
ResetPresentationStatsLocked();
}
Expand Down Expand Up @@ -382,38 +351,6 @@ void NativeRender::ApplyFrameRateRange() {
}
}

void NativeRender::RequestVSyncSample(int64_t nowNs) {
int64_t previousRequestNs =
lastVsyncSampleRequestNs_.load(std::memory_order_relaxed);
if (previousRequestNs > 0 &&
nowNs - previousRequestNs < kVsyncSampleIntervalNs) {
return;
}
if (!lastVsyncSampleRequestNs_.compare_exchange_strong(
previousRequestNs, nowNs, std::memory_order_relaxed)) {
return;
}

std::lock_guard<std::mutex> lock(nativeVsyncMutex_);
if (nativeVSync_ == nullptr || nativeVsyncGeneration_ == 0) {
return;
}

long long periodNs = 0;
if (OH_NativeVSync_GetPeriod(nativeVSync_, &periodNs) == 0 &&
periodNs > 0) {
g_observedVsyncPeriodNs.store(
static_cast<int64_t>(periodNs), std::memory_order_release);
}

const int result = OH_NativeVSync_RequestFrame(
nativeVSync_, OnVSyncSample,
reinterpret_cast<void*>(static_cast<uintptr_t>(nativeVsyncGeneration_)));
if (result != 0) {
g_vsyncSampleRequestFailures.fetch_add(1, std::memory_order_relaxed);
}
}

// =============================================================================
// PTS presentation clocks
// =============================================================================
Expand All @@ -431,17 +368,6 @@ void NativeRender::ResetPresentationStatsLocked() {
vsyncFrameCount_ = 0;
vsyncLateFrameCount_ = 0;
vsyncResyncCount_ = 0;
preciseScheduledCount_ = 0;
preciseDroppedCount_ = 0;
preciseLateCount_ = 0;
preciseCatchUpCount_ = 0;
precisePhaseShiftCount_ = 0;
preciseRebufferCount_ = 0;
preciseResyncCount_ = 0;
preciseQueueFullCount_ = 0;
preciseApiFailureCount_ = 0;
preciseMaxTargetLeadNs_ = 0;
presentationDiagnostics_.Reset();
}

void NativeRender::ResetPresentationClock() {
Expand Down Expand Up @@ -551,74 +477,13 @@ NativeRender::FrameSubmitResult NativeRender::SubmitFrame(const DecodedFrame& fr
}
} else {
const int64_t decodedAtNs = GetMonotonicTimeNs();
RequestVSyncSample(decodedAtNs);
const int64_t observedVsyncNs =
g_observedVsyncTimestampNs.load(std::memory_order_acquire);
const int64_t observedVsyncPeriodNs =
g_observedVsyncPeriodNs.load(std::memory_order_acquire);
const PresentationVsyncTiming vsyncTiming = {
observedVsyncNs, observedVsyncPeriodNs};

// Keep planning and timed submission ordered even if a codec emits
// output callbacks concurrently.
std::unique_lock<std::mutex> lock(presentationMutex_);
const PresentationPlan plan = ptsScheduler_.PlanFrame(
frame.ptsUs, decodedAtNs, vsyncTiming);
if (plan.action == PresentationAction::SCHEDULE) {
preciseScheduledCount_++;
} else {
preciseDroppedCount_++;
}
if (plan.latenessNs > 0) preciseLateCount_++;
if (plan.event == PresentationEvent::CATCH_UP) preciseCatchUpCount_++;
if (plan.event == PresentationEvent::PHASE_SHIFT) precisePhaseShiftCount_++;
if (plan.event == PresentationEvent::REBUFFER) preciseRebufferCount_++;
if (plan.event == PresentationEvent::DISCONTINUITY ||
plan.event == PresentationEvent::DUPLICATE_PTS) {
preciseResyncCount_++;
}
if (plan.event == PresentationEvent::QUEUE_FULL) preciseQueueFullCount_++;
if (plan.action == PresentationAction::SCHEDULE) {
preciseMaxTargetLeadNs_ = std::max(
preciseMaxTargetLeadNs_, plan.targetTimeNs - decodedAtNs);
presentationDiagnostics_.Record(
plan.targetTimeNs, decodedAtNs,
observedVsyncNs, observedVsyncPeriodNs);
}

const int64_t totalFrames = preciseScheduledCount_ + preciseDroppedCount_;
if (totalFrames % kHostPacedStatsLogIntervalFrames == 0) {
const PresentationTimingStats& timing =
presentationDiagnostics_.GetStats();
OH_LOG_INFO(LOG_APP,
"Host-paced stats: frames=%{public}lld, scheduled=%{public}lld, dropped=%{public}lld, late=%{public}lld, catchUp=%{public}lld, phaseShift=%{public}lld, rebuffer=%{public}lld, resync=%{public}lld, queueFull=%{public}lld, apiFailure=%{public}lld, lead=%{public}lldus, maxLead=%{public}lldus, sameSlot=%{public}lld, slotRegression=%{public}lld, targetRegression=%{public}lld, maxRegression=%{public}lldus, maxQueueSlots=%{public}lld, vsyncPeriod=%{public}lldus, vsyncAge=%{public}lldus, vsyncSampleFailure=%{public}lld",
static_cast<long long>(totalFrames),
static_cast<long long>(preciseScheduledCount_),
static_cast<long long>(preciseDroppedCount_),
static_cast<long long>(preciseLateCount_),
static_cast<long long>(preciseCatchUpCount_),
static_cast<long long>(precisePhaseShiftCount_),
static_cast<long long>(preciseRebufferCount_),
static_cast<long long>(preciseResyncCount_),
static_cast<long long>(preciseQueueFullCount_),
static_cast<long long>(preciseApiFailureCount_),
static_cast<long long>(ptsScheduler_.GetInitialLeadNs() / 1000),
static_cast<long long>(preciseMaxTargetLeadNs_ / 1000),
static_cast<long long>(timing.sameVsyncSlotCount),
static_cast<long long>(timing.vsyncSlotRegressionCount),
static_cast<long long>(timing.targetRegressionCount),
static_cast<long long>(timing.maxTargetRegressionNs / 1000),
static_cast<long long>(timing.maxQueueDepthSlots),
static_cast<long long>(observedVsyncPeriodNs / 1000),
static_cast<long long>(observedVsyncNs > 0
? std::max<int64_t>(0, decodedAtNs - observedVsyncNs) / 1000
: 0),
static_cast<long long>(g_vsyncSampleRequestFailures.load(
std::memory_order_relaxed)));
PresentationPlan plan;
{
std::lock_guard<std::mutex> lock(presentationMutex_);
plan = ptsScheduler_.PlanFrame(frame.ptsUs, decodedAtNs);
}

if (plan.action == PresentationAction::DROP) {
lock.unlock();
renderResult = freeFrame();
} else {
renderResult = renderAtTime(
Expand All @@ -627,7 +492,6 @@ NativeRender::FrameSubmitResult NativeRender::SubmitFrame(const DecodedFrame& fr
bufferConsumed = true;
framePresented = true;
} else {
preciseApiFailureCount_++;
OH_LOG_WARN(LOG_APP,
"Host-paced render failed: %{public}d, pts=%{public}lld, targetNs=%{public}lld; falling back",
renderResult, static_cast<long long>(frame.ptsUs),
Expand Down
18 changes: 0 additions & 18 deletions nativelib/src/main/cpp/native_render.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
#include <multimedia/player_framework/native_avcodec_videodecoder.h>
#include <hilog/log.h>

#include "presentation_diagnostics.h"
#include "presentation_scheduler.h"

#include <cstdint>
Expand Down Expand Up @@ -127,9 +126,6 @@ class NativeRender {
// 应用帧率范围(通过 NativeVSync,API 20+)
void ApplyFrameRateRange();

// 请求低频率的只读 VSync 时间样本,用于呈现诊断
void RequestVSyncSample(int64_t nowNs);

// 应用 NativeWindow 帧率(Surface buffer queue 级别,API 12+)
void ApplyNativeWindowFrameRate();

Expand Down Expand Up @@ -166,7 +162,6 @@ class NativeRender {
// separate clocks so switching decoder modes cannot perturb PTS cadence.
mutable std::mutex presentationMutex_;
PtsPresentationScheduler ptsScheduler_;
PresentationDiagnostics presentationDiagnostics_;

// Legacy VSync clock, kept isolated from the host-paced scheduler.
int64_t estimatedOffsetNs_ = 0; // 平滑后的 (本地 - host) 偏移均值(纳秒)
Expand All @@ -178,22 +173,9 @@ class NativeRender {
int64_t vsyncFrameCount_ = 0;
int64_t vsyncLateFrameCount_ = 0;
int64_t vsyncResyncCount_ = 0;
int64_t preciseScheduledCount_ = 0;
int64_t preciseDroppedCount_ = 0;
int64_t preciseLateCount_ = 0;
int64_t preciseCatchUpCount_ = 0;
int64_t precisePhaseShiftCount_ = 0;
int64_t preciseRebufferCount_ = 0;
int64_t preciseResyncCount_ = 0;
int64_t preciseQueueFullCount_ = 0;
int64_t preciseApiFailureCount_ = 0;
int64_t preciseMaxTargetLeadNs_ = 0;

// NativeVSync(用于设置期望帧率范围,API 20+)
std::mutex nativeVsyncMutex_;
OH_NativeVSync* nativeVSync_ = nullptr;
uint64_t nativeVsyncGeneration_ = 0;
std::atomic<int64_t> lastVsyncSampleRequestNs_{0};

};

Expand Down
60 changes: 0 additions & 60 deletions nativelib/src/main/cpp/presentation_diagnostics.cpp

This file was deleted.

32 changes: 0 additions & 32 deletions nativelib/src/main/cpp/presentation_diagnostics.h

This file was deleted.

Loading
Loading