3D 优化

This commit is contained in:
2026-08-28 01:07:54 +08:00
parent b9f19de776
commit fc68247cbc
28 changed files with 1317 additions and 573 deletions
@@ -52,7 +52,7 @@ struct Frame_Policy_Event {
* 任意线程只向 MPMC 事件流提交事实;Plot tick consumer 是唯一归并写者。
* 查询方只读取 current State,不参与事件归并,也不获取 Plot/Scene 锁。
*/
struct Frame_Policy final : double_buffer::Def<
struct Frame_Policy : double_buffer::Def<
Frame_Policy, double_buffer::Root,
double_buffer::Mpmc_Triple_Buffer<
detail::Frame_Policy_Event_Stream, detail::Frame_Policy_Event>> {
@@ -0,0 +1,65 @@
#include "Frame_Policy_3D.hpp"
#include <algorithm>
#include <span>
#include <utility>
namespace aethera {
void Frame_Policy_3D::submit_3d(detail::Frame_Policy_3D_Event event) {
submit_stream<detail::Frame_Policy_3D_Event_Stream>(std::move(event));
}
void Frame_Policy_3D::record_gpu_submitted(
std::uint64_t sequence, bool overlaps_gpu) {
submit_3d({detail::Frame_Policy_3D_Event_Type::submitted,
sequence, overlaps_gpu});
}
void Frame_Policy_3D::record_gpu_completed(std::uint64_t sequence) {
submit_3d({detail::Frame_Policy_3D_Event_Type::completed, sequence});
}
void Frame_Policy_3D::reset_3d_statistics() {
submit_3d({detail::Frame_Policy_3D_Event_Type::reset});
}
bool Frame_Policy_3D::consume_3d_events() {
exchange_stream<detail::Frame_Policy_3D_Event_Stream>();
bool consumed{};
auto& state = static_cast<State&>(
double_buffer::detail::Internal_Access::pending_state(this));
access_rendering_stream<detail::Frame_Policy_3D_Event_Stream>(
[&](std::span<detail::Frame_Policy_3D_Event> events) {
for (const auto& event : events) {
consumed = true;
switch (event.type) {
case detail::Frame_Policy_3D_Event_Type::submitted:
++state.gpu_submission_count;
++state.gpu_in_flight;
state.peak_gpu_in_flight = std::max(
state.peak_gpu_in_flight, state.gpu_in_flight);
state.last_submitted_sequence = event.sequence;
if (event.overlaps_gpu)
++state.overlapped_release_count;
else
++state.completion_gated_release_count;
break;
case detail::Frame_Policy_3D_Event_Type::completed:
++state.gpu_completion_count;
if (state.gpu_in_flight != 0) --state.gpu_in_flight;
state.last_completed_sequence = event.sequence;
break;
case detail::Frame_Policy_3D_Event_Type::reset: {
const auto in_flight = state.gpu_in_flight;
state = {};
state.pipeline_capacity = 3;
state.gpu_in_flight = in_flight;
state.peak_gpu_in_flight = in_flight;
break;
}
}
}
});
if (consumed) publish_state<Base_Tag>();
return consumed;
}
}
@@ -0,0 +1,53 @@
#pragma once
#include "Frame_Policy.hpp"
#include <cstddef>
namespace aethera {
namespace detail {
struct Frame_Policy_3D_Event_Stream;
enum struct Frame_Policy_3D_Event_Type : std::uint8_t {
submitted,
completed,
reset
};
struct Frame_Policy_3D_Event {
Frame_Policy_3D_Event_Type type{};
std::uint64_t sequence{};
bool overlaps_gpu{};
};
}
/*
* 3D 策略是 Frame_Policy 的独立状态层。它复用公共请求/吞吐事实,但不改变
* 2D Frame_Policy 的默认模式和完成释放语义。GPU 提交与退休由独立 MPMC
* 事件流进入,Plot 的唯一 tick consumer 归并并通过 double-buffer 发布。
*/
struct Frame_Policy_3D final : double_buffer::Def<
Frame_Policy_3D, Frame_Policy,
double_buffer::Mpmc_Triple_Buffer<
detail::Frame_Policy_3D_Event_Stream,
detail::Frame_Policy_3D_Event>> {
struct Prop : Prev_Prop {};
struct State : Prev_State {
std::size_t pipeline_capacity{3}; /* Scene 可绑定的物理 3D 帧槽数量。 */
std::uint64_t gpu_submission_count{}; /* Vulkan 实际提交的累计帧数。 */
std::uint64_t overlapped_release_count{}; /* 提交后即开放下一次 Prepare 的累计帧数。 */
std::uint64_t completion_gated_release_count{}; /* 因共享资源而等 GPU 退休后开放的累计帧数。 */
std::uint64_t gpu_completion_count{}; /* fence 正常或失败退休的累计帧数。 */
std::uint64_t gpu_in_flight{}; /* 已实际提交且尚未退休的当前帧数。 */
std::uint64_t peak_gpu_in_flight{}; /* 本统计代次内 gpu_in_flight 峰值。 */
std::uint64_t last_submitted_sequence{}; /* 最近实际提交的帧序号;未提交时为 0。 */
std::uint64_t last_completed_sequence{}; /* 最近退休的帧序号;未退休时为 0。 */
bool operator==(const State&) const = default;
};
struct Private : Prev_Private {};
void record_gpu_submitted(std::uint64_t sequence, bool overlaps_gpu);
void record_gpu_completed(std::uint64_t sequence);
void reset_3d_statistics();
[[nodiscard]] bool consume_3d_events();
private:
void submit_3d(detail::Frame_Policy_3D_Event event);
};
}
+58
View File
@@ -0,0 +1,58 @@
#include "Frame_Policy/Frame_Policy_3D.hpp"
#include <gtest/gtest.h>
#include <utility>
namespace {
TEST(frame_policy_3d, publishes_gpu_pipeline_facts_without_changing_common_policy) {
auto built = aethera::Frame_Policy_3D::Builder<
aethera::Frame_Policy_3D>{}.build();
ASSERT_TRUE(built.has_value());
auto policy = std::move(*built);
policy->record_gpu_submitted(11, true);
policy->record_gpu_submitted(12, false);
policy->record_gpu_completed(11);
ASSERT_TRUE(policy->consume_3d_events());
const auto& pipeline = policy->read_state<
aethera::Frame_Policy_3D::Base_Tag>();
EXPECT_EQ(pipeline.pipeline_capacity, 3u);
EXPECT_EQ(pipeline.gpu_submission_count, 2u);
EXPECT_EQ(pipeline.overlapped_release_count, 1u);
EXPECT_EQ(pipeline.completion_gated_release_count, 1u);
EXPECT_EQ(pipeline.gpu_completion_count, 1u);
EXPECT_EQ(pipeline.gpu_in_flight, 1u);
EXPECT_EQ(pipeline.peak_gpu_in_flight, 2u);
EXPECT_EQ(pipeline.last_submitted_sequence, 12u);
EXPECT_EQ(pipeline.last_completed_sequence, 11u);
const auto& common = policy->read_state<aethera::Frame_Policy::Base_Tag>();
EXPECT_EQ(common.submitted_frame_count, 0u);
EXPECT_EQ(common.completed_frame_count, 0u);
EXPECT_EQ(common.mode, aethera::Frame_Pacing_Mode::fixed_rate);
}
TEST(frame_policy_3d, reset_preserves_only_current_in_flight_ownership) {
auto built = aethera::Frame_Policy_3D::Builder<
aethera::Frame_Policy_3D>{}.build();
ASSERT_TRUE(built.has_value());
auto policy = std::move(*built);
policy->record_gpu_submitted(21, true);
ASSERT_TRUE(policy->consume_3d_events());
policy->reset_3d_statistics();
ASSERT_TRUE(policy->consume_3d_events());
const auto& state = policy->read_state<
aethera::Frame_Policy_3D::Base_Tag>();
EXPECT_EQ(state.pipeline_capacity, 3u);
EXPECT_EQ(state.gpu_submission_count, 0u);
EXPECT_EQ(state.gpu_completion_count, 0u);
EXPECT_EQ(state.gpu_in_flight, 1u);
EXPECT_EQ(state.peak_gpu_in_flight, 1u);
EXPECT_EQ(state.last_submitted_sequence, 0u);
EXPECT_EQ(state.last_completed_sequence, 0u);
}
}