This commit is contained in:
2026-08-15 23:24:23 +08:00
parent 023250c0fc
commit 7a94264c13
32 changed files with 1450 additions and 290 deletions
+11
View File
@@ -22,14 +22,25 @@ endif ()
set(Renderive_render_2D_source_dir "${CMAKE_CURRENT_LIST_DIR}/render_2D")
append_glob_source(Renderive_render_2D_sources "${Renderive_render_2D_source_dir}")
add_library(Renderive_render_2D STATIC ${Renderive_render_2D_sources})
add_library(Renderive::Render2D ALIAS Renderive_render_2D)
set_target_properties(Renderive_render_2D PROPERTIES EXPORT_NAME Render2D)
target_include_directories(Renderive_render_2D PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_compile_features(Renderive_render_2D PUBLIC cxx_std_20)
target_link_libraries(Renderive_render_2D PUBLIC Renderive_Kernel blend2d::blend2d)
if (MSVC)
target_compile_options(Renderive_render_2D PRIVATE /utf-8)
endif ()
install(TARGETS Renderive_render_2D
EXPORT RenderiveTargets
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
install(DIRECTORY "${Renderive_render_2D_source_dir}/"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/render_2D"
FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp")
if (RENDERIVE_BUILD_TESTS)
set(Renderive_render_2D_test_dir "${CMAKE_CURRENT_LIST_DIR}/tests")
append_glob_source(Renderive_render_2D_test_sources "${Renderive_render_2D_test_dir}")
@@ -74,22 +74,51 @@ struct Adaptive_Render_Partitioner {
std::chrono::microseconds(750)),
std::chrono::nanoseconds(frame_interval_ns / 4));
const int previous = automatic_count_;
const auto estimated_serial_cost = elapsed_ns * std::max(1, active_count);
if (elapsed_ns > bottleneck_threshold && active_count < automatic_limit) {
automatic_count_ = std::min(automatic_limit, active_count * 2);
const auto elapsed_count = static_cast<std::uint64_t>(
std::max<std::int64_t>(0, elapsed_ns.count()));
const auto active = static_cast<std::uint64_t>(std::max(1, active_count));
const auto maximum = std::numeric_limits<std::uint64_t>::max();
const auto measured_serial_ns =
active != 0 && elapsed_count > maximum / active
? maximum
: elapsed_count * active;
if (serial_cost_ewma_ns_ == 0) {
serial_cost_ewma_ns_ = measured_serial_ns;
} else {
// 75% history + 25% newest sample without overflowing uint64_t.
serial_cost_ewma_ns_ =
(serial_cost_ewma_ns_ / 4) * 3 + measured_serial_ns / 4;
}
else if (active_count > 1 &&
estimated_serial_cost < bottleneck_threshold * 3 / 5) {
automatic_count_ = 1;
}
else {
automatic_count_ = std::clamp(active_count, 1, automatic_limit);
const auto target_ns = static_cast<std::uint64_t>(
std::max<std::int64_t>(1, bottleneck_threshold.count()));
const auto required_partitions =
serial_cost_ewma_ns_ / target_ns +
(serial_cost_ewma_ns_ % target_ns != 0 ? 1U : 0U);
int desired = static_cast<int>(std::min<std::uint64_t>(
static_cast<std::uint64_t>(automatic_limit),
std::max<std::uint64_t>(1, required_partitions)));
// Collapse aggressively only when the measured serial work is clearly
// below 60% of the target. Otherwise use one-step hysteresis to avoid
// topology churn around a partition boundary.
const auto collapse_threshold =
(target_ns / 5) * 3 + ((target_ns % 5) * 3) / 5;
if (measured_serial_ns < collapse_threshold && active_count > 1) {
desired = 1;
} else if (desired > active_count) {
const int growth_limit = active_count <= automatic_limit / 2
? active_count * 2
: automatic_limit;
desired = std::min(desired, std::max(active_count + 1, growth_limit));
} else if (desired < active_count) {
desired = std::max(desired, active_count - 1);
}
automatic_count_ = std::clamp(desired, 1, automatic_limit);
return automatic_count_ != previous;
}
private:
using Clock = std::chrono::steady_clock;
Clock::time_point started_at_{};
std::uint64_t serial_cost_ewma_ns_{};
int automatic_count_{1};
};
} // namespace detail