Skip to content

Commit

Permalink
improve FrameSkipper when disregarding skipping
Browse files Browse the repository at this point in the history
It is legal for the app to draw a frame even when FrameSkipper 
detects that a frame should be skipped. In that case we used to
overwrite the most recent fence, but this wasn't ideal. We now
proceed as if the fence had signaled, i.e. we destroy it and
move all the fences up, creating a new one at the end of the 
delayed array.
  • Loading branch information
pixelflinger committed Aug 20, 2024
1 parent b70aa43 commit 3351db1
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 19 deletions.
43 changes: 25 additions & 18 deletions filament/src/FrameSkipper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,22 @@

#include "FrameSkipper.h"

#include <utils/Log.h>
#include <backend/DriverEnums.h>

#include <utils/compiler.h>
#include <utils/debug.h>

#include <algorithm>

#include <stddef.h>

namespace filament {

using namespace utils;
using namespace backend;

FrameSkipper::FrameSkipper(size_t latency) noexcept
: mLast(latency - 1) {
: mLast(std::max(latency, MAX_FRAME_LATENCY) - 1) {
assert_invariant(latency <= MAX_FRAME_LATENCY);
}

Expand All @@ -41,31 +47,32 @@ void FrameSkipper::terminate(DriverApi& driver) noexcept {

bool FrameSkipper::beginFrame(DriverApi& driver) noexcept {
auto& fences = mDelayedFences;
auto fence = fences.front();
if (fence) {
auto status = driver.getFenceStatus(fence);
if (status == FenceStatus::TIMEOUT_EXPIRED) {
// Sync not ready, skip frame
if (fences.front()) {
// Do we have a latency old fence?
auto status = driver.getFenceStatus(fences.front());
if (UTILS_UNLIKELY(status == FenceStatus::TIMEOUT_EXPIRED)) {
// The fence hasn't signaled yet, skip this frame
return false;
}
assert_invariant(status == FenceStatus::CONDITION_SATISFIED);
driver.destroyFence(fence);
}
// shift all fences down by 1
std::move(fences.begin() + 1, fences.end(), fences.begin());
fences.back() = {};
return true;
}

void FrameSkipper::endFrame(DriverApi& driver) noexcept {
// If the user produced a new frame despite the fact that the previous one wasn't finished
// (i.e. FrameSkipper::beginFrame() returned false), we need to make sure to replace
// a fence that might be here already)
auto& fence = mDelayedFences[mLast];
if (fence) {
driver.destroyFence(fence);
auto& fences = mDelayedFences;
size_t const last = mLast;

// pop the oldest fence and advance the other ones
if (fences.front()) {
driver.destroyFence(fences.front());
}
fence = driver.createFence();
std::move(fences.begin() + 1, fences.end(), fences.begin());

// add a new fence to the end
assert_invariant(!fences[last]);

fences[last] = driver.createFence();
}

} // namespace filament
5 changes: 4 additions & 1 deletion filament/src/FrameSkipper.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@

#include <array>

#include <stddef.h>
#include <stdint.h>

namespace filament {

/*
Expand Down Expand Up @@ -60,7 +63,7 @@ class FrameSkipper {
private:
using Container = std::array<backend::Handle<backend::HwFence>, MAX_FRAME_LATENCY>;
mutable Container mDelayedFences{};
size_t mLast;
uint8_t const mLast;
};

} // namespace filament
Expand Down

0 comments on commit 3351db1

Please sign in to comment.