Skip to content
Merged
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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ option(HIGHMAP_ENABLE_TESTS "" ON)
option(HIGHMAP_ENABLE_BENCHMARKS "" ON)
option(HIGHMAP_ENABLE_PROFILE_BUILD
"Enable build time profiling (-ftime-trace)" OFF)
option(HIGHMAP_ENABLE_TRACY "Enable optional Tracy CPU instrumentation" OFF)
option(HIGHMAP_ENABLE_PCH "Enable Precompiled Headers (PCH)" OFF)

# -----------------------------------------------------------------------------
Expand Down
7 changes: 7 additions & 0 deletions HighMap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ file(GLOB_RECURSE SOURCES ${PROJECT_SOURCE_DIR}/src/*.cpp)

add_library(${PROJECT_NAME} STATIC ${SOURCES})

if(HIGHMAP_ENABLE_TRACY)
find_package(Tracy CONFIG REQUIRED)
# Public because the tile dispatcher is instantiated by library consumers.
target_link_libraries(${PROJECT_NAME} PUBLIC Tracy::TracyClient)
target_compile_definitions(${PROJECT_NAME} PUBLIC HIGHMAP_ENABLE_TRACY)
endif()

target_include_directories(
${PROJECT_NAME}
PUBLIC ${PROJECT_SOURCE_DIR}/include
Expand Down
13 changes: 7 additions & 6 deletions HighMap/include/highmap/carving.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,11 @@ void trench(Array &z,
* @param[in] tile_size Spatial tile partition size.
* @param[in] bbox Domain bounding box.
*/
void trench(Array &z,
const Graph &graph,
const std::vector<float> &relative_widths,
float width,
bool enable_width_depth_scaling = true,
void trench(Array &z,
const Graph &graph,
const std::vector<float> &relative_widths,
float width,
bool enable_width_depth_scaling = true,
RadialProfile radial_profile = RadialProfile::RP_SMOOTHSTEP_UPPER,
float radial_profile_parameter = 2.f,
ElevationLongitudinalProfile longitudinal_profile =
Expand All @@ -268,7 +268,8 @@ void trench(Array &z,
*
* @param[in,out] z Target heightmap to carve in-place.
* @param[in] graph Input flow network Graph.
* @param[in] width Target river width at the outlet(s).
* @param[in] width Target river width at the
* outlet(s).
* @param[in] width_exponent Scaling exponent for width with
* distance to outlet (default: 1.0).
* @param[in] enable_width_depth_scaling Modulate width according to depth.
Expand Down
28 changes: 28 additions & 0 deletions HighMap/include/highmap/profiling.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

// Optional CPU instrumentation. No expressions are evaluated in normal builds.
#ifdef HIGHMAP_ENABLE_TRACY
#include <string_view>

#include <tracy/Tracy.hpp>
#ifndef TRACY_ENABLE
#error HIGHMAP_ENABLE_TRACY requires a Tracy client built with TRACY_ENABLE
#endif
#define HMAP_PROFILE_ZONE(name) ZoneScopedN(name)
#define HMAP_PROFILE_TEXT(text) \
do \
{ \
if (TracyIsConnected) \
{ \
const auto &hmap_profile_text = (text); \
const std::string_view hmap_profile_view(hmap_profile_text); \
ZoneText(hmap_profile_view.data(), hmap_profile_view.size()); \
} \
} while (false)
#else
#define HMAP_PROFILE_ZONE(name)
#define HMAP_PROFILE_TEXT(text) \
do \
{ \
} while (false)
#endif
1 change: 1 addition & 0 deletions HighMap/include/highmap/virtual_array/virtual_array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "highmap/filters.hpp"
#include "highmap/logger.hpp"
#include "highmap/math/core.hpp"
#include "highmap/profiling.hpp"
#include "highmap/virtual_array/tile_region.hpp"
#include "highmap/virtual_array/tile_storage.hpp"

Expand Down
150 changes: 93 additions & 57 deletions HighMap/include/highmap/virtual_array/virtual_array.inl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct TileAccess
template <typename Func>
void for_each_tile(const TileAccess &access, Func &&func, const ComputeMode &cm)
{
HMAP_PROFILE_ZONE("HighMap::for_each_tile");
if (access.outputs.empty() && access.inputs.empty())
{
hmap::log::error("no input or output VirtualArray");
Expand All @@ -30,6 +31,12 @@ void for_each_tile(const TileAccess &access, Func &&func, const ComputeMode &cm)
const VirtualArray *ref_va = access.ref_va();
if (!ref_va) return;

HMAP_PROFILE_TEXT(to_string(cm.mode) +
" shape=" + std::to_string(ref_va->shape.x) + "x" +
std::to_string(ref_va->shape.y) +
" tile=" + std::to_string(ref_va->tile_shape.x) + "x" +
std::to_string(ref_va->tile_shape.y));

// --- validate compatibility

auto check = [&](const VirtualArray *va)
Expand All @@ -56,25 +63,34 @@ void for_each_tile(const TileAccess &access, Func &&func, const ComputeMode &cm)

auto region_dispatcher = [&](const TileRegion &region)
{
HMAP_PROFILE_ZONE("HighMap::tile");
std::vector<const Array *> in_tiles;
std::vector<Array *> out_tiles;

in_tiles.reserve(access.inputs.size());
out_tiles.reserve(access.outputs.size());

for (auto *va : access.inputs)
in_tiles.push_back(va ? &va->storage->get_tile(region) : nullptr);

for (auto *va : access.outputs)
out_tiles.push_back(va ? &va->storage->get_tile(region) : nullptr);
{
HMAP_PROFILE_ZONE("HighMap::tile.acquire");
for (auto *va : access.inputs)
in_tiles.push_back(va ? &va->storage->get_tile(region) : nullptr);

func(in_tiles, out_tiles, region);
for (auto *va : access.outputs)
out_tiles.push_back(va ? &va->storage->get_tile(region) : nullptr);
}
{
HMAP_PROFILE_ZONE("HighMap::tile.algorithm");
func(in_tiles, out_tiles, region);
}
{
HMAP_PROFILE_ZONE("HighMap::tile.release");

for (auto *va : access.inputs)
if (va) va->storage->release_tile(region);
for (auto *va : access.inputs)
if (va) va->storage->release_tile(region);

for (auto *va : access.outputs)
if (va) va->storage->release_tile(region);
for (auto *va : access.outputs)
if (va) va->storage->release_tile(region);
}
};

// reuse your existing modes
Expand All @@ -96,6 +112,7 @@ void for_each_tile(const TileAccess &access, Func &&func, const ComputeMode &cm)

if (cm.trim_storage)
{
HMAP_PROFILE_ZONE("HighMap::trim_storage");
for (auto *va : access.inputs)
if (va) va->trim_storage();
for (auto *va : access.outputs)
Expand Down Expand Up @@ -175,6 +192,7 @@ void distributed_tile_loop(const VirtualArray &ref_va,
RegionDispatcher &&dispatcher,
int nthreads = 0)
{
HMAP_PROFILE_ZONE("HighMap::distributed_tile_loop");
const int nx = ceil_div(ref_va.shape.x, ref_va.tile_shape.x);
const int ny = ceil_div(ref_va.shape.y, ref_va.tile_shape.y);
const int ntasks = nx * ny;
Expand Down Expand Up @@ -210,6 +228,7 @@ void distributed_tile_loop(const VirtualArray &ref_va,
template <typename Func>
void single_array_compute(const TileAccess &access, Func &&func, int stride = 1)
{
HMAP_PROFILE_ZONE("HighMap::single_array");
const VirtualArray *ref_va = access.ref_va();
if (!ref_va) return;

Expand All @@ -232,16 +251,18 @@ void single_array_compute(const TileAccess &access, Func &&func, int stride = 1)
shape_wrk = glm::ivec2(nx, ny);
}

// project
for (auto *va : access.inputs)
arrays_in.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk)
: Array());

for (auto *va : access.outputs)
// TODO remove to_array(), left for retor-fit but misusage
arrays_out.push_back(
va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array());
{
HMAP_PROFILE_ZONE("HighMap::single_array.gather");
// project
for (auto *va : access.inputs)
arrays_in.push_back(
va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array());

for (auto *va : access.outputs)
// TODO remove to_array(), left for retor-fit but misusage
arrays_out.push_back(
va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array());
}
// create pointer vector for user func
std::vector<const Array *> in_tiles;
std::vector<Array *> out_tiles;
Expand All @@ -260,25 +281,32 @@ void single_array_compute(const TileAccess &access, Func &&func, int stride = 1)
shape_wrk,
{0, 0, 0, 0});

func(in_tiles, out_tiles, va_region);
{
HMAP_PROFILE_ZONE("HighMap::single_array.algorithm");
func(in_tiles, out_tiles, va_region);
}

// copy back to VirtualArrays (only outputs do not need to update const
// inputs)
for (size_t i = 0; i < access.outputs.size(); ++i)
if (access.outputs[i])
{
if (shape_wrk != ref_va->shape)
access.outputs[i]->from_array_bicubic(arrays_out[i], cm_local);
else
access.outputs[i]->from_array(arrays_out[i], cm_local);
}
{
HMAP_PROFILE_ZONE("HighMap::single_array.scatter");
// copy back to VirtualArrays (only outputs do not need to update const
// inputs)
for (size_t i = 0; i < access.outputs.size(); ++i)
if (access.outputs[i])
{
if (shape_wrk != ref_va->shape)
access.outputs[i]->from_array_bicubic(arrays_out[i], cm_local);
else
access.outputs[i]->from_array(arrays_out[i], cm_local);
}
}
}

template <typename Func>
void single_array_downscaled_compute(const TileAccess &access,
Func &&func,
float kc)
{
HMAP_PROFILE_ZONE("HighMap::single_array_downscaled");
const VirtualArray *ref_va = access.ref_va();
if (!ref_va) return;

Expand All @@ -301,16 +329,18 @@ void single_array_downscaled_compute(const TileAccess &access,
shape_wrk = glm::ivec2(nx, ny);
}

// project
for (auto *va : access.inputs)
arrays_in.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk)
: Array());

for (auto *va : access.outputs)
// TODO remove to_array(), left for retor-fit but misusage
arrays_out.push_back(
va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array());
{
HMAP_PROFILE_ZONE("HighMap::single_array.gather");
// project
for (auto *va : access.inputs)
arrays_in.push_back(
va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array());

for (auto *va : access.outputs)
// TODO remove to_array(), left for retor-fit but misusage
arrays_out.push_back(
va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array());
}
// create pointer vector for user func
std::vector<const Array *> in_tiles;
std::vector<Array *> out_tiles;
Expand All @@ -329,28 +359,34 @@ void single_array_downscaled_compute(const TileAccess &access,
shape_wrk,
{0, 0, 0, 0});

func(in_tiles, out_tiles, va_region);
{
HMAP_PROFILE_ZONE("HighMap::single_array.algorithm");
func(in_tiles, out_tiles, va_region);
}

// copy back to VirtualArrays (only outputs do not need to update const
// inputs)
for (size_t i = 0; i < access.outputs.size(); ++i)
if (access.outputs[i])
{
// resample to initial shape and add higher frequency
Array out_full = access.outputs[i]->to_array(cm_local);
Array out_low_pass = out_full.resample_to_shape(shape_wrk)
.resample_to_shape_bicubic(ref_va->shape);
{
HMAP_PROFILE_ZONE("HighMap::single_array.scatter");
// copy back to VirtualArrays (only outputs do not need to update const
// inputs)
for (size_t i = 0; i < access.outputs.size(); ++i)
if (access.outputs[i])
{
// resample to initial shape and add higher frequency
Array out_full = access.outputs[i]->to_array(cm_local);
Array out_low_pass = out_full.resample_to_shape(shape_wrk)
.resample_to_shape_bicubic(ref_va->shape);

// resample coarse result and use it to replace the initial
// low-frequency content
arrays_out[i] = arrays_out[i].resample_to_shape_bicubic(ref_va->shape);
// resample coarse result and use it to replace the initial
// low-frequency content
arrays_out[i] = arrays_out[i].resample_to_shape_bicubic(ref_va->shape);

// TODO add post-filter
// laplace(arrays_out[i]);
// TODO add post-filter
// laplace(arrays_out[i]);

access.outputs[i]->from_array(arrays_out[i] + (out_full - out_low_pass),
cm_local);
}
access.outputs[i]->from_array(arrays_out[i] + (out_full - out_low_pass),
cm_local);
}
}
}

template <typename Func>
Expand Down
25 changes: 18 additions & 7 deletions HighMap/src/erosion/hydraulic_blur.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,38 @@
#include "highmap/erosion/deprecated.hpp"
#include "highmap/filters.hpp"
#include "highmap/internal/validation.hpp"
#include "highmap/profiling.hpp"
#include "highmap/range.hpp"

namespace hmap
{

void hydraulic_blur(Array &z, float vmax, float radius, float k_smoothing)
{
HMAP_PROFILE_ZONE("HighMap::hydraulic_blur");
if (!validate_non_empty(z)) return;

int ir = std::max(1, (int)(radius * z.shape.x));

Array z_clamped = z;
if (k_smoothing)
clamp_min_smooth(z_clamped, vmax, k_smoothing);
else
clamp_min_smooth(z_clamped, vmax);
{
HMAP_PROFILE_ZONE("HighMap::hydraulic_blur.clamp");
if (k_smoothing)
clamp_min_smooth(z_clamped, vmax, k_smoothing);
else
clamp_min_smooth(z_clamped, vmax);
}

Array z_filtered = z;
smooth_cpulse(z_filtered, ir);

z = (z_clamped + z_filtered - vmax);
{
HMAP_PROFILE_ZONE("HighMap::hydraulic_blur.smooth");
smooth_cpulse(z_filtered, ir);
}

{
HMAP_PROFILE_ZONE("HighMap::hydraulic_blur.combine");
z = (z_clamped + z_filtered - vmax);
}
}

} // namespace hmap
Loading
Loading