From d15c53e530cc5a4d75a1fc1d99309a8fe8bc0776 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 20 Jun 2024 11:16:44 -0700 Subject: [PATCH] an easier way to pipe vsync time to beginFrame BUGS=[343764098] --- android/filament-android/src/main/cpp/Engine.cpp | 6 ++++++ .../filament-android/src/main/cpp/Renderer.cpp | 7 +++++++ .../java/com/google/android/filament/Engine.java | 8 +++++++- .../com/google/android/filament/Renderer.java | 14 ++++++++++++++ filament/include/filament/Engine.h | 15 +++++++++++++++ filament/include/filament/Renderer.h | 11 +++++++++++ filament/src/Engine.cpp | 8 +++++++- filament/src/Renderer.cpp | 4 ++++ filament/src/details/Renderer.cpp | 9 +++++++++ filament/src/details/Renderer.h | 16 +++++++++++++--- web/filament-js/jsbindings.cpp | 4 ++++ 11 files changed, 97 insertions(+), 5 deletions(-) diff --git a/android/filament-android/src/main/cpp/Engine.cpp b/android/filament-android/src/main/cpp/Engine.cpp index 4b3b33e530..f571422255 100644 --- a/android/filament-android/src/main/cpp/Engine.cpp +++ b/android/filament-android/src/main/cpp/Engine.cpp @@ -571,3 +571,9 @@ Java_com_google_android_filament_Engine_nBuilderBuild(JNIEnv*, jclass, jlong nat Engine::Builder* builder = (Engine::Builder*) nativeBuilder; return (jlong) builder->build(); } + +extern "C" +JNIEXPORT jlong JNICALL +Java_com_google_android_filament_Engine_getSteadyClockTimeNano(JNIEnv *env, jclass clazz) { + return (jlong)Engine::getSteadyClockTimeNano(); +} diff --git a/android/filament-android/src/main/cpp/Renderer.cpp b/android/filament-android/src/main/cpp/Renderer.cpp index c48b616f56..1dc252d356 100644 --- a/android/filament-android/src/main/cpp/Renderer.cpp +++ b/android/filament-android/src/main/cpp/Renderer.cpp @@ -187,3 +187,10 @@ Java_com_google_android_filament_Renderer_nSetPresentationTime(JNIEnv *, jclass Renderer *renderer = (Renderer *) nativeRenderer; renderer->setPresentationTime(monotonicClockNanos); } + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_Renderer_nSetVsyncTime(JNIEnv *, jclass, + jlong nativeRenderer, jlong steadyClockTimeNano) { + Renderer *renderer = (Renderer *) nativeRenderer; + renderer->setVsyncTime(steadyClockTimeNano); +} diff --git a/android/filament-android/src/main/java/com/google/android/filament/Engine.java b/android/filament-android/src/main/java/com/google/android/filament/Engine.java index 5a28d1eae8..6c4c5119e3 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/Engine.java +++ b/android/filament-android/src/main/java/com/google/android/filament/Engine.java @@ -1292,7 +1292,6 @@ public class Engine { /** * Switch the command queue to unprotected mode. Protected mode can be activated via * Renderer::beginFrame() using a protected SwapChain. - * @see Renderer * @see SwapChain */ @@ -1300,6 +1299,13 @@ public class Engine { nUnprotected(getNativeObject()); } + /** + * Get the current time. This is a convenience function that simply returns the + * time in nanosecond since epoch of std::chrono::steady_clock. + * @return current time in nanosecond since epoch of std::chrono::steady_clock. + * @see Renderer#beginFrame + */ + public static native long getSteadyClockTimeNano(); @UsedByReflection("TextureHelper.java") public long getNativeObject() { diff --git a/android/filament-android/src/main/java/com/google/android/filament/Renderer.java b/android/filament-android/src/main/java/com/google/android/filament/Renderer.java index ab70e9ed38..4fb447db2c 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/Renderer.java +++ b/android/filament-android/src/main/java/com/google/android/filament/Renderer.java @@ -284,6 +284,19 @@ public class Renderer { nSetPresentationTime(getNativeObject(), monotonicClockNanos); } + /** + * The use of this method is optional. It sets the VSYNC time expressed as the duration in + * nanosecond since epoch of std::chrono::steady_clock. + * If called, passing 0 to frameTimeNanos in Renderer.BeginFrame will use this + * time instead. + * @param steadyClockTimeNano duration in nanosecond since epoch of std::chrono::steady_clock + * @see Engine#getSteadyClockTimeNano + * @see Renderer#beginFrame + */ + public void setVsyncTime(long steadyClockTimeNano) { + nSetVsyncTime(getNativeObject(), steadyClockTimeNano); + } + /** * Sets up a frame for this Renderer. *

beginFrame manages frame pacing, and returns whether or not a frame should be @@ -702,6 +715,7 @@ public class Renderer { } private static native void nSetPresentationTime(long nativeObject, long monotonicClockNanos); + private static native void nSetVsyncTime(long nativeObject, long steadyClockTimeNano); private static native boolean nBeginFrame(long nativeRenderer, long nativeSwapChain, long frameTimeNanos); private static native void nEndFrame(long nativeRenderer); private static native void nRender(long nativeRenderer, long nativeView); diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h index 2aed82736f..1c44fe9ab9 100644 --- a/filament/include/filament/Engine.h +++ b/filament/include/filament/Engine.h @@ -1021,6 +1021,21 @@ public: void resetBackendState() noexcept; #endif + /** + * Get the current time. This is a convenience function that simply returns the + * time in nanosecond since epoch of std::chrono::steady_clock. + * A possible implementation is: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * return std::chrono::steady_clock::now().time_since_epoch().count(); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @return current time in nanosecond since epoch of std::chrono::steady_clock. + * @see Renderer::beginFrame() + */ + static uint64_t getSteadyClockTimeNano() noexcept; + + DebugRegistry& getDebugRegistry() noexcept; protected: diff --git a/filament/include/filament/Renderer.h b/filament/include/filament/Renderer.h index fdc291b1fd..83b6281604 100644 --- a/filament/include/filament/Renderer.h +++ b/filament/include/filament/Renderer.h @@ -227,6 +227,17 @@ public: static constexpr CopyFrameFlag CLEAR = 0x4; + /** + * The use of this method is optional. It sets the VSYNC time expressed as the duration in + * nanosecond since epoch of std::chrono::steady_clock. + * If called, passing 0 to vsyncSteadyClockTimeNano in Renderer::BeginFrame will use this + * time instead. + * @param steadyClockTimeNano duration in nanosecond since epoch of std::chrono::steady_clock + * @see Engine::getSteadyClockTimeNano() + * @see Renderer::BeginFrame() + */ + void setVsyncTime(uint64_t steadyClockTimeNano) noexcept; + /** * Set-up a frame for this Renderer. * diff --git a/filament/src/Engine.cpp b/filament/src/Engine.cpp index ad110dbc92..477a0871c8 100644 --- a/filament/src/Engine.cpp +++ b/filament/src/Engine.cpp @@ -39,6 +39,8 @@ #include #include +#include + #include #include @@ -361,7 +363,7 @@ const Engine::Config& Engine::getConfig() const noexcept { return downcast(this)->getConfig(); } -bool Engine::isStereoSupported(StereoscopicType stereoscopicType) const noexcept { +bool Engine::isStereoSupported(StereoscopicType) const noexcept { return downcast(this)->isStereoSupported(); } @@ -369,6 +371,10 @@ size_t Engine::getMaxStereoscopicEyes() noexcept { return FEngine::getMaxStereoscopicEyes(); } +uint64_t Engine::getSteadyClockTimeNano() noexcept { + return std::chrono::steady_clock::now().time_since_epoch().count(); +} + #if defined(__EMSCRIPTEN__) void Engine::resetBackendState() noexcept { downcast(this)->resetBackendState(); diff --git a/filament/src/Renderer.cpp b/filament/src/Renderer.cpp index 85d58f9ec1..00837319b2 100644 --- a/filament/src/Renderer.cpp +++ b/filament/src/Renderer.cpp @@ -89,4 +89,8 @@ void Renderer::renderStandaloneView(View const* view) { downcast(this)->renderStandaloneView(downcast(view)); } +void Renderer::setVsyncTime(uint64_t steadyClockTimeNano) noexcept { + downcast(this)->setVsyncTime(steadyClockTimeNano); +} + } // namespace filament diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index 15094a0759..b27486542f 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -232,6 +232,10 @@ void FRenderer::setPresentationTime(int64_t monotonic_clock_ns) { driver.setPresentationTime(monotonic_clock_ns); } +void FRenderer::setVsyncTime(uint64_t steadyClockTimeNano) noexcept { + mVsyncSteadyClockTimeNano = steadyClockTimeNano; +} + bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano) { assert_invariant(swapChain); @@ -252,6 +256,11 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN } #endif + if (!vsyncSteadyClockTimeNano) { + vsyncSteadyClockTimeNano = mVsyncSteadyClockTimeNano; + mVsyncSteadyClockTimeNano = 0; + } + // get the timestamp as soon as possible using namespace std::chrono; const steady_clock::time_point now{ steady_clock::now() }; diff --git a/filament/src/details/Renderer.h b/filament/src/details/Renderer.h index 056d559977..263f899886 100644 --- a/filament/src/details/Renderer.h +++ b/filament/src/details/Renderer.h @@ -29,9 +29,6 @@ #include "backend/DriverApiForward.h" -#include -#include - #include #include @@ -41,8 +38,18 @@ #include #include +#include + #include +#include +#include +#include +#include + +#include +#include + namespace filament { namespace backend { @@ -78,6 +85,8 @@ public: void setPresentationTime(int64_t monotonic_clock_ns); + void setVsyncTime(uint64_t steadyClockTimeNano) noexcept; + // start a frame bool beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano); @@ -187,6 +196,7 @@ private: backend::TargetBufferFlags mClearFlags{}; tsl::robin_set mPreviousRenderTargets; std::function mBeginFrameInternal; + uint64_t mVsyncSteadyClockTimeNano = 0; }; FILAMENT_DOWNCAST(Renderer) diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index 735305a563..e1bc5c3755 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -388,6 +388,8 @@ class_("Engine") return Engine::create(); }, allow_raw_pointers()) + .class_function("getSteadyClockTimeNano", &Engine::getSteadyClockTimeNano) + .function("unprotected", &Engine::unprotected) .function("enableAccurateTranslations", &Engine::enableAccurateTranslations) @@ -623,6 +625,8 @@ class_("Renderer") }), allow_raw_pointers()) .function("_setClearOptions", &Renderer::setClearOptions, allow_raw_pointers()) .function("getClearOptions", &Renderer::getClearOptions) + .function("setPresentationTime", &Renderer::setPresentationTime) + .function("setVsyncTime", &Renderer::setVsyncTime) .function("beginFrame", EMBIND_LAMBDA(bool, (Renderer* self, SwapChain* swapChain), { return self->beginFrame(swapChain); }), allow_raw_pointers())