Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1b8fc8f
call .get() to fix test
calebbuffa Apr 9, 2026
5eece01
create MainThreadOnly and TileObserver
calebbuffa Apr 9, 2026
89bc16d
create TileHiearchy and TileOverlaySystem
calebbuffa Apr 9, 2026
c282c89
create TileUnloadQueue
calebbuffa Apr 9, 2026
8b64f4b
make tile state update a function callback
calebbuffa Apr 9, 2026
fa17459
create TileSelection
calebbuffa Apr 9, 2026
aafcd22
tile selection delegates to free functions
calebbuffa Apr 9, 2026
f4c06d9
update content calls to use .get()
calebbuffa Apr 9, 2026
836f709
create free selectTiles test
calebbuffa Apr 9, 2026
32abaaa
remov unused makeCloseViewstate function to fix -Wunused-function ci …
calebbuffa Apr 10, 2026
acb9a7d
document undocumented public members
calebbuffa Apr 10, 2026
9abf209
satisfy clang-tidy includes
calebbuffa Apr 10, 2026
cb0aac9
Update comment TileOverlaySystem.h
calebbuffa Apr 11, 2026
1a576f8
move selectTiles to top
calebbuffa Apr 13, 2026
051f3ae
revert unnecessary changes based on feedback
calebbuffa Apr 13, 2026
47205f4
Merge branch 'ownership' of https://github.com/calebbuffa/cesium-nati…
calebbuffa Apr 13, 2026
d51f930
remove [main-thread-only] comment
calebbuffa Apr 13, 2026
1a9ddf5
revert _overlayCollection rename
calebbuffa Apr 13, 2026
792878b
fix comments
calebbuffa Apr 24, 2026
e33a898
update markIneligble call
calebbuffa Apr 24, 2026
9eaca5c
pass ViewUpdateResult instead of recreating in selectTiles
calebbuffa Apr 24, 2026
d7a8b89
format
calebbuffa Apr 24, 2026
7d1de8e
fix const cast
calebbuffa Apr 24, 2026
3e6c4eb
fix orphaned comment
calebbuffa Apr 24, 2026
488eb2d
fix remaining issues
calebbuffa Apr 24, 2026
abded91
Merge branch 'main' of https://github.com/CesiumGS/cesium-native into…
calebbuffa Apr 27, 2026
37018d3
Merge branch 'main' of https://github.com/CesiumGS/cesium-native into…
calebbuffa May 11, 2026
4112199
remove TraversalContext
calebbuffa May 13, 2026
44aec15
add this->_queue
calebbuffa May 13, 2026
2c8f6bf
fix docs/comments
calebbuffa May 13, 2026
7d9efb3
remove unused parameters
calebbuffa May 13, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class CESIUM3DTILESSELECTION_API Tile final {
/**
* @brief Returns the parent of this tile in the tile hierarchy.
*
* This will be the `nullptr` if this is the root tile.
* This will be `nullptr` if this is the root tile.
*
* @return The parent.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#pragma once

#include <Cesium3DTilesSelection/Tile.h>

namespace Cesium3DTilesSelection {

/**
* @brief LRU list of tiles eligible for content eviction.
*
* Head is least-recently-used, tail is most-recently-used.
*
* @private
*/
Comment thread
calebbuffa marked this conversation as resolved.
class TileUnloadQueue {
public:
TileUnloadQueue() noexcept = default;
~TileUnloadQueue() noexcept = default;

TileUnloadQueue(const TileUnloadQueue&) = delete;
TileUnloadQueue& operator=(const TileUnloadQueue&) = delete;
TileUnloadQueue(TileUnloadQueue&&) noexcept = default;
TileUnloadQueue& operator=(TileUnloadQueue&&) noexcept = default;

/**
* @brief Adds `tile` to the tail (most-recently-used end). No-op if already
* tracked.
*/
void markEligible(Tile& tile) noexcept {
if (!this->_queue.contains(tile)) {
this->_queue.insertAtTail(tile);
}
}

/** @brief Removes `tile` from the queue. No-op if not present. */
void markIneligible(Tile& tile) noexcept { this->_queue.remove(tile); }

/** @brief Returns true if `tile` is currently in the queue. */
bool contains(const Tile& tile) const noexcept {
return this->_queue.contains(tile);
}

/** @brief Returns the least-recently-used tile, or nullptr. */
Tile* head() noexcept { return this->_queue.head(); }

/** @brief Returns the tile following `tile` in LRU order. */
Tile* next(Tile& tile) noexcept { return this->_queue.next(tile); }

private:
Tile::UnusedLinkedList _queue;
};

} // namespace Cesium3DTilesSelection
158 changes: 3 additions & 155 deletions Cesium3DTilesSelection/include/Cesium3DTilesSelection/Tileset.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <Cesium3DTilesSelection/TilesetExternals.h>
#include <Cesium3DTilesSelection/TilesetLoadFailureDetails.h>
#include <Cesium3DTilesSelection/TilesetOptions.h>
#include <Cesium3DTilesSelection/TilesetSelection.h>
#include <Cesium3DTilesSelection/TilesetViewGroup.h>
#include <Cesium3DTilesSelection/ViewState.h>
#include <Cesium3DTilesSelection/ViewUpdateResult.h>
Expand Down Expand Up @@ -468,149 +469,6 @@ class CESIUM3DTILESSELECTION_API Tileset final {
Tileset& operator=(const Tileset& rhs) = delete;

private:
/**
* @brief The result of traversing one branch of the tile hierarchy.
*
* Instances of this structure are created by the `_visit...` functions,
* and summarize the information that was gathered during the traversal
* of the respective branch, so that this information can be used by
* the parent to decide on the further traversal process.
*/
struct TraversalDetails {
/**
* @brief Whether all selected tiles in this tile's subtree are renderable.
*
* This is `true` if all selected (i.e. not culled or refined) tiles in this
* tile's subtree are renderable. If the subtree is renderable, we'll render
* it; no drama.
*/
bool allAreRenderable = true;

/**
* @brief Whether any tile in this tile's subtree was rendered in the last
* frame.
*
* This is `true` if any tiles in this tile's subtree were rendered last
* frame. If any were, we must render the subtree rather than this tile,
* because rendering this tile would cause detail to vanish that was visible
* last frame, and that's no good.
*/
bool anyWereRenderedLastFrame = false;

/**
* @brief The number of selected tiles in this tile's subtree that are not
* yet renderable.
*
* Counts the number of selected tiles in this tile's subtree that are
* not yet ready to be rendered because they need more loading. Note that
* this value will _not_ necessarily be zero when
* `allAreRenderable` is `true`, for subtle reasons.
* When `allAreRenderable` and `anyWereRenderedLastFrame` are both `false`,
* we will render this tile instead of any tiles in its subtree and the
* `allAreRenderable` value for this tile will reflect only whether _this_
* tile is renderable. The `notYetRenderableCount` value, however, will
* still reflect the total number of tiles that we are waiting on, including
* the ones that we're not rendering. `notYetRenderableCount` is only reset
* when a subtree is removed from the render queue because the
* `notYetRenderableCount` exceeds the
* {@link TilesetOptions::loadingDescendantLimit}.
*/
uint32_t notYetRenderableCount = 0;
};

TraversalDetails _renderLeaf(
const TilesetFrameState& frameState,
Tile& tile,
double tilePriority,
double tileSse,
ViewUpdateResult& result);
TraversalDetails _renderInnerTile(
const TilesetFrameState& frameState,
Tile& tile,
double tileSse,
ViewUpdateResult& result);
bool _kickDescendantsAndRenderTile(
const TilesetFrameState& frameState,
Tile& tile,
ViewUpdateResult& result,
TraversalDetails& traversalDetails,
size_t firstRenderedDescendantIndex,
const TilesetViewGroup::LoadQueueCheckpoint& loadQueueBeforeChildren,
bool queuedForLoad,
double tilePriority,
double tileSse);
TileOcclusionState _checkOcclusion(const Tile& tile);

TraversalDetails _visitTile(
const TilesetFrameState& frameState,
uint32_t depth,
bool meetsSse,
bool ancestorMeetsSse,
Tile& tile,
double tilePriority,
double tileSse,
ViewUpdateResult& result);

struct CullResult {
// whether we should visit this tile
bool shouldVisit = true;
// whether this tile was culled (Note: we might still want to visit it)
bool culled = false;
};

// TODO: abstract these into a composable culling interface.
void _frustumCull(
const Tile& tile,
const TilesetFrameState& frameState,
bool cullWithChildrenBounds,
CullResult& cullResult);
void _fogCull(
const TilesetFrameState& frameState,
const std::vector<double>& distances,
CullResult& cullResult);
double _computeSse(
const std::vector<ViewState>& frustums,
const Tile& tile,
const std::vector<double>& distances) const noexcept;
bool _meetsSseThreshold(double sse, bool culled) const noexcept;

TraversalDetails _visitTileIfNeeded(
const TilesetFrameState& frameState,
uint32_t depth,
bool ancestorMeetsSse,
Tile& tile,
ViewUpdateResult& result);
TraversalDetails _visitVisibleChildrenNearToFar(
const TilesetFrameState& frameState,
uint32_t depth,
bool ancestorMeetsSse,
Tile& tile,
ViewUpdateResult& result);

/**
* @brief When called on an additive-refined tile, queues it for load and adds
* it to the render list.
*
* For replacement-refined tiles, this method does nothing and returns false.
*
* @param tile The tile to potentially load and render.
* @param result The current view update result.
* @param tilePriority The load priority of this tile.
* priority.
* @param tileSse The screen space error of this tile.
* @param queuedForLoad True if this tile has already been queued for loading.
* @return true The additive-refined tile was queued for load and added to the
* render list.
* @return false The non-additive-refined tile was ignored.
*/
bool _loadAndRenderAdditiveRefinedTile(
const TilesetFrameState& frameState,
Tile& tile,
ViewUpdateResult& result,
double tilePriority,
double tileSse,
bool queuedForLoad);

void _unloadCachedTiles(double timeBudget) noexcept;

void _updateLodTransitions(
Expand All @@ -627,8 +485,8 @@ class CESIUM3DTILESSELECTION_API Tileset final {
// selection.
std::vector<double> _distances;

// Holds the occlusion proxies of the children of a tile. Store them in this
// scratch variable so that it can allocate only when growing bigger.
// Holds the occlusion proxies of the children of a tile, to avoid
// per-frame allocation.
std::vector<const TileOcclusionRendererProxy*> _childOcclusionProxies;

CesiumUtility::IntrusivePointer<TilesetContentManager>
Expand All @@ -637,16 +495,6 @@ class CESIUM3DTILESSELECTION_API Tileset final {
std::list<TilesetHeightRequest> _heightRequests;

TilesetViewGroup _defaultViewGroup;

void addTileToLoadQueue(
const TilesetFrameState& frameState,
Tile& tile,
TileLoadPriorityGroup priorityGroup,
double priority);

static TraversalDetails createTraversalDetailsForSingleTile(
const TilesetFrameState& frameState,
const Tile& tile);
};

} // namespace Cesium3DTilesSelection
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
#include <Cesium3DTilesSelection/ViewState.h>

#include <cstdint>
#include <functional>
#include <vector>

namespace Cesium3DTilesSelection {

class Tile;
class TilesetViewGroup;

/**
Expand All @@ -29,6 +31,13 @@ class TilesetFrameState {
* @brief The computed fog density for each frustum.
*/
std::vector<double> fogDensities;

/**
* @brief Called once per visited tile to advance its content state (loading,
* finalization, child creation). Set by Tileset::updateViewGroup; may be
* null when testing selectTiles directly.
*/
std::function<void(Tile&)> tileStateUpdater;
};

} // namespace Cesium3DTilesSelection
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#pragma once

#include <Cesium3DTilesSelection/Library.h>
#include <Cesium3DTilesSelection/ViewUpdateResult.h>

#include <vector>

namespace Cesium3DTilesSelection {

class Tile;
class TilesetFrameState;
class TilesetExternals;
struct TilesetOptions;
class TileOcclusionRendererProxy;

/**
* @brief Per-frame inputs for the tile selection algorithm.
*/
struct TileSelectionContext {
/** @brief The tileset configuration options. */
const TilesetOptions& options;
/** @brief External interfaces (asset accessor, task processor, etc.). */
const TilesetExternals& externals;
/** @brief Scratch buffer reused across frames to avoid allocating them on the
* heap during selection. */
std::vector<double>& scratchDistances;
/** @brief Scratch buffer reused across frames to avoid allocating them on the
* heap during selection. Holds the occlusion proxies of the children of a
* tile. */
std::vector<const TileOcclusionRendererProxy*>& scratchOcclusionProxies;
};

/**
* @brief Runs the tile selection / LOD traversal algorithm.
*
* Populates `result` with the tiles to render this frame. The view group in
* `frameState` also receives load queue updates.
*
* @param context Configuration, external dependencies, and scratch buffers.
* @param frameState Per-frame view parameters and the view group to update.
* @param rootTile Root of the tile hierarchy to traverse.
* @param result Filled with the selected tiles and statistics for this frame.
Comment thread
calebbuffa marked this conversation as resolved.
*
* @private
*/
Comment thread
calebbuffa marked this conversation as resolved.
CESIUM3DTILESSELECTION_API void selectTiles(
const TileSelectionContext& context,
const TilesetFrameState& frameState,
Tile& rootTile,
ViewUpdateResult& result);
Comment thread
calebbuffa marked this conversation as resolved.

} // namespace Cesium3DTilesSelection
Loading
Loading