3D 第一个控件成功显示

This commit is contained in:
2026-08-14 11:07:38 +08:00
parent 02c60679e4
commit 38231dbc1c
28 changed files with 2758 additions and 28 deletions
+357
View File
@@ -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);