Skip to content

Commit

Permalink
merian-nodes: Graph: time controls
Browse files Browse the repository at this point in the history
  • Loading branch information
LDAP committed Aug 11, 2024
1 parent 2c3fa81 commit f8471e1
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 22 deletions.
95 changes: 87 additions & 8 deletions include/merian-nodes/graph/graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <unordered_map>
#include <unordered_set>

#include <fmt/chrono.h>
namespace merian_nodes {
namespace graph_internal {

Expand Down Expand Up @@ -156,6 +157,10 @@ struct NodeData {

errors.clear();
}

uint32_t set_index(const uint64_t run_iteration) const {
return run_iteration % descriptor_sets.size();
}
};

inline std::string format_as(const NodeData::NodeStatistics stats) {
Expand All @@ -166,6 +171,7 @@ inline std::string format_as(const NodeData::NodeStatistics stats) {

using namespace merian;
using namespace graph_internal;
using namespace std::literals::chrono_literals;

/**
* @brief A Vulkan processing graph.
Expand Down Expand Up @@ -206,6 +212,8 @@ class Graph : public std::enable_shared_from_this<Graph<RING_SIZE>> {
}
debug_utils = context->get_extension<ExtensionVkDebugUtils>();
run_profiler = std::make_shared<merian::Profiler>(context);
time_connect_reference = time_reference = std::chrono::high_resolution_clock::now();
duration_elapsed = 0ns;
}

~Graph() {
Expand Down Expand Up @@ -435,8 +443,10 @@ class Graph : public std::enable_shared_from_this<Graph<RING_SIZE>> {
}
}
}
iteration = 0;
run_iteration = 0;
last_build_report = profiler->get_report();
time_connect_reference = std::chrono::high_resolution_clock::now();
duration_elapsed_since_connect = 0ns;
}

// Runs one iteration of the graph.
Expand Down Expand Up @@ -469,7 +479,30 @@ class Graph : public std::enable_shared_from_this<Graph<RING_SIZE>> {
connect();
}

run.reset(iteration, iteration % RING_SIZE, profiler, cmd_pool, resource_allocator);
// Compute time stuff
assert(time_overwrite < 3);
const std::chrono::nanoseconds last_elapsed_ns = duration_elapsed;
if (time_overwrite == 1) {
const auto delta = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::duration<double>(time_delta_overwrite_ms / 1000.));
duration_elapsed += delta;
duration_elapsed_since_connect += delta;
time_delta_overwrite_ms = 0;
} else if (time_overwrite == 2) {
const auto delta = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::duration<double>(time_delta_overwrite_ms / 1000.));
duration_elapsed += delta;
duration_elapsed_since_connect += delta;
} else {
auto now = std::chrono::high_resolution_clock::now();
duration_elapsed = now - time_reference;
duration_elapsed_since_connect = now - time_connect_reference;
}
time_delta_ns = duration_elapsed - last_elapsed_ns;

run.reset(run_iteration, run_iteration % RING_SIZE, profiler, cmd_pool,
resource_allocator, time_delta_ns, duration_elapsed,
duration_elapsed_since_connect);

// While preprocessing nodes can signalize that they need to reconnect as well
{
Expand All @@ -478,7 +511,7 @@ class Graph : public std::enable_shared_from_this<Graph<RING_SIZE>> {
NodeData& data = node_data.at(node);
MERIAN_PROFILE_SCOPE(profiler, fmt::format("{} ({})", data.identifier,
registry.node_name(node)));
const uint32_t set_idx = iteration % data.descriptor_sets.size();
const uint32_t set_idx = data.set_index(run_iteration);
Node::NodeStatusFlags flags =
node->pre_process(run, data.resource_maps[set_idx]);
needs_reconnect |= flags & Node::NodeStatusFlagBits::NEEDS_RECONNECT;
Expand Down Expand Up @@ -517,7 +550,8 @@ class Graph : public std::enable_shared_from_this<Graph<RING_SIZE>> {
on_post_submit();

needs_reconnect |= run.needs_reconnect;
iteration++;
++run_iteration;
++total_iteration;
for (const auto& task : on_run_finished_tasks)
task();
on_run_finished_tasks.clear();
Expand Down Expand Up @@ -558,7 +592,38 @@ class Graph : public std::enable_shared_from_this<Graph<RING_SIZE>> {
void properties(Properties& props) {
needs_reconnect |= props.config_bool("Rebuild");
props.st_no_space();
props.output_text(fmt::format("Current iteration: {}", iteration));
props.output_text("Run iteration: {}", run_iteration);
if (props.st_begin_child("graph_properties", "Graph Properties",
Properties::ChildFlagBits::FRAMED)) {
props.output_text("Run iteration: {}", run_iteration);
props.output_text("Run Elapsed: {:%H:%M:%S}s", duration_elapsed_since_connect);
props.output_text("Total iterations: {}", total_iteration);
props.output_text("Total Elapsed: {:%H:%M:%S}s", duration_elapsed);
const double delta_ms =
std::chrono::duration_cast<
std::chrono::duration<double, std::chrono::milliseconds::period>>(time_delta_ns)
.count();
props.output_text("Time delta: {:04f}ms", delta_ms);
if (props.config_options("time overwrite", time_overwrite, {"None", "Time", "Delta"},
Properties::OptionsStyle::COMBO)) {
if (time_overwrite == 0) {
// move reference to prevent jump
const auto now = std::chrono::high_resolution_clock::now();
time_reference = now - duration_elapsed;
time_connect_reference = now - duration_elapsed_since_connect;
}
}

if (time_overwrite == 1) {
float delta_s = 0;
props.config_float("offset (s)", delta_s, "", 0.01);
time_delta_overwrite_ms += delta_s * 1000.;
} else if (time_overwrite == 2) {
props.config_float("delta (ms)", time_delta_overwrite_ms, "", 0.001);
}

props.st_end_child();
}

if (props.is_ui() &&
props.st_begin_child("edit", "Edit Graph", Properties::ChildFlagBits::FRAMED)) {
Expand Down Expand Up @@ -927,7 +992,7 @@ class Graph : public std::enable_shared_from_this<Graph<RING_SIZE>> {
registry.node_name(node)));
}

const uint32_t set_idx = iteration % data.descriptor_sets.size();
const uint32_t set_idx = data.set_index(run_iteration);
auto& [_, cur_resource_index] = per_output_info.precomputed_resources[set_idx];

config.output_text(fmt::format(
Expand Down Expand Up @@ -1033,7 +1098,7 @@ class Graph : public std::enable_shared_from_this<Graph<RING_SIZE>> {
const NodeHandle& node,
NodeData& data,
[[maybe_unused]] const ProfilerHandle& profiler) {
const uint32_t set_idx = iteration % data.descriptor_sets.size();
const uint32_t set_idx = data.set_index(run_iteration);

MERIAN_PROFILE_SCOPE_GPU(profiler, cmd,
fmt::format("{} ({})", data.identifier, registry.node_name(node)));
Expand Down Expand Up @@ -1805,12 +1870,26 @@ class Graph : public std::enable_shared_from_this<Graph<RING_SIZE>> {

// State
bool needs_reconnect = false;
uint64_t iteration = 0;
bool profiler_enable = true;
uint32_t profiler_report_intervall_ms = 50;
bool run_in_progress = false;
std::vector<std::function<void()>> on_run_finished_tasks;

uint64_t total_iteration = 0;
uint64_t run_iteration = 0;
// assert(overwrite_time || elapsed == now() - time_reference)
// to prevent divergence
std::chrono::high_resolution_clock::time_point time_reference;
std::chrono::high_resolution_clock::time_point time_connect_reference;
std::chrono::nanoseconds duration_elapsed_since_connect;
std::chrono::nanoseconds duration_elapsed;
int time_overwrite = 0; // NONE, TIME, DIFFERENCE
// this is also used for overwrite time. In this case this should only be applied once and then
// reset.
float time_delta_overwrite_ms = 0.;
// across builds. Might be not 0 at begin of run.
std::chrono::nanoseconds time_delta_ns = 0ns;

Profiler::Report last_build_report;
Profiler::Report last_run_report;
// in ms
Expand Down
56 changes: 49 additions & 7 deletions include/merian-nodes/graph/graph_run.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ class GraphRun {
template <uint32_t> friend class Graph;

public:
GraphRun(const uint32_t ring_size)
: ring_size(ring_size) {}
GraphRun(const uint32_t ring_size) : ring_size(ring_size) {}

void add_wait_semaphore(const BinarySemaphoreHandle& wait_semaphore,
const vk::PipelineStageFlags& wait_stage_flags) noexcept {
Expand Down Expand Up @@ -45,7 +44,8 @@ class GraphRun {
signal_values.push_back(value);
}

void add_submit_callback(std::function<void(const QueueHandle& queue)> callback) noexcept {
void
add_submit_callback(const std::function<void(const QueueHandle& queue)>& callback) noexcept {
submit_callbacks.push_back(callback);
}

Expand All @@ -69,7 +69,7 @@ class GraphRun {
return ring_size;
}

const CommandPoolHandle get_cmd_pool() noexcept {
const CommandPoolHandle& get_cmd_pool() noexcept {
return cmd_pool;
}

Expand All @@ -96,14 +96,14 @@ class GraphRun {

// You must call every callback after you submited the graph command buffer
// Or you use the execute_callbacks function.
const std::vector<std::function<void(const QueueHandle& queue)>>
const std::vector<std::function<void(const QueueHandle& queue)>>&
get_submit_callbacks() const noexcept {
return submit_callbacks;
}

// Call this after you submitted the graph command buffer
void execute_callbacks(const QueueHandle& queue) const {
for (auto& callback : submit_callbacks) {
for (const auto& callback : submit_callbacks) {
callback(queue);
}
}
Expand All @@ -118,16 +118,55 @@ class GraphRun {
return allocator;
}

// Returns the time difference to the last run in seconds.
// For the first run of a build the difference to the last run in the previous run is returned.
const std::chrono::nanoseconds& get_time_delta_duration() const {
return time_delta;
}

// Returns the time difference to the last run in seconds.
// For the first run of a build the difference to the last run in the previous run is returned.
double get_time_delta() const {
return std::chrono::duration_cast<std::chrono::duration<double>>(time_delta).count();
}

// Return elapsed time since graph initialization
const std::chrono::nanoseconds& get_elapsed_duration() const {
return elapsed;
}

// Return elapsed time since graph initialization in seconds.
double get_elapsed() const {
return std::chrono::duration_cast<std::chrono::duration<double>>(elapsed).count();
}

// Return elapsed time since the last connect()
const std::chrono::nanoseconds& get_elapsed_since_connect_duration() const {
return elapsed_since_connect;
}

// Return elapsed time since graph initialization in seconds.
double get_elapsed_since_connect() const {
return std::chrono::duration_cast<std::chrono::duration<double>>(elapsed_since_connect)
.count();
}

private:
void reset(const uint64_t iteration,
const uint32_t in_flight_index,
const ProfilerHandle profiler,
const CommandPoolHandle& cmd_pool,
const ResourceAllocatorHandle& allocator) {
const ResourceAllocatorHandle& allocator,
const std::chrono::nanoseconds time_delta,
const std::chrono::nanoseconds elapsed,
const std::chrono::nanoseconds elapsed_run) {
this->iteration = iteration;
this->in_flight_index = in_flight_index;
this->cmd_pool = cmd_pool;
this->allocator = allocator;
this->time_delta = time_delta;
this->elapsed = elapsed;
this->elapsed_since_connect = elapsed_run;
wait_semaphores.clear();
wait_stages.clear();
wait_values.clear();
Expand Down Expand Up @@ -157,6 +196,9 @@ class GraphRun {
bool needs_reconnect = false;
uint64_t iteration;
uint32_t in_flight_index;
std::chrono::nanoseconds time_delta;
std::chrono::nanoseconds elapsed;
std::chrono::nanoseconds elapsed_since_connect;
};

} // namespace merian_nodes
2 changes: 1 addition & 1 deletion include/merian-nodes/nodes/exposure/exposure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class AutoExposure : public Node {
static constexpr uint32_t local_size_y = 16;

struct PushConstant {
int automatic = false;
int automatic = 0;

float iso = 100.0;
float q = 0.65;
Expand Down
1 change: 0 additions & 1 deletion include/merian-nodes/nodes/shadertoy/shadertoy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ class Shadertoy : public AbstractCompute {
std::optional<ShaderCompiler::compilation_failed> error;

PushConstant constant;
Stopwatch sw;
};

} // namespace merian_nodes
9 changes: 4 additions & 5 deletions src/merian-nodes/nodes/shadertoy/shadertoy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ class ShadertoyInjectCompiler : public ShaderCompiler {

Shadertoy::Shadertoy(const ContextHandle context)
: AbstractCompute(context, sizeof(PushConstant)), shader_glsl(default_shader) {
sw.reset();

ShaderCompilerHandle shaderc_compiler = nullptr;
#if MERIAN_ENABLE_SHADERC
Expand Down Expand Up @@ -132,9 +131,8 @@ Shadertoy::get_specialization_info([[maybe_unused]] const NodeIO& io) noexcept {

const void* Shadertoy::get_push_constant([[maybe_unused]] GraphRun& run,
[[maybe_unused]] const NodeIO& io) {
float new_time = sw.seconds();
constant.iTimeDelta = new_time - constant.iTime;
constant.iTime = new_time;
constant.iTimeDelta = static_cast<float>(run.get_time_delta());
constant.iTime = static_cast<float>(run.get_elapsed());
constant.iFrame++;

return &constant;
Expand Down Expand Up @@ -185,7 +183,8 @@ AbstractCompute::NodeStatusFlags Shadertoy::properties(Properties& config) {
case 1: {
if (config.config_text("shader path", shader_path, true)) {
needs_reconnect = true;
resolved_shader_path = context->file_loader.find_file(shader_path).value_or(shader_path);
resolved_shader_path =
context->file_loader.find_file(shader_path).value_or(shader_path);
}

if (std::filesystem::exists(resolved_shader_path)) {
Expand Down

0 comments on commit f8471e1

Please sign in to comment.