Skip to content

Commit

Permalink
Replay renderer partial deletion (#2136)
Browse files Browse the repository at this point in the history
* Header clean-up in player and replay renderers.

* Implement partial scene deletion when using the batch renderer.

* Separate batch replay renderer deletions from the main keyframe processing method.

* Review pass.

* Move cast into deletion processing function.

* Clear transform cache before use.

* Move BatchPlayerImplementation into its own file.

* Add BatchPlayerImplementation node deletion test.

* Clang-tidy fixes.
  • Loading branch information
0mdc authored Jun 27, 2023
1 parent 017dcdb commit aa731e7
Show file tree
Hide file tree
Showing 10 changed files with 423 additions and 204 deletions.
104 changes: 74 additions & 30 deletions src/esp/gfx/replay/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@

#include "Player.h"

#include <Corrade/Containers/StringStl.h>
#include <Corrade/Utility/Path.h>

#include "esp/assets/ResourceManager.h"
#include "esp/core/Esp.h"
#include "esp/gfx/replay/Keyframe.h"
#include "esp/io/Json.h"
#include "esp/io/JsonAllTypes.h"

#include <rapidjson/document.h>

namespace esp {
namespace gfx {
Expand Down Expand Up @@ -69,6 +64,17 @@ void AbstractSceneGraphPlayerImplementation::setNodeTransform(
.setRotation(rotation);
}

void AbstractSceneGraphPlayerImplementation::setNodeTransform(
const NodeHandle node,
const Mn::Matrix4& transform) {
(*reinterpret_cast<scene::SceneNode*>(node)).setTransformation(transform);
}

Mn::Matrix4 AbstractSceneGraphPlayerImplementation::hackGetNodeTransform(
const NodeHandle node) const {
return (*reinterpret_cast<scene::SceneNode*>(node)).transformation();
}

void AbstractSceneGraphPlayerImplementation::setNodeSemanticId(
const NodeHandle node,
const unsigned id) {
Expand Down Expand Up @@ -170,6 +176,7 @@ void Player::clearFrame() {
implementation_->deleteAssetInstances(createdInstances_);
createdInstances_.clear();
assetInfos_.clear();
creationInfos_.clear();
frameIndex_ = -1;
}

Expand All @@ -183,15 +190,6 @@ void Player::applyKeyframe(const Keyframe& keyframe) {
assetInfos_[assetInfo.filepath] = assetInfo;
}

// If all current instances are being deleted, clear the frame. This enables
// the implementation to clear its memory and optimize its internals.
bool frameCleared = keyframe.deletions.size() > 0 &&
createdInstances_.size() == keyframe.deletions.size();
if (frameCleared) {
implementation_->deleteAssetInstances(createdInstances_);
createdInstances_.clear();
}

for (const auto& pair : keyframe.creations) {
const auto& creation = pair.second;

Expand Down Expand Up @@ -223,27 +221,15 @@ void Player::applyKeyframe(const Keyframe& keyframe) {
const auto& instanceKey = pair.first;
CORRADE_INTERNAL_ASSERT(createdInstances_.count(instanceKey) == 0);
createdInstances_[instanceKey] = node;
creationInfos_[instanceKey] = adjustedCreation;
}

if (!frameCleared) {
for (const auto& deletionInstanceKey : keyframe.deletions) {
const auto& it = createdInstances_.find(deletionInstanceKey);
if (it == createdInstances_.end()) {
// missing instance for this key, probably due to a failed instance
// creation
continue;
}

implementation_->deleteAssetInstance(it->second);
createdInstances_.erase(deletionInstanceKey);
}
}
hackProcessDeletions(keyframe);

for (const auto& pair : keyframe.stateUpdates) {
const auto& it = createdInstances_.find(pair.first);
if (it == createdInstances_.end()) {
// missing instance for this key, probably due to a failed instance
// creation
// Missing instance for this key due to a failed instance creation
continue;
}
auto* node = it->second;
Expand All @@ -258,6 +244,64 @@ void Player::applyKeyframe(const Keyframe& keyframe) {
}
}

void Player::hackProcessDeletions(const Keyframe& keyframe) {
// HACK: Classic and batch renderers currently handle deletions differently.
// The batch renderer can only clear the scene entirely; it cannot delete
// individual objects. To process deletions, all instances are deleted,
// remaining instances are re-created and latest transform updates are
// re-applied.
bool isClassicReplayRenderer =
dynamic_cast<AbstractSceneGraphPlayerImplementation*>(
implementation_.get()) != nullptr;
if (isClassicReplayRenderer) {
for (const auto& deletionInstanceKey : keyframe.deletions) {
const auto& it = createdInstances_.find(deletionInstanceKey);
if (it == createdInstances_.end()) {
// Missing instance for this key due to a failed instance creation
continue;
}

implementation_->deleteAssetInstance(it->second);
createdInstances_.erase(deletionInstanceKey);
}
} else if (keyframe.deletions.size() > 0) {
// Cache latest transforms
latestTransformCache_.clear();
for (const auto& pair : this->createdInstances_) {
const RenderAssetInstanceKey key = pair.first;
latestTransformCache_[key] =
implementation_->hackGetNodeTransform(pair.second);
}

// Delete all instances
implementation_->deleteAssetInstances(createdInstances_);

// Remove deleted instances from records
for (const auto& deletion : keyframe.deletions) {
const auto& createInstanceIt = createdInstances_.find(deletion);
if (createInstanceIt == createdInstances_.end()) {
// Missing instance for this key due to a failed instance creation
continue;
}
createdInstances_.erase(createInstanceIt);
creationInfos_.erase(deletion);
}

for (const auto& pair : createdInstances_) {
const auto key = pair.first;
const auto& creationInfo = creationInfos_[key];
auto* instance = implementation_->loadAndCreateRenderAssetInstance(
assetInfos_[creationInfo.filepath], creationInfo);

// Replace dangling reference
createdInstances_[key] = instance;

// Re-apply latest transform updates
implementation_->setNodeTransform(instance, latestTransformCache_[key]);
}
}
}

void Player::appendKeyframe(Keyframe&& keyframe) {
keyframes_.emplace_back(std::move(keyframe));
}
Expand Down
29 changes: 28 additions & 1 deletion src/esp/gfx/replay/Player.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class AbstractPlayerImplementation {
instances) = 0;

/**
* @brief Set node transform
* @brief Set node transform from translation and rotation components.
*
* The @p handle is expected to be returned from an earlier call to
* @ref loadAndCreateRenderAssetInstance() on the same instance.
Expand All @@ -94,6 +94,23 @@ class AbstractPlayerImplementation {
const Magnum::Vector3& translation,
const Magnum::Quaternion& rotation) = 0;

/**
* @brief Set node transform.
*
* The @p handle is expected to be returned from an earlier call to
* @ref loadAndCreateRenderAssetInstance() on the same instance.
*/
virtual void setNodeTransform(NodeHandle node,
const Mn::Matrix4& transform) = 0;

/**
* @brief Get node transform.
*
* The @p handle is expected to be returned from an earlier call to
* @ref loadAndCreateRenderAssetInstance() on the same instance.
*/
virtual Mn::Matrix4 hackGetNodeTransform(NodeHandle node) const = 0;

/**
* @brief Set node semantic ID
*
Expand Down Expand Up @@ -131,6 +148,10 @@ class AbstractSceneGraphPlayerImplementation
const Magnum::Vector3& translation,
const Magnum::Quaternion& rotation) override;

void setNodeTransform(NodeHandle node, const Mn::Matrix4& transform) override;

Mn::Matrix4 hackGetNodeTransform(NodeHandle node) const override;

void setNodeSemanticId(NodeHandle node, unsigned id) override;
};

Expand Down Expand Up @@ -251,13 +272,19 @@ class Player {
void applyKeyframe(const Keyframe& keyframe);
void readKeyframesFromJsonDocument(const rapidjson::Document& d);
void clearFrame();
void hackProcessDeletions(const Keyframe& keyframe);

std::shared_ptr<AbstractPlayerImplementation> implementation_;

int frameIndex_ = -1;
std::vector<Keyframe> keyframes_;
std::unordered_map<std::string, esp::assets::AssetInfo> assetInfos_;
std::unordered_map<RenderAssetInstanceKey, NodeHandle> createdInstances_;
std::unordered_map<RenderAssetInstanceKey,
assets::RenderAssetInstanceCreationInfo>
creationInfos_;
std::unordered_map<RenderAssetInstanceKey, Mn::Matrix4>
latestTransformCache_{};
std::set<std::string> failedFilepaths_;

ESP_SMART_POINTERS(Player)
Expand Down
3 changes: 0 additions & 3 deletions src/esp/sim/AbstractReplayRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

#include "AbstractReplayRenderer.h"

#include <Magnum/Math/Functions.h>
#include <Magnum/Math/Vector2.h>

#include "esp/gfx/replay/Player.h"

namespace esp {
Expand Down
7 changes: 0 additions & 7 deletions src/esp/sim/AbstractReplayRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,9 @@
#ifndef ESP_SIM_ABSTRACTREPLAYRENDERER_H_
#define ESP_SIM_ABSTRACTREPLAYRENDERER_H_

#include <Magnum/GL/GL.h>
#include <Magnum/Magnum.h>

#include "esp/core/Check.h"
#include "esp/core/Esp.h"
#include "esp/geo/Geo.h"
#include "esp/gfx/DebugLineRender.h"

#include <memory>

namespace esp {

namespace gfx {
Expand Down
Loading

0 comments on commit aa731e7

Please sign in to comment.