改结构

This commit is contained in:
2026-08-29 01:27:26 +08:00
parent e2cd28a93a
commit 31c8076822
4 changed files with 646 additions and 673 deletions
+573 -568
View File
File diff suppressed because it is too large Load Diff
@@ -5,7 +5,6 @@
#include <stdexcept>
#include <utility>
#include <vector>
namespace aethera::render_3d::detail {
namespace {
std::uint64_t elapsed_nanoseconds(
@@ -14,20 +13,15 @@ std::uint64_t elapsed_nanoseconds(
std::chrono::steady_clock::now() - started).count();
return elapsed > 0 ? static_cast<std::uint64_t>(elapsed) : 0ULL;
}
template <typename Value>
void update_peak(Value& peak, Value value) noexcept {
peak = std::max(peak, value);
}
}
Gpu_Completion_Service::Private::Private() = default;
Gpu_Completion_Service::Private::~Private() = default;
Gpu_Completion_Service::Gpu_Completion_Service() = default;
Gpu_Completion_Service::~Gpu_Completion_Service() = default;
Gpu_Completion_Service& Gpu_Completion_Service::instance() {
/*
* GPU completion 域与进程同寿命。主动泄放所有权可避免静态析构阶段
@@ -43,26 +37,20 @@ Gpu_Completion_Service& Gpu_Completion_Service::instance() {
}();
return *service;
}
Gpu_Completion_Service::Reservation::Reservation() = default;
Gpu_Completion_Service::Reservation::Reservation(
std::shared_ptr<Gpu_Completion_Pending_Fence> pending) noexcept
: pending_(std::move(pending)) {}
std::shared_ptr<Gpu_Completion_Pending_Fence> pending) noexcept : pending_(std::move(pending)) {}
Gpu_Completion_Service::Reservation::~Reservation() noexcept {
try { cancel(); }
try {
cancel();
}
catch (...) {}
}
Gpu_Completion_Service::Reservation::Reservation(
Reservation&& other) noexcept
: pending_(std::exchange(other.pending_, {})) {}
Reservation&& other) noexcept : pending_(std::exchange(other.pending_, {})) {}
Gpu_Completion_Service::Prepare_Result::operator bool() const noexcept {
return result == Admission_Result::none;
}
void Gpu_Completion_Service::Reservation::watch(std::uintptr_t device,
std::uintptr_t fence) {
if (!pending_ || device == 0 || fence == 0)
@@ -71,41 +59,32 @@ void Gpu_Completion_Service::Reservation::watch(std::uintptr_t device,
pending_->service->watch(pending_, device, fence);
pending_.reset();
}
void Gpu_Completion_Service::Reservation::cancel() {
if (!pending_) return;
pending_->service->cancel(pending_);
pending_.reset();
}
Gpu_Completion_Service::Prepare_Result Gpu_Completion_Service::prepare(
Completion completion, Exception_Handler on_exception, bool observe) {
return static_cast<Private&>(*d).prepare(
std::move(completion), std::move(on_exception), observe);
}
void Gpu_Completion_Service::watch(
const std::shared_ptr<Gpu_Completion_Pending_Fence>& pending,
std::uintptr_t device, std::uintptr_t fence) {
static_cast<Private&>(*d).watch(pending, device, fence);
}
void Gpu_Completion_Service::cancel(
const std::shared_ptr<Gpu_Completion_Pending_Fence>& pending) {
static_cast<Private&>(*d).cancel(pending);
}
Gpu_Completion_Service::Prepare_Result
Gpu_Completion_Service::Private::prepare(
Gpu_Completion_Service::Prepare_Result Gpu_Completion_Service::Private::prepare(
Completion completion, Exception_Handler on_exception, bool observe) {
if (!completion)
throw std::invalid_argument("GPU completion callback is empty");
if (!completion) throw std::invalid_argument("GPU completion callback is empty");
if (!on_exception)
throw std::invalid_argument(
"GPU completion exception handler is empty");
if (stopping.load(std::memory_order_acquire))
return {{}, Admission_Result::stopping};
if (stopping.load(std::memory_order_acquire)) return {{}, Admission_Result::stopping};
auto pending = std::make_shared<Gpu_Completion_Pending_Fence>();
pending->completion = std::move(completion);
pending->on_exception = std::move(on_exception);
@@ -113,11 +92,11 @@ Gpu_Completion_Service::Private::prepare(
pending->service = object;
Admission_Result admission{Admission_Result::none};
double_buffer::detail::Internal_Access::update_state<
&Gpu_Completion_State::State::in_flight, &Gpu_Completion_State::State::peak_in_flight,
&Gpu_Completion_State::State::reservation_count, &Gpu_Completion_State::State::backpressure_count>(
&State::in_flight, &State::peak_in_flight,
&State::reservation_count, &State::backpressure_count>(
object,
[&](State_Access<State> states) {
auto& state = states.template get<Gpu_Completion_State::Base_Tag>();
auto& state = states.template get<Base_Tag>();
if (state.in_flight >= state.capacity) {
++state.backpressure_count;
admission = Admission_Result::capacity_exhausted;
@@ -127,23 +106,21 @@ Gpu_Completion_Service::Private::prepare(
update_peak(state.peak_in_flight, state.in_flight);
++state.reservation_count;
});
if (admission != Admission_Result::none)
return {{}, admission};
if (admission != Admission_Result::none) return {{}, admission};
try {
double_buffer::detail::Internal_Access::submit_stream<GPU_Task_Tag>(object, pending);
}
catch (...) {
double_buffer::detail::Internal_Access::update_state<&Gpu_Completion_State::State::in_flight>(object,
[](State_Access<State> states) {
auto& state = states.template get<Gpu_Completion_State::Base_Tag>();
if (state.in_flight != 0) --state.in_flight;
});
double_buffer::detail::Internal_Access::update_state<&State::in_flight>(object,
[](State_Access<State> states) {
auto& state = states.template get<Base_Tag>();
if (state.in_flight != 0) --state.in_flight;
});
throw;
}
request_poll(std::chrono::nanoseconds{1});
return {Reservation(std::move(pending)), Admission_Result::none};
}
void Gpu_Completion_Service::Private::watch(
const std::shared_ptr<Gpu_Completion_Pending_Fence>& pending,
std::uintptr_t device, std::uintptr_t fence) {
@@ -158,42 +135,39 @@ void Gpu_Completion_Service::Private::watch(
pending->watched_at = std::chrono::steady_clock::now();
pending->status = Gpu_Completion_Pending_Fence::Status::watched;
}
double_buffer::detail::Internal_Access::update_state<&Gpu_Completion_State::State::watched, &Gpu_Completion_State::State::peak_watched>(object,
[](State_Access<State> states) {
auto& state = states.template get<Gpu_Completion_State::Base_Tag>();
++state.watched;
update_peak(state.peak_watched, state.watched);
});
double_buffer::detail::Internal_Access::update_state<&State::watched, &State::peak_watched>(object,
[](State_Access<State> states) {
auto& state = states.template get<Base_Tag>();
++state.watched;
update_peak(state.peak_watched, state.watched);
});
request_poll(std::chrono::nanoseconds{1});
}
void Gpu_Completion_Service::Private::cancel(
const std::shared_ptr<Gpu_Completion_Pending_Fence>& pending) {
{
std::lock_guard lock(service_mutex);
if (!pending || pending->service != object) return;
if (pending->status == Gpu_Completion_Pending_Fence::Status::reserved)
pending->status = Gpu_Completion_Pending_Fence::Status::canceled;
if (pending->status == Gpu_Completion_Pending_Fence::Status::reserved) pending->status = Gpu_Completion_Pending_Fence::Status::canceled;
}
request_poll(std::chrono::nanoseconds{1});
}
void Gpu_Completion_Service::Private::request_poll(
std::chrono::nanoseconds delay) noexcept {
if (stopping.load(std::memory_order_acquire)) return;
try { poll_timer.start_once(delay); }
try {
poll_timer.start_once(delay);
}
catch (...) {}
}
void Gpu_Completion_Service::Private::poll() noexcept {
if (stopping.load(std::memory_order_acquire)) return;
try {
double_buffer::detail::Internal_Access::exchange_stream<GPU_Task_Tag>(object);
double_buffer::detail::Internal_Access::access_rendering_stream<GPU_Task_Tag>(object,
[&](std::span<std::shared_ptr<Gpu_Completion_Pending_Fence>> pending) {
active.insert(active.end(), pending.begin(), pending.end());
});
[&](std::span<std::shared_ptr<Gpu_Completion_Pending_Fence>> pending) {
active.insert(active.end(), pending.begin(), pending.end());
});
const auto finish = [this](
const std::shared_ptr<Gpu_Completion_Pending_Fence>& pending,
VkResult vulkan_result, Completion_Error error) noexcept {
@@ -202,41 +176,41 @@ void Gpu_Completion_Service::Private::poll() noexcept {
Result result{};
{
std::lock_guard lock(service_mutex);
if (pending->status != Gpu_Completion_Pending_Fence::Status::watched)
return;
if (pending->status != Gpu_Completion_Pending_Fence::Status::watched) return;
completion = std::move(pending->completion);
on_exception = std::move(pending->on_exception);
result.error = error;
result.vulkan_result = static_cast<std::int32_t>(vulkan_result);
if (pending->observe)
result.wait_duration_ns = elapsed_nanoseconds(pending->watched_at);
if (pending->observe) result.wait_duration_ns = elapsed_nanoseconds(pending->watched_at);
pending->status = Gpu_Completion_Pending_Fence::Status::canceled;
}
double_buffer::detail::Internal_Access::update_state<
&Gpu_Completion_State::State::watched, &Gpu_Completion_State::State::fault_count, &Gpu_Completion_State::State::abandoned_count>(
&State::watched, &State::fault_count, &State::abandoned_count>(
object,
[error](State_Access<State> states) {
auto& state = states.template get<Gpu_Completion_State::Base_Tag>();
auto& state = states.template get<Base_Tag>();
if (state.watched != 0) --state.watched;
if (error != Completion_Error::none) {
++state.fault_count;
if (error == Completion_Error::fence_abandoned)
++state.abandoned_count;
if (error == Completion_Error::fence_abandoned) ++state.abandoned_count;
}
});
const auto callback_started = std::chrono::steady_clock::now();
std::exception_ptr callback_failure;
try { completion(std::move(result)); }
catch (...) { callback_failure = std::current_exception(); }
try {
completion(std::move(result));
}
catch (...) {
callback_failure = std::current_exception();
}
const auto callback_ns = elapsed_nanoseconds(callback_started);
double_buffer::detail::Internal_Access::update_state<
&Gpu_Completion_State::State::callback_total_ns, &Gpu_Completion_State::State::callback_max_ns,
&Gpu_Completion_State::State::callback_failure_count, &Gpu_Completion_State::State::completion_count,
&Gpu_Completion_State::State::in_flight>(
&State::callback_total_ns, &State::callback_max_ns,
&State::callback_failure_count, &State::completion_count,
&State::in_flight>(
object,
[callback_ns, &callback_failure](State_Access<State> states) {
auto& state = states.template get<Gpu_Completion_State::Base_Tag>();
auto& state = states.template get<Base_Tag>();
state.callback_total_ns += callback_ns;
update_peak(state.callback_max_ns, callback_ns);
if (callback_failure) ++state.callback_failure_count;
@@ -250,7 +224,6 @@ void Gpu_Completion_Service::Private::poll() noexcept {
}
catch (...) {}
};
std::size_t reserved_count{};
bool needs_more{};
for (auto iterator = active.begin(); iterator != active.end();) {
@@ -268,10 +241,10 @@ void Gpu_Completion_Service::Private::poll() noexcept {
if (status == Gpu_Completion_Pending_Fence::Status::canceled) {
iterator = active.erase(iterator);
double_buffer::detail::Internal_Access::update_state<
&Gpu_Completion_State::State::cancellation_count, &Gpu_Completion_State::State::in_flight>(
&State::cancellation_count, &State::in_flight>(
object,
[](State_Access<State> states) {
auto& state = states.template get<Gpu_Completion_State::Base_Tag>();
auto& state = states.template get<Base_Tag>();
++state.cancellation_count;
if (state.in_flight != 0) --state.in_flight;
});
@@ -288,10 +261,10 @@ void Gpu_Completion_Service::Private::poll() noexcept {
finish(pending, VK_TIMEOUT, Completion_Error::fence_abandoned);
continue;
}
double_buffer::detail::Internal_Access::update_state<&Gpu_Completion_State::State::fence_probe_count>(object,
[](State_Access<State> states) {
++states.template get<Gpu_Completion_State::Base_Tag>().fence_probe_count;
});
double_buffer::detail::Internal_Access::update_state<&State::fence_probe_count>(object,
[](State_Access<State> states) {
++states.template get<Base_Tag>().fence_probe_count;
});
const VkResult result = vkGetFenceStatus(
reinterpret_cast<VkDevice>(device),
reinterpret_cast<VkFence>(fence));
@@ -303,26 +276,25 @@ void Gpu_Completion_Service::Private::poll() noexcept {
auto pending = *iterator;
iterator = active.erase(iterator);
finish(pending, result,
result == VK_SUCCESS ? Completion_Error::none
: Completion_Error::vulkan_failure);
result == VK_SUCCESS
? Completion_Error::none
: Completion_Error::vulkan_failure);
}
const auto now = std::chrono::steady_clock::now();
if (last_state_publication == std::chrono::steady_clock::time_point{} ||
now - last_state_publication >= state_publication_interval) {
double_buffer::detail::Internal_Access::update_state<
&Gpu_Completion_State::State::active_fences, &Gpu_Completion_State::State::pending_fences>(
&State::active_fences, &State::pending_fences>(
object,
[active_count = active.size(), reserved_count](
State_Access<State> states) {
auto& state = states.template get<Gpu_Completion_State::Base_Tag>();
auto& state = states.template get<Base_Tag>();
state.active_fences = active_count;
state.pending_fences = reserved_count;
});
double_buffer::detail::Internal_Access::publish_state<Gpu_Completion_State::Base_Tag>(object);
double_buffer::detail::Internal_Access::publish_state<Base_Tag>(object);
last_state_publication = now;
}
if (needs_more) request_poll(probe_interval);
}
catch (...) {
@@ -332,13 +304,14 @@ void Gpu_Completion_Service::Private::poll() noexcept {
std::lock_guard lock(service_mutex);
for (auto& pending : active) {
pending->status = Gpu_Completion_Pending_Fence::Status::canceled;
if (pending->on_exception)
handlers.push_back(std::move(pending->on_exception));
if (pending->on_exception) handlers.push_back(std::move(pending->on_exception));
}
active.clear();
}
for (auto& handler : handlers) {
try { handler(failure); }
try {
handler(failure);
}
catch (...) {}
}
}
@@ -7,10 +7,12 @@
#include <memory>
namespace aethera::render_3d::detail {
struct GPU_Task_Tag {};
/* GPU completion 统计是独立状态领域;Service 只负责行为与任务流。 */
struct Gpu_Completion_State : Def<Gpu_Completion_State, Root> {
struct Gpu_Completion_Pending_Fence;
struct Gpu_Completion_Service : Def<Gpu_Completion_Service, Root,
Mpmc_Triple_Buffer<GPU_Task_Tag,
std::shared_ptr<Gpu_Completion_Pending_Fence>>> {
struct Prop : Prev_Prop {};
/* GPU completion 统计是独立状态领域;Service 只负责行为与任务流。 */
struct State : Prev_State {
std::size_t capacity{}; /* 可同时监视的最大 fence 数量。 */
std::size_t in_flight{}; /* 已准入且尚未完成的 reservation 数量。 */
@@ -35,15 +37,6 @@ struct Gpu_Completion_State : Def<Gpu_Completion_State, Root> {
std::uint64_t abandoned_count{};
bool operator==(const State&) const = default;
};
struct Private : Prev_Private {};
};
struct Gpu_Completion_Pending_Fence;
struct Gpu_Completion_Service : Def<Gpu_Completion_Service, Gpu_Completion_State,
Mpmc_Triple_Buffer<GPU_Task_Tag,
std::shared_ptr<Gpu_Completion_Pending_Fence>>> {
struct Prop : Prev_Prop {};
struct State : Prev_State {};
struct Private;
enum struct Admission_Result : std::uint8_t {
none,
@@ -35,12 +35,14 @@ struct Gpu_Completion_Service::Private : Prev_Private {
void bind_private_crtp(Attached_Object* attached) {
Prev_Private::bind_private_crtp(attached);
object = not_null{static_cast<Object*>(attached)};
double_buffer::detail::Internal_Access::update_state<&Gpu_Completion_State::State::capacity>(object,
static_cast<std::size_t>(default_capacity));
double_buffer::detail::Internal_Access::publish_state<Gpu_Completion_State::Base_Tag>(object);
double_buffer::detail::Internal_Access::update_state<&State::capacity>(object,
static_cast<std::size_t>(default_capacity));
double_buffer::detail::Internal_Access::publish_state<Base_Tag>(object);
active.reserve(static_cast<std::size_t>(default_capacity));
poll_timer = Frame_Scheduler::instance().make_timer(
[this](Frame_Scheduler::Tick) { poll(); });
[this](Frame_Scheduler::Tick) {
poll();
});
}
[[nodiscard]] Prepare_Result prepare(Completion completion,
Exception_Handler on_exception,
@@ -54,6 +56,6 @@ struct Gpu_Completion_Service::Private : Prev_Private {
static constexpr auto probe_interval = std::chrono::milliseconds(1);
static constexpr std::uint64_t maximum_fence_age_ns = 30'000'000'000ULL;
static constexpr auto state_publication_interval =
std::chrono::milliseconds(100);
std::chrono::milliseconds(100);
};
}