升级
This commit is contained in:
@@ -4,8 +4,16 @@
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
|
||||
namespace renderive::detail {
|
||||
namespace renderive {
|
||||
|
||||
enum class Render_Partition_Mode : std::uint8_t {
|
||||
Automatic,
|
||||
Fixed
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct Render_Partition_Range {
|
||||
std::size_t first{};
|
||||
@@ -23,14 +31,20 @@ inline Render_Partition_Range render_partition_range(std::size_t size,
|
||||
|
||||
class Adaptive_Render_Partitioner {
|
||||
public:
|
||||
[[nodiscard]] int graph_partition_count(int configured_count,
|
||||
int worker_count) noexcept {
|
||||
if (configured_count > 0)
|
||||
return configured_count;
|
||||
if (automatic_count_ == 0)
|
||||
automatic_count_ = std::max(1, worker_count);
|
||||
automatic_count_ = std::clamp(automatic_count_, 1,
|
||||
std::max(1, worker_count));
|
||||
[[nodiscard]] int graph_partition_count(Render_Partition_Mode mode,
|
||||
int configured_count,
|
||||
int worker_count,
|
||||
std::size_t work_size,
|
||||
std::size_t minimum_partition_size) noexcept {
|
||||
if (mode == Render_Partition_Mode::Fixed)
|
||||
return std::max(1, configured_count);
|
||||
|
||||
const std::size_t granularity = std::max<std::size_t>(1, minimum_partition_size);
|
||||
const int work_limit = static_cast<int>(std::min<std::size_t>(
|
||||
static_cast<std::size_t>(std::numeric_limits<int>::max()),
|
||||
std::max<std::size_t>(1, work_size / granularity)));
|
||||
const int automatic_limit = std::clamp(work_limit, 1, std::max(1, worker_count));
|
||||
automatic_count_ = std::clamp(automatic_count_, 1, automatic_limit);
|
||||
return automatic_count_;
|
||||
}
|
||||
|
||||
@@ -42,29 +56,43 @@ public:
|
||||
return std::clamp(graph_partition_count, 1, useful);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool finish(int configured_count, int active_count,
|
||||
int worker_count, std::size_t work_size) noexcept {
|
||||
if (configured_count != 0)
|
||||
[[nodiscard]] bool finish(Render_Partition_Mode mode, int active_count,
|
||||
std::uint64_t frame_interval_ns, int worker_count,
|
||||
std::size_t work_size,
|
||||
std::size_t minimum_partition_size) noexcept {
|
||||
if (mode != Render_Partition_Mode::Automatic)
|
||||
return false;
|
||||
const auto elapsed =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(Clock::now() - started_at_);
|
||||
constexpr auto target = std::chrono::microseconds(1500);
|
||||
const std::size_t granularity = std::max<std::size_t>(1, minimum_partition_size);
|
||||
const int work_limit = static_cast<int>(std::min<std::size_t>(
|
||||
static_cast<std::size_t>(std::numeric_limits<int>::max()),
|
||||
std::max<std::size_t>(1, work_size / granularity)));
|
||||
const int automatic_limit = std::clamp(work_limit, 1, std::max(1, worker_count));
|
||||
const auto elapsed = Clock::now() - started_at_;
|
||||
const auto elapsed_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed);
|
||||
const auto bottleneck_threshold = frame_interval_ns == 0
|
||||
? std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::microseconds(1500))
|
||||
: std::max(std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::microseconds(750)),
|
||||
std::chrono::nanoseconds(frame_interval_ns / 4));
|
||||
const int previous = automatic_count_;
|
||||
const int maximum = std::max(1, worker_count);
|
||||
if (elapsed > target * 2 && active_count < maximum &&
|
||||
work_size / static_cast<std::size_t>(active_count) >= 512)
|
||||
automatic_count_ = std::min(maximum, active_count + 1);
|
||||
else if (elapsed < target / 2 && active_count > 1)
|
||||
automatic_count_ = active_count - 1;
|
||||
else
|
||||
automatic_count_ = active_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);
|
||||
} 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);
|
||||
}
|
||||
return automatic_count_ != previous;
|
||||
}
|
||||
|
||||
private:
|
||||
using Clock = std::chrono::steady_clock;
|
||||
Clock::time_point started_at_{};
|
||||
int automatic_count_{};
|
||||
int automatic_count_{1};
|
||||
};
|
||||
|
||||
} // namespace renderive::detail
|
||||
} // namespace detail
|
||||
} // namespace renderive
|
||||
|
||||
@@ -60,7 +60,8 @@ void Renderable::build_task_graph(Renderable_Task_Graph& graph) {
|
||||
|
||||
void Renderable::build_paint_task_graph(Renderable_Task_Graph& graph) {
|
||||
add_paint_task(graph, "paint", [this](detail::Painter& painter,
|
||||
const Render_State_View& state) {
|
||||
const Render_State_View& state,
|
||||
const Scene_Render_Context&) {
|
||||
paint(painter, state);
|
||||
});
|
||||
}
|
||||
@@ -78,7 +79,7 @@ Renderable_Task_Graph::Task Renderable::add_paint_task(
|
||||
return;
|
||||
detail::Painter painter(*cache, viewport_size());
|
||||
if (painter)
|
||||
function(painter, render_state_view());
|
||||
function(painter, render_state_view(), context);
|
||||
},
|
||||
std::move(name));
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ public:
|
||||
|
||||
protected:
|
||||
using Paint_Task_Function =
|
||||
std::function<void(detail::Painter&, const Render_State_View&)>;
|
||||
std::function<void(detail::Painter&, const Render_State_View&,
|
||||
const Scene_Render_Context&)>;
|
||||
|
||||
virtual void paint(detail::Painter& painter, const Render_State_View& state) = 0;
|
||||
virtual void build_paint_task_graph(Renderable_Task_Graph& graph);
|
||||
|
||||
Reference in New Issue
Block a user