3D 第一个控件成功显示
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "Pixel_Frame.h"
|
||||
#include "Web_Performance_Log.h"
|
||||
#include "render_2D/export.h"
|
||||
#include "render_3D/Point_Demo.h"
|
||||
#include <renderive/base/statistics/Rolling_Statistics.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <algorithm>
|
||||
@@ -17,6 +18,7 @@
|
||||
#include <condition_variable>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <numbers>
|
||||
@@ -91,6 +93,9 @@ public:
|
||||
[[nodiscard]] virtual adminive::Update_Result apply_patch(std::string_view target, const nlohmann::json& patch) = 0;
|
||||
virtual void resize(Size size) = 0;
|
||||
virtual void dispatch(const Event& event) = 0;
|
||||
virtual void dispatch(const Pointer_Event& event) = 0;
|
||||
virtual void dispatch(const Wheel_Event& event) = 0;
|
||||
virtual void dispatch(const Key_Event& event) = 0;
|
||||
virtual bool render_latest_frame() = 0;
|
||||
[[nodiscard]] virtual std::optional<std::string> encode_latest_pixels() = 0;
|
||||
virtual void record_pixel_response(std::chrono::steady_clock::time_point request_started, std::chrono::steady_clock::time_point encode_started, std::chrono::steady_clock::time_point encode_finished, std::size_t pixel_bytes) = 0;
|
||||
@@ -235,6 +240,15 @@ public:
|
||||
plot_.deactivate_view();
|
||||
plot_.dispatch_event(event);
|
||||
}
|
||||
void dispatch(const Pointer_Event& event) {
|
||||
plot_.dispatch_event(event);
|
||||
}
|
||||
void dispatch(const Wheel_Event& event) {
|
||||
plot_.dispatch_event(event);
|
||||
}
|
||||
void dispatch(const Key_Event& event) {
|
||||
plot_.dispatch_event(event);
|
||||
}
|
||||
bool render_latest_frame() {
|
||||
if (!plot_.view_active())
|
||||
return false;
|
||||
@@ -1302,7 +1316,350 @@ private:
|
||||
bool rendered_since_last_pixel_{};
|
||||
std::string last_action_result_;
|
||||
};
|
||||
|
||||
render_3d::Frame_Mode point_frame_mode(Gallery_Frame_Mode mode) {
|
||||
switch (mode) {
|
||||
case Gallery_Frame_Mode::Manual:
|
||||
return render_3d::Frame_Mode::Manual;
|
||||
case Gallery_Frame_Mode::Low_Latency:
|
||||
return render_3d::Frame_Mode::Low_Latency;
|
||||
case Gallery_Frame_Mode::Playback:
|
||||
return render_3d::Frame_Mode::Playback;
|
||||
}
|
||||
throw std::invalid_argument("unknown 3D frame mode");
|
||||
}
|
||||
|
||||
class Point_Gallery_Scene final : public Gallery_Scene_Interface {
|
||||
public:
|
||||
Point_Gallery_Scene(Gallery_Frame_Mode mode, bool automatic_low_latency)
|
||||
: mode_(mode), automatic_low_latency_(automatic_low_latency),
|
||||
performance_started_(std::chrono::steady_clock::now()),
|
||||
demo_(render_3d::make_point_demo({
|
||||
{560, 320}, {}, point_frame_mode(mode), 60.0, 0, false})) {
|
||||
if (mode_ == Gallery_Frame_Mode::Playback) {
|
||||
for (int index = 0; index < 24; ++index) {
|
||||
phase_ = -1.20F + static_cast<float>(index) * 0.05F;
|
||||
publish_demo_points();
|
||||
(void)demo_.scene->prepare_frame();
|
||||
}
|
||||
(void)record_render([this] { return demo_.scene->render_prepared_frame(); });
|
||||
} else {
|
||||
(void)record_render([this] { return demo_.scene->request_frame(); });
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string& case_id() const noexcept override {
|
||||
return case_id_;
|
||||
}
|
||||
[[nodiscard]] nlohmann::json controls() const override {
|
||||
return {{"resources", nlohmann::json::array()},
|
||||
{"observers", nlohmann::json::array()},
|
||||
{"render_plan", nullptr},
|
||||
{"performance_capture", nullptr}};
|
||||
}
|
||||
[[nodiscard]] Gallery_Frame_Mode frame_mode() const noexcept override {
|
||||
return mode_;
|
||||
}
|
||||
void reset_monitoring() override {
|
||||
performance_started_ = std::chrono::steady_clock::now();
|
||||
render_attempt_count_ = 0;
|
||||
successful_render_count_ = 0;
|
||||
render_duration_statistics_.clear();
|
||||
pixel_encode_statistics_.clear();
|
||||
pixel_request_statistics_.clear();
|
||||
last_render_ms_ = 0.0;
|
||||
last_pixel_encode_ms_ = 0.0;
|
||||
last_pixel_request_ms_ = 0.0;
|
||||
last_pixel_bytes_ = 0;
|
||||
client_performance_ = {};
|
||||
}
|
||||
[[nodiscard]] bool can_render_automatically() const noexcept override {
|
||||
return active_ && automatic_low_latency_ &&
|
||||
mode_ == Gallery_Frame_Mode::Low_Latency;
|
||||
}
|
||||
[[nodiscard]] std::uint64_t kernel_refresh_interval_ns() const override {
|
||||
const auto interval = demo_.scene->frame_status().next_refresh_interval_ns;
|
||||
return interval == 0 ? 16'666'667U : interval;
|
||||
}
|
||||
void set_client_metrics(Gallery_Client_Performance metrics) noexcept override {
|
||||
client_performance_ = metrics;
|
||||
}
|
||||
[[nodiscard]] adminive::Update_Result apply_patch(
|
||||
std::string_view target, const nlohmann::json&) override {
|
||||
adminive::Update_Result result;
|
||||
result.message = "point_3d has no patchable control: " + std::string(target);
|
||||
return result;
|
||||
}
|
||||
void resize(Size size) override {
|
||||
if (size.width <= 0 || size.height <= 0)
|
||||
return;
|
||||
demo_.scene->resize({static_cast<std::uint32_t>(size.width),
|
||||
static_cast<std::uint32_t>(size.height)});
|
||||
rendered_since_last_pixel_ = false;
|
||||
}
|
||||
void dispatch(const Event& event) override {
|
||||
if (event.type == Event_Type::Show)
|
||||
active_ = true;
|
||||
else if (event.type == Event_Type::Hide)
|
||||
active_ = false;
|
||||
demo_.scene->dispatch(event);
|
||||
}
|
||||
void dispatch(const Pointer_Event& event) override {
|
||||
if (active_)
|
||||
demo_.scene->dispatch(event);
|
||||
}
|
||||
void dispatch(const Wheel_Event& event) override {
|
||||
if (active_)
|
||||
demo_.scene->dispatch(event);
|
||||
}
|
||||
void dispatch(const Key_Event& event) override {
|
||||
if (active_)
|
||||
demo_.scene->dispatch(event);
|
||||
}
|
||||
bool render_latest_frame() override {
|
||||
if (!active_)
|
||||
return false;
|
||||
if (can_render_automatically()) {
|
||||
phase_ += 0.045F;
|
||||
publish_demo_points();
|
||||
}
|
||||
return record_render([this] { return demo_.scene->request_frame(); });
|
||||
}
|
||||
[[nodiscard]] std::optional<std::string> encode_latest_pixels() override {
|
||||
if (!active_)
|
||||
return std::nullopt;
|
||||
if (!rendered_since_last_pixel_ && !can_render_automatically() &&
|
||||
!render_latest_frame())
|
||||
return std::nullopt;
|
||||
const auto frame = demo_.scene->latest_frame();
|
||||
if (!frame)
|
||||
return std::nullopt;
|
||||
rendered_since_last_pixel_ = false;
|
||||
auto encoded = encode_rgba8_pixel_frame(
|
||||
frame->rgba8.data(), frame->extent.width, frame->extent.height,
|
||||
static_cast<std::size_t>(frame->extent.width) * 4U);
|
||||
return encoded.empty() ? std::nullopt
|
||||
: std::optional<std::string>(std::move(encoded));
|
||||
}
|
||||
void record_pixel_response(
|
||||
std::chrono::steady_clock::time_point request_started,
|
||||
std::chrono::steady_clock::time_point encode_started,
|
||||
std::chrono::steady_clock::time_point encode_finished,
|
||||
std::size_t pixel_bytes) override {
|
||||
last_pixel_encode_ms_ = std::chrono::duration<double, std::milli>(
|
||||
encode_finished - encode_started)
|
||||
.count();
|
||||
last_pixel_request_ms_ = std::chrono::duration<double, std::milli>(
|
||||
encode_finished - request_started)
|
||||
.count();
|
||||
last_pixel_bytes_ = pixel_bytes;
|
||||
pixel_encode_statistics_.add(last_pixel_encode_ms_);
|
||||
pixel_request_statistics_.add(last_pixel_request_ms_);
|
||||
}
|
||||
[[nodiscard]] std::string action(const Gallery_Action_Request& request,
|
||||
bool& recognized) override {
|
||||
recognized = true;
|
||||
if (request.id == "mode_prepare") {
|
||||
const bool prepared = demo_.scene->prepare_frame();
|
||||
last_action_result_ = prepared ? "prepared" : "prepare_rejected";
|
||||
return prepared ? "Point frame prepared" : "Point frame prepare rejected";
|
||||
}
|
||||
if (request.id == "mode_refresh") {
|
||||
const bool refreshed = demo_.scene->refresh_manual_frame();
|
||||
last_action_result_ = refreshed ? "refresh_succeeded" : "refresh_failed";
|
||||
return refreshed ? "Point manual frame refreshed" : "No manual frame to refresh";
|
||||
}
|
||||
if (request.id == "mode_render" || request.id == "mode_dequeue") {
|
||||
const bool rendered = record_render(
|
||||
[this] { return demo_.scene->render_prepared_frame(); });
|
||||
last_action_result_ = rendered ? "rendered" : "render_queue_empty";
|
||||
return rendered ? "Point frame rendered" : "No Point frame available";
|
||||
}
|
||||
if (request.id == "mode_discard") {
|
||||
const bool discarded = demo_.scene->discard_pending_frame();
|
||||
last_action_result_ = discarded ? "manually_discarded" : "discard_failed";
|
||||
return discarded ? "Pending Point frame discarded" : "No Point frame to discard";
|
||||
}
|
||||
if (request.id == "mode_enqueue") {
|
||||
phase_ += 0.05F;
|
||||
publish_demo_points();
|
||||
const bool enqueued = demo_.scene->prepare_frame();
|
||||
last_action_result_ = enqueued ? "enqueued" : "enqueue_failed";
|
||||
return enqueued ? "Point playback frame enqueued" : "Point enqueue failed";
|
||||
}
|
||||
if (request.id == "orbit_points") {
|
||||
phase_ += 0.25F;
|
||||
publish_demo_points();
|
||||
last_action_result_ = "points_orbited";
|
||||
rendered_since_last_pixel_ = false;
|
||||
return "Point positions updated through Latest_Real_Time_Data";
|
||||
}
|
||||
if (request.id == "add_point") {
|
||||
auto points = current_points();
|
||||
points.push_back({{0.12F, -0.72F, 0.58F}, {55, 235, 230, 255}, 46.0F});
|
||||
demo_.points->update(std::move(points));
|
||||
last_action_result_ = "point_added";
|
||||
rendered_since_last_pixel_ = false;
|
||||
return "Point added to the bulk payload";
|
||||
}
|
||||
if (request.id == "remove_point") {
|
||||
auto points = current_points();
|
||||
if (points.size() > render_3d::point_demo_data().size()) {
|
||||
points.pop_back();
|
||||
demo_.points->update(std::move(points));
|
||||
last_action_result_ = "point_removed";
|
||||
rendered_since_last_pixel_ = false;
|
||||
return "Last added Point removed";
|
||||
}
|
||||
last_action_result_ = "no_added_point";
|
||||
return "No added Point to remove";
|
||||
}
|
||||
if (request.id == "point_churn") {
|
||||
auto stable = current_points();
|
||||
auto transient = stable;
|
||||
transient.push_back({{0.0F, 0.0F, 0.8F}, {255, 255, 255, 255}, 72.0F});
|
||||
demo_.points->update(std::move(transient));
|
||||
demo_.points->update(std::move(stable));
|
||||
last_action_result_ = "point_churned";
|
||||
rendered_since_last_pixel_ = false;
|
||||
return "Transient Point added and removed before the next frame snapshot";
|
||||
}
|
||||
if (request.id == "reset_points") {
|
||||
phase_ = 0.0F;
|
||||
publish_demo_points();
|
||||
last_action_result_ = "points_reset";
|
||||
rendered_since_last_pixel_ = false;
|
||||
return "Point demo payload reset";
|
||||
}
|
||||
recognized = false;
|
||||
return {};
|
||||
}
|
||||
void record_action_notice_if_empty(std::string_view notice) override {
|
||||
if (last_action_result_.empty())
|
||||
last_action_result_ = notice;
|
||||
}
|
||||
[[nodiscard]] std::string telemetry_json() const override {
|
||||
const auto status = demo_.scene->frame_status();
|
||||
const auto frame = demo_.scene->latest_frame();
|
||||
const auto points = current_points();
|
||||
const auto render_window = render_duration_statistics_.snapshot();
|
||||
const auto encode_window = pixel_encode_statistics_.snapshot();
|
||||
const auto request_window = pixel_request_statistics_.snapshot();
|
||||
const double elapsed = std::max(
|
||||
std::chrono::duration<double>(std::chrono::steady_clock::now() -
|
||||
performance_started_)
|
||||
.count(),
|
||||
1e-9);
|
||||
Gallery_Render_Performance performance;
|
||||
performance.render_attempt_count = render_attempt_count_;
|
||||
performance.successful_render_count = successful_render_count_;
|
||||
performance.failed_render_count = render_attempt_count_ - successful_render_count_;
|
||||
performance.lifetime_average_fps = successful_render_count_ / elapsed;
|
||||
performance.last_render_ms = last_render_ms_;
|
||||
performance.average_render_ms = render_window.average;
|
||||
performance.maximum_render_ms = render_window.maximum;
|
||||
performance.render_deviation_ms = render_window.deviation;
|
||||
performance.render_p50_ms = render_window.p50;
|
||||
performance.render_p95_ms = render_window.p95;
|
||||
performance.render_p99_ms = render_window.p99;
|
||||
performance.render_sample_count = render_window.sample_count;
|
||||
performance.last_pixel_encode_ms = last_pixel_encode_ms_;
|
||||
performance.average_pixel_encode_ms = encode_window.average;
|
||||
performance.maximum_pixel_encode_ms = encode_window.maximum;
|
||||
performance.pixel_encode_deviation_ms = encode_window.deviation;
|
||||
performance.pixel_encode_p50_ms = encode_window.p50;
|
||||
performance.pixel_encode_p95_ms = encode_window.p95;
|
||||
performance.pixel_encode_p99_ms = encode_window.p99;
|
||||
performance.pixel_encode_sample_count = encode_window.sample_count;
|
||||
performance.last_pixel_request_ms = last_pixel_request_ms_;
|
||||
performance.average_pixel_request_ms = request_window.average;
|
||||
performance.pixel_request_deviation_ms = request_window.deviation;
|
||||
performance.pixel_request_p95_ms = request_window.p95;
|
||||
performance.pixel_request_p99_ms = request_window.p99;
|
||||
performance.last_pixel_bytes = last_pixel_bytes_;
|
||||
performance.automatic_low_latency_scheduler = can_render_automatically();
|
||||
|
||||
const auto extent = frame ? frame->extent : render_3d::Extent{560, 320};
|
||||
nlohmann::json telemetry{
|
||||
{"case", case_id_},
|
||||
{"frame_mode", gallery_enum_id(mode_)},
|
||||
{"frame_index", status.latest_sequence},
|
||||
{"viewport", {{"width", extent.width}, {"height", extent.height}}},
|
||||
{"view_active", active_},
|
||||
{"kernel_frame_count", status.consumed_frame_count},
|
||||
{"performance", adminive::to_frontend_json<nlohmann::json>(performance)},
|
||||
{"kernel_observer",
|
||||
{{"mode", gallery_enum_id(mode_)},
|
||||
{"last_event", last_action_result_.empty()
|
||||
? (frame ? "rendered" : "none")
|
||||
: last_action_result_},
|
||||
{"frequency_hz", status.frequency_hz},
|
||||
{"produced_frame_count", status.produced_frame_count},
|
||||
{"consumed_frame_count", status.consumed_frame_count},
|
||||
{"dropped_frame_count", status.dropped_frame_count},
|
||||
{"failed_operation_count", status.failed_operation_count},
|
||||
{"pending_frame_count", status.pending_frame_count},
|
||||
{"latest_sequence", status.latest_sequence},
|
||||
{"next_refresh_interval_ns", status.next_refresh_interval_ns}}},
|
||||
{"consumer_feedback", nlohmann::json::object()},
|
||||
{"client_performance",
|
||||
adminive::to_frontend_json<nlohmann::json>(client_performance_)},
|
||||
{"renderable_observers", nlohmann::json::array()},
|
||||
{"performance_capture", nullptr},
|
||||
{"last_action_result", last_action_result_},
|
||||
{"point_3d", {{"point_count", points.size()},
|
||||
{"data_revision", demo_.points->revision()}}},
|
||||
{"data_shape", {{"input_elements", points.size()},
|
||||
{"rendered_elements", points.size()}}}}
|
||||
;
|
||||
return telemetry.dump();
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::vector<render_3d::Point> current_points() const {
|
||||
return demo_.points->snapshot().value_or(std::vector<render_3d::Point>{});
|
||||
}
|
||||
void publish_demo_points() {
|
||||
demo_.points->update(render_3d::point_demo_data(phase_));
|
||||
}
|
||||
template <class Render>
|
||||
bool record_render(Render&& render) {
|
||||
++render_attempt_count_;
|
||||
const auto started = std::chrono::steady_clock::now();
|
||||
const bool rendered = std::invoke(std::forward<Render>(render));
|
||||
last_render_ms_ = std::chrono::duration<double, std::milli>(
|
||||
std::chrono::steady_clock::now() - started)
|
||||
.count();
|
||||
render_duration_statistics_.add(last_render_ms_);
|
||||
successful_render_count_ += rendered ? 1U : 0U;
|
||||
rendered_since_last_pixel_ = rendered;
|
||||
return rendered;
|
||||
}
|
||||
|
||||
std::string case_id_{"point_3d"};
|
||||
Gallery_Frame_Mode mode_;
|
||||
bool automatic_low_latency_{};
|
||||
bool active_{true};
|
||||
std::chrono::steady_clock::time_point performance_started_;
|
||||
render_3d::Point_Demo demo_;
|
||||
float phase_{};
|
||||
std::uint64_t render_attempt_count_{};
|
||||
std::uint64_t successful_render_count_{};
|
||||
double last_render_ms_{};
|
||||
Rolling_Statistics render_duration_statistics_{256};
|
||||
double last_pixel_encode_ms_{};
|
||||
double last_pixel_request_ms_{};
|
||||
std::size_t last_pixel_bytes_{};
|
||||
Rolling_Statistics pixel_encode_statistics_{256};
|
||||
Rolling_Statistics pixel_request_statistics_{256};
|
||||
Gallery_Client_Performance client_performance_;
|
||||
bool rendered_since_last_pixel_{};
|
||||
std::string last_action_result_;
|
||||
};
|
||||
|
||||
std::unique_ptr<Gallery_Scene_Interface> make_gallery_scene(std::uint64_t session_id, std::string case_id, Gallery_Frame_Mode mode, bool automatic_low_latency) {
|
||||
if (case_id == "point_3d")
|
||||
return std::make_unique<Point_Gallery_Scene>(mode, 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);
|
||||
|
||||
Reference in New Issue
Block a user