修复若干问题
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
set(Renderive_Web_dependencies global::drogon global::spdlog global::magic_enum)
|
||||
if (RENDERIVE_BUILD_TESTS)
|
||||
set(Renderive_Web_test_targets)
|
||||
list(APPEND Renderive_Web_dependencies global::GTest)
|
||||
endif ()
|
||||
rcl_add_dependency_action_targets(Renderive_Web_env ${Renderive_Web_dependencies})
|
||||
@@ -207,5 +208,12 @@ if (RENDERIVE_BUILD_TESTS)
|
||||
target_link_libraries("${Renderive_Web_test_target}" PRIVATE Renderive_Web Adminive::Nlohmann GTest::gtest_main)
|
||||
renderive_stage_render_3D_runtime("${Renderive_Web_test_target}")
|
||||
add_test(NAME "${Renderive_Web_test_target}" COMMAND "${Renderive_Web_test_target}")
|
||||
set_tests_properties("${Renderive_Web_test_target}" PROPERTIES LABELS "Renderive_Web")
|
||||
list(APPEND Renderive_Web_test_targets "${Renderive_Web_test_target}")
|
||||
endforeach ()
|
||||
add_custom_target(Renderive_Web_check
|
||||
COMMAND "${CMAKE_CTEST_COMMAND}" --test-dir "${CMAKE_BINARY_DIR}"
|
||||
-C "$<CONFIG>" -L "^Renderive_Web$" --output-on-failure
|
||||
DEPENDS ${Renderive_Web_test_targets}
|
||||
USES_TERMINAL)
|
||||
endif ()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Gallery_Types.h"
|
||||
#include "renderive/scene/Scene2D_Context.hpp"
|
||||
#include "render_2D/scene/Scene_Context.hpp"
|
||||
#include <structive/property/property.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
@@ -83,19 +83,19 @@ struct Type_Descriptor<Manual_Refresh_Strategy<Scene_Frame, Mutex, Observer>> {
|
||||
using renderive::web::gallery_action;
|
||||
return object<T>(type_metadata(
|
||||
gallery_action("mode_prepare", "准备帧",
|
||||
"Manual_Refresh_Strategy::acquire_painter / Basic_Scene2D::prepare_frame",
|
||||
"Manual_Refresh_Strategy::acquire_painter / Plot_Scene::prepare_frame",
|
||||
"Manual_Refresh_Strategy"),
|
||||
gallery_action("mode_refresh", "提交手动刷新",
|
||||
"Manual_Refresh_Strategy::refresh / Basic_Scene2D::refresh_manual_frame",
|
||||
"Manual_Refresh_Strategy::refresh / Plot_Scene::refresh_manual_frame",
|
||||
"Manual_Refresh_Strategy"),
|
||||
gallery_action("mode_render", "渲染已刷新帧",
|
||||
"Manual_Refresh_Strategy::acquire_renderer / Basic_Scene2D::render_prepared_frame",
|
||||
"Manual_Refresh_Strategy::acquire_renderer / Plot_Scene::render_prepared_frame",
|
||||
"Manual_Refresh_Strategy", {}, {}, {}, 0.0, true),
|
||||
gallery_action("mode_discard", "丢弃待刷新帧",
|
||||
"Basic_Scene2D::discard_pending_frame",
|
||||
"Plot_Scene::discard_pending_frame",
|
||||
"Manual_Refresh_Strategy"),
|
||||
gallery_action("mode_cycle", "执行完整手动帧周期",
|
||||
"Basic_Scene2D::render_frame", "Manual_Refresh_Strategy",
|
||||
"Plot_Scene::render_frame", "Manual_Refresh_Strategy",
|
||||
{}, {}, {}, 0.0, true)));
|
||||
}
|
||||
};
|
||||
@@ -107,15 +107,15 @@ struct Type_Descriptor<Low_Latency_Strategy<Scene_Frame, Mutex, Observer>> {
|
||||
using renderive::web::gallery_action;
|
||||
return object<T>(type_metadata(
|
||||
gallery_action("mode_prepare", "发布低延迟帧",
|
||||
"Low_Latency_Strategy::acquire_painter / Basic_Scene2D::prepare_frame",
|
||||
"Low_Latency_Strategy::acquire_painter / Plot_Scene::prepare_frame",
|
||||
"Low_Latency_Strategy"),
|
||||
gallery_action("mode_render", "消费最新帧",
|
||||
"Low_Latency_Strategy::acquire_renderer / Basic_Scene2D::render_prepared_frame",
|
||||
"Low_Latency_Strategy::acquire_renderer / Plot_Scene::render_prepared_frame",
|
||||
"Low_Latency_Strategy", {}, {}, {}, 0.0, true),
|
||||
gallery_action("mode_discard", "丢弃陈旧帧",
|
||||
"Basic_Scene2D::discard_pending_frame", "Low_Latency_Strategy"),
|
||||
"Plot_Scene::discard_pending_frame", "Low_Latency_Strategy"),
|
||||
gallery_action("mode_cycle", "执行低延迟帧周期",
|
||||
"Basic_Scene2D::render_frame", "Low_Latency_Strategy",
|
||||
"Plot_Scene::render_frame", "Low_Latency_Strategy",
|
||||
{}, {}, {}, 0.0, true)));
|
||||
}
|
||||
};
|
||||
@@ -127,16 +127,16 @@ struct Type_Descriptor<Flow_Refresh_Strategy<Scene_Frame, Mutex, Observer>> {
|
||||
using renderive::web::gallery_action;
|
||||
return object<T>(type_metadata(
|
||||
gallery_action("mode_enqueue", "压入一帧",
|
||||
"Flow_Refresh_Strategy::acquire_painter / Basic_Scene2D::prepare_frame",
|
||||
"Flow_Refresh_Strategy::acquire_painter / Plot_Scene::prepare_frame",
|
||||
"Flow_Refresh_Strategy"),
|
||||
gallery_action("mode_enqueue_burst", "批量压入回放队列",
|
||||
"Flow_Refresh_Strategy::acquire_painter / Basic_Scene2D::prepare_frame x N",
|
||||
"Flow_Refresh_Strategy::acquire_painter / Plot_Scene::prepare_frame x N",
|
||||
"Flow_Refresh_Strategy", {}, "number", "帧数", 8.0),
|
||||
gallery_action("mode_dequeue", "消费队首帧",
|
||||
"Flow_Refresh_Strategy::acquire_renderer / Basic_Scene2D::render_prepared_frame",
|
||||
"Flow_Refresh_Strategy::acquire_renderer / Plot_Scene::render_prepared_frame",
|
||||
"Flow_Refresh_Strategy", {}, {}, {}, 0.0, true),
|
||||
gallery_action("mode_cycle", "执行回放帧周期",
|
||||
"Basic_Scene2D::render_frame", "Flow_Refresh_Strategy",
|
||||
"Plot_Scene::render_frame", "Flow_Refresh_Strategy",
|
||||
{}, {}, {}, 0.0, true)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "Gallery_Enum.h"
|
||||
#include "common/Gallery_Performance_Types.h"
|
||||
#include "render_2D/scene/Scene.h"
|
||||
#include "render_2D/scene/Plot_Scene.h"
|
||||
#include "render_2D/renderable/Renderable.h"
|
||||
|
||||
#include "adminive/adminive.hpp"
|
||||
@@ -66,15 +66,15 @@ struct Gallery_Render_Performance {
|
||||
namespace adminive {
|
||||
|
||||
template <class Json>
|
||||
struct Value_Adapter<renderive::Frame_Control_Mode, Json> {
|
||||
struct Value_Adapter<renderive::Plot_Frame_Mode, Json> {
|
||||
using value_type = std::string;
|
||||
|
||||
static std::string read(renderive::Frame_Control_Mode value) {
|
||||
static std::string read(renderive::Plot_Frame_Mode value) {
|
||||
return renderive::web::gallery_enum_id(value);
|
||||
}
|
||||
static void write(renderive::Frame_Control_Mode& target, std::string value) {
|
||||
static void write(renderive::Plot_Frame_Mode& target, std::string value) {
|
||||
const auto parsed =
|
||||
renderive::web::gallery_enum_cast<renderive::Frame_Control_Mode>(value);
|
||||
renderive::web::gallery_enum_cast<renderive::Plot_Frame_Mode>(value);
|
||||
if (!parsed)
|
||||
throw std::invalid_argument("unknown frame control mode: " + value);
|
||||
target = *parsed;
|
||||
@@ -82,14 +82,14 @@ struct Value_Adapter<renderive::Frame_Control_Mode, Json> {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type_Descriptor<renderive::Frame_Observer_Snapshot> {
|
||||
struct Type_Descriptor<renderive::Plot_Frame_Status> {
|
||||
static auto get() {
|
||||
using T = renderive::Frame_Observer_Snapshot;
|
||||
using T = renderive::Plot_Frame_Status;
|
||||
return object<T>("kernel_observer",
|
||||
ADMINIVE_FIELD_LABEL(T, mode, "模式")
|
||||
.enum_label<renderive::Frame_Control_Mode::Manual>("手动刷新")
|
||||
.enum_label<renderive::Frame_Control_Mode::Low_Latency>("低延迟")
|
||||
.enum_label<renderive::Frame_Control_Mode::Playback>("回放队列"),
|
||||
.enum_label<renderive::Plot_Frame_Mode::Manual>("手动刷新")
|
||||
.enum_label<renderive::Plot_Frame_Mode::Low_Latency>("低延迟")
|
||||
.enum_label<renderive::Plot_Frame_Mode::Playback>("回放队列"),
|
||||
ADMINIVE_FIELD_LABEL(T, last_event, "最近事件"),
|
||||
ADMINIVE_FIELD_LABEL(T, limit_state, "当前瓶颈"),
|
||||
ADMINIVE_FIELD_LABEL(T, frequency_hz, "配置频率"),
|
||||
@@ -229,7 +229,7 @@ struct Type_Descriptor<renderive::Renderable_Observation> {
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(Described_Type<renderive::Frame_Observer_Snapshot>);
|
||||
static_assert(Described_Type<renderive::Plot_Frame_Status>);
|
||||
static_assert(Described_Type<renderive::web::Gallery_Consumer_Feedback_Snapshot>);
|
||||
static_assert(Described_Type<renderive::web::Gallery_Render_Performance>);
|
||||
static_assert(Described_Type<renderive::web::Gallery_Client_Performance>);
|
||||
|
||||
@@ -85,13 +85,13 @@ void append_session_actions(Gallery_Frame_Mode frame_mode,
|
||||
std::vector<Action_Model>& result) {
|
||||
switch (frame_mode) {
|
||||
case Gallery_Frame_Mode::Manual:
|
||||
append_gallery_actions<Gallery_Session_Control<Manual_Scene2D>>(result);
|
||||
append_gallery_actions<Gallery_Session_Control<Plot_Scene>>(result);
|
||||
return;
|
||||
case Gallery_Frame_Mode::Low_Latency:
|
||||
append_gallery_actions<Gallery_Session_Control<Scene2D>>(result);
|
||||
append_gallery_actions<Gallery_Session_Control<Plot_Scene>>(result);
|
||||
return;
|
||||
case Gallery_Frame_Mode::Playback:
|
||||
append_gallery_actions<Gallery_Session_Control<Playback_Scene2D>>(result);
|
||||
append_gallery_actions<Gallery_Session_Control<Plot_Scene>>(result);
|
||||
return;
|
||||
}
|
||||
throw std::invalid_argument("unknown gallery frame mode");
|
||||
@@ -101,11 +101,11 @@ std::size_t session_control_count(std::string_view case_id, Gallery_Frame_Mode f
|
||||
return 0;
|
||||
switch (frame_mode) {
|
||||
case Gallery_Frame_Mode::Manual:
|
||||
return gallery_control_count<Gallery_Session_Control<Manual_Scene2D>>();
|
||||
return gallery_control_count<Gallery_Session_Control<Plot_Scene>>();
|
||||
case Gallery_Frame_Mode::Low_Latency:
|
||||
return gallery_control_count<Gallery_Session_Control<Scene2D>>();
|
||||
return gallery_control_count<Gallery_Session_Control<Plot_Scene>>();
|
||||
case Gallery_Frame_Mode::Playback:
|
||||
return gallery_control_count<Gallery_Session_Control<Playback_Scene2D>>();
|
||||
return gallery_control_count<Gallery_Session_Control<Plot_Scene>>();
|
||||
}
|
||||
throw std::invalid_argument("unknown gallery frame mode");
|
||||
}
|
||||
@@ -298,16 +298,16 @@ bool observer_detail_field(std::string_view name) {
|
||||
template <class Predicate>
|
||||
Json observer_fields(Predicate&& predicate) {
|
||||
const Json descriptor =
|
||||
adminive::to_descriptor_json<Json, renderive::Frame_Observer_Snapshot>();
|
||||
adminive::to_descriptor_json<Json, renderive::Plot_Frame_Status>();
|
||||
Json result = Json::array();
|
||||
for (const Json& field : descriptor.at("fields")) {
|
||||
const std::string name = field.at("name");
|
||||
if (predicate(name)) {
|
||||
Json field = described_dashboard_field<renderive::Frame_Observer_Snapshot>(
|
||||
Json field = described_dashboard_field<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", name);
|
||||
if (name == "frequency_hz") {
|
||||
field["enabled_source"] =
|
||||
described_source<renderive::Frame_Observer_Snapshot>(
|
||||
described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "frequency_limit_enabled");
|
||||
field["disabled_label"] = "已关闭";
|
||||
} else if (name == "end_to_end_ns") {
|
||||
@@ -345,17 +345,17 @@ Json dashboard_contract() {
|
||||
Json point_pair{{"label", "输入→绘制"}, {"format", "pair"},
|
||||
{"sources", Json::array({"data_shape.input_points", "data_shape.rendered_elements"})},
|
||||
{"separator", "→"}};
|
||||
Json bottleneck = described_dashboard_field<renderive::Frame_Observer_Snapshot>(
|
||||
Json bottleneck = described_dashboard_field<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "limit_state");
|
||||
bottleneck["format"] = "duration_enum";
|
||||
bottleneck["duration_sources"] = {
|
||||
{"frequency_limited", described_source<renderive::Frame_Observer_Snapshot>(
|
||||
{"frequency_limited", described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "target_interval_ns")},
|
||||
{"paint_limited", described_source<renderive::Frame_Observer_Snapshot>(
|
||||
{"paint_limited", described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "paint_duration_ns")},
|
||||
{"render_limited", described_source<renderive::Frame_Observer_Snapshot>(
|
||||
{"render_limited", described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "render_duration_ns")},
|
||||
{"consumer_limited", described_source<renderive::Frame_Observer_Snapshot>(
|
||||
{"consumer_limited", described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "consumer_interval_ns")}
|
||||
};
|
||||
Json dashboard{
|
||||
@@ -392,12 +392,12 @@ Json dashboard_contract() {
|
||||
dashboard_field("呈现 P95 ms", "client_performance.display_interval_p95_ms", "fixed", 2),
|
||||
dashboard_field("呈现 P99 ms", "client_performance.display_interval_p99_ms", "fixed", 2),
|
||||
dashboard_field("响应负载 MB/s", "performance.pixel_payload_megabytes_per_second", "fixed", 1),
|
||||
described_dashboard_field<renderive::Frame_Observer_Snapshot>(
|
||||
described_dashboard_field<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "pending_frame_count"),
|
||||
described_dashboard_field<renderive::Frame_Observer_Snapshot>(
|
||||
described_dashboard_field<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "dropped_frame_count"),
|
||||
std::move(point_pair), std::move(bottleneck),
|
||||
described_dashboard_field<renderive::Frame_Observer_Snapshot>(
|
||||
described_dashboard_field<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "last_event"),
|
||||
dashboard_field("像素超时", "client_performance.frame_request_timeout_count"),
|
||||
dashboard_field("最近像素龄", "client_performance.last_pixel_receive_age_ms", "milliseconds", 0)
|
||||
@@ -409,7 +409,7 @@ Json dashboard_contract() {
|
||||
{"title", "内核帧观察器"},
|
||||
{"source", "kernel_observer"},
|
||||
{"descriptor", adminive::to_descriptor_json<
|
||||
Json, renderive::Frame_Observer_Snapshot>()}
|
||||
Json, renderive::Plot_Frame_Status>()}
|
||||
}},
|
||||
{"renderables_source", "renderable_observers"},
|
||||
{"renderable_fields", Json::array({
|
||||
@@ -439,26 +439,26 @@ Json dashboard_contract() {
|
||||
}},
|
||||
{"limits", {
|
||||
{"aria_label", "低延迟限速来源"}, {"title", "限速来源"},
|
||||
{"current_source", described_source<renderive::Frame_Observer_Snapshot>(
|
||||
{"current_source", described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "limit_state")},
|
||||
{"active_label", "当前瓶颈"}, {"inactive_label", "未受限"},
|
||||
{"disabled_label", "已关闭"},
|
||||
{"fields", Json::array({
|
||||
{{"label", "内核用户频率"}, {"active_value", "frequency_limited"},
|
||||
{"duration_source", described_source<renderive::Frame_Observer_Snapshot>(
|
||||
{"duration_source", described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "target_interval_ns")},
|
||||
{"enabled_source", described_source<renderive::Frame_Observer_Snapshot>(
|
||||
{"enabled_source", described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "frequency_limit_enabled")}},
|
||||
{{"label", "内核绘制事件"}, {"active_value", "paint_limited"},
|
||||
{"duration_source", described_source<renderive::Frame_Observer_Snapshot>(
|
||||
{"duration_source", described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "paint_duration_ns")}},
|
||||
{{"label", "内核后台渲染"}, {"active_value", "render_limited"},
|
||||
{"duration_source", described_source<renderive::Frame_Observer_Snapshot>(
|
||||
{"duration_source", described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "render_duration_ns")}},
|
||||
{{"label", "消费者反馈"}, {"active_value", "consumer_limited"},
|
||||
{"duration_source", described_source<renderive::Frame_Observer_Snapshot>(
|
||||
{"duration_source", described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "consumer_interval_ns")},
|
||||
{"enabled_source", described_source<renderive::Frame_Observer_Snapshot>(
|
||||
{"enabled_source", described_source<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "consumer_feedback_enabled")}}
|
||||
})}
|
||||
}},
|
||||
@@ -466,11 +466,11 @@ Json dashboard_contract() {
|
||||
{"aria_label", "内核低延迟全量统计"},
|
||||
{"header", {
|
||||
{"prefix", "内核"}, {"suffix", "观察器"}, {"event_label", "事件"},
|
||||
{"mode", described_dashboard_field<renderive::Frame_Observer_Snapshot>(
|
||||
{"mode", described_dashboard_field<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "mode")},
|
||||
{"limit", described_dashboard_field<renderive::Frame_Observer_Snapshot>(
|
||||
{"limit", described_dashboard_field<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "limit_state")},
|
||||
{"event", described_dashboard_field<renderive::Frame_Observer_Snapshot>(
|
||||
{"event", described_dashboard_field<renderive::Plot_Frame_Status>(
|
||||
"kernel_observer", "last_event")}
|
||||
}},
|
||||
{"sections", Json::array({
|
||||
@@ -507,7 +507,7 @@ Json dashboard_contract() {
|
||||
}}
|
||||
};
|
||||
dashboard["observer"]["descriptor"] =
|
||||
adminive::to_descriptor_json<Json, renderive::Frame_Observer_Snapshot>();
|
||||
adminive::to_descriptor_json<Json, renderive::Plot_Frame_Status>();
|
||||
dashboard["observer"]["consumer_feedback_descriptor"] =
|
||||
adminive::to_descriptor_json<Json, Gallery_Consumer_Feedback_Snapshot>();
|
||||
return dashboard;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "render_2D/plottable/Performance_Overlay.h"
|
||||
#include "render_2D/renderable/Renderable.h"
|
||||
#include "render_2D/scene/Scene.h"
|
||||
#include "render_2D/scene/Plot_Scene.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
namespace adminive {
|
||||
|
||||
@@ -43,7 +43,7 @@ struct Type_Descriptor<renderive::web::Gallery_Session_Control<Scene_Type>> {
|
||||
static auto get() {
|
||||
using T = renderive::web::Gallery_Session_Control<Scene_Type>;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
const auto dirty = [](T& value) { value.scene_.notify_model_dirty(); };
|
||||
const auto dirty = [](T& value) { value.scene_.request_redraw(); };
|
||||
return adminive::object<T>("scene", "场景",
|
||||
callback_property<T, renderive::Color>(
|
||||
"background_color", "背景颜色", Field_Control::color,
|
||||
|
||||
@@ -49,7 +49,7 @@ double gaussian(double x, double center, double width) {
|
||||
}
|
||||
} // namespace
|
||||
struct Web_Plot_Session::Impl {
|
||||
Scene2D plot;
|
||||
Plot_Scene plot;
|
||||
renderive_Owner<Frequency_Axis> spectrum_frequency_axis;
|
||||
renderive_Owner<Axis> spectrum_power_axis;
|
||||
renderive_Owner<Frequency_Axis> waterfall_frequency_axis;
|
||||
@@ -306,7 +306,7 @@ struct Web_Plot_Session::Impl {
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Set_Demo_Mode>) {
|
||||
mode = value.mode;
|
||||
plot.notify_model_dirty();
|
||||
plot.request_redraw();
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Set_Center_Frequency>) {
|
||||
set_center_frequency(value.megahertz);
|
||||
@@ -316,7 +316,7 @@ struct Web_Plot_Session::Impl {
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Set_Gain>) {
|
||||
gain_db = value.decibels;
|
||||
plot.notify_model_dirty();
|
||||
plot.request_redraw();
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Set_Max_Hold>) {
|
||||
spectrum->set<&Spectrum::Properties::max_hold_visible>(value.enabled);
|
||||
|
||||
@@ -143,12 +143,24 @@ std::optional<double> action_number(const Gallery_Action_Request& request) {
|
||||
return std::nullopt;
|
||||
return std::get<double>(*request.argument);
|
||||
}
|
||||
|
||||
Plot_Frame_Mode plot_frame_mode(Gallery_Frame_Mode mode) {
|
||||
switch (mode) {
|
||||
case Gallery_Frame_Mode::Manual:
|
||||
return Plot_Frame_Mode::Manual;
|
||||
case Gallery_Frame_Mode::Low_Latency:
|
||||
return Plot_Frame_Mode::Low_Latency;
|
||||
case Gallery_Frame_Mode::Playback:
|
||||
return Plot_Frame_Mode::Playback;
|
||||
}
|
||||
throw std::invalid_argument("unknown gallery frame mode");
|
||||
}
|
||||
} // namespace
|
||||
template <class Scene_Type>
|
||||
class Gallery_Scene final : public Gallery_Scene_Interface {
|
||||
public:
|
||||
Gallery_Scene(std::uint64_t session_id, std::string case_id, Gallery_Frame_Mode frame_mode, bool automatic_low_latency)
|
||||
: session_id_(session_id), case_id_(std::move(case_id)), frame_mode_(frame_mode), automatic_low_latency_(automatic_low_latency), performance_started_(std::chrono::steady_clock::now()) {
|
||||
: session_id_(session_id), case_id_(std::move(case_id)), frame_mode_(frame_mode), automatic_low_latency_(automatic_low_latency),
|
||||
plot_(Plot_Scene_Options{plot_frame_mode(frame_mode)}), performance_started_(std::chrono::steady_clock::now()) {
|
||||
plot_.init();
|
||||
plot_.set_viewport_size({560, 320});
|
||||
root_ = plot_.root_renderable();
|
||||
@@ -172,7 +184,7 @@ public:
|
||||
}
|
||||
attach_performance_overlay(plot_);
|
||||
apply_layout();
|
||||
session_control_ = std::make_unique<Gallery_Session_Control<Scene_Type>>(
|
||||
session_control_ = std::make_unique<Gallery_Session_Control<Plot_Scene>>(
|
||||
plot_, *primary_, feedback_policy_);
|
||||
register_controls();
|
||||
set_performance_plot_name(plot_, case_id_ + "/" + gallery_enum_id(frame_mode_));
|
||||
@@ -193,9 +205,9 @@ public:
|
||||
[[nodiscard]] nlohmann::json controls() const {
|
||||
return {
|
||||
{"resources", controls_.resources()},
|
||||
{"observers", controls_.observers(plot_)},
|
||||
{"render_plan", controls_.render_plan(plot_)},
|
||||
{"performance_capture", gallery_performance_capture_json(plot_)}
|
||||
{"observers", controls_.observers(plot_.render_scene())},
|
||||
{"render_plan", controls_.render_plan(plot_.render_scene())},
|
||||
{"performance_capture", gallery_performance_capture_json(plot_.render_scene())}
|
||||
};
|
||||
}
|
||||
[[nodiscard]] Gallery_Frame_Mode frame_mode() const noexcept {
|
||||
@@ -262,7 +274,7 @@ public:
|
||||
}
|
||||
apply_layout();
|
||||
update_model();
|
||||
plot_.notify_model_dirty();
|
||||
plot_.request_redraw();
|
||||
return result;
|
||||
}
|
||||
void resize(int width, int height) override {
|
||||
@@ -351,10 +363,10 @@ public:
|
||||
last_action_result_.clear();
|
||||
recognized = true;
|
||||
if (request.id == "capture_next_frame") {
|
||||
const auto state = plot_.capture_state();
|
||||
const auto state = plot_.render_scene().capture_state();
|
||||
if (state.enabled())
|
||||
return "A performance capture session is already active";
|
||||
const auto session_id = plot_.capture_next_frame();
|
||||
const auto session_id = plot_.render_scene().capture_next_frame();
|
||||
last_action_result_ = "capture session=" + std::to_string(session_id);
|
||||
return "Capture next render frame requested";
|
||||
}
|
||||
@@ -364,10 +376,10 @@ public:
|
||||
return invalid_argument(recognized);
|
||||
const std::size_t count = static_cast<std::size_t>(
|
||||
std::clamp(std::llround(*argument), 1LL, 1000LL));
|
||||
const auto state = plot_.capture_state();
|
||||
const auto state = plot_.render_scene().capture_state();
|
||||
if (state.enabled())
|
||||
return "A performance capture session is already active";
|
||||
const auto session_id = plot_.capture_frames(count);
|
||||
const auto session_id = plot_.render_scene().capture_frames(count);
|
||||
last_action_result_ = "capture session=" + std::to_string(session_id) +
|
||||
", frames=" + std::to_string(count);
|
||||
return "Consecutive render frame capture requested";
|
||||
@@ -557,7 +569,7 @@ public:
|
||||
last_action_result_ = notice;
|
||||
}
|
||||
[[nodiscard]] std::string telemetry_json() const {
|
||||
const auto observer = plot_.frame_observer_snapshot();
|
||||
const auto observer = plot_.frame_status();
|
||||
const auto telemetry_now = std::chrono::steady_clock::now();
|
||||
const double elapsed_seconds = std::max(
|
||||
std::chrono::duration<double>(telemetry_now - performance_started_).count(),
|
||||
@@ -641,8 +653,8 @@ public:
|
||||
{"kernel_observer", std::move(observer_data)},
|
||||
{"consumer_feedback", std::move(consumer_feedback_data)},
|
||||
{"client_performance", std::move(client_performance_data)},
|
||||
{"renderable_observers", controls_.observers(plot_)},
|
||||
{"performance_capture", gallery_performance_capture_json(plot_)},
|
||||
{"renderable_observers", controls_.observers(plot_.render_scene())},
|
||||
{"performance_capture", gallery_performance_capture_json(plot_.render_scene())},
|
||||
{"last_action_result", last_action_result_}
|
||||
};
|
||||
if (primary_) {
|
||||
@@ -925,7 +937,7 @@ private:
|
||||
if (now - last_performance_log_ < std::chrono::seconds(1))
|
||||
return;
|
||||
last_performance_log_ = now;
|
||||
const auto observer = plot_.frame_observer_snapshot();
|
||||
const auto observer = plot_.frame_status();
|
||||
const auto unix_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
@@ -1344,9 +1356,9 @@ private:
|
||||
std::string case_id_;
|
||||
Gallery_Frame_Mode frame_mode_ = Gallery_Frame_Mode::Low_Latency;
|
||||
bool automatic_low_latency_{};
|
||||
Scene_Type plot_;
|
||||
Plot_Scene plot_;
|
||||
Gallery_Feedback_Policy feedback_policy_;
|
||||
std::unique_ptr<Gallery_Session_Control<Scene_Type>> session_control_;
|
||||
std::unique_ptr<Gallery_Session_Control<Plot_Scene>> session_control_;
|
||||
Gallery_Controls controls_;
|
||||
std::chrono::steady_clock::time_point performance_started_;
|
||||
std::chrono::steady_clock::time_point last_performance_log_;
|
||||
@@ -1389,14 +1401,7 @@ private:
|
||||
std::string last_action_result_;
|
||||
};
|
||||
std::unique_ptr<Gallery_Scene_Interface> make_gallery_scene_2d(std::uint64_t session_id, std::string case_id, Gallery_Frame_Mode mode, bool automatic_low_latency) {
|
||||
switch (mode) {
|
||||
case Gallery_Frame_Mode::Manual:
|
||||
return std::make_unique<Gallery_Scene<Manual_Scene2D>>(session_id, std::move(case_id), mode, automatic_low_latency);
|
||||
case Gallery_Frame_Mode::Low_Latency:
|
||||
return std::make_unique<Gallery_Scene<Scene2D>>(session_id, std::move(case_id), mode, automatic_low_latency);
|
||||
case Gallery_Frame_Mode::Playback:
|
||||
return std::make_unique<Gallery_Scene<Playback_Scene2D>>(session_id, std::move(case_id), mode, automatic_low_latency);
|
||||
}
|
||||
throw std::invalid_argument("unknown gallery frame mode");
|
||||
return std::make_unique<Gallery_Scene>(session_id, std::move(case_id),
|
||||
mode, automatic_low_latency);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
@@ -219,6 +220,9 @@ public:
|
||||
successful_render_count_ = 0;
|
||||
pixel_frame_count_ = 0;
|
||||
last_render_ms_ = 0.0;
|
||||
last_pixel_encode_ms_ = 0.0;
|
||||
render_history_.clear();
|
||||
pixel_history_.clear();
|
||||
last_event_ = "monitoring_reset";
|
||||
}
|
||||
|
||||
@@ -325,6 +329,7 @@ public:
|
||||
last_pixel_encode_ms_ = std::chrono::duration<double, std::milli>(
|
||||
encode_finished - encode_started)
|
||||
.count();
|
||||
record_sample(pixel_history_, encode_finished);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string action(const Gallery_Action_Request& request,
|
||||
@@ -433,19 +438,21 @@ public:
|
||||
|
||||
[[nodiscard]] std::string telemetry_json() const override {
|
||||
const auto status = scene_.frame_status();
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
return nlohmann::json{
|
||||
{"kernel_observer",
|
||||
{{"mode", mode_id(frame_mode_)},
|
||||
{"last_event", last_event_},
|
||||
{"pending_frame_count", status.pending_frame_count},
|
||||
{"dropped_frame_count", status.dropped_frame_count}}},
|
||||
{"render_performance",
|
||||
{"performance",
|
||||
{{"render_attempt_count", render_attempt_count_},
|
||||
{"successful_render_count", successful_render_count_},
|
||||
{"failed_render_count",
|
||||
render_attempt_count_ - successful_render_count_},
|
||||
{"measured_fps", recent_rate(render_history_, now)},
|
||||
{"last_render_ms", last_render_ms_},
|
||||
{"pixel_response_fps", 0.0},
|
||||
{"pixel_response_fps", recent_rate(pixel_history_, now)},
|
||||
{"last_pixel_encode_ms", last_pixel_encode_ms_},
|
||||
{"last_pixel_bytes", last_pixel_bytes_},
|
||||
{"automatic_low_latency_scheduler", can_render_automatically()}}},
|
||||
@@ -462,6 +469,31 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
using Performance_Clock = std::chrono::steady_clock;
|
||||
|
||||
static void record_sample(std::deque<Performance_Clock::time_point>& samples,
|
||||
Performance_Clock::time_point now) {
|
||||
samples.push_back(now);
|
||||
const auto cutoff = now - std::chrono::seconds(2);
|
||||
while (!samples.empty() && samples.front() < cutoff)
|
||||
samples.pop_front();
|
||||
}
|
||||
|
||||
static double recent_rate(
|
||||
const std::deque<Performance_Clock::time_point>& samples,
|
||||
Performance_Clock::time_point now) {
|
||||
const auto cutoff = now - std::chrono::seconds(1);
|
||||
const auto first = std::find_if(samples.begin(), samples.end(),
|
||||
[cutoff](auto sample) {
|
||||
return sample >= cutoff;
|
||||
});
|
||||
const auto count = std::distance(first, samples.end());
|
||||
if (count < 2)
|
||||
return 0.0;
|
||||
const double seconds = std::chrono::duration<double>(samples.back() - *first).count();
|
||||
return seconds > 0.0 ? static_cast<double>(count - 1) / seconds : 0.0;
|
||||
}
|
||||
|
||||
static std::vector<Point> initial_points() {
|
||||
return {{{-0.62F, -0.10F, 0.0F}, {255, 32, 24, 255}, 74.0F},
|
||||
{{0.0F, -0.10F, 0.0F}, {24, 255, 36, 255}, 74.0F},
|
||||
@@ -513,6 +545,8 @@ private:
|
||||
std::chrono::steady_clock::now() - started)
|
||||
.count();
|
||||
successful_render_count_ += rendered ? 1U : 0U;
|
||||
if (rendered)
|
||||
record_sample(render_history_, std::chrono::steady_clock::now());
|
||||
return rendered;
|
||||
}
|
||||
|
||||
@@ -524,6 +558,8 @@ private:
|
||||
std::chrono::steady_clock::now() - started)
|
||||
.count();
|
||||
successful_render_count_ += rendered ? 1U : 0U;
|
||||
if (rendered)
|
||||
record_sample(render_history_, std::chrono::steady_clock::now());
|
||||
return rendered;
|
||||
}
|
||||
|
||||
@@ -546,6 +582,8 @@ private:
|
||||
double last_render_ms_{};
|
||||
double last_pixel_encode_ms_{};
|
||||
std::size_t last_pixel_bytes_{};
|
||||
std::deque<Performance_Clock::time_point> render_history_;
|
||||
std::deque<Performance_Clock::time_point> pixel_history_;
|
||||
std::string last_event_{"initialized"};
|
||||
std::string last_action_result_;
|
||||
};
|
||||
|
||||
@@ -236,6 +236,15 @@ TEST(RenderiveWebDatovizGallery, PublishesRealRgbaAndRendersAfterResize) {
|
||||
ASSERT_EQ(invoke_action(session, "mode_render").at("type"), "case_state");
|
||||
const std::string resized = request_pixels(session);
|
||||
expect_actual_datoviz_pixels(resized, 900, 500);
|
||||
|
||||
const auto observed = response_json(session.handle(gallery_request(
|
||||
Gallery_Request_Kind::Observe,
|
||||
R"({"category":"event","type":"gallery_observe","client_metrics":{}})")));
|
||||
const auto& performance = observed.at("telemetry").at("performance");
|
||||
EXPECT_GT(performance.at("measured_fps").get<double>(), 0.0);
|
||||
EXPECT_GT(performance.at("pixel_response_fps").get<double>(), 0.0);
|
||||
EXPECT_GT(performance.at("last_render_ms").get<double>(), 0.0);
|
||||
EXPECT_GT(performance.at("last_pixel_encode_ms").get<double>(), 0.0);
|
||||
}
|
||||
|
||||
TEST(RenderiveWebDatovizGallery, AutomaticLowLatencyFramesCarryAnimatedState) {
|
||||
|
||||
Reference in New Issue
Block a user