Skip to content

Commit 70d4166

Browse files
committed
Add Renderer::shouldRenderFrame() API
FIXES=[410463814]
1 parent 08c783e commit 70d4166

File tree

10 files changed

+71
-19
lines changed

10 files changed

+71
-19
lines changed

NEW_RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
99
## Release notes for next branch cut
1010

1111
- Rename `sampler` parameter `unfilterable` to `filterable` [⚠️ **New Material Version**]
12+
- Added `Renderer::shouldRenderFrame()`

android/filament-android/src/main/cpp/Renderer.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ Java_com_google_android_filament_Renderer_nSkipFrame(JNIEnv *, jclass, jlong nat
3636
renderer->skipFrame(uint64_t(vsyncSteadyClockTimeNano));
3737
}
3838

39+
extern "C" JNIEXPORT jboolean JNICALL
40+
Java_com_google_android_filament_Renderer_nShouldRenderFrame(JNIEnv *, jclass, jlong nativeRenderer) {
41+
Renderer *renderer = (Renderer *) nativeRenderer;
42+
return (jboolean) renderer->shouldRenderFrame();
43+
}
44+
3945
extern "C" JNIEXPORT jboolean JNICALL
4046
Java_com_google_android_filament_Renderer_nBeginFrame(JNIEnv *, jclass, jlong nativeRenderer,
4147
jlong nativeSwapChain, jlong frameTimeNanos) {

android/filament-android/src/main/java/com/google/android/filament/Renderer.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,21 @@ public void skipFrame(long vsyncSteadyClockTimeNano) {
311311
nSkipFrame(getNativeObject(), vsyncSteadyClockTimeNano);
312312
}
313313

314+
/**
315+
* Returns true if the current frame should be rendered.
316+
*
317+
* This is a convenience method that returns the same value as {@link #beginFrame}.
318+
*
319+
* @return
320+
* <code>false</code> the current frame should be skipped<br>
321+
* <code>true</code> the current frame can be rendered
322+
*
323+
* @see #beginFrame
324+
*/
325+
public boolean shouldRenderFrame() {
326+
return nShouldRenderFrame(getNativeObject());
327+
}
328+
314329
/**
315330
* Sets up a frame for this <code>Renderer</code>.
316331
* <p><code>beginFrame</code> manages frame pacing, and returns whether or not a frame should be
@@ -731,6 +746,7 @@ void clearNativeObject() {
731746
private static native void nSetPresentationTime(long nativeObject, long monotonicClockNanos);
732747
private static native void nSetVsyncTime(long nativeObject, long steadyClockTimeNano);
733748
private static native void nSkipFrame(long nativeObject, long vsyncSteadyClockTimeNano);
749+
private static native boolean nShouldRenderFrame(long nativeObject);
734750
private static native boolean nBeginFrame(long nativeRenderer, long nativeSwapChain, long frameTimeNanos);
735751
private static native void nEndFrame(long nativeRenderer);
736752
private static native void nRender(long nativeRenderer, long nativeView);

filament/include/filament/Renderer.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,23 @@ class UTILS_PUBLIC Renderer : public FilamentAPI {
280280
void skipFrame(uint64_t vsyncSteadyClockTimeNano = 0u);
281281

282282
/**
283-
* Set-up a frame for this Renderer.
283+
* Returns true if the current frame should be rendered.
284284
*
285-
* beginFrame() manages frame pacing, and returns whether or not a frame should be drawn. The
285+
* This is a convenience method that returns the same value as beginFrame().
286+
*
287+
* @return
288+
* *false* the current frame should be skipped,
289+
* *true* the current frame can be rendered
290+
*
291+
* @see
292+
* beginFrame()
293+
*/
294+
bool shouldRenderFrame() const noexcept;
295+
296+
/**
297+
* Set up a frame for this Renderer.
298+
*
299+
* beginFrame() manages frame-pacing, and returns whether a frame should be drawn. The
286300
* goal of this is to skip frames when the GPU falls behind in order to keep the frame
287301
* latency low.
288302
*

filament/src/FrameSkipper.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2016 The Android Open Source Project
2+
* Copyright (C) 2025 The Android Open Source Project
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222
#include <utils/debug.h>
2323

2424
#include <algorithm>
25+
#include <utility>
2526

2627
#include <stddef.h>
2728

@@ -31,20 +32,20 @@ using namespace utils;
3132
using namespace backend;
3233

3334
FrameSkipper::FrameSkipper(size_t const latency) noexcept
34-
: mLast(std::clamp(latency, size_t(1), MAX_FRAME_LATENCY) - 1) {
35+
: mLatency(std::clamp(latency, size_t(1), MAX_FRAME_LATENCY) - 1) {
3536
}
3637

3738
FrameSkipper::~FrameSkipper() noexcept = default;
3839

3940
void FrameSkipper::terminate(DriverApi& driver) noexcept {
40-
for (auto fence : mDelayedFences) {
41+
for (auto& fence : mDelayedFences) {
4142
if (fence) {
42-
driver.destroyFence(fence);
43+
driver.destroyFence(std::move(fence));
4344
}
4445
}
4546
}
4647

47-
bool FrameSkipper::beginFrame(DriverApi& driver) noexcept {
48+
bool FrameSkipper::shouldRenderFrame(DriverApi& driver) const noexcept {
4849
auto& fences = mDelayedFences;
4950
if (fences.front()) {
5051
// Do we have a latency old fence?
@@ -58,9 +59,9 @@ bool FrameSkipper::beginFrame(DriverApi& driver) noexcept {
5859
return true;
5960
}
6061

61-
void FrameSkipper::endFrame(DriverApi& driver) noexcept {
62+
void FrameSkipper::submitFrame(DriverApi& driver) noexcept {
6263
auto& fences = mDelayedFences;
63-
size_t const last = mLast;
64+
size_t const last = mLatency;
6465

6566
// pop the oldest fence and advance the other ones
6667
if (fences.front()) {

filament/src/FrameSkipper.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2016 The Android Open Source Project
2+
* Copyright (C) 2025 The Android Open Source Project
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -64,17 +64,17 @@ class FrameSkipper {
6464

6565
void terminate(backend::DriverApi& driver) noexcept;
6666

67-
// Returns false if we need to skip this frame, because the GPU is running behind the CPU;
68-
// In that case, don't call render endFrame()
69-
// Returns true if rendering can proceed. Always call endFrame() when done.
70-
bool beginFrame(backend::DriverApi& driver) noexcept;
67+
// Returns false if we should skip this frame because the GPU is running behind the CPU.
68+
// In that case, don't call submitFrame().
69+
// Returns true if rendering can proceed. Always call submitFrame() when done.
70+
bool shouldRenderFrame(backend::DriverApi& driver) const noexcept;
7171

72-
void endFrame(backend::DriverApi& driver) noexcept;
72+
void submitFrame(backend::DriverApi& driver) noexcept;
7373

7474
private:
7575
using Container = std::array<backend::Handle<backend::HwFence>, MAX_FRAME_LATENCY>;
76-
mutable Container mDelayedFences{};
77-
uint8_t const mLast;
76+
Container mDelayedFences{};
77+
uint8_t const mLatency;
7878
};
7979

8080
} // namespace filament

filament/src/Renderer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ void Renderer::skipFrame(uint64_t const vsyncSteadyClockTimeNano) {
5050
downcast(this)->skipFrame(vsyncSteadyClockTimeNano);
5151
}
5252

53+
bool Renderer::shouldRenderFrame() const noexcept {
54+
return downcast(this)->shouldRenderFrame();
55+
}
56+
5357
bool Renderer::beginFrame(SwapChain* swapChain, uint64_t const vsyncSteadyClockTimeNano) {
5458
return downcast(this)->beginFrame(downcast(swapChain), vsyncSteadyClockTimeNano);
5559
}

filament/src/details/Renderer.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,12 @@ void FRenderer::skipFrame(uint64_t vsyncSteadyClockTimeNano) {
296296
js.waitAndRelease(job);
297297
}
298298

299+
bool FRenderer::shouldRenderFrame() const noexcept {
300+
FEngine& engine = mEngine;
301+
FEngine::DriverApi& driver = engine.getDriverApi();
302+
return mFrameSkipper.shouldRenderFrame(driver);
303+
}
304+
299305
bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano) {
300306
assert_invariant(swapChain);
301307

@@ -389,7 +395,7 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
389395
engine.prepare();
390396
};
391397

392-
if (mFrameSkipper.beginFrame(driver)) {
398+
if (mFrameSkipper.shouldRenderFrame(driver)) {
393399
// if beginFrame() returns true, we are expecting a call to endFrame(),
394400
// so do the beginFrame work right now, instead of requiring a call to render()
395401
beginFrameInternal();
@@ -436,7 +442,7 @@ void FRenderer::endFrame() {
436442
}
437443

438444
mFrameInfoManager.endFrame(driver);
439-
mFrameSkipper.endFrame(driver);
445+
mFrameSkipper.submitFrame(driver);
440446

441447
driver.endFrame(mFrameId);
442448

filament/src/details/Renderer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ class FRenderer : public Renderer {
9494
// skip a frame
9595
void skipFrame(uint64_t vsyncSteadyClockTimeNano);
9696

97+
// Whether a frame should be rendered or not.
98+
bool shouldRenderFrame() const noexcept;
99+
97100
// start a frame
98101
bool beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano);
99102

web/filament-js/jsbindings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@ class_<Renderer>("Renderer")
628628
.function("setPresentationTime", &Renderer::setPresentationTime)
629629
.function("setVsyncTime", &Renderer::setVsyncTime)
630630
.function("skipFrame", &Renderer::skipFrame)
631+
.function("shouldRenderFrame", &Renderer::shouldRenderFrame)
631632
.function("beginFrame", EMBIND_LAMBDA(bool, (Renderer* self, SwapChain* swapChain), {
632633
return self->beginFrame(swapChain);
633634
}), allow_raw_pointers())

0 commit comments

Comments
 (0)