Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion gl_engine/AvalancheWarningLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "ShaderProgram.h"
#include "ShaderRegistry.h"
#include "TileGeometry.h"
#include <QDebug>
#include <QOpenGLExtraFunctions>
#include <QtAssert>
#include <TextureLayer.h>
Expand Down Expand Up @@ -104,8 +105,11 @@ void AvalancheWarningLayer::update_gpu_tiles(const std::vector<nucleus::tile::Id
Q_ASSERT(tile.id.zoom_level < 100);
Q_ASSERT(tile.texture);

// find empty spot and upload texture
const auto layer_index = m_gpu_array_helper.add_tile(tile.id);
if (layer_index == nucleus::tile::GpuArrayHelper::invalid_layer) {
qWarning() << "AvalancheWarningLayer: texture array full, dropping remaining tiles this update";
break;
}
m_texture_array->upload(*tile.texture, layer_index);
}
}
Expand Down
6 changes: 5 additions & 1 deletion gl_engine/TextureLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "ShaderRegistry.h"
#include "Texture.h"
#include "TileGeometry.h"
#include <QDebug>
#include <QOpenGLExtraFunctions>
#include <QtAssert>

Expand Down Expand Up @@ -90,8 +91,11 @@ void TextureLayer::update_gpu_tiles(const std::vector<nucleus::tile::Id>& delete
Q_ASSERT(tile.id.zoom_level < 100);
Q_ASSERT(tile.texture);

// find empty spot and upload texture
const auto layer_index = m_gpu_array_helper.add_tile(tile.id);
if (layer_index == nucleus::tile::GpuArrayHelper::invalid_layer) {
qWarning() << "TextureLayer: texture array full, dropping remaining tiles this update";
break;
}
m_texture_array->upload(*tile.texture, layer_index);
}
}
Expand Down
5 changes: 4 additions & 1 deletion gl_engine/TileGeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,11 @@ void TileGeometry::update_gpu_tiles(const std::vector<radix::tile::Id>& deleted_
Q_ASSERT(tile.id.zoom_level < 100);
Q_ASSERT(tile.surface);

// find empty spot and upload texture
const auto layer_index = m_gpu_array_helper.add_tile(tile.id);
if (layer_index == nucleus::tile::GpuArrayHelper::invalid_layer) {
qWarning() << "TileGeometry: DTM texture array full, dropping remaining tiles this update";
break;
}
m_dtm_textures->upload(*tile.surface, layer_index);
}
}
Expand Down
57 changes: 38 additions & 19 deletions nucleus/tile/GpuArrayHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,46 +23,65 @@
namespace nucleus::tile {
GpuArrayHelper::GpuArrayHelper() { }

unsigned GpuArrayHelper::add_tile(const tile::Id& id)
uint16_t GpuArrayHelper::add_tile(const tile::Id& id)
{
Q_ASSERT(!m_id_to_layer.contains(id));
const auto t = std::find(m_array.begin(), m_array.end(), tile::Id { unsigned(-1), {} });
Q_ASSERT(t != m_array.end());
*t = id;
const auto existing = m_id_to_layer.find(id);
Q_ASSERT(existing == m_id_to_layer.end());
if (existing != m_id_to_layer.end())
return existing->second;

// returns index in texture array
const auto layer = unsigned(t - m_array.begin());
if (m_free_layers.empty())
return invalid_layer;

const auto layer = m_free_layers.back();
m_free_layers.pop_back();
m_id_to_layer.emplace(id, layer);
return layer;
}

void GpuArrayHelper::remove_tile(const tile::Id& tile_id)
{
Q_ASSERT(m_id_to_layer.contains(tile_id));
m_id_to_layer.erase(tile_id);
const auto t = std::find(m_array.begin(), m_array.end(), tile_id);
Q_ASSERT(t != m_array.end()); // removing a tile that's not here. likely there is a race.
*t = tile::Id { unsigned(-1), {} };
const auto layer_it = m_id_to_layer.find(tile_id);

// TODO: should this assert or be a noop?
Q_ASSERT(layer_it != m_id_to_layer.end());
if (layer_it == m_id_to_layer.end())
return;

m_free_layers.push_back(layer_it->second);
m_id_to_layer.erase(layer_it);
}

void GpuArrayHelper::set_tile_limit(unsigned int new_limit)
{
Q_ASSERT(m_array.empty());
m_array.resize(new_limit);
std::fill(m_array.begin(), m_array.end(), tile::Id { unsigned(-1), {} });
Q_ASSERT(m_size == 0);
Q_ASSERT(new_limit <= invalid_layer);
if (new_limit > invalid_layer)
new_limit = invalid_layer;

m_size = new_limit;
m_free_layers.resize(new_limit);
// fill freelist
for (unsigned i = 0; i < new_limit; ++i)
m_free_layers[i] = uint16_t(new_limit - 1 - i);

m_id_to_layer.reserve(new_limit);
}

unsigned GpuArrayHelper::size() const { return unsigned(m_array.size()); }
unsigned GpuArrayHelper::size() const { return m_size; }

unsigned GpuArrayHelper::n_occupied() const { return unsigned(m_id_to_layer.size()); }

GpuArrayHelper::LayerInfo GpuArrayHelper::layer(Id tile_id) const
{
while (!m_id_to_layer.contains(tile_id) && tile_id.zoom_level > 0)
auto it = m_id_to_layer.find(tile_id);
while (it == m_id_to_layer.end() && tile_id.zoom_level > 0) {
tile_id = tile_id.parent();
if (!m_id_to_layer.contains(tile_id))
it = m_id_to_layer.find(tile_id);
}
if (it == m_id_to_layer.end())
return { {}, 0 }; // may be empty during startup.
return { tile_id, m_id_to_layer.at(tile_id) };
return { tile_id, it->second };
}

bool GpuArrayHelper::contains(Id tile_id) const { return m_id_to_layer.contains(tile_id); }
Expand Down
14 changes: 9 additions & 5 deletions nucleus/tile/GpuArrayHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,16 @@ class GpuArrayHelper {
};
struct LayerInfo {
tile::Id id;
unsigned index;
uint16_t index;
};

// sentinel when the storage is full
static constexpr uint16_t invalid_layer = uint16_t(-1);

GpuArrayHelper();

/// returns index in texture array
unsigned add_tile(const tile::Id& tile_id);
/// returns index in texture array, or invalid_layer if the array is full
uint16_t add_tile(const tile::Id& tile_id);
void remove_tile(const tile::Id& tile_id);
void set_tile_limit(unsigned new_limit);
unsigned size() const;
Expand All @@ -47,8 +50,9 @@ class GpuArrayHelper {
bool contains(Id tile_id) const;

private:
std::vector<tile::Id> m_array;
tile::IdMap<unsigned> m_id_to_layer;
unsigned m_size = 0;
std::vector<uint16_t> m_free_layers; // freelist stack
tile::IdMap<uint16_t> m_id_to_layer;
};

} // namespace nucleus::tile
9 changes: 4 additions & 5 deletions webgpu/engine/cloud/CloudRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "nucleus/camera/Definition.h"
#include "nucleus/srs.h"
#include "nucleus/utils/terrain_mesh_index_generator.h"
#include <QDebug>
#include <QtAssert>

#include <webgpu/base/RenderResourceRegistry.h>
Expand Down Expand Up @@ -479,14 +480,12 @@ void CloudRenderer::update_gpu_tiles_cloud(const std::vector<nucleus::tile::Id>&
Q_ASSERT(tile.id.zoom_level < 100);
Q_ASSERT(tile.texture);

// Atlas is full
if (m_loaded_cloud_textures.n_occupied() >= m_loaded_cloud_textures.size()) {
const auto layer_index = m_loaded_cloud_textures.add_tile(tile.id);
if (layer_index == nucleus::tile::GpuArrayHelper::invalid_layer) {
qWarning() << "CloudRenderer: cloud atlas full, dropping remaining tiles this update";
break;
}

// find empty spot and upload texture
const auto layer_index = m_loaded_cloud_textures.add_tile(tile.id);

uint32_t atlas_x = layer_index & ATLAS_MASK_XY;
uint32_t atlas_y = (layer_index >> ATLAS_BITS_XY) & ATLAS_MASK_XY;
uint32_t atlas_z = (layer_index >> (2 * ATLAS_BITS_XY)) & ATLAS_MASK_Z;
Expand Down
10 changes: 8 additions & 2 deletions webgpu/engine/tile_mesh/TileMeshRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,11 @@ void TileMeshRenderer::update_gpu_tiles_height(const std::vector<radix::tile::Id
Q_ASSERT(tile.id.zoom_level < 100);
Q_ASSERT(tile.surface);

// find empty spot and upload texture
const uint32_t layer_index = m_loaded_height_textures.add_tile(tile.id);
if (layer_index == nucleus::tile::GpuArrayHelper::invalid_layer) {
qWarning() << "TileMeshRenderer: height texture array full, dropping remaining tiles this update";
break;
}
m_heightmap_textures->texture().write(m_ctx->queue(), *tile.surface, layer_index);
}
}
Expand All @@ -335,8 +338,11 @@ void TileMeshRenderer::update_gpu_tiles_ortho(const std::vector<nucleus::tile::I
Q_ASSERT(tile.id.zoom_level < 100);
Q_ASSERT(tile.texture);

// find empty spot and upload texture
const auto layer_index = m_loaded_ortho_textures.add_tile(tile.id);
if (layer_index == nucleus::tile::GpuArrayHelper::invalid_layer) {
qWarning() << "TileMeshRenderer: ortho texture array full, dropping remaining tiles this update";
break;
}
m_ortho_textures->texture().write(m_ctx->queue(), tile.texture->front(), uint32_t(layer_index));
}
}
Expand Down
Loading